aboutsummaryrefslogtreecommitdiff
path: root/drivers/scsi/scsi_lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/scsi_lib.c')
-rw-r--r--drivers/scsi/scsi_lib.c123
1 files changed, 64 insertions, 59 deletions
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 8b89fab7c420..abe93ec8b7d0 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -185,39 +185,37 @@ void scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
__scsi_queue_insert(cmd, reason, true);
}
-
/**
- * __scsi_execute - insert request and wait for the result
- * @sdev: scsi device
+ * scsi_execute_cmd - insert request and wait for the result
+ * @sdev: scsi_device
* @cmd: scsi command
- * @data_direction: data direction
+ * @opf: block layer request cmd_flags
* @buffer: data buffer
* @bufflen: len of buffer
- * @sense: optional sense buffer
- * @sshdr: optional decoded sense header
* @timeout: request timeout in HZ
* @retries: number of times to retry request
- * @flags: flags for ->cmd_flags
- * @rq_flags: flags for ->rq_flags
- * @resid: optional residual length
+ * @args: Optional args. See struct definition for field descriptions
*
* Returns the scsi_cmnd result field if a command was executed, or a negative
* Linux error code if we didn't get that far.
*/
-int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
- int data_direction, void *buffer, unsigned bufflen,
- unsigned char *sense, struct scsi_sense_hdr *sshdr,
- int timeout, int retries, blk_opf_t flags,
- req_flags_t rq_flags, int *resid)
+int scsi_execute_cmd(struct scsi_device *sdev, const unsigned char *cmd,
+ blk_opf_t opf, void *buffer, unsigned int bufflen,
+ int timeout, int retries,
+ const struct scsi_exec_args *args)
{
+ static const struct scsi_exec_args default_args;
struct request *req;
struct scsi_cmnd *scmd;
int ret;
- req = scsi_alloc_request(sdev->request_queue,
- data_direction == DMA_TO_DEVICE ?
- REQ_OP_DRV_OUT : REQ_OP_DRV_IN,
- rq_flags & RQF_PM ? BLK_MQ_REQ_PM : 0);
+ if (!args)
+ args = &default_args;
+ else if (WARN_ON_ONCE(args->sense &&
+ args->sense_len != SCSI_SENSE_BUFFERSIZE))
+ return -EINVAL;
+
+ req = scsi_alloc_request(sdev->request_queue, opf, args->req_flags);
if (IS_ERR(req))
return PTR_ERR(req);
@@ -232,8 +230,7 @@ int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
memcpy(scmd->cmnd, cmd, scmd->cmd_len);
scmd->allowed = retries;
req->timeout = timeout;
- req->cmd_flags |= flags;
- req->rq_flags |= rq_flags | RQF_QUIET;
+ req->rq_flags |= RQF_QUIET;
/*
* head injection *required* here otherwise quiesce won't work
@@ -249,20 +246,21 @@ int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
if (unlikely(scmd->resid_len > 0 && scmd->resid_len <= bufflen))
memset(buffer + bufflen - scmd->resid_len, 0, scmd->resid_len);
- if (resid)
- *resid = scmd->resid_len;
- if (sense && scmd->sense_len)
- memcpy(sense, scmd->sense_buffer, SCSI_SENSE_BUFFERSIZE);
- if (sshdr)
+ if (args->resid)
+ *args->resid = scmd->resid_len;
+ if (args->sense)
+ memcpy(args->sense, scmd->sense_buffer, SCSI_SENSE_BUFFERSIZE);
+ if (args->sshdr)
scsi_normalize_sense(scmd->sense_buffer, scmd->sense_len,
- sshdr);
+ args->sshdr);
+
ret = scmd->result;
out:
blk_mq_free_request(req);
return ret;
}
-EXPORT_SYMBOL(__scsi_execute);
+EXPORT_SYMBOL(scsi_execute_cmd);
/*
* Wake up the error handler if necessary. Avoid as follows that the error
@@ -308,6 +306,18 @@ static void scsi_kick_queue(struct request_queue *q)
}
/*
+ * Kick the queue of SCSI device @sdev if @sdev != current_sdev. Called with
+ * interrupts disabled.
+ */
+static void scsi_kick_sdev_queue(struct scsi_device *sdev, void *data)
+{
+ struct scsi_device *current_sdev = data;
+
+ if (sdev != current_sdev)
+ blk_mq_run_hw_queues(sdev->request_queue, true);
+}
+
+/*
* Called for single_lun devices on IO completion. Clear starget_sdev_user,
* and call blk_run_queue for all the scsi_devices on the target -
* including current_sdev first.
@@ -317,7 +327,6 @@ static void scsi_kick_queue(struct request_queue *q)
static void scsi_single_lun_run(struct scsi_device *current_sdev)
{
struct Scsi_Host *shost = current_sdev->host;
- struct scsi_device *sdev, *tmp;
struct scsi_target *starget = scsi_target(current_sdev);
unsigned long flags;
@@ -334,22 +343,9 @@ static void scsi_single_lun_run(struct scsi_device *current_sdev)
scsi_kick_queue(current_sdev->request_queue);
spin_lock_irqsave(shost->host_lock, flags);
- if (starget->starget_sdev_user)
- goto out;
- list_for_each_entry_safe(sdev, tmp, &starget->devices,
- same_target_siblings) {
- if (sdev == current_sdev)
- continue;
- if (scsi_device_get(sdev))
- continue;
-
- spin_unlock_irqrestore(shost->host_lock, flags);
- scsi_kick_queue(sdev->request_queue);
- spin_lock_irqsave(shost->host_lock, flags);
-
- scsi_device_put(sdev);
- }
- out:
+ if (!starget->starget_sdev_user)
+ __starget_for_each_device(starget, current_sdev,
+ scsi_kick_sdev_queue);
spin_unlock_irqrestore(shost->host_lock, flags);
}
@@ -1343,9 +1339,6 @@ static inline int scsi_host_queue_ready(struct request_queue *q,
struct scsi_device *sdev,
struct scsi_cmnd *cmd)
{
- if (scsi_host_in_recovery(shost))
- return 0;
-
if (atomic_read(&shost->host_blocked) > 0) {
if (scsi_host_busy(shost) > 0)
goto starved;
@@ -1469,8 +1462,6 @@ static int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
struct Scsi_Host *host = cmd->device->host;
int rtn = 0;
- atomic_inc(&cmd->device->iorequest_cnt);
-
/* check if the device is still usable */
if (unlikely(cmd->device->sdev_state == SDEV_DEL)) {
/* in SDEV_DEL we error all commands. DID_NO_CONNECT
@@ -1734,6 +1725,11 @@ static blk_status_t scsi_queue_rq(struct blk_mq_hw_ctx *hctx,
ret = BLK_STS_RESOURCE;
if (!scsi_target_queue_ready(shost, sdev))
goto out_put_budget;
+ if (unlikely(scsi_host_in_recovery(shost))) {
+ if (cmd->flags & SCMD_FAIL_IF_RECOVERING)
+ ret = BLK_STS_OFFLINE;
+ goto out_dec_target_busy;
+ }
if (!scsi_host_queue_ready(q, shost, sdev, cmd))
goto out_dec_target_busy;
@@ -1764,6 +1760,7 @@ static blk_status_t scsi_queue_rq(struct blk_mq_hw_ctx *hctx,
goto out_dec_host_busy;
}
+ atomic_inc(&cmd->device->iorequest_cnt);
return BLK_STS_OK;
out_dec_host_busy:
@@ -2087,6 +2084,9 @@ int scsi_mode_select(struct scsi_device *sdev, int pf, int sp,
{
unsigned char cmd[10];
unsigned char *real_buffer;
+ const struct scsi_exec_args exec_args = {
+ .sshdr = sshdr,
+ };
int ret;
memset(cmd, 0, sizeof(cmd));
@@ -2136,8 +2136,8 @@ int scsi_mode_select(struct scsi_device *sdev, int pf, int sp,
cmd[4] = len;
}
- ret = scsi_execute_req(sdev, cmd, DMA_TO_DEVICE, real_buffer, len,
- sshdr, timeout, retries, NULL);
+ ret = scsi_execute_cmd(sdev, cmd, REQ_OP_DRV_OUT, real_buffer, len,
+ timeout, retries, &exec_args);
kfree(real_buffer);
return ret;
}
@@ -2168,6 +2168,10 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
int header_length;
int result, retry_count = retries;
struct scsi_sense_hdr my_sshdr;
+ const struct scsi_exec_args exec_args = {
+ /* caller might not be interested in sense, but we need it */
+ .sshdr = sshdr ? : &my_sshdr,
+ };
memset(data, 0, sizeof(*data));
memset(&cmd[0], 0, 12);
@@ -2176,9 +2180,7 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
cmd[1] = dbd & 0x18; /* allows DBD and LLBA bits */
cmd[2] = modepage;
- /* caller might not be interested in sense, but we need it */
- if (!sshdr)
- sshdr = &my_sshdr;
+ sshdr = exec_args.sshdr;
retry:
use_10_for_ms = sdev->use_10_for_ms || len > 255;
@@ -2201,8 +2203,8 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
memset(buffer, 0, len);
- result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, len,
- sshdr, timeout, retries, NULL);
+ result = scsi_execute_cmd(sdev, cmd, REQ_OP_DRV_IN, buffer, len,
+ timeout, retries, &exec_args);
if (result < 0)
return result;
@@ -2282,12 +2284,15 @@ scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries,
char cmd[] = {
TEST_UNIT_READY, 0, 0, 0, 0, 0,
};
+ const struct scsi_exec_args exec_args = {
+ .sshdr = sshdr,
+ };
int result;
/* try to eat the UNIT_ATTENTION if there are enough retries */
do {
- result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, sshdr,
- timeout, 1, NULL);
+ result = scsi_execute_cmd(sdev, cmd, REQ_OP_DRV_IN, NULL, 0,
+ timeout, 1, &exec_args);
if (sdev->removable && scsi_sense_valid(sshdr) &&
sshdr->sense_key == UNIT_ATTENTION)
sdev->changed = 1;
@@ -2735,7 +2740,7 @@ static void scsi_stop_queue(struct scsi_device *sdev, bool nowait)
blk_mq_quiesce_queue(sdev->request_queue);
} else {
if (!nowait)
- blk_mq_wait_quiesce_done(sdev->request_queue);
+ blk_mq_wait_quiesce_done(sdev->request_queue->tag_set);
}
}