aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/st.c76
-rw-r--r--drivers/scsi/st.h1
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);
191static void move_buffer_data(struct st_buffer *, int); 191static void move_buffer_data(struct st_buffer *, int);
192static void buf_to_sg(struct st_buffer *, unsigned int); 192static void buf_to_sg(struct st_buffer *, unsigned int);
193 193
194static int sgl_map_user_pages(struct scatterlist *, const unsigned int, 194static int sgl_map_user_pages(struct st_buffer *, const unsigned int,
195 unsigned long, size_t, int); 195 unsigned long, size_t, int);
196static int sgl_unmap_user_pages(struct scatterlist *, const unsigned int, int); 196static int sgl_unmap_user_pages(struct st_buffer *, const unsigned int, int);
197 197
198static int st_probe(struct device *); 198static int st_probe(struct device *);
199static int st_remove(struct device *); 199static 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 */
440static 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
454static struct st_request *st_allocate_request(struct scsi_tape *stp) 438static 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. */
4650static int sgl_map_user_pages(struct scatterlist *sgl, const unsigned int max_pages, 4629static 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... */
4729static int sgl_unmap_user_pages(struct scatterlist *sgl, const unsigned int nr_pages, 4697static 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 */