diff options
author | Linus Torvalds | 2008-04-18 11:25:31 -0700 |
---|---|---|
committer | Linus Torvalds | 2008-04-18 11:25:31 -0700 |
commit | 2cca775baecbfede2fec20c99add709232311fe7 (patch) | |
tree | b0eefe80881d263ba7976174144ae4e9cf238425 /lib | |
parent | eddeb0e2d863e3941d8768e70cb50c6120e61fa0 (diff) | |
parent | 94795b61e84994a3b058f92d041d1fb3d869c7d5 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (137 commits)
[SCSI] iscsi: bidi support for iscsi_tcp
[SCSI] iscsi: bidi support at the generic libiscsi level
[SCSI] iscsi: extended cdb support
[SCSI] zfcp: Fix error handling for blocked unit for send FCP command
[SCSI] zfcp: Remove zfcp_erp_wait from slave destory handler to fix deadlock
[SCSI] zfcp: fix 31 bit compile warnings
[SCSI] bsg: no need to set BSG_F_BLOCK bit in bsg_complete_all_commands
[SCSI] bsg: remove minor in struct bsg_device
[SCSI] bsg: use better helper list functions
[SCSI] bsg: replace kobject_get with blk_get_queue
[SCSI] bsg: takes a ref to struct device in fops->open
[SCSI] qla1280: remove version check
[SCSI] libsas: fix endianness bug in sas_ata
[SCSI] zfcp: fix compiler warning caused by poking inside new semaphore (linux-next)
[SCSI] aacraid: Do not describe check_reset parameter with its value
[SCSI] aacraid: Fix down_interruptible() to check the return value
[SCSI] sun3_scsi_vme: add MODULE_LICENSE
[SCSI] st: rename flush_write_buffer()
[SCSI] tgt: use KMEM_CACHE macro
[SCSI] initio: fix big endian problems for auto request sense
...
Diffstat (limited to 'lib')
-rw-r--r-- | lib/scatterlist.c | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/lib/scatterlist.c b/lib/scatterlist.c index acca4901046c..b80c21100d78 100644 --- a/lib/scatterlist.c +++ b/lib/scatterlist.c @@ -8,6 +8,7 @@ */ #include <linux/module.h> #include <linux/scatterlist.h> +#include <linux/highmem.h> /** * sg_next - return the next scatterlist entry in a list @@ -292,3 +293,104 @@ int sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask) return ret; } EXPORT_SYMBOL(sg_alloc_table); + +/** + * sg_copy_buffer - Copy data between a linear buffer and an SG list + * @sgl: The SG list + * @nents: Number of SG entries + * @buf: Where to copy from + * @buflen: The number of bytes to copy + * @to_buffer: transfer direction (non zero == from an sg list to a + * buffer, 0 == from a buffer to an sg list + * + * Returns the number of copied bytes. + * + **/ +static size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents, + void *buf, size_t buflen, int to_buffer) +{ + struct scatterlist *sg; + size_t buf_off = 0; + int i; + + WARN_ON(!irqs_disabled()); + + for_each_sg(sgl, sg, nents, i) { + struct page *page; + int n = 0; + unsigned int sg_off = sg->offset; + unsigned int sg_copy = sg->length; + + if (sg_copy > buflen) + sg_copy = buflen; + buflen -= sg_copy; + + while (sg_copy > 0) { + unsigned int page_copy; + void *p; + + page_copy = PAGE_SIZE - sg_off; + if (page_copy > sg_copy) + page_copy = sg_copy; + + page = nth_page(sg_page(sg), n); + p = kmap_atomic(page, KM_BIO_SRC_IRQ); + + if (to_buffer) + memcpy(buf + buf_off, p + sg_off, page_copy); + else { + memcpy(p + sg_off, buf + buf_off, page_copy); + flush_kernel_dcache_page(page); + } + + kunmap_atomic(p, KM_BIO_SRC_IRQ); + + buf_off += page_copy; + sg_off += page_copy; + if (sg_off == PAGE_SIZE) { + sg_off = 0; + n++; + } + sg_copy -= page_copy; + } + + if (!buflen) + break; + } + + return buf_off; +} + +/** + * sg_copy_from_buffer - Copy from a linear buffer to an SG list + * @sgl: The SG list + * @nents: Number of SG entries + * @buf: Where to copy from + * @buflen: The number of bytes to copy + * + * Returns the number of copied bytes. + * + **/ +size_t sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents, + void *buf, size_t buflen) +{ + return sg_copy_buffer(sgl, nents, buf, buflen, 0); +} +EXPORT_SYMBOL(sg_copy_from_buffer); + +/** + * sg_copy_to_buffer - Copy from an SG list to a linear buffer + * @sgl: The SG list + * @nents: Number of SG entries + * @buf: Where to copy to + * @buflen: The number of bytes to copy + * + * Returns the number of copied bytes. + * + **/ +size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents, + void *buf, size_t buflen) +{ + return sg_copy_buffer(sgl, nents, buf, buflen, 1); +} +EXPORT_SYMBOL(sg_copy_to_buffer); |