diff options
author | Hannes Reinecke <hare@suse.de> | 2010-09-24 09:57:04 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-10-07 18:22:22 -0400 |
commit | 69723d178da97b09ae8996f60fbf2f0cf68d6d61 (patch) | |
tree | aef50073d685f31de4fc84e060dc59e8549e78b1 /drivers/scsi | |
parent | e27d6169c79e3c75edc74a14424a7856e7ff487c (diff) |
[SCSI] scsi_dh_alua: Handle all states correctly
For ALUA we should be handling all states, independent of whether
the mode is explicit or implicit. For 'Transitioning' we should retry
for a certain amount of time; after that we're setting the port
to 'Standby' and return SCSI_DH_RETRY to signal upper layers
a retry is in order here.
Signed-off-by: Hannes Reinecke <hare@suse.de>
Acked-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/device_handler/scsi_dh_alua.c | 65 |
1 files changed, 38 insertions, 27 deletions
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 1a970a76b1b9..6b729324b8d3 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Generic SCSI-3 ALUA SCSI Device Handler | 2 | * Generic SCSI-3 ALUA SCSI Device Handler |
3 | * | 3 | * |
4 | * Copyright (C) 2007, 2008 Hannes Reinecke, SUSE Linux Products GmbH. | 4 | * Copyright (C) 2007-2010 Hannes Reinecke, SUSE Linux Products GmbH. |
5 | * All rights reserved. | 5 | * All rights reserved. |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
@@ -20,17 +20,19 @@ | |||
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/delay.h> | ||
23 | #include <scsi/scsi.h> | 24 | #include <scsi/scsi.h> |
24 | #include <scsi/scsi_eh.h> | 25 | #include <scsi/scsi_eh.h> |
25 | #include <scsi/scsi_dh.h> | 26 | #include <scsi/scsi_dh.h> |
26 | 27 | ||
27 | #define ALUA_DH_NAME "alua" | 28 | #define ALUA_DH_NAME "alua" |
28 | #define ALUA_DH_VER "1.2" | 29 | #define ALUA_DH_VER "1.3" |
29 | 30 | ||
30 | #define TPGS_STATE_OPTIMIZED 0x0 | 31 | #define TPGS_STATE_OPTIMIZED 0x0 |
31 | #define TPGS_STATE_NONOPTIMIZED 0x1 | 32 | #define TPGS_STATE_NONOPTIMIZED 0x1 |
32 | #define TPGS_STATE_STANDBY 0x2 | 33 | #define TPGS_STATE_STANDBY 0x2 |
33 | #define TPGS_STATE_UNAVAILABLE 0x3 | 34 | #define TPGS_STATE_UNAVAILABLE 0x3 |
35 | #define TPGS_STATE_LBA_DEPENDENT 0x4 | ||
34 | #define TPGS_STATE_OFFLINE 0xe | 36 | #define TPGS_STATE_OFFLINE 0xe |
35 | #define TPGS_STATE_TRANSITIONING 0xf | 37 | #define TPGS_STATE_TRANSITIONING 0xf |
36 | 38 | ||
@@ -39,6 +41,7 @@ | |||
39 | #define TPGS_SUPPORT_NONOPTIMIZED 0x02 | 41 | #define TPGS_SUPPORT_NONOPTIMIZED 0x02 |
40 | #define TPGS_SUPPORT_STANDBY 0x04 | 42 | #define TPGS_SUPPORT_STANDBY 0x04 |
41 | #define TPGS_SUPPORT_UNAVAILABLE 0x08 | 43 | #define TPGS_SUPPORT_UNAVAILABLE 0x08 |
44 | #define TPGS_SUPPORT_LBA_DEPENDENT 0x10 | ||
42 | #define TPGS_SUPPORT_OFFLINE 0x40 | 45 | #define TPGS_SUPPORT_OFFLINE 0x40 |
43 | #define TPGS_SUPPORT_TRANSITION 0x80 | 46 | #define TPGS_SUPPORT_TRANSITION 0x80 |
44 | 47 | ||
@@ -460,6 +463,8 @@ static char print_alua_state(int state) | |||
460 | return 'S'; | 463 | return 'S'; |
461 | case TPGS_STATE_UNAVAILABLE: | 464 | case TPGS_STATE_UNAVAILABLE: |
462 | return 'U'; | 465 | return 'U'; |
466 | case TPGS_STATE_LBA_DEPENDENT: | ||
467 | return 'L'; | ||
463 | case TPGS_STATE_OFFLINE: | 468 | case TPGS_STATE_OFFLINE: |
464 | return 'O'; | 469 | return 'O'; |
465 | case TPGS_STATE_TRANSITIONING: | 470 | case TPGS_STATE_TRANSITIONING: |
@@ -542,7 +547,9 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) | |||
542 | int len, k, off, valid_states = 0; | 547 | int len, k, off, valid_states = 0; |
543 | char *ucp; | 548 | char *ucp; |
544 | unsigned err; | 549 | unsigned err; |
550 | unsigned long expiry, interval = 10; | ||
545 | 551 | ||
552 | expiry = round_jiffies_up(jiffies + ALUA_FAILOVER_TIMEOUT); | ||
546 | retry: | 553 | retry: |
547 | err = submit_rtpg(sdev, h); | 554 | err = submit_rtpg(sdev, h); |
548 | 555 | ||
@@ -553,7 +560,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) | |||
553 | return SCSI_DH_IO; | 560 | return SCSI_DH_IO; |
554 | 561 | ||
555 | err = alua_check_sense(sdev, &sense_hdr); | 562 | err = alua_check_sense(sdev, &sense_hdr); |
556 | if (err == ADD_TO_MLQUEUE) | 563 | if (err == ADD_TO_MLQUEUE && time_before(jiffies, expiry)) |
557 | goto retry; | 564 | goto retry; |
558 | sdev_printk(KERN_INFO, sdev, | 565 | sdev_printk(KERN_INFO, sdev, |
559 | "%s: rtpg sense code %02x/%02x/%02x\n", | 566 | "%s: rtpg sense code %02x/%02x/%02x\n", |
@@ -587,38 +594,37 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) | |||
587 | } | 594 | } |
588 | 595 | ||
589 | sdev_printk(KERN_INFO, sdev, | 596 | sdev_printk(KERN_INFO, sdev, |
590 | "%s: port group %02x state %c supports %c%c%c%c%c%c\n", | 597 | "%s: port group %02x state %c supports %c%c%c%c%c%c%c\n", |
591 | ALUA_DH_NAME, h->group_id, print_alua_state(h->state), | 598 | ALUA_DH_NAME, h->group_id, print_alua_state(h->state), |
592 | valid_states&TPGS_SUPPORT_TRANSITION?'T':'t', | 599 | valid_states&TPGS_SUPPORT_TRANSITION?'T':'t', |
593 | valid_states&TPGS_SUPPORT_OFFLINE?'O':'o', | 600 | valid_states&TPGS_SUPPORT_OFFLINE?'O':'o', |
601 | valid_states&TPGS_SUPPORT_LBA_DEPENDENT?'L':'l', | ||
594 | valid_states&TPGS_SUPPORT_UNAVAILABLE?'U':'u', | 602 | valid_states&TPGS_SUPPORT_UNAVAILABLE?'U':'u', |
595 | valid_states&TPGS_SUPPORT_STANDBY?'S':'s', | 603 | valid_states&TPGS_SUPPORT_STANDBY?'S':'s', |
596 | valid_states&TPGS_SUPPORT_NONOPTIMIZED?'N':'n', | 604 | valid_states&TPGS_SUPPORT_NONOPTIMIZED?'N':'n', |
597 | valid_states&TPGS_SUPPORT_OPTIMIZED?'A':'a'); | 605 | valid_states&TPGS_SUPPORT_OPTIMIZED?'A':'a'); |
598 | 606 | ||
599 | if (h->tpgs & TPGS_MODE_EXPLICIT) { | 607 | switch (h->state) { |
600 | switch (h->state) { | 608 | case TPGS_STATE_TRANSITIONING: |
601 | case TPGS_STATE_TRANSITIONING: | 609 | if (time_before(jiffies, expiry)) { |
602 | /* State transition, retry */ | 610 | /* State transition, retry */ |
611 | interval *= 10; | ||
612 | msleep(interval); | ||
603 | goto retry; | 613 | goto retry; |
604 | break; | ||
605 | case TPGS_STATE_OFFLINE: | ||
606 | /* Path is offline, fail */ | ||
607 | err = SCSI_DH_DEV_OFFLINED; | ||
608 | break; | ||
609 | default: | ||
610 | break; | ||
611 | } | 614 | } |
612 | } else { | 615 | /* Transitioning time exceeded, set port to standby */ |
613 | /* Only Implicit ALUA support */ | 616 | err = SCSI_DH_RETRY; |
614 | if (h->state == TPGS_STATE_OPTIMIZED || | 617 | h->state = TPGS_STATE_STANDBY; |
615 | h->state == TPGS_STATE_NONOPTIMIZED || | 618 | break; |
616 | h->state == TPGS_STATE_STANDBY) | 619 | case TPGS_STATE_OFFLINE: |
617 | /* Useable path if active */ | 620 | case TPGS_STATE_UNAVAILABLE: |
618 | err = SCSI_DH_OK; | 621 | /* Path unuseable for unavailable/offline */ |
619 | else | 622 | err = SCSI_DH_DEV_OFFLINED; |
620 | /* Path unuseable for unavailable/offline */ | 623 | break; |
621 | err = SCSI_DH_DEV_OFFLINED; | 624 | default: |
625 | /* Useable path if active */ | ||
626 | err = SCSI_DH_OK; | ||
627 | break; | ||
622 | } | 628 | } |
623 | return err; | 629 | return err; |
624 | } | 630 | } |
@@ -672,7 +678,9 @@ static int alua_activate(struct scsi_device *sdev, | |||
672 | goto out; | 678 | goto out; |
673 | } | 679 | } |
674 | 680 | ||
675 | if (h->tpgs & TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED) { | 681 | if (h->tpgs & TPGS_MODE_EXPLICIT && |
682 | h->state != TPGS_STATE_OPTIMIZED && | ||
683 | h->state != TPGS_STATE_LBA_DEPENDENT) { | ||
676 | h->callback_fn = fn; | 684 | h->callback_fn = fn; |
677 | h->callback_data = data; | 685 | h->callback_data = data; |
678 | err = submit_stpg(h); | 686 | err = submit_stpg(h); |
@@ -698,8 +706,11 @@ static int alua_prep_fn(struct scsi_device *sdev, struct request *req) | |||
698 | struct alua_dh_data *h = get_alua_data(sdev); | 706 | struct alua_dh_data *h = get_alua_data(sdev); |
699 | int ret = BLKPREP_OK; | 707 | int ret = BLKPREP_OK; |
700 | 708 | ||
701 | if (h->state != TPGS_STATE_OPTIMIZED && | 709 | if (h->state == TPGS_STATE_TRANSITIONING) |
702 | h->state != TPGS_STATE_NONOPTIMIZED) { | 710 | ret = BLKPREP_DEFER; |
711 | else if (h->state != TPGS_STATE_OPTIMIZED && | ||
712 | h->state != TPGS_STATE_NONOPTIMIZED && | ||
713 | h->state != TPGS_STATE_LBA_DEPENDENT) { | ||
703 | ret = BLKPREP_KILL; | 714 | ret = BLKPREP_KILL; |
704 | req->cmd_flags |= REQ_QUIET; | 715 | req->cmd_flags |= REQ_QUIET; |
705 | } | 716 | } |