Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

USB: gadget: storage: optional SCSI WRITE FUA bit

MS Windows mounts removable storage in "Removal optimized mode" by
default. All the writes to the media are synchronous which is achieved
by setting FUA (Force Unit Access) bit in SCSI WRITE(10,12) commands.
This prevents I/O requests aggregation in block layer dramatically
decreasing performance.

This patch brings an option to accept or ignore mentioned bit
a) via specifying module parameter "nofua", or
b) through sysfs entry
/sys/devices/platform/_UDC_/gadget/gadget-lunX/nofua
(_UDC_ is the name of the USB Device Controller driver)

Patch is based on the work that was done by Denis Karpov for Maemo 5
platform.

Signed-off-by: Andy Shevchenko <ext-andriy.shevchenko@nokia.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Cc: Denis Karpov <ext-denis.2.karpov@nokia.com>
Cc: Adrian Hunter <adrian.hunter@nokia.com>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by

Andy Shevchenko and committed by
Greg Kroah-Hartman
a93917d3 8156d158

+64 -7
+12
Documentation/ABI/testing/sysfs-devices-platform-_UDC_-gadget
··· 7 7 0 -> resumed 8 8 9 9 (_UDC_ is the name of the USB Device Controller driver) 10 + 11 + What: /sys/devices/platform/_UDC_/gadget/gadget-lunX/nofua 12 + Date: July 2010 13 + Contact: Andy Shevchenko <andy.shevchenko@gmail.com> 14 + Description: 15 + Show or set the reaction on the FUA (Force Unit Access) bit in 16 + the SCSI WRITE(10,12) commands when a gadget in USB Mass 17 + Storage mode. 18 + 19 + Possible values are: 20 + 1 -> ignore the FUA flag 21 + 0 -> obey the FUA flag
+24 -7
drivers/usb/gadget/file_storage.c
··· 93 93 * removable Default false, boolean for removable media 94 94 * luns=N Default N = number of filenames, number of 95 95 * LUNs to support 96 + * nofua=b[,b...] Default false, booleans for ignore FUA flag 97 + * in SCSI WRITE(10,12) commands 96 98 * stall Default determined according to the type of 97 99 * USB device controller (usually true), 98 100 * boolean to permit the driver to halt ··· 114 112 * PAGE_CACHE_SIZE) 115 113 * 116 114 * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro", 117 - * "removable", "luns", "stall", and "cdrom" options are available; default 118 - * values are used for everything else. 115 + * "removable", "luns", "nofua", "stall", and "cdrom" options are available; 116 + * default values are used for everything else. 119 117 * 120 118 * The pathnames of the backing files and the ro settings are available in 121 - * the attribute files "file" and "ro" in the lun<n> subdirectory of the 122 - * gadget's sysfs directory. If the "removable" option is set, writing to 119 + * the attribute files "file", "nofua", and "ro" in the lun<n> subdirectory of 120 + * the gadget's sysfs directory. If the "removable" option is set, writing to 123 121 * these files will simulate ejecting/loading the medium (writing an empty 124 122 * line means eject) and adjusting a write-enable tab. Changes to the ro 125 123 * setting are not allowed when the medium is loaded or if CD-ROM emulation ··· 306 304 static struct { 307 305 char *file[FSG_MAX_LUNS]; 308 306 int ro[FSG_MAX_LUNS]; 307 + int nofua[FSG_MAX_LUNS]; 309 308 unsigned int num_filenames; 310 309 unsigned int num_ros; 310 + unsigned int num_nofuas; 311 311 unsigned int nluns; 312 312 313 313 int removable; ··· 348 344 349 345 module_param_array_named(ro, mod_data.ro, bool, &mod_data.num_ros, S_IRUGO); 350 346 MODULE_PARM_DESC(ro, "true to force read-only"); 347 + 348 + module_param_array_named(nofua, mod_data.nofua, bool, &mod_data.num_nofuas, 349 + S_IRUGO); 350 + MODULE_PARM_DESC(nofua, "true to ignore SCSI WRITE(10,12) FUA bit"); 351 351 352 352 module_param_named(luns, mod_data.nluns, uint, S_IRUGO); 353 353 MODULE_PARM_DESC(luns, "number of LUNs"); ··· 1287 1279 curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 1288 1280 return -EINVAL; 1289 1281 } 1290 - if (fsg->cmnd[1] & 0x08) { // FUA 1282 + /* FUA */ 1283 + if (!curlun->nofua && (fsg->cmnd[1] & 0x08)) { 1291 1284 spin_lock(&curlun->filp->f_lock); 1292 1285 curlun->filp->f_flags |= O_DSYNC; 1293 1286 spin_unlock(&curlun->filp->f_lock); ··· 3142 3133 3143 3134 /* The write permissions and store_xxx pointers are set in fsg_bind() */ 3144 3135 static DEVICE_ATTR(ro, 0444, fsg_show_ro, NULL); 3136 + static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, NULL); 3145 3137 static DEVICE_ATTR(file, 0444, fsg_show_file, NULL); 3146 3138 3147 3139 ··· 3372 3362 } 3373 3363 } 3374 3364 3365 + /* Only for removable media? */ 3366 + dev_attr_nofua.attr.mode = 0644; 3367 + dev_attr_nofua.store = fsg_store_nofua; 3368 + 3375 3369 /* Find out how many LUNs there should be */ 3376 3370 i = mod_data.nluns; 3377 3371 if (i == 0) ··· 3401 3387 curlun->ro = mod_data.cdrom || mod_data.ro[i]; 3402 3388 curlun->initially_ro = curlun->ro; 3403 3389 curlun->removable = mod_data.removable; 3390 + curlun->nofua = mod_data.nofua[i]; 3404 3391 curlun->dev.release = lun_release; 3405 3392 curlun->dev.parent = &gadget->dev; 3406 3393 curlun->dev.driver = &fsg_driver.driver; ··· 3415 3400 } 3416 3401 if ((rc = device_create_file(&curlun->dev, 3417 3402 &dev_attr_ro)) != 0 || 3403 + (rc = device_create_file(&curlun->dev, 3404 + &dev_attr_nofua)) != 0 || 3418 3405 (rc = device_create_file(&curlun->dev, 3419 3406 &dev_attr_file)) != 0) { 3420 3407 device_unregister(&curlun->dev); ··· 3542 3525 if (IS_ERR(p)) 3543 3526 p = NULL; 3544 3527 } 3545 - LINFO(curlun, "ro=%d, file: %s\n", 3546 - curlun->ro, (p ? p : "(error)")); 3528 + LINFO(curlun, "ro=%d, nofua=%d, file: %s\n", 3529 + curlun->ro, curlun->nofua, (p ? p : "(error)")); 3547 3530 } 3548 3531 } 3549 3532 kfree(pathbuf);
+28
drivers/usb/gadget/storage_common.c
··· 284 284 unsigned int prevent_medium_removal:1; 285 285 unsigned int registered:1; 286 286 unsigned int info_valid:1; 287 + unsigned int nofua:1; 287 288 288 289 u32 sense_data; 289 290 u32 sense_data_info; ··· 715 714 : curlun->initially_ro); 716 715 } 717 716 717 + static ssize_t fsg_show_nofua(struct device *dev, struct device_attribute *attr, 718 + char *buf) 719 + { 720 + struct fsg_lun *curlun = fsg_lun_from_dev(dev); 721 + 722 + return sprintf(buf, "%u\n", curlun->nofua); 723 + } 724 + 718 725 static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr, 719 726 char *buf) 720 727 { ··· 777 768 } 778 769 up_read(filesem); 779 770 return rc; 771 + } 772 + 773 + static ssize_t fsg_store_nofua(struct device *dev, 774 + struct device_attribute *attr, 775 + const char *buf, size_t count) 776 + { 777 + struct fsg_lun *curlun = fsg_lun_from_dev(dev); 778 + unsigned long nofua; 779 + 780 + if (strict_strtoul(buf, 2, &nofua)) 781 + return -EINVAL; 782 + 783 + /* Sync data when switching from async mode to sync */ 784 + if (!nofua && curlun->nofua) 785 + fsg_lun_fsync_sub(curlun); 786 + 787 + curlun->nofua = nofua; 788 + 789 + return count; 780 790 } 781 791 782 792 static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr,