162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Transport & Protocol Driver for In-System Design, Inc. ISD200 ASIC 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Current development and maintenance: 662306a36Sopenharmony_ci * (C) 2001-2002 Björn Stenberg (bjorn@haxx.se) 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Developed with the assistance of: 962306a36Sopenharmony_ci * (C) 2002 Alan Stern <stern@rowland.org> 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Initial work: 1262306a36Sopenharmony_ci * (C) 2000 In-System Design, Inc. (support@in-system.com) 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * The ISD200 ASIC does not natively support ATA devices. The chip 1562306a36Sopenharmony_ci * does implement an interface, the ATA Command Block (ATACB) which provides 1662306a36Sopenharmony_ci * a means of passing ATA commands and ATA register accesses to a device. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * History: 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * 2002-10-19: Removed the specialized transfer routines. 2162306a36Sopenharmony_ci * (Alan Stern <stern@rowland.harvard.edu>) 2262306a36Sopenharmony_ci * 2001-02-24: Removed lots of duplicate code and simplified the structure. 2362306a36Sopenharmony_ci * (bjorn@haxx.se) 2462306a36Sopenharmony_ci * 2002-01-16: Fixed endianness bug so it works on the ppc arch. 2562306a36Sopenharmony_ci * (Luc Saillard <luc@saillard.org>) 2662306a36Sopenharmony_ci * 2002-01-17: All bitfields removed. 2762306a36Sopenharmony_ci * (bjorn@haxx.se) 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* Include files */ 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include <linux/jiffies.h> 3462306a36Sopenharmony_ci#include <linux/errno.h> 3562306a36Sopenharmony_ci#include <linux/module.h> 3662306a36Sopenharmony_ci#include <linux/slab.h> 3762306a36Sopenharmony_ci#include <linux/ata.h> 3862306a36Sopenharmony_ci#include <linux/hdreg.h> 3962306a36Sopenharmony_ci#include <linux/scatterlist.h> 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#include <scsi/scsi.h> 4262306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h> 4362306a36Sopenharmony_ci#include <scsi/scsi_device.h> 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#include "usb.h" 4662306a36Sopenharmony_ci#include "transport.h" 4762306a36Sopenharmony_ci#include "protocol.h" 4862306a36Sopenharmony_ci#include "debug.h" 4962306a36Sopenharmony_ci#include "scsiglue.h" 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#define DRV_NAME "ums-isd200" 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver for In-System Design, Inc. ISD200 ASIC"); 5462306a36Sopenharmony_ciMODULE_AUTHOR("Björn Stenberg <bjorn@haxx.se>"); 5562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 5662306a36Sopenharmony_ciMODULE_IMPORT_NS(USB_STORAGE); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic int isd200_Initialization(struct us_data *us); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* 6262306a36Sopenharmony_ci * The table of devices 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_ci#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ 6562306a36Sopenharmony_ci vendorName, productName, useProtocol, useTransport, \ 6662306a36Sopenharmony_ci initFunction, flags) \ 6762306a36Sopenharmony_ci{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ 6862306a36Sopenharmony_ci .driver_info = (flags) } 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic struct usb_device_id isd200_usb_ids[] = { 7162306a36Sopenharmony_ci# include "unusual_isd200.h" 7262306a36Sopenharmony_ci { } /* Terminating entry */ 7362306a36Sopenharmony_ci}; 7462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, isd200_usb_ids); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#undef UNUSUAL_DEV 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/* 7962306a36Sopenharmony_ci * The flags table 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_ci#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ 8262306a36Sopenharmony_ci vendor_name, product_name, use_protocol, use_transport, \ 8362306a36Sopenharmony_ci init_function, Flags) \ 8462306a36Sopenharmony_ci{ \ 8562306a36Sopenharmony_ci .vendorName = vendor_name, \ 8662306a36Sopenharmony_ci .productName = product_name, \ 8762306a36Sopenharmony_ci .useProtocol = use_protocol, \ 8862306a36Sopenharmony_ci .useTransport = use_transport, \ 8962306a36Sopenharmony_ci .initFunction = init_function, \ 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic struct us_unusual_dev isd200_unusual_dev_list[] = { 9362306a36Sopenharmony_ci# include "unusual_isd200.h" 9462306a36Sopenharmony_ci { } /* Terminating entry */ 9562306a36Sopenharmony_ci}; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci#undef UNUSUAL_DEV 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/* Timeout defines (in Seconds) */ 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci#define ISD200_ENUM_BSY_TIMEOUT 35 10262306a36Sopenharmony_ci#define ISD200_ENUM_DETECT_TIMEOUT 30 10362306a36Sopenharmony_ci#define ISD200_DEFAULT_TIMEOUT 30 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/* device flags */ 10662306a36Sopenharmony_ci#define DF_ATA_DEVICE 0x0001 10762306a36Sopenharmony_ci#define DF_MEDIA_STATUS_ENABLED 0x0002 10862306a36Sopenharmony_ci#define DF_REMOVABLE_MEDIA 0x0004 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci/* capability bit definitions */ 11162306a36Sopenharmony_ci#define CAPABILITY_DMA 0x01 11262306a36Sopenharmony_ci#define CAPABILITY_LBA 0x02 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci/* command_setX bit definitions */ 11562306a36Sopenharmony_ci#define COMMANDSET_REMOVABLE 0x02 11662306a36Sopenharmony_ci#define COMMANDSET_MEDIA_STATUS 0x10 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci/* ATA Vendor Specific defines */ 11962306a36Sopenharmony_ci#define ATA_ADDRESS_DEVHEAD_STD 0xa0 12062306a36Sopenharmony_ci#define ATA_ADDRESS_DEVHEAD_LBA_MODE 0x40 12162306a36Sopenharmony_ci#define ATA_ADDRESS_DEVHEAD_SLAVE 0x10 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci/* Action Select bits */ 12462306a36Sopenharmony_ci#define ACTION_SELECT_0 0x01 12562306a36Sopenharmony_ci#define ACTION_SELECT_1 0x02 12662306a36Sopenharmony_ci#define ACTION_SELECT_2 0x04 12762306a36Sopenharmony_ci#define ACTION_SELECT_3 0x08 12862306a36Sopenharmony_ci#define ACTION_SELECT_4 0x10 12962306a36Sopenharmony_ci#define ACTION_SELECT_5 0x20 13062306a36Sopenharmony_ci#define ACTION_SELECT_6 0x40 13162306a36Sopenharmony_ci#define ACTION_SELECT_7 0x80 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci/* Register Select bits */ 13462306a36Sopenharmony_ci#define REG_ALTERNATE_STATUS 0x01 13562306a36Sopenharmony_ci#define REG_DEVICE_CONTROL 0x01 13662306a36Sopenharmony_ci#define REG_ERROR 0x02 13762306a36Sopenharmony_ci#define REG_FEATURES 0x02 13862306a36Sopenharmony_ci#define REG_SECTOR_COUNT 0x04 13962306a36Sopenharmony_ci#define REG_SECTOR_NUMBER 0x08 14062306a36Sopenharmony_ci#define REG_CYLINDER_LOW 0x10 14162306a36Sopenharmony_ci#define REG_CYLINDER_HIGH 0x20 14262306a36Sopenharmony_ci#define REG_DEVICE_HEAD 0x40 14362306a36Sopenharmony_ci#define REG_STATUS 0x80 14462306a36Sopenharmony_ci#define REG_COMMAND 0x80 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci/* ATA registers offset definitions */ 14762306a36Sopenharmony_ci#define ATA_REG_ERROR_OFFSET 1 14862306a36Sopenharmony_ci#define ATA_REG_LCYL_OFFSET 4 14962306a36Sopenharmony_ci#define ATA_REG_HCYL_OFFSET 5 15062306a36Sopenharmony_ci#define ATA_REG_STATUS_OFFSET 7 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci/* ATA error definitions not in <linux/hdreg.h> */ 15362306a36Sopenharmony_ci#define ATA_ERROR_MEDIA_CHANGE 0x20 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/* ATA command definitions not in <linux/hdreg.h> */ 15662306a36Sopenharmony_ci#define ATA_COMMAND_GET_MEDIA_STATUS 0xDA 15762306a36Sopenharmony_ci#define ATA_COMMAND_MEDIA_EJECT 0xED 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci/* ATA drive control definitions */ 16062306a36Sopenharmony_ci#define ATA_DC_DISABLE_INTERRUPTS 0x02 16162306a36Sopenharmony_ci#define ATA_DC_RESET_CONTROLLER 0x04 16262306a36Sopenharmony_ci#define ATA_DC_REENABLE_CONTROLLER 0x00 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci/* 16562306a36Sopenharmony_ci * General purpose return codes 16662306a36Sopenharmony_ci */ 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci#define ISD200_ERROR -1 16962306a36Sopenharmony_ci#define ISD200_GOOD 0 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci/* 17262306a36Sopenharmony_ci * Transport return codes 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci#define ISD200_TRANSPORT_GOOD 0 /* Transport good, command good */ 17662306a36Sopenharmony_ci#define ISD200_TRANSPORT_FAILED 1 /* Transport good, command failed */ 17762306a36Sopenharmony_ci#define ISD200_TRANSPORT_ERROR 2 /* Transport bad (i.e. device dead) */ 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci/* driver action codes */ 18062306a36Sopenharmony_ci#define ACTION_READ_STATUS 0 18162306a36Sopenharmony_ci#define ACTION_RESET 1 18262306a36Sopenharmony_ci#define ACTION_REENABLE 2 18362306a36Sopenharmony_ci#define ACTION_SOFT_RESET 3 18462306a36Sopenharmony_ci#define ACTION_ENUM 4 18562306a36Sopenharmony_ci#define ACTION_IDENTIFY 5 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci/* 18962306a36Sopenharmony_ci * ata_cdb struct 19062306a36Sopenharmony_ci */ 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ciunion ata_cdb { 19462306a36Sopenharmony_ci struct { 19562306a36Sopenharmony_ci unsigned char SignatureByte0; 19662306a36Sopenharmony_ci unsigned char SignatureByte1; 19762306a36Sopenharmony_ci unsigned char ActionSelect; 19862306a36Sopenharmony_ci unsigned char RegisterSelect; 19962306a36Sopenharmony_ci unsigned char TransferBlockSize; 20062306a36Sopenharmony_ci unsigned char WriteData3F6; 20162306a36Sopenharmony_ci unsigned char WriteData1F1; 20262306a36Sopenharmony_ci unsigned char WriteData1F2; 20362306a36Sopenharmony_ci unsigned char WriteData1F3; 20462306a36Sopenharmony_ci unsigned char WriteData1F4; 20562306a36Sopenharmony_ci unsigned char WriteData1F5; 20662306a36Sopenharmony_ci unsigned char WriteData1F6; 20762306a36Sopenharmony_ci unsigned char WriteData1F7; 20862306a36Sopenharmony_ci unsigned char Reserved[3]; 20962306a36Sopenharmony_ci } generic; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci struct { 21262306a36Sopenharmony_ci unsigned char SignatureByte0; 21362306a36Sopenharmony_ci unsigned char SignatureByte1; 21462306a36Sopenharmony_ci unsigned char ActionSelect; 21562306a36Sopenharmony_ci unsigned char RegisterSelect; 21662306a36Sopenharmony_ci unsigned char TransferBlockSize; 21762306a36Sopenharmony_ci unsigned char AlternateStatusByte; 21862306a36Sopenharmony_ci unsigned char ErrorByte; 21962306a36Sopenharmony_ci unsigned char SectorCountByte; 22062306a36Sopenharmony_ci unsigned char SectorNumberByte; 22162306a36Sopenharmony_ci unsigned char CylinderLowByte; 22262306a36Sopenharmony_ci unsigned char CylinderHighByte; 22362306a36Sopenharmony_ci unsigned char DeviceHeadByte; 22462306a36Sopenharmony_ci unsigned char StatusByte; 22562306a36Sopenharmony_ci unsigned char Reserved[3]; 22662306a36Sopenharmony_ci } read; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci struct { 22962306a36Sopenharmony_ci unsigned char SignatureByte0; 23062306a36Sopenharmony_ci unsigned char SignatureByte1; 23162306a36Sopenharmony_ci unsigned char ActionSelect; 23262306a36Sopenharmony_ci unsigned char RegisterSelect; 23362306a36Sopenharmony_ci unsigned char TransferBlockSize; 23462306a36Sopenharmony_ci unsigned char DeviceControlByte; 23562306a36Sopenharmony_ci unsigned char FeaturesByte; 23662306a36Sopenharmony_ci unsigned char SectorCountByte; 23762306a36Sopenharmony_ci unsigned char SectorNumberByte; 23862306a36Sopenharmony_ci unsigned char CylinderLowByte; 23962306a36Sopenharmony_ci unsigned char CylinderHighByte; 24062306a36Sopenharmony_ci unsigned char DeviceHeadByte; 24162306a36Sopenharmony_ci unsigned char CommandByte; 24262306a36Sopenharmony_ci unsigned char Reserved[3]; 24362306a36Sopenharmony_ci } write; 24462306a36Sopenharmony_ci}; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci/* 24862306a36Sopenharmony_ci * Inquiry data structure. This is the data returned from the target 24962306a36Sopenharmony_ci * after it receives an inquiry. 25062306a36Sopenharmony_ci * 25162306a36Sopenharmony_ci * This structure may be extended by the number of bytes specified 25262306a36Sopenharmony_ci * in the field AdditionalLength. The defined size constant only 25362306a36Sopenharmony_ci * includes fields through ProductRevisionLevel. 25462306a36Sopenharmony_ci */ 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci/* 25762306a36Sopenharmony_ci * DeviceType field 25862306a36Sopenharmony_ci */ 25962306a36Sopenharmony_ci#define DIRECT_ACCESS_DEVICE 0x00 /* disks */ 26062306a36Sopenharmony_ci#define DEVICE_REMOVABLE 0x80 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistruct inquiry_data { 26362306a36Sopenharmony_ci unsigned char DeviceType; 26462306a36Sopenharmony_ci unsigned char DeviceTypeModifier; 26562306a36Sopenharmony_ci unsigned char Versions; 26662306a36Sopenharmony_ci unsigned char Format; 26762306a36Sopenharmony_ci unsigned char AdditionalLength; 26862306a36Sopenharmony_ci unsigned char Reserved[2]; 26962306a36Sopenharmony_ci unsigned char Capability; 27062306a36Sopenharmony_ci unsigned char VendorId[8]; 27162306a36Sopenharmony_ci unsigned char ProductId[16]; 27262306a36Sopenharmony_ci unsigned char ProductRevisionLevel[4]; 27362306a36Sopenharmony_ci unsigned char VendorSpecific[20]; 27462306a36Sopenharmony_ci unsigned char Reserved3[40]; 27562306a36Sopenharmony_ci} __attribute__ ((packed)); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci/* 27862306a36Sopenharmony_ci * INQUIRY data buffer size 27962306a36Sopenharmony_ci */ 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci#define INQUIRYDATABUFFERSIZE 36 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci/* 28562306a36Sopenharmony_ci * ISD200 CONFIG data struct 28662306a36Sopenharmony_ci */ 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci#define ATACFG_TIMING 0x0f 28962306a36Sopenharmony_ci#define ATACFG_ATAPI_RESET 0x10 29062306a36Sopenharmony_ci#define ATACFG_MASTER 0x20 29162306a36Sopenharmony_ci#define ATACFG_BLOCKSIZE 0xa0 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci#define ATACFGE_LAST_LUN 0x07 29462306a36Sopenharmony_ci#define ATACFGE_DESC_OVERRIDE 0x08 29562306a36Sopenharmony_ci#define ATACFGE_STATE_SUSPEND 0x10 29662306a36Sopenharmony_ci#define ATACFGE_SKIP_BOOT 0x20 29762306a36Sopenharmony_ci#define ATACFGE_CONF_DESC2 0x40 29862306a36Sopenharmony_ci#define ATACFGE_INIT_STATUS 0x80 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci#define CFG_CAPABILITY_SRST 0x01 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistruct isd200_config { 30362306a36Sopenharmony_ci unsigned char EventNotification; 30462306a36Sopenharmony_ci unsigned char ExternalClock; 30562306a36Sopenharmony_ci unsigned char ATAInitTimeout; 30662306a36Sopenharmony_ci unsigned char ATAConfig; 30762306a36Sopenharmony_ci unsigned char ATAMajorCommand; 30862306a36Sopenharmony_ci unsigned char ATAMinorCommand; 30962306a36Sopenharmony_ci unsigned char ATAExtraConfig; 31062306a36Sopenharmony_ci unsigned char Capability; 31162306a36Sopenharmony_ci}__attribute__ ((packed)); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci/* 31562306a36Sopenharmony_ci * ISD200 driver information struct 31662306a36Sopenharmony_ci */ 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistruct isd200_info { 31962306a36Sopenharmony_ci struct inquiry_data InquiryData; 32062306a36Sopenharmony_ci u16 *id; 32162306a36Sopenharmony_ci struct isd200_config ConfigData; 32262306a36Sopenharmony_ci unsigned char *RegsBuf; 32362306a36Sopenharmony_ci unsigned char ATARegs[8]; 32462306a36Sopenharmony_ci unsigned char DeviceHead; 32562306a36Sopenharmony_ci unsigned char DeviceFlags; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci /* maximum number of LUNs supported */ 32862306a36Sopenharmony_ci unsigned char MaxLUNs; 32962306a36Sopenharmony_ci unsigned char cmnd[MAX_COMMAND_SIZE]; 33062306a36Sopenharmony_ci struct scsi_cmnd srb; 33162306a36Sopenharmony_ci struct scatterlist sg; 33262306a36Sopenharmony_ci}; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci/* 33662306a36Sopenharmony_ci * Read Capacity Data - returned in Big Endian format 33762306a36Sopenharmony_ci */ 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistruct read_capacity_data { 34062306a36Sopenharmony_ci __be32 LogicalBlockAddress; 34162306a36Sopenharmony_ci __be32 BytesPerBlock; 34262306a36Sopenharmony_ci}; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci/* 34562306a36Sopenharmony_ci * Read Block Limits Data - returned in Big Endian format 34662306a36Sopenharmony_ci * This structure returns the maximum and minimum block 34762306a36Sopenharmony_ci * size for a TAPE device. 34862306a36Sopenharmony_ci */ 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_cistruct read_block_limits { 35162306a36Sopenharmony_ci unsigned char Reserved; 35262306a36Sopenharmony_ci unsigned char BlockMaximumSize[3]; 35362306a36Sopenharmony_ci unsigned char BlockMinimumSize[2]; 35462306a36Sopenharmony_ci}; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci/* 35862306a36Sopenharmony_ci * Sense Data Format 35962306a36Sopenharmony_ci */ 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci#define SENSE_ERRCODE 0x7f 36262306a36Sopenharmony_ci#define SENSE_ERRCODE_VALID 0x80 36362306a36Sopenharmony_ci#define SENSE_FLAG_SENSE_KEY 0x0f 36462306a36Sopenharmony_ci#define SENSE_FLAG_BAD_LENGTH 0x20 36562306a36Sopenharmony_ci#define SENSE_FLAG_END_OF_MEDIA 0x40 36662306a36Sopenharmony_ci#define SENSE_FLAG_FILE_MARK 0x80 36762306a36Sopenharmony_cistruct sense_data { 36862306a36Sopenharmony_ci unsigned char ErrorCode; 36962306a36Sopenharmony_ci unsigned char SegmentNumber; 37062306a36Sopenharmony_ci unsigned char Flags; 37162306a36Sopenharmony_ci unsigned char Information[4]; 37262306a36Sopenharmony_ci unsigned char AdditionalSenseLength; 37362306a36Sopenharmony_ci unsigned char CommandSpecificInformation[4]; 37462306a36Sopenharmony_ci unsigned char AdditionalSenseCode; 37562306a36Sopenharmony_ci unsigned char AdditionalSenseCodeQualifier; 37662306a36Sopenharmony_ci unsigned char FieldReplaceableUnitCode; 37762306a36Sopenharmony_ci unsigned char SenseKeySpecific[3]; 37862306a36Sopenharmony_ci} __attribute__ ((packed)); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci/* 38162306a36Sopenharmony_ci * Default request sense buffer size 38262306a36Sopenharmony_ci */ 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci#define SENSE_BUFFER_SIZE 18 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci/*********************************************************************** 38762306a36Sopenharmony_ci * Helper routines 38862306a36Sopenharmony_ci ***********************************************************************/ 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci/************************************************************************** 39162306a36Sopenharmony_ci * isd200_build_sense 39262306a36Sopenharmony_ci * 39362306a36Sopenharmony_ci * Builds an artificial sense buffer to report the results of a 39462306a36Sopenharmony_ci * failed command. 39562306a36Sopenharmony_ci * 39662306a36Sopenharmony_ci * RETURNS: 39762306a36Sopenharmony_ci * void 39862306a36Sopenharmony_ci */ 39962306a36Sopenharmony_cistatic void isd200_build_sense(struct us_data *us, struct scsi_cmnd *srb) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci struct isd200_info *info = (struct isd200_info *)us->extra; 40262306a36Sopenharmony_ci struct sense_data *buf = (struct sense_data *) &srb->sense_buffer[0]; 40362306a36Sopenharmony_ci unsigned char error = info->ATARegs[ATA_REG_ERROR_OFFSET]; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci if(error & ATA_ERROR_MEDIA_CHANGE) { 40662306a36Sopenharmony_ci buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; 40762306a36Sopenharmony_ci buf->AdditionalSenseLength = 0xb; 40862306a36Sopenharmony_ci buf->Flags = UNIT_ATTENTION; 40962306a36Sopenharmony_ci buf->AdditionalSenseCode = 0; 41062306a36Sopenharmony_ci buf->AdditionalSenseCodeQualifier = 0; 41162306a36Sopenharmony_ci } else if (error & ATA_MCR) { 41262306a36Sopenharmony_ci buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; 41362306a36Sopenharmony_ci buf->AdditionalSenseLength = 0xb; 41462306a36Sopenharmony_ci buf->Flags = UNIT_ATTENTION; 41562306a36Sopenharmony_ci buf->AdditionalSenseCode = 0; 41662306a36Sopenharmony_ci buf->AdditionalSenseCodeQualifier = 0; 41762306a36Sopenharmony_ci } else if (error & ATA_TRK0NF) { 41862306a36Sopenharmony_ci buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; 41962306a36Sopenharmony_ci buf->AdditionalSenseLength = 0xb; 42062306a36Sopenharmony_ci buf->Flags = NOT_READY; 42162306a36Sopenharmony_ci buf->AdditionalSenseCode = 0; 42262306a36Sopenharmony_ci buf->AdditionalSenseCodeQualifier = 0; 42362306a36Sopenharmony_ci } else if (error & ATA_UNC) { 42462306a36Sopenharmony_ci buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; 42562306a36Sopenharmony_ci buf->AdditionalSenseLength = 0xb; 42662306a36Sopenharmony_ci buf->Flags = DATA_PROTECT; 42762306a36Sopenharmony_ci buf->AdditionalSenseCode = 0; 42862306a36Sopenharmony_ci buf->AdditionalSenseCodeQualifier = 0; 42962306a36Sopenharmony_ci } else { 43062306a36Sopenharmony_ci buf->ErrorCode = 0; 43162306a36Sopenharmony_ci buf->AdditionalSenseLength = 0; 43262306a36Sopenharmony_ci buf->Flags = 0; 43362306a36Sopenharmony_ci buf->AdditionalSenseCode = 0; 43462306a36Sopenharmony_ci buf->AdditionalSenseCodeQualifier = 0; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci/*********************************************************************** 44062306a36Sopenharmony_ci * Transport routines 44162306a36Sopenharmony_ci ***********************************************************************/ 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci/************************************************************************** 44462306a36Sopenharmony_ci * isd200_set_srb(), isd200_srb_set_bufflen() 44562306a36Sopenharmony_ci * 44662306a36Sopenharmony_ci * Two helpers to facilitate in initialization of scsi_cmnd structure 44762306a36Sopenharmony_ci * Will need to change when struct scsi_cmnd changes 44862306a36Sopenharmony_ci */ 44962306a36Sopenharmony_cistatic void isd200_set_srb(struct isd200_info *info, 45062306a36Sopenharmony_ci enum dma_data_direction dir, void* buff, unsigned bufflen) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci struct scsi_cmnd *srb = &info->srb; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci if (buff) 45562306a36Sopenharmony_ci sg_init_one(&info->sg, buff, bufflen); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci srb->sc_data_direction = dir; 45862306a36Sopenharmony_ci srb->sdb.table.sgl = buff ? &info->sg : NULL; 45962306a36Sopenharmony_ci srb->sdb.length = bufflen; 46062306a36Sopenharmony_ci srb->sdb.table.nents = buff ? 1 : 0; 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_cistatic void isd200_srb_set_bufflen(struct scsi_cmnd *srb, unsigned bufflen) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci srb->sdb.length = bufflen; 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci/************************************************************************** 47062306a36Sopenharmony_ci * isd200_action 47162306a36Sopenharmony_ci * 47262306a36Sopenharmony_ci * Routine for sending commands to the isd200 47362306a36Sopenharmony_ci * 47462306a36Sopenharmony_ci * RETURNS: 47562306a36Sopenharmony_ci * ISD status code 47662306a36Sopenharmony_ci */ 47762306a36Sopenharmony_cistatic int isd200_action( struct us_data *us, int action, 47862306a36Sopenharmony_ci void* pointer, int value ) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci union ata_cdb ata; 48162306a36Sopenharmony_ci /* static to prevent this large struct being placed on the valuable stack */ 48262306a36Sopenharmony_ci static struct scsi_device srb_dev; 48362306a36Sopenharmony_ci struct isd200_info *info = (struct isd200_info *)us->extra; 48462306a36Sopenharmony_ci struct scsi_cmnd *srb = &info->srb; 48562306a36Sopenharmony_ci int status; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci memset(&ata, 0, sizeof(ata)); 48862306a36Sopenharmony_ci memcpy(srb->cmnd, info->cmnd, MAX_COMMAND_SIZE); 48962306a36Sopenharmony_ci srb->device = &srb_dev; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci ata.generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; 49262306a36Sopenharmony_ci ata.generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; 49362306a36Sopenharmony_ci ata.generic.TransferBlockSize = 1; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci switch ( action ) { 49662306a36Sopenharmony_ci case ACTION_READ_STATUS: 49762306a36Sopenharmony_ci usb_stor_dbg(us, " isd200_action(READ_STATUS)\n"); 49862306a36Sopenharmony_ci ata.generic.ActionSelect = ACTION_SELECT_0|ACTION_SELECT_2; 49962306a36Sopenharmony_ci ata.generic.RegisterSelect = 50062306a36Sopenharmony_ci REG_CYLINDER_LOW | REG_CYLINDER_HIGH | 50162306a36Sopenharmony_ci REG_STATUS | REG_ERROR; 50262306a36Sopenharmony_ci isd200_set_srb(info, DMA_FROM_DEVICE, pointer, value); 50362306a36Sopenharmony_ci break; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci case ACTION_ENUM: 50662306a36Sopenharmony_ci usb_stor_dbg(us, " isd200_action(ENUM,0x%02x)\n", value); 50762306a36Sopenharmony_ci ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| 50862306a36Sopenharmony_ci ACTION_SELECT_3|ACTION_SELECT_4| 50962306a36Sopenharmony_ci ACTION_SELECT_5; 51062306a36Sopenharmony_ci ata.generic.RegisterSelect = REG_DEVICE_HEAD; 51162306a36Sopenharmony_ci ata.write.DeviceHeadByte = value; 51262306a36Sopenharmony_ci isd200_set_srb(info, DMA_NONE, NULL, 0); 51362306a36Sopenharmony_ci break; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci case ACTION_RESET: 51662306a36Sopenharmony_ci usb_stor_dbg(us, " isd200_action(RESET)\n"); 51762306a36Sopenharmony_ci ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| 51862306a36Sopenharmony_ci ACTION_SELECT_3|ACTION_SELECT_4; 51962306a36Sopenharmony_ci ata.generic.RegisterSelect = REG_DEVICE_CONTROL; 52062306a36Sopenharmony_ci ata.write.DeviceControlByte = ATA_DC_RESET_CONTROLLER; 52162306a36Sopenharmony_ci isd200_set_srb(info, DMA_NONE, NULL, 0); 52262306a36Sopenharmony_ci break; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci case ACTION_REENABLE: 52562306a36Sopenharmony_ci usb_stor_dbg(us, " isd200_action(REENABLE)\n"); 52662306a36Sopenharmony_ci ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| 52762306a36Sopenharmony_ci ACTION_SELECT_3|ACTION_SELECT_4; 52862306a36Sopenharmony_ci ata.generic.RegisterSelect = REG_DEVICE_CONTROL; 52962306a36Sopenharmony_ci ata.write.DeviceControlByte = ATA_DC_REENABLE_CONTROLLER; 53062306a36Sopenharmony_ci isd200_set_srb(info, DMA_NONE, NULL, 0); 53162306a36Sopenharmony_ci break; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci case ACTION_SOFT_RESET: 53462306a36Sopenharmony_ci usb_stor_dbg(us, " isd200_action(SOFT_RESET)\n"); 53562306a36Sopenharmony_ci ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_5; 53662306a36Sopenharmony_ci ata.generic.RegisterSelect = REG_DEVICE_HEAD | REG_COMMAND; 53762306a36Sopenharmony_ci ata.write.DeviceHeadByte = info->DeviceHead; 53862306a36Sopenharmony_ci ata.write.CommandByte = ATA_CMD_DEV_RESET; 53962306a36Sopenharmony_ci isd200_set_srb(info, DMA_NONE, NULL, 0); 54062306a36Sopenharmony_ci break; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci case ACTION_IDENTIFY: 54362306a36Sopenharmony_ci usb_stor_dbg(us, " isd200_action(IDENTIFY)\n"); 54462306a36Sopenharmony_ci ata.generic.RegisterSelect = REG_COMMAND; 54562306a36Sopenharmony_ci ata.write.CommandByte = ATA_CMD_ID_ATA; 54662306a36Sopenharmony_ci isd200_set_srb(info, DMA_FROM_DEVICE, info->id, 54762306a36Sopenharmony_ci ATA_ID_WORDS * 2); 54862306a36Sopenharmony_ci break; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci default: 55162306a36Sopenharmony_ci usb_stor_dbg(us, "Error: Undefined action %d\n", action); 55262306a36Sopenharmony_ci return ISD200_ERROR; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci memcpy(srb->cmnd, &ata, sizeof(ata.generic)); 55662306a36Sopenharmony_ci srb->cmd_len = sizeof(ata.generic); 55762306a36Sopenharmony_ci status = usb_stor_Bulk_transport(srb, us); 55862306a36Sopenharmony_ci if (status == USB_STOR_TRANSPORT_GOOD) 55962306a36Sopenharmony_ci status = ISD200_GOOD; 56062306a36Sopenharmony_ci else { 56162306a36Sopenharmony_ci usb_stor_dbg(us, " isd200_action(0x%02x) error: %d\n", 56262306a36Sopenharmony_ci action, status); 56362306a36Sopenharmony_ci status = ISD200_ERROR; 56462306a36Sopenharmony_ci /* need to reset device here */ 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci return status; 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci/************************************************************************** 57162306a36Sopenharmony_ci * isd200_read_regs 57262306a36Sopenharmony_ci * 57362306a36Sopenharmony_ci * Read ATA Registers 57462306a36Sopenharmony_ci * 57562306a36Sopenharmony_ci * RETURNS: 57662306a36Sopenharmony_ci * ISD status code 57762306a36Sopenharmony_ci */ 57862306a36Sopenharmony_cistatic int isd200_read_regs( struct us_data *us ) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci struct isd200_info *info = (struct isd200_info *)us->extra; 58162306a36Sopenharmony_ci int retStatus = ISD200_GOOD; 58262306a36Sopenharmony_ci int transferStatus; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci usb_stor_dbg(us, "Entering isd200_IssueATAReadRegs\n"); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci transferStatus = isd200_action( us, ACTION_READ_STATUS, 58762306a36Sopenharmony_ci info->RegsBuf, sizeof(info->ATARegs) ); 58862306a36Sopenharmony_ci if (transferStatus != ISD200_TRANSPORT_GOOD) { 58962306a36Sopenharmony_ci usb_stor_dbg(us, " Error reading ATA registers\n"); 59062306a36Sopenharmony_ci retStatus = ISD200_ERROR; 59162306a36Sopenharmony_ci } else { 59262306a36Sopenharmony_ci memcpy(info->ATARegs, info->RegsBuf, sizeof(info->ATARegs)); 59362306a36Sopenharmony_ci usb_stor_dbg(us, " Got ATA Register[ATA_REG_ERROR_OFFSET] = 0x%x\n", 59462306a36Sopenharmony_ci info->ATARegs[ATA_REG_ERROR_OFFSET]); 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci return retStatus; 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci/************************************************************************** 60262306a36Sopenharmony_ci * Invoke the transport and basic error-handling/recovery methods 60362306a36Sopenharmony_ci * 60462306a36Sopenharmony_ci * This is used by the protocol layers to actually send the message to 60562306a36Sopenharmony_ci * the device and receive the response. 60662306a36Sopenharmony_ci */ 60762306a36Sopenharmony_cistatic void isd200_invoke_transport( struct us_data *us, 60862306a36Sopenharmony_ci struct scsi_cmnd *srb, 60962306a36Sopenharmony_ci union ata_cdb *ataCdb ) 61062306a36Sopenharmony_ci{ 61162306a36Sopenharmony_ci int need_auto_sense = 0; 61262306a36Sopenharmony_ci int transferStatus; 61362306a36Sopenharmony_ci int result; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci /* send the command to the transport layer */ 61662306a36Sopenharmony_ci memcpy(srb->cmnd, ataCdb, sizeof(ataCdb->generic)); 61762306a36Sopenharmony_ci srb->cmd_len = sizeof(ataCdb->generic); 61862306a36Sopenharmony_ci transferStatus = usb_stor_Bulk_transport(srb, us); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci /* 62162306a36Sopenharmony_ci * if the command gets aborted by the higher layers, we need to 62262306a36Sopenharmony_ci * short-circuit all other processing 62362306a36Sopenharmony_ci */ 62462306a36Sopenharmony_ci if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { 62562306a36Sopenharmony_ci usb_stor_dbg(us, "-- command was aborted\n"); 62662306a36Sopenharmony_ci goto Handle_Abort; 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci switch (transferStatus) { 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci case USB_STOR_TRANSPORT_GOOD: 63262306a36Sopenharmony_ci /* Indicate a good result */ 63362306a36Sopenharmony_ci srb->result = SAM_STAT_GOOD; 63462306a36Sopenharmony_ci break; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci case USB_STOR_TRANSPORT_NO_SENSE: 63762306a36Sopenharmony_ci usb_stor_dbg(us, "-- transport indicates protocol failure\n"); 63862306a36Sopenharmony_ci srb->result = SAM_STAT_CHECK_CONDITION; 63962306a36Sopenharmony_ci return; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci case USB_STOR_TRANSPORT_FAILED: 64262306a36Sopenharmony_ci usb_stor_dbg(us, "-- transport indicates command failure\n"); 64362306a36Sopenharmony_ci need_auto_sense = 1; 64462306a36Sopenharmony_ci break; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci case USB_STOR_TRANSPORT_ERROR: 64762306a36Sopenharmony_ci usb_stor_dbg(us, "-- transport indicates transport error\n"); 64862306a36Sopenharmony_ci srb->result = DID_ERROR << 16; 64962306a36Sopenharmony_ci /* Need reset here */ 65062306a36Sopenharmony_ci return; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci default: 65362306a36Sopenharmony_ci usb_stor_dbg(us, "-- transport indicates unknown error\n"); 65462306a36Sopenharmony_ci srb->result = DID_ERROR << 16; 65562306a36Sopenharmony_ci /* Need reset here */ 65662306a36Sopenharmony_ci return; 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci if ((scsi_get_resid(srb) > 0) && 66062306a36Sopenharmony_ci !((srb->cmnd[0] == REQUEST_SENSE) || 66162306a36Sopenharmony_ci (srb->cmnd[0] == INQUIRY) || 66262306a36Sopenharmony_ci (srb->cmnd[0] == MODE_SENSE) || 66362306a36Sopenharmony_ci (srb->cmnd[0] == LOG_SENSE) || 66462306a36Sopenharmony_ci (srb->cmnd[0] == MODE_SENSE_10))) { 66562306a36Sopenharmony_ci usb_stor_dbg(us, "-- unexpectedly short transfer\n"); 66662306a36Sopenharmony_ci need_auto_sense = 1; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci if (need_auto_sense) { 67062306a36Sopenharmony_ci result = isd200_read_regs(us); 67162306a36Sopenharmony_ci if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { 67262306a36Sopenharmony_ci usb_stor_dbg(us, "-- auto-sense aborted\n"); 67362306a36Sopenharmony_ci goto Handle_Abort; 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci if (result == ISD200_GOOD) { 67662306a36Sopenharmony_ci isd200_build_sense(us, srb); 67762306a36Sopenharmony_ci srb->result = SAM_STAT_CHECK_CONDITION; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci /* If things are really okay, then let's show that */ 68062306a36Sopenharmony_ci if ((srb->sense_buffer[2] & 0xf) == 0x0) 68162306a36Sopenharmony_ci srb->result = SAM_STAT_GOOD; 68262306a36Sopenharmony_ci } else { 68362306a36Sopenharmony_ci srb->result = DID_ERROR << 16; 68462306a36Sopenharmony_ci /* Need reset here */ 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci /* 68962306a36Sopenharmony_ci * Regardless of auto-sense, if we _know_ we have an error 69062306a36Sopenharmony_ci * condition, show that in the result code 69162306a36Sopenharmony_ci */ 69262306a36Sopenharmony_ci if (transferStatus == USB_STOR_TRANSPORT_FAILED) 69362306a36Sopenharmony_ci srb->result = SAM_STAT_CHECK_CONDITION; 69462306a36Sopenharmony_ci return; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci /* 69762306a36Sopenharmony_ci * abort processing: the bulk-only transport requires a reset 69862306a36Sopenharmony_ci * following an abort 69962306a36Sopenharmony_ci */ 70062306a36Sopenharmony_ci Handle_Abort: 70162306a36Sopenharmony_ci srb->result = DID_ABORT << 16; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci /* permit the reset transfer to take place */ 70462306a36Sopenharmony_ci clear_bit(US_FLIDX_ABORTING, &us->dflags); 70562306a36Sopenharmony_ci /* Need reset here */ 70662306a36Sopenharmony_ci} 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci#ifdef CONFIG_USB_STORAGE_DEBUG 70962306a36Sopenharmony_cistatic void isd200_log_config(struct us_data *us, struct isd200_info *info) 71062306a36Sopenharmony_ci{ 71162306a36Sopenharmony_ci usb_stor_dbg(us, " Event Notification: 0x%x\n", 71262306a36Sopenharmony_ci info->ConfigData.EventNotification); 71362306a36Sopenharmony_ci usb_stor_dbg(us, " External Clock: 0x%x\n", 71462306a36Sopenharmony_ci info->ConfigData.ExternalClock); 71562306a36Sopenharmony_ci usb_stor_dbg(us, " ATA Init Timeout: 0x%x\n", 71662306a36Sopenharmony_ci info->ConfigData.ATAInitTimeout); 71762306a36Sopenharmony_ci usb_stor_dbg(us, " ATAPI Command Block Size: 0x%x\n", 71862306a36Sopenharmony_ci (info->ConfigData.ATAConfig & ATACFG_BLOCKSIZE) >> 6); 71962306a36Sopenharmony_ci usb_stor_dbg(us, " Master/Slave Selection: 0x%x\n", 72062306a36Sopenharmony_ci info->ConfigData.ATAConfig & ATACFG_MASTER); 72162306a36Sopenharmony_ci usb_stor_dbg(us, " ATAPI Reset: 0x%x\n", 72262306a36Sopenharmony_ci info->ConfigData.ATAConfig & ATACFG_ATAPI_RESET); 72362306a36Sopenharmony_ci usb_stor_dbg(us, " ATA Timing: 0x%x\n", 72462306a36Sopenharmony_ci info->ConfigData.ATAConfig & ATACFG_TIMING); 72562306a36Sopenharmony_ci usb_stor_dbg(us, " ATA Major Command: 0x%x\n", 72662306a36Sopenharmony_ci info->ConfigData.ATAMajorCommand); 72762306a36Sopenharmony_ci usb_stor_dbg(us, " ATA Minor Command: 0x%x\n", 72862306a36Sopenharmony_ci info->ConfigData.ATAMinorCommand); 72962306a36Sopenharmony_ci usb_stor_dbg(us, " Init Status: 0x%x\n", 73062306a36Sopenharmony_ci info->ConfigData.ATAExtraConfig & ATACFGE_INIT_STATUS); 73162306a36Sopenharmony_ci usb_stor_dbg(us, " Config Descriptor 2: 0x%x\n", 73262306a36Sopenharmony_ci info->ConfigData.ATAExtraConfig & ATACFGE_CONF_DESC2); 73362306a36Sopenharmony_ci usb_stor_dbg(us, " Skip Device Boot: 0x%x\n", 73462306a36Sopenharmony_ci info->ConfigData.ATAExtraConfig & ATACFGE_SKIP_BOOT); 73562306a36Sopenharmony_ci usb_stor_dbg(us, " ATA 3 State Suspend: 0x%x\n", 73662306a36Sopenharmony_ci info->ConfigData.ATAExtraConfig & ATACFGE_STATE_SUSPEND); 73762306a36Sopenharmony_ci usb_stor_dbg(us, " Descriptor Override: 0x%x\n", 73862306a36Sopenharmony_ci info->ConfigData.ATAExtraConfig & ATACFGE_DESC_OVERRIDE); 73962306a36Sopenharmony_ci usb_stor_dbg(us, " Last LUN Identifier: 0x%x\n", 74062306a36Sopenharmony_ci info->ConfigData.ATAExtraConfig & ATACFGE_LAST_LUN); 74162306a36Sopenharmony_ci usb_stor_dbg(us, " SRST Enable: 0x%x\n", 74262306a36Sopenharmony_ci info->ConfigData.ATAExtraConfig & CFG_CAPABILITY_SRST); 74362306a36Sopenharmony_ci} 74462306a36Sopenharmony_ci#endif 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci/************************************************************************** 74762306a36Sopenharmony_ci * isd200_write_config 74862306a36Sopenharmony_ci * 74962306a36Sopenharmony_ci * Write the ISD200 Configuration data 75062306a36Sopenharmony_ci * 75162306a36Sopenharmony_ci * RETURNS: 75262306a36Sopenharmony_ci * ISD status code 75362306a36Sopenharmony_ci */ 75462306a36Sopenharmony_cistatic int isd200_write_config( struct us_data *us ) 75562306a36Sopenharmony_ci{ 75662306a36Sopenharmony_ci struct isd200_info *info = (struct isd200_info *)us->extra; 75762306a36Sopenharmony_ci int retStatus = ISD200_GOOD; 75862306a36Sopenharmony_ci int result; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci#ifdef CONFIG_USB_STORAGE_DEBUG 76162306a36Sopenharmony_ci usb_stor_dbg(us, "Entering isd200_write_config\n"); 76262306a36Sopenharmony_ci usb_stor_dbg(us, " Writing the following ISD200 Config Data:\n"); 76362306a36Sopenharmony_ci isd200_log_config(us, info); 76462306a36Sopenharmony_ci#endif 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci /* let's send the command via the control pipe */ 76762306a36Sopenharmony_ci result = usb_stor_ctrl_transfer( 76862306a36Sopenharmony_ci us, 76962306a36Sopenharmony_ci us->send_ctrl_pipe, 77062306a36Sopenharmony_ci 0x01, 77162306a36Sopenharmony_ci USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, 77262306a36Sopenharmony_ci 0x0000, 77362306a36Sopenharmony_ci 0x0002, 77462306a36Sopenharmony_ci (void *) &info->ConfigData, 77562306a36Sopenharmony_ci sizeof(info->ConfigData)); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci if (result >= 0) { 77862306a36Sopenharmony_ci usb_stor_dbg(us, " ISD200 Config Data was written successfully\n"); 77962306a36Sopenharmony_ci } else { 78062306a36Sopenharmony_ci usb_stor_dbg(us, " Request to write ISD200 Config Data failed!\n"); 78162306a36Sopenharmony_ci retStatus = ISD200_ERROR; 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci usb_stor_dbg(us, "Leaving isd200_write_config %08X\n", retStatus); 78562306a36Sopenharmony_ci return retStatus; 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci/************************************************************************** 79062306a36Sopenharmony_ci * isd200_read_config 79162306a36Sopenharmony_ci * 79262306a36Sopenharmony_ci * Reads the ISD200 Configuration data 79362306a36Sopenharmony_ci * 79462306a36Sopenharmony_ci * RETURNS: 79562306a36Sopenharmony_ci * ISD status code 79662306a36Sopenharmony_ci */ 79762306a36Sopenharmony_cistatic int isd200_read_config( struct us_data *us ) 79862306a36Sopenharmony_ci{ 79962306a36Sopenharmony_ci struct isd200_info *info = (struct isd200_info *)us->extra; 80062306a36Sopenharmony_ci int retStatus = ISD200_GOOD; 80162306a36Sopenharmony_ci int result; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci usb_stor_dbg(us, "Entering isd200_read_config\n"); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci /* read the configuration information from ISD200. Use this to */ 80662306a36Sopenharmony_ci /* determine what the special ATA CDB bytes are. */ 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci result = usb_stor_ctrl_transfer( 80962306a36Sopenharmony_ci us, 81062306a36Sopenharmony_ci us->recv_ctrl_pipe, 81162306a36Sopenharmony_ci 0x02, 81262306a36Sopenharmony_ci USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 81362306a36Sopenharmony_ci 0x0000, 81462306a36Sopenharmony_ci 0x0002, 81562306a36Sopenharmony_ci (void *) &info->ConfigData, 81662306a36Sopenharmony_ci sizeof(info->ConfigData)); 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci if (result >= 0) { 82062306a36Sopenharmony_ci usb_stor_dbg(us, " Retrieved the following ISD200 Config Data:\n"); 82162306a36Sopenharmony_ci#ifdef CONFIG_USB_STORAGE_DEBUG 82262306a36Sopenharmony_ci isd200_log_config(us, info); 82362306a36Sopenharmony_ci#endif 82462306a36Sopenharmony_ci } else { 82562306a36Sopenharmony_ci usb_stor_dbg(us, " Request to get ISD200 Config Data failed!\n"); 82662306a36Sopenharmony_ci retStatus = ISD200_ERROR; 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci usb_stor_dbg(us, "Leaving isd200_read_config %08X\n", retStatus); 83062306a36Sopenharmony_ci return retStatus; 83162306a36Sopenharmony_ci} 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci/************************************************************************** 83562306a36Sopenharmony_ci * isd200_atapi_soft_reset 83662306a36Sopenharmony_ci * 83762306a36Sopenharmony_ci * Perform an Atapi Soft Reset on the device 83862306a36Sopenharmony_ci * 83962306a36Sopenharmony_ci * RETURNS: 84062306a36Sopenharmony_ci * NT status code 84162306a36Sopenharmony_ci */ 84262306a36Sopenharmony_cistatic int isd200_atapi_soft_reset( struct us_data *us ) 84362306a36Sopenharmony_ci{ 84462306a36Sopenharmony_ci int retStatus = ISD200_GOOD; 84562306a36Sopenharmony_ci int transferStatus; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci usb_stor_dbg(us, "Entering isd200_atapi_soft_reset\n"); 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci transferStatus = isd200_action( us, ACTION_SOFT_RESET, NULL, 0 ); 85062306a36Sopenharmony_ci if (transferStatus != ISD200_TRANSPORT_GOOD) { 85162306a36Sopenharmony_ci usb_stor_dbg(us, " Error issuing Atapi Soft Reset\n"); 85262306a36Sopenharmony_ci retStatus = ISD200_ERROR; 85362306a36Sopenharmony_ci } 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci usb_stor_dbg(us, "Leaving isd200_atapi_soft_reset %08X\n", retStatus); 85662306a36Sopenharmony_ci return retStatus; 85762306a36Sopenharmony_ci} 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci/************************************************************************** 86162306a36Sopenharmony_ci * isd200_srst 86262306a36Sopenharmony_ci * 86362306a36Sopenharmony_ci * Perform an SRST on the device 86462306a36Sopenharmony_ci * 86562306a36Sopenharmony_ci * RETURNS: 86662306a36Sopenharmony_ci * ISD status code 86762306a36Sopenharmony_ci */ 86862306a36Sopenharmony_cistatic int isd200_srst( struct us_data *us ) 86962306a36Sopenharmony_ci{ 87062306a36Sopenharmony_ci int retStatus = ISD200_GOOD; 87162306a36Sopenharmony_ci int transferStatus; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci usb_stor_dbg(us, "Entering isd200_SRST\n"); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci transferStatus = isd200_action( us, ACTION_RESET, NULL, 0 ); 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci /* check to see if this request failed */ 87862306a36Sopenharmony_ci if (transferStatus != ISD200_TRANSPORT_GOOD) { 87962306a36Sopenharmony_ci usb_stor_dbg(us, " Error issuing SRST\n"); 88062306a36Sopenharmony_ci retStatus = ISD200_ERROR; 88162306a36Sopenharmony_ci } else { 88262306a36Sopenharmony_ci /* delay 10ms to give the drive a chance to see it */ 88362306a36Sopenharmony_ci msleep(10); 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci transferStatus = isd200_action( us, ACTION_REENABLE, NULL, 0 ); 88662306a36Sopenharmony_ci if (transferStatus != ISD200_TRANSPORT_GOOD) { 88762306a36Sopenharmony_ci usb_stor_dbg(us, " Error taking drive out of reset\n"); 88862306a36Sopenharmony_ci retStatus = ISD200_ERROR; 88962306a36Sopenharmony_ci } else { 89062306a36Sopenharmony_ci /* delay 50ms to give the drive a chance to recover after SRST */ 89162306a36Sopenharmony_ci msleep(50); 89262306a36Sopenharmony_ci } 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci usb_stor_dbg(us, "Leaving isd200_srst %08X\n", retStatus); 89662306a36Sopenharmony_ci return retStatus; 89762306a36Sopenharmony_ci} 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci/************************************************************************** 90162306a36Sopenharmony_ci * isd200_try_enum 90262306a36Sopenharmony_ci * 90362306a36Sopenharmony_ci * Helper function for isd200_manual_enum(). Does ENUM and READ_STATUS 90462306a36Sopenharmony_ci * and tries to analyze the status registers 90562306a36Sopenharmony_ci * 90662306a36Sopenharmony_ci * RETURNS: 90762306a36Sopenharmony_ci * ISD status code 90862306a36Sopenharmony_ci */ 90962306a36Sopenharmony_cistatic int isd200_try_enum(struct us_data *us, unsigned char master_slave, 91062306a36Sopenharmony_ci int detect ) 91162306a36Sopenharmony_ci{ 91262306a36Sopenharmony_ci int status = ISD200_GOOD; 91362306a36Sopenharmony_ci unsigned long endTime; 91462306a36Sopenharmony_ci struct isd200_info *info = (struct isd200_info *)us->extra; 91562306a36Sopenharmony_ci unsigned char *regs = info->RegsBuf; 91662306a36Sopenharmony_ci int recheckAsMaster = 0; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci if ( detect ) 91962306a36Sopenharmony_ci endTime = jiffies + ISD200_ENUM_DETECT_TIMEOUT * HZ; 92062306a36Sopenharmony_ci else 92162306a36Sopenharmony_ci endTime = jiffies + ISD200_ENUM_BSY_TIMEOUT * HZ; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci /* loop until we detect !BSY or timeout */ 92462306a36Sopenharmony_ci while(1) { 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci status = isd200_action( us, ACTION_ENUM, NULL, master_slave ); 92762306a36Sopenharmony_ci if ( status != ISD200_GOOD ) 92862306a36Sopenharmony_ci break; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci status = isd200_action( us, ACTION_READ_STATUS, 93162306a36Sopenharmony_ci regs, 8 ); 93262306a36Sopenharmony_ci if ( status != ISD200_GOOD ) 93362306a36Sopenharmony_ci break; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci if (!detect) { 93662306a36Sopenharmony_ci if (regs[ATA_REG_STATUS_OFFSET] & ATA_BUSY) { 93762306a36Sopenharmony_ci usb_stor_dbg(us, " %s status is still BSY, try again...\n", 93862306a36Sopenharmony_ci master_slave == ATA_ADDRESS_DEVHEAD_STD ? 93962306a36Sopenharmony_ci "Master" : "Slave"); 94062306a36Sopenharmony_ci } else { 94162306a36Sopenharmony_ci usb_stor_dbg(us, " %s status !BSY, continue with next operation\n", 94262306a36Sopenharmony_ci master_slave == ATA_ADDRESS_DEVHEAD_STD ? 94362306a36Sopenharmony_ci "Master" : "Slave"); 94462306a36Sopenharmony_ci break; 94562306a36Sopenharmony_ci } 94662306a36Sopenharmony_ci } 94762306a36Sopenharmony_ci /* check for ATA_BUSY and */ 94862306a36Sopenharmony_ci /* ATA_DF (workaround ATA Zip drive) and */ 94962306a36Sopenharmony_ci /* ATA_ERR (workaround for Archos CD-ROM) */ 95062306a36Sopenharmony_ci else if (regs[ATA_REG_STATUS_OFFSET] & 95162306a36Sopenharmony_ci (ATA_BUSY | ATA_DF | ATA_ERR)) { 95262306a36Sopenharmony_ci usb_stor_dbg(us, " Status indicates it is not ready, try again...\n"); 95362306a36Sopenharmony_ci } 95462306a36Sopenharmony_ci /* check for DRDY, ATA devices set DRDY after SRST */ 95562306a36Sopenharmony_ci else if (regs[ATA_REG_STATUS_OFFSET] & ATA_DRDY) { 95662306a36Sopenharmony_ci usb_stor_dbg(us, " Identified ATA device\n"); 95762306a36Sopenharmony_ci info->DeviceFlags |= DF_ATA_DEVICE; 95862306a36Sopenharmony_ci info->DeviceHead = master_slave; 95962306a36Sopenharmony_ci break; 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci /* 96262306a36Sopenharmony_ci * check Cylinder High/Low to 96362306a36Sopenharmony_ci * determine if it is an ATAPI device 96462306a36Sopenharmony_ci */ 96562306a36Sopenharmony_ci else if (regs[ATA_REG_HCYL_OFFSET] == 0xEB && 96662306a36Sopenharmony_ci regs[ATA_REG_LCYL_OFFSET] == 0x14) { 96762306a36Sopenharmony_ci /* 96862306a36Sopenharmony_ci * It seems that the RICOH 96962306a36Sopenharmony_ci * MP6200A CD/RW drive will 97062306a36Sopenharmony_ci * report itself okay as a 97162306a36Sopenharmony_ci * slave when it is really a 97262306a36Sopenharmony_ci * master. So this check again 97362306a36Sopenharmony_ci * as a master device just to 97462306a36Sopenharmony_ci * make sure it doesn't report 97562306a36Sopenharmony_ci * itself okay as a master also 97662306a36Sopenharmony_ci */ 97762306a36Sopenharmony_ci if ((master_slave & ATA_ADDRESS_DEVHEAD_SLAVE) && 97862306a36Sopenharmony_ci !recheckAsMaster) { 97962306a36Sopenharmony_ci usb_stor_dbg(us, " Identified ATAPI device as slave. Rechecking again as master\n"); 98062306a36Sopenharmony_ci recheckAsMaster = 1; 98162306a36Sopenharmony_ci master_slave = ATA_ADDRESS_DEVHEAD_STD; 98262306a36Sopenharmony_ci } else { 98362306a36Sopenharmony_ci usb_stor_dbg(us, " Identified ATAPI device\n"); 98462306a36Sopenharmony_ci info->DeviceHead = master_slave; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci status = isd200_atapi_soft_reset(us); 98762306a36Sopenharmony_ci break; 98862306a36Sopenharmony_ci } 98962306a36Sopenharmony_ci } else { 99062306a36Sopenharmony_ci usb_stor_dbg(us, " Not ATA, not ATAPI - Weird\n"); 99162306a36Sopenharmony_ci break; 99262306a36Sopenharmony_ci } 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci /* check for timeout on this request */ 99562306a36Sopenharmony_ci if (time_after_eq(jiffies, endTime)) { 99662306a36Sopenharmony_ci if (!detect) 99762306a36Sopenharmony_ci usb_stor_dbg(us, " BSY check timeout, just continue with next operation...\n"); 99862306a36Sopenharmony_ci else 99962306a36Sopenharmony_ci usb_stor_dbg(us, " Device detect timeout!\n"); 100062306a36Sopenharmony_ci break; 100162306a36Sopenharmony_ci } 100262306a36Sopenharmony_ci } 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci return status; 100562306a36Sopenharmony_ci} 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci/************************************************************************** 100862306a36Sopenharmony_ci * isd200_manual_enum 100962306a36Sopenharmony_ci * 101062306a36Sopenharmony_ci * Determines if the drive attached is an ATA or ATAPI and if it is a 101162306a36Sopenharmony_ci * master or slave. 101262306a36Sopenharmony_ci * 101362306a36Sopenharmony_ci * RETURNS: 101462306a36Sopenharmony_ci * ISD status code 101562306a36Sopenharmony_ci */ 101662306a36Sopenharmony_cistatic int isd200_manual_enum(struct us_data *us) 101762306a36Sopenharmony_ci{ 101862306a36Sopenharmony_ci struct isd200_info *info = (struct isd200_info *)us->extra; 101962306a36Sopenharmony_ci int retStatus = ISD200_GOOD; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci usb_stor_dbg(us, "Entering isd200_manual_enum\n"); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci retStatus = isd200_read_config(us); 102462306a36Sopenharmony_ci if (retStatus == ISD200_GOOD) { 102562306a36Sopenharmony_ci int isslave; 102662306a36Sopenharmony_ci /* master or slave? */ 102762306a36Sopenharmony_ci retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_STD, 0); 102862306a36Sopenharmony_ci if (retStatus == ISD200_GOOD) 102962306a36Sopenharmony_ci retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_SLAVE, 0); 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci if (retStatus == ISD200_GOOD) { 103262306a36Sopenharmony_ci retStatus = isd200_srst(us); 103362306a36Sopenharmony_ci if (retStatus == ISD200_GOOD) 103462306a36Sopenharmony_ci /* ata or atapi? */ 103562306a36Sopenharmony_ci retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_STD, 1); 103662306a36Sopenharmony_ci } 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci isslave = (info->DeviceHead & ATA_ADDRESS_DEVHEAD_SLAVE) ? 1 : 0; 103962306a36Sopenharmony_ci if (!(info->ConfigData.ATAConfig & ATACFG_MASTER)) { 104062306a36Sopenharmony_ci usb_stor_dbg(us, " Setting Master/Slave selection to %d\n", 104162306a36Sopenharmony_ci isslave); 104262306a36Sopenharmony_ci info->ConfigData.ATAConfig &= 0x3f; 104362306a36Sopenharmony_ci info->ConfigData.ATAConfig |= (isslave<<6); 104462306a36Sopenharmony_ci retStatus = isd200_write_config(us); 104562306a36Sopenharmony_ci } 104662306a36Sopenharmony_ci } 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci usb_stor_dbg(us, "Leaving isd200_manual_enum %08X\n", retStatus); 104962306a36Sopenharmony_ci return(retStatus); 105062306a36Sopenharmony_ci} 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_cistatic void isd200_fix_driveid(u16 *id) 105362306a36Sopenharmony_ci{ 105462306a36Sopenharmony_ci#ifndef __LITTLE_ENDIAN 105562306a36Sopenharmony_ci# ifdef __BIG_ENDIAN 105662306a36Sopenharmony_ci int i; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci for (i = 0; i < ATA_ID_WORDS; i++) 105962306a36Sopenharmony_ci id[i] = __le16_to_cpu(id[i]); 106062306a36Sopenharmony_ci# else 106162306a36Sopenharmony_ci# error "Please fix <asm/byteorder.h>" 106262306a36Sopenharmony_ci# endif 106362306a36Sopenharmony_ci#endif 106462306a36Sopenharmony_ci} 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_cistatic void isd200_dump_driveid(struct us_data *us, u16 *id) 106762306a36Sopenharmony_ci{ 106862306a36Sopenharmony_ci usb_stor_dbg(us, " Identify Data Structure:\n"); 106962306a36Sopenharmony_ci usb_stor_dbg(us, " config = 0x%x\n", id[ATA_ID_CONFIG]); 107062306a36Sopenharmony_ci usb_stor_dbg(us, " cyls = 0x%x\n", id[ATA_ID_CYLS]); 107162306a36Sopenharmony_ci usb_stor_dbg(us, " heads = 0x%x\n", id[ATA_ID_HEADS]); 107262306a36Sopenharmony_ci usb_stor_dbg(us, " track_bytes = 0x%x\n", id[4]); 107362306a36Sopenharmony_ci usb_stor_dbg(us, " sector_bytes = 0x%x\n", id[5]); 107462306a36Sopenharmony_ci usb_stor_dbg(us, " sectors = 0x%x\n", id[ATA_ID_SECTORS]); 107562306a36Sopenharmony_ci usb_stor_dbg(us, " serial_no[0] = 0x%x\n", *(char *)&id[ATA_ID_SERNO]); 107662306a36Sopenharmony_ci usb_stor_dbg(us, " buf_type = 0x%x\n", id[20]); 107762306a36Sopenharmony_ci usb_stor_dbg(us, " buf_size = 0x%x\n", id[ATA_ID_BUF_SIZE]); 107862306a36Sopenharmony_ci usb_stor_dbg(us, " ecc_bytes = 0x%x\n", id[22]); 107962306a36Sopenharmony_ci usb_stor_dbg(us, " fw_rev[0] = 0x%x\n", *(char *)&id[ATA_ID_FW_REV]); 108062306a36Sopenharmony_ci usb_stor_dbg(us, " model[0] = 0x%x\n", *(char *)&id[ATA_ID_PROD]); 108162306a36Sopenharmony_ci usb_stor_dbg(us, " max_multsect = 0x%x\n", id[ATA_ID_MAX_MULTSECT] & 0xff); 108262306a36Sopenharmony_ci usb_stor_dbg(us, " dword_io = 0x%x\n", id[ATA_ID_DWORD_IO]); 108362306a36Sopenharmony_ci usb_stor_dbg(us, " capability = 0x%x\n", id[ATA_ID_CAPABILITY] >> 8); 108462306a36Sopenharmony_ci usb_stor_dbg(us, " tPIO = 0x%x\n", id[ATA_ID_OLD_PIO_MODES] >> 8); 108562306a36Sopenharmony_ci usb_stor_dbg(us, " tDMA = 0x%x\n", id[ATA_ID_OLD_DMA_MODES] >> 8); 108662306a36Sopenharmony_ci usb_stor_dbg(us, " field_valid = 0x%x\n", id[ATA_ID_FIELD_VALID]); 108762306a36Sopenharmony_ci usb_stor_dbg(us, " cur_cyls = 0x%x\n", id[ATA_ID_CUR_CYLS]); 108862306a36Sopenharmony_ci usb_stor_dbg(us, " cur_heads = 0x%x\n", id[ATA_ID_CUR_HEADS]); 108962306a36Sopenharmony_ci usb_stor_dbg(us, " cur_sectors = 0x%x\n", id[ATA_ID_CUR_SECTORS]); 109062306a36Sopenharmony_ci usb_stor_dbg(us, " cur_capacity = 0x%x\n", ata_id_u32(id, 57)); 109162306a36Sopenharmony_ci usb_stor_dbg(us, " multsect = 0x%x\n", id[ATA_ID_MULTSECT] & 0xff); 109262306a36Sopenharmony_ci usb_stor_dbg(us, " lba_capacity = 0x%x\n", ata_id_u32(id, ATA_ID_LBA_CAPACITY)); 109362306a36Sopenharmony_ci usb_stor_dbg(us, " command_set_1 = 0x%x\n", id[ATA_ID_COMMAND_SET_1]); 109462306a36Sopenharmony_ci usb_stor_dbg(us, " command_set_2 = 0x%x\n", id[ATA_ID_COMMAND_SET_2]); 109562306a36Sopenharmony_ci} 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci/************************************************************************** 109862306a36Sopenharmony_ci * isd200_get_inquiry_data 109962306a36Sopenharmony_ci * 110062306a36Sopenharmony_ci * Get inquiry data 110162306a36Sopenharmony_ci * 110262306a36Sopenharmony_ci * RETURNS: 110362306a36Sopenharmony_ci * ISD status code 110462306a36Sopenharmony_ci */ 110562306a36Sopenharmony_cistatic int isd200_get_inquiry_data( struct us_data *us ) 110662306a36Sopenharmony_ci{ 110762306a36Sopenharmony_ci struct isd200_info *info = (struct isd200_info *)us->extra; 110862306a36Sopenharmony_ci int retStatus = ISD200_GOOD; 110962306a36Sopenharmony_ci u16 *id = info->id; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci usb_stor_dbg(us, "Entering isd200_get_inquiry_data\n"); 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci /* set default to Master */ 111462306a36Sopenharmony_ci info->DeviceHead = ATA_ADDRESS_DEVHEAD_STD; 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci /* attempt to manually enumerate this device */ 111762306a36Sopenharmony_ci retStatus = isd200_manual_enum(us); 111862306a36Sopenharmony_ci if (retStatus == ISD200_GOOD) { 111962306a36Sopenharmony_ci int transferStatus; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci /* check for an ATA device */ 112262306a36Sopenharmony_ci if (info->DeviceFlags & DF_ATA_DEVICE) { 112362306a36Sopenharmony_ci /* this must be an ATA device */ 112462306a36Sopenharmony_ci /* perform an ATA Command Identify */ 112562306a36Sopenharmony_ci transferStatus = isd200_action( us, ACTION_IDENTIFY, 112662306a36Sopenharmony_ci id, ATA_ID_WORDS * 2); 112762306a36Sopenharmony_ci if (transferStatus != ISD200_TRANSPORT_GOOD) { 112862306a36Sopenharmony_ci /* Error issuing ATA Command Identify */ 112962306a36Sopenharmony_ci usb_stor_dbg(us, " Error issuing ATA Command Identify\n"); 113062306a36Sopenharmony_ci retStatus = ISD200_ERROR; 113162306a36Sopenharmony_ci } else { 113262306a36Sopenharmony_ci /* ATA Command Identify successful */ 113362306a36Sopenharmony_ci int i; 113462306a36Sopenharmony_ci __be16 *src; 113562306a36Sopenharmony_ci __u16 *dest; 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci isd200_fix_driveid(id); 113862306a36Sopenharmony_ci isd200_dump_driveid(us, id); 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci memset(&info->InquiryData, 0, sizeof(info->InquiryData)); 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci /* Standard IDE interface only supports disks */ 114362306a36Sopenharmony_ci info->InquiryData.DeviceType = DIRECT_ACCESS_DEVICE; 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci /* The length must be at least 36 (5 + 31) */ 114662306a36Sopenharmony_ci info->InquiryData.AdditionalLength = 0x1F; 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci if (id[ATA_ID_COMMAND_SET_1] & COMMANDSET_MEDIA_STATUS) { 114962306a36Sopenharmony_ci /* set the removable bit */ 115062306a36Sopenharmony_ci info->InquiryData.DeviceTypeModifier = DEVICE_REMOVABLE; 115162306a36Sopenharmony_ci info->DeviceFlags |= DF_REMOVABLE_MEDIA; 115262306a36Sopenharmony_ci } 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci /* Fill in vendor identification fields */ 115562306a36Sopenharmony_ci src = (__be16 *)&id[ATA_ID_PROD]; 115662306a36Sopenharmony_ci dest = (__u16*)info->InquiryData.VendorId; 115762306a36Sopenharmony_ci for (i = 0; i < 4; i++) 115862306a36Sopenharmony_ci dest[i] = be16_to_cpu(src[i]); 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci src = (__be16 *)&id[ATA_ID_PROD + 8/2]; 116162306a36Sopenharmony_ci dest = (__u16*)info->InquiryData.ProductId; 116262306a36Sopenharmony_ci for (i=0;i<8;i++) 116362306a36Sopenharmony_ci dest[i] = be16_to_cpu(src[i]); 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci src = (__be16 *)&id[ATA_ID_FW_REV]; 116662306a36Sopenharmony_ci dest = (__u16*)info->InquiryData.ProductRevisionLevel; 116762306a36Sopenharmony_ci for (i=0;i<2;i++) 116862306a36Sopenharmony_ci dest[i] = be16_to_cpu(src[i]); 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci /* determine if it supports Media Status Notification */ 117162306a36Sopenharmony_ci if (id[ATA_ID_COMMAND_SET_2] & COMMANDSET_MEDIA_STATUS) { 117262306a36Sopenharmony_ci usb_stor_dbg(us, " Device supports Media Status Notification\n"); 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci /* 117562306a36Sopenharmony_ci * Indicate that it is enabled, even 117662306a36Sopenharmony_ci * though it is not. 117762306a36Sopenharmony_ci * This allows the lock/unlock of the 117862306a36Sopenharmony_ci * media to work correctly. 117962306a36Sopenharmony_ci */ 118062306a36Sopenharmony_ci info->DeviceFlags |= DF_MEDIA_STATUS_ENABLED; 118162306a36Sopenharmony_ci } 118262306a36Sopenharmony_ci else 118362306a36Sopenharmony_ci info->DeviceFlags &= ~DF_MEDIA_STATUS_ENABLED; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci } 118662306a36Sopenharmony_ci } else { 118762306a36Sopenharmony_ci /* 118862306a36Sopenharmony_ci * this must be an ATAPI device 118962306a36Sopenharmony_ci * use an ATAPI protocol (Transparent SCSI) 119062306a36Sopenharmony_ci */ 119162306a36Sopenharmony_ci us->protocol_name = "Transparent SCSI"; 119262306a36Sopenharmony_ci us->proto_handler = usb_stor_transparent_scsi_command; 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci usb_stor_dbg(us, "Protocol changed to: %s\n", 119562306a36Sopenharmony_ci us->protocol_name); 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci /* Free driver structure */ 119862306a36Sopenharmony_ci us->extra_destructor(info); 119962306a36Sopenharmony_ci kfree(info); 120062306a36Sopenharmony_ci us->extra = NULL; 120162306a36Sopenharmony_ci us->extra_destructor = NULL; 120262306a36Sopenharmony_ci } 120362306a36Sopenharmony_ci } 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci usb_stor_dbg(us, "Leaving isd200_get_inquiry_data %08X\n", retStatus); 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci return(retStatus); 120862306a36Sopenharmony_ci} 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci/************************************************************************** 121162306a36Sopenharmony_ci * isd200_scsi_to_ata 121262306a36Sopenharmony_ci * 121362306a36Sopenharmony_ci * Translate SCSI commands to ATA commands. 121462306a36Sopenharmony_ci * 121562306a36Sopenharmony_ci * RETURNS: 121662306a36Sopenharmony_ci * 1 if the command needs to be sent to the transport layer 121762306a36Sopenharmony_ci * 0 otherwise 121862306a36Sopenharmony_ci */ 121962306a36Sopenharmony_cistatic int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, 122062306a36Sopenharmony_ci union ata_cdb * ataCdb) 122162306a36Sopenharmony_ci{ 122262306a36Sopenharmony_ci struct isd200_info *info = (struct isd200_info *)us->extra; 122362306a36Sopenharmony_ci u16 *id = info->id; 122462306a36Sopenharmony_ci int sendToTransport = 1; 122562306a36Sopenharmony_ci unsigned char sectnum, head; 122662306a36Sopenharmony_ci unsigned short cylinder; 122762306a36Sopenharmony_ci unsigned long lba; 122862306a36Sopenharmony_ci unsigned long blockCount; 122962306a36Sopenharmony_ci unsigned char senseData[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci memset(ataCdb, 0, sizeof(union ata_cdb)); 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci /* SCSI Command */ 123462306a36Sopenharmony_ci switch (srb->cmnd[0]) { 123562306a36Sopenharmony_ci case INQUIRY: 123662306a36Sopenharmony_ci usb_stor_dbg(us, " ATA OUT - INQUIRY\n"); 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci /* copy InquiryData */ 123962306a36Sopenharmony_ci usb_stor_set_xfer_buf((unsigned char *) &info->InquiryData, 124062306a36Sopenharmony_ci sizeof(info->InquiryData), srb); 124162306a36Sopenharmony_ci srb->result = SAM_STAT_GOOD; 124262306a36Sopenharmony_ci sendToTransport = 0; 124362306a36Sopenharmony_ci break; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci case MODE_SENSE: 124662306a36Sopenharmony_ci usb_stor_dbg(us, " ATA OUT - SCSIOP_MODE_SENSE\n"); 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci /* Initialize the return buffer */ 124962306a36Sopenharmony_ci usb_stor_set_xfer_buf(senseData, sizeof(senseData), srb); 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci if (info->DeviceFlags & DF_MEDIA_STATUS_ENABLED) 125262306a36Sopenharmony_ci { 125362306a36Sopenharmony_ci ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; 125462306a36Sopenharmony_ci ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; 125562306a36Sopenharmony_ci ataCdb->generic.TransferBlockSize = 1; 125662306a36Sopenharmony_ci ataCdb->generic.RegisterSelect = REG_COMMAND; 125762306a36Sopenharmony_ci ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; 125862306a36Sopenharmony_ci isd200_srb_set_bufflen(srb, 0); 125962306a36Sopenharmony_ci } else { 126062306a36Sopenharmony_ci usb_stor_dbg(us, " Media Status not supported, just report okay\n"); 126162306a36Sopenharmony_ci srb->result = SAM_STAT_GOOD; 126262306a36Sopenharmony_ci sendToTransport = 0; 126362306a36Sopenharmony_ci } 126462306a36Sopenharmony_ci break; 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci case TEST_UNIT_READY: 126762306a36Sopenharmony_ci usb_stor_dbg(us, " ATA OUT - SCSIOP_TEST_UNIT_READY\n"); 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci if (info->DeviceFlags & DF_MEDIA_STATUS_ENABLED) 127062306a36Sopenharmony_ci { 127162306a36Sopenharmony_ci ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; 127262306a36Sopenharmony_ci ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; 127362306a36Sopenharmony_ci ataCdb->generic.TransferBlockSize = 1; 127462306a36Sopenharmony_ci ataCdb->generic.RegisterSelect = REG_COMMAND; 127562306a36Sopenharmony_ci ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; 127662306a36Sopenharmony_ci isd200_srb_set_bufflen(srb, 0); 127762306a36Sopenharmony_ci } else { 127862306a36Sopenharmony_ci usb_stor_dbg(us, " Media Status not supported, just report okay\n"); 127962306a36Sopenharmony_ci srb->result = SAM_STAT_GOOD; 128062306a36Sopenharmony_ci sendToTransport = 0; 128162306a36Sopenharmony_ci } 128262306a36Sopenharmony_ci break; 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci case READ_CAPACITY: 128562306a36Sopenharmony_ci { 128662306a36Sopenharmony_ci unsigned long capacity; 128762306a36Sopenharmony_ci struct read_capacity_data readCapacityData; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci usb_stor_dbg(us, " ATA OUT - SCSIOP_READ_CAPACITY\n"); 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci if (ata_id_has_lba(id)) 129262306a36Sopenharmony_ci capacity = ata_id_u32(id, ATA_ID_LBA_CAPACITY) - 1; 129362306a36Sopenharmony_ci else 129462306a36Sopenharmony_ci capacity = (id[ATA_ID_HEADS] * id[ATA_ID_CYLS] * 129562306a36Sopenharmony_ci id[ATA_ID_SECTORS]) - 1; 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci readCapacityData.LogicalBlockAddress = cpu_to_be32(capacity); 129862306a36Sopenharmony_ci readCapacityData.BytesPerBlock = cpu_to_be32(0x200); 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci usb_stor_set_xfer_buf((unsigned char *) &readCapacityData, 130162306a36Sopenharmony_ci sizeof(readCapacityData), srb); 130262306a36Sopenharmony_ci srb->result = SAM_STAT_GOOD; 130362306a36Sopenharmony_ci sendToTransport = 0; 130462306a36Sopenharmony_ci } 130562306a36Sopenharmony_ci break; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci case READ_10: 130862306a36Sopenharmony_ci usb_stor_dbg(us, " ATA OUT - SCSIOP_READ\n"); 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci lba = be32_to_cpu(*(__be32 *)&srb->cmnd[2]); 131162306a36Sopenharmony_ci blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8]; 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci if (ata_id_has_lba(id)) { 131462306a36Sopenharmony_ci sectnum = (unsigned char)(lba); 131562306a36Sopenharmony_ci cylinder = (unsigned short)(lba>>8); 131662306a36Sopenharmony_ci head = ATA_ADDRESS_DEVHEAD_LBA_MODE | (unsigned char)(lba>>24 & 0x0F); 131762306a36Sopenharmony_ci } else { 131862306a36Sopenharmony_ci sectnum = (u8)((lba % id[ATA_ID_SECTORS]) + 1); 131962306a36Sopenharmony_ci cylinder = (u16)(lba / (id[ATA_ID_SECTORS] * 132062306a36Sopenharmony_ci id[ATA_ID_HEADS])); 132162306a36Sopenharmony_ci head = (u8)((lba / id[ATA_ID_SECTORS]) % 132262306a36Sopenharmony_ci id[ATA_ID_HEADS]); 132362306a36Sopenharmony_ci } 132462306a36Sopenharmony_ci ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; 132562306a36Sopenharmony_ci ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; 132662306a36Sopenharmony_ci ataCdb->generic.TransferBlockSize = 1; 132762306a36Sopenharmony_ci ataCdb->generic.RegisterSelect = 132862306a36Sopenharmony_ci REG_SECTOR_COUNT | REG_SECTOR_NUMBER | 132962306a36Sopenharmony_ci REG_CYLINDER_LOW | REG_CYLINDER_HIGH | 133062306a36Sopenharmony_ci REG_DEVICE_HEAD | REG_COMMAND; 133162306a36Sopenharmony_ci ataCdb->write.SectorCountByte = (unsigned char)blockCount; 133262306a36Sopenharmony_ci ataCdb->write.SectorNumberByte = sectnum; 133362306a36Sopenharmony_ci ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8); 133462306a36Sopenharmony_ci ataCdb->write.CylinderLowByte = (unsigned char)cylinder; 133562306a36Sopenharmony_ci ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD); 133662306a36Sopenharmony_ci ataCdb->write.CommandByte = ATA_CMD_PIO_READ; 133762306a36Sopenharmony_ci break; 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci case WRITE_10: 134062306a36Sopenharmony_ci usb_stor_dbg(us, " ATA OUT - SCSIOP_WRITE\n"); 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci lba = be32_to_cpu(*(__be32 *)&srb->cmnd[2]); 134362306a36Sopenharmony_ci blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8]; 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci if (ata_id_has_lba(id)) { 134662306a36Sopenharmony_ci sectnum = (unsigned char)(lba); 134762306a36Sopenharmony_ci cylinder = (unsigned short)(lba>>8); 134862306a36Sopenharmony_ci head = ATA_ADDRESS_DEVHEAD_LBA_MODE | (unsigned char)(lba>>24 & 0x0F); 134962306a36Sopenharmony_ci } else { 135062306a36Sopenharmony_ci sectnum = (u8)((lba % id[ATA_ID_SECTORS]) + 1); 135162306a36Sopenharmony_ci cylinder = (u16)(lba / (id[ATA_ID_SECTORS] * 135262306a36Sopenharmony_ci id[ATA_ID_HEADS])); 135362306a36Sopenharmony_ci head = (u8)((lba / id[ATA_ID_SECTORS]) % 135462306a36Sopenharmony_ci id[ATA_ID_HEADS]); 135562306a36Sopenharmony_ci } 135662306a36Sopenharmony_ci ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; 135762306a36Sopenharmony_ci ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; 135862306a36Sopenharmony_ci ataCdb->generic.TransferBlockSize = 1; 135962306a36Sopenharmony_ci ataCdb->generic.RegisterSelect = 136062306a36Sopenharmony_ci REG_SECTOR_COUNT | REG_SECTOR_NUMBER | 136162306a36Sopenharmony_ci REG_CYLINDER_LOW | REG_CYLINDER_HIGH | 136262306a36Sopenharmony_ci REG_DEVICE_HEAD | REG_COMMAND; 136362306a36Sopenharmony_ci ataCdb->write.SectorCountByte = (unsigned char)blockCount; 136462306a36Sopenharmony_ci ataCdb->write.SectorNumberByte = sectnum; 136562306a36Sopenharmony_ci ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8); 136662306a36Sopenharmony_ci ataCdb->write.CylinderLowByte = (unsigned char)cylinder; 136762306a36Sopenharmony_ci ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD); 136862306a36Sopenharmony_ci ataCdb->write.CommandByte = ATA_CMD_PIO_WRITE; 136962306a36Sopenharmony_ci break; 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci case ALLOW_MEDIUM_REMOVAL: 137262306a36Sopenharmony_ci usb_stor_dbg(us, " ATA OUT - SCSIOP_MEDIUM_REMOVAL\n"); 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci if (info->DeviceFlags & DF_REMOVABLE_MEDIA) { 137562306a36Sopenharmony_ci usb_stor_dbg(us, " srb->cmnd[4] = 0x%X\n", 137662306a36Sopenharmony_ci srb->cmnd[4]); 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; 137962306a36Sopenharmony_ci ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; 138062306a36Sopenharmony_ci ataCdb->generic.TransferBlockSize = 1; 138162306a36Sopenharmony_ci ataCdb->generic.RegisterSelect = REG_COMMAND; 138262306a36Sopenharmony_ci ataCdb->write.CommandByte = (srb->cmnd[4] & 0x1) ? 138362306a36Sopenharmony_ci ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK; 138462306a36Sopenharmony_ci isd200_srb_set_bufflen(srb, 0); 138562306a36Sopenharmony_ci } else { 138662306a36Sopenharmony_ci usb_stor_dbg(us, " Not removable media, just report okay\n"); 138762306a36Sopenharmony_ci srb->result = SAM_STAT_GOOD; 138862306a36Sopenharmony_ci sendToTransport = 0; 138962306a36Sopenharmony_ci } 139062306a36Sopenharmony_ci break; 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci case START_STOP: 139362306a36Sopenharmony_ci usb_stor_dbg(us, " ATA OUT - SCSIOP_START_STOP_UNIT\n"); 139462306a36Sopenharmony_ci usb_stor_dbg(us, " srb->cmnd[4] = 0x%X\n", srb->cmnd[4]); 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci if ((srb->cmnd[4] & 0x3) == 0x2) { 139762306a36Sopenharmony_ci usb_stor_dbg(us, " Media Eject\n"); 139862306a36Sopenharmony_ci ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; 139962306a36Sopenharmony_ci ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; 140062306a36Sopenharmony_ci ataCdb->generic.TransferBlockSize = 0; 140162306a36Sopenharmony_ci ataCdb->generic.RegisterSelect = REG_COMMAND; 140262306a36Sopenharmony_ci ataCdb->write.CommandByte = ATA_COMMAND_MEDIA_EJECT; 140362306a36Sopenharmony_ci } else if ((srb->cmnd[4] & 0x3) == 0x1) { 140462306a36Sopenharmony_ci usb_stor_dbg(us, " Get Media Status\n"); 140562306a36Sopenharmony_ci ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; 140662306a36Sopenharmony_ci ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; 140762306a36Sopenharmony_ci ataCdb->generic.TransferBlockSize = 1; 140862306a36Sopenharmony_ci ataCdb->generic.RegisterSelect = REG_COMMAND; 140962306a36Sopenharmony_ci ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; 141062306a36Sopenharmony_ci isd200_srb_set_bufflen(srb, 0); 141162306a36Sopenharmony_ci } else { 141262306a36Sopenharmony_ci usb_stor_dbg(us, " Nothing to do, just report okay\n"); 141362306a36Sopenharmony_ci srb->result = SAM_STAT_GOOD; 141462306a36Sopenharmony_ci sendToTransport = 0; 141562306a36Sopenharmony_ci } 141662306a36Sopenharmony_ci break; 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci default: 141962306a36Sopenharmony_ci usb_stor_dbg(us, "Unsupported SCSI command - 0x%X\n", 142062306a36Sopenharmony_ci srb->cmnd[0]); 142162306a36Sopenharmony_ci srb->result = DID_ERROR << 16; 142262306a36Sopenharmony_ci sendToTransport = 0; 142362306a36Sopenharmony_ci break; 142462306a36Sopenharmony_ci } 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci return(sendToTransport); 142762306a36Sopenharmony_ci} 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci/************************************************************************** 143162306a36Sopenharmony_ci * isd200_free_info 143262306a36Sopenharmony_ci * 143362306a36Sopenharmony_ci * Frees the driver structure. 143462306a36Sopenharmony_ci */ 143562306a36Sopenharmony_cistatic void isd200_free_info_ptrs(void *info_) 143662306a36Sopenharmony_ci{ 143762306a36Sopenharmony_ci struct isd200_info *info = (struct isd200_info *) info_; 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci if (info) { 144062306a36Sopenharmony_ci kfree(info->id); 144162306a36Sopenharmony_ci kfree(info->RegsBuf); 144262306a36Sopenharmony_ci kfree(info->srb.sense_buffer); 144362306a36Sopenharmony_ci } 144462306a36Sopenharmony_ci} 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci/************************************************************************** 144762306a36Sopenharmony_ci * isd200_init_info 144862306a36Sopenharmony_ci * 144962306a36Sopenharmony_ci * Allocates (if necessary) and initializes the driver structure. 145062306a36Sopenharmony_ci * 145162306a36Sopenharmony_ci * RETURNS: 145262306a36Sopenharmony_ci * error status code 145362306a36Sopenharmony_ci */ 145462306a36Sopenharmony_cistatic int isd200_init_info(struct us_data *us) 145562306a36Sopenharmony_ci{ 145662306a36Sopenharmony_ci struct isd200_info *info; 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci info = kzalloc(sizeof(struct isd200_info), GFP_KERNEL); 145962306a36Sopenharmony_ci if (!info) 146062306a36Sopenharmony_ci return -ENOMEM; 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci info->id = kzalloc(ATA_ID_WORDS * 2, GFP_KERNEL); 146362306a36Sopenharmony_ci info->RegsBuf = kmalloc(sizeof(info->ATARegs), GFP_KERNEL); 146462306a36Sopenharmony_ci info->srb.sense_buffer = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci if (!info->id || !info->RegsBuf || !info->srb.sense_buffer) { 146762306a36Sopenharmony_ci isd200_free_info_ptrs(info); 146862306a36Sopenharmony_ci kfree(info); 146962306a36Sopenharmony_ci return -ENOMEM; 147062306a36Sopenharmony_ci } 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci us->extra = info; 147362306a36Sopenharmony_ci us->extra_destructor = isd200_free_info_ptrs; 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci return 0; 147662306a36Sopenharmony_ci} 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci/************************************************************************** 147962306a36Sopenharmony_ci * Initialization for the ISD200 148062306a36Sopenharmony_ci */ 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_cistatic int isd200_Initialization(struct us_data *us) 148362306a36Sopenharmony_ci{ 148462306a36Sopenharmony_ci usb_stor_dbg(us, "ISD200 Initialization...\n"); 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci /* Initialize ISD200 info struct */ 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci if (isd200_init_info(us) == ISD200_ERROR) { 148962306a36Sopenharmony_ci usb_stor_dbg(us, "ERROR Initializing ISD200 Info struct\n"); 149062306a36Sopenharmony_ci } else { 149162306a36Sopenharmony_ci /* Get device specific data */ 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci if (isd200_get_inquiry_data(us) != ISD200_GOOD) 149462306a36Sopenharmony_ci usb_stor_dbg(us, "ISD200 Initialization Failure\n"); 149562306a36Sopenharmony_ci else 149662306a36Sopenharmony_ci usb_stor_dbg(us, "ISD200 Initialization complete\n"); 149762306a36Sopenharmony_ci } 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci return 0; 150062306a36Sopenharmony_ci} 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci/************************************************************************** 150462306a36Sopenharmony_ci * Protocol and Transport for the ISD200 ASIC 150562306a36Sopenharmony_ci * 150662306a36Sopenharmony_ci * This protocol and transport are for ATA devices connected to an ISD200 150762306a36Sopenharmony_ci * ASIC. An ATAPI device that is connected as a slave device will be 150862306a36Sopenharmony_ci * detected in the driver initialization function and the protocol will 150962306a36Sopenharmony_ci * be changed to an ATAPI protocol (Transparent SCSI). 151062306a36Sopenharmony_ci * 151162306a36Sopenharmony_ci */ 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_cistatic void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us) 151462306a36Sopenharmony_ci{ 151562306a36Sopenharmony_ci int sendToTransport, orig_bufflen; 151662306a36Sopenharmony_ci union ata_cdb ataCdb; 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci /* Make sure driver was initialized */ 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci if (us->extra == NULL) { 152162306a36Sopenharmony_ci usb_stor_dbg(us, "ERROR Driver not initialized\n"); 152262306a36Sopenharmony_ci srb->result = DID_ERROR << 16; 152362306a36Sopenharmony_ci return; 152462306a36Sopenharmony_ci } 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci scsi_set_resid(srb, 0); 152762306a36Sopenharmony_ci /* scsi_bufflen might change in protocol translation to ata */ 152862306a36Sopenharmony_ci orig_bufflen = scsi_bufflen(srb); 152962306a36Sopenharmony_ci sendToTransport = isd200_scsi_to_ata(srb, us, &ataCdb); 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci /* send the command to the transport layer */ 153262306a36Sopenharmony_ci if (sendToTransport) 153362306a36Sopenharmony_ci isd200_invoke_transport(us, srb, &ataCdb); 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci isd200_srb_set_bufflen(srb, orig_bufflen); 153662306a36Sopenharmony_ci} 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_cistatic struct scsi_host_template isd200_host_template; 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_cistatic int isd200_probe(struct usb_interface *intf, 154162306a36Sopenharmony_ci const struct usb_device_id *id) 154262306a36Sopenharmony_ci{ 154362306a36Sopenharmony_ci struct us_data *us; 154462306a36Sopenharmony_ci int result; 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci result = usb_stor_probe1(&us, intf, id, 154762306a36Sopenharmony_ci (id - isd200_usb_ids) + isd200_unusual_dev_list, 154862306a36Sopenharmony_ci &isd200_host_template); 154962306a36Sopenharmony_ci if (result) 155062306a36Sopenharmony_ci return result; 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci us->protocol_name = "ISD200 ATA/ATAPI"; 155362306a36Sopenharmony_ci us->proto_handler = isd200_ata_command; 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci result = usb_stor_probe2(us); 155662306a36Sopenharmony_ci return result; 155762306a36Sopenharmony_ci} 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_cistatic struct usb_driver isd200_driver = { 156062306a36Sopenharmony_ci .name = DRV_NAME, 156162306a36Sopenharmony_ci .probe = isd200_probe, 156262306a36Sopenharmony_ci .disconnect = usb_stor_disconnect, 156362306a36Sopenharmony_ci .suspend = usb_stor_suspend, 156462306a36Sopenharmony_ci .resume = usb_stor_resume, 156562306a36Sopenharmony_ci .reset_resume = usb_stor_reset_resume, 156662306a36Sopenharmony_ci .pre_reset = usb_stor_pre_reset, 156762306a36Sopenharmony_ci .post_reset = usb_stor_post_reset, 156862306a36Sopenharmony_ci .id_table = isd200_usb_ids, 156962306a36Sopenharmony_ci .soft_unbind = 1, 157062306a36Sopenharmony_ci .no_dynamic_id = 1, 157162306a36Sopenharmony_ci}; 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_cimodule_usb_stor_driver(isd200_driver, isd200_host_template, DRV_NAME); 1574