From: Greg KH To: marcelo@conectiva.com.br Cc: linux-usb-devel@lists.sourceforge.net Subject: [PATCH 04 of 14] USB storage driver update Hi, Here's a patch against 2.4.19-pre2 that updates the USB Storage driver to the latest version. It contains the following: - Fix to ISD-200 driver to work on big-endian platforms, including PPC. This has been in circulation for a while, and seems well-tested. - Add several unusual_devs.h entries - A couple more debugging improvements - A slight improvement to the EXPERIMENTAL HP82xx driver, which should help with newer units. - A _major_ cleanup of error handling code throughout the driver. Note that this is in preparation to deploy the new error-handling state machine (special thanks to Alan Sterm for this work). Right now, the optimizations are simple and straightforward (elimination of redundant code paths, etc). Nothing tremendous, but it looks kinda invasive. This patch was done by Matt Dharm. thanks, greg k-h diff -Nru a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c --- a/drivers/usb/storage/datafab.c Mon Mar 4 08:48:59 2002 +++ b/drivers/usb/storage/datafab.c Mon Mar 4 08:48:59 2002 @@ -1,16 +1,25 @@ /* Driver for Datafab USB Compact Flash reader * + * $Id: datafab.c,v 1.7 2002/02/25 00:40:13 mdharm Exp $ + * * datafab driver v0.1: * * First release * * Current development and maintenance by: * (c) 2000 Jimmie Mayfield (mayfield+datafab@sackheads.org) - * many thanks to Robert Baruch for the SanDisk SmartMedia reader driver + * + * Many thanks to Robert Baruch for the SanDisk SmartMedia reader driver * which I used as a template for this driver. + * * Some bugfixes and scatter-gather code by Gregory P. Smith * (greg-usb@electricrain.com) * + * Fix for media change by Joerg Schneider (js@joergschneider.com) + * + * Other contributors: + * (c) 2002 Alan Stern + * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any @@ -102,7 +111,7 @@ if (result == -EPIPE) { US_DEBUGP("datafab_raw_bulk: EPIPE. clearing endpoint halt for" " pipe 0x%x, stalled at %d bytes\n", pipe, act_len); - usb_clear_halt(us->pusb_dev, pipe); + usb_stor_clear_halt(us, pipe); } if (result) { @@ -800,6 +809,23 @@ // return USB_STOR_TRANSPORT_GOOD; } + + if (srb->cmnd[0] == START_STOP) { + /* this is used by sd.c'check_scsidisk_media_change to detect + media change */ + US_DEBUGP("datafab_transport: START_STOP.\n"); + /* the first datafab_id_device after a media change returns + an error (determined experimentally) */ + rc = datafab_id_device(us, info); + if (rc == USB_STOR_TRANSPORT_GOOD) { + info->sense_key = NO_SENSE; + srb->result = SUCCESS; + } else { + info->sense_key = UNIT_ATTENTION; + srb->result = CHECK_CONDITION; + } + return rc; + } US_DEBUGP("datafab_transport: Gah! Unknown command: %d (0x%x)\n", srb->cmnd[0], srb->cmnd[0]); return USB_STOR_TRANSPORT_ERROR; diff -Nru a/drivers/usb/storage/debug.c b/drivers/usb/storage/debug.c --- a/drivers/usb/storage/debug.c Mon Mar 4 08:48:58 2002 +++ b/drivers/usb/storage/debug.c Mon Mar 4 08:48:58 2002 @@ -1,10 +1,13 @@ /* Driver for USB Mass Storage compliant devices * Debugging Functions Source Code File * - * $Id: debug.c,v 1.5 2001/06/27 23:20:45 mdharm Exp $ + * $Id: debug.c,v 1.8 2002/02/25 00:40:13 mdharm Exp $ * * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * + * Developed with the assistance of: + * (c) 2002 Alan Stern * * Initial work by: * (c) 1999 Michael Gee (michael@linuxspecific.com) @@ -300,9 +303,11 @@ case 0x1902: what="defect list error in primary list"; break; case 0x1903: what="defect list error in grown list"; break; case 0x1C00: what="defect list not found"; break; + case 0x2000: what="invalid command operation code"; break; case 0x2400: what="invalid field in CDB"; break; case 0x2703: what="associated write protect"; break; case 0x2800: what="not ready to ready transition"; break; + case 0x2900: what="device reset occurred"; break; case 0x2903: what="bus device reset function occurred"; break; case 0x2904: what="device internal reset"; break; case 0x2B00: what="copy can't execute / host can't disconnect"; break; @@ -325,6 +330,7 @@ case 0x3502: what="enclosure services unavailable"; break; case 0x3503: what="enclosure services transfer failure"; break; case 0x3504: what="enclosure services transfer refused"; break; + case 0x3A00: what="media not present"; break; case 0x3B0F: what="end of medium reached"; break; case 0x3F02: what="changed operating definition"; break; case 0x4100: what="data path failure (should use 40 NN)"; break; diff -Nru a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c --- a/drivers/usb/storage/isd200.c Mon Mar 4 08:48:58 2002 +++ b/drivers/usb/storage/isd200.c Mon Mar 4 08:48:58 2002 @@ -1,9 +1,15 @@ /* Transport & Protocol Driver for In-System Design, Inc. ISD200 ASIC * - * First release + * $Id: isd200.c,v 1.14 2002/02/25 00:40:13 mdharm Exp $ * - * Current development and maintenance by: - * (c) 2000 In-System Design, Inc. (support@in-system.com) + * Current development and maintenance: + * (C) 2001-2002 Björn Stenberg (bjorn@haxx.se) + * + * Developed with the assistance of: + * (C) 2002 Alan Stern + * + * Initial work: + * (C) 2000 In-System Design, Inc. (support@in-system.com) * * The ISD200 ASIC does not natively support ATA devices. The chip * does implement an interface, the ATA Command Block (ATACB) which provides @@ -27,6 +33,10 @@ * * 2001-02-24: Removed lots of duplicate code and simplified the structure. * (bjorn@haxx.se) + * 2002-01-16: Fixed endianness bug so it works on the ppc arch. + * (Luc Saillard ) + * 2002-01-17: All bitfields removed. + * (bjorn@haxx.se) */ @@ -45,15 +55,6 @@ #include #include -/* - * Inquiry defines. Used to interpret data returned from target as result - * of inquiry command. - * - * DeviceType field - */ - -#define DIRECT_ACCESS_DEVICE 0x00 /* disks */ - /* Timeout defines (in Seconds) */ #define ISD200_ENUM_BSY_TIMEOUT 35 @@ -88,6 +89,19 @@ #define ACTION_SELECT_6 0x40 #define ACTION_SELECT_7 0x80 +/* Register Select bits */ +#define REG_ALTERNATE_STATUS 0x01 +#define REG_DEVICE_CONTROL 0x01 +#define REG_ERROR 0x02 +#define REG_FEATURES 0x02 +#define REG_SECTOR_COUNT 0x04 +#define REG_SECTOR_NUMBER 0x08 +#define REG_CYLINDER_LOW 0x10 +#define REG_CYLINDER_HIGH 0x20 +#define REG_DEVICE_HEAD 0x40 +#define REG_STATUS 0x80 +#define REG_COMMAND 0x80 + /* ATA error definitions not in */ #define ATA_ERROR_MEDIA_CHANGE 0x20 @@ -152,20 +166,8 @@ struct { unsigned char SignatureByte0; unsigned char SignatureByte1; - unsigned char ReadRegisterAccessBit : 1; - unsigned char NoDeviceSelectionBit : 1; - unsigned char NoBSYPollBit : 1; - unsigned char IgnorePhaseErrorBit : 1; - unsigned char IgnoreDeviceErrorBit : 1; - unsigned char Reserved0Bit : 3; - unsigned char SelectAlternateStatus : 1; - unsigned char SelectError : 1; - unsigned char SelectSectorCount : 1; - unsigned char SelectSectorNumber : 1; - unsigned char SelectCylinderLow : 1; - unsigned char SelectCylinderHigh : 1; - unsigned char SelectDeviceHead : 1; - unsigned char SelectStatus : 1; + unsigned char ActionSelect; + unsigned char RegisterSelect; unsigned char TransferBlockSize; unsigned char AlternateStatusByte; unsigned char ErrorByte; @@ -181,20 +183,8 @@ struct { unsigned char SignatureByte0; unsigned char SignatureByte1; - unsigned char ReadRegisterAccessBit : 1; - unsigned char NoDeviceSelectionBit : 1; - unsigned char NoBSYPollBit : 1; - unsigned char IgnorePhaseErrorBit : 1; - unsigned char IgnoreDeviceErrorBit : 1; - unsigned char Reserved0Bit : 3; - unsigned char SelectDeviceControl : 1; - unsigned char SelectFeatures : 1; - unsigned char SelectSectorCount : 1; - unsigned char SelectSectorNumber : 1; - unsigned char SelectCylinderLow : 1; - unsigned char SelectCylinderHigh : 1; - unsigned char SelectDeviceHead : 1; - unsigned char SelectCommand : 1; + unsigned char ActionSelect; + unsigned char RegisterSelect; unsigned char TransferBlockSize; unsigned char DeviceControlByte; unsigned char FeaturesByte; @@ -218,27 +208,20 @@ * includes fields through ProductRevisionLevel. */ +/* + * DeviceType field + */ +#define DIRECT_ACCESS_DEVICE 0x00 /* disks */ +#define DEVICE_REMOVABLE 0x80 + struct inquiry_data { - unsigned char DeviceType : 5; - unsigned char DeviceTypeQualifier : 3; - unsigned char DeviceTypeModifier : 7; - unsigned char RemovableMedia : 1; + unsigned char DeviceType; + unsigned char DeviceTypeModifier; unsigned char Versions; - unsigned char ResponseDataFormat : 4; - unsigned char HiSupport : 1; - unsigned char NormACA : 1; - unsigned char ReservedBit : 1; - unsigned char AERC : 1; + unsigned char Format; unsigned char AdditionalLength; unsigned char Reserved[2]; - unsigned char SoftReset : 1; - unsigned char CommandQueue : 1; - unsigned char Reserved2 : 1; - unsigned char LinkedCommands : 1; - unsigned char Synchronous : 1; - unsigned char Wide16Bit : 1; - unsigned char Wide32Bit : 1; - unsigned char RelativeAddressing : 1; + unsigned char Capability; unsigned char VendorId[8]; unsigned char ProductId[16]; unsigned char ProductRevisionLevel[4]; @@ -257,25 +240,30 @@ * ISD200 CONFIG data struct */ +#define ATACFG_TIMING 0x0f +#define ATACFG_ATAPI_RESET 0x10 +#define ATACFG_MASTER 0x20 +#define ATACFG_BLOCKSIZE 0xa0 + +#define ATACFGE_LAST_LUN 0x07 +#define ATACFGE_DESC_OVERRIDE 0x08 +#define ATACFGE_STATE_SUSPEND 0x10 +#define ATACFGE_SKIP_BOOT 0x20 +#define ATACFGE_CONF_DESC2 0x40 +#define ATACFGE_INIT_STATUS 0x80 + +#define CFG_CAPABILITY_SRST 0x01 + struct isd200_config { unsigned char EventNotification; unsigned char ExternalClock; unsigned char ATAInitTimeout; - unsigned char ATATiming : 4; - unsigned char ATAPIReset : 1; - unsigned char MasterSlaveSelection : 1; - unsigned char ATAPICommandBlockSize : 2; + unsigned char ATAConfig; unsigned char ATAMajorCommand; unsigned char ATAMinorCommand; - unsigned char LastLUNIdentifier : 3; - unsigned char DescriptOverride : 1; - unsigned char ATA3StateSuspend : 1; - unsigned char SkipDeviceBoot : 1; - unsigned char ConfigDescriptor2 : 1; - unsigned char InitStatus : 1; - unsigned char SRSTEnable : 1; - unsigned char Reserved0 : 7; -}; + unsigned char ATAExtraConfig; + unsigned char Capability; +}__attribute__ ((packed)); /* @@ -321,15 +309,16 @@ * Sense Data Format */ +#define SENSE_ERRCODE 0x7f +#define SENSE_ERRCODE_VALID 0x80 +#define SENSE_FLAG_SENSE_KEY 0x0f +#define SENSE_FLAG_BAD_LENGTH 0x20 +#define SENSE_FLAG_END_OF_MEDIA 0x40 +#define SENSE_FLAG_FILE_MARK 0x80 struct sense_data { - unsigned char ErrorCode:7; - unsigned char Valid:1; - unsigned char SegmentNumber; - unsigned char SenseKey:4; - unsigned char Reserved:1; - unsigned char IncorrectLength:1; - unsigned char EndOfMedia:1; - unsigned char FileMark:1; + unsigned char ErrorCode; + unsigned char SegmentNumber; + unsigned char Flags; unsigned char Information[4]; unsigned char AdditionalSenseLength; unsigned char CommandSpecificInformation[4]; @@ -349,7 +338,6 @@ * Helper routines ***********************************************************************/ - /************************************************************************** * isd200_build_sense * @@ -366,38 +354,33 @@ unsigned char error = info->ATARegs[IDE_ERROR_OFFSET]; if(error & ATA_ERROR_MEDIA_CHANGE) { - buf->ErrorCode = 0x70; - buf->Valid = 1; + buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; buf->AdditionalSenseLength = 0xb; - buf->SenseKey = UNIT_ATTENTION; + buf->Flags = UNIT_ATTENTION; buf->AdditionalSenseCode = 0; buf->AdditionalSenseCodeQualifier = 0; } else if(error & MCR_ERR) { - buf->ErrorCode = 0x70; - buf->Valid = 1; + buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; buf->AdditionalSenseLength = 0xb; - buf->SenseKey = UNIT_ATTENTION; + buf->Flags = UNIT_ATTENTION; buf->AdditionalSenseCode = 0; buf->AdditionalSenseCodeQualifier = 0; } else if(error & TRK0_ERR) { - buf->ErrorCode = 0x70; - buf->Valid = 1; + buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; buf->AdditionalSenseLength = 0xb; - buf->SenseKey = NOT_READY; + buf->Flags = NOT_READY; buf->AdditionalSenseCode = 0; buf->AdditionalSenseCodeQualifier = 0; } else if(error & ECC_ERR) { - buf->ErrorCode = 0x70; - buf->Valid = 1; + buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; buf->AdditionalSenseLength = 0xb; - buf->SenseKey = DATA_PROTECT; + buf->Flags = DATA_PROTECT; buf->AdditionalSenseCode = 0; buf->AdditionalSenseCodeQualifier = 0; } else { buf->ErrorCode = 0; - buf->Valid = 0; buf->AdditionalSenseLength = 0; - buf->SenseKey = 0; + buf->Flags = 0; buf->AdditionalSenseCode = 0; buf->AdditionalSenseCodeQualifier = 0; } @@ -442,7 +425,7 @@ /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); + usb_stor_clear_halt(us, pipe); } /* did we send all the data? */ @@ -593,7 +576,7 @@ US_DEBUGP("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\n", le32_to_cpu(bcb.Signature), bcb.Tag, (bcb.Lun >> 4), (bcb.Lun & 0xFF), - bcb.DataTransferLength, bcb.Flags, bcb.Length); + le32_to_cpu(bcb.DataTransferLength), bcb.Flags, bcb.Length); result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN, &partial); US_DEBUGP("Bulk command transfer result=%d\n", result); @@ -603,7 +586,7 @@ else if (result == -EPIPE) { /* if we stall, we need to clear it before we go on */ US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); + usb_stor_clear_halt(us, pipe); } else if (result) return ISD200_TRANSPORT_ERROR; @@ -633,7 +616,7 @@ /* did the attempt to read the CSW fail? */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); + usb_stor_clear_halt(us, pipe); /* get the status again */ US_DEBUGP("Attempting to get CSW (2nd try)...\n"); @@ -647,7 +630,7 @@ /* if it fails again, we need a reset and return an error*/ if (result == -EPIPE) { US_DEBUGP("clearing halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); + usb_stor_clear_halt(us, pipe); return ISD200_TRANSPORT_ERROR; } } @@ -716,10 +699,9 @@ case ACTION_READ_STATUS: US_DEBUGP(" isd200_action(READ_STATUS)\n"); ata.generic.ActionSelect = ACTION_SELECT_0|ACTION_SELECT_2; - ata.read.SelectStatus = 1; - ata.read.SelectError = 1; - ata.read.SelectCylinderHigh = 1; - ata.read.SelectCylinderLow = 1; + ata.generic.RegisterSelect = + REG_CYLINDER_LOW | REG_CYLINDER_HIGH | + REG_STATUS | REG_ERROR; srb.sc_data_direction = SCSI_DATA_READ; srb.request_buffer = pointer; srb.request_bufflen = value; @@ -730,7 +712,7 @@ ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| ACTION_SELECT_3|ACTION_SELECT_4| ACTION_SELECT_5; - ata.write.SelectDeviceHead = 1; + ata.generic.RegisterSelect = REG_DEVICE_HEAD; ata.write.DeviceHeadByte = value; srb.sc_data_direction = SCSI_DATA_NONE; break; @@ -739,7 +721,7 @@ US_DEBUGP(" isd200_action(RESET)\n"); ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| ACTION_SELECT_3|ACTION_SELECT_4; - ata.write.SelectDeviceControl = 1; + ata.generic.RegisterSelect = REG_DEVICE_CONTROL; ata.write.DeviceControlByte = ATA_DC_RESET_CONTROLLER; srb.sc_data_direction = SCSI_DATA_NONE; break; @@ -748,7 +730,7 @@ US_DEBUGP(" isd200_action(REENABLE)\n"); ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| ACTION_SELECT_3|ACTION_SELECT_4; - ata.write.SelectDeviceControl = 1; + ata.generic.RegisterSelect = REG_DEVICE_CONTROL; ata.write.DeviceControlByte = ATA_DC_REENABLE_CONTROLLER; srb.sc_data_direction = SCSI_DATA_NONE; break; @@ -756,16 +738,15 @@ case ACTION_SOFT_RESET: US_DEBUGP(" isd200_action(SOFT_RESET)\n"); ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_5; - ata.write.SelectDeviceHead = 1; + ata.generic.RegisterSelect = REG_DEVICE_HEAD | REG_COMMAND; ata.write.DeviceHeadByte = info->DeviceHead; - ata.write.SelectCommand = 1; ata.write.CommandByte = WIN_SRST; srb.sc_data_direction = SCSI_DATA_NONE; break; case ACTION_IDENTIFY: US_DEBUGP(" isd200_action(IDENTIFY)\n"); - ata.write.SelectCommand = 1; + ata.generic.RegisterSelect = REG_COMMAND; ata.write.CommandByte = WIN_IDENTIFY; srb.sc_data_direction = SCSI_DATA_READ; srb.request_buffer = (void *)&info->drive; @@ -886,6 +867,43 @@ srb->result = CHECK_CONDITION; } +#ifdef CONFIG_USB_STORAGE_DEBUG +static void isd200_log_config( struct isd200_info* info ) +{ + US_DEBUGP(" Event Notification: 0x%x\n", + info->ConfigData.EventNotification); + US_DEBUGP(" External Clock: 0x%x\n", + info->ConfigData.ExternalClock); + US_DEBUGP(" ATA Init Timeout: 0x%x\n", + info->ConfigData.ATAInitTimeout); + US_DEBUGP(" ATAPI Command Block Size: 0x%x\n", + (info->ConfigData.ATAConfig & ATACFG_BLOCKSIZE) >> 6); + US_DEBUGP(" Master/Slave Selection: 0x%x\n", + info->ConfigData.ATAConfig & ATACFG_MASTER); + US_DEBUGP(" ATAPI Reset: 0x%x\n", + info->ConfigData.ATAConfig & ATACFG_ATAPI_RESET); + US_DEBUGP(" ATA Timing: 0x%x\n", + info->ConfigData.ATAConfig & ATACFG_TIMING); + US_DEBUGP(" ATA Major Command: 0x%x\n", + info->ConfigData.ATAMajorCommand); + US_DEBUGP(" ATA Minor Command: 0x%x\n", + info->ConfigData.ATAMinorCommand); + US_DEBUGP(" Init Status: 0x%x\n", + info->ConfigData.ATAExtraConfig & ATACFGE_INIT_STATUS); + US_DEBUGP(" Config Descriptor 2: 0x%x\n", + info->ConfigData.ATAExtraConfig & ATACFGE_CONF_DESC2); + US_DEBUGP(" Skip Device Boot: 0x%x\n", + info->ConfigData.ATAExtraConfig & ATACFGE_SKIP_BOOT); + US_DEBUGP(" ATA 3 State Supsend: 0x%x\n", + info->ConfigData.ATAExtraConfig & ATACFGE_STATE_SUSPEND); + US_DEBUGP(" Descriptor Override: 0x%x\n", + info->ConfigData.ATAExtraConfig & ATACFGE_DESC_OVERRIDE); + US_DEBUGP(" Last LUN Identifier: 0x%x\n", + info->ConfigData.ATAExtraConfig & ATACFGE_LAST_LUN); + US_DEBUGP(" SRST Enable: 0x%x\n", + info->ConfigData.ATAExtraConfig & CFG_CAPABILITY_SRST); +} +#endif /************************************************************************** * isd200_write_config @@ -901,26 +919,11 @@ int retStatus = ISD200_GOOD; int result; - +#ifdef CONFIG_USB_STORAGE_DEBUG US_DEBUGP("Entering isd200_write_config\n"); - US_DEBUGP(" Writing the following ISD200 Config Data:\n"); - US_DEBUGP(" Event Notification: 0x%x\n", info->ConfigData.EventNotification); - US_DEBUGP(" External Clock: 0x%x\n", info->ConfigData.ExternalClock); - US_DEBUGP(" ATA Init Timeout: 0x%x\n", info->ConfigData.ATAInitTimeout); - US_DEBUGP(" ATAPI Command Block Size: 0x%x\n", info->ConfigData.ATAPICommandBlockSize); - US_DEBUGP(" Master/Slave Selection: 0x%x\n", info->ConfigData.MasterSlaveSelection); - US_DEBUGP(" ATAPI Reset: 0x%x\n", info->ConfigData.ATAPIReset); - US_DEBUGP(" ATA Timing: 0x%x\n", info->ConfigData.ATATiming); - US_DEBUGP(" ATA Major Command: 0x%x\n", info->ConfigData.ATAMajorCommand); - US_DEBUGP(" ATA Minor Command: 0x%x\n", info->ConfigData.ATAMinorCommand); - US_DEBUGP(" Init Status: 0x%x\n", info->ConfigData.InitStatus); - US_DEBUGP(" Config Descriptor 2: 0x%x\n", info->ConfigData.ConfigDescriptor2); - US_DEBUGP(" Skip Device Boot: 0x%x\n", info->ConfigData.SkipDeviceBoot); - US_DEBUGP(" ATA 3 State Supsend: 0x%x\n", info->ConfigData.ATA3StateSuspend); - US_DEBUGP(" Descriptor Override: 0x%x\n", info->ConfigData.DescriptOverride); - US_DEBUGP(" Last LUN Identifier: 0x%x\n", info->ConfigData.LastLUNIdentifier); - US_DEBUGP(" SRST Enable: 0x%x\n", info->ConfigData.SRSTEnable); + isd200_log_config(info); +#endif /* let's send the command via the control pipe */ result = usb_stor_control_msg( @@ -941,8 +944,8 @@ /* STALL must be cleared when they are detected */ if (result == -EPIPE) { US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_stor_clear_halt(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, 0)); + result = usb_stor_clear_halt(us, + usb_sndctrlpipe(us->pusb_dev, 0)); US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result); } @@ -986,30 +989,17 @@ if (result >= 0) { US_DEBUGP(" Retrieved the following ISD200 Config Data:\n"); - US_DEBUGP(" Event Notification: 0x%x\n", info->ConfigData.EventNotification); - US_DEBUGP(" External Clock: 0x%x\n", info->ConfigData.ExternalClock); - US_DEBUGP(" ATA Init Timeout: 0x%x\n", info->ConfigData.ATAInitTimeout); - US_DEBUGP(" ATAPI Command Block Size: 0x%x\n", info->ConfigData.ATAPICommandBlockSize); - US_DEBUGP(" Master/Slave Selection: 0x%x\n", info->ConfigData.MasterSlaveSelection); - US_DEBUGP(" ATAPI Reset: 0x%x\n", info->ConfigData.ATAPIReset); - US_DEBUGP(" ATA Timing: 0x%x\n", info->ConfigData.ATATiming); - US_DEBUGP(" ATA Major Command: 0x%x\n", info->ConfigData.ATAMajorCommand); - US_DEBUGP(" ATA Minor Command: 0x%x\n", info->ConfigData.ATAMinorCommand); - US_DEBUGP(" Init Status: 0x%x\n", info->ConfigData.InitStatus); - US_DEBUGP(" Config Descriptor 2: 0x%x\n", info->ConfigData.ConfigDescriptor2); - US_DEBUGP(" Skip Device Boot: 0x%x\n", info->ConfigData.SkipDeviceBoot); - US_DEBUGP(" ATA 3 State Supsend: 0x%x\n", info->ConfigData.ATA3StateSuspend); - US_DEBUGP(" Descriptor Override: 0x%x\n", info->ConfigData.DescriptOverride); - US_DEBUGP(" Last LUN Identifier: 0x%x\n", info->ConfigData.LastLUNIdentifier); - US_DEBUGP(" SRST Enable: 0x%x\n", info->ConfigData.SRSTEnable); +#ifdef CONFIG_USB_STORAGE_DEBUG + isd200_log_config(info); +#endif } else { US_DEBUGP(" Request to get ISD200 Config Data failed!\n"); /* STALL must be cleared when they are detected */ if (result == -EPIPE) { US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_stor_clear_halt(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, 0)); + result = usb_stor_clear_halt(us, + usb_sndctrlpipe(us->pusb_dev, 0)); US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result); } @@ -1175,11 +1165,12 @@ break; } } else { - US_DEBUGP(" Not ATA, not ATAPI. Weird.\n"); + US_DEBUGP(" Not ATA, not ATAPI. Weird.\n"); + break; } /* check for timeout on this request */ - if (jiffies >= endTime) { + if (time_after_eq(jiffies, endTime)) { if (!detect) US_DEBUGP(" BSY check timeout, just continue with next operation...\n"); else @@ -1223,9 +1214,10 @@ } isslave = (info->DeviceHead & ATA_ADDRESS_DEVHEAD_SLAVE) ? 1 : 0; - if (info->ConfigData.MasterSlaveSelection != isslave) { + if (!(info->ConfigData.ATAConfig & ATACFG_MASTER)) { US_DEBUGP(" Setting Master/Slave selection to %d\n", isslave); - info->ConfigData.MasterSlaveSelection = isslave; + info->ConfigData.ATAConfig &= 0x3f; + info->ConfigData.ATAConfig |= (isslave<<6); retStatus = isd200_write_config(us); } } @@ -1272,6 +1264,8 @@ } else { /* ATA Command Identify successful */ int i; + __u16 *src, *dest; + ide_fix_driveid(&info->drive); US_DEBUGP(" Identify Data Structure:\n"); US_DEBUGP(" config = 0x%x\n", info->drive.config); @@ -1317,31 +1311,25 @@ if (info->drive.command_set_1 & COMMANDSET_MEDIA_STATUS) { /* set the removable bit */ - info->InquiryData.RemovableMedia = 1; + info->InquiryData.DeviceTypeModifier = DEVICE_REMOVABLE; info->DeviceFlags |= DF_REMOVABLE_MEDIA; } /* Fill in vendor identification fields */ - for (i = 0; i < 20; i += 2) { - info->InquiryData.VendorId[i] = - info->drive.model[i + 1]; - info->InquiryData.VendorId[i+1] = - info->drive.model[i]; - } - - /* Initialize unused portion of product id */ - for (i = 0; i < 4; i++) { - info->InquiryData.ProductId[12+i] = ' '; - } - - /* Move firmware revision from IDENTIFY data to */ - /* product revision in INQUIRY data */ - for (i = 0; i < 4; i += 2) { - info->InquiryData.ProductRevisionLevel[i] = - info->drive.fw_rev[i+1]; - info->InquiryData.ProductRevisionLevel[i+1] = - info->drive.fw_rev[i]; - } + src = (__u16*)info->drive.model; + dest = (__u16*)info->InquiryData.VendorId; + for (i=0;i<4;i++) + dest[i] = be16_to_cpu(src[i]); + + src = (__u16*)(info->drive.model+8); + dest = (__u16*)info->InquiryData.ProductId; + for (i=0;i<8;i++) + dest[i] = be16_to_cpu(src[i]); + + src = (__u16*)info->drive.fw_rev; + dest = (__u16*)info->InquiryData.ProductRevisionLevel; + for (i=0;i<2;i++) + dest[i] = be16_to_cpu(src[i]); /* determine if it supports Media Status Notification */ if (info->drive.command_set_2 & COMMANDSET_MEDIA_STATUS) { @@ -1483,7 +1471,7 @@ ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 1; - ataCdb->write.SelectCommand = 1; + ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; srb->request_bufflen = 0; } else { @@ -1504,7 +1492,7 @@ ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 1; - ataCdb->write.SelectCommand = 1; + ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; srb->request_bufflen = 0; } else { @@ -1561,17 +1549,15 @@ ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 1; - ataCdb->write.SelectSectorCount = 1; + ataCdb->generic.RegisterSelect = + REG_SECTOR_COUNT | REG_SECTOR_NUMBER | + REG_CYLINDER_LOW | REG_CYLINDER_HIGH | + REG_DEVICE_HEAD | REG_COMMAND; ataCdb->write.SectorCountByte = (unsigned char)blockCount; - ataCdb->write.SelectSectorNumber = 1; ataCdb->write.SectorNumberByte = sectnum; - ataCdb->write.SelectCylinderHigh = 1; ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8); - ataCdb->write.SelectCylinderLow = 1; ataCdb->write.CylinderLowByte = (unsigned char)cylinder; - ataCdb->write.SelectDeviceHead = 1; ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD); - ataCdb->write.SelectCommand = 1; ataCdb->write.CommandByte = WIN_READ; break; @@ -1594,17 +1580,15 @@ ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 1; - ataCdb->write.SelectSectorCount = 1; + ataCdb->generic.RegisterSelect = + REG_SECTOR_COUNT | REG_SECTOR_NUMBER | + REG_CYLINDER_LOW | REG_CYLINDER_HIGH | + REG_DEVICE_HEAD | REG_COMMAND; ataCdb->write.SectorCountByte = (unsigned char)blockCount; - ataCdb->write.SelectSectorNumber = 1; ataCdb->write.SectorNumberByte = sectnum; - ataCdb->write.SelectCylinderHigh = 1; ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8); - ataCdb->write.SelectCylinderLow = 1; ataCdb->write.CylinderLowByte = (unsigned char)cylinder; - ataCdb->write.SelectDeviceHead = 1; ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD); - ataCdb->write.SelectCommand = 1; ataCdb->write.CommandByte = WIN_WRITE; break; @@ -1617,7 +1601,7 @@ ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 1; - ataCdb->write.SelectCommand = 1; + ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = (srb->cmnd[4] & 0x1) ? WIN_DOORLOCK : WIN_DOORUNLOCK; srb->request_bufflen = 0; @@ -1640,14 +1624,14 @@ ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 0; - ataCdb->write.SelectCommand = 1; + ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = ATA_COMMAND_MEDIA_EJECT; } else if ((srb->cmnd[4] & 0x3) == 0x1) { US_DEBUGP(" Get Media Status\n"); ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 1; - ataCdb->write.SelectCommand = 1; + ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; srb->request_bufflen = 0; } else { diff -Nru a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c --- a/drivers/usb/storage/jumpshot.c Mon Mar 4 08:48:59 2002 +++ b/drivers/usb/storage/jumpshot.c Mon Mar 4 08:48:59 2002 @@ -1,16 +1,26 @@ /* Driver for Lexar "Jumpshot" Compact Flash reader * + * $Id: jumpshot.c,v 1.7 2002/02/25 00:40:13 mdharm Exp $ + * * jumpshot driver v0.1: * * First release * * Current development and maintenance by: * (c) 2000 Jimmie Mayfield (mayfield+usb@sackheads.org) - * many thanks to Robert Baruch for the SanDisk SmartMedia reader driver + * + * Many thanks to Robert Baruch for the SanDisk SmartMedia reader driver * which I used as a template for this driver. + * * Some bugfixes and scatter-gather code by Gregory P. Smith * (greg-usb@electricrain.com) * + * Fix for media change by Joerg Schneider (js@joergschneider.com) + * + * Developed with the assistance of: + * + * (C) 2002 Alan Stern + * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any @@ -128,8 +138,8 @@ /* a stall is a fatal condition from the device */ if (result == -EPIPE) { US_DEBUGP("jumpshot_send_control: -- Stall on control pipe. Clearing\n"); - result = usb_clear_halt(us->pusb_dev, pipe); - US_DEBUGP("jumpshot_send_control: -- usb_clear_halt() returns %d\n", result); + result = usb_stor_clear_halt(us, pipe); + US_DEBUGP("jumpshot_send_control: -- usb_stor_clear_halt() returns %d\n", result); return USB_STOR_TRANSPORT_FAILED; } @@ -161,7 +171,7 @@ if (result == -EPIPE) { US_DEBUGP("jumpshot_raw_bulk: EPIPE. clearing endpoint halt for" " pipe 0x%x, stalled at %d bytes\n", pipe, act_len); - usb_clear_halt(us->pusb_dev, pipe); + usb_stor_clear_halt(us, pipe); } if (result) { @@ -798,6 +808,23 @@ // return USB_STOR_TRANSPORT_GOOD; } + + if (srb->cmnd[0] == START_STOP) { + /* this is used by sd.c'check_scsidisk_media_change to detect + media change */ + US_DEBUGP("jumpshot_transport: START_STOP.\n"); + /* the first jumpshot_id_device after a media change returns + an error (determined experimentally) */ + rc = jumpshot_id_device(us, info); + if (rc == USB_STOR_TRANSPORT_GOOD) { + info->sense_key = NO_SENSE; + srb->result = SUCCESS; + } else { + info->sense_key = UNIT_ATTENTION; + srb->result = CHECK_CONDITION; + } + return rc; + } US_DEBUGP("jumpshot_transport: Gah! Unknown command: %d (0x%x)\n", srb->cmnd[0], srb->cmnd[0]); return USB_STOR_TRANSPORT_ERROR; diff -Nru a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c --- a/drivers/usb/storage/protocol.c Mon Mar 4 08:48:58 2002 +++ b/drivers/usb/storage/protocol.c Mon Mar 4 08:48:58 2002 @@ -1,12 +1,13 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: protocol.c,v 1.11 2002/01/13 06:40:25 mdharm Exp $ + * $Id: protocol.c,v 1.13 2002/02/25 00:34:56 mdharm Exp $ * * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * Developed with the assistance of: * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) + * (c) 2002 Alan Stern (stern@rowland.org) * * Initial work by: * (c) 1999 Michael Gee (michael@linuxspecific.com) @@ -97,9 +98,11 @@ /* send the command to the transport layer */ usb_stor_invoke_transport(srb, us); + if (srb->result == GOOD << 1) { - /* fix the INQUIRY data if necessary */ - fix_inquiry_data(srb); + /* fix the INQUIRY data if necessary */ + fix_inquiry_data(srb); + } } void usb_stor_ATAPI_command(Scsi_Cmnd *srb, struct us_data *us) @@ -168,13 +171,15 @@ /* send the command to the transport layer */ usb_stor_invoke_transport(srb, us); + if (srb->result == GOOD << 1) { - /* Fix the MODE_SENSE data if we translated the command */ - if ((old_cmnd == MODE_SENSE) && (status_byte(srb->result) == GOOD)) - usb_stor_scsiSense10to6(srb); - - /* fix the INQUIRY data if necessary */ - fix_inquiry_data(srb); + /* Fix the MODE_SENSE data if we translated the command */ + if (old_cmnd == MODE_SENSE) + usb_stor_scsiSense10to6(srb); + + /* fix the INQUIRY data if necessary */ + fix_inquiry_data(srb); + } } @@ -263,13 +268,15 @@ /* send the command to the transport layer */ usb_stor_invoke_transport(srb, us); + if (srb->result == GOOD << 1) { - /* Fix the MODE_SENSE data if we translated the command */ - if ((old_cmnd == MODE_SENSE) && (status_byte(srb->result) == GOOD)) - usb_stor_scsiSense10to6(srb); - - /* Fix the data for an INQUIRY, if necessary */ - fix_inquiry_data(srb); + /* Fix the MODE_SENSE data if we translated the command */ + if (old_cmnd == MODE_SENSE) + usb_stor_scsiSense10to6(srb); + + /* Fix the data for an INQUIRY, if necessary */ + fix_inquiry_data(srb); + } } void usb_stor_transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us) @@ -330,13 +337,14 @@ /* send the command to the transport layer */ usb_stor_invoke_transport(srb, us); + if (srb->result == GOOD << 1) { - /* Fix the MODE_SENSE data if we translated the command */ - if ((us->flags & US_FL_MODE_XLATE) && (old_cmnd == MODE_SENSE) - && (status_byte(srb->result) == GOOD)) - usb_stor_scsiSense10to6(srb); - - /* fix the INQUIRY data if necessary */ - fix_inquiry_data(srb); + /* Fix the MODE_SENSE data if we translated the command */ + if ((us->flags & US_FL_MODE_XLATE) && (old_cmnd == MODE_SENSE)) + usb_stor_scsiSense10to6(srb); + + /* fix the INQUIRY data if necessary */ + fix_inquiry_data(srb); + } } diff -Nru a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c --- a/drivers/usb/storage/sddr09.c Mon Mar 4 08:48:58 2002 +++ b/drivers/usb/storage/sddr09.c Mon Mar 4 08:48:58 2002 @@ -1,6 +1,6 @@ /* Driver for SanDisk SDDR-09 SmartMedia reader * - * $Id: sddr09.c,v 1.22 2001/12/08 23:32:48 mdharm Exp $ + * $Id: sddr09.c,v 1.23 2002/02/25 00:40:13 mdharm Exp $ * * SDDR09 driver v0.1: * @@ -9,6 +9,9 @@ * Current development and maintenance by: * (c) 2000, 2001 Robert Baruch (autophile@starband.net) * + * Developed with the assistance of: + * (c) 2002 Alan Stern + * * The SanDisk SDDR-09 SmartMedia reader uses the Shuttle EUSB-01 chip. * This chip is a programmable USB controller. In the SDDR-09, it has * been programmed to obey a certain limited set of SCSI commands. This @@ -113,8 +116,8 @@ /* a stall is a fatal condition from the device */ if (result == -EPIPE) { US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_clear_halt(us->pusb_dev, pipe); - US_DEBUGP("-- usb_clear_halt() returns %d\n", result); + result = usb_stor_clear_halt(us, pipe); + US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result); return USB_STOR_TRANSPORT_FAILED; } @@ -146,7 +149,7 @@ US_DEBUGP("EPIPE: clearing endpoint halt for" " pipe 0x%x, stalled at %d bytes\n", pipe, act_len); - usb_clear_halt(us->pusb_dev, pipe); + usb_stor_clear_halt(us, pipe); } if (result) { diff -Nru a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c --- a/drivers/usb/storage/shuttle_usbat.c Mon Mar 4 08:49:01 2002 +++ b/drivers/usb/storage/shuttle_usbat.c Mon Mar 4 08:49:01 2002 @@ -1,10 +1,13 @@ /* Driver for SCM Microsystems USB-ATAPI cable * - * $Id: shuttle_usbat.c,v 1.15 2001/12/08 23:32:48 mdharm Exp $ + * $Id: shuttle_usbat.c,v 1.16 2002/02/25 00:40:13 mdharm Exp $ * * Current development and maintenance by: * (c) 2000, 2001 Robert Baruch (autophile@starband.net) * + * Developed with the assistance of: + * (c) 2002 Alan Stern + * * Many originally ATAPI devices were slightly modified to meet the USB * market by using some kind of translation from ATAPI to USB on the host, * and the peripheral would translate from USB back to ATAPI. @@ -107,8 +110,8 @@ /* a stall is a fatal condition from the device */ if (result == -EPIPE) { US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_clear_halt(us->pusb_dev, pipe); - US_DEBUGP("-- usb_clear_halt() returns %d\n", result); + result = usb_stor_clear_halt(us, pipe); + US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result); return USB_STOR_TRANSPORT_FAILED; } @@ -140,7 +143,7 @@ US_DEBUGP("EPIPE: clearing endpoint halt for" " pipe 0x%x, stalled at %d bytes\n", pipe, act_len); - usb_clear_halt(us->pusb_dev, pipe); + usb_stor_clear_halt(us, pipe); } if (result) { @@ -515,7 +518,7 @@ */ if (direction==SCSI_DATA_READ && i==0) - usb_clear_halt(us->pusb_dev, + usb_stor_clear_halt(us, usb_sndbulkpipe(us->pusb_dev, us->ep_out)); /* @@ -675,9 +678,15 @@ len = short_pack(data[7+9], data[7+8]); len <<= 16; len |= data[7+7]; + US_DEBUGP("handle_read10: GPCMD_READ_CD: len %d\n", len); srb->transfersize = srb->request_bufflen/len; } + if (!srb->transfersize) { + srb->transfersize = 2048; /* A guess */ + US_DEBUGP("handle_read10: transfersize 0, forcing %d\n", + srb->transfersize); + } len = (65535/srb->transfersize) * srb->transfersize; US_DEBUGP("Max read is %d bytes\n", len); diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c --- a/drivers/usb/storage/transport.c Mon Mar 4 08:48:59 2002 +++ b/drivers/usb/storage/transport.c Mon Mar 4 08:48:59 2002 @@ -1,13 +1,14 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: transport.c,v 1.42 2001/12/08 23:32:48 mdharm Exp $ + * $Id: transport.c,v 1.44 2002/02/25 00:43:41 mdharm Exp $ * * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * Developed with the assistance of: * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) * (c) 2000 Stephen J. Gowdy (SGowdy@lbl.gov) + * (c) 2002 Alan Stern * * Initial work by: * (c) 1999 Michael Gee (michael@linuxspecific.com) @@ -335,31 +336,7 @@ len = srb->request_bufflen; } -return len; -} - -/* This is a version of usb_clear_halt() that doesn't read the status from - * the device -- this is because some devices crash their internal firmware - * when the status is requested after a halt - */ -int usb_stor_clear_halt(struct usb_device *dev, int pipe) -{ - int result; - int endp = usb_pipeendpoint(pipe) | (usb_pipein(pipe) << 7); - - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, - endp, NULL, 0, HZ * 3); - - /* this is a failure case */ - if (result < 0) - return result; - - /* reset the toggles and endpoint flags */ - usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); - usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); - - return 0; + return len; } /*********************************************************************** @@ -481,6 +458,34 @@ return us->current_urb->status; } +/* This is a version of usb_clear_halt() that doesn't read the status from + * the device -- this is because some devices crash their internal firmware + * when the status is requested after a halt + */ +int usb_stor_clear_halt(struct us_data *us, int pipe) +{ + int result; + int endp = usb_pipeendpoint(pipe) | (usb_pipein(pipe) << 7); + + result = usb_stor_control_msg(us, + usb_sndctrlpipe(us->pusb_dev, 0), + USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, + endp, NULL, 0); /* note: no 3*HZ timeout */ + US_DEBUGP("usb_stor_clear_halt: result=%d\n", result); + + /* this is a failure case */ + if (result < 0) + return result; + + /* reset the toggles and endpoint flags */ + usb_endpoint_running(us->pusb_dev, usb_pipeendpoint(pipe), + usb_pipeout(pipe)); + usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe), + usb_pipeout(pipe), 0); + + return 0; +} + /* * Transfer one SCSI scatter-gather buffer via bulk transfer * @@ -513,7 +518,13 @@ /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); + usb_stor_clear_halt(us, pipe); + } + + /* did we abort this command? */ + if (result == -ENOENT) { + US_DEBUGP("usb_stor_transfer_partial(): transfer aborted\n"); + return US_BULK_TRANSFER_ABORTED; } /* did we send all the data? */ @@ -522,21 +533,14 @@ return US_BULK_TRANSFER_GOOD; } - /* uh oh... we have an error code, so something went wrong. */ - if (result) { - /* NAK - that means we've retried a few times already */ - if (result == -ETIMEDOUT) { - US_DEBUGP("usb_stor_transfer_partial(): device NAKed\n"); - return US_BULK_TRANSFER_FAILED; - } - - /* -ENOENT -- we canceled this transfer */ - if (result == -ENOENT) { - US_DEBUGP("usb_stor_transfer_partial(): transfer aborted\n"); - return US_BULK_TRANSFER_ABORTED; - } + /* NAK - that means we've retried a few times already */ + if (result == -ETIMEDOUT) { + US_DEBUGP("usb_stor_transfer_partial(): device NAKed\n"); + return US_BULK_TRANSFER_FAILED; + } - /* the catch-all case */ + /* the catch-all error case */ + if (result) { US_DEBUGP("usb_stor_transfer_partial(): unknown error\n"); return US_BULK_TRANSFER_FAILED; } @@ -550,7 +554,7 @@ * Transfer an entire SCSI command's worth of data payload over the bulk * pipe. * - * Note that this uses usb_stor_transfer_partial to achieve it's goals -- this + * Note that this uses usb_stor_transfer_partial to achieve its goals -- this * function simply determines if we're going to use scatter-gather or not, * and acts appropriately. For now, it also re-interprets the error codes. */ @@ -631,6 +635,14 @@ return; } + /* if there is a transport error, reset and don't auto-sense */ + if (result == USB_STOR_TRANSPORT_ERROR) { + US_DEBUGP("-- transport indicates error, resetting\n"); + us->transport_reset(us); + srb->result = DID_ERROR << 16; + return; + } + /* Determine if we need to auto-sense * * I normally don't use a flag like this, but it's almost impossible @@ -660,7 +672,7 @@ } /* - * If we have an error, we're going to do a REQUEST_SENSE + * If we have a failure, we're going to do a REQUEST_SENSE * automatically. Note that we differentiate between a command * "failure" and an "error" in the transport mechanism. */ @@ -668,13 +680,6 @@ US_DEBUGP("-- transport indicates command failure\n"); need_auto_sense = 1; } - if (result == USB_STOR_TRANSPORT_ERROR) { - us->transport_reset(us); - US_DEBUGP("-- transport indicates transport failure\n"); - need_auto_sense = 0; - srb->result = DID_ERROR << 16; - return; - } /* * Also, if we have a short transfer on a command that can't have @@ -730,6 +735,19 @@ /* issue the auto-sense command */ temp_result = us->transport(us->srb, us); + + /* let's clean up right away */ + srb->request_buffer = old_request_buffer; + srb->request_bufflen = old_request_bufflen; + srb->use_sg = old_sg; + srb->sc_data_direction = old_sc_data_direction; + memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE); + + if (temp_result == USB_STOR_TRANSPORT_ABORTED) { + US_DEBUGP("-- auto-sense aborted\n"); + srb->result = DID_ABORT << 16; + return; + } if (temp_result != USB_STOR_TRANSPORT_GOOD) { US_DEBUGP("-- auto-sense failure\n"); @@ -760,13 +778,6 @@ /* set the result so the higher layers expect this data */ srb->result = CHECK_CONDITION << 1; - /* we're done here, let's clean up */ - srb->request_buffer = old_request_buffer; - srb->request_bufflen = old_request_bufflen; - srb->use_sg = old_sg; - srb->sc_data_direction = old_sc_data_direction; - memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE); - /* If things are really okay, then let's show that */ if ((srb->sense_buffer[2] & 0xf) == 0x0) srb->result = GOOD << 1; @@ -864,21 +875,25 @@ if (result < 0) { /* Reset flag for status notification */ atomic_set(us->ip_wanted, 0); + } + + /* if the command was aborted, indicate that */ + if (result == -ENOENT) + return USB_STOR_TRANSPORT_ABORTED; + + /* STALL must be cleared when it is detected */ + if (result == -EPIPE) { + US_DEBUGP("-- Stall on control pipe. Clearing\n"); + result = usb_stor_clear_halt(us, + usb_sndctrlpipe(us->pusb_dev, 0)); /* if the command was aborted, indicate that */ if (result == -ENOENT) return USB_STOR_TRANSPORT_ABORTED; + return USB_STOR_TRANSPORT_FAILED; + } - /* STALL must be cleared when they are detected */ - if (result == -EPIPE) { - US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_stor_clear_halt(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, - 0)); - US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result); - return USB_STOR_TRANSPORT_FAILED; - } - + if (result < 0) { /* Uh oh... serious problem here */ return USB_STOR_TRANSPORT_ERROR; } @@ -887,12 +902,18 @@ /* transfer the data payload for this command, if one exists*/ if (usb_stor_transfer_length(srb)) { usb_stor_transfer(srb, us); - US_DEBUGP("CBI data stage result is 0x%x\n", srb->result); + result = srb->result; + US_DEBUGP("CBI data stage result is 0x%x\n", result); - /* if it was aborted, we need to indicate that */ - if (srb->result == USB_STOR_TRANSPORT_ABORTED) { + /* report any errors */ + if (result == US_BULK_TRANSFER_ABORTED) { + atomic_set(us->ip_wanted, 0); return USB_STOR_TRANSPORT_ABORTED; } + if (result == US_BULK_TRANSFER_FAILED) { + atomic_set(us->ip_wanted, 0); + return USB_STOR_TRANSPORT_FAILED; + } } /* STATUS STAGE */ @@ -976,10 +997,12 @@ /* a stall is a fatal condition from the device */ if (result == -EPIPE) { US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_stor_clear_halt(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, - 0)); - US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result); + result = usb_stor_clear_halt(us, + usb_sndctrlpipe(us->pusb_dev, 0)); + + /* if the command was aborted, indicate that */ + if (result == -ENOENT) + return USB_STOR_TRANSPORT_ABORTED; return USB_STOR_TRANSPORT_FAILED; } @@ -991,11 +1014,16 @@ /* transfer the data payload for this command, if one exists*/ if (usb_stor_transfer_length(srb)) { usb_stor_transfer(srb, us); - US_DEBUGP("CB data stage result is 0x%x\n", srb->result); + result = srb->result; + US_DEBUGP("CB data stage result is 0x%x\n", result); - /* if it was aborted, we need to indicate that */ - if (srb->result == USB_STOR_TRANSPORT_ABORTED) + /* report any errors */ + if (result == US_BULK_TRANSFER_ABORTED) { return USB_STOR_TRANSPORT_ABORTED; + } + if (result == US_BULK_TRANSFER_FAILED) { + return USB_STOR_TRANSPORT_FAILED; + } } /* STATUS STAGE */ @@ -1016,7 +1044,8 @@ int result; int pipe; - /* issue the command */ + /* issue the command -- use usb_control_msg() because + * the state machine is not yet alive */ pipe = usb_rcvctrlpipe(us->pusb_dev, 0); result = usb_control_msg(us->pusb_dev, pipe, US_BULK_GET_MAX_LUN, @@ -1034,7 +1063,10 @@ /* if we get a STALL, clear the stall */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); + + /* Use usb_clear_halt() because the state machine + * is not yet alive */ + usb_clear_halt(us->pusb_dev, pipe); } /* return the default -- no LUNs */ @@ -1051,10 +1083,6 @@ int pipe; int partial; - /* if the device was removed, then we're already reset */ - if (!us->pusb_dev) - return SUCCESS; - /* set up the command wrapper */ bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN); bcb.DataTransferLength = cpu_to_le32(usb_stor_transfer_length(srb)); @@ -1088,7 +1116,12 @@ /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); + result = usb_stor_clear_halt(us, pipe); + + /* if the command was aborted, indicate that */ + if (result == -ENOENT) + return USB_STOR_TRANSPORT_ABORTED; + result = -EPIPE; } else if (result) { /* unknown error -- we've got a problem */ return USB_STOR_TRANSPORT_ERROR; @@ -1099,11 +1132,11 @@ /* send/receive data payload, if there is any */ if (bcb.DataTransferLength) { usb_stor_transfer(srb, us); - US_DEBUGP("Bulk data transfer result 0x%x\n", - srb->result); + result = srb->result; + US_DEBUGP("Bulk data transfer result 0x%x\n", result); /* if it was aborted, we need to indicate that */ - if (srb->result == USB_STOR_TRANSPORT_ABORTED) + if (result == US_BULK_TRANSFER_ABORTED) return USB_STOR_TRANSPORT_ABORTED; } } @@ -1127,8 +1160,12 @@ /* did the attempt to read the CSW fail? */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); - + result = usb_stor_clear_halt(us, pipe); + + /* if the command was aborted, indicate that */ + if (result == -ENOENT) + return USB_STOR_TRANSPORT_ABORTED; + /* get the status again */ US_DEBUGP("Attempting to get CSW (2nd try)...\n"); result = usb_stor_bulk_msg(us, &bcs, pipe, @@ -1141,7 +1178,11 @@ /* if it fails again, we need a reset and return an error*/ if (result == -EPIPE) { US_DEBUGP("clearing halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us->pusb_dev, pipe); + result = usb_stor_clear_halt(us, pipe); + + /* if the command was aborted, indicate that */ + if (result == -ENOENT) + return USB_STOR_TRANSPORT_ABORTED; return USB_STOR_TRANSPORT_ERROR; } } @@ -1220,10 +1261,10 @@ set_current_state(TASK_RUNNING); US_DEBUGP("CB_reset: clearing endpoint halt\n"); - usb_stor_clear_halt(us->pusb_dev, - usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); - usb_stor_clear_halt(us->pusb_dev, - usb_rcvbulkpipe(us->pusb_dev, us->ep_out)); + usb_stor_clear_halt(us, + usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); + usb_stor_clear_halt(us, + usb_sndbulkpipe(us->pusb_dev, us->ep_out)); US_DEBUGP("CB_reset done\n"); /* return a result code based on the result of the control message */ @@ -1259,10 +1300,10 @@ schedule_timeout(HZ*6); set_current_state(TASK_RUNNING); - usb_stor_clear_halt(us->pusb_dev, - usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); - usb_stor_clear_halt(us->pusb_dev, - usb_sndbulkpipe(us->pusb_dev, us->ep_out)); + usb_stor_clear_halt(us, + usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); + usb_stor_clear_halt(us, + usb_sndbulkpipe(us->pusb_dev, us->ep_out)); US_DEBUGP("Bulk soft reset completed\n"); return SUCCESS; } diff -Nru a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h --- a/drivers/usb/storage/transport.h Mon Mar 4 08:48:58 2002 +++ b/drivers/usb/storage/transport.h Mon Mar 4 08:48:58 2002 @@ -1,7 +1,7 @@ /* Driver for USB Mass Storage compliant devices * Transport Functions Header File * - * $Id: transport.h,v 1.15 2001/03/17 20:06:23 jrmayfield Exp $ + * $Id: transport.h,v 1.17 2002/02/25 00:43:41 mdharm Exp $ * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -112,7 +112,7 @@ #define US_BULK_GET_MAX_LUN 0xfe /* - * us_bulk_transfer() return codes + * usb_stor_transfer() return codes */ #define US_BULK_TRANSFER_GOOD 0 /* good transfer */ #define US_BULK_TRANSFER_SHORT 1 /* transfered less than expected */ @@ -151,6 +151,6 @@ unsigned int*); extern int usb_stor_control_msg(struct us_data*, unsigned int, u8, u8, u16, u16, void*, u16); +extern int usb_stor_clear_halt(struct us_data*, int ); extern void usb_stor_transfer(Scsi_Cmnd*, struct us_data*); -extern int usb_stor_clear_halt(struct usb_device*, int ); #endif diff -Nru a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h --- a/drivers/usb/storage/unusual_devs.h Mon Mar 4 08:48:59 2002 +++ b/drivers/usb/storage/unusual_devs.h Mon Mar 4 08:48:59 2002 @@ -1,10 +1,10 @@ /* Driver for USB Mass Storage compliant devices * Ununsual Devices File * - * $Id: unusual_devs.h,v 1.25 2002/01/13 06:39:17 mdharm Exp $ + * $Id: unusual_devs.h,v 1.32 2002/02/25 02:41:24 mdharm Exp $ * * Current development and maintenance by: - * (c) 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * (c) 2000-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * Initial work by: * (c) 2000 Adam J. Richter (adam@yggdrasil.com), Yggdrasil Computing, Inc. @@ -198,7 +198,7 @@ /* This entry is needed because the device reports Sub=ff */ UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0422, "Sony", - "DSC-S30/S70/S75/505V/F505", + "DSC-S30/S70/S75/505V/F505/F707", US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE ), @@ -289,9 +289,30 @@ "Lexar", "Jumpshot USB CF Reader", US_SC_SCSI, US_PR_JUMPSHOT, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), + US_FL_MODE_XLATE ), #endif +/* Reported by Carlos Villegas + * This device needs an INQUIRY of exactly 36-bytes to function. + * That is the only reason this entry is needed. + */ +UNUSUAL_DEV( 0x05e3, 0x0700, 0x0000, 0xffff, + "SIIG", + "CompactFlash Card Reader", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_FIX_INQUIRY ), + +/* Reported by Peter Marks + * Like the SIIG unit above, this unit needs an INQUIRY to ask for exactly + * 36 bytes of data. No more, no less. That is the only reason this entry + * is needed. + */ +UNUSUAL_DEV( 0x05e3, 0x0702, 0x0000, 0xffff, + "EagleTec", + "External Hard Disk", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_FIX_INQUIRY ), + UNUSUAL_DEV( 0x0644, 0x0000, 0x0100, 0x0100, "TEAC", "Floppy Drive", @@ -305,6 +326,14 @@ US_FL_SINGLE_LUN | US_FL_START_STOP ), #endif +/* Submitted by kedar@centillium + * Needed for START_STOP flag, but that is unconfirmed */ +UNUSUAL_DEV( 0x0686, 0x4006, 0x0001, 0x0001, + "Minolta", + "Dimage S304", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_START_STOP ), + /* Submitted by f.brugmans@hccnet.nl * Needed for START_STOP flag */ UNUSUAL_DEV( 0x0686, 0x4007, 0x0001, 0x0001, @@ -381,7 +410,7 @@ "Datafab", "MDCFE-B USB CF Reader", US_SC_SCSI, US_PR_DATAFAB, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), + US_FL_MODE_XLATE ), /* * The following Datafab-based devices may or may not work @@ -398,38 +427,38 @@ "SIIG/Datafab", "SIIG/Datafab Memory Stick+CF Reader/Writer", US_SC_SCSI, US_PR_DATAFAB, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), + US_FL_MODE_XLATE ), UNUSUAL_DEV( 0x07c4, 0xa003, 0x0000, 0xffff, "Datafab/Unknown", "Datafab-based Reader", US_SC_SCSI, US_PR_DATAFAB, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), + US_FL_MODE_XLATE ), UNUSUAL_DEV( 0x07c4, 0xa004, 0x0000, 0xffff, "Datafab/Unknown", "Datafab-based Reader", US_SC_SCSI, US_PR_DATAFAB, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), + US_FL_MODE_XLATE ), UNUSUAL_DEV( 0x07c4, 0xa005, 0x0000, 0xffff, "PNY/Datafab", "PNY/Datafab CF+SM Reader", US_SC_SCSI, US_PR_DATAFAB, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), + US_FL_MODE_XLATE ), UNUSUAL_DEV( 0x07c4, 0xa006, 0x0000, 0xffff, "Simple Tech/Datafab", "Simple Tech/Datafab CF+SM Reader", US_SC_SCSI, US_PR_DATAFAB, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), + US_FL_MODE_XLATE ), /* Submitted by Olaf Hering */ UNUSUAL_DEV( 0x07c4, 0xa109, 0x0000, 0xffff, "Datafab Systems, Inc.", "USB to CF + SM Combo (LC1)", US_SC_SCSI, US_PR_DATAFAB, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP ), + US_FL_MODE_XLATE ), #endif /* Casio QV 2x00/3x00/4000/8000 digital still cameras are not conformant @@ -469,6 +498,8 @@ /* Reported by Dan Pilone * The device needs the flags only. + * Also reported by Brian Hall , again for flags. + * I also suspect this device may have a broken serial number. */ UNUSUAL_DEV( 0x1065, 0x2136, 0x0000, 0x9999, "CCYU TECHNOLOGY", diff -Nru a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c --- a/drivers/usb/storage/usb.c Mon Mar 4 08:49:00 2002 +++ b/drivers/usb/storage/usb.c Mon Mar 4 08:49:00 2002 @@ -1,9 +1,9 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: usb.c,v 1.70 2002/01/06 07:14:12 mdharm Exp $ + * $Id: usb.c,v 1.73 2002/01/27 09:02:15 mdharm Exp $ * * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * Developed with the assistance of: * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) @@ -318,6 +318,7 @@ current->files = init_task.files; atomic_inc(¤t->files->count); daemonize(); + reparent_to_init(); /* avoid getting signals */ spin_lock_irq(¤t->sigmask_lock); @@ -958,6 +959,7 @@ ss->protocol_name = "Unknown"; kfree(ss->current_urb); kfree(ss); + usb_dec_dev_use(dev); return NULL; break; } @@ -965,6 +967,8 @@ /* allocate an IRQ callback if one is needed */ if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss)) { + kfree(ss->current_urb); + kfree(ss); usb_dec_dev_use(dev); return NULL; }