scsi_dh_alua: Handle all states correctly
PATCH 1/1 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 <[email protected]>
Acked-by Mike Snitzer <[email protected]>
drivers/scsi/device_handler/scsi_dh_alua.c +38 -27
@@ -1,7 +1,7 @@/* * 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. * * This program is free software; you can redistribute it and/or modify
@@ -20,17 +20,19 @@* */ #include <linux/slab.h> +#include <linux/delay.h> #include <scsi/scsi.h> #include <scsi/scsi_eh.h> #include <scsi/scsi_dh.h> #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_NONOPTIMIZED 0x1#define TPGS_STATE_STANDBY 0x2#define TPGS_STATE_UNAVAILABLE 0x3 +#define TPGS_STATE_LBA_DEPENDENT 0x4#define TPGS_STATE_OFFLINE 0xe#define TPGS_STATE_TRANSITIONING 0xf
@@ -39,6 +41,7 @@#define TPGS_SUPPORT_NONOPTIMIZED 0x02#define TPGS_SUPPORT_STANDBY 0x04#define TPGS_SUPPORT_UNAVAILABLE 0x08 +#define TPGS_SUPPORT_LBA_DEPENDENT 0x10#define TPGS_SUPPORT_OFFLINE 0x40#define TPGS_SUPPORT_TRANSITION 0x80
@@ -460,6 +463,8 @@ static char print_alua_state(int state)return 'S' ;case TPGS_STATE_UNAVAILABLE :return 'U' ; +case TPGS_STATE_LBA_DEPENDENT : +return 'L' ;case TPGS_STATE_OFFLINE :return 'O' ;case TPGS_STATE_TRANSITIONING :
@@ -542,7 +547,9 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)int len, k, off, valid_states =0 ;char *ucp;unsigned err; +unsigned long expiry, interval =10 ; + expiry =round_jiffies_up (jiffies +ALUA_FAILOVER_TIMEOUT ); retry: err =submit_rtpg (sdev, h);
@@ -553,7 +560,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)return SCSI_DH_IO ; err =alua_check_sense (sdev, &sense_hdr); -if (err ==ADD_TO_MLQUEUE ) +if (err ==ADD_TO_MLQUEUE &&time_before (jiffies, expiry)) goto retry; sdev_printk(KERN_INFO, sdev, "%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) }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), valid_states&TPGS_SUPPORT_TRANSITION ?'T' :'t' , 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_STANDBY ?'S' :'s' , valid_states&TPGS_SUPPORT_NONOPTIMIZED ?'N' :'n' , valid_states&TPGS_SUPPORT_OPTIMIZED ?'A' :'a' ); -if (h->tpgs &TPGS_MODE_EXPLICIT ) { -switch (h->state) { -case TPGS_STATE_TRANSITIONING : +switch (h->state) { +case TPGS_STATE_TRANSITIONING : +if (time_before (jiffies, expiry)) {/* State transition, retry */ + interval *=10 ; +msleep (interval); goto retry; -break ; -case TPGS_STATE_OFFLINE : -/* Path is offline, fail */ - err =SCSI_DH_DEV_OFFLINED ; -break ; -default : -break ; } - }else { -/* Only Implicit ALUA support */ -if (h->state ==TPGS_STATE_OPTIMIZED || - h->state ==TPGS_STATE_NONOPTIMIZED || - h->state ==TPGS_STATE_STANDBY ) -/* Useable path if active */ - err =SCSI_DH_OK ; -else -/* Path unuseable for unavailable/offline */ - err =SCSI_DH_DEV_OFFLINED ; +/* Transitioning time exceeded, set port to standby */ + err =SCSI_DH_RETRY ; + h->state =TPGS_STATE_STANDBY ; +break ; +case TPGS_STATE_OFFLINE : +case TPGS_STATE_UNAVAILABLE : +/* Path unuseable for unavailable/offline */ + err =SCSI_DH_DEV_OFFLINED ; +break ; +default : +/* Useable path if active */ + err =SCSI_DH_OK ; +break ; }return err; }
@@ -672,7 +678,9 @@ static int alua_activate(struct scsi_device *sdev, 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_data = data; err =submit_stpg (h);
@@ -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);int ret =BLKPREP_OK ; -if (h->state !=TPGS_STATE_OPTIMIZED && - h->state !=TPGS_STATE_NONOPTIMIZED ) { +if (h->state ==TPGS_STATE_TRANSITIONING ) + ret =BLKPREP_DEFER ; +else if (h->state !=TPGS_STATE_OPTIMIZED && + h->state !=TPGS_STATE_NONOPTIMIZED && + h->state !=TPGS_STATE_LBA_DEPENDENT ) { ret =BLKPREP_KILL ; req->cmd_flags |=REQ_QUIET ; }