Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

authored by

Hannes Reinecke and committed by
James Bottomley
69723d17 e27d6169

+38 -27
+38 -27
drivers/scsi/device_handler/scsi_dh_alua.c
··· 1 1 /* 2 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 5 * All rights reserved. 6 6 * 7 7 * This program is free software; you can redistribute it and/or modify ··· 20 20 * 21 21 */ 22 22 #include <linux/slab.h> 23 + #include <linux/delay.h> 23 24 #include <scsi/scsi.h> 24 25 #include <scsi/scsi_eh.h> 25 26 #include <scsi/scsi_dh.h> 26 27 27 28 #define ALUA_DH_NAME "alua" 28 - #define ALUA_DH_VER "1.2" 29 + #define ALUA_DH_VER "1.3" 29 30 30 31 #define TPGS_STATE_OPTIMIZED 0x0 31 32 #define TPGS_STATE_NONOPTIMIZED 0x1 32 33 #define TPGS_STATE_STANDBY 0x2 33 34 #define TPGS_STATE_UNAVAILABLE 0x3 35 + #define TPGS_STATE_LBA_DEPENDENT 0x4 34 36 #define TPGS_STATE_OFFLINE 0xe 35 37 #define TPGS_STATE_TRANSITIONING 0xf 36 38 ··· 41 39 #define TPGS_SUPPORT_NONOPTIMIZED 0x02 42 40 #define TPGS_SUPPORT_STANDBY 0x04 43 41 #define TPGS_SUPPORT_UNAVAILABLE 0x08 42 + #define TPGS_SUPPORT_LBA_DEPENDENT 0x10 44 43 #define TPGS_SUPPORT_OFFLINE 0x40 45 44 #define TPGS_SUPPORT_TRANSITION 0x80 46 45 ··· 463 460 return 'S'; 464 461 case TPGS_STATE_UNAVAILABLE: 465 462 return 'U'; 463 + case TPGS_STATE_LBA_DEPENDENT: 464 + return 'L'; 466 465 case TPGS_STATE_OFFLINE: 467 466 return 'O'; 468 467 case TPGS_STATE_TRANSITIONING: ··· 547 542 int len, k, off, valid_states = 0; 548 543 char *ucp; 549 544 unsigned err; 545 + unsigned long expiry, interval = 10; 550 546 547 + expiry = round_jiffies_up(jiffies + ALUA_FAILOVER_TIMEOUT); 551 548 retry: 552 549 err = submit_rtpg(sdev, h); 553 550 ··· 560 553 return SCSI_DH_IO; 561 554 562 555 err = alua_check_sense(sdev, &sense_hdr); 563 - if (err == ADD_TO_MLQUEUE) 556 + if (err == ADD_TO_MLQUEUE && time_before(jiffies, expiry)) 564 557 goto retry; 565 558 sdev_printk(KERN_INFO, sdev, 566 559 "%s: rtpg sense code %02x/%02x/%02x\n", ··· 594 587 } 595 588 596 589 sdev_printk(KERN_INFO, sdev, 597 - "%s: port group %02x state %c supports %c%c%c%c%c%c\n", 590 + "%s: port group %02x state %c supports %c%c%c%c%c%c%c\n", 598 591 ALUA_DH_NAME, h->group_id, print_alua_state(h->state), 599 592 valid_states&TPGS_SUPPORT_TRANSITION?'T':'t', 600 593 valid_states&TPGS_SUPPORT_OFFLINE?'O':'o', 594 + valid_states&TPGS_SUPPORT_LBA_DEPENDENT?'L':'l', 601 595 valid_states&TPGS_SUPPORT_UNAVAILABLE?'U':'u', 602 596 valid_states&TPGS_SUPPORT_STANDBY?'S':'s', 603 597 valid_states&TPGS_SUPPORT_NONOPTIMIZED?'N':'n', 604 598 valid_states&TPGS_SUPPORT_OPTIMIZED?'A':'a'); 605 599 606 - if (h->tpgs & TPGS_MODE_EXPLICIT) { 607 - switch (h->state) { 608 - case TPGS_STATE_TRANSITIONING: 600 + switch (h->state) { 601 + case TPGS_STATE_TRANSITIONING: 602 + if (time_before(jiffies, expiry)) { 609 603 /* State transition, retry */ 604 + interval *= 10; 605 + msleep(interval); 610 606 goto retry; 611 - break; 612 - case TPGS_STATE_OFFLINE: 613 - /* Path is offline, fail */ 614 - err = SCSI_DH_DEV_OFFLINED; 615 - break; 616 - default: 617 - break; 618 607 } 619 - } else { 620 - /* Only Implicit ALUA support */ 621 - if (h->state == TPGS_STATE_OPTIMIZED || 622 - h->state == TPGS_STATE_NONOPTIMIZED || 623 - h->state == TPGS_STATE_STANDBY) 624 - /* Useable path if active */ 625 - err = SCSI_DH_OK; 626 - else 627 - /* Path unuseable for unavailable/offline */ 628 - err = SCSI_DH_DEV_OFFLINED; 608 + /* Transitioning time exceeded, set port to standby */ 609 + err = SCSI_DH_RETRY; 610 + h->state = TPGS_STATE_STANDBY; 611 + break; 612 + case TPGS_STATE_OFFLINE: 613 + case TPGS_STATE_UNAVAILABLE: 614 + /* Path unuseable for unavailable/offline */ 615 + err = SCSI_DH_DEV_OFFLINED; 616 + break; 617 + default: 618 + /* Useable path if active */ 619 + err = SCSI_DH_OK; 620 + break; 629 621 } 630 622 return err; 631 623 } ··· 678 672 goto out; 679 673 } 680 674 681 - if (h->tpgs & TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED) { 675 + if (h->tpgs & TPGS_MODE_EXPLICIT && 676 + h->state != TPGS_STATE_OPTIMIZED && 677 + h->state != TPGS_STATE_LBA_DEPENDENT) { 682 678 h->callback_fn = fn; 683 679 h->callback_data = data; 684 680 err = submit_stpg(h); ··· 706 698 struct alua_dh_data *h = get_alua_data(sdev); 707 699 int ret = BLKPREP_OK; 708 700 709 - if (h->state != TPGS_STATE_OPTIMIZED && 710 - h->state != TPGS_STATE_NONOPTIMIZED) { 701 + if (h->state == TPGS_STATE_TRANSITIONING) 702 + ret = BLKPREP_DEFER; 703 + else if (h->state != TPGS_STATE_OPTIMIZED && 704 + h->state != TPGS_STATE_NONOPTIMIZED && 705 + h->state != TPGS_STATE_LBA_DEPENDENT) { 711 706 ret = BLKPREP_KILL; 712 707 req->cmd_flags |= REQ_QUIET; 713 708 }