Commit af20bb73 authored by Justin Tee's avatar Justin Tee Committed by Martin K. Petersen
Browse files

scsi: lpfc: Add support for 32 byte CDBs



The driver's I/O path is updated to support 32 byte CDBs.

Changes to accommodate 32 byte CDBs include:

 - Updating various size fields to allow for the larger 32 byte CDB.

 - Starting the FCP command payload at an earlier offset in WQE submission
   to fit the 32 byte CDB.

 - Redefining relevant structs to __le32/__be32 data types for proper cpu
   endianness macro usage.

Signed-off-by: default avatarJustin Tee <justin.tee@broadcom.com>
Link: https://lore.kernel.org/r/20240429221547.6842-7-justintee8345@gmail.com


Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent e780c942
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -2146,6 +2146,14 @@ struct sli4_sge { /* SLI-4 */
	uint32_t sge_len;
};

struct sli4_sge_le {
	__le32 addr_hi;
	__le32 addr_lo;

	__le32 word2;
	__le32 sge_len;
};

struct sli4_hybrid_sgl {
	struct list_head list_node;
	struct sli4_sge *dma_sgl;
+7 −4
Original line number Diff line number Diff line
@@ -4773,7 +4773,10 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
	shost->max_id = LPFC_MAX_TARGET;
	shost->max_lun = vport->cfg_max_luns;
	shost->this_id = -1;
	shost->max_cmd_len = 16;
	if (phba->sli_rev == LPFC_SLI_REV4)
		shost->max_cmd_len = LPFC_FCP_CDB_LEN_32;
	else
		shost->max_cmd_len = LPFC_FCP_CDB_LEN;

	if (phba->sli_rev == LPFC_SLI_REV4) {
		if (!phba->cfg_fcp_mq_threshold ||
@@ -8231,7 +8234,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
		 * our max amount and we need to limit lpfc_sg_seg_cnt
		 * to minimize the risk of running out.
		 */
		phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd) +
		phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd32) +
				sizeof(struct fcp_rsp) + max_buf_size;

		/* Total SGEs for scsi_sg_list and scsi_sg_prot_list */
@@ -8253,7 +8256,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
		 * the FCP rsp, a SGE for each, and a SGE for up to
		 * cfg_sg_seg_cnt data segments.
		 */
		phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd) +
		phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd32) +
				sizeof(struct fcp_rsp) +
				((phba->cfg_sg_seg_cnt + extra) *
				sizeof(struct sli4_sge));
@@ -8316,7 +8319,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
	phba->lpfc_cmd_rsp_buf_pool =
			dma_pool_create("lpfc_cmd_rsp_buf_pool",
					&phba->pcidev->dev,
					sizeof(struct fcp_cmnd) +
					sizeof(struct fcp_cmnd32) +
					sizeof(struct fcp_rsp),
					i, 0);
	if (!phba->lpfc_cmd_rsp_buf_pool) {
+37 −20
Original line number Diff line number Diff line
@@ -600,7 +600,7 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
{
	struct lpfc_io_buf *lpfc_cmd;
	struct lpfc_sli4_hdw_queue *qp;
	struct sli4_sge *sgl;
	struct sli4_sge_le *sgl;
	dma_addr_t pdma_phys_fcp_rsp;
	dma_addr_t pdma_phys_fcp_cmd;
	uint32_t cpu, idx;
@@ -651,23 +651,23 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
	 * The balance are sg list bdes. Initialize the
	 * first two and leave the rest for queuecommand.
	 */
	sgl = (struct sli4_sge *)lpfc_cmd->dma_sgl;
	sgl = (struct sli4_sge_le *)lpfc_cmd->dma_sgl;
	pdma_phys_fcp_cmd = tmp->fcp_cmd_rsp_dma_handle;
	sgl->addr_hi = cpu_to_le32(putPaddrHigh(pdma_phys_fcp_cmd));
	sgl->addr_lo = cpu_to_le32(putPaddrLow(pdma_phys_fcp_cmd));
	sgl->word2 = le32_to_cpu(sgl->word2);
	bf_set(lpfc_sli4_sge_last, sgl, 0);
	sgl->word2 = cpu_to_le32(sgl->word2);
	bf_set_le32(lpfc_sli4_sge_last, sgl, 0);
	if (cmnd && cmnd->cmd_len > LPFC_FCP_CDB_LEN)
		sgl->sge_len = cpu_to_le32(sizeof(struct fcp_cmnd32));
	else
		sgl->sge_len = cpu_to_le32(sizeof(struct fcp_cmnd));

	sgl++;

	/* Setup the physical region for the FCP RSP */
	pdma_phys_fcp_rsp = pdma_phys_fcp_cmd + sizeof(struct fcp_cmnd);
	pdma_phys_fcp_rsp = pdma_phys_fcp_cmd + sizeof(struct fcp_cmnd32);
	sgl->addr_hi = cpu_to_le32(putPaddrHigh(pdma_phys_fcp_rsp));
	sgl->addr_lo = cpu_to_le32(putPaddrLow(pdma_phys_fcp_rsp));
	sgl->word2 = le32_to_cpu(sgl->word2);
	bf_set(lpfc_sli4_sge_last, sgl, 1);
	sgl->word2 = cpu_to_le32(sgl->word2);
	bf_set_le32(lpfc_sli4_sge_last, sgl, 1);
	sgl->sge_len = cpu_to_le32(sizeof(struct fcp_rsp));

	if (lpfc_ndlp_check_qdepth(phba, ndlp)) {
@@ -2608,7 +2608,7 @@ lpfc_bg_scsi_prep_dma_buf_s3(struct lpfc_hba *phba,
	iocb_cmd->ulpLe = 1;

	fcpdl = lpfc_bg_scsi_adjust_dl(phba, lpfc_cmd);
	fcp_cmnd->fcpDl = be32_to_cpu(fcpdl);
	fcp_cmnd->fcpDl = cpu_to_be32(fcpdl);

	/*
	 * Due to difference in data length between DIF/non-DIF paths,
@@ -3225,6 +3225,10 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd)
	 * explicitly reinitialized.
	 * all iocb memory resources are reused.
	 */
	if (scsi_cmnd->cmd_len > LPFC_FCP_CDB_LEN)
		((struct fcp_cmnd32 *)fcp_cmnd)->fcpDl =
				cpu_to_be32(scsi_bufflen(scsi_cmnd));
	else
		fcp_cmnd->fcpDl = cpu_to_be32(scsi_bufflen(scsi_cmnd));
	/* Set first-burst provided it was successfully negotiated */
	if (!test_bit(HBA_FCOE_MODE, &phba->hba_flag) &&
@@ -3232,7 +3236,7 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd)
	    scsi_cmnd->sc_data_direction == DMA_TO_DEVICE) {
		u32 init_len, total_len;

		total_len = be32_to_cpu(fcp_cmnd->fcpDl);
		total_len = scsi_bufflen(scsi_cmnd);
		init_len = min(total_len, vport->cfg_first_burst_size);

		/* Word 4 & 5 */
@@ -3420,7 +3424,10 @@ lpfc_bg_scsi_prep_dma_buf_s4(struct lpfc_hba *phba,
	}

	fcpdl = lpfc_bg_scsi_adjust_dl(phba, lpfc_cmd);
	fcp_cmnd->fcpDl = be32_to_cpu(fcpdl);
	if (lpfc_cmd->pCmd->cmd_len > LPFC_FCP_CDB_LEN)
		((struct fcp_cmnd32 *)fcp_cmnd)->fcpDl = cpu_to_be32(fcpdl);
	else
		fcp_cmnd->fcpDl = cpu_to_be32(fcpdl);

	/* Set first-burst provided it was successfully negotiated */
	if (!test_bit(HBA_FCOE_MODE, &phba->hba_flag) &&
@@ -3428,7 +3435,7 @@ lpfc_bg_scsi_prep_dma_buf_s4(struct lpfc_hba *phba,
	    scsi_cmnd->sc_data_direction == DMA_TO_DEVICE) {
		u32 init_len, total_len;

		total_len = be32_to_cpu(fcp_cmnd->fcpDl);
		total_len = fcpdl;
		init_len = min(total_len, vport->cfg_first_burst_size);

		/* Word 4 & 5 */
@@ -3436,8 +3443,7 @@ lpfc_bg_scsi_prep_dma_buf_s4(struct lpfc_hba *phba,
		wqe->fcp_iwrite.total_xfer_len = total_len;
	} else {
		/* Word 4 */
		wqe->fcp_iwrite.total_xfer_len =
			be32_to_cpu(fcp_cmnd->fcpDl);
		wqe->fcp_iwrite.total_xfer_len = fcpdl;
	}

	/*
@@ -3894,6 +3900,9 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd,
			 fcprsp->rspInfo3);

	scsi_set_resid(cmnd, 0);
	if (cmnd->cmd_len > LPFC_FCP_CDB_LEN)
		fcpDl = be32_to_cpu(((struct fcp_cmnd32 *)fcpcmd)->fcpDl);
	else
		fcpDl = be32_to_cpu(fcpcmd->fcpDl);
	if (resp_info & RESID_UNDER) {
		scsi_set_resid(cmnd, be32_to_cpu(fcprsp->rspResId));
@@ -4723,6 +4732,14 @@ static int lpfc_scsi_prep_cmnd_buf_s4(struct lpfc_vport *vport,
				bf_set(wqe_iod, &wqe->fcp_iread.wqe_com,
				       LPFC_WQE_IOD_NONE);
		}

		/* Additional fcp cdb length field calculation.
		 * LPFC_FCP_CDB_LEN_32 - normal 16 byte cdb length,
		 * then divide by 4 for the word count.
		 * shift 2 because of the RDDATA/WRDATA.
		 */
		if (scsi_cmnd->cmd_len > LPFC_FCP_CDB_LEN)
			fcp_cmnd->fcpCntl3 |= 4 << 2;
	} else {
		/* From the icmnd template, initialize words 4 - 11 */
		memcpy(&wqe->words[4], &lpfc_icmnd_cmd_template.words[4],
@@ -4743,7 +4760,7 @@ static int lpfc_scsi_prep_cmnd_buf_s4(struct lpfc_vport *vport,

	 /* Word 3 */
	bf_set(payload_offset_len, &wqe->fcp_icmd,
	       sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp));
	       sizeof(struct fcp_cmnd32) + sizeof(struct fcp_rsp));

	/* Word 6 */
	bf_set(wqe_ctxt_tag, &wqe->generic.wqe_com,
@@ -4798,7 +4815,7 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd,
	int_to_scsilun(lpfc_cmd->pCmd->device->lun,
		       &lpfc_cmd->fcp_cmnd->fcp_lun);

	ptr = &fcp_cmnd->fcpCdb[0];
	ptr = &((struct fcp_cmnd32 *)fcp_cmnd)->fcpCdb[0];
	memcpy(ptr, scsi_cmnd->cmnd, scsi_cmnd->cmd_len);
	if (scsi_cmnd->cmd_len < LPFC_FCP_CDB_LEN) {
		ptr += scsi_cmnd->cmd_len;
+22 −8
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@

struct lpfc_hba;
#define LPFC_FCP_CDB_LEN 16
#define LPFC_FCP_CDB_LEN_32 32

#define list_remove_head(list, entry, type, member)		\
	do {							\
@@ -99,17 +100,11 @@ struct fcp_rsp {
#define SNSCOD_BADCMD 0x20	/* sense code is byte 13 ([12]) */
};

struct fcp_cmnd {
	struct scsi_lun  fcp_lun;

	uint8_t fcpCntl0;	/* FCP_CNTL byte 0 (reserved) */
	uint8_t fcpCntl1;	/* FCP_CNTL byte 1 task codes */
#define  SIMPLE_Q        0x00
#define  HEAD_OF_Q       0x01
#define  ORDERED_Q       0x02
#define  ACA_Q           0x04
#define  UNTAGGED        0x05
	uint8_t fcpCntl2;	/* FCP_CTL byte 2 task management codes */
#define  FCP_ABORT_TASK_SET  0x02	/* Bit 1 */
#define  FCP_CLEAR_TASK_SET  0x04	/* bit 2 */
#define  FCP_BUS_RESET       0x08	/* bit 3 */
@@ -117,12 +112,31 @@ struct fcp_cmnd {
#define  FCP_TARGET_RESET    0x20	/* bit 5 */
#define  FCP_CLEAR_ACA       0x40	/* bit 6 */
#define  FCP_TERMINATE_TASK  0x80	/* bit 7 */
	uint8_t fcpCntl3;
#define  WRITE_DATA      0x01	/* Bit 0 */
#define  READ_DATA       0x02	/* Bit 1 */

struct fcp_cmnd {
	struct scsi_lun  fcp_lun;

	uint8_t fcpCntl0;	/* FCP_CNTL byte 0 (reserved) */
	uint8_t fcpCntl1;	/* FCP_CNTL byte 1 task codes */
	uint8_t fcpCntl2;	/* FCP_CTL byte 2 task management codes */
	uint8_t fcpCntl3;

	uint8_t fcpCdb[LPFC_FCP_CDB_LEN]; /* SRB cdb field is copied here */
	uint32_t fcpDl;		/* Total transfer length */
	__be32 fcpDl;		/* Total transfer length */

};
struct fcp_cmnd32 {
	struct scsi_lun  fcp_lun;

	uint8_t fcpCntl0;	/* FCP_CNTL byte 0 (reserved) */
	uint8_t fcpCntl1;	/* FCP_CNTL byte 1 task codes */
	uint8_t fcpCntl2;	/* FCP_CTL byte 2 task management codes */
	uint8_t fcpCntl3;

	uint8_t fcpCdb[LPFC_FCP_CDB_LEN_32]; /* SRB cdb field is copied here */
	__be32 fcpDl;		/* Total transfer length */

};

+6 −6
Original line number Diff line number Diff line
@@ -10595,18 +10595,18 @@ lpfc_prep_embed_io(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd)
			BUFF_TYPE_BDE_IMMED;
		wqe->generic.bde.tus.f.bdeSize = sgl->sge_len;
		wqe->generic.bde.addrHigh = 0;
		wqe->generic.bde.addrLow =  88;  /* Word 22 */
		wqe->generic.bde.addrLow =  72;  /* Word 18 */
		bf_set(wqe_wqes, &wqe->fcp_iwrite.wqe_com, 1);
		bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 0);
		/* Word 22-29  FCP CMND Payload */
		ptr = &wqe->words[22];
		memcpy(ptr, fcp_cmnd, sizeof(struct fcp_cmnd));
		/* Word 18-29  FCP CMND Payload */
		ptr = &wqe->words[18];
		memcpy(ptr, fcp_cmnd, sgl->sge_len);
	} else {
		/* Word 0-2 - Inline BDE */
		wqe->generic.bde.tus.f.bdeFlags =  BUFF_TYPE_BDE_64;
		wqe->generic.bde.tus.f.bdeSize = sizeof(struct fcp_cmnd);
		wqe->generic.bde.tus.f.bdeSize = sgl->sge_len;
		wqe->generic.bde.addrHigh = sgl->addr_hi;
		wqe->generic.bde.addrLow =  sgl->addr_lo;
@@ -22469,7 +22469,7 @@ lpfc_get_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba,
		}
		tmp->fcp_rsp = (struct fcp_rsp *)((uint8_t *)tmp->fcp_cmnd +
				sizeof(struct fcp_cmnd));
				sizeof(struct fcp_cmnd32));
		spin_lock_irqsave(&hdwq->hdwq_lock, iflags);
		list_add_tail(&tmp->list_node, &lpfc_buf->dma_cmd_rsp_list);