Re: [PATCH 04/15] megaraid_sas: Task management support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxxxx>
> Signed-off-by: Kashyap Desai <kashyap.desai@xxxxxxxxxxxxx>
> ---
>  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@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux