summaryrefslogtreecommitdiff
path: root/drivers/scsi/osst.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2009-03-28 23:24:12 +0100
committerIngo Molnar <mingo@elte.hu>2009-03-28 23:24:12 +0100
commitd00ab2fdd4dc4361c97777bc1fef7234329d4659 (patch)
treeb8d8f98c1af633bbc1570b4270b39727737beebf /drivers/scsi/osst.c
parent88f502fedba82eff252b6420e8b8328e4ae25c67 (diff)
parent7c730ccdc1188b97f5c8cb690906242c7ed75c22 (diff)
downloadlinux-3.10-d00ab2fdd4dc4361c97777bc1fef7234329d4659.tar.gz
linux-3.10-d00ab2fdd4dc4361c97777bc1fef7234329d4659.tar.bz2
linux-3.10-d00ab2fdd4dc4361c97777bc1fef7234329d4659.zip
Merge branch 'linus' into core/futexes
Diffstat (limited to 'drivers/scsi/osst.c')
-rw-r--r--drivers/scsi/osst.c96
1 files changed, 83 insertions, 13 deletions
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
index 0ea78d9a37d..acb835837ee 100644
--- a/drivers/scsi/osst.c
+++ b/drivers/scsi/osst.c
@@ -280,8 +280,8 @@ static int osst_chk_result(struct osst_tape * STp, struct osst_request * SRpnt)
static int notyetprinted = 1;
printk(KERN_WARNING
- "%s:W: Warning %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
- name, result, suggestion(result), driver_byte(result) & DRIVER_MASK,
+ "%s:W: Warning %x (driver bt 0x%x, host bt 0x%x).\n",
+ name, result, driver_byte(result),
host_byte(result));
if (notyetprinted) {
notyetprinted = 0;
@@ -317,18 +317,25 @@ static int osst_chk_result(struct osst_tape * STp, struct osst_request * SRpnt)
/* Wakeup from interrupt */
-static void osst_sleep_done(void *data, char *sense, int result, int resid)
+static void osst_end_async(struct request *req, int update)
{
- struct osst_request *SRpnt = data;
+ struct osst_request *SRpnt = req->end_io_data;
struct osst_tape *STp = SRpnt->stp;
+ struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data;
- memcpy(SRpnt->sense, sense, SCSI_SENSE_BUFFERSIZE);
- STp->buffer->cmdstat.midlevel_result = SRpnt->result = result;
+ STp->buffer->cmdstat.midlevel_result = SRpnt->result = req->errors;
#if DEBUG
STp->write_pending = 0;
#endif
if (SRpnt->waiting)
complete(SRpnt->waiting);
+
+ if (SRpnt->bio) {
+ kfree(mdata->pages);
+ blk_rq_unmap_user(SRpnt->bio);
+ }
+
+ __blk_put_request(req->q, req);
}
/* osst_request memory management */
@@ -342,6 +349,74 @@ static void osst_release_request(struct osst_request *streq)
kfree(streq);
}
+static int osst_execute(struct osst_request *SRpnt, const unsigned char *cmd,
+ int cmd_len, int data_direction, void *buffer, unsigned bufflen,
+ int use_sg, int timeout, int retries)
+{
+ struct request *req;
+ struct page **pages = NULL;
+ 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;
+
+ SRpnt->bio = NULL;
+
+ if (use_sg) {
+ struct scatterlist *sg, *sgl = (struct scatterlist *)buffer;
+ int i;
+
+ pages = kzalloc(use_sg * sizeof(struct page *), GFP_KERNEL);
+ if (!pages)
+ goto free_req;
+
+ for_each_sg(sgl, sg, use_sg, i)
+ pages[i] = sg_page(sg);
+
+ mdata->null_mapped = 1;
+
+ mdata->page_order = get_order(sgl[0].length);
+ mdata->nr_entries =
+ DIV_ROUND_UP(bufflen, PAGE_SIZE << mdata->page_order);
+ mdata->offset = 0;
+
+ err = blk_rq_map_user(req->q, req, mdata, NULL, bufflen, GFP_KERNEL);
+ if (err) {
+ kfree(pages);
+ goto free_req;
+ }
+ SRpnt->bio = req->bio;
+ mdata->pages = pages;
+
+ } else if (bufflen) {
+ err = blk_rq_map_kern(req->q, req, buffer, bufflen, GFP_KERNEL);
+ if (err)
+ goto free_req;
+ }
+
+ req->cmd_len = cmd_len;
+ memset(req->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after 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, osst_end_async);
+ return 0;
+free_req:
+ blk_put_request(req);
+ return DRIVER_ERROR << 24;
+}
+
/* Do the scsi command. Waits until command performed if do_wait is true.
Otherwise osst_write_behind_check() is used to check that the command
has finished. */
@@ -403,8 +478,8 @@ static struct osst_request * osst_do_scsi(struct osst_request *SRpnt, struct oss
STp->buffer->cmdstat.have_sense = 0;
STp->buffer->syscall_result = 0;
- if (scsi_execute_async(STp->device, cmd, COMMAND_SIZE(cmd[0]), direction, bp, bytes,
- use_sg, timeout, retries, SRpnt, osst_sleep_done, GFP_KERNEL))
+ if (osst_execute(SRpnt, cmd, COMMAND_SIZE(cmd[0]), direction, bp, bytes,
+ use_sg, timeout, retries))
/* could not allocate the buffer or request was too large */
(STp->buffer)->syscall_result = (-EBUSY);
else if (do_wait) {
@@ -5286,11 +5361,6 @@ static int enlarge_buffer(struct osst_buffer *STbuffer, int need_dma)
struct page *page = alloc_pages(priority, (OS_FRAME_SIZE - got <= PAGE_SIZE) ? 0 : order);
STbuffer->sg[segs].offset = 0;
if (page == NULL) {
- if (OS_FRAME_SIZE - got <= (max_segs - segs) * b_size / 2 && order) {
- b_size /= 2; /* Large enough for the rest of the buffers */
- order--;
- continue;
- }
printk(KERN_WARNING "osst :W: Failed to enlarge buffer to %d bytes.\n",
OS_FRAME_SIZE);
#if DEBUG