> On Apr 13, 2022, at 7:56 AM, Sumit Saxena <sumit.saxena@xxxxxxxxxxxx> wrote: > > There are certain BSG commands which is to be completed > by driver without involving firmware. These requests are termed > as driver commands. This patch adds support for the same. > > Signed-off-by: Sumit Saxena <sumit.saxena@xxxxxxxxxxxx> > --- > drivers/scsi/mpi3mr/mpi3mr.h | 16 +- > drivers/scsi/mpi3mr/mpi3mr_app.c | 392 +++++++++++++++++++++++++ > drivers/scsi/mpi3mr/mpi3mr_debug.h | 12 +- > drivers/scsi/mpi3mr/mpi3mr_fw.c | 21 +- > drivers/scsi/mpi3mr/mpi3mr_os.c | 3 + > include/uapi/scsi/scsi_bsg_mpi3mr.h | 433 ++++++++++++++++++++++++++++ > 6 files changed, 865 insertions(+), 12 deletions(-) > create mode 100644 include/uapi/scsi/scsi_bsg_mpi3mr.h > > diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h > index f0515f929110..877b0925dbc5 100644 > --- a/drivers/scsi/mpi3mr/mpi3mr.h > +++ b/drivers/scsi/mpi3mr/mpi3mr.h > @@ -89,7 +89,7 @@ extern int prot_mask; > /* Reserved Host Tag definitions */ > #define MPI3MR_HOSTTAG_INVALID 0xFFFF > #define MPI3MR_HOSTTAG_INITCMDS 1 > -#define MPI3MR_HOSTTAG_IOCTLCMDS 2 > +#define MPI3MR_HOSTTAG_BSG_CMDS 2 > #define MPI3MR_HOSTTAG_BLK_TMS 5 > > #define MPI3MR_NUM_DEVRMCMD 16 > @@ -202,10 +202,10 @@ enum mpi3mr_iocstate { > enum mpi3mr_reset_reason { > MPI3MR_RESET_FROM_BRINGUP = 1, > MPI3MR_RESET_FROM_FAULT_WATCH = 2, > - MPI3MR_RESET_FROM_IOCTL = 3, > + MPI3MR_RESET_FROM_APP = 3, > MPI3MR_RESET_FROM_EH_HOS = 4, > MPI3MR_RESET_FROM_TM_TIMEOUT = 5, > - MPI3MR_RESET_FROM_IOCTL_TIMEOUT = 6, > + MPI3MR_RESET_FROM_APP_TIMEOUT = 6, > MPI3MR_RESET_FROM_MUR_FAILURE = 7, > MPI3MR_RESET_FROM_CTLR_CLEANUP = 8, > MPI3MR_RESET_FROM_CIACTIV_FAULT = 9, > @@ -698,6 +698,7 @@ struct scmd_priv { > * @chain_bitmap_sz: Chain buffer allocator bitmap size > * @chain_bitmap: Chain buffer allocator bitmap > * @chain_buf_lock: Chain buffer list lock > + * @bsg_cmds: Command tracker for BSG command > * @host_tm_cmds: Command tracker for task management commands > * @dev_rmhs_cmds: Command tracker for device removal commands > * @evtack_cmds: Command tracker for event ack commands > @@ -729,6 +730,10 @@ struct scmd_priv { > * @requested_poll_qcount: User requested poll queue count > * @bsg_dev: BSG device structure > * @bsg_queue: Request queue for BSG device > + * @stop_bsgs: Stop BSG request flag > + * @logdata_buf: Circular buffer to store log data entries > + * @logdata_buf_idx: Index of entry in buffer to store > + * @logdata_entry_sz: log data entry size > */ > struct mpi3mr_ioc { > struct list_head list; > @@ -835,6 +840,7 @@ struct mpi3mr_ioc { > void *chain_bitmap; > spinlock_t chain_buf_lock; > > + struct mpi3mr_drv_cmd bsg_cmds; > struct mpi3mr_drv_cmd host_tm_cmds; > struct mpi3mr_drv_cmd dev_rmhs_cmds[MPI3MR_NUM_DEVRMCMD]; > struct mpi3mr_drv_cmd evtack_cmds[MPI3MR_NUM_EVTACKCMD]; > @@ -872,6 +878,10 @@ struct mpi3mr_ioc { > > struct device *bsg_dev; > struct request_queue *bsg_queue; > + u8 stop_bsgs; > + u8 *logdata_buf; > + u16 logdata_buf_idx; > + u16 logdata_entry_sz; > }; > > /** > diff --git a/drivers/scsi/mpi3mr/mpi3mr_app.c b/drivers/scsi/mpi3mr/mpi3mr_app.c > index 9b6698525990..a1ca1f26bd08 100644 > --- a/drivers/scsi/mpi3mr/mpi3mr_app.c > +++ b/drivers/scsi/mpi3mr/mpi3mr_app.c > @@ -9,6 +9,381 @@ > > #include "mpi3mr.h" > #include <linux/bsg-lib.h> > +#include <uapi/scsi/scsi_bsg_mpi3mr.h> > + > +/** > + * mpi3mr_bsg_verify_adapter - verify adapter number is valid > + * @ioc_number: Adapter number > + * > + * This function returns the adapter instance pointer of given > + * adapter number. If adapter number does not match with the > + * driver's adapter list, driver returns NULL. > + * > + * Return: adapter instance reference > + */ > +static struct mpi3mr_ioc *mpi3mr_bsg_verify_adapter(int ioc_number) > +{ > + struct mpi3mr_ioc *mrioc = NULL; > + > + spin_lock(&mrioc_list_lock); > + list_for_each_entry(mrioc, &mrioc_list, list) { > + if (mrioc->id == ioc_number) { > + spin_unlock(&mrioc_list_lock); > + return mrioc; > + } > + } > + spin_unlock(&mrioc_list_lock); > + return NULL; > +} > + > +/** > + * mpi3mr_enable_logdata - Handler for log data enable > + * @mrioc: Adapter instance reference > + * @job: BSG job reference > + * > + * This function enables log data caching in the driver if not > + * already enabled and return the maximum number of log data > + * entries that can be cached in the driver. > + * > + * Return: 0 on success and proper error codes on failure > + */ > +static long mpi3mr_enable_logdata(struct mpi3mr_ioc *mrioc, > + struct bsg_job *job) > +{ > + long rval = -EINVAL; > + struct mpi3mr_logdata_enable logdata_enable; > + > + if (!mrioc->logdata_buf) { > + mrioc->logdata_entry_sz = > + (mrioc->reply_sz - (sizeof(struct mpi3_event_notification_reply) - 4)) > + + MPI3MR_BSG_LOGDATA_ENTRY_HEADER_SZ; > + mrioc->logdata_buf_idx = 0; > + mrioc->logdata_buf = kcalloc(MPI3MR_BSG_LOGDATA_MAX_ENTRIES, > + mrioc->logdata_entry_sz, GFP_KERNEL); > + > + if (!mrioc->logdata_buf) > + return -ENOMEM; > + } > + > + memset(&logdata_enable, 0, sizeof(logdata_enable)); > + logdata_enable.max_entries = > + MPI3MR_BSG_LOGDATA_MAX_ENTRIES; > + if (job->request_payload.payload_len >= sizeof(logdata_enable)) { > + sg_copy_from_buffer(job->request_payload.sg_list, > + job->request_payload.sg_cnt, > + &logdata_enable, sizeof(logdata_enable)); > + rval = 0; Just return 0 here > + } > + > + return rval; > +} > +/** > + * mpi3mr_get_logdata - Handler for get log data > + * @mrioc: Adapter instance reference > + * @job: BSG job pointer > + * This function copies the log data entries to the user buffer > + * when log caching is enabled in the driver. > + * > + * Return: 0 on success and proper error codes on failure > + */ > +static long mpi3mr_get_logdata(struct mpi3mr_ioc *mrioc, > + struct bsg_job *job) > +{ > + u16 num_entries, sz, entry_sz = mrioc->logdata_entry_sz; > + > + if ((!mrioc->logdata_buf) || (job->request_payload.payload_len < entry_sz)) > + return -EINVAL; > + > + num_entries = job->request_payload.payload_len / entry_sz; > + if (num_entries > MPI3MR_BSG_LOGDATA_MAX_ENTRIES) > + num_entries = MPI3MR_BSG_LOGDATA_MAX_ENTRIES; > + sz = num_entries * entry_sz; > + > + if (job->request_payload.payload_len >= sz) { > + sg_copy_from_buffer(job->request_payload.sg_list, > + job->request_payload.sg_cnt, > + mrioc->logdata_buf, sz); > + return 0; > + } > + return -EINVAL; > +} > + > +/** > + * mpi3mr_get_all_tgt_info - Get all target information > + * @mrioc: Adapter instance reference > + * @job: BSG job reference > + * > + * This function copies the driver managed target devices device > + * handle, persistent ID, bus ID and taret ID to the user > + * provided buffer for the specific controller. This function > + * also provides the number of devices managed by the driver for > + * the specific controller. > + * > + * Return: 0 on success and proper error codes on failure > + */ > +static long mpi3mr_get_all_tgt_info(struct mpi3mr_ioc *mrioc, > + struct bsg_job *job) > +{ > + long rval = -EINVAL; > + u16 num_devices = 0, i = 0, size; > + unsigned long flags; > + struct mpi3mr_tgt_dev *tgtdev; > + struct mpi3mr_device_map_info *devmap_info = NULL; > + struct mpi3mr_all_tgt_info *alltgt_info = NULL; > + uint32_t min_entrylen = 0, kern_entrylen = 0, usr_entrylen = 0; > + > + if (job->request_payload.payload_len < sizeof(u32)) { > + dprint_bsg_err(mrioc, "%s: invalid size argument\n", > + __func__); > + return rval; > + } > + > + spin_lock_irqsave(&mrioc->tgtdev_lock, flags); > + list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list) > + num_devices++; > + spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags); > + > + if ((job->request_payload.payload_len == sizeof(u32)) || > + list_empty(&mrioc->tgtdev_list)) { > + sg_copy_from_buffer(job->request_payload.sg_list, > + job->request_payload.sg_cnt, > + &num_devices, sizeof(num_devices)); > + return 0; > + } > + > + kern_entrylen = (num_devices - 1) * sizeof(*devmap_info); > + size = sizeof(*alltgt_info) + kern_entrylen; > + alltgt_info = kzalloc(size, GFP_KERNEL); > + if (!alltgt_info) > + return -ENOMEM; > + > + devmap_info = alltgt_info->dmi; > + memset((u8 *)devmap_info, 0xFF, (kern_entrylen + sizeof(*devmap_info))); > + spin_lock_irqsave(&mrioc->tgtdev_lock, flags); > + list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list) { > + if (i < num_devices) { > + devmap_info[i].handle = tgtdev->dev_handle; > + devmap_info[i].perst_id = tgtdev->perst_id; > + if (tgtdev->host_exposed && tgtdev->starget) { > + devmap_info[i].target_id = tgtdev->starget->id; > + devmap_info[i].bus_id = > + tgtdev->starget->channel; > + } > + i++; > + } > + } > + num_devices = i; > + spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags); > + > + memcpy(&alltgt_info->num_devices, &num_devices, sizeof(num_devices)); > + > + usr_entrylen = (job->request_payload.payload_len - sizeof(u32)) / sizeof(*devmap_info); > + usr_entrylen *= sizeof(*devmap_info); > + min_entrylen = min(usr_entrylen, kern_entrylen); > + if (min_entrylen && (!memcpy(&alltgt_info->dmi, devmap_info, min_entrylen))) { > + dprint_bsg_err(mrioc, "%s:%d: device map info copy failed\n", > + __func__, __LINE__); > + rval = -EFAULT; > + goto out; > + } > + > + sg_copy_from_buffer(job->request_payload.sg_list, > + job->request_payload.sg_cnt, > + alltgt_info, job->request_payload.payload_len); > + rval = 0; > +out: > + kfree(alltgt_info); > + return rval; > +} > + > +/** > + * mpi3mr_get_change_count - Get topology change count > + * @mrioc: Adapter instance reference > + * @job: BSG job reference > + * > + * This function copies the toplogy change count provided by the > + * driver in events and cached in the driver to the user > + * provided buffer for the specific controller. > + * > + * Return: 0 on success and proper error codes on failure > + */ > +static long mpi3mr_get_change_count(struct mpi3mr_ioc *mrioc, > + struct bsg_job *job) > +{ > + long rval = -EINVAL; > + struct mpi3mr_change_count chgcnt; > + > + memset(&chgcnt, 0, sizeof(chgcnt)); > + chgcnt.change_count = mrioc->change_count; > + if (job->request_payload.payload_len >= sizeof(chgcnt)) { > + sg_copy_from_buffer(job->request_payload.sg_list, > + job->request_payload.sg_cnt, > + &chgcnt, sizeof(chgcnt)); > + rval = 0; Just do return 0 > + } > + return rval; > +} > + > +/** > + * mpi3mr_bsg_adp_reset - Issue controller reset > + * @mrioc: Adapter instance reference > + * @job: BSG job reference > + * > + * This function identifies the user provided reset type and > + * issues approporiate reset to the controller and wait for that > + * to complete and reinitialize the controller and then returns > + * > + * Return: 0 on success and proper error codes on failure > + */ > +static long mpi3mr_bsg_adp_reset(struct mpi3mr_ioc *mrioc, > + struct bsg_job *job) > +{ > + long rval = -EINVAL; > + u8 save_snapdump; > + struct mpi3mr_bsg_adp_reset adpreset; > + > + if (job->request_payload.payload_len != > + sizeof(adpreset)) { > + dprint_bsg_err(mrioc, "%s: invalid size argument\n", > + __func__); > + goto out; > + } > + > + sg_copy_to_buffer(job->request_payload.sg_list, > + job->request_payload.sg_cnt, > + &adpreset, sizeof(adpreset)); > + > + switch (adpreset.reset_type) { > + case MPI3MR_BSG_ADPRESET_SOFT: > + save_snapdump = 0; > + break; > + case MPI3MR_BSG_ADPRESET_DIAG_FAULT: > + save_snapdump = 1; > + break; > + default: > + dprint_bsg_err(mrioc, "%s: unknown reset_type(%d)\n", > + __func__, adpreset.reset_type); > + goto out; > + } > + > + rval = mpi3mr_soft_reset_handler(mrioc, MPI3MR_RESET_FROM_APP, > + save_snapdump); > + > + if (rval) > + dprint_bsg_err(mrioc, > + "%s: reset handler returned error(%ld) for reset type %d\n", > + __func__, rval, adpreset.reset_type); > +out: > + return rval; > +} > + > +/** > + * mpi3mr_bsg_populate_adpinfo - Get adapter info command handler > + * @mrioc: Adapter instance reference > + * @job: BSG job reference > + * > + * This function provides adapter information for the given > + * controller > + * > + * Return: 0 on success and proper error codes on failure > + */ > +static long mpi3mr_bsg_populate_adpinfo(struct mpi3mr_ioc *mrioc, > + struct bsg_job *job) > +{ > + enum mpi3mr_iocstate ioc_state; > + struct mpi3mr_bsg_in_adpinfo adpinfo; > + > + memset(&adpinfo, 0, sizeof(adpinfo)); > + adpinfo.adp_type = MPI3MR_BSG_ADPTYPE_AVGFAMILY; > + adpinfo.pci_dev_id = mrioc->pdev->device; > + adpinfo.pci_dev_hw_rev = mrioc->pdev->revision; > + adpinfo.pci_subsys_dev_id = mrioc->pdev->subsystem_device; > + adpinfo.pci_subsys_ven_id = mrioc->pdev->subsystem_vendor; > + adpinfo.pci_bus = mrioc->pdev->bus->number; > + adpinfo.pci_dev = PCI_SLOT(mrioc->pdev->devfn); > + adpinfo.pci_func = PCI_FUNC(mrioc->pdev->devfn); > + adpinfo.pci_seg_id = pci_domain_nr(mrioc->pdev->bus); > + adpinfo.app_intfc_ver = MPI3MR_IOCTL_VERSION; > + > + ioc_state = mpi3mr_get_iocstate(mrioc); > + if (ioc_state == MRIOC_STATE_UNRECOVERABLE) > + adpinfo.adp_state = MPI3MR_BSG_ADPSTATE_UNRECOVERABLE; > + else if ((mrioc->reset_in_progress) || (mrioc->stop_bsgs)) > + adpinfo.adp_state = MPI3MR_BSG_ADPSTATE_IN_RESET; > + else if (ioc_state == MRIOC_STATE_FAULT) > + adpinfo.adp_state = MPI3MR_BSG_ADPSTATE_FAULT; > + else > + adpinfo.adp_state = MPI3MR_BSG_ADPSTATE_OPERATIONAL; > + > + memcpy((u8 *)&adpinfo.driver_info, (u8 *)&mrioc->driver_info, > + sizeof(adpinfo.driver_info)); > + > + if (job->request_payload.payload_len >= sizeof(adpinfo)) { > + sg_copy_from_buffer(job->request_payload.sg_list, > + job->request_payload.sg_cnt, > + &adpinfo, sizeof(adpinfo)); > + return 0; > + } > + return -EINVAL; > +} > + > +/** > + * mpi3mr_bsg_process_drv_cmds - Driver Command handler > + * @job: BSG job reference > + * > + * This function is the top level handler for driver commands, > + * this does basic validation of the buffer and identifies the > + * opcode and switches to correct sub handler. > + * > + * Return: 0 on success and proper error codes on failure > + */ > +static long mpi3mr_bsg_process_drv_cmds(struct bsg_job *job) > +{ > + long rval = -EINVAL; > + struct mpi3mr_ioc *mrioc = NULL; > + struct mpi3mr_bsg_packet *bsg_req = NULL; > + struct mpi3mr_bsg_drv_cmd *drvrcmd = NULL; > + > + bsg_req = job->request; > + drvrcmd = &bsg_req->cmd.drvrcmd; > + > + mrioc = mpi3mr_bsg_verify_adapter(drvrcmd->mrioc_id); > + if (!mrioc) > + return -ENODEV; > + > + if (drvrcmd->opcode == MPI3MR_DRVBSG_OPCODE_ADPINFO) { > + rval = mpi3mr_bsg_populate_adpinfo(mrioc, job); > + return rval; > + } > + > + if (mutex_lock_interruptible(&mrioc->bsg_cmds.mutex)) > + return -ERESTARTSYS; > + > + switch (drvrcmd->opcode) { > + case MPI3MR_DRVBSG_OPCODE_ADPRESET: > + rval = mpi3mr_bsg_adp_reset(mrioc, job); > + break; > + case MPI3MR_DRVBSG_OPCODE_ALLTGTDEVINFO: > + rval = mpi3mr_get_all_tgt_info(mrioc, job); > + break; > + case MPI3MR_DRVBSG_OPCODE_GETCHGCNT: > + rval = mpi3mr_get_change_count(mrioc, job); > + break; > + case MPI3MR_DRVBSG_OPCODE_LOGDATAENABLE: > + rval = mpi3mr_enable_logdata(mrioc, job); > + break; > + case MPI3MR_DRVBSG_OPCODE_GETLOGDATA: > + rval = mpi3mr_get_logdata(mrioc, job); > + break; > + case MPI3MR_DRVBSG_OPCODE_UNKNOWN: > + default: > + pr_err("%s: unsupported driver command opcode %d\n", > + MPI3MR_DRIVER_NAME, drvrcmd->opcode); > + break; > + } > + mutex_unlock(&mrioc->bsg_cmds.mutex); > + return rval; > +} > > /** > * mpi3mr_bsg_request - bsg request entry point > @@ -20,6 +395,23 @@ > */ > int mpi3mr_bsg_request(struct bsg_job *job) > { > + long rval = -EINVAL; > + unsigned int reply_payload_rcv_len = 0; > + > + struct mpi3mr_bsg_packet *bsg_req = job->request; > + > + switch (bsg_req->cmd_type) { > + case MPI3MR_DRV_CMD: > + rval = mpi3mr_bsg_process_drv_cmds(job); > + break; > + default: > + pr_err("%s: unsupported BSG command(0x%08x)\n", > + MPI3MR_DRIVER_NAME, bsg_req->cmd_type); > + break; > + } > + > + bsg_job_done(job, rval, reply_payload_rcv_len); > + > return 0; > } > > diff --git a/drivers/scsi/mpi3mr/mpi3mr_debug.h b/drivers/scsi/mpi3mr/mpi3mr_debug.h > index c7982443f45a..65bfac72948c 100644 > --- a/drivers/scsi/mpi3mr/mpi3mr_debug.h > +++ b/drivers/scsi/mpi3mr/mpi3mr_debug.h > @@ -23,8 +23,8 @@ > #define MPI3_DEBUG_RESET 0x00000020 > #define MPI3_DEBUG_SCSI_ERROR 0x00000040 > #define MPI3_DEBUG_REPLY 0x00000080 > -#define MPI3_DEBUG_IOCTL_ERROR 0x00008000 > -#define MPI3_DEBUG_IOCTL_INFO 0x00010000 > +#define MPI3_DEBUG_BSG_ERROR 0x00008000 > +#define MPI3_DEBUG_BSG_INFO 0x00010000 > #define MPI3_DEBUG_SCSI_INFO 0x00020000 > #define MPI3_DEBUG 0x01000000 > #define MPI3_DEBUG_SG 0x02000000 > @@ -110,15 +110,15 @@ > } while (0) > > > -#define dprint_ioctl_info(ioc, fmt, ...) \ > +#define dprint_bsg_info(ioc, fmt, ...) \ > do { \ > - if (ioc->logging_level & MPI3_DEBUG_IOCTL_INFO) \ > + if (ioc->logging_level & MPI3_DEBUG_BSG_INFO) \ > pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__); \ > } while (0) > > -#define dprint_ioctl_err(ioc, fmt, ...) \ > +#define dprint_bsg_err(ioc, fmt, ...) \ > do { \ > - if (ioc->logging_level & MPI3_DEBUG_IOCTL_ERROR) \ > + if (ioc->logging_level & MPI3_DEBUG_BSG_ERROR) \ > pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__); \ > } while (0) > > diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c > index e25c02466043..480730721f50 100644 > --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c > +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c > @@ -297,6 +297,8 @@ mpi3mr_get_drv_cmd(struct mpi3mr_ioc *mrioc, u16 host_tag, > switch (host_tag) { > case MPI3MR_HOSTTAG_INITCMDS: > return &mrioc->init_cmds; > + case MPI3MR_HOSTTAG_BSG_CMDS: > + return &mrioc->bsg_cmds; > case MPI3MR_HOSTTAG_BLK_TMS: > return &mrioc->host_tm_cmds; > case MPI3MR_HOSTTAG_INVALID: > @@ -865,10 +867,10 @@ static const struct { > } mpi3mr_reset_reason_codes[] = { > { MPI3MR_RESET_FROM_BRINGUP, "timeout in bringup" }, > { MPI3MR_RESET_FROM_FAULT_WATCH, "fault" }, > - { MPI3MR_RESET_FROM_IOCTL, "application invocation" }, > + { MPI3MR_RESET_FROM_APP, "application invocation" }, > { MPI3MR_RESET_FROM_EH_HOS, "error handling" }, > { MPI3MR_RESET_FROM_TM_TIMEOUT, "TM timeout" }, > - { MPI3MR_RESET_FROM_IOCTL_TIMEOUT, "IOCTL timeout" }, > + { MPI3MR_RESET_FROM_APP_TIMEOUT, "application command timeout" }, > { MPI3MR_RESET_FROM_MUR_FAILURE, "MUR failure" }, > { MPI3MR_RESET_FROM_CTLR_CLEANUP, "timeout in controller cleanup" }, > { MPI3MR_RESET_FROM_CIACTIV_FAULT, "component image activation fault" }, > @@ -2813,6 +2815,10 @@ static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc) > if (!mrioc->init_cmds.reply) > goto out_failed; > > + mrioc->bsg_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL); > + if (!mrioc->bsg_cmds.reply) > + goto out_failed; > + > for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) { > mrioc->dev_rmhs_cmds[i].reply = kzalloc(mrioc->reply_sz, > GFP_KERNEL); > @@ -3948,6 +3954,8 @@ void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc) > > if (mrioc->init_cmds.reply) { > memset(mrioc->init_cmds.reply, 0, sizeof(*mrioc->init_cmds.reply)); > + memset(mrioc->bsg_cmds.reply, 0, > + sizeof(*mrioc->bsg_cmds.reply)); > memset(mrioc->host_tm_cmds.reply, 0, > sizeof(*mrioc->host_tm_cmds.reply)); > for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) > @@ -4050,6 +4058,9 @@ void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc) > kfree(mrioc->init_cmds.reply); > mrioc->init_cmds.reply = NULL; > > + kfree(mrioc->bsg_cmds.reply); > + mrioc->bsg_cmds.reply = NULL; > + > kfree(mrioc->host_tm_cmds.reply); > mrioc->host_tm_cmds.reply = NULL; > > @@ -4235,6 +4246,8 @@ static void mpi3mr_flush_drv_cmds(struct mpi3mr_ioc *mrioc) > > cmdptr = &mrioc->init_cmds; > mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr); > + cmdptr = &mrioc->bsg_cmds; > + mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr); > cmdptr = &mrioc->host_tm_cmds; > mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr); > > @@ -4258,7 +4271,7 @@ static void mpi3mr_flush_drv_cmds(struct mpi3mr_ioc *mrioc) > * This is an handler for recovering controller by issuing soft > * reset are diag fault reset. This is a blocking function and > * when one reset is executed if any other resets they will be > - * blocked. All IOCTLs/IO will be blocked during the reset. If > + * blocked. All BSG requests will be blocked during the reset. If > * controller reset is successful then the controller will be > * reinitalized, otherwise the controller will be marked as not > * recoverable > @@ -4305,6 +4318,7 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, > mpi3mr_reset_rc_name(reset_reason)); > > mrioc->reset_in_progress = 1; > + mrioc->stop_bsgs = 1; > mrioc->prev_reset_result = -1; > > if ((!snapdump) && (reset_reason != MPI3MR_RESET_FROM_FAULT_WATCH) && > @@ -4377,6 +4391,7 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, > &mrioc->watchdog_work, > msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL)); > spin_unlock_irqrestore(&mrioc->watchdog_lock, flags); > + mrioc->stop_bsgs = 0; > } else { > mpi3mr_issue_reset(mrioc, > MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason); > diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c > index faf14a5f9123..a03e39083a42 100644 > --- a/drivers/scsi/mpi3mr/mpi3mr_os.c > +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c > @@ -3589,6 +3589,7 @@ static int mpi3mr_scan_finished(struct Scsi_Host *shost, > > mpi3mr_start_watchdog(mrioc); > mrioc->is_driver_loading = 0; > + mrioc->stop_bsgs = 0; > return 1; > } > > @@ -4259,6 +4260,7 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id) > mutex_init(&mrioc->reset_mutex); > mpi3mr_init_drv_cmd(&mrioc->init_cmds, MPI3MR_HOSTTAG_INITCMDS); > mpi3mr_init_drv_cmd(&mrioc->host_tm_cmds, MPI3MR_HOSTTAG_BLK_TMS); > + mpi3mr_init_drv_cmd(&mrioc->bsg_cmds, MPI3MR_HOSTTAG_BSG_CMDS); > > for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) > mpi3mr_init_drv_cmd(&mrioc->dev_rmhs_cmds[i], > @@ -4271,6 +4273,7 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id) > mrioc->logging_level = logging_level; > mrioc->shost = shost; > mrioc->pdev = pdev; > + mrioc->stop_bsgs = 1; > > /* init shost parameters */ > shost->max_cmd_len = MPI3MR_MAX_CDB_LENGTH; > diff --git a/include/uapi/scsi/scsi_bsg_mpi3mr.h b/include/uapi/scsi/scsi_bsg_mpi3mr.h > new file mode 100644 > index 000000000000..2319fc48ed78 > --- /dev/null > +++ b/include/uapi/scsi/scsi_bsg_mpi3mr.h > @@ -0,0 +1,433 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > +/* > + * Driver for Broadcom MPI3 Storage Controllers > + * > + * Copyright (C) 2017-2022 Broadcom Inc. > + * (mailto: mpi3mr-linuxdrv.pdl@xxxxxxxxxxxx) > + * > + */ > + > +#ifndef SCSI_BSG_MPI3MR_H_INCLUDED > +#define SCSI_BSG_MPI3MR_H_INCLUDED > + > +/* Definitions for BSG commands */ > +#define MPI3MR_IOCTL_VERSION 0x06 > + > +#define MPI3MR_APP_DEFAULT_TIMEOUT (60) /*seconds*/ > + > +#define MPI3MR_BSG_ADPTYPE_UNKNOWN 0 > +#define MPI3MR_BSG_ADPTYPE_AVGFAMILY 1 > + > +#define MPI3MR_BSG_ADPSTATE_UNKNOWN 0 > +#define MPI3MR_BSG_ADPSTATE_OPERATIONAL 1 > +#define MPI3MR_BSG_ADPSTATE_FAULT 2 > +#define MPI3MR_BSG_ADPSTATE_IN_RESET 3 > +#define MPI3MR_BSG_ADPSTATE_UNRECOVERABLE 4 > + > +#define MPI3MR_BSG_ADPRESET_UNKNOWN 0 > +#define MPI3MR_BSG_ADPRESET_SOFT 1 > +#define MPI3MR_BSG_ADPRESET_DIAG_FAULT 2 > + > +#define MPI3MR_BSG_LOGDATA_MAX_ENTRIES 400 > +#define MPI3MR_BSG_LOGDATA_ENTRY_HEADER_SZ 4 > + > +#define MPI3MR_DRVBSG_OPCODE_UNKNOWN 0 > +#define MPI3MR_DRVBSG_OPCODE_ADPINFO 1 > +#define MPI3MR_DRVBSG_OPCODE_ADPRESET 2 > +#define MPI3MR_DRVBSG_OPCODE_ALLTGTDEVINFO 4 > +#define MPI3MR_DRVBSG_OPCODE_GETCHGCNT 5 > +#define MPI3MR_DRVBSG_OPCODE_LOGDATAENABLE 6 > +#define MPI3MR_DRVBSG_OPCODE_PELENABLE 7 > +#define MPI3MR_DRVBSG_OPCODE_GETLOGDATA 8 > +#define MPI3MR_DRVBSG_OPCODE_QUERY_HDB 9 > +#define MPI3MR_DRVBSG_OPCODE_REPOST_HDB 10 > +#define MPI3MR_DRVBSG_OPCODE_UPLOAD_HDB 11 > +#define MPI3MR_DRVBSG_OPCODE_REFRESH_HDB_TRIGGERS 12 > + > + > +#define MPI3MR_BSG_BUFTYPE_UNKNOWN 0 > +#define MPI3MR_BSG_BUFTYPE_RAIDMGMT_CMD 1 > +#define MPI3MR_BSG_BUFTYPE_RAIDMGMT_RESP 2 > +#define MPI3MR_BSG_BUFTYPE_DATA_IN 3 > +#define MPI3MR_BSG_BUFTYPE_DATA_OUT 4 > +#define MPI3MR_BSG_BUFTYPE_MPI_REPLY 5 > +#define MPI3MR_BSG_BUFTYPE_ERR_RESPONSE 6 > +#define MPI3MR_BSG_BUFTYPE_MPI_REQUEST 0xFE > + > +#define MPI3MR_BSG_MPI_REPLY_BUFTYPE_UNKNOWN 0 > +#define MPI3MR_BSG_MPI_REPLY_BUFTYPE_STATUS 1 > +#define MPI3MR_BSG_MPI_REPLY_BUFTYPE_ADDRESS 2 > + > +#define MPI3MR_HDB_BUFTYPE_UNKNOWN 0 > +#define MPI3MR_HDB_BUFTYPE_TRACE 1 > +#define MPI3MR_HDB_BUFTYPE_FIRMWARE 2 > +#define MPI3MR_HDB_BUFTYPE_RESERVED 3 > + > +#define MPI3MR_HDB_BUFSTATUS_UNKNOWN 0 > +#define MPI3MR_HDB_BUFSTATUS_NOT_ALLOCATED 1 > +#define MPI3MR_HDB_BUFSTATUS_POSTED_UNPAUSED 2 > +#define MPI3MR_HDB_BUFSTATUS_POSTED_PAUSED 3 > +#define MPI3MR_HDB_BUFSTATUS_RELEASED 4 > + > +#define MPI3MR_HDB_TRIGGER_TYPE_UNKNOWN 0 > +#define MPI3MR_HDB_TRIGGER_TYPE_DIAGFAULT 1 > +#define MPI3MR_HDB_TRIGGER_TYPE_ELEMENT 2 > +#define MPI3MR_HDB_TRIGGER_TYPE_MASTER 3 > + > + > +/* Supported BSG commands */ > +enum command { > + MPI3MR_DRV_CMD = 1, > + MPI3MR_MPT_CMD = 2, > +}; > + > +/** > + * struct mpi3mr_bsg_in_adpinfo - Adapter information request > + * data returned by the driver. > + * > + * @adp_type: Adapter type > + * @rsvd1: Reserved > + * @pci_dev_id: PCI device ID of the adapter > + * @pci_dev_hw_rev: PCI revision of the adapter > + * @pci_subsys_dev_id: PCI subsystem device ID of the adapter > + * @pci_subsys_ven_id: PCI subsystem vendor ID of the adapter > + * @pci_dev: PCI device > + * @pci_func: PCI function > + * @pci_bus: PCI bus > + * @rsvd2: Reserved > + * @pci_seg_id: PCI segment ID > + * @app_intfc_ver: version of the application interface definition > + * @rsvd3: Reserved > + * @rsvd4: Reserved > + * @rsvd5: Reserved > + * @driver_info: Driver Information (Version/Name) > + */ > +struct mpi3mr_bsg_in_adpinfo { > + uint32_t adp_type; > + uint32_t rsvd1; > + uint32_t pci_dev_id; > + uint32_t pci_dev_hw_rev; > + uint32_t pci_subsys_dev_id; > + uint32_t pci_subsys_ven_id; > + uint32_t pci_dev:5; > + uint32_t pci_func:3; > + uint32_t pci_bus:8; > + uint16_t rsvd2; > + uint32_t pci_seg_id; > + uint32_t app_intfc_ver; > + uint8_t adp_state; > + uint8_t rsvd3; > + uint16_t rsvd4; > + uint32_t rsvd5[2]; > + struct mpi3_driver_info_layout driver_info; > +}; > + > +/** > + * struct mpi3mr_bsg_adp_reset - Adapter reset request > + * payload data to the driver. > + * > + * @reset_type: Reset type > + * @rsvd1: Reserved > + * @rsvd2: Reserved > + */ > +struct mpi3mr_bsg_adp_reset { > + uint8_t reset_type; > + uint8_t rsvd1; > + uint16_t rsvd2; > +}; > + > +/** > + * struct mpi3mr_change_count - Topology change count > + * returned by the driver. > + * > + * @change_count: Topology change count > + * @rsvd: Reserved > + */ > +struct mpi3mr_change_count { > + uint16_t change_count; > + uint16_t rsvd; > +}; > + > +/** > + * struct mpi3mr_device_map_info - Target device mapping > + * information > + * > + * @handle: Firmware device handle > + * @perst_id: Persistent ID assigned by the firmware > + * @target_id: Target ID assigned by the driver > + * @bus_id: Bus ID assigned by the driver > + * @rsvd1: Reserved > + * @rsvd2: Reserved > + */ > +struct mpi3mr_device_map_info { > + uint16_t handle; > + uint16_t perst_id; > + uint32_t target_id; > + uint8_t bus_id; > + uint8_t rsvd1; > + uint16_t rsvd2; > +}; > + > +/** > + * struct mpi3mr_all_tgt_info - Target device mapping > + * information returned by the driver > + * > + * @num_devices: The number of devices in driver's inventory > + * @rsvd1: Reserved > + * @rsvd2: Reserved > + * @dmi: Variable length array of mapping information of targets > + */ > +struct mpi3mr_all_tgt_info { > + uint16_t num_devices; > + uint16_t rsvd1; > + uint32_t rsvd2; > + struct mpi3mr_device_map_info dmi[1]; > +}; > + > +/** > + * struct mpi3mr_logdata_enable - Number of log data > + * entries saved by the driver returned as payload data for > + * enable logdata BSG request by the driver. > + * > + * @max_entries: Number of log data entries cached by the driver > + * @rsvd: Reserved > + */ > +struct mpi3mr_logdata_enable { > + uint16_t max_entries; > + uint16_t rsvd; > +}; > + > +/** > + * struct mpi3mr_bsg_out_pel_enable - PEL enable request payload > + * data to the driver. > + * > + * @pel_locale: PEL locale to the firmware > + * @pel_class: PEL class to the firmware > + * @rsvd: Reserved > + */ > +struct mpi3mr_bsg_out_pel_enable { > + uint16_t pel_locale; > + uint8_t pel_class; > + uint8_t rsvd; > +}; > + > +/** > + * struct mpi3mr_logdata_entry - Log data entry cached by the > + * driver. > + * > + * @valid_entry: Is the entry valid > + * @rsvd1: Reserved > + * @rsvd2: Reserved > + * @data: Variable length Log entry data > + */ > +struct mpi3mr_logdata_entry { > + uint8_t valid_entry; > + uint8_t rsvd1; > + uint16_t rsvd2; > + uint8_t data[1]; /* Variable length Array */ > +}; > + > +/** > + * struct mpi3mr_bsg_in_log_data - Log data entries saved by > + * the driver returned as payload data for Get logdata request > + * by the driver. > + * > + * @entry: Variable length Log data entry array > + */ > +struct mpi3mr_bsg_in_log_data { > + struct mpi3mr_logdata_entry entry[1]; > +}; > + > +/** > + * struct mpi3mr_hdb_entry - host diag buffer entry. > + * > + * @buf_type: Buffer type > + * @status: Buffer status > + * @trigger_type: Trigger type > + * @rsvd1: Reserved > + * @size: Buffer size > + * @rsvd2: Reserved > + * @trigger_data: Trigger specific data > + * @rsvd3: Reserved > + * @rsvd4: Reserved > + */ > +struct mpi3mr_hdb_entry { > + uint8_t buf_type; > + uint8_t status; > + uint8_t trigger_type; > + uint8_t rsvd1; > + uint16_t size; > + uint16_t rsvd2; > + uint64_t trigger_data; > + uint32_t rsvd3; > + uint32_t rsvd4; > +}; > + > + > +/** > + * struct mpi3mr_bsg_in_hdb_status - This structure contains > + * return data for the BSG request to retrieve the number of host > + * diagnostic buffers supported by the driver and their current > + * status and additional status specific data if any in forms of > + * multiple hdb entries. > + * > + * @num_hdb_types: Number of host diag buffer types supported > + * @rsvd1: Reserved > + * @rsvd2: Reserved > + * @rsvd3: Reserved > + * @entry: Variable length Diag buffer status entry array > + */ > +struct mpi3mr_bsg_in_hdb_status { > + uint8_t num_hdb_types; > + uint8_t rsvd1; > + uint16_t rsvd2; > + uint32_t rsvd3; > + struct mpi3mr_hdb_entry entry[1]; > +}; > + > +/** > + * struct mpi3mr_bsg_out_repost_hdb - Repost host diagnostic > + * buffer request payload data to the driver. > + * > + * @buf_type: Buffer type > + * @rsvd1: Reserved > + * @rsvd2: Reserved > + */ > +struct mpi3mr_bsg_out_repost_hdb { > + uint8_t buf_type; > + uint8_t rsvd1; > + uint16_t rsvd2; > +}; > + > +/** > + * struct mpi3mr_bsg_out_upload_hdb - Upload host diagnostic > + * buffer request payload data to the driver. > + * > + * @buf_type: Buffer type > + * @rsvd1: Reserved > + * @rsvd2: Reserved > + * @start_offset: Start offset of the buffer from where to copy > + * @length: Length of the buffer to copy > + */ > +struct mpi3mr_bsg_out_upload_hdb { > + uint8_t buf_type; > + uint8_t rsvd1; > + uint16_t rsvd2; > + uint32_t start_offset; > + uint32_t length; > +}; > + > +/** > + * struct mpi3mr_bsg_out_refresh_hdb_triggers - Refresh host > + * diagnostic buffer triggers request payload data to the driver. > + * > + * @page_type: Page type > + * @rsvd1: Reserved > + * @rsvd2: Reserved > + */ > +struct mpi3mr_bsg_out_refresh_hdb_triggers { > + uint8_t page_type; > + uint8_t rsvd1; > + uint16_t rsvd2; > +}; > +/** > + * struct mpi3mr_bsg_drv_cmd - Generic bsg data > + * structure for all driver specific requests. > + * > + * @mrioc_id: Controller ID > + * @opcode: Driver specific opcode > + * @rsvd1: Reserved > + * @rsvd2: Reserved > + */ > +struct mpi3mr_bsg_drv_cmd { > + uint8_t mrioc_id; > + uint8_t opcode; > + uint16_t rsvd1; > + uint32_t rsvd2[4]; > +}; > +/** > + * struct mpi3mr_bsg_in_reply_buf - MPI reply buffer returned > + * for MPI Passthrough request . > + * > + * @mpi_reply_type: Type of MPI reply > + * @rsvd1: Reserved > + * @rsvd2: Reserved > + * @reply_buf: Variable Length buffer based on mpirep type > + */ > +struct mpi3mr_bsg_in_reply_buf { > + uint8_t mpi_reply_type; > + uint8_t rsvd1; > + uint16_t rsvd2; > + uint8_t reply_buf[1]; > +}; > + > +/** > + * struct mpi3mr_buf_entry - User buffer descriptor for MPI > + * Passthrough requests. > + * > + * @buf_type: Buffer type > + * @rsvd1: Reserved > + * @rsvd2: Reserved > + * @buf_len: Buffer length > + */ > +struct mpi3mr_buf_entry { > + uint8_t buf_type; > + uint8_t rsvd1; > + uint16_t rsvd2; > + uint32_t buf_len; > +}; > +/** > + * struct mpi3mr_bsg_buf_entry_list - list of user buffer > + * descriptor for MPI Passthrough requests. > + * > + * @num_of_entries: Number of buffer descriptors > + * @rsvd1: Reserved > + * @rsvd2: Reserved > + * @rsvd3: Reserved > + * @buf_entry: Variable length array of buffer descriptors > + */ > +struct mpi3mr_buf_entry_list { > + uint8_t num_of_entries; > + uint8_t rsvd1; > + uint16_t rsvd2; > + uint32_t rsvd3; > + struct mpi3mr_buf_entry buf_entry[1]; > +}; > +/** > + * struct mpi3mr_bsg_mptcmd - Generic bsg data > + * structure for all MPI Passthrough requests . > + * > + * @mrioc_id: Controller ID > + * @rsvd1: Reserved > + * @timeout: MPI request timeout > + * @buf_entry_list: Buffer descriptor list > + */ > +struct mpi3mr_bsg_mptcmd { > + uint8_t mrioc_id; > + uint8_t rsvd1; > + uint16_t timeout; > + uint32_t rsvd2; > + struct mpi3mr_buf_entry_list buf_entry_list; > +}; > + > +/** > + * struct mpi3mr_bsg_packet - Generic bsg data > + * structure for all supported requests . > + * > + * @cmd_type: represents drvrcmd or mptcmd > + * @rsvd1: Reserved > + * @rsvd2: Reserved > + * @drvrcmd: driver request structure > + * @mptcmd: mpt request structure > + */ > +struct mpi3mr_bsg_packet { > + uint8_t cmd_type; > + uint8_t rsvd1; > + uint16_t rsvd2; > + uint32_t rsvd3; > + union { > + struct mpi3mr_bsg_drv_cmd drvrcmd; > + struct mpi3mr_bsg_mptcmd mptcmd; > + } cmd; > +}; > +#endif > -- > 2.27.0 > Once you fix small nit, you can add Reviewed-by: Himanshu Madhani <himanshu.madhani@xxxxxxxxxx> -- Himanshu Madhani Oracle Linux Engineering