RE: [PATCH 1/1] fnic: Adding Check Condition counter to misc fnicstats
Hi Martin, Apologies for the delay. I was not able to verify this because of another fnic issue blocking this test. Just now submitted a fix for that 'fnic issue' (in the patch => [PATCH 1/1] fnic: bug fix for fip.fip_subcode in fnic_fcoe_send_vlan_req) Did some quick verification and basic IO test, this patch looks good. Thanks, Satish Kharat -Original Message- From: Martin K. Petersen [mailto:martin.peter...@oracle.com] Sent: Wednesday, March 01, 2017 7:04 PM To: Satish Kharat (satishkh) Cc: linux-scsi@vger.kernel.org; Sesidhar Baddela (sebaddel) Subject: Re: [PATCH 1/1] fnic: Adding Check Condition counter to misc fnicstats > "Satish" == Satish Kharat writes: Satish, Satish> Just a simple counter of number of check conditions encountered Satish> on that host. Please test and review the following: https://patchwork.kernel.org/patch/9549777/ Thank you! -- Martin K. Petersen Oracle Linux Engineering
[PATCH 1/1] fnic: bug fix for fip.fip_subcode in fnic_fcoe_send_vlan_req
This is a bug introduced when they moved the fip subcodes to central place. Was sending FIP_SC_VL_NOTE in fip.fip_subcode for VLAN request in fnic_fcoe_send_vlan_req. Change is to use FIP_SC_VL_REQ instead. Signed-off-by: Satish Kharat Signed-off-by: Sesidhar Baddela --- drivers/scsi/fnic/fnic_fcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c index 3b7da66..f5e632f 100644 --- a/drivers/scsi/fnic/fnic_fcs.c +++ b/drivers/scsi/fnic/fnic_fcs.c @@ -359,7 +359,7 @@ static void fnic_fcoe_send_vlan_req(struct fnic *fnic) vlan->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER); vlan->fip.fip_op = htons(FIP_OP_VLAN); - vlan->fip.fip_subcode = FIP_SC_VL_NOTE; + vlan->fip.fip_subcode = FIP_SC_VL_REQ; vlan->fip.fip_dl_len = htons(sizeof(vlan->desc) / FIP_BPW); vlan->desc.mac.fd_desc.fip_dtype = FIP_DT_MAC; -- 2.7.4
RE: [PATCH v7 09/11] scsi: ufs: connect to RPMB subsystem
> > On Mon, Nov 07, 2016 at 07:27:38PM +, Winkler, Tomas wrote: > > I value your opinion but I'm not responsible for inventing RPMB > > and/or its implementation storage devices (eMMC, UFC, NVMe), it's pretty > much done deal out there in the wild. > > I'm just trying to provide common API above it. Somehow I've missed that answer, now I got back when search for comments before I'll post a new series. > And the common API must go through the SCSI midlayer. I've actually tried to do a midlayer, but I found it's too UFS specific, so there is no point to this abstraction. As not all needed data are accessible via scsi calls. The solution I propose fits with what is done in eMMC (emmc specific IOCTL). There is already some code that breaks that layering in ufshcd_set_dev_pwr_mode when talking to the special sdev_ufs. Maybe I need more hint for the correct directions. If it can't we won't > support it, so please drop the UFS patches from the series. If you have more constructive comments, I'll be glad to hear and address. Thanks Tomas
[PATCH] scsi: pm8001: build in relevant functions and code on PM8001_USE_MSIX
From: Colin Ian King Currently the misx and intx variables of the interrupt enable/disable helper functions are built in no matter what the setting of the macro PM8001_USE_MSIX. Clean this up by just building in the necessary helper functions and calls to these functions depending on the setting of PM8001_USE_MSIX. This addresses several dead code paths found by static analysis with CoverityScan. Signed-off-by: Colin Ian King --- drivers/scsi/pm8001/pm8001_hwi.c | 63 +--- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 10546faac58c..d1be10fd1350 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -1204,26 +1204,7 @@ void pm8001_chip_iounmap(struct pm8001_hba_info *pm8001_ha) } } -/** - * pm8001_chip_interrupt_enable - enable PM8001 chip interrupt - * @pm8001_ha: our hba card information - */ -static void -pm8001_chip_intx_interrupt_enable(struct pm8001_hba_info *pm8001_ha) -{ - pm8001_cw32(pm8001_ha, 0, MSGU_ODMR, ODMR_CLEAR_ALL); - pm8001_cw32(pm8001_ha, 0, MSGU_ODCR, ODCR_CLEAR_ALL); -} - - /** - * pm8001_chip_intx_interrupt_disable- disable PM8001 chip interrupt - * @pm8001_ha: our hba card information - */ -static void -pm8001_chip_intx_interrupt_disable(struct pm8001_hba_info *pm8001_ha) -{ - pm8001_cw32(pm8001_ha, 0, MSGU_ODMR, ODMR_MASK_ALL); -} +#ifdef PM8001_USE_MSIX /** * pm8001_chip_msix_interrupt_enable - enable PM8001 chip interrupt @@ -1257,6 +1238,30 @@ pm8001_chip_msix_interrupt_disable(struct pm8001_hba_info *pm8001_ha, pm8001_cw32(pm8001_ha, 0, msi_index, MSIX_INTERRUPT_DISABLE); } +#else + +/** + * pm8001_chip_interrupt_enable - enable PM8001 chip interrupt + * @pm8001_ha: our hba card information + */ +static void +pm8001_chip_intx_interrupt_enable(struct pm8001_hba_info *pm8001_ha) +{ + pm8001_cw32(pm8001_ha, 0, MSGU_ODMR, ODMR_CLEAR_ALL); + pm8001_cw32(pm8001_ha, 0, MSGU_ODCR, ODCR_CLEAR_ALL); +} + + /** + * pm8001_chip_intx_interrupt_disable- disable PM8001 chip interrupt + * @pm8001_ha: our hba card information + */ +static void +pm8001_chip_intx_interrupt_disable(struct pm8001_hba_info *pm8001_ha) +{ + pm8001_cw32(pm8001_ha, 0, MSGU_ODMR, ODMR_MASK_ALL); +} +#endif + /** * pm8001_chip_interrupt_enable - enable PM8001 chip interrupt * @pm8001_ha: our hba card information @@ -1266,10 +1271,9 @@ pm8001_chip_interrupt_enable(struct pm8001_hba_info *pm8001_ha, u8 vec) { #ifdef PM8001_USE_MSIX pm8001_chip_msix_interrupt_enable(pm8001_ha, 0); - return; -#endif +#else pm8001_chip_intx_interrupt_enable(pm8001_ha); - +#endif } /** @@ -1281,10 +1285,9 @@ pm8001_chip_interrupt_disable(struct pm8001_hba_info *pm8001_ha, u8 vec) { #ifdef PM8001_USE_MSIX pm8001_chip_msix_interrupt_disable(pm8001_ha, 0); - return; -#endif +#else pm8001_chip_intx_interrupt_disable(pm8001_ha); - +#endif } /** @@ -4613,15 +4616,15 @@ static int pm8001_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha, static u32 pm8001_chip_is_our_interupt(struct pm8001_hba_info *pm8001_ha) { - u32 value; #ifdef PM8001_USE_MSIX return 1; -#endif - value = pm8001_cr32(pm8001_ha, 0, MSGU_ODR); +#else + u32 value = pm8001_cr32(pm8001_ha, 0, MSGU_ODR); + if (value) return 1; return 0; - +#endif } /** -- 2.11.0
Re: [PATCH] scsi: fcoe: sanity check string size for store_ctrl_mode option
On 22/03/17 19:39, Dan Carpenter wrote: > On Wed, Mar 22, 2017 at 02:01:37PM +, Colin King wrote: >> From: Colin Ian King >> >> Reading and writing to mode[count - 1] implies the count should not >> be less than 1 so add a sanity check for this. >> >> Detected with CoverityScan, CID#1357345 ("Overflowed array index write") >> >> Signed-off-by: Colin Ian King > > This is harmless, of course, but count can't be zero. This is a sysfs > file so we test for zero size writes in sysfs_kf_write() and return > early. Ah, thanks for pointing out that. I overlooked that detail. Colin > > regards, > dan carpenter >
Re: [PATCH] scsi: fcoe: sanity check string size for store_ctrl_mode option
On Wed, Mar 22, 2017 at 02:01:37PM +, Colin King wrote: > From: Colin Ian King > > Reading and writing to mode[count - 1] implies the count should not > be less than 1 so add a sanity check for this. > > Detected with CoverityScan, CID#1357345 ("Overflowed array index write") > > Signed-off-by: Colin Ian King This is harmless, of course, but count can't be zero. This is a sysfs file so we test for zero size writes in sysfs_kf_write() and return early. regards, dan carpenter
Re: support ranges TRIM for libata
On Tue, Mar 21, 2017 at 02:59:01PM -0400, Tejun Heo wrote: > I do like the fact that this is a lot simpler than the previous > implementation but am not quite sure we want to deviate significantly > from what we do for other commands (command translation). Is it > because fixing the existing implementation would involve invaisve > changes including memory allocations? The current implementation already has the issue of that it does corrupt user data reliably if the using SG_IO for WRITE SAME commands. Doing ranges using translation would turn into a nightmare because ATA TRIM ranges are 16 bits long while SCSI UNAMP ranges are 32-bit, so we effectively can't translated them without introducing a non-standard hook between libata and scsi to communicate that limit. And once we're down that path we might as well just do the right thing directly.
[PATCH 14/23] scsi: hisi_sas: remove task free'ing for timeouts
When a TMF or internal abort times-out, do not free slot. We expect this to be done upon later escalated error handling. Signed-off-by: John Garry --- drivers/scsi/hisi_sas/hisi_sas_main.c | 15 +-- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index f9ea5cc..3d63a24 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -743,14 +743,6 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device, if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { dev_err(dev, "abort tmf: TMF task timeout\n"); - if (task->lldd_task) { - struct hisi_sas_slot *slot = - task->lldd_task; - - hisi_sas_slot_task_free(hisi_hba, - task, slot); - } - goto ex_err; } } @@ -1248,15 +1240,10 @@ static int hisi_sas_query_task(struct sas_task *task) goto exit; } - /* TMF timed out, return direct. */ + /* Internal abort timed out */ if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { dev_err(dev, "internal task abort: timeout.\n"); - if (task->lldd_task) { - struct hisi_sas_slot *slot = task->lldd_task; - - hisi_sas_slot_task_free(hisi_hba, task, slot); - } } } -- 1.9.1
[PATCH 02/23] scsi: hisi_sas: add controller reset
From: Xiang Chen There are some scenarios that we need to warm-rest to reset registers of SAS controller. During reset we disable interrupts/DQs/PHYs, and after reset we re-init the hardware and rescan the topology to see if anything changed. Signed-off-by: Xiang Chen Signed-off-by: Xiaofei Tan Signed-off-by: John Garry --- drivers/scsi/hisi_sas/hisi_sas.h | 7 ++ drivers/scsi/hisi_sas/hisi_sas_main.c | 134 +++-- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 94 +++ 3 files changed, 227 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index a018a8a..fd76a02 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -31,6 +31,7 @@ #define HISI_SAS_QUEUE_SLOTS 512 #define HISI_SAS_MAX_ITCT_ENTRIES 2048 #define HISI_SAS_MAX_DEVICES HISI_SAS_MAX_ITCT_ENTRIES +#define HISI_SAS_RESET_BIT 0 #define HISI_SAS_STATUS_BUF_SZ \ (sizeof(struct hisi_sas_err_record) + 1024) @@ -175,6 +176,7 @@ struct hisi_sas_hw { void (*free_device)(struct hisi_hba *hisi_hba, struct hisi_sas_device *dev); int (*get_wideport_bitmap)(struct hisi_hba *hisi_hba, int port_id); + int (*soft_reset)(struct hisi_hba *hisi_hba); int max_command_entries; int complete_hdr_size; }; @@ -233,7 +235,9 @@ struct hisi_hba { struct hisi_sas_breakpoint *sata_breakpoint; dma_addr_t sata_breakpoint_dma; struct hisi_sas_slot*slot_info; + unsigned long flags; const struct hisi_sas_hw *hw; /* Low level hw interface */ + struct work_struct rst_work; }; /* Generic HW DMA host memory structures */ @@ -356,4 +360,7 @@ extern int hisi_sas_probe(struct platform_device *pdev, extern void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, struct hisi_sas_slot *slot); +extern void hisi_sas_init_mem(struct hisi_hba *hisi_hba); +extern void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 old_state, +u32 state); #endif diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 11f32d2..cbaef90 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -351,6 +351,9 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags, struct hisi_hba *hisi_hba = dev_to_hisi_hba(task->dev); struct device *dev = &hisi_hba->pdev->dev; + if (unlikely(test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags))) + return -EINVAL; + /* protect task_prep and start_delivery sequence */ spin_lock_irqsave(&hisi_hba->lock, flags); rc = hisi_sas_task_prep(task, hisi_hba, is_tmf, tmf, &pass); @@ -613,6 +616,20 @@ static void hisi_sas_release_task(struct hisi_hba *hisi_hba, hisi_sas_do_release_task(hisi_hba, sas_phy->id, device); } +static void hisi_sas_release_tasks(struct hisi_hba *hisi_hba) +{ + int i; + + for (i = 0; i < HISI_SAS_MAX_PHYS; i++) { + struct hisi_sas_phy *phy = &hisi_hba->phy[i]; + struct asd_sas_phy *sas_phy = &phy->sas_phy; + + if (!sas_phy->port) + continue; + hisi_sas_port_notify_deformed(sas_phy); + } +} + static void hisi_sas_dev_gone(struct domain_device *device) { struct hisi_sas_device *sas_dev = device->lldd_dev; @@ -803,6 +820,40 @@ static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device, sizeof(ssp_task), tmf); } +static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba) +{ + int rc; + + if (!hisi_hba->hw->soft_reset) + return -1; + + if (!test_and_set_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) { + struct device *dev = &hisi_hba->pdev->dev; + struct sas_ha_struct *sas_ha = &hisi_hba->sha; + unsigned long flags; + + dev_dbg(dev, "controller reset begins!\n"); + scsi_block_requests(hisi_hba->shost); + rc = hisi_hba->hw->soft_reset(hisi_hba); + if (rc) { + dev_warn(dev, "controller reset failed (%d)\n", rc); + goto out; + } + spin_lock_irqsave(&hisi_hba->lock, flags); + hisi_sas_release_tasks(hisi_hba); + spin_unlock_irqrestore(&hisi_hba->lock, flags); + + sas_ha->notify_ha_event(sas_ha, HAE_RESET); + dev_dbg(dev, "controller reset successful!\n"); + } else + return -1; + +out: + scsi_unblock_requests(hisi_hba->shost); + clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags); + return rc; +} + static int hisi_sas_abort_task(struct sas_tas
[PATCH 08/23] scsi: hisi_sas: modify error handling for v2 hw
From: Xiang Chen For error codes which need abort-and-retry, simulate IO timeout and let SCSI+ATA layers process those errors. Previously for SSP, we should try to abort the IO in the LLDD and then pass back to upper layer, but sometimes this would also error. So Instead of adding special error handling for this scenario in the LLDD, allow the upper layer to handle completely. No performance hit is seen by taking this approach. Signed-off-by: Xiang Chen Signed-off-by: John Garry --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 9 +++-- 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index b9d5132..a35f881 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -1747,7 +1747,6 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, task->task_state_flags &= ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR); - task->task_state_flags |= SAS_TASK_STATE_DONE; memset(ts, 0, sizeof(*ts)); ts->resp = SAS_TASK_COMPLETE; @@ -1786,11 +1785,9 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, (!(complete_hdr->dw0 & CMPLT_HDR_RSPNS_XFRD_MSK))) { slot_err_v2_hw(hisi_hba, task, slot); - if (unlikely(slot->abort)) { - queue_work(hisi_hba->wq, &slot->abort_slot); - /* immediately return and do not complete */ + + if (unlikely(slot->abort)) return ts->stat; - } goto out; } @@ -1842,7 +1839,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, } out: - + task->task_state_flags |= SAS_TASK_STATE_DONE; hisi_sas_slot_task_free(hisi_hba, task, slot); sts = ts->stat; -- 1.9.1
[PATCH 05/23] scsi: hisi_sas: remove hisi_sas_port_deformed()
Currently when a root PHY is deformed from a asd_sas_port we try to release the slots in the LLDD, and fail. Regardless, it is not right to release this early. This patch removes the deformed function. As it was before, port deformation is still done in hisi_sas_phy_down(). It would be nice to actually remove the hisi_sas_port_{de}formed() pair, however we cannot as we need to know the asd_sas_port index libsas has associated with an asd_sas_phy. The hw does actually generate a port id for a PHY, but this seems to a random number, so ignored for this purpose. This patch also changes the code to link slots to the hisi_sas_device, and not hisi_sas_port. Signed-off-by: John Garry Signed-off-by: Xiang Chen --- drivers/scsi/hisi_sas/hisi_sas.h | 4 +- drivers/scsi/hisi_sas/hisi_sas_main.c | 85 ++ drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 9 ++-- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 13 +++--- 4 files changed, 46 insertions(+), 65 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 2135de9..6aa0b62 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -91,7 +91,6 @@ struct hisi_sas_port { struct asd_sas_port sas_port; u8 port_attached; u8 id; /* from hw */ - struct list_headlist; }; struct hisi_sas_cq { @@ -114,6 +113,7 @@ struct hisi_sas_device { u64 attached_phy; u64 device_id; atomic64_t running_req; + struct list_headlist; u8 dev_status; }; @@ -166,7 +166,7 @@ struct hisi_sas_hw { struct hisi_sas_slot *slot, int device_id, int abort_flag, int tag_to_abort); int (*slot_complete)(struct hisi_hba *hisi_hba, -struct hisi_sas_slot *slot, int abort); +struct hisi_sas_slot *slot); void (*phys_init)(struct hisi_hba *hisi_hba); void (*phy_enable)(struct hisi_hba *hisi_hba, int phy_no); void (*phy_disable)(struct hisi_hba *hisi_hba, int phy_no); diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 9d9f305..f64c1b6 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -308,7 +308,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, goto err_out_command_table; } - list_add_tail(&slot->entry, &port->list); + list_add_tail(&slot->entry, &sas_dev->list); spin_lock(&task->task_state_lock); task->task_state_flags |= SAS_TASK_AT_INITIATOR; spin_unlock(&task->task_state_lock); @@ -424,6 +424,7 @@ static struct hisi_sas_device *hisi_sas_alloc_dev(struct domain_device *device) sas_dev->dev_type = device->dev_type; sas_dev->hisi_hba = hisi_hba; sas_dev->sas_device = device; + INIT_LIST_HEAD(&hisi_hba->devices[i].list); break; } } @@ -568,63 +569,55 @@ static void hisi_sas_port_notify_formed(struct asd_sas_phy *sas_phy) spin_unlock_irqrestore(&hisi_hba->lock, flags); } -static void hisi_sas_do_release_task(struct hisi_hba *hisi_hba, int phy_no, -struct domain_device *device) +static void hisi_sas_do_release_task(struct hisi_hba *hisi_hba, +struct sas_task *task, +struct hisi_sas_slot *slot) { - struct hisi_sas_phy *phy; - struct hisi_sas_port *port; - struct hisi_sas_slot *slot, *slot2; - struct device *dev = &hisi_hba->pdev->dev; + struct task_status_struct *ts; + unsigned long flags; - phy = &hisi_hba->phy[phy_no]; - port = phy->port; - if (!port) + if (!task) return; - list_for_each_entry_safe(slot, slot2, &port->list, entry) { - struct sas_task *task; - - task = slot->task; - if (device && task->dev != device) - continue; - - dev_info(dev, "Release slot [%d:%d], task [%p]:\n", -slot->dlvry_queue, slot->dlvry_queue_slot, task); - hisi_hba->hw->slot_complete(hisi_hba, slot, 1); - } -} + ts = &task->task_status; -static void hisi_sas_port_notify_deformed(struct asd_sas_phy *sas_phy) -{ - struct domain_device *device; - struct hisi_sas_phy *phy = sas_phy->lldd_phy; - struct asd_sas_port *sas_port = sas_phy->port; + ts->resp = SAS_TASK_COMPLETE; + ts->stat = SAS_ABORTED_TASK; + spin_lock_irqsave(&task->task_state_lock, flags); + task->task_state_flags &= + ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR); + task->task_state_flags |= SAS_TASK_ST
[PATCH 22/23] scsi: hisi_sas: use dev_is_sata to identify SATA or SAS disk
From: Xiang Chen When SMP IO is sent, sas_protocol_ata couldn't judge whether the disk is SATA or SAS disk. So use dev_is_sata to identify SATA or SAS disk. Signed-off-by: Xiang Chen Signed-off-by: John Garry --- drivers/scsi/hisi_sas/hisi_sas_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index dcceff9..9890dfd 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -218,7 +218,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, port = to_hisi_sas_port(sas_port); if (port && !port->port_attached) { dev_info(dev, "task prep: %s port%d not attach device\n", -(sas_protocol_ata(task->task_proto)) ? +(dev_is_sata(device)) ? "SATA/STP" : "SAS", device->port->id); -- 1.9.1
[PATCH 01/23] scsi: hisi_sas: add to_hisi_sas_port()
Introduce function to get hisi_sas_port from asd_sas_port. Signed-off-by: John Garry Signed-off-by: Xiang Chen --- drivers/scsi/hisi_sas/hisi_sas.h | 2 ++ drivers/scsi/hisi_sas/hisi_sas_main.c | 17 + drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 4 +++- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 6 -- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 9216dea..a018a8a 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -346,6 +346,8 @@ struct hisi_sas_command_table_ssp { struct hisi_sas_command_table_smp smp; struct hisi_sas_command_table_stp stp; }; + +extern struct hisi_sas_port *to_hisi_sas_port(struct asd_sas_port *sas_port); extern int hisi_sas_probe(struct platform_device *pdev, const struct hisi_sas_hw *ops); extern int hisi_sas_remove(struct platform_device *pdev); diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 53637a9..11f32d2 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -27,6 +27,12 @@ static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device) return device->port->ha->lldd_ha; } +struct hisi_sas_port *to_hisi_sas_port(struct asd_sas_port *sas_port) +{ + return container_of(sas_port, struct hisi_sas_port, sas_port); +} +EXPORT_SYMBOL_GPL(to_hisi_sas_port); + static void hisi_sas_slot_index_clear(struct hisi_hba *hisi_hba, int slot_idx) { void *bitmap = hisi_hba->slot_index_tags; @@ -178,10 +184,11 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, struct hisi_sas_port *port; struct hisi_sas_slot *slot; struct hisi_sas_cmd_hdr *cmd_hdr_base; + struct asd_sas_port *sas_port = device->port; struct device *dev = &hisi_hba->pdev->dev; int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx; - if (!device->port) { + if (!sas_port) { struct task_status_struct *ts = &task->task_status; ts->resp = SAS_TASK_UNDELIVERED; @@ -206,7 +213,8 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, rc = SAS_PHY_DOWN; return rc; } - port = device->port->lldd_port; + + port = to_hisi_sas_port(sas_port); if (port && !port->port_attached) { dev_info(dev, "task prep: %s port%d not attach device\n", (sas_protocol_ata(task->task_proto)) ? @@ -545,7 +553,7 @@ static void hisi_sas_port_notify_formed(struct asd_sas_phy *sas_phy) struct hisi_hba *hisi_hba = sas_ha->lldd_ha; struct hisi_sas_phy *phy = sas_phy->lldd_phy; struct asd_sas_port *sas_port = sas_phy->port; - struct hisi_sas_port *port = &hisi_hba->port[phy->port_id]; + struct hisi_sas_port *port = to_hisi_sas_port(sas_port); unsigned long flags; if (!sas_port) @@ -990,13 +998,14 @@ static int hisi_sas_query_task(struct sas_task *task) struct device *dev = &hisi_hba->pdev->dev; struct hisi_sas_port *port; struct hisi_sas_slot *slot; + struct asd_sas_port *sas_port = device->port; struct hisi_sas_cmd_hdr *cmd_hdr_base; int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx; if (!device->port) return -1; - port = device->port->lldd_port; + port = to_hisi_sas_port(sas_port); /* simply get a slot and send abort command */ rc = hisi_sas_slot_index_alloc(hisi_hba, &slot_idx); diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index 854fbea..022ad10 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -508,6 +508,8 @@ static void setup_itct_v1_hw(struct hisi_hba *hisi_hba, struct device *dev = &hisi_hba->pdev->dev; u64 qw0, device_id = sas_dev->device_id; struct hisi_sas_itct *itct = &hisi_hba->itct[device_id]; + struct asd_sas_port *sas_port = device->port; + struct hisi_sas_port *port = to_hisi_sas_port(sas_port); memset(itct, 0, sizeof(*itct)); @@ -528,7 +530,7 @@ static void setup_itct_v1_hw(struct hisi_hba *hisi_hba, (1 << ITCT_HDR_AWT_CONTROL_OFF) | (device->max_linkrate << ITCT_HDR_MAX_CONN_RATE_OFF) | (1 << ITCT_HDR_VALID_LINK_NUM_OFF) | - (device->port->id << ITCT_HDR_PORT_ID_OFF)); + (port->id << ITCT_HDR_PORT_ID_OFF)); itct->qw0 = cpu_to_le64(qw0); /* qw1 */ diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 1b21445..1590e2f 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -676,7 +676,8 @
[PATCH 06/23] scsi: hisi_sas: error hisi_sas_task_prep() when port down
When sas_port is NULL, then return SAS_PHY_DOWN. In addition, when the sas_dev is gone then explicitly return SAS_PHY_DOWN. Signed-off-by: John Garry Signed-off-by: Xiang Chen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index f64c1b6..7c1fb75 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -200,7 +200,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, */ if (device->dev_type != SAS_SATA_DEV) task->task_done(task); - return 0; + return SAS_PHY_DOWN; } if (DEV_IS_GONE(sas_dev)) { @@ -211,8 +211,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, dev_info(dev, "task prep: device %016llx not ready\n", SAS_ADDR(device->sas_addr)); - rc = SAS_PHY_DOWN; - return rc; + return SAS_PHY_DOWN; } port = to_hisi_sas_port(sas_port); -- 1.9.1
[PATCH 15/23] scsi: hisi_sas: process error codes according to their priority
From: Xiang Chen There are some rules to decide which error code has the high priority when errors happen together: (1) Error phase of CQ decides the error happens on RX or TX; (2) For TX error, when DMA/TRANS TX error happen simultaneously, the priority of DMA TX error is higher than TRANS TX error, so for the priority of TX error: DW2 (DMA TX part) > DW0; (3) For RX error, when TRANS/DMA/SIPC RX error happen simultaneously, the priority of TRANS RX error is higher than DMA and SIPC RX error, and we should also keep the rules (the priority of DW3 > DW2), so for the priority of RX error: DW1 > DW3 > DW2(SIPC RX part); (4) There are also a priority we should keep in the same error type. So, modify slot error code to handle this. In addition to this, some some error codes are modified according to recommendation from SoC designer. Signed-off-by: Xiang Chen Signed-off-by: John Garry --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 553 - 1 file changed, 398 insertions(+), 155 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 2b6e64c..66a458b 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -313,6 +313,8 @@ /* Completion header */ /* dw0 */ +#define CMPLT_HDR_ERR_PHASE_OFF2 +#define CMPLT_HDR_ERR_PHASE_MSK(0xff << CMPLT_HDR_ERR_PHASE_OFF) #define CMPLT_HDR_RSPNS_XFRD_OFF 10 #define CMPLT_HDR_RSPNS_XFRD_MSK (0x1 << CMPLT_HDR_RSPNS_XFRD_OFF) #define CMPLT_HDR_ERX_OFF 12 @@ -389,10 +391,10 @@ enum { enum { TRANS_TX_FAIL_BASE = 0x0, /* dw0 */ - TRANS_RX_FAIL_BASE = 0x100, /* dw1 */ - DMA_TX_ERR_BASE = 0x200, /* dw2 bit 15-0 */ - SIPC_RX_ERR_BASE = 0x300, /* dw2 bit 31-16*/ - DMA_RX_ERR_BASE = 0x400, /* dw3 */ + TRANS_RX_FAIL_BASE = 0x20, /* dw1 */ + DMA_TX_ERR_BASE = 0x40, /* dw2 bit 15-0 */ + SIPC_RX_ERR_BASE = 0x50, /* dw2 bit 31-16*/ + DMA_RX_ERR_BASE = 0x60, /* dw3 */ /* trans tx*/ TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS = TRANS_TX_FAIL_BASE, /* 0x0 */ @@ -432,97 +434,100 @@ enum { TRANS_TX_ERR_WITH_WAIT_RECV_TIMEOUT, /* 0x1f for sata/stp */ /* trans rx */ - TRANS_RX_ERR_WITH_RXFRAME_CRC_ERR = TRANS_RX_FAIL_BASE, /* 0x100 */ - TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR, /* 0x101 for sata/stp */ - TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM, /* 0x102 for ssp/smp */ - /*IO_ERR_WITH_RXFIS_8B10B_CODE_ERR, [> 0x102 <] for sata/stp */ - TRANS_RX_ERR_WITH_RXFIS_DECODE_ERROR, /* 0x103 for sata/stp */ - TRANS_RX_ERR_WITH_RXFIS_CRC_ERR, /* 0x104 for sata/stp */ - TRANS_RX_ERR_WITH_RXFRAME_LENGTH_OVERRUN, /* 0x105 for smp */ - /*IO_ERR_WITH_RXFIS_TX SYNCP, [> 0x105 <] for sata/stp */ - TRANS_RX_ERR_WITH_RXFIS_RX_SYNCP, /* 0x106 for sata/stp*/ - TRANS_RX_ERR_WITH_LINK_BUF_OVERRUN, /* 0x107 */ - TRANS_RX_ERR_WITH_BREAK_TIMEOUT, /* 0x108 */ - TRANS_RX_ERR_WITH_BREAK_REQUEST, /* 0x109 */ - TRANS_RX_ERR_WITH_BREAK_RECEVIED, /* 0x10a */ - RESERVED1, /* 0x10b */ - TRANS_RX_ERR_WITH_CLOSE_NORMAL, /* 0x10c */ - TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE, /* 0x10d */ - TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT, /* 0x10e */ - TRANS_RX_ERR_WITH_CLOSE_COMINIT, /* 0x10f */ - TRANS_RX_ERR_WITH_DATA_LEN0, /* 0x110 for ssp/smp */ - TRANS_RX_ERR_WITH_BAD_HASH, /* 0x111 for ssp */ - /*IO_RX_ERR_WITH_FIS_TOO_SHORT, [> 0x111 <] for sata/stp */ - TRANS_RX_XRDY_WLEN_ZERO_ERR, /* 0x112 for ssp*/ - /*IO_RX_ERR_WITH_FIS_TOO_LONG, [> 0x112 <] for sata/stp */ - TRANS_RX_SSP_FRM_LEN_ERR, /* 0x113 for ssp */ - /*IO_RX_ERR_WITH_SATA_DEVICE_LOST, [> 0x113 <] for sata */ - RESERVED2, /* 0x114 */ - RESERVED3, /* 0x115 */ - RESERVED4, /* 0x116 */ - RESERVED5, /* 0x117 */ - TRANS_RX_ERR_WITH_BAD_FRM_TYPE, /* 0x118 */ - TRANS_RX_SMP_FRM_LEN_ERR, /* 0x119 */ - TRANS_RX_SMP_RESP_TIMEOUT_ERR, /* 0x11a */ - RESERVED6, /* 0x11b */ - RESERVED7, /* 0x11c */ - RESERVED8, /* 0x11d */ - RESERVED9, /* 0x11e */ - TRANS_RX_R_ERR, /* 0x11f */ + TRANS_RX_ERR_WITH_RXFRAME_CRC_ERR = TRANS_RX_FAIL_BASE, /* 0x20 */ + TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR, /* 0x21 for sata/stp */ + TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM, /* 0x22 for ssp/smp */ + /*IO_ERR_WITH_RXFIS_8B10B_CODE_ERR, [> 0x22 <] for sata/stp */ + TRANS_RX_ERR_WITH_RXFIS_DECODE_ERROR, /* 0x23 for sata/stp */ + TRANS_RX_ERR_WITH_RXFIS_CRC_ERR, /* 0x24 for sata/stp */ + TRANS_RX_ERR_WITH_RXFRAME_LENGTH_OVERRUN, /* 0x25 for smp */ + /*IO_ERR_WITH_RXFIS_TX SYNCP, [> 0x25 <] for sata/stp */ + TRANS_RX_ERR_WITH_RXFIS_RX_SYNCP, /* 0x26 for sata/stp*/ + TRANS_RX_ERR_WITH_LINK_BUF_OVERRUN, /* 0x27 */ + TRANS_RX_ERR_WITH_BREAK_TIMEOUT, /* 0x28 */ + TRANS_RX_ERR_WITH_BREAK
[PATCH 18/23] scsi: hisi_sas: rename hisi_sas_link_timeout_{enable, disable}_link
For consistency, remove the "hisi_sas_" prefix. Signed-off-by: John Garry --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 12 ++-- 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 45bd69d..e9c7188 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -549,7 +549,7 @@ enum { #define ERR_ON_RX_PHASE(err_phase) (err_phase == 0x10 || \ err_phase == 0x20 || err_phase == 0x40) -static void hisi_sas_link_timeout_disable_link(unsigned long data); +static void link_timeout_disable_link(unsigned long data); static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off) { @@ -1006,7 +1006,7 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba) upper_32_bits(hisi_hba->initial_fis_dma)); } -static void hisi_sas_link_timeout_enable_link(unsigned long data) +static void link_timeout_enable_link(unsigned long data) { struct hisi_hba *hisi_hba = (struct hisi_hba *)data; int i, reg_val; @@ -1020,11 +1020,11 @@ static void hisi_sas_link_timeout_enable_link(unsigned long data) } } - hisi_hba->timer.function = hisi_sas_link_timeout_disable_link; + hisi_hba->timer.function = link_timeout_disable_link; mod_timer(&hisi_hba->timer, jiffies + msecs_to_jiffies(900)); } -static void hisi_sas_link_timeout_disable_link(unsigned long data) +static void link_timeout_disable_link(unsigned long data) { struct hisi_hba *hisi_hba = (struct hisi_hba *)data; int i, reg_val; @@ -1038,14 +1038,14 @@ static void hisi_sas_link_timeout_disable_link(unsigned long data) } } - hisi_hba->timer.function = hisi_sas_link_timeout_enable_link; + hisi_hba->timer.function = link_timeout_enable_link; mod_timer(&hisi_hba->timer, jiffies + msecs_to_jiffies(100)); } static void set_link_timer_quirk(struct hisi_hba *hisi_hba) { hisi_hba->timer.data = (unsigned long)hisi_hba; - hisi_hba->timer.function = hisi_sas_link_timeout_disable_link; + hisi_hba->timer.function = link_timeout_disable_link; hisi_hba->timer.expires = jiffies + msecs_to_jiffies(1000); add_timer(&hisi_hba->timer); } -- 1.9.1
[PATCH 17/23] scsi: hisi_sas: handle PHY UP+DOWN simultaneous irq
From: Xiaofei Tan Handle the situation that PHY UP and DOWN irq happen simultaneously. There is no mechanism of SoC HW to ensure this situation will never happen. So, we add this handle just in case. Signed-off-by: Xiaofei Tan Signed-off-by: John Garry --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 56 +++--- 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 8e869d9..45bd69d 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -2285,7 +2285,7 @@ static int prep_abort_v2_hw(struct hisi_hba *hisi_hba, static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba) { - int i, res = 0; + int i, res = IRQ_HANDLED; u32 context, port_id, link_rate, hard_phy_linkrate; struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; struct asd_sas_phy *sas_phy = &phy->sas_phy; @@ -2373,7 +2373,6 @@ static bool check_any_wideports_v2_hw(struct hisi_hba *hisi_hba) static int phy_down_v2_hw(int phy_no, struct hisi_hba *hisi_hba) { - int res = 0; u32 phy_state, sl_ctrl, txid_auto; struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; struct hisi_sas_port *port = phy->port; @@ -2398,7 +2397,7 @@ static int phy_down_v2_hw(int phy_no, struct hisi_hba *hisi_hba) hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, CHL_INT0_NOT_RDY_MSK); hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 0); - return res; + return IRQ_HANDLED; } static irqreturn_t int_phy_updown_v2_hw(int irq_no, void *p) @@ -2406,35 +2405,58 @@ static irqreturn_t int_phy_updown_v2_hw(int irq_no, void *p) struct hisi_hba *hisi_hba = p; u32 irq_msk; int phy_no = 0; - irqreturn_t res = IRQ_HANDLED; irq_msk = (hisi_sas_read32(hisi_hba, HGC_INVLD_DQE_INFO) >> HGC_INVLD_DQE_INFO_FB_CH0_OFF) & 0x1ff; while (irq_msk) { if (irq_msk & 1) { - u32 irq_value = hisi_sas_phy_read32(hisi_hba, phy_no, - CHL_INT0); + u32 reg_value = hisi_sas_phy_read32(hisi_hba, phy_no, + CHL_INT0); + + switch (reg_value & (CHL_INT0_NOT_RDY_MSK | + CHL_INT0_SL_PHY_ENABLE_MSK)) { - if (irq_value & CHL_INT0_SL_PHY_ENABLE_MSK) + case CHL_INT0_SL_PHY_ENABLE_MSK: /* phy up */ - if (phy_up_v2_hw(phy_no, hisi_hba)) { - res = IRQ_NONE; - goto end; - } + if (phy_up_v2_hw(phy_no, hisi_hba) == + IRQ_NONE) + return IRQ_NONE; + break; - if (irq_value & CHL_INT0_NOT_RDY_MSK) + case CHL_INT0_NOT_RDY_MSK: /* phy down */ - if (phy_down_v2_hw(phy_no, hisi_hba)) { - res = IRQ_NONE; - goto end; + if (phy_down_v2_hw(phy_no, hisi_hba) == + IRQ_NONE) + return IRQ_NONE; + break; + + case (CHL_INT0_NOT_RDY_MSK | + CHL_INT0_SL_PHY_ENABLE_MSK): + reg_value = hisi_sas_read32(hisi_hba, + PHY_STATE); + if (reg_value & BIT(phy_no)) { + /* phy up */ + if (phy_up_v2_hw(phy_no, hisi_hba) == + IRQ_NONE) + return IRQ_NONE; + } else { + /* phy down */ + if (phy_down_v2_hw(phy_no, hisi_hba) == + IRQ_NONE) + return IRQ_NONE; } + break; + + default: + break; + } + } irq_msk >>= 1; phy_no++; } -end: - return res; + return IRQ_HANDLED; } static void phy_bcast_v2_hw(int phy_no, struct hisi_hba *hisi_hba) -- 1.9.1
[PATCH 04/23] scsi: hisi_sas: add softreset function for SATA disk
From: Xiang Chen Add softreset to clear IO after internal abort device for SATA disk. The SATA error handling for the controller is based on device internal abort and softreset function. The controller does not support internal abort for single IO, so we need to execute internal abort for device. Signed-off-by: Xiang Chen Signed-off-by: John Garry --- drivers/scsi/hisi_sas/Kconfig | 2 +- drivers/scsi/hisi_sas/hisi_sas_main.c | 70 -- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 3 +- 3 files changed, 69 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hisi_sas/Kconfig b/drivers/scsi/hisi_sas/Kconfig index d1dd161..ded2c20 100644 --- a/drivers/scsi/hisi_sas/Kconfig +++ b/drivers/scsi/hisi_sas/Kconfig @@ -2,7 +2,7 @@ config SCSI_HISI_SAS tristate "HiSilicon SAS" depends on HAS_DMA && HAS_IOMEM depends on ARM64 || COMPILE_TEST - select SCSI_SAS_LIBSAS + depends on SCSI_SAS_ATA select BLK_DEV_INTEGRITY help This driver supports HiSilicon's SAS HBA diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index b86a228..9d9f305 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -21,6 +21,7 @@ static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device, hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, struct domain_device *device, int abort_flag, int tag); +static int hisi_sas_softreset_ata_disk(struct domain_device *device); static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device) { @@ -720,7 +721,12 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device, task->dev = device; task->task_proto = device->tproto; - memcpy(&task->ssp_task, parameter, para_len); + if (dev_is_sata(device)) { + task->ata_task.device_control_reg_update = 1; + memcpy(&task->ata_task.fis, parameter, para_len); + } else { + memcpy(&task->ssp_task, parameter, para_len); + } task->task_done = hisi_sas_task_done; task->slow_task->timer.data = (unsigned long) task; @@ -742,8 +748,7 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device, /* Even TMF timed out, return direct. */ if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { - dev_err(dev, "abort tmf: TMF task[%d] timeout\n", - tmf->tag_of_task_to_be_managed); + dev_err(dev, "abort tmf: TMF task timeout\n"); if (task->lldd_task) { struct hisi_sas_slot *slot = task->lldd_task; @@ -803,6 +808,63 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device, return res; } +static void hisi_sas_fill_ata_reset_cmd(struct ata_device *dev, + bool reset, int pmp, u8 *fis) +{ + struct ata_taskfile tf; + + ata_tf_init(dev, &tf); + if (reset) + tf.ctl |= ATA_SRST; + else + tf.ctl &= ~ATA_SRST; + tf.command = ATA_CMD_DEV_RESET; + ata_tf_to_fis(&tf, pmp, 0, fis); +} + +static int hisi_sas_softreset_ata_disk(struct domain_device *device) +{ + u8 fis[20] = {0}; + struct ata_port *ap = device->sata_dev.ap; + struct ata_link *link; + int rc = TMF_RESP_FUNC_FAILED; + struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); + struct device *dev = &hisi_hba->pdev->dev; + int s = sizeof(struct host_to_dev_fis); + unsigned long flags; + + ata_for_each_link(link, ap, EDGE) { + int pmp = sata_srst_pmp(link); + + hisi_sas_fill_ata_reset_cmd(link->device, 1, pmp, fis); + rc = hisi_sas_exec_internal_tmf_task(device, fis, s, NULL); + if (rc != TMF_RESP_FUNC_COMPLETE) + break; + } + + if (rc == TMF_RESP_FUNC_COMPLETE) { + ata_for_each_link(link, ap, EDGE) { + int pmp = sata_srst_pmp(link); + + hisi_sas_fill_ata_reset_cmd(link->device, 0, pmp, fis); + rc = hisi_sas_exec_internal_tmf_task(device, fis, +s, NULL); + if (rc != TMF_RESP_FUNC_COMPLETE) + dev_err(dev, "ata disk de-reset failed\n"); + } + } else { + dev_err(dev, "ata disk reset failed\n"); + } + + if (rc == TMF_RESP_FUNC_COMPLETE) { +
[PATCH 19/23] scsi: hisi_sas: add hisi_sas_clear_nexus_ha()
Add function for upper-layer to reset controller when all else fails. Signed-off-by: John Garry Signed-off-by: Xiang Chen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 8 1 file changed, 8 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 3d63a24..f86263b 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1070,6 +1070,13 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun) return rc; } +static int hisi_sas_clear_nexus_ha(struct sas_ha_struct *sas_ha) +{ + struct hisi_hba *hisi_hba = sas_ha->lldd_ha; + + return hisi_sas_controller_reset(hisi_hba); +} + static int hisi_sas_query_task(struct sas_task *task) { struct scsi_lun lun; @@ -1368,6 +1375,7 @@ void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 old_state, .lldd_I_T_nexus_reset = hisi_sas_I_T_nexus_reset, .lldd_lu_reset = hisi_sas_lu_reset, .lldd_query_task= hisi_sas_query_task, + .lldd_clear_nexus_ha = hisi_sas_clear_nexus_ha, .lldd_port_formed = hisi_sas_port_formed, }; -- 1.9.1
[PATCH 03/23] scsi: hisi_sas: move PHY init to hisi_sas_scan_start()
Relocate the PHY init code from LLDD hw init path to hisi_sas_scan_start(). Signed-off-by: John Garry Signed-off-by: Xiang Chen --- drivers/scsi/hisi_sas/hisi_sas.h | 2 +- drivers/scsi/hisi_sas/hisi_sas_main.c | 9 +++-- drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 3 +-- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 3 +-- 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index fd76a02..2135de9 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -167,6 +167,7 @@ struct hisi_sas_hw { int device_id, int abort_flag, int tag_to_abort); int (*slot_complete)(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot, int abort); + void (*phys_init)(struct hisi_hba *hisi_hba); void (*phy_enable)(struct hisi_hba *hisi_hba, int phy_no); void (*phy_disable)(struct hisi_hba *hisi_hba, int phy_no); void (*phy_hard_reset)(struct hisi_hba *hisi_hba, int phy_no); @@ -195,7 +196,6 @@ struct hisi_hba { u8 sas_addr[SAS_ADDR_SIZE]; int n_phy; - int scan_finished; spinlock_t lock; struct timer_list timer; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index cbaef90..b86a228 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -493,12 +493,8 @@ static int hisi_sas_slave_configure(struct scsi_device *sdev) static void hisi_sas_scan_start(struct Scsi_Host *shost) { struct hisi_hba *hisi_hba = shost_priv(shost); - int i; - - for (i = 0; i < hisi_hba->n_phy; ++i) - hisi_sas_bytes_dmaed(hisi_hba, i); - hisi_hba->scan_finished = 1; + hisi_hba->hw->phys_init(hisi_hba); } static int hisi_sas_scan_finished(struct Scsi_Host *shost, unsigned long time) @@ -506,7 +502,8 @@ static int hisi_sas_scan_finished(struct Scsi_Host *shost, unsigned long time) struct hisi_hba *hisi_hba = shost_priv(shost); struct sas_ha_struct *sha = &hisi_hba->sha; - if (hisi_hba->scan_finished == 0) + /* Wait for PHY up interrupt to occur */ + if (time < HZ) return 0; sas_drain_work(sha); diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index 022ad10..43988eb 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -1847,8 +1847,6 @@ static int hisi_sas_v1_init(struct hisi_hba *hisi_hba) if (rc) return rc; - phys_init_v1_hw(hisi_hba); - return 0; } @@ -1862,6 +1860,7 @@ static int hisi_sas_v1_init(struct hisi_hba *hisi_hba) .get_free_slot = get_free_slot_v1_hw, .start_delivery = start_delivery_v1_hw, .slot_complete = slot_complete_v1_hw, + .phys_init = phys_init_v1_hw, .phy_enable = enable_phy_v1_hw, .phy_disable = disable_phy_v1_hw, .phy_hard_reset = phy_hard_reset_v1_hw, diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 53651cf..73e4f66 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -2864,8 +2864,6 @@ static int hisi_sas_v2_init(struct hisi_hba *hisi_hba) if (rc) return rc; - phys_init_v2_hw(hisi_hba); - return 0; } @@ -2965,6 +2963,7 @@ static int soft_reset_v2_hw(struct hisi_hba *hisi_hba) .get_free_slot = get_free_slot_v2_hw, .start_delivery = start_delivery_v2_hw, .slot_complete = slot_complete_v2_hw, + .phys_init = phys_init_v2_hw, .phy_enable = enable_phy_v2_hw, .phy_disable = disable_phy_v2_hw, .phy_hard_reset = phy_hard_reset_v2_hw, -- 1.9.1
[PATCH 13/23] scsi: hisi_sas: fix some sas_task.task_state_lock locking
Some more locking needs to be added/modified for when read-modify-writing sas_task.task_state_flags. Note: since we can attempt to grab this lock in interrupt context we should use irq variant of spin_lock. Signed-off-by: John Garry Signed-off-by: Xiang Chen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 13 ++--- drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 3 +++ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 7 +-- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 49cac22..f9ea5cc 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -188,6 +188,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, struct asd_sas_port *sas_port = device->port; struct device *dev = &hisi_hba->pdev->dev; int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx; + unsigned long flags; if (!sas_port) { struct task_status_struct *ts = &task->task_status; @@ -308,9 +309,9 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, } list_add_tail(&slot->entry, &sas_dev->list); - spin_lock(&task->task_state_lock); + spin_lock_irqsave(&task->task_state_lock, flags); task->task_state_flags |= SAS_TASK_AT_INITIATOR; - spin_unlock(&task->task_state_lock); + spin_unlock_irqrestore(&task->task_state_lock, flags); hisi_hba->slot_prep = slot; @@ -922,14 +923,11 @@ static int hisi_sas_abort_task(struct sas_task *task) return TMF_RESP_FUNC_FAILED; } - spin_lock_irqsave(&task->task_state_lock, flags); if (task->task_state_flags & SAS_TASK_STATE_DONE) { - spin_unlock_irqrestore(&task->task_state_lock, flags); rc = TMF_RESP_FUNC_COMPLETE; goto out; } - spin_unlock_irqrestore(&task->task_state_lock, flags); sas_dev->dev_status = HISI_SAS_DEV_EH; if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) { struct scsi_cmnd *cmnd = task->uldd_task; @@ -1127,6 +1125,7 @@ static int hisi_sas_query_task(struct sas_task *task) struct asd_sas_port *sas_port = device->port; struct hisi_sas_cmd_hdr *cmd_hdr_base; int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx; + unsigned long flags; if (unlikely(test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags))) return -EINVAL; @@ -1167,9 +1166,9 @@ static int hisi_sas_query_task(struct sas_task *task) list_add_tail(&slot->entry, &sas_dev->list); - spin_lock(&task->task_state_lock); + spin_lock_irqsave(&task->task_state_lock, flags); task->task_state_flags |= SAS_TASK_AT_INITIATOR; - spin_unlock(&task->task_state_lock); + spin_unlock_irqrestore(&task->task_state_lock, flags); hisi_hba->slot_prep = slot; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index 2f3e877..fc1c1b2 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -1288,6 +1288,7 @@ static int slot_complete_v1_hw(struct hisi_hba *hisi_hba, struct hisi_sas_complete_v1_hdr *complete_queue = hisi_hba->complete_hdr[slot->cmplt_queue]; struct hisi_sas_complete_v1_hdr *complete_hdr; + unsigned long flags; u32 cmplt_hdr_data; complete_hdr = &complete_queue[slot->cmplt_queue_slot]; @@ -1300,9 +1301,11 @@ static int slot_complete_v1_hw(struct hisi_hba *hisi_hba, device = task->dev; sas_dev = device->lldd_dev; + spin_lock_irqsave(&task->task_state_lock, flags); task->task_state_flags &= ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR); task->task_state_flags |= SAS_TASK_STATE_DONE; + spin_unlock_irqrestore(&task->task_state_lock, flags); memset(ts, 0, sizeof(*ts)); ts->resp = SAS_TASK_COMPLETE; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index f4d8200..2b6e64c 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -1737,6 +1737,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, hisi_hba->complete_hdr[slot->cmplt_queue]; struct hisi_sas_complete_v2_hdr *complete_hdr = &complete_queue[slot->cmplt_queue_slot]; + unsigned long flags; int aborted; if (unlikely(!task || !task->lldd_task || !task->dev)) @@ -1746,11 +1747,11 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, device = task->dev; sas_dev = device->lldd_dev; - spin_lock(&task->task_state_lock); + spin_lock_irqsave(&task->task_state_lock, flags); aborted = task->task_state_f
[PATCH 10/23] scsi: hisi_sas: hardreset for SATA disk in LU reset
When issuing an LU reset for a SATA target, issue an internal abort and a hard reset. Signed-off-by: John Garry Signed-off-by: Xiang Chen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 38 ++- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 36d4e5a..19f2892 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1037,23 +1037,43 @@ static int hisi_sas_I_T_nexus_reset(struct domain_device *device) static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun) { - struct hisi_sas_tmf_task tmf_task; struct hisi_sas_device *sas_dev = device->lldd_dev; struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); struct device *dev = &hisi_hba->pdev->dev; unsigned long flags; int rc = TMF_RESP_FUNC_FAILED; - tmf_task.tmf = TMF_LU_RESET; sas_dev->dev_status = HISI_SAS_DEV_EH; - rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task); - if (rc == TMF_RESP_FUNC_COMPLETE) { - spin_lock_irqsave(&hisi_hba->lock, flags); - hisi_sas_release_task(hisi_hba, device); - spin_unlock_irqrestore(&hisi_hba->lock, flags); - } + if (dev_is_sata(device)) { + struct sas_phy *phy; + + /* Clear internal IO and then hardreset */ + rc = hisi_sas_internal_task_abort(hisi_hba, device, + HISI_SAS_INT_ABT_DEV, 0); + if (rc == TMF_RESP_FUNC_FAILED) + goto out; - /* If failed, fall-through I_T_Nexus reset */ + phy = sas_get_local_phy(device); + + rc = sas_phy_reset(phy, 1); + + if (rc == 0) { + spin_lock_irqsave(&hisi_hba->lock, flags); + hisi_sas_release_task(hisi_hba, device); + spin_unlock_irqrestore(&hisi_hba->lock, flags); + } + sas_put_local_phy(phy); + } else { + struct hisi_sas_tmf_task tmf_task = { .tmf = TMF_LU_RESET }; + + rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task); + if (rc == TMF_RESP_FUNC_COMPLETE) { + spin_lock_irqsave(&hisi_hba->lock, flags); + hisi_sas_release_task(hisi_hba, device); + spin_unlock_irqrestore(&hisi_hba->lock, flags); + } + } +out: dev_err(dev, "lu_reset: for device[%llx]:rc= %d\n", sas_dev->device_id, rc); return rc; -- 1.9.1
[PATCH 20/23] scsi: hisi_sas: release SMP slot in lldd_abort_task
From: Xiang Chen When an SMP task timeouts, it will call lldd_abort_task to release the associated slot, and then will release the sas_task. Currently in lldd_abort_task, if we fail to internally abort IO, then the slot of SMP IO is not released, but sas_task will still be later released, so the slot's sas_task is NULL, which will cause NULL pointer when hisi_sas_slot_task_free happens later. To resolve, check the return value of internal abort, and release the slot if it failed. Signed-off-by: Xiang Chen Signed-off-by: John Garry --- drivers/scsi/hisi_sas/hisi_sas_main.c | 9 +++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index f86263b..1391f2d 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -962,8 +962,13 @@ static int hisi_sas_abort_task(struct sas_task *task) struct hisi_sas_slot *slot = task->lldd_task; u32 tag = slot->idx; - hisi_sas_internal_task_abort(hisi_hba, device, -HISI_SAS_INT_ABT_CMD, tag); + rc = hisi_sas_internal_task_abort(hisi_hba, device, +HISI_SAS_INT_ABT_CMD, tag); + if (rc == TMF_RESP_FUNC_FAILED) { + spin_lock_irqsave(&hisi_hba->lock, flags); + hisi_sas_do_release_task(hisi_hba, task, slot); + spin_unlock_irqrestore(&hisi_hba->lock, flags); + } } out: -- 1.9.1
[PATCH 12/23] scsi: hisi_sas: free slots after hardreset
From: Xiang Chen After hardreset, we clear up IOs of remote disks, so we need to free those slots in LLDD. Signed-off-by: Xiang Chen Signed-off-by: John Garry --- drivers/scsi/hisi_sas/hisi_sas_main.c | 11 ++- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 19f2892..49cac22 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1028,11 +1028,12 @@ static int hisi_sas_I_T_nexus_reset(struct domain_device *device) rc = hisi_sas_debug_I_T_nexus_reset(device); - spin_lock_irqsave(&hisi_hba->lock, flags); - hisi_sas_release_task(hisi_hba, device); - spin_unlock_irqrestore(&hisi_hba->lock, flags); - - return 0; + if (rc == TMF_RESP_FUNC_COMPLETE) { + spin_lock_irqsave(&hisi_hba->lock, flags); + hisi_sas_release_task(hisi_hba, device); + spin_unlock_irqrestore(&hisi_hba->lock, flags); + } + return rc; } static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun) -- 1.9.1
[PATCH 16/23] scsi: hisi_sas: some modifications to v2 hw reg init values
This patch includes: (1) Disable transport layer retry (2) Support CQ time and count interrupt coal (3) fix link FIFO full issue Signed-off-by: Xiang Chen Signed-off-by: Zhao Nenglong Signed-off-by: John Garry --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 12 ++-- 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 66a458b..8e869d9 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -893,7 +893,7 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba) (u32)((1ULL << hisi_hba->queue_count) - 1)); hisi_sas_write32(hisi_hba, AXI_USER1, 0xc000); hisi_sas_write32(hisi_hba, AXI_USER2, 0x1); - hisi_sas_write32(hisi_hba, HGC_SAS_TXFAIL_RETRY_CTRL, 0x108); + hisi_sas_write32(hisi_hba, HGC_SAS_TXFAIL_RETRY_CTRL, 0x0); hisi_sas_write32(hisi_hba, HGC_SAS_TX_OPEN_FAIL_RETRY_CTRL, 0x7FF); hisi_sas_write32(hisi_hba, OPENA_WT_CONTI_TIME, 0x1); hisi_sas_write32(hisi_hba, I_T_NEXUS_LOSS_TIME, 0x1F4); @@ -902,9 +902,9 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba) hisi_sas_write32(hisi_hba, CFG_AGING_TIME, 0x1); hisi_sas_write32(hisi_hba, HGC_ERR_STAT_EN, 0x1); hisi_sas_write32(hisi_hba, HGC_GET_ITV_TIME, 0x1); - hisi_sas_write32(hisi_hba, INT_COAL_EN, 0x1); - hisi_sas_write32(hisi_hba, OQ_INT_COAL_TIME, 0x1); - hisi_sas_write32(hisi_hba, OQ_INT_COAL_CNT, 0x1); + hisi_sas_write32(hisi_hba, INT_COAL_EN, 0xc); + hisi_sas_write32(hisi_hba, OQ_INT_COAL_TIME, 0x60); + hisi_sas_write32(hisi_hba, OQ_INT_COAL_CNT, 0x3); hisi_sas_write32(hisi_hba, ENT_INT_COAL_TIME, 0x1); hisi_sas_write32(hisi_hba, ENT_INT_COAL_CNT, 0x1); hisi_sas_write32(hisi_hba, OQ_INT_SRC, 0x0); @@ -927,14 +927,14 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba) hisi_sas_phy_write32(hisi_hba, i, SL_TOUT_CFG, 0x7d7d7d7d); hisi_sas_phy_write32(hisi_hba, i, SL_CONTROL, 0x0); hisi_sas_phy_write32(hisi_hba, i, TXID_AUTO, 0x2); - hisi_sas_phy_write32(hisi_hba, i, DONE_RECEIVED_TIME, 0x10); + hisi_sas_phy_write32(hisi_hba, i, DONE_RECEIVED_TIME, 0x8); hisi_sas_phy_write32(hisi_hba, i, CHL_INT0, 0x); hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, 0x); hisi_sas_phy_write32(hisi_hba, i, CHL_INT2, 0xfff87fff); hisi_sas_phy_write32(hisi_hba, i, RXOP_CHECK_CFG_H, 0x1000); hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0x); hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8bff); - hisi_sas_phy_write32(hisi_hba, i, SL_CFG, 0x23f801fc); + hisi_sas_phy_write32(hisi_hba, i, SL_CFG, 0x13f801fc); hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL_RDY_MSK, 0x0); hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_NOT_RDY_MSK, 0x0); hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_DWS_RESET_MSK, 0x0); -- 1.9.1
[PATCH 21/23] scsi: hisi_sas: check hisi_sas_lu_reset() error message
Unless we actually get some sort of failure in hisi_sas_lu_reset(), don't print a message. Signed-off-by: John Garry Signed-off-by: Xiang Chen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 1391f2d..dcceff9 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1070,8 +1070,9 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun) } } out: - dev_err(dev, "lu_reset: for device[%llx]:rc= %d\n", - sas_dev->device_id, rc); + if (rc != TMF_RESP_FUNC_COMPLETE) + dev_err(dev, "lu_reset: for device[%llx]:rc= %d\n", +sas_dev->device_id, rc); return rc; } -- 1.9.1
[PATCH 09/23] scsi: hisi_sas: modify hisi_sas_abort_task() for SSP
Currently an internal abort is executed regardless of the result of the TMF. We should also check the result of the internal abort to see if we should free the slot. So change the status code STAT_IO_COMPLETE to TMF_RESP_FUNC_SUCC, meaning the slot has been successfully aborted. Signed-off-by: John Garry Signed-off-by: Xiang Chen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 28 ++-- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 2 +- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 00068d2..36d4e5a 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -935,6 +935,7 @@ static int hisi_sas_abort_task(struct sas_task *task) struct scsi_cmnd *cmnd = task->uldd_task; struct hisi_sas_slot *slot = task->lldd_task; u32 tag = slot->idx; + int rc2; int_to_scsilun(cmnd->device->lun, &lun); tmf_task.tmf = TMF_ABORT_TASK; @@ -943,21 +944,22 @@ static int hisi_sas_abort_task(struct sas_task *task) rc = hisi_sas_debug_issue_ssp_tmf(task->dev, lun.scsi_lun, &tmf_task); - /* if successful, clear the task and callback forwards.*/ - if (rc == TMF_RESP_FUNC_COMPLETE) { + rc2 = hisi_sas_internal_task_abort(hisi_hba, device, + HISI_SAS_INT_ABT_CMD, tag); + /* +* If the TMF finds that the IO is not in the device and also +* the internal abort does not succeed, then it is safe to +* free the slot. +* Note: if the internal abort succeeds then the slot +* will have already been completed +*/ + if (rc == TMF_RESP_FUNC_COMPLETE && rc2 != TMF_RESP_FUNC_SUCC) { if (task->lldd_task) { - struct hisi_sas_slot *slot; - - slot = &hisi_hba->slot_info - [tmf_task.tag_of_task_to_be_managed]; spin_lock_irqsave(&hisi_hba->lock, flags); - hisi_hba->hw->slot_complete(hisi_hba, slot); + hisi_sas_do_release_task(hisi_hba, task, slot); spin_unlock_irqrestore(&hisi_hba->lock, flags); } } - - hisi_sas_internal_task_abort(hisi_hba, device, -HISI_SAS_INT_ABT_CMD, tag); } else if (task->task_proto & SAS_PROTOCOL_SATA || task->task_proto & SAS_PROTOCOL_STP) { if (task->dev->dev_type == SAS_SATA_DEV) { @@ -1220,6 +1222,12 @@ static int hisi_sas_query_task(struct sas_task *task) goto exit; } + if (task->task_status.resp == SAS_TASK_COMPLETE && + task->task_status.stat == TMF_RESP_FUNC_SUCC) { + res = TMF_RESP_FUNC_SUCC; + goto exit; + } + /* TMF timed out, return direct. */ if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index a35f881..ad5a7e6 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -1766,7 +1766,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, goto out; case STAT_IO_COMPLETE: /* internal abort command complete */ - ts->stat = TMF_RESP_FUNC_COMPLETE; + ts->stat = TMF_RESP_FUNC_SUCC; goto out; case STAT_IO_NO_DEVICE: ts->stat = TMF_RESP_FUNC_COMPLETE; -- 1.9.1
[PATCH 23/23] scsi: hisi_sas: add is_sata_phy_v2_hw()
From: Xiaofei Tan Add helper function is_sata_phy_v2_hw() to judge whether the attached device is SATA disk for a root PHY. Signed-off-by: Xiaofei Tan Signed-off-by: John Garry --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 17 + 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index e9c7188..a3af380 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -1075,6 +1075,17 @@ static void enable_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no) hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg); } +static bool is_sata_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no) +{ + u32 context; + + context = hisi_sas_read32(hisi_hba, PHY_CONTEXT); + if (context & (1 << phy_no)) + return true; + + return false; +} + static void disable_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no) { u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG); @@ -2286,7 +2297,7 @@ static int prep_abort_v2_hw(struct hisi_hba *hisi_hba, static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba) { int i, res = IRQ_HANDLED; - u32 context, port_id, link_rate, hard_phy_linkrate; + u32 port_id, link_rate, hard_phy_linkrate; struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; struct asd_sas_phy *sas_phy = &phy->sas_phy; struct device *dev = &hisi_hba->pdev->dev; @@ -2295,9 +2306,7 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba) hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 1); - /* Check for SATA dev */ - context = hisi_sas_read32(hisi_hba, PHY_CONTEXT); - if (context & (1 << phy_no)) + if (is_sata_phy_v2_hw(hisi_hba, phy_no)) goto end; if (phy_no == 8) { -- 1.9.1
[PATCH 11/23] scsi: hisi_sas: check for SAS_TASK_STATE_ABORTED in slot complete
Check in slot_complete_v2_hw() for whether a task has already been completed by upper layer. Signed-off-by: John Garry Reviewed-by: Xiang Chen --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 10 ++ 1 file changed, 10 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index ad5a7e6..f4d8200 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -1737,6 +1737,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, hisi_hba->complete_hdr[slot->cmplt_queue]; struct hisi_sas_complete_v2_hdr *complete_hdr = &complete_queue[slot->cmplt_queue_slot]; + int aborted; if (unlikely(!task || !task->lldd_task || !task->dev)) return -EINVAL; @@ -1745,12 +1746,21 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, device = task->dev; sas_dev = device->lldd_dev; + spin_lock(&task->task_state_lock); + aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED; task->task_state_flags &= ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR); + spin_unlock(&task->task_state_lock); memset(ts, 0, sizeof(*ts)); ts->resp = SAS_TASK_COMPLETE; + if (unlikely(aborted)) { + ts->stat = SAS_ABORTED_TASK; + hisi_sas_slot_task_free(hisi_hba, task, slot); + return -1; + } + if (unlikely(!sas_dev)) { dev_dbg(dev, "slot complete: port has no device\n"); ts->stat = SAS_PHY_DOWN; -- 1.9.1
[PATCH 07/23] scsi: hisi_sas: only reset link for PHY_FUNC_LINK_RESET
We currently do a hard reset for a link reset. Change this to do a link reset only. Signed-off-by: John Garry Signed-off-by: Xiang Chen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 7c1fb75..00068d2 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -659,8 +659,9 @@ static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func, break; case PHY_FUNC_LINK_RESET: + hisi_hba->hw->phy_disable(hisi_hba, phy_no); + msleep(100); hisi_hba->hw->phy_enable(hisi_hba, phy_no); - hisi_hba->hw->phy_hard_reset(hisi_hba, phy_no); break; case PHY_FUNC_DISABLE: -- 1.9.1
[PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements
This patchset introduces a range of error handling and other misc improvements for the HiSilicon SAS controller, including: - controller reset function - softreset for SATA error handling - fixes for slot free'ing - v2 hw error handling improvements - and other misc, more minor stuff John Garry (14): scsi: hisi_sas: add to_hisi_sas_port() scsi: hisi_sas: move PHY init to hisi_sas_scan_start() scsi: hisi_sas: remove hisi_sas_port_deformed() scsi: hisi_sas: error hisi_sas_task_prep() when port down scsi: hisi_sas: only reset link for PHY_FUNC_LINK_RESET scsi: hisi_sas: modify hisi_sas_abort_task() for SSP scsi: hisi_sas: hardreset for SATA disk in LU reset scsi: hisi_sas: check for SAS_TASK_STATE_ABORTED in slot complete scsi: hisi_sas: fix some sas_task.task_state_lock locking scsi: hisi_sas: remove task free'ing for timeouts scsi: hisi_sas: some modifications to v2 hw reg init values scsi: hisi_sas: rename hisi_sas_link_timeout_{enable, disable}_link scsi: hisi_sas: add hisi_sas_clear_nexus_ha() scsi: hisi_sas: check hisi_sas_lu_reset() error message Xiang Chen (7): scsi: hisi_sas: add controller reset scsi: hisi_sas: add softreset function for SATA disk scsi: hisi_sas: modify error handling for v2 hw scsi: hisi_sas: free slots after hardreset scsi: hisi_sas: process error codes according to their priority scsi: hisi_sas: release SMP slot in lldd_abort_task scsi: hisi_sas: use dev_is_sata to identify SATA or SAS disk Xiaofei Tan (2): scsi: hisi_sas: handle PHY UP+DOWN simultaneous irq scsi: hisi_sas: add is_sata_phy_v2_hw() drivers/scsi/hisi_sas/Kconfig | 2 +- drivers/scsi/hisi_sas/hisi_sas.h | 15 +- drivers/scsi/hisi_sas/hisi_sas_main.c | 436 +- drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 19 +- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 789 - 5 files changed, 925 insertions(+), 336 deletions(-) -- 1.9.1
[Bug 176951] boot fails unless acpi=off Acer Travelmate X-349
https://bugzilla.kernel.org/show_bug.cgi?id=176951 Alan Welsh (itsallene...@gmail.com) changed: What|Removed |Added CC||itsallene...@gmail.com --- Comment #22 from Alan Welsh (itsallene...@gmail.com) --- I can confirm the system does not boot unless either: a) passed with the acpi=off parameter in legacy mode or, b) booted in UEFI mode. As for (a): This issue is resolved with grsecurity kernel. As for (b): UEFI cannot be used because all linux bootloaders fail to be recognized by the firmware. There is not one distribution which boots after installation. The bootloader never loads. Only receive error message "disk not found" or something to that effect. Acer swift 3 (bios 1.08) All x64 flavors from: Ubuntu, Fedora, Gentoo, Arch, opensuse. -- You are receiving this mail because: You are watching the assignee of the bug.
[PATCH] scsi: fcoe: sanity check string size for store_ctrl_mode option
From: Colin Ian King Reading and writing to mode[count - 1] implies the count should not be less than 1 so add a sanity check for this. Detected with CoverityScan, CID#1357345 ("Overflowed array index write") Signed-off-by: Colin Ian King --- drivers/scsi/fcoe/fcoe_sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/fcoe/fcoe_sysfs.c b/drivers/scsi/fcoe/fcoe_sysfs.c index 9cf3d56296ab..e298240c728c 100644 --- a/drivers/scsi/fcoe/fcoe_sysfs.c +++ b/drivers/scsi/fcoe/fcoe_sysfs.c @@ -288,7 +288,7 @@ static ssize_t store_ctlr_mode(struct device *dev, struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev); char mode[FCOE_MAX_MODENAME_LEN + 1]; - if (count > FCOE_MAX_MODENAME_LEN) + if (count < 1 || count > FCOE_MAX_MODENAME_LEN) return -EINVAL; strncpy(mode, buf, count); -- 2.11.0
Re: [PATCH] scsi: ufs: remove the duplicated checking for supporting clkscaling
Hi, On Tuesday, March 21, 2017 09:19:57 PM Jaehoon Chung wrote: > There are same conditions for checking whether supporting clkscaling or > not. > When ufshcd is supporting clkscaling, active_reqs should be decreased by > two. I guess you meant "one" here, not "two"? > Signed-off-by: Jaehoon Chung > --- > drivers/scsi/ufs/ufshcd.c | 2 -- > 1 file changed, 2 deletions(-) > > diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c > index dc6efbd..f2cbc71 100644 > --- a/drivers/scsi/ufs/ufshcd.c > +++ b/drivers/scsi/ufs/ufshcd.c > @@ -4598,8 +4598,6 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba > *hba, > } > if (ufshcd_is_clkscaling_supported(hba)) > hba->clk_scaling.active_reqs--; > - if (ufshcd_is_clkscaling_supported(hba)) > - hba->clk_scaling.active_reqs--; > } > > /* clear corresponding bits of completed commands */ Best regards, -- Bartlomiej Zolnierkiewicz Samsung R&D Institute Poland Samsung Electronics
[PATCH] qla4xxx: drop redundant init_completion
The redundant init_completion() here seems to be a cut&past error as struct scsi_qla_host only has 4 completion elements to initialize, thus the duplicate init_completion(disable_acb_comp) is simply removed. Signed-off-by: Nicholas Mc Guire --- Found by experimental coccinelle script: ./drivers/scsi/qla4xxx/ql4_os.c:8667:1-16: WARNING: possible duplicate init_completion checking struct scsi_qla_host in drivers/scsi/qla4xxx/ql4_def.h:457 "Linux Host Adapter structure" it contain only the following 4 completion objects: struct completion disable_acb_comp; struct completion idc_comp; struct completion link_up_comp; struct completion mbx_intr_comp; so it seems the double initialization of disable_acb_comp was just a cut&past but and no omission of some other completion object - thus the second initialization is simply removed. Patch was only compile tested with: x86_64_defconfig + SCSI_LOWLEVEL=y, CONFIG_SCSI_QLA_ISCSI=m (...quite a few sparse and coccinelle errors/warnings during build-tests) Patch is against 4.11-rc3 (localversion-next is next-20170322) drivers/scsi/qla4xxx/ql4_os.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index ac52150..64c6fa5 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -8663,9 +8663,8 @@ static int qla4xxx_probe_adapter(struct pci_dev *pdev, init_completion(&ha->mbx_intr_comp); init_completion(&ha->disable_acb_comp); init_completion(&ha->idc_comp); init_completion(&ha->link_up_comp); - init_completion(&ha->disable_acb_comp); spin_lock_init(&ha->hardware_lock); spin_lock_init(&ha->work_lock); -- 2.1.4
Re: [PATCH] scsi: lpfc: fix linking against modular NVMe support
On Wed, Mar 22, 2017 at 3:25 AM, James Smart wrote: > > On 3/21/2017 7:23 PM, James Smart wrote: >> >> Arnd, >> >> All of the build issues, including building as modules, should have been >> resolved by the following patch: >> http://www.spinics.net/lists/linux-scsi/msg106102.html >> >> Am I missing something ? > > Note: the patch I referenced > (http://www.spinics.net/lists/linux-scsi/msg106102.html) replaced the one I > think you referenced below > (http://www.spinics.net/lists/linux-scsi/msg106024.html) The build error I fixed was on yesterday's linux-next, which has the http://www.spinics.net/lists/linux-scsi/msg106102.html patch, this is the one I referenced as 7d7080335f8d ("scsi: lpfc: Finalize Kconfig options for nvme"). The earlier version from linux-next-20170310 (there was no linux-next last week) had the same bug but needed a different workaround: diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 4bf55b5d78be..52245eb83295 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -1256,12 +1256,14 @@ config SCSI_LPFC_DEBUG_FS config LPFC_NVME_INITIATOR bool "Emulex LightPulse Fibre Channel NVME Initiator Support" depends on SCSI_LPFC && NVME_FC + depends on SCSI_LPFC=m || NVME_FC=y ---help--- This enables NVME Initiator support in the Emulex lpfc driver. config LPFC_NVME_TARGET bool "Emulex LightPulse Fibre Channel NVME Initiator Support" depends on SCSI_LPFC && NVME_TARGET_FC + depends on SCSI_LPFC=m || NVME_TARGET_FC=y ---help--- This enables NVME Target support in the Emulex lpfc driver. Target enablement must still be enabled on a per adapter As a side-note, the patch introduces a slightly unusual construct using #if (IS_ENABLED(CONFIG_NVME_FC)). This can usually expressed in a more readable way like this: --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -2190,13 +2192,12 @@ lpfc_nvme_create_localport(struct lpfc_vport *vport) void lpfc_nvme_destroy_localport(struct lpfc_vport *vport) { -#if (IS_ENABLED(CONFIG_NVME_FC)) struct nvme_fc_local_port *localport; struct lpfc_nvme_lport *lport; struct lpfc_nvme_rport *rport = NULL, *rport_next = NULL; int ret; - if (vport->nvmei_support == 0) + if (!IS_ENABLED(CONFIG_NVME_FC) || vport->nvmei_support == 0) return; localport = vport->localport; @@ -2243,7 +2244,6 @@ lpfc_nvme_destroy_localport(struct lpfc_vport *vport) "Failed, status x%x\n", ret); } -#endif } void You could also use if(IS_REACHABLE()) here to work around the link error when CONFIG_NVME_FC=m, but that would make things a little more confusing for users as it is not immediately clear why it fails to work at runtime. Arnd