aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/scsi_lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/scsi_lib.c')
-rw-r--r--drivers/scsi/scsi_lib.c57
1 files changed, 57 insertions, 0 deletions
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 7b0f9a3810d2..57453ca09700 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -2350,3 +2350,60 @@ scsi_target_unblock(struct device *dev)
2350 device_for_each_child(dev, NULL, target_unblock); 2350 device_for_each_child(dev, NULL, target_unblock);
2351} 2351}
2352EXPORT_SYMBOL_GPL(scsi_target_unblock); 2352EXPORT_SYMBOL_GPL(scsi_target_unblock);
2353
2354/**
2355 * scsi_kmap_atomic_sg - find and atomically map an sg-elemnt
2356 * @sg: scatter-gather list
2357 * @sg_count: number of segments in sg
2358 * @offset: offset in bytes into sg, on return offset into the mapped area
2359 * @len: bytes to map, on return number of bytes mapped
2360 *
2361 * Returns virtual address of the start of the mapped page
2362 */
2363void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count,
2364 size_t *offset, size_t *len)
2365{
2366 int i;
2367 size_t sg_len = 0, len_complete = 0;
2368 struct page *page;
2369
2370 for (i = 0; i < sg_count; i++) {
2371 len_complete = sg_len; /* Complete sg-entries */
2372 sg_len += sg[i].length;
2373 if (sg_len > *offset)
2374 break;
2375 }
2376
2377 if (unlikely(i == sg_count)) {
2378 printk(KERN_ERR "%s: Bytes in sg: %u, requested offset %u, elements %d\n",
2379 __FUNCTION__, sg_len, *offset, sg_count);
2380 WARN_ON(1);
2381 return NULL;
2382 }
2383
2384 /* Offset starting from the beginning of first page in this sg-entry */
2385 *offset = *offset - len_complete + sg[i].offset;
2386
2387 /* Assumption: contiguous pages can be accessed as "page + i" */
2388 page = nth_page(sg[i].page, (*offset >> PAGE_SHIFT));
2389 *offset &= ~PAGE_MASK;
2390
2391 /* Bytes in this sg-entry from *offset to the end of the page */
2392 sg_len = PAGE_SIZE - *offset;
2393 if (*len > sg_len)
2394 *len = sg_len;
2395
2396 return kmap_atomic(page, KM_BIO_SRC_IRQ);
2397}
2398EXPORT_SYMBOL(scsi_kmap_atomic_sg);
2399
2400/**
2401 * scsi_kunmap_atomic_sg - atomically unmap a virtual address, previously
2402 * mapped with scsi_kmap_atomic_sg
2403 * @virt: virtual address to be unmapped
2404 */
2405void scsi_kunmap_atomic_sg(void *virt)
2406{
2407 kunmap_atomic(virt, KM_BIO_SRC_IRQ);
2408}
2409EXPORT_SYMBOL(scsi_kunmap_atomic_sg);