Commit 69723d17 authored by Hannes Reinecke's avatar Hannes Reinecke Committed by James Bottomley

[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: default avatarHannes Reinecke <hare@suse.de>
Acked-by: default avatarMike Snitzer <snitzer@redhat.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent e27d6169
/* /*
* Generic SCSI-3 ALUA SCSI Device Handler * Generic SCSI-3 ALUA SCSI Device Handler
* *
* Copyright (C) 2007, 2008 Hannes Reinecke, SUSE Linux Products GmbH. * Copyright (C) 2007-2010 Hannes Reinecke, SUSE Linux Products GmbH.
* All rights reserved. * All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -20,17 +20,19 @@ ...@@ -20,17 +20,19 @@
* *
*/ */
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/delay.h>
#include <scsi/scsi.h> #include <scsi/scsi.h>
#include <scsi/scsi_eh.h> #include <scsi/scsi_eh.h>
#include <scsi/scsi_dh.h> #include <scsi/scsi_dh.h>
#define ALUA_DH_NAME "alua" #define ALUA_DH_NAME "alua"
#define ALUA_DH_VER "1.2" #define ALUA_DH_VER "1.3"
#define TPGS_STATE_OPTIMIZED 0x0 #define TPGS_STATE_OPTIMIZED 0x0
#define TPGS_STATE_NONOPTIMIZED 0x1 #define TPGS_STATE_NONOPTIMIZED 0x1
#define TPGS_STATE_STANDBY 0x2 #define TPGS_STATE_STANDBY 0x2
#define TPGS_STATE_UNAVAILABLE 0x3 #define TPGS_STATE_UNAVAILABLE 0x3
#define TPGS_STATE_LBA_DEPENDENT 0x4
#define TPGS_STATE_OFFLINE 0xe #define TPGS_STATE_OFFLINE 0xe
#define TPGS_STATE_TRANSITIONING 0xf #define TPGS_STATE_TRANSITIONING 0xf
...@@ -39,6 +41,7 @@ ...@@ -39,6 +41,7 @@
#define TPGS_SUPPORT_NONOPTIMIZED 0x02 #define TPGS_SUPPORT_NONOPTIMIZED 0x02
#define TPGS_SUPPORT_STANDBY 0x04 #define TPGS_SUPPORT_STANDBY 0x04
#define TPGS_SUPPORT_UNAVAILABLE 0x08 #define TPGS_SUPPORT_UNAVAILABLE 0x08
#define TPGS_SUPPORT_LBA_DEPENDENT 0x10
#define TPGS_SUPPORT_OFFLINE 0x40 #define TPGS_SUPPORT_OFFLINE 0x40
#define TPGS_SUPPORT_TRANSITION 0x80 #define TPGS_SUPPORT_TRANSITION 0x80
...@@ -460,6 +463,8 @@ static char print_alua_state(int state) ...@@ -460,6 +463,8 @@ static char print_alua_state(int state)
return 'S'; return 'S';
case TPGS_STATE_UNAVAILABLE: case TPGS_STATE_UNAVAILABLE:
return 'U'; return 'U';
case TPGS_STATE_LBA_DEPENDENT:
return 'L';
case TPGS_STATE_OFFLINE: case TPGS_STATE_OFFLINE:
return 'O'; return 'O';
case TPGS_STATE_TRANSITIONING: case TPGS_STATE_TRANSITIONING:
...@@ -542,7 +547,9 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) ...@@ -542,7 +547,9 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
int len, k, off, valid_states = 0; int len, k, off, valid_states = 0;
char *ucp; char *ucp;
unsigned err; unsigned err;
unsigned long expiry, interval = 10;
expiry = round_jiffies_up(jiffies + ALUA_FAILOVER_TIMEOUT);
retry: retry:
err = submit_rtpg(sdev, h); err = submit_rtpg(sdev, h);
...@@ -553,7 +560,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) ...@@ -553,7 +560,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
return SCSI_DH_IO; return SCSI_DH_IO;
err = alua_check_sense(sdev, &sense_hdr); err = alua_check_sense(sdev, &sense_hdr);
if (err == ADD_TO_MLQUEUE) if (err == ADD_TO_MLQUEUE && time_before(jiffies, expiry))
goto retry; goto retry;
sdev_printk(KERN_INFO, sdev, sdev_printk(KERN_INFO, sdev,
"%s: rtpg sense code %02x/%02x/%02x\n", "%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,38 +594,37 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
} }
sdev_printk(KERN_INFO, sdev, sdev_printk(KERN_INFO, sdev,
"%s: port group %02x state %c supports %c%c%c%c%c%c\n", "%s: port group %02x state %c supports %c%c%c%c%c%c%c\n",
ALUA_DH_NAME, h->group_id, print_alua_state(h->state), ALUA_DH_NAME, h->group_id, print_alua_state(h->state),
valid_states&TPGS_SUPPORT_TRANSITION?'T':'t', valid_states&TPGS_SUPPORT_TRANSITION?'T':'t',
valid_states&TPGS_SUPPORT_OFFLINE?'O':'o', valid_states&TPGS_SUPPORT_OFFLINE?'O':'o',
valid_states&TPGS_SUPPORT_LBA_DEPENDENT?'L':'l',
valid_states&TPGS_SUPPORT_UNAVAILABLE?'U':'u', valid_states&TPGS_SUPPORT_UNAVAILABLE?'U':'u',
valid_states&TPGS_SUPPORT_STANDBY?'S':'s', valid_states&TPGS_SUPPORT_STANDBY?'S':'s',
valid_states&TPGS_SUPPORT_NONOPTIMIZED?'N':'n', valid_states&TPGS_SUPPORT_NONOPTIMIZED?'N':'n',
valid_states&TPGS_SUPPORT_OPTIMIZED?'A':'a'); valid_states&TPGS_SUPPORT_OPTIMIZED?'A':'a');
if (h->tpgs & TPGS_MODE_EXPLICIT) { switch (h->state) {
switch (h->state) { case TPGS_STATE_TRANSITIONING:
case TPGS_STATE_TRANSITIONING: if (time_before(jiffies, expiry)) {
/* State transition, retry */ /* State transition, retry */
interval *= 10;
msleep(interval);
goto retry; goto retry;
break;
case TPGS_STATE_OFFLINE:
/* Path is offline, fail */
err = SCSI_DH_DEV_OFFLINED;
break;
default:
break;
} }
} else { /* Transitioning time exceeded, set port to standby */
/* Only Implicit ALUA support */ err = SCSI_DH_RETRY;
if (h->state == TPGS_STATE_OPTIMIZED || h->state = TPGS_STATE_STANDBY;
h->state == TPGS_STATE_NONOPTIMIZED || break;
h->state == TPGS_STATE_STANDBY) case TPGS_STATE_OFFLINE:
/* Useable path if active */ case TPGS_STATE_UNAVAILABLE:
err = SCSI_DH_OK; /* Path unuseable for unavailable/offline */
else err = SCSI_DH_DEV_OFFLINED;
/* Path unuseable for unavailable/offline */ break;
err = SCSI_DH_DEV_OFFLINED; default:
/* Useable path if active */
err = SCSI_DH_OK;
break;
} }
return err; return err;
} }
...@@ -672,7 +678,9 @@ static int alua_activate(struct scsi_device *sdev, ...@@ -672,7 +678,9 @@ static int alua_activate(struct scsi_device *sdev,
goto out; goto out;
} }
if (h->tpgs & TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED) { if (h->tpgs & TPGS_MODE_EXPLICIT &&
h->state != TPGS_STATE_OPTIMIZED &&
h->state != TPGS_STATE_LBA_DEPENDENT) {
h->callback_fn = fn; h->callback_fn = fn;
h->callback_data = data; h->callback_data = data;
err = submit_stpg(h); err = submit_stpg(h);
...@@ -698,8 +706,11 @@ static int alua_prep_fn(struct scsi_device *sdev, struct request *req) ...@@ -698,8 +706,11 @@ static int alua_prep_fn(struct scsi_device *sdev, struct request *req)
struct alua_dh_data *h = get_alua_data(sdev); struct alua_dh_data *h = get_alua_data(sdev);
int ret = BLKPREP_OK; int ret = BLKPREP_OK;
if (h->state != TPGS_STATE_OPTIMIZED && if (h->state == TPGS_STATE_TRANSITIONING)
h->state != TPGS_STATE_NONOPTIMIZED) { ret = BLKPREP_DEFER;
else if (h->state != TPGS_STATE_OPTIMIZED &&
h->state != TPGS_STATE_NONOPTIMIZED &&
h->state != TPGS_STATE_LBA_DEPENDENT) {
ret = BLKPREP_KILL; ret = BLKPREP_KILL;
req->cmd_flags |= REQ_QUIET; req->cmd_flags |= REQ_QUIET;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment