summaryrefslogtreecommitdiff
path: root/drivers/scsi/st.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/st.c')
-rw-r--r--drivers/scsi/st.c54
1 files changed, 54 insertions, 0 deletions
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 9d9e4b90f23b..084a967b2e78 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -475,6 +475,60 @@ static void st_release_request(struct st_request *streq)
kfree(streq);
}
+static void st_scsi_execute_end(struct request *req, int uptodate)
+{
+ struct st_request *SRpnt = req->end_io_data;
+ struct scsi_tape *STp = SRpnt->stp;
+
+ STp->buffer->cmdstat.midlevel_result = SRpnt->result = req->errors;
+ STp->buffer->cmdstat.residual = req->data_len;
+
+ if (SRpnt->waiting)
+ complete(SRpnt->waiting);
+
+ blk_rq_unmap_user(SRpnt->bio);
+ __blk_put_request(req->q, req);
+}
+
+static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd,
+ int data_direction, void *buffer, unsigned bufflen,
+ int timeout, int retries)
+{
+ struct request *req;
+ struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data;
+ int err = 0;
+ int write = (data_direction == DMA_TO_DEVICE);
+
+ req = blk_get_request(SRpnt->stp->device->request_queue, write,
+ GFP_KERNEL);
+ if (!req)
+ return DRIVER_ERROR << 24;
+
+ req->cmd_type = REQ_TYPE_BLOCK_PC;
+ req->cmd_flags |= REQ_QUIET;
+
+ mdata->null_mapped = 1;
+
+ err = blk_rq_map_user(req->q, req, mdata, NULL, bufflen, GFP_KERNEL);
+ if (err) {
+ blk_put_request(req);
+ return DRIVER_ERROR << 24;
+ }
+
+ SRpnt->bio = req->bio;
+ req->cmd_len = COMMAND_SIZE(cmd[0]);
+ memset(req->cmd, 0, BLK_MAX_CDB);
+ memcpy(req->cmd, cmd, req->cmd_len);
+ req->sense = SRpnt->sense;
+ req->sense_len = 0;
+ req->timeout = timeout;
+ req->retries = retries;
+ req->end_io_data = SRpnt;
+
+ blk_execute_rq_nowait(req->q, NULL, req, 1, st_scsi_execute_end);
+ return 0;
+}
+
/* Do the scsi command. Waits until command performed if do_wait is true.
Otherwise write_behind_check() is used to check that the command
has finished. */