Re: [PATCH] scsi: hisi_sas: add missing break in switch statement
On 28/03/2017 12:12, Colin King wrote: From: Colin Ian King <colin.k...@canonical.com> It appears that a break in the TRANS_TX_OPEN_CNX_ERR_NO_DESTINATION case got accidentally removed in an earlier commit, as it stands, the ts->stat and ts->open_rej_reason are being updated twice for this case which looks incorrect. Fix this by adding in the missing break statement. Detected by CoverityScan, CID#1422110 ("Missing break in switch") Fixes: 634a9585f49c7 ("scsi: hisi_sas: process error codes according to their priority") Signed-off-by: Colin Ian King <colin.k...@canonical.com> Thanks, checkpatch.pl would normally catch this but it was hidden in the formatted patch Signed-off-by: John Garry <john.ga...@huawei.com>
[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 <john.ga...@huawei.com> --- 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 <chenxian...@hisilicon.com> 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 <chenxian...@hisilicon.com> Signed-off-by: Xiaofei Tan <tanxiao...@huawei.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- 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 = _hba->pdev->dev; + if (unlikely(test_bit(HISI_SAS_RESET_BIT, _hba->flags))) + return -EINVAL; + /* protect task_prep and start_delivery sequence */ spin_lock_irqsave(_hba->lock, flags); rc = hisi_sas_task_prep(task, hisi_hba, is_tmf, tmf, ); @@ -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 = _hba->phy[i]; + struct asd_sas_phy *sas_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, _hba->flags)) { + struct device *dev = _hba->pdev->dev; + struct sas_ha_struct *sas_ha = _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(_hba->lock, flags); + hisi_sas_release_tasks(hisi_hba); + spin_unlock_irqrestore(_hba->lock, flags); + + sas_ha->notify_ha_event(sas_ha, HAE_RESET); + dev_dbg(dev, "controller reset successful!\n"); + } else + return -1; +
[PATCH 08/23] scsi: hisi_sas: modify error handling for v2 hw
From: Xiang Chen <chenxian...@hisilicon.com> 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 <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- 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, >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 <john.ga...@huawei.com> Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> --- 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(>entry, >list); + list_add_tail(>entry, _dev->list); spin_lock(>task_state_lock); task->task_state_flags |= SAS_TASK_AT_INITIATOR; spin_unlock(>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(_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(_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 = _hba->pdev->dev; + struct task_status_struct *ts; + unsigned long flags; - phy = _hba->phy[phy_no]; - port = phy->port; - if (!port) + if (!task) return; - list_for_each_entry_safe(slot, slot2, >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_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_state_lock, flags); + task->task_state_flags
[PATCH 22/23] scsi: hisi_sas: use dev_is_sata to identify SATA or SAS disk
From: Xiang Chen <chenxian...@hisilicon.com> 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 <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- 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 <john.ga...@huawei.com> Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> --- 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 = _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_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 = _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 = _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, _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 = _hba->pdev->dev; u64 qw0, device_id = sas_dev->device_id; struct hisi_sas_itct *itct = _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_h
[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 <john.ga...@huawei.com> Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> --- 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 <chenxian...@hisilicon.com> 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 <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- 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_
[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 <john.ga...@huawei.com> --- 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(_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(_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(_hba->timer); } -- 1.9.1
[PATCH 17/23] scsi: hisi_sas: handle PHY UP+DOWN simultaneous irq
From: Xiaofei Tan <tanxiao...@huawei.com> 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 <tanxiao...@huawei.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- 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 = _hba->phy[phy_no]; struct asd_sas_phy *sas_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 = _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 <chenxian...@hisilicon.com> 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 <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- 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(>ssp_task, parameter, para_len); + if (dev_is_sata(device)) { + task->ata_task.device_control_reg_update = 1; + memcpy(>ata_task.fis, parameter, para_len); + } else { + memcpy(>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, ); + if (reset) + tf.ctl |= ATA_SRST; + else + tf.ctl &= ~ATA_SRST; + tf.command = ATA_CMD_DEV_RESET; + ata_tf_to_fis(, 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 = _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_
[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 <john.ga...@huawei.com> Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> --- 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 <john.ga...@huawei.com> Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> --- 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 = _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 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 <john.ga...@huawei.com> Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> --- 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 = _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, _task); - if (rc == TMF_RESP_FUNC_COMPLETE) { - spin_lock_irqsave(_hba->lock, flags); - hisi_sas_release_task(hisi_hba, device); - spin_unlock_irqrestore(_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(_hba->lock, flags); + hisi_sas_release_task(hisi_hba, device); + spin_unlock_irqrestore(_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, _task); + if (rc == TMF_RESP_FUNC_COMPLETE) { + spin_lock_irqsave(_hba->lock, flags); + hisi_sas_release_task(hisi_hba, device); + spin_unlock_irqrestore(_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 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 <john.ga...@huawei.com> Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> --- 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 = _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_status; @@ -308,9 +309,9 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, } list_add_tail(>entry, _dev->list); - spin_lock(>task_state_lock); + spin_lock_irqsave(>task_state_lock, flags); task->task_state_flags |= SAS_TASK_AT_INITIATOR; - spin_unlock(>task_state_lock); + spin_unlock_irqrestore(>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_state_lock, flags); if (task->task_state_flags & SAS_TASK_STATE_DONE) { - spin_unlock_irqrestore(>task_state_lock, flags); rc = TMF_RESP_FUNC_COMPLETE; goto out; } - spin_unlock_irqrestore(>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, _hba->flags))) return -EINVAL; @@ -1167,9 +1166,9 @@ static int hisi_sas_query_task(struct sas_task *task) list_add_tail(>entry, _dev->list); - spin_lock(>task_state_lock); + spin_lock_irqsave(>task_state_lock, flags); task->task_state_flags |= SAS_TASK_AT_INITIATOR; - spin_unlock(>task_state_lock); + spin_unlock_irqrestore(>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 = _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_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_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 = _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_
[PATCH 20/23] scsi: hisi_sas: release SMP slot in lldd_abort_task
From: Xiang Chen <chenxian...@hisilicon.com> 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 <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- 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(_hba->lock, flags); + hisi_sas_do_release_task(hisi_hba, task, slot); + spin_unlock_irqrestore(_hba->lock, flags); + } } out: -- 1.9.1
[PATCH 12/23] scsi: hisi_sas: free slots after hardreset
From: Xiang Chen <chenxian...@hisilicon.com> After hardreset, we clear up IOs of remote disks, so we need to free those slots in LLDD. Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- 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(_hba->lock, flags); - hisi_sas_release_task(hisi_hba, device); - spin_unlock_irqrestore(_hba->lock, flags); - - return 0; + if (rc == TMF_RESP_FUNC_COMPLETE) { + spin_lock_irqsave(_hba->lock, flags); + hisi_sas_release_task(hisi_hba, device); + spin_unlock_irqrestore(_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 <chenxian...@hisilicon.com> Signed-off-by: Zhao Nenglong <zhaonengl...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- 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 <john.ga...@huawei.com> Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> --- 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 <john.ga...@huawei.com> Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> --- 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, ); 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, _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 = _hba->slot_info - [tmf_task.tag_of_task_to_be_managed]; spin_lock_irqsave(_hba->lock, flags); - hisi_hba->hw->slot_complete(hisi_hba, slot); + hisi_sas_do_release_task(hisi_hba, task, slot); spin_unlock_irqrestore(_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 <tanxiao...@huawei.com> 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 <tanxiao...@huawei.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- 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 = _hba->phy[phy_no]; struct asd_sas_phy *sas_phy = >sas_phy; struct device *dev = _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 <john.ga...@huawei.com> Reviewed-by: Xiang Chen <chenxian...@hisilicon.com> --- 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 = _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_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_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 <john.ga...@huawei.com> Signed-off-by: Xiang Chen <chenxi...@hisilicon.com> --- 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
Re: [PATCH] scsi: libsas: fix ata xfer length
On 19/03/2017 17:21, Martin K. Petersen wrote: John Garry <john.ga...@huawei.com> writes: John, The total ata xfer length may not be calculated properly, in that we do not use the proper method to get an sg element dma length. According to the code comment, sg_dma_len() should be used after dma_map_sg() is called. This issue was found by turning on the SMMUv3 in front of the hisi_sas controller in hip07. Multiple sg elements were being combined into a single element, but the original first element length was being use as the total xfer length. I should have added this originally to the changelog: Fixes: ff2aeb1eb64c8a4770a6 ("libata: convert to chained sg") BTW, I am surprised this issue has not been seen in almost 10 years, but we cannot attach a SATA disk when SMMU enabled without it. Cheers, John Applied to 4.11/scsi-fixes.
[PATCH] scsi: libsas: fix ata xfer length
The total ata xfer length may not be calculated properly, in that we do not use the proper method to get an sg element dma length. According to the code comment, sg_dma_len() should be used after dma_map_sg() is called. This issue was found by turning on the SMMUv3 in front of the hisi_sas controller in hip07. Multiple sg elements were being combined into a single element, but the original first element length was being use as the total xfer length. Signed-off-by: John Garry <john.ga...@huawei.com> diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 763f012..87f5e694 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -221,7 +221,7 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc) task->num_scatter = qc->n_elem; } else { for_each_sg(qc->sg, sg, qc->n_elem, si) - xfer += sg->length; + xfer += sg_dma_len(sg); task->total_xfer_len = xfer; task->num_scatter = si; -- 1.9.1
[PATCH v2 5/7] scsi: hisi_sas: downgrade internal abort exit print
Downgrade the exit print in hisi_sas_internal_task_abort() to dbg level, as info is not required. Signed-off-by: John Garry <john.ga...@huawei.com> Reviewed-by: Xiang Chen <chenxian...@hisilicon.com> Reviewed-by: Johannes Thumshirn <jthumsh...@suse.de> --- 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 eee7ae2..b2782ce 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1121,7 +1121,7 @@ static int hisi_sas_query_task(struct sas_task *task) } exit: - dev_info(dev, "internal task abort: task to dev %016llx task=%p " + dev_dbg(dev, "internal task abort: task to dev %016llx task=%p " "resp: 0x%x sts 0x%x\n", SAS_ADDR(device->sas_addr), task, -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 3/7] scsi: hisi_sas: downgrade refclk message
The message to inform that the controller has no refclk is currently at warning level, which is unnecessary, so downgrade to debug. Signed-off-by: John Garry <john.ga...@huawei.com> Reviewed-by: Xiang Chen <chenxian...@hisilicon.com> Reviewed-by: Johannes Thumshirn <jthumsh...@suse.de> --- 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 22dba01..eee7ae2 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1453,7 +1453,7 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev, refclk = devm_clk_get(>dev, NULL); if (IS_ERR(refclk)) - dev_info(dev, "no ref clk property\n"); + dev_dbg(dev, "no ref clk property\n"); else hisi_hba->refclk_frequency_mhz = clk_get_rate(refclk) / 100; -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 2/7] scsi: hisi_sas: modify some values of ITCT table
From: Xiang Chen <chenxian...@hisilicon.com> Set SMP connection timeout and continue AWT timer; Clear ITCT table when dev gone. Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> Reviewed-by: Johannes Thumshirn <jthumsh...@suse.de> --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 14 ++ 1 file changed, 10 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 6c787eb..93fceda 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -334,6 +334,11 @@ #define ITCT_HDR_MCR_MSK (0xf << ITCT_HDR_MCR_OFF) #define ITCT_HDR_VLN_OFF 9 #define ITCT_HDR_VLN_MSK (0xf << ITCT_HDR_VLN_OFF) +#define ITCT_HDR_SMP_TIMEOUT_OFF 16 +#define ITCT_HDR_SMP_TIMEOUT_8US 1 +#define ITCT_HDR_SMP_TIMEOUT (ITCT_HDR_SMP_TIMEOUT_8US * \ +250) /* 2ms */ +#define ITCT_HDR_AWT_CONTINUE_OFF 25 #define ITCT_HDR_PORT_ID_OFF 28 #define ITCT_HDR_PORT_ID_MSK (0xf << ITCT_HDR_PORT_ID_OFF) /* qw2 */ @@ -696,6 +701,8 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba, qw0 |= ((1 << ITCT_HDR_VALID_OFF) | (device->linkrate << ITCT_HDR_MCR_OFF) | (1 << ITCT_HDR_VLN_OFF) | + (ITCT_HDR_SMP_TIMEOUT << ITCT_HDR_SMP_TIMEOUT_OFF) | + (1 << ITCT_HDR_AWT_CONTINUE_OFF) | (port->id << ITCT_HDR_PORT_ID_OFF)); itct->qw0 = cpu_to_le64(qw0); @@ -705,7 +712,7 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba, /* qw2 */ if (!dev_is_sata(device)) - itct->qw2 = cpu_to_le64((500ULL << ITCT_HDR_INLT_OFF) | + itct->qw2 = cpu_to_le64((5000ULL << ITCT_HDR_INLT_OFF) | (0x1ULL << ITCT_HDR_BITLT_OFF) | (0x32ULL << ITCT_HDR_MCTLT_OFF) | (0x1ULL << ITCT_HDR_RTOLT_OFF)); @@ -714,7 +721,7 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba, static void free_device_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_device *sas_dev) { - u64 qw0, dev_id = sas_dev->device_id; + u64 dev_id = sas_dev->device_id; struct device *dev = _hba->pdev->dev; struct hisi_sas_itct *itct = _hba->itct[dev_id]; u32 reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3); @@ -738,8 +745,7 @@ static void free_device_v2_hw(struct hisi_hba *hisi_hba, dev_dbg(dev, "got clear ITCT done interrupt\n"); /* invalid the itct state*/ - qw0 = cpu_to_le64(itct->qw0); - qw0 &= ~(1 << ITCT_HDR_VALID_OFF); + memset(itct, 0, sizeof(struct hisi_sas_itct)); hisi_sas_write32(hisi_hba, ENT_INT_SRC3, ENT_INT_SRC3_ITC_INT_MSK); -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 0/7] hisi_sas: SATA IO workaround and other misc patches
This patchset introduces some misc fixes and improvements. Most signifigantly this patchset includes a workaround for a SATA IO issue on v2 hw (hip06/7). Differences v1->v2: - Add macro for SMP TIMEOUT in ITCT struct John Garry (2): scsi: hisi_sas: downgrade refclk message scsi: hisi_sas: downgrade internal abort exit print Xiang Chen (5): scsi: hisi_sas: workaround v2 hw SATA IO timeout issue scsi: hisi_sas: modify some values of ITCT table scsi: hisi_sas: modify hard reset for directed-attached disk scsi: hisi_sas: fix probe ordering problem scsi: hisi_sas: decrease running_req in hisi_sas_slot_task_free() drivers/scsi/hisi_sas/hisi_sas_main.c | 20 +++--- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 109 + 2 files changed, 106 insertions(+), 23 deletions(-) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 1/7] scsi: hisi_sas: workaround v2 hw SATA IO timeout issue
From: Xiang Chen <chenxian...@hisilicon.com> The v2 SAS controller needs more time to detect channel idle and send setup link request than SATA disk does, so it is difficult for the SAS controller to setup an STP link. Therefore it may cause some IO timeouts. We need to periodically configure the SAS controller so it doesn't receive STP setup requests from SATA disks for a while, so IO can be sent during this period. Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> Reviewed-by: Johannes Thumshirn <jthumsh...@suse.de> --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 75 +- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 69b0f06..6c787eb 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -215,6 +215,7 @@ #define RX_IDAF_DWORD5 (PORT_BASE + 0xd8) #define RX_IDAF_DWORD6 (PORT_BASE + 0xdc) #define RXOP_CHECK_CFG_H (PORT_BASE + 0xfc) +#define CON_CONTROL(PORT_BASE + 0x118) #define DONE_RECEIVED_TIME (PORT_BASE + 0x11c) #define CHL_INT0 (PORT_BASE + 0x1b4) #define CHL_INT0_HOTPLUG_TOUT_OFF 0 @@ -526,6 +527,8 @@ enum { #define SATA_PROTOCOL_FPDMA0x8 #define SATA_PROTOCOL_ATAPI0x10 +static void hisi_sas_link_timeout_disable_link(unsigned long data); + static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off) { void __iomem *regs = hisi_hba->regs + off; @@ -978,6 +981,50 @@ 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) +{ + struct hisi_hba *hisi_hba = (struct hisi_hba *)data; + int i, reg_val; + + for (i = 0; i < hisi_hba->n_phy; i++) { + reg_val = hisi_sas_phy_read32(hisi_hba, i, CON_CONTROL); + if (!(reg_val & BIT(0))) { + hisi_sas_phy_write32(hisi_hba, i, + CON_CONTROL, 0x7); + break; + } + } + + hisi_hba->timer.function = hisi_sas_link_timeout_disable_link; + mod_timer(_hba->timer, jiffies + msecs_to_jiffies(900)); +} + +static void hisi_sas_link_timeout_disable_link(unsigned long data) +{ + struct hisi_hba *hisi_hba = (struct hisi_hba *)data; + int i, reg_val; + + reg_val = hisi_sas_read32(hisi_hba, PHY_STATE); + for (i = 0; i < hisi_hba->n_phy && reg_val; i++) { + if (reg_val & BIT(i)) { + hisi_sas_phy_write32(hisi_hba, i, + CON_CONTROL, 0x6); + break; + } + } + + hisi_hba->timer.function = hisi_sas_link_timeout_enable_link; + mod_timer(_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.expires = jiffies + msecs_to_jiffies(1000); + add_timer(_hba->timer); +} + static int hw_init_v2_hw(struct hisi_hba *hisi_hba) { struct device *dev = _hba->pdev->dev; @@ -2020,9 +2067,12 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba) if (phy->identify.device_type == SAS_END_DEVICE) phy->identify.target_port_protocols = SAS_PROTOCOL_SSP; - else if (phy->identify.device_type != SAS_PHY_UNUSED) + else if (phy->identify.device_type != SAS_PHY_UNUSED) { phy->identify.target_port_protocols = SAS_PROTOCOL_SMP; + if (!timer_pending(_hba->timer)) + set_link_timer_quirk(hisi_hba); + } queue_work(hisi_hba->wq, >phyup_ws); end: @@ -2033,10 +2083,23 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba) return res; } +static bool check_any_wideports_v2_hw(struct hisi_hba *hisi_hba) +{ + u32 port_state; + + port_state = hisi_sas_read32(hisi_hba, PORT_STATE); + if (port_state & 0x1ff) + return true; + + return false; +} + 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 = _hba->phy[phy_no]; + struct hisi_sas_port *port = phy->port; hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 1); @@ -2046,6 +2109,10 @@ static int phy_down_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
[PATCH v2 6/7] scsi: hisi_sas: fix probe ordering problem
From: Xiang Chen <chenxian...@hisilicon.com> There is a potential probe issue in how we trigger the hw initialisation. Although we use 1s timer to delay hw initialisation, there is still a potential that sas_register_ha() is not be finished before we start the PHY init from hw->hw_init(). To avoid this issue, initialise the hw after sas_register_ha() in the same probe context. Note: it is not necessary to use 1s timer now (modified v2 hw only). Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> Reviewed-by: Johannes Thumshirn <jthumsh...@suse.de> --- drivers/scsi/hisi_sas/hisi_sas_main.c | 8 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 8 ++-- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index b2782ce..8601cec 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1552,10 +1552,6 @@ int hisi_sas_probe(struct platform_device *pdev, hisi_sas_init_add(hisi_hba); - rc = hisi_hba->hw->hw_init(hisi_hba); - if (rc) - goto err_out_ha; - rc = scsi_add_host(shost, >dev); if (rc) goto err_out_ha; @@ -1564,6 +1560,10 @@ int hisi_sas_probe(struct platform_device *pdev, if (rc) goto err_out_register_ha; + rc = hisi_hba->hw->hw_init(hisi_hba); + if (rc) + goto err_out_register_ha; + scsi_scan_host(shost); return 0; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 2e776b7..9e16f42 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -1093,9 +1093,8 @@ static void phy_hard_reset_v2_hw(struct hisi_hba *hisi_hba, int phy_no) start_phy_v2_hw(hisi_hba, phy_no); } -static void start_phys_v2_hw(unsigned long data) +static void start_phys_v2_hw(struct hisi_hba *hisi_hba) { - struct hisi_hba *hisi_hba = (struct hisi_hba *)data; int i; for (i = 0; i < hisi_hba->n_phy; i++) @@ -1104,10 +1103,7 @@ static void start_phys_v2_hw(unsigned long data) static void phys_init_v2_hw(struct hisi_hba *hisi_hba) { - struct timer_list *timer = _hba->timer; - - setup_timer(timer, start_phys_v2_hw, (unsigned long)hisi_hba); - mod_timer(timer, jiffies + HZ); + start_phys_v2_hw(hisi_hba); } static void sl_notify_v2_hw(struct hisi_hba *hisi_hba, int phy_no) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 4/7] scsi: hisi_sas: modify hard reset for directed-attached disk
From: Xiang Chen <chenxian...@hisilicon.com> Correctly set registers in v2 for root PHY hardreset for directly attached disk. Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> Reviewed-by: Johannes Thumshirn <jthumsh...@suse.de> --- 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 93fceda..2e776b7 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -207,6 +207,8 @@ #define TXID_AUTO (PORT_BASE + 0xb8) #define TXID_AUTO_CT3_OFF 1 #define TXID_AUTO_CT3_MSK (0x1 << TXID_AUTO_CT3_OFF) +#define TX_HARDRST_OFF 2 +#define TX_HARDRST_MSK (0x1 << TX_HARDRST_OFF) #define RX_IDAF_DWORD0 (PORT_BASE + 0xc4) #define RX_IDAF_DWORD1 (PORT_BASE + 0xc8) #define RX_IDAF_DWORD2 (PORT_BASE + 0xcc) @@ -1078,7 +1080,15 @@ static void stop_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no) static void phy_hard_reset_v2_hw(struct hisi_hba *hisi_hba, int phy_no) { + struct hisi_sas_phy *phy = _hba->phy[phy_no]; + u32 txid_auto; + stop_phy_v2_hw(hisi_hba, phy_no); + if (phy->identify.device_type == SAS_END_DEVICE) { + txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no, TXID_AUTO); + hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO, + txid_auto | TX_HARDRST_MSK); + } msleep(100); start_phy_v2_hw(hisi_hba, phy_no); } -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 7/7] scsi: hisi_sas: decrease running_req in hisi_sas_slot_task_free()
From: Xiang Chen <chenxian...@hisilicon.com> There is an issue that hisi_sas_dev.running_req is not decremented properly for internal abort and TMF. To resolve, only decrease running_req in hisi_sas_slot_task_free() Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> Reviewed-by: Johannes Thumshirn <jthumsh...@suse.de> --- drivers/scsi/hisi_sas/hisi_sas_main.c | 8 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 2 -- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 8601cec..53637a9 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -71,6 +71,8 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, struct hisi_sas_slot *slot) { struct device *dev = _hba->pdev->dev; + struct domain_device *device = task->dev; + struct hisi_sas_device *sas_dev = device->lldd_dev; if (!slot->task) return; @@ -97,6 +99,8 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, slot->task = NULL; slot->port = NULL; hisi_sas_slot_index_free(hisi_hba, slot->idx); + if (sas_dev) + atomic64_dec(_dev->running_req); /* slot memory is fully zeroed when it is reused */ } EXPORT_SYMBOL_GPL(hisi_sas_slot_task_free); @@ -141,8 +145,6 @@ static void hisi_sas_slot_abort(struct work_struct *work) struct hisi_hba *hisi_hba = dev_to_hisi_hba(task->dev); struct scsi_cmnd *cmnd = task->uldd_task; struct hisi_sas_tmf_task tmf_task; - struct domain_device *device = task->dev; - struct hisi_sas_device *sas_dev = device->lldd_dev; struct scsi_lun lun; struct device *dev = _hba->pdev->dev; int tag = abort_slot->idx; @@ -165,8 +167,6 @@ static void hisi_sas_slot_abort(struct work_struct *work) spin_unlock_irqrestore(_hba->lock, flags); if (task->task_done) task->task_done(task); - if (sas_dev) - atomic64_dec(_dev->running_req); } static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 9e16f42..1b21445 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -1830,8 +1830,6 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, } out: - if (sas_dev) - atomic64_dec(_dev->running_req); hisi_sas_slot_task_free(hisi_hba, task, slot); sts = ts->stat; -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/7] scsi: hisi_sas: modify some values of ITCT table
On 19/01/2017 08:44, Johannes Thumshirn wrote: On Thu, Jan 19, 2017 at 12:32:48AM +0800, John Garry wrote: From: Xiang Chen <chenxian...@hisilicon.com> Set SMP connection timeout and continue AWT timer; Clear ITCT table when dev gone. Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 11 +++ 1 file changed, 7 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 6c787eb..452e329 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -334,6 +334,8 @@ #define ITCT_HDR_MCR_MSK (0xf << ITCT_HDR_MCR_OFF) #define ITCT_HDR_VLN_OFF 9 #define ITCT_HDR_VLN_MSK (0xf << ITCT_HDR_VLN_OFF) +#define ITCT_HDR_SMP_TIMEOUT_OFF 16 +#define ITCT_HDR_AWT_CONTINUE_OFF 25 #define ITCT_HDR_PORT_ID_OFF 28 #define ITCT_HDR_PORT_ID_MSK (0xf << ITCT_HDR_PORT_ID_OFF) /* qw2 */ @@ -696,6 +698,8 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba, qw0 |= ((1 << ITCT_HDR_VALID_OFF) | (device->linkrate << ITCT_HDR_MCR_OFF) | (1 << ITCT_HDR_VLN_OFF) | + (0xfa << ITCT_HDR_SMP_TIMEOUT_OFF) | ^~ You may want to give that magic value a name. Thanks for having a look. We will create a new patch without the mysterious value. Regards, John Other than that, Reviewed-by: Johannes Thumshirn <jthumsh...@suse.de> -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 6/7] scsi: hisi_sas: fix probe ordering problem
From: Xiang Chen <chenxian...@hisilicon.com> There is a potential probe issue in how we trigger the hw initialisation. Although we use 1s timer to delay hw initialisation, there is still a potential that sas_register_ha() is not be finished before we start the PHY init from hw->hw_init(). To avoid this issue, initialise the hw after sas_register_ha() in the same probe context. Note: it is not necessary to use 1s timer now (modified v2 hw only). Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- drivers/scsi/hisi_sas/hisi_sas_main.c | 8 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 8 ++-- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index b2782ce..8601cec 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1552,10 +1552,6 @@ int hisi_sas_probe(struct platform_device *pdev, hisi_sas_init_add(hisi_hba); - rc = hisi_hba->hw->hw_init(hisi_hba); - if (rc) - goto err_out_ha; - rc = scsi_add_host(shost, >dev); if (rc) goto err_out_ha; @@ -1564,6 +1560,10 @@ int hisi_sas_probe(struct platform_device *pdev, if (rc) goto err_out_register_ha; + rc = hisi_hba->hw->hw_init(hisi_hba); + if (rc) + goto err_out_register_ha; + scsi_scan_host(shost); return 0; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 7519772..62655c7 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -1090,9 +1090,8 @@ static void phy_hard_reset_v2_hw(struct hisi_hba *hisi_hba, int phy_no) start_phy_v2_hw(hisi_hba, phy_no); } -static void start_phys_v2_hw(unsigned long data) +static void start_phys_v2_hw(struct hisi_hba *hisi_hba) { - struct hisi_hba *hisi_hba = (struct hisi_hba *)data; int i; for (i = 0; i < hisi_hba->n_phy; i++) @@ -1101,10 +1100,7 @@ static void start_phys_v2_hw(unsigned long data) static void phys_init_v2_hw(struct hisi_hba *hisi_hba) { - struct timer_list *timer = _hba->timer; - - setup_timer(timer, start_phys_v2_hw, (unsigned long)hisi_hba); - mod_timer(timer, jiffies + HZ); + start_phys_v2_hw(hisi_hba); } static void sl_notify_v2_hw(struct hisi_hba *hisi_hba, int phy_no) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 7/7] scsi: hisi_sas: decrease running_req in hisi_sas_slot_task_free()
From: Xiang Chen <chenxian...@hisilicon.com> There is an issue that hisi_sas_dev.running_req is not decremented properly for internal abort and TMF. To resolve, only decrease running_req in hisi_sas_slot_task_free() Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- drivers/scsi/hisi_sas/hisi_sas_main.c | 8 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 2 -- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 8601cec..53637a9 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -71,6 +71,8 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, struct hisi_sas_slot *slot) { struct device *dev = _hba->pdev->dev; + struct domain_device *device = task->dev; + struct hisi_sas_device *sas_dev = device->lldd_dev; if (!slot->task) return; @@ -97,6 +99,8 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, slot->task = NULL; slot->port = NULL; hisi_sas_slot_index_free(hisi_hba, slot->idx); + if (sas_dev) + atomic64_dec(_dev->running_req); /* slot memory is fully zeroed when it is reused */ } EXPORT_SYMBOL_GPL(hisi_sas_slot_task_free); @@ -141,8 +145,6 @@ static void hisi_sas_slot_abort(struct work_struct *work) struct hisi_hba *hisi_hba = dev_to_hisi_hba(task->dev); struct scsi_cmnd *cmnd = task->uldd_task; struct hisi_sas_tmf_task tmf_task; - struct domain_device *device = task->dev; - struct hisi_sas_device *sas_dev = device->lldd_dev; struct scsi_lun lun; struct device *dev = _hba->pdev->dev; int tag = abort_slot->idx; @@ -165,8 +167,6 @@ static void hisi_sas_slot_abort(struct work_struct *work) spin_unlock_irqrestore(_hba->lock, flags); if (task->task_done) task->task_done(task); - if (sas_dev) - atomic64_dec(_dev->running_req); } static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 62655c7..de240d2 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -1827,8 +1827,6 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, } out: - if (sas_dev) - atomic64_dec(_dev->running_req); hisi_sas_slot_task_free(hisi_hba, task, slot); sts = ts->stat; -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 0/7] hisi_sas: SATA IO workaround and other misc patches
This patchset introduces some misc fixes and improvements. Most signifigantly this patchset includes a workaround for a SATA IO issue on v2 hw (hip06/7). John Garry (2): scsi: hisi_sas: downgrade refclk message scsi: hisi_sas: downgrade internal abort exit print Xiang Chen (5): scsi: hisi_sas: workaround v2 hw SATA IO timeout issue scsi: hisi_sas: modify some values of ITCT table scsi: hisi_sas: modify hard reset for directed-attached disk scsi: hisi_sas: fix probe ordering problem scsi: hisi_sas: decrease running_req in hisi_sas_slot_task_free() drivers/scsi/hisi_sas/hisi_sas_main.c | 20 +++ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 106 + 2 files changed, 103 insertions(+), 23 deletions(-) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 5/7] scsi: hisi_sas: downgrade internal abort exit print
Downgrade the exit print in hisi_sas_internal_task_abort() to dbg level, as info is not required. Signed-off-by: John Garry <john.ga...@huawei.com> Reviewed-by: Xiang Chen <chenxian...@hisilicon.com> --- 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 eee7ae2..b2782ce 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1121,7 +1121,7 @@ static int hisi_sas_query_task(struct sas_task *task) } exit: - dev_info(dev, "internal task abort: task to dev %016llx task=%p " + dev_dbg(dev, "internal task abort: task to dev %016llx task=%p " "resp: 0x%x sts 0x%x\n", SAS_ADDR(device->sas_addr), task, -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/7] scsi: hisi_sas: modify some values of ITCT table
From: Xiang Chen <chenxian...@hisilicon.com> Set SMP connection timeout and continue AWT timer; Clear ITCT table when dev gone. Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 11 +++ 1 file changed, 7 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 6c787eb..452e329 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -334,6 +334,8 @@ #define ITCT_HDR_MCR_MSK (0xf << ITCT_HDR_MCR_OFF) #define ITCT_HDR_VLN_OFF 9 #define ITCT_HDR_VLN_MSK (0xf << ITCT_HDR_VLN_OFF) +#define ITCT_HDR_SMP_TIMEOUT_OFF 16 +#define ITCT_HDR_AWT_CONTINUE_OFF 25 #define ITCT_HDR_PORT_ID_OFF 28 #define ITCT_HDR_PORT_ID_MSK (0xf << ITCT_HDR_PORT_ID_OFF) /* qw2 */ @@ -696,6 +698,8 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba, qw0 |= ((1 << ITCT_HDR_VALID_OFF) | (device->linkrate << ITCT_HDR_MCR_OFF) | (1 << ITCT_HDR_VLN_OFF) | + (0xfa << ITCT_HDR_SMP_TIMEOUT_OFF) | + (1 << ITCT_HDR_AWT_CONTINUE_OFF) | (port->id << ITCT_HDR_PORT_ID_OFF)); itct->qw0 = cpu_to_le64(qw0); @@ -705,7 +709,7 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba, /* qw2 */ if (!dev_is_sata(device)) - itct->qw2 = cpu_to_le64((500ULL << ITCT_HDR_INLT_OFF) | + itct->qw2 = cpu_to_le64((5000ULL << ITCT_HDR_INLT_OFF) | (0x1ULL << ITCT_HDR_BITLT_OFF) | (0x32ULL << ITCT_HDR_MCTLT_OFF) | (0x1ULL << ITCT_HDR_RTOLT_OFF)); @@ -714,7 +718,7 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba, static void free_device_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_device *sas_dev) { - u64 qw0, dev_id = sas_dev->device_id; + u64 dev_id = sas_dev->device_id; struct device *dev = _hba->pdev->dev; struct hisi_sas_itct *itct = _hba->itct[dev_id]; u32 reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3); @@ -738,8 +742,7 @@ static void free_device_v2_hw(struct hisi_hba *hisi_hba, dev_dbg(dev, "got clear ITCT done interrupt\n"); /* invalid the itct state*/ - qw0 = cpu_to_le64(itct->qw0); - qw0 &= ~(1 << ITCT_HDR_VALID_OFF); + memset(itct, 0, sizeof(struct hisi_sas_itct)); hisi_sas_write32(hisi_hba, ENT_INT_SRC3, ENT_INT_SRC3_ITC_INT_MSK); -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/7] scsi: hisi_sas: workaround v2 hw SATA IO timeout issue
From: Xiang Chen <chenxian...@hisilicon.com> The v2 SAS controller needs more time to detect channel idle and send setup link request than SATA disk does, so it is difficult for SAS controller to setup an STP link. Therefore it may cause some IO timeouts. We need to periodically configure the SAS controller so it doesn't receive STP setup requests from SATA disks for a while, so IO can be sent during this period. Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 75 +- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 69b0f06..6c787eb 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -215,6 +215,7 @@ #define RX_IDAF_DWORD5 (PORT_BASE + 0xd8) #define RX_IDAF_DWORD6 (PORT_BASE + 0xdc) #define RXOP_CHECK_CFG_H (PORT_BASE + 0xfc) +#define CON_CONTROL(PORT_BASE + 0x118) #define DONE_RECEIVED_TIME (PORT_BASE + 0x11c) #define CHL_INT0 (PORT_BASE + 0x1b4) #define CHL_INT0_HOTPLUG_TOUT_OFF 0 @@ -526,6 +527,8 @@ enum { #define SATA_PROTOCOL_FPDMA0x8 #define SATA_PROTOCOL_ATAPI0x10 +static void hisi_sas_link_timeout_disable_link(unsigned long data); + static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off) { void __iomem *regs = hisi_hba->regs + off; @@ -978,6 +981,50 @@ 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) +{ + struct hisi_hba *hisi_hba = (struct hisi_hba *)data; + int i, reg_val; + + for (i = 0; i < hisi_hba->n_phy; i++) { + reg_val = hisi_sas_phy_read32(hisi_hba, i, CON_CONTROL); + if (!(reg_val & BIT(0))) { + hisi_sas_phy_write32(hisi_hba, i, + CON_CONTROL, 0x7); + break; + } + } + + hisi_hba->timer.function = hisi_sas_link_timeout_disable_link; + mod_timer(_hba->timer, jiffies + msecs_to_jiffies(900)); +} + +static void hisi_sas_link_timeout_disable_link(unsigned long data) +{ + struct hisi_hba *hisi_hba = (struct hisi_hba *)data; + int i, reg_val; + + reg_val = hisi_sas_read32(hisi_hba, PHY_STATE); + for (i = 0; i < hisi_hba->n_phy && reg_val; i++) { + if (reg_val & BIT(i)) { + hisi_sas_phy_write32(hisi_hba, i, + CON_CONTROL, 0x6); + break; + } + } + + hisi_hba->timer.function = hisi_sas_link_timeout_enable_link; + mod_timer(_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.expires = jiffies + msecs_to_jiffies(1000); + add_timer(_hba->timer); +} + static int hw_init_v2_hw(struct hisi_hba *hisi_hba) { struct device *dev = _hba->pdev->dev; @@ -2020,9 +2067,12 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba) if (phy->identify.device_type == SAS_END_DEVICE) phy->identify.target_port_protocols = SAS_PROTOCOL_SSP; - else if (phy->identify.device_type != SAS_PHY_UNUSED) + else if (phy->identify.device_type != SAS_PHY_UNUSED) { phy->identify.target_port_protocols = SAS_PROTOCOL_SMP; + if (!timer_pending(_hba->timer)) + set_link_timer_quirk(hisi_hba); + } queue_work(hisi_hba->wq, >phyup_ws); end: @@ -2033,10 +2083,23 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba) return res; } +static bool check_any_wideports_v2_hw(struct hisi_hba *hisi_hba) +{ + u32 port_state; + + port_state = hisi_sas_read32(hisi_hba, PORT_STATE); + if (port_state & 0x1ff) + return true; + + return false; +} + 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 = _hba->phy[phy_no]; + struct hisi_sas_port *port = phy->port; hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 1); @@ -2046,6 +2109,10 @@ static int phy_down_v2_hw(int phy_no, struct hisi_hba *hisi_hba) sl_ctrl = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL);
[PATCH 4/7] scsi: hisi_sas: modify hard reset for directed-attached disk
From: Xiang Chen <chenxian...@hisilicon.com> Correctly set registers in v2 for root PHY hardreset for directly attached disk. Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- 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 452e329..7519772 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -207,6 +207,8 @@ #define TXID_AUTO (PORT_BASE + 0xb8) #define TXID_AUTO_CT3_OFF 1 #define TXID_AUTO_CT3_MSK (0x1 << TXID_AUTO_CT3_OFF) +#define TX_HARDRST_OFF 2 +#define TX_HARDRST_MSK (0x1 << TX_HARDRST_OFF) #define RX_IDAF_DWORD0 (PORT_BASE + 0xc4) #define RX_IDAF_DWORD1 (PORT_BASE + 0xc8) #define RX_IDAF_DWORD2 (PORT_BASE + 0xcc) @@ -1075,7 +1077,15 @@ static void stop_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no) static void phy_hard_reset_v2_hw(struct hisi_hba *hisi_hba, int phy_no) { + struct hisi_sas_phy *phy = _hba->phy[phy_no]; + u32 txid_auto; + stop_phy_v2_hw(hisi_hba, phy_no); + if (phy->identify.device_type == SAS_END_DEVICE) { + txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no, TXID_AUTO); + hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO, + txid_auto | TX_HARDRST_MSK); + } msleep(100); start_phy_v2_hw(hisi_hba, phy_no); } -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 3/7] scsi: hisi_sas: downgrade refclk message
The message to inform that the controller has no refclk is currently at warning level, which is unnecessary, so downgrade to debug. Signed-off-by: John Garry <john.ga...@huawei.com> Reviewed-by: Xiang Chen <chenxian...@hisilicon.com> --- 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 22dba01..eee7ae2 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1453,7 +1453,7 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev, refclk = devm_clk_get(>dev, NULL); if (IS_ERR(refclk)) - dev_info(dev, "no ref clk property\n"); + dev_dbg(dev, "no ref clk property\n"); else hisi_hba->refclk_frequency_mhz = clk_get_rate(refclk) / 100; -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] libsas: fix \"sysfs group not found\" warnings at port teardown time
On 11/01/2017 06:29, seeteena wrote: Hi All, Let me know if this patch is accepted in Upsteam? let me know the commit id If it is the patch I think it is then it is not upstream (https://patchwork.kernel.org/patch/6450731/). I did propose a patch at the end of last year which fixed the warn, but it introduced some other potential hotplug issue. An engineer in my organisation proposed a re-work of libsas to fix all the hotplug issues, but it was not pushed and never got far: https://lkml.org/lkml/2016/9/12/1225 John -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] scsi: remove useless acpi functions in the head file
On 10/01/2017 08:14, Hanjun Guo wrote: From: Hanjun Guo <hanjun@linaro.org> commit f1bc1e4c44b1 ("ata: acpi: rework the ata acpi bind support") removed scsi_register_acpi_bus_type() and scsi_unregister_acpi_bus_type(), but forgot to remove them in the head file, do it now. Signed-off-by: Hanjun Guo <hanjun@linaro.org> --- include/scsi/scsi.h | 10 -- 1 file changed, 10 deletions(-) diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h index 8ec7c30..a1e1930 100644 --- a/include/scsi/scsi.h +++ b/include/scsi/scsi.h @@ -29,16 +29,6 @@ enum scsi_timeouts { */ #define SCAN_WILD_CARD ~0 -#ifdef CONFIG_ACPI -struct acpi_bus_type; - -extern int -scsi_register_acpi_bus_type(struct acpi_bus_type *bus); - -extern void -scsi_unregister_acpi_bus_type(struct acpi_bus_type *bus); -#endif - /** scsi_status_is_good - check the status return. * * @status: the status passed up from the driver (including host and Looks ok, Reviewed-by: John Garry <john.ga...@huawei.com> -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 3/3] scsi: hisi_sas: lock sensitive region in hisi_sas_slot_abort()
When we call hisi_sas_slot_task_free() we should grab the hisi_hba.lock, as hisi_sas_slot_task_free() accesses common hisi_hba elements. Function hisi_sas_slot_abort() is missing this, so add it. Signed-off-by: John Garry <john.ga...@huawei.com> --- drivers/scsi/hisi_sas/hisi_sas_main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index d50e9cf..22dba01 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -146,6 +146,7 @@ static void hisi_sas_slot_abort(struct work_struct *work) struct scsi_lun lun; struct device *dev = _hba->pdev->dev; int tag = abort_slot->idx; + unsigned long flags; if (!(task->task_proto & SAS_PROTOCOL_SSP)) { dev_err(dev, "cannot abort slot for non-ssp task\n"); @@ -159,7 +160,9 @@ static void hisi_sas_slot_abort(struct work_struct *work) hisi_sas_debug_issue_ssp_tmf(task->dev, lun.scsi_lun, _task); out: /* Do cleanup for this task */ + spin_lock_irqsave(_hba->lock, flags); hisi_sas_slot_task_free(hisi_hba, task, abort_slot); + spin_unlock_irqrestore(_hba->lock, flags); if (task->task_done) task->task_done(task); if (sas_dev) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/3] scsi: hisi_sas: service v2 hw CQ ISR with tasklet
Currently the all the slot processing for the completion queue is done in ISR context. It is judged that the slot processing can take a long time, especially when a SATA NCQ completes (upto 32 slots). So, as a solution, defer the bulk of the ISR processing to tasklet context. Each CQ will have its down tasklet. Signed-off-by: John Garry <john.ga...@huawei.com> Reviewed-by: Xiang Chen <chenxian...@hisilicon.com> --- drivers/scsi/hisi_sas/hisi_sas.h | 1 + drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 24 ++-- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index c0cd505..9216dea 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -95,6 +95,7 @@ struct hisi_sas_port { struct hisi_sas_cq { struct hisi_hba *hisi_hba; + struct tasklet_struct tasklet; int rd_point; int id; }; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index b934aec..e506260 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -2481,20 +2481,17 @@ static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p) return IRQ_HANDLED; } -static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p) +static void cq_tasklet_v2_hw(unsigned long val) { - struct hisi_sas_cq *cq = p; + struct hisi_sas_cq *cq = (struct hisi_sas_cq *)val; struct hisi_hba *hisi_hba = cq->hisi_hba; struct hisi_sas_slot *slot; struct hisi_sas_itct *itct; struct hisi_sas_complete_v2_hdr *complete_queue; - u32 irq_value, rd_point = cq->rd_point, wr_point, dev_id; + u32 rd_point = cq->rd_point, wr_point, dev_id; int queue = cq->id; complete_queue = hisi_hba->complete_hdr[queue]; - irq_value = hisi_sas_read32(hisi_hba, OQ_INT_SRC); - - hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue); wr_point = hisi_sas_read32(hisi_hba, COMPL_Q_0_WR_PTR + (0x14 * queue)); @@ -2545,6 +2542,18 @@ static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p) /* update rd_point */ cq->rd_point = rd_point; hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point); +} + +static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p) +{ + struct hisi_sas_cq *cq = p; + struct hisi_hba *hisi_hba = cq->hisi_hba; + int queue = cq->id; + + hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue); + + tasklet_schedule(>tasklet); + return IRQ_HANDLED; } @@ -2726,6 +2735,8 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba) for (i = 0; i < hisi_hba->queue_count; i++) { int idx = i + 96; /* First cq interrupt is irq96 */ + struct hisi_sas_cq *cq = _hba->cq[i]; + struct tasklet_struct *t = >tasklet; irq = irq_map[idx]; if (!irq) { @@ -2742,6 +2753,7 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba) irq, rc); return -ENOENT; } + tasklet_init(t, cq_tasklet_v2_hw, (unsigned long)cq); } return 0; -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 0/3] hisi_sas: some CQ processing fixes
This patchset fixes some issues related to servicing of the completion queue interrupt. The major fix is that sensitive hisi_hba structures need to be locked when free'ing a slot. Another modification is that the v2 hw completion queue irq is now serviced with a tasklet, as too much work was being done in the ISR. John Garry (3): scsi: hisi_sas: service v2 hw CQ ISR with tasklet scsi: hisi_sas: lock sensitive regions when servicing CQ interrupt scsi: hisi_sas: lock sensitive region in hisi_sas_slot_abort() drivers/scsi/hisi_sas/hisi_sas.h | 1 + drivers/scsi/hisi_sas/hisi_sas_main.c | 3 +++ drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 2 ++ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 26 -- 4 files changed, 26 insertions(+), 6 deletions(-) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/3] scsi: hisi_sas: lock sensitive regions when servicing CQ interrupt
There is a bug in the current driver in that certain hisi_hba and port structure elements which we access when servicing the CQ interrupt do not use thread-safe accesses; these include hisi_sas_port linked-list of active slots (hisi_sas_port.entry), bitmap of currently allocated IPTT (in hisi_hba.slot_index_tags), and completion queue read pointer. As a solution, lock these elements with the hisi_hba.lock. Signed-off-by: John Garry <john.ga...@huawei.com> Reviewed-by: Xiang Chen <chenxian...@hisilicon.com> --- drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 2 ++ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index 8a1be0b..854fbea 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -1596,6 +1596,7 @@ static irqreturn_t cq_interrupt_v1_hw(int irq, void *p) hisi_hba->complete_hdr[queue]; u32 irq_value, rd_point = cq->rd_point, wr_point; + spin_lock(_hba->lock); irq_value = hisi_sas_read32(hisi_hba, OQ_INT_SRC); hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue); @@ -1628,6 +1629,7 @@ static irqreturn_t cq_interrupt_v1_hw(int irq, void *p) /* update rd_point */ cq->rd_point = rd_point; hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point); + spin_unlock(_hba->lock); return IRQ_HANDLED; } diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index e506260..69b0f06 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -2493,6 +2493,7 @@ static void cq_tasklet_v2_hw(unsigned long val) complete_queue = hisi_hba->complete_hdr[queue]; + spin_lock(_hba->lock); wr_point = hisi_sas_read32(hisi_hba, COMPL_Q_0_WR_PTR + (0x14 * queue)); @@ -2542,6 +2543,7 @@ static void cq_tasklet_v2_hw(unsigned long val) /* update rd_point */ cq->rd_point = rd_point; hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point); + spin_unlock(_hba->lock); } static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] scsi: hisi_sas: support deferred probe for v2 hw
In the hip06 and hip07 SoCs, the interrupt lines from the SAS controllers are connected to mbigen hw module [1]. The mbigen module is probed with module_init, and, as such, is not guaranteed to probe before the SAS driver. So we need to support deferred probe. We check for probe deferral in the hw layer probe, so we not probe into the main layer and allocate shost, memories, etc., to later learn that we need to defer the probe. [1] ./Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt Signed-off-by: John Garry <john.ga...@huawei.com> diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index c0e7bf2..a179592 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -2971,6 +2971,18 @@ static int hisi_sas_v2_init(struct hisi_hba *hisi_hba) static int hisi_sas_v2_probe(struct platform_device *pdev) { + /* +* Check if we should defer the probe before we probe the +* upper layer, as it's hard to defer later on. +*/ + int ret = platform_get_irq(pdev, 0); + + if (ret < 0) { + if (ret != -EPROBE_DEFER) + dev_err(>dev, "cannot obtain irq\n"); + return ret; + } + return hisi_sas_probe(pdev, _sas_v2_hw); } -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] scsi: hisi_sas: fix free'ing in probe and remove
From: Xiaofei Tan <tanxiao...@huawei.com> This patch addresses 4 problems in the module probe/remove: - When hisi_sas_shost_alloc() fails after we alloc shost memory, we should free shost memory before the function returns. - When hisi_sas_probe() fails after we alloc the HBA memories, we should also free the HBA memories. - We should free shost memory at the end of hisi_sas_remove(). - sha->core.shost is set twice, so remove extra set. Signed-off-by: Xiaofei Tan <tanxiao...@huawei.com> Signed-off-by: John Garry <john.ga...@huawei.com> diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 6d6f150..d50e9cf 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1412,8 +1412,10 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev, struct clk *refclk; shost = scsi_host_alloc(_sas_sht, sizeof(*hisi_hba)); - if (!shost) - goto err_out; + if (!shost) { + dev_err(dev, "scsi host alloc failed\n"); + return NULL; + } hisi_hba = shost_priv(shost); hisi_hba->hw = hw; @@ -1477,6 +1479,7 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev, return shost; err_out: + kfree(shost); dev_err(dev, "shost alloc failed\n"); return NULL; } @@ -1503,10 +1506,8 @@ int hisi_sas_probe(struct platform_device *pdev, int rc, phy_nr, port_nr, i; shost = hisi_sas_shost_alloc(pdev, hw); - if (!shost) { - rc = -ENOMEM; - goto err_out_ha; - } + if (!shost) + return -ENOMEM; sha = SHOST_TO_SAS_HA(shost); hisi_hba = shost_priv(shost); @@ -1516,12 +1517,13 @@ int hisi_sas_probe(struct platform_device *pdev, arr_phy = devm_kcalloc(dev, phy_nr, sizeof(void *), GFP_KERNEL); arr_port = devm_kcalloc(dev, port_nr, sizeof(void *), GFP_KERNEL); - if (!arr_phy || !arr_port) - return -ENOMEM; + if (!arr_phy || !arr_port) { + rc = -ENOMEM; + goto err_out_ha; + } sha->sas_phy = arr_phy; sha->sas_port = arr_port; - sha->core.shost = shost; sha->lldd_ha = hisi_hba; shost->transportt = hisi_sas_stt; @@ -1566,6 +1568,7 @@ int hisi_sas_probe(struct platform_device *pdev, err_out_register_ha: scsi_remove_host(shost); err_out_ha: + hisi_sas_free(hisi_hba); kfree(shost); return rc; } @@ -1575,12 +1578,14 @@ int hisi_sas_remove(struct platform_device *pdev) { struct sas_ha_struct *sha = platform_get_drvdata(pdev); struct hisi_hba *hisi_hba = sha->lldd_ha; + struct Scsi_Host *shost = sha->core.shost; scsi_remove_host(sha->core.shost); sas_unregister_ha(sha); sas_remove_host(sha->core.shost); hisi_sas_free(hisi_hba); + kfree(shost); return 0; } EXPORT_SYMBOL_GPL(hisi_sas_remove); -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [patch] scsi: hisi_sas: shift vs compare typos
On 29/11/2016 10:47, Dan Carpenter wrote: There are some typos where we intended "<<" but have "<". Seems likely to cause a bunch of problems. Fixes: d3b688d3c69d ("scsi: hisi_sas: add v2 hw support for ECC and AXI bus fatal error") Signed-off-by: Dan Carpenter <dan.carpen...@oracle.com> --- There is another static checker warning to fix perhaps: drivers/scsi/hisi_sas/hisi_sas_v2_hw.c:2015 phy_up_v2_hw() warn: was expecting a 64 bit value instead of '(2 | 1)' The code is doing: phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA); Right, I think that a u32 would suffice. We can generate a separate patch for this. phy->phy_type is a u64 and PORT_TYPE_SAS is "1U << 1". So this code is clearing out the high 32 bits of ->phy_type uninitentionally. It's simple enough to make it 1ULL << 1 but the question is, do we really need ->phy_type to be a 64 bit variable? I'm pretty sure that a u32 will suffice. diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 15487f2..93876c0 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -64,19 +64,19 @@ HGC_LM_DFX_STATUS2_ITCTLIST_OFF) #define HGC_CQE_ECC_ADDR 0x13c #define HGC_CQE_ECC_1B_ADDR_OFF0 -#define HGC_CQE_ECC_1B_ADDR_MSK(0x3f < HGC_CQE_ECC_1B_ADDR_OFF) +#define HGC_CQE_ECC_1B_ADDR_MSK(0x3f << HGC_CQE_ECC_1B_ADDR_OFF) #define HGC_CQE_ECC_MB_ADDR_OFF8 -#define HGC_CQE_ECC_MB_ADDR_MSK (0x3f < HGC_CQE_ECC_MB_ADDR_OFF) +#define HGC_CQE_ECC_MB_ADDR_MSK (0x3f << HGC_CQE_ECC_MB_ADDR_OFF) #define HGC_IOST_ECC_ADDR 0x140 #define HGC_IOST_ECC_1B_ADDR_OFF 0 -#define HGC_IOST_ECC_1B_ADDR_MSK (0x3ff < HGC_IOST_ECC_1B_ADDR_OFF) +#define HGC_IOST_ECC_1B_ADDR_MSK (0x3ff << HGC_IOST_ECC_1B_ADDR_OFF) #define HGC_IOST_ECC_MB_ADDR_OFF 16 -#define HGC_IOST_ECC_MB_ADDR_MSK (0x3ff < HGC_IOST_ECC_MB_ADDR_OFF) +#define HGC_IOST_ECC_MB_ADDR_MSK (0x3ff << HGC_IOST_ECC_MB_ADDR_OFF) #define HGC_DQE_ECC_ADDR 0x144 #define HGC_DQE_ECC_1B_ADDR_OFF0 -#define HGC_DQE_ECC_1B_ADDR_MSK(0xfff < HGC_DQE_ECC_1B_ADDR_OFF) +#define HGC_DQE_ECC_1B_ADDR_MSK(0xfff << HGC_DQE_ECC_1B_ADDR_OFF) #define HGC_DQE_ECC_MB_ADDR_OFF16 -#define HGC_DQE_ECC_MB_ADDR_MSK (0xfff < HGC_DQE_ECC_MB_ADDR_OFF) +#define HGC_DQE_ECC_MB_ADDR_MSK (0xfff << HGC_DQE_ECC_MB_ADDR_OFF) #define HGC_INVLD_DQE_INFO 0x148 #define HGC_INVLD_DQE_INFO_FB_CH0_OFF 9 #define HGC_INVLD_DQE_INFO_FB_CH0_MSK (0x1 << HGC_INVLD_DQE_INFO_FB_CH0_OFF) . Cheers These were introduced in recent patch applied to 4.10 queue, and would only affect rare occurance of AXI/ECC error. Signed-off-by: John Garry <john.ga...@huawei.com> -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 00/11] hisi_sas: some fixes, improvements, and new features
On 22/11/2016 22:01, Martin K. Petersen wrote: "John" == John Garry <john.ga...@huawei.com> writes: John, John> Are you happy with this patchset now that I've got an external John> review? Zhangfei Geo asked a question about patch 1/11 that has yet to be answered. Patch 5/11 is still unreviewed. Hi Martin, I think that these 2 outstanding issues have been addressed. Please let me know if there is anything else. Thanks alot, John -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 01/11] hisi_sas: add v2 hw support for ECC and AXI bus fatal error
On 16/11/2016 01:47, Zhangfei Gao wrote: On Mon, Nov 7, 2016 at 8:48 PM, John Garry <john.ga...@huawei.com> wrote: From: Xiang Chen <chenxian...@hisilicon.com> For ECC 1bit error, logic can recover it, so we only print a warning. For ECC multi-bit and AXI bus fatal error, we panic. Is it possible to recover via resetting phy and device etc instead of panic? Thanks Hi Zhangfei, We are actually now working on supporting controller reset for certain AXI/ECC errors, so that we will not need to panic. Thanks, John -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC PATCH] scsi: libsas: fix WARN on device removal
On 21/11/2016 17:13, Dan Williams wrote: On Mon, Nov 21, 2016 at 7:16 AM, John Garry <john.ga...@huawei.com> wrote: @Maintainers, would you be willing to accept this patch as an interim fix for the dastardly WARN while we try to fix the flutter issue? To me this adds a bug to quiet a benign, albeit noisy, warning. What is the bug which is being added? The bug where we queue a port teardown, but see a port formation event in the meantime. As I understand, this vulnerability already exists: http://marc.info/?l=linux-scsi=143801026028006=2 I actually don't understand how libsas dealt with flutter (which I take to mean a burst of up and down events) before these changes, as it can only queue simultaneously one up and one down event per port. So, if we get a flutter, then the events are lost and we get indeterminate state. The events are not lost. In sas_queue_event(), if there is a particular event pending for a port/PHY, we cannot queue further same event types for that port/PHY. I think my colleagues found issue where we try to enqueue multiple complementary events. The new problem this patch introduces is delaying sas port deletion where it was previously immediate. So now we can get into a situation where the port has gone down and can start processing a port up event before the previous deletion work has run. And it's a very noisy warning, as in 6K lines on the console when an expander is unplugged. Does something like this modulate the failure? I'm curious if we simply need to fix the double deletion of the sas_port bsg queue, could you try the changes below? No, I just tested it on a root port and we get the same WARN. diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.cindex 60b651bfaa01..11401e5c88ba 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -262,9 +262,10 @@ static void sas_bsg_remove(struct Scsi_Host *shost, struct sas_rphy *rphy { struct request_queue *q; - if (rphy) + if (rphy) { q = rphy->q; - else + rphy->q = NULL; + } else q = to_sas_host_attrs(shost)->q; if (!q) . . -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 00/11] hisi_sas: some fixes, improvements, and new features
On 14/11/2016 23:49, Martin K. Petersen wrote: "John" == John Garry <john.ga...@huawei.com> writes: John> This patchset introduces some misc bug fixes, improvements, and John> new features to the HiSilicon SAS driver. This series needs review. Hi Martin, Are you happy with this patchset now that I've got an external review? Thanks, John -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC PATCH] scsi: libsas: fix WARN on device removal
@Maintainers, would you be willing to accept this patch as an interim fix for the dastardly WARN while we try to fix the flutter issue? To me this adds a bug to quiet a benign, albeit noisy, warning. What is the bug which is being added? The bug where we queue a port teardown, but see a port formation event in the meantime. As I understand, this vulnerability already exists: http://marc.info/?l=linux-scsi=143801026028006=2 I actually don't understand how libsas dealt with flutter (which I take to mean a burst of up and down events) before these changes, as it can only queue simultaneously one up and one down event per port. So, if we get a flutter, then the events are lost and we get indeterminate state. And it's a very noisy warning, as in 6K lines on the console when an expander is unplugged. Does something like this modulate the failure? diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.cindex 60b651bfaa01..11401e5c88ba 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -262,9 +262,10 @@ static void sas_bsg_remove(struct Scsi_Host *shost, struct sas_rphy *rphy { struct request_queue *q; - if (rphy) + if (rphy) { q = rphy->q; - else + rphy->q = NULL; + } else q = to_sas_host_attrs(shost)->q; if (!q) . -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] scsi: hisi_sas: Add a missing call to kfree
On 21/11/2016 14:25, Quentin Lambert wrote: On 11/21/2016 03:16 PM, John Garry wrote: On 21/11/2016 13:20, Quentin Lambert wrote: On 11/21/2016 01:53 PM, John Garry wrote: However I have noticed that we should do a call to hisi_sas_free() for this failure, and later failures in the probe. I don't understand why, and would welcome the opportunity to learn something. We call hisi_sas_alloc() from hisi_sas_shost_alloc(); if we fail after this in hisi_sas_probe(), then we should free the memmories and workqueue got in hisi_sas_alloc(), which we don't. Thanks. Are you writing the patch or do you want me to do it? We can do it, thanks. Quentin -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] scsi: hisi_sas: Add a missing call to kfree
On 21/11/2016 13:20, Quentin Lambert wrote: On 11/21/2016 01:53 PM, John Garry wrote: However I have noticed that we should do a call to hisi_sas_free() for this failure, and later failures in the probe. I don't understand why, and would welcome the opportunity to learn something. We call hisi_sas_alloc() from hisi_sas_shost_alloc(); if we fail after this in hisi_sas_probe(), then we should free the memmories and workqueue got in hisi_sas_alloc(), which we don't. Thanks, John Quentin -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] scsi: hisi_sas: Add a missing call to kfree
On 19/11/2016 17:42, Quentin Lambert wrote: Most error branches following the call to hisi_sas_shost_alloc contain a call to kfree. This patch add these calls where they are missing. This issue was found with Hector. I think that this patch is fine. However I have noticed that we should do a call to hisi_sas_free() for this failure, and later failures in the probe. I can generate a patch for this. Cheers, John Signed-off-by: Quentin Lambert--- drivers/scsi/hisi_sas/hisi_sas_main.c |6 -- 1 file changed, 4 insertions(+), 2 deletions(-) --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1503,8 +1503,10 @@ int hisi_sas_probe(struct platform_devic arr_phy = devm_kcalloc(dev, phy_nr, sizeof(void *), GFP_KERNEL); arr_port = devm_kcalloc(dev, port_nr, sizeof(void *), GFP_KERNEL); - if (!arr_phy || !arr_port) - return -ENOMEM; + if (!arr_phy || !arr_port) { + rc = -ENOMEM; + goto err_out_ha; + } sha->sas_phy = arr_phy; sha->sas_port = arr_port; . -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC PATCH] scsi: libsas: fix WARN on device removal
On 18/11/2016 01:53, Dan Williams wrote: On Thu, Nov 17, 2016 at 7:23 AM, John Garry <john.ga...@huawei.com> wrote: On 11/11/2016 08:49, wangyijing wrote: I have not seen the flutter issue. I am just trying to solve the horrible WARN dump. However I do understand that there may be a issue related to how we queue the events; there was a recent attempt to fix this, but it came to nothing: https://www.spinics.net/lists/linux-scsi/msg1.html We found libsas hotplug several problems: 1. sysfs warning calltrace(like the case you found); Maybe you can then review my patch. I did it, I think your solution to fix the sysfs calltrace issue is ok, and what I worried about is we still need to fix the rest issues. So it's better if we could fix all issues one time. @Maintainers, would you be willing to accept this patch as an interim fix for the dastardly WARN while we try to fix the flutter issue? To me this adds a bug to quiet a benign, albeit noisy, warning. What is the bug which is being added? And it's a very noisy warning, as in 6K lines on the console when an expander is unplugged. . -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC PATCH] scsi: libsas: fix WARN on device removal
On 11/11/2016 08:49, wangyijing wrote: I have not seen the flutter issue. I am just trying to solve the horrible WARN dump. However I do understand that there may be a issue related to how we queue the events; there was a recent attempt to fix this, but it came to nothing: https://www.spinics.net/lists/linux-scsi/msg1.html We found libsas hotplug several problems: 1. sysfs warning calltrace(like the case you found); Maybe you can then review my patch. I did it, I think your solution to fix the sysfs calltrace issue is ok, and what I worried about is we still need to fix the rest issues. So it's better if we could fix all issues one time. @Maintainers, would you be willing to accept this patch as an interim fix for the dastardly WARN while we try to fix the flutter issue? 2. hot-add and hot-remove work events may process out of order; 3. in some extreme cases, libsas may miss some events, if the same event is still pending in workqueue. Can you tell me how to recreate #2 and #3? Qilin Chen and Yousong He help me to reproduce it, I told them to reply this mail to tell you the test steps. Some tests we did is make sas phy link flutter, so hardware would post phy down and phy up events sequentially. 1. scsi host workqueue receive phy down and phy up events. in process new added 2. sas_deform_port would post a new destruct event to scsi host workqueue, so things in workqueue like [phy down-phy up -destruct] So the phy down logic is separated by phy up, and it's not atomic, not safe, something unexpected would happen. For case 3, we make hardware burst post lots pair of phy up and phy down events, so if libsas is processing the phy up event, the next phy up event can not queue to scsi host workqueue again, it will lost, it's not we expect. It's a complex issue, we posted two patches, try to fix these issues, but now few people are interested in it :( IIRC, you sent as RFC and got a "reviewed-by" from Hannes, so I'm not sure what else you want. BTW, I thought that the changes were quite drastic. I agree, the changes seems something drastic. But I think current libsas hotplug framework has a big flaw. John Alternatively we need a mechanism to cancel in-flight port shutdown requests when we start re-attaching devices before queued port destruction events have run. . ___ linuxarm mailing list linux...@huawei.com http://rnd-openeuler.huawei.com/mailman/listinfo/linuxarm . . . . -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 02/11] hisi_sas: alloc queue id of slot according to device id
On 16/11/2016 01:41, Zhangfei Gao wrote: On Mon, Nov 7, 2016 at 8:48 PM, John Garry <john.ga...@huawei.com> wrote: From: Xiang Chen <chenxian...@hisilicon.com> Currently slots are allocated from queues in a round-robin fashion. This causes a problem for internal commands in device mode. For this mode, we should ensure that the internal abort command is the last command seen in the host for that device. We can only ensure this when we place the internal abort command after the preceding commands for device that in the same queue, as there is no order in which the host will select a queue to execute the next command. Is there performance penalty, since only one queue is supported for a device. Hi Zhangfei, From testing I have not seen any noteable performance change. However, please note the comment on mq, below. Cheers, John This queue restriction makes supporting scsi mq more tricky in the future, but should not be a blocker. Note: Even though v1 hw does not support internal abort, the allocation method is chosen to be the same for consistency. Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> Reviewed-by: Zhangfei Gao <zhangfei@linaro.org> -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html . -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC PATCH] scsi: libsas: fix WARN on device removal
On 11/11/2016 08:12, wangyijing wrote: They're not the same. I don't see how your solution properly deals with remote sas_port deletion. When we unplug a device connected to an expander, can't the sas_port be deleted twice, in sas_unregister_devs_sas_addr() from domain revalidation and also now in sas_destruct_devices()? I think that this gives a NULL dereference. And we still get the WARN as the sas_port has still been deleted before the device. In my solution, we should always delete the sas_port after the attached device. i.e. it moves the port destruction to the workqueue and still suffers from the flutter problem: http://marc.info/?l=linux-scsi=143801026028006=2 http://marc.info/?l=linux-scsi=143801971131073=2 Perhaps we instead need to quiet this warning? http://marc.info/?l=linux-scsi=143802229932175=2 I have not seen the flutter issue. I am just trying to solve the horrible WARN dump. However I do understand that there may be a issue related to how we queue the events; there was a recent attempt to fix this, but it came to nothing: https://www.spinics.net/lists/linux-scsi/msg1.html We found libsas hotplug several problems: 1. sysfs warning calltrace(like the case you found); Maybe you can then review my patch. 2. hot-add and hot-remove work events may process out of order; 3. in some extreme cases, libsas may miss some events, if the same event is still pending in workqueue. Can you tell me how to recreate #2 and #3? It's a complex issue, we posted two patches, try to fix these issues, but now few people are interested in it :( IIRC, you sent as RFC and got a "reviewed-by" from Hannes, so I'm not sure what else you want. BTW, I thought that the changes were quite drastic. John Alternatively we need a mechanism to cancel in-flight port shutdown requests when we start re-attaching devices before queued port destruction events have run. . ___ linuxarm mailing list linux...@huawei.com http://rnd-openeuler.huawei.com/mailman/listinfo/linuxarm . . -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC PATCH] scsi: libsas: fix WARN on device removal
On 09/11/2016 20:35, Dan Williams wrote: On Wed, Nov 9, 2016 at 11:09 AM, Dan Williams <dan.j.willi...@intel.com> wrote: On Wed, Nov 9, 2016 at 9:36 AM, John Garry <john.ga...@huawei.com> wrote: On 09/11/2016 12:28, John Garry wrote: On 03/11/2016 14:58, John Garry wrote: The following patch introduces an annoying WARN when a device is removed from the SAS topology: [SCSI] libsas: prevent domain rediscovery competing with ata error handling Are there any views on this patch? I would have thought that the parties who use the drivers based on libsas would be interested in fixing this bug. I should have added the before and after logs earlier, so the issue is illustrated. Now attached. When a 24-port expander is unplugged we get >6k lines of WARN on the console, lasting >30 seconds. Not nice. I might be mistaken, but this patch seems functionally identical to this attempt: http://marc.info/?l=linux-scsi=143459794823595=2 Hi Dan, They're not the same. I don't see how your solution properly deals with remote sas_port deletion. When we unplug a device connected to an expander, can't the sas_port be deleted twice, in sas_unregister_devs_sas_addr() from domain revalidation and also now in sas_destruct_devices()? I think that this gives a NULL dereference. And we still get the WARN as the sas_port has still been deleted before the device. In my solution, we should always delete the sas_port after the attached device. i.e. it moves the port destruction to the workqueue and still suffers from the flutter problem: http://marc.info/?l=linux-scsi=143801026028006=2 http://marc.info/?l=linux-scsi=143801971131073=2 Perhaps we instead need to quiet this warning? http://marc.info/?l=linux-scsi=143802229932175=2 I have not seen the flutter issue. I am just trying to solve the horrible WARN dump. However I do understand that there may be a issue related to how we queue the events; there was a recent attempt to fix this, but it came to nothing: https://www.spinics.net/lists/linux-scsi/msg1.html Cheers, John Alternatively we need a mechanism to cancel in-flight port shutdown requests when we start re-attaching devices before queued port destruction events have run. . -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC PATCH] scsi: libsas: fix WARN on device removal
On 03/11/2016 14:58, John Garry wrote: The following patch introduces an annoying WARN when a device is removed from the SAS topology: [SCSI] libsas: prevent domain rediscovery competing with ata error handling Are there any views on this patch? I would have thought that the parties who use the drivers based on libsas would be interested in fixing this bug. BTW, We are internally testing, hence the RFC. Thanks in advance, John A sample WARN is as follows: [ 236.842227] WARNING: CPU: 7 PID: 1520 at fs/sysfs/group.c:237 sysfs_remove_group+0x90/0x98 [ 236.850465] Modules linked in: [ 236.853544] [ 236.855045] CPU: 7 PID: 1520 Comm: kworker/u64:4 Tainted: GW 4.9.0-rc1-15310-g3fbc29e-dirty #676 [ 236.865010] Hardware name: Huawei Taishan 2180 /D03, BIOS Estuary v2.3 D03 UEFI 08/17/2016 [ 236.873249] Workqueue: scsi_wq_0 sas_destruct_devices [ 236.878317] task: 8027ba31b200 task.stack: 8027b9d44000 [ 236.884225] PC is at sysfs_remove_group+0x90/0x98 [ 236.888920] LR is at sysfs_remove_group+0x90/0x98 [ 236.893616] pc : [] lr : [] pstate: 6145 [ 236.900989] sp : 8027b9d47bf0 < snip > [ 237.116463] [] sysfs_remove_group+0x90/0x98 [ 237.122197] [] dpm_sysfs_remove+0x58/0x68 [ 237.127758] [] device_del+0x40/0x218 [ 237.132886] [] device_unregister+0x14/0x2c [ 237.138536] [] bsg_unregister_queue+0x5c/0xa0 [ 237.12] [] sas_rphy_remove+0x44/0x80 [ 237.149915] [] sas_rphy_delete+0x14/0x28 [ 237.155388] [] sas_destruct_devices+0x64/0x98 [ 237.161293] [] process_one_work+0x128/0x2e4 [ 237.167027] [] worker_thread+0x58/0x434 [ 237.172415] [] kthread+0xd4/0xe8 [ 237.177198] [] ret_from_fork+0x10/0x50 [ 237.182557] sysfs group 'power' not found for kobject 'end_device-0:0:5' (this can be really huge when an expander is unplugged) The problem is with the process of sas_port and domain_device destruction in domain revalidation. There is a 2-stage process: In domain revalidation (which runs in work queue context), if a domain_device is discovered to be gone, then the following happens: - the domain_device is queued for destruction in a separate work item - the associated sas_port is destroyed immediately This causes a problem in that the sas_port associated with a domain_device is destroyed prior the domain_device: this causes the sysfs WARN. Essentially the "rug has been pulled from underneath". Also, likewise, when a root port is deformed due to loss of signal, we have the same issue. To solve, destroy the sas_port in a separate work item to which we do the domain revalidation with a new discovery event, as follows: - When a domain_device is detected to be gone, the domain_device is queued for destruction in a separate work item. The associated sas_port is also queued for destruction in another separate work item (needs to be queued 2nd) - the domain_device is destroyed - the sas_port is destroyed [similar is done for loss of signal event, in sas_port_deformed()]. Fixes: 87c8331fcf72e501c3a3c0cdc5c [SCSI] libsas: prevent domain rediscovery competing with ata error handling Signed-off-by: John Garry <john.ga...@huawei.com> diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index 60de662..01d0fe2 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c @@ -361,7 +361,7 @@ static void sas_destruct_devices(struct work_struct *work) clear_bit(DISCE_DESTRUCT, >disc.pending); - list_for_each_entry_safe(dev, n, >destroy_list, disco_list_node) { + list_for_each_entry_safe(dev, n, >dev_destroy_list, disco_list_node) { list_del_init(>disco_list_node); sas_remove_children(>rphy->dev); @@ -383,7 +383,7 @@ void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev) if (!test_and_set_bit(SAS_DEV_DESTROY, >state)) { sas_rphy_unlink(dev->rphy); - list_move_tail(>disco_list_node, >destroy_list); + list_move_tail(>disco_list_node, >dev_destroy_list); sas_discover_event(dev->port, DISCE_DESTRUCT); } } @@ -525,6 +525,28 @@ static void sas_revalidate_domain(struct work_struct *work) mutex_unlock(>disco_mutex); } +/* -- Async Port destruct -- */ +static void sas_async_port_destruct(struct work_struct *work) +{ + struct sas_discovery_event *ev = to_sas_discovery_event(work); + struct asd_sas_port *port = ev->port; + struct sas_port *sas_port, *n; + + clear_bit(DISCE_PORT_DESTRUCT, >disc.pending); + + list_for_each_entry_safe(sas_port, n, >port_destroy_list, destroy_list) { + list_del_init(>port_destroy_list); + + sas_port_delete(sas_port); + } +} + +void sas_port_destruct(struct asd_sas_port *port, struct sas_port *sas_port) +{ + list_move_tail(_port->destroy_
[PATCH 07/11] hisi_sas: delete repeated configuration in free_device_v2_hw()
From: Xiang Chen <chenxian...@hisilicon.com> Delete repeated configuration items for hisi_sas_device() when we free a device. These items are now only set in hisi_sas_dev_gone(). Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 7567193..3081eec 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -739,8 +739,6 @@ static void free_device_v2_hw(struct hisi_hba *hisi_hba, qw0 &= ~(1 << ITCT_HDR_VALID_OFF); hisi_sas_write32(hisi_hba, ENT_INT_SRC3, ENT_INT_SRC3_ITC_INT_MSK); - hisi_hba->devices[dev_id].dev_type = SAS_PHY_UNUSED; - hisi_hba->devices[dev_id].dev_status = HISI_SAS_DEV_NORMAL; /* clear the itct */ hisi_sas_write32(hisi_hba, ITCT_CLR, 0); -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 01/11] hisi_sas: add v2 hw support for ECC and AXI bus fatal error
From: Xiang Chen <chenxian...@hisilicon.com> For ECC 1bit error, logic can recover it, so we only print a warning. For ECC multi-bit and AXI bus fatal error, we panic. Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 425 - 1 file changed, 420 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 0763b47..9e70e6d 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -55,10 +55,44 @@ #define HGC_DFX_CFG2 0xc0 #define HGC_IOMB_PROC1_STATUS 0x104 #define CFG_1US_TIMER_TRSH 0xcc +#define HGC_LM_DFX_STATUS2 0x128 +#define HGC_LM_DFX_STATUS2_IOSTLIST_OFF0 +#define HGC_LM_DFX_STATUS2_IOSTLIST_MSK(0xfff << \ +HGC_LM_DFX_STATUS2_IOSTLIST_OFF) +#define HGC_LM_DFX_STATUS2_ITCTLIST_OFF12 +#define HGC_LM_DFX_STATUS2_ITCTLIST_MSK(0x7ff << \ +HGC_LM_DFX_STATUS2_ITCTLIST_OFF) +#define HGC_CQE_ECC_ADDR 0x13c +#define HGC_CQE_ECC_1B_ADDR_OFF0 +#define HGC_CQE_ECC_1B_ADDR_MSK(0x3f < HGC_CQE_ECC_1B_ADDR_OFF) +#define HGC_CQE_ECC_MB_ADDR_OFF8 +#define HGC_CQE_ECC_MB_ADDR_MSK (0x3f < HGC_CQE_ECC_MB_ADDR_OFF) +#define HGC_IOST_ECC_ADDR 0x140 +#define HGC_IOST_ECC_1B_ADDR_OFF 0 +#define HGC_IOST_ECC_1B_ADDR_MSK (0x3ff < HGC_IOST_ECC_1B_ADDR_OFF) +#define HGC_IOST_ECC_MB_ADDR_OFF 16 +#define HGC_IOST_ECC_MB_ADDR_MSK (0x3ff < HGC_IOST_ECC_MB_ADDR_OFF) +#define HGC_DQE_ECC_ADDR 0x144 +#define HGC_DQE_ECC_1B_ADDR_OFF0 +#define HGC_DQE_ECC_1B_ADDR_MSK(0xfff < HGC_DQE_ECC_1B_ADDR_OFF) +#define HGC_DQE_ECC_MB_ADDR_OFF16 +#define HGC_DQE_ECC_MB_ADDR_MSK (0xfff < HGC_DQE_ECC_MB_ADDR_OFF) #define HGC_INVLD_DQE_INFO 0x148 #define HGC_INVLD_DQE_INFO_FB_CH0_OFF 9 #define HGC_INVLD_DQE_INFO_FB_CH0_MSK (0x1 << HGC_INVLD_DQE_INFO_FB_CH0_OFF) #define HGC_INVLD_DQE_INFO_FB_CH3_OFF 18 +#define HGC_ITCT_ECC_ADDR 0x150 +#define HGC_ITCT_ECC_1B_ADDR_OFF 0 +#define HGC_ITCT_ECC_1B_ADDR_MSK (0x3ff << \ +HGC_ITCT_ECC_1B_ADDR_OFF) +#define HGC_ITCT_ECC_MB_ADDR_OFF 16 +#define HGC_ITCT_ECC_MB_ADDR_MSK (0x3ff << \ +HGC_ITCT_ECC_MB_ADDR_OFF) +#define HGC_AXI_FIFO_ERR_INFO 0x154 +#define AXI_ERR_INFO_OFF 0 +#define AXI_ERR_INFO_MSK (0xff << AXI_ERR_INFO_OFF) +#define FIFO_ERR_INFO_OFF 8 +#define FIFO_ERR_INFO_MSK (0xff << FIFO_ERR_INFO_OFF) #define INT_COAL_EN0x19c #define OQ_INT_COAL_TIME 0x1a0 #define OQ_INT_COAL_CNT0x1a4 @@ -73,13 +107,41 @@ #define ENT_INT_SRC1_D2H_FIS_CH1_MSK (0x1 << ENT_INT_SRC1_D2H_FIS_CH1_OFF) #define ENT_INT_SRC2 0x1bc #define ENT_INT_SRC3 0x1c0 +#define ENT_INT_SRC3_WP_DEPTH_OFF 8 +#define ENT_INT_SRC3_IPTT_SLOT_NOMATCH_OFF 9 +#define ENT_INT_SRC3_RP_DEPTH_OFF 10 +#define ENT_INT_SRC3_AXI_OFF 11 +#define ENT_INT_SRC3_FIFO_OFF 12 +#define ENT_INT_SRC3_LM_OFF14 #define ENT_INT_SRC3_ITC_INT_OFF 15 #define ENT_INT_SRC3_ITC_INT_MSK (0x1 << ENT_INT_SRC3_ITC_INT_OFF) +#define ENT_INT_SRC3_ABT_OFF 16 #define ENT_INT_SRC_MSK1 0x1c4 #define ENT_INT_SRC_MSK2 0x1c8 #define ENT_INT_SRC_MSK3 0x1cc #define ENT_INT_SRC_MSK3_ENT95_MSK_OFF 31 #define ENT_INT_SRC_MSK3_ENT95_MSK_MSK (0x1 << ENT_INT_SRC_MSK3_ENT95_MSK_OFF) +#define SAS_ECC_INTR 0x1e8 +#define SAS_ECC_INTR_DQE_ECC_1B_OFF0 +#define SAS_ECC_INTR_DQE_ECC_MB_OFF1 +#define SAS_ECC_INTR_IOST_ECC_1B_OFF 2 +#define SAS_ECC_INTR_IOST_ECC_MB_OFF 3 +#define SAS_ECC_INTR_ITCT_ECC_MB_OFF 4 +#define SAS_ECC_INTR_ITCT_ECC_1B_OFF 5 +#define SAS_ECC_INTR_IOSTLIST_ECC_MB_OFF 6 +#define SAS_ECC_INTR_IOSTLIST_ECC_1B_OFF 7 +#define SAS_ECC_INTR_ITCTLIST_ECC_1B_OFF 8 +#define SAS_ECC_INTR_ITCTLIST_ECC_MB_OFF 9 +#define SAS_ECC_INTR_CQE_ECC_1B_OFF10 +#define SAS_ECC_INTR_CQE_ECC_MB_OFF11 +#define SAS_ECC_INTR_NCQ_MEM0_ECC_MB_OFF 12 +#define SAS_ECC_INTR_NCQ_MEM0_ECC_1B_OFF 13 +#define SAS_ECC_INTR_NCQ_MEM1_ECC_MB_OFF 14 +#define SAS_ECC_INTR_NCQ_MEM1_ECC_1B_OFF 15 +#define SAS_ECC_INTR_NCQ_MEM2_ECC_MB_OFF 16 +#define SAS_ECC_INTR_NCQ_MEM2_ECC_1B_OFF
[PATCH 08/11] hisi_sas: modify some values in get_ata_protocol()
From: Xiang Chen <chenxian...@hisilicon.com> Modify and add some SATA commands according to SATA protocol. Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 14 -- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 3081eec..a5faa4d 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -1750,6 +1750,7 @@ static u8 get_ata_protocol(u8 cmd, int direction) case ATA_CMD_NCQ_NON_DATA: return SATA_PROTOCOL_FPDMA; + case ATA_CMD_DOWNLOAD_MICRO: case ATA_CMD_ID_ATA: case ATA_CMD_PMP_READ: case ATA_CMD_READ_LOG_EXT: @@ -1761,18 +1762,27 @@ static u8 get_ata_protocol(u8 cmd, int direction) case ATA_CMD_PIO_WRITE_EXT: return SATA_PROTOCOL_PIO; + case ATA_CMD_DSM: + case ATA_CMD_DOWNLOAD_MICRO_DMA: + case ATA_CMD_PMP_READ_DMA: + case ATA_CMD_PMP_WRITE_DMA: case ATA_CMD_READ: case ATA_CMD_READ_EXT: case ATA_CMD_READ_LOG_DMA_EXT: + case ATA_CMD_READ_STREAM_DMA_EXT: + case ATA_CMD_TRUSTED_RCV_DMA: + case ATA_CMD_TRUSTED_SND_DMA: case ATA_CMD_WRITE: case ATA_CMD_WRITE_EXT: + case ATA_CMD_WRITE_FUA_EXT: case ATA_CMD_WRITE_QUEUED: case ATA_CMD_WRITE_LOG_DMA_EXT: + case ATA_CMD_WRITE_STREAM_DMA_EXT: return SATA_PROTOCOL_DMA; - case ATA_CMD_DOWNLOAD_MICRO: - case ATA_CMD_DEV_RESET: case ATA_CMD_CHK_POWER: + case ATA_CMD_DEV_RESET: + case ATA_CMD_EDD: case ATA_CMD_FLUSH: case ATA_CMD_FLUSH_EXT: case ATA_CMD_VERIFY: -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 10/11] hisi_sas: use atomic64_t for hisi_sas_device.running_req
Sometimes the value of hisi_sas_device.running_req would go negative unless we have the check for running_req >= 0 before trying to decrement. This is because using running_req is not thread-safe. As such, the value for running_req may be actually incorrect, so use atomic64_t instead. Signed-off-by: John Garry <john.ga...@huawei.com> Reviewed-by: Xiang Chen <chenxian...@hisilicon.com> --- 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 | 4 ++-- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 4 ++-- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index bf59fab..8b5ecc6 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -111,7 +111,7 @@ struct hisi_sas_device { struct domain_device*sas_device; u64 attached_phy; u64 device_id; - u64 running_req; + atomic64_t running_req; u8 dev_status; }; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 504cbcf..18e2194 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -162,8 +162,8 @@ static void hisi_sas_slot_abort(struct work_struct *work) hisi_sas_slot_task_free(hisi_hba, task, abort_slot); if (task->task_done) task->task_done(task); - if (sas_dev && sas_dev->running_req) - sas_dev->running_req--; + if (sas_dev) + atomic64_dec(_dev->running_req); } static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, @@ -303,7 +303,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, hisi_hba->slot_prep = slot; - sas_dev->running_req++; + atomic64_inc(_dev->running_req); ++(*pass); return 0; @@ -1027,7 +1027,8 @@ static int hisi_sas_query_task(struct sas_task *task) hisi_hba->slot_prep = slot; - sas_dev->running_req++; + atomic64_inc(_dev->running_req); + /* send abort command to our chip */ hisi_hba->hw->start_delivery(hisi_hba); diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index bbc5760..05177fc 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -1366,8 +1366,8 @@ static int slot_complete_v1_hw(struct hisi_hba *hisi_hba, } out: - if (sas_dev && sas_dev->running_req) - sas_dev->running_req--; + if (sas_dev) + atomic64_dec(_dev->running_req); hisi_sas_slot_task_free(hisi_hba, task, slot); sts = ts->stat; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index cda3baf..e88113a 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -1728,8 +1728,8 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, } out: - if (sas_dev && sas_dev->running_req) - sas_dev->running_req--; + if (sas_dev) + atomic64_dec(_dev->running_req); hisi_sas_slot_task_free(hisi_hba, task, slot); sts = ts->stat; -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 04/11] hisi_sas: fix port form bug in hisi_sas_port_notify_formed()
From: Xiang Chen <chenxian...@hisilicon.com> When we form a wideport, we should use hardware PHY port_id instead of sas_phy->id. Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- 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 9f5ccc5..486aa92 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -537,7 +537,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 = _hba->port[sas_phy->id]; + struct hisi_sas_port *port = _hba->port[phy->port_id]; unsigned long flags; if (!sas_port) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 03/11] hisi_sas: only process broadcast change in phy_bcast_v2_hw()
From: Xiang Chen <chenxian...@hisilicon.com> There are many BROADCAST primitives generated by the host. We are only interested in BROADCAST (CHANGE) primitives currently, so only process this. Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 8 +++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index cb19e73..7567193 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -194,6 +194,9 @@ #define SL_CONTROL_NOTIFY_EN_MSK (0x1 << SL_CONTROL_NOTIFY_EN_OFF) #define SL_CONTROL_CTA_OFF 17 #define SL_CONTROL_CTA_MSK (0x1 << SL_CONTROL_CTA_OFF) +#define RX_PRIMS_STATUS (PORT_BASE + 0x98) +#define RX_BCAST_CHG_OFF1 +#define RX_BCAST_CHG_MSK(0x1 << RX_BCAST_CHG_OFF) #define TX_ID_DWORD0 (PORT_BASE + 0x9c) #define TX_ID_DWORD1 (PORT_BASE + 0xa0) #define TX_ID_DWORD2 (PORT_BASE + 0xa4) @@ -2044,9 +2047,12 @@ static void phy_bcast_v2_hw(int phy_no, struct hisi_hba *hisi_hba) struct hisi_sas_phy *phy = _hba->phy[phy_no]; struct asd_sas_phy *sas_phy = >sas_phy; struct sas_ha_struct *sas_ha = _hba->sha; + u32 bcast_status; hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 1); - sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); + bcast_status = hisi_sas_phy_read32(hisi_hba, phy_no, RX_PRIMS_STATUS); + if (bcast_status & RX_BCAST_CHG_MSK) + sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, CHL_INT0_SL_RX_BCST_ACK_MSK); hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 0); -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 00/11] hisi_sas: some fixes, improvements, and new features
This patchset introduces some misc bug fixes, improvements, and new features to the HiSilicon SAS driver. The new features include: - ECC and AXI bus fatal error handling for v2 hw - PHY (min and max) linkrate setting John Garry (1): hisi_sas: use atomic64_t for hisi_sas_device.running_req Xiang Chen (10): hisi_sas: add v2 hw support for ECC and AXI bus fatal error hisi_sas: alloc queue id of slot according to device id hisi_sas: only process broadcast change in phy_bcast_v2_hw() hisi_sas: fix port form bug in hisi_sas_port_notify_formed() hisi_sas: replace WARN_ON() with dev_warn() for internal abort hisi_sas: modify return value of hisi_sas_query_task() hisi_sas: delete repeated configuration in free_device_v2_hw() hisi_sas: modify some values in get_ata_protocol() hisi_sas: check SATA FIS when directly attaching SATA device hisi_sas: add PHY set linkrate support for v1 and v2 hw drivers/scsi/hisi_sas/hisi_sas.h | 9 +- drivers/scsi/hisi_sas/hisi_sas_main.c | 37 ++- drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 79 +++-- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 539 +++-- 4 files changed, 599 insertions(+), 65 deletions(-) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 06/11] hisi_sas: modify return value of hisi_sas_query_task()
From: Xiang Chen <chenxian...@hisilicon.com> sas_scsi_find_task() only deals with return value TMF_RESP_FUNC_FAILED/TMF_RESP_FUNC_SUCC/TMF_RESP_FUNC_COMPLETE of query task. So for LLDD errors just return TMF_RESP_FUNC_FAILED. Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- drivers/scsi/hisi_sas/hisi_sas_main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 9133238..504cbcf 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -961,6 +961,9 @@ static int hisi_sas_query_task(struct sas_task *task) case TMF_RESP_FUNC_FAILED: case TMF_RESP_FUNC_COMPLETE: break; + default: + rc = TMF_RESP_FUNC_FAILED; + break; } } return rc; -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 09/11] hisi_sas: check SATA FIS when directly attaching SATA device
From: Xiang Chen <chenxian...@hisilicon.com> Check ERR bit of status to decide whether there is something wrong with initial register-D2H FIS. If error exists, PHY reset the channel to restart OOB. Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- 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 a5faa4d..cda3baf 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -2537,6 +2537,16 @@ static irqreturn_t sata_int_v2_hw(int irq_no, void *p) goto end; } + /* check ERR bit of Status Register */ + if (fis->status & ATA_ERR) { + dev_warn(dev, "sata int: phy%d FIS status: 0x%x\n", phy_no, + fis->status); + disable_phy_v2_hw(hisi_hba, phy_no); + enable_phy_v2_hw(hisi_hba, phy_no); + res = IRQ_NONE; + goto end; + } + if (unlikely(phy_no == 8)) { u32 port_state = hisi_sas_read32(hisi_hba, PORT_STATE); -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 11/11] hisi_sas: add PHY set linkrate support for v1 and v2 hw
From: Xiang Chen <chenxian...@hisilicon.com> Add the function to set PHY min and max linkrate through sysfs interface. Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- drivers/scsi/hisi_sas/hisi_sas.h | 3 +++ drivers/scsi/hisi_sas/hisi_sas_main.c | 12 +++-- drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 45 ++ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 45 ++ 4 files changed, 103 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 8b5ecc6..c0cd505 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -168,6 +168,9 @@ struct hisi_sas_hw { 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); + void (*phy_set_linkrate)(struct hisi_hba *hisi_hba, int phy_no, + struct sas_phy_linkrates *linkrates); + enum sas_linkrate (*phy_get_max_linkrate)(void); 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); diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 18e2194..6d6f150 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -369,9 +369,14 @@ static void hisi_sas_bytes_dmaed(struct hisi_hba *hisi_hba, int phy_no) struct sas_phy *sphy = sas_phy->phy; sphy->negotiated_linkrate = sas_phy->linkrate; - sphy->minimum_linkrate = phy->minimum_linkrate; sphy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; - sphy->maximum_linkrate = phy->maximum_linkrate; + sphy->maximum_linkrate_hw = + hisi_hba->hw->phy_get_max_linkrate(); + if (sphy->minimum_linkrate == SAS_LINK_RATE_UNKNOWN) + sphy->minimum_linkrate = phy->minimum_linkrate; + + if (sphy->maximum_linkrate == SAS_LINK_RATE_UNKNOWN) + sphy->maximum_linkrate = phy->maximum_linkrate; } if (phy->phy_type & PORT_TYPE_SAS) { @@ -645,6 +650,9 @@ static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func, break; case PHY_FUNC_SET_LINK_RATE: + hisi_hba->hw->phy_set_linkrate(hisi_hba, phy_no, funcdata); + break; + case PHY_FUNC_RELEASE_SPINUP_HOLD: default: return -EOPNOTSUPP; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index 05177fc..8a1be0b 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -843,6 +843,49 @@ static void sl_notify_v1_hw(struct hisi_hba *hisi_hba, int phy_no) hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control); } +static enum sas_linkrate phy_get_max_linkrate_v1_hw(void) +{ + return SAS_LINK_RATE_6_0_GBPS; +} + +static void phy_set_linkrate_v1_hw(struct hisi_hba *hisi_hba, int phy_no, + struct sas_phy_linkrates *r) +{ + u32 prog_phy_link_rate = + hisi_sas_phy_read32(hisi_hba, phy_no, PROG_PHY_LINK_RATE); + struct hisi_sas_phy *phy = _hba->phy[phy_no]; + struct asd_sas_phy *sas_phy = >sas_phy; + int i; + enum sas_linkrate min, max; + u32 rate_mask = 0; + + if (r->maximum_linkrate == SAS_LINK_RATE_UNKNOWN) { + max = sas_phy->phy->maximum_linkrate; + min = r->minimum_linkrate; + } else if (r->minimum_linkrate == SAS_LINK_RATE_UNKNOWN) { + max = r->maximum_linkrate; + min = sas_phy->phy->minimum_linkrate; + } else + return; + + sas_phy->phy->maximum_linkrate = max; + sas_phy->phy->minimum_linkrate = min; + + min -= SAS_LINK_RATE_1_5_GBPS; + max -= SAS_LINK_RATE_1_5_GBPS; + + for (i = 0; i <= max; i++) + rate_mask |= 1 << (i * 2); + + prog_phy_link_rate &= ~0xff; + prog_phy_link_rate |= rate_mask; + + hisi_sas_phy_write32(hisi_hba, phy_no, PROG_PHY_LINK_RATE, + prog_phy_link_rate); + + phy_hard_reset_v1_hw(hisi_hba, phy_no); +} + static int get_wideport_bitmap_v1_hw(struct hisi_hba *hisi_hba, int port_id) { int i, bitmap = 0; @@ -1818,6 +1861,8 @@ static int hisi_sas_v1_init(struct hisi_hba *hisi_hba) .phy_enable = enable_phy_v1_hw, .phy_disable = disable_phy_v1_hw, .phy_hard_res
[PATCH 05/11] hisi_sas: replace WARN_ON() with dev_warn() for internal abort
From: Xiang Chen <chenxian...@hisilicon.com> Replace WARN_ON() with dev_warn() print when internal abort fails. Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- 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 486aa92..9133238 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -764,7 +764,8 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device, task = NULL; } ex_err: - WARN_ON(retry == TASK_RETRY); + if (retry == TASK_RETRY) + dev_warn(dev, "abort tmf: executing internal task failed!\n"); sas_free_task(task); return res; } -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 02/11] hisi_sas: alloc queue id of slot according to device id
From: Xiang Chen <chenxian...@hisilicon.com> Currently slots are allocated from queues in a round-robin fashion. This causes a problem for internal commands in device mode. For this mode, we should ensure that the internal abort command is the last command seen in the host for that device. We can only ensure this when we place the internal abort command after the preceding commands for device that in the same queue, as there is no order in which the host will select a queue to execute the next command. This queue restriction makes supporting scsi mq more tricky in the future, but should not be a blocker. Note: Even though v1 hw does not support internal abort, the allocation method is chosen to be the same for consistency. Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- drivers/scsi/hisi_sas/hisi_sas.h | 4 ++-- drivers/scsi/hisi_sas/hisi_sas_main.c | 8 drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 30 -- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 29 - 4 files changed, 30 insertions(+), 41 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 64046c5..bf59fab 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -150,7 +150,8 @@ struct hisi_sas_hw { struct domain_device *device); struct hisi_sas_device *(*alloc_dev)(struct domain_device *device); void (*sl_notify)(struct hisi_hba *hisi_hba, int phy_no); - int (*get_free_slot)(struct hisi_hba *hisi_hba, int *q, int *s); + int (*get_free_slot)(struct hisi_hba *hisi_hba, u32 dev_id, + int *q, int *s); void (*start_delivery)(struct hisi_hba *hisi_hba); int (*prep_ssp)(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot, int is_tmf, @@ -207,7 +208,6 @@ struct hisi_hba { struct hisi_sas_port port[HISI_SAS_MAX_PHYS]; int queue_count; - int queue; struct hisi_sas_slot*slot_prep; struct dma_pool *sge_page_pool; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 9afc697..9f5ccc5 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -232,8 +232,8 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, rc = hisi_sas_slot_index_alloc(hisi_hba, _idx); if (rc) goto err_out; - rc = hisi_hba->hw->get_free_slot(hisi_hba, _queue, -_queue_slot); + rc = hisi_hba->hw->get_free_slot(hisi_hba, sas_dev->device_id, + _queue, _queue_slot); if (rc) goto err_out_tag; @@ -987,8 +987,8 @@ static int hisi_sas_query_task(struct sas_task *task) rc = hisi_sas_slot_index_alloc(hisi_hba, _idx); if (rc) goto err_out; - rc = hisi_hba->hw->get_free_slot(hisi_hba, _queue, -_queue_slot); + rc = hisi_hba->hw->get_free_slot(hisi_hba, sas_dev->device_id, + _queue, _queue_slot); if (rc) goto err_out_tag; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index c0ac49d..bbc5760 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -862,29 +862,23 @@ static int get_wideport_bitmap_v1_hw(struct hisi_hba *hisi_hba, int port_id) * The callpath to this function and upto writing the write * queue pointer should be safe from interruption. */ -static int get_free_slot_v1_hw(struct hisi_hba *hisi_hba, int *q, int *s) +static int get_free_slot_v1_hw(struct hisi_hba *hisi_hba, u32 dev_id, + int *q, int *s) { struct device *dev = _hba->pdev->dev; struct hisi_sas_dq *dq; u32 r, w; - int queue = hisi_hba->queue; - - while (1) { - dq = _hba->dq[queue]; - w = dq->wr_point; - r = hisi_sas_read32_relaxed(hisi_hba, - DLVRY_Q_0_RD_PTR + (queue * 0x14)); - if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) { - queue = (queue + 1) % hisi_hba->queue_count; - if (queue == hisi_hba->queue) { - dev_warn(dev, "could not find free slot\n"); - return -EAGAIN; - } - continue; - } - break; + int queue = dev_id % hisi_hba->queue_count; + + dq = _hba->dq[queue]; + w = dq->wr_point; + r = hisi_sas_r
[RFC PATCH] scsi: libsas: fix WARN on device removal
The following patch introduces an annoying WARN when a device is removed from the SAS topology: [SCSI] libsas: prevent domain rediscovery competing with ata error handling A sample WARN is as follows: [ 236.842227] WARNING: CPU: 7 PID: 1520 at fs/sysfs/group.c:237 sysfs_remove_group+0x90/0x98 [ 236.850465] Modules linked in: [ 236.853544] [ 236.855045] CPU: 7 PID: 1520 Comm: kworker/u64:4 Tainted: GW 4.9.0-rc1-15310-g3fbc29e-dirty #676 [ 236.865010] Hardware name: Huawei Taishan 2180 /D03, BIOS Estuary v2.3 D03 UEFI 08/17/2016 [ 236.873249] Workqueue: scsi_wq_0 sas_destruct_devices [ 236.878317] task: 8027ba31b200 task.stack: 8027b9d44000 [ 236.884225] PC is at sysfs_remove_group+0x90/0x98 [ 236.888920] LR is at sysfs_remove_group+0x90/0x98 [ 236.893616] pc : [] lr : [] pstate: 6145 [ 236.900989] sp : 8027b9d47bf0 < snip > [ 237.116463] [] sysfs_remove_group+0x90/0x98 [ 237.122197] [] dpm_sysfs_remove+0x58/0x68 [ 237.127758] [] device_del+0x40/0x218 [ 237.132886] [] device_unregister+0x14/0x2c [ 237.138536] [] bsg_unregister_queue+0x5c/0xa0 [ 237.12] [] sas_rphy_remove+0x44/0x80 [ 237.149915] [] sas_rphy_delete+0x14/0x28 [ 237.155388] [] sas_destruct_devices+0x64/0x98 [ 237.161293] [] process_one_work+0x128/0x2e4 [ 237.167027] [] worker_thread+0x58/0x434 [ 237.172415] [] kthread+0xd4/0xe8 [ 237.177198] [] ret_from_fork+0x10/0x50 [ 237.182557] sysfs group 'power' not found for kobject 'end_device-0:0:5' (this can be really huge when an expander is unplugged) The problem is with the process of sas_port and domain_device destruction in domain revalidation. There is a 2-stage process: In domain revalidation (which runs in work queue context), if a domain_device is discovered to be gone, then the following happens: - the domain_device is queued for destruction in a separate work item - the associated sas_port is destroyed immediately This causes a problem in that the sas_port associated with a domain_device is destroyed prior the domain_device: this causes the sysfs WARN. Essentially the "rug has been pulled from underneath". Also, likewise, when a root port is deformed due to loss of signal, we have the same issue. To solve, destroy the sas_port in a separate work item to which we do the domain revalidation with a new discovery event, as follows: - When a domain_device is detected to be gone, the domain_device is queued for destruction in a separate work item. The associated sas_port is also queued for destruction in another separate work item (needs to be queued 2nd) - the domain_device is destroyed - the sas_port is destroyed [similar is done for loss of signal event, in sas_port_deformed()]. Fixes: 87c8331fcf72e501c3a3c0cdc5c [SCSI] libsas: prevent domain rediscovery competing with ata error handling Signed-off-by: John Garry <john.ga...@huawei.com> diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index 60de662..01d0fe2 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c @@ -361,7 +361,7 @@ static void sas_destruct_devices(struct work_struct *work) clear_bit(DISCE_DESTRUCT, >disc.pending); - list_for_each_entry_safe(dev, n, >destroy_list, disco_list_node) { + list_for_each_entry_safe(dev, n, >dev_destroy_list, disco_list_node) { list_del_init(>disco_list_node); sas_remove_children(>rphy->dev); @@ -383,7 +383,7 @@ void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev) if (!test_and_set_bit(SAS_DEV_DESTROY, >state)) { sas_rphy_unlink(dev->rphy); - list_move_tail(>disco_list_node, >destroy_list); + list_move_tail(>disco_list_node, >dev_destroy_list); sas_discover_event(dev->port, DISCE_DESTRUCT); } } @@ -525,6 +525,28 @@ static void sas_revalidate_domain(struct work_struct *work) mutex_unlock(>disco_mutex); } +/* -- Async Port destruct -- */ +static void sas_async_port_destruct(struct work_struct *work) +{ + struct sas_discovery_event *ev = to_sas_discovery_event(work); + struct asd_sas_port *port = ev->port; + struct sas_port *sas_port, *n; + + clear_bit(DISCE_PORT_DESTRUCT, >disc.pending); + + list_for_each_entry_safe(sas_port, n, >port_destroy_list, destroy_list) { + list_del_init(>port_destroy_list); + + sas_port_delete(sas_port); + } +} + +void sas_port_destruct(struct asd_sas_port *port, struct sas_port *sas_port) +{ + list_move_tail(_port->destroy_list, >port_destroy_list); + sas_discover_event(port, DISCE_PORT_DESTRUCT); +} + /* -- Events -- */ static void sas_chain_work(struct sas_ha_struct *ha, struct sas_work *sw) @@ -582,6 +604,7 @@ void sas_init_disc(struct sas_discovery *disc,
Re: [bug report] scsi: hisi_sas: add internal abort to hisi_sas_abort_task()
On 12/10/2016 14:12, Dan Carpenter wrote: Hello John Garry, The patch dc8a49cabc73: "scsi: hisi_sas: add internal abort to hisi_sas_abort_task()" from Aug 24, 2016, leads to the following static checker warning: drivers/scsi/hisi_sas/hisi_sas_main.c:848 hisi_sas_abort_task() error: we previously assumed 'slot' could be null (see line 847) drivers/scsi/hisi_sas/hisi_sas_main.c 809 spin_unlock_irqrestore(>task_state_lock, flags); 810 sas_dev->dev_status = HISI_SAS_DEV_EH; 811 if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) { ^^^ We assume that ->lldd_task can be NULL. 812 struct scsi_cmnd *cmnd = task->uldd_task; 813 struct hisi_sas_slot *slot = task->lldd_task; 814 u32 tag = slot->idx; 815 816 int_to_scsilun(cmnd->device->lun, ); 817 tmf_task.tmf = TMF_ABORT_TASK; 818 tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag); 819 820 rc = hisi_sas_debug_issue_ssp_tmf(task->dev, lun.scsi_lun, 821_task); 822 823 /* if successful, clear the task and callback forwards.*/ 824 if (rc == TMF_RESP_FUNC_COMPLETE) { 825 if (task->lldd_task) { 826 struct hisi_sas_slot *slot; 827 828 slot = _hba->slot_info 829 [tmf_task.tag_of_task_to_be_managed]; 830 spin_lock_irqsave(_hba->lock, flags); 831 hisi_hba->hw->slot_complete(hisi_hba, slot, 1); 832 spin_unlock_irqrestore(_hba->lock, flags); 833 } 834 } 835 836 hisi_sas_internal_task_abort(hisi_hba, device, 837 HISI_SAS_INT_ABT_CMD, tag); 838 } else if (task->task_proto & SAS_PROTOCOL_SATA || 839 task->task_proto & SAS_PROTOCOL_STP) { 840 if (task->dev->dev_type == SAS_SATA_DEV) { 841 hisi_sas_internal_task_abort(hisi_hba, device, 842 HISI_SAS_INT_ABT_DEV, 0); 843 rc = TMF_RESP_FUNC_COMPLETE; 844 } 845 } else if (task->task_proto & SAS_PROTOCOL_SMP) { 846 /* SMP */ 847 struct hisi_sas_slot *slot = task->lldd_task; We assign it to slot. I will check this. Thanks, John 848 u32 tag = slot->idx; ^ slot dereferenced without checking. 849 850 hisi_sas_internal_task_abort(hisi_hba, device, 851 HISI_SAS_INT_ABT_CMD, tag); 852 } regards, dan carpenter . -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 1/3] devicetree: bindings: scsi: hisi_sas add hip07 support
Add support for hip07 chipset to hisi_sas controller. Chipset hip07 has v2 hw. Signed-off-by: John Garry <john.ga...@huawei.com> Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> --- Documentation/devicetree/bindings/scsi/hisilicon-sas.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/scsi/hisilicon-sas.txt b/Documentation/devicetree/bindings/scsi/hisilicon-sas.txt index bf2411f..2a42a32 100644 --- a/Documentation/devicetree/bindings/scsi/hisilicon-sas.txt +++ b/Documentation/devicetree/bindings/scsi/hisilicon-sas.txt @@ -6,6 +6,7 @@ Main node required properties: - compatible : value should be as follows: (a) "hisilicon,hip05-sas-v1" for v1 hw in hip05 chipset (b) "hisilicon,hip06-sas-v2" for v2 hw in hip06 chipset + (c) "hisilicon,hip07-sas-v2" for v2 hw in hip07 chipset - sas-addr : array of 8 bytes for host SAS address - reg : Address and length of the SAS register - hisilicon,sas-syscon: phandle of syscon used for sas control -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 0/3] hisi_sas add hip07 support
This patchset introduces support for hip07 SoC. The hip07 SoC has the same v2 hw as in hip06. Support for different reference clock is required as some SAS registers need be programmed differently, depending on the refclock rate. Related patchset: - https://patchwork.ozlabs.org/patch/665172/ Once 4.9-rc1 is released, the D03 dts can be updated for the refclock. Note: there will be only 1 D03 dts, UEFI will update the refclock rate for that board in the fdt at boottime. Differences to v1: - dropped sas-v2 quirk amt for hip07 John Garry (3): devicetree: bindings: scsi: hisi_sas add hip07 support hisi_sas: add device tree support for hip07 hisi_sas: add v2 hw support for different refclk Documentation/devicetree/bindings/scsi/hisilicon-sas.txt | 1 + drivers/scsi/hisi_sas/hisi_sas.h | 2 ++ drivers/scsi/hisi_sas/hisi_sas_main.c| 7 +++ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 5 - 4 files changed, 14 insertions(+), 1 deletion(-) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 3/3] hisi_sas: add v2 hw support for different refclk
The hip06 D03 and hip07 D05 boards have different reference clock frequencies for the SAS controller. Register PHY_CTRL needs to be programmed differently according to this frequency, so add support for this. The default register setting in PHY_CTRL is for 50MHz, so only update this register when the refclk frequency is 66MHz. For ACPI we expect the _RST handler to set the correct value for PHY_CTRL (we're forced to take different approach for DT and ACPI as ACPI does not support fixed-clock device). Signed-off-by: John Garry <john.ga...@huawei.com> Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> --- drivers/scsi/hisi_sas/hisi_sas.h | 2 ++ drivers/scsi/hisi_sas/hisi_sas_main.c | 7 +++ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 4 +++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 72c9852..64046c5 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -13,6 +13,7 @@ #define _HISI_SAS_H_ #include +#include #include #include #include @@ -183,6 +184,7 @@ struct hisi_hba { u32 ctrl_reset_reg; u32 ctrl_reset_sts_reg; u32 ctrl_clock_ena_reg; + u32 refclk_frequency_mhz; u8 sas_addr[SAS_ADDR_SIZE]; int n_phy; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 2f872f7..9afc697 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1396,6 +1396,7 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev, struct hisi_hba *hisi_hba; struct device *dev = >dev; struct device_node *np = pdev->dev.of_node; + struct clk *refclk; shost = scsi_host_alloc(_sas_sht, sizeof(*hisi_hba)); if (!shost) @@ -1432,6 +1433,12 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev, goto err_out; } + refclk = devm_clk_get(>dev, NULL); + if (IS_ERR(refclk)) + dev_info(dev, "no ref clk property\n"); + else + hisi_hba->refclk_frequency_mhz = clk_get_rate(refclk) / 100; + if (device_property_read_u32(dev, "phy-count", _hba->n_phy)) goto err_out; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 758e06f..0763b47 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -836,7 +836,9 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba) hisi_sas_phy_write32(hisi_hba, i, SL_RX_BCAST_CHK_MSK, 0x0); hisi_sas_phy_write32(hisi_hba, i, CHL_INT_COAL_EN, 0x0); hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_OOB_RESTART_MSK, 0x0); - hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL, 0x199B694); + if (hisi_hba->refclk_frequency_mhz == 66) + hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL, 0x199B694); + /* else, do nothing -> leave it how you found it */ } for (i = 0; i < hisi_hba->queue_count; i++) { -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 2/3] hisi_sas: add device tree support for hip07
Chipset hip07 incorporates v2 hw. Signed-off-by: John Garry <john.ga...@huawei.com> Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 9825a3f..758e06f 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -2319,6 +2319,7 @@ static int hisi_sas_v2_remove(struct platform_device *pdev) static const struct of_device_id sas_v2_of_match[] = { { .compatible = "hisilicon,hip06-sas-v2",}, + { .compatible = "hisilicon,hip07-sas-v2",}, {}, }; MODULE_DEVICE_TABLE(of, sas_v2_of_match); -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/3] devicetree: bindings: scsi: hisi_sas hip07 support
On 23/09/2016 19:36, Rob Herring wrote: On Tue, Sep 20, 2016 at 06:48:58PM +0800, John Garry wrote: Add support for hip07 chipset to bindings. Chipset hip07 has v2 hw. The sas-v2 quirk amt is expanded to cover hip07. Signed-off-by: John Garry <john.ga...@huawei.com> Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> --- Documentation/devicetree/bindings/scsi/hisilicon-sas.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/scsi/hisilicon-sas.txt b/Documentation/devicetree/bindings/scsi/hisilicon-sas.txt index bf2411f..e604527 100644 --- a/Documentation/devicetree/bindings/scsi/hisilicon-sas.txt +++ b/Documentation/devicetree/bindings/scsi/hisilicon-sas.txt @@ -6,6 +6,7 @@ Main node required properties: - compatible : value should be as follows: (a) "hisilicon,hip05-sas-v1" for v1 hw in hip05 chipset (b) "hisilicon,hip06-sas-v2" for v2 hw in hip06 chipset + (c) "hisilicon,hip07-sas-v2" for v2 hw in hip07 chipset - sas-addr : array of 8 bytes for host SAS address - reg : Address and length of the SAS register - hisilicon,sas-syscon: phandle of syscon used for sas control @@ -47,7 +48,7 @@ Main node required properties: increasing order. Optional main node properties: - - hip06-sas-v2-quirk-amt : when set, indicates that the v2 controller has the + - hip06/7-sas-v2-quirk-amt : when set, indicates that the v2 controller has the Just use the existing property name for hip07. OK, but you mean existing hip06 property (hip06-sas-v2-quirk-amt), right? "am-max-transmissions" limitation. Example: -- 1.9.1 . -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/3] devicetree: bindings: scsi: hisi_sas hip07 support
Add support for hip07 chipset to bindings. Chipset hip07 has v2 hw. The sas-v2 quirk amt is expanded to cover hip07. Signed-off-by: John Garry <john.ga...@huawei.com> Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> --- Documentation/devicetree/bindings/scsi/hisilicon-sas.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/scsi/hisilicon-sas.txt b/Documentation/devicetree/bindings/scsi/hisilicon-sas.txt index bf2411f..e604527 100644 --- a/Documentation/devicetree/bindings/scsi/hisilicon-sas.txt +++ b/Documentation/devicetree/bindings/scsi/hisilicon-sas.txt @@ -6,6 +6,7 @@ Main node required properties: - compatible : value should be as follows: (a) "hisilicon,hip05-sas-v1" for v1 hw in hip05 chipset (b) "hisilicon,hip06-sas-v2" for v2 hw in hip06 chipset + (c) "hisilicon,hip07-sas-v2" for v2 hw in hip07 chipset - sas-addr : array of 8 bytes for host SAS address - reg : Address and length of the SAS register - hisilicon,sas-syscon: phandle of syscon used for sas control @@ -47,7 +48,7 @@ Main node required properties: increasing order. Optional main node properties: - - hip06-sas-v2-quirk-amt : when set, indicates that the v2 controller has the + - hip06/7-sas-v2-quirk-amt : when set, indicates that the v2 controller has the "am-max-transmissions" limitation. Example: -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 3/3] hisi_sas: add v2 hw support for different refclk
Some hip06 D03 and hip07 D05 boards have different reference clock frequencies for the SAS controller. Register PHY_CTRL needs to be programmed differently according to this frequency, so add support for this. The default register setting in PHY_CTRL is for 50MHz, so only update this register when the refclk frequency is 66MHz. The register cannot be set according to hip06 or hip07 as some variants of hip06 D03 board are 50MHz and some are 66MHz (early editions). All hip07 D05 are 50MHz. For ACPI we expect the _RST handler to set the correct value for PHY_CTRL (we take an alternate approach for DT and ACPI as ACPI does not support fixed-clock device type). Signed-off-by: John Garry <john.ga...@huawei.com> Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> --- drivers/scsi/hisi_sas/hisi_sas.h | 2 ++ drivers/scsi/hisi_sas/hisi_sas_main.c | 7 +++ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 4 +++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 72c9852..64046c5 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -13,6 +13,7 @@ #define _HISI_SAS_H_ #include +#include #include #include #include @@ -183,6 +184,7 @@ struct hisi_hba { u32 ctrl_reset_reg; u32 ctrl_reset_sts_reg; u32 ctrl_clock_ena_reg; + u32 refclk_frequency_mhz; u8 sas_addr[SAS_ADDR_SIZE]; int n_phy; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 2f872f7..0bc3165 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1396,6 +1396,7 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev, struct hisi_hba *hisi_hba; struct device *dev = >dev; struct device_node *np = pdev->dev.of_node; + struct clk *refclk; shost = scsi_host_alloc(_sas_sht, sizeof(*hisi_hba)); if (!shost) @@ -1432,6 +1433,12 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev, goto err_out; } + refclk = devm_clk_get(>dev, NULL); + if (IS_ERR(refclk)) + dev_info(dev, "no ref clk property\n"); + else + hisi_hba->refclk_frequency_mhz = clk_get_rate(refclk) / 100; + if (device_property_read_u32(dev, "phy-count", _hba->n_phy)) goto err_out; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index c1e3aa7..7014d99 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -837,7 +837,9 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba) hisi_sas_phy_write32(hisi_hba, i, SL_RX_BCAST_CHK_MSK, 0x0); hisi_sas_phy_write32(hisi_hba, i, CHL_INT_COAL_EN, 0x0); hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_OOB_RESTART_MSK, 0x0); - hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL, 0x199B694); + if (hisi_hba->refclk_frequency_mhz == 66) + hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL, 0x199B694); + /* else, do nothing -> leave it how you found it */ } for (i = 0; i < hisi_hba->queue_count; i++) { -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 0/3] hisi_sas add hip07 support
This patchset introduces support for hip07 SoC. The hip07 SoC has the same v2 hw as in hip06. Support for different reference clock is required as some SAS registers need be programmed differently, depending on the refclock rate. Related patchset: - https://patchwork.ozlabs.org/patch/665172/ Once 4.9-rc1 is released, the D03 dts can be updated for the refclock. Note: there will be only 1 D03 dts, UEFI will update the refclock rate for that board in the fdt at boot time. John Garry (3): devicetree: bindings: scsi: hisi_sas add hip07 support hisi_sas: add device tree support for hip07 hisi_sas: add v2 hw support for different refclk Documentation/devicetree/bindings/scsi/hisilicon-sas.txt | 3 ++- drivers/scsi/hisi_sas/hisi_sas.h | 2 ++ drivers/scsi/hisi_sas/hisi_sas_main.c| 7 +++ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 8 ++-- 4 files changed, 17 insertions(+), 3 deletions(-) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/3] hisi_sas: add device tree support for hip07
Chipset hip07 incorporates v2 hw. Signed-off-by: John Garry <john.ga...@huawei.com> Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 9825a3f..c1e3aa7 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -777,7 +777,8 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba) /* Global registers init */ /* Deal with am-max-transmissions quirk */ - if (device_property_present(dev, "hip06-sas-v2-quirk-amt")) { + if (device_property_present(dev, "hip06-sas-v2-quirk-amt") || + device_property_present(dev, "hip07-sas-v2-quirk-amt")) { hisi_sas_write32(hisi_hba, AM_CFG_MAX_TRANS, 0x2020); hisi_sas_write32(hisi_hba, AM_CFG_SINGLE_PORT_MAX_TRANS, 0x2020); @@ -2319,6 +2320,7 @@ static int hisi_sas_v2_remove(struct platform_device *pdev) static const struct of_device_id sas_v2_of_match[] = { { .compatible = "hisilicon,hip06-sas-v2",}, + { .compatible = "hisilicon,hip07-sas-v2",}, {}, }; MODULE_DEVICE_TABLE(of, sas_v2_of_match); -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] [SCSI] wd719x: Avoid calling request_firmware under spinlock
On 15/09/2016 15:08, John Garry wrote: On 15/09/2016 14:48, Vaishali Thakkar wrote: It is preferrable to use request_firmware where sleeping is allowed. Using it under spinlock can cause blocking. Here, the function wd719x_chip_init calls request_firmware while holding a spinlock. So, let's access it outside the spinlock. Coccinelle is used to detect the issue. Signed-off-by: Vaishali Thakkar <vaishali.thak...@oracle.com> --- Please note that the patch is compile-tested only. And this change may require driver testing. --- drivers/scsi/wd719x.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/wd719x.c b/drivers/scsi/wd719x.c index e3da1a2..b8e57f3 100644 --- a/drivers/scsi/wd719x.c +++ b/drivers/scsi/wd719x.c @@ -518,13 +518,14 @@ static int wd719x_host_reset(struct scsi_cmnd *cmd) int result; dev_info(>pdev->dev, "host reset requested\n"); -spin_lock_irqsave(wd->sh->host_lock, flags); + In the version of code I have flags is only used for this spinlock, so can flags be removed? I see we're just relocating the spinlock, so ignore me /* Try to reinit the RISC */ if (wd719x_chip_init(wd) == 0) result = SUCCESS; else result = FAILED; +spin_lock_irqsave(wd->sh->host_lock, flags); /* flush all SCBs */ list_for_each_entry_safe(scb, tmp, >active_scbs, list) { struct scsi_cmnd *tmp_cmd = scb->cmd; -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html . -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] [SCSI] wd719x: Avoid calling request_firmware under spinlock
On 15/09/2016 14:48, Vaishali Thakkar wrote: It is preferrable to use request_firmware where sleeping is allowed. Using it under spinlock can cause blocking. Here, the function wd719x_chip_init calls request_firmware while holding a spinlock. So, let's access it outside the spinlock. Coccinelle is used to detect the issue. Signed-off-by: Vaishali Thakkar--- Please note that the patch is compile-tested only. And this change may require driver testing. --- drivers/scsi/wd719x.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/wd719x.c b/drivers/scsi/wd719x.c index e3da1a2..b8e57f3 100644 --- a/drivers/scsi/wd719x.c +++ b/drivers/scsi/wd719x.c @@ -518,13 +518,14 @@ static int wd719x_host_reset(struct scsi_cmnd *cmd) int result; dev_info(>pdev->dev, "host reset requested\n"); - spin_lock_irqsave(wd->sh->host_lock, flags); + In the version of code I have flags is only used for this spinlock, so can flags be removed? /* Try to reinit the RISC */ if (wd719x_chip_init(wd) == 0) result = SUCCESS; else result = FAILED; + spin_lock_irqsave(wd->sh->host_lock, flags); /* flush all SCBs */ list_for_each_entry_safe(scb, tmp, >active_scbs, list) { struct scsi_cmnd *tmp_cmd = scb->cmd; -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 01/15] hisi_sas: save completion queue read pointer
Optimise by saving an avoidable read in the cq interrupt. The queue read pointer will only be updated by software, so don't bother re-reading what was already written in the previous interrupt. Signed-off-by: John Garry <john.ga...@huawei.com> --- drivers/scsi/hisi_sas/hisi_sas.h | 1 + drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 6 ++ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 5 ++--- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index ca55ec2..9410335 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -94,6 +94,7 @@ struct hisi_sas_port { struct hisi_sas_cq { struct hisi_hba *hisi_hba; + int rd_point; int id; }; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index 1abbc2e..3b31b20 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -1565,14 +1565,11 @@ static irqreturn_t cq_interrupt_v1_hw(int irq, void *p) struct hisi_sas_complete_v1_hdr *complete_queue = (struct hisi_sas_complete_v1_hdr *) hisi_hba->complete_hdr[queue]; - u32 irq_value, rd_point, wr_point; + u32 irq_value, rd_point = cq->rd_point, wr_point; irq_value = hisi_sas_read32(hisi_hba, OQ_INT_SRC); hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue); - - rd_point = hisi_sas_read32(hisi_hba, - COMPL_Q_0_RD_PTR + (0x14 * queue)); wr_point = hisi_sas_read32(hisi_hba, COMPL_Q_0_WR_PTR + (0x14 * queue)); @@ -1600,6 +1597,7 @@ static irqreturn_t cq_interrupt_v1_hw(int irq, void *p) } /* update rd_point */ + cq->rd_point = rd_point; hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point); return IRQ_HANDLED; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index bf9b693..11006c9 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -2049,7 +2049,7 @@ static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p) struct hisi_sas_slot *slot; struct hisi_sas_itct *itct; struct hisi_sas_complete_v2_hdr *complete_queue; - u32 irq_value, rd_point, wr_point, dev_id; + u32 irq_value, rd_point = cq->rd_point, wr_point, dev_id; int queue = cq->id; complete_queue = hisi_hba->complete_hdr[queue]; @@ -2057,8 +2057,6 @@ static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p) hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue); - rd_point = hisi_sas_read32(hisi_hba, COMPL_Q_0_RD_PTR + - (0x14 * queue)); wr_point = hisi_sas_read32(hisi_hba, COMPL_Q_0_WR_PTR + (0x14 * queue)); @@ -2106,6 +2104,7 @@ static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p) } /* update rd_point */ + cq->rd_point = rd_point; hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point); return IRQ_HANDLED; } -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 09/15] hisi_sas: set dma mask before allocate DMA memory
The device DMA mask was being set after the bulk of the DMA allocations in the driver init, so potentially DMA allocates fail. To resolve, relocate before allocating the DMA memory when initialising the driver. Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- drivers/scsi/hisi_sas/hisi_sas_main.c | 13 ++--- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index d58e223..2f872f7 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1439,6 +1439,12 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev, _hba->queue_count)) goto err_out; + if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)) && + dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32))) { + dev_err(dev, "No usable DMA addressing method\n"); + goto err_out; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); hisi_hba->regs = devm_ioremap_resource(dev, res); if (IS_ERR(hisi_hba->regs)) @@ -1486,13 +1492,6 @@ int hisi_sas_probe(struct platform_device *pdev, hisi_hba = shost_priv(shost); platform_set_drvdata(pdev, sha); - if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)) && - dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32))) { - dev_err(dev, "No usable DMA addressing method\n"); - rc = -EIO; - goto err_out_ha; - } - phy_nr = port_nr = hisi_hba->n_phy; arr_phy = devm_kcalloc(dev, phy_nr, sizeof(void *), GFP_KERNEL); -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 02/15] hisi_sas: save delivery queue write pointer
Optimise by saving an avoidable read in the get_free_slot function. The delivery queue write pointer will only be updated by software, so don't bother re-reading what was already written in the previous call to start_delivery function. Signed-off-by: John Garry <john.ga...@huawei.com> --- drivers/scsi/hisi_sas/hisi_sas.h | 7 +++ drivers/scsi/hisi_sas/hisi_sas_main.c | 5 + drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 12 +++- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 9 ++--- 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 9410335..72c9852 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -98,6 +98,12 @@ struct hisi_sas_cq { int id; }; +struct hisi_sas_dq { + struct hisi_hba *hisi_hba; + int wr_point; + int id; +}; + struct hisi_sas_device { enum sas_device_typedev_type; struct hisi_hba *hisi_hba; @@ -194,6 +200,7 @@ struct hisi_hba { struct Scsi_Host *shost; struct hisi_sas_cq cq[HISI_SAS_MAX_QUEUES]; + struct hisi_sas_dq dq[HISI_SAS_MAX_QUEUES]; struct hisi_sas_phy phy[HISI_SAS_MAX_PHYS]; struct hisi_sas_port port[HISI_SAS_MAX_PHYS]; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 85c73d3..5d56576 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1239,11 +1239,16 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost) for (i = 0; i < hisi_hba->queue_count; i++) { struct hisi_sas_cq *cq = _hba->cq[i]; + struct hisi_sas_dq *dq = _hba->dq[i]; /* Completion queue structure */ cq->id = i; cq->hisi_hba = hisi_hba; + /* Delivery queue structure */ + dq->id = i; + dq->hisi_hba = hisi_hba; + /* Delivery queue */ s = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS; hisi_hba->cmd_hdr[i] = dma_alloc_coherent(dev, s, diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index 3b31b20..b537464 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -875,12 +875,13 @@ static int get_wideport_bitmap_v1_hw(struct hisi_hba *hisi_hba, int port_id) static int get_free_slot_v1_hw(struct hisi_hba *hisi_hba, int *q, int *s) { struct device *dev = _hba->pdev->dev; + struct hisi_sas_dq *dq; u32 r, w; int queue = hisi_hba->queue; while (1) { - w = hisi_sas_read32_relaxed(hisi_hba, - DLVRY_Q_0_WR_PTR + (queue * 0x14)); + dq = _hba->dq[queue]; + w = dq->wr_point; r = hisi_sas_read32_relaxed(hisi_hba, DLVRY_Q_0_RD_PTR + (queue * 0x14)); if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) { @@ -903,10 +904,11 @@ static void start_delivery_v1_hw(struct hisi_hba *hisi_hba) { int dlvry_queue = hisi_hba->slot_prep->dlvry_queue; int dlvry_queue_slot = hisi_hba->slot_prep->dlvry_queue_slot; + struct hisi_sas_dq *dq = _hba->dq[dlvry_queue]; - hisi_sas_write32(hisi_hba, -DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14), -++dlvry_queue_slot % HISI_SAS_QUEUE_SLOTS); + dq->wr_point = ++dlvry_queue_slot % HISI_SAS_QUEUE_SLOTS; + hisi_sas_write32(hisi_hba, DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14), +dq->wr_point); } static int prep_prd_sge_v1_hw(struct hisi_hba *hisi_hba, diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 11006c9..e0c124b 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -1023,12 +1023,13 @@ static int get_wideport_bitmap_v2_hw(struct hisi_hba *hisi_hba, int port_id) static int get_free_slot_v2_hw(struct hisi_hba *hisi_hba, int *q, int *s) { struct device *dev = _hba->pdev->dev; + struct hisi_sas_dq *dq; u32 r, w; int queue = hisi_hba->queue; while (1) { - w = hisi_sas_read32_relaxed(hisi_hba, - DLVRY_Q_0_WR_PTR + (queue * 0x14)); + dq = _hba->dq[queue]; + w = dq->wr_point; r = hisi_sas_read32_relaxed(hisi_hba, DLVRY_Q_0_RD_PTR + (queue * 0x14)); if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) { @@ -1051,9 +1052,11 @@ static void start_delivery_v2_hw(struct hisi_hba *hisi_hba) { int dlvry_queue = hisi_hba->slot_
[PATCH 04/15] hisi_sas: only zero slot memory when reused
Currently the slot memory is zeroed when it is freed and also when it is reused, like in hisi_sas_task_prep(). Optimise by avoiding the redundant zeroing in the free. Signed-off-by: John Garry <john.ga...@huawei.com> --- 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 5d56576..0e48751 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -97,7 +97,7 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, slot->task = NULL; slot->port = NULL; hisi_sas_slot_index_free(hisi_hba, slot->idx); - memset(slot, 0, sizeof(*slot)); + /* slot memory is fully zeroed when it is reused */ } EXPORT_SYMBOL_GPL(hisi_sas_slot_task_free); -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 00/15] hisi_sas misc fixes and minor optimisations
This patchset introdcues some minor bug fixes and optimisations for v1+v2 hw. No new functional features are introduced in this patchset. John Garry (15): hisi_sas: save completion queue read pointer hisi_sas: save delivery queue write pointer hisi_sas: keep CHL_INT2 masked for v2 HW hisi_sas: only zero slot memory when reused hisi_sas: use safe BITS_PER_BYTE for slot tag size calculation hisi_sas: disable dlvry queues once at reset for v2 hw hisi_sas: fix phy8 linkrate calculation in phy_up_v2_hw() hisi_sas: fix a potential warning for sata disk ejection hisi_sas: set dma mask before allocate DMA memory hisi_sas: fix HBA SAS addr endianness for v2 hw hisi_sas: fix HBA SAS addr endianness for v1 hw hisi_sas: remove init_id_frame_v2_hw() hisi_sas: remove init_id_frame_v1_hw() hisi_sas: add missing SATA pending device type to v2 hw hisi_sas: send three identify before PHY up drivers/scsi/hisi_sas/hisi_sas.h | 8 + drivers/scsi/hisi_sas/hisi_sas_main.c | 48 ++--- drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 36 +++ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 66 -- 4 files changed, 70 insertions(+), 88 deletions(-) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 15/15] hisi_sas: send three identify before phy up
When the v2 hw is attached with many disks through an expander, there may be OOB reset resulting in a PHY going down after the speed is negotiated (very low probability). This issue is resolved by modifying the link control registers to send three identify frames before the PHY is ready (according to 6.10.3.3.2 in SAS 3.0 spec) and close ready when the PHY is down. Signed-off-by: NengLong Zhao <zhaonengl...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 20 1 file changed, 16 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 735ebff..9825a3f 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -117,6 +117,8 @@ #define SL_CONTROL (PORT_BASE + 0x94) #define SL_CONTROL_NOTIFY_EN_OFF 0 #define SL_CONTROL_NOTIFY_EN_MSK (0x1 << SL_CONTROL_NOTIFY_EN_OFF) +#define SL_CONTROL_CTA_OFF 17 +#define SL_CONTROL_CTA_MSK (0x1 << SL_CONTROL_CTA_OFF) #define TX_ID_DWORD0 (PORT_BASE + 0x9c) #define TX_ID_DWORD1 (PORT_BASE + 0xa0) #define TX_ID_DWORD2 (PORT_BASE + 0xa4) @@ -124,6 +126,9 @@ #define TX_ID_DWORD4 (PORT_BASE + 0xaC) #define TX_ID_DWORD5 (PORT_BASE + 0xb0) #define TX_ID_DWORD6 (PORT_BASE + 0xb4) +#define TXID_AUTO (PORT_BASE + 0xb8) +#define TXID_AUTO_CT3_OFF 1 +#define TXID_AUTO_CT3_MSK (0x1 << TXID_AUTO_CT3_OFF) #define RX_IDAF_DWORD0 (PORT_BASE + 0xc4) #define RX_IDAF_DWORD1 (PORT_BASE + 0xc8) #define RX_IDAF_DWORD2 (PORT_BASE + 0xcc) @@ -814,6 +819,8 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba) hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE, 0x855); hisi_sas_phy_write32(hisi_hba, i, SAS_PHY_CTRL, 0x30b9908); 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, CHL_INT0, 0x); hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, 0x); @@ -1901,16 +1908,21 @@ end: static int phy_down_v2_hw(int phy_no, struct hisi_hba *hisi_hba) { int res = 0; - u32 phy_cfg, phy_state; + u32 phy_state, sl_ctrl, txid_auto; hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 1); - phy_cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG); - phy_state = hisi_sas_read32(hisi_hba, PHY_STATE); - hisi_sas_phy_down(hisi_hba, phy_no, (phy_state & 1 << phy_no) ? 1 : 0); + sl_ctrl = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL); + hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, +sl_ctrl & ~SL_CONTROL_CTA_MSK); + + txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no, TXID_AUTO); + hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO, +txid_auto | TXID_AUTO_CT3_MSK); + 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); -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 08/15] hisi_sas: fix a potential warning for sata disk ejection
If hisi_sas_task_prep() fails for a SATA device due to PHY down, we return a failure to libata and also call task_done(), which will cause ata_qc_complete() to be called twice: - first call from hisi_sas_task_prep(), which will clear flag ATA_QCFLAG_ACTIVE - ata_qc_complete() called from libata The warning call trace is as follows: [ 117.070206] [] __ata_qc_complete+0xf4/0x11c [ 117.070208] [] ata_qc_complete+0x180/0x200 [ 117.070210] [] ata_qc_issue+0x110/0x354 [ 117.070212] [] ata_exec_internal_sg+0x240/0x4d0 [ 117.070214] [] ata_exec_internal+0x60/0xa0 [ 117.070217] [] ata_read_log_page+0x188/0x1b4 [ 117.070218] [] ata_eh_analyze_ncq_error+0xa8/0x274 [ 117.070220] [] ata_eh_link_autopsy+0x94/0x8c8 [ 117.070222] [] ata_eh_autopsy+0x34/0xe8 [ 117.070223] [] ata_do_eh+0x28/0xc0 [ 117.070225] [] ata_std_error_handler+0x3c/0x84 [ 117.070227] [] ata_scsi_port_error_handler+0x480/0x674 [ 117.070230] [] async_sas_ata_eh+0x44/0x78 [ 117.070231] [] async_run_entry_fn+0x40/0x104 [ 117.070234] [] process_one_work+0x128/0x2f0 [ 117.070235] [] worker_thread+0x58/0x434 [ 117.070237] [] kthread+0xd4/0xe8 [ 117.070240] [] ret_from_fork+0x10/0x40 The issue is resolved by simply returning a failure status code to the upper layer. Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> Signed-off-by: John Garry <john.ga...@huawei.com> --- drivers/scsi/hisi_sas/hisi_sas_main.c | 26 ++ 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index dcb17a3..d58e223 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -205,26 +205,12 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba, } port = device->port->lldd_port; if (port && !port->port_attached) { - if (sas_protocol_ata(task->task_proto)) { - struct task_status_struct *ts = >task_status; - - dev_info(dev, -"task prep: SATA/STP port%d not attach device\n", -device->port->id); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_PHY_DOWN; - task->task_done(task); - } else { - struct task_status_struct *ts = >task_status; - - dev_info(dev, -"task prep: SAS port%d does not attach device\n", -device->port->id); - ts->resp = SAS_TASK_UNDELIVERED; - ts->stat = SAS_PHY_DOWN; - task->task_done(task); - } - return 0; + dev_info(dev, "task prep: %s port%d not attach device\n", +(sas_protocol_ata(task->task_proto)) ? +"SATA/STP" : "SAS", +device->port->id); + + return SAS_PHY_DOWN; } if (!sas_protocol_ata(task->task_proto)) { -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 10/15] hisi_sas: fix HBA SAS addr endianness for v2 hw
The endianness for the SAS address in the TX_ID_DWORD registers is set incorrectly. We see errors like this in the boot log: [7.583284] sas: target proto 0x0 at 5d1108e7923f:0x1f not handled This is due to the host SAS addr not matching the PHY SAS addr in the expander host-attached phy discovery responses. To fix, we byte swap the SAS addr from BE to LE (which is the endianness of the SAS controller). Signed-off-by: John Garry <john.ga...@huawei.com> Signed-off-by: Xiang Chen <chenxian...@hisilicon.com> --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 8 1 file changed, 4 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 ae3..ce84211 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -562,13 +562,13 @@ static void config_id_frame_v2_hw(struct hisi_hba *hisi_hba, int phy_no) hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD0, __swab32(identify_buffer[0])); hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD1, - identify_buffer[2]); + __swab32(identify_buffer[1])); hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD2, - identify_buffer[1]); + __swab32(identify_buffer[2])); hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD3, - identify_buffer[4]); + __swab32(identify_buffer[3])); hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD4, - identify_buffer[3]); + __swab32(identify_buffer[4])); hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD5, __swab32(identify_buffer[5])); } -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html