Skip to content

Commit a91603a

Browse files
sreekanthbrcmmartinkpetersen
authored andcommitted
scsi: mpi3mr: Enhanced Task Management Support Reply handling
Enhance driver to consider MPI3_IOCSTATUS_SCSI_IOC_TERMINATED as a success for TMs issued by it and check the pending I/Os to decide the success or failure of the task management requests instead of just considering the MPI3_IOCSTATUS_SCSI_IOC_TERMINATED as a failure of the task management request. Link: https://lore.kernel.org/r/20211220141159.16117-24-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
1 parent c866513 commit a91603a

2 files changed

Lines changed: 185 additions & 38 deletions

File tree

drivers/scsi/mpi3mr/mpi3mr.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,8 @@ static inline void mpi3mr_tgtdev_put(struct mpi3mr_tgt_dev *s)
497497
* @dev_removedelay: Device is waiting to be removed in FW
498498
* @dev_type: Device type
499499
* @tgt_dev: Internal target device pointer
500+
* @pend_count: Counter to track pending I/Os during error
501+
* handling
500502
*/
501503
struct mpi3mr_stgt_priv_data {
502504
struct scsi_target *starget;
@@ -508,6 +510,7 @@ struct mpi3mr_stgt_priv_data {
508510
u8 dev_removedelay;
509511
u8 dev_type;
510512
struct mpi3mr_tgt_dev *tgt_dev;
513+
u32 pend_count;
511514
};
512515

513516
/**
@@ -516,11 +519,14 @@ struct mpi3mr_stgt_priv_data {
516519
* @tgt_priv_data: Scsi_target private data pointer
517520
* @lun_id: LUN ID of the device
518521
* @ncq_prio_enable: NCQ priority enable for SATA device
522+
* @pend_count: Counter to track pending I/Os during error
523+
* handling
519524
*/
520525
struct mpi3mr_sdev_priv_data {
521526
struct mpi3mr_stgt_priv_data *tgt_priv_data;
522527
u32 lun_id;
523528
u8 ncq_prio_enable;
529+
u32 pend_count;
524530
};
525531

526532
/**

drivers/scsi/mpi3mr/mpi3mr_os.c

Lines changed: 179 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,74 @@ static bool mpi3mr_flush_scmd(struct request *rq,
420420
return(true);
421421
}
422422

423+
/**
424+
* mpi3mr_count_dev_pending - Count commands pending for a lun
425+
* @rq: Block request
426+
* @data: SCSI device reference
427+
* @reserved: Unused
428+
*
429+
* This is an iterator function called for each SCSI command in
430+
* a host and if the command is pending in the LLD for the
431+
* specific device(lun) then device specific pending I/O counter
432+
* is updated in the device structure.
433+
*
434+
* Return: true always.
435+
*/
436+
437+
static bool mpi3mr_count_dev_pending(struct request *rq,
438+
void *data, bool reserved)
439+
{
440+
struct scsi_device *sdev = (struct scsi_device *)data;
441+
struct mpi3mr_sdev_priv_data *sdev_priv_data = sdev->hostdata;
442+
struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq);
443+
struct scmd_priv *priv;
444+
445+
if (scmd) {
446+
priv = scsi_cmd_priv(scmd);
447+
if (!priv->in_lld_scope)
448+
goto out;
449+
if (scmd->device == sdev)
450+
sdev_priv_data->pend_count++;
451+
}
452+
453+
out:
454+
return true;
455+
}
456+
457+
/**
458+
* mpi3mr_count_tgt_pending - Count commands pending for target
459+
* @rq: Block request
460+
* @data: SCSI target reference
461+
* @reserved: Unused
462+
*
463+
* This is an iterator function called for each SCSI command in
464+
* a host and if the command is pending in the LLD for the
465+
* specific target then target specific pending I/O counter is
466+
* updated in the target structure.
467+
*
468+
* Return: true always.
469+
*/
470+
471+
static bool mpi3mr_count_tgt_pending(struct request *rq,
472+
void *data, bool reserved)
473+
{
474+
struct scsi_target *starget = (struct scsi_target *)data;
475+
struct mpi3mr_stgt_priv_data *stgt_priv_data = starget->hostdata;
476+
struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq);
477+
struct scmd_priv *priv;
478+
479+
if (scmd) {
480+
priv = scsi_cmd_priv(scmd);
481+
if (!priv->in_lld_scope)
482+
goto out;
483+
if (scmd->device && (scsi_target(scmd->device) == starget))
484+
stgt_priv_data->pend_count++;
485+
}
486+
487+
out:
488+
return true;
489+
}
490+
423491
/**
424492
* mpi3mr_flush_host_io - Flush host I/Os
425493
* @mrioc: Adapter instance reference
@@ -2847,16 +2915,28 @@ static const char *mpi3mr_tm_response_name(u8 resp_code)
28472915
return desc;
28482916
}
28492917

2918+
inline void mpi3mr_poll_pend_io_completions(struct mpi3mr_ioc *mrioc)
2919+
{
2920+
int i;
2921+
int num_of_reply_queues =
2922+
mrioc->num_op_reply_q + mrioc->op_reply_q_offset;
2923+
2924+
for (i = mrioc->op_reply_q_offset; i < num_of_reply_queues; i++)
2925+
mpi3mr_process_op_reply_q(mrioc,
2926+
mrioc->intr_info[i].op_reply_q);
2927+
}
2928+
28502929
/**
28512930
* mpi3mr_issue_tm - Issue Task Management request
28522931
* @mrioc: Adapter instance reference
28532932
* @tm_type: Task Management type
28542933
* @handle: Device handle
28552934
* @lun: lun ID
28562935
* @htag: Host tag of the TM request
2936+
* @timeout: TM timeout value
28572937
* @drv_cmd: Internal command tracker
28582938
* @resp_code: Response code place holder
2859-
* @cmd_priv: SCSI command private data
2939+
* @scmd: SCSI command
28602940
*
28612941
* Issues a Task Management Request to the controller for a
28622942
* specified target, lun and command and wait for its completion
@@ -2868,14 +2948,16 @@ static const char *mpi3mr_tm_response_name(u8 resp_code)
28682948
static int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type,
28692949
u16 handle, uint lun, u16 htag, ulong timeout,
28702950
struct mpi3mr_drv_cmd *drv_cmd,
2871-
u8 *resp_code, struct scmd_priv *cmd_priv)
2951+
u8 *resp_code, struct scsi_cmnd *scmd)
28722952
{
28732953
struct mpi3_scsi_task_mgmt_request tm_req;
28742954
struct mpi3_scsi_task_mgmt_reply *tm_reply = NULL;
28752955
int retval = 0;
28762956
struct mpi3mr_tgt_dev *tgtdev = NULL;
28772957
struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data = NULL;
2878-
struct op_req_qinfo *op_req_q = NULL;
2958+
struct scmd_priv *cmd_priv = NULL;
2959+
struct scsi_device *sdev = NULL;
2960+
struct mpi3mr_sdev_priv_data *sdev_priv_data = NULL;
28792961

28802962
ioc_info(mrioc, "%s :Issue TM: TM type (0x%x) for devhandle 0x%04x\n",
28812963
__func__, tm_type, handle);
@@ -2912,16 +2994,21 @@ static int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type,
29122994
tm_req.function = MPI3_FUNCTION_SCSI_TASK_MGMT;
29132995

29142996
tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, handle);
2915-
if (tgtdev && tgtdev->starget && tgtdev->starget->hostdata) {
2916-
scsi_tgt_priv_data = (struct mpi3mr_stgt_priv_data *)
2917-
tgtdev->starget->hostdata;
2918-
atomic_inc(&scsi_tgt_priv_data->block_io);
2919-
}
2920-
if (cmd_priv) {
2921-
op_req_q = &mrioc->req_qinfo[cmd_priv->req_q_idx];
2922-
tm_req.task_host_tag = cpu_to_le16(cmd_priv->host_tag);
2923-
tm_req.task_request_queue_id = cpu_to_le16(op_req_q->qid);
2997+
2998+
if (scmd) {
2999+
sdev = scmd->device;
3000+
sdev_priv_data = sdev->hostdata;
3001+
scsi_tgt_priv_data = ((sdev_priv_data) ?
3002+
sdev_priv_data->tgt_priv_data : NULL);
3003+
} else {
3004+
if (tgtdev && tgtdev->starget && tgtdev->starget->hostdata)
3005+
scsi_tgt_priv_data = (struct mpi3mr_stgt_priv_data *)
3006+
tgtdev->starget->hostdata;
29243007
}
3008+
3009+
if (scsi_tgt_priv_data)
3010+
atomic_inc(&scsi_tgt_priv_data->block_io);
3011+
29253012
if (tgtdev && (tgtdev->dev_type == MPI3_DEVICE_DEVFORM_PCIE)) {
29263013
if (cmd_priv && tgtdev->dev_spec.pcie_inf.abort_to)
29273014
timeout = tgtdev->dev_spec.pcie_inf.abort_to;
@@ -2938,35 +3025,44 @@ static int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type,
29383025
wait_for_completion_timeout(&drv_cmd->done, (timeout * HZ));
29393026

29403027
if (!(drv_cmd->state & MPI3MR_CMD_COMPLETE)) {
2941-
ioc_err(mrioc, "%s :Issue TM: command timed out\n", __func__);
29423028
drv_cmd->is_waiting = 0;
29433029
retval = -1;
2944-
if (!(drv_cmd->state & MPI3MR_CMD_RESET))
3030+
if (!(drv_cmd->state & MPI3MR_CMD_RESET)) {
3031+
dprint_tm(mrioc,
3032+
"task management request timed out after %ld seconds\n",
3033+
timeout);
3034+
if (mrioc->logging_level & MPI3_DEBUG_TM)
3035+
dprint_dump_req(&tm_req, sizeof(tm_req)/4);
29453036
mpi3mr_soft_reset_handler(mrioc,
29463037
MPI3MR_RESET_FROM_TM_TIMEOUT, 1);
3038+
}
29473039
goto out_unlock;
29483040
}
29493041

2950-
if (drv_cmd->state & MPI3MR_CMD_REPLY_VALID)
2951-
tm_reply = (struct mpi3_scsi_task_mgmt_reply *)drv_cmd->reply;
2952-
2953-
if (drv_cmd->ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2954-
ioc_err(mrioc,
2955-
"%s :Issue TM: handle(0x%04x) Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
2956-
__func__, handle, drv_cmd->ioc_status,
2957-
drv_cmd->ioc_loginfo);
3042+
if (!(drv_cmd->state & MPI3MR_CMD_REPLY_VALID)) {
3043+
dprint_tm(mrioc, "invalid task management reply message\n");
29583044
retval = -1;
29593045
goto out_unlock;
29603046
}
29613047

2962-
if (!tm_reply) {
2963-
ioc_err(mrioc, "%s :Issue TM: No TM Reply message\n", __func__);
3048+
tm_reply = (struct mpi3_scsi_task_mgmt_reply *)drv_cmd->reply;
3049+
3050+
switch (drv_cmd->ioc_status) {
3051+
case MPI3_IOCSTATUS_SUCCESS:
3052+
*resp_code = le32_to_cpu(tm_reply->response_data) &
3053+
MPI3MR_RI_MASK_RESPCODE;
3054+
break;
3055+
case MPI3_IOCSTATUS_SCSI_IOC_TERMINATED:
3056+
*resp_code = MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE;
3057+
break;
3058+
default:
3059+
dprint_tm(mrioc,
3060+
"task management request to handle(0x%04x) is failed with ioc_status(0x%04x) log_info(0x%08x)\n",
3061+
handle, drv_cmd->ioc_status, drv_cmd->ioc_loginfo);
29643062
retval = -1;
29653063
goto out_unlock;
29663064
}
29673065

2968-
*resp_code = le32_to_cpu(tm_reply->response_data) &
2969-
MPI3MR_RI_MASK_RESPCODE;
29703066
switch (*resp_code) {
29713067
case MPI3_SCSITASKMGMT_RSPCODE_TM_SUCCEEDED:
29723068
case MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE:
@@ -2986,21 +3082,39 @@ static int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type,
29863082
le32_to_cpu(tm_reply->termination_count),
29873083
mpi3mr_tm_response_name(*resp_code), *resp_code);
29883084

3085+
if (!retval) {
3086+
mpi3mr_ioc_disable_intr(mrioc);
3087+
mpi3mr_poll_pend_io_completions(mrioc);
3088+
mpi3mr_ioc_enable_intr(mrioc);
3089+
mpi3mr_poll_pend_io_completions(mrioc);
3090+
}
3091+
switch (tm_type) {
3092+
case MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
3093+
if (!scsi_tgt_priv_data)
3094+
break;
3095+
scsi_tgt_priv_data->pend_count = 0;
3096+
blk_mq_tagset_busy_iter(&mrioc->shost->tag_set,
3097+
mpi3mr_count_tgt_pending,
3098+
(void *)scsi_tgt_priv_data->starget);
3099+
break;
3100+
case MPI3_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET:
3101+
if (!sdev_priv_data)
3102+
break;
3103+
sdev_priv_data->pend_count = 0;
3104+
blk_mq_tagset_busy_iter(&mrioc->shost->tag_set,
3105+
mpi3mr_count_dev_pending, (void *)sdev);
3106+
break;
3107+
default:
3108+
break;
3109+
}
3110+
29893111
out_unlock:
29903112
drv_cmd->state = MPI3MR_CMD_NOTUSED;
29913113
mutex_unlock(&drv_cmd->mutex);
29923114
if (scsi_tgt_priv_data)
29933115
atomic_dec_if_positive(&scsi_tgt_priv_data->block_io);
29943116
if (tgtdev)
29953117
mpi3mr_tgtdev_put(tgtdev);
2996-
if (!retval) {
2997-
/*
2998-
* Flush all IRQ handlers by calling synchronize_irq().
2999-
* mpi3mr_ioc_disable_intr() takes care of it.
3000-
*/
3001-
mpi3mr_ioc_disable_intr(mrioc);
3002-
mpi3mr_ioc_enable_intr(mrioc);
3003-
}
30043118
out:
30053119
return retval;
30063120
}
@@ -3250,22 +3364,36 @@ static int mpi3mr_eh_target_reset(struct scsi_cmnd *scmd)
32503364

32513365
stgt_priv_data = sdev_priv_data->tgt_priv_data;
32523366
dev_handle = stgt_priv_data->dev_handle;
3367+
if (stgt_priv_data->dev_removed) {
3368+
sdev_printk(KERN_INFO, scmd->device,
3369+
"%s:target(handle = 0x%04x) is removed, target reset is not issued\n",
3370+
mrioc->name, dev_handle);
3371+
retval = FAILED;
3372+
goto out;
3373+
}
32533374
sdev_printk(KERN_INFO, scmd->device,
32543375
"Target Reset is issued to handle(0x%04x)\n",
32553376
dev_handle);
32563377

32573378
ret = mpi3mr_issue_tm(mrioc,
32583379
MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET, dev_handle,
32593380
sdev_priv_data->lun_id, MPI3MR_HOSTTAG_BLK_TMS,
3260-
MPI3MR_RESETTM_TIMEOUT, &mrioc->host_tm_cmds, &resp_code, NULL);
3381+
MPI3MR_RESETTM_TIMEOUT, &mrioc->host_tm_cmds, &resp_code, scmd);
32613382

32623383
if (ret)
32633384
goto out;
32643385

3386+
if (stgt_priv_data->pend_count) {
3387+
sdev_printk(KERN_INFO, scmd->device,
3388+
"%s: target has %d pending commands, target reset is failed\n",
3389+
mrioc->name, sdev_priv_data->pend_count);
3390+
goto out;
3391+
}
3392+
32653393
retval = SUCCESS;
32663394
out:
32673395
sdev_printk(KERN_INFO, scmd->device,
3268-
"Target reset is %s for scmd(%p)\n",
3396+
"%s: target reset is %s for scmd(%p)\n", mrioc->name,
32693397
((retval == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
32703398

32713399
return retval;
@@ -3304,21 +3432,34 @@ static int mpi3mr_eh_dev_reset(struct scsi_cmnd *scmd)
33043432

33053433
stgt_priv_data = sdev_priv_data->tgt_priv_data;
33063434
dev_handle = stgt_priv_data->dev_handle;
3435+
if (stgt_priv_data->dev_removed) {
3436+
sdev_printk(KERN_INFO, scmd->device,
3437+
"%s: device(handle = 0x%04x) is removed, device(LUN) reset is not issued\n",
3438+
mrioc->name, dev_handle);
3439+
retval = FAILED;
3440+
goto out;
3441+
}
33073442
sdev_printk(KERN_INFO, scmd->device,
33083443
"Device(lun) Reset is issued to handle(0x%04x)\n", dev_handle);
33093444

33103445
ret = mpi3mr_issue_tm(mrioc,
33113446
MPI3_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, dev_handle,
33123447
sdev_priv_data->lun_id, MPI3MR_HOSTTAG_BLK_TMS,
3313-
MPI3MR_RESETTM_TIMEOUT, &mrioc->host_tm_cmds, &resp_code, NULL);
3448+
MPI3MR_RESETTM_TIMEOUT, &mrioc->host_tm_cmds, &resp_code, scmd);
33143449

33153450
if (ret)
33163451
goto out;
33173452

3453+
if (sdev_priv_data->pend_count) {
3454+
sdev_printk(KERN_INFO, scmd->device,
3455+
"%s: device has %d pending commands, device(LUN) reset is failed\n",
3456+
mrioc->name, sdev_priv_data->pend_count);
3457+
goto out;
3458+
}
33183459
retval = SUCCESS;
33193460
out:
33203461
sdev_printk(KERN_INFO, scmd->device,
3321-
"Device(lun) reset is %s for scmd(%p)\n",
3462+
"%s: device(LUN) reset is %s for scmd(%p)\n", mrioc->name,
33223463
((retval == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
33233464

33243465
return retval;

0 commit comments

Comments
 (0)