diff options
author | James Smart <James.Smart@Emulex.Com> | 2007-04-25 09:51:38 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2007-05-06 10:33:13 -0400 |
commit | 07951076aefa4194e1dbf1d8c89eaff040c45155 (patch) | |
tree | 636052abb3f9f2a1bdc0d9adfec130b224a02289 /drivers | |
parent | 1dcb58e5680b6673bf984696d3d8b9033b6e41bf (diff) |
[SCSI] lpfc 8.1.12 : Modify ELS abort handling to prevent double completion
Modify ELS abort handling to prevent double completion
Rework portions of ELS abort handling to prevent double completion
- Rework ELS iotags and correct abort routine
- Move the (badly wrong) ELS completion logic from the initial ELS
abort request function to the ELS completion function.
- Fixup the iocb completion handling to account for the ELS abort
completions.
Signed-off-by: James Smart <James.Smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_crtn.h | 7 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 64 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 2 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_nportdisc.c | 76 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 122 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.h | 7 |
6 files changed, 97 insertions, 181 deletions
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 1251788ce2a3..4132a2dfac54 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h | |||
@@ -66,8 +66,7 @@ int lpfc_disc_state_machine(struct lpfc_hba *, struct lpfc_nodelist *, void *, | |||
66 | 66 | ||
67 | int lpfc_check_sparm(struct lpfc_hba *, struct lpfc_nodelist *, | 67 | int lpfc_check_sparm(struct lpfc_hba *, struct lpfc_nodelist *, |
68 | struct serv_parm *, uint32_t); | 68 | struct serv_parm *, uint32_t); |
69 | int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist * ndlp, | 69 | int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist * ndlp); |
70 | int); | ||
71 | int lpfc_els_abort_flogi(struct lpfc_hba *); | 70 | int lpfc_els_abort_flogi(struct lpfc_hba *); |
72 | int lpfc_initial_flogi(struct lpfc_hba *); | 71 | int lpfc_initial_flogi(struct lpfc_hba *); |
73 | int lpfc_issue_els_plogi(struct lpfc_hba *, uint32_t, uint8_t); | 72 | int lpfc_issue_els_plogi(struct lpfc_hba *, uint32_t, uint8_t); |
@@ -162,8 +161,8 @@ int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *, | |||
162 | struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *, | 161 | struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *, |
163 | struct lpfc_sli_ring *, | 162 | struct lpfc_sli_ring *, |
164 | dma_addr_t); | 163 | dma_addr_t); |
165 | int lpfc_sli_issue_abort_iotag32(struct lpfc_hba *, struct lpfc_sli_ring *, | 164 | int lpfc_sli_issue_abort_iotag(struct lpfc_hba *, struct lpfc_sli_ring *, |
166 | struct lpfc_iocbq *); | 165 | struct lpfc_iocbq *); |
167 | int lpfc_sli_sum_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t, | 166 | int lpfc_sli_sum_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t, |
168 | uint64_t, lpfc_ctx_cmd); | 167 | uint64_t, lpfc_ctx_cmd); |
169 | int lpfc_sli_abort_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t, | 168 | int lpfc_sli_abort_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t, |
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index e1c61dbb3d0f..4a9e61345693 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c | |||
@@ -582,24 +582,8 @@ lpfc_els_abort_flogi(struct lpfc_hba * phba) | |||
582 | icmd = &iocb->iocb; | 582 | icmd = &iocb->iocb; |
583 | if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR) { | 583 | if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR) { |
584 | ndlp = (struct lpfc_nodelist *)(iocb->context1); | 584 | ndlp = (struct lpfc_nodelist *)(iocb->context1); |
585 | if (ndlp && (ndlp->nlp_DID == Fabric_DID)) { | 585 | if (ndlp && (ndlp->nlp_DID == Fabric_DID)) |
586 | list_del(&iocb->list); | 586 | lpfc_sli_issue_abort_iotag(phba, pring, iocb); |
587 | pring->txcmplq_cnt--; | ||
588 | |||
589 | if ((icmd->un.elsreq64.bdl.ulpIoTag32)) { | ||
590 | lpfc_sli_issue_abort_iotag32 | ||
591 | (phba, pring, iocb); | ||
592 | } | ||
593 | if (iocb->iocb_cmpl) { | ||
594 | icmd->ulpStatus = IOSTAT_LOCAL_REJECT; | ||
595 | icmd->un.ulpWord[4] = | ||
596 | IOERR_SLI_ABORTED; | ||
597 | spin_unlock_irq(phba->host->host_lock); | ||
598 | (iocb->iocb_cmpl) (phba, iocb, iocb); | ||
599 | spin_lock_irq(phba->host->host_lock); | ||
600 | } else | ||
601 | lpfc_sli_release_iocbq(phba, iocb); | ||
602 | } | ||
603 | } | 587 | } |
604 | } | 588 | } |
605 | spin_unlock_irq(phba->host->host_lock); | 589 | spin_unlock_irq(phba->host->host_lock); |
@@ -3245,7 +3229,6 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba) | |||
3245 | struct lpfc_iocbq *tmp_iocb, *piocb; | 3229 | struct lpfc_iocbq *tmp_iocb, *piocb; |
3246 | IOCB_t *cmd = NULL; | 3230 | IOCB_t *cmd = NULL; |
3247 | struct lpfc_dmabuf *pcmd; | 3231 | struct lpfc_dmabuf *pcmd; |
3248 | struct list_head *dlp; | ||
3249 | uint32_t *elscmd; | 3232 | uint32_t *elscmd; |
3250 | uint32_t els_command; | 3233 | uint32_t els_command; |
3251 | uint32_t timeout; | 3234 | uint32_t timeout; |
@@ -3262,7 +3245,6 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba) | |||
3262 | timeout = (uint32_t)(phba->fc_ratov << 1); | 3245 | timeout = (uint32_t)(phba->fc_ratov << 1); |
3263 | 3246 | ||
3264 | pring = &phba->sli.ring[LPFC_ELS_RING]; | 3247 | pring = &phba->sli.ring[LPFC_ELS_RING]; |
3265 | dlp = &pring->txcmplq; | ||
3266 | 3248 | ||
3267 | list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) { | 3249 | list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) { |
3268 | cmd = &piocb->iocb; | 3250 | cmd = &piocb->iocb; |
@@ -3288,19 +3270,12 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba) | |||
3288 | continue; | 3270 | continue; |
3289 | } | 3271 | } |
3290 | 3272 | ||
3291 | list_del(&piocb->list); | ||
3292 | pring->txcmplq_cnt--; | ||
3293 | |||
3294 | if (cmd->ulpCommand == CMD_GEN_REQUEST64_CR) { | 3273 | if (cmd->ulpCommand == CMD_GEN_REQUEST64_CR) { |
3295 | struct lpfc_nodelist *ndlp; | 3274 | struct lpfc_nodelist *ndlp; |
3296 | spin_unlock_irq(phba->host->host_lock); | 3275 | spin_unlock_irq(phba->host->host_lock); |
3297 | ndlp = lpfc_findnode_rpi(phba, cmd->ulpContext); | 3276 | ndlp = lpfc_findnode_rpi(phba, cmd->ulpContext); |
3298 | spin_lock_irq(phba->host->host_lock); | 3277 | spin_lock_irq(phba->host->host_lock); |
3299 | remote_ID = ndlp->nlp_DID; | 3278 | remote_ID = ndlp->nlp_DID; |
3300 | if (cmd->un.elsreq64.bdl.ulpIoTag32) { | ||
3301 | lpfc_sli_issue_abort_iotag32(phba, | ||
3302 | pring, piocb); | ||
3303 | } | ||
3304 | } else { | 3279 | } else { |
3305 | remote_ID = cmd->un.elsreq64.remoteID; | 3280 | remote_ID = cmd->un.elsreq64.remoteID; |
3306 | } | 3281 | } |
@@ -3312,17 +3287,7 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba) | |||
3312 | phba->brd_no, els_command, | 3287 | phba->brd_no, els_command, |
3313 | remote_ID, cmd->ulpCommand, cmd->ulpIoTag); | 3288 | remote_ID, cmd->ulpCommand, cmd->ulpIoTag); |
3314 | 3289 | ||
3315 | /* | 3290 | lpfc_sli_issue_abort_iotag(phba, pring, piocb); |
3316 | * The iocb has timed out; abort it. | ||
3317 | */ | ||
3318 | if (piocb->iocb_cmpl) { | ||
3319 | cmd->ulpStatus = IOSTAT_LOCAL_REJECT; | ||
3320 | cmd->un.ulpWord[4] = IOERR_SLI_ABORTED; | ||
3321 | spin_unlock_irq(phba->host->host_lock); | ||
3322 | (piocb->iocb_cmpl) (phba, piocb, piocb); | ||
3323 | spin_lock_irq(phba->host->host_lock); | ||
3324 | } else | ||
3325 | lpfc_sli_release_iocbq(phba, piocb); | ||
3326 | } | 3291 | } |
3327 | if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt) | 3292 | if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt) |
3328 | mod_timer(&phba->els_tmofunc, jiffies + HZ * timeout); | 3293 | mod_timer(&phba->els_tmofunc, jiffies + HZ * timeout); |
@@ -3336,9 +3301,6 @@ lpfc_els_flush_cmd(struct lpfc_hba * phba) | |||
3336 | struct lpfc_sli_ring *pring; | 3301 | struct lpfc_sli_ring *pring; |
3337 | struct lpfc_iocbq *tmp_iocb, *piocb; | 3302 | struct lpfc_iocbq *tmp_iocb, *piocb; |
3338 | IOCB_t *cmd = NULL; | 3303 | IOCB_t *cmd = NULL; |
3339 | struct lpfc_dmabuf *pcmd; | ||
3340 | uint32_t *elscmd; | ||
3341 | uint32_t els_command; | ||
3342 | 3304 | ||
3343 | pring = &phba->sli.ring[LPFC_ELS_RING]; | 3305 | pring = &phba->sli.ring[LPFC_ELS_RING]; |
3344 | spin_lock_irq(phba->host->host_lock); | 3306 | spin_lock_irq(phba->host->host_lock); |
@@ -3357,10 +3319,6 @@ lpfc_els_flush_cmd(struct lpfc_hba * phba) | |||
3357 | continue; | 3319 | continue; |
3358 | } | 3320 | } |
3359 | 3321 | ||
3360 | pcmd = (struct lpfc_dmabuf *) piocb->context2; | ||
3361 | elscmd = (uint32_t *) (pcmd->virt); | ||
3362 | els_command = *elscmd; | ||
3363 | |||
3364 | list_del(&piocb->list); | 3322 | list_del(&piocb->list); |
3365 | pring->txq_cnt--; | 3323 | pring->txq_cnt--; |
3366 | 3324 | ||
@@ -3381,22 +3339,8 @@ lpfc_els_flush_cmd(struct lpfc_hba * phba) | |||
3381 | if (piocb->iocb_flag & LPFC_IO_LIBDFC) { | 3339 | if (piocb->iocb_flag & LPFC_IO_LIBDFC) { |
3382 | continue; | 3340 | continue; |
3383 | } | 3341 | } |
3384 | pcmd = (struct lpfc_dmabuf *) piocb->context2; | ||
3385 | elscmd = (uint32_t *) (pcmd->virt); | ||
3386 | els_command = *elscmd; | ||
3387 | |||
3388 | list_del(&piocb->list); | ||
3389 | pring->txcmplq_cnt--; | ||
3390 | 3342 | ||
3391 | cmd->ulpStatus = IOSTAT_LOCAL_REJECT; | 3343 | lpfc_sli_issue_abort_iotag(phba, pring, piocb); |
3392 | cmd->un.ulpWord[4] = IOERR_SLI_ABORTED; | ||
3393 | |||
3394 | if (piocb->iocb_cmpl) { | ||
3395 | spin_unlock_irq(phba->host->host_lock); | ||
3396 | (piocb->iocb_cmpl) (phba, piocb, piocb); | ||
3397 | spin_lock_irq(phba->host->host_lock); | ||
3398 | } else | ||
3399 | lpfc_sli_release_iocbq(phba, piocb); | ||
3400 | } | 3344 | } |
3401 | spin_unlock_irq(phba->host->host_lock); | 3345 | spin_unlock_irq(phba->host->host_lock); |
3402 | return; | 3346 | return; |
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index bd7bbedb941e..485a13fa527d 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c | |||
@@ -1596,7 +1596,7 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) | |||
1596 | } | 1596 | } |
1597 | spin_unlock_irq(phba->host->host_lock); | 1597 | spin_unlock_irq(phba->host->host_lock); |
1598 | 1598 | ||
1599 | lpfc_els_abort(phba,ndlp,0); | 1599 | lpfc_els_abort(phba,ndlp); |
1600 | spin_lock_irq(phba->host->host_lock); | 1600 | spin_lock_irq(phba->host->host_lock); |
1601 | ndlp->nlp_flag &= ~NLP_DELAY_TMO; | 1601 | ndlp->nlp_flag &= ~NLP_DELAY_TMO; |
1602 | spin_unlock_irq(phba->host->host_lock); | 1602 | spin_unlock_irq(phba->host->host_lock); |
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 0c7e731dc45a..aa7f446c8da1 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c | |||
@@ -168,8 +168,7 @@ lpfc_check_elscmpl_iocb(struct lpfc_hba * phba, | |||
168 | * routine effectively results in a "software abort". | 168 | * routine effectively results in a "software abort". |
169 | */ | 169 | */ |
170 | int | 170 | int |
171 | lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, | 171 | lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) |
172 | int send_abts) | ||
173 | { | 172 | { |
174 | struct lpfc_sli *psli; | 173 | struct lpfc_sli *psli; |
175 | struct lpfc_sli_ring *pring; | 174 | struct lpfc_sli_ring *pring; |
@@ -215,48 +214,17 @@ lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, | |||
215 | spin_unlock_irq(phba->host->host_lock); | 214 | spin_unlock_irq(phba->host->host_lock); |
216 | } while (found); | 215 | } while (found); |
217 | 216 | ||
218 | /* Everything on txcmplq will be returned by firmware | ||
219 | * with a no rpi / linkdown / abort error. For ring 0, | ||
220 | * ELS discovery, we want to get rid of it right here. | ||
221 | */ | ||
222 | /* Next check the txcmplq */ | 217 | /* Next check the txcmplq */ |
223 | do { | 218 | spin_lock_irq(phba->host->host_lock); |
224 | found = 0; | 219 | list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) { |
225 | spin_lock_irq(phba->host->host_lock); | 220 | /* Check to see if iocb matches the nport we are looking |
226 | list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, | 221 | for */ |
227 | list) { | 222 | if ((lpfc_check_sli_ndlp (phba, pring, iocb, ndlp))) { |
228 | /* Check to see if iocb matches the nport we are looking | 223 | icmd = &iocb->iocb; |
229 | for */ | 224 | lpfc_sli_issue_abort_iotag(phba, pring, iocb); |
230 | if ((lpfc_check_sli_ndlp (phba, pring, iocb, ndlp))) { | ||
231 | found = 1; | ||
232 | /* It matches, so deque and call compl with an | ||
233 | error */ | ||
234 | list_del(&iocb->list); | ||
235 | pring->txcmplq_cnt--; | ||
236 | |||
237 | icmd = &iocb->iocb; | ||
238 | /* If the driver is completing an ELS | ||
239 | * command early, flush it out of the firmware. | ||
240 | */ | ||
241 | if (send_abts && | ||
242 | (icmd->ulpCommand == CMD_ELS_REQUEST64_CR) && | ||
243 | (icmd->un.elsreq64.bdl.ulpIoTag32)) { | ||
244 | lpfc_sli_issue_abort_iotag32(phba, | ||
245 | pring, iocb); | ||
246 | } | ||
247 | if (iocb->iocb_cmpl) { | ||
248 | icmd->ulpStatus = IOSTAT_LOCAL_REJECT; | ||
249 | icmd->un.ulpWord[4] = IOERR_SLI_ABORTED; | ||
250 | spin_unlock_irq(phba->host->host_lock); | ||
251 | (iocb->iocb_cmpl) (phba, iocb, iocb); | ||
252 | spin_lock_irq(phba->host->host_lock); | ||
253 | } else | ||
254 | lpfc_sli_release_iocbq(phba, iocb); | ||
255 | break; | ||
256 | } | ||
257 | } | 225 | } |
258 | spin_unlock_irq(phba->host->host_lock); | 226 | } |
259 | } while(found); | 227 | spin_unlock_irq(phba->host->host_lock); |
260 | 228 | ||
261 | /* If we are delaying issuing an ELS command, cancel it */ | 229 | /* If we are delaying issuing an ELS command, cancel it */ |
262 | if (ndlp->nlp_flag & NLP_DELAY_TMO) | 230 | if (ndlp->nlp_flag & NLP_DELAY_TMO) |
@@ -404,7 +372,7 @@ lpfc_rcv_plogi(struct lpfc_hba * phba, | |||
404 | */ | 372 | */ |
405 | if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) { | 373 | if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) { |
406 | /* software abort outstanding PLOGI */ | 374 | /* software abort outstanding PLOGI */ |
407 | lpfc_els_abort(phba, ndlp, 1); | 375 | lpfc_els_abort(phba, ndlp); |
408 | } | 376 | } |
409 | 377 | ||
410 | lpfc_els_rsp_acc(phba, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox, 0); | 378 | lpfc_els_rsp_acc(phba, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox, 0); |
@@ -697,7 +665,7 @@ lpfc_rcv_logo_plogi_issue(struct lpfc_hba * phba, | |||
697 | cmdiocb = (struct lpfc_iocbq *) arg; | 665 | cmdiocb = (struct lpfc_iocbq *) arg; |
698 | 666 | ||
699 | /* software abort outstanding PLOGI */ | 667 | /* software abort outstanding PLOGI */ |
700 | lpfc_els_abort(phba, ndlp, 1); | 668 | lpfc_els_abort(phba, ndlp); |
701 | 669 | ||
702 | lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO); | 670 | lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO); |
703 | return ndlp->nlp_state; | 671 | return ndlp->nlp_state; |
@@ -712,7 +680,7 @@ lpfc_rcv_els_plogi_issue(struct lpfc_hba * phba, | |||
712 | cmdiocb = (struct lpfc_iocbq *) arg; | 680 | cmdiocb = (struct lpfc_iocbq *) arg; |
713 | 681 | ||
714 | /* software abort outstanding PLOGI */ | 682 | /* software abort outstanding PLOGI */ |
715 | lpfc_els_abort(phba, ndlp, 1); | 683 | lpfc_els_abort(phba, ndlp); |
716 | 684 | ||
717 | if (evt == NLP_EVT_RCV_LOGO) { | 685 | if (evt == NLP_EVT_RCV_LOGO) { |
718 | lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0); | 686 | lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0); |
@@ -855,7 +823,7 @@ lpfc_device_rm_plogi_issue(struct lpfc_hba * phba, | |||
855 | } | 823 | } |
856 | else { | 824 | else { |
857 | /* software abort outstanding PLOGI */ | 825 | /* software abort outstanding PLOGI */ |
858 | lpfc_els_abort(phba, ndlp, 1); | 826 | lpfc_els_abort(phba, ndlp); |
859 | 827 | ||
860 | lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); | 828 | lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); |
861 | return NLP_STE_FREED_NODE; | 829 | return NLP_STE_FREED_NODE; |
@@ -868,7 +836,7 @@ lpfc_device_recov_plogi_issue(struct lpfc_hba * phba, | |||
868 | uint32_t evt) | 836 | uint32_t evt) |
869 | { | 837 | { |
870 | /* software abort outstanding PLOGI */ | 838 | /* software abort outstanding PLOGI */ |
871 | lpfc_els_abort(phba, ndlp, 1); | 839 | lpfc_els_abort(phba, ndlp); |
872 | 840 | ||
873 | ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE; | 841 | ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE; |
874 | ndlp->nlp_state = NLP_STE_NPR_NODE; | 842 | ndlp->nlp_state = NLP_STE_NPR_NODE; |
@@ -888,7 +856,7 @@ lpfc_rcv_plogi_adisc_issue(struct lpfc_hba * phba, | |||
888 | struct lpfc_iocbq *cmdiocb; | 856 | struct lpfc_iocbq *cmdiocb; |
889 | 857 | ||
890 | /* software abort outstanding ADISC */ | 858 | /* software abort outstanding ADISC */ |
891 | lpfc_els_abort(phba, ndlp, 1); | 859 | lpfc_els_abort(phba, ndlp); |
892 | 860 | ||
893 | cmdiocb = (struct lpfc_iocbq *) arg; | 861 | cmdiocb = (struct lpfc_iocbq *) arg; |
894 | 862 | ||
@@ -926,7 +894,7 @@ lpfc_rcv_logo_adisc_issue(struct lpfc_hba * phba, | |||
926 | cmdiocb = (struct lpfc_iocbq *) arg; | 894 | cmdiocb = (struct lpfc_iocbq *) arg; |
927 | 895 | ||
928 | /* software abort outstanding ADISC */ | 896 | /* software abort outstanding ADISC */ |
929 | lpfc_els_abort(phba, ndlp, 0); | 897 | lpfc_els_abort(phba, ndlp); |
930 | 898 | ||
931 | lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO); | 899 | lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO); |
932 | return ndlp->nlp_state; | 900 | return ndlp->nlp_state; |
@@ -1016,7 +984,7 @@ lpfc_device_rm_adisc_issue(struct lpfc_hba * phba, | |||
1016 | } | 984 | } |
1017 | else { | 985 | else { |
1018 | /* software abort outstanding ADISC */ | 986 | /* software abort outstanding ADISC */ |
1019 | lpfc_els_abort(phba, ndlp, 1); | 987 | lpfc_els_abort(phba, ndlp); |
1020 | 988 | ||
1021 | lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); | 989 | lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); |
1022 | return NLP_STE_FREED_NODE; | 990 | return NLP_STE_FREED_NODE; |
@@ -1029,7 +997,7 @@ lpfc_device_recov_adisc_issue(struct lpfc_hba * phba, | |||
1029 | uint32_t evt) | 997 | uint32_t evt) |
1030 | { | 998 | { |
1031 | /* software abort outstanding ADISC */ | 999 | /* software abort outstanding ADISC */ |
1032 | lpfc_els_abort(phba, ndlp, 1); | 1000 | lpfc_els_abort(phba, ndlp); |
1033 | 1001 | ||
1034 | ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; | 1002 | ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; |
1035 | ndlp->nlp_state = NLP_STE_NPR_NODE; | 1003 | ndlp->nlp_state = NLP_STE_NPR_NODE; |
@@ -1230,7 +1198,7 @@ lpfc_rcv_logo_prli_issue(struct lpfc_hba * phba, | |||
1230 | cmdiocb = (struct lpfc_iocbq *) arg; | 1198 | cmdiocb = (struct lpfc_iocbq *) arg; |
1231 | 1199 | ||
1232 | /* Software abort outstanding PRLI before sending acc */ | 1200 | /* Software abort outstanding PRLI before sending acc */ |
1233 | lpfc_els_abort(phba, ndlp, 1); | 1201 | lpfc_els_abort(phba, ndlp); |
1234 | 1202 | ||
1235 | lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO); | 1203 | lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO); |
1236 | return ndlp->nlp_state; | 1204 | return ndlp->nlp_state; |
@@ -1330,7 +1298,7 @@ lpfc_device_rm_prli_issue(struct lpfc_hba * phba, | |||
1330 | } | 1298 | } |
1331 | else { | 1299 | else { |
1332 | /* software abort outstanding PLOGI */ | 1300 | /* software abort outstanding PLOGI */ |
1333 | lpfc_els_abort(phba, ndlp, 1); | 1301 | lpfc_els_abort(phba, ndlp); |
1334 | 1302 | ||
1335 | lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); | 1303 | lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); |
1336 | return NLP_STE_FREED_NODE; | 1304 | return NLP_STE_FREED_NODE; |
@@ -1359,7 +1327,7 @@ lpfc_device_recov_prli_issue(struct lpfc_hba * phba, | |||
1359 | struct lpfc_nodelist * ndlp, void *arg, uint32_t evt) | 1327 | struct lpfc_nodelist * ndlp, void *arg, uint32_t evt) |
1360 | { | 1328 | { |
1361 | /* software abort outstanding PRLI */ | 1329 | /* software abort outstanding PRLI */ |
1362 | lpfc_els_abort(phba, ndlp, 1); | 1330 | lpfc_els_abort(phba, ndlp); |
1363 | 1331 | ||
1364 | ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; | 1332 | ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; |
1365 | ndlp->nlp_state = NLP_STE_NPR_NODE; | 1333 | ndlp->nlp_state = NLP_STE_NPR_NODE; |
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 54a8f4d3db13..dcd313ab4a72 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c | |||
@@ -816,6 +816,14 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, | |||
816 | * All other are passed to the completion callback. | 816 | * All other are passed to the completion callback. |
817 | */ | 817 | */ |
818 | if (pring->ringno == LPFC_ELS_RING) { | 818 | if (pring->ringno == LPFC_ELS_RING) { |
819 | if (cmdiocbp->iocb_flag & LPFC_DRIVER_ABORTED) { | ||
820 | cmdiocbp->iocb_flag &= | ||
821 | ~LPFC_DRIVER_ABORTED; | ||
822 | saveq->iocb.ulpStatus = | ||
823 | IOSTAT_LOCAL_REJECT; | ||
824 | saveq->iocb.un.ulpWord[4] = | ||
825 | IOERR_SLI_ABORTED; | ||
826 | } | ||
819 | spin_unlock_irqrestore(phba->host->host_lock, | 827 | spin_unlock_irqrestore(phba->host->host_lock, |
820 | iflag); | 828 | iflag); |
821 | (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq); | 829 | (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq); |
@@ -2728,85 +2736,81 @@ lpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
2728 | } | 2736 | } |
2729 | 2737 | ||
2730 | static void | 2738 | static void |
2731 | lpfc_sli_abort_elsreq_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, | 2739 | lpfc_sli_abort_els_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, |
2732 | struct lpfc_iocbq * rspiocb) | 2740 | struct lpfc_iocbq * rspiocb) |
2733 | { | 2741 | { |
2734 | struct lpfc_dmabuf *buf_ptr, *buf_ptr1; | 2742 | spin_lock_irq(phba->host->host_lock); |
2735 | /* Free the resources associated with the ELS_REQUEST64 IOCB the driver | ||
2736 | * just aborted. | ||
2737 | * In this case, context2 = cmd, context2->next = rsp, context3 = bpl | ||
2738 | */ | ||
2739 | if (cmdiocb->context2) { | ||
2740 | buf_ptr1 = (struct lpfc_dmabuf *) cmdiocb->context2; | ||
2741 | |||
2742 | /* Free the response IOCB before completing the abort | ||
2743 | command. */ | ||
2744 | buf_ptr = NULL; | ||
2745 | list_remove_head((&buf_ptr1->list), buf_ptr, | ||
2746 | struct lpfc_dmabuf, list); | ||
2747 | if (buf_ptr) { | ||
2748 | lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); | ||
2749 | kfree(buf_ptr); | ||
2750 | } | ||
2751 | lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys); | ||
2752 | kfree(buf_ptr1); | ||
2753 | } | ||
2754 | |||
2755 | if (cmdiocb->context3) { | ||
2756 | buf_ptr = (struct lpfc_dmabuf *) cmdiocb->context3; | ||
2757 | lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); | ||
2758 | kfree(buf_ptr); | ||
2759 | } | ||
2760 | |||
2761 | lpfc_sli_release_iocbq(phba, cmdiocb); | 2743 | lpfc_sli_release_iocbq(phba, cmdiocb); |
2744 | spin_unlock_irq(phba->host->host_lock); | ||
2762 | return; | 2745 | return; |
2763 | } | 2746 | } |
2764 | 2747 | ||
2765 | int | 2748 | int |
2766 | lpfc_sli_issue_abort_iotag32(struct lpfc_hba * phba, | 2749 | lpfc_sli_issue_abort_iotag(struct lpfc_hba * phba, |
2767 | struct lpfc_sli_ring * pring, | 2750 | struct lpfc_sli_ring * pring, |
2768 | struct lpfc_iocbq * cmdiocb) | 2751 | struct lpfc_iocbq * cmdiocb) |
2769 | { | 2752 | { |
2770 | struct lpfc_iocbq *abtsiocbp; | 2753 | struct lpfc_iocbq *abtsiocbp; |
2771 | IOCB_t *icmd = NULL; | 2754 | IOCB_t *icmd = NULL; |
2772 | IOCB_t *iabt = NULL; | 2755 | IOCB_t *iabt = NULL; |
2756 | int retval = IOCB_ERROR; | ||
2757 | |||
2758 | /* There are certain command types we don't want | ||
2759 | * to abort. | ||
2760 | */ | ||
2761 | icmd = &cmdiocb->iocb; | ||
2762 | if ((icmd->ulpCommand == CMD_ABORT_XRI_CN) || | ||
2763 | (icmd->ulpCommand == CMD_CLOSE_XRI_CN)) | ||
2764 | return 0; | ||
2765 | |||
2766 | /* If we're unloading, interrupts are disabled so we | ||
2767 | * need to cleanup the iocb here. | ||
2768 | */ | ||
2769 | if (phba->fc_flag & FC_UNLOADING) | ||
2770 | goto abort_iotag_exit; | ||
2773 | 2771 | ||
2774 | /* issue ABTS for this IOCB based on iotag */ | 2772 | /* issue ABTS for this IOCB based on iotag */ |
2775 | abtsiocbp = lpfc_sli_get_iocbq(phba); | 2773 | abtsiocbp = lpfc_sli_get_iocbq(phba); |
2776 | if (abtsiocbp == NULL) | 2774 | if (abtsiocbp == NULL) |
2777 | return 0; | 2775 | return 0; |
2778 | 2776 | ||
2777 | /* This signals the response to set the correct status | ||
2778 | * before calling the completion handler. | ||
2779 | */ | ||
2780 | cmdiocb->iocb_flag |= LPFC_DRIVER_ABORTED; | ||
2781 | |||
2779 | iabt = &abtsiocbp->iocb; | 2782 | iabt = &abtsiocbp->iocb; |
2780 | icmd = &cmdiocb->iocb; | 2783 | iabt->un.acxri.abortType = ABORT_TYPE_ABTS; |
2781 | switch (icmd->ulpCommand) { | 2784 | iabt->un.acxri.abortContextTag = icmd->ulpContext; |
2782 | case CMD_ELS_REQUEST64_CR: | 2785 | iabt->un.acxri.abortIoTag = icmd->ulpIoTag; |
2783 | /* Even though we abort the ELS command, the firmware may access | 2786 | iabt->ulpLe = 1; |
2784 | * the BPL or other resources before it processes our | 2787 | iabt->ulpClass = icmd->ulpClass; |
2785 | * ABORT_MXRI64. Thus we must delay reusing the cmdiocb | ||
2786 | * resources till the actual abort request completes. | ||
2787 | */ | ||
2788 | abtsiocbp->context1 = (void *)((unsigned long)icmd->ulpCommand); | ||
2789 | abtsiocbp->context2 = cmdiocb->context2; | ||
2790 | abtsiocbp->context3 = cmdiocb->context3; | ||
2791 | cmdiocb->context2 = NULL; | ||
2792 | cmdiocb->context3 = NULL; | ||
2793 | abtsiocbp->iocb_cmpl = lpfc_sli_abort_elsreq_cmpl; | ||
2794 | break; | ||
2795 | default: | ||
2796 | lpfc_sli_release_iocbq(phba, abtsiocbp); | ||
2797 | return 0; | ||
2798 | } | ||
2799 | 2788 | ||
2800 | iabt->un.amxri.abortType = ABORT_TYPE_ABTS; | 2789 | if (phba->hba_state >= LPFC_LINK_UP) |
2801 | iabt->un.amxri.iotag32 = icmd->un.elsreq64.bdl.ulpIoTag32; | 2790 | iabt->ulpCommand = CMD_ABORT_XRI_CN; |
2791 | else | ||
2792 | iabt->ulpCommand = CMD_CLOSE_XRI_CN; | ||
2802 | 2793 | ||
2803 | iabt->ulpLe = 1; | 2794 | abtsiocbp->iocb_cmpl = lpfc_sli_abort_els_cmpl; |
2804 | iabt->ulpClass = CLASS3; | 2795 | retval = lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0); |
2805 | iabt->ulpCommand = CMD_ABORT_MXRI64_CN; | ||
2806 | 2796 | ||
2807 | if (lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0) == IOCB_ERROR) { | 2797 | abort_iotag_exit: |
2808 | lpfc_sli_release_iocbq(phba, abtsiocbp); | 2798 | |
2809 | return 0; | 2799 | /* If we could not issue an abort dequeue the iocb and handle |
2800 | * the completion here. | ||
2801 | */ | ||
2802 | if (retval == IOCB_ERROR) { | ||
2803 | list_del(&cmdiocb->list); | ||
2804 | pring->txcmplq_cnt--; | ||
2805 | |||
2806 | if (cmdiocb->iocb_cmpl) { | ||
2807 | icmd->ulpStatus = IOSTAT_LOCAL_REJECT; | ||
2808 | icmd->un.ulpWord[4] = IOERR_SLI_ABORTED; | ||
2809 | spin_unlock_irq(phba->host->host_lock); | ||
2810 | (cmdiocb->iocb_cmpl) (phba, cmdiocb, cmdiocb); | ||
2811 | spin_lock_irq(phba->host->host_lock); | ||
2812 | } else | ||
2813 | lpfc_sli_release_iocbq(phba, cmdiocb); | ||
2810 | } | 2814 | } |
2811 | 2815 | ||
2812 | return 1; | 2816 | return 1; |
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index a43549959dc7..10dd5a9ddfd3 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h | |||
@@ -39,9 +39,10 @@ struct lpfc_iocbq { | |||
39 | IOCB_t iocb; /* IOCB cmd */ | 39 | IOCB_t iocb; /* IOCB cmd */ |
40 | uint8_t retry; /* retry counter for IOCB cmd - if needed */ | 40 | uint8_t retry; /* retry counter for IOCB cmd - if needed */ |
41 | uint8_t iocb_flag; | 41 | uint8_t iocb_flag; |
42 | #define LPFC_IO_LIBDFC 1 /* libdfc iocb */ | 42 | #define LPFC_IO_LIBDFC 1 /* libdfc iocb */ |
43 | #define LPFC_IO_WAKE 2 /* High Priority Queue signal flag */ | 43 | #define LPFC_IO_WAKE 2 /* High Priority Queue signal flag */ |
44 | #define LPFC_IO_FCP 4 /* FCP command -- iocbq in scsi_buf */ | 44 | #define LPFC_IO_FCP 4 /* FCP command -- iocbq in scsi_buf */ |
45 | #define LPFC_DRIVER_ABORTED 8 /* driver aborted this request */ | ||
45 | 46 | ||
46 | uint8_t abort_count; | 47 | uint8_t abort_count; |
47 | uint8_t rsvd2; | 48 | uint8_t rsvd2; |