diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-18 14:25:31 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-18 14:25:31 -0400 |
| 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 @@ | |||
| 8 | */ | 8 | */ |
| 9 | #include <linux/module.h> | 9 | #include <linux/module.h> |
| 10 | #include <linux/scatterlist.h> | 10 | #include <linux/scatterlist.h> |
| 11 | #include <linux/highmem.h> | ||
| 11 | 12 | ||
| 12 | /** | 13 | /** |
| 13 | * sg_next - return the next scatterlist entry in a list | 14 | * 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) | |||
| 292 | return ret; | 293 | return ret; |
| 293 | } | 294 | } |
| 294 | EXPORT_SYMBOL(sg_alloc_table); | 295 | EXPORT_SYMBOL(sg_alloc_table); |
| 296 | |||
| 297 | /** | ||
| 298 | * sg_copy_buffer - Copy data between a linear buffer and an SG list | ||
| 299 | * @sgl: The SG list | ||
| 300 | * @nents: Number of SG entries | ||
| 301 | * @buf: Where to copy from | ||
| 302 | * @buflen: The number of bytes to copy | ||
| 303 | * @to_buffer: transfer direction (non zero == from an sg list to a | ||
| 304 | * buffer, 0 == from a buffer to an sg list | ||
| 305 | * | ||
| 306 | * Returns the number of copied bytes. | ||
| 307 | * | ||
| 308 | **/ | ||
| 309 | static size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents, | ||
| 310 | void *buf, size_t buflen, int to_buffer) | ||
| 311 | { | ||
| 312 | struct scatterlist *sg; | ||
| 313 | size_t buf_off = 0; | ||
| 314 | int i; | ||
| 315 | |||
| 316 | WARN_ON(!irqs_disabled()); | ||
| 317 | |||
| 318 | for_each_sg(sgl, sg, nents, i) { | ||
| 319 | struct page *page; | ||
| 320 | int n = 0; | ||
| 321 | unsigned int sg_off = sg->offset; | ||
| 322 | unsigned int sg_copy = sg->length; | ||
| 323 | |||
| 324 | if (sg_copy > buflen) | ||
| 325 | sg_copy = buflen; | ||
| 326 | buflen -= sg_copy; | ||
| 327 | |||
| 328 | while (sg_copy > 0) { | ||
| 329 | unsigned int page_copy; | ||
| 330 | void *p; | ||
| 331 | |||
| 332 | page_copy = PAGE_SIZE - sg_off; | ||
| 333 | if (page_copy > sg_copy) | ||
| 334 | page_copy = sg_copy; | ||
| 335 | |||
| 336 | page = nth_page(sg_page(sg), n); | ||
| 337 | p = kmap_atomic(page, KM_BIO_SRC_IRQ); | ||
| 338 | |||
| 339 | if (to_buffer) | ||
| 340 | memcpy(buf + buf_off, p + sg_off, page_copy); | ||
| 341 | else { | ||
| 342 | memcpy(p + sg_off, buf + buf_off, page_copy); | ||
| 343 | flush_kernel_dcache_page(page); | ||
| 344 | } | ||
| 345 | |||
| 346 | kunmap_atomic(p, KM_BIO_SRC_IRQ); | ||
| 347 | |||
| 348 | buf_off += page_copy; | ||
| 349 | sg_off += page_copy; | ||
| 350 | if (sg_off == PAGE_SIZE) { | ||
| 351 | sg_off = 0; | ||
| 352 | n++; | ||
| 353 | } | ||
| 354 | sg_copy -= page_copy; | ||
| 355 | } | ||
| 356 | |||
| 357 | if (!buflen) | ||
| 358 | break; | ||
| 359 | } | ||
| 360 | |||
| 361 | return buf_off; | ||
| 362 | } | ||
| 363 | |||
| 364 | /** | ||
| 365 | * sg_copy_from_buffer - Copy from a linear buffer to an SG list | ||
| 366 | * @sgl: The SG list | ||
| 367 | * @nents: Number of SG entries | ||
| 368 | * @buf: Where to copy from | ||
| 369 | * @buflen: The number of bytes to copy | ||
| 370 | * | ||
| 371 | * Returns the number of copied bytes. | ||
| 372 | * | ||
| 373 | **/ | ||
| 374 | size_t sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents, | ||
| 375 | void *buf, size_t buflen) | ||
| 376 | { | ||
| 377 | return sg_copy_buffer(sgl, nents, buf, buflen, 0); | ||
| 378 | } | ||
| 379 | EXPORT_SYMBOL(sg_copy_from_buffer); | ||
| 380 | |||
| 381 | /** | ||
| 382 | * sg_copy_to_buffer - Copy from an SG list to a linear buffer | ||
| 383 | * @sgl: The SG list | ||
| 384 | * @nents: Number of SG entries | ||
| 385 | * @buf: Where to copy to | ||
| 386 | * @buflen: The number of bytes to copy | ||
| 387 | * | ||
| 388 | * Returns the number of copied bytes. | ||
| 389 | * | ||
| 390 | **/ | ||
| 391 | size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents, | ||
| 392 | void *buf, size_t buflen) | ||
| 393 | { | ||
| 394 | return sg_copy_buffer(sgl, nents, buf, buflen, 1); | ||
| 395 | } | ||
| 396 | EXPORT_SYMBOL(sg_copy_to_buffer); | ||
