162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Driver for Datafab USB Compact Flash reader
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * datafab driver v0.1:
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * First release
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Current development and maintenance by:
1062306a36Sopenharmony_ci *   (c) 2000 Jimmie Mayfield (mayfield+datafab@sackheads.org)
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci *   Many thanks to Robert Baruch for the SanDisk SmartMedia reader driver
1362306a36Sopenharmony_ci *   which I used as a template for this driver.
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci *   Some bugfixes and scatter-gather code by Gregory P. Smith
1662306a36Sopenharmony_ci *   (greg-usb@electricrain.com)
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci *   Fix for media change by Joerg Schneider (js@joergschneider.com)
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci * Other contributors:
2162306a36Sopenharmony_ci *   (c) 2002 Alan Stern <stern@rowland.org>
2262306a36Sopenharmony_ci */
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/*
2562306a36Sopenharmony_ci * This driver attempts to support USB CompactFlash reader/writer devices
2662306a36Sopenharmony_ci * based on Datafab USB-to-ATA chips.  It was specifically developed for the
2762306a36Sopenharmony_ci * Datafab MDCFE-B USB CompactFlash reader but has since been found to work
2862306a36Sopenharmony_ci * with a variety of Datafab-based devices from a number of manufacturers.
2962306a36Sopenharmony_ci * I've received a report of this driver working with a Datafab-based
3062306a36Sopenharmony_ci * SmartMedia device though please be aware that I'm personally unable to
3162306a36Sopenharmony_ci * test SmartMedia support.
3262306a36Sopenharmony_ci *
3362306a36Sopenharmony_ci * This driver supports reading and writing.  If you're truly paranoid,
3462306a36Sopenharmony_ci * however, you can force the driver into a write-protected state by setting
3562306a36Sopenharmony_ci * the WP enable bits in datafab_handle_mode_sense().  See the comments
3662306a36Sopenharmony_ci * in that routine.
3762306a36Sopenharmony_ci */
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#include <linux/errno.h>
4062306a36Sopenharmony_ci#include <linux/module.h>
4162306a36Sopenharmony_ci#include <linux/slab.h>
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#include <scsi/scsi.h>
4462306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h>
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#include "usb.h"
4762306a36Sopenharmony_ci#include "transport.h"
4862306a36Sopenharmony_ci#include "protocol.h"
4962306a36Sopenharmony_ci#include "debug.h"
5062306a36Sopenharmony_ci#include "scsiglue.h"
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define DRV_NAME "ums-datafab"
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver for Datafab USB Compact Flash reader");
5562306a36Sopenharmony_ciMODULE_AUTHOR("Jimmie Mayfield <mayfield+datafab@sackheads.org>");
5662306a36Sopenharmony_ciMODULE_LICENSE("GPL");
5762306a36Sopenharmony_ciMODULE_IMPORT_NS(USB_STORAGE);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistruct datafab_info {
6062306a36Sopenharmony_ci	unsigned long   sectors;	/* total sector count */
6162306a36Sopenharmony_ci	unsigned long   ssize;		/* sector size in bytes */
6262306a36Sopenharmony_ci	signed char	lun;		/* used for dual-slot readers */
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	/* the following aren't used yet */
6562306a36Sopenharmony_ci	unsigned char   sense_key;
6662306a36Sopenharmony_ci	unsigned long   sense_asc;	/* additional sense code */
6762306a36Sopenharmony_ci	unsigned long   sense_ascq;	/* additional sense code qualifier */
6862306a36Sopenharmony_ci};
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic int datafab_determine_lun(struct us_data *us,
7162306a36Sopenharmony_ci				 struct datafab_info *info);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci/*
7562306a36Sopenharmony_ci * The table of devices
7662306a36Sopenharmony_ci */
7762306a36Sopenharmony_ci#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
7862306a36Sopenharmony_ci		    vendorName, productName, useProtocol, useTransport, \
7962306a36Sopenharmony_ci		    initFunction, flags) \
8062306a36Sopenharmony_ci{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
8162306a36Sopenharmony_ci  .driver_info = (flags) }
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic struct usb_device_id datafab_usb_ids[] = {
8462306a36Sopenharmony_ci#	include "unusual_datafab.h"
8562306a36Sopenharmony_ci	{ }		/* Terminating entry */
8662306a36Sopenharmony_ci};
8762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, datafab_usb_ids);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci#undef UNUSUAL_DEV
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci/*
9262306a36Sopenharmony_ci * The flags table
9362306a36Sopenharmony_ci */
9462306a36Sopenharmony_ci#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
9562306a36Sopenharmony_ci		    vendor_name, product_name, use_protocol, use_transport, \
9662306a36Sopenharmony_ci		    init_function, Flags) \
9762306a36Sopenharmony_ci{ \
9862306a36Sopenharmony_ci	.vendorName = vendor_name,	\
9962306a36Sopenharmony_ci	.productName = product_name,	\
10062306a36Sopenharmony_ci	.useProtocol = use_protocol,	\
10162306a36Sopenharmony_ci	.useTransport = use_transport,	\
10262306a36Sopenharmony_ci	.initFunction = init_function,	\
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic struct us_unusual_dev datafab_unusual_dev_list[] = {
10662306a36Sopenharmony_ci#	include "unusual_datafab.h"
10762306a36Sopenharmony_ci	{ }		/* Terminating entry */
10862306a36Sopenharmony_ci};
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci#undef UNUSUAL_DEV
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic inline int
11462306a36Sopenharmony_cidatafab_bulk_read(struct us_data *us, unsigned char *data, unsigned int len) {
11562306a36Sopenharmony_ci	if (len == 0)
11662306a36Sopenharmony_ci		return USB_STOR_XFER_GOOD;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	usb_stor_dbg(us, "len = %d\n", len);
11962306a36Sopenharmony_ci	return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
12062306a36Sopenharmony_ci			data, len, NULL);
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic inline int
12562306a36Sopenharmony_cidatafab_bulk_write(struct us_data *us, unsigned char *data, unsigned int len) {
12662306a36Sopenharmony_ci	if (len == 0)
12762306a36Sopenharmony_ci		return USB_STOR_XFER_GOOD;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	usb_stor_dbg(us, "len = %d\n", len);
13062306a36Sopenharmony_ci	return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
13162306a36Sopenharmony_ci			data, len, NULL);
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic int datafab_read_data(struct us_data *us,
13662306a36Sopenharmony_ci			     struct datafab_info *info,
13762306a36Sopenharmony_ci			     u32 sector,
13862306a36Sopenharmony_ci			     u32 sectors)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	unsigned char *command = us->iobuf;
14162306a36Sopenharmony_ci	unsigned char *buffer;
14262306a36Sopenharmony_ci	unsigned char  thistime;
14362306a36Sopenharmony_ci	unsigned int totallen, alloclen;
14462306a36Sopenharmony_ci	int len, result;
14562306a36Sopenharmony_ci	unsigned int sg_offset = 0;
14662306a36Sopenharmony_ci	struct scatterlist *sg = NULL;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	// we're working in LBA mode.  according to the ATA spec,
14962306a36Sopenharmony_ci	// we can support up to 28-bit addressing.  I don't know if Datafab
15062306a36Sopenharmony_ci	// supports beyond 24-bit addressing.  It's kind of hard to test
15162306a36Sopenharmony_ci	// since it requires > 8GB CF card.
15262306a36Sopenharmony_ci	//
15362306a36Sopenharmony_ci	if (sectors > 0x0FFFFFFF)
15462306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	if (info->lun == -1) {
15762306a36Sopenharmony_ci		result = datafab_determine_lun(us, info);
15862306a36Sopenharmony_ci		if (result != USB_STOR_TRANSPORT_GOOD)
15962306a36Sopenharmony_ci			return result;
16062306a36Sopenharmony_ci	}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	totallen = sectors * info->ssize;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	// Since we don't read more than 64 KB at a time, we have to create
16562306a36Sopenharmony_ci	// a bounce buffer and move the data a piece at a time between the
16662306a36Sopenharmony_ci	// bounce buffer and the actual transfer buffer.
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	alloclen = min(totallen, 65536u);
16962306a36Sopenharmony_ci	buffer = kmalloc(alloclen, GFP_NOIO);
17062306a36Sopenharmony_ci	if (buffer == NULL)
17162306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	do {
17462306a36Sopenharmony_ci		// loop, never allocate or transfer more than 64k at once
17562306a36Sopenharmony_ci		// (min(128k, 255*info->ssize) is the real limit)
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci		len = min(totallen, alloclen);
17862306a36Sopenharmony_ci		thistime = (len / info->ssize) & 0xff;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci		command[0] = 0;
18162306a36Sopenharmony_ci		command[1] = thistime;
18262306a36Sopenharmony_ci		command[2] = sector & 0xFF;
18362306a36Sopenharmony_ci		command[3] = (sector >> 8) & 0xFF;
18462306a36Sopenharmony_ci		command[4] = (sector >> 16) & 0xFF;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci		command[5] = 0xE0 + (info->lun << 4);
18762306a36Sopenharmony_ci		command[5] |= (sector >> 24) & 0x0F;
18862306a36Sopenharmony_ci		command[6] = 0x20;
18962306a36Sopenharmony_ci		command[7] = 0x01;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci		// send the read command
19262306a36Sopenharmony_ci		result = datafab_bulk_write(us, command, 8);
19362306a36Sopenharmony_ci		if (result != USB_STOR_XFER_GOOD)
19462306a36Sopenharmony_ci			goto leave;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci		// read the result
19762306a36Sopenharmony_ci		result = datafab_bulk_read(us, buffer, len);
19862306a36Sopenharmony_ci		if (result != USB_STOR_XFER_GOOD)
19962306a36Sopenharmony_ci			goto leave;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci		// Store the data in the transfer buffer
20262306a36Sopenharmony_ci		usb_stor_access_xfer_buf(buffer, len, us->srb,
20362306a36Sopenharmony_ci				 &sg, &sg_offset, TO_XFER_BUF);
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci		sector += thistime;
20662306a36Sopenharmony_ci		totallen -= len;
20762306a36Sopenharmony_ci	} while (totallen > 0);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	kfree(buffer);
21062306a36Sopenharmony_ci	return USB_STOR_TRANSPORT_GOOD;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci leave:
21362306a36Sopenharmony_ci	kfree(buffer);
21462306a36Sopenharmony_ci	return USB_STOR_TRANSPORT_ERROR;
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic int datafab_write_data(struct us_data *us,
21962306a36Sopenharmony_ci			      struct datafab_info *info,
22062306a36Sopenharmony_ci			      u32 sector,
22162306a36Sopenharmony_ci			      u32 sectors)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	unsigned char *command = us->iobuf;
22462306a36Sopenharmony_ci	unsigned char *reply = us->iobuf;
22562306a36Sopenharmony_ci	unsigned char *buffer;
22662306a36Sopenharmony_ci	unsigned char thistime;
22762306a36Sopenharmony_ci	unsigned int totallen, alloclen;
22862306a36Sopenharmony_ci	int len, result;
22962306a36Sopenharmony_ci	unsigned int sg_offset = 0;
23062306a36Sopenharmony_ci	struct scatterlist *sg = NULL;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	// we're working in LBA mode.  according to the ATA spec,
23362306a36Sopenharmony_ci	// we can support up to 28-bit addressing.  I don't know if Datafab
23462306a36Sopenharmony_ci	// supports beyond 24-bit addressing.  It's kind of hard to test
23562306a36Sopenharmony_ci	// since it requires > 8GB CF card.
23662306a36Sopenharmony_ci	//
23762306a36Sopenharmony_ci	if (sectors > 0x0FFFFFFF)
23862306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	if (info->lun == -1) {
24162306a36Sopenharmony_ci		result = datafab_determine_lun(us, info);
24262306a36Sopenharmony_ci		if (result != USB_STOR_TRANSPORT_GOOD)
24362306a36Sopenharmony_ci			return result;
24462306a36Sopenharmony_ci	}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	totallen = sectors * info->ssize;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	// Since we don't write more than 64 KB at a time, we have to create
24962306a36Sopenharmony_ci	// a bounce buffer and move the data a piece at a time between the
25062306a36Sopenharmony_ci	// bounce buffer and the actual transfer buffer.
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	alloclen = min(totallen, 65536u);
25362306a36Sopenharmony_ci	buffer = kmalloc(alloclen, GFP_NOIO);
25462306a36Sopenharmony_ci	if (buffer == NULL)
25562306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	do {
25862306a36Sopenharmony_ci		// loop, never allocate or transfer more than 64k at once
25962306a36Sopenharmony_ci		// (min(128k, 255*info->ssize) is the real limit)
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci		len = min(totallen, alloclen);
26262306a36Sopenharmony_ci		thistime = (len / info->ssize) & 0xff;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci		// Get the data from the transfer buffer
26562306a36Sopenharmony_ci		usb_stor_access_xfer_buf(buffer, len, us->srb,
26662306a36Sopenharmony_ci				&sg, &sg_offset, FROM_XFER_BUF);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci		command[0] = 0;
26962306a36Sopenharmony_ci		command[1] = thistime;
27062306a36Sopenharmony_ci		command[2] = sector & 0xFF;
27162306a36Sopenharmony_ci		command[3] = (sector >> 8) & 0xFF;
27262306a36Sopenharmony_ci		command[4] = (sector >> 16) & 0xFF;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci		command[5] = 0xE0 + (info->lun << 4);
27562306a36Sopenharmony_ci		command[5] |= (sector >> 24) & 0x0F;
27662306a36Sopenharmony_ci		command[6] = 0x30;
27762306a36Sopenharmony_ci		command[7] = 0x02;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci		// send the command
28062306a36Sopenharmony_ci		result = datafab_bulk_write(us, command, 8);
28162306a36Sopenharmony_ci		if (result != USB_STOR_XFER_GOOD)
28262306a36Sopenharmony_ci			goto leave;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci		// send the data
28562306a36Sopenharmony_ci		result = datafab_bulk_write(us, buffer, len);
28662306a36Sopenharmony_ci		if (result != USB_STOR_XFER_GOOD)
28762306a36Sopenharmony_ci			goto leave;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci		// read the result
29062306a36Sopenharmony_ci		result = datafab_bulk_read(us, reply, 2);
29162306a36Sopenharmony_ci		if (result != USB_STOR_XFER_GOOD)
29262306a36Sopenharmony_ci			goto leave;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci		if (reply[0] != 0x50 && reply[1] != 0) {
29562306a36Sopenharmony_ci			usb_stor_dbg(us, "Gah! write return code: %02x %02x\n",
29662306a36Sopenharmony_ci				     reply[0], reply[1]);
29762306a36Sopenharmony_ci			goto leave;
29862306a36Sopenharmony_ci		}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci		sector += thistime;
30162306a36Sopenharmony_ci		totallen -= len;
30262306a36Sopenharmony_ci	} while (totallen > 0);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	kfree(buffer);
30562306a36Sopenharmony_ci	return USB_STOR_TRANSPORT_GOOD;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci leave:
30862306a36Sopenharmony_ci	kfree(buffer);
30962306a36Sopenharmony_ci	return USB_STOR_TRANSPORT_ERROR;
31062306a36Sopenharmony_ci}
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_cistatic int datafab_determine_lun(struct us_data *us,
31462306a36Sopenharmony_ci				 struct datafab_info *info)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	// Dual-slot readers can be thought of as dual-LUN devices.
31762306a36Sopenharmony_ci	// We need to determine which card slot is being used.
31862306a36Sopenharmony_ci	// We'll send an IDENTIFY DEVICE command and see which LUN responds...
31962306a36Sopenharmony_ci	//
32062306a36Sopenharmony_ci	// There might be a better way of doing this?
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	static unsigned char scommand[8] = { 0, 1, 0, 0, 0, 0xa0, 0xec, 1 };
32362306a36Sopenharmony_ci	unsigned char *command = us->iobuf;
32462306a36Sopenharmony_ci	unsigned char *buf;
32562306a36Sopenharmony_ci	int count = 0, rc;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	if (!info)
32862306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	memcpy(command, scommand, 8);
33162306a36Sopenharmony_ci	buf = kmalloc(512, GFP_NOIO);
33262306a36Sopenharmony_ci	if (!buf)
33362306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	usb_stor_dbg(us, "locating...\n");
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	// we'll try 3 times before giving up...
33862306a36Sopenharmony_ci	//
33962306a36Sopenharmony_ci	while (count++ < 3) {
34062306a36Sopenharmony_ci		command[5] = 0xa0;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci		rc = datafab_bulk_write(us, command, 8);
34362306a36Sopenharmony_ci		if (rc != USB_STOR_XFER_GOOD) {
34462306a36Sopenharmony_ci			rc = USB_STOR_TRANSPORT_ERROR;
34562306a36Sopenharmony_ci			goto leave;
34662306a36Sopenharmony_ci		}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci		rc = datafab_bulk_read(us, buf, 512);
34962306a36Sopenharmony_ci		if (rc == USB_STOR_XFER_GOOD) {
35062306a36Sopenharmony_ci			info->lun = 0;
35162306a36Sopenharmony_ci			rc = USB_STOR_TRANSPORT_GOOD;
35262306a36Sopenharmony_ci			goto leave;
35362306a36Sopenharmony_ci		}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci		command[5] = 0xb0;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci		rc = datafab_bulk_write(us, command, 8);
35862306a36Sopenharmony_ci		if (rc != USB_STOR_XFER_GOOD) {
35962306a36Sopenharmony_ci			rc = USB_STOR_TRANSPORT_ERROR;
36062306a36Sopenharmony_ci			goto leave;
36162306a36Sopenharmony_ci		}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci		rc = datafab_bulk_read(us, buf, 512);
36462306a36Sopenharmony_ci		if (rc == USB_STOR_XFER_GOOD) {
36562306a36Sopenharmony_ci			info->lun = 1;
36662306a36Sopenharmony_ci			rc = USB_STOR_TRANSPORT_GOOD;
36762306a36Sopenharmony_ci			goto leave;
36862306a36Sopenharmony_ci		}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci		msleep(20);
37162306a36Sopenharmony_ci	}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	rc = USB_STOR_TRANSPORT_ERROR;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci leave:
37662306a36Sopenharmony_ci	kfree(buf);
37762306a36Sopenharmony_ci	return rc;
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic int datafab_id_device(struct us_data *us,
38162306a36Sopenharmony_ci			     struct datafab_info *info)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	// this is a variation of the ATA "IDENTIFY DEVICE" command...according
38462306a36Sopenharmony_ci	// to the ATA spec, 'Sector Count' isn't used but the Windows driver
38562306a36Sopenharmony_ci	// sets this bit so we do too...
38662306a36Sopenharmony_ci	//
38762306a36Sopenharmony_ci	static unsigned char scommand[8] = { 0, 1, 0, 0, 0, 0xa0, 0xec, 1 };
38862306a36Sopenharmony_ci	unsigned char *command = us->iobuf;
38962306a36Sopenharmony_ci	unsigned char *reply;
39062306a36Sopenharmony_ci	int rc;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	if (!info)
39362306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	if (info->lun == -1) {
39662306a36Sopenharmony_ci		rc = datafab_determine_lun(us, info);
39762306a36Sopenharmony_ci		if (rc != USB_STOR_TRANSPORT_GOOD)
39862306a36Sopenharmony_ci			return rc;
39962306a36Sopenharmony_ci	}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	memcpy(command, scommand, 8);
40262306a36Sopenharmony_ci	reply = kmalloc(512, GFP_NOIO);
40362306a36Sopenharmony_ci	if (!reply)
40462306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	command[5] += (info->lun << 4);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	rc = datafab_bulk_write(us, command, 8);
40962306a36Sopenharmony_ci	if (rc != USB_STOR_XFER_GOOD) {
41062306a36Sopenharmony_ci		rc = USB_STOR_TRANSPORT_ERROR;
41162306a36Sopenharmony_ci		goto leave;
41262306a36Sopenharmony_ci	}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	// we'll go ahead and extract the media capacity while we're here...
41562306a36Sopenharmony_ci	//
41662306a36Sopenharmony_ci	rc = datafab_bulk_read(us, reply, 512);
41762306a36Sopenharmony_ci	if (rc == USB_STOR_XFER_GOOD) {
41862306a36Sopenharmony_ci		// capacity is at word offset 57-58
41962306a36Sopenharmony_ci		//
42062306a36Sopenharmony_ci		info->sectors = ((u32)(reply[117]) << 24) |
42162306a36Sopenharmony_ci				((u32)(reply[116]) << 16) |
42262306a36Sopenharmony_ci				((u32)(reply[115]) <<  8) |
42362306a36Sopenharmony_ci				((u32)(reply[114])      );
42462306a36Sopenharmony_ci		rc = USB_STOR_TRANSPORT_GOOD;
42562306a36Sopenharmony_ci		goto leave;
42662306a36Sopenharmony_ci	}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	rc = USB_STOR_TRANSPORT_ERROR;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci leave:
43162306a36Sopenharmony_ci	kfree(reply);
43262306a36Sopenharmony_ci	return rc;
43362306a36Sopenharmony_ci}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_cistatic int datafab_handle_mode_sense(struct us_data *us,
43762306a36Sopenharmony_ci				     struct scsi_cmnd * srb,
43862306a36Sopenharmony_ci				     int sense_6)
43962306a36Sopenharmony_ci{
44062306a36Sopenharmony_ci	static unsigned char rw_err_page[12] = {
44162306a36Sopenharmony_ci		0x1, 0xA, 0x21, 1, 0, 0, 0, 0, 1, 0, 0, 0
44262306a36Sopenharmony_ci	};
44362306a36Sopenharmony_ci	static unsigned char cache_page[12] = {
44462306a36Sopenharmony_ci		0x8, 0xA, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0
44562306a36Sopenharmony_ci	};
44662306a36Sopenharmony_ci	static unsigned char rbac_page[12] = {
44762306a36Sopenharmony_ci		0x1B, 0xA, 0, 0x81, 0, 0, 0, 0, 0, 0, 0, 0
44862306a36Sopenharmony_ci	};
44962306a36Sopenharmony_ci	static unsigned char timer_page[8] = {
45062306a36Sopenharmony_ci		0x1C, 0x6, 0, 0, 0, 0
45162306a36Sopenharmony_ci	};
45262306a36Sopenharmony_ci	unsigned char pc, page_code;
45362306a36Sopenharmony_ci	unsigned int i = 0;
45462306a36Sopenharmony_ci	struct datafab_info *info = (struct datafab_info *) (us->extra);
45562306a36Sopenharmony_ci	unsigned char *ptr = us->iobuf;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	// most of this stuff is just a hack to get things working.  the
45862306a36Sopenharmony_ci	// datafab reader doesn't present a SCSI interface so we
45962306a36Sopenharmony_ci	// fudge the SCSI commands...
46062306a36Sopenharmony_ci	//
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	pc = srb->cmnd[2] >> 6;
46362306a36Sopenharmony_ci	page_code = srb->cmnd[2] & 0x3F;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	switch (pc) {
46662306a36Sopenharmony_ci	   case 0x0:
46762306a36Sopenharmony_ci		   usb_stor_dbg(us, "Current values\n");
46862306a36Sopenharmony_ci		break;
46962306a36Sopenharmony_ci	   case 0x1:
47062306a36Sopenharmony_ci		   usb_stor_dbg(us, "Changeable values\n");
47162306a36Sopenharmony_ci		break;
47262306a36Sopenharmony_ci	   case 0x2:
47362306a36Sopenharmony_ci		   usb_stor_dbg(us, "Default values\n");
47462306a36Sopenharmony_ci		break;
47562306a36Sopenharmony_ci	   case 0x3:
47662306a36Sopenharmony_ci		   usb_stor_dbg(us, "Saves values\n");
47762306a36Sopenharmony_ci		break;
47862306a36Sopenharmony_ci	}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	memset(ptr, 0, 8);
48162306a36Sopenharmony_ci	if (sense_6) {
48262306a36Sopenharmony_ci		ptr[2] = 0x00;		// WP enable: 0x80
48362306a36Sopenharmony_ci		i = 4;
48462306a36Sopenharmony_ci	} else {
48562306a36Sopenharmony_ci		ptr[3] = 0x00;		// WP enable: 0x80
48662306a36Sopenharmony_ci		i = 8;
48762306a36Sopenharmony_ci	}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	switch (page_code) {
49062306a36Sopenharmony_ci	   default:
49162306a36Sopenharmony_ci		// vendor-specific mode
49262306a36Sopenharmony_ci		info->sense_key = 0x05;
49362306a36Sopenharmony_ci		info->sense_asc = 0x24;
49462306a36Sopenharmony_ci		info->sense_ascq = 0x00;
49562306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_FAILED;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	   case 0x1:
49862306a36Sopenharmony_ci		memcpy(ptr + i, rw_err_page, sizeof(rw_err_page));
49962306a36Sopenharmony_ci		i += sizeof(rw_err_page);
50062306a36Sopenharmony_ci		break;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	   case 0x8:
50362306a36Sopenharmony_ci		memcpy(ptr + i, cache_page, sizeof(cache_page));
50462306a36Sopenharmony_ci		i += sizeof(cache_page);
50562306a36Sopenharmony_ci		break;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	   case 0x1B:
50862306a36Sopenharmony_ci		memcpy(ptr + i, rbac_page, sizeof(rbac_page));
50962306a36Sopenharmony_ci		i += sizeof(rbac_page);
51062306a36Sopenharmony_ci		break;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	   case 0x1C:
51362306a36Sopenharmony_ci		memcpy(ptr + i, timer_page, sizeof(timer_page));
51462306a36Sopenharmony_ci		i += sizeof(timer_page);
51562306a36Sopenharmony_ci		break;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	   case 0x3F:		// retrieve all pages
51862306a36Sopenharmony_ci		memcpy(ptr + i, timer_page, sizeof(timer_page));
51962306a36Sopenharmony_ci		i += sizeof(timer_page);
52062306a36Sopenharmony_ci		memcpy(ptr + i, rbac_page, sizeof(rbac_page));
52162306a36Sopenharmony_ci		i += sizeof(rbac_page);
52262306a36Sopenharmony_ci		memcpy(ptr + i, cache_page, sizeof(cache_page));
52362306a36Sopenharmony_ci		i += sizeof(cache_page);
52462306a36Sopenharmony_ci		memcpy(ptr + i, rw_err_page, sizeof(rw_err_page));
52562306a36Sopenharmony_ci		i += sizeof(rw_err_page);
52662306a36Sopenharmony_ci		break;
52762306a36Sopenharmony_ci	}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	if (sense_6)
53062306a36Sopenharmony_ci		ptr[0] = i - 1;
53162306a36Sopenharmony_ci	else
53262306a36Sopenharmony_ci		((__be16 *) ptr)[0] = cpu_to_be16(i - 2);
53362306a36Sopenharmony_ci	usb_stor_set_xfer_buf(ptr, i, srb);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	return USB_STOR_TRANSPORT_GOOD;
53662306a36Sopenharmony_ci}
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_cistatic void datafab_info_destructor(void *extra)
53962306a36Sopenharmony_ci{
54062306a36Sopenharmony_ci	// this routine is a placeholder...
54162306a36Sopenharmony_ci	// currently, we don't allocate any extra memory so we're okay
54262306a36Sopenharmony_ci}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci// Transport for the Datafab MDCFE-B
54662306a36Sopenharmony_ci//
54762306a36Sopenharmony_cistatic int datafab_transport(struct scsi_cmnd *srb, struct us_data *us)
54862306a36Sopenharmony_ci{
54962306a36Sopenharmony_ci	struct datafab_info *info;
55062306a36Sopenharmony_ci	int rc;
55162306a36Sopenharmony_ci	unsigned long block, blocks;
55262306a36Sopenharmony_ci	unsigned char *ptr = us->iobuf;
55362306a36Sopenharmony_ci	static unsigned char inquiry_reply[8] = {
55462306a36Sopenharmony_ci		0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00
55562306a36Sopenharmony_ci	};
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	if (!us->extra) {
55862306a36Sopenharmony_ci		us->extra = kzalloc(sizeof(struct datafab_info), GFP_NOIO);
55962306a36Sopenharmony_ci		if (!us->extra)
56062306a36Sopenharmony_ci			return USB_STOR_TRANSPORT_ERROR;
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci		us->extra_destructor = datafab_info_destructor;
56362306a36Sopenharmony_ci  		((struct datafab_info *)us->extra)->lun = -1;
56462306a36Sopenharmony_ci	}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	info = (struct datafab_info *) (us->extra);
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	if (srb->cmnd[0] == INQUIRY) {
56962306a36Sopenharmony_ci		usb_stor_dbg(us, "INQUIRY - Returning bogus response\n");
57062306a36Sopenharmony_ci		memcpy(ptr, inquiry_reply, sizeof(inquiry_reply));
57162306a36Sopenharmony_ci		fill_inquiry_response(us, ptr, 36);
57262306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_GOOD;
57362306a36Sopenharmony_ci	}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	if (srb->cmnd[0] == READ_CAPACITY) {
57662306a36Sopenharmony_ci		info->ssize = 0x200;  // hard coded 512 byte sectors as per ATA spec
57762306a36Sopenharmony_ci		rc = datafab_id_device(us, info);
57862306a36Sopenharmony_ci		if (rc != USB_STOR_TRANSPORT_GOOD)
57962306a36Sopenharmony_ci			return rc;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci		usb_stor_dbg(us, "READ_CAPACITY:  %ld sectors, %ld bytes per sector\n",
58262306a36Sopenharmony_ci			     info->sectors, info->ssize);
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci		// build the reply
58562306a36Sopenharmony_ci		// we need the last sector, not the number of sectors
58662306a36Sopenharmony_ci		((__be32 *) ptr)[0] = cpu_to_be32(info->sectors - 1);
58762306a36Sopenharmony_ci		((__be32 *) ptr)[1] = cpu_to_be32(info->ssize);
58862306a36Sopenharmony_ci		usb_stor_set_xfer_buf(ptr, 8, srb);
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_GOOD;
59162306a36Sopenharmony_ci	}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	if (srb->cmnd[0] == MODE_SELECT_10) {
59462306a36Sopenharmony_ci		usb_stor_dbg(us, "Gah! MODE_SELECT_10\n");
59562306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
59662306a36Sopenharmony_ci	}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	// don't bother implementing READ_6 or WRITE_6.
59962306a36Sopenharmony_ci	//
60062306a36Sopenharmony_ci	if (srb->cmnd[0] == READ_10) {
60162306a36Sopenharmony_ci		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
60262306a36Sopenharmony_ci			((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci		blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci		usb_stor_dbg(us, "READ_10: read block 0x%04lx  count %ld\n",
60762306a36Sopenharmony_ci			     block, blocks);
60862306a36Sopenharmony_ci		return datafab_read_data(us, info, block, blocks);
60962306a36Sopenharmony_ci	}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	if (srb->cmnd[0] == READ_12) {
61262306a36Sopenharmony_ci		// we'll probably never see a READ_12 but we'll do it anyway...
61362306a36Sopenharmony_ci		//
61462306a36Sopenharmony_ci		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
61562306a36Sopenharmony_ci			((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci		blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
61862306a36Sopenharmony_ci			 ((u32)(srb->cmnd[8]) <<  8) | ((u32)(srb->cmnd[9]));
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci		usb_stor_dbg(us, "READ_12: read block 0x%04lx  count %ld\n",
62162306a36Sopenharmony_ci			     block, blocks);
62262306a36Sopenharmony_ci		return datafab_read_data(us, info, block, blocks);
62362306a36Sopenharmony_ci	}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	if (srb->cmnd[0] == WRITE_10) {
62662306a36Sopenharmony_ci		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
62762306a36Sopenharmony_ci			((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci		blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci		usb_stor_dbg(us, "WRITE_10: write block 0x%04lx count %ld\n",
63262306a36Sopenharmony_ci			     block, blocks);
63362306a36Sopenharmony_ci		return datafab_write_data(us, info, block, blocks);
63462306a36Sopenharmony_ci	}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	if (srb->cmnd[0] == WRITE_12) {
63762306a36Sopenharmony_ci		// we'll probably never see a WRITE_12 but we'll do it anyway...
63862306a36Sopenharmony_ci		//
63962306a36Sopenharmony_ci		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
64062306a36Sopenharmony_ci			((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci		blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
64362306a36Sopenharmony_ci			 ((u32)(srb->cmnd[8]) <<  8) | ((u32)(srb->cmnd[9]));
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci		usb_stor_dbg(us, "WRITE_12: write block 0x%04lx count %ld\n",
64662306a36Sopenharmony_ci			     block, blocks);
64762306a36Sopenharmony_ci		return datafab_write_data(us, info, block, blocks);
64862306a36Sopenharmony_ci	}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	if (srb->cmnd[0] == TEST_UNIT_READY) {
65162306a36Sopenharmony_ci		usb_stor_dbg(us, "TEST_UNIT_READY\n");
65262306a36Sopenharmony_ci		return datafab_id_device(us, info);
65362306a36Sopenharmony_ci	}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	if (srb->cmnd[0] == REQUEST_SENSE) {
65662306a36Sopenharmony_ci		usb_stor_dbg(us, "REQUEST_SENSE - Returning faked response\n");
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci		// this response is pretty bogus right now.  eventually if necessary
65962306a36Sopenharmony_ci		// we can set the correct sense data.  so far though it hasn't been
66062306a36Sopenharmony_ci		// necessary
66162306a36Sopenharmony_ci		//
66262306a36Sopenharmony_ci		memset(ptr, 0, 18);
66362306a36Sopenharmony_ci		ptr[0] = 0xF0;
66462306a36Sopenharmony_ci		ptr[2] = info->sense_key;
66562306a36Sopenharmony_ci		ptr[7] = 11;
66662306a36Sopenharmony_ci		ptr[12] = info->sense_asc;
66762306a36Sopenharmony_ci		ptr[13] = info->sense_ascq;
66862306a36Sopenharmony_ci		usb_stor_set_xfer_buf(ptr, 18, srb);
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_GOOD;
67162306a36Sopenharmony_ci	}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	if (srb->cmnd[0] == MODE_SENSE) {
67462306a36Sopenharmony_ci		usb_stor_dbg(us, "MODE_SENSE_6 detected\n");
67562306a36Sopenharmony_ci		return datafab_handle_mode_sense(us, srb, 1);
67662306a36Sopenharmony_ci	}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	if (srb->cmnd[0] == MODE_SENSE_10) {
67962306a36Sopenharmony_ci		usb_stor_dbg(us, "MODE_SENSE_10 detected\n");
68062306a36Sopenharmony_ci		return datafab_handle_mode_sense(us, srb, 0);
68162306a36Sopenharmony_ci	}
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
68462306a36Sopenharmony_ci		/*
68562306a36Sopenharmony_ci		 * sure.  whatever.  not like we can stop the user from
68662306a36Sopenharmony_ci		 * popping the media out of the device (no locking doors, etc)
68762306a36Sopenharmony_ci		 */
68862306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_GOOD;
68962306a36Sopenharmony_ci	}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	if (srb->cmnd[0] == START_STOP) {
69262306a36Sopenharmony_ci		/*
69362306a36Sopenharmony_ci		 * this is used by sd.c'check_scsidisk_media_change to detect
69462306a36Sopenharmony_ci		 * media change
69562306a36Sopenharmony_ci		 */
69662306a36Sopenharmony_ci		usb_stor_dbg(us, "START_STOP\n");
69762306a36Sopenharmony_ci		/*
69862306a36Sopenharmony_ci		 * the first datafab_id_device after a media change returns
69962306a36Sopenharmony_ci		 * an error (determined experimentally)
70062306a36Sopenharmony_ci		 */
70162306a36Sopenharmony_ci		rc = datafab_id_device(us, info);
70262306a36Sopenharmony_ci		if (rc == USB_STOR_TRANSPORT_GOOD) {
70362306a36Sopenharmony_ci			info->sense_key = NO_SENSE;
70462306a36Sopenharmony_ci			srb->result = SUCCESS;
70562306a36Sopenharmony_ci		} else {
70662306a36Sopenharmony_ci			info->sense_key = UNIT_ATTENTION;
70762306a36Sopenharmony_ci			srb->result = SAM_STAT_CHECK_CONDITION;
70862306a36Sopenharmony_ci		}
70962306a36Sopenharmony_ci		return rc;
71062306a36Sopenharmony_ci	}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	usb_stor_dbg(us, "Gah! Unknown command: %d (0x%x)\n",
71362306a36Sopenharmony_ci		     srb->cmnd[0], srb->cmnd[0]);
71462306a36Sopenharmony_ci	info->sense_key = 0x05;
71562306a36Sopenharmony_ci	info->sense_asc = 0x20;
71662306a36Sopenharmony_ci	info->sense_ascq = 0x00;
71762306a36Sopenharmony_ci	return USB_STOR_TRANSPORT_FAILED;
71862306a36Sopenharmony_ci}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_cistatic struct scsi_host_template datafab_host_template;
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_cistatic int datafab_probe(struct usb_interface *intf,
72362306a36Sopenharmony_ci			 const struct usb_device_id *id)
72462306a36Sopenharmony_ci{
72562306a36Sopenharmony_ci	struct us_data *us;
72662306a36Sopenharmony_ci	int result;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	result = usb_stor_probe1(&us, intf, id,
72962306a36Sopenharmony_ci			(id - datafab_usb_ids) + datafab_unusual_dev_list,
73062306a36Sopenharmony_ci			&datafab_host_template);
73162306a36Sopenharmony_ci	if (result)
73262306a36Sopenharmony_ci		return result;
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	us->transport_name  = "Datafab Bulk-Only";
73562306a36Sopenharmony_ci	us->transport = datafab_transport;
73662306a36Sopenharmony_ci	us->transport_reset = usb_stor_Bulk_reset;
73762306a36Sopenharmony_ci	us->max_lun = 1;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	result = usb_stor_probe2(us);
74062306a36Sopenharmony_ci	return result;
74162306a36Sopenharmony_ci}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_cistatic struct usb_driver datafab_driver = {
74462306a36Sopenharmony_ci	.name =		DRV_NAME,
74562306a36Sopenharmony_ci	.probe =	datafab_probe,
74662306a36Sopenharmony_ci	.disconnect =	usb_stor_disconnect,
74762306a36Sopenharmony_ci	.suspend =	usb_stor_suspend,
74862306a36Sopenharmony_ci	.resume =	usb_stor_resume,
74962306a36Sopenharmony_ci	.reset_resume =	usb_stor_reset_resume,
75062306a36Sopenharmony_ci	.pre_reset =	usb_stor_pre_reset,
75162306a36Sopenharmony_ci	.post_reset =	usb_stor_post_reset,
75262306a36Sopenharmony_ci	.id_table =	datafab_usb_ids,
75362306a36Sopenharmony_ci	.soft_unbind =	1,
75462306a36Sopenharmony_ci	.no_dynamic_id = 1,
75562306a36Sopenharmony_ci};
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_cimodule_usb_stor_driver(datafab_driver, datafab_host_template, DRV_NAME);
758