|
@@ -60,11 +60,17 @@ struct alua_dh_data {
|
|
|
int bufflen;
|
|
|
unsigned char sense[SCSI_SENSE_BUFFERSIZE];
|
|
|
int senselen;
|
|
|
+ struct scsi_device *sdev;
|
|
|
+ activate_complete callback_fn;
|
|
|
+ void *callback_data;
|
|
|
};
|
|
|
|
|
|
#define ALUA_POLICY_SWITCH_CURRENT 0
|
|
|
#define ALUA_POLICY_SWITCH_ALL 1
|
|
|
|
|
|
+static char print_alua_state(int);
|
|
|
+static int alua_check_sense(struct scsi_device *, struct scsi_sense_hdr *);
|
|
|
+
|
|
|
static inline struct alua_dh_data *get_alua_data(struct scsi_device *sdev)
|
|
|
{
|
|
|
struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data;
|
|
@@ -230,19 +236,72 @@ done:
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * alua_stpg - Evaluate SET TARGET GROUP STATES
|
|
|
+ * @sdev: the device to be evaluated
|
|
|
+ * @state: the new target group state
|
|
|
+ *
|
|
|
+ * Send a SET TARGET GROUP STATES command to the device.
|
|
|
+ * We only have to test here if we should resubmit the command;
|
|
|
+ * any other error is assumed as a failure.
|
|
|
+ */
|
|
|
+static void stpg_endio(struct request *req, int error)
|
|
|
+{
|
|
|
+ struct alua_dh_data *h = req->end_io_data;
|
|
|
+ struct scsi_sense_hdr sense_hdr;
|
|
|
+ unsigned err = SCSI_DH_IO;
|
|
|
+
|
|
|
+ if (error || host_byte(req->errors) != DID_OK ||
|
|
|
+ msg_byte(req->errors) != COMMAND_COMPLETE)
|
|
|
+ goto done;
|
|
|
+
|
|
|
+ if (err == SCSI_DH_IO && h->senselen > 0) {
|
|
|
+ err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
|
|
|
+ &sense_hdr);
|
|
|
+ if (!err) {
|
|
|
+ err = SCSI_DH_IO;
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+ err = alua_check_sense(h->sdev, &sense_hdr);
|
|
|
+ if (err == ADD_TO_MLQUEUE) {
|
|
|
+ err = SCSI_DH_RETRY;
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+ sdev_printk(KERN_INFO, h->sdev,
|
|
|
+ "%s: stpg sense code: %02x/%02x/%02x\n",
|
|
|
+ ALUA_DH_NAME, sense_hdr.sense_key,
|
|
|
+ sense_hdr.asc, sense_hdr.ascq);
|
|
|
+ err = SCSI_DH_IO;
|
|
|
+ }
|
|
|
+ if (err == SCSI_DH_OK) {
|
|
|
+ h->state = TPGS_STATE_OPTIMIZED;
|
|
|
+ sdev_printk(KERN_INFO, h->sdev,
|
|
|
+ "%s: port group %02x switched to state %c\n",
|
|
|
+ ALUA_DH_NAME, h->group_id,
|
|
|
+ print_alua_state(h->state));
|
|
|
+ }
|
|
|
+done:
|
|
|
+ blk_put_request(req);
|
|
|
+ if (h->callback_fn) {
|
|
|
+ h->callback_fn(h->callback_data, err);
|
|
|
+ h->callback_fn = h->callback_data = NULL;
|
|
|
+ }
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* submit_stpg - Issue a SET TARGET GROUP STATES command
|
|
|
- * @sdev: sdev the command should be sent to
|
|
|
*
|
|
|
* Currently we're only setting the current target port group state
|
|
|
* to 'active/optimized' and let the array firmware figure out
|
|
|
* the states of the remaining groups.
|
|
|
*/
|
|
|
-static unsigned submit_stpg(struct scsi_device *sdev, struct alua_dh_data *h)
|
|
|
+static unsigned submit_stpg(struct alua_dh_data *h)
|
|
|
{
|
|
|
struct request *rq;
|
|
|
int err = SCSI_DH_RES_TEMP_UNAVAIL;
|
|
|
int stpg_len = 8;
|
|
|
+ struct scsi_device *sdev = h->sdev;
|
|
|
|
|
|
/* Prepare the data buffer */
|
|
|
memset(h->buff, 0, stpg_len);
|
|
@@ -252,7 +311,7 @@ static unsigned submit_stpg(struct scsi_device *sdev, struct alua_dh_data *h)
|
|
|
|
|
|
rq = get_alua_req(sdev, h->buff, stpg_len, WRITE);
|
|
|
if (!rq)
|
|
|
- goto done;
|
|
|
+ return SCSI_DH_RES_TEMP_UNAVAIL;
|
|
|
|
|
|
/* Prepare the command. */
|
|
|
rq->cmd[0] = MAINTENANCE_OUT;
|
|
@@ -266,17 +325,9 @@ static unsigned submit_stpg(struct scsi_device *sdev, struct alua_dh_data *h)
|
|
|
rq->sense = h->sense;
|
|
|
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
|
|
|
rq->sense_len = h->senselen = 0;
|
|
|
+ rq->end_io_data = h;
|
|
|
|
|
|
- err = blk_execute_rq(rq->q, NULL, rq, 1);
|
|
|
- if (err == -EIO) {
|
|
|
- sdev_printk(KERN_INFO, sdev,
|
|
|
- "%s: stpg failed with %x\n",
|
|
|
- ALUA_DH_NAME, rq->errors);
|
|
|
- h->senselen = rq->sense_len;
|
|
|
- err = SCSI_DH_IO;
|
|
|
- }
|
|
|
- blk_put_request(rq);
|
|
|
-done:
|
|
|
+ blk_execute_rq_nowait(rq->q, NULL, rq, 1, stpg_endio);
|
|
|
return err;
|
|
|
}
|
|
|
|
|
@@ -476,50 +527,6 @@ static int alua_check_sense(struct scsi_device *sdev,
|
|
|
return SCSI_RETURN_NOT_HANDLED;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * alua_stpg - Evaluate SET TARGET GROUP STATES
|
|
|
- * @sdev: the device to be evaluated
|
|
|
- * @state: the new target group state
|
|
|
- *
|
|
|
- * Send a SET TARGET GROUP STATES command to the device.
|
|
|
- * We only have to test here if we should resubmit the command;
|
|
|
- * any other error is assumed as a failure.
|
|
|
- */
|
|
|
-static int alua_stpg(struct scsi_device *sdev, int state,
|
|
|
- struct alua_dh_data *h)
|
|
|
-{
|
|
|
- struct scsi_sense_hdr sense_hdr;
|
|
|
- unsigned err;
|
|
|
- int retry = ALUA_FAILOVER_RETRIES;
|
|
|
-
|
|
|
- retry:
|
|
|
- err = submit_stpg(sdev, h);
|
|
|
- if (err == SCSI_DH_IO && h->senselen > 0) {
|
|
|
- err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
|
|
|
- &sense_hdr);
|
|
|
- if (!err)
|
|
|
- return SCSI_DH_IO;
|
|
|
- err = alua_check_sense(sdev, &sense_hdr);
|
|
|
- if (retry > 0 && err == ADD_TO_MLQUEUE) {
|
|
|
- retry--;
|
|
|
- goto retry;
|
|
|
- }
|
|
|
- sdev_printk(KERN_INFO, sdev,
|
|
|
- "%s: stpg sense code: %02x/%02x/%02x\n",
|
|
|
- ALUA_DH_NAME, sense_hdr.sense_key,
|
|
|
- sense_hdr.asc, sense_hdr.ascq);
|
|
|
- err = SCSI_DH_IO;
|
|
|
- }
|
|
|
- if (err == SCSI_DH_OK) {
|
|
|
- h->state = state;
|
|
|
- sdev_printk(KERN_INFO, sdev,
|
|
|
- "%s: port group %02x switched to state %c\n",
|
|
|
- ALUA_DH_NAME, h->group_id,
|
|
|
- print_alua_state(h->state) );
|
|
|
- }
|
|
|
- return err;
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* alua_rtpg - Evaluate REPORT TARGET GROUP STATES
|
|
|
* @sdev: the device to be evaluated.
|
|
@@ -664,8 +671,14 @@ static int alua_activate(struct scsi_device *sdev,
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- if (h->tpgs & TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED)
|
|
|
- err = alua_stpg(sdev, TPGS_STATE_OPTIMIZED, h);
|
|
|
+ if (h->tpgs & TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED) {
|
|
|
+ h->callback_fn = fn;
|
|
|
+ h->callback_data = data;
|
|
|
+ err = submit_stpg(h);
|
|
|
+ if (err == SCSI_DH_OK)
|
|
|
+ return 0;
|
|
|
+ h->callback_fn = h->callback_data = NULL;
|
|
|
+ }
|
|
|
|
|
|
out:
|
|
|
if (fn)
|
|
@@ -748,6 +761,7 @@ static int alua_bus_attach(struct scsi_device *sdev)
|
|
|
h->rel_port = -1;
|
|
|
h->buff = h->inq;
|
|
|
h->bufflen = ALUA_INQUIRY_SIZE;
|
|
|
+ h->sdev = sdev;
|
|
|
|
|
|
err = alua_initialize(sdev, h);
|
|
|
if (err != SCSI_DH_OK)
|