All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/19] hisi_sas: PM, RAS, and other misc changes
@ 2017-12-08 17:16 ` John Garry
  0 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen; +Cc: linuxarm, linux-scsi, linux-kernel, John Garry

This patchset contains support for some new
features, and also some modifications and other
fixes.

Headline changes include:
- v3 hw Suspend and Resume support
- v3 hw RAS (PCI AER) support
- v2 hw HW port error handling support
- other misc fixes and tidy-up

Xiang Chen (8):
  scsi: hisi_sas: initialize dq spinlock before use
  scsi: hisi_sas: fix dma_unmap_sg() parameter
  scsi: hisi_sas: modify hisi_sas_dev_gone() for reset
  scsi: hisi_sas: change ncq process for v3 hw
  scsi: hisi_sas: add some print to enhance debugging
  scsi: hisi_sas: fix SAS_QUEUE_FULL problem while running IO
  scsi: hisi_sas: re-add the lldd_port_deformed()
  scsi: hisi_sas: add v3 hw suspend and resume

Xiaofei Tan (11):
  scsi: hisi_sas: relocate clearing ITCT and freeing device
  scsi: hisi_sas: optimise port id refresh function
  scsi: hisi_sas: some optimizations of host controller reset
  scsi: hisi_sas: add an mechanism to do reset work synchronously
  scsi: hisi_sas: add RAS feature for v3 hw
  scsi: hisi_sas: improve int_chnl_int_v2_hw() consistenty with v3 hw
  scsi: hisi_sas: add v2 hw port AXI error handling support
  scsi: hisi_sas: use an general way to delay PHY work
  scsi: hisi_sas: do link reset for some CHL_INT2 ints
  scsi: hisi_sas: judge result of internal abort
  scsi: hisi_sas: add internal abort dev in some places

 drivers/scsi/hisi_sas/hisi_sas.h       |  40 +++-
 drivers/scsi/hisi_sas/hisi_sas_main.c  | 222 +++++++++++++++++-----
 drivers/scsi/hisi_sas/hisi_sas_v1_hw.c |   6 +-
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 153 ++++++++++-----
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 330 ++++++++++++++++++++++++++++-----
 5 files changed, 610 insertions(+), 141 deletions(-)

-- 
1.9.1

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

* [PATCH 00/19] hisi_sas: PM, RAS, and other misc changes
@ 2017-12-08 17:16 ` John Garry
  0 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen; +Cc: linuxarm, linux-scsi, linux-kernel, John Garry

This patchset contains support for some new
features, and also some modifications and other
fixes.

Headline changes include:
- v3 hw Suspend and Resume support
- v3 hw RAS (PCI AER) support
- v2 hw HW port error handling support
- other misc fixes and tidy-up

Xiang Chen (8):
  scsi: hisi_sas: initialize dq spinlock before use
  scsi: hisi_sas: fix dma_unmap_sg() parameter
  scsi: hisi_sas: modify hisi_sas_dev_gone() for reset
  scsi: hisi_sas: change ncq process for v3 hw
  scsi: hisi_sas: add some print to enhance debugging
  scsi: hisi_sas: fix SAS_QUEUE_FULL problem while running IO
  scsi: hisi_sas: re-add the lldd_port_deformed()
  scsi: hisi_sas: add v3 hw suspend and resume

Xiaofei Tan (11):
  scsi: hisi_sas: relocate clearing ITCT and freeing device
  scsi: hisi_sas: optimise port id refresh function
  scsi: hisi_sas: some optimizations of host controller reset
  scsi: hisi_sas: add an mechanism to do reset work synchronously
  scsi: hisi_sas: add RAS feature for v3 hw
  scsi: hisi_sas: improve int_chnl_int_v2_hw() consistenty with v3 hw
  scsi: hisi_sas: add v2 hw port AXI error handling support
  scsi: hisi_sas: use an general way to delay PHY work
  scsi: hisi_sas: do link reset for some CHL_INT2 ints
  scsi: hisi_sas: judge result of internal abort
  scsi: hisi_sas: add internal abort dev in some places

 drivers/scsi/hisi_sas/hisi_sas.h       |  40 +++-
 drivers/scsi/hisi_sas/hisi_sas_main.c  | 222 +++++++++++++++++-----
 drivers/scsi/hisi_sas/hisi_sas_v1_hw.c |   6 +-
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 153 ++++++++++-----
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 330 ++++++++++++++++++++++++++++-----
 5 files changed, 610 insertions(+), 141 deletions(-)

-- 
1.9.1

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

* [PATCH 01/19] scsi: hisi_sas: initialize dq spinlock before use
  2017-12-08 17:16 ` John Garry
@ 2017-12-08 17:16   ` John Garry
  -1 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiang Chen, John Garry

From: Xiang Chen <chenxiang66@hisilicon.com>

It is required to initialize the dq spinlock before use, which
was not being done, so fix it. This issue can be detected when
CONFIG_DEBUG_SPINLOCK is enabled.

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 | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 5f503cb..359ec52 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -1657,6 +1657,7 @@ int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
 		cq->hisi_hba = hisi_hba;
 
 		/* Delivery queue structure */
+		spin_lock_init(&dq->lock);
 		dq->id = i;
 		dq->hisi_hba = hisi_hba;
 
-- 
1.9.1

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

* [PATCH 01/19] scsi: hisi_sas: initialize dq spinlock before use
@ 2017-12-08 17:16   ` John Garry
  0 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiang Chen, John Garry

From: Xiang Chen <chenxiang66@hisilicon.com>

It is required to initialize the dq spinlock before use, which
was not being done, so fix it. This issue can be detected when
CONFIG_DEBUG_SPINLOCK is enabled.

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 | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 5f503cb..359ec52 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -1657,6 +1657,7 @@ int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
 		cq->hisi_hba = hisi_hba;
 
 		/* Delivery queue structure */
+		spin_lock_init(&dq->lock);
 		dq->id = i;
 		dq->hisi_hba = hisi_hba;
 
-- 
1.9.1

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

* [PATCH 02/19] scsi: hisi_sas: fix dma_unmap_sg() parameter
  2017-12-08 17:16 ` John Garry
@ 2017-12-08 17:16   ` John Garry
  -1 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiang Chen, John Garry

From: Xiang Chen <chenxiang66@hisilicon.com>

For function dma_unmap_sg(), the <nents> parameter
should be number of elements in the scatterlist
prior to the mapping, not after the mapping.

Fix this usage.

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 | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 359ec52..d842530 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -192,7 +192,8 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task,
 
 		if (!sas_protocol_ata(task->task_proto))
 			if (slot->n_elem)
-				dma_unmap_sg(dev, task->scatter, slot->n_elem,
+				dma_unmap_sg(dev, task->scatter,
+					     task->num_scatter,
 					     task->data_dir);
 
 		if (sas_dev)
@@ -431,7 +432,8 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq
 	dev_err(dev, "task prep: failed[%d]!\n", rc);
 	if (!sas_protocol_ata(task->task_proto))
 		if (n_elem)
-			dma_unmap_sg(dev, task->scatter, n_elem,
+			dma_unmap_sg(dev, task->scatter,
+				     task->num_scatter,
 				     task->data_dir);
 prep_out:
 	return rc;
-- 
1.9.1

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

* [PATCH 02/19] scsi: hisi_sas: fix dma_unmap_sg() parameter
@ 2017-12-08 17:16   ` John Garry
  0 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiang Chen, John Garry

From: Xiang Chen <chenxiang66@hisilicon.com>

For function dma_unmap_sg(), the <nents> parameter
should be number of elements in the scatterlist
prior to the mapping, not after the mapping.

Fix this usage.

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 | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 359ec52..d842530 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -192,7 +192,8 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task,
 
 		if (!sas_protocol_ata(task->task_proto))
 			if (slot->n_elem)
-				dma_unmap_sg(dev, task->scatter, slot->n_elem,
+				dma_unmap_sg(dev, task->scatter,
+					     task->num_scatter,
 					     task->data_dir);
 
 		if (sas_dev)
@@ -431,7 +432,8 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq
 	dev_err(dev, "task prep: failed[%d]!\n", rc);
 	if (!sas_protocol_ata(task->task_proto))
 		if (n_elem)
-			dma_unmap_sg(dev, task->scatter, n_elem,
+			dma_unmap_sg(dev, task->scatter,
+				     task->num_scatter,
 				     task->data_dir);
 prep_out:
 	return rc;
-- 
1.9.1

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

* [PATCH 03/19] scsi: hisi_sas: relocate clearing ITCT and freeing device
  2017-12-08 17:16 ` John Garry
@ 2017-12-08 17:16   ` John Garry
  -1 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiaofei Tan, John Garry

From: Xiaofei Tan <tanxiaofei@huawei.com>

In certain scenarios we may just want to clear the ITCT for
a device, and not free other resources like the SATA bitmap
using in v2 hw.

To facilitate this, this patch relocates the code of clearing
ITCT from free_device() to an new hw interface clear_itct().
Then for some hw, we should not realise free_device() if there's
nothing left to do for it.

Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas.h       |  3 ++-
 drivers/scsi/hisi_sas/hisi_sas_main.c  |  7 +++++--
 drivers/scsi/hisi_sas/hisi_sas_v1_hw.c |  4 ++--
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 16 +++++++++++-----
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c |  4 ++--
 5 files changed, 22 insertions(+), 12 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index 83357b03..b2534ca 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -205,8 +205,9 @@ struct hisi_sas_hw {
 	void (*phy_set_linkrate)(struct hisi_hba *hisi_hba, int phy_no,
 			struct sas_phy_linkrates *linkrates);
 	enum sas_linkrate (*phy_get_max_linkrate)(void);
-	void (*free_device)(struct hisi_hba *hisi_hba,
+	void (*clear_itct)(struct hisi_hba *hisi_hba,
 			    struct hisi_sas_device *dev);
+	void (*free_device)(struct hisi_sas_device *sas_dev);
 	int (*get_wideport_bitmap)(struct hisi_hba *hisi_hba, int port_id);
 	void (*dereg_device)(struct hisi_hba *hisi_hba,
 				struct domain_device *device);
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index d842530..6446ce2 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -743,7 +743,10 @@ static void hisi_sas_dev_gone(struct domain_device *device)
 
 	hisi_sas_dereg_device(hisi_hba, device);
 
-	hisi_hba->hw->free_device(hisi_hba, sas_dev);
+	hisi_hba->hw->clear_itct(hisi_hba, sas_dev);
+	if (hisi_hba->hw->free_device)
+		hisi_hba->hw->free_device(sas_dev);
+
 	device->lldd_dev = NULL;
 	memset(sas_dev, 0, sizeof(*sas_dev));
 	sas_dev->dev_type = SAS_PHY_UNUSED;
@@ -1001,7 +1004,7 @@ static void hisi_sas_refresh_port_id(struct hisi_hba *hisi_hba,
 				|| !device || (device->port != sas_port))
 			continue;
 
-		hisi_hba->hw->free_device(hisi_hba, sas_dev);
+		hisi_hba->hw->clear_itct(hisi_hba, sas_dev);
 
 		/* Update linkrate of directly attached device. */
 		if (!device->parent)
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
index dc6eca8..8cb9061 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
@@ -544,7 +544,7 @@ static void setup_itct_v1_hw(struct hisi_hba *hisi_hba,
 				(0xff00ULL << ITCT_HDR_REJ_OPEN_TL_OFF));
 }
 
-static void free_device_v1_hw(struct hisi_hba *hisi_hba,
+static void clear_itct_v1_hw(struct hisi_hba *hisi_hba,
 			      struct hisi_sas_device *sas_dev)
 {
 	u64 dev_id = sas_dev->device_id;
@@ -1850,7 +1850,7 @@ static int hisi_sas_v1_init(struct hisi_hba *hisi_hba)
 	.hw_init = hisi_sas_v1_init,
 	.setup_itct = setup_itct_v1_hw,
 	.sl_notify = sl_notify_v1_hw,
-	.free_device = free_device_v1_hw,
+	.clear_itct = clear_itct_v1_hw,
 	.prep_smp = prep_smp_v1_hw,
 	.prep_ssp = prep_ssp_v1_hw,
 	.get_free_slot = get_free_slot_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 5d3467f..cd9cd84 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -952,7 +952,7 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba,
 					(0x1ULL << ITCT_HDR_RTOLT_OFF));
 }
 
-static void free_device_v2_hw(struct hisi_hba *hisi_hba,
+static void clear_itct_v2_hw(struct hisi_hba *hisi_hba,
 			      struct hisi_sas_device *sas_dev)
 {
 	DECLARE_COMPLETION_ONSTACK(completion);
@@ -963,10 +963,6 @@ static void free_device_v2_hw(struct hisi_hba *hisi_hba,
 
 	sas_dev->completion = &completion;
 
-	/* SoC bug workaround */
-	if (dev_is_sata(sas_dev->sas_device))
-		clear_bit(sas_dev->sata_idx, hisi_hba->sata_dev_bitmap);
-
 	/* clear the itct interrupt state */
 	if (ENT_INT_SRC3_ITC_INT_MSK & reg_val)
 		hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
@@ -981,6 +977,15 @@ static void free_device_v2_hw(struct hisi_hba *hisi_hba,
 	}
 }
 
+static void free_device_v2_hw(struct hisi_sas_device *sas_dev)
+{
+	struct hisi_hba *hisi_hba = sas_dev->hisi_hba;
+
+	/* SoC bug workaround */
+	if (dev_is_sata(sas_dev->sas_device))
+		clear_bit(sas_dev->sata_idx, hisi_hba->sata_dev_bitmap);
+}
+
 static int reset_hw_v2_hw(struct hisi_hba *hisi_hba)
 {
 	int i, reset_val;
@@ -3415,6 +3420,7 @@ static int soft_reset_v2_hw(struct hisi_hba *hisi_hba)
 	.alloc_dev = alloc_dev_quirk_v2_hw,
 	.sl_notify = sl_notify_v2_hw,
 	.get_wideport_bitmap = get_wideport_bitmap_v2_hw,
+	.clear_itct = clear_itct_v2_hw,
 	.free_device = free_device_v2_hw,
 	.prep_smp = prep_smp_v2_hw,
 	.prep_ssp = prep_ssp_v2_hw,
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 19b1f2f..44f07bc 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -588,7 +588,7 @@ static void setup_itct_v3_hw(struct hisi_hba *hisi_hba,
 					(0x1ULL << ITCT_HDR_RTOLT_OFF));
 }
 
-static void free_device_v3_hw(struct hisi_hba *hisi_hba,
+static void clear_itct_v3_hw(struct hisi_hba *hisi_hba,
 			      struct hisi_sas_device *sas_dev)
 {
 	DECLARE_COMPLETION_ONSTACK(completion);
@@ -1951,7 +1951,7 @@ static int soft_reset_v3_hw(struct hisi_hba *hisi_hba)
 	.max_command_entries = HISI_SAS_COMMAND_ENTRIES_V3_HW,
 	.get_wideport_bitmap = get_wideport_bitmap_v3_hw,
 	.complete_hdr_size = sizeof(struct hisi_sas_complete_v3_hdr),
-	.free_device = free_device_v3_hw,
+	.clear_itct = clear_itct_v3_hw,
 	.sl_notify = sl_notify_v3_hw,
 	.prep_ssp = prep_ssp_v3_hw,
 	.prep_smp = prep_smp_v3_hw,
-- 
1.9.1

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

* [PATCH 03/19] scsi: hisi_sas: relocate clearing ITCT and freeing device
@ 2017-12-08 17:16   ` John Garry
  0 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiaofei Tan, John Garry

From: Xiaofei Tan <tanxiaofei@huawei.com>

In certain scenarios we may just want to clear the ITCT for
a device, and not free other resources like the SATA bitmap
using in v2 hw.

To facilitate this, this patch relocates the code of clearing
ITCT from free_device() to an new hw interface clear_itct().
Then for some hw, we should not realise free_device() if there's
nothing left to do for it.

Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas.h       |  3 ++-
 drivers/scsi/hisi_sas/hisi_sas_main.c  |  7 +++++--
 drivers/scsi/hisi_sas/hisi_sas_v1_hw.c |  4 ++--
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 16 +++++++++++-----
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c |  4 ++--
 5 files changed, 22 insertions(+), 12 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index 83357b03..b2534ca 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -205,8 +205,9 @@ struct hisi_sas_hw {
 	void (*phy_set_linkrate)(struct hisi_hba *hisi_hba, int phy_no,
 			struct sas_phy_linkrates *linkrates);
 	enum sas_linkrate (*phy_get_max_linkrate)(void);
-	void (*free_device)(struct hisi_hba *hisi_hba,
+	void (*clear_itct)(struct hisi_hba *hisi_hba,
 			    struct hisi_sas_device *dev);
+	void (*free_device)(struct hisi_sas_device *sas_dev);
 	int (*get_wideport_bitmap)(struct hisi_hba *hisi_hba, int port_id);
 	void (*dereg_device)(struct hisi_hba *hisi_hba,
 				struct domain_device *device);
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index d842530..6446ce2 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -743,7 +743,10 @@ static void hisi_sas_dev_gone(struct domain_device *device)
 
 	hisi_sas_dereg_device(hisi_hba, device);
 
-	hisi_hba->hw->free_device(hisi_hba, sas_dev);
+	hisi_hba->hw->clear_itct(hisi_hba, sas_dev);
+	if (hisi_hba->hw->free_device)
+		hisi_hba->hw->free_device(sas_dev);
+
 	device->lldd_dev = NULL;
 	memset(sas_dev, 0, sizeof(*sas_dev));
 	sas_dev->dev_type = SAS_PHY_UNUSED;
@@ -1001,7 +1004,7 @@ static void hisi_sas_refresh_port_id(struct hisi_hba *hisi_hba,
 				|| !device || (device->port != sas_port))
 			continue;
 
-		hisi_hba->hw->free_device(hisi_hba, sas_dev);
+		hisi_hba->hw->clear_itct(hisi_hba, sas_dev);
 
 		/* Update linkrate of directly attached device. */
 		if (!device->parent)
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
index dc6eca8..8cb9061 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
@@ -544,7 +544,7 @@ static void setup_itct_v1_hw(struct hisi_hba *hisi_hba,
 				(0xff00ULL << ITCT_HDR_REJ_OPEN_TL_OFF));
 }
 
-static void free_device_v1_hw(struct hisi_hba *hisi_hba,
+static void clear_itct_v1_hw(struct hisi_hba *hisi_hba,
 			      struct hisi_sas_device *sas_dev)
 {
 	u64 dev_id = sas_dev->device_id;
@@ -1850,7 +1850,7 @@ static int hisi_sas_v1_init(struct hisi_hba *hisi_hba)
 	.hw_init = hisi_sas_v1_init,
 	.setup_itct = setup_itct_v1_hw,
 	.sl_notify = sl_notify_v1_hw,
-	.free_device = free_device_v1_hw,
+	.clear_itct = clear_itct_v1_hw,
 	.prep_smp = prep_smp_v1_hw,
 	.prep_ssp = prep_ssp_v1_hw,
 	.get_free_slot = get_free_slot_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 5d3467f..cd9cd84 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -952,7 +952,7 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba,
 					(0x1ULL << ITCT_HDR_RTOLT_OFF));
 }
 
-static void free_device_v2_hw(struct hisi_hba *hisi_hba,
+static void clear_itct_v2_hw(struct hisi_hba *hisi_hba,
 			      struct hisi_sas_device *sas_dev)
 {
 	DECLARE_COMPLETION_ONSTACK(completion);
@@ -963,10 +963,6 @@ static void free_device_v2_hw(struct hisi_hba *hisi_hba,
 
 	sas_dev->completion = &completion;
 
-	/* SoC bug workaround */
-	if (dev_is_sata(sas_dev->sas_device))
-		clear_bit(sas_dev->sata_idx, hisi_hba->sata_dev_bitmap);
-
 	/* clear the itct interrupt state */
 	if (ENT_INT_SRC3_ITC_INT_MSK & reg_val)
 		hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
@@ -981,6 +977,15 @@ static void free_device_v2_hw(struct hisi_hba *hisi_hba,
 	}
 }
 
+static void free_device_v2_hw(struct hisi_sas_device *sas_dev)
+{
+	struct hisi_hba *hisi_hba = sas_dev->hisi_hba;
+
+	/* SoC bug workaround */
+	if (dev_is_sata(sas_dev->sas_device))
+		clear_bit(sas_dev->sata_idx, hisi_hba->sata_dev_bitmap);
+}
+
 static int reset_hw_v2_hw(struct hisi_hba *hisi_hba)
 {
 	int i, reset_val;
@@ -3415,6 +3420,7 @@ static int soft_reset_v2_hw(struct hisi_hba *hisi_hba)
 	.alloc_dev = alloc_dev_quirk_v2_hw,
 	.sl_notify = sl_notify_v2_hw,
 	.get_wideport_bitmap = get_wideport_bitmap_v2_hw,
+	.clear_itct = clear_itct_v2_hw,
 	.free_device = free_device_v2_hw,
 	.prep_smp = prep_smp_v2_hw,
 	.prep_ssp = prep_ssp_v2_hw,
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 19b1f2f..44f07bc 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -588,7 +588,7 @@ static void setup_itct_v3_hw(struct hisi_hba *hisi_hba,
 					(0x1ULL << ITCT_HDR_RTOLT_OFF));
 }
 
-static void free_device_v3_hw(struct hisi_hba *hisi_hba,
+static void clear_itct_v3_hw(struct hisi_hba *hisi_hba,
 			      struct hisi_sas_device *sas_dev)
 {
 	DECLARE_COMPLETION_ONSTACK(completion);
@@ -1951,7 +1951,7 @@ static int soft_reset_v3_hw(struct hisi_hba *hisi_hba)
 	.max_command_entries = HISI_SAS_COMMAND_ENTRIES_V3_HW,
 	.get_wideport_bitmap = get_wideport_bitmap_v3_hw,
 	.complete_hdr_size = sizeof(struct hisi_sas_complete_v3_hdr),
-	.free_device = free_device_v3_hw,
+	.clear_itct = clear_itct_v3_hw,
 	.sl_notify = sl_notify_v3_hw,
 	.prep_ssp = prep_ssp_v3_hw,
 	.prep_smp = prep_smp_v3_hw,
-- 
1.9.1

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

* [PATCH 04/19] scsi: hisi_sas: optimise port id refresh function
  2017-12-08 17:16 ` John Garry
@ 2017-12-08 17:16   ` John Garry
  -1 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiaofei Tan, John Garry

From: Xiaofei Tan <tanxiaofei@huawei.com>

Currently refreshing the PHY port id after reset is
done in the rescan topology function, which is quite
late in the reset process. It could be moved earlier in
the process, as the port id can be refreshed once the
PHYs become ready.

In addition to this, we should set the hisi_sas_dev port
id to 0xff (invalid port id) if all PHYs of this port remain
down for the same device.

Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas_main.c | 48 ++++++++++++++++++++++-------------
 1 file changed, 30 insertions(+), 18 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 6446ce2..326ecb2 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -990,27 +990,42 @@ static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device,
 				sizeof(ssp_task), tmf);
 }
 
-static void hisi_sas_refresh_port_id(struct hisi_hba *hisi_hba,
-		struct asd_sas_port *sas_port, enum sas_linkrate linkrate)
+static void hisi_sas_refresh_port_id(struct hisi_hba *hisi_hba)
 {
-	struct hisi_sas_device	*sas_dev;
-	struct domain_device *device;
+	u32 state = hisi_hba->hw->get_phys_state(hisi_hba);
 	int i;
 
 	for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) {
-		sas_dev = &hisi_hba->devices[i];
-		device = sas_dev->sas_device;
+		struct hisi_sas_device *sas_dev = &hisi_hba->devices[i];
+		struct domain_device *device = sas_dev->sas_device;
+		struct asd_sas_port *sas_port;
+		struct hisi_sas_port *port;
+		struct hisi_sas_phy *phy = NULL;
+		struct asd_sas_phy *sas_phy;
+
 		if ((sas_dev->dev_type == SAS_PHY_UNUSED)
-				|| !device || (device->port != sas_port))
+				|| !device || !device->port)
 			continue;
 
-		hisi_hba->hw->clear_itct(hisi_hba, sas_dev);
+		sas_port = device->port;
+		port = to_hisi_sas_port(sas_port);
+
+		list_for_each_entry(sas_phy, &sas_port->phy_list, port_phy_el)
+			if (state & BIT(sas_phy->id)) {
+				phy = sas_phy->lldd_phy;
+				break;
+			}
+
+		if (phy) {
+			port->id = phy->port_id;
 
-		/* Update linkrate of directly attached device. */
-		if (!device->parent)
-			device->linkrate = linkrate;
+			/* Update linkrate of directly attached device. */
+			if (!device->parent)
+				device->linkrate = phy->sas_phy.linkrate;
 
-		hisi_hba->hw->setup_itct(hisi_hba, sas_dev);
+			hisi_hba->hw->setup_itct(hisi_hba, sas_dev);
+		} else
+			port->id = 0xff;
 	}
 }
 
@@ -1025,21 +1040,17 @@ static void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 old_state,
 		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 hisi_sas_port *port = to_hisi_sas_port(sas_port);
 		bool do_port_check = !!(_sas_port != sas_port);
 
 		if (!sas_phy->phy->enabled)
 			continue;
 
 		/* Report PHY state change to libsas */
-		if (state & (1 << phy_no)) {
-			if (do_port_check && sas_port) {
+		if (state & BIT(phy_no)) {
+			if (do_port_check && sas_port && sas_port->port_dev) {
 				struct domain_device *dev = sas_port->port_dev;
 
 				_sas_port = sas_port;
-				port->id = phy->port_id;
-				hisi_sas_refresh_port_id(hisi_hba,
-						sas_port, sas_phy->linkrate);
 
 				if (DEV_IS_EXPANDER(dev->dev_type))
 					sas_ha->notify_port_event(sas_phy,
@@ -1088,6 +1099,7 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba)
 	/* Init and wait for PHYs to come up and all libsas event finished. */
 	hisi_hba->hw->phys_init(hisi_hba);
 	msleep(1000);
+	hisi_sas_refresh_port_id(hisi_hba);
 	drain_workqueue(hisi_hba->wq);
 	drain_workqueue(shost->work_q);
 
-- 
1.9.1

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

* [PATCH 04/19] scsi: hisi_sas: optimise port id refresh function
@ 2017-12-08 17:16   ` John Garry
  0 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiaofei Tan, John Garry

From: Xiaofei Tan <tanxiaofei@huawei.com>

Currently refreshing the PHY port id after reset is
done in the rescan topology function, which is quite
late in the reset process. It could be moved earlier in
the process, as the port id can be refreshed once the
PHYs become ready.

In addition to this, we should set the hisi_sas_dev port
id to 0xff (invalid port id) if all PHYs of this port remain
down for the same device.

Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas_main.c | 48 ++++++++++++++++++++++-------------
 1 file changed, 30 insertions(+), 18 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 6446ce2..326ecb2 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -990,27 +990,42 @@ static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device,
 				sizeof(ssp_task), tmf);
 }
 
-static void hisi_sas_refresh_port_id(struct hisi_hba *hisi_hba,
-		struct asd_sas_port *sas_port, enum sas_linkrate linkrate)
+static void hisi_sas_refresh_port_id(struct hisi_hba *hisi_hba)
 {
-	struct hisi_sas_device	*sas_dev;
-	struct domain_device *device;
+	u32 state = hisi_hba->hw->get_phys_state(hisi_hba);
 	int i;
 
 	for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) {
-		sas_dev = &hisi_hba->devices[i];
-		device = sas_dev->sas_device;
+		struct hisi_sas_device *sas_dev = &hisi_hba->devices[i];
+		struct domain_device *device = sas_dev->sas_device;
+		struct asd_sas_port *sas_port;
+		struct hisi_sas_port *port;
+		struct hisi_sas_phy *phy = NULL;
+		struct asd_sas_phy *sas_phy;
+
 		if ((sas_dev->dev_type == SAS_PHY_UNUSED)
-				|| !device || (device->port != sas_port))
+				|| !device || !device->port)
 			continue;
 
-		hisi_hba->hw->clear_itct(hisi_hba, sas_dev);
+		sas_port = device->port;
+		port = to_hisi_sas_port(sas_port);
+
+		list_for_each_entry(sas_phy, &sas_port->phy_list, port_phy_el)
+			if (state & BIT(sas_phy->id)) {
+				phy = sas_phy->lldd_phy;
+				break;
+			}
+
+		if (phy) {
+			port->id = phy->port_id;
 
-		/* Update linkrate of directly attached device. */
-		if (!device->parent)
-			device->linkrate = linkrate;
+			/* Update linkrate of directly attached device. */
+			if (!device->parent)
+				device->linkrate = phy->sas_phy.linkrate;
 
-		hisi_hba->hw->setup_itct(hisi_hba, sas_dev);
+			hisi_hba->hw->setup_itct(hisi_hba, sas_dev);
+		} else
+			port->id = 0xff;
 	}
 }
 
@@ -1025,21 +1040,17 @@ static void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 old_state,
 		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 hisi_sas_port *port = to_hisi_sas_port(sas_port);
 		bool do_port_check = !!(_sas_port != sas_port);
 
 		if (!sas_phy->phy->enabled)
 			continue;
 
 		/* Report PHY state change to libsas */
-		if (state & (1 << phy_no)) {
-			if (do_port_check && sas_port) {
+		if (state & BIT(phy_no)) {
+			if (do_port_check && sas_port && sas_port->port_dev) {
 				struct domain_device *dev = sas_port->port_dev;
 
 				_sas_port = sas_port;
-				port->id = phy->port_id;
-				hisi_sas_refresh_port_id(hisi_hba,
-						sas_port, sas_phy->linkrate);
 
 				if (DEV_IS_EXPANDER(dev->dev_type))
 					sas_ha->notify_port_event(sas_phy,
@@ -1088,6 +1099,7 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba)
 	/* Init and wait for PHYs to come up and all libsas event finished. */
 	hisi_hba->hw->phys_init(hisi_hba);
 	msleep(1000);
+	hisi_sas_refresh_port_id(hisi_hba);
 	drain_workqueue(hisi_hba->wq);
 	drain_workqueue(shost->work_q);
 
-- 
1.9.1

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

* [PATCH 05/19] scsi: hisi_sas: some optimizations of host controller reset
  2017-12-08 17:16 ` John Garry
@ 2017-12-08 17:16   ` John Garry
  -1 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiaofei Tan, John Garry

From: Xiaofei Tan <tanxiaofei@huawei.com>

This patch do following optimizations to host controller reset:
1. Unblock scsi requests before rescanning topology, as SCSI
command need be used if new device is found during rescanning
topology.

2. Remove drain_workqueue(hisi_hba->wq) and
drain_workqueue(shost->work_q), as there is no need to ensure
that all PHYs event are done before exiting host reset.

3. Improve message print level of host reset. Host reset is an
important and very few occurrence event. We should know its progress
even when not debugging.

Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas_main.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 326ecb2..64d51a8 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -1061,8 +1061,6 @@ static void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 old_state,
 			hisi_sas_phy_down(hisi_hba, phy_no, 0);
 
 	}
-
-	drain_workqueue(hisi_hba->shost->work_q);
 }
 
 static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba)
@@ -1079,7 +1077,7 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba)
 	if (test_and_set_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags))
 		return -1;
 
-	dev_dbg(dev, "controller resetting...\n");
+	dev_info(dev, "controller resetting...\n");
 	old_state = hisi_hba->hw->get_phys_state(hisi_hba);
 
 	scsi_block_requests(shost);
@@ -1088,6 +1086,7 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba)
 	if (rc) {
 		dev_warn(dev, "controller reset failed (%d)\n", rc);
 		clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
+		scsi_unblock_requests(shost);
 		goto out;
 	}
 	spin_lock_irqsave(&hisi_hba->lock, flags);
@@ -1100,15 +1099,13 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba)
 	hisi_hba->hw->phys_init(hisi_hba);
 	msleep(1000);
 	hisi_sas_refresh_port_id(hisi_hba);
-	drain_workqueue(hisi_hba->wq);
-	drain_workqueue(shost->work_q);
+	scsi_unblock_requests(shost);
 
 	state = hisi_hba->hw->get_phys_state(hisi_hba);
 	hisi_sas_rescan_topology(hisi_hba, old_state, state);
-	dev_dbg(dev, "controller reset complete\n");
+	dev_info(dev, "controller reset complete\n");
 
 out:
-	scsi_unblock_requests(shost);
 	clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags);
 
 	return rc;
-- 
1.9.1

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

* [PATCH 05/19] scsi: hisi_sas: some optimizations of host controller reset
@ 2017-12-08 17:16   ` John Garry
  0 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiaofei Tan, John Garry

From: Xiaofei Tan <tanxiaofei@huawei.com>

This patch do following optimizations to host controller reset:
1. Unblock scsi requests before rescanning topology, as SCSI
command need be used if new device is found during rescanning
topology.

2. Remove drain_workqueue(hisi_hba->wq) and
drain_workqueue(shost->work_q), as there is no need to ensure
that all PHYs event are done before exiting host reset.

3. Improve message print level of host reset. Host reset is an
important and very few occurrence event. We should know its progress
even when not debugging.

Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas_main.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 326ecb2..64d51a8 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -1061,8 +1061,6 @@ static void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 old_state,
 			hisi_sas_phy_down(hisi_hba, phy_no, 0);
 
 	}
-
-	drain_workqueue(hisi_hba->shost->work_q);
 }
 
 static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba)
@@ -1079,7 +1077,7 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba)
 	if (test_and_set_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags))
 		return -1;
 
-	dev_dbg(dev, "controller resetting...\n");
+	dev_info(dev, "controller resetting...\n");
 	old_state = hisi_hba->hw->get_phys_state(hisi_hba);
 
 	scsi_block_requests(shost);
@@ -1088,6 +1086,7 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba)
 	if (rc) {
 		dev_warn(dev, "controller reset failed (%d)\n", rc);
 		clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
+		scsi_unblock_requests(shost);
 		goto out;
 	}
 	spin_lock_irqsave(&hisi_hba->lock, flags);
@@ -1100,15 +1099,13 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba)
 	hisi_hba->hw->phys_init(hisi_hba);
 	msleep(1000);
 	hisi_sas_refresh_port_id(hisi_hba);
-	drain_workqueue(hisi_hba->wq);
-	drain_workqueue(shost->work_q);
+	scsi_unblock_requests(shost);
 
 	state = hisi_hba->hw->get_phys_state(hisi_hba);
 	hisi_sas_rescan_topology(hisi_hba, old_state, state);
-	dev_dbg(dev, "controller reset complete\n");
+	dev_info(dev, "controller reset complete\n");
 
 out:
-	scsi_unblock_requests(shost);
 	clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags);
 
 	return rc;
-- 
1.9.1

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

* [PATCH 06/19] scsi: hisi_sas: modify hisi_sas_dev_gone() for reset
  2017-12-08 17:16 ` John Garry
@ 2017-12-08 17:16   ` John Garry
  -1 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiang Chen, John Garry

From: Xiang Chen <chenxiang66@hisilicon.com>

Do a couple of changes for when HISI_SAS_RESET_BIT is
set for HBA:
- Clearing ITCT is not necessary
- Remove internal abort as it will fail during reset

Flag sas_dev->dev_type is kept as SAS_PHY_UNUSED.

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 | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 64d51a8..e4b3092 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -738,17 +738,19 @@ static void hisi_sas_dev_gone(struct domain_device *device)
 	dev_info(dev, "found dev[%d:%x] is gone\n",
 		 sas_dev->device_id, sas_dev->dev_type);
 
-	hisi_sas_internal_task_abort(hisi_hba, device,
+	if (!test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) {
+		hisi_sas_internal_task_abort(hisi_hba, device,
 				     HISI_SAS_INT_ABT_DEV, 0);
 
-	hisi_sas_dereg_device(hisi_hba, device);
+		hisi_sas_dereg_device(hisi_hba, device);
+
+		hisi_hba->hw->clear_itct(hisi_hba, sas_dev);
+		device->lldd_dev = NULL;
+		memset(sas_dev, 0, sizeof(*sas_dev));
+	}
 
-	hisi_hba->hw->clear_itct(hisi_hba, sas_dev);
 	if (hisi_hba->hw->free_device)
 		hisi_hba->hw->free_device(sas_dev);
-
-	device->lldd_dev = NULL;
-	memset(sas_dev, 0, sizeof(*sas_dev));
 	sas_dev->dev_type = SAS_PHY_UNUSED;
 }
 
-- 
1.9.1

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

* [PATCH 06/19] scsi: hisi_sas: modify hisi_sas_dev_gone() for reset
@ 2017-12-08 17:16   ` John Garry
  0 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiang Chen, John Garry

From: Xiang Chen <chenxiang66@hisilicon.com>

Do a couple of changes for when HISI_SAS_RESET_BIT is
set for HBA:
- Clearing ITCT is not necessary
- Remove internal abort as it will fail during reset

Flag sas_dev->dev_type is kept as SAS_PHY_UNUSED.

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 | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 64d51a8..e4b3092 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -738,17 +738,19 @@ static void hisi_sas_dev_gone(struct domain_device *device)
 	dev_info(dev, "found dev[%d:%x] is gone\n",
 		 sas_dev->device_id, sas_dev->dev_type);
 
-	hisi_sas_internal_task_abort(hisi_hba, device,
+	if (!test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) {
+		hisi_sas_internal_task_abort(hisi_hba, device,
 				     HISI_SAS_INT_ABT_DEV, 0);
 
-	hisi_sas_dereg_device(hisi_hba, device);
+		hisi_sas_dereg_device(hisi_hba, device);
+
+		hisi_hba->hw->clear_itct(hisi_hba, sas_dev);
+		device->lldd_dev = NULL;
+		memset(sas_dev, 0, sizeof(*sas_dev));
+	}
 
-	hisi_hba->hw->clear_itct(hisi_hba, sas_dev);
 	if (hisi_hba->hw->free_device)
 		hisi_hba->hw->free_device(sas_dev);
-
-	device->lldd_dev = NULL;
-	memset(sas_dev, 0, sizeof(*sas_dev));
 	sas_dev->dev_type = SAS_PHY_UNUSED;
 }
 
-- 
1.9.1

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

* [PATCH 07/19] scsi: hisi_sas: add an mechanism to do reset work synchronously
  2017-12-08 17:16 ` John Garry
@ 2017-12-08 17:16   ` John Garry
  -1 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiaofei Tan, John Garry

From: Xiaofei Tan <tanxiaofei@huawei.com>

Sometimes it is required to know when the controller reset
has completed and also if it has completed successfully.
For such places, we call hisi_sas_controller_reset() directly
before. That may lead to multiple calls to this function.

This patch create a per-reset structure which contains
a completion structure and status flag to know when the reset
completes and also the status. It is also in hisi_hba.wq to
do reset work.

As all host reset works are done in hisi_hba.wq, we don't worry
multiple calls to hisi_sas_controller_reset().

Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas.h      | 26 ++++++++++++++++++++++++++
 drivers/scsi/hisi_sas/hisi_sas_main.c | 19 ++++++++++++++++++-
 2 files changed, 44 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index b2534ca..71bc8ea 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -99,6 +99,31 @@ struct hisi_sas_hw_error {
 	const struct hisi_sas_hw_error *sub;
 };
 
+struct hisi_sas_rst {
+	struct hisi_hba *hisi_hba;
+	struct completion *completion;
+	struct work_struct work;
+	bool done;
+};
+
+#define HISI_SAS_RST_WORK_INIT(r, c) \
+	{	.hisi_hba = hisi_hba, \
+		.completion = &c, \
+		.work = __WORK_INITIALIZER(r.work, \
+				hisi_sas_sync_rst_work_handler), \
+		.done = false, \
+		}
+
+#define HISI_SAS_DECLARE_RST_WORK_ON_STACK(r) \
+	DECLARE_COMPLETION_ONSTACK(c); \
+	DECLARE_WORK(w, hisi_sas_sync_rst_work_handler); \
+	struct hisi_sas_rst r = HISI_SAS_RST_WORK_INIT(r, c)
+
+enum hisi_sas_bit_err_type {
+	HISI_SAS_ERR_SINGLE_BIT_ECC = 0x0,
+	HISI_SAS_ERR_MULTI_BIT_ECC = 0x1,
+};
+
 struct hisi_sas_phy {
 	struct hisi_hba	*hisi_hba;
 	struct hisi_sas_port	*port;
@@ -426,5 +451,6 @@ extern void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba,
 				    struct hisi_sas_slot *slot);
 extern void hisi_sas_init_mem(struct hisi_hba *hisi_hba);
 extern void hisi_sas_rst_work_handler(struct work_struct *work);
+extern void hisi_sas_sync_rst_work_handler(struct work_struct *work);
 extern void hisi_sas_kill_tasklets(struct hisi_hba *hisi_hba);
 #endif
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index e4b3092..fb162c0 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -1299,8 +1299,14 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun)
 static int hisi_sas_clear_nexus_ha(struct sas_ha_struct *sas_ha)
 {
 	struct hisi_hba *hisi_hba = sas_ha->lldd_ha;
+	HISI_SAS_DECLARE_RST_WORK_ON_STACK(r);
 
-	return hisi_sas_controller_reset(hisi_hba);
+	queue_work(hisi_hba->wq, &r.work);
+	wait_for_completion(r.completion);
+	if (r.done)
+		return TMF_RESP_FUNC_COMPLETE;
+
+	return TMF_RESP_FUNC_FAILED;
 }
 
 static int hisi_sas_query_task(struct sas_task *task)
@@ -1820,6 +1826,17 @@ void hisi_sas_rst_work_handler(struct work_struct *work)
 }
 EXPORT_SYMBOL_GPL(hisi_sas_rst_work_handler);
 
+void hisi_sas_sync_rst_work_handler(struct work_struct *work)
+{
+	struct hisi_sas_rst *rst =
+		container_of(work, struct hisi_sas_rst, work);
+
+	if (!hisi_sas_controller_reset(rst->hisi_hba))
+		rst->done = true;
+	complete(rst->completion);
+}
+EXPORT_SYMBOL_GPL(hisi_sas_sync_rst_work_handler);
+
 int hisi_sas_get_fw_info(struct hisi_hba *hisi_hba)
 {
 	struct device *dev = hisi_hba->dev;
-- 
1.9.1

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

* [PATCH 07/19] scsi: hisi_sas: add an mechanism to do reset work synchronously
@ 2017-12-08 17:16   ` John Garry
  0 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiaofei Tan, John Garry

From: Xiaofei Tan <tanxiaofei@huawei.com>

Sometimes it is required to know when the controller reset
has completed and also if it has completed successfully.
For such places, we call hisi_sas_controller_reset() directly
before. That may lead to multiple calls to this function.

This patch create a per-reset structure which contains
a completion structure and status flag to know when the reset
completes and also the status. It is also in hisi_hba.wq to
do reset work.

As all host reset works are done in hisi_hba.wq, we don't worry
multiple calls to hisi_sas_controller_reset().

Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas.h      | 26 ++++++++++++++++++++++++++
 drivers/scsi/hisi_sas/hisi_sas_main.c | 19 ++++++++++++++++++-
 2 files changed, 44 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index b2534ca..71bc8ea 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -99,6 +99,31 @@ struct hisi_sas_hw_error {
 	const struct hisi_sas_hw_error *sub;
 };
 
+struct hisi_sas_rst {
+	struct hisi_hba *hisi_hba;
+	struct completion *completion;
+	struct work_struct work;
+	bool done;
+};
+
+#define HISI_SAS_RST_WORK_INIT(r, c) \
+	{	.hisi_hba = hisi_hba, \
+		.completion = &c, \
+		.work = __WORK_INITIALIZER(r.work, \
+				hisi_sas_sync_rst_work_handler), \
+		.done = false, \
+		}
+
+#define HISI_SAS_DECLARE_RST_WORK_ON_STACK(r) \
+	DECLARE_COMPLETION_ONSTACK(c); \
+	DECLARE_WORK(w, hisi_sas_sync_rst_work_handler); \
+	struct hisi_sas_rst r = HISI_SAS_RST_WORK_INIT(r, c)
+
+enum hisi_sas_bit_err_type {
+	HISI_SAS_ERR_SINGLE_BIT_ECC = 0x0,
+	HISI_SAS_ERR_MULTI_BIT_ECC = 0x1,
+};
+
 struct hisi_sas_phy {
 	struct hisi_hba	*hisi_hba;
 	struct hisi_sas_port	*port;
@@ -426,5 +451,6 @@ extern void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba,
 				    struct hisi_sas_slot *slot);
 extern void hisi_sas_init_mem(struct hisi_hba *hisi_hba);
 extern void hisi_sas_rst_work_handler(struct work_struct *work);
+extern void hisi_sas_sync_rst_work_handler(struct work_struct *work);
 extern void hisi_sas_kill_tasklets(struct hisi_hba *hisi_hba);
 #endif
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index e4b3092..fb162c0 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -1299,8 +1299,14 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun)
 static int hisi_sas_clear_nexus_ha(struct sas_ha_struct *sas_ha)
 {
 	struct hisi_hba *hisi_hba = sas_ha->lldd_ha;
+	HISI_SAS_DECLARE_RST_WORK_ON_STACK(r);
 
-	return hisi_sas_controller_reset(hisi_hba);
+	queue_work(hisi_hba->wq, &r.work);
+	wait_for_completion(r.completion);
+	if (r.done)
+		return TMF_RESP_FUNC_COMPLETE;
+
+	return TMF_RESP_FUNC_FAILED;
 }
 
 static int hisi_sas_query_task(struct sas_task *task)
@@ -1820,6 +1826,17 @@ void hisi_sas_rst_work_handler(struct work_struct *work)
 }
 EXPORT_SYMBOL_GPL(hisi_sas_rst_work_handler);
 
+void hisi_sas_sync_rst_work_handler(struct work_struct *work)
+{
+	struct hisi_sas_rst *rst =
+		container_of(work, struct hisi_sas_rst, work);
+
+	if (!hisi_sas_controller_reset(rst->hisi_hba))
+		rst->done = true;
+	complete(rst->completion);
+}
+EXPORT_SYMBOL_GPL(hisi_sas_sync_rst_work_handler);
+
 int hisi_sas_get_fw_info(struct hisi_hba *hisi_hba)
 {
 	struct device *dev = hisi_hba->dev;
-- 
1.9.1

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

* [PATCH 08/19] scsi: hisi_sas: change ncq process for v3 hw
  2017-12-08 17:16 ` John Garry
@ 2017-12-08 17:16   ` John Garry
  -1 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiang Chen, John Garry

From: Xiang Chen <chenxiang66@hisilicon.com>

For v3 hw, each NCQ will return a CQ, so it is no need to
acquire IPTT from ITCT, just acquire it from IPTT field of
CQ.

Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 40 +++++-----------------------------
 1 file changed, 6 insertions(+), 34 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 44f07bc..69aa7bc 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -1653,9 +1653,8 @@ static void cq_tasklet_v3_hw(unsigned long val)
 	struct hisi_sas_cq *cq = (struct hisi_sas_cq *)val;
 	struct hisi_hba *hisi_hba = cq->hisi_hba;
 	struct hisi_sas_slot *slot;
-	struct hisi_sas_itct *itct;
 	struct hisi_sas_complete_v3_hdr *complete_queue;
-	u32 rd_point = cq->rd_point, wr_point, dev_id;
+	u32 rd_point = cq->rd_point, wr_point;
 	int queue = cq->id;
 	struct hisi_sas_dq *dq = &hisi_hba->dq[queue];
 
@@ -1671,38 +1670,11 @@ static void cq_tasklet_v3_hw(unsigned long val)
 
 		complete_hdr = &complete_queue[rd_point];
 
-		/* Check for NCQ completion */
-		if (complete_hdr->act) {
-			u32 act_tmp = complete_hdr->act;
-			int ncq_tag_count = ffs(act_tmp);
-
-			dev_id = (complete_hdr->dw1 & CMPLT_HDR_DEV_ID_MSK) >>
-				 CMPLT_HDR_DEV_ID_OFF;
-			itct = &hisi_hba->itct[dev_id];
-
-			/* The NCQ tags are held in the itct header */
-			while (ncq_tag_count) {
-				__le64 *ncq_tag = &itct->qw4_15[0];
-
-				ncq_tag_count -= 1;
-				iptt = (ncq_tag[ncq_tag_count / 5]
-					>> (ncq_tag_count % 5) * 12) & 0xfff;
-
-				slot = &hisi_hba->slot_info[iptt];
-				slot->cmplt_queue_slot = rd_point;
-				slot->cmplt_queue = queue;
-				slot_complete_v3_hw(hisi_hba, slot);
-
-				act_tmp &= ~(1 << ncq_tag_count);
-				ncq_tag_count = ffs(act_tmp);
-			}
-		} else {
-			iptt = (complete_hdr->dw1) & CMPLT_HDR_IPTT_MSK;
-			slot = &hisi_hba->slot_info[iptt];
-			slot->cmplt_queue_slot = rd_point;
-			slot->cmplt_queue = queue;
-			slot_complete_v3_hw(hisi_hba, slot);
-		}
+		iptt = (complete_hdr->dw1) & CMPLT_HDR_IPTT_MSK;
+		slot = &hisi_hba->slot_info[iptt];
+		slot->cmplt_queue_slot = rd_point;
+		slot->cmplt_queue = queue;
+		slot_complete_v3_hw(hisi_hba, slot);
 
 		if (++rd_point >= HISI_SAS_QUEUE_SLOTS)
 			rd_point = 0;
-- 
1.9.1

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

* [PATCH 08/19] scsi: hisi_sas: change ncq process for v3 hw
@ 2017-12-08 17:16   ` John Garry
  0 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiang Chen, John Garry

From: Xiang Chen <chenxiang66@hisilicon.com>

For v3 hw, each NCQ will return a CQ, so it is no need to
acquire IPTT from ITCT, just acquire it from IPTT field of
CQ.

Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 40 +++++-----------------------------
 1 file changed, 6 insertions(+), 34 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 44f07bc..69aa7bc 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -1653,9 +1653,8 @@ static void cq_tasklet_v3_hw(unsigned long val)
 	struct hisi_sas_cq *cq = (struct hisi_sas_cq *)val;
 	struct hisi_hba *hisi_hba = cq->hisi_hba;
 	struct hisi_sas_slot *slot;
-	struct hisi_sas_itct *itct;
 	struct hisi_sas_complete_v3_hdr *complete_queue;
-	u32 rd_point = cq->rd_point, wr_point, dev_id;
+	u32 rd_point = cq->rd_point, wr_point;
 	int queue = cq->id;
 	struct hisi_sas_dq *dq = &hisi_hba->dq[queue];
 
@@ -1671,38 +1670,11 @@ static void cq_tasklet_v3_hw(unsigned long val)
 
 		complete_hdr = &complete_queue[rd_point];
 
-		/* Check for NCQ completion */
-		if (complete_hdr->act) {
-			u32 act_tmp = complete_hdr->act;
-			int ncq_tag_count = ffs(act_tmp);
-
-			dev_id = (complete_hdr->dw1 & CMPLT_HDR_DEV_ID_MSK) >>
-				 CMPLT_HDR_DEV_ID_OFF;
-			itct = &hisi_hba->itct[dev_id];
-
-			/* The NCQ tags are held in the itct header */
-			while (ncq_tag_count) {
-				__le64 *ncq_tag = &itct->qw4_15[0];
-
-				ncq_tag_count -= 1;
-				iptt = (ncq_tag[ncq_tag_count / 5]
-					>> (ncq_tag_count % 5) * 12) & 0xfff;
-
-				slot = &hisi_hba->slot_info[iptt];
-				slot->cmplt_queue_slot = rd_point;
-				slot->cmplt_queue = queue;
-				slot_complete_v3_hw(hisi_hba, slot);
-
-				act_tmp &= ~(1 << ncq_tag_count);
-				ncq_tag_count = ffs(act_tmp);
-			}
-		} else {
-			iptt = (complete_hdr->dw1) & CMPLT_HDR_IPTT_MSK;
-			slot = &hisi_hba->slot_info[iptt];
-			slot->cmplt_queue_slot = rd_point;
-			slot->cmplt_queue = queue;
-			slot_complete_v3_hw(hisi_hba, slot);
-		}
+		iptt = (complete_hdr->dw1) & CMPLT_HDR_IPTT_MSK;
+		slot = &hisi_hba->slot_info[iptt];
+		slot->cmplt_queue_slot = rd_point;
+		slot->cmplt_queue = queue;
+		slot_complete_v3_hw(hisi_hba, slot);
 
 		if (++rd_point >= HISI_SAS_QUEUE_SLOTS)
 			rd_point = 0;
-- 
1.9.1

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

* [PATCH 09/19] scsi: hisi_sas: add RAS feature for v3 hw
  2017-12-08 17:16 ` John Garry
@ 2017-12-08 17:16   ` John Garry
  -1 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiaofei Tan, John Garry

From: Xiaofei Tan <tanxiaofei@huawei.com>

We use PCIe AER to support RAS feature for v3 hw.
This driver should do following two things to support this:
1. Enable RAS interrupts, so that errors can be reported to
RAS module.
2. Realize err_handler for sas_v3_pci_driver. Then if non-fatal
error is detected, print error source and try to recover SAS
controller.

Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 139 +++++++++++++++++++++++++++++++++
 1 file changed, 139 insertions(+)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 69aa7bc..d356e12 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -204,6 +204,13 @@
 #define AM_ROB_ECC_MULBIT_ERR_ADDR_OFF	8
 #define AM_ROB_ECC_MULBIT_ERR_ADDR_MSK	(0xff << AM_ROB_ECC_MULBIT_ERR_ADDR_OFF)
 
+/* RAS registers need init */
+#define RAS_BASE		(0x6000)
+#define SAS_RAS_INTR0			(RAS_BASE)
+#define SAS_RAS_INTR1			(RAS_BASE + 0x04)
+#define SAS_RAS_INTR0_MASK		(RAS_BASE + 0x08)
+#define SAS_RAS_INTR1_MASK		(RAS_BASE + 0x0c)
+
 /* HW dma structures */
 /* Delivery queue header */
 /* dw0 */
@@ -496,6 +503,10 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
 
 	hisi_sas_write32(hisi_hba, SATA_INITI_D2H_STORE_ADDR_HI,
 			 upper_32_bits(hisi_hba->initial_fis_dma));
+
+	/* RAS registers init */
+	hisi_sas_write32(hisi_hba, SAS_RAS_INTR0_MASK, 0x0);
+	hisi_sas_write32(hisi_hba, SAS_RAS_INTR1_MASK, 0x0);
 }
 
 static void config_phy_opt_mode_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
@@ -2129,6 +2140,127 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev)
 	scsi_host_put(shost);
 }
 
+static const struct hisi_sas_hw_error sas_ras_intr0_nfe[] = {
+	{ .irq_msk = BIT(19), .msg = "HILINK_INT" },
+	{ .irq_msk = BIT(20), .msg = "HILINK_PLL0_OUT_OF_LOCK" },
+	{ .irq_msk = BIT(21), .msg = "HILINK_PLL1_OUT_OF_LOCK" },
+	{ .irq_msk = BIT(22), .msg = "HILINK_LOSS_OF_REFCLK0" },
+	{ .irq_msk = BIT(23), .msg = "HILINK_LOSS_OF_REFCLK1" },
+	{ .irq_msk = BIT(24), .msg = "DMAC0_TX_POISON" },
+	{ .irq_msk = BIT(25), .msg = "DMAC1_TX_POISON" },
+	{ .irq_msk = BIT(26), .msg = "DMAC2_TX_POISON" },
+	{ .irq_msk = BIT(27), .msg = "DMAC3_TX_POISON" },
+	{ .irq_msk = BIT(28), .msg = "DMAC4_TX_POISON" },
+	{ .irq_msk = BIT(29), .msg = "DMAC5_TX_POISON" },
+	{ .irq_msk = BIT(30), .msg = "DMAC6_TX_POISON" },
+	{ .irq_msk = BIT(31), .msg = "DMAC7_TX_POISON" },
+};
+
+static const struct hisi_sas_hw_error sas_ras_intr1_nfe[] = {
+	{ .irq_msk = BIT(0), .msg = "RXM_CFG_MEM3_ECC2B_INTR" },
+	{ .irq_msk = BIT(1), .msg = "RXM_CFG_MEM2_ECC2B_INTR" },
+	{ .irq_msk = BIT(2), .msg = "RXM_CFG_MEM1_ECC2B_INTR" },
+	{ .irq_msk = BIT(3), .msg = "RXM_CFG_MEM0_ECC2B_INTR" },
+	{ .irq_msk = BIT(4), .msg = "HGC_CQE_ECC2B_INTR" },
+	{ .irq_msk = BIT(5), .msg = "LM_CFG_IOSTL_ECC2B_INTR" },
+	{ .irq_msk = BIT(6), .msg = "LM_CFG_ITCTL_ECC2B_INTR" },
+	{ .irq_msk = BIT(7), .msg = "HGC_ITCT_ECC2B_INTR" },
+	{ .irq_msk = BIT(8), .msg = "HGC_IOST_ECC2B_INTR" },
+	{ .irq_msk = BIT(9), .msg = "HGC_DQE_ECC2B_INTR" },
+	{ .irq_msk = BIT(10), .msg = "DMAC0_RAM_ECC2B_INTR" },
+	{ .irq_msk = BIT(11), .msg = "DMAC1_RAM_ECC2B_INTR" },
+	{ .irq_msk = BIT(12), .msg = "DMAC2_RAM_ECC2B_INTR" },
+	{ .irq_msk = BIT(13), .msg = "DMAC3_RAM_ECC2B_INTR" },
+	{ .irq_msk = BIT(14), .msg = "DMAC4_RAM_ECC2B_INTR" },
+	{ .irq_msk = BIT(15), .msg = "DMAC5_RAM_ECC2B_INTR" },
+	{ .irq_msk = BIT(16), .msg = "DMAC6_RAM_ECC2B_INTR" },
+	{ .irq_msk = BIT(17), .msg = "DMAC7_RAM_ECC2B_INTR" },
+	{ .irq_msk = BIT(18), .msg = "OOO_RAM_ECC2B_INTR" },
+	{ .irq_msk = BIT(20), .msg = "HGC_DQE_POISON_INTR" },
+	{ .irq_msk = BIT(21), .msg = "HGC_IOST_POISON_INTR" },
+	{ .irq_msk = BIT(22), .msg = "HGC_ITCT_POISON_INTR" },
+	{ .irq_msk = BIT(23), .msg = "HGC_ITCT_NCQ_POISON_INTR" },
+	{ .irq_msk = BIT(24), .msg = "DMAC0_RX_POISON" },
+	{ .irq_msk = BIT(25), .msg = "DMAC1_RX_POISON" },
+	{ .irq_msk = BIT(26), .msg = "DMAC2_RX_POISON" },
+	{ .irq_msk = BIT(27), .msg = "DMAC3_RX_POISON" },
+	{ .irq_msk = BIT(28), .msg = "DMAC4_RX_POISON" },
+	{ .irq_msk = BIT(29), .msg = "DMAC5_RX_POISON" },
+	{ .irq_msk = BIT(30), .msg = "DMAC6_RX_POISON" },
+	{ .irq_msk = BIT(31), .msg = "DMAC7_RX_POISON" },
+};
+
+static bool process_non_fatal_error_v3_hw(struct hisi_hba *hisi_hba)
+{
+	struct device *dev = hisi_hba->dev;
+	const struct hisi_sas_hw_error *ras_error;
+	bool need_reset = false;
+	u32 irq_value;
+	int i;
+
+	irq_value = hisi_sas_read32(hisi_hba, SAS_RAS_INTR0);
+	for (i = 0; i < ARRAY_SIZE(sas_ras_intr0_nfe); i++) {
+		ras_error = &sas_ras_intr0_nfe[i];
+		if (ras_error->irq_msk & irq_value) {
+			dev_warn(dev, "SAS_RAS_INTR0: %s(irq_value=0x%x) found.\n",
+					ras_error->msg, irq_value);
+			need_reset = true;
+		}
+	}
+	hisi_sas_write32(hisi_hba, SAS_RAS_INTR0, irq_value);
+
+	irq_value = hisi_sas_read32(hisi_hba, SAS_RAS_INTR1);
+	for (i = 0; i < ARRAY_SIZE(sas_ras_intr1_nfe); i++) {
+		ras_error = &sas_ras_intr1_nfe[i];
+		if (ras_error->irq_msk & irq_value) {
+			dev_warn(dev, "SAS_RAS_INTR1: %s(irq_value=0x%x) found.\n",
+					ras_error->msg, irq_value);
+			need_reset = true;
+		}
+	}
+	hisi_sas_write32(hisi_hba, SAS_RAS_INTR1, irq_value);
+
+	return need_reset;
+}
+
+static pci_ers_result_t hisi_sas_error_detected_v3_hw(struct pci_dev *pdev,
+		pci_channel_state_t state)
+{
+	struct sas_ha_struct *sha = pci_get_drvdata(pdev);
+	struct hisi_hba *hisi_hba = sha->lldd_ha;
+	struct device *dev = hisi_hba->dev;
+
+	dev_info(dev, "PCI error: detected callback, state(%d)!!\n", state);
+	if (state == pci_channel_io_perm_failure)
+		return PCI_ERS_RESULT_DISCONNECT;
+
+	if (process_non_fatal_error_v3_hw(hisi_hba))
+		return PCI_ERS_RESULT_NEED_RESET;
+
+	return PCI_ERS_RESULT_CAN_RECOVER;
+}
+
+static pci_ers_result_t hisi_sas_mmio_enabled_v3_hw(struct pci_dev *pdev)
+{
+	return PCI_ERS_RESULT_RECOVERED;
+}
+
+static pci_ers_result_t hisi_sas_slot_reset_v3_hw(struct pci_dev *pdev)
+{
+	struct sas_ha_struct *sha = pci_get_drvdata(pdev);
+	struct hisi_hba *hisi_hba = sha->lldd_ha;
+	struct device *dev = hisi_hba->dev;
+	HISI_SAS_DECLARE_RST_WORK_ON_STACK(r);
+
+	dev_info(dev, "PCI error: slot reset callback!!\n");
+	queue_work(hisi_hba->wq, &r.work);
+	wait_for_completion(r.completion);
+	if (r.done)
+		return PCI_ERS_RESULT_RECOVERED;
+
+	return PCI_ERS_RESULT_DISCONNECT;
+}
+
 enum {
 	/* instances of the controller */
 	hip08,
@@ -2139,11 +2271,18 @@ enum {
 	{}
 };
 
+static const struct pci_error_handlers hisi_sas_err_handler = {
+	.error_detected	= hisi_sas_error_detected_v3_hw,
+	.mmio_enabled	= hisi_sas_mmio_enabled_v3_hw,
+	.slot_reset	= hisi_sas_slot_reset_v3_hw,
+};
+
 static struct pci_driver sas_v3_pci_driver = {
 	.name		= DRV_NAME,
 	.id_table	= sas_v3_pci_table,
 	.probe		= hisi_sas_v3_probe,
 	.remove		= hisi_sas_v3_remove,
+	.err_handler	= &hisi_sas_err_handler,
 };
 
 module_pci_driver(sas_v3_pci_driver);
-- 
1.9.1

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

* [PATCH 09/19] scsi: hisi_sas: add RAS feature for v3 hw
@ 2017-12-08 17:16   ` John Garry
  0 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiaofei Tan, John Garry

From: Xiaofei Tan <tanxiaofei@huawei.com>

We use PCIe AER to support RAS feature for v3 hw.
This driver should do following two things to support this:
1. Enable RAS interrupts, so that errors can be reported to
RAS module.
2. Realize err_handler for sas_v3_pci_driver. Then if non-fatal
error is detected, print error source and try to recover SAS
controller.

Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 139 +++++++++++++++++++++++++++++++++
 1 file changed, 139 insertions(+)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 69aa7bc..d356e12 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -204,6 +204,13 @@
 #define AM_ROB_ECC_MULBIT_ERR_ADDR_OFF	8
 #define AM_ROB_ECC_MULBIT_ERR_ADDR_MSK	(0xff << AM_ROB_ECC_MULBIT_ERR_ADDR_OFF)
 
+/* RAS registers need init */
+#define RAS_BASE		(0x6000)
+#define SAS_RAS_INTR0			(RAS_BASE)
+#define SAS_RAS_INTR1			(RAS_BASE + 0x04)
+#define SAS_RAS_INTR0_MASK		(RAS_BASE + 0x08)
+#define SAS_RAS_INTR1_MASK		(RAS_BASE + 0x0c)
+
 /* HW dma structures */
 /* Delivery queue header */
 /* dw0 */
@@ -496,6 +503,10 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
 
 	hisi_sas_write32(hisi_hba, SATA_INITI_D2H_STORE_ADDR_HI,
 			 upper_32_bits(hisi_hba->initial_fis_dma));
+
+	/* RAS registers init */
+	hisi_sas_write32(hisi_hba, SAS_RAS_INTR0_MASK, 0x0);
+	hisi_sas_write32(hisi_hba, SAS_RAS_INTR1_MASK, 0x0);
 }
 
 static void config_phy_opt_mode_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
@@ -2129,6 +2140,127 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev)
 	scsi_host_put(shost);
 }
 
+static const struct hisi_sas_hw_error sas_ras_intr0_nfe[] = {
+	{ .irq_msk = BIT(19), .msg = "HILINK_INT" },
+	{ .irq_msk = BIT(20), .msg = "HILINK_PLL0_OUT_OF_LOCK" },
+	{ .irq_msk = BIT(21), .msg = "HILINK_PLL1_OUT_OF_LOCK" },
+	{ .irq_msk = BIT(22), .msg = "HILINK_LOSS_OF_REFCLK0" },
+	{ .irq_msk = BIT(23), .msg = "HILINK_LOSS_OF_REFCLK1" },
+	{ .irq_msk = BIT(24), .msg = "DMAC0_TX_POISON" },
+	{ .irq_msk = BIT(25), .msg = "DMAC1_TX_POISON" },
+	{ .irq_msk = BIT(26), .msg = "DMAC2_TX_POISON" },
+	{ .irq_msk = BIT(27), .msg = "DMAC3_TX_POISON" },
+	{ .irq_msk = BIT(28), .msg = "DMAC4_TX_POISON" },
+	{ .irq_msk = BIT(29), .msg = "DMAC5_TX_POISON" },
+	{ .irq_msk = BIT(30), .msg = "DMAC6_TX_POISON" },
+	{ .irq_msk = BIT(31), .msg = "DMAC7_TX_POISON" },
+};
+
+static const struct hisi_sas_hw_error sas_ras_intr1_nfe[] = {
+	{ .irq_msk = BIT(0), .msg = "RXM_CFG_MEM3_ECC2B_INTR" },
+	{ .irq_msk = BIT(1), .msg = "RXM_CFG_MEM2_ECC2B_INTR" },
+	{ .irq_msk = BIT(2), .msg = "RXM_CFG_MEM1_ECC2B_INTR" },
+	{ .irq_msk = BIT(3), .msg = "RXM_CFG_MEM0_ECC2B_INTR" },
+	{ .irq_msk = BIT(4), .msg = "HGC_CQE_ECC2B_INTR" },
+	{ .irq_msk = BIT(5), .msg = "LM_CFG_IOSTL_ECC2B_INTR" },
+	{ .irq_msk = BIT(6), .msg = "LM_CFG_ITCTL_ECC2B_INTR" },
+	{ .irq_msk = BIT(7), .msg = "HGC_ITCT_ECC2B_INTR" },
+	{ .irq_msk = BIT(8), .msg = "HGC_IOST_ECC2B_INTR" },
+	{ .irq_msk = BIT(9), .msg = "HGC_DQE_ECC2B_INTR" },
+	{ .irq_msk = BIT(10), .msg = "DMAC0_RAM_ECC2B_INTR" },
+	{ .irq_msk = BIT(11), .msg = "DMAC1_RAM_ECC2B_INTR" },
+	{ .irq_msk = BIT(12), .msg = "DMAC2_RAM_ECC2B_INTR" },
+	{ .irq_msk = BIT(13), .msg = "DMAC3_RAM_ECC2B_INTR" },
+	{ .irq_msk = BIT(14), .msg = "DMAC4_RAM_ECC2B_INTR" },
+	{ .irq_msk = BIT(15), .msg = "DMAC5_RAM_ECC2B_INTR" },
+	{ .irq_msk = BIT(16), .msg = "DMAC6_RAM_ECC2B_INTR" },
+	{ .irq_msk = BIT(17), .msg = "DMAC7_RAM_ECC2B_INTR" },
+	{ .irq_msk = BIT(18), .msg = "OOO_RAM_ECC2B_INTR" },
+	{ .irq_msk = BIT(20), .msg = "HGC_DQE_POISON_INTR" },
+	{ .irq_msk = BIT(21), .msg = "HGC_IOST_POISON_INTR" },
+	{ .irq_msk = BIT(22), .msg = "HGC_ITCT_POISON_INTR" },
+	{ .irq_msk = BIT(23), .msg = "HGC_ITCT_NCQ_POISON_INTR" },
+	{ .irq_msk = BIT(24), .msg = "DMAC0_RX_POISON" },
+	{ .irq_msk = BIT(25), .msg = "DMAC1_RX_POISON" },
+	{ .irq_msk = BIT(26), .msg = "DMAC2_RX_POISON" },
+	{ .irq_msk = BIT(27), .msg = "DMAC3_RX_POISON" },
+	{ .irq_msk = BIT(28), .msg = "DMAC4_RX_POISON" },
+	{ .irq_msk = BIT(29), .msg = "DMAC5_RX_POISON" },
+	{ .irq_msk = BIT(30), .msg = "DMAC6_RX_POISON" },
+	{ .irq_msk = BIT(31), .msg = "DMAC7_RX_POISON" },
+};
+
+static bool process_non_fatal_error_v3_hw(struct hisi_hba *hisi_hba)
+{
+	struct device *dev = hisi_hba->dev;
+	const struct hisi_sas_hw_error *ras_error;
+	bool need_reset = false;
+	u32 irq_value;
+	int i;
+
+	irq_value = hisi_sas_read32(hisi_hba, SAS_RAS_INTR0);
+	for (i = 0; i < ARRAY_SIZE(sas_ras_intr0_nfe); i++) {
+		ras_error = &sas_ras_intr0_nfe[i];
+		if (ras_error->irq_msk & irq_value) {
+			dev_warn(dev, "SAS_RAS_INTR0: %s(irq_value=0x%x) found.\n",
+					ras_error->msg, irq_value);
+			need_reset = true;
+		}
+	}
+	hisi_sas_write32(hisi_hba, SAS_RAS_INTR0, irq_value);
+
+	irq_value = hisi_sas_read32(hisi_hba, SAS_RAS_INTR1);
+	for (i = 0; i < ARRAY_SIZE(sas_ras_intr1_nfe); i++) {
+		ras_error = &sas_ras_intr1_nfe[i];
+		if (ras_error->irq_msk & irq_value) {
+			dev_warn(dev, "SAS_RAS_INTR1: %s(irq_value=0x%x) found.\n",
+					ras_error->msg, irq_value);
+			need_reset = true;
+		}
+	}
+	hisi_sas_write32(hisi_hba, SAS_RAS_INTR1, irq_value);
+
+	return need_reset;
+}
+
+static pci_ers_result_t hisi_sas_error_detected_v3_hw(struct pci_dev *pdev,
+		pci_channel_state_t state)
+{
+	struct sas_ha_struct *sha = pci_get_drvdata(pdev);
+	struct hisi_hba *hisi_hba = sha->lldd_ha;
+	struct device *dev = hisi_hba->dev;
+
+	dev_info(dev, "PCI error: detected callback, state(%d)!!\n", state);
+	if (state == pci_channel_io_perm_failure)
+		return PCI_ERS_RESULT_DISCONNECT;
+
+	if (process_non_fatal_error_v3_hw(hisi_hba))
+		return PCI_ERS_RESULT_NEED_RESET;
+
+	return PCI_ERS_RESULT_CAN_RECOVER;
+}
+
+static pci_ers_result_t hisi_sas_mmio_enabled_v3_hw(struct pci_dev *pdev)
+{
+	return PCI_ERS_RESULT_RECOVERED;
+}
+
+static pci_ers_result_t hisi_sas_slot_reset_v3_hw(struct pci_dev *pdev)
+{
+	struct sas_ha_struct *sha = pci_get_drvdata(pdev);
+	struct hisi_hba *hisi_hba = sha->lldd_ha;
+	struct device *dev = hisi_hba->dev;
+	HISI_SAS_DECLARE_RST_WORK_ON_STACK(r);
+
+	dev_info(dev, "PCI error: slot reset callback!!\n");
+	queue_work(hisi_hba->wq, &r.work);
+	wait_for_completion(r.completion);
+	if (r.done)
+		return PCI_ERS_RESULT_RECOVERED;
+
+	return PCI_ERS_RESULT_DISCONNECT;
+}
+
 enum {
 	/* instances of the controller */
 	hip08,
@@ -2139,11 +2271,18 @@ enum {
 	{}
 };
 
+static const struct pci_error_handlers hisi_sas_err_handler = {
+	.error_detected	= hisi_sas_error_detected_v3_hw,
+	.mmio_enabled	= hisi_sas_mmio_enabled_v3_hw,
+	.slot_reset	= hisi_sas_slot_reset_v3_hw,
+};
+
 static struct pci_driver sas_v3_pci_driver = {
 	.name		= DRV_NAME,
 	.id_table	= sas_v3_pci_table,
 	.probe		= hisi_sas_v3_probe,
 	.remove		= hisi_sas_v3_remove,
+	.err_handler	= &hisi_sas_err_handler,
 };
 
 module_pci_driver(sas_v3_pci_driver);
-- 
1.9.1

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

* [PATCH 10/19] scsi: hisi_sas: add some print to enhance debugging
  2017-12-08 17:16 ` John Garry
@ 2017-12-08 17:16   ` John Garry
  -1 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiang Chen, John Garry

From: Xiang Chen <chenxiang66@hisilicon.com>

Add some print at some places such as error info and cq
of exception IO, device found etc, and also adjust some
log levels.

All this to assist debugging ability.

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  | 15 ++++++++++-----
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 24 +++++++++++++++++++-----
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 22 +++++++++++++++++-----
 3 files changed, 46 insertions(+), 15 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index fb162c0..1f6f063 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -580,6 +580,9 @@ static int hisi_sas_dev_found(struct domain_device *device)
 		}
 	}
 
+	dev_info(dev, "dev[%d:%x] found\n",
+		sas_dev->device_id, sas_dev->dev_type);
+
 	return 0;
 }
 
@@ -735,7 +738,7 @@ static void hisi_sas_dev_gone(struct domain_device *device)
 	struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
 	struct device *dev = hisi_hba->dev;
 
-	dev_info(dev, "found dev[%d:%x] is gone\n",
+	dev_info(dev, "dev[%d:%x] is gone\n",
 		 sas_dev->device_id, sas_dev->dev_type);
 
 	if (!test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) {
@@ -866,12 +869,13 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
 			if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
 				struct hisi_sas_slot *slot = task->lldd_task;
 
-				dev_err(dev, "abort tmf: TMF task timeout\n");
+				dev_err(dev, "abort tmf: TMF task timeout and not done\n");
 				if (slot)
 					slot->task = NULL;
 
 				goto ex_err;
-			}
+			} else
+				dev_err(dev, "abort tmf: TMF task timeout\n");
 		}
 
 		if (task->task_status.resp == SAS_TASK_COMPLETE &&
@@ -1495,9 +1499,10 @@ static int hisi_sas_query_task(struct sas_task *task)
 
 			if (slot)
 				slot->task = NULL;
-			dev_err(dev, "internal task abort: timeout.\n");
+			dev_err(dev, "internal task abort: timeout and not done.\n");
 			goto exit;
-		}
+		} else
+			dev_err(dev, "internal task abort: timeout.\n");
 	}
 
 	if (task->task_status.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 cd9cd84..8d6886a 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -2361,6 +2361,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 	ts->resp = SAS_TASK_COMPLETE;
 
 	if (unlikely(aborted)) {
+		dev_dbg(dev, "slot_complete: task(%p) aborted\n", task);
 		ts->stat = SAS_ABORTED_TASK;
 		spin_lock_irqsave(&hisi_hba->lock, flags);
 		hisi_sas_slot_task_free(hisi_hba, task, slot);
@@ -2405,6 +2406,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 		(!(complete_hdr->dw0 & CMPLT_HDR_RSPNS_XFRD_MSK))) {
 		u32 err_phase = (complete_hdr->dw0 & CMPLT_HDR_ERR_PHASE_MSK)
 				>> CMPLT_HDR_ERR_PHASE_OFF;
+		u32 *error_info = hisi_sas_status_buf_addr_mem(slot);
 
 		/* Analyse error happens on which phase TX or RX */
 		if (ERR_ON_TX_PHASE(err_phase))
@@ -2412,6 +2414,16 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 		else if (ERR_ON_RX_PHASE(err_phase))
 			slot_err_v2_hw(hisi_hba, task, slot, 2);
 
+		if (ts->stat != SAS_DATA_UNDERRUN)
+			dev_info(dev, "erroneous completion iptt=%d task=%p "
+				"CQ hdr: 0x%x 0x%x 0x%x 0x%x "
+				"Error info: 0x%x 0x%x 0x%x 0x%x\n",
+				slot->idx, task,
+				complete_hdr->dw0, complete_hdr->dw1,
+				complete_hdr->act, complete_hdr->dw3,
+				error_info[0], error_info[1],
+				error_info[2], error_info[3]);
+
 		if (unlikely(slot->abort))
 			return ts->stat;
 		goto out;
@@ -2461,7 +2473,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 	}
 
 	if (!slot->port->port_attached) {
-		dev_err(dev, "slot complete: port %d has removed\n",
+		dev_warn(dev, "slot complete: port %d has removed\n",
 			slot->port->sas_port.id);
 		ts->stat = SAS_PHY_DOWN;
 	}
@@ -2718,10 +2730,12 @@ static int phy_down_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
 	u32 phy_state, sl_ctrl, txid_auto;
 	struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
 	struct hisi_sas_port *port = phy->port;
+	struct device *dev = hisi_hba->dev;
 
 	hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 1);
 
 	phy_state = hisi_sas_read32(hisi_hba, PHY_STATE);
+	dev_info(dev, "phydown: phy%d phy_state=0x%x\n", phy_no, phy_state);
 	hisi_sas_phy_down(hisi_hba, phy_no, (phy_state & 1 << phy_no) ? 1 : 0);
 
 	sl_ctrl = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL);
@@ -2911,7 +2925,7 @@ static void multi_bit_ecc_error_process_v2_hw(struct hisi_hba *hisi_hba,
 			val = hisi_sas_read32(hisi_hba, ecc_error->reg);
 			val &= ecc_error->msk;
 			val >>= ecc_error->shift;
-			dev_warn(dev, ecc_error->msg, irq_value, val);
+			dev_err(dev, ecc_error->msg, irq_value, val);
 			queue_work(hisi_hba->wq, &hisi_hba->rst_work);
 		}
 	}
@@ -3020,12 +3034,12 @@ static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p)
 			for (; sub->msk || sub->msg; sub++) {
 				if (!(err_value & sub->msk))
 					continue;
-				dev_warn(dev, "%s (0x%x) found!\n",
+				dev_err(dev, "%s (0x%x) found!\n",
 					 sub->msg, irq_value);
 				queue_work(hisi_hba->wq, &hisi_hba->rst_work);
 			}
 		} else {
-			dev_warn(dev, "%s (0x%x) found!\n",
+			dev_err(dev, "%s (0x%x) found!\n",
 				 axi_error->msg, irq_value);
 			queue_work(hisi_hba->wq, &hisi_hba->rst_work);
 		}
@@ -3397,7 +3411,7 @@ static int soft_reset_v2_hw(struct hisi_hba *hisi_hba)
 
 		udelay(10);
 		if (cnt++ > 10) {
-			dev_info(dev, "wait axi bus state to idle timeout!\n");
+			dev_err(dev, "wait axi bus state to idle timeout!\n");
 			return -1;
 		}
 	}
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index d356e12..67020bd 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -1149,7 +1149,7 @@ static int phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
 		struct dev_to_host_fis *fis;
 		u8 attached_sas_addr[SAS_ADDR_SIZE] = {0};
 
-		dev_info(dev, "phyup: phy%d link_rate=%d\n", phy_no, link_rate);
+		dev_info(dev, "phyup: phy%d link_rate=%d(sata)\n", phy_no, link_rate);
 		initial_fis = &hisi_hba->initial_fis[phy_no];
 		fis = &initial_fis->fis;
 		sas_phy->oob_mode = SATA_OOB_MODE;
@@ -1333,7 +1333,7 @@ static irqreturn_t int_chnl_int_v3_hw(int irq_no, void *p)
 				if (!(irq_value1 & error->irq_msk))
 					continue;
 
-				dev_warn(dev, "%s error (phy%d 0x%x) found!\n",
+				dev_err(dev, "%s error (phy%d 0x%x) found!\n",
 					error->msg, phy_no, irq_value1);
 				queue_work(hisi_hba->wq, &hisi_hba->rst_work);
 			}
@@ -1443,12 +1443,12 @@ static irqreturn_t fatal_axi_int_v3_hw(int irq_no, void *p)
 				if (!(err_value & sub->msk))
 					continue;
 
-				dev_warn(dev, "%s error (0x%x) found!\n",
+				dev_err(dev, "%s error (0x%x) found!\n",
 					sub->msg, irq_value);
 				queue_work(hisi_hba->wq, &hisi_hba->rst_work);
 			}
 		} else {
-			dev_warn(dev, "%s error (0x%x) found!\n",
+			dev_err(dev, "%s error (0x%x) found!\n",
 				error->msg, irq_value);
 			queue_work(hisi_hba->wq, &hisi_hba->rst_work);
 		}
@@ -1553,6 +1553,7 @@ static irqreturn_t fatal_axi_int_v3_hw(int irq_no, void *p)
 	memset(ts, 0, sizeof(*ts));
 	ts->resp = SAS_TASK_COMPLETE;
 	if (unlikely(aborted)) {
+		dev_dbg(dev, "slot complete: task(%p) aborted\n", task);
 		ts->stat = SAS_ABORTED_TASK;
 		spin_lock_irqsave(&hisi_hba->lock, flags);
 		hisi_sas_slot_task_free(hisi_hba, task, slot);
@@ -1594,7 +1595,18 @@ static irqreturn_t fatal_axi_int_v3_hw(int irq_no, void *p)
 
 	/* check for erroneous completion */
 	if ((complete_hdr->dw0 & CMPLT_HDR_CMPLT_MSK) == 0x3) {
+		u32 *error_info = hisi_sas_status_buf_addr_mem(slot);
+
 		slot_err_v3_hw(hisi_hba, task, slot);
+		if (ts->stat != SAS_DATA_UNDERRUN)
+			dev_info(dev, "erroneous completion iptt=%d task=%p "
+				"CQ hdr: 0x%x 0x%x 0x%x 0x%x "
+				"Error info: 0x%x 0x%x 0x%x 0x%x\n",
+				slot->idx, task,
+				complete_hdr->dw0, complete_hdr->dw1,
+				complete_hdr->act, complete_hdr->dw3,
+				error_info[0], error_info[1],
+				error_info[2], error_info[3]);
 		if (unlikely(slot->abort))
 			return ts->stat;
 		goto out;
@@ -1639,7 +1651,7 @@ static irqreturn_t fatal_axi_int_v3_hw(int irq_no, void *p)
 	}
 
 	if (!slot->port->port_attached) {
-		dev_err(dev, "slot complete: port %d has removed\n",
+		dev_warn(dev, "slot complete: port %d has removed\n",
 			slot->port->sas_port.id);
 		ts->stat = SAS_PHY_DOWN;
 	}
-- 
1.9.1

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

* [PATCH 10/19] scsi: hisi_sas: add some print to enhance debugging
@ 2017-12-08 17:16   ` John Garry
  0 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiang Chen, John Garry

From: Xiang Chen <chenxiang66@hisilicon.com>

Add some print at some places such as error info and cq
of exception IO, device found etc, and also adjust some
log levels.

All this to assist debugging ability.

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  | 15 ++++++++++-----
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 24 +++++++++++++++++++-----
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 22 +++++++++++++++++-----
 3 files changed, 46 insertions(+), 15 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index fb162c0..1f6f063 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -580,6 +580,9 @@ static int hisi_sas_dev_found(struct domain_device *device)
 		}
 	}
 
+	dev_info(dev, "dev[%d:%x] found\n",
+		sas_dev->device_id, sas_dev->dev_type);
+
 	return 0;
 }
 
@@ -735,7 +738,7 @@ static void hisi_sas_dev_gone(struct domain_device *device)
 	struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
 	struct device *dev = hisi_hba->dev;
 
-	dev_info(dev, "found dev[%d:%x] is gone\n",
+	dev_info(dev, "dev[%d:%x] is gone\n",
 		 sas_dev->device_id, sas_dev->dev_type);
 
 	if (!test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) {
@@ -866,12 +869,13 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
 			if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
 				struct hisi_sas_slot *slot = task->lldd_task;
 
-				dev_err(dev, "abort tmf: TMF task timeout\n");
+				dev_err(dev, "abort tmf: TMF task timeout and not done\n");
 				if (slot)
 					slot->task = NULL;
 
 				goto ex_err;
-			}
+			} else
+				dev_err(dev, "abort tmf: TMF task timeout\n");
 		}
 
 		if (task->task_status.resp == SAS_TASK_COMPLETE &&
@@ -1495,9 +1499,10 @@ static int hisi_sas_query_task(struct sas_task *task)
 
 			if (slot)
 				slot->task = NULL;
-			dev_err(dev, "internal task abort: timeout.\n");
+			dev_err(dev, "internal task abort: timeout and not done.\n");
 			goto exit;
-		}
+		} else
+			dev_err(dev, "internal task abort: timeout.\n");
 	}
 
 	if (task->task_status.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 cd9cd84..8d6886a 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -2361,6 +2361,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 	ts->resp = SAS_TASK_COMPLETE;
 
 	if (unlikely(aborted)) {
+		dev_dbg(dev, "slot_complete: task(%p) aborted\n", task);
 		ts->stat = SAS_ABORTED_TASK;
 		spin_lock_irqsave(&hisi_hba->lock, flags);
 		hisi_sas_slot_task_free(hisi_hba, task, slot);
@@ -2405,6 +2406,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 		(!(complete_hdr->dw0 & CMPLT_HDR_RSPNS_XFRD_MSK))) {
 		u32 err_phase = (complete_hdr->dw0 & CMPLT_HDR_ERR_PHASE_MSK)
 				>> CMPLT_HDR_ERR_PHASE_OFF;
+		u32 *error_info = hisi_sas_status_buf_addr_mem(slot);
 
 		/* Analyse error happens on which phase TX or RX */
 		if (ERR_ON_TX_PHASE(err_phase))
@@ -2412,6 +2414,16 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 		else if (ERR_ON_RX_PHASE(err_phase))
 			slot_err_v2_hw(hisi_hba, task, slot, 2);
 
+		if (ts->stat != SAS_DATA_UNDERRUN)
+			dev_info(dev, "erroneous completion iptt=%d task=%p "
+				"CQ hdr: 0x%x 0x%x 0x%x 0x%x "
+				"Error info: 0x%x 0x%x 0x%x 0x%x\n",
+				slot->idx, task,
+				complete_hdr->dw0, complete_hdr->dw1,
+				complete_hdr->act, complete_hdr->dw3,
+				error_info[0], error_info[1],
+				error_info[2], error_info[3]);
+
 		if (unlikely(slot->abort))
 			return ts->stat;
 		goto out;
@@ -2461,7 +2473,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 	}
 
 	if (!slot->port->port_attached) {
-		dev_err(dev, "slot complete: port %d has removed\n",
+		dev_warn(dev, "slot complete: port %d has removed\n",
 			slot->port->sas_port.id);
 		ts->stat = SAS_PHY_DOWN;
 	}
@@ -2718,10 +2730,12 @@ static int phy_down_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
 	u32 phy_state, sl_ctrl, txid_auto;
 	struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
 	struct hisi_sas_port *port = phy->port;
+	struct device *dev = hisi_hba->dev;
 
 	hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 1);
 
 	phy_state = hisi_sas_read32(hisi_hba, PHY_STATE);
+	dev_info(dev, "phydown: phy%d phy_state=0x%x\n", phy_no, phy_state);
 	hisi_sas_phy_down(hisi_hba, phy_no, (phy_state & 1 << phy_no) ? 1 : 0);
 
 	sl_ctrl = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL);
@@ -2911,7 +2925,7 @@ static void multi_bit_ecc_error_process_v2_hw(struct hisi_hba *hisi_hba,
 			val = hisi_sas_read32(hisi_hba, ecc_error->reg);
 			val &= ecc_error->msk;
 			val >>= ecc_error->shift;
-			dev_warn(dev, ecc_error->msg, irq_value, val);
+			dev_err(dev, ecc_error->msg, irq_value, val);
 			queue_work(hisi_hba->wq, &hisi_hba->rst_work);
 		}
 	}
@@ -3020,12 +3034,12 @@ static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p)
 			for (; sub->msk || sub->msg; sub++) {
 				if (!(err_value & sub->msk))
 					continue;
-				dev_warn(dev, "%s (0x%x) found!\n",
+				dev_err(dev, "%s (0x%x) found!\n",
 					 sub->msg, irq_value);
 				queue_work(hisi_hba->wq, &hisi_hba->rst_work);
 			}
 		} else {
-			dev_warn(dev, "%s (0x%x) found!\n",
+			dev_err(dev, "%s (0x%x) found!\n",
 				 axi_error->msg, irq_value);
 			queue_work(hisi_hba->wq, &hisi_hba->rst_work);
 		}
@@ -3397,7 +3411,7 @@ static int soft_reset_v2_hw(struct hisi_hba *hisi_hba)
 
 		udelay(10);
 		if (cnt++ > 10) {
-			dev_info(dev, "wait axi bus state to idle timeout!\n");
+			dev_err(dev, "wait axi bus state to idle timeout!\n");
 			return -1;
 		}
 	}
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index d356e12..67020bd 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -1149,7 +1149,7 @@ static int phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
 		struct dev_to_host_fis *fis;
 		u8 attached_sas_addr[SAS_ADDR_SIZE] = {0};
 
-		dev_info(dev, "phyup: phy%d link_rate=%d\n", phy_no, link_rate);
+		dev_info(dev, "phyup: phy%d link_rate=%d(sata)\n", phy_no, link_rate);
 		initial_fis = &hisi_hba->initial_fis[phy_no];
 		fis = &initial_fis->fis;
 		sas_phy->oob_mode = SATA_OOB_MODE;
@@ -1333,7 +1333,7 @@ static irqreturn_t int_chnl_int_v3_hw(int irq_no, void *p)
 				if (!(irq_value1 & error->irq_msk))
 					continue;
 
-				dev_warn(dev, "%s error (phy%d 0x%x) found!\n",
+				dev_err(dev, "%s error (phy%d 0x%x) found!\n",
 					error->msg, phy_no, irq_value1);
 				queue_work(hisi_hba->wq, &hisi_hba->rst_work);
 			}
@@ -1443,12 +1443,12 @@ static irqreturn_t fatal_axi_int_v3_hw(int irq_no, void *p)
 				if (!(err_value & sub->msk))
 					continue;
 
-				dev_warn(dev, "%s error (0x%x) found!\n",
+				dev_err(dev, "%s error (0x%x) found!\n",
 					sub->msg, irq_value);
 				queue_work(hisi_hba->wq, &hisi_hba->rst_work);
 			}
 		} else {
-			dev_warn(dev, "%s error (0x%x) found!\n",
+			dev_err(dev, "%s error (0x%x) found!\n",
 				error->msg, irq_value);
 			queue_work(hisi_hba->wq, &hisi_hba->rst_work);
 		}
@@ -1553,6 +1553,7 @@ static irqreturn_t fatal_axi_int_v3_hw(int irq_no, void *p)
 	memset(ts, 0, sizeof(*ts));
 	ts->resp = SAS_TASK_COMPLETE;
 	if (unlikely(aborted)) {
+		dev_dbg(dev, "slot complete: task(%p) aborted\n", task);
 		ts->stat = SAS_ABORTED_TASK;
 		spin_lock_irqsave(&hisi_hba->lock, flags);
 		hisi_sas_slot_task_free(hisi_hba, task, slot);
@@ -1594,7 +1595,18 @@ static irqreturn_t fatal_axi_int_v3_hw(int irq_no, void *p)
 
 	/* check for erroneous completion */
 	if ((complete_hdr->dw0 & CMPLT_HDR_CMPLT_MSK) == 0x3) {
+		u32 *error_info = hisi_sas_status_buf_addr_mem(slot);
+
 		slot_err_v3_hw(hisi_hba, task, slot);
+		if (ts->stat != SAS_DATA_UNDERRUN)
+			dev_info(dev, "erroneous completion iptt=%d task=%p "
+				"CQ hdr: 0x%x 0x%x 0x%x 0x%x "
+				"Error info: 0x%x 0x%x 0x%x 0x%x\n",
+				slot->idx, task,
+				complete_hdr->dw0, complete_hdr->dw1,
+				complete_hdr->act, complete_hdr->dw3,
+				error_info[0], error_info[1],
+				error_info[2], error_info[3]);
 		if (unlikely(slot->abort))
 			return ts->stat;
 		goto out;
@@ -1639,7 +1651,7 @@ static irqreturn_t fatal_axi_int_v3_hw(int irq_no, void *p)
 	}
 
 	if (!slot->port->port_attached) {
-		dev_err(dev, "slot complete: port %d has removed\n",
+		dev_warn(dev, "slot complete: port %d has removed\n",
 			slot->port->sas_port.id);
 		ts->stat = SAS_PHY_DOWN;
 	}
-- 
1.9.1

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

* [PATCH 11/19] scsi: hisi_sas: improve int_chnl_int_v2_hw() consistency with v3 hw
  2017-12-08 17:16 ` John Garry
@ 2017-12-08 17:16   ` John Garry
  -1 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiaofei Tan, John Garry

From: Xiaofei Tan <tanxiaofei@huawei.com>

Change code format of int_chnl_int_v2_hw() to be consistent with
v3 hw to reduce an tag indent.

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 | 58 ++++++++++++++++------------------
 1 file changed, 28 insertions(+), 30 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index 8d6886a..4c4a000 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -2848,40 +2848,38 @@ static irqreturn_t int_chnl_int_v2_hw(int irq_no, void *p)
 			HGC_INVLD_DQE_INFO_FB_CH3_OFF) & 0x1ff;
 
 	while (irq_msk) {
-		if (irq_msk & (1 << phy_no)) {
-			u32 irq_value0 = hisi_sas_phy_read32(hisi_hba, phy_no,
-							     CHL_INT0);
-			u32 irq_value1 = hisi_sas_phy_read32(hisi_hba, phy_no,
-							     CHL_INT1);
-			u32 irq_value2 = hisi_sas_phy_read32(hisi_hba, phy_no,
-							     CHL_INT2);
-
-			if (irq_value1) {
-				if (irq_value1 & (CHL_INT1_DMAC_RX_ECC_ERR_MSK |
-						  CHL_INT1_DMAC_TX_ECC_ERR_MSK))
-					panic("%s: DMAC RX/TX ecc bad error!\
-					       (0x%x)",
-					      dev_name(dev), irq_value1);
-
-				hisi_sas_phy_write32(hisi_hba, phy_no,
-						     CHL_INT1, irq_value1);
-			}
+		u32 irq_value0 = hisi_sas_phy_read32(hisi_hba, phy_no,
+						     CHL_INT0);
+		u32 irq_value1 = hisi_sas_phy_read32(hisi_hba, phy_no,
+						     CHL_INT1);
+		u32 irq_value2 = hisi_sas_phy_read32(hisi_hba, phy_no,
+						     CHL_INT2);
+
+		if ((irq_msk & (1 << phy_no)) && irq_value1) {
+			if (irq_value1 & (CHL_INT1_DMAC_RX_ECC_ERR_MSK |
+					  CHL_INT1_DMAC_TX_ECC_ERR_MSK))
+				panic("%s: DMAC RX/TX ecc bad error!\
+				       (0x%x)",
+				      dev_name(dev), irq_value1);
 
-			if (irq_value2)
-				hisi_sas_phy_write32(hisi_hba, phy_no,
-						     CHL_INT2, irq_value2);
+			hisi_sas_phy_write32(hisi_hba, phy_no,
+					     CHL_INT1, irq_value1);
+		}
 
+		if ((irq_msk & (1 << phy_no)) && irq_value2)
+			hisi_sas_phy_write32(hisi_hba, phy_no,
+					     CHL_INT2, irq_value2);
 
-			if (irq_value0) {
-				if (irq_value0 & CHL_INT0_SL_RX_BCST_ACK_MSK)
-					phy_bcast_v2_hw(phy_no, hisi_hba);
 
-				hisi_sas_phy_write32(hisi_hba, phy_no,
-						CHL_INT0, irq_value0
-						& (~CHL_INT0_HOTPLUG_TOUT_MSK)
-						& (~CHL_INT0_SL_PHY_ENABLE_MSK)
-						& (~CHL_INT0_NOT_RDY_MSK));
-			}
+		if ((irq_msk & (1 << phy_no)) && irq_value0) {
+			if (irq_value0 & CHL_INT0_SL_RX_BCST_ACK_MSK)
+				phy_bcast_v2_hw(phy_no, hisi_hba);
+
+			hisi_sas_phy_write32(hisi_hba, phy_no,
+					CHL_INT0, irq_value0
+					& (~CHL_INT0_HOTPLUG_TOUT_MSK)
+					& (~CHL_INT0_SL_PHY_ENABLE_MSK)
+					& (~CHL_INT0_NOT_RDY_MSK));
 		}
 		irq_msk &= ~(1 << phy_no);
 		phy_no++;
-- 
1.9.1

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

* [PATCH 11/19] scsi: hisi_sas: improve int_chnl_int_v2_hw() consistency with v3 hw
@ 2017-12-08 17:16   ` John Garry
  0 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiaofei Tan, John Garry

From: Xiaofei Tan <tanxiaofei@huawei.com>

Change code format of int_chnl_int_v2_hw() to be consistent with
v3 hw to reduce an tag indent.

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 | 58 ++++++++++++++++------------------
 1 file changed, 28 insertions(+), 30 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index 8d6886a..4c4a000 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -2848,40 +2848,38 @@ static irqreturn_t int_chnl_int_v2_hw(int irq_no, void *p)
 			HGC_INVLD_DQE_INFO_FB_CH3_OFF) & 0x1ff;
 
 	while (irq_msk) {
-		if (irq_msk & (1 << phy_no)) {
-			u32 irq_value0 = hisi_sas_phy_read32(hisi_hba, phy_no,
-							     CHL_INT0);
-			u32 irq_value1 = hisi_sas_phy_read32(hisi_hba, phy_no,
-							     CHL_INT1);
-			u32 irq_value2 = hisi_sas_phy_read32(hisi_hba, phy_no,
-							     CHL_INT2);
-
-			if (irq_value1) {
-				if (irq_value1 & (CHL_INT1_DMAC_RX_ECC_ERR_MSK |
-						  CHL_INT1_DMAC_TX_ECC_ERR_MSK))
-					panic("%s: DMAC RX/TX ecc bad error!\
-					       (0x%x)",
-					      dev_name(dev), irq_value1);
-
-				hisi_sas_phy_write32(hisi_hba, phy_no,
-						     CHL_INT1, irq_value1);
-			}
+		u32 irq_value0 = hisi_sas_phy_read32(hisi_hba, phy_no,
+						     CHL_INT0);
+		u32 irq_value1 = hisi_sas_phy_read32(hisi_hba, phy_no,
+						     CHL_INT1);
+		u32 irq_value2 = hisi_sas_phy_read32(hisi_hba, phy_no,
+						     CHL_INT2);
+
+		if ((irq_msk & (1 << phy_no)) && irq_value1) {
+			if (irq_value1 & (CHL_INT1_DMAC_RX_ECC_ERR_MSK |
+					  CHL_INT1_DMAC_TX_ECC_ERR_MSK))
+				panic("%s: DMAC RX/TX ecc bad error!\
+				       (0x%x)",
+				      dev_name(dev), irq_value1);
 
-			if (irq_value2)
-				hisi_sas_phy_write32(hisi_hba, phy_no,
-						     CHL_INT2, irq_value2);
+			hisi_sas_phy_write32(hisi_hba, phy_no,
+					     CHL_INT1, irq_value1);
+		}
 
+		if ((irq_msk & (1 << phy_no)) && irq_value2)
+			hisi_sas_phy_write32(hisi_hba, phy_no,
+					     CHL_INT2, irq_value2);
 
-			if (irq_value0) {
-				if (irq_value0 & CHL_INT0_SL_RX_BCST_ACK_MSK)
-					phy_bcast_v2_hw(phy_no, hisi_hba);
 
-				hisi_sas_phy_write32(hisi_hba, phy_no,
-						CHL_INT0, irq_value0
-						& (~CHL_INT0_HOTPLUG_TOUT_MSK)
-						& (~CHL_INT0_SL_PHY_ENABLE_MSK)
-						& (~CHL_INT0_NOT_RDY_MSK));
-			}
+		if ((irq_msk & (1 << phy_no)) && irq_value0) {
+			if (irq_value0 & CHL_INT0_SL_RX_BCST_ACK_MSK)
+				phy_bcast_v2_hw(phy_no, hisi_hba);
+
+			hisi_sas_phy_write32(hisi_hba, phy_no,
+					CHL_INT0, irq_value0
+					& (~CHL_INT0_HOTPLUG_TOUT_MSK)
+					& (~CHL_INT0_SL_PHY_ENABLE_MSK)
+					& (~CHL_INT0_NOT_RDY_MSK));
 		}
 		irq_msk &= ~(1 << phy_no);
 		phy_no++;
-- 
1.9.1

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

* [PATCH 12/19] scsi: hisi_sas: add v2 hw port AXI error handling support
  2017-12-08 17:16 ` John Garry
@ 2017-12-08 17:16   ` John Garry
  -1 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiaofei Tan, John Garry

From: Xiaofei Tan <tanxiaofei@huawei.com>

Add port AXI errors handling for v2 hw. We do host controller
reset for such errors.

Besides, change port muli-bits ECC error handling, and we
should also do host reset for such error. So, this patch put
them in the same struct with port AXI error.

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 | 51 ++++++++++++++++++++++++++++++----
 1 file changed, 45 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 4c4a000..7257311 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -240,6 +240,10 @@
 #define CHL_INT1_DMAC_TX_ECC_ERR_MSK	(0x1 << CHL_INT1_DMAC_TX_ECC_ERR_OFF)
 #define CHL_INT1_DMAC_RX_ECC_ERR_OFF	17
 #define CHL_INT1_DMAC_RX_ECC_ERR_MSK	(0x1 << CHL_INT1_DMAC_RX_ECC_ERR_OFF)
+#define CHL_INT1_DMAC_TX_AXI_WR_ERR_OFF	19
+#define CHL_INT1_DMAC_TX_AXI_RD_ERR_OFF	20
+#define CHL_INT1_DMAC_RX_AXI_WR_ERR_OFF	21
+#define CHL_INT1_DMAC_RX_AXI_RD_ERR_OFF	22
 #define CHL_INT2			(PORT_BASE + 0x1bc)
 #define CHL_INT0_MSK			(PORT_BASE + 0x1c0)
 #define CHL_INT1_MSK			(PORT_BASE + 0x1c4)
@@ -1182,7 +1186,7 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
 		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_INT1_MSK, 0xff857fff);
 		hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8ffffbff);
 		hisi_sas_phy_write32(hisi_hba, i, SL_CFG, 0x13f801fc);
 		hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL_RDY_MSK, 0x0);
@@ -2832,6 +2836,33 @@ static void phy_bcast_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
 	hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 0);
 }
 
+static const struct hisi_sas_hw_error port_ecc_axi_error[] = {
+	{
+		.irq_msk = BIT(CHL_INT1_DMAC_TX_ECC_ERR_OFF),
+		.msg = "dmac_tx_ecc_bad_err",
+	},
+	{
+		.irq_msk = BIT(CHL_INT1_DMAC_RX_ECC_ERR_OFF),
+		.msg = "dmac_rx_ecc_bad_err",
+	},
+	{
+		.irq_msk = BIT(CHL_INT1_DMAC_TX_AXI_WR_ERR_OFF),
+		.msg = "dma_tx_axi_wr_err",
+	},
+	{
+		.irq_msk = BIT(CHL_INT1_DMAC_TX_AXI_RD_ERR_OFF),
+		.msg = "dma_tx_axi_rd_err",
+	},
+	{
+		.irq_msk = BIT(CHL_INT1_DMAC_RX_AXI_WR_ERR_OFF),
+		.msg = "dma_rx_axi_wr_err",
+	},
+	{
+		.irq_msk = BIT(CHL_INT1_DMAC_RX_AXI_RD_ERR_OFF),
+		.msg = "dma_rx_axi_rd_err",
+	},
+};
+
 static irqreturn_t int_chnl_int_v2_hw(int irq_no, void *p)
 {
 	struct hisi_hba *hisi_hba = p;
@@ -2856,11 +2887,19 @@ static irqreturn_t int_chnl_int_v2_hw(int irq_no, void *p)
 						     CHL_INT2);
 
 		if ((irq_msk & (1 << phy_no)) && irq_value1) {
-			if (irq_value1 & (CHL_INT1_DMAC_RX_ECC_ERR_MSK |
-					  CHL_INT1_DMAC_TX_ECC_ERR_MSK))
-				panic("%s: DMAC RX/TX ecc bad error!\
-				       (0x%x)",
-				      dev_name(dev), irq_value1);
+			int i;
+
+			for (i = 0; i < ARRAY_SIZE(port_ecc_axi_error); i++) {
+				const struct hisi_sas_hw_error *error =
+						&port_ecc_axi_error[i];
+
+				if (!(irq_value1 & error->irq_msk))
+					continue;
+
+				dev_warn(dev, "%s error (phy%d 0x%x) found!\n",
+					error->msg, phy_no, irq_value1);
+				queue_work(hisi_hba->wq, &hisi_hba->rst_work);
+			}
 
 			hisi_sas_phy_write32(hisi_hba, phy_no,
 					     CHL_INT1, irq_value1);
-- 
1.9.1

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

* [PATCH 12/19] scsi: hisi_sas: add v2 hw port AXI error handling support
@ 2017-12-08 17:16   ` John Garry
  0 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiaofei Tan, John Garry

From: Xiaofei Tan <tanxiaofei@huawei.com>

Add port AXI errors handling for v2 hw. We do host controller
reset for such errors.

Besides, change port muli-bits ECC error handling, and we
should also do host reset for such error. So, this patch put
them in the same struct with port AXI error.

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 | 51 ++++++++++++++++++++++++++++++----
 1 file changed, 45 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 4c4a000..7257311 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -240,6 +240,10 @@
 #define CHL_INT1_DMAC_TX_ECC_ERR_MSK	(0x1 << CHL_INT1_DMAC_TX_ECC_ERR_OFF)
 #define CHL_INT1_DMAC_RX_ECC_ERR_OFF	17
 #define CHL_INT1_DMAC_RX_ECC_ERR_MSK	(0x1 << CHL_INT1_DMAC_RX_ECC_ERR_OFF)
+#define CHL_INT1_DMAC_TX_AXI_WR_ERR_OFF	19
+#define CHL_INT1_DMAC_TX_AXI_RD_ERR_OFF	20
+#define CHL_INT1_DMAC_RX_AXI_WR_ERR_OFF	21
+#define CHL_INT1_DMAC_RX_AXI_RD_ERR_OFF	22
 #define CHL_INT2			(PORT_BASE + 0x1bc)
 #define CHL_INT0_MSK			(PORT_BASE + 0x1c0)
 #define CHL_INT1_MSK			(PORT_BASE + 0x1c4)
@@ -1182,7 +1186,7 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
 		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_INT1_MSK, 0xff857fff);
 		hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8ffffbff);
 		hisi_sas_phy_write32(hisi_hba, i, SL_CFG, 0x13f801fc);
 		hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL_RDY_MSK, 0x0);
@@ -2832,6 +2836,33 @@ static void phy_bcast_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
 	hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 0);
 }
 
+static const struct hisi_sas_hw_error port_ecc_axi_error[] = {
+	{
+		.irq_msk = BIT(CHL_INT1_DMAC_TX_ECC_ERR_OFF),
+		.msg = "dmac_tx_ecc_bad_err",
+	},
+	{
+		.irq_msk = BIT(CHL_INT1_DMAC_RX_ECC_ERR_OFF),
+		.msg = "dmac_rx_ecc_bad_err",
+	},
+	{
+		.irq_msk = BIT(CHL_INT1_DMAC_TX_AXI_WR_ERR_OFF),
+		.msg = "dma_tx_axi_wr_err",
+	},
+	{
+		.irq_msk = BIT(CHL_INT1_DMAC_TX_AXI_RD_ERR_OFF),
+		.msg = "dma_tx_axi_rd_err",
+	},
+	{
+		.irq_msk = BIT(CHL_INT1_DMAC_RX_AXI_WR_ERR_OFF),
+		.msg = "dma_rx_axi_wr_err",
+	},
+	{
+		.irq_msk = BIT(CHL_INT1_DMAC_RX_AXI_RD_ERR_OFF),
+		.msg = "dma_rx_axi_rd_err",
+	},
+};
+
 static irqreturn_t int_chnl_int_v2_hw(int irq_no, void *p)
 {
 	struct hisi_hba *hisi_hba = p;
@@ -2856,11 +2887,19 @@ static irqreturn_t int_chnl_int_v2_hw(int irq_no, void *p)
 						     CHL_INT2);
 
 		if ((irq_msk & (1 << phy_no)) && irq_value1) {
-			if (irq_value1 & (CHL_INT1_DMAC_RX_ECC_ERR_MSK |
-					  CHL_INT1_DMAC_TX_ECC_ERR_MSK))
-				panic("%s: DMAC RX/TX ecc bad error!\
-				       (0x%x)",
-				      dev_name(dev), irq_value1);
+			int i;
+
+			for (i = 0; i < ARRAY_SIZE(port_ecc_axi_error); i++) {
+				const struct hisi_sas_hw_error *error =
+						&port_ecc_axi_error[i];
+
+				if (!(irq_value1 & error->irq_msk))
+					continue;
+
+				dev_warn(dev, "%s error (phy%d 0x%x) found!\n",
+					error->msg, phy_no, irq_value1);
+				queue_work(hisi_hba->wq, &hisi_hba->rst_work);
+			}
 
 			hisi_sas_phy_write32(hisi_hba, phy_no,
 					     CHL_INT1, irq_value1);
-- 
1.9.1

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

* [PATCH 13/19] scsi: hisi_sas: use an general way to delay PHY work
  2017-12-08 17:16 ` John Garry
@ 2017-12-08 17:16   ` John Garry
  -1 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiaofei Tan, John Garry

From: Xiaofei Tan <tanxiaofei@huawei.com>

Use an general way to do delay work for a PHY. Then it will
be easier to add new delayed work for a PHY in future.

Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas.h       |  9 ++++++++-
 drivers/scsi/hisi_sas/hisi_sas_main.c  | 22 ++++++++++++++++++++--
 drivers/scsi/hisi_sas/hisi_sas_v1_hw.c |  2 +-
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c |  4 ++--
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c |  2 +-
 5 files changed, 32 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index 71bc8ea..aa14638 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -124,12 +124,17 @@ enum hisi_sas_bit_err_type {
 	HISI_SAS_ERR_MULTI_BIT_ECC = 0x1,
 };
 
+enum hisi_sas_phy_event {
+	HISI_PHYE_PHY_UP   = 0U,
+	HISI_PHYES_NUM,
+};
+
 struct hisi_sas_phy {
+	struct work_struct	works[HISI_PHYES_NUM];
 	struct hisi_hba	*hisi_hba;
 	struct hisi_sas_port	*port;
 	struct asd_sas_phy	sas_phy;
 	struct sas_identify	identify;
-	struct work_struct	phyup_ws;
 	u64		port_id; /* from hw */
 	u64		dev_sas_addr;
 	u64		frame_rcvd_size;
@@ -453,4 +458,6 @@ extern void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba,
 extern void hisi_sas_rst_work_handler(struct work_struct *work);
 extern void hisi_sas_sync_rst_work_handler(struct work_struct *work);
 extern void hisi_sas_kill_tasklets(struct hisi_hba *hisi_hba);
+extern bool hisi_sas_notify_phy_event(struct hisi_sas_phy *phy,
+				enum hisi_sas_phy_event event);
 #endif
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 1f6f063..326dc81 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -622,7 +622,7 @@ static int hisi_sas_scan_finished(struct Scsi_Host *shost, unsigned long time)
 static void hisi_sas_phyup_work(struct work_struct *work)
 {
 	struct hisi_sas_phy *phy =
-		container_of(work, struct hisi_sas_phy, phyup_ws);
+		container_of(work, typeof(*phy), works[HISI_PHYE_PHY_UP]);
 	struct hisi_hba *hisi_hba = phy->hisi_hba;
 	struct asd_sas_phy *sas_phy = &phy->sas_phy;
 	int phy_no = sas_phy->id;
@@ -631,10 +631,27 @@ static void hisi_sas_phyup_work(struct work_struct *work)
 	hisi_sas_bytes_dmaed(hisi_hba, phy_no);
 }
 
+static const work_func_t hisi_sas_phye_fns[HISI_PHYES_NUM] = {
+	[HISI_PHYE_PHY_UP] = hisi_sas_phyup_work,
+};
+
+bool hisi_sas_notify_phy_event(struct hisi_sas_phy *phy,
+				enum hisi_sas_phy_event event)
+{
+	struct hisi_hba *hisi_hba = phy->hisi_hba;
+
+	if (WARN_ON(event >= HISI_PHYES_NUM))
+		return false;
+
+	return queue_work(hisi_hba->wq, &phy->works[event]);
+}
+EXPORT_SYMBOL_GPL(hisi_sas_notify_phy_event);
+
 static void hisi_sas_phy_init(struct hisi_hba *hisi_hba, int phy_no)
 {
 	struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
 	struct asd_sas_phy *sas_phy = &phy->sas_phy;
+	int i;
 
 	phy->hisi_hba = hisi_hba;
 	phy->port = NULL;
@@ -652,7 +669,8 @@ static void hisi_sas_phy_init(struct hisi_hba *hisi_hba, int phy_no)
 	sas_phy->ha = (struct sas_ha_struct *)hisi_hba->shost->hostdata;
 	sas_phy->lldd_phy = phy;
 
-	INIT_WORK(&phy->phyup_ws, hisi_sas_phyup_work);
+	for (i = 0; i < HISI_PHYES_NUM; i++)
+		INIT_WORK(&phy->works[i], hisi_sas_phye_fns[i]);
 }
 
 static void hisi_sas_port_notify_formed(struct asd_sas_phy *sas_phy)
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
index 8cb9061..679e76f 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
@@ -1482,7 +1482,7 @@ static irqreturn_t int_phyup_v1_hw(int irq_no, void *p)
 	else if (phy->identify.device_type != SAS_PHY_UNUSED)
 		phy->identify.target_port_protocols =
 			SAS_PROTOCOL_SMP;
-	queue_work(hisi_hba->wq, &phy->phyup_ws);
+	hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP);
 
 end:
 	hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2,
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index 7257311..e521c42 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -2708,7 +2708,7 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
 		if (!timer_pending(&hisi_hba->timer))
 			set_link_timer_quirk(hisi_hba);
 	}
-	queue_work(hisi_hba->wq, &phy->phyup_ws);
+	hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP);
 
 end:
 	hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0,
@@ -3262,7 +3262,7 @@ static irqreturn_t sata_int_v2_hw(int irq_no, void *p)
 	phy->identify.device_type = SAS_SATA_DEV;
 	phy->frame_rcvd_size = sizeof(struct dev_to_host_fis);
 	phy->identify.target_port_protocols = SAS_PROTOCOL_SATA;
-	queue_work(hisi_hba->wq, &phy->phyup_ws);
+	hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP);
 
 end:
 	hisi_sas_write32(hisi_hba, ENT_INT_SRC1 + offset, ent_tmp);
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 67020bd..4b7f251 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -1192,7 +1192,7 @@ static int phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
 
 	phy->port_id = port_id;
 	phy->phy_attached = 1;
-	queue_work(hisi_hba->wq, &phy->phyup_ws);
+	hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP);
 
 end:
 	hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0,
-- 
1.9.1

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

* [PATCH 13/19] scsi: hisi_sas: use an general way to delay PHY work
@ 2017-12-08 17:16   ` John Garry
  0 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiaofei Tan, John Garry

From: Xiaofei Tan <tanxiaofei@huawei.com>

Use an general way to do delay work for a PHY. Then it will
be easier to add new delayed work for a PHY in future.

Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas.h       |  9 ++++++++-
 drivers/scsi/hisi_sas/hisi_sas_main.c  | 22 ++++++++++++++++++++--
 drivers/scsi/hisi_sas/hisi_sas_v1_hw.c |  2 +-
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c |  4 ++--
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c |  2 +-
 5 files changed, 32 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index 71bc8ea..aa14638 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -124,12 +124,17 @@ enum hisi_sas_bit_err_type {
 	HISI_SAS_ERR_MULTI_BIT_ECC = 0x1,
 };
 
+enum hisi_sas_phy_event {
+	HISI_PHYE_PHY_UP   = 0U,
+	HISI_PHYES_NUM,
+};
+
 struct hisi_sas_phy {
+	struct work_struct	works[HISI_PHYES_NUM];
 	struct hisi_hba	*hisi_hba;
 	struct hisi_sas_port	*port;
 	struct asd_sas_phy	sas_phy;
 	struct sas_identify	identify;
-	struct work_struct	phyup_ws;
 	u64		port_id; /* from hw */
 	u64		dev_sas_addr;
 	u64		frame_rcvd_size;
@@ -453,4 +458,6 @@ extern void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba,
 extern void hisi_sas_rst_work_handler(struct work_struct *work);
 extern void hisi_sas_sync_rst_work_handler(struct work_struct *work);
 extern void hisi_sas_kill_tasklets(struct hisi_hba *hisi_hba);
+extern bool hisi_sas_notify_phy_event(struct hisi_sas_phy *phy,
+				enum hisi_sas_phy_event event);
 #endif
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 1f6f063..326dc81 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -622,7 +622,7 @@ static int hisi_sas_scan_finished(struct Scsi_Host *shost, unsigned long time)
 static void hisi_sas_phyup_work(struct work_struct *work)
 {
 	struct hisi_sas_phy *phy =
-		container_of(work, struct hisi_sas_phy, phyup_ws);
+		container_of(work, typeof(*phy), works[HISI_PHYE_PHY_UP]);
 	struct hisi_hba *hisi_hba = phy->hisi_hba;
 	struct asd_sas_phy *sas_phy = &phy->sas_phy;
 	int phy_no = sas_phy->id;
@@ -631,10 +631,27 @@ static void hisi_sas_phyup_work(struct work_struct *work)
 	hisi_sas_bytes_dmaed(hisi_hba, phy_no);
 }
 
+static const work_func_t hisi_sas_phye_fns[HISI_PHYES_NUM] = {
+	[HISI_PHYE_PHY_UP] = hisi_sas_phyup_work,
+};
+
+bool hisi_sas_notify_phy_event(struct hisi_sas_phy *phy,
+				enum hisi_sas_phy_event event)
+{
+	struct hisi_hba *hisi_hba = phy->hisi_hba;
+
+	if (WARN_ON(event >= HISI_PHYES_NUM))
+		return false;
+
+	return queue_work(hisi_hba->wq, &phy->works[event]);
+}
+EXPORT_SYMBOL_GPL(hisi_sas_notify_phy_event);
+
 static void hisi_sas_phy_init(struct hisi_hba *hisi_hba, int phy_no)
 {
 	struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
 	struct asd_sas_phy *sas_phy = &phy->sas_phy;
+	int i;
 
 	phy->hisi_hba = hisi_hba;
 	phy->port = NULL;
@@ -652,7 +669,8 @@ static void hisi_sas_phy_init(struct hisi_hba *hisi_hba, int phy_no)
 	sas_phy->ha = (struct sas_ha_struct *)hisi_hba->shost->hostdata;
 	sas_phy->lldd_phy = phy;
 
-	INIT_WORK(&phy->phyup_ws, hisi_sas_phyup_work);
+	for (i = 0; i < HISI_PHYES_NUM; i++)
+		INIT_WORK(&phy->works[i], hisi_sas_phye_fns[i]);
 }
 
 static void hisi_sas_port_notify_formed(struct asd_sas_phy *sas_phy)
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
index 8cb9061..679e76f 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
@@ -1482,7 +1482,7 @@ static irqreturn_t int_phyup_v1_hw(int irq_no, void *p)
 	else if (phy->identify.device_type != SAS_PHY_UNUSED)
 		phy->identify.target_port_protocols =
 			SAS_PROTOCOL_SMP;
-	queue_work(hisi_hba->wq, &phy->phyup_ws);
+	hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP);
 
 end:
 	hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2,
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index 7257311..e521c42 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -2708,7 +2708,7 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
 		if (!timer_pending(&hisi_hba->timer))
 			set_link_timer_quirk(hisi_hba);
 	}
-	queue_work(hisi_hba->wq, &phy->phyup_ws);
+	hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP);
 
 end:
 	hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0,
@@ -3262,7 +3262,7 @@ static irqreturn_t sata_int_v2_hw(int irq_no, void *p)
 	phy->identify.device_type = SAS_SATA_DEV;
 	phy->frame_rcvd_size = sizeof(struct dev_to_host_fis);
 	phy->identify.target_port_protocols = SAS_PROTOCOL_SATA;
-	queue_work(hisi_hba->wq, &phy->phyup_ws);
+	hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP);
 
 end:
 	hisi_sas_write32(hisi_hba, ENT_INT_SRC1 + offset, ent_tmp);
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 67020bd..4b7f251 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -1192,7 +1192,7 @@ static int phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
 
 	phy->port_id = port_id;
 	phy->phy_attached = 1;
-	queue_work(hisi_hba->wq, &phy->phyup_ws);
+	hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP);
 
 end:
 	hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0,
-- 
1.9.1

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

* [PATCH 14/19] scsi: hisi_sas: do link reset for some CHL_INT2 ints
  2017-12-08 17:16 ` John Garry
@ 2017-12-08 17:16   ` John Garry
  -1 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiaofei Tan, John Garry

From: Xiaofei Tan <tanxiaofei@huawei.com>

We should do link reset of PHY when identify timeout or
STP link timeout. They are internal events of SOC and are
notified to driver through interrupts of CHL_INT2.

Besides, we should add an delay work to do link reset as
it needs sleep. So, this patch add an new PHY event
HISI_PHYE_LINK_RESET for this.

Notes: v2 HW doesn't report the event of STP link timeout.
So, we only need to handle event of identify timeout for v2 HW.

Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas.h       |  1 +
 drivers/scsi/hisi_sas/hisi_sas_main.c  | 12 ++++++++++++
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 18 ++++++++++++++----
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 29 +++++++++++++++++++++++++++--
 4 files changed, 54 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index aa14638..4343c4c 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -126,6 +126,7 @@ enum hisi_sas_bit_err_type {
 
 enum hisi_sas_phy_event {
 	HISI_PHYE_PHY_UP   = 0U,
+	HISI_PHYE_LINK_RESET,
 	HISI_PHYES_NUM,
 };
 
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 326dc81..7446a39 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -22,6 +22,8 @@ static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device,
 			     struct domain_device *device,
 			     int abort_flag, int tag);
 static int hisi_sas_softreset_ata_disk(struct domain_device *device);
+static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func,
+				void *funcdata);
 
 u8 hisi_sas_get_ata_protocol(u8 cmd, int direction)
 {
@@ -631,8 +633,18 @@ static void hisi_sas_phyup_work(struct work_struct *work)
 	hisi_sas_bytes_dmaed(hisi_hba, phy_no);
 }
 
+static void hisi_sas_linkreset_work(struct work_struct *work)
+{
+	struct hisi_sas_phy *phy =
+		container_of(work, typeof(*phy), works[HISI_PHYE_LINK_RESET]);
+	struct asd_sas_phy *sas_phy = &phy->sas_phy;
+
+	hisi_sas_control_phy(sas_phy, PHY_FUNC_LINK_RESET, NULL);
+}
+
 static const work_func_t hisi_sas_phye_fns[HISI_PHYES_NUM] = {
 	[HISI_PHYE_PHY_UP] = hisi_sas_phyup_work,
+	[HISI_PHYE_LINK_RESET] = hisi_sas_linkreset_work,
 };
 
 bool hisi_sas_notify_phy_event(struct hisi_sas_phy *phy,
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index e521c42..b8fe08d 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -245,6 +245,7 @@
 #define CHL_INT1_DMAC_RX_AXI_WR_ERR_OFF	21
 #define CHL_INT1_DMAC_RX_AXI_RD_ERR_OFF	22
 #define CHL_INT2			(PORT_BASE + 0x1bc)
+#define CHL_INT2_SL_IDAF_TOUT_CONF_OFF	0
 #define CHL_INT0_MSK			(PORT_BASE + 0x1c0)
 #define CHL_INT1_MSK			(PORT_BASE + 0x1c4)
 #define CHL_INT2_MSK			(PORT_BASE + 0x1c8)
@@ -1187,7 +1188,7 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
 		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, 0xff857fff);
-		hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8ffffbff);
+		hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8ffffbfe);
 		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);
@@ -2905,10 +2906,19 @@ static irqreturn_t int_chnl_int_v2_hw(int irq_no, void *p)
 					     CHL_INT1, irq_value1);
 		}
 
-		if ((irq_msk & (1 << phy_no)) && irq_value2)
-			hisi_sas_phy_write32(hisi_hba, phy_no,
-					     CHL_INT2, irq_value2);
+		if ((irq_msk & (1 << phy_no)) && irq_value2) {
+			struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+
+			if (irq_value2 & BIT(CHL_INT2_SL_IDAF_TOUT_CONF_OFF)) {
+				dev_warn(dev, "phy%d identify timeout\n",
+						phy_no);
+				hisi_sas_notify_phy_event(phy,
+						HISI_PHYE_LINK_RESET);
+			}
 
+			hisi_sas_phy_write32(hisi_hba, phy_no,
+						 CHL_INT2, irq_value2);
+		}
 
 		if ((irq_msk & (1 << phy_no)) && irq_value0) {
 			if (irq_value0 & CHL_INT0_SL_RX_BCST_ACK_MSK)
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 4b7f251..9e32105 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -140,6 +140,7 @@
 #define RX_IDAF_DWORD0			(PORT_BASE + 0xc4)
 #define RXOP_CHECK_CFG_H		(PORT_BASE + 0xfc)
 #define STP_LINK_TIMER			(PORT_BASE + 0x120)
+#define STP_LINK_TIMEOUT_STATE		(PORT_BASE + 0x124)
 #define CON_CFG_DRIVER			(PORT_BASE + 0x130)
 #define SAS_SSP_CON_TIMER_CFG		(PORT_BASE + 0x134)
 #define SAS_SMP_CON_TIMER_CFG		(PORT_BASE + 0x138)
@@ -165,6 +166,8 @@
 #define CHL_INT1_DMAC_RX_AXI_WR_ERR_OFF	21
 #define CHL_INT1_DMAC_RX_AXI_RD_ERR_OFF	22
 #define CHL_INT2			(PORT_BASE + 0x1bc)
+#define CHL_INT2_SL_IDAF_TOUT_CONF_OFF	0
+#define CHL_INT2_STP_LINK_TIMEOUT_OFF	31
 #define CHL_INT0_MSK			(PORT_BASE + 0x1c0)
 #define CHL_INT1_MSK			(PORT_BASE + 0x1c4)
 #define CHL_INT2_MSK			(PORT_BASE + 0x1c8)
@@ -429,7 +432,7 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
 		hisi_sas_phy_write32(hisi_hba, i, CHL_INT2, 0xffffffff);
 		hisi_sas_phy_write32(hisi_hba, i, RXOP_CHECK_CFG_H, 0x1000);
 		hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0xff87ffff);
-		hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8ffffbff);
+		hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0xffffbfe);
 		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);
@@ -1342,9 +1345,31 @@ static irqreturn_t int_chnl_int_v3_hw(int irq_no, void *p)
 					     CHL_INT1, irq_value1);
 		}
 
-		if (irq_msk & (8 << (phy_no * 4)) && irq_value2)
+		if (irq_msk & (8 << (phy_no * 4)) && irq_value2) {
+			struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+
+			if (irq_value2 & BIT(CHL_INT2_SL_IDAF_TOUT_CONF_OFF)) {
+				dev_warn(dev, "phy%d identify timeout\n",
+							phy_no);
+				hisi_sas_notify_phy_event(phy,
+					HISI_PHYE_LINK_RESET);
+
+			}
+
+			if (irq_value2 & BIT(CHL_INT2_STP_LINK_TIMEOUT_OFF)) {
+				u32 reg_value = hisi_sas_phy_read32(hisi_hba,
+						phy_no, STP_LINK_TIMEOUT_STATE);
+
+				dev_warn(dev, "phy%d stp link timeout (0x%x)\n",
+							phy_no, reg_value);
+				if (reg_value & BIT(4))
+					hisi_sas_notify_phy_event(phy,
+						HISI_PHYE_LINK_RESET);
+			}
+
 			hisi_sas_phy_write32(hisi_hba, phy_no,
 					     CHL_INT2, irq_value2);
+		}
 
 
 		if (irq_msk & (2 << (phy_no * 4)) && irq_value0) {
-- 
1.9.1

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

* [PATCH 14/19] scsi: hisi_sas: do link reset for some CHL_INT2 ints
@ 2017-12-08 17:16   ` John Garry
  0 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiaofei Tan, John Garry

From: Xiaofei Tan <tanxiaofei@huawei.com>

We should do link reset of PHY when identify timeout or
STP link timeout. They are internal events of SOC and are
notified to driver through interrupts of CHL_INT2.

Besides, we should add an delay work to do link reset as
it needs sleep. So, this patch add an new PHY event
HISI_PHYE_LINK_RESET for this.

Notes: v2 HW doesn't report the event of STP link timeout.
So, we only need to handle event of identify timeout for v2 HW.

Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas.h       |  1 +
 drivers/scsi/hisi_sas/hisi_sas_main.c  | 12 ++++++++++++
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 18 ++++++++++++++----
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 29 +++++++++++++++++++++++++++--
 4 files changed, 54 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index aa14638..4343c4c 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -126,6 +126,7 @@ enum hisi_sas_bit_err_type {
 
 enum hisi_sas_phy_event {
 	HISI_PHYE_PHY_UP   = 0U,
+	HISI_PHYE_LINK_RESET,
 	HISI_PHYES_NUM,
 };
 
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 326dc81..7446a39 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -22,6 +22,8 @@ static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device,
 			     struct domain_device *device,
 			     int abort_flag, int tag);
 static int hisi_sas_softreset_ata_disk(struct domain_device *device);
+static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func,
+				void *funcdata);
 
 u8 hisi_sas_get_ata_protocol(u8 cmd, int direction)
 {
@@ -631,8 +633,18 @@ static void hisi_sas_phyup_work(struct work_struct *work)
 	hisi_sas_bytes_dmaed(hisi_hba, phy_no);
 }
 
+static void hisi_sas_linkreset_work(struct work_struct *work)
+{
+	struct hisi_sas_phy *phy =
+		container_of(work, typeof(*phy), works[HISI_PHYE_LINK_RESET]);
+	struct asd_sas_phy *sas_phy = &phy->sas_phy;
+
+	hisi_sas_control_phy(sas_phy, PHY_FUNC_LINK_RESET, NULL);
+}
+
 static const work_func_t hisi_sas_phye_fns[HISI_PHYES_NUM] = {
 	[HISI_PHYE_PHY_UP] = hisi_sas_phyup_work,
+	[HISI_PHYE_LINK_RESET] = hisi_sas_linkreset_work,
 };
 
 bool hisi_sas_notify_phy_event(struct hisi_sas_phy *phy,
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index e521c42..b8fe08d 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -245,6 +245,7 @@
 #define CHL_INT1_DMAC_RX_AXI_WR_ERR_OFF	21
 #define CHL_INT1_DMAC_RX_AXI_RD_ERR_OFF	22
 #define CHL_INT2			(PORT_BASE + 0x1bc)
+#define CHL_INT2_SL_IDAF_TOUT_CONF_OFF	0
 #define CHL_INT0_MSK			(PORT_BASE + 0x1c0)
 #define CHL_INT1_MSK			(PORT_BASE + 0x1c4)
 #define CHL_INT2_MSK			(PORT_BASE + 0x1c8)
@@ -1187,7 +1188,7 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
 		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, 0xff857fff);
-		hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8ffffbff);
+		hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8ffffbfe);
 		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);
@@ -2905,10 +2906,19 @@ static irqreturn_t int_chnl_int_v2_hw(int irq_no, void *p)
 					     CHL_INT1, irq_value1);
 		}
 
-		if ((irq_msk & (1 << phy_no)) && irq_value2)
-			hisi_sas_phy_write32(hisi_hba, phy_no,
-					     CHL_INT2, irq_value2);
+		if ((irq_msk & (1 << phy_no)) && irq_value2) {
+			struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+
+			if (irq_value2 & BIT(CHL_INT2_SL_IDAF_TOUT_CONF_OFF)) {
+				dev_warn(dev, "phy%d identify timeout\n",
+						phy_no);
+				hisi_sas_notify_phy_event(phy,
+						HISI_PHYE_LINK_RESET);
+			}
 
+			hisi_sas_phy_write32(hisi_hba, phy_no,
+						 CHL_INT2, irq_value2);
+		}
 
 		if ((irq_msk & (1 << phy_no)) && irq_value0) {
 			if (irq_value0 & CHL_INT0_SL_RX_BCST_ACK_MSK)
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 4b7f251..9e32105 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -140,6 +140,7 @@
 #define RX_IDAF_DWORD0			(PORT_BASE + 0xc4)
 #define RXOP_CHECK_CFG_H		(PORT_BASE + 0xfc)
 #define STP_LINK_TIMER			(PORT_BASE + 0x120)
+#define STP_LINK_TIMEOUT_STATE		(PORT_BASE + 0x124)
 #define CON_CFG_DRIVER			(PORT_BASE + 0x130)
 #define SAS_SSP_CON_TIMER_CFG		(PORT_BASE + 0x134)
 #define SAS_SMP_CON_TIMER_CFG		(PORT_BASE + 0x138)
@@ -165,6 +166,8 @@
 #define CHL_INT1_DMAC_RX_AXI_WR_ERR_OFF	21
 #define CHL_INT1_DMAC_RX_AXI_RD_ERR_OFF	22
 #define CHL_INT2			(PORT_BASE + 0x1bc)
+#define CHL_INT2_SL_IDAF_TOUT_CONF_OFF	0
+#define CHL_INT2_STP_LINK_TIMEOUT_OFF	31
 #define CHL_INT0_MSK			(PORT_BASE + 0x1c0)
 #define CHL_INT1_MSK			(PORT_BASE + 0x1c4)
 #define CHL_INT2_MSK			(PORT_BASE + 0x1c8)
@@ -429,7 +432,7 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
 		hisi_sas_phy_write32(hisi_hba, i, CHL_INT2, 0xffffffff);
 		hisi_sas_phy_write32(hisi_hba, i, RXOP_CHECK_CFG_H, 0x1000);
 		hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0xff87ffff);
-		hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8ffffbff);
+		hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0xffffbfe);
 		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);
@@ -1342,9 +1345,31 @@ static irqreturn_t int_chnl_int_v3_hw(int irq_no, void *p)
 					     CHL_INT1, irq_value1);
 		}
 
-		if (irq_msk & (8 << (phy_no * 4)) && irq_value2)
+		if (irq_msk & (8 << (phy_no * 4)) && irq_value2) {
+			struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+
+			if (irq_value2 & BIT(CHL_INT2_SL_IDAF_TOUT_CONF_OFF)) {
+				dev_warn(dev, "phy%d identify timeout\n",
+							phy_no);
+				hisi_sas_notify_phy_event(phy,
+					HISI_PHYE_LINK_RESET);
+
+			}
+
+			if (irq_value2 & BIT(CHL_INT2_STP_LINK_TIMEOUT_OFF)) {
+				u32 reg_value = hisi_sas_phy_read32(hisi_hba,
+						phy_no, STP_LINK_TIMEOUT_STATE);
+
+				dev_warn(dev, "phy%d stp link timeout (0x%x)\n",
+							phy_no, reg_value);
+				if (reg_value & BIT(4))
+					hisi_sas_notify_phy_event(phy,
+						HISI_PHYE_LINK_RESET);
+			}
+
 			hisi_sas_phy_write32(hisi_hba, phy_no,
 					     CHL_INT2, irq_value2);
+		}
 
 
 		if (irq_msk & (2 << (phy_no * 4)) && irq_value0) {
-- 
1.9.1

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

* [PATCH 15/19] scsi: hisi_sas: judge result of internal abort
  2017-12-08 17:16 ` John Garry
@ 2017-12-08 17:16   ` John Garry
  -1 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiaofei Tan, John Garry

From: Xiaofei Tan <tanxiaofei@huawei.com>

Normally, hardware should ensure that internal abort
timeout will never happen. If happen, it would be an SoC
failure. What's more, HW will not process any other
commands if an internal abort hasn't return CQ, and they
will time out also.

So, we should judge the result of internal abort in SCSI
EH, if it is failed, we should give up to do TMF/softreset
and return failure to the upper layer directly.

This patch do following things to achieve this.
1. When internal abort timeout happened, we set return
value to -EIO in hisi_sas_internal_task_abort().

2. If prep_abort() is not support, let
hisi_sas_internal_task_abort() return
TMF_RESP_FUNC_FAILED.

3. If hisi_sas_internal_task_abort() return
an negative number, it can be thought that it not
executed properly or internal abort timeout. Then we
won't do behind TMF or softreset, and return failure
directly.

Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas_main.c | 38 ++++++++++++++++++++++++++++-------
 1 file changed, 31 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 7446a39..1b9c48c 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -1184,6 +1184,11 @@ static int hisi_sas_abort_task(struct sas_task *task)
 
 		rc2 = hisi_sas_internal_task_abort(hisi_hba, device,
 						   HISI_SAS_INT_ABT_CMD, tag);
+		if (rc2 < 0) {
+			dev_err(dev, "abort task: internal abort (%d)\n", rc2);
+			return TMF_RESP_FUNC_FAILED;
+		}
+
 		/*
 		 * 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
@@ -1201,8 +1206,12 @@ static int hisi_sas_abort_task(struct sas_task *task)
 	} else if (task->task_proto & SAS_PROTOCOL_SATA ||
 		task->task_proto & SAS_PROTOCOL_STP) {
 		if (task->dev->dev_type == SAS_SATA_DEV) {
-			hisi_sas_internal_task_abort(hisi_hba, device,
-						     HISI_SAS_INT_ABT_DEV, 0);
+			rc = hisi_sas_internal_task_abort(hisi_hba, device,
+						HISI_SAS_INT_ABT_DEV, 0);
+			if (rc < 0) {
+				dev_err(dev, "abort task: internal abort failed\n");
+				goto out;
+			}
 			hisi_sas_dereg_device(hisi_hba, device);
 			rc = hisi_sas_softreset_ata_disk(device);
 		}
@@ -1213,7 +1222,8 @@ static int hisi_sas_abort_task(struct sas_task *task)
 
 		rc = hisi_sas_internal_task_abort(hisi_hba, device,
 			     HISI_SAS_INT_ABT_CMD, tag);
-		if (rc == TMF_RESP_FUNC_FAILED && task->lldd_task) {
+		if (((rc < 0) || (rc == TMF_RESP_FUNC_FAILED)) &&
+					task->lldd_task) {
 			spin_lock_irqsave(&hisi_hba->lock, flags);
 			hisi_sas_do_release_task(hisi_hba, task, slot);
 			spin_unlock_irqrestore(&hisi_hba->lock, flags);
@@ -1263,15 +1273,20 @@ static int hisi_sas_I_T_nexus_reset(struct domain_device *device)
 {
 	struct hisi_sas_device *sas_dev = device->lldd_dev;
 	struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
-	unsigned long flags;
+	struct device *dev = hisi_hba->dev;
 	int rc = TMF_RESP_FUNC_FAILED;
+	unsigned long flags;
 
 	if (sas_dev->dev_status != HISI_SAS_DEV_EH)
 		return TMF_RESP_FUNC_FAILED;
 	sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
 
-	hisi_sas_internal_task_abort(hisi_hba, device,
+	rc = hisi_sas_internal_task_abort(hisi_hba, device,
 					HISI_SAS_INT_ABT_DEV, 0);
+	if (rc < 0) {
+		dev_err(dev, "I_T nexus reset: internal abort (%d)\n", rc);
+		return TMF_RESP_FUNC_FAILED;
+	}
 	hisi_sas_dereg_device(hisi_hba, device);
 
 	rc = hisi_sas_debug_I_T_nexus_reset(device);
@@ -1299,8 +1314,10 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun)
 		/* 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)
+		if (rc < 0) {
+			dev_err(dev, "lu_reset: internal abort failed\n");
 			goto out;
+		}
 		hisi_sas_dereg_device(hisi_hba, device);
 
 		phy = sas_get_local_phy(device);
@@ -1497,8 +1514,14 @@ static int hisi_sas_query_task(struct sas_task *task)
 	struct device *dev = hisi_hba->dev;
 	int res;
 
+	/*
+	 * The interface is not realized means this HW don't support internal
+	 * abort, or don't need to do internal abort. Then here, we return
+	 * TMF_RESP_FUNC_FAILED and let other steps go on, which depends that
+	 * the internal abort has been executed and returned CQ.
+	 */
 	if (!hisi_hba->hw->prep_abort)
-		return -EOPNOTSUPP;
+		return TMF_RESP_FUNC_FAILED;
 
 	task = sas_alloc_slow_task(GFP_KERNEL);
 	if (!task)
@@ -1530,6 +1553,7 @@ static int hisi_sas_query_task(struct sas_task *task)
 			if (slot)
 				slot->task = NULL;
 			dev_err(dev, "internal task abort: timeout and not done.\n");
+			res = -EIO;
 			goto exit;
 		} else
 			dev_err(dev, "internal task abort: timeout.\n");
-- 
1.9.1

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

* [PATCH 15/19] scsi: hisi_sas: judge result of internal abort
@ 2017-12-08 17:16   ` John Garry
  0 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiaofei Tan, John Garry

From: Xiaofei Tan <tanxiaofei@huawei.com>

Normally, hardware should ensure that internal abort
timeout will never happen. If happen, it would be an SoC
failure. What's more, HW will not process any other
commands if an internal abort hasn't return CQ, and they
will time out also.

So, we should judge the result of internal abort in SCSI
EH, if it is failed, we should give up to do TMF/softreset
and return failure to the upper layer directly.

This patch do following things to achieve this.
1. When internal abort timeout happened, we set return
value to -EIO in hisi_sas_internal_task_abort().

2. If prep_abort() is not support, let
hisi_sas_internal_task_abort() return
TMF_RESP_FUNC_FAILED.

3. If hisi_sas_internal_task_abort() return
an negative number, it can be thought that it not
executed properly or internal abort timeout. Then we
won't do behind TMF or softreset, and return failure
directly.

Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas_main.c | 38 ++++++++++++++++++++++++++++-------
 1 file changed, 31 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 7446a39..1b9c48c 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -1184,6 +1184,11 @@ static int hisi_sas_abort_task(struct sas_task *task)
 
 		rc2 = hisi_sas_internal_task_abort(hisi_hba, device,
 						   HISI_SAS_INT_ABT_CMD, tag);
+		if (rc2 < 0) {
+			dev_err(dev, "abort task: internal abort (%d)\n", rc2);
+			return TMF_RESP_FUNC_FAILED;
+		}
+
 		/*
 		 * 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
@@ -1201,8 +1206,12 @@ static int hisi_sas_abort_task(struct sas_task *task)
 	} else if (task->task_proto & SAS_PROTOCOL_SATA ||
 		task->task_proto & SAS_PROTOCOL_STP) {
 		if (task->dev->dev_type == SAS_SATA_DEV) {
-			hisi_sas_internal_task_abort(hisi_hba, device,
-						     HISI_SAS_INT_ABT_DEV, 0);
+			rc = hisi_sas_internal_task_abort(hisi_hba, device,
+						HISI_SAS_INT_ABT_DEV, 0);
+			if (rc < 0) {
+				dev_err(dev, "abort task: internal abort failed\n");
+				goto out;
+			}
 			hisi_sas_dereg_device(hisi_hba, device);
 			rc = hisi_sas_softreset_ata_disk(device);
 		}
@@ -1213,7 +1222,8 @@ static int hisi_sas_abort_task(struct sas_task *task)
 
 		rc = hisi_sas_internal_task_abort(hisi_hba, device,
 			     HISI_SAS_INT_ABT_CMD, tag);
-		if (rc == TMF_RESP_FUNC_FAILED && task->lldd_task) {
+		if (((rc < 0) || (rc == TMF_RESP_FUNC_FAILED)) &&
+					task->lldd_task) {
 			spin_lock_irqsave(&hisi_hba->lock, flags);
 			hisi_sas_do_release_task(hisi_hba, task, slot);
 			spin_unlock_irqrestore(&hisi_hba->lock, flags);
@@ -1263,15 +1273,20 @@ static int hisi_sas_I_T_nexus_reset(struct domain_device *device)
 {
 	struct hisi_sas_device *sas_dev = device->lldd_dev;
 	struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
-	unsigned long flags;
+	struct device *dev = hisi_hba->dev;
 	int rc = TMF_RESP_FUNC_FAILED;
+	unsigned long flags;
 
 	if (sas_dev->dev_status != HISI_SAS_DEV_EH)
 		return TMF_RESP_FUNC_FAILED;
 	sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
 
-	hisi_sas_internal_task_abort(hisi_hba, device,
+	rc = hisi_sas_internal_task_abort(hisi_hba, device,
 					HISI_SAS_INT_ABT_DEV, 0);
+	if (rc < 0) {
+		dev_err(dev, "I_T nexus reset: internal abort (%d)\n", rc);
+		return TMF_RESP_FUNC_FAILED;
+	}
 	hisi_sas_dereg_device(hisi_hba, device);
 
 	rc = hisi_sas_debug_I_T_nexus_reset(device);
@@ -1299,8 +1314,10 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun)
 		/* 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)
+		if (rc < 0) {
+			dev_err(dev, "lu_reset: internal abort failed\n");
 			goto out;
+		}
 		hisi_sas_dereg_device(hisi_hba, device);
 
 		phy = sas_get_local_phy(device);
@@ -1497,8 +1514,14 @@ static int hisi_sas_query_task(struct sas_task *task)
 	struct device *dev = hisi_hba->dev;
 	int res;
 
+	/*
+	 * The interface is not realized means this HW don't support internal
+	 * abort, or don't need to do internal abort. Then here, we return
+	 * TMF_RESP_FUNC_FAILED and let other steps go on, which depends that
+	 * the internal abort has been executed and returned CQ.
+	 */
 	if (!hisi_hba->hw->prep_abort)
-		return -EOPNOTSUPP;
+		return TMF_RESP_FUNC_FAILED;
 
 	task = sas_alloc_slow_task(GFP_KERNEL);
 	if (!task)
@@ -1530,6 +1553,7 @@ static int hisi_sas_query_task(struct sas_task *task)
 			if (slot)
 				slot->task = NULL;
 			dev_err(dev, "internal task abort: timeout and not done.\n");
+			res = -EIO;
 			goto exit;
 		} else
 			dev_err(dev, "internal task abort: timeout.\n");
-- 
1.9.1

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

* [PATCH 16/19] scsi: hisi_sas: add internal abort dev in some places
  2017-12-08 17:16 ` John Garry
@ 2017-12-08 17:16   ` John Garry
  -1 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiaofei Tan, John Garry

From: Xiaofei Tan <tanxiaofei@huawei.com>

We should do internal abort dev before
TMF_ABORT_TASK_SET and TMF_LU_RESET. Because we may
only have done internal abort for single IO in the
earlier part of SCSI EH process. Even the internal abort
to the single IO, we also don't know whether it is
successful.

Besides, we should release slots of the device in
hisi_sas_abort_task_set() if the abort is successful.

Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas_main.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 1b9c48c..302da84 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -1238,12 +1238,29 @@ static int hisi_sas_abort_task(struct sas_task *task)
 
 static int hisi_sas_abort_task_set(struct domain_device *device, u8 *lun)
 {
+	struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+	struct device *dev = hisi_hba->dev;
 	struct hisi_sas_tmf_task tmf_task;
 	int rc = TMF_RESP_FUNC_FAILED;
+	unsigned long flags;
+
+	rc = hisi_sas_internal_task_abort(hisi_hba, device,
+					HISI_SAS_INT_ABT_DEV, 0);
+	if (rc < 0) {
+		dev_err(dev, "abort task set: internal abort rc=%d\n", rc);
+		return TMF_RESP_FUNC_FAILED;
+	}
+	hisi_sas_dereg_device(hisi_hba, device);
 
 	tmf_task.tmf = TMF_ABORT_TASK_SET;
 	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);
+	}
+
 	return rc;
 }
 
@@ -1333,6 +1350,14 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun)
 	} else {
 		struct hisi_sas_tmf_task tmf_task = { .tmf =  TMF_LU_RESET };
 
+		rc = hisi_sas_internal_task_abort(hisi_hba, device,
+						HISI_SAS_INT_ABT_DEV, 0);
+		if (rc < 0) {
+			dev_err(dev, "lu_reset: internal abort failed\n");
+			goto out;
+		}
+		hisi_sas_dereg_device(hisi_hba, device);
+
 		rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task);
 		if (rc == TMF_RESP_FUNC_COMPLETE) {
 			spin_lock_irqsave(&hisi_hba->lock, flags);
-- 
1.9.1

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

* [PATCH 16/19] scsi: hisi_sas: add internal abort dev in some places
@ 2017-12-08 17:16   ` John Garry
  0 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiaofei Tan, John Garry

From: Xiaofei Tan <tanxiaofei@huawei.com>

We should do internal abort dev before
TMF_ABORT_TASK_SET and TMF_LU_RESET. Because we may
only have done internal abort for single IO in the
earlier part of SCSI EH process. Even the internal abort
to the single IO, we also don't know whether it is
successful.

Besides, we should release slots of the device in
hisi_sas_abort_task_set() if the abort is successful.

Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas_main.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 1b9c48c..302da84 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -1238,12 +1238,29 @@ static int hisi_sas_abort_task(struct sas_task *task)
 
 static int hisi_sas_abort_task_set(struct domain_device *device, u8 *lun)
 {
+	struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+	struct device *dev = hisi_hba->dev;
 	struct hisi_sas_tmf_task tmf_task;
 	int rc = TMF_RESP_FUNC_FAILED;
+	unsigned long flags;
+
+	rc = hisi_sas_internal_task_abort(hisi_hba, device,
+					HISI_SAS_INT_ABT_DEV, 0);
+	if (rc < 0) {
+		dev_err(dev, "abort task set: internal abort rc=%d\n", rc);
+		return TMF_RESP_FUNC_FAILED;
+	}
+	hisi_sas_dereg_device(hisi_hba, device);
 
 	tmf_task.tmf = TMF_ABORT_TASK_SET;
 	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);
+	}
+
 	return rc;
 }
 
@@ -1333,6 +1350,14 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun)
 	} else {
 		struct hisi_sas_tmf_task tmf_task = { .tmf =  TMF_LU_RESET };
 
+		rc = hisi_sas_internal_task_abort(hisi_hba, device,
+						HISI_SAS_INT_ABT_DEV, 0);
+		if (rc < 0) {
+			dev_err(dev, "lu_reset: internal abort failed\n");
+			goto out;
+		}
+		hisi_sas_dereg_device(hisi_hba, device);
+
 		rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task);
 		if (rc == TMF_RESP_FUNC_COMPLETE) {
 			spin_lock_irqsave(&hisi_hba->lock, flags);
-- 
1.9.1

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

* [PATCH 17/19] scsi: hisi_sas: fix SAS_QUEUE_FULL problem while running IO
  2017-12-08 17:16 ` John Garry
@ 2017-12-08 17:16   ` John Garry
  -1 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiang Chen, Xiaofei Tan, John Garry

From: Xiang Chen <chenxiang66@hisilicon.com>

This patch fix SAS_QUEUE_FULL problem. The test situation is
close port while running IO.

In sas_eh_handle_sas_errors(), SCSI EH will free sas_task of
the device if lldd_I_T_nexus_reset() return
TMF_RESP_FUNC_COMPLETE or -ENODEV.
But in our SAS driver, we only free slots of the device when
the return value is TMF_RESP_FUNC_COMPLETE. So if the return
value is -ENODEV, the slot resource will not free any more.

As an solution, we should also free slots of the device in
lldd_I_T_nexus_reset() if the return value is -ENODEV.

Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.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 302da84..9bd98e5 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -1308,7 +1308,7 @@ static int hisi_sas_I_T_nexus_reset(struct domain_device *device)
 
 	rc = hisi_sas_debug_I_T_nexus_reset(device);
 
-	if (rc == TMF_RESP_FUNC_COMPLETE) {
+	if ((rc == TMF_RESP_FUNC_COMPLETE) || (rc == -ENODEV)) {
 		spin_lock_irqsave(&hisi_hba->lock, flags);
 		hisi_sas_release_task(hisi_hba, device);
 		spin_unlock_irqrestore(&hisi_hba->lock, flags);
-- 
1.9.1

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

* [PATCH 17/19] scsi: hisi_sas: fix SAS_QUEUE_FULL problem while running IO
@ 2017-12-08 17:16   ` John Garry
  0 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiang Chen, Xiaofei Tan, John Garry

From: Xiang Chen <chenxiang66@hisilicon.com>

This patch fix SAS_QUEUE_FULL problem. The test situation is
close port while running IO.

In sas_eh_handle_sas_errors(), SCSI EH will free sas_task of
the device if lldd_I_T_nexus_reset() return
TMF_RESP_FUNC_COMPLETE or -ENODEV.
But in our SAS driver, we only free slots of the device when
the return value is TMF_RESP_FUNC_COMPLETE. So if the return
value is -ENODEV, the slot resource will not free any more.

As an solution, we should also free slots of the device in
lldd_I_T_nexus_reset() if the return value is -ENODEV.

Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.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 302da84..9bd98e5 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -1308,7 +1308,7 @@ static int hisi_sas_I_T_nexus_reset(struct domain_device *device)
 
 	rc = hisi_sas_debug_I_T_nexus_reset(device);
 
-	if (rc == TMF_RESP_FUNC_COMPLETE) {
+	if ((rc == TMF_RESP_FUNC_COMPLETE) || (rc == -ENODEV)) {
 		spin_lock_irqsave(&hisi_hba->lock, flags);
 		hisi_sas_release_task(hisi_hba, device);
 		spin_unlock_irqrestore(&hisi_hba->lock, flags);
-- 
1.9.1

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

* [PATCH 18/19] scsi: hisi_sas: re-add the lldd_port_deformed()
  2017-12-08 17:16 ` John Garry
@ 2017-12-08 17:16   ` John Garry
  -1 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiang Chen, John Garry

From: Xiang Chen <chenxiang66@hisilicon.com>

In function sas_suspend_devices(), it requires
callback lldd_port_deformed callback to be
implemented if lldd_port_deformed is
implemented.

So add a stub for lldd_port_deformed.

Callback lldd_port_deformed was not required as the
port deformation is done elsewhere in the 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 | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 9bd98e5..ad12237 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -1613,6 +1613,10 @@ 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)
+{
+}
+
 static void hisi_sas_phy_disconnected(struct hisi_sas_phy *phy)
 {
 	phy->phy_attached = 0;
@@ -1703,6 +1707,7 @@ void hisi_sas_kill_tasklets(struct hisi_hba *hisi_hba)
 	.lldd_query_task	= hisi_sas_query_task,
 	.lldd_clear_nexus_ha = hisi_sas_clear_nexus_ha,
 	.lldd_port_formed	= hisi_sas_port_formed,
+	.lldd_port_deformed = hisi_sas_port_deformed,
 };
 
 void hisi_sas_init_mem(struct hisi_hba *hisi_hba)
-- 
1.9.1

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

* [PATCH 18/19] scsi: hisi_sas: re-add the lldd_port_deformed()
@ 2017-12-08 17:16   ` John Garry
  0 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiang Chen, John Garry

From: Xiang Chen <chenxiang66@hisilicon.com>

In function sas_suspend_devices(), it requires
callback lldd_port_deformed callback to be
implemented if lldd_port_deformed is
implemented.

So add a stub for lldd_port_deformed.

Callback lldd_port_deformed was not required as the
port deformation is done elsewhere in the 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 | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 9bd98e5..ad12237 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -1613,6 +1613,10 @@ 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)
+{
+}
+
 static void hisi_sas_phy_disconnected(struct hisi_sas_phy *phy)
 {
 	phy->phy_attached = 0;
@@ -1703,6 +1707,7 @@ void hisi_sas_kill_tasklets(struct hisi_hba *hisi_hba)
 	.lldd_query_task	= hisi_sas_query_task,
 	.lldd_clear_nexus_ha = hisi_sas_clear_nexus_ha,
 	.lldd_port_formed	= hisi_sas_port_formed,
+	.lldd_port_deformed = hisi_sas_port_deformed,
 };
 
 void hisi_sas_init_mem(struct hisi_hba *hisi_hba)
-- 
1.9.1

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

* [PATCH 19/19] scsi: hisi_sas: add v3 hw suspend and resume
  2017-12-08 17:16 ` John Garry
@ 2017-12-08 17:16   ` John Garry
  -1 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiang Chen, John Garry

From: Xiang Chen <chenxiang66@hisilicon.com>

For v3 hw SAS, it supports configuring power state
from D0 to D3 for entering Low Power status and
power state from D3 to D0 for quit Low Power status.

When power state from D0 to D3, HW will send FLR to
clear the registers of ECAM and BAR space, and when
power state from D3 to D0, it will clear the
registers of ECAM space only.

So when suspend, need to do like controller reset
(including disable interrupts/DQ/PHY/BUS), and
also release slots after FLR. When resume,
re-config the registers of BAR space.

Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas.h       |  1 +
 drivers/scsi/hisi_sas/hisi_sas_main.c  |  3 +-
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 94 ++++++++++++++++++++++++++++++++++
 3 files changed, 97 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index 4343c4c..cc05029 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -461,4 +461,5 @@ extern void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba,
 extern void hisi_sas_kill_tasklets(struct hisi_hba *hisi_hba);
 extern bool hisi_sas_notify_phy_event(struct hisi_sas_phy *phy,
 				enum hisi_sas_phy_event event);
+extern void hisi_sas_release_tasks(struct hisi_hba *hisi_hba);
 #endif
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index ad12237..04e1172b 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -737,7 +737,7 @@ static void hisi_sas_release_task(struct hisi_hba *hisi_hba,
 		hisi_sas_do_release_task(hisi_hba, slot->task, slot);
 }
 
-static void hisi_sas_release_tasks(struct hisi_hba *hisi_hba)
+void hisi_sas_release_tasks(struct hisi_hba *hisi_hba)
 {
 	struct hisi_sas_device *sas_dev;
 	struct domain_device *device;
@@ -754,6 +754,7 @@ static void hisi_sas_release_tasks(struct hisi_hba *hisi_hba)
 		hisi_sas_release_task(hisi_hba, device);
 	}
 }
+EXPORT_SYMBOL_GPL(hisi_sas_release_tasks);
 
 static void hisi_sas_dereg_device(struct hisi_hba *hisi_hba,
 				struct domain_device *device)
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 9e32105..6a408d2 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -2303,6 +2303,98 @@ enum {
 	hip08,
 };
 
+static int hisi_sas_v3_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct sas_ha_struct *sha = pci_get_drvdata(pdev);
+	struct hisi_hba *hisi_hba = sha->lldd_ha;
+	struct device *dev = hisi_hba->dev;
+	struct Scsi_Host *shost = hisi_hba->shost;
+	u32 device_state, status;
+	int rc;
+	u32 reg_val;
+	unsigned long flags;
+
+	if (!pdev->pm_cap) {
+		dev_err(dev, "PCI PM not supported\n");
+		return -ENODEV;
+	}
+
+	set_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags);
+	scsi_block_requests(shost);
+	set_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
+	flush_workqueue(hisi_hba->wq);
+	/* disable DQ/PHY/bus */
+	interrupt_disable_v3_hw(hisi_hba);
+	hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0x0);
+	hisi_sas_kill_tasklets(hisi_hba);
+
+	hisi_sas_stop_phys(hisi_hba);
+
+	reg_val = hisi_sas_read32(hisi_hba, AXI_MASTER_CFG_BASE +
+		AM_CTRL_GLOBAL);
+	reg_val |= 0x1;
+	hisi_sas_write32(hisi_hba, AXI_MASTER_CFG_BASE +
+		AM_CTRL_GLOBAL, reg_val);
+
+	/* wait until bus idle */
+	rc = readl_poll_timeout(hisi_hba->regs + AXI_MASTER_CFG_BASE +
+		AM_CURR_TRANS_RETURN, status, status == 0x3, 10, 100);
+	if (rc) {
+		dev_err(dev, "axi bus is not idle, rc = %d\n", rc);
+		clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
+		clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags);
+		scsi_unblock_requests(shost);
+		return rc;
+	}
+
+	hisi_sas_init_mem(hisi_hba);
+
+	device_state = pci_choose_state(pdev, state);
+	dev_warn(dev, "entering operating state [D%d]\n",
+			device_state);
+	pci_save_state(pdev);
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, device_state);
+
+	spin_lock_irqsave(&hisi_hba->lock, flags);
+	hisi_sas_release_tasks(hisi_hba);
+	spin_unlock_irqrestore(&hisi_hba->lock, flags);
+
+	sas_suspend_ha(sha);
+	return 0;
+}
+
+static int hisi_sas_v3_resume(struct pci_dev *pdev)
+{
+	struct sas_ha_struct *sha = pci_get_drvdata(pdev);
+	struct hisi_hba *hisi_hba = sha->lldd_ha;
+	struct Scsi_Host *shost = hisi_hba->shost;
+	struct device *dev = hisi_hba->dev;
+	unsigned int rc;
+	u32 device_state = pdev->current_state;
+
+	dev_warn(dev, "resuming from operating state [D%d]\n",
+			device_state);
+	pci_set_power_state(pdev, PCI_D0);
+	pci_enable_wake(pdev, PCI_D0, 0);
+	pci_restore_state(pdev);
+	rc = pci_enable_device(pdev);
+	if (rc)
+		dev_err(dev, "enable device failed during resume (%d)\n", rc);
+
+	pci_set_master(pdev);
+	scsi_unblock_requests(shost);
+	clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
+
+	sas_prep_resume_ha(sha);
+	init_reg_v3_hw(hisi_hba);
+	hisi_hba->hw->phys_init(hisi_hba);
+	sas_resume_ha(sha);
+	clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags);
+
+	return 0;
+}
+
 static const struct pci_device_id sas_v3_pci_table[] = {
 	{ PCI_VDEVICE(HUAWEI, 0xa230), hip08 },
 	{}
@@ -2319,6 +2411,8 @@ enum {
 	.id_table	= sas_v3_pci_table,
 	.probe		= hisi_sas_v3_probe,
 	.remove		= hisi_sas_v3_remove,
+	.suspend	= hisi_sas_v3_suspend,
+	.resume		= hisi_sas_v3_resume,
 	.err_handler	= &hisi_sas_err_handler,
 };
 
-- 
1.9.1

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

* [PATCH 19/19] scsi: hisi_sas: add v3 hw suspend and resume
@ 2017-12-08 17:16   ` John Garry
  0 siblings, 0 replies; 42+ messages in thread
From: John Garry @ 2017-12-08 17:16 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-scsi, linux-kernel, Xiang Chen, John Garry

From: Xiang Chen <chenxiang66@hisilicon.com>

For v3 hw SAS, it supports configuring power state
from D0 to D3 for entering Low Power status and
power state from D3 to D0 for quit Low Power status.

When power state from D0 to D3, HW will send FLR to
clear the registers of ECAM and BAR space, and when
power state from D3 to D0, it will clear the
registers of ECAM space only.

So when suspend, need to do like controller reset
(including disable interrupts/DQ/PHY/BUS), and
also release slots after FLR. When resume,
re-config the registers of BAR space.

Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas.h       |  1 +
 drivers/scsi/hisi_sas/hisi_sas_main.c  |  3 +-
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 94 ++++++++++++++++++++++++++++++++++
 3 files changed, 97 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index 4343c4c..cc05029 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -461,4 +461,5 @@ extern void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba,
 extern void hisi_sas_kill_tasklets(struct hisi_hba *hisi_hba);
 extern bool hisi_sas_notify_phy_event(struct hisi_sas_phy *phy,
 				enum hisi_sas_phy_event event);
+extern void hisi_sas_release_tasks(struct hisi_hba *hisi_hba);
 #endif
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index ad12237..04e1172b 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -737,7 +737,7 @@ static void hisi_sas_release_task(struct hisi_hba *hisi_hba,
 		hisi_sas_do_release_task(hisi_hba, slot->task, slot);
 }
 
-static void hisi_sas_release_tasks(struct hisi_hba *hisi_hba)
+void hisi_sas_release_tasks(struct hisi_hba *hisi_hba)
 {
 	struct hisi_sas_device *sas_dev;
 	struct domain_device *device;
@@ -754,6 +754,7 @@ static void hisi_sas_release_tasks(struct hisi_hba *hisi_hba)
 		hisi_sas_release_task(hisi_hba, device);
 	}
 }
+EXPORT_SYMBOL_GPL(hisi_sas_release_tasks);
 
 static void hisi_sas_dereg_device(struct hisi_hba *hisi_hba,
 				struct domain_device *device)
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 9e32105..6a408d2 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -2303,6 +2303,98 @@ enum {
 	hip08,
 };
 
+static int hisi_sas_v3_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct sas_ha_struct *sha = pci_get_drvdata(pdev);
+	struct hisi_hba *hisi_hba = sha->lldd_ha;
+	struct device *dev = hisi_hba->dev;
+	struct Scsi_Host *shost = hisi_hba->shost;
+	u32 device_state, status;
+	int rc;
+	u32 reg_val;
+	unsigned long flags;
+
+	if (!pdev->pm_cap) {
+		dev_err(dev, "PCI PM not supported\n");
+		return -ENODEV;
+	}
+
+	set_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags);
+	scsi_block_requests(shost);
+	set_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
+	flush_workqueue(hisi_hba->wq);
+	/* disable DQ/PHY/bus */
+	interrupt_disable_v3_hw(hisi_hba);
+	hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0x0);
+	hisi_sas_kill_tasklets(hisi_hba);
+
+	hisi_sas_stop_phys(hisi_hba);
+
+	reg_val = hisi_sas_read32(hisi_hba, AXI_MASTER_CFG_BASE +
+		AM_CTRL_GLOBAL);
+	reg_val |= 0x1;
+	hisi_sas_write32(hisi_hba, AXI_MASTER_CFG_BASE +
+		AM_CTRL_GLOBAL, reg_val);
+
+	/* wait until bus idle */
+	rc = readl_poll_timeout(hisi_hba->regs + AXI_MASTER_CFG_BASE +
+		AM_CURR_TRANS_RETURN, status, status == 0x3, 10, 100);
+	if (rc) {
+		dev_err(dev, "axi bus is not idle, rc = %d\n", rc);
+		clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
+		clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags);
+		scsi_unblock_requests(shost);
+		return rc;
+	}
+
+	hisi_sas_init_mem(hisi_hba);
+
+	device_state = pci_choose_state(pdev, state);
+	dev_warn(dev, "entering operating state [D%d]\n",
+			device_state);
+	pci_save_state(pdev);
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, device_state);
+
+	spin_lock_irqsave(&hisi_hba->lock, flags);
+	hisi_sas_release_tasks(hisi_hba);
+	spin_unlock_irqrestore(&hisi_hba->lock, flags);
+
+	sas_suspend_ha(sha);
+	return 0;
+}
+
+static int hisi_sas_v3_resume(struct pci_dev *pdev)
+{
+	struct sas_ha_struct *sha = pci_get_drvdata(pdev);
+	struct hisi_hba *hisi_hba = sha->lldd_ha;
+	struct Scsi_Host *shost = hisi_hba->shost;
+	struct device *dev = hisi_hba->dev;
+	unsigned int rc;
+	u32 device_state = pdev->current_state;
+
+	dev_warn(dev, "resuming from operating state [D%d]\n",
+			device_state);
+	pci_set_power_state(pdev, PCI_D0);
+	pci_enable_wake(pdev, PCI_D0, 0);
+	pci_restore_state(pdev);
+	rc = pci_enable_device(pdev);
+	if (rc)
+		dev_err(dev, "enable device failed during resume (%d)\n", rc);
+
+	pci_set_master(pdev);
+	scsi_unblock_requests(shost);
+	clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
+
+	sas_prep_resume_ha(sha);
+	init_reg_v3_hw(hisi_hba);
+	hisi_hba->hw->phys_init(hisi_hba);
+	sas_resume_ha(sha);
+	clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags);
+
+	return 0;
+}
+
 static const struct pci_device_id sas_v3_pci_table[] = {
 	{ PCI_VDEVICE(HUAWEI, 0xa230), hip08 },
 	{}
@@ -2319,6 +2411,8 @@ enum {
 	.id_table	= sas_v3_pci_table,
 	.probe		= hisi_sas_v3_probe,
 	.remove		= hisi_sas_v3_remove,
+	.suspend	= hisi_sas_v3_suspend,
+	.resume		= hisi_sas_v3_resume,
 	.err_handler	= &hisi_sas_err_handler,
 };
 
-- 
1.9.1

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

* Re: [PATCH 00/19] hisi_sas: PM, RAS, and other misc changes
  2017-12-08 17:16 ` John Garry
@ 2017-12-15  2:34   ` Martin K. Petersen
  -1 siblings, 0 replies; 42+ messages in thread
From: Martin K. Petersen @ 2017-12-15  2:34 UTC (permalink / raw)
  To: John Garry; +Cc: jejb, martin.petersen, linuxarm, linux-scsi, linux-kernel


John,

> This patchset contains support for some new
> features, and also some modifications and other
> fixes.
>
> Headline changes include:
> - v3 hw Suspend and Resume support
> - v3 hw RAS (PCI AER) support
> - v2 hw HW port error handling support
> - other misc fixes and tidy-up

Applied to 4.16/scsi-queue. Thank you!

-- 
Martin K. Petersen	Oracle Linux Engineering

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

* Re: [PATCH 00/19] hisi_sas: PM, RAS, and other misc changes
@ 2017-12-15  2:34   ` Martin K. Petersen
  0 siblings, 0 replies; 42+ messages in thread
From: Martin K. Petersen @ 2017-12-15  2:34 UTC (permalink / raw)
  To: John Garry; +Cc: jejb, martin.petersen, linuxarm, linux-scsi, linux-kernel


John,

> This patchset contains support for some new
> features, and also some modifications and other
> fixes.
>
> Headline changes include:
> - v3 hw Suspend and Resume support
> - v3 hw RAS (PCI AER) support
> - v2 hw HW port error handling support
> - other misc fixes and tidy-up

Applied to 4.16/scsi-queue. Thank you!

-- 
Martin K. Petersen	Oracle Linux Engineering

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

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

Thread overview: 42+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-12-08 17:16 [PATCH 00/19] hisi_sas: PM, RAS, and other misc changes John Garry
2017-12-08 17:16 ` John Garry
2017-12-08 17:16 ` [PATCH 01/19] scsi: hisi_sas: initialize dq spinlock before use John Garry
2017-12-08 17:16   ` John Garry
2017-12-08 17:16 ` [PATCH 02/19] scsi: hisi_sas: fix dma_unmap_sg() parameter John Garry
2017-12-08 17:16   ` John Garry
2017-12-08 17:16 ` [PATCH 03/19] scsi: hisi_sas: relocate clearing ITCT and freeing device John Garry
2017-12-08 17:16   ` John Garry
2017-12-08 17:16 ` [PATCH 04/19] scsi: hisi_sas: optimise port id refresh function John Garry
2017-12-08 17:16   ` John Garry
2017-12-08 17:16 ` [PATCH 05/19] scsi: hisi_sas: some optimizations of host controller reset John Garry
2017-12-08 17:16   ` John Garry
2017-12-08 17:16 ` [PATCH 06/19] scsi: hisi_sas: modify hisi_sas_dev_gone() for reset John Garry
2017-12-08 17:16   ` John Garry
2017-12-08 17:16 ` [PATCH 07/19] scsi: hisi_sas: add an mechanism to do reset work synchronously John Garry
2017-12-08 17:16   ` John Garry
2017-12-08 17:16 ` [PATCH 08/19] scsi: hisi_sas: change ncq process for v3 hw John Garry
2017-12-08 17:16   ` John Garry
2017-12-08 17:16 ` [PATCH 09/19] scsi: hisi_sas: add RAS feature " John Garry
2017-12-08 17:16   ` John Garry
2017-12-08 17:16 ` [PATCH 10/19] scsi: hisi_sas: add some print to enhance debugging John Garry
2017-12-08 17:16   ` John Garry
2017-12-08 17:16 ` [PATCH 11/19] scsi: hisi_sas: improve int_chnl_int_v2_hw() consistency with v3 hw John Garry
2017-12-08 17:16   ` John Garry
2017-12-08 17:16 ` [PATCH 12/19] scsi: hisi_sas: add v2 hw port AXI error handling support John Garry
2017-12-08 17:16   ` John Garry
2017-12-08 17:16 ` [PATCH 13/19] scsi: hisi_sas: use an general way to delay PHY work John Garry
2017-12-08 17:16   ` John Garry
2017-12-08 17:16 ` [PATCH 14/19] scsi: hisi_sas: do link reset for some CHL_INT2 ints John Garry
2017-12-08 17:16   ` John Garry
2017-12-08 17:16 ` [PATCH 15/19] scsi: hisi_sas: judge result of internal abort John Garry
2017-12-08 17:16   ` John Garry
2017-12-08 17:16 ` [PATCH 16/19] scsi: hisi_sas: add internal abort dev in some places John Garry
2017-12-08 17:16   ` John Garry
2017-12-08 17:16 ` [PATCH 17/19] scsi: hisi_sas: fix SAS_QUEUE_FULL problem while running IO John Garry
2017-12-08 17:16   ` John Garry
2017-12-08 17:16 ` [PATCH 18/19] scsi: hisi_sas: re-add the lldd_port_deformed() John Garry
2017-12-08 17:16   ` John Garry
2017-12-08 17:16 ` [PATCH 19/19] scsi: hisi_sas: add v3 hw suspend and resume John Garry
2017-12-08 17:16   ` John Garry
2017-12-15  2:34 ` [PATCH 00/19] hisi_sas: PM, RAS, and other misc changes Martin K. Petersen
2017-12-15  2:34   ` Martin K. Petersen

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.