Commit f5e6d5a3 authored by Sumit Saxena's avatar Sumit Saxena Committed by Martin K. Petersen
Browse files

scsi: mpi3mr: Add support for driver commands

There are certain bsg commands which need to be completed by the driver
without involving firmware. These requests are termed driver commands. Add
support for these.

Link: https://lore.kernel.org/r/20220429211641.642010-3-sumit.saxena@broadcom.com


Reported by: Stephen Rothwell <sfr@canb.auug.org.au>
Reported-by: default avatarkernel test robot <lkp@intel.com>
Reviewed-by: default avatarHimanshu Madhani <himanshu.madhani@oracle.com>
Signed-off-by: default avatarSumit Saxena <sumit.saxena@broadcom.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 4268fa75
Loading
Loading
Loading
Loading
+0 −10
Original line number Diff line number Diff line
@@ -38,16 +38,6 @@ struct mpi3_ioc_init_request {
#define MPI3_WHOINIT_ROM_BIOS                            (0x02)
#define MPI3_WHOINIT_HOST_DRIVER                         (0x03)
#define MPI3_WHOINIT_MANUFACTURER                        (0x04)
struct mpi3_driver_info_layout {
	__le32             information_length;
	u8                 driver_signature[12];
	u8                 os_name[16];
	u8                 os_version[12];
	u8                 driver_name[20];
	u8                 driver_version[32];
	u8                 driver_release_date[20];
	__le32             driver_capabilities;
};

struct mpi3_ioc_facts_request {
	__le16                 host_tag;
+13 −3
Original line number Diff line number Diff line
@@ -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;
};

/**
+390 −0
Original line number Diff line number Diff line
@@ -9,6 +9,379 @@

#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)
{
	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));
		return 0;
	}

	return -EINVAL;
}
/**
 * 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)
{
	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));
		return 0;
	}
	return -EINVAL;
}

/**
 * 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 +393,23 @@
 */
static 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;
}

+6 −6
Original line number Diff line number Diff line
@@ -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)

+18 −3
Original line number Diff line number Diff line
@@ -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);
Loading