aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/st.c78
-rw-r--r--drivers/scsi/st.h7
2 files changed, 43 insertions, 42 deletions
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index ce1fd3ab243b..1cfd217f8904 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -3753,8 +3753,9 @@ static struct st_buffer *
3753 else 3753 else
3754 priority = GFP_KERNEL; 3754 priority = GFP_KERNEL;
3755 3755
3756 i = sizeof(struct st_buffer) + (max_sg - 1) * sizeof(struct scatterlist) + 3756 i = sizeof(struct st_buffer) +
3757 max_sg * sizeof(struct st_buf_fragment); 3757 (max_sg - 1) * sizeof(struct scatterlist);
3758
3758 tb = kzalloc(i, priority); 3759 tb = kzalloc(i, priority);
3759 if (!tb) { 3760 if (!tb) {
3760 printk(KERN_NOTICE "st: Can't allocate new tape buffer.\n"); 3761 printk(KERN_NOTICE "st: Can't allocate new tape buffer.\n");
@@ -3762,7 +3763,6 @@ static struct st_buffer *
3762 } 3763 }
3763 tb->frp_segs = tb->orig_frp_segs = 0; 3764 tb->frp_segs = tb->orig_frp_segs = 0;
3764 tb->use_sg = max_sg; 3765 tb->use_sg = max_sg;
3765 tb->frp = (struct st_buf_fragment *)(&(tb->sg[0]) + max_sg);
3766 3766
3767 tb->dma = need_dma; 3767 tb->dma = need_dma;
3768 tb->buffer_size = got; 3768 tb->buffer_size = got;
@@ -3799,9 +3799,12 @@ static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dm
3799 if (need_dma) 3799 if (need_dma)
3800 priority |= GFP_DMA; 3800 priority |= GFP_DMA;
3801 3801
3802 if (STbuffer->cleared)
3803 priority |= __GFP_ZERO;
3804
3802 if (STbuffer->frp_segs) { 3805 if (STbuffer->frp_segs) {
3803 b_size = STbuffer->frp[0].length; 3806 order = STbuffer->map_data.page_order;
3804 order = get_order(b_size); 3807 b_size = PAGE_SIZE << order;
3805 } else { 3808 } else {
3806 for (b_size = PAGE_SIZE, order = 0; 3809 for (b_size = PAGE_SIZE, order = 0;
3807 order <= 6 && b_size < new_size; order++, b_size *= 2) 3810 order <= 6 && b_size < new_size; order++, b_size *= 2)
@@ -3810,22 +3813,22 @@ static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dm
3810 3813
3811 for (segs = STbuffer->frp_segs, got = STbuffer->buffer_size; 3814 for (segs = STbuffer->frp_segs, got = STbuffer->buffer_size;
3812 segs < max_segs && got < new_size;) { 3815 segs < max_segs && got < new_size;) {
3813 STbuffer->frp[segs].page = alloc_pages(priority, order); 3816 struct page *page;
3814 if (STbuffer->frp[segs].page == NULL) { 3817
3818 page = alloc_pages(priority, order);
3819 if (!page) {
3815 DEB(STbuffer->buffer_size = got); 3820 DEB(STbuffer->buffer_size = got);
3816 normalize_buffer(STbuffer); 3821 normalize_buffer(STbuffer);
3817 return 0; 3822 return 0;
3818 } 3823 }
3819 STbuffer->frp[segs].length = b_size; 3824
3820 STbuffer->frp_segs += 1; 3825 STbuffer->frp_segs += 1;
3821 got += b_size; 3826 got += b_size;
3822 STbuffer->buffer_size = got; 3827 STbuffer->buffer_size = got;
3823 if (STbuffer->cleared) 3828 STbuffer->reserved_pages[segs] = page;
3824 memset(page_address(STbuffer->frp[segs].page), 0, b_size);
3825 STbuffer->reserved_pages[segs] = STbuffer->frp[segs].page;
3826 segs++; 3829 segs++;
3827 } 3830 }
3828 STbuffer->b_data = page_address(STbuffer->frp[0].page); 3831 STbuffer->b_data = page_address(STbuffer->reserved_pages[0]);
3829 STbuffer->map_data.page_order = order; 3832 STbuffer->map_data.page_order = order;
3830 3833
3831 return 1; 3834 return 1;
@@ -3838,7 +3841,8 @@ static void clear_buffer(struct st_buffer * st_bp)
3838 int i; 3841 int i;
3839 3842
3840 for (i=0; i < st_bp->frp_segs; i++) 3843 for (i=0; i < st_bp->frp_segs; i++)
3841 memset(page_address(st_bp->frp[i].page), 0, st_bp->frp[i].length); 3844 memset(page_address(st_bp->reserved_pages[i]), 0,
3845 PAGE_SIZE << st_bp->map_data.page_order);
3842 st_bp->cleared = 1; 3846 st_bp->cleared = 1;
3843} 3847}
3844 3848
@@ -3846,12 +3850,11 @@ static void clear_buffer(struct st_buffer * st_bp)
3846/* Release the extra buffer */ 3850/* Release the extra buffer */
3847static void normalize_buffer(struct st_buffer * STbuffer) 3851static void normalize_buffer(struct st_buffer * STbuffer)
3848{ 3852{
3849 int i, order; 3853 int i, order = STbuffer->map_data.page_order;
3850 3854
3851 for (i = STbuffer->orig_frp_segs; i < STbuffer->frp_segs; i++) { 3855 for (i = STbuffer->orig_frp_segs; i < STbuffer->frp_segs; i++) {
3852 order = get_order(STbuffer->frp[i].length); 3856 __free_pages(STbuffer->reserved_pages[i], order);
3853 __free_pages(STbuffer->frp[i].page, order); 3857 STbuffer->buffer_size -= (PAGE_SIZE << order);
3854 STbuffer->buffer_size -= STbuffer->frp[i].length;
3855 } 3858 }
3856 STbuffer->frp_segs = STbuffer->orig_frp_segs; 3859 STbuffer->frp_segs = STbuffer->orig_frp_segs;
3857 STbuffer->frp_sg_current = 0; 3860 STbuffer->frp_sg_current = 0;
@@ -3866,18 +3869,19 @@ static void normalize_buffer(struct st_buffer * STbuffer)
3866static int append_to_buffer(const char __user *ubp, struct st_buffer * st_bp, int do_count) 3869static int append_to_buffer(const char __user *ubp, struct st_buffer * st_bp, int do_count)
3867{ 3870{
3868 int i, cnt, res, offset; 3871 int i, cnt, res, offset;
3872 int length = PAGE_SIZE << st_bp->map_data.page_order;
3869 3873
3870 for (i = 0, offset = st_bp->buffer_bytes; 3874 for (i = 0, offset = st_bp->buffer_bytes;
3871 i < st_bp->frp_segs && offset >= st_bp->frp[i].length; i++) 3875 i < st_bp->frp_segs && offset >= length; i++)
3872 offset -= st_bp->frp[i].length; 3876 offset -= length;
3873 if (i == st_bp->frp_segs) { /* Should never happen */ 3877 if (i == st_bp->frp_segs) { /* Should never happen */
3874 printk(KERN_WARNING "st: append_to_buffer offset overflow.\n"); 3878 printk(KERN_WARNING "st: append_to_buffer offset overflow.\n");
3875 return (-EIO); 3879 return (-EIO);
3876 } 3880 }
3877 for (; i < st_bp->frp_segs && do_count > 0; i++) { 3881 for (; i < st_bp->frp_segs && do_count > 0; i++) {
3878 cnt = st_bp->frp[i].length - offset < do_count ? 3882 struct page *page = st_bp->reserved_pages[i];
3879 st_bp->frp[i].length - offset : do_count; 3883 cnt = length - offset < do_count ? length - offset : do_count;
3880 res = copy_from_user(page_address(st_bp->frp[i].page) + offset, ubp, cnt); 3884 res = copy_from_user(page_address(page) + offset, ubp, cnt);
3881 if (res) 3885 if (res)
3882 return (-EFAULT); 3886 return (-EFAULT);
3883 do_count -= cnt; 3887 do_count -= cnt;
@@ -3897,18 +3901,19 @@ static int append_to_buffer(const char __user *ubp, struct st_buffer * st_bp, in
3897static int from_buffer(struct st_buffer * st_bp, char __user *ubp, int do_count) 3901static int from_buffer(struct st_buffer * st_bp, char __user *ubp, int do_count)
3898{ 3902{
3899 int i, cnt, res, offset; 3903 int i, cnt, res, offset;
3904 int length = PAGE_SIZE << st_bp->map_data.page_order;
3900 3905
3901 for (i = 0, offset = st_bp->read_pointer; 3906 for (i = 0, offset = st_bp->read_pointer;
3902 i < st_bp->frp_segs && offset >= st_bp->frp[i].length; i++) 3907 i < st_bp->frp_segs && offset >= length; i++)
3903 offset -= st_bp->frp[i].length; 3908 offset -= length;
3904 if (i == st_bp->frp_segs) { /* Should never happen */ 3909 if (i == st_bp->frp_segs) { /* Should never happen */
3905 printk(KERN_WARNING "st: from_buffer offset overflow.\n"); 3910 printk(KERN_WARNING "st: from_buffer offset overflow.\n");
3906 return (-EIO); 3911 return (-EIO);
3907 } 3912 }
3908 for (; i < st_bp->frp_segs && do_count > 0; i++) { 3913 for (; i < st_bp->frp_segs && do_count > 0; i++) {
3909 cnt = st_bp->frp[i].length - offset < do_count ? 3914 struct page *page = st_bp->reserved_pages[i];
3910 st_bp->frp[i].length - offset : do_count; 3915 cnt = length - offset < do_count ? length - offset : do_count;
3911 res = copy_to_user(ubp, page_address(st_bp->frp[i].page) + offset, cnt); 3916 res = copy_to_user(ubp, page_address(page) + offset, cnt);
3912 if (res) 3917 if (res)
3913 return (-EFAULT); 3918 return (-EFAULT);
3914 do_count -= cnt; 3919 do_count -= cnt;
@@ -3929,6 +3934,7 @@ static void move_buffer_data(struct st_buffer * st_bp, int offset)
3929{ 3934{
3930 int src_seg, dst_seg, src_offset = 0, dst_offset; 3935 int src_seg, dst_seg, src_offset = 0, dst_offset;
3931 int count, total; 3936 int count, total;
3937 int length = PAGE_SIZE << st_bp->map_data.page_order;
3932 3938
3933 if (offset == 0) 3939 if (offset == 0)
3934 return; 3940 return;
@@ -3936,24 +3942,26 @@ static void move_buffer_data(struct st_buffer * st_bp, int offset)
3936 total=st_bp->buffer_bytes - offset; 3942 total=st_bp->buffer_bytes - offset;
3937 for (src_seg=0; src_seg < st_bp->frp_segs; src_seg++) { 3943 for (src_seg=0; src_seg < st_bp->frp_segs; src_seg++) {
3938 src_offset = offset; 3944 src_offset = offset;
3939 if (src_offset < st_bp->frp[src_seg].length) 3945 if (src_offset < length)
3940 break; 3946 break;
3941 offset -= st_bp->frp[src_seg].length; 3947 offset -= length;
3942 } 3948 }
3943 3949
3944 st_bp->buffer_bytes = st_bp->read_pointer = total; 3950 st_bp->buffer_bytes = st_bp->read_pointer = total;
3945 for (dst_seg=dst_offset=0; total > 0; ) { 3951 for (dst_seg=dst_offset=0; total > 0; ) {
3946 count = min(st_bp->frp[dst_seg].length - dst_offset, 3952 struct page *dpage = st_bp->reserved_pages[dst_seg];
3947 st_bp->frp[src_seg].length - src_offset); 3953 struct page *spage = st_bp->reserved_pages[src_seg];
3948 memmove(page_address(st_bp->frp[dst_seg].page) + dst_offset, 3954
3949 page_address(st_bp->frp[src_seg].page) + src_offset, count); 3955 count = min(length - dst_offset, length - src_offset);
3956 memmove(page_address(dpage) + dst_offset,
3957 page_address(spage) + src_offset, count);
3950 src_offset += count; 3958 src_offset += count;
3951 if (src_offset >= st_bp->frp[src_seg].length) { 3959 if (src_offset >= length) {
3952 src_seg++; 3960 src_seg++;
3953 src_offset = 0; 3961 src_offset = 0;
3954 } 3962 }
3955 dst_offset += count; 3963 dst_offset += count;
3956 if (dst_offset >= st_bp->frp[dst_seg].length) { 3964 if (dst_offset >= length) {
3957 dst_seg++; 3965 dst_seg++;
3958 dst_offset = 0; 3966 dst_offset = 0;
3959 } 3967 }
diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h
index d80926f9c6e3..cc46f18762b7 100644
--- a/drivers/scsi/st.h
+++ b/drivers/scsi/st.h
@@ -54,16 +54,9 @@ struct st_buffer {
54 unsigned short orig_frp_segs; /* number of segments allocated at first try */ 54 unsigned short orig_frp_segs; /* number of segments allocated at first try */
55 unsigned short frp_segs; /* number of buffer segments */ 55 unsigned short frp_segs; /* number of buffer segments */
56 unsigned int frp_sg_current; /* driver buffer length currently in s/g list */ 56 unsigned int frp_sg_current; /* driver buffer length currently in s/g list */
57 struct st_buf_fragment *frp; /* the allocated buffer fragment list */
58 struct scatterlist sg[1]; /* MUST BE last item */ 57 struct scatterlist sg[1]; /* MUST BE last item */
59}; 58};
60 59
61/* The tape buffer fragment descriptor */
62struct st_buf_fragment {
63 struct page *page;
64 unsigned int length;
65};
66
67/* The tape mode definition */ 60/* The tape mode definition */
68struct st_modedef { 61struct st_modedef {
69 unsigned char defined; 62 unsigned char defined;