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 | |
| 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>
| -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 | } |
