[PATCH draft 2/2] scsi_dh: cleanup blk_get_request callers

From: Joe Lawrence
Date: Thu Apr 25 2013 - 16:00:51 EST


Collect common code scattered throughout the SCSI device handler drivers
that call blk_get_request. Create a wrapper in scsi_dh that gets the
request, maps a kernel buffer, and sets command failfast behavior.
Callers should be prepared to handle various SCSI_DH_* error codes.

Also fix the callers of the scsi_dh_emc routine send_inquiry_cmd to
properly handle errors when the sense length is zero.

Signed-off-by: Joe Lawrence <joe.lawrence@xxxxxxxxxxx>
---
drivers/scsi/device_handler/scsi_dh.c | 58 +++++++++++++++
drivers/scsi/device_handler/scsi_dh_alua.c | 58 +++++----------
drivers/scsi/device_handler/scsi_dh_emc.c | 111 ++++++++++------------------
drivers/scsi/device_handler/scsi_dh_hp_sw.c | 36 ++++-----
drivers/scsi/device_handler/scsi_dh_rdac.c | 60 +++++----------
include/scsi/scsi_dh.h | 10 +++
6 files changed, 161 insertions(+), 172 deletions(-)

diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c
index 33e422e..b629de0 100644
--- a/drivers/scsi/device_handler/scsi_dh.c
+++ b/drivers/scsi/device_handler/scsi_dh.c
@@ -561,6 +561,64 @@ const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp)
}
EXPORT_SYMBOL_GPL(scsi_dh_attached_handler_name);

+#define errno_to_SCSI_DH(errno) \
+ (((errno) == -ENODEV) ? SCSI_DH_DEV_OFFLINED \
+ : SCSI_DH_RES_TEMP_UNAVAIL) \
+
+/*
+ * scsi_dh_get_request - Wrapper of blk_get_request for device handlers
+ * @rqp - pointer to new request pointer
+ * @rw - request RW and SYNC flags
+ * @sdev - SCSI device of associated request queue
+ * @buf - kernel buffer to map into request
+ * @buflen - kernel buffer length
+ * @timeout - request timeout
+ * @retries - request retries
+ *
+ * Get a free request from SCSI device request queue. Maps kernel data
+ * buffer if @buf and @buflen are non-zero. Sets new request structure
+ * timeout and retries members.
+ *
+ * Returns SCSI_DH_OK and sets @*rqp on success, SCSI_DH_* on error.
+ */
+int scsi_dh_get_request(struct request **rqp, int rw, gfp_t gfp_mask,
+ struct scsi_device *sdev, void *buf, unsigned buflen,
+ unsigned timeout, int retries)
+{
+ struct request *rq;
+ struct request_queue *q = sdev->request_queue;
+ int err;
+
+ rq = blk_get_request(q, rw, gfp_mask);
+
+ if (IS_ERR(rq)) {
+ sdev_printk(KERN_INFO, sdev,
+ "%s: blk_get_request failed\n", __func__);
+ return errno_to_SCSI_DH(PTR_ERR(rq));
+ }
+
+ if (buf && buflen) {
+ err = blk_rq_map_kern(q, rq, buf, buflen, gfp_mask);
+ if (err) {
+ blk_put_request(rq);
+ sdev_printk(KERN_INFO, sdev,
+ "%s: blk__rq_map_kern failed.\n", __func__);
+ return errno_to_SCSI_DH(err);
+ }
+ }
+
+ rq->cmd_type = REQ_TYPE_BLOCK_PC;
+ rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
+ REQ_FAILFAST_DRIVER;
+ rq->timeout = timeout;
+ rq->retries = retries;
+
+ *rqp = rq;
+
+ return SCSI_DH_OK;
+}
+EXPORT_SYMBOL_GPL(scsi_dh_get_request);
+
static struct notifier_block scsi_dh_nb = {
.notifier_call = scsi_dh_notifier
};
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index f07f152..ed9e0c7 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -107,36 +107,6 @@ 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;
- }
-
- 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_type = REQ_TYPE_BLOCK_PC;
- 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_vpd_inquiry - Issue an INQUIRY VPD page 0x83 command
* @sdev: sdev the command should be sent to
@@ -144,10 +114,12 @@ static struct request *get_alua_req(struct scsi_device *sdev,
static int submit_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
{
struct request *rq;
- int err = SCSI_DH_RES_TEMP_UNAVAIL;
+ int err;

- rq = get_alua_req(sdev, h->buff, h->bufflen, READ);
- if (!rq)
+ err = scsi_dh_get_request(&rq, READ, GFP_NOIO, sdev, h->buff,
+ h->bufflen, ALUA_FAILOVER_TIMEOUT * HZ,
+ ALUA_FAILOVER_RETRIES);
+ if (err)
goto done;

/* Prepare the command. */
@@ -182,10 +154,12 @@ 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)
+ err = scsi_dh_get_request(&rq, READ, GFP_NOIO, sdev, h->buff,
+ h->bufflen, ALUA_FAILOVER_TIMEOUT * HZ,
+ ALUA_FAILOVER_RETRIES);
+ if (err)
goto done;

/* Prepare the command. */
@@ -285,6 +259,7 @@ static unsigned submit_stpg(struct alua_dh_data *h)
struct request *rq;
int stpg_len = 8;
struct scsi_device *sdev = h->sdev;
+ int err;

/* Prepare the data buffer */
memset(h->buff, 0, stpg_len);
@@ -292,9 +267,11 @@ static unsigned submit_stpg(struct alua_dh_data *h)
h->buff[6] = (h->group_id >> 8) & 0xff;
h->buff[7] = h->group_id & 0xff;

- rq = get_alua_req(sdev, h->buff, stpg_len, WRITE);
- if (!rq)
- return SCSI_DH_RES_TEMP_UNAVAIL;
+ err = scsi_dh_get_request(&rq, WRITE, GFP_NOIO, sdev, h->buff,
+ stpg_len, ALUA_FAILOVER_TIMEOUT * HZ,
+ ALUA_FAILOVER_RETRIES);
+ if (err)
+ goto done;

/* Prepare the command. */
rq->cmd[0] = MAINTENANCE_OUT;
@@ -311,7 +288,8 @@ static unsigned submit_stpg(struct alua_dh_data *h)
rq->end_io_data = h;

blk_execute_rq_nowait(rq->q, NULL, rq, 1, stpg_endio);
- return SCSI_DH_OK;
+done:
+ return err;
}

/*
diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c
index 2ec3261..eab62c5 100644
--- a/drivers/scsi/device_handler/scsi_dh_emc.c
+++ b/drivers/scsi/device_handler/scsi_dh_emc.c
@@ -260,82 +260,32 @@ out:
return sp_model;
}

-/*
- * Get block request for REQ_BLOCK_PC command issued to path. Currently
- * limited to MODE_SELECT (trespass) and INQUIRY (VPD page 0xC0) commands.
- *
- * Uses data and sense buffers in hardware handler context structure and
- * assumes serial servicing of commands, both issuance and completion.
- */
-static struct request *get_req(struct scsi_device *sdev, int cmd,
- unsigned char *buffer)
-{
- struct request *rq;
- int len = 0;
-
- rq = blk_get_request(sdev->request_queue,
- (cmd != INQUIRY) ? WRITE : READ, GFP_NOIO);
- if (IS_ERR(rq)) {
- sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed");
- return NULL;
- }
-
- rq->cmd_len = COMMAND_SIZE(cmd);
- rq->cmd[0] = cmd;
-
- switch (cmd) {
- case MODE_SELECT:
- len = sizeof(short_trespass);
- rq->cmd[1] = 0x10;
- rq->cmd[4] = len;
- break;
- case MODE_SELECT_10:
- len = sizeof(long_trespass);
- rq->cmd[1] = 0x10;
- rq->cmd[8] = len;
- break;
- case INQUIRY:
- len = CLARIION_BUFFER_SIZE;
- rq->cmd[4] = len;
- memset(buffer, 0, len);
- break;
- default:
- BUG_ON(1);
- break;
- }
-
- rq->cmd_type = REQ_TYPE_BLOCK_PC;
- rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
- REQ_FAILFAST_DRIVER;
- rq->timeout = CLARIION_TIMEOUT;
- rq->retries = CLARIION_RETRIES;
-
- if (blk_rq_map_kern(rq->q, rq, buffer, len, GFP_NOIO)) {
- blk_put_request(rq);
- return NULL;
- }
-
- return rq;
-}
-
static int send_inquiry_cmd(struct scsi_device *sdev, int page,
struct clariion_dh_data *csdev)
{
- struct request *rq = get_req(sdev, INQUIRY, csdev->buffer);
+ struct request *rq;
int err;

- if (!rq)
- return SCSI_DH_RES_TEMP_UNAVAIL;
-
- rq->sense = csdev->sense;
- memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
- rq->sense_len = csdev->senselen = 0;
+ err = scsi_dh_get_request(&rq, READ, GFP_NOIO, sdev, csdev->buffer,
+ CLARIION_BUFFER_SIZE, CLARIION_TIMEOUT,
+ CLARIION_RETRIES);
+ if (err)
+ goto done;

+ /* Prepare the command. */
rq->cmd[0] = INQUIRY;
if (page != 0) {
rq->cmd[1] = 1;
rq->cmd[2] = page;
}
+ rq->cmd[4] = CLARIION_BUFFER_SIZE;
+ memset(csdev->buffer, 0, CLARIION_BUFFER_SIZE);
+ rq->cmd_len = COMMAND_SIZE(INQUIRY);
+
+ rq->sense = csdev->sense;
+ memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
+ rq->sense_len = csdev->senselen = 0;
+
err = blk_execute_rq(sdev->request_queue, NULL, rq, 1);
if (err == -EIO) {
sdev_printk(KERN_INFO, sdev,
@@ -347,7 +297,7 @@ static int send_inquiry_cmd(struct scsi_device *sdev, int page,
}

blk_put_request(rq);
-
+done:
return err;
}

@@ -376,9 +326,19 @@ static int send_trespass_cmd(struct scsi_device *sdev,
BUG_ON((len > CLARIION_BUFFER_SIZE));
memcpy(csdev->buffer, page22, len);

- rq = get_req(sdev, cmd, csdev->buffer);
- if (!rq)
- return SCSI_DH_RES_TEMP_UNAVAIL;
+ err = scsi_dh_get_request(&rq, WRITE, GFP_NOIO, sdev, csdev->buffer,
+ len, CLARIION_TIMEOUT, CLARIION_RETRIES);
+ if (err)
+ goto done;
+
+ /* Prepare the command. */
+ rq->cmd[0] = cmd;
+ rq->cmd[1] = 0x10;
+ if (cmd == MODE_SELECT)
+ rq->cmd[4] = len;
+ else if (cmd == MODE_SELECT_10)
+ rq->cmd[8] = len;
+ rq->cmd_len = COMMAND_SIZE(cmd);

rq->sense = csdev->sense;
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
@@ -396,7 +356,7 @@ static int send_trespass_cmd(struct scsi_device *sdev,
}

blk_put_request(rq);
-
+done:
return err;
}

@@ -468,9 +428,12 @@ static int clariion_std_inquiry(struct scsi_device *sdev,
char *sp_model;

err = send_inquiry_cmd(sdev, 0, csdev);
- if (err != SCSI_DH_OK && csdev->senselen) {
+ if (err != SCSI_DH_OK) {
struct scsi_sense_hdr sshdr;

+ if (!csdev->senselen)
+ goto out;
+
if (scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE,
&sshdr)) {
sdev_printk(KERN_ERR, sdev, "%s: INQUIRY sense code "
@@ -507,9 +470,12 @@ static int clariion_send_inquiry(struct scsi_device *sdev,

retry:
err = send_inquiry_cmd(sdev, 0xC0, csdev);
- if (err != SCSI_DH_OK && csdev->senselen) {
+ if (err != SCSI_DH_OK) {
struct scsi_sense_hdr sshdr;

+ if (!csdev->senselen)
+ goto done;
+
err = scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE,
&sshdr);
if (!err)
@@ -527,6 +493,7 @@ retry:
} else {
err = parse_sp_info_reply(sdev, csdev);
}
+done:
return err;
}

diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
index 1cf4019..2d03c4d 100644
--- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c
+++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
@@ -116,16 +116,15 @@ static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h)
int ret;

retry:
- req = blk_get_request(sdev->request_queue, WRITE, GFP_NOIO);
- if (IS_ERR(req))
- return SCSI_DH_RES_TEMP_UNAVAIL;
+ ret = scsi_dh_get_request(&req, WRITE, GFP_NOIO, sdev, 0, 0,
+ HP_SW_TIMEOUT, 0);
+ if (ret)
+ goto done;

- req->cmd_type = REQ_TYPE_BLOCK_PC;
- req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
- REQ_FAILFAST_DRIVER;
- req->cmd_len = COMMAND_SIZE(TEST_UNIT_READY);
+ /* Prepare the command. */
req->cmd[0] = TEST_UNIT_READY;
- req->timeout = HP_SW_TIMEOUT;
+ req->cmd_len = COMMAND_SIZE(TEST_UNIT_READY);
+
req->sense = h->sense;
memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
req->sense_len = 0;
@@ -154,7 +153,7 @@ retry:
}

blk_put_request(req);
-
+done:
return ret;
}

@@ -245,25 +244,26 @@ done:
static int hp_sw_start_stop(struct hp_sw_dh_data *h)
{
struct request *req;
+ int ret;

- req = blk_get_request(h->sdev->request_queue, WRITE, GFP_ATOMIC);
- if (IS_ERR(req))
- return SCSI_DH_RES_TEMP_UNAVAIL;
+ ret = scsi_dh_get_request(&req, WRITE, GFP_ATOMIC, h->sdev, 0, 0,
+ HP_SW_TIMEOUT, 0);
+ if (ret)
+ goto done;

- req->cmd_type = REQ_TYPE_BLOCK_PC;
- req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
- REQ_FAILFAST_DRIVER;
- req->cmd_len = COMMAND_SIZE(START_STOP);
+ /* Prepare the command. */
req->cmd[0] = START_STOP;
req->cmd[4] = 1; /* Start spin cycle */
- req->timeout = HP_SW_TIMEOUT;
+ req->cmd_len = COMMAND_SIZE(START_STOP);
+
req->sense = h->sense;
memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
req->sense_len = 0;
req->end_io_data = h;

blk_execute_rq_nowait(req->q, NULL, req, 1, start_stop_endio);
- return SCSI_DH_OK;
+done:
+ return ret;
}

static int hp_sw_prep_fn(struct scsi_device *sdev, struct request *req)
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
index 009bd8f..26ed28f 100644
--- a/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -266,44 +266,16 @@ static inline struct rdac_dh_data *get_rdac_data(struct scsi_device *sdev)
return ((struct rdac_dh_data *) scsi_dh_data->buf);
}

-static struct request *get_rdac_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,
- "get_rdac_req: blk_get_request failed.\n");
- return NULL;
- }
-
- if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_NOIO)) {
- blk_put_request(rq);
- sdev_printk(KERN_INFO, sdev,
- "get_rdac_req: blk_rq_map_kern failed.\n");
- return NULL;
- }
-
- rq->cmd_type = REQ_TYPE_BLOCK_PC;
- rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
- REQ_FAILFAST_DRIVER;
- rq->retries = RDAC_RETRIES;
- rq->timeout = RDAC_TIMEOUT;
-
- return rq;
-}
-
-static struct request *rdac_failover_get(struct scsi_device *sdev,
- struct rdac_dh_data *h, struct list_head *list)
+static int rdac_failover_get(struct request **rqp,
+ struct scsi_device *sdev, struct rdac_dh_data *h,
+ struct list_head *list)
{
struct request *rq;
struct rdac_mode_common *common;
unsigned data_size;
struct rdac_queue_data *qdata;
u8 *lun_table;
+ int err;

if (h->ctlr->use_ms10) {
struct rdac_pg_expanded *rdac_pg;
@@ -337,9 +309,11 @@ static struct request *rdac_failover_get(struct scsi_device *sdev,
}

/* get request for block layer packet command */
- rq = get_rdac_req(sdev, &h->ctlr->mode_select, data_size, WRITE);
- if (!rq)
- return NULL;
+ err = scsi_dh_get_request(&rq, WRITE, GFP_NOIO, sdev,
+ &h->ctlr->mode_select, data_size,
+ RDAC_TIMEOUT, RDAC_RETRIES);
+ if (err)
+ goto done;

/* Prepare the command. */
if (h->ctlr->use_ms10) {
@@ -356,7 +330,9 @@ static struct request *rdac_failover_get(struct scsi_device *sdev,
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
rq->sense_len = 0;

- return rq;
+ *rqp = rq;
+done:
+ return err;
}

static void release_controller(struct kref *kref)
@@ -408,10 +384,11 @@ static int submit_inquiry(struct scsi_device *sdev, int page_code,
{
struct request *rq;
struct request_queue *q = sdev->request_queue;
- int err = SCSI_DH_RES_TEMP_UNAVAIL;
+ int err;

- rq = get_rdac_req(sdev, &h->inq, len, READ);
- if (!rq)
+ err = scsi_dh_get_request(&rq, READ, GFP_NOIO, sdev, &h->inq, len,
+ RDAC_TIMEOUT, RDAC_RETRIES);
+ if (err)
goto done;

/* Prepare the command. */
@@ -603,9 +580,8 @@ static void send_mode_select(struct work_struct *work)
spin_unlock(&ctlr->ms_lock);

retry:
- err = SCSI_DH_RES_TEMP_UNAVAIL;
- rq = rdac_failover_get(sdev, h, &list);
- if (!rq)
+ err = rdac_failover_get(&rq, sdev, h, &list);
+ if (err)
goto done;

RDAC_LOG(RDAC_LOG_FAILOVER, sdev, "array %s, ctlr %d, "
diff --git a/include/scsi/scsi_dh.h b/include/scsi/scsi_dh.h
index 620c723..c3bc702 100644
--- a/include/scsi/scsi_dh.h
+++ b/include/scsi/scsi_dh.h
@@ -62,6 +62,9 @@ extern int scsi_dh_attach(struct request_queue *, const char *);
extern void scsi_dh_detach(struct request_queue *);
extern const char *scsi_dh_attached_handler_name(struct request_queue *, gfp_t);
extern int scsi_dh_set_params(struct request_queue *, const char *);
+extern int scsi_dh_get_request(struct request **, int, gfp_t,
+ struct scsi_device *, void *, unsigned len,
+ unsigned timeout, int retries);
#else
static inline int scsi_dh_activate(struct request_queue *req,
activate_complete fn, void *data)
@@ -90,4 +93,11 @@ static inline int scsi_dh_set_params(struct request_queue *req, const char *para
{
return -SCSI_DH_NOSYS;
}
+static inline int scsi_dh_get_request(struct request **rqp, int rw,
+ gfp_t gfp_mask, struct scsi_device *sdev,
+ void *buf, unsigned len, unsigned timeout,
+ int retries)
+{
+ return SCSI_DH_NOSYS;
+}
#endif
--
1.8.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/