|
@@ -46,13 +46,16 @@
|
|
#define TPGS_SUPPORT_OFFLINE 0x40
|
|
#define TPGS_SUPPORT_OFFLINE 0x40
|
|
#define TPGS_SUPPORT_TRANSITION 0x80
|
|
#define TPGS_SUPPORT_TRANSITION 0x80
|
|
|
|
|
|
|
|
+#define RTPG_FMT_MASK 0x70
|
|
|
|
+#define RTPG_FMT_EXT_HDR 0x10
|
|
|
|
+
|
|
#define TPGS_MODE_UNINITIALIZED -1
|
|
#define TPGS_MODE_UNINITIALIZED -1
|
|
#define TPGS_MODE_NONE 0x0
|
|
#define TPGS_MODE_NONE 0x0
|
|
#define TPGS_MODE_IMPLICIT 0x1
|
|
#define TPGS_MODE_IMPLICIT 0x1
|
|
#define TPGS_MODE_EXPLICIT 0x2
|
|
#define TPGS_MODE_EXPLICIT 0x2
|
|
|
|
|
|
#define ALUA_INQUIRY_SIZE 36
|
|
#define ALUA_INQUIRY_SIZE 36
|
|
-#define ALUA_FAILOVER_TIMEOUT (60 * HZ)
|
|
|
|
|
|
+#define ALUA_FAILOVER_TIMEOUT 60
|
|
#define ALUA_FAILOVER_RETRIES 5
|
|
#define ALUA_FAILOVER_RETRIES 5
|
|
|
|
|
|
/* flags passed from user level */
|
|
/* flags passed from user level */
|
|
@@ -68,6 +71,7 @@ struct alua_dh_data {
|
|
unsigned char inq[ALUA_INQUIRY_SIZE];
|
|
unsigned char inq[ALUA_INQUIRY_SIZE];
|
|
unsigned char *buff;
|
|
unsigned char *buff;
|
|
int bufflen;
|
|
int bufflen;
|
|
|
|
+ unsigned char transition_tmo;
|
|
unsigned char sense[SCSI_SENSE_BUFFERSIZE];
|
|
unsigned char sense[SCSI_SENSE_BUFFERSIZE];
|
|
int senselen;
|
|
int senselen;
|
|
struct scsi_device *sdev;
|
|
struct scsi_device *sdev;
|
|
@@ -128,7 +132,7 @@ static struct request *get_alua_req(struct scsi_device *sdev,
|
|
rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
|
|
rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
|
|
REQ_FAILFAST_DRIVER;
|
|
REQ_FAILFAST_DRIVER;
|
|
rq->retries = ALUA_FAILOVER_RETRIES;
|
|
rq->retries = ALUA_FAILOVER_RETRIES;
|
|
- rq->timeout = ALUA_FAILOVER_TIMEOUT;
|
|
|
|
|
|
+ rq->timeout = ALUA_FAILOVER_TIMEOUT * HZ;
|
|
|
|
|
|
return rq;
|
|
return rq;
|
|
}
|
|
}
|
|
@@ -185,7 +189,7 @@ static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
|
|
|
|
|
|
/* Prepare the command. */
|
|
/* Prepare the command. */
|
|
rq->cmd[0] = MAINTENANCE_IN;
|
|
rq->cmd[0] = MAINTENANCE_IN;
|
|
- rq->cmd[1] = MI_REPORT_TARGET_PGS;
|
|
|
|
|
|
+ rq->cmd[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT;
|
|
rq->cmd[6] = (h->bufflen >> 24) & 0xff;
|
|
rq->cmd[6] = (h->bufflen >> 24) & 0xff;
|
|
rq->cmd[7] = (h->bufflen >> 16) & 0xff;
|
|
rq->cmd[7] = (h->bufflen >> 16) & 0xff;
|
|
rq->cmd[8] = (h->bufflen >> 8) & 0xff;
|
|
rq->cmd[8] = (h->bufflen >> 8) & 0xff;
|
|
@@ -519,8 +523,14 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
|
|
unsigned char *ucp;
|
|
unsigned char *ucp;
|
|
unsigned err;
|
|
unsigned err;
|
|
unsigned long expiry, interval = 1000;
|
|
unsigned long expiry, interval = 1000;
|
|
|
|
+ unsigned int tpg_desc_tbl_off;
|
|
|
|
+ unsigned char orig_transition_tmo;
|
|
|
|
+
|
|
|
|
+ if (!h->transition_tmo)
|
|
|
|
+ expiry = round_jiffies_up(jiffies + ALUA_FAILOVER_TIMEOUT * HZ);
|
|
|
|
+ else
|
|
|
|
+ expiry = round_jiffies_up(jiffies + h->transition_tmo * HZ);
|
|
|
|
|
|
- expiry = round_jiffies_up(jiffies + ALUA_FAILOVER_TIMEOUT);
|
|
|
|
retry:
|
|
retry:
|
|
err = submit_rtpg(sdev, h);
|
|
err = submit_rtpg(sdev, h);
|
|
|
|
|
|
@@ -556,7 +566,28 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
|
|
goto retry;
|
|
goto retry;
|
|
}
|
|
}
|
|
|
|
|
|
- for (k = 4, ucp = h->buff + 4; k < len; k += off, ucp += off) {
|
|
|
|
|
|
+ orig_transition_tmo = h->transition_tmo;
|
|
|
|
+ if ((h->buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR && h->buff[5] != 0)
|
|
|
|
+ h->transition_tmo = h->buff[5];
|
|
|
|
+ else
|
|
|
|
+ h->transition_tmo = ALUA_FAILOVER_TIMEOUT;
|
|
|
|
+
|
|
|
|
+ if (orig_transition_tmo != h->transition_tmo) {
|
|
|
|
+ sdev_printk(KERN_INFO, sdev,
|
|
|
|
+ "%s: transition timeout set to %d seconds\n",
|
|
|
|
+ ALUA_DH_NAME, h->transition_tmo);
|
|
|
|
+ expiry = jiffies + h->transition_tmo * HZ;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if ((h->buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR)
|
|
|
|
+ tpg_desc_tbl_off = 8;
|
|
|
|
+ else
|
|
|
|
+ tpg_desc_tbl_off = 4;
|
|
|
|
+
|
|
|
|
+ for (k = tpg_desc_tbl_off, ucp = h->buff + tpg_desc_tbl_off;
|
|
|
|
+ k < len;
|
|
|
|
+ k += off, ucp += off) {
|
|
|
|
+
|
|
if (h->group_id == (ucp[2] << 8) + ucp[3]) {
|
|
if (h->group_id == (ucp[2] << 8) + ucp[3]) {
|
|
h->state = ucp[0] & 0x0f;
|
|
h->state = ucp[0] & 0x0f;
|
|
h->pref = ucp[0] >> 7;
|
|
h->pref = ucp[0] >> 7;
|