* [PATCHv2 00/20] asynchronous ALUA device handler
@ 2015-07-08 9:05 Hannes Reinecke
2015-07-08 9:05 ` [PATCH 01/20] scsi_dh_alua: Disable ALUA handling for non-disk devices Hannes Reinecke
` (19 more replies)
0 siblings, 20 replies; 38+ messages in thread
From: Hannes Reinecke @ 2015-07-08 9:05 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, linux-scsi, Martin K. Petersen,
Bart van Assche, Hannes Reinecke
Hi all,
here is an update to the ALUA device handler. The main
features are:
- Topology discovery: the device handler creates a separate
port_group structure, which is used to update all paths to
the same port group. With that we achieve a significant
reduction of the number of RTPGs.
- Asynchronous state update: The ALUA state is now updated
from a workqueue item, so all concurrent RTPG calls are
coaleasced. The ALUA state update is also triggered by
sense codes indicating an ALUA state change.
- Use the existing vpd page 0x83 to detect device IDs
The patchset is relative to the V3 version of the scsi_dh update.
The entire tree can be found at
kernel/hare/scsi-devel branch alua.v3
on git.kernel.org
As usual, reviews and comments are welcome.
Changes to v1:
- Split off rtpg workqueue into separate items
- User per-port workqueues
- Incorporate review from Bart
- Incorporate review from hch
Hannes Reinecke (20):
scsi_dh_alua: Disable ALUA handling for non-disk devices
scsi_dh_alua: Use vpd_pg83 information
scsi_dh_alua: improved logging
scsi_dh_alua: Improve error handling
scsi: remove scsi_show_sense_hdr()
scsi_dh_alua: use flag for RTPG extended header
scsi_dh_alua: Pass buffer as function argument
scsi_dh_alua: Make stpg synchronous
scsi_dh_alua: switch to scsi_execute()
scsi_dh_alua: put sense buffer on stack
scsi_dh_alua: Use separate alua_port_group structure
scsi_dh_alua: allocate RTPG buffer separately
scsi_dh_alua: simplify sense code handling
scsi_dh_alua: parse target device id
revert "scsi_dh_alua: ALUA hander attach should succeed while TPG is
transitioning"
scsi_dh_alua: Use workqueue for RTPG
scsi_dh_alua: Recheck state on unit attention
scsi_dh_alua: update all port states
scsi_dh_alua: Send TEST UNIT READY to poll for transitioning
scsi_dh_alua: Update version to 2.0
drivers/scsi/device_handler/scsi_dh_alua.c | 1231 ++++++++++++++++++----------
include/scsi/scsi_dbg.h | 2 -
2 files changed, 809 insertions(+), 424 deletions(-)
--
1.8.5.2
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 01/20] scsi_dh_alua: Disable ALUA handling for non-disk devices
2015-07-08 9:05 [PATCHv2 00/20] asynchronous ALUA device handler Hannes Reinecke
@ 2015-07-08 9:05 ` Hannes Reinecke
2015-07-08 9:06 ` [PATCH 02/20] scsi_dh_alua: Use vpd_pg83 information Hannes Reinecke
` (18 subsequent siblings)
19 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2015-07-08 9:05 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, linux-scsi, Martin K. Petersen,
Bart van Assche, Hannes Reinecke
Non-disk devices might support ALUA, but the firmware
implementation is untested and frequently broken.
As we're don't actually need it disable ALUA support
for non-disk device for now.
Signed-off-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Bart Van Assche <bart.vanassche@sandisk.com>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index cc2773b..7d01ef0 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -320,6 +320,18 @@ static int alua_check_tpgs(struct scsi_device *sdev, struct alua_dh_data *h)
{
int err = SCSI_DH_OK;
+ /*
+ * ALUA support for non-disk devices is fraught with
+ * difficulties, so disable it for now.
+ */
+ if (sdev->type != TYPE_DISK) {
+ h->tpgs = TPGS_MODE_NONE;
+ sdev_printk(KERN_INFO, sdev,
+ "%s: disable for non-disk devices\n",
+ ALUA_DH_NAME);
+ return SCSI_DH_DEV_UNSUPP;
+ }
+
h->tpgs = scsi_device_tpgs(sdev);
switch (h->tpgs) {
case TPGS_MODE_EXPLICIT|TPGS_MODE_IMPLICIT:
--
1.8.5.2
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 02/20] scsi_dh_alua: Use vpd_pg83 information
2015-07-08 9:05 [PATCHv2 00/20] asynchronous ALUA device handler Hannes Reinecke
2015-07-08 9:05 ` [PATCH 01/20] scsi_dh_alua: Disable ALUA handling for non-disk devices Hannes Reinecke
@ 2015-07-08 9:06 ` Hannes Reinecke
2015-07-08 9:06 ` [PATCH 03/20] scsi_dh_alua: improved logging Hannes Reinecke
` (17 subsequent siblings)
19 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2015-07-08 9:06 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, linux-scsi, Martin K. Petersen,
Bart van Assche, Hannes Reinecke
The SCSI device now has the VPD page 0x83 information attached,
so there is no need to query it again.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 83 +++++-------------------------
1 file changed, 13 insertions(+), 70 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 7d01ef0..f15b977 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -131,43 +131,6 @@ static struct request *get_alua_req(struct scsi_device *sdev,
}
/*
- * submit_vpd_inquiry - Issue an INQUIRY VPD page 0x83 command
- * @sdev: sdev the command should be sent to
- */
-static int submit_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
-{
- struct request *rq;
- int err = SCSI_DH_RES_TEMP_UNAVAIL;
-
- rq = get_alua_req(sdev, h->buff, h->bufflen, READ);
- if (!rq)
- goto done;
-
- /* Prepare the command. */
- rq->cmd[0] = INQUIRY;
- rq->cmd[1] = 1;
- rq->cmd[2] = 0x83;
- rq->cmd[4] = h->bufflen;
- rq->cmd_len = COMMAND_SIZE(INQUIRY);
-
- rq->sense = h->sense;
- memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
- rq->sense_len = h->senselen = 0;
-
- err = blk_execute_rq(rq->q, NULL, rq, 1);
- if (err == -EIO) {
- sdev_printk(KERN_INFO, sdev,
- "%s: evpd inquiry failed with %x\n",
- ALUA_DH_NAME, rq->errors);
- h->senselen = rq->sense_len;
- err = SCSI_DH_IO;
- }
- blk_put_request(rq);
-done:
- return err;
-}
-
-/*
* submit_rtpg - Issue a REPORT TARGET GROUP STATES command
* @sdev: sdev the command should be sent to
*/
@@ -359,43 +322,24 @@ static int alua_check_tpgs(struct scsi_device *sdev, struct alua_dh_data *h)
}
/*
- * alua_vpd_inquiry - Evaluate INQUIRY vpd page 0x83
+ * alua_check_vpd - Evaluate INQUIRY vpd page 0x83
* @sdev: device to be checked
*
* Extract the relative target port and the target port group
* descriptor from the list of identificators.
*/
-static int alua_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
+static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h)
{
- int len;
- unsigned err;
unsigned char *d;
- retry:
- err = submit_vpd_inquiry(sdev, h);
-
- if (err != SCSI_DH_OK)
- return err;
-
- /* Check if vpd page exceeds initial buffer */
- len = (h->buff[2] << 8) + h->buff[3] + 4;
- if (len > h->bufflen) {
- /* Resubmit with the correct length */
- if (realloc_buffer(h, len)) {
- sdev_printk(KERN_WARNING, sdev,
- "%s: kmalloc buffer failed\n",
- ALUA_DH_NAME);
- /* Temporary failure, bypass */
- return SCSI_DH_DEV_TEMP_BUSY;
- }
- goto retry;
- }
+ if (!sdev->vpd_pg83)
+ return SCSI_DH_DEV_UNSUPP;
/*
- * Now look for the correct descriptor.
+ * Look for the correct descriptor.
*/
- d = h->buff + 4;
- while (d < h->buff + len) {
+ d = sdev->vpd_pg83 + 4;
+ while (d < sdev->vpd_pg83 + sdev->vpd_pg83_len) {
switch (d[1] & 0xf) {
case 0x4:
/* Relative target port */
@@ -422,14 +366,13 @@ static int alua_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
ALUA_DH_NAME);
h->state = TPGS_STATE_OPTIMIZED;
h->tpgs = TPGS_MODE_NONE;
- err = SCSI_DH_DEV_UNSUPP;
- } else {
- sdev_printk(KERN_INFO, sdev,
- "%s: port group %02x rel port %02x\n",
- ALUA_DH_NAME, h->group_id, h->rel_port);
+ return SCSI_DH_DEV_UNSUPP;
}
+ sdev_printk(KERN_INFO, sdev,
+ "%s: port group %02x rel port %02x\n",
+ ALUA_DH_NAME, h->group_id, h->rel_port);
- return err;
+ return 0;
}
static char print_alua_state(int state)
@@ -692,7 +635,7 @@ static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h)
if (err != SCSI_DH_OK)
goto out;
- err = alua_vpd_inquiry(sdev, h);
+ err = alua_check_vpd(sdev, h);
if (err != SCSI_DH_OK)
goto out;
--
1.8.5.2
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 03/20] scsi_dh_alua: improved logging
2015-07-08 9:05 [PATCHv2 00/20] asynchronous ALUA device handler Hannes Reinecke
2015-07-08 9:05 ` [PATCH 01/20] scsi_dh_alua: Disable ALUA handling for non-disk devices Hannes Reinecke
2015-07-08 9:06 ` [PATCH 02/20] scsi_dh_alua: Use vpd_pg83 information Hannes Reinecke
@ 2015-07-08 9:06 ` Hannes Reinecke
2015-07-08 9:06 ` [PATCH 04/20] scsi_dh_alua: Improve error handling Hannes Reinecke
` (16 subsequent siblings)
19 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2015-07-08 9:06 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, linux-scsi, Martin K. Petersen,
Bart van Assche, Hannes Reinecke
Issue different logging messages if ALUA is not supported
or the TPGS setting is invalid.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index f15b977..a20c8bf 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -310,12 +310,18 @@ static int alua_check_tpgs(struct scsi_device *sdev, struct alua_dh_data *h)
sdev_printk(KERN_INFO, sdev, "%s: supports implicit TPGS\n",
ALUA_DH_NAME);
break;
- default:
- h->tpgs = TPGS_MODE_NONE;
+ case TPGS_MODE_NONE:
sdev_printk(KERN_INFO, sdev, "%s: not supported\n",
ALUA_DH_NAME);
err = SCSI_DH_DEV_UNSUPP;
break;
+ default:
+ sdev_printk(KERN_INFO, sdev,
+ "%s: unsupported TPGS setting %d\n",
+ ALUA_DH_NAME, h->tpgs);
+ h->tpgs = TPGS_MODE_NONE;
+ err = SCSI_DH_DEV_UNSUPP;
+ break;
}
return err;
--
1.8.5.2
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 04/20] scsi_dh_alua: Improve error handling
2015-07-08 9:05 [PATCHv2 00/20] asynchronous ALUA device handler Hannes Reinecke
` (2 preceding siblings ...)
2015-07-08 9:06 ` [PATCH 03/20] scsi_dh_alua: improved logging Hannes Reinecke
@ 2015-07-08 9:06 ` Hannes Reinecke
2015-07-24 14:48 ` Christoph Hellwig
2015-07-08 9:06 ` [PATCH 05/20] scsi: remove scsi_show_sense_hdr() Hannes Reinecke
` (15 subsequent siblings)
19 siblings, 1 reply; 38+ messages in thread
From: Hannes Reinecke @ 2015-07-08 9:06 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, linux-scsi, Martin K. Petersen,
Bart van Assche, Hannes Reinecke
Improve error handling and use standard logging functions
instead of hand-crafted ones.
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 78 +++++++++++++++---------------
1 file changed, 39 insertions(+), 39 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index a20c8bf..0b92319 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -23,6 +23,7 @@
#include <linux/delay.h>
#include <linux/module.h>
#include <scsi/scsi.h>
+#include <scsi/scsi_dbg.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_dh.h>
@@ -138,11 +139,13 @@ static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h,
bool rtpg_ext_hdr_req)
{
struct request *rq;
- int err = SCSI_DH_RES_TEMP_UNAVAIL;
+ int err;
rq = get_alua_req(sdev, h->buff, h->bufflen, READ);
- if (!rq)
+ if (!rq) {
+ err = DRIVER_BUSY << 24;
goto done;
+ }
/* Prepare the command. */
rq->cmd[0] = MAINTENANCE_IN;
@@ -160,13 +163,10 @@ static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h,
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
rq->sense_len = h->senselen = 0;
- err = blk_execute_rq(rq->q, NULL, rq, 1);
- if (err == -EIO) {
- sdev_printk(KERN_INFO, sdev,
- "%s: rtpg failed with %x\n",
- ALUA_DH_NAME, rq->errors);
+ blk_execute_rq(rq->q, NULL, rq, 1);
+ if (rq->errors) {
+ err = rq->errors;
h->senselen = rq->sense_len;
- err = SCSI_DH_IO;
}
blk_put_request(rq);
done:
@@ -174,13 +174,11 @@ done:
}
/*
- * alua_stpg - Evaluate SET TARGET GROUP STATES
+ * stpg_endio - 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.
+ * Evaluate a SET TARGET GROUP STATES command response.
*/
static void stpg_endio(struct request *req, int error)
{
@@ -194,22 +192,16 @@ static void stpg_endio(struct request *req, int error)
goto done;
}
- if (req->sense_len > 0) {
- err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
- &sense_hdr);
- if (!err) {
- err = SCSI_DH_IO;
- goto done;
- }
+ if (scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
+ &sense_hdr)) {
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);
+ sdev_printk(KERN_INFO, h->sdev, "%s: stpg failed\n",
+ ALUA_DH_NAME);
+ scsi_print_sense_hdr(h->sdev, ALUA_DH_NAME, &sense_hdr);
err = SCSI_DH_IO;
} else if (error)
err = SCSI_DH_IO;
@@ -494,7 +486,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
struct scsi_sense_hdr sense_hdr;
int len, k, off, valid_states = 0;
unsigned char *ucp;
- unsigned err;
+ unsigned err, retval;
bool rtpg_ext_hdr_req = 1;
unsigned long expiry, interval = 0;
unsigned int tpg_desc_tbl_off;
@@ -506,13 +498,20 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
expiry = round_jiffies_up(jiffies + h->transition_tmo * HZ);
retry:
- err = submit_rtpg(sdev, h, rtpg_ext_hdr_req);
-
- 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;
+ retval = submit_rtpg(sdev, h, rtpg_ext_hdr_req);
+
+ if (retval) {
+ if (!scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
+ &sense_hdr)) {
+ sdev_printk(KERN_INFO, sdev,
+ "%s: rtpg failed, result %d\n",
+ ALUA_DH_NAME, retval);
+ if (driver_byte(retval) == DRIVER_BUSY)
+ err = SCSI_DH_DEV_TEMP_BUSY;
+ else
+ err = SCSI_DH_IO;
+ return err;
+ }
/*
* submit_rtpg() has failed on existing arrays
@@ -530,16 +529,17 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
}
err = alua_check_sense(sdev, &sense_hdr);
- if (err == ADD_TO_MLQUEUE && time_before(jiffies, expiry))
+ if (err == ADD_TO_MLQUEUE && time_before(jiffies, expiry)) {
+ sdev_printk(KERN_ERR, sdev, "%s: rtpg retry\n",
+ ALUA_DH_NAME);
+ scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
goto retry;
- sdev_printk(KERN_INFO, sdev,
- "%s: rtpg sense code %02x/%02x/%02x\n",
- ALUA_DH_NAME, sense_hdr.sense_key,
- sense_hdr.asc, sense_hdr.ascq);
- err = SCSI_DH_IO;
+ }
+ sdev_printk(KERN_ERR, sdev, "%s: rtpg failed\n",
+ ALUA_DH_NAME);
+ scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
+ return SCSI_DH_IO;
}
- if (err != SCSI_DH_OK)
- return err;
len = (h->buff[0] << 24) + (h->buff[1] << 16) +
(h->buff[2] << 8) + h->buff[3] + 4;
--
1.8.5.2
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 05/20] scsi: remove scsi_show_sense_hdr()
2015-07-08 9:05 [PATCHv2 00/20] asynchronous ALUA device handler Hannes Reinecke
` (3 preceding siblings ...)
2015-07-08 9:06 ` [PATCH 04/20] scsi_dh_alua: Improve error handling Hannes Reinecke
@ 2015-07-08 9:06 ` Hannes Reinecke
2015-07-08 9:06 ` [PATCH 06/20] scsi_dh_alua: use flag for RTPG extended header Hannes Reinecke
` (14 subsequent siblings)
19 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2015-07-08 9:06 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, linux-scsi, Martin K. Petersen,
Bart van Assche, Hannes Reinecke
Last caller is gone, so remove it.
Reviewed-by: Bart Van Assche <bart.vanassche@sandisk.com>
Reviewed-by: Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
include/scsi/scsi_dbg.h | 2 --
1 file changed, 2 deletions(-)
diff --git a/include/scsi/scsi_dbg.h b/include/scsi/scsi_dbg.h
index f8170e9..56710e0 100644
--- a/include/scsi/scsi_dbg.h
+++ b/include/scsi/scsi_dbg.h
@@ -12,8 +12,6 @@ extern size_t __scsi_format_command(char *, size_t,
const unsigned char *, size_t);
extern void scsi_show_extd_sense(const struct scsi_device *, const char *,
unsigned char, unsigned char);
-extern void scsi_show_sense_hdr(const struct scsi_device *, const char *,
- const struct scsi_sense_hdr *);
extern void scsi_print_sense_hdr(const struct scsi_device *, const char *,
const struct scsi_sense_hdr *);
extern void scsi_print_sense(const struct scsi_cmnd *);
--
1.8.5.2
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 06/20] scsi_dh_alua: use flag for RTPG extended header
2015-07-08 9:05 [PATCHv2 00/20] asynchronous ALUA device handler Hannes Reinecke
` (4 preceding siblings ...)
2015-07-08 9:06 ` [PATCH 05/20] scsi: remove scsi_show_sense_hdr() Hannes Reinecke
@ 2015-07-08 9:06 ` Hannes Reinecke
2015-07-08 9:06 ` [PATCH 07/20] scsi_dh_alua: Pass buffer as function argument Hannes Reinecke
` (13 subsequent siblings)
19 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2015-07-08 9:06 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, linux-scsi, Martin K. Petersen,
Bart van Assche, Hannes Reinecke
We should be using a flag when RTPG extended header is not
supported, that saves us sending RTPG twice for older arrays.
Reviewed-by: Bart Van Assche <bart.vanassche@sandisk.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 0b92319..3f4fe0e 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -59,8 +59,9 @@
#define ALUA_FAILOVER_TIMEOUT 60
#define ALUA_FAILOVER_RETRIES 5
-/* flags passed from user level */
+/* device handler flags */
#define ALUA_OPTIMIZE_STPG 1
+#define ALUA_RTPG_EXT_HDR_UNSUPP 2
struct alua_dh_data {
int group_id;
@@ -135,8 +136,7 @@ static struct request *get_alua_req(struct scsi_device *sdev,
* submit_rtpg - Issue a REPORT TARGET GROUP STATES command
* @sdev: sdev the command should be sent to
*/
-static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h,
- bool rtpg_ext_hdr_req)
+static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
{
struct request *rq;
int err;
@@ -149,7 +149,7 @@ static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h,
/* Prepare the command. */
rq->cmd[0] = MAINTENANCE_IN;
- if (rtpg_ext_hdr_req)
+ if (!(h->flags & ALUA_RTPG_EXT_HDR_UNSUPP))
rq->cmd[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT;
else
rq->cmd[1] = MI_REPORT_TARGET_PGS;
@@ -487,7 +487,6 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
int len, k, off, valid_states = 0;
unsigned char *ucp;
unsigned err, retval;
- bool rtpg_ext_hdr_req = 1;
unsigned long expiry, interval = 0;
unsigned int tpg_desc_tbl_off;
unsigned char orig_transition_tmo;
@@ -498,7 +497,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
expiry = round_jiffies_up(jiffies + h->transition_tmo * HZ);
retry:
- retval = submit_rtpg(sdev, h, rtpg_ext_hdr_req);
+ retval = submit_rtpg(sdev, h);
if (retval) {
if (!scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
@@ -521,10 +520,10 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
* The retry without rtpg_ext_hdr_req set
* handles this.
*/
- if (rtpg_ext_hdr_req == 1 &&
+ if (!(h->flags & ALUA_RTPG_EXT_HDR_UNSUPP) &&
sense_hdr.sense_key == ILLEGAL_REQUEST &&
sense_hdr.asc == 0x24 && sense_hdr.ascq == 0) {
- rtpg_ext_hdr_req = 0;
+ h->flags |= ALUA_RTPG_EXT_HDR_UNSUPP;
goto retry;
}
--
1.8.5.2
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 07/20] scsi_dh_alua: Pass buffer as function argument
2015-07-08 9:05 [PATCHv2 00/20] asynchronous ALUA device handler Hannes Reinecke
` (5 preceding siblings ...)
2015-07-08 9:06 ` [PATCH 06/20] scsi_dh_alua: use flag for RTPG extended header Hannes Reinecke
@ 2015-07-08 9:06 ` Hannes Reinecke
2015-07-24 14:48 ` Christoph Hellwig
2015-07-08 9:06 ` [PATCH 08/20] scsi_dh_alua: Make stpg synchronous Hannes Reinecke
` (12 subsequent siblings)
19 siblings, 1 reply; 38+ messages in thread
From: Hannes Reinecke @ 2015-07-08 9:06 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, linux-scsi, Martin K. Petersen,
Bart van Assche, Hannes Reinecke
Pass in the buffer as a function argument for submit_vpd() and
submit_rtpg().
Reviewed-by: Bart Van Assche <bart.vanassche@sandisk.com>
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 24 +++++++++++-------------
1 file changed, 11 insertions(+), 13 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 3f4fe0e..28a3b99 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -22,6 +22,7 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/module.h>
+#include <asm/unaligned.h>
#include <scsi/scsi.h>
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_eh.h>
@@ -136,12 +137,13 @@ static struct request *get_alua_req(struct scsi_device *sdev,
* submit_rtpg - Issue a REPORT TARGET GROUP STATES command
* @sdev: sdev the command should be sent to
*/
-static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
+static unsigned submit_rtpg(struct scsi_device *sdev, unsigned char *buff,
+ int bufflen, unsigned char *sense, int flags)
{
struct request *rq;
int err;
- rq = get_alua_req(sdev, h->buff, h->bufflen, READ);
+ rq = get_alua_req(sdev, buff, bufflen, READ);
if (!rq) {
err = DRIVER_BUSY << 24;
goto done;
@@ -149,25 +151,21 @@ static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
/* Prepare the command. */
rq->cmd[0] = MAINTENANCE_IN;
- if (!(h->flags & ALUA_RTPG_EXT_HDR_UNSUPP))
+ if (!(flags & ALUA_RTPG_EXT_HDR_UNSUPP))
rq->cmd[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT;
else
rq->cmd[1] = MI_REPORT_TARGET_PGS;
- rq->cmd[6] = (h->bufflen >> 24) & 0xff;
- rq->cmd[7] = (h->bufflen >> 16) & 0xff;
- rq->cmd[8] = (h->bufflen >> 8) & 0xff;
- rq->cmd[9] = h->bufflen & 0xff;
+ put_unaligned_be32(bufflen, &rq->cmd[6]);
rq->cmd_len = COMMAND_SIZE(MAINTENANCE_IN);
- rq->sense = h->sense;
+ rq->sense = sense;
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
- rq->sense_len = h->senselen = 0;
+ rq->sense_len = 0;
blk_execute_rq(rq->q, NULL, rq, 1);
- if (rq->errors) {
+ if (rq->errors)
err = rq->errors;
- h->senselen = rq->sense_len;
- }
+
blk_put_request(rq);
done:
return err;
@@ -497,7 +495,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
expiry = round_jiffies_up(jiffies + h->transition_tmo * HZ);
retry:
- retval = submit_rtpg(sdev, h);
+ retval = submit_rtpg(sdev, h->buff, h->bufflen, h->sense, h->flags);
if (retval) {
if (!scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
--
1.8.5.2
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 08/20] scsi_dh_alua: Make stpg synchronous
2015-07-08 9:05 [PATCHv2 00/20] asynchronous ALUA device handler Hannes Reinecke
` (6 preceding siblings ...)
2015-07-08 9:06 ` [PATCH 07/20] scsi_dh_alua: Pass buffer as function argument Hannes Reinecke
@ 2015-07-08 9:06 ` Hannes Reinecke
2015-07-24 14:51 ` Christoph Hellwig
2015-07-08 9:06 ` [PATCH 09/20] scsi_dh_alua: switch to scsi_execute() Hannes Reinecke
` (11 subsequent siblings)
19 siblings, 1 reply; 38+ messages in thread
From: Hannes Reinecke @ 2015-07-08 9:06 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, linux-scsi, Martin K. Petersen,
Bart van Assche, Hannes Reinecke
We should be issuing STPG synchronously as we need to
evaluate the return code on failure.
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 189 +++++++++++++----------------
1 file changed, 87 insertions(+), 102 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 28a3b99..76bc66d 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -172,94 +172,46 @@ done:
}
/*
- * stpg_endio - Evaluate SET TARGET GROUP STATES
- * @sdev: the device to be evaluated
- * @state: the new target group state
- *
- * Evaluate a SET TARGET GROUP STATES command response.
- */
-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_OK;
-
- if (host_byte(req->errors) != DID_OK ||
- msg_byte(req->errors) != COMMAND_COMPLETE) {
- err = SCSI_DH_IO;
- goto done;
- }
-
- if (scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
- &sense_hdr)) {
- 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 failed\n",
- ALUA_DH_NAME);
- scsi_print_sense_hdr(h->sdev, ALUA_DH_NAME, &sense_hdr);
- err = SCSI_DH_IO;
- } else if (error)
- 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:
- req->end_io_data = NULL;
- __blk_put_request(req->q, 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
*
* 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 alua_dh_data *h)
+static unsigned submit_stpg(struct scsi_device *sdev, int group_id,
+ unsigned char *sense)
{
struct request *rq;
+ unsigned char stpg_data[8];
int stpg_len = 8;
- struct scsi_device *sdev = h->sdev;
+ int err = 0;
/* Prepare the data buffer */
- memset(h->buff, 0, stpg_len);
- h->buff[4] = TPGS_STATE_OPTIMIZED & 0x0f;
- h->buff[6] = (h->group_id >> 8) & 0xff;
- h->buff[7] = h->group_id & 0xff;
+ memset(stpg_data, 0, stpg_len);
+ stpg_data[4] = TPGS_STATE_OPTIMIZED & 0x0f;
+ put_unaligned_be16(group_id, &stpg_data[6]);
- rq = get_alua_req(sdev, h->buff, stpg_len, WRITE);
+ rq = get_alua_req(sdev, stpg_data, stpg_len, WRITE);
if (!rq)
- return SCSI_DH_RES_TEMP_UNAVAIL;
+ return DRIVER_BUSY << 24;
/* Prepare the command. */
rq->cmd[0] = MAINTENANCE_OUT;
rq->cmd[1] = MO_SET_TARGET_PGS;
- rq->cmd[6] = (stpg_len >> 24) & 0xff;
- rq->cmd[7] = (stpg_len >> 16) & 0xff;
- rq->cmd[8] = (stpg_len >> 8) & 0xff;
- rq->cmd[9] = stpg_len & 0xff;
+ put_unaligned_be32(stpg_len, &rq->cmd[6]);
rq->cmd_len = COMMAND_SIZE(MAINTENANCE_OUT);
- rq->sense = h->sense;
+ rq->sense = sense;
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
- rq->sense_len = h->senselen = 0;
- rq->end_io_data = h;
+ rq->sense_len = 0;
+
+ blk_execute_rq(rq->q, NULL, rq, 1);
+ if (rq->errors)
+ err = rq->errors;
+
+ blk_put_request(rq);
- blk_execute_rq_nowait(rq->q, NULL, rq, 1, stpg_endio);
- return SCSI_DH_OK;
+ return err;
}
/*
@@ -498,7 +450,8 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
retval = submit_rtpg(sdev, h->buff, h->bufflen, h->sense, h->flags);
if (retval) {
- if (!scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
+ if (!(driver_byte(retval) & DRIVER_SENSE) ||
+ !scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
&sense_hdr)) {
sdev_printk(KERN_INFO, sdev,
"%s: rtpg failed, result %d\n",
@@ -624,6 +577,69 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
}
/*
+ * alua_stpg - Issue a SET TARGET GROUP STATES command
+ *
+ * Issue a SET TARGET GROUP STATES command and evaluate the
+ * response. Returns SCSI_DH_RETRY per default to trigger
+ * a re-evaluation of the target group state.
+ */
+static unsigned alua_stpg(struct scsi_device *sdev, struct alua_dh_data *h)
+{
+ int retval;
+ struct scsi_sense_hdr sense_hdr;
+
+ if (!(h->tpgs & TPGS_MODE_EXPLICIT)) {
+ /* Only implicit ALUA supported, retry */
+ return SCSI_DH_RETRY;
+ }
+ switch (h->state) {
+ case TPGS_STATE_OPTIMIZED:
+ return SCSI_DH_OK;
+ case TPGS_STATE_NONOPTIMIZED:
+ if ((h->flags & ALUA_OPTIMIZE_STPG) &&
+ (!h->pref) &&
+ (h->tpgs & TPGS_MODE_IMPLICIT))
+ return SCSI_DH_OK;
+ break;
+ case TPGS_STATE_STANDBY:
+ case TPGS_STATE_UNAVAILABLE:
+ break;
+ case TPGS_STATE_OFFLINE:
+ return SCSI_DH_IO;
+ break;
+ case TPGS_STATE_TRANSITIONING:
+ break;
+ default:
+ sdev_printk(KERN_INFO, sdev,
+ "%s: stpg failed, unhandled TPGS state %d",
+ ALUA_DH_NAME, h->state);
+ return SCSI_DH_NOSYS;
+ break;
+ }
+ /* Set state to transitioning */
+ h->state = TPGS_STATE_TRANSITIONING;
+ retval = submit_stpg(sdev, h->group_id, h->sense);
+
+ if (retval) {
+ if (!(driver_byte(retval) & DRIVER_SENSE) ||
+ !scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
+ &sense_hdr)) {
+ sdev_printk(KERN_INFO, sdev,
+ "%s: stpg failed, result %d",
+ ALUA_DH_NAME, retval);
+ if (driver_byte(retval) == DRIVER_BUSY)
+ return SCSI_DH_DEV_TEMP_BUSY;
+ } else {
+ sdev_printk(KERN_INFO, h->sdev, "%s: stpg failed\n",
+ ALUA_DH_NAME);
+ scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
+ }
+ }
+ /* Retry RTPG */
+ return SCSI_DH_RETRY;
+}
+
+/*
* alua_initialize - Initialize ALUA state
* @sdev: the device to be initialized
*
@@ -700,7 +716,6 @@ static int alua_activate(struct scsi_device *sdev,
{
struct alua_dh_data *h = sdev->handler_data;
int err = SCSI_DH_OK;
- int stpg = 0;
err = alua_rtpg(sdev, h, 1);
if (err != SCSI_DH_OK)
@@ -709,39 +724,9 @@ static int alua_activate(struct scsi_device *sdev,
if (optimize_stpg)
h->flags |= ALUA_OPTIMIZE_STPG;
- if (h->tpgs & TPGS_MODE_EXPLICIT) {
- switch (h->state) {
- case TPGS_STATE_NONOPTIMIZED:
- stpg = 1;
- if ((h->flags & ALUA_OPTIMIZE_STPG) &&
- (!h->pref) &&
- (h->tpgs & TPGS_MODE_IMPLICIT))
- stpg = 0;
- break;
- case TPGS_STATE_STANDBY:
- case TPGS_STATE_UNAVAILABLE:
- stpg = 1;
- break;
- case TPGS_STATE_OFFLINE:
- err = SCSI_DH_IO;
- break;
- case TPGS_STATE_TRANSITIONING:
- err = SCSI_DH_RETRY;
- break;
- default:
- break;
- }
- }
-
- if (stpg) {
- 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;
- }
-
+ err = alua_stpg(sdev, h);
+ if (err == SCSI_DH_RETRY)
+ err = alua_rtpg(sdev, h, 1);
out:
if (fn)
fn(data, err);
--
1.8.5.2
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 09/20] scsi_dh_alua: switch to scsi_execute()
2015-07-08 9:05 [PATCHv2 00/20] asynchronous ALUA device handler Hannes Reinecke
` (7 preceding siblings ...)
2015-07-08 9:06 ` [PATCH 08/20] scsi_dh_alua: Make stpg synchronous Hannes Reinecke
@ 2015-07-08 9:06 ` Hannes Reinecke
2015-07-24 14:53 ` Christoph Hellwig
2015-07-08 9:06 ` [PATCH 10/20] scsi_dh_alua: put sense buffer on stack Hannes Reinecke
` (10 subsequent siblings)
19 siblings, 1 reply; 38+ messages in thread
From: Hannes Reinecke @ 2015-07-08 9:06 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, linux-scsi, Martin K. Petersen,
Bart van Assche, Hannes Reinecke
All commands are issued synchronously, so no need to open-code
scsi_execute anymore.
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 108 ++++++++---------------------
1 file changed, 27 insertions(+), 81 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 76bc66d..61301cf 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -103,72 +103,29 @@ static int realloc_buffer(struct alua_dh_data *h, unsigned len)
return 0;
}
-static struct request *get_alua_req(struct scsi_device *sdev,
- void *buffer, unsigned buflen, int rw)
-{
- struct request *rq;
- struct request_queue *q = sdev->request_queue;
-
- rq = blk_get_request(q, rw, GFP_NOIO);
-
- if (IS_ERR(rq)) {
- sdev_printk(KERN_INFO, sdev,
- "%s: blk_get_request failed\n", __func__);
- return NULL;
- }
- blk_rq_set_block_pc(rq);
-
- if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_NOIO)) {
- blk_put_request(rq);
- sdev_printk(KERN_INFO, sdev,
- "%s: blk_rq_map_kern failed\n", __func__);
- return NULL;
- }
-
- rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
- REQ_FAILFAST_DRIVER;
- rq->retries = ALUA_FAILOVER_RETRIES;
- rq->timeout = ALUA_FAILOVER_TIMEOUT * HZ;
-
- return rq;
-}
-
/*
* submit_rtpg - Issue a REPORT TARGET GROUP STATES command
* @sdev: sdev the command should be sent to
*/
-static unsigned submit_rtpg(struct scsi_device *sdev, unsigned char *buff,
+static int submit_rtpg(struct scsi_device *sdev, unsigned char *buff,
int bufflen, unsigned char *sense, int flags)
{
- struct request *rq;
- int err;
-
- rq = get_alua_req(sdev, buff, bufflen, READ);
- if (!rq) {
- err = DRIVER_BUSY << 24;
- goto done;
- }
+ u8 cdb[16];
+ int req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
+ REQ_FAILFAST_DRIVER;
/* Prepare the command. */
- rq->cmd[0] = MAINTENANCE_IN;
+ memset(cdb, 0x0, 16);
+ cdb[0] = MAINTENANCE_IN;
if (!(flags & ALUA_RTPG_EXT_HDR_UNSUPP))
- rq->cmd[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT;
+ cdb[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT;
else
- rq->cmd[1] = MI_REPORT_TARGET_PGS;
- put_unaligned_be32(bufflen, &rq->cmd[6]);
- rq->cmd_len = COMMAND_SIZE(MAINTENANCE_IN);
+ cdb[1] = MI_REPORT_TARGET_PGS;
+ put_unaligned_be32(bufflen, &cdb[6]);
- rq->sense = sense;
- memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
- rq->sense_len = 0;
-
- blk_execute_rq(rq->q, NULL, rq, 1);
- if (rq->errors)
- err = rq->errors;
-
- blk_put_request(rq);
-done:
- return err;
+ return scsi_execute(sdev, cdb, DMA_FROM_DEVICE, buff, bufflen,
+ sense, ALUA_FAILOVER_TIMEOUT * HZ,
+ ALUA_FAILOVER_RETRIES, req_flags, NULL);
}
/*
@@ -178,40 +135,29 @@ done:
* to 'active/optimized' and let the array firmware figure out
* the states of the remaining groups.
*/
-static unsigned submit_stpg(struct scsi_device *sdev, int group_id,
- unsigned char *sense)
+static int submit_stpg(struct scsi_device *sdev, int group_id,
+ unsigned char *sense)
{
- struct request *rq;
+ u8 cdb[COMMAND_SIZE(MAINTENANCE_OUT)];
unsigned char stpg_data[8];
int stpg_len = 8;
- int err = 0;
+ int req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
+ REQ_FAILFAST_DRIVER;
/* Prepare the data buffer */
memset(stpg_data, 0, stpg_len);
stpg_data[4] = TPGS_STATE_OPTIMIZED & 0x0f;
put_unaligned_be16(group_id, &stpg_data[6]);
- rq = get_alua_req(sdev, stpg_data, stpg_len, WRITE);
- if (!rq)
- return DRIVER_BUSY << 24;
-
/* Prepare the command. */
- rq->cmd[0] = MAINTENANCE_OUT;
- rq->cmd[1] = MO_SET_TARGET_PGS;
- put_unaligned_be32(stpg_len, &rq->cmd[6]);
- rq->cmd_len = COMMAND_SIZE(MAINTENANCE_OUT);
-
- rq->sense = sense;
- memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
- rq->sense_len = 0;
-
- blk_execute_rq(rq->q, NULL, rq, 1);
- if (rq->errors)
- err = rq->errors;
-
- blk_put_request(rq);
-
- return err;
+ memset(cdb, 0x0, COMMAND_SIZE(MAINTENANCE_OUT));
+ cdb[0] = MAINTENANCE_OUT;
+ cdb[1] = MO_SET_TARGET_PGS;
+ put_unaligned_be32(stpg_len, &cdb[6]);
+
+ return scsi_execute(sdev, cdb, DMA_TO_DEVICE, stpg_data, stpg_len,
+ sense, ALUA_FAILOVER_TIMEOUT * HZ,
+ ALUA_FAILOVER_RETRIES, req_flags, NULL);
}
/*
@@ -456,7 +402,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
sdev_printk(KERN_INFO, sdev,
"%s: rtpg failed, result %d\n",
ALUA_DH_NAME, retval);
- if (driver_byte(retval) == DRIVER_BUSY)
+ if (driver_byte(retval) == DRIVER_ERROR)
err = SCSI_DH_DEV_TEMP_BUSY;
else
err = SCSI_DH_IO;
@@ -627,7 +573,7 @@ static unsigned alua_stpg(struct scsi_device *sdev, struct alua_dh_data *h)
sdev_printk(KERN_INFO, sdev,
"%s: stpg failed, result %d",
ALUA_DH_NAME, retval);
- if (driver_byte(retval) == DRIVER_BUSY)
+ if (driver_byte(retval) == DRIVER_ERROR)
return SCSI_DH_DEV_TEMP_BUSY;
} else {
sdev_printk(KERN_INFO, h->sdev, "%s: stpg failed\n",
--
1.8.5.2
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 10/20] scsi_dh_alua: put sense buffer on stack
2015-07-08 9:05 [PATCHv2 00/20] asynchronous ALUA device handler Hannes Reinecke
` (8 preceding siblings ...)
2015-07-08 9:06 ` [PATCH 09/20] scsi_dh_alua: switch to scsi_execute() Hannes Reinecke
@ 2015-07-08 9:06 ` Hannes Reinecke
2015-07-08 9:06 ` [PATCH 11/20] scsi_dh_alua: Use separate alua_port_group structure Hannes Reinecke
` (9 subsequent siblings)
19 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2015-07-08 9:06 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, linux-scsi, Martin K. Petersen,
Bart van Assche, Hannes Reinecke
We don't need to have the sense buffer available all the time,
putting it on stack is totally sufficient.
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 61301cf..ea4a920 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -75,8 +75,6 @@ struct alua_dh_data {
unsigned char *buff;
int bufflen;
unsigned char transition_tmo;
- unsigned char sense[SCSI_SENSE_BUFFERSIZE];
- int senselen;
struct scsi_device *sdev;
activate_complete callback_fn;
void *callback_data;
@@ -379,6 +377,7 @@ static int alua_check_sense(struct scsi_device *sdev,
*/
static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_for_transition)
{
+ unsigned char sense[SCSI_SENSE_BUFFERSIZE];
struct scsi_sense_hdr sense_hdr;
int len, k, off, valid_states = 0;
unsigned char *ucp;
@@ -393,11 +392,11 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
expiry = round_jiffies_up(jiffies + h->transition_tmo * HZ);
retry:
- retval = submit_rtpg(sdev, h->buff, h->bufflen, h->sense, h->flags);
+ retval = submit_rtpg(sdev, h->buff, h->bufflen, sense, h->flags);
if (retval) {
if (!(driver_byte(retval) & DRIVER_SENSE) ||
- !scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
+ !scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE,
&sense_hdr)) {
sdev_printk(KERN_INFO, sdev,
"%s: rtpg failed, result %d\n",
@@ -532,6 +531,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
static unsigned alua_stpg(struct scsi_device *sdev, struct alua_dh_data *h)
{
int retval;
+ unsigned char sense[SCSI_SENSE_BUFFERSIZE];
struct scsi_sense_hdr sense_hdr;
if (!(h->tpgs & TPGS_MODE_EXPLICIT)) {
@@ -564,11 +564,11 @@ static unsigned alua_stpg(struct scsi_device *sdev, struct alua_dh_data *h)
}
/* Set state to transitioning */
h->state = TPGS_STATE_TRANSITIONING;
- retval = submit_stpg(sdev, h->group_id, h->sense);
+ retval = submit_stpg(sdev, h->group_id, sense);
if (retval) {
if (!(driver_byte(retval) & DRIVER_SENSE) ||
- !scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
+ !scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE,
&sense_hdr)) {
sdev_printk(KERN_INFO, sdev,
"%s: stpg failed, result %d",
--
1.8.5.2
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 11/20] scsi_dh_alua: Use separate alua_port_group structure
2015-07-08 9:05 [PATCHv2 00/20] asynchronous ALUA device handler Hannes Reinecke
` (9 preceding siblings ...)
2015-07-08 9:06 ` [PATCH 10/20] scsi_dh_alua: put sense buffer on stack Hannes Reinecke
@ 2015-07-08 9:06 ` Hannes Reinecke
2015-07-24 14:58 ` Christoph Hellwig
2015-07-08 9:06 ` [PATCH 12/20] scsi_dh_alua: allocate RTPG buffer separately Hannes Reinecke
` (8 subsequent siblings)
19 siblings, 1 reply; 38+ messages in thread
From: Hannes Reinecke @ 2015-07-08 9:06 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, linux-scsi, Martin K. Petersen,
Bart van Assche, Hannes Reinecke
The port group needs to be a separate structure as several
LUNs might belong to the same group.
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 210 +++++++++++++++++++----------
1 file changed, 137 insertions(+), 73 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index ea4a920..3f18f6b 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -64,9 +64,13 @@
#define ALUA_OPTIMIZE_STPG 1
#define ALUA_RTPG_EXT_HDR_UNSUPP 2
-struct alua_dh_data {
+static LIST_HEAD(port_group_list);
+static DEFINE_SPINLOCK(port_group_lock);
+
+struct alua_port_group {
+ struct kref kref;
+ struct list_head node;
int group_id;
- int rel_port;
int tpgs;
int state;
int pref;
@@ -75,6 +79,12 @@ struct alua_dh_data {
unsigned char *buff;
int bufflen;
unsigned char transition_tmo;
+};
+
+struct alua_dh_data {
+ struct alua_port_group *pg;
+ int rel_port;
+ int tpgs;
struct scsi_device *sdev;
activate_complete callback_fn;
void *callback_data;
@@ -86,21 +96,35 @@ struct alua_dh_data {
static char print_alua_state(int);
static int alua_check_sense(struct scsi_device *, struct scsi_sense_hdr *);
-static int realloc_buffer(struct alua_dh_data *h, unsigned len)
+static int realloc_buffer(struct alua_port_group *pg, unsigned len)
{
- if (h->buff && h->buff != h->inq)
- kfree(h->buff);
+ if (pg->buff && pg->buff != pg->inq)
+ kfree(pg->buff);
- h->buff = kmalloc(len, GFP_NOIO);
- if (!h->buff) {
- h->buff = h->inq;
- h->bufflen = ALUA_INQUIRY_SIZE;
+ pg->buff = kmalloc(len, GFP_NOIO);
+ if (!pg->buff) {
+ pg->buff = pg->inq;
+ pg->bufflen = ALUA_INQUIRY_SIZE;
return 1;
}
- h->bufflen = len;
+ pg->bufflen = len;
return 0;
}
+static void release_port_group(struct kref *kref)
+{
+ struct alua_port_group *pg;
+
+ pg = container_of(kref, struct alua_port_group, kref);
+ printk(KERN_WARNING "alua: release port group %d\n", pg->group_id);
+ spin_lock(&port_group_lock);
+ list_del(&pg->node);
+ spin_unlock(&port_group_lock);
+ if (pg->buff && pg->inq != pg->buff)
+ kfree(pg->buff);
+ kfree(pg);
+}
+
/*
* submit_rtpg - Issue a REPORT TARGET GROUP STATES command
* @sdev: sdev the command should be sent to
@@ -223,6 +247,8 @@ static int alua_check_tpgs(struct scsi_device *sdev, struct alua_dh_data *h)
static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h)
{
unsigned char *d;
+ int group_id = -1;
+ struct alua_port_group *pg = NULL;
if (!sdev->vpd_pg83)
return SCSI_DH_DEV_UNSUPP;
@@ -239,7 +265,7 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h)
break;
case 0x5:
/* Target port group */
- h->group_id = (d[6] << 8) + d[7];
+ group_id = (d[6] << 8) + d[7];
break;
default:
break;
@@ -247,7 +273,7 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h)
d += d[3] + 4;
}
- if (h->group_id == -1) {
+ if (group_id == -1) {
/*
* Internal error; TPGS supported but required
* VPD identification descriptors not present.
@@ -256,15 +282,33 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h)
sdev_printk(KERN_INFO, sdev,
"%s: No target port descriptors found\n",
ALUA_DH_NAME);
- h->state = TPGS_STATE_OPTIMIZED;
h->tpgs = TPGS_MODE_NONE;
return SCSI_DH_DEV_UNSUPP;
}
sdev_printk(KERN_INFO, sdev,
"%s: port group %02x rel port %02x\n",
- ALUA_DH_NAME, h->group_id, h->rel_port);
+ ALUA_DH_NAME, group_id, h->rel_port);
- return 0;
+ pg = kzalloc(sizeof(struct alua_port_group), GFP_KERNEL);
+ if (!pg) {
+ sdev_printk(KERN_WARNING, sdev,
+ "%s: kzalloc port group failed\n",
+ ALUA_DH_NAME);
+ /* Temporary failure, bypass */
+ return SCSI_DH_DEV_TEMP_BUSY;
+ }
+ pg->group_id = group_id;
+ pg->buff = pg->inq;
+ pg->bufflen = ALUA_INQUIRY_SIZE;
+ pg->tpgs = h->tpgs;
+ pg->state = TPGS_STATE_OPTIMIZED;
+ kref_init(&pg->kref);
+ spin_lock(&port_group_lock);
+ list_add(&pg->node, &port_group_list);
+ h->pg = pg;
+ spin_unlock(&port_group_lock);
+
+ return SCSI_DH_OK;
}
static char print_alua_state(int state)
@@ -375,7 +419,7 @@ static int alua_check_sense(struct scsi_device *sdev,
* Returns SCSI_DH_DEV_OFFLINED if the path is
* found to be unusable.
*/
-static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_for_transition)
+static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int wait_for_transition)
{
unsigned char sense[SCSI_SENSE_BUFFERSIZE];
struct scsi_sense_hdr sense_hdr;
@@ -386,13 +430,13 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
unsigned int tpg_desc_tbl_off;
unsigned char orig_transition_tmo;
- if (!h->transition_tmo)
+ if (!pg->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 + pg->transition_tmo * HZ);
retry:
- retval = submit_rtpg(sdev, h->buff, h->bufflen, sense, h->flags);
+ retval = submit_rtpg(sdev, pg->buff, pg->bufflen, sense, pg->flags);
if (retval) {
if (!(driver_byte(retval) & DRIVER_SENSE) ||
@@ -416,10 +460,10 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
* The retry without rtpg_ext_hdr_req set
* handles this.
*/
- if (!(h->flags & ALUA_RTPG_EXT_HDR_UNSUPP) &&
+ if (!(pg->flags & ALUA_RTPG_EXT_HDR_UNSUPP) &&
sense_hdr.sense_key == ILLEGAL_REQUEST &&
sense_hdr.asc == 0x24 && sense_hdr.ascq == 0) {
- h->flags |= ALUA_RTPG_EXT_HDR_UNSUPP;
+ pg->flags |= ALUA_RTPG_EXT_HDR_UNSUPP;
goto retry;
}
@@ -436,12 +480,11 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
return SCSI_DH_IO;
}
- len = (h->buff[0] << 24) + (h->buff[1] << 16) +
- (h->buff[2] << 8) + h->buff[3] + 4;
+ len = get_unaligned_be32(&pg->buff[0]) + 4;
- if (len > h->bufflen) {
+ if (len > pg->bufflen) {
/* Resubmit with the correct length */
- if (realloc_buffer(h, len)) {
+ if (realloc_buffer(pg, len)) {
sdev_printk(KERN_WARNING, sdev,
"%s: kmalloc buffer failed\n",__func__);
/* Temporary failure, bypass */
@@ -450,31 +493,32 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
goto retry;
}
- 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];
+ orig_transition_tmo = pg->transition_tmo;
+ if ((pg->buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR &&
+ pg->buff[5] != 0)
+ pg->transition_tmo = pg->buff[5];
else
- h->transition_tmo = ALUA_FAILOVER_TIMEOUT;
+ pg->transition_tmo = ALUA_FAILOVER_TIMEOUT;
- if (wait_for_transition && (orig_transition_tmo != h->transition_tmo)) {
+ if (wait_for_transition && (orig_transition_tmo != pg->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;
+ ALUA_DH_NAME, pg->transition_tmo);
+ expiry = jiffies + pg->transition_tmo * HZ;
}
- if ((h->buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR)
+ if ((pg->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;
+ for (k = tpg_desc_tbl_off, ucp = pg->buff + tpg_desc_tbl_off;
k < len;
k += off, ucp += off) {
- if (h->group_id == (ucp[2] << 8) + ucp[3]) {
- h->state = ucp[0] & 0x0f;
- h->pref = ucp[0] >> 7;
+ if (pg->group_id == (ucp[2] << 8) + ucp[3]) {
+ pg->state = ucp[0] & 0x0f;
+ pg->pref = ucp[0] >> 7;
valid_states = ucp[1];
}
off = 8 + (ucp[7] * 4);
@@ -482,8 +526,8 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
sdev_printk(KERN_INFO, sdev,
"%s: port group %02x state %c %s supports %c%c%c%c%c%c%c\n",
- ALUA_DH_NAME, h->group_id, print_alua_state(h->state),
- h->pref ? "preferred" : "non-preferred",
+ ALUA_DH_NAME, pg->group_id, print_alua_state(pg->state),
+ pg->pref ? "preferred" : "non-preferred",
valid_states&TPGS_SUPPORT_TRANSITION?'T':'t',
valid_states&TPGS_SUPPORT_OFFLINE?'O':'o',
valid_states&TPGS_SUPPORT_LBA_DEPENDENT?'L':'l',
@@ -492,7 +536,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
valid_states&TPGS_SUPPORT_NONOPTIMIZED?'N':'n',
valid_states&TPGS_SUPPORT_OPTIMIZED?'A':'a');
- switch (h->state) {
+ switch (pg->state) {
case TPGS_STATE_TRANSITIONING:
if (wait_for_transition) {
if (time_before(jiffies, expiry)) {
@@ -507,7 +551,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
}
/* Transitioning time exceeded, set port to standby */
- h->state = TPGS_STATE_STANDBY;
+ pg->state = TPGS_STATE_STANDBY;
break;
case TPGS_STATE_OFFLINE:
/* Path unusable */
@@ -528,23 +572,23 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
* response. Returns SCSI_DH_RETRY per default to trigger
* a re-evaluation of the target group state.
*/
-static unsigned alua_stpg(struct scsi_device *sdev, struct alua_dh_data *h)
+static unsigned alua_stpg(struct scsi_device *sdev, struct alua_port_group *pg)
{
int retval;
unsigned char sense[SCSI_SENSE_BUFFERSIZE];
struct scsi_sense_hdr sense_hdr;
- if (!(h->tpgs & TPGS_MODE_EXPLICIT)) {
+ if (!(pg->tpgs & TPGS_MODE_EXPLICIT)) {
/* Only implicit ALUA supported, retry */
return SCSI_DH_RETRY;
}
- switch (h->state) {
+ switch (pg->state) {
case TPGS_STATE_OPTIMIZED:
return SCSI_DH_OK;
case TPGS_STATE_NONOPTIMIZED:
- if ((h->flags & ALUA_OPTIMIZE_STPG) &&
- (!h->pref) &&
- (h->tpgs & TPGS_MODE_IMPLICIT))
+ if ((pg->flags & ALUA_OPTIMIZE_STPG) &&
+ (!pg->pref) &&
+ (pg->tpgs & TPGS_MODE_IMPLICIT))
return SCSI_DH_OK;
break;
case TPGS_STATE_STANDBY:
@@ -558,13 +602,13 @@ static unsigned alua_stpg(struct scsi_device *sdev, struct alua_dh_data *h)
default:
sdev_printk(KERN_INFO, sdev,
"%s: stpg failed, unhandled TPGS state %d",
- ALUA_DH_NAME, h->state);
+ ALUA_DH_NAME, pg->state);
return SCSI_DH_NOSYS;
break;
}
/* Set state to transitioning */
- h->state = TPGS_STATE_TRANSITIONING;
- retval = submit_stpg(sdev, h->group_id, sense);
+ pg->state = TPGS_STATE_TRANSITIONING;
+ retval = submit_stpg(sdev, pg->group_id, sense);
if (retval) {
if (!(driver_byte(retval) & DRIVER_SENSE) ||
@@ -576,7 +620,7 @@ static unsigned alua_stpg(struct scsi_device *sdev, struct alua_dh_data *h)
if (driver_byte(retval) == DRIVER_ERROR)
return SCSI_DH_DEV_TEMP_BUSY;
} else {
- sdev_printk(KERN_INFO, h->sdev, "%s: stpg failed\n",
+ sdev_printk(KERN_INFO, sdev, "%s: stpg failed\n",
ALUA_DH_NAME);
scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
}
@@ -601,13 +645,12 @@ static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h)
goto out;
err = alua_check_vpd(sdev, h);
- if (err != SCSI_DH_OK)
- goto out;
-
- err = alua_rtpg(sdev, h, 0);
- if (err != SCSI_DH_OK)
+ if (err != SCSI_DH_OK || !h->pg)
goto out;
+ kref_get(&h->pg->kref);
+ err = alua_rtpg(sdev, h->pg, 0);
+ kref_put(&h->pg->kref, release_port_group);
out:
return err;
}
@@ -623,6 +666,7 @@ out:
static int alua_set_params(struct scsi_device *sdev, const char *params)
{
struct alua_dh_data *h = sdev->handler_data;
+ struct alua_port_group *pg = NULL;
unsigned int optimize = 0, argc;
const char *p = params;
int result = SCSI_DH_OK;
@@ -635,10 +679,18 @@ static int alua_set_params(struct scsi_device *sdev, const char *params)
if ((sscanf(p, "%u", &optimize) != 1) || (optimize > 1))
return -EINVAL;
+ rcu_read_lock();
+ pg = rcu_dereference(h->pg);
+ if (!pg) {
+ rcu_read_unlock();
+ return -ENXIO;
+ }
+ rcu_read_unlock();
+
if (optimize)
- h->flags |= ALUA_OPTIMIZE_STPG;
+ pg->flags |= ALUA_OPTIMIZE_STPG;
else
- h->flags &= ~ALUA_OPTIMIZE_STPG;
+ pg->flags |= ~ALUA_OPTIMIZE_STPG;
return result;
}
@@ -663,16 +715,23 @@ static int alua_activate(struct scsi_device *sdev,
struct alua_dh_data *h = sdev->handler_data;
int err = SCSI_DH_OK;
- err = alua_rtpg(sdev, h, 1);
- if (err != SCSI_DH_OK)
+ if (!h->pg)
goto out;
+ kref_get(&h->pg->kref);
+
if (optimize_stpg)
- h->flags |= ALUA_OPTIMIZE_STPG;
+ h->pg->flags |= ALUA_OPTIMIZE_STPG;
- err = alua_stpg(sdev, h);
+ err = alua_rtpg(sdev, h->pg, 1);
+ if (err != SCSI_DH_OK) {
+ kref_put(&h->pg->kref, release_port_group);
+ goto out;
+ }
+ err = alua_stpg(sdev, h->pg);
if (err == SCSI_DH_RETRY)
- err = alua_rtpg(sdev, h, 1);
+ err = alua_rtpg(sdev, h->pg, 1);
+ kref_put(&h->pg->kref, release_port_group);
out:
if (fn)
fn(data, err);
@@ -688,13 +747,19 @@ out:
static int alua_prep_fn(struct scsi_device *sdev, struct request *req)
{
struct alua_dh_data *h = sdev->handler_data;
+ int state;
int ret = BLKPREP_OK;
- if (h->state == TPGS_STATE_TRANSITIONING)
+ if (!h->pg)
+ return ret;
+ kref_get(&h->pg->kref);
+ state = h->pg->state;
+ kref_put(&h->pg->kref, release_port_group);
+ if (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) {
+ else if (state != TPGS_STATE_OPTIMIZED &&
+ state != TPGS_STATE_NONOPTIMIZED &&
+ state != TPGS_STATE_LBA_DEPENDENT) {
ret = BLKPREP_KILL;
req->cmd_flags |= REQ_QUIET;
}
@@ -715,11 +780,8 @@ static int alua_bus_attach(struct scsi_device *sdev)
if (!h)
return -ENOMEM;
h->tpgs = TPGS_MODE_UNINITIALIZED;
- h->state = TPGS_STATE_OPTIMIZED;
- h->group_id = -1;
+ h->pg = NULL;
h->rel_port = -1;
- h->buff = h->inq;
- h->bufflen = ALUA_INQUIRY_SIZE;
h->sdev = sdev;
err = alua_initialize(sdev, h);
@@ -741,8 +803,10 @@ static void alua_bus_detach(struct scsi_device *sdev)
{
struct alua_dh_data *h = sdev->handler_data;
- if (h->buff && h->inq != h->buff)
- kfree(h->buff);
+ if (h->pg) {
+ kref_put(&h->pg->kref, release_port_group);
+ h->pg = NULL;
+ }
sdev->handler_data = NULL;
kfree(h);
}
--
1.8.5.2
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 12/20] scsi_dh_alua: allocate RTPG buffer separately
2015-07-08 9:05 [PATCHv2 00/20] asynchronous ALUA device handler Hannes Reinecke
` (10 preceding siblings ...)
2015-07-08 9:06 ` [PATCH 11/20] scsi_dh_alua: Use separate alua_port_group structure Hannes Reinecke
@ 2015-07-08 9:06 ` Hannes Reinecke
2015-07-24 14:59 ` Christoph Hellwig
2015-07-08 9:06 ` [PATCH 13/20] scsi_dh_alua: simplify sense code handling Hannes Reinecke
` (7 subsequent siblings)
19 siblings, 1 reply; 38+ messages in thread
From: Hannes Reinecke @ 2015-07-08 9:06 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, linux-scsi, Martin K. Petersen,
Bart van Assche, Hannes Reinecke
The RTPG buffer will only evaluated within alua_rtpg(),
so we can allocate it locally there and avoid having to
put it into the global structure.
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 55 ++++++++++++------------------
1 file changed, 21 insertions(+), 34 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 3f18f6b..e8bfbce 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -56,7 +56,7 @@
#define TPGS_MODE_IMPLICIT 0x1
#define TPGS_MODE_EXPLICIT 0x2
-#define ALUA_INQUIRY_SIZE 36
+#define ALUA_RTPG_SIZE 128
#define ALUA_FAILOVER_TIMEOUT 60
#define ALUA_FAILOVER_RETRIES 5
@@ -75,9 +75,6 @@ struct alua_port_group {
int state;
int pref;
unsigned flags; /* used for optimizing STPG */
- unsigned char inq[ALUA_INQUIRY_SIZE];
- unsigned char *buff;
- int bufflen;
unsigned char transition_tmo;
};
@@ -96,21 +93,6 @@ struct alua_dh_data {
static char print_alua_state(int);
static int alua_check_sense(struct scsi_device *, struct scsi_sense_hdr *);
-static int realloc_buffer(struct alua_port_group *pg, unsigned len)
-{
- if (pg->buff && pg->buff != pg->inq)
- kfree(pg->buff);
-
- pg->buff = kmalloc(len, GFP_NOIO);
- if (!pg->buff) {
- pg->buff = pg->inq;
- pg->bufflen = ALUA_INQUIRY_SIZE;
- return 1;
- }
- pg->bufflen = len;
- return 0;
-}
-
static void release_port_group(struct kref *kref)
{
struct alua_port_group *pg;
@@ -120,8 +102,6 @@ static void release_port_group(struct kref *kref)
spin_lock(&port_group_lock);
list_del(&pg->node);
spin_unlock(&port_group_lock);
- if (pg->buff && pg->inq != pg->buff)
- kfree(pg->buff);
kfree(pg);
}
@@ -298,8 +278,6 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h)
return SCSI_DH_DEV_TEMP_BUSY;
}
pg->group_id = group_id;
- pg->buff = pg->inq;
- pg->bufflen = ALUA_INQUIRY_SIZE;
pg->tpgs = h->tpgs;
pg->state = TPGS_STATE_OPTIMIZED;
kref_init(&pg->kref);
@@ -423,8 +401,8 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int w
{
unsigned char sense[SCSI_SENSE_BUFFERSIZE];
struct scsi_sense_hdr sense_hdr;
- int len, k, off, valid_states = 0;
- unsigned char *ucp;
+ int len, k, off, valid_states = 0, bufflen = ALUA_RTPG_SIZE;
+ unsigned char *ucp, *buff;
unsigned err, retval;
unsigned long expiry, interval = 0;
unsigned int tpg_desc_tbl_off;
@@ -435,8 +413,12 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int w
else
expiry = round_jiffies_up(jiffies + pg->transition_tmo * HZ);
+ buff = kzalloc(bufflen, GFP_KERNEL);
+ if (!buff)
+ return SCSI_DH_DEV_TEMP_BUSY;
+
retry:
- retval = submit_rtpg(sdev, pg->buff, pg->bufflen, sense, pg->flags);
+ retval = submit_rtpg(sdev, buff, bufflen, sense, pg->flags);
if (retval) {
if (!(driver_byte(retval) & DRIVER_SENSE) ||
@@ -449,6 +431,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int w
err = SCSI_DH_DEV_TEMP_BUSY;
else
err = SCSI_DH_IO;
+ kfree(buff);
return err;
}
@@ -477,14 +460,18 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int w
sdev_printk(KERN_ERR, sdev, "%s: rtpg failed\n",
ALUA_DH_NAME);
scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
+ kfree(buff);
return SCSI_DH_IO;
}
- len = get_unaligned_be32(&pg->buff[0]) + 4;
+ len = get_unaligned_be32(&buff[0]) + 4;
- if (len > pg->bufflen) {
+ if (len > bufflen) {
/* Resubmit with the correct length */
- if (realloc_buffer(pg, len)) {
+ kfree(buff);
+ bufflen = len;
+ buff = kmalloc(bufflen, GFP_KERNEL);
+ if (!buff) {
sdev_printk(KERN_WARNING, sdev,
"%s: kmalloc buffer failed\n",__func__);
/* Temporary failure, bypass */
@@ -494,9 +481,8 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int w
}
orig_transition_tmo = pg->transition_tmo;
- if ((pg->buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR &&
- pg->buff[5] != 0)
- pg->transition_tmo = pg->buff[5];
+ if ((buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR && buff[5] != 0)
+ pg->transition_tmo = buff[5];
else
pg->transition_tmo = ALUA_FAILOVER_TIMEOUT;
@@ -507,12 +493,12 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int w
expiry = jiffies + pg->transition_tmo * HZ;
}
- if ((pg->buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR)
+ if ((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 = pg->buff + tpg_desc_tbl_off;
+ for (k = tpg_desc_tbl_off, ucp = buff + tpg_desc_tbl_off;
k < len;
k += off, ucp += off) {
@@ -562,6 +548,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int w
err = SCSI_DH_OK;
break;
}
+ kfree(buff);
return err;
}
--
1.8.5.2
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 13/20] scsi_dh_alua: simplify sense code handling
2015-07-08 9:05 [PATCHv2 00/20] asynchronous ALUA device handler Hannes Reinecke
` (11 preceding siblings ...)
2015-07-08 9:06 ` [PATCH 12/20] scsi_dh_alua: allocate RTPG buffer separately Hannes Reinecke
@ 2015-07-08 9:06 ` Hannes Reinecke
2015-07-24 15:00 ` Christoph Hellwig
2015-07-08 9:06 ` [PATCH 14/20] scsi_dh_alua: parse target device id Hannes Reinecke
` (6 subsequent siblings)
19 siblings, 1 reply; 38+ messages in thread
From: Hannes Reinecke @ 2015-07-08 9:06 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, linux-scsi, Martin K. Petersen,
Bart van Assche, Hannes Reinecke
Most sense code is already handled in the generic
code, so we shouldn't be adding special cases here.
However, when doing so we need to check for
unit attention whenever we're sending an internal
command.
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 50 +++++++-----------------------
1 file changed, 11 insertions(+), 39 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index e8bfbce..f4d851a 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -91,7 +91,6 @@ struct alua_dh_data {
#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 void release_port_group(struct kref *kref)
{
@@ -321,28 +320,6 @@ static int alua_check_sense(struct scsi_device *sdev,
* LUN Not Accessible - ALUA state transition
*/
return ADD_TO_MLQUEUE;
- if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0b)
- /*
- * LUN Not Accessible -- Target port in standby state
- */
- return SUCCESS;
- if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0c)
- /*
- * LUN Not Accessible -- Target port in unavailable state
- */
- return SUCCESS;
- if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x12)
- /*
- * LUN Not Ready -- Offline
- */
- return SUCCESS;
- if (sdev->allow_restart &&
- sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x02)
- /*
- * if the device is not started, we need to wake
- * the error handler to start the motor
- */
- return FAILED;
break;
case UNIT_ATTENTION:
if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00)
@@ -357,7 +334,7 @@ static int alua_check_sense(struct scsi_device *sdev,
return ADD_TO_MLQUEUE;
if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x01)
/*
- * Mode Parameters Changed
+ * Mode Parameter Changed
*/
return ADD_TO_MLQUEUE;
if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06)
@@ -370,18 +347,6 @@ static int alua_check_sense(struct scsi_device *sdev,
* Implicit ALUA state transition failed
*/
return ADD_TO_MLQUEUE;
- if (sense_hdr->asc == 0x3f && sense_hdr->ascq == 0x03)
- /*
- * Inquiry data has changed
- */
- return ADD_TO_MLQUEUE;
- if (sense_hdr->asc == 0x3f && sense_hdr->ascq == 0x0e)
- /*
- * REPORTED_LUNS_DATA_HAS_CHANGED is reported
- * when switching controllers on targets like
- * Intel Multi-Flex. We can just retry.
- */
- return ADD_TO_MLQUEUE;
break;
}
@@ -449,9 +414,16 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int w
pg->flags |= ALUA_RTPG_EXT_HDR_UNSUPP;
goto retry;
}
-
- err = alua_check_sense(sdev, &sense_hdr);
- if (err == ADD_TO_MLQUEUE && time_before(jiffies, expiry)) {
+ /*
+ * Retry on ALUA state transition or if any
+ * UNIT ATTENTION occurred.
+ */
+ if (sense_hdr.sense_key == NOT_READY &&
+ sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a)
+ err = SCSI_DH_RETRY;
+ if (sense_hdr.sense_key == UNIT_ATTENTION)
+ err = SCSI_DH_RETRY;
+ if (err == SCSI_DH_RETRY && time_before(jiffies, expiry)) {
sdev_printk(KERN_ERR, sdev, "%s: rtpg retry\n",
ALUA_DH_NAME);
scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
--
1.8.5.2
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 14/20] scsi_dh_alua: parse target device id
2015-07-08 9:05 [PATCHv2 00/20] asynchronous ALUA device handler Hannes Reinecke
` (12 preceding siblings ...)
2015-07-08 9:06 ` [PATCH 13/20] scsi_dh_alua: simplify sense code handling Hannes Reinecke
@ 2015-07-08 9:06 ` Hannes Reinecke
2015-07-24 15:07 ` Christoph Hellwig
2015-07-08 9:06 ` [PATCH 15/20] revert "scsi_dh_alua: ALUA hander attach should succeed while TPG is transitioning" Hannes Reinecke
` (5 subsequent siblings)
19 siblings, 1 reply; 38+ messages in thread
From: Hannes Reinecke @ 2015-07-08 9:06 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, linux-scsi, Martin K. Petersen,
Bart van Assche, Hannes Reinecke
Parse VPD descriptor to figure out the device identification.
As devices might implement several descriptors the order
of preference is:
- NAA IEE Registered Extended
- EUI-64 based 16-byte
- EUI-64 based 12-byte
- NAA IEEE Registered
- NAA IEEE Extended
A SCSI name string descriptor is preferred to all of them
if the identification is longer than 16 bytes.
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 152 ++++++++++++++++++++++++++++-
1 file changed, 147 insertions(+), 5 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index f4d851a..6991171 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -70,6 +70,9 @@ static DEFINE_SPINLOCK(port_group_lock);
struct alua_port_group {
struct kref kref;
struct list_head node;
+ unsigned char device_id[256];
+ unsigned char device_id_str[256];
+ int device_id_size;
int group_id;
int tpgs;
int state;
@@ -227,17 +230,84 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h)
{
unsigned char *d;
int group_id = -1;
- struct alua_port_group *pg = NULL;
+ char device_id_str[256], *device_id = NULL;
+ int device_id_size, device_id_type = 0;
+ struct alua_port_group *tmp_pg, *pg = NULL;
if (!sdev->vpd_pg83)
return SCSI_DH_DEV_UNSUPP;
/*
* Look for the correct descriptor.
+ * Order of preference for lun descriptor:
+ * - SCSI name string
+ * - NAA IEEE Registered Extended
+ * - EUI-64 based 16-byte
+ * - EUI-64 based 12-byte
+ * - NAA IEEE Registered
+ * - NAA IEEE Extended
+ * as longer descriptors reduce the likelyhood
+ * of identification clashes.
*/
+ memset(device_id_str, 0, 256);
+ device_id_size = 0;
d = sdev->vpd_pg83 + 4;
while (d < sdev->vpd_pg83 + sdev->vpd_pg83_len) {
switch (d[1] & 0xf) {
+ case 0x2:
+ /* EUI-64 */
+ if ((d[1] & 0x30) == 0x00) {
+ if (device_id_size > d[3])
+ break;
+ /* Prefer NAA IEEE Registered Extended */
+ if (device_id_type == 0x3 &&
+ device_id_size == d[3])
+ break;
+ device_id_size = d[3];
+ device_id = d + 4;
+ device_id_type = d[1] & 0xf;
+ switch (device_id_size) {
+ case 8:
+ sprintf(device_id_str,
+ "eui.%8phN", d + 4);
+ break;
+ case 12:
+ sprintf(device_id_str,
+ "eui.%12phN", d + 4);
+ break;
+ case 16:
+ sprintf(device_id_str,
+ "eui.%16phN", d + 4);
+ break;
+ default:
+ device_id_size = 0;
+ break;
+ }
+ }
+ break;
+ case 0x3:
+ /* NAA */
+ if ((d[1] & 0x30) == 0x00) {
+ if (device_id_size > d[3])
+ break;
+ device_id_size = d[3];
+ device_id = d + 4;
+ device_id_type = d[1] & 0xf;
+ switch (device_id_size) {
+ case 8:
+ sprintf(device_id_str,
+ "naa.%8phN", d + 4);
+ break;
+ case 16:
+ sprintf(device_id_str,
+ "naa.%16phN", d + 4);
+ break;
+ default:
+ device_id_size = 0;
+ break;
+ }
+ }
+ break;
case 0x4:
/* Relative target port */
h->rel_port = (d[6] << 8) + d[7];
@@ -246,6 +316,21 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h)
/* Target port group */
group_id = (d[6] << 8) + d[7];
break;
+ case 0x8:
+ /* SCSI name string */
+ if ((d[1] & 0x30) == 0x00) {
+ /* SCSI name */
+ if (device_id_size > d[3])
+ break;
+ device_id_size = d[3];
+ device_id = d + 4;
+ device_id_type = d[1] & 0xf;
+ strncpy(device_id_str, d + 4, 256);
+ if (device_id_size > 255)
+ device_id_size = 255;
+ device_id_str[device_id_size] = '\0';
+ }
+ break;
default:
break;
}
@@ -264,9 +349,38 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h)
h->tpgs = TPGS_MODE_NONE;
return SCSI_DH_DEV_UNSUPP;
}
+ if (!device_id_size) {
+ /*
+ * Internal error: TPGS supported by no
+ * device identifcation found.
+ * Disable ALUA support.
+ */
+ sdev_printk(KERN_INFO, sdev,
+ "%s: No device descriptors found\n",
+ ALUA_DH_NAME);
+ h->tpgs = TPGS_MODE_NONE;
+ return SCSI_DH_DEV_UNSUPP;
+ }
sdev_printk(KERN_INFO, sdev,
- "%s: port group %02x rel port %02x\n",
- ALUA_DH_NAME, group_id, h->rel_port);
+ "%s: device %s port group %02x "
+ "rel port %02x\n", ALUA_DH_NAME,
+ device_id_str, group_id, h->rel_port);
+ spin_lock(&port_group_lock);
+ list_for_each_entry(tmp_pg, &port_group_list, node) {
+ if (tmp_pg->group_id != group_id)
+ continue;
+ if (tmp_pg->device_id_size != device_id_size)
+ continue;
+ if (memcmp(tmp_pg->device_id, device_id,
+ device_id_size))
+ continue;
+ h->pg = tmp_pg;
+ kref_get(&tmp_pg->kref);
+ break;
+ }
+ spin_unlock(&port_group_lock);
+ if (h->pg)
+ return SCSI_DH_OK;
pg = kzalloc(sizeof(struct alua_port_group), GFP_KERNEL);
if (!pg) {
@@ -276,13 +390,41 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h)
/* Temporary failure, bypass */
return SCSI_DH_DEV_TEMP_BUSY;
}
+ if (device_id_size) {
+ memcpy(pg->device_id, device_id, device_id_size);
+ strncpy(pg->device_id_str, device_id_str, 256);
+ } else {
+ memset(pg->device_id, 0, 256);
+ pg->device_id_str[0] = '\0';
+ }
+ pg->device_id_size = device_id_size;
pg->group_id = group_id;
pg->tpgs = h->tpgs;
pg->state = TPGS_STATE_OPTIMIZED;
kref_init(&pg->kref);
spin_lock(&port_group_lock);
- list_add(&pg->node, &port_group_list);
- h->pg = pg;
+ /*
+ * Re-check list again to catch
+ * concurrent updates
+ */
+ list_for_each_entry(tmp_pg, &port_group_list, node) {
+ if (tmp_pg->group_id != pg->group_id)
+ continue;
+ if (tmp_pg->device_id_size != pg->device_id_size)
+ continue;
+ if (memcmp(tmp_pg->device_id, pg->device_id,
+ device_id_size))
+ continue;
+ h->pg = tmp_pg;
+ kref_get(&tmp_pg->kref);
+ kfree(pg);
+ pg = NULL;
+ break;
+ }
+ if (pg) {
+ list_add(&pg->node, &port_group_list);
+ h->pg = pg;
+ }
spin_unlock(&port_group_lock);
return SCSI_DH_OK;
--
1.8.5.2
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 15/20] revert "scsi_dh_alua: ALUA hander attach should succeed while TPG is transitioning"
2015-07-08 9:05 [PATCHv2 00/20] asynchronous ALUA device handler Hannes Reinecke
` (13 preceding siblings ...)
2015-07-08 9:06 ` [PATCH 14/20] scsi_dh_alua: parse target device id Hannes Reinecke
@ 2015-07-08 9:06 ` Hannes Reinecke
2015-07-08 9:06 ` [PATCH 16/20] scsi_dh_alua: Use workqueue for RTPG Hannes Reinecke
` (4 subsequent siblings)
19 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2015-07-08 9:06 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, linux-scsi, Martin K. Petersen,
Bart van Assche, Hannes Reinecke
This reverts commit a8e5a2d593cbfccf530c3382c2c328d2edaa7b66
Obsoleted by the next patch.
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 22 ++++++++--------------
1 file changed, 8 insertions(+), 14 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 6991171..88c150a 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -498,13 +498,12 @@ static int alua_check_sense(struct scsi_device *sdev,
/*
* alua_rtpg - Evaluate REPORT TARGET GROUP STATES
* @sdev: the device to be evaluated.
- * @wait_for_transition: if nonzero, wait ALUA_FAILOVER_TIMEOUT seconds for device to exit transitioning state
*
* Evaluate the Target Port Group State.
* Returns SCSI_DH_DEV_OFFLINED if the path is
* found to be unusable.
*/
-static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int wait_for_transition)
+static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
{
unsigned char sense[SCSI_SENSE_BUFFERSIZE];
struct scsi_sense_hdr sense_hdr;
@@ -600,7 +599,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int w
else
pg->transition_tmo = ALUA_FAILOVER_TIMEOUT;
- if (wait_for_transition && (orig_transition_tmo != pg->transition_tmo)) {
+ if (orig_transition_tmo != pg->transition_tmo) {
sdev_printk(KERN_INFO, sdev,
"%s: transition timeout set to %d seconds\n",
ALUA_DH_NAME, pg->transition_tmo);
@@ -638,19 +637,14 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int w
switch (pg->state) {
case TPGS_STATE_TRANSITIONING:
- if (wait_for_transition) {
- if (time_before(jiffies, expiry)) {
- /* State transition, retry */
- interval += 2000;
- msleep(interval);
- goto retry;
- }
- err = SCSI_DH_RETRY;
- } else {
- err = SCSI_DH_OK;
+ if (time_before(jiffies, expiry)) {
+ /* State transition, retry */
+ interval += 2000;
+ msleep(interval);
+ goto retry;
}
-
/* Transitioning time exceeded, set port to standby */
+ err = SCSI_DH_RETRY;
pg->state = TPGS_STATE_STANDBY;
break;
case TPGS_STATE_OFFLINE:
--
1.8.5.2
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 16/20] scsi_dh_alua: Use workqueue for RTPG
2015-07-08 9:05 [PATCHv2 00/20] asynchronous ALUA device handler Hannes Reinecke
` (14 preceding siblings ...)
2015-07-08 9:06 ` [PATCH 15/20] revert "scsi_dh_alua: ALUA hander attach should succeed while TPG is transitioning" Hannes Reinecke
@ 2015-07-08 9:06 ` Hannes Reinecke
2015-07-24 15:21 ` Christoph Hellwig
2015-07-08 9:06 ` [PATCH 17/20] scsi_dh_alua: Recheck state on unit attention Hannes Reinecke
` (3 subsequent siblings)
19 siblings, 1 reply; 38+ messages in thread
From: Hannes Reinecke @ 2015-07-08 9:06 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, linux-scsi, Martin K. Petersen,
Bart van Assche, Hannes Reinecke
The current ALUA device_handler has two drawbacks:
- We're sending a 'SET TARGET PORT GROUP' command to every LUN,
disregarding the fact that several LUNs might be in a port group
and will be automatically switched whenever _any_ LUN within
that port group receives the command.
- Whenever a LUN is in 'transitioning' mode we cannot block I/O
to that LUN, instead the controller has to abort the command.
This leads to increased traffic across the wire and heavy load
on the controller during switchover.
With this patch the RTPG handling is moved to a per-portgroup
workqueue. This reduces the number of 'REPORT TARGET PORT GROUP'
and 'SET TARGET PORT GROUPS' sent to the controller as we're sending
them now per port group, and not per device as previously.
It also allows us to block I/O to any LUN / port group found to be
in 'transitioning' ALUA mode, as the workqueue item will be requeued
until the controller moves out of transitioning.
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 412 ++++++++++++++++++++++++-----
1 file changed, 349 insertions(+), 63 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 88c150a..ea47d15 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -22,6 +22,8 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/module.h>
+#include <linux/workqueue.h>
+#include <linux/rcupdate.h>
#include <asm/unaligned.h>
#include <scsi/scsi.h>
#include <scsi/scsi_dbg.h>
@@ -59,10 +61,15 @@
#define ALUA_RTPG_SIZE 128
#define ALUA_FAILOVER_TIMEOUT 60
#define ALUA_FAILOVER_RETRIES 5
+#define ALUA_RTPG_DELAY_MSECS 5
/* device handler flags */
-#define ALUA_OPTIMIZE_STPG 1
-#define ALUA_RTPG_EXT_HDR_UNSUPP 2
+#define ALUA_OPTIMIZE_STPG 0x01
+#define ALUA_RTPG_EXT_HDR_UNSUPP 0x02
+/* State machine flags */
+#define ALUA_PG_RUN_RTPG 0x10
+#define ALUA_PG_RUN_STPG 0x20
+
static LIST_HEAD(port_group_list);
static DEFINE_SPINLOCK(port_group_lock);
@@ -79,13 +86,29 @@ struct alua_port_group {
int pref;
unsigned flags; /* used for optimizing STPG */
unsigned char transition_tmo;
+ unsigned long expiry;
+ unsigned long interval;
+ char work_q_name[264];
+ struct workqueue_struct *work_q;
+ struct delayed_work rtpg_work;
+ struct delayed_work stpg_work;
+ struct delayed_work qdata_work;
+ spinlock_t rtpg_lock;
+ struct list_head rtpg_list;
+ struct scsi_device *rtpg_sdev;
};
struct alua_dh_data {
struct alua_port_group *pg;
+ spinlock_t pg_lock;
int rel_port;
int tpgs;
- struct scsi_device *sdev;
+ int error;
+ struct completion init_complete;
+};
+
+struct alua_queue_data {
+ struct list_head entry;
activate_complete callback_fn;
void *callback_data;
};
@@ -94,6 +117,10 @@ struct alua_dh_data {
#define ALUA_POLICY_SWITCH_ALL 1
static char print_alua_state(int);
+static void alua_rtpg_work(struct work_struct *work);
+static void alua_stpg_work(struct work_struct *work);
+static void alua_qdata_work(struct work_struct *work);
+static void alua_check(struct scsi_device *sdev);
static void release_port_group(struct kref *kref)
{
@@ -104,6 +131,9 @@ static void release_port_group(struct kref *kref)
spin_lock(&port_group_lock);
list_del(&pg->node);
spin_unlock(&port_group_lock);
+ WARN_ON(pg->rtpg_sdev);
+ if (pg->work_q)
+ destroy_workqueue(pg->work_q);
kfree(pg);
}
@@ -374,13 +404,17 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h)
if (memcmp(tmp_pg->device_id, device_id,
device_id_size))
continue;
- h->pg = tmp_pg;
kref_get(&tmp_pg->kref);
+ spin_lock(&h->pg_lock);
+ rcu_assign_pointer(h->pg, tmp_pg);
+ spin_unlock(&h->pg_lock);
break;
}
spin_unlock(&port_group_lock);
- if (h->pg)
+ if (h->pg) {
+ synchronize_rcu();
return SCSI_DH_OK;
+ }
pg = kzalloc(sizeof(struct alua_port_group), GFP_KERNEL);
if (!pg) {
@@ -402,6 +436,20 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h)
pg->tpgs = h->tpgs;
pg->state = TPGS_STATE_OPTIMIZED;
kref_init(&pg->kref);
+ INIT_DELAYED_WORK(&pg->rtpg_work, alua_rtpg_work);
+ INIT_DELAYED_WORK(&pg->stpg_work, alua_stpg_work);
+ INIT_DELAYED_WORK(&pg->qdata_work, alua_qdata_work);
+ INIT_LIST_HEAD(&pg->rtpg_list);
+ INIT_LIST_HEAD(&pg->node);
+ spin_lock_init(&pg->rtpg_lock);
+ snprintf(pg->work_q_name, sizeof(pg->work_q_name),
+ "alua_wq_%s_%d", pg->device_id_str, pg->group_id);
+ pg->work_q = create_singlethread_workqueue(pg->work_q_name);
+ if (!pg->work_q) {
+ kref_put(&pg->kref, release_port_group);
+ /* Temporary failure, bypass */
+ return SCSI_DH_DEV_TEMP_BUSY;
+ }
spin_lock(&port_group_lock);
/*
* Re-check list again to catch
@@ -415,15 +463,19 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h)
if (memcmp(tmp_pg->device_id, pg->device_id,
device_id_size))
continue;
- h->pg = tmp_pg;
kref_get(&tmp_pg->kref);
+ spin_lock(&h->pg_lock);
+ rcu_assign_pointer(h->pg, tmp_pg);
+ spin_unlock(&h->pg_lock);
kfree(pg);
pg = NULL;
break;
}
if (pg) {
list_add(&pg->node, &port_group_list);
- h->pg = pg;
+ spin_lock(&h->pg_lock);
+ rcu_assign_pointer(h->pg, pg);
+ spin_unlock(&h->pg_lock);
}
spin_unlock(&port_group_lock);
@@ -457,11 +509,14 @@ static int alua_check_sense(struct scsi_device *sdev,
{
switch (sense_hdr->sense_key) {
case NOT_READY:
- if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a)
+ if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a) {
/*
* LUN Not Accessible - ALUA state transition
+ * Kickoff worker to update internal state.
*/
+ alua_check(sdev);
return ADD_TO_MLQUEUE;
+ }
break;
case UNIT_ATTENTION:
if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00)
@@ -510,14 +565,15 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
int len, k, off, valid_states = 0, bufflen = ALUA_RTPG_SIZE;
unsigned char *ucp, *buff;
unsigned err, retval;
- unsigned long expiry, interval = 0;
unsigned int tpg_desc_tbl_off;
unsigned char orig_transition_tmo;
- if (!pg->transition_tmo)
- expiry = round_jiffies_up(jiffies + ALUA_FAILOVER_TIMEOUT * HZ);
- else
- expiry = round_jiffies_up(jiffies + pg->transition_tmo * HZ);
+ if (!pg->expiry) {
+ if (!pg->transition_tmo)
+ pg->expiry = round_jiffies_up(jiffies + ALUA_FAILOVER_TIMEOUT * HZ);
+ else
+ pg->expiry = round_jiffies_up(jiffies + pg->transition_tmo * HZ);
+ }
buff = kzalloc(bufflen, GFP_KERNEL);
if (!buff)
@@ -538,6 +594,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
else
err = SCSI_DH_IO;
kfree(buff);
+ pg->expiry = 0;
return err;
}
@@ -564,16 +621,18 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
err = SCSI_DH_RETRY;
if (sense_hdr.sense_key == UNIT_ATTENTION)
err = SCSI_DH_RETRY;
- if (err == SCSI_DH_RETRY && time_before(jiffies, expiry)) {
+ if (err == SCSI_DH_RETRY &&
+ pg->expiry != 0 && time_before(jiffies, pg->expiry)) {
sdev_printk(KERN_ERR, sdev, "%s: rtpg retry\n",
ALUA_DH_NAME);
scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
- goto retry;
+ return err;
}
sdev_printk(KERN_ERR, sdev, "%s: rtpg failed\n",
ALUA_DH_NAME);
scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
kfree(buff);
+ pg->expiry = 0;
return SCSI_DH_IO;
}
@@ -588,6 +647,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
sdev_printk(KERN_WARNING, sdev,
"%s: kmalloc buffer failed\n",__func__);
/* Temporary failure, bypass */
+ pg->expiry = 0;
return SCSI_DH_DEV_TEMP_BUSY;
}
goto retry;
@@ -603,7 +663,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
sdev_printk(KERN_INFO, sdev,
"%s: transition timeout set to %d seconds\n",
ALUA_DH_NAME, pg->transition_tmo);
- expiry = jiffies + pg->transition_tmo * HZ;
+ pg->expiry = jiffies + pg->transition_tmo * HZ;
}
if ((buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR)
@@ -637,23 +697,26 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
switch (pg->state) {
case TPGS_STATE_TRANSITIONING:
- if (time_before(jiffies, expiry)) {
+ if (time_before(jiffies, pg->expiry)) {
/* State transition, retry */
- interval += 2000;
- msleep(interval);
- goto retry;
+ pg->interval = 2;
+ err = SCSI_DH_RETRY;
+ } else {
+ /* Transitioning time exceeded, set port to standby */
+ err = SCSI_DH_IO;
+ pg->state = TPGS_STATE_STANDBY;
+ pg->expiry = 0;
}
- /* Transitioning time exceeded, set port to standby */
- err = SCSI_DH_RETRY;
- pg->state = TPGS_STATE_STANDBY;
break;
case TPGS_STATE_OFFLINE:
/* Path unusable */
err = SCSI_DH_DEV_OFFLINED;
+ pg->expiry = 0;
break;
default:
/* Useable path if active */
err = SCSI_DH_OK;
+ pg->expiry = 0;
break;
}
kfree(buff);
@@ -674,8 +737,8 @@ static unsigned alua_stpg(struct scsi_device *sdev, struct alua_port_group *pg)
struct scsi_sense_hdr sense_hdr;
if (!(pg->tpgs & TPGS_MODE_EXPLICIT)) {
- /* Only implicit ALUA supported, retry */
- return SCSI_DH_RETRY;
+ /* Only implicit ALUA supported */
+ return SCSI_DH_OK;
}
switch (pg->state) {
case TPGS_STATE_OPTIMIZED:
@@ -701,8 +764,6 @@ static unsigned alua_stpg(struct scsi_device *sdev, struct alua_port_group *pg)
return SCSI_DH_NOSYS;
break;
}
- /* Set state to transitioning */
- pg->state = TPGS_STATE_TRANSITIONING;
retval = submit_stpg(sdev, pg->group_id, sense);
if (retval) {
@@ -724,6 +785,150 @@ static unsigned alua_stpg(struct scsi_device *sdev, struct alua_port_group *pg)
return SCSI_DH_RETRY;
}
+static void alua_rtpg_work(struct work_struct *work)
+{
+ struct alua_port_group *pg =
+ container_of(work, struct alua_port_group, rtpg_work.work);
+ struct scsi_device *sdev;
+ int err = SCSI_DH_OK;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pg->rtpg_lock, flags);
+ sdev = pg->rtpg_sdev;
+ if (!sdev) {
+ WARN_ON(pg->flags & ALUA_PG_RUN_RTPG ||
+ pg->flags & ALUA_PG_RUN_STPG);
+ spin_unlock_irqrestore(&pg->rtpg_lock, flags);
+ return;
+ }
+ if (pg->flags & ALUA_PG_RUN_RTPG) {
+ spin_unlock_irqrestore(&pg->rtpg_lock, flags);
+ err = alua_rtpg(sdev, pg);
+ if (err == SCSI_DH_RETRY) {
+ queue_delayed_work(pg->work_q, &pg->rtpg_work,
+ pg->interval * HZ);
+ return;
+ }
+ spin_lock_irqsave(&pg->rtpg_lock, flags);
+ pg->flags &= ~ALUA_PG_RUN_RTPG;
+ if (err != SCSI_DH_OK)
+ pg->flags &= ~ALUA_PG_RUN_STPG;
+ }
+ if (pg->flags & ALUA_PG_RUN_STPG) {
+ spin_unlock_irqrestore(&pg->rtpg_lock, flags);
+ queue_delayed_work(pg->work_q, &pg->stpg_work, 0);
+ return;
+ }
+ spin_unlock_irqrestore(&pg->rtpg_lock, flags);
+ queue_delayed_work(pg->work_q, &pg->qdata_work, 0);
+}
+
+static void alua_stpg_work(struct work_struct *work)
+{
+ struct alua_port_group *pg =
+ container_of(work, struct alua_port_group, stpg_work.work);
+ struct scsi_device *sdev;
+ int err = SCSI_DH_OK;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pg->rtpg_lock, flags);
+ sdev = pg->rtpg_sdev;
+ if (!sdev) {
+ WARN_ON(pg->flags & ALUA_PG_RUN_STPG);
+ spin_unlock_irqrestore(&pg->rtpg_lock, flags);
+ return;
+ }
+
+ if (pg->flags & ALUA_PG_RUN_STPG) {
+ spin_unlock_irqrestore(&pg->rtpg_lock, flags);
+ err = alua_stpg(sdev, pg);
+ spin_lock_irqsave(&pg->rtpg_lock, flags);
+ pg->flags &= ~ALUA_PG_RUN_STPG;
+ if (err == SCSI_DH_RETRY) {
+ pg->flags |= ALUA_PG_RUN_RTPG;
+ pg->interval = 0;
+ }
+ }
+ if (pg->flags & ALUA_PG_RUN_RTPG) {
+ spin_unlock_irqrestore(&pg->rtpg_lock, flags);
+ queue_delayed_work(pg->work_q, &pg->rtpg_work,
+ msecs_to_jiffies(ALUA_RTPG_DELAY_MSECS));
+ return;
+ }
+
+ spin_unlock_irqrestore(&pg->rtpg_lock, flags);
+ queue_delayed_work(pg->work_q, &pg->qdata_work, 0);
+}
+
+static void alua_qdata_work(struct work_struct *work)
+{
+ struct alua_port_group *pg =
+ container_of(work, struct alua_port_group, qdata_work.work);
+ struct scsi_device *sdev;
+ LIST_HEAD(qdata_list);
+ int err = SCSI_DH_OK;
+ struct alua_queue_data *qdata, *tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pg->rtpg_lock, flags);
+ sdev = pg->rtpg_sdev;
+ if (WARN_ON(!sdev)) {
+ spin_unlock_irqrestore(&pg->rtpg_lock, flags);
+ return;
+ }
+ if (pg->flags & ALUA_PG_RUN_RTPG) {
+ spin_unlock_irqrestore(&pg->rtpg_lock, flags);
+ queue_delayed_work(pg->work_q, &pg->rtpg_work,
+ msecs_to_jiffies(ALUA_RTPG_DELAY_MSECS));
+ return;
+ }
+
+ list_splice_init(&pg->rtpg_list, &qdata_list);
+ pg->rtpg_sdev = NULL;
+ spin_unlock_irqrestore(&pg->rtpg_lock, flags);
+
+ list_for_each_entry_safe(qdata, tmp, &qdata_list, entry) {
+ list_del(&qdata->entry);
+ if (qdata->callback_fn)
+ qdata->callback_fn(qdata->callback_data, err);
+ kfree(qdata);
+ }
+ kref_put(&pg->kref, release_port_group);
+ scsi_device_put(sdev);
+}
+
+static void alua_rtpg_queue(struct alua_port_group *pg,
+ struct scsi_device *sdev,
+ struct alua_queue_data *qdata)
+{
+ int start_queue = 0;
+ unsigned long flags;
+
+ if (!pg)
+ return;
+
+ kref_get(&pg->kref);
+ spin_lock_irqsave(&pg->rtpg_lock, flags);
+ if (qdata) {
+ list_add_tail(&qdata->entry, &pg->rtpg_list);
+ pg->flags |= ALUA_PG_RUN_STPG;
+ }
+ if (pg->rtpg_sdev == NULL) {
+ pg->interval = 0;
+ pg->flags |= ALUA_PG_RUN_RTPG;
+ kref_get(&pg->kref);
+ pg->rtpg_sdev = sdev;
+ scsi_device_get(sdev);
+ start_queue = 1;
+ }
+ spin_unlock_irqrestore(&pg->rtpg_lock, flags);
+
+ if (start_queue)
+ queue_delayed_work(pg->work_q, &pg->rtpg_work,
+ msecs_to_jiffies(ALUA_RTPG_DELAY_MSECS));
+ kref_put(&pg->kref, release_port_group);
+}
+
/*
* alua_initialize - Initialize ALUA state
* @sdev: the device to be initialized
@@ -733,22 +938,33 @@ static unsigned alua_stpg(struct scsi_device *sdev, struct alua_port_group *pg)
*/
static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h)
{
- int err;
-
- err = alua_check_tpgs(sdev, h);
- if (err != SCSI_DH_OK)
- goto out;
-
- err = alua_check_vpd(sdev, h);
- if (err != SCSI_DH_OK || !h->pg)
- goto out;
+ struct alua_port_group *pg = NULL;
- kref_get(&h->pg->kref);
- err = alua_rtpg(sdev, h->pg, 0);
- kref_put(&h->pg->kref, release_port_group);
-out:
- return err;
+ h->error = alua_check_tpgs(sdev, h);
+ if (h->error == SCSI_DH_OK) {
+ h->error = alua_check_vpd(sdev, h);
+ rcu_read_lock();
+ pg = rcu_dereference(h->pg);
+ if (!pg) {
+ rcu_read_unlock();
+ h->tpgs = TPGS_MODE_NONE;
+ if (h->error == SCSI_DH_OK)
+ h->error = SCSI_DH_IO;
+ } else {
+ WARN_ON(h->error != SCSI_DH_OK);
+ kref_get(&pg->kref);
+ rcu_read_unlock();
+ }
+ }
+ complete(&h->init_complete);
+ if (pg) {
+ pg->expiry = 0;
+ alua_rtpg_queue(pg, sdev, NULL);
+ kref_put(&pg->kref, release_port_group);
+ }
+ return h->error;
}
+
/*
* alua_set_params - set/unset the optimize flag
* @sdev: device on the path to be activated
@@ -765,6 +981,10 @@ static int alua_set_params(struct scsi_device *sdev, const char *params)
unsigned int optimize = 0, argc;
const char *p = params;
int result = SCSI_DH_OK;
+ unsigned long flags;
+
+ if (!h)
+ return -ENXIO;
if ((sscanf(params, "%u", &argc) != 1) || (argc != 1))
return -EINVAL;
@@ -782,10 +1002,12 @@ static int alua_set_params(struct scsi_device *sdev, const char *params)
}
rcu_read_unlock();
+ spin_lock_irqsave(&pg->rtpg_lock, flags);
if (optimize)
pg->flags |= ALUA_OPTIMIZE_STPG;
else
pg->flags |= ~ALUA_OPTIMIZE_STPG;
+ spin_unlock_irqrestore(&pg->rtpg_lock, flags);
return result;
}
@@ -809,24 +1031,49 @@ static int alua_activate(struct scsi_device *sdev,
{
struct alua_dh_data *h = sdev->handler_data;
int err = SCSI_DH_OK;
+ struct alua_queue_data *qdata;
+ struct alua_port_group *pg;
- if (!h->pg)
+ if (!h) {
+ err = SCSI_DH_NOSYS;
goto out;
+ }
- kref_get(&h->pg->kref);
+ qdata = kzalloc(sizeof(*qdata), GFP_KERNEL);
+ if (!qdata) {
+ err = SCSI_DH_RES_TEMP_UNAVAIL;
+ goto out;
+ }
+ qdata->callback_fn = fn;
+ qdata->callback_data = data;
- if (optimize_stpg)
- h->pg->flags |= ALUA_OPTIMIZE_STPG;
+ rcu_read_lock();
+ pg = rcu_dereference(h->pg);
+ if (!pg) {
+ rcu_read_unlock();
+ wait_for_completion(&h->init_complete);
+ rcu_read_lock();
+ pg = rcu_dereference(h->pg);
+ if (!pg) {
+ rcu_read_unlock();
+ kfree(qdata);
+ err = h->error;
+ goto out;
+ }
+ }
+ fn = NULL;
+ kref_get(&pg->kref);
+ rcu_read_unlock();
- err = alua_rtpg(sdev, h->pg, 1);
- if (err != SCSI_DH_OK) {
- kref_put(&h->pg->kref, release_port_group);
- goto out;
+ if (optimize_stpg) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&pg->rtpg_lock, flags);
+ pg->flags |= ALUA_OPTIMIZE_STPG;
+ spin_unlock_irqrestore(&pg->rtpg_lock, flags);
}
- err = alua_stpg(sdev, h->pg);
- if (err == SCSI_DH_RETRY)
- err = alua_rtpg(sdev, h->pg, 1);
- kref_put(&h->pg->kref, release_port_group);
+ alua_rtpg_queue(pg, sdev, qdata);
+ kref_put(&pg->kref, release_port_group);
out:
if (fn)
fn(data, err);
@@ -834,6 +1081,28 @@ out:
}
/*
+ * alua_check - check path status
+ * @sdev: device on the path to be checked
+ *
+ * Check the device status
+ */
+static void alua_check(struct scsi_device *sdev)
+{
+ struct alua_dh_data *h = sdev->handler_data;
+ struct alua_port_group *pg;
+
+ rcu_read_lock();
+ pg = rcu_dereference(h->pg);
+ if (pg) {
+ kref_get(&pg->kref);
+ rcu_read_unlock();
+ alua_rtpg_queue(pg, sdev, NULL);
+ kref_put(&pg->kref, release_port_group);
+ } else
+ rcu_read_unlock();
+}
+
+/*
* alua_prep_fn - request callback
*
* Fail I/O to all paths not in state
@@ -842,14 +1111,22 @@ out:
static int alua_prep_fn(struct scsi_device *sdev, struct request *req)
{
struct alua_dh_data *h = sdev->handler_data;
- int state;
+ struct alua_port_group *pg;
+ int state = TPGS_STATE_OPTIMIZED;
int ret = BLKPREP_OK;
- if (!h->pg)
+ if (!h)
return ret;
- kref_get(&h->pg->kref);
- state = h->pg->state;
- kref_put(&h->pg->kref, release_port_group);
+
+ rcu_read_lock();
+ pg = rcu_dereference(h->pg);
+ if (pg) {
+ state = pg->state;
+ /* Defer I/O while rtpg_work is active */
+ if (pg->rtpg_sdev)
+ state = TPGS_STATE_TRANSITIONING;
+ }
+ rcu_read_unlock();
if (state == TPGS_STATE_TRANSITIONING)
ret = BLKPREP_DEFER;
else if (state != TPGS_STATE_OPTIMIZED &&
@@ -874,11 +1151,13 @@ static int alua_bus_attach(struct scsi_device *sdev)
h = kzalloc(sizeof(*h) , GFP_KERNEL);
if (!h)
return -ENOMEM;
+ spin_lock_init(&h->pg_lock);
h->tpgs = TPGS_MODE_UNINITIALIZED;
- h->pg = NULL;
+ rcu_assign_pointer(h->pg, NULL);
h->rel_port = -1;
- h->sdev = sdev;
+ h->error = SCSI_DH_OK;
+ init_completion(&h->init_complete);
err = alua_initialize(sdev, h);
if (err != SCSI_DH_OK && err != SCSI_DH_DEV_OFFLINED)
goto failed;
@@ -897,10 +1176,17 @@ failed:
static void alua_bus_detach(struct scsi_device *sdev)
{
struct alua_dh_data *h = sdev->handler_data;
+ struct alua_port_group *pg;
- if (h->pg) {
- kref_put(&h->pg->kref, release_port_group);
- h->pg = NULL;
+ spin_lock(&h->pg_lock);
+ pg = h->pg;
+ rcu_assign_pointer(h->pg, NULL);
+ spin_unlock(&h->pg_lock);
+ synchronize_rcu();
+ if (pg) {
+ if (pg->rtpg_sdev)
+ flush_workqueue(pg->work_q);
+ kref_put(&pg->kref, release_port_group);
}
sdev->handler_data = NULL;
kfree(h);
--
1.8.5.2
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 17/20] scsi_dh_alua: Recheck state on unit attention
2015-07-08 9:05 [PATCHv2 00/20] asynchronous ALUA device handler Hannes Reinecke
` (15 preceding siblings ...)
2015-07-08 9:06 ` [PATCH 16/20] scsi_dh_alua: Use workqueue for RTPG Hannes Reinecke
@ 2015-07-08 9:06 ` Hannes Reinecke
2015-07-08 9:06 ` [PATCH 18/20] scsi_dh_alua: update all port states Hannes Reinecke
` (2 subsequent siblings)
19 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2015-07-08 9:06 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, linux-scsi, Martin K. Petersen,
Bart van Assche, Hannes Reinecke
When we receive a unit attention code of 'ALUA state changed'
we should recheck the state, as it might be due to an implicit
ALUA state transition.
At the same time a workqueue item might already be queued, which
should be started immediately to avoid any delays.
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 48 +++++++++++++++---------------
1 file changed, 24 insertions(+), 24 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index ea47d15..aa58659 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -120,7 +120,7 @@ static char print_alua_state(int);
static void alua_rtpg_work(struct work_struct *work);
static void alua_stpg_work(struct work_struct *work);
static void alua_qdata_work(struct work_struct *work);
-static void alua_check(struct scsi_device *sdev);
+static void alua_check(struct scsi_device *sdev, bool force);
static void release_port_group(struct kref *kref)
{
@@ -505,7 +505,7 @@ static char print_alua_state(int state)
}
static int alua_check_sense(struct scsi_device *sdev,
- struct scsi_sense_hdr *sense_hdr)
+ struct scsi_sense_hdr *sense_hdr)
{
switch (sense_hdr->sense_key) {
case NOT_READY:
@@ -514,36 +514,34 @@ static int alua_check_sense(struct scsi_device *sdev,
* LUN Not Accessible - ALUA state transition
* Kickoff worker to update internal state.
*/
- alua_check(sdev);
- return ADD_TO_MLQUEUE;
+ alua_check(sdev, false);
+ return NEEDS_RETRY;
}
break;
case UNIT_ATTENTION:
- if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00)
- /*
- * Power On, Reset, or Bus Device Reset, just retry.
- */
- return ADD_TO_MLQUEUE;
- if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x04)
- /*
- * Device internal reset
- */
- return ADD_TO_MLQUEUE;
- if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x01)
+ if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) {
/*
- * Mode Parameter Changed
+ * Power On, Reset, or Bus Device Reset.
+ * Might have obscured a state transition,
+ * so schedule a recheck.
*/
+ alua_check(sdev, true);
return ADD_TO_MLQUEUE;
- if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06)
+ }
+ if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06) {
/*
* ALUA state changed
*/
+ alua_check(sdev, true);
return ADD_TO_MLQUEUE;
- if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07)
+ }
+ if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07) {
/*
* Implicit ALUA state transition failed
*/
+ alua_check(sdev, true);
return ADD_TO_MLQUEUE;
+ }
break;
}
@@ -899,7 +897,7 @@ static void alua_qdata_work(struct work_struct *work)
static void alua_rtpg_queue(struct alua_port_group *pg,
struct scsi_device *sdev,
- struct alua_queue_data *qdata)
+ struct alua_queue_data *qdata, bool force)
{
int start_queue = 0;
unsigned long flags;
@@ -920,7 +918,9 @@ static void alua_rtpg_queue(struct alua_port_group *pg,
pg->rtpg_sdev = sdev;
scsi_device_get(sdev);
start_queue = 1;
- }
+ } else if (!(pg->flags & ALUA_PG_RUN_RTPG) && force)
+ start_queue = 1;
+
spin_unlock_irqrestore(&pg->rtpg_lock, flags);
if (start_queue)
@@ -959,7 +959,7 @@ static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h)
complete(&h->init_complete);
if (pg) {
pg->expiry = 0;
- alua_rtpg_queue(pg, sdev, NULL);
+ alua_rtpg_queue(pg, sdev, NULL, true);
kref_put(&pg->kref, release_port_group);
}
return h->error;
@@ -1072,7 +1072,7 @@ static int alua_activate(struct scsi_device *sdev,
pg->flags |= ALUA_OPTIMIZE_STPG;
spin_unlock_irqrestore(&pg->rtpg_lock, flags);
}
- alua_rtpg_queue(pg, sdev, qdata);
+ alua_rtpg_queue(pg, sdev, qdata, true);
kref_put(&pg->kref, release_port_group);
out:
if (fn)
@@ -1086,7 +1086,7 @@ out:
*
* Check the device status
*/
-static void alua_check(struct scsi_device *sdev)
+static void alua_check(struct scsi_device *sdev, bool force)
{
struct alua_dh_data *h = sdev->handler_data;
struct alua_port_group *pg;
@@ -1096,7 +1096,7 @@ static void alua_check(struct scsi_device *sdev)
if (pg) {
kref_get(&pg->kref);
rcu_read_unlock();
- alua_rtpg_queue(pg, sdev, NULL);
+ alua_rtpg_queue(pg, sdev, NULL, force);
kref_put(&pg->kref, release_port_group);
} else
rcu_read_unlock();
--
1.8.5.2
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 18/20] scsi_dh_alua: update all port states
2015-07-08 9:05 [PATCHv2 00/20] asynchronous ALUA device handler Hannes Reinecke
` (16 preceding siblings ...)
2015-07-08 9:06 ` [PATCH 17/20] scsi_dh_alua: Recheck state on unit attention Hannes Reinecke
@ 2015-07-08 9:06 ` Hannes Reinecke
2015-07-08 9:06 ` [PATCH 19/20] scsi_dh_alua: Send TEST UNIT READY to poll for transitioning Hannes Reinecke
2015-07-08 9:06 ` [PATCH 20/20] scsi_dh_alua: Update version to 2.0 Hannes Reinecke
19 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2015-07-08 9:06 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, linux-scsi, Martin K. Petersen,
Bart van Assche, Hannes Reinecke
When we read in the target port group state we should be
updating all affected port groups, otherwise we risk
running out of sync.
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 28 ++++++++++++++++++++++++----
1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index aa58659..44b57bc 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -560,11 +560,13 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
{
unsigned char sense[SCSI_SENSE_BUFFERSIZE];
struct scsi_sense_hdr sense_hdr;
+ struct alua_port_group *tmp_pg;
int len, k, off, valid_states = 0, bufflen = ALUA_RTPG_SIZE;
unsigned char *ucp, *buff;
unsigned err, retval;
unsigned int tpg_desc_tbl_off;
unsigned char orig_transition_tmo;
+ unsigned long flags;
if (!pg->expiry) {
if (!pg->transition_tmo)
@@ -669,17 +671,35 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
else
tpg_desc_tbl_off = 4;
+ spin_lock_irqsave(&port_group_lock, flags);
for (k = tpg_desc_tbl_off, ucp = buff + tpg_desc_tbl_off;
k < len;
k += off, ucp += off) {
- if (pg->group_id == (ucp[2] << 8) + ucp[3]) {
- pg->state = ucp[0] & 0x0f;
- pg->pref = ucp[0] >> 7;
- valid_states = ucp[1];
+ list_for_each_entry(tmp_pg, &port_group_list, node) {
+ u16 group_id = get_unaligned_be16(&ucp[2]);
+ if (tmp_pg->group_id != group_id)
+ continue;
+ if (tmp_pg->device_id_size != pg->device_id_size)
+ continue;
+ if (memcmp(tmp_pg->device_id, pg->device_id,
+ tmp_pg->device_id_size))
+ continue;
+ tmp_pg->state = ucp[0] & 0x0f;
+ tmp_pg->pref = ucp[0] >> 7;
+ sdev_printk(KERN_INFO, sdev,
+ "%s: device %s port group %02x "
+ "state %c %s\n", ALUA_DH_NAME,
+ tmp_pg->device_id_str, tmp_pg->group_id,
+ print_alua_state(tmp_pg->state),
+ tmp_pg->pref ?
+ "preferred" : "non-preferred");
+ if (tmp_pg == pg)
+ valid_states = ucp[1];
}
off = 8 + (ucp[7] * 4);
}
+ spin_unlock_irqrestore(&port_group_lock, flags);
sdev_printk(KERN_INFO, sdev,
"%s: port group %02x state %c %s supports %c%c%c%c%c%c%c\n",
--
1.8.5.2
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 19/20] scsi_dh_alua: Send TEST UNIT READY to poll for transitioning
2015-07-08 9:05 [PATCHv2 00/20] asynchronous ALUA device handler Hannes Reinecke
` (17 preceding siblings ...)
2015-07-08 9:06 ` [PATCH 18/20] scsi_dh_alua: update all port states Hannes Reinecke
@ 2015-07-08 9:06 ` Hannes Reinecke
2015-07-08 9:06 ` [PATCH 20/20] scsi_dh_alua: Update version to 2.0 Hannes Reinecke
19 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2015-07-08 9:06 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, linux-scsi, Martin K. Petersen,
Bart van Assche, Hannes Reinecke
Sending a 'REPORT TARGET PORT GROUP' command is a costly operation,
as the array has to gather information about all ports.
So instead of using RTPG to poll for a status update when a port
is in transitioning we should be sending a TEST UNIT READY, and
wait for the sense code to report success.
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 33 ++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 44b57bc..30310c8 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -549,6 +549,30 @@ static int alua_check_sense(struct scsi_device *sdev,
}
/*
+ * alua_tur - Send a TEST UNIT READY
+ * @sdev: device to which the TEST UNIT READY command should be send
+ *
+ * Send a TEST UNIT READY to @sdev to figure out the device state
+ * Returns SCSI_DH_RETRY if the sense code is NOT READY/ALUA TRANSITIONING,
+ * SCSI_DH_OK if no error occured, and SCSI_DH_IO otherwise.
+ */
+static int alua_tur(struct scsi_device *sdev)
+{
+ struct scsi_sense_hdr sense_hdr;
+ int retval;
+
+ retval = scsi_test_unit_ready(sdev, ALUA_FAILOVER_TIMEOUT * HZ,
+ ALUA_FAILOVER_RETRIES, &sense_hdr);
+ if (sense_hdr.sense_key == NOT_READY &&
+ sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a)
+ return SCSI_DH_RETRY;
+ else if (retval)
+ return SCSI_DH_IO;
+ else
+ return SCSI_DH_OK;
+}
+
+/*
* alua_rtpg - Evaluate REPORT TARGET GROUP STATES
* @sdev: the device to be evaluated.
*
@@ -820,7 +844,16 @@ static void alua_rtpg_work(struct work_struct *work)
return;
}
if (pg->flags & ALUA_PG_RUN_RTPG) {
+ int state = pg->state;
spin_unlock_irqrestore(&pg->rtpg_lock, flags);
+ if (state == TPGS_STATE_TRANSITIONING) {
+ if (alua_tur(sdev) == SCSI_DH_RETRY) {
+ queue_delayed_work(pg->work_q, &pg->rtpg_work,
+ pg->interval * HZ);
+ return;
+ }
+ /* Send RTPG on failure or if TUR indicates SUCCESS */
+ }
err = alua_rtpg(sdev, pg);
if (err == SCSI_DH_RETRY) {
queue_delayed_work(pg->work_q, &pg->rtpg_work,
--
1.8.5.2
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 20/20] scsi_dh_alua: Update version to 2.0
2015-07-08 9:05 [PATCHv2 00/20] asynchronous ALUA device handler Hannes Reinecke
` (18 preceding siblings ...)
2015-07-08 9:06 ` [PATCH 19/20] scsi_dh_alua: Send TEST UNIT READY to poll for transitioning Hannes Reinecke
@ 2015-07-08 9:06 ` Hannes Reinecke
19 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2015-07-08 9:06 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, linux-scsi, Martin K. Petersen,
Bart van Assche, Hannes Reinecke
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 30310c8..d077014 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -31,7 +31,7 @@
#include <scsi/scsi_dh.h>
#define ALUA_DH_NAME "alua"
-#define ALUA_DH_VER "1.3"
+#define ALUA_DH_VER "2.0"
#define TPGS_STATE_OPTIMIZED 0x0
#define TPGS_STATE_NONOPTIMIZED 0x1
--
1.8.5.2
^ permalink raw reply related [flat|nested] 38+ messages in thread
* Re: [PATCH 04/20] scsi_dh_alua: Improve error handling
2015-07-08 9:06 ` [PATCH 04/20] scsi_dh_alua: Improve error handling Hannes Reinecke
@ 2015-07-24 14:48 ` Christoph Hellwig
2015-07-25 15:42 ` Hannes Reinecke
0 siblings, 1 reply; 38+ messages in thread
From: Christoph Hellwig @ 2015-07-24 14:48 UTC (permalink / raw)
To: Hannes Reinecke
Cc: James Bottomley, Christoph Hellwig, linux-scsi,
Martin K. Petersen, Bart van Assche
This seems to be a bit of a catchall. Can you split the logging changes
from actual error code logic changes and describe the latter in more detail?
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 07/20] scsi_dh_alua: Pass buffer as function argument
2015-07-08 9:06 ` [PATCH 07/20] scsi_dh_alua: Pass buffer as function argument Hannes Reinecke
@ 2015-07-24 14:48 ` Christoph Hellwig
0 siblings, 0 replies; 38+ messages in thread
From: Christoph Hellwig @ 2015-07-24 14:48 UTC (permalink / raw)
To: Hannes Reinecke
Cc: James Bottomley, Christoph Hellwig, linux-scsi,
Martin K. Petersen, Bart van Assche
> - rq->cmd[6] = (h->bufflen >> 24) & 0xff;
> - rq->cmd[7] = (h->bufflen >> 16) & 0xff;
> - rq->cmd[8] = (h->bufflen >> 8) & 0xff;
> - rq->cmd[9] = h->bufflen & 0xff;
> + put_unaligned_be32(bufflen, &rq->cmd[6]);
This is unrelated to the rest of the patch, can you split it out,
maybe together with other get/put_unaligned conversions?
Otherwise looks good:
Reviewed-by: Christoph Hellwig <hch@lst.de>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 08/20] scsi_dh_alua: Make stpg synchronous
2015-07-08 9:06 ` [PATCH 08/20] scsi_dh_alua: Make stpg synchronous Hannes Reinecke
@ 2015-07-24 14:51 ` Christoph Hellwig
2015-07-25 15:44 ` Hannes Reinecke
0 siblings, 1 reply; 38+ messages in thread
From: Christoph Hellwig @ 2015-07-24 14:51 UTC (permalink / raw)
To: Hannes Reinecke
Cc: James Bottomley, Christoph Hellwig, linux-scsi,
Martin K. Petersen, Bart van Assche
> - memset(h->buff, 0, stpg_len);
> - h->buff[4] = TPGS_STATE_OPTIMIZED & 0x0f;
> - h->buff[6] = (h->group_id >> 8) & 0xff;
> - h->buff[7] = h->group_id & 0xff;
> + memset(stpg_data, 0, stpg_len);
> + stpg_data[4] = TPGS_STATE_OPTIMIZED & 0x0f;
> + put_unaligned_be16(group_id, &stpg_data[6]);
Unrelated get/put_unaligned changes again.
> - if (!scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
> + if (!(driver_byte(retval) & DRIVER_SENSE) ||
> + !scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
Where does this come from?
> + (!h->pref) &&
no need for braces here.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 09/20] scsi_dh_alua: switch to scsi_execute()
2015-07-08 9:06 ` [PATCH 09/20] scsi_dh_alua: switch to scsi_execute() Hannes Reinecke
@ 2015-07-24 14:53 ` Christoph Hellwig
2015-07-25 15:44 ` Hannes Reinecke
0 siblings, 1 reply; 38+ messages in thread
From: Christoph Hellwig @ 2015-07-24 14:53 UTC (permalink / raw)
To: Hannes Reinecke
Cc: James Bottomley, Christoph Hellwig, linux-scsi,
Martin K. Petersen, Bart van Assche
Seems like this should use scsi_execute_req_flags instead so that it doesn't
have to deal with the raw sense buffer.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 11/20] scsi_dh_alua: Use separate alua_port_group structure
2015-07-08 9:06 ` [PATCH 11/20] scsi_dh_alua: Use separate alua_port_group structure Hannes Reinecke
@ 2015-07-24 14:58 ` Christoph Hellwig
2015-07-25 15:52 ` Hannes Reinecke
0 siblings, 1 reply; 38+ messages in thread
From: Christoph Hellwig @ 2015-07-24 14:58 UTC (permalink / raw)
To: Hannes Reinecke
Cc: James Bottomley, Christoph Hellwig, linux-scsi,
Martin K. Petersen, Bart van Assche
On Wed, Jul 08, 2015 at 11:06:09AM +0200, Hannes Reinecke wrote:
> + pg = kzalloc(sizeof(struct alua_port_group), GFP_KERNEL);
> + if (!pg) {
> + sdev_printk(KERN_WARNING, sdev,
> + "%s: kzalloc port group failed\n",
> + ALUA_DH_NAME);
> + /* Temporary failure, bypass */
> + return SCSI_DH_DEV_TEMP_BUSY;
> + }
> + pg->group_id = group_id;
> + pg->buff = pg->inq;
> + pg->bufflen = ALUA_INQUIRY_SIZE;
> + pg->tpgs = h->tpgs;
> + pg->state = TPGS_STATE_OPTIMIZED;
> + kref_init(&pg->kref);
> + spin_lock(&port_group_lock);
> + list_add(&pg->node, &port_group_list);
> + h->pg = pg;
> + spin_unlock(&port_group_lock);
Is there any high level protection against someone racing to allocate
this structure, e.g. from a sysfs-initiated scan?
> - len = (h->buff[0] << 24) + (h->buff[1] << 16) +
> - (h->buff[2] << 8) + h->buff[3] + 4;
> + len = get_unaligned_be32(&pg->buff[0]) + 4;
Andother spurious get/set_unaligned conversion. I'd really recommend doing
all of them before the atual series.
> + rcu_read_lock();
> + pg = rcu_dereference(h->pg);
> + if (!pg) {
> + rcu_read_unlock();
> + return -ENXIO;
> + }
> + rcu_read_unlock();
> +
> if (optimize)
> - h->flags |= ALUA_OPTIMIZE_STPG;
> + pg->flags |= ALUA_OPTIMIZE_STPG;
> else
> - h->flags &= ~ALUA_OPTIMIZE_STPG;
> + pg->flags |= ~ALUA_OPTIMIZE_STPG;
You'll need to move the rcu_read_unlock here to be safe.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 12/20] scsi_dh_alua: allocate RTPG buffer separately
2015-07-08 9:06 ` [PATCH 12/20] scsi_dh_alua: allocate RTPG buffer separately Hannes Reinecke
@ 2015-07-24 14:59 ` Christoph Hellwig
0 siblings, 0 replies; 38+ messages in thread
From: Christoph Hellwig @ 2015-07-24 14:59 UTC (permalink / raw)
To: Hannes Reinecke
Cc: James Bottomley, Christoph Hellwig, linux-scsi,
Martin K. Petersen, Bart van Assche
Looks good,
Reviewed-by: Christoph Hellwig <hch@lst.de>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 13/20] scsi_dh_alua: simplify sense code handling
2015-07-08 9:06 ` [PATCH 13/20] scsi_dh_alua: simplify sense code handling Hannes Reinecke
@ 2015-07-24 15:00 ` Christoph Hellwig
0 siblings, 0 replies; 38+ messages in thread
From: Christoph Hellwig @ 2015-07-24 15:00 UTC (permalink / raw)
To: Hannes Reinecke
Cc: James Bottomley, Christoph Hellwig, linux-scsi,
Martin K. Petersen, Bart van Assche
> + /*
> + * Retry on ALUA state transition or if any
> + * UNIT ATTENTION occurred.
> + */
> + if (sense_hdr.sense_key == NOT_READY &&
> + sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a)
> + err = SCSI_DH_RETRY;
> + if (sense_hdr.sense_key == UNIT_ATTENTION)
else if or just but cases in the same condition for clarity?
Otherwise looks fine:
Reviewed-by: Christoph Hellwig <hch@lst.de>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 14/20] scsi_dh_alua: parse target device id
2015-07-08 9:06 ` [PATCH 14/20] scsi_dh_alua: parse target device id Hannes Reinecke
@ 2015-07-24 15:07 ` Christoph Hellwig
2015-07-24 15:28 ` Martin K. Petersen
2015-07-25 15:53 ` Hannes Reinecke
0 siblings, 2 replies; 38+ messages in thread
From: Christoph Hellwig @ 2015-07-24 15:07 UTC (permalink / raw)
To: Hannes Reinecke
Cc: James Bottomley, Christoph Hellwig, linux-scsi,
Martin K. Petersen, Bart van Assche
On Wed, Jul 08, 2015 at 11:06:12AM +0200, Hannes Reinecke wrote:
> Parse VPD descriptor to figure out the device identification.
> As devices might implement several descriptors the order
> of preference is:
> - NAA IEE Registered Extended
> - EUI-64 based 16-byte
> - EUI-64 based 12-byte
> - NAA IEEE Registered
> - NAA IEEE Extended
> A SCSI name string descriptor is preferred to all of them
> if the identification is longer than 16 bytes.
Can you move this to scsi_mod.ko? I'll need the same code for the NFS
SCSI layout driver soon.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 16/20] scsi_dh_alua: Use workqueue for RTPG
2015-07-08 9:06 ` [PATCH 16/20] scsi_dh_alua: Use workqueue for RTPG Hannes Reinecke
@ 2015-07-24 15:21 ` Christoph Hellwig
2015-07-25 15:58 ` Hannes Reinecke
0 siblings, 1 reply; 38+ messages in thread
From: Christoph Hellwig @ 2015-07-24 15:21 UTC (permalink / raw)
To: Hannes Reinecke
Cc: James Bottomley, Christoph Hellwig, linux-scsi,
Martin K. Petersen, Bart van Assche
> + char work_q_name[264];
create_workqueue and friends now accept printf-like format
string, so there is no need for this temporary buffer.
> + int error;
> + struct completion init_complete;
Please rename error to init_error and only assign to it before calling
complete().
Also I'm not sure what the real point of init_complete is, shouldn't
we just have a mutex held in alua_initialize and alua_activate to
synchronize the two against each other?
> + rcu_read_lock();
> + pg = rcu_dereference(h->pg);
> + if (pg) {
> + kref_get(&pg->kref);
> + rcu_read_unlock();
> + alua_rtpg_queue(pg, sdev, NULL);
> + kref_put(&pg->kref, release_port_group);
> + } else
> + rcu_read_unlock();
> +}
How about:
rcu_read_lock();
pg = rcu_dereference(h->pg);
if (!pg) {
rcu_read_unlock();
return;
}
kref_get(&pg->kref);
rcu_read_unlock();
alua_rtpg_queue(pg, sdev, NULL);
kref_put(&pg->kref, release_port_group);
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 14/20] scsi_dh_alua: parse target device id
2015-07-24 15:07 ` Christoph Hellwig
@ 2015-07-24 15:28 ` Martin K. Petersen
2015-07-25 16:00 ` Hannes Reinecke
2015-07-25 15:53 ` Hannes Reinecke
1 sibling, 1 reply; 38+ messages in thread
From: Martin K. Petersen @ 2015-07-24 15:28 UTC (permalink / raw)
To: Christoph Hellwig
Cc: Hannes Reinecke, James Bottomley, linux-scsi, Martin K. Petersen,
Bart van Assche
>>>>> "Christoph" == Christoph Hellwig <hch@lst.de> writes:
Christoph> Can you move this to scsi_mod.ko? I'll need the same code
Christoph> for the NFS SCSI layout driver soon.
Same here. Working on copy offload again.
--
Martin K. Petersen Oracle Linux Engineering
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 04/20] scsi_dh_alua: Improve error handling
2015-07-24 14:48 ` Christoph Hellwig
@ 2015-07-25 15:42 ` Hannes Reinecke
0 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2015-07-25 15:42 UTC (permalink / raw)
To: Christoph Hellwig
Cc: James Bottomley, linux-scsi, Martin K. Petersen, Bart van Assche
On 07/24/2015 04:48 PM, Christoph Hellwig wrote:
> This seems to be a bit of a catchall. Can you split the logging changes
> from actual error code logic changes and describe the latter in more detail?
>
Ok.
Cheers,
Hannes
--
Dr. Hannes Reinecke zSeries & Storage
hare@suse.de +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 08/20] scsi_dh_alua: Make stpg synchronous
2015-07-24 14:51 ` Christoph Hellwig
@ 2015-07-25 15:44 ` Hannes Reinecke
0 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2015-07-25 15:44 UTC (permalink / raw)
To: Christoph Hellwig
Cc: James Bottomley, linux-scsi, Martin K. Petersen, Bart van Assche
On 07/24/2015 04:51 PM, Christoph Hellwig wrote:
>> - memset(h->buff, 0, stpg_len);
>> - h->buff[4] = TPGS_STATE_OPTIMIZED & 0x0f;
>> - h->buff[6] = (h->group_id >> 8) & 0xff;
>> - h->buff[7] = h->group_id & 0xff;
>> + memset(stpg_data, 0, stpg_len);
>> + stpg_data[4] = TPGS_STATE_OPTIMIZED & 0x0f;
>> + put_unaligned_be16(group_id, &stpg_data[6]);
>
> Unrelated get/put_unaligned changes again.
>
>
>> - if (!scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
>> + if (!(driver_byte(retval) & DRIVER_SENSE) ||
>> + !scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
>
> Where does this come from?
>
Hmm. Probably slipped in during patch rework. I'll be removing it.
>> + (!h->pref) &&
>
>
> no need for braces here.
>
OK.
Cheers,
Hannes
--
Dr. Hannes Reinecke zSeries & Storage
hare@suse.de +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 09/20] scsi_dh_alua: switch to scsi_execute()
2015-07-24 14:53 ` Christoph Hellwig
@ 2015-07-25 15:44 ` Hannes Reinecke
0 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2015-07-25 15:44 UTC (permalink / raw)
To: Christoph Hellwig
Cc: James Bottomley, linux-scsi, Martin K. Petersen, Bart van Assche
On 07/24/2015 04:53 PM, Christoph Hellwig wrote:
> Seems like this should use scsi_execute_req_flags instead so that it doesn't
> have to deal with the raw sense buffer.
>
Ok, I'll have a look here.
Cheers,
Hannes
--
Dr. Hannes Reinecke zSeries & Storage
hare@suse.de +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 11/20] scsi_dh_alua: Use separate alua_port_group structure
2015-07-24 14:58 ` Christoph Hellwig
@ 2015-07-25 15:52 ` Hannes Reinecke
0 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2015-07-25 15:52 UTC (permalink / raw)
To: Christoph Hellwig
Cc: James Bottomley, linux-scsi, Martin K. Petersen, Bart van Assche
On 07/24/2015 04:58 PM, Christoph Hellwig wrote:
> On Wed, Jul 08, 2015 at 11:06:09AM +0200, Hannes Reinecke wrote:
>> + pg = kzalloc(sizeof(struct alua_port_group), GFP_KERNEL);
>> + if (!pg) {
>> + sdev_printk(KERN_WARNING, sdev,
>> + "%s: kzalloc port group failed\n",
>> + ALUA_DH_NAME);
>> + /* Temporary failure, bypass */
>> + return SCSI_DH_DEV_TEMP_BUSY;
>> + }
>> + pg->group_id = group_id;
>> + pg->buff = pg->inq;
>> + pg->bufflen = ALUA_INQUIRY_SIZE;
>> + pg->tpgs = h->tpgs;
>> + pg->state = TPGS_STATE_OPTIMIZED;
>> + kref_init(&pg->kref);
>> + spin_lock(&port_group_lock);
>> + list_add(&pg->node, &port_group_list);
>> + h->pg = pg;
>> + spin_unlock(&port_group_lock);
>
> Is there any high level protection against someone racing to allocate
> this structure, e.g. from a sysfs-initiated scan?
>
Not in this patch, as this is called during device scan only. It is
assumed that higher levels will protect against simultaneous scans.
Real protection against concurrent updates is done in patch
'scsi_dh_alua: parse device id', as with that we can easily hit existing
port groups.
>> - len = (h->buff[0] << 24) + (h->buff[1] << 16) +
>> - (h->buff[2] << 8) + h->buff[3] + 4;
>> + len = get_unaligned_be32(&pg->buff[0]) + 4;
>
> Andother spurious get/set_unaligned conversion. I'd really recommend doing
> all of them before the atual series.
>
Okay, will be doing so.
>> + rcu_read_lock();
>> + pg = rcu_dereference(h->pg);
>> + if (!pg) {
>> + rcu_read_unlock();
>> + return -ENXIO;
>> + }
>> + rcu_read_unlock();
>> +
>> if (optimize)
>> - h->flags |= ALUA_OPTIMIZE_STPG;
>> + pg->flags |= ALUA_OPTIMIZE_STPG;
>> else
>> - h->flags &= ~ALUA_OPTIMIZE_STPG;
>> + pg->flags |= ~ALUA_OPTIMIZE_STPG;
>
> You'll need to move the rcu_read_unlock here to be safe.
>
Ok.
Cheers,
Hannes
--
Dr. Hannes Reinecke zSeries & Storage
hare@suse.de +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 14/20] scsi_dh_alua: parse target device id
2015-07-24 15:07 ` Christoph Hellwig
2015-07-24 15:28 ` Martin K. Petersen
@ 2015-07-25 15:53 ` Hannes Reinecke
1 sibling, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2015-07-25 15:53 UTC (permalink / raw)
To: Christoph Hellwig
Cc: James Bottomley, linux-scsi, Martin K. Petersen, Bart van Assche
On 07/24/2015 05:07 PM, Christoph Hellwig wrote:
> On Wed, Jul 08, 2015 at 11:06:12AM +0200, Hannes Reinecke wrote:
>> Parse VPD descriptor to figure out the device identification.
>> As devices might implement several descriptors the order
>> of preference is:
>> - NAA IEE Registered Extended
>> - EUI-64 based 16-byte
>> - EUI-64 based 12-byte
>> - NAA IEEE Registered
>> - NAA IEEE Extended
>> A SCSI name string descriptor is preferred to all of them
>> if the identification is longer than 16 bytes.
>
> Can you move this to scsi_mod.ko? I'll need the same code for the NFS
> SCSI layout driver soon.
>
Ok, will be doing so.
Cheers,
Hannes
--
Dr. Hannes Reinecke zSeries & Storage
hare@suse.de +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 16/20] scsi_dh_alua: Use workqueue for RTPG
2015-07-24 15:21 ` Christoph Hellwig
@ 2015-07-25 15:58 ` Hannes Reinecke
0 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2015-07-25 15:58 UTC (permalink / raw)
To: Christoph Hellwig
Cc: James Bottomley, linux-scsi, Martin K. Petersen, Bart van Assche
On 07/24/2015 05:21 PM, Christoph Hellwig wrote:
>> + char work_q_name[264];
>
> create_workqueue and friends now accept printf-like format
> string, so there is no need for this temporary buffer.
>
>> + int error;
>> + struct completion init_complete;
>
> Please rename error to init_error and only assign to it before calling
> complete().
>
> Also I'm not sure what the real point of init_complete is, shouldn't
> we just have a mutex held in alua_initialize and alua_activate to
> synchronize the two against each other?
>
Hmm. I guess I could; I'll check here.
>> + rcu_read_lock();
>> + pg = rcu_dereference(h->pg);
>> + if (pg) {
>> + kref_get(&pg->kref);
>> + rcu_read_unlock();
>> + alua_rtpg_queue(pg, sdev, NULL);
>> + kref_put(&pg->kref, release_port_group);
>> + } else
>> + rcu_read_unlock();
>> +}
>
> How about:
>
> rcu_read_lock();
> pg = rcu_dereference(h->pg);
> if (!pg) {
> rcu_read_unlock();
> return;
> }
>
> kref_get(&pg->kref);
> rcu_read_unlock();
> alua_rtpg_queue(pg, sdev, NULL);
> kref_put(&pg->kref, release_port_group);
>
Ok.
Cheers,
Hannes
--
Dr. Hannes Reinecke zSeries & Storage
hare@suse.de +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 14/20] scsi_dh_alua: parse target device id
2015-07-24 15:28 ` Martin K. Petersen
@ 2015-07-25 16:00 ` Hannes Reinecke
0 siblings, 0 replies; 38+ messages in thread
From: Hannes Reinecke @ 2015-07-25 16:00 UTC (permalink / raw)
To: Martin K. Petersen, Christoph Hellwig
Cc: James Bottomley, linux-scsi, Bart van Assche
On 07/24/2015 05:28 PM, Martin K. Petersen wrote:
>>>>>> "Christoph" == Christoph Hellwig <hch@lst.de> writes:
>
> Christoph> Can you move this to scsi_mod.ko? I'll need the same code
> Christoph> for the NFS SCSI layout driver soon.
>
> Same here. Working on copy offload again.
>
Hehe. Thought that was needed after all.
(I dimly remember having some parsing code in my initial VPD page
patchset :-)
Cheers,
Hannes
--
Dr. Hannes Reinecke zSeries & Storage
hare@suse.de +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 38+ messages in thread
end of thread, other threads:[~2015-07-25 16:00 UTC | newest]
Thread overview: 38+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-07-08 9:05 [PATCHv2 00/20] asynchronous ALUA device handler Hannes Reinecke
2015-07-08 9:05 ` [PATCH 01/20] scsi_dh_alua: Disable ALUA handling for non-disk devices Hannes Reinecke
2015-07-08 9:06 ` [PATCH 02/20] scsi_dh_alua: Use vpd_pg83 information Hannes Reinecke
2015-07-08 9:06 ` [PATCH 03/20] scsi_dh_alua: improved logging Hannes Reinecke
2015-07-08 9:06 ` [PATCH 04/20] scsi_dh_alua: Improve error handling Hannes Reinecke
2015-07-24 14:48 ` Christoph Hellwig
2015-07-25 15:42 ` Hannes Reinecke
2015-07-08 9:06 ` [PATCH 05/20] scsi: remove scsi_show_sense_hdr() Hannes Reinecke
2015-07-08 9:06 ` [PATCH 06/20] scsi_dh_alua: use flag for RTPG extended header Hannes Reinecke
2015-07-08 9:06 ` [PATCH 07/20] scsi_dh_alua: Pass buffer as function argument Hannes Reinecke
2015-07-24 14:48 ` Christoph Hellwig
2015-07-08 9:06 ` [PATCH 08/20] scsi_dh_alua: Make stpg synchronous Hannes Reinecke
2015-07-24 14:51 ` Christoph Hellwig
2015-07-25 15:44 ` Hannes Reinecke
2015-07-08 9:06 ` [PATCH 09/20] scsi_dh_alua: switch to scsi_execute() Hannes Reinecke
2015-07-24 14:53 ` Christoph Hellwig
2015-07-25 15:44 ` Hannes Reinecke
2015-07-08 9:06 ` [PATCH 10/20] scsi_dh_alua: put sense buffer on stack Hannes Reinecke
2015-07-08 9:06 ` [PATCH 11/20] scsi_dh_alua: Use separate alua_port_group structure Hannes Reinecke
2015-07-24 14:58 ` Christoph Hellwig
2015-07-25 15:52 ` Hannes Reinecke
2015-07-08 9:06 ` [PATCH 12/20] scsi_dh_alua: allocate RTPG buffer separately Hannes Reinecke
2015-07-24 14:59 ` Christoph Hellwig
2015-07-08 9:06 ` [PATCH 13/20] scsi_dh_alua: simplify sense code handling Hannes Reinecke
2015-07-24 15:00 ` Christoph Hellwig
2015-07-08 9:06 ` [PATCH 14/20] scsi_dh_alua: parse target device id Hannes Reinecke
2015-07-24 15:07 ` Christoph Hellwig
2015-07-24 15:28 ` Martin K. Petersen
2015-07-25 16:00 ` Hannes Reinecke
2015-07-25 15:53 ` Hannes Reinecke
2015-07-08 9:06 ` [PATCH 15/20] revert "scsi_dh_alua: ALUA hander attach should succeed while TPG is transitioning" Hannes Reinecke
2015-07-08 9:06 ` [PATCH 16/20] scsi_dh_alua: Use workqueue for RTPG Hannes Reinecke
2015-07-24 15:21 ` Christoph Hellwig
2015-07-25 15:58 ` Hannes Reinecke
2015-07-08 9:06 ` [PATCH 17/20] scsi_dh_alua: Recheck state on unit attention Hannes Reinecke
2015-07-08 9:06 ` [PATCH 18/20] scsi_dh_alua: update all port states Hannes Reinecke
2015-07-08 9:06 ` [PATCH 19/20] scsi_dh_alua: Send TEST UNIT READY to poll for transitioning Hannes Reinecke
2015-07-08 9:06 ` [PATCH 20/20] scsi_dh_alua: Update version to 2.0 Hannes Reinecke
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).