Commit b5a9b2dfe685117d20062e7cb7998df4d786fca7
Committed by
James Bottomley
1 parent
9a86ed4840
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
[SCSI] lpfc 8.3.42: Fixed race condition between BSG I/O dispatch and timeout handling
Signed-off-by: James Smart <james.smart@emulex.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Showing 2 changed files with 72 additions and 17 deletions Side-by-side Diff
drivers/scsi/lpfc/lpfc_bsg.c
... | ... | @@ -317,6 +317,11 @@ |
317 | 317 | } |
318 | 318 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); |
319 | 319 | |
320 | + /* Close the timeout handler abort window */ | |
321 | + spin_lock_irqsave(&phba->hbalock, flags); | |
322 | + cmdiocbq->iocb_aux_flag &= ~LPFC_IO_CMD_OUTSTANDING; | |
323 | + spin_unlock_irqrestore(&phba->hbalock, flags); | |
324 | + | |
320 | 325 | iocb = &dd_data->context_un.iocb; |
321 | 326 | ndlp = iocb->ndlp; |
322 | 327 | rmp = iocb->rmp; |
... | ... | @@ -387,6 +392,7 @@ |
387 | 392 | int request_nseg; |
388 | 393 | int reply_nseg; |
389 | 394 | struct bsg_job_data *dd_data; |
395 | + unsigned long flags; | |
390 | 396 | uint32_t creg_val; |
391 | 397 | int rc = 0; |
392 | 398 | int iocb_stat; |
393 | 399 | |
394 | 400 | |
395 | 401 | |
396 | 402 | |
... | ... | @@ -501,14 +507,24 @@ |
501 | 507 | } |
502 | 508 | |
503 | 509 | iocb_stat = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); |
504 | - if (iocb_stat == IOCB_SUCCESS) | |
510 | + | |
511 | + if (iocb_stat == IOCB_SUCCESS) { | |
512 | + spin_lock_irqsave(&phba->hbalock, flags); | |
513 | + /* make sure the I/O had not been completed yet */ | |
514 | + if (cmdiocbq->iocb_flag & LPFC_IO_LIBDFC) { | |
515 | + /* open up abort window to timeout handler */ | |
516 | + cmdiocbq->iocb_aux_flag |= LPFC_IO_CMD_OUTSTANDING; | |
517 | + } | |
518 | + spin_unlock_irqrestore(&phba->hbalock, flags); | |
505 | 519 | return 0; /* done for now */ |
506 | - else if (iocb_stat == IOCB_BUSY) | |
520 | + } else if (iocb_stat == IOCB_BUSY) { | |
507 | 521 | rc = -EAGAIN; |
508 | - else | |
522 | + } else { | |
509 | 523 | rc = -EIO; |
524 | + } | |
510 | 525 | |
511 | 526 | /* iocb failed so cleanup */ |
527 | + job->dd_data = NULL; | |
512 | 528 | |
513 | 529 | free_rmp: |
514 | 530 | lpfc_free_bsg_buffers(phba, rmp); |
... | ... | @@ -577,6 +593,11 @@ |
577 | 593 | } |
578 | 594 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); |
579 | 595 | |
596 | + /* Close the timeout handler abort window */ | |
597 | + spin_lock_irqsave(&phba->hbalock, flags); | |
598 | + cmdiocbq->iocb_aux_flag &= ~LPFC_IO_CMD_OUTSTANDING; | |
599 | + spin_unlock_irqrestore(&phba->hbalock, flags); | |
600 | + | |
580 | 601 | rsp = &rspiocbq->iocb; |
581 | 602 | pcmd = (struct lpfc_dmabuf *)cmdiocbq->context2; |
582 | 603 | prsp = (struct lpfc_dmabuf *)pcmd->list.next; |
... | ... | @@ -639,6 +660,7 @@ |
639 | 660 | struct lpfc_iocbq *cmdiocbq; |
640 | 661 | uint16_t rpi = 0; |
641 | 662 | struct bsg_job_data *dd_data; |
663 | + unsigned long flags; | |
642 | 664 | uint32_t creg_val; |
643 | 665 | int rc = 0; |
644 | 666 | |
645 | 667 | |
646 | 668 | |
647 | 669 | |
648 | 670 | |
649 | 671 | |
... | ... | @@ -721,15 +743,25 @@ |
721 | 743 | |
722 | 744 | rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); |
723 | 745 | |
724 | - if (rc == IOCB_SUCCESS) | |
746 | + if (rc == IOCB_SUCCESS) { | |
747 | + spin_lock_irqsave(&phba->hbalock, flags); | |
748 | + /* make sure the I/O had not been completed/released */ | |
749 | + if (cmdiocbq->iocb_flag & LPFC_IO_LIBDFC) { | |
750 | + /* open up abort window to timeout handler */ | |
751 | + cmdiocbq->iocb_aux_flag |= LPFC_IO_CMD_OUTSTANDING; | |
752 | + } | |
753 | + spin_unlock_irqrestore(&phba->hbalock, flags); | |
725 | 754 | return 0; /* done for now */ |
726 | - else if (rc == IOCB_BUSY) | |
755 | + } else if (rc == IOCB_BUSY) { | |
727 | 756 | rc = -EAGAIN; |
728 | - else | |
757 | + } else { | |
729 | 758 | rc = -EIO; |
759 | + } | |
730 | 760 | |
731 | -linkdown_err: | |
761 | + /* iocb failed so cleanup */ | |
762 | + job->dd_data = NULL; | |
732 | 763 | |
764 | +linkdown_err: | |
733 | 765 | cmdiocbq->context1 = ndlp; |
734 | 766 | lpfc_els_free_iocb(phba, cmdiocbq); |
735 | 767 | |
... | ... | @@ -1370,6 +1402,11 @@ |
1370 | 1402 | } |
1371 | 1403 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); |
1372 | 1404 | |
1405 | + /* Close the timeout handler abort window */ | |
1406 | + spin_lock_irqsave(&phba->hbalock, flags); | |
1407 | + cmdiocbq->iocb_aux_flag &= ~LPFC_IO_CMD_OUTSTANDING; | |
1408 | + spin_unlock_irqrestore(&phba->hbalock, flags); | |
1409 | + | |
1373 | 1410 | ndlp = dd_data->context_un.iocb.ndlp; |
1374 | 1411 | cmp = cmdiocbq->context2; |
1375 | 1412 | bmp = cmdiocbq->context3; |
... | ... | @@ -1433,6 +1470,7 @@ |
1433 | 1470 | int rc = 0; |
1434 | 1471 | struct lpfc_nodelist *ndlp = NULL; |
1435 | 1472 | struct bsg_job_data *dd_data; |
1473 | + unsigned long flags; | |
1436 | 1474 | uint32_t creg_val; |
1437 | 1475 | |
1438 | 1476 | /* allocate our bsg tracking structure */ |
1439 | 1477 | |
1440 | 1478 | |
... | ... | @@ -1542,9 +1580,20 @@ |
1542 | 1580 | |
1543 | 1581 | rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0); |
1544 | 1582 | |
1545 | - if (rc == IOCB_SUCCESS) | |
1583 | + if (rc == IOCB_SUCCESS) { | |
1584 | + spin_lock_irqsave(&phba->hbalock, flags); | |
1585 | + /* make sure the I/O had not been completed/released */ | |
1586 | + if (ctiocb->iocb_flag & LPFC_IO_LIBDFC) { | |
1587 | + /* open up abort window to timeout handler */ | |
1588 | + ctiocb->iocb_aux_flag |= LPFC_IO_CMD_OUTSTANDING; | |
1589 | + } | |
1590 | + spin_unlock_irqrestore(&phba->hbalock, flags); | |
1546 | 1591 | return 0; /* done for now */ |
1592 | + } | |
1547 | 1593 | |
1594 | + /* iocb failed so cleanup */ | |
1595 | + job->dd_data = NULL; | |
1596 | + | |
1548 | 1597 | issue_ct_rsp_exit: |
1549 | 1598 | lpfc_sli_release_iocbq(phba, ctiocb); |
1550 | 1599 | no_ctiocb: |
1551 | 1600 | |
... | ... | @@ -5284,9 +5333,15 @@ |
5284 | 5333 | * remove it from the txq queue and call cancel iocbs. |
5285 | 5334 | * Otherwise, call abort iotag |
5286 | 5335 | */ |
5287 | - | |
5288 | 5336 | cmdiocb = dd_data->context_un.iocb.cmdiocbq; |
5289 | - spin_lock_irq(&phba->hbalock); | |
5337 | + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | |
5338 | + | |
5339 | + spin_lock_irqsave(&phba->hbalock, flags); | |
5340 | + /* make sure the I/O abort window is still open */ | |
5341 | + if (!(cmdiocb->iocb_aux_flag & LPFC_IO_CMD_OUTSTANDING)) { | |
5342 | + spin_unlock_irqrestore(&phba->hbalock, flags); | |
5343 | + return -EAGAIN; | |
5344 | + } | |
5290 | 5345 | list_for_each_entry_safe(check_iocb, next_iocb, &pring->txq, |
5291 | 5346 | list) { |
5292 | 5347 | if (check_iocb == cmdiocb) { |
... | ... | @@ -5296,8 +5351,7 @@ |
5296 | 5351 | } |
5297 | 5352 | if (list_empty(&completions)) |
5298 | 5353 | lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb); |
5299 | - spin_unlock_irq(&phba->hbalock); | |
5300 | - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | |
5354 | + spin_unlock_irqrestore(&phba->hbalock, flags); | |
5301 | 5355 | if (!list_empty(&completions)) { |
5302 | 5356 | lpfc_sli_cancel_iocbs(phba, &completions, |
5303 | 5357 | IOSTAT_LOCAL_REJECT, |
5304 | 5358 | |
... | ... | @@ -5321,9 +5375,10 @@ |
5321 | 5375 | * remove it from the txq queue and call cancel iocbs. |
5322 | 5376 | * Otherwise, call abort iotag. |
5323 | 5377 | */ |
5324 | - | |
5325 | 5378 | cmdiocb = dd_data->context_un.menlo.cmdiocbq; |
5326 | - spin_lock_irq(&phba->hbalock); | |
5379 | + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | |
5380 | + | |
5381 | + spin_lock_irqsave(&phba->hbalock, flags); | |
5327 | 5382 | list_for_each_entry_safe(check_iocb, next_iocb, &pring->txq, |
5328 | 5383 | list) { |
5329 | 5384 | if (check_iocb == cmdiocb) { |
... | ... | @@ -5333,8 +5388,7 @@ |
5333 | 5388 | } |
5334 | 5389 | if (list_empty(&completions)) |
5335 | 5390 | lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb); |
5336 | - spin_unlock_irq(&phba->hbalock); | |
5337 | - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | |
5391 | + spin_unlock_irqrestore(&phba->hbalock, flags); | |
5338 | 5392 | if (!list_empty(&completions)) { |
5339 | 5393 | lpfc_sli_cancel_iocbs(phba, &completions, |
5340 | 5394 | IOSTAT_LOCAL_REJECT, |
drivers/scsi/lpfc/lpfc_sli.h
... | ... | @@ -77,7 +77,8 @@ |
77 | 77 | #define LPFC_FIP_ELS_ID_MASK 0xc000 /* ELS_ID range 0-3, non-shifted mask */ |
78 | 78 | #define LPFC_FIP_ELS_ID_SHIFT 14 |
79 | 79 | |
80 | - uint8_t rsvd2; | |
80 | + uint8_t iocb_aux_flag; | |
81 | +#define LPFC_IO_CMD_OUTSTANDING 0x01 /* timeout handler abort window */ | |
81 | 82 | uint32_t drvrTimeout; /* driver timeout in seconds */ |
82 | 83 | uint32_t fcp_wqidx; /* index to FCP work queue */ |
83 | 84 | struct lpfc_vport *vport;/* virtual port pointer */ |