summaryrefslogtreecommitdiffstats
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.c84
1 files changed, 37 insertions, 47 deletions
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 47d3cdd6ddf..94d82cb9662 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -1039,9 +1039,6 @@ static int scsi_init_io(struct scsi_cmnd *cmd)
printk(KERN_ERR "req nr_sec %lu, cur_nr_sec %u\n", req->nr_sectors,
req->current_nr_sectors);
- /* release the command and kill it */
- scsi_release_buffers(cmd);
- scsi_put_command(cmd);
return BLKPREP_KILL;
}
@@ -1078,9 +1075,13 @@ static void scsi_blk_pc_done(struct scsi_cmnd *cmd)
scsi_io_completion(cmd, cmd->request_bufflen);
}
-static int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
+int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
{
struct scsi_cmnd *cmd;
+ int ret = scsi_prep_state_check(sdev, req);
+
+ if (ret != BLKPREP_OK)
+ return ret;
cmd = scsi_get_cmd_from_req(sdev, req);
if (unlikely(!cmd))
@@ -1126,18 +1127,20 @@ static int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
cmd->done = scsi_blk_pc_done;
return BLKPREP_OK;
}
+EXPORT_SYMBOL(scsi_setup_blk_pc_cmnd);
/*
* Setup a REQ_TYPE_FS command. These are simple read/write request
* from filesystems that still need to be translated to SCSI CDBs from
* the ULD.
*/
-static int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req)
+int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req)
{
struct scsi_cmnd *cmd;
- struct scsi_driver *drv;
- int ret;
+ int ret = scsi_prep_state_check(sdev, req);
+ if (ret != BLKPREP_OK)
+ return ret;
/*
* Filesystem requests must transfer data.
*/
@@ -1147,26 +1150,12 @@ static int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req)
if (unlikely(!cmd))
return BLKPREP_DEFER;
- ret = scsi_init_io(cmd);
- if (unlikely(ret))
- return ret;
-
- /*
- * Initialize the actual SCSI command for this request.
- */
- drv = *(struct scsi_driver **)req->rq_disk->private_data;
- if (unlikely(!drv->init_command(cmd))) {
- scsi_release_buffers(cmd);
- scsi_put_command(cmd);
- return BLKPREP_KILL;
- }
-
- return BLKPREP_OK;
+ return scsi_init_io(cmd);
}
+EXPORT_SYMBOL(scsi_setup_fs_cmnd);
-static int scsi_prep_fn(struct request_queue *q, struct request *req)
+int scsi_prep_state_check(struct scsi_device *sdev, struct request *req)
{
- struct scsi_device *sdev = q->queuedata;
int ret = BLKPREP_OK;
/*
@@ -1212,35 +1201,25 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
ret = BLKPREP_KILL;
break;
}
-
- if (ret != BLKPREP_OK)
- goto out;
}
+ return ret;
+}
+EXPORT_SYMBOL(scsi_prep_state_check);
- switch (req->cmd_type) {
- case REQ_TYPE_BLOCK_PC:
- ret = scsi_setup_blk_pc_cmnd(sdev, req);
- break;
- case REQ_TYPE_FS:
- ret = scsi_setup_fs_cmnd(sdev, req);
- break;
- default:
- /*
- * All other command types are not supported.
- *
- * Note that these days the SCSI subsystem does not use
- * REQ_TYPE_SPECIAL requests anymore. These are only used
- * (directly or via blk_insert_request) by non-SCSI drivers.
- */
- blk_dump_rq_flags(req, "SCSI bad req");
- ret = BLKPREP_KILL;
- break;
- }
+int scsi_prep_return(struct request_queue *q, struct request *req, int ret)
+{
+ struct scsi_device *sdev = q->queuedata;
- out:
switch (ret) {
case BLKPREP_KILL:
req->errors = DID_NO_CONNECT << 16;
+ /* release the command and kill it */
+ if (req->special) {
+ struct scsi_cmnd *cmd = req->special;
+ scsi_release_buffers(cmd);
+ scsi_put_command(cmd);
+ req->special = NULL;
+ }
break;
case BLKPREP_DEFER:
/*
@@ -1257,6 +1236,17 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
return ret;
}
+EXPORT_SYMBOL(scsi_prep_return);
+
+static int scsi_prep_fn(struct request_queue *q, struct request *req)
+{
+ struct scsi_device *sdev = q->queuedata;
+ int ret = BLKPREP_KILL;
+
+ if (req->cmd_type == REQ_TYPE_BLOCK_PC)
+ ret = scsi_setup_blk_pc_cmnd(sdev, req);
+ return scsi_prep_return(q, req, ret);
+}
/*
* scsi_dev_queue_ready: if we can send requests to sdev, return 1 else