162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Driver for SCM Microsystems (a.k.a. Shuttle) USB-ATAPI cable
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Current development and maintenance by:
662306a36Sopenharmony_ci *   (c) 2000, 2001 Robert Baruch (autophile@starband.net)
762306a36Sopenharmony_ci *   (c) 2004, 2005 Daniel Drake <dsd@gentoo.org>
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Developed with the assistance of:
1062306a36Sopenharmony_ci *   (c) 2002 Alan Stern <stern@rowland.org>
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * Flash support based on earlier work by:
1362306a36Sopenharmony_ci *   (c) 2002 Thomas Kreiling <usbdev@sm04.de>
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci * Many originally ATAPI devices were slightly modified to meet the USB
1662306a36Sopenharmony_ci * market by using some kind of translation from ATAPI to USB on the host,
1762306a36Sopenharmony_ci * and the peripheral would translate from USB back to ATAPI.
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * SCM Microsystems (www.scmmicro.com) makes a device, sold to OEM's only,
2062306a36Sopenharmony_ci * which does the USB-to-ATAPI conversion.  By obtaining the data sheet on
2162306a36Sopenharmony_ci * their device under nondisclosure agreement, I have been able to write
2262306a36Sopenharmony_ci * this driver for Linux.
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci * The chip used in the device can also be used for EPP and ISA translation
2562306a36Sopenharmony_ci * as well. This driver is only guaranteed to work with the ATAPI
2662306a36Sopenharmony_ci * translation.
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci * See the Kconfig help text for a list of devices known to be supported by
2962306a36Sopenharmony_ci * this driver.
3062306a36Sopenharmony_ci */
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#include <linux/errno.h>
3362306a36Sopenharmony_ci#include <linux/module.h>
3462306a36Sopenharmony_ci#include <linux/slab.h>
3562306a36Sopenharmony_ci#include <linux/cdrom.h>
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#include <scsi/scsi.h>
3862306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h>
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#include "usb.h"
4162306a36Sopenharmony_ci#include "transport.h"
4262306a36Sopenharmony_ci#include "protocol.h"
4362306a36Sopenharmony_ci#include "debug.h"
4462306a36Sopenharmony_ci#include "scsiglue.h"
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#define DRV_NAME "ums-usbat"
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver for SCM Microsystems (a.k.a. Shuttle) USB-ATAPI cable");
4962306a36Sopenharmony_ciMODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>, Robert Baruch <autophile@starband.net>");
5062306a36Sopenharmony_ciMODULE_LICENSE("GPL");
5162306a36Sopenharmony_ciMODULE_IMPORT_NS(USB_STORAGE);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/* Supported device types */
5462306a36Sopenharmony_ci#define USBAT_DEV_HP8200	0x01
5562306a36Sopenharmony_ci#define USBAT_DEV_FLASH		0x02
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#define USBAT_EPP_PORT		0x10
5862306a36Sopenharmony_ci#define USBAT_EPP_REGISTER	0x30
5962306a36Sopenharmony_ci#define USBAT_ATA		0x40
6062306a36Sopenharmony_ci#define USBAT_ISA		0x50
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/* Commands (need to be logically OR'd with an access type */
6362306a36Sopenharmony_ci#define USBAT_CMD_READ_REG		0x00
6462306a36Sopenharmony_ci#define USBAT_CMD_WRITE_REG		0x01
6562306a36Sopenharmony_ci#define USBAT_CMD_READ_BLOCK	0x02
6662306a36Sopenharmony_ci#define USBAT_CMD_WRITE_BLOCK	0x03
6762306a36Sopenharmony_ci#define USBAT_CMD_COND_READ_BLOCK	0x04
6862306a36Sopenharmony_ci#define USBAT_CMD_COND_WRITE_BLOCK	0x05
6962306a36Sopenharmony_ci#define USBAT_CMD_WRITE_REGS	0x07
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci/* Commands (these don't need an access type) */
7262306a36Sopenharmony_ci#define USBAT_CMD_EXEC_CMD	0x80
7362306a36Sopenharmony_ci#define USBAT_CMD_SET_FEAT	0x81
7462306a36Sopenharmony_ci#define USBAT_CMD_UIO		0x82
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci/* Methods of accessing UIO register */
7762306a36Sopenharmony_ci#define USBAT_UIO_READ	1
7862306a36Sopenharmony_ci#define USBAT_UIO_WRITE	0
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci/* Qualifier bits */
8162306a36Sopenharmony_ci#define USBAT_QUAL_FCQ	0x20	/* full compare */
8262306a36Sopenharmony_ci#define USBAT_QUAL_ALQ	0x10	/* auto load subcount */
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci/* USBAT Flash Media status types */
8562306a36Sopenharmony_ci#define USBAT_FLASH_MEDIA_NONE	0
8662306a36Sopenharmony_ci#define USBAT_FLASH_MEDIA_CF	1
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/* USBAT Flash Media change types */
8962306a36Sopenharmony_ci#define USBAT_FLASH_MEDIA_SAME	0
9062306a36Sopenharmony_ci#define USBAT_FLASH_MEDIA_CHANGED	1
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci/* USBAT ATA registers */
9362306a36Sopenharmony_ci#define USBAT_ATA_DATA      0x10  /* read/write data (R/W) */
9462306a36Sopenharmony_ci#define USBAT_ATA_FEATURES  0x11  /* set features (W) */
9562306a36Sopenharmony_ci#define USBAT_ATA_ERROR     0x11  /* error (R) */
9662306a36Sopenharmony_ci#define USBAT_ATA_SECCNT    0x12  /* sector count (R/W) */
9762306a36Sopenharmony_ci#define USBAT_ATA_SECNUM    0x13  /* sector number (R/W) */
9862306a36Sopenharmony_ci#define USBAT_ATA_LBA_ME    0x14  /* cylinder low (R/W) */
9962306a36Sopenharmony_ci#define USBAT_ATA_LBA_HI    0x15  /* cylinder high (R/W) */
10062306a36Sopenharmony_ci#define USBAT_ATA_DEVICE    0x16  /* head/device selection (R/W) */
10162306a36Sopenharmony_ci#define USBAT_ATA_STATUS    0x17  /* device status (R) */
10262306a36Sopenharmony_ci#define USBAT_ATA_CMD       0x17  /* device command (W) */
10362306a36Sopenharmony_ci#define USBAT_ATA_ALTSTATUS 0x0E  /* status (no clear IRQ) (R) */
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci/* USBAT User I/O Data registers */
10662306a36Sopenharmony_ci#define USBAT_UIO_EPAD		0x80 /* Enable Peripheral Control Signals */
10762306a36Sopenharmony_ci#define USBAT_UIO_CDT		0x40 /* Card Detect (Read Only) */
10862306a36Sopenharmony_ci				     /* CDT = ACKD & !UI1 & !UI0 */
10962306a36Sopenharmony_ci#define USBAT_UIO_1		0x20 /* I/O 1 */
11062306a36Sopenharmony_ci#define USBAT_UIO_0		0x10 /* I/O 0 */
11162306a36Sopenharmony_ci#define USBAT_UIO_EPP_ATA	0x08 /* 1=EPP mode, 0=ATA mode */
11262306a36Sopenharmony_ci#define USBAT_UIO_UI1		0x04 /* Input 1 */
11362306a36Sopenharmony_ci#define USBAT_UIO_UI0		0x02 /* Input 0 */
11462306a36Sopenharmony_ci#define USBAT_UIO_INTR_ACK	0x01 /* Interrupt (ATA/ISA)/Acknowledge (EPP) */
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci/* USBAT User I/O Enable registers */
11762306a36Sopenharmony_ci#define USBAT_UIO_DRVRST	0x80 /* Reset Peripheral */
11862306a36Sopenharmony_ci#define USBAT_UIO_ACKD		0x40 /* Enable Card Detect */
11962306a36Sopenharmony_ci#define USBAT_UIO_OE1		0x20 /* I/O 1 set=output/clr=input */
12062306a36Sopenharmony_ci				     /* If ACKD=1, set OE1 to 1 also. */
12162306a36Sopenharmony_ci#define USBAT_UIO_OE0		0x10 /* I/O 0 set=output/clr=input */
12262306a36Sopenharmony_ci#define USBAT_UIO_ADPRST	0x01 /* Reset SCM chip */
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci/* USBAT Features */
12562306a36Sopenharmony_ci#define USBAT_FEAT_ETEN	0x80	/* External trigger enable */
12662306a36Sopenharmony_ci#define USBAT_FEAT_U1	0x08
12762306a36Sopenharmony_ci#define USBAT_FEAT_U0	0x04
12862306a36Sopenharmony_ci#define USBAT_FEAT_ET1	0x02
12962306a36Sopenharmony_ci#define USBAT_FEAT_ET2	0x01
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistruct usbat_info {
13262306a36Sopenharmony_ci	int devicetype;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	/* Used for Flash readers only */
13562306a36Sopenharmony_ci	unsigned long sectors;     /* total sector count */
13662306a36Sopenharmony_ci	unsigned long ssize;       /* sector size in bytes */
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	unsigned char sense_key;
13962306a36Sopenharmony_ci	unsigned long sense_asc;   /* additional sense code */
14062306a36Sopenharmony_ci	unsigned long sense_ascq;  /* additional sense code qualifier */
14162306a36Sopenharmony_ci};
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci#define short_pack(LSB,MSB) ( ((u16)(LSB)) | ( ((u16)(MSB))<<8 ) )
14462306a36Sopenharmony_ci#define LSB_of(s) ((s)&0xFF)
14562306a36Sopenharmony_ci#define MSB_of(s) ((s)>>8)
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic int transferred = 0;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us);
15062306a36Sopenharmony_cistatic int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic int init_usbat_cd(struct us_data *us);
15362306a36Sopenharmony_cistatic int init_usbat_flash(struct us_data *us);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci/*
15762306a36Sopenharmony_ci * The table of devices
15862306a36Sopenharmony_ci */
15962306a36Sopenharmony_ci#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
16062306a36Sopenharmony_ci		    vendorName, productName, useProtocol, useTransport, \
16162306a36Sopenharmony_ci		    initFunction, flags) \
16262306a36Sopenharmony_ci{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
16362306a36Sopenharmony_ci  .driver_info = (flags) }
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic struct usb_device_id usbat_usb_ids[] = {
16662306a36Sopenharmony_ci#	include "unusual_usbat.h"
16762306a36Sopenharmony_ci	{ }		/* Terminating entry */
16862306a36Sopenharmony_ci};
16962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, usbat_usb_ids);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci#undef UNUSUAL_DEV
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci/*
17462306a36Sopenharmony_ci * The flags table
17562306a36Sopenharmony_ci */
17662306a36Sopenharmony_ci#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
17762306a36Sopenharmony_ci		    vendor_name, product_name, use_protocol, use_transport, \
17862306a36Sopenharmony_ci		    init_function, Flags) \
17962306a36Sopenharmony_ci{ \
18062306a36Sopenharmony_ci	.vendorName = vendor_name,	\
18162306a36Sopenharmony_ci	.productName = product_name,	\
18262306a36Sopenharmony_ci	.useProtocol = use_protocol,	\
18362306a36Sopenharmony_ci	.useTransport = use_transport,	\
18462306a36Sopenharmony_ci	.initFunction = init_function,	\
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistatic struct us_unusual_dev usbat_unusual_dev_list[] = {
18862306a36Sopenharmony_ci#	include "unusual_usbat.h"
18962306a36Sopenharmony_ci	{ }		/* Terminating entry */
19062306a36Sopenharmony_ci};
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci#undef UNUSUAL_DEV
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci/*
19562306a36Sopenharmony_ci * Convenience function to produce an ATA read/write sectors command
19662306a36Sopenharmony_ci * Use cmd=0x20 for read, cmd=0x30 for write
19762306a36Sopenharmony_ci */
19862306a36Sopenharmony_cistatic void usbat_pack_ata_sector_cmd(unsigned char *buf,
19962306a36Sopenharmony_ci					unsigned char thistime,
20062306a36Sopenharmony_ci					u32 sector, unsigned char cmd)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	buf[0] = 0;
20362306a36Sopenharmony_ci	buf[1] = thistime;
20462306a36Sopenharmony_ci	buf[2] = sector & 0xFF;
20562306a36Sopenharmony_ci	buf[3] = (sector >>  8) & 0xFF;
20662306a36Sopenharmony_ci	buf[4] = (sector >> 16) & 0xFF;
20762306a36Sopenharmony_ci	buf[5] = 0xE0 | ((sector >> 24) & 0x0F);
20862306a36Sopenharmony_ci	buf[6] = cmd;
20962306a36Sopenharmony_ci}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci/*
21262306a36Sopenharmony_ci * Convenience function to get the device type (flash or hp8200)
21362306a36Sopenharmony_ci */
21462306a36Sopenharmony_cistatic int usbat_get_device_type(struct us_data *us)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	return ((struct usbat_info*)us->extra)->devicetype;
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci/*
22062306a36Sopenharmony_ci * Read a register from the device
22162306a36Sopenharmony_ci */
22262306a36Sopenharmony_cistatic int usbat_read(struct us_data *us,
22362306a36Sopenharmony_ci		      unsigned char access,
22462306a36Sopenharmony_ci		      unsigned char reg,
22562306a36Sopenharmony_ci		      unsigned char *content)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	return usb_stor_ctrl_transfer(us,
22862306a36Sopenharmony_ci		us->recv_ctrl_pipe,
22962306a36Sopenharmony_ci		access | USBAT_CMD_READ_REG,
23062306a36Sopenharmony_ci		0xC0,
23162306a36Sopenharmony_ci		(u16)reg,
23262306a36Sopenharmony_ci		0,
23362306a36Sopenharmony_ci		content,
23462306a36Sopenharmony_ci		1);
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci/*
23862306a36Sopenharmony_ci * Write to a register on the device
23962306a36Sopenharmony_ci */
24062306a36Sopenharmony_cistatic int usbat_write(struct us_data *us,
24162306a36Sopenharmony_ci		       unsigned char access,
24262306a36Sopenharmony_ci		       unsigned char reg,
24362306a36Sopenharmony_ci		       unsigned char content)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	return usb_stor_ctrl_transfer(us,
24662306a36Sopenharmony_ci		us->send_ctrl_pipe,
24762306a36Sopenharmony_ci		access | USBAT_CMD_WRITE_REG,
24862306a36Sopenharmony_ci		0x40,
24962306a36Sopenharmony_ci		short_pack(reg, content),
25062306a36Sopenharmony_ci		0,
25162306a36Sopenharmony_ci		NULL,
25262306a36Sopenharmony_ci		0);
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci/*
25662306a36Sopenharmony_ci * Convenience function to perform a bulk read
25762306a36Sopenharmony_ci */
25862306a36Sopenharmony_cistatic int usbat_bulk_read(struct us_data *us,
25962306a36Sopenharmony_ci			   void* buf,
26062306a36Sopenharmony_ci			   unsigned int len,
26162306a36Sopenharmony_ci			   int use_sg)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	if (len == 0)
26462306a36Sopenharmony_ci		return USB_STOR_XFER_GOOD;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	usb_stor_dbg(us, "len = %d\n", len);
26762306a36Sopenharmony_ci	return usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, buf, len, use_sg, NULL);
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci/*
27162306a36Sopenharmony_ci * Convenience function to perform a bulk write
27262306a36Sopenharmony_ci */
27362306a36Sopenharmony_cistatic int usbat_bulk_write(struct us_data *us,
27462306a36Sopenharmony_ci			    void* buf,
27562306a36Sopenharmony_ci			    unsigned int len,
27662306a36Sopenharmony_ci			    int use_sg)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	if (len == 0)
27962306a36Sopenharmony_ci		return USB_STOR_XFER_GOOD;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	usb_stor_dbg(us, "len = %d\n", len);
28262306a36Sopenharmony_ci	return usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, buf, len, use_sg, NULL);
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci/*
28662306a36Sopenharmony_ci * Some USBAT-specific commands can only be executed over a command transport
28762306a36Sopenharmony_ci * This transport allows one (len=8) or two (len=16) vendor-specific commands
28862306a36Sopenharmony_ci * to be executed.
28962306a36Sopenharmony_ci */
29062306a36Sopenharmony_cistatic int usbat_execute_command(struct us_data *us,
29162306a36Sopenharmony_ci								 unsigned char *commands,
29262306a36Sopenharmony_ci								 unsigned int len)
29362306a36Sopenharmony_ci{
29462306a36Sopenharmony_ci	return usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
29562306a36Sopenharmony_ci								  USBAT_CMD_EXEC_CMD, 0x40, 0, 0,
29662306a36Sopenharmony_ci								  commands, len);
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci/*
30062306a36Sopenharmony_ci * Read the status register
30162306a36Sopenharmony_ci */
30262306a36Sopenharmony_cistatic int usbat_get_status(struct us_data *us, unsigned char *status)
30362306a36Sopenharmony_ci{
30462306a36Sopenharmony_ci	int rc;
30562306a36Sopenharmony_ci	rc = usbat_read(us, USBAT_ATA, USBAT_ATA_STATUS, status);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	usb_stor_dbg(us, "0x%02X\n", *status);
30862306a36Sopenharmony_ci	return rc;
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci/*
31262306a36Sopenharmony_ci * Check the device status
31362306a36Sopenharmony_ci */
31462306a36Sopenharmony_cistatic int usbat_check_status(struct us_data *us)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	unsigned char *reply = us->iobuf;
31762306a36Sopenharmony_ci	int rc;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	rc = usbat_get_status(us, reply);
32062306a36Sopenharmony_ci	if (rc != USB_STOR_XFER_GOOD)
32162306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_FAILED;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	/* error/check condition (0x51 is ok) */
32462306a36Sopenharmony_ci	if (*reply & 0x01 && *reply != 0x51)
32562306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_FAILED;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	/* device fault */
32862306a36Sopenharmony_ci	if (*reply & 0x20)
32962306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_FAILED;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	return USB_STOR_TRANSPORT_GOOD;
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci/*
33562306a36Sopenharmony_ci * Stores critical information in internal registers in preparation for the execution
33662306a36Sopenharmony_ci * of a conditional usbat_read_blocks or usbat_write_blocks call.
33762306a36Sopenharmony_ci */
33862306a36Sopenharmony_cistatic int usbat_set_shuttle_features(struct us_data *us,
33962306a36Sopenharmony_ci				      unsigned char external_trigger,
34062306a36Sopenharmony_ci				      unsigned char epp_control,
34162306a36Sopenharmony_ci				      unsigned char mask_byte,
34262306a36Sopenharmony_ci				      unsigned char test_pattern,
34362306a36Sopenharmony_ci				      unsigned char subcountH,
34462306a36Sopenharmony_ci				      unsigned char subcountL)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	unsigned char *command = us->iobuf;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	command[0] = 0x40;
34962306a36Sopenharmony_ci	command[1] = USBAT_CMD_SET_FEAT;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	/*
35262306a36Sopenharmony_ci	 * The only bit relevant to ATA access is bit 6
35362306a36Sopenharmony_ci	 * which defines 8 bit data access (set) or 16 bit (unset)
35462306a36Sopenharmony_ci	 */
35562306a36Sopenharmony_ci	command[2] = epp_control;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	/*
35862306a36Sopenharmony_ci	 * If FCQ is set in the qualifier (defined in R/W cmd), then bits U0, U1,
35962306a36Sopenharmony_ci	 * ET1 and ET2 define an external event to be checked for on event of a
36062306a36Sopenharmony_ci	 * _read_blocks or _write_blocks operation. The read/write will not take
36162306a36Sopenharmony_ci	 * place unless the defined trigger signal is active.
36262306a36Sopenharmony_ci	 */
36362306a36Sopenharmony_ci	command[3] = external_trigger;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	/*
36662306a36Sopenharmony_ci	 * The resultant byte of the mask operation (see mask_byte) is compared for
36762306a36Sopenharmony_ci	 * equivalence with this test pattern. If equal, the read/write will take
36862306a36Sopenharmony_ci	 * place.
36962306a36Sopenharmony_ci	 */
37062306a36Sopenharmony_ci	command[4] = test_pattern;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	/*
37362306a36Sopenharmony_ci	 * This value is logically ANDed with the status register field specified
37462306a36Sopenharmony_ci	 * in the read/write command.
37562306a36Sopenharmony_ci	 */
37662306a36Sopenharmony_ci	command[5] = mask_byte;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	/*
37962306a36Sopenharmony_ci	 * If ALQ is set in the qualifier, this field contains the address of the
38062306a36Sopenharmony_ci	 * registers where the byte count should be read for transferring the data.
38162306a36Sopenharmony_ci	 * If ALQ is not set, then this field contains the number of bytes to be
38262306a36Sopenharmony_ci	 * transferred.
38362306a36Sopenharmony_ci	 */
38462306a36Sopenharmony_ci	command[6] = subcountL;
38562306a36Sopenharmony_ci	command[7] = subcountH;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	return usbat_execute_command(us, command, 8);
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci/*
39162306a36Sopenharmony_ci * Block, waiting for an ATA device to become not busy or to report
39262306a36Sopenharmony_ci * an error condition.
39362306a36Sopenharmony_ci */
39462306a36Sopenharmony_cistatic int usbat_wait_not_busy(struct us_data *us, int minutes)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci	int i;
39762306a36Sopenharmony_ci	int result;
39862306a36Sopenharmony_ci	unsigned char *status = us->iobuf;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	/*
40162306a36Sopenharmony_ci	 * Synchronizing cache on a CDR could take a heck of a long time,
40262306a36Sopenharmony_ci	 * but probably not more than 10 minutes or so. On the other hand,
40362306a36Sopenharmony_ci	 * doing a full blank on a CDRW at speed 1 will take about 75
40462306a36Sopenharmony_ci	 * minutes!
40562306a36Sopenharmony_ci	 */
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	for (i=0; i<1200+minutes*60; i++) {
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci 		result = usbat_get_status(us, status);
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci		if (result!=USB_STOR_XFER_GOOD)
41262306a36Sopenharmony_ci			return USB_STOR_TRANSPORT_ERROR;
41362306a36Sopenharmony_ci		if (*status & 0x01) { /* check condition */
41462306a36Sopenharmony_ci			result = usbat_read(us, USBAT_ATA, 0x10, status);
41562306a36Sopenharmony_ci			return USB_STOR_TRANSPORT_FAILED;
41662306a36Sopenharmony_ci		}
41762306a36Sopenharmony_ci		if (*status & 0x20) /* device fault */
41862306a36Sopenharmony_ci			return USB_STOR_TRANSPORT_FAILED;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci		if ((*status & 0x80)==0x00) { /* not busy */
42162306a36Sopenharmony_ci			usb_stor_dbg(us, "Waited not busy for %d steps\n", i);
42262306a36Sopenharmony_ci			return USB_STOR_TRANSPORT_GOOD;
42362306a36Sopenharmony_ci		}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci		if (i<500)
42662306a36Sopenharmony_ci			msleep(10); /* 5 seconds */
42762306a36Sopenharmony_ci		else if (i<700)
42862306a36Sopenharmony_ci			msleep(50); /* 10 seconds */
42962306a36Sopenharmony_ci		else if (i<1200)
43062306a36Sopenharmony_ci			msleep(100); /* 50 seconds */
43162306a36Sopenharmony_ci		else
43262306a36Sopenharmony_ci			msleep(1000); /* X minutes */
43362306a36Sopenharmony_ci	}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	usb_stor_dbg(us, "Waited not busy for %d minutes, timing out\n",
43662306a36Sopenharmony_ci		     minutes);
43762306a36Sopenharmony_ci	return USB_STOR_TRANSPORT_FAILED;
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci/*
44162306a36Sopenharmony_ci * Read block data from the data register
44262306a36Sopenharmony_ci */
44362306a36Sopenharmony_cistatic int usbat_read_block(struct us_data *us,
44462306a36Sopenharmony_ci			    void* buf,
44562306a36Sopenharmony_ci			    unsigned short len,
44662306a36Sopenharmony_ci			    int use_sg)
44762306a36Sopenharmony_ci{
44862306a36Sopenharmony_ci	int result;
44962306a36Sopenharmony_ci	unsigned char *command = us->iobuf;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	if (!len)
45262306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_GOOD;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	command[0] = 0xC0;
45562306a36Sopenharmony_ci	command[1] = USBAT_ATA | USBAT_CMD_READ_BLOCK;
45662306a36Sopenharmony_ci	command[2] = USBAT_ATA_DATA;
45762306a36Sopenharmony_ci	command[3] = 0;
45862306a36Sopenharmony_ci	command[4] = 0;
45962306a36Sopenharmony_ci	command[5] = 0;
46062306a36Sopenharmony_ci	command[6] = LSB_of(len);
46162306a36Sopenharmony_ci	command[7] = MSB_of(len);
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	result = usbat_execute_command(us, command, 8);
46462306a36Sopenharmony_ci	if (result != USB_STOR_XFER_GOOD)
46562306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	result = usbat_bulk_read(us, buf, len, use_sg);
46862306a36Sopenharmony_ci	return (result == USB_STOR_XFER_GOOD ?
46962306a36Sopenharmony_ci			USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
47062306a36Sopenharmony_ci}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci/*
47362306a36Sopenharmony_ci * Write block data via the data register
47462306a36Sopenharmony_ci */
47562306a36Sopenharmony_cistatic int usbat_write_block(struct us_data *us,
47662306a36Sopenharmony_ci			     unsigned char access,
47762306a36Sopenharmony_ci			     void* buf,
47862306a36Sopenharmony_ci			     unsigned short len,
47962306a36Sopenharmony_ci			     int minutes,
48062306a36Sopenharmony_ci			     int use_sg)
48162306a36Sopenharmony_ci{
48262306a36Sopenharmony_ci	int result;
48362306a36Sopenharmony_ci	unsigned char *command = us->iobuf;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	if (!len)
48662306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_GOOD;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	command[0] = 0x40;
48962306a36Sopenharmony_ci	command[1] = access | USBAT_CMD_WRITE_BLOCK;
49062306a36Sopenharmony_ci	command[2] = USBAT_ATA_DATA;
49162306a36Sopenharmony_ci	command[3] = 0;
49262306a36Sopenharmony_ci	command[4] = 0;
49362306a36Sopenharmony_ci	command[5] = 0;
49462306a36Sopenharmony_ci	command[6] = LSB_of(len);
49562306a36Sopenharmony_ci	command[7] = MSB_of(len);
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	result = usbat_execute_command(us, command, 8);
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	if (result != USB_STOR_XFER_GOOD)
50062306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	result = usbat_bulk_write(us, buf, len, use_sg);
50362306a36Sopenharmony_ci	if (result != USB_STOR_XFER_GOOD)
50462306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	return usbat_wait_not_busy(us, minutes);
50762306a36Sopenharmony_ci}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci/*
51062306a36Sopenharmony_ci * Process read and write requests
51162306a36Sopenharmony_ci */
51262306a36Sopenharmony_cistatic int usbat_hp8200e_rw_block_test(struct us_data *us,
51362306a36Sopenharmony_ci				       unsigned char access,
51462306a36Sopenharmony_ci				       unsigned char *registers,
51562306a36Sopenharmony_ci				       unsigned char *data_out,
51662306a36Sopenharmony_ci				       unsigned short num_registers,
51762306a36Sopenharmony_ci				       unsigned char data_reg,
51862306a36Sopenharmony_ci				       unsigned char status_reg,
51962306a36Sopenharmony_ci				       unsigned char timeout,
52062306a36Sopenharmony_ci				       unsigned char qualifier,
52162306a36Sopenharmony_ci				       int direction,
52262306a36Sopenharmony_ci				       void *buf,
52362306a36Sopenharmony_ci				       unsigned short len,
52462306a36Sopenharmony_ci				       int use_sg,
52562306a36Sopenharmony_ci				       int minutes)
52662306a36Sopenharmony_ci{
52762306a36Sopenharmony_ci	int result;
52862306a36Sopenharmony_ci	unsigned int pipe = (direction == DMA_FROM_DEVICE) ?
52962306a36Sopenharmony_ci			us->recv_bulk_pipe : us->send_bulk_pipe;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	unsigned char *command = us->iobuf;
53262306a36Sopenharmony_ci	int i, j;
53362306a36Sopenharmony_ci	int cmdlen;
53462306a36Sopenharmony_ci	unsigned char *data = us->iobuf;
53562306a36Sopenharmony_ci	unsigned char *status = us->iobuf;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	BUG_ON(num_registers > US_IOBUF_SIZE/2);
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	for (i=0; i<20; i++) {
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci		/*
54262306a36Sopenharmony_ci		 * The first time we send the full command, which consists
54362306a36Sopenharmony_ci		 * of downloading the SCSI command followed by downloading
54462306a36Sopenharmony_ci		 * the data via a write-and-test.  Any other time we only
54562306a36Sopenharmony_ci		 * send the command to download the data -- the SCSI command
54662306a36Sopenharmony_ci		 * is still 'active' in some sense in the device.
54762306a36Sopenharmony_ci		 *
54862306a36Sopenharmony_ci		 * We're only going to try sending the data 10 times. After
54962306a36Sopenharmony_ci		 * that, we just return a failure.
55062306a36Sopenharmony_ci		 */
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci		if (i==0) {
55362306a36Sopenharmony_ci			cmdlen = 16;
55462306a36Sopenharmony_ci			/*
55562306a36Sopenharmony_ci			 * Write to multiple registers
55662306a36Sopenharmony_ci			 * Not really sure the 0x07, 0x17, 0xfc, 0xe7 is
55762306a36Sopenharmony_ci			 * necessary here, but that's what came out of the
55862306a36Sopenharmony_ci			 * trace every single time.
55962306a36Sopenharmony_ci			 */
56062306a36Sopenharmony_ci			command[0] = 0x40;
56162306a36Sopenharmony_ci			command[1] = access | USBAT_CMD_WRITE_REGS;
56262306a36Sopenharmony_ci			command[2] = 0x07;
56362306a36Sopenharmony_ci			command[3] = 0x17;
56462306a36Sopenharmony_ci			command[4] = 0xFC;
56562306a36Sopenharmony_ci			command[5] = 0xE7;
56662306a36Sopenharmony_ci			command[6] = LSB_of(num_registers*2);
56762306a36Sopenharmony_ci			command[7] = MSB_of(num_registers*2);
56862306a36Sopenharmony_ci		} else
56962306a36Sopenharmony_ci			cmdlen = 8;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci		/* Conditionally read or write blocks */
57262306a36Sopenharmony_ci		command[cmdlen-8] = (direction==DMA_TO_DEVICE ? 0x40 : 0xC0);
57362306a36Sopenharmony_ci		command[cmdlen-7] = access |
57462306a36Sopenharmony_ci				(direction==DMA_TO_DEVICE ?
57562306a36Sopenharmony_ci				 USBAT_CMD_COND_WRITE_BLOCK : USBAT_CMD_COND_READ_BLOCK);
57662306a36Sopenharmony_ci		command[cmdlen-6] = data_reg;
57762306a36Sopenharmony_ci		command[cmdlen-5] = status_reg;
57862306a36Sopenharmony_ci		command[cmdlen-4] = timeout;
57962306a36Sopenharmony_ci		command[cmdlen-3] = qualifier;
58062306a36Sopenharmony_ci		command[cmdlen-2] = LSB_of(len);
58162306a36Sopenharmony_ci		command[cmdlen-1] = MSB_of(len);
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci		result = usbat_execute_command(us, command, cmdlen);
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci		if (result != USB_STOR_XFER_GOOD)
58662306a36Sopenharmony_ci			return USB_STOR_TRANSPORT_ERROR;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci		if (i==0) {
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci			for (j=0; j<num_registers; j++) {
59162306a36Sopenharmony_ci				data[j<<1] = registers[j];
59262306a36Sopenharmony_ci				data[1+(j<<1)] = data_out[j];
59362306a36Sopenharmony_ci			}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci			result = usbat_bulk_write(us, data, num_registers*2, 0);
59662306a36Sopenharmony_ci			if (result != USB_STOR_XFER_GOOD)
59762306a36Sopenharmony_ci				return USB_STOR_TRANSPORT_ERROR;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci		}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci		result = usb_stor_bulk_transfer_sg(us,
60262306a36Sopenharmony_ci			pipe, buf, len, use_sg, NULL);
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci		/*
60562306a36Sopenharmony_ci		 * If we get a stall on the bulk download, we'll retry
60662306a36Sopenharmony_ci		 * the bulk download -- but not the SCSI command because
60762306a36Sopenharmony_ci		 * in some sense the SCSI command is still 'active' and
60862306a36Sopenharmony_ci		 * waiting for the data. Don't ask me why this should be;
60962306a36Sopenharmony_ci		 * I'm only following what the Windoze driver did.
61062306a36Sopenharmony_ci		 *
61162306a36Sopenharmony_ci		 * Note that a stall for the test-and-read/write command means
61262306a36Sopenharmony_ci		 * that the test failed. In this case we're testing to make
61362306a36Sopenharmony_ci		 * sure that the device is error-free
61462306a36Sopenharmony_ci		 * (i.e. bit 0 -- CHK -- of status is 0). The most likely
61562306a36Sopenharmony_ci		 * hypothesis is that the USBAT chip somehow knows what
61662306a36Sopenharmony_ci		 * the device will accept, but doesn't give the device any
61762306a36Sopenharmony_ci		 * data until all data is received. Thus, the device would
61862306a36Sopenharmony_ci		 * still be waiting for the first byte of data if a stall
61962306a36Sopenharmony_ci		 * occurs, even if the stall implies that some data was
62062306a36Sopenharmony_ci		 * transferred.
62162306a36Sopenharmony_ci		 */
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci		if (result == USB_STOR_XFER_SHORT ||
62462306a36Sopenharmony_ci				result == USB_STOR_XFER_STALLED) {
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci			/*
62762306a36Sopenharmony_ci			 * If we're reading and we stalled, then clear
62862306a36Sopenharmony_ci			 * the bulk output pipe only the first time.
62962306a36Sopenharmony_ci			 */
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci			if (direction==DMA_FROM_DEVICE && i==0) {
63262306a36Sopenharmony_ci				if (usb_stor_clear_halt(us,
63362306a36Sopenharmony_ci						us->send_bulk_pipe) < 0)
63462306a36Sopenharmony_ci					return USB_STOR_TRANSPORT_ERROR;
63562306a36Sopenharmony_ci			}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci			/*
63862306a36Sopenharmony_ci			 * Read status: is the device angry, or just busy?
63962306a36Sopenharmony_ci			 */
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci 			result = usbat_read(us, USBAT_ATA,
64262306a36Sopenharmony_ci				direction==DMA_TO_DEVICE ?
64362306a36Sopenharmony_ci					USBAT_ATA_STATUS : USBAT_ATA_ALTSTATUS,
64462306a36Sopenharmony_ci				status);
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci			if (result!=USB_STOR_XFER_GOOD)
64762306a36Sopenharmony_ci				return USB_STOR_TRANSPORT_ERROR;
64862306a36Sopenharmony_ci			if (*status & 0x01) /* check condition */
64962306a36Sopenharmony_ci				return USB_STOR_TRANSPORT_FAILED;
65062306a36Sopenharmony_ci			if (*status & 0x20) /* device fault */
65162306a36Sopenharmony_ci				return USB_STOR_TRANSPORT_FAILED;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci			usb_stor_dbg(us, "Redoing %s\n",
65462306a36Sopenharmony_ci				     direction == DMA_TO_DEVICE
65562306a36Sopenharmony_ci				     ? "write" : "read");
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci		} else if (result != USB_STOR_XFER_GOOD)
65862306a36Sopenharmony_ci			return USB_STOR_TRANSPORT_ERROR;
65962306a36Sopenharmony_ci		else
66062306a36Sopenharmony_ci			return usbat_wait_not_busy(us, minutes);
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	usb_stor_dbg(us, "Bummer! %s bulk data 20 times failed\n",
66562306a36Sopenharmony_ci		     direction == DMA_TO_DEVICE ? "Writing" : "Reading");
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	return USB_STOR_TRANSPORT_FAILED;
66862306a36Sopenharmony_ci}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci/*
67162306a36Sopenharmony_ci * Write to multiple registers:
67262306a36Sopenharmony_ci * Allows us to write specific data to any registers. The data to be written
67362306a36Sopenharmony_ci * gets packed in this sequence: reg0, data0, reg1, data1, ..., regN, dataN
67462306a36Sopenharmony_ci * which gets sent through bulk out.
67562306a36Sopenharmony_ci * Not designed for large transfers of data!
67662306a36Sopenharmony_ci */
67762306a36Sopenharmony_cistatic int usbat_multiple_write(struct us_data *us,
67862306a36Sopenharmony_ci				unsigned char *registers,
67962306a36Sopenharmony_ci				unsigned char *data_out,
68062306a36Sopenharmony_ci				unsigned short num_registers)
68162306a36Sopenharmony_ci{
68262306a36Sopenharmony_ci	int i, result;
68362306a36Sopenharmony_ci	unsigned char *data = us->iobuf;
68462306a36Sopenharmony_ci	unsigned char *command = us->iobuf;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	BUG_ON(num_registers > US_IOBUF_SIZE/2);
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	/* Write to multiple registers, ATA access */
68962306a36Sopenharmony_ci	command[0] = 0x40;
69062306a36Sopenharmony_ci	command[1] = USBAT_ATA | USBAT_CMD_WRITE_REGS;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	/* No relevance */
69362306a36Sopenharmony_ci	command[2] = 0;
69462306a36Sopenharmony_ci	command[3] = 0;
69562306a36Sopenharmony_ci	command[4] = 0;
69662306a36Sopenharmony_ci	command[5] = 0;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	/* Number of bytes to be transferred (incl. addresses and data) */
69962306a36Sopenharmony_ci	command[6] = LSB_of(num_registers*2);
70062306a36Sopenharmony_ci	command[7] = MSB_of(num_registers*2);
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	/* The setup command */
70362306a36Sopenharmony_ci	result = usbat_execute_command(us, command, 8);
70462306a36Sopenharmony_ci	if (result != USB_STOR_XFER_GOOD)
70562306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	/* Create the reg/data, reg/data sequence */
70862306a36Sopenharmony_ci	for (i=0; i<num_registers; i++) {
70962306a36Sopenharmony_ci		data[i<<1] = registers[i];
71062306a36Sopenharmony_ci		data[1+(i<<1)] = data_out[i];
71162306a36Sopenharmony_ci	}
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	/* Send the data */
71462306a36Sopenharmony_ci	result = usbat_bulk_write(us, data, num_registers*2, 0);
71562306a36Sopenharmony_ci	if (result != USB_STOR_XFER_GOOD)
71662306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	if (usbat_get_device_type(us) == USBAT_DEV_HP8200)
71962306a36Sopenharmony_ci		return usbat_wait_not_busy(us, 0);
72062306a36Sopenharmony_ci	else
72162306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_GOOD;
72262306a36Sopenharmony_ci}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci/*
72562306a36Sopenharmony_ci * Conditionally read blocks from device:
72662306a36Sopenharmony_ci * Allows us to read blocks from a specific data register, based upon the
72762306a36Sopenharmony_ci * condition that a status register can be successfully masked with a status
72862306a36Sopenharmony_ci * qualifier. If this condition is not initially met, the read will wait
72962306a36Sopenharmony_ci * up until a maximum amount of time has elapsed, as specified by timeout.
73062306a36Sopenharmony_ci * The read will start when the condition is met, otherwise the command aborts.
73162306a36Sopenharmony_ci *
73262306a36Sopenharmony_ci * The qualifier defined here is not the value that is masked, it defines
73362306a36Sopenharmony_ci * conditions for the write to take place. The actual masked qualifier (and
73462306a36Sopenharmony_ci * other related details) are defined beforehand with _set_shuttle_features().
73562306a36Sopenharmony_ci */
73662306a36Sopenharmony_cistatic int usbat_read_blocks(struct us_data *us,
73762306a36Sopenharmony_ci			     void* buffer,
73862306a36Sopenharmony_ci			     int len,
73962306a36Sopenharmony_ci			     int use_sg)
74062306a36Sopenharmony_ci{
74162306a36Sopenharmony_ci	int result;
74262306a36Sopenharmony_ci	unsigned char *command = us->iobuf;
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	command[0] = 0xC0;
74562306a36Sopenharmony_ci	command[1] = USBAT_ATA | USBAT_CMD_COND_READ_BLOCK;
74662306a36Sopenharmony_ci	command[2] = USBAT_ATA_DATA;
74762306a36Sopenharmony_ci	command[3] = USBAT_ATA_STATUS;
74862306a36Sopenharmony_ci	command[4] = 0xFD; /* Timeout (ms); */
74962306a36Sopenharmony_ci	command[5] = USBAT_QUAL_FCQ;
75062306a36Sopenharmony_ci	command[6] = LSB_of(len);
75162306a36Sopenharmony_ci	command[7] = MSB_of(len);
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	/* Multiple block read setup command */
75462306a36Sopenharmony_ci	result = usbat_execute_command(us, command, 8);
75562306a36Sopenharmony_ci	if (result != USB_STOR_XFER_GOOD)
75662306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_FAILED;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	/* Read the blocks we just asked for */
75962306a36Sopenharmony_ci	result = usbat_bulk_read(us, buffer, len, use_sg);
76062306a36Sopenharmony_ci	if (result != USB_STOR_XFER_GOOD)
76162306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_FAILED;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	return USB_STOR_TRANSPORT_GOOD;
76462306a36Sopenharmony_ci}
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci/*
76762306a36Sopenharmony_ci * Conditionally write blocks to device:
76862306a36Sopenharmony_ci * Allows us to write blocks to a specific data register, based upon the
76962306a36Sopenharmony_ci * condition that a status register can be successfully masked with a status
77062306a36Sopenharmony_ci * qualifier. If this condition is not initially met, the write will wait
77162306a36Sopenharmony_ci * up until a maximum amount of time has elapsed, as specified by timeout.
77262306a36Sopenharmony_ci * The read will start when the condition is met, otherwise the command aborts.
77362306a36Sopenharmony_ci *
77462306a36Sopenharmony_ci * The qualifier defined here is not the value that is masked, it defines
77562306a36Sopenharmony_ci * conditions for the write to take place. The actual masked qualifier (and
77662306a36Sopenharmony_ci * other related details) are defined beforehand with _set_shuttle_features().
77762306a36Sopenharmony_ci */
77862306a36Sopenharmony_cistatic int usbat_write_blocks(struct us_data *us,
77962306a36Sopenharmony_ci			      void* buffer,
78062306a36Sopenharmony_ci			      int len,
78162306a36Sopenharmony_ci			      int use_sg)
78262306a36Sopenharmony_ci{
78362306a36Sopenharmony_ci	int result;
78462306a36Sopenharmony_ci	unsigned char *command = us->iobuf;
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	command[0] = 0x40;
78762306a36Sopenharmony_ci	command[1] = USBAT_ATA | USBAT_CMD_COND_WRITE_BLOCK;
78862306a36Sopenharmony_ci	command[2] = USBAT_ATA_DATA;
78962306a36Sopenharmony_ci	command[3] = USBAT_ATA_STATUS;
79062306a36Sopenharmony_ci	command[4] = 0xFD; /* Timeout (ms) */
79162306a36Sopenharmony_ci	command[5] = USBAT_QUAL_FCQ;
79262306a36Sopenharmony_ci	command[6] = LSB_of(len);
79362306a36Sopenharmony_ci	command[7] = MSB_of(len);
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	/* Multiple block write setup command */
79662306a36Sopenharmony_ci	result = usbat_execute_command(us, command, 8);
79762306a36Sopenharmony_ci	if (result != USB_STOR_XFER_GOOD)
79862306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_FAILED;
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	/* Write the data */
80162306a36Sopenharmony_ci	result = usbat_bulk_write(us, buffer, len, use_sg);
80262306a36Sopenharmony_ci	if (result != USB_STOR_XFER_GOOD)
80362306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_FAILED;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	return USB_STOR_TRANSPORT_GOOD;
80662306a36Sopenharmony_ci}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci/*
80962306a36Sopenharmony_ci * Read the User IO register
81062306a36Sopenharmony_ci */
81162306a36Sopenharmony_cistatic int usbat_read_user_io(struct us_data *us, unsigned char *data_flags)
81262306a36Sopenharmony_ci{
81362306a36Sopenharmony_ci	int result;
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	result = usb_stor_ctrl_transfer(us,
81662306a36Sopenharmony_ci		us->recv_ctrl_pipe,
81762306a36Sopenharmony_ci		USBAT_CMD_UIO,
81862306a36Sopenharmony_ci		0xC0,
81962306a36Sopenharmony_ci		0,
82062306a36Sopenharmony_ci		0,
82162306a36Sopenharmony_ci		data_flags,
82262306a36Sopenharmony_ci		USBAT_UIO_READ);
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	usb_stor_dbg(us, "UIO register reads %02X\n", *data_flags);
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	return result;
82762306a36Sopenharmony_ci}
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci/*
83062306a36Sopenharmony_ci * Write to the User IO register
83162306a36Sopenharmony_ci */
83262306a36Sopenharmony_cistatic int usbat_write_user_io(struct us_data *us,
83362306a36Sopenharmony_ci			       unsigned char enable_flags,
83462306a36Sopenharmony_ci			       unsigned char data_flags)
83562306a36Sopenharmony_ci{
83662306a36Sopenharmony_ci	return usb_stor_ctrl_transfer(us,
83762306a36Sopenharmony_ci		us->send_ctrl_pipe,
83862306a36Sopenharmony_ci		USBAT_CMD_UIO,
83962306a36Sopenharmony_ci		0x40,
84062306a36Sopenharmony_ci		short_pack(enable_flags, data_flags),
84162306a36Sopenharmony_ci		0,
84262306a36Sopenharmony_ci		NULL,
84362306a36Sopenharmony_ci		USBAT_UIO_WRITE);
84462306a36Sopenharmony_ci}
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci/*
84762306a36Sopenharmony_ci * Reset the device
84862306a36Sopenharmony_ci * Often needed on media change.
84962306a36Sopenharmony_ci */
85062306a36Sopenharmony_cistatic int usbat_device_reset(struct us_data *us)
85162306a36Sopenharmony_ci{
85262306a36Sopenharmony_ci	int rc;
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	/*
85562306a36Sopenharmony_ci	 * Reset peripheral, enable peripheral control signals
85662306a36Sopenharmony_ci	 * (bring reset signal up)
85762306a36Sopenharmony_ci	 */
85862306a36Sopenharmony_ci	rc = usbat_write_user_io(us,
85962306a36Sopenharmony_ci							 USBAT_UIO_DRVRST | USBAT_UIO_OE1 | USBAT_UIO_OE0,
86062306a36Sopenharmony_ci							 USBAT_UIO_EPAD | USBAT_UIO_1);
86162306a36Sopenharmony_ci	if (rc != USB_STOR_XFER_GOOD)
86262306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	/*
86562306a36Sopenharmony_ci	 * Enable peripheral control signals
86662306a36Sopenharmony_ci	 * (bring reset signal down)
86762306a36Sopenharmony_ci	 */
86862306a36Sopenharmony_ci	rc = usbat_write_user_io(us,
86962306a36Sopenharmony_ci							 USBAT_UIO_OE1  | USBAT_UIO_OE0,
87062306a36Sopenharmony_ci							 USBAT_UIO_EPAD | USBAT_UIO_1);
87162306a36Sopenharmony_ci	if (rc != USB_STOR_XFER_GOOD)
87262306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	return USB_STOR_TRANSPORT_GOOD;
87562306a36Sopenharmony_ci}
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci/*
87862306a36Sopenharmony_ci * Enable card detect
87962306a36Sopenharmony_ci */
88062306a36Sopenharmony_cistatic int usbat_device_enable_cdt(struct us_data *us)
88162306a36Sopenharmony_ci{
88262306a36Sopenharmony_ci	int rc;
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	/* Enable peripheral control signals and card detect */
88562306a36Sopenharmony_ci	rc = usbat_write_user_io(us,
88662306a36Sopenharmony_ci							 USBAT_UIO_ACKD | USBAT_UIO_OE1  | USBAT_UIO_OE0,
88762306a36Sopenharmony_ci							 USBAT_UIO_EPAD | USBAT_UIO_1);
88862306a36Sopenharmony_ci	if (rc != USB_STOR_XFER_GOOD)
88962306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	return USB_STOR_TRANSPORT_GOOD;
89262306a36Sopenharmony_ci}
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci/*
89562306a36Sopenharmony_ci * Determine if media is present.
89662306a36Sopenharmony_ci */
89762306a36Sopenharmony_cistatic int usbat_flash_check_media_present(struct us_data *us,
89862306a36Sopenharmony_ci					   unsigned char *uio)
89962306a36Sopenharmony_ci{
90062306a36Sopenharmony_ci	if (*uio & USBAT_UIO_UI0) {
90162306a36Sopenharmony_ci		usb_stor_dbg(us, "no media detected\n");
90262306a36Sopenharmony_ci		return USBAT_FLASH_MEDIA_NONE;
90362306a36Sopenharmony_ci	}
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	return USBAT_FLASH_MEDIA_CF;
90662306a36Sopenharmony_ci}
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci/*
90962306a36Sopenharmony_ci * Determine if media has changed since last operation
91062306a36Sopenharmony_ci */
91162306a36Sopenharmony_cistatic int usbat_flash_check_media_changed(struct us_data *us,
91262306a36Sopenharmony_ci					   unsigned char *uio)
91362306a36Sopenharmony_ci{
91462306a36Sopenharmony_ci	if (*uio & USBAT_UIO_0) {
91562306a36Sopenharmony_ci		usb_stor_dbg(us, "media change detected\n");
91662306a36Sopenharmony_ci		return USBAT_FLASH_MEDIA_CHANGED;
91762306a36Sopenharmony_ci	}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	return USBAT_FLASH_MEDIA_SAME;
92062306a36Sopenharmony_ci}
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci/*
92362306a36Sopenharmony_ci * Check for media change / no media and handle the situation appropriately
92462306a36Sopenharmony_ci */
92562306a36Sopenharmony_cistatic int usbat_flash_check_media(struct us_data *us,
92662306a36Sopenharmony_ci				   struct usbat_info *info)
92762306a36Sopenharmony_ci{
92862306a36Sopenharmony_ci	int rc;
92962306a36Sopenharmony_ci	unsigned char *uio = us->iobuf;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	rc = usbat_read_user_io(us, uio);
93262306a36Sopenharmony_ci	if (rc != USB_STOR_XFER_GOOD)
93362306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	/* Check for media existence */
93662306a36Sopenharmony_ci	rc = usbat_flash_check_media_present(us, uio);
93762306a36Sopenharmony_ci	if (rc == USBAT_FLASH_MEDIA_NONE) {
93862306a36Sopenharmony_ci		info->sense_key = 0x02;
93962306a36Sopenharmony_ci		info->sense_asc = 0x3A;
94062306a36Sopenharmony_ci		info->sense_ascq = 0x00;
94162306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_FAILED;
94262306a36Sopenharmony_ci	}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	/* Check for media change */
94562306a36Sopenharmony_ci	rc = usbat_flash_check_media_changed(us, uio);
94662306a36Sopenharmony_ci	if (rc == USBAT_FLASH_MEDIA_CHANGED) {
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci		/* Reset and re-enable card detect */
94962306a36Sopenharmony_ci		rc = usbat_device_reset(us);
95062306a36Sopenharmony_ci		if (rc != USB_STOR_TRANSPORT_GOOD)
95162306a36Sopenharmony_ci			return rc;
95262306a36Sopenharmony_ci		rc = usbat_device_enable_cdt(us);
95362306a36Sopenharmony_ci		if (rc != USB_STOR_TRANSPORT_GOOD)
95462306a36Sopenharmony_ci			return rc;
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci		msleep(50);
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci		rc = usbat_read_user_io(us, uio);
95962306a36Sopenharmony_ci		if (rc != USB_STOR_XFER_GOOD)
96062306a36Sopenharmony_ci			return USB_STOR_TRANSPORT_ERROR;
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci		info->sense_key = UNIT_ATTENTION;
96362306a36Sopenharmony_ci		info->sense_asc = 0x28;
96462306a36Sopenharmony_ci		info->sense_ascq = 0x00;
96562306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_FAILED;
96662306a36Sopenharmony_ci	}
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	return USB_STOR_TRANSPORT_GOOD;
96962306a36Sopenharmony_ci}
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci/*
97262306a36Sopenharmony_ci * Determine whether we are controlling a flash-based reader/writer,
97362306a36Sopenharmony_ci * or a HP8200-based CD drive.
97462306a36Sopenharmony_ci * Sets transport functions as appropriate.
97562306a36Sopenharmony_ci */
97662306a36Sopenharmony_cistatic int usbat_identify_device(struct us_data *us,
97762306a36Sopenharmony_ci				 struct usbat_info *info)
97862306a36Sopenharmony_ci{
97962306a36Sopenharmony_ci	int rc;
98062306a36Sopenharmony_ci	unsigned char status;
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	if (!us || !info)
98362306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	rc = usbat_device_reset(us);
98662306a36Sopenharmony_ci	if (rc != USB_STOR_TRANSPORT_GOOD)
98762306a36Sopenharmony_ci		return rc;
98862306a36Sopenharmony_ci	msleep(500);
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	/*
99162306a36Sopenharmony_ci	 * In attempt to distinguish between HP CDRW's and Flash readers, we now
99262306a36Sopenharmony_ci	 * execute the IDENTIFY PACKET DEVICE command. On ATA devices (i.e. flash
99362306a36Sopenharmony_ci	 * readers), this command should fail with error. On ATAPI devices (i.e.
99462306a36Sopenharmony_ci	 * CDROM drives), it should succeed.
99562306a36Sopenharmony_ci	 */
99662306a36Sopenharmony_ci	rc = usbat_write(us, USBAT_ATA, USBAT_ATA_CMD, 0xA1);
99762306a36Sopenharmony_ci 	if (rc != USB_STOR_XFER_GOOD)
99862306a36Sopenharmony_ci 		return USB_STOR_TRANSPORT_ERROR;
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	rc = usbat_get_status(us, &status);
100162306a36Sopenharmony_ci 	if (rc != USB_STOR_XFER_GOOD)
100262306a36Sopenharmony_ci 		return USB_STOR_TRANSPORT_ERROR;
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	/* Check for error bit, or if the command 'fell through' */
100562306a36Sopenharmony_ci	if (status == 0xA1 || !(status & 0x01)) {
100662306a36Sopenharmony_ci		/* Device is HP 8200 */
100762306a36Sopenharmony_ci		usb_stor_dbg(us, "Detected HP8200 CDRW\n");
100862306a36Sopenharmony_ci		info->devicetype = USBAT_DEV_HP8200;
100962306a36Sopenharmony_ci	} else {
101062306a36Sopenharmony_ci		/* Device is a CompactFlash reader/writer */
101162306a36Sopenharmony_ci		usb_stor_dbg(us, "Detected Flash reader/writer\n");
101262306a36Sopenharmony_ci		info->devicetype = USBAT_DEV_FLASH;
101362306a36Sopenharmony_ci	}
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	return USB_STOR_TRANSPORT_GOOD;
101662306a36Sopenharmony_ci}
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci/*
101962306a36Sopenharmony_ci * Set the transport function based on the device type
102062306a36Sopenharmony_ci */
102162306a36Sopenharmony_cistatic int usbat_set_transport(struct us_data *us,
102262306a36Sopenharmony_ci			       struct usbat_info *info,
102362306a36Sopenharmony_ci			       int devicetype)
102462306a36Sopenharmony_ci{
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	if (!info->devicetype)
102762306a36Sopenharmony_ci		info->devicetype = devicetype;
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	if (!info->devicetype)
103062306a36Sopenharmony_ci		usbat_identify_device(us, info);
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	switch (info->devicetype) {
103362306a36Sopenharmony_ci	default:
103462306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	case  USBAT_DEV_HP8200:
103762306a36Sopenharmony_ci		us->transport = usbat_hp8200e_transport;
103862306a36Sopenharmony_ci		break;
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	case USBAT_DEV_FLASH:
104162306a36Sopenharmony_ci		us->transport = usbat_flash_transport;
104262306a36Sopenharmony_ci		break;
104362306a36Sopenharmony_ci	}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	return 0;
104662306a36Sopenharmony_ci}
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci/*
104962306a36Sopenharmony_ci * Read the media capacity
105062306a36Sopenharmony_ci */
105162306a36Sopenharmony_cistatic int usbat_flash_get_sector_count(struct us_data *us,
105262306a36Sopenharmony_ci					struct usbat_info *info)
105362306a36Sopenharmony_ci{
105462306a36Sopenharmony_ci	unsigned char registers[3] = {
105562306a36Sopenharmony_ci		USBAT_ATA_SECCNT,
105662306a36Sopenharmony_ci		USBAT_ATA_DEVICE,
105762306a36Sopenharmony_ci		USBAT_ATA_CMD,
105862306a36Sopenharmony_ci	};
105962306a36Sopenharmony_ci	unsigned char  command[3] = { 0x01, 0xA0, 0xEC };
106062306a36Sopenharmony_ci	unsigned char *reply;
106162306a36Sopenharmony_ci	unsigned char status;
106262306a36Sopenharmony_ci	int rc;
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	if (!us || !info)
106562306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	reply = kmalloc(512, GFP_NOIO);
106862306a36Sopenharmony_ci	if (!reply)
106962306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	/* ATA command : IDENTIFY DEVICE */
107262306a36Sopenharmony_ci	rc = usbat_multiple_write(us, registers, command, 3);
107362306a36Sopenharmony_ci	if (rc != USB_STOR_XFER_GOOD) {
107462306a36Sopenharmony_ci		usb_stor_dbg(us, "Gah! identify_device failed\n");
107562306a36Sopenharmony_ci		rc = USB_STOR_TRANSPORT_ERROR;
107662306a36Sopenharmony_ci		goto leave;
107762306a36Sopenharmony_ci	}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	/* Read device status */
108062306a36Sopenharmony_ci	if (usbat_get_status(us, &status) != USB_STOR_XFER_GOOD) {
108162306a36Sopenharmony_ci		rc = USB_STOR_TRANSPORT_ERROR;
108262306a36Sopenharmony_ci		goto leave;
108362306a36Sopenharmony_ci	}
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	msleep(100);
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci	/* Read the device identification data */
108862306a36Sopenharmony_ci	rc = usbat_read_block(us, reply, 512, 0);
108962306a36Sopenharmony_ci	if (rc != USB_STOR_TRANSPORT_GOOD)
109062306a36Sopenharmony_ci		goto leave;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	info->sectors = ((u32)(reply[117]) << 24) |
109362306a36Sopenharmony_ci		((u32)(reply[116]) << 16) |
109462306a36Sopenharmony_ci		((u32)(reply[115]) <<  8) |
109562306a36Sopenharmony_ci		((u32)(reply[114])      );
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	rc = USB_STOR_TRANSPORT_GOOD;
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci leave:
110062306a36Sopenharmony_ci	kfree(reply);
110162306a36Sopenharmony_ci	return rc;
110262306a36Sopenharmony_ci}
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci/*
110562306a36Sopenharmony_ci * Read data from device
110662306a36Sopenharmony_ci */
110762306a36Sopenharmony_cistatic int usbat_flash_read_data(struct us_data *us,
110862306a36Sopenharmony_ci								 struct usbat_info *info,
110962306a36Sopenharmony_ci								 u32 sector,
111062306a36Sopenharmony_ci								 u32 sectors)
111162306a36Sopenharmony_ci{
111262306a36Sopenharmony_ci	unsigned char registers[7] = {
111362306a36Sopenharmony_ci		USBAT_ATA_FEATURES,
111462306a36Sopenharmony_ci		USBAT_ATA_SECCNT,
111562306a36Sopenharmony_ci		USBAT_ATA_SECNUM,
111662306a36Sopenharmony_ci		USBAT_ATA_LBA_ME,
111762306a36Sopenharmony_ci		USBAT_ATA_LBA_HI,
111862306a36Sopenharmony_ci		USBAT_ATA_DEVICE,
111962306a36Sopenharmony_ci		USBAT_ATA_STATUS,
112062306a36Sopenharmony_ci	};
112162306a36Sopenharmony_ci	unsigned char command[7];
112262306a36Sopenharmony_ci	unsigned char *buffer;
112362306a36Sopenharmony_ci	unsigned char  thistime;
112462306a36Sopenharmony_ci	unsigned int totallen, alloclen;
112562306a36Sopenharmony_ci	int len, result;
112662306a36Sopenharmony_ci	unsigned int sg_offset = 0;
112762306a36Sopenharmony_ci	struct scatterlist *sg = NULL;
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	result = usbat_flash_check_media(us, info);
113062306a36Sopenharmony_ci	if (result != USB_STOR_TRANSPORT_GOOD)
113162306a36Sopenharmony_ci		return result;
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	/*
113462306a36Sopenharmony_ci	 * we're working in LBA mode.  according to the ATA spec,
113562306a36Sopenharmony_ci	 * we can support up to 28-bit addressing.  I don't know if Jumpshot
113662306a36Sopenharmony_ci	 * supports beyond 24-bit addressing.  It's kind of hard to test
113762306a36Sopenharmony_ci	 * since it requires > 8GB CF card.
113862306a36Sopenharmony_ci	 */
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	if (sector > 0x0FFFFFFF)
114162306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	totallen = sectors * info->ssize;
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	/*
114662306a36Sopenharmony_ci	 * Since we don't read more than 64 KB at a time, we have to create
114762306a36Sopenharmony_ci	 * a bounce buffer and move the data a piece at a time between the
114862306a36Sopenharmony_ci	 * bounce buffer and the actual transfer buffer.
114962306a36Sopenharmony_ci	 */
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci	alloclen = min(totallen, 65536u);
115262306a36Sopenharmony_ci	buffer = kmalloc(alloclen, GFP_NOIO);
115362306a36Sopenharmony_ci	if (buffer == NULL)
115462306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	do {
115762306a36Sopenharmony_ci		/*
115862306a36Sopenharmony_ci		 * loop, never allocate or transfer more than 64k at once
115962306a36Sopenharmony_ci		 * (min(128k, 255*info->ssize) is the real limit)
116062306a36Sopenharmony_ci		 */
116162306a36Sopenharmony_ci		len = min(totallen, alloclen);
116262306a36Sopenharmony_ci		thistime = (len / info->ssize) & 0xff;
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci		/* ATA command 0x20 (READ SECTORS) */
116562306a36Sopenharmony_ci		usbat_pack_ata_sector_cmd(command, thistime, sector, 0x20);
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci		/* Write/execute ATA read command */
116862306a36Sopenharmony_ci		result = usbat_multiple_write(us, registers, command, 7);
116962306a36Sopenharmony_ci		if (result != USB_STOR_TRANSPORT_GOOD)
117062306a36Sopenharmony_ci			goto leave;
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci		/* Read the data we just requested */
117362306a36Sopenharmony_ci		result = usbat_read_blocks(us, buffer, len, 0);
117462306a36Sopenharmony_ci		if (result != USB_STOR_TRANSPORT_GOOD)
117562306a36Sopenharmony_ci			goto leave;
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci		usb_stor_dbg(us, "%d bytes\n", len);
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci		/* Store the data in the transfer buffer */
118062306a36Sopenharmony_ci		usb_stor_access_xfer_buf(buffer, len, us->srb,
118162306a36Sopenharmony_ci					 &sg, &sg_offset, TO_XFER_BUF);
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci		sector += thistime;
118462306a36Sopenharmony_ci		totallen -= len;
118562306a36Sopenharmony_ci	} while (totallen > 0);
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	kfree(buffer);
118862306a36Sopenharmony_ci	return USB_STOR_TRANSPORT_GOOD;
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_cileave:
119162306a36Sopenharmony_ci	kfree(buffer);
119262306a36Sopenharmony_ci	return USB_STOR_TRANSPORT_ERROR;
119362306a36Sopenharmony_ci}
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci/*
119662306a36Sopenharmony_ci * Write data to device
119762306a36Sopenharmony_ci */
119862306a36Sopenharmony_cistatic int usbat_flash_write_data(struct us_data *us,
119962306a36Sopenharmony_ci								  struct usbat_info *info,
120062306a36Sopenharmony_ci								  u32 sector,
120162306a36Sopenharmony_ci								  u32 sectors)
120262306a36Sopenharmony_ci{
120362306a36Sopenharmony_ci	unsigned char registers[7] = {
120462306a36Sopenharmony_ci		USBAT_ATA_FEATURES,
120562306a36Sopenharmony_ci		USBAT_ATA_SECCNT,
120662306a36Sopenharmony_ci		USBAT_ATA_SECNUM,
120762306a36Sopenharmony_ci		USBAT_ATA_LBA_ME,
120862306a36Sopenharmony_ci		USBAT_ATA_LBA_HI,
120962306a36Sopenharmony_ci		USBAT_ATA_DEVICE,
121062306a36Sopenharmony_ci		USBAT_ATA_STATUS,
121162306a36Sopenharmony_ci	};
121262306a36Sopenharmony_ci	unsigned char command[7];
121362306a36Sopenharmony_ci	unsigned char *buffer;
121462306a36Sopenharmony_ci	unsigned char  thistime;
121562306a36Sopenharmony_ci	unsigned int totallen, alloclen;
121662306a36Sopenharmony_ci	int len, result;
121762306a36Sopenharmony_ci	unsigned int sg_offset = 0;
121862306a36Sopenharmony_ci	struct scatterlist *sg = NULL;
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	result = usbat_flash_check_media(us, info);
122162306a36Sopenharmony_ci	if (result != USB_STOR_TRANSPORT_GOOD)
122262306a36Sopenharmony_ci		return result;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	/*
122562306a36Sopenharmony_ci	 * we're working in LBA mode.  according to the ATA spec,
122662306a36Sopenharmony_ci	 * we can support up to 28-bit addressing.  I don't know if the device
122762306a36Sopenharmony_ci	 * supports beyond 24-bit addressing.  It's kind of hard to test
122862306a36Sopenharmony_ci	 * since it requires > 8GB media.
122962306a36Sopenharmony_ci	 */
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	if (sector > 0x0FFFFFFF)
123262306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	totallen = sectors * info->ssize;
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci	/*
123762306a36Sopenharmony_ci	 * Since we don't write more than 64 KB at a time, we have to create
123862306a36Sopenharmony_ci	 * a bounce buffer and move the data a piece at a time between the
123962306a36Sopenharmony_ci	 * bounce buffer and the actual transfer buffer.
124062306a36Sopenharmony_ci	 */
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	alloclen = min(totallen, 65536u);
124362306a36Sopenharmony_ci	buffer = kmalloc(alloclen, GFP_NOIO);
124462306a36Sopenharmony_ci	if (buffer == NULL)
124562306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	do {
124862306a36Sopenharmony_ci		/*
124962306a36Sopenharmony_ci		 * loop, never allocate or transfer more than 64k at once
125062306a36Sopenharmony_ci		 * (min(128k, 255*info->ssize) is the real limit)
125162306a36Sopenharmony_ci		 */
125262306a36Sopenharmony_ci		len = min(totallen, alloclen);
125362306a36Sopenharmony_ci		thistime = (len / info->ssize) & 0xff;
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci		/* Get the data from the transfer buffer */
125662306a36Sopenharmony_ci		usb_stor_access_xfer_buf(buffer, len, us->srb,
125762306a36Sopenharmony_ci					 &sg, &sg_offset, FROM_XFER_BUF);
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci		/* ATA command 0x30 (WRITE SECTORS) */
126062306a36Sopenharmony_ci		usbat_pack_ata_sector_cmd(command, thistime, sector, 0x30);
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci		/* Write/execute ATA write command */
126362306a36Sopenharmony_ci		result = usbat_multiple_write(us, registers, command, 7);
126462306a36Sopenharmony_ci		if (result != USB_STOR_TRANSPORT_GOOD)
126562306a36Sopenharmony_ci			goto leave;
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci		/* Write the data */
126862306a36Sopenharmony_ci		result = usbat_write_blocks(us, buffer, len, 0);
126962306a36Sopenharmony_ci		if (result != USB_STOR_TRANSPORT_GOOD)
127062306a36Sopenharmony_ci			goto leave;
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci		sector += thistime;
127362306a36Sopenharmony_ci		totallen -= len;
127462306a36Sopenharmony_ci	} while (totallen > 0);
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	kfree(buffer);
127762306a36Sopenharmony_ci	return result;
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_cileave:
128062306a36Sopenharmony_ci	kfree(buffer);
128162306a36Sopenharmony_ci	return USB_STOR_TRANSPORT_ERROR;
128262306a36Sopenharmony_ci}
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci/*
128562306a36Sopenharmony_ci * Squeeze a potentially huge (> 65535 byte) read10 command into
128662306a36Sopenharmony_ci * a little ( <= 65535 byte) ATAPI pipe
128762306a36Sopenharmony_ci */
128862306a36Sopenharmony_cistatic int usbat_hp8200e_handle_read10(struct us_data *us,
128962306a36Sopenharmony_ci				       unsigned char *registers,
129062306a36Sopenharmony_ci				       unsigned char *data,
129162306a36Sopenharmony_ci				       struct scsi_cmnd *srb)
129262306a36Sopenharmony_ci{
129362306a36Sopenharmony_ci	int result = USB_STOR_TRANSPORT_GOOD;
129462306a36Sopenharmony_ci	unsigned char *buffer;
129562306a36Sopenharmony_ci	unsigned int len;
129662306a36Sopenharmony_ci	unsigned int sector;
129762306a36Sopenharmony_ci	unsigned int sg_offset = 0;
129862306a36Sopenharmony_ci	struct scatterlist *sg = NULL;
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	usb_stor_dbg(us, "transfersize %d\n", srb->transfersize);
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	if (scsi_bufflen(srb) < 0x10000) {
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci		result = usbat_hp8200e_rw_block_test(us, USBAT_ATA,
130562306a36Sopenharmony_ci			registers, data, 19,
130662306a36Sopenharmony_ci			USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD,
130762306a36Sopenharmony_ci			(USBAT_QUAL_FCQ | USBAT_QUAL_ALQ),
130862306a36Sopenharmony_ci			DMA_FROM_DEVICE,
130962306a36Sopenharmony_ci			scsi_sglist(srb),
131062306a36Sopenharmony_ci			scsi_bufflen(srb), scsi_sg_count(srb), 1);
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci		return result;
131362306a36Sopenharmony_ci	}
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	/*
131662306a36Sopenharmony_ci	 * Since we're requesting more data than we can handle in
131762306a36Sopenharmony_ci	 * a single read command (max is 64k-1), we will perform
131862306a36Sopenharmony_ci	 * multiple reads, but each read must be in multiples of
131962306a36Sopenharmony_ci	 * a sector.  Luckily the sector size is in srb->transfersize
132062306a36Sopenharmony_ci	 * (see linux/drivers/scsi/sr.c).
132162306a36Sopenharmony_ci	 */
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	if (data[7+0] == GPCMD_READ_CD) {
132462306a36Sopenharmony_ci		len = short_pack(data[7+9], data[7+8]);
132562306a36Sopenharmony_ci		len <<= 16;
132662306a36Sopenharmony_ci		len |= data[7+7];
132762306a36Sopenharmony_ci		usb_stor_dbg(us, "GPCMD_READ_CD: len %d\n", len);
132862306a36Sopenharmony_ci		srb->transfersize = scsi_bufflen(srb)/len;
132962306a36Sopenharmony_ci	}
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	if (!srb->transfersize)  {
133262306a36Sopenharmony_ci		srb->transfersize = 2048; /* A guess */
133362306a36Sopenharmony_ci		usb_stor_dbg(us, "transfersize 0, forcing %d\n",
133462306a36Sopenharmony_ci			     srb->transfersize);
133562306a36Sopenharmony_ci	}
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	/*
133862306a36Sopenharmony_ci	 * Since we only read in one block at a time, we have to create
133962306a36Sopenharmony_ci	 * a bounce buffer and move the data a piece at a time between the
134062306a36Sopenharmony_ci	 * bounce buffer and the actual transfer buffer.
134162306a36Sopenharmony_ci	 */
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	len = (65535/srb->transfersize) * srb->transfersize;
134462306a36Sopenharmony_ci	usb_stor_dbg(us, "Max read is %d bytes\n", len);
134562306a36Sopenharmony_ci	len = min(len, scsi_bufflen(srb));
134662306a36Sopenharmony_ci	buffer = kmalloc(len, GFP_NOIO);
134762306a36Sopenharmony_ci	if (buffer == NULL) /* bloody hell! */
134862306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_FAILED;
134962306a36Sopenharmony_ci	sector = short_pack(data[7+3], data[7+2]);
135062306a36Sopenharmony_ci	sector <<= 16;
135162306a36Sopenharmony_ci	sector |= short_pack(data[7+5], data[7+4]);
135262306a36Sopenharmony_ci	transferred = 0;
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	while (transferred != scsi_bufflen(srb)) {
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci		if (len > scsi_bufflen(srb) - transferred)
135762306a36Sopenharmony_ci			len = scsi_bufflen(srb) - transferred;
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci		data[3] = len&0xFF; 	  /* (cylL) = expected length (L) */
136062306a36Sopenharmony_ci		data[4] = (len>>8)&0xFF;  /* (cylH) = expected length (H) */
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci		/* Fix up the SCSI command sector and num sectors */
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci		data[7+2] = MSB_of(sector>>16); /* SCSI command sector */
136562306a36Sopenharmony_ci		data[7+3] = LSB_of(sector>>16);
136662306a36Sopenharmony_ci		data[7+4] = MSB_of(sector&0xFFFF);
136762306a36Sopenharmony_ci		data[7+5] = LSB_of(sector&0xFFFF);
136862306a36Sopenharmony_ci		if (data[7+0] == GPCMD_READ_CD)
136962306a36Sopenharmony_ci			data[7+6] = 0;
137062306a36Sopenharmony_ci		data[7+7] = MSB_of(len / srb->transfersize); /* SCSI command */
137162306a36Sopenharmony_ci		data[7+8] = LSB_of(len / srb->transfersize); /* num sectors */
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci		result = usbat_hp8200e_rw_block_test(us, USBAT_ATA,
137462306a36Sopenharmony_ci			registers, data, 19,
137562306a36Sopenharmony_ci			USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD,
137662306a36Sopenharmony_ci			(USBAT_QUAL_FCQ | USBAT_QUAL_ALQ),
137762306a36Sopenharmony_ci			DMA_FROM_DEVICE,
137862306a36Sopenharmony_ci			buffer,
137962306a36Sopenharmony_ci			len, 0, 1);
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci		if (result != USB_STOR_TRANSPORT_GOOD)
138262306a36Sopenharmony_ci			break;
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci		/* Store the data in the transfer buffer */
138562306a36Sopenharmony_ci		usb_stor_access_xfer_buf(buffer, len, srb,
138662306a36Sopenharmony_ci				 &sg, &sg_offset, TO_XFER_BUF);
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci		/* Update the amount transferred and the sector number */
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci		transferred += len;
139162306a36Sopenharmony_ci		sector += len / srb->transfersize;
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	} /* while transferred != scsi_bufflen(srb) */
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	kfree(buffer);
139662306a36Sopenharmony_ci	return result;
139762306a36Sopenharmony_ci}
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_cistatic int usbat_select_and_test_registers(struct us_data *us)
140062306a36Sopenharmony_ci{
140162306a36Sopenharmony_ci	int selector;
140262306a36Sopenharmony_ci	unsigned char *status = us->iobuf;
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	/* try device = master, then device = slave. */
140562306a36Sopenharmony_ci	for (selector = 0xA0; selector <= 0xB0; selector += 0x10) {
140662306a36Sopenharmony_ci		if (usbat_write(us, USBAT_ATA, USBAT_ATA_DEVICE, selector) !=
140762306a36Sopenharmony_ci				USB_STOR_XFER_GOOD)
140862306a36Sopenharmony_ci			return USB_STOR_TRANSPORT_ERROR;
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ci		if (usbat_read(us, USBAT_ATA, USBAT_ATA_STATUS, status) !=
141162306a36Sopenharmony_ci				USB_STOR_XFER_GOOD)
141262306a36Sopenharmony_ci			return USB_STOR_TRANSPORT_ERROR;
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci		if (usbat_read(us, USBAT_ATA, USBAT_ATA_DEVICE, status) !=
141562306a36Sopenharmony_ci				USB_STOR_XFER_GOOD)
141662306a36Sopenharmony_ci			return USB_STOR_TRANSPORT_ERROR;
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci		if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) !=
141962306a36Sopenharmony_ci				USB_STOR_XFER_GOOD)
142062306a36Sopenharmony_ci			return USB_STOR_TRANSPORT_ERROR;
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci		if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_HI, status) !=
142362306a36Sopenharmony_ci				USB_STOR_XFER_GOOD)
142462306a36Sopenharmony_ci			return USB_STOR_TRANSPORT_ERROR;
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci		if (usbat_write(us, USBAT_ATA, USBAT_ATA_LBA_ME, 0x55) !=
142762306a36Sopenharmony_ci				USB_STOR_XFER_GOOD)
142862306a36Sopenharmony_ci			return USB_STOR_TRANSPORT_ERROR;
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci		if (usbat_write(us, USBAT_ATA, USBAT_ATA_LBA_HI, 0xAA) !=
143162306a36Sopenharmony_ci				USB_STOR_XFER_GOOD)
143262306a36Sopenharmony_ci			return USB_STOR_TRANSPORT_ERROR;
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci		if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) !=
143562306a36Sopenharmony_ci				USB_STOR_XFER_GOOD)
143662306a36Sopenharmony_ci			return USB_STOR_TRANSPORT_ERROR;
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci		if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) !=
143962306a36Sopenharmony_ci				USB_STOR_XFER_GOOD)
144062306a36Sopenharmony_ci			return USB_STOR_TRANSPORT_ERROR;
144162306a36Sopenharmony_ci	}
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci	return USB_STOR_TRANSPORT_GOOD;
144462306a36Sopenharmony_ci}
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci/*
144762306a36Sopenharmony_ci * Initialize the USBAT processor and the storage device
144862306a36Sopenharmony_ci */
144962306a36Sopenharmony_cistatic int init_usbat(struct us_data *us, int devicetype)
145062306a36Sopenharmony_ci{
145162306a36Sopenharmony_ci	int rc;
145262306a36Sopenharmony_ci	struct usbat_info *info;
145362306a36Sopenharmony_ci	unsigned char subcountH = USBAT_ATA_LBA_HI;
145462306a36Sopenharmony_ci	unsigned char subcountL = USBAT_ATA_LBA_ME;
145562306a36Sopenharmony_ci	unsigned char *status = us->iobuf;
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	us->extra = kzalloc(sizeof(struct usbat_info), GFP_NOIO);
145862306a36Sopenharmony_ci	if (!us->extra)
145962306a36Sopenharmony_ci		return -ENOMEM;
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci	info = (struct usbat_info *) (us->extra);
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	/* Enable peripheral control signals */
146462306a36Sopenharmony_ci	rc = usbat_write_user_io(us,
146562306a36Sopenharmony_ci				 USBAT_UIO_OE1 | USBAT_UIO_OE0,
146662306a36Sopenharmony_ci				 USBAT_UIO_EPAD | USBAT_UIO_1);
146762306a36Sopenharmony_ci	if (rc != USB_STOR_XFER_GOOD)
146862306a36Sopenharmony_ci		return -EIO;
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci	usb_stor_dbg(us, "INIT 1\n");
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	msleep(2000);
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci	rc = usbat_read_user_io(us, status);
147562306a36Sopenharmony_ci	if (rc != USB_STOR_TRANSPORT_GOOD)
147662306a36Sopenharmony_ci		return -EIO;
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci	usb_stor_dbg(us, "INIT 2\n");
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	rc = usbat_read_user_io(us, status);
148162306a36Sopenharmony_ci	if (rc != USB_STOR_XFER_GOOD)
148262306a36Sopenharmony_ci		return -EIO;
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci	rc = usbat_read_user_io(us, status);
148562306a36Sopenharmony_ci	if (rc != USB_STOR_XFER_GOOD)
148662306a36Sopenharmony_ci		return -EIO;
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	usb_stor_dbg(us, "INIT 3\n");
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	rc = usbat_select_and_test_registers(us);
149162306a36Sopenharmony_ci	if (rc != USB_STOR_TRANSPORT_GOOD)
149262306a36Sopenharmony_ci		return -EIO;
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	usb_stor_dbg(us, "INIT 4\n");
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci	rc = usbat_read_user_io(us, status);
149762306a36Sopenharmony_ci	if (rc != USB_STOR_XFER_GOOD)
149862306a36Sopenharmony_ci		return -EIO;
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	usb_stor_dbg(us, "INIT 5\n");
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci	/* Enable peripheral control signals and card detect */
150362306a36Sopenharmony_ci	rc = usbat_device_enable_cdt(us);
150462306a36Sopenharmony_ci	if (rc != USB_STOR_TRANSPORT_GOOD)
150562306a36Sopenharmony_ci		return -EIO;
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci	usb_stor_dbg(us, "INIT 6\n");
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci	rc = usbat_read_user_io(us, status);
151062306a36Sopenharmony_ci	if (rc != USB_STOR_XFER_GOOD)
151162306a36Sopenharmony_ci		return -EIO;
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	usb_stor_dbg(us, "INIT 7\n");
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci	msleep(1400);
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	rc = usbat_read_user_io(us, status);
151862306a36Sopenharmony_ci	if (rc != USB_STOR_XFER_GOOD)
151962306a36Sopenharmony_ci		return -EIO;
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	usb_stor_dbg(us, "INIT 8\n");
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	rc = usbat_select_and_test_registers(us);
152462306a36Sopenharmony_ci	if (rc != USB_STOR_TRANSPORT_GOOD)
152562306a36Sopenharmony_ci		return -EIO;
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci	usb_stor_dbg(us, "INIT 9\n");
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	/* At this point, we need to detect which device we are using */
153062306a36Sopenharmony_ci	if (usbat_set_transport(us, info, devicetype))
153162306a36Sopenharmony_ci		return -EIO;
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	usb_stor_dbg(us, "INIT 10\n");
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci	if (usbat_get_device_type(us) == USBAT_DEV_FLASH) {
153662306a36Sopenharmony_ci		subcountH = 0x02;
153762306a36Sopenharmony_ci		subcountL = 0x00;
153862306a36Sopenharmony_ci	}
153962306a36Sopenharmony_ci	rc = usbat_set_shuttle_features(us, (USBAT_FEAT_ETEN | USBAT_FEAT_ET2 | USBAT_FEAT_ET1),
154062306a36Sopenharmony_ci									0x00, 0x88, 0x08, subcountH, subcountL);
154162306a36Sopenharmony_ci	if (rc != USB_STOR_XFER_GOOD)
154262306a36Sopenharmony_ci		return -EIO;
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci	usb_stor_dbg(us, "INIT 11\n");
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	return 0;
154762306a36Sopenharmony_ci}
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci/*
155062306a36Sopenharmony_ci * Transport for the HP 8200e
155162306a36Sopenharmony_ci */
155262306a36Sopenharmony_cistatic int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
155362306a36Sopenharmony_ci{
155462306a36Sopenharmony_ci	int result;
155562306a36Sopenharmony_ci	unsigned char *status = us->iobuf;
155662306a36Sopenharmony_ci	unsigned char registers[32];
155762306a36Sopenharmony_ci	unsigned char data[32];
155862306a36Sopenharmony_ci	unsigned int len;
155962306a36Sopenharmony_ci	int i;
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci	len = scsi_bufflen(srb);
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci	/*
156462306a36Sopenharmony_ci	 * Send A0 (ATA PACKET COMMAND).
156562306a36Sopenharmony_ci	 * Note: I guess we're never going to get any of the ATA
156662306a36Sopenharmony_ci	 * commands... just ATA Packet Commands.
156762306a36Sopenharmony_ci 	 */
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci	registers[0] = USBAT_ATA_FEATURES;
157062306a36Sopenharmony_ci	registers[1] = USBAT_ATA_SECCNT;
157162306a36Sopenharmony_ci	registers[2] = USBAT_ATA_SECNUM;
157262306a36Sopenharmony_ci	registers[3] = USBAT_ATA_LBA_ME;
157362306a36Sopenharmony_ci	registers[4] = USBAT_ATA_LBA_HI;
157462306a36Sopenharmony_ci	registers[5] = USBAT_ATA_DEVICE;
157562306a36Sopenharmony_ci	registers[6] = USBAT_ATA_CMD;
157662306a36Sopenharmony_ci	data[0] = 0x00;
157762306a36Sopenharmony_ci	data[1] = 0x00;
157862306a36Sopenharmony_ci	data[2] = 0x00;
157962306a36Sopenharmony_ci	data[3] = len&0xFF; 		/* (cylL) = expected length (L) */
158062306a36Sopenharmony_ci	data[4] = (len>>8)&0xFF; 	/* (cylH) = expected length (H) */
158162306a36Sopenharmony_ci	data[5] = 0xB0; 		/* (device sel) = slave */
158262306a36Sopenharmony_ci	data[6] = 0xA0; 		/* (command) = ATA PACKET COMMAND */
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	for (i=7; i<19; i++) {
158562306a36Sopenharmony_ci		registers[i] = 0x10;
158662306a36Sopenharmony_ci		data[i] = (i-7 >= srb->cmd_len) ? 0 : srb->cmnd[i-7];
158762306a36Sopenharmony_ci	}
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	result = usbat_get_status(us, status);
159062306a36Sopenharmony_ci	usb_stor_dbg(us, "Status = %02X\n", *status);
159162306a36Sopenharmony_ci	if (result != USB_STOR_XFER_GOOD)
159262306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
159362306a36Sopenharmony_ci	if (srb->cmnd[0] == TEST_UNIT_READY)
159462306a36Sopenharmony_ci		transferred = 0;
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	if (srb->sc_data_direction == DMA_TO_DEVICE) {
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci		result = usbat_hp8200e_rw_block_test(us, USBAT_ATA,
159962306a36Sopenharmony_ci			registers, data, 19,
160062306a36Sopenharmony_ci			USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD,
160162306a36Sopenharmony_ci			(USBAT_QUAL_FCQ | USBAT_QUAL_ALQ),
160262306a36Sopenharmony_ci			DMA_TO_DEVICE,
160362306a36Sopenharmony_ci			scsi_sglist(srb),
160462306a36Sopenharmony_ci			len, scsi_sg_count(srb), 10);
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ci		if (result == USB_STOR_TRANSPORT_GOOD) {
160762306a36Sopenharmony_ci			transferred += len;
160862306a36Sopenharmony_ci			usb_stor_dbg(us, "Wrote %08X bytes\n", transferred);
160962306a36Sopenharmony_ci		}
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci		return result;
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci	} else if (srb->cmnd[0] == READ_10 ||
161462306a36Sopenharmony_ci		   srb->cmnd[0] == GPCMD_READ_CD) {
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci		return usbat_hp8200e_handle_read10(us, registers, data, srb);
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci	}
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	if (len > 0xFFFF) {
162162306a36Sopenharmony_ci		usb_stor_dbg(us, "Error: len = %08X... what do I do now?\n",
162262306a36Sopenharmony_ci			     len);
162362306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
162462306a36Sopenharmony_ci	}
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_ci	result = usbat_multiple_write(us, registers, data, 7);
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	if (result != USB_STOR_TRANSPORT_GOOD)
162962306a36Sopenharmony_ci		return result;
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci	/*
163262306a36Sopenharmony_ci	 * Write the 12-byte command header.
163362306a36Sopenharmony_ci	 *
163462306a36Sopenharmony_ci	 * If the command is BLANK then set the timer for 75 minutes.
163562306a36Sopenharmony_ci	 * Otherwise set it for 10 minutes.
163662306a36Sopenharmony_ci	 *
163762306a36Sopenharmony_ci	 * NOTE: THE 8200 DOCUMENTATION STATES THAT BLANKING A CDRW
163862306a36Sopenharmony_ci	 * AT SPEED 4 IS UNRELIABLE!!!
163962306a36Sopenharmony_ci	 */
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_ci	result = usbat_write_block(us, USBAT_ATA, srb->cmnd, 12,
164262306a36Sopenharmony_ci				   srb->cmnd[0] == GPCMD_BLANK ? 75 : 10, 0);
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci	if (result != USB_STOR_TRANSPORT_GOOD)
164562306a36Sopenharmony_ci		return result;
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci	/* If there is response data to be read in then do it here. */
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci	if (len != 0 && (srb->sc_data_direction == DMA_FROM_DEVICE)) {
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ci		/* How many bytes to read in? Check cylL register */
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci		if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) !=
165462306a36Sopenharmony_ci		    	USB_STOR_XFER_GOOD) {
165562306a36Sopenharmony_ci			return USB_STOR_TRANSPORT_ERROR;
165662306a36Sopenharmony_ci		}
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci		if (len > 0xFF) { /* need to read cylH also */
165962306a36Sopenharmony_ci			len = *status;
166062306a36Sopenharmony_ci			if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_HI, status) !=
166162306a36Sopenharmony_ci				    USB_STOR_XFER_GOOD) {
166262306a36Sopenharmony_ci				return USB_STOR_TRANSPORT_ERROR;
166362306a36Sopenharmony_ci			}
166462306a36Sopenharmony_ci			len += ((unsigned int) *status)<<8;
166562306a36Sopenharmony_ci		}
166662306a36Sopenharmony_ci		else
166762306a36Sopenharmony_ci			len = *status;
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci		result = usbat_read_block(us, scsi_sglist(srb), len,
167162306a36Sopenharmony_ci			                                   scsi_sg_count(srb));
167262306a36Sopenharmony_ci	}
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci	return result;
167562306a36Sopenharmony_ci}
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci/*
167862306a36Sopenharmony_ci * Transport for USBAT02-based CompactFlash and similar storage devices
167962306a36Sopenharmony_ci */
168062306a36Sopenharmony_cistatic int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us)
168162306a36Sopenharmony_ci{
168262306a36Sopenharmony_ci	int rc;
168362306a36Sopenharmony_ci	struct usbat_info *info = (struct usbat_info *) (us->extra);
168462306a36Sopenharmony_ci	unsigned long block, blocks;
168562306a36Sopenharmony_ci	unsigned char *ptr = us->iobuf;
168662306a36Sopenharmony_ci	static unsigned char inquiry_response[36] = {
168762306a36Sopenharmony_ci		0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00
168862306a36Sopenharmony_ci	};
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	if (srb->cmnd[0] == INQUIRY) {
169162306a36Sopenharmony_ci		usb_stor_dbg(us, "INQUIRY - Returning bogus response\n");
169262306a36Sopenharmony_ci		memcpy(ptr, inquiry_response, sizeof(inquiry_response));
169362306a36Sopenharmony_ci		fill_inquiry_response(us, ptr, 36);
169462306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_GOOD;
169562306a36Sopenharmony_ci	}
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ci	if (srb->cmnd[0] == READ_CAPACITY) {
169862306a36Sopenharmony_ci		rc = usbat_flash_check_media(us, info);
169962306a36Sopenharmony_ci		if (rc != USB_STOR_TRANSPORT_GOOD)
170062306a36Sopenharmony_ci			return rc;
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci		rc = usbat_flash_get_sector_count(us, info);
170362306a36Sopenharmony_ci		if (rc != USB_STOR_TRANSPORT_GOOD)
170462306a36Sopenharmony_ci			return rc;
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci		/* hard coded 512 byte sectors as per ATA spec */
170762306a36Sopenharmony_ci		info->ssize = 0x200;
170862306a36Sopenharmony_ci		usb_stor_dbg(us, "READ_CAPACITY: %ld sectors, %ld bytes per sector\n",
170962306a36Sopenharmony_ci			     info->sectors, info->ssize);
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_ci		/*
171262306a36Sopenharmony_ci		 * build the reply
171362306a36Sopenharmony_ci		 * note: must return the sector number of the last sector,
171462306a36Sopenharmony_ci		 * *not* the total number of sectors
171562306a36Sopenharmony_ci		 */
171662306a36Sopenharmony_ci		((__be32 *) ptr)[0] = cpu_to_be32(info->sectors - 1);
171762306a36Sopenharmony_ci		((__be32 *) ptr)[1] = cpu_to_be32(info->ssize);
171862306a36Sopenharmony_ci		usb_stor_set_xfer_buf(ptr, 8, srb);
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_GOOD;
172162306a36Sopenharmony_ci	}
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	if (srb->cmnd[0] == MODE_SELECT_10) {
172462306a36Sopenharmony_ci		usb_stor_dbg(us, "Gah! MODE_SELECT_10\n");
172562306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_ERROR;
172662306a36Sopenharmony_ci	}
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci	if (srb->cmnd[0] == READ_10) {
172962306a36Sopenharmony_ci		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
173062306a36Sopenharmony_ci				((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci		blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ci		usb_stor_dbg(us, "READ_10: read block 0x%04lx  count %ld\n",
173562306a36Sopenharmony_ci			     block, blocks);
173662306a36Sopenharmony_ci		return usbat_flash_read_data(us, info, block, blocks);
173762306a36Sopenharmony_ci	}
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci	if (srb->cmnd[0] == READ_12) {
174062306a36Sopenharmony_ci		/*
174162306a36Sopenharmony_ci		 * I don't think we'll ever see a READ_12 but support it anyway
174262306a36Sopenharmony_ci		 */
174362306a36Sopenharmony_ci		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
174462306a36Sopenharmony_ci		        ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci		blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
174762306a36Sopenharmony_ci		         ((u32)(srb->cmnd[8]) <<  8) | ((u32)(srb->cmnd[9]));
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_ci		usb_stor_dbg(us, "READ_12: read block 0x%04lx  count %ld\n",
175062306a36Sopenharmony_ci			     block, blocks);
175162306a36Sopenharmony_ci		return usbat_flash_read_data(us, info, block, blocks);
175262306a36Sopenharmony_ci	}
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci	if (srb->cmnd[0] == WRITE_10) {
175562306a36Sopenharmony_ci		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
175662306a36Sopenharmony_ci		        ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_ci		blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci		usb_stor_dbg(us, "WRITE_10: write block 0x%04lx  count %ld\n",
176162306a36Sopenharmony_ci			     block, blocks);
176262306a36Sopenharmony_ci		return usbat_flash_write_data(us, info, block, blocks);
176362306a36Sopenharmony_ci	}
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci	if (srb->cmnd[0] == WRITE_12) {
176662306a36Sopenharmony_ci		/*
176762306a36Sopenharmony_ci		 * I don't think we'll ever see a WRITE_12 but support it anyway
176862306a36Sopenharmony_ci		 */
176962306a36Sopenharmony_ci		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
177062306a36Sopenharmony_ci		        ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci		blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
177362306a36Sopenharmony_ci		         ((u32)(srb->cmnd[8]) <<  8) | ((u32)(srb->cmnd[9]));
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ci		usb_stor_dbg(us, "WRITE_12: write block 0x%04lx  count %ld\n",
177662306a36Sopenharmony_ci			     block, blocks);
177762306a36Sopenharmony_ci		return usbat_flash_write_data(us, info, block, blocks);
177862306a36Sopenharmony_ci	}
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_ci	if (srb->cmnd[0] == TEST_UNIT_READY) {
178262306a36Sopenharmony_ci		usb_stor_dbg(us, "TEST_UNIT_READY\n");
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci		rc = usbat_flash_check_media(us, info);
178562306a36Sopenharmony_ci		if (rc != USB_STOR_TRANSPORT_GOOD)
178662306a36Sopenharmony_ci			return rc;
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci		return usbat_check_status(us);
178962306a36Sopenharmony_ci	}
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_ci	if (srb->cmnd[0] == REQUEST_SENSE) {
179262306a36Sopenharmony_ci		usb_stor_dbg(us, "REQUEST_SENSE\n");
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci		memset(ptr, 0, 18);
179562306a36Sopenharmony_ci		ptr[0] = 0xF0;
179662306a36Sopenharmony_ci		ptr[2] = info->sense_key;
179762306a36Sopenharmony_ci		ptr[7] = 11;
179862306a36Sopenharmony_ci		ptr[12] = info->sense_asc;
179962306a36Sopenharmony_ci		ptr[13] = info->sense_ascq;
180062306a36Sopenharmony_ci		usb_stor_set_xfer_buf(ptr, 18, srb);
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_GOOD;
180362306a36Sopenharmony_ci	}
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci	if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
180662306a36Sopenharmony_ci		/*
180762306a36Sopenharmony_ci		 * sure.  whatever.  not like we can stop the user from popping
180862306a36Sopenharmony_ci		 * the media out of the device (no locking doors, etc)
180962306a36Sopenharmony_ci		 */
181062306a36Sopenharmony_ci		return USB_STOR_TRANSPORT_GOOD;
181162306a36Sopenharmony_ci	}
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci	usb_stor_dbg(us, "Gah! Unknown command: %d (0x%x)\n",
181462306a36Sopenharmony_ci		     srb->cmnd[0], srb->cmnd[0]);
181562306a36Sopenharmony_ci	info->sense_key = 0x05;
181662306a36Sopenharmony_ci	info->sense_asc = 0x20;
181762306a36Sopenharmony_ci	info->sense_ascq = 0x00;
181862306a36Sopenharmony_ci	return USB_STOR_TRANSPORT_FAILED;
181962306a36Sopenharmony_ci}
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_cistatic int init_usbat_cd(struct us_data *us)
182262306a36Sopenharmony_ci{
182362306a36Sopenharmony_ci	return init_usbat(us, USBAT_DEV_HP8200);
182462306a36Sopenharmony_ci}
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_cistatic int init_usbat_flash(struct us_data *us)
182762306a36Sopenharmony_ci{
182862306a36Sopenharmony_ci	return init_usbat(us, USBAT_DEV_FLASH);
182962306a36Sopenharmony_ci}
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_cistatic struct scsi_host_template usbat_host_template;
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_cistatic int usbat_probe(struct usb_interface *intf,
183462306a36Sopenharmony_ci			 const struct usb_device_id *id)
183562306a36Sopenharmony_ci{
183662306a36Sopenharmony_ci	struct us_data *us;
183762306a36Sopenharmony_ci	int result;
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_ci	result = usb_stor_probe1(&us, intf, id,
184062306a36Sopenharmony_ci			(id - usbat_usb_ids) + usbat_unusual_dev_list,
184162306a36Sopenharmony_ci			&usbat_host_template);
184262306a36Sopenharmony_ci	if (result)
184362306a36Sopenharmony_ci		return result;
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci	/*
184662306a36Sopenharmony_ci	 * The actual transport will be determined later by the
184762306a36Sopenharmony_ci	 * initialization routine; this is just a placeholder.
184862306a36Sopenharmony_ci	 */
184962306a36Sopenharmony_ci	us->transport_name = "Shuttle USBAT";
185062306a36Sopenharmony_ci	us->transport = usbat_flash_transport;
185162306a36Sopenharmony_ci	us->transport_reset = usb_stor_CB_reset;
185262306a36Sopenharmony_ci	us->max_lun = 0;
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci	result = usb_stor_probe2(us);
185562306a36Sopenharmony_ci	return result;
185662306a36Sopenharmony_ci}
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_cistatic struct usb_driver usbat_driver = {
185962306a36Sopenharmony_ci	.name =		DRV_NAME,
186062306a36Sopenharmony_ci	.probe =	usbat_probe,
186162306a36Sopenharmony_ci	.disconnect =	usb_stor_disconnect,
186262306a36Sopenharmony_ci	.suspend =	usb_stor_suspend,
186362306a36Sopenharmony_ci	.resume =	usb_stor_resume,
186462306a36Sopenharmony_ci	.reset_resume =	usb_stor_reset_resume,
186562306a36Sopenharmony_ci	.pre_reset =	usb_stor_pre_reset,
186662306a36Sopenharmony_ci	.post_reset =	usb_stor_post_reset,
186762306a36Sopenharmony_ci	.id_table =	usbat_usb_ids,
186862306a36Sopenharmony_ci	.soft_unbind =	1,
186962306a36Sopenharmony_ci	.no_dynamic_id = 1,
187062306a36Sopenharmony_ci};
187162306a36Sopenharmony_ci
187262306a36Sopenharmony_cimodule_usb_stor_driver(usbat_driver, usbat_host_template, DRV_NAME);
1873