diff options
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/osst.c | 87 | ||||
-rw-r--r-- | drivers/scsi/osst.h | 2 |
2 files changed, 83 insertions, 6 deletions
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 13f908cb0674..acb835837eec 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c | |||
@@ -317,18 +317,25 @@ static int osst_chk_result(struct osst_tape * STp, struct osst_request * SRpnt) | |||
317 | 317 | ||
318 | 318 | ||
319 | /* Wakeup from interrupt */ | 319 | /* Wakeup from interrupt */ |
320 | static void osst_sleep_done(void *data, char *sense, int result, int resid) | 320 | static void osst_end_async(struct request *req, int update) |
321 | { | 321 | { |
322 | struct osst_request *SRpnt = data; | 322 | struct osst_request *SRpnt = req->end_io_data; |
323 | struct osst_tape *STp = SRpnt->stp; | 323 | struct osst_tape *STp = SRpnt->stp; |
324 | struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data; | ||
324 | 325 | ||
325 | memcpy(SRpnt->sense, sense, SCSI_SENSE_BUFFERSIZE); | 326 | STp->buffer->cmdstat.midlevel_result = SRpnt->result = req->errors; |
326 | STp->buffer->cmdstat.midlevel_result = SRpnt->result = result; | ||
327 | #if DEBUG | 327 | #if DEBUG |
328 | STp->write_pending = 0; | 328 | STp->write_pending = 0; |
329 | #endif | 329 | #endif |
330 | if (SRpnt->waiting) | 330 | if (SRpnt->waiting) |
331 | complete(SRpnt->waiting); | 331 | complete(SRpnt->waiting); |
332 | |||
333 | if (SRpnt->bio) { | ||
334 | kfree(mdata->pages); | ||
335 | blk_rq_unmap_user(SRpnt->bio); | ||
336 | } | ||
337 | |||
338 | __blk_put_request(req->q, req); | ||
332 | } | 339 | } |
333 | 340 | ||
334 | /* osst_request memory management */ | 341 | /* osst_request memory management */ |
@@ -342,6 +349,74 @@ static void osst_release_request(struct osst_request *streq) | |||
342 | kfree(streq); | 349 | kfree(streq); |
343 | } | 350 | } |
344 | 351 | ||
352 | static int osst_execute(struct osst_request *SRpnt, const unsigned char *cmd, | ||
353 | int cmd_len, int data_direction, void *buffer, unsigned bufflen, | ||
354 | int use_sg, int timeout, int retries) | ||
355 | { | ||
356 | struct request *req; | ||
357 | struct page **pages = NULL; | ||
358 | struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data; | ||
359 | |||
360 | int err = 0; | ||
361 | int write = (data_direction == DMA_TO_DEVICE); | ||
362 | |||
363 | req = blk_get_request(SRpnt->stp->device->request_queue, write, GFP_KERNEL); | ||
364 | if (!req) | ||
365 | return DRIVER_ERROR << 24; | ||
366 | |||
367 | req->cmd_type = REQ_TYPE_BLOCK_PC; | ||
368 | req->cmd_flags |= REQ_QUIET; | ||
369 | |||
370 | SRpnt->bio = NULL; | ||
371 | |||
372 | if (use_sg) { | ||
373 | struct scatterlist *sg, *sgl = (struct scatterlist *)buffer; | ||
374 | int i; | ||
375 | |||
376 | pages = kzalloc(use_sg * sizeof(struct page *), GFP_KERNEL); | ||
377 | if (!pages) | ||
378 | goto free_req; | ||
379 | |||
380 | for_each_sg(sgl, sg, use_sg, i) | ||
381 | pages[i] = sg_page(sg); | ||
382 | |||
383 | mdata->null_mapped = 1; | ||
384 | |||
385 | mdata->page_order = get_order(sgl[0].length); | ||
386 | mdata->nr_entries = | ||
387 | DIV_ROUND_UP(bufflen, PAGE_SIZE << mdata->page_order); | ||
388 | mdata->offset = 0; | ||
389 | |||
390 | err = blk_rq_map_user(req->q, req, mdata, NULL, bufflen, GFP_KERNEL); | ||
391 | if (err) { | ||
392 | kfree(pages); | ||
393 | goto free_req; | ||
394 | } | ||
395 | SRpnt->bio = req->bio; | ||
396 | mdata->pages = pages; | ||
397 | |||
398 | } else if (bufflen) { | ||
399 | err = blk_rq_map_kern(req->q, req, buffer, bufflen, GFP_KERNEL); | ||
400 | if (err) | ||
401 | goto free_req; | ||
402 | } | ||
403 | |||
404 | req->cmd_len = cmd_len; | ||
405 | memset(req->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */ | ||
406 | memcpy(req->cmd, cmd, req->cmd_len); | ||
407 | req->sense = SRpnt->sense; | ||
408 | req->sense_len = 0; | ||
409 | req->timeout = timeout; | ||
410 | req->retries = retries; | ||
411 | req->end_io_data = SRpnt; | ||
412 | |||
413 | blk_execute_rq_nowait(req->q, NULL, req, 1, osst_end_async); | ||
414 | return 0; | ||
415 | free_req: | ||
416 | blk_put_request(req); | ||
417 | return DRIVER_ERROR << 24; | ||
418 | } | ||
419 | |||
345 | /* Do the scsi command. Waits until command performed if do_wait is true. | 420 | /* Do the scsi command. Waits until command performed if do_wait is true. |
346 | Otherwise osst_write_behind_check() is used to check that the command | 421 | Otherwise osst_write_behind_check() is used to check that the command |
347 | has finished. */ | 422 | has finished. */ |
@@ -403,8 +478,8 @@ static struct osst_request * osst_do_scsi(struct osst_request *SRpnt, struct oss | |||
403 | STp->buffer->cmdstat.have_sense = 0; | 478 | STp->buffer->cmdstat.have_sense = 0; |
404 | STp->buffer->syscall_result = 0; | 479 | STp->buffer->syscall_result = 0; |
405 | 480 | ||
406 | if (scsi_execute_async(STp->device, cmd, COMMAND_SIZE(cmd[0]), direction, bp, bytes, | 481 | if (osst_execute(SRpnt, cmd, COMMAND_SIZE(cmd[0]), direction, bp, bytes, |
407 | use_sg, timeout, retries, SRpnt, osst_sleep_done, GFP_KERNEL)) | 482 | use_sg, timeout, retries)) |
408 | /* could not allocate the buffer or request was too large */ | 483 | /* could not allocate the buffer or request was too large */ |
409 | (STp->buffer)->syscall_result = (-EBUSY); | 484 | (STp->buffer)->syscall_result = (-EBUSY); |
410 | else if (do_wait) { | 485 | else if (do_wait) { |
diff --git a/drivers/scsi/osst.h b/drivers/scsi/osst.h index 5aa22740b5df..11d26c57f3f8 100644 --- a/drivers/scsi/osst.h +++ b/drivers/scsi/osst.h | |||
@@ -520,6 +520,7 @@ struct osst_buffer { | |||
520 | int syscall_result; | 520 | int syscall_result; |
521 | struct osst_request *last_SRpnt; | 521 | struct osst_request *last_SRpnt; |
522 | struct st_cmdstatus cmdstat; | 522 | struct st_cmdstatus cmdstat; |
523 | struct rq_map_data map_data; | ||
523 | unsigned char *b_data; | 524 | unsigned char *b_data; |
524 | os_aux_t *aux; /* onstream AUX structure at end of each block */ | 525 | os_aux_t *aux; /* onstream AUX structure at end of each block */ |
525 | unsigned short use_sg; /* zero or number of s/g segments for this adapter */ | 526 | unsigned short use_sg; /* zero or number of s/g segments for this adapter */ |
@@ -634,6 +635,7 @@ struct osst_request { | |||
634 | int result; | 635 | int result; |
635 | struct osst_tape *stp; | 636 | struct osst_tape *stp; |
636 | struct completion *waiting; | 637 | struct completion *waiting; |
638 | struct bio *bio; | ||
637 | }; | 639 | }; |
638 | 640 | ||
639 | /* Values of write_type */ | 641 | /* Values of write_type */ |