diff options
| author | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2008-12-18 00:49:41 -0500 |
|---|---|---|
| committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-01-02 12:54:45 -0500 |
| commit | 13b53b443482623d33fd9446289d320e1c719f02 (patch) | |
| tree | ce987e03335e3cc34f2d0cd47f9769af56476bde /drivers/scsi/st.c | |
| parent | d0e1ae31be226e83cdd0684625bf1535518ee0d3 (diff) | |
[SCSI] st: add st_scsi_execute helper function
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>
Diffstat (limited to 'drivers/scsi/st.c')
| -rw-r--r-- | drivers/scsi/st.c | 54 |
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) | |||
| 475 | kfree(streq); | 475 | kfree(streq); |
| 476 | } | 476 | } |
| 477 | 477 | ||
| 478 | static void st_scsi_execute_end(struct request *req, int uptodate) | ||
| 479 | { | ||
| 480 | struct st_request *SRpnt = req->end_io_data; | ||
| 481 | struct scsi_tape *STp = SRpnt->stp; | ||
| 482 | |||
| 483 | STp->buffer->cmdstat.midlevel_result = SRpnt->result = req->errors; | ||
| 484 | STp->buffer->cmdstat.residual = req->data_len; | ||
| 485 | |||
| 486 | if (SRpnt->waiting) | ||
| 487 | complete(SRpnt->waiting); | ||
| 488 | |||
| 489 | blk_rq_unmap_user(SRpnt->bio); | ||
| 490 | __blk_put_request(req->q, req); | ||
| 491 | } | ||
| 492 | |||
| 493 | static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd, | ||
| 494 | int data_direction, void *buffer, unsigned bufflen, | ||
| 495 | int timeout, int retries) | ||
| 496 | { | ||
| 497 | struct request *req; | ||
| 498 | struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data; | ||
| 499 | int err = 0; | ||
| 500 | int write = (data_direction == DMA_TO_DEVICE); | ||
| 501 | |||
| 502 | req = blk_get_request(SRpnt->stp->device->request_queue, write, | ||
| 503 | GFP_KERNEL); | ||
| 504 | if (!req) | ||
| 505 | return DRIVER_ERROR << 24; | ||
| 506 | |||
| 507 | req->cmd_type = REQ_TYPE_BLOCK_PC; | ||
| 508 | req->cmd_flags |= REQ_QUIET; | ||
| 509 | |||
| 510 | mdata->null_mapped = 1; | ||
| 511 | |||
| 512 | err = blk_rq_map_user(req->q, req, mdata, NULL, bufflen, GFP_KERNEL); | ||
| 513 | if (err) { | ||
| 514 | blk_put_request(req); | ||
| 515 | return DRIVER_ERROR << 24; | ||
| 516 | } | ||
| 517 | |||
| 518 | SRpnt->bio = req->bio; | ||
| 519 | req->cmd_len = COMMAND_SIZE(cmd[0]); | ||
| 520 | memset(req->cmd, 0, BLK_MAX_CDB); | ||
| 521 | memcpy(req->cmd, cmd, req->cmd_len); | ||
| 522 | req->sense = SRpnt->sense; | ||
| 523 | req->sense_len = 0; | ||
| 524 | req->timeout = timeout; | ||
| 525 | req->retries = retries; | ||
| 526 | req->end_io_data = SRpnt; | ||
| 527 | |||
| 528 | blk_execute_rq_nowait(req->q, NULL, req, 1, st_scsi_execute_end); | ||
| 529 | return 0; | ||
| 530 | } | ||
| 531 | |||
| 478 | /* Do the scsi command. Waits until command performed if do_wait is true. | 532 | /* Do the scsi command. Waits until command performed if do_wait is true. |
| 479 | Otherwise write_behind_check() is used to check that the command | 533 | Otherwise write_behind_check() is used to check that the command |
| 480 | has finished. */ | 534 | has finished. */ |
