diff options
-rw-r--r-- | Documentation/ABI/testing/sysfs-devices-platform-_UDC_-gadget | 12 | ||||
-rw-r--r-- | drivers/usb/gadget/file_storage.c | 31 | ||||
-rw-r--r-- | drivers/usb/gadget/storage_common.c | 28 |
3 files changed, 64 insertions, 7 deletions
diff --git a/Documentation/ABI/testing/sysfs-devices-platform-_UDC_-gadget b/Documentation/ABI/testing/sysfs-devices-platform-_UDC_-gadget index 34034027b13c..d548eaac230a 100644 --- a/Documentation/ABI/testing/sysfs-devices-platform-_UDC_-gadget +++ b/Documentation/ABI/testing/sysfs-devices-platform-_UDC_-gadget | |||
@@ -7,3 +7,15 @@ Description: | |||
7 | 0 -> resumed | 7 | 0 -> resumed |
8 | 8 | ||
9 | (_UDC_ is the name of the USB Device Controller driver) | 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 | ||
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index d57c09f764d6..88e5ad2bc710 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c | |||
@@ -93,6 +93,8 @@ | |||
93 | * removable Default false, boolean for removable media | 93 | * removable Default false, boolean for removable media |
94 | * luns=N Default N = number of filenames, number of | 94 | * luns=N Default N = number of filenames, number of |
95 | * LUNs to support | 95 | * LUNs to support |
96 | * nofua=b[,b...] Default false, booleans for ignore FUA flag | ||
97 | * in SCSI WRITE(10,12) commands | ||
96 | * stall Default determined according to the type of | 98 | * stall Default determined according to the type of |
97 | * USB device controller (usually true), | 99 | * USB device controller (usually true), |
98 | * boolean to permit the driver to halt | 100 | * boolean to permit the driver to halt |
@@ -112,12 +114,12 @@ | |||
112 | * PAGE_CACHE_SIZE) | 114 | * PAGE_CACHE_SIZE) |
113 | * | 115 | * |
114 | * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro", | 116 | * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro", |
115 | * "removable", "luns", "stall", and "cdrom" options are available; default | 117 | * "removable", "luns", "nofua", "stall", and "cdrom" options are available; |
116 | * values are used for everything else. | 118 | * default values are used for everything else. |
117 | * | 119 | * |
118 | * The pathnames of the backing files and the ro settings are available in | 120 | * The pathnames of the backing files and the ro settings are available in |
119 | * the attribute files "file" and "ro" in the lun<n> subdirectory of the | 121 | * the attribute files "file", "nofua", and "ro" in the lun<n> subdirectory of |
120 | * gadget's sysfs directory. If the "removable" option is set, writing to | 122 | * the gadget's sysfs directory. If the "removable" option is set, writing to |
121 | * these files will simulate ejecting/loading the medium (writing an empty | 123 | * these files will simulate ejecting/loading the medium (writing an empty |
122 | * line means eject) and adjusting a write-enable tab. Changes to the ro | 124 | * line means eject) and adjusting a write-enable tab. Changes to the ro |
123 | * setting are not allowed when the medium is loaded or if CD-ROM emulation | 125 | * setting are not allowed when the medium is loaded or if CD-ROM emulation |
@@ -304,8 +306,10 @@ MODULE_LICENSE("Dual BSD/GPL"); | |||
304 | static struct { | 306 | static struct { |
305 | char *file[FSG_MAX_LUNS]; | 307 | char *file[FSG_MAX_LUNS]; |
306 | int ro[FSG_MAX_LUNS]; | 308 | int ro[FSG_MAX_LUNS]; |
309 | int nofua[FSG_MAX_LUNS]; | ||
307 | unsigned int num_filenames; | 310 | unsigned int num_filenames; |
308 | unsigned int num_ros; | 311 | unsigned int num_ros; |
312 | unsigned int num_nofuas; | ||
309 | unsigned int nluns; | 313 | unsigned int nluns; |
310 | 314 | ||
311 | int removable; | 315 | int removable; |
@@ -345,6 +349,10 @@ MODULE_PARM_DESC(file, "names of backing files or devices"); | |||
345 | module_param_array_named(ro, mod_data.ro, bool, &mod_data.num_ros, S_IRUGO); | 349 | module_param_array_named(ro, mod_data.ro, bool, &mod_data.num_ros, S_IRUGO); |
346 | MODULE_PARM_DESC(ro, "true to force read-only"); | 350 | MODULE_PARM_DESC(ro, "true to force read-only"); |
347 | 351 | ||
352 | module_param_array_named(nofua, mod_data.nofua, bool, &mod_data.num_nofuas, | ||
353 | S_IRUGO); | ||
354 | MODULE_PARM_DESC(nofua, "true to ignore SCSI WRITE(10,12) FUA bit"); | ||
355 | |||
348 | module_param_named(luns, mod_data.nluns, uint, S_IRUGO); | 356 | module_param_named(luns, mod_data.nluns, uint, S_IRUGO); |
349 | MODULE_PARM_DESC(luns, "number of LUNs"); | 357 | MODULE_PARM_DESC(luns, "number of LUNs"); |
350 | 358 | ||
@@ -1279,7 +1287,8 @@ static int do_write(struct fsg_dev *fsg) | |||
1279 | curlun->sense_data = SS_INVALID_FIELD_IN_CDB; | 1287 | curlun->sense_data = SS_INVALID_FIELD_IN_CDB; |
1280 | return -EINVAL; | 1288 | return -EINVAL; |
1281 | } | 1289 | } |
1282 | if (fsg->cmnd[1] & 0x08) { // FUA | 1290 | /* FUA */ |
1291 | if (!curlun->nofua && (fsg->cmnd[1] & 0x08)) { | ||
1283 | spin_lock(&curlun->filp->f_lock); | 1292 | spin_lock(&curlun->filp->f_lock); |
1284 | curlun->filp->f_flags |= O_DSYNC; | 1293 | curlun->filp->f_flags |= O_DSYNC; |
1285 | spin_unlock(&curlun->filp->f_lock); | 1294 | spin_unlock(&curlun->filp->f_lock); |
@@ -3133,6 +3142,7 @@ static int fsg_main_thread(void *fsg_) | |||
3133 | 3142 | ||
3134 | /* The write permissions and store_xxx pointers are set in fsg_bind() */ | 3143 | /* The write permissions and store_xxx pointers are set in fsg_bind() */ |
3135 | static DEVICE_ATTR(ro, 0444, fsg_show_ro, NULL); | 3144 | static DEVICE_ATTR(ro, 0444, fsg_show_ro, NULL); |
3145 | static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, NULL); | ||
3136 | static DEVICE_ATTR(file, 0444, fsg_show_file, NULL); | 3146 | static DEVICE_ATTR(file, 0444, fsg_show_file, NULL); |
3137 | 3147 | ||
3138 | 3148 | ||
@@ -3362,6 +3372,10 @@ static int __ref fsg_bind(struct usb_gadget *gadget) | |||
3362 | } | 3372 | } |
3363 | } | 3373 | } |
3364 | 3374 | ||
3375 | /* Only for removable media? */ | ||
3376 | dev_attr_nofua.attr.mode = 0644; | ||
3377 | dev_attr_nofua.store = fsg_store_nofua; | ||
3378 | |||
3365 | /* Find out how many LUNs there should be */ | 3379 | /* Find out how many LUNs there should be */ |
3366 | i = mod_data.nluns; | 3380 | i = mod_data.nluns; |
3367 | if (i == 0) | 3381 | if (i == 0) |
@@ -3387,6 +3401,7 @@ static int __ref fsg_bind(struct usb_gadget *gadget) | |||
3387 | curlun->ro = mod_data.cdrom || mod_data.ro[i]; | 3401 | curlun->ro = mod_data.cdrom || mod_data.ro[i]; |
3388 | curlun->initially_ro = curlun->ro; | 3402 | curlun->initially_ro = curlun->ro; |
3389 | curlun->removable = mod_data.removable; | 3403 | curlun->removable = mod_data.removable; |
3404 | curlun->nofua = mod_data.nofua[i]; | ||
3390 | curlun->dev.release = lun_release; | 3405 | curlun->dev.release = lun_release; |
3391 | curlun->dev.parent = &gadget->dev; | 3406 | curlun->dev.parent = &gadget->dev; |
3392 | curlun->dev.driver = &fsg_driver.driver; | 3407 | curlun->dev.driver = &fsg_driver.driver; |
@@ -3401,6 +3416,8 @@ static int __ref fsg_bind(struct usb_gadget *gadget) | |||
3401 | if ((rc = device_create_file(&curlun->dev, | 3416 | if ((rc = device_create_file(&curlun->dev, |
3402 | &dev_attr_ro)) != 0 || | 3417 | &dev_attr_ro)) != 0 || |
3403 | (rc = device_create_file(&curlun->dev, | 3418 | (rc = device_create_file(&curlun->dev, |
3419 | &dev_attr_nofua)) != 0 || | ||
3420 | (rc = device_create_file(&curlun->dev, | ||
3404 | &dev_attr_file)) != 0) { | 3421 | &dev_attr_file)) != 0) { |
3405 | device_unregister(&curlun->dev); | 3422 | device_unregister(&curlun->dev); |
3406 | goto out; | 3423 | goto out; |
@@ -3525,8 +3542,8 @@ static int __ref fsg_bind(struct usb_gadget *gadget) | |||
3525 | if (IS_ERR(p)) | 3542 | if (IS_ERR(p)) |
3526 | p = NULL; | 3543 | p = NULL; |
3527 | } | 3544 | } |
3528 | LINFO(curlun, "ro=%d, file: %s\n", | 3545 | LINFO(curlun, "ro=%d, nofua=%d, file: %s\n", |
3529 | curlun->ro, (p ? p : "(error)")); | 3546 | curlun->ro, curlun->nofua, (p ? p : "(error)")); |
3530 | } | 3547 | } |
3531 | } | 3548 | } |
3532 | kfree(pathbuf); | 3549 | kfree(pathbuf); |
diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index 3bbddab72e57..484acfb1a7c5 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c | |||
@@ -284,6 +284,7 @@ struct fsg_lun { | |||
284 | unsigned int prevent_medium_removal:1; | 284 | unsigned int prevent_medium_removal:1; |
285 | unsigned int registered:1; | 285 | unsigned int registered:1; |
286 | unsigned int info_valid:1; | 286 | unsigned int info_valid:1; |
287 | unsigned int nofua:1; | ||
287 | 288 | ||
288 | u32 sense_data; | 289 | u32 sense_data; |
289 | u32 sense_data_info; | 290 | u32 sense_data_info; |
@@ -714,6 +715,14 @@ static ssize_t fsg_show_ro(struct device *dev, struct device_attribute *attr, | |||
714 | : curlun->initially_ro); | 715 | : curlun->initially_ro); |
715 | } | 716 | } |
716 | 717 | ||
718 | static ssize_t fsg_show_nofua(struct device *dev, struct device_attribute *attr, | ||
719 | char *buf) | ||
720 | { | ||
721 | struct fsg_lun *curlun = fsg_lun_from_dev(dev); | ||
722 | |||
723 | return sprintf(buf, "%u\n", curlun->nofua); | ||
724 | } | ||
725 | |||
717 | static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr, | 726 | static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr, |
718 | char *buf) | 727 | char *buf) |
719 | { | 728 | { |
@@ -770,6 +779,25 @@ static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr, | |||
770 | return rc; | 779 | return rc; |
771 | } | 780 | } |
772 | 781 | ||
782 | static ssize_t fsg_store_nofua(struct device *dev, | ||
783 | struct device_attribute *attr, | ||
784 | const char *buf, size_t count) | ||
785 | { | ||
786 | struct fsg_lun *curlun = fsg_lun_from_dev(dev); | ||
787 | unsigned long nofua; | ||
788 | |||
789 | if (strict_strtoul(buf, 2, &nofua)) | ||
790 | return -EINVAL; | ||
791 | |||
792 | /* Sync data when switching from async mode to sync */ | ||
793 | if (!nofua && curlun->nofua) | ||
794 | fsg_lun_fsync_sub(curlun); | ||
795 | |||
796 | curlun->nofua = nofua; | ||
797 | |||
798 | return count; | ||
799 | } | ||
800 | |||
773 | static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr, | 801 | static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr, |
774 | const char *buf, size_t count) | 802 | const char *buf, size_t count) |
775 | { | 803 | { |