# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.539 -> 1.540 # drivers/usb/storage/shuttle_usbat.c 1.7 -> 1.8 # drivers/usb/storage/protocol.c 1.6 -> 1.7 # drivers/usb/storage/jumpshot.c 1.8 -> 1.9 # drivers/usb/storage/debug.c 1.7 -> 1.8 # drivers/usb/storage/usb.c 1.16 -> 1.17 # drivers/usb/storage/transport.c 1.15 -> 1.16 # drivers/usb/storage/transport.h 1.6 -> 1.7 # drivers/usb/storage/freecom.c 1.10 -> 1.11 # drivers/usb/storage/isd200.c 1.7 -> 1.8 # drivers/usb/storage/scsiglue.c 1.16 -> 1.17 # drivers/usb/storage/usb.h 1.6 -> 1.7 # drivers/usb/storage/unusual_devs.h 1.11 -> 1.12 # drivers/usb/storage/sddr09.c 1.13 -> 1.14 # drivers/usb/storage/datafab.c 1.7 -> 1.8 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/05/11 greg@kroah.com 1.540 # USB storage # # sync up with both the -dj and cvs version of the usb-storage code. # -------------------------------------------- # diff -Nru a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c --- a/drivers/usb/storage/datafab.c Sat May 11 22:29:15 2002 +++ b/drivers/usb/storage/datafab.c Sat May 11 22:29:15 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 Sat May 11 22:29:14 2002 +++ b/drivers/usb/storage/debug.c Sat May 11 22:29:14 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.9 2002/04/22 03:39:43 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) @@ -302,9 +305,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; @@ -327,7 +332,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="medium not present"; 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/freecom.c b/drivers/usb/storage/freecom.c --- a/drivers/usb/storage/freecom.c Sat May 11 22:29:14 2002 +++ b/drivers/usb/storage/freecom.c Sat May 11 22:29:14 2002 @@ -1,6 +1,6 @@ /* Driver for Freecom USB/IDE adaptor * - * $Id: freecom.c,v 1.21 2001/12/29 03:47:33 mdharm Exp $ + * $Id: freecom.c,v 1.22 2002/04/22 03:39:43 mdharm Exp $ * * Freecom v0.1: * diff -Nru a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c --- a/drivers/usb/storage/isd200.c Sat May 11 22:29:14 2002 +++ b/drivers/usb/storage/isd200.c Sat May 11 22:29:14 2002 @@ -1,9 +1,15 @@ /* Transport & Protocol Driver for In-System Design, Inc. ISD200 ASIC * - * First release + * $Id: isd200.c,v 1.16 2002/04/22 03:39:43 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? */ @@ -524,7 +507,7 @@ } else result = isd200_transfer_partial(us, srb->sc_data_direction, - page_address(sg[i].page) + sg[i].offset, + page_address(sg[i].page) + sg[i].offset, transfer_amount - total_transferred); /* if we get an error, end the loop here */ @@ -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 Sat May 11 22:29:14 2002 +++ b/drivers/usb/storage/jumpshot.c Sat May 11 22:29:14 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 Sat May 11 22:29:14 2002 +++ b/drivers/usb/storage/protocol.c Sat May 11 22:29:14 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.14 2002/04/22 03:39:43 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) @@ -67,10 +68,16 @@ US_DEBUGP("Fixing INQUIRY data to show SCSI rev 2\n"); /* find the location of the data */ - if (srb->use_sg) - BUG(); - - data_ptr = (unsigned char *) srb->request_buffer; + if (srb->use_sg) { + /* this piece of code only works if the first page is big enough to + * hold more than 3 bytes -- which is _very_ likely + */ + struct scatterlist *sg; + + sg = (struct scatterlist *) srb->request_buffer; + data_ptr = (unsigned char *) page_address(sg[0].page) + sg[0].offset; + } else + data_ptr = (unsigned char *)srb->request_buffer; /* Change the SCSI revision number */ data_ptr[2] = (data_ptr[2] & ~7) | 2; @@ -94,9 +101,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) @@ -165,13 +174,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); + } } @@ -260,13 +271,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) @@ -327,13 +340,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/scsiglue.c b/drivers/usb/storage/scsiglue.c --- a/drivers/usb/storage/scsiglue.c Sat May 11 22:29:14 2002 +++ b/drivers/usb/storage/scsiglue.c Sat May 11 22:29:14 2002 @@ -1,7 +1,7 @@ /* Driver for USB Mass Storage compliant devices * SCSI layer glue code * - * $Id: scsiglue.c,v 1.24 2001/11/11 03:33:58 mdharm Exp $ + * $Id: scsiglue.c,v 1.26 2002/04/22 03:39:43 mdharm Exp $ * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -177,22 +177,8 @@ US_DEBUGP("command_abort() called\n"); - /* if we're stuck waiting for an IRQ, simulate it */ - if (atomic_read(us->ip_wanted)) { - US_DEBUGP("-- simulating missing IRQ\n"); - up(&(us->ip_waitq)); - } - - /* if the device has been removed, this worked */ - if (!us->pusb_dev) { - US_DEBUGP("-- device removed already\n"); - return SUCCESS; - } - - /* if we have an urb pending, let's wake the control thread up */ - if (us->current_urb->status == -EINPROGRESS) { - /* cancel the URB -- this will automatically wake the thread */ - usb_unlink_urb(us->current_urb); + if (atomic_read(&us->sm_state) == US_STATE_RUNNING) { + usb_stor_abort_transport(us); /* wait for us to be done */ wait_for_completion(&(us->notify)); @@ -208,47 +194,57 @@ static int device_reset( Scsi_Cmnd *srb ) { struct us_data *us = (struct us_data *)srb->host->hostdata[0]; + int result; US_DEBUGP("device_reset() called\n" ); - return us->transport_reset(us); + + /* if the device was removed, then we're already reset */ + if (atomic_read(&us->sm_state) == US_STATE_DETACHED) + return SUCCESS; + + /* lock the device pointers */ + down(&(us->dev_semaphore)); + us->srb = srb; + atomic_set(&us->sm_state, US_STATE_RESETTING); + result = us->transport_reset(us); + atomic_set(&us->sm_state, US_STATE_IDLE); + + /* unlock the device pointers */ + up(&(us->dev_semaphore)); + return result; } /* This resets the device port, and simulates the device - * disconnect/reconnect for all drivers which have claimed other - * interfaces. */ + * disconnect/reconnect for all drivers which have claimed + * interfaces, including ourself. */ static int bus_reset( Scsi_Cmnd *srb ) { struct us_data *us = (struct us_data *)srb->host->hostdata[0]; int i; int result; + struct usb_device *pusb_dev_save = us->pusb_dev; /* we use the usb_reset_device() function to handle this for us */ US_DEBUGP("bus_reset() called\n"); /* if the device has been removed, this worked */ - if (!us->pusb_dev) { + if (atomic_read(&us->sm_state) == US_STATE_DETACHED) { US_DEBUGP("-- device removed already\n"); return SUCCESS; } - /* release the IRQ, if we have one */ - down(&(us->irq_urb_sem)); - if (us->irq_urb) { - US_DEBUGP("-- releasing irq URB\n"); - result = usb_unlink_urb(us->irq_urb); - US_DEBUGP("-- usb_unlink_urb() returned %d\n", result); - } - up(&(us->irq_urb_sem)); - /* attempt to reset the port */ - if (usb_reset_device(us->pusb_dev) < 0) + result = usb_reset_device(pusb_dev_save); + US_DEBUGP("usb_reset_device returns %d\n", result); + if (result < 0) return FAILED; /* FIXME: This needs to lock out driver probing while it's working * or we can have race conditions */ - for (i = 0; i < us->pusb_dev->actconfig->bNumInterfaces; i++) { + /* Is that still true? I don't see how... AS */ + for (i = 0; i < pusb_dev_save->actconfig->bNumInterfaces; i++) { struct usb_interface *intf = - &us->pusb_dev->actconfig->interface[i]; + &pusb_dev_save->actconfig->interface[i]; const struct usb_device_id *id; /* if this is an unclaimed interface, skip it */ @@ -256,33 +252,17 @@ continue; } - US_DEBUGP("Examinging driver %s...", intf->driver->name); - /* skip interfaces which we've claimed */ - if (intf->driver == &usb_storage_driver) { - US_DEBUGPX("skipping ourselves.\n"); - continue; - } + US_DEBUGP("Examining driver %s...", intf->driver->name); /* simulate a disconnect and reconnect for all interfaces */ US_DEBUGPX("simulating disconnect/reconnect.\n"); down(&intf->driver->serialize); - intf->driver->disconnect(us->pusb_dev, intf->private_data); - id = usb_match_id(us->pusb_dev, intf, intf->driver->id_table); - intf->driver->probe(us->pusb_dev, i, id); + intf->driver->disconnect(pusb_dev_save, intf->private_data); + id = usb_match_id(pusb_dev_save, intf, intf->driver->id_table); + intf->driver->probe(pusb_dev_save, i, id); up(&intf->driver->serialize); } - /* re-allocate the IRQ URB and submit it to restore connectivity - * for CBI devices - */ - if (us->protocol == US_PR_CBI) { - down(&(us->irq_urb_sem)); - us->irq_urb->dev = us->pusb_dev; - result = usb_submit_urb(us->irq_urb, GFP_NOIO); - US_DEBUGP("usb_submit_urb() returns %d\n", result); - up(&(us->irq_urb_sem)); - } - US_DEBUGP("bus_reset() complete\n"); return SUCCESS; } @@ -346,7 +326,8 @@ /* show the GUID of the device */ SPRINTF(" GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid)); - SPRINTF(" Attached: %s\n", us->pusb_dev ? "Yes" : "No"); + SPRINTF(" Attached: %s\n", (atomic_read(&us->sm_state) == + US_STATE_DETACHED) ? "Yes" : "No"); /* * Calculate start of next buffer, and return value. @@ -565,11 +546,11 @@ /* copy one byte */ { - char *src = page_address(sg[sb].page) + sg[sb].offset + si; - char *dst = page_address(sg[db].page) + sg[db].offset + di; + char *src = page_address(sg[sb].page) + sg[sb].offset + si; + char *dst = page_address(sg[db].page) + sg[db].offset + di; - *dst = *src; - } + *dst = *src; + } /* get next destination */ if ( sg[db].length-1 == di ) @@ -607,7 +588,7 @@ break; } - *(char *)(page_address(sg[db].page) + sg[db].offset) = 0; + *(char*)(page_address(sg[db].page) + sg[db].offset) = 0; /* get next destination */ if ( sg[db].length-1 == di ) @@ -758,11 +739,11 @@ /* copy one byte */ { - char *src = page_address(sg[sb].page) + sg[sb].offset + si; - char *dst = page_address(sg[db].page) + sg[db].offset + di; + char *src = page_address(sg[sb].page) + sg[sb].offset + si; + char *dst = page_address(sg[db].page) + sg[db].offset + di; - *dst = *src; - } + *dst = *src; + } /* get next destination */ if ( di == 0 ) @@ -799,11 +780,12 @@ break; } - { - char *dst = page_address(sg[db].page) + sg[db].offset + di; + { + char *dst = page_address(sg[db].page) + sg[db].offset + di; + + *dst = tempBuffer[element-USB_STOR_SCSI_SENSE_HDRSZ]; + } - *dst = tempBuffer[element-USB_STOR_SCSI_SENSE_HDRSZ]; - } /* get next destination */ if ( di == 0 ) @@ -853,19 +835,18 @@ if ( element < USB_STOR_SCSI_SENSE_HDRSZ ) { /* fill in the pointers for both header types */ - the6->array[element] = - page_address(sg[i].page) + - sg[i].offset + j; - the10->array[element] = - page_address(sg[i].page) + - sg[i].offset + j; + the6->array[element] = page_address(sg[i].page) + + sg[i].offset + j; + the10->array[element] = page_address(sg[i].page) + + sg[i].offset + j; + } else if ( element < USB_STOR_SCSI_SENSE_10_HDRSZ ) { /* only the longer headers still cares now */ - the10->array[element] = - page_address(sg[i].page) + - sg[i].offset + j; + the10->array[element] = page_address(sg[i].page) + + sg[i].offset + j; + } /* increase element counter */ element++; diff -Nru a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c --- a/drivers/usb/storage/sddr09.c Sat May 11 22:29:14 2002 +++ b/drivers/usb/storage/sddr09.c Sat May 11 22:29:15 2002 @@ -1,7 +1,10 @@ /* Driver for SanDisk SDDR-09 SmartMedia reader * + * $Id: sddr09.c,v 1.24 2002/04/22 03:39:43 mdharm Exp $ * (c) 2000, 2001 Robert Baruch (autophile@starband.net) * (c) 2002 Andries Brouwer (aeb@cwi.nl) + * 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 @@ -262,8 +265,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; } @@ -317,13 +320,13 @@ result = usb_stor_bulk_msg(us, data, pipe, len, &act_len); - /* if we stall, we need to clear it before we go on */ - if (result == -EPIPE) { - 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); - } + /* if we stall, we need to clear it before we go on */ + if (result == -EPIPE) { + US_DEBUGP("EPIPE: clearing endpoint halt for" + " pipe 0x%x, stalled at %d bytes\n", + pipe, act_len); + usb_stor_clear_halt(us, pipe); + } if (result) { /* -ENOENT -- we canceled this transfer */ @@ -1386,15 +1389,6 @@ // Each block is 64 bytes of control data, so block i is located in // scatterlist block i*64/128k = i*(2^6)*(2^-17) = i*(2^-11) -#if 0 - /* No translation */ - for (i=0; ipba_to_lba[i] = lba; - info->lba_to_pba[lba] = i; - } - printk("sddr09: no translation today\n"); -#else for (i=0; i>11].page) + sg[i>>11].offset + ((i&0x7ff)<<6); @@ -1482,7 +1476,6 @@ info->pba_to_lba[i] = lba; info->lba_to_pba[lba] = i; } -#endif /* * Approximate capacity. This is not entirely correct yet, @@ -1508,7 +1501,7 @@ US_DEBUGP("Found %d LBA's\n", lbact); for (i=0; i + * * 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) { @@ -214,7 +217,7 @@ sg = (struct scatterlist *)data; for (i=0; i sg[i].length ? sg[i].length : len-transferred); if (result!=US_BULK_TRANSFER_GOOD) @@ -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); @@ -734,7 +743,7 @@ if (len - amount >= sg[sg_segment].length-sg_offset) { memcpy(page_address(sg[sg_segment].page) + - sg[sg_segment].offset + sg_offset, + sg[sg_sgement].offset + sg_offset, buffer + amount, sg[sg_segment].length - sg_offset); amount += diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c --- a/drivers/usb/storage/transport.c Sat May 11 22:29:14 2002 +++ b/drivers/usb/storage/transport.c Sat May 11 22:29:14 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.47 2002/04/22 03:39:43 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) @@ -329,37 +330,21 @@ for (i = 0; i < srb->use_sg; i++) total += sg[i].length; len = total; + + /* Double-check to see if the advertised buffer + * length less than the actual buffer length -- + * in other words, we should tend towards the + * conservative side for data transfers. + */ + if (len > srb->request_bufflen) + len = srb->request_bufflen; } else /* Just return the length of the buffer */ 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; } /*********************************************************************** @@ -376,109 +361,142 @@ complete(urb_done_ptr); } -/* This is our function to emulate usb_control_msg() but give us enough - * access to make aborts/resets work +/* This is the common part of the URB message submission code + * This function expects the current_urb_sem to be held upon entry. + */ +static int usb_stor_msg_common(struct us_data *us) +{ + struct completion urb_done; + int status; + + /* set up data structures for the wakeup system */ + init_completion(&urb_done); + + /* fill the common fields in the URB */ + us->current_urb->context = &urb_done; + us->current_urb->actual_length = 0; + us->current_urb->error_count = 0; + us->current_urb->transfer_flags = USB_ASYNC_UNLINK; + + /* submit the URB */ + status = usb_submit_urb(us->current_urb, GFP_NOIO); + if (status) { + /* something went wrong */ + return status; + } + + /* has the current command been aborted? */ + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + + /* avoid a race with usb_stor_abort_transport(): + * if the abort took place before we submitted + * the URB, we must cancel it ourselves */ + if (us->current_urb->status == -EINPROGRESS) + usb_unlink_urb(us->current_urb); + } + + /* wait for the completion of the URB */ + up(&(us->current_urb_sem)); + wait_for_completion(&urb_done); + down(&(us->current_urb_sem)); + + /* return the URB status */ + return us->current_urb->status; +} + +/* This is our function to emulate usb_control_msg() with enough control + * to make aborts/resets/timeouts work */ int usb_stor_control_msg(struct us_data *us, unsigned int pipe, u8 request, u8 requesttype, u16 value, u16 index, void *data, u16 size) { - struct completion urb_done; int status; struct usb_ctrlrequest *dr; - /* allocate the device request structure */ dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO); if (!dr) return -ENOMEM; - /* fill in the structure */ + /* fill in the devrequest structure */ dr->bRequestType = requesttype; dr->bRequest = request; dr->wValue = cpu_to_le16(value); dr->wIndex = cpu_to_le16(index); dr->wLength = cpu_to_le16(size); - /* set up data structures for the wakeup system */ - init_completion(&urb_done); - /* lock the URB */ down(&(us->current_urb_sem)); /* fill the URB */ FILL_CONTROL_URB(us->current_urb, us->pusb_dev, pipe, - (unsigned char*) dr, data, size, - usb_stor_blocking_completion, &urb_done); - us->current_urb->actual_length = 0; - us->current_urb->error_count = 0; - us->current_urb->transfer_flags = USB_ASYNC_UNLINK; + (unsigned char*) &dr, data, size, + usb_stor_blocking_completion, NULL); /* submit the URB */ - status = usb_submit_urb(us->current_urb, GFP_NOIO); - if (status) { - /* something went wrong */ - up(&(us->current_urb_sem)); - kfree(dr); - return status; - } - - /* wait for the completion of the URB */ - up(&(us->current_urb_sem)); - wait_for_completion(&urb_done); - down(&(us->current_urb_sem)); + status = usb_stor_msg_common(us); /* return the actual length of the data transferred if no error*/ - status = us->current_urb->status; if (status >= 0) status = us->current_urb->actual_length; /* release the lock and return status */ up(&(us->current_urb_sem)); - kfree(dr); - return status; + return status; } -/* This is our function to emulate usb_bulk_msg() but give us enough - * access to make aborts/resets work +/* This is our function to emulate usb_bulk_msg() with enough control + * to make aborts/resets/timeouts work */ int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe, unsigned int len, unsigned int *act_len) { - struct completion urb_done; int status; - /* set up data structures for the wakeup system */ - init_completion(&urb_done); - /* lock the URB */ down(&(us->current_urb_sem)); /* fill the URB */ FILL_BULK_URB(us->current_urb, us->pusb_dev, pipe, data, len, - usb_stor_blocking_completion, &urb_done); - us->current_urb->actual_length = 0; - us->current_urb->error_count = 0; - us->current_urb->transfer_flags = USB_ASYNC_UNLINK; + usb_stor_blocking_completion, NULL); /* submit the URB */ - status = usb_submit_urb(us->current_urb, GFP_NOIO); - if (status) { - /* something went wrong */ - up(&(us->current_urb_sem)); - return status; - } - - /* wait for the completion of the URB */ - up(&(us->current_urb_sem)); - wait_for_completion(&urb_done); - down(&(us->current_urb_sem)); + status = usb_stor_msg_common(us); /* return the actual length of the data transferred */ *act_len = us->current_urb->actual_length; /* release the lock and return status */ up(&(us->current_urb_sem)); - return us->current_urb->status; + return 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; } /* @@ -513,7 +531,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 (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + US_DEBUGP("usb_stor_transfer_partial(): transfer aborted\n"); + return US_BULK_TRANSFER_ABORTED; } /* did we send all the data? */ @@ -522,21 +546,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 +567,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 +648,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 +685,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 +693,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 +748,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 +791,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; @@ -789,6 +813,39 @@ srb->sense_buffer[0] = 0x0; } +/* Abort the currently running scsi command or device reset. + */ +void usb_stor_abort_transport(struct us_data *us) +{ + int state = atomic_read(&us->sm_state); + + US_DEBUGP("usb_stor_abort_transport called\n"); + + /* If the current state is wrong or if there's + * no srb, then there's nothing to do */ + if ( !(state == US_STATE_RUNNING || state == US_STATE_RESETTING) + || !us->srb) { + US_DEBUGP("-- invalid current state\n"); + return; + } + atomic_set(&us->sm_state, US_STATE_ABORTING); + + /* If the state machine is blocked waiting for an URB or an IRQ, + * let's wake it up */ + + /* if we have an URB pending, cancel it */ + if (us->current_urb->status == -EINPROGRESS) { + US_DEBUGP("-- cancelling URB\n"); + usb_unlink_urb(us->current_urb); + } + + /* if we are waiting for an IRQ, simulate it */ + else if (test_bit(IP_WANTED, &us->bitflags)) { + US_DEBUGP("-- simulating missing IRQ\n"); + usb_stor_CBI_irq(us->irq_urb); + } +} + /* * Control/Bulk/Interrupt transport */ @@ -804,15 +861,40 @@ US_DEBUGP("-- Interrupt Status (0x%x, 0x%x)\n", us->irqbuf[0], us->irqbuf[1]); - /* reject improper IRQs */ - if (urb->actual_length != 2) { - US_DEBUGP("-- IRQ too short\n"); + /* has the current command been aborted? */ + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + + /* was this a wanted interrupt? */ + if (!test_and_clear_bit(IP_WANTED, &us->bitflags)) { + US_DEBUGP("ERROR: Unwanted interrupt received!\n"); + return; + } + US_DEBUGP("-- command aborted\n"); + + /* wake up the command thread */ + up(&us->ip_waitq); return; } /* is the device removed? */ if (urb->status == -ENOENT) { US_DEBUGP("-- device has been removed\n"); + + /* was this a wanted interrupt? */ + if (!test_and_clear_bit(IP_WANTED, &us->bitflags)) + return; + + /* indicate a transport error -- this is the best we can do */ + us->irqdata[0] = us->irqdata[1] = 0xFF; + + /* wake up the command thread */ + up(&us->ip_waitq); + return; + } + + /* reject improper IRQs */ + if (urb->actual_length != 2) { + US_DEBUGP("-- IRQ too short\n"); return; } @@ -823,21 +905,16 @@ } /* was this a wanted interrupt? */ - if (!atomic_read(us->ip_wanted)) { + if (!test_and_clear_bit(IP_WANTED, &us->bitflags)) { US_DEBUGP("ERROR: Unwanted interrupt received!\n"); return; } - - /* adjust the flag */ - atomic_set(us->ip_wanted, 0); /* copy the valid data */ us->irqdata[0] = us->irqbuf[0]; us->irqdata[1] = us->irqbuf[1]; /* wake up the command thread */ - US_DEBUGP("-- Current value of ip_waitq is: %d\n", - atomic_read(&us->ip_waitq.count)); up(&(us->ip_waitq)); } @@ -845,13 +922,13 @@ { int result; - /* Set up for status notification */ - atomic_set(us->ip_wanted, 1); - /* re-initialize the mutex so that we avoid any races with * early/late IRQs from previous commands */ init_MUTEX_LOCKED(&(us->ip_waitq)); + /* Set up for status notification */ + set_bit(IP_WANTED, &us->bitflags); + /* COMMAND STAGE */ /* let's send the command via the control pipe */ result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0), @@ -863,22 +940,26 @@ US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result); if (result < 0) { /* Reset flag for status notification */ - atomic_set(us->ip_wanted, 0); + clear_bit(IP_WANTED, &us->bitflags); + } + + /* 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,24 +968,28 @@ /* 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) { + clear_bit(IP_WANTED, &us->bitflags); return USB_STOR_TRANSPORT_ABORTED; } + if (result == US_BULK_TRANSFER_FAILED) { + clear_bit(IP_WANTED, &us->bitflags); + return USB_STOR_TRANSPORT_FAILED; + } } /* STATUS STAGE */ /* go to sleep until we get this interrupt */ - US_DEBUGP("Current value of ip_waitq is: %d\n", atomic_read(&us->ip_waitq.count)); down(&(us->ip_waitq)); - /* if we were woken up by an abort instead of the actual interrupt */ - if (atomic_read(us->ip_wanted)) { - US_DEBUGP("Did not get interrupt on CBI\n"); - atomic_set(us->ip_wanted, 0); + /* has the current command been aborted? */ + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + US_DEBUGP("CBI interrupt aborted\n"); return USB_STOR_TRANSPORT_ABORTED; } @@ -922,11 +1007,12 @@ if (srb->cmnd[0] == REQUEST_SENSE || srb->cmnd[0] == INQUIRY) return USB_STOR_TRANSPORT_GOOD; - else - if (((unsigned char*)us->irq_urb->transfer_buffer)[0]) + else { + if (us->irqdata[0]) return USB_STOR_TRANSPORT_FAILED; else return USB_STOR_TRANSPORT_GOOD; + } } /* If not UFI, we interpret the data as a result code @@ -976,10 +1062,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 +1079,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 +1109,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,15 +1128,16 @@ /* 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 */ return 0; } -int usb_stor_Bulk_reset(struct us_data *us); - int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) { struct bulk_cb_wrap bcb; @@ -1051,10 +1146,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 +1179,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 +1195,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 +1223,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 +1241,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; } } @@ -1188,46 +1292,117 @@ * Reset routines ***********************************************************************/ -/* This issues a CB[I] Reset to the device in question +struct us_timeout { + struct us_data *us; + spinlock_t timer_lock; +}; + +/* The timeout event handler */ -int usb_stor_CB_reset(struct us_data *us) +static void usb_stor_timeout_handler(unsigned long to__) { - unsigned char cmd[12]; - int result; + struct us_timeout *to = (struct us_timeout *) to__; + struct us_data *us = to->us; - US_DEBUGP("CB_reset() called\n"); + US_DEBUGP("Timeout occurred\n"); - /* if the device was removed, then we're already reset */ - if (!us->pusb_dev) - return SUCCESS; + /* abort the current request */ + usb_stor_abort_transport(us); - memset(cmd, 0xFF, sizeof(cmd)); - cmd[0] = SEND_DIAGNOSTIC; - cmd[1] = 4; - result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), - US_CBI_ADSC, - USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, us->ifnum, cmd, sizeof(cmd), HZ*5); + /* let the reset routine know we have finished */ + spin_unlock(&to->timer_lock); +} - if (result < 0) { - US_DEBUGP("CB[I] soft reset failed %d\n", result); - return FAILED; - } +/* This is the common part of the device reset code. + * + * It's handy that every transport mechanism uses the control endpoint for + * resets. + * + * Basically, we send a reset with a 20-second timeout, so we don't get + * jammed attempting to do the reset. + */ +void usb_stor_reset_common(struct us_data *us, u8 request, u8 requesttype, + u16 value, u16 index, void *data, u16 size) +{ + int result; + struct us_timeout timeout_data = {us, SPIN_LOCK_UNLOCKED}; + struct timer_list timeout_list; + + /* prepare the timeout handler */ + spin_lock(&timeout_data.timer_lock); + init_timer(&timeout_list); + + /* A 20-second timeout may seem rather long, but a LaCie + * StudioDrive USB2 device takes 16+ seconds to get going + * following a powerup or USB attach event. */ + + timeout_list.expires = jiffies + 20 * HZ; + timeout_list.data = (unsigned long) &timeout_data; + timeout_list.function = usb_stor_timeout_handler; + add_timer(&timeout_list); + + result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0), + request, requesttype, value, index, data, size); + if (result < 0) + goto Done; /* long wait for reset */ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ*6); 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)); + US_DEBUGP("Soft reset: clearing bulk-in endpoint halt\n"); + result = usb_stor_clear_halt(us, + usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); + if (result < 0) + goto Done; + + US_DEBUGP("Soft reset: clearing bulk-out endpoint halt\n"); + result = usb_stor_clear_halt(us, + usb_sndbulkpipe(us->pusb_dev, us->ep_out)); + + Done: + + /* prevent the timer from coming back to haunt us */ + if (!del_timer(&timeout_list)) { + /* the handler has already started; wait for it to finish */ + spin_lock(&timeout_data.timer_lock); + /* change the abort into a timeout */ + if (result == -ENOENT) + result = -ETIMEDOUT; + } - US_DEBUGP("CB_reset done\n"); /* return a result code based on the result of the control message */ - return SUCCESS; + if (result >= 0) + US_DEBUGP("Soft reset done\n"); + else + US_DEBUGP("Soft reset failed: %d\n", result); + + if (result == -ETIMEDOUT) + us->srb->result = DID_TIME_OUT << 16; + else if (result == -ENOENT) + us->srb->result = DID_ABORT << 16; + else if (result < 0) + us->srb->result = DID_ERROR << 16; + else + us->srb->result = GOOD << 1; +} + +/* This issues a CB[I] Reset to the device in question + */ +int usb_stor_CB_reset(struct us_data *us) +{ + unsigned char cmd[12]; + + US_DEBUGP("CB_reset() called\n"); + + memset(cmd, 0xFF, sizeof(cmd)); + cmd[0] = SEND_DIAGNOSTIC; + cmd[1] = 4; + usb_stor_reset_common(us, US_CBI_ADSC, + USB_TYPE_CLASS | USB_RECIP_INTERFACE, + 0, us->ifnum, cmd, sizeof(cmd)); + return (us->srb->result == GOOD << 1 ? SUCCESS : FAILED); } /* This issues a Bulk-only Reset to the device in question, including @@ -1235,34 +1410,10 @@ */ int usb_stor_Bulk_reset(struct us_data *us) { - int result; - US_DEBUGP("Bulk reset requested\n"); - /* if the device was removed, then we're already reset */ - if (!us->pusb_dev) - return SUCCESS; - - result = usb_control_msg(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev,0), - US_BULK_RESET_REQUEST, + usb_stor_reset_common(us, US_BULK_RESET_REQUEST, USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, us->ifnum, NULL, 0, HZ*5); - - if (result < 0) { - US_DEBUGP("Bulk soft reset failed %d\n", result); - return FAILED; - } - - /* long wait for reset */ - set_current_state(TASK_UNINTERRUPTIBLE); - 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)); - US_DEBUGP("Bulk soft reset completed\n"); - return SUCCESS; + 0, us->ifnum, NULL, 0); + return (us->srb->result == GOOD << 1 ? SUCCESS : FAILED); } diff -Nru a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h --- a/drivers/usb/storage/transport.h Sat May 11 22:29:14 2002 +++ b/drivers/usb/storage/transport.h Sat May 11 22:29:14 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.18 2002/04/21 02:57:59 mdharm Exp $ * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -146,11 +146,12 @@ extern unsigned int usb_stor_transfer_length(Scsi_Cmnd*); extern void usb_stor_invoke_transport(Scsi_Cmnd*, struct us_data*); +extern void usb_stor_abort_transport(struct us_data*); extern int usb_stor_transfer_partial(struct us_data*, char*, int); extern int usb_stor_bulk_msg(struct us_data*, void*, int, unsigned int, 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 Sat May 11 22:29:14 2002 +++ b/drivers/usb/storage/unusual_devs.h Sat May 11 22:29:14 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. @@ -110,6 +110,13 @@ "LS-120 Camera", US_SC_UFI, US_PR_CBI, NULL, 0), +/* Reported by Peter Wächtler */ +UNUSUAL_DEV( 0x04ce, 0x0002, 0x0074, 0x0074, + "ScanLogic", + "SL11R-IDE 0049SQFP-1.2 A002", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_FIX_INQUIRY ), + /* Most of the following entries were developed with the help of * Shuttle/SCM directly. */ @@ -198,7 +205,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 +296,36 @@ "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( 0x05e3, 0x0700, 0x0000, 0x9999, + "Unknown", + "GL641USB based CF Card reader", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_FIX_INQUIRY | US_FL_MODE_XLATE), + UNUSUAL_DEV( 0x0644, 0x0000, 0x0100, 0x0100, "TEAC", "Floppy Drive", @@ -305,6 +339,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 +423,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 +440,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 @@ -451,6 +493,12 @@ US_SC_SCSI, US_PR_CB, NULL, US_FL_MODE_XLATE ), +UNUSUAL_DEV( 0x0a16, 0x8888, 0x0100, 0x0100, + "IBM", + "IBM USB Memory Key", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_FIX_INQUIRY ), + #ifdef CONFIG_USB_STORAGE_ISD200 UNUSUAL_DEV( 0x0bf6, 0xa001, 0x0100, 0x0110, "ATI", @@ -459,6 +507,13 @@ 0 ), #endif +/* EasyDisk support. Submitted by Stanislav Karchebny */ +UNUSUAL_DEV( 0x1065, 0x2136, 0x0000, 0x0001, + "Global Channel Solutions", + "EasyDisk EDxxxx", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_MODE_XLATE | US_FL_START_STOP | US_FL_FIX_INQUIRY ), + /* Submitted by Brian Hall * Needed for START_STOP flag */ UNUSUAL_DEV( 0x0c76, 0x0003, 0x0100, 0x0100, @@ -469,6 +524,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 Sat May 11 22:29:14 2002 +++ b/drivers/usb/storage/usb.c Sat May 11 22:29:14 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.75 2002/04/22 03:39:43 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) @@ -315,6 +315,7 @@ * so get rid of all our resources.. */ daemonize(); + reparent_to_init(); /* avoid getting signals */ spin_lock_irq(¤t->sigmask_lock); @@ -409,7 +410,7 @@ down(&(us->dev_semaphore)); /* our device has gone - pretend not ready */ - if (!us->pusb_dev) { + if (atomic_read(&us->sm_state) == US_STATE_DETACHED) { US_DEBUGP("Request is for removed device\n"); /* For REQUEST_SENSE, it's the data. But * for anything else, it should look like @@ -433,7 +434,7 @@ sizeof(usb_stor_sense_notready)); us->srb->result = CHECK_CONDITION << 1; } - } else { /* !us->pusb_dev */ + } else { /* atomic_read(&us->sm_state) == STATE_DETACHED */ /* Handle those devices which need us to fake * their inquiry data */ @@ -449,7 +450,9 @@ } else { /* we've got a command, let's do it! */ US_DEBUG(usb_stor_show_command(us->srb)); + atomic_set(&us->sm_state, US_STATE_RUNNING); us->proto_handler(us->srb, us); + atomic_set(&us->sm_state, US_STATE_IDLE); } } @@ -713,6 +716,7 @@ /* establish the connection to the new device upon reconnect */ ss->ifnum = ifnum; ss->pusb_dev = dev; + atomic_set(&ss->sm_state, US_STATE_IDLE); /* copy over the endpoint data */ if (ep_in) @@ -955,6 +959,7 @@ ss->protocol_name = "Unknown"; kfree(ss->current_urb); kfree(ss); + usb_dec_dev_use(dev); return NULL; break; } @@ -962,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; } @@ -990,6 +997,7 @@ unusual_dev->initFunction(ss); /* start up our control thread */ + atomic_set(&ss->sm_state, US_STATE_IDLE); ss->pid = kernel_thread(usb_stor_control_thread, ss, CLONE_VM); if (ss->pid < 0) { @@ -1006,7 +1014,7 @@ /* now register - our detect function will be called */ ss->htmplt.module = THIS_MODULE; - scsi_register_host(&ss->htmplt); + scsi_register_host(&(ss->htmplt)); /* lock access to the data structures */ down(&us_list_semaphore); @@ -1066,6 +1074,7 @@ /* mark the device as gone */ usb_dec_dev_use(ss->pusb_dev); ss->pusb_dev = NULL; + atomic_set(&ss->sm_state, US_STATE_DETACHED); /* unlock access to the device data structure */ up(&(ss->dev_semaphore)); @@ -1112,7 +1121,7 @@ */ for (next = us_list; next; next = next->next) { US_DEBUGP("-- calling scsi_unregister_host()\n"); - scsi_unregister_host(&next->htmplt); + scsi_unregister_host(&(next->htmplt)); } /* While there are still structures, free them. Note that we are diff -Nru a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h --- a/drivers/usb/storage/usb.h Sat May 11 22:29:14 2002 +++ b/drivers/usb/storage/usb.h Sat May 11 22:29:14 2002 @@ -1,7 +1,7 @@ /* Driver for USB Mass Storage compliant devices * Main Header File * - * $Id: usb.h,v 1.18 2001/07/30 00:27:59 mdharm Exp $ + * $Id: usb.h,v 1.21 2002/04/21 02:57:59 mdharm Exp $ * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -102,6 +102,12 @@ #define US_FL_SCM_MULT_TARG 0x00000020 /* supports multiple targets */ #define US_FL_FIX_INQUIRY 0x00000040 /* INQUIRY response needs fixing */ +#define US_STATE_DETACHED 1 /* State machine states */ +#define US_STATE_IDLE 2 +#define US_STATE_RUNNING 3 +#define US_STATE_RESETTING 4 +#define US_STATE_ABORTING 5 + #define USB_STOR_STRING_LEN 32 typedef int (*trans_cmnd)(Scsi_Cmnd*, struct us_data*); @@ -152,10 +158,12 @@ Scsi_Cmnd *queue_srb; /* the single queue slot */ int action; /* what to do */ int pid; /* control thread */ + atomic_t sm_state; /* interrupt info for CBI devices -- only good if attached */ struct semaphore ip_waitq; /* for CBI interrupts */ - atomic_t ip_wanted[1]; /* is an IRQ expected? */ + unsigned long bitflags; /* single-bit flags: */ +#define IP_WANTED 1 /* is an IRQ expected? */ /* interrupt communications data */ struct semaphore irq_urb_sem; /* to protect irq_urb */ @@ -188,4 +196,5 @@ /* Function to fill an inquiry response. See usb.c for details */ extern void fill_inquiry_response(struct us_data *us, unsigned char *data, unsigned int data_len); + #endif