diff options
author | Douglas Gilbert <dougg@torque.net> | 2006-09-20 18:20:49 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-09-26 12:23:15 -0400 |
commit | 6460e75a104d10458817d2f5b2fbff775bf0b43a (patch) | |
tree | 88e2a88aef94282728d1c764d02e5efa7ef7fee4 /drivers/scsi | |
parent | 8aee918a1cff2a3722ce76fc6fa5abe09aa98d1b (diff) |
[SCSI] sg: fixes for large page_size
This sg driver patch addresses the problem with larger
page sizes reported by Brian King in this post:
http://marc.theaimsgroup.com/?l=linux-scsi&m=115867718623631&w=2
Some other related matters are also addressed. Some of these
prevent oopses when the SG_SCATTER_SZ or scatter_elem_sz are
set to inappropriate values.
The scatter_elem_sz has been tested up to 4 MB which should
make the largest data transfer with one SCSI command, 32 MB
less one block, achievable with a relatively small number
of elements in the scatter gather list.
ChangeLog:
- add scatter_elem_sz boot time parameter and sysfs module
parameter that is initialized to SG_SCATTER_SZ
- the driver will then adjust scatter_elem_sz to be the
max(given(scatter_elem_sz), PAGE_SIZE)
It will also round it up, if necessary, to be a power
of two
- clean up sg.h header, correct bad urls and some statements
that are no longer valid
- make the def_reserved_size sysfs module attribute writable
Signed-off-by: Douglas Gilbert <dougg@torque.net>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/sg.c | 53 |
1 files changed, 40 insertions, 13 deletions
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 34f9343ed0af..3f8b93188567 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c | |||
@@ -60,7 +60,7 @@ static int sg_version_num = 30534; /* 2 digits for each component */ | |||
60 | 60 | ||
61 | #ifdef CONFIG_SCSI_PROC_FS | 61 | #ifdef CONFIG_SCSI_PROC_FS |
62 | #include <linux/proc_fs.h> | 62 | #include <linux/proc_fs.h> |
63 | static char *sg_version_date = "20060818"; | 63 | static char *sg_version_date = "20060920"; |
64 | 64 | ||
65 | static int sg_proc_init(void); | 65 | static int sg_proc_init(void); |
66 | static void sg_proc_cleanup(void); | 66 | static void sg_proc_cleanup(void); |
@@ -94,6 +94,9 @@ int sg_big_buff = SG_DEF_RESERVED_SIZE; | |||
94 | static int def_reserved_size = -1; /* picks up init parameter */ | 94 | static int def_reserved_size = -1; /* picks up init parameter */ |
95 | static int sg_allow_dio = SG_ALLOW_DIO_DEF; | 95 | static int sg_allow_dio = SG_ALLOW_DIO_DEF; |
96 | 96 | ||
97 | static int scatter_elem_sz = SG_SCATTER_SZ; | ||
98 | static int scatter_elem_sz_prev = SG_SCATTER_SZ; | ||
99 | |||
97 | #define SG_SECTOR_SZ 512 | 100 | #define SG_SECTOR_SZ 512 |
98 | #define SG_SECTOR_MSK (SG_SECTOR_SZ - 1) | 101 | #define SG_SECTOR_MSK (SG_SECTOR_SZ - 1) |
99 | 102 | ||
@@ -1537,11 +1540,9 @@ sg_remove(struct class_device *cl_dev, struct class_interface *cl_intf) | |||
1537 | msleep(10); /* dirty detach so delay device destruction */ | 1540 | msleep(10); /* dirty detach so delay device destruction */ |
1538 | } | 1541 | } |
1539 | 1542 | ||
1540 | /* Set 'perm' (4th argument) to 0 to disable module_param's definition | 1543 | module_param_named(scatter_elem_sz, scatter_elem_sz, int, S_IRUGO | S_IWUSR); |
1541 | * of sysfs parameters (which module_param doesn't yet support). | 1544 | module_param_named(def_reserved_size, def_reserved_size, int, |
1542 | * Sysfs parameters defined explicitly below. | 1545 | S_IRUGO | S_IWUSR); |
1543 | */ | ||
1544 | module_param_named(def_reserved_size, def_reserved_size, int, S_IRUGO); | ||
1545 | module_param_named(allow_dio, sg_allow_dio, int, S_IRUGO | S_IWUSR); | 1546 | module_param_named(allow_dio, sg_allow_dio, int, S_IRUGO | S_IWUSR); |
1546 | 1547 | ||
1547 | MODULE_AUTHOR("Douglas Gilbert"); | 1548 | MODULE_AUTHOR("Douglas Gilbert"); |
@@ -1550,6 +1551,8 @@ MODULE_LICENSE("GPL"); | |||
1550 | MODULE_VERSION(SG_VERSION_STR); | 1551 | MODULE_VERSION(SG_VERSION_STR); |
1551 | MODULE_ALIAS_CHARDEV_MAJOR(SCSI_GENERIC_MAJOR); | 1552 | MODULE_ALIAS_CHARDEV_MAJOR(SCSI_GENERIC_MAJOR); |
1552 | 1553 | ||
1554 | MODULE_PARM_DESC(scatter_elem_sz, "scatter gather element " | ||
1555 | "size (default: max(SG_SCATTER_SZ, PAGE_SIZE))"); | ||
1553 | MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd"); | 1556 | MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd"); |
1554 | MODULE_PARM_DESC(allow_dio, "allow direct I/O (default: 0 (disallow))"); | 1557 | MODULE_PARM_DESC(allow_dio, "allow direct I/O (default: 0 (disallow))"); |
1555 | 1558 | ||
@@ -1558,8 +1561,14 @@ init_sg(void) | |||
1558 | { | 1561 | { |
1559 | int rc; | 1562 | int rc; |
1560 | 1563 | ||
1564 | if (scatter_elem_sz < PAGE_SIZE) { | ||
1565 | scatter_elem_sz = PAGE_SIZE; | ||
1566 | scatter_elem_sz_prev = scatter_elem_sz; | ||
1567 | } | ||
1561 | if (def_reserved_size >= 0) | 1568 | if (def_reserved_size >= 0) |
1562 | sg_big_buff = def_reserved_size; | 1569 | sg_big_buff = def_reserved_size; |
1570 | else | ||
1571 | def_reserved_size = sg_big_buff; | ||
1563 | 1572 | ||
1564 | rc = register_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), | 1573 | rc = register_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), |
1565 | SG_MAX_DEVS, "sg"); | 1574 | SG_MAX_DEVS, "sg"); |
@@ -1842,15 +1851,30 @@ sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size) | |||
1842 | if (mx_sc_elems < 0) | 1851 | if (mx_sc_elems < 0) |
1843 | return mx_sc_elems; /* most likely -ENOMEM */ | 1852 | return mx_sc_elems; /* most likely -ENOMEM */ |
1844 | 1853 | ||
1854 | num = scatter_elem_sz; | ||
1855 | if (unlikely(num != scatter_elem_sz_prev)) { | ||
1856 | if (num < PAGE_SIZE) { | ||
1857 | scatter_elem_sz = PAGE_SIZE; | ||
1858 | scatter_elem_sz_prev = PAGE_SIZE; | ||
1859 | } else | ||
1860 | scatter_elem_sz_prev = num; | ||
1861 | } | ||
1845 | for (k = 0, sg = schp->buffer, rem_sz = blk_size; | 1862 | for (k = 0, sg = schp->buffer, rem_sz = blk_size; |
1846 | (rem_sz > 0) && (k < mx_sc_elems); | 1863 | (rem_sz > 0) && (k < mx_sc_elems); |
1847 | ++k, rem_sz -= ret_sz, ++sg) { | 1864 | ++k, rem_sz -= ret_sz, ++sg) { |
1848 | 1865 | ||
1849 | num = (rem_sz > SG_SCATTER_SZ) ? SG_SCATTER_SZ : rem_sz; | 1866 | num = (rem_sz > scatter_elem_sz_prev) ? |
1867 | scatter_elem_sz_prev : rem_sz; | ||
1850 | p = sg_page_malloc(num, sfp->low_dma, &ret_sz); | 1868 | p = sg_page_malloc(num, sfp->low_dma, &ret_sz); |
1851 | if (!p) | 1869 | if (!p) |
1852 | return -ENOMEM; | 1870 | return -ENOMEM; |
1853 | 1871 | ||
1872 | if (num == scatter_elem_sz_prev) { | ||
1873 | if (unlikely(ret_sz > scatter_elem_sz_prev)) { | ||
1874 | scatter_elem_sz = ret_sz; | ||
1875 | scatter_elem_sz_prev = ret_sz; | ||
1876 | } | ||
1877 | } | ||
1854 | sg->page = p; | 1878 | sg->page = p; |
1855 | sg->length = ret_sz; | 1879 | sg->length = ret_sz; |
1856 | 1880 | ||
@@ -2341,6 +2365,9 @@ sg_add_sfp(Sg_device * sdp, int dev) | |||
2341 | } | 2365 | } |
2342 | write_unlock_irqrestore(&sg_dev_arr_lock, iflags); | 2366 | write_unlock_irqrestore(&sg_dev_arr_lock, iflags); |
2343 | SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp)); | 2367 | SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp)); |
2368 | if (unlikely(sg_big_buff != def_reserved_size)) | ||
2369 | sg_big_buff = def_reserved_size; | ||
2370 | |||
2344 | sg_build_reserve(sfp, sg_big_buff); | 2371 | sg_build_reserve(sfp, sg_big_buff); |
2345 | SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: bufflen=%d, k_use_sg=%d\n", | 2372 | SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: bufflen=%d, k_use_sg=%d\n", |
2346 | sfp->reserve.bufflen, sfp->reserve.k_use_sg)); | 2373 | sfp->reserve.bufflen, sfp->reserve.k_use_sg)); |
@@ -2437,16 +2464,16 @@ sg_res_in_use(Sg_fd * sfp) | |||
2437 | return srp ? 1 : 0; | 2464 | return srp ? 1 : 0; |
2438 | } | 2465 | } |
2439 | 2466 | ||
2440 | /* If retSzp==NULL want exact size or fail */ | 2467 | /* The size fetched (value output via retSzp) set when non-NULL return */ |
2441 | static struct page * | 2468 | static struct page * |
2442 | sg_page_malloc(int rqSz, int lowDma, int *retSzp) | 2469 | sg_page_malloc(int rqSz, int lowDma, int *retSzp) |
2443 | { | 2470 | { |
2444 | struct page *resp = NULL; | 2471 | struct page *resp = NULL; |
2445 | gfp_t page_mask; | 2472 | gfp_t page_mask; |
2446 | int order, a_size; | 2473 | int order, a_size; |
2447 | int resSz = rqSz; | 2474 | int resSz; |
2448 | 2475 | ||
2449 | if (rqSz <= 0) | 2476 | if ((rqSz <= 0) || (NULL == retSzp)) |
2450 | return resp; | 2477 | return resp; |
2451 | 2478 | ||
2452 | if (lowDma) | 2479 | if (lowDma) |
@@ -2456,8 +2483,9 @@ sg_page_malloc(int rqSz, int lowDma, int *retSzp) | |||
2456 | 2483 | ||
2457 | for (order = 0, a_size = PAGE_SIZE; a_size < rqSz; | 2484 | for (order = 0, a_size = PAGE_SIZE; a_size < rqSz; |
2458 | order++, a_size <<= 1) ; | 2485 | order++, a_size <<= 1) ; |
2486 | resSz = a_size; /* rounded up if necessary */ | ||
2459 | resp = alloc_pages(page_mask, order); | 2487 | resp = alloc_pages(page_mask, order); |
2460 | while ((!resp) && order && retSzp) { | 2488 | while ((!resp) && order) { |
2461 | --order; | 2489 | --order; |
2462 | a_size >>= 1; /* divide by 2, until PAGE_SIZE */ | 2490 | a_size >>= 1; /* divide by 2, until PAGE_SIZE */ |
2463 | resp = alloc_pages(page_mask, order); /* try half */ | 2491 | resp = alloc_pages(page_mask, order); /* try half */ |
@@ -2466,8 +2494,7 @@ sg_page_malloc(int rqSz, int lowDma, int *retSzp) | |||
2466 | if (resp) { | 2494 | if (resp) { |
2467 | if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) | 2495 | if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) |
2468 | memset(page_address(resp), 0, resSz); | 2496 | memset(page_address(resp), 0, resSz); |
2469 | if (retSzp) | 2497 | *retSzp = resSz; |
2470 | *retSzp = resSz; | ||
2471 | } | 2498 | } |
2472 | return resp; | 2499 | return resp; |
2473 | } | 2500 | } |