diff options
author | James Smart <james.smart@emulex.com> | 2013-12-17 20:29:36 -0500 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2014-03-15 13:18:55 -0400 |
commit | 0976e1a650bdcdf235808e35c96eee70081c079d (patch) | |
tree | 1f8fd11826c0c5c3d562efd63e47266fd896a2af /drivers/scsi/lpfc | |
parent | 646a2dd7515177376cf12aeb60bd6d462d61c5b8 (diff) |
[SCSI] lpfc 8.3.44: Fix Crash in lpfc_els_timeout_handler
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_els.c | 101 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_nportdisc.c | 56 |
2 files changed, 84 insertions, 73 deletions
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 110445f0c58d..647f4f3b3748 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c | |||
@@ -6223,19 +6223,17 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport) | |||
6223 | uint32_t els_command = 0; | 6223 | uint32_t els_command = 0; |
6224 | uint32_t timeout; | 6224 | uint32_t timeout; |
6225 | uint32_t remote_ID = 0xffffffff; | 6225 | uint32_t remote_ID = 0xffffffff; |
6226 | LIST_HEAD(txcmplq_completions); | ||
6227 | LIST_HEAD(abort_list); | 6226 | LIST_HEAD(abort_list); |
6228 | 6227 | ||
6229 | 6228 | ||
6230 | timeout = (uint32_t)(phba->fc_ratov << 1); | 6229 | timeout = (uint32_t)(phba->fc_ratov << 1); |
6231 | 6230 | ||
6232 | pring = &phba->sli.ring[LPFC_ELS_RING]; | 6231 | pring = &phba->sli.ring[LPFC_ELS_RING]; |
6233 | |||
6234 | spin_lock_irq(&phba->hbalock); | 6232 | spin_lock_irq(&phba->hbalock); |
6235 | list_splice_init(&pring->txcmplq, &txcmplq_completions); | 6233 | if (phba->sli_rev == LPFC_SLI_REV4) |
6236 | spin_unlock_irq(&phba->hbalock); | 6234 | spin_lock(&pring->ring_lock); |
6237 | 6235 | ||
6238 | list_for_each_entry_safe(piocb, tmp_iocb, &txcmplq_completions, list) { | 6236 | list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) { |
6239 | cmd = &piocb->iocb; | 6237 | cmd = &piocb->iocb; |
6240 | 6238 | ||
6241 | if ((piocb->iocb_flag & LPFC_IO_LIBDFC) != 0 || | 6239 | if ((piocb->iocb_flag & LPFC_IO_LIBDFC) != 0 || |
@@ -6274,8 +6272,8 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport) | |||
6274 | } | 6272 | } |
6275 | list_add_tail(&piocb->dlist, &abort_list); | 6273 | list_add_tail(&piocb->dlist, &abort_list); |
6276 | } | 6274 | } |
6277 | spin_lock_irq(&phba->hbalock); | 6275 | if (phba->sli_rev == LPFC_SLI_REV4) |
6278 | list_splice(&txcmplq_completions, &pring->txcmplq); | 6276 | spin_unlock(&pring->ring_lock); |
6279 | spin_unlock_irq(&phba->hbalock); | 6277 | spin_unlock_irq(&phba->hbalock); |
6280 | 6278 | ||
6281 | list_for_each_entry_safe(piocb, tmp_iocb, &abort_list, dlist) { | 6279 | list_for_each_entry_safe(piocb, tmp_iocb, &abort_list, dlist) { |
@@ -6317,15 +6315,50 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport) | |||
6317 | void | 6315 | void |
6318 | lpfc_els_flush_cmd(struct lpfc_vport *vport) | 6316 | lpfc_els_flush_cmd(struct lpfc_vport *vport) |
6319 | { | 6317 | { |
6320 | LIST_HEAD(completions); | 6318 | LIST_HEAD(abort_list); |
6321 | struct lpfc_hba *phba = vport->phba; | 6319 | struct lpfc_hba *phba = vport->phba; |
6322 | struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; | 6320 | struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; |
6323 | struct lpfc_iocbq *tmp_iocb, *piocb; | 6321 | struct lpfc_iocbq *tmp_iocb, *piocb; |
6324 | IOCB_t *cmd = NULL; | 6322 | IOCB_t *cmd = NULL; |
6325 | 6323 | ||
6326 | lpfc_fabric_abort_vport(vport); | 6324 | lpfc_fabric_abort_vport(vport); |
6325 | /* | ||
6326 | * For SLI3, only the hbalock is required. But SLI4 needs to coordinate | ||
6327 | * with the ring insert operation. Because lpfc_sli_issue_abort_iotag | ||
6328 | * ultimately grabs the ring_lock, the driver must splice the list into | ||
6329 | * a working list and release the locks before calling the abort. | ||
6330 | */ | ||
6331 | spin_lock_irq(&phba->hbalock); | ||
6332 | if (phba->sli_rev == LPFC_SLI_REV4) | ||
6333 | spin_lock(&pring->ring_lock); | ||
6334 | |||
6335 | list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) { | ||
6336 | if (piocb->iocb_flag & LPFC_IO_LIBDFC) | ||
6337 | continue; | ||
6338 | |||
6339 | if (piocb->vport != vport) | ||
6340 | continue; | ||
6341 | list_add_tail(&piocb->dlist, &abort_list); | ||
6342 | } | ||
6343 | if (phba->sli_rev == LPFC_SLI_REV4) | ||
6344 | spin_unlock(&pring->ring_lock); | ||
6345 | spin_unlock_irq(&phba->hbalock); | ||
6346 | /* Abort each iocb on the aborted list and remove the dlist links. */ | ||
6347 | list_for_each_entry_safe(piocb, tmp_iocb, &abort_list, dlist) { | ||
6348 | spin_lock_irq(&phba->hbalock); | ||
6349 | list_del_init(&piocb->dlist); | ||
6350 | lpfc_sli_issue_abort_iotag(phba, pring, piocb); | ||
6351 | spin_unlock_irq(&phba->hbalock); | ||
6352 | } | ||
6353 | if (!list_empty(&abort_list)) | ||
6354 | lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, | ||
6355 | "3387 abort list for txq not empty\n"); | ||
6356 | INIT_LIST_HEAD(&abort_list); | ||
6327 | 6357 | ||
6328 | spin_lock_irq(&phba->hbalock); | 6358 | spin_lock_irq(&phba->hbalock); |
6359 | if (phba->sli_rev == LPFC_SLI_REV4) | ||
6360 | spin_lock(&pring->ring_lock); | ||
6361 | |||
6329 | list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) { | 6362 | list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) { |
6330 | cmd = &piocb->iocb; | 6363 | cmd = &piocb->iocb; |
6331 | 6364 | ||
@@ -6343,24 +6376,16 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport) | |||
6343 | if (piocb->vport != vport) | 6376 | if (piocb->vport != vport) |
6344 | continue; | 6377 | continue; |
6345 | 6378 | ||
6346 | list_move_tail(&piocb->list, &completions); | 6379 | list_del_init(&piocb->list); |
6347 | } | 6380 | list_add_tail(&piocb->list, &abort_list); |
6348 | |||
6349 | list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) { | ||
6350 | if (piocb->iocb_flag & LPFC_IO_LIBDFC) { | ||
6351 | continue; | ||
6352 | } | ||
6353 | |||
6354 | if (piocb->vport != vport) | ||
6355 | continue; | ||
6356 | |||
6357 | lpfc_sli_issue_abort_iotag(phba, pring, piocb); | ||
6358 | } | 6381 | } |
6382 | if (phba->sli_rev == LPFC_SLI_REV4) | ||
6383 | spin_unlock(&pring->ring_lock); | ||
6359 | spin_unlock_irq(&phba->hbalock); | 6384 | spin_unlock_irq(&phba->hbalock); |
6360 | 6385 | ||
6361 | /* Cancell all the IOCBs from the completions list */ | 6386 | /* Cancell all the IOCBs from the completions list */ |
6362 | lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, | 6387 | lpfc_sli_cancel_iocbs(phba, &abort_list, |
6363 | IOERR_SLI_ABORTED); | 6388 | IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED); |
6364 | 6389 | ||
6365 | return; | 6390 | return; |
6366 | } | 6391 | } |
@@ -6385,35 +6410,9 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport) | |||
6385 | void | 6410 | void |
6386 | lpfc_els_flush_all_cmd(struct lpfc_hba *phba) | 6411 | lpfc_els_flush_all_cmd(struct lpfc_hba *phba) |
6387 | { | 6412 | { |
6388 | LIST_HEAD(completions); | 6413 | struct lpfc_vport *vport; |
6389 | struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; | 6414 | list_for_each_entry(vport, &phba->port_list, listentry) |
6390 | struct lpfc_iocbq *tmp_iocb, *piocb; | 6415 | lpfc_els_flush_cmd(vport); |
6391 | IOCB_t *cmd = NULL; | ||
6392 | |||
6393 | lpfc_fabric_abort_hba(phba); | ||
6394 | spin_lock_irq(&phba->hbalock); | ||
6395 | list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) { | ||
6396 | cmd = &piocb->iocb; | ||
6397 | if (piocb->iocb_flag & LPFC_IO_LIBDFC) | ||
6398 | continue; | ||
6399 | /* Do not flush out the QUE_RING and ABORT/CLOSE iocbs */ | ||
6400 | if (cmd->ulpCommand == CMD_QUE_RING_BUF_CN || | ||
6401 | cmd->ulpCommand == CMD_QUE_RING_BUF64_CN || | ||
6402 | cmd->ulpCommand == CMD_CLOSE_XRI_CN || | ||
6403 | cmd->ulpCommand == CMD_ABORT_XRI_CN) | ||
6404 | continue; | ||
6405 | list_move_tail(&piocb->list, &completions); | ||
6406 | } | ||
6407 | list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) { | ||
6408 | if (piocb->iocb_flag & LPFC_IO_LIBDFC) | ||
6409 | continue; | ||
6410 | lpfc_sli_issue_abort_iotag(phba, pring, piocb); | ||
6411 | } | ||
6412 | spin_unlock_irq(&phba->hbalock); | ||
6413 | |||
6414 | /* Cancel all the IOCBs from the completions list */ | ||
6415 | lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, | ||
6416 | IOERR_SLI_ABORTED); | ||
6417 | 6416 | ||
6418 | return; | 6417 | return; |
6419 | } | 6418 | } |
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index abc361259d6d..c342f6afd747 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c | |||
@@ -203,8 +203,6 @@ lpfc_check_elscmpl_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
203 | int | 203 | int |
204 | lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) | 204 | lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) |
205 | { | 205 | { |
206 | LIST_HEAD(completions); | ||
207 | LIST_HEAD(txcmplq_completions); | ||
208 | LIST_HEAD(abort_list); | 206 | LIST_HEAD(abort_list); |
209 | struct lpfc_sli *psli = &phba->sli; | 207 | struct lpfc_sli *psli = &phba->sli; |
210 | struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING]; | 208 | struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING]; |
@@ -216,32 +214,27 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) | |||
216 | "Data: x%x x%x x%x\n", | 214 | "Data: x%x x%x x%x\n", |
217 | ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, | 215 | ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, |
218 | ndlp->nlp_rpi); | 216 | ndlp->nlp_rpi); |
219 | 217 | /* Clean up all fabric IOs first.*/ | |
220 | lpfc_fabric_abort_nport(ndlp); | 218 | lpfc_fabric_abort_nport(ndlp); |
221 | 219 | ||
222 | /* First check the txq */ | 220 | /* |
221 | * Lock the ELS ring txcmplq for SLI3/SLI4 and build a local list | ||
222 | * of all ELS IOs that need an ABTS. The IOs need to stay on the | ||
223 | * txcmplq so that the abort operation completes them successfully. | ||
224 | */ | ||
223 | spin_lock_irq(&phba->hbalock); | 225 | spin_lock_irq(&phba->hbalock); |
224 | list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) { | 226 | if (phba->sli_rev == LPFC_SLI_REV4) |
225 | /* Check to see if iocb matches the nport we are looking for */ | 227 | spin_lock(&pring->ring_lock); |
226 | if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) { | 228 | list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) { |
227 | /* It matches, so deque and call compl with anp error */ | 229 | /* Add to abort_list on on NDLP match. */ |
228 | list_move_tail(&iocb->list, &completions); | ||
229 | } | ||
230 | } | ||
231 | |||
232 | /* Next check the txcmplq */ | ||
233 | list_splice_init(&pring->txcmplq, &txcmplq_completions); | ||
234 | spin_unlock_irq(&phba->hbalock); | ||
235 | |||
236 | list_for_each_entry_safe(iocb, next_iocb, &txcmplq_completions, list) { | ||
237 | /* Check to see if iocb matches the nport we are looking for */ | ||
238 | if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) | 230 | if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) |
239 | list_add_tail(&iocb->dlist, &abort_list); | 231 | list_add_tail(&iocb->dlist, &abort_list); |
240 | } | 232 | } |
241 | spin_lock_irq(&phba->hbalock); | 233 | if (phba->sli_rev == LPFC_SLI_REV4) |
242 | list_splice(&txcmplq_completions, &pring->txcmplq); | 234 | spin_unlock(&pring->ring_lock); |
243 | spin_unlock_irq(&phba->hbalock); | 235 | spin_unlock_irq(&phba->hbalock); |
244 | 236 | ||
237 | /* Abort the targeted IOs and remove them from the abort list. */ | ||
245 | list_for_each_entry_safe(iocb, next_iocb, &abort_list, dlist) { | 238 | list_for_each_entry_safe(iocb, next_iocb, &abort_list, dlist) { |
246 | spin_lock_irq(&phba->hbalock); | 239 | spin_lock_irq(&phba->hbalock); |
247 | list_del_init(&iocb->dlist); | 240 | list_del_init(&iocb->dlist); |
@@ -249,9 +242,28 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) | |||
249 | spin_unlock_irq(&phba->hbalock); | 242 | spin_unlock_irq(&phba->hbalock); |
250 | } | 243 | } |
251 | 244 | ||
245 | INIT_LIST_HEAD(&abort_list); | ||
246 | |||
247 | /* Now process the txq */ | ||
248 | spin_lock_irq(&phba->hbalock); | ||
249 | if (phba->sli_rev == LPFC_SLI_REV4) | ||
250 | spin_lock(&pring->ring_lock); | ||
251 | |||
252 | list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) { | ||
253 | /* Check to see if iocb matches the nport we are looking for */ | ||
254 | if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) { | ||
255 | list_del_init(&iocb->list); | ||
256 | list_add_tail(&iocb->list, &abort_list); | ||
257 | } | ||
258 | } | ||
259 | |||
260 | if (phba->sli_rev == LPFC_SLI_REV4) | ||
261 | spin_unlock(&pring->ring_lock); | ||
262 | spin_unlock_irq(&phba->hbalock); | ||
263 | |||
252 | /* Cancel all the IOCBs from the completions list */ | 264 | /* Cancel all the IOCBs from the completions list */ |
253 | lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, | 265 | lpfc_sli_cancel_iocbs(phba, &abort_list, |
254 | IOERR_SLI_ABORTED); | 266 | IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED); |
255 | 267 | ||
256 | lpfc_cancel_retry_delay_tmo(phba->pport, ndlp); | 268 | lpfc_cancel_retry_delay_tmo(phba->pport, ndlp); |
257 | return 0; | 269 | return 0; |