X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fscsi%2Fsg.c;h=85d38940a6c91e2b0d5b546bb0705bdd3ab37f8a;hb=ea98054fefa28b646c740baffe83c2962f8228f6;hp=d5bbb97bb74b185a27c0bb425faae9c0db015b47;hpb=454e8957eb60841016deb319dbbf83042fb32a39;p=linux-2.6-omap-h63xx.git diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index d5bbb97bb74..85d38940a6c 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -18,8 +18,8 @@ * */ -static int sg_version_num = 30533; /* 2 digits for each component */ -#define SG_VERSION_STR "3.5.33" +static int sg_version_num = 30534; /* 2 digits for each component */ +#define SG_VERSION_STR "3.5.34" /* * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes: @@ -28,7 +28,6 @@ static int sg_version_num = 30533; /* 2 digits for each component */ * (otherwise the macros compile to empty statements). * */ -#include #include #include @@ -42,7 +41,6 @@ static int sg_version_num = 30533; /* 2 digits for each component */ #include #include #include -#include #include #include #include @@ -61,7 +59,7 @@ static int sg_version_num = 30533; /* 2 digits for each component */ #ifdef CONFIG_SCSI_PROC_FS #include -static char *sg_version_date = "20050908"; +static char *sg_version_date = "20061027"; static int sg_proc_init(void); static void sg_proc_cleanup(void); @@ -95,6 +93,9 @@ int sg_big_buff = SG_DEF_RESERVED_SIZE; static int def_reserved_size = -1; /* picks up init parameter */ static int sg_allow_dio = SG_ALLOW_DIO_DEF; +static int scatter_elem_sz = SG_SCATTER_SZ; +static int scatter_elem_sz_prev = SG_SCATTER_SZ; + #define SG_SECTOR_SZ 512 #define SG_SECTOR_MSK (SG_SECTOR_SZ - 1) @@ -708,12 +709,12 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, (int) cmnd[0], (int) hp->cmd_len)); if ((k = sg_start_req(srp))) { - SCSI_LOG_TIMEOUT(1, printk("sg_write: start_req err=%d\n", k)); + SCSI_LOG_TIMEOUT(1, printk("sg_common_write: start_req err=%d\n", k)); sg_finish_rem_req(srp); return k; /* probably out of space --> ENOMEM */ } if ((k = sg_write_xfer(srp))) { - SCSI_LOG_TIMEOUT(1, printk("sg_write: write_xfer, bad address\n")); + SCSI_LOG_TIMEOUT(1, printk("sg_common_write: write_xfer, bad address\n")); sg_finish_rem_req(srp); return k; } @@ -744,7 +745,7 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, hp->dxfer_len, srp->data.k_use_sg, timeout, SG_DEFAULT_RETRIES, srp, sg_cmd_done, GFP_ATOMIC)) { - SCSI_LOG_TIMEOUT(1, printk("sg_write: scsi_execute_async failed\n")); + SCSI_LOG_TIMEOUT(1, printk("sg_common_write: scsi_execute_async failed\n")); /* * most likely out of mem, but could also be a bad map */ @@ -915,6 +916,8 @@ sg_ioctl(struct inode *inode, struct file *filp, return result; if (val < 0) return -EINVAL; + val = min_t(int, val, + sdp->device->request_queue->max_sectors * 512); if (val != sfp->reserve.bufflen) { if (sg_res_in_use(sfp) || sfp->mmap_called) return -EBUSY; @@ -923,7 +926,8 @@ sg_ioctl(struct inode *inode, struct file *filp, } return 0; case SG_GET_RESERVED_SIZE: - val = (int) sfp->reserve.bufflen; + val = min_t(int, sfp->reserve.bufflen, + sdp->device->request_queue->max_sectors * 512); return put_user(val, ip); case SG_SET_COMMAND_Q: result = get_user(val, ip); @@ -1059,6 +1063,9 @@ sg_ioctl(struct inode *inode, struct file *filp, if (sdp->detached) return -ENODEV; return scsi_ioctl(sdp->device, cmd_in, p); + case BLKSECTGET: + return put_user(sdp->device->request_queue->max_sectors * 512, + ip); default: if (read_only) return -EPERM; /* don't know so take safe approach */ @@ -1165,7 +1172,7 @@ sg_vma_nopage(struct vm_area_struct *vma, unsigned long addr, int *type) len = vma->vm_end - sa; len = (len < sg->length) ? len : sg->length; if (offset < len) { - page = sg->page; + page = virt_to_page(page_address(sg->page) + offset); get_page(page); /* increment page count */ break; } @@ -1281,7 +1288,7 @@ sg_cmd_done(void *data, char *sense, int result, int resid) sg_finish_rem_req(srp); srp = NULL; if (NULL == sfp->headrp) { - SCSI_LOG_TIMEOUT(1, printk("sg...bh: already closed, final cleanup\n")); + SCSI_LOG_TIMEOUT(1, printk("sg_cmd_done: already closed, final cleanup\n")); if (0 == sg_remove_sfp(sdp, sfp)) { /* device still present */ scsi_device_put(sdp->device); } @@ -1510,12 +1517,12 @@ sg_remove(struct class_device *cl_dev, struct class_interface *cl_intf) POLL_HUP); } } - SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d, dirty\n", k)); + SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d, dirty\n", k)); if (NULL == sdp->headfp) { sg_dev_arr[k] = NULL; } } else { /* nothing active, simple case */ - SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k)); + SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d\n", k)); sg_dev_arr[k] = NULL; } sg_nr_dev--; @@ -1538,11 +1545,9 @@ sg_remove(struct class_device *cl_dev, struct class_interface *cl_intf) msleep(10); /* dirty detach so delay device destruction */ } -/* Set 'perm' (4th argument) to 0 to disable module_param's definition - * of sysfs parameters (which module_param doesn't yet support). - * Sysfs parameters defined explicitly below. - */ -module_param_named(def_reserved_size, def_reserved_size, int, S_IRUGO); +module_param_named(scatter_elem_sz, scatter_elem_sz, int, S_IRUGO | S_IWUSR); +module_param_named(def_reserved_size, def_reserved_size, int, + S_IRUGO | S_IWUSR); module_param_named(allow_dio, sg_allow_dio, int, S_IRUGO | S_IWUSR); MODULE_AUTHOR("Douglas Gilbert"); @@ -1551,6 +1556,8 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(SG_VERSION_STR); MODULE_ALIAS_CHARDEV_MAJOR(SCSI_GENERIC_MAJOR); +MODULE_PARM_DESC(scatter_elem_sz, "scatter gather element " + "size (default: max(SG_SCATTER_SZ, PAGE_SIZE))"); MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd"); MODULE_PARM_DESC(allow_dio, "allow direct I/O (default: 0 (disallow))"); @@ -1559,8 +1566,14 @@ init_sg(void) { int rc; + if (scatter_elem_sz < PAGE_SIZE) { + scatter_elem_sz = PAGE_SIZE; + scatter_elem_sz_prev = scatter_elem_sz; + } if (def_reserved_size >= 0) sg_big_buff = def_reserved_size; + else + def_reserved_size = sg_big_buff; rc = register_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), SG_MAX_DEVS, "sg"); @@ -1829,7 +1842,7 @@ sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size) int blk_size = buff_size; struct page *p = NULL; - if ((blk_size < 0) || (!sfp)) + if (blk_size < 0) return -EFAULT; if (0 == blk_size) ++blk_size; /* don't know why */ @@ -1843,24 +1856,40 @@ sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size) if (mx_sc_elems < 0) return mx_sc_elems; /* most likely -ENOMEM */ + num = scatter_elem_sz; + if (unlikely(num != scatter_elem_sz_prev)) { + if (num < PAGE_SIZE) { + scatter_elem_sz = PAGE_SIZE; + scatter_elem_sz_prev = PAGE_SIZE; + } else + scatter_elem_sz_prev = num; + } for (k = 0, sg = schp->buffer, rem_sz = blk_size; (rem_sz > 0) && (k < mx_sc_elems); ++k, rem_sz -= ret_sz, ++sg) { - num = (rem_sz > SG_SCATTER_SZ) ? SG_SCATTER_SZ : rem_sz; + num = (rem_sz > scatter_elem_sz_prev) ? + scatter_elem_sz_prev : rem_sz; p = sg_page_malloc(num, sfp->low_dma, &ret_sz); if (!p) return -ENOMEM; + if (num == scatter_elem_sz_prev) { + if (unlikely(ret_sz > scatter_elem_sz_prev)) { + scatter_elem_sz = ret_sz; + scatter_elem_sz_prev = ret_sz; + } + } sg->page = p; - sg->length = ret_sz; + sg->length = (ret_sz > num) ? num : ret_sz; - SCSI_LOG_TIMEOUT(5, printk("sg_build_build: k=%d, a=0x%p, len=%d\n", - k, p, ret_sz)); + SCSI_LOG_TIMEOUT(5, printk("sg_build_indirect: k=%d, num=%d, " + "ret_sz=%d\n", k, num, ret_sz)); } /* end of for loop */ schp->k_use_sg = k; - SCSI_LOG_TIMEOUT(5, printk("sg_build_indirect: k_use_sg=%d, rem_sz=%d\n", k, rem_sz)); + SCSI_LOG_TIMEOUT(5, printk("sg_build_indirect: k_use_sg=%d, " + "rem_sz=%d\n", k, rem_sz)); schp->bufflen = blk_size; if (rem_sz > 0) /* must have failed */ @@ -1991,7 +2020,7 @@ sg_remove_scat(Sg_scatter_hold * schp) for (k = 0; (k < schp->k_use_sg) && sg->page; ++k, ++sg) { SCSI_LOG_TIMEOUT(5, printk( - "sg_remove_scat: k=%d, a=0x%p, len=%d\n", + "sg_remove_scat: k=%d, pg=0x%p, len=%d\n", k, sg->page, sg->length)); sg_page_free(sg->page, sg->length); } @@ -2315,6 +2344,7 @@ sg_add_sfp(Sg_device * sdp, int dev) { Sg_fd *sfp; unsigned long iflags; + int bufflen; sfp = kzalloc(sizeof(*sfp), GFP_ATOMIC | __GFP_NOWARN); if (!sfp) @@ -2342,7 +2372,12 @@ sg_add_sfp(Sg_device * sdp, int dev) } write_unlock_irqrestore(&sg_dev_arr_lock, iflags); SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp)); - sg_build_reserve(sfp, sg_big_buff); + if (unlikely(sg_big_buff != def_reserved_size)) + sg_big_buff = def_reserved_size; + + bufflen = min_t(int, sg_big_buff, + sdp->device->request_queue->max_sectors * 512); + sg_build_reserve(sfp, bufflen); SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: bufflen=%d, k_use_sg=%d\n", sfp->reserve.bufflen, sfp->reserve.k_use_sg)); return sfp; @@ -2438,16 +2473,16 @@ sg_res_in_use(Sg_fd * sfp) return srp ? 1 : 0; } -/* If retSzp==NULL want exact size or fail */ +/* The size fetched (value output via retSzp) set when non-NULL return */ static struct page * sg_page_malloc(int rqSz, int lowDma, int *retSzp) { struct page *resp = NULL; gfp_t page_mask; int order, a_size; - int resSz = rqSz; + int resSz; - if (rqSz <= 0) + if ((rqSz <= 0) || (NULL == retSzp)) return resp; if (lowDma) @@ -2457,8 +2492,9 @@ sg_page_malloc(int rqSz, int lowDma, int *retSzp) for (order = 0, a_size = PAGE_SIZE; a_size < rqSz; order++, a_size <<= 1) ; + resSz = a_size; /* rounded up if necessary */ resp = alloc_pages(page_mask, order); - while ((!resp) && order && retSzp) { + while ((!resp) && order) { --order; a_size >>= 1; /* divide by 2, until PAGE_SIZE */ resp = alloc_pages(page_mask, order); /* try half */ @@ -2467,8 +2503,7 @@ sg_page_malloc(int rqSz, int lowDma, int *retSzp) if (resp) { if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) memset(page_address(resp), 0, resSz); - if (retSzp) - *retSzp = resSz; + *retSzp = resSz; } return resp; }