// SPDX-License-Identifier: GPL-2.0+
/*
* Driver for USB Mass Storage compliant devices
*
* Current development and maintenance by:
* (c) 1999-2003 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
* Developed with the assistance of:
* (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
* (c) 2003-2009 Alan Stern (stern@rowland.harvard.edu)
*
* Initial work by:
* (c) 1999 Michael Gee (michael@linuxspecific.com)
*
* usb_device_id support by Adam J. Richter (adam@yggdrasil.com):
* (c) 2000 Yggdrasil Computing, Inc.
*
* This driver is based on the 'USB Mass Storage Class' document. This
* describes in detail the protocol used to communicate with such
* devices. Clearly, the designers had SCSI and ATAPI commands in
* mind when they created this document. The commands are all very
* similar to commands in the SCSI-II and ATAPI specifications.
*
* It is important to note that in a number of cases this class
* exhibits class-specific exemptions from the USB specification.
* Notably the usage of NAK, STALL and ACK differs from the norm, in
* that they are used to communicate wait, failed and OK on commands.
*
* Also, for certain devices, the interrupt endpoint is used to convey
* status of a command.
*/
#ifdef CONFIG_USB_STORAGE_DEBUG
#define DEBUG
#endif
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/kthread.h>
#include <linux/mutex.h>
#include <linux/utsname.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include "usb.h"
#include <linux/usb/hcd.h>
#include "scsiglue.h"
#include "transport.h"
#include "protocol.h"
#include "debug.h"
#include "initializers.h"
#include "sierra_ms.h"
#include "option_ms.h"
#if IS_ENABLED(CONFIG_USB_UAS)
#include "uas-detect.h"
#endif
#define DRV_NAME "usb-storage"
/* Some informational data */
MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
MODULE_DESCRIPTION("USB Mass Storage driver for Linux");
MODULE_LICENSE("GPL");
static unsigned int delay_use = 1 * MSEC_PER_SEC;
/**
* parse_delay_str - parse an unsigned decimal integer delay
* @str: String to parse.
* @ndecimals: Number of decimal to scale up.
* @suffix: Suffix string to parse.
* @val: Where to store the parsed value.
*
* Parse an unsigned decimal value in @str, optionally end with @suffix.
* Stores the parsed value in @val just as it is if @str ends with @suffix.
* Otherwise store the value scale up by 10^(@ndecimal).
*
* Returns 0 on success, a negative error code otherwise.
*/
static int parse_delay_str(const char *str, int ndecimals, const char *suffix,
unsigned int *val)
{
int n, n2, l;
char buf[16];
l = strlen(suffix);
n = strlen(str);
if (n > 0 && str[n - 1] == '\n')
--n;
if (n >= l && !strncmp(&str[n - l], suffix, l)) {
n -= l;
n2 = 0;
} else
n2 = ndecimals;
if (n + n2 > sizeof(buf) - 1)
return -EINVAL;
memcpy(buf, str, n);
while (n2-- > 0)
buf[n++] = '0';
buf[n] = 0;
return kstrtouint(buf, 10, val);
}
/**
* format_delay_ms - format an integer value into a delay string
* @val: The integer value to format, scaled by 10^(@ndecimals).
* @ndecimals: Number of decimal to scale down.
* @suffix: Suffix string to format.
* @str: Where to store the formatted string.
* @size: The size of buffer for @str.
*
* Format an integer value in @val scale down by 10^(@ndecimals) without @suffix
* if @val is divisible by 10^(@ndecimals).
* Otherwise format a value in @val just as it is with @suffix
*
* Returns the number of characters written into @str.
*/
static int format_delay_ms(unsigned int val, int ndecimals, const char *suffix,
char *str, int size)
{
u64 delay_ms = val;
unsigned int rem = do_div(delay_ms, int_pow(10, ndecimals));
int ret;
if (rem)
ret = scnprintf(str, size, "%u%s\n", val, suffix);
else
ret = scnprintf(str, size, "%u\n", (unsigned int)delay_ms);
return ret;
}
static int delay_use_set(const char *s, const struct kernel_param *kp)
{
unsigned int delay_ms;
int ret;
ret