diff options
Diffstat (limited to 'drivers/scsi/mpi3mr/mpi3mr_os.c')
| -rw-r--r-- | drivers/scsi/mpi3mr/mpi3mr_os.c | 771 | 
1 files changed, 642 insertions, 129 deletions
| diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index fe10f257b5a4..284117da9086 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -34,6 +34,9 @@ MODULE_PARM_DESC(logging_level,  	" bits for enabling additional logging info (default=0)");  /* Forward declarations*/ +static void mpi3mr_send_event_ack(struct mpi3mr_ioc *mrioc, u8 event, +	struct mpi3mr_drv_cmd *cmdparam, u32 event_ctx); +  /**   * mpi3mr_host_tag_for_scmd - Get host tag for a scmd   * @mrioc: Adapter instance reference @@ -418,6 +421,74 @@ out:  }  /** + * mpi3mr_count_dev_pending - Count commands pending for a lun + * @rq: Block request + * @data: SCSI device reference + * @reserved: Unused + * + * This is an iterator function called for each SCSI command in + * a host and if the command is pending in the LLD for the + * specific device(lun) then device specific pending I/O counter + * is updated in the device structure. + * + * Return: true always. + */ + +static bool mpi3mr_count_dev_pending(struct request *rq, +	void *data, bool reserved) +{ +	struct scsi_device *sdev = (struct scsi_device *)data; +	struct mpi3mr_sdev_priv_data *sdev_priv_data = sdev->hostdata; +	struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq); +	struct scmd_priv *priv; + +	if (scmd) { +		priv = scsi_cmd_priv(scmd); +		if (!priv->in_lld_scope) +			goto out; +		if (scmd->device == sdev) +			sdev_priv_data->pend_count++; +	} + +out: +	return true; +} + +/** + * mpi3mr_count_tgt_pending - Count commands pending for target + * @rq: Block request + * @data: SCSI target reference + * @reserved: Unused + * + * This is an iterator function called for each SCSI command in + * a host and if the command is pending in the LLD for the + * specific target then target specific pending I/O counter is + * updated in the target structure. + * + * Return: true always. + */ + +static bool mpi3mr_count_tgt_pending(struct request *rq, +	void *data, bool reserved) +{ +	struct scsi_target *starget = (struct scsi_target *)data; +	struct mpi3mr_stgt_priv_data *stgt_priv_data = starget->hostdata; +	struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq); +	struct scmd_priv *priv; + +	if (scmd) { +		priv = scsi_cmd_priv(scmd); +		if (!priv->in_lld_scope) +			goto out; +		if (scmd->device && (scsi_target(scmd->device) == starget)) +			stgt_priv_data->pend_count++; +	} + +out: +	return true; +} + +/**   * mpi3mr_flush_host_io -  Flush host I/Os   * @mrioc: Adapter instance reference   * @@ -742,11 +813,18 @@ mpi3mr_update_sdev(struct scsi_device *sdev, void *data)  	switch (tgtdev->dev_type) {  	case MPI3_DEVICE_DEVFORM_PCIE:  		/*The block layer hw sector size = 512*/ -		blk_queue_max_hw_sectors(sdev->request_queue, -		    tgtdev->dev_spec.pcie_inf.mdts / 512); -		blk_queue_virt_boundary(sdev->request_queue, -		    ((1 << tgtdev->dev_spec.pcie_inf.pgsz) - 1)); - +		if ((tgtdev->dev_spec.pcie_inf.dev_info & +		    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) == +		    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) { +			blk_queue_max_hw_sectors(sdev->request_queue, +			    tgtdev->dev_spec.pcie_inf.mdts / 512); +			if (tgtdev->dev_spec.pcie_inf.pgsz == 0) +				blk_queue_virt_boundary(sdev->request_queue, +				    ((1 << MPI3MR_DEFAULT_PGSZEXP) - 1)); +			else +				blk_queue_virt_boundary(sdev->request_queue, +				    ((1 << tgtdev->dev_spec.pcie_inf.pgsz) - 1)); +		}  		break;  	default:  		break; @@ -824,6 +902,17 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,  		scsi_tgt_priv_data->dev_type = tgtdev->dev_type;  	} +	switch (dev_pg0->access_status) { +	case MPI3_DEVICE0_ASTATUS_NO_ERRORS: +	case MPI3_DEVICE0_ASTATUS_PREPARE: +	case MPI3_DEVICE0_ASTATUS_NEEDS_INITIALIZATION: +	case MPI3_DEVICE0_ASTATUS_DEVICE_MISSING_DELAY: +		break; +	default: +		tgtdev->is_hidden = 1; +		break; +	} +  	switch (tgtdev->dev_type) {  	case MPI3_DEVICE_DEVFORM_SAS_SATA:  	{ @@ -848,6 +937,7 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,  		    &dev_pg0->device_specific.pcie_format;  		u16 dev_info = le16_to_cpu(pcieinf->device_info); +		tgtdev->dev_spec.pcie_inf.dev_info = dev_info;  		tgtdev->dev_spec.pcie_inf.capb =  		    le32_to_cpu(pcieinf->capabilities);  		tgtdev->dev_spec.pcie_inf.mdts = MPI3MR_DEFAULT_MDTS; @@ -858,14 +948,18 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,  			    le32_to_cpu(pcieinf->maximum_data_transfer_size);  			tgtdev->dev_spec.pcie_inf.pgsz = pcieinf->page_size;  			tgtdev->dev_spec.pcie_inf.reset_to = -			    pcieinf->controller_reset_to; +			    max_t(u8, pcieinf->controller_reset_to, +			     MPI3MR_INTADMCMD_TIMEOUT);  			tgtdev->dev_spec.pcie_inf.abort_to = -			    pcieinf->nv_me_abort_to; +			    max_t(u8, pcieinf->nvme_abort_to, +			    MPI3MR_INTADMCMD_TIMEOUT);  		}  		if (tgtdev->dev_spec.pcie_inf.mdts > (1024 * 1024))  			tgtdev->dev_spec.pcie_inf.mdts = (1024 * 1024); -		if ((dev_info & MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) != -		    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) +		if (((dev_info & MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) != +		    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) && +		    ((dev_info & MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) != +		    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_SCSI_DEVICE))  			tgtdev->is_hidden = 1;  		if (!mrioc->shost)  			break; @@ -1313,7 +1407,7 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,  evt_ack:  	if (fwevt->send_ack) -		mpi3mr_send_event_ack(mrioc, fwevt->event_id, +		mpi3mr_process_event_ack(mrioc, fwevt->event_id,  		    fwevt->evt_ctx);  out:  	/* Put fwevt reference count to neutralize kref_init increment */ @@ -1377,24 +1471,33 @@ static int mpi3mr_create_tgtdev(struct mpi3mr_ioc *mrioc,  }  /** - * mpi3mr_flush_delayed_rmhs_list - Flush pending commands + * mpi3mr_flush_delayed_cmd_lists - Flush pending commands   * @mrioc: Adapter instance reference   * - * Flush pending commands in the delayed removal handshake list - * due to a controller reset or driver removal as a cleanup. + * Flush pending commands in the delayed lists due to a + * controller reset or driver removal as a cleanup.   *   * Return: Nothing   */ -void mpi3mr_flush_delayed_rmhs_list(struct mpi3mr_ioc *mrioc) +void mpi3mr_flush_delayed_cmd_lists(struct mpi3mr_ioc *mrioc)  {  	struct delayed_dev_rmhs_node *_rmhs_node; +	struct delayed_evt_ack_node *_evtack_node; +	dprint_reset(mrioc, "flushing delayed dev_remove_hs commands\n");  	while (!list_empty(&mrioc->delayed_rmhs_list)) {  		_rmhs_node = list_entry(mrioc->delayed_rmhs_list.next,  		    struct delayed_dev_rmhs_node, list);  		list_del(&_rmhs_node->list);  		kfree(_rmhs_node);  	} +	dprint_reset(mrioc, "flushing delayed event ack commands\n"); +	while (!list_empty(&mrioc->delayed_evtack_cmds_list)) { +		_evtack_node = list_entry(mrioc->delayed_evtack_cmds_list.next, +		    struct delayed_evt_ack_node, list); +		list_del(&_evtack_node->list); +		kfree(_evtack_node); +	}  }  /** @@ -1611,6 +1714,141 @@ out_failed:  }  /** + * mpi3mr_complete_evt_ack - event ack request completion + * @mrioc: Adapter instance reference + * @drv_cmd: Internal command tracker + * + * This is the completion handler for non blocking event + * acknowledgment sent to the firmware and this will issue any + * pending event acknowledgment request. + * + * Return: Nothing + */ +static void mpi3mr_complete_evt_ack(struct mpi3mr_ioc *mrioc, +	struct mpi3mr_drv_cmd *drv_cmd) +{ +	u16 cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_EVTACKCMD_MIN; +	struct delayed_evt_ack_node *delayed_evtack = NULL; + +	if (drv_cmd->ioc_status != MPI3_IOCSTATUS_SUCCESS) { +		dprint_event_th(mrioc, +		    "immediate event ack failed with ioc_status(0x%04x) log_info(0x%08x)\n", +		    (drv_cmd->ioc_status & MPI3_IOCSTATUS_STATUS_MASK), +		    drv_cmd->ioc_loginfo); +	} + +	if (!list_empty(&mrioc->delayed_evtack_cmds_list)) { +		delayed_evtack = +			list_entry(mrioc->delayed_evtack_cmds_list.next, +			    struct delayed_evt_ack_node, list); +		mpi3mr_send_event_ack(mrioc, delayed_evtack->event, drv_cmd, +		    delayed_evtack->event_ctx); +		list_del(&delayed_evtack->list); +		kfree(delayed_evtack); +		return; +	} +	drv_cmd->state = MPI3MR_CMD_NOTUSED; +	drv_cmd->callback = NULL; +	clear_bit(cmd_idx, mrioc->evtack_cmds_bitmap); +} + +/** + * mpi3mr_send_event_ack - Issue event acknwoledgment request + * @mrioc: Adapter instance reference + * @event: MPI3 event id + * @cmdparam: Internal command tracker + * @event_ctx: event context + * + * Issues event acknowledgment request to the firmware if there + * is a free command to send the event ack else it to a pend + * list so that it will be processed on a completion of a prior + * event acknowledgment . + * + * Return: Nothing + */ +static void mpi3mr_send_event_ack(struct mpi3mr_ioc *mrioc, u8 event, +	struct mpi3mr_drv_cmd *cmdparam, u32 event_ctx) +{ +	struct mpi3_event_ack_request evtack_req; +	int retval = 0; +	u8 retrycount = 5; +	u16 cmd_idx = MPI3MR_NUM_EVTACKCMD; +	struct mpi3mr_drv_cmd *drv_cmd = cmdparam; +	struct delayed_evt_ack_node *delayed_evtack = NULL; + +	if (drv_cmd) { +		dprint_event_th(mrioc, +		    "sending delayed event ack in the top half for event(0x%02x), event_ctx(0x%08x)\n", +		    event, event_ctx); +		goto issue_cmd; +	} +	dprint_event_th(mrioc, +	    "sending event ack in the top half for event(0x%02x), event_ctx(0x%08x)\n", +	    event, event_ctx); +	do { +		cmd_idx = find_first_zero_bit(mrioc->evtack_cmds_bitmap, +		    MPI3MR_NUM_EVTACKCMD); +		if (cmd_idx < MPI3MR_NUM_EVTACKCMD) { +			if (!test_and_set_bit(cmd_idx, +			    mrioc->evtack_cmds_bitmap)) +				break; +			cmd_idx = MPI3MR_NUM_EVTACKCMD; +		} +	} while (retrycount--); + +	if (cmd_idx >= MPI3MR_NUM_EVTACKCMD) { +		delayed_evtack = kzalloc(sizeof(*delayed_evtack), +		    GFP_ATOMIC); +		if (!delayed_evtack) +			return; +		INIT_LIST_HEAD(&delayed_evtack->list); +		delayed_evtack->event = event; +		delayed_evtack->event_ctx = event_ctx; +		list_add_tail(&delayed_evtack->list, +		    &mrioc->delayed_evtack_cmds_list); +		dprint_event_th(mrioc, +		    "event ack in the top half for event(0x%02x), event_ctx(0x%08x) is postponed\n", +		    event, event_ctx); +		return; +	} +	drv_cmd = &mrioc->evtack_cmds[cmd_idx]; + +issue_cmd: +	cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_EVTACKCMD_MIN; + +	memset(&evtack_req, 0, sizeof(evtack_req)); +	if (drv_cmd->state & MPI3MR_CMD_PENDING) { +		dprint_event_th(mrioc, +		    "sending event ack failed due to command in use\n"); +		goto out; +	} +	drv_cmd->state = MPI3MR_CMD_PENDING; +	drv_cmd->is_waiting = 0; +	drv_cmd->callback = mpi3mr_complete_evt_ack; +	evtack_req.host_tag = cpu_to_le16(drv_cmd->host_tag); +	evtack_req.function = MPI3_FUNCTION_EVENT_ACK; +	evtack_req.event = event; +	evtack_req.event_context = cpu_to_le32(event_ctx); +	retval = mpi3mr_admin_request_post(mrioc, &evtack_req, +	    sizeof(evtack_req), 1); +	if (retval) { +		dprint_event_th(mrioc, +		    "posting event ack request is failed\n"); +		goto out_failed; +	} + +	dprint_event_th(mrioc, +	    "event ack in the top half for event(0x%02x), event_ctx(0x%08x) is posted\n", +	    event, event_ctx); +out: +	return; +out_failed: +	drv_cmd->state = MPI3MR_CMD_NOTUSED; +	drv_cmd->callback = NULL; +	clear_bit(cmd_idx, mrioc->evtack_cmds_bitmap); +} + +/**   * mpi3mr_pcietopochg_evt_th - PCIETopologyChange evt tophalf   * @mrioc: Adapter instance reference   * @event_reply: event data @@ -1819,6 +2057,40 @@ out:  }  /** + * mpi3mr_preparereset_evt_th - Prepare for reset event tophalf + * @mrioc: Adapter instance reference + * @event_reply: event data + * + * Blocks and unblocks host level I/O based on the reason code + * + * Return: Nothing + */ +static void mpi3mr_preparereset_evt_th(struct mpi3mr_ioc *mrioc, +	struct mpi3_event_notification_reply *event_reply) +{ +	struct mpi3_event_data_prepare_for_reset *evtdata = +	    (struct mpi3_event_data_prepare_for_reset *)event_reply->event_data; + +	if (evtdata->reason_code == MPI3_EVENT_PREPARE_RESET_RC_START) { +		dprint_event_th(mrioc, +		    "prepare for reset event top half with rc=start\n"); +		if (mrioc->prepare_for_reset) +			return; +		mrioc->prepare_for_reset = 1; +		mrioc->prepare_for_reset_timeout_counter = 0; +	} else if (evtdata->reason_code == MPI3_EVENT_PREPARE_RESET_RC_ABORT) { +		dprint_event_th(mrioc, +		    "prepare for reset top half with rc=abort\n"); +		mrioc->prepare_for_reset = 0; +		mrioc->prepare_for_reset_timeout_counter = 0; +	} +	if ((event_reply->msg_flags & MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_MASK) +	    == MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_REQUIRED) +		mpi3mr_send_event_ack(mrioc, event_reply->event, NULL, +		    le32_to_cpu(event_reply->event_context)); +} + +/**   * mpi3mr_energypackchg_evt_th - Energy pack change evt tophalf   * @mrioc: Adapter instance reference   * @event_reply: event data @@ -1848,6 +2120,66 @@ static void mpi3mr_energypackchg_evt_th(struct mpi3mr_ioc *mrioc,  }  /** + * mpi3mr_tempthreshold_evt_th - Temp threshold event tophalf + * @mrioc: Adapter instance reference + * @event_reply: event data + * + * Displays temperature threshold event details and fault code + * if any is hit due to temperature exceeding threshold. + * + * Return: Nothing + */ +static void mpi3mr_tempthreshold_evt_th(struct mpi3mr_ioc *mrioc, +	struct mpi3_event_notification_reply *event_reply) +{ +	struct mpi3_event_data_temp_threshold *evtdata = +	    (struct mpi3_event_data_temp_threshold *)event_reply->event_data; + +	ioc_err(mrioc, "Temperature threshold levels %s%s%s exceeded for sensor: %d !!! Current temperature in Celsius: %d\n", +	    (le16_to_cpu(evtdata->status) & 0x1) ? "Warning " : " ", +	    (le16_to_cpu(evtdata->status) & 0x2) ? "Critical " : " ", +	    (le16_to_cpu(evtdata->status) & 0x4) ? "Fatal " : " ", evtdata->sensor_num, +	    le16_to_cpu(evtdata->current_temperature)); +	mpi3mr_print_fault_info(mrioc); +} + +/** + * mpi3mr_cablemgmt_evt_th - Cable management event tophalf + * @mrioc: Adapter instance reference + * @event_reply: event data + * + * Displays Cable manegemt event details. + * + * Return: Nothing + */ +static void mpi3mr_cablemgmt_evt_th(struct mpi3mr_ioc *mrioc, +	struct mpi3_event_notification_reply *event_reply) +{ +	struct mpi3_event_data_cable_management *evtdata = +	    (struct mpi3_event_data_cable_management *)event_reply->event_data; + +	switch (evtdata->status) { +	case MPI3_EVENT_CABLE_MGMT_STATUS_INSUFFICIENT_POWER: +	{ +		ioc_info(mrioc, "An active cable with receptacle_id %d cannot be powered.\n" +		    "Devices connected to this cable are not detected.\n" +		    "This cable requires %d mW of power.\n", +		    evtdata->receptacle_id, +		    le32_to_cpu(evtdata->active_cable_power_requirement)); +		break; +	} +	case MPI3_EVENT_CABLE_MGMT_STATUS_DEGRADED: +	{ +		ioc_info(mrioc, "A cable with receptacle_id %d is not running at optimal speed\n", +		    evtdata->receptacle_id); +		break; +	} +	default: +		break; +	} +} + +/**   * mpi3mr_os_handle_events - Firmware event handler   * @mrioc: Adapter instance reference   * @event_reply: event data @@ -1905,6 +2237,12 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc,  		mpi3mr_pcietopochg_evt_th(mrioc, event_reply);  		break;  	} +	case MPI3_EVENT_PREPARE_FOR_RESET: +	{ +		mpi3mr_preparereset_evt_th(mrioc, event_reply); +		ack_req = 0; +		break; +	}  	case MPI3_EVENT_DEVICE_INFO_CHANGED:  	{  		process_evt_bh = 1; @@ -1915,9 +2253,18 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc,  		mpi3mr_energypackchg_evt_th(mrioc, event_reply);  		break;  	} +	case MPI3_EVENT_TEMP_THRESHOLD: +	{ +		mpi3mr_tempthreshold_evt_th(mrioc, event_reply); +		break; +	} +	case MPI3_EVENT_CABLE_MGMT: +	{ +		mpi3mr_cablemgmt_evt_th(mrioc, event_reply); +		break; +	}  	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:  	case MPI3_EVENT_SAS_DISCOVERY: -	case MPI3_EVENT_CABLE_MGMT:  	case MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR:  	case MPI3_EVENT_SAS_BROADCAST_PRIMITIVE:  	case MPI3_EVENT_PCIE_ENUMERATION: @@ -2520,49 +2867,63 @@ static int mpi3mr_build_sg_scmd(struct mpi3mr_ioc *mrioc,  }  /** - * mpi3mr_print_response_code - print TM response as a string - * @mrioc: Adapter instance reference + * mpi3mr_tm_response_name -  get TM response as a string   * @resp_code: TM response code   * - * Print TM response code as a readable string. + * Convert known task management response code as a readable + * string.   * - * Return: Nothing. + * Return: response code string.   */ -static void mpi3mr_print_response_code(struct mpi3mr_ioc *mrioc, u8 resp_code) +static const char *mpi3mr_tm_response_name(u8 resp_code)  {  	char *desc;  	switch (resp_code) { -	case MPI3MR_RSP_TM_COMPLETE: +	case MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE:  		desc = "task management request completed";  		break; -	case MPI3MR_RSP_INVALID_FRAME: +	case MPI3_SCSITASKMGMT_RSPCODE_INVALID_FRAME:  		desc = "invalid frame";  		break; -	case MPI3MR_RSP_TM_NOT_SUPPORTED: +	case MPI3_SCSITASKMGMT_RSPCODE_TM_FUNCTION_NOT_SUPPORTED:  		desc = "task management request not supported";  		break; -	case MPI3MR_RSP_TM_FAILED: +	case MPI3_SCSITASKMGMT_RSPCODE_TM_FAILED:  		desc = "task management request failed";  		break; -	case MPI3MR_RSP_TM_SUCCEEDED: +	case MPI3_SCSITASKMGMT_RSPCODE_TM_SUCCEEDED:  		desc = "task management request succeeded";  		break; -	case MPI3MR_RSP_TM_INVALID_LUN: -		desc = "invalid lun"; +	case MPI3_SCSITASKMGMT_RSPCODE_TM_INVALID_LUN: +		desc = "invalid LUN";  		break; -	case MPI3MR_RSP_TM_OVERLAPPED_TAG: +	case MPI3_SCSITASKMGMT_RSPCODE_TM_OVERLAPPED_TAG:  		desc = "overlapped tag attempted";  		break; -	case MPI3MR_RSP_IO_QUEUED_ON_IOC: +	case MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC:  		desc = "task queued, however not sent to target";  		break; +	case MPI3_SCSITASKMGMT_RSPCODE_TM_NVME_DENIED: +		desc = "task management request denied by NVMe device"; +		break;  	default:  		desc = "unknown";  		break;  	} -	ioc_info(mrioc, "%s :response_code(0x%01x): %s\n", __func__, -	    resp_code, desc); + +	return desc; +} + +inline void mpi3mr_poll_pend_io_completions(struct mpi3mr_ioc *mrioc) +{ +	int i; +	int num_of_reply_queues = +	    mrioc->num_op_reply_q + mrioc->op_reply_q_offset; + +	for (i = mrioc->op_reply_q_offset; i < num_of_reply_queues; i++) +		mpi3mr_process_op_reply_q(mrioc, +		    mrioc->intr_info[i].op_reply_q);  }  /** @@ -2572,9 +2933,10 @@ static void mpi3mr_print_response_code(struct mpi3mr_ioc *mrioc, u8 resp_code)   * @handle: Device handle   * @lun: lun ID   * @htag: Host tag of the TM request + * @timeout: TM timeout value   * @drv_cmd: Internal command tracker   * @resp_code: Response code place holder - * @cmd_priv: SCSI command private data + * @scmd: SCSI command   *   * Issues a Task Management Request to the controller for a   * specified target, lun and command and wait for its completion @@ -2586,14 +2948,16 @@ static void mpi3mr_print_response_code(struct mpi3mr_ioc *mrioc, u8 resp_code)  static int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type,  	u16 handle, uint lun, u16 htag, ulong timeout,  	struct mpi3mr_drv_cmd *drv_cmd, -	u8 *resp_code, struct scmd_priv *cmd_priv) +	u8 *resp_code, struct scsi_cmnd *scmd)  {  	struct mpi3_scsi_task_mgmt_request tm_req;  	struct mpi3_scsi_task_mgmt_reply *tm_reply = NULL;  	int retval = 0;  	struct mpi3mr_tgt_dev *tgtdev = NULL;  	struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data = NULL; -	struct op_req_qinfo *op_req_q = NULL; +	struct scmd_priv *cmd_priv = NULL; +	struct scsi_device *sdev = NULL; +	struct mpi3mr_sdev_priv_data *sdev_priv_data = NULL;  	ioc_info(mrioc, "%s :Issue TM: TM type (0x%x) for devhandle 0x%04x\n",  	     __func__, tm_type, handle); @@ -2630,16 +2994,21 @@ static int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type,  	tm_req.function = MPI3_FUNCTION_SCSI_TASK_MGMT;  	tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, handle); -	if (tgtdev && tgtdev->starget && tgtdev->starget->hostdata) { -		scsi_tgt_priv_data = (struct mpi3mr_stgt_priv_data *) -		    tgtdev->starget->hostdata; -		atomic_inc(&scsi_tgt_priv_data->block_io); -	} -	if (cmd_priv) { -		op_req_q = &mrioc->req_qinfo[cmd_priv->req_q_idx]; -		tm_req.task_host_tag = cpu_to_le16(cmd_priv->host_tag); -		tm_req.task_request_queue_id = cpu_to_le16(op_req_q->qid); + +	if (scmd) { +		sdev = scmd->device; +		sdev_priv_data = sdev->hostdata; +		scsi_tgt_priv_data = ((sdev_priv_data) ? +		    sdev_priv_data->tgt_priv_data : NULL); +	} else { +		if (tgtdev && tgtdev->starget && tgtdev->starget->hostdata) +			scsi_tgt_priv_data = (struct mpi3mr_stgt_priv_data *) +			    tgtdev->starget->hostdata;  	} + +	if (scsi_tgt_priv_data) +		atomic_inc(&scsi_tgt_priv_data->block_io); +  	if (tgtdev && (tgtdev->dev_type == MPI3_DEVICE_DEVFORM_PCIE)) {  		if (cmd_priv && tgtdev->dev_spec.pcie_inf.abort_to)  			timeout = tgtdev->dev_spec.pcie_inf.abort_to; @@ -2656,39 +3025,49 @@ static int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type,  	wait_for_completion_timeout(&drv_cmd->done, (timeout * HZ));  	if (!(drv_cmd->state & MPI3MR_CMD_COMPLETE)) { -		ioc_err(mrioc, "%s :Issue TM: command timed out\n", __func__);  		drv_cmd->is_waiting = 0;  		retval = -1; -		mpi3mr_soft_reset_handler(mrioc, -		    MPI3MR_RESET_FROM_TM_TIMEOUT, 1); +		if (!(drv_cmd->state & MPI3MR_CMD_RESET)) { +			dprint_tm(mrioc, +			    "task management request timed out after %ld seconds\n", +			    timeout); +			if (mrioc->logging_level & MPI3_DEBUG_TM) +				dprint_dump_req(&tm_req, sizeof(tm_req)/4); +			mpi3mr_soft_reset_handler(mrioc, +			    MPI3MR_RESET_FROM_TM_TIMEOUT, 1); +		}  		goto out_unlock;  	} -	if (drv_cmd->state & MPI3MR_CMD_REPLY_VALID) -		tm_reply = (struct mpi3_scsi_task_mgmt_reply *)drv_cmd->reply; - -	if (drv_cmd->ioc_status != MPI3_IOCSTATUS_SUCCESS) { -		ioc_err(mrioc, -		    "%s :Issue TM: handle(0x%04x) Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", -		    __func__, handle, drv_cmd->ioc_status, -		    drv_cmd->ioc_loginfo); +	if (!(drv_cmd->state & MPI3MR_CMD_REPLY_VALID)) { +		dprint_tm(mrioc, "invalid task management reply message\n");  		retval = -1;  		goto out_unlock;  	} -	if (!tm_reply) { -		ioc_err(mrioc, "%s :Issue TM: No TM Reply message\n", __func__); +	tm_reply = (struct mpi3_scsi_task_mgmt_reply *)drv_cmd->reply; + +	switch (drv_cmd->ioc_status) { +	case MPI3_IOCSTATUS_SUCCESS: +		*resp_code = le32_to_cpu(tm_reply->response_data) & +			MPI3MR_RI_MASK_RESPCODE; +		break; +	case MPI3_IOCSTATUS_SCSI_IOC_TERMINATED: +		*resp_code = MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE; +		break; +	default: +		dprint_tm(mrioc, +		    "task management request to handle(0x%04x) is failed with ioc_status(0x%04x) log_info(0x%08x)\n", +		    handle, drv_cmd->ioc_status, drv_cmd->ioc_loginfo);  		retval = -1;  		goto out_unlock;  	} -	*resp_code = le32_to_cpu(tm_reply->response_data) & -	    MPI3MR_RI_MASK_RESPCODE;  	switch (*resp_code) { -	case MPI3MR_RSP_TM_SUCCEEDED: -	case MPI3MR_RSP_TM_COMPLETE: +	case MPI3_SCSITASKMGMT_RSPCODE_TM_SUCCEEDED: +	case MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE:  		break; -	case MPI3MR_RSP_IO_QUEUED_ON_IOC: +	case MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC:  		if (tm_type != MPI3_SCSITASKMGMT_TASKTYPE_QUERY_TASK)  			retval = -1;  		break; @@ -2697,14 +3076,37 @@ static int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type,  		break;  	} -	ioc_info(mrioc, -	    "%s :Issue TM: Completed TM type (0x%x) handle(0x%04x) ", -	    __func__, tm_type, handle); -	ioc_info(mrioc, -	    "with ioc_status(0x%04x), loginfo(0x%08x), term_count(0x%08x)\n", -	    drv_cmd->ioc_status, drv_cmd->ioc_loginfo, -	    le32_to_cpu(tm_reply->termination_count)); -	mpi3mr_print_response_code(mrioc, *resp_code); +	dprint_tm(mrioc, +	    "task management request type(%d) completed for handle(0x%04x) with ioc_status(0x%04x), log_info(0x%08x), termination_count(%d), response:%s(0x%x)\n", +	    tm_type, handle, drv_cmd->ioc_status, drv_cmd->ioc_loginfo, +	    le32_to_cpu(tm_reply->termination_count), +	    mpi3mr_tm_response_name(*resp_code), *resp_code); + +	if (!retval) { +		mpi3mr_ioc_disable_intr(mrioc); +		mpi3mr_poll_pend_io_completions(mrioc); +		mpi3mr_ioc_enable_intr(mrioc); +		mpi3mr_poll_pend_io_completions(mrioc); +	} +	switch (tm_type) { +	case MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET: +		if (!scsi_tgt_priv_data) +			break; +		scsi_tgt_priv_data->pend_count = 0; +		blk_mq_tagset_busy_iter(&mrioc->shost->tag_set, +		    mpi3mr_count_tgt_pending, +		    (void *)scsi_tgt_priv_data->starget); +		break; +	case MPI3_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET: +		if (!sdev_priv_data) +			break; +		sdev_priv_data->pend_count = 0; +		blk_mq_tagset_busy_iter(&mrioc->shost->tag_set, +		    mpi3mr_count_dev_pending, (void *)sdev); +		break; +	default: +		break; +	}  out_unlock:  	drv_cmd->state = MPI3MR_CMD_NOTUSED; @@ -2713,14 +3115,6 @@ out_unlock:  		atomic_dec_if_positive(&scsi_tgt_priv_data->block_io);  	if (tgtdev)  		mpi3mr_tgtdev_put(tgtdev); -	if (!retval) { -		/* -		 * Flush all IRQ handlers by calling synchronize_irq(). -		 * mpi3mr_ioc_disable_intr() takes care of it. -		 */ -		mpi3mr_ioc_disable_intr(mrioc); -		mpi3mr_ioc_enable_intr(mrioc); -	}  out:  	return retval;  } @@ -2769,17 +3163,49 @@ static int mpi3mr_bios_param(struct scsi_device *sdev,   * mpi3mr_map_queues - Map queues callback handler   * @shost: SCSI host reference   * - * Call the blk_mq_pci_map_queues with from which operational - * queue the mapping has to be done + * Maps default and poll queues.   * - * Return: return of blk_mq_pci_map_queues + * Return: return zero.   */  static int mpi3mr_map_queues(struct Scsi_Host *shost)  {  	struct mpi3mr_ioc *mrioc = shost_priv(shost); +	int i, qoff, offset; +	struct blk_mq_queue_map *map = NULL; + +	offset = mrioc->op_reply_q_offset; + +	for (i = 0, qoff = 0; i < HCTX_MAX_TYPES; i++) { +		map = &shost->tag_set.map[i]; + +		map->nr_queues  = 0; + +		if (i == HCTX_TYPE_DEFAULT) +			map->nr_queues = mrioc->default_qcount; +		else if (i == HCTX_TYPE_POLL) +			map->nr_queues = mrioc->active_poll_qcount; + +		if (!map->nr_queues) { +			BUG_ON(i == HCTX_TYPE_DEFAULT); +			continue; +		} + +		/* +		 * The poll queue(s) doesn't have an IRQ (and hence IRQ +		 * affinity), so use the regular blk-mq cpu mapping +		 */ +		map->queue_offset = qoff; +		if (i != HCTX_TYPE_POLL) +			blk_mq_pci_map_queues(map, mrioc->pdev, offset); +		else +			blk_mq_map_queues(map); + +		qoff += map->nr_queues; +		offset += map->nr_queues; +	} + +	return 0; -	return blk_mq_pci_map_queues(&shost->tag_set.map[HCTX_TYPE_DEFAULT], -	    mrioc->pdev, mrioc->op_reply_q_offset);  }  /** @@ -2938,6 +3364,13 @@ static int mpi3mr_eh_target_reset(struct scsi_cmnd *scmd)  	stgt_priv_data = sdev_priv_data->tgt_priv_data;  	dev_handle = stgt_priv_data->dev_handle; +	if (stgt_priv_data->dev_removed) { +		sdev_printk(KERN_INFO, scmd->device, +		    "%s:target(handle = 0x%04x) is removed, target reset is not issued\n", +		    mrioc->name, dev_handle); +		retval = FAILED; +		goto out; +	}  	sdev_printk(KERN_INFO, scmd->device,  	    "Target Reset is issued to handle(0x%04x)\n",  	    dev_handle); @@ -2945,15 +3378,22 @@ static int mpi3mr_eh_target_reset(struct scsi_cmnd *scmd)  	ret = mpi3mr_issue_tm(mrioc,  	    MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET, dev_handle,  	    sdev_priv_data->lun_id, MPI3MR_HOSTTAG_BLK_TMS, -	    MPI3MR_RESETTM_TIMEOUT, &mrioc->host_tm_cmds, &resp_code, NULL); +	    MPI3MR_RESETTM_TIMEOUT, &mrioc->host_tm_cmds, &resp_code, scmd);  	if (ret)  		goto out; +	if (stgt_priv_data->pend_count) { +		sdev_printk(KERN_INFO, scmd->device, +		    "%s: target has %d pending commands, target reset is failed\n", +		    mrioc->name, sdev_priv_data->pend_count); +		goto out; +	} +  	retval = SUCCESS;  out:  	sdev_printk(KERN_INFO, scmd->device, -	    "Target reset is %s for scmd(%p)\n", +	    "%s: target reset is %s for scmd(%p)\n", mrioc->name,  	    ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);  	return retval; @@ -2992,21 +3432,34 @@ static int mpi3mr_eh_dev_reset(struct scsi_cmnd *scmd)  	stgt_priv_data = sdev_priv_data->tgt_priv_data;  	dev_handle = stgt_priv_data->dev_handle; +	if (stgt_priv_data->dev_removed) { +		sdev_printk(KERN_INFO, scmd->device, +		    "%s: device(handle = 0x%04x) is removed, device(LUN) reset is not issued\n", +		    mrioc->name, dev_handle); +		retval = FAILED; +		goto out; +	}  	sdev_printk(KERN_INFO, scmd->device,  	    "Device(lun) Reset is issued to handle(0x%04x)\n", dev_handle);  	ret = mpi3mr_issue_tm(mrioc,  	    MPI3_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, dev_handle,  	    sdev_priv_data->lun_id, MPI3MR_HOSTTAG_BLK_TMS, -	    MPI3MR_RESETTM_TIMEOUT, &mrioc->host_tm_cmds, &resp_code, NULL); +	    MPI3MR_RESETTM_TIMEOUT, &mrioc->host_tm_cmds, &resp_code, scmd);  	if (ret)  		goto out; +	if (sdev_priv_data->pend_count) { +		sdev_printk(KERN_INFO, scmd->device, +		    "%s: device has %d pending commands, device(LUN) reset is failed\n", +		    mrioc->name, sdev_priv_data->pend_count); +		goto out; +	}  	retval = SUCCESS;  out:  	sdev_printk(KERN_INFO, scmd->device, -	    "Device(lun) reset is %s for scmd(%p)\n", +	    "%s: device(LUN) reset is %s for scmd(%p)\n", mrioc->name,  	    ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);  	return retval; @@ -3049,32 +3502,42 @@ static int mpi3mr_scan_finished(struct Scsi_Host *shost,  {  	struct mpi3mr_ioc *mrioc = shost_priv(shost);  	u32 pe_timeout = MPI3MR_PORTENABLE_TIMEOUT; +	u32 ioc_status = readl(&mrioc->sysif_regs->ioc_status); -	if (time >= (pe_timeout * HZ)) { +	if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) || +	    (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) { +		ioc_err(mrioc, "port enable failed due to fault or reset\n"); +		mpi3mr_print_fault_info(mrioc); +		mrioc->scan_failed = MPI3_IOCSTATUS_INTERNAL_ERROR; +		mrioc->scan_started = 0;  		mrioc->init_cmds.is_waiting = 0;  		mrioc->init_cmds.callback = NULL;  		mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; -		ioc_err(mrioc, "%s :port enable request timed out\n", __func__); -		mrioc->is_driver_loading = 0; -		mpi3mr_soft_reset_handler(mrioc, -		    MPI3MR_RESET_FROM_PE_TIMEOUT, 1);  	} -	if (mrioc->scan_failed) { -		ioc_err(mrioc, -		    "%s :port enable failed with (ioc_status=0x%08x)\n", -		    __func__, mrioc->scan_failed); -		mrioc->is_driver_loading = 0; -		mrioc->stop_drv_processing = 1; -		return 1; +	if (time >= (pe_timeout * HZ)) { +		ioc_err(mrioc, "port enable failed due to time out\n"); +		mpi3mr_check_rh_fault_ioc(mrioc, +		    MPI3MR_RESET_FROM_PE_TIMEOUT); +		mrioc->scan_failed = MPI3_IOCSTATUS_INTERNAL_ERROR; +		mrioc->scan_started = 0; +		mrioc->init_cmds.is_waiting = 0; +		mrioc->init_cmds.callback = NULL; +		mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;  	}  	if (mrioc->scan_started)  		return 0; -	ioc_info(mrioc, "%s :port enable: SUCCESS\n", __func__); + +	if (mrioc->scan_failed) { +		ioc_err(mrioc, +		    "port enable failed with status=0x%04x\n", +		    mrioc->scan_failed); +	} else +		ioc_info(mrioc, "port enable is successfully completed\n"); +  	mpi3mr_start_watchdog(mrioc);  	mrioc->is_driver_loading = 0; -  	return 1;  } @@ -3189,10 +3652,18 @@ static int mpi3mr_slave_configure(struct scsi_device *sdev)  	switch (tgt_dev->dev_type) {  	case MPI3_DEVICE_DEVFORM_PCIE:  		/*The block layer hw sector size = 512*/ -		blk_queue_max_hw_sectors(sdev->request_queue, -		    tgt_dev->dev_spec.pcie_inf.mdts / 512); -		blk_queue_virt_boundary(sdev->request_queue, -		    ((1 << tgt_dev->dev_spec.pcie_inf.pgsz) - 1)); +		if ((tgt_dev->dev_spec.pcie_inf.dev_info & +		    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) == +		    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) { +			blk_queue_max_hw_sectors(sdev->request_queue, +			    tgt_dev->dev_spec.pcie_inf.mdts / 512); +			if (tgt_dev->dev_spec.pcie_inf.pgsz == 0) +				blk_queue_virt_boundary(sdev->request_queue, +				    ((1 << MPI3MR_DEFAULT_PGSZEXP) - 1)); +			else +				blk_queue_virt_boundary(sdev->request_queue, +				    ((1 << tgt_dev->dev_spec.pcie_inf.pgsz) - 1)); +		}  		break;  	default:  		break; @@ -3312,9 +3783,22 @@ static bool mpi3mr_check_return_unmap(struct mpi3mr_ioc *mrioc,  	struct scsi_cmnd *scmd)  {  	unsigned char *buf; -	u16 param_len, desc_len; - -	param_len = get_unaligned_be16(scmd->cmnd + 7); +	u16 param_len, desc_len, trunc_param_len; + +	trunc_param_len = param_len = get_unaligned_be16(scmd->cmnd + 7); + +	if (mrioc->pdev->revision) { +		if ((param_len > 24) && ((param_len - 8) & 0xF)) { +			trunc_param_len -= (param_len - 8) & 0xF; +			dprint_scsi_command(mrioc, scmd, MPI3_DEBUG_SCSI_ERROR); +			dprint_scsi_err(mrioc, +			    "truncating param_len from (%d) to (%d)\n", +			    param_len, trunc_param_len); +			put_unaligned_be16(trunc_param_len, scmd->cmnd + 7); +			dprint_scsi_command(mrioc, scmd, MPI3_DEBUG_SCSI_ERROR); +		} +		return false; +	}  	if (!param_len) {  		ioc_warn(mrioc, @@ -3374,12 +3858,12 @@ static bool mpi3mr_check_return_unmap(struct mpi3mr_ioc *mrioc,  	}  	if (param_len > (desc_len + 8)) { +		trunc_param_len = desc_len + 8;  		scsi_print_command(scmd); -		ioc_warn(mrioc, -		    "%s: Truncating param_len(%d) to desc_len+8(%d)\n", -		    __func__, param_len, (desc_len + 8)); -		param_len = desc_len + 8; -		put_unaligned_be16(param_len, scmd->cmnd + 7); +		dprint_scsi_err(mrioc, +		    "truncating param_len(%d) to desc_len+8(%d)\n", +		    param_len, trunc_param_len); +		put_unaligned_be16(trunc_param_len, scmd->cmnd + 7);  		scsi_print_command(scmd);  	} @@ -3434,6 +3918,7 @@ static int mpi3mr_qcmd(struct Scsi_Host *shost,  	u32 scsiio_flags = 0;  	struct request *rq = scsi_cmd_to_rq(scmd);  	int iprio_class; +	u8 is_pcie_dev = 0;  	sdev_priv_data = scmd->device->hostdata;  	if (!sdev_priv_data || !sdev_priv_data->tgt_priv_data) { @@ -3478,8 +3963,10 @@ static int mpi3mr_qcmd(struct Scsi_Host *shost,  		goto out;  	} -	if ((scmd->cmnd[0] == UNMAP) && -	    (stgt_priv_data->dev_type == MPI3_DEVICE_DEVFORM_PCIE) && +	if (stgt_priv_data->dev_type == MPI3_DEVICE_DEVFORM_PCIE) +		is_pcie_dev = 1; +	if ((scmd->cmnd[0] == UNMAP) && is_pcie_dev && +	    (mrioc->pdev->device == MPI3_MFGPAGE_DEVID_SAS4116) &&  	    mpi3mr_check_return_unmap(mrioc, scmd))  		goto out; @@ -3559,6 +4046,7 @@ static struct scsi_host_template mpi3mr_driver_template = {  	.eh_host_reset_handler		= mpi3mr_eh_host_reset,  	.bios_param			= mpi3mr_bios_param,  	.map_queues			= mpi3mr_map_queues, +	.mq_poll                        = mpi3mr_blk_mq_poll,  	.no_write_same			= 1,  	.can_queue			= 1,  	.this_id			= -1, @@ -3567,6 +4055,7 @@ static struct scsi_host_template mpi3mr_driver_template = {  	 */  	.max_sectors			= 2048,  	.cmd_per_lun			= MPI3MR_MAX_CMDS_LUN, +	.max_segment_size		= 0xffffffff,  	.track_queue_depth		= 1,  	.cmd_size			= sizeof(struct scmd_priv),  }; @@ -3714,6 +4203,7 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)  	INIT_LIST_HEAD(&mrioc->fwevt_list);  	INIT_LIST_HEAD(&mrioc->tgtdev_list);  	INIT_LIST_HEAD(&mrioc->delayed_rmhs_list); +	INIT_LIST_HEAD(&mrioc->delayed_evtack_cmds_list);  	mutex_init(&mrioc->reset_mutex);  	mpi3mr_init_drv_cmd(&mrioc->init_cmds, MPI3MR_HOSTTAG_INITCMDS); @@ -3772,21 +4262,29 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)  		ioc_err(mrioc, "failure at %s:%d/%s()!\n",  		    __FILE__, __LINE__, __func__);  		retval = -ENODEV; -		goto out_fwevtthread_failed; +		goto fwevtthread_failed;  	}  	mrioc->is_driver_loading = 1; -	if (mpi3mr_init_ioc(mrioc, MPI3MR_IT_INIT)) { -		ioc_err(mrioc, "failure at %s:%d/%s()!\n", -		    __FILE__, __LINE__, __func__); +	mrioc->cpu_count = num_online_cpus(); +	if (mpi3mr_setup_resources(mrioc)) { +		ioc_err(mrioc, "setup resources failed\n");  		retval = -ENODEV; -		goto out_iocinit_failed; +		goto resource_alloc_failed; +	} +	if (mpi3mr_init_ioc(mrioc)) { +		ioc_err(mrioc, "initializing IOC failed\n"); +		retval = -ENODEV; +		goto init_ioc_failed;  	}  	shost->nr_hw_queues = mrioc->num_op_reply_q; +	if (mrioc->active_poll_qcount) +		shost->nr_maps = 3; +  	shost->can_queue = mrioc->max_host_ios;  	shost->sg_tablesize = MPI3MR_SG_DEPTH; -	shost->max_id = mrioc->facts.max_perids; +	shost->max_id = mrioc->facts.max_perids + 1;  	retval = scsi_add_host(shost, &pdev->dev);  	if (retval) { @@ -3799,10 +4297,14 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)  	return retval;  addhost_failed: -	mpi3mr_cleanup_ioc(mrioc, MPI3MR_COMPLETE_CLEANUP); -out_iocinit_failed: +	mpi3mr_stop_watchdog(mrioc); +	mpi3mr_cleanup_ioc(mrioc); +init_ioc_failed: +	mpi3mr_free_mem(mrioc); +	mpi3mr_cleanup_resources(mrioc); +resource_alloc_failed:  	destroy_workqueue(mrioc->fwevt_worker_thread); -out_fwevtthread_failed: +fwevtthread_failed:  	spin_lock(&mrioc_list_lock);  	list_del(&mrioc->list);  	spin_unlock(&mrioc_list_lock); @@ -3815,6 +4317,7 @@ shost_failed:   * mpi3mr_remove - PCI remove callback   * @pdev: PCI device instance   * + * Cleanup the IOC by issuing MUR and shutdown notification.   * Free up all memory and resources associated with the   * controllerand target devices, unregister the shost.   * @@ -3851,7 +4354,10 @@ static void mpi3mr_remove(struct pci_dev *pdev)  		mpi3mr_tgtdev_del_from_list(mrioc, tgtdev);  		mpi3mr_tgtdev_put(tgtdev);  	} -	mpi3mr_cleanup_ioc(mrioc, MPI3MR_COMPLETE_CLEANUP); +	mpi3mr_stop_watchdog(mrioc); +	mpi3mr_cleanup_ioc(mrioc); +	mpi3mr_free_mem(mrioc); +	mpi3mr_cleanup_resources(mrioc);  	spin_lock(&mrioc_list_lock);  	list_del(&mrioc->list); @@ -3891,7 +4397,10 @@ static void mpi3mr_shutdown(struct pci_dev *pdev)  	spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);  	if (wq)  		destroy_workqueue(wq); -	mpi3mr_cleanup_ioc(mrioc, MPI3MR_COMPLETE_CLEANUP); + +	mpi3mr_stop_watchdog(mrioc); +	mpi3mr_cleanup_ioc(mrioc); +	mpi3mr_cleanup_resources(mrioc);  }  #ifdef CONFIG_PM @@ -3921,7 +4430,7 @@ static int mpi3mr_suspend(struct pci_dev *pdev, pm_message_t state)  	mpi3mr_cleanup_fwevt_list(mrioc);  	scsi_block_requests(shost);  	mpi3mr_stop_watchdog(mrioc); -	mpi3mr_cleanup_ioc(mrioc, MPI3MR_SUSPEND); +	mpi3mr_cleanup_ioc(mrioc);  	device_state = pci_choose_state(pdev, state);  	ioc_info(mrioc, "pdev=0x%p, slot=%s, entering operating state [D%d]\n", @@ -3970,7 +4479,11 @@ static int mpi3mr_resume(struct pci_dev *pdev)  	mrioc->stop_drv_processing = 0;  	mpi3mr_memset_buffers(mrioc); -	mpi3mr_init_ioc(mrioc, MPI3MR_IT_RESUME); +	r = mpi3mr_reinit_ioc(mrioc, 1); +	if (r) { +		ioc_err(mrioc, "resuming controller failed[%d]\n", r); +		return r; +	}  	scsi_unblock_requests(shost);  	mpi3mr_start_watchdog(mrioc); @@ -3980,8 +4493,8 @@ static int mpi3mr_resume(struct pci_dev *pdev)  static const struct pci_device_id mpi3mr_pci_id_table[] = {  	{ -		PCI_DEVICE_SUB(PCI_VENDOR_ID_LSI_LOGIC, 0x00A5, -		    PCI_ANY_ID, PCI_ANY_ID) +		PCI_DEVICE_SUB(MPI3_MFGPAGE_VENDORID_BROADCOM, +		    MPI3_MFGPAGE_DEVID_SAS4116, PCI_ANY_ID, PCI_ANY_ID)  	},  	{ 0 }  }; |