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