diff options
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/st.c | 76 | ||||
-rw-r--r-- | drivers/scsi/st.h | 1 |
2 files changed, 24 insertions, 53 deletions
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 390689d5fdf3..fec5568c711a 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c | |||
@@ -191,9 +191,9 @@ static int from_buffer(struct st_buffer *, char __user *, int); | |||
191 | static void move_buffer_data(struct st_buffer *, int); | 191 | static void move_buffer_data(struct st_buffer *, int); |
192 | static void buf_to_sg(struct st_buffer *, unsigned int); | 192 | static void buf_to_sg(struct st_buffer *, unsigned int); |
193 | 193 | ||
194 | static int sgl_map_user_pages(struct scatterlist *, const unsigned int, | 194 | static int sgl_map_user_pages(struct st_buffer *, const unsigned int, |
195 | unsigned long, size_t, int); | 195 | unsigned long, size_t, int); |
196 | static int sgl_unmap_user_pages(struct scatterlist *, const unsigned int, int); | 196 | static int sgl_unmap_user_pages(struct st_buffer *, const unsigned int, int); |
197 | 197 | ||
198 | static int st_probe(struct device *); | 198 | static int st_probe(struct device *); |
199 | static int st_remove(struct device *); | 199 | static int st_remove(struct device *); |
@@ -435,22 +435,6 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt) | |||
435 | return (-EIO); | 435 | return (-EIO); |
436 | } | 436 | } |
437 | 437 | ||
438 | |||
439 | /* Wakeup from interrupt */ | ||
440 | static void st_sleep_done(void *data, char *sense, int result, int resid) | ||
441 | { | ||
442 | struct st_request *SRpnt = data; | ||
443 | struct scsi_tape *STp = SRpnt->stp; | ||
444 | |||
445 | memcpy(SRpnt->sense, sense, SCSI_SENSE_BUFFERSIZE); | ||
446 | (STp->buffer)->cmdstat.midlevel_result = SRpnt->result = result; | ||
447 | (STp->buffer)->cmdstat.residual = resid; | ||
448 | DEB( STp->write_pending = 0; ) | ||
449 | |||
450 | if (SRpnt->waiting) | ||
451 | complete(SRpnt->waiting); | ||
452 | } | ||
453 | |||
454 | static struct st_request *st_allocate_request(struct scsi_tape *stp) | 438 | static struct st_request *st_allocate_request(struct scsi_tape *stp) |
455 | { | 439 | { |
456 | struct st_request *streq; | 440 | struct st_request *streq; |
@@ -566,7 +550,10 @@ st_do_scsi(struct st_request * SRpnt, struct scsi_tape * STp, unsigned char *cmd | |||
566 | init_completion(waiting); | 550 | init_completion(waiting); |
567 | SRpnt->waiting = waiting; | 551 | SRpnt->waiting = waiting; |
568 | 552 | ||
569 | if (!STp->buffer->do_dio) { | 553 | if (STp->buffer->do_dio) { |
554 | mdata->nr_entries = STp->buffer->sg_segs; | ||
555 | mdata->pages = STp->buffer->mapped_pages; | ||
556 | } else { | ||
570 | buf_to_sg(STp->buffer, bytes); | 557 | buf_to_sg(STp->buffer, bytes); |
571 | 558 | ||
572 | mdata->nr_entries = | 559 | mdata->nr_entries = |
@@ -579,16 +566,8 @@ st_do_scsi(struct st_request * SRpnt, struct scsi_tape * STp, unsigned char *cmd | |||
579 | STp->buffer->cmdstat.have_sense = 0; | 566 | STp->buffer->cmdstat.have_sense = 0; |
580 | STp->buffer->syscall_result = 0; | 567 | STp->buffer->syscall_result = 0; |
581 | 568 | ||
582 | if (STp->buffer->do_dio) | 569 | ret = st_scsi_execute(SRpnt, cmd, direction, NULL, bytes, timeout, |
583 | ret = scsi_execute_async(STp->device, cmd, COMMAND_SIZE(cmd[0]), | 570 | retries); |
584 | direction, &((STp->buffer)->sg[0]), | ||
585 | bytes, (STp->buffer)->sg_segs, timeout, | ||
586 | retries, SRpnt, st_sleep_done, | ||
587 | GFP_KERNEL); | ||
588 | else | ||
589 | ret = st_scsi_execute(SRpnt, cmd, direction, NULL, bytes, | ||
590 | timeout, retries); | ||
591 | |||
592 | if (ret) { | 571 | if (ret) { |
593 | /* could not allocate the buffer or request was too large */ | 572 | /* could not allocate the buffer or request was too large */ |
594 | (STp->buffer)->syscall_result = (-EBUSY); | 573 | (STp->buffer)->syscall_result = (-EBUSY); |
@@ -1540,8 +1519,8 @@ static int setup_buffering(struct scsi_tape *STp, const char __user *buf, | |||
1540 | 1519 | ||
1541 | if (i && ((unsigned long)buf & queue_dma_alignment( | 1520 | if (i && ((unsigned long)buf & queue_dma_alignment( |
1542 | STp->device->request_queue)) == 0) { | 1521 | STp->device->request_queue)) == 0) { |
1543 | i = sgl_map_user_pages(&(STbp->sg[0]), STbp->use_sg, | 1522 | i = sgl_map_user_pages(STbp, STbp->use_sg, (unsigned long)buf, |
1544 | (unsigned long)buf, count, (is_read ? READ : WRITE)); | 1523 | count, (is_read ? READ : WRITE)); |
1545 | if (i > 0) { | 1524 | if (i > 0) { |
1546 | STbp->do_dio = i; | 1525 | STbp->do_dio = i; |
1547 | STbp->buffer_bytes = 0; /* can be used as transfer counter */ | 1526 | STbp->buffer_bytes = 0; /* can be used as transfer counter */ |
@@ -1595,7 +1574,7 @@ static void release_buffering(struct scsi_tape *STp, int is_read) | |||
1595 | 1574 | ||
1596 | STbp = STp->buffer; | 1575 | STbp = STp->buffer; |
1597 | if (STbp->do_dio) { | 1576 | if (STbp->do_dio) { |
1598 | sgl_unmap_user_pages(&(STbp->sg[0]), STbp->do_dio, is_read); | 1577 | sgl_unmap_user_pages(STbp, STbp->do_dio, is_read); |
1599 | STbp->do_dio = 0; | 1578 | STbp->do_dio = 0; |
1600 | STbp->sg_segs = 0; | 1579 | STbp->sg_segs = 0; |
1601 | } | 1580 | } |
@@ -4647,14 +4626,16 @@ out: | |||
4647 | } | 4626 | } |
4648 | 4627 | ||
4649 | /* The following functions may be useful for a larger audience. */ | 4628 | /* The following functions may be useful for a larger audience. */ |
4650 | static int sgl_map_user_pages(struct scatterlist *sgl, const unsigned int max_pages, | 4629 | static int sgl_map_user_pages(struct st_buffer *STbp, |
4651 | unsigned long uaddr, size_t count, int rw) | 4630 | const unsigned int max_pages, unsigned long uaddr, |
4631 | size_t count, int rw) | ||
4652 | { | 4632 | { |
4653 | unsigned long end = (uaddr + count + PAGE_SIZE - 1) >> PAGE_SHIFT; | 4633 | unsigned long end = (uaddr + count + PAGE_SIZE - 1) >> PAGE_SHIFT; |
4654 | unsigned long start = uaddr >> PAGE_SHIFT; | 4634 | unsigned long start = uaddr >> PAGE_SHIFT; |
4655 | const int nr_pages = end - start; | 4635 | const int nr_pages = end - start; |
4656 | int res, i, j; | 4636 | int res, i, j; |
4657 | struct page **pages; | 4637 | struct page **pages; |
4638 | struct rq_map_data *mdata = &STbp->map_data; | ||
4658 | 4639 | ||
4659 | /* User attempted Overflow! */ | 4640 | /* User attempted Overflow! */ |
4660 | if ((uaddr + count) < uaddr) | 4641 | if ((uaddr + count) < uaddr) |
@@ -4696,24 +4677,11 @@ static int sgl_map_user_pages(struct scatterlist *sgl, const unsigned int max_pa | |||
4696 | flush_dcache_page(pages[i]); | 4677 | flush_dcache_page(pages[i]); |
4697 | } | 4678 | } |
4698 | 4679 | ||
4699 | /* Populate the scatter/gather list */ | 4680 | mdata->offset = uaddr & ~PAGE_MASK; |
4700 | sg_set_page(&sgl[0], pages[0], 0, uaddr & ~PAGE_MASK); | 4681 | mdata->page_order = 0; |
4701 | if (nr_pages > 1) { | 4682 | STbp->mapped_pages = pages; |
4702 | sgl[0].length = PAGE_SIZE - sgl[0].offset; | ||
4703 | count -= sgl[0].length; | ||
4704 | for (i=1; i < nr_pages ; i++) { | ||
4705 | sg_set_page(&sgl[i], pages[i], | ||
4706 | count < PAGE_SIZE ? count : PAGE_SIZE, 0);; | ||
4707 | count -= PAGE_SIZE; | ||
4708 | } | ||
4709 | } | ||
4710 | else { | ||
4711 | sgl[0].length = count; | ||
4712 | } | ||
4713 | 4683 | ||
4714 | kfree(pages); | ||
4715 | return nr_pages; | 4684 | return nr_pages; |
4716 | |||
4717 | out_unmap: | 4685 | out_unmap: |
4718 | if (res > 0) { | 4686 | if (res > 0) { |
4719 | for (j=0; j < res; j++) | 4687 | for (j=0; j < res; j++) |
@@ -4726,13 +4694,13 @@ static int sgl_map_user_pages(struct scatterlist *sgl, const unsigned int max_pa | |||
4726 | 4694 | ||
4727 | 4695 | ||
4728 | /* And unmap them... */ | 4696 | /* And unmap them... */ |
4729 | static int sgl_unmap_user_pages(struct scatterlist *sgl, const unsigned int nr_pages, | 4697 | static int sgl_unmap_user_pages(struct st_buffer *STbp, |
4730 | int dirtied) | 4698 | const unsigned int nr_pages, int dirtied) |
4731 | { | 4699 | { |
4732 | int i; | 4700 | int i; |
4733 | 4701 | ||
4734 | for (i=0; i < nr_pages; i++) { | 4702 | for (i=0; i < nr_pages; i++) { |
4735 | struct page *page = sg_page(&sgl[i]); | 4703 | struct page *page = STbp->mapped_pages[i]; |
4736 | 4704 | ||
4737 | if (dirtied) | 4705 | if (dirtied) |
4738 | SetPageDirty(page); | 4706 | SetPageDirty(page); |
@@ -4741,6 +4709,8 @@ static int sgl_unmap_user_pages(struct scatterlist *sgl, const unsigned int nr_p | |||
4741 | */ | 4709 | */ |
4742 | page_cache_release(page); | 4710 | page_cache_release(page); |
4743 | } | 4711 | } |
4712 | kfree(STbp->mapped_pages); | ||
4713 | STbp->mapped_pages = NULL; | ||
4744 | 4714 | ||
4745 | return 0; | 4715 | return 0; |
4746 | } | 4716 | } |
diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h index 77302fa8608a..d80926f9c6e3 100644 --- a/drivers/scsi/st.h +++ b/drivers/scsi/st.h | |||
@@ -46,6 +46,7 @@ struct st_buffer { | |||
46 | struct st_request *last_SRpnt; | 46 | struct st_request *last_SRpnt; |
47 | struct st_cmdstatus cmdstat; | 47 | struct st_cmdstatus cmdstat; |
48 | struct page **reserved_pages; | 48 | struct page **reserved_pages; |
49 | struct page **mapped_pages; | ||
49 | struct rq_map_data map_data; | 50 | struct rq_map_data map_data; |
50 | unsigned char *b_data; | 51 | unsigned char *b_data; |
51 | unsigned short use_sg; /* zero or max number of s/g segments for this adapter */ | 52 | unsigned short use_sg; /* zero or max number of s/g segments for this adapter */ |