Message ID | 1450445228-26571-5-git-send-email-Sumit.Saxena@avagotech.com (mailing list archive) |
---|---|
State | Changes Requested, archived |
Headers | show |
On 18.12.2015 14:26, Sumit Saxena wrote: > This patch will add task management(TM) support for SCSI commands in megaraid_sas driver. > Added TM functions are below- > 1)Task abort > 2)Target reset > > Below are few key points- > > 1. Currently, megaraid_sas driver performs Controller reset when any IO times out. > With these TM support added in driver, in case of IO timeout task abort and target > reset will be tried to recover timed out IO. If both fails to recover IO, then > Controller reset will be called. If the TM request times out, fail the TM and escalate > to the next level(Controller reset). > > 2. mr_device_priv_data will be allocated for all generation of controller, but is_tm_capable > flag will never be set for older controllers (prior to Invader series) as firmware support is not > available for T.M functionality. > > 3. whichever firmware is capable for TM will set is_tm_capable flag in firmware API, which will be used > by Driver to pass TM frame to firmware or return back to OS as Failure to escalate next level of Error handling. > > Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com> > Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com> > --- > drivers/scsi/megaraid/megaraid_sas.h | 13 + > drivers/scsi/megaraid/megaraid_sas_base.c | 63 +++- > drivers/scsi/megaraid/megaraid_sas_fusion.c | 479 ++++++++++++++++++++++++++- > drivers/scsi/megaraid/megaraid_sas_fusion.h | 117 +++++++- > 4 files changed, 653 insertions(+), 19 deletions(-) > > diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h > index dcc6ff8..0fcb156 100644 > --- a/drivers/scsi/megaraid/megaraid_sas.h > +++ b/drivers/scsi/megaraid/megaraid_sas.h > @@ -1520,6 +1520,15 @@ union megasas_frame { > u8 raw_bytes[64]; > }; > > +/** > + * struct MR_PRIV_DEVICE - sdev private hostdata > + * @is_tm_capable: firmware managed tm_capable flag > + * @tm_busy: TM request is in progress > + */ > +struct MR_PRIV_DEVICE { > + bool is_tm_capable; > + bool tm_busy; > +}; > struct megasas_cmd; > > union megasas_evt_class_locale { > @@ -2073,4 +2082,8 @@ void megasas_return_mfi_mpt_pthr(struct megasas_instance *instance, > int megasas_cmd_type(struct scsi_cmnd *cmd); > void megasas_setup_jbod_map(struct megasas_instance *instance); > > +void megasas_update_sdev_properties(struct scsi_device *sdev); > +int megasas_reset_fusion(struct Scsi_Host *shost, int reason); > +int megasas_task_abort_fusion(struct scsi_cmnd *scmd); > +int megasas_reset_target_fusion(struct scsi_cmnd *scmd); > #endif /*LSI_MEGARAID_SAS_H */ > diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c > index 380c627..c1dc23c 100644 > --- a/drivers/scsi/megaraid/megaraid_sas_base.c > +++ b/drivers/scsi/megaraid/megaraid_sas_base.c > @@ -189,7 +189,6 @@ int > wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd, > int seconds); > void megasas_reset_reply_desc(struct megasas_instance *instance); > -int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout); > void megasas_fusion_ocr_wq(struct work_struct *work); > static int megasas_get_ld_vf_affiliation(struct megasas_instance *instance, > int initial); > @@ -1645,6 +1644,7 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd) > { > struct megasas_instance *instance; > unsigned long flags; > + struct MR_PRIV_DEVICE *mr_device_priv_data; > > instance = (struct megasas_instance *) > scmd->device->host->hostdata; > @@ -1681,11 +1681,24 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd) > return 0; > } > > + mr_device_priv_data = scmd->device->hostdata; > + if (!mr_device_priv_data) { > + spin_unlock_irqrestore(&instance->hba_lock, flags); > + scmd->result = DID_NO_CONNECT << 16; > + scmd->scsi_done(scmd); > + return 0; > + } > + > if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) { > spin_unlock_irqrestore(&instance->hba_lock, flags); > return SCSI_MLQUEUE_HOST_BUSY; > } > > + if (mr_device_priv_data->tm_busy) { > + spin_unlock_irqrestore(&instance->hba_lock, flags); > + return SCSI_MLQUEUE_DEVICE_BUSY; > + } > + > spin_unlock_irqrestore(&instance->hba_lock, flags); > > scmd->result = 0; > @@ -1736,27 +1749,39 @@ static struct megasas_instance *megasas_lookup_instance(u16 host_no) > } > > /* > -* megasas_set_dma_alignment - Set DMA alignment for PI enabled VD > +* megasas_update_sdev_properties - Update sdev structure based on controller's FW capabilities > * > * @sdev: OS provided scsi device > * > * Returns void > */ > -static void megasas_set_dma_alignment(struct scsi_device *sdev) > +void megasas_update_sdev_properties(struct scsi_device *sdev) > { > + u16 pd_index = 0; > u32 device_id, ld; > struct megasas_instance *instance; > struct fusion_context *fusion; > + struct MR_PRIV_DEVICE *mr_device_priv_data; > + struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync; > struct MR_LD_RAID *raid; > struct MR_DRV_RAID_MAP_ALL *local_map_ptr; > > instance = megasas_lookup_instance(sdev->host->host_no); > fusion = instance->ctrl_context; > + mr_device_priv_data = sdev->hostdata; > > - if (!fusion) > + if (!fusion || !mr_device_priv_data) > return; How can this happen that mr_device_priv_data is NULL, and if isn't it a problem that you do not set the dma alignment and other megasas_instance values? > > - if (sdev->channel >= MEGASAS_MAX_PD_CHANNELS) { > + if (sdev->channel < MEGASAS_MAX_PD_CHANNELS && > + instance->use_seqnum_jbod_fp) { > + pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + > + sdev->id; > + pd_sync = (void *)fusion->pd_seq_sync > + [(instance->pd_seq_map_id - 1) & 1]; > + mr_device_priv_data->is_tm_capable = > + pd_sync->seq[pd_index].capability.tmCapable; > + } else { > device_id = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) > + sdev->id; > local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)]; > @@ -1764,10 +1789,14 @@ static void megasas_set_dma_alignment(struct scsi_device *sdev) > raid = MR_LdRaidGet(ld, local_map_ptr); > > if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER) > - blk_queue_update_dma_alignment(sdev->request_queue, 0x7); > + blk_queue_update_dma_alignment(sdev->request_queue, 0x7); Please keep the whitespace above. > + > + mr_device_priv_data->is_tm_capable = > + raid->capability.tmCapable; > } > } > > + > static int megasas_slave_configure(struct scsi_device *sdev) > { > u16 pd_index = 0; > @@ -1784,7 +1813,8 @@ static int megasas_slave_configure(struct scsi_device *sdev) > return -ENXIO; > } > } > - megasas_set_dma_alignment(sdev); > + megasas_update_sdev_properties(sdev); > + > /* > * The RAID firmware may require extended timeouts. > */ > @@ -1798,6 +1828,7 @@ static int megasas_slave_alloc(struct scsi_device *sdev) > { > u16 pd_index = 0; > struct megasas_instance *instance ; > + struct MR_PRIV_DEVICE *mr_device_priv_data; > > instance = megasas_lookup_instance(sdev->host->host_no); > if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) { > @@ -1809,13 +1840,26 @@ static int megasas_slave_alloc(struct scsi_device *sdev) > sdev->id; > if ((instance->allow_fw_scan || instance->pd_list[pd_index].driveState == > MR_PD_STATE_SYSTEM)) { > - return 0; > + goto scan_target; > } > return -ENXIO; > } > + > +scan_target: > + mr_device_priv_data = kzalloc(sizeof(*mr_device_priv_data), > + GFP_KERNEL); > + if (!mr_device_priv_data) > + return -ENOMEM; > + sdev->hostdata = mr_device_priv_data; > return 0; > } > > +static void megasas_slave_destroy(struct scsi_device *sdev) > +{ > + kfree(sdev->hostdata); > + sdev->hostdata = NULL; > +} > + > /* > * megasas_complete_outstanding_ioctls - Complete outstanding ioctls after a > * kill adapter > @@ -2885,6 +2929,7 @@ static struct scsi_host_template megasas_template = { > .proc_name = "megaraid_sas", > .slave_configure = megasas_slave_configure, > .slave_alloc = megasas_slave_alloc, > + .slave_destroy = megasas_slave_destroy, > .queuecommand = megasas_queue_command, > .eh_device_reset_handler = megasas_reset_device, > .eh_bus_reset_handler = megasas_reset_bus_host, > @@ -5434,6 +5479,8 @@ static int megasas_io_attach(struct megasas_instance *instance) > if (instance->ctrl_context) { > host->hostt->eh_device_reset_handler = NULL; > host->hostt->eh_bus_reset_handler = NULL; > + host->hostt->eh_target_reset_handler = megasas_reset_target_fusion; > + host->hostt->eh_abort_handler = megasas_task_abort_fusion; > } > > /* > diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c > index 1dc4537..0b31f5a 100644 > --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c > +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c > @@ -2100,6 +2100,8 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) > struct LD_LOAD_BALANCE_INFO *lbinfo; > int threshold_reply_count = 0; > struct scsi_cmnd *scmd_local = NULL; > + struct MR_TASK_MANAGE_REQUEST *mr_tm_req; > + struct MPI2_SCSI_TASK_MANAGE_REQUEST *mpi_tm_req; > > fusion = instance->ctrl_context; > > @@ -2141,6 +2143,16 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) > extStatus = scsi_io_req->RaidContext.exStatus; > > switch (scsi_io_req->Function) { > + case MPI2_FUNCTION_SCSI_TASK_MGMT: > + mr_tm_req = (struct MR_TASK_MANAGE_REQUEST *) > + cmd_fusion->io_request; > + mpi_tm_req = (struct MPI2_SCSI_TASK_MANAGE_REQUEST *) > + &mr_tm_req->TmRequest; > + dev_dbg(&instance->pdev->dev, "TM completion:" > + "type: 0x%x TaskMID: 0x%x\n", > + mpi_tm_req->TaskType, mpi_tm_req->TaskMID); > + complete(&cmd_fusion->done); > + break; > case MPI2_FUNCTION_SCSI_IO_REQUEST: /*Fast Path IO.*/ > /* Update load balancing info */ > device_id = MEGASAS_DEV_INDEX(scmd_local); > @@ -2727,6 +2739,457 @@ void megasas_refire_mgmt_cmd(struct megasas_instance *instance) > } > } > > +/* > + * megasas_track_scsiio : Track SCSI IOs outstanding to a SCSI device > + * @instance: per adapter struct > + * @channel: the channel assigned by the OS > + * @id: the id assigned by the OS > + * > + * Returns SUCCESS if no IOs pending to SCSI device, else return FAILED > + */ > + > +static int megasas_track_scsiio(struct megasas_instance *instance, > + int id, int channel) > +{ > + int i, found = 0; > + struct megasas_cmd_fusion *cmd_fusion; > + struct fusion_context *fusion; > + fusion = instance->ctrl_context; > + > + for (i = 0 ; i < instance->max_scsi_cmds; i++) { > + cmd_fusion = fusion->cmd_list[i]; > + if (cmd_fusion->scmd && > + (cmd_fusion->scmd->device->id == id && > + cmd_fusion->scmd->device->channel == channel)) { > + dev_info(&instance->pdev->dev, > + "SCSI commands pending to target" > + "channel %d id %d \tSMID: 0x%x\n", > + channel, id, cmd_fusion->index); > + scsi_print_command(cmd_fusion->scmd); > + found = 1; > + break; > + } > + } > + > + return found ? FAILED : SUCCESS; > +} > + > +/** > + * megasas_tm_response_code - translation of device response code > + * @ioc: per adapter object > + * @mpi_reply: MPI reply returned by firmware > + * > + * Return nothing. > + */ > +static void > +megasas_tm_response_code(struct megasas_instance *instance, > + struct MPI2_SCSI_TASK_MANAGE_REPLY *mpi_reply) > +{ > + char *desc; > + > + switch (mpi_reply->ResponseCode) { > + case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE: > + desc = "task management request completed"; > + break; > + case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME: > + desc = "invalid frame"; > + break; > + case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED: > + desc = "task management request not supported"; > + break; > + case MPI2_SCSITASKMGMT_RSP_TM_FAILED: > + desc = "task management request failed"; > + break; > + case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED: > + desc = "task management request succeeded"; > + break; > + case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN: > + desc = "invalid lun"; > + break; > + case 0xA: > + desc = "overlapped tag attempted"; > + break; > + case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC: > + desc = "task queued, however not sent to target"; > + break; > + default: > + desc = "unknown"; > + break; > + } > + dev_dbg(&instance->pdev->dev, "response_code(%01x): %s\n", > + mpi_reply->ResponseCode, desc); > + dev_dbg(&instance->pdev->dev, > + "TerminationCount/DevHandle/Function/TaskType/IOCStat/IOCLoginfo" > + " 0x%x/0x%x/0x%x/0x%x/0x%x/0x%x\n", > + mpi_reply->TerminationCount, mpi_reply->DevHandle, > + mpi_reply->Function, mpi_reply->TaskType, > + mpi_reply->IOCStatus, mpi_reply->IOCLogInfo); > +} > + > +/** > + * megasas_issue_tm - main routine for sending tm requests > + * @instance: per adapter struct > + * @device_handle: device handle > + * @channel: the channel assigned by the OS > + * @id: the id assigned by the OS > + * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in megaraid_sas_fusion.c) > + * @smid_task: smid assigned to the task > + * @m_type: TM_MUTEX_ON or TM_MUTEX_OFF > + * Context: user > + * > + * MegaRaid use MPT interface for Task Magement request. > + * A generic API for sending task management requests to firmware. > + * > + * Return SUCCESS or FAILED. > + */ > +static int > +megasas_issue_tm(struct megasas_instance *instance, u16 device_handle, > + uint channel, uint id, u16 smid_task, u8 type) > +{ > + struct MR_TASK_MANAGE_REQUEST *mr_request; > + struct MPI2_SCSI_TASK_MANAGE_REQUEST *mpi_request; > + unsigned long timeleft; > + struct megasas_cmd_fusion *cmd_fusion; > + struct megasas_cmd *cmd_mfi; > + union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc; > + struct fusion_context *fusion; > + struct megasas_cmd_fusion *scsi_lookup; > + int rc; > + struct MPI2_SCSI_TASK_MANAGE_REPLY *mpi_reply; > + > + fusion = instance->ctrl_context; > + > + cmd_mfi = megasas_get_cmd(instance); > + > + if (!cmd_mfi) { > + dev_err(&instance->pdev->dev, "Failed from %s %d\n", > + __func__, __LINE__); > + return -ENOMEM; > + } > + > + cmd_fusion = megasas_get_cmd_fusion(instance, > + instance->max_scsi_cmds + cmd_mfi->index); > + > + /* Save the smid. To be used for returning the cmd */ > + cmd_mfi->context.smid = cmd_fusion->index; > + > + req_desc = megasas_get_request_descriptor(instance, > + (cmd_fusion->index - 1)); > + if (!req_desc) { > + dev_err(&instance->pdev->dev, "Failed from %s %d\n", > + __func__, __LINE__); megasas_return_cmd should be called here? > + return -ENOMEM; > + } > + > + cmd_fusion->request_desc = req_desc; > + req_desc->Words = 0; > + > + scsi_lookup = fusion->cmd_list[smid_task - 1]; > + > + mr_request = (struct MR_TASK_MANAGE_REQUEST *) cmd_fusion->io_request; > + memset(mr_request, 0, sizeof(struct MR_TASK_MANAGE_REQUEST)); > + mpi_request = (struct MPI2_SCSI_TASK_MANAGE_REQUEST *) &mr_request->TmRequest; > + mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; > + mpi_request->DevHandle = cpu_to_le16(device_handle); > + mpi_request->TaskType = type; > + mpi_request->TaskMID = cpu_to_le16(smid_task); > + mpi_request->LUN[1] = 0; > + > + > + req_desc = cmd_fusion->request_desc; > + req_desc->HighPriority.SMID = cpu_to_le16(cmd_fusion->index); > + req_desc->HighPriority.RequestFlags = > + (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY << > + MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); > + req_desc->HighPriority.MSIxIndex = 0; > + req_desc->HighPriority.LMID = 0; > + req_desc->HighPriority.Reserved1 = 0; > + > + if (channel < MEGASAS_MAX_PD_CHANNELS) > + mr_request->tmReqFlags.isTMForPD = 1; > + else > + mr_request->tmReqFlags.isTMForLD = 1; > + > + init_completion(&cmd_fusion->done); > + megasas_fire_cmd_fusion(instance, req_desc); > + > + timeleft = wait_for_completion_timeout(&cmd_fusion->done, 50 * HZ); > + > + if (!timeleft) { > + dev_err(&instance->pdev->dev, > + "task mgmt type 0x%x timed out\n", type); > + mutex_unlock(&instance->reset_mutex); > + rc = megasas_reset_fusion(instance->host, MFI_IO_TIMEOUT_OCR); > + mutex_lock(&instance->reset_mutex); megasas_return_cmd should be called here too? > + return rc; > + } > + > + mpi_reply = (struct MPI2_SCSI_TASK_MANAGE_REPLY *) &mr_request->TMReply; > + megasas_tm_response_code(instance, mpi_reply); > + > + megasas_return_cmd(instance, cmd_mfi); > + rc = SUCCESS; > + switch (type) { > + case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK: > + if (scsi_lookup->scmd == NULL) > + break; > + else { > + instance->instancet->disable_intr(instance); > + msleep(1000); > + megasas_complete_cmd_dpc_fusion > + ((unsigned long)instance); > + instance->instancet->enable_intr(instance); > + if (scsi_lookup->scmd == NULL) > + break; > + } > + rc = FAILED; > + break; > + > + case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET: > + if ((channel == 0xFFFFFFFF) && (id == 0xFFFFFFFF)) > + break; > + instance->instancet->disable_intr(instance); > + msleep(1000); > + megasas_complete_cmd_dpc_fusion > + ((unsigned long)instance); > + rc = megasas_track_scsiio(instance, id, channel); > + instance->instancet->enable_intr(instance); > + > + break; > + case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET: > + case MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK: > + break; > + default: > + rc = FAILED; > + break; > + } > + > + return rc; > + > +} > + > +/* > + * megasas_fusion_smid_lookup : Look for fusion command correpspodning to SCSI > + * @instance: per adapter struct > + * > + * Return Non Zero index, if SMID found in outstanding commands > + */ > +static u16 megasas_fusion_smid_lookup(struct scsi_cmnd *scmd) > +{ > + int i, ret = 0; > + struct megasas_instance *instance; > + struct megasas_cmd_fusion *cmd_fusion; > + struct fusion_context *fusion; > + > + instance = (struct megasas_instance *)scmd->device->host->hostdata; > + > + fusion = instance->ctrl_context; > + > + for (i = 0; i < instance->max_scsi_cmds; i++) { > + cmd_fusion = fusion->cmd_list[i]; > + if (cmd_fusion->scmd && (cmd_fusion->scmd == scmd)) { > + scmd_printk(KERN_NOTICE, scmd, "Abort request is for" > + " SMID: %d\n", cmd_fusion->index); > + ret = cmd_fusion->index; > + break; > + } > + } > + > + return ret; > +} > + > +/* > +* megasas_get_tm_devhandle - Get devhandle for TM request > +* @sdev- OS provided scsi device > +* > +* Returns- devhandle/targetID of SCSI device > +*/ > +static u16 megasas_get_tm_devhandle(struct scsi_device *sdev) > +{ > + u16 pd_index = 0; > + u32 device_id; > + struct megasas_instance *instance; > + struct fusion_context *fusion; > + struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync; > + u16 devhandle = (u16)ULONG_MAX; > + > + instance = (struct megasas_instance *)sdev->host->hostdata; > + fusion = instance->ctrl_context; > + > + if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) { > + if (instance->use_seqnum_jbod_fp) { > + pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + > + sdev->id; > + pd_sync = (void *)fusion->pd_seq_sync > + [(instance->pd_seq_map_id - 1) & 1]; > + devhandle = pd_sync->seq[pd_index].devHandle; > + } else > + sdev_printk(KERN_ERR, sdev, "Firmware expose tmCapable" > + " without JBOD MAP support from %s %d\n", __func__, __LINE__); > + } else { > + device_id = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) > + + sdev->id; > + devhandle = device_id; > + } > + > + return devhandle; > +} > + > +/* > + * megasas_task_abort_fusion : SCSI task abort function for fusion adapters > + * @scmd : pointer to scsi command object > + * > + * Return SUCCESS, if command aborted else FAILED > + */ > + > +int megasas_task_abort_fusion(struct scsi_cmnd *scmd) > +{ > + struct megasas_instance *instance; > + u16 smid, devhandle; > + struct fusion_context *fusion; > + int ret; > + struct MR_PRIV_DEVICE *mr_device_priv_data; > + mr_device_priv_data = scmd->device->hostdata; > + > + > + instance = (struct megasas_instance *)scmd->device->host->hostdata; > + fusion = instance->ctrl_context; > + > + if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) { > + dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL," > + "SCSI host:%d\n", instance->host->host_no); > + ret = FAILED; > + return ret; > + } > + > + if (!mr_device_priv_data) { > + sdev_printk(KERN_INFO, scmd->device, "device been deleted! " > + "scmd(%p)\n", scmd); > + scmd->result = DID_NO_CONNECT << 16; > + scmd->scsi_done(scmd); Device has been deleted doesn't that imply that all commands had to be before finished - so you should not call scsi_done ? > + ret = SUCCESS; > + goto out; > + } > + > + > + if (!mr_device_priv_data->is_tm_capable) { > + scmd->result = DID_RESET << 16; I think that setting scmd->result makes no sense here (too) a FAILED return should be enough. > + ret = FAILED; > + goto out; > + } > + > + mutex_lock(&instance->reset_mutex); > + > + smid = megasas_fusion_smid_lookup(scmd); > + > + if (!smid) { > + scmd->result = DID_RESET << 16; I think that setting scmd->result makes no sense here (too) a SUCCESS return should be enough. > + ret = SUCCESS; > + scmd_printk(KERN_NOTICE, scmd, "Command for which abort is" > + " issued is not found in oustanding commands\n"); > + mutex_unlock(&instance->reset_mutex); > + goto out; > + } > + > + devhandle = megasas_get_tm_devhandle(scmd->device); > + > + if (devhandle == (u16)ULONG_MAX) { > + scmd->result = DID_RESET << 16; same here and on other places > + ret = SUCCESS; > + sdev_printk(KERN_INFO, scmd->device, > + "task abort issued for invalid devhandle\n"); > + mutex_unlock(&instance->reset_mutex); > + goto out; > + } > + sdev_printk(KERN_INFO, scmd->device, > + "attempting task abort! scmd(%p) tm_dev_handle 0x%x\n", > + scmd, devhandle); > + > + mr_device_priv_data->tm_busy = 1; > + ret = megasas_issue_tm(instance, devhandle, > + scmd->device->channel, scmd->device->id, smid, > + MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK); > + mr_device_priv_data->tm_busy = 0; > + > + mutex_unlock(&instance->reset_mutex); > +out: > + sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n", > + ((ret == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); > + > + return ret; > +} > + > +/* > + * megasas_reset_target_fusion : target reset function for fusion adapters > + * scmd: SCSI command pointer > + * > + * Returns SUCCESS if all commands associated with target aborted else FAILED > + */ > + > +int megasas_reset_target_fusion(struct scsi_cmnd *scmd) > +{ > + > + struct megasas_instance *instance; > + int ret = FAILED; > + u16 devhandle; > + struct fusion_context *fusion; > + struct MR_PRIV_DEVICE *mr_device_priv_data; > + mr_device_priv_data = scmd->device->hostdata; > + > + instance = (struct megasas_instance *)scmd->device->host->hostdata; > + fusion = instance->ctrl_context; > + > + if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) { > + dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL," > + "SCSI host:%d\n", instance->host->host_no); > + ret = FAILED; > + return ret; > + } > + > + if (!mr_device_priv_data) { > + sdev_printk(KERN_INFO, scmd->device, "device been deleted! " > + "scmd(%p)\n", scmd); > + scmd->result = DID_NO_CONNECT << 16; > + scmd->scsi_done(scmd); > + ret = SUCCESS; > + goto out; > + } > + > + > + if (!mr_device_priv_data->is_tm_capable) { > + scmd->result = DID_RESET << 16; > + ret = FAILED; > + goto out; > + } > + > + mutex_lock(&instance->reset_mutex); > + devhandle = megasas_get_tm_devhandle(scmd->device); > + > + if (devhandle == (u16)ULONG_MAX) { > + scmd->result = DID_RESET << 16; > + ret = SUCCESS; > + sdev_printk(KERN_INFO, scmd->device, > + "target reset issued for invalid devhandle\n"); > + mutex_unlock(&instance->reset_mutex); > + goto out; > + } > + > + sdev_printk(KERN_INFO, scmd->device, > + "attempting target reset! scmd(%p) tm_dev_handle 0x%x\n", > + scmd, devhandle); > + mr_device_priv_data->tm_busy = 1; > + ret = megasas_issue_tm(instance, devhandle, > + scmd->device->channel, scmd->device->id, 0, > + MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET); > + mr_device_priv_data->tm_busy = 0; > + mutex_unlock(&instance->reset_mutex); > +out: > + scmd_printk(KERN_NOTICE, scmd, "megasas: target reset %s!!\n", > + (ret == SUCCESS) ? "SUCCESS" : "FAILED"); > + > + return ret; > +} > + > /* Check for a second path that is currently UP */ > int megasas_check_mpio_paths(struct megasas_instance *instance, > struct scsi_cmnd *scmd) > @@ -2752,7 +3215,7 @@ out: > } > > /* Core fusion reset function */ > -int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) > +int megasas_reset_fusion(struct Scsi_Host *shost, int reason) > { > int retval = SUCCESS, i, convert = 0; > struct megasas_instance *instance; > @@ -2761,6 +3224,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) > u32 abs_state, status_reg, reset_adapter; > u32 io_timeout_in_crash_mode = 0; > struct scsi_cmnd *scmd_local = NULL; > + struct scsi_device *sdev; > > instance = (struct megasas_instance *)shost->hostdata; > fusion = instance->ctrl_context; > @@ -2779,8 +3243,8 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) > > /* IO timeout detected, forcibly put FW in FAULT state */ > if (abs_state != MFI_STATE_FAULT && instance->crash_dump_buf && > - instance->crash_dump_app_support && iotimeout) { > - dev_info(&instance->pdev->dev, "IO timeout is detected, " > + instance->crash_dump_app_support && reason) { > + dev_info(&instance->pdev->dev, "IO/DCMD timeout is detected, " > "forcibly FAULT Firmware\n"); > instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT; > status_reg = readl(&instance->reg_set->doorbell); > @@ -2819,13 +3283,13 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) > msleep(1000); > > /* First try waiting for commands to complete */ > - if (megasas_wait_for_outstanding_fusion(instance, iotimeout, > + if (megasas_wait_for_outstanding_fusion(instance, reason, > &convert)) { > instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT; > dev_warn(&instance->pdev->dev, "resetting fusion " > "adapter scsi%d.\n", instance->host->host_no); > if (convert) > - iotimeout = 0; > + reason = 0; > > /* Now return commands back to the OS */ > for (i = 0 ; i < instance->max_scsi_cmds; i++) { > @@ -2859,7 +3323,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) > } > > /* Let SR-IOV VF & PF sync up if there was a HB failure */ > - if (instance->requestorId && !iotimeout) { > + if (instance->requestorId && !reason) { > msleep(MEGASAS_OCR_SETTLE_TIME_VF); > /* Look for a late HB update after VF settle time */ > if (abs_state == MFI_STATE_OPERATIONAL && > @@ -2954,6 +3418,9 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) > > megasas_setup_jbod_map(instance); > > + shost_for_each_device(sdev, shost) > + megasas_update_sdev_properties(sdev); > + > clear_bit(MEGASAS_FUSION_IN_RESET, > &instance->reset_flags); > instance->instancet->enable_intr(instance); > diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h > index a9e10c4..a1f1c0b 100644 > --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h > +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h > @@ -176,6 +176,7 @@ enum REGION_TYPE { > #define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD (0x0100) > #define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP (0x0004) > #define MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) /* SCSI IO */ > +#define MPI2_FUNCTION_SCSI_TASK_MGMT (0x01) > #define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x03) > #define MPI2_REQ_DESCRIPT_FLAGS_FP_IO (0x06) > #define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO (0x00) > @@ -278,6 +279,100 @@ union MPI2_SCSI_IO_CDB_UNION { > struct MPI2_SGE_SIMPLE_UNION SGE; > }; > > +/**************************************************************************** > +* SCSI Task Management messages > +****************************************************************************/ > + > +/*SCSI Task Management Request Message */ > +struct MPI2_SCSI_TASK_MANAGE_REQUEST { > + u16 DevHandle; /*0x00 */ > + u8 ChainOffset; /*0x02 */ > + u8 Function; /*0x03 */ > + u8 Reserved1; /*0x04 */ > + u8 TaskType; /*0x05 */ > + u8 Reserved2; /*0x06 */ > + u8 MsgFlags; /*0x07 */ > + u8 VP_ID; /*0x08 */ > + u8 VF_ID; /*0x09 */ > + u16 Reserved3; /*0x0A */ > + u8 LUN[8]; /*0x0C */ > + u32 Reserved4[7]; /*0x14 */ > + u16 TaskMID; /*0x30 */ > + u16 Reserved5; /*0x32 */ > +}; > + > + > +/*SCSI Task Management Reply Message */ > +struct MPI2_SCSI_TASK_MANAGE_REPLY { > + u16 DevHandle; /*0x00 */ > + u8 MsgLength; /*0x02 */ > + u8 Function; /*0x03 */ > + u8 ResponseCode; /*0x04 */ > + u8 TaskType; /*0x05 */ > + u8 Reserved1; /*0x06 */ > + u8 MsgFlags; /*0x07 */ > + u8 VP_ID; /*0x08 */ > + u8 VF_ID; /*0x09 */ > + u16 Reserved2; /*0x0A */ > + u16 Reserved3; /*0x0C */ > + u16 IOCStatus; /*0x0E */ > + u32 IOCLogInfo; /*0x10 */ > + u32 TerminationCount; /*0x14 */ > + u32 ResponseInfo; /*0x18 */ > +}; > + > +struct MR_TM_REQUEST { > + char request[128]; > +}; > + > +struct MR_TM_REPLY { > + char reply[128]; > +}; > + > +/* SCSI Task Management Request Message */ > +struct MR_TASK_MANAGE_REQUEST { > + /*To be type casted to struct MPI2_SCSI_TASK_MANAGE_REQUEST */ > + struct MR_TM_REQUEST TmRequest; > + union { > + struct { > +#if defined(__BIG_ENDIAN_BITFIELD) > + u32 reserved1:30; > + u32 isTMForPD:1; > + u32 isTMForLD:1; > +#else > + u32 isTMForLD:1; > + u32 isTMForPD:1; > + u32 reserved1:30; > +#endif > + u32 reserved2; > + } tmReqFlags; > + struct MR_TM_REPLY TMReply; > + }; > +}; > + > +/* TaskType values */ > + > +#define MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK (0x01) > +#define MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET (0x02) > +#define MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET (0x03) > +#define MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05) > +#define MPI2_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06) > +#define MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK (0x07) > +#define MPI2_SCSITASKMGMT_TASKTYPE_CLR_ACA (0x08) > +#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_TASK_SET (0x09) > +#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT (0x0A) > + > +/* ResponseCode values */ > + > +#define MPI2_SCSITASKMGMT_RSP_TM_COMPLETE (0x00) > +#define MPI2_SCSITASKMGMT_RSP_INVALID_FRAME (0x02) > +#define MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED (0x04) > +#define MPI2_SCSITASKMGMT_RSP_TM_FAILED (0x05) > +#define MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED (0x08) > +#define MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN (0x09) > +#define MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG (0x0A) > +#define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC (0x80) > + > /* > * RAID SCSI IO Request Message > * Total SGE count will be one less than _MPI2_SCSI_IO_REQUEST > @@ -548,7 +643,8 @@ struct MR_SPAN_BLOCK_INFO { > struct MR_LD_RAID { > struct { > #if defined(__BIG_ENDIAN_BITFIELD) > - u32 reserved4:7; > + u32 reserved4:6; > + u32 tmCapable:1; > u32 fpNonRWCapable:1; > u32 fpReadAcrossStripe:1; > u32 fpWriteAcrossStripe:1; > @@ -570,7 +666,8 @@ struct MR_LD_RAID { > u32 fpWriteAcrossStripe:1; > u32 fpReadAcrossStripe:1; > u32 fpNonRWCapable:1; > - u32 reserved4:7; > + u32 tmCapable:1; > + u32 reserved4:6; > #endif > } capability; > __le32 reserved6; > @@ -695,6 +792,7 @@ struct megasas_cmd_fusion { > u32 sync_cmd_idx; > u32 index; > u8 pd_r1_lb; > + struct completion done; > }; > > struct LD_LOAD_BALANCE_INFO { > @@ -808,9 +906,18 @@ struct MR_FW_RAID_MAP_EXT { > * * define MR_PD_CFG_SEQ structure for system PDs > * */ > struct MR_PD_CFG_SEQ { > - __le16 seqNum; > - __le16 devHandle; > - u8 reserved[4]; > + u16 seqNum; > + u16 devHandle; > + struct { > +#if defined(__BIG_ENDIAN_BITFIELD) > + u8 reserved:7; > + u8 tmCapable:1; > +#else > + u8 tmCapable:1; > + u8 reserved:7; > +#endif > + } capability; > + u8 reserved[3]; > } __packed; > > struct MR_PD_CFG_SEQ_NUM_SYNC { -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
> -----Original Message----- > From: Tomas Henzl [mailto:thenzl@redhat.com] > Sent: Monday, January 11, 2016 10:34 PM > To: Sumit Saxena; jbottomley@parallels.com; hch@infradead.org; > martin.petersen@oracle.com > Cc: linux-scsi@vger.kernel.org; kashyap.desai@avagotech.com > Subject: Re: [PATCH 04/15] megaraid_sas: Task management support > > On 18.12.2015 14:26, Sumit Saxena wrote: > > This patch will add task management(TM) support for SCSI commands in > megaraid_sas driver. > > Added TM functions are below- > > 1)Task abort > > 2)Target reset > > > > Below are few key points- > > > > 1. Currently, megaraid_sas driver performs Controller reset when any IO times > out. > > With these TM support added in driver, in case of IO timeout task > > abort and target reset will be tried to recover timed out IO. If both > > fails to recover IO, then Controller reset will be called. If the TM > > request times out, fail the TM and escalate to the next level(Controller reset). > > > > 2. mr_device_priv_data will be allocated for all generation of > > controller, but is_tm_capable flag will never be set for older > > controllers (prior to Invader series) as firmware support is not available for > T.M functionality. > > > > 3. whichever firmware is capable for TM will set is_tm_capable flag in > > firmware API, which will be used by Driver to pass TM frame to firmware or > return back to OS as Failure to escalate next level of Error handling. > > > > Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com> > > Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com> > > --- > > drivers/scsi/megaraid/megaraid_sas.h | 13 + > > drivers/scsi/megaraid/megaraid_sas_base.c | 63 +++- > > drivers/scsi/megaraid/megaraid_sas_fusion.c | 479 > > ++++++++++++++++++++++++++- > > drivers/scsi/megaraid/megaraid_sas_fusion.h | 117 +++++++- > > 4 files changed, 653 insertions(+), 19 deletions(-) > > > > diff --git a/drivers/scsi/megaraid/megaraid_sas.h > > b/drivers/scsi/megaraid/megaraid_sas.h > > index dcc6ff8..0fcb156 100644 > > --- a/drivers/scsi/megaraid/megaraid_sas.h > > +++ b/drivers/scsi/megaraid/megaraid_sas.h > > @@ -1520,6 +1520,15 @@ union megasas_frame { > > u8 raw_bytes[64]; > > }; > > > > +/** > > + * struct MR_PRIV_DEVICE - sdev private hostdata > > + * @is_tm_capable: firmware managed tm_capable flag > > + * @tm_busy: TM request is in progress */ struct MR_PRIV_DEVICE { > > + bool is_tm_capable; > > + bool tm_busy; > > +}; > > struct megasas_cmd; > > > > union megasas_evt_class_locale { > > @@ -2073,4 +2082,8 @@ void megasas_return_mfi_mpt_pthr(struct > > megasas_instance *instance, int megasas_cmd_type(struct scsi_cmnd > > *cmd); void megasas_setup_jbod_map(struct megasas_instance > > *instance); > > > > +void megasas_update_sdev_properties(struct scsi_device *sdev); int > > +megasas_reset_fusion(struct Scsi_Host *shost, int reason); int > > +megasas_task_abort_fusion(struct scsi_cmnd *scmd); int > > +megasas_reset_target_fusion(struct scsi_cmnd *scmd); > > #endif /*LSI_MEGARAID_SAS_H */ > > diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c > > b/drivers/scsi/megaraid/megaraid_sas_base.c > > index 380c627..c1dc23c 100644 > > --- a/drivers/scsi/megaraid/megaraid_sas_base.c > > +++ b/drivers/scsi/megaraid/megaraid_sas_base.c > > @@ -189,7 +189,6 @@ int > > wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd, > > int seconds); > > void megasas_reset_reply_desc(struct megasas_instance *instance); > > -int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout); > > void megasas_fusion_ocr_wq(struct work_struct *work); static int > > megasas_get_ld_vf_affiliation(struct megasas_instance *instance, > > int initial); > > @@ -1645,6 +1644,7 @@ megasas_queue_command(struct Scsi_Host *shost, > > struct scsi_cmnd *scmd) { > > struct megasas_instance *instance; > > unsigned long flags; > > + struct MR_PRIV_DEVICE *mr_device_priv_data; > > > > instance = (struct megasas_instance *) > > scmd->device->host->hostdata; > > @@ -1681,11 +1681,24 @@ megasas_queue_command(struct Scsi_Host > *shost, struct scsi_cmnd *scmd) > > return 0; > > } > > > > + mr_device_priv_data = scmd->device->hostdata; > > + if (!mr_device_priv_data) { > > + spin_unlock_irqrestore(&instance->hba_lock, flags); > > + scmd->result = DID_NO_CONNECT << 16; > > + scmd->scsi_done(scmd); > > + return 0; > > + } > > + > > if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) { > > spin_unlock_irqrestore(&instance->hba_lock, flags); > > return SCSI_MLQUEUE_HOST_BUSY; > > } > > > > + if (mr_device_priv_data->tm_busy) { > > + spin_unlock_irqrestore(&instance->hba_lock, flags); > > + return SCSI_MLQUEUE_DEVICE_BUSY; > > + } > > + > > spin_unlock_irqrestore(&instance->hba_lock, flags); > > > > scmd->result = 0; > > @@ -1736,27 +1749,39 @@ static struct megasas_instance > > *megasas_lookup_instance(u16 host_no) } > > > > /* > > -* megasas_set_dma_alignment - Set DMA alignment for PI enabled VD > > +* megasas_update_sdev_properties - Update sdev structure based on > > +controller's FW capabilities > > * > > * @sdev: OS provided scsi device > > * > > * Returns void > > */ > > -static void megasas_set_dma_alignment(struct scsi_device *sdev) > > +void megasas_update_sdev_properties(struct scsi_device *sdev) > > { > > + u16 pd_index = 0; > > u32 device_id, ld; > > struct megasas_instance *instance; > > struct fusion_context *fusion; > > + struct MR_PRIV_DEVICE *mr_device_priv_data; > > + struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync; > > struct MR_LD_RAID *raid; > > struct MR_DRV_RAID_MAP_ALL *local_map_ptr; > > > > instance = megasas_lookup_instance(sdev->host->host_no); > > fusion = instance->ctrl_context; > > + mr_device_priv_data = sdev->hostdata; > > > > - if (!fusion) > > + if (!fusion || !mr_device_priv_data) > > return; > > How can this happen that mr_device_priv_data is NULL, and if isn't it a problem > that you do not set the dma alignment and other megasas_instance values? > Yes, "mr_device_priv_data" cannot be NULL. If allocation of "mr_device_priv_data" is failed inside slave_alloc then slave_config will not be called at all for that particular "sdev". I will send modified patch. > > > > - if (sdev->channel >= MEGASAS_MAX_PD_CHANNELS) { > > + if (sdev->channel < MEGASAS_MAX_PD_CHANNELS && > > + instance->use_seqnum_jbod_fp) { > > + pd_index = (sdev->channel * > MEGASAS_MAX_DEV_PER_CHANNEL) + > > + sdev->id; > > + pd_sync = (void *)fusion->pd_seq_sync > > + [(instance->pd_seq_map_id - 1) & 1]; > > + mr_device_priv_data->is_tm_capable = > > + pd_sync->seq[pd_index].capability.tmCapable; > > + } else { > > device_id = ((sdev->channel % 2) * > MEGASAS_MAX_DEV_PER_CHANNEL) > > + sdev->id; > > local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)]; > @@ > > -1764,10 +1789,14 @@ static void megasas_set_dma_alignment(struct > scsi_device *sdev) > > raid = MR_LdRaidGet(ld, local_map_ptr); > > > > if (raid->capability.ldPiMode == > MR_PROT_INFO_TYPE_CONTROLLER) > > - blk_queue_update_dma_alignment(sdev- > >request_queue, 0x7); > > + blk_queue_update_dma_alignment(sdev->request_queue, 0x7); > > Please keep the whitespace above. Ok.. > > > + > > + mr_device_priv_data->is_tm_capable = > > + raid->capability.tmCapable; > > } > > } > > > > + > > static int megasas_slave_configure(struct scsi_device *sdev) { > > u16 pd_index = 0; > > @@ -1784,7 +1813,8 @@ static int megasas_slave_configure(struct > scsi_device *sdev) > > return -ENXIO; > > } > > } > > - megasas_set_dma_alignment(sdev); > > + megasas_update_sdev_properties(sdev); > > + > > /* > > * The RAID firmware may require extended timeouts. > > */ > > @@ -1798,6 +1828,7 @@ static int megasas_slave_alloc(struct > > scsi_device *sdev) { > > u16 pd_index = 0; > > struct megasas_instance *instance ; > > + struct MR_PRIV_DEVICE *mr_device_priv_data; > > > > instance = megasas_lookup_instance(sdev->host->host_no); > > if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) { @@ -1809,13 > +1840,26 > > @@ static int megasas_slave_alloc(struct scsi_device *sdev) > > sdev->id; > > if ((instance->allow_fw_scan || instance- > >pd_list[pd_index].driveState == > > MR_PD_STATE_SYSTEM)) { > > - return 0; > > + goto scan_target; > > } > > return -ENXIO; > > } > > + > > +scan_target: > > + mr_device_priv_data = kzalloc(sizeof(*mr_device_priv_data), > > + GFP_KERNEL); > > + if (!mr_device_priv_data) > > + return -ENOMEM; > > + sdev->hostdata = mr_device_priv_data; > > return 0; > > } > > > > +static void megasas_slave_destroy(struct scsi_device *sdev) { > > + kfree(sdev->hostdata); > > + sdev->hostdata = NULL; > > +} > > + > > /* > > * megasas_complete_outstanding_ioctls - Complete outstanding ioctls after a > > * kill adapter > > @@ -2885,6 +2929,7 @@ static struct scsi_host_template megasas_template > = { > > .proc_name = "megaraid_sas", > > .slave_configure = megasas_slave_configure, > > .slave_alloc = megasas_slave_alloc, > > + .slave_destroy = megasas_slave_destroy, > > .queuecommand = megasas_queue_command, > > .eh_device_reset_handler = megasas_reset_device, > > .eh_bus_reset_handler = megasas_reset_bus_host, @@ -5434,6 > +5479,8 > > @@ static int megasas_io_attach(struct megasas_instance *instance) > > if (instance->ctrl_context) { > > host->hostt->eh_device_reset_handler = NULL; > > host->hostt->eh_bus_reset_handler = NULL; > > + host->hostt->eh_target_reset_handler = > megasas_reset_target_fusion; > > + host->hostt->eh_abort_handler = megasas_task_abort_fusion; > > } > > > > /* > > diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c > > b/drivers/scsi/megaraid/megaraid_sas_fusion.c > > index 1dc4537..0b31f5a 100644 > > --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c > > +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c > > @@ -2100,6 +2100,8 @@ complete_cmd_fusion(struct megasas_instance > *instance, u32 MSIxIndex) > > struct LD_LOAD_BALANCE_INFO *lbinfo; > > int threshold_reply_count = 0; > > struct scsi_cmnd *scmd_local = NULL; > > + struct MR_TASK_MANAGE_REQUEST *mr_tm_req; > > + struct MPI2_SCSI_TASK_MANAGE_REQUEST *mpi_tm_req; > > > > fusion = instance->ctrl_context; > > > > @@ -2141,6 +2143,16 @@ complete_cmd_fusion(struct megasas_instance > *instance, u32 MSIxIndex) > > extStatus = scsi_io_req->RaidContext.exStatus; > > > > switch (scsi_io_req->Function) { > > + case MPI2_FUNCTION_SCSI_TASK_MGMT: > > + mr_tm_req = (struct MR_TASK_MANAGE_REQUEST *) > > + cmd_fusion->io_request; > > + mpi_tm_req = (struct > MPI2_SCSI_TASK_MANAGE_REQUEST *) > > + &mr_tm_req->TmRequest; > > + dev_dbg(&instance->pdev->dev, "TM completion:" > > + "type: 0x%x TaskMID: 0x%x\n", > > + mpi_tm_req->TaskType, mpi_tm_req- > >TaskMID); > > + complete(&cmd_fusion->done); > > + break; > > case MPI2_FUNCTION_SCSI_IO_REQUEST: /*Fast Path IO.*/ > > /* Update load balancing info */ > > device_id = MEGASAS_DEV_INDEX(scmd_local); @@ - > 2727,6 +2739,457 @@ > > void megasas_refire_mgmt_cmd(struct megasas_instance *instance) > > } > > } > > > > +/* > > + * megasas_track_scsiio : Track SCSI IOs outstanding to a SCSI device > > + * @instance: per adapter struct > > + * @channel: the channel assigned by the OS > > + * @id: the id assigned by the OS > > + * > > + * Returns SUCCESS if no IOs pending to SCSI device, else return > > +FAILED */ > > + > > +static int megasas_track_scsiio(struct megasas_instance *instance, > > + int id, int channel) > > +{ > > + int i, found = 0; > > + struct megasas_cmd_fusion *cmd_fusion; > > + struct fusion_context *fusion; > > + fusion = instance->ctrl_context; > > + > > + for (i = 0 ; i < instance->max_scsi_cmds; i++) { > > + cmd_fusion = fusion->cmd_list[i]; > > + if (cmd_fusion->scmd && > > + (cmd_fusion->scmd->device->id == id && > > + cmd_fusion->scmd->device->channel == channel)) { > > + dev_info(&instance->pdev->dev, > > + "SCSI commands pending to target" > > + "channel %d id %d \tSMID: 0x%x\n", > > + channel, id, cmd_fusion->index); > > + scsi_print_command(cmd_fusion->scmd); > > + found = 1; > > + break; > > + } > > + } > > + > > + return found ? FAILED : SUCCESS; > > +} > > + > > +/** > > + * megasas_tm_response_code - translation of device response code > > + * @ioc: per adapter object > > + * @mpi_reply: MPI reply returned by firmware > > + * > > + * Return nothing. > > + */ > > +static void > > +megasas_tm_response_code(struct megasas_instance *instance, > > + struct MPI2_SCSI_TASK_MANAGE_REPLY *mpi_reply) { > > + char *desc; > > + > > + switch (mpi_reply->ResponseCode) { > > + case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE: > > + desc = "task management request completed"; > > + break; > > + case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME: > > + desc = "invalid frame"; > > + break; > > + case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED: > > + desc = "task management request not supported"; > > + break; > > + case MPI2_SCSITASKMGMT_RSP_TM_FAILED: > > + desc = "task management request failed"; > > + break; > > + case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED: > > + desc = "task management request succeeded"; > > + break; > > + case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN: > > + desc = "invalid lun"; > > + break; > > + case 0xA: > > + desc = "overlapped tag attempted"; > > + break; > > + case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC: > > + desc = "task queued, however not sent to target"; > > + break; > > + default: > > + desc = "unknown"; > > + break; > > + } > > + dev_dbg(&instance->pdev->dev, "response_code(%01x): %s\n", > > + mpi_reply->ResponseCode, desc); > > + dev_dbg(&instance->pdev->dev, > > + > "TerminationCount/DevHandle/Function/TaskType/IOCStat/IOCLoginfo > " > > + " 0x%x/0x%x/0x%x/0x%x/0x%x/0x%x\n", > > + mpi_reply->TerminationCount, mpi_reply->DevHandle, > > + mpi_reply->Function, mpi_reply->TaskType, > > + mpi_reply->IOCStatus, mpi_reply->IOCLogInfo); } > > + > > +/** > > + * megasas_issue_tm - main routine for sending tm requests > > + * @instance: per adapter struct > > + * @device_handle: device handle > > + * @channel: the channel assigned by the OS > > + * @id: the id assigned by the OS > > + * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in > > +megaraid_sas_fusion.c) > > + * @smid_task: smid assigned to the task > > + * @m_type: TM_MUTEX_ON or TM_MUTEX_OFF > > + * Context: user > > + * > > + * MegaRaid use MPT interface for Task Magement request. > > + * A generic API for sending task management requests to firmware. > > + * > > + * Return SUCCESS or FAILED. > > + */ > > +static int > > +megasas_issue_tm(struct megasas_instance *instance, u16 device_handle, > > + uint channel, uint id, u16 smid_task, u8 type) { > > + struct MR_TASK_MANAGE_REQUEST *mr_request; > > + struct MPI2_SCSI_TASK_MANAGE_REQUEST *mpi_request; > > + unsigned long timeleft; > > + struct megasas_cmd_fusion *cmd_fusion; > > + struct megasas_cmd *cmd_mfi; > > + union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc; > > + struct fusion_context *fusion; > > + struct megasas_cmd_fusion *scsi_lookup; > > + int rc; > > + struct MPI2_SCSI_TASK_MANAGE_REPLY *mpi_reply; > > + > > + fusion = instance->ctrl_context; > > + > > + cmd_mfi = megasas_get_cmd(instance); > > + > > + if (!cmd_mfi) { > > + dev_err(&instance->pdev->dev, "Failed from %s %d\n", > > + __func__, __LINE__); > > + return -ENOMEM; > > + } > > + > > + cmd_fusion = megasas_get_cmd_fusion(instance, > > + instance->max_scsi_cmds + cmd_mfi->index); > > + > > + /* Save the smid. To be used for returning the cmd */ > > + cmd_mfi->context.smid = cmd_fusion->index; > > + > > + req_desc = megasas_get_request_descriptor(instance, > > + (cmd_fusion->index - 1)); > > + if (!req_desc) { > > + dev_err(&instance->pdev->dev, "Failed from %s %d\n", > > + __func__, __LINE__); > > megasas_return_cmd should be called here? I will handle this and send updated patch. > > > + return -ENOMEM; > > + } > > + > > + cmd_fusion->request_desc = req_desc; > > + req_desc->Words = 0; > > + > > + scsi_lookup = fusion->cmd_list[smid_task - 1]; > > + > > + mr_request = (struct MR_TASK_MANAGE_REQUEST *) cmd_fusion- > >io_request; > > + memset(mr_request, 0, sizeof(struct MR_TASK_MANAGE_REQUEST)); > > + mpi_request = (struct MPI2_SCSI_TASK_MANAGE_REQUEST *) > &mr_request->TmRequest; > > + mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; > > + mpi_request->DevHandle = cpu_to_le16(device_handle); > > + mpi_request->TaskType = type; > > + mpi_request->TaskMID = cpu_to_le16(smid_task); > > + mpi_request->LUN[1] = 0; > > + > > + > > + req_desc = cmd_fusion->request_desc; > > + req_desc->HighPriority.SMID = cpu_to_le16(cmd_fusion->index); > > + req_desc->HighPriority.RequestFlags = > > + (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY << > > + MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); > > + req_desc->HighPriority.MSIxIndex = 0; > > + req_desc->HighPriority.LMID = 0; > > + req_desc->HighPriority.Reserved1 = 0; > > + > > + if (channel < MEGASAS_MAX_PD_CHANNELS) > > + mr_request->tmReqFlags.isTMForPD = 1; > > + else > > + mr_request->tmReqFlags.isTMForLD = 1; > > + > > + init_completion(&cmd_fusion->done); > > + megasas_fire_cmd_fusion(instance, req_desc); > > + > > + timeleft = wait_for_completion_timeout(&cmd_fusion->done, 50 * HZ); > > + > > + if (!timeleft) { > > + dev_err(&instance->pdev->dev, > > + "task mgmt type 0x%x timed out\n", type); > > + mutex_unlock(&instance->reset_mutex); > > + rc = megasas_reset_fusion(instance->host, > MFI_IO_TIMEOUT_OCR); > > + mutex_lock(&instance->reset_mutex); > > megasas_return_cmd should be called here too? Agree, I will fix this. > > > + return rc; > > + } > > + > > + mpi_reply = (struct MPI2_SCSI_TASK_MANAGE_REPLY *) &mr_request- > >TMReply; > > + megasas_tm_response_code(instance, mpi_reply); > > + > > + megasas_return_cmd(instance, cmd_mfi); > > + rc = SUCCESS; > > + switch (type) { > > + case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK: > > + if (scsi_lookup->scmd == NULL) > > + break; > > + else { > > + instance->instancet->disable_intr(instance); > > + msleep(1000); > > + megasas_complete_cmd_dpc_fusion > > + ((unsigned long)instance); > > + instance->instancet->enable_intr(instance); > > + if (scsi_lookup->scmd == NULL) > > + break; > > + } > > + rc = FAILED; > > + break; > > + > > + case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET: > > + if ((channel == 0xFFFFFFFF) && (id == 0xFFFFFFFF)) > > + break; > > + instance->instancet->disable_intr(instance); > > + msleep(1000); > > + megasas_complete_cmd_dpc_fusion > > + ((unsigned long)instance); > > + rc = megasas_track_scsiio(instance, id, channel); > > + instance->instancet->enable_intr(instance); > > + > > + break; > > + case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET: > > + case MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK: > > + break; > > + default: > > + rc = FAILED; > > + break; > > + } > > + > > + return rc; > > + > > +} > > + > > +/* > > + * megasas_fusion_smid_lookup : Look for fusion command > > +correpspodning to SCSI > > + * @instance: per adapter struct > > + * > > + * Return Non Zero index, if SMID found in outstanding commands */ > > +static u16 megasas_fusion_smid_lookup(struct scsi_cmnd *scmd) { > > + int i, ret = 0; > > + struct megasas_instance *instance; > > + struct megasas_cmd_fusion *cmd_fusion; > > + struct fusion_context *fusion; > > + > > + instance = (struct megasas_instance *)scmd->device->host->hostdata; > > + > > + fusion = instance->ctrl_context; > > + > > + for (i = 0; i < instance->max_scsi_cmds; i++) { > > + cmd_fusion = fusion->cmd_list[i]; > > + if (cmd_fusion->scmd && (cmd_fusion->scmd == scmd)) { > > + scmd_printk(KERN_NOTICE, scmd, "Abort request is > for" > > + " SMID: %d\n", cmd_fusion->index); > > + ret = cmd_fusion->index; > > + break; > > + } > > + } > > + > > + return ret; > > +} > > + > > +/* > > +* megasas_get_tm_devhandle - Get devhandle for TM request > > +* @sdev- OS provided scsi device > > +* > > +* Returns- devhandle/targetID of SCSI device > > +*/ > > +static u16 megasas_get_tm_devhandle(struct scsi_device *sdev) { > > + u16 pd_index = 0; > > + u32 device_id; > > + struct megasas_instance *instance; > > + struct fusion_context *fusion; > > + struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync; > > + u16 devhandle = (u16)ULONG_MAX; > > + > > + instance = (struct megasas_instance *)sdev->host->hostdata; > > + fusion = instance->ctrl_context; > > + > > + if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) { > > + if (instance->use_seqnum_jbod_fp) { > > + pd_index = (sdev->channel * > MEGASAS_MAX_DEV_PER_CHANNEL) + > > + sdev->id; > > + pd_sync = (void *)fusion->pd_seq_sync > > + [(instance->pd_seq_map_id - > 1) & 1]; > > + devhandle = pd_sync- > >seq[pd_index].devHandle; > > + } else > > + sdev_printk(KERN_ERR, sdev, "Firmware expose > tmCapable" > > + " without JBOD MAP support from %s %d\n", > __func__, __LINE__); > > + } else { > > + device_id = ((sdev->channel % 2) * > MEGASAS_MAX_DEV_PER_CHANNEL) > > + + sdev->id; > > + devhandle = device_id; > > + } > > + > > + return devhandle; > > +} > > + > > +/* > > + * megasas_task_abort_fusion : SCSI task abort function for fusion > > +adapters > > + * @scmd : pointer to scsi command object > > + * > > + * Return SUCCESS, if command aborted else FAILED */ > > + > > +int megasas_task_abort_fusion(struct scsi_cmnd *scmd) { > > + struct megasas_instance *instance; > > + u16 smid, devhandle; > > + struct fusion_context *fusion; > > + int ret; > > + struct MR_PRIV_DEVICE *mr_device_priv_data; > > + mr_device_priv_data = scmd->device->hostdata; > > + > > + > > + instance = (struct megasas_instance *)scmd->device->host->hostdata; > > + fusion = instance->ctrl_context; > > + > > + if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) { > > + dev_err(&instance->pdev->dev, "Controller is not > OPERATIONAL," > > + "SCSI host:%d\n", instance->host->host_no); > > + ret = FAILED; > > + return ret; > > + } > > + > > + if (!mr_device_priv_data) { > > + sdev_printk(KERN_INFO, scmd->device, "device been deleted! " > > + "scmd(%p)\n", scmd); > > + scmd->result = DID_NO_CONNECT << 16; > > + scmd->scsi_done(scmd); > > Device has been deleted doesn't that imply that all commands had to be before > finished - so you should not call scsi_done ? Agree, I will modify this. > > > + ret = SUCCESS; > > + goto out; > > + } > > + > > + > > + if (!mr_device_priv_data->is_tm_capable) { > > + scmd->result = DID_RESET << 16; > > I think that setting scmd->result makes no sense here (too) a FAILED return > should be enough. Agree.. > > > + ret = FAILED; > > + goto out; > > + } > > + > > + mutex_lock(&instance->reset_mutex); > > + > > + smid = megasas_fusion_smid_lookup(scmd); > > + > > + if (!smid) { > > + scmd->result = DID_RESET << 16; > > I think that setting scmd->result makes no sense here (too) a SUCCESS return > should be enough. Agree.. > > > + ret = SUCCESS; > > + scmd_printk(KERN_NOTICE, scmd, "Command for which abort > is" > > + " issued is not found in oustanding commands\n"); > > + mutex_unlock(&instance->reset_mutex); > > + goto out; > > + } > > + > > + devhandle = megasas_get_tm_devhandle(scmd->device); > > + > > + if (devhandle == (u16)ULONG_MAX) { > > + scmd->result = DID_RESET << 16; > > same here and on other places Hmm..I agree. > > > + ret = SUCCESS; > > + sdev_printk(KERN_INFO, scmd->device, > > + "task abort issued for invalid devhandle\n"); > > + mutex_unlock(&instance->reset_mutex); > > + goto out; > > + } > > + sdev_printk(KERN_INFO, scmd->device, > > + "attempting task abort! scmd(%p) tm_dev_handle 0x%x\n", > > + scmd, devhandle); > > + > > + mr_device_priv_data->tm_busy = 1; > > + ret = megasas_issue_tm(instance, devhandle, > > + scmd->device->channel, scmd->device->id, smid, > > + MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK); > > + mr_device_priv_data->tm_busy = 0; > > + > > + mutex_unlock(&instance->reset_mutex); > > +out: > > + sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n", > > + ((ret == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); > > + > > + return ret; > > +} > > + > > +/* > > + * megasas_reset_target_fusion : target reset function for fusion > > +adapters > > + * scmd: SCSI command pointer > > + * > > + * Returns SUCCESS if all commands associated with target aborted > > +else FAILED */ > > + > > +int megasas_reset_target_fusion(struct scsi_cmnd *scmd) { > > + > > + struct megasas_instance *instance; > > + int ret = FAILED; > > + u16 devhandle; > > + struct fusion_context *fusion; > > + struct MR_PRIV_DEVICE *mr_device_priv_data; > > + mr_device_priv_data = scmd->device->hostdata; > > + > > + instance = (struct megasas_instance *)scmd->device->host->hostdata; > > + fusion = instance->ctrl_context; > > + > > + if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) { > > + dev_err(&instance->pdev->dev, "Controller is not > OPERATIONAL," > > + "SCSI host:%d\n", instance->host->host_no); > > + ret = FAILED; > > + return ret; > > + } > > + > > + if (!mr_device_priv_data) { > > + sdev_printk(KERN_INFO, scmd->device, "device been deleted! " > > + "scmd(%p)\n", scmd); > > + scmd->result = DID_NO_CONNECT << 16; > > + scmd->scsi_done(scmd); > > + ret = SUCCESS; > > + goto out; > > + } > > + > > + > > + if (!mr_device_priv_data->is_tm_capable) { > > + scmd->result = DID_RESET << 16; > > + ret = FAILED; > > + goto out; > > + } > > + > > + mutex_lock(&instance->reset_mutex); > > + devhandle = megasas_get_tm_devhandle(scmd->device); > > + > > + if (devhandle == (u16)ULONG_MAX) { > > + scmd->result = DID_RESET << 16; > > + ret = SUCCESS; > > + sdev_printk(KERN_INFO, scmd->device, > > + "target reset issued for invalid devhandle\n"); > > + mutex_unlock(&instance->reset_mutex); > > + goto out; > > + } > > + > > + sdev_printk(KERN_INFO, scmd->device, > > + "attempting target reset! scmd(%p) tm_dev_handle 0x%x\n", > > + scmd, devhandle); > > + mr_device_priv_data->tm_busy = 1; > > + ret = megasas_issue_tm(instance, devhandle, > > + scmd->device->channel, scmd->device->id, 0, > > + MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET); > > + mr_device_priv_data->tm_busy = 0; > > + mutex_unlock(&instance->reset_mutex); > > +out: > > + scmd_printk(KERN_NOTICE, scmd, "megasas: target reset %s!!\n", > > + (ret == SUCCESS) ? "SUCCESS" : "FAILED"); > > + > > + return ret; > > +} > > + > > /* Check for a second path that is currently UP */ int > > megasas_check_mpio_paths(struct megasas_instance *instance, > > struct scsi_cmnd *scmd) > > @@ -2752,7 +3215,7 @@ out: > > } > > > > /* Core fusion reset function */ > > -int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) > > +int megasas_reset_fusion(struct Scsi_Host *shost, int reason) > > { > > int retval = SUCCESS, i, convert = 0; > > struct megasas_instance *instance; > > @@ -2761,6 +3224,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, > int iotimeout) > > u32 abs_state, status_reg, reset_adapter; > > u32 io_timeout_in_crash_mode = 0; > > struct scsi_cmnd *scmd_local = NULL; > > + struct scsi_device *sdev; > > > > instance = (struct megasas_instance *)shost->hostdata; > > fusion = instance->ctrl_context; > > @@ -2779,8 +3243,8 @@ int megasas_reset_fusion(struct Scsi_Host > > *shost, int iotimeout) > > > > /* IO timeout detected, forcibly put FW in FAULT state */ > > if (abs_state != MFI_STATE_FAULT && instance->crash_dump_buf && > > - instance->crash_dump_app_support && iotimeout) { > > - dev_info(&instance->pdev->dev, "IO timeout is detected, " > > + instance->crash_dump_app_support && reason) { > > + dev_info(&instance->pdev->dev, "IO/DCMD timeout is > detected, " > > "forcibly FAULT Firmware\n"); > > instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT; > > status_reg = readl(&instance->reg_set->doorbell); > > @@ -2819,13 +3283,13 @@ int megasas_reset_fusion(struct Scsi_Host > *shost, int iotimeout) > > msleep(1000); > > > > /* First try waiting for commands to complete */ > > - if (megasas_wait_for_outstanding_fusion(instance, iotimeout, > > + if (megasas_wait_for_outstanding_fusion(instance, reason, > > &convert)) { > > instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT; > > dev_warn(&instance->pdev->dev, "resetting fusion " > > "adapter scsi%d.\n", instance->host->host_no); > > if (convert) > > - iotimeout = 0; > > + reason = 0; > > > > /* Now return commands back to the OS */ > > for (i = 0 ; i < instance->max_scsi_cmds; i++) { @@ -2859,7 > +3323,7 > > @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) > > } > > > > /* Let SR-IOV VF & PF sync up if there was a HB failure */ > > - if (instance->requestorId && !iotimeout) { > > + if (instance->requestorId && !reason) { > > msleep(MEGASAS_OCR_SETTLE_TIME_VF); > > /* Look for a late HB update after VF settle time */ > > if (abs_state == MFI_STATE_OPERATIONAL && @@ - > 2954,6 +3418,9 @@ > > int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) > > > > megasas_setup_jbod_map(instance); > > > > + shost_for_each_device(sdev, shost) > > + megasas_update_sdev_properties(sdev); > > + > > clear_bit(MEGASAS_FUSION_IN_RESET, > > &instance->reset_flags); > > instance->instancet->enable_intr(instance); > > diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h > > b/drivers/scsi/megaraid/megaraid_sas_fusion.h > > index a9e10c4..a1f1c0b 100644 > > --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h > > +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h > > @@ -176,6 +176,7 @@ enum REGION_TYPE { > > #define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD (0x0100) > > #define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP (0x0004) > > #define MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) /* SCSI IO */ > > +#define MPI2_FUNCTION_SCSI_TASK_MGMT (0x01) > > #define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x03) > > #define MPI2_REQ_DESCRIPT_FLAGS_FP_IO (0x06) > > #define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO (0x00) > > @@ -278,6 +279,100 @@ union MPI2_SCSI_IO_CDB_UNION { > > struct MPI2_SGE_SIMPLE_UNION SGE; > > }; > > > > > +/*************************************************************** > ***** > > +******** > > +* SCSI Task Management messages > > > +**************************************************************** > ***** > > +*******/ > > + > > +/*SCSI Task Management Request Message */ struct > > +MPI2_SCSI_TASK_MANAGE_REQUEST { > > + u16 DevHandle; /*0x00 */ > > + u8 ChainOffset; /*0x02 */ > > + u8 Function; /*0x03 */ > > + u8 Reserved1; /*0x04 */ > > + u8 TaskType; /*0x05 */ > > + u8 Reserved2; /*0x06 */ > > + u8 MsgFlags; /*0x07 */ > > + u8 VP_ID; /*0x08 */ > > + u8 VF_ID; /*0x09 */ > > + u16 Reserved3; /*0x0A */ > > + u8 LUN[8]; /*0x0C */ > > + u32 Reserved4[7]; /*0x14 */ > > + u16 TaskMID; /*0x30 */ > > + u16 Reserved5; /*0x32 */ > > +}; > > + > > + > > +/*SCSI Task Management Reply Message */ struct > > +MPI2_SCSI_TASK_MANAGE_REPLY { > > + u16 DevHandle; /*0x00 */ > > + u8 MsgLength; /*0x02 */ > > + u8 Function; /*0x03 */ > > + u8 ResponseCode; /*0x04 */ > > + u8 TaskType; /*0x05 */ > > + u8 Reserved1; /*0x06 */ > > + u8 MsgFlags; /*0x07 */ > > + u8 VP_ID; /*0x08 */ > > + u8 VF_ID; /*0x09 */ > > + u16 Reserved2; /*0x0A */ > > + u16 Reserved3; /*0x0C */ > > + u16 IOCStatus; /*0x0E */ > > + u32 IOCLogInfo; /*0x10 */ > > + u32 TerminationCount; /*0x14 */ > > + u32 ResponseInfo; /*0x18 */ > > +}; > > + > > +struct MR_TM_REQUEST { > > + char request[128]; > > +}; > > + > > +struct MR_TM_REPLY { > > + char reply[128]; > > +}; > > + > > +/* SCSI Task Management Request Message */ struct > > +MR_TASK_MANAGE_REQUEST { > > + /*To be type casted to struct MPI2_SCSI_TASK_MANAGE_REQUEST */ > > + struct MR_TM_REQUEST TmRequest; > > + union { > > + struct { > > +#if defined(__BIG_ENDIAN_BITFIELD) > > + u32 reserved1:30; > > + u32 isTMForPD:1; > > + u32 isTMForLD:1; > > +#else > > + u32 isTMForLD:1; > > + u32 isTMForPD:1; > > + u32 reserved1:30; > > +#endif > > + u32 reserved2; > > + } tmReqFlags; > > + struct MR_TM_REPLY TMReply; > > + }; > > +}; > > + > > +/* TaskType values */ > > + > > +#define MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK (0x01) > > +#define MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET (0x02) > > +#define MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET (0x03) > > +#define MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05) > > +#define MPI2_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06) > > +#define MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK (0x07) > > +#define MPI2_SCSITASKMGMT_TASKTYPE_CLR_ACA (0x08) > > +#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_TASK_SET (0x09) > > +#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT (0x0A) > > + > > +/* ResponseCode values */ > > + > > +#define MPI2_SCSITASKMGMT_RSP_TM_COMPLETE (0x00) > > +#define MPI2_SCSITASKMGMT_RSP_INVALID_FRAME (0x02) > > +#define MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED (0x04) > > +#define MPI2_SCSITASKMGMT_RSP_TM_FAILED (0x05) > > +#define MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED (0x08) > > +#define MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN (0x09) > > +#define MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG (0x0A) > > +#define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC (0x80) > > + > > /* > > * RAID SCSI IO Request Message > > * Total SGE count will be one less than _MPI2_SCSI_IO_REQUEST @@ > > -548,7 +643,8 @@ struct MR_SPAN_BLOCK_INFO { struct MR_LD_RAID { > > struct { > > #if defined(__BIG_ENDIAN_BITFIELD) > > - u32 reserved4:7; > > + u32 reserved4:6; > > + u32 tmCapable:1; > > u32 fpNonRWCapable:1; > > u32 fpReadAcrossStripe:1; > > u32 fpWriteAcrossStripe:1; > > @@ -570,7 +666,8 @@ struct MR_LD_RAID { > > u32 fpWriteAcrossStripe:1; > > u32 fpReadAcrossStripe:1; > > u32 fpNonRWCapable:1; > > - u32 reserved4:7; > > + u32 tmCapable:1; > > + u32 reserved4:6; > > #endif > > } capability; > > __le32 reserved6; > > @@ -695,6 +792,7 @@ struct megasas_cmd_fusion { > > u32 sync_cmd_idx; > > u32 index; > > u8 pd_r1_lb; > > + struct completion done; > > }; > > > > struct LD_LOAD_BALANCE_INFO { > > @@ -808,9 +906,18 @@ struct MR_FW_RAID_MAP_EXT { > > * * define MR_PD_CFG_SEQ structure for system PDs > > * */ > > struct MR_PD_CFG_SEQ { > > - __le16 seqNum; > > - __le16 devHandle; > > - u8 reserved[4]; > > + u16 seqNum; > > + u16 devHandle; > > + struct { > > +#if defined(__BIG_ENDIAN_BITFIELD) > > + u8 reserved:7; > > + u8 tmCapable:1; > > +#else > > + u8 tmCapable:1; > > + u8 reserved:7; > > +#endif > > + } capability; > > + u8 reserved[3]; > > } __packed; > > > > struct MR_PD_CFG_SEQ_NUM_SYNC { -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index dcc6ff8..0fcb156 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -1520,6 +1520,15 @@ union megasas_frame { u8 raw_bytes[64]; }; +/** + * struct MR_PRIV_DEVICE - sdev private hostdata + * @is_tm_capable: firmware managed tm_capable flag + * @tm_busy: TM request is in progress + */ +struct MR_PRIV_DEVICE { + bool is_tm_capable; + bool tm_busy; +}; struct megasas_cmd; union megasas_evt_class_locale { @@ -2073,4 +2082,8 @@ void megasas_return_mfi_mpt_pthr(struct megasas_instance *instance, int megasas_cmd_type(struct scsi_cmnd *cmd); void megasas_setup_jbod_map(struct megasas_instance *instance); +void megasas_update_sdev_properties(struct scsi_device *sdev); +int megasas_reset_fusion(struct Scsi_Host *shost, int reason); +int megasas_task_abort_fusion(struct scsi_cmnd *scmd); +int megasas_reset_target_fusion(struct scsi_cmnd *scmd); #endif /*LSI_MEGARAID_SAS_H */ diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 380c627..c1dc23c 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -189,7 +189,6 @@ int wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd, int seconds); void megasas_reset_reply_desc(struct megasas_instance *instance); -int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout); void megasas_fusion_ocr_wq(struct work_struct *work); static int megasas_get_ld_vf_affiliation(struct megasas_instance *instance, int initial); @@ -1645,6 +1644,7 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd) { struct megasas_instance *instance; unsigned long flags; + struct MR_PRIV_DEVICE *mr_device_priv_data; instance = (struct megasas_instance *) scmd->device->host->hostdata; @@ -1681,11 +1681,24 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd) return 0; } + mr_device_priv_data = scmd->device->hostdata; + if (!mr_device_priv_data) { + spin_unlock_irqrestore(&instance->hba_lock, flags); + scmd->result = DID_NO_CONNECT << 16; + scmd->scsi_done(scmd); + return 0; + } + if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) { spin_unlock_irqrestore(&instance->hba_lock, flags); return SCSI_MLQUEUE_HOST_BUSY; } + if (mr_device_priv_data->tm_busy) { + spin_unlock_irqrestore(&instance->hba_lock, flags); + return SCSI_MLQUEUE_DEVICE_BUSY; + } + spin_unlock_irqrestore(&instance->hba_lock, flags); scmd->result = 0; @@ -1736,27 +1749,39 @@ static struct megasas_instance *megasas_lookup_instance(u16 host_no) } /* -* megasas_set_dma_alignment - Set DMA alignment for PI enabled VD +* megasas_update_sdev_properties - Update sdev structure based on controller's FW capabilities * * @sdev: OS provided scsi device * * Returns void */ -static void megasas_set_dma_alignment(struct scsi_device *sdev) +void megasas_update_sdev_properties(struct scsi_device *sdev) { + u16 pd_index = 0; u32 device_id, ld; struct megasas_instance *instance; struct fusion_context *fusion; + struct MR_PRIV_DEVICE *mr_device_priv_data; + struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync; struct MR_LD_RAID *raid; struct MR_DRV_RAID_MAP_ALL *local_map_ptr; instance = megasas_lookup_instance(sdev->host->host_no); fusion = instance->ctrl_context; + mr_device_priv_data = sdev->hostdata; - if (!fusion) + if (!fusion || !mr_device_priv_data) return; - if (sdev->channel >= MEGASAS_MAX_PD_CHANNELS) { + if (sdev->channel < MEGASAS_MAX_PD_CHANNELS && + instance->use_seqnum_jbod_fp) { + pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + + sdev->id; + pd_sync = (void *)fusion->pd_seq_sync + [(instance->pd_seq_map_id - 1) & 1]; + mr_device_priv_data->is_tm_capable = + pd_sync->seq[pd_index].capability.tmCapable; + } else { device_id = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id; local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)]; @@ -1764,10 +1789,14 @@ static void megasas_set_dma_alignment(struct scsi_device *sdev) raid = MR_LdRaidGet(ld, local_map_ptr); if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER) - blk_queue_update_dma_alignment(sdev->request_queue, 0x7); + blk_queue_update_dma_alignment(sdev->request_queue, 0x7); + + mr_device_priv_data->is_tm_capable = + raid->capability.tmCapable; } } + static int megasas_slave_configure(struct scsi_device *sdev) { u16 pd_index = 0; @@ -1784,7 +1813,8 @@ static int megasas_slave_configure(struct scsi_device *sdev) return -ENXIO; } } - megasas_set_dma_alignment(sdev); + megasas_update_sdev_properties(sdev); + /* * The RAID firmware may require extended timeouts. */ @@ -1798,6 +1828,7 @@ static int megasas_slave_alloc(struct scsi_device *sdev) { u16 pd_index = 0; struct megasas_instance *instance ; + struct MR_PRIV_DEVICE *mr_device_priv_data; instance = megasas_lookup_instance(sdev->host->host_no); if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) { @@ -1809,13 +1840,26 @@ static int megasas_slave_alloc(struct scsi_device *sdev) sdev->id; if ((instance->allow_fw_scan || instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM)) { - return 0; + goto scan_target; } return -ENXIO; } + +scan_target: + mr_device_priv_data = kzalloc(sizeof(*mr_device_priv_data), + GFP_KERNEL); + if (!mr_device_priv_data) + return -ENOMEM; + sdev->hostdata = mr_device_priv_data; return 0; } +static void megasas_slave_destroy(struct scsi_device *sdev) +{ + kfree(sdev->hostdata); + sdev->hostdata = NULL; +} + /* * megasas_complete_outstanding_ioctls - Complete outstanding ioctls after a * kill adapter @@ -2885,6 +2929,7 @@ static struct scsi_host_template megasas_template = { .proc_name = "megaraid_sas", .slave_configure = megasas_slave_configure, .slave_alloc = megasas_slave_alloc, + .slave_destroy = megasas_slave_destroy, .queuecommand = megasas_queue_command, .eh_device_reset_handler = megasas_reset_device, .eh_bus_reset_handler = megasas_reset_bus_host, @@ -5434,6 +5479,8 @@ static int megasas_io_attach(struct megasas_instance *instance) if (instance->ctrl_context) { host->hostt->eh_device_reset_handler = NULL; host->hostt->eh_bus_reset_handler = NULL; + host->hostt->eh_target_reset_handler = megasas_reset_target_fusion; + host->hostt->eh_abort_handler = megasas_task_abort_fusion; } /* diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 1dc4537..0b31f5a 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -2100,6 +2100,8 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) struct LD_LOAD_BALANCE_INFO *lbinfo; int threshold_reply_count = 0; struct scsi_cmnd *scmd_local = NULL; + struct MR_TASK_MANAGE_REQUEST *mr_tm_req; + struct MPI2_SCSI_TASK_MANAGE_REQUEST *mpi_tm_req; fusion = instance->ctrl_context; @@ -2141,6 +2143,16 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) extStatus = scsi_io_req->RaidContext.exStatus; switch (scsi_io_req->Function) { + case MPI2_FUNCTION_SCSI_TASK_MGMT: + mr_tm_req = (struct MR_TASK_MANAGE_REQUEST *) + cmd_fusion->io_request; + mpi_tm_req = (struct MPI2_SCSI_TASK_MANAGE_REQUEST *) + &mr_tm_req->TmRequest; + dev_dbg(&instance->pdev->dev, "TM completion:" + "type: 0x%x TaskMID: 0x%x\n", + mpi_tm_req->TaskType, mpi_tm_req->TaskMID); + complete(&cmd_fusion->done); + break; case MPI2_FUNCTION_SCSI_IO_REQUEST: /*Fast Path IO.*/ /* Update load balancing info */ device_id = MEGASAS_DEV_INDEX(scmd_local); @@ -2727,6 +2739,457 @@ void megasas_refire_mgmt_cmd(struct megasas_instance *instance) } } +/* + * megasas_track_scsiio : Track SCSI IOs outstanding to a SCSI device + * @instance: per adapter struct + * @channel: the channel assigned by the OS + * @id: the id assigned by the OS + * + * Returns SUCCESS if no IOs pending to SCSI device, else return FAILED + */ + +static int megasas_track_scsiio(struct megasas_instance *instance, + int id, int channel) +{ + int i, found = 0; + struct megasas_cmd_fusion *cmd_fusion; + struct fusion_context *fusion; + fusion = instance->ctrl_context; + + for (i = 0 ; i < instance->max_scsi_cmds; i++) { + cmd_fusion = fusion->cmd_list[i]; + if (cmd_fusion->scmd && + (cmd_fusion->scmd->device->id == id && + cmd_fusion->scmd->device->channel == channel)) { + dev_info(&instance->pdev->dev, + "SCSI commands pending to target" + "channel %d id %d \tSMID: 0x%x\n", + channel, id, cmd_fusion->index); + scsi_print_command(cmd_fusion->scmd); + found = 1; + break; + } + } + + return found ? FAILED : SUCCESS; +} + +/** + * megasas_tm_response_code - translation of device response code + * @ioc: per adapter object + * @mpi_reply: MPI reply returned by firmware + * + * Return nothing. + */ +static void +megasas_tm_response_code(struct megasas_instance *instance, + struct MPI2_SCSI_TASK_MANAGE_REPLY *mpi_reply) +{ + char *desc; + + switch (mpi_reply->ResponseCode) { + case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE: + desc = "task management request completed"; + break; + case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME: + desc = "invalid frame"; + break; + case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED: + desc = "task management request not supported"; + break; + case MPI2_SCSITASKMGMT_RSP_TM_FAILED: + desc = "task management request failed"; + break; + case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED: + desc = "task management request succeeded"; + break; + case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN: + desc = "invalid lun"; + break; + case 0xA: + desc = "overlapped tag attempted"; + break; + case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC: + desc = "task queued, however not sent to target"; + break; + default: + desc = "unknown"; + break; + } + dev_dbg(&instance->pdev->dev, "response_code(%01x): %s\n", + mpi_reply->ResponseCode, desc); + dev_dbg(&instance->pdev->dev, + "TerminationCount/DevHandle/Function/TaskType/IOCStat/IOCLoginfo" + " 0x%x/0x%x/0x%x/0x%x/0x%x/0x%x\n", + mpi_reply->TerminationCount, mpi_reply->DevHandle, + mpi_reply->Function, mpi_reply->TaskType, + mpi_reply->IOCStatus, mpi_reply->IOCLogInfo); +} + +/** + * megasas_issue_tm - main routine for sending tm requests + * @instance: per adapter struct + * @device_handle: device handle + * @channel: the channel assigned by the OS + * @id: the id assigned by the OS + * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in megaraid_sas_fusion.c) + * @smid_task: smid assigned to the task + * @m_type: TM_MUTEX_ON or TM_MUTEX_OFF + * Context: user + * + * MegaRaid use MPT interface for Task Magement request. + * A generic API for sending task management requests to firmware. + * + * Return SUCCESS or FAILED. + */ +static int +megasas_issue_tm(struct megasas_instance *instance, u16 device_handle, + uint channel, uint id, u16 smid_task, u8 type) +{ + struct MR_TASK_MANAGE_REQUEST *mr_request; + struct MPI2_SCSI_TASK_MANAGE_REQUEST *mpi_request; + unsigned long timeleft; + struct megasas_cmd_fusion *cmd_fusion; + struct megasas_cmd *cmd_mfi; + union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc; + struct fusion_context *fusion; + struct megasas_cmd_fusion *scsi_lookup; + int rc; + struct MPI2_SCSI_TASK_MANAGE_REPLY *mpi_reply; + + fusion = instance->ctrl_context; + + cmd_mfi = megasas_get_cmd(instance); + + if (!cmd_mfi) { + dev_err(&instance->pdev->dev, "Failed from %s %d\n", + __func__, __LINE__); + return -ENOMEM; + } + + cmd_fusion = megasas_get_cmd_fusion(instance, + instance->max_scsi_cmds + cmd_mfi->index); + + /* Save the smid. To be used for returning the cmd */ + cmd_mfi->context.smid = cmd_fusion->index; + + req_desc = megasas_get_request_descriptor(instance, + (cmd_fusion->index - 1)); + if (!req_desc) { + dev_err(&instance->pdev->dev, "Failed from %s %d\n", + __func__, __LINE__); + return -ENOMEM; + } + + cmd_fusion->request_desc = req_desc; + req_desc->Words = 0; + + scsi_lookup = fusion->cmd_list[smid_task - 1]; + + mr_request = (struct MR_TASK_MANAGE_REQUEST *) cmd_fusion->io_request; + memset(mr_request, 0, sizeof(struct MR_TASK_MANAGE_REQUEST)); + mpi_request = (struct MPI2_SCSI_TASK_MANAGE_REQUEST *) &mr_request->TmRequest; + mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; + mpi_request->DevHandle = cpu_to_le16(device_handle); + mpi_request->TaskType = type; + mpi_request->TaskMID = cpu_to_le16(smid_task); + mpi_request->LUN[1] = 0; + + + req_desc = cmd_fusion->request_desc; + req_desc->HighPriority.SMID = cpu_to_le16(cmd_fusion->index); + req_desc->HighPriority.RequestFlags = + (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY << + MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); + req_desc->HighPriority.MSIxIndex = 0; + req_desc->HighPriority.LMID = 0; + req_desc->HighPriority.Reserved1 = 0; + + if (channel < MEGASAS_MAX_PD_CHANNELS) + mr_request->tmReqFlags.isTMForPD = 1; + else + mr_request->tmReqFlags.isTMForLD = 1; + + init_completion(&cmd_fusion->done); + megasas_fire_cmd_fusion(instance, req_desc); + + timeleft = wait_for_completion_timeout(&cmd_fusion->done, 50 * HZ); + + if (!timeleft) { + dev_err(&instance->pdev->dev, + "task mgmt type 0x%x timed out\n", type); + mutex_unlock(&instance->reset_mutex); + rc = megasas_reset_fusion(instance->host, MFI_IO_TIMEOUT_OCR); + mutex_lock(&instance->reset_mutex); + return rc; + } + + mpi_reply = (struct MPI2_SCSI_TASK_MANAGE_REPLY *) &mr_request->TMReply; + megasas_tm_response_code(instance, mpi_reply); + + megasas_return_cmd(instance, cmd_mfi); + rc = SUCCESS; + switch (type) { + case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK: + if (scsi_lookup->scmd == NULL) + break; + else { + instance->instancet->disable_intr(instance); + msleep(1000); + megasas_complete_cmd_dpc_fusion + ((unsigned long)instance); + instance->instancet->enable_intr(instance); + if (scsi_lookup->scmd == NULL) + break; + } + rc = FAILED; + break; + + case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET: + if ((channel == 0xFFFFFFFF) && (id == 0xFFFFFFFF)) + break; + instance->instancet->disable_intr(instance); + msleep(1000); + megasas_complete_cmd_dpc_fusion + ((unsigned long)instance); + rc = megasas_track_scsiio(instance, id, channel); + instance->instancet->enable_intr(instance); + + break; + case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET: + case MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK: + break; + default: + rc = FAILED; + break; + } + + return rc; + +} + +/* + * megasas_fusion_smid_lookup : Look for fusion command correpspodning to SCSI + * @instance: per adapter struct + * + * Return Non Zero index, if SMID found in outstanding commands + */ +static u16 megasas_fusion_smid_lookup(struct scsi_cmnd *scmd) +{ + int i, ret = 0; + struct megasas_instance *instance; + struct megasas_cmd_fusion *cmd_fusion; + struct fusion_context *fusion; + + instance = (struct megasas_instance *)scmd->device->host->hostdata; + + fusion = instance->ctrl_context; + + for (i = 0; i < instance->max_scsi_cmds; i++) { + cmd_fusion = fusion->cmd_list[i]; + if (cmd_fusion->scmd && (cmd_fusion->scmd == scmd)) { + scmd_printk(KERN_NOTICE, scmd, "Abort request is for" + " SMID: %d\n", cmd_fusion->index); + ret = cmd_fusion->index; + break; + } + } + + return ret; +} + +/* +* megasas_get_tm_devhandle - Get devhandle for TM request +* @sdev- OS provided scsi device +* +* Returns- devhandle/targetID of SCSI device +*/ +static u16 megasas_get_tm_devhandle(struct scsi_device *sdev) +{ + u16 pd_index = 0; + u32 device_id; + struct megasas_instance *instance; + struct fusion_context *fusion; + struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync; + u16 devhandle = (u16)ULONG_MAX; + + instance = (struct megasas_instance *)sdev->host->hostdata; + fusion = instance->ctrl_context; + + if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) { + if (instance->use_seqnum_jbod_fp) { + pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + + sdev->id; + pd_sync = (void *)fusion->pd_seq_sync + [(instance->pd_seq_map_id - 1) & 1]; + devhandle = pd_sync->seq[pd_index].devHandle; + } else + sdev_printk(KERN_ERR, sdev, "Firmware expose tmCapable" + " without JBOD MAP support from %s %d\n", __func__, __LINE__); + } else { + device_id = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) + + sdev->id; + devhandle = device_id; + } + + return devhandle; +} + +/* + * megasas_task_abort_fusion : SCSI task abort function for fusion adapters + * @scmd : pointer to scsi command object + * + * Return SUCCESS, if command aborted else FAILED + */ + +int megasas_task_abort_fusion(struct scsi_cmnd *scmd) +{ + struct megasas_instance *instance; + u16 smid, devhandle; + struct fusion_context *fusion; + int ret; + struct MR_PRIV_DEVICE *mr_device_priv_data; + mr_device_priv_data = scmd->device->hostdata; + + + instance = (struct megasas_instance *)scmd->device->host->hostdata; + fusion = instance->ctrl_context; + + if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) { + dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL," + "SCSI host:%d\n", instance->host->host_no); + ret = FAILED; + return ret; + } + + if (!mr_device_priv_data) { + sdev_printk(KERN_INFO, scmd->device, "device been deleted! " + "scmd(%p)\n", scmd); + scmd->result = DID_NO_CONNECT << 16; + scmd->scsi_done(scmd); + ret = SUCCESS; + goto out; + } + + + if (!mr_device_priv_data->is_tm_capable) { + scmd->result = DID_RESET << 16; + ret = FAILED; + goto out; + } + + mutex_lock(&instance->reset_mutex); + + smid = megasas_fusion_smid_lookup(scmd); + + if (!smid) { + scmd->result = DID_RESET << 16; + ret = SUCCESS; + scmd_printk(KERN_NOTICE, scmd, "Command for which abort is" + " issued is not found in oustanding commands\n"); + mutex_unlock(&instance->reset_mutex); + goto out; + } + + devhandle = megasas_get_tm_devhandle(scmd->device); + + if (devhandle == (u16)ULONG_MAX) { + scmd->result = DID_RESET << 16; + ret = SUCCESS; + sdev_printk(KERN_INFO, scmd->device, + "task abort issued for invalid devhandle\n"); + mutex_unlock(&instance->reset_mutex); + goto out; + } + sdev_printk(KERN_INFO, scmd->device, + "attempting task abort! scmd(%p) tm_dev_handle 0x%x\n", + scmd, devhandle); + + mr_device_priv_data->tm_busy = 1; + ret = megasas_issue_tm(instance, devhandle, + scmd->device->channel, scmd->device->id, smid, + MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK); + mr_device_priv_data->tm_busy = 0; + + mutex_unlock(&instance->reset_mutex); +out: + sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n", + ((ret == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); + + return ret; +} + +/* + * megasas_reset_target_fusion : target reset function for fusion adapters + * scmd: SCSI command pointer + * + * Returns SUCCESS if all commands associated with target aborted else FAILED + */ + +int megasas_reset_target_fusion(struct scsi_cmnd *scmd) +{ + + struct megasas_instance *instance; + int ret = FAILED; + u16 devhandle; + struct fusion_context *fusion; + struct MR_PRIV_DEVICE *mr_device_priv_data; + mr_device_priv_data = scmd->device->hostdata; + + instance = (struct megasas_instance *)scmd->device->host->hostdata; + fusion = instance->ctrl_context; + + if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) { + dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL," + "SCSI host:%d\n", instance->host->host_no); + ret = FAILED; + return ret; + } + + if (!mr_device_priv_data) { + sdev_printk(KERN_INFO, scmd->device, "device been deleted! " + "scmd(%p)\n", scmd); + scmd->result = DID_NO_CONNECT << 16; + scmd->scsi_done(scmd); + ret = SUCCESS; + goto out; + } + + + if (!mr_device_priv_data->is_tm_capable) { + scmd->result = DID_RESET << 16; + ret = FAILED; + goto out; + } + + mutex_lock(&instance->reset_mutex); + devhandle = megasas_get_tm_devhandle(scmd->device); + + if (devhandle == (u16)ULONG_MAX) { + scmd->result = DID_RESET << 16; + ret = SUCCESS; + sdev_printk(KERN_INFO, scmd->device, + "target reset issued for invalid devhandle\n"); + mutex_unlock(&instance->reset_mutex); + goto out; + } + + sdev_printk(KERN_INFO, scmd->device, + "attempting target reset! scmd(%p) tm_dev_handle 0x%x\n", + scmd, devhandle); + mr_device_priv_data->tm_busy = 1; + ret = megasas_issue_tm(instance, devhandle, + scmd->device->channel, scmd->device->id, 0, + MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET); + mr_device_priv_data->tm_busy = 0; + mutex_unlock(&instance->reset_mutex); +out: + scmd_printk(KERN_NOTICE, scmd, "megasas: target reset %s!!\n", + (ret == SUCCESS) ? "SUCCESS" : "FAILED"); + + return ret; +} + /* Check for a second path that is currently UP */ int megasas_check_mpio_paths(struct megasas_instance *instance, struct scsi_cmnd *scmd) @@ -2752,7 +3215,7 @@ out: } /* Core fusion reset function */ -int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) +int megasas_reset_fusion(struct Scsi_Host *shost, int reason) { int retval = SUCCESS, i, convert = 0; struct megasas_instance *instance; @@ -2761,6 +3224,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) u32 abs_state, status_reg, reset_adapter; u32 io_timeout_in_crash_mode = 0; struct scsi_cmnd *scmd_local = NULL; + struct scsi_device *sdev; instance = (struct megasas_instance *)shost->hostdata; fusion = instance->ctrl_context; @@ -2779,8 +3243,8 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) /* IO timeout detected, forcibly put FW in FAULT state */ if (abs_state != MFI_STATE_FAULT && instance->crash_dump_buf && - instance->crash_dump_app_support && iotimeout) { - dev_info(&instance->pdev->dev, "IO timeout is detected, " + instance->crash_dump_app_support && reason) { + dev_info(&instance->pdev->dev, "IO/DCMD timeout is detected, " "forcibly FAULT Firmware\n"); instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT; status_reg = readl(&instance->reg_set->doorbell); @@ -2819,13 +3283,13 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) msleep(1000); /* First try waiting for commands to complete */ - if (megasas_wait_for_outstanding_fusion(instance, iotimeout, + if (megasas_wait_for_outstanding_fusion(instance, reason, &convert)) { instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT; dev_warn(&instance->pdev->dev, "resetting fusion " "adapter scsi%d.\n", instance->host->host_no); if (convert) - iotimeout = 0; + reason = 0; /* Now return commands back to the OS */ for (i = 0 ; i < instance->max_scsi_cmds; i++) { @@ -2859,7 +3323,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) } /* Let SR-IOV VF & PF sync up if there was a HB failure */ - if (instance->requestorId && !iotimeout) { + if (instance->requestorId && !reason) { msleep(MEGASAS_OCR_SETTLE_TIME_VF); /* Look for a late HB update after VF settle time */ if (abs_state == MFI_STATE_OPERATIONAL && @@ -2954,6 +3418,9 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) megasas_setup_jbod_map(instance); + shost_for_each_device(sdev, shost) + megasas_update_sdev_properties(sdev); + clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags); instance->instancet->enable_intr(instance); diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h index a9e10c4..a1f1c0b 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -176,6 +176,7 @@ enum REGION_TYPE { #define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD (0x0100) #define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP (0x0004) #define MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) /* SCSI IO */ +#define MPI2_FUNCTION_SCSI_TASK_MGMT (0x01) #define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x03) #define MPI2_REQ_DESCRIPT_FLAGS_FP_IO (0x06) #define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO (0x00) @@ -278,6 +279,100 @@ union MPI2_SCSI_IO_CDB_UNION { struct MPI2_SGE_SIMPLE_UNION SGE; }; +/**************************************************************************** +* SCSI Task Management messages +****************************************************************************/ + +/*SCSI Task Management Request Message */ +struct MPI2_SCSI_TASK_MANAGE_REQUEST { + u16 DevHandle; /*0x00 */ + u8 ChainOffset; /*0x02 */ + u8 Function; /*0x03 */ + u8 Reserved1; /*0x04 */ + u8 TaskType; /*0x05 */ + u8 Reserved2; /*0x06 */ + u8 MsgFlags; /*0x07 */ + u8 VP_ID; /*0x08 */ + u8 VF_ID; /*0x09 */ + u16 Reserved3; /*0x0A */ + u8 LUN[8]; /*0x0C */ + u32 Reserved4[7]; /*0x14 */ + u16 TaskMID; /*0x30 */ + u16 Reserved5; /*0x32 */ +}; + + +/*SCSI Task Management Reply Message */ +struct MPI2_SCSI_TASK_MANAGE_REPLY { + u16 DevHandle; /*0x00 */ + u8 MsgLength; /*0x02 */ + u8 Function; /*0x03 */ + u8 ResponseCode; /*0x04 */ + u8 TaskType; /*0x05 */ + u8 Reserved1; /*0x06 */ + u8 MsgFlags; /*0x07 */ + u8 VP_ID; /*0x08 */ + u8 VF_ID; /*0x09 */ + u16 Reserved2; /*0x0A */ + u16 Reserved3; /*0x0C */ + u16 IOCStatus; /*0x0E */ + u32 IOCLogInfo; /*0x10 */ + u32 TerminationCount; /*0x14 */ + u32 ResponseInfo; /*0x18 */ +}; + +struct MR_TM_REQUEST { + char request[128]; +}; + +struct MR_TM_REPLY { + char reply[128]; +}; + +/* SCSI Task Management Request Message */ +struct MR_TASK_MANAGE_REQUEST { + /*To be type casted to struct MPI2_SCSI_TASK_MANAGE_REQUEST */ + struct MR_TM_REQUEST TmRequest; + union { + struct { +#if defined(__BIG_ENDIAN_BITFIELD) + u32 reserved1:30; + u32 isTMForPD:1; + u32 isTMForLD:1; +#else + u32 isTMForLD:1; + u32 isTMForPD:1; + u32 reserved1:30; +#endif + u32 reserved2; + } tmReqFlags; + struct MR_TM_REPLY TMReply; + }; +}; + +/* TaskType values */ + +#define MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK (0x01) +#define MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET (0x02) +#define MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET (0x03) +#define MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05) +#define MPI2_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06) +#define MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK (0x07) +#define MPI2_SCSITASKMGMT_TASKTYPE_CLR_ACA (0x08) +#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_TASK_SET (0x09) +#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT (0x0A) + +/* ResponseCode values */ + +#define MPI2_SCSITASKMGMT_RSP_TM_COMPLETE (0x00) +#define MPI2_SCSITASKMGMT_RSP_INVALID_FRAME (0x02) +#define MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED (0x04) +#define MPI2_SCSITASKMGMT_RSP_TM_FAILED (0x05) +#define MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED (0x08) +#define MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN (0x09) +#define MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG (0x0A) +#define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC (0x80) + /* * RAID SCSI IO Request Message * Total SGE count will be one less than _MPI2_SCSI_IO_REQUEST @@ -548,7 +643,8 @@ struct MR_SPAN_BLOCK_INFO { struct MR_LD_RAID { struct { #if defined(__BIG_ENDIAN_BITFIELD) - u32 reserved4:7; + u32 reserved4:6; + u32 tmCapable:1; u32 fpNonRWCapable:1; u32 fpReadAcrossStripe:1; u32 fpWriteAcrossStripe:1; @@ -570,7 +666,8 @@ struct MR_LD_RAID { u32 fpWriteAcrossStripe:1; u32 fpReadAcrossStripe:1; u32 fpNonRWCapable:1; - u32 reserved4:7; + u32 tmCapable:1; + u32 reserved4:6; #endif } capability; __le32 reserved6; @@ -695,6 +792,7 @@ struct megasas_cmd_fusion { u32 sync_cmd_idx; u32 index; u8 pd_r1_lb; + struct completion done; }; struct LD_LOAD_BALANCE_INFO { @@ -808,9 +906,18 @@ struct MR_FW_RAID_MAP_EXT { * * define MR_PD_CFG_SEQ structure for system PDs * */ struct MR_PD_CFG_SEQ { - __le16 seqNum; - __le16 devHandle; - u8 reserved[4]; + u16 seqNum; + u16 devHandle; + struct { +#if defined(__BIG_ENDIAN_BITFIELD) + u8 reserved:7; + u8 tmCapable:1; +#else + u8 tmCapable:1; + u8 reserved:7; +#endif + } capability; + u8 reserved[3]; } __packed; struct MR_PD_CFG_SEQ_NUM_SYNC {