v4.19.13 snapshot.
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
new file mode 100644
index 0000000..ec84758
--- /dev/null
+++ b/drivers/usb/storage/Kconfig
@@ -0,0 +1,214 @@
+#
+# USB Storage driver configuration
+#
+
+comment "NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may"
+comment "also be needed; see USB_STORAGE Help for more info"
+
+config USB_STORAGE
+	tristate "USB Mass Storage support"
+	depends on SCSI
+	---help---
+	  Say Y here if you want to connect USB mass storage devices to your
+	  computer's USB port. This is the driver you need for USB
+	  floppy drives, USB hard disks, USB tape drives, USB CD-ROMs,
+	  USB flash devices, and memory sticks, along with
+	  similar devices. This driver may also be used for some cameras
+	  and card readers.
+
+	  This option depends on 'SCSI' support being enabled, but you
+	  probably also need 'SCSI device support: SCSI disk support'
+	  (BLK_DEV_SD) for most USB storage devices.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called usb-storage.
+
+config USB_STORAGE_DEBUG
+	bool "USB Mass Storage verbose debug"
+	depends on USB_STORAGE
+	help
+	  Say Y here in order to have the USB Mass Storage code generate
+	  verbose debugging messages.
+
+config USB_STORAGE_REALTEK
+	tristate "Realtek Card Reader support"
+	depends on USB_STORAGE
+	help
+	  Say Y here to include additional code to support the power-saving function
+	  for Realtek RTS51xx USB card readers.
+
+	  If this driver is compiled as a module, it will be named ums-realtek.
+
+config REALTEK_AUTOPM
+	bool "Realtek Card Reader autosuspend support"
+	depends on USB_STORAGE_REALTEK && PM
+	default y
+
+config USB_STORAGE_DATAFAB
+	tristate "Datafab Compact Flash Reader support"
+	depends on USB_STORAGE
+	help
+	  Support for certain Datafab CompactFlash readers.
+	  Datafab has a web page at <http://www.datafab.com/>.
+
+	  If this driver is compiled as a module, it will be named ums-datafab.
+
+config USB_STORAGE_FREECOM
+	tristate "Freecom USB/ATAPI Bridge support"
+	depends on USB_STORAGE
+	help
+	  Support for the Freecom USB to IDE/ATAPI adaptor.
+	  Freecom has a web page at <http://www.freecom.de/>.
+
+	  If this driver is compiled as a module, it will be named ums-freecom.
+
+config USB_STORAGE_ISD200
+	tristate "ISD-200 USB/ATA Bridge support"
+	depends on USB_STORAGE
+	---help---
+	  Say Y here if you want to use USB Mass Store devices based
+	  on the In-Systems Design ISD-200 USB/ATA bridge.
+
+	  Some of the products that use this chip are:
+
+	  - Archos Jukebox 6000
+	  - ISD SmartCable for Storage
+	  - Taiwan Skymaster CD530U/DEL-0241 IDE bridge
+	  - Sony CRX10U CD-R/RW drive
+	  - CyQ've CQ8060A CDRW drive
+	  - Planex eXtreme Drive RX-25HU USB-IDE cable (not model RX-25U)
+
+	  If this driver is compiled as a module, it will be named ums-isd200.
+
+config USB_STORAGE_USBAT
+	tristate "USBAT/USBAT02-based storage support"
+	depends on USB_STORAGE
+	help
+	  Say Y here to include additional code to support storage devices
+	  based on the SCM/Shuttle USBAT/USBAT02 processors.
+
+	  Devices reported to work with this driver include:
+	  - CompactFlash reader included with Kodak DC3800 camera
+	  - Dane-Elec Zmate CompactFlash reader
+	  - Delkin Efilm reader2
+	  - HP 8200e/8210e/8230e CD-Writer Plus drives
+	  - I-JAM JS-50U
+	  - Jessops CompactFlash JESDCFRU BLACK
+	  - Kingston Technology PCREAD-USB/CF
+	  - Maxell UA4 CompactFlash reader
+	  - Memorex UCF-100
+	  - Microtech ZiO! ICS-45 CF2
+	  - RCA LYRA MP3 portable
+	  - Sandisk ImageMate SDDR-05b
+
+	  If this driver is compiled as a module, it will be named ums-usbat.
+
+config USB_STORAGE_SDDR09
+	tristate "SanDisk SDDR-09 (and other SmartMedia, including DPCM) support"
+	depends on USB_STORAGE
+	help
+	  Say Y here to include additional code to support the Sandisk SDDR-09
+	  SmartMedia reader in the USB Mass Storage driver.
+	  Also works for the Microtech Zio! CompactFlash/SmartMedia reader.
+
+	  If this driver is compiled as a module, it will be named ums-sddr09.
+
+config USB_STORAGE_SDDR55
+	tristate "SanDisk SDDR-55 SmartMedia support"
+	depends on USB_STORAGE
+	help
+	  Say Y here to include additional code to support the Sandisk SDDR-55
+	  SmartMedia reader in the USB Mass Storage driver.
+
+	  If this driver is compiled as a module, it will be named ums-sddr55.
+
+config USB_STORAGE_JUMPSHOT
+	tristate "Lexar Jumpshot Compact Flash Reader"
+	depends on USB_STORAGE
+	help
+	  Say Y here to include additional code to support the Lexar Jumpshot
+	  USB CompactFlash reader.
+
+	  If this driver is compiled as a module, it will be named ums-jumpshot.
+
+config USB_STORAGE_ALAUDA
+	tristate "Olympus MAUSB-10/Fuji DPC-R1 support"
+	depends on USB_STORAGE
+	help
+	  Say Y here to include additional code to support the Olympus MAUSB-10
+	  and Fujifilm DPC-R1 USB Card reader/writer devices.
+
+	  These devices are based on the Alauda chip and support both
+	  XD and SmartMedia cards.
+
+	  If this driver is compiled as a module, it will be named ums-alauda.
+
+config USB_STORAGE_ONETOUCH
+	tristate "Support OneTouch Button on Maxtor Hard Drives"
+	depends on USB_STORAGE
+	depends on INPUT=y || INPUT=USB_STORAGE
+	help
+	  Say Y here to include additional code to support the Maxtor OneTouch
+	  USB hard drive's onetouch button.
+
+	  This code registers the button on the front of Maxtor OneTouch USB
+	  hard drive's as an input device. An action can be associated with
+	  this input in any keybinding software. (e.g. gnome's keyboard short-
+	  cuts)
+
+	  If this driver is compiled as a module, it will be named ums-onetouch.
+
+config USB_STORAGE_KARMA
+	tristate "Support for Rio Karma music player"
+	depends on USB_STORAGE
+	help
+	  Say Y here to include additional code to support the Rio Karma
+	  USB interface.
+
+	  This code places the Rio Karma into mass storage mode, enabling
+	  it to be mounted as an ordinary filesystem. Performing an eject
+	  on the resulting scsi device node returns the Karma to normal
+	  operation.
+
+	  If this driver is compiled as a module, it will be named ums-karma.
+
+config USB_STORAGE_CYPRESS_ATACB
+	tristate "SAT emulation on Cypress USB/ATA Bridge with ATACB"
+	depends on USB_STORAGE
+	---help---
+	  Say Y here if you want to use SAT (ata pass through) on devices based
+	  on the Cypress USB/ATA bridge supporting ATACB. This will allow you
+	  to use tools to tune and monitor your drive (like hdparm or smartctl).
+
+	  If you say no here your device will still work with the standard usb
+	  mass storage class.
+
+	  If this driver is compiled as a module, it will be named ums-cypress.
+
+config USB_STORAGE_ENE_UB6250
+	tristate "USB ENE card reader support"
+	depends on SCSI
+	depends on USB_STORAGE
+	---help---
+	  Say Y here if you wish to control a ENE SD/MS Card reader.
+	  Note that this driver does not support SM cards.
+
+	  This option depends on 'SCSI' support being enabled, but you
+	  probably also need 'SCSI device support: SCSI disk support'
+	  (BLK_DEV_SD) for most USB storage devices.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ums-eneub6250.
+
+config USB_UAS
+	tristate "USB Attached SCSI"
+	depends on SCSI && USB_STORAGE
+	help
+	  The USB Attached SCSI protocol is supported by some USB
+	  storage devices.  It permits higher performance by supporting
+	  multiple outstanding commands.
+
+	  If you don't know whether you have a UAS device, it is safe to
+	  say 'Y' or 'M' here and the kernel will use the right driver.
+
+	  If you compile this driver as a module, it will be named uas.
diff --git a/drivers/usb/storage/Makefile b/drivers/usb/storage/Makefile
new file mode 100644
index 0000000..c5126a4
--- /dev/null
+++ b/drivers/usb/storage/Makefile
@@ -0,0 +1,45 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the USB Mass Storage device drivers.
+#
+# 15 Aug 2000, Christoph Hellwig <hch@infradead.org>
+# Rewritten to use lists instead of if-statements.
+#
+
+ccflags-y := -Idrivers/scsi
+
+obj-$(CONFIG_USB_UAS)		+= uas.o
+obj-$(CONFIG_USB_STORAGE)	+= usb-storage.o
+
+usb-storage-y := scsiglue.o protocol.o transport.o usb.o
+usb-storage-y += initializers.o sierra_ms.o option_ms.o
+usb-storage-y += usual-tables.o
+usb-storage-$(CONFIG_USB_STORAGE_DEBUG) += debug.o
+
+obj-$(CONFIG_USB_STORAGE_ALAUDA)	+= ums-alauda.o
+obj-$(CONFIG_USB_STORAGE_CYPRESS_ATACB) += ums-cypress.o
+obj-$(CONFIG_USB_STORAGE_DATAFAB)	+= ums-datafab.o
+obj-$(CONFIG_USB_STORAGE_ENE_UB6250)	+= ums-eneub6250.o
+obj-$(CONFIG_USB_STORAGE_FREECOM)	+= ums-freecom.o
+obj-$(CONFIG_USB_STORAGE_ISD200)	+= ums-isd200.o
+obj-$(CONFIG_USB_STORAGE_JUMPSHOT)	+= ums-jumpshot.o
+obj-$(CONFIG_USB_STORAGE_KARMA)		+= ums-karma.o
+obj-$(CONFIG_USB_STORAGE_ONETOUCH)	+= ums-onetouch.o
+obj-$(CONFIG_USB_STORAGE_REALTEK)	+= ums-realtek.o
+obj-$(CONFIG_USB_STORAGE_SDDR09)	+= ums-sddr09.o
+obj-$(CONFIG_USB_STORAGE_SDDR55)	+= ums-sddr55.o
+obj-$(CONFIG_USB_STORAGE_USBAT)		+= ums-usbat.o
+
+ums-alauda-y		:= alauda.o
+ums-cypress-y		:= cypress_atacb.o
+ums-datafab-y		:= datafab.o
+ums-eneub6250-y		:= ene_ub6250.o
+ums-freecom-y		:= freecom.o
+ums-isd200-y		:= isd200.o
+ums-jumpshot-y		:= jumpshot.o
+ums-karma-y		:= karma.o
+ums-onetouch-y		:= onetouch.o
+ums-realtek-y		:= realtek_cr.o
+ums-sddr09-y		:= sddr09.o
+ums-sddr55-y		:= sddr55.o
+ums-usbat-y		:= shuttle_usbat.o
diff --git a/drivers/usb/storage/alauda.c b/drivers/usb/storage/alauda.c
new file mode 100644
index 0000000..6b8edf6
--- /dev/null
+++ b/drivers/usb/storage/alauda.c
@@ -0,0 +1,1263 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for Alauda-based card readers
+ *
+ * Current development and maintenance by:
+ *   (c) 2005 Daniel Drake <dsd@gentoo.org>
+ *
+ * The 'Alauda' is a chip manufacturered by RATOC for OEM use.
+ *
+ * Alauda implements a vendor-specific command set to access two media reader
+ * ports (XD, SmartMedia). This driver converts SCSI commands to the commands
+ * which are accepted by these devices.
+ *
+ * The driver was developed through reverse-engineering, with the help of the
+ * sddr09 driver which has many similarities, and with some help from the
+ * (very old) vendor-supplied GPL sma03 driver.
+ *
+ * For protocol info, see http://alauda.sourceforge.net
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "protocol.h"
+#include "debug.h"
+#include "scsiglue.h"
+
+#define DRV_NAME "ums-alauda"
+
+MODULE_DESCRIPTION("Driver for Alauda-based card readers");
+MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>");
+MODULE_LICENSE("GPL");
+
+/*
+ * Status bytes
+ */
+#define ALAUDA_STATUS_ERROR		0x01
+#define ALAUDA_STATUS_READY		0x40
+
+/*
+ * Control opcodes (for request field)
+ */
+#define ALAUDA_GET_XD_MEDIA_STATUS	0x08
+#define ALAUDA_GET_SM_MEDIA_STATUS	0x98
+#define ALAUDA_ACK_XD_MEDIA_CHANGE	0x0a
+#define ALAUDA_ACK_SM_MEDIA_CHANGE	0x9a
+#define ALAUDA_GET_XD_MEDIA_SIG		0x86
+#define ALAUDA_GET_SM_MEDIA_SIG		0x96
+
+/*
+ * Bulk command identity (byte 0)
+ */
+#define ALAUDA_BULK_CMD			0x40
+
+/*
+ * Bulk opcodes (byte 1)
+ */
+#define ALAUDA_BULK_GET_REDU_DATA	0x85
+#define ALAUDA_BULK_READ_BLOCK		0x94
+#define ALAUDA_BULK_ERASE_BLOCK		0xa3
+#define ALAUDA_BULK_WRITE_BLOCK		0xb4
+#define ALAUDA_BULK_GET_STATUS2		0xb7
+#define ALAUDA_BULK_RESET_MEDIA		0xe0
+
+/*
+ * Port to operate on (byte 8)
+ */
+#define ALAUDA_PORT_XD			0x00
+#define ALAUDA_PORT_SM			0x01
+
+/*
+ * LBA and PBA are unsigned ints. Special values.
+ */
+#define UNDEF    0xffff
+#define SPARE    0xfffe
+#define UNUSABLE 0xfffd
+
+struct alauda_media_info {
+	unsigned long capacity;		/* total media size in bytes */
+	unsigned int pagesize;		/* page size in bytes */
+	unsigned int blocksize;		/* number of pages per block */
+	unsigned int uzonesize;		/* number of usable blocks per zone */
+	unsigned int zonesize;		/* number of blocks per zone */
+	unsigned int blockmask;		/* mask to get page from address */
+
+	unsigned char pageshift;
+	unsigned char blockshift;
+	unsigned char zoneshift;
+
+	u16 **lba_to_pba;		/* logical to physical block map */
+	u16 **pba_to_lba;		/* physical to logical block map */
+};
+
+struct alauda_info {
+	struct alauda_media_info port[2];
+	int wr_ep;			/* endpoint to write data out of */
+
+	unsigned char sense_key;
+	unsigned long sense_asc;	/* additional sense code */
+	unsigned long sense_ascq;	/* additional sense code qualifier */
+};
+
+#define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) )
+#define LSB_of(s) ((s)&0xFF)
+#define MSB_of(s) ((s)>>8)
+
+#define MEDIA_PORT(us) us->srb->device->lun
+#define MEDIA_INFO(us) ((struct alauda_info *)us->extra)->port[MEDIA_PORT(us)]
+
+#define PBA_LO(pba) ((pba & 0xF) << 5)
+#define PBA_HI(pba) (pba >> 3)
+#define PBA_ZONE(pba) (pba >> 11)
+
+static int init_alauda(struct us_data *us);
+
+
+/*
+ * The table of devices
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+		    vendorName, productName, useProtocol, useTransport, \
+		    initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+  .driver_info = (flags) }
+
+static struct usb_device_id alauda_usb_ids[] = {
+#	include "unusual_alauda.h"
+	{ }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, alauda_usb_ids);
+
+#undef UNUSUAL_DEV
+
+/*
+ * The flags table
+ */
+#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
+		    vendor_name, product_name, use_protocol, use_transport, \
+		    init_function, Flags) \
+{ \
+	.vendorName = vendor_name,	\
+	.productName = product_name,	\
+	.useProtocol = use_protocol,	\
+	.useTransport = use_transport,	\
+	.initFunction = init_function,	\
+}
+
+static struct us_unusual_dev alauda_unusual_dev_list[] = {
+#	include "unusual_alauda.h"
+	{ }		/* Terminating entry */
+};
+
+#undef UNUSUAL_DEV
+
+
+/*
+ * Media handling
+ */
+
+struct alauda_card_info {
+	unsigned char id;		/* id byte */
+	unsigned char chipshift;	/* 1<<cs bytes total capacity */
+	unsigned char pageshift;	/* 1<<ps bytes in a page */
+	unsigned char blockshift;	/* 1<<bs pages per block */
+	unsigned char zoneshift;	/* 1<<zs blocks per zone */
+};
+
+static struct alauda_card_info alauda_card_ids[] = {
+	/* NAND flash */
+	{ 0x6e, 20, 8, 4, 8},	/* 1 MB */
+	{ 0xe8, 20, 8, 4, 8},	/* 1 MB */
+	{ 0xec, 20, 8, 4, 8},	/* 1 MB */
+	{ 0x64, 21, 8, 4, 9}, 	/* 2 MB */
+	{ 0xea, 21, 8, 4, 9},	/* 2 MB */
+	{ 0x6b, 22, 9, 4, 9},	/* 4 MB */
+	{ 0xe3, 22, 9, 4, 9},	/* 4 MB */
+	{ 0xe5, 22, 9, 4, 9},	/* 4 MB */
+	{ 0xe6, 23, 9, 4, 10},	/* 8 MB */
+	{ 0x73, 24, 9, 5, 10},	/* 16 MB */
+	{ 0x75, 25, 9, 5, 10},	/* 32 MB */
+	{ 0x76, 26, 9, 5, 10},	/* 64 MB */
+	{ 0x79, 27, 9, 5, 10},	/* 128 MB */
+	{ 0x71, 28, 9, 5, 10},	/* 256 MB */
+
+	/* MASK ROM */
+	{ 0x5d, 21, 9, 4, 8},	/* 2 MB */
+	{ 0xd5, 22, 9, 4, 9},	/* 4 MB */
+	{ 0xd6, 23, 9, 4, 10},	/* 8 MB */
+	{ 0x57, 24, 9, 4, 11},	/* 16 MB */
+	{ 0x58, 25, 9, 4, 12},	/* 32 MB */
+	{ 0,}
+};
+
+static struct alauda_card_info *alauda_card_find_id(unsigned char id)
+{
+	int i;
+
+	for (i = 0; alauda_card_ids[i].id != 0; i++)
+		if (alauda_card_ids[i].id == id)
+			return &(alauda_card_ids[i]);
+	return NULL;
+}
+
+/*
+ * ECC computation.
+ */
+
+static unsigned char parity[256];
+static unsigned char ecc2[256];
+
+static void nand_init_ecc(void)
+{
+	int i, j, a;
+
+	parity[0] = 0;
+	for (i = 1; i < 256; i++)
+		parity[i] = (parity[i&(i-1)] ^ 1);
+
+	for (i = 0; i < 256; i++) {
+		a = 0;
+		for (j = 0; j < 8; j++) {
+			if (i & (1<<j)) {
+				if ((j & 1) == 0)
+					a ^= 0x04;
+				if ((j & 2) == 0)
+					a ^= 0x10;
+				if ((j & 4) == 0)
+					a ^= 0x40;
+			}
+		}
+		ecc2[i] = ~(a ^ (a<<1) ^ (parity[i] ? 0xa8 : 0));
+	}
+}
+
+/* compute 3-byte ecc on 256 bytes */
+static void nand_compute_ecc(unsigned char *data, unsigned char *ecc)
+{
+	int i, j, a;
+	unsigned char par = 0, bit, bits[8] = {0};
+
+	/* collect 16 checksum bits */
+	for (i = 0; i < 256; i++) {
+		par ^= data[i];
+		bit = parity[data[i]];
+		for (j = 0; j < 8; j++)
+			if ((i & (1<<j)) == 0)
+				bits[j] ^= bit;
+	}
+
+	/* put 4+4+4 = 12 bits in the ecc */
+	a = (bits[3] << 6) + (bits[2] << 4) + (bits[1] << 2) + bits[0];
+	ecc[0] = ~(a ^ (a<<1) ^ (parity[par] ? 0xaa : 0));
+
+	a = (bits[7] << 6) + (bits[6] << 4) + (bits[5] << 2) + bits[4];
+	ecc[1] = ~(a ^ (a<<1) ^ (parity[par] ? 0xaa : 0));
+
+	ecc[2] = ecc2[par];
+}
+
+static int nand_compare_ecc(unsigned char *data, unsigned char *ecc)
+{
+	return (data[0] == ecc[0] && data[1] == ecc[1] && data[2] == ecc[2]);
+}
+
+static void nand_store_ecc(unsigned char *data, unsigned char *ecc)
+{
+	memcpy(data, ecc, 3);
+}
+
+/*
+ * Alauda driver
+ */
+
+/*
+ * Forget our PBA <---> LBA mappings for a particular port
+ */
+static void alauda_free_maps (struct alauda_media_info *media_info)
+{
+	unsigned int shift = media_info->zoneshift
+		+ media_info->blockshift + media_info->pageshift;
+	unsigned int num_zones = media_info->capacity >> shift;
+	unsigned int i;
+
+	if (media_info->lba_to_pba != NULL)
+		for (i = 0; i < num_zones; i++) {
+			kfree(media_info->lba_to_pba[i]);
+			media_info->lba_to_pba[i] = NULL;
+		}
+
+	if (media_info->pba_to_lba != NULL)
+		for (i = 0; i < num_zones; i++) {
+			kfree(media_info->pba_to_lba[i]);
+			media_info->pba_to_lba[i] = NULL;
+		}
+}
+
+/*
+ * Returns 2 bytes of status data
+ * The first byte describes media status, and second byte describes door status
+ */
+static int alauda_get_media_status(struct us_data *us, unsigned char *data)
+{
+	int rc;
+	unsigned char command;
+
+	if (MEDIA_PORT(us) == ALAUDA_PORT_XD)
+		command = ALAUDA_GET_XD_MEDIA_STATUS;
+	else
+		command = ALAUDA_GET_SM_MEDIA_STATUS;
+
+	rc = usb_stor_ctrl_transfer(us, us->recv_ctrl_pipe,
+		command, 0xc0, 0, 1, data, 2);
+
+	usb_stor_dbg(us, "Media status %02X %02X\n", data[0], data[1]);
+
+	return rc;
+}
+
+/*
+ * Clears the "media was changed" bit so that we know when it changes again
+ * in the future.
+ */
+static int alauda_ack_media(struct us_data *us)
+{
+	unsigned char command;
+
+	if (MEDIA_PORT(us) == ALAUDA_PORT_XD)
+		command = ALAUDA_ACK_XD_MEDIA_CHANGE;
+	else
+		command = ALAUDA_ACK_SM_MEDIA_CHANGE;
+
+	return usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
+		command, 0x40, 0, 1, NULL, 0);
+}
+
+/*
+ * Retrieves a 4-byte media signature, which indicates manufacturer, capacity,
+ * and some other details.
+ */
+static int alauda_get_media_signature(struct us_data *us, unsigned char *data)
+{
+	unsigned char command;
+
+	if (MEDIA_PORT(us) == ALAUDA_PORT_XD)
+		command = ALAUDA_GET_XD_MEDIA_SIG;
+	else
+		command = ALAUDA_GET_SM_MEDIA_SIG;
+
+	return usb_stor_ctrl_transfer(us, us->recv_ctrl_pipe,
+		command, 0xc0, 0, 0, data, 4);
+}
+
+/*
+ * Resets the media status (but not the whole device?)
+ */
+static int alauda_reset_media(struct us_data *us)
+{
+	unsigned char *command = us->iobuf;
+
+	memset(command, 0, 9);
+	command[0] = ALAUDA_BULK_CMD;
+	command[1] = ALAUDA_BULK_RESET_MEDIA;
+	command[8] = MEDIA_PORT(us);
+
+	return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+		command, 9, NULL);
+}
+
+/*
+ * Examines the media and deduces capacity, etc.
+ */
+static int alauda_init_media(struct us_data *us)
+{
+	unsigned char *data = us->iobuf;
+	int ready = 0;
+	struct alauda_card_info *media_info;
+	unsigned int num_zones;
+
+	while (ready == 0) {
+		msleep(20);
+
+		if (alauda_get_media_status(us, data) != USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		if (data[0] & 0x10)
+			ready = 1;
+	}
+
+	usb_stor_dbg(us, "We are ready for action!\n");
+
+	if (alauda_ack_media(us) != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	msleep(10);
+
+	if (alauda_get_media_status(us, data) != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	if (data[0] != 0x14) {
+		usb_stor_dbg(us, "Media not ready after ack\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	if (alauda_get_media_signature(us, data) != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	usb_stor_dbg(us, "Media signature: %4ph\n", data);
+	media_info = alauda_card_find_id(data[1]);
+	if (media_info == NULL) {
+		pr_warn("alauda_init_media: Unrecognised media signature: %4ph\n",
+			data);
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	MEDIA_INFO(us).capacity = 1 << media_info->chipshift;
+	usb_stor_dbg(us, "Found media with capacity: %ldMB\n",
+		     MEDIA_INFO(us).capacity >> 20);
+
+	MEDIA_INFO(us).pageshift = media_info->pageshift;
+	MEDIA_INFO(us).blockshift = media_info->blockshift;
+	MEDIA_INFO(us).zoneshift = media_info->zoneshift;
+
+	MEDIA_INFO(us).pagesize = 1 << media_info->pageshift;
+	MEDIA_INFO(us).blocksize = 1 << media_info->blockshift;
+	MEDIA_INFO(us).zonesize = 1 << media_info->zoneshift;
+
+	MEDIA_INFO(us).uzonesize = ((1 << media_info->zoneshift) / 128) * 125;
+	MEDIA_INFO(us).blockmask = MEDIA_INFO(us).blocksize - 1;
+
+	num_zones = MEDIA_INFO(us).capacity >> (MEDIA_INFO(us).zoneshift
+		+ MEDIA_INFO(us).blockshift + MEDIA_INFO(us).pageshift);
+	MEDIA_INFO(us).pba_to_lba = kcalloc(num_zones, sizeof(u16*), GFP_NOIO);
+	MEDIA_INFO(us).lba_to_pba = kcalloc(num_zones, sizeof(u16*), GFP_NOIO);
+
+	if (alauda_reset_media(us) != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Examines the media status and does the right thing when the media has gone,
+ * appeared, or changed.
+ */
+static int alauda_check_media(struct us_data *us)
+{
+	struct alauda_info *info = (struct alauda_info *) us->extra;
+	unsigned char status[2];
+	int rc;
+
+	rc = alauda_get_media_status(us, status);
+
+	/* Check for no media or door open */
+	if ((status[0] & 0x80) || ((status[0] & 0x1F) == 0x10)
+		|| ((status[1] & 0x01) == 0)) {
+		usb_stor_dbg(us, "No media, or door open\n");
+		alauda_free_maps(&MEDIA_INFO(us));
+		info->sense_key = 0x02;
+		info->sense_asc = 0x3A;
+		info->sense_ascq = 0x00;
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	/* Check for media change */
+	if (status[0] & 0x08) {
+		usb_stor_dbg(us, "Media change detected\n");
+		alauda_free_maps(&MEDIA_INFO(us));
+		alauda_init_media(us);
+
+		info->sense_key = UNIT_ATTENTION;
+		info->sense_asc = 0x28;
+		info->sense_ascq = 0x00;
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Checks the status from the 2nd status register
+ * Returns 3 bytes of status data, only the first is known
+ */
+static int alauda_check_status2(struct us_data *us)
+{
+	int rc;
+	unsigned char command[] = {
+		ALAUDA_BULK_CMD, ALAUDA_BULK_GET_STATUS2,
+		0, 0, 0, 0, 3, 0, MEDIA_PORT(us)
+	};
+	unsigned char data[3];
+
+	rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+		command, 9, NULL);
+	if (rc != USB_STOR_XFER_GOOD)
+		return rc;
+
+	rc = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+		data, 3, NULL);
+	if (rc != USB_STOR_XFER_GOOD)
+		return rc;
+
+	usb_stor_dbg(us, "%3ph\n", data);
+	if (data[0] & ALAUDA_STATUS_ERROR)
+		return USB_STOR_XFER_ERROR;
+
+	return USB_STOR_XFER_GOOD;
+}
+
+/*
+ * Gets the redundancy data for the first page of a PBA
+ * Returns 16 bytes.
+ */
+static int alauda_get_redu_data(struct us_data *us, u16 pba, unsigned char *data)
+{
+	int rc;
+	unsigned char command[] = {
+		ALAUDA_BULK_CMD, ALAUDA_BULK_GET_REDU_DATA,
+		PBA_HI(pba), PBA_ZONE(pba), 0, PBA_LO(pba), 0, 0, MEDIA_PORT(us)
+	};
+
+	rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+		command, 9, NULL);
+	if (rc != USB_STOR_XFER_GOOD)
+		return rc;
+
+	return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+		data, 16, NULL);
+}
+
+/*
+ * Finds the first unused PBA in a zone
+ * Returns the absolute PBA of an unused PBA, or 0 if none found.
+ */
+static u16 alauda_find_unused_pba(struct alauda_media_info *info,
+	unsigned int zone)
+{
+	u16 *pba_to_lba = info->pba_to_lba[zone];
+	unsigned int i;
+
+	for (i = 0; i < info->zonesize; i++)
+		if (pba_to_lba[i] == UNDEF)
+			return (zone << info->zoneshift) + i;
+
+	return 0;
+}
+
+/*
+ * Reads the redundancy data for all PBA's in a zone
+ * Produces lba <--> pba mappings
+ */
+static int alauda_read_map(struct us_data *us, unsigned int zone)
+{
+	unsigned char *data = us->iobuf;
+	int result;
+	int i, j;
+	unsigned int zonesize = MEDIA_INFO(us).zonesize;
+	unsigned int uzonesize = MEDIA_INFO(us).uzonesize;
+	unsigned int lba_offset, lba_real, blocknum;
+	unsigned int zone_base_lba = zone * uzonesize;
+	unsigned int zone_base_pba = zone * zonesize;
+	u16 *lba_to_pba = kcalloc(zonesize, sizeof(u16), GFP_NOIO);
+	u16 *pba_to_lba = kcalloc(zonesize, sizeof(u16), GFP_NOIO);
+	if (lba_to_pba == NULL || pba_to_lba == NULL) {
+		result = USB_STOR_TRANSPORT_ERROR;
+		goto error;
+	}
+
+	usb_stor_dbg(us, "Mapping blocks for zone %d\n", zone);
+
+	/* 1024 PBA's per zone */
+	for (i = 0; i < zonesize; i++)
+		lba_to_pba[i] = pba_to_lba[i] = UNDEF;
+
+	for (i = 0; i < zonesize; i++) {
+		blocknum = zone_base_pba + i;
+
+		result = alauda_get_redu_data(us, blocknum, data);
+		if (result != USB_STOR_XFER_GOOD) {
+			result = USB_STOR_TRANSPORT_ERROR;
+			goto error;
+		}
+
+		/* special PBAs have control field 0^16 */
+		for (j = 0; j < 16; j++)
+			if (data[j] != 0)
+				goto nonz;
+		pba_to_lba[i] = UNUSABLE;
+		usb_stor_dbg(us, "PBA %d has no logical mapping\n", blocknum);
+		continue;
+
+	nonz:
+		/* unwritten PBAs have control field FF^16 */
+		for (j = 0; j < 16; j++)
+			if (data[j] != 0xff)
+				goto nonff;
+		continue;
+
+	nonff:
+		/* normal PBAs start with six FFs */
+		if (j < 6) {
+			usb_stor_dbg(us, "PBA %d has no logical mapping: reserved area = %02X%02X%02X%02X data status %02X block status %02X\n",
+				     blocknum,
+				     data[0], data[1], data[2], data[3],
+				     data[4], data[5]);
+			pba_to_lba[i] = UNUSABLE;
+			continue;
+		}
+
+		if ((data[6] >> 4) != 0x01) {
+			usb_stor_dbg(us, "PBA %d has invalid address field %02X%02X/%02X%02X\n",
+				     blocknum, data[6], data[7],
+				     data[11], data[12]);
+			pba_to_lba[i] = UNUSABLE;
+			continue;
+		}
+
+		/* check even parity */
+		if (parity[data[6] ^ data[7]]) {
+			printk(KERN_WARNING
+			       "alauda_read_map: Bad parity in LBA for block %d"
+			       " (%02X %02X)\n", i, data[6], data[7]);
+			pba_to_lba[i] = UNUSABLE;
+			continue;
+		}
+
+		lba_offset = short_pack(data[7], data[6]);
+		lba_offset = (lba_offset & 0x07FF) >> 1;
+		lba_real = lba_offset + zone_base_lba;
+
+		/*
+		 * Every 1024 physical blocks ("zone"), the LBA numbers
+		 * go back to zero, but are within a higher block of LBA's.
+		 * Also, there is a maximum of 1000 LBA's per zone.
+		 * In other words, in PBA 1024-2047 you will find LBA 0-999
+		 * which are really LBA 1000-1999. This allows for 24 bad
+		 * or special physical blocks per zone.
+		 */
+
+		if (lba_offset >= uzonesize) {
+			printk(KERN_WARNING
+			       "alauda_read_map: Bad low LBA %d for block %d\n",
+			       lba_real, blocknum);
+			continue;
+		}
+
+		if (lba_to_pba[lba_offset] != UNDEF) {
+			printk(KERN_WARNING
+			       "alauda_read_map: "
+			       "LBA %d seen for PBA %d and %d\n",
+			       lba_real, lba_to_pba[lba_offset], blocknum);
+			continue;
+		}
+
+		pba_to_lba[i] = lba_real;
+		lba_to_pba[lba_offset] = blocknum;
+		continue;
+	}
+
+	MEDIA_INFO(us).lba_to_pba[zone] = lba_to_pba;
+	MEDIA_INFO(us).pba_to_lba[zone] = pba_to_lba;
+	result = 0;
+	goto out;
+
+error:
+	kfree(lba_to_pba);
+	kfree(pba_to_lba);
+out:
+	return result;
+}
+
+/*
+ * Checks to see whether we have already mapped a certain zone
+ * If we haven't, the map is generated
+ */
+static void alauda_ensure_map_for_zone(struct us_data *us, unsigned int zone)
+{
+	if (MEDIA_INFO(us).lba_to_pba[zone] == NULL
+		|| MEDIA_INFO(us).pba_to_lba[zone] == NULL)
+		alauda_read_map(us, zone);
+}
+
+/*
+ * Erases an entire block
+ */
+static int alauda_erase_block(struct us_data *us, u16 pba)
+{
+	int rc;
+	unsigned char command[] = {
+		ALAUDA_BULK_CMD, ALAUDA_BULK_ERASE_BLOCK, PBA_HI(pba),
+		PBA_ZONE(pba), 0, PBA_LO(pba), 0x02, 0, MEDIA_PORT(us)
+	};
+	unsigned char buf[2];
+
+	usb_stor_dbg(us, "Erasing PBA %d\n", pba);
+
+	rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+		command, 9, NULL);
+	if (rc != USB_STOR_XFER_GOOD)
+		return rc;
+
+	rc = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+		buf, 2, NULL);
+	if (rc != USB_STOR_XFER_GOOD)
+		return rc;
+
+	usb_stor_dbg(us, "Erase result: %02X %02X\n", buf[0], buf[1]);
+	return rc;
+}
+
+/*
+ * Reads data from a certain offset page inside a PBA, including interleaved
+ * redundancy data. Returns (pagesize+64)*pages bytes in data.
+ */
+static int alauda_read_block_raw(struct us_data *us, u16 pba,
+		unsigned int page, unsigned int pages, unsigned char *data)
+{
+	int rc;
+	unsigned char command[] = {
+		ALAUDA_BULK_CMD, ALAUDA_BULK_READ_BLOCK, PBA_HI(pba),
+		PBA_ZONE(pba), 0, PBA_LO(pba) + page, pages, 0, MEDIA_PORT(us)
+	};
+
+	usb_stor_dbg(us, "pba %d page %d count %d\n", pba, page, pages);
+
+	rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+		command, 9, NULL);
+	if (rc != USB_STOR_XFER_GOOD)
+		return rc;
+
+	return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+		data, (MEDIA_INFO(us).pagesize + 64) * pages, NULL);
+}
+
+/*
+ * Reads data from a certain offset page inside a PBA, excluding redundancy
+ * data. Returns pagesize*pages bytes in data. Note that data must be big enough
+ * to hold (pagesize+64)*pages bytes of data, but you can ignore those 'extra'
+ * trailing bytes outside this function.
+ */
+static int alauda_read_block(struct us_data *us, u16 pba,
+		unsigned int page, unsigned int pages, unsigned char *data)
+{
+	int i, rc;
+	unsigned int pagesize = MEDIA_INFO(us).pagesize;
+
+	rc = alauda_read_block_raw(us, pba, page, pages, data);
+	if (rc != USB_STOR_XFER_GOOD)
+		return rc;
+
+	/* Cut out the redundancy data */
+	for (i = 0; i < pages; i++) {
+		int dest_offset = i * pagesize;
+		int src_offset = i * (pagesize + 64);
+		memmove(data + dest_offset, data + src_offset, pagesize);
+	}
+
+	return rc;
+}
+
+/*
+ * Writes an entire block of data and checks status after write.
+ * Redundancy data must be already included in data. Data should be
+ * (pagesize+64)*blocksize bytes in length.
+ */
+static int alauda_write_block(struct us_data *us, u16 pba, unsigned char *data)
+{
+	int rc;
+	struct alauda_info *info = (struct alauda_info *) us->extra;
+	unsigned char command[] = {
+		ALAUDA_BULK_CMD, ALAUDA_BULK_WRITE_BLOCK, PBA_HI(pba),
+		PBA_ZONE(pba), 0, PBA_LO(pba), 32, 0, MEDIA_PORT(us)
+	};
+
+	usb_stor_dbg(us, "pba %d\n", pba);
+
+	rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+		command, 9, NULL);
+	if (rc != USB_STOR_XFER_GOOD)
+		return rc;
+
+	rc = usb_stor_bulk_transfer_buf(us, info->wr_ep, data,
+		(MEDIA_INFO(us).pagesize + 64) * MEDIA_INFO(us).blocksize,
+		NULL);
+	if (rc != USB_STOR_XFER_GOOD)
+		return rc;
+
+	return alauda_check_status2(us);
+}
+
+/*
+ * Write some data to a specific LBA.
+ */
+static int alauda_write_lba(struct us_data *us, u16 lba,
+		 unsigned int page, unsigned int pages,
+		 unsigned char *ptr, unsigned char *blockbuffer)
+{
+	u16 pba, lbap, new_pba;
+	unsigned char *bptr, *cptr, *xptr;
+	unsigned char ecc[3];
+	int i, result;
+	unsigned int uzonesize = MEDIA_INFO(us).uzonesize;
+	unsigned int zonesize = MEDIA_INFO(us).zonesize;
+	unsigned int pagesize = MEDIA_INFO(us).pagesize;
+	unsigned int blocksize = MEDIA_INFO(us).blocksize;
+	unsigned int lba_offset = lba % uzonesize;
+	unsigned int new_pba_offset;
+	unsigned int zone = lba / uzonesize;
+
+	alauda_ensure_map_for_zone(us, zone);
+
+	pba = MEDIA_INFO(us).lba_to_pba[zone][lba_offset];
+	if (pba == 1) {
+		/*
+		 * Maybe it is impossible to write to PBA 1.
+		 * Fake success, but don't do anything.
+		 */
+		printk(KERN_WARNING
+		       "alauda_write_lba: avoid writing to pba 1\n");
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	new_pba = alauda_find_unused_pba(&MEDIA_INFO(us), zone);
+	if (!new_pba) {
+		printk(KERN_WARNING
+		       "alauda_write_lba: Out of unused blocks\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	/* read old contents */
+	if (pba != UNDEF) {
+		result = alauda_read_block_raw(us, pba, 0,
+			blocksize, blockbuffer);
+		if (result != USB_STOR_XFER_GOOD)
+			return result;
+	} else {
+		memset(blockbuffer, 0, blocksize * (pagesize + 64));
+	}
+
+	lbap = (lba_offset << 1) | 0x1000;
+	if (parity[MSB_of(lbap) ^ LSB_of(lbap)])
+		lbap ^= 1;
+
+	/* check old contents and fill lba */
+	for (i = 0; i < blocksize; i++) {
+		bptr = blockbuffer + (i * (pagesize + 64));
+		cptr = bptr + pagesize;
+		nand_compute_ecc(bptr, ecc);
+		if (!nand_compare_ecc(cptr+13, ecc)) {
+			usb_stor_dbg(us, "Warning: bad ecc in page %d- of pba %d\n",
+				     i, pba);
+			nand_store_ecc(cptr+13, ecc);
+		}
+		nand_compute_ecc(bptr + (pagesize / 2), ecc);
+		if (!nand_compare_ecc(cptr+8, ecc)) {
+			usb_stor_dbg(us, "Warning: bad ecc in page %d+ of pba %d\n",
+				     i, pba);
+			nand_store_ecc(cptr+8, ecc);
+		}
+		cptr[6] = cptr[11] = MSB_of(lbap);
+		cptr[7] = cptr[12] = LSB_of(lbap);
+	}
+
+	/* copy in new stuff and compute ECC */
+	xptr = ptr;
+	for (i = page; i < page+pages; i++) {
+		bptr = blockbuffer + (i * (pagesize + 64));
+		cptr = bptr + pagesize;
+		memcpy(bptr, xptr, pagesize);
+		xptr += pagesize;
+		nand_compute_ecc(bptr, ecc);
+		nand_store_ecc(cptr+13, ecc);
+		nand_compute_ecc(bptr + (pagesize / 2), ecc);
+		nand_store_ecc(cptr+8, ecc);
+	}
+
+	result = alauda_write_block(us, new_pba, blockbuffer);
+	if (result != USB_STOR_XFER_GOOD)
+		return result;
+
+	new_pba_offset = new_pba - (zone * zonesize);
+	MEDIA_INFO(us).pba_to_lba[zone][new_pba_offset] = lba;
+	MEDIA_INFO(us).lba_to_pba[zone][lba_offset] = new_pba;
+	usb_stor_dbg(us, "Remapped LBA %d to PBA %d\n", lba, new_pba);
+
+	if (pba != UNDEF) {
+		unsigned int pba_offset = pba - (zone * zonesize);
+		result = alauda_erase_block(us, pba);
+		if (result != USB_STOR_XFER_GOOD)
+			return result;
+		MEDIA_INFO(us).pba_to_lba[zone][pba_offset] = UNDEF;
+	}
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Read data from a specific sector address
+ */
+static int alauda_read_data(struct us_data *us, unsigned long address,
+		unsigned int sectors)
+{
+	unsigned char *buffer;
+	u16 lba, max_lba;
+	unsigned int page, len, offset;
+	unsigned int blockshift = MEDIA_INFO(us).blockshift;
+	unsigned int pageshift = MEDIA_INFO(us).pageshift;
+	unsigned int blocksize = MEDIA_INFO(us).blocksize;
+	unsigned int pagesize = MEDIA_INFO(us).pagesize;
+	unsigned int uzonesize = MEDIA_INFO(us).uzonesize;
+	struct scatterlist *sg;
+	int result;
+
+	/*
+	 * Since we only read in one block at a time, we have to create
+	 * a bounce buffer and move the data a piece at a time between the
+	 * bounce buffer and the actual transfer buffer.
+	 * We make this buffer big enough to hold temporary redundancy data,
+	 * which we use when reading the data blocks.
+	 */
+
+	len = min(sectors, blocksize) * (pagesize + 64);
+	buffer = kmalloc(len, GFP_NOIO);
+	if (!buffer)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	/* Figure out the initial LBA and page */
+	lba = address >> blockshift;
+	page = (address & MEDIA_INFO(us).blockmask);
+	max_lba = MEDIA_INFO(us).capacity >> (blockshift + pageshift);
+
+	result = USB_STOR_TRANSPORT_GOOD;
+	offset = 0;
+	sg = NULL;
+
+	while (sectors > 0) {
+		unsigned int zone = lba / uzonesize; /* integer division */
+		unsigned int lba_offset = lba - (zone * uzonesize);
+		unsigned int pages;
+		u16 pba;
+		alauda_ensure_map_for_zone(us, zone);
+
+		/* Not overflowing capacity? */
+		if (lba >= max_lba) {
+			usb_stor_dbg(us, "Error: Requested lba %u exceeds maximum %u\n",
+				     lba, max_lba);
+			result = USB_STOR_TRANSPORT_ERROR;
+			break;
+		}
+
+		/* Find number of pages we can read in this block */
+		pages = min(sectors, blocksize - page);
+		len = pages << pageshift;
+
+		/* Find where this lba lives on disk */
+		pba = MEDIA_INFO(us).lba_to_pba[zone][lba_offset];
+
+		if (pba == UNDEF) {	/* this lba was never written */
+			usb_stor_dbg(us, "Read %d zero pages (LBA %d) page %d\n",
+				     pages, lba, page);
+
+			/*
+			 * This is not really an error. It just means
+			 * that the block has never been written.
+			 * Instead of returning USB_STOR_TRANSPORT_ERROR
+			 * it is better to return all zero data.
+			 */
+
+			memset(buffer, 0, len);
+		} else {
+			usb_stor_dbg(us, "Read %d pages, from PBA %d (LBA %d) page %d\n",
+				     pages, pba, lba, page);
+
+			result = alauda_read_block(us, pba, page, pages, buffer);
+			if (result != USB_STOR_TRANSPORT_GOOD)
+				break;
+		}
+
+		/* Store the data in the transfer buffer */
+		usb_stor_access_xfer_buf(buffer, len, us->srb,
+				&sg, &offset, TO_XFER_BUF);
+
+		page = 0;
+		lba++;
+		sectors -= pages;
+	}
+
+	kfree(buffer);
+	return result;
+}
+
+/*
+ * Write data to a specific sector address
+ */
+static int alauda_write_data(struct us_data *us, unsigned long address,
+		unsigned int sectors)
+{
+	unsigned char *buffer, *blockbuffer;
+	unsigned int page, len, offset;
+	unsigned int blockshift = MEDIA_INFO(us).blockshift;
+	unsigned int pageshift = MEDIA_INFO(us).pageshift;
+	unsigned int blocksize = MEDIA_INFO(us).blocksize;
+	unsigned int pagesize = MEDIA_INFO(us).pagesize;
+	struct scatterlist *sg;
+	u16 lba, max_lba;
+	int result;
+
+	/*
+	 * Since we don't write the user data directly to the device,
+	 * we have to create a bounce buffer and move the data a piece
+	 * at a time between the bounce buffer and the actual transfer buffer.
+	 */
+
+	len = min(sectors, blocksize) * pagesize;
+	buffer = kmalloc(len, GFP_NOIO);
+	if (!buffer)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	/*
+	 * We also need a temporary block buffer, where we read in the old data,
+	 * overwrite parts with the new data, and manipulate the redundancy data
+	 */
+	blockbuffer = kmalloc_array(pagesize + 64, blocksize, GFP_NOIO);
+	if (!blockbuffer) {
+		kfree(buffer);
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	/* Figure out the initial LBA and page */
+	lba = address >> blockshift;
+	page = (address & MEDIA_INFO(us).blockmask);
+	max_lba = MEDIA_INFO(us).capacity >> (pageshift + blockshift);
+
+	result = USB_STOR_TRANSPORT_GOOD;
+	offset = 0;
+	sg = NULL;
+
+	while (sectors > 0) {
+		/* Write as many sectors as possible in this block */
+		unsigned int pages = min(sectors, blocksize - page);
+		len = pages << pageshift;
+
+		/* Not overflowing capacity? */
+		if (lba >= max_lba) {
+			usb_stor_dbg(us, "Requested lba %u exceeds maximum %u\n",
+				     lba, max_lba);
+			result = USB_STOR_TRANSPORT_ERROR;
+			break;
+		}
+
+		/* Get the data from the transfer buffer */
+		usb_stor_access_xfer_buf(buffer, len, us->srb,
+				&sg, &offset, FROM_XFER_BUF);
+
+		result = alauda_write_lba(us, lba, page, pages, buffer,
+			blockbuffer);
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			break;
+
+		page = 0;
+		lba++;
+		sectors -= pages;
+	}
+
+	kfree(buffer);
+	kfree(blockbuffer);
+	return result;
+}
+
+/*
+ * Our interface with the rest of the world
+ */
+
+static void alauda_info_destructor(void *extra)
+{
+	struct alauda_info *info = (struct alauda_info *) extra;
+	int port;
+
+	if (!info)
+		return;
+
+	for (port = 0; port < 2; port++) {
+		struct alauda_media_info *media_info = &info->port[port];
+
+		alauda_free_maps(media_info);
+		kfree(media_info->lba_to_pba);
+		kfree(media_info->pba_to_lba);
+	}
+}
+
+/*
+ * Initialize alauda_info struct and find the data-write endpoint
+ */
+static int init_alauda(struct us_data *us)
+{
+	struct alauda_info *info;
+	struct usb_host_interface *altsetting = us->pusb_intf->cur_altsetting;
+	nand_init_ecc();
+
+	us->extra = kzalloc(sizeof(struct alauda_info), GFP_NOIO);
+	if (!us->extra)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	info = (struct alauda_info *) us->extra;
+	us->extra_destructor = alauda_info_destructor;
+
+	info->wr_ep = usb_sndbulkpipe(us->pusb_dev,
+		altsetting->endpoint[0].desc.bEndpointAddress
+		& USB_ENDPOINT_NUMBER_MASK);
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int alauda_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+	int rc;
+	struct alauda_info *info = (struct alauda_info *) us->extra;
+	unsigned char *ptr = us->iobuf;
+	static unsigned char inquiry_response[36] = {
+		0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00
+	};
+
+	if (srb->cmnd[0] == INQUIRY) {
+		usb_stor_dbg(us, "INQUIRY - Returning bogus response\n");
+		memcpy(ptr, inquiry_response, sizeof(inquiry_response));
+		fill_inquiry_response(us, ptr, 36);
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == TEST_UNIT_READY) {
+		usb_stor_dbg(us, "TEST_UNIT_READY\n");
+		return alauda_check_media(us);
+	}
+
+	if (srb->cmnd[0] == READ_CAPACITY) {
+		unsigned int num_zones;
+		unsigned long capacity;
+
+		rc = alauda_check_media(us);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+
+		num_zones = MEDIA_INFO(us).capacity >> (MEDIA_INFO(us).zoneshift
+			+ MEDIA_INFO(us).blockshift + MEDIA_INFO(us).pageshift);
+
+		capacity = num_zones * MEDIA_INFO(us).uzonesize
+			* MEDIA_INFO(us).blocksize;
+
+		/* Report capacity and page size */
+		((__be32 *) ptr)[0] = cpu_to_be32(capacity - 1);
+		((__be32 *) ptr)[1] = cpu_to_be32(512);
+
+		usb_stor_set_xfer_buf(ptr, 8, srb);
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == READ_10) {
+		unsigned int page, pages;
+
+		rc = alauda_check_media(us);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+
+		page = short_pack(srb->cmnd[3], srb->cmnd[2]);
+		page <<= 16;
+		page |= short_pack(srb->cmnd[5], srb->cmnd[4]);
+		pages = short_pack(srb->cmnd[8], srb->cmnd[7]);
+
+		usb_stor_dbg(us, "READ_10: page %d pagect %d\n", page, pages);
+
+		return alauda_read_data(us, page, pages);
+	}
+
+	if (srb->cmnd[0] == WRITE_10) {
+		unsigned int page, pages;
+
+		rc = alauda_check_media(us);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+
+		page = short_pack(srb->cmnd[3], srb->cmnd[2]);
+		page <<= 16;
+		page |= short_pack(srb->cmnd[5], srb->cmnd[4]);
+		pages = short_pack(srb->cmnd[8], srb->cmnd[7]);
+
+		usb_stor_dbg(us, "WRITE_10: page %d pagect %d\n", page, pages);
+
+		return alauda_write_data(us, page, pages);
+	}
+
+	if (srb->cmnd[0] == REQUEST_SENSE) {
+		usb_stor_dbg(us, "REQUEST_SENSE\n");
+
+		memset(ptr, 0, 18);
+		ptr[0] = 0xF0;
+		ptr[2] = info->sense_key;
+		ptr[7] = 11;
+		ptr[12] = info->sense_asc;
+		ptr[13] = info->sense_ascq;
+		usb_stor_set_xfer_buf(ptr, 18, srb);
+
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
+		/*
+		 * sure.  whatever.  not like we can stop the user from popping
+		 * the media out of the device (no locking doors, etc)
+		 */
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	usb_stor_dbg(us, "Gah! Unknown command: %d (0x%x)\n",
+		     srb->cmnd[0], srb->cmnd[0]);
+	info->sense_key = 0x05;
+	info->sense_asc = 0x20;
+	info->sense_ascq = 0x00;
+	return USB_STOR_TRANSPORT_FAILED;
+}
+
+static struct scsi_host_template alauda_host_template;
+
+static int alauda_probe(struct usb_interface *intf,
+			 const struct usb_device_id *id)
+{
+	struct us_data *us;
+	int result;
+
+	result = usb_stor_probe1(&us, intf, id,
+			(id - alauda_usb_ids) + alauda_unusual_dev_list,
+			&alauda_host_template);
+	if (result)
+		return result;
+
+	us->transport_name  = "Alauda Control/Bulk";
+	us->transport = alauda_transport;
+	us->transport_reset = usb_stor_Bulk_reset;
+	us->max_lun = 1;
+
+	result = usb_stor_probe2(us);
+	return result;
+}
+
+static struct usb_driver alauda_driver = {
+	.name =		DRV_NAME,
+	.probe =	alauda_probe,
+	.disconnect =	usb_stor_disconnect,
+	.suspend =	usb_stor_suspend,
+	.resume =	usb_stor_resume,
+	.reset_resume =	usb_stor_reset_resume,
+	.pre_reset =	usb_stor_pre_reset,
+	.post_reset =	usb_stor_post_reset,
+	.id_table =	alauda_usb_ids,
+	.soft_unbind =	1,
+	.no_dynamic_id = 1,
+};
+
+module_usb_stor_driver(alauda_driver, alauda_host_template, DRV_NAME);
diff --git a/drivers/usb/storage/cypress_atacb.c b/drivers/usb/storage/cypress_atacb.c
new file mode 100644
index 0000000..4825902
--- /dev/null
+++ b/drivers/usb/storage/cypress_atacb.c
@@ -0,0 +1,286 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Support for emulating SAT (ata pass through) on devices based
+ *       on the Cypress USB/ATA bridge supporting ATACB.
+ *
+ * Copyright (c) 2008 Matthieu Castet (castet.matthieu@free.fr)
+ */
+
+#include <linux/module.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_eh.h>
+#include <linux/ata.h>
+
+#include "usb.h"
+#include "protocol.h"
+#include "scsiglue.h"
+#include "debug.h"
+
+#define DRV_NAME "ums-cypress"
+
+MODULE_DESCRIPTION("SAT support for Cypress USB/ATA bridges with ATACB");
+MODULE_AUTHOR("Matthieu Castet <castet.matthieu@free.fr>");
+MODULE_LICENSE("GPL");
+
+/*
+ * The table of devices
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+		    vendorName, productName, useProtocol, useTransport, \
+		    initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+  .driver_info = (flags) }
+
+static struct usb_device_id cypress_usb_ids[] = {
+#	include "unusual_cypress.h"
+	{ }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, cypress_usb_ids);
+
+#undef UNUSUAL_DEV
+
+/*
+ * The flags table
+ */
+#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
+		    vendor_name, product_name, use_protocol, use_transport, \
+		    init_function, Flags) \
+{ \
+	.vendorName = vendor_name,	\
+	.productName = product_name,	\
+	.useProtocol = use_protocol,	\
+	.useTransport = use_transport,	\
+	.initFunction = init_function,	\
+}
+
+static struct us_unusual_dev cypress_unusual_dev_list[] = {
+#	include "unusual_cypress.h"
+	{ }		/* Terminating entry */
+};
+
+#undef UNUSUAL_DEV
+
+
+/*
+ * ATACB is a protocol used on cypress usb<->ata bridge to
+ * send raw ATA command over mass storage
+ * There is a ATACB2 protocol that support LBA48 on newer chip.
+ * More info that be found on cy7c68310_8.pdf and cy7c68300c_8.pdf
+ * datasheet from cypress.com.
+ */
+static void cypress_atacb_passthrough(struct scsi_cmnd *srb, struct us_data *us)
+{
+	unsigned char save_cmnd[MAX_COMMAND_SIZE];
+
+	if (likely(srb->cmnd[0] != ATA_16 && srb->cmnd[0] != ATA_12)) {
+		usb_stor_transparent_scsi_command(srb, us);
+		return;
+	}
+
+	memcpy(save_cmnd, srb->cmnd, sizeof(save_cmnd));
+	memset(srb->cmnd, 0, MAX_COMMAND_SIZE);
+
+	/* check if we support the command */
+	if (save_cmnd[1] >> 5) /* MULTIPLE_COUNT */
+		goto invalid_fld;
+	/* check protocol */
+	switch ((save_cmnd[1] >> 1) & 0xf) {
+	case 3: /*no DATA */
+	case 4: /* PIO in */
+	case 5: /* PIO out */
+		break;
+	default:
+		goto invalid_fld;
+	}
+
+	/* first build the ATACB command */
+	srb->cmd_len = 16;
+
+	srb->cmnd[0] = 0x24; /*
+			      * bVSCBSignature : vendor-specific command
+			      * this value can change, but most(all ?) manufacturers
+			      * keep the cypress default : 0x24
+			      */
+	srb->cmnd[1] = 0x24; /* bVSCBSubCommand : 0x24 for ATACB */
+
+	srb->cmnd[3] = 0xff - 1; /*
+				  * features, sector count, lba low, lba med
+				  * lba high, device, command are valid
+				  */
+	srb->cmnd[4] = 1; /* TransferBlockCount : 512 */
+
+	if (save_cmnd[0] == ATA_16) {
+		srb->cmnd[ 6] = save_cmnd[ 4]; /* features */
+		srb->cmnd[ 7] = save_cmnd[ 6]; /* sector count */
+		srb->cmnd[ 8] = save_cmnd[ 8]; /* lba low */
+		srb->cmnd[ 9] = save_cmnd[10]; /* lba med */
+		srb->cmnd[10] = save_cmnd[12]; /* lba high */
+		srb->cmnd[11] = save_cmnd[13]; /* device */
+		srb->cmnd[12] = save_cmnd[14]; /* command */
+
+		if (save_cmnd[1] & 0x01) {/* extended bit set for LBA48 */
+			/* this could be supported by atacb2 */
+			if (save_cmnd[3] || save_cmnd[5] || save_cmnd[7] || save_cmnd[9]
+					|| save_cmnd[11])
+				goto invalid_fld;
+		}
+	} else { /* ATA12 */
+		srb->cmnd[ 6] = save_cmnd[3]; /* features */
+		srb->cmnd[ 7] = save_cmnd[4]; /* sector count */
+		srb->cmnd[ 8] = save_cmnd[5]; /* lba low */
+		srb->cmnd[ 9] = save_cmnd[6]; /* lba med */
+		srb->cmnd[10] = save_cmnd[7]; /* lba high */
+		srb->cmnd[11] = save_cmnd[8]; /* device */
+		srb->cmnd[12] = save_cmnd[9]; /* command */
+
+	}
+	/* Filter SET_FEATURES - XFER MODE command */
+	if ((srb->cmnd[12] == ATA_CMD_SET_FEATURES)
+			&& (srb->cmnd[6] == SETFEATURES_XFER))
+		goto invalid_fld;
+
+	if (srb->cmnd[12] == ATA_CMD_ID_ATA || srb->cmnd[12] == ATA_CMD_ID_ATAPI)
+		srb->cmnd[2] |= (1<<7); /* set  IdentifyPacketDevice for these cmds */
+
+
+	usb_stor_transparent_scsi_command(srb, us);
+
+	/* if the device doesn't support ATACB */
+	if (srb->result == SAM_STAT_CHECK_CONDITION &&
+			memcmp(srb->sense_buffer, usb_stor_sense_invalidCDB,
+				sizeof(usb_stor_sense_invalidCDB)) == 0) {
+		usb_stor_dbg(us, "cypress atacb not supported ???\n");
+		goto end;
+	}
+
+	/*
+	 * if ck_cond flags is set, and there wasn't critical error,
+	 * build the special sense
+	 */
+	if ((srb->result != (DID_ERROR << 16) &&
+				srb->result != (DID_ABORT << 16)) &&
+			save_cmnd[2] & 0x20) {
+		struct scsi_eh_save ses;
+		unsigned char regs[8];
+		unsigned char *sb = srb->sense_buffer;
+		unsigned char *desc = sb + 8;
+		int tmp_result;
+
+		/* build the command for reading the ATA registers */
+		scsi_eh_prep_cmnd(srb, &ses, NULL, 0, sizeof(regs));
+
+		/*
+		 * we use the same command as before, but we set
+		 * the read taskfile bit, for not executing atacb command,
+		 * but reading register selected in srb->cmnd[4]
+		 */
+		srb->cmd_len = 16;
+		srb->cmnd = ses.cmnd;
+		srb->cmnd[2] = 1;
+
+		usb_stor_transparent_scsi_command(srb, us);
+		memcpy(regs, srb->sense_buffer, sizeof(regs));
+		tmp_result = srb->result;
+		scsi_eh_restore_cmnd(srb, &ses);
+		/* we fail to get registers, report invalid command */
+		if (tmp_result != SAM_STAT_GOOD)
+			goto invalid_fld;
+
+		/* build the sense */
+		memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
+
+		/* set sk, asc for a good command */
+		sb[1] = RECOVERED_ERROR;
+		sb[2] = 0; /* ATA PASS THROUGH INFORMATION AVAILABLE */
+		sb[3] = 0x1D;
+
+		/*
+		 * XXX we should generate sk, asc, ascq from status and error
+		 * regs
+		 * (see 11.1 Error translation ATA device error to SCSI error
+		 * map, and ata_to_sense_error from libata.)
+		 */
+
+		/* Sense data is current and format is descriptor. */
+		sb[0] = 0x72;
+		desc[0] = 0x09; /* ATA_RETURN_DESCRIPTOR */
+
+		/* set length of additional sense data */
+		sb[7] = 14;
+		desc[1] = 12;
+
+		/* Copy registers into sense buffer. */
+		desc[ 2] = 0x00;
+		desc[ 3] = regs[1];  /* features */
+		desc[ 5] = regs[2];  /* sector count */
+		desc[ 7] = regs[3];  /* lba low */
+		desc[ 9] = regs[4];  /* lba med */
+		desc[11] = regs[5];  /* lba high */
+		desc[12] = regs[6];  /* device */
+		desc[13] = regs[7];  /* command */
+
+		srb->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+	}
+	goto end;
+invalid_fld:
+	srb->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+
+	memcpy(srb->sense_buffer,
+			usb_stor_sense_invalidCDB,
+			sizeof(usb_stor_sense_invalidCDB));
+end:
+	memcpy(srb->cmnd, save_cmnd, sizeof(save_cmnd));
+	if (srb->cmnd[0] == ATA_12)
+		srb->cmd_len = 12;
+}
+
+static struct scsi_host_template cypress_host_template;
+
+static int cypress_probe(struct usb_interface *intf,
+			 const struct usb_device_id *id)
+{
+	struct us_data *us;
+	int result;
+	struct usb_device *device;
+
+	result = usb_stor_probe1(&us, intf, id,
+			(id - cypress_usb_ids) + cypress_unusual_dev_list,
+			&cypress_host_template);
+	if (result)
+		return result;
+
+	/*
+	 * Among CY7C68300 chips, the A revision does not support Cypress ATACB
+	 * Filter out this revision from EEPROM default descriptor values
+	 */
+	device = interface_to_usbdev(intf);
+	if (device->descriptor.iManufacturer != 0x38 ||
+	    device->descriptor.iProduct != 0x4e ||
+	    device->descriptor.iSerialNumber != 0x64) {
+		us->protocol_name = "Transparent SCSI with Cypress ATACB";
+		us->proto_handler = cypress_atacb_passthrough;
+	} else {
+		us->protocol_name = "Transparent SCSI";
+		us->proto_handler = usb_stor_transparent_scsi_command;
+	}
+
+	result = usb_stor_probe2(us);
+	return result;
+}
+
+static struct usb_driver cypress_driver = {
+	.name =		DRV_NAME,
+	.probe =	cypress_probe,
+	.disconnect =	usb_stor_disconnect,
+	.suspend =	usb_stor_suspend,
+	.resume =	usb_stor_resume,
+	.reset_resume =	usb_stor_reset_resume,
+	.pre_reset =	usb_stor_pre_reset,
+	.post_reset =	usb_stor_post_reset,
+	.id_table =	cypress_usb_ids,
+	.soft_unbind =	1,
+	.no_dynamic_id = 1,
+};
+
+module_usb_stor_driver(cypress_driver, cypress_host_template, DRV_NAME);
diff --git a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c
new file mode 100644
index 0000000..09353be
--- /dev/null
+++ b/drivers/usb/storage/datafab.c
@@ -0,0 +1,757 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for Datafab USB Compact Flash reader
+ *
+ * datafab driver v0.1:
+ *
+ * First release
+ *
+ * Current development and maintenance by:
+ *   (c) 2000 Jimmie Mayfield (mayfield+datafab@sackheads.org)
+ *
+ *   Many thanks to Robert Baruch for the SanDisk SmartMedia reader driver
+ *   which I used as a template for this driver.
+ *
+ *   Some bugfixes and scatter-gather code by Gregory P. Smith 
+ *   (greg-usb@electricrain.com)
+ *
+ *   Fix for media change by Joerg Schneider (js@joergschneider.com)
+ *
+ * Other contributors:
+ *   (c) 2002 Alan Stern <stern@rowland.org>
+ */
+
+/*
+ * This driver attempts to support USB CompactFlash reader/writer devices
+ * based on Datafab USB-to-ATA chips.  It was specifically developed for the 
+ * Datafab MDCFE-B USB CompactFlash reader but has since been found to work 
+ * with a variety of Datafab-based devices from a number of manufacturers.
+ * I've received a report of this driver working with a Datafab-based
+ * SmartMedia device though please be aware that I'm personally unable to
+ * test SmartMedia support.
+ *
+ * This driver supports reading and writing.  If you're truly paranoid,
+ * however, you can force the driver into a write-protected state by setting
+ * the WP enable bits in datafab_handle_mode_sense().  See the comments
+ * in that routine.
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "protocol.h"
+#include "debug.h"
+#include "scsiglue.h"
+
+#define DRV_NAME "ums-datafab"
+
+MODULE_DESCRIPTION("Driver for Datafab USB Compact Flash reader");
+MODULE_AUTHOR("Jimmie Mayfield <mayfield+datafab@sackheads.org>");
+MODULE_LICENSE("GPL");
+
+struct datafab_info {
+	unsigned long   sectors;	/* total sector count */
+	unsigned long   ssize;		/* sector size in bytes */
+	signed char	lun;		/* used for dual-slot readers */
+
+	/* the following aren't used yet */
+	unsigned char   sense_key;
+	unsigned long   sense_asc;	/* additional sense code */
+	unsigned long   sense_ascq;	/* additional sense code qualifier */
+};
+
+static int datafab_determine_lun(struct us_data *us,
+				 struct datafab_info *info);
+
+
+/*
+ * The table of devices
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+		    vendorName, productName, useProtocol, useTransport, \
+		    initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+  .driver_info = (flags) }
+
+static struct usb_device_id datafab_usb_ids[] = {
+#	include "unusual_datafab.h"
+	{ }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, datafab_usb_ids);
+
+#undef UNUSUAL_DEV
+
+/*
+ * The flags table
+ */
+#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
+		    vendor_name, product_name, use_protocol, use_transport, \
+		    init_function, Flags) \
+{ \
+	.vendorName = vendor_name,	\
+	.productName = product_name,	\
+	.useProtocol = use_protocol,	\
+	.useTransport = use_transport,	\
+	.initFunction = init_function,	\
+}
+
+static struct us_unusual_dev datafab_unusual_dev_list[] = {
+#	include "unusual_datafab.h"
+	{ }		/* Terminating entry */
+};
+
+#undef UNUSUAL_DEV
+
+
+static inline int
+datafab_bulk_read(struct us_data *us, unsigned char *data, unsigned int len) {
+	if (len == 0)
+		return USB_STOR_XFER_GOOD;
+
+	usb_stor_dbg(us, "len = %d\n", len);
+	return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+			data, len, NULL);
+}
+
+
+static inline int
+datafab_bulk_write(struct us_data *us, unsigned char *data, unsigned int len) {
+	if (len == 0)
+		return USB_STOR_XFER_GOOD;
+
+	usb_stor_dbg(us, "len = %d\n", len);
+	return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+			data, len, NULL);
+}
+
+
+static int datafab_read_data(struct us_data *us,
+			     struct datafab_info *info,
+			     u32 sector,
+			     u32 sectors)
+{
+	unsigned char *command = us->iobuf;
+	unsigned char *buffer;
+	unsigned char  thistime;
+	unsigned int totallen, alloclen;
+	int len, result;
+	unsigned int sg_offset = 0;
+	struct scatterlist *sg = NULL;
+
+	// we're working in LBA mode.  according to the ATA spec, 
+	// we can support up to 28-bit addressing.  I don't know if Datafab
+	// supports beyond 24-bit addressing.  It's kind of hard to test 
+	// since it requires > 8GB CF card.
+	//
+	if (sectors > 0x0FFFFFFF)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	if (info->lun == -1) {
+		result = datafab_determine_lun(us, info);
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			return result;
+	}
+
+	totallen = sectors * info->ssize;
+
+	// Since we don't read more than 64 KB at a time, we have to create
+	// a bounce buffer and move the data a piece at a time between the
+	// bounce buffer and the actual transfer buffer.
+
+	alloclen = min(totallen, 65536u);
+	buffer = kmalloc(alloclen, GFP_NOIO);
+	if (buffer == NULL)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	do {
+		// loop, never allocate or transfer more than 64k at once
+		// (min(128k, 255*info->ssize) is the real limit)
+
+		len = min(totallen, alloclen);
+		thistime = (len / info->ssize) & 0xff;
+
+		command[0] = 0;
+		command[1] = thistime;
+		command[2] = sector & 0xFF;
+		command[3] = (sector >> 8) & 0xFF;
+		command[4] = (sector >> 16) & 0xFF;
+
+		command[5] = 0xE0 + (info->lun << 4);
+		command[5] |= (sector >> 24) & 0x0F;
+		command[6] = 0x20;
+		command[7] = 0x01;
+
+		// send the read command
+		result = datafab_bulk_write(us, command, 8);
+		if (result != USB_STOR_XFER_GOOD)
+			goto leave;
+
+		// read the result
+		result = datafab_bulk_read(us, buffer, len);
+		if (result != USB_STOR_XFER_GOOD)
+			goto leave;
+
+		// Store the data in the transfer buffer
+		usb_stor_access_xfer_buf(buffer, len, us->srb,
+				 &sg, &sg_offset, TO_XFER_BUF);
+
+		sector += thistime;
+		totallen -= len;
+	} while (totallen > 0);
+
+	kfree(buffer);
+	return USB_STOR_TRANSPORT_GOOD;
+
+ leave:
+	kfree(buffer);
+	return USB_STOR_TRANSPORT_ERROR;
+}
+
+
+static int datafab_write_data(struct us_data *us,
+			      struct datafab_info *info,
+			      u32 sector,
+			      u32 sectors)
+{
+	unsigned char *command = us->iobuf;
+	unsigned char *reply = us->iobuf;
+	unsigned char *buffer;
+	unsigned char thistime;
+	unsigned int totallen, alloclen;
+	int len, result;
+	unsigned int sg_offset = 0;
+	struct scatterlist *sg = NULL;
+
+	// we're working in LBA mode.  according to the ATA spec, 
+	// we can support up to 28-bit addressing.  I don't know if Datafab
+	// supports beyond 24-bit addressing.  It's kind of hard to test 
+	// since it requires > 8GB CF card.
+	//
+	if (sectors > 0x0FFFFFFF)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	if (info->lun == -1) {
+		result = datafab_determine_lun(us, info);
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			return result;
+	}
+
+	totallen = sectors * info->ssize;
+
+	// Since we don't write more than 64 KB at a time, we have to create
+	// a bounce buffer and move the data a piece at a time between the
+	// bounce buffer and the actual transfer buffer.
+
+	alloclen = min(totallen, 65536u);
+	buffer = kmalloc(alloclen, GFP_NOIO);
+	if (buffer == NULL)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	do {
+		// loop, never allocate or transfer more than 64k at once
+		// (min(128k, 255*info->ssize) is the real limit)
+
+		len = min(totallen, alloclen);
+		thistime = (len / info->ssize) & 0xff;
+
+		// Get the data from the transfer buffer
+		usb_stor_access_xfer_buf(buffer, len, us->srb,
+				&sg, &sg_offset, FROM_XFER_BUF);
+
+		command[0] = 0;
+		command[1] = thistime;
+		command[2] = sector & 0xFF;
+		command[3] = (sector >> 8) & 0xFF;
+		command[4] = (sector >> 16) & 0xFF;
+
+		command[5] = 0xE0 + (info->lun << 4);
+		command[5] |= (sector >> 24) & 0x0F;
+		command[6] = 0x30;
+		command[7] = 0x02;
+
+		// send the command
+		result = datafab_bulk_write(us, command, 8);
+		if (result != USB_STOR_XFER_GOOD)
+			goto leave;
+
+		// send the data
+		result = datafab_bulk_write(us, buffer, len);
+		if (result != USB_STOR_XFER_GOOD)
+			goto leave;
+
+		// read the result
+		result = datafab_bulk_read(us, reply, 2);
+		if (result != USB_STOR_XFER_GOOD)
+			goto leave;
+
+		if (reply[0] != 0x50 && reply[1] != 0) {
+			usb_stor_dbg(us, "Gah! write return code: %02x %02x\n",
+				     reply[0], reply[1]);
+			result = USB_STOR_TRANSPORT_ERROR;
+			goto leave;
+		}
+
+		sector += thistime;
+		totallen -= len;
+	} while (totallen > 0);
+
+	kfree(buffer);
+	return USB_STOR_TRANSPORT_GOOD;
+
+ leave:
+	kfree(buffer);
+	return USB_STOR_TRANSPORT_ERROR;
+}
+
+
+static int datafab_determine_lun(struct us_data *us,
+				 struct datafab_info *info)
+{
+	// Dual-slot readers can be thought of as dual-LUN devices.
+	// We need to determine which card slot is being used.
+	// We'll send an IDENTIFY DEVICE command and see which LUN responds...
+	//
+	// There might be a better way of doing this?
+
+	static unsigned char scommand[8] = { 0, 1, 0, 0, 0, 0xa0, 0xec, 1 };
+	unsigned char *command = us->iobuf;
+	unsigned char *buf;
+	int count = 0, rc;
+
+	if (!info)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	memcpy(command, scommand, 8);
+	buf = kmalloc(512, GFP_NOIO);
+	if (!buf)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	usb_stor_dbg(us, "locating...\n");
+
+	// we'll try 3 times before giving up...
+	//
+	while (count++ < 3) {
+		command[5] = 0xa0;
+
+		rc = datafab_bulk_write(us, command, 8);
+		if (rc != USB_STOR_XFER_GOOD) {
+			rc = USB_STOR_TRANSPORT_ERROR;
+			goto leave;
+		}
+
+		rc = datafab_bulk_read(us, buf, 512);
+		if (rc == USB_STOR_XFER_GOOD) {
+			info->lun = 0;
+			rc = USB_STOR_TRANSPORT_GOOD;
+			goto leave;
+		}
+
+		command[5] = 0xb0;
+
+		rc = datafab_bulk_write(us, command, 8);
+		if (rc != USB_STOR_XFER_GOOD) {
+			rc = USB_STOR_TRANSPORT_ERROR;
+			goto leave;
+		}
+
+		rc = datafab_bulk_read(us, buf, 512);
+		if (rc == USB_STOR_XFER_GOOD) {
+			info->lun = 1;
+			rc = USB_STOR_TRANSPORT_GOOD;
+			goto leave;
+		}
+
+		msleep(20);
+	}
+
+	rc = USB_STOR_TRANSPORT_ERROR;
+
+ leave:
+	kfree(buf);
+	return rc;
+}
+
+static int datafab_id_device(struct us_data *us,
+			     struct datafab_info *info)
+{
+	// this is a variation of the ATA "IDENTIFY DEVICE" command...according
+	// to the ATA spec, 'Sector Count' isn't used but the Windows driver
+	// sets this bit so we do too...
+	//
+	static unsigned char scommand[8] = { 0, 1, 0, 0, 0, 0xa0, 0xec, 1 };
+	unsigned char *command = us->iobuf;
+	unsigned char *reply;
+	int rc;
+
+	if (!info)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	if (info->lun == -1) {
+		rc = datafab_determine_lun(us, info);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+	}
+
+	memcpy(command, scommand, 8);
+	reply = kmalloc(512, GFP_NOIO);
+	if (!reply)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	command[5] += (info->lun << 4);
+
+	rc = datafab_bulk_write(us, command, 8);
+	if (rc != USB_STOR_XFER_GOOD) {
+		rc = USB_STOR_TRANSPORT_ERROR;
+		goto leave;
+	}
+
+	// we'll go ahead and extract the media capacity while we're here...
+	//
+	rc = datafab_bulk_read(us, reply, 512);
+	if (rc == USB_STOR_XFER_GOOD) {
+		// capacity is at word offset 57-58
+		//
+		info->sectors = ((u32)(reply[117]) << 24) | 
+				((u32)(reply[116]) << 16) |
+				((u32)(reply[115]) <<  8) | 
+				((u32)(reply[114])      );
+		rc = USB_STOR_TRANSPORT_GOOD;
+		goto leave;
+	}
+
+	rc = USB_STOR_TRANSPORT_ERROR;
+
+ leave:
+	kfree(reply);
+	return rc;
+}
+
+
+static int datafab_handle_mode_sense(struct us_data *us,
+				     struct scsi_cmnd * srb, 
+				     int sense_6)
+{
+	static unsigned char rw_err_page[12] = {
+		0x1, 0xA, 0x21, 1, 0, 0, 0, 0, 1, 0, 0, 0
+	};
+	static unsigned char cache_page[12] = {
+		0x8, 0xA, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0
+	};
+	static unsigned char rbac_page[12] = {
+		0x1B, 0xA, 0, 0x81, 0, 0, 0, 0, 0, 0, 0, 0
+	};
+	static unsigned char timer_page[8] = {
+		0x1C, 0x6, 0, 0, 0, 0
+	};
+	unsigned char pc, page_code;
+	unsigned int i = 0;
+	struct datafab_info *info = (struct datafab_info *) (us->extra);
+	unsigned char *ptr = us->iobuf;
+
+	// most of this stuff is just a hack to get things working.  the
+	// datafab reader doesn't present a SCSI interface so we
+	// fudge the SCSI commands...
+	//
+
+	pc = srb->cmnd[2] >> 6;
+	page_code = srb->cmnd[2] & 0x3F;
+
+	switch (pc) {
+	   case 0x0:
+		   usb_stor_dbg(us, "Current values\n");
+		break;
+	   case 0x1:
+		   usb_stor_dbg(us, "Changeable values\n");
+		break;
+	   case 0x2:
+		   usb_stor_dbg(us, "Default values\n");
+		break;
+	   case 0x3:
+		   usb_stor_dbg(us, "Saves values\n");
+		break;
+	}
+
+	memset(ptr, 0, 8);
+	if (sense_6) {
+		ptr[2] = 0x00;		// WP enable: 0x80
+		i = 4;
+	} else {
+		ptr[3] = 0x00;		// WP enable: 0x80
+		i = 8;
+	}
+
+	switch (page_code) {
+	   default:
+		// vendor-specific mode
+		info->sense_key = 0x05;
+		info->sense_asc = 0x24;
+		info->sense_ascq = 0x00;
+		return USB_STOR_TRANSPORT_FAILED;
+
+	   case 0x1:
+		memcpy(ptr + i, rw_err_page, sizeof(rw_err_page));
+		i += sizeof(rw_err_page);
+		break;
+
+	   case 0x8:
+		memcpy(ptr + i, cache_page, sizeof(cache_page));
+		i += sizeof(cache_page);
+		break;
+
+	   case 0x1B:
+		memcpy(ptr + i, rbac_page, sizeof(rbac_page));
+		i += sizeof(rbac_page);
+		break;
+
+	   case 0x1C:
+		memcpy(ptr + i, timer_page, sizeof(timer_page));
+		i += sizeof(timer_page);
+		break;
+
+	   case 0x3F:		// retrieve all pages
+		memcpy(ptr + i, timer_page, sizeof(timer_page));
+		i += sizeof(timer_page);
+		memcpy(ptr + i, rbac_page, sizeof(rbac_page));
+		i += sizeof(rbac_page);
+		memcpy(ptr + i, cache_page, sizeof(cache_page));
+		i += sizeof(cache_page);
+		memcpy(ptr + i, rw_err_page, sizeof(rw_err_page));
+		i += sizeof(rw_err_page);
+		break;
+	}
+
+	if (sense_6)
+		ptr[0] = i - 1;
+	else
+		((__be16 *) ptr)[0] = cpu_to_be16(i - 2);
+	usb_stor_set_xfer_buf(ptr, i, srb);
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static void datafab_info_destructor(void *extra)
+{
+	// this routine is a placeholder...
+	// currently, we don't allocate any extra memory so we're okay
+}
+
+
+// Transport for the Datafab MDCFE-B
+//
+static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+	struct datafab_info *info;
+	int rc;
+	unsigned long block, blocks;
+	unsigned char *ptr = us->iobuf;
+	static unsigned char inquiry_reply[8] = {
+		0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00
+	};
+
+	if (!us->extra) {
+		us->extra = kzalloc(sizeof(struct datafab_info), GFP_NOIO);
+		if (!us->extra)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		us->extra_destructor = datafab_info_destructor;
+  		((struct datafab_info *)us->extra)->lun = -1;
+	}
+
+	info = (struct datafab_info *) (us->extra);
+
+	if (srb->cmnd[0] == INQUIRY) {
+		usb_stor_dbg(us, "INQUIRY - Returning bogus response\n");
+		memcpy(ptr, inquiry_reply, sizeof(inquiry_reply));
+		fill_inquiry_response(us, ptr, 36);
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == READ_CAPACITY) {
+		info->ssize = 0x200;  // hard coded 512 byte sectors as per ATA spec
+		rc = datafab_id_device(us, info);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+
+		usb_stor_dbg(us, "READ_CAPACITY:  %ld sectors, %ld bytes per sector\n",
+			     info->sectors, info->ssize);
+
+		// build the reply
+		// we need the last sector, not the number of sectors
+		((__be32 *) ptr)[0] = cpu_to_be32(info->sectors - 1);
+		((__be32 *) ptr)[1] = cpu_to_be32(info->ssize);
+		usb_stor_set_xfer_buf(ptr, 8, srb);
+
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == MODE_SELECT_10) {
+		usb_stor_dbg(us, "Gah! MODE_SELECT_10\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	// don't bother implementing READ_6 or WRITE_6.
+	//
+	if (srb->cmnd[0] == READ_10) {
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+			((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
+
+		usb_stor_dbg(us, "READ_10: read block 0x%04lx  count %ld\n",
+			     block, blocks);
+		return datafab_read_data(us, info, block, blocks);
+	}
+
+	if (srb->cmnd[0] == READ_12) {
+		// we'll probably never see a READ_12 but we'll do it anyway...
+		//
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+			((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
+			 ((u32)(srb->cmnd[8]) <<  8) | ((u32)(srb->cmnd[9]));
+
+		usb_stor_dbg(us, "READ_12: read block 0x%04lx  count %ld\n",
+			     block, blocks);
+		return datafab_read_data(us, info, block, blocks);
+	}
+
+	if (srb->cmnd[0] == WRITE_10) {
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+			((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
+
+		usb_stor_dbg(us, "WRITE_10: write block 0x%04lx count %ld\n",
+			     block, blocks);
+		return datafab_write_data(us, info, block, blocks);
+	}
+
+	if (srb->cmnd[0] == WRITE_12) {
+		// we'll probably never see a WRITE_12 but we'll do it anyway...
+		//
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+			((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
+			 ((u32)(srb->cmnd[8]) <<  8) | ((u32)(srb->cmnd[9]));
+
+		usb_stor_dbg(us, "WRITE_12: write block 0x%04lx count %ld\n",
+			     block, blocks);
+		return datafab_write_data(us, info, block, blocks);
+	}
+
+	if (srb->cmnd[0] == TEST_UNIT_READY) {
+		usb_stor_dbg(us, "TEST_UNIT_READY\n");
+		return datafab_id_device(us, info);
+	}
+
+	if (srb->cmnd[0] == REQUEST_SENSE) {
+		usb_stor_dbg(us, "REQUEST_SENSE - Returning faked response\n");
+
+		// this response is pretty bogus right now.  eventually if necessary
+		// we can set the correct sense data.  so far though it hasn't been
+		// necessary
+		//
+		memset(ptr, 0, 18);
+		ptr[0] = 0xF0;
+		ptr[2] = info->sense_key;
+		ptr[7] = 11;
+		ptr[12] = info->sense_asc;
+		ptr[13] = info->sense_ascq;
+		usb_stor_set_xfer_buf(ptr, 18, srb);
+
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == MODE_SENSE) {
+		usb_stor_dbg(us, "MODE_SENSE_6 detected\n");
+		return datafab_handle_mode_sense(us, srb, 1);
+	}
+
+	if (srb->cmnd[0] == MODE_SENSE_10) {
+		usb_stor_dbg(us, "MODE_SENSE_10 detected\n");
+		return datafab_handle_mode_sense(us, srb, 0);
+	}
+
+	if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
+		/*
+		 * sure.  whatever.  not like we can stop the user from
+		 * popping the media out of the device (no locking doors, etc)
+		 */
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == START_STOP) {
+		/*
+		 * this is used by sd.c'check_scsidisk_media_change to detect
+		 * media change
+		 */
+		usb_stor_dbg(us, "START_STOP\n");
+		/*
+		 * the first datafab_id_device after a media change returns
+		 * an error (determined experimentally)
+		 */
+		rc = datafab_id_device(us, info);
+		if (rc == USB_STOR_TRANSPORT_GOOD) {
+			info->sense_key = NO_SENSE;
+			srb->result = SUCCESS;
+		} else {
+			info->sense_key = UNIT_ATTENTION;
+			srb->result = SAM_STAT_CHECK_CONDITION;
+		}
+		return rc;
+	}
+
+	usb_stor_dbg(us, "Gah! Unknown command: %d (0x%x)\n",
+		     srb->cmnd[0], srb->cmnd[0]);
+	info->sense_key = 0x05;
+	info->sense_asc = 0x20;
+	info->sense_ascq = 0x00;
+	return USB_STOR_TRANSPORT_FAILED;
+}
+
+static struct scsi_host_template datafab_host_template;
+
+static int datafab_probe(struct usb_interface *intf,
+			 const struct usb_device_id *id)
+{
+	struct us_data *us;
+	int result;
+
+	result = usb_stor_probe1(&us, intf, id,
+			(id - datafab_usb_ids) + datafab_unusual_dev_list,
+			&datafab_host_template);
+	if (result)
+		return result;
+
+	us->transport_name  = "Datafab Bulk-Only";
+	us->transport = datafab_transport;
+	us->transport_reset = usb_stor_Bulk_reset;
+	us->max_lun = 1;
+
+	result = usb_stor_probe2(us);
+	return result;
+}
+
+static struct usb_driver datafab_driver = {
+	.name =		DRV_NAME,
+	.probe =	datafab_probe,
+	.disconnect =	usb_stor_disconnect,
+	.suspend =	usb_stor_suspend,
+	.resume =	usb_stor_resume,
+	.reset_resume =	usb_stor_reset_resume,
+	.pre_reset =	usb_stor_pre_reset,
+	.post_reset =	usb_stor_post_reset,
+	.id_table =	datafab_usb_ids,
+	.soft_unbind =	1,
+	.no_dynamic_id = 1,
+};
+
+module_usb_stor_driver(datafab_driver, datafab_host_template, DRV_NAME);
diff --git a/drivers/usb/storage/debug.c b/drivers/usb/storage/debug.c
new file mode 100644
index 0000000..d7f50b7
--- /dev/null
+++ b/drivers/usb/storage/debug.c
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for USB Mass Storage compliant devices
+ * Debugging Functions Source Code File
+ *
+ * Current development and maintenance by:
+ *   (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * Developed with the assistance of:
+ *   (c) 2002 Alan Stern <stern@rowland.org>
+ *
+ * Initial work by:
+ *   (c) 1999 Michael Gee (michael@linuxspecific.com)
+ *
+ * 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.
+ */
+
+#include <linux/device.h>
+#include <linux/cdrom.h>
+#include <linux/export.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
+
+#include "usb.h"
+#include "debug.h"
+#include "scsi.h"
+
+
+void usb_stor_show_command(const struct us_data *us, struct scsi_cmnd *srb)
+{
+	char *what = NULL;
+
+	switch (srb->cmnd[0]) {
+	case TEST_UNIT_READY: what = "TEST_UNIT_READY"; break;
+	case REZERO_UNIT: what = "REZERO_UNIT"; break;
+	case REQUEST_SENSE: what = "REQUEST_SENSE"; break;
+	case FORMAT_UNIT: what = "FORMAT_UNIT"; break;
+	case READ_BLOCK_LIMITS: what = "READ_BLOCK_LIMITS"; break;
+	case REASSIGN_BLOCKS: what = "REASSIGN_BLOCKS"; break;
+	case READ_6: what = "READ_6"; break;
+	case WRITE_6: what = "WRITE_6"; break;
+	case SEEK_6: what = "SEEK_6"; break;
+	case READ_REVERSE: what = "READ_REVERSE"; break;
+	case WRITE_FILEMARKS: what = "WRITE_FILEMARKS"; break;
+	case SPACE: what = "SPACE"; break;
+	case INQUIRY: what = "INQUIRY"; break;
+	case RECOVER_BUFFERED_DATA: what = "RECOVER_BUFFERED_DATA"; break;
+	case MODE_SELECT: what = "MODE_SELECT"; break;
+	case RESERVE: what = "RESERVE"; break;
+	case RELEASE: what = "RELEASE"; break;
+	case COPY: what = "COPY"; break;
+	case ERASE: what = "ERASE"; break;
+	case MODE_SENSE: what = "MODE_SENSE"; break;
+	case START_STOP: what = "START_STOP"; break;
+	case RECEIVE_DIAGNOSTIC: what = "RECEIVE_DIAGNOSTIC"; break;
+	case SEND_DIAGNOSTIC: what = "SEND_DIAGNOSTIC"; break;
+	case ALLOW_MEDIUM_REMOVAL: what = "ALLOW_MEDIUM_REMOVAL"; break;
+	case SET_WINDOW: what = "SET_WINDOW"; break;
+	case READ_CAPACITY: what = "READ_CAPACITY"; break;
+	case READ_10: what = "READ_10"; break;
+	case WRITE_10: what = "WRITE_10"; break;
+	case SEEK_10: what = "SEEK_10"; break;
+	case WRITE_VERIFY: what = "WRITE_VERIFY"; break;
+	case VERIFY: what = "VERIFY"; break;
+	case SEARCH_HIGH: what = "SEARCH_HIGH"; break;
+	case SEARCH_EQUAL: what = "SEARCH_EQUAL"; break;
+	case SEARCH_LOW: what = "SEARCH_LOW"; break;
+	case SET_LIMITS: what = "SET_LIMITS"; break;
+	case READ_POSITION: what = "READ_POSITION"; break;
+	case SYNCHRONIZE_CACHE: what = "SYNCHRONIZE_CACHE"; break;
+	case LOCK_UNLOCK_CACHE: what = "LOCK_UNLOCK_CACHE"; break;
+	case READ_DEFECT_DATA: what = "READ_DEFECT_DATA"; break;
+	case MEDIUM_SCAN: what = "MEDIUM_SCAN"; break;
+	case COMPARE: what = "COMPARE"; break;
+	case COPY_VERIFY: what = "COPY_VERIFY"; break;
+	case WRITE_BUFFER: what = "WRITE_BUFFER"; break;
+	case READ_BUFFER: what = "READ_BUFFER"; break;
+	case UPDATE_BLOCK: what = "UPDATE_BLOCK"; break;
+	case READ_LONG: what = "READ_LONG"; break;
+	case WRITE_LONG: what = "WRITE_LONG"; break;
+	case CHANGE_DEFINITION: what = "CHANGE_DEFINITION"; break;
+	case WRITE_SAME: what = "WRITE_SAME"; break;
+	case GPCMD_READ_SUBCHANNEL: what = "READ SUBCHANNEL"; break;
+	case READ_TOC: what = "READ_TOC"; break;
+	case GPCMD_READ_HEADER: what = "READ HEADER"; break;
+	case GPCMD_PLAY_AUDIO_10: what = "PLAY AUDIO (10)"; break;
+	case GPCMD_PLAY_AUDIO_MSF: what = "PLAY AUDIO MSF"; break;
+	case GPCMD_GET_EVENT_STATUS_NOTIFICATION:
+		what = "GET EVENT/STATUS NOTIFICATION"; break;
+	case GPCMD_PAUSE_RESUME: what = "PAUSE/RESUME"; break;
+	case LOG_SELECT: what = "LOG_SELECT"; break;
+	case LOG_SENSE: what = "LOG_SENSE"; break;
+	case GPCMD_STOP_PLAY_SCAN: what = "STOP PLAY/SCAN"; break;
+	case GPCMD_READ_DISC_INFO: what = "READ DISC INFORMATION"; break;
+	case GPCMD_READ_TRACK_RZONE_INFO:
+		what = "READ TRACK INFORMATION"; break;
+	case GPCMD_RESERVE_RZONE_TRACK: what = "RESERVE TRACK"; break;
+	case GPCMD_SEND_OPC: what = "SEND OPC"; break;
+	case MODE_SELECT_10: what = "MODE_SELECT_10"; break;
+	case GPCMD_REPAIR_RZONE_TRACK: what = "REPAIR TRACK"; break;
+	case 0x59: what = "READ MASTER CUE"; break;
+	case MODE_SENSE_10: what = "MODE_SENSE_10"; break;
+	case GPCMD_CLOSE_TRACK: what = "CLOSE TRACK/SESSION"; break;
+	case 0x5C: what = "READ BUFFER CAPACITY"; break;
+	case 0x5D: what = "SEND CUE SHEET"; break;
+	case GPCMD_BLANK: what = "BLANK"; break;
+	case REPORT_LUNS: what = "REPORT LUNS"; break;
+	case MOVE_MEDIUM: what = "MOVE_MEDIUM or PLAY AUDIO (12)"; break;
+	case READ_12: what = "READ_12"; break;
+	case WRITE_12: what = "WRITE_12"; break;
+	case WRITE_VERIFY_12: what = "WRITE_VERIFY_12"; break;
+	case SEARCH_HIGH_12: what = "SEARCH_HIGH_12"; break;
+	case SEARCH_EQUAL_12: what = "SEARCH_EQUAL_12"; break;
+	case SEARCH_LOW_12: what = "SEARCH_LOW_12"; break;
+	case SEND_VOLUME_TAG: what = "SEND_VOLUME_TAG"; break;
+	case READ_ELEMENT_STATUS: what = "READ_ELEMENT_STATUS"; break;
+	case GPCMD_READ_CD_MSF: what = "READ CD MSF"; break;
+	case GPCMD_SCAN: what = "SCAN"; break;
+	case GPCMD_SET_SPEED: what = "SET CD SPEED"; break;
+	case GPCMD_MECHANISM_STATUS: what = "MECHANISM STATUS"; break;
+	case GPCMD_READ_CD: what = "READ CD"; break;
+	case 0xE1: what = "WRITE CONTINUE"; break;
+	case WRITE_LONG_2: what = "WRITE_LONG_2"; break;
+	default: what = "(unknown command)"; break;
+	}
+	usb_stor_dbg(us, "Command %s (%d bytes)\n", what, srb->cmd_len);
+	usb_stor_dbg(us, "bytes: %*ph\n", min_t(int, srb->cmd_len, 16),
+		     (const unsigned char *)srb->cmnd);
+}
+
+void usb_stor_show_sense(const struct us_data *us,
+			 unsigned char key,
+			 unsigned char asc,
+			 unsigned char ascq)
+{
+	const char *what, *keystr, *fmt;
+
+	keystr = scsi_sense_key_string(key);
+	what = scsi_extd_sense_format(asc, ascq, &fmt);
+
+	if (keystr == NULL)
+		keystr = "(Unknown Key)";
+	if (what == NULL)
+		what = "(unknown ASC/ASCQ)";
+
+	if (fmt)
+		usb_stor_dbg(us, "%s: %s (%s%x)\n", keystr, what, fmt, ascq);
+	else
+		usb_stor_dbg(us, "%s: %s\n", keystr, what);
+}
+
+void usb_stor_dbg(const struct us_data *us, const char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+
+	dev_vprintk_emit(LOGLEVEL_DEBUG, &us->pusb_dev->dev, fmt, args);
+
+	va_end(args);
+}
+EXPORT_SYMBOL_GPL(usb_stor_dbg);
diff --git a/drivers/usb/storage/debug.h b/drivers/usb/storage/debug.h
new file mode 100644
index 0000000..6d64f34
--- /dev/null
+++ b/drivers/usb/storage/debug.h
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for USB Mass Storage compliant devices
+ * Debugging Functions Header File
+ *
+ * Current development and maintenance by:
+ *   (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * Initial work by:
+ *   (c) 1999 Michael Gee (michael@linuxspecific.com)
+ *
+ * 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.
+ */
+
+#ifndef _DEBUG_H_
+#define _DEBUG_H_
+
+#include <linux/kernel.h>
+
+#define USB_STORAGE "usb-storage: "
+
+#ifdef CONFIG_USB_STORAGE_DEBUG
+void usb_stor_show_command(const struct us_data *us, struct scsi_cmnd *srb);
+void usb_stor_show_sense(const struct us_data *us, unsigned char key,
+			 unsigned char asc, unsigned char ascq);
+__printf(2, 3) void usb_stor_dbg(const struct us_data *us,
+				 const char *fmt, ...);
+
+#define US_DEBUG(x)		x
+#else
+__printf(2, 3)
+static inline void _usb_stor_dbg(const struct us_data *us,
+				 const char *fmt, ...)
+{
+}
+#define usb_stor_dbg(us, fmt, ...)				\
+	do { if (0) _usb_stor_dbg(us, fmt, ##__VA_ARGS__); } while (0)
+#define US_DEBUG(x)
+#endif
+
+#endif
diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c
new file mode 100644
index 0000000..4d261e4
--- /dev/null
+++ b/drivers/usb/storage/ene_ub6250.c
@@ -0,0 +1,2442 @@
+// SPDX-License-Identifier: GPL-2.0+
+#include <linux/jiffies.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include <linux/firmware.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "protocol.h"
+#include "debug.h"
+#include "scsiglue.h"
+
+#define SD_INIT1_FIRMWARE "ene-ub6250/sd_init1.bin"
+#define SD_INIT2_FIRMWARE "ene-ub6250/sd_init2.bin"
+#define SD_RW_FIRMWARE "ene-ub6250/sd_rdwr.bin"
+#define MS_INIT_FIRMWARE "ene-ub6250/ms_init.bin"
+#define MSP_RW_FIRMWARE "ene-ub6250/msp_rdwr.bin"
+#define MS_RW_FIRMWARE "ene-ub6250/ms_rdwr.bin"
+
+#define DRV_NAME "ums_eneub6250"
+
+MODULE_DESCRIPTION("Driver for ENE UB6250 reader");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(SD_INIT1_FIRMWARE);
+MODULE_FIRMWARE(SD_INIT2_FIRMWARE);
+MODULE_FIRMWARE(SD_RW_FIRMWARE);
+MODULE_FIRMWARE(MS_INIT_FIRMWARE);
+MODULE_FIRMWARE(MSP_RW_FIRMWARE);
+MODULE_FIRMWARE(MS_RW_FIRMWARE);
+
+/*
+ * The table of devices
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+		    vendorName, productName, useProtocol, useTransport, \
+		    initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+	.driver_info = (flags)}
+
+static struct usb_device_id ene_ub6250_usb_ids[] = {
+#	include "unusual_ene_ub6250.h"
+	{ }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, ene_ub6250_usb_ids);
+
+#undef UNUSUAL_DEV
+
+/*
+ * The flags table
+ */
+#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
+		    vendor_name, product_name, use_protocol, use_transport, \
+		    init_function, Flags) \
+{ \
+	.vendorName = vendor_name,	\
+	.productName = product_name,	\
+	.useProtocol = use_protocol,	\
+	.useTransport = use_transport,	\
+	.initFunction = init_function,	\
+}
+
+static struct us_unusual_dev ene_ub6250_unusual_dev_list[] = {
+#	include "unusual_ene_ub6250.h"
+	{ }		/* Terminating entry */
+};
+
+#undef UNUSUAL_DEV
+
+
+
+/* ENE bin code len */
+#define ENE_BIN_CODE_LEN    0x800
+/* EnE HW Register */
+#define REG_CARD_STATUS     0xFF83
+#define REG_HW_TRAP1        0xFF89
+
+/* SRB Status */
+#define SS_SUCCESS		0x000000	/* No Sense */
+#define SS_NOT_READY		0x023A00	/* Medium not present */
+#define SS_MEDIUM_ERR		0x031100	/* Unrecovered read error */
+#define SS_HW_ERR		0x040800	/* Communication failure */
+#define SS_ILLEGAL_REQUEST	0x052000	/* Invalid command */
+#define SS_UNIT_ATTENTION	0x062900	/* Reset occurred */
+
+/* ENE Load FW Pattern */
+#define SD_INIT1_PATTERN   1
+#define SD_INIT2_PATTERN   2
+#define SD_RW_PATTERN      3
+#define MS_INIT_PATTERN    4
+#define MSP_RW_PATTERN     5
+#define MS_RW_PATTERN      6
+#define SM_INIT_PATTERN    7
+#define SM_RW_PATTERN      8
+
+#define FDIR_WRITE         0
+#define FDIR_READ          1
+
+/* For MS Card */
+
+/* Status Register 1 */
+#define MS_REG_ST1_MB           0x80    /* media busy */
+#define MS_REG_ST1_FB1          0x40    /* flush busy 1 */
+#define MS_REG_ST1_DTER         0x20    /* error on data(corrected) */
+#define MS_REG_ST1_UCDT         0x10    /* unable to correct data */
+#define MS_REG_ST1_EXER         0x08    /* error on extra(corrected) */
+#define MS_REG_ST1_UCEX         0x04    /* unable to correct extra */
+#define MS_REG_ST1_FGER         0x02    /* error on overwrite flag(corrected) */
+#define MS_REG_ST1_UCFG         0x01    /* unable to correct overwrite flag */
+#define MS_REG_ST1_DEFAULT	(MS_REG_ST1_MB | MS_REG_ST1_FB1 | MS_REG_ST1_DTER | MS_REG_ST1_UCDT | MS_REG_ST1_EXER | MS_REG_ST1_UCEX | MS_REG_ST1_FGER | MS_REG_ST1_UCFG)
+
+/* Overwrite Area */
+#define MS_REG_OVR_BKST		0x80            /* block status */
+#define MS_REG_OVR_BKST_OK	MS_REG_OVR_BKST     /* OK */
+#define MS_REG_OVR_BKST_NG	0x00            /* NG */
+#define MS_REG_OVR_PGST0	0x40            /* page status */
+#define MS_REG_OVR_PGST1	0x20
+#define MS_REG_OVR_PGST_MASK	(MS_REG_OVR_PGST0 | MS_REG_OVR_PGST1)
+#define MS_REG_OVR_PGST_OK	(MS_REG_OVR_PGST0 | MS_REG_OVR_PGST1) /* OK */
+#define MS_REG_OVR_PGST_NG	MS_REG_OVR_PGST1                      /* NG */
+#define MS_REG_OVR_PGST_DATA_ERROR	0x00        /* data error */
+#define MS_REG_OVR_UDST			0x10        /* update status */
+#define MS_REG_OVR_UDST_UPDATING	0x00        /* updating */
+#define MS_REG_OVR_UDST_NO_UPDATE	MS_REG_OVR_UDST
+#define MS_REG_OVR_RESERVED	0x08
+#define MS_REG_OVR_DEFAULT	(MS_REG_OVR_BKST_OK | MS_REG_OVR_PGST_OK | MS_REG_OVR_UDST_NO_UPDATE | MS_REG_OVR_RESERVED)
+
+/* Management Flag */
+#define MS_REG_MNG_SCMS0	0x20    /* serial copy management system */
+#define MS_REG_MNG_SCMS1	0x10
+#define MS_REG_MNG_SCMS_MASK		(MS_REG_MNG_SCMS0 | MS_REG_MNG_SCMS1)
+#define MS_REG_MNG_SCMS_COPY_OK		(MS_REG_MNG_SCMS0 | MS_REG_MNG_SCMS1)
+#define MS_REG_MNG_SCMS_ONE_COPY	MS_REG_MNG_SCMS1
+#define MS_REG_MNG_SCMS_NO_COPY	0x00
+#define MS_REG_MNG_ATFLG	0x08    /* address transfer table flag */
+#define MS_REG_MNG_ATFLG_OTHER	MS_REG_MNG_ATFLG    /* other */
+#define MS_REG_MNG_ATFLG_ATTBL	0x00	/* address transfer table */
+#define MS_REG_MNG_SYSFLG	0x04	/* system flag */
+#define MS_REG_MNG_SYSFLG_USER	MS_REG_MNG_SYSFLG   /* user block */
+#define MS_REG_MNG_SYSFLG_BOOT	0x00	/* system block */
+#define MS_REG_MNG_RESERVED	0xc3
+#define MS_REG_MNG_DEFAULT	(MS_REG_MNG_SCMS_COPY_OK | MS_REG_MNG_ATFLG_OTHER | MS_REG_MNG_SYSFLG_USER | MS_REG_MNG_RESERVED)
+
+
+#define MS_MAX_PAGES_PER_BLOCK		32
+#define MS_MAX_INITIAL_ERROR_BLOCKS 	10
+#define MS_LIB_BITS_PER_BYTE		8
+
+#define MS_SYSINF_FORMAT_FAT		1
+#define MS_SYSINF_USAGE_GENERAL		0
+
+#define MS_SYSINF_MSCLASS_TYPE_1	1
+#define MS_SYSINF_PAGE_SIZE		MS_BYTES_PER_PAGE /* fixed */
+
+#define MS_SYSINF_CARDTYPE_RDONLY	1
+#define MS_SYSINF_CARDTYPE_RDWR		2
+#define MS_SYSINF_CARDTYPE_HYBRID	3
+#define MS_SYSINF_SECURITY		0x01
+#define MS_SYSINF_SECURITY_NO_SUPPORT	MS_SYSINF_SECURITY
+#define MS_SYSINF_SECURITY_SUPPORT	0
+
+#define MS_SYSINF_RESERVED1		1
+#define MS_SYSINF_RESERVED2		1
+
+#define MS_SYSENT_TYPE_INVALID_BLOCK	0x01
+#define MS_SYSENT_TYPE_CIS_IDI		0x0a    /* CIS/IDI */
+
+#define SIZE_OF_KIRO		1024
+#define BYTE_MASK		0xff
+
+/* ms error code */
+#define MS_STATUS_WRITE_PROTECT	0x0106
+#define MS_STATUS_SUCCESS	0x0000
+#define MS_ERROR_FLASH_READ	0x8003
+#define MS_ERROR_FLASH_ERASE	0x8005
+#define MS_LB_ERROR		0xfff0
+#define MS_LB_BOOT_BLOCK	0xfff1
+#define MS_LB_INITIAL_ERROR	0xfff2
+#define MS_STATUS_SUCCESS_WITH_ECC 0xfff3
+#define MS_LB_ACQUIRED_ERROR	0xfff4
+#define MS_LB_NOT_USED_ERASED	0xfff5
+#define MS_NOCARD_ERROR		0xfff8
+#define MS_NO_MEMORY_ERROR	0xfff9
+#define MS_STATUS_INT_ERROR	0xfffa
+#define MS_STATUS_ERROR		0xfffe
+#define MS_LB_NOT_USED		0xffff
+
+#define MS_REG_MNG_SYSFLG	0x04    /* system flag */
+#define MS_REG_MNG_SYSFLG_USER	MS_REG_MNG_SYSFLG   /* user block */
+
+#define MS_BOOT_BLOCK_ID                        0x0001
+#define MS_BOOT_BLOCK_FORMAT_VERSION            0x0100
+#define MS_BOOT_BLOCK_DATA_ENTRIES              2
+
+#define MS_NUMBER_OF_SYSTEM_ENTRY       	4
+#define MS_NUMBER_OF_BOOT_BLOCK			2
+#define MS_BYTES_PER_PAGE			512
+#define MS_LOGICAL_BLOCKS_PER_SEGMENT		496
+#define MS_LOGICAL_BLOCKS_IN_1ST_SEGMENT        494
+
+#define MS_PHYSICAL_BLOCKS_PER_SEGMENT		0x200 /* 512 */
+#define MS_PHYSICAL_BLOCKS_PER_SEGMENT_MASK     0x1ff
+
+/* overwrite area */
+#define MS_REG_OVR_BKST		0x80		/* block status */
+#define MS_REG_OVR_BKST_OK	MS_REG_OVR_BKST	/* OK */
+#define MS_REG_OVR_BKST_NG	0x00            /* NG */
+
+/* Status Register 1 */
+#define MS_REG_ST1_DTER		0x20	/* error on data(corrected) */
+#define MS_REG_ST1_EXER		0x08	/* error on extra(corrected) */
+#define MS_REG_ST1_FGER		0x02	/* error on overwrite flag(corrected) */
+
+/* MemoryStick Register */
+/* Status Register 0 */
+#define MS_REG_ST0_WP		0x01	/* write protected */
+#define MS_REG_ST0_WP_ON	MS_REG_ST0_WP
+
+#define MS_LIB_CTRL_RDONLY      0
+#define MS_LIB_CTRL_WRPROTECT   1
+
+/*dphy->log table */
+#define ms_libconv_to_logical(pdx, PhyBlock) (((PhyBlock) >= (pdx)->MS_Lib.NumberOfPhyBlock) ? MS_STATUS_ERROR : (pdx)->MS_Lib.Phy2LogMap[PhyBlock])
+#define ms_libconv_to_physical(pdx, LogBlock) (((LogBlock) >= (pdx)->MS_Lib.NumberOfLogBlock) ? MS_STATUS_ERROR : (pdx)->MS_Lib.Log2PhyMap[LogBlock])
+
+#define ms_lib_ctrl_set(pdx, Flag)	((pdx)->MS_Lib.flags |= (1 << (Flag)))
+#define ms_lib_ctrl_reset(pdx, Flag)	((pdx)->MS_Lib.flags &= ~(1 << (Flag)))
+#define ms_lib_ctrl_check(pdx, Flag)	((pdx)->MS_Lib.flags & (1 << (Flag)))
+
+#define ms_lib_iswritable(pdx) ((ms_lib_ctrl_check((pdx), MS_LIB_CTRL_RDONLY) == 0) && (ms_lib_ctrl_check(pdx, MS_LIB_CTRL_WRPROTECT) == 0))
+#define ms_lib_clear_pagemap(pdx) memset((pdx)->MS_Lib.pagemap, 0, sizeof((pdx)->MS_Lib.pagemap))
+#define memstick_logaddr(logadr1, logadr0) ((((u16)(logadr1)) << 8) | (logadr0))
+
+
+struct SD_STATUS {
+	u8    Insert:1;
+	u8    Ready:1;
+	u8    MediaChange:1;
+	u8    IsMMC:1;
+	u8    HiCapacity:1;
+	u8    HiSpeed:1;
+	u8    WtP:1;
+	u8    Reserved:1;
+};
+
+struct MS_STATUS {
+	u8    Insert:1;
+	u8    Ready:1;
+	u8    MediaChange:1;
+	u8    IsMSPro:1;
+	u8    IsMSPHG:1;
+	u8    Reserved1:1;
+	u8    WtP:1;
+	u8    Reserved2:1;
+};
+
+struct SM_STATUS {
+	u8    Insert:1;
+	u8    Ready:1;
+	u8    MediaChange:1;
+	u8    Reserved:3;
+	u8    WtP:1;
+	u8    IsMS:1;
+};
+
+struct ms_bootblock_cis {
+	u8 bCistplDEVICE[6];    /* 0 */
+	u8 bCistplDEVICE0C[6];  /* 6 */
+	u8 bCistplJEDECC[4];    /* 12 */
+	u8 bCistplMANFID[6];    /* 16 */
+	u8 bCistplVER1[32];     /* 22 */
+	u8 bCistplFUNCID[4];    /* 54 */
+	u8 bCistplFUNCE0[4];    /* 58 */
+	u8 bCistplFUNCE1[5];    /* 62 */
+	u8 bCistplCONF[7];      /* 67 */
+	u8 bCistplCFTBLENT0[10];/* 74 */
+	u8 bCistplCFTBLENT1[8]; /* 84 */
+	u8 bCistplCFTBLENT2[12];/* 92 */
+	u8 bCistplCFTBLENT3[8]; /* 104 */
+	u8 bCistplCFTBLENT4[17];/* 112 */
+	u8 bCistplCFTBLENT5[8]; /* 129 */
+	u8 bCistplCFTBLENT6[17];/* 137 */
+	u8 bCistplCFTBLENT7[8]; /* 154 */
+	u8 bCistplNOLINK[3];    /* 162 */
+} ;
+
+struct ms_bootblock_idi {
+#define MS_IDI_GENERAL_CONF 0x848A
+	u16 wIDIgeneralConfiguration;	/* 0 */
+	u16 wIDInumberOfCylinder;	/* 1 */
+	u16 wIDIreserved0;		/* 2 */
+	u16 wIDInumberOfHead;		/* 3 */
+	u16 wIDIbytesPerTrack;		/* 4 */
+	u16 wIDIbytesPerSector;		/* 5 */
+	u16 wIDIsectorsPerTrack;	/* 6 */
+	u16 wIDItotalSectors[2];	/* 7-8  high,low */
+	u16 wIDIreserved1[11];		/* 9-19 */
+	u16 wIDIbufferType;		/* 20 */
+	u16 wIDIbufferSize;		/* 21 */
+	u16 wIDIlongCmdECC;		/* 22 */
+	u16 wIDIfirmVersion[4];		/* 23-26 */
+	u16 wIDImodelName[20];		/* 27-46 */
+	u16 wIDIreserved2;		/* 47 */
+	u16 wIDIlongWordSupported;	/* 48 */
+	u16 wIDIdmaSupported;		/* 49 */
+	u16 wIDIreserved3;		/* 50 */
+	u16 wIDIpioTiming;		/* 51 */
+	u16 wIDIdmaTiming;		/* 52 */
+	u16 wIDItransferParameter;	/* 53 */
+	u16 wIDIformattedCylinder;	/* 54 */
+	u16 wIDIformattedHead;		/* 55 */
+	u16 wIDIformattedSectorsPerTrack;/* 56 */
+	u16 wIDIformattedTotalSectors[2];/* 57-58 */
+	u16 wIDImultiSector;		/* 59 */
+	u16 wIDIlbaSectors[2];		/* 60-61 */
+	u16 wIDIsingleWordDMA;		/* 62 */
+	u16 wIDImultiWordDMA;		/* 63 */
+	u16 wIDIreserved4[192];		/* 64-255 */
+};
+
+struct ms_bootblock_sysent_rec {
+	u32 dwStart;
+	u32 dwSize;
+	u8 bType;
+	u8 bReserved[3];
+};
+
+struct ms_bootblock_sysent {
+	struct ms_bootblock_sysent_rec entry[MS_NUMBER_OF_SYSTEM_ENTRY];
+};
+
+struct ms_bootblock_sysinf {
+	u8 bMsClass;			/* must be 1 */
+	u8 bCardType;			/* see below */
+	u16 wBlockSize;			/* n KB */
+	u16 wBlockNumber;		/* number of physical block */
+	u16 wTotalBlockNumber;		/* number of logical block */
+	u16 wPageSize;			/* must be 0x200 */
+	u8 bExtraSize;			/* 0x10 */
+	u8 bSecuritySupport;
+	u8 bAssemblyDate[8];
+	u8 bFactoryArea[4];
+	u8 bAssemblyMakerCode;
+	u8 bAssemblyMachineCode[3];
+	u16 wMemoryMakerCode;
+	u16 wMemoryDeviceCode;
+	u16 wMemorySize;
+	u8 bReserved1;
+	u8 bReserved2;
+	u8 bVCC;
+	u8 bVPP;
+	u16 wControllerChipNumber;
+	u16 wControllerFunction;	/* New MS */
+	u8 bReserved3[9];		/* New MS */
+	u8 bParallelSupport;		/* New MS */
+	u16 wFormatValue;		/* New MS */
+	u8 bFormatType;
+	u8 bUsage;
+	u8 bDeviceType;
+	u8 bReserved4[22];
+	u8 bFUValue3;
+	u8 bFUValue4;
+	u8 bReserved5[15];
+};
+
+struct ms_bootblock_header {
+	u16 wBlockID;
+	u16 wFormatVersion;
+	u8 bReserved1[184];
+	u8 bNumberOfDataEntry;
+	u8 bReserved2[179];
+};
+
+struct ms_bootblock_page0 {
+	struct ms_bootblock_header header;
+	struct ms_bootblock_sysent sysent;
+	struct ms_bootblock_sysinf sysinf;
+};
+
+struct ms_bootblock_cis_idi {
+	union {
+		struct ms_bootblock_cis cis;
+		u8 dmy[256];
+	} cis;
+
+	union {
+		struct ms_bootblock_idi idi;
+		u8 dmy[256];
+	} idi;
+
+};
+
+/* ENE MS Lib struct */
+struct ms_lib_type_extdat {
+	u8 reserved;
+	u8 intr;
+	u8 status0;
+	u8 status1;
+	u8 ovrflg;
+	u8 mngflg;
+	u16 logadr;
+};
+
+struct ms_lib_ctrl {
+	u32 flags;
+	u32 BytesPerSector;
+	u32 NumberOfCylinder;
+	u32 SectorsPerCylinder;
+	u16 cardType;			/* R/W, RO, Hybrid */
+	u16 blockSize;
+	u16 PagesPerBlock;
+	u16 NumberOfPhyBlock;
+	u16 NumberOfLogBlock;
+	u16 NumberOfSegment;
+	u16 *Phy2LogMap;		/* phy2log table */
+	u16 *Log2PhyMap;		/* log2phy table */
+	u16 wrtblk;
+	unsigned char *pagemap[(MS_MAX_PAGES_PER_BLOCK + (MS_LIB_BITS_PER_BYTE-1)) / MS_LIB_BITS_PER_BYTE];
+	unsigned char *blkpag;
+	struct ms_lib_type_extdat *blkext;
+	unsigned char copybuf[512];
+};
+
+
+/* SD Block Length */
+/* 2^9 = 512 Bytes, The HW maximum read/write data length */
+#define SD_BLOCK_LEN  9
+
+struct ene_ub6250_info {
+
+	/* I/O bounce buffer */
+	u8		*bbuf;
+
+	/* for 6250 code */
+	struct SD_STATUS	SD_Status;
+	struct MS_STATUS	MS_Status;
+	struct SM_STATUS	SM_Status;
+
+	/* ----- SD Control Data ---------------- */
+	/*SD_REGISTER SD_Regs; */
+	u16		SD_Block_Mult;
+	u8		SD_READ_BL_LEN;
+	u16		SD_C_SIZE;
+	u8		SD_C_SIZE_MULT;
+
+	/* SD/MMC New spec. */
+	u8		SD_SPEC_VER;
+	u8		SD_CSD_VER;
+	u8		SD20_HIGH_CAPACITY;
+	u32		HC_C_SIZE;
+	u8		MMC_SPEC_VER;
+	u8		MMC_BusWidth;
+	u8		MMC_HIGH_CAPACITY;
+
+	/*----- MS Control Data ---------------- */
+	bool		MS_SWWP;
+	u32		MSP_TotalBlock;
+	struct ms_lib_ctrl MS_Lib;
+	bool		MS_IsRWPage;
+	u16		MS_Model;
+
+	/*----- SM Control Data ---------------- */
+	u8		SM_DeviceID;
+	u8		SM_CardID;
+
+	unsigned char	*testbuf;
+	u8		BIN_FLAG;
+	u32		bl_num;
+	int		SrbStatus;
+
+	/*------Power Managerment ---------------*/
+	bool		Power_IsResum;
+};
+
+static int ene_sd_init(struct us_data *us);
+static int ene_ms_init(struct us_data *us);
+static int ene_load_bincode(struct us_data *us, unsigned char flag);
+
+static void ene_ub6250_info_destructor(void *extra)
+{
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) extra;
+
+	if (!extra)
+		return;
+	kfree(info->bbuf);
+}
+
+static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg)
+{
+	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+	struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
+
+	int result;
+	unsigned int residue;
+	unsigned int cswlen = 0, partial = 0;
+	unsigned int transfer_length = bcb->DataTransferLength;
+
+	/* usb_stor_dbg(us, "transport --- ene_send_scsi_cmd\n"); */
+	/* send cmd to out endpoint */
+	result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+					    bcb, US_BULK_CB_WRAP_LEN, NULL);
+	if (result != USB_STOR_XFER_GOOD) {
+		usb_stor_dbg(us, "send cmd to out endpoint fail ---\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	if (buf) {
+		unsigned int pipe = fDir;
+
+		if (fDir  == FDIR_READ)
+			pipe = us->recv_bulk_pipe;
+		else
+			pipe = us->send_bulk_pipe;
+
+		/* Bulk */
+		if (use_sg) {
+			result = usb_stor_bulk_srb(us, pipe, us->srb);
+		} else {
+			result = usb_stor_bulk_transfer_sg(us, pipe, buf,
+						transfer_length, 0, &partial);
+		}
+		if (result != USB_STOR_XFER_GOOD) {
+			usb_stor_dbg(us, "data transfer fail ---\n");
+			return USB_STOR_TRANSPORT_ERROR;
+		}
+	}
+
+	/* Get CSW for device status */
+	result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs,
+					    US_BULK_CS_WRAP_LEN, &cswlen);
+
+	if (result == USB_STOR_XFER_SHORT && cswlen == 0) {
+		usb_stor_dbg(us, "Received 0-length CSW; retrying...\n");
+		result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+					    bcs, US_BULK_CS_WRAP_LEN, &cswlen);
+	}
+
+	if (result == USB_STOR_XFER_STALLED) {
+		/* get the status again */
+		usb_stor_dbg(us, "Attempting to get CSW (2nd try)...\n");
+		result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+						bcs, US_BULK_CS_WRAP_LEN, NULL);
+	}
+
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	/* check bulk status */
+	residue = le32_to_cpu(bcs->Residue);
+
+	/*
+	 * try to compute the actual residue, based on how much data
+	 * was really transferred and what the device tells us
+	 */
+	if (residue && !(us->fflags & US_FL_IGNORE_RESIDUE)) {
+		residue = min(residue, transfer_length);
+		if (us->srb != NULL)
+			scsi_set_resid(us->srb, max(scsi_get_resid(us->srb),
+								(int)residue));
+	}
+
+	if (bcs->Status != US_BULK_STAT_OK)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int do_scsi_request_sense(struct us_data *us, struct scsi_cmnd *srb)
+{
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+	unsigned char buf[18];
+
+	memset(buf, 0, 18);
+	buf[0] = 0x70;				/* Current error */
+	buf[2] = info->SrbStatus >> 16;		/* Sense key */
+	buf[7] = 10;				/* Additional length */
+	buf[12] = info->SrbStatus >> 8;		/* ASC */
+	buf[13] = info->SrbStatus;		/* ASCQ */
+
+	usb_stor_set_xfer_buf(buf, sizeof(buf), srb);
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int do_scsi_inquiry(struct us_data *us, struct scsi_cmnd *srb)
+{
+	unsigned char data_ptr[36] = {
+		0x00, 0x00, 0x02, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x55,
+		0x53, 0x42, 0x32, 0x2E, 0x30, 0x20, 0x20, 0x43, 0x61,
+		0x72, 0x64, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x20,
+		0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x31, 0x30, 0x30 };
+
+	usb_stor_set_xfer_buf(data_ptr, 36, srb);
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int sd_scsi_test_unit_ready(struct us_data *us, struct scsi_cmnd *srb)
+{
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+	if (info->SD_Status.Insert && info->SD_Status.Ready)
+		return USB_STOR_TRANSPORT_GOOD;
+	else {
+		ene_sd_init(us);
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int sd_scsi_mode_sense(struct us_data *us, struct scsi_cmnd *srb)
+{
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+	unsigned char mediaNoWP[12] = {
+		0x0b, 0x00, 0x00, 0x08, 0x00, 0x00,
+		0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 };
+	unsigned char mediaWP[12]   = {
+		0x0b, 0x00, 0x80, 0x08, 0x00, 0x00,
+		0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 };
+
+	if (info->SD_Status.WtP)
+		usb_stor_set_xfer_buf(mediaWP, 12, srb);
+	else
+		usb_stor_set_xfer_buf(mediaNoWP, 12, srb);
+
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int sd_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb)
+{
+	u32	bl_num;
+	u32	bl_len;
+	unsigned int offset = 0;
+	unsigned char    buf[8];
+	struct scatterlist *sg = NULL;
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+	usb_stor_dbg(us, "sd_scsi_read_capacity\n");
+	if (info->SD_Status.HiCapacity) {
+		bl_len = 0x200;
+		if (info->SD_Status.IsMMC)
+			bl_num = info->HC_C_SIZE-1;
+		else
+			bl_num = (info->HC_C_SIZE + 1) * 1024 - 1;
+	} else {
+		bl_len = 1 << (info->SD_READ_BL_LEN);
+		bl_num = info->SD_Block_Mult * (info->SD_C_SIZE + 1)
+				* (1 << (info->SD_C_SIZE_MULT + 2)) - 1;
+	}
+	info->bl_num = bl_num;
+	usb_stor_dbg(us, "bl_len = %x\n", bl_len);
+	usb_stor_dbg(us, "bl_num = %x\n", bl_num);
+
+	/*srb->request_bufflen = 8; */
+	buf[0] = (bl_num >> 24) & 0xff;
+	buf[1] = (bl_num >> 16) & 0xff;
+	buf[2] = (bl_num >> 8) & 0xff;
+	buf[3] = (bl_num >> 0) & 0xff;
+	buf[4] = (bl_len >> 24) & 0xff;
+	buf[5] = (bl_len >> 16) & 0xff;
+	buf[6] = (bl_len >> 8) & 0xff;
+	buf[7] = (bl_len >> 0) & 0xff;
+
+	usb_stor_access_xfer_buf(buf, 8, srb, &sg, &offset, TO_XFER_BUF);
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int sd_scsi_read(struct us_data *us, struct scsi_cmnd *srb)
+{
+	int result;
+	unsigned char *cdb = srb->cmnd;
+	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+	u32 bn = ((cdb[2] << 24) & 0xff000000) | ((cdb[3] << 16) & 0x00ff0000) |
+		 ((cdb[4] << 8) & 0x0000ff00) | ((cdb[5] << 0) & 0x000000ff);
+	u16 blen = ((cdb[7] << 8) & 0xff00) | ((cdb[8] << 0) & 0x00ff);
+	u32 bnByte = bn * 0x200;
+	u32 blenByte = blen * 0x200;
+
+	if (bn > info->bl_num)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	result = ene_load_bincode(us, SD_RW_PATTERN);
+	if (result != USB_STOR_XFER_GOOD) {
+		usb_stor_dbg(us, "Load SD RW pattern Fail !!\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	if (info->SD_Status.HiCapacity)
+		bnByte = bn;
+
+	/* set up the command wrapper */
+	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+	bcb->DataTransferLength = blenByte;
+	bcb->Flags  = US_BULK_FLAG_IN;
+	bcb->CDB[0] = 0xF1;
+	bcb->CDB[5] = (unsigned char)(bnByte);
+	bcb->CDB[4] = (unsigned char)(bnByte>>8);
+	bcb->CDB[3] = (unsigned char)(bnByte>>16);
+	bcb->CDB[2] = (unsigned char)(bnByte>>24);
+
+	result = ene_send_scsi_cmd(us, FDIR_READ, scsi_sglist(srb), 1);
+	return result;
+}
+
+static int sd_scsi_write(struct us_data *us, struct scsi_cmnd *srb)
+{
+	int result;
+	unsigned char *cdb = srb->cmnd;
+	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+	u32 bn = ((cdb[2] << 24) & 0xff000000) | ((cdb[3] << 16) & 0x00ff0000) |
+		 ((cdb[4] << 8) & 0x0000ff00) | ((cdb[5] << 0) & 0x000000ff);
+	u16 blen = ((cdb[7] << 8) & 0xff00) | ((cdb[8] << 0) & 0x00ff);
+	u32 bnByte = bn * 0x200;
+	u32 blenByte = blen * 0x200;
+
+	if (bn > info->bl_num)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	result = ene_load_bincode(us, SD_RW_PATTERN);
+	if (result != USB_STOR_XFER_GOOD) {
+		usb_stor_dbg(us, "Load SD RW pattern Fail !!\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	if (info->SD_Status.HiCapacity)
+		bnByte = bn;
+
+	/* set up the command wrapper */
+	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+	bcb->DataTransferLength = blenByte;
+	bcb->Flags  = 0x00;
+	bcb->CDB[0] = 0xF0;
+	bcb->CDB[5] = (unsigned char)(bnByte);
+	bcb->CDB[4] = (unsigned char)(bnByte>>8);
+	bcb->CDB[3] = (unsigned char)(bnByte>>16);
+	bcb->CDB[2] = (unsigned char)(bnByte>>24);
+
+	result = ene_send_scsi_cmd(us, FDIR_WRITE, scsi_sglist(srb), 1);
+	return result;
+}
+
+/*
+ * ENE MS Card
+ */
+
+static int ms_lib_set_logicalpair(struct us_data *us, u16 logblk, u16 phyblk)
+{
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+	if ((logblk >= info->MS_Lib.NumberOfLogBlock) || (phyblk >= info->MS_Lib.NumberOfPhyBlock))
+		return (u32)-1;
+
+	info->MS_Lib.Phy2LogMap[phyblk] = logblk;
+	info->MS_Lib.Log2PhyMap[logblk] = phyblk;
+
+	return 0;
+}
+
+static int ms_lib_set_logicalblockmark(struct us_data *us, u16 phyblk, u16 mark)
+{
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+	if (phyblk >= info->MS_Lib.NumberOfPhyBlock)
+		return (u32)-1;
+
+	info->MS_Lib.Phy2LogMap[phyblk] = mark;
+
+	return 0;
+}
+
+static int ms_lib_set_initialerrorblock(struct us_data *us, u16 phyblk)
+{
+	return ms_lib_set_logicalblockmark(us, phyblk, MS_LB_INITIAL_ERROR);
+}
+
+static int ms_lib_set_bootblockmark(struct us_data *us, u16 phyblk)
+{
+	return ms_lib_set_logicalblockmark(us, phyblk, MS_LB_BOOT_BLOCK);
+}
+
+static int ms_lib_free_logicalmap(struct us_data *us)
+{
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+	kfree(info->MS_Lib.Phy2LogMap);
+	info->MS_Lib.Phy2LogMap = NULL;
+
+	kfree(info->MS_Lib.Log2PhyMap);
+	info->MS_Lib.Log2PhyMap = NULL;
+
+	return 0;
+}
+
+static int ms_lib_alloc_logicalmap(struct us_data *us)
+{
+	u32  i;
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+	info->MS_Lib.Phy2LogMap = kmalloc_array(info->MS_Lib.NumberOfPhyBlock,
+						sizeof(u16),
+						GFP_KERNEL);
+	info->MS_Lib.Log2PhyMap = kmalloc_array(info->MS_Lib.NumberOfLogBlock,
+						sizeof(u16),
+						GFP_KERNEL);
+
+	if ((info->MS_Lib.Phy2LogMap == NULL) || (info->MS_Lib.Log2PhyMap == NULL)) {
+		ms_lib_free_logicalmap(us);
+		return (u32)-1;
+	}
+
+	for (i = 0; i < info->MS_Lib.NumberOfPhyBlock; i++)
+		info->MS_Lib.Phy2LogMap[i] = MS_LB_NOT_USED;
+
+	for (i = 0; i < info->MS_Lib.NumberOfLogBlock; i++)
+		info->MS_Lib.Log2PhyMap[i] = MS_LB_NOT_USED;
+
+	return 0;
+}
+
+static void ms_lib_clear_writebuf(struct us_data *us)
+{
+	int i;
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+	info->MS_Lib.wrtblk = (u16)-1;
+	ms_lib_clear_pagemap(info);
+
+	if (info->MS_Lib.blkpag)
+		memset(info->MS_Lib.blkpag, 0xff, info->MS_Lib.PagesPerBlock * info->MS_Lib.BytesPerSector);
+
+	if (info->MS_Lib.blkext) {
+		for (i = 0; i < info->MS_Lib.PagesPerBlock; i++) {
+			info->MS_Lib.blkext[i].status1 = MS_REG_ST1_DEFAULT;
+			info->MS_Lib.blkext[i].ovrflg = MS_REG_OVR_DEFAULT;
+			info->MS_Lib.blkext[i].mngflg = MS_REG_MNG_DEFAULT;
+			info->MS_Lib.blkext[i].logadr = MS_LB_NOT_USED;
+		}
+	}
+}
+
+static int ms_count_freeblock(struct us_data *us, u16 PhyBlock)
+{
+	u32 Ende, Count;
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+	Ende = PhyBlock + MS_PHYSICAL_BLOCKS_PER_SEGMENT;
+	for (Count = 0; PhyBlock < Ende; PhyBlock++) {
+		switch (info->MS_Lib.Phy2LogMap[PhyBlock]) {
+		case MS_LB_NOT_USED:
+		case MS_LB_NOT_USED_ERASED:
+			Count++;
+		default:
+			break;
+		}
+	}
+
+	return Count;
+}
+
+static int ms_read_readpage(struct us_data *us, u32 PhyBlockAddr,
+		u8 PageNum, u32 *PageBuf, struct ms_lib_type_extdat *ExtraDat)
+{
+	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+	u8 *bbuf = info->bbuf;
+	int result;
+	u32 bn = PhyBlockAddr * 0x20 + PageNum;
+
+	result = ene_load_bincode(us, MS_RW_PATTERN);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	/* Read Page Data */
+	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+	bcb->DataTransferLength = 0x200;
+	bcb->Flags      = US_BULK_FLAG_IN;
+	bcb->CDB[0]     = 0xF1;
+
+	bcb->CDB[1]     = 0x02; /* in init.c ENE_MSInit() is 0x01 */
+
+	bcb->CDB[5]     = (unsigned char)(bn);
+	bcb->CDB[4]     = (unsigned char)(bn>>8);
+	bcb->CDB[3]     = (unsigned char)(bn>>16);
+	bcb->CDB[2]     = (unsigned char)(bn>>24);
+
+	result = ene_send_scsi_cmd(us, FDIR_READ, PageBuf, 0);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+
+	/* Read Extra Data */
+	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+	bcb->DataTransferLength = 0x4;
+	bcb->Flags      = US_BULK_FLAG_IN;
+	bcb->CDB[0]     = 0xF1;
+	bcb->CDB[1]     = 0x03;
+
+	bcb->CDB[5]     = (unsigned char)(PageNum);
+	bcb->CDB[4]     = (unsigned char)(PhyBlockAddr);
+	bcb->CDB[3]     = (unsigned char)(PhyBlockAddr>>8);
+	bcb->CDB[2]     = (unsigned char)(PhyBlockAddr>>16);
+	bcb->CDB[6]     = 0x01;
+
+	result = ene_send_scsi_cmd(us, FDIR_READ, bbuf, 0);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	ExtraDat->reserved = 0;
+	ExtraDat->intr     = 0x80;  /* Not yet,fireware support */
+	ExtraDat->status0  = 0x10;  /* Not yet,fireware support */
+
+	ExtraDat->status1  = 0x00;  /* Not yet,fireware support */
+	ExtraDat->ovrflg   = bbuf[0];
+	ExtraDat->mngflg   = bbuf[1];
+	ExtraDat->logadr   = memstick_logaddr(bbuf[2], bbuf[3]);
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int ms_lib_process_bootblock(struct us_data *us, u16 PhyBlock, u8 *PageData)
+{
+	struct ms_bootblock_sysent *SysEntry;
+	struct ms_bootblock_sysinf *SysInfo;
+	u32 i, result;
+	u8 PageNumber;
+	u8 *PageBuffer;
+	struct ms_lib_type_extdat ExtraData;
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+	PageBuffer = kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL);
+	if (PageBuffer == NULL)
+		return (u32)-1;
+
+	result = (u32)-1;
+
+	SysInfo = &(((struct ms_bootblock_page0 *)PageData)->sysinf);
+
+	if ((SysInfo->bMsClass != MS_SYSINF_MSCLASS_TYPE_1) ||
+		(be16_to_cpu(SysInfo->wPageSize) != MS_SYSINF_PAGE_SIZE) ||
+		((SysInfo->bSecuritySupport & MS_SYSINF_SECURITY) == MS_SYSINF_SECURITY_SUPPORT) ||
+		(SysInfo->bReserved1 != MS_SYSINF_RESERVED1) ||
+		(SysInfo->bReserved2 != MS_SYSINF_RESERVED2) ||
+		(SysInfo->bFormatType != MS_SYSINF_FORMAT_FAT) ||
+		(SysInfo->bUsage != MS_SYSINF_USAGE_GENERAL))
+		goto exit;
+		/* */
+	switch (info->MS_Lib.cardType = SysInfo->bCardType) {
+	case MS_SYSINF_CARDTYPE_RDONLY:
+		ms_lib_ctrl_set(info, MS_LIB_CTRL_RDONLY);
+		break;
+	case MS_SYSINF_CARDTYPE_RDWR:
+		ms_lib_ctrl_reset(info, MS_LIB_CTRL_RDONLY);
+		break;
+	case MS_SYSINF_CARDTYPE_HYBRID:
+	default:
+		goto exit;
+	}
+
+	info->MS_Lib.blockSize = be16_to_cpu(SysInfo->wBlockSize);
+	info->MS_Lib.NumberOfPhyBlock = be16_to_cpu(SysInfo->wBlockNumber);
+	info->MS_Lib.NumberOfLogBlock = be16_to_cpu(SysInfo->wTotalBlockNumber)-2;
+	info->MS_Lib.PagesPerBlock = info->MS_Lib.blockSize * SIZE_OF_KIRO / MS_BYTES_PER_PAGE;
+	info->MS_Lib.NumberOfSegment = info->MS_Lib.NumberOfPhyBlock / MS_PHYSICAL_BLOCKS_PER_SEGMENT;
+	info->MS_Model = be16_to_cpu(SysInfo->wMemorySize);
+
+	/*Allocate to all number of logicalblock and physicalblock */
+	if (ms_lib_alloc_logicalmap(us))
+		goto exit;
+
+	/* Mark the book block */
+	ms_lib_set_bootblockmark(us, PhyBlock);
+
+	SysEntry = &(((struct ms_bootblock_page0 *)PageData)->sysent);
+
+	for (i = 0; i < MS_NUMBER_OF_SYSTEM_ENTRY; i++) {
+		u32  EntryOffset, EntrySize;
+
+		EntryOffset = be32_to_cpu(SysEntry->entry[i].dwStart);
+
+		if (EntryOffset == 0xffffff)
+			continue;
+		EntrySize = be32_to_cpu(SysEntry->entry[i].dwSize);
+
+		if (EntrySize == 0)
+			continue;
+
+		if (EntryOffset + MS_BYTES_PER_PAGE + EntrySize > info->MS_Lib.blockSize * (u32)SIZE_OF_KIRO)
+			continue;
+
+		if (i == 0) {
+			u8 PrevPageNumber = 0;
+			u16 phyblk;
+
+			if (SysEntry->entry[i].bType != MS_SYSENT_TYPE_INVALID_BLOCK)
+				goto exit;
+
+			while (EntrySize > 0) {
+
+				PageNumber = (u8)(EntryOffset / MS_BYTES_PER_PAGE + 1);
+				if (PageNumber != PrevPageNumber) {
+					switch (ms_read_readpage(us, PhyBlock, PageNumber, (u32 *)PageBuffer, &ExtraData)) {
+					case MS_STATUS_SUCCESS:
+						break;
+					case MS_STATUS_WRITE_PROTECT:
+					case MS_ERROR_FLASH_READ:
+					case MS_STATUS_ERROR:
+					default:
+						goto exit;
+					}
+
+					PrevPageNumber = PageNumber;
+				}
+
+				phyblk = be16_to_cpu(*(u16 *)(PageBuffer + (EntryOffset % MS_BYTES_PER_PAGE)));
+				if (phyblk < 0x0fff)
+					ms_lib_set_initialerrorblock(us, phyblk);
+
+				EntryOffset += 2;
+				EntrySize -= 2;
+			}
+		} else if (i == 1) {  /* CIS/IDI */
+			struct ms_bootblock_idi *idi;
+
+			if (SysEntry->entry[i].bType != MS_SYSENT_TYPE_CIS_IDI)
+				goto exit;
+
+			switch (ms_read_readpage(us, PhyBlock, (u8)(EntryOffset / MS_BYTES_PER_PAGE + 1), (u32 *)PageBuffer, &ExtraData)) {
+			case MS_STATUS_SUCCESS:
+				break;
+			case MS_STATUS_WRITE_PROTECT:
+			case MS_ERROR_FLASH_READ:
+			case MS_STATUS_ERROR:
+			default:
+				goto exit;
+			}
+
+			idi = &((struct ms_bootblock_cis_idi *)(PageBuffer + (EntryOffset % MS_BYTES_PER_PAGE)))->idi.idi;
+			if (le16_to_cpu(idi->wIDIgeneralConfiguration) != MS_IDI_GENERAL_CONF)
+				goto exit;
+
+			info->MS_Lib.BytesPerSector = le16_to_cpu(idi->wIDIbytesPerSector);
+			if (info->MS_Lib.BytesPerSector != MS_BYTES_PER_PAGE)
+				goto exit;
+		}
+	} /* End for .. */
+
+	result = 0;
+
+exit:
+	if (result)
+		ms_lib_free_logicalmap(us);
+
+	kfree(PageBuffer);
+
+	result = 0;
+	return result;
+}
+
+static void ms_lib_free_writebuf(struct us_data *us)
+{
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+	info->MS_Lib.wrtblk = (u16)-1; /* set to -1 */
+
+	/* memset((fdoExt)->MS_Lib.pagemap, 0, sizeof((fdoExt)->MS_Lib.pagemap)) */
+
+	ms_lib_clear_pagemap(info); /* (pdx)->MS_Lib.pagemap memset 0 in ms.h */
+
+	if (info->MS_Lib.blkpag) {
+		kfree(info->MS_Lib.blkpag);  /* Arnold test ... */
+		info->MS_Lib.blkpag = NULL;
+	}
+
+	if (info->MS_Lib.blkext) {
+		kfree(info->MS_Lib.blkext);  /* Arnold test ... */
+		info->MS_Lib.blkext = NULL;
+	}
+}
+
+
+static void ms_lib_free_allocatedarea(struct us_data *us)
+{
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+	ms_lib_free_writebuf(us); /* Free MS_Lib.pagemap */
+	ms_lib_free_logicalmap(us); /* kfree MS_Lib.Phy2LogMap and MS_Lib.Log2PhyMap */
+
+	/* set struct us point flag to 0 */
+	info->MS_Lib.flags = 0;
+	info->MS_Lib.BytesPerSector = 0;
+	info->MS_Lib.SectorsPerCylinder = 0;
+
+	info->MS_Lib.cardType = 0;
+	info->MS_Lib.blockSize = 0;
+	info->MS_Lib.PagesPerBlock = 0;
+
+	info->MS_Lib.NumberOfPhyBlock = 0;
+	info->MS_Lib.NumberOfLogBlock = 0;
+}
+
+
+static int ms_lib_alloc_writebuf(struct us_data *us)
+{
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+	info->MS_Lib.wrtblk = (u16)-1;
+
+	info->MS_Lib.blkpag = kmalloc_array(info->MS_Lib.PagesPerBlock,
+					    info->MS_Lib.BytesPerSector,
+					    GFP_KERNEL);
+	info->MS_Lib.blkext = kmalloc_array(info->MS_Lib.PagesPerBlock,
+					    sizeof(struct ms_lib_type_extdat),
+					    GFP_KERNEL);
+
+	if ((info->MS_Lib.blkpag == NULL) || (info->MS_Lib.blkext == NULL)) {
+		ms_lib_free_writebuf(us);
+		return (u32)-1;
+	}
+
+	ms_lib_clear_writebuf(us);
+
+return 0;
+}
+
+static int ms_lib_force_setlogical_pair(struct us_data *us, u16 logblk, u16 phyblk)
+{
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+	if (logblk == MS_LB_NOT_USED)
+		return 0;
+
+	if ((logblk >= info->MS_Lib.NumberOfLogBlock) ||
+		(phyblk >= info->MS_Lib.NumberOfPhyBlock))
+		return (u32)-1;
+
+	info->MS_Lib.Phy2LogMap[phyblk] = logblk;
+	info->MS_Lib.Log2PhyMap[logblk] = phyblk;
+
+	return 0;
+}
+
+static int ms_read_copyblock(struct us_data *us, u16 oldphy, u16 newphy,
+			u16 PhyBlockAddr, u8 PageNum, unsigned char *buf, u16 len)
+{
+	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+	int result;
+
+	result = ene_load_bincode(us, MS_RW_PATTERN);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+	bcb->DataTransferLength = 0x200*len;
+	bcb->Flags = 0x00;
+	bcb->CDB[0] = 0xF0;
+	bcb->CDB[1] = 0x08;
+	bcb->CDB[4] = (unsigned char)(oldphy);
+	bcb->CDB[3] = (unsigned char)(oldphy>>8);
+	bcb->CDB[2] = 0; /* (BYTE)(oldphy>>16) */
+	bcb->CDB[7] = (unsigned char)(newphy);
+	bcb->CDB[6] = (unsigned char)(newphy>>8);
+	bcb->CDB[5] = 0; /* (BYTE)(newphy>>16) */
+	bcb->CDB[9] = (unsigned char)(PhyBlockAddr);
+	bcb->CDB[8] = (unsigned char)(PhyBlockAddr>>8);
+	bcb->CDB[10] = PageNum;
+
+	result = ene_send_scsi_cmd(us, FDIR_WRITE, buf, 0);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int ms_read_eraseblock(struct us_data *us, u32 PhyBlockAddr)
+{
+	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+	int result;
+	u32 bn = PhyBlockAddr;
+
+	result = ene_load_bincode(us, MS_RW_PATTERN);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+	bcb->DataTransferLength = 0x200;
+	bcb->Flags = US_BULK_FLAG_IN;
+	bcb->CDB[0] = 0xF2;
+	bcb->CDB[1] = 0x06;
+	bcb->CDB[4] = (unsigned char)(bn);
+	bcb->CDB[3] = (unsigned char)(bn>>8);
+	bcb->CDB[2] = (unsigned char)(bn>>16);
+
+	result = ene_send_scsi_cmd(us, FDIR_READ, NULL, 0);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int ms_lib_check_disableblock(struct us_data *us, u16 PhyBlock)
+{
+	unsigned char *PageBuf = NULL;
+	u16 result = MS_STATUS_SUCCESS;
+	u16 blk, index = 0;
+	struct ms_lib_type_extdat extdat;
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+	PageBuf = kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL);
+	if (PageBuf == NULL) {
+		result = MS_NO_MEMORY_ERROR;
+		goto exit;
+	}
+
+	ms_read_readpage(us, PhyBlock, 1, (u32 *)PageBuf, &extdat);
+	do {
+		blk = be16_to_cpu(PageBuf[index]);
+		if (blk == MS_LB_NOT_USED)
+			break;
+		if (blk == info->MS_Lib.Log2PhyMap[0]) {
+			result = MS_ERROR_FLASH_READ;
+			break;
+		}
+		index++;
+	} while (1);
+
+exit:
+	kfree(PageBuf);
+	return result;
+}
+
+static int ms_lib_setacquired_errorblock(struct us_data *us, u16 phyblk)
+{
+	u16 log;
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+	if (phyblk >= info->MS_Lib.NumberOfPhyBlock)
+		return (u32)-1;
+
+	log = info->MS_Lib.Phy2LogMap[phyblk];
+
+	if (log < info->MS_Lib.NumberOfLogBlock)
+		info->MS_Lib.Log2PhyMap[log] = MS_LB_NOT_USED;
+
+	if (info->MS_Lib.Phy2LogMap[phyblk] != MS_LB_INITIAL_ERROR)
+		info->MS_Lib.Phy2LogMap[phyblk] = MS_LB_ACQUIRED_ERROR;
+
+	return 0;
+}
+
+static int ms_lib_overwrite_extra(struct us_data *us, u32 PhyBlockAddr,
+				u8 PageNum, u8 OverwriteFlag)
+{
+	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+	int result;
+
+	result = ene_load_bincode(us, MS_RW_PATTERN);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+	bcb->DataTransferLength = 0x4;
+	bcb->Flags = US_BULK_FLAG_IN;
+	bcb->CDB[0] = 0xF2;
+	bcb->CDB[1] = 0x05;
+	bcb->CDB[5] = (unsigned char)(PageNum);
+	bcb->CDB[4] = (unsigned char)(PhyBlockAddr);
+	bcb->CDB[3] = (unsigned char)(PhyBlockAddr>>8);
+	bcb->CDB[2] = (unsigned char)(PhyBlockAddr>>16);
+	bcb->CDB[6] = OverwriteFlag;
+	bcb->CDB[7] = 0xFF;
+	bcb->CDB[8] = 0xFF;
+	bcb->CDB[9] = 0xFF;
+
+	result = ene_send_scsi_cmd(us, FDIR_READ, NULL, 0);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int ms_lib_error_phyblock(struct us_data *us, u16 phyblk)
+{
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+	if (phyblk >= info->MS_Lib.NumberOfPhyBlock)
+		return MS_STATUS_ERROR;
+
+	ms_lib_setacquired_errorblock(us, phyblk);
+
+	if (ms_lib_iswritable(info))
+		return ms_lib_overwrite_extra(us, phyblk, 0, (u8)(~MS_REG_OVR_BKST & BYTE_MASK));
+
+	return MS_STATUS_SUCCESS;
+}
+
+static int ms_lib_erase_phyblock(struct us_data *us, u16 phyblk)
+{
+	u16 log;
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+	if (phyblk >= info->MS_Lib.NumberOfPhyBlock)
+		return MS_STATUS_ERROR;
+
+	log = info->MS_Lib.Phy2LogMap[phyblk];
+
+	if (log < info->MS_Lib.NumberOfLogBlock)
+		info->MS_Lib.Log2PhyMap[log] = MS_LB_NOT_USED;
+
+	info->MS_Lib.Phy2LogMap[phyblk] = MS_LB_NOT_USED;
+
+	if (ms_lib_iswritable(info)) {
+		switch (ms_read_eraseblock(us, phyblk)) {
+		case MS_STATUS_SUCCESS:
+			info->MS_Lib.Phy2LogMap[phyblk] = MS_LB_NOT_USED_ERASED;
+			return MS_STATUS_SUCCESS;
+		case MS_ERROR_FLASH_ERASE:
+		case MS_STATUS_INT_ERROR:
+			ms_lib_error_phyblock(us, phyblk);
+			return MS_ERROR_FLASH_ERASE;
+		case MS_STATUS_ERROR:
+		default:
+			ms_lib_ctrl_set(info, MS_LIB_CTRL_RDONLY); /* MS_LibCtrlSet will used by ENE_MSInit ,need check, and why us to info*/
+			ms_lib_setacquired_errorblock(us, phyblk);
+			return MS_STATUS_ERROR;
+		}
+	}
+
+	ms_lib_setacquired_errorblock(us, phyblk);
+
+	return MS_STATUS_SUCCESS;
+}
+
+static int ms_lib_read_extra(struct us_data *us, u32 PhyBlock,
+				u8 PageNum, struct ms_lib_type_extdat *ExtraDat)
+{
+	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+	u8 *bbuf = info->bbuf;
+	int result;
+
+	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+	bcb->DataTransferLength = 0x4;
+	bcb->Flags      = US_BULK_FLAG_IN;
+	bcb->CDB[0]     = 0xF1;
+	bcb->CDB[1]     = 0x03;
+	bcb->CDB[5]     = (unsigned char)(PageNum);
+	bcb->CDB[4]     = (unsigned char)(PhyBlock);
+	bcb->CDB[3]     = (unsigned char)(PhyBlock>>8);
+	bcb->CDB[2]     = (unsigned char)(PhyBlock>>16);
+	bcb->CDB[6]     = 0x01;
+
+	result = ene_send_scsi_cmd(us, FDIR_READ, bbuf, 0);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	ExtraDat->reserved = 0;
+	ExtraDat->intr     = 0x80;  /* Not yet, waiting for fireware support */
+	ExtraDat->status0  = 0x10;  /* Not yet, waiting for fireware support */
+	ExtraDat->status1  = 0x00;  /* Not yet, waiting for fireware support */
+	ExtraDat->ovrflg   = bbuf[0];
+	ExtraDat->mngflg   = bbuf[1];
+	ExtraDat->logadr   = memstick_logaddr(bbuf[2], bbuf[3]);
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int ms_libsearch_block_from_physical(struct us_data *us, u16 phyblk)
+{
+	u16 blk;
+	struct ms_lib_type_extdat extdat; /* need check */
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+
+	if (phyblk >= info->MS_Lib.NumberOfPhyBlock)
+		return MS_LB_ERROR;
+
+	for (blk = phyblk + 1; blk != phyblk; blk++) {
+		if ((blk & MS_PHYSICAL_BLOCKS_PER_SEGMENT_MASK) == 0)
+			blk -= MS_PHYSICAL_BLOCKS_PER_SEGMENT;
+
+		if (info->MS_Lib.Phy2LogMap[blk] == MS_LB_NOT_USED_ERASED) {
+			return blk;
+		} else if (info->MS_Lib.Phy2LogMap[blk] == MS_LB_NOT_USED) {
+			switch (ms_lib_read_extra(us, blk, 0, &extdat)) {
+			case MS_STATUS_SUCCESS:
+			case MS_STATUS_SUCCESS_WITH_ECC:
+				break;
+			case MS_NOCARD_ERROR:
+				return MS_NOCARD_ERROR;
+			case MS_STATUS_INT_ERROR:
+				return MS_LB_ERROR;
+			case MS_ERROR_FLASH_READ:
+			default:
+				ms_lib_setacquired_errorblock(us, blk);
+				continue;
+			} /* End switch */
+
+			if ((extdat.ovrflg & MS_REG_OVR_BKST) != MS_REG_OVR_BKST_OK) {
+				ms_lib_setacquired_errorblock(us, blk);
+				continue;
+			}
+
+			switch (ms_lib_erase_phyblock(us, blk)) {
+			case MS_STATUS_SUCCESS:
+				return blk;
+			case MS_STATUS_ERROR:
+				return MS_LB_ERROR;
+			case MS_ERROR_FLASH_ERASE:
+			default:
+				ms_lib_error_phyblock(us, blk);
+				break;
+			}
+		}
+	} /* End for */
+
+	return MS_LB_ERROR;
+}
+static int ms_libsearch_block_from_logical(struct us_data *us, u16 logblk)
+{
+	u16 phyblk;
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+	phyblk = ms_libconv_to_physical(info, logblk);
+	if (phyblk >= MS_LB_ERROR) {
+		if (logblk >= info->MS_Lib.NumberOfLogBlock)
+			return MS_LB_ERROR;
+
+		phyblk = (logblk + MS_NUMBER_OF_BOOT_BLOCK) / MS_LOGICAL_BLOCKS_PER_SEGMENT;
+		phyblk *= MS_PHYSICAL_BLOCKS_PER_SEGMENT;
+		phyblk += MS_PHYSICAL_BLOCKS_PER_SEGMENT - 1;
+	}
+
+	return ms_libsearch_block_from_physical(us, phyblk);
+}
+
+static int ms_scsi_test_unit_ready(struct us_data *us, struct scsi_cmnd *srb)
+{
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
+
+	/* pr_info("MS_SCSI_Test_Unit_Ready\n"); */
+	if (info->MS_Status.Insert && info->MS_Status.Ready) {
+		return USB_STOR_TRANSPORT_GOOD;
+	} else {
+		ene_ms_init(us);
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int ms_scsi_mode_sense(struct us_data *us, struct scsi_cmnd *srb)
+{
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+	unsigned char mediaNoWP[12] = {
+		0x0b, 0x00, 0x00, 0x08, 0x00, 0x00,
+		0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 };
+	unsigned char mediaWP[12]   = {
+		0x0b, 0x00, 0x80, 0x08, 0x00, 0x00,
+		0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 };
+
+	if (info->MS_Status.WtP)
+		usb_stor_set_xfer_buf(mediaWP, 12, srb);
+	else
+		usb_stor_set_xfer_buf(mediaNoWP, 12, srb);
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int ms_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb)
+{
+	u32   bl_num;
+	u16    bl_len;
+	unsigned int offset = 0;
+	unsigned char    buf[8];
+	struct scatterlist *sg = NULL;
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+	usb_stor_dbg(us, "ms_scsi_read_capacity\n");
+	bl_len = 0x200;
+	if (info->MS_Status.IsMSPro)
+		bl_num = info->MSP_TotalBlock - 1;
+	else
+		bl_num = info->MS_Lib.NumberOfLogBlock * info->MS_Lib.blockSize * 2 - 1;
+
+	info->bl_num = bl_num;
+	usb_stor_dbg(us, "bl_len = %x\n", bl_len);
+	usb_stor_dbg(us, "bl_num = %x\n", bl_num);
+
+	/*srb->request_bufflen = 8; */
+	buf[0] = (bl_num >> 24) & 0xff;
+	buf[1] = (bl_num >> 16) & 0xff;
+	buf[2] = (bl_num >> 8) & 0xff;
+	buf[3] = (bl_num >> 0) & 0xff;
+	buf[4] = (bl_len >> 24) & 0xff;
+	buf[5] = (bl_len >> 16) & 0xff;
+	buf[6] = (bl_len >> 8) & 0xff;
+	buf[7] = (bl_len >> 0) & 0xff;
+
+	usb_stor_access_xfer_buf(buf, 8, srb, &sg, &offset, TO_XFER_BUF);
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static void ms_lib_phy_to_log_range(u16 PhyBlock, u16 *LogStart, u16 *LogEnde)
+{
+	PhyBlock /= MS_PHYSICAL_BLOCKS_PER_SEGMENT;
+
+	if (PhyBlock) {
+		*LogStart = MS_LOGICAL_BLOCKS_IN_1ST_SEGMENT + (PhyBlock - 1) * MS_LOGICAL_BLOCKS_PER_SEGMENT;/*496*/
+		*LogEnde = *LogStart + MS_LOGICAL_BLOCKS_PER_SEGMENT;/*496*/
+	} else {
+		*LogStart = 0;
+		*LogEnde = MS_LOGICAL_BLOCKS_IN_1ST_SEGMENT;/*494*/
+	}
+}
+
+static int ms_lib_read_extrablock(struct us_data *us, u32 PhyBlock,
+	u8 PageNum, u8 blen, void *buf)
+{
+	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+	int     result;
+
+	/* Read Extra Data */
+	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+	bcb->DataTransferLength = 0x4 * blen;
+	bcb->Flags      = US_BULK_FLAG_IN;
+	bcb->CDB[0]     = 0xF1;
+	bcb->CDB[1]     = 0x03;
+	bcb->CDB[5]     = (unsigned char)(PageNum);
+	bcb->CDB[4]     = (unsigned char)(PhyBlock);
+	bcb->CDB[3]     = (unsigned char)(PhyBlock>>8);
+	bcb->CDB[2]     = (unsigned char)(PhyBlock>>16);
+	bcb->CDB[6]     = blen;
+
+	result = ene_send_scsi_cmd(us, FDIR_READ, buf, 0);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int ms_lib_scan_logicalblocknumber(struct us_data *us, u16 btBlk1st)
+{
+	u16 PhyBlock, newblk, i;
+	u16 LogStart, LogEnde;
+	struct ms_lib_type_extdat extdat;
+	u32 count = 0, index = 0;
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+	u8 *bbuf = info->bbuf;
+
+	for (PhyBlock = 0; PhyBlock < info->MS_Lib.NumberOfPhyBlock;) {
+		ms_lib_phy_to_log_range(PhyBlock, &LogStart, &LogEnde);
+
+		for (i = 0; i < MS_PHYSICAL_BLOCKS_PER_SEGMENT; i++, PhyBlock++) {
+			switch (ms_libconv_to_logical(info, PhyBlock)) {
+			case MS_STATUS_ERROR:
+				continue;
+			default:
+				break;
+			}
+
+			if (count == PhyBlock) {
+				ms_lib_read_extrablock(us, PhyBlock, 0, 0x80,
+						bbuf);
+				count += 0x80;
+			}
+			index = (PhyBlock % 0x80) * 4;
+
+			extdat.ovrflg = bbuf[index];
+			extdat.mngflg = bbuf[index+1];
+			extdat.logadr = memstick_logaddr(bbuf[index+2],
+					bbuf[index+3]);
+
+			if ((extdat.ovrflg & MS_REG_OVR_BKST) != MS_REG_OVR_BKST_OK) {
+				ms_lib_setacquired_errorblock(us, PhyBlock);
+				continue;
+			}
+
+			if ((extdat.mngflg & MS_REG_MNG_ATFLG) == MS_REG_MNG_ATFLG_ATTBL) {
+				ms_lib_erase_phyblock(us, PhyBlock);
+				continue;
+			}
+
+			if (extdat.logadr != MS_LB_NOT_USED) {
+				if ((extdat.logadr < LogStart) || (LogEnde <= extdat.logadr)) {
+					ms_lib_erase_phyblock(us, PhyBlock);
+					continue;
+				}
+
+				newblk = ms_libconv_to_physical(info, extdat.logadr);
+
+				if (newblk != MS_LB_NOT_USED) {
+					if (extdat.logadr == 0) {
+						ms_lib_set_logicalpair(us, extdat.logadr, PhyBlock);
+						if (ms_lib_check_disableblock(us, btBlk1st)) {
+							ms_lib_set_logicalpair(us, extdat.logadr, newblk);
+							continue;
+						}
+					}
+
+					ms_lib_read_extra(us, newblk, 0, &extdat);
+					if ((extdat.ovrflg & MS_REG_OVR_UDST) == MS_REG_OVR_UDST_UPDATING) {
+						ms_lib_erase_phyblock(us, PhyBlock);
+						continue;
+					} else {
+						ms_lib_erase_phyblock(us, newblk);
+					}
+				}
+
+				ms_lib_set_logicalpair(us, extdat.logadr, PhyBlock);
+			}
+		}
+	} /* End for ... */
+
+	return MS_STATUS_SUCCESS;
+}
+
+
+static int ms_scsi_read(struct us_data *us, struct scsi_cmnd *srb)
+{
+	int result;
+	unsigned char *cdb = srb->cmnd;
+	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+	u32 bn = ((cdb[2] << 24) & 0xff000000) | ((cdb[3] << 16) & 0x00ff0000) |
+		((cdb[4] << 8) & 0x0000ff00) | ((cdb[5] << 0) & 0x000000ff);
+	u16 blen = ((cdb[7] << 8) & 0xff00) | ((cdb[8] << 0) & 0x00ff);
+	u32 blenByte = blen * 0x200;
+
+	if (bn > info->bl_num)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	if (info->MS_Status.IsMSPro) {
+		result = ene_load_bincode(us, MSP_RW_PATTERN);
+		if (result != USB_STOR_XFER_GOOD) {
+			usb_stor_dbg(us, "Load MPS RW pattern Fail !!\n");
+			return USB_STOR_TRANSPORT_ERROR;
+		}
+
+		/* set up the command wrapper */
+		memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+		bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+		bcb->DataTransferLength = blenByte;
+		bcb->Flags  = US_BULK_FLAG_IN;
+		bcb->CDB[0] = 0xF1;
+		bcb->CDB[1] = 0x02;
+		bcb->CDB[5] = (unsigned char)(bn);
+		bcb->CDB[4] = (unsigned char)(bn>>8);
+		bcb->CDB[3] = (unsigned char)(bn>>16);
+		bcb->CDB[2] = (unsigned char)(bn>>24);
+
+		result = ene_send_scsi_cmd(us, FDIR_READ, scsi_sglist(srb), 1);
+	} else {
+		void *buf;
+		int offset = 0;
+		u16 phyblk, logblk;
+		u8 PageNum;
+		u16 len;
+		u32 blkno;
+
+		buf = kmalloc(blenByte, GFP_KERNEL);
+		if (buf == NULL)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		result = ene_load_bincode(us, MS_RW_PATTERN);
+		if (result != USB_STOR_XFER_GOOD) {
+			pr_info("Load MS RW pattern Fail !!\n");
+			result = USB_STOR_TRANSPORT_ERROR;
+			goto exit;
+		}
+
+		logblk  = (u16)(bn / info->MS_Lib.PagesPerBlock);
+		PageNum = (u8)(bn % info->MS_Lib.PagesPerBlock);
+
+		while (1) {
+			if (blen > (info->MS_Lib.PagesPerBlock-PageNum))
+				len = info->MS_Lib.PagesPerBlock-PageNum;
+			else
+				len = blen;
+
+			phyblk = ms_libconv_to_physical(info, logblk);
+			blkno  = phyblk * 0x20 + PageNum;
+
+			/* set up the command wrapper */
+			memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+			bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+			bcb->DataTransferLength = 0x200 * len;
+			bcb->Flags  = US_BULK_FLAG_IN;
+			bcb->CDB[0] = 0xF1;
+			bcb->CDB[1] = 0x02;
+			bcb->CDB[5] = (unsigned char)(blkno);
+			bcb->CDB[4] = (unsigned char)(blkno>>8);
+			bcb->CDB[3] = (unsigned char)(blkno>>16);
+			bcb->CDB[2] = (unsigned char)(blkno>>24);
+
+			result = ene_send_scsi_cmd(us, FDIR_READ, buf+offset, 0);
+			if (result != USB_STOR_XFER_GOOD) {
+				pr_info("MS_SCSI_Read --- result = %x\n", result);
+				result = USB_STOR_TRANSPORT_ERROR;
+				goto exit;
+			}
+
+			blen -= len;
+			if (blen <= 0)
+				break;
+			logblk++;
+			PageNum = 0;
+			offset += MS_BYTES_PER_PAGE*len;
+		}
+		usb_stor_set_xfer_buf(buf, blenByte, srb);
+exit:
+		kfree(buf);
+	}
+	return result;
+}
+
+static int ms_scsi_write(struct us_data *us, struct scsi_cmnd *srb)
+{
+	int result;
+	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+	unsigned char *cdb = srb->cmnd;
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+	u32 bn = ((cdb[2] << 24) & 0xff000000) |
+			((cdb[3] << 16) & 0x00ff0000) |
+			((cdb[4] << 8) & 0x0000ff00) |
+			((cdb[5] << 0) & 0x000000ff);
+	u16 blen = ((cdb[7] << 8) & 0xff00) | ((cdb[8] << 0) & 0x00ff);
+	u32 blenByte = blen * 0x200;
+
+	if (bn > info->bl_num)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	if (info->MS_Status.IsMSPro) {
+		result = ene_load_bincode(us, MSP_RW_PATTERN);
+		if (result != USB_STOR_XFER_GOOD) {
+			pr_info("Load MSP RW pattern Fail !!\n");
+			return USB_STOR_TRANSPORT_ERROR;
+		}
+
+		/* set up the command wrapper */
+		memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+		bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+		bcb->DataTransferLength = blenByte;
+		bcb->Flags  = 0x00;
+		bcb->CDB[0] = 0xF0;
+		bcb->CDB[1] = 0x04;
+		bcb->CDB[5] = (unsigned char)(bn);
+		bcb->CDB[4] = (unsigned char)(bn>>8);
+		bcb->CDB[3] = (unsigned char)(bn>>16);
+		bcb->CDB[2] = (unsigned char)(bn>>24);
+
+		result = ene_send_scsi_cmd(us, FDIR_WRITE, scsi_sglist(srb), 1);
+	} else {
+		void *buf;
+		int offset = 0;
+		u16 PhyBlockAddr;
+		u8 PageNum;
+		u16 len, oldphy, newphy;
+
+		buf = kmalloc(blenByte, GFP_KERNEL);
+		if (buf == NULL)
+			return USB_STOR_TRANSPORT_ERROR;
+		usb_stor_set_xfer_buf(buf, blenByte, srb);
+
+		result = ene_load_bincode(us, MS_RW_PATTERN);
+		if (result != USB_STOR_XFER_GOOD) {
+			pr_info("Load MS RW pattern Fail !!\n");
+			result = USB_STOR_TRANSPORT_ERROR;
+			goto exit;
+		}
+
+		PhyBlockAddr = (u16)(bn / info->MS_Lib.PagesPerBlock);
+		PageNum      = (u8)(bn % info->MS_Lib.PagesPerBlock);
+
+		while (1) {
+			if (blen > (info->MS_Lib.PagesPerBlock-PageNum))
+				len = info->MS_Lib.PagesPerBlock-PageNum;
+			else
+				len = blen;
+
+			oldphy = ms_libconv_to_physical(info, PhyBlockAddr); /* need check us <-> info */
+			newphy = ms_libsearch_block_from_logical(us, PhyBlockAddr);
+
+			result = ms_read_copyblock(us, oldphy, newphy, PhyBlockAddr, PageNum, buf+offset, len);
+
+			if (result != USB_STOR_XFER_GOOD) {
+				pr_info("MS_SCSI_Write --- result = %x\n", result);
+				result =  USB_STOR_TRANSPORT_ERROR;
+				goto exit;
+			}
+
+			info->MS_Lib.Phy2LogMap[oldphy] = MS_LB_NOT_USED_ERASED;
+			ms_lib_force_setlogical_pair(us, PhyBlockAddr, newphy);
+
+			blen -= len;
+			if (blen <= 0)
+				break;
+			PhyBlockAddr++;
+			PageNum = 0;
+			offset += MS_BYTES_PER_PAGE*len;
+		}
+exit:
+		kfree(buf);
+	}
+	return result;
+}
+
+/*
+ * ENE MS Card
+ */
+
+static int ene_get_card_type(struct us_data *us, u16 index, void *buf)
+{
+	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+	int result;
+
+	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+	bcb->DataTransferLength	= 0x01;
+	bcb->Flags			= US_BULK_FLAG_IN;
+	bcb->CDB[0]			= 0xED;
+	bcb->CDB[2]			= (unsigned char)(index>>8);
+	bcb->CDB[3]			= (unsigned char)index;
+
+	result = ene_send_scsi_cmd(us, FDIR_READ, buf, 0);
+	return result;
+}
+
+static int ene_get_card_status(struct us_data *us, u8 *buf)
+{
+	u16 tmpreg;
+	u32 reg4b;
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+	/*usb_stor_dbg(us, "transport --- ENE_ReadSDReg\n");*/
+	reg4b = *(u32 *)&buf[0x18];
+	info->SD_READ_BL_LEN = (u8)((reg4b >> 8) & 0x0f);
+
+	tmpreg = (u16) reg4b;
+	reg4b = *(u32 *)(&buf[0x14]);
+	if (info->SD_Status.HiCapacity && !info->SD_Status.IsMMC)
+		info->HC_C_SIZE = (reg4b >> 8) & 0x3fffff;
+
+	info->SD_C_SIZE = ((tmpreg & 0x03) << 10) | (u16)(reg4b >> 22);
+	info->SD_C_SIZE_MULT = (u8)(reg4b >> 7)  & 0x07;
+	if (info->SD_Status.HiCapacity && info->SD_Status.IsMMC)
+		info->HC_C_SIZE = *(u32 *)(&buf[0x100]);
+
+	if (info->SD_READ_BL_LEN > SD_BLOCK_LEN) {
+		info->SD_Block_Mult = 1 << (info->SD_READ_BL_LEN-SD_BLOCK_LEN);
+		info->SD_READ_BL_LEN = SD_BLOCK_LEN;
+	} else {
+		info->SD_Block_Mult = 1;
+	}
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int ene_load_bincode(struct us_data *us, unsigned char flag)
+{
+	int err;
+	char *fw_name = NULL;
+	unsigned char *buf = NULL;
+	const struct firmware *sd_fw = NULL;
+	int result = USB_STOR_TRANSPORT_ERROR;
+	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+	if (info->BIN_FLAG == flag)
+		return USB_STOR_TRANSPORT_GOOD;
+
+	switch (flag) {
+	/* For SD */
+	case SD_INIT1_PATTERN:
+		usb_stor_dbg(us, "SD_INIT1_PATTERN\n");
+		fw_name = SD_INIT1_FIRMWARE;
+		break;
+	case SD_INIT2_PATTERN:
+		usb_stor_dbg(us, "SD_INIT2_PATTERN\n");
+		fw_name = SD_INIT2_FIRMWARE;
+		break;
+	case SD_RW_PATTERN:
+		usb_stor_dbg(us, "SD_RW_PATTERN\n");
+		fw_name = SD_RW_FIRMWARE;
+		break;
+	/* For MS */
+	case MS_INIT_PATTERN:
+		usb_stor_dbg(us, "MS_INIT_PATTERN\n");
+		fw_name = MS_INIT_FIRMWARE;
+		break;
+	case MSP_RW_PATTERN:
+		usb_stor_dbg(us, "MSP_RW_PATTERN\n");
+		fw_name = MSP_RW_FIRMWARE;
+		break;
+	case MS_RW_PATTERN:
+		usb_stor_dbg(us, "MS_RW_PATTERN\n");
+		fw_name = MS_RW_FIRMWARE;
+		break;
+	default:
+		usb_stor_dbg(us, "----------- Unknown PATTERN ----------\n");
+		goto nofw;
+	}
+
+	err = request_firmware(&sd_fw, fw_name, &us->pusb_dev->dev);
+	if (err) {
+		usb_stor_dbg(us, "load firmware %s failed\n", fw_name);
+		goto nofw;
+	}
+	buf = kmemdup(sd_fw->data, sd_fw->size, GFP_KERNEL);
+	if (buf == NULL)
+		goto nofw;
+
+	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+	bcb->DataTransferLength = sd_fw->size;
+	bcb->Flags = 0x00;
+	bcb->CDB[0] = 0xEF;
+
+	result = ene_send_scsi_cmd(us, FDIR_WRITE, buf, 0);
+	if (us->srb != NULL)
+		scsi_set_resid(us->srb, 0);
+	info->BIN_FLAG = flag;
+	kfree(buf);
+
+nofw:
+	release_firmware(sd_fw);
+	return result;
+}
+
+static int ms_card_init(struct us_data *us)
+{
+	u32 result;
+	u16 TmpBlock;
+	unsigned char *PageBuffer0 = NULL, *PageBuffer1 = NULL;
+	struct ms_lib_type_extdat extdat;
+	u16 btBlk1st, btBlk2nd;
+	u32 btBlk1stErred;
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+	printk(KERN_INFO "MS_CardInit start\n");
+
+	ms_lib_free_allocatedarea(us); /* Clean buffer and set struct us_data flag to 0 */
+
+	/* get two PageBuffer */
+	PageBuffer0 = kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL);
+	PageBuffer1 = kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL);
+	if ((PageBuffer0 == NULL) || (PageBuffer1 == NULL)) {
+		result = MS_NO_MEMORY_ERROR;
+		goto exit;
+	}
+
+	btBlk1st = btBlk2nd = MS_LB_NOT_USED;
+	btBlk1stErred = 0;
+
+	for (TmpBlock = 0; TmpBlock < MS_MAX_INITIAL_ERROR_BLOCKS+2; TmpBlock++) {
+
+		switch (ms_read_readpage(us, TmpBlock, 0, (u32 *)PageBuffer0, &extdat)) {
+		case MS_STATUS_SUCCESS:
+			break;
+		case MS_STATUS_INT_ERROR:
+			break;
+		case MS_STATUS_ERROR:
+		default:
+			continue;
+		}
+
+		if ((extdat.ovrflg & MS_REG_OVR_BKST) == MS_REG_OVR_BKST_NG)
+			continue;
+
+		if (((extdat.mngflg & MS_REG_MNG_SYSFLG) == MS_REG_MNG_SYSFLG_USER) ||
+			(be16_to_cpu(((struct ms_bootblock_page0 *)PageBuffer0)->header.wBlockID) != MS_BOOT_BLOCK_ID) ||
+			(be16_to_cpu(((struct ms_bootblock_page0 *)PageBuffer0)->header.wFormatVersion) != MS_BOOT_BLOCK_FORMAT_VERSION) ||
+			(((struct ms_bootblock_page0 *)PageBuffer0)->header.bNumberOfDataEntry != MS_BOOT_BLOCK_DATA_ENTRIES))
+				continue;
+
+		if (btBlk1st != MS_LB_NOT_USED) {
+			btBlk2nd = TmpBlock;
+			break;
+		}
+
+		btBlk1st = TmpBlock;
+		memcpy(PageBuffer1, PageBuffer0, MS_BYTES_PER_PAGE);
+		if (extdat.status1 & (MS_REG_ST1_DTER | MS_REG_ST1_EXER | MS_REG_ST1_FGER))
+			btBlk1stErred = 1;
+	}
+
+	if (btBlk1st == MS_LB_NOT_USED) {
+		result = MS_STATUS_ERROR;
+		goto exit;
+	}
+
+	/* write protect */
+	if ((extdat.status0 & MS_REG_ST0_WP) == MS_REG_ST0_WP_ON)
+		ms_lib_ctrl_set(info, MS_LIB_CTRL_WRPROTECT);
+
+	result = MS_STATUS_ERROR;
+	/* 1st Boot Block */
+	if (btBlk1stErred == 0)
+		result = ms_lib_process_bootblock(us, btBlk1st, PageBuffer1);
+		/* 1st */
+	/* 2nd Boot Block */
+	if (result && (btBlk2nd != MS_LB_NOT_USED))
+		result = ms_lib_process_bootblock(us, btBlk2nd, PageBuffer0);
+
+	if (result) {
+		result = MS_STATUS_ERROR;
+		goto exit;
+	}
+
+	for (TmpBlock = 0; TmpBlock < btBlk1st; TmpBlock++)
+		info->MS_Lib.Phy2LogMap[TmpBlock] = MS_LB_INITIAL_ERROR;
+
+	info->MS_Lib.Phy2LogMap[btBlk1st] = MS_LB_BOOT_BLOCK;
+
+	if (btBlk2nd != MS_LB_NOT_USED) {
+		for (TmpBlock = btBlk1st + 1; TmpBlock < btBlk2nd; TmpBlock++)
+			info->MS_Lib.Phy2LogMap[TmpBlock] = MS_LB_INITIAL_ERROR;
+
+		info->MS_Lib.Phy2LogMap[btBlk2nd] = MS_LB_BOOT_BLOCK;
+	}
+
+	result = ms_lib_scan_logicalblocknumber(us, btBlk1st);
+	if (result)
+		goto exit;
+
+	for (TmpBlock = MS_PHYSICAL_BLOCKS_PER_SEGMENT;
+		TmpBlock < info->MS_Lib.NumberOfPhyBlock;
+		TmpBlock += MS_PHYSICAL_BLOCKS_PER_SEGMENT) {
+		if (ms_count_freeblock(us, TmpBlock) == 0) {
+			ms_lib_ctrl_set(info, MS_LIB_CTRL_WRPROTECT);
+			break;
+		}
+	}
+
+	/* write */
+	if (ms_lib_alloc_writebuf(us)) {
+		result = MS_NO_MEMORY_ERROR;
+		goto exit;
+	}
+
+	result = MS_STATUS_SUCCESS;
+
+exit:
+	kfree(PageBuffer1);
+	kfree(PageBuffer0);
+
+	printk(KERN_INFO "MS_CardInit end\n");
+	return result;
+}
+
+static int ene_ms_init(struct us_data *us)
+{
+	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+	int result;
+	u16 MSP_BlockSize, MSP_UserAreaBlocks;
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+	u8 *bbuf = info->bbuf;
+
+	printk(KERN_INFO "transport --- ENE_MSInit\n");
+
+	/* the same part to test ENE */
+
+	result = ene_load_bincode(us, MS_INIT_PATTERN);
+	if (result != USB_STOR_XFER_GOOD) {
+		printk(KERN_ERR "Load MS Init Code Fail !!\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+	bcb->DataTransferLength = 0x200;
+	bcb->Flags      = US_BULK_FLAG_IN;
+	bcb->CDB[0]     = 0xF1;
+	bcb->CDB[1]     = 0x01;
+
+	result = ene_send_scsi_cmd(us, FDIR_READ, bbuf, 0);
+	if (result != USB_STOR_XFER_GOOD) {
+		printk(KERN_ERR "Execution MS Init Code Fail !!\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+	/* the same part to test ENE */
+	info->MS_Status = *(struct MS_STATUS *) bbuf;
+
+	if (info->MS_Status.Insert && info->MS_Status.Ready) {
+		printk(KERN_INFO "Insert     = %x\n", info->MS_Status.Insert);
+		printk(KERN_INFO "Ready      = %x\n", info->MS_Status.Ready);
+		printk(KERN_INFO "IsMSPro    = %x\n", info->MS_Status.IsMSPro);
+		printk(KERN_INFO "IsMSPHG    = %x\n", info->MS_Status.IsMSPHG);
+		printk(KERN_INFO "WtP= %x\n", info->MS_Status.WtP);
+		if (info->MS_Status.IsMSPro) {
+			MSP_BlockSize      = (bbuf[6] << 8) | bbuf[7];
+			MSP_UserAreaBlocks = (bbuf[10] << 8) | bbuf[11];
+			info->MSP_TotalBlock = MSP_BlockSize * MSP_UserAreaBlocks;
+		} else {
+			ms_card_init(us); /* Card is MS (to ms.c)*/
+		}
+		usb_stor_dbg(us, "MS Init Code OK !!\n");
+	} else {
+		usb_stor_dbg(us, "MS Card Not Ready --- %x\n", bbuf[0]);
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int ene_sd_init(struct us_data *us)
+{
+	int result;
+	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+	u8 *bbuf = info->bbuf;
+
+	usb_stor_dbg(us, "transport --- ENE_SDInit\n");
+	/* SD Init Part-1 */
+	result = ene_load_bincode(us, SD_INIT1_PATTERN);
+	if (result != USB_STOR_XFER_GOOD) {
+		usb_stor_dbg(us, "Load SD Init Code Part-1 Fail !!\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+	bcb->Flags = US_BULK_FLAG_IN;
+	bcb->CDB[0] = 0xF2;
+
+	result = ene_send_scsi_cmd(us, FDIR_READ, NULL, 0);
+	if (result != USB_STOR_XFER_GOOD) {
+		usb_stor_dbg(us, "Execution SD Init Code Fail !!\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	/* SD Init Part-2 */
+	result = ene_load_bincode(us, SD_INIT2_PATTERN);
+	if (result != USB_STOR_XFER_GOOD) {
+		usb_stor_dbg(us, "Load SD Init Code Part-2 Fail !!\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+	bcb->DataTransferLength = 0x200;
+	bcb->Flags              = US_BULK_FLAG_IN;
+	bcb->CDB[0]             = 0xF1;
+
+	result = ene_send_scsi_cmd(us, FDIR_READ, bbuf, 0);
+	if (result != USB_STOR_XFER_GOOD) {
+		usb_stor_dbg(us, "Execution SD Init Code Fail !!\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	info->SD_Status =  *(struct SD_STATUS *) bbuf;
+	if (info->SD_Status.Insert && info->SD_Status.Ready) {
+		struct SD_STATUS *s = &info->SD_Status;
+
+		ene_get_card_status(us, bbuf);
+		usb_stor_dbg(us, "Insert     = %x\n", s->Insert);
+		usb_stor_dbg(us, "Ready      = %x\n", s->Ready);
+		usb_stor_dbg(us, "IsMMC      = %x\n", s->IsMMC);
+		usb_stor_dbg(us, "HiCapacity = %x\n", s->HiCapacity);
+		usb_stor_dbg(us, "HiSpeed    = %x\n", s->HiSpeed);
+		usb_stor_dbg(us, "WtP        = %x\n", s->WtP);
+	} else {
+		usb_stor_dbg(us, "SD Card Not Ready --- %x\n", bbuf[0]);
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+
+static int ene_init(struct us_data *us)
+{
+	int result;
+	u8  misc_reg03;
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
+	u8 *bbuf = info->bbuf;
+
+	result = ene_get_card_type(us, REG_CARD_STATUS, bbuf);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	misc_reg03 = bbuf[0];
+	if (misc_reg03 & 0x01) {
+		if (!info->SD_Status.Ready) {
+			result = ene_sd_init(us);
+			if (result != USB_STOR_XFER_GOOD)
+				return USB_STOR_TRANSPORT_ERROR;
+		}
+	}
+	if (misc_reg03 & 0x02) {
+		if (!info->MS_Status.Ready) {
+			result = ene_ms_init(us);
+			if (result != USB_STOR_XFER_GOOD)
+				return USB_STOR_TRANSPORT_ERROR;
+		}
+	}
+	return result;
+}
+
+/*----- sd_scsi_irp() ---------*/
+static int sd_scsi_irp(struct us_data *us, struct scsi_cmnd *srb)
+{
+	int    result;
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *)us->extra;
+
+	switch (srb->cmnd[0]) {
+	case TEST_UNIT_READY:
+		result = sd_scsi_test_unit_ready(us, srb);
+		break; /* 0x00 */
+	case REQUEST_SENSE:
+		result = do_scsi_request_sense(us, srb);
+		break; /* 0x03 */
+	case INQUIRY:
+		result = do_scsi_inquiry(us, srb);
+		break; /* 0x12 */
+	case MODE_SENSE:
+		result = sd_scsi_mode_sense(us, srb);
+		break; /* 0x1A */
+	/*
+	case START_STOP:
+		result = SD_SCSI_Start_Stop(us, srb);
+		break; //0x1B
+	*/
+	case READ_CAPACITY:
+		result = sd_scsi_read_capacity(us, srb);
+		break; /* 0x25 */
+	case READ_10:
+		result = sd_scsi_read(us, srb);
+		break; /* 0x28 */
+	case WRITE_10:
+		result = sd_scsi_write(us, srb);
+		break; /* 0x2A */
+	default:
+		info->SrbStatus = SS_ILLEGAL_REQUEST;
+		result = USB_STOR_TRANSPORT_FAILED;
+		break;
+	}
+	if (result == USB_STOR_TRANSPORT_GOOD)
+		info->SrbStatus = SS_SUCCESS;
+	return result;
+}
+
+/*
+ * ms_scsi_irp()
+ */
+static int ms_scsi_irp(struct us_data *us, struct scsi_cmnd *srb)
+{
+	int result;
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *)us->extra;
+
+	switch (srb->cmnd[0]) {
+	case TEST_UNIT_READY:
+		result = ms_scsi_test_unit_ready(us, srb);
+		break; /* 0x00 */
+	case REQUEST_SENSE:
+		result = do_scsi_request_sense(us, srb);
+		break; /* 0x03 */
+	case INQUIRY:
+		result = do_scsi_inquiry(us, srb);
+		break; /* 0x12 */
+	case MODE_SENSE:
+		result = ms_scsi_mode_sense(us, srb);
+		break; /* 0x1A */
+	case READ_CAPACITY:
+		result = ms_scsi_read_capacity(us, srb);
+		break; /* 0x25 */
+	case READ_10:
+		result = ms_scsi_read(us, srb);
+		break; /* 0x28 */
+	case WRITE_10:
+		result = ms_scsi_write(us, srb);
+		break;  /* 0x2A */
+	default:
+		info->SrbStatus = SS_ILLEGAL_REQUEST;
+		result = USB_STOR_TRANSPORT_FAILED;
+		break;
+	}
+	if (result == USB_STOR_TRANSPORT_GOOD)
+		info->SrbStatus = SS_SUCCESS;
+	return result;
+}
+
+static int ene_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+	int result = USB_STOR_XFER_GOOD;
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
+
+	/*US_DEBUG(usb_stor_show_command(us, srb)); */
+	scsi_set_resid(srb, 0);
+	if (unlikely(!(info->SD_Status.Ready || info->MS_Status.Ready)))
+		result = ene_init(us);
+	if (result == USB_STOR_XFER_GOOD) {
+		result = USB_STOR_TRANSPORT_ERROR;
+		if (info->SD_Status.Ready)
+			result = sd_scsi_irp(us, srb);
+
+		if (info->MS_Status.Ready)
+			result = ms_scsi_irp(us, srb);
+	}
+	return result;
+}
+
+static struct scsi_host_template ene_ub6250_host_template;
+
+static int ene_ub6250_probe(struct usb_interface *intf,
+			 const struct usb_device_id *id)
+{
+	int result;
+	u8  misc_reg03;
+	struct us_data *us;
+	struct ene_ub6250_info *info;
+
+	result = usb_stor_probe1(&us, intf, id,
+		   (id - ene_ub6250_usb_ids) + ene_ub6250_unusual_dev_list,
+		   &ene_ub6250_host_template);
+	if (result)
+		return result;
+
+	/* FIXME: where should the code alloc extra buf ? */
+	us->extra = kzalloc(sizeof(struct ene_ub6250_info), GFP_KERNEL);
+	if (!us->extra)
+		return -ENOMEM;
+	us->extra_destructor = ene_ub6250_info_destructor;
+
+	info = (struct ene_ub6250_info *)(us->extra);
+	info->bbuf = kmalloc(512, GFP_KERNEL);
+	if (!info->bbuf) {
+		kfree(us->extra);
+		return -ENOMEM;
+	}
+
+	us->transport_name = "ene_ub6250";
+	us->transport = ene_transport;
+	us->max_lun = 0;
+
+	result = usb_stor_probe2(us);
+	if (result)
+		return result;
+
+	/* probe card type */
+	result = ene_get_card_type(us, REG_CARD_STATUS, info->bbuf);
+	if (result != USB_STOR_XFER_GOOD) {
+		usb_stor_disconnect(intf);
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	misc_reg03 = info->bbuf[0];
+	if (!(misc_reg03 & 0x01)) {
+		pr_info("ums_eneub6250: This driver only supports SD/MS cards. "
+			"It does not support SM cards.\n");
+	}
+
+	return result;
+}
+
+
+#ifdef CONFIG_PM
+
+static int ene_ub6250_resume(struct usb_interface *iface)
+{
+	u8 tmp = 0;
+	struct us_data *us = usb_get_intfdata(iface);
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
+
+	mutex_lock(&us->dev_mutex);
+
+	if (us->suspend_resume_hook)
+		(us->suspend_resume_hook)(us, US_RESUME);
+
+	mutex_unlock(&us->dev_mutex);
+
+	info->Power_IsResum = true;
+	/*info->SD_Status.Ready = 0; */
+	info->SD_Status = *(struct SD_STATUS *)&tmp;
+	info->MS_Status = *(struct MS_STATUS *)&tmp;
+	info->SM_Status = *(struct SM_STATUS *)&tmp;
+
+	return 0;
+}
+
+static int ene_ub6250_reset_resume(struct usb_interface *iface)
+{
+	u8 tmp = 0;
+	struct us_data *us = usb_get_intfdata(iface);
+	struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
+
+	/* Report the reset to the SCSI core */
+	usb_stor_reset_resume(iface);
+
+	/*
+	 * FIXME: Notify the subdrivers that they need to reinitialize
+	 * the device
+	 */
+	info->Power_IsResum = true;
+	/*info->SD_Status.Ready = 0; */
+	info->SD_Status = *(struct SD_STATUS *)&tmp;
+	info->MS_Status = *(struct MS_STATUS *)&tmp;
+	info->SM_Status = *(struct SM_STATUS *)&tmp;
+
+	return 0;
+}
+
+#else
+
+#define ene_ub6250_resume		NULL
+#define ene_ub6250_reset_resume		NULL
+
+#endif
+
+static struct usb_driver ene_ub6250_driver = {
+	.name =		DRV_NAME,
+	.probe =	ene_ub6250_probe,
+	.disconnect =	usb_stor_disconnect,
+	.suspend =	usb_stor_suspend,
+	.resume =	ene_ub6250_resume,
+	.reset_resume =	ene_ub6250_reset_resume,
+	.pre_reset =	usb_stor_pre_reset,
+	.post_reset =	usb_stor_post_reset,
+	.id_table =	ene_ub6250_usb_ids,
+	.soft_unbind =	1,
+	.no_dynamic_id = 1,
+};
+
+module_usb_stor_driver(ene_ub6250_driver, ene_ub6250_host_template, DRV_NAME);
diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c
new file mode 100644
index 0000000..4f542df
--- /dev/null
+++ b/drivers/usb/storage/freecom.c
@@ -0,0 +1,578 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for Freecom USB/IDE adaptor
+ *
+ * Freecom v0.1:
+ *
+ * First release
+ *
+ * Current development and maintenance by:
+ *   (C) 2000 David Brown <usb-storage@davidb.org>
+ *
+ * This driver was developed with information provided in FREECOM's USB
+ * Programmers Reference Guide.  For further information contact Freecom
+ * (http://www.freecom.de/)
+ */
+
+#include <linux/module.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "protocol.h"
+#include "debug.h"
+#include "scsiglue.h"
+
+#define DRV_NAME "ums-freecom"
+
+MODULE_DESCRIPTION("Driver for Freecom USB/IDE adaptor");
+MODULE_AUTHOR("David Brown <usb-storage@davidb.org>");
+MODULE_LICENSE("GPL");
+
+#ifdef CONFIG_USB_STORAGE_DEBUG
+static void pdump(struct us_data *us, void *ibuffer, int length);
+#endif
+
+/* Bits of HD_STATUS */
+#define ERR_STAT		0x01
+#define DRQ_STAT		0x08
+
+/* All of the outgoing packets are 64 bytes long. */
+struct freecom_cb_wrap {
+	u8    Type;		/* Command type. */
+	u8    Timeout;		/* Timeout in seconds. */
+	u8    Atapi[12];	/* An ATAPI packet. */
+	u8    Filler[50];	/* Padding Data. */
+};
+
+struct freecom_xfer_wrap {
+	u8    Type;		/* Command type. */
+	u8    Timeout;		/* Timeout in seconds. */
+	__le32   Count;		/* Number of bytes to transfer. */
+	u8    Pad[58];
+} __attribute__ ((packed));
+
+struct freecom_ide_out {
+	u8    Type;		/* Type + IDE register. */
+	u8    Pad;
+	__le16   Value;		/* Value to write. */
+	u8    Pad2[60];
+};
+
+struct freecom_ide_in {
+	u8    Type;		/* Type | IDE register. */
+	u8    Pad[63];
+};
+
+struct freecom_status {
+	u8    Status;
+	u8    Reason;
+	__le16   Count;
+	u8    Pad[60];
+};
+
+/*
+ * Freecom stuffs the interrupt status in the INDEX_STAT bit of the ide
+ * register.
+ */
+#define FCM_INT_STATUS		0x02 /* INDEX_STAT */
+#define FCM_STATUS_BUSY		0x80
+
+/*
+ * These are the packet types.  The low bit indicates that this command
+ * should wait for an interrupt.
+ */
+#define FCM_PACKET_ATAPI	0x21
+#define FCM_PACKET_STATUS	0x20
+
+/*
+ * Receive data from the IDE interface.  The ATAPI packet has already
+ * waited, so the data should be immediately available.
+ */
+#define FCM_PACKET_INPUT	0x81
+
+/* Send data to the IDE interface. */
+#define FCM_PACKET_OUTPUT	0x01
+
+/*
+ * Write a value to an ide register.  Or the ide register to write after
+ * munging the address a bit.
+ */
+#define FCM_PACKET_IDE_WRITE	0x40
+#define FCM_PACKET_IDE_READ	0xC0
+
+/* All packets (except for status) are 64 bytes long. */
+#define FCM_PACKET_LENGTH		64
+#define FCM_STATUS_PACKET_LENGTH	4
+
+static int init_freecom(struct us_data *us);
+
+
+/*
+ * The table of devices
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+		    vendorName, productName, useProtocol, useTransport, \
+		    initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+  .driver_info = (flags) }
+
+static struct usb_device_id freecom_usb_ids[] = {
+#	include "unusual_freecom.h"
+	{ }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, freecom_usb_ids);
+
+#undef UNUSUAL_DEV
+
+/*
+ * The flags table
+ */
+#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
+		    vendor_name, product_name, use_protocol, use_transport, \
+		    init_function, Flags) \
+{ \
+	.vendorName = vendor_name,	\
+	.productName = product_name,	\
+	.useProtocol = use_protocol,	\
+	.useTransport = use_transport,	\
+	.initFunction = init_function,	\
+}
+
+static struct us_unusual_dev freecom_unusual_dev_list[] = {
+#	include "unusual_freecom.h"
+	{ }		/* Terminating entry */
+};
+
+#undef UNUSUAL_DEV
+
+static int
+freecom_readdata (struct scsi_cmnd *srb, struct us_data *us,
+		unsigned int ipipe, unsigned int opipe, int count)
+{
+	struct freecom_xfer_wrap *fxfr =
+		(struct freecom_xfer_wrap *) us->iobuf;
+	int result;
+
+	fxfr->Type = FCM_PACKET_INPUT | 0x00;
+	fxfr->Timeout = 0;    /* Short timeout for debugging. */
+	fxfr->Count = cpu_to_le32 (count);
+	memset (fxfr->Pad, 0, sizeof (fxfr->Pad));
+
+	usb_stor_dbg(us, "Read data Freecom! (c=%d)\n", count);
+
+	/* Issue the transfer command. */
+	result = usb_stor_bulk_transfer_buf (us, opipe, fxfr,
+			FCM_PACKET_LENGTH, NULL);
+	if (result != USB_STOR_XFER_GOOD) {
+		usb_stor_dbg(us, "Freecom readdata transport error\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	/* Now transfer all of our blocks. */
+	usb_stor_dbg(us, "Start of read\n");
+	result = usb_stor_bulk_srb(us, ipipe, srb);
+	usb_stor_dbg(us, "freecom_readdata done!\n");
+
+	if (result > USB_STOR_XFER_SHORT)
+		return USB_STOR_TRANSPORT_ERROR;
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int
+freecom_writedata (struct scsi_cmnd *srb, struct us_data *us,
+		int unsigned ipipe, unsigned int opipe, int count)
+{
+	struct freecom_xfer_wrap *fxfr =
+		(struct freecom_xfer_wrap *) us->iobuf;
+	int result;
+
+	fxfr->Type = FCM_PACKET_OUTPUT | 0x00;
+	fxfr->Timeout = 0;    /* Short timeout for debugging. */
+	fxfr->Count = cpu_to_le32 (count);
+	memset (fxfr->Pad, 0, sizeof (fxfr->Pad));
+
+	usb_stor_dbg(us, "Write data Freecom! (c=%d)\n", count);
+
+	/* Issue the transfer command. */
+	result = usb_stor_bulk_transfer_buf (us, opipe, fxfr,
+			FCM_PACKET_LENGTH, NULL);
+	if (result != USB_STOR_XFER_GOOD) {
+		usb_stor_dbg(us, "Freecom writedata transport error\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	/* Now transfer all of our blocks. */
+	usb_stor_dbg(us, "Start of write\n");
+	result = usb_stor_bulk_srb(us, opipe, srb);
+
+	usb_stor_dbg(us, "freecom_writedata done!\n");
+	if (result > USB_STOR_XFER_SHORT)
+		return USB_STOR_TRANSPORT_ERROR;
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Transport for the Freecom USB/IDE adaptor.
+ *
+ */
+static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+	struct freecom_cb_wrap *fcb;
+	struct freecom_status  *fst;
+	unsigned int ipipe, opipe;		/* We need both pipes. */
+	int result;
+	unsigned int partial;
+	int length;
+
+	fcb = (struct freecom_cb_wrap *) us->iobuf;
+	fst = (struct freecom_status *) us->iobuf;
+
+	usb_stor_dbg(us, "Freecom TRANSPORT STARTED\n");
+
+	/* Get handles for both transports. */
+	opipe = us->send_bulk_pipe;
+	ipipe = us->recv_bulk_pipe;
+
+	/* The ATAPI Command always goes out first. */
+	fcb->Type = FCM_PACKET_ATAPI | 0x00;
+	fcb->Timeout = 0;
+	memcpy (fcb->Atapi, srb->cmnd, 12);
+	memset (fcb->Filler, 0, sizeof (fcb->Filler));
+
+	US_DEBUG(pdump(us, srb->cmnd, 12));
+
+	/* Send it out. */
+	result = usb_stor_bulk_transfer_buf (us, opipe, fcb,
+			FCM_PACKET_LENGTH, NULL);
+
+	/*
+	 * The Freecom device will only fail if there is something wrong in
+	 * USB land.  It returns the status in its own registers, which
+	 * come back in the bulk pipe.
+	 */
+	if (result != USB_STOR_XFER_GOOD) {
+		usb_stor_dbg(us, "freecom transport error\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	/*
+	 * There are times we can optimize out this status read, but it
+	 * doesn't hurt us to always do it now.
+	 */
+	result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
+			FCM_STATUS_PACKET_LENGTH, &partial);
+	usb_stor_dbg(us, "foo Status result %d %u\n", result, partial);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	US_DEBUG(pdump(us, (void *)fst, partial));
+
+	/*
+	 * The firmware will time-out commands after 20 seconds. Some commands
+	 * can legitimately take longer than this, so we use a different
+	 * command that only waits for the interrupt and then sends status,
+	 * without having to send a new ATAPI command to the device.
+	 *
+	 * NOTE: There is some indication that a data transfer after a timeout
+	 * may not work, but that is a condition that should never happen.
+	 */
+	while (fst->Status & FCM_STATUS_BUSY) {
+		usb_stor_dbg(us, "20 second USB/ATAPI bridge TIMEOUT occurred!\n");
+		usb_stor_dbg(us, "fst->Status is %x\n", fst->Status);
+
+		/* Get the status again */
+		fcb->Type = FCM_PACKET_STATUS;
+		fcb->Timeout = 0;
+		memset (fcb->Atapi, 0, sizeof(fcb->Atapi));
+		memset (fcb->Filler, 0, sizeof (fcb->Filler));
+
+		/* Send it out. */
+		result = usb_stor_bulk_transfer_buf (us, opipe, fcb,
+				FCM_PACKET_LENGTH, NULL);
+
+		/*
+		 * The Freecom device will only fail if there is something
+		 * wrong in USB land.  It returns the status in its own
+		 * registers, which come back in the bulk pipe.
+		 */
+		if (result != USB_STOR_XFER_GOOD) {
+			usb_stor_dbg(us, "freecom transport error\n");
+			return USB_STOR_TRANSPORT_ERROR;
+		}
+
+		/* get the data */
+		result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
+				FCM_STATUS_PACKET_LENGTH, &partial);
+
+		usb_stor_dbg(us, "bar Status result %d %u\n", result, partial);
+		if (result != USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		US_DEBUG(pdump(us, (void *)fst, partial));
+	}
+
+	if (partial != 4)
+		return USB_STOR_TRANSPORT_ERROR;
+	if ((fst->Status & 1) != 0) {
+		usb_stor_dbg(us, "operation failed\n");
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	/*
+	 * The device might not have as much data available as we
+	 * requested.  If you ask for more than the device has, this reads
+	 * and such will hang.
+	 */
+	usb_stor_dbg(us, "Device indicates that it has %d bytes available\n",
+		     le16_to_cpu(fst->Count));
+	usb_stor_dbg(us, "SCSI requested %d\n", scsi_bufflen(srb));
+
+	/* Find the length we desire to read. */
+	switch (srb->cmnd[0]) {
+	case INQUIRY:
+	case REQUEST_SENSE:	/* 16 or 18 bytes? spec says 18, lots of devices only have 16 */
+	case MODE_SENSE:
+	case MODE_SENSE_10:
+		length = le16_to_cpu(fst->Count);
+		break;
+	default:
+		length = scsi_bufflen(srb);
+	}
+
+	/* verify that this amount is legal */
+	if (length > scsi_bufflen(srb)) {
+		length = scsi_bufflen(srb);
+		usb_stor_dbg(us, "Truncating request to match buffer length: %d\n",
+			     length);
+	}
+
+	/*
+	 * What we do now depends on what direction the data is supposed to
+	 * move in.
+	 */
+
+	switch (us->srb->sc_data_direction) {
+	case DMA_FROM_DEVICE:
+		/* catch bogus "read 0 length" case */
+		if (!length)
+			break;
+		/*
+		 * Make sure that the status indicates that the device
+		 * wants data as well.
+		 */
+		if ((fst->Status & DRQ_STAT) == 0 || (fst->Reason & 3) != 2) {
+			usb_stor_dbg(us, "SCSI wants data, drive doesn't have any\n");
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+		result = freecom_readdata (srb, us, ipipe, opipe, length);
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			return result;
+
+		usb_stor_dbg(us, "Waiting for status\n");
+		result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
+				FCM_PACKET_LENGTH, &partial);
+		US_DEBUG(pdump(us, (void *)fst, partial));
+
+		if (partial != 4 || result > USB_STOR_XFER_SHORT)
+			return USB_STOR_TRANSPORT_ERROR;
+		if ((fst->Status & ERR_STAT) != 0) {
+			usb_stor_dbg(us, "operation failed\n");
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+		if ((fst->Reason & 3) != 3) {
+			usb_stor_dbg(us, "Drive seems still hungry\n");
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+		usb_stor_dbg(us, "Transfer happy\n");
+		break;
+
+	case DMA_TO_DEVICE:
+		/* catch bogus "write 0 length" case */
+		if (!length)
+			break;
+		/*
+		 * Make sure the status indicates that the device wants to
+		 * send us data.
+		 */
+		/* !!IMPLEMENT!! */
+		result = freecom_writedata (srb, us, ipipe, opipe, length);
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			return result;
+
+		usb_stor_dbg(us, "Waiting for status\n");
+		result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
+				FCM_PACKET_LENGTH, &partial);
+
+		if (partial != 4 || result > USB_STOR_XFER_SHORT)
+			return USB_STOR_TRANSPORT_ERROR;
+		if ((fst->Status & ERR_STAT) != 0) {
+			usb_stor_dbg(us, "operation failed\n");
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+		if ((fst->Reason & 3) != 3) {
+			usb_stor_dbg(us, "Drive seems still hungry\n");
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+
+		usb_stor_dbg(us, "Transfer happy\n");
+		break;
+
+
+	case DMA_NONE:
+		/* Easy, do nothing. */
+		break;
+
+	default:
+		/* should never hit here -- filtered in usb.c */
+		usb_stor_dbg(us, "freecom unimplemented direction: %d\n",
+			     us->srb->sc_data_direction);
+		/* Return fail, SCSI seems to handle this better. */
+		return USB_STOR_TRANSPORT_FAILED;
+		break;
+	}
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int init_freecom(struct us_data *us)
+{
+	int result;
+	char *buffer = us->iobuf;
+
+	/*
+	 * The DMA-mapped I/O buffer is 64 bytes long, just right for
+	 * all our packets.  No need to allocate any extra buffer space.
+	 */
+
+	result = usb_stor_control_msg(us, us->recv_ctrl_pipe,
+			0x4c, 0xc0, 0x4346, 0x0, buffer, 0x20, 3*HZ);
+	buffer[32] = '\0';
+	usb_stor_dbg(us, "String returned from FC init is: %s\n", buffer);
+
+	/*
+	 * Special thanks to the people at Freecom for providing me with
+	 * this "magic sequence", which they use in their Windows and MacOS
+	 * drivers to make sure that all the attached perhiperals are
+	 * properly reset.
+	 */
+
+	/* send reset */
+	result = usb_stor_control_msg(us, us->send_ctrl_pipe,
+			0x4d, 0x40, 0x24d8, 0x0, NULL, 0x0, 3*HZ);
+	usb_stor_dbg(us, "result from activate reset is %d\n", result);
+
+	/* wait 250ms */
+	msleep(250);
+
+	/* clear reset */
+	result = usb_stor_control_msg(us, us->send_ctrl_pipe,
+			0x4d, 0x40, 0x24f8, 0x0, NULL, 0x0, 3*HZ);
+	usb_stor_dbg(us, "result from clear reset is %d\n", result);
+
+	/* wait 3 seconds */
+	msleep(3 * 1000);
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int usb_stor_freecom_reset(struct us_data *us)
+{
+	printk (KERN_CRIT "freecom reset called\n");
+
+	/* We don't really have this feature. */
+	return FAILED;
+}
+
+#ifdef CONFIG_USB_STORAGE_DEBUG
+static void pdump(struct us_data *us, void *ibuffer, int length)
+{
+	static char line[80];
+	int offset = 0;
+	unsigned char *buffer = (unsigned char *) ibuffer;
+	int i, j;
+	int from, base;
+
+	offset = 0;
+	for (i = 0; i < length; i++) {
+		if ((i & 15) == 0) {
+			if (i > 0) {
+				offset += sprintf (line+offset, " - ");
+				for (j = i - 16; j < i; j++) {
+					if (buffer[j] >= 32 && buffer[j] <= 126)
+						line[offset++] = buffer[j];
+					else
+						line[offset++] = '.';
+				}
+				line[offset] = 0;
+				usb_stor_dbg(us, "%s\n", line);
+				offset = 0;
+			}
+			offset += sprintf (line+offset, "%08x:", i);
+		} else if ((i & 7) == 0) {
+			offset += sprintf (line+offset, " -");
+		}
+		offset += sprintf (line+offset, " %02x", buffer[i] & 0xff);
+	}
+
+	/* Add the last "chunk" of data. */
+	from = (length - 1) % 16;
+	base = ((length - 1) / 16) * 16;
+
+	for (i = from + 1; i < 16; i++)
+		offset += sprintf (line+offset, "   ");
+	if (from < 8)
+		offset += sprintf (line+offset, "  ");
+	offset += sprintf (line+offset, " - ");
+
+	for (i = 0; i <= from; i++) {
+		if (buffer[base+i] >= 32 && buffer[base+i] <= 126)
+			line[offset++] = buffer[base+i];
+		else
+			line[offset++] = '.';
+	}
+	line[offset] = 0;
+	usb_stor_dbg(us, "%s\n", line);
+	offset = 0;
+}
+#endif
+
+static struct scsi_host_template freecom_host_template;
+
+static int freecom_probe(struct usb_interface *intf,
+			 const struct usb_device_id *id)
+{
+	struct us_data *us;
+	int result;
+
+	result = usb_stor_probe1(&us, intf, id,
+			(id - freecom_usb_ids) + freecom_unusual_dev_list,
+			&freecom_host_template);
+	if (result)
+		return result;
+
+	us->transport_name = "Freecom";
+	us->transport = freecom_transport;
+	us->transport_reset = usb_stor_freecom_reset;
+	us->max_lun = 0;
+
+	result = usb_stor_probe2(us);
+	return result;
+}
+
+static struct usb_driver freecom_driver = {
+	.name =		DRV_NAME,
+	.probe =	freecom_probe,
+	.disconnect =	usb_stor_disconnect,
+	.suspend =	usb_stor_suspend,
+	.resume =	usb_stor_resume,
+	.reset_resume =	usb_stor_reset_resume,
+	.pre_reset =	usb_stor_pre_reset,
+	.post_reset =	usb_stor_post_reset,
+	.id_table =	freecom_usb_ids,
+	.soft_unbind =	1,
+	.no_dynamic_id = 1,
+};
+
+module_usb_stor_driver(freecom_driver, freecom_host_template, DRV_NAME);
diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c
new file mode 100644
index 0000000..f8f9ce8
--- /dev/null
+++ b/drivers/usb/storage/initializers.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Special Initializers for certain USB Mass Storage devices
+ *
+ * Current development and maintenance by:
+ *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * 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.
+ */
+
+#include <linux/errno.h>
+
+#include "usb.h"
+#include "initializers.h"
+#include "debug.h"
+#include "transport.h"
+
+/*
+ * This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target
+ * mode
+ */
+int usb_stor_euscsi_init(struct us_data *us)
+{
+	int result;
+
+	usb_stor_dbg(us, "Attempting to init eUSCSI bridge...\n");
+	result = usb_stor_control_msg(us, us->send_ctrl_pipe,
+			0x0C, USB_RECIP_INTERFACE | USB_TYPE_VENDOR,
+			0x01, 0x0, NULL, 0x0, 5 * HZ);
+	usb_stor_dbg(us, "-- result is %d\n", result);
+
+	return 0;
+}
+
+/*
+ * This function is required to activate all four slots on the UCR-61S2B
+ * flash reader
+ */
+int usb_stor_ucr61s2b_init(struct us_data *us)
+{
+	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap*) us->iobuf;
+	struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap*) us->iobuf;
+	int res;
+	unsigned int partial;
+	static char init_string[] = "\xec\x0a\x06\x00$PCCHIPS";
+
+	usb_stor_dbg(us, "Sending UCR-61S2B initialization packet...\n");
+
+	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+	bcb->Tag = 0;
+	bcb->DataTransferLength = cpu_to_le32(0);
+	bcb->Flags = bcb->Lun = 0;
+	bcb->Length = sizeof(init_string) - 1;
+	memset(bcb->CDB, 0, sizeof(bcb->CDB));
+	memcpy(bcb->CDB, init_string, sizeof(init_string) - 1);
+
+	res = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb,
+			US_BULK_CB_WRAP_LEN, &partial);
+	if (res)
+		return -EIO;
+
+	usb_stor_dbg(us, "Getting status packet...\n");
+	res = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs,
+			US_BULK_CS_WRAP_LEN, &partial);
+	if (res)
+		return -EIO;
+
+	return 0;
+}
+
+/* This places the HUAWEI E220 devices in multi-port mode */
+int usb_stor_huawei_e220_init(struct us_data *us)
+{
+	int result;
+
+	result = usb_stor_control_msg(us, us->send_ctrl_pipe,
+				      USB_REQ_SET_FEATURE,
+				      USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+				      0x01, 0x0, NULL, 0x0, 1 * HZ);
+	usb_stor_dbg(us, "Huawei mode set result is %d\n", result);
+	return 0;
+}
diff --git a/drivers/usb/storage/initializers.h b/drivers/usb/storage/initializers.h
new file mode 100644
index 0000000..2dbf9c7
--- /dev/null
+++ b/drivers/usb/storage/initializers.h
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Header file for Special Initializers for certain USB Mass Storage devices
+ *
+ * Current development and maintenance by:
+ *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * 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.
+ */
+
+#include "usb.h"
+#include "transport.h"
+
+/*
+ * This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target
+ * mode
+ */
+int usb_stor_euscsi_init(struct us_data *us);
+
+/*
+ * This function is required to activate all four slots on the UCR-61S2B
+ * flash reader
+ */
+int usb_stor_ucr61s2b_init(struct us_data *us);
+
+/* This places the HUAWEI E220 devices in multi-port mode */
+int usb_stor_huawei_e220_init(struct us_data *us);
diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c
new file mode 100644
index 0000000..f5e4500
--- /dev/null
+++ b/drivers/usb/storage/isd200.c
@@ -0,0 +1,1572 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Transport & Protocol Driver for In-System Design, Inc. ISD200 ASIC
+ *
+ * Current development and maintenance:
+ *   (C) 2001-2002 Björn Stenberg (bjorn@haxx.se)
+ *
+ * Developed with the assistance of:
+ *   (C) 2002 Alan Stern <stern@rowland.org>
+ *
+ * Initial work:
+ *   (C) 2000 In-System Design, Inc. (support@in-system.com)
+ *
+ * The ISD200 ASIC does not natively support ATA devices.  The chip
+ * does implement an interface, the ATA Command Block (ATACB) which provides
+ * a means of passing ATA commands and ATA register accesses to a device.
+ *
+ * History:
+ *
+ *  2002-10-19: Removed the specialized transfer routines.
+ *		(Alan Stern <stern@rowland.harvard.edu>)
+ *  2001-02-24: Removed lots of duplicate code and simplified the structure.
+ *	      (bjorn@haxx.se)
+ *  2002-01-16: Fixed endianness bug so it works on the ppc arch.
+ *	      (Luc Saillard <luc@saillard.org>)
+ *  2002-01-17: All bitfields removed.
+ *	      (bjorn@haxx.se)
+ */
+
+
+/* Include files */
+
+#include <linux/jiffies.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/ata.h>
+#include <linux/hdreg.h>
+#include <linux/scatterlist.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "protocol.h"
+#include "debug.h"
+#include "scsiglue.h"
+
+#define DRV_NAME "ums-isd200"
+
+MODULE_DESCRIPTION("Driver for In-System Design, Inc. ISD200 ASIC");
+MODULE_AUTHOR("Björn Stenberg <bjorn@haxx.se>");
+MODULE_LICENSE("GPL");
+
+static int isd200_Initialization(struct us_data *us);
+
+
+/*
+ * The table of devices
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+		    vendorName, productName, useProtocol, useTransport, \
+		    initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+  .driver_info = (flags) }
+
+static struct usb_device_id isd200_usb_ids[] = {
+#	include "unusual_isd200.h"
+	{ }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, isd200_usb_ids);
+
+#undef UNUSUAL_DEV
+
+/*
+ * The flags table
+ */
+#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
+		    vendor_name, product_name, use_protocol, use_transport, \
+		    init_function, Flags) \
+{ \
+	.vendorName = vendor_name,	\
+	.productName = product_name,	\
+	.useProtocol = use_protocol,	\
+	.useTransport = use_transport,	\
+	.initFunction = init_function,	\
+}
+
+static struct us_unusual_dev isd200_unusual_dev_list[] = {
+#	include "unusual_isd200.h"
+	{ }		/* Terminating entry */
+};
+
+#undef UNUSUAL_DEV
+
+/* Timeout defines (in Seconds) */
+
+#define ISD200_ENUM_BSY_TIMEOUT		35
+#define ISD200_ENUM_DETECT_TIMEOUT      30
+#define ISD200_DEFAULT_TIMEOUT		30
+
+/* device flags */
+#define DF_ATA_DEVICE		0x0001
+#define DF_MEDIA_STATUS_ENABLED	0x0002
+#define DF_REMOVABLE_MEDIA	0x0004
+
+/* capability bit definitions */
+#define CAPABILITY_DMA		0x01
+#define CAPABILITY_LBA		0x02
+
+/* command_setX bit definitions */
+#define COMMANDSET_REMOVABLE	0x02
+#define COMMANDSET_MEDIA_STATUS 0x10
+
+/* ATA Vendor Specific defines */
+#define ATA_ADDRESS_DEVHEAD_STD      0xa0
+#define ATA_ADDRESS_DEVHEAD_LBA_MODE 0x40    
+#define ATA_ADDRESS_DEVHEAD_SLAVE    0x10
+
+/* Action Select bits */
+#define ACTION_SELECT_0	     0x01
+#define ACTION_SELECT_1	     0x02
+#define ACTION_SELECT_2	     0x04
+#define ACTION_SELECT_3	     0x08
+#define ACTION_SELECT_4	     0x10
+#define ACTION_SELECT_5	     0x20
+#define ACTION_SELECT_6	     0x40
+#define ACTION_SELECT_7	     0x80
+
+/* Register Select bits */
+#define REG_ALTERNATE_STATUS	0x01
+#define REG_DEVICE_CONTROL	0x01
+#define REG_ERROR		0x02
+#define REG_FEATURES		0x02
+#define REG_SECTOR_COUNT	0x04
+#define REG_SECTOR_NUMBER	0x08
+#define REG_CYLINDER_LOW	0x10
+#define REG_CYLINDER_HIGH	0x20
+#define REG_DEVICE_HEAD		0x40
+#define REG_STATUS		0x80
+#define REG_COMMAND		0x80
+
+/* ATA registers offset definitions */
+#define ATA_REG_ERROR_OFFSET		1
+#define ATA_REG_LCYL_OFFSET		4
+#define ATA_REG_HCYL_OFFSET		5
+#define ATA_REG_STATUS_OFFSET		7
+
+/* ATA error definitions not in <linux/hdreg.h> */
+#define ATA_ERROR_MEDIA_CHANGE		0x20
+
+/* ATA command definitions not in <linux/hdreg.h> */
+#define ATA_COMMAND_GET_MEDIA_STATUS	0xDA
+#define ATA_COMMAND_MEDIA_EJECT		0xED
+
+/* ATA drive control definitions */
+#define ATA_DC_DISABLE_INTERRUPTS	0x02
+#define ATA_DC_RESET_CONTROLLER		0x04
+#define ATA_DC_REENABLE_CONTROLLER	0x00
+
+/*
+ *  General purpose return codes
+ */ 
+
+#define ISD200_ERROR		-1
+#define ISD200_GOOD		 0
+
+/*
+ * Transport return codes
+ */
+
+#define ISD200_TRANSPORT_GOOD       0   /* Transport good, command good     */
+#define ISD200_TRANSPORT_FAILED     1   /* Transport good, command failed   */
+#define ISD200_TRANSPORT_ERROR      2   /* Transport bad (i.e. device dead) */
+
+/* driver action codes */
+#define	ACTION_READ_STATUS	0
+#define	ACTION_RESET		1
+#define	ACTION_REENABLE		2
+#define	ACTION_SOFT_RESET	3
+#define	ACTION_ENUM		4
+#define	ACTION_IDENTIFY		5
+
+
+/*
+ * ata_cdb struct
+ */
+
+
+union ata_cdb {
+	struct {
+		unsigned char SignatureByte0;
+		unsigned char SignatureByte1;
+		unsigned char ActionSelect;
+		unsigned char RegisterSelect;
+		unsigned char TransferBlockSize;
+		unsigned char WriteData3F6;
+		unsigned char WriteData1F1;
+		unsigned char WriteData1F2;
+		unsigned char WriteData1F3;
+		unsigned char WriteData1F4;
+		unsigned char WriteData1F5;
+		unsigned char WriteData1F6;
+		unsigned char WriteData1F7;
+		unsigned char Reserved[3];
+	} generic;
+
+	struct {
+		unsigned char SignatureByte0;
+		unsigned char SignatureByte1;
+		unsigned char ActionSelect;
+		unsigned char RegisterSelect;
+		unsigned char TransferBlockSize;
+		unsigned char AlternateStatusByte;
+		unsigned char ErrorByte;
+		unsigned char SectorCountByte;
+		unsigned char SectorNumberByte;
+		unsigned char CylinderLowByte;
+		unsigned char CylinderHighByte;
+		unsigned char DeviceHeadByte;
+		unsigned char StatusByte;
+		unsigned char Reserved[3];
+	} read;
+
+	struct {
+		unsigned char SignatureByte0;
+		unsigned char SignatureByte1;
+		unsigned char ActionSelect;
+		unsigned char RegisterSelect;
+		unsigned char TransferBlockSize;
+		unsigned char DeviceControlByte;
+		unsigned char FeaturesByte;
+		unsigned char SectorCountByte;
+		unsigned char SectorNumberByte;
+		unsigned char CylinderLowByte;
+		unsigned char CylinderHighByte;
+		unsigned char DeviceHeadByte;
+		unsigned char CommandByte;
+		unsigned char Reserved[3];
+	} write;
+};
+
+
+/*
+ * Inquiry data structure. This is the data returned from the target
+ * after it receives an inquiry.
+ *
+ * This structure may be extended by the number of bytes specified
+ * in the field AdditionalLength. The defined size constant only
+ * includes fields through ProductRevisionLevel.
+ */
+
+/*
+ * DeviceType field
+ */
+#define DIRECT_ACCESS_DEVICE	    0x00    /* disks */
+#define DEVICE_REMOVABLE		0x80
+
+struct inquiry_data {
+   	unsigned char DeviceType;
+	unsigned char DeviceTypeModifier;
+	unsigned char Versions;
+	unsigned char Format; 
+	unsigned char AdditionalLength;
+	unsigned char Reserved[2];
+	unsigned char Capability;
+	unsigned char VendorId[8];
+	unsigned char ProductId[16];
+	unsigned char ProductRevisionLevel[4];
+	unsigned char VendorSpecific[20];
+	unsigned char Reserved3[40];
+} __attribute__ ((packed));
+
+/*
+ * INQUIRY data buffer size
+ */
+
+#define INQUIRYDATABUFFERSIZE 36
+
+
+/*
+ * ISD200 CONFIG data struct
+ */
+
+#define ATACFG_TIMING	  0x0f
+#define ATACFG_ATAPI_RESET     0x10
+#define ATACFG_MASTER	  0x20
+#define ATACFG_BLOCKSIZE       0xa0
+
+#define ATACFGE_LAST_LUN       0x07
+#define ATACFGE_DESC_OVERRIDE  0x08
+#define ATACFGE_STATE_SUSPEND  0x10
+#define ATACFGE_SKIP_BOOT      0x20
+#define ATACFGE_CONF_DESC2     0x40
+#define ATACFGE_INIT_STATUS    0x80
+
+#define CFG_CAPABILITY_SRST    0x01
+
+struct isd200_config {
+	unsigned char EventNotification;
+	unsigned char ExternalClock;
+	unsigned char ATAInitTimeout;
+	unsigned char ATAConfig;
+	unsigned char ATAMajorCommand;
+	unsigned char ATAMinorCommand;
+	unsigned char ATAExtraConfig;
+	unsigned char Capability;
+}__attribute__ ((packed));
+
+
+/*
+ * ISD200 driver information struct
+ */
+
+struct isd200_info {
+	struct inquiry_data InquiryData;
+	u16 *id;
+	struct isd200_config ConfigData;
+	unsigned char *RegsBuf;
+	unsigned char ATARegs[8];
+	unsigned char DeviceHead;
+	unsigned char DeviceFlags;
+
+	/* maximum number of LUNs supported */
+	unsigned char MaxLUNs;
+	unsigned char cmnd[BLK_MAX_CDB];
+	struct scsi_cmnd srb;
+	struct scatterlist sg;
+};
+
+
+/*
+ * Read Capacity Data - returned in Big Endian format
+ */
+
+struct read_capacity_data {
+	__be32 LogicalBlockAddress;
+	__be32 BytesPerBlock;
+};
+
+/*
+ * Read Block Limits Data - returned in Big Endian format
+ * This structure returns the maximum and minimum block
+ * size for a TAPE device.
+ */
+
+struct read_block_limits {
+	unsigned char Reserved;
+	unsigned char BlockMaximumSize[3];
+	unsigned char BlockMinimumSize[2];
+};
+
+
+/*
+ * Sense Data Format
+ */
+
+#define SENSE_ERRCODE	   0x7f
+#define SENSE_ERRCODE_VALID     0x80
+#define SENSE_FLAG_SENSE_KEY    0x0f
+#define SENSE_FLAG_BAD_LENGTH   0x20
+#define SENSE_FLAG_END_OF_MEDIA 0x40
+#define SENSE_FLAG_FILE_MARK    0x80
+struct sense_data {
+	unsigned char ErrorCode;
+	unsigned char SegmentNumber;
+	unsigned char Flags;
+	unsigned char Information[4];
+	unsigned char AdditionalSenseLength;
+	unsigned char CommandSpecificInformation[4];
+	unsigned char AdditionalSenseCode;
+	unsigned char AdditionalSenseCodeQualifier;
+	unsigned char FieldReplaceableUnitCode;
+	unsigned char SenseKeySpecific[3];
+} __attribute__ ((packed));
+
+/*
+ * Default request sense buffer size
+ */
+
+#define SENSE_BUFFER_SIZE 18
+
+/***********************************************************************
+ * Helper routines
+ ***********************************************************************/
+
+/**************************************************************************
+ * isd200_build_sense
+ *									 
+ *  Builds an artificial sense buffer to report the results of a 
+ *  failed command.
+ *								       
+ * RETURNS:
+ *    void
+ */
+static void isd200_build_sense(struct us_data *us, struct scsi_cmnd *srb)
+{
+	struct isd200_info *info = (struct isd200_info *)us->extra;
+	struct sense_data *buf = (struct sense_data *) &srb->sense_buffer[0];
+	unsigned char error = info->ATARegs[ATA_REG_ERROR_OFFSET];
+
+	if(error & ATA_ERROR_MEDIA_CHANGE) {
+		buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID;
+		buf->AdditionalSenseLength = 0xb;
+		buf->Flags = UNIT_ATTENTION;
+		buf->AdditionalSenseCode = 0;
+		buf->AdditionalSenseCodeQualifier = 0;
+	} else if (error & ATA_MCR) {
+		buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID;
+		buf->AdditionalSenseLength = 0xb;
+		buf->Flags =  UNIT_ATTENTION;
+		buf->AdditionalSenseCode = 0;
+		buf->AdditionalSenseCodeQualifier = 0;
+	} else if (error & ATA_TRK0NF) {
+		buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID;
+		buf->AdditionalSenseLength = 0xb;
+		buf->Flags =  NOT_READY;
+		buf->AdditionalSenseCode = 0;
+		buf->AdditionalSenseCodeQualifier = 0;
+	} else if (error & ATA_UNC) {
+		buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID;
+		buf->AdditionalSenseLength = 0xb;
+		buf->Flags =  DATA_PROTECT;
+		buf->AdditionalSenseCode = 0;
+		buf->AdditionalSenseCodeQualifier = 0;
+	} else {
+		buf->ErrorCode = 0;
+		buf->AdditionalSenseLength = 0;
+		buf->Flags =  0;
+		buf->AdditionalSenseCode = 0;
+		buf->AdditionalSenseCodeQualifier = 0;
+	}
+}
+
+
+/***********************************************************************
+ * Transport routines
+ ***********************************************************************/
+
+/**************************************************************************
+ *  isd200_set_srb(), isd200_srb_set_bufflen()
+ *
+ * Two helpers to facilitate in initialization of scsi_cmnd structure
+ * Will need to change when struct scsi_cmnd changes
+ */
+static void isd200_set_srb(struct isd200_info *info,
+	enum dma_data_direction dir, void* buff, unsigned bufflen)
+{
+	struct scsi_cmnd *srb = &info->srb;
+
+	if (buff)
+		sg_init_one(&info->sg, buff, bufflen);
+
+	srb->sc_data_direction = dir;
+	srb->sdb.table.sgl = buff ? &info->sg : NULL;
+	srb->sdb.length = bufflen;
+	srb->sdb.table.nents = buff ? 1 : 0;
+}
+
+static void isd200_srb_set_bufflen(struct scsi_cmnd *srb, unsigned bufflen)
+{
+	srb->sdb.length = bufflen;
+}
+
+
+/**************************************************************************
+ *  isd200_action
+ *
+ * Routine for sending commands to the isd200
+ *
+ * RETURNS:
+ *    ISD status code
+ */
+static int isd200_action( struct us_data *us, int action, 
+			  void* pointer, int value )
+{
+	union ata_cdb ata;
+	/* static to prevent this large struct being placed on the valuable stack */
+	static struct scsi_device srb_dev;
+	struct isd200_info *info = (struct isd200_info *)us->extra;
+	struct scsi_cmnd *srb = &info->srb;
+	int status;
+
+	memset(&ata, 0, sizeof(ata));
+	srb->cmnd = info->cmnd;
+	srb->device = &srb_dev;
+
+	ata.generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
+	ata.generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
+	ata.generic.TransferBlockSize = 1;
+
+	switch ( action ) {
+	case ACTION_READ_STATUS:
+		usb_stor_dbg(us, "   isd200_action(READ_STATUS)\n");
+		ata.generic.ActionSelect = ACTION_SELECT_0|ACTION_SELECT_2;
+		ata.generic.RegisterSelect =
+		  REG_CYLINDER_LOW | REG_CYLINDER_HIGH |
+		  REG_STATUS | REG_ERROR;
+		isd200_set_srb(info, DMA_FROM_DEVICE, pointer, value);
+		break;
+
+	case ACTION_ENUM:
+		usb_stor_dbg(us, "   isd200_action(ENUM,0x%02x)\n", value);
+		ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2|
+					   ACTION_SELECT_3|ACTION_SELECT_4|
+					   ACTION_SELECT_5;
+		ata.generic.RegisterSelect = REG_DEVICE_HEAD;
+		ata.write.DeviceHeadByte = value;
+		isd200_set_srb(info, DMA_NONE, NULL, 0);
+		break;
+
+	case ACTION_RESET:
+		usb_stor_dbg(us, "   isd200_action(RESET)\n");
+		ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2|
+					   ACTION_SELECT_3|ACTION_SELECT_4;
+		ata.generic.RegisterSelect = REG_DEVICE_CONTROL;
+		ata.write.DeviceControlByte = ATA_DC_RESET_CONTROLLER;
+		isd200_set_srb(info, DMA_NONE, NULL, 0);
+		break;
+
+	case ACTION_REENABLE:
+		usb_stor_dbg(us, "   isd200_action(REENABLE)\n");
+		ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2|
+					   ACTION_SELECT_3|ACTION_SELECT_4;
+		ata.generic.RegisterSelect = REG_DEVICE_CONTROL;
+		ata.write.DeviceControlByte = ATA_DC_REENABLE_CONTROLLER;
+		isd200_set_srb(info, DMA_NONE, NULL, 0);
+		break;
+
+	case ACTION_SOFT_RESET:
+		usb_stor_dbg(us, "   isd200_action(SOFT_RESET)\n");
+		ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_5;
+		ata.generic.RegisterSelect = REG_DEVICE_HEAD | REG_COMMAND;
+		ata.write.DeviceHeadByte = info->DeviceHead;
+		ata.write.CommandByte = ATA_CMD_DEV_RESET;
+		isd200_set_srb(info, DMA_NONE, NULL, 0);
+		break;
+
+	case ACTION_IDENTIFY:
+		usb_stor_dbg(us, "   isd200_action(IDENTIFY)\n");
+		ata.generic.RegisterSelect = REG_COMMAND;
+		ata.write.CommandByte = ATA_CMD_ID_ATA;
+		isd200_set_srb(info, DMA_FROM_DEVICE, info->id,
+				ATA_ID_WORDS * 2);
+		break;
+
+	default:
+		usb_stor_dbg(us, "Error: Undefined action %d\n", action);
+		return ISD200_ERROR;
+	}
+
+	memcpy(srb->cmnd, &ata, sizeof(ata.generic));
+	srb->cmd_len = sizeof(ata.generic);
+	status = usb_stor_Bulk_transport(srb, us);
+	if (status == USB_STOR_TRANSPORT_GOOD)
+		status = ISD200_GOOD;
+	else {
+		usb_stor_dbg(us, "   isd200_action(0x%02x) error: %d\n",
+			     action, status);
+		status = ISD200_ERROR;
+		/* need to reset device here */
+	}
+
+	return status;
+}
+
+/**************************************************************************
+ * isd200_read_regs
+ *									 
+ * Read ATA Registers
+ *
+ * RETURNS:
+ *    ISD status code
+ */
+static int isd200_read_regs( struct us_data *us )
+{
+	struct isd200_info *info = (struct isd200_info *)us->extra;
+	int retStatus = ISD200_GOOD;
+	int transferStatus;
+
+	usb_stor_dbg(us, "Entering isd200_IssueATAReadRegs\n");
+
+	transferStatus = isd200_action( us, ACTION_READ_STATUS,
+				    info->RegsBuf, sizeof(info->ATARegs) );
+	if (transferStatus != ISD200_TRANSPORT_GOOD) {
+		usb_stor_dbg(us, "   Error reading ATA registers\n");
+		retStatus = ISD200_ERROR;
+	} else {
+		memcpy(info->ATARegs, info->RegsBuf, sizeof(info->ATARegs));
+		usb_stor_dbg(us, "   Got ATA Register[ATA_REG_ERROR_OFFSET] = 0x%x\n",
+			     info->ATARegs[ATA_REG_ERROR_OFFSET]);
+	}
+
+	return retStatus;
+}
+
+
+/**************************************************************************
+ * Invoke the transport and basic error-handling/recovery methods
+ *
+ * This is used by the protocol layers to actually send the message to
+ * the device and receive the response.
+ */
+static void isd200_invoke_transport( struct us_data *us, 
+			      struct scsi_cmnd *srb, 
+			      union ata_cdb *ataCdb )
+{
+	int need_auto_sense = 0;
+	int transferStatus;
+	int result;
+
+	/* send the command to the transport layer */
+	memcpy(srb->cmnd, ataCdb, sizeof(ataCdb->generic));
+	srb->cmd_len = sizeof(ataCdb->generic);
+	transferStatus = usb_stor_Bulk_transport(srb, us);
+
+	/*
+	 * if the command gets aborted by the higher layers, we need to
+	 * short-circuit all other processing
+	 */
+	if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
+		usb_stor_dbg(us, "-- command was aborted\n");
+		goto Handle_Abort;
+	}
+
+	switch (transferStatus) {
+
+	case USB_STOR_TRANSPORT_GOOD:
+		/* Indicate a good result */
+		srb->result = SAM_STAT_GOOD;
+		break;
+
+	case USB_STOR_TRANSPORT_NO_SENSE:
+		usb_stor_dbg(us, "-- transport indicates protocol failure\n");
+		srb->result = SAM_STAT_CHECK_CONDITION;
+		return;
+
+	case USB_STOR_TRANSPORT_FAILED:
+		usb_stor_dbg(us, "-- transport indicates command failure\n");
+		need_auto_sense = 1;
+		break;
+
+	case USB_STOR_TRANSPORT_ERROR:
+		usb_stor_dbg(us, "-- transport indicates transport error\n");
+		srb->result = DID_ERROR << 16;
+		/* Need reset here */
+		return;
+    
+	default:
+		usb_stor_dbg(us, "-- transport indicates unknown error\n");
+		srb->result = DID_ERROR << 16;
+		/* Need reset here */
+		return;
+	}
+
+	if ((scsi_get_resid(srb) > 0) &&
+	    !((srb->cmnd[0] == REQUEST_SENSE) ||
+	      (srb->cmnd[0] == INQUIRY) ||
+	      (srb->cmnd[0] == MODE_SENSE) ||
+	      (srb->cmnd[0] == LOG_SENSE) ||
+	      (srb->cmnd[0] == MODE_SENSE_10))) {
+		usb_stor_dbg(us, "-- unexpectedly short transfer\n");
+		need_auto_sense = 1;
+	}
+
+	if (need_auto_sense) {
+		result = isd200_read_regs(us);
+		if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
+			usb_stor_dbg(us, "-- auto-sense aborted\n");
+			goto Handle_Abort;
+		}
+		if (result == ISD200_GOOD) {
+			isd200_build_sense(us, srb);
+			srb->result = SAM_STAT_CHECK_CONDITION;
+
+			/* If things are really okay, then let's show that */
+			if ((srb->sense_buffer[2] & 0xf) == 0x0)
+				srb->result = SAM_STAT_GOOD;
+		} else {
+			srb->result = DID_ERROR << 16;
+			/* Need reset here */
+		}
+	}
+
+	/*
+	 * Regardless of auto-sense, if we _know_ we have an error
+	 * condition, show that in the result code
+	 */
+	if (transferStatus == USB_STOR_TRANSPORT_FAILED)
+		srb->result = SAM_STAT_CHECK_CONDITION;
+	return;
+
+	/*
+	 * abort processing: the bulk-only transport requires a reset
+	 * following an abort
+	 */
+	Handle_Abort:
+	srb->result = DID_ABORT << 16;
+
+	/* permit the reset transfer to take place */
+	clear_bit(US_FLIDX_ABORTING, &us->dflags);
+	/* Need reset here */
+}
+
+#ifdef CONFIG_USB_STORAGE_DEBUG
+static void isd200_log_config(struct us_data *us, struct isd200_info *info)
+{
+	usb_stor_dbg(us, "      Event Notification: 0x%x\n",
+		     info->ConfigData.EventNotification);
+	usb_stor_dbg(us, "      External Clock: 0x%x\n",
+		     info->ConfigData.ExternalClock);
+	usb_stor_dbg(us, "      ATA Init Timeout: 0x%x\n",
+		     info->ConfigData.ATAInitTimeout);
+	usb_stor_dbg(us, "      ATAPI Command Block Size: 0x%x\n",
+		     (info->ConfigData.ATAConfig & ATACFG_BLOCKSIZE) >> 6);
+	usb_stor_dbg(us, "      Master/Slave Selection: 0x%x\n",
+		     info->ConfigData.ATAConfig & ATACFG_MASTER);
+	usb_stor_dbg(us, "      ATAPI Reset: 0x%x\n",
+		     info->ConfigData.ATAConfig & ATACFG_ATAPI_RESET);
+	usb_stor_dbg(us, "      ATA Timing: 0x%x\n",
+		     info->ConfigData.ATAConfig & ATACFG_TIMING);
+	usb_stor_dbg(us, "      ATA Major Command: 0x%x\n",
+		     info->ConfigData.ATAMajorCommand);
+	usb_stor_dbg(us, "      ATA Minor Command: 0x%x\n",
+		     info->ConfigData.ATAMinorCommand);
+	usb_stor_dbg(us, "      Init Status: 0x%x\n",
+		     info->ConfigData.ATAExtraConfig & ATACFGE_INIT_STATUS);
+	usb_stor_dbg(us, "      Config Descriptor 2: 0x%x\n",
+		     info->ConfigData.ATAExtraConfig & ATACFGE_CONF_DESC2);
+	usb_stor_dbg(us, "      Skip Device Boot: 0x%x\n",
+		     info->ConfigData.ATAExtraConfig & ATACFGE_SKIP_BOOT);
+	usb_stor_dbg(us, "      ATA 3 State Suspend: 0x%x\n",
+		     info->ConfigData.ATAExtraConfig & ATACFGE_STATE_SUSPEND);
+	usb_stor_dbg(us, "      Descriptor Override: 0x%x\n",
+		     info->ConfigData.ATAExtraConfig & ATACFGE_DESC_OVERRIDE);
+	usb_stor_dbg(us, "      Last LUN Identifier: 0x%x\n",
+		     info->ConfigData.ATAExtraConfig & ATACFGE_LAST_LUN);
+	usb_stor_dbg(us, "      SRST Enable: 0x%x\n",
+		     info->ConfigData.ATAExtraConfig & CFG_CAPABILITY_SRST);
+}
+#endif
+
+/**************************************************************************
+ * isd200_write_config
+ *									 
+ * Write the ISD200 Configuration data
+ *
+ * RETURNS:
+ *    ISD status code
+ */
+static int isd200_write_config( struct us_data *us ) 
+{
+	struct isd200_info *info = (struct isd200_info *)us->extra;
+	int retStatus = ISD200_GOOD;
+	int result;
+
+#ifdef CONFIG_USB_STORAGE_DEBUG
+	usb_stor_dbg(us, "Entering isd200_write_config\n");
+	usb_stor_dbg(us, "   Writing the following ISD200 Config Data:\n");
+	isd200_log_config(us, info);
+#endif
+
+	/* let's send the command via the control pipe */
+	result = usb_stor_ctrl_transfer(
+		us, 
+		us->send_ctrl_pipe,
+		0x01, 
+		USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+		0x0000, 
+		0x0002, 
+		(void *) &info->ConfigData, 
+		sizeof(info->ConfigData));
+
+	if (result >= 0) {
+		usb_stor_dbg(us, "   ISD200 Config Data was written successfully\n");
+	} else {
+		usb_stor_dbg(us, "   Request to write ISD200 Config Data failed!\n");
+		retStatus = ISD200_ERROR;
+	}
+
+	usb_stor_dbg(us, "Leaving isd200_write_config %08X\n", retStatus);
+	return retStatus;
+}
+
+
+/**************************************************************************
+ * isd200_read_config
+ *									 
+ * Reads the ISD200 Configuration data
+ *
+ * RETURNS:
+ *    ISD status code
+ */
+static int isd200_read_config( struct us_data *us ) 
+{
+	struct isd200_info *info = (struct isd200_info *)us->extra;
+	int retStatus = ISD200_GOOD;
+	int result;
+
+	usb_stor_dbg(us, "Entering isd200_read_config\n");
+
+	/* read the configuration information from ISD200.  Use this to */
+	/* determine what the special ATA CDB bytes are.		*/
+
+	result = usb_stor_ctrl_transfer(
+		us, 
+		us->recv_ctrl_pipe,
+		0x02, 
+		USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+		0x0000, 
+		0x0002, 
+		(void *) &info->ConfigData, 
+		sizeof(info->ConfigData));
+
+
+	if (result >= 0) {
+		usb_stor_dbg(us, "   Retrieved the following ISD200 Config Data:\n");
+#ifdef CONFIG_USB_STORAGE_DEBUG
+		isd200_log_config(us, info);
+#endif
+	} else {
+		usb_stor_dbg(us, "   Request to get ISD200 Config Data failed!\n");
+		retStatus = ISD200_ERROR;
+	}
+
+	usb_stor_dbg(us, "Leaving isd200_read_config %08X\n", retStatus);
+	return retStatus;
+}
+
+
+/**************************************************************************
+ * isd200_atapi_soft_reset
+ *									 
+ * Perform an Atapi Soft Reset on the device
+ *
+ * RETURNS:
+ *    NT status code
+ */
+static int isd200_atapi_soft_reset( struct us_data *us ) 
+{
+	int retStatus = ISD200_GOOD;
+	int transferStatus;
+
+	usb_stor_dbg(us, "Entering isd200_atapi_soft_reset\n");
+
+	transferStatus = isd200_action( us, ACTION_SOFT_RESET, NULL, 0 );
+	if (transferStatus != ISD200_TRANSPORT_GOOD) {
+		usb_stor_dbg(us, "   Error issuing Atapi Soft Reset\n");
+		retStatus = ISD200_ERROR;
+	}
+
+	usb_stor_dbg(us, "Leaving isd200_atapi_soft_reset %08X\n", retStatus);
+	return retStatus;
+}
+
+
+/**************************************************************************
+ * isd200_srst
+ *									 
+ * Perform an SRST on the device
+ *
+ * RETURNS:
+ *    ISD status code
+ */
+static int isd200_srst( struct us_data *us ) 
+{
+	int retStatus = ISD200_GOOD;
+	int transferStatus;
+
+	usb_stor_dbg(us, "Entering isd200_SRST\n");
+
+	transferStatus = isd200_action( us, ACTION_RESET, NULL, 0 );
+
+	/* check to see if this request failed */
+	if (transferStatus != ISD200_TRANSPORT_GOOD) {
+		usb_stor_dbg(us, "   Error issuing SRST\n");
+		retStatus = ISD200_ERROR;
+	} else {
+		/* delay 10ms to give the drive a chance to see it */
+		msleep(10);
+
+		transferStatus = isd200_action( us, ACTION_REENABLE, NULL, 0 );
+		if (transferStatus != ISD200_TRANSPORT_GOOD) {
+			usb_stor_dbg(us, "   Error taking drive out of reset\n");
+			retStatus = ISD200_ERROR;
+		} else {
+			/* delay 50ms to give the drive a chance to recover after SRST */
+			msleep(50);
+		}
+	}
+
+	usb_stor_dbg(us, "Leaving isd200_srst %08X\n", retStatus);
+	return retStatus;
+}
+
+
+/**************************************************************************
+ * isd200_try_enum
+ *									 
+ * Helper function for isd200_manual_enum(). Does ENUM and READ_STATUS
+ * and tries to analyze the status registers
+ *
+ * RETURNS:
+ *    ISD status code
+ */
+static int isd200_try_enum(struct us_data *us, unsigned char master_slave,
+			   int detect )
+{
+	int status = ISD200_GOOD;
+	unsigned long endTime;
+	struct isd200_info *info = (struct isd200_info *)us->extra;
+	unsigned char *regs = info->RegsBuf;
+	int recheckAsMaster = 0;
+
+	if ( detect )
+		endTime = jiffies + ISD200_ENUM_DETECT_TIMEOUT * HZ;
+	else
+		endTime = jiffies + ISD200_ENUM_BSY_TIMEOUT * HZ;
+
+	/* loop until we detect !BSY or timeout */
+	while(1) {
+
+		status = isd200_action( us, ACTION_ENUM, NULL, master_slave );
+		if ( status != ISD200_GOOD )
+			break;
+
+		status = isd200_action( us, ACTION_READ_STATUS, 
+					regs, 8 );
+		if ( status != ISD200_GOOD )
+			break;
+
+		if (!detect) {
+			if (regs[ATA_REG_STATUS_OFFSET] & ATA_BUSY) {
+				usb_stor_dbg(us, "   %s status is still BSY, try again...\n",
+					     master_slave == ATA_ADDRESS_DEVHEAD_STD ?
+					     "Master" : "Slave");
+			} else {
+				usb_stor_dbg(us, "   %s status !BSY, continue with next operation\n",
+					     master_slave == ATA_ADDRESS_DEVHEAD_STD ?
+					     "Master" : "Slave");
+				break;
+			}
+		}
+		/* check for ATA_BUSY and */
+		/* ATA_DF (workaround ATA Zip drive) and */
+		/* ATA_ERR (workaround for Archos CD-ROM) */
+		else if (regs[ATA_REG_STATUS_OFFSET] &
+			 (ATA_BUSY | ATA_DF | ATA_ERR)) {
+			usb_stor_dbg(us, "   Status indicates it is not ready, try again...\n");
+		}
+		/* check for DRDY, ATA devices set DRDY after SRST */
+		else if (regs[ATA_REG_STATUS_OFFSET] & ATA_DRDY) {
+			usb_stor_dbg(us, "   Identified ATA device\n");
+			info->DeviceFlags |= DF_ATA_DEVICE;
+			info->DeviceHead = master_slave;
+			break;
+		} 
+		/*
+		 * check Cylinder High/Low to
+		 * determine if it is an ATAPI device
+		 */
+		else if (regs[ATA_REG_HCYL_OFFSET] == 0xEB &&
+			 regs[ATA_REG_LCYL_OFFSET] == 0x14) {
+			/*
+			 * It seems that the RICOH
+			 * MP6200A CD/RW drive will
+			 * report itself okay as a
+			 * slave when it is really a
+			 * master. So this check again
+			 * as a master device just to
+			 * make sure it doesn't report
+			 * itself okay as a master also
+			 */
+			if ((master_slave & ATA_ADDRESS_DEVHEAD_SLAVE) &&
+			    !recheckAsMaster) {
+				usb_stor_dbg(us, "   Identified ATAPI device as slave.  Rechecking again as master\n");
+				recheckAsMaster = 1;
+				master_slave = ATA_ADDRESS_DEVHEAD_STD;
+			} else {
+				usb_stor_dbg(us, "   Identified ATAPI device\n");
+				info->DeviceHead = master_slave;
+			      
+				status = isd200_atapi_soft_reset(us);
+				break;
+			}
+		} else {
+			usb_stor_dbg(us, "   Not ATA, not ATAPI - Weird\n");
+			break;
+		}
+
+		/* check for timeout on this request */
+		if (time_after_eq(jiffies, endTime)) {
+			if (!detect)
+				usb_stor_dbg(us, "   BSY check timeout, just continue with next operation...\n");
+			else
+				usb_stor_dbg(us, "   Device detect timeout!\n");
+			break;
+		}
+	}
+
+	return status;
+}
+
+/**************************************************************************
+ * isd200_manual_enum
+ *									 
+ * Determines if the drive attached is an ATA or ATAPI and if it is a
+ * master or slave.
+ *
+ * RETURNS:
+ *    ISD status code
+ */
+static int isd200_manual_enum(struct us_data *us)
+{
+	struct isd200_info *info = (struct isd200_info *)us->extra;
+	int retStatus = ISD200_GOOD;
+
+	usb_stor_dbg(us, "Entering isd200_manual_enum\n");
+
+	retStatus = isd200_read_config(us);
+	if (retStatus == ISD200_GOOD) {
+		int isslave;
+		/* master or slave? */
+		retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_STD, 0);
+		if (retStatus == ISD200_GOOD)
+			retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_SLAVE, 0);
+
+		if (retStatus == ISD200_GOOD) {
+			retStatus = isd200_srst(us);
+			if (retStatus == ISD200_GOOD)
+				/* ata or atapi? */
+				retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_STD, 1);
+		}
+
+		isslave = (info->DeviceHead & ATA_ADDRESS_DEVHEAD_SLAVE) ? 1 : 0;
+		if (!(info->ConfigData.ATAConfig & ATACFG_MASTER)) {
+			usb_stor_dbg(us, "   Setting Master/Slave selection to %d\n",
+				     isslave);
+			info->ConfigData.ATAConfig &= 0x3f;
+			info->ConfigData.ATAConfig |= (isslave<<6);
+			retStatus = isd200_write_config(us);
+		}
+	}
+
+	usb_stor_dbg(us, "Leaving isd200_manual_enum %08X\n", retStatus);
+	return(retStatus);
+}
+
+static void isd200_fix_driveid(u16 *id)
+{
+#ifndef __LITTLE_ENDIAN
+# ifdef __BIG_ENDIAN
+	int i;
+
+	for (i = 0; i < ATA_ID_WORDS; i++)
+		id[i] = __le16_to_cpu(id[i]);
+# else
+#  error "Please fix <asm/byteorder.h>"
+# endif
+#endif
+}
+
+static void isd200_dump_driveid(struct us_data *us, u16 *id)
+{
+	usb_stor_dbg(us, "   Identify Data Structure:\n");
+	usb_stor_dbg(us, "      config = 0x%x\n",	id[ATA_ID_CONFIG]);
+	usb_stor_dbg(us, "      cyls = 0x%x\n",		id[ATA_ID_CYLS]);
+	usb_stor_dbg(us, "      heads = 0x%x\n",	id[ATA_ID_HEADS]);
+	usb_stor_dbg(us, "      track_bytes = 0x%x\n",	id[4]);
+	usb_stor_dbg(us, "      sector_bytes = 0x%x\n", id[5]);
+	usb_stor_dbg(us, "      sectors = 0x%x\n",	id[ATA_ID_SECTORS]);
+	usb_stor_dbg(us, "      serial_no[0] = 0x%x\n", *(char *)&id[ATA_ID_SERNO]);
+	usb_stor_dbg(us, "      buf_type = 0x%x\n",	id[20]);
+	usb_stor_dbg(us, "      buf_size = 0x%x\n",	id[ATA_ID_BUF_SIZE]);
+	usb_stor_dbg(us, "      ecc_bytes = 0x%x\n",	id[22]);
+	usb_stor_dbg(us, "      fw_rev[0] = 0x%x\n",	*(char *)&id[ATA_ID_FW_REV]);
+	usb_stor_dbg(us, "      model[0] = 0x%x\n",	*(char *)&id[ATA_ID_PROD]);
+	usb_stor_dbg(us, "      max_multsect = 0x%x\n", id[ATA_ID_MAX_MULTSECT] & 0xff);
+	usb_stor_dbg(us, "      dword_io = 0x%x\n",	id[ATA_ID_DWORD_IO]);
+	usb_stor_dbg(us, "      capability = 0x%x\n",	id[ATA_ID_CAPABILITY] >> 8);
+	usb_stor_dbg(us, "      tPIO = 0x%x\n",	  id[ATA_ID_OLD_PIO_MODES] >> 8);
+	usb_stor_dbg(us, "      tDMA = 0x%x\n",	  id[ATA_ID_OLD_DMA_MODES] >> 8);
+	usb_stor_dbg(us, "      field_valid = 0x%x\n",	id[ATA_ID_FIELD_VALID]);
+	usb_stor_dbg(us, "      cur_cyls = 0x%x\n",	id[ATA_ID_CUR_CYLS]);
+	usb_stor_dbg(us, "      cur_heads = 0x%x\n",	id[ATA_ID_CUR_HEADS]);
+	usb_stor_dbg(us, "      cur_sectors = 0x%x\n",	id[ATA_ID_CUR_SECTORS]);
+	usb_stor_dbg(us, "      cur_capacity = 0x%x\n", ata_id_u32(id, 57));
+	usb_stor_dbg(us, "      multsect = 0x%x\n",	id[ATA_ID_MULTSECT] & 0xff);
+	usb_stor_dbg(us, "      lba_capacity = 0x%x\n", ata_id_u32(id, ATA_ID_LBA_CAPACITY));
+	usb_stor_dbg(us, "      command_set_1 = 0x%x\n", id[ATA_ID_COMMAND_SET_1]);
+	usb_stor_dbg(us, "      command_set_2 = 0x%x\n", id[ATA_ID_COMMAND_SET_2]);
+}
+
+/**************************************************************************
+ * isd200_get_inquiry_data
+ *
+ * Get inquiry data
+ *
+ * RETURNS:
+ *    ISD status code
+ */
+static int isd200_get_inquiry_data( struct us_data *us )
+{
+	struct isd200_info *info = (struct isd200_info *)us->extra;
+	int retStatus = ISD200_GOOD;
+	u16 *id = info->id;
+
+	usb_stor_dbg(us, "Entering isd200_get_inquiry_data\n");
+
+	/* set default to Master */
+	info->DeviceHead = ATA_ADDRESS_DEVHEAD_STD;
+
+	/* attempt to manually enumerate this device */
+	retStatus = isd200_manual_enum(us);
+	if (retStatus == ISD200_GOOD) {
+		int transferStatus;
+
+		/* check for an ATA device */
+		if (info->DeviceFlags & DF_ATA_DEVICE) {
+			/* this must be an ATA device */
+			/* perform an ATA Command Identify */
+			transferStatus = isd200_action( us, ACTION_IDENTIFY,
+							id, ATA_ID_WORDS * 2);
+			if (transferStatus != ISD200_TRANSPORT_GOOD) {
+				/* Error issuing ATA Command Identify */
+				usb_stor_dbg(us, "   Error issuing ATA Command Identify\n");
+				retStatus = ISD200_ERROR;
+			} else {
+				/* ATA Command Identify successful */
+				int i;
+				__be16 *src;
+				__u16 *dest;
+
+				isd200_fix_driveid(id);
+				isd200_dump_driveid(us, id);
+
+				memset(&info->InquiryData, 0, sizeof(info->InquiryData));
+
+				/* Standard IDE interface only supports disks */
+				info->InquiryData.DeviceType = DIRECT_ACCESS_DEVICE;
+
+				/* The length must be at least 36 (5 + 31) */
+				info->InquiryData.AdditionalLength = 0x1F;
+
+				if (id[ATA_ID_COMMAND_SET_1] & COMMANDSET_MEDIA_STATUS) {
+					/* set the removable bit */
+					info->InquiryData.DeviceTypeModifier = DEVICE_REMOVABLE;
+					info->DeviceFlags |= DF_REMOVABLE_MEDIA;
+				}
+
+				/* Fill in vendor identification fields */
+				src = (__be16 *)&id[ATA_ID_PROD];
+				dest = (__u16*)info->InquiryData.VendorId;
+				for (i=0;i<4;i++)
+					dest[i] = be16_to_cpu(src[i]);
+
+				src = (__be16 *)&id[ATA_ID_PROD + 8/2];
+				dest = (__u16*)info->InquiryData.ProductId;
+				for (i=0;i<8;i++)
+					dest[i] = be16_to_cpu(src[i]);
+
+				src = (__be16 *)&id[ATA_ID_FW_REV];
+				dest = (__u16*)info->InquiryData.ProductRevisionLevel;
+				for (i=0;i<2;i++)
+					dest[i] = be16_to_cpu(src[i]);
+
+				/* determine if it supports Media Status Notification */
+				if (id[ATA_ID_COMMAND_SET_2] & COMMANDSET_MEDIA_STATUS) {
+					usb_stor_dbg(us, "   Device supports Media Status Notification\n");
+
+					/*
+					 * Indicate that it is enabled, even
+					 * though it is not.
+					 * This allows the lock/unlock of the
+					 * media to work correctly.
+					 */
+					info->DeviceFlags |= DF_MEDIA_STATUS_ENABLED;
+				}
+				else
+					info->DeviceFlags &= ~DF_MEDIA_STATUS_ENABLED;
+
+			}
+		} else {
+			/* 
+			 * this must be an ATAPI device 
+			 * use an ATAPI protocol (Transparent SCSI)
+			 */
+			us->protocol_name = "Transparent SCSI";
+			us->proto_handler = usb_stor_transparent_scsi_command;
+
+			usb_stor_dbg(us, "Protocol changed to: %s\n",
+				     us->protocol_name);
+	    
+			/* Free driver structure */
+			us->extra_destructor(info);
+			kfree(info);
+			us->extra = NULL;
+			us->extra_destructor = NULL;
+		}
+	}
+
+	usb_stor_dbg(us, "Leaving isd200_get_inquiry_data %08X\n", retStatus);
+
+	return(retStatus);
+}
+
+/**************************************************************************
+ * isd200_scsi_to_ata
+ *									 
+ * Translate SCSI commands to ATA commands.
+ *
+ * RETURNS:
+ *    1 if the command needs to be sent to the transport layer
+ *    0 otherwise
+ */
+static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
+			      union ata_cdb * ataCdb)
+{
+	struct isd200_info *info = (struct isd200_info *)us->extra;
+	u16 *id = info->id;
+	int sendToTransport = 1;
+	unsigned char sectnum, head;
+	unsigned short cylinder;
+	unsigned long lba;
+	unsigned long blockCount;
+	unsigned char senseData[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+	memset(ataCdb, 0, sizeof(union ata_cdb));
+
+	/* SCSI Command */
+	switch (srb->cmnd[0]) {
+	case INQUIRY:
+		usb_stor_dbg(us, "   ATA OUT - INQUIRY\n");
+
+		/* copy InquiryData */
+		usb_stor_set_xfer_buf((unsigned char *) &info->InquiryData,
+				sizeof(info->InquiryData), srb);
+		srb->result = SAM_STAT_GOOD;
+		sendToTransport = 0;
+		break;
+
+	case MODE_SENSE:
+		usb_stor_dbg(us, "   ATA OUT - SCSIOP_MODE_SENSE\n");
+
+		/* Initialize the return buffer */
+		usb_stor_set_xfer_buf(senseData, sizeof(senseData), srb);
+
+		if (info->DeviceFlags & DF_MEDIA_STATUS_ENABLED)
+		{
+			ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
+			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
+			ataCdb->generic.TransferBlockSize = 1;
+			ataCdb->generic.RegisterSelect = REG_COMMAND;
+			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
+			isd200_srb_set_bufflen(srb, 0);
+		} else {
+			usb_stor_dbg(us, "   Media Status not supported, just report okay\n");
+			srb->result = SAM_STAT_GOOD;
+			sendToTransport = 0;
+		}
+		break;
+
+	case TEST_UNIT_READY:
+		usb_stor_dbg(us, "   ATA OUT - SCSIOP_TEST_UNIT_READY\n");
+
+		if (info->DeviceFlags & DF_MEDIA_STATUS_ENABLED)
+		{
+			ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
+			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
+			ataCdb->generic.TransferBlockSize = 1;
+			ataCdb->generic.RegisterSelect = REG_COMMAND;
+			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
+			isd200_srb_set_bufflen(srb, 0);
+		} else {
+			usb_stor_dbg(us, "   Media Status not supported, just report okay\n");
+			srb->result = SAM_STAT_GOOD;
+			sendToTransport = 0;
+		}
+		break;
+
+	case READ_CAPACITY:
+	{
+		unsigned long capacity;
+		struct read_capacity_data readCapacityData;
+
+		usb_stor_dbg(us, "   ATA OUT - SCSIOP_READ_CAPACITY\n");
+
+		if (ata_id_has_lba(id))
+			capacity = ata_id_u32(id, ATA_ID_LBA_CAPACITY) - 1;
+		else
+			capacity = (id[ATA_ID_HEADS] * id[ATA_ID_CYLS] *
+				    id[ATA_ID_SECTORS]) - 1;
+
+		readCapacityData.LogicalBlockAddress = cpu_to_be32(capacity);
+		readCapacityData.BytesPerBlock = cpu_to_be32(0x200);
+
+		usb_stor_set_xfer_buf((unsigned char *) &readCapacityData,
+				sizeof(readCapacityData), srb);
+		srb->result = SAM_STAT_GOOD;
+		sendToTransport = 0;
+	}
+	break;
+
+	case READ_10:
+		usb_stor_dbg(us, "   ATA OUT - SCSIOP_READ\n");
+
+		lba = be32_to_cpu(*(__be32 *)&srb->cmnd[2]);
+		blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8];
+
+		if (ata_id_has_lba(id)) {
+			sectnum = (unsigned char)(lba);
+			cylinder = (unsigned short)(lba>>8);
+			head = ATA_ADDRESS_DEVHEAD_LBA_MODE | (unsigned char)(lba>>24 & 0x0F);
+		} else {
+			sectnum = (u8)((lba % id[ATA_ID_SECTORS]) + 1);
+			cylinder = (u16)(lba / (id[ATA_ID_SECTORS] *
+					id[ATA_ID_HEADS]));
+			head = (u8)((lba / id[ATA_ID_SECTORS]) %
+					id[ATA_ID_HEADS]);
+		}
+		ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
+		ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
+		ataCdb->generic.TransferBlockSize = 1;
+		ataCdb->generic.RegisterSelect =
+		  REG_SECTOR_COUNT | REG_SECTOR_NUMBER |
+		  REG_CYLINDER_LOW | REG_CYLINDER_HIGH |
+		  REG_DEVICE_HEAD  | REG_COMMAND;
+		ataCdb->write.SectorCountByte = (unsigned char)blockCount;
+		ataCdb->write.SectorNumberByte = sectnum;
+		ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8);
+		ataCdb->write.CylinderLowByte = (unsigned char)cylinder;
+		ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD);
+		ataCdb->write.CommandByte = ATA_CMD_PIO_READ;
+		break;
+
+	case WRITE_10:
+		usb_stor_dbg(us, "   ATA OUT - SCSIOP_WRITE\n");
+
+		lba = be32_to_cpu(*(__be32 *)&srb->cmnd[2]);
+		blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8];
+
+		if (ata_id_has_lba(id)) {
+			sectnum = (unsigned char)(lba);
+			cylinder = (unsigned short)(lba>>8);
+			head = ATA_ADDRESS_DEVHEAD_LBA_MODE | (unsigned char)(lba>>24 & 0x0F);
+		} else {
+			sectnum = (u8)((lba % id[ATA_ID_SECTORS]) + 1);
+			cylinder = (u16)(lba / (id[ATA_ID_SECTORS] *
+					id[ATA_ID_HEADS]));
+			head = (u8)((lba / id[ATA_ID_SECTORS]) %
+					id[ATA_ID_HEADS]);
+		}
+		ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
+		ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
+		ataCdb->generic.TransferBlockSize = 1;
+		ataCdb->generic.RegisterSelect =
+		  REG_SECTOR_COUNT | REG_SECTOR_NUMBER |
+		  REG_CYLINDER_LOW | REG_CYLINDER_HIGH |
+		  REG_DEVICE_HEAD  | REG_COMMAND;
+		ataCdb->write.SectorCountByte = (unsigned char)blockCount;
+		ataCdb->write.SectorNumberByte = sectnum;
+		ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8);
+		ataCdb->write.CylinderLowByte = (unsigned char)cylinder;
+		ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD);
+		ataCdb->write.CommandByte = ATA_CMD_PIO_WRITE;
+		break;
+
+	case ALLOW_MEDIUM_REMOVAL:
+		usb_stor_dbg(us, "   ATA OUT - SCSIOP_MEDIUM_REMOVAL\n");
+
+		if (info->DeviceFlags & DF_REMOVABLE_MEDIA) {
+			usb_stor_dbg(us, "   srb->cmnd[4] = 0x%X\n",
+				     srb->cmnd[4]);
+	    
+			ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
+			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
+			ataCdb->generic.TransferBlockSize = 1;
+			ataCdb->generic.RegisterSelect = REG_COMMAND;
+			ataCdb->write.CommandByte = (srb->cmnd[4] & 0x1) ?
+				ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK;
+			isd200_srb_set_bufflen(srb, 0);
+		} else {
+			usb_stor_dbg(us, "   Not removeable media, just report okay\n");
+			srb->result = SAM_STAT_GOOD;
+			sendToTransport = 0;
+		}
+		break;
+
+	case START_STOP:    
+		usb_stor_dbg(us, "   ATA OUT - SCSIOP_START_STOP_UNIT\n");
+		usb_stor_dbg(us, "   srb->cmnd[4] = 0x%X\n", srb->cmnd[4]);
+
+		if ((srb->cmnd[4] & 0x3) == 0x2) {
+			usb_stor_dbg(us, "   Media Eject\n");
+			ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
+			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
+			ataCdb->generic.TransferBlockSize = 0;
+			ataCdb->generic.RegisterSelect = REG_COMMAND;
+			ataCdb->write.CommandByte = ATA_COMMAND_MEDIA_EJECT;
+		} else if ((srb->cmnd[4] & 0x3) == 0x1) {
+			usb_stor_dbg(us, "   Get Media Status\n");
+			ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
+			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
+			ataCdb->generic.TransferBlockSize = 1;
+			ataCdb->generic.RegisterSelect = REG_COMMAND;
+			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
+			isd200_srb_set_bufflen(srb, 0);
+		} else {
+			usb_stor_dbg(us, "   Nothing to do, just report okay\n");
+			srb->result = SAM_STAT_GOOD;
+			sendToTransport = 0;
+		}
+		break;
+
+	default:
+		usb_stor_dbg(us, "Unsupported SCSI command - 0x%X\n",
+			     srb->cmnd[0]);
+		srb->result = DID_ERROR << 16;
+		sendToTransport = 0;
+		break;
+	}
+
+	return(sendToTransport);
+}
+
+
+/**************************************************************************
+ * isd200_free_info
+ *
+ * Frees the driver structure.
+ */
+static void isd200_free_info_ptrs(void *info_)
+{
+	struct isd200_info *info = (struct isd200_info *) info_;
+
+	if (info) {
+		kfree(info->id);
+		kfree(info->RegsBuf);
+		kfree(info->srb.sense_buffer);
+	}
+}
+
+/**************************************************************************
+ * isd200_init_info
+ *									 
+ * Allocates (if necessary) and initializes the driver structure.
+ *
+ * RETURNS:
+ *    ISD status code
+ */
+static int isd200_init_info(struct us_data *us)
+{
+	struct isd200_info *info;
+
+	info = kzalloc(sizeof(struct isd200_info), GFP_KERNEL);
+	if (!info)
+		return ISD200_ERROR;
+
+	info->id = kzalloc(ATA_ID_WORDS * 2, GFP_KERNEL);
+	info->RegsBuf = kmalloc(sizeof(info->ATARegs), GFP_KERNEL);
+	info->srb.sense_buffer = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL);
+
+	if (!info->id || !info->RegsBuf || !info->srb.sense_buffer) {
+		isd200_free_info_ptrs(info);
+		kfree(info);
+		return ISD200_ERROR;
+	}
+
+	us->extra = info;
+	us->extra_destructor = isd200_free_info_ptrs;
+
+	return ISD200_GOOD;
+}
+
+/**************************************************************************
+ * Initialization for the ISD200 
+ */
+
+static int isd200_Initialization(struct us_data *us)
+{
+	usb_stor_dbg(us, "ISD200 Initialization...\n");
+
+	/* Initialize ISD200 info struct */
+
+	if (isd200_init_info(us) == ISD200_ERROR) {
+		usb_stor_dbg(us, "ERROR Initializing ISD200 Info struct\n");
+	} else {
+		/* Get device specific data */
+
+		if (isd200_get_inquiry_data(us) != ISD200_GOOD)
+			usb_stor_dbg(us, "ISD200 Initialization Failure\n");
+		else
+			usb_stor_dbg(us, "ISD200 Initialization complete\n");
+	}
+
+	return 0;
+}
+
+
+/**************************************************************************
+ * Protocol and Transport for the ISD200 ASIC
+ *
+ * This protocol and transport are for ATA devices connected to an ISD200
+ * ASIC.  An ATAPI device that is connected as a slave device will be
+ * detected in the driver initialization function and the protocol will
+ * be changed to an ATAPI protocol (Transparent SCSI).
+ *
+ */
+
+static void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us)
+{
+	int sendToTransport = 1, orig_bufflen;
+	union ata_cdb ataCdb;
+
+	/* Make sure driver was initialized */
+
+	if (us->extra == NULL) {
+		usb_stor_dbg(us, "ERROR Driver not initialized\n");
+		srb->result = DID_ERROR << 16;
+		return;
+	}
+
+	scsi_set_resid(srb, 0);
+	/* scsi_bufflen might change in protocol translation to ata */
+	orig_bufflen = scsi_bufflen(srb);
+	sendToTransport = isd200_scsi_to_ata(srb, us, &ataCdb);
+
+	/* send the command to the transport layer */
+	if (sendToTransport)
+		isd200_invoke_transport(us, srb, &ataCdb);
+
+	isd200_srb_set_bufflen(srb, orig_bufflen);
+}
+
+static struct scsi_host_template isd200_host_template;
+
+static int isd200_probe(struct usb_interface *intf,
+			 const struct usb_device_id *id)
+{
+	struct us_data *us;
+	int result;
+
+	result = usb_stor_probe1(&us, intf, id,
+			(id - isd200_usb_ids) + isd200_unusual_dev_list,
+			&isd200_host_template);
+	if (result)
+		return result;
+
+	us->protocol_name = "ISD200 ATA/ATAPI";
+	us->proto_handler = isd200_ata_command;
+
+	result = usb_stor_probe2(us);
+	return result;
+}
+
+static struct usb_driver isd200_driver = {
+	.name =		DRV_NAME,
+	.probe =	isd200_probe,
+	.disconnect =	usb_stor_disconnect,
+	.suspend =	usb_stor_suspend,
+	.resume =	usb_stor_resume,
+	.reset_resume =	usb_stor_reset_resume,
+	.pre_reset =	usb_stor_pre_reset,
+	.post_reset =	usb_stor_post_reset,
+	.id_table =	isd200_usb_ids,
+	.soft_unbind =	1,
+	.no_dynamic_id = 1,
+};
+
+module_usb_stor_driver(isd200_driver, isd200_host_template, DRV_NAME);
diff --git a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c
new file mode 100644
index 0000000..917f170
--- /dev/null
+++ b/drivers/usb/storage/jumpshot.c
@@ -0,0 +1,682 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for Lexar "Jumpshot" Compact Flash reader
+ *
+ * jumpshot driver v0.1:
+ *
+ * First release
+ *
+ * Current development and maintenance by:
+ *   (c) 2000 Jimmie Mayfield (mayfield+usb@sackheads.org)
+ *
+ *   Many thanks to Robert Baruch for the SanDisk SmartMedia reader driver
+ *   which I used as a template for this driver.
+ *
+ *   Some bugfixes and scatter-gather code by Gregory P. Smith 
+ *   (greg-usb@electricrain.com)
+ *
+ *   Fix for media change by Joerg Schneider (js@joergschneider.com)
+ *
+ * Developed with the assistance of:
+ *
+ *   (C) 2002 Alan Stern <stern@rowland.org>
+ */
+ 
+ /*
+  * This driver attempts to support the Lexar Jumpshot USB CompactFlash 
+  * reader.  Like many other USB CompactFlash readers, the Jumpshot contains
+  * a USB-to-ATA chip. 
+  *
+  * This driver supports reading and writing.  If you're truly paranoid,
+  * however, you can force the driver into a write-protected state by setting
+  * the WP enable bits in jumpshot_handle_mode_sense.  See the comments
+  * in that routine.
+  */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "protocol.h"
+#include "debug.h"
+#include "scsiglue.h"
+
+#define DRV_NAME "ums-jumpshot"
+
+MODULE_DESCRIPTION("Driver for Lexar \"Jumpshot\" Compact Flash reader");
+MODULE_AUTHOR("Jimmie Mayfield <mayfield+usb@sackheads.org>");
+MODULE_LICENSE("GPL");
+
+/*
+ * The table of devices
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+		    vendorName, productName, useProtocol, useTransport, \
+		    initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+  .driver_info = (flags) }
+
+static struct usb_device_id jumpshot_usb_ids[] = {
+#	include "unusual_jumpshot.h"
+	{ }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, jumpshot_usb_ids);
+
+#undef UNUSUAL_DEV
+
+/*
+ * The flags table
+ */
+#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
+		    vendor_name, product_name, use_protocol, use_transport, \
+		    init_function, Flags) \
+{ \
+	.vendorName = vendor_name,	\
+	.productName = product_name,	\
+	.useProtocol = use_protocol,	\
+	.useTransport = use_transport,	\
+	.initFunction = init_function,	\
+}
+
+static struct us_unusual_dev jumpshot_unusual_dev_list[] = {
+#	include "unusual_jumpshot.h"
+	{ }		/* Terminating entry */
+};
+
+#undef UNUSUAL_DEV
+
+
+struct jumpshot_info {
+   unsigned long   sectors;     /* total sector count */
+   unsigned long   ssize;       /* sector size in bytes */
+
+   /* the following aren't used yet */
+   unsigned char   sense_key;
+   unsigned long   sense_asc;   /* additional sense code */
+   unsigned long   sense_ascq;  /* additional sense code qualifier */
+};
+
+static inline int jumpshot_bulk_read(struct us_data *us,
+				     unsigned char *data, 
+				     unsigned int len)
+{
+	if (len == 0)
+		return USB_STOR_XFER_GOOD;
+
+	usb_stor_dbg(us, "len = %d\n", len);
+	return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+			data, len, NULL);
+}
+
+
+static inline int jumpshot_bulk_write(struct us_data *us,
+				      unsigned char *data, 
+				      unsigned int len)
+{
+	if (len == 0)
+		return USB_STOR_XFER_GOOD;
+
+	usb_stor_dbg(us, "len = %d\n", len);
+	return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+			data, len, NULL);
+}
+
+
+static int jumpshot_get_status(struct us_data  *us)
+{
+	int rc;
+
+	if (!us)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	// send the setup
+	rc = usb_stor_ctrl_transfer(us, us->recv_ctrl_pipe,
+				   0, 0xA0, 0, 7, us->iobuf, 1);
+
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	if (us->iobuf[0] != 0x50) {
+		usb_stor_dbg(us, "0x%2x\n", us->iobuf[0]);
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int jumpshot_read_data(struct us_data *us,
+			      struct jumpshot_info *info,
+			      u32 sector,
+			      u32 sectors)
+{
+	unsigned char *command = us->iobuf;
+	unsigned char *buffer;
+	unsigned char  thistime;
+	unsigned int totallen, alloclen;
+	int len, result;
+	unsigned int sg_offset = 0;
+	struct scatterlist *sg = NULL;
+
+	// we're working in LBA mode.  according to the ATA spec, 
+	// we can support up to 28-bit addressing.  I don't know if Jumpshot
+	// supports beyond 24-bit addressing.  It's kind of hard to test 
+	// since it requires > 8GB CF card.
+
+	if (sector > 0x0FFFFFFF)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	totallen = sectors * info->ssize;
+
+	// Since we don't read more than 64 KB at a time, we have to create
+	// a bounce buffer and move the data a piece at a time between the
+	// bounce buffer and the actual transfer buffer.
+
+	alloclen = min(totallen, 65536u);
+	buffer = kmalloc(alloclen, GFP_NOIO);
+	if (buffer == NULL)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	do {
+		// loop, never allocate or transfer more than 64k at once
+		// (min(128k, 255*info->ssize) is the real limit)
+		len = min(totallen, alloclen);
+		thistime = (len / info->ssize) & 0xff;
+
+		command[0] = 0;
+		command[1] = thistime;
+		command[2] = sector & 0xFF;
+		command[3] = (sector >>  8) & 0xFF;
+		command[4] = (sector >> 16) & 0xFF;
+
+		command[5] = 0xE0 | ((sector >> 24) & 0x0F);
+		command[6] = 0x20;
+
+		// send the setup + command
+		result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
+					       0, 0x20, 0, 1, command, 7);
+		if (result != USB_STOR_XFER_GOOD)
+			goto leave;
+
+		// read the result
+		result = jumpshot_bulk_read(us, buffer, len);
+		if (result != USB_STOR_XFER_GOOD)
+			goto leave;
+
+		usb_stor_dbg(us, "%d bytes\n", len);
+
+		// Store the data in the transfer buffer
+		usb_stor_access_xfer_buf(buffer, len, us->srb,
+				 &sg, &sg_offset, TO_XFER_BUF);
+
+		sector += thistime;
+		totallen -= len;
+	} while (totallen > 0);
+
+	kfree(buffer);
+	return USB_STOR_TRANSPORT_GOOD;
+
+ leave:
+	kfree(buffer);
+	return USB_STOR_TRANSPORT_ERROR;
+}
+
+
+static int jumpshot_write_data(struct us_data *us,
+			       struct jumpshot_info *info,
+			       u32 sector,
+			       u32 sectors)
+{
+	unsigned char *command = us->iobuf;
+	unsigned char *buffer;
+	unsigned char  thistime;
+	unsigned int totallen, alloclen;
+	int len, result, waitcount;
+	unsigned int sg_offset = 0;
+	struct scatterlist *sg = NULL;
+
+	// we're working in LBA mode.  according to the ATA spec, 
+	// we can support up to 28-bit addressing.  I don't know if Jumpshot
+	// supports beyond 24-bit addressing.  It's kind of hard to test 
+	// since it requires > 8GB CF card.
+	//
+	if (sector > 0x0FFFFFFF)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	totallen = sectors * info->ssize;
+
+	// Since we don't write more than 64 KB at a time, we have to create
+	// a bounce buffer and move the data a piece at a time between the
+	// bounce buffer and the actual transfer buffer.
+
+	alloclen = min(totallen, 65536u);
+	buffer = kmalloc(alloclen, GFP_NOIO);
+	if (buffer == NULL)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	do {
+		// loop, never allocate or transfer more than 64k at once
+		// (min(128k, 255*info->ssize) is the real limit)
+
+		len = min(totallen, alloclen);
+		thistime = (len / info->ssize) & 0xff;
+
+		// Get the data from the transfer buffer
+		usb_stor_access_xfer_buf(buffer, len, us->srb,
+				&sg, &sg_offset, FROM_XFER_BUF);
+
+		command[0] = 0;
+		command[1] = thistime;
+		command[2] = sector & 0xFF;
+		command[3] = (sector >>  8) & 0xFF;
+		command[4] = (sector >> 16) & 0xFF;
+
+		command[5] = 0xE0 | ((sector >> 24) & 0x0F);
+		command[6] = 0x30;
+
+		// send the setup + command
+		result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
+			0, 0x20, 0, 1, command, 7);
+		if (result != USB_STOR_XFER_GOOD)
+			goto leave;
+
+		// send the data
+		result = jumpshot_bulk_write(us, buffer, len);
+		if (result != USB_STOR_XFER_GOOD)
+			goto leave;
+
+		// read the result.  apparently the bulk write can complete
+		// before the jumpshot drive is finished writing.  so we loop
+		// here until we get a good return code
+		waitcount = 0;
+		do {
+			result = jumpshot_get_status(us);
+			if (result != USB_STOR_TRANSPORT_GOOD) {
+				// I have not experimented to find the smallest value.
+				//
+				msleep(50); 
+			}
+		} while ((result != USB_STOR_TRANSPORT_GOOD) && (waitcount < 10));
+
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			usb_stor_dbg(us, "Gah!  Waitcount = 10.  Bad write!?\n");
+
+		sector += thistime;
+		totallen -= len;
+	} while (totallen > 0);
+
+	kfree(buffer);
+	return result;
+
+ leave:
+	kfree(buffer);
+	return USB_STOR_TRANSPORT_ERROR;
+}
+
+static int jumpshot_id_device(struct us_data *us,
+			      struct jumpshot_info *info)
+{
+	unsigned char *command = us->iobuf;
+	unsigned char *reply;
+	int 	 rc;
+
+	if (!info)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	command[0] = 0xE0;
+	command[1] = 0xEC;
+	reply = kmalloc(512, GFP_NOIO);
+	if (!reply)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	// send the setup
+	rc = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
+				   0, 0x20, 0, 6, command, 2);
+
+	if (rc != USB_STOR_XFER_GOOD) {
+		usb_stor_dbg(us, "Gah! send_control for read_capacity failed\n");
+		rc = USB_STOR_TRANSPORT_ERROR;
+		goto leave;
+	}
+
+	// read the reply
+	rc = jumpshot_bulk_read(us, reply, 512);
+	if (rc != USB_STOR_XFER_GOOD) {
+		rc = USB_STOR_TRANSPORT_ERROR;
+		goto leave;
+	}
+
+	info->sectors = ((u32)(reply[117]) << 24) |
+			((u32)(reply[116]) << 16) |
+			((u32)(reply[115]) <<  8) |
+			((u32)(reply[114])      );
+
+	rc = USB_STOR_TRANSPORT_GOOD;
+
+ leave:
+	kfree(reply);
+	return rc;
+}
+
+static int jumpshot_handle_mode_sense(struct us_data *us,
+				      struct scsi_cmnd * srb, 
+				      int sense_6)
+{
+	static unsigned char rw_err_page[12] = {
+		0x1, 0xA, 0x21, 1, 0, 0, 0, 0, 1, 0, 0, 0
+	};
+	static unsigned char cache_page[12] = {
+		0x8, 0xA, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0
+	};
+	static unsigned char rbac_page[12] = {
+		0x1B, 0xA, 0, 0x81, 0, 0, 0, 0, 0, 0, 0, 0
+	};
+	static unsigned char timer_page[8] = {
+		0x1C, 0x6, 0, 0, 0, 0
+	};
+	unsigned char pc, page_code;
+	unsigned int i = 0;
+	struct jumpshot_info *info = (struct jumpshot_info *) (us->extra);
+	unsigned char *ptr = us->iobuf;
+
+	pc = srb->cmnd[2] >> 6;
+	page_code = srb->cmnd[2] & 0x3F;
+
+	switch (pc) {
+	   case 0x0:
+		   usb_stor_dbg(us, "Current values\n");
+		   break;
+	   case 0x1:
+		   usb_stor_dbg(us, "Changeable values\n");
+		   break;
+	   case 0x2:
+		   usb_stor_dbg(us, "Default values\n");
+		   break;
+	   case 0x3:
+		   usb_stor_dbg(us, "Saves values\n");
+		   break;
+	}
+
+	memset(ptr, 0, 8);
+	if (sense_6) {
+		ptr[2] = 0x00;		// WP enable: 0x80
+		i = 4;
+	} else {
+		ptr[3] = 0x00;		// WP enable: 0x80
+		i = 8;
+	}
+
+	switch (page_code) {
+	   case 0x0:
+		// vendor-specific mode
+		info->sense_key = 0x05;
+		info->sense_asc = 0x24;
+		info->sense_ascq = 0x00;
+		return USB_STOR_TRANSPORT_FAILED;
+
+	   case 0x1:
+		memcpy(ptr + i, rw_err_page, sizeof(rw_err_page));
+		i += sizeof(rw_err_page);
+		break;
+
+	   case 0x8:
+		memcpy(ptr + i, cache_page, sizeof(cache_page));
+		i += sizeof(cache_page);
+		break;
+
+	   case 0x1B:
+		memcpy(ptr + i, rbac_page, sizeof(rbac_page));
+		i += sizeof(rbac_page);
+		break;
+
+	   case 0x1C:
+		memcpy(ptr + i, timer_page, sizeof(timer_page));
+		i += sizeof(timer_page);
+		break;
+
+	   case 0x3F:
+		memcpy(ptr + i, timer_page, sizeof(timer_page));
+		i += sizeof(timer_page);
+		memcpy(ptr + i, rbac_page, sizeof(rbac_page));
+		i += sizeof(rbac_page);
+		memcpy(ptr + i, cache_page, sizeof(cache_page));
+		i += sizeof(cache_page);
+		memcpy(ptr + i, rw_err_page, sizeof(rw_err_page));
+		i += sizeof(rw_err_page);
+		break;
+	}
+
+	if (sense_6)
+		ptr[0] = i - 1;
+	else
+		((__be16 *) ptr)[0] = cpu_to_be16(i - 2);
+	usb_stor_set_xfer_buf(ptr, i, srb);
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+
+static void jumpshot_info_destructor(void *extra)
+{
+	// this routine is a placeholder...
+	// currently, we don't allocate any extra blocks so we're okay
+}
+
+
+
+// Transport for the Lexar 'Jumpshot'
+//
+static int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+	struct jumpshot_info *info;
+	int rc;
+	unsigned long block, blocks;
+	unsigned char *ptr = us->iobuf;
+	static unsigned char inquiry_response[8] = {
+		0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00
+	};
+
+	if (!us->extra) {
+		us->extra = kzalloc(sizeof(struct jumpshot_info), GFP_NOIO);
+		if (!us->extra)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		us->extra_destructor = jumpshot_info_destructor;
+	}
+
+	info = (struct jumpshot_info *) (us->extra);
+
+	if (srb->cmnd[0] == INQUIRY) {
+		usb_stor_dbg(us, "INQUIRY - Returning bogus response\n");
+		memcpy(ptr, inquiry_response, sizeof(inquiry_response));
+		fill_inquiry_response(us, ptr, 36);
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == READ_CAPACITY) {
+		info->ssize = 0x200;  // hard coded 512 byte sectors as per ATA spec
+
+		rc = jumpshot_get_status(us);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+
+		rc = jumpshot_id_device(us, info);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+
+		usb_stor_dbg(us, "READ_CAPACITY:  %ld sectors, %ld bytes per sector\n",
+			     info->sectors, info->ssize);
+
+		// build the reply
+		//
+		((__be32 *) ptr)[0] = cpu_to_be32(info->sectors - 1);
+		((__be32 *) ptr)[1] = cpu_to_be32(info->ssize);
+		usb_stor_set_xfer_buf(ptr, 8, srb);
+
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == MODE_SELECT_10) {
+		usb_stor_dbg(us, "Gah! MODE_SELECT_10\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	if (srb->cmnd[0] == READ_10) {
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+			((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
+
+		usb_stor_dbg(us, "READ_10: read block 0x%04lx  count %ld\n",
+			     block, blocks);
+		return jumpshot_read_data(us, info, block, blocks);
+	}
+
+	if (srb->cmnd[0] == READ_12) {
+		// I don't think we'll ever see a READ_12 but support it anyway...
+		//
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+			((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
+			 ((u32)(srb->cmnd[8]) <<  8) | ((u32)(srb->cmnd[9]));
+
+		usb_stor_dbg(us, "READ_12: read block 0x%04lx  count %ld\n",
+			     block, blocks);
+		return jumpshot_read_data(us, info, block, blocks);
+	}
+
+	if (srb->cmnd[0] == WRITE_10) {
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+			((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
+
+		usb_stor_dbg(us, "WRITE_10: write block 0x%04lx  count %ld\n",
+			     block, blocks);
+		return jumpshot_write_data(us, info, block, blocks);
+	}
+
+	if (srb->cmnd[0] == WRITE_12) {
+		// I don't think we'll ever see a WRITE_12 but support it anyway...
+		//
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+			((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
+			 ((u32)(srb->cmnd[8]) <<  8) | ((u32)(srb->cmnd[9]));
+
+		usb_stor_dbg(us, "WRITE_12: write block 0x%04lx  count %ld\n",
+			     block, blocks);
+		return jumpshot_write_data(us, info, block, blocks);
+	}
+
+
+	if (srb->cmnd[0] == TEST_UNIT_READY) {
+		usb_stor_dbg(us, "TEST_UNIT_READY\n");
+		return jumpshot_get_status(us);
+	}
+
+	if (srb->cmnd[0] == REQUEST_SENSE) {
+		usb_stor_dbg(us, "REQUEST_SENSE\n");
+
+		memset(ptr, 0, 18);
+		ptr[0] = 0xF0;
+		ptr[2] = info->sense_key;
+		ptr[7] = 11;
+		ptr[12] = info->sense_asc;
+		ptr[13] = info->sense_ascq;
+		usb_stor_set_xfer_buf(ptr, 18, srb);
+
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == MODE_SENSE) {
+		usb_stor_dbg(us, "MODE_SENSE_6 detected\n");
+		return jumpshot_handle_mode_sense(us, srb, 1);
+	}
+
+	if (srb->cmnd[0] == MODE_SENSE_10) {
+		usb_stor_dbg(us, "MODE_SENSE_10 detected\n");
+		return jumpshot_handle_mode_sense(us, srb, 0);
+	}
+
+	if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
+		/*
+		 * sure.  whatever.  not like we can stop the user from popping
+		 * the media out of the device (no locking doors, etc)
+		 */
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == START_STOP) {
+		/*
+		 * this is used by sd.c'check_scsidisk_media_change to detect
+		 * media change
+		 */
+		usb_stor_dbg(us, "START_STOP\n");
+		/*
+		 * the first jumpshot_id_device after a media change returns
+		 * an error (determined experimentally)
+		 */
+		rc = jumpshot_id_device(us, info);
+		if (rc == USB_STOR_TRANSPORT_GOOD) {
+			info->sense_key = NO_SENSE;
+			srb->result = SUCCESS;
+		} else {
+			info->sense_key = UNIT_ATTENTION;
+			srb->result = SAM_STAT_CHECK_CONDITION;
+		}
+		return rc;
+	}
+
+	usb_stor_dbg(us, "Gah! Unknown command: %d (0x%x)\n",
+		     srb->cmnd[0], srb->cmnd[0]);
+	info->sense_key = 0x05;
+	info->sense_asc = 0x20;
+	info->sense_ascq = 0x00;
+	return USB_STOR_TRANSPORT_FAILED;
+}
+
+static struct scsi_host_template jumpshot_host_template;
+
+static int jumpshot_probe(struct usb_interface *intf,
+			 const struct usb_device_id *id)
+{
+	struct us_data *us;
+	int result;
+
+	result = usb_stor_probe1(&us, intf, id,
+			(id - jumpshot_usb_ids) + jumpshot_unusual_dev_list,
+			&jumpshot_host_template);
+	if (result)
+		return result;
+
+	us->transport_name  = "Lexar Jumpshot Control/Bulk";
+	us->transport = jumpshot_transport;
+	us->transport_reset = usb_stor_Bulk_reset;
+	us->max_lun = 1;
+
+	result = usb_stor_probe2(us);
+	return result;
+}
+
+static struct usb_driver jumpshot_driver = {
+	.name =		DRV_NAME,
+	.probe =	jumpshot_probe,
+	.disconnect =	usb_stor_disconnect,
+	.suspend =	usb_stor_suspend,
+	.resume =	usb_stor_resume,
+	.reset_resume =	usb_stor_reset_resume,
+	.pre_reset =	usb_stor_pre_reset,
+	.post_reset =	usb_stor_post_reset,
+	.id_table =	jumpshot_usb_ids,
+	.soft_unbind =	1,
+	.no_dynamic_id = 1,
+};
+
+module_usb_stor_driver(jumpshot_driver, jumpshot_host_template, DRV_NAME);
diff --git a/drivers/usb/storage/karma.c b/drivers/usb/storage/karma.c
new file mode 100644
index 0000000..edcf2be
--- /dev/null
+++ b/drivers/usb/storage/karma.c
@@ -0,0 +1,230 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for Rio Karma
+ *
+ *   (c) 2006 Bob Copeland <me@bobcopeland.com>
+ *   (c) 2006 Keith Bennett <keith@mcs.st-and.ac.uk>
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "debug.h"
+#include "scsiglue.h"
+
+#define DRV_NAME "ums-karma"
+
+MODULE_DESCRIPTION("Driver for Rio Karma");
+MODULE_AUTHOR("Bob Copeland <me@bobcopeland.com>, Keith Bennett <keith@mcs.st-and.ac.uk>");
+MODULE_LICENSE("GPL");
+
+#define RIO_PREFIX "RIOP\x00"
+#define RIO_PREFIX_LEN 5
+#define RIO_SEND_LEN 40
+#define RIO_RECV_LEN 0x200
+
+#define RIO_ENTER_STORAGE 0x1
+#define RIO_LEAVE_STORAGE 0x2
+#define RIO_RESET 0xC
+
+struct karma_data {
+	int in_storage;
+	char *recv;
+};
+
+static int rio_karma_init(struct us_data *us);
+
+
+/*
+ * The table of devices
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+		    vendorName, productName, useProtocol, useTransport, \
+		    initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+  .driver_info = (flags) }
+
+static struct usb_device_id karma_usb_ids[] = {
+#	include "unusual_karma.h"
+	{ }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, karma_usb_ids);
+
+#undef UNUSUAL_DEV
+
+/*
+ * The flags table
+ */
+#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
+		    vendor_name, product_name, use_protocol, use_transport, \
+		    init_function, Flags) \
+{ \
+	.vendorName = vendor_name,	\
+	.productName = product_name,	\
+	.useProtocol = use_protocol,	\
+	.useTransport = use_transport,	\
+	.initFunction = init_function,	\
+}
+
+static struct us_unusual_dev karma_unusual_dev_list[] = {
+#	include "unusual_karma.h"
+	{ }		/* Terminating entry */
+};
+
+#undef UNUSUAL_DEV
+
+
+/*
+ * Send commands to Rio Karma.
+ *
+ * For each command we send 40 bytes starting 'RIOP\0' followed by
+ * the command number and a sequence number, which the device will ack
+ * with a 512-byte packet with the high four bits set and everything
+ * else null.  Then we send 'RIOP\x80' followed by a zero and the
+ * sequence number, until byte 5 in the response repeats the sequence
+ * number.
+ */
+static int rio_karma_send_command(char cmd, struct us_data *us)
+{
+	int result;
+	unsigned long timeout;
+	static unsigned char seq = 1;
+	struct karma_data *data = (struct karma_data *) us->extra;
+
+	usb_stor_dbg(us, "sending command %04x\n", cmd);
+	memset(us->iobuf, 0, RIO_SEND_LEN);
+	memcpy(us->iobuf, RIO_PREFIX, RIO_PREFIX_LEN);
+	us->iobuf[5] = cmd;
+	us->iobuf[6] = seq;
+
+	timeout = jiffies + msecs_to_jiffies(6000);
+	for (;;) {
+		result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+			us->iobuf, RIO_SEND_LEN, NULL);
+		if (result != USB_STOR_XFER_GOOD)
+			goto err;
+
+		result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+			data->recv, RIO_RECV_LEN, NULL);
+		if (result != USB_STOR_XFER_GOOD)
+			goto err;
+
+		if (data->recv[5] == seq)
+			break;
+
+		if (time_after(jiffies, timeout))
+			goto err;
+
+		us->iobuf[4] = 0x80;
+		us->iobuf[5] = 0;
+		msleep(50);
+	}
+
+	seq++;
+	if (seq == 0)
+		seq = 1;
+
+	usb_stor_dbg(us, "sent command %04x\n", cmd);
+	return 0;
+err:
+	usb_stor_dbg(us, "command %04x failed\n", cmd);
+	return USB_STOR_TRANSPORT_FAILED;
+}
+
+/*
+ * Trap START_STOP and READ_10 to leave/re-enter storage mode.
+ * Everything else is propagated to the normal bulk layer.
+ */
+static int rio_karma_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+	int ret;
+	struct karma_data *data = (struct karma_data *) us->extra;
+
+	if (srb->cmnd[0] == READ_10 && !data->in_storage) {
+		ret = rio_karma_send_command(RIO_ENTER_STORAGE, us);
+		if (ret)
+			return ret;
+
+		data->in_storage = 1;
+		return usb_stor_Bulk_transport(srb, us);
+	} else if (srb->cmnd[0] == START_STOP) {
+		ret = rio_karma_send_command(RIO_LEAVE_STORAGE, us);
+		if (ret)
+			return ret;
+
+		data->in_storage = 0;
+		return rio_karma_send_command(RIO_RESET, us);
+	}
+	return usb_stor_Bulk_transport(srb, us);
+}
+
+static void rio_karma_destructor(void *extra)
+{
+	struct karma_data *data = (struct karma_data *) extra;
+	kfree(data->recv);
+}
+
+static int rio_karma_init(struct us_data *us)
+{
+	int ret = 0;
+	struct karma_data *data = kzalloc(sizeof(struct karma_data), GFP_NOIO);
+	if (!data)
+		goto out;
+
+	data->recv = kmalloc(RIO_RECV_LEN, GFP_NOIO);
+	if (!data->recv) {
+		kfree(data);
+		goto out;
+	}
+
+	us->extra = data;
+	us->extra_destructor = rio_karma_destructor;
+	ret = rio_karma_send_command(RIO_ENTER_STORAGE, us);
+	data->in_storage = (ret == 0);
+out:
+	return ret;
+}
+
+static struct scsi_host_template karma_host_template;
+
+static int karma_probe(struct usb_interface *intf,
+			 const struct usb_device_id *id)
+{
+	struct us_data *us;
+	int result;
+
+	result = usb_stor_probe1(&us, intf, id,
+			(id - karma_usb_ids) + karma_unusual_dev_list,
+			&karma_host_template);
+	if (result)
+		return result;
+
+	us->transport_name = "Rio Karma/Bulk";
+	us->transport = rio_karma_transport;
+	us->transport_reset = usb_stor_Bulk_reset;
+
+	result = usb_stor_probe2(us);
+	return result;
+}
+
+static struct usb_driver karma_driver = {
+	.name =		DRV_NAME,
+	.probe =	karma_probe,
+	.disconnect =	usb_stor_disconnect,
+	.suspend =	usb_stor_suspend,
+	.resume =	usb_stor_resume,
+	.reset_resume =	usb_stor_reset_resume,
+	.pre_reset =	usb_stor_pre_reset,
+	.post_reset =	usb_stor_post_reset,
+	.id_table =	karma_usb_ids,
+	.soft_unbind =	1,
+	.no_dynamic_id = 1,
+};
+
+module_usb_stor_driver(karma_driver, karma_host_template, DRV_NAME);
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
new file mode 100644
index 0000000..39a5009
--- /dev/null
+++ b/drivers/usb/storage/onetouch.c
@@ -0,0 +1,306 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Support for the Maxtor OneTouch USB hard drive's button
+ *
+ * Current development and maintenance by:
+ *	Copyright (c) 2005 Nick Sillik <n.sillik@temple.edu>
+ *
+ * Initial work by:
+ *	Copyright (c) 2003 Erik Thyren <erth7411@student.uu.se>
+ *
+ * Based on usbmouse.c (Vojtech Pavlik) and xpad.c (Marko Friedemann)
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/usb/input.h>
+#include "usb.h"
+#include "debug.h"
+#include "scsiglue.h"
+
+#define DRV_NAME "ums-onetouch"
+
+MODULE_DESCRIPTION("Maxtor USB OneTouch hard drive button driver");
+MODULE_AUTHOR("Nick Sillik <n.sillik@temple.edu>");
+MODULE_LICENSE("GPL");
+
+#define ONETOUCH_PKT_LEN        0x02
+#define ONETOUCH_BUTTON         KEY_PROG1
+
+static int onetouch_connect_input(struct us_data *ss);
+static void onetouch_release_input(void *onetouch_);
+
+struct usb_onetouch {
+	char name[128];
+	char phys[64];
+	struct input_dev *dev;	/* input device interface */
+	struct usb_device *udev;	/* usb device */
+
+	struct urb *irq;	/* urb for interrupt in report */
+	unsigned char *data;	/* input data */
+	dma_addr_t data_dma;
+	unsigned int is_open:1;
+};
+
+
+/*
+ * The table of devices
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+		    vendorName, productName, useProtocol, useTransport, \
+		    initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+  .driver_info = (flags) }
+
+static struct usb_device_id onetouch_usb_ids[] = {
+#	include "unusual_onetouch.h"
+	{ }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, onetouch_usb_ids);
+
+#undef UNUSUAL_DEV
+
+/*
+ * The flags table
+ */
+#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
+		    vendor_name, product_name, use_protocol, use_transport, \
+		    init_function, Flags) \
+{ \
+	.vendorName = vendor_name,	\
+	.productName = product_name,	\
+	.useProtocol = use_protocol,	\
+	.useTransport = use_transport,	\
+	.initFunction = init_function,	\
+}
+
+static struct us_unusual_dev onetouch_unusual_dev_list[] = {
+#	include "unusual_onetouch.h"
+	{ }		/* Terminating entry */
+};
+
+#undef UNUSUAL_DEV
+
+
+static void usb_onetouch_irq(struct urb *urb)
+{
+	struct usb_onetouch *onetouch = urb->context;
+	signed char *data = onetouch->data;
+	struct input_dev *dev = onetouch->dev;
+	int status = urb->status;
+	int retval;
+
+	switch (status) {
+	case 0:			/* success */
+		break;
+	case -ECONNRESET:	/* unlink */
+	case -ENOENT:
+	case -ESHUTDOWN:
+		return;
+	/* -EPIPE:  should clear the halt */
+	default:		/* error */
+		goto resubmit;
+	}
+
+	input_report_key(dev, ONETOUCH_BUTTON, data[0] & 0x02);
+	input_sync(dev);
+
+resubmit:
+	retval = usb_submit_urb (urb, GFP_ATOMIC);
+	if (retval)
+		dev_err(&dev->dev, "can't resubmit intr, %s-%s/input0, "
+			"retval %d\n", onetouch->udev->bus->bus_name,
+			onetouch->udev->devpath, retval);
+}
+
+static int usb_onetouch_open(struct input_dev *dev)
+{
+	struct usb_onetouch *onetouch = input_get_drvdata(dev);
+
+	onetouch->is_open = 1;
+	onetouch->irq->dev = onetouch->udev;
+	if (usb_submit_urb(onetouch->irq, GFP_KERNEL)) {
+		dev_err(&dev->dev, "usb_submit_urb failed\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static void usb_onetouch_close(struct input_dev *dev)
+{
+	struct usb_onetouch *onetouch = input_get_drvdata(dev);
+
+	usb_kill_urb(onetouch->irq);
+	onetouch->is_open = 0;
+}
+
+#ifdef CONFIG_PM
+static void usb_onetouch_pm_hook(struct us_data *us, int action)
+{
+	struct usb_onetouch *onetouch = (struct usb_onetouch *) us->extra;
+
+	if (onetouch->is_open) {
+		switch (action) {
+		case US_SUSPEND:
+			usb_kill_urb(onetouch->irq);
+			break;
+		case US_RESUME:
+			if (usb_submit_urb(onetouch->irq, GFP_NOIO) != 0)
+				dev_err(&onetouch->irq->dev->dev,
+					"usb_submit_urb failed\n");
+			break;
+		default:
+			break;
+		}
+	}
+}
+#endif /* CONFIG_PM */
+
+static int onetouch_connect_input(struct us_data *ss)
+{
+	struct usb_device *udev = ss->pusb_dev;
+	struct usb_host_interface *interface;
+	struct usb_endpoint_descriptor *endpoint;
+	struct usb_onetouch *onetouch;
+	struct input_dev *input_dev;
+	int pipe, maxp;
+	int error = -ENOMEM;
+
+	interface = ss->pusb_intf->cur_altsetting;
+
+	if (interface->desc.bNumEndpoints != 3)
+		return -ENODEV;
+
+	endpoint = &interface->endpoint[2].desc;
+	if (!usb_endpoint_is_int_in(endpoint))
+		return -ENODEV;
+
+	pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
+	maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+	maxp = min(maxp, ONETOUCH_PKT_LEN);
+
+	onetouch = kzalloc(sizeof(struct usb_onetouch), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!onetouch || !input_dev)
+		goto fail1;
+
+	onetouch->data = usb_alloc_coherent(udev, ONETOUCH_PKT_LEN,
+					    GFP_KERNEL, &onetouch->data_dma);
+	if (!onetouch->data)
+		goto fail1;
+
+	onetouch->irq = usb_alloc_urb(0, GFP_KERNEL);
+	if (!onetouch->irq)
+		goto fail2;
+
+	onetouch->udev = udev;
+	onetouch->dev = input_dev;
+
+	if (udev->manufacturer)
+		strlcpy(onetouch->name, udev->manufacturer,
+			sizeof(onetouch->name));
+	if (udev->product) {
+		if (udev->manufacturer)
+			strlcat(onetouch->name, " ", sizeof(onetouch->name));
+		strlcat(onetouch->name, udev->product, sizeof(onetouch->name));
+	}
+
+	if (!strlen(onetouch->name))
+		snprintf(onetouch->name, sizeof(onetouch->name),
+			 "Maxtor Onetouch %04x:%04x",
+			 le16_to_cpu(udev->descriptor.idVendor),
+			 le16_to_cpu(udev->descriptor.idProduct));
+
+	usb_make_path(udev, onetouch->phys, sizeof(onetouch->phys));
+	strlcat(onetouch->phys, "/input0", sizeof(onetouch->phys));
+
+	input_dev->name = onetouch->name;
+	input_dev->phys = onetouch->phys;
+	usb_to_input_id(udev, &input_dev->id);
+	input_dev->dev.parent = &udev->dev;
+
+	set_bit(EV_KEY, input_dev->evbit);
+	set_bit(ONETOUCH_BUTTON, input_dev->keybit);
+	clear_bit(0, input_dev->keybit);
+
+	input_set_drvdata(input_dev, onetouch);
+
+	input_dev->open = usb_onetouch_open;
+	input_dev->close = usb_onetouch_close;
+
+	usb_fill_int_urb(onetouch->irq, udev, pipe, onetouch->data, maxp,
+			 usb_onetouch_irq, onetouch, endpoint->bInterval);
+	onetouch->irq->transfer_dma = onetouch->data_dma;
+	onetouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	ss->extra_destructor = onetouch_release_input;
+	ss->extra = onetouch;
+#ifdef CONFIG_PM
+	ss->suspend_resume_hook = usb_onetouch_pm_hook;
+#endif
+
+	error = input_register_device(onetouch->dev);
+	if (error)
+		goto fail3;
+
+	return 0;
+
+ fail3:	usb_free_urb(onetouch->irq);
+ fail2:	usb_free_coherent(udev, ONETOUCH_PKT_LEN,
+			  onetouch->data, onetouch->data_dma);
+ fail1:	kfree(onetouch);
+	input_free_device(input_dev);
+	return error;
+}
+
+static void onetouch_release_input(void *onetouch_)
+{
+	struct usb_onetouch *onetouch = (struct usb_onetouch *) onetouch_;
+
+	if (onetouch) {
+		usb_kill_urb(onetouch->irq);
+		input_unregister_device(onetouch->dev);
+		usb_free_urb(onetouch->irq);
+		usb_free_coherent(onetouch->udev, ONETOUCH_PKT_LEN,
+				  onetouch->data, onetouch->data_dma);
+	}
+}
+
+static struct scsi_host_template onetouch_host_template;
+
+static int onetouch_probe(struct usb_interface *intf,
+			 const struct usb_device_id *id)
+{
+	struct us_data *us;
+	int result;
+
+	result = usb_stor_probe1(&us, intf, id,
+			(id - onetouch_usb_ids) + onetouch_unusual_dev_list,
+			&onetouch_host_template);
+	if (result)
+		return result;
+
+	/* Use default transport and protocol */
+
+	result = usb_stor_probe2(us);
+	return result;
+}
+
+static struct usb_driver onetouch_driver = {
+	.name =		DRV_NAME,
+	.probe =	onetouch_probe,
+	.disconnect =	usb_stor_disconnect,
+	.suspend =	usb_stor_suspend,
+	.resume =	usb_stor_resume,
+	.reset_resume =	usb_stor_reset_resume,
+	.pre_reset =	usb_stor_pre_reset,
+	.post_reset =	usb_stor_post_reset,
+	.id_table =	onetouch_usb_ids,
+	.soft_unbind =	1,
+	.no_dynamic_id = 1,
+};
+
+module_usb_stor_driver(onetouch_driver, onetouch_host_template, DRV_NAME);
diff --git a/drivers/usb/storage/option_ms.c b/drivers/usb/storage/option_ms.c
new file mode 100644
index 0000000..7c0b05a
--- /dev/null
+++ b/drivers/usb/storage/option_ms.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for Option High Speed Mobile Devices.
+ *
+ *   (c) 2008 Dan Williams <dcbw@redhat.com>
+ *
+ * Inspiration taken from sierra_ms.c by Kevin Lloyd <klloyd@sierrawireless.com>
+ */
+
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "option_ms.h"
+#include "debug.h"
+
+#define ZCD_FORCE_MODEM			0x01
+#define ZCD_ALLOW_MS 			0x02
+
+static unsigned int option_zero_cd = ZCD_FORCE_MODEM;
+module_param(option_zero_cd, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(option_zero_cd, "ZeroCD mode (1=Force Modem (default),"
+		 " 2=Allow CD-Rom");
+
+#define RESPONSE_LEN 1024
+
+static int option_rezero(struct us_data *us)
+{
+	static const unsigned char rezero_msg[] = {
+	  0x55, 0x53, 0x42, 0x43, 0x78, 0x56, 0x34, 0x12,
+	  0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x01,
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+	};
+	char *buffer;
+	int result;
+
+	usb_stor_dbg(us, "Option MS: %s\n", "DEVICE MODE SWITCH");
+
+	buffer = kzalloc(RESPONSE_LEN, GFP_KERNEL);
+	if (buffer == NULL)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	memcpy(buffer, rezero_msg, sizeof(rezero_msg));
+	result = usb_stor_bulk_transfer_buf(us,
+			us->send_bulk_pipe,
+			buffer, sizeof(rezero_msg), NULL);
+	if (result != USB_STOR_XFER_GOOD) {
+		result = USB_STOR_XFER_ERROR;
+		goto out;
+	}
+
+	/*
+	 * Some of the devices need to be asked for a response, but we don't
+	 * care what that response is.
+	 */
+	usb_stor_bulk_transfer_buf(us,
+			us->recv_bulk_pipe,
+			buffer, RESPONSE_LEN, NULL);
+
+	/* Read the CSW */
+	usb_stor_bulk_transfer_buf(us,
+			us->recv_bulk_pipe,
+			buffer, 13, NULL);
+
+	result = USB_STOR_XFER_GOOD;
+
+out:
+	kfree(buffer);
+	return result;
+}
+
+static int option_inquiry(struct us_data *us)
+{
+	static const unsigned char inquiry_msg[] = {
+	  0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78,
+	  0x24, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x12,
+	  0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00,
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+	};
+	char *buffer;
+	int result;
+
+	usb_stor_dbg(us, "Option MS: %s\n", "device inquiry for vendor name");
+
+	buffer = kzalloc(0x24, GFP_KERNEL);
+	if (buffer == NULL)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	memcpy(buffer, inquiry_msg, sizeof(inquiry_msg));
+	result = usb_stor_bulk_transfer_buf(us,
+			us->send_bulk_pipe,
+			buffer, sizeof(inquiry_msg), NULL);
+	if (result != USB_STOR_XFER_GOOD) {
+		result = USB_STOR_XFER_ERROR;
+		goto out;
+	}
+
+	result = usb_stor_bulk_transfer_buf(us,
+			us->recv_bulk_pipe,
+			buffer, 0x24, NULL);
+	if (result != USB_STOR_XFER_GOOD) {
+		result = USB_STOR_XFER_ERROR;
+		goto out;
+	}
+
+	result = memcmp(buffer+8, "Option", 6);
+
+	if (result != 0)
+		result = memcmp(buffer+8, "ZCOPTION", 8);
+
+	/* Read the CSW */
+	usb_stor_bulk_transfer_buf(us,
+			us->recv_bulk_pipe,
+			buffer, 13, NULL);
+
+out:
+	kfree(buffer);
+	return result;
+}
+
+
+int option_ms_init(struct us_data *us)
+{
+	int result;
+
+	usb_stor_dbg(us, "Option MS: %s\n", "option_ms_init called");
+
+	/*
+	 * Additional test for vendor information via INQUIRY,
+	 * because some vendor/product IDs are ambiguous
+	 */
+	result = option_inquiry(us);
+	if (result != 0) {
+		usb_stor_dbg(us, "Option MS: %s\n",
+			     "vendor is not Option or not determinable, no action taken");
+		return 0;
+	} else
+		usb_stor_dbg(us, "Option MS: %s\n",
+			     "this is a genuine Option device, proceeding");
+
+	/* Force Modem mode */
+	if (option_zero_cd == ZCD_FORCE_MODEM) {
+		usb_stor_dbg(us, "Option MS: %s\n", "Forcing Modem Mode");
+		result = option_rezero(us);
+		if (result != USB_STOR_XFER_GOOD)
+			usb_stor_dbg(us, "Option MS: %s\n",
+				     "Failed to switch to modem mode");
+		return -EIO;
+	} else if (option_zero_cd == ZCD_ALLOW_MS) {
+		/* Allow Mass Storage mode (keep CD-Rom) */
+		usb_stor_dbg(us, "Option MS: %s\n",
+			     "Allowing Mass Storage Mode if device requests it");
+	}
+
+	return 0;
+}
+
diff --git a/drivers/usb/storage/option_ms.h b/drivers/usb/storage/option_ms.h
new file mode 100644
index 0000000..6439992
--- /dev/null
+++ b/drivers/usb/storage/option_ms.h
@@ -0,0 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _OPTION_MS_H_
+#define _OPTION_MS_H_
+extern int option_ms_init(struct us_data *us);
+#endif
diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c
new file mode 100644
index 0000000..9033e50
--- /dev/null
+++ b/drivers/usb/storage/protocol.c
@@ -0,0 +1,181 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for USB Mass Storage compliant devices
+ *
+ * Current development and maintenance by:
+ *   (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * Developed with the assistance of:
+ *   (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
+ *   (c) 2002 Alan Stern (stern@rowland.org)
+ *
+ * Initial work by:
+ *   (c) 1999 Michael Gee (michael@linuxspecific.com)
+ *
+ * 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.
+ */
+
+#include <linux/highmem.h>
+#include <linux/export.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include "usb.h"
+#include "protocol.h"
+#include "debug.h"
+#include "scsiglue.h"
+#include "transport.h"
+
+/***********************************************************************
+ * Protocol routines
+ ***********************************************************************/
+
+void usb_stor_pad12_command(struct scsi_cmnd *srb, struct us_data *us)
+{
+	/*
+	 * Pad the SCSI command with zeros out to 12 bytes.  If the
+	 * command already is 12 bytes or longer, leave it alone.
+	 *
+	 * NOTE: This only works because a scsi_cmnd struct field contains
+	 * a unsigned char cmnd[16], so we know we have storage available
+	 */
+	for (; srb->cmd_len < 12; srb->cmd_len++)
+		srb->cmnd[srb->cmd_len] = 0;
+
+	/* send the command to the transport layer */
+	usb_stor_invoke_transport(srb, us);
+}
+
+void usb_stor_ufi_command(struct scsi_cmnd *srb, struct us_data *us)
+{
+	/*
+	 * fix some commands -- this is a form of mode translation
+	 * UFI devices only accept 12 byte long commands
+	 *
+	 * NOTE: This only works because a scsi_cmnd struct field contains
+	 * a unsigned char cmnd[16], so we know we have storage available
+	 */
+
+	/* Pad the ATAPI command with zeros */
+	for (; srb->cmd_len < 12; srb->cmd_len++)
+		srb->cmnd[srb->cmd_len] = 0;
+
+	/* set command length to 12 bytes (this affects the transport layer) */
+	srb->cmd_len = 12;
+
+	/* XXX We should be constantly re-evaluating the need for these */
+
+	/* determine the correct data length for these commands */
+	switch (srb->cmnd[0]) {
+
+		/* for INQUIRY, UFI devices only ever return 36 bytes */
+	case INQUIRY:
+		srb->cmnd[4] = 36;
+		break;
+
+		/* again, for MODE_SENSE_10, we get the minimum (8) */
+	case MODE_SENSE_10:
+		srb->cmnd[7] = 0;
+		srb->cmnd[8] = 8;
+		break;
+
+		/* for REQUEST_SENSE, UFI devices only ever return 18 bytes */
+	case REQUEST_SENSE:
+		srb->cmnd[4] = 18;
+		break;
+	} /* end switch on cmnd[0] */
+
+	/* send the command to the transport layer */
+	usb_stor_invoke_transport(srb, us);
+}
+
+void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb,
+				       struct us_data *us)
+{
+	/* send the command to the transport layer */
+	usb_stor_invoke_transport(srb, us);
+}
+EXPORT_SYMBOL_GPL(usb_stor_transparent_scsi_command);
+
+/***********************************************************************
+ * Scatter-gather transfer buffer access routines
+ ***********************************************************************/
+
+/*
+ * Copy a buffer of length buflen to/from the srb's transfer buffer.
+ * Update the **sgptr and *offset variables so that the next copy will
+ * pick up from where this one left off.
+ */
+unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
+	unsigned int buflen, struct scsi_cmnd *srb, struct scatterlist **sgptr,
+	unsigned int *offset, enum xfer_buf_dir dir)
+{
+	unsigned int cnt = 0;
+	struct scatterlist *sg = *sgptr;
+	struct sg_mapping_iter miter;
+	unsigned int nents = scsi_sg_count(srb);
+
+	if (sg)
+		nents = sg_nents(sg);
+	else
+		sg = scsi_sglist(srb);
+
+	sg_miter_start(&miter, sg, nents, dir == FROM_XFER_BUF ?
+		SG_MITER_FROM_SG: SG_MITER_TO_SG);
+
+	if (!sg_miter_skip(&miter, *offset))
+		return cnt;
+
+	while (sg_miter_next(&miter) && cnt < buflen) {
+		unsigned int len = min_t(unsigned int, miter.length,
+				buflen - cnt);
+
+		if (dir == FROM_XFER_BUF)
+			memcpy(buffer + cnt, miter.addr, len);
+		else
+			memcpy(miter.addr, buffer + cnt, len);
+
+		if (*offset + len < miter.piter.sg->length) {
+			*offset += len;
+			*sgptr = miter.piter.sg;
+		} else {
+			*offset = 0;
+			*sgptr = sg_next(miter.piter.sg);
+		}
+		cnt += len;
+	}
+	sg_miter_stop(&miter);
+
+	return cnt;
+}
+EXPORT_SYMBOL_GPL(usb_stor_access_xfer_buf);
+
+/*
+ * Store the contents of buffer into srb's transfer buffer and set the
+ * SCSI residue.
+ */
+void usb_stor_set_xfer_buf(unsigned char *buffer,
+	unsigned int buflen, struct scsi_cmnd *srb)
+{
+	unsigned int offset = 0;
+	struct scatterlist *sg = NULL;
+
+	buflen = min(buflen, scsi_bufflen(srb));
+	buflen = usb_stor_access_xfer_buf(buffer, buflen, srb, &sg, &offset,
+			TO_XFER_BUF);
+	if (buflen < scsi_bufflen(srb))
+		scsi_set_resid(srb, scsi_bufflen(srb) - buflen);
+}
+EXPORT_SYMBOL_GPL(usb_stor_set_xfer_buf);
diff --git a/drivers/usb/storage/protocol.h b/drivers/usb/storage/protocol.h
new file mode 100644
index 0000000..072f1ff
--- /dev/null
+++ b/drivers/usb/storage/protocol.h
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for USB Mass Storage compliant devices
+ * Protocol Functions Header File
+ *
+ * Current development and maintenance by:
+ *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * 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.
+ */
+
+#ifndef _PROTOCOL_H_
+#define _PROTOCOL_H_
+
+/* Protocol handling routines */
+extern void usb_stor_pad12_command(struct scsi_cmnd*, struct us_data*);
+extern void usb_stor_ufi_command(struct scsi_cmnd*, struct us_data*);
+extern void usb_stor_transparent_scsi_command(struct scsi_cmnd*,
+		struct us_data*);
+
+/* struct scsi_cmnd transfer buffer access utilities */
+enum xfer_buf_dir	{TO_XFER_BUF, FROM_XFER_BUF};
+
+extern unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
+	unsigned int buflen, struct scsi_cmnd *srb, struct scatterlist **,
+	unsigned int *offset, enum xfer_buf_dir dir);
+
+extern void usb_stor_set_xfer_buf(unsigned char *buffer,
+	unsigned int buflen, struct scsi_cmnd *srb);
+#endif
diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c
new file mode 100644
index 0000000..31b0244
--- /dev/null
+++ b/drivers/usb/storage/realtek_cr.c
@@ -0,0 +1,1069 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for Realtek RTS51xx USB card reader
+ *
+ * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved.
+ *
+ * Author:
+ *   wwang (wei_wang@realsil.com.cn)
+ *   No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
+ */
+
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <linux/cdrom.h>
+
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include <linux/usb_usual.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "protocol.h"
+#include "debug.h"
+#include "scsiglue.h"
+
+#define DRV_NAME "ums-realtek"
+
+MODULE_DESCRIPTION("Driver for Realtek USB Card Reader");
+MODULE_AUTHOR("wwang <wei_wang@realsil.com.cn>");
+MODULE_LICENSE("GPL");
+
+static int auto_delink_en = 1;
+module_param(auto_delink_en, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(auto_delink_en, "enable auto delink");
+
+#ifdef CONFIG_REALTEK_AUTOPM
+static int ss_en = 1;
+module_param(ss_en, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(ss_en, "enable selective suspend");
+
+static int ss_delay = 50;
+module_param(ss_delay, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(ss_delay,
+		 "seconds to delay before entering selective suspend");
+
+enum RTS51X_STAT {
+	RTS51X_STAT_INIT,
+	RTS51X_STAT_IDLE,
+	RTS51X_STAT_RUN,
+	RTS51X_STAT_SS
+};
+
+#define POLLING_INTERVAL	50
+
+#define rts51x_set_stat(chip, stat)	\
+	((chip)->state = (enum RTS51X_STAT)(stat))
+#define rts51x_get_stat(chip)		((chip)->state)
+
+#define SET_LUN_READY(chip, lun)	((chip)->lun_ready |= ((u8)1 << (lun)))
+#define CLR_LUN_READY(chip, lun)	((chip)->lun_ready &= ~((u8)1 << (lun)))
+#define TST_LUN_READY(chip, lun)	((chip)->lun_ready & ((u8)1 << (lun)))
+
+#endif
+
+struct rts51x_status {
+	u16 vid;
+	u16 pid;
+	u8 cur_lun;
+	u8 card_type;
+	u8 total_lun;
+	u16 fw_ver;
+	u8 phy_exist;
+	u8 multi_flag;
+	u8 multi_card;
+	u8 log_exist;
+	union {
+		u8 detailed_type1;
+		u8 detailed_type2;
+	} detailed_type;
+	u8 function[2];
+};
+
+struct rts51x_chip {
+	u16 vendor_id;
+	u16 product_id;
+	char max_lun;
+
+	struct rts51x_status *status;
+	int status_len;
+
+	u32 flag;
+	struct us_data *us;
+
+#ifdef CONFIG_REALTEK_AUTOPM
+	struct timer_list rts51x_suspend_timer;
+	unsigned long timer_expires;
+	int pwr_state;
+	u8 lun_ready;
+	enum RTS51X_STAT state;
+	int support_auto_delink;
+#endif
+	/* used to back up the protocol chosen in probe1 phase */
+	proto_cmnd proto_handler_backup;
+};
+
+/* flag definition */
+#define FLIDX_AUTO_DELINK		0x01
+
+#define SCSI_LUN(srb)			((srb)->device->lun)
+
+/* Bit Operation */
+#define SET_BIT(data, idx)		((data) |= 1 << (idx))
+#define CLR_BIT(data, idx)		((data) &= ~(1 << (idx)))
+#define CHK_BIT(data, idx)		((data) & (1 << (idx)))
+
+#define SET_AUTO_DELINK(chip)		((chip)->flag |= FLIDX_AUTO_DELINK)
+#define CLR_AUTO_DELINK(chip)		((chip)->flag &= ~FLIDX_AUTO_DELINK)
+#define CHK_AUTO_DELINK(chip)		((chip)->flag & FLIDX_AUTO_DELINK)
+
+#define RTS51X_GET_VID(chip)		((chip)->vendor_id)
+#define RTS51X_GET_PID(chip)		((chip)->product_id)
+
+#define VENDOR_ID(chip)			((chip)->status[0].vid)
+#define PRODUCT_ID(chip)		((chip)->status[0].pid)
+#define FW_VERSION(chip)		((chip)->status[0].fw_ver)
+#define STATUS_LEN(chip)		((chip)->status_len)
+
+#define STATUS_SUCCESS		0
+#define STATUS_FAIL		1
+
+/* Check card reader function */
+#define SUPPORT_DETAILED_TYPE1(chip)	\
+		CHK_BIT((chip)->status[0].function[0], 1)
+#define SUPPORT_OT(chip)		\
+		CHK_BIT((chip)->status[0].function[0], 2)
+#define SUPPORT_OC(chip)		\
+		CHK_BIT((chip)->status[0].function[0], 3)
+#define SUPPORT_AUTO_DELINK(chip)	\
+		CHK_BIT((chip)->status[0].function[0], 4)
+#define SUPPORT_SDIO(chip)		\
+		CHK_BIT((chip)->status[0].function[1], 0)
+#define SUPPORT_DETAILED_TYPE2(chip)	\
+		CHK_BIT((chip)->status[0].function[1], 1)
+
+#define CHECK_PID(chip, pid)		(RTS51X_GET_PID(chip) == (pid))
+#define CHECK_FW_VER(chip, fw_ver)	(FW_VERSION(chip) == (fw_ver))
+#define CHECK_ID(chip, pid, fw_ver)	\
+		(CHECK_PID((chip), (pid)) && CHECK_FW_VER((chip), (fw_ver)))
+
+static int init_realtek_cr(struct us_data *us);
+
+/*
+ * The table of devices
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+		    vendorName, productName, useProtocol, useTransport, \
+		    initFunction, flags) \
+{\
+	USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+	.driver_info = (flags) \
+}
+
+static const struct usb_device_id realtek_cr_ids[] = {
+#	include "unusual_realtek.h"
+	{}			/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, realtek_cr_ids);
+
+#undef UNUSUAL_DEV
+
+/*
+ * The flags table
+ */
+#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
+		    vendor_name, product_name, use_protocol, use_transport, \
+		    init_function, Flags) \
+{ \
+	.vendorName = vendor_name,	\
+	.productName = product_name,	\
+	.useProtocol = use_protocol,	\
+	.useTransport = use_transport,	\
+	.initFunction = init_function,	\
+}
+
+static struct us_unusual_dev realtek_cr_unusual_dev_list[] = {
+#	include "unusual_realtek.h"
+	{}			/* Terminating entry */
+};
+
+#undef UNUSUAL_DEV
+
+static int rts51x_bulk_transport(struct us_data *us, u8 lun,
+				 u8 *cmd, int cmd_len, u8 *buf, int buf_len,
+				 enum dma_data_direction dir, int *act_len)
+{
+	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *)us->iobuf;
+	struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *)us->iobuf;
+	int result;
+	unsigned int residue;
+	unsigned int cswlen;
+	unsigned int cbwlen = US_BULK_CB_WRAP_LEN;
+
+	/* set up the command wrapper */
+	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+	bcb->DataTransferLength = cpu_to_le32(buf_len);
+	bcb->Flags = (dir == DMA_FROM_DEVICE) ? US_BULK_FLAG_IN : 0;
+	bcb->Tag = ++us->tag;
+	bcb->Lun = lun;
+	bcb->Length = cmd_len;
+
+	/* copy the command payload */
+	memset(bcb->CDB, 0, sizeof(bcb->CDB));
+	memcpy(bcb->CDB, cmd, bcb->Length);
+
+	/* send it to out endpoint */
+	result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+					    bcb, cbwlen, NULL);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	/* DATA STAGE */
+	/* send/receive data payload, if there is any */
+
+	if (buf && buf_len) {
+		unsigned int pipe = (dir == DMA_FROM_DEVICE) ?
+		    us->recv_bulk_pipe : us->send_bulk_pipe;
+		result = usb_stor_bulk_transfer_buf(us, pipe,
+						    buf, buf_len, NULL);
+		if (result == USB_STOR_XFER_ERROR)
+			return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	/* get CSW for device status */
+	result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+					    bcs, US_BULK_CS_WRAP_LEN, &cswlen);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	/* check bulk status */
+	if (bcs->Signature != cpu_to_le32(US_BULK_CS_SIGN)) {
+		usb_stor_dbg(us, "Signature mismatch: got %08X, expecting %08X\n",
+			     le32_to_cpu(bcs->Signature), US_BULK_CS_SIGN);
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	residue = bcs->Residue;
+	if (bcs->Tag != us->tag)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	/*
+	 * try to compute the actual residue, based on how much data
+	 * was really transferred and what the device tells us
+	 */
+	if (residue)
+		residue = residue < buf_len ? residue : buf_len;
+
+	if (act_len)
+		*act_len = buf_len - residue;
+
+	/* based on the status code, we report good or bad */
+	switch (bcs->Status) {
+	case US_BULK_STAT_OK:
+		/* command good -- note that data could be short */
+		return USB_STOR_TRANSPORT_GOOD;
+
+	case US_BULK_STAT_FAIL:
+		/* command failed */
+		return USB_STOR_TRANSPORT_FAILED;
+
+	case US_BULK_STAT_PHASE:
+		/*
+		 * phase error -- note that a transport reset will be
+		 * invoked by the invoke_transport() function
+		 */
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	/* we should never get here, but if we do, we're in trouble */
+	return USB_STOR_TRANSPORT_ERROR;
+}
+
+static int rts51x_bulk_transport_special(struct us_data *us, u8 lun,
+				 u8 *cmd, int cmd_len, u8 *buf, int buf_len,
+				 enum dma_data_direction dir, int *act_len)
+{
+	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+	struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
+	int result;
+	unsigned int cswlen;
+	unsigned int cbwlen = US_BULK_CB_WRAP_LEN;
+
+	/* set up the command wrapper */
+	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+	bcb->DataTransferLength = cpu_to_le32(buf_len);
+	bcb->Flags = (dir == DMA_FROM_DEVICE) ? US_BULK_FLAG_IN : 0;
+	bcb->Tag = ++us->tag;
+	bcb->Lun = lun;
+	bcb->Length = cmd_len;
+
+	/* copy the command payload */
+	memset(bcb->CDB, 0, sizeof(bcb->CDB));
+	memcpy(bcb->CDB, cmd, bcb->Length);
+
+	/* send it to out endpoint */
+	result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+				bcb, cbwlen, NULL);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	/* DATA STAGE */
+	/* send/receive data payload, if there is any */
+
+	if (buf && buf_len) {
+		unsigned int pipe = (dir == DMA_FROM_DEVICE) ?
+				us->recv_bulk_pipe : us->send_bulk_pipe;
+		result = usb_stor_bulk_transfer_buf(us, pipe,
+				buf, buf_len, NULL);
+		if (result == USB_STOR_XFER_ERROR)
+			return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	/* get CSW for device status */
+	result = usb_bulk_msg(us->pusb_dev, us->recv_bulk_pipe, bcs,
+			US_BULK_CS_WRAP_LEN, &cswlen, 250);
+	return result;
+}
+
+/* Determine what the maximum LUN supported is */
+static int rts51x_get_max_lun(struct us_data *us)
+{
+	int result;
+
+	/* issue the command */
+	us->iobuf[0] = 0;
+	result = usb_stor_control_msg(us, us->recv_ctrl_pipe,
+				      US_BULK_GET_MAX_LUN,
+				      USB_DIR_IN | USB_TYPE_CLASS |
+				      USB_RECIP_INTERFACE,
+				      0, us->ifnum, us->iobuf, 1, 10 * HZ);
+
+	usb_stor_dbg(us, "GetMaxLUN command result is %d, data is %d\n",
+		     result, us->iobuf[0]);
+
+	/* if we have a successful request, return the result */
+	if (result > 0)
+		return us->iobuf[0];
+
+	return 0;
+}
+
+static int rts51x_read_mem(struct us_data *us, u16 addr, u8 *data, u16 len)
+{
+	int retval;
+	u8 cmnd[12] = { 0 };
+	u8 *buf;
+
+	buf = kmalloc(len, GFP_NOIO);
+	if (buf == NULL)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	usb_stor_dbg(us, "addr = 0x%x, len = %d\n", addr, len);
+
+	cmnd[0] = 0xF0;
+	cmnd[1] = 0x0D;
+	cmnd[2] = (u8) (addr >> 8);
+	cmnd[3] = (u8) addr;
+	cmnd[4] = (u8) (len >> 8);
+	cmnd[5] = (u8) len;
+
+	retval = rts51x_bulk_transport(us, 0, cmnd, 12,
+				       buf, len, DMA_FROM_DEVICE, NULL);
+	if (retval != USB_STOR_TRANSPORT_GOOD) {
+		kfree(buf);
+		return -EIO;
+	}
+
+	memcpy(data, buf, len);
+	kfree(buf);
+	return 0;
+}
+
+static int rts51x_write_mem(struct us_data *us, u16 addr, u8 *data, u16 len)
+{
+	int retval;
+	u8 cmnd[12] = { 0 };
+	u8 *buf;
+
+	buf = kmemdup(data, len, GFP_NOIO);
+	if (buf == NULL)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	usb_stor_dbg(us, "addr = 0x%x, len = %d\n", addr, len);
+
+	cmnd[0] = 0xF0;
+	cmnd[1] = 0x0E;
+	cmnd[2] = (u8) (addr >> 8);
+	cmnd[3] = (u8) addr;
+	cmnd[4] = (u8) (len >> 8);
+	cmnd[5] = (u8) len;
+
+	retval = rts51x_bulk_transport(us, 0, cmnd, 12,
+				       buf, len, DMA_TO_DEVICE, NULL);
+	kfree(buf);
+	if (retval != USB_STOR_TRANSPORT_GOOD)
+		return -EIO;
+
+	return 0;
+}
+
+static int rts51x_read_status(struct us_data *us,
+			      u8 lun, u8 *status, int len, int *actlen)
+{
+	int retval;
+	u8 cmnd[12] = { 0 };
+	u8 *buf;
+
+	buf = kmalloc(len, GFP_NOIO);
+	if (buf == NULL)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	usb_stor_dbg(us, "lun = %d\n", lun);
+
+	cmnd[0] = 0xF0;
+	cmnd[1] = 0x09;
+
+	retval = rts51x_bulk_transport(us, lun, cmnd, 12,
+				       buf, len, DMA_FROM_DEVICE, actlen);
+	if (retval != USB_STOR_TRANSPORT_GOOD) {
+		kfree(buf);
+		return -EIO;
+	}
+
+	memcpy(status, buf, len);
+	kfree(buf);
+	return 0;
+}
+
+static int rts51x_check_status(struct us_data *us, u8 lun)
+{
+	struct rts51x_chip *chip = (struct rts51x_chip *)(us->extra);
+	int retval;
+	u8 buf[16];
+
+	retval = rts51x_read_status(us, lun, buf, 16, &(chip->status_len));
+	if (retval != STATUS_SUCCESS)
+		return -EIO;
+
+	usb_stor_dbg(us, "chip->status_len = %d\n", chip->status_len);
+
+	chip->status[lun].vid = ((u16) buf[0] << 8) | buf[1];
+	chip->status[lun].pid = ((u16) buf[2] << 8) | buf[3];
+	chip->status[lun].cur_lun = buf[4];
+	chip->status[lun].card_type = buf[5];
+	chip->status[lun].total_lun = buf[6];
+	chip->status[lun].fw_ver = ((u16) buf[7] << 8) | buf[8];
+	chip->status[lun].phy_exist = buf[9];
+	chip->status[lun].multi_flag = buf[10];
+	chip->status[lun].multi_card = buf[11];
+	chip->status[lun].log_exist = buf[12];
+	if (chip->status_len == 16) {
+		chip->status[lun].detailed_type.detailed_type1 = buf[13];
+		chip->status[lun].function[0] = buf[14];
+		chip->status[lun].function[1] = buf[15];
+	}
+
+	return 0;
+}
+
+static int enable_oscillator(struct us_data *us)
+{
+	int retval;
+	u8 value;
+
+	retval = rts51x_read_mem(us, 0xFE77, &value, 1);
+	if (retval < 0)
+		return -EIO;
+
+	value |= 0x04;
+	retval = rts51x_write_mem(us, 0xFE77, &value, 1);
+	if (retval < 0)
+		return -EIO;
+
+	retval = rts51x_read_mem(us, 0xFE77, &value, 1);
+	if (retval < 0)
+		return -EIO;
+
+	if (!(value & 0x04))
+		return -EIO;
+
+	return 0;
+}
+
+static int __do_config_autodelink(struct us_data *us, u8 *data, u16 len)
+{
+	int retval;
+	u8 cmnd[12] = {0};
+	u8 *buf;
+
+	usb_stor_dbg(us, "addr = 0xfe47, len = %d\n", len);
+
+	buf = kmemdup(data, len, GFP_NOIO);
+	if (!buf)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	cmnd[0] = 0xF0;
+	cmnd[1] = 0x0E;
+	cmnd[2] = 0xfe;
+	cmnd[3] = 0x47;
+	cmnd[4] = (u8)(len >> 8);
+	cmnd[5] = (u8)len;
+
+	retval = rts51x_bulk_transport_special(us, 0, cmnd, 12, buf, len, DMA_TO_DEVICE, NULL);
+	kfree(buf);
+	if (retval != USB_STOR_TRANSPORT_GOOD) {
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int do_config_autodelink(struct us_data *us, int enable, int force)
+{
+	int retval;
+	u8 value;
+
+	retval = rts51x_read_mem(us, 0xFE47, &value, 1);
+	if (retval < 0)
+		return -EIO;
+
+	if (enable) {
+		if (force)
+			value |= 0x03;
+		else
+			value |= 0x01;
+	} else {
+		value &= ~0x03;
+	}
+
+	usb_stor_dbg(us, "set 0xfe47 to 0x%x\n", value);
+
+	/* retval = rts51x_write_mem(us, 0xFE47, &value, 1); */
+	retval = __do_config_autodelink(us, &value, 1);
+	if (retval < 0)
+		return -EIO;
+
+	return 0;
+}
+
+static int config_autodelink_after_power_on(struct us_data *us)
+{
+	struct rts51x_chip *chip = (struct rts51x_chip *)(us->extra);
+	int retval;
+	u8 value;
+
+	if (!CHK_AUTO_DELINK(chip))
+		return 0;
+
+	retval = rts51x_read_mem(us, 0xFE47, &value, 1);
+	if (retval < 0)
+		return -EIO;
+
+	if (auto_delink_en) {
+		CLR_BIT(value, 0);
+		CLR_BIT(value, 1);
+		SET_BIT(value, 2);
+
+		if (CHECK_ID(chip, 0x0138, 0x3882))
+			CLR_BIT(value, 2);
+
+		SET_BIT(value, 7);
+
+		/* retval = rts51x_write_mem(us, 0xFE47, &value, 1); */
+		retval = __do_config_autodelink(us, &value, 1);
+		if (retval < 0)
+			return -EIO;
+
+		retval = enable_oscillator(us);
+		if (retval == 0)
+			(void)do_config_autodelink(us, 1, 0);
+	} else {
+		/* Autodelink controlled by firmware */
+
+		SET_BIT(value, 2);
+
+		if (CHECK_ID(chip, 0x0138, 0x3882))
+			CLR_BIT(value, 2);
+
+		if (CHECK_ID(chip, 0x0159, 0x5889) ||
+		    CHECK_ID(chip, 0x0138, 0x3880)) {
+			CLR_BIT(value, 0);
+			CLR_BIT(value, 7);
+		}
+
+		/* retval = rts51x_write_mem(us, 0xFE47, &value, 1); */
+		retval = __do_config_autodelink(us, &value, 1);
+		if (retval < 0)
+			return -EIO;
+
+		if (CHECK_ID(chip, 0x0159, 0x5888)) {
+			value = 0xFF;
+			retval = rts51x_write_mem(us, 0xFE79, &value, 1);
+			if (retval < 0)
+				return -EIO;
+
+			value = 0x01;
+			retval = rts51x_write_mem(us, 0x48, &value, 1);
+			if (retval < 0)
+				return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int config_autodelink_before_power_down(struct us_data *us)
+{
+	struct rts51x_chip *chip = (struct rts51x_chip *)(us->extra);
+	int retval;
+	u8 value;
+
+	if (!CHK_AUTO_DELINK(chip))
+		return 0;
+
+	if (auto_delink_en) {
+		retval = rts51x_read_mem(us, 0xFE77, &value, 1);
+		if (retval < 0)
+			return -EIO;
+
+		SET_BIT(value, 2);
+		retval = rts51x_write_mem(us, 0xFE77, &value, 1);
+		if (retval < 0)
+			return -EIO;
+
+		if (CHECK_ID(chip, 0x0159, 0x5888)) {
+			value = 0x01;
+			retval = rts51x_write_mem(us, 0x48, &value, 1);
+			if (retval < 0)
+				return -EIO;
+		}
+
+		retval = rts51x_read_mem(us, 0xFE47, &value, 1);
+		if (retval < 0)
+			return -EIO;
+
+		SET_BIT(value, 0);
+		if (CHECK_ID(chip, 0x0138, 0x3882))
+			SET_BIT(value, 2);
+		retval = rts51x_write_mem(us, 0xFE77, &value, 1);
+		if (retval < 0)
+			return -EIO;
+	} else {
+		if (CHECK_ID(chip, 0x0159, 0x5889) ||
+		    CHECK_ID(chip, 0x0138, 0x3880) ||
+		    CHECK_ID(chip, 0x0138, 0x3882)) {
+			retval = rts51x_read_mem(us, 0xFE47, &value, 1);
+			if (retval < 0)
+				return -EIO;
+
+			if (CHECK_ID(chip, 0x0159, 0x5889) ||
+			    CHECK_ID(chip, 0x0138, 0x3880)) {
+				SET_BIT(value, 0);
+				SET_BIT(value, 7);
+			}
+
+			if (CHECK_ID(chip, 0x0138, 0x3882))
+				SET_BIT(value, 2);
+
+			/* retval = rts51x_write_mem(us, 0xFE47, &value, 1); */
+			retval = __do_config_autodelink(us, &value, 1);
+			if (retval < 0)
+				return -EIO;
+		}
+
+		if (CHECK_ID(chip, 0x0159, 0x5888)) {
+			value = 0x01;
+			retval = rts51x_write_mem(us, 0x48, &value, 1);
+			if (retval < 0)
+				return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+static void fw5895_init(struct us_data *us)
+{
+	struct rts51x_chip *chip = (struct rts51x_chip *)(us->extra);
+	int retval;
+	u8 val;
+
+	if ((PRODUCT_ID(chip) != 0x0158) || (FW_VERSION(chip) != 0x5895)) {
+		usb_stor_dbg(us, "Not the specified device, return immediately!\n");
+	} else {
+		retval = rts51x_read_mem(us, 0xFD6F, &val, 1);
+		if (retval == STATUS_SUCCESS && (val & 0x1F) == 0) {
+			val = 0x1F;
+			retval = rts51x_write_mem(us, 0xFD70, &val, 1);
+			if (retval != STATUS_SUCCESS)
+				usb_stor_dbg(us, "Write memory fail\n");
+		} else {
+			usb_stor_dbg(us, "Read memory fail, OR (val & 0x1F) != 0\n");
+		}
+	}
+}
+#endif
+
+#ifdef CONFIG_REALTEK_AUTOPM
+static void fw5895_set_mmc_wp(struct us_data *us)
+{
+	struct rts51x_chip *chip = (struct rts51x_chip *)(us->extra);
+	int retval;
+	u8 buf[13];
+
+	if ((PRODUCT_ID(chip) != 0x0158) || (FW_VERSION(chip) != 0x5895)) {
+		usb_stor_dbg(us, "Not the specified device, return immediately!\n");
+	} else {
+		retval = rts51x_read_mem(us, 0xFD6F, buf, 1);
+		if (retval == STATUS_SUCCESS && (buf[0] & 0x24) == 0x24) {
+			/* SD Exist and SD WP */
+			retval = rts51x_read_mem(us, 0xD04E, buf, 1);
+			if (retval == STATUS_SUCCESS) {
+				buf[0] |= 0x04;
+				retval = rts51x_write_mem(us, 0xFD70, buf, 1);
+				if (retval != STATUS_SUCCESS)
+					usb_stor_dbg(us, "Write memory fail\n");
+			} else {
+				usb_stor_dbg(us, "Read memory fail\n");
+			}
+		} else {
+			usb_stor_dbg(us, "Read memory fail, OR (buf[0]&0x24)!=0x24\n");
+		}
+	}
+}
+
+static void rts51x_modi_suspend_timer(struct rts51x_chip *chip)
+{
+	struct us_data *us = chip->us;
+
+	usb_stor_dbg(us, "state:%d\n", rts51x_get_stat(chip));
+
+	chip->timer_expires = jiffies + msecs_to_jiffies(1000*ss_delay);
+	mod_timer(&chip->rts51x_suspend_timer, chip->timer_expires);
+}
+
+static void rts51x_suspend_timer_fn(struct timer_list *t)
+{
+	struct rts51x_chip *chip = from_timer(chip, t, rts51x_suspend_timer);
+	struct us_data *us = chip->us;
+
+	switch (rts51x_get_stat(chip)) {
+	case RTS51X_STAT_INIT:
+	case RTS51X_STAT_RUN:
+		rts51x_modi_suspend_timer(chip);
+		break;
+	case RTS51X_STAT_IDLE:
+	case RTS51X_STAT_SS:
+		usb_stor_dbg(us, "RTS51X_STAT_SS, intf->pm_usage_cnt:%d, power.usage:%d\n",
+			     atomic_read(&us->pusb_intf->pm_usage_cnt),
+			     atomic_read(&us->pusb_intf->dev.power.usage_count));
+
+		if (atomic_read(&us->pusb_intf->pm_usage_cnt) > 0) {
+			usb_stor_dbg(us, "Ready to enter SS state\n");
+			rts51x_set_stat(chip, RTS51X_STAT_SS);
+			/* ignore mass storage interface's children */
+			pm_suspend_ignore_children(&us->pusb_intf->dev, true);
+			usb_autopm_put_interface_async(us->pusb_intf);
+			usb_stor_dbg(us, "RTS51X_STAT_SS 01, intf->pm_usage_cnt:%d, power.usage:%d\n",
+				     atomic_read(&us->pusb_intf->pm_usage_cnt),
+				     atomic_read(&us->pusb_intf->dev.power.usage_count));
+		}
+		break;
+	default:
+		usb_stor_dbg(us, "Unknown state !!!\n");
+		break;
+	}
+}
+
+static inline int working_scsi(struct scsi_cmnd *srb)
+{
+	if ((srb->cmnd[0] == TEST_UNIT_READY) ||
+	    (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL)) {
+		return 0;
+	}
+
+	return 1;
+}
+
+static void rts51x_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+	struct rts51x_chip *chip = (struct rts51x_chip *)(us->extra);
+	static int card_first_show = 1;
+	static u8 media_not_present[] = { 0x70, 0, 0x02, 0, 0, 0, 0,
+		10, 0, 0, 0, 0, 0x3A, 0, 0, 0, 0, 0
+	};
+	static u8 invalid_cmd_field[] = { 0x70, 0, 0x05, 0, 0, 0, 0,
+		10, 0, 0, 0, 0, 0x24, 0, 0, 0, 0, 0
+	};
+	int ret;
+
+	if (working_scsi(srb)) {
+		usb_stor_dbg(us, "working scsi, intf->pm_usage_cnt:%d, power.usage:%d\n",
+			     atomic_read(&us->pusb_intf->pm_usage_cnt),
+			     atomic_read(&us->pusb_intf->dev.power.usage_count));
+
+		if (atomic_read(&us->pusb_intf->pm_usage_cnt) <= 0) {
+			ret = usb_autopm_get_interface(us->pusb_intf);
+			usb_stor_dbg(us, "working scsi, ret=%d\n", ret);
+		}
+		if (rts51x_get_stat(chip) != RTS51X_STAT_RUN)
+			rts51x_set_stat(chip, RTS51X_STAT_RUN);
+		chip->proto_handler_backup(srb, us);
+	} else {
+		if (rts51x_get_stat(chip) == RTS51X_STAT_SS) {
+			usb_stor_dbg(us, "NOT working scsi\n");
+			if ((srb->cmnd[0] == TEST_UNIT_READY) &&
+			    (chip->pwr_state == US_SUSPEND)) {
+				if (TST_LUN_READY(chip, srb->device->lun)) {
+					srb->result = SAM_STAT_GOOD;
+				} else {
+					srb->result = SAM_STAT_CHECK_CONDITION;
+					memcpy(srb->sense_buffer,
+					       media_not_present,
+					       US_SENSE_SIZE);
+				}
+				usb_stor_dbg(us, "TEST_UNIT_READY\n");
+				goto out;
+			}
+			if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
+				int prevent = srb->cmnd[4] & 0x1;
+				if (prevent) {
+					srb->result = SAM_STAT_CHECK_CONDITION;
+					memcpy(srb->sense_buffer,
+					       invalid_cmd_field,
+					       US_SENSE_SIZE);
+				} else {
+					srb->result = SAM_STAT_GOOD;
+				}
+				usb_stor_dbg(us, "ALLOW_MEDIUM_REMOVAL\n");
+				goto out;
+			}
+		} else {
+			usb_stor_dbg(us, "NOT working scsi, not SS\n");
+			chip->proto_handler_backup(srb, us);
+			/* Check whether card is plugged in */
+			if (srb->cmnd[0] == TEST_UNIT_READY) {
+				if (srb->result == SAM_STAT_GOOD) {
+					SET_LUN_READY(chip, srb->device->lun);
+					if (card_first_show) {
+						card_first_show = 0;
+						fw5895_set_mmc_wp(us);
+					}
+				} else {
+					CLR_LUN_READY(chip, srb->device->lun);
+					card_first_show = 1;
+				}
+			}
+			if (rts51x_get_stat(chip) != RTS51X_STAT_IDLE)
+				rts51x_set_stat(chip, RTS51X_STAT_IDLE);
+		}
+	}
+out:
+	usb_stor_dbg(us, "state:%d\n", rts51x_get_stat(chip));
+	if (rts51x_get_stat(chip) == RTS51X_STAT_RUN)
+		rts51x_modi_suspend_timer(chip);
+}
+
+static int realtek_cr_autosuspend_setup(struct us_data *us)
+{
+	struct rts51x_chip *chip;
+	struct rts51x_status *status = NULL;
+	u8 buf[16];
+	int retval;
+
+	chip = (struct rts51x_chip *)us->extra;
+	chip->support_auto_delink = 0;
+	chip->pwr_state = US_RESUME;
+	chip->lun_ready = 0;
+	rts51x_set_stat(chip, RTS51X_STAT_INIT);
+
+	retval = rts51x_read_status(us, 0, buf, 16, &(chip->status_len));
+	if (retval != STATUS_SUCCESS) {
+		usb_stor_dbg(us, "Read status fail\n");
+		return -EIO;
+	}
+	status = chip->status;
+	status->vid = ((u16) buf[0] << 8) | buf[1];
+	status->pid = ((u16) buf[2] << 8) | buf[3];
+	status->cur_lun = buf[4];
+	status->card_type = buf[5];
+	status->total_lun = buf[6];
+	status->fw_ver = ((u16) buf[7] << 8) | buf[8];
+	status->phy_exist = buf[9];
+	status->multi_flag = buf[10];
+	status->multi_card = buf[11];
+	status->log_exist = buf[12];
+	if (chip->status_len == 16) {
+		status->detailed_type.detailed_type1 = buf[13];
+		status->function[0] = buf[14];
+		status->function[1] = buf[15];
+	}
+
+	/* back up the proto_handler in us->extra */
+	chip = (struct rts51x_chip *)(us->extra);
+	chip->proto_handler_backup = us->proto_handler;
+	/* Set the autosuspend_delay to 0 */
+	pm_runtime_set_autosuspend_delay(&us->pusb_dev->dev, 0);
+	/* override us->proto_handler setted in get_protocol() */
+	us->proto_handler = rts51x_invoke_transport;
+
+	chip->timer_expires = 0;
+	timer_setup(&chip->rts51x_suspend_timer, rts51x_suspend_timer_fn, 0);
+	fw5895_init(us);
+
+	/* enable autosuspend function of the usb device */
+	usb_enable_autosuspend(us->pusb_dev);
+
+	return 0;
+}
+#endif
+
+static void realtek_cr_destructor(void *extra)
+{
+	struct rts51x_chip *chip = extra;
+
+	if (!chip)
+		return;
+
+#ifdef CONFIG_REALTEK_AUTOPM
+	if (ss_en) {
+		del_timer(&chip->rts51x_suspend_timer);
+		chip->timer_expires = 0;
+	}
+#endif
+	kfree(chip->status);
+}
+
+#ifdef CONFIG_PM
+static int realtek_cr_suspend(struct usb_interface *iface, pm_message_t message)
+{
+	struct us_data *us = usb_get_intfdata(iface);
+
+	/* wait until no command is running */
+	mutex_lock(&us->dev_mutex);
+
+	config_autodelink_before_power_down(us);
+
+	mutex_unlock(&us->dev_mutex);
+
+	return 0;
+}
+
+static int realtek_cr_resume(struct usb_interface *iface)
+{
+	struct us_data *us = usb_get_intfdata(iface);
+
+	fw5895_init(us);
+	config_autodelink_after_power_on(us);
+
+	return 0;
+}
+#else
+#define realtek_cr_suspend	NULL
+#define realtek_cr_resume	NULL
+#endif
+
+static int init_realtek_cr(struct us_data *us)
+{
+	struct rts51x_chip *chip;
+	int size, i, retval;
+
+	chip = kzalloc(sizeof(struct rts51x_chip), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	us->extra = chip;
+	us->extra_destructor = realtek_cr_destructor;
+	us->max_lun = chip->max_lun = rts51x_get_max_lun(us);
+	chip->us = us;
+
+	usb_stor_dbg(us, "chip->max_lun = %d\n", chip->max_lun);
+
+	size = (chip->max_lun + 1) * sizeof(struct rts51x_status);
+	chip->status = kzalloc(size, GFP_KERNEL);
+	if (!chip->status)
+		goto INIT_FAIL;
+
+	for (i = 0; i <= (int)(chip->max_lun); i++) {
+		retval = rts51x_check_status(us, (u8) i);
+		if (retval < 0)
+			goto INIT_FAIL;
+	}
+
+	if (CHECK_FW_VER(chip, 0x5888) || CHECK_FW_VER(chip, 0x5889) ||
+	    CHECK_FW_VER(chip, 0x5901))
+		SET_AUTO_DELINK(chip);
+	if (STATUS_LEN(chip) == 16) {
+		if (SUPPORT_AUTO_DELINK(chip))
+			SET_AUTO_DELINK(chip);
+	}
+#ifdef CONFIG_REALTEK_AUTOPM
+	if (ss_en)
+		realtek_cr_autosuspend_setup(us);
+#endif
+
+	usb_stor_dbg(us, "chip->flag = 0x%x\n", chip->flag);
+
+	(void)config_autodelink_after_power_on(us);
+
+	return 0;
+
+INIT_FAIL:
+	if (us->extra) {
+		kfree(chip->status);
+		kfree(us->extra);
+		us->extra = NULL;
+	}
+
+	return -EIO;
+}
+
+static struct scsi_host_template realtek_cr_host_template;
+
+static int realtek_cr_probe(struct usb_interface *intf,
+			    const struct usb_device_id *id)
+{
+	struct us_data *us;
+	int result;
+
+	dev_dbg(&intf->dev, "Probe Realtek Card Reader!\n");
+
+	result = usb_stor_probe1(&us, intf, id,
+				 (id - realtek_cr_ids) +
+				 realtek_cr_unusual_dev_list,
+				 &realtek_cr_host_template);
+	if (result)
+		return result;
+
+	result = usb_stor_probe2(us);
+
+	return result;
+}
+
+static struct usb_driver realtek_cr_driver = {
+	.name = DRV_NAME,
+	.probe = realtek_cr_probe,
+	.disconnect = usb_stor_disconnect,
+	/* .suspend =      usb_stor_suspend, */
+	/* .resume =       usb_stor_resume, */
+	.reset_resume = usb_stor_reset_resume,
+	.suspend = realtek_cr_suspend,
+	.resume = realtek_cr_resume,
+	.pre_reset = usb_stor_pre_reset,
+	.post_reset = usb_stor_post_reset,
+	.id_table = realtek_cr_ids,
+	.soft_unbind = 1,
+	.supports_autosuspend = 1,
+	.no_dynamic_id = 1,
+};
+
+module_usb_stor_driver(realtek_cr_driver, realtek_cr_host_template, DRV_NAME);
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
new file mode 100644
index 0000000..e227bb5
--- /dev/null
+++ b/drivers/usb/storage/scsiglue.c
@@ -0,0 +1,679 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for USB Mass Storage compliant devices
+ * SCSI layer glue code
+ *
+ * Current development and maintenance by:
+ *   (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * Developed with the assistance of:
+ *   (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
+ *   (c) 2000 Stephen J. Gowdy (SGowdy@lbl.gov)
+ *
+ * Initial work by:
+ *   (c) 1999 Michael Gee (michael@linuxspecific.com)
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/mutex.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_devinfo.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_eh.h>
+
+#include "usb.h"
+#include "scsiglue.h"
+#include "debug.h"
+#include "transport.h"
+#include "protocol.h"
+
+/*
+ * Vendor IDs for companies that seem to include the READ CAPACITY bug
+ * in all their devices
+ */
+#define VENDOR_ID_NOKIA		0x0421
+#define VENDOR_ID_NIKON		0x04b0
+#define VENDOR_ID_PENTAX	0x0a17
+#define VENDOR_ID_MOTOROLA	0x22b8
+
+/***********************************************************************
+ * Host functions 
+ ***********************************************************************/
+
+static const char* host_info(struct Scsi_Host *host)
+{
+	struct us_data *us = host_to_us(host);
+	return us->scsi_name;
+}
+
+static int slave_alloc (struct scsi_device *sdev)
+{
+	struct us_data *us = host_to_us(sdev->host);
+
+	/*
+	 * Set the INQUIRY transfer length to 36.  We don't use any of
+	 * the extra data and many devices choke if asked for more or
+	 * less than 36 bytes.
+	 */
+	sdev->inquiry_len = 36;
+
+	/*
+	 * USB has unusual DMA-alignment requirements: Although the
+	 * starting address of each scatter-gather element doesn't matter,
+	 * the length of each element except the last must be divisible
+	 * by the Bulk maxpacket value.  There's currently no way to
+	 * express this by block-layer constraints, so we'll cop out
+	 * and simply require addresses to be aligned at 512-byte
+	 * boundaries.  This is okay since most block I/O involves
+	 * hardware sectors that are multiples of 512 bytes in length,
+	 * and since host controllers up through USB 2.0 have maxpacket
+	 * values no larger than 512.
+	 *
+	 * But it doesn't suffice for Wireless USB, where Bulk maxpacket
+	 * values can be as large as 2048.  To make that work properly
+	 * will require changes to the block layer.
+	 */
+	blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1));
+
+	/* Tell the SCSI layer if we know there is more than one LUN */
+	if (us->protocol == USB_PR_BULK && us->max_lun > 0)
+		sdev->sdev_bflags |= BLIST_FORCELUN;
+
+	return 0;
+}
+
+static int slave_configure(struct scsi_device *sdev)
+{
+	struct us_data *us = host_to_us(sdev->host);
+
+	/*
+	 * Many devices have trouble transferring more than 32KB at a time,
+	 * while others have trouble with more than 64K. At this time we
+	 * are limiting both to 32K (64 sectores).
+	 */
+	if (us->fflags & (US_FL_MAX_SECTORS_64 | US_FL_MAX_SECTORS_MIN)) {
+		unsigned int max_sectors = 64;
+
+		if (us->fflags & US_FL_MAX_SECTORS_MIN)
+			max_sectors = PAGE_SIZE >> 9;
+		if (queue_max_hw_sectors(sdev->request_queue) > max_sectors)
+			blk_queue_max_hw_sectors(sdev->request_queue,
+					      max_sectors);
+	} else if (sdev->type == TYPE_TAPE) {
+		/*
+		 * Tapes need much higher max_sector limits, so just
+		 * raise it to the maximum possible (4 GB / 512) and
+		 * let the queue segment size sort out the real limit.
+		 */
+		blk_queue_max_hw_sectors(sdev->request_queue, 0x7FFFFF);
+	} else if (us->pusb_dev->speed >= USB_SPEED_SUPER) {
+		/*
+		 * USB3 devices will be limited to 2048 sectors. This gives us
+		 * better throughput on most devices.
+		 */
+		blk_queue_max_hw_sectors(sdev->request_queue, 2048);
+	}
+
+	/*
+	 * Some USB host controllers can't do DMA; they have to use PIO.
+	 * They indicate this by setting their dma_mask to NULL.  For
+	 * such controllers we need to make sure the block layer sets
+	 * up bounce buffers in addressable memory.
+	 */
+	if (!us->pusb_dev->bus->controller->dma_mask)
+		blk_queue_bounce_limit(sdev->request_queue, BLK_BOUNCE_HIGH);
+
+	/*
+	 * We can't put these settings in slave_alloc() because that gets
+	 * called before the device type is known.  Consequently these
+	 * settings can't be overridden via the scsi devinfo mechanism.
+	 */
+	if (sdev->type == TYPE_DISK) {
+
+		/*
+		 * Some vendors seem to put the READ CAPACITY bug into
+		 * all their devices -- primarily makers of cell phones
+		 * and digital cameras.  Since these devices always use
+		 * flash media and can be expected to have an even number
+		 * of sectors, we will always enable the CAPACITY_HEURISTICS
+		 * flag unless told otherwise.
+		 */
+		switch (le16_to_cpu(us->pusb_dev->descriptor.idVendor)) {
+		case VENDOR_ID_NOKIA:
+		case VENDOR_ID_NIKON:
+		case VENDOR_ID_PENTAX:
+		case VENDOR_ID_MOTOROLA:
+			if (!(us->fflags & (US_FL_FIX_CAPACITY |
+					US_FL_CAPACITY_OK)))
+				us->fflags |= US_FL_CAPACITY_HEURISTICS;
+			break;
+		}
+
+		/*
+		 * Disk-type devices use MODE SENSE(6) if the protocol
+		 * (SubClass) is Transparent SCSI, otherwise they use
+		 * MODE SENSE(10).
+		 */
+		if (us->subclass != USB_SC_SCSI && us->subclass != USB_SC_CYP_ATACB)
+			sdev->use_10_for_ms = 1;
+
+		/*
+		 *Many disks only accept MODE SENSE transfer lengths of
+		 * 192 bytes (that's what Windows uses).
+		 */
+		sdev->use_192_bytes_for_3f = 1;
+
+		/*
+		 * Some devices don't like MODE SENSE with page=0x3f,
+		 * which is the command used for checking if a device
+		 * is write-protected.  Now that we tell the sd driver
+		 * to do a 192-byte transfer with this command the
+		 * majority of devices work fine, but a few still can't
+		 * handle it.  The sd driver will simply assume those
+		 * devices are write-enabled.
+		 */
+		if (us->fflags & US_FL_NO_WP_DETECT)
+			sdev->skip_ms_page_3f = 1;
+
+		/*
+		 * A number of devices have problems with MODE SENSE for
+		 * page x08, so we will skip it.
+		 */
+		sdev->skip_ms_page_8 = 1;
+
+		/* Some devices don't handle VPD pages correctly */
+		sdev->skip_vpd_pages = 1;
+
+		/* Do not attempt to use REPORT SUPPORTED OPERATION CODES */
+		sdev->no_report_opcodes = 1;
+
+		/* Do not attempt to use WRITE SAME */
+		sdev->no_write_same = 1;
+
+		/*
+		 * Some disks return the total number of blocks in response
+		 * to READ CAPACITY rather than the highest block number.
+		 * If this device makes that mistake, tell the sd driver.
+		 */
+		if (us->fflags & US_FL_FIX_CAPACITY)
+			sdev->fix_capacity = 1;
+
+		/*
+		 * A few disks have two indistinguishable version, one of
+		 * which reports the correct capacity and the other does not.
+		 * The sd driver has to guess which is the case.
+		 */
+		if (us->fflags & US_FL_CAPACITY_HEURISTICS)
+			sdev->guess_capacity = 1;
+
+		/* Some devices cannot handle READ_CAPACITY_16 */
+		if (us->fflags & US_FL_NO_READ_CAPACITY_16)
+			sdev->no_read_capacity_16 = 1;
+
+		/*
+		 * Many devices do not respond properly to READ_CAPACITY_16.
+		 * Tell the SCSI layer to try READ_CAPACITY_10 first.
+		 * However some USB 3.0 drive enclosures return capacity
+		 * modulo 2TB. Those must use READ_CAPACITY_16
+		 */
+		if (!(us->fflags & US_FL_NEEDS_CAP16))
+			sdev->try_rc_10_first = 1;
+
+		/* assume SPC3 or latter devices support sense size > 18 */
+		if (sdev->scsi_level > SCSI_SPC_2)
+			us->fflags |= US_FL_SANE_SENSE;
+
+		/*
+		 * USB-IDE bridges tend to report SK = 0x04 (Non-recoverable
+		 * Hardware Error) when any low-level error occurs,
+		 * recoverable or not.  Setting this flag tells the SCSI
+		 * midlayer to retry such commands, which frequently will
+		 * succeed and fix the error.  The worst this can lead to
+		 * is an occasional series of retries that will all fail.
+		 */
+		sdev->retry_hwerror = 1;
+
+		/*
+		 * USB disks should allow restart.  Some drives spin down
+		 * automatically, requiring a START-STOP UNIT command.
+		 */
+		sdev->allow_restart = 1;
+
+		/*
+		 * Some USB cardreaders have trouble reading an sdcard's last
+		 * sector in a larger then 1 sector read, since the performance
+		 * impact is negligible we set this flag for all USB disks
+		 */
+		sdev->last_sector_bug = 1;
+
+		/*
+		 * Enable last-sector hacks for single-target devices using
+		 * the Bulk-only transport, unless we already know the
+		 * capacity will be decremented or is correct.
+		 */
+		if (!(us->fflags & (US_FL_FIX_CAPACITY | US_FL_CAPACITY_OK |
+					US_FL_SCM_MULT_TARG)) &&
+				us->protocol == USB_PR_BULK)
+			us->use_last_sector_hacks = 1;
+
+		/* Check if write cache default on flag is set or not */
+		if (us->fflags & US_FL_WRITE_CACHE)
+			sdev->wce_default_on = 1;
+
+		/* A few buggy USB-ATA bridges don't understand FUA */
+		if (us->fflags & US_FL_BROKEN_FUA)
+			sdev->broken_fua = 1;
+
+		/* Some even totally fail to indicate a cache */
+		if (us->fflags & US_FL_ALWAYS_SYNC) {
+			/* don't read caching information */
+			sdev->skip_ms_page_8 = 1;
+			sdev->skip_ms_page_3f = 1;
+			/* assume sync is needed */
+			sdev->wce_default_on = 1;
+		}
+	} else {
+
+		/*
+		 * Non-disk-type devices don't need to blacklist any pages
+		 * or to force 192-byte transfer lengths for MODE SENSE.
+		 * But they do need to use MODE SENSE(10).
+		 */
+		sdev->use_10_for_ms = 1;
+
+		/* Some (fake) usb cdrom devices don't like READ_DISC_INFO */
+		if (us->fflags & US_FL_NO_READ_DISC_INFO)
+			sdev->no_read_disc_info = 1;
+	}
+
+	/*
+	 * The CB and CBI transports have no way to pass LUN values
+	 * other than the bits in the second byte of a CDB.  But those
+	 * bits don't get set to the LUN value if the device reports
+	 * scsi_level == 0 (UNKNOWN).  Hence such devices must necessarily
+	 * be single-LUN.
+	 */
+	if ((us->protocol == USB_PR_CB || us->protocol == USB_PR_CBI) &&
+			sdev->scsi_level == SCSI_UNKNOWN)
+		us->max_lun = 0;
+
+	/*
+	 * Some devices choke when they receive a PREVENT-ALLOW MEDIUM
+	 * REMOVAL command, so suppress those commands.
+	 */
+	if (us->fflags & US_FL_NOT_LOCKABLE)
+		sdev->lockable = 0;
+
+	/*
+	 * this is to satisfy the compiler, tho I don't think the 
+	 * return code is ever checked anywhere.
+	 */
+	return 0;
+}
+
+static int target_alloc(struct scsi_target *starget)
+{
+	struct us_data *us = host_to_us(dev_to_shost(starget->dev.parent));
+
+	/*
+	 * Some USB drives don't support REPORT LUNS, even though they
+	 * report a SCSI revision level above 2.  Tell the SCSI layer
+	 * not to issue that command; it will perform a normal sequential
+	 * scan instead.
+	 */
+	starget->no_report_luns = 1;
+
+	/*
+	 * The UFI spec treats the Peripheral Qualifier bits in an
+	 * INQUIRY result as reserved and requires devices to set them
+	 * to 0.  However the SCSI spec requires these bits to be set
+	 * to 3 to indicate when a LUN is not present.
+	 *
+	 * Let the scanning code know if this target merely sets
+	 * Peripheral Device Type to 0x1f to indicate no LUN.
+	 */
+	if (us->subclass == USB_SC_UFI)
+		starget->pdt_1f_for_no_lun = 1;
+
+	return 0;
+}
+
+/* queue a command */
+/* This is always called with scsi_lock(host) held */
+static int queuecommand_lck(struct scsi_cmnd *srb,
+			void (*done)(struct scsi_cmnd *))
+{
+	struct us_data *us = host_to_us(srb->device->host);
+
+	/* check for state-transition errors */
+	if (us->srb != NULL) {
+		printk(KERN_ERR USB_STORAGE "Error in %s: us->srb = %p\n",
+			__func__, us->srb);
+		return SCSI_MLQUEUE_HOST_BUSY;
+	}
+
+	/* fail the command if we are disconnecting */
+	if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
+		usb_stor_dbg(us, "Fail command during disconnect\n");
+		srb->result = DID_NO_CONNECT << 16;
+		done(srb);
+		return 0;
+	}
+
+	if ((us->fflags & US_FL_NO_ATA_1X) &&
+			(srb->cmnd[0] == ATA_12 || srb->cmnd[0] == ATA_16)) {
+		memcpy(srb->sense_buffer, usb_stor_sense_invalidCDB,
+		       sizeof(usb_stor_sense_invalidCDB));
+		srb->result = SAM_STAT_CHECK_CONDITION;
+		done(srb);
+		return 0;
+	}
+
+	/* enqueue the command and wake up the control thread */
+	srb->scsi_done = done;
+	us->srb = srb;
+	complete(&us->cmnd_ready);
+
+	return 0;
+}
+
+static DEF_SCSI_QCMD(queuecommand)
+
+/***********************************************************************
+ * Error handling functions
+ ***********************************************************************/
+
+/* Command timeout and abort */
+static int command_abort(struct scsi_cmnd *srb)
+{
+	struct us_data *us = host_to_us(srb->device->host);
+
+	usb_stor_dbg(us, "%s called\n", __func__);
+
+	/*
+	 * us->srb together with the TIMED_OUT, RESETTING, and ABORTING
+	 * bits are protected by the host lock.
+	 */
+	scsi_lock(us_to_host(us));
+
+	/* Is this command still active? */
+	if (us->srb != srb) {
+		scsi_unlock(us_to_host(us));
+		usb_stor_dbg(us, "-- nothing to abort\n");
+		return FAILED;
+	}
+
+	/*
+	 * Set the TIMED_OUT bit.  Also set the ABORTING bit, but only if
+	 * a device reset isn't already in progress (to avoid interfering
+	 * with the reset).  Note that we must retain the host lock while
+	 * calling usb_stor_stop_transport(); otherwise it might interfere
+	 * with an auto-reset that begins as soon as we release the lock.
+	 */
+	set_bit(US_FLIDX_TIMED_OUT, &us->dflags);
+	if (!test_bit(US_FLIDX_RESETTING, &us->dflags)) {
+		set_bit(US_FLIDX_ABORTING, &us->dflags);
+		usb_stor_stop_transport(us);
+	}
+	scsi_unlock(us_to_host(us));
+
+	/* Wait for the aborted command to finish */
+	wait_for_completion(&us->notify);
+	return SUCCESS;
+}
+
+/*
+ * This invokes the transport reset mechanism to reset the state of the
+ * device
+ */
+static int device_reset(struct scsi_cmnd *srb)
+{
+	struct us_data *us = host_to_us(srb->device->host);
+	int result;
+
+	usb_stor_dbg(us, "%s called\n", __func__);
+
+	/* lock the device pointers and do the reset */
+	mutex_lock(&(us->dev_mutex));
+	result = us->transport_reset(us);
+	mutex_unlock(&us->dev_mutex);
+
+	return result < 0 ? FAILED : SUCCESS;
+}
+
+/* Simulate a SCSI bus reset by resetting the device's USB port. */
+static int bus_reset(struct scsi_cmnd *srb)
+{
+	struct us_data *us = host_to_us(srb->device->host);
+	int result;
+
+	usb_stor_dbg(us, "%s called\n", __func__);
+
+	result = usb_stor_port_reset(us);
+	return result < 0 ? FAILED : SUCCESS;
+}
+
+/*
+ * Report a driver-initiated device reset to the SCSI layer.
+ * Calling this for a SCSI-initiated reset is unnecessary but harmless.
+ * The caller must own the SCSI host lock.
+ */
+void usb_stor_report_device_reset(struct us_data *us)
+{
+	int i;
+	struct Scsi_Host *host = us_to_host(us);
+
+	scsi_report_device_reset(host, 0, 0);
+	if (us->fflags & US_FL_SCM_MULT_TARG) {
+		for (i = 1; i < host->max_id; ++i)
+			scsi_report_device_reset(host, 0, i);
+	}
+}
+
+/*
+ * Report a driver-initiated bus reset to the SCSI layer.
+ * Calling this for a SCSI-initiated reset is unnecessary but harmless.
+ * The caller must not own the SCSI host lock.
+ */
+void usb_stor_report_bus_reset(struct us_data *us)
+{
+	struct Scsi_Host *host = us_to_host(us);
+
+	scsi_lock(host);
+	scsi_report_bus_reset(host, 0);
+	scsi_unlock(host);
+}
+
+/***********************************************************************
+ * /proc/scsi/ functions
+ ***********************************************************************/
+
+static int write_info(struct Scsi_Host *host, char *buffer, int length)
+{
+	/* if someone is sending us data, just throw it away */
+	return length;
+}
+
+static int show_info (struct seq_file *m, struct Scsi_Host *host)
+{
+	struct us_data *us = host_to_us(host);
+	const char *string;
+
+	/* print the controller name */
+	seq_printf(m, "   Host scsi%d: usb-storage\n", host->host_no);
+
+	/* print product, vendor, and serial number strings */
+	if (us->pusb_dev->manufacturer)
+		string = us->pusb_dev->manufacturer;
+	else if (us->unusual_dev->vendorName)
+		string = us->unusual_dev->vendorName;
+	else
+		string = "Unknown";
+	seq_printf(m, "       Vendor: %s\n", string);
+	if (us->pusb_dev->product)
+		string = us->pusb_dev->product;
+	else if (us->unusual_dev->productName)
+		string = us->unusual_dev->productName;
+	else
+		string = "Unknown";
+	seq_printf(m, "      Product: %s\n", string);
+	if (us->pusb_dev->serial)
+		string = us->pusb_dev->serial;
+	else
+		string = "None";
+	seq_printf(m, "Serial Number: %s\n", string);
+
+	/* show the protocol and transport */
+	seq_printf(m, "     Protocol: %s\n", us->protocol_name);
+	seq_printf(m, "    Transport: %s\n", us->transport_name);
+
+	/* show the device flags */
+	seq_printf(m, "       Quirks:");
+
+#define US_FLAG(name, value) \
+	if (us->fflags & value) seq_printf(m, " " #name);
+US_DO_ALL_FLAGS
+#undef US_FLAG
+	seq_putc(m, '\n');
+	return 0;
+}
+
+/***********************************************************************
+ * Sysfs interface
+ ***********************************************************************/
+
+/* Output routine for the sysfs max_sectors file */
+static ssize_t max_sectors_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct scsi_device *sdev = to_scsi_device(dev);
+
+	return sprintf(buf, "%u\n", queue_max_hw_sectors(sdev->request_queue));
+}
+
+/* Input routine for the sysfs max_sectors file */
+static ssize_t max_sectors_store(struct device *dev, struct device_attribute *attr, const char *buf,
+		size_t count)
+{
+	struct scsi_device *sdev = to_scsi_device(dev);
+	unsigned short ms;
+
+	if (sscanf(buf, "%hu", &ms) > 0) {
+		blk_queue_max_hw_sectors(sdev->request_queue, ms);
+		return count;
+	}
+	return -EINVAL;
+}
+static DEVICE_ATTR_RW(max_sectors);
+
+static struct device_attribute *sysfs_device_attr_list[] = {
+	&dev_attr_max_sectors,
+	NULL,
+};
+
+/*
+ * this defines our host template, with which we'll allocate hosts
+ */
+
+static const struct scsi_host_template usb_stor_host_template = {
+	/* basic userland interface stuff */
+	.name =				"usb-storage",
+	.proc_name =			"usb-storage",
+	.show_info =			show_info,
+	.write_info =			write_info,
+	.info =				host_info,
+
+	/* command interface -- queued only */
+	.queuecommand =			queuecommand,
+
+	/* error and abort handlers */
+	.eh_abort_handler =		command_abort,
+	.eh_device_reset_handler =	device_reset,
+	.eh_bus_reset_handler =		bus_reset,
+
+	/* queue commands only, only one command per LUN */
+	.can_queue =			1,
+
+	/* unknown initiator id */
+	.this_id =			-1,
+
+	.slave_alloc =			slave_alloc,
+	.slave_configure =		slave_configure,
+	.target_alloc =			target_alloc,
+
+	/* lots of sg segments can be handled */
+	.sg_tablesize =			SG_MAX_SEGMENTS,
+
+
+	/*
+	 * Limit the total size of a transfer to 120 KB.
+	 *
+	 * Some devices are known to choke with anything larger. It seems like
+	 * the problem stems from the fact that original IDE controllers had
+	 * only an 8-bit register to hold the number of sectors in one transfer
+	 * and even those couldn't handle a full 256 sectors.
+	 *
+	 * Because we want to make sure we interoperate with as many devices as
+	 * possible, we will maintain a 240 sector transfer size limit for USB
+	 * Mass Storage devices.
+	 *
+	 * Tests show that other operating have similar limits with Microsoft
+	 * Windows 7 limiting transfers to 128 sectors for both USB2 and USB3
+	 * and Apple Mac OS X 10.11 limiting transfers to 256 sectors for USB2
+	 * and 2048 for USB3 devices.
+	 */
+	.max_sectors =                  240,
+
+	/*
+	 * merge commands... this seems to help performance, but
+	 * periodically someone should test to see which setting is more
+	 * optimal.
+	 */
+	.use_clustering =		1,
+
+	/* emulated HBA */
+	.emulated =			1,
+
+	/* we do our own delay after a device or bus reset */
+	.skip_settle_delay =		1,
+
+	/* sysfs device attributes */
+	.sdev_attrs =			sysfs_device_attr_list,
+
+	/* module management */
+	.module =			THIS_MODULE
+};
+
+void usb_stor_host_template_init(struct scsi_host_template *sht,
+				 const char *name, struct module *owner)
+{
+	*sht = usb_stor_host_template;
+	sht->name = name;
+	sht->proc_name = name;
+	sht->module = owner;
+}
+EXPORT_SYMBOL_GPL(usb_stor_host_template_init);
+
+/* To Report "Illegal Request: Invalid Field in CDB */
+unsigned char usb_stor_sense_invalidCDB[18] = {
+	[0]	= 0x70,			    /* current error */
+	[2]	= ILLEGAL_REQUEST,	    /* Illegal Request = 0x05 */
+	[7]	= 0x0a,			    /* additional length */
+	[12]	= 0x24			    /* Invalid Field in CDB */
+};
+EXPORT_SYMBOL_GPL(usb_stor_sense_invalidCDB);
diff --git a/drivers/usb/storage/scsiglue.h b/drivers/usb/storage/scsiglue.h
new file mode 100644
index 0000000..2bc5ea0
--- /dev/null
+++ b/drivers/usb/storage/scsiglue.h
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for USB Mass Storage compliant devices
+ * SCSI Connecting Glue Header File
+ *
+ * Current development and maintenance by:
+ *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * 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.
+ */
+
+#ifndef _SCSIGLUE_H_
+#define _SCSIGLUE_H_
+
+extern void usb_stor_report_device_reset(struct us_data *us);
+extern void usb_stor_report_bus_reset(struct us_data *us);
+extern void usb_stor_host_template_init(struct scsi_host_template *sht,
+					const char *name, struct module *owner);
+
+extern unsigned char usb_stor_sense_invalidCDB[18];
+
+#endif
diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c
new file mode 100644
index 0000000..bc9da73
--- /dev/null
+++ b/drivers/usb/storage/sddr09.c
@@ -0,0 +1,1789 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for SanDisk SDDR-09 SmartMedia reader
+ *
+ *   (c) 2000, 2001 Robert Baruch (autophile@starband.net)
+ *   (c) 2002 Andries Brouwer (aeb@cwi.nl)
+ * Developed with the assistance of:
+ *   (c) 2002 Alan Stern <stern@rowland.org>
+ *
+ * The SanDisk SDDR-09 SmartMedia reader uses the Shuttle EUSB-01 chip.
+ * This chip is a programmable USB controller. In the SDDR-09, it has
+ * been programmed to obey a certain limited set of SCSI commands.
+ * This driver translates the "real" SCSI commands to the SDDR-09 SCSI
+ * commands.
+ */
+
+/*
+ * Known vendor commands: 12 bytes, first byte is opcode
+ *
+ * E7: read scatter gather
+ * E8: read
+ * E9: write
+ * EA: erase
+ * EB: reset
+ * EC: read status
+ * ED: read ID
+ * EE: write CIS (?)
+ * EF: compute checksum (?)
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "protocol.h"
+#include "debug.h"
+#include "scsiglue.h"
+
+#define DRV_NAME "ums-sddr09"
+
+MODULE_DESCRIPTION("Driver for SanDisk SDDR-09 SmartMedia reader");
+MODULE_AUTHOR("Andries Brouwer <aeb@cwi.nl>, Robert Baruch <autophile@starband.net>");
+MODULE_LICENSE("GPL");
+
+static int usb_stor_sddr09_dpcm_init(struct us_data *us);
+static int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us);
+static int usb_stor_sddr09_init(struct us_data *us);
+
+
+/*
+ * The table of devices
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+		    vendorName, productName, useProtocol, useTransport, \
+		    initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+  .driver_info = (flags) }
+
+static struct usb_device_id sddr09_usb_ids[] = {
+#	include "unusual_sddr09.h"
+	{ }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, sddr09_usb_ids);
+
+#undef UNUSUAL_DEV
+
+/*
+ * The flags table
+ */
+#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
+		    vendor_name, product_name, use_protocol, use_transport, \
+		    init_function, Flags) \
+{ \
+	.vendorName = vendor_name,	\
+	.productName = product_name,	\
+	.useProtocol = use_protocol,	\
+	.useTransport = use_transport,	\
+	.initFunction = init_function,	\
+}
+
+static struct us_unusual_dev sddr09_unusual_dev_list[] = {
+#	include "unusual_sddr09.h"
+	{ }		/* Terminating entry */
+};
+
+#undef UNUSUAL_DEV
+
+
+#define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) )
+#define LSB_of(s) ((s)&0xFF)
+#define MSB_of(s) ((s)>>8)
+
+/*
+ * First some stuff that does not belong here:
+ * data on SmartMedia and other cards, completely
+ * unrelated to this driver.
+ * Similar stuff occurs in <linux/mtd/nand_ids.h>.
+ */
+
+struct nand_flash_dev {
+	int model_id;
+	int chipshift;		/* 1<<cs bytes total capacity */
+	char pageshift;		/* 1<<ps bytes in a page */
+	char blockshift;	/* 1<<bs pages in an erase block */
+	char zoneshift;		/* 1<<zs blocks in a zone */
+				/* # of logical blocks is 125/128 of this */
+	char pageadrlen;	/* length of an address in bytes - 1 */
+};
+
+/*
+ * NAND Flash Manufacturer ID Codes
+ */
+#define NAND_MFR_AMD		0x01
+#define NAND_MFR_NATSEMI	0x8f
+#define NAND_MFR_TOSHIBA	0x98
+#define NAND_MFR_SAMSUNG	0xec
+
+static inline char *nand_flash_manufacturer(int manuf_id) {
+	switch(manuf_id) {
+	case NAND_MFR_AMD:
+		return "AMD";
+	case NAND_MFR_NATSEMI:
+		return "NATSEMI";
+	case NAND_MFR_TOSHIBA:
+		return "Toshiba";
+	case NAND_MFR_SAMSUNG:
+		return "Samsung";
+	default:
+		return "unknown";
+	}
+}
+
+/*
+ * It looks like it is unnecessary to attach manufacturer to the
+ * remaining data: SSFDC prescribes manufacturer-independent id codes.
+ *
+ * 256 MB NAND flash has a 5-byte ID with 2nd byte 0xaa, 0xba, 0xca or 0xda.
+ */
+
+static struct nand_flash_dev nand_flash_ids[] = {
+	/* NAND flash */
+	{ 0x6e, 20, 8, 4, 8, 2},	/* 1 MB */
+	{ 0xe8, 20, 8, 4, 8, 2},	/* 1 MB */
+	{ 0xec, 20, 8, 4, 8, 2},	/* 1 MB */
+	{ 0x64, 21, 8, 4, 9, 2}, 	/* 2 MB */
+	{ 0xea, 21, 8, 4, 9, 2},	/* 2 MB */
+	{ 0x6b, 22, 9, 4, 9, 2},	/* 4 MB */
+	{ 0xe3, 22, 9, 4, 9, 2},	/* 4 MB */
+	{ 0xe5, 22, 9, 4, 9, 2},	/* 4 MB */
+	{ 0xe6, 23, 9, 4, 10, 2},	/* 8 MB */
+	{ 0x73, 24, 9, 5, 10, 2},	/* 16 MB */
+	{ 0x75, 25, 9, 5, 10, 2},	/* 32 MB */
+	{ 0x76, 26, 9, 5, 10, 3},	/* 64 MB */
+	{ 0x79, 27, 9, 5, 10, 3},	/* 128 MB */
+
+	/* MASK ROM */
+	{ 0x5d, 21, 9, 4, 8, 2},	/* 2 MB */
+	{ 0xd5, 22, 9, 4, 9, 2},	/* 4 MB */
+	{ 0xd6, 23, 9, 4, 10, 2},	/* 8 MB */
+	{ 0x57, 24, 9, 4, 11, 2},	/* 16 MB */
+	{ 0x58, 25, 9, 4, 12, 2},	/* 32 MB */
+	{ 0,}
+};
+
+static struct nand_flash_dev *
+nand_find_id(unsigned char id) {
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(nand_flash_ids); i++)
+		if (nand_flash_ids[i].model_id == id)
+			return &(nand_flash_ids[i]);
+	return NULL;
+}
+
+/*
+ * ECC computation.
+ */
+static unsigned char parity[256];
+static unsigned char ecc2[256];
+
+static void nand_init_ecc(void) {
+	int i, j, a;
+
+	parity[0] = 0;
+	for (i = 1; i < 256; i++)
+		parity[i] = (parity[i&(i-1)] ^ 1);
+
+	for (i = 0; i < 256; i++) {
+		a = 0;
+		for (j = 0; j < 8; j++) {
+			if (i & (1<<j)) {
+				if ((j & 1) == 0)
+					a ^= 0x04;
+				if ((j & 2) == 0)
+					a ^= 0x10;
+				if ((j & 4) == 0)
+					a ^= 0x40;
+			}
+		}
+		ecc2[i] = ~(a ^ (a<<1) ^ (parity[i] ? 0xa8 : 0));
+	}
+}
+
+/* compute 3-byte ecc on 256 bytes */
+static void nand_compute_ecc(unsigned char *data, unsigned char *ecc) {
+	int i, j, a;
+	unsigned char par = 0, bit, bits[8] = {0};
+
+	/* collect 16 checksum bits */
+	for (i = 0; i < 256; i++) {
+		par ^= data[i];
+		bit = parity[data[i]];
+		for (j = 0; j < 8; j++)
+			if ((i & (1<<j)) == 0)
+				bits[j] ^= bit;
+	}
+
+	/* put 4+4+4 = 12 bits in the ecc */
+	a = (bits[3] << 6) + (bits[2] << 4) + (bits[1] << 2) + bits[0];
+	ecc[0] = ~(a ^ (a<<1) ^ (parity[par] ? 0xaa : 0));
+
+	a = (bits[7] << 6) + (bits[6] << 4) + (bits[5] << 2) + bits[4];
+	ecc[1] = ~(a ^ (a<<1) ^ (parity[par] ? 0xaa : 0));
+
+	ecc[2] = ecc2[par];
+}
+
+static int nand_compare_ecc(unsigned char *data, unsigned char *ecc) {
+	return (data[0] == ecc[0] && data[1] == ecc[1] && data[2] == ecc[2]);
+}
+
+static void nand_store_ecc(unsigned char *data, unsigned char *ecc) {
+	memcpy(data, ecc, 3);
+}
+
+/*
+ * The actual driver starts here.
+ */
+
+struct sddr09_card_info {
+	unsigned long	capacity;	/* Size of card in bytes */
+	int		pagesize;	/* Size of page in bytes */
+	int		pageshift;	/* log2 of pagesize */
+	int		blocksize;	/* Size of block in pages */
+	int		blockshift;	/* log2 of blocksize */
+	int		blockmask;	/* 2^blockshift - 1 */
+	int		*lba_to_pba;	/* logical to physical map */
+	int		*pba_to_lba;	/* physical to logical map */
+	int		lbact;		/* number of available pages */
+	int		flags;
+#define	SDDR09_WP	1		/* write protected */
+};
+
+/*
+ * On my 16MB card, control blocks have size 64 (16 real control bytes,
+ * and 48 junk bytes). In reality of course the card uses 16 control bytes,
+ * so the reader makes up the remaining 48. Don't know whether these numbers
+ * depend on the card. For now a constant.
+ */
+#define CONTROL_SHIFT 6
+
+/*
+ * On my Combo CF/SM reader, the SM reader has LUN 1.
+ * (and things fail with LUN 0).
+ * It seems LUN is irrelevant for others.
+ */
+#define LUN	1
+#define	LUNBITS	(LUN << 5)
+
+/*
+ * LBA and PBA are unsigned ints. Special values.
+ */
+#define UNDEF    0xffffffff
+#define SPARE    0xfffffffe
+#define UNUSABLE 0xfffffffd
+
+static const int erase_bad_lba_entries = 0;
+
+/* send vendor interface command (0x41) */
+/* called for requests 0, 1, 8 */
+static int
+sddr09_send_command(struct us_data *us,
+		    unsigned char request,
+		    unsigned char direction,
+		    unsigned char *xfer_data,
+		    unsigned int xfer_len) {
+	unsigned int pipe;
+	unsigned char requesttype = (0x41 | direction);
+	int rc;
+
+	// Get the receive or send control pipe number
+
+	if (direction == USB_DIR_IN)
+		pipe = us->recv_ctrl_pipe;
+	else
+		pipe = us->send_ctrl_pipe;
+
+	rc = usb_stor_ctrl_transfer(us, pipe, request, requesttype,
+				   0, 0, xfer_data, xfer_len);
+	switch (rc) {
+		case USB_STOR_XFER_GOOD:	return 0;
+		case USB_STOR_XFER_STALLED:	return -EPIPE;
+		default:			return -EIO;
+	}
+}
+
+static int
+sddr09_send_scsi_command(struct us_data *us,
+			 unsigned char *command,
+			 unsigned int command_len) {
+	return sddr09_send_command(us, 0, USB_DIR_OUT, command, command_len);
+}
+
+#if 0
+/*
+ * Test Unit Ready Command: 12 bytes.
+ * byte 0: opcode: 00
+ */
+static int
+sddr09_test_unit_ready(struct us_data *us) {
+	unsigned char *command = us->iobuf;
+	int result;
+
+	memset(command, 0, 6);
+	command[1] = LUNBITS;
+
+	result = sddr09_send_scsi_command(us, command, 6);
+
+	usb_stor_dbg(us, "sddr09_test_unit_ready returns %d\n", result);
+
+	return result;
+}
+#endif
+
+/*
+ * Request Sense Command: 12 bytes.
+ * byte 0: opcode: 03
+ * byte 4: data length
+ */
+static int
+sddr09_request_sense(struct us_data *us, unsigned char *sensebuf, int buflen) {
+	unsigned char *command = us->iobuf;
+	int result;
+
+	memset(command, 0, 12);
+	command[0] = 0x03;
+	command[1] = LUNBITS;
+	command[4] = buflen;
+
+	result = sddr09_send_scsi_command(us, command, 12);
+	if (result)
+		return result;
+
+	result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+			sensebuf, buflen, NULL);
+	return (result == USB_STOR_XFER_GOOD ? 0 : -EIO);
+}
+
+/*
+ * Read Command: 12 bytes.
+ * byte 0: opcode: E8
+ * byte 1: last two bits: 00: read data, 01: read blockwise control,
+ *			10: read both, 11: read pagewise control.
+ *	 It turns out we need values 20, 21, 22, 23 here (LUN 1).
+ * bytes 2-5: address (interpretation depends on byte 1, see below)
+ * bytes 10-11: count (idem)
+ *
+ * A page has 512 data bytes and 64 control bytes (16 control and 48 junk).
+ * A read data command gets data in 512-byte pages.
+ * A read control command gets control in 64-byte chunks.
+ * A read both command gets data+control in 576-byte chunks.
+ *
+ * Blocks are groups of 32 pages, and read blockwise control jumps to the
+ * next block, while read pagewise control jumps to the next page after
+ * reading a group of 64 control bytes.
+ * [Here 512 = 1<<pageshift, 32 = 1<<blockshift, 64 is constant?]
+ *
+ * (1 MB and 2 MB cards are a bit different, but I have only a 16 MB card.)
+ */
+
+static int
+sddr09_readX(struct us_data *us, int x, unsigned long fromaddress,
+	     int nr_of_pages, int bulklen, unsigned char *buf,
+	     int use_sg) {
+
+	unsigned char *command = us->iobuf;
+	int result;
+
+	command[0] = 0xE8;
+	command[1] = LUNBITS | x;
+	command[2] = MSB_of(fromaddress>>16);
+	command[3] = LSB_of(fromaddress>>16); 
+	command[4] = MSB_of(fromaddress & 0xFFFF);
+	command[5] = LSB_of(fromaddress & 0xFFFF); 
+	command[6] = 0;
+	command[7] = 0;
+	command[8] = 0;
+	command[9] = 0;
+	command[10] = MSB_of(nr_of_pages);
+	command[11] = LSB_of(nr_of_pages);
+
+	result = sddr09_send_scsi_command(us, command, 12);
+
+	if (result) {
+		usb_stor_dbg(us, "Result for send_control in sddr09_read2%d %d\n",
+			     x, result);
+		return result;
+	}
+
+	result = usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe,
+				       buf, bulklen, use_sg, NULL);
+
+	if (result != USB_STOR_XFER_GOOD) {
+		usb_stor_dbg(us, "Result for bulk_transfer in sddr09_read2%d %d\n",
+			     x, result);
+		return -EIO;
+	}
+	return 0;
+}
+
+/*
+ * Read Data
+ *
+ * fromaddress counts data shorts:
+ * increasing it by 256 shifts the bytestream by 512 bytes;
+ * the last 8 bits are ignored.
+ *
+ * nr_of_pages counts pages of size (1 << pageshift).
+ */
+static int
+sddr09_read20(struct us_data *us, unsigned long fromaddress,
+	      int nr_of_pages, int pageshift, unsigned char *buf, int use_sg) {
+	int bulklen = nr_of_pages << pageshift;
+
+	/* The last 8 bits of fromaddress are ignored. */
+	return sddr09_readX(us, 0, fromaddress, nr_of_pages, bulklen,
+			    buf, use_sg);
+}
+
+/*
+ * Read Blockwise Control
+ *
+ * fromaddress gives the starting position (as in read data;
+ * the last 8 bits are ignored); increasing it by 32*256 shifts
+ * the output stream by 64 bytes.
+ *
+ * count counts control groups of size (1 << controlshift).
+ * For me, controlshift = 6. Is this constant?
+ *
+ * After getting one control group, jump to the next block
+ * (fromaddress += 8192).
+ */
+static int
+sddr09_read21(struct us_data *us, unsigned long fromaddress,
+	      int count, int controlshift, unsigned char *buf, int use_sg) {
+
+	int bulklen = (count << controlshift);
+	return sddr09_readX(us, 1, fromaddress, count, bulklen,
+			    buf, use_sg);
+}
+
+/*
+ * Read both Data and Control
+ *
+ * fromaddress counts data shorts, ignoring control:
+ * increasing it by 256 shifts the bytestream by 576 = 512+64 bytes;
+ * the last 8 bits are ignored.
+ *
+ * nr_of_pages counts pages of size (1 << pageshift) + (1 << controlshift).
+ */
+static int
+sddr09_read22(struct us_data *us, unsigned long fromaddress,
+	      int nr_of_pages, int pageshift, unsigned char *buf, int use_sg) {
+
+	int bulklen = (nr_of_pages << pageshift) + (nr_of_pages << CONTROL_SHIFT);
+	usb_stor_dbg(us, "reading %d pages, %d bytes\n", nr_of_pages, bulklen);
+	return sddr09_readX(us, 2, fromaddress, nr_of_pages, bulklen,
+			    buf, use_sg);
+}
+
+#if 0
+/*
+ * Read Pagewise Control
+ *
+ * fromaddress gives the starting position (as in read data;
+ * the last 8 bits are ignored); increasing it by 256 shifts
+ * the output stream by 64 bytes.
+ *
+ * count counts control groups of size (1 << controlshift).
+ * For me, controlshift = 6. Is this constant?
+ *
+ * After getting one control group, jump to the next page
+ * (fromaddress += 256).
+ */
+static int
+sddr09_read23(struct us_data *us, unsigned long fromaddress,
+	      int count, int controlshift, unsigned char *buf, int use_sg) {
+
+	int bulklen = (count << controlshift);
+	return sddr09_readX(us, 3, fromaddress, count, bulklen,
+			    buf, use_sg);
+}
+#endif
+
+/*
+ * Erase Command: 12 bytes.
+ * byte 0: opcode: EA
+ * bytes 6-9: erase address (big-endian, counting shorts, sector aligned).
+ * 
+ * Always precisely one block is erased; bytes 2-5 and 10-11 are ignored.
+ * The byte address being erased is 2*Eaddress.
+ * The CIS cannot be erased.
+ */
+static int
+sddr09_erase(struct us_data *us, unsigned long Eaddress) {
+	unsigned char *command = us->iobuf;
+	int result;
+
+	usb_stor_dbg(us, "erase address %lu\n", Eaddress);
+
+	memset(command, 0, 12);
+	command[0] = 0xEA;
+	command[1] = LUNBITS;
+	command[6] = MSB_of(Eaddress>>16);
+	command[7] = LSB_of(Eaddress>>16);
+	command[8] = MSB_of(Eaddress & 0xFFFF);
+	command[9] = LSB_of(Eaddress & 0xFFFF);
+
+	result = sddr09_send_scsi_command(us, command, 12);
+
+	if (result)
+		usb_stor_dbg(us, "Result for send_control in sddr09_erase %d\n",
+			     result);
+
+	return result;
+}
+
+/*
+ * Write CIS Command: 12 bytes.
+ * byte 0: opcode: EE
+ * bytes 2-5: write address in shorts
+ * bytes 10-11: sector count
+ *
+ * This writes at the indicated address. Don't know how it differs
+ * from E9. Maybe it does not erase? However, it will also write to
+ * the CIS.
+ *
+ * When two such commands on the same page follow each other directly,
+ * the second one is not done.
+ */
+
+/*
+ * Write Command: 12 bytes.
+ * byte 0: opcode: E9
+ * bytes 2-5: write address (big-endian, counting shorts, sector aligned).
+ * bytes 6-9: erase address (big-endian, counting shorts, sector aligned).
+ * bytes 10-11: sector count (big-endian, in 512-byte sectors).
+ *
+ * If write address equals erase address, the erase is done first,
+ * otherwise the write is done first. When erase address equals zero
+ * no erase is done?
+ */
+static int
+sddr09_writeX(struct us_data *us,
+	      unsigned long Waddress, unsigned long Eaddress,
+	      int nr_of_pages, int bulklen, unsigned char *buf, int use_sg) {
+
+	unsigned char *command = us->iobuf;
+	int result;
+
+	command[0] = 0xE9;
+	command[1] = LUNBITS;
+
+	command[2] = MSB_of(Waddress>>16);
+	command[3] = LSB_of(Waddress>>16);
+	command[4] = MSB_of(Waddress & 0xFFFF);
+	command[5] = LSB_of(Waddress & 0xFFFF);
+
+	command[6] = MSB_of(Eaddress>>16);
+	command[7] = LSB_of(Eaddress>>16);
+	command[8] = MSB_of(Eaddress & 0xFFFF);
+	command[9] = LSB_of(Eaddress & 0xFFFF);
+
+	command[10] = MSB_of(nr_of_pages);
+	command[11] = LSB_of(nr_of_pages);
+
+	result = sddr09_send_scsi_command(us, command, 12);
+
+	if (result) {
+		usb_stor_dbg(us, "Result for send_control in sddr09_writeX %d\n",
+			     result);
+		return result;
+	}
+
+	result = usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe,
+				       buf, bulklen, use_sg, NULL);
+
+	if (result != USB_STOR_XFER_GOOD) {
+		usb_stor_dbg(us, "Result for bulk_transfer in sddr09_writeX %d\n",
+			     result);
+		return -EIO;
+	}
+	return 0;
+}
+
+/* erase address, write same address */
+static int
+sddr09_write_inplace(struct us_data *us, unsigned long address,
+		     int nr_of_pages, int pageshift, unsigned char *buf,
+		     int use_sg) {
+	int bulklen = (nr_of_pages << pageshift) + (nr_of_pages << CONTROL_SHIFT);
+	return sddr09_writeX(us, address, address, nr_of_pages, bulklen,
+			     buf, use_sg);
+}
+
+#if 0
+/*
+ * Read Scatter Gather Command: 3+4n bytes.
+ * byte 0: opcode E7
+ * byte 2: n
+ * bytes 4i-1,4i,4i+1: page address
+ * byte 4i+2: page count
+ * (i=1..n)
+ *
+ * This reads several pages from the card to a single memory buffer.
+ * The last two bits of byte 1 have the same meaning as for E8.
+ */
+static int
+sddr09_read_sg_test_only(struct us_data *us) {
+	unsigned char *command = us->iobuf;
+	int result, bulklen, nsg, ct;
+	unsigned char *buf;
+	unsigned long address;
+
+	nsg = bulklen = 0;
+	command[0] = 0xE7;
+	command[1] = LUNBITS;
+	command[2] = 0;
+	address = 040000; ct = 1;
+	nsg++;
+	bulklen += (ct << 9);
+	command[4*nsg+2] = ct;
+	command[4*nsg+1] = ((address >> 9) & 0xFF);
+	command[4*nsg+0] = ((address >> 17) & 0xFF);
+	command[4*nsg-1] = ((address >> 25) & 0xFF);
+
+	address = 0340000; ct = 1;
+	nsg++;
+	bulklen += (ct << 9);
+	command[4*nsg+2] = ct;
+	command[4*nsg+1] = ((address >> 9) & 0xFF);
+	command[4*nsg+0] = ((address >> 17) & 0xFF);
+	command[4*nsg-1] = ((address >> 25) & 0xFF);
+
+	address = 01000000; ct = 2;
+	nsg++;
+	bulklen += (ct << 9);
+	command[4*nsg+2] = ct;
+	command[4*nsg+1] = ((address >> 9) & 0xFF);
+	command[4*nsg+0] = ((address >> 17) & 0xFF);
+	command[4*nsg-1] = ((address >> 25) & 0xFF);
+
+	command[2] = nsg;
+
+	result = sddr09_send_scsi_command(us, command, 4*nsg+3);
+
+	if (result) {
+		usb_stor_dbg(us, "Result for send_control in sddr09_read_sg %d\n",
+			     result);
+		return result;
+	}
+
+	buf = kmalloc(bulklen, GFP_NOIO);
+	if (!buf)
+		return -ENOMEM;
+
+	result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+				       buf, bulklen, NULL);
+	kfree(buf);
+	if (result != USB_STOR_XFER_GOOD) {
+		usb_stor_dbg(us, "Result for bulk_transfer in sddr09_read_sg %d\n",
+			     result);
+		return -EIO;
+	}
+
+	return 0;
+}
+#endif
+
+/*
+ * Read Status Command: 12 bytes.
+ * byte 0: opcode: EC
+ *
+ * Returns 64 bytes, all zero except for the first.
+ * bit 0: 1: Error
+ * bit 5: 1: Suspended
+ * bit 6: 1: Ready
+ * bit 7: 1: Not write-protected
+ */
+
+static int
+sddr09_read_status(struct us_data *us, unsigned char *status) {
+
+	unsigned char *command = us->iobuf;
+	unsigned char *data = us->iobuf;
+	int result;
+
+	usb_stor_dbg(us, "Reading status...\n");
+
+	memset(command, 0, 12);
+	command[0] = 0xEC;
+	command[1] = LUNBITS;
+
+	result = sddr09_send_scsi_command(us, command, 12);
+	if (result)
+		return result;
+
+	result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+				       data, 64, NULL);
+	*status = data[0];
+	return (result == USB_STOR_XFER_GOOD ? 0 : -EIO);
+}
+
+static int
+sddr09_read_data(struct us_data *us,
+		 unsigned long address,
+		 unsigned int sectors) {
+
+	struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra;
+	unsigned char *buffer;
+	unsigned int lba, maxlba, pba;
+	unsigned int page, pages;
+	unsigned int len, offset;
+	struct scatterlist *sg;
+	int result;
+
+	// Figure out the initial LBA and page
+	lba = address >> info->blockshift;
+	page = (address & info->blockmask);
+	maxlba = info->capacity >> (info->pageshift + info->blockshift);
+	if (lba >= maxlba)
+		return -EIO;
+
+	// Since we only read in one block at a time, we have to create
+	// a bounce buffer and move the data a piece at a time between the
+	// bounce buffer and the actual transfer buffer.
+
+	len = min(sectors, (unsigned int) info->blocksize) * info->pagesize;
+	buffer = kmalloc(len, GFP_NOIO);
+	if (!buffer)
+		return -ENOMEM;
+
+	// This could be made much more efficient by checking for
+	// contiguous LBA's. Another exercise left to the student.
+
+	result = 0;
+	offset = 0;
+	sg = NULL;
+
+	while (sectors > 0) {
+
+		/* Find number of pages we can read in this block */
+		pages = min(sectors, info->blocksize - page);
+		len = pages << info->pageshift;
+
+		/* Not overflowing capacity? */
+		if (lba >= maxlba) {
+			usb_stor_dbg(us, "Error: Requested lba %u exceeds maximum %u\n",
+				     lba, maxlba);
+			result = -EIO;
+			break;
+		}
+
+		/* Find where this lba lives on disk */
+		pba = info->lba_to_pba[lba];
+
+		if (pba == UNDEF) {	/* this lba was never written */
+
+			usb_stor_dbg(us, "Read %d zero pages (LBA %d) page %d\n",
+				     pages, lba, page);
+
+			/*
+			 * This is not really an error. It just means
+			 * that the block has never been written.
+			 * Instead of returning an error
+			 * it is better to return all zero data.
+			 */
+
+			memset(buffer, 0, len);
+
+		} else {
+			usb_stor_dbg(us, "Read %d pages, from PBA %d (LBA %d) page %d\n",
+				     pages, pba, lba, page);
+
+			address = ((pba << info->blockshift) + page) << 
+				info->pageshift;
+
+			result = sddr09_read20(us, address>>1,
+					pages, info->pageshift, buffer, 0);
+			if (result)
+				break;
+		}
+
+		// Store the data in the transfer buffer
+		usb_stor_access_xfer_buf(buffer, len, us->srb,
+				&sg, &offset, TO_XFER_BUF);
+
+		page = 0;
+		lba++;
+		sectors -= pages;
+	}
+
+	kfree(buffer);
+	return result;
+}
+
+static unsigned int
+sddr09_find_unused_pba(struct sddr09_card_info *info, unsigned int lba) {
+	static unsigned int lastpba = 1;
+	int zonestart, end, i;
+
+	zonestart = (lba/1000) << 10;
+	end = info->capacity >> (info->blockshift + info->pageshift);
+	end -= zonestart;
+	if (end > 1024)
+		end = 1024;
+
+	for (i = lastpba+1; i < end; i++) {
+		if (info->pba_to_lba[zonestart+i] == UNDEF) {
+			lastpba = i;
+			return zonestart+i;
+		}
+	}
+	for (i = 0; i <= lastpba; i++) {
+		if (info->pba_to_lba[zonestart+i] == UNDEF) {
+			lastpba = i;
+			return zonestart+i;
+		}
+	}
+	return 0;
+}
+
+static int
+sddr09_write_lba(struct us_data *us, unsigned int lba,
+		 unsigned int page, unsigned int pages,
+		 unsigned char *ptr, unsigned char *blockbuffer) {
+
+	struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra;
+	unsigned long address;
+	unsigned int pba, lbap;
+	unsigned int pagelen;
+	unsigned char *bptr, *cptr, *xptr;
+	unsigned char ecc[3];
+	int i, result;
+
+	lbap = ((lba % 1000) << 1) | 0x1000;
+	if (parity[MSB_of(lbap) ^ LSB_of(lbap)])
+		lbap ^= 1;
+	pba = info->lba_to_pba[lba];
+
+	if (pba == UNDEF) {
+		pba = sddr09_find_unused_pba(info, lba);
+		if (!pba) {
+			printk(KERN_WARNING
+			       "sddr09_write_lba: Out of unused blocks\n");
+			return -ENOSPC;
+		}
+		info->pba_to_lba[pba] = lba;
+		info->lba_to_pba[lba] = pba;
+	}
+
+	if (pba == 1) {
+		/*
+		 * Maybe it is impossible to write to PBA 1.
+		 * Fake success, but don't do anything.
+		 */
+		printk(KERN_WARNING "sddr09: avoid writing to pba 1\n");
+		return 0;
+	}
+
+	pagelen = (1 << info->pageshift) + (1 << CONTROL_SHIFT);
+
+	/* read old contents */
+	address = (pba << (info->pageshift + info->blockshift));
+	result = sddr09_read22(us, address>>1, info->blocksize,
+			       info->pageshift, blockbuffer, 0);
+	if (result)
+		return result;
+
+	/* check old contents and fill lba */
+	for (i = 0; i < info->blocksize; i++) {
+		bptr = blockbuffer + i*pagelen;
+		cptr = bptr + info->pagesize;
+		nand_compute_ecc(bptr, ecc);
+		if (!nand_compare_ecc(cptr+13, ecc)) {
+			usb_stor_dbg(us, "Warning: bad ecc in page %d- of pba %d\n",
+				     i, pba);
+			nand_store_ecc(cptr+13, ecc);
+		}
+		nand_compute_ecc(bptr+(info->pagesize / 2), ecc);
+		if (!nand_compare_ecc(cptr+8, ecc)) {
+			usb_stor_dbg(us, "Warning: bad ecc in page %d+ of pba %d\n",
+				     i, pba);
+			nand_store_ecc(cptr+8, ecc);
+		}
+		cptr[6] = cptr[11] = MSB_of(lbap);
+		cptr[7] = cptr[12] = LSB_of(lbap);
+	}
+
+	/* copy in new stuff and compute ECC */
+	xptr = ptr;
+	for (i = page; i < page+pages; i++) {
+		bptr = blockbuffer + i*pagelen;
+		cptr = bptr + info->pagesize;
+		memcpy(bptr, xptr, info->pagesize);
+		xptr += info->pagesize;
+		nand_compute_ecc(bptr, ecc);
+		nand_store_ecc(cptr+13, ecc);
+		nand_compute_ecc(bptr+(info->pagesize / 2), ecc);
+		nand_store_ecc(cptr+8, ecc);
+	}
+
+	usb_stor_dbg(us, "Rewrite PBA %d (LBA %d)\n", pba, lba);
+
+	result = sddr09_write_inplace(us, address>>1, info->blocksize,
+				      info->pageshift, blockbuffer, 0);
+
+	usb_stor_dbg(us, "sddr09_write_inplace returns %d\n", result);
+
+#if 0
+	{
+		unsigned char status = 0;
+		int result2 = sddr09_read_status(us, &status);
+		if (result2)
+			usb_stor_dbg(us, "cannot read status\n");
+		else if (status != 0xc0)
+			usb_stor_dbg(us, "status after write: 0x%x\n", status);
+	}
+#endif
+
+#if 0
+	{
+		int result2 = sddr09_test_unit_ready(us);
+	}
+#endif
+
+	return result;
+}
+
+static int
+sddr09_write_data(struct us_data *us,
+		  unsigned long address,
+		  unsigned int sectors) {
+
+	struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra;
+	unsigned int lba, maxlba, page, pages;
+	unsigned int pagelen, blocklen;
+	unsigned char *blockbuffer;
+	unsigned char *buffer;
+	unsigned int len, offset;
+	struct scatterlist *sg;
+	int result;
+
+	/* Figure out the initial LBA and page */
+	lba = address >> info->blockshift;
+	page = (address & info->blockmask);
+	maxlba = info->capacity >> (info->pageshift + info->blockshift);
+	if (lba >= maxlba)
+		return -EIO;
+
+	/*
+	 * blockbuffer is used for reading in the old data, overwriting
+	 * with the new data, and performing ECC calculations
+	 */
+
+	/*
+	 * TODO: instead of doing kmalloc/kfree for each write,
+	 * add a bufferpointer to the info structure
+	 */
+
+	pagelen = (1 << info->pageshift) + (1 << CONTROL_SHIFT);
+	blocklen = (pagelen << info->blockshift);
+	blockbuffer = kmalloc(blocklen, GFP_NOIO);
+	if (!blockbuffer)
+		return -ENOMEM;
+
+	/*
+	 * Since we don't write the user data directly to the device,
+	 * we have to create a bounce buffer and move the data a piece
+	 * at a time between the bounce buffer and the actual transfer buffer.
+	 */
+
+	len = min(sectors, (unsigned int) info->blocksize) * info->pagesize;
+	buffer = kmalloc(len, GFP_NOIO);
+	if (!buffer) {
+		kfree(blockbuffer);
+		return -ENOMEM;
+	}
+
+	result = 0;
+	offset = 0;
+	sg = NULL;
+
+	while (sectors > 0) {
+
+		/* Write as many sectors as possible in this block */
+
+		pages = min(sectors, info->blocksize - page);
+		len = (pages << info->pageshift);
+
+		/* Not overflowing capacity? */
+		if (lba >= maxlba) {
+			usb_stor_dbg(us, "Error: Requested lba %u exceeds maximum %u\n",
+				     lba, maxlba);
+			result = -EIO;
+			break;
+		}
+
+		/* Get the data from the transfer buffer */
+		usb_stor_access_xfer_buf(buffer, len, us->srb,
+				&sg, &offset, FROM_XFER_BUF);
+
+		result = sddr09_write_lba(us, lba, page, pages,
+				buffer, blockbuffer);
+		if (result)
+			break;
+
+		page = 0;
+		lba++;
+		sectors -= pages;
+	}
+
+	kfree(buffer);
+	kfree(blockbuffer);
+
+	return result;
+}
+
+static int
+sddr09_read_control(struct us_data *us,
+		unsigned long address,
+		unsigned int blocks,
+		unsigned char *content,
+		int use_sg) {
+
+	usb_stor_dbg(us, "Read control address %lu, blocks %d\n",
+		     address, blocks);
+
+	return sddr09_read21(us, address, blocks,
+			     CONTROL_SHIFT, content, use_sg);
+}
+
+/*
+ * Read Device ID Command: 12 bytes.
+ * byte 0: opcode: ED
+ *
+ * Returns 2 bytes: Manufacturer ID and Device ID.
+ * On more recent cards 3 bytes: the third byte is an option code A5
+ * signifying that the secret command to read an 128-bit ID is available.
+ * On still more recent cards 4 bytes: the fourth byte C0 means that
+ * a second read ID cmd is available.
+ */
+static int
+sddr09_read_deviceID(struct us_data *us, unsigned char *deviceID) {
+	unsigned char *command = us->iobuf;
+	unsigned char *content = us->iobuf;
+	int result, i;
+
+	memset(command, 0, 12);
+	command[0] = 0xED;
+	command[1] = LUNBITS;
+
+	result = sddr09_send_scsi_command(us, command, 12);
+	if (result)
+		return result;
+
+	result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+			content, 64, NULL);
+
+	for (i = 0; i < 4; i++)
+		deviceID[i] = content[i];
+
+	return (result == USB_STOR_XFER_GOOD ? 0 : -EIO);
+}
+
+static int
+sddr09_get_wp(struct us_data *us, struct sddr09_card_info *info) {
+	int result;
+	unsigned char status;
+	const char *wp_fmt;
+
+	result = sddr09_read_status(us, &status);
+	if (result) {
+		usb_stor_dbg(us, "read_status fails\n");
+		return result;
+	}
+	if ((status & 0x80) == 0) {
+		info->flags |= SDDR09_WP;	/* write protected */
+		wp_fmt = " WP";
+	} else {
+		wp_fmt = "";
+	}
+	usb_stor_dbg(us, "status 0x%02X%s%s%s%s\n", status, wp_fmt,
+		     status & 0x40 ? " Ready" : "",
+		     status & LUNBITS ? " Suspended" : "",
+		     status & 0x01 ? " Error" : "");
+
+	return 0;
+}
+
+#if 0
+/*
+ * Reset Command: 12 bytes.
+ * byte 0: opcode: EB
+ */
+static int
+sddr09_reset(struct us_data *us) {
+
+	unsigned char *command = us->iobuf;
+
+	memset(command, 0, 12);
+	command[0] = 0xEB;
+	command[1] = LUNBITS;
+
+	return sddr09_send_scsi_command(us, command, 12);
+}
+#endif
+
+static struct nand_flash_dev *
+sddr09_get_cardinfo(struct us_data *us, unsigned char flags) {
+	struct nand_flash_dev *cardinfo;
+	unsigned char deviceID[4];
+	char blurbtxt[256];
+	int result;
+
+	usb_stor_dbg(us, "Reading capacity...\n");
+
+	result = sddr09_read_deviceID(us, deviceID);
+
+	if (result) {
+		usb_stor_dbg(us, "Result of read_deviceID is %d\n", result);
+		printk(KERN_WARNING "sddr09: could not read card info\n");
+		return NULL;
+	}
+
+	sprintf(blurbtxt, "sddr09: Found Flash card, ID = %4ph", deviceID);
+
+	/* Byte 0 is the manufacturer */
+	sprintf(blurbtxt + strlen(blurbtxt),
+		": Manuf. %s",
+		nand_flash_manufacturer(deviceID[0]));
+
+	/* Byte 1 is the device type */
+	cardinfo = nand_find_id(deviceID[1]);
+	if (cardinfo) {
+		/*
+		 * MB or MiB? It is neither. A 16 MB card has
+		 * 17301504 raw bytes, of which 16384000 are
+		 * usable for user data.
+		 */
+		sprintf(blurbtxt + strlen(blurbtxt),
+			", %d MB", 1<<(cardinfo->chipshift - 20));
+	} else {
+		sprintf(blurbtxt + strlen(blurbtxt),
+			", type unrecognized");
+	}
+
+	/* Byte 2 is code to signal availability of 128-bit ID */
+	if (deviceID[2] == 0xa5) {
+		sprintf(blurbtxt + strlen(blurbtxt),
+			", 128-bit ID");
+	}
+
+	/* Byte 3 announces the availability of another read ID command */
+	if (deviceID[3] == 0xc0) {
+		sprintf(blurbtxt + strlen(blurbtxt),
+			", extra cmd");
+	}
+
+	if (flags & SDDR09_WP)
+		sprintf(blurbtxt + strlen(blurbtxt),
+			", WP");
+
+	printk(KERN_WARNING "%s\n", blurbtxt);
+
+	return cardinfo;
+}
+
+static int
+sddr09_read_map(struct us_data *us) {
+
+	struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra;
+	int numblocks, alloc_len, alloc_blocks;
+	int i, j, result;
+	unsigned char *buffer, *buffer_end, *ptr;
+	unsigned int lba, lbact;
+
+	if (!info->capacity)
+		return -1;
+
+	/*
+	 * size of a block is 1 << (blockshift + pageshift) bytes
+	 * divide into the total capacity to get the number of blocks
+	 */
+
+	numblocks = info->capacity >> (info->blockshift + info->pageshift);
+
+	/*
+	 * read 64 bytes for every block (actually 1 << CONTROL_SHIFT)
+	 * but only use a 64 KB buffer
+	 * buffer size used must be a multiple of (1 << CONTROL_SHIFT)
+	 */
+#define SDDR09_READ_MAP_BUFSZ 65536
+
+	alloc_blocks = min(numblocks, SDDR09_READ_MAP_BUFSZ >> CONTROL_SHIFT);
+	alloc_len = (alloc_blocks << CONTROL_SHIFT);
+	buffer = kmalloc(alloc_len, GFP_NOIO);
+	if (!buffer) {
+		result = -1;
+		goto done;
+	}
+	buffer_end = buffer + alloc_len;
+
+#undef SDDR09_READ_MAP_BUFSZ
+
+	kfree(info->lba_to_pba);
+	kfree(info->pba_to_lba);
+	info->lba_to_pba = kmalloc_array(numblocks, sizeof(int), GFP_NOIO);
+	info->pba_to_lba = kmalloc_array(numblocks, sizeof(int), GFP_NOIO);
+
+	if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) {
+		printk(KERN_WARNING "sddr09_read_map: out of memory\n");
+		result = -1;
+		goto done;
+	}
+
+	for (i = 0; i < numblocks; i++)
+		info->lba_to_pba[i] = info->pba_to_lba[i] = UNDEF;
+
+	/*
+	 * Define lba-pba translation table
+	 */
+
+	ptr = buffer_end;
+	for (i = 0; i < numblocks; i++) {
+		ptr += (1 << CONTROL_SHIFT);
+		if (ptr >= buffer_end) {
+			unsigned long address;
+
+			address = i << (info->pageshift + info->blockshift);
+			result = sddr09_read_control(
+				us, address>>1,
+				min(alloc_blocks, numblocks - i),
+				buffer, 0);
+			if (result) {
+				result = -1;
+				goto done;
+			}
+			ptr = buffer;
+		}
+
+		if (i == 0 || i == 1) {
+			info->pba_to_lba[i] = UNUSABLE;
+			continue;
+		}
+
+		/* special PBAs have control field 0^16 */
+		for (j = 0; j < 16; j++)
+			if (ptr[j] != 0)
+				goto nonz;
+		info->pba_to_lba[i] = UNUSABLE;
+		printk(KERN_WARNING "sddr09: PBA %d has no logical mapping\n",
+		       i);
+		continue;
+
+	nonz:
+		/* unwritten PBAs have control field FF^16 */
+		for (j = 0; j < 16; j++)
+			if (ptr[j] != 0xff)
+				goto nonff;
+		continue;
+
+	nonff:
+		/* normal PBAs start with six FFs */
+		if (j < 6) {
+			printk(KERN_WARNING
+			       "sddr09: PBA %d has no logical mapping: "
+			       "reserved area = %02X%02X%02X%02X "
+			       "data status %02X block status %02X\n",
+			       i, ptr[0], ptr[1], ptr[2], ptr[3],
+			       ptr[4], ptr[5]);
+			info->pba_to_lba[i] = UNUSABLE;
+			continue;
+		}
+
+		if ((ptr[6] >> 4) != 0x01) {
+			printk(KERN_WARNING
+			       "sddr09: PBA %d has invalid address field "
+			       "%02X%02X/%02X%02X\n",
+			       i, ptr[6], ptr[7], ptr[11], ptr[12]);
+			info->pba_to_lba[i] = UNUSABLE;
+			continue;
+		}
+
+		/* check even parity */
+		if (parity[ptr[6] ^ ptr[7]]) {
+			printk(KERN_WARNING
+			       "sddr09: Bad parity in LBA for block %d"
+			       " (%02X %02X)\n", i, ptr[6], ptr[7]);
+			info->pba_to_lba[i] = UNUSABLE;
+			continue;
+		}
+
+		lba = short_pack(ptr[7], ptr[6]);
+		lba = (lba & 0x07FF) >> 1;
+
+		/*
+		 * Every 1024 physical blocks ("zone"), the LBA numbers
+		 * go back to zero, but are within a higher block of LBA's.
+		 * Also, there is a maximum of 1000 LBA's per zone.
+		 * In other words, in PBA 1024-2047 you will find LBA 0-999
+		 * which are really LBA 1000-1999. This allows for 24 bad
+		 * or special physical blocks per zone.
+		 */
+
+		if (lba >= 1000) {
+			printk(KERN_WARNING
+			       "sddr09: Bad low LBA %d for block %d\n",
+			       lba, i);
+			goto possibly_erase;
+		}
+
+		lba += 1000*(i/0x400);
+
+		if (info->lba_to_pba[lba] != UNDEF) {
+			printk(KERN_WARNING
+			       "sddr09: LBA %d seen for PBA %d and %d\n",
+			       lba, info->lba_to_pba[lba], i);
+			goto possibly_erase;
+		}
+
+		info->pba_to_lba[i] = lba;
+		info->lba_to_pba[lba] = i;
+		continue;
+
+	possibly_erase:
+		if (erase_bad_lba_entries) {
+			unsigned long address;
+
+			address = (i << (info->pageshift + info->blockshift));
+			sddr09_erase(us, address>>1);
+			info->pba_to_lba[i] = UNDEF;
+		} else
+			info->pba_to_lba[i] = UNUSABLE;
+	}
+
+	/*
+	 * Approximate capacity. This is not entirely correct yet,
+	 * since a zone with less than 1000 usable pages leads to
+	 * missing LBAs. Especially if it is the last zone, some
+	 * LBAs can be past capacity.
+	 */
+	lbact = 0;
+	for (i = 0; i < numblocks; i += 1024) {
+		int ct = 0;
+
+		for (j = 0; j < 1024 && i+j < numblocks; j++) {
+			if (info->pba_to_lba[i+j] != UNUSABLE) {
+				if (ct >= 1000)
+					info->pba_to_lba[i+j] = SPARE;
+				else
+					ct++;
+			}
+		}
+		lbact += ct;
+	}
+	info->lbact = lbact;
+	usb_stor_dbg(us, "Found %d LBA's\n", lbact);
+	result = 0;
+
+ done:
+	if (result != 0) {
+		kfree(info->lba_to_pba);
+		kfree(info->pba_to_lba);
+		info->lba_to_pba = NULL;
+		info->pba_to_lba = NULL;
+	}
+	kfree(buffer);
+	return result;
+}
+
+static void
+sddr09_card_info_destructor(void *extra) {
+	struct sddr09_card_info *info = (struct sddr09_card_info *)extra;
+
+	if (!info)
+		return;
+
+	kfree(info->lba_to_pba);
+	kfree(info->pba_to_lba);
+}
+
+static int
+sddr09_common_init(struct us_data *us) {
+	int result;
+
+	/* set the configuration -- STALL is an acceptable response here */
+	if (us->pusb_dev->actconfig->desc.bConfigurationValue != 1) {
+		usb_stor_dbg(us, "active config #%d != 1 ??\n",
+			     us->pusb_dev->actconfig->desc.bConfigurationValue);
+		return -EINVAL;
+	}
+
+	result = usb_reset_configuration(us->pusb_dev);
+	usb_stor_dbg(us, "Result of usb_reset_configuration is %d\n", result);
+	if (result == -EPIPE) {
+		usb_stor_dbg(us, "-- stall on control interface\n");
+	} else if (result != 0) {
+		/* it's not a stall, but another error -- time to bail */
+		usb_stor_dbg(us, "-- Unknown error.  Rejecting device\n");
+		return -EINVAL;
+	}
+
+	us->extra = kzalloc(sizeof(struct sddr09_card_info), GFP_NOIO);
+	if (!us->extra)
+		return -ENOMEM;
+	us->extra_destructor = sddr09_card_info_destructor;
+
+	nand_init_ecc();
+	return 0;
+}
+
+
+/*
+ * This is needed at a very early stage. If this is not listed in the
+ * unusual devices list but called from here then LUN 0 of the combo reader
+ * is not recognized. But I do not know what precisely these calls do.
+ */
+static int
+usb_stor_sddr09_dpcm_init(struct us_data *us) {
+	int result;
+	unsigned char *data = us->iobuf;
+
+	result = sddr09_common_init(us);
+	if (result)
+		return result;
+
+	result = sddr09_send_command(us, 0x01, USB_DIR_IN, data, 2);
+	if (result) {
+		usb_stor_dbg(us, "send_command fails\n");
+		return result;
+	}
+
+	usb_stor_dbg(us, "%02X %02X\n", data[0], data[1]);
+	// get 07 02
+
+	result = sddr09_send_command(us, 0x08, USB_DIR_IN, data, 2);
+	if (result) {
+		usb_stor_dbg(us, "2nd send_command fails\n");
+		return result;
+	}
+
+	usb_stor_dbg(us, "%02X %02X\n", data[0], data[1]);
+	// get 07 00
+
+	result = sddr09_request_sense(us, data, 18);
+	if (result == 0 && data[2] != 0) {
+		int j;
+		for (j=0; j<18; j++)
+			printk(" %02X", data[j]);
+		printk("\n");
+		// get 70 00 00 00 00 00 00 * 00 00 00 00 00 00
+		// 70: current command
+		// sense key 0, sense code 0, extd sense code 0
+		// additional transfer length * = sizeof(data) - 7
+		// Or: 70 00 06 00 00 00 00 0b 00 00 00 00 28 00 00 00 00 00
+		// sense key 06, sense code 28: unit attention,
+		// not ready to ready transition
+	}
+
+	// test unit ready
+
+	return 0;		/* not result */
+}
+
+/*
+ * Transport for the Microtech DPCM-USB
+ */
+static int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+	int ret;
+
+	usb_stor_dbg(us, "LUN=%d\n", (u8)srb->device->lun);
+
+	switch (srb->device->lun) {
+	case 0:
+
+		/*
+		 * LUN 0 corresponds to the CompactFlash card reader.
+		 */
+		ret = usb_stor_CB_transport(srb, us);
+		break;
+
+	case 1:
+
+		/*
+		 * LUN 1 corresponds to the SmartMedia card reader.
+		 */
+
+		/*
+		 * Set the LUN to 0 (just in case).
+		 */
+		srb->device->lun = 0;
+		ret = sddr09_transport(srb, us);
+		srb->device->lun = 1;
+		break;
+
+	default:
+	    usb_stor_dbg(us, "Invalid LUN %d\n", (u8)srb->device->lun);
+		ret = USB_STOR_TRANSPORT_ERROR;
+		break;
+	}
+	return ret;
+}
+
+
+/*
+ * Transport for the Sandisk SDDR-09
+ */
+static int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+	static unsigned char sensekey = 0, sensecode = 0;
+	static unsigned char havefakesense = 0;
+	int result, i;
+	unsigned char *ptr = us->iobuf;
+	unsigned long capacity;
+	unsigned int page, pages;
+
+	struct sddr09_card_info *info;
+
+	static unsigned char inquiry_response[8] = {
+		0x00, 0x80, 0x00, 0x02, 0x1F, 0x00, 0x00, 0x00
+	};
+
+	/* note: no block descriptor support */
+	static unsigned char mode_page_01[19] = {
+		0x00, 0x0F, 0x00, 0x0, 0x0, 0x0, 0x00,
+		0x01, 0x0A,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+	};
+
+	info = (struct sddr09_card_info *)us->extra;
+
+	if (srb->cmnd[0] == REQUEST_SENSE && havefakesense) {
+		/* for a faked command, we have to follow with a faked sense */
+		memset(ptr, 0, 18);
+		ptr[0] = 0x70;
+		ptr[2] = sensekey;
+		ptr[7] = 11;
+		ptr[12] = sensecode;
+		usb_stor_set_xfer_buf(ptr, 18, srb);
+		sensekey = sensecode = havefakesense = 0;
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	havefakesense = 1;
+
+	/*
+	 * Dummy up a response for INQUIRY since SDDR09 doesn't
+	 * respond to INQUIRY commands
+	 */
+
+	if (srb->cmnd[0] == INQUIRY) {
+		memcpy(ptr, inquiry_response, 8);
+		fill_inquiry_response(us, ptr, 36);
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == READ_CAPACITY) {
+		struct nand_flash_dev *cardinfo;
+
+		sddr09_get_wp(us, info);	/* read WP bit */
+
+		cardinfo = sddr09_get_cardinfo(us, info->flags);
+		if (!cardinfo) {
+			/* probably no media */
+		init_error:
+			sensekey = 0x02;	/* not ready */
+			sensecode = 0x3a;	/* medium not present */
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+
+		info->capacity = (1 << cardinfo->chipshift);
+		info->pageshift = cardinfo->pageshift;
+		info->pagesize = (1 << info->pageshift);
+		info->blockshift = cardinfo->blockshift;
+		info->blocksize = (1 << info->blockshift);
+		info->blockmask = info->blocksize - 1;
+
+		// map initialization, must follow get_cardinfo()
+		if (sddr09_read_map(us)) {
+			/* probably out of memory */
+			goto init_error;
+		}
+
+		// Report capacity
+
+		capacity = (info->lbact << info->blockshift) - 1;
+
+		((__be32 *) ptr)[0] = cpu_to_be32(capacity);
+
+		// Report page size
+
+		((__be32 *) ptr)[1] = cpu_to_be32(info->pagesize);
+		usb_stor_set_xfer_buf(ptr, 8, srb);
+
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == MODE_SENSE_10) {
+		int modepage = (srb->cmnd[2] & 0x3F);
+
+		/*
+		 * They ask for the Read/Write error recovery page,
+		 * or for all pages.
+		 */
+		/* %% We should check DBD %% */
+		if (modepage == 0x01 || modepage == 0x3F) {
+			usb_stor_dbg(us, "Dummy up request for mode page 0x%x\n",
+				     modepage);
+
+			memcpy(ptr, mode_page_01, sizeof(mode_page_01));
+			((__be16*)ptr)[0] = cpu_to_be16(sizeof(mode_page_01) - 2);
+			ptr[3] = (info->flags & SDDR09_WP) ? 0x80 : 0;
+			usb_stor_set_xfer_buf(ptr, sizeof(mode_page_01), srb);
+			return USB_STOR_TRANSPORT_GOOD;
+		}
+
+		sensekey = 0x05;	/* illegal request */
+		sensecode = 0x24;	/* invalid field in CDB */
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL)
+		return USB_STOR_TRANSPORT_GOOD;
+
+	havefakesense = 0;
+
+	if (srb->cmnd[0] == READ_10) {
+
+		page = short_pack(srb->cmnd[3], srb->cmnd[2]);
+		page <<= 16;
+		page |= short_pack(srb->cmnd[5], srb->cmnd[4]);
+		pages = short_pack(srb->cmnd[8], srb->cmnd[7]);
+
+		usb_stor_dbg(us, "READ_10: read page %d pagect %d\n",
+			     page, pages);
+
+		result = sddr09_read_data(us, page, pages);
+		return (result == 0 ? USB_STOR_TRANSPORT_GOOD :
+				USB_STOR_TRANSPORT_ERROR);
+	}
+
+	if (srb->cmnd[0] == WRITE_10) {
+
+		page = short_pack(srb->cmnd[3], srb->cmnd[2]);
+		page <<= 16;
+		page |= short_pack(srb->cmnd[5], srb->cmnd[4]);
+		pages = short_pack(srb->cmnd[8], srb->cmnd[7]);
+
+		usb_stor_dbg(us, "WRITE_10: write page %d pagect %d\n",
+			     page, pages);
+
+		result = sddr09_write_data(us, page, pages);
+		return (result == 0 ? USB_STOR_TRANSPORT_GOOD :
+				USB_STOR_TRANSPORT_ERROR);
+	}
+
+	/*
+	 * catch-all for all other commands, except
+	 * pass TEST_UNIT_READY and REQUEST_SENSE through
+	 */
+	if (srb->cmnd[0] != TEST_UNIT_READY &&
+	    srb->cmnd[0] != REQUEST_SENSE) {
+		sensekey = 0x05;	/* illegal request */
+		sensecode = 0x20;	/* invalid command */
+		havefakesense = 1;
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	for (; srb->cmd_len<12; srb->cmd_len++)
+		srb->cmnd[srb->cmd_len] = 0;
+
+	srb->cmnd[1] = LUNBITS;
+
+	ptr[0] = 0;
+	for (i=0; i<12; i++)
+		sprintf(ptr+strlen(ptr), "%02X ", srb->cmnd[i]);
+
+	usb_stor_dbg(us, "Send control for command %s\n", ptr);
+
+	result = sddr09_send_scsi_command(us, srb->cmnd, 12);
+	if (result) {
+		usb_stor_dbg(us, "sddr09_send_scsi_command returns %d\n",
+			     result);
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	if (scsi_bufflen(srb) == 0)
+		return USB_STOR_TRANSPORT_GOOD;
+
+	if (srb->sc_data_direction == DMA_TO_DEVICE ||
+	    srb->sc_data_direction == DMA_FROM_DEVICE) {
+		unsigned int pipe = (srb->sc_data_direction == DMA_TO_DEVICE)
+				? us->send_bulk_pipe : us->recv_bulk_pipe;
+
+		usb_stor_dbg(us, "%s %d bytes\n",
+			     (srb->sc_data_direction == DMA_TO_DEVICE) ?
+			     "sending" : "receiving",
+			     scsi_bufflen(srb));
+
+		result = usb_stor_bulk_srb(us, pipe, srb);
+
+		return (result == USB_STOR_XFER_GOOD ?
+			USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
+	} 
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Initialization routine for the sddr09 subdriver
+ */
+static int
+usb_stor_sddr09_init(struct us_data *us) {
+	return sddr09_common_init(us);
+}
+
+static struct scsi_host_template sddr09_host_template;
+
+static int sddr09_probe(struct usb_interface *intf,
+			 const struct usb_device_id *id)
+{
+	struct us_data *us;
+	int result;
+
+	result = usb_stor_probe1(&us, intf, id,
+			(id - sddr09_usb_ids) + sddr09_unusual_dev_list,
+			&sddr09_host_template);
+	if (result)
+		return result;
+
+	if (us->protocol == USB_PR_DPCM_USB) {
+		us->transport_name = "Control/Bulk-EUSB/SDDR09";
+		us->transport = dpcm_transport;
+		us->transport_reset = usb_stor_CB_reset;
+		us->max_lun = 1;
+	} else {
+		us->transport_name = "EUSB/SDDR09";
+		us->transport = sddr09_transport;
+		us->transport_reset = usb_stor_CB_reset;
+		us->max_lun = 0;
+	}
+
+	result = usb_stor_probe2(us);
+	return result;
+}
+
+static struct usb_driver sddr09_driver = {
+	.name =		DRV_NAME,
+	.probe =	sddr09_probe,
+	.disconnect =	usb_stor_disconnect,
+	.suspend =	usb_stor_suspend,
+	.resume =	usb_stor_resume,
+	.reset_resume =	usb_stor_reset_resume,
+	.pre_reset =	usb_stor_pre_reset,
+	.post_reset =	usb_stor_post_reset,
+	.id_table =	sddr09_usb_ids,
+	.soft_unbind =	1,
+	.no_dynamic_id = 1,
+};
+
+module_usb_stor_driver(sddr09_driver, sddr09_host_template, DRV_NAME);
diff --git a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c
new file mode 100644
index 0000000..b8527c5
--- /dev/null
+++ b/drivers/usb/storage/sddr55.c
@@ -0,0 +1,1014 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for SanDisk SDDR-55 SmartMedia reader
+ *
+ * SDDR55 driver v0.1:
+ *
+ * First release
+ *
+ * Current development and maintenance by:
+ *   (c) 2002 Simon Munton
+ */
+
+#include <linux/jiffies.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "protocol.h"
+#include "debug.h"
+#include "scsiglue.h"
+
+#define DRV_NAME "ums-sddr55"
+
+MODULE_DESCRIPTION("Driver for SanDisk SDDR-55 SmartMedia reader");
+MODULE_AUTHOR("Simon Munton");
+MODULE_LICENSE("GPL");
+
+/*
+ * The table of devices
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+		    vendorName, productName, useProtocol, useTransport, \
+		    initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+  .driver_info = (flags) }
+
+static struct usb_device_id sddr55_usb_ids[] = {
+#	include "unusual_sddr55.h"
+	{ }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, sddr55_usb_ids);
+
+#undef UNUSUAL_DEV
+
+/*
+ * The flags table
+ */
+#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
+		    vendor_name, product_name, use_protocol, use_transport, \
+		    init_function, Flags) \
+{ \
+	.vendorName = vendor_name,	\
+	.productName = product_name,	\
+	.useProtocol = use_protocol,	\
+	.useTransport = use_transport,	\
+	.initFunction = init_function,	\
+}
+
+static struct us_unusual_dev sddr55_unusual_dev_list[] = {
+#	include "unusual_sddr55.h"
+	{ }		/* Terminating entry */
+};
+
+#undef UNUSUAL_DEV
+
+
+#define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) )
+#define LSB_of(s) ((s)&0xFF)
+#define MSB_of(s) ((s)>>8)
+#define PAGESIZE  512
+
+#define set_sense_info(sk, asc, ascq)	\
+    do {				\
+	info->sense_data[2] = sk;	\
+	info->sense_data[12] = asc;	\
+	info->sense_data[13] = ascq;	\
+	} while (0)
+
+
+struct sddr55_card_info {
+	unsigned long	capacity;	/* Size of card in bytes */
+	int		max_log_blks;	/* maximum number of logical blocks */
+	int		pageshift;	/* log2 of pagesize */
+	int		smallpageshift;	/* 1 if pagesize == 256 */
+	int		blocksize;	/* Size of block in pages */
+	int		blockshift;	/* log2 of blocksize */
+	int		blockmask;	/* 2^blockshift - 1 */
+	int		read_only;	/* non zero if card is write protected */
+	int		force_read_only;	/* non zero if we find a map error*/
+	int		*lba_to_pba;	/* logical to physical map */
+	int		*pba_to_lba;	/* physical to logical map */
+	int		fatal_error;	/* set if we detect something nasty */
+	unsigned long 	last_access;	/* number of jiffies since we last talked to device */
+	unsigned char   sense_data[18];
+};
+
+
+#define NOT_ALLOCATED		0xffffffff
+#define BAD_BLOCK		0xffff
+#define CIS_BLOCK		0x400
+#define UNUSED_BLOCK		0x3ff
+
+static int
+sddr55_bulk_transport(struct us_data *us, int direction,
+		      unsigned char *data, unsigned int len) {
+	struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra;
+	unsigned int pipe = (direction == DMA_FROM_DEVICE) ?
+			us->recv_bulk_pipe : us->send_bulk_pipe;
+
+	if (!len)
+		return USB_STOR_XFER_GOOD;
+	info->last_access = jiffies;
+	return usb_stor_bulk_transfer_buf(us, pipe, data, len, NULL);
+}
+
+/*
+ * check if card inserted, if there is, update read_only status
+ * return non zero if no card
+ */
+
+static int sddr55_status(struct us_data *us)
+{
+	int result;
+	unsigned char *command = us->iobuf;
+	unsigned char *status = us->iobuf;
+	struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra;
+
+	/* send command */
+	memset(command, 0, 8);
+	command[5] = 0xB0;
+	command[7] = 0x80;
+	result = sddr55_bulk_transport(us,
+		DMA_TO_DEVICE, command, 8);
+
+	usb_stor_dbg(us, "Result for send_command in status %d\n", result);
+
+	if (result != USB_STOR_XFER_GOOD) {
+		set_sense_info (4, 0, 0);	/* hardware error */
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	result = sddr55_bulk_transport(us,
+		DMA_FROM_DEVICE, status,	4);
+
+	/* expect to get short transfer if no card fitted */
+	if (result == USB_STOR_XFER_SHORT || result == USB_STOR_XFER_STALLED) {
+		/* had a short transfer, no card inserted, free map memory */
+		kfree(info->lba_to_pba);
+		kfree(info->pba_to_lba);
+		info->lba_to_pba = NULL;
+		info->pba_to_lba = NULL;
+
+		info->fatal_error = 0;
+		info->force_read_only = 0;
+
+		set_sense_info (2, 0x3a, 0);	/* not ready, medium not present */
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	if (result != USB_STOR_XFER_GOOD) {
+		set_sense_info (4, 0, 0);	/* hardware error */
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+	
+	/* check write protect status */
+	info->read_only = (status[0] & 0x20);
+
+	/* now read status */
+	result = sddr55_bulk_transport(us,
+		DMA_FROM_DEVICE, status,	2);
+
+	if (result != USB_STOR_XFER_GOOD) {
+		set_sense_info (4, 0, 0);	/* hardware error */
+	}
+
+	return (result == USB_STOR_XFER_GOOD ?
+			USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_FAILED);
+}
+
+
+static int sddr55_read_data(struct us_data *us,
+		unsigned int lba,
+		unsigned int page,
+		unsigned short sectors) {
+
+	int result = USB_STOR_TRANSPORT_GOOD;
+	unsigned char *command = us->iobuf;
+	unsigned char *status = us->iobuf;
+	struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra;
+	unsigned char *buffer;
+
+	unsigned int pba;
+	unsigned long address;
+
+	unsigned short pages;
+	unsigned int len, offset;
+	struct scatterlist *sg;
+
+	// Since we only read in one block at a time, we have to create
+	// a bounce buffer and move the data a piece at a time between the
+	// bounce buffer and the actual transfer buffer.
+
+	len = min((unsigned int) sectors, (unsigned int) info->blocksize >>
+			info->smallpageshift) * PAGESIZE;
+	buffer = kmalloc(len, GFP_NOIO);
+	if (buffer == NULL)
+		return USB_STOR_TRANSPORT_ERROR; /* out of memory */
+	offset = 0;
+	sg = NULL;
+
+	while (sectors>0) {
+
+		/* have we got to end? */
+		if (lba >= info->max_log_blks)
+			break;
+
+		pba = info->lba_to_pba[lba];
+
+		// Read as many sectors as possible in this block
+
+		pages = min((unsigned int) sectors << info->smallpageshift,
+				info->blocksize - page);
+		len = pages << info->pageshift;
+
+		usb_stor_dbg(us, "Read %02X pages, from PBA %04X (LBA %04X) page %02X\n",
+			     pages, pba, lba, page);
+
+		if (pba == NOT_ALLOCATED) {
+			/* no pba for this lba, fill with zeroes */
+			memset (buffer, 0, len);
+		} else {
+
+			address = (pba << info->blockshift) + page;
+
+			command[0] = 0;
+			command[1] = LSB_of(address>>16);
+			command[2] = LSB_of(address>>8);
+			command[3] = LSB_of(address);
+
+			command[4] = 0;
+			command[5] = 0xB0;
+			command[6] = LSB_of(pages << (1 - info->smallpageshift));
+			command[7] = 0x85;
+
+			/* send command */
+			result = sddr55_bulk_transport(us,
+				DMA_TO_DEVICE, command, 8);
+
+			usb_stor_dbg(us, "Result for send_command in read_data %d\n",
+				     result);
+
+			if (result != USB_STOR_XFER_GOOD) {
+				result = USB_STOR_TRANSPORT_ERROR;
+				goto leave;
+			}
+
+			/* read data */
+			result = sddr55_bulk_transport(us,
+				DMA_FROM_DEVICE, buffer, len);
+
+			if (result != USB_STOR_XFER_GOOD) {
+				result = USB_STOR_TRANSPORT_ERROR;
+				goto leave;
+			}
+
+			/* now read status */
+			result = sddr55_bulk_transport(us,
+				DMA_FROM_DEVICE, status, 2);
+
+			if (result != USB_STOR_XFER_GOOD) {
+				result = USB_STOR_TRANSPORT_ERROR;
+				goto leave;
+			}
+
+			/* check status for error */
+			if (status[0] == 0xff && status[1] == 0x4) {
+				set_sense_info (3, 0x11, 0);
+				result = USB_STOR_TRANSPORT_FAILED;
+				goto leave;
+			}
+		}
+
+		// Store the data in the transfer buffer
+		usb_stor_access_xfer_buf(buffer, len, us->srb,
+				&sg, &offset, TO_XFER_BUF);
+
+		page = 0;
+		lba++;
+		sectors -= pages >> info->smallpageshift;
+	}
+
+	result = USB_STOR_TRANSPORT_GOOD;
+
+leave:
+	kfree(buffer);
+
+	return result;
+}
+
+static int sddr55_write_data(struct us_data *us,
+		unsigned int lba,
+		unsigned int page,
+		unsigned short sectors) {
+
+	int result = USB_STOR_TRANSPORT_GOOD;
+	unsigned char *command = us->iobuf;
+	unsigned char *status = us->iobuf;
+	struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra;
+	unsigned char *buffer;
+
+	unsigned int pba;
+	unsigned int new_pba;
+	unsigned long address;
+
+	unsigned short pages;
+	int i;
+	unsigned int len, offset;
+	struct scatterlist *sg;
+
+	/* check if we are allowed to write */
+	if (info->read_only || info->force_read_only) {
+		set_sense_info (7, 0x27, 0);	/* read only */
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	// Since we only write one block at a time, we have to create
+	// a bounce buffer and move the data a piece at a time between the
+	// bounce buffer and the actual transfer buffer.
+
+	len = min((unsigned int) sectors, (unsigned int) info->blocksize >>
+			info->smallpageshift) * PAGESIZE;
+	buffer = kmalloc(len, GFP_NOIO);
+	if (buffer == NULL)
+		return USB_STOR_TRANSPORT_ERROR;
+	offset = 0;
+	sg = NULL;
+
+	while (sectors > 0) {
+
+		/* have we got to end? */
+		if (lba >= info->max_log_blks)
+			break;
+
+		pba = info->lba_to_pba[lba];
+
+		// Write as many sectors as possible in this block
+
+		pages = min((unsigned int) sectors << info->smallpageshift,
+				info->blocksize - page);
+		len = pages << info->pageshift;
+
+		// Get the data from the transfer buffer
+		usb_stor_access_xfer_buf(buffer, len, us->srb,
+				&sg, &offset, FROM_XFER_BUF);
+
+		usb_stor_dbg(us, "Write %02X pages, to PBA %04X (LBA %04X) page %02X\n",
+			     pages, pba, lba, page);
+			
+		command[4] = 0;
+
+		if (pba == NOT_ALLOCATED) {
+			/* no pba allocated for this lba, find a free pba to use */
+
+			int max_pba = (info->max_log_blks / 250 ) * 256;
+			int found_count = 0;
+			int found_pba = -1;
+
+			/* set pba to first block in zone lba is in */
+			pba = (lba / 1000) * 1024;
+
+			usb_stor_dbg(us, "No PBA for LBA %04X\n", lba);
+
+			if (max_pba > 1024)
+				max_pba = 1024;
+
+			/*
+			 * Scan through the map looking for an unused block
+			 * leave 16 unused blocks at start (or as many as
+			 * possible) since the sddr55 seems to reuse a used
+			 * block when it shouldn't if we don't leave space.
+			 */
+			for (i = 0; i < max_pba; i++, pba++) {
+				if (info->pba_to_lba[pba] == UNUSED_BLOCK) {
+					found_pba = pba;
+					if (found_count++ > 16)
+						break;
+				}
+			}
+
+			pba = found_pba;
+
+			if (pba == -1) {
+				/* oh dear */
+				usb_stor_dbg(us, "Couldn't find unallocated block\n");
+
+				set_sense_info (3, 0x31, 0);	/* medium error */
+				result = USB_STOR_TRANSPORT_FAILED;
+				goto leave;
+			}
+
+			usb_stor_dbg(us, "Allocating PBA %04X for LBA %04X\n",
+				     pba, lba);
+
+			/* set writing to unallocated block flag */
+			command[4] = 0x40;
+		}
+
+		address = (pba << info->blockshift) + page;
+
+		command[1] = LSB_of(address>>16);
+		command[2] = LSB_of(address>>8); 
+		command[3] = LSB_of(address);
+
+		/* set the lba into the command, modulo 1000 */
+		command[0] = LSB_of(lba % 1000);
+		command[6] = MSB_of(lba % 1000);
+
+		command[4] |= LSB_of(pages >> info->smallpageshift);
+		command[5] = 0xB0;
+		command[7] = 0x86;
+
+		/* send command */
+		result = sddr55_bulk_transport(us,
+			DMA_TO_DEVICE, command, 8);
+
+		if (result != USB_STOR_XFER_GOOD) {
+			usb_stor_dbg(us, "Result for send_command in write_data %d\n",
+				     result);
+
+			/* set_sense_info is superfluous here? */
+			set_sense_info (3, 0x3, 0);/* peripheral write error */
+			result = USB_STOR_TRANSPORT_FAILED;
+			goto leave;
+		}
+
+		/* send the data */
+		result = sddr55_bulk_transport(us,
+			DMA_TO_DEVICE, buffer, len);
+
+		if (result != USB_STOR_XFER_GOOD) {
+			usb_stor_dbg(us, "Result for send_data in write_data %d\n",
+				     result);
+
+			/* set_sense_info is superfluous here? */
+			set_sense_info (3, 0x3, 0);/* peripheral write error */
+			result = USB_STOR_TRANSPORT_FAILED;
+			goto leave;
+		}
+
+		/* now read status */
+		result = sddr55_bulk_transport(us, DMA_FROM_DEVICE, status, 6);
+
+		if (result != USB_STOR_XFER_GOOD) {
+			usb_stor_dbg(us, "Result for get_status in write_data %d\n",
+				     result);
+
+			/* set_sense_info is superfluous here? */
+			set_sense_info (3, 0x3, 0);/* peripheral write error */
+			result = USB_STOR_TRANSPORT_FAILED;
+			goto leave;
+		}
+
+		new_pba = (status[3] + (status[4] << 8) + (status[5] << 16))
+						  >> info->blockshift;
+
+		/* check status for error */
+		if (status[0] == 0xff && status[1] == 0x4) {
+			info->pba_to_lba[new_pba] = BAD_BLOCK;
+
+			set_sense_info (3, 0x0c, 0);
+			result = USB_STOR_TRANSPORT_FAILED;
+			goto leave;
+		}
+
+		usb_stor_dbg(us, "Updating maps for LBA %04X: old PBA %04X, new PBA %04X\n",
+			     lba, pba, new_pba);
+
+		/* update the lba<->pba maps, note new_pba might be the same as pba */
+		info->lba_to_pba[lba] = new_pba;
+		info->pba_to_lba[pba] = UNUSED_BLOCK;
+
+		/* check that new_pba wasn't already being used */
+		if (info->pba_to_lba[new_pba] != UNUSED_BLOCK) {
+			printk(KERN_ERR "sddr55 error: new PBA %04X already in use for LBA %04X\n",
+				new_pba, info->pba_to_lba[new_pba]);
+			info->fatal_error = 1;
+			set_sense_info (3, 0x31, 0);
+			result = USB_STOR_TRANSPORT_FAILED;
+			goto leave;
+		}
+
+		/* update the pba<->lba maps for new_pba */
+		info->pba_to_lba[new_pba] = lba % 1000;
+
+		page = 0;
+		lba++;
+		sectors -= pages >> info->smallpageshift;
+	}
+	result = USB_STOR_TRANSPORT_GOOD;
+
+ leave:
+	kfree(buffer);
+	return result;
+}
+
+static int sddr55_read_deviceID(struct us_data *us,
+		unsigned char *manufacturerID,
+		unsigned char *deviceID) {
+
+	int result;
+	unsigned char *command = us->iobuf;
+	unsigned char *content = us->iobuf;
+
+	memset(command, 0, 8);
+	command[5] = 0xB0;
+	command[7] = 0x84;
+	result = sddr55_bulk_transport(us, DMA_TO_DEVICE, command, 8);
+
+	usb_stor_dbg(us, "Result of send_control for device ID is %d\n",
+		     result);
+
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	result = sddr55_bulk_transport(us,
+		DMA_FROM_DEVICE, content, 4);
+
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	*manufacturerID = content[0];
+	*deviceID = content[1];
+
+	if (content[0] != 0xff)	{
+    		result = sddr55_bulk_transport(us,
+			DMA_FROM_DEVICE, content, 2);
+	}
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+
+static int sddr55_reset(struct us_data *us)
+{
+	return 0;
+}
+
+
+static unsigned long sddr55_get_capacity(struct us_data *us) {
+
+	unsigned char uninitialized_var(manufacturerID);
+	unsigned char uninitialized_var(deviceID);
+	int result;
+	struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra;
+
+	usb_stor_dbg(us, "Reading capacity...\n");
+
+	result = sddr55_read_deviceID(us,
+		&manufacturerID,
+		&deviceID);
+
+	usb_stor_dbg(us, "Result of read_deviceID is %d\n", result);
+
+	if (result != USB_STOR_XFER_GOOD)
+		return 0;
+
+	usb_stor_dbg(us, "Device ID = %02X\n", deviceID);
+	usb_stor_dbg(us, "Manuf  ID = %02X\n", manufacturerID);
+
+	info->pageshift = 9;
+	info->smallpageshift = 0;
+	info->blocksize = 16;
+	info->blockshift = 4;
+	info->blockmask = 15;
+
+	switch (deviceID) {
+
+	case 0x6e: // 1MB
+	case 0xe8:
+	case 0xec:
+		info->pageshift = 8;
+		info->smallpageshift = 1;
+		return 0x00100000;
+
+	case 0xea: // 2MB
+	case 0x64:
+		info->pageshift = 8;
+		info->smallpageshift = 1;
+		/* fall through */
+	case 0x5d: // 5d is a ROM card with pagesize 512.
+		return 0x00200000;
+
+	case 0xe3: // 4MB
+	case 0xe5:
+	case 0x6b:
+	case 0xd5:
+		return 0x00400000;
+
+	case 0xe6: // 8MB
+	case 0xd6:
+		return 0x00800000;
+
+	case 0x73: // 16MB
+		info->blocksize = 32;
+		info->blockshift = 5;
+		info->blockmask = 31;
+		return 0x01000000;
+
+	case 0x75: // 32MB
+		info->blocksize = 32;
+		info->blockshift = 5;
+		info->blockmask = 31;
+		return 0x02000000;
+
+	case 0x76: // 64MB
+		info->blocksize = 32;
+		info->blockshift = 5;
+		info->blockmask = 31;
+		return 0x04000000;
+
+	case 0x79: // 128MB
+		info->blocksize = 32;
+		info->blockshift = 5;
+		info->blockmask = 31;
+		return 0x08000000;
+
+	default: // unknown
+		return 0;
+
+	}
+}
+
+static int sddr55_read_map(struct us_data *us) {
+
+	struct sddr55_card_info *info = (struct sddr55_card_info *)(us->extra);
+	int numblocks;
+	unsigned char *buffer;
+	unsigned char *command = us->iobuf;
+	int i;
+	unsigned short lba;
+	unsigned short max_lba;
+	int result;
+
+	if (!info->capacity)
+		return -1;
+
+	numblocks = info->capacity >> (info->blockshift + info->pageshift);
+	
+	buffer = kmalloc_array(numblocks, 2, GFP_NOIO );
+	
+	if (!buffer)
+		return -1;
+
+	memset(command, 0, 8);
+	command[5] = 0xB0;
+	command[6] = numblocks * 2 / 256;
+	command[7] = 0x8A;
+
+	result = sddr55_bulk_transport(us, DMA_TO_DEVICE, command, 8);
+
+	if ( result != USB_STOR_XFER_GOOD) {
+		kfree (buffer);
+		return -1;
+	}
+
+	result = sddr55_bulk_transport(us, DMA_FROM_DEVICE, buffer, numblocks * 2);
+
+	if ( result != USB_STOR_XFER_GOOD) {
+		kfree (buffer);
+		return -1;
+	}
+
+	result = sddr55_bulk_transport(us, DMA_FROM_DEVICE, command, 2);
+
+	if ( result != USB_STOR_XFER_GOOD) {
+		kfree (buffer);
+		return -1;
+	}
+
+	kfree(info->lba_to_pba);
+	kfree(info->pba_to_lba);
+	info->lba_to_pba = kmalloc_array(numblocks, sizeof(int), GFP_NOIO);
+	info->pba_to_lba = kmalloc_array(numblocks, sizeof(int), GFP_NOIO);
+
+	if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) {
+		kfree(info->lba_to_pba);
+		kfree(info->pba_to_lba);
+		info->lba_to_pba = NULL;
+		info->pba_to_lba = NULL;
+		kfree(buffer);
+		return -1;
+	}
+
+	memset(info->lba_to_pba, 0xff, numblocks*sizeof(int));
+	memset(info->pba_to_lba, 0xff, numblocks*sizeof(int));
+
+	/* set maximum lba */
+	max_lba = info->max_log_blks;
+	if (max_lba > 1000)
+		max_lba = 1000;
+
+	/*
+	 * Each block is 64 bytes of control data, so block i is located in
+	 * scatterlist block i*64/128k = i*(2^6)*(2^-17) = i*(2^-11)
+	 */
+
+	for (i=0; i<numblocks; i++) {
+		int zone = i / 1024;
+
+		lba = short_pack(buffer[i * 2], buffer[i * 2 + 1]);
+
+			/*
+			 * Every 1024 physical blocks ("zone"), the LBA numbers
+			 * go back to zero, but are within a higher
+			 * block of LBA's. Also, there is a maximum of
+			 * 1000 LBA's per zone. In other words, in PBA
+			 * 1024-2047 you will find LBA 0-999 which are
+			 * really LBA 1000-1999. Yes, this wastes 24
+			 * physical blocks per zone. Go figure. 
+			 * These devices can have blocks go bad, so there
+			 * are 24 spare blocks to use when blocks do go bad.
+			 */
+
+			/*
+			 * SDDR55 returns 0xffff for a bad block, and 0x400 for the 
+			 * CIS block. (Is this true for cards 8MB or less??)
+			 * Record these in the physical to logical map
+			 */ 
+
+		info->pba_to_lba[i] = lba;
+
+		if (lba >= max_lba) {
+			continue;
+		}
+		
+		if (info->lba_to_pba[lba + zone * 1000] != NOT_ALLOCATED &&
+		    !info->force_read_only) {
+			printk(KERN_WARNING
+			       "sddr55: map inconsistency at LBA %04X\n",
+			       lba + zone * 1000);
+			info->force_read_only = 1;
+		}
+
+		if (lba<0x10 || (lba>=0x3E0 && lba<0x3EF))
+			usb_stor_dbg(us, "LBA %04X <-> PBA %04X\n", lba, i);
+
+		info->lba_to_pba[lba + zone * 1000] = i;
+	}
+
+	kfree(buffer);
+	return 0;
+}
+
+
+static void sddr55_card_info_destructor(void *extra) {
+	struct sddr55_card_info *info = (struct sddr55_card_info *)extra;
+
+	if (!extra)
+		return;
+
+	kfree(info->lba_to_pba);
+	kfree(info->pba_to_lba);
+}
+
+
+/*
+ * Transport for the Sandisk SDDR-55
+ */
+static int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+	int result;
+	static unsigned char inquiry_response[8] = {
+		0x00, 0x80, 0x00, 0x02, 0x1F, 0x00, 0x00, 0x00
+	};
+ 	// write-protected for now, no block descriptor support
+	static unsigned char mode_page_01[20] = {
+		0x0, 0x12, 0x00, 0x80, 0x0, 0x0, 0x0, 0x0,
+		0x01, 0x0A,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+	};
+	unsigned char *ptr = us->iobuf;
+	unsigned long capacity;
+	unsigned int lba;
+	unsigned int pba;
+	unsigned int page;
+	unsigned short pages;
+	struct sddr55_card_info *info;
+
+	if (!us->extra) {
+		us->extra = kzalloc(
+			sizeof(struct sddr55_card_info), GFP_NOIO);
+		if (!us->extra)
+			return USB_STOR_TRANSPORT_ERROR;
+		us->extra_destructor = sddr55_card_info_destructor;
+	}
+
+	info = (struct sddr55_card_info *)(us->extra);
+
+	if (srb->cmnd[0] == REQUEST_SENSE) {
+		usb_stor_dbg(us, "request sense %02x/%02x/%02x\n",
+			     info->sense_data[2],
+			     info->sense_data[12],
+			     info->sense_data[13]);
+
+		memcpy (ptr, info->sense_data, sizeof info->sense_data);
+		ptr[0] = 0x70;
+		ptr[7] = 11;
+		usb_stor_set_xfer_buf (ptr, sizeof info->sense_data, srb);
+		memset (info->sense_data, 0, sizeof info->sense_data);
+
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	memset (info->sense_data, 0, sizeof info->sense_data);
+
+	/*
+	 * Dummy up a response for INQUIRY since SDDR55 doesn't
+	 * respond to INQUIRY commands
+	 */
+
+	if (srb->cmnd[0] == INQUIRY) {
+		memcpy(ptr, inquiry_response, 8);
+		fill_inquiry_response(us, ptr, 36);
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	/*
+	 * only check card status if the map isn't allocated, ie no card seen yet
+	 * or if it's been over half a second since we last accessed it
+	 */
+	if (info->lba_to_pba == NULL || time_after(jiffies, info->last_access + HZ/2)) {
+
+		/* check to see if a card is fitted */
+		result = sddr55_status (us);
+		if (result) {
+			result = sddr55_status (us);
+			if (!result) {
+			set_sense_info (6, 0x28, 0);	/* new media, set unit attention, not ready to ready */
+			}
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+	}
+
+	/*
+	 * if we detected a problem with the map when writing,
+	 * don't allow any more access
+	 */
+	if (info->fatal_error) {
+
+		set_sense_info (3, 0x31, 0);
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	if (srb->cmnd[0] == READ_CAPACITY) {
+
+		capacity = sddr55_get_capacity(us);
+
+		if (!capacity) {
+			set_sense_info (3, 0x30, 0); /* incompatible medium */
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+
+		info->capacity = capacity;
+
+		/*
+		 * figure out the maximum logical block number, allowing for
+		 * the fact that only 250 out of every 256 are used
+		 */
+		info->max_log_blks = ((info->capacity >> (info->pageshift + info->blockshift)) / 256) * 250;
+
+		/*
+		 * Last page in the card, adjust as we only use 250 out of
+		 * every 256 pages
+		 */
+		capacity = (capacity / 256) * 250;
+
+		capacity /= PAGESIZE;
+		capacity--;
+
+		((__be32 *) ptr)[0] = cpu_to_be32(capacity);
+		((__be32 *) ptr)[1] = cpu_to_be32(PAGESIZE);
+		usb_stor_set_xfer_buf(ptr, 8, srb);
+
+		sddr55_read_map(us);
+
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == MODE_SENSE_10) {
+
+		memcpy(ptr, mode_page_01, sizeof mode_page_01);
+		ptr[3] = (info->read_only || info->force_read_only) ? 0x80 : 0;
+		usb_stor_set_xfer_buf(ptr, sizeof(mode_page_01), srb);
+
+		if ( (srb->cmnd[2] & 0x3F) == 0x01 ) {
+			usb_stor_dbg(us, "Dummy up request for mode page 1\n");
+			return USB_STOR_TRANSPORT_GOOD;
+
+		} else if ( (srb->cmnd[2] & 0x3F) == 0x3F ) {
+			usb_stor_dbg(us, "Dummy up request for all mode pages\n");
+			return USB_STOR_TRANSPORT_GOOD;
+		}
+
+		set_sense_info (5, 0x24, 0);	/* invalid field in command */
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
+
+		usb_stor_dbg(us, "%s medium removal. Not that I can do anything about it...\n",
+			     (srb->cmnd[4]&0x03) ? "Prevent" : "Allow");
+
+		return USB_STOR_TRANSPORT_GOOD;
+
+	}
+
+	if (srb->cmnd[0] == READ_10 || srb->cmnd[0] == WRITE_10) {
+
+		page = short_pack(srb->cmnd[3], srb->cmnd[2]);
+		page <<= 16;
+		page |= short_pack(srb->cmnd[5], srb->cmnd[4]);
+		pages = short_pack(srb->cmnd[8], srb->cmnd[7]);
+
+		page <<= info->smallpageshift;
+
+		// convert page to block and page-within-block
+
+		lba = page >> info->blockshift;
+		page = page & info->blockmask;
+
+		// locate physical block corresponding to logical block
+
+		if (lba >= info->max_log_blks) {
+
+			usb_stor_dbg(us, "Error: Requested LBA %04X exceeds maximum block %04X\n",
+				     lba, info->max_log_blks - 1);
+
+			set_sense_info (5, 0x24, 0);	/* invalid field in command */
+
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+
+		pba = info->lba_to_pba[lba];
+
+		if (srb->cmnd[0] == WRITE_10) {
+			usb_stor_dbg(us, "WRITE_10: write block %04X (LBA %04X) page %01X pages %d\n",
+				     pba, lba, page, pages);
+
+			return sddr55_write_data(us, lba, page, pages);
+		} else {
+			usb_stor_dbg(us, "READ_10: read block %04X (LBA %04X) page %01X pages %d\n",
+				     pba, lba, page, pages);
+
+			return sddr55_read_data(us, lba, page, pages);
+		}
+	}
+
+
+	if (srb->cmnd[0] == TEST_UNIT_READY) {
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == START_STOP) {
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	set_sense_info (5, 0x20, 0);	/* illegal command */
+
+	return USB_STOR_TRANSPORT_FAILED; // FIXME: sense buffer?
+}
+
+static struct scsi_host_template sddr55_host_template;
+
+static int sddr55_probe(struct usb_interface *intf,
+			 const struct usb_device_id *id)
+{
+	struct us_data *us;
+	int result;
+
+	result = usb_stor_probe1(&us, intf, id,
+			(id - sddr55_usb_ids) + sddr55_unusual_dev_list,
+			&sddr55_host_template);
+	if (result)
+		return result;
+
+	us->transport_name = "SDDR55";
+	us->transport = sddr55_transport;
+	us->transport_reset = sddr55_reset;
+	us->max_lun = 0;
+
+	result = usb_stor_probe2(us);
+	return result;
+}
+
+static struct usb_driver sddr55_driver = {
+	.name =		DRV_NAME,
+	.probe =	sddr55_probe,
+	.disconnect =	usb_stor_disconnect,
+	.suspend =	usb_stor_suspend,
+	.resume =	usb_stor_resume,
+	.reset_resume =	usb_stor_reset_resume,
+	.pre_reset =	usb_stor_pre_reset,
+	.post_reset =	usb_stor_post_reset,
+	.id_table =	sddr55_usb_ids,
+	.soft_unbind =	1,
+	.no_dynamic_id = 1,
+};
+
+module_usb_stor_driver(sddr55_driver, sddr55_host_template, DRV_NAME);
diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c
new file mode 100644
index 0000000..854498e
--- /dev/null
+++ b/drivers/usb/storage/shuttle_usbat.c
@@ -0,0 +1,1871 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for SCM Microsystems (a.k.a. Shuttle) USB-ATAPI cable
+ *
+ * Current development and maintenance by:
+ *   (c) 2000, 2001 Robert Baruch (autophile@starband.net)
+ *   (c) 2004, 2005 Daniel Drake <dsd@gentoo.org>
+ *
+ * Developed with the assistance of:
+ *   (c) 2002 Alan Stern <stern@rowland.org>
+ *
+ * Flash support based on earlier work by:
+ *   (c) 2002 Thomas Kreiling <usbdev@sm04.de>
+ *
+ * Many originally ATAPI devices were slightly modified to meet the USB
+ * market by using some kind of translation from ATAPI to USB on the host,
+ * and the peripheral would translate from USB back to ATAPI.
+ *
+ * SCM Microsystems (www.scmmicro.com) makes a device, sold to OEM's only, 
+ * which does the USB-to-ATAPI conversion.  By obtaining the data sheet on
+ * their device under nondisclosure agreement, I have been able to write
+ * this driver for Linux.
+ *
+ * The chip used in the device can also be used for EPP and ISA translation
+ * as well. This driver is only guaranteed to work with the ATAPI
+ * translation.
+ *
+ * See the Kconfig help text for a list of devices known to be supported by
+ * this driver.
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/cdrom.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "protocol.h"
+#include "debug.h"
+#include "scsiglue.h"
+
+#define DRV_NAME "ums-usbat"
+
+MODULE_DESCRIPTION("Driver for SCM Microsystems (a.k.a. Shuttle) USB-ATAPI cable");
+MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>, Robert Baruch <autophile@starband.net>");
+MODULE_LICENSE("GPL");
+
+/* Supported device types */
+#define USBAT_DEV_HP8200	0x01
+#define USBAT_DEV_FLASH		0x02
+
+#define USBAT_EPP_PORT		0x10
+#define USBAT_EPP_REGISTER	0x30
+#define USBAT_ATA		0x40
+#define USBAT_ISA		0x50
+
+/* Commands (need to be logically OR'd with an access type */
+#define USBAT_CMD_READ_REG		0x00
+#define USBAT_CMD_WRITE_REG		0x01
+#define USBAT_CMD_READ_BLOCK	0x02
+#define USBAT_CMD_WRITE_BLOCK	0x03
+#define USBAT_CMD_COND_READ_BLOCK	0x04
+#define USBAT_CMD_COND_WRITE_BLOCK	0x05
+#define USBAT_CMD_WRITE_REGS	0x07
+
+/* Commands (these don't need an access type) */
+#define USBAT_CMD_EXEC_CMD	0x80
+#define USBAT_CMD_SET_FEAT	0x81
+#define USBAT_CMD_UIO		0x82
+
+/* Methods of accessing UIO register */
+#define USBAT_UIO_READ	1
+#define USBAT_UIO_WRITE	0
+
+/* Qualifier bits */
+#define USBAT_QUAL_FCQ	0x20	/* full compare */
+#define USBAT_QUAL_ALQ	0x10	/* auto load subcount */
+
+/* USBAT Flash Media status types */
+#define USBAT_FLASH_MEDIA_NONE	0
+#define USBAT_FLASH_MEDIA_CF	1
+
+/* USBAT Flash Media change types */
+#define USBAT_FLASH_MEDIA_SAME	0
+#define USBAT_FLASH_MEDIA_CHANGED	1
+
+/* USBAT ATA registers */
+#define USBAT_ATA_DATA      0x10  /* read/write data (R/W) */
+#define USBAT_ATA_FEATURES  0x11  /* set features (W) */
+#define USBAT_ATA_ERROR     0x11  /* error (R) */
+#define USBAT_ATA_SECCNT    0x12  /* sector count (R/W) */
+#define USBAT_ATA_SECNUM    0x13  /* sector number (R/W) */
+#define USBAT_ATA_LBA_ME    0x14  /* cylinder low (R/W) */
+#define USBAT_ATA_LBA_HI    0x15  /* cylinder high (R/W) */
+#define USBAT_ATA_DEVICE    0x16  /* head/device selection (R/W) */
+#define USBAT_ATA_STATUS    0x17  /* device status (R) */
+#define USBAT_ATA_CMD       0x17  /* device command (W) */
+#define USBAT_ATA_ALTSTATUS 0x0E  /* status (no clear IRQ) (R) */
+
+/* USBAT User I/O Data registers */
+#define USBAT_UIO_EPAD		0x80 /* Enable Peripheral Control Signals */
+#define USBAT_UIO_CDT		0x40 /* Card Detect (Read Only) */
+				     /* CDT = ACKD & !UI1 & !UI0 */
+#define USBAT_UIO_1		0x20 /* I/O 1 */
+#define USBAT_UIO_0		0x10 /* I/O 0 */
+#define USBAT_UIO_EPP_ATA	0x08 /* 1=EPP mode, 0=ATA mode */
+#define USBAT_UIO_UI1		0x04 /* Input 1 */
+#define USBAT_UIO_UI0		0x02 /* Input 0 */
+#define USBAT_UIO_INTR_ACK	0x01 /* Interrupt (ATA/ISA)/Acknowledge (EPP) */
+
+/* USBAT User I/O Enable registers */
+#define USBAT_UIO_DRVRST	0x80 /* Reset Peripheral */
+#define USBAT_UIO_ACKD		0x40 /* Enable Card Detect */
+#define USBAT_UIO_OE1		0x20 /* I/O 1 set=output/clr=input */
+				     /* If ACKD=1, set OE1 to 1 also. */
+#define USBAT_UIO_OE0		0x10 /* I/O 0 set=output/clr=input */
+#define USBAT_UIO_ADPRST	0x01 /* Reset SCM chip */
+
+/* USBAT Features */
+#define USBAT_FEAT_ETEN	0x80	/* External trigger enable */
+#define USBAT_FEAT_U1	0x08
+#define USBAT_FEAT_U0	0x04
+#define USBAT_FEAT_ET1	0x02
+#define USBAT_FEAT_ET2	0x01
+
+struct usbat_info {
+	int devicetype;
+
+	/* Used for Flash readers only */
+	unsigned long sectors;     /* total sector count */
+	unsigned long ssize;       /* sector size in bytes */
+
+	unsigned char sense_key;
+	unsigned long sense_asc;   /* additional sense code */
+	unsigned long sense_ascq;  /* additional sense code qualifier */
+};
+
+#define short_pack(LSB,MSB) ( ((u16)(LSB)) | ( ((u16)(MSB))<<8 ) )
+#define LSB_of(s) ((s)&0xFF)
+#define MSB_of(s) ((s)>>8)
+
+static int transferred = 0;
+
+static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us);
+static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us);
+
+static int init_usbat_cd(struct us_data *us);
+static int init_usbat_flash(struct us_data *us);
+
+
+/*
+ * The table of devices
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+		    vendorName, productName, useProtocol, useTransport, \
+		    initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+  .driver_info = (flags) }
+
+static struct usb_device_id usbat_usb_ids[] = {
+#	include "unusual_usbat.h"
+	{ }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, usbat_usb_ids);
+
+#undef UNUSUAL_DEV
+
+/*
+ * The flags table
+ */
+#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
+		    vendor_name, product_name, use_protocol, use_transport, \
+		    init_function, Flags) \
+{ \
+	.vendorName = vendor_name,	\
+	.productName = product_name,	\
+	.useProtocol = use_protocol,	\
+	.useTransport = use_transport,	\
+	.initFunction = init_function,	\
+}
+
+static struct us_unusual_dev usbat_unusual_dev_list[] = {
+#	include "unusual_usbat.h"
+	{ }		/* Terminating entry */
+};
+
+#undef UNUSUAL_DEV
+
+/*
+ * Convenience function to produce an ATA read/write sectors command
+ * Use cmd=0x20 for read, cmd=0x30 for write
+ */
+static void usbat_pack_ata_sector_cmd(unsigned char *buf,
+					unsigned char thistime,
+					u32 sector, unsigned char cmd)
+{
+	buf[0] = 0;
+	buf[1] = thistime;
+	buf[2] = sector & 0xFF;
+	buf[3] = (sector >>  8) & 0xFF;
+	buf[4] = (sector >> 16) & 0xFF;
+	buf[5] = 0xE0 | ((sector >> 24) & 0x0F);
+	buf[6] = cmd;
+}
+
+/*
+ * Convenience function to get the device type (flash or hp8200)
+ */
+static int usbat_get_device_type(struct us_data *us)
+{
+	return ((struct usbat_info*)us->extra)->devicetype;
+}
+
+/*
+ * Read a register from the device
+ */
+static int usbat_read(struct us_data *us,
+		      unsigned char access,
+		      unsigned char reg,
+		      unsigned char *content)
+{
+	return usb_stor_ctrl_transfer(us,
+		us->recv_ctrl_pipe,
+		access | USBAT_CMD_READ_REG,
+		0xC0,
+		(u16)reg,
+		0,
+		content,
+		1);
+}
+
+/*
+ * Write to a register on the device
+ */
+static int usbat_write(struct us_data *us,
+		       unsigned char access,
+		       unsigned char reg,
+		       unsigned char content)
+{
+	return usb_stor_ctrl_transfer(us,
+		us->send_ctrl_pipe,
+		access | USBAT_CMD_WRITE_REG,
+		0x40,
+		short_pack(reg, content),
+		0,
+		NULL,
+		0);
+}
+
+/*
+ * Convenience function to perform a bulk read
+ */
+static int usbat_bulk_read(struct us_data *us,
+			   void* buf,
+			   unsigned int len,
+			   int use_sg)
+{
+	if (len == 0)
+		return USB_STOR_XFER_GOOD;
+
+	usb_stor_dbg(us, "len = %d\n", len);
+	return usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, buf, len, use_sg, NULL);
+}
+
+/*
+ * Convenience function to perform a bulk write
+ */
+static int usbat_bulk_write(struct us_data *us,
+			    void* buf,
+			    unsigned int len,
+			    int use_sg)
+{
+	if (len == 0)
+		return USB_STOR_XFER_GOOD;
+
+	usb_stor_dbg(us, "len = %d\n", len);
+	return usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, buf, len, use_sg, NULL);
+}
+
+/*
+ * Some USBAT-specific commands can only be executed over a command transport
+ * This transport allows one (len=8) or two (len=16) vendor-specific commands
+ * to be executed.
+ */
+static int usbat_execute_command(struct us_data *us,
+								 unsigned char *commands,
+								 unsigned int len)
+{
+	return usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
+								  USBAT_CMD_EXEC_CMD, 0x40, 0, 0,
+								  commands, len);
+}
+
+/*
+ * Read the status register
+ */
+static int usbat_get_status(struct us_data *us, unsigned char *status)
+{
+	int rc;
+	rc = usbat_read(us, USBAT_ATA, USBAT_ATA_STATUS, status);
+
+	usb_stor_dbg(us, "0x%02X\n", *status);
+	return rc;
+}
+
+/*
+ * Check the device status
+ */
+static int usbat_check_status(struct us_data *us)
+{
+	unsigned char *reply = us->iobuf;
+	int rc;
+
+	rc = usbat_get_status(us, reply);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_FAILED;
+
+	/* error/check condition (0x51 is ok) */
+	if (*reply & 0x01 && *reply != 0x51)
+		return USB_STOR_TRANSPORT_FAILED;
+
+	/* device fault */
+	if (*reply & 0x20)
+		return USB_STOR_TRANSPORT_FAILED;
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Stores critical information in internal registers in preparation for the execution
+ * of a conditional usbat_read_blocks or usbat_write_blocks call.
+ */
+static int usbat_set_shuttle_features(struct us_data *us,
+				      unsigned char external_trigger,
+				      unsigned char epp_control,
+				      unsigned char mask_byte,
+				      unsigned char test_pattern,
+				      unsigned char subcountH,
+				      unsigned char subcountL)
+{
+	unsigned char *command = us->iobuf;
+
+	command[0] = 0x40;
+	command[1] = USBAT_CMD_SET_FEAT;
+
+	/*
+	 * The only bit relevant to ATA access is bit 6
+	 * which defines 8 bit data access (set) or 16 bit (unset)
+	 */
+	command[2] = epp_control;
+
+	/*
+	 * If FCQ is set in the qualifier (defined in R/W cmd), then bits U0, U1,
+	 * ET1 and ET2 define an external event to be checked for on event of a
+	 * _read_blocks or _write_blocks operation. The read/write will not take
+	 * place unless the defined trigger signal is active.
+	 */
+	command[3] = external_trigger;
+
+	/*
+	 * The resultant byte of the mask operation (see mask_byte) is compared for
+	 * equivalence with this test pattern. If equal, the read/write will take
+	 * place.
+	 */
+	command[4] = test_pattern;
+
+	/*
+	 * This value is logically ANDed with the status register field specified
+	 * in the read/write command.
+	 */
+	command[5] = mask_byte;
+
+	/*
+	 * If ALQ is set in the qualifier, this field contains the address of the
+	 * registers where the byte count should be read for transferring the data.
+	 * If ALQ is not set, then this field contains the number of bytes to be
+	 * transferred.
+	 */
+	command[6] = subcountL;
+	command[7] = subcountH;
+
+	return usbat_execute_command(us, command, 8);
+}
+
+/*
+ * Block, waiting for an ATA device to become not busy or to report
+ * an error condition.
+ */
+static int usbat_wait_not_busy(struct us_data *us, int minutes)
+{
+	int i;
+	int result;
+	unsigned char *status = us->iobuf;
+
+	/*
+	 * Synchronizing cache on a CDR could take a heck of a long time,
+	 * but probably not more than 10 minutes or so. On the other hand,
+	 * doing a full blank on a CDRW at speed 1 will take about 75
+	 * minutes!
+	 */
+
+	for (i=0; i<1200+minutes*60; i++) {
+
+ 		result = usbat_get_status(us, status);
+
+		if (result!=USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+		if (*status & 0x01) { /* check condition */
+			result = usbat_read(us, USBAT_ATA, 0x10, status);
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+		if (*status & 0x20) /* device fault */
+			return USB_STOR_TRANSPORT_FAILED;
+
+		if ((*status & 0x80)==0x00) { /* not busy */
+			usb_stor_dbg(us, "Waited not busy for %d steps\n", i);
+			return USB_STOR_TRANSPORT_GOOD;
+		}
+
+		if (i<500)
+			msleep(10); /* 5 seconds */
+		else if (i<700)
+			msleep(50); /* 10 seconds */
+		else if (i<1200)
+			msleep(100); /* 50 seconds */
+		else
+			msleep(1000); /* X minutes */
+	}
+
+	usb_stor_dbg(us, "Waited not busy for %d minutes, timing out\n",
+		     minutes);
+	return USB_STOR_TRANSPORT_FAILED;
+}
+
+/*
+ * Read block data from the data register
+ */
+static int usbat_read_block(struct us_data *us,
+			    void* buf,
+			    unsigned short len,
+			    int use_sg)
+{
+	int result;
+	unsigned char *command = us->iobuf;
+
+	if (!len)
+		return USB_STOR_TRANSPORT_GOOD;
+
+	command[0] = 0xC0;
+	command[1] = USBAT_ATA | USBAT_CMD_READ_BLOCK;
+	command[2] = USBAT_ATA_DATA;
+	command[3] = 0;
+	command[4] = 0;
+	command[5] = 0;
+	command[6] = LSB_of(len);
+	command[7] = MSB_of(len);
+
+	result = usbat_execute_command(us, command, 8);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	result = usbat_bulk_read(us, buf, len, use_sg);
+	return (result == USB_STOR_XFER_GOOD ?
+			USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
+}
+
+/*
+ * Write block data via the data register
+ */
+static int usbat_write_block(struct us_data *us,
+			     unsigned char access,
+			     void* buf,
+			     unsigned short len,
+			     int minutes,
+			     int use_sg)
+{
+	int result;
+	unsigned char *command = us->iobuf;
+
+	if (!len)
+		return USB_STOR_TRANSPORT_GOOD;
+
+	command[0] = 0x40;
+	command[1] = access | USBAT_CMD_WRITE_BLOCK;
+	command[2] = USBAT_ATA_DATA;
+	command[3] = 0;
+	command[4] = 0;
+	command[5] = 0;
+	command[6] = LSB_of(len);
+	command[7] = MSB_of(len);
+
+	result = usbat_execute_command(us, command, 8);
+
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	result = usbat_bulk_write(us, buf, len, use_sg);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	return usbat_wait_not_busy(us, minutes);
+}
+
+/*
+ * Process read and write requests
+ */
+static int usbat_hp8200e_rw_block_test(struct us_data *us,
+				       unsigned char access,
+				       unsigned char *registers,
+				       unsigned char *data_out,
+				       unsigned short num_registers,
+				       unsigned char data_reg,
+				       unsigned char status_reg,
+				       unsigned char timeout,
+				       unsigned char qualifier,
+				       int direction,
+				       void *buf,
+				       unsigned short len,
+				       int use_sg,
+				       int minutes)
+{
+	int result;
+	unsigned int pipe = (direction == DMA_FROM_DEVICE) ?
+			us->recv_bulk_pipe : us->send_bulk_pipe;
+
+	unsigned char *command = us->iobuf;
+	int i, j;
+	int cmdlen;
+	unsigned char *data = us->iobuf;
+	unsigned char *status = us->iobuf;
+
+	BUG_ON(num_registers > US_IOBUF_SIZE/2);
+
+	for (i=0; i<20; i++) {
+
+		/*
+		 * The first time we send the full command, which consists
+		 * of downloading the SCSI command followed by downloading
+		 * the data via a write-and-test.  Any other time we only
+		 * send the command to download the data -- the SCSI command
+		 * is still 'active' in some sense in the device.
+		 * 
+		 * We're only going to try sending the data 10 times. After
+		 * that, we just return a failure.
+		 */
+
+		if (i==0) {
+			cmdlen = 16;
+			/*
+			 * Write to multiple registers
+			 * Not really sure the 0x07, 0x17, 0xfc, 0xe7 is
+			 * necessary here, but that's what came out of the
+			 * trace every single time.
+			 */
+			command[0] = 0x40;
+			command[1] = access | USBAT_CMD_WRITE_REGS;
+			command[2] = 0x07;
+			command[3] = 0x17;
+			command[4] = 0xFC;
+			command[5] = 0xE7;
+			command[6] = LSB_of(num_registers*2);
+			command[7] = MSB_of(num_registers*2);
+		} else
+			cmdlen = 8;
+
+		/* Conditionally read or write blocks */
+		command[cmdlen-8] = (direction==DMA_TO_DEVICE ? 0x40 : 0xC0);
+		command[cmdlen-7] = access |
+				(direction==DMA_TO_DEVICE ?
+				 USBAT_CMD_COND_WRITE_BLOCK : USBAT_CMD_COND_READ_BLOCK);
+		command[cmdlen-6] = data_reg;
+		command[cmdlen-5] = status_reg;
+		command[cmdlen-4] = timeout;
+		command[cmdlen-3] = qualifier;
+		command[cmdlen-2] = LSB_of(len);
+		command[cmdlen-1] = MSB_of(len);
+
+		result = usbat_execute_command(us, command, cmdlen);
+
+		if (result != USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		if (i==0) {
+
+			for (j=0; j<num_registers; j++) {
+				data[j<<1] = registers[j];
+				data[1+(j<<1)] = data_out[j];
+			}
+
+			result = usbat_bulk_write(us, data, num_registers*2, 0);
+			if (result != USB_STOR_XFER_GOOD)
+				return USB_STOR_TRANSPORT_ERROR;
+
+		}
+
+		result = usb_stor_bulk_transfer_sg(us,
+			pipe, buf, len, use_sg, NULL);
+
+		/*
+		 * If we get a stall on the bulk download, we'll retry
+		 * the bulk download -- but not the SCSI command because
+		 * in some sense the SCSI command is still 'active' and
+		 * waiting for the data. Don't ask me why this should be;
+		 * I'm only following what the Windoze driver did.
+		 *
+		 * Note that a stall for the test-and-read/write command means
+		 * that the test failed. In this case we're testing to make
+		 * sure that the device is error-free
+		 * (i.e. bit 0 -- CHK -- of status is 0). The most likely
+		 * hypothesis is that the USBAT chip somehow knows what
+		 * the device will accept, but doesn't give the device any
+		 * data until all data is received. Thus, the device would
+		 * still be waiting for the first byte of data if a stall
+		 * occurs, even if the stall implies that some data was
+		 * transferred.
+		 */
+
+		if (result == USB_STOR_XFER_SHORT ||
+				result == USB_STOR_XFER_STALLED) {
+
+			/*
+			 * If we're reading and we stalled, then clear
+			 * the bulk output pipe only the first time.
+			 */
+
+			if (direction==DMA_FROM_DEVICE && i==0) {
+				if (usb_stor_clear_halt(us,
+						us->send_bulk_pipe) < 0)
+					return USB_STOR_TRANSPORT_ERROR;
+			}
+
+			/*
+			 * Read status: is the device angry, or just busy?
+			 */
+
+ 			result = usbat_read(us, USBAT_ATA, 
+				direction==DMA_TO_DEVICE ?
+					USBAT_ATA_STATUS : USBAT_ATA_ALTSTATUS,
+				status);
+
+			if (result!=USB_STOR_XFER_GOOD)
+				return USB_STOR_TRANSPORT_ERROR;
+			if (*status & 0x01) /* check condition */
+				return USB_STOR_TRANSPORT_FAILED;
+			if (*status & 0x20) /* device fault */
+				return USB_STOR_TRANSPORT_FAILED;
+
+			usb_stor_dbg(us, "Redoing %s\n",
+				     direction == DMA_TO_DEVICE
+				     ? "write" : "read");
+
+		} else if (result != USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+		else
+			return usbat_wait_not_busy(us, minutes);
+
+	}
+
+	usb_stor_dbg(us, "Bummer! %s bulk data 20 times failed\n",
+		     direction == DMA_TO_DEVICE ? "Writing" : "Reading");
+
+	return USB_STOR_TRANSPORT_FAILED;
+}
+
+/*
+ * Write to multiple registers:
+ * Allows us to write specific data to any registers. The data to be written
+ * gets packed in this sequence: reg0, data0, reg1, data1, ..., regN, dataN
+ * which gets sent through bulk out.
+ * Not designed for large transfers of data!
+ */
+static int usbat_multiple_write(struct us_data *us,
+				unsigned char *registers,
+				unsigned char *data_out,
+				unsigned short num_registers)
+{
+	int i, result;
+	unsigned char *data = us->iobuf;
+	unsigned char *command = us->iobuf;
+
+	BUG_ON(num_registers > US_IOBUF_SIZE/2);
+
+	/* Write to multiple registers, ATA access */
+	command[0] = 0x40;
+	command[1] = USBAT_ATA | USBAT_CMD_WRITE_REGS;
+
+	/* No relevance */
+	command[2] = 0;
+	command[3] = 0;
+	command[4] = 0;
+	command[5] = 0;
+
+	/* Number of bytes to be transferred (incl. addresses and data) */
+	command[6] = LSB_of(num_registers*2);
+	command[7] = MSB_of(num_registers*2);
+
+	/* The setup command */
+	result = usbat_execute_command(us, command, 8);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	/* Create the reg/data, reg/data sequence */
+	for (i=0; i<num_registers; i++) {
+		data[i<<1] = registers[i];
+		data[1+(i<<1)] = data_out[i];
+	}
+
+	/* Send the data */
+	result = usbat_bulk_write(us, data, num_registers*2, 0);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	if (usbat_get_device_type(us) == USBAT_DEV_HP8200)
+		return usbat_wait_not_busy(us, 0);
+	else
+		return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Conditionally read blocks from device:
+ * Allows us to read blocks from a specific data register, based upon the
+ * condition that a status register can be successfully masked with a status
+ * qualifier. If this condition is not initially met, the read will wait
+ * up until a maximum amount of time has elapsed, as specified by timeout.
+ * The read will start when the condition is met, otherwise the command aborts.
+ *
+ * The qualifier defined here is not the value that is masked, it defines
+ * conditions for the write to take place. The actual masked qualifier (and
+ * other related details) are defined beforehand with _set_shuttle_features().
+ */
+static int usbat_read_blocks(struct us_data *us,
+			     void* buffer,
+			     int len,
+			     int use_sg)
+{
+	int result;
+	unsigned char *command = us->iobuf;
+
+	command[0] = 0xC0;
+	command[1] = USBAT_ATA | USBAT_CMD_COND_READ_BLOCK;
+	command[2] = USBAT_ATA_DATA;
+	command[3] = USBAT_ATA_STATUS;
+	command[4] = 0xFD; /* Timeout (ms); */
+	command[5] = USBAT_QUAL_FCQ;
+	command[6] = LSB_of(len);
+	command[7] = MSB_of(len);
+
+	/* Multiple block read setup command */
+	result = usbat_execute_command(us, command, 8);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_FAILED;
+	
+	/* Read the blocks we just asked for */
+	result = usbat_bulk_read(us, buffer, len, use_sg);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_FAILED;
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Conditionally write blocks to device:
+ * Allows us to write blocks to a specific data register, based upon the
+ * condition that a status register can be successfully masked with a status
+ * qualifier. If this condition is not initially met, the write will wait
+ * up until a maximum amount of time has elapsed, as specified by timeout.
+ * The read will start when the condition is met, otherwise the command aborts.
+ *
+ * The qualifier defined here is not the value that is masked, it defines
+ * conditions for the write to take place. The actual masked qualifier (and
+ * other related details) are defined beforehand with _set_shuttle_features().
+ */
+static int usbat_write_blocks(struct us_data *us,
+			      void* buffer,
+			      int len,
+			      int use_sg)
+{
+	int result;
+	unsigned char *command = us->iobuf;
+
+	command[0] = 0x40;
+	command[1] = USBAT_ATA | USBAT_CMD_COND_WRITE_BLOCK;
+	command[2] = USBAT_ATA_DATA;
+	command[3] = USBAT_ATA_STATUS;
+	command[4] = 0xFD; /* Timeout (ms) */
+	command[5] = USBAT_QUAL_FCQ;
+	command[6] = LSB_of(len);
+	command[7] = MSB_of(len);
+
+	/* Multiple block write setup command */
+	result = usbat_execute_command(us, command, 8);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_FAILED;
+	
+	/* Write the data */
+	result = usbat_bulk_write(us, buffer, len, use_sg);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_FAILED;
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Read the User IO register
+ */
+static int usbat_read_user_io(struct us_data *us, unsigned char *data_flags)
+{
+	int result;
+
+	result = usb_stor_ctrl_transfer(us,
+		us->recv_ctrl_pipe,
+		USBAT_CMD_UIO,
+		0xC0,
+		0,
+		0,
+		data_flags,
+		USBAT_UIO_READ);
+
+	usb_stor_dbg(us, "UIO register reads %02X\n", *data_flags);
+
+	return result;
+}
+
+/*
+ * Write to the User IO register
+ */
+static int usbat_write_user_io(struct us_data *us,
+			       unsigned char enable_flags,
+			       unsigned char data_flags)
+{
+	return usb_stor_ctrl_transfer(us,
+		us->send_ctrl_pipe,
+		USBAT_CMD_UIO,
+		0x40,
+		short_pack(enable_flags, data_flags),
+		0,
+		NULL,
+		USBAT_UIO_WRITE);
+}
+
+/*
+ * Reset the device
+ * Often needed on media change.
+ */
+static int usbat_device_reset(struct us_data *us)
+{
+	int rc;
+
+	/*
+	 * Reset peripheral, enable peripheral control signals
+	 * (bring reset signal up)
+	 */
+	rc = usbat_write_user_io(us,
+							 USBAT_UIO_DRVRST | USBAT_UIO_OE1 | USBAT_UIO_OE0,
+							 USBAT_UIO_EPAD | USBAT_UIO_1);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+			
+	/*
+	 * Enable peripheral control signals
+	 * (bring reset signal down)
+	 */
+	rc = usbat_write_user_io(us,
+							 USBAT_UIO_OE1  | USBAT_UIO_OE0,
+							 USBAT_UIO_EPAD | USBAT_UIO_1);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Enable card detect
+ */
+static int usbat_device_enable_cdt(struct us_data *us)
+{
+	int rc;
+
+	/* Enable peripheral control signals and card detect */
+	rc = usbat_write_user_io(us,
+							 USBAT_UIO_ACKD | USBAT_UIO_OE1  | USBAT_UIO_OE0,
+							 USBAT_UIO_EPAD | USBAT_UIO_1);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Determine if media is present.
+ */
+static int usbat_flash_check_media_present(struct us_data *us,
+					   unsigned char *uio)
+{
+	if (*uio & USBAT_UIO_UI0) {
+		usb_stor_dbg(us, "no media detected\n");
+		return USBAT_FLASH_MEDIA_NONE;
+	}
+
+	return USBAT_FLASH_MEDIA_CF;
+}
+
+/*
+ * Determine if media has changed since last operation
+ */
+static int usbat_flash_check_media_changed(struct us_data *us,
+					   unsigned char *uio)
+{
+	if (*uio & USBAT_UIO_0) {
+		usb_stor_dbg(us, "media change detected\n");
+		return USBAT_FLASH_MEDIA_CHANGED;
+	}
+
+	return USBAT_FLASH_MEDIA_SAME;
+}
+
+/*
+ * Check for media change / no media and handle the situation appropriately
+ */
+static int usbat_flash_check_media(struct us_data *us,
+				   struct usbat_info *info)
+{
+	int rc;
+	unsigned char *uio = us->iobuf;
+
+	rc = usbat_read_user_io(us, uio);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	/* Check for media existence */
+	rc = usbat_flash_check_media_present(us, uio);
+	if (rc == USBAT_FLASH_MEDIA_NONE) {
+		info->sense_key = 0x02;
+		info->sense_asc = 0x3A;
+		info->sense_ascq = 0x00;
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	/* Check for media change */
+	rc = usbat_flash_check_media_changed(us, uio);
+	if (rc == USBAT_FLASH_MEDIA_CHANGED) {
+
+		/* Reset and re-enable card detect */
+		rc = usbat_device_reset(us);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+		rc = usbat_device_enable_cdt(us);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+
+		msleep(50);
+
+		rc = usbat_read_user_io(us, uio);
+		if (rc != USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+		
+		info->sense_key = UNIT_ATTENTION;
+		info->sense_asc = 0x28;
+		info->sense_ascq = 0x00;
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Determine whether we are controlling a flash-based reader/writer,
+ * or a HP8200-based CD drive.
+ * Sets transport functions as appropriate.
+ */
+static int usbat_identify_device(struct us_data *us,
+				 struct usbat_info *info)
+{
+	int rc;
+	unsigned char status;
+
+	if (!us || !info)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	rc = usbat_device_reset(us);
+	if (rc != USB_STOR_TRANSPORT_GOOD)
+		return rc;
+	msleep(500);
+
+	/*
+	 * In attempt to distinguish between HP CDRW's and Flash readers, we now
+	 * execute the IDENTIFY PACKET DEVICE command. On ATA devices (i.e. flash
+	 * readers), this command should fail with error. On ATAPI devices (i.e.
+	 * CDROM drives), it should succeed.
+	 */
+	rc = usbat_write(us, USBAT_ATA, USBAT_ATA_CMD, 0xA1);
+ 	if (rc != USB_STOR_XFER_GOOD)
+ 		return USB_STOR_TRANSPORT_ERROR;
+
+	rc = usbat_get_status(us, &status);
+ 	if (rc != USB_STOR_XFER_GOOD)
+ 		return USB_STOR_TRANSPORT_ERROR;
+
+	/* Check for error bit, or if the command 'fell through' */
+	if (status == 0xA1 || !(status & 0x01)) {
+		/* Device is HP 8200 */
+		usb_stor_dbg(us, "Detected HP8200 CDRW\n");
+		info->devicetype = USBAT_DEV_HP8200;
+	} else {
+		/* Device is a CompactFlash reader/writer */
+		usb_stor_dbg(us, "Detected Flash reader/writer\n");
+		info->devicetype = USBAT_DEV_FLASH;
+	}
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Set the transport function based on the device type
+ */
+static int usbat_set_transport(struct us_data *us,
+			       struct usbat_info *info,
+			       int devicetype)
+{
+
+	if (!info->devicetype)
+		info->devicetype = devicetype;
+
+	if (!info->devicetype)
+		usbat_identify_device(us, info);
+
+	switch (info->devicetype) {
+	default:
+		return USB_STOR_TRANSPORT_ERROR;
+
+	case  USBAT_DEV_HP8200:
+		us->transport = usbat_hp8200e_transport;
+		break;
+
+	case USBAT_DEV_FLASH:
+		us->transport = usbat_flash_transport;
+		break;
+	}
+
+	return 0;
+}
+
+/*
+ * Read the media capacity
+ */
+static int usbat_flash_get_sector_count(struct us_data *us,
+					struct usbat_info *info)
+{
+	unsigned char registers[3] = {
+		USBAT_ATA_SECCNT,
+		USBAT_ATA_DEVICE,
+		USBAT_ATA_CMD,
+	};
+	unsigned char  command[3] = { 0x01, 0xA0, 0xEC };
+	unsigned char *reply;
+	unsigned char status;
+	int rc;
+
+	if (!us || !info)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	reply = kmalloc(512, GFP_NOIO);
+	if (!reply)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	/* ATA command : IDENTIFY DEVICE */
+	rc = usbat_multiple_write(us, registers, command, 3);
+	if (rc != USB_STOR_XFER_GOOD) {
+		usb_stor_dbg(us, "Gah! identify_device failed\n");
+		rc = USB_STOR_TRANSPORT_ERROR;
+		goto leave;
+	}
+
+	/* Read device status */
+	if (usbat_get_status(us, &status) != USB_STOR_XFER_GOOD) {
+		rc = USB_STOR_TRANSPORT_ERROR;
+		goto leave;
+	}
+
+	msleep(100);
+
+	/* Read the device identification data */
+	rc = usbat_read_block(us, reply, 512, 0);
+	if (rc != USB_STOR_TRANSPORT_GOOD)
+		goto leave;
+
+	info->sectors = ((u32)(reply[117]) << 24) |
+		((u32)(reply[116]) << 16) |
+		((u32)(reply[115]) <<  8) |
+		((u32)(reply[114])      );
+
+	rc = USB_STOR_TRANSPORT_GOOD;
+
+ leave:
+	kfree(reply);
+	return rc;
+}
+
+/*
+ * Read data from device
+ */
+static int usbat_flash_read_data(struct us_data *us,
+								 struct usbat_info *info,
+								 u32 sector,
+								 u32 sectors)
+{
+	unsigned char registers[7] = {
+		USBAT_ATA_FEATURES,
+		USBAT_ATA_SECCNT,
+		USBAT_ATA_SECNUM,
+		USBAT_ATA_LBA_ME,
+		USBAT_ATA_LBA_HI,
+		USBAT_ATA_DEVICE,
+		USBAT_ATA_STATUS,
+	};
+	unsigned char command[7];
+	unsigned char *buffer;
+	unsigned char  thistime;
+	unsigned int totallen, alloclen;
+	int len, result;
+	unsigned int sg_offset = 0;
+	struct scatterlist *sg = NULL;
+
+	result = usbat_flash_check_media(us, info);
+	if (result != USB_STOR_TRANSPORT_GOOD)
+		return result;
+
+	/*
+	 * we're working in LBA mode.  according to the ATA spec,
+	 * we can support up to 28-bit addressing.  I don't know if Jumpshot
+	 * supports beyond 24-bit addressing.  It's kind of hard to test
+	 * since it requires > 8GB CF card.
+	 */
+
+	if (sector > 0x0FFFFFFF)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	totallen = sectors * info->ssize;
+
+	/*
+	 * Since we don't read more than 64 KB at a time, we have to create
+	 * a bounce buffer and move the data a piece at a time between the
+	 * bounce buffer and the actual transfer buffer.
+	 */
+
+	alloclen = min(totallen, 65536u);
+	buffer = kmalloc(alloclen, GFP_NOIO);
+	if (buffer == NULL)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	do {
+		/*
+		 * loop, never allocate or transfer more than 64k at once
+		 * (min(128k, 255*info->ssize) is the real limit)
+		 */
+		len = min(totallen, alloclen);
+		thistime = (len / info->ssize) & 0xff;
+ 
+		/* ATA command 0x20 (READ SECTORS) */
+		usbat_pack_ata_sector_cmd(command, thistime, sector, 0x20);
+
+		/* Write/execute ATA read command */
+		result = usbat_multiple_write(us, registers, command, 7);
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			goto leave;
+
+		/* Read the data we just requested */
+		result = usbat_read_blocks(us, buffer, len, 0);
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			goto leave;
+  	 
+		usb_stor_dbg(us, "%d bytes\n", len);
+	
+		/* Store the data in the transfer buffer */
+		usb_stor_access_xfer_buf(buffer, len, us->srb,
+					 &sg, &sg_offset, TO_XFER_BUF);
+
+		sector += thistime;
+		totallen -= len;
+	} while (totallen > 0);
+
+	kfree(buffer);
+	return USB_STOR_TRANSPORT_GOOD;
+
+leave:
+	kfree(buffer);
+	return USB_STOR_TRANSPORT_ERROR;
+}
+
+/*
+ * Write data to device
+ */
+static int usbat_flash_write_data(struct us_data *us,
+								  struct usbat_info *info,
+								  u32 sector,
+								  u32 sectors)
+{
+	unsigned char registers[7] = {
+		USBAT_ATA_FEATURES,
+		USBAT_ATA_SECCNT,
+		USBAT_ATA_SECNUM,
+		USBAT_ATA_LBA_ME,
+		USBAT_ATA_LBA_HI,
+		USBAT_ATA_DEVICE,
+		USBAT_ATA_STATUS,
+	};
+	unsigned char command[7];
+	unsigned char *buffer;
+	unsigned char  thistime;
+	unsigned int totallen, alloclen;
+	int len, result;
+	unsigned int sg_offset = 0;
+	struct scatterlist *sg = NULL;
+
+	result = usbat_flash_check_media(us, info);
+	if (result != USB_STOR_TRANSPORT_GOOD)
+		return result;
+
+	/*
+	 * we're working in LBA mode.  according to the ATA spec,
+	 * we can support up to 28-bit addressing.  I don't know if the device
+	 * supports beyond 24-bit addressing.  It's kind of hard to test
+	 * since it requires > 8GB media.
+	 */
+
+	if (sector > 0x0FFFFFFF)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	totallen = sectors * info->ssize;
+
+	/*
+	 * Since we don't write more than 64 KB at a time, we have to create
+	 * a bounce buffer and move the data a piece at a time between the
+	 * bounce buffer and the actual transfer buffer.
+	 */
+
+	alloclen = min(totallen, 65536u);
+	buffer = kmalloc(alloclen, GFP_NOIO);
+	if (buffer == NULL)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	do {
+		/*
+		 * loop, never allocate or transfer more than 64k at once
+		 * (min(128k, 255*info->ssize) is the real limit)
+		 */
+		len = min(totallen, alloclen);
+		thistime = (len / info->ssize) & 0xff;
+
+		/* Get the data from the transfer buffer */
+		usb_stor_access_xfer_buf(buffer, len, us->srb,
+					 &sg, &sg_offset, FROM_XFER_BUF);
+
+		/* ATA command 0x30 (WRITE SECTORS) */
+		usbat_pack_ata_sector_cmd(command, thistime, sector, 0x30);
+
+		/* Write/execute ATA write command */
+		result = usbat_multiple_write(us, registers, command, 7);
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			goto leave;
+
+		/* Write the data */
+		result = usbat_write_blocks(us, buffer, len, 0);
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			goto leave;
+
+		sector += thistime;
+		totallen -= len;
+	} while (totallen > 0);
+
+	kfree(buffer);
+	return result;
+
+leave:
+	kfree(buffer);
+	return USB_STOR_TRANSPORT_ERROR;
+}
+
+/*
+ * Squeeze a potentially huge (> 65535 byte) read10 command into
+ * a little ( <= 65535 byte) ATAPI pipe
+ */
+static int usbat_hp8200e_handle_read10(struct us_data *us,
+				       unsigned char *registers,
+				       unsigned char *data,
+				       struct scsi_cmnd *srb)
+{
+	int result = USB_STOR_TRANSPORT_GOOD;
+	unsigned char *buffer;
+	unsigned int len;
+	unsigned int sector;
+	unsigned int sg_offset = 0;
+	struct scatterlist *sg = NULL;
+
+	usb_stor_dbg(us, "transfersize %d\n", srb->transfersize);
+
+	if (scsi_bufflen(srb) < 0x10000) {
+
+		result = usbat_hp8200e_rw_block_test(us, USBAT_ATA, 
+			registers, data, 19,
+			USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD,
+			(USBAT_QUAL_FCQ | USBAT_QUAL_ALQ),
+			DMA_FROM_DEVICE,
+			scsi_sglist(srb),
+			scsi_bufflen(srb), scsi_sg_count(srb), 1);
+
+		return result;
+	}
+
+	/*
+	 * Since we're requesting more data than we can handle in
+	 * a single read command (max is 64k-1), we will perform
+	 * multiple reads, but each read must be in multiples of
+	 * a sector.  Luckily the sector size is in srb->transfersize
+	 * (see linux/drivers/scsi/sr.c).
+	 */
+
+	if (data[7+0] == GPCMD_READ_CD) {
+		len = short_pack(data[7+9], data[7+8]);
+		len <<= 16;
+		len |= data[7+7];
+		usb_stor_dbg(us, "GPCMD_READ_CD: len %d\n", len);
+		srb->transfersize = scsi_bufflen(srb)/len;
+	}
+
+	if (!srb->transfersize)  {
+		srb->transfersize = 2048; /* A guess */
+		usb_stor_dbg(us, "transfersize 0, forcing %d\n",
+			     srb->transfersize);
+	}
+
+	/*
+	 * Since we only read in one block at a time, we have to create
+	 * a bounce buffer and move the data a piece at a time between the
+	 * bounce buffer and the actual transfer buffer.
+	 */
+
+	len = (65535/srb->transfersize) * srb->transfersize;
+	usb_stor_dbg(us, "Max read is %d bytes\n", len);
+	len = min(len, scsi_bufflen(srb));
+	buffer = kmalloc(len, GFP_NOIO);
+	if (buffer == NULL) /* bloody hell! */
+		return USB_STOR_TRANSPORT_FAILED;
+	sector = short_pack(data[7+3], data[7+2]);
+	sector <<= 16;
+	sector |= short_pack(data[7+5], data[7+4]);
+	transferred = 0;
+
+	while (transferred != scsi_bufflen(srb)) {
+
+		if (len > scsi_bufflen(srb) - transferred)
+			len = scsi_bufflen(srb) - transferred;
+
+		data[3] = len&0xFF; 	  /* (cylL) = expected length (L) */
+		data[4] = (len>>8)&0xFF;  /* (cylH) = expected length (H) */
+
+		/* Fix up the SCSI command sector and num sectors */
+
+		data[7+2] = MSB_of(sector>>16); /* SCSI command sector */
+		data[7+3] = LSB_of(sector>>16);
+		data[7+4] = MSB_of(sector&0xFFFF);
+		data[7+5] = LSB_of(sector&0xFFFF);
+		if (data[7+0] == GPCMD_READ_CD)
+			data[7+6] = 0;
+		data[7+7] = MSB_of(len / srb->transfersize); /* SCSI command */
+		data[7+8] = LSB_of(len / srb->transfersize); /* num sectors */
+
+		result = usbat_hp8200e_rw_block_test(us, USBAT_ATA, 
+			registers, data, 19,
+			USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD, 
+			(USBAT_QUAL_FCQ | USBAT_QUAL_ALQ),
+			DMA_FROM_DEVICE,
+			buffer,
+			len, 0, 1);
+
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			break;
+
+		/* Store the data in the transfer buffer */
+		usb_stor_access_xfer_buf(buffer, len, srb,
+				 &sg, &sg_offset, TO_XFER_BUF);
+
+		/* Update the amount transferred and the sector number */
+
+		transferred += len;
+		sector += len / srb->transfersize;
+
+	} /* while transferred != scsi_bufflen(srb) */
+
+	kfree(buffer);
+	return result;
+}
+
+static int usbat_select_and_test_registers(struct us_data *us)
+{
+	int selector;
+	unsigned char *status = us->iobuf;
+
+	/* try device = master, then device = slave. */
+	for (selector = 0xA0; selector <= 0xB0; selector += 0x10) {
+		if (usbat_write(us, USBAT_ATA, USBAT_ATA_DEVICE, selector) !=
+				USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		if (usbat_read(us, USBAT_ATA, USBAT_ATA_STATUS, status) != 
+				USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		if (usbat_read(us, USBAT_ATA, USBAT_ATA_DEVICE, status) != 
+				USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) != 
+				USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_HI, status) != 
+				USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		if (usbat_write(us, USBAT_ATA, USBAT_ATA_LBA_ME, 0x55) != 
+				USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		if (usbat_write(us, USBAT_ATA, USBAT_ATA_LBA_HI, 0xAA) != 
+				USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) != 
+				USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) != 
+				USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Initialize the USBAT processor and the storage device
+ */
+static int init_usbat(struct us_data *us, int devicetype)
+{
+	int rc;
+	struct usbat_info *info;
+	unsigned char subcountH = USBAT_ATA_LBA_HI;
+	unsigned char subcountL = USBAT_ATA_LBA_ME;
+	unsigned char *status = us->iobuf;
+
+	us->extra = kzalloc(sizeof(struct usbat_info), GFP_NOIO);
+	if (!us->extra)
+		return 1;
+
+	info = (struct usbat_info *) (us->extra);
+
+	/* Enable peripheral control signals */
+	rc = usbat_write_user_io(us,
+				 USBAT_UIO_OE1 | USBAT_UIO_OE0,
+				 USBAT_UIO_EPAD | USBAT_UIO_1);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	usb_stor_dbg(us, "INIT 1\n");
+
+	msleep(2000);
+
+	rc = usbat_read_user_io(us, status);
+	if (rc != USB_STOR_TRANSPORT_GOOD)
+		return rc;
+
+	usb_stor_dbg(us, "INIT 2\n");
+
+	rc = usbat_read_user_io(us, status);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	rc = usbat_read_user_io(us, status);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	usb_stor_dbg(us, "INIT 3\n");
+
+	rc = usbat_select_and_test_registers(us);
+	if (rc != USB_STOR_TRANSPORT_GOOD)
+		return rc;
+
+	usb_stor_dbg(us, "INIT 4\n");
+
+	rc = usbat_read_user_io(us, status);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	usb_stor_dbg(us, "INIT 5\n");
+
+	/* Enable peripheral control signals and card detect */
+	rc = usbat_device_enable_cdt(us);
+	if (rc != USB_STOR_TRANSPORT_GOOD)
+		return rc;
+
+	usb_stor_dbg(us, "INIT 6\n");
+
+	rc = usbat_read_user_io(us, status);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	usb_stor_dbg(us, "INIT 7\n");
+
+	msleep(1400);
+
+	rc = usbat_read_user_io(us, status);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	usb_stor_dbg(us, "INIT 8\n");
+
+	rc = usbat_select_and_test_registers(us);
+	if (rc != USB_STOR_TRANSPORT_GOOD)
+		return rc;
+
+	usb_stor_dbg(us, "INIT 9\n");
+
+	/* At this point, we need to detect which device we are using */
+	if (usbat_set_transport(us, info, devicetype))
+		return USB_STOR_TRANSPORT_ERROR;
+
+	usb_stor_dbg(us, "INIT 10\n");
+
+	if (usbat_get_device_type(us) == USBAT_DEV_FLASH) { 
+		subcountH = 0x02;
+		subcountL = 0x00;
+	}
+	rc = usbat_set_shuttle_features(us, (USBAT_FEAT_ETEN | USBAT_FEAT_ET2 | USBAT_FEAT_ET1),
+									0x00, 0x88, 0x08, subcountH, subcountL);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	usb_stor_dbg(us, "INIT 11\n");
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Transport for the HP 8200e
+ */
+static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+	int result;
+	unsigned char *status = us->iobuf;
+	unsigned char registers[32];
+	unsigned char data[32];
+	unsigned int len;
+	int i;
+
+	len = scsi_bufflen(srb);
+
+	/*
+	 * Send A0 (ATA PACKET COMMAND).
+	 * Note: I guess we're never going to get any of the ATA
+	 * commands... just ATA Packet Commands.
+ 	 */
+
+	registers[0] = USBAT_ATA_FEATURES;
+	registers[1] = USBAT_ATA_SECCNT;
+	registers[2] = USBAT_ATA_SECNUM;
+	registers[3] = USBAT_ATA_LBA_ME;
+	registers[4] = USBAT_ATA_LBA_HI;
+	registers[5] = USBAT_ATA_DEVICE;
+	registers[6] = USBAT_ATA_CMD;
+	data[0] = 0x00;
+	data[1] = 0x00;
+	data[2] = 0x00;
+	data[3] = len&0xFF; 		/* (cylL) = expected length (L) */
+	data[4] = (len>>8)&0xFF; 	/* (cylH) = expected length (H) */
+	data[5] = 0xB0; 		/* (device sel) = slave */
+	data[6] = 0xA0; 		/* (command) = ATA PACKET COMMAND */
+
+	for (i=7; i<19; i++) {
+		registers[i] = 0x10;
+		data[i] = (i-7 >= srb->cmd_len) ? 0 : srb->cmnd[i-7];
+	}
+
+	result = usbat_get_status(us, status);
+	usb_stor_dbg(us, "Status = %02X\n", *status);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+	if (srb->cmnd[0] == TEST_UNIT_READY)
+		transferred = 0;
+
+	if (srb->sc_data_direction == DMA_TO_DEVICE) {
+
+		result = usbat_hp8200e_rw_block_test(us, USBAT_ATA, 
+			registers, data, 19,
+			USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD,
+			(USBAT_QUAL_FCQ | USBAT_QUAL_ALQ),
+			DMA_TO_DEVICE,
+			scsi_sglist(srb),
+			len, scsi_sg_count(srb), 10);
+
+		if (result == USB_STOR_TRANSPORT_GOOD) {
+			transferred += len;
+			usb_stor_dbg(us, "Wrote %08X bytes\n", transferred);
+		}
+
+		return result;
+
+	} else if (srb->cmnd[0] == READ_10 ||
+		   srb->cmnd[0] == GPCMD_READ_CD) {
+
+		return usbat_hp8200e_handle_read10(us, registers, data, srb);
+
+	}
+
+	if (len > 0xFFFF) {
+		usb_stor_dbg(us, "Error: len = %08X... what do I do now?\n",
+			     len);
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	result = usbat_multiple_write(us, registers, data, 7);
+
+	if (result != USB_STOR_TRANSPORT_GOOD)
+		return result;
+
+	/*
+	 * Write the 12-byte command header.
+	 *
+	 * If the command is BLANK then set the timer for 75 minutes.
+	 * Otherwise set it for 10 minutes.
+	 *
+	 * NOTE: THE 8200 DOCUMENTATION STATES THAT BLANKING A CDRW
+	 * AT SPEED 4 IS UNRELIABLE!!!
+	 */
+
+	result = usbat_write_block(us, USBAT_ATA, srb->cmnd, 12,
+				   srb->cmnd[0] == GPCMD_BLANK ? 75 : 10, 0);
+
+	if (result != USB_STOR_TRANSPORT_GOOD)
+		return result;
+
+	/* If there is response data to be read in then do it here. */
+
+	if (len != 0 && (srb->sc_data_direction == DMA_FROM_DEVICE)) {
+
+		/* How many bytes to read in? Check cylL register */
+
+		if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) != 
+		    	USB_STOR_XFER_GOOD) {
+			return USB_STOR_TRANSPORT_ERROR;
+		}
+
+		if (len > 0xFF) { /* need to read cylH also */
+			len = *status;
+			if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_HI, status) !=
+				    USB_STOR_XFER_GOOD) {
+				return USB_STOR_TRANSPORT_ERROR;
+			}
+			len += ((unsigned int) *status)<<8;
+		}
+		else
+			len = *status;
+
+
+		result = usbat_read_block(us, scsi_sglist(srb), len,
+			                                   scsi_sg_count(srb));
+	}
+
+	return result;
+}
+
+/*
+ * Transport for USBAT02-based CompactFlash and similar storage devices
+ */
+static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us)
+{
+	int rc;
+	struct usbat_info *info = (struct usbat_info *) (us->extra);
+	unsigned long block, blocks;
+	unsigned char *ptr = us->iobuf;
+	static unsigned char inquiry_response[36] = {
+		0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00
+	};
+
+	if (srb->cmnd[0] == INQUIRY) {
+		usb_stor_dbg(us, "INQUIRY - Returning bogus response\n");
+		memcpy(ptr, inquiry_response, sizeof(inquiry_response));
+		fill_inquiry_response(us, ptr, 36);
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == READ_CAPACITY) {
+		rc = usbat_flash_check_media(us, info);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+
+		rc = usbat_flash_get_sector_count(us, info);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+
+		/* hard coded 512 byte sectors as per ATA spec */
+		info->ssize = 0x200;
+		usb_stor_dbg(us, "READ_CAPACITY: %ld sectors, %ld bytes per sector\n",
+			     info->sectors, info->ssize);
+
+		/*
+		 * build the reply
+		 * note: must return the sector number of the last sector,
+		 * *not* the total number of sectors
+		 */
+		((__be32 *) ptr)[0] = cpu_to_be32(info->sectors - 1);
+		((__be32 *) ptr)[1] = cpu_to_be32(info->ssize);
+		usb_stor_set_xfer_buf(ptr, 8, srb);
+
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == MODE_SELECT_10) {
+		usb_stor_dbg(us, "Gah! MODE_SELECT_10\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	if (srb->cmnd[0] == READ_10) {
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+				((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
+
+		usb_stor_dbg(us, "READ_10: read block 0x%04lx  count %ld\n",
+			     block, blocks);
+		return usbat_flash_read_data(us, info, block, blocks);
+	}
+
+	if (srb->cmnd[0] == READ_12) {
+		/*
+		 * I don't think we'll ever see a READ_12 but support it anyway
+		 */
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+		        ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
+		         ((u32)(srb->cmnd[8]) <<  8) | ((u32)(srb->cmnd[9]));
+
+		usb_stor_dbg(us, "READ_12: read block 0x%04lx  count %ld\n",
+			     block, blocks);
+		return usbat_flash_read_data(us, info, block, blocks);
+	}
+
+	if (srb->cmnd[0] == WRITE_10) {
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+		        ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
+
+		usb_stor_dbg(us, "WRITE_10: write block 0x%04lx  count %ld\n",
+			     block, blocks);
+		return usbat_flash_write_data(us, info, block, blocks);
+	}
+
+	if (srb->cmnd[0] == WRITE_12) {
+		/*
+		 * I don't think we'll ever see a WRITE_12 but support it anyway
+		 */
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+		        ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
+		         ((u32)(srb->cmnd[8]) <<  8) | ((u32)(srb->cmnd[9]));
+
+		usb_stor_dbg(us, "WRITE_12: write block 0x%04lx  count %ld\n",
+			     block, blocks);
+		return usbat_flash_write_data(us, info, block, blocks);
+	}
+
+
+	if (srb->cmnd[0] == TEST_UNIT_READY) {
+		usb_stor_dbg(us, "TEST_UNIT_READY\n");
+
+		rc = usbat_flash_check_media(us, info);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+
+		return usbat_check_status(us);
+	}
+
+	if (srb->cmnd[0] == REQUEST_SENSE) {
+		usb_stor_dbg(us, "REQUEST_SENSE\n");
+
+		memset(ptr, 0, 18);
+		ptr[0] = 0xF0;
+		ptr[2] = info->sense_key;
+		ptr[7] = 11;
+		ptr[12] = info->sense_asc;
+		ptr[13] = info->sense_ascq;
+		usb_stor_set_xfer_buf(ptr, 18, srb);
+
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
+		/*
+		 * sure.  whatever.  not like we can stop the user from popping
+		 * the media out of the device (no locking doors, etc)
+		 */
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	usb_stor_dbg(us, "Gah! Unknown command: %d (0x%x)\n",
+		     srb->cmnd[0], srb->cmnd[0]);
+	info->sense_key = 0x05;
+	info->sense_asc = 0x20;
+	info->sense_ascq = 0x00;
+	return USB_STOR_TRANSPORT_FAILED;
+}
+
+static int init_usbat_cd(struct us_data *us)
+{
+	return init_usbat(us, USBAT_DEV_HP8200);
+}
+
+static int init_usbat_flash(struct us_data *us)
+{
+	return init_usbat(us, USBAT_DEV_FLASH);
+}
+
+static struct scsi_host_template usbat_host_template;
+
+static int usbat_probe(struct usb_interface *intf,
+			 const struct usb_device_id *id)
+{
+	struct us_data *us;
+	int result;
+
+	result = usb_stor_probe1(&us, intf, id,
+			(id - usbat_usb_ids) + usbat_unusual_dev_list,
+			&usbat_host_template);
+	if (result)
+		return result;
+
+	/*
+	 * The actual transport will be determined later by the
+	 * initialization routine; this is just a placeholder.
+	 */
+	us->transport_name = "Shuttle USBAT";
+	us->transport = usbat_flash_transport;
+	us->transport_reset = usb_stor_CB_reset;
+	us->max_lun = 0;
+
+	result = usb_stor_probe2(us);
+	return result;
+}
+
+static struct usb_driver usbat_driver = {
+	.name =		DRV_NAME,
+	.probe =	usbat_probe,
+	.disconnect =	usb_stor_disconnect,
+	.suspend =	usb_stor_suspend,
+	.resume =	usb_stor_resume,
+	.reset_resume =	usb_stor_reset_resume,
+	.pre_reset =	usb_stor_pre_reset,
+	.post_reset =	usb_stor_post_reset,
+	.id_table =	usbat_usb_ids,
+	.soft_unbind =	1,
+	.no_dynamic_id = 1,
+};
+
+module_usb_stor_driver(usbat_driver, usbat_host_template, DRV_NAME);
diff --git a/drivers/usb/storage/sierra_ms.c b/drivers/usb/storage/sierra_ms.c
new file mode 100644
index 0000000..6ac60ab
--- /dev/null
+++ b/drivers/usb/storage/sierra_ms.c
@@ -0,0 +1,201 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <linux/usb.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "protocol.h"
+#include "scsiglue.h"
+#include "sierra_ms.h"
+#include "debug.h"
+
+#define SWIMS_USB_REQUEST_SetSwocMode	0x0B
+#define SWIMS_USB_REQUEST_GetSwocInfo	0x0A
+#define SWIMS_USB_INDEX_SetMode		0x0000
+#define SWIMS_SET_MODE_Modem		0x0001
+
+#define TRU_NORMAL 			0x01
+#define TRU_FORCE_MS 			0x02
+#define TRU_FORCE_MODEM 		0x03
+
+static unsigned int swi_tru_install = 1;
+module_param(swi_tru_install, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(swi_tru_install, "TRU-Install mode (1=Full Logic (def),"
+		 " 2=Force CD-Rom, 3=Force Modem)");
+
+struct swoc_info {
+	__u8 rev;
+	__u8 reserved[8];
+	__u16 LinuxSKU;
+	__u16 LinuxVer;
+	__u8 reserved2[47];
+} __attribute__((__packed__));
+
+static bool containsFullLinuxPackage(struct swoc_info *swocInfo)
+{
+	if ((swocInfo->LinuxSKU >= 0x2100 && swocInfo->LinuxSKU <= 0x2FFF) ||
+	   (swocInfo->LinuxSKU >= 0x7100 && swocInfo->LinuxSKU <= 0x7FFF))
+		return true;
+	else
+		return false;
+}
+
+static int sierra_set_ms_mode(struct usb_device *udev, __u16 eSWocMode)
+{
+	int result;
+	dev_dbg(&udev->dev, "SWIMS: %s", "DEVICE MODE SWITCH\n");
+	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			SWIMS_USB_REQUEST_SetSwocMode,	/* __u8 request      */
+			USB_TYPE_VENDOR | USB_DIR_OUT,	/* __u8 request type */
+			eSWocMode,			/* __u16 value       */
+			0x0000,				/* __u16 index       */
+			NULL,				/* void *data        */
+			0,				/* __u16 size 	     */
+			USB_CTRL_SET_TIMEOUT);		/* int timeout       */
+	return result;
+}
+
+
+static int sierra_get_swoc_info(struct usb_device *udev,
+				struct swoc_info *swocInfo)
+{
+	int result;
+
+	dev_dbg(&udev->dev, "SWIMS: Attempting to get TRU-Install info\n");
+
+	result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+			SWIMS_USB_REQUEST_GetSwocInfo,	/* __u8 request      */
+			USB_TYPE_VENDOR | USB_DIR_IN,	/* __u8 request type */
+			0,				/* __u16 value       */
+			0,				/* __u16 index       */
+			(void *) swocInfo,		/* void *data        */
+			sizeof(struct swoc_info),	/* __u16 size 	     */
+			USB_CTRL_SET_TIMEOUT);		/* int timeout 	     */
+
+	swocInfo->LinuxSKU = le16_to_cpu(swocInfo->LinuxSKU);
+	swocInfo->LinuxVer = le16_to_cpu(swocInfo->LinuxVer);
+	return result;
+}
+
+static void debug_swoc(const struct device *dev, struct swoc_info *swocInfo)
+{
+	dev_dbg(dev, "SWIMS: SWoC Rev: %02d\n", swocInfo->rev);
+	dev_dbg(dev, "SWIMS: Linux SKU: %04X\n", swocInfo->LinuxSKU);
+	dev_dbg(dev, "SWIMS: Linux Version: %04X\n", swocInfo->LinuxVer);
+}
+
+
+static ssize_t truinst_show(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct swoc_info *swocInfo;
+	struct usb_interface *intf = to_usb_interface(dev);
+	struct usb_device *udev = interface_to_usbdev(intf);
+	int result;
+	if (swi_tru_install == TRU_FORCE_MS) {
+		result = snprintf(buf, PAGE_SIZE, "Forced Mass Storage\n");
+	} else {
+		swocInfo = kmalloc(sizeof(struct swoc_info), GFP_KERNEL);
+		if (!swocInfo) {
+			snprintf(buf, PAGE_SIZE, "Error\n");
+			return -ENOMEM;
+		}
+		result = sierra_get_swoc_info(udev, swocInfo);
+		if (result < 0) {
+			dev_dbg(dev, "SWIMS: failed SWoC query\n");
+			kfree(swocInfo);
+			snprintf(buf, PAGE_SIZE, "Error\n");
+			return -EIO;
+		}
+		debug_swoc(dev, swocInfo);
+		result = snprintf(buf, PAGE_SIZE,
+			"REV=%02d SKU=%04X VER=%04X\n",
+			swocInfo->rev,
+			swocInfo->LinuxSKU,
+			swocInfo->LinuxVer);
+		kfree(swocInfo);
+	}
+	return result;
+}
+static DEVICE_ATTR_RO(truinst);
+
+int sierra_ms_init(struct us_data *us)
+{
+	int result, retries;
+	struct swoc_info *swocInfo;
+	struct usb_device *udev;
+	struct Scsi_Host *sh;
+
+	retries = 3;
+	result = 0;
+	udev = us->pusb_dev;
+
+	sh = us_to_host(us);
+	scsi_get_host_dev(sh);
+
+	/* Force Modem mode */
+	if (swi_tru_install == TRU_FORCE_MODEM) {
+		usb_stor_dbg(us, "SWIMS: Forcing Modem Mode\n");
+		result = sierra_set_ms_mode(udev, SWIMS_SET_MODE_Modem);
+		if (result < 0)
+			usb_stor_dbg(us, "SWIMS: Failed to switch to modem mode\n");
+		return -EIO;
+	}
+	/* Force Mass Storage mode (keep CD-Rom) */
+	else if (swi_tru_install == TRU_FORCE_MS) {
+		usb_stor_dbg(us, "SWIMS: Forcing Mass Storage Mode\n");
+		goto complete;
+	}
+	/* Normal TRU-Install Logic */
+	else {
+		usb_stor_dbg(us, "SWIMS: Normal SWoC Logic\n");
+
+		swocInfo = kmalloc(sizeof(struct swoc_info),
+				GFP_KERNEL);
+		if (!swocInfo)
+			return -ENOMEM;
+
+		retries = 3;
+		do {
+			retries--;
+			result = sierra_get_swoc_info(udev, swocInfo);
+			if (result < 0) {
+				usb_stor_dbg(us, "SWIMS: Failed SWoC query\n");
+				schedule_timeout_uninterruptible(2*HZ);
+			}
+		} while (retries && result < 0);
+
+		if (result < 0) {
+			usb_stor_dbg(us, "SWIMS: Completely failed SWoC query\n");
+			kfree(swocInfo);
+			return -EIO;
+		}
+
+		debug_swoc(&us->pusb_dev->dev, swocInfo);
+
+		/*
+		 * If there is not Linux software on the TRU-Install device
+		 * then switch to modem mode
+		 */
+		if (!containsFullLinuxPackage(swocInfo)) {
+			usb_stor_dbg(us, "SWIMS: Switching to Modem Mode\n");
+			result = sierra_set_ms_mode(udev,
+				SWIMS_SET_MODE_Modem);
+			if (result < 0)
+				usb_stor_dbg(us, "SWIMS: Failed to switch modem\n");
+			kfree(swocInfo);
+			return -EIO;
+		}
+		kfree(swocInfo);
+	}
+complete:
+	result = device_create_file(&us->pusb_intf->dev, &dev_attr_truinst);
+
+	return 0;
+}
+
diff --git a/drivers/usb/storage/sierra_ms.h b/drivers/usb/storage/sierra_ms.h
new file mode 100644
index 0000000..3e9da53
--- /dev/null
+++ b/drivers/usb/storage/sierra_ms.h
@@ -0,0 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _SIERRA_MS_H_
+#define _SIERRA_MS_H_
+extern int sierra_ms_init(struct us_data *us);
+#endif
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
new file mode 100644
index 0000000..96cb040
--- /dev/null
+++ b/drivers/usb/storage/transport.c
@@ -0,0 +1,1439 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for USB Mass Storage compliant devices
+ *
+ * Current development and maintenance by:
+ *   (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * Developed with the assistance of:
+ *   (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
+ *   (c) 2000 Stephen J. Gowdy (SGowdy@lbl.gov)
+ *   (c) 2002 Alan Stern <stern@rowland.org>
+ *
+ * Initial work by:
+ *   (c) 1999 Michael Gee (michael@linuxspecific.com)
+ *
+ * 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.
+ */
+
+#include <linux/sched.h>
+#include <linux/gfp.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+
+#include <linux/usb/quirks.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_device.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "protocol.h"
+#include "scsiglue.h"
+#include "debug.h"
+
+#include <linux/blkdev.h>
+#include "../../scsi/sd.h"
+
+
+/***********************************************************************
+ * Data transfer routines
+ ***********************************************************************/
+
+/*
+ * This is subtle, so pay attention:
+ * ---------------------------------
+ * We're very concerned about races with a command abort.  Hanging this code
+ * is a sure fire way to hang the kernel.  (Note that this discussion applies
+ * only to transactions resulting from a scsi queued-command, since only
+ * these transactions are subject to a scsi abort.  Other transactions, such
+ * as those occurring during device-specific initialization, must be handled
+ * by a separate code path.)
+ *
+ * The abort function (usb_storage_command_abort() in scsiglue.c) first
+ * sets the machine state and the ABORTING bit in us->dflags to prevent
+ * new URBs from being submitted.  It then calls usb_stor_stop_transport()
+ * below, which atomically tests-and-clears the URB_ACTIVE bit in us->dflags
+ * to see if the current_urb needs to be stopped.  Likewise, the SG_ACTIVE
+ * bit is tested to see if the current_sg scatter-gather request needs to be
+ * stopped.  The timeout callback routine does much the same thing.
+ *
+ * When a disconnect occurs, the DISCONNECTING bit in us->dflags is set to
+ * prevent new URBs from being submitted, and usb_stor_stop_transport() is
+ * called to stop any ongoing requests.
+ *
+ * The submit function first verifies that the submitting is allowed
+ * (neither ABORTING nor DISCONNECTING bits are set) and that the submit
+ * completes without errors, and only then sets the URB_ACTIVE bit.  This
+ * prevents the stop_transport() function from trying to cancel the URB
+ * while the submit call is underway.  Next, the submit function must test
+ * the flags to see if an abort or disconnect occurred during the submission
+ * or before the URB_ACTIVE bit was set.  If so, it's essential to cancel
+ * the URB if it hasn't been cancelled already (i.e., if the URB_ACTIVE bit
+ * is still set).  Either way, the function must then wait for the URB to
+ * finish.  Note that the URB can still be in progress even after a call to
+ * usb_unlink_urb() returns.
+ *
+ * The idea is that (1) once the ABORTING or DISCONNECTING bit is set,
+ * either the stop_transport() function or the submitting function
+ * is guaranteed to call usb_unlink_urb() for an active URB,
+ * and (2) test_and_clear_bit() prevents usb_unlink_urb() from being
+ * called more than once or from being called during usb_submit_urb().
+ */
+
+/*
+ * This is the completion handler which will wake us up when an URB
+ * completes.
+ */
+static void usb_stor_blocking_completion(struct urb *urb)
+{
+	struct completion *urb_done_ptr = urb->context;
+
+	complete(urb_done_ptr);
+}
+
+/*
+ * This is the common part of the URB message submission code
+ *
+ * All URBs from the usb-storage driver involved in handling a queued scsi
+ * command _must_ pass through this function (or something like it) for the
+ * abort mechanisms to work properly.
+ */
+static int usb_stor_msg_common(struct us_data *us, int timeout)
+{
+	struct completion urb_done;
+	long timeleft;
+	int status;
+
+	/* don't submit URBs during abort processing */
+	if (test_bit(US_FLIDX_ABORTING, &us->dflags))
+		return -EIO;
+
+	/* set up data structures for the wakeup system */
+	init_completion(&urb_done);
+
+	/* fill the common fields in the URB */
+	us->current_urb->context = &urb_done;
+	us->current_urb->transfer_flags = 0;
+
+	/*
+	 * we assume that if transfer_buffer isn't us->iobuf then it
+	 * hasn't been mapped for DMA.  Yes, this is clunky, but it's
+	 * easier than always having the caller tell us whether the
+	 * transfer buffer has already been mapped.
+	 */
+	if (us->current_urb->transfer_buffer == us->iobuf)
+		us->current_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+	us->current_urb->transfer_dma = us->iobuf_dma;
+
+	/* submit the URB */
+	status = usb_submit_urb(us->current_urb, GFP_NOIO);
+	if (status) {
+		/* something went wrong */
+		return status;
+	}
+
+	/*
+	 * since the URB has been submitted successfully, it's now okay
+	 * to cancel it
+	 */
+	set_bit(US_FLIDX_URB_ACTIVE, &us->dflags);
+
+	/* did an abort occur during the submission? */
+	if (test_bit(US_FLIDX_ABORTING, &us->dflags)) {
+
+		/* cancel the URB, if it hasn't been cancelled already */
+		if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags)) {
+			usb_stor_dbg(us, "-- cancelling URB\n");
+			usb_unlink_urb(us->current_urb);
+		}
+	}
+ 
+	/* wait for the completion of the URB */
+	timeleft = wait_for_completion_interruptible_timeout(
+			&urb_done, timeout ? : MAX_SCHEDULE_TIMEOUT);
+ 
+	clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags);
+
+	if (timeleft <= 0) {
+		usb_stor_dbg(us, "%s -- cancelling URB\n",
+			     timeleft == 0 ? "Timeout" : "Signal");
+		usb_kill_urb(us->current_urb);
+	}
+
+	/* return the URB status */
+	return us->current_urb->status;
+}
+
+/*
+ * Transfer one control message, with timeouts, and allowing early
+ * termination.  Return codes are usual -Exxx, *not* USB_STOR_XFER_xxx.
+ */
+int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
+		 u8 request, u8 requesttype, u16 value, u16 index, 
+		 void *data, u16 size, int timeout)
+{
+	int status;
+
+	usb_stor_dbg(us, "rq=%02x rqtype=%02x value=%04x index=%02x len=%u\n",
+		     request, requesttype, value, index, size);
+
+	/* fill in the devrequest structure */
+	us->cr->bRequestType = requesttype;
+	us->cr->bRequest = request;
+	us->cr->wValue = cpu_to_le16(value);
+	us->cr->wIndex = cpu_to_le16(index);
+	us->cr->wLength = cpu_to_le16(size);
+
+	/* fill and submit the URB */
+	usb_fill_control_urb(us->current_urb, us->pusb_dev, pipe, 
+			 (unsigned char*) us->cr, data, size, 
+			 usb_stor_blocking_completion, NULL);
+	status = usb_stor_msg_common(us, timeout);
+
+	/* return the actual length of the data transferred if no error */
+	if (status == 0)
+		status = us->current_urb->actual_length;
+	return status;
+}
+EXPORT_SYMBOL_GPL(usb_stor_control_msg);
+
+/*
+ * This is a version of usb_clear_halt() that allows early termination and
+ * doesn't read the status from the device -- this is because some devices
+ * crash their internal firmware when the status is requested after a halt.
+ *
+ * A definitive list of these 'bad' devices is too difficult to maintain or
+ * make complete enough to be useful.  This problem was first observed on the
+ * Hagiwara FlashGate DUAL unit.  However, bus traces reveal that neither
+ * MacOS nor Windows checks the status after clearing a halt.
+ *
+ * Since many vendors in this space limit their testing to interoperability
+ * with these two OSes, specification violations like this one are common.
+ */
+int usb_stor_clear_halt(struct us_data *us, unsigned int pipe)
+{
+	int result;
+	int endp = usb_pipeendpoint(pipe);
+
+	if (usb_pipein (pipe))
+		endp |= USB_DIR_IN;
+
+	result = usb_stor_control_msg(us, us->send_ctrl_pipe,
+		USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT,
+		USB_ENDPOINT_HALT, endp,
+		NULL, 0, 3*HZ);
+
+	if (result >= 0)
+		usb_reset_endpoint(us->pusb_dev, endp);
+
+	usb_stor_dbg(us, "result = %d\n", result);
+	return result;
+}
+EXPORT_SYMBOL_GPL(usb_stor_clear_halt);
+
+
+/*
+ * Interpret the results of a URB transfer
+ *
+ * This function prints appropriate debugging messages, clears halts on
+ * non-control endpoints, and translates the status to the corresponding
+ * USB_STOR_XFER_xxx return code.
+ */
+static int interpret_urb_result(struct us_data *us, unsigned int pipe,
+		unsigned int length, int result, unsigned int partial)
+{
+	usb_stor_dbg(us, "Status code %d; transferred %u/%u\n",
+		     result, partial, length);
+	switch (result) {
+
+	/* no error code; did we send all the data? */
+	case 0:
+		if (partial != length) {
+			usb_stor_dbg(us, "-- short transfer\n");
+			return USB_STOR_XFER_SHORT;
+		}
+
+		usb_stor_dbg(us, "-- transfer complete\n");
+		return USB_STOR_XFER_GOOD;
+
+	/* stalled */
+	case -EPIPE:
+		/*
+		 * for control endpoints, (used by CB[I]) a stall indicates
+		 * a failed command
+		 */
+		if (usb_pipecontrol(pipe)) {
+			usb_stor_dbg(us, "-- stall on control pipe\n");
+			return USB_STOR_XFER_STALLED;
+		}
+
+		/* for other sorts of endpoint, clear the stall */
+		usb_stor_dbg(us, "clearing endpoint halt for pipe 0x%x\n",
+			     pipe);
+		if (usb_stor_clear_halt(us, pipe) < 0)
+			return USB_STOR_XFER_ERROR;
+		return USB_STOR_XFER_STALLED;
+
+	/* babble - the device tried to send more than we wanted to read */
+	case -EOVERFLOW:
+		usb_stor_dbg(us, "-- babble\n");
+		return USB_STOR_XFER_LONG;
+
+	/* the transfer was cancelled by abort, disconnect, or timeout */
+	case -ECONNRESET:
+		usb_stor_dbg(us, "-- transfer cancelled\n");
+		return USB_STOR_XFER_ERROR;
+
+	/* short scatter-gather read transfer */
+	case -EREMOTEIO:
+		usb_stor_dbg(us, "-- short read transfer\n");
+		return USB_STOR_XFER_SHORT;
+
+	/* abort or disconnect in progress */
+	case -EIO:
+		usb_stor_dbg(us, "-- abort or disconnect in progress\n");
+		return USB_STOR_XFER_ERROR;
+
+	/* the catch-all error case */
+	default:
+		usb_stor_dbg(us, "-- unknown error\n");
+		return USB_STOR_XFER_ERROR;
+	}
+}
+
+/*
+ * Transfer one control message, without timeouts, but allowing early
+ * termination.  Return codes are USB_STOR_XFER_xxx.
+ */
+int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe,
+		u8 request, u8 requesttype, u16 value, u16 index,
+		void *data, u16 size)
+{
+	int result;
+
+	usb_stor_dbg(us, "rq=%02x rqtype=%02x value=%04x index=%02x len=%u\n",
+		     request, requesttype, value, index, size);
+
+	/* fill in the devrequest structure */
+	us->cr->bRequestType = requesttype;
+	us->cr->bRequest = request;
+	us->cr->wValue = cpu_to_le16(value);
+	us->cr->wIndex = cpu_to_le16(index);
+	us->cr->wLength = cpu_to_le16(size);
+
+	/* fill and submit the URB */
+	usb_fill_control_urb(us->current_urb, us->pusb_dev, pipe, 
+			 (unsigned char*) us->cr, data, size, 
+			 usb_stor_blocking_completion, NULL);
+	result = usb_stor_msg_common(us, 0);
+
+	return interpret_urb_result(us, pipe, size, result,
+			us->current_urb->actual_length);
+}
+EXPORT_SYMBOL_GPL(usb_stor_ctrl_transfer);
+
+/*
+ * Receive one interrupt buffer, without timeouts, but allowing early
+ * termination.  Return codes are USB_STOR_XFER_xxx.
+ *
+ * This routine always uses us->recv_intr_pipe as the pipe and
+ * us->ep_bInterval as the interrupt interval.
+ */
+static int usb_stor_intr_transfer(struct us_data *us, void *buf,
+				  unsigned int length)
+{
+	int result;
+	unsigned int pipe = us->recv_intr_pipe;
+	unsigned int maxp;
+
+	usb_stor_dbg(us, "xfer %u bytes\n", length);
+
+	/* calculate the max packet size */
+	maxp = usb_maxpacket(us->pusb_dev, pipe, usb_pipeout(pipe));
+	if (maxp > length)
+		maxp = length;
+
+	/* fill and submit the URB */
+	usb_fill_int_urb(us->current_urb, us->pusb_dev, pipe, buf,
+			maxp, usb_stor_blocking_completion, NULL,
+			us->ep_bInterval);
+	result = usb_stor_msg_common(us, 0);
+
+	return interpret_urb_result(us, pipe, length, result,
+			us->current_urb->actual_length);
+}
+
+/*
+ * Transfer one buffer via bulk pipe, without timeouts, but allowing early
+ * termination.  Return codes are USB_STOR_XFER_xxx.  If the bulk pipe
+ * stalls during the transfer, the halt is automatically cleared.
+ */
+int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
+	void *buf, unsigned int length, unsigned int *act_len)
+{
+	int result;
+
+	usb_stor_dbg(us, "xfer %u bytes\n", length);
+
+	/* fill and submit the URB */
+	usb_fill_bulk_urb(us->current_urb, us->pusb_dev, pipe, buf, length,
+		      usb_stor_blocking_completion, NULL);
+	result = usb_stor_msg_common(us, 0);
+
+	/* store the actual length of the data transferred */
+	if (act_len)
+		*act_len = us->current_urb->actual_length;
+	return interpret_urb_result(us, pipe, length, result, 
+			us->current_urb->actual_length);
+}
+EXPORT_SYMBOL_GPL(usb_stor_bulk_transfer_buf);
+
+/*
+ * Transfer a scatter-gather list via bulk transfer
+ *
+ * This function does basically the same thing as usb_stor_bulk_transfer_buf()
+ * above, but it uses the usbcore scatter-gather library.
+ */
+static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
+		struct scatterlist *sg, int num_sg, unsigned int length,
+		unsigned int *act_len)
+{
+	int result;
+
+	/* don't submit s-g requests during abort processing */
+	if (test_bit(US_FLIDX_ABORTING, &us->dflags))
+		return USB_STOR_XFER_ERROR;
+
+	/* initialize the scatter-gather request block */
+	usb_stor_dbg(us, "xfer %u bytes, %d entries\n", length, num_sg);
+	result = usb_sg_init(&us->current_sg, us->pusb_dev, pipe, 0,
+			sg, num_sg, length, GFP_NOIO);
+	if (result) {
+		usb_stor_dbg(us, "usb_sg_init returned %d\n", result);
+		return USB_STOR_XFER_ERROR;
+	}
+
+	/*
+	 * since the block has been initialized successfully, it's now
+	 * okay to cancel it
+	 */
+	set_bit(US_FLIDX_SG_ACTIVE, &us->dflags);
+
+	/* did an abort occur during the submission? */
+	if (test_bit(US_FLIDX_ABORTING, &us->dflags)) {
+
+		/* cancel the request, if it hasn't been cancelled already */
+		if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags)) {
+			usb_stor_dbg(us, "-- cancelling sg request\n");
+			usb_sg_cancel(&us->current_sg);
+		}
+	}
+
+	/* wait for the completion of the transfer */
+	usb_sg_wait(&us->current_sg);
+	clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags);
+
+	result = us->current_sg.status;
+	if (act_len)
+		*act_len = us->current_sg.bytes;
+	return interpret_urb_result(us, pipe, length, result,
+			us->current_sg.bytes);
+}
+
+/*
+ * Common used function. Transfer a complete command
+ * via usb_stor_bulk_transfer_sglist() above. Set cmnd resid
+ */
+int usb_stor_bulk_srb(struct us_data* us, unsigned int pipe,
+		      struct scsi_cmnd* srb)
+{
+	unsigned int partial;
+	int result = usb_stor_bulk_transfer_sglist(us, pipe, scsi_sglist(srb),
+				      scsi_sg_count(srb), scsi_bufflen(srb),
+				      &partial);
+
+	scsi_set_resid(srb, scsi_bufflen(srb) - partial);
+	return result;
+}
+EXPORT_SYMBOL_GPL(usb_stor_bulk_srb);
+
+/*
+ * Transfer an entire SCSI command's worth of data payload over the bulk
+ * pipe.
+ *
+ * Note that this uses usb_stor_bulk_transfer_buf() and
+ * usb_stor_bulk_transfer_sglist() to achieve its goals --
+ * this function simply determines whether we're going to use
+ * scatter-gather or not, and acts appropriately.
+ */
+int usb_stor_bulk_transfer_sg(struct us_data* us, unsigned int pipe,
+		void *buf, unsigned int length_left, int use_sg, int *residual)
+{
+	int result;
+	unsigned int partial;
+
+	/* are we scatter-gathering? */
+	if (use_sg) {
+		/* use the usb core scatter-gather primitives */
+		result = usb_stor_bulk_transfer_sglist(us, pipe,
+				(struct scatterlist *) buf, use_sg,
+				length_left, &partial);
+		length_left -= partial;
+	} else {
+		/* no scatter-gather, just make the request */
+		result = usb_stor_bulk_transfer_buf(us, pipe, buf, 
+				length_left, &partial);
+		length_left -= partial;
+	}
+
+	/* store the residual and return the error code */
+	if (residual)
+		*residual = length_left;
+	return result;
+}
+EXPORT_SYMBOL_GPL(usb_stor_bulk_transfer_sg);
+
+/***********************************************************************
+ * Transport routines
+ ***********************************************************************/
+
+/*
+ * There are so many devices that report the capacity incorrectly,
+ * this routine was written to counteract some of the resulting
+ * problems.
+ */
+static void last_sector_hacks(struct us_data *us, struct scsi_cmnd *srb)
+{
+	struct gendisk *disk;
+	struct scsi_disk *sdkp;
+	u32 sector;
+
+	/* To Report "Medium Error: Record Not Found */
+	static unsigned char record_not_found[18] = {
+		[0]	= 0x70,			/* current error */
+		[2]	= MEDIUM_ERROR,		/* = 0x03 */
+		[7]	= 0x0a,			/* additional length */
+		[12]	= 0x14			/* Record Not Found */
+	};
+
+	/*
+	 * If last-sector problems can't occur, whether because the
+	 * capacity was already decremented or because the device is
+	 * known to report the correct capacity, then we don't need
+	 * to do anything.
+	 */
+	if (!us->use_last_sector_hacks)
+		return;
+
+	/* Was this command a READ(10) or a WRITE(10)? */
+	if (srb->cmnd[0] != READ_10 && srb->cmnd[0] != WRITE_10)
+		goto done;
+
+	/* Did this command access the last sector? */
+	sector = (srb->cmnd[2] << 24) | (srb->cmnd[3] << 16) |
+			(srb->cmnd[4] << 8) | (srb->cmnd[5]);
+	disk = srb->request->rq_disk;
+	if (!disk)
+		goto done;
+	sdkp = scsi_disk(disk);
+	if (!sdkp)
+		goto done;
+	if (sector + 1 != sdkp->capacity)
+		goto done;
+
+	if (srb->result == SAM_STAT_GOOD && scsi_get_resid(srb) == 0) {
+
+		/*
+		 * The command succeeded.  We know this device doesn't
+		 * have the last-sector bug, so stop checking it.
+		 */
+		us->use_last_sector_hacks = 0;
+
+	} else {
+		/*
+		 * The command failed.  Allow up to 3 retries in case this
+		 * is some normal sort of failure.  After that, assume the
+		 * capacity is wrong and we're trying to access the sector
+		 * beyond the end.  Replace the result code and sense data
+		 * with values that will cause the SCSI core to fail the
+		 * command immediately, instead of going into an infinite
+		 * (or even just a very long) retry loop.
+		 */
+		if (++us->last_sector_retries < 3)
+			return;
+		srb->result = SAM_STAT_CHECK_CONDITION;
+		memcpy(srb->sense_buffer, record_not_found,
+				sizeof(record_not_found));
+	}
+
+ done:
+	/*
+	 * Don't reset the retry counter for TEST UNIT READY commands,
+	 * because they get issued after device resets which might be
+	 * caused by a failed last-sector access.
+	 */
+	if (srb->cmnd[0] != TEST_UNIT_READY)
+		us->last_sector_retries = 0;
+}
+
+/*
+ * Invoke the transport and basic error-handling/recovery methods
+ *
+ * This is used by the protocol layers to actually send the message to
+ * the device and receive the response.
+ */
+void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+	int need_auto_sense;
+	int result;
+
+	/* send the command to the transport layer */
+	scsi_set_resid(srb, 0);
+	result = us->transport(srb, us);
+
+	/*
+	 * if the command gets aborted by the higher layers, we need to
+	 * short-circuit all other processing
+	 */
+	if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
+		usb_stor_dbg(us, "-- command was aborted\n");
+		srb->result = DID_ABORT << 16;
+		goto Handle_Errors;
+	}
+
+	/* if there is a transport error, reset and don't auto-sense */
+	if (result == USB_STOR_TRANSPORT_ERROR) {
+		usb_stor_dbg(us, "-- transport indicates error, resetting\n");
+		srb->result = DID_ERROR << 16;
+		goto Handle_Errors;
+	}
+
+	/* if the transport provided its own sense data, don't auto-sense */
+	if (result == USB_STOR_TRANSPORT_NO_SENSE) {
+		srb->result = SAM_STAT_CHECK_CONDITION;
+		last_sector_hacks(us, srb);
+		return;
+	}
+
+	srb->result = SAM_STAT_GOOD;
+
+	/*
+	 * Determine if we need to auto-sense
+	 *
+	 * I normally don't use a flag like this, but it's almost impossible
+	 * to understand what's going on here if I don't.
+	 */
+	need_auto_sense = 0;
+
+	/*
+	 * If we're running the CB transport, which is incapable
+	 * of determining status on its own, we will auto-sense
+	 * unless the operation involved a data-in transfer.  Devices
+	 * can signal most data-in errors by stalling the bulk-in pipe.
+	 */
+	if ((us->protocol == USB_PR_CB || us->protocol == USB_PR_DPCM_USB) &&
+			srb->sc_data_direction != DMA_FROM_DEVICE) {
+		usb_stor_dbg(us, "-- CB transport device requiring auto-sense\n");
+		need_auto_sense = 1;
+	}
+
+	/*
+	 * If we have a failure, we're going to do a REQUEST_SENSE 
+	 * automatically.  Note that we differentiate between a command
+	 * "failure" and an "error" in the transport mechanism.
+	 */
+	if (result == USB_STOR_TRANSPORT_FAILED) {
+		usb_stor_dbg(us, "-- transport indicates command failure\n");
+		need_auto_sense = 1;
+	}
+
+	/*
+	 * Determine if this device is SAT by seeing if the
+	 * command executed successfully.  Otherwise we'll have
+	 * to wait for at least one CHECK_CONDITION to determine
+	 * SANE_SENSE support
+	 */
+	if (unlikely((srb->cmnd[0] == ATA_16 || srb->cmnd[0] == ATA_12) &&
+	    result == USB_STOR_TRANSPORT_GOOD &&
+	    !(us->fflags & US_FL_SANE_SENSE) &&
+	    !(us->fflags & US_FL_BAD_SENSE) &&
+	    !(srb->cmnd[2] & 0x20))) {
+		usb_stor_dbg(us, "-- SAT supported, increasing auto-sense\n");
+		us->fflags |= US_FL_SANE_SENSE;
+	}
+
+	/*
+	 * A short transfer on a command where we don't expect it
+	 * is unusual, but it doesn't mean we need to auto-sense.
+	 */
+	if ((scsi_get_resid(srb) > 0) &&
+	    !((srb->cmnd[0] == REQUEST_SENSE) ||
+	      (srb->cmnd[0] == INQUIRY) ||
+	      (srb->cmnd[0] == MODE_SENSE) ||
+	      (srb->cmnd[0] == LOG_SENSE) ||
+	      (srb->cmnd[0] == MODE_SENSE_10))) {
+		usb_stor_dbg(us, "-- unexpectedly short transfer\n");
+	}
+
+	/* Now, if we need to do the auto-sense, let's do it */
+	if (need_auto_sense) {
+		int temp_result;
+		struct scsi_eh_save ses;
+		int sense_size = US_SENSE_SIZE;
+		struct scsi_sense_hdr sshdr;
+		const u8 *scdd;
+		u8 fm_ili;
+
+		/* device supports and needs bigger sense buffer */
+		if (us->fflags & US_FL_SANE_SENSE)
+			sense_size = ~0;
+Retry_Sense:
+		usb_stor_dbg(us, "Issuing auto-REQUEST_SENSE\n");
+
+		scsi_eh_prep_cmnd(srb, &ses, NULL, 0, sense_size);
+
+		/* FIXME: we must do the protocol translation here */
+		if (us->subclass == USB_SC_RBC || us->subclass == USB_SC_SCSI ||
+				us->subclass == USB_SC_CYP_ATACB)
+			srb->cmd_len = 6;
+		else
+			srb->cmd_len = 12;
+
+		/* issue the auto-sense command */
+		scsi_set_resid(srb, 0);
+		temp_result = us->transport(us->srb, us);
+
+		/* let's clean up right away */
+		scsi_eh_restore_cmnd(srb, &ses);
+
+		if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
+			usb_stor_dbg(us, "-- auto-sense aborted\n");
+			srb->result = DID_ABORT << 16;
+
+			/* If SANE_SENSE caused this problem, disable it */
+			if (sense_size != US_SENSE_SIZE) {
+				us->fflags &= ~US_FL_SANE_SENSE;
+				us->fflags |= US_FL_BAD_SENSE;
+			}
+			goto Handle_Errors;
+		}
+
+		/*
+		 * Some devices claim to support larger sense but fail when
+		 * trying to request it. When a transport failure happens
+		 * using US_FS_SANE_SENSE, we always retry with a standard
+		 * (small) sense request. This fixes some USB GSM modems
+		 */
+		if (temp_result == USB_STOR_TRANSPORT_FAILED &&
+				sense_size != US_SENSE_SIZE) {
+			usb_stor_dbg(us, "-- auto-sense failure, retry small sense\n");
+			sense_size = US_SENSE_SIZE;
+			us->fflags &= ~US_FL_SANE_SENSE;
+			us->fflags |= US_FL_BAD_SENSE;
+			goto Retry_Sense;
+		}
+
+		/* Other failures */
+		if (temp_result != USB_STOR_TRANSPORT_GOOD) {
+			usb_stor_dbg(us, "-- auto-sense failure\n");
+
+			/*
+			 * we skip the reset if this happens to be a
+			 * multi-target device, since failure of an
+			 * auto-sense is perfectly valid
+			 */
+			srb->result = DID_ERROR << 16;
+			if (!(us->fflags & US_FL_SCM_MULT_TARG))
+				goto Handle_Errors;
+			return;
+		}
+
+		/*
+		 * If the sense data returned is larger than 18-bytes then we
+		 * assume this device supports requesting more in the future.
+		 * The response code must be 70h through 73h inclusive.
+		 */
+		if (srb->sense_buffer[7] > (US_SENSE_SIZE - 8) &&
+		    !(us->fflags & US_FL_SANE_SENSE) &&
+		    !(us->fflags & US_FL_BAD_SENSE) &&
+		    (srb->sense_buffer[0] & 0x7C) == 0x70) {
+			usb_stor_dbg(us, "-- SANE_SENSE support enabled\n");
+			us->fflags |= US_FL_SANE_SENSE;
+
+			/*
+			 * Indicate to the user that we truncated their sense
+			 * because we didn't know it supported larger sense.
+			 */
+			usb_stor_dbg(us, "-- Sense data truncated to %i from %i\n",
+				     US_SENSE_SIZE,
+				     srb->sense_buffer[7] + 8);
+			srb->sense_buffer[7] = (US_SENSE_SIZE - 8);
+		}
+
+		scsi_normalize_sense(srb->sense_buffer, SCSI_SENSE_BUFFERSIZE,
+				     &sshdr);
+
+		usb_stor_dbg(us, "-- Result from auto-sense is %d\n",
+			     temp_result);
+		usb_stor_dbg(us, "-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
+			     sshdr.response_code, sshdr.sense_key,
+			     sshdr.asc, sshdr.ascq);
+#ifdef CONFIG_USB_STORAGE_DEBUG
+		usb_stor_show_sense(us, sshdr.sense_key, sshdr.asc, sshdr.ascq);
+#endif
+
+		/* set the result so the higher layers expect this data */
+		srb->result = SAM_STAT_CHECK_CONDITION;
+
+		scdd = scsi_sense_desc_find(srb->sense_buffer,
+					    SCSI_SENSE_BUFFERSIZE, 4);
+		fm_ili = (scdd ? scdd[3] : srb->sense_buffer[2]) & 0xA0;
+
+		/*
+		 * We often get empty sense data.  This could indicate that
+		 * everything worked or that there was an unspecified
+		 * problem.  We have to decide which.
+		 */
+		if (sshdr.sense_key == 0 && sshdr.asc == 0 && sshdr.ascq == 0 &&
+		    fm_ili == 0) {
+			/*
+			 * If things are really okay, then let's show that.
+			 * Zero out the sense buffer so the higher layers
+			 * won't realize we did an unsolicited auto-sense.
+			 */
+			if (result == USB_STOR_TRANSPORT_GOOD) {
+				srb->result = SAM_STAT_GOOD;
+				srb->sense_buffer[0] = 0x0;
+			}
+
+			/*
+			 * ATA-passthru commands use sense data to report
+			 * the command completion status, and often devices
+			 * return Check Condition status when nothing is
+			 * wrong.
+			 */
+			else if (srb->cmnd[0] == ATA_16 ||
+					srb->cmnd[0] == ATA_12) {
+				/* leave the data alone */
+			}
+
+			/*
+			 * If there was a problem, report an unspecified
+			 * hardware error to prevent the higher layers from
+			 * entering an infinite retry loop.
+			 */
+			else {
+				srb->result = DID_ERROR << 16;
+				if ((sshdr.response_code & 0x72) == 0x72)
+					srb->sense_buffer[1] = HARDWARE_ERROR;
+				else
+					srb->sense_buffer[2] = HARDWARE_ERROR;
+			}
+		}
+	}
+
+	/*
+	 * Some devices don't work or return incorrect data the first
+	 * time they get a READ(10) command, or for the first READ(10)
+	 * after a media change.  If the INITIAL_READ10 flag is set,
+	 * keep track of whether READ(10) commands succeed.  If the
+	 * previous one succeeded and this one failed, set the REDO_READ10
+	 * flag to force a retry.
+	 */
+	if (unlikely((us->fflags & US_FL_INITIAL_READ10) &&
+			srb->cmnd[0] == READ_10)) {
+		if (srb->result == SAM_STAT_GOOD) {
+			set_bit(US_FLIDX_READ10_WORKED, &us->dflags);
+		} else if (test_bit(US_FLIDX_READ10_WORKED, &us->dflags)) {
+			clear_bit(US_FLIDX_READ10_WORKED, &us->dflags);
+			set_bit(US_FLIDX_REDO_READ10, &us->dflags);
+		}
+
+		/*
+		 * Next, if the REDO_READ10 flag is set, return a result
+		 * code that will cause the SCSI core to retry the READ(10)
+		 * command immediately.
+		 */
+		if (test_bit(US_FLIDX_REDO_READ10, &us->dflags)) {
+			clear_bit(US_FLIDX_REDO_READ10, &us->dflags);
+			srb->result = DID_IMM_RETRY << 16;
+			srb->sense_buffer[0] = 0;
+		}
+	}
+
+	/* Did we transfer less than the minimum amount required? */
+	if ((srb->result == SAM_STAT_GOOD || srb->sense_buffer[2] == 0) &&
+			scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow)
+		srb->result = DID_ERROR << 16;
+
+	last_sector_hacks(us, srb);
+	return;
+
+	/*
+	 * Error and abort processing: try to resynchronize with the device
+	 * by issuing a port reset.  If that fails, try a class-specific
+	 * device reset.
+	 */
+  Handle_Errors:
+
+	/*
+	 * Set the RESETTING bit, and clear the ABORTING bit so that
+	 * the reset may proceed.
+	 */
+	scsi_lock(us_to_host(us));
+	set_bit(US_FLIDX_RESETTING, &us->dflags);
+	clear_bit(US_FLIDX_ABORTING, &us->dflags);
+	scsi_unlock(us_to_host(us));
+
+	/*
+	 * We must release the device lock because the pre_reset routine
+	 * will want to acquire it.
+	 */
+	mutex_unlock(&us->dev_mutex);
+	result = usb_stor_port_reset(us);
+	mutex_lock(&us->dev_mutex);
+
+	if (result < 0) {
+		scsi_lock(us_to_host(us));
+		usb_stor_report_device_reset(us);
+		scsi_unlock(us_to_host(us));
+		us->transport_reset(us);
+	}
+	clear_bit(US_FLIDX_RESETTING, &us->dflags);
+	last_sector_hacks(us, srb);
+}
+
+/* Stop the current URB transfer */
+void usb_stor_stop_transport(struct us_data *us)
+{
+	/*
+	 * If the state machine is blocked waiting for an URB,
+	 * let's wake it up.  The test_and_clear_bit() call
+	 * guarantees that if a URB has just been submitted,
+	 * it won't be cancelled more than once.
+	 */
+	if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags)) {
+		usb_stor_dbg(us, "-- cancelling URB\n");
+		usb_unlink_urb(us->current_urb);
+	}
+
+	/* If we are waiting for a scatter-gather operation, cancel it. */
+	if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags)) {
+		usb_stor_dbg(us, "-- cancelling sg request\n");
+		usb_sg_cancel(&us->current_sg);
+	}
+}
+
+/*
+ * Control/Bulk and Control/Bulk/Interrupt transport
+ */
+
+int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+	unsigned int transfer_length = scsi_bufflen(srb);
+	unsigned int pipe = 0;
+	int result;
+
+	/* COMMAND STAGE */
+	/* let's send the command via the control pipe */
+	/*
+	 * Command is sometime (f.e. after scsi_eh_prep_cmnd) on the stack.
+	 * Stack may be vmallocated.  So no DMA for us.  Make a copy.
+	 */
+	memcpy(us->iobuf, srb->cmnd, srb->cmd_len);
+	result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
+				      US_CBI_ADSC, 
+				      USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, 
+				      us->ifnum, us->iobuf, srb->cmd_len);
+
+	/* check the return code for the command */
+	usb_stor_dbg(us, "Call to usb_stor_ctrl_transfer() returned %d\n",
+		     result);
+
+	/* if we stalled the command, it means command failed */
+	if (result == USB_STOR_XFER_STALLED) {
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	/* Uh oh... serious problem here */
+	if (result != USB_STOR_XFER_GOOD) {
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	/* DATA STAGE */
+	/* transfer the data payload for this command, if one exists*/
+	if (transfer_length) {
+		pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? 
+				us->recv_bulk_pipe : us->send_bulk_pipe;
+		result = usb_stor_bulk_srb(us, pipe, srb);
+		usb_stor_dbg(us, "CBI data stage result is 0x%x\n", result);
+
+		/* if we stalled the data transfer it means command failed */
+		if (result == USB_STOR_XFER_STALLED)
+			return USB_STOR_TRANSPORT_FAILED;
+		if (result > USB_STOR_XFER_STALLED)
+			return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	/* STATUS STAGE */
+
+	/*
+	 * NOTE: CB does not have a status stage.  Silly, I know.  So
+	 * we have to catch this at a higher level.
+	 */
+	if (us->protocol != USB_PR_CBI)
+		return USB_STOR_TRANSPORT_GOOD;
+
+	result = usb_stor_intr_transfer(us, us->iobuf, 2);
+	usb_stor_dbg(us, "Got interrupt data (0x%x, 0x%x)\n",
+		     us->iobuf[0], us->iobuf[1]);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	/*
+	 * UFI gives us ASC and ASCQ, like a request sense
+	 *
+	 * REQUEST_SENSE and INQUIRY don't affect the sense data on UFI
+	 * devices, so we ignore the information for those commands.  Note
+	 * that this means we could be ignoring a real error on these
+	 * commands, but that can't be helped.
+	 */
+	if (us->subclass == USB_SC_UFI) {
+		if (srb->cmnd[0] == REQUEST_SENSE ||
+		    srb->cmnd[0] == INQUIRY)
+			return USB_STOR_TRANSPORT_GOOD;
+		if (us->iobuf[0])
+			goto Failed;
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	/*
+	 * If not UFI, we interpret the data as a result code 
+	 * The first byte should always be a 0x0.
+	 *
+	 * Some bogus devices don't follow that rule.  They stuff the ASC
+	 * into the first byte -- so if it's non-zero, call it a failure.
+	 */
+	if (us->iobuf[0]) {
+		usb_stor_dbg(us, "CBI IRQ data showed reserved bType 0x%x\n",
+			     us->iobuf[0]);
+		goto Failed;
+
+	}
+
+	/* The second byte & 0x0F should be 0x0 for good, otherwise error */
+	switch (us->iobuf[1] & 0x0F) {
+		case 0x00: 
+			return USB_STOR_TRANSPORT_GOOD;
+		case 0x01: 
+			goto Failed;
+	}
+	return USB_STOR_TRANSPORT_ERROR;
+
+	/*
+	 * the CBI spec requires that the bulk pipe must be cleared
+	 * following any data-in/out command failure (section 2.4.3.1.3)
+	 */
+  Failed:
+	if (pipe)
+		usb_stor_clear_halt(us, pipe);
+	return USB_STOR_TRANSPORT_FAILED;
+}
+EXPORT_SYMBOL_GPL(usb_stor_CB_transport);
+
+/*
+ * Bulk only transport
+ */
+
+/* Determine what the maximum LUN supported is */
+int usb_stor_Bulk_max_lun(struct us_data *us)
+{
+	int result;
+
+	/* issue the command */
+	us->iobuf[0] = 0;
+	result = usb_stor_control_msg(us, us->recv_ctrl_pipe,
+				 US_BULK_GET_MAX_LUN, 
+				 USB_DIR_IN | USB_TYPE_CLASS | 
+				 USB_RECIP_INTERFACE,
+				 0, us->ifnum, us->iobuf, 1, 10*HZ);
+
+	usb_stor_dbg(us, "GetMaxLUN command result is %d, data is %d\n",
+		     result, us->iobuf[0]);
+
+	/*
+	 * If we have a successful request, return the result if valid. The
+	 * CBW LUN field is 4 bits wide, so the value reported by the device
+	 * should fit into that.
+	 */
+	if (result > 0) {
+		if (us->iobuf[0] < 16) {
+			return us->iobuf[0];
+		} else {
+			dev_info(&us->pusb_intf->dev,
+				 "Max LUN %d is not valid, using 0 instead",
+				 us->iobuf[0]);
+		}
+	}
+
+	/*
+	 * Some devices don't like GetMaxLUN.  They may STALL the control
+	 * pipe, they may return a zero-length result, they may do nothing at
+	 * all and timeout, or they may fail in even more bizarrely creative
+	 * ways.  In these cases the best approach is to use the default
+	 * value: only one LUN.
+	 */
+	return 0;
+}
+
+int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+	struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
+	unsigned int transfer_length = scsi_bufflen(srb);
+	unsigned int residue;
+	int result;
+	int fake_sense = 0;
+	unsigned int cswlen;
+	unsigned int cbwlen = US_BULK_CB_WRAP_LEN;
+
+	/* Take care of BULK32 devices; set extra byte to 0 */
+	if (unlikely(us->fflags & US_FL_BULK32)) {
+		cbwlen = 32;
+		us->iobuf[31] = 0;
+	}
+
+	/* set up the command wrapper */
+	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+	bcb->DataTransferLength = cpu_to_le32(transfer_length);
+	bcb->Flags = srb->sc_data_direction == DMA_FROM_DEVICE ?
+		US_BULK_FLAG_IN : 0;
+	bcb->Tag = ++us->tag;
+	bcb->Lun = srb->device->lun;
+	if (us->fflags & US_FL_SCM_MULT_TARG)
+		bcb->Lun |= srb->device->id << 4;
+	bcb->Length = srb->cmd_len;
+
+	/* copy the command payload */
+	memset(bcb->CDB, 0, sizeof(bcb->CDB));
+	memcpy(bcb->CDB, srb->cmnd, bcb->Length);
+
+	/* send it to out endpoint */
+	usb_stor_dbg(us, "Bulk Command S 0x%x T 0x%x L %d F %d Trg %d LUN %d CL %d\n",
+		     le32_to_cpu(bcb->Signature), bcb->Tag,
+		     le32_to_cpu(bcb->DataTransferLength), bcb->Flags,
+		     (bcb->Lun >> 4), (bcb->Lun & 0x0F),
+		     bcb->Length);
+	result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+				bcb, cbwlen, NULL);
+	usb_stor_dbg(us, "Bulk command transfer result=%d\n", result);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	/* DATA STAGE */
+	/* send/receive data payload, if there is any */
+
+	/*
+	 * Some USB-IDE converter chips need a 100us delay between the
+	 * command phase and the data phase.  Some devices need a little
+	 * more than that, probably because of clock rate inaccuracies.
+	 */
+	if (unlikely(us->fflags & US_FL_GO_SLOW))
+		usleep_range(125, 150);
+
+	if (transfer_length) {
+		unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? 
+				us->recv_bulk_pipe : us->send_bulk_pipe;
+		result = usb_stor_bulk_srb(us, pipe, srb);
+		usb_stor_dbg(us, "Bulk data transfer result 0x%x\n", result);
+		if (result == USB_STOR_XFER_ERROR)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		/*
+		 * If the device tried to send back more data than the
+		 * amount requested, the spec requires us to transfer
+		 * the CSW anyway.  Since there's no point retrying the
+		 * the command, we'll return fake sense data indicating
+		 * Illegal Request, Invalid Field in CDB.
+		 */
+		if (result == USB_STOR_XFER_LONG)
+			fake_sense = 1;
+
+		/*
+		 * Sometimes a device will mistakenly skip the data phase
+		 * and go directly to the status phase without sending a
+		 * zero-length packet.  If we get a 13-byte response here,
+		 * check whether it really is a CSW.
+		 */
+		if (result == USB_STOR_XFER_SHORT &&
+				srb->sc_data_direction == DMA_FROM_DEVICE &&
+				transfer_length - scsi_get_resid(srb) ==
+					US_BULK_CS_WRAP_LEN) {
+			struct scatterlist *sg = NULL;
+			unsigned int offset = 0;
+
+			if (usb_stor_access_xfer_buf((unsigned char *) bcs,
+					US_BULK_CS_WRAP_LEN, srb, &sg,
+					&offset, FROM_XFER_BUF) ==
+						US_BULK_CS_WRAP_LEN &&
+					bcs->Signature ==
+						cpu_to_le32(US_BULK_CS_SIGN)) {
+				usb_stor_dbg(us, "Device skipped data phase\n");
+				scsi_set_resid(srb, transfer_length);
+				goto skipped_data_phase;
+			}
+		}
+	}
+
+	/*
+	 * See flow chart on pg 15 of the Bulk Only Transport spec for
+	 * an explanation of how this code works.
+	 */
+
+	/* get CSW for device status */
+	usb_stor_dbg(us, "Attempting to get CSW...\n");
+	result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+				bcs, US_BULK_CS_WRAP_LEN, &cswlen);
+
+	/*
+	 * Some broken devices add unnecessary zero-length packets to the
+	 * end of their data transfers.  Such packets show up as 0-length
+	 * CSWs.  If we encounter such a thing, try to read the CSW again.
+	 */
+	if (result == USB_STOR_XFER_SHORT && cswlen == 0) {
+		usb_stor_dbg(us, "Received 0-length CSW; retrying...\n");
+		result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+				bcs, US_BULK_CS_WRAP_LEN, &cswlen);
+	}
+
+	/* did the attempt to read the CSW fail? */
+	if (result == USB_STOR_XFER_STALLED) {
+
+		/* get the status again */
+		usb_stor_dbg(us, "Attempting to get CSW (2nd try)...\n");
+		result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+				bcs, US_BULK_CS_WRAP_LEN, NULL);
+	}
+
+	/* if we still have a failure at this point, we're in trouble */
+	usb_stor_dbg(us, "Bulk status result = %d\n", result);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+ skipped_data_phase:
+	/* check bulk status */
+	residue = le32_to_cpu(bcs->Residue);
+	usb_stor_dbg(us, "Bulk Status S 0x%x T 0x%x R %u Stat 0x%x\n",
+		     le32_to_cpu(bcs->Signature), bcs->Tag,
+		     residue, bcs->Status);
+	if (!(bcs->Tag == us->tag || (us->fflags & US_FL_BULK_IGNORE_TAG)) ||
+		bcs->Status > US_BULK_STAT_PHASE) {
+		usb_stor_dbg(us, "Bulk logical error\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	/*
+	 * Some broken devices report odd signatures, so we do not check them
+	 * for validity against the spec. We store the first one we see,
+	 * and check subsequent transfers for validity against this signature.
+	 */
+	if (!us->bcs_signature) {
+		us->bcs_signature = bcs->Signature;
+		if (us->bcs_signature != cpu_to_le32(US_BULK_CS_SIGN))
+			usb_stor_dbg(us, "Learnt BCS signature 0x%08X\n",
+				     le32_to_cpu(us->bcs_signature));
+	} else if (bcs->Signature != us->bcs_signature) {
+		usb_stor_dbg(us, "Signature mismatch: got %08X, expecting %08X\n",
+			     le32_to_cpu(bcs->Signature),
+			     le32_to_cpu(us->bcs_signature));
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	/*
+	 * try to compute the actual residue, based on how much data
+	 * was really transferred and what the device tells us
+	 */
+	if (residue && !(us->fflags & US_FL_IGNORE_RESIDUE)) {
+
+		/*
+		 * Heuristically detect devices that generate bogus residues
+		 * by seeing what happens with INQUIRY and READ CAPACITY
+		 * commands.
+		 */
+		if (bcs->Status == US_BULK_STAT_OK &&
+				scsi_get_resid(srb) == 0 &&
+					((srb->cmnd[0] == INQUIRY &&
+						transfer_length == 36) ||
+					(srb->cmnd[0] == READ_CAPACITY &&
+						transfer_length == 8))) {
+			us->fflags |= US_FL_IGNORE_RESIDUE;
+
+		} else {
+			residue = min(residue, transfer_length);
+			scsi_set_resid(srb, max(scsi_get_resid(srb),
+			                                       (int) residue));
+		}
+	}
+
+	/* based on the status code, we report good or bad */
+	switch (bcs->Status) {
+		case US_BULK_STAT_OK:
+			/* device babbled -- return fake sense data */
+			if (fake_sense) {
+				memcpy(srb->sense_buffer, 
+				       usb_stor_sense_invalidCDB, 
+				       sizeof(usb_stor_sense_invalidCDB));
+				return USB_STOR_TRANSPORT_NO_SENSE;
+			}
+
+			/* command good -- note that data could be short */
+			return USB_STOR_TRANSPORT_GOOD;
+
+		case US_BULK_STAT_FAIL:
+			/* command failed */
+			return USB_STOR_TRANSPORT_FAILED;
+
+		case US_BULK_STAT_PHASE:
+			/*
+			 * phase error -- note that a transport reset will be
+			 * invoked by the invoke_transport() function
+			 */
+			return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	/* we should never get here, but if we do, we're in trouble */
+	return USB_STOR_TRANSPORT_ERROR;
+}
+EXPORT_SYMBOL_GPL(usb_stor_Bulk_transport);
+
+/***********************************************************************
+ * Reset routines
+ ***********************************************************************/
+
+/*
+ * This is the common part of the device reset code.
+ *
+ * It's handy that every transport mechanism uses the control endpoint for
+ * resets.
+ *
+ * Basically, we send a reset with a 5-second timeout, so we don't get
+ * jammed attempting to do the reset.
+ */
+static int usb_stor_reset_common(struct us_data *us,
+		u8 request, u8 requesttype,
+		u16 value, u16 index, void *data, u16 size)
+{
+	int result;
+	int result2;
+
+	if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
+		usb_stor_dbg(us, "No reset during disconnect\n");
+		return -EIO;
+	}
+
+	result = usb_stor_control_msg(us, us->send_ctrl_pipe,
+			request, requesttype, value, index, data, size,
+			5*HZ);
+	if (result < 0) {
+		usb_stor_dbg(us, "Soft reset failed: %d\n", result);
+		return result;
+	}
+
+	/*
+	 * Give the device some time to recover from the reset,
+	 * but don't delay disconnect processing.
+	 */
+	wait_event_interruptible_timeout(us->delay_wait,
+			test_bit(US_FLIDX_DISCONNECTING, &us->dflags),
+			HZ*6);
+	if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
+		usb_stor_dbg(us, "Reset interrupted by disconnect\n");
+		return -EIO;
+	}
+
+	usb_stor_dbg(us, "Soft reset: clearing bulk-in endpoint halt\n");
+	result = usb_stor_clear_halt(us, us->recv_bulk_pipe);
+
+	usb_stor_dbg(us, "Soft reset: clearing bulk-out endpoint halt\n");
+	result2 = usb_stor_clear_halt(us, us->send_bulk_pipe);
+
+	/* return a result code based on the result of the clear-halts */
+	if (result >= 0)
+		result = result2;
+	if (result < 0)
+		usb_stor_dbg(us, "Soft reset failed\n");
+	else
+		usb_stor_dbg(us, "Soft reset done\n");
+	return result;
+}
+
+/* This issues a CB[I] Reset to the device in question */
+#define CB_RESET_CMD_SIZE	12
+
+int usb_stor_CB_reset(struct us_data *us)
+{
+	memset(us->iobuf, 0xFF, CB_RESET_CMD_SIZE);
+	us->iobuf[0] = SEND_DIAGNOSTIC;
+	us->iobuf[1] = 4;
+	return usb_stor_reset_common(us, US_CBI_ADSC, 
+				 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+				 0, us->ifnum, us->iobuf, CB_RESET_CMD_SIZE);
+}
+EXPORT_SYMBOL_GPL(usb_stor_CB_reset);
+
+/*
+ * This issues a Bulk-only Reset to the device in question, including
+ * clearing the subsequent endpoint halts that may occur.
+ */
+int usb_stor_Bulk_reset(struct us_data *us)
+{
+	return usb_stor_reset_common(us, US_BULK_RESET_REQUEST, 
+				 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+				 0, us->ifnum, NULL, 0);
+}
+EXPORT_SYMBOL_GPL(usb_stor_Bulk_reset);
+
+/*
+ * Issue a USB port reset to the device.  The caller must not hold
+ * us->dev_mutex.
+ */
+int usb_stor_port_reset(struct us_data *us)
+{
+	int result;
+
+	/*for these devices we must use the class specific method */
+	if (us->pusb_dev->quirks & USB_QUIRK_RESET)
+		return -EPERM;
+
+	result = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
+	if (result < 0)
+		usb_stor_dbg(us, "unable to lock device for reset: %d\n",
+			     result);
+	else {
+		/* Were we disconnected while waiting for the lock? */
+		if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
+			result = -EIO;
+			usb_stor_dbg(us, "No reset during disconnect\n");
+		} else {
+			result = usb_reset_device(us->pusb_dev);
+			usb_stor_dbg(us, "usb_reset_device returns %d\n",
+				     result);
+		}
+		usb_unlock_device(us->pusb_dev);
+	}
+	return result;
+}
diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h
new file mode 100644
index 0000000..fb3bb4e
--- /dev/null
+++ b/drivers/usb/storage/transport.h
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for USB Mass Storage compliant devices
+ * Transport Functions Header File
+ *
+ * Current development and maintenance by:
+ *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * 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.
+ */
+
+#ifndef _TRANSPORT_H_
+#define _TRANSPORT_H_
+
+#include <linux/blkdev.h>
+
+/*
+ * usb_stor_bulk_transfer_xxx() return codes, in order of severity
+ */
+
+#define USB_STOR_XFER_GOOD	0	/* good transfer                 */
+#define USB_STOR_XFER_SHORT	1	/* transferred less than expected */
+#define USB_STOR_XFER_STALLED	2	/* endpoint stalled              */
+#define USB_STOR_XFER_LONG	3	/* device tried to send too much */
+#define USB_STOR_XFER_ERROR	4	/* transfer died in the middle   */
+
+/*
+ * Transport return codes
+ */
+
+#define USB_STOR_TRANSPORT_GOOD	   0   /* Transport good, command good	   */
+#define USB_STOR_TRANSPORT_FAILED  1   /* Transport good, command failed   */
+#define USB_STOR_TRANSPORT_NO_SENSE 2  /* Command failed, no auto-sense    */
+#define USB_STOR_TRANSPORT_ERROR   3   /* Transport bad (i.e. device dead) */
+
+/*
+ * We used to have USB_STOR_XFER_ABORTED and USB_STOR_TRANSPORT_ABORTED
+ * return codes.  But now the transport and low-level transfer routines
+ * treat an abort as just another error (-ENOENT for a cancelled URB).
+ * It is up to the invoke_transport() function to test for aborts and
+ * distinguish them from genuine communication errors.
+ */
+
+/*
+ * CBI accept device specific command
+ */
+
+#define US_CBI_ADSC		0
+
+extern int usb_stor_CB_transport(struct scsi_cmnd *, struct us_data*);
+extern int usb_stor_CB_reset(struct us_data*);
+
+extern int usb_stor_Bulk_transport(struct scsi_cmnd *, struct us_data*);
+extern int usb_stor_Bulk_max_lun(struct us_data*);
+extern int usb_stor_Bulk_reset(struct us_data*);
+
+extern void usb_stor_invoke_transport(struct scsi_cmnd *, struct us_data*);
+extern void usb_stor_stop_transport(struct us_data*);
+
+extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
+		u8 request, u8 requesttype, u16 value, u16 index,
+		void *data, u16 size, int timeout);
+extern int usb_stor_clear_halt(struct us_data *us, unsigned int pipe);
+
+extern int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe,
+		u8 request, u8 requesttype, u16 value, u16 index,
+		void *data, u16 size);
+extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
+		void *buf, unsigned int length, unsigned int *act_len);
+extern int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe,
+		void *buf, unsigned int length, int use_sg, int *residual);
+extern int usb_stor_bulk_srb(struct us_data* us, unsigned int pipe,
+		struct scsi_cmnd* srb);
+
+extern int usb_stor_port_reset(struct us_data *us);
+#endif
diff --git a/drivers/usb/storage/uas-detect.h b/drivers/usb/storage/uas-detect.h
new file mode 100644
index 0000000..3734a25
--- /dev/null
+++ b/drivers/usb/storage/uas-detect.h
@@ -0,0 +1,149 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include "usb.h"
+
+static int uas_is_interface(struct usb_host_interface *intf)
+{
+	return (intf->desc.bInterfaceClass == USB_CLASS_MASS_STORAGE &&
+		intf->desc.bInterfaceSubClass == USB_SC_SCSI &&
+		intf->desc.bInterfaceProtocol == USB_PR_UAS);
+}
+
+static struct usb_host_interface *uas_find_uas_alt_setting(
+		struct usb_interface *intf)
+{
+	int i;
+
+	for (i = 0; i < intf->num_altsetting; i++) {
+		struct usb_host_interface *alt = &intf->altsetting[i];
+
+		if (uas_is_interface(alt))
+			return alt;
+	}
+
+	return NULL;
+}
+
+static int uas_find_endpoints(struct usb_host_interface *alt,
+			      struct usb_host_endpoint *eps[])
+{
+	struct usb_host_endpoint *endpoint = alt->endpoint;
+	unsigned i, n_endpoints = alt->desc.bNumEndpoints;
+
+	for (i = 0; i < n_endpoints; i++) {
+		unsigned char *extra = endpoint[i].extra;
+		int len = endpoint[i].extralen;
+		while (len >= 3) {
+			if (extra[1] == USB_DT_PIPE_USAGE) {
+				unsigned pipe_id = extra[2];
+				if (pipe_id > 0 && pipe_id < 5)
+					eps[pipe_id - 1] = &endpoint[i];
+				break;
+			}
+			len -= extra[0];
+			extra += extra[0];
+		}
+	}
+
+	if (!eps[0] || !eps[1] || !eps[2] || !eps[3])
+		return -ENODEV;
+
+	return 0;
+}
+
+static int uas_use_uas_driver(struct usb_interface *intf,
+			      const struct usb_device_id *id,
+			      unsigned long *flags_ret)
+{
+	struct usb_host_endpoint *eps[4] = { };
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+	unsigned long flags = id->driver_info;
+	struct usb_host_interface *alt;
+	int r;
+
+	alt = uas_find_uas_alt_setting(intf);
+	if (!alt)
+		return 0;
+
+	r = uas_find_endpoints(alt, eps);
+	if (r < 0)
+		return 0;
+
+	/*
+	 * ASMedia has a number of usb3 to sata bridge chips, at the time of
+	 * this writing the following versions exist:
+	 * ASM1051 - no uas support version
+	 * ASM1051 - with broken (*) uas support
+	 * ASM1053 - with working uas support, but problems with large xfers
+	 * ASM1153 - with working uas support
+	 *
+	 * Devices with these chips re-use a number of device-ids over the
+	 * entire line, so the device-id is useless to determine if we're
+	 * dealing with an ASM1051 (which we want to avoid).
+	 *
+	 * The ASM1153 can be identified by config.MaxPower == 0,
+	 * where as the ASM105x models have config.MaxPower == 36.
+	 *
+	 * Differentiating between the ASM1053 and ASM1051 is trickier, when
+	 * connected over USB-3 we can look at the number of streams supported,
+	 * ASM1051 supports 32 streams, where as early ASM1053 versions support
+	 * 16 streams, newer ASM1053-s also support 32 streams, but have a
+	 * different prod-id.
+	 *
+	 * (*) ASM1051 chips do work with UAS with some disks (with the
+	 *     US_FL_NO_REPORT_OPCODES quirk), but are broken with other disks
+	 */
+	if (le16_to_cpu(udev->descriptor.idVendor) == 0x174c &&
+			(le16_to_cpu(udev->descriptor.idProduct) == 0x5106 ||
+			 le16_to_cpu(udev->descriptor.idProduct) == 0x55aa)) {
+		if (udev->actconfig->desc.bMaxPower == 0) {
+			/* ASM1153, do nothing */
+		} else if (udev->speed < USB_SPEED_SUPER) {
+			/* No streams info, assume ASM1051 */
+			flags |= US_FL_IGNORE_UAS;
+		} else if (usb_ss_max_streams(&eps[1]->ss_ep_comp) == 32) {
+			/* Possibly an ASM1051, disable uas */
+			flags |= US_FL_IGNORE_UAS;
+		} else {
+			/* ASM1053, these have issues with large transfers */
+			flags |= US_FL_MAX_SECTORS_240;
+		}
+	}
+
+	/* All Seagate disk enclosures have broken ATA pass-through support */
+	if (le16_to_cpu(udev->descriptor.idVendor) == 0x0bc2)
+		flags |= US_FL_NO_ATA_1X;
+
+	usb_stor_adjust_quirks(udev, &flags);
+
+	if (flags & US_FL_IGNORE_UAS) {
+		dev_warn(&udev->dev,
+			"UAS is blacklisted for this device, using usb-storage instead\n");
+		return 0;
+	}
+
+	if (udev->bus->sg_tablesize == 0) {
+		dev_warn(&udev->dev,
+			"The driver for the USB controller %s does not support scatter-gather which is\n",
+			hcd->driver->description);
+		dev_warn(&udev->dev,
+			"required by the UAS driver. Please try an other USB controller if you wish to use UAS.\n");
+		return 0;
+	}
+
+	if (udev->speed >= USB_SPEED_SUPER && !hcd->can_do_streams) {
+		dev_warn(&udev->dev,
+			"USB controller %s does not support streams, which are required by the UAS driver.\n",
+			hcd_to_bus(hcd)->bus_name);
+		dev_warn(&udev->dev,
+			"Please try an other USB controller if you wish to use UAS.\n");
+		return 0;
+	}
+
+	if (flags_ret)
+		*flags_ret = flags;
+
+	return 1;
+}
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
new file mode 100644
index 0000000..1f7b401
--- /dev/null
+++ b/drivers/usb/storage/uas.c
@@ -0,0 +1,1220 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * USB Attached SCSI
+ * Note that this is not the same as the USB Mass Storage driver
+ *
+ * Copyright Hans de Goede <hdegoede@redhat.com> for Red Hat, Inc. 2013 - 2016
+ * Copyright Matthew Wilcox for Intel Corp, 2010
+ * Copyright Sarah Sharp for Intel Corp, 2010
+ */
+
+#include <linux/blkdev.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb_usual.h>
+#include <linux/usb/hcd.h>
+#include <linux/usb/storage.h>
+#include <linux/usb/uas.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+
+#include "uas-detect.h"
+#include "scsiglue.h"
+
+#define MAX_CMNDS 256
+
+struct uas_dev_info {
+	struct usb_interface *intf;
+	struct usb_device *udev;
+	struct usb_anchor cmd_urbs;
+	struct usb_anchor sense_urbs;
+	struct usb_anchor data_urbs;
+	unsigned long flags;
+	int qdepth, resetting;
+	unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe;
+	unsigned use_streams:1;
+	unsigned shutdown:1;
+	struct scsi_cmnd *cmnd[MAX_CMNDS];
+	spinlock_t lock;
+	struct work_struct work;
+};
+
+enum {
+	SUBMIT_STATUS_URB	= BIT(1),
+	ALLOC_DATA_IN_URB	= BIT(2),
+	SUBMIT_DATA_IN_URB	= BIT(3),
+	ALLOC_DATA_OUT_URB	= BIT(4),
+	SUBMIT_DATA_OUT_URB	= BIT(5),
+	ALLOC_CMD_URB		= BIT(6),
+	SUBMIT_CMD_URB		= BIT(7),
+	COMMAND_INFLIGHT        = BIT(8),
+	DATA_IN_URB_INFLIGHT    = BIT(9),
+	DATA_OUT_URB_INFLIGHT   = BIT(10),
+	COMMAND_ABORTED         = BIT(11),
+	IS_IN_WORK_LIST         = BIT(12),
+};
+
+/* Overrides scsi_pointer */
+struct uas_cmd_info {
+	unsigned int state;
+	unsigned int uas_tag;
+	struct urb *cmd_urb;
+	struct urb *data_in_urb;
+	struct urb *data_out_urb;
+};
+
+/* I hate forward declarations, but I actually have a loop */
+static int uas_submit_urbs(struct scsi_cmnd *cmnd,
+				struct uas_dev_info *devinfo);
+static void uas_do_work(struct work_struct *work);
+static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller);
+static void uas_free_streams(struct uas_dev_info *devinfo);
+static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *prefix,
+				int status);
+
+static void uas_do_work(struct work_struct *work)
+{
+	struct uas_dev_info *devinfo =
+		container_of(work, struct uas_dev_info, work);
+	struct uas_cmd_info *cmdinfo;
+	struct scsi_cmnd *cmnd;
+	unsigned long flags;
+	int i, err;
+
+	spin_lock_irqsave(&devinfo->lock, flags);
+
+	if (devinfo->resetting)
+		goto out;
+
+	for (i = 0; i < devinfo->qdepth; i++) {
+		if (!devinfo->cmnd[i])
+			continue;
+
+		cmnd = devinfo->cmnd[i];
+		cmdinfo = (void *)&cmnd->SCp;
+
+		if (!(cmdinfo->state & IS_IN_WORK_LIST))
+			continue;
+
+		err = uas_submit_urbs(cmnd, cmnd->device->hostdata);
+		if (!err)
+			cmdinfo->state &= ~IS_IN_WORK_LIST;
+		else
+			schedule_work(&devinfo->work);
+	}
+out:
+	spin_unlock_irqrestore(&devinfo->lock, flags);
+}
+
+static void uas_add_work(struct uas_cmd_info *cmdinfo)
+{
+	struct scsi_pointer *scp = (void *)cmdinfo;
+	struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd, SCp);
+	struct uas_dev_info *devinfo = cmnd->device->hostdata;
+
+	lockdep_assert_held(&devinfo->lock);
+	cmdinfo->state |= IS_IN_WORK_LIST;
+	schedule_work(&devinfo->work);
+}
+
+static void uas_zap_pending(struct uas_dev_info *devinfo, int result)
+{
+	struct uas_cmd_info *cmdinfo;
+	struct scsi_cmnd *cmnd;
+	unsigned long flags;
+	int i, err;
+
+	spin_lock_irqsave(&devinfo->lock, flags);
+	for (i = 0; i < devinfo->qdepth; i++) {
+		if (!devinfo->cmnd[i])
+			continue;
+
+		cmnd = devinfo->cmnd[i];
+		cmdinfo = (void *)&cmnd->SCp;
+		uas_log_cmd_state(cmnd, __func__, 0);
+		/* Sense urbs were killed, clear COMMAND_INFLIGHT manually */
+		cmdinfo->state &= ~COMMAND_INFLIGHT;
+		cmnd->result = result << 16;
+		err = uas_try_complete(cmnd, __func__);
+		WARN_ON(err != 0);
+	}
+	spin_unlock_irqrestore(&devinfo->lock, flags);
+}
+
+static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
+{
+	struct sense_iu *sense_iu = urb->transfer_buffer;
+	struct scsi_device *sdev = cmnd->device;
+
+	if (urb->actual_length > 16) {
+		unsigned len = be16_to_cpup(&sense_iu->len);
+		if (len + 16 != urb->actual_length) {
+			int newlen = min(len + 16, urb->actual_length) - 16;
+			if (newlen < 0)
+				newlen = 0;
+			sdev_printk(KERN_INFO, sdev, "%s: urb length %d "
+				"disagrees with IU sense data length %d, "
+				"using %d bytes of sense data\n", __func__,
+					urb->actual_length, len, newlen);
+			len = newlen;
+		}
+		memcpy(cmnd->sense_buffer, sense_iu->sense, len);
+	}
+
+	cmnd->result = sense_iu->status;
+}
+
+static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *prefix,
+			      int status)
+{
+	struct uas_cmd_info *ci = (void *)&cmnd->SCp;
+	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+
+	scmd_printk(KERN_INFO, cmnd,
+		    "%s %d uas-tag %d inflight:%s%s%s%s%s%s%s%s%s%s%s%s ",
+		    prefix, status, cmdinfo->uas_tag,
+		    (ci->state & SUBMIT_STATUS_URB)     ? " s-st"  : "",
+		    (ci->state & ALLOC_DATA_IN_URB)     ? " a-in"  : "",
+		    (ci->state & SUBMIT_DATA_IN_URB)    ? " s-in"  : "",
+		    (ci->state & ALLOC_DATA_OUT_URB)    ? " a-out" : "",
+		    (ci->state & SUBMIT_DATA_OUT_URB)   ? " s-out" : "",
+		    (ci->state & ALLOC_CMD_URB)         ? " a-cmd" : "",
+		    (ci->state & SUBMIT_CMD_URB)        ? " s-cmd" : "",
+		    (ci->state & COMMAND_INFLIGHT)      ? " CMD"   : "",
+		    (ci->state & DATA_IN_URB_INFLIGHT)  ? " IN"    : "",
+		    (ci->state & DATA_OUT_URB_INFLIGHT) ? " OUT"   : "",
+		    (ci->state & COMMAND_ABORTED)       ? " abort" : "",
+		    (ci->state & IS_IN_WORK_LIST)       ? " work"  : "");
+	scsi_print_command(cmnd);
+}
+
+static void uas_free_unsubmitted_urbs(struct scsi_cmnd *cmnd)
+{
+	struct uas_cmd_info *cmdinfo;
+
+	if (!cmnd)
+		return;
+
+	cmdinfo = (void *)&cmnd->SCp;
+
+	if (cmdinfo->state & SUBMIT_CMD_URB)
+		usb_free_urb(cmdinfo->cmd_urb);
+
+	/* data urbs may have never gotten their submit flag set */
+	if (!(cmdinfo->state & DATA_IN_URB_INFLIGHT))
+		usb_free_urb(cmdinfo->data_in_urb);
+	if (!(cmdinfo->state & DATA_OUT_URB_INFLIGHT))
+		usb_free_urb(cmdinfo->data_out_urb);
+}
+
+static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller)
+{
+	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
+
+	lockdep_assert_held(&devinfo->lock);
+	if (cmdinfo->state & (COMMAND_INFLIGHT |
+			      DATA_IN_URB_INFLIGHT |
+			      DATA_OUT_URB_INFLIGHT |
+			      COMMAND_ABORTED))
+		return -EBUSY;
+	devinfo->cmnd[cmdinfo->uas_tag - 1] = NULL;
+	uas_free_unsubmitted_urbs(cmnd);
+	cmnd->scsi_done(cmnd);
+	return 0;
+}
+
+static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
+			  unsigned direction)
+{
+	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+	int err;
+
+	cmdinfo->state |= direction | SUBMIT_STATUS_URB;
+	err = uas_submit_urbs(cmnd, cmnd->device->hostdata);
+	if (err) {
+		uas_add_work(cmdinfo);
+	}
+}
+
+static bool uas_evaluate_response_iu(struct response_iu *riu, struct scsi_cmnd *cmnd)
+{
+	u8 response_code = riu->response_code;
+
+	switch (response_code) {
+	case RC_INCORRECT_LUN:
+		cmnd->result = DID_BAD_TARGET << 16;
+		break;
+	case RC_TMF_SUCCEEDED:
+		cmnd->result = DID_OK << 16;
+		break;
+	case RC_TMF_NOT_SUPPORTED:
+		cmnd->result = DID_TARGET_FAILURE << 16;
+		break;
+	default:
+		uas_log_cmd_state(cmnd, "response iu", response_code);
+		cmnd->result = DID_ERROR << 16;
+		break;
+	}
+
+	return response_code == RC_TMF_SUCCEEDED;
+}
+
+static void uas_stat_cmplt(struct urb *urb)
+{
+	struct iu *iu = urb->transfer_buffer;
+	struct Scsi_Host *shost = urb->context;
+	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
+	struct urb *data_in_urb = NULL;
+	struct urb *data_out_urb = NULL;
+	struct scsi_cmnd *cmnd;
+	struct uas_cmd_info *cmdinfo;
+	unsigned long flags;
+	unsigned int idx;
+	int status = urb->status;
+	bool success;
+
+	spin_lock_irqsave(&devinfo->lock, flags);
+
+	if (devinfo->resetting)
+		goto out;
+
+	if (status) {
+		if (status != -ENOENT && status != -ECONNRESET && status != -ESHUTDOWN)
+			dev_err(&urb->dev->dev, "stat urb: status %d\n", status);
+		goto out;
+	}
+
+	idx = be16_to_cpup(&iu->tag) - 1;
+	if (idx >= MAX_CMNDS || !devinfo->cmnd[idx]) {
+		dev_err(&urb->dev->dev,
+			"stat urb: no pending cmd for uas-tag %d\n", idx + 1);
+		goto out;
+	}
+
+	cmnd = devinfo->cmnd[idx];
+	cmdinfo = (void *)&cmnd->SCp;
+
+	if (!(cmdinfo->state & COMMAND_INFLIGHT)) {
+		uas_log_cmd_state(cmnd, "unexpected status cmplt", 0);
+		goto out;
+	}
+
+	switch (iu->iu_id) {
+	case IU_ID_STATUS:
+		uas_sense(urb, cmnd);
+		if (cmnd->result != 0) {
+			/* cancel data transfers on error */
+			data_in_urb = usb_get_urb(cmdinfo->data_in_urb);
+			data_out_urb = usb_get_urb(cmdinfo->data_out_urb);
+		}
+		cmdinfo->state &= ~COMMAND_INFLIGHT;
+		uas_try_complete(cmnd, __func__);
+		break;
+	case IU_ID_READ_READY:
+		if (!cmdinfo->data_in_urb ||
+				(cmdinfo->state & DATA_IN_URB_INFLIGHT)) {
+			uas_log_cmd_state(cmnd, "unexpected read rdy", 0);
+			break;
+		}
+		uas_xfer_data(urb, cmnd, SUBMIT_DATA_IN_URB);
+		break;
+	case IU_ID_WRITE_READY:
+		if (!cmdinfo->data_out_urb ||
+				(cmdinfo->state & DATA_OUT_URB_INFLIGHT)) {
+			uas_log_cmd_state(cmnd, "unexpected write rdy", 0);
+			break;
+		}
+		uas_xfer_data(urb, cmnd, SUBMIT_DATA_OUT_URB);
+		break;
+	case IU_ID_RESPONSE:
+		cmdinfo->state &= ~COMMAND_INFLIGHT;
+		success = uas_evaluate_response_iu((struct response_iu *)iu, cmnd);
+		if (!success) {
+			/* Error, cancel data transfers */
+			data_in_urb = usb_get_urb(cmdinfo->data_in_urb);
+			data_out_urb = usb_get_urb(cmdinfo->data_out_urb);
+		}
+		uas_try_complete(cmnd, __func__);
+		break;
+	default:
+		uas_log_cmd_state(cmnd, "bogus IU", iu->iu_id);
+	}
+out:
+	usb_free_urb(urb);
+	spin_unlock_irqrestore(&devinfo->lock, flags);
+
+	/* Unlinking of data urbs must be done without holding the lock */
+	if (data_in_urb) {
+		usb_unlink_urb(data_in_urb);
+		usb_put_urb(data_in_urb);
+	}
+	if (data_out_urb) {
+		usb_unlink_urb(data_out_urb);
+		usb_put_urb(data_out_urb);
+	}
+}
+
+static void uas_data_cmplt(struct urb *urb)
+{
+	struct scsi_cmnd *cmnd = urb->context;
+	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
+	struct scsi_data_buffer *sdb = NULL;
+	unsigned long flags;
+	int status = urb->status;
+
+	spin_lock_irqsave(&devinfo->lock, flags);
+
+	if (cmdinfo->data_in_urb == urb) {
+		sdb = scsi_in(cmnd);
+		cmdinfo->state &= ~DATA_IN_URB_INFLIGHT;
+		cmdinfo->data_in_urb = NULL;
+	} else if (cmdinfo->data_out_urb == urb) {
+		sdb = scsi_out(cmnd);
+		cmdinfo->state &= ~DATA_OUT_URB_INFLIGHT;
+		cmdinfo->data_out_urb = NULL;
+	}
+	if (sdb == NULL) {
+		WARN_ON_ONCE(1);
+		goto out;
+	}
+
+	if (devinfo->resetting)
+		goto out;
+
+	/* Data urbs should not complete before the cmd urb is submitted */
+	if (cmdinfo->state & SUBMIT_CMD_URB) {
+		uas_log_cmd_state(cmnd, "unexpected data cmplt", 0);
+		goto out;
+	}
+
+	if (status) {
+		if (status != -ENOENT && status != -ECONNRESET && status != -ESHUTDOWN)
+			uas_log_cmd_state(cmnd, "data cmplt err", status);
+		/* error: no data transfered */
+		sdb->resid = sdb->length;
+	} else {
+		sdb->resid = sdb->length - urb->actual_length;
+	}
+	uas_try_complete(cmnd, __func__);
+out:
+	usb_free_urb(urb);
+	spin_unlock_irqrestore(&devinfo->lock, flags);
+}
+
+static void uas_cmd_cmplt(struct urb *urb)
+{
+	if (urb->status)
+		dev_err(&urb->dev->dev, "cmd cmplt err %d\n", urb->status);
+
+	usb_free_urb(urb);
+}
+
+static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
+				      struct scsi_cmnd *cmnd,
+				      enum dma_data_direction dir)
+{
+	struct usb_device *udev = devinfo->udev;
+	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+	struct urb *urb = usb_alloc_urb(0, gfp);
+	struct scsi_data_buffer *sdb = (dir == DMA_FROM_DEVICE)
+		? scsi_in(cmnd) : scsi_out(cmnd);
+	unsigned int pipe = (dir == DMA_FROM_DEVICE)
+		? devinfo->data_in_pipe : devinfo->data_out_pipe;
+
+	if (!urb)
+		goto out;
+	usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length,
+			  uas_data_cmplt, cmnd);
+	if (devinfo->use_streams)
+		urb->stream_id = cmdinfo->uas_tag;
+	urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0;
+	urb->sg = sdb->table.sgl;
+ out:
+	return urb;
+}
+
+static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp,
+				       struct scsi_cmnd *cmnd)
+{
+	struct usb_device *udev = devinfo->udev;
+	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+	struct urb *urb = usb_alloc_urb(0, gfp);
+	struct sense_iu *iu;
+
+	if (!urb)
+		goto out;
+
+	iu = kzalloc(sizeof(*iu), gfp);
+	if (!iu)
+		goto free;
+
+	usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu),
+			  uas_stat_cmplt, cmnd->device->host);
+	if (devinfo->use_streams)
+		urb->stream_id = cmdinfo->uas_tag;
+	urb->transfer_flags |= URB_FREE_BUFFER;
+ out:
+	return urb;
+ free:
+	usb_free_urb(urb);
+	return NULL;
+}
+
+static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp,
+					struct scsi_cmnd *cmnd)
+{
+	struct usb_device *udev = devinfo->udev;
+	struct scsi_device *sdev = cmnd->device;
+	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+	struct urb *urb = usb_alloc_urb(0, gfp);
+	struct command_iu *iu;
+	int len;
+
+	if (!urb)
+		goto out;
+
+	len = cmnd->cmd_len - 16;
+	if (len < 0)
+		len = 0;
+	len = ALIGN(len, 4);
+	iu = kzalloc(sizeof(*iu) + len, gfp);
+	if (!iu)
+		goto free;
+
+	iu->iu_id = IU_ID_COMMAND;
+	iu->tag = cpu_to_be16(cmdinfo->uas_tag);
+	iu->prio_attr = UAS_SIMPLE_TAG;
+	iu->len = len;
+	int_to_scsilun(sdev->lun, &iu->lun);
+	memcpy(iu->cdb, cmnd->cmnd, cmnd->cmd_len);
+
+	usb_fill_bulk_urb(urb, udev, devinfo->cmd_pipe, iu, sizeof(*iu) + len,
+							uas_cmd_cmplt, NULL);
+	urb->transfer_flags |= URB_FREE_BUFFER;
+ out:
+	return urb;
+ free:
+	usb_free_urb(urb);
+	return NULL;
+}
+
+/*
+ * Why should I request the Status IU before sending the Command IU?  Spec
+ * says to, but also says the device may receive them in any order.  Seems
+ * daft to me.
+ */
+
+static struct urb *uas_submit_sense_urb(struct scsi_cmnd *cmnd, gfp_t gfp)
+{
+	struct uas_dev_info *devinfo = cmnd->device->hostdata;
+	struct urb *urb;
+	int err;
+
+	urb = uas_alloc_sense_urb(devinfo, gfp, cmnd);
+	if (!urb)
+		return NULL;
+	usb_anchor_urb(urb, &devinfo->sense_urbs);
+	err = usb_submit_urb(urb, gfp);
+	if (err) {
+		usb_unanchor_urb(urb);
+		uas_log_cmd_state(cmnd, "sense submit err", err);
+		usb_free_urb(urb);
+		return NULL;
+	}
+	return urb;
+}
+
+static int uas_submit_urbs(struct scsi_cmnd *cmnd,
+			   struct uas_dev_info *devinfo)
+{
+	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+	struct urb *urb;
+	int err;
+
+	lockdep_assert_held(&devinfo->lock);
+	if (cmdinfo->state & SUBMIT_STATUS_URB) {
+		urb = uas_submit_sense_urb(cmnd, GFP_ATOMIC);
+		if (!urb)
+			return SCSI_MLQUEUE_DEVICE_BUSY;
+		cmdinfo->state &= ~SUBMIT_STATUS_URB;
+	}
+
+	if (cmdinfo->state & ALLOC_DATA_IN_URB) {
+		cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, GFP_ATOMIC,
+							cmnd, DMA_FROM_DEVICE);
+		if (!cmdinfo->data_in_urb)
+			return SCSI_MLQUEUE_DEVICE_BUSY;
+		cmdinfo->state &= ~ALLOC_DATA_IN_URB;
+	}
+
+	if (cmdinfo->state & SUBMIT_DATA_IN_URB) {
+		usb_anchor_urb(cmdinfo->data_in_urb, &devinfo->data_urbs);
+		err = usb_submit_urb(cmdinfo->data_in_urb, GFP_ATOMIC);
+		if (err) {
+			usb_unanchor_urb(cmdinfo->data_in_urb);
+			uas_log_cmd_state(cmnd, "data in submit err", err);
+			return SCSI_MLQUEUE_DEVICE_BUSY;
+		}
+		cmdinfo->state &= ~SUBMIT_DATA_IN_URB;
+		cmdinfo->state |= DATA_IN_URB_INFLIGHT;
+	}
+
+	if (cmdinfo->state & ALLOC_DATA_OUT_URB) {
+		cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, GFP_ATOMIC,
+							cmnd, DMA_TO_DEVICE);
+		if (!cmdinfo->data_out_urb)
+			return SCSI_MLQUEUE_DEVICE_BUSY;
+		cmdinfo->state &= ~ALLOC_DATA_OUT_URB;
+	}
+
+	if (cmdinfo->state & SUBMIT_DATA_OUT_URB) {
+		usb_anchor_urb(cmdinfo->data_out_urb, &devinfo->data_urbs);
+		err = usb_submit_urb(cmdinfo->data_out_urb, GFP_ATOMIC);
+		if (err) {
+			usb_unanchor_urb(cmdinfo->data_out_urb);
+			uas_log_cmd_state(cmnd, "data out submit err", err);
+			return SCSI_MLQUEUE_DEVICE_BUSY;
+		}
+		cmdinfo->state &= ~SUBMIT_DATA_OUT_URB;
+		cmdinfo->state |= DATA_OUT_URB_INFLIGHT;
+	}
+
+	if (cmdinfo->state & ALLOC_CMD_URB) {
+		cmdinfo->cmd_urb = uas_alloc_cmd_urb(devinfo, GFP_ATOMIC, cmnd);
+		if (!cmdinfo->cmd_urb)
+			return SCSI_MLQUEUE_DEVICE_BUSY;
+		cmdinfo->state &= ~ALLOC_CMD_URB;
+	}
+
+	if (cmdinfo->state & SUBMIT_CMD_URB) {
+		usb_anchor_urb(cmdinfo->cmd_urb, &devinfo->cmd_urbs);
+		err = usb_submit_urb(cmdinfo->cmd_urb, GFP_ATOMIC);
+		if (err) {
+			usb_unanchor_urb(cmdinfo->cmd_urb);
+			uas_log_cmd_state(cmnd, "cmd submit err", err);
+			return SCSI_MLQUEUE_DEVICE_BUSY;
+		}
+		cmdinfo->cmd_urb = NULL;
+		cmdinfo->state &= ~SUBMIT_CMD_URB;
+		cmdinfo->state |= COMMAND_INFLIGHT;
+	}
+
+	return 0;
+}
+
+static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
+					void (*done)(struct scsi_cmnd *))
+{
+	struct scsi_device *sdev = cmnd->device;
+	struct uas_dev_info *devinfo = sdev->hostdata;
+	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+	unsigned long flags;
+	int idx, err;
+
+	BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer));
+
+	/* Re-check scsi_block_requests now that we've the host-lock */
+	if (cmnd->device->host->host_self_blocked)
+		return SCSI_MLQUEUE_DEVICE_BUSY;
+
+	if ((devinfo->flags & US_FL_NO_ATA_1X) &&
+			(cmnd->cmnd[0] == ATA_12 || cmnd->cmnd[0] == ATA_16)) {
+		memcpy(cmnd->sense_buffer, usb_stor_sense_invalidCDB,
+		       sizeof(usb_stor_sense_invalidCDB));
+		cmnd->result = SAM_STAT_CHECK_CONDITION;
+		cmnd->scsi_done(cmnd);
+		return 0;
+	}
+
+	spin_lock_irqsave(&devinfo->lock, flags);
+
+	if (devinfo->resetting) {
+		cmnd->result = DID_ERROR << 16;
+		cmnd->scsi_done(cmnd);
+		spin_unlock_irqrestore(&devinfo->lock, flags);
+		return 0;
+	}
+
+	/* Find a free uas-tag */
+	for (idx = 0; idx < devinfo->qdepth; idx++) {
+		if (!devinfo->cmnd[idx])
+			break;
+	}
+	if (idx == devinfo->qdepth) {
+		spin_unlock_irqrestore(&devinfo->lock, flags);
+		return SCSI_MLQUEUE_DEVICE_BUSY;
+	}
+
+	cmnd->scsi_done = done;
+
+	memset(cmdinfo, 0, sizeof(*cmdinfo));
+	cmdinfo->uas_tag = idx + 1; /* uas-tag == usb-stream-id, so 1 based */
+	cmdinfo->state = SUBMIT_STATUS_URB | ALLOC_CMD_URB | SUBMIT_CMD_URB;
+
+	switch (cmnd->sc_data_direction) {
+	case DMA_FROM_DEVICE:
+		cmdinfo->state |= ALLOC_DATA_IN_URB | SUBMIT_DATA_IN_URB;
+		break;
+	case DMA_BIDIRECTIONAL:
+		cmdinfo->state |= ALLOC_DATA_IN_URB | SUBMIT_DATA_IN_URB;
+		/* fall through */
+	case DMA_TO_DEVICE:
+		cmdinfo->state |= ALLOC_DATA_OUT_URB | SUBMIT_DATA_OUT_URB;
+	case DMA_NONE:
+		break;
+	}
+
+	if (!devinfo->use_streams)
+		cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB);
+
+	err = uas_submit_urbs(cmnd, devinfo);
+	if (err) {
+		/* If we did nothing, give up now */
+		if (cmdinfo->state & SUBMIT_STATUS_URB) {
+			spin_unlock_irqrestore(&devinfo->lock, flags);
+			return SCSI_MLQUEUE_DEVICE_BUSY;
+		}
+		uas_add_work(cmdinfo);
+	}
+
+	devinfo->cmnd[idx] = cmnd;
+	spin_unlock_irqrestore(&devinfo->lock, flags);
+	return 0;
+}
+
+static DEF_SCSI_QCMD(uas_queuecommand)
+
+/*
+ * For now we do not support actually sending an abort to the device, so
+ * this eh always fails. Still we must define it to make sure that we've
+ * dropped all references to the cmnd in question once this function exits.
+ */
+static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
+{
+	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
+	struct urb *data_in_urb = NULL;
+	struct urb *data_out_urb = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&devinfo->lock, flags);
+
+	uas_log_cmd_state(cmnd, __func__, 0);
+
+	/* Ensure that try_complete does not call scsi_done */
+	cmdinfo->state |= COMMAND_ABORTED;
+
+	/* Drop all refs to this cmnd, kill data urbs to break their ref */
+	devinfo->cmnd[cmdinfo->uas_tag - 1] = NULL;
+	if (cmdinfo->state & DATA_IN_URB_INFLIGHT)
+		data_in_urb = usb_get_urb(cmdinfo->data_in_urb);
+	if (cmdinfo->state & DATA_OUT_URB_INFLIGHT)
+		data_out_urb = usb_get_urb(cmdinfo->data_out_urb);
+
+	uas_free_unsubmitted_urbs(cmnd);
+
+	spin_unlock_irqrestore(&devinfo->lock, flags);
+
+	if (data_in_urb) {
+		usb_kill_urb(data_in_urb);
+		usb_put_urb(data_in_urb);
+	}
+	if (data_out_urb) {
+		usb_kill_urb(data_out_urb);
+		usb_put_urb(data_out_urb);
+	}
+
+	return FAILED;
+}
+
+static int uas_eh_device_reset_handler(struct scsi_cmnd *cmnd)
+{
+	struct scsi_device *sdev = cmnd->device;
+	struct uas_dev_info *devinfo = sdev->hostdata;
+	struct usb_device *udev = devinfo->udev;
+	unsigned long flags;
+	int err;
+
+	err = usb_lock_device_for_reset(udev, devinfo->intf);
+	if (err) {
+		shost_printk(KERN_ERR, sdev->host,
+			     "%s FAILED to get lock err %d\n", __func__, err);
+		return FAILED;
+	}
+
+	shost_printk(KERN_INFO, sdev->host, "%s start\n", __func__);
+
+	spin_lock_irqsave(&devinfo->lock, flags);
+	devinfo->resetting = 1;
+	spin_unlock_irqrestore(&devinfo->lock, flags);
+
+	usb_kill_anchored_urbs(&devinfo->cmd_urbs);
+	usb_kill_anchored_urbs(&devinfo->sense_urbs);
+	usb_kill_anchored_urbs(&devinfo->data_urbs);
+	uas_zap_pending(devinfo, DID_RESET);
+
+	err = usb_reset_device(udev);
+
+	spin_lock_irqsave(&devinfo->lock, flags);
+	devinfo->resetting = 0;
+	spin_unlock_irqrestore(&devinfo->lock, flags);
+
+	usb_unlock_device(udev);
+
+	if (err) {
+		shost_printk(KERN_INFO, sdev->host, "%s FAILED err %d\n",
+			     __func__, err);
+		return FAILED;
+	}
+
+	shost_printk(KERN_INFO, sdev->host, "%s success\n", __func__);
+	return SUCCESS;
+}
+
+static int uas_target_alloc(struct scsi_target *starget)
+{
+	struct uas_dev_info *devinfo = (struct uas_dev_info *)
+			dev_to_shost(starget->dev.parent)->hostdata;
+
+	if (devinfo->flags & US_FL_NO_REPORT_LUNS)
+		starget->no_report_luns = 1;
+
+	return 0;
+}
+
+static int uas_slave_alloc(struct scsi_device *sdev)
+{
+	struct uas_dev_info *devinfo =
+		(struct uas_dev_info *)sdev->host->hostdata;
+
+	sdev->hostdata = devinfo;
+
+	/*
+	 * USB has unusual DMA-alignment requirements: Although the
+	 * starting address of each scatter-gather element doesn't matter,
+	 * the length of each element except the last must be divisible
+	 * by the Bulk maxpacket value.  There's currently no way to
+	 * express this by block-layer constraints, so we'll cop out
+	 * and simply require addresses to be aligned at 512-byte
+	 * boundaries.  This is okay since most block I/O involves
+	 * hardware sectors that are multiples of 512 bytes in length,
+	 * and since host controllers up through USB 2.0 have maxpacket
+	 * values no larger than 512.
+	 *
+	 * But it doesn't suffice for Wireless USB, where Bulk maxpacket
+	 * values can be as large as 2048.  To make that work properly
+	 * will require changes to the block layer.
+	 */
+	blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1));
+
+	if (devinfo->flags & US_FL_MAX_SECTORS_64)
+		blk_queue_max_hw_sectors(sdev->request_queue, 64);
+	else if (devinfo->flags & US_FL_MAX_SECTORS_240)
+		blk_queue_max_hw_sectors(sdev->request_queue, 240);
+
+	return 0;
+}
+
+static int uas_slave_configure(struct scsi_device *sdev)
+{
+	struct uas_dev_info *devinfo = sdev->hostdata;
+
+	if (devinfo->flags & US_FL_NO_REPORT_OPCODES)
+		sdev->no_report_opcodes = 1;
+
+	/* A few buggy USB-ATA bridges don't understand FUA */
+	if (devinfo->flags & US_FL_BROKEN_FUA)
+		sdev->broken_fua = 1;
+
+	/* UAS also needs to support FL_ALWAYS_SYNC */
+	if (devinfo->flags & US_FL_ALWAYS_SYNC) {
+		sdev->skip_ms_page_3f = 1;
+		sdev->skip_ms_page_8 = 1;
+		sdev->wce_default_on = 1;
+	}
+
+	/*
+	 * Some disks return the total number of blocks in response
+	 * to READ CAPACITY rather than the highest block number.
+	 * If this device makes that mistake, tell the sd driver.
+	 */
+	if (devinfo->flags & US_FL_FIX_CAPACITY)
+		sdev->fix_capacity = 1;
+
+	/*
+	 * Some devices don't like MODE SENSE with page=0x3f,
+	 * which is the command used for checking if a device
+	 * is write-protected.  Now that we tell the sd driver
+	 * to do a 192-byte transfer with this command the
+	 * majority of devices work fine, but a few still can't
+	 * handle it.  The sd driver will simply assume those
+	 * devices are write-enabled.
+	 */
+	if (devinfo->flags & US_FL_NO_WP_DETECT)
+		sdev->skip_ms_page_3f = 1;
+
+	scsi_change_queue_depth(sdev, devinfo->qdepth - 2);
+	return 0;
+}
+
+static struct scsi_host_template uas_host_template = {
+	.module = THIS_MODULE,
+	.name = "uas",
+	.queuecommand = uas_queuecommand,
+	.target_alloc = uas_target_alloc,
+	.slave_alloc = uas_slave_alloc,
+	.slave_configure = uas_slave_configure,
+	.eh_abort_handler = uas_eh_abort_handler,
+	.eh_device_reset_handler = uas_eh_device_reset_handler,
+	.this_id = -1,
+	.sg_tablesize = SG_NONE,
+	.skip_settle_delay = 1,
+};
+
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+		    vendorName, productName, useProtocol, useTransport, \
+		    initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+	.driver_info = (flags) }
+
+static struct usb_device_id uas_usb_ids[] = {
+#	include "unusual_uas.h"
+	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_BULK) },
+	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_UAS) },
+	{ }
+};
+MODULE_DEVICE_TABLE(usb, uas_usb_ids);
+
+#undef UNUSUAL_DEV
+
+static int uas_switch_interface(struct usb_device *udev,
+				struct usb_interface *intf)
+{
+	struct usb_host_interface *alt;
+
+	alt = uas_find_uas_alt_setting(intf);
+	if (!alt)
+		return -ENODEV;
+
+	return usb_set_interface(udev, alt->desc.bInterfaceNumber,
+			alt->desc.bAlternateSetting);
+}
+
+static int uas_configure_endpoints(struct uas_dev_info *devinfo)
+{
+	struct usb_host_endpoint *eps[4] = { };
+	struct usb_device *udev = devinfo->udev;
+	int r;
+
+	r = uas_find_endpoints(devinfo->intf->cur_altsetting, eps);
+	if (r)
+		return r;
+
+	devinfo->cmd_pipe = usb_sndbulkpipe(udev,
+					    usb_endpoint_num(&eps[0]->desc));
+	devinfo->status_pipe = usb_rcvbulkpipe(udev,
+					    usb_endpoint_num(&eps[1]->desc));
+	devinfo->data_in_pipe = usb_rcvbulkpipe(udev,
+					    usb_endpoint_num(&eps[2]->desc));
+	devinfo->data_out_pipe = usb_sndbulkpipe(udev,
+					    usb_endpoint_num(&eps[3]->desc));
+
+	if (udev->speed < USB_SPEED_SUPER) {
+		devinfo->qdepth = 32;
+		devinfo->use_streams = 0;
+	} else {
+		devinfo->qdepth = usb_alloc_streams(devinfo->intf, eps + 1,
+						    3, MAX_CMNDS, GFP_NOIO);
+		if (devinfo->qdepth < 0)
+			return devinfo->qdepth;
+		devinfo->use_streams = 1;
+	}
+
+	return 0;
+}
+
+static void uas_free_streams(struct uas_dev_info *devinfo)
+{
+	struct usb_device *udev = devinfo->udev;
+	struct usb_host_endpoint *eps[3];
+
+	eps[0] = usb_pipe_endpoint(udev, devinfo->status_pipe);
+	eps[1] = usb_pipe_endpoint(udev, devinfo->data_in_pipe);
+	eps[2] = usb_pipe_endpoint(udev, devinfo->data_out_pipe);
+	usb_free_streams(devinfo->intf, eps, 3, GFP_NOIO);
+}
+
+static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	int result = -ENOMEM;
+	struct Scsi_Host *shost = NULL;
+	struct uas_dev_info *devinfo;
+	struct usb_device *udev = interface_to_usbdev(intf);
+	unsigned long dev_flags;
+
+	if (!uas_use_uas_driver(intf, id, &dev_flags))
+		return -ENODEV;
+
+	if (uas_switch_interface(udev, intf))
+		return -ENODEV;
+
+	shost = scsi_host_alloc(&uas_host_template,
+				sizeof(struct uas_dev_info));
+	if (!shost)
+		goto set_alt0;
+
+	shost->max_cmd_len = 16 + 252;
+	shost->max_id = 1;
+	shost->max_lun = 256;
+	shost->max_channel = 0;
+	shost->sg_tablesize = udev->bus->sg_tablesize;
+
+	devinfo = (struct uas_dev_info *)shost->hostdata;
+	devinfo->intf = intf;
+	devinfo->udev = udev;
+	devinfo->resetting = 0;
+	devinfo->shutdown = 0;
+	devinfo->flags = dev_flags;
+	init_usb_anchor(&devinfo->cmd_urbs);
+	init_usb_anchor(&devinfo->sense_urbs);
+	init_usb_anchor(&devinfo->data_urbs);
+	spin_lock_init(&devinfo->lock);
+	INIT_WORK(&devinfo->work, uas_do_work);
+
+	result = uas_configure_endpoints(devinfo);
+	if (result)
+		goto set_alt0;
+
+	/*
+	 * 1 tag is reserved for untagged commands +
+	 * 1 tag to avoid off by one errors in some bridge firmwares
+	 */
+	shost->can_queue = devinfo->qdepth - 2;
+
+	usb_set_intfdata(intf, shost);
+	result = scsi_add_host(shost, &intf->dev);
+	if (result)
+		goto free_streams;
+
+	scsi_scan_host(shost);
+	return result;
+
+free_streams:
+	uas_free_streams(devinfo);
+	usb_set_intfdata(intf, NULL);
+set_alt0:
+	usb_set_interface(udev, intf->altsetting[0].desc.bInterfaceNumber, 0);
+	if (shost)
+		scsi_host_put(shost);
+	return result;
+}
+
+static int uas_cmnd_list_empty(struct uas_dev_info *devinfo)
+{
+	unsigned long flags;
+	int i, r = 1;
+
+	spin_lock_irqsave(&devinfo->lock, flags);
+
+	for (i = 0; i < devinfo->qdepth; i++) {
+		if (devinfo->cmnd[i]) {
+			r = 0; /* Not empty */
+			break;
+		}
+	}
+
+	spin_unlock_irqrestore(&devinfo->lock, flags);
+
+	return r;
+}
+
+/*
+ * Wait for any pending cmnds to complete, on usb-2 sense_urbs may temporarily
+ * get empty while there still is more work to do due to sense-urbs completing
+ * with a READ/WRITE_READY iu code, so keep waiting until the list gets empty.
+ */
+static int uas_wait_for_pending_cmnds(struct uas_dev_info *devinfo)
+{
+	unsigned long start_time;
+	int r;
+
+	start_time = jiffies;
+	do {
+		flush_work(&devinfo->work);
+
+		r = usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 5000);
+		if (r == 0)
+			return -ETIME;
+
+		r = usb_wait_anchor_empty_timeout(&devinfo->data_urbs, 500);
+		if (r == 0)
+			return -ETIME;
+
+		if (time_after(jiffies, start_time + 5 * HZ))
+			return -ETIME;
+	} while (!uas_cmnd_list_empty(devinfo));
+
+	return 0;
+}
+
+static int uas_pre_reset(struct usb_interface *intf)
+{
+	struct Scsi_Host *shost = usb_get_intfdata(intf);
+	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
+	unsigned long flags;
+
+	if (devinfo->shutdown)
+		return 0;
+
+	/* Block new requests */
+	spin_lock_irqsave(shost->host_lock, flags);
+	scsi_block_requests(shost);
+	spin_unlock_irqrestore(shost->host_lock, flags);
+
+	if (uas_wait_for_pending_cmnds(devinfo) != 0) {
+		shost_printk(KERN_ERR, shost, "%s: timed out\n", __func__);
+		scsi_unblock_requests(shost);
+		return 1;
+	}
+
+	uas_free_streams(devinfo);
+
+	return 0;
+}
+
+static int uas_post_reset(struct usb_interface *intf)
+{
+	struct Scsi_Host *shost = usb_get_intfdata(intf);
+	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
+	unsigned long flags;
+	int err;
+
+	if (devinfo->shutdown)
+		return 0;
+
+	err = uas_configure_endpoints(devinfo);
+	if (err && err != -ENODEV)
+		shost_printk(KERN_ERR, shost,
+			     "%s: alloc streams error %d after reset",
+			     __func__, err);
+
+	/* we must unblock the host in every case lest we deadlock */
+	spin_lock_irqsave(shost->host_lock, flags);
+	scsi_report_bus_reset(shost, 0);
+	spin_unlock_irqrestore(shost->host_lock, flags);
+
+	scsi_unblock_requests(shost);
+
+	return err ? 1 : 0;
+}
+
+static int uas_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct Scsi_Host *shost = usb_get_intfdata(intf);
+	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
+
+	if (uas_wait_for_pending_cmnds(devinfo) != 0) {
+		shost_printk(KERN_ERR, shost, "%s: timed out\n", __func__);
+		return -ETIME;
+	}
+
+	return 0;
+}
+
+static int uas_resume(struct usb_interface *intf)
+{
+	return 0;
+}
+
+static int uas_reset_resume(struct usb_interface *intf)
+{
+	struct Scsi_Host *shost = usb_get_intfdata(intf);
+	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
+	unsigned long flags;
+	int err;
+
+	err = uas_configure_endpoints(devinfo);
+	if (err) {
+		shost_printk(KERN_ERR, shost,
+			     "%s: alloc streams error %d after reset",
+			     __func__, err);
+		return -EIO;
+	}
+
+	spin_lock_irqsave(shost->host_lock, flags);
+	scsi_report_bus_reset(shost, 0);
+	spin_unlock_irqrestore(shost->host_lock, flags);
+
+	return 0;
+}
+
+static void uas_disconnect(struct usb_interface *intf)
+{
+	struct Scsi_Host *shost = usb_get_intfdata(intf);
+	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
+	unsigned long flags;
+
+	spin_lock_irqsave(&devinfo->lock, flags);
+	devinfo->resetting = 1;
+	spin_unlock_irqrestore(&devinfo->lock, flags);
+
+	cancel_work_sync(&devinfo->work);
+	usb_kill_anchored_urbs(&devinfo->cmd_urbs);
+	usb_kill_anchored_urbs(&devinfo->sense_urbs);
+	usb_kill_anchored_urbs(&devinfo->data_urbs);
+	uas_zap_pending(devinfo, DID_NO_CONNECT);
+
+	scsi_remove_host(shost);
+	uas_free_streams(devinfo);
+	scsi_host_put(shost);
+}
+
+/*
+ * Put the device back in usb-storage mode on shutdown, as some BIOS-es
+ * hang on reboot when the device is still in uas mode. Note the reset is
+ * necessary as some devices won't revert to usb-storage mode without it.
+ */
+static void uas_shutdown(struct device *dev)
+{
+	struct usb_interface *intf = to_usb_interface(dev);
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct Scsi_Host *shost = usb_get_intfdata(intf);
+	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
+
+	if (system_state != SYSTEM_RESTART)
+		return;
+
+	devinfo->shutdown = 1;
+	uas_free_streams(devinfo);
+	usb_set_interface(udev, intf->altsetting[0].desc.bInterfaceNumber, 0);
+	usb_reset_device(udev);
+}
+
+static struct usb_driver uas_driver = {
+	.name = "uas",
+	.probe = uas_probe,
+	.disconnect = uas_disconnect,
+	.pre_reset = uas_pre_reset,
+	.post_reset = uas_post_reset,
+	.suspend = uas_suspend,
+	.resume = uas_resume,
+	.reset_resume = uas_reset_resume,
+	.drvwrap.driver.shutdown = uas_shutdown,
+	.id_table = uas_usb_ids,
+};
+
+module_usb_driver(uas_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR(
+	"Hans de Goede <hdegoede@redhat.com>, Matthew Wilcox and Sarah Sharp");
diff --git a/drivers/usb/storage/unusual_alauda.h b/drivers/usb/storage/unusual_alauda.h
new file mode 100644
index 0000000..0ec8c99
--- /dev/null
+++ b/drivers/usb/storage/unusual_alauda.h
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Unusual Devices File for the Alauda-based card readers
+ */
+
+#if defined(CONFIG_USB_STORAGE_ALAUDA) || \
+		defined(CONFIG_USB_STORAGE_ALAUDA_MODULE)
+
+UNUSUAL_DEV(  0x0584, 0x0008, 0x0102, 0x0102,
+		"Fujifilm",
+		"DPC-R1 (Alauda)",
+		USB_SC_SCSI, USB_PR_ALAUDA, init_alauda, 0),
+
+UNUSUAL_DEV(  0x07b4, 0x010a, 0x0102, 0x0102,
+		"Olympus",
+		"MAUSB-10 (Alauda)",
+		USB_SC_SCSI, USB_PR_ALAUDA, init_alauda, 0),
+
+#endif /* defined(CONFIG_USB_STORAGE_ALAUDA) || ... */
diff --git a/drivers/usb/storage/unusual_cypress.h b/drivers/usb/storage/unusual_cypress.h
new file mode 100644
index 0000000..fb99e52
--- /dev/null
+++ b/drivers/usb/storage/unusual_cypress.h
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Unusual Devices File for devices based on the Cypress USB/ATA bridge
+ *	with support for ATACB
+ */
+
+#if defined(CONFIG_USB_STORAGE_CYPRESS_ATACB) || \
+		defined(CONFIG_USB_STORAGE_CYPRESS_ATACB_MODULE)
+
+/* CY7C68300 : support atacb */
+UNUSUAL_DEV(  0x04b4, 0x6830, 0x0000, 0x9999,
+		"Cypress",
+		"Cypress AT2LP",
+		USB_SC_CYP_ATACB, USB_PR_DEVICE, NULL, 0),
+
+/* CY7C68310 : support atacb and atacb2 */
+UNUSUAL_DEV(  0x04b4, 0x6831, 0x0000, 0x9999,
+		"Cypress",
+		"Cypress ISD-300LP",
+		USB_SC_CYP_ATACB, USB_PR_DEVICE, NULL, 0),
+
+UNUSUAL_DEV( 0x14cd, 0x6116, 0x0160, 0x0160,
+		"Super Top",
+		"USB 2.0  SATA BRIDGE",
+		USB_SC_CYP_ATACB, USB_PR_DEVICE, NULL, 0),
+
+#endif /* defined(CONFIG_USB_STORAGE_CYPRESS_ATACB) || ... */
diff --git a/drivers/usb/storage/unusual_datafab.h b/drivers/usb/storage/unusual_datafab.h
new file mode 100644
index 0000000..fdab5e7
--- /dev/null
+++ b/drivers/usb/storage/unusual_datafab.h
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Unusual Devices File for the Datafab USB Compact Flash reader
+ */
+
+#if defined(CONFIG_USB_STORAGE_DATAFAB) || \
+		defined(CONFIG_USB_STORAGE_DATAFAB_MODULE)
+
+UNUSUAL_DEV(  0x07c4, 0xa000, 0x0000, 0x0015,
+		"Datafab",
+		"MDCFE-B USB CF Reader",
+		USB_SC_SCSI, USB_PR_DATAFAB, NULL,
+		0),
+
+/*
+ * The following Datafab-based devices may or may not work
+ * using the current driver...the 0xffff is arbitrary since I
+ * don't know what device versions exist for these guys.
+ *
+ * The 0xa003 and 0xa004 devices in particular I'm curious about.
+ * I'm told they exist but so far nobody has come forward to say that
+ * they work with this driver.  Given the success we've had getting
+ * other Datafab-based cards operational with this driver, I've decided
+ * to leave these two devices in the list.
+ */
+UNUSUAL_DEV( 0x07c4, 0xa001, 0x0000, 0xffff,
+		"SIIG/Datafab",
+		"SIIG/Datafab Memory Stick+CF Reader/Writer",
+		USB_SC_SCSI, USB_PR_DATAFAB, NULL,
+		0),
+
+/* Reported by Josef Reisinger <josef.reisinger@netcologne.de> */
+UNUSUAL_DEV( 0x07c4, 0xa002, 0x0000, 0xffff,
+		"Datafab/Unknown",
+		"MD2/MD3 Disk enclosure",
+		USB_SC_SCSI, USB_PR_DATAFAB, NULL,
+		US_FL_SINGLE_LUN),
+
+UNUSUAL_DEV( 0x07c4, 0xa003, 0x0000, 0xffff,
+		"Datafab/Unknown",
+		"Datafab-based Reader",
+		USB_SC_SCSI, USB_PR_DATAFAB, NULL,
+		0),
+
+UNUSUAL_DEV( 0x07c4, 0xa004, 0x0000, 0xffff,
+		"Datafab/Unknown",
+		"Datafab-based Reader",
+		USB_SC_SCSI, USB_PR_DATAFAB, NULL,
+		0),
+
+UNUSUAL_DEV( 0x07c4, 0xa005, 0x0000, 0xffff,
+		"PNY/Datafab",
+		"PNY/Datafab CF+SM Reader",
+		USB_SC_SCSI, USB_PR_DATAFAB, NULL,
+		0),
+
+UNUSUAL_DEV( 0x07c4, 0xa006, 0x0000, 0xffff,
+		"Simple Tech/Datafab",
+		"Simple Tech/Datafab CF+SM Reader",
+		USB_SC_SCSI, USB_PR_DATAFAB, NULL,
+		0),
+
+/* Submitted by Olaf Hering <olh@suse.de> */
+UNUSUAL_DEV(  0x07c4, 0xa109, 0x0000, 0xffff,
+		"Datafab Systems, Inc.",
+		"USB to CF + SM Combo (LC1)",
+		USB_SC_SCSI, USB_PR_DATAFAB, NULL,
+		0),
+
+/*
+ * Reported by Felix Moeller <felix@derklecks.de>
+ * in Germany this is sold by Hama with the productnumber 46952
+ * as "DualSlot CompactFlash(TM) & MStick Drive USB"
+ */
+UNUSUAL_DEV(  0x07c4, 0xa10b, 0x0000, 0xffff,
+		"DataFab Systems Inc.",
+		"USB CF+MS",
+		USB_SC_SCSI, USB_PR_DATAFAB, NULL,
+		0),
+
+UNUSUAL_DEV( 0x0c0b, 0xa109, 0x0000, 0xffff,
+		"Acomdata",
+		"CF",
+		USB_SC_SCSI, USB_PR_DATAFAB, NULL,
+		US_FL_SINGLE_LUN),
+
+#endif /* defined(CONFIG_USB_STORAGE_DATAFAB) || ... */
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
new file mode 100644
index 0000000..f7f83b2
--- /dev/null
+++ b/drivers/usb/storage/unusual_devs.h
@@ -0,0 +1,2390 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for USB Mass Storage compliant devices
+ * Unusual Devices File
+ *
+ * Current development and maintenance by:
+ *   (c) 2000-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * Initial work by:
+ *   (c) 2000 Adam J. Richter (adam@yggdrasil.com), Yggdrasil Computing, Inc.
+ */
+
+/*
+ * IMPORTANT NOTE: This file must be included in another file which does
+ * the following thing for it to work:
+ * The UNUSUAL_DEV, COMPLIANT_DEV, and USUAL_DEV macros must be defined
+ * before this file is included.
+ */
+
+/*
+ * If you edit this file, please try to keep it sorted first by VendorID,
+ * then by ProductID.
+ *
+ * If you want to add an entry for this file, be sure to include the
+ * following information:
+ *	- a patch that adds the entry for your device, including your
+ *	  email address right above the entry (plus maybe a brief
+ *	  explanation of the reason for the entry),
+ *	- a copy of /sys/kernel/debug/usb/devices with your device plugged in
+ *	  running with this patch.
+ * Send your submission to the USB development list <linux-usb@vger.kernel.org>
+ */
+
+/*
+ * Note: If you add an entry only in order to set the CAPACITY_OK flag,
+ * use the COMPLIANT_DEV macro instead of UNUSUAL_DEV.  This is
+ * because such entries mark devices which actually work correctly,
+ * as opposed to devices that do something strangely or wrongly.
+ */
+
+/*
+ * In-kernel mode switching is deprecated.  Do not add new devices to
+ * this list for the sole purpose of switching them to a different
+ * mode.  Existing userspace solutions are superior.
+ *
+ * New mode switching devices should instead be added to the database
+ * maintained at http://www.draisberghof.de/usb_modeswitch/
+ */
+
+#if !defined(CONFIG_USB_STORAGE_SDDR09) && \
+		!defined(CONFIG_USB_STORAGE_SDDR09_MODULE)
+#define NO_SDDR09
+#endif
+
+/* patch submitted by Vivian Bregier <Vivian.Bregier@imag.fr> */
+UNUSUAL_DEV(  0x03eb, 0x2002, 0x0100, 0x0100,
+		"ATMEL",
+		"SND1 Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE),
+
+/* Reported by Rodolfo Quesada <rquesada@roqz.net> */
+UNUSUAL_DEV(  0x03ee, 0x6906, 0x0003, 0x0003,
+		"VIA Technologies Inc.",
+		"Mitsumi multi cardreader",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+UNUSUAL_DEV(  0x03f0, 0x0107, 0x0200, 0x0200,
+		"HP",
+		"CD-Writer+",
+		USB_SC_8070, USB_PR_CB, NULL, 0),
+
+/* Reported by Ben Efros <ben@pc-doctor.com> */
+UNUSUAL_DEV(  0x03f0, 0x070c, 0x0000, 0x0000,
+		"HP",
+		"Personal Media Drive",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_SANE_SENSE ),
+
+/*
+ * Reported by Grant Grundler <grundler@parisc-linux.org>
+ * HP r707 camera in "Disk" mode with 2.00.23 or 2.00.24 firmware.
+ */
+UNUSUAL_DEV(  0x03f0, 0x4002, 0x0001, 0x0001,
+		"HP",
+		"PhotoSmart R707",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_FIX_CAPACITY),
+
+UNUSUAL_DEV(  0x03f3, 0x0001, 0x0000, 0x9999,
+		"Adaptec",
+		"USBConnect 2000",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init,
+		US_FL_SCM_MULT_TARG ),
+
+/*
+ * Reported by Sebastian Kapfer <sebastian_kapfer@gmx.net>
+ * and Olaf Hering <olh@suse.de> (different bcd's, same vendor/product)
+ * for USB floppies that need the SINGLE_LUN enforcement.
+ */
+UNUSUAL_DEV(  0x0409, 0x0040, 0x0000, 0x9999,
+		"NEC",
+		"NEC USB UF000x",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_SINGLE_LUN ),
+
+/* Patch submitted by Mihnea-Costin Grigore <mihnea@zulu.ro> */
+UNUSUAL_DEV(  0x040d, 0x6205, 0x0003, 0x0003,
+		"VIA Technologies Inc.",
+		"USB 2.0 Card Reader",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/*
+ * Deduced by Jonathan Woithe <jwoithe@just42.net>
+ * Entry needed for flags: US_FL_FIX_INQUIRY because initial inquiry message
+ * always fails and confuses drive.
+ */
+UNUSUAL_DEV(  0x0411, 0x001c, 0x0113, 0x0113,
+		"Buffalo",
+		"DUB-P40G HDD",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY ),
+
+/* Submitted by Ernestas Vaiciukevicius <ernisv@gmail.com> */
+UNUSUAL_DEV(  0x0419, 0x0100, 0x0100, 0x0100,
+		"Samsung Info. Systems America, Inc.",
+		"MP3 Player",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Orgad Shaneh <orgads@gmail.com> */
+UNUSUAL_DEV(  0x0419, 0xaace, 0x0100, 0x0100,
+		"Samsung", "MP3 Player",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Christian Leber <christian@leber.de> */
+UNUSUAL_DEV(  0x0419, 0xaaf5, 0x0100, 0x0100,
+		"TrekStor",
+		"i.Beat 115 2.0",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE | US_FL_NOT_LOCKABLE ),
+
+/* Reported by Stefan Werner <dustbln@gmx.de> */
+UNUSUAL_DEV(  0x0419, 0xaaf6, 0x0100, 0x0100,
+		"TrekStor",
+		"i.Beat Joy 2.0",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Pete Zaitcev <zaitcev@redhat.com>, bz#176584 */
+UNUSUAL_DEV(  0x0420, 0x0001, 0x0100, 0x0100,
+		"GENERIC", "MP3 PLAYER", /* MyMusix PD-205 on the outside. */
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/*
+ * Reported by Andrew Nayenko <relan@bk.ru>
+ * Updated for new firmware by Phillip Potter <phil@philpotter.co.uk>
+ */
+UNUSUAL_DEV(  0x0421, 0x0019, 0x0592, 0x0610,
+		"Nokia",
+		"Nokia 6288",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_MAX_SECTORS_64 ),
+
+/* Reported by Mario Rettig <mariorettig@web.de> */
+UNUSUAL_DEV(  0x0421, 0x042e, 0x0100, 0x0100,
+		"Nokia",
+		"Nokia 3250",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
+
+/* Reported by <honkkis@gmail.com> */
+UNUSUAL_DEV(  0x0421, 0x0433, 0x0100, 0x0100,
+		"Nokia",
+		"E70",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
+
+/* Reported by Jon Hart <Jon.Hart@web.de> */
+UNUSUAL_DEV(  0x0421, 0x0434, 0x0100, 0x0100,
+		"Nokia",
+		"E60",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY | US_FL_IGNORE_RESIDUE ),
+
+/*
+ * Reported by Sumedha Swamy <sumedhaswamy@gmail.com> and
+ * Einar Th. Einarsson <einarthered@gmail.com>
+ */
+UNUSUAL_DEV(  0x0421, 0x0444, 0x0100, 0x0100,
+		"Nokia",
+		"N91",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
+
+/*
+ * Reported by Jiri Slaby <jirislaby@gmail.com> and
+ * Rene C. Castberg <Rene@Castberg.org>
+ */
+UNUSUAL_DEV(  0x0421, 0x0446, 0x0100, 0x0100,
+		"Nokia",
+		"N80",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
+
+/* Reported by Matthew Bloch <matthew@bytemark.co.uk> */
+UNUSUAL_DEV(  0x0421, 0x044e, 0x0100, 0x0100,
+		"Nokia",
+		"E61",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
+
+/* Reported by Bardur Arantsson <bardur@scientician.net> */
+UNUSUAL_DEV(  0x0421, 0x047c, 0x0370, 0x0610,
+		"Nokia",
+		"6131",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_MAX_SECTORS_64 ),
+
+/* Reported by Manuel Osdoba <manuel.osdoba@tu-ilmenau.de> */
+UNUSUAL_DEV( 0x0421, 0x0492, 0x0452, 0x9999,
+		"Nokia",
+		"Nokia 6233",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_MAX_SECTORS_64 ),
+
+/* Reported by Alex Corcoles <alex@corcoles.net> */
+UNUSUAL_DEV(  0x0421, 0x0495, 0x0370, 0x0370,
+		"Nokia",
+		"6234",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_MAX_SECTORS_64 ),
+
+/* Reported by Daniele Forsi <dforsi@gmail.com> */
+UNUSUAL_DEV(  0x0421, 0x04b9, 0x0350, 0x0350,
+		"Nokia",
+		"5300",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_MAX_SECTORS_64 ),
+
+/* Patch submitted by Victor A. Santos <victoraur.santos@gmail.com> */
+UNUSUAL_DEV(  0x0421, 0x05af, 0x0742, 0x0742,
+		"Nokia",
+		"305",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_MAX_SECTORS_64),
+
+/* Patch submitted by Mikhail Zolotaryov <lebon@lebon.org.ua> */
+UNUSUAL_DEV(  0x0421, 0x06aa, 0x1110, 0x1110,
+		"Nokia",
+		"502",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_MAX_SECTORS_64 ),
+
+#ifdef NO_SDDR09
+UNUSUAL_DEV(  0x0436, 0x0005, 0x0100, 0x0100,
+		"Microtech",
+		"CameraMate",
+		USB_SC_SCSI, USB_PR_CB, NULL,
+		US_FL_SINGLE_LUN ),
+#endif
+
+/*
+ * Patch submitted by Daniel Drake <dsd@gentoo.org>
+ * Device reports nonsense bInterfaceProtocol 6 when connected over USB2
+ */
+UNUSUAL_DEV(  0x0451, 0x5416, 0x0100, 0x0100,
+		"Neuros Audio",
+		"USB 2.0 HD 2.5",
+		USB_SC_DEVICE, USB_PR_BULK, NULL,
+		US_FL_NEED_OVERRIDE ),
+
+/*
+ * Pete Zaitcev <zaitcev@yahoo.com>, from Patrick C. F. Ernzer, bz#162559.
+ * The key does not actually break, but it returns zero sense which
+ * makes our SCSI stack to print confusing messages.
+ */
+UNUSUAL_DEV(  0x0457, 0x0150, 0x0100, 0x0100,
+		"USBest Technology",	/* sold by Transcend */
+		"USB Mass Storage Device",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ),
+
+/*
+ * Bohdan Linda <bohdan.linda@gmail.com>
+ * 1GB USB sticks MyFlash High Speed. I have restricted
+ * the revision to my model only
+ */
+UNUSUAL_DEV(  0x0457, 0x0151, 0x0100, 0x0100,
+		"USB 2.0",
+		"Flash Disk",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NOT_LOCKABLE ),
+
+/*
+ * Reported by Tamas Kerecsen <kerecsen@bigfoot.com>
+ * Obviously the PROM has not been customized by the VAR;
+ * the Vendor and Product string descriptors are:
+ *	Generic Mass Storage (PROTOTYPE--Remember to change idVendor)
+ *	Generic Manufacturer (PROTOTYPE--Remember to change idVendor)
+ */
+UNUSUAL_DEV(  0x045e, 0xffff, 0x0000, 0x0000,
+		"Mitac",
+		"GPS",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_MAX_SECTORS_64 ),
+
+/*
+ * This virtual floppy is found in Sun equipment (x4600, x4200m2, etc.)
+ * Reported by Pete Zaitcev <zaitcev@redhat.com>
+ * This device chokes on both version of MODE SENSE which we have, so
+ * use_10_for_ms is not effective, and we use US_FL_NO_WP_DETECT.
+ */
+UNUSUAL_DEV(  0x046b, 0xff40, 0x0100, 0x0100,
+		"AMI",
+		"Virtual Floppy",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NO_WP_DETECT),
+
+/* Reported by Egbert Eich <eich@suse.com> */
+UNUSUAL_DEV(  0x0480, 0xd010, 0x0100, 0x9999,
+		"Toshiba",
+		"External USB 3.0",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_ALWAYS_SYNC),
+
+/* Patch submitted by Philipp Friedrich <philipp@void.at> */
+UNUSUAL_DEV(  0x0482, 0x0100, 0x0100, 0x0100,
+		"Kyocera",
+		"Finecam S3x",
+		USB_SC_8070, USB_PR_CB, NULL, US_FL_FIX_INQUIRY),
+
+/* Patch submitted by Philipp Friedrich <philipp@void.at> */
+UNUSUAL_DEV(  0x0482, 0x0101, 0x0100, 0x0100,
+		"Kyocera",
+		"Finecam S4",
+		USB_SC_8070, USB_PR_CB, NULL, US_FL_FIX_INQUIRY),
+
+/* Patch submitted by Stephane Galles <stephane.galles@free.fr> */
+UNUSUAL_DEV(  0x0482, 0x0103, 0x0100, 0x0100,
+		"Kyocera",
+		"Finecam S5",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_FIX_INQUIRY),
+
+/* Patch submitted by Jens Taprogge <jens.taprogge@taprogge.org> */
+UNUSUAL_DEV(  0x0482, 0x0107, 0x0100, 0x0100,
+		"Kyocera",
+		"CONTAX SL300R T*",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY | US_FL_NOT_LOCKABLE),
+
+/*
+ * Reported by Paul Stewart <stewart@wetlogic.net>
+ * This entry is needed because the device reports Sub=ff
+ */
+UNUSUAL_DEV(  0x04a4, 0x0004, 0x0001, 0x0001,
+		"Hitachi",
+		"DVD-CAM DZ-MV100A Camcorder",
+		USB_SC_SCSI, USB_PR_CB, NULL, US_FL_SINGLE_LUN),
+
+/*
+ * BENQ DC5330
+ * Reported by Manuel Fombuena <mfombuena@ya.com> and
+ * Frank Copeland <fjc@thingy.apana.org.au>
+ */
+UNUSUAL_DEV(  0x04a5, 0x3010, 0x0100, 0x0100,
+		"Tekom Technologies, Inc",
+		"300_CAMERA",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/*
+ * Patch for Nikon coolpix 2000
+ * Submitted by Fabien Cosse <fabien.cosse@wanadoo.fr>
+ */
+UNUSUAL_DEV(  0x04b0, 0x0301, 0x0010, 0x0010,
+		"NIKON",
+		"NIKON DSC E2000",
+		USB_SC_DEVICE, USB_PR_DEVICE,NULL,
+		US_FL_NOT_LOCKABLE ),
+
+/* Reported by Doug Maxey (dwm@austin.ibm.com) */
+UNUSUAL_DEV(  0x04b3, 0x4001, 0x0110, 0x0110,
+		"IBM",
+		"IBM RSA2",
+		USB_SC_DEVICE, USB_PR_CB, NULL,
+		US_FL_MAX_SECTORS_MIN),
+
+/*
+ * Reported by Simon Levitt <simon@whattf.com>
+ * This entry needs Sub and Proto fields
+ */
+UNUSUAL_DEV(  0x04b8, 0x0601, 0x0100, 0x0100,
+		"Epson",
+		"875DC Storage",
+		USB_SC_SCSI, USB_PR_CB, NULL, US_FL_FIX_INQUIRY),
+
+/*
+ * Reported by Khalid Aziz <khalid@gonehiking.org>
+ * This entry is needed because the device reports Sub=ff
+ */
+UNUSUAL_DEV(  0x04b8, 0x0602, 0x0110, 0x0110,
+		"Epson",
+		"785EPX Storage",
+		USB_SC_SCSI, USB_PR_BULK, NULL, US_FL_SINGLE_LUN),
+
+/*
+ * Not sure who reported this originally but
+ * Pavel Machek <pavel@ucw.cz> reported that the extra US_FL_SINGLE_LUN
+ * flag be added */
+UNUSUAL_DEV(  0x04cb, 0x0100, 0x0000, 0x2210,
+		"Fujifilm",
+		"FinePix 1400Zoom",
+		USB_SC_UFI, USB_PR_DEVICE, NULL, US_FL_FIX_INQUIRY | US_FL_SINGLE_LUN),
+
+/*
+ * Reported by Ondrej Zary <linux@rainbow-software.org>
+ * The device reports one sector more and breaks when that sector is accessed
+ */
+UNUSUAL_DEV(  0x04ce, 0x0002, 0x026c, 0x026c,
+		"ScanLogic",
+		"SL11R-IDE",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY),
+
+/*
+ * Reported by Kriston Fincher <kriston@airmail.net>
+ * Patch submitted by Sean Millichamp <sean@bruenor.org>
+ * This is to support the Panasonic PalmCam PV-SD4090
+ * This entry is needed because the device reports Sub=ff 
+ */
+UNUSUAL_DEV(  0x04da, 0x0901, 0x0100, 0x0200,
+		"Panasonic",
+		"LS-120 Camera",
+		USB_SC_UFI, USB_PR_DEVICE, NULL, 0),
+
+/*
+ * From Yukihiro Nakai, via zaitcev@yahoo.com.
+ * This is needed for CB instead of CBI
+ */
+UNUSUAL_DEV(  0x04da, 0x0d05, 0x0000, 0x0000,
+		"Sharp CE-CW05",
+		"CD-R/RW Drive",
+		USB_SC_8070, USB_PR_CB, NULL, 0),
+
+/* Reported by Adriaan Penning <a.penning@luon.net> */
+UNUSUAL_DEV(  0x04da, 0x2372, 0x0000, 0x9999,
+		"Panasonic",
+		"DMC-LCx Camera",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY | US_FL_NOT_LOCKABLE ),
+
+/* Reported by Simeon Simeonov <simeonov_2000@yahoo.com> */
+UNUSUAL_DEV(  0x04da, 0x2373, 0x0000, 0x9999,
+		"LEICA",
+		"D-LUX Camera",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY | US_FL_NOT_LOCKABLE ),
+
+/*
+ * Most of the following entries were developed with the help of
+ * Shuttle/SCM directly.
+ */
+UNUSUAL_DEV(  0x04e6, 0x0001, 0x0200, 0x0200,
+		"Matshita",
+		"LS-120",
+		USB_SC_8020, USB_PR_CB, NULL, 0),
+
+UNUSUAL_DEV(  0x04e6, 0x0002, 0x0100, 0x0100,
+		"Shuttle",
+		"eUSCSI Bridge",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init,
+		US_FL_SCM_MULT_TARG ),
+
+#ifdef NO_SDDR09
+UNUSUAL_DEV(  0x04e6, 0x0005, 0x0100, 0x0208,
+		"SCM Microsystems",
+		"eUSB CompactFlash Adapter",
+		USB_SC_SCSI, USB_PR_CB, NULL,
+		US_FL_SINGLE_LUN),
+#endif
+
+/* Reported by Markus Demleitner <msdemlei@cl.uni-heidelberg.de> */
+UNUSUAL_DEV(  0x04e6, 0x0006, 0x0100, 0x0100,
+		"SCM Microsystems Inc.",
+		"eUSB MMC Adapter",
+		USB_SC_SCSI, USB_PR_CB, NULL,
+		US_FL_SINGLE_LUN),
+
+/* Reported by Daniel Nouri <dpunktnpunkt@web.de> */
+UNUSUAL_DEV(  0x04e6, 0x0006, 0x0205, 0x0205,
+		"Shuttle",
+		"eUSB MMC Adapter",
+		USB_SC_SCSI, USB_PR_DEVICE, NULL,
+		US_FL_SINGLE_LUN),
+
+UNUSUAL_DEV(  0x04e6, 0x0007, 0x0100, 0x0200,
+		"Sony",
+		"Hifd",
+		USB_SC_SCSI, USB_PR_CB, NULL,
+		US_FL_SINGLE_LUN),
+
+UNUSUAL_DEV(  0x04e6, 0x0009, 0x0200, 0x0200,
+		"Shuttle",
+		"eUSB ATA/ATAPI Adapter",
+		USB_SC_8020, USB_PR_CB, NULL, 0),
+
+UNUSUAL_DEV(  0x04e6, 0x000a, 0x0200, 0x0200,
+		"Shuttle",
+		"eUSB CompactFlash Adapter",
+		USB_SC_8020, USB_PR_CB, NULL, 0),
+
+UNUSUAL_DEV(  0x04e6, 0x000b, 0x0100, 0x0100,
+		"Shuttle",
+		"eUSCSI Bridge",
+		USB_SC_SCSI, USB_PR_BULK, usb_stor_euscsi_init,
+		US_FL_SCM_MULT_TARG ), 
+
+UNUSUAL_DEV(  0x04e6, 0x000c, 0x0100, 0x0100,
+		"Shuttle",
+		"eUSCSI Bridge",
+		USB_SC_SCSI, USB_PR_BULK, usb_stor_euscsi_init,
+		US_FL_SCM_MULT_TARG ),
+
+UNUSUAL_DEV(  0x04e6, 0x000f, 0x0000, 0x9999,
+		"SCM Microsystems",
+		"eUSB SCSI Adapter (Bus Powered)",
+		USB_SC_SCSI, USB_PR_BULK, usb_stor_euscsi_init,
+		US_FL_SCM_MULT_TARG ),
+
+UNUSUAL_DEV(  0x04e6, 0x0101, 0x0200, 0x0200,
+		"Shuttle",
+		"CD-RW Device",
+		USB_SC_8020, USB_PR_CB, NULL, 0),
+
+/* Reported by Dmitry Khlystov <adminimus@gmail.com> */
+UNUSUAL_DEV(  0x04e8, 0x507c, 0x0220, 0x0220,
+		"Samsung",
+		"YP-U3",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_MAX_SECTORS_64),
+
+/* Reported by Vitaly Kuznetsov <vitty@altlinux.ru> */
+UNUSUAL_DEV(  0x04e8, 0x5122, 0x0000, 0x9999,
+		"Samsung",
+		"YP-CP3",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_MAX_SECTORS_64 | US_FL_BULK_IGNORE_TAG),
+
+/* Added by Dmitry Artamonow <mad_soft@inbox.ru> */
+UNUSUAL_DEV(  0x04e8, 0x5136, 0x0000, 0x9999,
+		"Samsung",
+		"YP-Z3",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_MAX_SECTORS_64),
+
+/*
+ * Entry and supporting patch by Theodore Kilgore <kilgota@auburn.edu>.
+ * Device uses standards-violating 32-byte Bulk Command Block Wrappers and
+ * reports itself as "Proprietary SCSI Bulk." Cf. device entry 0x084d:0x0011.
+ */
+UNUSUAL_DEV(  0x04fc, 0x80c2, 0x0100, 0x0100,
+		"Kobian Mercury",
+		"Binocam DCB-132",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_BULK32),
+
+/* Reported by Bob Sass <rls@vectordb.com> -- only rev 1.33 tested */
+UNUSUAL_DEV(  0x050d, 0x0115, 0x0133, 0x0133,
+		"Belkin",
+		"USB SCSI Adaptor",
+		USB_SC_SCSI, USB_PR_BULK, usb_stor_euscsi_init,
+		US_FL_SCM_MULT_TARG ),
+
+/*
+ * Iomega Clik! Drive 
+ * Reported by David Chatenay <dchatenay@hotmail.com>
+ * The reason this is needed is not fully known.
+ */
+UNUSUAL_DEV(  0x0525, 0xa140, 0x0100, 0x0100,
+		"Iomega",
+		"USB Clik! 40",
+		USB_SC_8070, USB_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY ),
+
+/* Added by Alan Stern <stern@rowland.harvard.edu> */
+COMPLIANT_DEV(0x0525, 0xa4a5, 0x0000, 0x9999,
+		"Linux",
+		"File-backed Storage Gadget",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_CAPACITY_OK ),
+
+/*
+ * Yakumo Mega Image 37
+ * Submitted by Stephan Fuhrmann <atomenergie@t-online.de> */
+UNUSUAL_DEV(  0x052b, 0x1801, 0x0100, 0x0100,
+		"Tekom Technologies, Inc",
+		"300_CAMERA",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/*
+ * Another Yakumo camera.
+ * Reported by Michele Alzetta <michele.alzetta@aliceposta.it>
+ */
+UNUSUAL_DEV(  0x052b, 0x1804, 0x0100, 0x0100,
+		"Tekom Technologies, Inc",
+		"300_CAMERA",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Iacopo Spalletti <avvisi@spalletti.it> */
+UNUSUAL_DEV(  0x052b, 0x1807, 0x0100, 0x0100,
+		"Tekom Technologies, Inc",
+		"300_CAMERA",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/*
+ * Yakumo Mega Image 47
+ * Reported by Bjoern Paetzel <kolrabi@kolrabi.de>
+ */
+UNUSUAL_DEV(  0x052b, 0x1905, 0x0100, 0x0100,
+		"Tekom Technologies, Inc",
+		"400_CAMERA",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/*
+ * Reported by Paul Ortyl <ortylp@3miasto.net>
+ * Note that it's similar to the device above, only different prodID
+ */
+UNUSUAL_DEV(  0x052b, 0x1911, 0x0100, 0x0100,
+		"Tekom Technologies, Inc",
+		"400_CAMERA",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+UNUSUAL_DEV(  0x054c, 0x0010, 0x0106, 0x0450,
+		"Sony",
+		"DSC-S30/S70/S75/505V/F505/F707/F717/P8",
+		USB_SC_SCSI, USB_PR_DEVICE, NULL,
+		US_FL_SINGLE_LUN | US_FL_NOT_LOCKABLE | US_FL_NO_WP_DETECT ),
+
+/*
+ * Submitted by Lars Jacob <jacob.lars@googlemail.com>
+ * This entry is needed because the device reports Sub=ff
+ */
+UNUSUAL_DEV(  0x054c, 0x0010, 0x0500, 0x0610,
+		"Sony",
+		"DSC-T1/T5/H5",
+		USB_SC_8070, USB_PR_DEVICE, NULL,
+		US_FL_SINGLE_LUN ),
+
+
+/* Reported by wim@geeks.nl */
+UNUSUAL_DEV(  0x054c, 0x0025, 0x0100, 0x0100,
+		"Sony",
+		"Memorystick NW-MS7",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_SINGLE_LUN ),
+
+/* Submitted by Olaf Hering, <olh@suse.de> SuSE Bugzilla #49049 */
+UNUSUAL_DEV(  0x054c, 0x002c, 0x0501, 0x2000,
+		"Sony",
+		"USB Floppy Drive",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_SINGLE_LUN ),
+
+UNUSUAL_DEV(  0x054c, 0x002d, 0x0100, 0x0100,
+		"Sony",
+		"Memorystick MSAC-US1",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_SINGLE_LUN ),
+
+/* Submitted by Klaus Mueller <k.mueller@intershop.de> */
+UNUSUAL_DEV(  0x054c, 0x002e, 0x0106, 0x0310,
+		"Sony",
+		"Handycam",
+		USB_SC_SCSI, USB_PR_DEVICE, NULL,
+		US_FL_SINGLE_LUN ),
+
+/* Submitted by Rajesh Kumble Nayak <nayak@obs-nice.fr> */
+UNUSUAL_DEV(  0x054c, 0x002e, 0x0500, 0x0500,
+		"Sony",
+		"Handycam HC-85",
+		USB_SC_UFI, USB_PR_DEVICE, NULL,
+		US_FL_SINGLE_LUN ),
+
+UNUSUAL_DEV(  0x054c, 0x0032, 0x0000, 0x9999,
+		"Sony",
+		"Memorystick MSC-U01N",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_SINGLE_LUN ),
+
+/* Submitted by Michal Mlotek <mlotek@foobar.pl> */
+UNUSUAL_DEV(  0x054c, 0x0058, 0x0000, 0x9999,
+		"Sony",
+		"PEG N760c Memorystick",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY ),
+		
+UNUSUAL_DEV(  0x054c, 0x0069, 0x0000, 0x9999,
+		"Sony",
+		"Memorystick MSC-U03",
+		USB_SC_UFI, USB_PR_CB, NULL,
+		US_FL_SINGLE_LUN ),
+
+/* Submitted by Nathan Babb <nathan@lexi.com> */
+UNUSUAL_DEV(  0x054c, 0x006d, 0x0000, 0x9999,
+		"Sony",
+		"PEG Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY ),
+
+/* Submitted by Frank Engel <frankie@cse.unsw.edu.au> */
+UNUSUAL_DEV(  0x054c, 0x0099, 0x0000, 0x9999,
+		"Sony",
+		"PEG Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY ),
+
+/* Submitted by Mike Alborn <malborn@deandra.homeip.net> */
+UNUSUAL_DEV(  0x054c, 0x016a, 0x0000, 0x9999,
+		"Sony",
+		"PEG Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY ),
+
+/* Submitted by Ren Bigcren <bigcren.ren@sonymobile.com> */
+UNUSUAL_DEV(  0x054c, 0x02a5, 0x0100, 0x0100,
+		"Sony Corp.",
+		"MicroVault Flash Drive",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NO_READ_CAPACITY_16 ),
+
+/* floppy reports multiple luns */
+UNUSUAL_DEV(  0x055d, 0x2020, 0x0000, 0x0210,
+		"SAMSUNG",
+		"SFD-321U [FW 0C]",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_SINGLE_LUN ),
+
+/* We keep this entry to force the transport; firmware 3.00 and later is ok. */
+UNUSUAL_DEV(  0x057b, 0x0000, 0x0000, 0x0299,
+		"Y-E Data",
+		"Flashbuster-U",
+		USB_SC_DEVICE,  USB_PR_CB, NULL,
+		US_FL_SINGLE_LUN),
+
+/*
+ * Reported by Johann Cardon <johann.cardon@free.fr>
+ * This entry is needed only because the device reports
+ * bInterfaceClass = 0xff (vendor-specific)
+ */
+UNUSUAL_DEV(  0x057b, 0x0022, 0x0000, 0x9999,
+		"Y-E Data",
+		"Silicon Media R/W",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL, 0),
+
+/* Reported by RTE <raszilki@yandex.ru> */
+UNUSUAL_DEV(  0x058f, 0x6387, 0x0141, 0x0141,
+		"JetFlash",
+		"TS1GJF2A/120",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_MAX_SECTORS_64 ),
+
+/* Fabrizio Fellini <fello@libero.it> */
+UNUSUAL_DEV(  0x0595, 0x4343, 0x0000, 0x2210,
+		"Fujifilm",
+		"Digital Camera EX-20 DSC",
+		USB_SC_8070, USB_PR_DEVICE, NULL, 0 ),
+
+/*
+ * Reported by Andre Welter <a.r.welter@gmx.de>
+ * This antique device predates the release of the Bulk-only Transport
+ * spec, and if it gets a Get-Max-LUN then it requires the host to do a
+ * Clear-Halt on the bulk endpoints.  The SINGLE_LUN flag will prevent
+ * us from sending the request.
+ */
+UNUSUAL_DEV(  0x059b, 0x0001, 0x0100, 0x0100,
+		"Iomega",
+		"ZIP 100",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_SINGLE_LUN ),
+
+UNUSUAL_DEV(  0x059b, 0x0040, 0x0100, 0x0100,
+		"Iomega",
+		"Jaz USB Adapter",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_SINGLE_LUN ),
+
+/* Reported by <Hendryk.Pfeiffer@gmx.de> */
+UNUSUAL_DEV(  0x059f, 0x0643, 0x0000, 0x0000,
+		"LaCie",
+		"DVD+-RW",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_GO_SLOW ),
+
+/* Reported by Christian Schaller <cschalle@redhat.com> */
+UNUSUAL_DEV(  0x059f, 0x0651, 0x0000, 0x0000,
+		"LaCie",
+		"External HDD",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NO_WP_DETECT ),
+
+/*
+ * Submitted by Joel Bourquard <numlock@freesurf.ch>
+ * Some versions of this device need the SubClass and Protocol overrides
+ * while others don't.
+ */
+UNUSUAL_DEV(  0x05ab, 0x0060, 0x1104, 0x1110,
+		"In-System",
+		"PyroGate External CD-ROM Enclosure (FCD-523)",
+		USB_SC_SCSI, USB_PR_BULK, NULL,
+		US_FL_NEED_OVERRIDE ),
+
+/*
+ * Submitted by Sven Anderson <sven-linux@anderson.de>
+ * There are at least four ProductIDs used for iPods, so I added 0x1202 and
+ * 0x1204. They just need the US_FL_FIX_CAPACITY. As the bcdDevice appears
+ * to change with firmware updates, I changed the range to maximum for all
+ * iPod entries.
+ */
+UNUSUAL_DEV( 0x05ac, 0x1202, 0x0000, 0x9999,
+		"Apple",
+		"iPod",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY ),
+
+/* Reported by Avi Kivity <avi@argo.co.il> */
+UNUSUAL_DEV( 0x05ac, 0x1203, 0x0000, 0x9999,
+		"Apple",
+		"iPod",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY ),
+
+UNUSUAL_DEV( 0x05ac, 0x1204, 0x0000, 0x9999,
+		"Apple",
+		"iPod",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY | US_FL_NOT_LOCKABLE ),
+
+UNUSUAL_DEV( 0x05ac, 0x1205, 0x0000, 0x9999,
+		"Apple",
+		"iPod",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY ),
+
+/*
+ * Reported by Tyson Vinson <lornoss@gmail.com>
+ * This particular productId is the iPod Nano
+ */
+UNUSUAL_DEV( 0x05ac, 0x120a, 0x0000, 0x9999,
+		"Apple",
+		"iPod",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY ),
+
+/*
+ * Reported by Dan Williams <dcbw@redhat.com>
+ * Option N.V. mobile broadband modems
+ * Ignore driver CD mode and force into modem mode by default.
+ */
+
+/* Globetrotter HSDPA; mass storage shows up as Qualcomm for vendor */
+UNUSUAL_DEV(  0x05c6, 0x1000, 0x0000, 0x9999,
+		"Option N.V.",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, option_ms_init,
+		0),
+
+/* Reported by Blake Matheny <bmatheny@purdue.edu> */
+UNUSUAL_DEV(  0x05dc, 0xb002, 0x0000, 0x0113,
+		"Lexar",
+		"USB CF Reader",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY ),
+
+/*
+ * The following two entries are for a Genesys USB to IDE
+ * converter chip, but it changes its ProductId depending
+ * on whether or not a disk or an optical device is enclosed
+ * They were originally reported by Alexander Oltu
+ * <alexander@all-2.com> and Peter Marks <peter.marks@turner.com>
+ * respectively.
+ *
+ * US_FL_GO_SLOW and US_FL_MAX_SECTORS_64 added by Phil Dibowitz
+ * <phil@ipom.com> as these flags were made and hard-coded
+ * special-cases were pulled from scsiglue.c.
+ */
+UNUSUAL_DEV(  0x05e3, 0x0701, 0x0000, 0xffff,
+		"Genesys Logic",
+		"USB to IDE Optical",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 | US_FL_IGNORE_RESIDUE ),
+
+UNUSUAL_DEV(  0x05e3, 0x0702, 0x0000, 0xffff,
+		"Genesys Logic",
+		"USB to IDE Disk",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 | US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Ben Efros <ben@pc-doctor.com> */
+UNUSUAL_DEV(  0x05e3, 0x0723, 0x9451, 0x9451,
+		"Genesys Logic",
+		"USB to SATA",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_SANE_SENSE ),
+
+/*
+ * Reported by Hanno Boeck <hanno@gmx.de>
+ * Taken from the Lycoris Kernel
+ */
+UNUSUAL_DEV(  0x0636, 0x0003, 0x0000, 0x9999,
+		"Vivitar",
+		"Vivicam 35Xx",
+		USB_SC_SCSI, USB_PR_BULK, NULL,
+		US_FL_FIX_INQUIRY ),
+
+UNUSUAL_DEV(  0x0644, 0x0000, 0x0100, 0x0100,
+		"TEAC",
+		"Floppy Drive",
+		USB_SC_UFI, USB_PR_CB, NULL, 0 ),
+
+/* Reported by Darsen Lu <darsen@micro.ee.nthu.edu.tw> */
+UNUSUAL_DEV( 0x066f, 0x8000, 0x0001, 0x0001,
+		"SigmaTel",
+		"USBMSC Audio Player",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY ),
+
+/* Reported by Daniel Kukula <daniel.kuku@gmail.com> */
+UNUSUAL_DEV( 0x067b, 0x1063, 0x0100, 0x0100,
+		"Prolific Technology, Inc.",
+		"Prolific Storage Gadget",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_BAD_SENSE ),
+
+/* Reported by Rogerio Brito <rbrito@ime.usp.br> */
+UNUSUAL_DEV( 0x067b, 0x2317, 0x0001, 0x001,
+		"Prolific Technology, Inc.",
+		"Mass Storage Device",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NOT_LOCKABLE ),
+
+/* Reported by Richard -=[]=- <micro_flyer@hotmail.com> */
+/*
+ * Change to bcdDeviceMin (0x0100 to 0x0001) reported by
+ * Thomas Bartosik <tbartdev@gmx-topmail.de>
+ */
+UNUSUAL_DEV( 0x067b, 0x2507, 0x0001, 0x0100,
+		"Prolific Technology Inc.",
+		"Mass Storage Device",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY | US_FL_GO_SLOW ),
+
+/* Reported by Alex Butcher <alex.butcher@assursys.co.uk> */
+UNUSUAL_DEV( 0x067b, 0x3507, 0x0001, 0x0101,
+		"Prolific Technology Inc.",
+		"ATAPI-6 Bridge Controller",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY | US_FL_GO_SLOW ),
+
+/* Submitted by Benny Sjostrand <benny@hostmobility.com> */
+UNUSUAL_DEV( 0x0686, 0x4011, 0x0001, 0x0001,
+		"Minolta",
+		"Dimage F300",
+		USB_SC_SCSI, USB_PR_BULK, NULL, 0 ),
+
+/* Reported by Miguel A. Fosas <amn3s1a@ono.com> */
+UNUSUAL_DEV(  0x0686, 0x4017, 0x0001, 0x0001,
+		"Minolta",
+		"DIMAGE E223",
+		USB_SC_SCSI, USB_PR_DEVICE, NULL, 0 ),
+
+UNUSUAL_DEV(  0x0693, 0x0005, 0x0100, 0x0100,
+		"Hagiwara",
+		"Flashgate",
+		USB_SC_SCSI, USB_PR_BULK, NULL, 0 ),
+
+/* Reported by David Hamilton <niftimusmaximus@lycos.com> */
+UNUSUAL_DEV(  0x069b, 0x3004, 0x0001, 0x0001,
+		"Thomson Multimedia Inc.",
+		"RCA RD1080 MP3 Player",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY ),
+
+UNUSUAL_DEV(  0x06ca, 0x2003, 0x0100, 0x0100,
+		"Newer Technology",
+		"uSCSI",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init,
+		US_FL_SCM_MULT_TARG ),
+
+/* Reported by Adrian Pilchowiec <adi1981@epf.pl> */
+UNUSUAL_DEV(  0x071b, 0x3203, 0x0000, 0x0000,
+		"RockChip",
+		"MP3",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NO_WP_DETECT | US_FL_MAX_SECTORS_64 |
+		US_FL_NO_READ_CAPACITY_16),
+
+/*
+ * Reported by Jean-Baptiste Onofre <jb@nanthrax.net>
+ * Support the following product :
+ *    "Dane-Elec MediaTouch"
+ */
+UNUSUAL_DEV(  0x071b, 0x32bb, 0x0000, 0x0000,
+		"RockChip",
+		"MTP",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NO_WP_DETECT | US_FL_MAX_SECTORS_64),
+
+/*
+ * Reported by Massimiliano Ghilardi <massimiliano.ghilardi@gmail.com>
+ * This USB MP3/AVI player device fails and disconnects if more than 128
+ * sectors (64kB) are read/written in a single command, and may be present
+ * at least in the following products:
+ *   "Magnex Digital Video Panel DVP 1800"
+ *   "MP4 AIGO 4GB SLOT SD"
+ *   "Teclast TL-C260 MP3"
+ *   "i.Meizu PMP MP3/MP4"
+ *   "Speed MV8 MP4 Audio Player"
+ */
+UNUSUAL_DEV(  0x071b, 0x3203, 0x0100, 0x0100,
+		"RockChip",
+		"ROCK MP3",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_MAX_SECTORS_64),
+
+/* Reported by Olivier Blondeau <zeitoun@gmail.com> */
+UNUSUAL_DEV(  0x0727, 0x0306, 0x0100, 0x0100,
+		"ATMEL",
+		"SND1 Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE),
+
+/* Submitted by Roman Hodek <roman@hodek.net> */
+UNUSUAL_DEV(  0x0781, 0x0001, 0x0200, 0x0200,
+		"Sandisk",
+		"ImageMate SDDR-05a",
+		USB_SC_SCSI, USB_PR_CB, NULL,
+		US_FL_SINGLE_LUN ),
+
+UNUSUAL_DEV(  0x0781, 0x0002, 0x0009, 0x0009,
+		"SanDisk Corporation",
+		"ImageMate CompactFlash USB",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY ),
+
+UNUSUAL_DEV(  0x0781, 0x0100, 0x0100, 0x0100,
+		"Sandisk",
+		"ImageMate SDDR-12",
+		USB_SC_SCSI, USB_PR_CB, NULL,
+		US_FL_SINGLE_LUN ),
+
+/* Reported by Eero Volotinen <eero@ping-viini.org> */
+UNUSUAL_DEV(  0x07ab, 0xfccd, 0x0000, 0x9999,
+		"Freecom Technologies",
+		"FHD-Classic",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY),
+
+UNUSUAL_DEV(  0x07af, 0x0004, 0x0100, 0x0133,
+		"Microtech",
+		"USB-SCSI-DB25",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init,
+		US_FL_SCM_MULT_TARG ), 
+
+UNUSUAL_DEV(  0x07af, 0x0005, 0x0100, 0x0100,
+		"Microtech",
+		"USB-SCSI-HD50",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init,
+		US_FL_SCM_MULT_TARG ),
+
+#ifdef NO_SDDR09
+UNUSUAL_DEV(  0x07af, 0x0006, 0x0100, 0x0100,
+		"Microtech",
+		"CameraMate",
+		USB_SC_SCSI, USB_PR_CB, NULL,
+		US_FL_SINGLE_LUN ),
+#endif
+
+/*
+ * Datafab KECF-USB / Sagatek DCS-CF / Simpletech Flashlink UCF-100
+ * Only revision 1.13 tested (same for all of the above devices,
+ * based on the Datafab DF-UG-07 chip).  Needed for US_FL_FIX_INQUIRY.
+ * Submitted by Marek Michalkiewicz <marekm@amelek.gda.pl>.
+ * See also http://martin.wilck.bei.t-online.de/#kecf .
+ */
+UNUSUAL_DEV(  0x07c4, 0xa400, 0x0000, 0xffff,
+		"Datafab",
+		"KECF-USB",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY | US_FL_FIX_CAPACITY ),
+
+/*
+ * Reported by Rauch Wolke <rauchwolke@gmx.net>
+ * and augmented by binbin <binbinsh@gmail.com> (Bugzilla #12882)
+ */
+UNUSUAL_DEV(  0x07c4, 0xa4a5, 0x0000, 0xffff,
+		"Simple Tech/Datafab",
+		"CF+SM Reader",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE | US_FL_MAX_SECTORS_64 ),
+
+/*
+ * Casio QV 2x00/3x00/4000/8000 digital still cameras are not conformant
+ * to the USB storage specification in two ways:
+ * - They tell us they are using transport protocol CBI. In reality they
+ *   are using transport protocol CB.
+ * - They don't like the INQUIRY command. So we must handle this command
+ *   of the SCSI layer ourselves.
+ * - Some cameras with idProduct=0x1001 and bcdDevice=0x1000 have
+ *   bInterfaceProtocol=0x00 (USB_PR_CBI) while others have 0x01 (USB_PR_CB).
+ *   So don't remove the USB_PR_CB override!
+ * - Cameras with bcdDevice=0x9009 require the USB_SC_8070 override.
+ */
+UNUSUAL_DEV( 0x07cf, 0x1001, 0x1000, 0x9999,
+		"Casio",
+		"QV DigitalCamera",
+		USB_SC_8070, USB_PR_CB, NULL,
+		US_FL_NEED_OVERRIDE | US_FL_FIX_INQUIRY ),
+
+/* Submitted by Oleksandr Chumachenko <ledest@gmail.com> */
+UNUSUAL_DEV( 0x07cf, 0x1167, 0x0100, 0x0100,
+		"Casio",
+		"EX-N1 DigitalCamera",
+		USB_SC_8070, USB_PR_DEVICE, NULL, 0),
+
+/* Submitted by Hartmut Wahl <hwahl@hwahl.de>*/
+UNUSUAL_DEV( 0x0839, 0x000a, 0x0001, 0x0001,
+		"Samsung",
+		"Digimax 410",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY),
+
+/* Reported by Luciano Rocha <luciano@eurotux.com> */
+UNUSUAL_DEV( 0x0840, 0x0082, 0x0001, 0x0001,
+		"Argosy",
+		"Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY),
+
+/* Reported and patched by Nguyen Anh Quynh <aquynh@gmail.com> */
+UNUSUAL_DEV( 0x0840, 0x0084, 0x0001, 0x0001,
+		"Argosy",
+		"Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY),
+
+/* Reported by Martijn Hijdra <martijn.hijdra@gmail.com> */
+UNUSUAL_DEV( 0x0840, 0x0085, 0x0001, 0x0001,
+		"Argosy",
+		"Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY),
+
+/* Supplied with some Castlewood ORB removable drives */
+UNUSUAL_DEV(  0x084b, 0xa001, 0x0000, 0x9999,
+		"Castlewood Systems",
+		"USB to SCSI cable",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init,
+		US_FL_SCM_MULT_TARG ),
+
+/*
+ * Entry and supporting patch by Theodore Kilgore <kilgota@auburn.edu>.
+ * Flag will support Bulk devices which use a standards-violating 32-byte
+ * Command Block Wrapper. Here, the "DC2MEGA" cameras (several brands) with
+ * Grandtech GT892x chip, which request "Proprietary SCSI Bulk" support.
+ */
+
+UNUSUAL_DEV(  0x084d, 0x0011, 0x0110, 0x0110,
+		"Grandtech",
+		"DC2MEGA",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_BULK32),
+
+/*
+ * Reported by <ttkspam@free.fr>
+ * The device reports a vendor-specific device class, requiring an
+ * explicit vendor/product match.
+ */
+UNUSUAL_DEV(  0x0851, 0x1542, 0x0002, 0x0002,
+		"MagicPixel",
+		"FW_Omega2",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL, 0),
+
+/*
+ * Andrew Lunn <andrew@lunn.ch>
+ * PanDigital Digital Picture Frame. Does not like ALLOW_MEDIUM_REMOVAL
+ * on LUN 4.
+ * Note: Vend:Prod clash with "Ltd Maxell WS30 Slim Digital Camera"
+ */
+UNUSUAL_DEV(  0x0851, 0x1543, 0x0200, 0x0200,
+		"PanDigital",
+		"Photo Frame",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NOT_LOCKABLE),
+
+UNUSUAL_DEV(  0x085a, 0x0026, 0x0100, 0x0133,
+		"Xircom",
+		"PortGear USB-SCSI (Mac USB Dock)",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init,
+		US_FL_SCM_MULT_TARG ),
+
+UNUSUAL_DEV(  0x085a, 0x0028, 0x0100, 0x0133,
+		"Xircom",
+		"PortGear USB to SCSI Converter",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init,
+		US_FL_SCM_MULT_TARG ),
+
+/* Submitted by Jan De Luyck <lkml@kcore.org> */
+UNUSUAL_DEV(  0x08bd, 0x1100, 0x0000, 0x0000,
+		"CITIZEN",
+		"X1DE-USB",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_SINGLE_LUN),
+
+/*
+ * Submitted by Dylan Taft <d13f00l@gmail.com>
+ * US_FL_IGNORE_RESIDUE Needed
+ */
+UNUSUAL_DEV(  0x08ca, 0x3103, 0x0100, 0x0100,
+		"AIPTEK",
+		"Aiptek USB Keychain MP3 Player",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE),
+
+/*
+ * Entry needed for flags. Moreover, all devices with this ID use
+ * bulk-only transport, but _some_ falsely report Control/Bulk instead.
+ * One example is "Trumpion Digital Research MYMP3".
+ * Submitted by Bjoern Brill <brill(at)fs.math.uni-frankfurt.de>
+ */
+UNUSUAL_DEV(  0x090a, 0x1001, 0x0100, 0x0100,
+		"Trumpion",
+		"t33520 USB Flash Card Controller",
+		USB_SC_DEVICE, USB_PR_BULK, NULL,
+		US_FL_NEED_OVERRIDE ),
+
+/*
+ * Reported by Filippo Bardelli <filibard@libero.it>
+ * The device reports a subclass of RBC, which is wrong.
+ */
+UNUSUAL_DEV(  0x090a, 0x1050, 0x0100, 0x0100,
+		"Trumpion Microelectronics, Inc.",
+		"33520 USB Digital Voice Recorder",
+		USB_SC_UFI, USB_PR_DEVICE, NULL,
+		0),
+
+/* Trumpion Microelectronics MP3 player (felipe_alfaro@linuxmail.org) */
+UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999,
+		"Trumpion",
+		"MP3 player",
+		USB_SC_RBC, USB_PR_BULK, NULL,
+		0 ),
+
+/* aeb */
+UNUSUAL_DEV( 0x090c, 0x1132, 0x0000, 0xffff,
+		"Feiya",
+		"5-in-1 Card Reader",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY ),
+
+/*
+ * Reported by Paul Hartman <paul.hartman+linux@gmail.com>
+ * This card reader returns "Illegal Request, Logical Block Address
+ * Out of Range" for the first READ(10) after a new card is inserted.
+ */
+UNUSUAL_DEV(  0x090c, 0x6000, 0x0100, 0x0100,
+		"Feiya",
+		"SD/SDHC Card Reader",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_INITIAL_READ10 ),
+
+/*
+ * This Pentax still camera is not conformant
+ * to the USB storage specification: -
+ * - It does not like the INQUIRY command. So we must handle this command
+ *   of the SCSI layer ourselves.
+ * Tested on Rev. 10.00 (0x1000)
+ * Submitted by James Courtier-Dutton <James@superbug.demon.co.uk>
+ */
+UNUSUAL_DEV( 0x0a17, 0x0004, 0x1000, 0x1000,
+		"Pentax",
+		"Optio 2/3/400",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY ),
+
+/*
+ * These are virtual windows driver CDs, which the zd1211rw driver
+ * automatically converts into WLAN devices.
+ */
+UNUSUAL_DEV( 0x0ace, 0x2011, 0x0101, 0x0101,
+		"ZyXEL",
+		"G-220F USB-WLAN Install",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_DEVICE ),
+
+UNUSUAL_DEV( 0x0ace, 0x20ff, 0x0101, 0x0101,
+		"SiteCom",
+		"WL-117 USB-WLAN Install",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_DEVICE ),
+
+/*
+ * Reported by Dan Williams <dcbw@redhat.com>
+ * Option N.V. mobile broadband modems
+ * Ignore driver CD mode and force into modem mode by default.
+ */
+
+/* iCON 225 */
+UNUSUAL_DEV(  0x0af0, 0x6971, 0x0000, 0x9999,
+		"Option N.V.",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, option_ms_init,
+		0),
+
+/*
+ * Reported by F. Aben <f.aben@option.com>
+ * This device (wrongly) has a vendor-specific device descriptor.
+ * The entry is needed so usb-storage can bind to it's mass-storage
+ * interface as an interface driver
+ */
+UNUSUAL_DEV( 0x0af0, 0x7401, 0x0000, 0x0000,
+		"Option",
+		"GI 0401 SD-Card",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		0 ),
+
+/*
+ * Reported by Jan Dumon <j.dumon@option.com>
+ * These devices (wrongly) have a vendor-specific device descriptor.
+ * These entries are needed so usb-storage can bind to their mass-storage
+ * interface as an interface driver
+ */
+UNUSUAL_DEV( 0x0af0, 0x7501, 0x0000, 0x0000,
+		"Option",
+		"GI 0431 SD-Card",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x7701, 0x0000, 0x0000,
+		"Option",
+		"GI 0451 SD-Card",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x7706, 0x0000, 0x0000,
+		"Option",
+		"GI 0451 SD-Card",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x7901, 0x0000, 0x0000,
+		"Option",
+		"GI 0452 SD-Card",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x7A01, 0x0000, 0x0000,
+		"Option",
+		"GI 0461 SD-Card",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x7A05, 0x0000, 0x0000,
+		"Option",
+		"GI 0461 SD-Card",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x8300, 0x0000, 0x0000,
+		"Option",
+		"GI 033x SD-Card",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x8302, 0x0000, 0x0000,
+		"Option",
+		"GI 033x SD-Card",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x8304, 0x0000, 0x0000,
+		"Option",
+		"GI 033x SD-Card",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		0 ),
+
+UNUSUAL_DEV( 0x0af0, 0xc100, 0x0000, 0x0000,
+		"Option",
+		"GI 070x SD-Card",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		0 ),
+
+UNUSUAL_DEV( 0x0af0, 0xd057, 0x0000, 0x0000,
+		"Option",
+		"GI 1505 SD-Card",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		0 ),
+
+UNUSUAL_DEV( 0x0af0, 0xd058, 0x0000, 0x0000,
+		"Option",
+		"GI 1509 SD-Card",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		0 ),
+
+UNUSUAL_DEV( 0x0af0, 0xd157, 0x0000, 0x0000,
+		"Option",
+		"GI 1515 SD-Card",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		0 ),
+
+UNUSUAL_DEV( 0x0af0, 0xd257, 0x0000, 0x0000,
+		"Option",
+		"GI 1215 SD-Card",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		0 ),
+
+UNUSUAL_DEV( 0x0af0, 0xd357, 0x0000, 0x0000,
+		"Option",
+		"GI 1505 SD-Card",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		0 ),
+
+/* Reported by Namjae Jeon <namjae.jeon@samsung.com> */
+UNUSUAL_DEV(0x0bc2, 0x2300, 0x0000, 0x9999,
+		"Seagate",
+		"Portable HDD",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_WRITE_CACHE),
+
+/* Reported by Ben Efros <ben@pc-doctor.com> */
+UNUSUAL_DEV( 0x0bc2, 0x3010, 0x0000, 0x0000,
+		"Seagate",
+		"FreeAgent Pro",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_SANE_SENSE ),
+
+/* Reported by Kris Lindgren <kris.lindgren@gmail.com> */
+UNUSUAL_DEV( 0x0bc2, 0x3332, 0x0000, 0x9999,
+		"Seagate",
+		"External",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NO_WP_DETECT ),
+
+UNUSUAL_DEV(  0x0d49, 0x7310, 0x0000, 0x9999,
+		"Maxtor",
+		"USB to SATA",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_SANE_SENSE),
+
+/*
+ * Pete Zaitcev <zaitcev@yahoo.com>, bz#164688.
+ * The device blatantly ignores LUN and returns 1 in GetMaxLUN.
+ */
+UNUSUAL_DEV( 0x0c45, 0x1060, 0x0100, 0x0100,
+		"Unknown",
+		"Unknown",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_SINGLE_LUN ),
+
+/* Submitted by Joris Struyve <joris@struyve.be> */
+UNUSUAL_DEV( 0x0d96, 0x410a, 0x0001, 0xffff,
+		"Medion",
+		"MD 7425",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY),
+
+/*
+ * Entry for Jenoptik JD 5200z3
+ *
+ * email: car.busse@gmx.de
+ */
+UNUSUAL_DEV(  0x0d96, 0x5200, 0x0001, 0x0200,
+		"Jenoptik",
+		"JD 5200 z3",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_FIX_INQUIRY),
+
+/* Reported by  Jason Johnston <killean@shaw.ca> */
+UNUSUAL_DEV(  0x0dc4, 0x0073, 0x0000, 0x0000,
+		"Macpower Technology Co.LTD.",
+		"USB 2.0 3.5\" DEVICE",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY),
+
+/*
+ * Reported by Lubomir Blaha <tritol@trilogic.cz>
+ * I _REALLY_ don't know what 3rd, 4th number and all defines mean, but this
+ * works for me. Can anybody correct these values? (I able to test corrected
+ * version.)
+ */
+UNUSUAL_DEV( 0x0dd8, 0x1060, 0x0000, 0xffff,
+		"Netac",
+		"USB-CF-Card",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY ),
+
+/*
+ * Reported by Edward Chapman (taken from linux-usb mailing list)
+ * Netac OnlyDisk Mini U2CV2 512MB USB 2.0 Flash Drive
+ */
+UNUSUAL_DEV( 0x0dd8, 0xd202, 0x0000, 0x9999,
+		"Netac",
+		"USB Flash Disk",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+
+/*
+ * Patch by Stephan Walter <stephan.walter@epfl.ch>
+ * I don't know why, but it works...
+ */
+UNUSUAL_DEV( 0x0dda, 0x0001, 0x0012, 0x0012,
+		"WINWARD",
+		"Music Disk",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Ian McConnell <ian at emit.demon.co.uk> */
+UNUSUAL_DEV(  0x0dda, 0x0301, 0x0012, 0x0012,
+		"PNP_MP3",
+		"PNP_MP3 PLAYER",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Jim McCloskey <mcclosk@ucsc.edu> */
+UNUSUAL_DEV( 0x0e21, 0x0520, 0x0100, 0x0100,
+		"Cowon Systems",
+		"iAUDIO M5",
+		USB_SC_DEVICE, USB_PR_BULK, NULL,
+		US_FL_NEED_OVERRIDE ),
+
+/* Submitted by Antoine Mairesse <antoine.mairesse@free.fr> */
+UNUSUAL_DEV( 0x0ed1, 0x6660, 0x0100, 0x0300,
+		"USB",
+		"Solid state disk",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY ),
+
+/*
+ * Submitted by Daniel Drake <dsd@gentoo.org>
+ * Reported by dayul on the Gentoo Forums
+ */
+UNUSUAL_DEV(  0x0ea0, 0x2168, 0x0110, 0x0110,
+		"Ours Technology",
+		"Flash Disk",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Rastislav Stanik <rs_kernel@yahoo.com> */
+UNUSUAL_DEV(  0x0ea0, 0x6828, 0x0110, 0x0110,
+		"USB",
+		"Flash Disk",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/*
+ * Reported by Benjamin Schiller <sbenni@gmx.de>
+ * It is also sold by Easylite as DJ 20
+ */
+UNUSUAL_DEV(  0x0ed1, 0x7636, 0x0103, 0x0103,
+		"Typhoon",
+		"My DJ 1820",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE | US_FL_GO_SLOW | US_FL_MAX_SECTORS_64),
+
+/*
+ * Patch by Leonid Petrov mail at lpetrov.net
+ * Reported by Robert Spitzenpfeil <robert@spitzenpfeil.org>
+ * http://www.qbik.ch/usb/devices/showdev.php?id=1705
+ * Updated to 103 device by MJ Ray mjr at phonecoop.coop
+ */
+UNUSUAL_DEV(  0x0f19, 0x0103, 0x0100, 0x0100,
+		"Oracom Co., Ltd",
+		"ORC-200M",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/*
+ * David Kuehling <dvdkhlng@gmx.de>:
+ * for MP3-Player AVOX WSX-300ER (bought in Japan).  Reports lots of SCSI
+ * errors when trying to write.
+ */
+UNUSUAL_DEV(  0x0f19, 0x0105, 0x0100, 0x0100,
+		"C-MEX",
+		"A-VOX",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/* Submitted by Nick Holloway */
+UNUSUAL_DEV( 0x0f88, 0x042e, 0x0100, 0x0100,
+		"VTech",
+		"Kidizoom",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY ),
+
+/* Reported by Moritz Moeller-Herrmann <moritz-kernel@moeller-herrmann.de> */
+UNUSUAL_DEV(  0x0fca, 0x8004, 0x0201, 0x0201,
+		"Research In Motion",
+		"BlackBerry Bold 9000",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_MAX_SECTORS_64 ),
+
+/* Reported by Michael Stattmann <michael@stattmann.com> */
+UNUSUAL_DEV(  0x0fce, 0xd008, 0x0000, 0x0000,
+		"Sony Ericsson",
+		"V800-Vodafone 802",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NO_WP_DETECT ),
+
+/* Reported by The Solutor <thesolutor@gmail.com> */
+UNUSUAL_DEV(  0x0fce, 0xd0e1, 0x0000, 0x0000,
+		"Sony Ericsson",
+		"MD400",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_DEVICE),
+
+/*
+ * Reported by Jan Mate <mate@fiit.stuba.sk>
+ * and by Soeren Sonnenburg <kernel@nn7.de>
+ */
+UNUSUAL_DEV(  0x0fce, 0xe030, 0x0000, 0x0000,
+		"Sony Ericsson",
+		"P990i",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY | US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Emmanuel Vasilakis <evas@forthnet.gr> */
+UNUSUAL_DEV(  0x0fce, 0xe031, 0x0000, 0x0000,
+		"Sony Ericsson",
+		"M600i",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
+
+/* Reported by Ricardo Barberis <ricardo@dattatec.com> */
+UNUSUAL_DEV(  0x0fce, 0xe092, 0x0000, 0x0000,
+		"Sony Ericsson",
+		"P1i",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/*
+ * Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu>
+ * Tested on hardware version 1.10.
+ * Entry is needed only for the initializer function override.
+ * Devices with bcd > 110 seem to not need it while those
+ * with bcd < 110 appear to need it.
+ */
+UNUSUAL_DEV(  0x1019, 0x0c55, 0x0000, 0x0110,
+		"Desknote",
+		"UCR-61S2B",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_ucr61s2b_init,
+		0 ),
+
+UNUSUAL_DEV(  0x1058, 0x0704, 0x0000, 0x9999,
+		"Western Digital",
+		"External HDD",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_SANE_SENSE),
+
+/* Reported by Namjae Jeon <namjae.jeon@samsung.com> */
+UNUSUAL_DEV(0x1058, 0x070a, 0x0000, 0x9999,
+		"Western Digital",
+		"My Passport HDD",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_WRITE_CACHE),
+
+/*
+ * Reported by Fabio Venturi <f.venturi@tdnet.it>
+ * The device reports a vendor-specific bDeviceClass.
+ */
+UNUSUAL_DEV(  0x10d6, 0x2200, 0x0100, 0x0100,
+		"Actions Semiconductor",
+		"Mtp device",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		0),
+
+/*
+ * Reported by Pascal Terjan <pterjan@mandriva.com>
+ * Ignore driver CD mode and force into modem mode by default.
+ */
+UNUSUAL_DEV(  0x1186, 0x3e04, 0x0000, 0x0000,
+           "D-Link",
+           "USB Mass Storage",
+           USB_SC_DEVICE, USB_PR_DEVICE, option_ms_init, US_FL_IGNORE_DEVICE),
+
+/*
+ * Reported by Kevin Lloyd <linux@sierrawireless.com>
+ * Entry is needed for the initializer function override,
+ * which instructs the device to load as a modem
+ * device.
+ */
+UNUSUAL_DEV(  0x1199, 0x0fff, 0x0000, 0x9999,
+		"Sierra Wireless",
+		"USB MMC Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, sierra_ms_init,
+		0),
+
+/*
+ * Reported by Jaco Kroon <jaco@kroon.co.za>
+ * The usb-storage module found on the Digitech GNX4 (and supposedly other
+ * devices) misbehaves and causes a bunch of invalid I/O errors.
+ */
+UNUSUAL_DEV(  0x1210, 0x0003, 0x0100, 0x0100,
+		"Digitech HMG",
+		"DigiTech Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/*
+ * Reported by fangxiaozhi <huananhu@huawei.com>
+ * This brings the HUAWEI data card devices into multi-port mode
+ */
+UNUSUAL_DEV(  0x12d1, 0x1001, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1003, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1004, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1401, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1402, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1403, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1404, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1405, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1406, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1407, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1408, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1409, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x140A, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x140B, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x140C, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x140D, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x140E, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x140F, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1410, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1411, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1412, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1413, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1414, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1415, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1416, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1417, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1418, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1419, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x141A, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x141B, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x141C, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x141D, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x141E, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x141F, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1420, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1421, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1422, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1423, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1424, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1425, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1426, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1427, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1428, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1429, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x142A, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x142B, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x142C, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x142D, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x142E, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x142F, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1430, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1431, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1432, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1433, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1434, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1435, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1436, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1437, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1438, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x1439, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x143A, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x143B, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x143C, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x143D, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x143E, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+UNUSUAL_DEV(  0x12d1, 0x143F, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+
+/* Reported by Vilius Bilinkevicius <vilisas AT xxx DOT lt) */
+UNUSUAL_DEV(  0x132b, 0x000b, 0x0001, 0x0001,
+		"Minolta",
+		"Dimage Z10",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		0 ),
+
+/* Reported by Kotrla Vitezslav <kotrla@ceb.cz> */
+UNUSUAL_DEV(  0x1370, 0x6828, 0x0110, 0x0110,
+		"SWISSBIT",
+		"Black Silver",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/*
+ * Reported by Tobias Jakobi <tjakobi@math.uni-bielefeld.de>
+ * The INIC-3619 bridge is used in the StarTech SLSODDU33B
+ * SATA-USB enclosure for slimline optical drives.
+ *
+ * The quirk enables MakeMKV to properly exchange keys with
+ * an installed BD drive.
+ */
+UNUSUAL_DEV(  0x13fd, 0x3609, 0x0209, 0x0209,
+		"Initio Corporation",
+		"INIC-3619",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Qinglin Ye <yestyle@gmail.com> */
+UNUSUAL_DEV(  0x13fe, 0x3600, 0x0100, 0x0100,
+		"Kingston",
+		"DT 101 G2",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_BULK_IGNORE_TAG ),
+
+/* Reported by Francesco Foresti <frafore@tiscali.it> */
+UNUSUAL_DEV(  0x14cd, 0x6600, 0x0201, 0x0201,
+		"Super Top",
+		"IDE DEVICE",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Michael Büsch <m@bues.ch> */
+UNUSUAL_DEV(  0x152d, 0x0567, 0x0114, 0x0116,
+		"JMicron",
+		"USB to ATA/ATAPI Bridge",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_BROKEN_FUA ),
+
+/* Reported by David Kozub <zub@linux.fjfi.cvut.cz> */
+UNUSUAL_DEV(0x152d, 0x0578, 0x0000, 0x9999,
+		"JMicron",
+		"JMS567",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_BROKEN_FUA),
+
+/*
+ * Reported by Alexandre Oliva <oliva@lsd.ic.unicamp.br>
+ * JMicron responds to USN and several other SCSI ioctls with a
+ * residue that causes subsequent I/O requests to fail.  */
+UNUSUAL_DEV(  0x152d, 0x2329, 0x0100, 0x0100,
+		"JMicron",
+		"USB to ATA/ATAPI Bridge",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE | US_FL_SANE_SENSE ),
+
+/* Reported by Dmitry Nezhevenko <dion@dion.org.ua> */
+UNUSUAL_DEV(  0x152d, 0x2566, 0x0114, 0x0114,
+		"JMicron",
+		"USB to ATA/ATAPI Bridge",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_BROKEN_FUA ),
+
+/* Reported by Teijo Kinnunen <teijo.kinnunen@code-q.fi> */
+UNUSUAL_DEV(  0x152d, 0x2567, 0x0117, 0x0117,
+		"JMicron",
+		"USB to ATA/ATAPI Bridge",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_BROKEN_FUA ),
+
+/* Reported-by George Cherian <george.cherian@cavium.com> */
+UNUSUAL_DEV(0x152d, 0x9561, 0x0000, 0x9999,
+		"JMicron",
+		"JMS56x",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NO_REPORT_OPCODES),
+
+/*
+ * Entrega Technologies U1-SC25 (later Xircom PortGear PGSCSI)
+ * and Mac USB Dock USB-SCSI */
+UNUSUAL_DEV(  0x1645, 0x0007, 0x0100, 0x0133,
+		"Entrega Technologies",
+		"USB to SCSI Converter",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init,
+		US_FL_SCM_MULT_TARG ),
+
+/*
+ * Reported by Robert Schedel <r.schedel@yahoo.de>
+ * Note: this is a 'super top' device like the above 14cd/6600 device
+ */
+UNUSUAL_DEV(  0x1652, 0x6600, 0x0201, 0x0201,
+		"Teac",
+		"HD-35PUK-B",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Oliver Neukum <oneukum@suse.com> */
+UNUSUAL_DEV(  0x174c, 0x55aa, 0x0100, 0x0100,
+		"ASMedia",
+		"AS2105",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NEEDS_CAP16),
+
+/* Reported by Jesse Feddema <jdfeddema@gmail.com> */
+UNUSUAL_DEV(  0x177f, 0x0400, 0x0000, 0x0000,
+		"Yarvik",
+		"PMP400",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_BULK_IGNORE_TAG | US_FL_MAX_SECTORS_64 ),
+
+UNUSUAL_DEV(  0x1822, 0x0001, 0x0000, 0x9999,
+		"Ariston Technologies",
+		"iConnect USB to SCSI adapter",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init,
+		US_FL_SCM_MULT_TARG ),
+
+/*
+ * Reported by Hans de Goede <hdegoede@redhat.com>
+ * These Appotech controllers are found in Picture Frames, they provide a
+ * (buggy) emulation of a cdrom drive which contains the windows software
+ * Uploading of pictures happens over the corresponding /dev/sg device.
+ */
+UNUSUAL_DEV( 0x1908, 0x1315, 0x0000, 0x0000,
+		"BUILDWIN",
+		"Photo Frame",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_BAD_SENSE ),
+UNUSUAL_DEV( 0x1908, 0x1320, 0x0000, 0x0000,
+		"BUILDWIN",
+		"Photo Frame",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_BAD_SENSE ),
+UNUSUAL_DEV( 0x1908, 0x3335, 0x0200, 0x0200,
+		"BUILDWIN",
+		"Photo Frame",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NO_READ_DISC_INFO ),
+
+/*
+ * Reported by Oliver Neukum <oneukum@suse.com>
+ * This device morphes spontaneously into another device if the access
+ * pattern of Windows isn't followed. Thus writable media would be dirty
+ * if the initial instance is used. So the device is limited to its
+ * virtual CD.
+ * And yes, the concept that BCD goes up to 9 is not heeded
+ */
+UNUSUAL_DEV( 0x19d2, 0x1225, 0x0000, 0xffff,
+		"ZTE,Incorporated",
+		"ZTE WCDMA Technologies MSM",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_SINGLE_LUN ),
+
+/*
+ * Reported by Sven Geggus <sven-usbst@geggus.net>
+ * This encrypted pen drive returns bogus data for the initial READ(10).
+ */
+UNUSUAL_DEV(  0x1b1c, 0x1ab5, 0x0200, 0x0200,
+		"Corsair",
+		"Padlock v2",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_INITIAL_READ10 ),
+
+/*
+ * Reported by Hans de Goede <hdegoede@redhat.com>
+ * These are mini projectors using USB for both power and video data transport
+ * The usb-storage interface is a virtual windows driver CD, which the gm12u320
+ * driver automatically converts into framebuffer & kms dri device nodes.
+ */
+UNUSUAL_DEV( 0x1de1, 0xc102, 0x0000, 0xffff,
+		"Grain-media Technology Corp.",
+		"USB3.0 Device GM12U320",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_DEVICE ),
+
+/*
+ * Patch by Richard Schütz <r.schtz@t-online.de>
+ * This external hard drive enclosure uses a JMicron chip which
+ * needs the US_FL_IGNORE_RESIDUE flag to work properly.
+ */
+UNUSUAL_DEV(  0x1e68, 0x001b, 0x0000, 0x0000,
+		"TrekStor GmbH & Co. KG",
+		"DataStation maxi g.u",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE | US_FL_SANE_SENSE ),
+
+/* Reported by Jasper Mackenzie <scarletpimpernal@hotmail.com> */
+UNUSUAL_DEV( 0x1e74, 0x4621, 0x0000, 0x0000,
+		"Coby Electronics",
+		"MP3 Player",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_BULK_IGNORE_TAG | US_FL_MAX_SECTORS_64 ),
+
+/* Supplied with some Castlewood ORB removable drives */
+UNUSUAL_DEV(  0x2027, 0xa001, 0x0000, 0x9999,
+		"Double-H Technology",
+		"USB to SCSI Intelligent Cable",
+		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init,
+		US_FL_SCM_MULT_TARG ),
+
+UNUSUAL_DEV( 0x2116, 0x0320, 0x0001, 0x0001,
+		"ST",
+		"2A",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY),
+
+/*
+ * patch submitted by Davide Perini <perini.davide@dpsoftware.org>
+ * and Renato Perini <rperini@email.it>
+ */
+UNUSUAL_DEV(  0x22b8, 0x3010, 0x0001, 0x0001,
+		"Motorola",
+		"RAZR V3x",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY | US_FL_IGNORE_RESIDUE ),
+
+/*
+ * Patch by Constantin Baranov <const@tltsu.ru>
+ * Report by Andreas Koenecke.
+ * Motorola ROKR Z6.
+ */
+UNUSUAL_DEV(  0x22b8, 0x6426, 0x0101, 0x0101,
+		"Motorola",
+		"MSnc.",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY | US_FL_FIX_CAPACITY | US_FL_BULK_IGNORE_TAG),
+
+/* Reported by Radovan Garabik <garabik@kassiopeia.juls.savba.sk> */
+UNUSUAL_DEV(  0x2735, 0x100b, 0x0000, 0x9999,
+		"MPIO",
+		"HS200",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_GO_SLOW ),
+
+/* Reported-by: Tim Anderson <tsa@biglakesoftware.com> */
+UNUSUAL_DEV(  0x2ca3, 0x0031, 0x0000, 0x9999,
+		"DJI",
+		"CineSSD",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NO_ATA_1X),
+
+/*
+ * Reported by Frederic Marchal <frederic.marchal@wowcompany.com>
+ * Mio Moov 330
+ */
+UNUSUAL_DEV(  0x3340, 0xffff, 0x0000, 0x0000,
+		"Mitac",
+		"Mio DigiWalker USB Sync",
+		USB_SC_DEVICE,USB_PR_DEVICE,NULL,
+		US_FL_MAX_SECTORS_64 ),
+
+/* Reported by Andrey Rahmatullin <wrar@altlinux.org> */
+UNUSUAL_DEV(  0x4102, 0x1020, 0x0100,  0x0100,
+		"iRiver",
+		"MP3 T10",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Sergey Pinaev <dfo@antex.ru> */
+UNUSUAL_DEV(  0x4102, 0x1059, 0x0000,  0x0000,
+               "iRiver",
+               "P7K",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_MAX_SECTORS_64 ),
+
+/*
+ * David Härdeman <david@2gen.com>
+ * The key makes the SCSI stack print confusing (but harmless) messages
+ */
+UNUSUAL_DEV(  0x4146, 0xba01, 0x0100, 0x0100,
+		"Iomega",
+		"Micro Mini 1GB",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ),
+
+/* "G-DRIVE" external HDD hangs on write without these.
+ * Patch submitted by Alexander Kappner <agk@godking.net>
+ */
+UNUSUAL_DEV(0x4971, 0x8024, 0x0000, 0x9999,
+		"SimpleTech",
+		"External HDD",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_ALWAYS_SYNC),
+
+/*
+ * Nick Bowler <nbowler@elliptictech.com>
+ * SCSI stack spams (otherwise harmless) error messages.
+ */
+UNUSUAL_DEV(  0xc251, 0x4003, 0x0100, 0x0100,
+		"Keil Software, Inc.",
+		"V2M MotherBoard",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NOT_LOCKABLE),
+
+/* Reported by Andrew Simmons <andrew.simmons@gmail.com> */
+UNUSUAL_DEV(  0xed06, 0x4500, 0x0001, 0x0001,
+		"DataStor",
+		"USB4500 FW1.04",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_CAPACITY_HEURISTICS),
+
+/* Reported by Alessio Treglia <quadrispro@ubuntu.com> */
+UNUSUAL_DEV( 0xed10, 0x7636, 0x0001, 0x0001,
+		"TGE",
+		"Digital MP3 Audio Player",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ),
+
+/* Unusual uas devices */
+#if IS_ENABLED(CONFIG_USB_UAS)
+#include "unusual_uas.h"
+#endif
+
+/* Control/Bulk transport for all SubClass values */
+USUAL_DEV(USB_SC_RBC, USB_PR_CB),
+USUAL_DEV(USB_SC_8020, USB_PR_CB),
+USUAL_DEV(USB_SC_QIC, USB_PR_CB),
+USUAL_DEV(USB_SC_UFI, USB_PR_CB),
+USUAL_DEV(USB_SC_8070, USB_PR_CB),
+USUAL_DEV(USB_SC_SCSI, USB_PR_CB),
+
+/* Control/Bulk/Interrupt transport for all SubClass values */
+USUAL_DEV(USB_SC_RBC, USB_PR_CBI),
+USUAL_DEV(USB_SC_8020, USB_PR_CBI),
+USUAL_DEV(USB_SC_QIC, USB_PR_CBI),
+USUAL_DEV(USB_SC_UFI, USB_PR_CBI),
+USUAL_DEV(USB_SC_8070, USB_PR_CBI),
+USUAL_DEV(USB_SC_SCSI, USB_PR_CBI),
+
+/* Bulk-only transport for all SubClass values */
+USUAL_DEV(USB_SC_RBC, USB_PR_BULK),
+USUAL_DEV(USB_SC_8020, USB_PR_BULK),
+USUAL_DEV(USB_SC_QIC, USB_PR_BULK),
+USUAL_DEV(USB_SC_UFI, USB_PR_BULK),
+USUAL_DEV(USB_SC_8070, USB_PR_BULK),
+USUAL_DEV(USB_SC_SCSI, USB_PR_BULK),
diff --git a/drivers/usb/storage/unusual_ene_ub6250.h b/drivers/usb/storage/unusual_ene_ub6250.h
new file mode 100644
index 0000000..9134b91
--- /dev/null
+++ b/drivers/usb/storage/unusual_ene_ub6250.h
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
+#if defined(CONFIG_USB_STORAGE_ENE_UB6250) || \
+		defined(CONFIG_USB_STORAGE_ENE_UB6250_MODULE)
+
+UNUSUAL_DEV(0x0cf2, 0x6250, 0x0000, 0x9999,
+		"ENE",
+		"ENE UB6250 reader",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL, 0),
+
+#endif /* defined(CONFIG_USB_STORAGE_ENE_UB6250) || ... */
diff --git a/drivers/usb/storage/unusual_freecom.h b/drivers/usb/storage/unusual_freecom.h
new file mode 100644
index 0000000..949231c
--- /dev/null
+++ b/drivers/usb/storage/unusual_freecom.h
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Unusual Devices File for the Freecom USB/IDE adaptor
+ */
+
+#if defined(CONFIG_USB_STORAGE_FREECOM) || \
+		defined(CONFIG_USB_STORAGE_FREECOM_MODULE)
+
+UNUSUAL_DEV(  0x07ab, 0xfc01, 0x0000, 0x9999,
+		"Freecom",
+		"USB-IDE",
+		USB_SC_QIC, USB_PR_FREECOM, init_freecom, 0),
+
+#endif /* defined(CONFIG_USB_STORAGE_FREECOM) || ... */
diff --git a/drivers/usb/storage/unusual_isd200.h b/drivers/usb/storage/unusual_isd200.h
new file mode 100644
index 0000000..d03a02c
--- /dev/null
+++ b/drivers/usb/storage/unusual_isd200.h
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Unusual Devices File for In-System Design, Inc. ISD200 ASIC
+ */
+
+#if defined(CONFIG_USB_STORAGE_ISD200) || \
+		defined(CONFIG_USB_STORAGE_ISD200_MODULE)
+
+UNUSUAL_DEV(  0x054c, 0x002b, 0x0100, 0x0110,
+		"Sony",
+		"Portable USB Harddrive V2",
+		USB_SC_ISD200, USB_PR_BULK, isd200_Initialization,
+		0),
+
+UNUSUAL_DEV(  0x05ab, 0x0031, 0x0100, 0x0110,
+		"In-System",
+		"USB/IDE Bridge (ATA/ATAPI)",
+		USB_SC_ISD200, USB_PR_BULK, isd200_Initialization,
+		0),
+
+UNUSUAL_DEV(  0x05ab, 0x0301, 0x0100, 0x0110,
+		"In-System",
+		"Portable USB Harddrive V2",
+		USB_SC_ISD200, USB_PR_BULK, isd200_Initialization,
+		0),
+
+UNUSUAL_DEV(  0x05ab, 0x0351, 0x0100, 0x0110,
+		"In-System",
+		"Portable USB Harddrive V2",
+		USB_SC_ISD200, USB_PR_BULK, isd200_Initialization,
+		0),
+
+UNUSUAL_DEV(  0x05ab, 0x5701, 0x0100, 0x0110,
+		"In-System",
+		"USB Storage Adapter V2",
+		USB_SC_ISD200, USB_PR_BULK, isd200_Initialization,
+		0),
+
+UNUSUAL_DEV(  0x0bf6, 0xa001, 0x0100, 0x0110,
+		"ATI",
+		"USB Cable 205",
+		USB_SC_ISD200, USB_PR_BULK, isd200_Initialization,
+		0),
+
+#endif /* defined(CONFIG_USB_STORAGE_ISD200) || ... */
diff --git a/drivers/usb/storage/unusual_jumpshot.h b/drivers/usb/storage/unusual_jumpshot.h
new file mode 100644
index 0000000..c323338
--- /dev/null
+++ b/drivers/usb/storage/unusual_jumpshot.h
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Unusual Devices File for the Lexar "Jumpshot" Compact Flash reader
+ */
+
+#if defined(CONFIG_USB_STORAGE_JUMPSHOT) || \
+		defined(CONFIG_USB_STORAGE_JUMPSHOT_MODULE)
+
+UNUSUAL_DEV(  0x05dc, 0x0001, 0x0000, 0x0001,
+		"Lexar",
+		"Jumpshot USB CF Reader",
+		USB_SC_SCSI, USB_PR_JUMPSHOT, NULL,
+		US_FL_NEED_OVERRIDE),
+
+#endif /* defined(CONFIG_USB_STORAGE_JUMPSHOT) || ... */
diff --git a/drivers/usb/storage/unusual_karma.h b/drivers/usb/storage/unusual_karma.h
new file mode 100644
index 0000000..8f1eebd
--- /dev/null
+++ b/drivers/usb/storage/unusual_karma.h
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Unusual Devices File for the Rio Karma
+ */
+
+#if defined(CONFIG_USB_STORAGE_KARMA) || \
+		defined(CONFIG_USB_STORAGE_KARMA_MODULE)
+
+UNUSUAL_DEV(  0x045a, 0x5210, 0x0101, 0x0101,
+		"Rio",
+		"Rio Karma",
+		USB_SC_SCSI, USB_PR_KARMA, rio_karma_init, 0),
+
+#endif /* defined(CONFIG_USB_STORAGE_KARMA) || ... */
diff --git a/drivers/usb/storage/unusual_onetouch.h b/drivers/usb/storage/unusual_onetouch.h
new file mode 100644
index 0000000..c76d4e9
--- /dev/null
+++ b/drivers/usb/storage/unusual_onetouch.h
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Unusual Devices File for the Maxtor OneTouch USB hard drive's button
+ */
+
+#if defined(CONFIG_USB_STORAGE_ONETOUCH) || \
+		defined(CONFIG_USB_STORAGE_ONETOUCH_MODULE)
+
+/*
+ * Submitted by: Nick Sillik <n.sillik@temple.edu>
+ * Needed for OneTouch extension to usb-storage
+ */
+UNUSUAL_DEV(  0x0d49, 0x7000, 0x0000, 0x9999,
+		"Maxtor",
+		"OneTouch External Harddrive",
+		USB_SC_DEVICE, USB_PR_DEVICE, onetouch_connect_input,
+		0),
+
+UNUSUAL_DEV(  0x0d49, 0x7010, 0x0000, 0x9999,
+		"Maxtor",
+		"OneTouch External Harddrive",
+		USB_SC_DEVICE, USB_PR_DEVICE, onetouch_connect_input,
+		0),
+
+#endif /* defined(CONFIG_USB_STORAGE_ONETOUCH) || ... */
diff --git a/drivers/usb/storage/unusual_realtek.h b/drivers/usb/storage/unusual_realtek.h
new file mode 100644
index 0000000..6b2140f
--- /dev/null
+++ b/drivers/usb/storage/unusual_realtek.h
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for Realtek RTS51xx USB card reader
+ *
+ * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved.
+ *
+ * Author:
+ *   wwang (wei_wang@realsil.com.cn)
+ *   No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
+ */
+
+#if defined(CONFIG_USB_STORAGE_REALTEK) || \
+		defined(CONFIG_USB_STORAGE_REALTEK_MODULE)
+
+UNUSUAL_DEV(0x0bda, 0x0138, 0x0000, 0x9999,
+		"Realtek",
+		"USB Card Reader",
+		USB_SC_DEVICE, USB_PR_DEVICE, init_realtek_cr, 0),
+
+UNUSUAL_DEV(0x0bda, 0x0158, 0x0000, 0x9999,
+		"Realtek",
+		"USB Card Reader",
+		USB_SC_DEVICE, USB_PR_DEVICE, init_realtek_cr, 0),
+
+UNUSUAL_DEV(0x0bda, 0x0159, 0x0000, 0x9999,
+		"Realtek",
+		"USB Card Reader",
+		USB_SC_DEVICE, USB_PR_DEVICE, init_realtek_cr, 0),
+
+UNUSUAL_DEV(0x0bda, 0x0177, 0x0000, 0x9999,
+		"Realtek",
+		"USB Card Reader",
+		USB_SC_DEVICE, USB_PR_DEVICE, init_realtek_cr, 0),
+
+UNUSUAL_DEV(0x0bda, 0x0184, 0x0000, 0x9999,
+		"Realtek",
+		"USB Card Reader",
+		USB_SC_DEVICE, USB_PR_DEVICE, init_realtek_cr, 0),
+
+#endif  /* defined(CONFIG_USB_STORAGE_REALTEK) || ... */
diff --git a/drivers/usb/storage/unusual_sddr09.h b/drivers/usb/storage/unusual_sddr09.h
new file mode 100644
index 0000000..650cf28
--- /dev/null
+++ b/drivers/usb/storage/unusual_sddr09.h
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Unusual Devices File for SanDisk SDDR-09 SmartMedia reader
+ */
+
+#if defined(CONFIG_USB_STORAGE_SDDR09) || \
+		defined(CONFIG_USB_STORAGE_SDDR09_MODULE)
+
+UNUSUAL_DEV(  0x0436, 0x0005, 0x0100, 0x0100,
+		"Microtech",
+		"CameraMate (DPCM_USB)",
+		USB_SC_SCSI, USB_PR_DPCM_USB, NULL, 0),
+
+UNUSUAL_DEV(  0x04e6, 0x0003, 0x0000, 0x9999,
+		"Sandisk",
+		"ImageMate SDDR09",
+		USB_SC_SCSI, USB_PR_EUSB_SDDR09, usb_stor_sddr09_init,
+		0),
+
+/* This entry is from Andries.Brouwer@cwi.nl */
+UNUSUAL_DEV(  0x04e6, 0x0005, 0x0100, 0x0208,
+		"SCM Microsystems",
+		"eUSB SmartMedia / CompactFlash Adapter",
+		USB_SC_SCSI, USB_PR_DPCM_USB, usb_stor_sddr09_dpcm_init,
+		0),
+
+UNUSUAL_DEV(  0x066b, 0x0105, 0x0100, 0x0100,
+		"Olympus",
+		"Camedia MAUSB-2",
+		USB_SC_SCSI, USB_PR_EUSB_SDDR09, usb_stor_sddr09_init,
+		0),
+
+UNUSUAL_DEV(  0x0781, 0x0200, 0x0000, 0x9999,
+		"Sandisk",
+		"ImageMate SDDR-09",
+		USB_SC_SCSI, USB_PR_EUSB_SDDR09, usb_stor_sddr09_init,
+		0),
+
+UNUSUAL_DEV(  0x07af, 0x0006, 0x0100, 0x0100,
+		"Microtech",
+		"CameraMate (DPCM_USB)",
+		USB_SC_SCSI, USB_PR_DPCM_USB, NULL, 0),
+
+#endif /* defined(CONFIG_USB_STORAGE_SDDR09) || ... */
diff --git a/drivers/usb/storage/unusual_sddr55.h b/drivers/usb/storage/unusual_sddr55.h
new file mode 100644
index 0000000..e89df2c
--- /dev/null
+++ b/drivers/usb/storage/unusual_sddr55.h
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Unusual Devices File for SanDisk SDDR-55 SmartMedia reader
+ */
+
+#if defined(CONFIG_USB_STORAGE_SDDR55) || \
+		defined(CONFIG_USB_STORAGE_SDDR55_MODULE)
+
+/* Contributed by Peter Waechtler */
+UNUSUAL_DEV( 0x07c4, 0xa103, 0x0000, 0x9999,
+		"Datafab",
+		"MDSM-B reader",
+		USB_SC_SCSI, USB_PR_SDDR55, NULL,
+		US_FL_FIX_INQUIRY),
+
+/* SM part - aeb <Andries.Brouwer@cwi.nl> */
+UNUSUAL_DEV(  0x07c4, 0xa109, 0x0000, 0xffff,
+		"Datafab Systems, Inc.",
+		"USB to CF + SM Combo (LC1)",
+		USB_SC_SCSI, USB_PR_SDDR55, NULL, 0),
+
+UNUSUAL_DEV( 0x0c0b, 0xa109, 0x0000, 0xffff,
+		"Acomdata",
+		"SM",
+		USB_SC_SCSI, USB_PR_SDDR55, NULL, 0),
+
+UNUSUAL_DEV(  0x55aa, 0xa103, 0x0000, 0x9999,
+		"Sandisk",
+		"ImageMate SDDR55",
+		USB_SC_SCSI, USB_PR_SDDR55, NULL, 0),
+
+#endif /* defined(CONFIG_USB_STORAGE_SDDR55) || ... */
diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h
new file mode 100644
index 0000000..d0bdebd
--- /dev/null
+++ b/drivers/usb/storage/unusual_uas.h
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for USB Attached SCSI devices - Unusual Devices File
+ *
+ *   (c) 2013 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Based on the same file for the usb-storage driver, which is:
+ *   (c) 2000-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *   (c) 2000 Adam J. Richter (adam@yggdrasil.com), Yggdrasil Computing, Inc.
+ */
+
+/*
+ * IMPORTANT NOTE: This file must be included in another file which defines
+ * a UNUSUAL_DEV macro before this file is included.
+ */
+
+/*
+ * If you edit this file, please try to keep it sorted first by VendorID,
+ * then by ProductID.
+ *
+ * If you want to add an entry for this file, be sure to include the
+ * following information:
+ *	- a patch that adds the entry for your device, including your
+ *	  email address right above the entry (plus maybe a brief
+ *	  explanation of the reason for the entry),
+ *	- lsusb -v output for the device
+ * Send your submission to Hans de Goede <hdegoede@redhat.com>
+ * and don't forget to CC: the USB development list <linux-usb@vger.kernel.org>
+ */
+
+/*
+ * Apricorn USB3 dongle sometimes returns "USBSUSBSUSBS" in response to SCSI
+ * commands in UAS mode.  Observed with the 1.28 firmware; are there others?
+ */
+UNUSUAL_DEV(0x0984, 0x0301, 0x0128, 0x0128,
+		"Apricorn",
+		"",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_UAS),
+
+/* Reported-by: David Webb <djw@noc.ac.uk> */
+UNUSUAL_DEV(0x0bc2, 0x331a, 0x0000, 0x9999,
+		"Seagate",
+		"Expansion Desk",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NO_REPORT_LUNS),
+
+/* Reported-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> */
+UNUSUAL_DEV(0x13fd, 0x3940, 0x0000, 0x9999,
+		"Initio Corporation",
+		"INIC-3069",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NO_ATA_1X | US_FL_IGNORE_RESIDUE),
+
+/* Reported-by: Tom Arild Naess <tanaess@gmail.com> */
+UNUSUAL_DEV(0x152d, 0x0539, 0x0000, 0x9999,
+		"JMicron",
+		"JMS539",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NO_REPORT_OPCODES),
+
+/* Reported-by: Claudio Bizzarri <claudio.bizzarri@gmail.com> */
+UNUSUAL_DEV(0x152d, 0x0567, 0x0000, 0x9999,
+		"JMicron",
+		"JMS567",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_BROKEN_FUA | US_FL_NO_REPORT_OPCODES),
+
+/* Reported-by: David Kozub <zub@linux.fjfi.cvut.cz> */
+UNUSUAL_DEV(0x152d, 0x0578, 0x0000, 0x9999,
+		"JMicron",
+		"JMS567",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_BROKEN_FUA),
+
+/* Reported-by: Hans de Goede <hdegoede@redhat.com> */
+UNUSUAL_DEV(0x2109, 0x0711, 0x0000, 0x9999,
+		"VIA",
+		"VL711",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NO_ATA_1X),
+
+/* Reported-by: Icenowy Zheng <icenowy@aosc.io> */
+UNUSUAL_DEV(0x2537, 0x1068, 0x0000, 0x9999,
+		"Norelsys",
+		"NS1068X",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_UAS),
+
+/* Reported-by: Takeo Nakayama <javhera@gmx.com> */
+UNUSUAL_DEV(0x357d, 0x7788, 0x0000, 0x9999,
+		"JMicron",
+		"JMS566",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NO_REPORT_OPCODES),
+
+/* Reported-by: Hans de Goede <hdegoede@redhat.com> */
+UNUSUAL_DEV(0x4971, 0x1012, 0x0000, 0x9999,
+		"Hitachi",
+		"External HDD",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_IGNORE_UAS),
+
+/* Reported-by: Richard Henderson <rth@redhat.com> */
+UNUSUAL_DEV(0x4971, 0x8017, 0x0000, 0x9999,
+		"SimpleTech",
+		"External HDD",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_NO_REPORT_OPCODES),
+
+/* "G-DRIVE" external HDD hangs on write without these.
+ * Patch submitted by Alexander Kappner <agk@godking.net>
+ */
+UNUSUAL_DEV(0x4971, 0x8024, 0x0000, 0x9999,
+		"SimpleTech",
+		"External HDD",
+		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+		US_FL_ALWAYS_SYNC),
diff --git a/drivers/usb/storage/unusual_usbat.h b/drivers/usb/storage/unusual_usbat.h
new file mode 100644
index 0000000..05abf68
--- /dev/null
+++ b/drivers/usb/storage/unusual_usbat.h
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Unusual Devices File for SCM Microsystems (a.k.a. Shuttle) USB-ATAPI cable
+ */
+
+#if defined(CONFIG_USB_STORAGE_USBAT) || \
+		defined(CONFIG_USB_STORAGE_USBAT_MODULE)
+
+UNUSUAL_DEV(  0x03f0, 0x0207, 0x0001, 0x0001,
+		"HP",
+		"CD-Writer+ 8200e",
+		USB_SC_8070, USB_PR_USBAT, init_usbat_cd, 0),
+
+UNUSUAL_DEV(  0x03f0, 0x0307, 0x0001, 0x0001,
+		"HP",
+		"CD-Writer+ CD-4e",
+		USB_SC_8070, USB_PR_USBAT, init_usbat_cd, 0),
+
+UNUSUAL_DEV(  0x04e6, 0x1010, 0x0000, 0x9999,
+		"Shuttle/SCM",
+		"USBAT-02",
+		USB_SC_SCSI, USB_PR_USBAT, init_usbat_flash,
+		US_FL_SINGLE_LUN),
+
+UNUSUAL_DEV(  0x0781, 0x0005, 0x0005, 0x0005,
+		"Sandisk",
+		"ImageMate SDDR-05b",
+		USB_SC_SCSI, USB_PR_USBAT, init_usbat_flash,
+		US_FL_SINGLE_LUN),
+
+#endif /* defined(CONFIG_USB_STORAGE_USBAT) || ... */
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
new file mode 100644
index 0000000..9a79cd9
--- /dev/null
+++ b/drivers/usb/storage/usb.c
@@ -0,0 +1,1156 @@
+// 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 "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;
+module_param(delay_use, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device");
+
+static char quirks[128];
+module_param_string(quirks, quirks, sizeof(quirks), S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks");
+
+
+/*
+ * The entries in this table correspond, line for line,
+ * with the entries in usb_storage_usb_ids[], defined in usual-tables.c.
+ */
+
+/*
+ *The vendor name should be kept at eight characters or less, and
+ * the product name should be kept at 16 characters or less. If a device
+ * has the US_FL_FIX_INQUIRY flag, then the vendor and product names
+ * normally generated by a device through the INQUIRY response will be
+ * taken from this list, and this is the reason for the above size
+ * restriction. However, if the flag is not present, then you
+ * are free to use as many characters as you like.
+ */
+
+#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
+		    vendor_name, product_name, use_protocol, use_transport, \
+		    init_function, Flags) \
+{ \
+	.vendorName = vendor_name,	\
+	.productName = product_name,	\
+	.useProtocol = use_protocol,	\
+	.useTransport = use_transport,	\
+	.initFunction = init_function,	\
+}
+
+#define COMPLIANT_DEV	UNUSUAL_DEV
+
+#define USUAL_DEV(use_protocol, use_transport) \
+{ \
+	.useProtocol = use_protocol,	\
+	.useTransport = use_transport,	\
+}
+
+#define UNUSUAL_VENDOR_INTF(idVendor, cl, sc, pr, \
+		vendor_name, product_name, use_protocol, use_transport, \
+		init_function, Flags) \
+{ \
+	.vendorName = vendor_name,	\
+	.productName = product_name,	\
+	.useProtocol = use_protocol,	\
+	.useTransport = use_transport,	\
+	.initFunction = init_function,	\
+}
+
+static struct us_unusual_dev us_unusual_dev_list[] = {
+#	include "unusual_devs.h"
+	{ }		/* Terminating entry */
+};
+
+static struct us_unusual_dev for_dynamic_ids =
+		USUAL_DEV(USB_SC_SCSI, USB_PR_BULK);
+
+#undef UNUSUAL_DEV
+#undef COMPLIANT_DEV
+#undef USUAL_DEV
+#undef UNUSUAL_VENDOR_INTF
+
+#ifdef CONFIG_LOCKDEP
+
+static struct lock_class_key us_interface_key[USB_MAXINTERFACES];
+
+static void us_set_lock_class(struct mutex *mutex,
+		struct usb_interface *intf)
+{
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct usb_host_config *config = udev->actconfig;
+	int i;
+
+	for (i = 0; i < config->desc.bNumInterfaces; i++) {
+		if (config->interface[i] == intf)
+			break;
+	}
+
+	BUG_ON(i == config->desc.bNumInterfaces);
+
+	lockdep_set_class(mutex, &us_interface_key[i]);
+}
+
+#else
+
+static void us_set_lock_class(struct mutex *mutex,
+		struct usb_interface *intf)
+{
+}
+
+#endif
+
+#ifdef CONFIG_PM	/* Minimal support for suspend and resume */
+
+int usb_stor_suspend(struct usb_interface *iface, pm_message_t message)
+{
+	struct us_data *us = usb_get_intfdata(iface);
+
+	/* Wait until no command is running */
+	mutex_lock(&us->dev_mutex);
+
+	if (us->suspend_resume_hook)
+		(us->suspend_resume_hook)(us, US_SUSPEND);
+
+	/*
+	 * When runtime PM is working, we'll set a flag to indicate
+	 * whether we should autoresume when a SCSI request arrives.
+	 */
+
+	mutex_unlock(&us->dev_mutex);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_stor_suspend);
+
+int usb_stor_resume(struct usb_interface *iface)
+{
+	struct us_data *us = usb_get_intfdata(iface);
+
+	mutex_lock(&us->dev_mutex);
+
+	if (us->suspend_resume_hook)
+		(us->suspend_resume_hook)(us, US_RESUME);
+
+	mutex_unlock(&us->dev_mutex);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_stor_resume);
+
+int usb_stor_reset_resume(struct usb_interface *iface)
+{
+	struct us_data *us = usb_get_intfdata(iface);
+
+	/* Report the reset to the SCSI core */
+	usb_stor_report_bus_reset(us);
+
+	/*
+	 * If any of the subdrivers implemented a reinitialization scheme,
+	 * this is where the callback would be invoked.
+	 */
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_stor_reset_resume);
+
+#endif /* CONFIG_PM */
+
+/*
+ * The next two routines get called just before and just after
+ * a USB port reset, whether from this driver or a different one.
+ */
+
+int usb_stor_pre_reset(struct usb_interface *iface)
+{
+	struct us_data *us = usb_get_intfdata(iface);
+
+	/* Make sure no command runs during the reset */
+	mutex_lock(&us->dev_mutex);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_stor_pre_reset);
+
+int usb_stor_post_reset(struct usb_interface *iface)
+{
+	struct us_data *us = usb_get_intfdata(iface);
+
+	/* Report the reset to the SCSI core */
+	usb_stor_report_bus_reset(us);
+
+	/*
+	 * If any of the subdrivers implemented a reinitialization scheme,
+	 * this is where the callback would be invoked.
+	 */
+
+	mutex_unlock(&us->dev_mutex);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_stor_post_reset);
+
+/*
+ * fill_inquiry_response takes an unsigned char array (which must
+ * be at least 36 characters) and populates the vendor name,
+ * product name, and revision fields. Then the array is copied
+ * into the SCSI command's response buffer (oddly enough
+ * called request_buffer). data_len contains the length of the
+ * data array, which again must be at least 36.
+ */
+
+void fill_inquiry_response(struct us_data *us, unsigned char *data,
+		unsigned int data_len)
+{
+	if (data_len < 36) /* You lose. */
+		return;
+
+	memset(data+8, ' ', 28);
+	if (data[0]&0x20) { /*
+			     * USB device currently not connected. Return
+			     * peripheral qualifier 001b ("...however, the
+			     * physical device is not currently connected
+			     * to this logical unit") and leave vendor and
+			     * product identification empty. ("If the target
+			     * does store some of the INQUIRY data on the
+			     * device, it may return zeros or ASCII spaces
+			     * (20h) in those fields until the data is
+			     * available from the device.").
+			     */
+	} else {
+		u16 bcdDevice = le16_to_cpu(us->pusb_dev->descriptor.bcdDevice);
+		int n;
+
+		n = strlen(us->unusual_dev->vendorName);
+		memcpy(data+8, us->unusual_dev->vendorName, min(8, n));
+		n = strlen(us->unusual_dev->productName);
+		memcpy(data+16, us->unusual_dev->productName, min(16, n));
+
+		data[32] = 0x30 + ((bcdDevice>>12) & 0x0F);
+		data[33] = 0x30 + ((bcdDevice>>8) & 0x0F);
+		data[34] = 0x30 + ((bcdDevice>>4) & 0x0F);
+		data[35] = 0x30 + ((bcdDevice) & 0x0F);
+	}
+
+	usb_stor_set_xfer_buf(data, data_len, us->srb);
+}
+EXPORT_SYMBOL_GPL(fill_inquiry_response);
+
+static int usb_stor_control_thread(void * __us)
+{
+	struct us_data *us = (struct us_data *)__us;
+	struct Scsi_Host *host = us_to_host(us);
+	struct scsi_cmnd *srb;
+
+	for (;;) {
+		usb_stor_dbg(us, "*** thread sleeping\n");
+		if (wait_for_completion_interruptible(&us->cmnd_ready))
+			break;
+
+		usb_stor_dbg(us, "*** thread awakened\n");
+
+		/* lock the device pointers */
+		mutex_lock(&(us->dev_mutex));
+
+		/* lock access to the state */
+		scsi_lock(host);
+
+		/* When we are called with no command pending, we're done */
+		srb = us->srb;
+		if (srb == NULL) {
+			scsi_unlock(host);
+			mutex_unlock(&us->dev_mutex);
+			usb_stor_dbg(us, "-- exiting\n");
+			break;
+		}
+
+		/* has the command timed out *already* ? */
+		if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
+			srb->result = DID_ABORT << 16;
+			goto SkipForAbort;
+		}
+
+		scsi_unlock(host);
+
+		/*
+		 * reject the command if the direction indicator
+		 * is UNKNOWN
+		 */
+		if (srb->sc_data_direction == DMA_BIDIRECTIONAL) {
+			usb_stor_dbg(us, "UNKNOWN data direction\n");
+			srb->result = DID_ERROR << 16;
+		}
+
+		/*
+		 * reject if target != 0 or if LUN is higher than
+		 * the maximum known LUN
+		 */
+		else if (srb->device->id &&
+				!(us->fflags & US_FL_SCM_MULT_TARG)) {
+			usb_stor_dbg(us, "Bad target number (%d:%llu)\n",
+				     srb->device->id,
+				     srb->device->lun);
+			srb->result = DID_BAD_TARGET << 16;
+		}
+
+		else if (srb->device->lun > us->max_lun) {
+			usb_stor_dbg(us, "Bad LUN (%d:%llu)\n",
+				     srb->device->id,
+				     srb->device->lun);
+			srb->result = DID_BAD_TARGET << 16;
+		}
+
+		/*
+		 * Handle those devices which need us to fake
+		 * their inquiry data
+		 */
+		else if ((srb->cmnd[0] == INQUIRY) &&
+			    (us->fflags & US_FL_FIX_INQUIRY)) {
+			unsigned char data_ptr[36] = {
+			    0x00, 0x80, 0x02, 0x02,
+			    0x1F, 0x00, 0x00, 0x00};
+
+			usb_stor_dbg(us, "Faking INQUIRY command\n");
+			fill_inquiry_response(us, data_ptr, 36);
+			srb->result = SAM_STAT_GOOD;
+		}
+
+		/* we've got a command, let's do it! */
+		else {
+			US_DEBUG(usb_stor_show_command(us, srb));
+			us->proto_handler(srb, us);
+			usb_mark_last_busy(us->pusb_dev);
+		}
+
+		/* lock access to the state */
+		scsi_lock(host);
+
+		/* was the command aborted? */
+		if (srb->result == DID_ABORT << 16) {
+SkipForAbort:
+			usb_stor_dbg(us, "scsi command aborted\n");
+			srb = NULL;	/* Don't call srb->scsi_done() */
+		}
+
+		/*
+		 * If an abort request was received we need to signal that
+		 * the abort has finished.  The proper test for this is
+		 * the TIMED_OUT flag, not srb->result == DID_ABORT, because
+		 * the timeout might have occurred after the command had
+		 * already completed with a different result code.
+		 */
+		if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
+			complete(&(us->notify));
+
+			/* Allow USB transfers to resume */
+			clear_bit(US_FLIDX_ABORTING, &us->dflags);
+			clear_bit(US_FLIDX_TIMED_OUT, &us->dflags);
+		}
+
+		/* finished working on this command */
+		us->srb = NULL;
+		scsi_unlock(host);
+
+		/* unlock the device pointers */
+		mutex_unlock(&us->dev_mutex);
+
+		/* now that the locks are released, notify the SCSI core */
+		if (srb) {
+			usb_stor_dbg(us, "scsi cmd done, result=0x%x\n",
+					srb->result);
+			srb->scsi_done(srb);
+		}
+	} /* for (;;) */
+
+	/* Wait until we are told to stop */
+	for (;;) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (kthread_should_stop())
+			break;
+		schedule();
+	}
+	__set_current_state(TASK_RUNNING);
+	return 0;
+}
+
+/***********************************************************************
+ * Device probing and disconnecting
+ ***********************************************************************/
+
+/* Associate our private data with the USB device */
+static int associate_dev(struct us_data *us, struct usb_interface *intf)
+{
+	/* Fill in the device-related fields */
+	us->pusb_dev = interface_to_usbdev(intf);
+	us->pusb_intf = intf;
+	us->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
+	usb_stor_dbg(us, "Vendor: 0x%04x, Product: 0x%04x, Revision: 0x%04x\n",
+		     le16_to_cpu(us->pusb_dev->descriptor.idVendor),
+		     le16_to_cpu(us->pusb_dev->descriptor.idProduct),
+		     le16_to_cpu(us->pusb_dev->descriptor.bcdDevice));
+	usb_stor_dbg(us, "Interface Subclass: 0x%02x, Protocol: 0x%02x\n",
+		     intf->cur_altsetting->desc.bInterfaceSubClass,
+		     intf->cur_altsetting->desc.bInterfaceProtocol);
+
+	/* Store our private data in the interface */
+	usb_set_intfdata(intf, us);
+
+	/* Allocate the control/setup and DMA-mapped buffers */
+	us->cr = kmalloc(sizeof(*us->cr), GFP_KERNEL);
+	if (!us->cr)
+		return -ENOMEM;
+
+	us->iobuf = usb_alloc_coherent(us->pusb_dev, US_IOBUF_SIZE,
+			GFP_KERNEL, &us->iobuf_dma);
+	if (!us->iobuf) {
+		usb_stor_dbg(us, "I/O buffer allocation failed\n");
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+/* Works only for digits and letters, but small and fast */
+#define TOLOWER(x) ((x) | 0x20)
+
+/* Adjust device flags based on the "quirks=" module parameter */
+void usb_stor_adjust_quirks(struct usb_device *udev, unsigned long *fflags)
+{
+	char *p;
+	u16 vid = le16_to_cpu(udev->descriptor.idVendor);
+	u16 pid = le16_to_cpu(udev->descriptor.idProduct);
+	unsigned f = 0;
+	unsigned int mask = (US_FL_SANE_SENSE | US_FL_BAD_SENSE |
+			US_FL_FIX_CAPACITY | US_FL_IGNORE_UAS |
+			US_FL_CAPACITY_HEURISTICS | US_FL_IGNORE_DEVICE |
+			US_FL_NOT_LOCKABLE | US_FL_MAX_SECTORS_64 |
+			US_FL_CAPACITY_OK | US_FL_IGNORE_RESIDUE |
+			US_FL_SINGLE_LUN | US_FL_NO_WP_DETECT |
+			US_FL_NO_READ_DISC_INFO | US_FL_NO_READ_CAPACITY_16 |
+			US_FL_INITIAL_READ10 | US_FL_WRITE_CACHE |
+			US_FL_NO_ATA_1X | US_FL_NO_REPORT_OPCODES |
+			US_FL_MAX_SECTORS_240 | US_FL_NO_REPORT_LUNS |
+			US_FL_ALWAYS_SYNC);
+
+	p = quirks;
+	while (*p) {
+		/* Each entry consists of VID:PID:flags */
+		if (vid == simple_strtoul(p, &p, 16) &&
+				*p == ':' &&
+				pid == simple_strtoul(p+1, &p, 16) &&
+				*p == ':')
+			break;
+
+		/* Move forward to the next entry */
+		while (*p) {
+			if (*p++ == ',')
+				break;
+		}
+	}
+	if (!*p)	/* No match */
+		return;
+
+	/* Collect the flags */
+	while (*++p && *p != ',') {
+		switch (TOLOWER(*p)) {
+		case 'a':
+			f |= US_FL_SANE_SENSE;
+			break;
+		case 'b':
+			f |= US_FL_BAD_SENSE;
+			break;
+		case 'c':
+			f |= US_FL_FIX_CAPACITY;
+			break;
+		case 'd':
+			f |= US_FL_NO_READ_DISC_INFO;
+			break;
+		case 'e':
+			f |= US_FL_NO_READ_CAPACITY_16;
+			break;
+		case 'f':
+			f |= US_FL_NO_REPORT_OPCODES;
+			break;
+		case 'g':
+			f |= US_FL_MAX_SECTORS_240;
+			break;
+		case 'h':
+			f |= US_FL_CAPACITY_HEURISTICS;
+			break;
+		case 'i':
+			f |= US_FL_IGNORE_DEVICE;
+			break;
+		case 'j':
+			f |= US_FL_NO_REPORT_LUNS;
+			break;
+		case 'l':
+			f |= US_FL_NOT_LOCKABLE;
+			break;
+		case 'm':
+			f |= US_FL_MAX_SECTORS_64;
+			break;
+		case 'n':
+			f |= US_FL_INITIAL_READ10;
+			break;
+		case 'o':
+			f |= US_FL_CAPACITY_OK;
+			break;
+		case 'p':
+			f |= US_FL_WRITE_CACHE;
+			break;
+		case 'r':
+			f |= US_FL_IGNORE_RESIDUE;
+			break;
+		case 's':
+			f |= US_FL_SINGLE_LUN;
+			break;
+		case 't':
+			f |= US_FL_NO_ATA_1X;
+			break;
+		case 'u':
+			f |= US_FL_IGNORE_UAS;
+			break;
+		case 'w':
+			f |= US_FL_NO_WP_DETECT;
+			break;
+		case 'y':
+			f |= US_FL_ALWAYS_SYNC;
+			break;
+		/* Ignore unrecognized flag characters */
+		}
+	}
+	*fflags = (*fflags & ~mask) | f;
+}
+EXPORT_SYMBOL_GPL(usb_stor_adjust_quirks);
+
+/* Get the unusual_devs entries and the string descriptors */
+static int get_device_info(struct us_data *us, const struct usb_device_id *id,
+		struct us_unusual_dev *unusual_dev)
+{
+	struct usb_device *dev = us->pusb_dev;
+	struct usb_interface_descriptor *idesc =
+		&us->pusb_intf->cur_altsetting->desc;
+	struct device *pdev = &us->pusb_intf->dev;
+
+	/* Store the entries */
+	us->unusual_dev = unusual_dev;
+	us->subclass = (unusual_dev->useProtocol == USB_SC_DEVICE) ?
+			idesc->bInterfaceSubClass :
+			unusual_dev->useProtocol;
+	us->protocol = (unusual_dev->useTransport == USB_PR_DEVICE) ?
+			idesc->bInterfaceProtocol :
+			unusual_dev->useTransport;
+	us->fflags = id->driver_info;
+	usb_stor_adjust_quirks(us->pusb_dev, &us->fflags);
+
+	if (us->fflags & US_FL_IGNORE_DEVICE) {
+		dev_info(pdev, "device ignored\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * This flag is only needed when we're in high-speed, so let's
+	 * disable it if we're in full-speed
+	 */
+	if (dev->speed != USB_SPEED_HIGH)
+		us->fflags &= ~US_FL_GO_SLOW;
+
+	if (us->fflags)
+		dev_info(pdev, "Quirks match for vid %04x pid %04x: %lx\n",
+				le16_to_cpu(dev->descriptor.idVendor),
+				le16_to_cpu(dev->descriptor.idProduct),
+				us->fflags);
+
+	/*
+	 * Log a message if a non-generic unusual_dev entry contains an
+	 * unnecessary subclass or protocol override.  This may stimulate
+	 * reports from users that will help us remove unneeded entries
+	 * from the unusual_devs.h table.
+	 */
+	if (id->idVendor || id->idProduct) {
+		static const char *msgs[3] = {
+			"an unneeded SubClass entry",
+			"an unneeded Protocol entry",
+			"unneeded SubClass and Protocol entries"};
+		struct usb_device_descriptor *ddesc = &dev->descriptor;
+		int msg = -1;
+
+		if (unusual_dev->useProtocol != USB_SC_DEVICE &&
+			us->subclass == idesc->bInterfaceSubClass)
+			msg += 1;
+		if (unusual_dev->useTransport != USB_PR_DEVICE &&
+			us->protocol == idesc->bInterfaceProtocol)
+			msg += 2;
+		if (msg >= 0 && !(us->fflags & US_FL_NEED_OVERRIDE))
+			dev_notice(pdev, "This device "
+					"(%04x,%04x,%04x S %02x P %02x)"
+					" has %s in unusual_devs.h (kernel"
+					" %s)\n"
+					"   Please send a copy of this message to "
+					"<linux-usb@vger.kernel.org> and "
+					"<usb-storage@lists.one-eyed-alien.net>\n",
+					le16_to_cpu(ddesc->idVendor),
+					le16_to_cpu(ddesc->idProduct),
+					le16_to_cpu(ddesc->bcdDevice),
+					idesc->bInterfaceSubClass,
+					idesc->bInterfaceProtocol,
+					msgs[msg],
+					utsname()->release);
+	}
+
+	return 0;
+}
+
+/* Get the transport settings */
+static void get_transport(struct us_data *us)
+{
+	switch (us->protocol) {
+	case USB_PR_CB:
+		us->transport_name = "Control/Bulk";
+		us->transport = usb_stor_CB_transport;
+		us->transport_reset = usb_stor_CB_reset;
+		us->max_lun = 7;
+		break;
+
+	case USB_PR_CBI:
+		us->transport_name = "Control/Bulk/Interrupt";
+		us->transport = usb_stor_CB_transport;
+		us->transport_reset = usb_stor_CB_reset;
+		us->max_lun = 7;
+		break;
+
+	case USB_PR_BULK:
+		us->transport_name = "Bulk";
+		us->transport = usb_stor_Bulk_transport;
+		us->transport_reset = usb_stor_Bulk_reset;
+		break;
+	}
+}
+
+/* Get the protocol settings */
+static void get_protocol(struct us_data *us)
+{
+	switch (us->subclass) {
+	case USB_SC_RBC:
+		us->protocol_name = "Reduced Block Commands (RBC)";
+		us->proto_handler = usb_stor_transparent_scsi_command;
+		break;
+
+	case USB_SC_8020:
+		us->protocol_name = "8020i";
+		us->proto_handler = usb_stor_pad12_command;
+		us->max_lun = 0;
+		break;
+
+	case USB_SC_QIC:
+		us->protocol_name = "QIC-157";
+		us->proto_handler = usb_stor_pad12_command;
+		us->max_lun = 0;
+		break;
+
+	case USB_SC_8070:
+		us->protocol_name = "8070i";
+		us->proto_handler = usb_stor_pad12_command;
+		us->max_lun = 0;
+		break;
+
+	case USB_SC_SCSI:
+		us->protocol_name = "Transparent SCSI";
+		us->proto_handler = usb_stor_transparent_scsi_command;
+		break;
+
+	case USB_SC_UFI:
+		us->protocol_name = "Uniform Floppy Interface (UFI)";
+		us->proto_handler = usb_stor_ufi_command;
+		break;
+	}
+}
+
+/* Get the pipe settings */
+static int get_pipes(struct us_data *us)
+{
+	struct usb_host_interface *alt = us->pusb_intf->cur_altsetting;
+	struct usb_endpoint_descriptor *ep_in;
+	struct usb_endpoint_descriptor *ep_out;
+	struct usb_endpoint_descriptor *ep_int;
+	int res;
+
+	/*
+	 * Find the first endpoint of each type we need.
+	 * We are expecting a minimum of 2 endpoints - in and out (bulk).
+	 * An optional interrupt-in is OK (necessary for CBI protocol).
+	 * We will ignore any others.
+	 */
+	res = usb_find_common_endpoints(alt, &ep_in, &ep_out, NULL, NULL);
+	if (res) {
+		usb_stor_dbg(us, "bulk endpoints not found\n");
+		return res;
+	}
+
+	res = usb_find_int_in_endpoint(alt, &ep_int);
+	if (res && us->protocol == USB_PR_CBI) {
+		usb_stor_dbg(us, "interrupt endpoint not found\n");
+		return res;
+	}
+
+	/* Calculate and store the pipe values */
+	us->send_ctrl_pipe = usb_sndctrlpipe(us->pusb_dev, 0);
+	us->recv_ctrl_pipe = usb_rcvctrlpipe(us->pusb_dev, 0);
+	us->send_bulk_pipe = usb_sndbulkpipe(us->pusb_dev,
+		usb_endpoint_num(ep_out));
+	us->recv_bulk_pipe = usb_rcvbulkpipe(us->pusb_dev,
+		usb_endpoint_num(ep_in));
+	if (ep_int) {
+		us->recv_intr_pipe = usb_rcvintpipe(us->pusb_dev,
+			usb_endpoint_num(ep_int));
+		us->ep_bInterval = ep_int->bInterval;
+	}
+	return 0;
+}
+
+/* Initialize all the dynamic resources we need */
+static int usb_stor_acquire_resources(struct us_data *us)
+{
+	int p;
+	struct task_struct *th;
+
+	us->current_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!us->current_urb)
+		return -ENOMEM;
+
+	/*
+	 * Just before we start our control thread, initialize
+	 * the device if it needs initialization
+	 */
+	if (us->unusual_dev->initFunction) {
+		p = us->unusual_dev->initFunction(us);
+		if (p)
+			return p;
+	}
+
+	/* Start up our control thread */
+	th = kthread_run(usb_stor_control_thread, us, "usb-storage");
+	if (IS_ERR(th)) {
+		dev_warn(&us->pusb_intf->dev,
+				"Unable to start control thread\n");
+		return PTR_ERR(th);
+	}
+	us->ctl_thread = th;
+
+	return 0;
+}
+
+/* Release all our dynamic resources */
+static void usb_stor_release_resources(struct us_data *us)
+{
+	/*
+	 * Tell the control thread to exit.  The SCSI host must
+	 * already have been removed and the DISCONNECTING flag set
+	 * so that we won't accept any more commands.
+	 */
+	usb_stor_dbg(us, "-- sending exit command to thread\n");
+	complete(&us->cmnd_ready);
+	if (us->ctl_thread)
+		kthread_stop(us->ctl_thread);
+
+	/* Call the destructor routine, if it exists */
+	if (us->extra_destructor) {
+		usb_stor_dbg(us, "-- calling extra_destructor()\n");
+		us->extra_destructor(us->extra);
+	}
+
+	/* Free the extra data and the URB */
+	kfree(us->extra);
+	usb_free_urb(us->current_urb);
+}
+
+/* Dissociate from the USB device */
+static void dissociate_dev(struct us_data *us)
+{
+	/* Free the buffers */
+	kfree(us->cr);
+	usb_free_coherent(us->pusb_dev, US_IOBUF_SIZE, us->iobuf, us->iobuf_dma);
+
+	/* Remove our private data from the interface */
+	usb_set_intfdata(us->pusb_intf, NULL);
+}
+
+/*
+ * First stage of disconnect processing: stop SCSI scanning,
+ * remove the host, and stop accepting new commands
+ */
+static void quiesce_and_remove_host(struct us_data *us)
+{
+	struct Scsi_Host *host = us_to_host(us);
+
+	/* If the device is really gone, cut short reset delays */
+	if (us->pusb_dev->state == USB_STATE_NOTATTACHED) {
+		set_bit(US_FLIDX_DISCONNECTING, &us->dflags);
+		wake_up(&us->delay_wait);
+	}
+
+	/*
+	 * Prevent SCSI scanning (if it hasn't started yet)
+	 * or wait for the SCSI-scanning routine to stop.
+	 */
+	cancel_delayed_work_sync(&us->scan_dwork);
+
+	/* Balance autopm calls if scanning was cancelled */
+	if (test_bit(US_FLIDX_SCAN_PENDING, &us->dflags))
+		usb_autopm_put_interface_no_suspend(us->pusb_intf);
+
+	/*
+	 * Removing the host will perform an orderly shutdown: caches
+	 * synchronized, disks spun down, etc.
+	 */
+	scsi_remove_host(host);
+
+	/*
+	 * Prevent any new commands from being accepted and cut short
+	 * reset delays.
+	 */
+	scsi_lock(host);
+	set_bit(US_FLIDX_DISCONNECTING, &us->dflags);
+	scsi_unlock(host);
+	wake_up(&us->delay_wait);
+}
+
+/* Second stage of disconnect processing: deallocate all resources */
+static void release_everything(struct us_data *us)
+{
+	usb_stor_release_resources(us);
+	dissociate_dev(us);
+
+	/*
+	 * Drop our reference to the host; the SCSI core will free it
+	 * (and "us" along with it) when the refcount becomes 0.
+	 */
+	scsi_host_put(us_to_host(us));
+}
+
+/* Delayed-work routine to carry out SCSI-device scanning */
+static void usb_stor_scan_dwork(struct work_struct *work)
+{
+	struct us_data *us = container_of(work, struct us_data,
+			scan_dwork.work);
+	struct device *dev = &us->pusb_intf->dev;
+
+	dev_dbg(dev, "starting scan\n");
+
+	/* For bulk-only devices, determine the max LUN value */
+	if (us->protocol == USB_PR_BULK &&
+	    !(us->fflags & US_FL_SINGLE_LUN) &&
+	    !(us->fflags & US_FL_SCM_MULT_TARG)) {
+		mutex_lock(&us->dev_mutex);
+		us->max_lun = usb_stor_Bulk_max_lun(us);
+		/*
+		 * Allow proper scanning of devices that present more than 8 LUNs
+		 * While not affecting other devices that may need the previous
+		 * behavior
+		 */
+		if (us->max_lun >= 8)
+			us_to_host(us)->max_lun = us->max_lun+1;
+		mutex_unlock(&us->dev_mutex);
+	}
+	scsi_scan_host(us_to_host(us));
+	dev_dbg(dev, "scan complete\n");
+
+	/* Should we unbind if no devices were detected? */
+
+	usb_autopm_put_interface(us->pusb_intf);
+	clear_bit(US_FLIDX_SCAN_PENDING, &us->dflags);
+}
+
+static unsigned int usb_stor_sg_tablesize(struct usb_interface *intf)
+{
+	struct usb_device *usb_dev = interface_to_usbdev(intf);
+
+	if (usb_dev->bus->sg_tablesize) {
+		return usb_dev->bus->sg_tablesize;
+	}
+	return SG_ALL;
+}
+
+/* First part of general USB mass-storage probing */
+int usb_stor_probe1(struct us_data **pus,
+		struct usb_interface *intf,
+		const struct usb_device_id *id,
+		struct us_unusual_dev *unusual_dev,
+		struct scsi_host_template *sht)
+{
+	struct Scsi_Host *host;
+	struct us_data *us;
+	int result;
+
+	dev_info(&intf->dev, "USB Mass Storage device detected\n");
+
+	/*
+	 * Ask the SCSI layer to allocate a host structure, with extra
+	 * space at the end for our private us_data structure.
+	 */
+	host = scsi_host_alloc(sht, sizeof(*us));
+	if (!host) {
+		dev_warn(&intf->dev, "Unable to allocate the scsi host\n");
+		return -ENOMEM;
+	}
+
+	/*
+	 * Allow 16-byte CDBs and thus > 2TB
+	 */
+	host->max_cmd_len = 16;
+	host->sg_tablesize = usb_stor_sg_tablesize(intf);
+	*pus = us = host_to_us(host);
+	mutex_init(&(us->dev_mutex));
+	us_set_lock_class(&us->dev_mutex, intf);
+	init_completion(&us->cmnd_ready);
+	init_completion(&(us->notify));
+	init_waitqueue_head(&us->delay_wait);
+	INIT_DELAYED_WORK(&us->scan_dwork, usb_stor_scan_dwork);
+
+	/* Associate the us_data structure with the USB device */
+	result = associate_dev(us, intf);
+	if (result)
+		goto BadDevice;
+
+	/* Get the unusual_devs entries and the descriptors */
+	result = get_device_info(us, id, unusual_dev);
+	if (result)
+		goto BadDevice;
+
+	/* Get standard transport and protocol settings */
+	get_transport(us);
+	get_protocol(us);
+
+	/*
+	 * Give the caller a chance to fill in specialized transport
+	 * or protocol settings.
+	 */
+	return 0;
+
+BadDevice:
+	usb_stor_dbg(us, "storage_probe() failed\n");
+	release_everything(us);
+	return result;
+}
+EXPORT_SYMBOL_GPL(usb_stor_probe1);
+
+/* Second part of general USB mass-storage probing */
+int usb_stor_probe2(struct us_data *us)
+{
+	int result;
+	struct device *dev = &us->pusb_intf->dev;
+
+	/* Make sure the transport and protocol have both been set */
+	if (!us->transport || !us->proto_handler) {
+		result = -ENXIO;
+		goto BadDevice;
+	}
+	usb_stor_dbg(us, "Transport: %s\n", us->transport_name);
+	usb_stor_dbg(us, "Protocol: %s\n", us->protocol_name);
+
+	if (us->fflags & US_FL_SCM_MULT_TARG) {
+		/*
+		 * SCM eUSCSI bridge devices can have different numbers
+		 * of LUNs on different targets; allow all to be probed.
+		 */
+		us->max_lun = 7;
+		/* The eUSCSI itself has ID 7, so avoid scanning that */
+		us_to_host(us)->this_id = 7;
+		/* max_id is 8 initially, so no need to set it here */
+	} else {
+		/* In the normal case there is only a single target */
+		us_to_host(us)->max_id = 1;
+		/*
+		 * Like Windows, we won't store the LUN bits in CDB[1] for
+		 * SCSI-2 devices using the Bulk-Only transport (even though
+		 * this violates the SCSI spec).
+		 */
+		if (us->transport == usb_stor_Bulk_transport)
+			us_to_host(us)->no_scsi2_lun_in_cdb = 1;
+	}
+
+	/* fix for single-lun devices */
+	if (us->fflags & US_FL_SINGLE_LUN)
+		us->max_lun = 0;
+
+	/* Find the endpoints and calculate pipe values */
+	result = get_pipes(us);
+	if (result)
+		goto BadDevice;
+
+	/*
+	 * If the device returns invalid data for the first READ(10)
+	 * command, indicate the command should be retried.
+	 */
+	if (us->fflags & US_FL_INITIAL_READ10)
+		set_bit(US_FLIDX_REDO_READ10, &us->dflags);
+
+	/* Acquire all the other resources and add the host */
+	result = usb_stor_acquire_resources(us);
+	if (result)
+		goto BadDevice;
+	usb_autopm_get_interface_no_resume(us->pusb_intf);
+	snprintf(us->scsi_name, sizeof(us->scsi_name), "usb-storage %s",
+					dev_name(&us->pusb_intf->dev));
+	result = scsi_add_host(us_to_host(us), dev);
+	if (result) {
+		dev_warn(dev,
+				"Unable to add the scsi host\n");
+		goto HostAddErr;
+	}
+
+	/* Submit the delayed_work for SCSI-device scanning */
+	set_bit(US_FLIDX_SCAN_PENDING, &us->dflags);
+
+	if (delay_use > 0)
+		dev_dbg(dev, "waiting for device to settle before scanning\n");
+	queue_delayed_work(system_freezable_wq, &us->scan_dwork,
+			delay_use * HZ);
+	return 0;
+
+	/* We come here if there are any problems */
+HostAddErr:
+	usb_autopm_put_interface_no_suspend(us->pusb_intf);
+BadDevice:
+	usb_stor_dbg(us, "storage_probe() failed\n");
+	release_everything(us);
+	return result;
+}
+EXPORT_SYMBOL_GPL(usb_stor_probe2);
+
+/* Handle a USB mass-storage disconnect */
+void usb_stor_disconnect(struct usb_interface *intf)
+{
+	struct us_data *us = usb_get_intfdata(intf);
+
+	quiesce_and_remove_host(us);
+	release_everything(us);
+}
+EXPORT_SYMBOL_GPL(usb_stor_disconnect);
+
+static struct scsi_host_template usb_stor_host_template;
+
+/* The main probe routine for standard devices */
+static int storage_probe(struct usb_interface *intf,
+			 const struct usb_device_id *id)
+{
+	struct us_unusual_dev *unusual_dev;
+	struct us_data *us;
+	int result;
+	int size;
+
+	/* If uas is enabled and this device can do uas then ignore it. */
+#if IS_ENABLED(CONFIG_USB_UAS)
+	if (uas_use_uas_driver(intf, id, NULL))
+		return -ENXIO;
+#endif
+
+	/*
+	 * If the device isn't standard (is handled by a subdriver
+	 * module) then don't accept it.
+	 */
+	if (usb_usual_ignore_device(intf))
+		return -ENXIO;
+
+	/*
+	 * Call the general probe procedures.
+	 *
+	 * The unusual_dev_list array is parallel to the usb_storage_usb_ids
+	 * table, so we use the index of the id entry to find the
+	 * corresponding unusual_devs entry.
+	 */
+
+	size = ARRAY_SIZE(us_unusual_dev_list);
+	if (id >= usb_storage_usb_ids && id < usb_storage_usb_ids + size) {
+		unusual_dev = (id - usb_storage_usb_ids) + us_unusual_dev_list;
+	} else {
+		unusual_dev = &for_dynamic_ids;
+
+		dev_dbg(&intf->dev, "Use Bulk-Only transport with the Transparent SCSI protocol for dynamic id: 0x%04x 0x%04x\n",
+			id->idVendor, id->idProduct);
+	}
+
+	result = usb_stor_probe1(&us, intf, id, unusual_dev,
+				 &usb_stor_host_template);
+	if (result)
+		return result;
+
+	/* No special transport or protocol settings in the main module */
+
+	result = usb_stor_probe2(us);
+	return result;
+}
+
+static struct usb_driver usb_storage_driver = {
+	.name =		DRV_NAME,
+	.probe =	storage_probe,
+	.disconnect =	usb_stor_disconnect,
+	.suspend =	usb_stor_suspend,
+	.resume =	usb_stor_resume,
+	.reset_resume =	usb_stor_reset_resume,
+	.pre_reset =	usb_stor_pre_reset,
+	.post_reset =	usb_stor_post_reset,
+	.id_table =	usb_storage_usb_ids,
+	.supports_autosuspend = 1,
+	.soft_unbind =	1,
+};
+
+module_usb_stor_driver(usb_storage_driver, usb_stor_host_template, DRV_NAME);
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
new file mode 100644
index 0000000..85052cd
--- /dev/null
+++ b/drivers/usb/storage/usb.h
@@ -0,0 +1,209 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for USB Mass Storage compliant devices
+ * Main Header File
+ *
+ * Current development and maintenance by:
+ *   (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * Initial work by:
+ *   (c) 1999 Michael Gee (michael@linuxspecific.com)
+ *
+ * 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.
+ */
+
+#ifndef _USB_H_
+#define _USB_H_
+
+#include <linux/usb.h>
+#include <linux/usb_usual.h>
+#include <linux/blkdev.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <scsi/scsi_host.h>
+
+struct us_data;
+struct scsi_cmnd;
+
+/*
+ * Unusual device list definitions 
+ */
+
+struct us_unusual_dev {
+	const char* vendorName;
+	const char* productName;
+	__u8  useProtocol;
+	__u8  useTransport;
+	int (*initFunction)(struct us_data *);
+};
+
+
+/* Dynamic bitflag definitions (us->dflags): used in set_bit() etc. */
+#define US_FLIDX_URB_ACTIVE	0	/* current_urb is in use    */
+#define US_FLIDX_SG_ACTIVE	1	/* current_sg is in use     */
+#define US_FLIDX_ABORTING	2	/* abort is in progress     */
+#define US_FLIDX_DISCONNECTING	3	/* disconnect in progress   */
+#define US_FLIDX_RESETTING	4	/* device reset in progress */
+#define US_FLIDX_TIMED_OUT	5	/* SCSI midlayer timed out  */
+#define US_FLIDX_SCAN_PENDING	6	/* scanning not yet done    */
+#define US_FLIDX_REDO_READ10	7	/* redo READ(10) command    */
+#define US_FLIDX_READ10_WORKED	8	/* previous READ(10) succeeded */
+
+#define USB_STOR_STRING_LEN 32
+
+/*
+ * We provide a DMA-mapped I/O buffer for use with small USB transfers.
+ * It turns out that CB[I] needs a 12-byte buffer and Bulk-only needs a
+ * 31-byte buffer.  But Freecom needs a 64-byte buffer, so that's the
+ * size we'll allocate.
+ */
+
+#define US_IOBUF_SIZE		64	/* Size of the DMA-mapped I/O buffer */
+#define US_SENSE_SIZE		18	/* Size of the autosense data buffer */
+
+typedef int (*trans_cmnd)(struct scsi_cmnd *, struct us_data*);
+typedef int (*trans_reset)(struct us_data*);
+typedef void (*proto_cmnd)(struct scsi_cmnd*, struct us_data*);
+typedef void (*extra_data_destructor)(void *);	/* extra data destructor */
+typedef void (*pm_hook)(struct us_data *, int);	/* power management hook */
+
+#define US_SUSPEND	0
+#define US_RESUME	1
+
+/* we allocate one of these for every device that we remember */
+struct us_data {
+	/*
+	 * The device we're working with
+	 * It's important to note:
+	 *    (o) you must hold dev_mutex to change pusb_dev
+	 */
+	struct mutex		dev_mutex;	 /* protect pusb_dev */
+	struct usb_device	*pusb_dev;	 /* this usb_device */
+	struct usb_interface	*pusb_intf;	 /* this interface */
+	struct us_unusual_dev   *unusual_dev;	 /* device-filter entry     */
+	unsigned long		fflags;		 /* fixed flags from filter */
+	unsigned long		dflags;		 /* dynamic atomic bitflags */
+	unsigned int		send_bulk_pipe;	 /* cached pipe values */
+	unsigned int		recv_bulk_pipe;
+	unsigned int		send_ctrl_pipe;
+	unsigned int		recv_ctrl_pipe;
+	unsigned int		recv_intr_pipe;
+
+	/* information about the device */
+	char			*transport_name;
+	char			*protocol_name;
+	__le32			bcs_signature;
+	u8			subclass;
+	u8			protocol;
+	u8			max_lun;
+
+	u8			ifnum;		 /* interface number   */
+	u8			ep_bInterval;	 /* interrupt interval */
+
+	/* function pointers for this device */
+	trans_cmnd		transport;	 /* transport function	   */
+	trans_reset		transport_reset; /* transport device reset */
+	proto_cmnd		proto_handler;	 /* protocol handler	   */
+
+	/* SCSI interfaces */
+	struct scsi_cmnd	*srb;		 /* current srb		*/
+	unsigned int		tag;		 /* current dCBWTag	*/
+	char			scsi_name[32];	 /* scsi_host name	*/
+
+	/* control and bulk communications data */
+	struct urb		*current_urb;	 /* USB requests	 */
+	struct usb_ctrlrequest	*cr;		 /* control requests	 */
+	struct usb_sg_request	current_sg;	 /* scatter-gather req.  */
+	unsigned char		*iobuf;		 /* I/O buffer		 */
+	dma_addr_t		iobuf_dma;	 /* buffer DMA addresses */
+	struct task_struct	*ctl_thread;	 /* the control thread   */
+
+	/* mutual exclusion and synchronization structures */
+	struct completion	cmnd_ready;	 /* to sleep thread on	    */
+	struct completion	notify;		 /* thread begin/end	    */
+	wait_queue_head_t	delay_wait;	 /* wait during reset	    */
+	struct delayed_work	scan_dwork;	 /* for async scanning      */
+
+	/* subdriver information */
+	void			*extra;		 /* Any extra data          */
+	extra_data_destructor	extra_destructor;/* extra data destructor   */
+#ifdef CONFIG_PM
+	pm_hook			suspend_resume_hook;
+#endif
+
+	/* hacks for READ CAPACITY bug handling */
+	int			use_last_sector_hacks;
+	int			last_sector_retries;
+};
+
+/* Convert between us_data and the corresponding Scsi_Host */
+static inline struct Scsi_Host *us_to_host(struct us_data *us) {
+	return container_of((void *) us, struct Scsi_Host, hostdata);
+}
+static inline struct us_data *host_to_us(struct Scsi_Host *host) {
+	return (struct us_data *) host->hostdata;
+}
+
+/* Function to fill an inquiry response. See usb.c for details */
+extern void fill_inquiry_response(struct us_data *us,
+	unsigned char *data, unsigned int data_len);
+
+/*
+ * The scsi_lock() and scsi_unlock() macros protect the sm_state and the
+ * single queue element srb for write access
+ */
+#define scsi_unlock(host)	spin_unlock_irq(host->host_lock)
+#define scsi_lock(host)		spin_lock_irq(host->host_lock)
+
+/* General routines provided by the usb-storage standard core */
+#ifdef CONFIG_PM
+extern int usb_stor_suspend(struct usb_interface *iface, pm_message_t message);
+extern int usb_stor_resume(struct usb_interface *iface);
+extern int usb_stor_reset_resume(struct usb_interface *iface);
+#else
+#define usb_stor_suspend	NULL
+#define usb_stor_resume		NULL
+#define usb_stor_reset_resume	NULL
+#endif
+
+extern int usb_stor_pre_reset(struct usb_interface *iface);
+extern int usb_stor_post_reset(struct usb_interface *iface);
+
+extern int usb_stor_probe1(struct us_data **pus,
+		struct usb_interface *intf,
+		const struct usb_device_id *id,
+		struct us_unusual_dev *unusual_dev,
+		struct scsi_host_template *sht);
+extern int usb_stor_probe2(struct us_data *us);
+extern void usb_stor_disconnect(struct usb_interface *intf);
+
+extern void usb_stor_adjust_quirks(struct usb_device *dev,
+		unsigned long *fflags);
+
+#define module_usb_stor_driver(__driver, __sht, __name) \
+static int __init __driver##_init(void) \
+{ \
+	usb_stor_host_template_init(&(__sht), __name, THIS_MODULE); \
+	return usb_register(&(__driver)); \
+} \
+module_init(__driver##_init); \
+static void __exit __driver##_exit(void) \
+{ \
+	usb_deregister(&(__driver)); \
+} \
+module_exit(__driver##_exit)
+
+#endif
diff --git a/drivers/usb/storage/usual-tables.c b/drivers/usb/storage/usual-tables.c
new file mode 100644
index 0000000..cfd12e5
--- /dev/null
+++ b/drivers/usb/storage/usual-tables.c
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for USB Mass Storage devices
+ * Usual Tables File for usb-storage and libusual
+ *
+ * Copyright (C) 2009 Alan Stern (stern@rowland.harvard.edu)
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb_usual.h>
+
+
+/*
+ * The table of devices
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+		    vendorName, productName, useProtocol, useTransport, \
+		    initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+  .driver_info = (flags) }
+
+#define COMPLIANT_DEV	UNUSUAL_DEV
+
+#define USUAL_DEV(useProto, useTrans) \
+{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, useProto, useTrans) }
+
+/* Define the device is matched with Vendor ID and interface descriptors */
+#define UNUSUAL_VENDOR_INTF(id_vendor, cl, sc, pr, \
+			vendorName, productName, useProtocol, useTransport, \
+			initFunction, flags) \
+{ \
+	.match_flags = USB_DEVICE_ID_MATCH_INT_INFO \
+				| USB_DEVICE_ID_MATCH_VENDOR, \
+	.idVendor    = (id_vendor), \
+	.bInterfaceClass = (cl), \
+	.bInterfaceSubClass = (sc), \
+	.bInterfaceProtocol = (pr), \
+	.driver_info = (flags) \
+}
+
+struct usb_device_id usb_storage_usb_ids[] = {
+#	include "unusual_devs.h"
+	{ }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, usb_storage_usb_ids);
+
+#undef UNUSUAL_DEV
+#undef COMPLIANT_DEV
+#undef USUAL_DEV
+#undef UNUSUAL_VENDOR_INTF
+
+/*
+ * The table of devices to ignore
+ */
+struct ignore_entry {
+	u16	vid, pid, bcdmin, bcdmax;
+};
+
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+		    vendorName, productName, useProtocol, useTransport, \
+		    initFunction, flags) \
+{					\
+	.vid	= id_vendor,		\
+	.pid 	= id_product,		\
+	.bcdmin	= bcdDeviceMin,		\
+	.bcdmax = bcdDeviceMax,		\
+}
+
+static struct ignore_entry ignore_ids[] = {
+#	include "unusual_alauda.h"
+#	include "unusual_cypress.h"
+#	include "unusual_datafab.h"
+#	include "unusual_ene_ub6250.h"
+#	include "unusual_freecom.h"
+#	include "unusual_isd200.h"
+#	include "unusual_jumpshot.h"
+#	include "unusual_karma.h"
+#	include "unusual_onetouch.h"
+#	include "unusual_realtek.h"
+#	include "unusual_sddr09.h"
+#	include "unusual_sddr55.h"
+#	include "unusual_usbat.h"
+	{ }		/* Terminating entry */
+};
+
+#undef UNUSUAL_DEV
+
+/* Return an error if a device is in the ignore_ids list */
+int usb_usual_ignore_device(struct usb_interface *intf)
+{
+	struct usb_device *udev;
+	unsigned vid, pid, bcd;
+	struct ignore_entry *p;
+
+	udev = interface_to_usbdev(intf);
+	vid = le16_to_cpu(udev->descriptor.idVendor);
+	pid = le16_to_cpu(udev->descriptor.idProduct);
+	bcd = le16_to_cpu(udev->descriptor.bcdDevice);
+
+	for (p = ignore_ids; p->vid; ++p) {
+		if (p->vid == vid && p->pid == pid &&
+				p->bcdmin <= bcd && p->bcdmax >= bcd)
+			return -ENXIO;
+	}
+	return 0;
+}