[SCSI] st: add st_scsi_execute helper function
authorFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Thu, 18 Dec 2008 05:49:41 +0000 (14:49 +0900)
committerJames Bottomley <James.Bottomley@HansenPartnership.com>
Fri, 2 Jan 2009 17:54:45 +0000 (11:54 -0600)
st_scsi_execute is a helper function to perform SCSI commands
involving data transfer between user and kernel space (st_read and
st_write).

It's the future plan to combine this with st_scsi_kern_execute helper
function.

Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Acked-by: Kai Makisara <Kai.Makisara@kolumbus.fi>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
drivers/scsi/st.c
drivers/scsi/st.h

index 9d9e4b90f23b34e1a6559cb8f8778411f482267d..084a967b2e782b811a9d8b577207760436be6c4b 100644 (file)
@@ -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. */
index 74748abe82463c0a138ac742f33256bae6bbacc3..77302fa8608aa7f098f43050c73a77e41641601b 100644 (file)
@@ -29,6 +29,7 @@ struct st_request {
        int result;
        struct scsi_tape *stp;
        struct completion *waiting;
+       struct bio *bio;
 };
 
 /* The tape buffer descriptor. */