aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorHannes Reinecke <hare@suse.de>2010-09-24 09:57:04 -0400
committerJames Bottomley <James.Bottomley@suse.de>2010-10-07 18:22:22 -0400
commit69723d178da97b09ae8996f60fbf2f0cf68d6d61 (patch)
treeaef50073d685f31de4fc84e060dc59e8549e78b1 /drivers/scsi
parente27d6169c79e3c75edc74a14424a7856e7ff487c (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.c65
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 }