diff options
author | James Smart <James.Smart@Emulex.Com> | 2007-04-25 09:52:34 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2007-05-06 10:33:14 -0400 |
commit | 7054a606e6724674a5acd103ed74eacb02c73393 (patch) | |
tree | 271327c20a1e4bff9475ef7a9d98afd4644d6570 /drivers/scsi/lpfc/lpfc_scsi.c | |
parent | de0c5b32b50ef2673f4cd434b9c2732237d715dd (diff) |
[SCSI] lpfc 8.1.12 : Round 2 of Miscellaneous fixes
Round 2 of Miscellaneous fixes:
- Ensure we don't prematurely re-enable IRQs in lpfc_sli_abort_fcp_cmpl().
- Prevent freeing of iocb after IOCB_TIMEDOUT error.
- Added code to cleanup REG_LOGIN mailbox command when a LOGO is received.
- Fix offline window where more work can sneak in after clearing work_ha
- Use target reset instead of LU reset in bus_device_reset_handler
- Fixed system hangs due to leaked host_lock.
- Fixed NULL pointer dereference during I/O with LIP.
- Fixed false iocb timeout.
- Fixed name server query response handling.
- Change rport dev_loss_tmo value when user change lpfc HBA's dev_loss_tmo.
- Fixed a memory leak in lpfc_sli_wake_mbox_wait.
- Fixed check for dropped frames.
- Removed hba queue depth calculation based on device PCI IDs
- Change min cr_count value specified in comment to agree with setting
Signed-off-by: James Smart <James.Smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_scsi.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 90 |
1 files changed, 66 insertions, 24 deletions
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 28dbd6be72ee..efd1cf638b8c 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c | |||
@@ -292,13 +292,13 @@ lpfc_scsi_unprep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb) | |||
292 | } | 292 | } |
293 | 293 | ||
294 | static void | 294 | static void |
295 | lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd) | 295 | lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_iocbq *rsp_iocb) |
296 | { | 296 | { |
297 | struct scsi_cmnd *cmnd = lpfc_cmd->pCmd; | 297 | struct scsi_cmnd *cmnd = lpfc_cmd->pCmd; |
298 | struct fcp_cmnd *fcpcmd = lpfc_cmd->fcp_cmnd; | 298 | struct fcp_cmnd *fcpcmd = lpfc_cmd->fcp_cmnd; |
299 | struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp; | 299 | struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp; |
300 | struct lpfc_hba *phba = lpfc_cmd->scsi_hba; | 300 | struct lpfc_hba *phba = lpfc_cmd->scsi_hba; |
301 | uint32_t fcpi_parm = lpfc_cmd->cur_iocbq.iocb.un.fcpi.fcpi_parm; | 301 | uint32_t fcpi_parm = rsp_iocb->iocb.un.fcpi.fcpi_parm; |
302 | uint32_t resp_info = fcprsp->rspStatus2; | 302 | uint32_t resp_info = fcprsp->rspStatus2; |
303 | uint32_t scsi_status = fcprsp->rspStatus3; | 303 | uint32_t scsi_status = fcprsp->rspStatus3; |
304 | uint32_t *lp; | 304 | uint32_t *lp; |
@@ -360,6 +360,24 @@ lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd) | |||
360 | fcpi_parm, cmnd->cmnd[0], cmnd->underflow); | 360 | fcpi_parm, cmnd->cmnd[0], cmnd->underflow); |
361 | 361 | ||
362 | /* | 362 | /* |
363 | * If there is an under run check if under run reported by | ||
364 | * storage array is same as the under run reported by HBA. | ||
365 | * If this is not same, there is a dropped frame. | ||
366 | */ | ||
367 | if ((cmnd->sc_data_direction == DMA_FROM_DEVICE) && | ||
368 | fcpi_parm && | ||
369 | (cmnd->resid != fcpi_parm)) { | ||
370 | lpfc_printf_log(phba, KERN_WARNING, | ||
371 | LOG_FCP | LOG_FCP_ERROR, | ||
372 | "%d:0735 FCP Read Check Error and Underrun " | ||
373 | "Data: x%x x%x x%x x%x\n", phba->brd_no, | ||
374 | be32_to_cpu(fcpcmd->fcpDl), | ||
375 | cmnd->resid, | ||
376 | fcpi_parm, cmnd->cmnd[0]); | ||
377 | cmnd->resid = cmnd->request_bufflen; | ||
378 | host_status = DID_ERROR; | ||
379 | } | ||
380 | /* | ||
363 | * The cmnd->underflow is the minimum number of bytes that must | 381 | * The cmnd->underflow is the minimum number of bytes that must |
364 | * be transfered for this command. Provided a sense condition | 382 | * be transfered for this command. Provided a sense condition |
365 | * is not present, make sure the actual amount transferred is at | 383 | * is not present, make sure the actual amount transferred is at |
@@ -439,7 +457,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, | |||
439 | switch (lpfc_cmd->status) { | 457 | switch (lpfc_cmd->status) { |
440 | case IOSTAT_FCP_RSP_ERROR: | 458 | case IOSTAT_FCP_RSP_ERROR: |
441 | /* Call FCP RSP handler to determine result */ | 459 | /* Call FCP RSP handler to determine result */ |
442 | lpfc_handle_fcp_err(lpfc_cmd); | 460 | lpfc_handle_fcp_err(lpfc_cmd,pIocbOut); |
443 | break; | 461 | break; |
444 | case IOSTAT_NPORT_BSY: | 462 | case IOSTAT_NPORT_BSY: |
445 | case IOSTAT_FABRIC_BSY: | 463 | case IOSTAT_FABRIC_BSY: |
@@ -673,6 +691,18 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba, | |||
673 | return (1); | 691 | return (1); |
674 | } | 692 | } |
675 | 693 | ||
694 | static void | ||
695 | lpfc_tskmgmt_def_cmpl(struct lpfc_hba *phba, | ||
696 | struct lpfc_iocbq *cmdiocbq, | ||
697 | struct lpfc_iocbq *rspiocbq) | ||
698 | { | ||
699 | struct lpfc_scsi_buf *lpfc_cmd = | ||
700 | (struct lpfc_scsi_buf *) cmdiocbq->context1; | ||
701 | if (lpfc_cmd) | ||
702 | lpfc_release_scsi_buf(phba, lpfc_cmd); | ||
703 | return; | ||
704 | } | ||
705 | |||
676 | static int | 706 | static int |
677 | lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba, | 707 | lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba, |
678 | unsigned tgt_id, unsigned int lun, | 708 | unsigned tgt_id, unsigned int lun, |
@@ -709,8 +739,9 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba, | |||
709 | &phba->sli.ring[phba->sli.fcp_ring], | 739 | &phba->sli.ring[phba->sli.fcp_ring], |
710 | iocbq, iocbqrsp, lpfc_cmd->timeout); | 740 | iocbq, iocbqrsp, lpfc_cmd->timeout); |
711 | if (ret != IOCB_SUCCESS) { | 741 | if (ret != IOCB_SUCCESS) { |
742 | if (ret == IOCB_TIMEDOUT) | ||
743 | iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl; | ||
712 | lpfc_cmd->status = IOSTAT_DRIVER_REJECT; | 744 | lpfc_cmd->status = IOSTAT_DRIVER_REJECT; |
713 | ret = FAILED; | ||
714 | } else { | 745 | } else { |
715 | ret = SUCCESS; | 746 | ret = SUCCESS; |
716 | lpfc_cmd->result = iocbqrsp->iocb.un.ulpWord[4]; | 747 | lpfc_cmd->result = iocbqrsp->iocb.un.ulpWord[4]; |
@@ -977,7 +1008,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) | |||
977 | } | 1008 | } |
978 | 1009 | ||
979 | static int | 1010 | static int |
980 | lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) | 1011 | lpfc_device_reset_handler(struct scsi_cmnd *cmnd) |
981 | { | 1012 | { |
982 | struct Scsi_Host *shost = cmnd->device->host; | 1013 | struct Scsi_Host *shost = cmnd->device->host; |
983 | struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata; | 1014 | struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata; |
@@ -987,6 +1018,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) | |||
987 | struct lpfc_nodelist *pnode = rdata->pnode; | 1018 | struct lpfc_nodelist *pnode = rdata->pnode; |
988 | uint32_t cmd_result = 0, cmd_status = 0; | 1019 | uint32_t cmd_result = 0, cmd_status = 0; |
989 | int ret = FAILED; | 1020 | int ret = FAILED; |
1021 | int iocb_status = IOCB_SUCCESS; | ||
990 | int cnt, loopcnt; | 1022 | int cnt, loopcnt; |
991 | 1023 | ||
992 | lpfc_block_error_handler(cmnd); | 1024 | lpfc_block_error_handler(cmnd); |
@@ -998,7 +1030,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) | |||
998 | */ | 1030 | */ |
999 | while ( 1 ) { | 1031 | while ( 1 ) { |
1000 | if (!pnode) | 1032 | if (!pnode) |
1001 | return FAILED; | 1033 | goto out; |
1002 | 1034 | ||
1003 | if (pnode->nlp_state != NLP_STE_MAPPED_NODE) { | 1035 | if (pnode->nlp_state != NLP_STE_MAPPED_NODE) { |
1004 | spin_unlock_irq(phba->host->host_lock); | 1036 | spin_unlock_irq(phba->host->host_lock); |
@@ -1016,7 +1048,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) | |||
1016 | } | 1048 | } |
1017 | pnode = rdata->pnode; | 1049 | pnode = rdata->pnode; |
1018 | if (!pnode) | 1050 | if (!pnode) |
1019 | return FAILED; | 1051 | goto out; |
1020 | } | 1052 | } |
1021 | if (pnode->nlp_state == NLP_STE_MAPPED_NODE) | 1053 | if (pnode->nlp_state == NLP_STE_MAPPED_NODE) |
1022 | break; | 1054 | break; |
@@ -1031,7 +1063,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) | |||
1031 | lpfc_cmd->rdata = rdata; | 1063 | lpfc_cmd->rdata = rdata; |
1032 | 1064 | ||
1033 | ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, cmnd->device->lun, | 1065 | ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, cmnd->device->lun, |
1034 | FCP_LUN_RESET); | 1066 | FCP_TARGET_RESET); |
1035 | if (!ret) | 1067 | if (!ret) |
1036 | goto out_free_scsi_buf; | 1068 | goto out_free_scsi_buf; |
1037 | 1069 | ||
@@ -1043,16 +1075,21 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) | |||
1043 | goto out_free_scsi_buf; | 1075 | goto out_free_scsi_buf; |
1044 | 1076 | ||
1045 | lpfc_printf_log(phba, KERN_INFO, LOG_FCP, | 1077 | lpfc_printf_log(phba, KERN_INFO, LOG_FCP, |
1046 | "%d:0703 Issue LUN Reset to TGT %d LUN %d " | 1078 | "%d:0703 Issue target reset to TGT %d LUN %d rpi x%x " |
1047 | "Data: x%x x%x\n", phba->brd_no, cmnd->device->id, | 1079 | "nlp_flag x%x\n", phba->brd_no, cmnd->device->id, |
1048 | cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag); | 1080 | cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag); |
1049 | 1081 | ||
1050 | ret = lpfc_sli_issue_iocb_wait(phba, | 1082 | iocb_status = lpfc_sli_issue_iocb_wait(phba, |
1051 | &phba->sli.ring[phba->sli.fcp_ring], | 1083 | &phba->sli.ring[phba->sli.fcp_ring], |
1052 | iocbq, iocbqrsp, lpfc_cmd->timeout); | 1084 | iocbq, iocbqrsp, lpfc_cmd->timeout); |
1053 | if (ret == IOCB_SUCCESS) | ||
1054 | ret = SUCCESS; | ||
1055 | 1085 | ||
1086 | if (iocb_status == IOCB_TIMEDOUT) | ||
1087 | iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl; | ||
1088 | |||
1089 | if (iocb_status == IOCB_SUCCESS) | ||
1090 | ret = SUCCESS; | ||
1091 | else | ||
1092 | ret = iocb_status; | ||
1056 | 1093 | ||
1057 | cmd_result = iocbqrsp->iocb.un.ulpWord[4]; | 1094 | cmd_result = iocbqrsp->iocb.un.ulpWord[4]; |
1058 | cmd_status = iocbqrsp->iocb.ulpStatus; | 1095 | cmd_status = iocbqrsp->iocb.ulpStatus; |
@@ -1090,18 +1127,19 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) | |||
1090 | 1127 | ||
1091 | if (cnt) { | 1128 | if (cnt) { |
1092 | lpfc_printf_log(phba, KERN_ERR, LOG_FCP, | 1129 | lpfc_printf_log(phba, KERN_ERR, LOG_FCP, |
1093 | "%d:0719 LUN Reset I/O flush failure: cnt x%x\n", | 1130 | "%d:0719 device reset I/O flush failure: cnt x%x\n", |
1094 | phba->brd_no, cnt); | 1131 | phba->brd_no, cnt); |
1095 | ret = FAILED; | 1132 | ret = FAILED; |
1096 | } | 1133 | } |
1097 | 1134 | ||
1098 | out_free_scsi_buf: | 1135 | out_free_scsi_buf: |
1099 | lpfc_release_scsi_buf(phba, lpfc_cmd); | 1136 | if (iocb_status != IOCB_TIMEDOUT) { |
1100 | 1137 | lpfc_release_scsi_buf(phba, lpfc_cmd); | |
1138 | } | ||
1101 | lpfc_printf_log(phba, KERN_ERR, LOG_FCP, | 1139 | lpfc_printf_log(phba, KERN_ERR, LOG_FCP, |
1102 | "%d:0713 SCSI layer issued LUN reset (%d, %d) " | 1140 | "%d:0713 SCSI layer issued device reset (%d, %d) " |
1103 | "Data: x%x x%x x%x\n", | 1141 | "return x%x status x%x result x%x\n", |
1104 | phba->brd_no, cmnd->device->id,cmnd->device->lun, | 1142 | phba->brd_no, cmnd->device->id, cmnd->device->lun, |
1105 | ret, cmd_status, cmd_result); | 1143 | ret, cmd_status, cmd_result); |
1106 | 1144 | ||
1107 | out: | 1145 | out: |
@@ -1110,7 +1148,7 @@ out: | |||
1110 | } | 1148 | } |
1111 | 1149 | ||
1112 | static int | 1150 | static int |
1113 | lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) | 1151 | lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) |
1114 | { | 1152 | { |
1115 | struct Scsi_Host *shost = cmnd->device->host; | 1153 | struct Scsi_Host *shost = cmnd->device->host; |
1116 | struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata; | 1154 | struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata; |
@@ -1155,13 +1193,17 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) | |||
1155 | "%d:0700 Bus Reset on target %d failed\n", | 1193 | "%d:0700 Bus Reset on target %d failed\n", |
1156 | phba->brd_no, i); | 1194 | phba->brd_no, i); |
1157 | err_count++; | 1195 | err_count++; |
1196 | break; | ||
1158 | } | 1197 | } |
1159 | } | 1198 | } |
1160 | 1199 | ||
1200 | if (ret != IOCB_TIMEDOUT) | ||
1201 | lpfc_release_scsi_buf(phba, lpfc_cmd); | ||
1202 | |||
1161 | if (err_count == 0) | 1203 | if (err_count == 0) |
1162 | ret = SUCCESS; | 1204 | ret = SUCCESS; |
1163 | 1205 | else | |
1164 | lpfc_release_scsi_buf(phba, lpfc_cmd); | 1206 | ret = FAILED; |
1165 | 1207 | ||
1166 | /* | 1208 | /* |
1167 | * All outstanding txcmplq I/Os should have been aborted by | 1209 | * All outstanding txcmplq I/Os should have been aborted by |
@@ -1302,8 +1344,8 @@ struct scsi_host_template lpfc_template = { | |||
1302 | .info = lpfc_info, | 1344 | .info = lpfc_info, |
1303 | .queuecommand = lpfc_queuecommand, | 1345 | .queuecommand = lpfc_queuecommand, |
1304 | .eh_abort_handler = lpfc_abort_handler, | 1346 | .eh_abort_handler = lpfc_abort_handler, |
1305 | .eh_device_reset_handler= lpfc_reset_lun_handler, | 1347 | .eh_device_reset_handler= lpfc_device_reset_handler, |
1306 | .eh_bus_reset_handler = lpfc_reset_bus_handler, | 1348 | .eh_bus_reset_handler = lpfc_bus_reset_handler, |
1307 | .slave_alloc = lpfc_slave_alloc, | 1349 | .slave_alloc = lpfc_slave_alloc, |
1308 | .slave_configure = lpfc_slave_configure, | 1350 | .slave_configure = lpfc_slave_configure, |
1309 | .slave_destroy = lpfc_slave_destroy, | 1351 | .slave_destroy = lpfc_slave_destroy, |