diff options
author | Stewart, Sean <Sean.Stewart@netapp.com> | 2013-10-15 11:52:54 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2013-10-25 06:19:33 -0400 |
commit | a8e5a2d593cbfccf530c3382c2c328d2edaa7b66 (patch) | |
tree | 879d7cc9168fbe2c9fceba2c16923f59c2f69ed1 /drivers/scsi | |
parent | c20ee7b56e0a1937b41919813e5a98373ca48ae8 (diff) |
[SCSI] scsi_dh_alua: ALUA handler attach should succeed while TPG is transitioning
During testing, it was discovered that when a device tries to attach to the
alua handler while in TPG state of transitioning, the alua_rtpg function will
wait for it to exit the state before allowing it to continue. As a result, if
the 60 second timeout expires, the alua handler will not attach to the device.
To fix this, I have introduced an input argument to alua_rtpg called
wait_for_transition. The idea is that it will wait for the transition to
complete before an activation (because the current TPG state has some bearing
in that case), but during a discovery if it is transitioning, it will not
wait, and will store the state as standby for the time being.
I believe the precedent exists for this from commit
c0d289b3e59577532c45ee9110ef81bd7b341272 Since if the device reports a state
of transitioning, it can transition to other more valid states, and it has
been established TPGS is supported on the device, if it is attaching.
Signed-off-by: Sean Stewart <Sean.Stewart@netapp.com>
Acked-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/device_handler/scsi_dh_alua.c | 26 |
1 files changed, 16 insertions, 10 deletions
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 78205cc2059c..5248c888552b 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c | |||
@@ -522,12 +522,13 @@ static int alua_check_sense(struct scsi_device *sdev, | |||
522 | /* | 522 | /* |
523 | * alua_rtpg - Evaluate REPORT TARGET GROUP STATES | 523 | * alua_rtpg - Evaluate REPORT TARGET GROUP STATES |
524 | * @sdev: the device to be evaluated. | 524 | * @sdev: the device to be evaluated. |
525 | * @wait_for_transition: if nonzero, wait ALUA_FAILOVER_TIMEOUT seconds for device to exit transitioning state | ||
525 | * | 526 | * |
526 | * Evaluate the Target Port Group State. | 527 | * Evaluate the Target Port Group State. |
527 | * Returns SCSI_DH_DEV_OFFLINED if the path is | 528 | * Returns SCSI_DH_DEV_OFFLINED if the path is |
528 | * found to be unusable. | 529 | * found to be unusable. |
529 | */ | 530 | */ |
530 | static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) | 531 | static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_for_transition) |
531 | { | 532 | { |
532 | struct scsi_sense_hdr sense_hdr; | 533 | struct scsi_sense_hdr sense_hdr; |
533 | int len, k, off, valid_states = 0; | 534 | int len, k, off, valid_states = 0; |
@@ -599,7 +600,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) | |||
599 | else | 600 | else |
600 | h->transition_tmo = ALUA_FAILOVER_TIMEOUT; | 601 | h->transition_tmo = ALUA_FAILOVER_TIMEOUT; |
601 | 602 | ||
602 | if (orig_transition_tmo != h->transition_tmo) { | 603 | if (wait_for_transition && (orig_transition_tmo != h->transition_tmo)) { |
603 | sdev_printk(KERN_INFO, sdev, | 604 | sdev_printk(KERN_INFO, sdev, |
604 | "%s: transition timeout set to %d seconds\n", | 605 | "%s: transition timeout set to %d seconds\n", |
605 | ALUA_DH_NAME, h->transition_tmo); | 606 | ALUA_DH_NAME, h->transition_tmo); |
@@ -637,14 +638,19 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) | |||
637 | 638 | ||
638 | switch (h->state) { | 639 | switch (h->state) { |
639 | case TPGS_STATE_TRANSITIONING: | 640 | case TPGS_STATE_TRANSITIONING: |
640 | if (time_before(jiffies, expiry)) { | 641 | if (wait_for_transition) { |
641 | /* State transition, retry */ | 642 | if (time_before(jiffies, expiry)) { |
642 | interval += 2000; | 643 | /* State transition, retry */ |
643 | msleep(interval); | 644 | interval += 2000; |
644 | goto retry; | 645 | msleep(interval); |
646 | goto retry; | ||
647 | } | ||
648 | err = SCSI_DH_RETRY; | ||
649 | } else { | ||
650 | err = SCSI_DH_OK; | ||
645 | } | 651 | } |
652 | |||
646 | /* Transitioning time exceeded, set port to standby */ | 653 | /* Transitioning time exceeded, set port to standby */ |
647 | err = SCSI_DH_RETRY; | ||
648 | h->state = TPGS_STATE_STANDBY; | 654 | h->state = TPGS_STATE_STANDBY; |
649 | break; | 655 | break; |
650 | case TPGS_STATE_OFFLINE: | 656 | case TPGS_STATE_OFFLINE: |
@@ -678,7 +684,7 @@ static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h) | |||
678 | if (err != SCSI_DH_OK) | 684 | if (err != SCSI_DH_OK) |
679 | goto out; | 685 | goto out; |
680 | 686 | ||
681 | err = alua_rtpg(sdev, h); | 687 | err = alua_rtpg(sdev, h, 0); |
682 | if (err != SCSI_DH_OK) | 688 | if (err != SCSI_DH_OK) |
683 | goto out; | 689 | goto out; |
684 | 690 | ||
@@ -738,7 +744,7 @@ static int alua_activate(struct scsi_device *sdev, | |||
738 | int err = SCSI_DH_OK; | 744 | int err = SCSI_DH_OK; |
739 | int stpg = 0; | 745 | int stpg = 0; |
740 | 746 | ||
741 | err = alua_rtpg(sdev, h); | 747 | err = alua_rtpg(sdev, h, 1); |
742 | if (err != SCSI_DH_OK) | 748 | if (err != SCSI_DH_OK) |
743 | goto out; | 749 | goto out; |
744 | 750 | ||