> On Apr 19, 2021, at 6:01 AM, Kashyap Desai <kashyap.desai@xxxxxxxxxxxx> wrote: > > Signed-off-by: Kashyap Desai <kashyap.desai@xxxxxxxxxxxx> > Reviewed-by: Hannes Reinecke <hare@xxxxxxx> > Reviewed-by: Tomas Henzl <thenzl@xxxxxxxxxx> > > Cc: sathya.prakash@xxxxxxxxxxxx > --- > drivers/scsi/mpi3mr/mpi3mr.h | 7 +- > drivers/scsi/mpi3mr/mpi3mr_fw.c | 7 + > drivers/scsi/mpi3mr/mpi3mr_os.c | 303 +++++++++++++++++++++++++++++++- > 3 files changed, 311 insertions(+), 6 deletions(-) > > diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h > index db9cb11db3bf..6e5d83f8685a 100644 > --- a/drivers/scsi/mpi3mr/mpi3mr.h > +++ b/drivers/scsi/mpi3mr/mpi3mr.h > @@ -118,6 +118,7 @@ extern struct list_head mrioc_list; > #define MPI3MR_SENSEBUF_SZ 256 > #define MPI3MR_SENSEBUF_FACTOR 3 > #define MPI3MR_CHAINBUF_FACTOR 3 > +#define MPI3MR_CHAINBUFDIX_FACTOR 2 > > /* Invalid target device handle */ > #define MPI3MR_INVALID_DEV_HANDLE 0xFFFF > @@ -557,17 +558,21 @@ struct chain_element { > * > * @host_tag: Host tag specific to operational queue > * @in_lld_scope: Command in LLD scope or not > + * @meta_sg_valid: DIX command with meta data SGL or not > * @scmd: SCSI Command pointer > - * @req_q_idx: Operational request queue index > + * @req_q_idx: Operational request queue undex > * @chain_idx: Chain frame index > + * @meta_chain_idx: Chain frame index of meta data SGL > * @mpi3mr_scsiio_req: MPI SCSI IO request > */ > struct scmd_priv { > u16 host_tag; > u8 in_lld_scope; > + u8 meta_sg_valid; > struct scsi_cmnd *scmd; > u16 req_q_idx; > int chain_idx; > + int meta_chain_idx; > u8 mpi3mr_scsiio_req[MPI3MR_ADMIN_REQ_FRAME_SZ]; > }; > > diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c > index 488fc3eac9dc..ee20d63f6061 100644 > --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c > +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c > @@ -9,6 +9,7 @@ > > #include "mpi3mr.h" > #include <linux/io-64-nonatomic-lo-hi.h> > +extern int prot_mask; > > #if defined(writeq) && defined(CONFIG_64BIT) > static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr) > @@ -2767,6 +2768,12 @@ static int mpi3mr_alloc_chain_bufs(struct mpi3mr_ioc *mrioc) > > num_chains = mrioc->max_host_ios/MPI3MR_CHAINBUF_FACTOR; > > + if (prot_mask & (SHOST_DIX_TYPE0_PROTECTION > + | SHOST_DIX_TYPE1_PROTECTION > + | SHOST_DIX_TYPE2_PROTECTION > + | SHOST_DIX_TYPE3_PROTECTION)) > + num_chains += (num_chains / MPI3MR_CHAINBUFDIX_FACTOR); > + > mrioc->chain_buf_count = num_chains; > sz = sizeof(struct chain_element) * num_chains; > mrioc->chain_sgl_list = kzalloc(sz, GFP_KERNEL); > diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c > index 836005ce6999..9a189fb32ab0 100644 > --- a/drivers/scsi/mpi3mr/mpi3mr_os.c > +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c > @@ -21,6 +21,13 @@ MODULE_LICENSE(MPI3MR_DRIVER_LICENSE); > MODULE_VERSION(MPI3MR_DRIVER_VERSION); > > /* Module parameters*/ > +int prot_mask = -1; > +module_param(prot_mask, int, 0); > +MODULE_PARM_DESC(prot_mask, "Host protection capabilities mask, def=0x07"); > + I don’t really get this. Parameter description says "def=0x7" but you are initializing it to -1? > +int prot_guard_mask = 3; > +module_param(prot_guard_mask, int, 0); > +MODULE_PARM_DESC(prot_guard_mask, " Host protection guard mask, def=3"); > int logging_level; > module_param(logging_level, int, 0); > MODULE_PARM_DESC(logging_level, > @@ -59,7 +66,9 @@ static u16 mpi3mr_host_tag_for_scmd(struct mpi3mr_ioc *mrioc, > priv->scmd = scmd; > priv->in_lld_scope = 1; > priv->req_q_idx = hw_queue; > + priv->meta_chain_idx = -1; > priv->chain_idx = -1; > + priv->meta_sg_valid = 0; > return priv->host_tag; > } > > @@ -119,10 +128,15 @@ static void mpi3mr_clear_scmd_priv(struct mpi3mr_ioc *mrioc, > priv->req_q_idx = 0xFFFF; > priv->scmd = NULL; > priv->in_lld_scope = 0; > + priv->meta_sg_valid = 0; > if (priv->chain_idx >= 0) { > clear_bit(priv->chain_idx, mrioc->chain_bitmap); > priv->chain_idx = -1; > } > + if (priv->meta_chain_idx >= 0) { > + clear_bit(priv->meta_chain_idx, mrioc->chain_bitmap); > + priv->meta_chain_idx = -1; > + } > } > > static void mpi3mr_dev_rmhs_send_tm(struct mpi3mr_ioc *mrioc, u16 handle, > @@ -390,6 +404,9 @@ static bool mpi3mr_flush_scmd(struct request *rq, > if (!priv->in_lld_scope) > goto out; > > + if (priv->meta_sg_valid) > + dma_unmap_sg(&mrioc->pdev->dev, scsi_prot_sglist(scmd), > + scsi_prot_sg_count(scmd), scmd->sc_data_direction); > mpi3mr_clear_scmd_priv(mrioc, scmd); > scsi_dma_unmap(scmd); > scmd->result = DID_RESET << 16; > @@ -792,6 +809,7 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc, > { > u16 flags = 0; > struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data; > + u8 prot_mask = 0; > > tgtdev->perst_id = le16_to_cpu(dev_pg0->PersistentID); > tgtdev->dev_handle = le16_to_cpu(dev_pg0->DevHandle); > @@ -856,6 +874,15 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc, > if ((dev_info & MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) != > MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) > tgtdev->is_hidden = 1; > + if (mrioc->shost) > + prot_mask = scsi_host_get_prot(mrioc->shost); > + if (prot_mask & SHOST_DIX_TYPE0_PROTECTION) { > + scsi_host_set_prot(mrioc->shost, prot_mask & 0x77); > + ioc_info(mrioc, > + "%s : Disabling DIX0 prot capability\n", __func__); > + ioc_info(mrioc, > + "because HBA does not support DIX0 operation on NVME drives\n"); > + } > break; > } > case MPI3_DEVICE_DEVFORM_VD: > @@ -1769,6 +1796,195 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc, > > } > > +/** > + * mpi3mr_setup_eedp - Setup EEDP information in MPI3 SCSI IO > + * @mrioc: Adapter instance reference > + * @scmd: SCSI command reference > + * @scsiio_req: MPI3 SCSI IO request > + * > + * Identifies the protection information flags from the SCSI > + * command and set appropriate flags in the MPI3 SCSI IO > + * request. > + * > + * Return: Nothing > + */ > +static void mpi3mr_setup_eedp(struct mpi3mr_ioc *mrioc, > + struct scsi_cmnd *scmd, Mpi3SCSIIORequest_t *scsiio_req) > +{ > + u16 eedp_flags = 0; > + unsigned char prot_op = scsi_get_prot_op(scmd); > + unsigned char prot_type = scsi_get_prot_type(scmd); > + > + switch (prot_op) { > + case SCSI_PROT_NORMAL: > + return; > + case SCSI_PROT_READ_STRIP: > + eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_CHECK_REMOVE; > + break; > + case SCSI_PROT_WRITE_INSERT: > + eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_INSERT; > + break; > + case SCSI_PROT_READ_INSERT: > + eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_INSERT; > + scsiio_req->MsgFlags |= MPI3_SCSIIO_MSGFLAGS_METASGL_VALID; > + break; > + case SCSI_PROT_WRITE_STRIP: > + eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_CHECK_REMOVE; > + scsiio_req->MsgFlags |= MPI3_SCSIIO_MSGFLAGS_METASGL_VALID; > + break; > + case SCSI_PROT_READ_PASS: > + eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_CHECK | > + MPI3_EEDPFLAGS_CHK_REF_TAG | MPI3_EEDPFLAGS_CHK_APP_TAG | > + MPI3_EEDPFLAGS_CHK_GUARD; > + scsiio_req->MsgFlags |= MPI3_SCSIIO_MSGFLAGS_METASGL_VALID; > + break; > + case SCSI_PROT_WRITE_PASS: > + if (scsi_host_get_guard(scmd->device->host) > + & SHOST_DIX_GUARD_IP) { > + eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_CHECK_REGEN | > + MPI3_EEDPFLAGS_CHK_APP_TAG | > + MPI3_EEDPFLAGS_CHK_GUARD | > + MPI3_EEDPFLAGS_INCR_PRI_REF_TAG; > + scsiio_req->SGL[0].Eedp.ApplicationTagTranslationMask > + = 0xffff; > + } else { > + eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_CHECK | > + MPI3_EEDPFLAGS_CHK_REF_TAG | > + MPI3_EEDPFLAGS_CHK_APP_TAG | > + MPI3_EEDPFLAGS_CHK_GUARD; > + } > + scsiio_req->MsgFlags |= MPI3_SCSIIO_MSGFLAGS_METASGL_VALID; > + break; > + default: > + return; > + } > + > + if (scsi_host_get_guard(scmd->device->host) & SHOST_DIX_GUARD_IP) > + eedp_flags |= MPI3_EEDPFLAGS_HOST_GUARD_IP_CHKSUM; > + > + switch (prot_type) { > + case SCSI_PROT_DIF_TYPE0: > + eedp_flags |= MPI3_EEDPFLAGS_INCR_PRI_REF_TAG; > + scsiio_req->CDB.EEDP32.PrimaryReferenceTag = > + cpu_to_be32(t10_pi_ref_tag(scmd->request)); > + break; > + case SCSI_PROT_DIF_TYPE1: > + case SCSI_PROT_DIF_TYPE2: > + eedp_flags |= MPI3_EEDPFLAGS_INCR_PRI_REF_TAG | > + MPI3_EEDPFLAGS_ESC_MODE_APPTAG_DISABLE | > + MPI3_EEDPFLAGS_CHK_GUARD; > + scsiio_req->CDB.EEDP32.PrimaryReferenceTag = > + cpu_to_be32(t10_pi_ref_tag(scmd->request)); > + break; > + case SCSI_PROT_DIF_TYPE3: > + eedp_flags |= MPI3_EEDPFLAGS_CHK_GUARD | > + MPI3_EEDPFLAGS_ESC_MODE_APPTAG_DISABLE; > + break; > + > + default: > + scsiio_req->MsgFlags &= ~(MPI3_SCSIIO_MSGFLAGS_METASGL_VALID); > + return; > + } > + > + switch (scmd->device->sector_size) { > + case 512: > + scsiio_req->SGL[0].Eedp.UserDataSize = MPI3_EEDP_UDS_512; > + break; > + case 520: > + scsiio_req->SGL[0].Eedp.UserDataSize = MPI3_EEDP_UDS_520; > + break; > + case 4080: > + scsiio_req->SGL[0].Eedp.UserDataSize = MPI3_EEDP_UDS_4080; > + break; > + case 4088: > + scsiio_req->SGL[0].Eedp.UserDataSize = MPI3_EEDP_UDS_4088; > + break; > + case 4096: > + scsiio_req->SGL[0].Eedp.UserDataSize = MPI3_EEDP_UDS_4096; > + break; > + case 4104: > + scsiio_req->SGL[0].Eedp.UserDataSize = MPI3_EEDP_UDS_4104; > + break; > + case 4160: > + scsiio_req->SGL[0].Eedp.UserDataSize = MPI3_EEDP_UDS_4160; > + break; > + default: > + break; > + } > + > + scsiio_req->SGL[0].Eedp.EEDPFlags = cpu_to_le16(eedp_flags); > + scsiio_req->SGL[0].Eedp.Flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_EXTENDED; > +} > + > + > + > +/** > + * mpi3mr_build_sense_buffer - Map sense information > + * @desc: Sense type > + * @buf: Sense buffer to populate > + * @key: Sense key > + * @asc: Additional sense code > + * @ascq: Additional sense code qualifier > + * > + * Maps the given sense information into either descriptor or > + * fixed format sense data. > + * > + * Return: Nothing > + */ > +static inline void mpi3mr_build_sense_buffer(int desc, u8 *buf, u8 key, > + u8 asc, u8 ascq) > +{ > + if (desc) { > + buf[0] = 0x72; /* descriptor, current */ > + buf[1] = key; > + buf[2] = asc; > + buf[3] = ascq; > + buf[7] = 0; > + } else { > + buf[0] = 0x70; /* fixed, current */ > + buf[2] = key; > + buf[7] = 0xa; > + buf[12] = asc; > + buf[13] = ascq; > + } > +} > + > +/** > + * mpi3mr_map_eedp_error - Map EEDP errors from IOC status > + * @scmd: SCSI command reference > + * @ioc_status: Status of MPI3 request > + * > + * Maps the EEDP error status of the SCSI IO request to sense > + * data. > + * > + * Return: Nothing > + */ > +static void mpi3mr_map_eedp_error(struct scsi_cmnd *scmd, > + u16 ioc_status) > +{ > + u8 ascq = 0; > + > + switch (ioc_status) { > + case MPI3_IOCSTATUS_EEDP_GUARD_ERROR: > + ascq = 0x01; > + break; > + case MPI3_IOCSTATUS_EEDP_APP_TAG_ERROR: > + ascq = 0x02; > + break; > + case MPI3_IOCSTATUS_EEDP_REF_TAG_ERROR: > + ascq = 0x03; > + break; > + default: > + ascq = 0x00; > + break; > + } > + > + mpi3mr_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST, > + 0x10, ascq); > + scmd->result = DRIVER_SENSE << 24 | (DID_ABORT << 16) | > + SAM_STAT_CHECK_CONDITION; > +} > + > /** > * mpi3mr_process_op_reply_desc - reply descriptor handler > * @mrioc: Adapter instance reference > @@ -1931,6 +2147,11 @@ void mpi3mr_process_op_reply_desc(struct mpi3mr_ioc *mrioc, > else if (scsi_state & MPI3_SCSI_STATE_TERMINATED) > scmd->result = DID_RESET << 16; > break; > + case MPI3_IOCSTATUS_EEDP_GUARD_ERROR: > + case MPI3_IOCSTATUS_EEDP_REF_TAG_ERROR: > + case MPI3_IOCSTATUS_EEDP_APP_TAG_ERROR: > + mpi3mr_map_eedp_error(scmd, ioc_status); > + break; > case MPI3_IOCSTATUS_SCSI_PROTOCOL_ERROR: > case MPI3_IOCSTATUS_INVALID_FUNCTION: > case MPI3_IOCSTATUS_INVALID_SGL: > @@ -1966,6 +2187,10 @@ void mpi3mr_process_op_reply_desc(struct mpi3mr_ioc *mrioc, > } > } > out_success: > + if (priv->meta_sg_valid) { > + dma_unmap_sg(&mrioc->pdev->dev, scsi_prot_sglist(scmd), > + scsi_prot_sg_count(scmd), scmd->sc_data_direction); > + } > mpi3mr_clear_scmd_priv(mrioc, scmd); > scsi_dma_unmap(scmd); > scmd->scsi_done(scmd); > @@ -2029,6 +2254,8 @@ static int mpi3mr_prepare_sg_scmd(struct mpi3mr_ioc *mrioc, > u8 last_chain_sgl_flags; > struct chain_element *chain_req; > struct scmd_priv *priv = NULL; > + u32 meta_sg = le32_to_cpu(scsiio_req->Flags) & > + MPI3_SCSIIO_FLAGS_DMAOPERATION_HOST_PI; > > priv = scsi_cmd_priv(scmd); > > @@ -2039,15 +2266,27 @@ static int mpi3mr_prepare_sg_scmd(struct mpi3mr_ioc *mrioc, > last_chain_sgl_flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_LAST_CHAIN | > MPI3_SGE_FLAGS_DLAS_SYSTEM; > > - sg_local = &scsiio_req->SGL; > + if (meta_sg) > + sg_local = &scsiio_req->SGL[MPI3_SCSIIO_METASGL_INDEX]; > + else > + sg_local = &scsiio_req->SGL; > > - if (!scsiio_req->DataLength) { > + if (!scsiio_req->DataLength && !meta_sg) { > mpi3mr_build_zero_len_sge(sg_local); > return 0; > } > > - sg_scmd = scsi_sglist(scmd); > - sges_left = scsi_dma_map(scmd); > + if (meta_sg) { > + sg_scmd = scsi_prot_sglist(scmd); > + sges_left = dma_map_sg(&mrioc->pdev->dev, > + scsi_prot_sglist(scmd), > + scsi_prot_sg_count(scmd), > + scmd->sc_data_direction); > + priv->meta_sg_valid = 1; /* To unmap meta sg DMA */ > + } else { > + sg_scmd = scsi_sglist(scmd); > + sges_left = scsi_dma_map(scmd); > + } > > if (sges_left < 0) { > sdev_printk(KERN_ERR, scmd->device, > @@ -2065,6 +2304,22 @@ static int mpi3mr_prepare_sg_scmd(struct mpi3mr_ioc *mrioc, > sges_in_segment = (mrioc->facts.op_req_sz - > offsetof(Mpi3SCSIIORequest_t, SGL))/sizeof(Mpi3SGESimple_t); > > + if (scsiio_req->SGL[0].Eedp.Flags == > + MPI3_SGE_FLAGS_ELEMENT_TYPE_EXTENDED && !meta_sg) { > + sg_local += sizeof(Mpi3SGEUnion_t); > + sges_in_segment--; > + /* Reserve 1st segment (scsiio_req->SGL[0]) for eedp */ > + } > + > + if (scsiio_req->MsgFlags == > + MPI3_SCSIIO_MSGFLAGS_METASGL_VALID && !meta_sg) { > + sges_in_segment--; > + /* Reserve last segment (scsiio_req->SGL[3]) for meta sg */ > + } > + > + if (meta_sg) > + sges_in_segment = 1; > + > if (sges_left <= sges_in_segment) > goto fill_in_last_segment; > > @@ -2082,7 +2337,10 @@ static int mpi3mr_prepare_sg_scmd(struct mpi3mr_ioc *mrioc, > if (chain_idx < 0) > return -1; > chain_req = &mrioc->chain_sgl_list[chain_idx]; > - priv->chain_idx = chain_idx; > + if (meta_sg) > + priv->meta_chain_idx = chain_idx; > + else > + priv->chain_idx = chain_idx; > > chain = chain_req->addr; > chain_dma = chain_req->dma_addr; > @@ -2132,6 +2390,13 @@ static int mpi3mr_build_sg_scmd(struct mpi3mr_ioc *mrioc, > if (ret) > return ret; > > + if (scsiio_req->MsgFlags == MPI3_SCSIIO_MSGFLAGS_METASGL_VALID) { > + /* There is a valid meta sg */ > + scsiio_req->Flags |= > + cpu_to_le32(MPI3_SCSIIO_FLAGS_DMAOPERATION_HOST_PI); > + ret = mpi3mr_prepare_sg_scmd(mrioc, scmd, scsiio_req); > + } > + > return ret; > } > > @@ -3130,6 +3395,8 @@ static int mpi3mr_qcmd(struct Scsi_Host *shost, > scsiio_req->Function = MPI3_FUNCTION_SCSI_IO; > scsiio_req->HostTag = cpu_to_le16(host_tag); > > + mpi3mr_setup_eedp(mrioc, scmd, scsiio_req); > + > memcpy(scsiio_req->CDB.CDB32, scmd->cmnd, scmd->cmd_len); > scsiio_req->DataLength = cpu_to_le32(scsi_bufflen(scmd)); > scsiio_req->DevHandle = cpu_to_le16(dev_handle); > @@ -3354,6 +3621,32 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id) > shost->max_channel = 1; > shost->max_id = 0xFFFFFFFF; > > + if (prot_mask >= 0) > + scsi_host_set_prot(shost, prot_mask); > + else { > + prot_mask = SHOST_DIF_TYPE1_PROTECTION > + | SHOST_DIF_TYPE2_PROTECTION > + | SHOST_DIF_TYPE3_PROTECTION; > + scsi_host_set_prot(shost, prot_mask); > + > + } > + > + ioc_info(mrioc, > + "%s :host protection capabilities enabled %s%s%s%s%s%s%s\n", > + __func__, > + (prot_mask & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "", > + (prot_mask & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "", > + (prot_mask & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "", > + (prot_mask & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "", > + (prot_mask & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "", > + (prot_mask & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "", > + (prot_mask & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : ""); > + > + if (prot_guard_mask) > + scsi_host_set_guard(shost, (prot_guard_mask & 3)); > + else > + scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC); > + > snprintf(mrioc->fwevt_worker_name, sizeof(mrioc->fwevt_worker_name), > "%s%d_fwevt_wrkr", mrioc->driver_name, mrioc->id); > mrioc->fwevt_worker_thread = alloc_ordered_workqueue( > -- > 2.18.1 > -- Himanshu Madhani Oracle Linux Engineering