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 | |
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>
-rw-r--r-- | drivers/scsi/sg.c | 53 | ||||
-rw-r--r-- | include/scsi/sg.h | 61 |
2 files changed, 61 insertions, 53 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 | } |
diff --git a/include/scsi/sg.h b/include/scsi/sg.h index 0a487fe26d4f..519c49a0fc11 100644 --- a/include/scsi/sg.h +++ b/include/scsi/sg.h | |||
@@ -11,26 +11,10 @@ | |||
11 | Original driver (sg.h): | 11 | Original driver (sg.h): |
12 | * Copyright (C) 1992 Lawrence Foard | 12 | * Copyright (C) 1992 Lawrence Foard |
13 | Version 2 and 3 extensions to driver: | 13 | Version 2 and 3 extensions to driver: |
14 | * Copyright (C) 1998 - 2003 Douglas Gilbert | 14 | * Copyright (C) 1998 - 2006 Douglas Gilbert |
15 | 15 | ||
16 | Version: 3.5.29 (20030529) | 16 | Version: 3.5.34 (20060920) |
17 | This version is for 2.5 series kernels. | 17 | This version is for 2.6 series kernels. |
18 | |||
19 | Changes since 3.5.28 (20030308) | ||
20 | - fix bug introduced in version 3.1.24 (last segment of sgat list) | ||
21 | Changes since 3.5.27 (20020812) | ||
22 | - remove procfs entries: hosts, host_hdr + host_strs (now in sysfs) | ||
23 | - add sysfs sg driver params: def_reserved_size, allow_dio, version | ||
24 | - new boot option: "sg_allow_dio" and module parameter: "allow_dio" | ||
25 | - multiple internal changes due to scsi subsystem rework | ||
26 | Changes since 3.5.26 (20020708) | ||
27 | - re-add direct IO using Kai Makisara's work | ||
28 | - re-tab to 8, start using C99-isms | ||
29 | - simplify memory management | ||
30 | Changes since 3.5.25 (20020504) | ||
31 | - driverfs additions | ||
32 | - copy_to/from_user() fixes [William Stinson] | ||
33 | - disable kiobufs support | ||
34 | 18 | ||
35 | For a full changelog see http://www.torque.net/sg | 19 | For a full changelog see http://www.torque.net/sg |
36 | 20 | ||
@@ -40,7 +24,7 @@ Map of SG verions to the Linux kernels in which they appear: | |||
40 | 2.1.40 2.2.20 | 24 | 2.1.40 2.2.20 |
41 | 3.0.x optional version 3 sg driver for 2.2 series | 25 | 3.0.x optional version 3 sg driver for 2.2 series |
42 | 3.1.17++ 2.4.0++ | 26 | 3.1.17++ 2.4.0++ |
43 | 3.5.23++ 2.5.0++ | 27 | 3.5.30++ 2.6.0++ |
44 | 28 | ||
45 | Major new features in SG 3.x driver (cf SG 2.x drivers) | 29 | Major new features in SG 3.x driver (cf SG 2.x drivers) |
46 | - SG_IO ioctl() combines function if write() and read() | 30 | - SG_IO ioctl() combines function if write() and read() |
@@ -51,14 +35,15 @@ Major new features in SG 3.x driver (cf SG 2.x drivers) | |||
51 | data into kernel buffers and then use the CPU to copy the data into the | 35 | data into kernel buffers and then use the CPU to copy the data into the |
52 | user space (vice versa for writes). That is called "indirect" IO due to | 36 | user space (vice versa for writes). That is called "indirect" IO due to |
53 | the double handling of data. There are two methods offered to remove the | 37 | the double handling of data. There are two methods offered to remove the |
54 | redundant copy: 1) direct IO which uses the kernel kiobuf mechanism and | 38 | redundant copy: 1) direct IO and 2) using the mmap() system call to map |
55 | 2) using the mmap() system call to map the reserve buffer (this driver has | 39 | the reserve buffer (this driver has one reserve buffer per fd) into the |
56 | one reserve buffer per fd) into the user space. Both have their advantages. | 40 | user space. Both have their advantages. |
57 | In terms of absolute speed mmap() is faster. If speed is not a concern, | 41 | In terms of absolute speed mmap() is faster. If speed is not a concern, |
58 | indirect IO should be fine. Read the documentation for more information. | 42 | indirect IO should be fine. Read the documentation for more information. |
59 | 43 | ||
60 | ** N.B. To use direct IO 'echo 1 > /proc/scsi/sg/allow_dio' may be | 44 | ** N.B. To use direct IO 'echo 1 > /proc/scsi/sg/allow_dio' or |
61 | needed. That pseudo file's content is defaulted to 0. ** | 45 | 'echo 1 > /sys/module/sg/parameters/allow_dio' is needed. |
46 | That attribute is 0 by default. ** | ||
62 | 47 | ||
63 | Historical note: this SCSI pass-through driver has been known as "sg" for | 48 | Historical note: this SCSI pass-through driver has been known as "sg" for |
64 | a decade. In broader kernel discussions "sg" is used to refer to scatter | 49 | a decade. In broader kernel discussions "sg" is used to refer to scatter |
@@ -72,20 +57,17 @@ Major new features in SG 3.x driver (cf SG 2.x drivers) | |||
72 | http://www.torque.net/sg/p/sg_v3_ho.html | 57 | http://www.torque.net/sg/p/sg_v3_ho.html |
73 | This is a rendering from DocBook source [change the extension to "sgml" | 58 | This is a rendering from DocBook source [change the extension to "sgml" |
74 | or "xml"]. There are renderings in "ps", "pdf", "rtf" and "txt" (soon). | 59 | or "xml"]. There are renderings in "ps", "pdf", "rtf" and "txt" (soon). |
60 | The SG_IO ioctl is now found in other parts kernel (e.g. the block layer). | ||
61 | For more information see http://www.torque.net/sg/sg_io.html | ||
75 | 62 | ||
76 | The older, version 2 documents discuss the original sg interface in detail: | 63 | The older, version 2 documents discuss the original sg interface in detail: |
77 | http://www.torque.net/sg/p/scsi-generic.txt | 64 | http://www.torque.net/sg/p/scsi-generic.txt |
78 | http://www.torque.net/sg/p/scsi-generic_long.txt | 65 | http://www.torque.net/sg/p/scsi-generic_long.txt |
79 | A version of this document (potentially out of date) may also be found in | 66 | Also available: <kernel_source>/Documentation/scsi/scsi-generic.txt |
80 | the kernel source tree, probably at: | ||
81 | Documentation/scsi/scsi-generic.txt . | ||
82 | 67 | ||
83 | Utility and test programs are available at the sg web site. They are | 68 | Utility and test programs are available at the sg web site. They are |
84 | bundled as sg_utils (for the lk 2.2 series) and sg3_utils (for the | 69 | packaged as sg3_utils (for the lk 2.4 and 2.6 series) and sg_utils |
85 | lk 2.4 series). | 70 | (for the lk 2.2 series). |
86 | |||
87 | There is a HOWTO on the Linux SCSI subsystem in the lk 2.4 series at: | ||
88 | http://www.linuxdoc.org/HOWTO/SCSI-2.4-HOWTO | ||
89 | */ | 71 | */ |
90 | 72 | ||
91 | 73 | ||
@@ -238,13 +220,12 @@ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */ | |||
238 | #define SG_GET_ACCESS_COUNT 0x2289 | 220 | #define SG_GET_ACCESS_COUNT 0x2289 |
239 | 221 | ||
240 | 222 | ||
241 | #define SG_SCATTER_SZ (8 * 4096) /* PAGE_SIZE not available to user */ | 223 | #define SG_SCATTER_SZ (8 * 4096) |
242 | /* Largest size (in bytes) a single scatter-gather list element can have. | 224 | /* Largest size (in bytes) a single scatter-gather list element can have. |
243 | The value must be a power of 2 and <= (PAGE_SIZE * 32) [131072 bytes on | 225 | The value used by the driver is 'max(SG_SCATTER_SZ, PAGE_SIZE)'. |
244 | i386]. The minimum value is PAGE_SIZE. If scatter-gather not supported | 226 | This value should be a power of 2 (and may be rounded up internally). |
245 | by adapter then this value is the largest data block that can be | 227 | If scatter-gather is not supported by adapter then this value is the |
246 | read/written by a single scsi command. The user can find the value of | 228 | largest data block that can be read/written by a single scsi command. */ |
247 | PAGE_SIZE by calling getpagesize() defined in unistd.h . */ | ||
248 | 229 | ||
249 | #define SG_DEFAULT_RETRIES 0 | 230 | #define SG_DEFAULT_RETRIES 0 |
250 | 231 | ||