linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements
@ 2017-03-22 17:25 John Garry
  2017-03-22 17:25 ` [PATCH 01/23] scsi: hisi_sas: add to_hisi_sas_port() John Garry
                   ` (23 more replies)
  0 siblings, 24 replies; 25+ messages in thread
From: John Garry @ 2017-03-22 17:25 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, john.garry2, linux-scsi, linux-kernel, zhangfei.gao,
	John Garry

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

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 01/23] scsi: hisi_sas: add to_hisi_sas_port()
  2017-03-22 17:25 [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements John Garry
@ 2017-03-22 17:25 ` John Garry
  2017-03-22 17:25 ` [PATCH 02/23] scsi: hisi_sas: add controller reset John Garry
                   ` (22 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: John Garry @ 2017-03-22 17:25 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, john.garry2, linux-scsi, linux-kernel, zhangfei.gao,
	John Garry, Xiang Chen

Introduce function to get hisi_sas_port from
asd_sas_port.

Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Xiang Chen <chenxiang66@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 = &hisi_hba->pdev->dev;
 	int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx;
 
-	if (!device->port) {
+	if (!sas_port) {
 		struct task_status_struct *ts = &task->task_status;
 
 		ts->resp = SAS_TASK_UNDELIVERED;
@@ -206,7 +213,8 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba,
 		rc = SAS_PHY_DOWN;
 		return rc;
 	}
-	port = device->port->lldd_port;
+
+	port = to_hisi_sas_port(sas_port);
 	if (port && !port->port_attached) {
 		dev_info(dev, "task prep: %s port%d not attach device\n",
 			 (sas_protocol_ata(task->task_proto)) ?
@@ -545,7 +553,7 @@ static void hisi_sas_port_notify_formed(struct asd_sas_phy *sas_phy)
 	struct hisi_hba *hisi_hba = sas_ha->lldd_ha;
 	struct hisi_sas_phy *phy = sas_phy->lldd_phy;
 	struct asd_sas_port *sas_port = sas_phy->port;
-	struct hisi_sas_port *port = &hisi_hba->port[phy->port_id];
+	struct hisi_sas_port *port = to_hisi_sas_port(sas_port);
 	unsigned long flags;
 
 	if (!sas_port)
@@ -990,13 +998,14 @@ static int hisi_sas_query_task(struct sas_task *task)
 	struct device *dev = &hisi_hba->pdev->dev;
 	struct hisi_sas_port *port;
 	struct hisi_sas_slot *slot;
+	struct asd_sas_port *sas_port = device->port;
 	struct hisi_sas_cmd_hdr *cmd_hdr_base;
 	int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx;
 
 	if (!device->port)
 		return -1;
 
-	port = device->port->lldd_port;
+	port = to_hisi_sas_port(sas_port);
 
 	/* simply get a slot and send abort command */
 	rc = hisi_sas_slot_index_alloc(hisi_hba, &slot_idx);
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
index 854fbea..022ad10 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
@@ -508,6 +508,8 @@ static void setup_itct_v1_hw(struct hisi_hba *hisi_hba,
 	struct device *dev = &hisi_hba->pdev->dev;
 	u64 qw0, device_id = sas_dev->device_id;
 	struct hisi_sas_itct *itct = &hisi_hba->itct[device_id];
+	struct asd_sas_port *sas_port = device->port;
+	struct hisi_sas_port *port = to_hisi_sas_port(sas_port);
 
 	memset(itct, 0, sizeof(*itct));
 
@@ -528,7 +530,7 @@ static void setup_itct_v1_hw(struct hisi_hba *hisi_hba,
 		(1 << ITCT_HDR_AWT_CONTROL_OFF) |
 		(device->max_linkrate << ITCT_HDR_MAX_CONN_RATE_OFF) |
 		(1 << ITCT_HDR_VALID_LINK_NUM_OFF) |
-		(device->port->id << ITCT_HDR_PORT_ID_OFF));
+		(port->id << ITCT_HDR_PORT_ID_OFF));
 	itct->qw0 = cpu_to_le64(qw0);
 
 	/* qw1 */
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index 1b21445..1590e2f 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -676,7 +676,8 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba,
 	u64 qw0, device_id = sas_dev->device_id;
 	struct hisi_sas_itct *itct = &hisi_hba->itct[device_id];
 	struct domain_device *parent_dev = device->parent;
-	struct hisi_sas_port *port = device->port->lldd_port;
+	struct asd_sas_port *sas_port = device->port;
+	struct hisi_sas_port *port = to_hisi_sas_port(sas_port);
 
 	memset(itct, 0, sizeof(*itct));
 
@@ -1920,7 +1921,8 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba,
 	struct domain_device *parent_dev = device->parent;
 	struct hisi_sas_device *sas_dev = device->lldd_dev;
 	struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
-	struct hisi_sas_port *port = device->port->lldd_port;
+	struct asd_sas_port *sas_port = device->port;
+	struct hisi_sas_port *port = to_hisi_sas_port(sas_port);
 	u8 *buf_cmd;
 	int has_data = 0, rc = 0, hdr_tag = 0;
 	u32 dw1 = 0, dw2 = 0;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 02/23] scsi: hisi_sas: add controller reset
  2017-03-22 17:25 [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements John Garry
  2017-03-22 17:25 ` [PATCH 01/23] scsi: hisi_sas: add to_hisi_sas_port() John Garry
@ 2017-03-22 17:25 ` John Garry
  2017-03-22 17:25 ` [PATCH 03/23] scsi: hisi_sas: move PHY init to hisi_sas_scan_start() John Garry
                   ` (21 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: John Garry @ 2017-03-22 17:25 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, john.garry2, linux-scsi, linux-kernel, zhangfei.gao,
	Xiang Chen, Xiaofei Tan, John Garry

From: Xiang Chen <chenxiang66@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 <chenxiang66@hisilicon.com>
Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
Signed-off-by: John Garry <john.garry@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 = &hisi_hba->pdev->dev;
 
+	if (unlikely(test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)))
+		return -EINVAL;
+
 	/* protect task_prep and start_delivery sequence */
 	spin_lock_irqsave(&hisi_hba->lock, flags);
 	rc = hisi_sas_task_prep(task, hisi_hba, is_tmf, tmf, &pass);
@@ -613,6 +616,20 @@ static void hisi_sas_release_task(struct hisi_hba *hisi_hba,
 		hisi_sas_do_release_task(hisi_hba, sas_phy->id, device);
 }
 
+static void hisi_sas_release_tasks(struct hisi_hba *hisi_hba)
+{
+	int i;
+
+	for (i = 0; i < HISI_SAS_MAX_PHYS; i++) {
+		struct hisi_sas_phy *phy = &hisi_hba->phy[i];
+		struct asd_sas_phy *sas_phy = &phy->sas_phy;
+
+		if (!sas_phy->port)
+			continue;
+		hisi_sas_port_notify_deformed(sas_phy);
+	}
+}
+
 static void hisi_sas_dev_gone(struct domain_device *device)
 {
 	struct hisi_sas_device *sas_dev = device->lldd_dev;
@@ -803,6 +820,40 @@ static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device,
 				sizeof(ssp_task), tmf);
 }
 
+static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba)
+{
+	int rc;
+
+	if (!hisi_hba->hw->soft_reset)
+		return -1;
+
+	if (!test_and_set_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) {
+		struct device *dev = &hisi_hba->pdev->dev;
+		struct sas_ha_struct *sas_ha = &hisi_hba->sha;
+		unsigned long flags;
+
+		dev_dbg(dev, "controller reset begins!\n");
+		scsi_block_requests(hisi_hba->shost);
+		rc = hisi_hba->hw->soft_reset(hisi_hba);
+		if (rc) {
+			dev_warn(dev, "controller reset failed (%d)\n", rc);
+			goto out;
+		}
+		spin_lock_irqsave(&hisi_hba->lock, flags);
+		hisi_sas_release_tasks(hisi_hba);
+		spin_unlock_irqrestore(&hisi_hba->lock, flags);
+
+		sas_ha->notify_ha_event(sas_ha, HAE_RESET);
+		dev_dbg(dev, "controller reset successful!\n");
+	} else
+		return -1;
+
+out:
+	scsi_unblock_requests(hisi_hba->shost);
+	clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags);
+	return rc;
+}
+
 static int hisi_sas_abort_task(struct sas_task *task)
 {
 	struct scsi_lun lun;
@@ -1002,6 +1053,9 @@ static int hisi_sas_query_task(struct sas_task *task)
 	struct hisi_sas_cmd_hdr *cmd_hdr_base;
 	int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx;
 
+	if (unlikely(test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)))
+		return -EINVAL;
+
 	if (!device->port)
 		return -1;
 
@@ -1190,6 +1244,37 @@ void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy)
 }
 EXPORT_SYMBOL_GPL(hisi_sas_phy_down);
 
+void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 old_state,
+			      u32 state)
+{
+	struct sas_ha_struct *sas_ha = &hisi_hba->sha;
+	int phy_no;
+
+	for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
+		struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+		struct asd_sas_phy *sas_phy = &phy->sas_phy;
+		struct asd_sas_port *sas_port = sas_phy->port;
+		struct domain_device *dev;
+
+		if (sas_phy->enabled) {
+			/* Report PHY state change to libsas */
+			if (state & (1 << phy_no))
+				continue;
+
+			if (old_state & (1 << phy_no))
+				/* PHY down but was up before */
+				hisi_sas_phy_down(hisi_hba, phy_no, 0);
+		}
+		if (!sas_port)
+			continue;
+		dev = sas_port->port_dev;
+
+		if (DEV_IS_EXPANDER(dev->dev_type))
+			sas_ha->notify_phy_event(sas_phy, PORTE_BROADCAST_RCVD);
+	}
+}
+EXPORT_SYMBOL_GPL(hisi_sas_rescan_topology);
+
 static struct scsi_transport_template *hisi_sas_stt;
 
 static struct scsi_host_template hisi_sas_sht = {
@@ -1228,6 +1313,37 @@ void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy)
 	.lldd_port_deformed	= hisi_sas_port_deformed,
 };
 
+void hisi_sas_init_mem(struct hisi_hba *hisi_hba)
+{
+	int i, s, max_command_entries = hisi_hba->hw->max_command_entries;
+
+	for (i = 0; i < hisi_hba->queue_count; i++) {
+		struct hisi_sas_cq *cq = &hisi_hba->cq[i];
+		struct hisi_sas_dq *dq = &hisi_hba->dq[i];
+
+		s = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS;
+		memset(hisi_hba->cmd_hdr[i], 0, s);
+		dq->wr_point = 0;
+
+		s = hisi_hba->hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS;
+		memset(hisi_hba->complete_hdr[i], 0, s);
+		cq->rd_point = 0;
+	}
+
+	s = sizeof(struct hisi_sas_initial_fis) * hisi_hba->n_phy;
+	memset(hisi_hba->initial_fis, 0, s);
+
+	s = max_command_entries * sizeof(struct hisi_sas_iost);
+	memset(hisi_hba->iost, 0, s);
+
+	s = max_command_entries * sizeof(struct hisi_sas_breakpoint);
+	memset(hisi_hba->breakpoint, 0, s);
+
+	s = max_command_entries * sizeof(struct hisi_sas_breakpoint) * 2;
+	memset(hisi_hba->sata_breakpoint, 0, s);
+}
+EXPORT_SYMBOL_GPL(hisi_sas_init_mem);
+
 static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
 {
 	struct platform_device *pdev = hisi_hba->pdev;
@@ -1266,7 +1382,6 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
 					&hisi_hba->cmd_hdr_dma[i], GFP_KERNEL);
 		if (!hisi_hba->cmd_hdr[i])
 			goto err_out;
-		memset(hisi_hba->cmd_hdr[i], 0, s);
 
 		/* Completion queue */
 		s = hisi_hba->hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS;
@@ -1274,7 +1389,6 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
 				&hisi_hba->complete_hdr_dma[i], GFP_KERNEL);
 		if (!hisi_hba->complete_hdr[i])
 			goto err_out;
-		memset(hisi_hba->complete_hdr[i], 0, s);
 	}
 
 	s = HISI_SAS_STATUS_BUF_SZ;
@@ -1309,16 +1423,12 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
 	if (!hisi_hba->iost)
 		goto err_out;
 
-	memset(hisi_hba->iost, 0, s);
-
 	s = max_command_entries * sizeof(struct hisi_sas_breakpoint);
 	hisi_hba->breakpoint = dma_alloc_coherent(dev, s,
 				&hisi_hba->breakpoint_dma, GFP_KERNEL);
 	if (!hisi_hba->breakpoint)
 		goto err_out;
 
-	memset(hisi_hba->breakpoint, 0, s);
-
 	hisi_hba->slot_index_count = max_command_entries;
 	s = hisi_hba->slot_index_count / BITS_PER_BYTE;
 	hisi_hba->slot_index_tags = devm_kzalloc(dev, s, GFP_KERNEL);
@@ -1335,14 +1445,13 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
 				&hisi_hba->initial_fis_dma, GFP_KERNEL);
 	if (!hisi_hba->initial_fis)
 		goto err_out;
-	memset(hisi_hba->initial_fis, 0, s);
 
 	s = max_command_entries * sizeof(struct hisi_sas_breakpoint) * 2;
 	hisi_hba->sata_breakpoint = dma_alloc_coherent(dev, s,
 				&hisi_hba->sata_breakpoint_dma, GFP_KERNEL);
 	if (!hisi_hba->sata_breakpoint)
 		goto err_out;
-	memset(hisi_hba->sata_breakpoint, 0, s);
+	hisi_sas_init_mem(hisi_hba);
 
 	hisi_sas_slot_index_init(hisi_hba);
 
@@ -1413,6 +1522,14 @@ static void hisi_sas_free(struct hisi_hba *hisi_hba)
 		destroy_workqueue(hisi_hba->wq);
 }
 
+static void hisi_sas_rst_work_handler(struct work_struct *work)
+{
+	struct hisi_hba *hisi_hba =
+		container_of(work, struct hisi_hba, rst_work);
+
+	hisi_sas_controller_reset(hisi_hba);
+}
+
 static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev,
 					      const struct hisi_sas_hw *hw)
 {
@@ -1430,6 +1547,7 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev,
 	}
 	hisi_hba = shost_priv(shost);
 
+	INIT_WORK(&hisi_hba->rst_work, hisi_sas_rst_work_handler);
 	hisi_hba->hw = hw;
 	hisi_hba->pdev = pdev;
 	hisi_hba->shost = shost;
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index 1590e2f..53651cf 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -257,6 +257,10 @@
 #define AM_CFG_MAX_TRANS		(0x5010)
 #define AM_CFG_SINGLE_PORT_MAX_TRANS	(0x5014)
 
+#define AXI_MASTER_CFG_BASE		(0x5000)
+#define AM_CTRL_GLOBAL			(0x0)
+#define AM_CURR_TRANS_RETURN	(0x150)
+
 /* HW dma structures */
 /* Delivery queue header */
 /* dw0 */
@@ -1079,6 +1083,14 @@ static void stop_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
 	disable_phy_v2_hw(hisi_hba, phy_no);
 }
 
+static void stop_phys_v2_hw(struct hisi_hba *hisi_hba)
+{
+	int i;
+
+	for (i = 0; i < hisi_hba->n_phy; i++)
+		stop_phy_v2_hw(hisi_hba, i);
+}
+
 static void phy_hard_reset_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
 {
 	struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
@@ -2857,6 +2869,87 @@ static int hisi_sas_v2_init(struct hisi_hba *hisi_hba)
 	return 0;
 }
 
+static void interrupt_disable_v2_hw(struct hisi_hba *hisi_hba)
+{
+	struct platform_device *pdev = hisi_hba->pdev;
+	int i;
+
+	for (i = 0; i < hisi_hba->queue_count; i++)
+		hisi_sas_write32(hisi_hba, OQ0_INT_SRC_MSK + 0x4 * i, 0x1);
+
+	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, 0xffffffff);
+	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK2, 0xffffffff);
+	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0xffffffff);
+	hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, 0xffffffff);
+
+	for (i = 0; i < hisi_hba->n_phy; i++) {
+		hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0xffffffff);
+		hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0xffffffff);
+	}
+
+	for (i = 0; i < 128; i++)
+		synchronize_irq(platform_get_irq(pdev, i));
+}
+
+static int soft_reset_v2_hw(struct hisi_hba *hisi_hba)
+{
+	struct device *dev = &hisi_hba->pdev->dev;
+	u32 old_state, state;
+	int rc, cnt;
+	int phy_no;
+
+	old_state = hisi_sas_read32(hisi_hba, PHY_STATE);
+
+	interrupt_disable_v2_hw(hisi_hba);
+	hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0x0);
+
+	stop_phys_v2_hw(hisi_hba);
+
+	mdelay(10);
+
+	hisi_sas_write32(hisi_hba, AXI_MASTER_CFG_BASE + AM_CTRL_GLOBAL, 0x1);
+
+	/* wait until bus idle */
+	cnt = 0;
+	while (1) {
+		u32 status = hisi_sas_read32_relaxed(hisi_hba,
+				AXI_MASTER_CFG_BASE + AM_CURR_TRANS_RETURN);
+
+		if (status == 0x3)
+			break;
+
+		udelay(10);
+		if (cnt++ > 10) {
+			dev_info(dev, "wait axi bus state to idle timeout!\n");
+			return -1;
+		}
+	}
+
+	hisi_sas_init_mem(hisi_hba);
+
+	rc = hw_init_v2_hw(hisi_hba);
+	if (rc)
+		return rc;
+
+	/* Re-enable the PHYs */
+	for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
+		struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+		struct asd_sas_phy *sas_phy = &phy->sas_phy;
+
+		if (sas_phy->enabled)
+			start_phy_v2_hw(hisi_hba, phy_no);
+	}
+
+	/* Wait for the PHYs to come up and read the PHY state */
+	msleep(1000);
+
+	state = hisi_sas_read32(hisi_hba, PHY_STATE);
+
+	hisi_sas_rescan_topology(hisi_hba, old_state, state);
+
+	return 0;
+}
+
 static const struct hisi_sas_hw hisi_sas_v2_hw = {
 	.hw_init = hisi_sas_v2_init,
 	.setup_itct = setup_itct_v2_hw,
@@ -2879,6 +2972,7 @@ static int hisi_sas_v2_init(struct hisi_hba *hisi_hba)
 	.phy_get_max_linkrate = phy_get_max_linkrate_v2_hw,
 	.max_command_entries = HISI_SAS_COMMAND_ENTRIES_V2_HW,
 	.complete_hdr_size = sizeof(struct hisi_sas_complete_v2_hdr),
+	.soft_reset = soft_reset_v2_hw,
 };
 
 static int hisi_sas_v2_probe(struct platform_device *pdev)
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 03/23] scsi: hisi_sas: move PHY init to hisi_sas_scan_start()
  2017-03-22 17:25 [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements John Garry
  2017-03-22 17:25 ` [PATCH 01/23] scsi: hisi_sas: add to_hisi_sas_port() John Garry
  2017-03-22 17:25 ` [PATCH 02/23] scsi: hisi_sas: add controller reset John Garry
@ 2017-03-22 17:25 ` John Garry
  2017-03-22 17:25 ` [PATCH 04/23] scsi: hisi_sas: add softreset function for SATA disk John Garry
                   ` (20 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: John Garry @ 2017-03-22 17:25 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, john.garry2, linux-scsi, linux-kernel, zhangfei.gao,
	John Garry, Xiang Chen

Relocate the PHY init code from LLDD hw init path
to hisi_sas_scan_start().

Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Xiang Chen <chenxiang66@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 = &hisi_hba->sha;
 
-	if (hisi_hba->scan_finished == 0)
+	/* Wait for PHY up interrupt to occur */
+	if (time < HZ)
 		return 0;
 
 	sas_drain_work(sha);
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
index 022ad10..43988eb 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
@@ -1847,8 +1847,6 @@ static int hisi_sas_v1_init(struct hisi_hba *hisi_hba)
 	if (rc)
 		return rc;
 
-	phys_init_v1_hw(hisi_hba);
-
 	return 0;
 }
 
@@ -1862,6 +1860,7 @@ static int hisi_sas_v1_init(struct hisi_hba *hisi_hba)
 	.get_free_slot = get_free_slot_v1_hw,
 	.start_delivery = start_delivery_v1_hw,
 	.slot_complete = slot_complete_v1_hw,
+	.phys_init = phys_init_v1_hw,
 	.phy_enable = enable_phy_v1_hw,
 	.phy_disable = disable_phy_v1_hw,
 	.phy_hard_reset = phy_hard_reset_v1_hw,
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index 53651cf..73e4f66 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -2864,8 +2864,6 @@ static int hisi_sas_v2_init(struct hisi_hba *hisi_hba)
 	if (rc)
 		return rc;
 
-	phys_init_v2_hw(hisi_hba);
-
 	return 0;
 }
 
@@ -2965,6 +2963,7 @@ static int soft_reset_v2_hw(struct hisi_hba *hisi_hba)
 	.get_free_slot = get_free_slot_v2_hw,
 	.start_delivery = start_delivery_v2_hw,
 	.slot_complete = slot_complete_v2_hw,
+	.phys_init = phys_init_v2_hw,
 	.phy_enable = enable_phy_v2_hw,
 	.phy_disable = disable_phy_v2_hw,
 	.phy_hard_reset = phy_hard_reset_v2_hw,
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 04/23] scsi: hisi_sas: add softreset function for SATA disk
  2017-03-22 17:25 [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements John Garry
                   ` (2 preceding siblings ...)
  2017-03-22 17:25 ` [PATCH 03/23] scsi: hisi_sas: move PHY init to hisi_sas_scan_start() John Garry
@ 2017-03-22 17:25 ` John Garry
  2017-03-22 17:25 ` [PATCH 05/23] scsi: hisi_sas: remove hisi_sas_port_deformed() John Garry
                   ` (19 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: John Garry @ 2017-03-22 17:25 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, john.garry2, linux-scsi, linux-kernel, zhangfei.gao,
	Xiang Chen, John Garry

From: Xiang Chen <chenxiang66@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 <chenxiang66@hisilicon.com>
Signed-off-by: John Garry <john.garry@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(&task->ssp_task, parameter, para_len);
+		if (dev_is_sata(device)) {
+			task->ata_task.device_control_reg_update = 1;
+			memcpy(&task->ata_task.fis, parameter, para_len);
+		} else {
+			memcpy(&task->ssp_task, parameter, para_len);
+		}
 		task->task_done = hisi_sas_task_done;
 
 		task->slow_task->timer.data = (unsigned long) task;
@@ -742,8 +748,7 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
 		/* Even TMF timed out, return direct. */
 		if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
 			if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
-				dev_err(dev, "abort tmf: TMF task[%d] timeout\n",
-					tmf->tag_of_task_to_be_managed);
+				dev_err(dev, "abort tmf: TMF task timeout\n");
 				if (task->lldd_task) {
 					struct hisi_sas_slot *slot =
 						task->lldd_task;
@@ -803,6 +808,63 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
 	return res;
 }
 
+static void hisi_sas_fill_ata_reset_cmd(struct ata_device *dev,
+		bool reset, int pmp, u8 *fis)
+{
+	struct ata_taskfile tf;
+
+	ata_tf_init(dev, &tf);
+	if (reset)
+		tf.ctl |= ATA_SRST;
+	else
+		tf.ctl &= ~ATA_SRST;
+	tf.command = ATA_CMD_DEV_RESET;
+	ata_tf_to_fis(&tf, pmp, 0, fis);
+}
+
+static int hisi_sas_softreset_ata_disk(struct domain_device *device)
+{
+	u8 fis[20] = {0};
+	struct ata_port *ap = device->sata_dev.ap;
+	struct ata_link *link;
+	int rc = TMF_RESP_FUNC_FAILED;
+	struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+	struct device *dev = &hisi_hba->pdev->dev;
+	int s = sizeof(struct host_to_dev_fis);
+	unsigned long flags;
+
+	ata_for_each_link(link, ap, EDGE) {
+		int pmp = sata_srst_pmp(link);
+
+		hisi_sas_fill_ata_reset_cmd(link->device, 1, pmp, fis);
+		rc = hisi_sas_exec_internal_tmf_task(device, fis, s, NULL);
+		if (rc != TMF_RESP_FUNC_COMPLETE)
+			break;
+	}
+
+	if (rc == TMF_RESP_FUNC_COMPLETE) {
+		ata_for_each_link(link, ap, EDGE) {
+			int pmp = sata_srst_pmp(link);
+
+			hisi_sas_fill_ata_reset_cmd(link->device, 0, pmp, fis);
+			rc = hisi_sas_exec_internal_tmf_task(device, fis,
+							     s, NULL);
+			if (rc != TMF_RESP_FUNC_COMPLETE)
+				dev_err(dev, "ata disk de-reset failed\n");
+		}
+	} else {
+		dev_err(dev, "ata disk reset failed\n");
+	}
+
+	if (rc == TMF_RESP_FUNC_COMPLETE) {
+		spin_lock_irqsave(&hisi_hba->lock, flags);
+		hisi_sas_release_task(hisi_hba, device);
+		spin_unlock_irqrestore(&hisi_hba->lock, flags);
+	}
+
+	return rc;
+}
+
 static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device,
 				u8 *lun, struct hisi_sas_tmf_task *tmf)
 {
@@ -908,7 +970,7 @@ static int hisi_sas_abort_task(struct sas_task *task)
 		if (task->dev->dev_type == SAS_SATA_DEV) {
 			hisi_sas_internal_task_abort(hisi_hba, device,
 						     HISI_SAS_INT_ABT_DEV, 0);
-			rc = TMF_RESP_FUNC_COMPLETE;
+			rc = hisi_sas_softreset_ata_disk(device);
 		}
 	} else if (task->task_proto & SAS_PROTOCOL_SMP) {
 		/* SMP */
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index 73e4f66..401e5c6 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -1961,7 +1961,8 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba,
 		dw1 &= ~CMD_HDR_DIR_MSK;
 	}
 
-	if (0 == task->ata_task.fis.command)
+	if ((task->ata_task.fis.command == ATA_CMD_DEV_RESET) &&
+			(task->ata_task.fis.control & ATA_SRST))
 		dw1 |= 1 << CMD_HDR_RESET_OFF;
 
 	dw1 |= (get_ata_protocol(task->ata_task.fis.command, task->data_dir))
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 05/23] scsi: hisi_sas: remove hisi_sas_port_deformed()
  2017-03-22 17:25 [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements John Garry
                   ` (3 preceding siblings ...)
  2017-03-22 17:25 ` [PATCH 04/23] scsi: hisi_sas: add softreset function for SATA disk John Garry
@ 2017-03-22 17:25 ` John Garry
  2017-03-22 17:25 ` [PATCH 06/23] scsi: hisi_sas: error hisi_sas_task_prep() when port down John Garry
                   ` (18 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: John Garry @ 2017-03-22 17:25 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, john.garry2, linux-scsi, linux-kernel, zhangfei.gao,
	John Garry, Xiang Chen

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.garry@huawei.com>
Signed-off-by: Xiang Chen <chenxiang66@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_head	list;
 };
 
 struct hisi_sas_cq {
@@ -114,6 +113,7 @@ struct hisi_sas_device {
 	u64 attached_phy;
 	u64 device_id;
 	atomic64_t running_req;
+	struct list_head	list;
 	u8 dev_status;
 };
 
@@ -166,7 +166,7 @@ struct hisi_sas_hw {
 			  struct hisi_sas_slot *slot,
 			  int device_id, int abort_flag, int tag_to_abort);
 	int (*slot_complete)(struct hisi_hba *hisi_hba,
-			     struct hisi_sas_slot *slot, int abort);
+			     struct hisi_sas_slot *slot);
 	void (*phys_init)(struct hisi_hba *hisi_hba);
 	void (*phy_enable)(struct hisi_hba *hisi_hba, int phy_no);
 	void (*phy_disable)(struct hisi_hba *hisi_hba, int phy_no);
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 9d9f305..f64c1b6 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -308,7 +308,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba,
 		goto err_out_command_table;
 	}
 
-	list_add_tail(&slot->entry, &port->list);
+	list_add_tail(&slot->entry, &sas_dev->list);
 	spin_lock(&task->task_state_lock);
 	task->task_state_flags |= SAS_TASK_AT_INITIATOR;
 	spin_unlock(&task->task_state_lock);
@@ -424,6 +424,7 @@ static struct hisi_sas_device *hisi_sas_alloc_dev(struct domain_device *device)
 			sas_dev->dev_type = device->dev_type;
 			sas_dev->hisi_hba = hisi_hba;
 			sas_dev->sas_device = device;
+			INIT_LIST_HEAD(&hisi_hba->devices[i].list);
 			break;
 		}
 	}
@@ -568,63 +569,55 @@ static void hisi_sas_port_notify_formed(struct asd_sas_phy *sas_phy)
 	spin_unlock_irqrestore(&hisi_hba->lock, flags);
 }
 
-static void hisi_sas_do_release_task(struct hisi_hba *hisi_hba, int phy_no,
-				     struct domain_device *device)
+static void hisi_sas_do_release_task(struct hisi_hba *hisi_hba,
+				     struct sas_task *task,
+				     struct hisi_sas_slot *slot)
 {
-	struct hisi_sas_phy *phy;
-	struct hisi_sas_port *port;
-	struct hisi_sas_slot *slot, *slot2;
-	struct device *dev = &hisi_hba->pdev->dev;
+	struct task_status_struct *ts;
+	unsigned long flags;
 
-	phy = &hisi_hba->phy[phy_no];
-	port = phy->port;
-	if (!port)
+	if (!task)
 		return;
 
-	list_for_each_entry_safe(slot, slot2, &port->list, entry) {
-		struct sas_task *task;
-
-		task = slot->task;
-		if (device && task->dev != device)
-			continue;
-
-		dev_info(dev, "Release slot [%d:%d], task [%p]:\n",
-			 slot->dlvry_queue, slot->dlvry_queue_slot, task);
-		hisi_hba->hw->slot_complete(hisi_hba, slot, 1);
-	}
-}
+	ts = &task->task_status;
 
-static void hisi_sas_port_notify_deformed(struct asd_sas_phy *sas_phy)
-{
-	struct domain_device *device;
-	struct hisi_sas_phy *phy = sas_phy->lldd_phy;
-	struct asd_sas_port *sas_port = sas_phy->port;
+	ts->resp = SAS_TASK_COMPLETE;
+	ts->stat = SAS_ABORTED_TASK;
+	spin_lock_irqsave(&task->task_state_lock, flags);
+	task->task_state_flags &=
+		~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
+	task->task_state_flags |= SAS_TASK_STATE_DONE;
+	spin_unlock_irqrestore(&task->task_state_lock, flags);
 
-	list_for_each_entry(device, &sas_port->dev_list, dev_list_node)
-		hisi_sas_do_release_task(phy->hisi_hba, sas_phy->id, device);
+	hisi_sas_slot_task_free(hisi_hba, task, slot);
 }
 
+/* hisi_hba.lock should be locked */
 static void hisi_sas_release_task(struct hisi_hba *hisi_hba,
 			struct domain_device *device)
 {
-	struct asd_sas_port *port = device->port;
-	struct asd_sas_phy *sas_phy;
+	struct hisi_sas_slot *slot, *slot2;
+	struct hisi_sas_device *sas_dev = device->lldd_dev;
 
-	list_for_each_entry(sas_phy, &port->phy_list, port_phy_el)
-		hisi_sas_do_release_task(hisi_hba, sas_phy->id, device);
+	list_for_each_entry_safe(slot, slot2, &sas_dev->list, entry)
+		hisi_sas_do_release_task(hisi_hba, slot->task, slot);
 }
 
 static void hisi_sas_release_tasks(struct hisi_hba *hisi_hba)
 {
+	struct hisi_sas_device *sas_dev;
+	struct domain_device *device;
 	int i;
 
-	for (i = 0; i < HISI_SAS_MAX_PHYS; i++) {
-		struct hisi_sas_phy *phy = &hisi_hba->phy[i];
-		struct asd_sas_phy *sas_phy = &phy->sas_phy;
+	for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) {
+		sas_dev = &hisi_hba->devices[i];
+		device = sas_dev->sas_device;
 
-		if (!sas_phy->port)
+		if ((sas_dev->dev_type == SAS_PHY_UNUSED) ||
+		    !device)
 			continue;
-		hisi_sas_port_notify_deformed(sas_phy);
+
+		hisi_sas_release_task(hisi_hba, device);
 	}
 }
 
@@ -958,7 +951,7 @@ static int hisi_sas_abort_task(struct sas_task *task)
 				slot = &hisi_hba->slot_info
 					[tmf_task.tag_of_task_to_be_managed];
 				spin_lock_irqsave(&hisi_hba->lock, flags);
-				hisi_hba->hw->slot_complete(hisi_hba, slot, 1);
+				hisi_hba->hw->slot_complete(hisi_hba, slot);
 				spin_unlock_irqrestore(&hisi_hba->lock, flags);
 			}
 		}
@@ -1149,11 +1142,8 @@ static int hisi_sas_query_task(struct sas_task *task)
 	if (rc)
 		goto err_out_tag;
 
-	/* Port structure is static for the HBA, so
-	*  even if the port is deformed it is ok
-	*  to reference.
-	*/
-	list_add_tail(&slot->entry, &port->list);
+
+	list_add_tail(&slot->entry, &sas_dev->list);
 	spin_lock(&task->task_state_lock);
 	task->task_state_flags |= SAS_TASK_AT_INITIATOR;
 	spin_unlock(&task->task_state_lock);
@@ -1259,11 +1249,6 @@ static void hisi_sas_port_formed(struct asd_sas_phy *sas_phy)
 	hisi_sas_port_notify_formed(sas_phy);
 }
 
-static void hisi_sas_port_deformed(struct asd_sas_phy *sas_phy)
-{
-	hisi_sas_port_notify_deformed(sas_phy);
-}
-
 static void hisi_sas_phy_disconnected(struct hisi_sas_phy *phy)
 {
 	phy->phy_attached = 0;
@@ -1369,7 +1354,6 @@ void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 old_state,
 	.lldd_lu_reset		= hisi_sas_lu_reset,
 	.lldd_query_task	= hisi_sas_query_task,
 	.lldd_port_formed	= hisi_sas_port_formed,
-	.lldd_port_deformed	= hisi_sas_port_deformed,
 };
 
 void hisi_sas_init_mem(struct hisi_hba *hisi_hba)
@@ -1414,7 +1398,6 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
 		hisi_sas_phy_init(hisi_hba, i);
 		hisi_hba->port[i].port_attached = 0;
 		hisi_hba->port[i].id = -1;
-		INIT_LIST_HEAD(&hisi_hba->port[i].list);
 	}
 
 	for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) {
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
index 43988eb..2f3e877 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
@@ -1277,7 +1277,7 @@ static void slot_err_v1_hw(struct hisi_hba *hisi_hba,
 }
 
 static int slot_complete_v1_hw(struct hisi_hba *hisi_hba,
-			       struct hisi_sas_slot *slot, int abort)
+			       struct hisi_sas_slot *slot)
 {
 	struct sas_task *task = slot->task;
 	struct hisi_sas_device *sas_dev;
@@ -1307,9 +1307,8 @@ static int slot_complete_v1_hw(struct hisi_hba *hisi_hba,
 	memset(ts, 0, sizeof(*ts));
 	ts->resp = SAS_TASK_COMPLETE;
 
-	if (unlikely(!sas_dev || abort)) {
-		if (!sas_dev)
-			dev_dbg(dev, "slot complete: port has not device\n");
+	if (unlikely(!sas_dev)) {
+		dev_dbg(dev, "slot complete: port has no device\n");
 		ts->stat = SAS_PHY_DOWN;
 		goto out;
 	}
@@ -1622,7 +1621,7 @@ static irqreturn_t cq_interrupt_v1_hw(int irq, void *p)
 		 */
 		slot->cmplt_queue_slot = rd_point;
 		slot->cmplt_queue = queue;
-		slot_complete_v1_hw(hisi_hba, slot, 0);
+		slot_complete_v1_hw(hisi_hba, slot);
 
 		if (++rd_point >= HISI_SAS_QUEUE_SLOTS)
 			rd_point = 0;
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index 401e5c6..b9d5132 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -625,6 +625,7 @@ hisi_sas_device *alloc_dev_quirk_v2_hw(struct domain_device *device)
 			sas_dev->dev_type = device->dev_type;
 			sas_dev->hisi_hba = hisi_hba;
 			sas_dev->sas_device = device;
+			INIT_LIST_HEAD(&hisi_hba->devices[i].list);
 			break;
 		}
 	}
@@ -1724,8 +1725,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 }
 
 static int
-slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot,
-		    int abort)
+slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
 {
 	struct sas_task *task = slot->task;
 	struct hisi_sas_device *sas_dev;
@@ -1752,9 +1752,8 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 	memset(ts, 0, sizeof(*ts));
 	ts->resp = SAS_TASK_COMPLETE;
 
-	if (unlikely(!sas_dev || abort)) {
-		if (!sas_dev)
-			dev_dbg(dev, "slot complete: port has not device\n");
+	if (unlikely(!sas_dev)) {
+		dev_dbg(dev, "slot complete: port has no device\n");
 		ts->stat = SAS_PHY_DOWN;
 		goto out;
 	}
@@ -2615,7 +2614,7 @@ static void cq_tasklet_v2_hw(unsigned long val)
 				slot = &hisi_hba->slot_info[iptt];
 				slot->cmplt_queue_slot = rd_point;
 				slot->cmplt_queue = queue;
-				slot_complete_v2_hw(hisi_hba, slot, 0);
+				slot_complete_v2_hw(hisi_hba, slot);
 
 				act_tmp &= ~(1 << ncq_tag_count);
 				ncq_tag_count = ffs(act_tmp);
@@ -2625,7 +2624,7 @@ static void cq_tasklet_v2_hw(unsigned long val)
 			slot = &hisi_hba->slot_info[iptt];
 			slot->cmplt_queue_slot = rd_point;
 			slot->cmplt_queue = queue;
-			slot_complete_v2_hw(hisi_hba, slot, 0);
+			slot_complete_v2_hw(hisi_hba, slot);
 		}
 
 		if (++rd_point >= HISI_SAS_QUEUE_SLOTS)
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 06/23] scsi: hisi_sas: error hisi_sas_task_prep() when port down
  2017-03-22 17:25 [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements John Garry
                   ` (4 preceding siblings ...)
  2017-03-22 17:25 ` [PATCH 05/23] scsi: hisi_sas: remove hisi_sas_port_deformed() John Garry
@ 2017-03-22 17:25 ` John Garry
  2017-03-22 17:25 ` [PATCH 07/23] scsi: hisi_sas: only reset link for PHY_FUNC_LINK_RESET John Garry
                   ` (17 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: John Garry @ 2017-03-22 17:25 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, john.garry2, linux-scsi, linux-kernel, zhangfei.gao,
	John Garry, Xiang Chen

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.garry@huawei.com>
Signed-off-by: Xiang Chen <chenxiang66@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

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 07/23] scsi: hisi_sas: only reset link for PHY_FUNC_LINK_RESET
  2017-03-22 17:25 [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements John Garry
                   ` (5 preceding siblings ...)
  2017-03-22 17:25 ` [PATCH 06/23] scsi: hisi_sas: error hisi_sas_task_prep() when port down John Garry
@ 2017-03-22 17:25 ` John Garry
  2017-03-22 17:25 ` [PATCH 08/23] scsi: hisi_sas: modify error handling for v2 hw John Garry
                   ` (16 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: John Garry @ 2017-03-22 17:25 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, john.garry2, linux-scsi, linux-kernel, zhangfei.gao,
	John Garry, Xiang Chen

We currently do a hard reset for a link reset. Change this
to do a link reset only.

Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Xiang Chen <chenxiang@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

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 08/23] scsi: hisi_sas: modify error handling for v2 hw
  2017-03-22 17:25 [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements John Garry
                   ` (6 preceding siblings ...)
  2017-03-22 17:25 ` [PATCH 07/23] scsi: hisi_sas: only reset link for PHY_FUNC_LINK_RESET John Garry
@ 2017-03-22 17:25 ` John Garry
  2017-03-22 17:25 ` [PATCH 09/23] scsi: hisi_sas: modify hisi_sas_abort_task() for SSP John Garry
                   ` (15 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: John Garry @ 2017-03-22 17:25 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, john.garry2, linux-scsi, linux-kernel, zhangfei.gao,
	Xiang Chen, John Garry

From: Xiang Chen <chenxiang66@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 <chenxiang66@hisilicon.com>
Signed-off-by: John Garry <john.garry@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, &slot->abort_slot);
-			/* immediately return and do not complete */
+
+		if (unlikely(slot->abort))
 			return ts->stat;
-		}
 		goto out;
 	}
 
@@ -1842,7 +1839,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 	}
 
 out:
-
+	task->task_state_flags |= SAS_TASK_STATE_DONE;
 	hisi_sas_slot_task_free(hisi_hba, task, slot);
 	sts = ts->stat;
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 09/23] scsi: hisi_sas: modify hisi_sas_abort_task() for SSP
  2017-03-22 17:25 [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements John Garry
                   ` (7 preceding siblings ...)
  2017-03-22 17:25 ` [PATCH 08/23] scsi: hisi_sas: modify error handling for v2 hw John Garry
@ 2017-03-22 17:25 ` John Garry
  2017-03-22 17:25 ` [PATCH 10/23] scsi: hisi_sas: hardreset for SATA disk in LU reset John Garry
                   ` (14 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: John Garry @ 2017-03-22 17:25 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, john.garry2, linux-scsi, linux-kernel, zhangfei.gao,
	John Garry, Xiang Chen

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.garry@huawei.com>
Signed-off-by: Xiang Chen <chenxiang66@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, &lun);
 		tmf_task.tmf = TMF_ABORT_TASK;
@@ -943,21 +944,22 @@ static int hisi_sas_abort_task(struct sas_task *task)
 		rc = hisi_sas_debug_issue_ssp_tmf(task->dev, lun.scsi_lun,
 						  &tmf_task);
 
-		/* if successful, clear the task and callback forwards.*/
-		if (rc == TMF_RESP_FUNC_COMPLETE) {
+		rc2 = hisi_sas_internal_task_abort(hisi_hba, device,
+						   HISI_SAS_INT_ABT_CMD, tag);
+		/*
+		 * If the TMF finds that the IO is not in the device and also
+		 * the internal abort does not succeed, then it is safe to
+		 * free the slot.
+		 * Note: if the internal abort succeeds then the slot
+		 * will have already been completed
+		 */
+		if (rc == TMF_RESP_FUNC_COMPLETE && rc2 != TMF_RESP_FUNC_SUCC) {
 			if (task->lldd_task) {
-				struct hisi_sas_slot *slot;
-
-				slot = &hisi_hba->slot_info
-					[tmf_task.tag_of_task_to_be_managed];
 				spin_lock_irqsave(&hisi_hba->lock, flags);
-				hisi_hba->hw->slot_complete(hisi_hba, slot);
+				hisi_sas_do_release_task(hisi_hba, task, slot);
 				spin_unlock_irqrestore(&hisi_hba->lock, flags);
 			}
 		}
-
-		hisi_sas_internal_task_abort(hisi_hba, device,
-					     HISI_SAS_INT_ABT_CMD, tag);
 	} else if (task->task_proto & SAS_PROTOCOL_SATA ||
 		task->task_proto & SAS_PROTOCOL_STP) {
 		if (task->dev->dev_type == SAS_SATA_DEV) {
@@ -1220,6 +1222,12 @@ static int hisi_sas_query_task(struct sas_task *task)
 		goto exit;
 	}
 
+	if (task->task_status.resp == SAS_TASK_COMPLETE &&
+		task->task_status.stat == TMF_RESP_FUNC_SUCC) {
+		res = TMF_RESP_FUNC_SUCC;
+		goto exit;
+	}
+
 	/* TMF timed out, return direct. */
 	if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
 		if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index a35f881..ad5a7e6 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -1766,7 +1766,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 		goto out;
 	case STAT_IO_COMPLETE:
 		/* internal abort command complete */
-		ts->stat = TMF_RESP_FUNC_COMPLETE;
+		ts->stat = TMF_RESP_FUNC_SUCC;
 		goto out;
 	case STAT_IO_NO_DEVICE:
 		ts->stat = TMF_RESP_FUNC_COMPLETE;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 10/23] scsi: hisi_sas: hardreset for SATA disk in LU reset
  2017-03-22 17:25 [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements John Garry
                   ` (8 preceding siblings ...)
  2017-03-22 17:25 ` [PATCH 09/23] scsi: hisi_sas: modify hisi_sas_abort_task() for SSP John Garry
@ 2017-03-22 17:25 ` John Garry
  2017-03-22 17:25 ` [PATCH 11/23] scsi: hisi_sas: check for SAS_TASK_STATE_ABORTED in slot complete John Garry
                   ` (13 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: John Garry @ 2017-03-22 17:25 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, john.garry2, linux-scsi, linux-kernel, zhangfei.gao,
	John Garry, Xiang Chen

When issuing an LU reset for a SATA target, issue an
internal abort and a hard reset.

Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Xiang Chen <chenxiang66@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 = &hisi_hba->pdev->dev;
 	unsigned long flags;
 	int rc = TMF_RESP_FUNC_FAILED;
 
-	tmf_task.tmf = TMF_LU_RESET;
 	sas_dev->dev_status = HISI_SAS_DEV_EH;
-	rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task);
-	if (rc == TMF_RESP_FUNC_COMPLETE) {
-		spin_lock_irqsave(&hisi_hba->lock, flags);
-		hisi_sas_release_task(hisi_hba, device);
-		spin_unlock_irqrestore(&hisi_hba->lock, flags);
-	}
+	if (dev_is_sata(device)) {
+		struct sas_phy *phy;
+
+		/* Clear internal IO and then hardreset */
+		rc = hisi_sas_internal_task_abort(hisi_hba, device,
+						  HISI_SAS_INT_ABT_DEV, 0);
+		if (rc == TMF_RESP_FUNC_FAILED)
+			goto out;
 
-	/* If failed, fall-through I_T_Nexus reset */
+		phy = sas_get_local_phy(device);
+
+		rc = sas_phy_reset(phy, 1);
+
+		if (rc == 0) {
+			spin_lock_irqsave(&hisi_hba->lock, flags);
+			hisi_sas_release_task(hisi_hba, device);
+			spin_unlock_irqrestore(&hisi_hba->lock, flags);
+		}
+		sas_put_local_phy(phy);
+	} else {
+		struct hisi_sas_tmf_task tmf_task = { .tmf =  TMF_LU_RESET };
+
+		rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task);
+		if (rc == TMF_RESP_FUNC_COMPLETE) {
+			spin_lock_irqsave(&hisi_hba->lock, flags);
+			hisi_sas_release_task(hisi_hba, device);
+			spin_unlock_irqrestore(&hisi_hba->lock, flags);
+		}
+	}
+out:
 	dev_err(dev, "lu_reset: for device[%llx]:rc= %d\n",
 		sas_dev->device_id, rc);
 	return rc;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 11/23] scsi: hisi_sas: check for SAS_TASK_STATE_ABORTED in slot complete
  2017-03-22 17:25 [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements John Garry
                   ` (9 preceding siblings ...)
  2017-03-22 17:25 ` [PATCH 10/23] scsi: hisi_sas: hardreset for SATA disk in LU reset John Garry
@ 2017-03-22 17:25 ` John Garry
  2017-03-22 17:25 ` [PATCH 12/23] scsi: hisi_sas: free slots after hardreset John Garry
                   ` (12 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: John Garry @ 2017-03-22 17:25 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, john.garry2, linux-scsi, linux-kernel, zhangfei.gao,
	John Garry

Check in slot_complete_v2_hw() for whether a task has
already been completed by upper layer.

Signed-off-by: John Garry <john.garry@huawei.com>
Reviewed-by: Xiang Chen <chenxiang66@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 =
 			&complete_queue[slot->cmplt_queue_slot];
+	int aborted;
 
 	if (unlikely(!task || !task->lldd_task || !task->dev))
 		return -EINVAL;
@@ -1745,12 +1746,21 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 	device = task->dev;
 	sas_dev = device->lldd_dev;
 
+	spin_lock(&task->task_state_lock);
+	aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED;
 	task->task_state_flags &=
 		~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
+	spin_unlock(&task->task_state_lock);
 
 	memset(ts, 0, sizeof(*ts));
 	ts->resp = SAS_TASK_COMPLETE;
 
+	if (unlikely(aborted)) {
+		ts->stat = SAS_ABORTED_TASK;
+		hisi_sas_slot_task_free(hisi_hba, task, slot);
+		return -1;
+	}
+
 	if (unlikely(!sas_dev)) {
 		dev_dbg(dev, "slot complete: port has no device\n");
 		ts->stat = SAS_PHY_DOWN;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 12/23] scsi: hisi_sas: free slots after hardreset
  2017-03-22 17:25 [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements John Garry
                   ` (10 preceding siblings ...)
  2017-03-22 17:25 ` [PATCH 11/23] scsi: hisi_sas: check for SAS_TASK_STATE_ABORTED in slot complete John Garry
@ 2017-03-22 17:25 ` John Garry
  2017-03-22 17:25 ` [PATCH 13/23] scsi: hisi_sas: fix some sas_task.task_state_lock locking John Garry
                   ` (11 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: John Garry @ 2017-03-22 17:25 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, john.garry2, linux-scsi, linux-kernel, zhangfei.gao,
	Xiang Chen, John Garry

From: Xiang Chen <chenxiang66@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 <chenxiang66@hisilicon.com>
Signed-off-by: John Garry <john.garry@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(&hisi_hba->lock, flags);
-	hisi_sas_release_task(hisi_hba, device);
-	spin_unlock_irqrestore(&hisi_hba->lock, flags);
-
-	return 0;
+	if (rc == TMF_RESP_FUNC_COMPLETE) {
+		spin_lock_irqsave(&hisi_hba->lock, flags);
+		hisi_sas_release_task(hisi_hba, device);
+		spin_unlock_irqrestore(&hisi_hba->lock, flags);
+	}
+	return rc;
 }
 
 static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun)
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 13/23] scsi: hisi_sas: fix some sas_task.task_state_lock locking
  2017-03-22 17:25 [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements John Garry
                   ` (11 preceding siblings ...)
  2017-03-22 17:25 ` [PATCH 12/23] scsi: hisi_sas: free slots after hardreset John Garry
@ 2017-03-22 17:25 ` John Garry
  2017-03-22 17:25 ` [PATCH 14/23] scsi: hisi_sas: remove task free'ing for timeouts John Garry
                   ` (10 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: John Garry @ 2017-03-22 17:25 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, john.garry2, linux-scsi, linux-kernel, zhangfei.gao,
	John Garry, Xiang Chen

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.garry@huawei.com>
Signed-off-by: Xiang Chen <chenxiang66@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 = &hisi_hba->pdev->dev;
 	int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx;
+	unsigned long flags;
 
 	if (!sas_port) {
 		struct task_status_struct *ts = &task->task_status;
@@ -308,9 +309,9 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba,
 	}
 
 	list_add_tail(&slot->entry, &sas_dev->list);
-	spin_lock(&task->task_state_lock);
+	spin_lock_irqsave(&task->task_state_lock, flags);
 	task->task_state_flags |= SAS_TASK_AT_INITIATOR;
-	spin_unlock(&task->task_state_lock);
+	spin_unlock_irqrestore(&task->task_state_lock, flags);
 
 	hisi_hba->slot_prep = slot;
 
@@ -922,14 +923,11 @@ static int hisi_sas_abort_task(struct sas_task *task)
 		return TMF_RESP_FUNC_FAILED;
 	}
 
-	spin_lock_irqsave(&task->task_state_lock, flags);
 	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
-		spin_unlock_irqrestore(&task->task_state_lock, flags);
 		rc = TMF_RESP_FUNC_COMPLETE;
 		goto out;
 	}
 
-	spin_unlock_irqrestore(&task->task_state_lock, flags);
 	sas_dev->dev_status = HISI_SAS_DEV_EH;
 	if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) {
 		struct scsi_cmnd *cmnd = task->uldd_task;
@@ -1127,6 +1125,7 @@ static int hisi_sas_query_task(struct sas_task *task)
 	struct asd_sas_port *sas_port = device->port;
 	struct hisi_sas_cmd_hdr *cmd_hdr_base;
 	int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx;
+	unsigned long flags;
 
 	if (unlikely(test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)))
 		return -EINVAL;
@@ -1167,9 +1166,9 @@ static int hisi_sas_query_task(struct sas_task *task)
 
 
 	list_add_tail(&slot->entry, &sas_dev->list);
-	spin_lock(&task->task_state_lock);
+	spin_lock_irqsave(&task->task_state_lock, flags);
 	task->task_state_flags |= SAS_TASK_AT_INITIATOR;
-	spin_unlock(&task->task_state_lock);
+	spin_unlock_irqrestore(&task->task_state_lock, flags);
 
 	hisi_hba->slot_prep = slot;
 
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
index 2f3e877..fc1c1b2 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
@@ -1288,6 +1288,7 @@ static int slot_complete_v1_hw(struct hisi_hba *hisi_hba,
 	struct hisi_sas_complete_v1_hdr *complete_queue =
 			hisi_hba->complete_hdr[slot->cmplt_queue];
 	struct hisi_sas_complete_v1_hdr *complete_hdr;
+	unsigned long flags;
 	u32 cmplt_hdr_data;
 
 	complete_hdr = &complete_queue[slot->cmplt_queue_slot];
@@ -1300,9 +1301,11 @@ static int slot_complete_v1_hw(struct hisi_hba *hisi_hba,
 	device = task->dev;
 	sas_dev = device->lldd_dev;
 
+	spin_lock_irqsave(&task->task_state_lock, flags);
 	task->task_state_flags &=
 		~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
 	task->task_state_flags |= SAS_TASK_STATE_DONE;
+	spin_unlock_irqrestore(&task->task_state_lock, flags);
 
 	memset(ts, 0, sizeof(*ts));
 	ts->resp = SAS_TASK_COMPLETE;
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index f4d8200..2b6e64c 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -1737,6 +1737,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 			hisi_hba->complete_hdr[slot->cmplt_queue];
 	struct hisi_sas_complete_v2_hdr *complete_hdr =
 			&complete_queue[slot->cmplt_queue_slot];
+	unsigned long flags;
 	int aborted;
 
 	if (unlikely(!task || !task->lldd_task || !task->dev))
@@ -1746,11 +1747,11 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 	device = task->dev;
 	sas_dev = device->lldd_dev;
 
-	spin_lock(&task->task_state_lock);
+	spin_lock_irqsave(&task->task_state_lock, flags);
 	aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED;
 	task->task_state_flags &=
 		~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
-	spin_unlock(&task->task_state_lock);
+	spin_unlock_irqrestore(&task->task_state_lock, flags);
 
 	memset(ts, 0, sizeof(*ts));
 	ts->resp = SAS_TASK_COMPLETE;
@@ -1849,7 +1850,9 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 	}
 
 out:
+	spin_lock_irqsave(&task->task_state_lock, flags);
 	task->task_state_flags |= SAS_TASK_STATE_DONE;
+	spin_unlock_irqrestore(&task->task_state_lock, flags);
 	hisi_sas_slot_task_free(hisi_hba, task, slot);
 	sts = ts->stat;
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 14/23] scsi: hisi_sas: remove task free'ing for timeouts
  2017-03-22 17:25 [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements John Garry
                   ` (12 preceding siblings ...)
  2017-03-22 17:25 ` [PATCH 13/23] scsi: hisi_sas: fix some sas_task.task_state_lock locking John Garry
@ 2017-03-22 17:25 ` John Garry
  2017-03-22 17:25 ` [PATCH 15/23] scsi: hisi_sas: process error codes according to their priority John Garry
                   ` (9 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: John Garry @ 2017-03-22 17:25 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, john.garry2, linux-scsi, linux-kernel, zhangfei.gao,
	John Garry

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.garry@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

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 15/23] scsi: hisi_sas: process error codes according to their priority
  2017-03-22 17:25 [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements John Garry
                   ` (13 preceding siblings ...)
  2017-03-22 17:25 ` [PATCH 14/23] scsi: hisi_sas: remove task free'ing for timeouts John Garry
@ 2017-03-22 17:25 ` John Garry
  2017-03-22 17:25 ` [PATCH 16/23] scsi: hisi_sas: some modifications to v2 hw reg init values John Garry
                   ` (8 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: John Garry @ 2017-03-22 17:25 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, john.garry2, linux-scsi, linux-kernel, zhangfei.gao,
	Xiang Chen, John Garry

From: Xiang Chen <chenxiang66@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 <chenxiang66@hisilicon.com>
Signed-off-by: John Garry <john.garry@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_OFF	2
+#define CMPLT_HDR_ERR_PHASE_MSK	(0xff << CMPLT_HDR_ERR_PHASE_OFF)
 #define CMPLT_HDR_RSPNS_XFRD_OFF	10
 #define CMPLT_HDR_RSPNS_XFRD_MSK	(0x1 << CMPLT_HDR_RSPNS_XFRD_OFF)
 #define CMPLT_HDR_ERX_OFF		12
@@ -389,10 +391,10 @@ enum {
 
 enum {
 	TRANS_TX_FAIL_BASE = 0x0, /* dw0 */
-	TRANS_RX_FAIL_BASE = 0x100, /* dw1 */
-	DMA_TX_ERR_BASE = 0x200, /* dw2 bit 15-0 */
-	SIPC_RX_ERR_BASE = 0x300, /* dw2 bit 31-16*/
-	DMA_RX_ERR_BASE = 0x400, /* dw3 */
+	TRANS_RX_FAIL_BASE = 0x20, /* dw1 */
+	DMA_TX_ERR_BASE = 0x40, /* dw2 bit 15-0 */
+	SIPC_RX_ERR_BASE = 0x50, /* dw2 bit 31-16*/
+	DMA_RX_ERR_BASE = 0x60, /* dw3 */
 
 	/* trans tx*/
 	TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS = TRANS_TX_FAIL_BASE, /* 0x0 */
@@ -432,97 +434,100 @@ enum {
 	TRANS_TX_ERR_WITH_WAIT_RECV_TIMEOUT, /* 0x1f for sata/stp */
 
 	/* trans rx */
-	TRANS_RX_ERR_WITH_RXFRAME_CRC_ERR = TRANS_RX_FAIL_BASE, /* 0x100 */
-	TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR, /* 0x101 for sata/stp */
-	TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM, /* 0x102 for ssp/smp */
-	/*IO_ERR_WITH_RXFIS_8B10B_CODE_ERR, [> 0x102 <] for sata/stp */
-	TRANS_RX_ERR_WITH_RXFIS_DECODE_ERROR, /* 0x103 for sata/stp */
-	TRANS_RX_ERR_WITH_RXFIS_CRC_ERR, /* 0x104 for sata/stp */
-	TRANS_RX_ERR_WITH_RXFRAME_LENGTH_OVERRUN, /* 0x105 for smp */
-	/*IO_ERR_WITH_RXFIS_TX SYNCP, [> 0x105 <] for sata/stp */
-	TRANS_RX_ERR_WITH_RXFIS_RX_SYNCP, /* 0x106 for sata/stp*/
-	TRANS_RX_ERR_WITH_LINK_BUF_OVERRUN, /* 0x107 */
-	TRANS_RX_ERR_WITH_BREAK_TIMEOUT, /* 0x108 */
-	TRANS_RX_ERR_WITH_BREAK_REQUEST, /* 0x109 */
-	TRANS_RX_ERR_WITH_BREAK_RECEVIED, /* 0x10a */
-	RESERVED1, /* 0x10b */
-	TRANS_RX_ERR_WITH_CLOSE_NORMAL, /* 0x10c */
-	TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE, /* 0x10d */
-	TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT, /* 0x10e */
-	TRANS_RX_ERR_WITH_CLOSE_COMINIT, /* 0x10f */
-	TRANS_RX_ERR_WITH_DATA_LEN0, /* 0x110 for ssp/smp */
-	TRANS_RX_ERR_WITH_BAD_HASH, /* 0x111 for ssp */
-	/*IO_RX_ERR_WITH_FIS_TOO_SHORT, [> 0x111 <] for sata/stp */
-	TRANS_RX_XRDY_WLEN_ZERO_ERR, /* 0x112 for ssp*/
-	/*IO_RX_ERR_WITH_FIS_TOO_LONG, [> 0x112 <] for sata/stp */
-	TRANS_RX_SSP_FRM_LEN_ERR, /* 0x113 for ssp */
-	/*IO_RX_ERR_WITH_SATA_DEVICE_LOST, [> 0x113 <] for sata */
-	RESERVED2, /* 0x114 */
-	RESERVED3, /* 0x115 */
-	RESERVED4, /* 0x116 */
-	RESERVED5, /* 0x117 */
-	TRANS_RX_ERR_WITH_BAD_FRM_TYPE, /* 0x118 */
-	TRANS_RX_SMP_FRM_LEN_ERR, /* 0x119 */
-	TRANS_RX_SMP_RESP_TIMEOUT_ERR, /* 0x11a */
-	RESERVED6, /* 0x11b */
-	RESERVED7, /* 0x11c */
-	RESERVED8, /* 0x11d */
-	RESERVED9, /* 0x11e */
-	TRANS_RX_R_ERR, /* 0x11f */
+	TRANS_RX_ERR_WITH_RXFRAME_CRC_ERR = TRANS_RX_FAIL_BASE, /* 0x20 */
+	TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR, /* 0x21 for sata/stp */
+	TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM, /* 0x22 for ssp/smp */
+	/*IO_ERR_WITH_RXFIS_8B10B_CODE_ERR, [> 0x22 <] for sata/stp */
+	TRANS_RX_ERR_WITH_RXFIS_DECODE_ERROR, /* 0x23 for sata/stp */
+	TRANS_RX_ERR_WITH_RXFIS_CRC_ERR, /* 0x24 for sata/stp */
+	TRANS_RX_ERR_WITH_RXFRAME_LENGTH_OVERRUN, /* 0x25 for smp */
+	/*IO_ERR_WITH_RXFIS_TX SYNCP, [> 0x25 <] for sata/stp */
+	TRANS_RX_ERR_WITH_RXFIS_RX_SYNCP, /* 0x26 for sata/stp*/
+	TRANS_RX_ERR_WITH_LINK_BUF_OVERRUN, /* 0x27 */
+	TRANS_RX_ERR_WITH_BREAK_TIMEOUT, /* 0x28 */
+	TRANS_RX_ERR_WITH_BREAK_REQUEST, /* 0x29 */
+	TRANS_RX_ERR_WITH_BREAK_RECEVIED, /* 0x2a */
+	RESERVED1, /* 0x2b */
+	TRANS_RX_ERR_WITH_CLOSE_NORMAL, /* 0x2c */
+	TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE, /* 0x2d */
+	TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT, /* 0x2e */
+	TRANS_RX_ERR_WITH_CLOSE_COMINIT, /* 0x2f */
+	TRANS_RX_ERR_WITH_DATA_LEN0, /* 0x30 for ssp/smp */
+	TRANS_RX_ERR_WITH_BAD_HASH, /* 0x31 for ssp */
+	/*IO_RX_ERR_WITH_FIS_TOO_SHORT, [> 0x31 <] for sata/stp */
+	TRANS_RX_XRDY_WLEN_ZERO_ERR, /* 0x32 for ssp*/
+	/*IO_RX_ERR_WITH_FIS_TOO_LONG, [> 0x32 <] for sata/stp */
+	TRANS_RX_SSP_FRM_LEN_ERR, /* 0x33 for ssp */
+	/*IO_RX_ERR_WITH_SATA_DEVICE_LOST, [> 0x33 <] for sata */
+	RESERVED2, /* 0x34 */
+	RESERVED3, /* 0x35 */
+	RESERVED4, /* 0x36 */
+	RESERVED5, /* 0x37 */
+	TRANS_RX_ERR_WITH_BAD_FRM_TYPE, /* 0x38 */
+	TRANS_RX_SMP_FRM_LEN_ERR, /* 0x39 */
+	TRANS_RX_SMP_RESP_TIMEOUT_ERR, /* 0x3a */
+	RESERVED6, /* 0x3b */
+	RESERVED7, /* 0x3c */
+	RESERVED8, /* 0x3d */
+	RESERVED9, /* 0x3e */
+	TRANS_RX_R_ERR, /* 0x3f */
 
 	/* dma tx */
-	DMA_TX_DIF_CRC_ERR = DMA_TX_ERR_BASE, /* 0x200 */
-	DMA_TX_DIF_APP_ERR, /* 0x201 */
-	DMA_TX_DIF_RPP_ERR, /* 0x202 */
-	DMA_TX_DATA_SGL_OVERFLOW, /* 0x203 */
-	DMA_TX_DIF_SGL_OVERFLOW, /* 0x204 */
-	DMA_TX_UNEXP_XFER_ERR, /* 0x205 */
-	DMA_TX_UNEXP_RETRANS_ERR, /* 0x206 */
-	DMA_TX_XFER_LEN_OVERFLOW, /* 0x207 */
-	DMA_TX_XFER_OFFSET_ERR, /* 0x208 */
-	DMA_TX_RAM_ECC_ERR, /* 0x209 */
-	DMA_TX_DIF_LEN_ALIGN_ERR, /* 0x20a */
+	DMA_TX_DIF_CRC_ERR = DMA_TX_ERR_BASE, /* 0x40 */
+	DMA_TX_DIF_APP_ERR, /* 0x41 */
+	DMA_TX_DIF_RPP_ERR, /* 0x42 */
+	DMA_TX_DATA_SGL_OVERFLOW, /* 0x43 */
+	DMA_TX_DIF_SGL_OVERFLOW, /* 0x44 */
+	DMA_TX_UNEXP_XFER_ERR, /* 0x45 */
+	DMA_TX_UNEXP_RETRANS_ERR, /* 0x46 */
+	DMA_TX_XFER_LEN_OVERFLOW, /* 0x47 */
+	DMA_TX_XFER_OFFSET_ERR, /* 0x48 */
+	DMA_TX_RAM_ECC_ERR, /* 0x49 */
+	DMA_TX_DIF_LEN_ALIGN_ERR, /* 0x4a */
+	DMA_TX_MAX_ERR_CODE,
 
 	/* sipc rx */
-	SIPC_RX_FIS_STATUS_ERR_BIT_VLD = SIPC_RX_ERR_BASE, /* 0x300 */
-	SIPC_RX_PIO_WRSETUP_STATUS_DRQ_ERR, /* 0x301 */
-	SIPC_RX_FIS_STATUS_BSY_BIT_ERR, /* 0x302 */
-	SIPC_RX_WRSETUP_LEN_ODD_ERR, /* 0x303 */
-	SIPC_RX_WRSETUP_LEN_ZERO_ERR, /* 0x304 */
-	SIPC_RX_WRDATA_LEN_NOT_MATCH_ERR, /* 0x305 */
-	SIPC_RX_NCQ_WRSETUP_OFFSET_ERR, /* 0x306 */
-	SIPC_RX_NCQ_WRSETUP_AUTO_ACTIVE_ERR, /* 0x307 */
-	SIPC_RX_SATA_UNEXP_FIS_ERR, /* 0x308 */
-	SIPC_RX_WRSETUP_ESTATUS_ERR, /* 0x309 */
-	SIPC_RX_DATA_UNDERFLOW_ERR, /* 0x30a */
+	SIPC_RX_FIS_STATUS_ERR_BIT_VLD = SIPC_RX_ERR_BASE, /* 0x50 */
+	SIPC_RX_PIO_WRSETUP_STATUS_DRQ_ERR, /* 0x51 */
+	SIPC_RX_FIS_STATUS_BSY_BIT_ERR, /* 0x52 */
+	SIPC_RX_WRSETUP_LEN_ODD_ERR, /* 0x53 */
+	SIPC_RX_WRSETUP_LEN_ZERO_ERR, /* 0x54 */
+	SIPC_RX_WRDATA_LEN_NOT_MATCH_ERR, /* 0x55 */
+	SIPC_RX_NCQ_WRSETUP_OFFSET_ERR, /* 0x56 */
+	SIPC_RX_NCQ_WRSETUP_AUTO_ACTIVE_ERR, /* 0x57 */
+	SIPC_RX_SATA_UNEXP_FIS_ERR, /* 0x58 */
+	SIPC_RX_WRSETUP_ESTATUS_ERR, /* 0x59 */
+	SIPC_RX_DATA_UNDERFLOW_ERR, /* 0x5a */
+	SIPC_RX_MAX_ERR_CODE,
 
 	/* dma rx */
-	DMA_RX_DIF_CRC_ERR = DMA_RX_ERR_BASE, /* 0x400 */
-	DMA_RX_DIF_APP_ERR, /* 0x401 */
-	DMA_RX_DIF_RPP_ERR, /* 0x402 */
-	DMA_RX_DATA_SGL_OVERFLOW, /* 0x403 */
-	DMA_RX_DIF_SGL_OVERFLOW, /* 0x404 */
-	DMA_RX_DATA_LEN_OVERFLOW, /* 0x405 */
-	DMA_RX_DATA_LEN_UNDERFLOW, /* 0x406 */
-	DMA_RX_DATA_OFFSET_ERR, /* 0x407 */
-	RESERVED10, /* 0x408 */
-	DMA_RX_SATA_FRAME_TYPE_ERR, /* 0x409 */
-	DMA_RX_RESP_BUF_OVERFLOW, /* 0x40a */
-	DMA_RX_UNEXP_RETRANS_RESP_ERR, /* 0x40b */
-	DMA_RX_UNEXP_NORM_RESP_ERR, /* 0x40c */
-	DMA_RX_UNEXP_RDFRAME_ERR, /* 0x40d */
-	DMA_RX_PIO_DATA_LEN_ERR, /* 0x40e */
-	DMA_RX_RDSETUP_STATUS_ERR, /* 0x40f */
-	DMA_RX_RDSETUP_STATUS_DRQ_ERR, /* 0x410 */
-	DMA_RX_RDSETUP_STATUS_BSY_ERR, /* 0x411 */
-	DMA_RX_RDSETUP_LEN_ODD_ERR, /* 0x412 */
-	DMA_RX_RDSETUP_LEN_ZERO_ERR, /* 0x413 */
-	DMA_RX_RDSETUP_LEN_OVER_ERR, /* 0x414 */
-	DMA_RX_RDSETUP_OFFSET_ERR, /* 0x415 */
-	DMA_RX_RDSETUP_ACTIVE_ERR, /* 0x416 */
-	DMA_RX_RDSETUP_ESTATUS_ERR, /* 0x417 */
-	DMA_RX_RAM_ECC_ERR, /* 0x418 */
-	DMA_RX_UNKNOWN_FRM_ERR, /* 0x419 */
+	DMA_RX_DIF_CRC_ERR = DMA_RX_ERR_BASE, /* 0x60 */
+	DMA_RX_DIF_APP_ERR, /* 0x61 */
+	DMA_RX_DIF_RPP_ERR, /* 0x62 */
+	DMA_RX_DATA_SGL_OVERFLOW, /* 0x63 */
+	DMA_RX_DIF_SGL_OVERFLOW, /* 0x64 */
+	DMA_RX_DATA_LEN_OVERFLOW, /* 0x65 */
+	DMA_RX_DATA_LEN_UNDERFLOW, /* 0x66 */
+	DMA_RX_DATA_OFFSET_ERR, /* 0x67 */
+	RESERVED10, /* 0x68 */
+	DMA_RX_SATA_FRAME_TYPE_ERR, /* 0x69 */
+	DMA_RX_RESP_BUF_OVERFLOW, /* 0x6a */
+	DMA_RX_UNEXP_RETRANS_RESP_ERR, /* 0x6b */
+	DMA_RX_UNEXP_NORM_RESP_ERR, /* 0x6c */
+	DMA_RX_UNEXP_RDFRAME_ERR, /* 0x6d */
+	DMA_RX_PIO_DATA_LEN_ERR, /* 0x6e */
+	DMA_RX_RDSETUP_STATUS_ERR, /* 0x6f */
+	DMA_RX_RDSETUP_STATUS_DRQ_ERR, /* 0x70 */
+	DMA_RX_RDSETUP_STATUS_BSY_ERR, /* 0x71 */
+	DMA_RX_RDSETUP_LEN_ODD_ERR, /* 0x72 */
+	DMA_RX_RDSETUP_LEN_ZERO_ERR, /* 0x73 */
+	DMA_RX_RDSETUP_LEN_OVER_ERR, /* 0x74 */
+	DMA_RX_RDSETUP_OFFSET_ERR, /* 0x75 */
+	DMA_RX_RDSETUP_ACTIVE_ERR, /* 0x76 */
+	DMA_RX_RDSETUP_ESTATUS_ERR, /* 0x77 */
+	DMA_RX_RAM_ECC_ERR, /* 0x78 */
+	DMA_RX_UNKNOWN_FRM_ERR, /* 0x79 */
+	DMA_RX_MAX_ERR_CODE,
 };
 
 #define HISI_SAS_COMMAND_ENTRIES_V2_HW 4096
@@ -538,6 +543,12 @@ enum {
 #define SATA_PROTOCOL_FPDMA		0x8
 #define SATA_PROTOCOL_ATAPI		0x10
 
+#define ERR_ON_TX_PHASE(err_phase) (err_phase == 0x2 || \
+		err_phase == 0x4 || err_phase == 0x8 ||\
+		err_phase == 0x6 || err_phase == 0xa)
+#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 u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off)
@@ -1451,10 +1462,205 @@ static void sata_done_v2_hw(struct hisi_hba *hisi_hba, struct sas_task *task,
 	ts->buf_valid_size = sizeof(*resp);
 }
 
+#define TRANS_TX_ERR	0
+#define TRANS_RX_ERR	1
+#define DMA_TX_ERR		2
+#define SIPC_RX_ERR		3
+#define DMA_RX_ERR		4
+
+#define DMA_TX_ERR_OFF	0
+#define DMA_TX_ERR_MSK	(0xffff << DMA_TX_ERR_OFF)
+#define SIPC_RX_ERR_OFF	16
+#define SIPC_RX_ERR_MSK (0xffff << SIPC_RX_ERR_OFF)
+
+static int parse_trans_tx_err_code_v2_hw(u32 err_msk)
+{
+	const u8 trans_tx_err_code_prio[] = {
+		TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS,
+		TRANS_TX_ERR_PHY_NOT_ENABLE,
+		TRANS_TX_OPEN_CNX_ERR_WRONG_DESTINATION,
+		TRANS_TX_OPEN_CNX_ERR_ZONE_VIOLATION,
+		TRANS_TX_OPEN_CNX_ERR_BY_OTHER,
+		RESERVED0,
+		TRANS_TX_OPEN_CNX_ERR_AIP_TIMEOUT,
+		TRANS_TX_OPEN_CNX_ERR_STP_RESOURCES_BUSY,
+		TRANS_TX_OPEN_CNX_ERR_PROTOCOL_NOT_SUPPORTED,
+		TRANS_TX_OPEN_CNX_ERR_CONNECTION_RATE_NOT_SUPPORTED,
+		TRANS_TX_OPEN_CNX_ERR_BAD_DESTINATION,
+		TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD,
+		TRANS_TX_OPEN_CNX_ERR_LOW_PHY_POWER,
+		TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED,
+		TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT,
+		TRANS_TX_OPEN_CNX_ERR_NO_DESTINATION,
+		TRANS_TX_OPEN_RETRY_ERR_THRESHOLD_REACHED,
+		TRANS_TX_ERR_WITH_CLOSE_PHYDISALE,
+		TRANS_TX_ERR_WITH_CLOSE_DWS_TIMEOUT,
+		TRANS_TX_ERR_WITH_CLOSE_COMINIT,
+		TRANS_TX_ERR_WITH_BREAK_TIMEOUT,
+		TRANS_TX_ERR_WITH_BREAK_REQUEST,
+		TRANS_TX_ERR_WITH_BREAK_RECEVIED,
+		TRANS_TX_ERR_WITH_CLOSE_TIMEOUT,
+		TRANS_TX_ERR_WITH_CLOSE_NORMAL,
+		TRANS_TX_ERR_WITH_NAK_RECEVIED,
+		TRANS_TX_ERR_WITH_ACK_NAK_TIMEOUT,
+		TRANS_TX_ERR_WITH_CREDIT_TIMEOUT,
+		TRANS_TX_ERR_WITH_IPTT_CONFLICT,
+		TRANS_TX_ERR_WITH_OPEN_BY_DES_OR_OTHERS,
+		TRANS_TX_ERR_WITH_WAIT_RECV_TIMEOUT,
+	};
+	int index, i;
+
+	for (i = 0; i < ARRAY_SIZE(trans_tx_err_code_prio); i++) {
+		index = trans_tx_err_code_prio[i] - TRANS_TX_FAIL_BASE;
+		if (err_msk & (1 << index))
+			return trans_tx_err_code_prio[i];
+	}
+	return -1;
+}
+
+static int parse_trans_rx_err_code_v2_hw(u32 err_msk)
+{
+	const u8 trans_rx_err_code_prio[] = {
+		TRANS_RX_ERR_WITH_RXFRAME_CRC_ERR,
+		TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR,
+		TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM,
+		TRANS_RX_ERR_WITH_RXFIS_DECODE_ERROR,
+		TRANS_RX_ERR_WITH_RXFIS_CRC_ERR,
+		TRANS_RX_ERR_WITH_RXFRAME_LENGTH_OVERRUN,
+		TRANS_RX_ERR_WITH_RXFIS_RX_SYNCP,
+		TRANS_RX_ERR_WITH_LINK_BUF_OVERRUN,
+		TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE,
+		TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT,
+		TRANS_RX_ERR_WITH_CLOSE_COMINIT,
+		TRANS_RX_ERR_WITH_BREAK_TIMEOUT,
+		TRANS_RX_ERR_WITH_BREAK_REQUEST,
+		TRANS_RX_ERR_WITH_BREAK_RECEVIED,
+		RESERVED1,
+		TRANS_RX_ERR_WITH_CLOSE_NORMAL,
+		TRANS_RX_ERR_WITH_DATA_LEN0,
+		TRANS_RX_ERR_WITH_BAD_HASH,
+		TRANS_RX_XRDY_WLEN_ZERO_ERR,
+		TRANS_RX_SSP_FRM_LEN_ERR,
+		RESERVED2,
+		RESERVED3,
+		RESERVED4,
+		RESERVED5,
+		TRANS_RX_ERR_WITH_BAD_FRM_TYPE,
+		TRANS_RX_SMP_FRM_LEN_ERR,
+		TRANS_RX_SMP_RESP_TIMEOUT_ERR,
+		RESERVED6,
+		RESERVED7,
+		RESERVED8,
+		RESERVED9,
+		TRANS_RX_R_ERR,
+	};
+	int index, i;
+
+	for (i = 0; i < ARRAY_SIZE(trans_rx_err_code_prio); i++) {
+		index = trans_rx_err_code_prio[i] - TRANS_RX_FAIL_BASE;
+		if (err_msk & (1 << index))
+			return trans_rx_err_code_prio[i];
+	}
+	return -1;
+}
+
+static int parse_dma_tx_err_code_v2_hw(u32 err_msk)
+{
+	const u8 dma_tx_err_code_prio[] = {
+		DMA_TX_UNEXP_XFER_ERR,
+		DMA_TX_UNEXP_RETRANS_ERR,
+		DMA_TX_XFER_LEN_OVERFLOW,
+		DMA_TX_XFER_OFFSET_ERR,
+		DMA_TX_RAM_ECC_ERR,
+		DMA_TX_DIF_LEN_ALIGN_ERR,
+		DMA_TX_DIF_CRC_ERR,
+		DMA_TX_DIF_APP_ERR,
+		DMA_TX_DIF_RPP_ERR,
+		DMA_TX_DATA_SGL_OVERFLOW,
+		DMA_TX_DIF_SGL_OVERFLOW,
+	};
+	int index, i;
+
+	for (i = 0; i < ARRAY_SIZE(dma_tx_err_code_prio); i++) {
+		index = dma_tx_err_code_prio[i] - DMA_TX_ERR_BASE;
+		err_msk = err_msk & DMA_TX_ERR_MSK;
+		if (err_msk & (1 << index))
+			return dma_tx_err_code_prio[i];
+	}
+	return -1;
+}
+
+static int parse_sipc_rx_err_code_v2_hw(u32 err_msk)
+{
+	const u8 sipc_rx_err_code_prio[] = {
+		SIPC_RX_FIS_STATUS_ERR_BIT_VLD,
+		SIPC_RX_PIO_WRSETUP_STATUS_DRQ_ERR,
+		SIPC_RX_FIS_STATUS_BSY_BIT_ERR,
+		SIPC_RX_WRSETUP_LEN_ODD_ERR,
+		SIPC_RX_WRSETUP_LEN_ZERO_ERR,
+		SIPC_RX_WRDATA_LEN_NOT_MATCH_ERR,
+		SIPC_RX_NCQ_WRSETUP_OFFSET_ERR,
+		SIPC_RX_NCQ_WRSETUP_AUTO_ACTIVE_ERR,
+		SIPC_RX_SATA_UNEXP_FIS_ERR,
+		SIPC_RX_WRSETUP_ESTATUS_ERR,
+		SIPC_RX_DATA_UNDERFLOW_ERR,
+	};
+	int index, i;
+
+	for (i = 0; i < ARRAY_SIZE(sipc_rx_err_code_prio); i++) {
+		index = sipc_rx_err_code_prio[i] - SIPC_RX_ERR_BASE;
+		err_msk = err_msk & SIPC_RX_ERR_MSK;
+		if (err_msk & (1 << (index + 0x10)))
+			return sipc_rx_err_code_prio[i];
+	}
+	return -1;
+}
+
+static int parse_dma_rx_err_code_v2_hw(u32 err_msk)
+{
+	const u8 dma_rx_err_code_prio[] = {
+		DMA_RX_UNKNOWN_FRM_ERR,
+		DMA_RX_DATA_LEN_OVERFLOW,
+		DMA_RX_DATA_LEN_UNDERFLOW,
+		DMA_RX_DATA_OFFSET_ERR,
+		RESERVED10,
+		DMA_RX_SATA_FRAME_TYPE_ERR,
+		DMA_RX_RESP_BUF_OVERFLOW,
+		DMA_RX_UNEXP_RETRANS_RESP_ERR,
+		DMA_RX_UNEXP_NORM_RESP_ERR,
+		DMA_RX_UNEXP_RDFRAME_ERR,
+		DMA_RX_PIO_DATA_LEN_ERR,
+		DMA_RX_RDSETUP_STATUS_ERR,
+		DMA_RX_RDSETUP_STATUS_DRQ_ERR,
+		DMA_RX_RDSETUP_STATUS_BSY_ERR,
+		DMA_RX_RDSETUP_LEN_ODD_ERR,
+		DMA_RX_RDSETUP_LEN_ZERO_ERR,
+		DMA_RX_RDSETUP_LEN_OVER_ERR,
+		DMA_RX_RDSETUP_OFFSET_ERR,
+		DMA_RX_RDSETUP_ACTIVE_ERR,
+		DMA_RX_RDSETUP_ESTATUS_ERR,
+		DMA_RX_RAM_ECC_ERR,
+		DMA_RX_DIF_CRC_ERR,
+		DMA_RX_DIF_APP_ERR,
+		DMA_RX_DIF_RPP_ERR,
+		DMA_RX_DATA_SGL_OVERFLOW,
+		DMA_RX_DIF_SGL_OVERFLOW,
+	};
+	int index, i;
+
+	for (i = 0; i < ARRAY_SIZE(dma_rx_err_code_prio); i++) {
+		index = dma_rx_err_code_prio[i] - DMA_RX_ERR_BASE;
+		if (err_msk & (1 << index))
+			return dma_rx_err_code_prio[i];
+	}
+	return -1;
+}
+
 /* by default, task resp is complete */
 static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 			   struct sas_task *task,
-			   struct hisi_sas_slot *slot)
+			   struct hisi_sas_slot *slot,
+			   int err_phase)
 {
 	struct task_status_struct *ts = &task->task_status;
 	struct hisi_sas_err_record_v2 *err_record = slot->status_buffer;
@@ -1465,21 +1671,23 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 	u32 dma_rx_err_type = cpu_to_le32(err_record->dma_rx_err_type);
 	int error = -1;
 
-	if (dma_rx_err_type) {
-		error = ffs(dma_rx_err_type)
-			- 1 + DMA_RX_ERR_BASE;
-	} else if (sipc_rx_err_type) {
-		error = ffs(sipc_rx_err_type)
-			- 1 + SIPC_RX_ERR_BASE;
-	}  else if (dma_tx_err_type) {
-		error = ffs(dma_tx_err_type)
-			- 1 + DMA_TX_ERR_BASE;
-	} else if (trans_rx_fail_type) {
-		error = ffs(trans_rx_fail_type)
-			- 1 + TRANS_RX_FAIL_BASE;
-	} else if (trans_tx_fail_type) {
-		error = ffs(trans_tx_fail_type)
-			- 1 + TRANS_TX_FAIL_BASE;
+	if (err_phase == 1) {
+		/* error in TX phase, the priority of error is: DW2 > DW0 */
+		error = parse_dma_tx_err_code_v2_hw(dma_tx_err_type);
+		if (error == -1)
+			error = parse_trans_tx_err_code_v2_hw(
+					trans_tx_fail_type);
+	} else if (err_phase == 2) {
+		/* error in RX phase, the priority is: DW1 > DW3 > DW2 */
+		error = parse_trans_rx_err_code_v2_hw(
+					trans_rx_fail_type);
+		if (error == -1) {
+			error = parse_dma_rx_err_code_v2_hw(
+					dma_rx_err_type);
+			if (error == -1)
+				error = parse_sipc_rx_err_code_v2_hw(
+						sipc_rx_err_type);
+		}
 	}
 
 	switch (task->task_proto) {
@@ -1490,13 +1698,6 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 		{
 			ts->stat = SAS_OPEN_REJECT;
 			ts->open_rej_reason = SAS_OREJ_NO_DEST;
-			break;
-		}
-		case TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED:
-		{
-			ts->stat = SAS_OPEN_REJECT;
-			ts->open_rej_reason = SAS_OREJ_PATH_BLOCKED;
-			break;
 		}
 		case TRANS_TX_OPEN_CNX_ERR_PROTOCOL_NOT_SUPPORTED:
 		{
@@ -1516,19 +1717,15 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 			ts->open_rej_reason = SAS_OREJ_BAD_DEST;
 			break;
 		}
-		case TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD:
-		{
-			ts->stat = SAS_OPEN_REJECT;
-			ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
-			break;
-		}
 		case TRANS_TX_OPEN_CNX_ERR_WRONG_DESTINATION:
 		{
 			ts->stat = SAS_OPEN_REJECT;
 			ts->open_rej_reason = SAS_OREJ_WRONG_DEST;
 			break;
 		}
+		case DMA_RX_UNEXP_NORM_RESP_ERR:
 		case TRANS_TX_OPEN_CNX_ERR_ZONE_VIOLATION:
+		case DMA_RX_RESP_BUF_OVERFLOW:
 		{
 			ts->stat = SAS_OPEN_REJECT;
 			ts->open_rej_reason = SAS_OREJ_UNKNOWN;
@@ -1540,16 +1737,6 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 			ts->stat = SAS_DEV_NO_RESPONSE;
 			break;
 		}
-		case TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE:
-		{
-			ts->stat = SAS_PHY_DOWN;
-			break;
-		}
-		case TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT:
-		{
-			ts->stat = SAS_OPEN_TO;
-			break;
-		}
 		case DMA_RX_DATA_LEN_OVERFLOW:
 		{
 			ts->stat = SAS_DATA_OVERRUN;
@@ -1557,60 +1744,65 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 			break;
 		}
 		case DMA_RX_DATA_LEN_UNDERFLOW:
-		case SIPC_RX_DATA_UNDERFLOW_ERR:
 		{
-			ts->residual = trans_tx_fail_type;
+			ts->residual = dma_rx_err_type;
 			ts->stat = SAS_DATA_UNDERRUN;
 			break;
 		}
-		case TRANS_TX_ERR_FRAME_TXED:
-		{
-			/* This will request a retry */
-			ts->stat = SAS_QUEUE_FULL;
-			slot->abort = 1;
-			break;
-		}
 		case TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS:
 		case TRANS_TX_ERR_PHY_NOT_ENABLE:
 		case TRANS_TX_OPEN_CNX_ERR_BY_OTHER:
 		case TRANS_TX_OPEN_CNX_ERR_AIP_TIMEOUT:
+		case TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD:
+		case TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED:
+		case TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT:
 		case TRANS_TX_OPEN_RETRY_ERR_THRESHOLD_REACHED:
 		case TRANS_TX_ERR_WITH_BREAK_TIMEOUT:
 		case TRANS_TX_ERR_WITH_BREAK_REQUEST:
 		case TRANS_TX_ERR_WITH_BREAK_RECEVIED:
 		case TRANS_TX_ERR_WITH_CLOSE_TIMEOUT:
 		case TRANS_TX_ERR_WITH_CLOSE_NORMAL:
+		case TRANS_TX_ERR_WITH_CLOSE_PHYDISALE:
 		case TRANS_TX_ERR_WITH_CLOSE_DWS_TIMEOUT:
 		case TRANS_TX_ERR_WITH_CLOSE_COMINIT:
 		case TRANS_TX_ERR_WITH_NAK_RECEVIED:
 		case TRANS_TX_ERR_WITH_ACK_NAK_TIMEOUT:
-		case TRANS_TX_ERR_WITH_IPTT_CONFLICT:
 		case TRANS_TX_ERR_WITH_CREDIT_TIMEOUT:
+		case TRANS_TX_ERR_WITH_IPTT_CONFLICT:
 		case TRANS_RX_ERR_WITH_RXFRAME_CRC_ERR:
 		case TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR:
 		case TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM:
+		case TRANS_RX_ERR_WITH_LINK_BUF_OVERRUN:
 		case TRANS_RX_ERR_WITH_BREAK_TIMEOUT:
 		case TRANS_RX_ERR_WITH_BREAK_REQUEST:
 		case TRANS_RX_ERR_WITH_BREAK_RECEVIED:
 		case TRANS_RX_ERR_WITH_CLOSE_NORMAL:
 		case TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT:
 		case TRANS_RX_ERR_WITH_CLOSE_COMINIT:
+		case TRANS_TX_ERR_FRAME_TXED:
+		case TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE:
 		case TRANS_RX_ERR_WITH_DATA_LEN0:
 		case TRANS_RX_ERR_WITH_BAD_HASH:
 		case TRANS_RX_XRDY_WLEN_ZERO_ERR:
 		case TRANS_RX_SSP_FRM_LEN_ERR:
 		case TRANS_RX_ERR_WITH_BAD_FRM_TYPE:
+		case DMA_TX_DATA_SGL_OVERFLOW:
 		case DMA_TX_UNEXP_XFER_ERR:
 		case DMA_TX_UNEXP_RETRANS_ERR:
 		case DMA_TX_XFER_LEN_OVERFLOW:
 		case DMA_TX_XFER_OFFSET_ERR:
+		case SIPC_RX_DATA_UNDERFLOW_ERR:
+		case DMA_RX_DATA_SGL_OVERFLOW:
 		case DMA_RX_DATA_OFFSET_ERR:
-		case DMA_RX_UNEXP_NORM_RESP_ERR:
-		case DMA_RX_UNEXP_RDFRAME_ERR:
+		case DMA_RX_RDSETUP_LEN_ODD_ERR:
+		case DMA_RX_RDSETUP_LEN_ZERO_ERR:
+		case DMA_RX_RDSETUP_LEN_OVER_ERR:
+		case DMA_RX_SATA_FRAME_TYPE_ERR:
 		case DMA_RX_UNKNOWN_FRM_ERR:
 		{
-			ts->stat = SAS_OPEN_REJECT;
-			ts->open_rej_reason = SAS_OREJ_UNKNOWN;
+			/* This will request a retry */
+			ts->stat = SAS_QUEUE_FULL;
+			slot->abort = 1;
 			break;
 		}
 		default:
@@ -1627,57 +1819,92 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 	case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
 	{
 		switch (error) {
-		case TRANS_TX_OPEN_CNX_ERR_LOW_PHY_POWER:
-		case TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED:
 		case TRANS_TX_OPEN_CNX_ERR_NO_DESTINATION:
 		{
+			ts->stat = SAS_OPEN_REJECT;
+			ts->open_rej_reason = SAS_OREJ_NO_DEST;
+			break;
+		}
+		case TRANS_TX_OPEN_CNX_ERR_LOW_PHY_POWER:
+		{
 			ts->resp = SAS_TASK_UNDELIVERED;
 			ts->stat = SAS_DEV_NO_RESPONSE;
 			break;
 		}
 		case TRANS_TX_OPEN_CNX_ERR_PROTOCOL_NOT_SUPPORTED:
+		{
+			ts->stat = SAS_OPEN_REJECT;
+			ts->open_rej_reason = SAS_OREJ_EPROTO;
+			break;
+		}
 		case TRANS_TX_OPEN_CNX_ERR_CONNECTION_RATE_NOT_SUPPORTED:
+		{
+			ts->stat = SAS_OPEN_REJECT;
+			ts->open_rej_reason = SAS_OREJ_CONN_RATE;
+			break;
+		}
 		case TRANS_TX_OPEN_CNX_ERR_BAD_DESTINATION:
-		case TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD:
+		{
+			ts->stat = SAS_OPEN_REJECT;
+			ts->open_rej_reason = SAS_OREJ_CONN_RATE;
+			break;
+		}
 		case TRANS_TX_OPEN_CNX_ERR_WRONG_DESTINATION:
-		case TRANS_TX_OPEN_CNX_ERR_ZONE_VIOLATION:
-		case TRANS_TX_OPEN_CNX_ERR_STP_RESOURCES_BUSY:
 		{
 			ts->stat = SAS_OPEN_REJECT;
+			ts->open_rej_reason = SAS_OREJ_WRONG_DEST;
 			break;
 		}
-		case TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT:
+		case DMA_RX_RESP_BUF_OVERFLOW:
+		case DMA_RX_UNEXP_NORM_RESP_ERR:
+		case TRANS_TX_OPEN_CNX_ERR_ZONE_VIOLATION:
 		{
-			ts->stat = SAS_OPEN_TO;
+			ts->stat = SAS_OPEN_REJECT;
+			ts->open_rej_reason = SAS_OREJ_UNKNOWN;
 			break;
 		}
 		case DMA_RX_DATA_LEN_OVERFLOW:
 		{
 			ts->stat = SAS_DATA_OVERRUN;
+			ts->residual = 0;
+			break;
+		}
+		case DMA_RX_DATA_LEN_UNDERFLOW:
+		{
+			ts->residual = dma_rx_err_type;
+			ts->stat = SAS_DATA_UNDERRUN;
 			break;
 		}
 		case TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS:
 		case TRANS_TX_ERR_PHY_NOT_ENABLE:
 		case TRANS_TX_OPEN_CNX_ERR_BY_OTHER:
 		case TRANS_TX_OPEN_CNX_ERR_AIP_TIMEOUT:
+		case TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD:
+		case TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED:
+		case TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT:
 		case TRANS_TX_OPEN_RETRY_ERR_THRESHOLD_REACHED:
 		case TRANS_TX_ERR_WITH_BREAK_TIMEOUT:
 		case TRANS_TX_ERR_WITH_BREAK_REQUEST:
 		case TRANS_TX_ERR_WITH_BREAK_RECEVIED:
 		case TRANS_TX_ERR_WITH_CLOSE_TIMEOUT:
 		case TRANS_TX_ERR_WITH_CLOSE_NORMAL:
+		case TRANS_TX_ERR_WITH_CLOSE_PHYDISALE:
 		case TRANS_TX_ERR_WITH_CLOSE_DWS_TIMEOUT:
 		case TRANS_TX_ERR_WITH_CLOSE_COMINIT:
-		case TRANS_TX_ERR_WITH_NAK_RECEVIED:
 		case TRANS_TX_ERR_WITH_ACK_NAK_TIMEOUT:
 		case TRANS_TX_ERR_WITH_CREDIT_TIMEOUT:
+		case TRANS_TX_ERR_WITH_OPEN_BY_DES_OR_OTHERS:
 		case TRANS_TX_ERR_WITH_WAIT_RECV_TIMEOUT:
-		case TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR:
 		case TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM:
+		case TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR:
 		case TRANS_RX_ERR_WITH_RXFIS_DECODE_ERROR:
 		case TRANS_RX_ERR_WITH_RXFIS_CRC_ERR:
 		case TRANS_RX_ERR_WITH_RXFRAME_LENGTH_OVERRUN:
 		case TRANS_RX_ERR_WITH_RXFIS_RX_SYNCP:
+		case TRANS_RX_ERR_WITH_LINK_BUF_OVERRUN:
+		case TRANS_RX_ERR_WITH_BREAK_TIMEOUT:
+		case TRANS_RX_ERR_WITH_BREAK_REQUEST:
+		case TRANS_RX_ERR_WITH_BREAK_RECEVIED:
 		case TRANS_RX_ERR_WITH_CLOSE_NORMAL:
 		case TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE:
 		case TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT:
@@ -1685,7 +1912,12 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 		case TRANS_RX_ERR_WITH_DATA_LEN0:
 		case TRANS_RX_ERR_WITH_BAD_HASH:
 		case TRANS_RX_XRDY_WLEN_ZERO_ERR:
-		case TRANS_RX_SSP_FRM_LEN_ERR:
+		case TRANS_RX_ERR_WITH_BAD_FRM_TYPE:
+		case DMA_TX_DATA_SGL_OVERFLOW:
+		case DMA_TX_UNEXP_XFER_ERR:
+		case DMA_TX_UNEXP_RETRANS_ERR:
+		case DMA_TX_XFER_LEN_OVERFLOW:
+		case DMA_TX_XFER_OFFSET_ERR:
 		case SIPC_RX_FIS_STATUS_ERR_BIT_VLD:
 		case SIPC_RX_PIO_WRSETUP_STATUS_DRQ_ERR:
 		case SIPC_RX_FIS_STATUS_BSY_BIT_ERR:
@@ -1693,6 +1925,8 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 		case SIPC_RX_WRSETUP_LEN_ZERO_ERR:
 		case SIPC_RX_WRDATA_LEN_NOT_MATCH_ERR:
 		case SIPC_RX_SATA_UNEXP_FIS_ERR:
+		case DMA_RX_DATA_SGL_OVERFLOW:
+		case DMA_RX_DATA_OFFSET_ERR:
 		case DMA_RX_SATA_FRAME_TYPE_ERR:
 		case DMA_RX_UNEXP_RDFRAME_ERR:
 		case DMA_RX_PIO_DATA_LEN_ERR:
@@ -1706,8 +1940,11 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 		case DMA_RX_RDSETUP_ACTIVE_ERR:
 		case DMA_RX_RDSETUP_ESTATUS_ERR:
 		case DMA_RX_UNKNOWN_FRM_ERR:
+		case TRANS_RX_SSP_FRM_LEN_ERR:
+		case TRANS_TX_OPEN_CNX_ERR_STP_RESOURCES_BUSY:
 		{
-			ts->stat = SAS_OPEN_REJECT;
+			slot->abort = 1;
+			ts->stat = SAS_PHY_DOWN;
 			break;
 		}
 		default:
@@ -1794,8 +2031,14 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 
 	if ((complete_hdr->dw0 & CMPLT_HDR_ERX_MSK) &&
 		(!(complete_hdr->dw0 & CMPLT_HDR_RSPNS_XFRD_MSK))) {
-
-		slot_err_v2_hw(hisi_hba, task, slot);
+		u32 err_phase = (complete_hdr->dw0 & CMPLT_HDR_ERR_PHASE_MSK)
+				>> CMPLT_HDR_ERR_PHASE_OFF;
+
+		/* Analyse error happens on which phase TX or RX */
+		if (ERR_ON_TX_PHASE(err_phase))
+			slot_err_v2_hw(hisi_hba, task, slot, 1);
+		else if (ERR_ON_RX_PHASE(err_phase))
+			slot_err_v2_hw(hisi_hba, task, slot, 2);
 
 		if (unlikely(slot->abort))
 			return ts->stat;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 16/23] scsi: hisi_sas: some modifications to v2 hw reg init values
  2017-03-22 17:25 [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements John Garry
                   ` (14 preceding siblings ...)
  2017-03-22 17:25 ` [PATCH 15/23] scsi: hisi_sas: process error codes according to their priority John Garry
@ 2017-03-22 17:25 ` John Garry
  2017-03-22 17:25 ` [PATCH 17/23] scsi: hisi_sas: handle PHY UP+DOWN simultaneous irq John Garry
                   ` (7 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: John Garry @ 2017-03-22 17:25 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, john.garry2, linux-scsi, linux-kernel, zhangfei.gao,
	John Garry, Xiang Chen, Zhao Nenglong

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 <chenxiang66@hisilicon.com>
Signed-off-by: Zhao Nenglong <zhaonenglong@hisilicon.com>
Signed-off-by: John Garry <john.garry@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, 0xc0000000);
 	hisi_sas_write32(hisi_hba, AXI_USER2, 0x10000);
-	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, 0xffffffff);
 		hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, 0xffffffff);
 		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, 0xffffffff);
 		hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8ffffbff);
-		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

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 17/23] scsi: hisi_sas: handle PHY UP+DOWN simultaneous irq
  2017-03-22 17:25 [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements John Garry
                   ` (15 preceding siblings ...)
  2017-03-22 17:25 ` [PATCH 16/23] scsi: hisi_sas: some modifications to v2 hw reg init values John Garry
@ 2017-03-22 17:25 ` John Garry
  2017-03-22 17:25 ` [PATCH 18/23] scsi: hisi_sas: rename hisi_sas_link_timeout_{enable, disable}_link John Garry
                   ` (6 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: John Garry @ 2017-03-22 17:25 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, john.garry2, linux-scsi, linux-kernel, zhangfei.gao,
	Xiaofei Tan, John Garry

From: Xiaofei Tan <tanxiaofei@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 <tanxiaofei@huawei.com>
Signed-off-by: John Garry <john.garry@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 = &hisi_hba->phy[phy_no];
 	struct asd_sas_phy *sas_phy = &phy->sas_phy;
@@ -2373,7 +2373,6 @@ static bool check_any_wideports_v2_hw(struct hisi_hba *hisi_hba)
 
 static int phy_down_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
 {
-	int res = 0;
 	u32 phy_state, sl_ctrl, txid_auto;
 	struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
 	struct hisi_sas_port *port = phy->port;
@@ -2398,7 +2397,7 @@ static int phy_down_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
 	hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, CHL_INT0_NOT_RDY_MSK);
 	hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 0);
 
-	return res;
+	return IRQ_HANDLED;
 }
 
 static irqreturn_t int_phy_updown_v2_hw(int irq_no, void *p)
@@ -2406,35 +2405,58 @@ static irqreturn_t int_phy_updown_v2_hw(int irq_no, void *p)
 	struct hisi_hba *hisi_hba = p;
 	u32 irq_msk;
 	int phy_no = 0;
-	irqreturn_t res = IRQ_HANDLED;
 
 	irq_msk = (hisi_sas_read32(hisi_hba, HGC_INVLD_DQE_INFO)
 		   >> HGC_INVLD_DQE_INFO_FB_CH0_OFF) & 0x1ff;
 	while (irq_msk) {
 		if (irq_msk  & 1) {
-			u32 irq_value = hisi_sas_phy_read32(hisi_hba, phy_no,
-							    CHL_INT0);
+			u32 reg_value = hisi_sas_phy_read32(hisi_hba, phy_no,
+					    CHL_INT0);
+
+			switch (reg_value & (CHL_INT0_NOT_RDY_MSK |
+					CHL_INT0_SL_PHY_ENABLE_MSK)) {
 
-			if (irq_value & CHL_INT0_SL_PHY_ENABLE_MSK)
+			case CHL_INT0_SL_PHY_ENABLE_MSK:
 				/* phy up */
-				if (phy_up_v2_hw(phy_no, hisi_hba)) {
-					res = IRQ_NONE;
-					goto end;
-				}
+				if (phy_up_v2_hw(phy_no, hisi_hba) ==
+				    IRQ_NONE)
+					return IRQ_NONE;
+				break;
 
-			if (irq_value & CHL_INT0_NOT_RDY_MSK)
+			case CHL_INT0_NOT_RDY_MSK:
 				/* phy down */
-				if (phy_down_v2_hw(phy_no, hisi_hba)) {
-					res = IRQ_NONE;
-					goto end;
+				if (phy_down_v2_hw(phy_no, hisi_hba) ==
+				    IRQ_NONE)
+					return IRQ_NONE;
+				break;
+
+			case (CHL_INT0_NOT_RDY_MSK |
+					CHL_INT0_SL_PHY_ENABLE_MSK):
+				reg_value = hisi_sas_read32(hisi_hba,
+						PHY_STATE);
+				if (reg_value & BIT(phy_no)) {
+					/* phy up */
+					if (phy_up_v2_hw(phy_no, hisi_hba) ==
+					    IRQ_NONE)
+						return IRQ_NONE;
+				} else {
+					/* phy down */
+					if (phy_down_v2_hw(phy_no, hisi_hba) ==
+					    IRQ_NONE)
+						return IRQ_NONE;
 				}
+				break;
+
+			default:
+				break;
+			}
+
 		}
 		irq_msk >>= 1;
 		phy_no++;
 	}
 
-end:
-	return res;
+	return IRQ_HANDLED;
 }
 
 static void phy_bcast_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 18/23] scsi: hisi_sas: rename hisi_sas_link_timeout_{enable, disable}_link
  2017-03-22 17:25 [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements John Garry
                   ` (16 preceding siblings ...)
  2017-03-22 17:25 ` [PATCH 17/23] scsi: hisi_sas: handle PHY UP+DOWN simultaneous irq John Garry
@ 2017-03-22 17:25 ` John Garry
  2017-03-22 17:25 ` [PATCH 19/23] scsi: hisi_sas: add hisi_sas_clear_nexus_ha() John Garry
                   ` (5 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: John Garry @ 2017-03-22 17:25 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, john.garry2, linux-scsi, linux-kernel, zhangfei.gao,
	John Garry

For consistency, remove the "hisi_sas_" prefix.

Signed-off-by: John Garry <john.garry@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(&hisi_hba->timer, jiffies + msecs_to_jiffies(900));
 }
 
-static void hisi_sas_link_timeout_disable_link(unsigned long data)
+static void link_timeout_disable_link(unsigned long data)
 {
 	struct hisi_hba *hisi_hba = (struct hisi_hba *)data;
 	int i, reg_val;
@@ -1038,14 +1038,14 @@ static void hisi_sas_link_timeout_disable_link(unsigned long data)
 		}
 	}
 
-	hisi_hba->timer.function = hisi_sas_link_timeout_enable_link;
+	hisi_hba->timer.function = link_timeout_enable_link;
 	mod_timer(&hisi_hba->timer, jiffies + msecs_to_jiffies(100));
 }
 
 static void set_link_timer_quirk(struct hisi_hba *hisi_hba)
 {
 	hisi_hba->timer.data = (unsigned long)hisi_hba;
-	hisi_hba->timer.function = hisi_sas_link_timeout_disable_link;
+	hisi_hba->timer.function = link_timeout_disable_link;
 	hisi_hba->timer.expires = jiffies + msecs_to_jiffies(1000);
 	add_timer(&hisi_hba->timer);
 }
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 19/23] scsi: hisi_sas: add hisi_sas_clear_nexus_ha()
  2017-03-22 17:25 [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements John Garry
                   ` (17 preceding siblings ...)
  2017-03-22 17:25 ` [PATCH 18/23] scsi: hisi_sas: rename hisi_sas_link_timeout_{enable, disable}_link John Garry
@ 2017-03-22 17:25 ` John Garry
  2017-03-22 17:25 ` [PATCH 20/23] scsi: hisi_sas: release SMP slot in lldd_abort_task John Garry
                   ` (4 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: John Garry @ 2017-03-22 17:25 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, john.garry2, linux-scsi, linux-kernel, zhangfei.gao,
	John Garry, Xiang Chen

Add function for upper-layer to reset controller
when all else fails.

Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Xiang Chen <chenxiang66@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

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 20/23] scsi: hisi_sas: release SMP slot in lldd_abort_task
  2017-03-22 17:25 [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements John Garry
                   ` (18 preceding siblings ...)
  2017-03-22 17:25 ` [PATCH 19/23] scsi: hisi_sas: add hisi_sas_clear_nexus_ha() John Garry
@ 2017-03-22 17:25 ` John Garry
  2017-03-22 17:25 ` [PATCH 21/23] scsi: hisi_sas: check hisi_sas_lu_reset() error message John Garry
                   ` (3 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: John Garry @ 2017-03-22 17:25 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, john.garry2, linux-scsi, linux-kernel, zhangfei.gao,
	Xiang Chen, John Garry

From: Xiang Chen <chenxiang66@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 <chenxiang66@hisilicon.com>
Signed-off-by: John Garry <john.garry@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(&hisi_hba->lock, flags);
+			hisi_sas_do_release_task(hisi_hba, task, slot);
+			spin_unlock_irqrestore(&hisi_hba->lock, flags);
+		}
 	}
 
 out:
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 21/23] scsi: hisi_sas: check hisi_sas_lu_reset() error message
  2017-03-22 17:25 [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements John Garry
                   ` (19 preceding siblings ...)
  2017-03-22 17:25 ` [PATCH 20/23] scsi: hisi_sas: release SMP slot in lldd_abort_task John Garry
@ 2017-03-22 17:25 ` John Garry
  2017-03-22 17:25 ` [PATCH 22/23] scsi: hisi_sas: use dev_is_sata to identify SATA or SAS disk John Garry
                   ` (2 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: John Garry @ 2017-03-22 17:25 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, john.garry2, linux-scsi, linux-kernel, zhangfei.gao,
	John Garry, Xiang Chen

Unless we actually get some sort of failure in
hisi_sas_lu_reset(), don't print a message.

Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Xiang Chen <chenxiang66@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

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 22/23] scsi: hisi_sas: use dev_is_sata to identify SATA or SAS disk
  2017-03-22 17:25 [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements John Garry
                   ` (20 preceding siblings ...)
  2017-03-22 17:25 ` [PATCH 21/23] scsi: hisi_sas: check hisi_sas_lu_reset() error message John Garry
@ 2017-03-22 17:25 ` John Garry
  2017-03-22 17:25 ` [PATCH 23/23] scsi: hisi_sas: add is_sata_phy_v2_hw() John Garry
  2017-03-23 15:12 ` [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements Martin K. Petersen
  23 siblings, 0 replies; 25+ messages in thread
From: John Garry @ 2017-03-22 17:25 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, john.garry2, linux-scsi, linux-kernel, zhangfei.gao,
	Xiang Chen, John Garry

From: Xiang Chen <chenxiang66@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 <chenxiang66@hisilicon.com>
Signed-off-by: John Garry <john.garry@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

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 23/23] scsi: hisi_sas: add is_sata_phy_v2_hw()
  2017-03-22 17:25 [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements John Garry
                   ` (21 preceding siblings ...)
  2017-03-22 17:25 ` [PATCH 22/23] scsi: hisi_sas: use dev_is_sata to identify SATA or SAS disk John Garry
@ 2017-03-22 17:25 ` John Garry
  2017-03-23 15:12 ` [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements Martin K. Petersen
  23 siblings, 0 replies; 25+ messages in thread
From: John Garry @ 2017-03-22 17:25 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, john.garry2, linux-scsi, linux-kernel, zhangfei.gao,
	Xiaofei Tan, John Garry

From: Xiaofei Tan <tanxiaofei@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 <tanxiaofei@huawei.com>
Signed-off-by: John Garry <john.garry@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 = &hisi_hba->phy[phy_no];
 	struct asd_sas_phy *sas_phy = &phy->sas_phy;
 	struct device *dev = &hisi_hba->pdev->dev;
@@ -2295,9 +2306,7 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
 
 	hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 1);
 
-	/* Check for SATA dev */
-	context = hisi_sas_read32(hisi_hba, PHY_CONTEXT);
-	if (context & (1 << phy_no))
+	if (is_sata_phy_v2_hw(hisi_hba, phy_no))
 		goto end;
 
 	if (phy_no == 8) {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements
  2017-03-22 17:25 [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements John Garry
                   ` (22 preceding siblings ...)
  2017-03-22 17:25 ` [PATCH 23/23] scsi: hisi_sas: add is_sata_phy_v2_hw() John Garry
@ 2017-03-23 15:12 ` Martin K. Petersen
  23 siblings, 0 replies; 25+ messages in thread
From: Martin K. Petersen @ 2017-03-23 15:12 UTC (permalink / raw)
  To: John Garry
  Cc: jejb, martin.petersen, linuxarm, john.garry2, linux-scsi,
	linux-kernel, zhangfei.gao

John Garry <john.garry@huawei.com> writes:

John,

> 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

Applied to 4.12/scsi-queue. Thanks!

-- 
Martin K. Petersen	Oracle Linux Engineering

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2017-03-23 15:12 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-22 17:25 [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements John Garry
2017-03-22 17:25 ` [PATCH 01/23] scsi: hisi_sas: add to_hisi_sas_port() John Garry
2017-03-22 17:25 ` [PATCH 02/23] scsi: hisi_sas: add controller reset John Garry
2017-03-22 17:25 ` [PATCH 03/23] scsi: hisi_sas: move PHY init to hisi_sas_scan_start() John Garry
2017-03-22 17:25 ` [PATCH 04/23] scsi: hisi_sas: add softreset function for SATA disk John Garry
2017-03-22 17:25 ` [PATCH 05/23] scsi: hisi_sas: remove hisi_sas_port_deformed() John Garry
2017-03-22 17:25 ` [PATCH 06/23] scsi: hisi_sas: error hisi_sas_task_prep() when port down John Garry
2017-03-22 17:25 ` [PATCH 07/23] scsi: hisi_sas: only reset link for PHY_FUNC_LINK_RESET John Garry
2017-03-22 17:25 ` [PATCH 08/23] scsi: hisi_sas: modify error handling for v2 hw John Garry
2017-03-22 17:25 ` [PATCH 09/23] scsi: hisi_sas: modify hisi_sas_abort_task() for SSP John Garry
2017-03-22 17:25 ` [PATCH 10/23] scsi: hisi_sas: hardreset for SATA disk in LU reset John Garry
2017-03-22 17:25 ` [PATCH 11/23] scsi: hisi_sas: check for SAS_TASK_STATE_ABORTED in slot complete John Garry
2017-03-22 17:25 ` [PATCH 12/23] scsi: hisi_sas: free slots after hardreset John Garry
2017-03-22 17:25 ` [PATCH 13/23] scsi: hisi_sas: fix some sas_task.task_state_lock locking John Garry
2017-03-22 17:25 ` [PATCH 14/23] scsi: hisi_sas: remove task free'ing for timeouts John Garry
2017-03-22 17:25 ` [PATCH 15/23] scsi: hisi_sas: process error codes according to their priority John Garry
2017-03-22 17:25 ` [PATCH 16/23] scsi: hisi_sas: some modifications to v2 hw reg init values John Garry
2017-03-22 17:25 ` [PATCH 17/23] scsi: hisi_sas: handle PHY UP+DOWN simultaneous irq John Garry
2017-03-22 17:25 ` [PATCH 18/23] scsi: hisi_sas: rename hisi_sas_link_timeout_{enable, disable}_link John Garry
2017-03-22 17:25 ` [PATCH 19/23] scsi: hisi_sas: add hisi_sas_clear_nexus_ha() John Garry
2017-03-22 17:25 ` [PATCH 20/23] scsi: hisi_sas: release SMP slot in lldd_abort_task John Garry
2017-03-22 17:25 ` [PATCH 21/23] scsi: hisi_sas: check hisi_sas_lu_reset() error message John Garry
2017-03-22 17:25 ` [PATCH 22/23] scsi: hisi_sas: use dev_is_sata to identify SATA or SAS disk John Garry
2017-03-22 17:25 ` [PATCH 23/23] scsi: hisi_sas: add is_sata_phy_v2_hw() John Garry
2017-03-23 15:12 ` [PATCH 00/23] hisi_sas: error handling and other misc fixes and improvements Martin K. Petersen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).