diff options
author | James Smart <james.smart@emulex.com> | 2013-10-10 12:24:07 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2013-10-25 04:58:18 -0400 |
commit | 53151bbb83f11b358ac94eddd81347c581dc51ea (patch) | |
tree | ffce8c5717d448789f1be3ac78c261b6d2d5a681 /drivers/scsi/lpfc | |
parent | 725dd399ae69d0703c0417f9ce0ce065d2a914d1 (diff) |
[SCSI] lpfc 8.3.43: Fixed not processing task management IOCB response status
This patch implements the changes requested by Jeremy Linton:
http://marc.info/?l=linux-scsi&m=136242124409687&w=2
The patch revises the command issuing behavior, detecting cases where the
Task Mgmt command may have completed but with a non-successful status, which it
previously treated as a successful TMF. The patch also corrects a flushing of
I/O that was done which should only be done on successful TMF completion.
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/lpfc')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_bsg.c | 7 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 112 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.h | 1 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 5 |
4 files changed, 104 insertions, 21 deletions
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index b92aec989d60..82134d20e2d8 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c | |||
@@ -2629,7 +2629,7 @@ static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi, | |||
2629 | rspiocbq, | 2629 | rspiocbq, |
2630 | (phba->fc_ratov * 2) | 2630 | (phba->fc_ratov * 2) |
2631 | + LPFC_DRVR_TIMEOUT); | 2631 | + LPFC_DRVR_TIMEOUT); |
2632 | if (iocb_stat) { | 2632 | if ((iocb_stat != IOCB_SUCCESS) || (rsp->ulpStatus != IOSTAT_SUCCESS)) { |
2633 | ret_val = -EIO; | 2633 | ret_val = -EIO; |
2634 | goto err_get_xri_exit; | 2634 | goto err_get_xri_exit; |
2635 | } | 2635 | } |
@@ -3204,8 +3204,9 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job) | |||
3204 | rspiocbq, (phba->fc_ratov * 2) + | 3204 | rspiocbq, (phba->fc_ratov * 2) + |
3205 | LPFC_DRVR_TIMEOUT); | 3205 | LPFC_DRVR_TIMEOUT); |
3206 | 3206 | ||
3207 | if ((iocb_stat != IOCB_SUCCESS) || ((phba->sli_rev < LPFC_SLI_REV4) && | 3207 | if ((iocb_stat != IOCB_SUCCESS) || |
3208 | (rsp->ulpStatus != IOCB_SUCCESS))) { | 3208 | ((phba->sli_rev < LPFC_SLI_REV4) && |
3209 | (rsp->ulpStatus != IOSTAT_SUCCESS))) { | ||
3209 | lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, | 3210 | lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, |
3210 | "3126 Failed loopback test issue iocb: " | 3211 | "3126 Failed loopback test issue iocb: " |
3211 | "iocb_stat:x%x\n", iocb_stat); | 3212 | "iocb_stat:x%x\n", iocb_stat); |
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 443bbca9694c..b2ede05a5f0a 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c | |||
@@ -4490,9 +4490,7 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_vport *vport, | |||
4490 | piocb->ulpContext = | 4490 | piocb->ulpContext = |
4491 | vport->phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; | 4491 | vport->phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; |
4492 | } | 4492 | } |
4493 | if (ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) { | 4493 | piocb->ulpFCP2Rcvy = (ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) ? 1 : 0; |
4494 | piocb->ulpFCP2Rcvy = 1; | ||
4495 | } | ||
4496 | piocb->ulpClass = (ndlp->nlp_fcp_info & 0x0f); | 4494 | piocb->ulpClass = (ndlp->nlp_fcp_info & 0x0f); |
4497 | 4495 | ||
4498 | /* ulpTimeout is only one byte */ | 4496 | /* ulpTimeout is only one byte */ |
@@ -4986,6 +4984,73 @@ lpfc_taskmgmt_name(uint8_t task_mgmt_cmd) | |||
4986 | } | 4984 | } |
4987 | } | 4985 | } |
4988 | 4986 | ||
4987 | |||
4988 | /** | ||
4989 | * lpfc_check_fcp_rsp - check the returned fcp_rsp to see if task failed | ||
4990 | * @vport: The virtual port for which this call is being executed. | ||
4991 | * @lpfc_cmd: Pointer to lpfc_scsi_buf data structure. | ||
4992 | * | ||
4993 | * This routine checks the FCP RSP INFO to see if the tsk mgmt command succeded | ||
4994 | * | ||
4995 | * Return code : | ||
4996 | * 0x2003 - Error | ||
4997 | * 0x2002 - Success | ||
4998 | **/ | ||
4999 | static int | ||
5000 | lpfc_check_fcp_rsp(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd) | ||
5001 | { | ||
5002 | struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp; | ||
5003 | uint32_t rsp_info; | ||
5004 | uint32_t rsp_len; | ||
5005 | uint8_t rsp_info_code; | ||
5006 | int ret = FAILED; | ||
5007 | |||
5008 | |||
5009 | if (fcprsp == NULL) | ||
5010 | lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, | ||
5011 | "0703 fcp_rsp is missing\n"); | ||
5012 | else { | ||
5013 | rsp_info = fcprsp->rspStatus2; | ||
5014 | rsp_len = be32_to_cpu(fcprsp->rspRspLen); | ||
5015 | rsp_info_code = fcprsp->rspInfo3; | ||
5016 | |||
5017 | |||
5018 | lpfc_printf_vlog(vport, KERN_INFO, | ||
5019 | LOG_FCP, | ||
5020 | "0706 fcp_rsp valid 0x%x," | ||
5021 | " rsp len=%d code 0x%x\n", | ||
5022 | rsp_info, | ||
5023 | rsp_len, rsp_info_code); | ||
5024 | |||
5025 | if ((fcprsp->rspStatus2&RSP_LEN_VALID) && (rsp_len == 8)) { | ||
5026 | switch (rsp_info_code) { | ||
5027 | case RSP_NO_FAILURE: | ||
5028 | lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, | ||
5029 | "0715 Task Mgmt No Failure\n"); | ||
5030 | ret = SUCCESS; | ||
5031 | break; | ||
5032 | case RSP_TM_NOT_SUPPORTED: /* TM rejected */ | ||
5033 | lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, | ||
5034 | "0716 Task Mgmt Target " | ||
5035 | "reject\n"); | ||
5036 | break; | ||
5037 | case RSP_TM_NOT_COMPLETED: /* TM failed */ | ||
5038 | lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, | ||
5039 | "0717 Task Mgmt Target " | ||
5040 | "failed TM\n"); | ||
5041 | break; | ||
5042 | case RSP_TM_INVALID_LU: /* TM to invalid LU! */ | ||
5043 | lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, | ||
5044 | "0718 Task Mgmt to invalid " | ||
5045 | "LUN\n"); | ||
5046 | break; | ||
5047 | } | ||
5048 | } | ||
5049 | } | ||
5050 | return ret; | ||
5051 | } | ||
5052 | |||
5053 | |||
4989 | /** | 5054 | /** |
4990 | * lpfc_send_taskmgmt - Generic SCSI Task Mgmt Handler | 5055 | * lpfc_send_taskmgmt - Generic SCSI Task Mgmt Handler |
4991 | * @vport: The virtual port for which this call is being executed. | 5056 | * @vport: The virtual port for which this call is being executed. |
@@ -5047,12 +5112,8 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata, | |||
5047 | 5112 | ||
5048 | status = lpfc_sli_issue_iocb_wait(phba, LPFC_FCP_RING, | 5113 | status = lpfc_sli_issue_iocb_wait(phba, LPFC_FCP_RING, |
5049 | iocbq, iocbqrsp, lpfc_cmd->timeout); | 5114 | iocbq, iocbqrsp, lpfc_cmd->timeout); |
5050 | if (status != IOCB_SUCCESS) { | 5115 | if ((status != IOCB_SUCCESS) || |
5051 | if (status == IOCB_TIMEDOUT) { | 5116 | (iocbqrsp->iocb.ulpStatus != IOSTAT_SUCCESS)) { |
5052 | ret = TIMEOUT_ERROR; | ||
5053 | } else | ||
5054 | ret = FAILED; | ||
5055 | lpfc_cmd->status = IOSTAT_DRIVER_REJECT; | ||
5056 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | 5117 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, |
5057 | "0727 TMF %s to TGT %d LUN %d failed (%d, %d) " | 5118 | "0727 TMF %s to TGT %d LUN %d failed (%d, %d) " |
5058 | "iocb_flag x%x\n", | 5119 | "iocb_flag x%x\n", |
@@ -5060,9 +5121,21 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata, | |||
5060 | tgt_id, lun_id, iocbqrsp->iocb.ulpStatus, | 5121 | tgt_id, lun_id, iocbqrsp->iocb.ulpStatus, |
5061 | iocbqrsp->iocb.un.ulpWord[4], | 5122 | iocbqrsp->iocb.un.ulpWord[4], |
5062 | iocbq->iocb_flag); | 5123 | iocbq->iocb_flag); |
5063 | } else if (status == IOCB_BUSY) | 5124 | /* if ulpStatus != IOCB_SUCCESS, then status == IOCB_SUCCESS */ |
5064 | ret = FAILED; | 5125 | if (status == IOCB_SUCCESS) { |
5065 | else | 5126 | if (iocbqrsp->iocb.ulpStatus == IOSTAT_FCP_RSP_ERROR) |
5127 | /* Something in the FCP_RSP was invalid. | ||
5128 | * Check conditions */ | ||
5129 | ret = lpfc_check_fcp_rsp(vport, lpfc_cmd); | ||
5130 | else | ||
5131 | ret = FAILED; | ||
5132 | } else if (status == IOCB_TIMEDOUT) { | ||
5133 | ret = TIMEOUT_ERROR; | ||
5134 | } else { | ||
5135 | ret = FAILED; | ||
5136 | } | ||
5137 | lpfc_cmd->status = IOSTAT_DRIVER_REJECT; | ||
5138 | } else | ||
5066 | ret = SUCCESS; | 5139 | ret = SUCCESS; |
5067 | 5140 | ||
5068 | lpfc_sli_release_iocbq(phba, iocbqrsp); | 5141 | lpfc_sli_release_iocbq(phba, iocbqrsp); |
@@ -5186,7 +5259,7 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd) | |||
5186 | unsigned tgt_id = cmnd->device->id; | 5259 | unsigned tgt_id = cmnd->device->id; |
5187 | unsigned int lun_id = cmnd->device->lun; | 5260 | unsigned int lun_id = cmnd->device->lun; |
5188 | struct lpfc_scsi_event_header scsi_event; | 5261 | struct lpfc_scsi_event_header scsi_event; |
5189 | int status, ret = SUCCESS; | 5262 | int status; |
5190 | 5263 | ||
5191 | if (!rdata) { | 5264 | if (!rdata) { |
5192 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | 5265 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, |
@@ -5227,9 +5300,11 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd) | |||
5227 | * So, continue on. | 5300 | * So, continue on. |
5228 | * We will report success if all the i/o aborts successfully. | 5301 | * We will report success if all the i/o aborts successfully. |
5229 | */ | 5302 | */ |
5230 | ret = lpfc_reset_flush_io_context(vport, tgt_id, lun_id, | 5303 | if (status == SUCCESS) |
5304 | status = lpfc_reset_flush_io_context(vport, tgt_id, lun_id, | ||
5231 | LPFC_CTX_LUN); | 5305 | LPFC_CTX_LUN); |
5232 | return ret; | 5306 | |
5307 | return status; | ||
5233 | } | 5308 | } |
5234 | 5309 | ||
5235 | /** | 5310 | /** |
@@ -5253,7 +5328,7 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd) | |||
5253 | unsigned tgt_id = cmnd->device->id; | 5328 | unsigned tgt_id = cmnd->device->id; |
5254 | unsigned int lun_id = cmnd->device->lun; | 5329 | unsigned int lun_id = cmnd->device->lun; |
5255 | struct lpfc_scsi_event_header scsi_event; | 5330 | struct lpfc_scsi_event_header scsi_event; |
5256 | int status, ret = SUCCESS; | 5331 | int status; |
5257 | 5332 | ||
5258 | if (!rdata) { | 5333 | if (!rdata) { |
5259 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | 5334 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, |
@@ -5294,9 +5369,10 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd) | |||
5294 | * So, continue on. | 5369 | * So, continue on. |
5295 | * We will report success if all the i/o aborts successfully. | 5370 | * We will report success if all the i/o aborts successfully. |
5296 | */ | 5371 | */ |
5297 | ret = lpfc_reset_flush_io_context(vport, tgt_id, lun_id, | 5372 | if (status == SUCCESS) |
5373 | status = lpfc_reset_flush_io_context(vport, tgt_id, lun_id, | ||
5298 | LPFC_CTX_TGT); | 5374 | LPFC_CTX_TGT); |
5299 | return ret; | 5375 | return status; |
5300 | } | 5376 | } |
5301 | 5377 | ||
5302 | /** | 5378 | /** |
diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h index b1d9f7fcb911..852ff7def493 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.h +++ b/drivers/scsi/lpfc/lpfc_scsi.h | |||
@@ -73,6 +73,7 @@ struct fcp_rsp { | |||
73 | #define RSP_RO_MISMATCH_ERR 0x03 | 73 | #define RSP_RO_MISMATCH_ERR 0x03 |
74 | #define RSP_TM_NOT_SUPPORTED 0x04 /* Task mgmt function not supported */ | 74 | #define RSP_TM_NOT_SUPPORTED 0x04 /* Task mgmt function not supported */ |
75 | #define RSP_TM_NOT_COMPLETED 0x05 /* Task mgmt function not performed */ | 75 | #define RSP_TM_NOT_COMPLETED 0x05 /* Task mgmt function not performed */ |
76 | #define RSP_TM_INVALID_LU 0x09 /* Task mgmt function to invalid LU */ | ||
76 | 77 | ||
77 | uint32_t rspInfoRsvd; /* FCP_RSP_INFO bytes 4-7 (reserved) */ | 78 | uint32_t rspInfoRsvd; /* FCP_RSP_INFO bytes 4-7 (reserved) */ |
78 | 79 | ||
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index a262d22bca44..8f580fda443f 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c | |||
@@ -10196,6 +10196,11 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba, | |||
10196 | if (iocb_completed) { | 10196 | if (iocb_completed) { |
10197 | lpfc_printf_log(phba, KERN_INFO, LOG_SLI, | 10197 | lpfc_printf_log(phba, KERN_INFO, LOG_SLI, |
10198 | "0331 IOCB wake signaled\n"); | 10198 | "0331 IOCB wake signaled\n"); |
10199 | /* Note: we are not indicating if the IOCB has a success | ||
10200 | * status or not - that's for the caller to check. | ||
10201 | * IOCB_SUCCESS means just that the command was sent and | ||
10202 | * completed. Not that it completed successfully. | ||
10203 | * */ | ||
10199 | } else if (timeleft == 0) { | 10204 | } else if (timeleft == 0) { |
10200 | lpfc_printf_log(phba, KERN_ERR, LOG_SLI, | 10205 | lpfc_printf_log(phba, KERN_ERR, LOG_SLI, |
10201 | "0338 IOCB wait timeout error - no " | 10206 | "0338 IOCB wait timeout error - no " |