18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Transport & Protocol Driver for In-System Design, Inc. ISD200 ASIC 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Current development and maintenance: 68c2ecf20Sopenharmony_ci * (C) 2001-2002 Björn Stenberg (bjorn@haxx.se) 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Developed with the assistance of: 98c2ecf20Sopenharmony_ci * (C) 2002 Alan Stern <stern@rowland.org> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Initial work: 128c2ecf20Sopenharmony_ci * (C) 2000 In-System Design, Inc. (support@in-system.com) 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * The ISD200 ASIC does not natively support ATA devices. The chip 158c2ecf20Sopenharmony_ci * does implement an interface, the ATA Command Block (ATACB) which provides 168c2ecf20Sopenharmony_ci * a means of passing ATA commands and ATA register accesses to a device. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * History: 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * 2002-10-19: Removed the specialized transfer routines. 218c2ecf20Sopenharmony_ci * (Alan Stern <stern@rowland.harvard.edu>) 228c2ecf20Sopenharmony_ci * 2001-02-24: Removed lots of duplicate code and simplified the structure. 238c2ecf20Sopenharmony_ci * (bjorn@haxx.se) 248c2ecf20Sopenharmony_ci * 2002-01-16: Fixed endianness bug so it works on the ppc arch. 258c2ecf20Sopenharmony_ci * (Luc Saillard <luc@saillard.org>) 268c2ecf20Sopenharmony_ci * 2002-01-17: All bitfields removed. 278c2ecf20Sopenharmony_ci * (bjorn@haxx.se) 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* Include files */ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 348c2ecf20Sopenharmony_ci#include <linux/errno.h> 358c2ecf20Sopenharmony_ci#include <linux/module.h> 368c2ecf20Sopenharmony_ci#include <linux/slab.h> 378c2ecf20Sopenharmony_ci#include <linux/ata.h> 388c2ecf20Sopenharmony_ci#include <linux/hdreg.h> 398c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 428c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 438c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h> 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#include "usb.h" 468c2ecf20Sopenharmony_ci#include "transport.h" 478c2ecf20Sopenharmony_ci#include "protocol.h" 488c2ecf20Sopenharmony_ci#include "debug.h" 498c2ecf20Sopenharmony_ci#include "scsiglue.h" 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define DRV_NAME "ums-isd200" 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Driver for In-System Design, Inc. ISD200 ASIC"); 548c2ecf20Sopenharmony_ciMODULE_AUTHOR("Björn Stenberg <bjorn@haxx.se>"); 558c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 568c2ecf20Sopenharmony_ciMODULE_IMPORT_NS(USB_STORAGE); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic int isd200_Initialization(struct us_data *us); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* 628c2ecf20Sopenharmony_ci * The table of devices 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_ci#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ 658c2ecf20Sopenharmony_ci vendorName, productName, useProtocol, useTransport, \ 668c2ecf20Sopenharmony_ci initFunction, flags) \ 678c2ecf20Sopenharmony_ci{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ 688c2ecf20Sopenharmony_ci .driver_info = (flags) } 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic struct usb_device_id isd200_usb_ids[] = { 718c2ecf20Sopenharmony_ci# include "unusual_isd200.h" 728c2ecf20Sopenharmony_ci { } /* Terminating entry */ 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, isd200_usb_ids); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#undef UNUSUAL_DEV 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* 798c2ecf20Sopenharmony_ci * The flags table 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_ci#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ 828c2ecf20Sopenharmony_ci vendor_name, product_name, use_protocol, use_transport, \ 838c2ecf20Sopenharmony_ci init_function, Flags) \ 848c2ecf20Sopenharmony_ci{ \ 858c2ecf20Sopenharmony_ci .vendorName = vendor_name, \ 868c2ecf20Sopenharmony_ci .productName = product_name, \ 878c2ecf20Sopenharmony_ci .useProtocol = use_protocol, \ 888c2ecf20Sopenharmony_ci .useTransport = use_transport, \ 898c2ecf20Sopenharmony_ci .initFunction = init_function, \ 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic struct us_unusual_dev isd200_unusual_dev_list[] = { 938c2ecf20Sopenharmony_ci# include "unusual_isd200.h" 948c2ecf20Sopenharmony_ci { } /* Terminating entry */ 958c2ecf20Sopenharmony_ci}; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci#undef UNUSUAL_DEV 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* Timeout defines (in Seconds) */ 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci#define ISD200_ENUM_BSY_TIMEOUT 35 1028c2ecf20Sopenharmony_ci#define ISD200_ENUM_DETECT_TIMEOUT 30 1038c2ecf20Sopenharmony_ci#define ISD200_DEFAULT_TIMEOUT 30 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci/* device flags */ 1068c2ecf20Sopenharmony_ci#define DF_ATA_DEVICE 0x0001 1078c2ecf20Sopenharmony_ci#define DF_MEDIA_STATUS_ENABLED 0x0002 1088c2ecf20Sopenharmony_ci#define DF_REMOVABLE_MEDIA 0x0004 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci/* capability bit definitions */ 1118c2ecf20Sopenharmony_ci#define CAPABILITY_DMA 0x01 1128c2ecf20Sopenharmony_ci#define CAPABILITY_LBA 0x02 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci/* command_setX bit definitions */ 1158c2ecf20Sopenharmony_ci#define COMMANDSET_REMOVABLE 0x02 1168c2ecf20Sopenharmony_ci#define COMMANDSET_MEDIA_STATUS 0x10 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/* ATA Vendor Specific defines */ 1198c2ecf20Sopenharmony_ci#define ATA_ADDRESS_DEVHEAD_STD 0xa0 1208c2ecf20Sopenharmony_ci#define ATA_ADDRESS_DEVHEAD_LBA_MODE 0x40 1218c2ecf20Sopenharmony_ci#define ATA_ADDRESS_DEVHEAD_SLAVE 0x10 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/* Action Select bits */ 1248c2ecf20Sopenharmony_ci#define ACTION_SELECT_0 0x01 1258c2ecf20Sopenharmony_ci#define ACTION_SELECT_1 0x02 1268c2ecf20Sopenharmony_ci#define ACTION_SELECT_2 0x04 1278c2ecf20Sopenharmony_ci#define ACTION_SELECT_3 0x08 1288c2ecf20Sopenharmony_ci#define ACTION_SELECT_4 0x10 1298c2ecf20Sopenharmony_ci#define ACTION_SELECT_5 0x20 1308c2ecf20Sopenharmony_ci#define ACTION_SELECT_6 0x40 1318c2ecf20Sopenharmony_ci#define ACTION_SELECT_7 0x80 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/* Register Select bits */ 1348c2ecf20Sopenharmony_ci#define REG_ALTERNATE_STATUS 0x01 1358c2ecf20Sopenharmony_ci#define REG_DEVICE_CONTROL 0x01 1368c2ecf20Sopenharmony_ci#define REG_ERROR 0x02 1378c2ecf20Sopenharmony_ci#define REG_FEATURES 0x02 1388c2ecf20Sopenharmony_ci#define REG_SECTOR_COUNT 0x04 1398c2ecf20Sopenharmony_ci#define REG_SECTOR_NUMBER 0x08 1408c2ecf20Sopenharmony_ci#define REG_CYLINDER_LOW 0x10 1418c2ecf20Sopenharmony_ci#define REG_CYLINDER_HIGH 0x20 1428c2ecf20Sopenharmony_ci#define REG_DEVICE_HEAD 0x40 1438c2ecf20Sopenharmony_ci#define REG_STATUS 0x80 1448c2ecf20Sopenharmony_ci#define REG_COMMAND 0x80 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/* ATA registers offset definitions */ 1478c2ecf20Sopenharmony_ci#define ATA_REG_ERROR_OFFSET 1 1488c2ecf20Sopenharmony_ci#define ATA_REG_LCYL_OFFSET 4 1498c2ecf20Sopenharmony_ci#define ATA_REG_HCYL_OFFSET 5 1508c2ecf20Sopenharmony_ci#define ATA_REG_STATUS_OFFSET 7 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci/* ATA error definitions not in <linux/hdreg.h> */ 1538c2ecf20Sopenharmony_ci#define ATA_ERROR_MEDIA_CHANGE 0x20 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci/* ATA command definitions not in <linux/hdreg.h> */ 1568c2ecf20Sopenharmony_ci#define ATA_COMMAND_GET_MEDIA_STATUS 0xDA 1578c2ecf20Sopenharmony_ci#define ATA_COMMAND_MEDIA_EJECT 0xED 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci/* ATA drive control definitions */ 1608c2ecf20Sopenharmony_ci#define ATA_DC_DISABLE_INTERRUPTS 0x02 1618c2ecf20Sopenharmony_ci#define ATA_DC_RESET_CONTROLLER 0x04 1628c2ecf20Sopenharmony_ci#define ATA_DC_REENABLE_CONTROLLER 0x00 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci/* 1658c2ecf20Sopenharmony_ci * General purpose return codes 1668c2ecf20Sopenharmony_ci */ 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci#define ISD200_ERROR -1 1698c2ecf20Sopenharmony_ci#define ISD200_GOOD 0 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci/* 1728c2ecf20Sopenharmony_ci * Transport return codes 1738c2ecf20Sopenharmony_ci */ 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci#define ISD200_TRANSPORT_GOOD 0 /* Transport good, command good */ 1768c2ecf20Sopenharmony_ci#define ISD200_TRANSPORT_FAILED 1 /* Transport good, command failed */ 1778c2ecf20Sopenharmony_ci#define ISD200_TRANSPORT_ERROR 2 /* Transport bad (i.e. device dead) */ 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci/* driver action codes */ 1808c2ecf20Sopenharmony_ci#define ACTION_READ_STATUS 0 1818c2ecf20Sopenharmony_ci#define ACTION_RESET 1 1828c2ecf20Sopenharmony_ci#define ACTION_REENABLE 2 1838c2ecf20Sopenharmony_ci#define ACTION_SOFT_RESET 3 1848c2ecf20Sopenharmony_ci#define ACTION_ENUM 4 1858c2ecf20Sopenharmony_ci#define ACTION_IDENTIFY 5 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci/* 1898c2ecf20Sopenharmony_ci * ata_cdb struct 1908c2ecf20Sopenharmony_ci */ 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ciunion ata_cdb { 1948c2ecf20Sopenharmony_ci struct { 1958c2ecf20Sopenharmony_ci unsigned char SignatureByte0; 1968c2ecf20Sopenharmony_ci unsigned char SignatureByte1; 1978c2ecf20Sopenharmony_ci unsigned char ActionSelect; 1988c2ecf20Sopenharmony_ci unsigned char RegisterSelect; 1998c2ecf20Sopenharmony_ci unsigned char TransferBlockSize; 2008c2ecf20Sopenharmony_ci unsigned char WriteData3F6; 2018c2ecf20Sopenharmony_ci unsigned char WriteData1F1; 2028c2ecf20Sopenharmony_ci unsigned char WriteData1F2; 2038c2ecf20Sopenharmony_ci unsigned char WriteData1F3; 2048c2ecf20Sopenharmony_ci unsigned char WriteData1F4; 2058c2ecf20Sopenharmony_ci unsigned char WriteData1F5; 2068c2ecf20Sopenharmony_ci unsigned char WriteData1F6; 2078c2ecf20Sopenharmony_ci unsigned char WriteData1F7; 2088c2ecf20Sopenharmony_ci unsigned char Reserved[3]; 2098c2ecf20Sopenharmony_ci } generic; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci struct { 2128c2ecf20Sopenharmony_ci unsigned char SignatureByte0; 2138c2ecf20Sopenharmony_ci unsigned char SignatureByte1; 2148c2ecf20Sopenharmony_ci unsigned char ActionSelect; 2158c2ecf20Sopenharmony_ci unsigned char RegisterSelect; 2168c2ecf20Sopenharmony_ci unsigned char TransferBlockSize; 2178c2ecf20Sopenharmony_ci unsigned char AlternateStatusByte; 2188c2ecf20Sopenharmony_ci unsigned char ErrorByte; 2198c2ecf20Sopenharmony_ci unsigned char SectorCountByte; 2208c2ecf20Sopenharmony_ci unsigned char SectorNumberByte; 2218c2ecf20Sopenharmony_ci unsigned char CylinderLowByte; 2228c2ecf20Sopenharmony_ci unsigned char CylinderHighByte; 2238c2ecf20Sopenharmony_ci unsigned char DeviceHeadByte; 2248c2ecf20Sopenharmony_ci unsigned char StatusByte; 2258c2ecf20Sopenharmony_ci unsigned char Reserved[3]; 2268c2ecf20Sopenharmony_ci } read; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci struct { 2298c2ecf20Sopenharmony_ci unsigned char SignatureByte0; 2308c2ecf20Sopenharmony_ci unsigned char SignatureByte1; 2318c2ecf20Sopenharmony_ci unsigned char ActionSelect; 2328c2ecf20Sopenharmony_ci unsigned char RegisterSelect; 2338c2ecf20Sopenharmony_ci unsigned char TransferBlockSize; 2348c2ecf20Sopenharmony_ci unsigned char DeviceControlByte; 2358c2ecf20Sopenharmony_ci unsigned char FeaturesByte; 2368c2ecf20Sopenharmony_ci unsigned char SectorCountByte; 2378c2ecf20Sopenharmony_ci unsigned char SectorNumberByte; 2388c2ecf20Sopenharmony_ci unsigned char CylinderLowByte; 2398c2ecf20Sopenharmony_ci unsigned char CylinderHighByte; 2408c2ecf20Sopenharmony_ci unsigned char DeviceHeadByte; 2418c2ecf20Sopenharmony_ci unsigned char CommandByte; 2428c2ecf20Sopenharmony_ci unsigned char Reserved[3]; 2438c2ecf20Sopenharmony_ci } write; 2448c2ecf20Sopenharmony_ci}; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci/* 2488c2ecf20Sopenharmony_ci * Inquiry data structure. This is the data returned from the target 2498c2ecf20Sopenharmony_ci * after it receives an inquiry. 2508c2ecf20Sopenharmony_ci * 2518c2ecf20Sopenharmony_ci * This structure may be extended by the number of bytes specified 2528c2ecf20Sopenharmony_ci * in the field AdditionalLength. The defined size constant only 2538c2ecf20Sopenharmony_ci * includes fields through ProductRevisionLevel. 2548c2ecf20Sopenharmony_ci */ 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci/* 2578c2ecf20Sopenharmony_ci * DeviceType field 2588c2ecf20Sopenharmony_ci */ 2598c2ecf20Sopenharmony_ci#define DIRECT_ACCESS_DEVICE 0x00 /* disks */ 2608c2ecf20Sopenharmony_ci#define DEVICE_REMOVABLE 0x80 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistruct inquiry_data { 2638c2ecf20Sopenharmony_ci unsigned char DeviceType; 2648c2ecf20Sopenharmony_ci unsigned char DeviceTypeModifier; 2658c2ecf20Sopenharmony_ci unsigned char Versions; 2668c2ecf20Sopenharmony_ci unsigned char Format; 2678c2ecf20Sopenharmony_ci unsigned char AdditionalLength; 2688c2ecf20Sopenharmony_ci unsigned char Reserved[2]; 2698c2ecf20Sopenharmony_ci unsigned char Capability; 2708c2ecf20Sopenharmony_ci unsigned char VendorId[8]; 2718c2ecf20Sopenharmony_ci unsigned char ProductId[16]; 2728c2ecf20Sopenharmony_ci unsigned char ProductRevisionLevel[4]; 2738c2ecf20Sopenharmony_ci unsigned char VendorSpecific[20]; 2748c2ecf20Sopenharmony_ci unsigned char Reserved3[40]; 2758c2ecf20Sopenharmony_ci} __attribute__ ((packed)); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci/* 2788c2ecf20Sopenharmony_ci * INQUIRY data buffer size 2798c2ecf20Sopenharmony_ci */ 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci#define INQUIRYDATABUFFERSIZE 36 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci/* 2858c2ecf20Sopenharmony_ci * ISD200 CONFIG data struct 2868c2ecf20Sopenharmony_ci */ 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci#define ATACFG_TIMING 0x0f 2898c2ecf20Sopenharmony_ci#define ATACFG_ATAPI_RESET 0x10 2908c2ecf20Sopenharmony_ci#define ATACFG_MASTER 0x20 2918c2ecf20Sopenharmony_ci#define ATACFG_BLOCKSIZE 0xa0 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci#define ATACFGE_LAST_LUN 0x07 2948c2ecf20Sopenharmony_ci#define ATACFGE_DESC_OVERRIDE 0x08 2958c2ecf20Sopenharmony_ci#define ATACFGE_STATE_SUSPEND 0x10 2968c2ecf20Sopenharmony_ci#define ATACFGE_SKIP_BOOT 0x20 2978c2ecf20Sopenharmony_ci#define ATACFGE_CONF_DESC2 0x40 2988c2ecf20Sopenharmony_ci#define ATACFGE_INIT_STATUS 0x80 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci#define CFG_CAPABILITY_SRST 0x01 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistruct isd200_config { 3038c2ecf20Sopenharmony_ci unsigned char EventNotification; 3048c2ecf20Sopenharmony_ci unsigned char ExternalClock; 3058c2ecf20Sopenharmony_ci unsigned char ATAInitTimeout; 3068c2ecf20Sopenharmony_ci unsigned char ATAConfig; 3078c2ecf20Sopenharmony_ci unsigned char ATAMajorCommand; 3088c2ecf20Sopenharmony_ci unsigned char ATAMinorCommand; 3098c2ecf20Sopenharmony_ci unsigned char ATAExtraConfig; 3108c2ecf20Sopenharmony_ci unsigned char Capability; 3118c2ecf20Sopenharmony_ci}__attribute__ ((packed)); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci/* 3158c2ecf20Sopenharmony_ci * ISD200 driver information struct 3168c2ecf20Sopenharmony_ci */ 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistruct isd200_info { 3198c2ecf20Sopenharmony_ci struct inquiry_data InquiryData; 3208c2ecf20Sopenharmony_ci u16 *id; 3218c2ecf20Sopenharmony_ci struct isd200_config ConfigData; 3228c2ecf20Sopenharmony_ci unsigned char *RegsBuf; 3238c2ecf20Sopenharmony_ci unsigned char ATARegs[8]; 3248c2ecf20Sopenharmony_ci unsigned char DeviceHead; 3258c2ecf20Sopenharmony_ci unsigned char DeviceFlags; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci /* maximum number of LUNs supported */ 3288c2ecf20Sopenharmony_ci unsigned char MaxLUNs; 3298c2ecf20Sopenharmony_ci unsigned char cmnd[BLK_MAX_CDB]; 3308c2ecf20Sopenharmony_ci struct scsi_cmnd srb; 3318c2ecf20Sopenharmony_ci struct scatterlist sg; 3328c2ecf20Sopenharmony_ci}; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci/* 3368c2ecf20Sopenharmony_ci * Read Capacity Data - returned in Big Endian format 3378c2ecf20Sopenharmony_ci */ 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistruct read_capacity_data { 3408c2ecf20Sopenharmony_ci __be32 LogicalBlockAddress; 3418c2ecf20Sopenharmony_ci __be32 BytesPerBlock; 3428c2ecf20Sopenharmony_ci}; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci/* 3458c2ecf20Sopenharmony_ci * Read Block Limits Data - returned in Big Endian format 3468c2ecf20Sopenharmony_ci * This structure returns the maximum and minimum block 3478c2ecf20Sopenharmony_ci * size for a TAPE device. 3488c2ecf20Sopenharmony_ci */ 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_cistruct read_block_limits { 3518c2ecf20Sopenharmony_ci unsigned char Reserved; 3528c2ecf20Sopenharmony_ci unsigned char BlockMaximumSize[3]; 3538c2ecf20Sopenharmony_ci unsigned char BlockMinimumSize[2]; 3548c2ecf20Sopenharmony_ci}; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci/* 3588c2ecf20Sopenharmony_ci * Sense Data Format 3598c2ecf20Sopenharmony_ci */ 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci#define SENSE_ERRCODE 0x7f 3628c2ecf20Sopenharmony_ci#define SENSE_ERRCODE_VALID 0x80 3638c2ecf20Sopenharmony_ci#define SENSE_FLAG_SENSE_KEY 0x0f 3648c2ecf20Sopenharmony_ci#define SENSE_FLAG_BAD_LENGTH 0x20 3658c2ecf20Sopenharmony_ci#define SENSE_FLAG_END_OF_MEDIA 0x40 3668c2ecf20Sopenharmony_ci#define SENSE_FLAG_FILE_MARK 0x80 3678c2ecf20Sopenharmony_cistruct sense_data { 3688c2ecf20Sopenharmony_ci unsigned char ErrorCode; 3698c2ecf20Sopenharmony_ci unsigned char SegmentNumber; 3708c2ecf20Sopenharmony_ci unsigned char Flags; 3718c2ecf20Sopenharmony_ci unsigned char Information[4]; 3728c2ecf20Sopenharmony_ci unsigned char AdditionalSenseLength; 3738c2ecf20Sopenharmony_ci unsigned char CommandSpecificInformation[4]; 3748c2ecf20Sopenharmony_ci unsigned char AdditionalSenseCode; 3758c2ecf20Sopenharmony_ci unsigned char AdditionalSenseCodeQualifier; 3768c2ecf20Sopenharmony_ci unsigned char FieldReplaceableUnitCode; 3778c2ecf20Sopenharmony_ci unsigned char SenseKeySpecific[3]; 3788c2ecf20Sopenharmony_ci} __attribute__ ((packed)); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci/* 3818c2ecf20Sopenharmony_ci * Default request sense buffer size 3828c2ecf20Sopenharmony_ci */ 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci#define SENSE_BUFFER_SIZE 18 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci/*********************************************************************** 3878c2ecf20Sopenharmony_ci * Helper routines 3888c2ecf20Sopenharmony_ci ***********************************************************************/ 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci/************************************************************************** 3918c2ecf20Sopenharmony_ci * isd200_build_sense 3928c2ecf20Sopenharmony_ci * 3938c2ecf20Sopenharmony_ci * Builds an artificial sense buffer to report the results of a 3948c2ecf20Sopenharmony_ci * failed command. 3958c2ecf20Sopenharmony_ci * 3968c2ecf20Sopenharmony_ci * RETURNS: 3978c2ecf20Sopenharmony_ci * void 3988c2ecf20Sopenharmony_ci */ 3998c2ecf20Sopenharmony_cistatic void isd200_build_sense(struct us_data *us, struct scsi_cmnd *srb) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci struct isd200_info *info = (struct isd200_info *)us->extra; 4028c2ecf20Sopenharmony_ci struct sense_data *buf = (struct sense_data *) &srb->sense_buffer[0]; 4038c2ecf20Sopenharmony_ci unsigned char error = info->ATARegs[ATA_REG_ERROR_OFFSET]; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci if(error & ATA_ERROR_MEDIA_CHANGE) { 4068c2ecf20Sopenharmony_ci buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; 4078c2ecf20Sopenharmony_ci buf->AdditionalSenseLength = 0xb; 4088c2ecf20Sopenharmony_ci buf->Flags = UNIT_ATTENTION; 4098c2ecf20Sopenharmony_ci buf->AdditionalSenseCode = 0; 4108c2ecf20Sopenharmony_ci buf->AdditionalSenseCodeQualifier = 0; 4118c2ecf20Sopenharmony_ci } else if (error & ATA_MCR) { 4128c2ecf20Sopenharmony_ci buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; 4138c2ecf20Sopenharmony_ci buf->AdditionalSenseLength = 0xb; 4148c2ecf20Sopenharmony_ci buf->Flags = UNIT_ATTENTION; 4158c2ecf20Sopenharmony_ci buf->AdditionalSenseCode = 0; 4168c2ecf20Sopenharmony_ci buf->AdditionalSenseCodeQualifier = 0; 4178c2ecf20Sopenharmony_ci } else if (error & ATA_TRK0NF) { 4188c2ecf20Sopenharmony_ci buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; 4198c2ecf20Sopenharmony_ci buf->AdditionalSenseLength = 0xb; 4208c2ecf20Sopenharmony_ci buf->Flags = NOT_READY; 4218c2ecf20Sopenharmony_ci buf->AdditionalSenseCode = 0; 4228c2ecf20Sopenharmony_ci buf->AdditionalSenseCodeQualifier = 0; 4238c2ecf20Sopenharmony_ci } else if (error & ATA_UNC) { 4248c2ecf20Sopenharmony_ci buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; 4258c2ecf20Sopenharmony_ci buf->AdditionalSenseLength = 0xb; 4268c2ecf20Sopenharmony_ci buf->Flags = DATA_PROTECT; 4278c2ecf20Sopenharmony_ci buf->AdditionalSenseCode = 0; 4288c2ecf20Sopenharmony_ci buf->AdditionalSenseCodeQualifier = 0; 4298c2ecf20Sopenharmony_ci } else { 4308c2ecf20Sopenharmony_ci buf->ErrorCode = 0; 4318c2ecf20Sopenharmony_ci buf->AdditionalSenseLength = 0; 4328c2ecf20Sopenharmony_ci buf->Flags = 0; 4338c2ecf20Sopenharmony_ci buf->AdditionalSenseCode = 0; 4348c2ecf20Sopenharmony_ci buf->AdditionalSenseCodeQualifier = 0; 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci/*********************************************************************** 4408c2ecf20Sopenharmony_ci * Transport routines 4418c2ecf20Sopenharmony_ci ***********************************************************************/ 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci/************************************************************************** 4448c2ecf20Sopenharmony_ci * isd200_set_srb(), isd200_srb_set_bufflen() 4458c2ecf20Sopenharmony_ci * 4468c2ecf20Sopenharmony_ci * Two helpers to facilitate in initialization of scsi_cmnd structure 4478c2ecf20Sopenharmony_ci * Will need to change when struct scsi_cmnd changes 4488c2ecf20Sopenharmony_ci */ 4498c2ecf20Sopenharmony_cistatic void isd200_set_srb(struct isd200_info *info, 4508c2ecf20Sopenharmony_ci enum dma_data_direction dir, void* buff, unsigned bufflen) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci struct scsi_cmnd *srb = &info->srb; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if (buff) 4558c2ecf20Sopenharmony_ci sg_init_one(&info->sg, buff, bufflen); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci srb->sc_data_direction = dir; 4588c2ecf20Sopenharmony_ci srb->sdb.table.sgl = buff ? &info->sg : NULL; 4598c2ecf20Sopenharmony_ci srb->sdb.length = bufflen; 4608c2ecf20Sopenharmony_ci srb->sdb.table.nents = buff ? 1 : 0; 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_cistatic void isd200_srb_set_bufflen(struct scsi_cmnd *srb, unsigned bufflen) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci srb->sdb.length = bufflen; 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci/************************************************************************** 4708c2ecf20Sopenharmony_ci * isd200_action 4718c2ecf20Sopenharmony_ci * 4728c2ecf20Sopenharmony_ci * Routine for sending commands to the isd200 4738c2ecf20Sopenharmony_ci * 4748c2ecf20Sopenharmony_ci * RETURNS: 4758c2ecf20Sopenharmony_ci * ISD status code 4768c2ecf20Sopenharmony_ci */ 4778c2ecf20Sopenharmony_cistatic int isd200_action( struct us_data *us, int action, 4788c2ecf20Sopenharmony_ci void* pointer, int value ) 4798c2ecf20Sopenharmony_ci{ 4808c2ecf20Sopenharmony_ci union ata_cdb ata; 4818c2ecf20Sopenharmony_ci /* static to prevent this large struct being placed on the valuable stack */ 4828c2ecf20Sopenharmony_ci static struct scsi_device srb_dev; 4838c2ecf20Sopenharmony_ci struct isd200_info *info = (struct isd200_info *)us->extra; 4848c2ecf20Sopenharmony_ci struct scsi_cmnd *srb = &info->srb; 4858c2ecf20Sopenharmony_ci int status; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci memset(&ata, 0, sizeof(ata)); 4888c2ecf20Sopenharmony_ci srb->cmnd = info->cmnd; 4898c2ecf20Sopenharmony_ci srb->device = &srb_dev; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci ata.generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; 4928c2ecf20Sopenharmony_ci ata.generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; 4938c2ecf20Sopenharmony_ci ata.generic.TransferBlockSize = 1; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci switch ( action ) { 4968c2ecf20Sopenharmony_ci case ACTION_READ_STATUS: 4978c2ecf20Sopenharmony_ci usb_stor_dbg(us, " isd200_action(READ_STATUS)\n"); 4988c2ecf20Sopenharmony_ci ata.generic.ActionSelect = ACTION_SELECT_0|ACTION_SELECT_2; 4998c2ecf20Sopenharmony_ci ata.generic.RegisterSelect = 5008c2ecf20Sopenharmony_ci REG_CYLINDER_LOW | REG_CYLINDER_HIGH | 5018c2ecf20Sopenharmony_ci REG_STATUS | REG_ERROR; 5028c2ecf20Sopenharmony_ci isd200_set_srb(info, DMA_FROM_DEVICE, pointer, value); 5038c2ecf20Sopenharmony_ci break; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci case ACTION_ENUM: 5068c2ecf20Sopenharmony_ci usb_stor_dbg(us, " isd200_action(ENUM,0x%02x)\n", value); 5078c2ecf20Sopenharmony_ci ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| 5088c2ecf20Sopenharmony_ci ACTION_SELECT_3|ACTION_SELECT_4| 5098c2ecf20Sopenharmony_ci ACTION_SELECT_5; 5108c2ecf20Sopenharmony_ci ata.generic.RegisterSelect = REG_DEVICE_HEAD; 5118c2ecf20Sopenharmony_ci ata.write.DeviceHeadByte = value; 5128c2ecf20Sopenharmony_ci isd200_set_srb(info, DMA_NONE, NULL, 0); 5138c2ecf20Sopenharmony_ci break; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci case ACTION_RESET: 5168c2ecf20Sopenharmony_ci usb_stor_dbg(us, " isd200_action(RESET)\n"); 5178c2ecf20Sopenharmony_ci ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| 5188c2ecf20Sopenharmony_ci ACTION_SELECT_3|ACTION_SELECT_4; 5198c2ecf20Sopenharmony_ci ata.generic.RegisterSelect = REG_DEVICE_CONTROL; 5208c2ecf20Sopenharmony_ci ata.write.DeviceControlByte = ATA_DC_RESET_CONTROLLER; 5218c2ecf20Sopenharmony_ci isd200_set_srb(info, DMA_NONE, NULL, 0); 5228c2ecf20Sopenharmony_ci break; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci case ACTION_REENABLE: 5258c2ecf20Sopenharmony_ci usb_stor_dbg(us, " isd200_action(REENABLE)\n"); 5268c2ecf20Sopenharmony_ci ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| 5278c2ecf20Sopenharmony_ci ACTION_SELECT_3|ACTION_SELECT_4; 5288c2ecf20Sopenharmony_ci ata.generic.RegisterSelect = REG_DEVICE_CONTROL; 5298c2ecf20Sopenharmony_ci ata.write.DeviceControlByte = ATA_DC_REENABLE_CONTROLLER; 5308c2ecf20Sopenharmony_ci isd200_set_srb(info, DMA_NONE, NULL, 0); 5318c2ecf20Sopenharmony_ci break; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci case ACTION_SOFT_RESET: 5348c2ecf20Sopenharmony_ci usb_stor_dbg(us, " isd200_action(SOFT_RESET)\n"); 5358c2ecf20Sopenharmony_ci ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_5; 5368c2ecf20Sopenharmony_ci ata.generic.RegisterSelect = REG_DEVICE_HEAD | REG_COMMAND; 5378c2ecf20Sopenharmony_ci ata.write.DeviceHeadByte = info->DeviceHead; 5388c2ecf20Sopenharmony_ci ata.write.CommandByte = ATA_CMD_DEV_RESET; 5398c2ecf20Sopenharmony_ci isd200_set_srb(info, DMA_NONE, NULL, 0); 5408c2ecf20Sopenharmony_ci break; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci case ACTION_IDENTIFY: 5438c2ecf20Sopenharmony_ci usb_stor_dbg(us, " isd200_action(IDENTIFY)\n"); 5448c2ecf20Sopenharmony_ci ata.generic.RegisterSelect = REG_COMMAND; 5458c2ecf20Sopenharmony_ci ata.write.CommandByte = ATA_CMD_ID_ATA; 5468c2ecf20Sopenharmony_ci isd200_set_srb(info, DMA_FROM_DEVICE, info->id, 5478c2ecf20Sopenharmony_ci ATA_ID_WORDS * 2); 5488c2ecf20Sopenharmony_ci break; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci default: 5518c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Error: Undefined action %d\n", action); 5528c2ecf20Sopenharmony_ci return ISD200_ERROR; 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci memcpy(srb->cmnd, &ata, sizeof(ata.generic)); 5568c2ecf20Sopenharmony_ci srb->cmd_len = sizeof(ata.generic); 5578c2ecf20Sopenharmony_ci status = usb_stor_Bulk_transport(srb, us); 5588c2ecf20Sopenharmony_ci if (status == USB_STOR_TRANSPORT_GOOD) 5598c2ecf20Sopenharmony_ci status = ISD200_GOOD; 5608c2ecf20Sopenharmony_ci else { 5618c2ecf20Sopenharmony_ci usb_stor_dbg(us, " isd200_action(0x%02x) error: %d\n", 5628c2ecf20Sopenharmony_ci action, status); 5638c2ecf20Sopenharmony_ci status = ISD200_ERROR; 5648c2ecf20Sopenharmony_ci /* need to reset device here */ 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci return status; 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci/************************************************************************** 5718c2ecf20Sopenharmony_ci * isd200_read_regs 5728c2ecf20Sopenharmony_ci * 5738c2ecf20Sopenharmony_ci * Read ATA Registers 5748c2ecf20Sopenharmony_ci * 5758c2ecf20Sopenharmony_ci * RETURNS: 5768c2ecf20Sopenharmony_ci * ISD status code 5778c2ecf20Sopenharmony_ci */ 5788c2ecf20Sopenharmony_cistatic int isd200_read_regs( struct us_data *us ) 5798c2ecf20Sopenharmony_ci{ 5808c2ecf20Sopenharmony_ci struct isd200_info *info = (struct isd200_info *)us->extra; 5818c2ecf20Sopenharmony_ci int retStatus = ISD200_GOOD; 5828c2ecf20Sopenharmony_ci int transferStatus; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Entering isd200_IssueATAReadRegs\n"); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci transferStatus = isd200_action( us, ACTION_READ_STATUS, 5878c2ecf20Sopenharmony_ci info->RegsBuf, sizeof(info->ATARegs) ); 5888c2ecf20Sopenharmony_ci if (transferStatus != ISD200_TRANSPORT_GOOD) { 5898c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Error reading ATA registers\n"); 5908c2ecf20Sopenharmony_ci retStatus = ISD200_ERROR; 5918c2ecf20Sopenharmony_ci } else { 5928c2ecf20Sopenharmony_ci memcpy(info->ATARegs, info->RegsBuf, sizeof(info->ATARegs)); 5938c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Got ATA Register[ATA_REG_ERROR_OFFSET] = 0x%x\n", 5948c2ecf20Sopenharmony_ci info->ATARegs[ATA_REG_ERROR_OFFSET]); 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci return retStatus; 5988c2ecf20Sopenharmony_ci} 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci/************************************************************************** 6028c2ecf20Sopenharmony_ci * Invoke the transport and basic error-handling/recovery methods 6038c2ecf20Sopenharmony_ci * 6048c2ecf20Sopenharmony_ci * This is used by the protocol layers to actually send the message to 6058c2ecf20Sopenharmony_ci * the device and receive the response. 6068c2ecf20Sopenharmony_ci */ 6078c2ecf20Sopenharmony_cistatic void isd200_invoke_transport( struct us_data *us, 6088c2ecf20Sopenharmony_ci struct scsi_cmnd *srb, 6098c2ecf20Sopenharmony_ci union ata_cdb *ataCdb ) 6108c2ecf20Sopenharmony_ci{ 6118c2ecf20Sopenharmony_ci int need_auto_sense = 0; 6128c2ecf20Sopenharmony_ci int transferStatus; 6138c2ecf20Sopenharmony_ci int result; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci /* send the command to the transport layer */ 6168c2ecf20Sopenharmony_ci memcpy(srb->cmnd, ataCdb, sizeof(ataCdb->generic)); 6178c2ecf20Sopenharmony_ci srb->cmd_len = sizeof(ataCdb->generic); 6188c2ecf20Sopenharmony_ci transferStatus = usb_stor_Bulk_transport(srb, us); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci /* 6218c2ecf20Sopenharmony_ci * if the command gets aborted by the higher layers, we need to 6228c2ecf20Sopenharmony_ci * short-circuit all other processing 6238c2ecf20Sopenharmony_ci */ 6248c2ecf20Sopenharmony_ci if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { 6258c2ecf20Sopenharmony_ci usb_stor_dbg(us, "-- command was aborted\n"); 6268c2ecf20Sopenharmony_ci goto Handle_Abort; 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci switch (transferStatus) { 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci case USB_STOR_TRANSPORT_GOOD: 6328c2ecf20Sopenharmony_ci /* Indicate a good result */ 6338c2ecf20Sopenharmony_ci srb->result = SAM_STAT_GOOD; 6348c2ecf20Sopenharmony_ci break; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci case USB_STOR_TRANSPORT_NO_SENSE: 6378c2ecf20Sopenharmony_ci usb_stor_dbg(us, "-- transport indicates protocol failure\n"); 6388c2ecf20Sopenharmony_ci srb->result = SAM_STAT_CHECK_CONDITION; 6398c2ecf20Sopenharmony_ci return; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci case USB_STOR_TRANSPORT_FAILED: 6428c2ecf20Sopenharmony_ci usb_stor_dbg(us, "-- transport indicates command failure\n"); 6438c2ecf20Sopenharmony_ci need_auto_sense = 1; 6448c2ecf20Sopenharmony_ci break; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci case USB_STOR_TRANSPORT_ERROR: 6478c2ecf20Sopenharmony_ci usb_stor_dbg(us, "-- transport indicates transport error\n"); 6488c2ecf20Sopenharmony_ci srb->result = DID_ERROR << 16; 6498c2ecf20Sopenharmony_ci /* Need reset here */ 6508c2ecf20Sopenharmony_ci return; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci default: 6538c2ecf20Sopenharmony_ci usb_stor_dbg(us, "-- transport indicates unknown error\n"); 6548c2ecf20Sopenharmony_ci srb->result = DID_ERROR << 16; 6558c2ecf20Sopenharmony_ci /* Need reset here */ 6568c2ecf20Sopenharmony_ci return; 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci if ((scsi_get_resid(srb) > 0) && 6608c2ecf20Sopenharmony_ci !((srb->cmnd[0] == REQUEST_SENSE) || 6618c2ecf20Sopenharmony_ci (srb->cmnd[0] == INQUIRY) || 6628c2ecf20Sopenharmony_ci (srb->cmnd[0] == MODE_SENSE) || 6638c2ecf20Sopenharmony_ci (srb->cmnd[0] == LOG_SENSE) || 6648c2ecf20Sopenharmony_ci (srb->cmnd[0] == MODE_SENSE_10))) { 6658c2ecf20Sopenharmony_ci usb_stor_dbg(us, "-- unexpectedly short transfer\n"); 6668c2ecf20Sopenharmony_ci need_auto_sense = 1; 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci if (need_auto_sense) { 6708c2ecf20Sopenharmony_ci result = isd200_read_regs(us); 6718c2ecf20Sopenharmony_ci if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { 6728c2ecf20Sopenharmony_ci usb_stor_dbg(us, "-- auto-sense aborted\n"); 6738c2ecf20Sopenharmony_ci goto Handle_Abort; 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci if (result == ISD200_GOOD) { 6768c2ecf20Sopenharmony_ci isd200_build_sense(us, srb); 6778c2ecf20Sopenharmony_ci srb->result = SAM_STAT_CHECK_CONDITION; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci /* If things are really okay, then let's show that */ 6808c2ecf20Sopenharmony_ci if ((srb->sense_buffer[2] & 0xf) == 0x0) 6818c2ecf20Sopenharmony_ci srb->result = SAM_STAT_GOOD; 6828c2ecf20Sopenharmony_ci } else { 6838c2ecf20Sopenharmony_ci srb->result = DID_ERROR << 16; 6848c2ecf20Sopenharmony_ci /* Need reset here */ 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci /* 6898c2ecf20Sopenharmony_ci * Regardless of auto-sense, if we _know_ we have an error 6908c2ecf20Sopenharmony_ci * condition, show that in the result code 6918c2ecf20Sopenharmony_ci */ 6928c2ecf20Sopenharmony_ci if (transferStatus == USB_STOR_TRANSPORT_FAILED) 6938c2ecf20Sopenharmony_ci srb->result = SAM_STAT_CHECK_CONDITION; 6948c2ecf20Sopenharmony_ci return; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci /* 6978c2ecf20Sopenharmony_ci * abort processing: the bulk-only transport requires a reset 6988c2ecf20Sopenharmony_ci * following an abort 6998c2ecf20Sopenharmony_ci */ 7008c2ecf20Sopenharmony_ci Handle_Abort: 7018c2ecf20Sopenharmony_ci srb->result = DID_ABORT << 16; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci /* permit the reset transfer to take place */ 7048c2ecf20Sopenharmony_ci clear_bit(US_FLIDX_ABORTING, &us->dflags); 7058c2ecf20Sopenharmony_ci /* Need reset here */ 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci#ifdef CONFIG_USB_STORAGE_DEBUG 7098c2ecf20Sopenharmony_cistatic void isd200_log_config(struct us_data *us, struct isd200_info *info) 7108c2ecf20Sopenharmony_ci{ 7118c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Event Notification: 0x%x\n", 7128c2ecf20Sopenharmony_ci info->ConfigData.EventNotification); 7138c2ecf20Sopenharmony_ci usb_stor_dbg(us, " External Clock: 0x%x\n", 7148c2ecf20Sopenharmony_ci info->ConfigData.ExternalClock); 7158c2ecf20Sopenharmony_ci usb_stor_dbg(us, " ATA Init Timeout: 0x%x\n", 7168c2ecf20Sopenharmony_ci info->ConfigData.ATAInitTimeout); 7178c2ecf20Sopenharmony_ci usb_stor_dbg(us, " ATAPI Command Block Size: 0x%x\n", 7188c2ecf20Sopenharmony_ci (info->ConfigData.ATAConfig & ATACFG_BLOCKSIZE) >> 6); 7198c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Master/Slave Selection: 0x%x\n", 7208c2ecf20Sopenharmony_ci info->ConfigData.ATAConfig & ATACFG_MASTER); 7218c2ecf20Sopenharmony_ci usb_stor_dbg(us, " ATAPI Reset: 0x%x\n", 7228c2ecf20Sopenharmony_ci info->ConfigData.ATAConfig & ATACFG_ATAPI_RESET); 7238c2ecf20Sopenharmony_ci usb_stor_dbg(us, " ATA Timing: 0x%x\n", 7248c2ecf20Sopenharmony_ci info->ConfigData.ATAConfig & ATACFG_TIMING); 7258c2ecf20Sopenharmony_ci usb_stor_dbg(us, " ATA Major Command: 0x%x\n", 7268c2ecf20Sopenharmony_ci info->ConfigData.ATAMajorCommand); 7278c2ecf20Sopenharmony_ci usb_stor_dbg(us, " ATA Minor Command: 0x%x\n", 7288c2ecf20Sopenharmony_ci info->ConfigData.ATAMinorCommand); 7298c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Init Status: 0x%x\n", 7308c2ecf20Sopenharmony_ci info->ConfigData.ATAExtraConfig & ATACFGE_INIT_STATUS); 7318c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Config Descriptor 2: 0x%x\n", 7328c2ecf20Sopenharmony_ci info->ConfigData.ATAExtraConfig & ATACFGE_CONF_DESC2); 7338c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Skip Device Boot: 0x%x\n", 7348c2ecf20Sopenharmony_ci info->ConfigData.ATAExtraConfig & ATACFGE_SKIP_BOOT); 7358c2ecf20Sopenharmony_ci usb_stor_dbg(us, " ATA 3 State Suspend: 0x%x\n", 7368c2ecf20Sopenharmony_ci info->ConfigData.ATAExtraConfig & ATACFGE_STATE_SUSPEND); 7378c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Descriptor Override: 0x%x\n", 7388c2ecf20Sopenharmony_ci info->ConfigData.ATAExtraConfig & ATACFGE_DESC_OVERRIDE); 7398c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Last LUN Identifier: 0x%x\n", 7408c2ecf20Sopenharmony_ci info->ConfigData.ATAExtraConfig & ATACFGE_LAST_LUN); 7418c2ecf20Sopenharmony_ci usb_stor_dbg(us, " SRST Enable: 0x%x\n", 7428c2ecf20Sopenharmony_ci info->ConfigData.ATAExtraConfig & CFG_CAPABILITY_SRST); 7438c2ecf20Sopenharmony_ci} 7448c2ecf20Sopenharmony_ci#endif 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci/************************************************************************** 7478c2ecf20Sopenharmony_ci * isd200_write_config 7488c2ecf20Sopenharmony_ci * 7498c2ecf20Sopenharmony_ci * Write the ISD200 Configuration data 7508c2ecf20Sopenharmony_ci * 7518c2ecf20Sopenharmony_ci * RETURNS: 7528c2ecf20Sopenharmony_ci * ISD status code 7538c2ecf20Sopenharmony_ci */ 7548c2ecf20Sopenharmony_cistatic int isd200_write_config( struct us_data *us ) 7558c2ecf20Sopenharmony_ci{ 7568c2ecf20Sopenharmony_ci struct isd200_info *info = (struct isd200_info *)us->extra; 7578c2ecf20Sopenharmony_ci int retStatus = ISD200_GOOD; 7588c2ecf20Sopenharmony_ci int result; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci#ifdef CONFIG_USB_STORAGE_DEBUG 7618c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Entering isd200_write_config\n"); 7628c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Writing the following ISD200 Config Data:\n"); 7638c2ecf20Sopenharmony_ci isd200_log_config(us, info); 7648c2ecf20Sopenharmony_ci#endif 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci /* let's send the command via the control pipe */ 7678c2ecf20Sopenharmony_ci result = usb_stor_ctrl_transfer( 7688c2ecf20Sopenharmony_ci us, 7698c2ecf20Sopenharmony_ci us->send_ctrl_pipe, 7708c2ecf20Sopenharmony_ci 0x01, 7718c2ecf20Sopenharmony_ci USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, 7728c2ecf20Sopenharmony_ci 0x0000, 7738c2ecf20Sopenharmony_ci 0x0002, 7748c2ecf20Sopenharmony_ci (void *) &info->ConfigData, 7758c2ecf20Sopenharmony_ci sizeof(info->ConfigData)); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci if (result >= 0) { 7788c2ecf20Sopenharmony_ci usb_stor_dbg(us, " ISD200 Config Data was written successfully\n"); 7798c2ecf20Sopenharmony_ci } else { 7808c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Request to write ISD200 Config Data failed!\n"); 7818c2ecf20Sopenharmony_ci retStatus = ISD200_ERROR; 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Leaving isd200_write_config %08X\n", retStatus); 7858c2ecf20Sopenharmony_ci return retStatus; 7868c2ecf20Sopenharmony_ci} 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci/************************************************************************** 7908c2ecf20Sopenharmony_ci * isd200_read_config 7918c2ecf20Sopenharmony_ci * 7928c2ecf20Sopenharmony_ci * Reads the ISD200 Configuration data 7938c2ecf20Sopenharmony_ci * 7948c2ecf20Sopenharmony_ci * RETURNS: 7958c2ecf20Sopenharmony_ci * ISD status code 7968c2ecf20Sopenharmony_ci */ 7978c2ecf20Sopenharmony_cistatic int isd200_read_config( struct us_data *us ) 7988c2ecf20Sopenharmony_ci{ 7998c2ecf20Sopenharmony_ci struct isd200_info *info = (struct isd200_info *)us->extra; 8008c2ecf20Sopenharmony_ci int retStatus = ISD200_GOOD; 8018c2ecf20Sopenharmony_ci int result; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Entering isd200_read_config\n"); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci /* read the configuration information from ISD200. Use this to */ 8068c2ecf20Sopenharmony_ci /* determine what the special ATA CDB bytes are. */ 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci result = usb_stor_ctrl_transfer( 8098c2ecf20Sopenharmony_ci us, 8108c2ecf20Sopenharmony_ci us->recv_ctrl_pipe, 8118c2ecf20Sopenharmony_ci 0x02, 8128c2ecf20Sopenharmony_ci USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 8138c2ecf20Sopenharmony_ci 0x0000, 8148c2ecf20Sopenharmony_ci 0x0002, 8158c2ecf20Sopenharmony_ci (void *) &info->ConfigData, 8168c2ecf20Sopenharmony_ci sizeof(info->ConfigData)); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci if (result >= 0) { 8208c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Retrieved the following ISD200 Config Data:\n"); 8218c2ecf20Sopenharmony_ci#ifdef CONFIG_USB_STORAGE_DEBUG 8228c2ecf20Sopenharmony_ci isd200_log_config(us, info); 8238c2ecf20Sopenharmony_ci#endif 8248c2ecf20Sopenharmony_ci } else { 8258c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Request to get ISD200 Config Data failed!\n"); 8268c2ecf20Sopenharmony_ci retStatus = ISD200_ERROR; 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Leaving isd200_read_config %08X\n", retStatus); 8308c2ecf20Sopenharmony_ci return retStatus; 8318c2ecf20Sopenharmony_ci} 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci/************************************************************************** 8358c2ecf20Sopenharmony_ci * isd200_atapi_soft_reset 8368c2ecf20Sopenharmony_ci * 8378c2ecf20Sopenharmony_ci * Perform an Atapi Soft Reset on the device 8388c2ecf20Sopenharmony_ci * 8398c2ecf20Sopenharmony_ci * RETURNS: 8408c2ecf20Sopenharmony_ci * NT status code 8418c2ecf20Sopenharmony_ci */ 8428c2ecf20Sopenharmony_cistatic int isd200_atapi_soft_reset( struct us_data *us ) 8438c2ecf20Sopenharmony_ci{ 8448c2ecf20Sopenharmony_ci int retStatus = ISD200_GOOD; 8458c2ecf20Sopenharmony_ci int transferStatus; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Entering isd200_atapi_soft_reset\n"); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci transferStatus = isd200_action( us, ACTION_SOFT_RESET, NULL, 0 ); 8508c2ecf20Sopenharmony_ci if (transferStatus != ISD200_TRANSPORT_GOOD) { 8518c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Error issuing Atapi Soft Reset\n"); 8528c2ecf20Sopenharmony_ci retStatus = ISD200_ERROR; 8538c2ecf20Sopenharmony_ci } 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Leaving isd200_atapi_soft_reset %08X\n", retStatus); 8568c2ecf20Sopenharmony_ci return retStatus; 8578c2ecf20Sopenharmony_ci} 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci/************************************************************************** 8618c2ecf20Sopenharmony_ci * isd200_srst 8628c2ecf20Sopenharmony_ci * 8638c2ecf20Sopenharmony_ci * Perform an SRST on the device 8648c2ecf20Sopenharmony_ci * 8658c2ecf20Sopenharmony_ci * RETURNS: 8668c2ecf20Sopenharmony_ci * ISD status code 8678c2ecf20Sopenharmony_ci */ 8688c2ecf20Sopenharmony_cistatic int isd200_srst( struct us_data *us ) 8698c2ecf20Sopenharmony_ci{ 8708c2ecf20Sopenharmony_ci int retStatus = ISD200_GOOD; 8718c2ecf20Sopenharmony_ci int transferStatus; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Entering isd200_SRST\n"); 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci transferStatus = isd200_action( us, ACTION_RESET, NULL, 0 ); 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci /* check to see if this request failed */ 8788c2ecf20Sopenharmony_ci if (transferStatus != ISD200_TRANSPORT_GOOD) { 8798c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Error issuing SRST\n"); 8808c2ecf20Sopenharmony_ci retStatus = ISD200_ERROR; 8818c2ecf20Sopenharmony_ci } else { 8828c2ecf20Sopenharmony_ci /* delay 10ms to give the drive a chance to see it */ 8838c2ecf20Sopenharmony_ci msleep(10); 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci transferStatus = isd200_action( us, ACTION_REENABLE, NULL, 0 ); 8868c2ecf20Sopenharmony_ci if (transferStatus != ISD200_TRANSPORT_GOOD) { 8878c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Error taking drive out of reset\n"); 8888c2ecf20Sopenharmony_ci retStatus = ISD200_ERROR; 8898c2ecf20Sopenharmony_ci } else { 8908c2ecf20Sopenharmony_ci /* delay 50ms to give the drive a chance to recover after SRST */ 8918c2ecf20Sopenharmony_ci msleep(50); 8928c2ecf20Sopenharmony_ci } 8938c2ecf20Sopenharmony_ci } 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Leaving isd200_srst %08X\n", retStatus); 8968c2ecf20Sopenharmony_ci return retStatus; 8978c2ecf20Sopenharmony_ci} 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci/************************************************************************** 9018c2ecf20Sopenharmony_ci * isd200_try_enum 9028c2ecf20Sopenharmony_ci * 9038c2ecf20Sopenharmony_ci * Helper function for isd200_manual_enum(). Does ENUM and READ_STATUS 9048c2ecf20Sopenharmony_ci * and tries to analyze the status registers 9058c2ecf20Sopenharmony_ci * 9068c2ecf20Sopenharmony_ci * RETURNS: 9078c2ecf20Sopenharmony_ci * ISD status code 9088c2ecf20Sopenharmony_ci */ 9098c2ecf20Sopenharmony_cistatic int isd200_try_enum(struct us_data *us, unsigned char master_slave, 9108c2ecf20Sopenharmony_ci int detect ) 9118c2ecf20Sopenharmony_ci{ 9128c2ecf20Sopenharmony_ci int status = ISD200_GOOD; 9138c2ecf20Sopenharmony_ci unsigned long endTime; 9148c2ecf20Sopenharmony_ci struct isd200_info *info = (struct isd200_info *)us->extra; 9158c2ecf20Sopenharmony_ci unsigned char *regs = info->RegsBuf; 9168c2ecf20Sopenharmony_ci int recheckAsMaster = 0; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci if ( detect ) 9198c2ecf20Sopenharmony_ci endTime = jiffies + ISD200_ENUM_DETECT_TIMEOUT * HZ; 9208c2ecf20Sopenharmony_ci else 9218c2ecf20Sopenharmony_ci endTime = jiffies + ISD200_ENUM_BSY_TIMEOUT * HZ; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci /* loop until we detect !BSY or timeout */ 9248c2ecf20Sopenharmony_ci while(1) { 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci status = isd200_action( us, ACTION_ENUM, NULL, master_slave ); 9278c2ecf20Sopenharmony_ci if ( status != ISD200_GOOD ) 9288c2ecf20Sopenharmony_ci break; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci status = isd200_action( us, ACTION_READ_STATUS, 9318c2ecf20Sopenharmony_ci regs, 8 ); 9328c2ecf20Sopenharmony_ci if ( status != ISD200_GOOD ) 9338c2ecf20Sopenharmony_ci break; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci if (!detect) { 9368c2ecf20Sopenharmony_ci if (regs[ATA_REG_STATUS_OFFSET] & ATA_BUSY) { 9378c2ecf20Sopenharmony_ci usb_stor_dbg(us, " %s status is still BSY, try again...\n", 9388c2ecf20Sopenharmony_ci master_slave == ATA_ADDRESS_DEVHEAD_STD ? 9398c2ecf20Sopenharmony_ci "Master" : "Slave"); 9408c2ecf20Sopenharmony_ci } else { 9418c2ecf20Sopenharmony_ci usb_stor_dbg(us, " %s status !BSY, continue with next operation\n", 9428c2ecf20Sopenharmony_ci master_slave == ATA_ADDRESS_DEVHEAD_STD ? 9438c2ecf20Sopenharmony_ci "Master" : "Slave"); 9448c2ecf20Sopenharmony_ci break; 9458c2ecf20Sopenharmony_ci } 9468c2ecf20Sopenharmony_ci } 9478c2ecf20Sopenharmony_ci /* check for ATA_BUSY and */ 9488c2ecf20Sopenharmony_ci /* ATA_DF (workaround ATA Zip drive) and */ 9498c2ecf20Sopenharmony_ci /* ATA_ERR (workaround for Archos CD-ROM) */ 9508c2ecf20Sopenharmony_ci else if (regs[ATA_REG_STATUS_OFFSET] & 9518c2ecf20Sopenharmony_ci (ATA_BUSY | ATA_DF | ATA_ERR)) { 9528c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Status indicates it is not ready, try again...\n"); 9538c2ecf20Sopenharmony_ci } 9548c2ecf20Sopenharmony_ci /* check for DRDY, ATA devices set DRDY after SRST */ 9558c2ecf20Sopenharmony_ci else if (regs[ATA_REG_STATUS_OFFSET] & ATA_DRDY) { 9568c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Identified ATA device\n"); 9578c2ecf20Sopenharmony_ci info->DeviceFlags |= DF_ATA_DEVICE; 9588c2ecf20Sopenharmony_ci info->DeviceHead = master_slave; 9598c2ecf20Sopenharmony_ci break; 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci /* 9628c2ecf20Sopenharmony_ci * check Cylinder High/Low to 9638c2ecf20Sopenharmony_ci * determine if it is an ATAPI device 9648c2ecf20Sopenharmony_ci */ 9658c2ecf20Sopenharmony_ci else if (regs[ATA_REG_HCYL_OFFSET] == 0xEB && 9668c2ecf20Sopenharmony_ci regs[ATA_REG_LCYL_OFFSET] == 0x14) { 9678c2ecf20Sopenharmony_ci /* 9688c2ecf20Sopenharmony_ci * It seems that the RICOH 9698c2ecf20Sopenharmony_ci * MP6200A CD/RW drive will 9708c2ecf20Sopenharmony_ci * report itself okay as a 9718c2ecf20Sopenharmony_ci * slave when it is really a 9728c2ecf20Sopenharmony_ci * master. So this check again 9738c2ecf20Sopenharmony_ci * as a master device just to 9748c2ecf20Sopenharmony_ci * make sure it doesn't report 9758c2ecf20Sopenharmony_ci * itself okay as a master also 9768c2ecf20Sopenharmony_ci */ 9778c2ecf20Sopenharmony_ci if ((master_slave & ATA_ADDRESS_DEVHEAD_SLAVE) && 9788c2ecf20Sopenharmony_ci !recheckAsMaster) { 9798c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Identified ATAPI device as slave. Rechecking again as master\n"); 9808c2ecf20Sopenharmony_ci recheckAsMaster = 1; 9818c2ecf20Sopenharmony_ci master_slave = ATA_ADDRESS_DEVHEAD_STD; 9828c2ecf20Sopenharmony_ci } else { 9838c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Identified ATAPI device\n"); 9848c2ecf20Sopenharmony_ci info->DeviceHead = master_slave; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci status = isd200_atapi_soft_reset(us); 9878c2ecf20Sopenharmony_ci break; 9888c2ecf20Sopenharmony_ci } 9898c2ecf20Sopenharmony_ci } else { 9908c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Not ATA, not ATAPI - Weird\n"); 9918c2ecf20Sopenharmony_ci break; 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci /* check for timeout on this request */ 9958c2ecf20Sopenharmony_ci if (time_after_eq(jiffies, endTime)) { 9968c2ecf20Sopenharmony_ci if (!detect) 9978c2ecf20Sopenharmony_ci usb_stor_dbg(us, " BSY check timeout, just continue with next operation...\n"); 9988c2ecf20Sopenharmony_ci else 9998c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Device detect timeout!\n"); 10008c2ecf20Sopenharmony_ci break; 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci } 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci return status; 10058c2ecf20Sopenharmony_ci} 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci/************************************************************************** 10088c2ecf20Sopenharmony_ci * isd200_manual_enum 10098c2ecf20Sopenharmony_ci * 10108c2ecf20Sopenharmony_ci * Determines if the drive attached is an ATA or ATAPI and if it is a 10118c2ecf20Sopenharmony_ci * master or slave. 10128c2ecf20Sopenharmony_ci * 10138c2ecf20Sopenharmony_ci * RETURNS: 10148c2ecf20Sopenharmony_ci * ISD status code 10158c2ecf20Sopenharmony_ci */ 10168c2ecf20Sopenharmony_cistatic int isd200_manual_enum(struct us_data *us) 10178c2ecf20Sopenharmony_ci{ 10188c2ecf20Sopenharmony_ci struct isd200_info *info = (struct isd200_info *)us->extra; 10198c2ecf20Sopenharmony_ci int retStatus = ISD200_GOOD; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Entering isd200_manual_enum\n"); 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci retStatus = isd200_read_config(us); 10248c2ecf20Sopenharmony_ci if (retStatus == ISD200_GOOD) { 10258c2ecf20Sopenharmony_ci int isslave; 10268c2ecf20Sopenharmony_ci /* master or slave? */ 10278c2ecf20Sopenharmony_ci retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_STD, 0); 10288c2ecf20Sopenharmony_ci if (retStatus == ISD200_GOOD) 10298c2ecf20Sopenharmony_ci retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_SLAVE, 0); 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci if (retStatus == ISD200_GOOD) { 10328c2ecf20Sopenharmony_ci retStatus = isd200_srst(us); 10338c2ecf20Sopenharmony_ci if (retStatus == ISD200_GOOD) 10348c2ecf20Sopenharmony_ci /* ata or atapi? */ 10358c2ecf20Sopenharmony_ci retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_STD, 1); 10368c2ecf20Sopenharmony_ci } 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci isslave = (info->DeviceHead & ATA_ADDRESS_DEVHEAD_SLAVE) ? 1 : 0; 10398c2ecf20Sopenharmony_ci if (!(info->ConfigData.ATAConfig & ATACFG_MASTER)) { 10408c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Setting Master/Slave selection to %d\n", 10418c2ecf20Sopenharmony_ci isslave); 10428c2ecf20Sopenharmony_ci info->ConfigData.ATAConfig &= 0x3f; 10438c2ecf20Sopenharmony_ci info->ConfigData.ATAConfig |= (isslave<<6); 10448c2ecf20Sopenharmony_ci retStatus = isd200_write_config(us); 10458c2ecf20Sopenharmony_ci } 10468c2ecf20Sopenharmony_ci } 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Leaving isd200_manual_enum %08X\n", retStatus); 10498c2ecf20Sopenharmony_ci return(retStatus); 10508c2ecf20Sopenharmony_ci} 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_cistatic void isd200_fix_driveid(u16 *id) 10538c2ecf20Sopenharmony_ci{ 10548c2ecf20Sopenharmony_ci#ifndef __LITTLE_ENDIAN 10558c2ecf20Sopenharmony_ci# ifdef __BIG_ENDIAN 10568c2ecf20Sopenharmony_ci int i; 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci for (i = 0; i < ATA_ID_WORDS; i++) 10598c2ecf20Sopenharmony_ci id[i] = __le16_to_cpu(id[i]); 10608c2ecf20Sopenharmony_ci# else 10618c2ecf20Sopenharmony_ci# error "Please fix <asm/byteorder.h>" 10628c2ecf20Sopenharmony_ci# endif 10638c2ecf20Sopenharmony_ci#endif 10648c2ecf20Sopenharmony_ci} 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_cistatic void isd200_dump_driveid(struct us_data *us, u16 *id) 10678c2ecf20Sopenharmony_ci{ 10688c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Identify Data Structure:\n"); 10698c2ecf20Sopenharmony_ci usb_stor_dbg(us, " config = 0x%x\n", id[ATA_ID_CONFIG]); 10708c2ecf20Sopenharmony_ci usb_stor_dbg(us, " cyls = 0x%x\n", id[ATA_ID_CYLS]); 10718c2ecf20Sopenharmony_ci usb_stor_dbg(us, " heads = 0x%x\n", id[ATA_ID_HEADS]); 10728c2ecf20Sopenharmony_ci usb_stor_dbg(us, " track_bytes = 0x%x\n", id[4]); 10738c2ecf20Sopenharmony_ci usb_stor_dbg(us, " sector_bytes = 0x%x\n", id[5]); 10748c2ecf20Sopenharmony_ci usb_stor_dbg(us, " sectors = 0x%x\n", id[ATA_ID_SECTORS]); 10758c2ecf20Sopenharmony_ci usb_stor_dbg(us, " serial_no[0] = 0x%x\n", *(char *)&id[ATA_ID_SERNO]); 10768c2ecf20Sopenharmony_ci usb_stor_dbg(us, " buf_type = 0x%x\n", id[20]); 10778c2ecf20Sopenharmony_ci usb_stor_dbg(us, " buf_size = 0x%x\n", id[ATA_ID_BUF_SIZE]); 10788c2ecf20Sopenharmony_ci usb_stor_dbg(us, " ecc_bytes = 0x%x\n", id[22]); 10798c2ecf20Sopenharmony_ci usb_stor_dbg(us, " fw_rev[0] = 0x%x\n", *(char *)&id[ATA_ID_FW_REV]); 10808c2ecf20Sopenharmony_ci usb_stor_dbg(us, " model[0] = 0x%x\n", *(char *)&id[ATA_ID_PROD]); 10818c2ecf20Sopenharmony_ci usb_stor_dbg(us, " max_multsect = 0x%x\n", id[ATA_ID_MAX_MULTSECT] & 0xff); 10828c2ecf20Sopenharmony_ci usb_stor_dbg(us, " dword_io = 0x%x\n", id[ATA_ID_DWORD_IO]); 10838c2ecf20Sopenharmony_ci usb_stor_dbg(us, " capability = 0x%x\n", id[ATA_ID_CAPABILITY] >> 8); 10848c2ecf20Sopenharmony_ci usb_stor_dbg(us, " tPIO = 0x%x\n", id[ATA_ID_OLD_PIO_MODES] >> 8); 10858c2ecf20Sopenharmony_ci usb_stor_dbg(us, " tDMA = 0x%x\n", id[ATA_ID_OLD_DMA_MODES] >> 8); 10868c2ecf20Sopenharmony_ci usb_stor_dbg(us, " field_valid = 0x%x\n", id[ATA_ID_FIELD_VALID]); 10878c2ecf20Sopenharmony_ci usb_stor_dbg(us, " cur_cyls = 0x%x\n", id[ATA_ID_CUR_CYLS]); 10888c2ecf20Sopenharmony_ci usb_stor_dbg(us, " cur_heads = 0x%x\n", id[ATA_ID_CUR_HEADS]); 10898c2ecf20Sopenharmony_ci usb_stor_dbg(us, " cur_sectors = 0x%x\n", id[ATA_ID_CUR_SECTORS]); 10908c2ecf20Sopenharmony_ci usb_stor_dbg(us, " cur_capacity = 0x%x\n", ata_id_u32(id, 57)); 10918c2ecf20Sopenharmony_ci usb_stor_dbg(us, " multsect = 0x%x\n", id[ATA_ID_MULTSECT] & 0xff); 10928c2ecf20Sopenharmony_ci usb_stor_dbg(us, " lba_capacity = 0x%x\n", ata_id_u32(id, ATA_ID_LBA_CAPACITY)); 10938c2ecf20Sopenharmony_ci usb_stor_dbg(us, " command_set_1 = 0x%x\n", id[ATA_ID_COMMAND_SET_1]); 10948c2ecf20Sopenharmony_ci usb_stor_dbg(us, " command_set_2 = 0x%x\n", id[ATA_ID_COMMAND_SET_2]); 10958c2ecf20Sopenharmony_ci} 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci/************************************************************************** 10988c2ecf20Sopenharmony_ci * isd200_get_inquiry_data 10998c2ecf20Sopenharmony_ci * 11008c2ecf20Sopenharmony_ci * Get inquiry data 11018c2ecf20Sopenharmony_ci * 11028c2ecf20Sopenharmony_ci * RETURNS: 11038c2ecf20Sopenharmony_ci * ISD status code 11048c2ecf20Sopenharmony_ci */ 11058c2ecf20Sopenharmony_cistatic int isd200_get_inquiry_data( struct us_data *us ) 11068c2ecf20Sopenharmony_ci{ 11078c2ecf20Sopenharmony_ci struct isd200_info *info = (struct isd200_info *)us->extra; 11088c2ecf20Sopenharmony_ci int retStatus = ISD200_GOOD; 11098c2ecf20Sopenharmony_ci u16 *id = info->id; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Entering isd200_get_inquiry_data\n"); 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci /* set default to Master */ 11148c2ecf20Sopenharmony_ci info->DeviceHead = ATA_ADDRESS_DEVHEAD_STD; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci /* attempt to manually enumerate this device */ 11178c2ecf20Sopenharmony_ci retStatus = isd200_manual_enum(us); 11188c2ecf20Sopenharmony_ci if (retStatus == ISD200_GOOD) { 11198c2ecf20Sopenharmony_ci int transferStatus; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci /* check for an ATA device */ 11228c2ecf20Sopenharmony_ci if (info->DeviceFlags & DF_ATA_DEVICE) { 11238c2ecf20Sopenharmony_ci /* this must be an ATA device */ 11248c2ecf20Sopenharmony_ci /* perform an ATA Command Identify */ 11258c2ecf20Sopenharmony_ci transferStatus = isd200_action( us, ACTION_IDENTIFY, 11268c2ecf20Sopenharmony_ci id, ATA_ID_WORDS * 2); 11278c2ecf20Sopenharmony_ci if (transferStatus != ISD200_TRANSPORT_GOOD) { 11288c2ecf20Sopenharmony_ci /* Error issuing ATA Command Identify */ 11298c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Error issuing ATA Command Identify\n"); 11308c2ecf20Sopenharmony_ci retStatus = ISD200_ERROR; 11318c2ecf20Sopenharmony_ci } else { 11328c2ecf20Sopenharmony_ci /* ATA Command Identify successful */ 11338c2ecf20Sopenharmony_ci int i; 11348c2ecf20Sopenharmony_ci __be16 *src; 11358c2ecf20Sopenharmony_ci __u16 *dest; 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci isd200_fix_driveid(id); 11388c2ecf20Sopenharmony_ci isd200_dump_driveid(us, id); 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci memset(&info->InquiryData, 0, sizeof(info->InquiryData)); 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci /* Standard IDE interface only supports disks */ 11438c2ecf20Sopenharmony_ci info->InquiryData.DeviceType = DIRECT_ACCESS_DEVICE; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci /* The length must be at least 36 (5 + 31) */ 11468c2ecf20Sopenharmony_ci info->InquiryData.AdditionalLength = 0x1F; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci if (id[ATA_ID_COMMAND_SET_1] & COMMANDSET_MEDIA_STATUS) { 11498c2ecf20Sopenharmony_ci /* set the removable bit */ 11508c2ecf20Sopenharmony_ci info->InquiryData.DeviceTypeModifier = DEVICE_REMOVABLE; 11518c2ecf20Sopenharmony_ci info->DeviceFlags |= DF_REMOVABLE_MEDIA; 11528c2ecf20Sopenharmony_ci } 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci /* Fill in vendor identification fields */ 11558c2ecf20Sopenharmony_ci src = (__be16 *)&id[ATA_ID_PROD]; 11568c2ecf20Sopenharmony_ci dest = (__u16*)info->InquiryData.VendorId; 11578c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) 11588c2ecf20Sopenharmony_ci dest[i] = be16_to_cpu(src[i]); 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci src = (__be16 *)&id[ATA_ID_PROD + 8/2]; 11618c2ecf20Sopenharmony_ci dest = (__u16*)info->InquiryData.ProductId; 11628c2ecf20Sopenharmony_ci for (i=0;i<8;i++) 11638c2ecf20Sopenharmony_ci dest[i] = be16_to_cpu(src[i]); 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci src = (__be16 *)&id[ATA_ID_FW_REV]; 11668c2ecf20Sopenharmony_ci dest = (__u16*)info->InquiryData.ProductRevisionLevel; 11678c2ecf20Sopenharmony_ci for (i=0;i<2;i++) 11688c2ecf20Sopenharmony_ci dest[i] = be16_to_cpu(src[i]); 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci /* determine if it supports Media Status Notification */ 11718c2ecf20Sopenharmony_ci if (id[ATA_ID_COMMAND_SET_2] & COMMANDSET_MEDIA_STATUS) { 11728c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Device supports Media Status Notification\n"); 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci /* 11758c2ecf20Sopenharmony_ci * Indicate that it is enabled, even 11768c2ecf20Sopenharmony_ci * though it is not. 11778c2ecf20Sopenharmony_ci * This allows the lock/unlock of the 11788c2ecf20Sopenharmony_ci * media to work correctly. 11798c2ecf20Sopenharmony_ci */ 11808c2ecf20Sopenharmony_ci info->DeviceFlags |= DF_MEDIA_STATUS_ENABLED; 11818c2ecf20Sopenharmony_ci } 11828c2ecf20Sopenharmony_ci else 11838c2ecf20Sopenharmony_ci info->DeviceFlags &= ~DF_MEDIA_STATUS_ENABLED; 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci } 11868c2ecf20Sopenharmony_ci } else { 11878c2ecf20Sopenharmony_ci /* 11888c2ecf20Sopenharmony_ci * this must be an ATAPI device 11898c2ecf20Sopenharmony_ci * use an ATAPI protocol (Transparent SCSI) 11908c2ecf20Sopenharmony_ci */ 11918c2ecf20Sopenharmony_ci us->protocol_name = "Transparent SCSI"; 11928c2ecf20Sopenharmony_ci us->proto_handler = usb_stor_transparent_scsi_command; 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Protocol changed to: %s\n", 11958c2ecf20Sopenharmony_ci us->protocol_name); 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci /* Free driver structure */ 11988c2ecf20Sopenharmony_ci us->extra_destructor(info); 11998c2ecf20Sopenharmony_ci kfree(info); 12008c2ecf20Sopenharmony_ci us->extra = NULL; 12018c2ecf20Sopenharmony_ci us->extra_destructor = NULL; 12028c2ecf20Sopenharmony_ci } 12038c2ecf20Sopenharmony_ci } 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Leaving isd200_get_inquiry_data %08X\n", retStatus); 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci return(retStatus); 12088c2ecf20Sopenharmony_ci} 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci/************************************************************************** 12118c2ecf20Sopenharmony_ci * isd200_scsi_to_ata 12128c2ecf20Sopenharmony_ci * 12138c2ecf20Sopenharmony_ci * Translate SCSI commands to ATA commands. 12148c2ecf20Sopenharmony_ci * 12158c2ecf20Sopenharmony_ci * RETURNS: 12168c2ecf20Sopenharmony_ci * 1 if the command needs to be sent to the transport layer 12178c2ecf20Sopenharmony_ci * 0 otherwise 12188c2ecf20Sopenharmony_ci */ 12198c2ecf20Sopenharmony_cistatic int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, 12208c2ecf20Sopenharmony_ci union ata_cdb * ataCdb) 12218c2ecf20Sopenharmony_ci{ 12228c2ecf20Sopenharmony_ci struct isd200_info *info = (struct isd200_info *)us->extra; 12238c2ecf20Sopenharmony_ci u16 *id = info->id; 12248c2ecf20Sopenharmony_ci int sendToTransport = 1; 12258c2ecf20Sopenharmony_ci unsigned char sectnum, head; 12268c2ecf20Sopenharmony_ci unsigned short cylinder; 12278c2ecf20Sopenharmony_ci unsigned long lba; 12288c2ecf20Sopenharmony_ci unsigned long blockCount; 12298c2ecf20Sopenharmony_ci unsigned char senseData[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci memset(ataCdb, 0, sizeof(union ata_cdb)); 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci /* SCSI Command */ 12348c2ecf20Sopenharmony_ci switch (srb->cmnd[0]) { 12358c2ecf20Sopenharmony_ci case INQUIRY: 12368c2ecf20Sopenharmony_ci usb_stor_dbg(us, " ATA OUT - INQUIRY\n"); 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci /* copy InquiryData */ 12398c2ecf20Sopenharmony_ci usb_stor_set_xfer_buf((unsigned char *) &info->InquiryData, 12408c2ecf20Sopenharmony_ci sizeof(info->InquiryData), srb); 12418c2ecf20Sopenharmony_ci srb->result = SAM_STAT_GOOD; 12428c2ecf20Sopenharmony_ci sendToTransport = 0; 12438c2ecf20Sopenharmony_ci break; 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci case MODE_SENSE: 12468c2ecf20Sopenharmony_ci usb_stor_dbg(us, " ATA OUT - SCSIOP_MODE_SENSE\n"); 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci /* Initialize the return buffer */ 12498c2ecf20Sopenharmony_ci usb_stor_set_xfer_buf(senseData, sizeof(senseData), srb); 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci if (info->DeviceFlags & DF_MEDIA_STATUS_ENABLED) 12528c2ecf20Sopenharmony_ci { 12538c2ecf20Sopenharmony_ci ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; 12548c2ecf20Sopenharmony_ci ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; 12558c2ecf20Sopenharmony_ci ataCdb->generic.TransferBlockSize = 1; 12568c2ecf20Sopenharmony_ci ataCdb->generic.RegisterSelect = REG_COMMAND; 12578c2ecf20Sopenharmony_ci ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; 12588c2ecf20Sopenharmony_ci isd200_srb_set_bufflen(srb, 0); 12598c2ecf20Sopenharmony_ci } else { 12608c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Media Status not supported, just report okay\n"); 12618c2ecf20Sopenharmony_ci srb->result = SAM_STAT_GOOD; 12628c2ecf20Sopenharmony_ci sendToTransport = 0; 12638c2ecf20Sopenharmony_ci } 12648c2ecf20Sopenharmony_ci break; 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci case TEST_UNIT_READY: 12678c2ecf20Sopenharmony_ci usb_stor_dbg(us, " ATA OUT - SCSIOP_TEST_UNIT_READY\n"); 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci if (info->DeviceFlags & DF_MEDIA_STATUS_ENABLED) 12708c2ecf20Sopenharmony_ci { 12718c2ecf20Sopenharmony_ci ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; 12728c2ecf20Sopenharmony_ci ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; 12738c2ecf20Sopenharmony_ci ataCdb->generic.TransferBlockSize = 1; 12748c2ecf20Sopenharmony_ci ataCdb->generic.RegisterSelect = REG_COMMAND; 12758c2ecf20Sopenharmony_ci ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; 12768c2ecf20Sopenharmony_ci isd200_srb_set_bufflen(srb, 0); 12778c2ecf20Sopenharmony_ci } else { 12788c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Media Status not supported, just report okay\n"); 12798c2ecf20Sopenharmony_ci srb->result = SAM_STAT_GOOD; 12808c2ecf20Sopenharmony_ci sendToTransport = 0; 12818c2ecf20Sopenharmony_ci } 12828c2ecf20Sopenharmony_ci break; 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci case READ_CAPACITY: 12858c2ecf20Sopenharmony_ci { 12868c2ecf20Sopenharmony_ci unsigned long capacity; 12878c2ecf20Sopenharmony_ci struct read_capacity_data readCapacityData; 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci usb_stor_dbg(us, " ATA OUT - SCSIOP_READ_CAPACITY\n"); 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci if (ata_id_has_lba(id)) 12928c2ecf20Sopenharmony_ci capacity = ata_id_u32(id, ATA_ID_LBA_CAPACITY) - 1; 12938c2ecf20Sopenharmony_ci else 12948c2ecf20Sopenharmony_ci capacity = (id[ATA_ID_HEADS] * id[ATA_ID_CYLS] * 12958c2ecf20Sopenharmony_ci id[ATA_ID_SECTORS]) - 1; 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci readCapacityData.LogicalBlockAddress = cpu_to_be32(capacity); 12988c2ecf20Sopenharmony_ci readCapacityData.BytesPerBlock = cpu_to_be32(0x200); 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci usb_stor_set_xfer_buf((unsigned char *) &readCapacityData, 13018c2ecf20Sopenharmony_ci sizeof(readCapacityData), srb); 13028c2ecf20Sopenharmony_ci srb->result = SAM_STAT_GOOD; 13038c2ecf20Sopenharmony_ci sendToTransport = 0; 13048c2ecf20Sopenharmony_ci } 13058c2ecf20Sopenharmony_ci break; 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci case READ_10: 13088c2ecf20Sopenharmony_ci usb_stor_dbg(us, " ATA OUT - SCSIOP_READ\n"); 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci lba = be32_to_cpu(*(__be32 *)&srb->cmnd[2]); 13118c2ecf20Sopenharmony_ci blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8]; 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci if (ata_id_has_lba(id)) { 13148c2ecf20Sopenharmony_ci sectnum = (unsigned char)(lba); 13158c2ecf20Sopenharmony_ci cylinder = (unsigned short)(lba>>8); 13168c2ecf20Sopenharmony_ci head = ATA_ADDRESS_DEVHEAD_LBA_MODE | (unsigned char)(lba>>24 & 0x0F); 13178c2ecf20Sopenharmony_ci } else { 13188c2ecf20Sopenharmony_ci sectnum = (u8)((lba % id[ATA_ID_SECTORS]) + 1); 13198c2ecf20Sopenharmony_ci cylinder = (u16)(lba / (id[ATA_ID_SECTORS] * 13208c2ecf20Sopenharmony_ci id[ATA_ID_HEADS])); 13218c2ecf20Sopenharmony_ci head = (u8)((lba / id[ATA_ID_SECTORS]) % 13228c2ecf20Sopenharmony_ci id[ATA_ID_HEADS]); 13238c2ecf20Sopenharmony_ci } 13248c2ecf20Sopenharmony_ci ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; 13258c2ecf20Sopenharmony_ci ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; 13268c2ecf20Sopenharmony_ci ataCdb->generic.TransferBlockSize = 1; 13278c2ecf20Sopenharmony_ci ataCdb->generic.RegisterSelect = 13288c2ecf20Sopenharmony_ci REG_SECTOR_COUNT | REG_SECTOR_NUMBER | 13298c2ecf20Sopenharmony_ci REG_CYLINDER_LOW | REG_CYLINDER_HIGH | 13308c2ecf20Sopenharmony_ci REG_DEVICE_HEAD | REG_COMMAND; 13318c2ecf20Sopenharmony_ci ataCdb->write.SectorCountByte = (unsigned char)blockCount; 13328c2ecf20Sopenharmony_ci ataCdb->write.SectorNumberByte = sectnum; 13338c2ecf20Sopenharmony_ci ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8); 13348c2ecf20Sopenharmony_ci ataCdb->write.CylinderLowByte = (unsigned char)cylinder; 13358c2ecf20Sopenharmony_ci ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD); 13368c2ecf20Sopenharmony_ci ataCdb->write.CommandByte = ATA_CMD_PIO_READ; 13378c2ecf20Sopenharmony_ci break; 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci case WRITE_10: 13408c2ecf20Sopenharmony_ci usb_stor_dbg(us, " ATA OUT - SCSIOP_WRITE\n"); 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci lba = be32_to_cpu(*(__be32 *)&srb->cmnd[2]); 13438c2ecf20Sopenharmony_ci blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8]; 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci if (ata_id_has_lba(id)) { 13468c2ecf20Sopenharmony_ci sectnum = (unsigned char)(lba); 13478c2ecf20Sopenharmony_ci cylinder = (unsigned short)(lba>>8); 13488c2ecf20Sopenharmony_ci head = ATA_ADDRESS_DEVHEAD_LBA_MODE | (unsigned char)(lba>>24 & 0x0F); 13498c2ecf20Sopenharmony_ci } else { 13508c2ecf20Sopenharmony_ci sectnum = (u8)((lba % id[ATA_ID_SECTORS]) + 1); 13518c2ecf20Sopenharmony_ci cylinder = (u16)(lba / (id[ATA_ID_SECTORS] * 13528c2ecf20Sopenharmony_ci id[ATA_ID_HEADS])); 13538c2ecf20Sopenharmony_ci head = (u8)((lba / id[ATA_ID_SECTORS]) % 13548c2ecf20Sopenharmony_ci id[ATA_ID_HEADS]); 13558c2ecf20Sopenharmony_ci } 13568c2ecf20Sopenharmony_ci ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; 13578c2ecf20Sopenharmony_ci ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; 13588c2ecf20Sopenharmony_ci ataCdb->generic.TransferBlockSize = 1; 13598c2ecf20Sopenharmony_ci ataCdb->generic.RegisterSelect = 13608c2ecf20Sopenharmony_ci REG_SECTOR_COUNT | REG_SECTOR_NUMBER | 13618c2ecf20Sopenharmony_ci REG_CYLINDER_LOW | REG_CYLINDER_HIGH | 13628c2ecf20Sopenharmony_ci REG_DEVICE_HEAD | REG_COMMAND; 13638c2ecf20Sopenharmony_ci ataCdb->write.SectorCountByte = (unsigned char)blockCount; 13648c2ecf20Sopenharmony_ci ataCdb->write.SectorNumberByte = sectnum; 13658c2ecf20Sopenharmony_ci ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8); 13668c2ecf20Sopenharmony_ci ataCdb->write.CylinderLowByte = (unsigned char)cylinder; 13678c2ecf20Sopenharmony_ci ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD); 13688c2ecf20Sopenharmony_ci ataCdb->write.CommandByte = ATA_CMD_PIO_WRITE; 13698c2ecf20Sopenharmony_ci break; 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci case ALLOW_MEDIUM_REMOVAL: 13728c2ecf20Sopenharmony_ci usb_stor_dbg(us, " ATA OUT - SCSIOP_MEDIUM_REMOVAL\n"); 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci if (info->DeviceFlags & DF_REMOVABLE_MEDIA) { 13758c2ecf20Sopenharmony_ci usb_stor_dbg(us, " srb->cmnd[4] = 0x%X\n", 13768c2ecf20Sopenharmony_ci srb->cmnd[4]); 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; 13798c2ecf20Sopenharmony_ci ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; 13808c2ecf20Sopenharmony_ci ataCdb->generic.TransferBlockSize = 1; 13818c2ecf20Sopenharmony_ci ataCdb->generic.RegisterSelect = REG_COMMAND; 13828c2ecf20Sopenharmony_ci ataCdb->write.CommandByte = (srb->cmnd[4] & 0x1) ? 13838c2ecf20Sopenharmony_ci ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK; 13848c2ecf20Sopenharmony_ci isd200_srb_set_bufflen(srb, 0); 13858c2ecf20Sopenharmony_ci } else { 13868c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Not removable media, just report okay\n"); 13878c2ecf20Sopenharmony_ci srb->result = SAM_STAT_GOOD; 13888c2ecf20Sopenharmony_ci sendToTransport = 0; 13898c2ecf20Sopenharmony_ci } 13908c2ecf20Sopenharmony_ci break; 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci case START_STOP: 13938c2ecf20Sopenharmony_ci usb_stor_dbg(us, " ATA OUT - SCSIOP_START_STOP_UNIT\n"); 13948c2ecf20Sopenharmony_ci usb_stor_dbg(us, " srb->cmnd[4] = 0x%X\n", srb->cmnd[4]); 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci if ((srb->cmnd[4] & 0x3) == 0x2) { 13978c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Media Eject\n"); 13988c2ecf20Sopenharmony_ci ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; 13998c2ecf20Sopenharmony_ci ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; 14008c2ecf20Sopenharmony_ci ataCdb->generic.TransferBlockSize = 0; 14018c2ecf20Sopenharmony_ci ataCdb->generic.RegisterSelect = REG_COMMAND; 14028c2ecf20Sopenharmony_ci ataCdb->write.CommandByte = ATA_COMMAND_MEDIA_EJECT; 14038c2ecf20Sopenharmony_ci } else if ((srb->cmnd[4] & 0x3) == 0x1) { 14048c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Get Media Status\n"); 14058c2ecf20Sopenharmony_ci ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; 14068c2ecf20Sopenharmony_ci ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; 14078c2ecf20Sopenharmony_ci ataCdb->generic.TransferBlockSize = 1; 14088c2ecf20Sopenharmony_ci ataCdb->generic.RegisterSelect = REG_COMMAND; 14098c2ecf20Sopenharmony_ci ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; 14108c2ecf20Sopenharmony_ci isd200_srb_set_bufflen(srb, 0); 14118c2ecf20Sopenharmony_ci } else { 14128c2ecf20Sopenharmony_ci usb_stor_dbg(us, " Nothing to do, just report okay\n"); 14138c2ecf20Sopenharmony_ci srb->result = SAM_STAT_GOOD; 14148c2ecf20Sopenharmony_ci sendToTransport = 0; 14158c2ecf20Sopenharmony_ci } 14168c2ecf20Sopenharmony_ci break; 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci default: 14198c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Unsupported SCSI command - 0x%X\n", 14208c2ecf20Sopenharmony_ci srb->cmnd[0]); 14218c2ecf20Sopenharmony_ci srb->result = DID_ERROR << 16; 14228c2ecf20Sopenharmony_ci sendToTransport = 0; 14238c2ecf20Sopenharmony_ci break; 14248c2ecf20Sopenharmony_ci } 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci return(sendToTransport); 14278c2ecf20Sopenharmony_ci} 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci/************************************************************************** 14318c2ecf20Sopenharmony_ci * isd200_free_info 14328c2ecf20Sopenharmony_ci * 14338c2ecf20Sopenharmony_ci * Frees the driver structure. 14348c2ecf20Sopenharmony_ci */ 14358c2ecf20Sopenharmony_cistatic void isd200_free_info_ptrs(void *info_) 14368c2ecf20Sopenharmony_ci{ 14378c2ecf20Sopenharmony_ci struct isd200_info *info = (struct isd200_info *) info_; 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci if (info) { 14408c2ecf20Sopenharmony_ci kfree(info->id); 14418c2ecf20Sopenharmony_ci kfree(info->RegsBuf); 14428c2ecf20Sopenharmony_ci kfree(info->srb.sense_buffer); 14438c2ecf20Sopenharmony_ci } 14448c2ecf20Sopenharmony_ci} 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci/************************************************************************** 14478c2ecf20Sopenharmony_ci * isd200_init_info 14488c2ecf20Sopenharmony_ci * 14498c2ecf20Sopenharmony_ci * Allocates (if necessary) and initializes the driver structure. 14508c2ecf20Sopenharmony_ci * 14518c2ecf20Sopenharmony_ci * RETURNS: 14528c2ecf20Sopenharmony_ci * ISD status code 14538c2ecf20Sopenharmony_ci */ 14548c2ecf20Sopenharmony_cistatic int isd200_init_info(struct us_data *us) 14558c2ecf20Sopenharmony_ci{ 14568c2ecf20Sopenharmony_ci struct isd200_info *info; 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci info = kzalloc(sizeof(struct isd200_info), GFP_KERNEL); 14598c2ecf20Sopenharmony_ci if (!info) 14608c2ecf20Sopenharmony_ci return ISD200_ERROR; 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci info->id = kzalloc(ATA_ID_WORDS * 2, GFP_KERNEL); 14638c2ecf20Sopenharmony_ci info->RegsBuf = kmalloc(sizeof(info->ATARegs), GFP_KERNEL); 14648c2ecf20Sopenharmony_ci info->srb.sense_buffer = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci if (!info->id || !info->RegsBuf || !info->srb.sense_buffer) { 14678c2ecf20Sopenharmony_ci isd200_free_info_ptrs(info); 14688c2ecf20Sopenharmony_ci kfree(info); 14698c2ecf20Sopenharmony_ci return ISD200_ERROR; 14708c2ecf20Sopenharmony_ci } 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci us->extra = info; 14738c2ecf20Sopenharmony_ci us->extra_destructor = isd200_free_info_ptrs; 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci return ISD200_GOOD; 14768c2ecf20Sopenharmony_ci} 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci/************************************************************************** 14798c2ecf20Sopenharmony_ci * Initialization for the ISD200 14808c2ecf20Sopenharmony_ci */ 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_cistatic int isd200_Initialization(struct us_data *us) 14838c2ecf20Sopenharmony_ci{ 14848c2ecf20Sopenharmony_ci usb_stor_dbg(us, "ISD200 Initialization...\n"); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci /* Initialize ISD200 info struct */ 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci if (isd200_init_info(us) == ISD200_ERROR) { 14898c2ecf20Sopenharmony_ci usb_stor_dbg(us, "ERROR Initializing ISD200 Info struct\n"); 14908c2ecf20Sopenharmony_ci } else { 14918c2ecf20Sopenharmony_ci /* Get device specific data */ 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci if (isd200_get_inquiry_data(us) != ISD200_GOOD) 14948c2ecf20Sopenharmony_ci usb_stor_dbg(us, "ISD200 Initialization Failure\n"); 14958c2ecf20Sopenharmony_ci else 14968c2ecf20Sopenharmony_ci usb_stor_dbg(us, "ISD200 Initialization complete\n"); 14978c2ecf20Sopenharmony_ci } 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci return 0; 15008c2ecf20Sopenharmony_ci} 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci/************************************************************************** 15048c2ecf20Sopenharmony_ci * Protocol and Transport for the ISD200 ASIC 15058c2ecf20Sopenharmony_ci * 15068c2ecf20Sopenharmony_ci * This protocol and transport are for ATA devices connected to an ISD200 15078c2ecf20Sopenharmony_ci * ASIC. An ATAPI device that is connected as a slave device will be 15088c2ecf20Sopenharmony_ci * detected in the driver initialization function and the protocol will 15098c2ecf20Sopenharmony_ci * be changed to an ATAPI protocol (Transparent SCSI). 15108c2ecf20Sopenharmony_ci * 15118c2ecf20Sopenharmony_ci */ 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_cistatic void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us) 15148c2ecf20Sopenharmony_ci{ 15158c2ecf20Sopenharmony_ci int sendToTransport, orig_bufflen; 15168c2ecf20Sopenharmony_ci union ata_cdb ataCdb; 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci /* Make sure driver was initialized */ 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci if (us->extra == NULL) { 15218c2ecf20Sopenharmony_ci usb_stor_dbg(us, "ERROR Driver not initialized\n"); 15228c2ecf20Sopenharmony_ci srb->result = DID_ERROR << 16; 15238c2ecf20Sopenharmony_ci return; 15248c2ecf20Sopenharmony_ci } 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci scsi_set_resid(srb, 0); 15278c2ecf20Sopenharmony_ci /* scsi_bufflen might change in protocol translation to ata */ 15288c2ecf20Sopenharmony_ci orig_bufflen = scsi_bufflen(srb); 15298c2ecf20Sopenharmony_ci sendToTransport = isd200_scsi_to_ata(srb, us, &ataCdb); 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci /* send the command to the transport layer */ 15328c2ecf20Sopenharmony_ci if (sendToTransport) 15338c2ecf20Sopenharmony_ci isd200_invoke_transport(us, srb, &ataCdb); 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci isd200_srb_set_bufflen(srb, orig_bufflen); 15368c2ecf20Sopenharmony_ci} 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_cistatic struct scsi_host_template isd200_host_template; 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_cistatic int isd200_probe(struct usb_interface *intf, 15418c2ecf20Sopenharmony_ci const struct usb_device_id *id) 15428c2ecf20Sopenharmony_ci{ 15438c2ecf20Sopenharmony_ci struct us_data *us; 15448c2ecf20Sopenharmony_ci int result; 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci result = usb_stor_probe1(&us, intf, id, 15478c2ecf20Sopenharmony_ci (id - isd200_usb_ids) + isd200_unusual_dev_list, 15488c2ecf20Sopenharmony_ci &isd200_host_template); 15498c2ecf20Sopenharmony_ci if (result) 15508c2ecf20Sopenharmony_ci return result; 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci us->protocol_name = "ISD200 ATA/ATAPI"; 15538c2ecf20Sopenharmony_ci us->proto_handler = isd200_ata_command; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci result = usb_stor_probe2(us); 15568c2ecf20Sopenharmony_ci return result; 15578c2ecf20Sopenharmony_ci} 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_cistatic struct usb_driver isd200_driver = { 15608c2ecf20Sopenharmony_ci .name = DRV_NAME, 15618c2ecf20Sopenharmony_ci .probe = isd200_probe, 15628c2ecf20Sopenharmony_ci .disconnect = usb_stor_disconnect, 15638c2ecf20Sopenharmony_ci .suspend = usb_stor_suspend, 15648c2ecf20Sopenharmony_ci .resume = usb_stor_resume, 15658c2ecf20Sopenharmony_ci .reset_resume = usb_stor_reset_resume, 15668c2ecf20Sopenharmony_ci .pre_reset = usb_stor_pre_reset, 15678c2ecf20Sopenharmony_ci .post_reset = usb_stor_post_reset, 15688c2ecf20Sopenharmony_ci .id_table = isd200_usb_ids, 15698c2ecf20Sopenharmony_ci .soft_unbind = 1, 15708c2ecf20Sopenharmony_ci .no_dynamic_id = 1, 15718c2ecf20Sopenharmony_ci}; 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_cimodule_usb_stor_driver(isd200_driver, isd200_host_template, DRV_NAME); 1574