aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/ibmvscsi
diff options
context:
space:
mode:
authorBrian King <brking@linux.vnet.ibm.com>2010-06-17 14:55:13 -0400
committerJames Bottomley <James.Bottomley@suse.de>2010-07-27 13:02:39 -0400
commit73ee5d8672871bd69077ca71e7208a36bfa6343c (patch)
tree6494ae5426a54a98ad5f8f6aec4ba58e41003fc4 /drivers/scsi/ibmvscsi
parent15f7fc060a7bf49991c35b23e1e7d73a1535382a (diff)
[SCSI] ibmvfc: Fix soft lockup on resume
This fixes a softlockup seen on resume. During resume, the CRQ must be reenabled. However, the H_ENABLE_CRQ hcall used to do this may return H_BUSY or H_LONG_BUSY. When this happens, the caller is expected to retry later. Normally the H_ENABLE_CRQ succeeds relatively soon. However, we have seen cases where this can take long enough to see softlockup warnings. This patch changes a simple loop, which was causing the softlockup, to a loop at task level which sleeps between retries rather than simply spinning. Signed-off-by: Brian King <brking@linux.vnet.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/ibmvscsi')
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.c81
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.h2
2 files changed, 56 insertions, 27 deletions
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index fef49521cbc3..d6fcb3f43969 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -504,12 +504,23 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost,
504 if (vhost->action == IBMVFC_HOST_ACTION_ALLOC_TGTS) 504 if (vhost->action == IBMVFC_HOST_ACTION_ALLOC_TGTS)
505 vhost->action = action; 505 vhost->action = action;
506 break; 506 break;
507 case IBMVFC_HOST_ACTION_LOGO:
508 case IBMVFC_HOST_ACTION_INIT: 507 case IBMVFC_HOST_ACTION_INIT:
509 case IBMVFC_HOST_ACTION_TGT_DEL: 508 case IBMVFC_HOST_ACTION_TGT_DEL:
509 switch (vhost->action) {
510 case IBMVFC_HOST_ACTION_RESET:
511 case IBMVFC_HOST_ACTION_REENABLE:
512 break;
513 default:
514 vhost->action = action;
515 break;
516 };
517 break;
518 case IBMVFC_HOST_ACTION_LOGO:
510 case IBMVFC_HOST_ACTION_QUERY_TGTS: 519 case IBMVFC_HOST_ACTION_QUERY_TGTS:
511 case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: 520 case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:
512 case IBMVFC_HOST_ACTION_NONE: 521 case IBMVFC_HOST_ACTION_NONE:
522 case IBMVFC_HOST_ACTION_RESET:
523 case IBMVFC_HOST_ACTION_REENABLE:
513 default: 524 default:
514 vhost->action = action; 525 vhost->action = action;
515 break; 526 break;
@@ -641,7 +652,7 @@ static int ibmvfc_send_crq_init_complete(struct ibmvfc_host *vhost)
641 **/ 652 **/
642static void ibmvfc_release_crq_queue(struct ibmvfc_host *vhost) 653static void ibmvfc_release_crq_queue(struct ibmvfc_host *vhost)
643{ 654{
644 long rc; 655 long rc = 0;
645 struct vio_dev *vdev = to_vio_dev(vhost->dev); 656 struct vio_dev *vdev = to_vio_dev(vhost->dev);
646 struct ibmvfc_crq_queue *crq = &vhost->crq; 657 struct ibmvfc_crq_queue *crq = &vhost->crq;
647 658
@@ -649,6 +660,8 @@ static void ibmvfc_release_crq_queue(struct ibmvfc_host *vhost)
649 free_irq(vdev->irq, vhost); 660 free_irq(vdev->irq, vhost);
650 tasklet_kill(&vhost->tasklet); 661 tasklet_kill(&vhost->tasklet);
651 do { 662 do {
663 if (rc)
664 msleep(100);
652 rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); 665 rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
653 } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); 666 } while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
654 667
@@ -667,11 +680,13 @@ static void ibmvfc_release_crq_queue(struct ibmvfc_host *vhost)
667 **/ 680 **/
668static int ibmvfc_reenable_crq_queue(struct ibmvfc_host *vhost) 681static int ibmvfc_reenable_crq_queue(struct ibmvfc_host *vhost)
669{ 682{
670 int rc; 683 int rc = 0;
671 struct vio_dev *vdev = to_vio_dev(vhost->dev); 684 struct vio_dev *vdev = to_vio_dev(vhost->dev);
672 685
673 /* Re-enable the CRQ */ 686 /* Re-enable the CRQ */
674 do { 687 do {
688 if (rc)
689 msleep(100);
675 rc = plpar_hcall_norets(H_ENABLE_CRQ, vdev->unit_address); 690 rc = plpar_hcall_norets(H_ENABLE_CRQ, vdev->unit_address);
676 } while (rc == H_IN_PROGRESS || rc == H_BUSY || H_IS_LONG_BUSY(rc)); 691 } while (rc == H_IN_PROGRESS || rc == H_BUSY || H_IS_LONG_BUSY(rc));
677 692
@@ -690,15 +705,19 @@ static int ibmvfc_reenable_crq_queue(struct ibmvfc_host *vhost)
690 **/ 705 **/
691static int ibmvfc_reset_crq(struct ibmvfc_host *vhost) 706static int ibmvfc_reset_crq(struct ibmvfc_host *vhost)
692{ 707{
693 int rc; 708 int rc = 0;
709 unsigned long flags;
694 struct vio_dev *vdev = to_vio_dev(vhost->dev); 710 struct vio_dev *vdev = to_vio_dev(vhost->dev);
695 struct ibmvfc_crq_queue *crq = &vhost->crq; 711 struct ibmvfc_crq_queue *crq = &vhost->crq;
696 712
697 /* Close the CRQ */ 713 /* Close the CRQ */
698 do { 714 do {
715 if (rc)
716 msleep(100);
699 rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); 717 rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
700 } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); 718 } while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
701 719
720 spin_lock_irqsave(vhost->host->host_lock, flags);
702 vhost->state = IBMVFC_NO_CRQ; 721 vhost->state = IBMVFC_NO_CRQ;
703 vhost->logged_in = 0; 722 vhost->logged_in = 0;
704 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); 723 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE);
@@ -716,6 +735,7 @@ static int ibmvfc_reset_crq(struct ibmvfc_host *vhost)
716 dev_warn(vhost->dev, "Partner adapter not ready\n"); 735 dev_warn(vhost->dev, "Partner adapter not ready\n");
717 else if (rc != 0) 736 else if (rc != 0)
718 dev_warn(vhost->dev, "Couldn't register crq (rc=%d)\n", rc); 737 dev_warn(vhost->dev, "Couldn't register crq (rc=%d)\n", rc);
738 spin_unlock_irqrestore(vhost->host->host_lock, flags);
719 739
720 return rc; 740 return rc;
721} 741}
@@ -821,17 +841,9 @@ static void ibmvfc_purge_requests(struct ibmvfc_host *vhost, int error_code)
821 **/ 841 **/
822static void ibmvfc_hard_reset_host(struct ibmvfc_host *vhost) 842static void ibmvfc_hard_reset_host(struct ibmvfc_host *vhost)
823{ 843{
824 int rc;
825
826 scsi_block_requests(vhost->host);
827 ibmvfc_purge_requests(vhost, DID_ERROR); 844 ibmvfc_purge_requests(vhost, DID_ERROR);
828 if ((rc = ibmvfc_reset_crq(vhost)) || 845 ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
829 (rc = ibmvfc_send_crq_init(vhost)) || 846 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_RESET);
830 (rc = vio_enable_interrupts(to_vio_dev(vhost->dev)))) {
831 dev_err(vhost->dev, "Error after reset rc=%d\n", rc);
832 ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
833 } else
834 ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
835} 847}
836 848
837/** 849/**
@@ -2606,22 +2618,13 @@ static void ibmvfc_handle_crq(struct ibmvfc_crq *crq, struct ibmvfc_host *vhost)
2606 dev_info(vhost->dev, "Re-enabling adapter\n"); 2618 dev_info(vhost->dev, "Re-enabling adapter\n");
2607 vhost->client_migrated = 1; 2619 vhost->client_migrated = 1;
2608 ibmvfc_purge_requests(vhost, DID_REQUEUE); 2620 ibmvfc_purge_requests(vhost, DID_REQUEUE);
2609 if ((rc = ibmvfc_reenable_crq_queue(vhost)) || 2621 ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
2610 (rc = ibmvfc_send_crq_init(vhost))) { 2622 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_REENABLE);
2611 ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
2612 dev_err(vhost->dev, "Error after enable (rc=%ld)\n", rc);
2613 } else
2614 ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
2615 } else { 2623 } else {
2616 dev_err(vhost->dev, "Virtual adapter failed (rc=%d)\n", crq->format); 2624 dev_err(vhost->dev, "Virtual adapter failed (rc=%d)\n", crq->format);
2617
2618 ibmvfc_purge_requests(vhost, DID_ERROR); 2625 ibmvfc_purge_requests(vhost, DID_ERROR);
2619 if ((rc = ibmvfc_reset_crq(vhost)) || 2626 ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
2620 (rc = ibmvfc_send_crq_init(vhost))) { 2627 ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_RESET);
2621 ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
2622 dev_err(vhost->dev, "Error after reset (rc=%ld)\n", rc);
2623 } else
2624 ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
2625 } 2628 }
2626 return; 2629 return;
2627 case IBMVFC_CRQ_CMD_RSP: 2630 case IBMVFC_CRQ_CMD_RSP:
@@ -4123,6 +4126,8 @@ static int __ibmvfc_work_to_do(struct ibmvfc_host *vhost)
4123 case IBMVFC_HOST_ACTION_TGT_DEL: 4126 case IBMVFC_HOST_ACTION_TGT_DEL:
4124 case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: 4127 case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:
4125 case IBMVFC_HOST_ACTION_QUERY: 4128 case IBMVFC_HOST_ACTION_QUERY:
4129 case IBMVFC_HOST_ACTION_RESET:
4130 case IBMVFC_HOST_ACTION_REENABLE:
4126 default: 4131 default:
4127 break; 4132 break;
4128 }; 4133 };
@@ -4220,6 +4225,7 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost)
4220 struct ibmvfc_target *tgt; 4225 struct ibmvfc_target *tgt;
4221 unsigned long flags; 4226 unsigned long flags;
4222 struct fc_rport *rport; 4227 struct fc_rport *rport;
4228 int rc;
4223 4229
4224 ibmvfc_log_ae(vhost, vhost->events_to_log); 4230 ibmvfc_log_ae(vhost, vhost->events_to_log);
4225 spin_lock_irqsave(vhost->host->host_lock, flags); 4231 spin_lock_irqsave(vhost->host->host_lock, flags);
@@ -4229,6 +4235,27 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost)
4229 case IBMVFC_HOST_ACTION_LOGO_WAIT: 4235 case IBMVFC_HOST_ACTION_LOGO_WAIT:
4230 case IBMVFC_HOST_ACTION_INIT_WAIT: 4236 case IBMVFC_HOST_ACTION_INIT_WAIT:
4231 break; 4237 break;
4238 case IBMVFC_HOST_ACTION_RESET:
4239 vhost->action = IBMVFC_HOST_ACTION_TGT_DEL;
4240 spin_unlock_irqrestore(vhost->host->host_lock, flags);
4241 rc = ibmvfc_reset_crq(vhost);
4242 spin_lock_irqsave(vhost->host->host_lock, flags);
4243 if (rc || (rc = ibmvfc_send_crq_init(vhost)) ||
4244 (rc = vio_enable_interrupts(to_vio_dev(vhost->dev)))) {
4245 ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
4246 dev_err(vhost->dev, "Error after reset (rc=%d)\n", rc);
4247 }
4248 break;
4249 case IBMVFC_HOST_ACTION_REENABLE:
4250 vhost->action = IBMVFC_HOST_ACTION_TGT_DEL;
4251 spin_unlock_irqrestore(vhost->host->host_lock, flags);
4252 rc = ibmvfc_reenable_crq_queue(vhost);
4253 spin_lock_irqsave(vhost->host->host_lock, flags);
4254 if (rc || (rc = ibmvfc_send_crq_init(vhost))) {
4255 ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
4256 dev_err(vhost->dev, "Error after enable (rc=%d)\n", rc);
4257 }
4258 break;
4232 case IBMVFC_HOST_ACTION_LOGO: 4259 case IBMVFC_HOST_ACTION_LOGO:
4233 vhost->job_step(vhost); 4260 vhost->job_step(vhost);
4234 break; 4261 break;
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h
index 7e9742764e4b..2010d73aca81 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.h
+++ b/drivers/scsi/ibmvscsi/ibmvfc.h
@@ -649,6 +649,8 @@ struct ibmvfc_event_pool {
649 649
650enum ibmvfc_host_action { 650enum ibmvfc_host_action {
651 IBMVFC_HOST_ACTION_NONE = 0, 651 IBMVFC_HOST_ACTION_NONE = 0,
652 IBMVFC_HOST_ACTION_RESET,
653 IBMVFC_HOST_ACTION_REENABLE,
652 IBMVFC_HOST_ACTION_LOGO, 654 IBMVFC_HOST_ACTION_LOGO,
653 IBMVFC_HOST_ACTION_LOGO_WAIT, 655 IBMVFC_HOST_ACTION_LOGO_WAIT,
654 IBMVFC_HOST_ACTION_INIT, 656 IBMVFC_HOST_ACTION_INIT,