18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for SCM Microsystems (a.k.a. Shuttle) USB-ATAPI cable 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Current development and maintenance by: 68c2ecf20Sopenharmony_ci * (c) 2000, 2001 Robert Baruch (autophile@starband.net) 78c2ecf20Sopenharmony_ci * (c) 2004, 2005 Daniel Drake <dsd@gentoo.org> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Developed with the assistance of: 108c2ecf20Sopenharmony_ci * (c) 2002 Alan Stern <stern@rowland.org> 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Flash support based on earlier work by: 138c2ecf20Sopenharmony_ci * (c) 2002 Thomas Kreiling <usbdev@sm04.de> 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Many originally ATAPI devices were slightly modified to meet the USB 168c2ecf20Sopenharmony_ci * market by using some kind of translation from ATAPI to USB on the host, 178c2ecf20Sopenharmony_ci * and the peripheral would translate from USB back to ATAPI. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * SCM Microsystems (www.scmmicro.com) makes a device, sold to OEM's only, 208c2ecf20Sopenharmony_ci * which does the USB-to-ATAPI conversion. By obtaining the data sheet on 218c2ecf20Sopenharmony_ci * their device under nondisclosure agreement, I have been able to write 228c2ecf20Sopenharmony_ci * this driver for Linux. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * The chip used in the device can also be used for EPP and ISA translation 258c2ecf20Sopenharmony_ci * as well. This driver is only guaranteed to work with the ATAPI 268c2ecf20Sopenharmony_ci * translation. 278c2ecf20Sopenharmony_ci * 288c2ecf20Sopenharmony_ci * See the Kconfig help text for a list of devices known to be supported by 298c2ecf20Sopenharmony_ci * this driver. 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include <linux/errno.h> 338c2ecf20Sopenharmony_ci#include <linux/module.h> 348c2ecf20Sopenharmony_ci#include <linux/slab.h> 358c2ecf20Sopenharmony_ci#include <linux/cdrom.h> 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 388c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#include "usb.h" 418c2ecf20Sopenharmony_ci#include "transport.h" 428c2ecf20Sopenharmony_ci#include "protocol.h" 438c2ecf20Sopenharmony_ci#include "debug.h" 448c2ecf20Sopenharmony_ci#include "scsiglue.h" 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define DRV_NAME "ums-usbat" 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Driver for SCM Microsystems (a.k.a. Shuttle) USB-ATAPI cable"); 498c2ecf20Sopenharmony_ciMODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>, Robert Baruch <autophile@starband.net>"); 508c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 518c2ecf20Sopenharmony_ciMODULE_IMPORT_NS(USB_STORAGE); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* Supported device types */ 548c2ecf20Sopenharmony_ci#define USBAT_DEV_HP8200 0x01 558c2ecf20Sopenharmony_ci#define USBAT_DEV_FLASH 0x02 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define USBAT_EPP_PORT 0x10 588c2ecf20Sopenharmony_ci#define USBAT_EPP_REGISTER 0x30 598c2ecf20Sopenharmony_ci#define USBAT_ATA 0x40 608c2ecf20Sopenharmony_ci#define USBAT_ISA 0x50 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* Commands (need to be logically OR'd with an access type */ 638c2ecf20Sopenharmony_ci#define USBAT_CMD_READ_REG 0x00 648c2ecf20Sopenharmony_ci#define USBAT_CMD_WRITE_REG 0x01 658c2ecf20Sopenharmony_ci#define USBAT_CMD_READ_BLOCK 0x02 668c2ecf20Sopenharmony_ci#define USBAT_CMD_WRITE_BLOCK 0x03 678c2ecf20Sopenharmony_ci#define USBAT_CMD_COND_READ_BLOCK 0x04 688c2ecf20Sopenharmony_ci#define USBAT_CMD_COND_WRITE_BLOCK 0x05 698c2ecf20Sopenharmony_ci#define USBAT_CMD_WRITE_REGS 0x07 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci/* Commands (these don't need an access type) */ 728c2ecf20Sopenharmony_ci#define USBAT_CMD_EXEC_CMD 0x80 738c2ecf20Sopenharmony_ci#define USBAT_CMD_SET_FEAT 0x81 748c2ecf20Sopenharmony_ci#define USBAT_CMD_UIO 0x82 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/* Methods of accessing UIO register */ 778c2ecf20Sopenharmony_ci#define USBAT_UIO_READ 1 788c2ecf20Sopenharmony_ci#define USBAT_UIO_WRITE 0 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/* Qualifier bits */ 818c2ecf20Sopenharmony_ci#define USBAT_QUAL_FCQ 0x20 /* full compare */ 828c2ecf20Sopenharmony_ci#define USBAT_QUAL_ALQ 0x10 /* auto load subcount */ 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/* USBAT Flash Media status types */ 858c2ecf20Sopenharmony_ci#define USBAT_FLASH_MEDIA_NONE 0 868c2ecf20Sopenharmony_ci#define USBAT_FLASH_MEDIA_CF 1 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci/* USBAT Flash Media change types */ 898c2ecf20Sopenharmony_ci#define USBAT_FLASH_MEDIA_SAME 0 908c2ecf20Sopenharmony_ci#define USBAT_FLASH_MEDIA_CHANGED 1 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci/* USBAT ATA registers */ 938c2ecf20Sopenharmony_ci#define USBAT_ATA_DATA 0x10 /* read/write data (R/W) */ 948c2ecf20Sopenharmony_ci#define USBAT_ATA_FEATURES 0x11 /* set features (W) */ 958c2ecf20Sopenharmony_ci#define USBAT_ATA_ERROR 0x11 /* error (R) */ 968c2ecf20Sopenharmony_ci#define USBAT_ATA_SECCNT 0x12 /* sector count (R/W) */ 978c2ecf20Sopenharmony_ci#define USBAT_ATA_SECNUM 0x13 /* sector number (R/W) */ 988c2ecf20Sopenharmony_ci#define USBAT_ATA_LBA_ME 0x14 /* cylinder low (R/W) */ 998c2ecf20Sopenharmony_ci#define USBAT_ATA_LBA_HI 0x15 /* cylinder high (R/W) */ 1008c2ecf20Sopenharmony_ci#define USBAT_ATA_DEVICE 0x16 /* head/device selection (R/W) */ 1018c2ecf20Sopenharmony_ci#define USBAT_ATA_STATUS 0x17 /* device status (R) */ 1028c2ecf20Sopenharmony_ci#define USBAT_ATA_CMD 0x17 /* device command (W) */ 1038c2ecf20Sopenharmony_ci#define USBAT_ATA_ALTSTATUS 0x0E /* status (no clear IRQ) (R) */ 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci/* USBAT User I/O Data registers */ 1068c2ecf20Sopenharmony_ci#define USBAT_UIO_EPAD 0x80 /* Enable Peripheral Control Signals */ 1078c2ecf20Sopenharmony_ci#define USBAT_UIO_CDT 0x40 /* Card Detect (Read Only) */ 1088c2ecf20Sopenharmony_ci /* CDT = ACKD & !UI1 & !UI0 */ 1098c2ecf20Sopenharmony_ci#define USBAT_UIO_1 0x20 /* I/O 1 */ 1108c2ecf20Sopenharmony_ci#define USBAT_UIO_0 0x10 /* I/O 0 */ 1118c2ecf20Sopenharmony_ci#define USBAT_UIO_EPP_ATA 0x08 /* 1=EPP mode, 0=ATA mode */ 1128c2ecf20Sopenharmony_ci#define USBAT_UIO_UI1 0x04 /* Input 1 */ 1138c2ecf20Sopenharmony_ci#define USBAT_UIO_UI0 0x02 /* Input 0 */ 1148c2ecf20Sopenharmony_ci#define USBAT_UIO_INTR_ACK 0x01 /* Interrupt (ATA/ISA)/Acknowledge (EPP) */ 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci/* USBAT User I/O Enable registers */ 1178c2ecf20Sopenharmony_ci#define USBAT_UIO_DRVRST 0x80 /* Reset Peripheral */ 1188c2ecf20Sopenharmony_ci#define USBAT_UIO_ACKD 0x40 /* Enable Card Detect */ 1198c2ecf20Sopenharmony_ci#define USBAT_UIO_OE1 0x20 /* I/O 1 set=output/clr=input */ 1208c2ecf20Sopenharmony_ci /* If ACKD=1, set OE1 to 1 also. */ 1218c2ecf20Sopenharmony_ci#define USBAT_UIO_OE0 0x10 /* I/O 0 set=output/clr=input */ 1228c2ecf20Sopenharmony_ci#define USBAT_UIO_ADPRST 0x01 /* Reset SCM chip */ 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci/* USBAT Features */ 1258c2ecf20Sopenharmony_ci#define USBAT_FEAT_ETEN 0x80 /* External trigger enable */ 1268c2ecf20Sopenharmony_ci#define USBAT_FEAT_U1 0x08 1278c2ecf20Sopenharmony_ci#define USBAT_FEAT_U0 0x04 1288c2ecf20Sopenharmony_ci#define USBAT_FEAT_ET1 0x02 1298c2ecf20Sopenharmony_ci#define USBAT_FEAT_ET2 0x01 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistruct usbat_info { 1328c2ecf20Sopenharmony_ci int devicetype; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* Used for Flash readers only */ 1358c2ecf20Sopenharmony_ci unsigned long sectors; /* total sector count */ 1368c2ecf20Sopenharmony_ci unsigned long ssize; /* sector size in bytes */ 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci unsigned char sense_key; 1398c2ecf20Sopenharmony_ci unsigned long sense_asc; /* additional sense code */ 1408c2ecf20Sopenharmony_ci unsigned long sense_ascq; /* additional sense code qualifier */ 1418c2ecf20Sopenharmony_ci}; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci#define short_pack(LSB,MSB) ( ((u16)(LSB)) | ( ((u16)(MSB))<<8 ) ) 1448c2ecf20Sopenharmony_ci#define LSB_of(s) ((s)&0xFF) 1458c2ecf20Sopenharmony_ci#define MSB_of(s) ((s)>>8) 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic int transferred = 0; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us); 1508c2ecf20Sopenharmony_cistatic int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic int init_usbat_cd(struct us_data *us); 1538c2ecf20Sopenharmony_cistatic int init_usbat_flash(struct us_data *us); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci/* 1578c2ecf20Sopenharmony_ci * The table of devices 1588c2ecf20Sopenharmony_ci */ 1598c2ecf20Sopenharmony_ci#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ 1608c2ecf20Sopenharmony_ci vendorName, productName, useProtocol, useTransport, \ 1618c2ecf20Sopenharmony_ci initFunction, flags) \ 1628c2ecf20Sopenharmony_ci{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ 1638c2ecf20Sopenharmony_ci .driver_info = (flags) } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic struct usb_device_id usbat_usb_ids[] = { 1668c2ecf20Sopenharmony_ci# include "unusual_usbat.h" 1678c2ecf20Sopenharmony_ci { } /* Terminating entry */ 1688c2ecf20Sopenharmony_ci}; 1698c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, usbat_usb_ids); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci#undef UNUSUAL_DEV 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci/* 1748c2ecf20Sopenharmony_ci * The flags table 1758c2ecf20Sopenharmony_ci */ 1768c2ecf20Sopenharmony_ci#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ 1778c2ecf20Sopenharmony_ci vendor_name, product_name, use_protocol, use_transport, \ 1788c2ecf20Sopenharmony_ci init_function, Flags) \ 1798c2ecf20Sopenharmony_ci{ \ 1808c2ecf20Sopenharmony_ci .vendorName = vendor_name, \ 1818c2ecf20Sopenharmony_ci .productName = product_name, \ 1828c2ecf20Sopenharmony_ci .useProtocol = use_protocol, \ 1838c2ecf20Sopenharmony_ci .useTransport = use_transport, \ 1848c2ecf20Sopenharmony_ci .initFunction = init_function, \ 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic struct us_unusual_dev usbat_unusual_dev_list[] = { 1888c2ecf20Sopenharmony_ci# include "unusual_usbat.h" 1898c2ecf20Sopenharmony_ci { } /* Terminating entry */ 1908c2ecf20Sopenharmony_ci}; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci#undef UNUSUAL_DEV 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci/* 1958c2ecf20Sopenharmony_ci * Convenience function to produce an ATA read/write sectors command 1968c2ecf20Sopenharmony_ci * Use cmd=0x20 for read, cmd=0x30 for write 1978c2ecf20Sopenharmony_ci */ 1988c2ecf20Sopenharmony_cistatic void usbat_pack_ata_sector_cmd(unsigned char *buf, 1998c2ecf20Sopenharmony_ci unsigned char thistime, 2008c2ecf20Sopenharmony_ci u32 sector, unsigned char cmd) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci buf[0] = 0; 2038c2ecf20Sopenharmony_ci buf[1] = thistime; 2048c2ecf20Sopenharmony_ci buf[2] = sector & 0xFF; 2058c2ecf20Sopenharmony_ci buf[3] = (sector >> 8) & 0xFF; 2068c2ecf20Sopenharmony_ci buf[4] = (sector >> 16) & 0xFF; 2078c2ecf20Sopenharmony_ci buf[5] = 0xE0 | ((sector >> 24) & 0x0F); 2088c2ecf20Sopenharmony_ci buf[6] = cmd; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci/* 2128c2ecf20Sopenharmony_ci * Convenience function to get the device type (flash or hp8200) 2138c2ecf20Sopenharmony_ci */ 2148c2ecf20Sopenharmony_cistatic int usbat_get_device_type(struct us_data *us) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci return ((struct usbat_info*)us->extra)->devicetype; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci/* 2208c2ecf20Sopenharmony_ci * Read a register from the device 2218c2ecf20Sopenharmony_ci */ 2228c2ecf20Sopenharmony_cistatic int usbat_read(struct us_data *us, 2238c2ecf20Sopenharmony_ci unsigned char access, 2248c2ecf20Sopenharmony_ci unsigned char reg, 2258c2ecf20Sopenharmony_ci unsigned char *content) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci return usb_stor_ctrl_transfer(us, 2288c2ecf20Sopenharmony_ci us->recv_ctrl_pipe, 2298c2ecf20Sopenharmony_ci access | USBAT_CMD_READ_REG, 2308c2ecf20Sopenharmony_ci 0xC0, 2318c2ecf20Sopenharmony_ci (u16)reg, 2328c2ecf20Sopenharmony_ci 0, 2338c2ecf20Sopenharmony_ci content, 2348c2ecf20Sopenharmony_ci 1); 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci/* 2388c2ecf20Sopenharmony_ci * Write to a register on the device 2398c2ecf20Sopenharmony_ci */ 2408c2ecf20Sopenharmony_cistatic int usbat_write(struct us_data *us, 2418c2ecf20Sopenharmony_ci unsigned char access, 2428c2ecf20Sopenharmony_ci unsigned char reg, 2438c2ecf20Sopenharmony_ci unsigned char content) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci return usb_stor_ctrl_transfer(us, 2468c2ecf20Sopenharmony_ci us->send_ctrl_pipe, 2478c2ecf20Sopenharmony_ci access | USBAT_CMD_WRITE_REG, 2488c2ecf20Sopenharmony_ci 0x40, 2498c2ecf20Sopenharmony_ci short_pack(reg, content), 2508c2ecf20Sopenharmony_ci 0, 2518c2ecf20Sopenharmony_ci NULL, 2528c2ecf20Sopenharmony_ci 0); 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci/* 2568c2ecf20Sopenharmony_ci * Convenience function to perform a bulk read 2578c2ecf20Sopenharmony_ci */ 2588c2ecf20Sopenharmony_cistatic int usbat_bulk_read(struct us_data *us, 2598c2ecf20Sopenharmony_ci void* buf, 2608c2ecf20Sopenharmony_ci unsigned int len, 2618c2ecf20Sopenharmony_ci int use_sg) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci if (len == 0) 2648c2ecf20Sopenharmony_ci return USB_STOR_XFER_GOOD; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci usb_stor_dbg(us, "len = %d\n", len); 2678c2ecf20Sopenharmony_ci return usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, buf, len, use_sg, NULL); 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci/* 2718c2ecf20Sopenharmony_ci * Convenience function to perform a bulk write 2728c2ecf20Sopenharmony_ci */ 2738c2ecf20Sopenharmony_cistatic int usbat_bulk_write(struct us_data *us, 2748c2ecf20Sopenharmony_ci void* buf, 2758c2ecf20Sopenharmony_ci unsigned int len, 2768c2ecf20Sopenharmony_ci int use_sg) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci if (len == 0) 2798c2ecf20Sopenharmony_ci return USB_STOR_XFER_GOOD; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci usb_stor_dbg(us, "len = %d\n", len); 2828c2ecf20Sopenharmony_ci return usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, buf, len, use_sg, NULL); 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci/* 2868c2ecf20Sopenharmony_ci * Some USBAT-specific commands can only be executed over a command transport 2878c2ecf20Sopenharmony_ci * This transport allows one (len=8) or two (len=16) vendor-specific commands 2888c2ecf20Sopenharmony_ci * to be executed. 2898c2ecf20Sopenharmony_ci */ 2908c2ecf20Sopenharmony_cistatic int usbat_execute_command(struct us_data *us, 2918c2ecf20Sopenharmony_ci unsigned char *commands, 2928c2ecf20Sopenharmony_ci unsigned int len) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci return usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, 2958c2ecf20Sopenharmony_ci USBAT_CMD_EXEC_CMD, 0x40, 0, 0, 2968c2ecf20Sopenharmony_ci commands, len); 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci/* 3008c2ecf20Sopenharmony_ci * Read the status register 3018c2ecf20Sopenharmony_ci */ 3028c2ecf20Sopenharmony_cistatic int usbat_get_status(struct us_data *us, unsigned char *status) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci int rc; 3058c2ecf20Sopenharmony_ci rc = usbat_read(us, USBAT_ATA, USBAT_ATA_STATUS, status); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci usb_stor_dbg(us, "0x%02X\n", *status); 3088c2ecf20Sopenharmony_ci return rc; 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci/* 3128c2ecf20Sopenharmony_ci * Check the device status 3138c2ecf20Sopenharmony_ci */ 3148c2ecf20Sopenharmony_cistatic int usbat_check_status(struct us_data *us) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci unsigned char *reply = us->iobuf; 3178c2ecf20Sopenharmony_ci int rc; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci rc = usbat_get_status(us, reply); 3208c2ecf20Sopenharmony_ci if (rc != USB_STOR_XFER_GOOD) 3218c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_FAILED; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci /* error/check condition (0x51 is ok) */ 3248c2ecf20Sopenharmony_ci if (*reply & 0x01 && *reply != 0x51) 3258c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_FAILED; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci /* device fault */ 3288c2ecf20Sopenharmony_ci if (*reply & 0x20) 3298c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_FAILED; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci/* 3358c2ecf20Sopenharmony_ci * Stores critical information in internal registers in preparation for the execution 3368c2ecf20Sopenharmony_ci * of a conditional usbat_read_blocks or usbat_write_blocks call. 3378c2ecf20Sopenharmony_ci */ 3388c2ecf20Sopenharmony_cistatic int usbat_set_shuttle_features(struct us_data *us, 3398c2ecf20Sopenharmony_ci unsigned char external_trigger, 3408c2ecf20Sopenharmony_ci unsigned char epp_control, 3418c2ecf20Sopenharmony_ci unsigned char mask_byte, 3428c2ecf20Sopenharmony_ci unsigned char test_pattern, 3438c2ecf20Sopenharmony_ci unsigned char subcountH, 3448c2ecf20Sopenharmony_ci unsigned char subcountL) 3458c2ecf20Sopenharmony_ci{ 3468c2ecf20Sopenharmony_ci unsigned char *command = us->iobuf; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci command[0] = 0x40; 3498c2ecf20Sopenharmony_ci command[1] = USBAT_CMD_SET_FEAT; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci /* 3528c2ecf20Sopenharmony_ci * The only bit relevant to ATA access is bit 6 3538c2ecf20Sopenharmony_ci * which defines 8 bit data access (set) or 16 bit (unset) 3548c2ecf20Sopenharmony_ci */ 3558c2ecf20Sopenharmony_ci command[2] = epp_control; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* 3588c2ecf20Sopenharmony_ci * If FCQ is set in the qualifier (defined in R/W cmd), then bits U0, U1, 3598c2ecf20Sopenharmony_ci * ET1 and ET2 define an external event to be checked for on event of a 3608c2ecf20Sopenharmony_ci * _read_blocks or _write_blocks operation. The read/write will not take 3618c2ecf20Sopenharmony_ci * place unless the defined trigger signal is active. 3628c2ecf20Sopenharmony_ci */ 3638c2ecf20Sopenharmony_ci command[3] = external_trigger; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci /* 3668c2ecf20Sopenharmony_ci * The resultant byte of the mask operation (see mask_byte) is compared for 3678c2ecf20Sopenharmony_ci * equivalence with this test pattern. If equal, the read/write will take 3688c2ecf20Sopenharmony_ci * place. 3698c2ecf20Sopenharmony_ci */ 3708c2ecf20Sopenharmony_ci command[4] = test_pattern; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci /* 3738c2ecf20Sopenharmony_ci * This value is logically ANDed with the status register field specified 3748c2ecf20Sopenharmony_ci * in the read/write command. 3758c2ecf20Sopenharmony_ci */ 3768c2ecf20Sopenharmony_ci command[5] = mask_byte; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci /* 3798c2ecf20Sopenharmony_ci * If ALQ is set in the qualifier, this field contains the address of the 3808c2ecf20Sopenharmony_ci * registers where the byte count should be read for transferring the data. 3818c2ecf20Sopenharmony_ci * If ALQ is not set, then this field contains the number of bytes to be 3828c2ecf20Sopenharmony_ci * transferred. 3838c2ecf20Sopenharmony_ci */ 3848c2ecf20Sopenharmony_ci command[6] = subcountL; 3858c2ecf20Sopenharmony_ci command[7] = subcountH; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci return usbat_execute_command(us, command, 8); 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci/* 3918c2ecf20Sopenharmony_ci * Block, waiting for an ATA device to become not busy or to report 3928c2ecf20Sopenharmony_ci * an error condition. 3938c2ecf20Sopenharmony_ci */ 3948c2ecf20Sopenharmony_cistatic int usbat_wait_not_busy(struct us_data *us, int minutes) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci int i; 3978c2ecf20Sopenharmony_ci int result; 3988c2ecf20Sopenharmony_ci unsigned char *status = us->iobuf; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci /* 4018c2ecf20Sopenharmony_ci * Synchronizing cache on a CDR could take a heck of a long time, 4028c2ecf20Sopenharmony_ci * but probably not more than 10 minutes or so. On the other hand, 4038c2ecf20Sopenharmony_ci * doing a full blank on a CDRW at speed 1 will take about 75 4048c2ecf20Sopenharmony_ci * minutes! 4058c2ecf20Sopenharmony_ci */ 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci for (i=0; i<1200+minutes*60; i++) { 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci result = usbat_get_status(us, status); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (result!=USB_STOR_XFER_GOOD) 4128c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 4138c2ecf20Sopenharmony_ci if (*status & 0x01) { /* check condition */ 4148c2ecf20Sopenharmony_ci result = usbat_read(us, USBAT_ATA, 0x10, status); 4158c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_FAILED; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci if (*status & 0x20) /* device fault */ 4188c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_FAILED; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci if ((*status & 0x80)==0x00) { /* not busy */ 4218c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Waited not busy for %d steps\n", i); 4228c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if (i<500) 4268c2ecf20Sopenharmony_ci msleep(10); /* 5 seconds */ 4278c2ecf20Sopenharmony_ci else if (i<700) 4288c2ecf20Sopenharmony_ci msleep(50); /* 10 seconds */ 4298c2ecf20Sopenharmony_ci else if (i<1200) 4308c2ecf20Sopenharmony_ci msleep(100); /* 50 seconds */ 4318c2ecf20Sopenharmony_ci else 4328c2ecf20Sopenharmony_ci msleep(1000); /* X minutes */ 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Waited not busy for %d minutes, timing out\n", 4368c2ecf20Sopenharmony_ci minutes); 4378c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_FAILED; 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci/* 4418c2ecf20Sopenharmony_ci * Read block data from the data register 4428c2ecf20Sopenharmony_ci */ 4438c2ecf20Sopenharmony_cistatic int usbat_read_block(struct us_data *us, 4448c2ecf20Sopenharmony_ci void* buf, 4458c2ecf20Sopenharmony_ci unsigned short len, 4468c2ecf20Sopenharmony_ci int use_sg) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci int result; 4498c2ecf20Sopenharmony_ci unsigned char *command = us->iobuf; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (!len) 4528c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci command[0] = 0xC0; 4558c2ecf20Sopenharmony_ci command[1] = USBAT_ATA | USBAT_CMD_READ_BLOCK; 4568c2ecf20Sopenharmony_ci command[2] = USBAT_ATA_DATA; 4578c2ecf20Sopenharmony_ci command[3] = 0; 4588c2ecf20Sopenharmony_ci command[4] = 0; 4598c2ecf20Sopenharmony_ci command[5] = 0; 4608c2ecf20Sopenharmony_ci command[6] = LSB_of(len); 4618c2ecf20Sopenharmony_ci command[7] = MSB_of(len); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci result = usbat_execute_command(us, command, 8); 4648c2ecf20Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) 4658c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci result = usbat_bulk_read(us, buf, len, use_sg); 4688c2ecf20Sopenharmony_ci return (result == USB_STOR_XFER_GOOD ? 4698c2ecf20Sopenharmony_ci USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR); 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci/* 4738c2ecf20Sopenharmony_ci * Write block data via the data register 4748c2ecf20Sopenharmony_ci */ 4758c2ecf20Sopenharmony_cistatic int usbat_write_block(struct us_data *us, 4768c2ecf20Sopenharmony_ci unsigned char access, 4778c2ecf20Sopenharmony_ci void* buf, 4788c2ecf20Sopenharmony_ci unsigned short len, 4798c2ecf20Sopenharmony_ci int minutes, 4808c2ecf20Sopenharmony_ci int use_sg) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci int result; 4838c2ecf20Sopenharmony_ci unsigned char *command = us->iobuf; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci if (!len) 4868c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci command[0] = 0x40; 4898c2ecf20Sopenharmony_ci command[1] = access | USBAT_CMD_WRITE_BLOCK; 4908c2ecf20Sopenharmony_ci command[2] = USBAT_ATA_DATA; 4918c2ecf20Sopenharmony_ci command[3] = 0; 4928c2ecf20Sopenharmony_ci command[4] = 0; 4938c2ecf20Sopenharmony_ci command[5] = 0; 4948c2ecf20Sopenharmony_ci command[6] = LSB_of(len); 4958c2ecf20Sopenharmony_ci command[7] = MSB_of(len); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci result = usbat_execute_command(us, command, 8); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) 5008c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci result = usbat_bulk_write(us, buf, len, use_sg); 5038c2ecf20Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) 5048c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci return usbat_wait_not_busy(us, minutes); 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci/* 5108c2ecf20Sopenharmony_ci * Process read and write requests 5118c2ecf20Sopenharmony_ci */ 5128c2ecf20Sopenharmony_cistatic int usbat_hp8200e_rw_block_test(struct us_data *us, 5138c2ecf20Sopenharmony_ci unsigned char access, 5148c2ecf20Sopenharmony_ci unsigned char *registers, 5158c2ecf20Sopenharmony_ci unsigned char *data_out, 5168c2ecf20Sopenharmony_ci unsigned short num_registers, 5178c2ecf20Sopenharmony_ci unsigned char data_reg, 5188c2ecf20Sopenharmony_ci unsigned char status_reg, 5198c2ecf20Sopenharmony_ci unsigned char timeout, 5208c2ecf20Sopenharmony_ci unsigned char qualifier, 5218c2ecf20Sopenharmony_ci int direction, 5228c2ecf20Sopenharmony_ci void *buf, 5238c2ecf20Sopenharmony_ci unsigned short len, 5248c2ecf20Sopenharmony_ci int use_sg, 5258c2ecf20Sopenharmony_ci int minutes) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci int result; 5288c2ecf20Sopenharmony_ci unsigned int pipe = (direction == DMA_FROM_DEVICE) ? 5298c2ecf20Sopenharmony_ci us->recv_bulk_pipe : us->send_bulk_pipe; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci unsigned char *command = us->iobuf; 5328c2ecf20Sopenharmony_ci int i, j; 5338c2ecf20Sopenharmony_ci int cmdlen; 5348c2ecf20Sopenharmony_ci unsigned char *data = us->iobuf; 5358c2ecf20Sopenharmony_ci unsigned char *status = us->iobuf; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci BUG_ON(num_registers > US_IOBUF_SIZE/2); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci for (i=0; i<20; i++) { 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci /* 5428c2ecf20Sopenharmony_ci * The first time we send the full command, which consists 5438c2ecf20Sopenharmony_ci * of downloading the SCSI command followed by downloading 5448c2ecf20Sopenharmony_ci * the data via a write-and-test. Any other time we only 5458c2ecf20Sopenharmony_ci * send the command to download the data -- the SCSI command 5468c2ecf20Sopenharmony_ci * is still 'active' in some sense in the device. 5478c2ecf20Sopenharmony_ci * 5488c2ecf20Sopenharmony_ci * We're only going to try sending the data 10 times. After 5498c2ecf20Sopenharmony_ci * that, we just return a failure. 5508c2ecf20Sopenharmony_ci */ 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci if (i==0) { 5538c2ecf20Sopenharmony_ci cmdlen = 16; 5548c2ecf20Sopenharmony_ci /* 5558c2ecf20Sopenharmony_ci * Write to multiple registers 5568c2ecf20Sopenharmony_ci * Not really sure the 0x07, 0x17, 0xfc, 0xe7 is 5578c2ecf20Sopenharmony_ci * necessary here, but that's what came out of the 5588c2ecf20Sopenharmony_ci * trace every single time. 5598c2ecf20Sopenharmony_ci */ 5608c2ecf20Sopenharmony_ci command[0] = 0x40; 5618c2ecf20Sopenharmony_ci command[1] = access | USBAT_CMD_WRITE_REGS; 5628c2ecf20Sopenharmony_ci command[2] = 0x07; 5638c2ecf20Sopenharmony_ci command[3] = 0x17; 5648c2ecf20Sopenharmony_ci command[4] = 0xFC; 5658c2ecf20Sopenharmony_ci command[5] = 0xE7; 5668c2ecf20Sopenharmony_ci command[6] = LSB_of(num_registers*2); 5678c2ecf20Sopenharmony_ci command[7] = MSB_of(num_registers*2); 5688c2ecf20Sopenharmony_ci } else 5698c2ecf20Sopenharmony_ci cmdlen = 8; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci /* Conditionally read or write blocks */ 5728c2ecf20Sopenharmony_ci command[cmdlen-8] = (direction==DMA_TO_DEVICE ? 0x40 : 0xC0); 5738c2ecf20Sopenharmony_ci command[cmdlen-7] = access | 5748c2ecf20Sopenharmony_ci (direction==DMA_TO_DEVICE ? 5758c2ecf20Sopenharmony_ci USBAT_CMD_COND_WRITE_BLOCK : USBAT_CMD_COND_READ_BLOCK); 5768c2ecf20Sopenharmony_ci command[cmdlen-6] = data_reg; 5778c2ecf20Sopenharmony_ci command[cmdlen-5] = status_reg; 5788c2ecf20Sopenharmony_ci command[cmdlen-4] = timeout; 5798c2ecf20Sopenharmony_ci command[cmdlen-3] = qualifier; 5808c2ecf20Sopenharmony_ci command[cmdlen-2] = LSB_of(len); 5818c2ecf20Sopenharmony_ci command[cmdlen-1] = MSB_of(len); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci result = usbat_execute_command(us, command, cmdlen); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) 5868c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if (i==0) { 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci for (j=0; j<num_registers; j++) { 5918c2ecf20Sopenharmony_ci data[j<<1] = registers[j]; 5928c2ecf20Sopenharmony_ci data[1+(j<<1)] = data_out[j]; 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci result = usbat_bulk_write(us, data, num_registers*2, 0); 5968c2ecf20Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) 5978c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci result = usb_stor_bulk_transfer_sg(us, 6028c2ecf20Sopenharmony_ci pipe, buf, len, use_sg, NULL); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci /* 6058c2ecf20Sopenharmony_ci * If we get a stall on the bulk download, we'll retry 6068c2ecf20Sopenharmony_ci * the bulk download -- but not the SCSI command because 6078c2ecf20Sopenharmony_ci * in some sense the SCSI command is still 'active' and 6088c2ecf20Sopenharmony_ci * waiting for the data. Don't ask me why this should be; 6098c2ecf20Sopenharmony_ci * I'm only following what the Windoze driver did. 6108c2ecf20Sopenharmony_ci * 6118c2ecf20Sopenharmony_ci * Note that a stall for the test-and-read/write command means 6128c2ecf20Sopenharmony_ci * that the test failed. In this case we're testing to make 6138c2ecf20Sopenharmony_ci * sure that the device is error-free 6148c2ecf20Sopenharmony_ci * (i.e. bit 0 -- CHK -- of status is 0). The most likely 6158c2ecf20Sopenharmony_ci * hypothesis is that the USBAT chip somehow knows what 6168c2ecf20Sopenharmony_ci * the device will accept, but doesn't give the device any 6178c2ecf20Sopenharmony_ci * data until all data is received. Thus, the device would 6188c2ecf20Sopenharmony_ci * still be waiting for the first byte of data if a stall 6198c2ecf20Sopenharmony_ci * occurs, even if the stall implies that some data was 6208c2ecf20Sopenharmony_ci * transferred. 6218c2ecf20Sopenharmony_ci */ 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci if (result == USB_STOR_XFER_SHORT || 6248c2ecf20Sopenharmony_ci result == USB_STOR_XFER_STALLED) { 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci /* 6278c2ecf20Sopenharmony_ci * If we're reading and we stalled, then clear 6288c2ecf20Sopenharmony_ci * the bulk output pipe only the first time. 6298c2ecf20Sopenharmony_ci */ 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci if (direction==DMA_FROM_DEVICE && i==0) { 6328c2ecf20Sopenharmony_ci if (usb_stor_clear_halt(us, 6338c2ecf20Sopenharmony_ci us->send_bulk_pipe) < 0) 6348c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci /* 6388c2ecf20Sopenharmony_ci * Read status: is the device angry, or just busy? 6398c2ecf20Sopenharmony_ci */ 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci result = usbat_read(us, USBAT_ATA, 6428c2ecf20Sopenharmony_ci direction==DMA_TO_DEVICE ? 6438c2ecf20Sopenharmony_ci USBAT_ATA_STATUS : USBAT_ATA_ALTSTATUS, 6448c2ecf20Sopenharmony_ci status); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci if (result!=USB_STOR_XFER_GOOD) 6478c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 6488c2ecf20Sopenharmony_ci if (*status & 0x01) /* check condition */ 6498c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_FAILED; 6508c2ecf20Sopenharmony_ci if (*status & 0x20) /* device fault */ 6518c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_FAILED; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Redoing %s\n", 6548c2ecf20Sopenharmony_ci direction == DMA_TO_DEVICE 6558c2ecf20Sopenharmony_ci ? "write" : "read"); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci } else if (result != USB_STOR_XFER_GOOD) 6588c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 6598c2ecf20Sopenharmony_ci else 6608c2ecf20Sopenharmony_ci return usbat_wait_not_busy(us, minutes); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Bummer! %s bulk data 20 times failed\n", 6658c2ecf20Sopenharmony_ci direction == DMA_TO_DEVICE ? "Writing" : "Reading"); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_FAILED; 6688c2ecf20Sopenharmony_ci} 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci/* 6718c2ecf20Sopenharmony_ci * Write to multiple registers: 6728c2ecf20Sopenharmony_ci * Allows us to write specific data to any registers. The data to be written 6738c2ecf20Sopenharmony_ci * gets packed in this sequence: reg0, data0, reg1, data1, ..., regN, dataN 6748c2ecf20Sopenharmony_ci * which gets sent through bulk out. 6758c2ecf20Sopenharmony_ci * Not designed for large transfers of data! 6768c2ecf20Sopenharmony_ci */ 6778c2ecf20Sopenharmony_cistatic int usbat_multiple_write(struct us_data *us, 6788c2ecf20Sopenharmony_ci unsigned char *registers, 6798c2ecf20Sopenharmony_ci unsigned char *data_out, 6808c2ecf20Sopenharmony_ci unsigned short num_registers) 6818c2ecf20Sopenharmony_ci{ 6828c2ecf20Sopenharmony_ci int i, result; 6838c2ecf20Sopenharmony_ci unsigned char *data = us->iobuf; 6848c2ecf20Sopenharmony_ci unsigned char *command = us->iobuf; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci BUG_ON(num_registers > US_IOBUF_SIZE/2); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci /* Write to multiple registers, ATA access */ 6898c2ecf20Sopenharmony_ci command[0] = 0x40; 6908c2ecf20Sopenharmony_ci command[1] = USBAT_ATA | USBAT_CMD_WRITE_REGS; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci /* No relevance */ 6938c2ecf20Sopenharmony_ci command[2] = 0; 6948c2ecf20Sopenharmony_ci command[3] = 0; 6958c2ecf20Sopenharmony_ci command[4] = 0; 6968c2ecf20Sopenharmony_ci command[5] = 0; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci /* Number of bytes to be transferred (incl. addresses and data) */ 6998c2ecf20Sopenharmony_ci command[6] = LSB_of(num_registers*2); 7008c2ecf20Sopenharmony_ci command[7] = MSB_of(num_registers*2); 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci /* The setup command */ 7038c2ecf20Sopenharmony_ci result = usbat_execute_command(us, command, 8); 7048c2ecf20Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) 7058c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci /* Create the reg/data, reg/data sequence */ 7088c2ecf20Sopenharmony_ci for (i=0; i<num_registers; i++) { 7098c2ecf20Sopenharmony_ci data[i<<1] = registers[i]; 7108c2ecf20Sopenharmony_ci data[1+(i<<1)] = data_out[i]; 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci /* Send the data */ 7148c2ecf20Sopenharmony_ci result = usbat_bulk_write(us, data, num_registers*2, 0); 7158c2ecf20Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) 7168c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci if (usbat_get_device_type(us) == USBAT_DEV_HP8200) 7198c2ecf20Sopenharmony_ci return usbat_wait_not_busy(us, 0); 7208c2ecf20Sopenharmony_ci else 7218c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 7228c2ecf20Sopenharmony_ci} 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci/* 7258c2ecf20Sopenharmony_ci * Conditionally read blocks from device: 7268c2ecf20Sopenharmony_ci * Allows us to read blocks from a specific data register, based upon the 7278c2ecf20Sopenharmony_ci * condition that a status register can be successfully masked with a status 7288c2ecf20Sopenharmony_ci * qualifier. If this condition is not initially met, the read will wait 7298c2ecf20Sopenharmony_ci * up until a maximum amount of time has elapsed, as specified by timeout. 7308c2ecf20Sopenharmony_ci * The read will start when the condition is met, otherwise the command aborts. 7318c2ecf20Sopenharmony_ci * 7328c2ecf20Sopenharmony_ci * The qualifier defined here is not the value that is masked, it defines 7338c2ecf20Sopenharmony_ci * conditions for the write to take place. The actual masked qualifier (and 7348c2ecf20Sopenharmony_ci * other related details) are defined beforehand with _set_shuttle_features(). 7358c2ecf20Sopenharmony_ci */ 7368c2ecf20Sopenharmony_cistatic int usbat_read_blocks(struct us_data *us, 7378c2ecf20Sopenharmony_ci void* buffer, 7388c2ecf20Sopenharmony_ci int len, 7398c2ecf20Sopenharmony_ci int use_sg) 7408c2ecf20Sopenharmony_ci{ 7418c2ecf20Sopenharmony_ci int result; 7428c2ecf20Sopenharmony_ci unsigned char *command = us->iobuf; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci command[0] = 0xC0; 7458c2ecf20Sopenharmony_ci command[1] = USBAT_ATA | USBAT_CMD_COND_READ_BLOCK; 7468c2ecf20Sopenharmony_ci command[2] = USBAT_ATA_DATA; 7478c2ecf20Sopenharmony_ci command[3] = USBAT_ATA_STATUS; 7488c2ecf20Sopenharmony_ci command[4] = 0xFD; /* Timeout (ms); */ 7498c2ecf20Sopenharmony_ci command[5] = USBAT_QUAL_FCQ; 7508c2ecf20Sopenharmony_ci command[6] = LSB_of(len); 7518c2ecf20Sopenharmony_ci command[7] = MSB_of(len); 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci /* Multiple block read setup command */ 7548c2ecf20Sopenharmony_ci result = usbat_execute_command(us, command, 8); 7558c2ecf20Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) 7568c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_FAILED; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci /* Read the blocks we just asked for */ 7598c2ecf20Sopenharmony_ci result = usbat_bulk_read(us, buffer, len, use_sg); 7608c2ecf20Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) 7618c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_FAILED; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 7648c2ecf20Sopenharmony_ci} 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci/* 7678c2ecf20Sopenharmony_ci * Conditionally write blocks to device: 7688c2ecf20Sopenharmony_ci * Allows us to write blocks to a specific data register, based upon the 7698c2ecf20Sopenharmony_ci * condition that a status register can be successfully masked with a status 7708c2ecf20Sopenharmony_ci * qualifier. If this condition is not initially met, the write will wait 7718c2ecf20Sopenharmony_ci * up until a maximum amount of time has elapsed, as specified by timeout. 7728c2ecf20Sopenharmony_ci * The read will start when the condition is met, otherwise the command aborts. 7738c2ecf20Sopenharmony_ci * 7748c2ecf20Sopenharmony_ci * The qualifier defined here is not the value that is masked, it defines 7758c2ecf20Sopenharmony_ci * conditions for the write to take place. The actual masked qualifier (and 7768c2ecf20Sopenharmony_ci * other related details) are defined beforehand with _set_shuttle_features(). 7778c2ecf20Sopenharmony_ci */ 7788c2ecf20Sopenharmony_cistatic int usbat_write_blocks(struct us_data *us, 7798c2ecf20Sopenharmony_ci void* buffer, 7808c2ecf20Sopenharmony_ci int len, 7818c2ecf20Sopenharmony_ci int use_sg) 7828c2ecf20Sopenharmony_ci{ 7838c2ecf20Sopenharmony_ci int result; 7848c2ecf20Sopenharmony_ci unsigned char *command = us->iobuf; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci command[0] = 0x40; 7878c2ecf20Sopenharmony_ci command[1] = USBAT_ATA | USBAT_CMD_COND_WRITE_BLOCK; 7888c2ecf20Sopenharmony_ci command[2] = USBAT_ATA_DATA; 7898c2ecf20Sopenharmony_ci command[3] = USBAT_ATA_STATUS; 7908c2ecf20Sopenharmony_ci command[4] = 0xFD; /* Timeout (ms) */ 7918c2ecf20Sopenharmony_ci command[5] = USBAT_QUAL_FCQ; 7928c2ecf20Sopenharmony_ci command[6] = LSB_of(len); 7938c2ecf20Sopenharmony_ci command[7] = MSB_of(len); 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci /* Multiple block write setup command */ 7968c2ecf20Sopenharmony_ci result = usbat_execute_command(us, command, 8); 7978c2ecf20Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) 7988c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_FAILED; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci /* Write the data */ 8018c2ecf20Sopenharmony_ci result = usbat_bulk_write(us, buffer, len, use_sg); 8028c2ecf20Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) 8038c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_FAILED; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 8068c2ecf20Sopenharmony_ci} 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci/* 8098c2ecf20Sopenharmony_ci * Read the User IO register 8108c2ecf20Sopenharmony_ci */ 8118c2ecf20Sopenharmony_cistatic int usbat_read_user_io(struct us_data *us, unsigned char *data_flags) 8128c2ecf20Sopenharmony_ci{ 8138c2ecf20Sopenharmony_ci int result; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci result = usb_stor_ctrl_transfer(us, 8168c2ecf20Sopenharmony_ci us->recv_ctrl_pipe, 8178c2ecf20Sopenharmony_ci USBAT_CMD_UIO, 8188c2ecf20Sopenharmony_ci 0xC0, 8198c2ecf20Sopenharmony_ci 0, 8208c2ecf20Sopenharmony_ci 0, 8218c2ecf20Sopenharmony_ci data_flags, 8228c2ecf20Sopenharmony_ci USBAT_UIO_READ); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci usb_stor_dbg(us, "UIO register reads %02X\n", *data_flags); 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci return result; 8278c2ecf20Sopenharmony_ci} 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci/* 8308c2ecf20Sopenharmony_ci * Write to the User IO register 8318c2ecf20Sopenharmony_ci */ 8328c2ecf20Sopenharmony_cistatic int usbat_write_user_io(struct us_data *us, 8338c2ecf20Sopenharmony_ci unsigned char enable_flags, 8348c2ecf20Sopenharmony_ci unsigned char data_flags) 8358c2ecf20Sopenharmony_ci{ 8368c2ecf20Sopenharmony_ci return usb_stor_ctrl_transfer(us, 8378c2ecf20Sopenharmony_ci us->send_ctrl_pipe, 8388c2ecf20Sopenharmony_ci USBAT_CMD_UIO, 8398c2ecf20Sopenharmony_ci 0x40, 8408c2ecf20Sopenharmony_ci short_pack(enable_flags, data_flags), 8418c2ecf20Sopenharmony_ci 0, 8428c2ecf20Sopenharmony_ci NULL, 8438c2ecf20Sopenharmony_ci USBAT_UIO_WRITE); 8448c2ecf20Sopenharmony_ci} 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci/* 8478c2ecf20Sopenharmony_ci * Reset the device 8488c2ecf20Sopenharmony_ci * Often needed on media change. 8498c2ecf20Sopenharmony_ci */ 8508c2ecf20Sopenharmony_cistatic int usbat_device_reset(struct us_data *us) 8518c2ecf20Sopenharmony_ci{ 8528c2ecf20Sopenharmony_ci int rc; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci /* 8558c2ecf20Sopenharmony_ci * Reset peripheral, enable peripheral control signals 8568c2ecf20Sopenharmony_ci * (bring reset signal up) 8578c2ecf20Sopenharmony_ci */ 8588c2ecf20Sopenharmony_ci rc = usbat_write_user_io(us, 8598c2ecf20Sopenharmony_ci USBAT_UIO_DRVRST | USBAT_UIO_OE1 | USBAT_UIO_OE0, 8608c2ecf20Sopenharmony_ci USBAT_UIO_EPAD | USBAT_UIO_1); 8618c2ecf20Sopenharmony_ci if (rc != USB_STOR_XFER_GOOD) 8628c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci /* 8658c2ecf20Sopenharmony_ci * Enable peripheral control signals 8668c2ecf20Sopenharmony_ci * (bring reset signal down) 8678c2ecf20Sopenharmony_ci */ 8688c2ecf20Sopenharmony_ci rc = usbat_write_user_io(us, 8698c2ecf20Sopenharmony_ci USBAT_UIO_OE1 | USBAT_UIO_OE0, 8708c2ecf20Sopenharmony_ci USBAT_UIO_EPAD | USBAT_UIO_1); 8718c2ecf20Sopenharmony_ci if (rc != USB_STOR_XFER_GOOD) 8728c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 8758c2ecf20Sopenharmony_ci} 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci/* 8788c2ecf20Sopenharmony_ci * Enable card detect 8798c2ecf20Sopenharmony_ci */ 8808c2ecf20Sopenharmony_cistatic int usbat_device_enable_cdt(struct us_data *us) 8818c2ecf20Sopenharmony_ci{ 8828c2ecf20Sopenharmony_ci int rc; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci /* Enable peripheral control signals and card detect */ 8858c2ecf20Sopenharmony_ci rc = usbat_write_user_io(us, 8868c2ecf20Sopenharmony_ci USBAT_UIO_ACKD | USBAT_UIO_OE1 | USBAT_UIO_OE0, 8878c2ecf20Sopenharmony_ci USBAT_UIO_EPAD | USBAT_UIO_1); 8888c2ecf20Sopenharmony_ci if (rc != USB_STOR_XFER_GOOD) 8898c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 8928c2ecf20Sopenharmony_ci} 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci/* 8958c2ecf20Sopenharmony_ci * Determine if media is present. 8968c2ecf20Sopenharmony_ci */ 8978c2ecf20Sopenharmony_cistatic int usbat_flash_check_media_present(struct us_data *us, 8988c2ecf20Sopenharmony_ci unsigned char *uio) 8998c2ecf20Sopenharmony_ci{ 9008c2ecf20Sopenharmony_ci if (*uio & USBAT_UIO_UI0) { 9018c2ecf20Sopenharmony_ci usb_stor_dbg(us, "no media detected\n"); 9028c2ecf20Sopenharmony_ci return USBAT_FLASH_MEDIA_NONE; 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci return USBAT_FLASH_MEDIA_CF; 9068c2ecf20Sopenharmony_ci} 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci/* 9098c2ecf20Sopenharmony_ci * Determine if media has changed since last operation 9108c2ecf20Sopenharmony_ci */ 9118c2ecf20Sopenharmony_cistatic int usbat_flash_check_media_changed(struct us_data *us, 9128c2ecf20Sopenharmony_ci unsigned char *uio) 9138c2ecf20Sopenharmony_ci{ 9148c2ecf20Sopenharmony_ci if (*uio & USBAT_UIO_0) { 9158c2ecf20Sopenharmony_ci usb_stor_dbg(us, "media change detected\n"); 9168c2ecf20Sopenharmony_ci return USBAT_FLASH_MEDIA_CHANGED; 9178c2ecf20Sopenharmony_ci } 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci return USBAT_FLASH_MEDIA_SAME; 9208c2ecf20Sopenharmony_ci} 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci/* 9238c2ecf20Sopenharmony_ci * Check for media change / no media and handle the situation appropriately 9248c2ecf20Sopenharmony_ci */ 9258c2ecf20Sopenharmony_cistatic int usbat_flash_check_media(struct us_data *us, 9268c2ecf20Sopenharmony_ci struct usbat_info *info) 9278c2ecf20Sopenharmony_ci{ 9288c2ecf20Sopenharmony_ci int rc; 9298c2ecf20Sopenharmony_ci unsigned char *uio = us->iobuf; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci rc = usbat_read_user_io(us, uio); 9328c2ecf20Sopenharmony_ci if (rc != USB_STOR_XFER_GOOD) 9338c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci /* Check for media existence */ 9368c2ecf20Sopenharmony_ci rc = usbat_flash_check_media_present(us, uio); 9378c2ecf20Sopenharmony_ci if (rc == USBAT_FLASH_MEDIA_NONE) { 9388c2ecf20Sopenharmony_ci info->sense_key = 0x02; 9398c2ecf20Sopenharmony_ci info->sense_asc = 0x3A; 9408c2ecf20Sopenharmony_ci info->sense_ascq = 0x00; 9418c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_FAILED; 9428c2ecf20Sopenharmony_ci } 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci /* Check for media change */ 9458c2ecf20Sopenharmony_ci rc = usbat_flash_check_media_changed(us, uio); 9468c2ecf20Sopenharmony_ci if (rc == USBAT_FLASH_MEDIA_CHANGED) { 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci /* Reset and re-enable card detect */ 9498c2ecf20Sopenharmony_ci rc = usbat_device_reset(us); 9508c2ecf20Sopenharmony_ci if (rc != USB_STOR_TRANSPORT_GOOD) 9518c2ecf20Sopenharmony_ci return rc; 9528c2ecf20Sopenharmony_ci rc = usbat_device_enable_cdt(us); 9538c2ecf20Sopenharmony_ci if (rc != USB_STOR_TRANSPORT_GOOD) 9548c2ecf20Sopenharmony_ci return rc; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci msleep(50); 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci rc = usbat_read_user_io(us, uio); 9598c2ecf20Sopenharmony_ci if (rc != USB_STOR_XFER_GOOD) 9608c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci info->sense_key = UNIT_ATTENTION; 9638c2ecf20Sopenharmony_ci info->sense_asc = 0x28; 9648c2ecf20Sopenharmony_ci info->sense_ascq = 0x00; 9658c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_FAILED; 9668c2ecf20Sopenharmony_ci } 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 9698c2ecf20Sopenharmony_ci} 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci/* 9728c2ecf20Sopenharmony_ci * Determine whether we are controlling a flash-based reader/writer, 9738c2ecf20Sopenharmony_ci * or a HP8200-based CD drive. 9748c2ecf20Sopenharmony_ci * Sets transport functions as appropriate. 9758c2ecf20Sopenharmony_ci */ 9768c2ecf20Sopenharmony_cistatic int usbat_identify_device(struct us_data *us, 9778c2ecf20Sopenharmony_ci struct usbat_info *info) 9788c2ecf20Sopenharmony_ci{ 9798c2ecf20Sopenharmony_ci int rc; 9808c2ecf20Sopenharmony_ci unsigned char status; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci if (!us || !info) 9838c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci rc = usbat_device_reset(us); 9868c2ecf20Sopenharmony_ci if (rc != USB_STOR_TRANSPORT_GOOD) 9878c2ecf20Sopenharmony_ci return rc; 9888c2ecf20Sopenharmony_ci msleep(500); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci /* 9918c2ecf20Sopenharmony_ci * In attempt to distinguish between HP CDRW's and Flash readers, we now 9928c2ecf20Sopenharmony_ci * execute the IDENTIFY PACKET DEVICE command. On ATA devices (i.e. flash 9938c2ecf20Sopenharmony_ci * readers), this command should fail with error. On ATAPI devices (i.e. 9948c2ecf20Sopenharmony_ci * CDROM drives), it should succeed. 9958c2ecf20Sopenharmony_ci */ 9968c2ecf20Sopenharmony_ci rc = usbat_write(us, USBAT_ATA, USBAT_ATA_CMD, 0xA1); 9978c2ecf20Sopenharmony_ci if (rc != USB_STOR_XFER_GOOD) 9988c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci rc = usbat_get_status(us, &status); 10018c2ecf20Sopenharmony_ci if (rc != USB_STOR_XFER_GOOD) 10028c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci /* Check for error bit, or if the command 'fell through' */ 10058c2ecf20Sopenharmony_ci if (status == 0xA1 || !(status & 0x01)) { 10068c2ecf20Sopenharmony_ci /* Device is HP 8200 */ 10078c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Detected HP8200 CDRW\n"); 10088c2ecf20Sopenharmony_ci info->devicetype = USBAT_DEV_HP8200; 10098c2ecf20Sopenharmony_ci } else { 10108c2ecf20Sopenharmony_ci /* Device is a CompactFlash reader/writer */ 10118c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Detected Flash reader/writer\n"); 10128c2ecf20Sopenharmony_ci info->devicetype = USBAT_DEV_FLASH; 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 10168c2ecf20Sopenharmony_ci} 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci/* 10198c2ecf20Sopenharmony_ci * Set the transport function based on the device type 10208c2ecf20Sopenharmony_ci */ 10218c2ecf20Sopenharmony_cistatic int usbat_set_transport(struct us_data *us, 10228c2ecf20Sopenharmony_ci struct usbat_info *info, 10238c2ecf20Sopenharmony_ci int devicetype) 10248c2ecf20Sopenharmony_ci{ 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci if (!info->devicetype) 10278c2ecf20Sopenharmony_ci info->devicetype = devicetype; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci if (!info->devicetype) 10308c2ecf20Sopenharmony_ci usbat_identify_device(us, info); 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci switch (info->devicetype) { 10338c2ecf20Sopenharmony_ci default: 10348c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci case USBAT_DEV_HP8200: 10378c2ecf20Sopenharmony_ci us->transport = usbat_hp8200e_transport; 10388c2ecf20Sopenharmony_ci break; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci case USBAT_DEV_FLASH: 10418c2ecf20Sopenharmony_ci us->transport = usbat_flash_transport; 10428c2ecf20Sopenharmony_ci break; 10438c2ecf20Sopenharmony_ci } 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci return 0; 10468c2ecf20Sopenharmony_ci} 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci/* 10498c2ecf20Sopenharmony_ci * Read the media capacity 10508c2ecf20Sopenharmony_ci */ 10518c2ecf20Sopenharmony_cistatic int usbat_flash_get_sector_count(struct us_data *us, 10528c2ecf20Sopenharmony_ci struct usbat_info *info) 10538c2ecf20Sopenharmony_ci{ 10548c2ecf20Sopenharmony_ci unsigned char registers[3] = { 10558c2ecf20Sopenharmony_ci USBAT_ATA_SECCNT, 10568c2ecf20Sopenharmony_ci USBAT_ATA_DEVICE, 10578c2ecf20Sopenharmony_ci USBAT_ATA_CMD, 10588c2ecf20Sopenharmony_ci }; 10598c2ecf20Sopenharmony_ci unsigned char command[3] = { 0x01, 0xA0, 0xEC }; 10608c2ecf20Sopenharmony_ci unsigned char *reply; 10618c2ecf20Sopenharmony_ci unsigned char status; 10628c2ecf20Sopenharmony_ci int rc; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci if (!us || !info) 10658c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci reply = kmalloc(512, GFP_NOIO); 10688c2ecf20Sopenharmony_ci if (!reply) 10698c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci /* ATA command : IDENTIFY DEVICE */ 10728c2ecf20Sopenharmony_ci rc = usbat_multiple_write(us, registers, command, 3); 10738c2ecf20Sopenharmony_ci if (rc != USB_STOR_XFER_GOOD) { 10748c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Gah! identify_device failed\n"); 10758c2ecf20Sopenharmony_ci rc = USB_STOR_TRANSPORT_ERROR; 10768c2ecf20Sopenharmony_ci goto leave; 10778c2ecf20Sopenharmony_ci } 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci /* Read device status */ 10808c2ecf20Sopenharmony_ci if (usbat_get_status(us, &status) != USB_STOR_XFER_GOOD) { 10818c2ecf20Sopenharmony_ci rc = USB_STOR_TRANSPORT_ERROR; 10828c2ecf20Sopenharmony_ci goto leave; 10838c2ecf20Sopenharmony_ci } 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci msleep(100); 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci /* Read the device identification data */ 10888c2ecf20Sopenharmony_ci rc = usbat_read_block(us, reply, 512, 0); 10898c2ecf20Sopenharmony_ci if (rc != USB_STOR_TRANSPORT_GOOD) 10908c2ecf20Sopenharmony_ci goto leave; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci info->sectors = ((u32)(reply[117]) << 24) | 10938c2ecf20Sopenharmony_ci ((u32)(reply[116]) << 16) | 10948c2ecf20Sopenharmony_ci ((u32)(reply[115]) << 8) | 10958c2ecf20Sopenharmony_ci ((u32)(reply[114]) ); 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci rc = USB_STOR_TRANSPORT_GOOD; 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci leave: 11008c2ecf20Sopenharmony_ci kfree(reply); 11018c2ecf20Sopenharmony_ci return rc; 11028c2ecf20Sopenharmony_ci} 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci/* 11058c2ecf20Sopenharmony_ci * Read data from device 11068c2ecf20Sopenharmony_ci */ 11078c2ecf20Sopenharmony_cistatic int usbat_flash_read_data(struct us_data *us, 11088c2ecf20Sopenharmony_ci struct usbat_info *info, 11098c2ecf20Sopenharmony_ci u32 sector, 11108c2ecf20Sopenharmony_ci u32 sectors) 11118c2ecf20Sopenharmony_ci{ 11128c2ecf20Sopenharmony_ci unsigned char registers[7] = { 11138c2ecf20Sopenharmony_ci USBAT_ATA_FEATURES, 11148c2ecf20Sopenharmony_ci USBAT_ATA_SECCNT, 11158c2ecf20Sopenharmony_ci USBAT_ATA_SECNUM, 11168c2ecf20Sopenharmony_ci USBAT_ATA_LBA_ME, 11178c2ecf20Sopenharmony_ci USBAT_ATA_LBA_HI, 11188c2ecf20Sopenharmony_ci USBAT_ATA_DEVICE, 11198c2ecf20Sopenharmony_ci USBAT_ATA_STATUS, 11208c2ecf20Sopenharmony_ci }; 11218c2ecf20Sopenharmony_ci unsigned char command[7]; 11228c2ecf20Sopenharmony_ci unsigned char *buffer; 11238c2ecf20Sopenharmony_ci unsigned char thistime; 11248c2ecf20Sopenharmony_ci unsigned int totallen, alloclen; 11258c2ecf20Sopenharmony_ci int len, result; 11268c2ecf20Sopenharmony_ci unsigned int sg_offset = 0; 11278c2ecf20Sopenharmony_ci struct scatterlist *sg = NULL; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci result = usbat_flash_check_media(us, info); 11308c2ecf20Sopenharmony_ci if (result != USB_STOR_TRANSPORT_GOOD) 11318c2ecf20Sopenharmony_ci return result; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci /* 11348c2ecf20Sopenharmony_ci * we're working in LBA mode. according to the ATA spec, 11358c2ecf20Sopenharmony_ci * we can support up to 28-bit addressing. I don't know if Jumpshot 11368c2ecf20Sopenharmony_ci * supports beyond 24-bit addressing. It's kind of hard to test 11378c2ecf20Sopenharmony_ci * since it requires > 8GB CF card. 11388c2ecf20Sopenharmony_ci */ 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci if (sector > 0x0FFFFFFF) 11418c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci totallen = sectors * info->ssize; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci /* 11468c2ecf20Sopenharmony_ci * Since we don't read more than 64 KB at a time, we have to create 11478c2ecf20Sopenharmony_ci * a bounce buffer and move the data a piece at a time between the 11488c2ecf20Sopenharmony_ci * bounce buffer and the actual transfer buffer. 11498c2ecf20Sopenharmony_ci */ 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci alloclen = min(totallen, 65536u); 11528c2ecf20Sopenharmony_ci buffer = kmalloc(alloclen, GFP_NOIO); 11538c2ecf20Sopenharmony_ci if (buffer == NULL) 11548c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci do { 11578c2ecf20Sopenharmony_ci /* 11588c2ecf20Sopenharmony_ci * loop, never allocate or transfer more than 64k at once 11598c2ecf20Sopenharmony_ci * (min(128k, 255*info->ssize) is the real limit) 11608c2ecf20Sopenharmony_ci */ 11618c2ecf20Sopenharmony_ci len = min(totallen, alloclen); 11628c2ecf20Sopenharmony_ci thistime = (len / info->ssize) & 0xff; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci /* ATA command 0x20 (READ SECTORS) */ 11658c2ecf20Sopenharmony_ci usbat_pack_ata_sector_cmd(command, thistime, sector, 0x20); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci /* Write/execute ATA read command */ 11688c2ecf20Sopenharmony_ci result = usbat_multiple_write(us, registers, command, 7); 11698c2ecf20Sopenharmony_ci if (result != USB_STOR_TRANSPORT_GOOD) 11708c2ecf20Sopenharmony_ci goto leave; 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci /* Read the data we just requested */ 11738c2ecf20Sopenharmony_ci result = usbat_read_blocks(us, buffer, len, 0); 11748c2ecf20Sopenharmony_ci if (result != USB_STOR_TRANSPORT_GOOD) 11758c2ecf20Sopenharmony_ci goto leave; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci usb_stor_dbg(us, "%d bytes\n", len); 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci /* Store the data in the transfer buffer */ 11808c2ecf20Sopenharmony_ci usb_stor_access_xfer_buf(buffer, len, us->srb, 11818c2ecf20Sopenharmony_ci &sg, &sg_offset, TO_XFER_BUF); 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci sector += thistime; 11848c2ecf20Sopenharmony_ci totallen -= len; 11858c2ecf20Sopenharmony_ci } while (totallen > 0); 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci kfree(buffer); 11888c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_cileave: 11918c2ecf20Sopenharmony_ci kfree(buffer); 11928c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 11938c2ecf20Sopenharmony_ci} 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci/* 11968c2ecf20Sopenharmony_ci * Write data to device 11978c2ecf20Sopenharmony_ci */ 11988c2ecf20Sopenharmony_cistatic int usbat_flash_write_data(struct us_data *us, 11998c2ecf20Sopenharmony_ci struct usbat_info *info, 12008c2ecf20Sopenharmony_ci u32 sector, 12018c2ecf20Sopenharmony_ci u32 sectors) 12028c2ecf20Sopenharmony_ci{ 12038c2ecf20Sopenharmony_ci unsigned char registers[7] = { 12048c2ecf20Sopenharmony_ci USBAT_ATA_FEATURES, 12058c2ecf20Sopenharmony_ci USBAT_ATA_SECCNT, 12068c2ecf20Sopenharmony_ci USBAT_ATA_SECNUM, 12078c2ecf20Sopenharmony_ci USBAT_ATA_LBA_ME, 12088c2ecf20Sopenharmony_ci USBAT_ATA_LBA_HI, 12098c2ecf20Sopenharmony_ci USBAT_ATA_DEVICE, 12108c2ecf20Sopenharmony_ci USBAT_ATA_STATUS, 12118c2ecf20Sopenharmony_ci }; 12128c2ecf20Sopenharmony_ci unsigned char command[7]; 12138c2ecf20Sopenharmony_ci unsigned char *buffer; 12148c2ecf20Sopenharmony_ci unsigned char thistime; 12158c2ecf20Sopenharmony_ci unsigned int totallen, alloclen; 12168c2ecf20Sopenharmony_ci int len, result; 12178c2ecf20Sopenharmony_ci unsigned int sg_offset = 0; 12188c2ecf20Sopenharmony_ci struct scatterlist *sg = NULL; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci result = usbat_flash_check_media(us, info); 12218c2ecf20Sopenharmony_ci if (result != USB_STOR_TRANSPORT_GOOD) 12228c2ecf20Sopenharmony_ci return result; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci /* 12258c2ecf20Sopenharmony_ci * we're working in LBA mode. according to the ATA spec, 12268c2ecf20Sopenharmony_ci * we can support up to 28-bit addressing. I don't know if the device 12278c2ecf20Sopenharmony_ci * supports beyond 24-bit addressing. It's kind of hard to test 12288c2ecf20Sopenharmony_ci * since it requires > 8GB media. 12298c2ecf20Sopenharmony_ci */ 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci if (sector > 0x0FFFFFFF) 12328c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci totallen = sectors * info->ssize; 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci /* 12378c2ecf20Sopenharmony_ci * Since we don't write more than 64 KB at a time, we have to create 12388c2ecf20Sopenharmony_ci * a bounce buffer and move the data a piece at a time between the 12398c2ecf20Sopenharmony_ci * bounce buffer and the actual transfer buffer. 12408c2ecf20Sopenharmony_ci */ 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci alloclen = min(totallen, 65536u); 12438c2ecf20Sopenharmony_ci buffer = kmalloc(alloclen, GFP_NOIO); 12448c2ecf20Sopenharmony_ci if (buffer == NULL) 12458c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci do { 12488c2ecf20Sopenharmony_ci /* 12498c2ecf20Sopenharmony_ci * loop, never allocate or transfer more than 64k at once 12508c2ecf20Sopenharmony_ci * (min(128k, 255*info->ssize) is the real limit) 12518c2ecf20Sopenharmony_ci */ 12528c2ecf20Sopenharmony_ci len = min(totallen, alloclen); 12538c2ecf20Sopenharmony_ci thistime = (len / info->ssize) & 0xff; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci /* Get the data from the transfer buffer */ 12568c2ecf20Sopenharmony_ci usb_stor_access_xfer_buf(buffer, len, us->srb, 12578c2ecf20Sopenharmony_ci &sg, &sg_offset, FROM_XFER_BUF); 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci /* ATA command 0x30 (WRITE SECTORS) */ 12608c2ecf20Sopenharmony_ci usbat_pack_ata_sector_cmd(command, thistime, sector, 0x30); 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci /* Write/execute ATA write command */ 12638c2ecf20Sopenharmony_ci result = usbat_multiple_write(us, registers, command, 7); 12648c2ecf20Sopenharmony_ci if (result != USB_STOR_TRANSPORT_GOOD) 12658c2ecf20Sopenharmony_ci goto leave; 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci /* Write the data */ 12688c2ecf20Sopenharmony_ci result = usbat_write_blocks(us, buffer, len, 0); 12698c2ecf20Sopenharmony_ci if (result != USB_STOR_TRANSPORT_GOOD) 12708c2ecf20Sopenharmony_ci goto leave; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci sector += thistime; 12738c2ecf20Sopenharmony_ci totallen -= len; 12748c2ecf20Sopenharmony_ci } while (totallen > 0); 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci kfree(buffer); 12778c2ecf20Sopenharmony_ci return result; 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_cileave: 12808c2ecf20Sopenharmony_ci kfree(buffer); 12818c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 12828c2ecf20Sopenharmony_ci} 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci/* 12858c2ecf20Sopenharmony_ci * Squeeze a potentially huge (> 65535 byte) read10 command into 12868c2ecf20Sopenharmony_ci * a little ( <= 65535 byte) ATAPI pipe 12878c2ecf20Sopenharmony_ci */ 12888c2ecf20Sopenharmony_cistatic int usbat_hp8200e_handle_read10(struct us_data *us, 12898c2ecf20Sopenharmony_ci unsigned char *registers, 12908c2ecf20Sopenharmony_ci unsigned char *data, 12918c2ecf20Sopenharmony_ci struct scsi_cmnd *srb) 12928c2ecf20Sopenharmony_ci{ 12938c2ecf20Sopenharmony_ci int result = USB_STOR_TRANSPORT_GOOD; 12948c2ecf20Sopenharmony_ci unsigned char *buffer; 12958c2ecf20Sopenharmony_ci unsigned int len; 12968c2ecf20Sopenharmony_ci unsigned int sector; 12978c2ecf20Sopenharmony_ci unsigned int sg_offset = 0; 12988c2ecf20Sopenharmony_ci struct scatterlist *sg = NULL; 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci usb_stor_dbg(us, "transfersize %d\n", srb->transfersize); 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci if (scsi_bufflen(srb) < 0x10000) { 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci result = usbat_hp8200e_rw_block_test(us, USBAT_ATA, 13058c2ecf20Sopenharmony_ci registers, data, 19, 13068c2ecf20Sopenharmony_ci USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD, 13078c2ecf20Sopenharmony_ci (USBAT_QUAL_FCQ | USBAT_QUAL_ALQ), 13088c2ecf20Sopenharmony_ci DMA_FROM_DEVICE, 13098c2ecf20Sopenharmony_ci scsi_sglist(srb), 13108c2ecf20Sopenharmony_ci scsi_bufflen(srb), scsi_sg_count(srb), 1); 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci return result; 13138c2ecf20Sopenharmony_ci } 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci /* 13168c2ecf20Sopenharmony_ci * Since we're requesting more data than we can handle in 13178c2ecf20Sopenharmony_ci * a single read command (max is 64k-1), we will perform 13188c2ecf20Sopenharmony_ci * multiple reads, but each read must be in multiples of 13198c2ecf20Sopenharmony_ci * a sector. Luckily the sector size is in srb->transfersize 13208c2ecf20Sopenharmony_ci * (see linux/drivers/scsi/sr.c). 13218c2ecf20Sopenharmony_ci */ 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci if (data[7+0] == GPCMD_READ_CD) { 13248c2ecf20Sopenharmony_ci len = short_pack(data[7+9], data[7+8]); 13258c2ecf20Sopenharmony_ci len <<= 16; 13268c2ecf20Sopenharmony_ci len |= data[7+7]; 13278c2ecf20Sopenharmony_ci usb_stor_dbg(us, "GPCMD_READ_CD: len %d\n", len); 13288c2ecf20Sopenharmony_ci srb->transfersize = scsi_bufflen(srb)/len; 13298c2ecf20Sopenharmony_ci } 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci if (!srb->transfersize) { 13328c2ecf20Sopenharmony_ci srb->transfersize = 2048; /* A guess */ 13338c2ecf20Sopenharmony_ci usb_stor_dbg(us, "transfersize 0, forcing %d\n", 13348c2ecf20Sopenharmony_ci srb->transfersize); 13358c2ecf20Sopenharmony_ci } 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci /* 13388c2ecf20Sopenharmony_ci * Since we only read in one block at a time, we have to create 13398c2ecf20Sopenharmony_ci * a bounce buffer and move the data a piece at a time between the 13408c2ecf20Sopenharmony_ci * bounce buffer and the actual transfer buffer. 13418c2ecf20Sopenharmony_ci */ 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci len = (65535/srb->transfersize) * srb->transfersize; 13448c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Max read is %d bytes\n", len); 13458c2ecf20Sopenharmony_ci len = min(len, scsi_bufflen(srb)); 13468c2ecf20Sopenharmony_ci buffer = kmalloc(len, GFP_NOIO); 13478c2ecf20Sopenharmony_ci if (buffer == NULL) /* bloody hell! */ 13488c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_FAILED; 13498c2ecf20Sopenharmony_ci sector = short_pack(data[7+3], data[7+2]); 13508c2ecf20Sopenharmony_ci sector <<= 16; 13518c2ecf20Sopenharmony_ci sector |= short_pack(data[7+5], data[7+4]); 13528c2ecf20Sopenharmony_ci transferred = 0; 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci while (transferred != scsi_bufflen(srb)) { 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci if (len > scsi_bufflen(srb) - transferred) 13578c2ecf20Sopenharmony_ci len = scsi_bufflen(srb) - transferred; 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci data[3] = len&0xFF; /* (cylL) = expected length (L) */ 13608c2ecf20Sopenharmony_ci data[4] = (len>>8)&0xFF; /* (cylH) = expected length (H) */ 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci /* Fix up the SCSI command sector and num sectors */ 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci data[7+2] = MSB_of(sector>>16); /* SCSI command sector */ 13658c2ecf20Sopenharmony_ci data[7+3] = LSB_of(sector>>16); 13668c2ecf20Sopenharmony_ci data[7+4] = MSB_of(sector&0xFFFF); 13678c2ecf20Sopenharmony_ci data[7+5] = LSB_of(sector&0xFFFF); 13688c2ecf20Sopenharmony_ci if (data[7+0] == GPCMD_READ_CD) 13698c2ecf20Sopenharmony_ci data[7+6] = 0; 13708c2ecf20Sopenharmony_ci data[7+7] = MSB_of(len / srb->transfersize); /* SCSI command */ 13718c2ecf20Sopenharmony_ci data[7+8] = LSB_of(len / srb->transfersize); /* num sectors */ 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci result = usbat_hp8200e_rw_block_test(us, USBAT_ATA, 13748c2ecf20Sopenharmony_ci registers, data, 19, 13758c2ecf20Sopenharmony_ci USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD, 13768c2ecf20Sopenharmony_ci (USBAT_QUAL_FCQ | USBAT_QUAL_ALQ), 13778c2ecf20Sopenharmony_ci DMA_FROM_DEVICE, 13788c2ecf20Sopenharmony_ci buffer, 13798c2ecf20Sopenharmony_ci len, 0, 1); 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci if (result != USB_STOR_TRANSPORT_GOOD) 13828c2ecf20Sopenharmony_ci break; 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci /* Store the data in the transfer buffer */ 13858c2ecf20Sopenharmony_ci usb_stor_access_xfer_buf(buffer, len, srb, 13868c2ecf20Sopenharmony_ci &sg, &sg_offset, TO_XFER_BUF); 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci /* Update the amount transferred and the sector number */ 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci transferred += len; 13918c2ecf20Sopenharmony_ci sector += len / srb->transfersize; 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci } /* while transferred != scsi_bufflen(srb) */ 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci kfree(buffer); 13968c2ecf20Sopenharmony_ci return result; 13978c2ecf20Sopenharmony_ci} 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_cistatic int usbat_select_and_test_registers(struct us_data *us) 14008c2ecf20Sopenharmony_ci{ 14018c2ecf20Sopenharmony_ci int selector; 14028c2ecf20Sopenharmony_ci unsigned char *status = us->iobuf; 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci /* try device = master, then device = slave. */ 14058c2ecf20Sopenharmony_ci for (selector = 0xA0; selector <= 0xB0; selector += 0x10) { 14068c2ecf20Sopenharmony_ci if (usbat_write(us, USBAT_ATA, USBAT_ATA_DEVICE, selector) != 14078c2ecf20Sopenharmony_ci USB_STOR_XFER_GOOD) 14088c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci if (usbat_read(us, USBAT_ATA, USBAT_ATA_STATUS, status) != 14118c2ecf20Sopenharmony_ci USB_STOR_XFER_GOOD) 14128c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci if (usbat_read(us, USBAT_ATA, USBAT_ATA_DEVICE, status) != 14158c2ecf20Sopenharmony_ci USB_STOR_XFER_GOOD) 14168c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) != 14198c2ecf20Sopenharmony_ci USB_STOR_XFER_GOOD) 14208c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_HI, status) != 14238c2ecf20Sopenharmony_ci USB_STOR_XFER_GOOD) 14248c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci if (usbat_write(us, USBAT_ATA, USBAT_ATA_LBA_ME, 0x55) != 14278c2ecf20Sopenharmony_ci USB_STOR_XFER_GOOD) 14288c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci if (usbat_write(us, USBAT_ATA, USBAT_ATA_LBA_HI, 0xAA) != 14318c2ecf20Sopenharmony_ci USB_STOR_XFER_GOOD) 14328c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) != 14358c2ecf20Sopenharmony_ci USB_STOR_XFER_GOOD) 14368c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) != 14398c2ecf20Sopenharmony_ci USB_STOR_XFER_GOOD) 14408c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 14418c2ecf20Sopenharmony_ci } 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 14448c2ecf20Sopenharmony_ci} 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci/* 14478c2ecf20Sopenharmony_ci * Initialize the USBAT processor and the storage device 14488c2ecf20Sopenharmony_ci */ 14498c2ecf20Sopenharmony_cistatic int init_usbat(struct us_data *us, int devicetype) 14508c2ecf20Sopenharmony_ci{ 14518c2ecf20Sopenharmony_ci int rc; 14528c2ecf20Sopenharmony_ci struct usbat_info *info; 14538c2ecf20Sopenharmony_ci unsigned char subcountH = USBAT_ATA_LBA_HI; 14548c2ecf20Sopenharmony_ci unsigned char subcountL = USBAT_ATA_LBA_ME; 14558c2ecf20Sopenharmony_ci unsigned char *status = us->iobuf; 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci us->extra = kzalloc(sizeof(struct usbat_info), GFP_NOIO); 14588c2ecf20Sopenharmony_ci if (!us->extra) 14598c2ecf20Sopenharmony_ci return 1; 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci info = (struct usbat_info *) (us->extra); 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci /* Enable peripheral control signals */ 14648c2ecf20Sopenharmony_ci rc = usbat_write_user_io(us, 14658c2ecf20Sopenharmony_ci USBAT_UIO_OE1 | USBAT_UIO_OE0, 14668c2ecf20Sopenharmony_ci USBAT_UIO_EPAD | USBAT_UIO_1); 14678c2ecf20Sopenharmony_ci if (rc != USB_STOR_XFER_GOOD) 14688c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci usb_stor_dbg(us, "INIT 1\n"); 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci msleep(2000); 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci rc = usbat_read_user_io(us, status); 14758c2ecf20Sopenharmony_ci if (rc != USB_STOR_TRANSPORT_GOOD) 14768c2ecf20Sopenharmony_ci return rc; 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci usb_stor_dbg(us, "INIT 2\n"); 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci rc = usbat_read_user_io(us, status); 14818c2ecf20Sopenharmony_ci if (rc != USB_STOR_XFER_GOOD) 14828c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci rc = usbat_read_user_io(us, status); 14858c2ecf20Sopenharmony_ci if (rc != USB_STOR_XFER_GOOD) 14868c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci usb_stor_dbg(us, "INIT 3\n"); 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci rc = usbat_select_and_test_registers(us); 14918c2ecf20Sopenharmony_ci if (rc != USB_STOR_TRANSPORT_GOOD) 14928c2ecf20Sopenharmony_ci return rc; 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci usb_stor_dbg(us, "INIT 4\n"); 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci rc = usbat_read_user_io(us, status); 14978c2ecf20Sopenharmony_ci if (rc != USB_STOR_XFER_GOOD) 14988c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci usb_stor_dbg(us, "INIT 5\n"); 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci /* Enable peripheral control signals and card detect */ 15038c2ecf20Sopenharmony_ci rc = usbat_device_enable_cdt(us); 15048c2ecf20Sopenharmony_ci if (rc != USB_STOR_TRANSPORT_GOOD) 15058c2ecf20Sopenharmony_ci return rc; 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci usb_stor_dbg(us, "INIT 6\n"); 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci rc = usbat_read_user_io(us, status); 15108c2ecf20Sopenharmony_ci if (rc != USB_STOR_XFER_GOOD) 15118c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci usb_stor_dbg(us, "INIT 7\n"); 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci msleep(1400); 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci rc = usbat_read_user_io(us, status); 15188c2ecf20Sopenharmony_ci if (rc != USB_STOR_XFER_GOOD) 15198c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci usb_stor_dbg(us, "INIT 8\n"); 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci rc = usbat_select_and_test_registers(us); 15248c2ecf20Sopenharmony_ci if (rc != USB_STOR_TRANSPORT_GOOD) 15258c2ecf20Sopenharmony_ci return rc; 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci usb_stor_dbg(us, "INIT 9\n"); 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci /* At this point, we need to detect which device we are using */ 15308c2ecf20Sopenharmony_ci if (usbat_set_transport(us, info, devicetype)) 15318c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci usb_stor_dbg(us, "INIT 10\n"); 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci if (usbat_get_device_type(us) == USBAT_DEV_FLASH) { 15368c2ecf20Sopenharmony_ci subcountH = 0x02; 15378c2ecf20Sopenharmony_ci subcountL = 0x00; 15388c2ecf20Sopenharmony_ci } 15398c2ecf20Sopenharmony_ci rc = usbat_set_shuttle_features(us, (USBAT_FEAT_ETEN | USBAT_FEAT_ET2 | USBAT_FEAT_ET1), 15408c2ecf20Sopenharmony_ci 0x00, 0x88, 0x08, subcountH, subcountL); 15418c2ecf20Sopenharmony_ci if (rc != USB_STOR_XFER_GOOD) 15428c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci usb_stor_dbg(us, "INIT 11\n"); 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 15478c2ecf20Sopenharmony_ci} 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci/* 15508c2ecf20Sopenharmony_ci * Transport for the HP 8200e 15518c2ecf20Sopenharmony_ci */ 15528c2ecf20Sopenharmony_cistatic int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us) 15538c2ecf20Sopenharmony_ci{ 15548c2ecf20Sopenharmony_ci int result; 15558c2ecf20Sopenharmony_ci unsigned char *status = us->iobuf; 15568c2ecf20Sopenharmony_ci unsigned char registers[32]; 15578c2ecf20Sopenharmony_ci unsigned char data[32]; 15588c2ecf20Sopenharmony_ci unsigned int len; 15598c2ecf20Sopenharmony_ci int i; 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci len = scsi_bufflen(srb); 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci /* 15648c2ecf20Sopenharmony_ci * Send A0 (ATA PACKET COMMAND). 15658c2ecf20Sopenharmony_ci * Note: I guess we're never going to get any of the ATA 15668c2ecf20Sopenharmony_ci * commands... just ATA Packet Commands. 15678c2ecf20Sopenharmony_ci */ 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci registers[0] = USBAT_ATA_FEATURES; 15708c2ecf20Sopenharmony_ci registers[1] = USBAT_ATA_SECCNT; 15718c2ecf20Sopenharmony_ci registers[2] = USBAT_ATA_SECNUM; 15728c2ecf20Sopenharmony_ci registers[3] = USBAT_ATA_LBA_ME; 15738c2ecf20Sopenharmony_ci registers[4] = USBAT_ATA_LBA_HI; 15748c2ecf20Sopenharmony_ci registers[5] = USBAT_ATA_DEVICE; 15758c2ecf20Sopenharmony_ci registers[6] = USBAT_ATA_CMD; 15768c2ecf20Sopenharmony_ci data[0] = 0x00; 15778c2ecf20Sopenharmony_ci data[1] = 0x00; 15788c2ecf20Sopenharmony_ci data[2] = 0x00; 15798c2ecf20Sopenharmony_ci data[3] = len&0xFF; /* (cylL) = expected length (L) */ 15808c2ecf20Sopenharmony_ci data[4] = (len>>8)&0xFF; /* (cylH) = expected length (H) */ 15818c2ecf20Sopenharmony_ci data[5] = 0xB0; /* (device sel) = slave */ 15828c2ecf20Sopenharmony_ci data[6] = 0xA0; /* (command) = ATA PACKET COMMAND */ 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci for (i=7; i<19; i++) { 15858c2ecf20Sopenharmony_ci registers[i] = 0x10; 15868c2ecf20Sopenharmony_ci data[i] = (i-7 >= srb->cmd_len) ? 0 : srb->cmnd[i-7]; 15878c2ecf20Sopenharmony_ci } 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci result = usbat_get_status(us, status); 15908c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Status = %02X\n", *status); 15918c2ecf20Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) 15928c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 15938c2ecf20Sopenharmony_ci if (srb->cmnd[0] == TEST_UNIT_READY) 15948c2ecf20Sopenharmony_ci transferred = 0; 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci if (srb->sc_data_direction == DMA_TO_DEVICE) { 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci result = usbat_hp8200e_rw_block_test(us, USBAT_ATA, 15998c2ecf20Sopenharmony_ci registers, data, 19, 16008c2ecf20Sopenharmony_ci USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD, 16018c2ecf20Sopenharmony_ci (USBAT_QUAL_FCQ | USBAT_QUAL_ALQ), 16028c2ecf20Sopenharmony_ci DMA_TO_DEVICE, 16038c2ecf20Sopenharmony_ci scsi_sglist(srb), 16048c2ecf20Sopenharmony_ci len, scsi_sg_count(srb), 10); 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci if (result == USB_STOR_TRANSPORT_GOOD) { 16078c2ecf20Sopenharmony_ci transferred += len; 16088c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Wrote %08X bytes\n", transferred); 16098c2ecf20Sopenharmony_ci } 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci return result; 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci } else if (srb->cmnd[0] == READ_10 || 16148c2ecf20Sopenharmony_ci srb->cmnd[0] == GPCMD_READ_CD) { 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci return usbat_hp8200e_handle_read10(us, registers, data, srb); 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ci } 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci if (len > 0xFFFF) { 16218c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Error: len = %08X... what do I do now?\n", 16228c2ecf20Sopenharmony_ci len); 16238c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 16248c2ecf20Sopenharmony_ci } 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci result = usbat_multiple_write(us, registers, data, 7); 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci if (result != USB_STOR_TRANSPORT_GOOD) 16298c2ecf20Sopenharmony_ci return result; 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci /* 16328c2ecf20Sopenharmony_ci * Write the 12-byte command header. 16338c2ecf20Sopenharmony_ci * 16348c2ecf20Sopenharmony_ci * If the command is BLANK then set the timer for 75 minutes. 16358c2ecf20Sopenharmony_ci * Otherwise set it for 10 minutes. 16368c2ecf20Sopenharmony_ci * 16378c2ecf20Sopenharmony_ci * NOTE: THE 8200 DOCUMENTATION STATES THAT BLANKING A CDRW 16388c2ecf20Sopenharmony_ci * AT SPEED 4 IS UNRELIABLE!!! 16398c2ecf20Sopenharmony_ci */ 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci result = usbat_write_block(us, USBAT_ATA, srb->cmnd, 12, 16428c2ecf20Sopenharmony_ci srb->cmnd[0] == GPCMD_BLANK ? 75 : 10, 0); 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci if (result != USB_STOR_TRANSPORT_GOOD) 16458c2ecf20Sopenharmony_ci return result; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci /* If there is response data to be read in then do it here. */ 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci if (len != 0 && (srb->sc_data_direction == DMA_FROM_DEVICE)) { 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci /* How many bytes to read in? Check cylL register */ 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) != 16548c2ecf20Sopenharmony_ci USB_STOR_XFER_GOOD) { 16558c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 16568c2ecf20Sopenharmony_ci } 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci if (len > 0xFF) { /* need to read cylH also */ 16598c2ecf20Sopenharmony_ci len = *status; 16608c2ecf20Sopenharmony_ci if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_HI, status) != 16618c2ecf20Sopenharmony_ci USB_STOR_XFER_GOOD) { 16628c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 16638c2ecf20Sopenharmony_ci } 16648c2ecf20Sopenharmony_ci len += ((unsigned int) *status)<<8; 16658c2ecf20Sopenharmony_ci } 16668c2ecf20Sopenharmony_ci else 16678c2ecf20Sopenharmony_ci len = *status; 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci result = usbat_read_block(us, scsi_sglist(srb), len, 16718c2ecf20Sopenharmony_ci scsi_sg_count(srb)); 16728c2ecf20Sopenharmony_ci } 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci return result; 16758c2ecf20Sopenharmony_ci} 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci/* 16788c2ecf20Sopenharmony_ci * Transport for USBAT02-based CompactFlash and similar storage devices 16798c2ecf20Sopenharmony_ci */ 16808c2ecf20Sopenharmony_cistatic int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us) 16818c2ecf20Sopenharmony_ci{ 16828c2ecf20Sopenharmony_ci int rc; 16838c2ecf20Sopenharmony_ci struct usbat_info *info = (struct usbat_info *) (us->extra); 16848c2ecf20Sopenharmony_ci unsigned long block, blocks; 16858c2ecf20Sopenharmony_ci unsigned char *ptr = us->iobuf; 16868c2ecf20Sopenharmony_ci static unsigned char inquiry_response[36] = { 16878c2ecf20Sopenharmony_ci 0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00 16888c2ecf20Sopenharmony_ci }; 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci if (srb->cmnd[0] == INQUIRY) { 16918c2ecf20Sopenharmony_ci usb_stor_dbg(us, "INQUIRY - Returning bogus response\n"); 16928c2ecf20Sopenharmony_ci memcpy(ptr, inquiry_response, sizeof(inquiry_response)); 16938c2ecf20Sopenharmony_ci fill_inquiry_response(us, ptr, 36); 16948c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 16958c2ecf20Sopenharmony_ci } 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci if (srb->cmnd[0] == READ_CAPACITY) { 16988c2ecf20Sopenharmony_ci rc = usbat_flash_check_media(us, info); 16998c2ecf20Sopenharmony_ci if (rc != USB_STOR_TRANSPORT_GOOD) 17008c2ecf20Sopenharmony_ci return rc; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci rc = usbat_flash_get_sector_count(us, info); 17038c2ecf20Sopenharmony_ci if (rc != USB_STOR_TRANSPORT_GOOD) 17048c2ecf20Sopenharmony_ci return rc; 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci /* hard coded 512 byte sectors as per ATA spec */ 17078c2ecf20Sopenharmony_ci info->ssize = 0x200; 17088c2ecf20Sopenharmony_ci usb_stor_dbg(us, "READ_CAPACITY: %ld sectors, %ld bytes per sector\n", 17098c2ecf20Sopenharmony_ci info->sectors, info->ssize); 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci /* 17128c2ecf20Sopenharmony_ci * build the reply 17138c2ecf20Sopenharmony_ci * note: must return the sector number of the last sector, 17148c2ecf20Sopenharmony_ci * *not* the total number of sectors 17158c2ecf20Sopenharmony_ci */ 17168c2ecf20Sopenharmony_ci ((__be32 *) ptr)[0] = cpu_to_be32(info->sectors - 1); 17178c2ecf20Sopenharmony_ci ((__be32 *) ptr)[1] = cpu_to_be32(info->ssize); 17188c2ecf20Sopenharmony_ci usb_stor_set_xfer_buf(ptr, 8, srb); 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 17218c2ecf20Sopenharmony_ci } 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci if (srb->cmnd[0] == MODE_SELECT_10) { 17248c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Gah! MODE_SELECT_10\n"); 17258c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 17268c2ecf20Sopenharmony_ci } 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci if (srb->cmnd[0] == READ_10) { 17298c2ecf20Sopenharmony_ci block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | 17308c2ecf20Sopenharmony_ci ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci usb_stor_dbg(us, "READ_10: read block 0x%04lx count %ld\n", 17358c2ecf20Sopenharmony_ci block, blocks); 17368c2ecf20Sopenharmony_ci return usbat_flash_read_data(us, info, block, blocks); 17378c2ecf20Sopenharmony_ci } 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci if (srb->cmnd[0] == READ_12) { 17408c2ecf20Sopenharmony_ci /* 17418c2ecf20Sopenharmony_ci * I don't think we'll ever see a READ_12 but support it anyway 17428c2ecf20Sopenharmony_ci */ 17438c2ecf20Sopenharmony_ci block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | 17448c2ecf20Sopenharmony_ci ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) | 17478c2ecf20Sopenharmony_ci ((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9])); 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci usb_stor_dbg(us, "READ_12: read block 0x%04lx count %ld\n", 17508c2ecf20Sopenharmony_ci block, blocks); 17518c2ecf20Sopenharmony_ci return usbat_flash_read_data(us, info, block, blocks); 17528c2ecf20Sopenharmony_ci } 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci if (srb->cmnd[0] == WRITE_10) { 17558c2ecf20Sopenharmony_ci block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | 17568c2ecf20Sopenharmony_ci ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci usb_stor_dbg(us, "WRITE_10: write block 0x%04lx count %ld\n", 17618c2ecf20Sopenharmony_ci block, blocks); 17628c2ecf20Sopenharmony_ci return usbat_flash_write_data(us, info, block, blocks); 17638c2ecf20Sopenharmony_ci } 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci if (srb->cmnd[0] == WRITE_12) { 17668c2ecf20Sopenharmony_ci /* 17678c2ecf20Sopenharmony_ci * I don't think we'll ever see a WRITE_12 but support it anyway 17688c2ecf20Sopenharmony_ci */ 17698c2ecf20Sopenharmony_ci block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | 17708c2ecf20Sopenharmony_ci ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) | 17738c2ecf20Sopenharmony_ci ((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9])); 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci usb_stor_dbg(us, "WRITE_12: write block 0x%04lx count %ld\n", 17768c2ecf20Sopenharmony_ci block, blocks); 17778c2ecf20Sopenharmony_ci return usbat_flash_write_data(us, info, block, blocks); 17788c2ecf20Sopenharmony_ci } 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci if (srb->cmnd[0] == TEST_UNIT_READY) { 17828c2ecf20Sopenharmony_ci usb_stor_dbg(us, "TEST_UNIT_READY\n"); 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci rc = usbat_flash_check_media(us, info); 17858c2ecf20Sopenharmony_ci if (rc != USB_STOR_TRANSPORT_GOOD) 17868c2ecf20Sopenharmony_ci return rc; 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci return usbat_check_status(us); 17898c2ecf20Sopenharmony_ci } 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci if (srb->cmnd[0] == REQUEST_SENSE) { 17928c2ecf20Sopenharmony_ci usb_stor_dbg(us, "REQUEST_SENSE\n"); 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci memset(ptr, 0, 18); 17958c2ecf20Sopenharmony_ci ptr[0] = 0xF0; 17968c2ecf20Sopenharmony_ci ptr[2] = info->sense_key; 17978c2ecf20Sopenharmony_ci ptr[7] = 11; 17988c2ecf20Sopenharmony_ci ptr[12] = info->sense_asc; 17998c2ecf20Sopenharmony_ci ptr[13] = info->sense_ascq; 18008c2ecf20Sopenharmony_ci usb_stor_set_xfer_buf(ptr, 18, srb); 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 18038c2ecf20Sopenharmony_ci } 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { 18068c2ecf20Sopenharmony_ci /* 18078c2ecf20Sopenharmony_ci * sure. whatever. not like we can stop the user from popping 18088c2ecf20Sopenharmony_ci * the media out of the device (no locking doors, etc) 18098c2ecf20Sopenharmony_ci */ 18108c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 18118c2ecf20Sopenharmony_ci } 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Gah! Unknown command: %d (0x%x)\n", 18148c2ecf20Sopenharmony_ci srb->cmnd[0], srb->cmnd[0]); 18158c2ecf20Sopenharmony_ci info->sense_key = 0x05; 18168c2ecf20Sopenharmony_ci info->sense_asc = 0x20; 18178c2ecf20Sopenharmony_ci info->sense_ascq = 0x00; 18188c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_FAILED; 18198c2ecf20Sopenharmony_ci} 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_cistatic int init_usbat_cd(struct us_data *us) 18228c2ecf20Sopenharmony_ci{ 18238c2ecf20Sopenharmony_ci return init_usbat(us, USBAT_DEV_HP8200); 18248c2ecf20Sopenharmony_ci} 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_cistatic int init_usbat_flash(struct us_data *us) 18278c2ecf20Sopenharmony_ci{ 18288c2ecf20Sopenharmony_ci return init_usbat(us, USBAT_DEV_FLASH); 18298c2ecf20Sopenharmony_ci} 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_cistatic struct scsi_host_template usbat_host_template; 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_cistatic int usbat_probe(struct usb_interface *intf, 18348c2ecf20Sopenharmony_ci const struct usb_device_id *id) 18358c2ecf20Sopenharmony_ci{ 18368c2ecf20Sopenharmony_ci struct us_data *us; 18378c2ecf20Sopenharmony_ci int result; 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci result = usb_stor_probe1(&us, intf, id, 18408c2ecf20Sopenharmony_ci (id - usbat_usb_ids) + usbat_unusual_dev_list, 18418c2ecf20Sopenharmony_ci &usbat_host_template); 18428c2ecf20Sopenharmony_ci if (result) 18438c2ecf20Sopenharmony_ci return result; 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci /* 18468c2ecf20Sopenharmony_ci * The actual transport will be determined later by the 18478c2ecf20Sopenharmony_ci * initialization routine; this is just a placeholder. 18488c2ecf20Sopenharmony_ci */ 18498c2ecf20Sopenharmony_ci us->transport_name = "Shuttle USBAT"; 18508c2ecf20Sopenharmony_ci us->transport = usbat_flash_transport; 18518c2ecf20Sopenharmony_ci us->transport_reset = usb_stor_CB_reset; 18528c2ecf20Sopenharmony_ci us->max_lun = 0; 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci result = usb_stor_probe2(us); 18558c2ecf20Sopenharmony_ci return result; 18568c2ecf20Sopenharmony_ci} 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_cistatic struct usb_driver usbat_driver = { 18598c2ecf20Sopenharmony_ci .name = DRV_NAME, 18608c2ecf20Sopenharmony_ci .probe = usbat_probe, 18618c2ecf20Sopenharmony_ci .disconnect = usb_stor_disconnect, 18628c2ecf20Sopenharmony_ci .suspend = usb_stor_suspend, 18638c2ecf20Sopenharmony_ci .resume = usb_stor_resume, 18648c2ecf20Sopenharmony_ci .reset_resume = usb_stor_reset_resume, 18658c2ecf20Sopenharmony_ci .pre_reset = usb_stor_pre_reset, 18668c2ecf20Sopenharmony_ci .post_reset = usb_stor_post_reset, 18678c2ecf20Sopenharmony_ci .id_table = usbat_usb_ids, 18688c2ecf20Sopenharmony_ci .soft_unbind = 1, 18698c2ecf20Sopenharmony_ci .no_dynamic_id = 1, 18708c2ecf20Sopenharmony_ci}; 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_cimodule_usb_stor_driver(usbat_driver, usbat_host_template, DRV_NAME); 1873