Commit e5fc70d5 authored by Ming Lei's avatar Ming Lei Committed by Greg Kroah-Hartman

USB: storage: use sg_miter_* APIs to access scsi buffer

We have sg_miter_* APIs for accessing scsi sg buffer, so
use them to make code clean and bug free.

Cc: Matthew Dharm <mdharm-usb@one-eyed-alien.net>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarMing Lei <ming.lei@canonical.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 0d6077f8
...@@ -135,69 +135,41 @@ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer, ...@@ -135,69 +135,41 @@ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
unsigned int buflen, struct scsi_cmnd *srb, struct scatterlist **sgptr, unsigned int buflen, struct scsi_cmnd *srb, struct scatterlist **sgptr,
unsigned int *offset, enum xfer_buf_dir dir) unsigned int *offset, enum xfer_buf_dir dir)
{ {
unsigned int cnt; unsigned int cnt = 0;
struct scatterlist *sg = *sgptr; struct scatterlist *sg = *sgptr;
struct sg_mapping_iter miter;
unsigned int nents = scsi_sg_count(srb);
/* We have to go through the list one entry if (sg)
* at a time. Each s-g entry contains some number of pages, and nents = sg_nents(sg);
* each page has to be kmap()'ed separately. If the page is already else
* in kernel-addressable memory then kmap() will return its address.
* If the page is not directly accessible -- such as a user buffer
* located in high memory -- then kmap() will map it to a temporary
* position in the kernel's virtual address space.
*/
if (!sg)
sg = scsi_sglist(srb); sg = scsi_sglist(srb);
/* This loop handles a single s-g list entry, which may sg_miter_start(&miter, sg, nents, dir == FROM_XFER_BUF ?
* include multiple pages. Find the initial page structure SG_MITER_FROM_SG: SG_MITER_TO_SG);
* and the starting offset within the page, and update
* the *offset and **sgptr values for the next loop.
*/
cnt = 0;
while (cnt < buflen && sg) {
struct page *page = sg_page(sg) +
((sg->offset + *offset) >> PAGE_SHIFT);
unsigned int poff = (sg->offset + *offset) & (PAGE_SIZE-1);
unsigned int sglen = sg->length - *offset;
if (sglen > buflen - cnt) {
/* Transfer ends within this s-g entry */
sglen = buflen - cnt;
*offset += sglen;
} else {
/* Transfer continues to next s-g entry */ if (!sg_miter_skip(&miter, *offset))
*offset = 0; return cnt;
sg = sg_next(sg);
} while (sg_miter_next(&miter) && cnt < buflen) {
unsigned int len = min(miter.length, buflen - cnt);
if (dir == FROM_XFER_BUF)
memcpy(buffer + cnt, miter.addr, len);
else
memcpy(miter.addr, buffer + cnt, len);
/* Transfer the data for all the pages in this if (*offset + len < miter.piter.sg->length) {
* s-g entry. For each page: call kmap(), do the *offset += len;
* transfer, and call kunmap() immediately after. */ *sgptr = miter.piter.sg;
while (sglen > 0) { } else {
unsigned int plen = min(sglen, (unsigned int) *offset = 0;
PAGE_SIZE - poff); *sgptr = sg_next(miter.piter.sg);
unsigned char *ptr = kmap(page);
if (dir == TO_XFER_BUF)
memcpy(ptr + poff, buffer + cnt, plen);
else
memcpy(buffer + cnt, ptr + poff, plen);
kunmap(page);
/* Start at the beginning of the next page */
poff = 0;
++page;
cnt += plen;
sglen -= plen;
} }
cnt += len;
} }
*sgptr = sg; sg_miter_stop(&miter);
/* Return the amount actually transferred */
return cnt; return cnt;
} }
EXPORT_SYMBOL_GPL(usb_stor_access_xfer_buf); EXPORT_SYMBOL_GPL(usb_stor_access_xfer_buf);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment