diff options
Diffstat (limited to 'drivers/scsi/osst.c')
-rw-r--r-- | drivers/scsi/osst.c | 96 |
1 files changed, 83 insertions, 13 deletions
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 0ea78d9a37db..acb835837eec 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) | |||
280 | static int notyetprinted = 1; | 280 | static int notyetprinted = 1; |
281 | 281 | ||
282 | printk(KERN_WARNING | 282 | printk(KERN_WARNING |
283 | "%s:W: Warning %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n", | 283 | "%s:W: Warning %x (driver bt 0x%x, host bt 0x%x).\n", |
284 | name, result, suggestion(result), driver_byte(result) & DRIVER_MASK, | 284 | name, result, driver_byte(result), |
285 | host_byte(result)); | 285 | host_byte(result)); |
286 | if (notyetprinted) { | 286 | if (notyetprinted) { |
287 | notyetprinted = 0; | 287 | notyetprinted = 0; |
@@ -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) { |
@@ -5286,11 +5361,6 @@ static int enlarge_buffer(struct osst_buffer *STbuffer, int need_dma) | |||
5286 | struct page *page = alloc_pages(priority, (OS_FRAME_SIZE - got <= PAGE_SIZE) ? 0 : order); | 5361 | struct page *page = alloc_pages(priority, (OS_FRAME_SIZE - got <= PAGE_SIZE) ? 0 : order); |
5287 | STbuffer->sg[segs].offset = 0; | 5362 | STbuffer->sg[segs].offset = 0; |
5288 | if (page == NULL) { | 5363 | if (page == NULL) { |
5289 | if (OS_FRAME_SIZE - got <= (max_segs - segs) * b_size / 2 && order) { | ||
5290 | b_size /= 2; /* Large enough for the rest of the buffers */ | ||
5291 | order--; | ||
5292 | continue; | ||
5293 | } | ||
5294 | printk(KERN_WARNING "osst :W: Failed to enlarge buffer to %d bytes.\n", | 5364 | printk(KERN_WARNING "osst :W: Failed to enlarge buffer to %d bytes.\n", |
5295 | OS_FRAME_SIZE); | 5365 | OS_FRAME_SIZE); |
5296 | #if DEBUG | 5366 | #if DEBUG |