linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/5]  hisi_sas: DIF support
@ 2018-12-06 13:34 John Garry
  2018-12-06 13:34 ` [PATCH v4 1/5] scsi: hisi_sas: Fix warnings detected by sparse John Garry
                   ` (5 more replies)
  0 siblings, 6 replies; 16+ messages in thread
From: John Garry @ 2018-12-06 13:34 UTC (permalink / raw)
  To: jejb, martin.petersen; +Cc: linuxarm, linux-kernel, linux-scsi, John Garry

This patchset introduces support to the driver for DIF/DIX.

We are making DIX support as RFC for now, based on issues discussed in the
following:
https://marc.info/?l=linux-scsi&m=154357719329297&w=4 and
https://marc.info/?l=linux-scsi&m=154406987703456&w=2

We will only support PI in v3 hw at the moment, even though previous hw
versions also support it.

The series is broken down as follows:
- Fix pre-existing sparse warnings
- Tidy sg table size config
- Some tidy-up to accept PI support
- Add components for PI support for main and v3 driver

Differences:
v3->v4:
- re-add DIX support as RFC - do not commit please!
- also DIX support is labelled experimental in the driver

v2->v3:
- fix sparse warnings
- drop DIX support

v1->v2:
- drop scsi_prot_op_normal()

John Garry (1):
  scsi: hisi_sas: Fix warnings detected by sparse

Xiang Chen (4):
  scsi: hisi_sas: Relocate some code to reduce complexity
  scsi: hisi_sas: Make sg_tablesize consistent value
  scsi: hisi_sas: Add support for DIF feature for v3 hw
  scsi: hisi_sas: Add support for DIX feature for v3 hw as experimental

 drivers/scsi/hisi_sas/hisi_sas.h       |  21 ++-
 drivers/scsi/hisi_sas/hisi_sas_main.c  | 246 ++++++++++++++++++++++++---------
 drivers/scsi/hisi_sas/hisi_sas_v1_hw.c |  17 +--
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c |  68 +++++----
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 243 +++++++++++++++++++++++++++++---
 5 files changed, 464 insertions(+), 131 deletions(-)

-- 
1.9.1


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

* [PATCH v4 1/5] scsi: hisi_sas: Fix warnings detected by sparse
  2018-12-06 13:34 [PATCH v4 0/5] hisi_sas: DIF support John Garry
@ 2018-12-06 13:34 ` John Garry
  2018-12-06 13:34 ` [PATCH v4 2/5] scsi: hisi_sas: Relocate some code to reduce complexity John Garry
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: John Garry @ 2018-12-06 13:34 UTC (permalink / raw)
  To: jejb, martin.petersen; +Cc: linuxarm, linux-kernel, linux-scsi, John Garry

This patchset fixes some warnings detected by the sparse tool, like these:
drivers/scsi/hisi_sas/hisi_sas_main.c:1469:52: warning: incorrect type in assignment (different base types)
drivers/scsi/hisi_sas/hisi_sas_main.c:1469:52:    expected unsigned short [unsigned] [assigned] [usertype] tag_of_task_to_be_managed
drivers/scsi/hisi_sas/hisi_sas_main.c:1469:52:    got restricted __le16 [usertype] <noident>
drivers/scsi/hisi_sas/hisi_sas_main.c:1723:52: warning: incorrect type in assignment (different base types)
drivers/scsi/hisi_sas/hisi_sas_main.c:1723:52:    expected unsigned short [unsigned] [assigned] [usertype] tag_of_task_to_be_managed
drivers/scsi/hisi_sas/hisi_sas_main.c:1723:52:    got restricted __le16 [usertype] <noident>

Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas.h       |  2 +-
 drivers/scsi/hisi_sas/hisi_sas_main.c  |  6 ++--
 drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 15 ++++----
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 66 +++++++++++++++++++---------------
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 37 +++++++++++--------
 5 files changed, 71 insertions(+), 55 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index 535c613..912d234 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -211,7 +211,7 @@ struct hisi_sas_slot {
 	/* Do not reorder/change members after here */
 	void	*buf;
 	dma_addr_t buf_dma;
-	int	idx;
+	u16	idx;
 };
 
 struct hisi_sas_hw {
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 65dc749..c39c91c 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -1461,12 +1461,12 @@ static int hisi_sas_abort_task(struct sas_task *task)
 	if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) {
 		struct scsi_cmnd *cmnd = task->uldd_task;
 		struct hisi_sas_slot *slot = task->lldd_task;
-		u32 tag = slot->idx;
+		u16 tag = slot->idx;
 		int rc2;
 
 		int_to_scsilun(cmnd->device->lun, &lun);
 		tmf_task.tmf = TMF_ABORT_TASK;
-		tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag);
+		tmf_task.tag_of_task_to_be_managed = tag;
 
 		rc = hisi_sas_debug_issue_ssp_tmf(task->dev, lun.scsi_lun,
 						  &tmf_task);
@@ -1720,7 +1720,7 @@ static int hisi_sas_query_task(struct sas_task *task)
 
 		int_to_scsilun(cmnd->device->lun, &lun);
 		tmf_task.tmf = TMF_QUERY_TASK;
-		tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag);
+		tmf_task.tag_of_task_to_be_managed = tag;
 
 		rc = hisi_sas_debug_issue_ssp_tmf(device,
 						  lun.scsi_lun,
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
index d24342b..7186648 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
@@ -510,6 +510,7 @@ static void setup_itct_v1_hw(struct hisi_hba *hisi_hba,
 	struct hisi_sas_itct *itct = &hisi_hba->itct[device_id];
 	struct asd_sas_port *sas_port = device->port;
 	struct hisi_sas_port *port = to_hisi_sas_port(sas_port);
+	u64 sas_addr;
 
 	memset(itct, 0, sizeof(*itct));
 
@@ -534,8 +535,8 @@ static void setup_itct_v1_hw(struct hisi_hba *hisi_hba,
 	itct->qw0 = cpu_to_le64(qw0);
 
 	/* qw1 */
-	memcpy(&itct->sas_addr, device->sas_addr, SAS_ADDR_SIZE);
-	itct->sas_addr = __swab64(itct->sas_addr);
+	memcpy(&sas_addr, device->sas_addr, SAS_ADDR_SIZE);
+	itct->sas_addr = cpu_to_le64(__swab64(sas_addr));
 
 	/* qw2 */
 	itct->qw2 = cpu_to_le64((500ULL << ITCT_HDR_IT_NEXUS_LOSS_TL_OFF) |
@@ -561,7 +562,7 @@ static void clear_itct_v1_hw(struct hisi_hba *hisi_hba,
 	reg_val &= ~CFG_AGING_TIME_ITCT_REL_MSK;
 	hisi_sas_write32(hisi_hba, CFG_AGING_TIME, reg_val);
 
-	qw0 = cpu_to_le64(itct->qw0);
+	qw0 = le64_to_cpu(itct->qw0);
 	qw0 &= ~ITCT_HDR_VALID_MSK;
 	itct->qw0 = cpu_to_le64(qw0);
 }
@@ -1102,7 +1103,7 @@ static void slot_err_v1_hw(struct hisi_hba *hisi_hba,
 	case SAS_PROTOCOL_SSP:
 	{
 		int error = -1;
-		u32 dma_err_type = cpu_to_le32(err_record->dma_err_type);
+		u32 dma_err_type = le32_to_cpu(err_record->dma_err_type);
 		u32 dma_tx_err_type = ((dma_err_type &
 					ERR_HDR_DMA_TX_ERR_TYPE_MSK)) >>
 					ERR_HDR_DMA_TX_ERR_TYPE_OFF;
@@ -1110,9 +1111,9 @@ static void slot_err_v1_hw(struct hisi_hba *hisi_hba,
 					ERR_HDR_DMA_RX_ERR_TYPE_MSK)) >>
 					ERR_HDR_DMA_RX_ERR_TYPE_OFF;
 		u32 trans_tx_fail_type =
-				cpu_to_le32(err_record->trans_tx_fail_type);
+				le32_to_cpu(err_record->trans_tx_fail_type);
 		u32 trans_rx_fail_type =
-				cpu_to_le32(err_record->trans_rx_fail_type);
+				le32_to_cpu(err_record->trans_rx_fail_type);
 
 		if (dma_tx_err_type) {
 			/* dma tx err */
@@ -1560,7 +1561,7 @@ static irqreturn_t cq_interrupt_v1_hw(int irq, void *p)
 		u32 cmplt_hdr_data;
 
 		complete_hdr = &complete_queue[rd_point];
-		cmplt_hdr_data = cpu_to_le32(complete_hdr->data);
+		cmplt_hdr_data = le32_to_cpu(complete_hdr->data);
 		idx = (cmplt_hdr_data & CMPLT_HDR_IPTT_MSK) >>
 		      CMPLT_HDR_IPTT_OFF;
 		slot = &hisi_hba->slot_info[idx];
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index e78a97e..8580c71 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -934,6 +934,7 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba,
 	struct domain_device *parent_dev = device->parent;
 	struct asd_sas_port *sas_port = device->port;
 	struct hisi_sas_port *port = to_hisi_sas_port(sas_port);
+	u64 sas_addr;
 
 	memset(itct, 0, sizeof(*itct));
 
@@ -966,8 +967,8 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba,
 	itct->qw0 = cpu_to_le64(qw0);
 
 	/* qw1 */
-	memcpy(&itct->sas_addr, device->sas_addr, SAS_ADDR_SIZE);
-	itct->sas_addr = __swab64(itct->sas_addr);
+	memcpy(&sas_addr, device->sas_addr, SAS_ADDR_SIZE);
+	itct->sas_addr = cpu_to_le64(__swab64(sas_addr));
 
 	/* qw2 */
 	if (!dev_is_sata(device))
@@ -2046,11 +2047,11 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 	struct task_status_struct *ts = &task->task_status;
 	struct hisi_sas_err_record_v2 *err_record =
 			hisi_sas_status_buf_addr_mem(slot);
-	u32 trans_tx_fail_type = cpu_to_le32(err_record->trans_tx_fail_type);
-	u32 trans_rx_fail_type = cpu_to_le32(err_record->trans_rx_fail_type);
-	u16 dma_tx_err_type = cpu_to_le16(err_record->dma_tx_err_type);
-	u16 sipc_rx_err_type = cpu_to_le16(err_record->sipc_rx_err_type);
-	u32 dma_rx_err_type = cpu_to_le32(err_record->dma_rx_err_type);
+	u32 trans_tx_fail_type = le32_to_cpu(err_record->trans_tx_fail_type);
+	u32 trans_rx_fail_type = le32_to_cpu(err_record->trans_rx_fail_type);
+	u16 dma_tx_err_type = le16_to_cpu(err_record->dma_tx_err_type);
+	u16 sipc_rx_err_type = le16_to_cpu(err_record->sipc_rx_err_type);
+	u32 dma_rx_err_type = le32_to_cpu(err_record->dma_rx_err_type);
 	int error = -1;
 
 	if (err_phase == 1) {
@@ -2061,8 +2062,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 					trans_tx_fail_type);
 	} else if (err_phase == 2) {
 		/* error in RX phase, the priority is: DW1 > DW3 > DW2 */
-		error = parse_trans_rx_err_code_v2_hw(
-					trans_rx_fail_type);
+		error = parse_trans_rx_err_code_v2_hw(trans_rx_fail_type);
 		if (error == -1) {
 			error = parse_dma_rx_err_code_v2_hw(
 					dma_rx_err_type);
@@ -2360,6 +2360,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 			&complete_queue[slot->cmplt_queue_slot];
 	unsigned long flags;
 	bool is_internal = slot->is_internal;
+	u32 dw0;
 
 	if (unlikely(!task || !task->lldd_task || !task->dev))
 		return -EINVAL;
@@ -2384,8 +2385,9 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 	}
 
 	/* Use SAS+TMF status codes */
-	switch ((complete_hdr->dw0 & CMPLT_HDR_ABORT_STAT_MSK)
-			>> CMPLT_HDR_ABORT_STAT_OFF) {
+	dw0 = le32_to_cpu(complete_hdr->dw0);
+	switch ((dw0 & CMPLT_HDR_ABORT_STAT_MSK) >>
+		CMPLT_HDR_ABORT_STAT_OFF) {
 	case STAT_IO_ABORTED:
 		/* this io has been aborted by abort command */
 		ts->stat = SAS_ABORTED_TASK;
@@ -2410,9 +2412,8 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
 		break;
 	}
 
-	if ((complete_hdr->dw0 & CMPLT_HDR_ERX_MSK) &&
-		(!(complete_hdr->dw0 & CMPLT_HDR_RSPNS_XFRD_MSK))) {
-		u32 err_phase = (complete_hdr->dw0 & CMPLT_HDR_ERR_PHASE_MSK)
+	if ((dw0 & CMPLT_HDR_ERX_MSK) && (!(dw0 & CMPLT_HDR_RSPNS_XFRD_MSK))) {
+		u32 err_phase = (dw0 & CMPLT_HDR_ERR_PHASE_MSK)
 				>> CMPLT_HDR_ERR_PHASE_OFF;
 		u32 *error_info = hisi_sas_status_buf_addr_mem(slot);
 
@@ -2528,22 +2529,23 @@ static void prep_ata_v2_hw(struct hisi_hba *hisi_hba,
 	struct hisi_sas_tmf_task *tmf = slot->tmf;
 	u8 *buf_cmd;
 	int has_data = 0, hdr_tag = 0;
-	u32 dw1 = 0, dw2 = 0;
+	u32 dw0, dw1 = 0, dw2 = 0;
 
 	/* create header */
 	/* dw0 */
-	hdr->dw0 = cpu_to_le32(port->id << CMD_HDR_PORT_OFF);
+	dw0 = port->id << CMD_HDR_PORT_OFF;
 	if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
-		hdr->dw0 |= cpu_to_le32(3 << CMD_HDR_CMD_OFF);
+		dw0 |= 3 << CMD_HDR_CMD_OFF;
 	else
-		hdr->dw0 |= cpu_to_le32(4 << CMD_HDR_CMD_OFF);
+		dw0 |= 4 << CMD_HDR_CMD_OFF;
 
 	if (tmf && tmf->force_phy) {
-		hdr->dw0 |= CMD_HDR_FORCE_PHY_MSK;
-		hdr->dw0 |= cpu_to_le32((1 << tmf->phy_id)
-				<< CMD_HDR_PHY_ID_OFF);
+		dw0 |= CMD_HDR_FORCE_PHY_MSK;
+		dw0 |= (1 << tmf->phy_id) << CMD_HDR_PHY_ID_OFF;
 	}
 
+	hdr->dw0 = cpu_to_le32(dw0);
+
 	/* dw1 */
 	switch (task->data_dir) {
 	case DMA_TO_DEVICE:
@@ -3154,20 +3156,24 @@ static void cq_tasklet_v2_hw(unsigned long val)
 
 		/* Check for NCQ completion */
 		if (complete_hdr->act) {
-			u32 act_tmp = complete_hdr->act;
+			u32 act_tmp = le32_to_cpu(complete_hdr->act);
 			int ncq_tag_count = ffs(act_tmp);
+			u32 dw1 = le32_to_cpu(complete_hdr->dw1);
 
-			dev_id = (complete_hdr->dw1 & CMPLT_HDR_DEV_ID_MSK) >>
+			dev_id = (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];
+				__le64 *_ncq_tag = &itct->qw4_15[0], __ncq_tag;
+				u64 ncq_tag;
 
-				ncq_tag_count -= 1;
-				iptt = (ncq_tag[ncq_tag_count / 5]
-					>> (ncq_tag_count % 5) * 12) & 0xfff;
+				ncq_tag_count--;
+				__ncq_tag = _ncq_tag[ncq_tag_count / 5];
+				ncq_tag = le64_to_cpu(__ncq_tag);
+				iptt = (ncq_tag >> (ncq_tag_count % 5) * 12) &
+				       0xfff;
 
 				slot = &hisi_hba->slot_info[iptt];
 				slot->cmplt_queue_slot = rd_point;
@@ -3178,7 +3184,9 @@ static void cq_tasklet_v2_hw(unsigned long val)
 				ncq_tag_count = ffs(act_tmp);
 			}
 		} else {
-			iptt = (complete_hdr->dw1) & CMPLT_HDR_IPTT_MSK;
+			u32 dw1 = le32_to_cpu(complete_hdr->dw1);
+
+			iptt = dw1 & CMPLT_HDR_IPTT_MSK;
 			slot = &hisi_hba->slot_info[iptt];
 			slot->cmplt_queue_slot = rd_point;
 			slot->cmplt_queue = queue;
@@ -3554,7 +3562,7 @@ static void wait_cmds_complete_timeout_v2_hw(struct hisi_hba *hisi_hba,
 	dev_dbg(dev, "wait commands complete %dms\n", time);
 }
 
-struct device_attribute *host_attrs_v2_hw[] = {
+static struct device_attribute *host_attrs_v2_hw[] = {
 	&dev_attr_phy_event_threshold,
 	NULL
 };
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 7e2b020..59b5f64 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -628,6 +628,7 @@ static void setup_itct_v3_hw(struct hisi_hba *hisi_hba,
 	struct domain_device *parent_dev = device->parent;
 	struct asd_sas_port *sas_port = device->port;
 	struct hisi_sas_port *port = to_hisi_sas_port(sas_port);
+	u64 sas_addr;
 
 	memset(itct, 0, sizeof(*itct));
 
@@ -660,8 +661,8 @@ static void setup_itct_v3_hw(struct hisi_hba *hisi_hba,
 	itct->qw0 = cpu_to_le64(qw0);
 
 	/* qw1 */
-	memcpy(&itct->sas_addr, device->sas_addr, SAS_ADDR_SIZE);
-	itct->sas_addr = __swab64(itct->sas_addr);
+	memcpy(&sas_addr, device->sas_addr, SAS_ADDR_SIZE);
+	itct->sas_addr = cpu_to_le64(__swab64(sas_addr));
 
 	/* qw2 */
 	if (!dev_is_sata(device))
@@ -1592,15 +1593,16 @@ static irqreturn_t fatal_axi_int_v3_hw(int irq_no, void *p)
 			&complete_queue[slot->cmplt_queue_slot];
 	struct hisi_sas_err_record_v3 *record =
 			hisi_sas_status_buf_addr_mem(slot);
-	u32 dma_rx_err_type = record->dma_rx_err_type;
-	u32 trans_tx_fail_type = record->trans_tx_fail_type;
+	u32 dma_rx_err_type = le32_to_cpu(record->dma_rx_err_type);
+	u32 trans_tx_fail_type = le32_to_cpu(record->trans_tx_fail_type);
+	u32 dw3 = le32_to_cpu(complete_hdr->dw3);
 
 	switch (task->task_proto) {
 	case SAS_PROTOCOL_SSP:
 		if (dma_rx_err_type & RX_DATA_LEN_UNDERFLOW_MSK) {
 			ts->residual = trans_tx_fail_type;
 			ts->stat = SAS_DATA_UNDERRUN;
-		} else if (complete_hdr->dw3 & CMPLT_HDR_IO_IN_TARGET_MSK) {
+		} else if (dw3 & CMPLT_HDR_IO_IN_TARGET_MSK) {
 			ts->stat = SAS_QUEUE_FULL;
 			slot->abort = 1;
 		} else {
@@ -1614,7 +1616,7 @@ static irqreturn_t fatal_axi_int_v3_hw(int irq_no, void *p)
 		if (dma_rx_err_type & RX_DATA_LEN_UNDERFLOW_MSK) {
 			ts->residual = trans_tx_fail_type;
 			ts->stat = SAS_DATA_UNDERRUN;
-		} else if (complete_hdr->dw3 & CMPLT_HDR_IO_IN_TARGET_MSK) {
+		} else if (dw3 & CMPLT_HDR_IO_IN_TARGET_MSK) {
 			ts->stat = SAS_PHY_DOWN;
 			slot->abort = 1;
 		} else {
@@ -1647,6 +1649,7 @@ static irqreturn_t fatal_axi_int_v3_hw(int irq_no, void *p)
 			&complete_queue[slot->cmplt_queue_slot];
 	unsigned long flags;
 	bool is_internal = slot->is_internal;
+	u32 dw0, dw1, dw3;
 
 	if (unlikely(!task || !task->lldd_task || !task->dev))
 		return -EINVAL;
@@ -1670,11 +1673,14 @@ static irqreturn_t fatal_axi_int_v3_hw(int irq_no, void *p)
 		goto out;
 	}
 
+	dw0 = le32_to_cpu(complete_hdr->dw0);
+	dw1 = le32_to_cpu(complete_hdr->dw1);
+	dw3 = le32_to_cpu(complete_hdr->dw3);
+
 	/*
 	 * Use SAS+TMF status codes
 	 */
-	switch ((complete_hdr->dw0 & CMPLT_HDR_ABORT_STAT_MSK)
-			>> CMPLT_HDR_ABORT_STAT_OFF) {
+	switch ((dw0 & CMPLT_HDR_ABORT_STAT_MSK) >> CMPLT_HDR_ABORT_STAT_OFF) {
 	case STAT_IO_ABORTED:
 		/* this IO has been aborted by abort command */
 		ts->stat = SAS_ABORTED_TASK;
@@ -1697,7 +1703,7 @@ 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) {
+	if ((dw0 & CMPLT_HDR_CMPLT_MSK) == 0x3) {
 		u32 *error_info = hisi_sas_status_buf_addr_mem(slot);
 
 		slot_err_v3_hw(hisi_hba, task, slot);
@@ -1706,8 +1712,7 @@ static irqreturn_t fatal_axi_int_v3_hw(int irq_no, void *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, sas_dev->device_id,
-				complete_hdr->dw0, complete_hdr->dw1,
-				complete_hdr->act, complete_hdr->dw3,
+				dw0, dw1, complete_hdr->act, dw3,
 				error_info[0], error_info[1],
 				error_info[2], error_info[3]);
 		if (unlikely(slot->abort))
@@ -1805,11 +1810,13 @@ static void cq_tasklet_v3_hw(unsigned long val)
 	while (rd_point != wr_point) {
 		struct hisi_sas_complete_v3_hdr *complete_hdr;
 		struct device *dev = hisi_hba->dev;
+		u32 dw1;
 		int iptt;
 
 		complete_hdr = &complete_queue[rd_point];
+		dw1 = le32_to_cpu(complete_hdr->dw1);
 
-		iptt = (complete_hdr->dw1) & CMPLT_HDR_IPTT_MSK;
+		iptt = dw1 & CMPLT_HDR_IPTT_MSK;
 		if (likely(iptt < HISI_SAS_COMMAND_ENTRIES_V3_HW)) {
 			slot = &hisi_hba->slot_info[iptt];
 			slot->cmplt_queue_slot = rd_point;
@@ -2205,7 +2212,7 @@ static ssize_t intr_coal_count_v3_hw_store(struct device *dev,
 }
 static DEVICE_ATTR_RW(intr_coal_count_v3_hw);
 
-struct device_attribute *host_attrs_v3_hw[] = {
+static struct device_attribute *host_attrs_v3_hw[] = {
 	&dev_attr_phy_event_threshold,
 	&dev_attr_intr_conv_v3_hw,
 	&dev_attr_intr_coal_ticks_v3_hw,
@@ -2651,7 +2658,7 @@ static int hisi_sas_v3_suspend(struct pci_dev *pdev, pm_message_t state)
 	struct hisi_hba *hisi_hba = sha->lldd_ha;
 	struct device *dev = hisi_hba->dev;
 	struct Scsi_Host *shost = hisi_hba->shost;
-	u32 device_state;
+	pci_power_t device_state;
 	int rc;
 
 	if (!pdev->pm_cap) {
@@ -2697,7 +2704,7 @@ static int hisi_sas_v3_resume(struct pci_dev *pdev)
 	struct Scsi_Host *shost = hisi_hba->shost;
 	struct device *dev = hisi_hba->dev;
 	unsigned int rc;
-	u32 device_state = pdev->current_state;
+	pci_power_t device_state = pdev->current_state;
 
 	dev_warn(dev, "resuming from operating state [D%d]\n",
 			device_state);
-- 
1.9.1


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

* [PATCH v4 2/5] scsi: hisi_sas: Relocate some code to reduce complexity
  2018-12-06 13:34 [PATCH v4 0/5] hisi_sas: DIF support John Garry
  2018-12-06 13:34 ` [PATCH v4 1/5] scsi: hisi_sas: Fix warnings detected by sparse John Garry
@ 2018-12-06 13:34 ` John Garry
  2018-12-06 14:17   ` Johannes Thumshirn
  2018-12-06 13:34 ` [PATCH v4 3/5] scsi: hisi_sas: Make sg_tablesize consistent value John Garry
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 16+ messages in thread
From: John Garry @ 2018-12-06 13:34 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-kernel, linux-scsi, Xiang Chen, John Garry

From: Xiang Chen <chenxiang66@hisilicon.com>

Relocate the codes related to dma_map/unmap in hisi_sas_task_prep()
to reduce complexity, with a view to add DIF/DIX support.

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 | 146 +++++++++++++++++++++-------------
 1 file changed, 90 insertions(+), 56 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index c39c91c..95350fd 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -296,6 +296,90 @@ static void hisi_sas_task_prep_abort(struct hisi_hba *hisi_hba,
 			device_id, abort_flag, tag_to_abort);
 }
 
+static void hisi_sas_dma_unmap(struct hisi_hba *hisi_hba,
+			       struct sas_task *task, int n_elem,
+			       int n_elem_req, int n_elem_resp)
+{
+	struct device *dev = hisi_hba->dev;
+
+	if (!sas_protocol_ata(task->task_proto)) {
+		if (task->num_scatter) {
+			if (n_elem)
+				dma_unmap_sg(dev, task->scatter,
+					     task->num_scatter,
+					     task->data_dir);
+		} else if (task->task_proto & SAS_PROTOCOL_SMP) {
+			if (n_elem_req)
+				dma_unmap_sg(dev, &task->smp_task.smp_req,
+					     1, DMA_TO_DEVICE);
+			if (n_elem_resp)
+				dma_unmap_sg(dev, &task->smp_task.smp_resp,
+					     1, DMA_FROM_DEVICE);
+		}
+	}
+}
+
+static int hisi_sas_dma_map(struct hisi_hba *hisi_hba,
+			    struct sas_task *task, int *n_elem,
+			    int *n_elem_req, int *n_elem_resp)
+{
+	struct device *dev = hisi_hba->dev;
+	int rc;
+
+	if (sas_protocol_ata(task->task_proto)) {
+		*n_elem = task->num_scatter;
+	} else {
+		unsigned int req_len, resp_len;
+
+		if (task->num_scatter) {
+			*n_elem = dma_map_sg(dev, task->scatter,
+					     task->num_scatter, task->data_dir);
+			if (!*n_elem) {
+				rc = -ENOMEM;
+				goto prep_out;
+			}
+		} else if (task->task_proto & SAS_PROTOCOL_SMP) {
+			*n_elem_req = dma_map_sg(dev, &task->smp_task.smp_req,
+						 1, DMA_TO_DEVICE);
+			if (!*n_elem_req) {
+				rc = -ENOMEM;
+				goto prep_out;
+			}
+			req_len = sg_dma_len(&task->smp_task.smp_req);
+			if (req_len & 0x3) {
+				rc = -EINVAL;
+				goto err_out_dma_unmap;
+			}
+			*n_elem_resp = dma_map_sg(dev, &task->smp_task.smp_resp,
+						  1, DMA_FROM_DEVICE);
+			if (!*n_elem_resp) {
+				rc = -ENOMEM;
+				goto err_out_dma_unmap;
+			}
+			resp_len = sg_dma_len(&task->smp_task.smp_resp);
+			if (resp_len & 0x3) {
+				rc = -EINVAL;
+				goto err_out_dma_unmap;
+			}
+		}
+	}
+
+	if (*n_elem > HISI_SAS_SGE_PAGE_CNT) {
+		dev_err(dev, "task prep: n_elem(%d) > HISI_SAS_SGE_PAGE_CNT",
+			*n_elem);
+		rc = -EINVAL;
+		goto err_out_dma_unmap;
+	}
+	return 0;
+
+err_out_dma_unmap:
+	/* It would be better to call dma_unmap_sg() here, but it's messy */
+	hisi_sas_dma_unmap(hisi_hba, task, *n_elem,
+			   *n_elem_req, *n_elem_resp);
+prep_out:
+	return rc;
+}
+
 static int hisi_sas_task_prep(struct sas_task *task,
 			      struct hisi_sas_dq **dq_pointer,
 			      bool is_tmf, struct hisi_sas_tmf_task *tmf,
@@ -338,49 +422,10 @@ static int hisi_sas_task_prep(struct sas_task *task,
 		return -ECOMM;
 	}
 
-	if (!sas_protocol_ata(task->task_proto)) {
-		unsigned int req_len, resp_len;
-
-		if (task->num_scatter) {
-			n_elem = dma_map_sg(dev, task->scatter,
-					    task->num_scatter, task->data_dir);
-			if (!n_elem) {
-				rc = -ENOMEM;
-				goto prep_out;
-			}
-		} else if (task->task_proto & SAS_PROTOCOL_SMP) {
-			n_elem_req = dma_map_sg(dev, &task->smp_task.smp_req,
-						1, DMA_TO_DEVICE);
-			if (!n_elem_req) {
-				rc = -ENOMEM;
-				goto prep_out;
-			}
-			req_len = sg_dma_len(&task->smp_task.smp_req);
-			if (req_len & 0x3) {
-				rc = -EINVAL;
-				goto err_out_dma_unmap;
-			}
-			n_elem_resp = dma_map_sg(dev, &task->smp_task.smp_resp,
-						 1, DMA_FROM_DEVICE);
-			if (!n_elem_resp) {
-				rc = -ENOMEM;
-				goto err_out_dma_unmap;
-			}
-			resp_len = sg_dma_len(&task->smp_task.smp_resp);
-			if (resp_len & 0x3) {
-				rc = -EINVAL;
-				goto err_out_dma_unmap;
-			}
-		}
-	} else
-		n_elem = task->num_scatter;
-
-	if (n_elem > HISI_SAS_SGE_PAGE_CNT) {
-		dev_err(dev, "task prep: n_elem(%d) > HISI_SAS_SGE_PAGE_CNT",
-			n_elem);
-		rc = -EINVAL;
-		goto err_out_dma_unmap;
-	}
+	rc = hisi_sas_dma_map(hisi_hba, task, &n_elem,
+			      &n_elem_req, &n_elem_resp);
+	if (rc < 0)
+		goto prep_out;
 
 	if (hisi_hba->hw->slot_index_alloc)
 		rc = hisi_hba->hw->slot_index_alloc(hisi_hba, device);
@@ -465,19 +510,8 @@ static int hisi_sas_task_prep(struct sas_task *task,
 err_out_tag:
 	hisi_sas_slot_index_free(hisi_hba, slot_idx);
 err_out_dma_unmap:
-	if (!sas_protocol_ata(task->task_proto)) {
-		if (task->num_scatter) {
-			dma_unmap_sg(dev, task->scatter, task->num_scatter,
-			     task->data_dir);
-		} else if (task->task_proto & SAS_PROTOCOL_SMP) {
-			if (n_elem_req)
-				dma_unmap_sg(dev, &task->smp_task.smp_req,
-					     1, DMA_TO_DEVICE);
-			if (n_elem_resp)
-				dma_unmap_sg(dev, &task->smp_task.smp_resp,
-					     1, DMA_FROM_DEVICE);
-		}
-	}
+	hisi_sas_dma_unmap(hisi_hba, task, n_elem,
+			   n_elem_req, n_elem_resp);
 prep_out:
 	dev_err(dev, "task prep: failed[%d]!\n", rc);
 	return rc;
-- 
1.9.1


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

* [PATCH v4 3/5] scsi: hisi_sas: Make sg_tablesize consistent value
  2018-12-06 13:34 [PATCH v4 0/5] hisi_sas: DIF support John Garry
  2018-12-06 13:34 ` [PATCH v4 1/5] scsi: hisi_sas: Fix warnings detected by sparse John Garry
  2018-12-06 13:34 ` [PATCH v4 2/5] scsi: hisi_sas: Relocate some code to reduce complexity John Garry
@ 2018-12-06 13:34 ` John Garry
  2018-12-06 13:34 ` [PATCH v4 4/5] scsi: hisi_sas: Add support for DIF feature for v3 hw John Garry
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: John Garry @ 2018-12-06 13:34 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-kernel, linux-scsi, Xiang Chen, John Garry

From: Xiang Chen <chenxiang66@hisilicon.com>

Sht->sg_tablesize is set in the driver, and it will be assigned to
shost->sg_tablesize in SCSI mid-layer. So it is not necessary to
assign shost->sg_table one more time in the driver.

In addition to the change, change each scsi_host_template.sg_tablesize
to HISI_SAS_SGE_PAGE_CNT instead of SG_ALL.

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 -
 drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 2 +-
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 2 +-
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 3 +--
 4 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 95350fd..eed7fc5 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -2410,7 +2410,6 @@ int hisi_sas_probe(struct platform_device *pdev,
 	shost->max_lun = ~0;
 	shost->max_channel = 1;
 	shost->max_cmd_len = 16;
-	shost->sg_tablesize = min_t(u16, SG_ALL, HISI_SAS_SGE_PAGE_CNT);
 	if (hisi_hba->hw->slot_index_alloc) {
 		shost->can_queue = hisi_hba->hw->max_command_entries;
 		shost->cmd_per_lun = hisi_hba->hw->max_command_entries;
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
index 7186648..107f7c9 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
@@ -1816,7 +1816,7 @@ static int hisi_sas_v1_init(struct hisi_hba *hisi_hba)
 	.change_queue_depth	= sas_change_queue_depth,
 	.bios_param		= sas_bios_param,
 	.this_id		= -1,
-	.sg_tablesize		= SG_ALL,
+	.sg_tablesize		= HISI_SAS_SGE_PAGE_CNT,
 	.max_sectors		= SCSI_DEFAULT_MAX_SECTORS,
 	.use_clustering		= ENABLE_CLUSTERING,
 	.eh_device_reset_handler = sas_eh_device_reset_handler,
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index 8580c71..8760987 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -3578,7 +3578,7 @@ static void wait_cmds_complete_timeout_v2_hw(struct hisi_hba *hisi_hba,
 	.change_queue_depth	= sas_change_queue_depth,
 	.bios_param		= sas_bios_param,
 	.this_id		= -1,
-	.sg_tablesize		= SG_ALL,
+	.sg_tablesize		= HISI_SAS_SGE_PAGE_CNT,
 	.max_sectors		= SCSI_DEFAULT_MAX_SECTORS,
 	.use_clustering		= ENABLE_CLUSTERING,
 	.eh_device_reset_handler = sas_eh_device_reset_handler,
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 59b5f64..44781e3 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -2231,7 +2231,7 @@ static ssize_t intr_coal_count_v3_hw_store(struct device *dev,
 	.change_queue_depth	= sas_change_queue_depth,
 	.bios_param		= sas_bios_param,
 	.this_id		= -1,
-	.sg_tablesize		= SG_ALL,
+	.sg_tablesize		= HISI_SAS_SGE_PAGE_CNT,
 	.max_sectors		= SCSI_DEFAULT_MAX_SECTORS,
 	.use_clustering		= ENABLE_CLUSTERING,
 	.eh_device_reset_handler = sas_eh_device_reset_handler,
@@ -2373,7 +2373,6 @@ static ssize_t intr_coal_count_v3_hw_store(struct device *dev,
 	shost->max_lun = ~0;
 	shost->max_channel = 1;
 	shost->max_cmd_len = 16;
-	shost->sg_tablesize = min_t(u16, SG_ALL, HISI_SAS_SGE_PAGE_CNT);
 	shost->can_queue = hisi_hba->hw->max_command_entries -
 		HISI_SAS_RESERVED_IPTT_CNT;
 	shost->cmd_per_lun = hisi_hba->hw->max_command_entries -
-- 
1.9.1


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

* [PATCH v4 4/5] scsi: hisi_sas: Add support for DIF feature for v3 hw
  2018-12-06 13:34 [PATCH v4 0/5] hisi_sas: DIF support John Garry
                   ` (2 preceding siblings ...)
  2018-12-06 13:34 ` [PATCH v4 3/5] scsi: hisi_sas: Make sg_tablesize consistent value John Garry
@ 2018-12-06 13:34 ` John Garry
  2018-12-13  2:20   ` Martin K. Petersen
  2018-12-06 13:34 ` [RFC PATCH v4 5/5] scsi: hisi_sas: Add support for DIX feature for v3 hw as experimental John Garry
  2018-12-13  2:23 ` [PATCH v4 0/5] hisi_sas: DIF support Martin K. Petersen
  5 siblings, 1 reply; 16+ messages in thread
From: John Garry @ 2018-12-06 13:34 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-kernel, linux-scsi, Xiang Chen, John Garry

From: Xiang Chen <chenxiang66@hisilicon.com>

For v3 hw, we support DIF operation for SAS, but not SATA.

This patchset adds the SW support for the described features. The main
components are as follows:
- Get DIF enablement from module param
- Fill PI fields
- Fill related to DIF in DQ and protection iu memories

Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas.h       |   2 +
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 122 ++++++++++++++++++++++++++++++++-
 2 files changed, 121 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index 912d234..5c780fe 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -268,6 +268,8 @@ struct hisi_hba {
 	struct pci_dev *pci_dev;
 	struct device *dev;
 
+	bool enable_dif;
+
 	void __iomem *regs;
 	void __iomem *sgpio_regs;
 	struct regmap *ctrl;
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 44781e3..c707bb1 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -127,6 +127,8 @@
 #define PHY_CTRL			(PORT_BASE + 0x14)
 #define PHY_CTRL_RESET_OFF		0
 #define PHY_CTRL_RESET_MSK		(0x1 << PHY_CTRL_RESET_OFF)
+#define CMD_HDR_PIR_OFF			8
+#define CMD_HDR_PIR_MSK			(0x1 << CMD_HDR_PIR_OFF)
 #define SL_CFG				(PORT_BASE + 0x84)
 #define AIP_LIMIT			(PORT_BASE + 0x90)
 #define SL_CONTROL			(PORT_BASE + 0x94)
@@ -333,6 +335,16 @@
 #define ITCT_HDR_RTOLT_OFF		48
 #define ITCT_HDR_RTOLT_MSK		(0xffffULL << ITCT_HDR_RTOLT_OFF)
 
+struct hisi_sas_protect_iu_v3_hw {
+	u32 dw0;
+	u32 lbrtcv;
+	u32 lbrtgv;
+	u32 dw3;
+	u32 dw4;
+	u32 dw5;
+	u32 rsv;
+};
+
 struct hisi_sas_complete_v3_hdr {
 	__le32 dw0;
 	__le32 dw1;
@@ -372,9 +384,27 @@ struct hisi_sas_err_record_v3 {
 	((fis.command == ATA_CMD_DEV_RESET) && \
 	((fis.control & ATA_SRST) != 0)))
 
+#define T10_INSRT_EN_OFF    0
+#define T10_INSRT_EN_MSK    (1 << T10_INSRT_EN_OFF)
+#define T10_RMV_EN_OFF	    1
+#define T10_RMV_EN_MSK	    (1 << T10_RMV_EN_OFF)
+#define T10_RPLC_EN_OFF	    2
+#define T10_RPLC_EN_MSK	    (1 << T10_RPLC_EN_OFF)
+#define T10_CHK_EN_OFF	    3
+#define T10_CHK_EN_MSK	    (1 << T10_CHK_EN_OFF)
+#define INCR_LBRT_OFF	    5
+#define INCR_LBRT_MSK	    (1 << INCR_LBRT_OFF)
+#define USR_DATA_BLOCK_SZ_OFF	20
+#define USR_DATA_BLOCK_SZ_MSK	(0x3 << USR_DATA_BLOCK_SZ_OFF)
+#define T10_CHK_MSK_OFF	    16
+
 static bool hisi_sas_intr_conv;
 MODULE_PARM_DESC(intr_conv, "interrupt converge enable (0-1)");
 
+static bool enable_dif;
+module_param(enable_dif, bool, 0444);
+MODULE_PARM_DESC(enable_dif, "DIF enable (0-1)");
+
 static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off)
 {
 	void __iomem *regs = hisi_hba->regs + off;
@@ -941,6 +971,54 @@ static void prep_prd_sge_v3_hw(struct hisi_hba *hisi_hba,
 	hdr->sg_len = cpu_to_le32(n_elem << CMD_HDR_DATA_SGL_LEN_OFF);
 }
 
+static void fill_prot_v3_hw(struct scsi_cmnd *scsi_cmnd,
+			    struct hisi_sas_protect_iu_v3_hw *prot)
+{
+	u8 prot_type = scsi_get_prot_type(scsi_cmnd);
+	u8 prot_op = scsi_get_prot_op(scsi_cmnd);
+	unsigned int interval = scsi_prot_interval(scsi_cmnd);
+	u32 lbrt_chk_val;
+
+	if (interval == 4096)
+		lbrt_chk_val = (u32)(scsi_get_lba(scsi_cmnd) >> 3);
+	else
+		lbrt_chk_val = (u32)scsi_get_lba(scsi_cmnd);
+
+	switch (prot_op) {
+	case SCSI_PROT_READ_STRIP:
+		prot->dw0 |= (T10_RMV_EN_MSK | T10_CHK_EN_MSK);
+		prot->lbrtcv = lbrt_chk_val;
+		if (prot_type == SCSI_PROT_DIF_TYPE1)
+			prot->dw4 |= (0xc << 16);
+		else if (prot_type == SCSI_PROT_DIF_TYPE3)
+			prot->dw4 |= (0xfc << 16);
+		break;
+	case SCSI_PROT_WRITE_INSERT:
+		prot->dw0 |= T10_INSRT_EN_MSK;
+		prot->lbrtgv = lbrt_chk_val;
+		break;
+	default:
+		WARN_ONCE(1, "prot_op(0x%x) is not valid\n", prot_op);
+		break;
+	}
+
+	switch (interval) {
+	case 512:
+		break;
+	case 4096:
+		prot->dw0 |= (0x1 << USR_DATA_BLOCK_SZ_OFF);
+		break;
+	case 520:
+		prot->dw0 |= (0x2 << USR_DATA_BLOCK_SZ_OFF);
+		break;
+	default:
+		WARN_ONCE(1, "protection interval (0x%x) invalid\n", interval);
+		break;
+	}
+
+	prot->dw0 |= INCR_LBRT_MSK;
+}
+
 static void prep_ssp_v3_hw(struct hisi_hba *hisi_hba,
 			  struct hisi_sas_slot *slot)
 {
@@ -952,9 +1030,10 @@ static void prep_ssp_v3_hw(struct hisi_hba *hisi_hba,
 	struct sas_ssp_task *ssp_task = &task->ssp_task;
 	struct scsi_cmnd *scsi_cmnd = ssp_task->cmd;
 	struct hisi_sas_tmf_task *tmf = slot->tmf;
+	unsigned char prot_op = scsi_get_prot_op(scsi_cmnd);
 	int has_data = 0, priority = !!tmf;
 	u8 *buf_cmd;
-	u32 dw1 = 0, dw2 = 0;
+	u32 dw1 = 0, dw2 = 0, len = 0;
 
 	hdr->dw0 = cpu_to_le32((1 << CMD_HDR_RESP_REPORT_OFF) |
 			       (2 << CMD_HDR_TLR_CTRL_OFF) |
@@ -984,7 +1063,6 @@ static void prep_ssp_v3_hw(struct hisi_hba *hisi_hba,
 
 	/* map itct entry */
 	dw1 |= sas_dev->device_id << CMD_HDR_DEV_ID_OFF;
-	hdr->dw1 = cpu_to_le32(dw1);
 
 	dw2 = (((sizeof(struct ssp_command_iu) + sizeof(struct ssp_frame_hdr)
 	      + 3) / 4) << CMD_HDR_CFL_OFF) |
@@ -997,7 +1075,6 @@ static void prep_ssp_v3_hw(struct hisi_hba *hisi_hba,
 		prep_prd_sge_v3_hw(hisi_hba, slot, hdr, task->scatter,
 					slot->n_elem);
 
-	hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len);
 	hdr->cmd_table_addr = cpu_to_le64(hisi_sas_cmd_hdr_addr_dma(slot));
 	hdr->sts_buffer_addr = cpu_to_le64(hisi_sas_status_buf_addr_dma(slot));
 
@@ -1022,6 +1099,33 @@ static void prep_ssp_v3_hw(struct hisi_hba *hisi_hba,
 			break;
 		}
 	}
+
+	if (has_data && (prot_op != SCSI_PROT_NORMAL)) {
+		struct hisi_sas_protect_iu_v3_hw prot;
+		u8 *buf_cmd_prot;
+
+		hdr->dw7 |= cpu_to_le32(1 << CMD_HDR_ADDR_MODE_SEL_OFF);
+		dw1 |= CMD_HDR_PIR_MSK;
+		buf_cmd_prot = hisi_sas_cmd_hdr_addr_mem(slot) +
+			       sizeof(struct ssp_frame_hdr) +
+			       sizeof(struct ssp_command_iu);
+
+		memset(&prot, 0, sizeof(struct hisi_sas_protect_iu_v3_hw));
+		fill_prot_v3_hw(scsi_cmnd, &prot);
+		memcpy(buf_cmd_prot, &prot,
+		       sizeof(struct hisi_sas_protect_iu_v3_hw));
+
+		if (prot_op == SCSI_PROT_WRITE_INSERT) {
+			unsigned int interval = scsi_prot_interval(scsi_cmnd);
+			unsigned int ilog2_interval = ilog2(interval);
+
+			len = (task->total_xfer_len >> ilog2_interval) * 8;
+		}
+	}
+
+	hdr->dw1 = cpu_to_le32(dw1);
+
+	hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len + len);
 }
 
 static void prep_smp_v3_hw(struct hisi_hba *hisi_hba,
@@ -2291,6 +2395,7 @@ static ssize_t intr_coal_count_v3_hw_store(struct device *dev,
 	hisi_hba->dev = dev;
 	hisi_hba->shost = shost;
 	SHOST_TO_SAS_HA(shost) = &hisi_hba->sha;
+	hisi_hba->enable_dif = enable_dif;
 
 	timer_setup(&hisi_hba->timer, NULL, 0);
 
@@ -2319,6 +2424,7 @@ static ssize_t intr_coal_count_v3_hw_store(struct device *dev,
 	struct asd_sas_port **arr_port;
 	struct sas_ha_struct *sha;
 	int rc, phy_nr, port_nr, i;
+	unsigned int prot;
 
 	rc = pci_enable_device(pdev);
 	if (rc)
@@ -2402,6 +2508,16 @@ static ssize_t intr_coal_count_v3_hw_store(struct device *dev,
 	if (rc)
 		goto err_out_register_ha;
 
+	prot = 0;
+	if (hisi_hba->enable_dif) {
+		dev_info(dev, "Registering for DIF type 1/2/3 protection.\n");
+		prot |=	SHOST_DIF_TYPE1_PROTECTION |
+			SHOST_DIF_TYPE2_PROTECTION |
+			SHOST_DIF_TYPE3_PROTECTION;
+	}
+
+	scsi_host_set_prot(hisi_hba->shost, prot);
+
 	scsi_scan_host(shost);
 
 	return 0;
-- 
1.9.1


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

* [RFC PATCH v4 5/5] scsi: hisi_sas: Add support for DIX feature for v3 hw as experimental
  2018-12-06 13:34 [PATCH v4 0/5] hisi_sas: DIF support John Garry
                   ` (3 preceding siblings ...)
  2018-12-06 13:34 ` [PATCH v4 4/5] scsi: hisi_sas: Add support for DIF feature for v3 hw John Garry
@ 2018-12-06 13:34 ` John Garry
  2018-12-13  2:23 ` [PATCH v4 0/5] hisi_sas: DIF support Martin K. Petersen
  5 siblings, 0 replies; 16+ messages in thread
From: John Garry @ 2018-12-06 13:34 UTC (permalink / raw)
  To: jejb, martin.petersen
  Cc: linuxarm, linux-kernel, linux-scsi, Xiang Chen, John Garry

From: Xiang Chen <chenxiang66@hisilicon.com>

This patchset adds support for DIX to v3 hw driver.

As discussed in the following thread, DIX seems to be in conflict with
SCSI MQ, so this is why we mark the support for this driver as
experimental:
https://marc.info/?l=linux-scsi&m=154392687627603&w=2,

As for cause of the issue, we cannot confirm.

As for DIX support itself, we build upon support for DIF, most
significantly is adding new DMA map and unmap paths.

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

diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index 5c780fe..acac923 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -55,6 +55,11 @@
 #define hisi_sas_sge_addr_mem(slot) hisi_sas_sge_addr(slot->buf)
 #define hisi_sas_sge_addr_dma(slot) hisi_sas_sge_addr(slot->buf_dma)
 
+#define hisi_sas_sge_dif_addr(buf) \
+	(buf + offsetof(struct hisi_sas_slot_dif_buf_table, sge_dif_page))
+#define hisi_sas_sge_dif_addr_mem(slot) hisi_sas_sge_dif_addr(slot->buf)
+#define hisi_sas_sge_dif_addr_dma(slot) hisi_sas_sge_dif_addr(slot->buf_dma)
+
 #define HISI_SAS_MAX_SSP_RESP_SZ (sizeof(struct ssp_frame_hdr) + 1024)
 #define HISI_SAS_MAX_SMP_RESP_SZ 1028
 #define HISI_SAS_MAX_STP_RESP_SZ 28
@@ -197,6 +202,7 @@ struct hisi_sas_slot {
 	struct sas_task *task;
 	struct hisi_sas_port	*port;
 	u64	n_elem;
+	u64	n_elem_dif;
 	int	dlvry_queue;
 	int	dlvry_queue_slot;
 	int	cmplt_queue;
@@ -269,6 +275,7 @@ struct hisi_hba {
 	struct device *dev;
 
 	bool enable_dif;
+	bool enable_dix_experimental;
 
 	void __iomem *regs;
 	void __iomem *sgpio_regs;
@@ -424,6 +431,11 @@ struct hisi_sas_sge_page {
 	struct hisi_sas_sge sge[HISI_SAS_SGE_PAGE_CNT];
 }  __aligned(16);
 
+#define HISI_SAS_SGE_DIF_PAGE_CNT   SG_CHUNK_SIZE
+struct hisi_sas_sge_dif_page {
+	struct hisi_sas_sge sge[HISI_SAS_SGE_DIF_PAGE_CNT];
+}  __aligned(16);
+
 struct hisi_sas_command_table_ssp {
 	struct ssp_frame_hdr hdr;
 	union {
@@ -454,6 +466,11 @@ struct hisi_sas_slot_buf_table {
 	struct hisi_sas_sge_page sge_page;
 };
 
+struct hisi_sas_slot_dif_buf_table {
+	struct hisi_sas_slot_buf_table slot_buf;
+	struct hisi_sas_sge_dif_page sge_dif_page;
+};
+
 extern struct scsi_transport_template *hisi_sas_stt;
 extern void hisi_sas_stop_phys(struct hisi_hba *hisi_hba);
 extern int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost);
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index eed7fc5..48b2b52 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -252,14 +252,21 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task,
 
 		task->lldd_task = NULL;
 
-		if (!sas_protocol_ata(task->task_proto))
+		if (!sas_protocol_ata(task->task_proto)) {
+			struct sas_ssp_task *ssp_task = &task->ssp_task;
+			struct scsi_cmnd *scsi_cmnd = ssp_task->cmd;
+
 			if (slot->n_elem)
 				dma_unmap_sg(dev, task->scatter,
 					     task->num_scatter,
 					     task->data_dir);
+			if (slot->n_elem_dif)
+				dma_unmap_sg(dev, scsi_prot_sglist(scsi_cmnd),
+					     scsi_prot_sg_count(scsi_cmnd),
+					     task->data_dir);
+		}
 	}
 
-
 	spin_lock_irqsave(&dq->lock, flags);
 	list_del_init(&slot->entry);
 	spin_unlock_irqrestore(&dq->lock, flags);
@@ -380,6 +387,59 @@ static int hisi_sas_dma_map(struct hisi_hba *hisi_hba,
 	return rc;
 }
 
+static void hisi_sas_dif_dma_unmap(struct hisi_hba *hisi_hba,
+				   struct sas_task *task, int n_elem_dif)
+{
+	struct device *dev = hisi_hba->dev;
+
+	if (n_elem_dif) {
+		struct sas_ssp_task *ssp_task = &task->ssp_task;
+		struct scsi_cmnd *scsi_cmnd = ssp_task->cmd;
+
+		dma_unmap_sg(dev, scsi_prot_sglist(scsi_cmnd),
+			     scsi_prot_sg_count(scsi_cmnd),
+			     task->data_dir);
+	}
+}
+
+static int hisi_sas_dif_dma_map(struct hisi_hba *hisi_hba,
+				int *n_elem_dif, struct sas_task *task)
+{
+	struct device *dev = hisi_hba->dev;
+	struct sas_ssp_task *ssp_task;
+	struct scsi_cmnd *scsi_cmnd;
+	int rc;
+
+	if (task->num_scatter) {
+		ssp_task = &task->ssp_task;
+		scsi_cmnd = ssp_task->cmd;
+
+		if (scsi_prot_sg_count(scsi_cmnd)) {
+			*n_elem_dif = dma_map_sg(dev,
+						 scsi_prot_sglist(scsi_cmnd),
+						 scsi_prot_sg_count(scsi_cmnd),
+						 task->data_dir);
+
+			if (!*n_elem_dif)
+				return -ENOMEM;
+
+			if (*n_elem_dif > HISI_SAS_SGE_DIF_PAGE_CNT) {
+				dev_err(dev, "task prep: n_elem_dif(%d) too large\n",
+					*n_elem_dif);
+				rc = -EINVAL;
+				goto err_out_dif_dma_unmap;
+			}
+		}
+	}
+
+	return 0;
+
+err_out_dif_dma_unmap:
+	dma_unmap_sg(dev, scsi_prot_sglist(scsi_cmnd),
+		     scsi_prot_sg_count(scsi_cmnd), task->data_dir);
+	return rc;
+}
+
 static int hisi_sas_task_prep(struct sas_task *task,
 			      struct hisi_sas_dq **dq_pointer,
 			      bool is_tmf, struct hisi_sas_tmf_task *tmf,
@@ -394,7 +454,7 @@ static int hisi_sas_task_prep(struct sas_task *task,
 	struct asd_sas_port *sas_port = device->port;
 	struct device *dev = hisi_hba->dev;
 	int dlvry_queue_slot, dlvry_queue, rc, slot_idx;
-	int n_elem = 0, n_elem_req = 0, n_elem_resp = 0;
+	int n_elem = 0, n_elem_dif = 0, n_elem_req = 0, n_elem_resp = 0;
 	struct hisi_sas_dq *dq;
 	unsigned long flags;
 	int wr_q_index;
@@ -427,6 +487,12 @@ static int hisi_sas_task_prep(struct sas_task *task,
 	if (rc < 0)
 		goto prep_out;
 
+	if (!sas_protocol_ata(task->task_proto)) {
+		rc = hisi_sas_dif_dma_map(hisi_hba, &n_elem_dif, task);
+		if (rc < 0)
+			goto err_out_dma_unmap;
+	}
+
 	if (hisi_hba->hw->slot_index_alloc)
 		rc = hisi_hba->hw->slot_index_alloc(hisi_hba, device);
 	else {
@@ -445,7 +511,7 @@ static int hisi_sas_task_prep(struct sas_task *task,
 		rc  = hisi_sas_slot_index_alloc(hisi_hba, scsi_cmnd);
 	}
 	if (rc < 0)
-		goto err_out_dma_unmap;
+		goto err_out_dif_dma_unmap;
 
 	slot_idx = rc;
 	slot = &hisi_hba->slot_info[slot_idx];
@@ -466,6 +532,7 @@ static int hisi_sas_task_prep(struct sas_task *task,
 	dlvry_queue_slot = wr_q_index;
 
 	slot->n_elem = n_elem;
+	slot->n_elem_dif = n_elem_dif;
 	slot->dlvry_queue = dlvry_queue;
 	slot->dlvry_queue_slot = dlvry_queue_slot;
 	cmd_hdr_base = hisi_hba->cmd_hdr[dlvry_queue];
@@ -509,6 +576,9 @@ static int hisi_sas_task_prep(struct sas_task *task,
 
 err_out_tag:
 	hisi_sas_slot_index_free(hisi_hba, slot_idx);
+err_out_dif_dma_unmap:
+	if (!sas_protocol_ata(task->task_proto))
+		hisi_sas_dif_dma_unmap(hisi_hba, task, n_elem_dif);
 err_out_dma_unmap:
 	hisi_sas_dma_unmap(hisi_hba, task, n_elem,
 			   n_elem_req, n_elem_resp);
@@ -2144,19 +2214,24 @@ int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
 
 	/* roundup to avoid overly large block size */
 	max_command_entries_ru = roundup(max_command_entries, 64);
-	sz_slot_buf_ru = roundup(sizeof(struct hisi_sas_slot_buf_table), 64);
+	if (hisi_hba->enable_dix_experimental)
+		sz_slot_buf_ru = sizeof(struct hisi_sas_slot_dif_buf_table);
+	else
+		sz_slot_buf_ru = sizeof(struct hisi_sas_slot_buf_table);
+	sz_slot_buf_ru = roundup(sz_slot_buf_ru, 64);
 	s = lcm(max_command_entries_ru, sz_slot_buf_ru);
 	blk_cnt = (max_command_entries_ru * sz_slot_buf_ru) / s;
 	slots_per_blk = s / sz_slot_buf_ru;
+
 	for (i = 0; i < blk_cnt; i++) {
-		struct hisi_sas_slot_buf_table *buf;
-		dma_addr_t buf_dma;
 		int slot_index = i * slots_per_blk;
+		dma_addr_t buf_dma;
+		void *buf;
 
-		buf = dmam_alloc_coherent(dev, s, &buf_dma, GFP_KERNEL);
+		buf = dmam_alloc_coherent(dev, s, &buf_dma,
+					  GFP_KERNEL | __GFP_ZERO);
 		if (!buf)
 			goto err_out;
-		memset(buf, 0, s);
 
 		for (j = 0; j < slots_per_blk; j++, slot_index++) {
 			struct hisi_sas_slot *slot;
@@ -2166,8 +2241,8 @@ int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
 			slot->buf_dma = buf_dma;
 			slot->idx = slot_index;
 
-			buf++;
-			buf_dma += sizeof(*buf);
+			buf += sz_slot_buf_ru;
+			buf_dma += sz_slot_buf_ru;
 		}
 	}
 
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index c707bb1..e15d87f 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -405,6 +405,10 @@ struct hisi_sas_err_record_v3 {
 module_param(enable_dif, bool, 0444);
 MODULE_PARM_DESC(enable_dif, "DIF enable (0-1)");
 
+static bool enable_dix_experimental;
+module_param(enable_dix_experimental, bool, 0444);
+MODULE_PARM_DESC(enable_dix_experimental, "DIX enable (experimental) (0-1)");
+
 static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off)
 {
 	void __iomem *regs = hisi_hba->regs + off;
@@ -968,7 +972,34 @@ static void prep_prd_sge_v3_hw(struct hisi_hba *hisi_hba,
 
 	hdr->prd_table_addr = cpu_to_le64(hisi_sas_sge_addr_dma(slot));
 
-	hdr->sg_len = cpu_to_le32(n_elem << CMD_HDR_DATA_SGL_LEN_OFF);
+	hdr->sg_len |= cpu_to_le32(n_elem << CMD_HDR_DATA_SGL_LEN_OFF);
+}
+
+static void prep_prd_sge_dif_v3_hw(struct hisi_hba *hisi_hba,
+				  struct hisi_sas_slot *slot,
+				  struct hisi_sas_cmd_hdr *hdr,
+				  struct scatterlist *scatter,
+				  int n_elem)
+{
+	struct hisi_sas_sge_dif_page *sge_dif_page;
+	struct scatterlist *sg;
+	int i;
+
+	sge_dif_page = hisi_sas_sge_dif_addr_mem(slot);
+
+	for_each_sg(scatter, sg, n_elem, i) {
+		struct hisi_sas_sge *entry = &sge_dif_page->sge[i];
+
+		entry->addr = cpu_to_le64(sg_dma_address(sg));
+		entry->page_ctrl_0 = entry->page_ctrl_1 = 0;
+		entry->data_len = cpu_to_le32(sg_dma_len(sg));
+		entry->data_off = 0;
+	}
+
+	hdr->dif_prd_table_addr = cpu_to_le64(
+			hisi_sas_sge_dif_addr_dma(slot));
+
+	hdr->sg_len |= cpu_to_le32(n_elem << CMD_HDR_DIF_SGL_LEN_OFF);
 }
 
 static void fill_prot_v3_hw(struct scsi_cmnd *scsi_cmnd,
@@ -985,6 +1016,10 @@ static void fill_prot_v3_hw(struct scsi_cmnd *scsi_cmnd,
 		lbrt_chk_val = (u32)scsi_get_lba(scsi_cmnd);
 
 	switch (prot_op) {
+	case SCSI_PROT_READ_INSERT:
+		prot->dw0 |= T10_INSRT_EN_MSK;
+		prot->lbrtgv = lbrt_chk_val;
+		break;
 	case SCSI_PROT_READ_STRIP:
 		prot->dw0 |= (T10_RMV_EN_MSK | T10_CHK_EN_MSK);
 		prot->lbrtcv = lbrt_chk_val;
@@ -993,10 +1028,30 @@ static void fill_prot_v3_hw(struct scsi_cmnd *scsi_cmnd,
 		else if (prot_type == SCSI_PROT_DIF_TYPE3)
 			prot->dw4 |= (0xfc << 16);
 		break;
+	case SCSI_PROT_READ_PASS:
+		prot->dw0 |= T10_CHK_EN_MSK;
+		prot->lbrtcv = lbrt_chk_val;
+		if (prot_type == SCSI_PROT_DIF_TYPE1)
+			prot->dw4 |= (0xc << 16);
+		else if (prot_type == SCSI_PROT_DIF_TYPE3)
+			prot->dw4 |= (0xfc << 16);
+		break;
 	case SCSI_PROT_WRITE_INSERT:
 		prot->dw0 |= T10_INSRT_EN_MSK;
 		prot->lbrtgv = lbrt_chk_val;
 		break;
+	case SCSI_PROT_WRITE_STRIP:
+		prot->dw0 |= (T10_RMV_EN_MSK | T10_CHK_EN_MSK);
+		prot->lbrtcv = lbrt_chk_val;
+		break;
+	case SCSI_PROT_WRITE_PASS:
+		prot->dw0 |= T10_CHK_EN_MSK;
+		prot->lbrtcv = lbrt_chk_val;
+		if (prot_type == SCSI_PROT_DIF_TYPE1)
+			prot->dw4 |= (0xc << 16);
+		else if (prot_type == SCSI_PROT_DIF_TYPE3)
+			prot->dw4 |= (0xfc << 16);
+		break;
 	default:
 		WARN_ONCE(1, "prot_op(0x%x) is not valid\n", prot_op);
 		break;
@@ -1071,9 +1126,15 @@ static void prep_ssp_v3_hw(struct hisi_hba *hisi_hba,
 	hdr->dw2 = cpu_to_le32(dw2);
 	hdr->transfer_tags = cpu_to_le32(slot->idx);
 
-	if (has_data)
+	if (has_data) {
 		prep_prd_sge_v3_hw(hisi_hba, slot, hdr, task->scatter,
-					slot->n_elem);
+				   slot->n_elem);
+
+		if (scsi_prot_sg_count(scsi_cmnd))
+			prep_prd_sge_dif_v3_hw(hisi_hba, slot, hdr,
+					       scsi_prot_sglist(scsi_cmnd),
+					       slot->n_elem_dif);
+	}
 
 	hdr->cmd_table_addr = cpu_to_le64(hisi_sas_cmd_hdr_addr_dma(slot));
 	hdr->sts_buffer_addr = cpu_to_le64(hisi_sas_status_buf_addr_dma(slot));
@@ -1115,7 +1176,10 @@ static void prep_ssp_v3_hw(struct hisi_hba *hisi_hba,
 		memcpy(buf_cmd_prot, &prot,
 		       sizeof(struct hisi_sas_protect_iu_v3_hw));
 
-		if (prot_op == SCSI_PROT_WRITE_INSERT) {
+		if ((prot_op == SCSI_PROT_WRITE_INSERT) ||
+		    (prot_op == SCSI_PROT_READ_INSERT) ||
+		    (prot_op == SCSI_PROT_WRITE_PASS) ||
+		    (prot_op == SCSI_PROT_READ_PASS)) {
 			unsigned int interval = scsi_prot_interval(scsi_cmnd);
 			unsigned int ilog2_interval = ilog2(interval);
 
@@ -2336,6 +2400,7 @@ static ssize_t intr_coal_count_v3_hw_store(struct device *dev,
 	.bios_param		= sas_bios_param,
 	.this_id		= -1,
 	.sg_tablesize		= HISI_SAS_SGE_PAGE_CNT,
+	.sg_prot_tablesize	= HISI_SAS_SGE_PAGE_CNT,
 	.max_sectors		= SCSI_DEFAULT_MAX_SECTORS,
 	.use_clustering		= ENABLE_CLUSTERING,
 	.eh_device_reset_handler = sas_eh_device_reset_handler,
@@ -2396,6 +2461,7 @@ static ssize_t intr_coal_count_v3_hw_store(struct device *dev,
 	hisi_hba->shost = shost;
 	SHOST_TO_SAS_HA(shost) = &hisi_hba->sha;
 	hisi_hba->enable_dif = enable_dif;
+	hisi_hba->enable_dix_experimental = enable_dix_experimental;
 
 	timer_setup(&hisi_hba->timer, NULL, 0);
 
@@ -2516,6 +2582,15 @@ static ssize_t intr_coal_count_v3_hw_store(struct device *dev,
 			SHOST_DIF_TYPE3_PROTECTION;
 	}
 
+	if (hisi_hba->enable_dix_experimental) {
+		dev_warn(dev, "Registering for DIX type 1/2/3 protection as experimental.\n");
+		prot |= SHOST_DIX_TYPE1_PROTECTION |
+			SHOST_DIX_TYPE2_PROTECTION |
+			SHOST_DIX_TYPE3_PROTECTION;
+		scsi_host_set_guard(hisi_hba->shost,
+				    SHOST_DIX_GUARD_CRC);
+	}
+
 	scsi_host_set_prot(hisi_hba->shost, prot);
 
 	scsi_scan_host(shost);
-- 
1.9.1


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

* Re: [PATCH v4 2/5] scsi: hisi_sas: Relocate some code to reduce complexity
  2018-12-06 13:34 ` [PATCH v4 2/5] scsi: hisi_sas: Relocate some code to reduce complexity John Garry
@ 2018-12-06 14:17   ` Johannes Thumshirn
  2018-12-06 15:37     ` John Garry
  0 siblings, 1 reply; 16+ messages in thread
From: Johannes Thumshirn @ 2018-12-06 14:17 UTC (permalink / raw)
  To: John Garry, jejb, martin.petersen
  Cc: linuxarm, linux-kernel, linux-scsi, Xiang Chen

On 06/12/2018 14:34, John Garry wrote:
[...]
> +static void hisi_sas_dma_unmap(struct hisi_hba *hisi_hba,
> +			       struct sas_task *task, int n_elem,
> +			       int n_elem_req, int n_elem_resp)
> +{
> +	struct device *dev = hisi_hba->dev;
> +
> +	if (!sas_protocol_ata(task->task_proto)) {
> +		if (task->num_scatter) {
> +			if (n_elem)
> +				dma_unmap_sg(dev, task->scatter,
> +					     task->num_scatter,
> +					     task->data_dir);
> +		} else if (task->task_proto & SAS_PROTOCOL_SMP) {
> +			if (n_elem_req)
> +				dma_unmap_sg(dev, &task->smp_task.smp_req,
> +					     1, DMA_TO_DEVICE);
> +			if (n_elem_resp)
> +				dma_unmap_sg(dev, &task->smp_task.smp_resp,
> +					     1, DMA_FROM_DEVICE);
> +		}
> +	}

	if (sas_protocol_ata(task->task_proto))
		return;

Would save you a level of indentation and make the above more readable.


-- 
Johannes Thumshirn                            SUSE Labs Filesystems
jthumshirn@suse.de                                +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850

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

* Re: [PATCH v4 2/5] scsi: hisi_sas: Relocate some code to reduce complexity
  2018-12-06 14:17   ` Johannes Thumshirn
@ 2018-12-06 15:37     ` John Garry
  2018-12-06 16:20       ` Johannes Thumshirn
  0 siblings, 1 reply; 16+ messages in thread
From: John Garry @ 2018-12-06 15:37 UTC (permalink / raw)
  To: Johannes Thumshirn, jejb, martin.petersen
  Cc: linuxarm, linux-kernel, linux-scsi, Xiang Chen

On 06/12/2018 14:17, Johannes Thumshirn wrote:
> On 06/12/2018 14:34, John Garry wrote:
> [...]
>> +static void hisi_sas_dma_unmap(struct hisi_hba *hisi_hba,
>> +			       struct sas_task *task, int n_elem,
>> +			       int n_elem_req, int n_elem_resp)
>> +{
>> +	struct device *dev = hisi_hba->dev;
>> +
>> +	if (!sas_protocol_ata(task->task_proto)) {
>> +		if (task->num_scatter) {
>> +			if (n_elem)
>> +				dma_unmap_sg(dev, task->scatter,
>> +					     task->num_scatter,
>> +					     task->data_dir);
>> +		} else if (task->task_proto & SAS_PROTOCOL_SMP) {
>> +			if (n_elem_req)
>> +				dma_unmap_sg(dev, &task->smp_task.smp_req,
>> +					     1, DMA_TO_DEVICE);
>> +			if (n_elem_resp)
>> +				dma_unmap_sg(dev, &task->smp_task.smp_resp,
>> +					     1, DMA_FROM_DEVICE);
>> +		}
>> +	}
>
> 	if (sas_protocol_ata(task->task_proto))
> 		return;
>
> Would save you a level of indentation and make the above more readable.
>
>

Hi Johannes,

Whilst I agree with the idea, the current approach makes the function 
more symmetic with its mapping buddy, hisi_sas_dma_map():

static void hisi_sas_dma_unmap(struct hisi_hba *hisi_hba,
                    struct sas_task *task, int n_elem,
                    int n_elem_req, int n_elem_resp)
{
     struct device *dev = hisi_hba->dev;

     if (!sas_protocol_ata(task->task_proto)) {
         if (task->num_scatter) {
             if (n_elem)
                 dma_unmap_sg(dev, task->scatter,

	...
}

static int hisi_sas_dma_map(struct hisi_hba *hisi_hba,
                 struct sas_task *task, int *n_elem,
                 int *n_elem_req, int *n_elem_resp)
{
     struct device *dev = hisi_hba->dev;
     int rc;

     if (sas_protocol_ata(task->task_proto)) {
         *n_elem = task->num_scatter;
     } else {
         unsigned int req_len, resp_len;

         if (task->num_scatter) {
             *n_elem = dma_map_sg(dev, task->scatter,
                          task->num_scatter, task->data_dir);
    		...

}

which is important. Let me know if you disagree and I can change it.

Thanks,
John



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

* Re: [PATCH v4 2/5] scsi: hisi_sas: Relocate some code to reduce complexity
  2018-12-06 15:37     ` John Garry
@ 2018-12-06 16:20       ` Johannes Thumshirn
  2018-12-07 10:07         ` John Garry
  0 siblings, 1 reply; 16+ messages in thread
From: Johannes Thumshirn @ 2018-12-06 16:20 UTC (permalink / raw)
  To: John Garry, jejb, martin.petersen
  Cc: linuxarm, linux-kernel, linux-scsi, Xiang Chen

On 06/12/2018 16:37, John Garry wrote:
> which is important. Let me know if you disagree and I can change it.

Sure, it's your driver. It was just because the patch is even titled
"Relocate some code to reduce complexity", so I thought of reducing the
complexity for readers even further (like you don't need the line wrap
at 80 chars, and so on).

Byte,
	Johannes
-- 
Johannes Thumshirn                            SUSE Labs Filesystems
jthumshirn@suse.de                                +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850

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

* Re: [PATCH v4 2/5] scsi: hisi_sas: Relocate some code to reduce complexity
  2018-12-06 16:20       ` Johannes Thumshirn
@ 2018-12-07 10:07         ` John Garry
  2018-12-07 10:53           ` Johannes Thumshirn
  0 siblings, 1 reply; 16+ messages in thread
From: John Garry @ 2018-12-07 10:07 UTC (permalink / raw)
  To: Johannes Thumshirn, jejb, martin.petersen
  Cc: linuxarm, linux-kernel, linux-scsi, Xiang Chen

On 06/12/2018 16:20, Johannes Thumshirn wrote:
> On 06/12/2018 16:37, John Garry wrote:
>> which is important. Let me know if you disagree and I can change it.
>
> Sure, it's your driver. It was just because the patch is even titled
> "Relocate some code to reduce complexity", so I thought of reducing the
> complexity for readers even further (like you don't need the line wrap
> at 80 chars, and so on).
>
> Byte,
> 	Johannes
>

I would rather not change if you don't mind. When we say "reduce 
complexity", we are talking about moving the DMA mapping code from the 
task prep function, as, when we add the DIX-related DMA mapping code, 
leaving all the DMA mapping code in the task prep function would make it 
a monster.

Thanks,
John


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

* Re: [PATCH v4 2/5] scsi: hisi_sas: Relocate some code to reduce complexity
  2018-12-07 10:07         ` John Garry
@ 2018-12-07 10:53           ` Johannes Thumshirn
  0 siblings, 0 replies; 16+ messages in thread
From: Johannes Thumshirn @ 2018-12-07 10:53 UTC (permalink / raw)
  To: John Garry, jejb, martin.petersen
  Cc: linuxarm, linux-kernel, linux-scsi, Xiang Chen

On 07/12/2018 11:07, John Garry wrote:
> On 06/12/2018 16:20, Johannes Thumshirn wrote:
>> On 06/12/2018 16:37, John Garry wrote:
>>> which is important. Let me know if you disagree and I can change it.
>>
>> Sure, it's your driver. It was just because the patch is even titled
>> "Relocate some code to reduce complexity", so I thought of reducing the
>> complexity for readers even further (like you don't need the line wrap
>> at 80 chars, and so on).
>>
>> Byte,
>>     Johannes
>>
> 
> I would rather not change if you don't mind. When we say "reduce
> complexity", we are talking about moving the DMA mapping code from the
> task prep function, as, when we add the DIX-related DMA mapping code,
> leaving all the DMA mapping code in the task prep function would make it
> a monster.

Sure


-- 
Johannes Thumshirn                            SUSE Labs Filesystems
jthumshirn@suse.de                                +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850

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

* Re: [PATCH v4 4/5] scsi: hisi_sas: Add support for DIF feature for v3 hw
  2018-12-06 13:34 ` [PATCH v4 4/5] scsi: hisi_sas: Add support for DIF feature for v3 hw John Garry
@ 2018-12-13  2:20   ` Martin K. Petersen
  2018-12-13 13:35     ` John Garry
  0 siblings, 1 reply; 16+ messages in thread
From: Martin K. Petersen @ 2018-12-13  2:20 UTC (permalink / raw)
  To: John Garry
  Cc: jejb, martin.petersen, linuxarm, linux-kernel, linux-scsi, Xiang Chen


John,

> +static void fill_prot_v3_hw(struct scsi_cmnd *scsi_cmnd,
> +			    struct hisi_sas_protect_iu_v3_hw *prot)
> +{
> +	u8 prot_type = scsi_get_prot_type(scsi_cmnd);
> +	u8 prot_op = scsi_get_prot_op(scsi_cmnd);
> +	unsigned int interval = scsi_prot_interval(scsi_cmnd);
> +	u32 lbrt_chk_val;
> +
> +	if (interval == 4096)
> +		lbrt_chk_val = (u32)(scsi_get_lba(scsi_cmnd) >> 3);
> +	else
> +		lbrt_chk_val = (u32)scsi_get_lba(scsi_cmnd);

lbrt_chk_val = t10_pi_ref_tag(scmd->request);

> +
> +	switch (prot_op) {
> +	case SCSI_PROT_READ_STRIP:
> +		prot->dw0 |= (T10_RMV_EN_MSK | T10_CHK_EN_MSK);
> +		prot->lbrtcv = lbrt_chk_val;
> +		if (prot_type == SCSI_PROT_DIF_TYPE1)
> +			prot->dw4 |= (0xc << 16);
> +		else if (prot_type == SCSI_PROT_DIF_TYPE3)
> +			prot->dw4 |= (0xfc << 16);

We're moving away from prot_type. You should use:

enum scsi_prot_flags {
        SCSI_PROT_TRANSFER_PI           = 1 << 0,
        SCSI_PROT_GUARD_CHECK           = 1 << 1,
        SCSI_PROT_REF_CHECK             = 1 << 2,
        SCSI_PROT_REF_INCREMENT         = 1 << 3,
        SCSI_PROT_IP_CHECKSUM           = 1 << 4,
};

to set your controller flags.

+		if (prot_op == SCSI_PROT_WRITE_INSERT) {
+			unsigned int interval = scsi_prot_interval(scsi_cmnd);
+			unsigned int ilog2_interval = ilog2(interval);
+
+			len = (task->total_xfer_len >> ilog2_interval) * 8;

scsi_transfer_length(struct scsi_cmnd *scmd)

> +	if (hisi_hba->enable_dif) {
> +		dev_info(dev, "Registering for DIF type 1/2/3 protection.\n");
> +		prot |=	SHOST_DIF_TYPE1_PROTECTION |
> +			SHOST_DIF_TYPE2_PROTECTION |
> +			SHOST_DIF_TYPE3_PROTECTION;
> +	}
> +
> +	scsi_host_set_prot(hisi_hba->shost, prot);

I'm not so keen on this enable_dif/enable_dix business in module
parameters. I suggest you just allow the user to specify the host
protection mask instead of having a layer of indirection.

-- 
Martin K. Petersen	Oracle Linux Engineering

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

* Re: [PATCH v4 0/5]  hisi_sas: DIF support
  2018-12-06 13:34 [PATCH v4 0/5] hisi_sas: DIF support John Garry
                   ` (4 preceding siblings ...)
  2018-12-06 13:34 ` [RFC PATCH v4 5/5] scsi: hisi_sas: Add support for DIX feature for v3 hw as experimental John Garry
@ 2018-12-13  2:23 ` Martin K. Petersen
  5 siblings, 0 replies; 16+ messages in thread
From: Martin K. Petersen @ 2018-12-13  2:23 UTC (permalink / raw)
  To: John Garry; +Cc: jejb, martin.petersen, linuxarm, linux-kernel, linux-scsi


John,

> This patchset introduces support to the driver for DIF/DIX.

Applied 1-3 to 4.21/scsi-queue.

-- 
Martin K. Petersen	Oracle Linux Engineering

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

* Re: [PATCH v4 4/5] scsi: hisi_sas: Add support for DIF feature for v3 hw
  2018-12-13  2:20   ` Martin K. Petersen
@ 2018-12-13 13:35     ` John Garry
  2018-12-17 14:51       ` John Garry
  0 siblings, 1 reply; 16+ messages in thread
From: John Garry @ 2018-12-13 13:35 UTC (permalink / raw)
  To: Martin K. Petersen; +Cc: jejb, linuxarm, linux-kernel, linux-scsi, Xiang Chen

On 13/12/2018 02:20, Martin K. Petersen wrote:
>
> John,

Hi Martin,

>
>> +static void fill_prot_v3_hw(struct scsi_cmnd *scsi_cmnd,
>> +			    struct hisi_sas_protect_iu_v3_hw *prot)
>> +{
>> +	u8 prot_type = scsi_get_prot_type(scsi_cmnd);
>> +	u8 prot_op = scsi_get_prot_op(scsi_cmnd);
>> +	unsigned int interval = scsi_prot_interval(scsi_cmnd);
>> +	u32 lbrt_chk_val;
>> +
>> +	if (interval == 4096)
>> +		lbrt_chk_val = (u32)(scsi_get_lba(scsi_cmnd) >> 3);
>> +	else
>> +		lbrt_chk_val = (u32)scsi_get_lba(scsi_cmnd);
>
> lbrt_chk_val = t10_pi_ref_tag(scmd->request);
>

ok

> +
>> +	switch (prot_op) {
>> +	case SCSI_PROT_READ_STRIP:
>> +		prot->dw0 |= (T10_RMV_EN_MSK | T10_CHK_EN_MSK);
>> +		prot->lbrtcv = lbrt_chk_val;
>> +		if (prot_type == SCSI_PROT_DIF_TYPE1)
>> +			prot->dw4 |= (0xc << 16);
>> +		else if (prot_type == SCSI_PROT_DIF_TYPE3)
>> +			prot->dw4 |= (0xfc << 16);
>
> We're moving away from prot_type. You should use:
>
> enum scsi_prot_flags {
>         SCSI_PROT_TRANSFER_PI           = 1 << 0,
>         SCSI_PROT_GUARD_CHECK           = 1 << 1,
>         SCSI_PROT_REF_CHECK             = 1 << 2,
>         SCSI_PROT_REF_INCREMENT         = 1 << 3,
>         SCSI_PROT_IP_CHECKSUM           = 1 << 4,
> };

ok

>
> to set your controller flags.
>
> +		if (prot_op == SCSI_PROT_WRITE_INSERT) {
> +			unsigned int interval = scsi_prot_interval(scsi_cmnd);
> +			unsigned int ilog2_interval = ilog2(interval);
> +
> +			len = (task->total_xfer_len >> ilog2_interval) * 8;
>
> scsi_transfer_length(struct scsi_cmnd *scmd)

ok

>
>> +	if (hisi_hba->enable_dif) {
>> +		dev_info(dev, "Registering for DIF type 1/2/3 protection.\n");
>> +		prot |=	SHOST_DIF_TYPE1_PROTECTION |
>> +			SHOST_DIF_TYPE2_PROTECTION |
>> +			SHOST_DIF_TYPE3_PROTECTION;
>> +	}
>> +
>> +	scsi_host_set_prot(hisi_hba->shost, prot);
>
> I'm not so keen on this enable_dif/enable_dix business in module
> parameters. I suggest you just allow the user to specify the host
> protection mask instead of having a layer of indirection.
>

Fine, we can let the user select the mask. However, for now, I would 
like to keep default at off. When soaks a bit, we can make default on @ 0x7.

Cheers,
John



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

* Re: [PATCH v4 4/5] scsi: hisi_sas: Add support for DIF feature for v3 hw
  2018-12-13 13:35     ` John Garry
@ 2018-12-17 14:51       ` John Garry
  2018-12-18  3:31         ` Martin K. Petersen
  0 siblings, 1 reply; 16+ messages in thread
From: John Garry @ 2018-12-17 14:51 UTC (permalink / raw)
  To: Martin K. Petersen; +Cc: jejb, linuxarm, linux-kernel, linux-scsi, Xiang Chen

On 13/12/2018 13:35, John Garry wrote:
>
>>
>> to set your controller flags.
>>
>> +        if (prot_op == SCSI_PROT_WRITE_INSERT) {
>> +            unsigned int interval = scsi_prot_interval(scsi_cmnd);
>> +            unsigned int ilog2_interval = ilog2(interval);
>> +
>> +            len = (task->total_xfer_len >> ilog2_interval) * 8;
>>
>> scsi_transfer_length(struct scsi_cmnd *scmd)
>
> ok

Hi Martin,

We have an issue with using scsi_transfer_length().

As I understand, for our controller we need to set the host structure 
data transfer size to the size of data to write to the disk for WRITE 
type command, and at size of info received to host memory for READ type 
command. As such, for READ STRIP, we only want the SCSI buf len, and not 
the scsi buf len and PI (this is what scsi_transfer_length() provides).

Thanks,
John



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

* Re: [PATCH v4 4/5] scsi: hisi_sas: Add support for DIF feature for v3 hw
  2018-12-17 14:51       ` John Garry
@ 2018-12-18  3:31         ` Martin K. Petersen
  0 siblings, 0 replies; 16+ messages in thread
From: Martin K. Petersen @ 2018-12-18  3:31 UTC (permalink / raw)
  To: John Garry
  Cc: Martin K. Petersen, jejb, linuxarm, linux-kernel, linux-scsi, Xiang Chen


John,

> We have an issue with using scsi_transfer_length().
>
> As I understand, for our controller we need to set the host structure
> data transfer size to the size of data to write to the disk for WRITE
> type command, and at size of info received to host memory for READ
> type command. As such, for READ STRIP, we only want the SCSI buf len,
> and not the scsi buf len and PI (this is what scsi_transfer_length()
> provides).

Interesting asymmetry.

-- 
Martin K. Petersen	Oracle Linux Engineering

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

end of thread, other threads:[~2018-12-18  3:31 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-12-06 13:34 [PATCH v4 0/5] hisi_sas: DIF support John Garry
2018-12-06 13:34 ` [PATCH v4 1/5] scsi: hisi_sas: Fix warnings detected by sparse John Garry
2018-12-06 13:34 ` [PATCH v4 2/5] scsi: hisi_sas: Relocate some code to reduce complexity John Garry
2018-12-06 14:17   ` Johannes Thumshirn
2018-12-06 15:37     ` John Garry
2018-12-06 16:20       ` Johannes Thumshirn
2018-12-07 10:07         ` John Garry
2018-12-07 10:53           ` Johannes Thumshirn
2018-12-06 13:34 ` [PATCH v4 3/5] scsi: hisi_sas: Make sg_tablesize consistent value John Garry
2018-12-06 13:34 ` [PATCH v4 4/5] scsi: hisi_sas: Add support for DIF feature for v3 hw John Garry
2018-12-13  2:20   ` Martin K. Petersen
2018-12-13 13:35     ` John Garry
2018-12-17 14:51       ` John Garry
2018-12-18  3:31         ` Martin K. Petersen
2018-12-06 13:34 ` [RFC PATCH v4 5/5] scsi: hisi_sas: Add support for DIX feature for v3 hw as experimental John Garry
2018-12-13  2:23 ` [PATCH v4 0/5] hisi_sas: DIF support Martin K. Petersen

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