diff options
author | James Smart <james.smart@emulex.com> | 2011-12-13 13:21:57 -0500 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2011-12-15 01:57:44 -0500 |
commit | cb69f7decc3777822b240c46890a209df288c7bb (patch) | |
tree | 8ae647f9d3d50452fc0bc684a8b4108a4f94a65e /drivers/scsi/lpfc/lpfc_sli.c | |
parent | ff78d8f97c85a568c0799b06137a4171db45b923 (diff) |
[SCSI] lpfc 8.3.28: Add support for ABTS failure handling
Add support for ABTS failure handling:
- Add asynchronous ABTS notification event feature to driver (CR 124578)
- Change driver message 3092 and 3116 to KERN_WARNING (CR 124768)
- Alter the SCR ELS command to use the temporary RPI and the
Destination DID for SLI4-FC (CR 126070)
Signed-off-by: Alex Iannicelli <alex.iannicelli@emulex.com>
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_sli.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 214 |
1 files changed, 177 insertions, 37 deletions
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 4c4d77356bb2..97bbafb21bc2 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c | |||
@@ -4339,6 +4339,11 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode) | |||
4339 | phba->sli.sli_flag &= ~LPFC_SLI_ASYNC_MBX_BLK; | 4339 | phba->sli.sli_flag &= ~LPFC_SLI_ASYNC_MBX_BLK; |
4340 | spin_unlock_irq(&phba->hbalock); | 4340 | spin_unlock_irq(&phba->hbalock); |
4341 | done = 1; | 4341 | done = 1; |
4342 | |||
4343 | if ((pmb->u.mb.un.varCfgPort.casabt == 1) && | ||
4344 | (pmb->u.mb.un.varCfgPort.gasabt == 0)) | ||
4345 | lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, | ||
4346 | "3110 Port did not grant ASABT\n"); | ||
4342 | } | 4347 | } |
4343 | } | 4348 | } |
4344 | if (!done) { | 4349 | if (!done) { |
@@ -7704,6 +7709,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, | |||
7704 | iocbq->context2)->virt); | 7709 | iocbq->context2)->virt); |
7705 | if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { | 7710 | if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { |
7706 | if (pcmd && (*pcmd == ELS_CMD_FLOGI || | 7711 | if (pcmd && (*pcmd == ELS_CMD_FLOGI || |
7712 | *pcmd == ELS_CMD_SCR || | ||
7707 | *pcmd == ELS_CMD_PLOGI)) { | 7713 | *pcmd == ELS_CMD_PLOGI)) { |
7708 | bf_set(els_req64_sp, &wqe->els_req, 1); | 7714 | bf_set(els_req64_sp, &wqe->els_req, 1); |
7709 | bf_set(els_req64_sid, &wqe->els_req, | 7715 | bf_set(els_req64_sid, &wqe->els_req, |
@@ -8213,6 +8219,137 @@ lpfc_extra_ring_setup( struct lpfc_hba *phba) | |||
8213 | return 0; | 8219 | return 0; |
8214 | } | 8220 | } |
8215 | 8221 | ||
8222 | /* lpfc_sli_abts_recover_port - Recover a port that failed an ABTS. | ||
8223 | * @vport: pointer to virtual port object. | ||
8224 | * @ndlp: nodelist pointer for the impacted rport. | ||
8225 | * | ||
8226 | * The driver calls this routine in response to a XRI ABORT CQE | ||
8227 | * event from the port. In this event, the driver is required to | ||
8228 | * recover its login to the rport even though its login may be valid | ||
8229 | * from the driver's perspective. The failed ABTS notice from the | ||
8230 | * port indicates the rport is not responding. | ||
8231 | */ | ||
8232 | static void | ||
8233 | lpfc_sli_abts_recover_port(struct lpfc_vport *vport, | ||
8234 | struct lpfc_nodelist *ndlp) | ||
8235 | { | ||
8236 | struct Scsi_Host *shost; | ||
8237 | struct lpfc_hba *phba; | ||
8238 | unsigned long flags = 0; | ||
8239 | |||
8240 | shost = lpfc_shost_from_vport(vport); | ||
8241 | phba = vport->phba; | ||
8242 | if (ndlp->nlp_state != NLP_STE_MAPPED_NODE) { | ||
8243 | lpfc_printf_log(phba, KERN_INFO, | ||
8244 | LOG_SLI, "3093 No rport recovery needed. " | ||
8245 | "rport in state 0x%x\n", | ||
8246 | ndlp->nlp_state); | ||
8247 | return; | ||
8248 | } | ||
8249 | lpfc_printf_log(phba, KERN_ERR, LOG_SLI, | ||
8250 | "3094 Start rport recovery on shost id 0x%x " | ||
8251 | "fc_id 0x%06x vpi 0x%x rpi 0x%x state 0x%x " | ||
8252 | "flags 0x%x\n", | ||
8253 | shost->host_no, ndlp->nlp_DID, | ||
8254 | vport->vpi, ndlp->nlp_rpi, ndlp->nlp_state, | ||
8255 | ndlp->nlp_flag); | ||
8256 | /* | ||
8257 | * The rport is not responding. Don't attempt ADISC recovery. | ||
8258 | * Remove the FCP-2 flag to force a PLOGI. | ||
8259 | */ | ||
8260 | spin_lock_irqsave(shost->host_lock, flags); | ||
8261 | ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; | ||
8262 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
8263 | lpfc_disc_state_machine(vport, ndlp, NULL, | ||
8264 | NLP_EVT_DEVICE_RECOVERY); | ||
8265 | lpfc_cancel_retry_delay_tmo(vport, ndlp); | ||
8266 | spin_lock_irqsave(shost->host_lock, flags); | ||
8267 | ndlp->nlp_flag |= NLP_NPR_2B_DISC; | ||
8268 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
8269 | lpfc_disc_start(vport); | ||
8270 | } | ||
8271 | |||
8272 | /* lpfc_sli_abts_err_handler - handle a failed ABTS request from an SLI3 port. | ||
8273 | * @phba: Pointer to HBA context object. | ||
8274 | * @iocbq: Pointer to iocb object. | ||
8275 | * | ||
8276 | * The async_event handler calls this routine when it receives | ||
8277 | * an ASYNC_STATUS_CN event from the port. The port generates | ||
8278 | * this event when an Abort Sequence request to an rport fails | ||
8279 | * twice in succession. The abort could be originated by the | ||
8280 | * driver or by the port. The ABTS could have been for an ELS | ||
8281 | * or FCP IO. The port only generates this event when an ABTS | ||
8282 | * fails to complete after one retry. | ||
8283 | */ | ||
8284 | static void | ||
8285 | lpfc_sli_abts_err_handler(struct lpfc_hba *phba, | ||
8286 | struct lpfc_iocbq *iocbq) | ||
8287 | { | ||
8288 | struct lpfc_nodelist *ndlp = NULL; | ||
8289 | uint16_t rpi = 0, vpi = 0; | ||
8290 | struct lpfc_vport *vport = NULL; | ||
8291 | |||
8292 | /* The rpi in the ulpContext is vport-sensitive. */ | ||
8293 | vpi = iocbq->iocb.un.asyncstat.sub_ctxt_tag; | ||
8294 | rpi = iocbq->iocb.ulpContext; | ||
8295 | |||
8296 | lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, | ||
8297 | "3092 Port generated ABTS async event " | ||
8298 | "on vpi %d rpi %d status 0x%x\n", | ||
8299 | vpi, rpi, iocbq->iocb.ulpStatus); | ||
8300 | |||
8301 | vport = lpfc_find_vport_by_vpid(phba, vpi); | ||
8302 | if (!vport) | ||
8303 | goto err_exit; | ||
8304 | ndlp = lpfc_findnode_rpi(vport, rpi); | ||
8305 | if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) | ||
8306 | goto err_exit; | ||
8307 | |||
8308 | if (iocbq->iocb.ulpStatus == IOSTAT_LOCAL_REJECT) | ||
8309 | lpfc_sli_abts_recover_port(vport, ndlp); | ||
8310 | return; | ||
8311 | |||
8312 | err_exit: | ||
8313 | lpfc_printf_log(phba, KERN_INFO, LOG_SLI, | ||
8314 | "3095 Event Context not found, no " | ||
8315 | "action on vpi %d rpi %d status 0x%x, reason 0x%x\n", | ||
8316 | iocbq->iocb.ulpContext, iocbq->iocb.ulpStatus, | ||
8317 | vpi, rpi); | ||
8318 | } | ||
8319 | |||
8320 | /* lpfc_sli4_abts_err_handler - handle a failed ABTS request from an SLI4 port. | ||
8321 | * @phba: pointer to HBA context object. | ||
8322 | * @ndlp: nodelist pointer for the impacted rport. | ||
8323 | * @axri: pointer to the wcqe containing the failed exchange. | ||
8324 | * | ||
8325 | * The driver calls this routine when it receives an ABORT_XRI_FCP CQE from the | ||
8326 | * port. The port generates this event when an abort exchange request to an | ||
8327 | * rport fails twice in succession with no reply. The abort could be originated | ||
8328 | * by the driver or by the port. The ABTS could have been for an ELS or FCP IO. | ||
8329 | */ | ||
8330 | void | ||
8331 | lpfc_sli4_abts_err_handler(struct lpfc_hba *phba, | ||
8332 | struct lpfc_nodelist *ndlp, | ||
8333 | struct sli4_wcqe_xri_aborted *axri) | ||
8334 | { | ||
8335 | struct lpfc_vport *vport; | ||
8336 | |||
8337 | if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) | ||
8338 | lpfc_printf_log(phba, KERN_INFO, LOG_SLI, | ||
8339 | "3115 Node Context not found, driver " | ||
8340 | "ignoring abts err event\n"); | ||
8341 | vport = ndlp->vport; | ||
8342 | lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, | ||
8343 | "3116 Port generated FCP XRI ABORT event on " | ||
8344 | "vpi %d rpi %d xri x%x status 0x%x\n", | ||
8345 | ndlp->vport->vpi, ndlp->nlp_rpi, | ||
8346 | bf_get(lpfc_wcqe_xa_xri, axri), | ||
8347 | bf_get(lpfc_wcqe_xa_status, axri)); | ||
8348 | |||
8349 | if (bf_get(lpfc_wcqe_xa_status, axri) == IOSTAT_LOCAL_REJECT) | ||
8350 | lpfc_sli_abts_recover_port(vport, ndlp); | ||
8351 | } | ||
8352 | |||
8216 | /** | 8353 | /** |
8217 | * lpfc_sli_async_event_handler - ASYNC iocb handler function | 8354 | * lpfc_sli_async_event_handler - ASYNC iocb handler function |
8218 | * @phba: Pointer to HBA context object. | 8355 | * @phba: Pointer to HBA context object. |
@@ -8232,63 +8369,58 @@ lpfc_sli_async_event_handler(struct lpfc_hba * phba, | |||
8232 | { | 8369 | { |
8233 | IOCB_t *icmd; | 8370 | IOCB_t *icmd; |
8234 | uint16_t evt_code; | 8371 | uint16_t evt_code; |
8235 | uint16_t temp; | ||
8236 | struct temp_event temp_event_data; | 8372 | struct temp_event temp_event_data; |
8237 | struct Scsi_Host *shost; | 8373 | struct Scsi_Host *shost; |
8238 | uint32_t *iocb_w; | 8374 | uint32_t *iocb_w; |
8239 | 8375 | ||
8240 | icmd = &iocbq->iocb; | 8376 | icmd = &iocbq->iocb; |
8241 | evt_code = icmd->un.asyncstat.evt_code; | 8377 | evt_code = icmd->un.asyncstat.evt_code; |
8242 | temp = icmd->ulpContext; | ||
8243 | 8378 | ||
8244 | if ((evt_code != ASYNC_TEMP_WARN) && | 8379 | switch (evt_code) { |
8245 | (evt_code != ASYNC_TEMP_SAFE)) { | 8380 | case ASYNC_TEMP_WARN: |
8381 | case ASYNC_TEMP_SAFE: | ||
8382 | temp_event_data.data = (uint32_t) icmd->ulpContext; | ||
8383 | temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT; | ||
8384 | if (evt_code == ASYNC_TEMP_WARN) { | ||
8385 | temp_event_data.event_code = LPFC_THRESHOLD_TEMP; | ||
8386 | lpfc_printf_log(phba, KERN_ERR, LOG_TEMP, | ||
8387 | "0347 Adapter is very hot, please take " | ||
8388 | "corrective action. temperature : %d Celsius\n", | ||
8389 | (uint32_t) icmd->ulpContext); | ||
8390 | } else { | ||
8391 | temp_event_data.event_code = LPFC_NORMAL_TEMP; | ||
8392 | lpfc_printf_log(phba, KERN_ERR, LOG_TEMP, | ||
8393 | "0340 Adapter temperature is OK now. " | ||
8394 | "temperature : %d Celsius\n", | ||
8395 | (uint32_t) icmd->ulpContext); | ||
8396 | } | ||
8397 | |||
8398 | /* Send temperature change event to applications */ | ||
8399 | shost = lpfc_shost_from_vport(phba->pport); | ||
8400 | fc_host_post_vendor_event(shost, fc_get_event_number(), | ||
8401 | sizeof(temp_event_data), (char *) &temp_event_data, | ||
8402 | LPFC_NL_VENDOR_ID); | ||
8403 | break; | ||
8404 | case ASYNC_STATUS_CN: | ||
8405 | lpfc_sli_abts_err_handler(phba, iocbq); | ||
8406 | break; | ||
8407 | default: | ||
8246 | iocb_w = (uint32_t *) icmd; | 8408 | iocb_w = (uint32_t *) icmd; |
8247 | lpfc_printf_log(phba, | 8409 | lpfc_printf_log(phba, KERN_ERR, LOG_SLI, |
8248 | KERN_ERR, | ||
8249 | LOG_SLI, | ||
8250 | "0346 Ring %d handler: unexpected ASYNC_STATUS" | 8410 | "0346 Ring %d handler: unexpected ASYNC_STATUS" |
8251 | " evt_code 0x%x\n" | 8411 | " evt_code 0x%x\n" |
8252 | "W0 0x%08x W1 0x%08x W2 0x%08x W3 0x%08x\n" | 8412 | "W0 0x%08x W1 0x%08x W2 0x%08x W3 0x%08x\n" |
8253 | "W4 0x%08x W5 0x%08x W6 0x%08x W7 0x%08x\n" | 8413 | "W4 0x%08x W5 0x%08x W6 0x%08x W7 0x%08x\n" |
8254 | "W8 0x%08x W9 0x%08x W10 0x%08x W11 0x%08x\n" | 8414 | "W8 0x%08x W9 0x%08x W10 0x%08x W11 0x%08x\n" |
8255 | "W12 0x%08x W13 0x%08x W14 0x%08x W15 0x%08x\n", | 8415 | "W12 0x%08x W13 0x%08x W14 0x%08x W15 0x%08x\n", |
8256 | pring->ringno, | 8416 | pring->ringno, icmd->un.asyncstat.evt_code, |
8257 | icmd->un.asyncstat.evt_code, | ||
8258 | iocb_w[0], iocb_w[1], iocb_w[2], iocb_w[3], | 8417 | iocb_w[0], iocb_w[1], iocb_w[2], iocb_w[3], |
8259 | iocb_w[4], iocb_w[5], iocb_w[6], iocb_w[7], | 8418 | iocb_w[4], iocb_w[5], iocb_w[6], iocb_w[7], |
8260 | iocb_w[8], iocb_w[9], iocb_w[10], iocb_w[11], | 8419 | iocb_w[8], iocb_w[9], iocb_w[10], iocb_w[11], |
8261 | iocb_w[12], iocb_w[13], iocb_w[14], iocb_w[15]); | 8420 | iocb_w[12], iocb_w[13], iocb_w[14], iocb_w[15]); |
8262 | 8421 | ||
8263 | return; | 8422 | break; |
8264 | } | ||
8265 | temp_event_data.data = (uint32_t)temp; | ||
8266 | temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT; | ||
8267 | if (evt_code == ASYNC_TEMP_WARN) { | ||
8268 | temp_event_data.event_code = LPFC_THRESHOLD_TEMP; | ||
8269 | lpfc_printf_log(phba, | ||
8270 | KERN_ERR, | ||
8271 | LOG_TEMP, | ||
8272 | "0347 Adapter is very hot, please take " | ||
8273 | "corrective action. temperature : %d Celsius\n", | ||
8274 | temp); | ||
8275 | } | ||
8276 | if (evt_code == ASYNC_TEMP_SAFE) { | ||
8277 | temp_event_data.event_code = LPFC_NORMAL_TEMP; | ||
8278 | lpfc_printf_log(phba, | ||
8279 | KERN_ERR, | ||
8280 | LOG_TEMP, | ||
8281 | "0340 Adapter temperature is OK now. " | ||
8282 | "temperature : %d Celsius\n", | ||
8283 | temp); | ||
8284 | } | 8423 | } |
8285 | |||
8286 | /* Send temperature change event to applications */ | ||
8287 | shost = lpfc_shost_from_vport(phba->pport); | ||
8288 | fc_host_post_vendor_event(shost, fc_get_event_number(), | ||
8289 | sizeof(temp_event_data), (char *) &temp_event_data, | ||
8290 | LPFC_NL_VENDOR_ID); | ||
8291 | |||
8292 | } | 8424 | } |
8293 | 8425 | ||
8294 | 8426 | ||
@@ -9247,6 +9379,14 @@ void | |||
9247 | lpfc_sli_abort_fcp_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | 9379 | lpfc_sli_abort_fcp_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, |
9248 | struct lpfc_iocbq *rspiocb) | 9380 | struct lpfc_iocbq *rspiocb) |
9249 | { | 9381 | { |
9382 | lpfc_printf_log(phba, KERN_INFO, LOG_SLI, | ||
9383 | "3096 ABORT_XRI_CN completing on xri x%x " | ||
9384 | "original iotag x%x, abort cmd iotag x%x " | ||
9385 | "status 0x%x, reason 0x%x\n", | ||
9386 | cmdiocb->iocb.un.acxri.abortContextTag, | ||
9387 | cmdiocb->iocb.un.acxri.abortIoTag, | ||
9388 | cmdiocb->iotag, rspiocb->iocb.ulpStatus, | ||
9389 | rspiocb->iocb.un.ulpWord[4]); | ||
9250 | lpfc_sli_release_iocbq(phba, cmdiocb); | 9390 | lpfc_sli_release_iocbq(phba, cmdiocb); |
9251 | return; | 9391 | return; |
9252 | } | 9392 | } |