Commit 13ef29ea authored by Kashyap Desai's avatar Kashyap Desai Committed by Martin K. Petersen
Browse files

scsi: mpi3mr: Add support for device add/remove event handling

Firmware can report various MPI Events. Enable support for processing the
following events related to device addition/removal to the driver:

 - MPI3_EVENT_DEVICE_ADDED
 - MPI3_EVENT_DEVICE_INFO_CHANGED
 - MPI3_EVENT_DEVICE_STATUS_CHANGE
 - MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE
 - MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST
 - MPI3_EVENT_SAS_DISCOVERY
 - MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR

Link: https://lore.kernel.org/r/20210520152545.2710479-7-kashyap.desai@broadcom.com


Cc: sathya.prakash@broadcom.com
Reported-by: default avatarkernel test robot <lkp@intel.com>
Reviewed-by: default avatarTomas Henzl <thenzl@redhat.com>
Reviewed-by: default avatarHimanshu Madhani <himanshu.madhani@oracle.com>
Reviewed-by: default avatarHannes Reinecke <hare@suse.de>
Signed-off-by: default avatarKashyap Desai <kashyap.desai@broadcom.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 672ae26c
Loading
Loading
Loading
Loading
+1880 −0

File added.

Preview size limit exceeded, changes collapsed.

+33 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 *  Copyright 2016-2021 Broadcom Inc. All rights reserved.
 *
 */
#ifndef MPI30_SAS_H
#define MPI30_SAS_H     1
#define MPI3_SAS_DEVICE_INFO_SSP_TARGET             (0x00000100)
#define MPI3_SAS_DEVICE_INFO_STP_SATA_TARGET        (0x00000080)
#define MPI3_SAS_DEVICE_INFO_SMP_TARGET             (0x00000040)
#define MPI3_SAS_DEVICE_INFO_SSP_INITIATOR          (0x00000020)
#define MPI3_SAS_DEVICE_INFO_STP_INITIATOR          (0x00000010)
#define MPI3_SAS_DEVICE_INFO_SMP_INITIATOR          (0x00000008)
#define MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK       (0x00000007)
#define MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_NO_DEVICE  (0x00000000)
#define MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_END_DEVICE (0x00000001)
#define MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_EXPANDER   (0x00000002)
struct mpi3_smp_passthrough_request {
	__le16                     host_tag;
	u8                         ioc_use_only02;
	u8                         function;
	__le16                     ioc_use_only04;
	u8                         ioc_use_only06;
	u8                         msg_flags;
	__le16                     change_count;
	u8                         reserved0a;
	u8                         io_unit_port;
	__le32                     reserved0c[3];
	__le64                     sas_address;
	struct mpi3_sge_common         request_sge;
	struct mpi3_sge_common         response_sge;
};
#endif
+204 −0
Original line number Diff line number Diff line
@@ -40,9 +40,11 @@
#include <scsi/scsi_tcq.h>

#include "mpi/mpi30_transport.h"
#include "mpi/mpi30_cnfg.h"
#include "mpi/mpi30_image.h"
#include "mpi/mpi30_init.h"
#include "mpi/mpi30_ioc.h"
#include "mpi/mpi30_sas.h"
#include "mpi3mr_debug.h"

/* Global list and lock for storing multiple adapters managed by the driver */
@@ -137,6 +139,10 @@ extern struct list_head mrioc_list;
#define MPI3MR_RSP_IO_QUEUED_ON_IOC \
			MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC

#define MPI3MR_DEFAULT_MDTS	(128 * 1024)
/* Command retry count definitions */
#define MPI3MR_DEV_RMHS_RETRY_COUNT 3

/* SGE Flag definition */
#define MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST \
	(MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE | MPI3_SGE_FLAGS_DLAS_SYSTEM | \
@@ -316,6 +322,126 @@ struct mpi3mr_intr_info {
	char name[MPI3MR_NAME_LENGTH];
};

/**
 * struct tgt_dev_sas_sata - SAS/SATA device specific
 * information cached from firmware given data
 *
 * @sas_address: World wide unique SAS address
 * @dev_info: Device information bits
 */
struct tgt_dev_sas_sata {
	u64 sas_address;
	u16 dev_info;
};

/**
 * struct tgt_dev_pcie - PCIe device specific information cached
 * from firmware given data
 *
 * @mdts: Maximum data transfer size
 * @capb: Device capabilities
 * @pgsz: Device page size
 * @abort_to: Timeout for abort TM
 * @reset_to: Timeout for Target/LUN reset TM
 */
struct tgt_dev_pcie {
	u32 mdts;
	u16 capb;
	u8 pgsz;
	u8 abort_to;
	u8 reset_to;
};

/**
 * struct tgt_dev_volume - virtual device specific information
 * cached from firmware given data
 *
 * @state: State of the VD
 */
struct tgt_dev_volume {
	u8 state;
};

/**
 * union _form_spec_inf - union of device specific information
 */
union _form_spec_inf {
	struct tgt_dev_sas_sata sas_sata_inf;
	struct tgt_dev_pcie pcie_inf;
	struct tgt_dev_volume vol_inf;
};



/**
 * struct mpi3mr_tgt_dev - target device data structure
 *
 * @list: List pointer
 * @starget: Scsi_target pointer
 * @dev_handle: FW device handle
 * @parent_handle: FW parent device handle
 * @slot: Slot number
 * @encl_handle: FW enclosure handle
 * @perst_id: FW assigned Persistent ID
 * @dev_type: SAS/SATA/PCIE device type
 * @is_hidden: Should be exposed to upper layers or not
 * @host_exposed: Already exposed to host or not
 * @q_depth: Device specific Queue Depth
 * @wwid: World wide ID
 * @dev_spec: Device type specific information
 * @ref_count: Reference count
 */
struct mpi3mr_tgt_dev {
	struct list_head list;
	struct scsi_target *starget;
	u16 dev_handle;
	u16 parent_handle;
	u16 slot;
	u16 encl_handle;
	u16 perst_id;
	u8 dev_type;
	u8 is_hidden;
	u8 host_exposed;
	u16 q_depth;
	u64 wwid;
	union _form_spec_inf dev_spec;
	struct kref ref_count;
};

/**
 * mpi3mr_tgtdev_get - k reference incrementor
 * @s: Target device reference
 *
 * Increment target device reference count.
 */
static inline void mpi3mr_tgtdev_get(struct mpi3mr_tgt_dev *s)
{
	kref_get(&s->ref_count);
}

/**
 * mpi3mr_free_tgtdev - target device memory dealloctor
 * @r: k reference pointer of the target device
 *
 * Free target device memory when no reference.
 */
static inline void mpi3mr_free_tgtdev(struct kref *r)
{
	kfree(container_of(r, struct mpi3mr_tgt_dev, ref_count));
}

/**
 * mpi3mr_tgtdev_put - k reference decrementor
 * @s: Target device reference
 *
 * Decrement target device reference count.
 */
static inline void mpi3mr_tgtdev_put(struct mpi3mr_tgt_dev *s)
{
	kref_put(&s->ref_count, mpi3mr_free_tgtdev);
}


/**
 * struct mpi3mr_stgt_priv_data - SCSI target private structure
 *
@@ -361,6 +487,7 @@ struct mpi3mr_sdev_priv_data {
 * @done: Completeor for wakeup
 * @reply: Firmware reply for internal commands
 * @sensebuf: Sensebuf for SCSI IO commands
 * @iou_rc: IO Unit control reason code
 * @state: Command State
 * @dev_handle: Firmware handle for device specific commands
 * @ioc_status: IOC status from the firmware
@@ -375,6 +502,7 @@ struct mpi3mr_drv_cmd {
	struct completion done;
	void *reply;
	u8 *sensebuf;
	u8 iou_rc;
	u16 state;
	u16 dev_handle;
	u16 ioc_status;
@@ -481,6 +609,11 @@ struct scmd_priv {
 * @sense_buf_q_dma: Sense buffer queue DMA address
 * @sbq_lock: Sense buffer queue lock
 * @sbq_host_index: Sense buffer queuehost index
 * @event_masks: Event mask bitmap
 * @fwevt_worker_name: Firmware event worker thread name
 * @fwevt_worker_thread: Firmware event worker thread
 * @fwevt_lock: Firmware event lock
 * @fwevt_list: Firmware event list
 * @watchdog_work_q_name: Fault watchdog worker thread name
 * @watchdog_work_q: Fault watchdog worker thread
 * @watchdog_work: Fault watchdog work
@@ -496,6 +629,12 @@ struct scmd_priv {
 * @chain_bitmap_sz: Chain buffer allocator bitmap size
 * @chain_bitmap: Chain buffer allocator bitmap
 * @chain_buf_lock: Chain buffer list lock
 * @dev_rmhs_cmds: Command tracker for device removal commands
 * @devrem_bitmap_sz: Device removal bitmap size
 * @devrem_bitmap: Device removal bitmap
 * @dev_handle_bitmap_sz: Device handle bitmap size
 * @removepend_bitmap: Remove pending bitmap
 * @delayed_rmhs_list: Delayed device removal list
 * @reset_in_progress: Reset in progress flag
 * @unrecoverable: Controller unrecoverable flag
 * @diagsave_timeout: Diagnostic information save timeout
@@ -579,6 +718,12 @@ struct mpi3mr_ioc {
	dma_addr_t sense_buf_q_dma;
	spinlock_t sbq_lock;
	u32 sbq_host_index;
	u32 event_masks[MPI3_EVENT_NOTIFY_EVENTMASK_WORDS];

	char fwevt_worker_name[MPI3MR_NAME_LENGTH];
	struct workqueue_struct	*fwevt_worker_thread;
	spinlock_t fwevt_lock;
	struct list_head fwevt_list;

	char watchdog_work_q_name[20];
	struct workqueue_struct *watchdog_work_q;
@@ -591,6 +736,8 @@ struct mpi3mr_ioc {
	u8 stop_drv_processing;

	u16 max_host_ios;
	spinlock_t tgtdev_lock;
	struct list_head tgtdev_list;

	u32 chain_buf_count;
	struct dma_pool *chain_buf_pool;
@@ -599,6 +746,13 @@ struct mpi3mr_ioc {
	void *chain_bitmap;
	spinlock_t chain_buf_lock;

	struct mpi3mr_drv_cmd dev_rmhs_cmds[MPI3MR_NUM_DEVRMCMD];
	u16 devrem_bitmap_sz;
	void *devrem_bitmap;
	u16 dev_handle_bitmap_sz;
	void *removepend_bitmap;
	struct list_head delayed_rmhs_list;

	u8 reset_in_progress;
	u8 unrecoverable;

@@ -611,6 +765,45 @@ struct mpi3mr_ioc {
	u16 op_reply_q_offset;
};

/**
 * struct mpi3mr_fwevt - Firmware event structure.
 *
 * @list: list head
 * @work: Work structure
 * @mrioc: Adapter instance reference
 * @event_id: MPI3 firmware event ID
 * @send_ack: Event acknowledgment required or not
 * @process_evt: Bottomhalf processing required or not
 * @evt_ctx: Event context to send in Ack
 * @ref_count: kref count
 * @event_data: Actual MPI3 event data
 */
struct mpi3mr_fwevt {
	struct list_head list;
	struct work_struct work;
	struct mpi3mr_ioc *mrioc;
	u16 event_id;
	bool send_ack;
	bool process_evt;
	u32 evt_ctx;
	struct kref ref_count;
	char event_data[0] __aligned(4);
};


/**
 * struct delayed_dev_rmhs_node - Delayed device removal node
 *
 * @list: list head
 * @handle: Device handle
 * @iou_rc: IO Unit Control Reason Code
 */
struct delayed_dev_rmhs_node {
	struct list_head list;
	u16 handle;
	u8 iou_rc;
};

int mpi3mr_setup_resources(struct mpi3mr_ioc *mrioc);
void mpi3mr_cleanup_resources(struct mpi3mr_ioc *mrioc);
int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc);
@@ -630,6 +823,8 @@ void *mpi3mr_get_reply_virt_addr(struct mpi3mr_ioc *mrioc,
void mpi3mr_repost_sense_buf(struct mpi3mr_ioc *mrioc,
				     u64 sense_buf_dma);

void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc,
			     struct mpi3_event_notification_reply *event_reply);
void mpi3mr_process_op_reply_desc(struct mpi3mr_ioc *mrioc,
				  struct mpi3_default_reply_descriptor *reply_desc,
				  u64 *reply_dma, u16 qidx);
@@ -642,5 +837,14 @@ void mpi3mr_ioc_disable_intr(struct mpi3mr_ioc *mrioc);
void mpi3mr_ioc_enable_intr(struct mpi3mr_ioc *mrioc);

enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_ioc *mrioc);
int mpi3mr_send_event_ack(struct mpi3mr_ioc *mrioc, u8 event,
			  u32 event_ctx);

void mpi3mr_wait_for_host_io(struct mpi3mr_ioc *mrioc, u32 timeout);
void mpi3mr_cleanup_fwevt_list(struct mpi3mr_ioc *mrioc);
void mpi3mr_flush_host_io(struct mpi3mr_ioc *mrioc);
void mpi3mr_invalidate_devhandles(struct mpi3mr_ioc *mrioc);
void mpi3mr_rfresh_tgtdevs(struct mpi3mr_ioc *mrioc);
void mpi3mr_flush_delayed_rmhs_list(struct mpi3mr_ioc *mrioc);

#endif /*MPI3MR_H_INCLUDED*/
+196 −1
Original line number Diff line number Diff line
@@ -160,12 +160,15 @@ static void mpi3mr_handle_events(struct mpi3mr_ioc *mrioc,
	    (struct mpi3_event_notification_reply *)def_reply;

	mrioc->change_count = le16_to_cpu(event_reply->ioc_change_count);
	mpi3mr_os_handle_events(mrioc, event_reply);
}

static struct mpi3mr_drv_cmd *
mpi3mr_get_drv_cmd(struct mpi3mr_ioc *mrioc, u16 host_tag,
	struct mpi3_default_reply *def_reply)
{
	u16 idx;

	switch (host_tag) {
	case MPI3MR_HOSTTAG_INITCMDS:
		return &mrioc->init_cmds;
@@ -177,6 +180,11 @@ mpi3mr_get_drv_cmd(struct mpi3mr_ioc *mrioc, u16 host_tag,
	default:
		break;
	}
	if (host_tag >= MPI3MR_HOSTTAG_DEVRMCMD_MIN &&
	    host_tag <= MPI3MR_HOSTTAG_DEVRMCMD_MAX) {
		idx = host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN;
		return &mrioc->dev_rmhs_cmds[idx];
	}

	return NULL;
}
@@ -1910,6 +1918,13 @@ static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc)
	if (!mrioc->init_cmds.reply)
		goto out_failed;

	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
		mrioc->dev_rmhs_cmds[i].reply = kzalloc(mrioc->facts.reply_sz,
		    GFP_KERNEL);
		if (!mrioc->dev_rmhs_cmds[i].reply)
			goto out_failed;
	}

	mrioc->num_reply_bufs = mrioc->facts.max_reqs + MPI3MR_NUM_EVT_REPLIES;
	mrioc->reply_free_qsz = mrioc->num_reply_bufs + 1;
	mrioc->num_sense_bufs = mrioc->facts.max_reqs / MPI3MR_SENSEBUF_FACTOR;
@@ -2119,6 +2134,163 @@ static int mpi3mr_issue_iocinit(struct mpi3mr_ioc *mrioc)
	return retval;
}

/**
 * mpi3mr_unmask_events - Unmask events in event mask bitmap
 * @mrioc: Adapter instance reference
 * @event: MPI event ID
 *
 * Un mask the specific event by resetting the event_mask
 * bitmap.
 *
 * Return: 0 on success, non-zero on failures.
 */
static void mpi3mr_unmask_events(struct mpi3mr_ioc *mrioc, u16 event)
{
	u32 desired_event;
	u8 word;

	if (event >= 128)
		return;

	desired_event = (1 << (event % 32));
	word = event / 32;

	mrioc->event_masks[word] &= ~desired_event;
}

/**
 * mpi3mr_issue_event_notification - Send event notification
 * @mrioc: Adapter instance reference
 *
 * Issue event notification MPI request through admin queue and
 * wait for the completion of it or time out.
 *
 * Return: 0 on success, non-zero on failures.
 */
static int mpi3mr_issue_event_notification(struct mpi3mr_ioc *mrioc)
{
	struct mpi3_event_notification_request evtnotify_req;
	int retval = 0;
	u8 i;

	memset(&evtnotify_req, 0, sizeof(evtnotify_req));
	mutex_lock(&mrioc->init_cmds.mutex);
	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
		retval = -1;
		ioc_err(mrioc, "Issue EvtNotify: Init command is in use\n");
		mutex_unlock(&mrioc->init_cmds.mutex);
		goto out;
	}
	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
	mrioc->init_cmds.is_waiting = 1;
	mrioc->init_cmds.callback = NULL;
	evtnotify_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
	evtnotify_req.function = MPI3_FUNCTION_EVENT_NOTIFICATION;
	for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
		evtnotify_req.event_masks[i] =
		    cpu_to_le32(mrioc->event_masks[i]);
	init_completion(&mrioc->init_cmds.done);
	retval = mpi3mr_admin_request_post(mrioc, &evtnotify_req,
	    sizeof(evtnotify_req), 1);
	if (retval) {
		ioc_err(mrioc, "Issue EvtNotify: Admin Post failed\n");
		goto out_unlock;
	}
	wait_for_completion_timeout(&mrioc->init_cmds.done,
	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
		ioc_err(mrioc, "Issue EvtNotify: command timed out\n");
		mpi3mr_set_diagsave(mrioc);
		mpi3mr_issue_reset(mrioc,
		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
		    MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT);
		mrioc->unrecoverable = 1;
		retval = -1;
		goto out_unlock;
	}
	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
	    != MPI3_IOCSTATUS_SUCCESS) {
		ioc_err(mrioc,
		    "Issue EvtNotify: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
		    mrioc->init_cmds.ioc_loginfo);
		retval = -1;
		goto out_unlock;
	}

out_unlock:
	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
	mutex_unlock(&mrioc->init_cmds.mutex);
out:
	return retval;
}

/**
 * mpi3mr_send_event_ack - Send event acknowledgment
 * @mrioc: Adapter instance reference
 * @event: MPI3 event ID
 * @event_ctx: Event context
 *
 * Send event acknowledgment through admin queue and wait for
 * it to complete.
 *
 * Return: 0 on success, non-zero on failures.
 */
int mpi3mr_send_event_ack(struct mpi3mr_ioc *mrioc, u8 event,
	u32 event_ctx)
{
	struct mpi3_event_ack_request evtack_req;
	int retval = 0;

	memset(&evtack_req, 0, sizeof(evtack_req));
	mutex_lock(&mrioc->init_cmds.mutex);
	if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
		retval = -1;
		ioc_err(mrioc, "Send EvtAck: Init command is in use\n");
		mutex_unlock(&mrioc->init_cmds.mutex);
		goto out;
	}
	mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
	mrioc->init_cmds.is_waiting = 1;
	mrioc->init_cmds.callback = NULL;
	evtack_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
	evtack_req.function = MPI3_FUNCTION_EVENT_ACK;
	evtack_req.event = event;
	evtack_req.event_context = cpu_to_le32(event_ctx);

	init_completion(&mrioc->init_cmds.done);
	retval = mpi3mr_admin_request_post(mrioc, &evtack_req,
	    sizeof(evtack_req), 1);
	if (retval) {
		ioc_err(mrioc, "Send EvtAck: Admin Post failed\n");
		goto out_unlock;
	}
	wait_for_completion_timeout(&mrioc->init_cmds.done,
	    (MPI3MR_INTADMCMD_TIMEOUT * HZ));
	if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
		ioc_err(mrioc, "Issue EvtNotify: command timed out\n");
		mpi3mr_soft_reset_handler(mrioc,
		    MPI3MR_RESET_FROM_EVTACK_TIMEOUT, 1);
		retval = -1;
		goto out_unlock;
	}
	if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
	    != MPI3_IOCSTATUS_SUCCESS) {
		ioc_err(mrioc,
		    "Send EvtAck: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
		    (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
		    mrioc->init_cmds.ioc_loginfo);
		retval = -1;
		goto out_unlock;
	}

out_unlock:
	mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
	mutex_unlock(&mrioc->init_cmds.mutex);
out:
	return retval;
}

/**
 * mpi3mr_alloc_chain_bufs - Allocate chain buffers
 * @mrioc: Adapter instance reference
@@ -2396,7 +2568,7 @@ int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc)
	enum mpi3mr_iocstate ioc_state;
	u64 base_info;
	u32 timeout;
	u32 ioc_status, ioc_config;
	u32 ioc_status, ioc_config, i;
	struct mpi3_ioc_facts_data facts_data;

	mrioc->change_count = 0;
@@ -2546,6 +2718,24 @@ int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc)
		goto out_failed;
	}

	for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
		mrioc->event_masks[i] = -1;

	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_ADDED);
	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_INFO_CHANGED);
	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_STATUS_CHANGE);
	mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE);
	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST);
	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DISCOVERY);
	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR);

	retval = mpi3mr_issue_event_notification(mrioc);
	if (retval) {
		ioc_err(mrioc, "Failed to issue event notification %d\n",
		    retval);
		goto out_failed;
	}

	return retval;

out_failed:
@@ -2627,6 +2817,11 @@ static void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc)
	kfree(mrioc->chain_bitmap);
	mrioc->chain_bitmap = NULL;

	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
		kfree(mrioc->dev_rmhs_cmds[i].reply);
		mrioc->dev_rmhs_cmds[i].reply = NULL;
	}

	if (mrioc->chain_buf_pool) {
		for (i = 0; i < mrioc->chain_buf_count; i++) {
			if (mrioc->chain_sgl_list[i].addr) {
+1455 −2

File changed.

Preview size limit exceeded, changes collapsed.