Commit b5a9b2dfe685117d20062e7cb7998df4d786fca7

Authored by James Smart
Committed by James Bottomley
1 parent 9a86ed4840

[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 */