Commit 58a5ae6a authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

USB storage

sync up with both the -dj and cvs version of the usb-storage code.
parent ea3aba35
/* Driver for Datafab USB Compact Flash reader /* 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: * datafab driver v0.1:
* *
...@@ -6,11 +8,18 @@ ...@@ -6,11 +8,18 @@
* *
* Current development and maintenance by: * Current development and maintenance by:
* (c) 2000 Jimmie Mayfield (mayfield+datafab@sackheads.org) * (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. * which I used as a template for this driver.
*
* Some bugfixes and scatter-gather code by Gregory P. Smith * Some bugfixes and scatter-gather code by Gregory P. Smith
* (greg-usb@electricrain.com) * (greg-usb@electricrain.com)
* *
* Fix for media change by Joerg Schneider (js@joergschneider.com)
*
* Other contributors:
* (c) 2002 Alan Stern <stern@rowland.org>
*
* This program is free software; you can redistribute it and/or modify it * 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 * under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any * Free Software Foundation; either version 2, or (at your option) any
...@@ -102,7 +111,7 @@ static int datafab_raw_bulk(int direction, ...@@ -102,7 +111,7 @@ static int datafab_raw_bulk(int direction,
if (result == -EPIPE) { if (result == -EPIPE) {
US_DEBUGP("datafab_raw_bulk: EPIPE. clearing endpoint halt for" US_DEBUGP("datafab_raw_bulk: EPIPE. clearing endpoint halt for"
" pipe 0x%x, stalled at %d bytes\n", pipe, act_len); " 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) { if (result) {
...@@ -801,6 +810,23 @@ int datafab_transport(Scsi_Cmnd * srb, struct us_data *us) ...@@ -801,6 +810,23 @@ int datafab_transport(Scsi_Cmnd * srb, struct us_data *us)
return USB_STOR_TRANSPORT_GOOD; 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]); US_DEBUGP("datafab_transport: Gah! Unknown command: %d (0x%x)\n", srb->cmnd[0], srb->cmnd[0]);
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
} }
/* Driver for USB Mass Storage compliant devices /* Driver for USB Mass Storage compliant devices
* Debugging Functions Source Code File * 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: * 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 <stern@rowland.org>
* *
* Initial work by: * Initial work by:
* (c) 1999 Michael Gee (michael@linuxspecific.com) * (c) 1999 Michael Gee (michael@linuxspecific.com)
...@@ -302,9 +305,11 @@ void usb_stor_show_sense( ...@@ -302,9 +305,11 @@ void usb_stor_show_sense(
case 0x1902: what="defect list error in primary list"; break; case 0x1902: what="defect list error in primary list"; break;
case 0x1903: what="defect list error in grown list"; break; case 0x1903: what="defect list error in grown list"; break;
case 0x1C00: what="defect list not found"; 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 0x2400: what="invalid field in CDB"; break;
case 0x2703: what="associated write protect"; break; case 0x2703: what="associated write protect"; break;
case 0x2800: what="not ready to ready transition"; 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 0x2903: what="bus device reset function occurred"; break;
case 0x2904: what="device internal reset"; break; case 0x2904: what="device internal reset"; break;
case 0x2B00: what="copy can't execute / host can't disconnect"; break; case 0x2B00: what="copy can't execute / host can't disconnect"; break;
...@@ -327,7 +332,7 @@ void usb_stor_show_sense( ...@@ -327,7 +332,7 @@ void usb_stor_show_sense(
case 0x3502: what="enclosure services unavailable"; break; case 0x3502: what="enclosure services unavailable"; break;
case 0x3503: what="enclosure services transfer failure"; break; case 0x3503: what="enclosure services transfer failure"; break;
case 0x3504: what="enclosure services transfer refused"; 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 0x3B0F: what="end of medium reached"; break;
case 0x3F02: what="changed operating definition"; break; case 0x3F02: what="changed operating definition"; break;
case 0x4100: what="data path failure (should use 40 NN)"; break; case 0x4100: what="data path failure (should use 40 NN)"; break;
......
/* Driver for Freecom USB/IDE adaptor /* 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: * Freecom v0.1:
* *
......
/* Transport & Protocol Driver for In-System Design, Inc. ISD200 ASIC /* 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: * Current development and maintenance:
* (c) 2000 In-System Design, Inc. (support@in-system.com) * (C) 2001-2002 Bjrn Stenberg (bjorn@haxx.se)
*
* Developed with the assistance of:
* (C) 2002 Alan Stern <stern@rowland.org>
*
* Initial work:
* (C) 2000 In-System Design, Inc. (support@in-system.com)
* *
* The ISD200 ASIC does not natively support ATA devices. The chip * The ISD200 ASIC does not natively support ATA devices. The chip
* does implement an interface, the ATA Command Block (ATACB) which provides * does implement an interface, the ATA Command Block (ATACB) which provides
...@@ -27,6 +33,10 @@ ...@@ -27,6 +33,10 @@
* *
* 2001-02-24: Removed lots of duplicate code and simplified the structure. * 2001-02-24: Removed lots of duplicate code and simplified the structure.
* (bjorn@haxx.se) * (bjorn@haxx.se)
* 2002-01-16: Fixed endianness bug so it works on the ppc arch.
* (Luc Saillard <luc@saillard.org>)
* 2002-01-17: All bitfields removed.
* (bjorn@haxx.se)
*/ */
...@@ -45,15 +55,6 @@ ...@@ -45,15 +55,6 @@
#include <linux/hdreg.h> #include <linux/hdreg.h>
#include <linux/ide.h> #include <linux/ide.h>
/*
* 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) */ /* Timeout defines (in Seconds) */
#define ISD200_ENUM_BSY_TIMEOUT 35 #define ISD200_ENUM_BSY_TIMEOUT 35
...@@ -88,6 +89,19 @@ ...@@ -88,6 +89,19 @@
#define ACTION_SELECT_6 0x40 #define ACTION_SELECT_6 0x40
#define ACTION_SELECT_7 0x80 #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 <linux/hdreg.h> */ /* ATA error definitions not in <linux/hdreg.h> */
#define ATA_ERROR_MEDIA_CHANGE 0x20 #define ATA_ERROR_MEDIA_CHANGE 0x20
...@@ -152,20 +166,8 @@ union ata_cdb { ...@@ -152,20 +166,8 @@ union ata_cdb {
struct { struct {
unsigned char SignatureByte0; unsigned char SignatureByte0;
unsigned char SignatureByte1; unsigned char SignatureByte1;
unsigned char ReadRegisterAccessBit : 1; unsigned char ActionSelect;
unsigned char NoDeviceSelectionBit : 1; unsigned char RegisterSelect;
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 TransferBlockSize; unsigned char TransferBlockSize;
unsigned char AlternateStatusByte; unsigned char AlternateStatusByte;
unsigned char ErrorByte; unsigned char ErrorByte;
...@@ -181,20 +183,8 @@ union ata_cdb { ...@@ -181,20 +183,8 @@ union ata_cdb {
struct { struct {
unsigned char SignatureByte0; unsigned char SignatureByte0;
unsigned char SignatureByte1; unsigned char SignatureByte1;
unsigned char ReadRegisterAccessBit : 1; unsigned char ActionSelect;
unsigned char NoDeviceSelectionBit : 1; unsigned char RegisterSelect;
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 TransferBlockSize; unsigned char TransferBlockSize;
unsigned char DeviceControlByte; unsigned char DeviceControlByte;
unsigned char FeaturesByte; unsigned char FeaturesByte;
...@@ -218,27 +208,20 @@ union ata_cdb { ...@@ -218,27 +208,20 @@ union ata_cdb {
* includes fields through ProductRevisionLevel. * includes fields through ProductRevisionLevel.
*/ */
/*
* DeviceType field
*/
#define DIRECT_ACCESS_DEVICE 0x00 /* disks */
#define DEVICE_REMOVABLE 0x80
struct inquiry_data { struct inquiry_data {
unsigned char DeviceType : 5; unsigned char DeviceType;
unsigned char DeviceTypeQualifier : 3; unsigned char DeviceTypeModifier;
unsigned char DeviceTypeModifier : 7;
unsigned char RemovableMedia : 1;
unsigned char Versions; unsigned char Versions;
unsigned char ResponseDataFormat : 4; unsigned char Format;
unsigned char HiSupport : 1;
unsigned char NormACA : 1;
unsigned char ReservedBit : 1;
unsigned char AERC : 1;
unsigned char AdditionalLength; unsigned char AdditionalLength;
unsigned char Reserved[2]; unsigned char Reserved[2];
unsigned char SoftReset : 1; unsigned char Capability;
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 VendorId[8]; unsigned char VendorId[8];
unsigned char ProductId[16]; unsigned char ProductId[16];
unsigned char ProductRevisionLevel[4]; unsigned char ProductRevisionLevel[4];
...@@ -257,25 +240,30 @@ struct inquiry_data { ...@@ -257,25 +240,30 @@ struct inquiry_data {
* ISD200 CONFIG data struct * 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 { struct isd200_config {
unsigned char EventNotification; unsigned char EventNotification;
unsigned char ExternalClock; unsigned char ExternalClock;
unsigned char ATAInitTimeout; unsigned char ATAInitTimeout;
unsigned char ATATiming : 4; unsigned char ATAConfig;
unsigned char ATAPIReset : 1;
unsigned char MasterSlaveSelection : 1;
unsigned char ATAPICommandBlockSize : 2;
unsigned char ATAMajorCommand; unsigned char ATAMajorCommand;
unsigned char ATAMinorCommand; unsigned char ATAMinorCommand;
unsigned char LastLUNIdentifier : 3; unsigned char ATAExtraConfig;
unsigned char DescriptOverride : 1; unsigned char Capability;
unsigned char ATA3StateSuspend : 1; }__attribute__ ((packed));
unsigned char SkipDeviceBoot : 1;
unsigned char ConfigDescriptor2 : 1;
unsigned char InitStatus : 1;
unsigned char SRSTEnable : 1;
unsigned char Reserved0 : 7;
};
/* /*
...@@ -321,15 +309,16 @@ struct read_block_limits { ...@@ -321,15 +309,16 @@ struct read_block_limits {
* Sense Data Format * 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 { struct sense_data {
unsigned char ErrorCode:7; unsigned char ErrorCode;
unsigned char Valid:1; unsigned char SegmentNumber;
unsigned char SegmentNumber; unsigned char Flags;
unsigned char SenseKey:4;
unsigned char Reserved:1;
unsigned char IncorrectLength:1;
unsigned char EndOfMedia:1;
unsigned char FileMark:1;
unsigned char Information[4]; unsigned char Information[4];
unsigned char AdditionalSenseLength; unsigned char AdditionalSenseLength;
unsigned char CommandSpecificInformation[4]; unsigned char CommandSpecificInformation[4];
...@@ -349,7 +338,6 @@ struct sense_data { ...@@ -349,7 +338,6 @@ struct sense_data {
* Helper routines * Helper routines
***********************************************************************/ ***********************************************************************/
/************************************************************************** /**************************************************************************
* isd200_build_sense * isd200_build_sense
* *
...@@ -366,38 +354,33 @@ void isd200_build_sense(struct us_data *us, Scsi_Cmnd *srb) ...@@ -366,38 +354,33 @@ void isd200_build_sense(struct us_data *us, Scsi_Cmnd *srb)
unsigned char error = info->ATARegs[IDE_ERROR_OFFSET]; unsigned char error = info->ATARegs[IDE_ERROR_OFFSET];
if(error & ATA_ERROR_MEDIA_CHANGE) { if(error & ATA_ERROR_MEDIA_CHANGE) {
buf->ErrorCode = 0x70; buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID;
buf->Valid = 1;
buf->AdditionalSenseLength = 0xb; buf->AdditionalSenseLength = 0xb;
buf->SenseKey = UNIT_ATTENTION; buf->Flags = UNIT_ATTENTION;
buf->AdditionalSenseCode = 0; buf->AdditionalSenseCode = 0;
buf->AdditionalSenseCodeQualifier = 0; buf->AdditionalSenseCodeQualifier = 0;
} else if(error & MCR_ERR) { } else if(error & MCR_ERR) {
buf->ErrorCode = 0x70; buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID;
buf->Valid = 1;
buf->AdditionalSenseLength = 0xb; buf->AdditionalSenseLength = 0xb;
buf->SenseKey = UNIT_ATTENTION; buf->Flags = UNIT_ATTENTION;
buf->AdditionalSenseCode = 0; buf->AdditionalSenseCode = 0;
buf->AdditionalSenseCodeQualifier = 0; buf->AdditionalSenseCodeQualifier = 0;
} else if(error & TRK0_ERR) { } else if(error & TRK0_ERR) {
buf->ErrorCode = 0x70; buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID;
buf->Valid = 1;
buf->AdditionalSenseLength = 0xb; buf->AdditionalSenseLength = 0xb;
buf->SenseKey = NOT_READY; buf->Flags = NOT_READY;
buf->AdditionalSenseCode = 0; buf->AdditionalSenseCode = 0;
buf->AdditionalSenseCodeQualifier = 0; buf->AdditionalSenseCodeQualifier = 0;
} else if(error & ECC_ERR) { } else if(error & ECC_ERR) {
buf->ErrorCode = 0x70; buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID;
buf->Valid = 1;
buf->AdditionalSenseLength = 0xb; buf->AdditionalSenseLength = 0xb;
buf->SenseKey = DATA_PROTECT; buf->Flags = DATA_PROTECT;
buf->AdditionalSenseCode = 0; buf->AdditionalSenseCode = 0;
buf->AdditionalSenseCodeQualifier = 0; buf->AdditionalSenseCodeQualifier = 0;
} else { } else {
buf->ErrorCode = 0; buf->ErrorCode = 0;
buf->Valid = 0;
buf->AdditionalSenseLength = 0; buf->AdditionalSenseLength = 0;
buf->SenseKey = 0; buf->Flags = 0;
buf->AdditionalSenseCode = 0; buf->AdditionalSenseCode = 0;
buf->AdditionalSenseCodeQualifier = 0; buf->AdditionalSenseCodeQualifier = 0;
} }
...@@ -442,7 +425,7 @@ static int isd200_transfer_partial( struct us_data *us, ...@@ -442,7 +425,7 @@ static int isd200_transfer_partial( struct us_data *us,
/* if we stall, we need to clear it before we go on */ /* if we stall, we need to clear it before we go on */
if (result == -EPIPE) { if (result == -EPIPE) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); 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? */ /* did we send all the data? */
...@@ -524,7 +507,7 @@ static void isd200_transfer( struct us_data *us, Scsi_Cmnd *srb ) ...@@ -524,7 +507,7 @@ static void isd200_transfer( struct us_data *us, Scsi_Cmnd *srb )
} else } else
result = isd200_transfer_partial(us, result = isd200_transfer_partial(us,
srb->sc_data_direction, srb->sc_data_direction,
page_address(sg[i].page) + sg[i].offset, page_address(sg[i].page) + sg[i].offset,
transfer_amount - total_transferred); transfer_amount - total_transferred);
/* if we get an error, end the loop here */ /* if we get an error, end the loop here */
...@@ -593,7 +576,7 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb, ...@@ -593,7 +576,7 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb,
US_DEBUGP("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\n", 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, le32_to_cpu(bcb.Signature), bcb.Tag,
(bcb.Lun >> 4), (bcb.Lun & 0xFF), (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, result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN,
&partial); &partial);
US_DEBUGP("Bulk command transfer result=%d\n", result); US_DEBUGP("Bulk command transfer result=%d\n", result);
...@@ -603,7 +586,7 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb, ...@@ -603,7 +586,7 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb,
else if (result == -EPIPE) { else if (result == -EPIPE) {
/* if we stall, we need to clear it before we go on */ /* if we stall, we need to clear it before we go on */
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); 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) } else if (result)
return ISD200_TRANSPORT_ERROR; return ISD200_TRANSPORT_ERROR;
...@@ -633,7 +616,7 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb, ...@@ -633,7 +616,7 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb,
/* did the attempt to read the CSW fail? */ /* did the attempt to read the CSW fail? */
if (result == -EPIPE) { if (result == -EPIPE) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); 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 */ /* get the status again */
US_DEBUGP("Attempting to get CSW (2nd try)...\n"); US_DEBUGP("Attempting to get CSW (2nd try)...\n");
...@@ -647,7 +630,7 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb, ...@@ -647,7 +630,7 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb,
/* if it fails again, we need a reset and return an error*/ /* if it fails again, we need a reset and return an error*/
if (result == -EPIPE) { if (result == -EPIPE) {
US_DEBUGP("clearing halt for pipe 0x%x\n", pipe); 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; return ISD200_TRANSPORT_ERROR;
} }
} }
...@@ -716,10 +699,9 @@ static int isd200_action( struct us_data *us, int action, ...@@ -716,10 +699,9 @@ static int isd200_action( struct us_data *us, int action,
case ACTION_READ_STATUS: case ACTION_READ_STATUS:
US_DEBUGP(" isd200_action(READ_STATUS)\n"); US_DEBUGP(" isd200_action(READ_STATUS)\n");
ata.generic.ActionSelect = ACTION_SELECT_0|ACTION_SELECT_2; ata.generic.ActionSelect = ACTION_SELECT_0|ACTION_SELECT_2;
ata.read.SelectStatus = 1; ata.generic.RegisterSelect =
ata.read.SelectError = 1; REG_CYLINDER_LOW | REG_CYLINDER_HIGH |
ata.read.SelectCylinderHigh = 1; REG_STATUS | REG_ERROR;
ata.read.SelectCylinderLow = 1;
srb.sc_data_direction = SCSI_DATA_READ; srb.sc_data_direction = SCSI_DATA_READ;
srb.request_buffer = pointer; srb.request_buffer = pointer;
srb.request_bufflen = value; srb.request_bufflen = value;
...@@ -730,7 +712,7 @@ static int isd200_action( struct us_data *us, int action, ...@@ -730,7 +712,7 @@ static int isd200_action( struct us_data *us, int action,
ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2|
ACTION_SELECT_3|ACTION_SELECT_4| ACTION_SELECT_3|ACTION_SELECT_4|
ACTION_SELECT_5; ACTION_SELECT_5;
ata.write.SelectDeviceHead = 1; ata.generic.RegisterSelect = REG_DEVICE_HEAD;
ata.write.DeviceHeadByte = value; ata.write.DeviceHeadByte = value;
srb.sc_data_direction = SCSI_DATA_NONE; srb.sc_data_direction = SCSI_DATA_NONE;
break; break;
...@@ -739,7 +721,7 @@ static int isd200_action( struct us_data *us, int action, ...@@ -739,7 +721,7 @@ static int isd200_action( struct us_data *us, int action,
US_DEBUGP(" isd200_action(RESET)\n"); US_DEBUGP(" isd200_action(RESET)\n");
ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2|
ACTION_SELECT_3|ACTION_SELECT_4; ACTION_SELECT_3|ACTION_SELECT_4;
ata.write.SelectDeviceControl = 1; ata.generic.RegisterSelect = REG_DEVICE_CONTROL;
ata.write.DeviceControlByte = ATA_DC_RESET_CONTROLLER; ata.write.DeviceControlByte = ATA_DC_RESET_CONTROLLER;
srb.sc_data_direction = SCSI_DATA_NONE; srb.sc_data_direction = SCSI_DATA_NONE;
break; break;
...@@ -748,7 +730,7 @@ static int isd200_action( struct us_data *us, int action, ...@@ -748,7 +730,7 @@ static int isd200_action( struct us_data *us, int action,
US_DEBUGP(" isd200_action(REENABLE)\n"); US_DEBUGP(" isd200_action(REENABLE)\n");
ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2|
ACTION_SELECT_3|ACTION_SELECT_4; ACTION_SELECT_3|ACTION_SELECT_4;
ata.write.SelectDeviceControl = 1; ata.generic.RegisterSelect = REG_DEVICE_CONTROL;
ata.write.DeviceControlByte = ATA_DC_REENABLE_CONTROLLER; ata.write.DeviceControlByte = ATA_DC_REENABLE_CONTROLLER;
srb.sc_data_direction = SCSI_DATA_NONE; srb.sc_data_direction = SCSI_DATA_NONE;
break; break;
...@@ -756,16 +738,15 @@ static int isd200_action( struct us_data *us, int action, ...@@ -756,16 +738,15 @@ static int isd200_action( struct us_data *us, int action,
case ACTION_SOFT_RESET: case ACTION_SOFT_RESET:
US_DEBUGP(" isd200_action(SOFT_RESET)\n"); US_DEBUGP(" isd200_action(SOFT_RESET)\n");
ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_5; 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.DeviceHeadByte = info->DeviceHead;
ata.write.SelectCommand = 1;
ata.write.CommandByte = WIN_SRST; ata.write.CommandByte = WIN_SRST;
srb.sc_data_direction = SCSI_DATA_NONE; srb.sc_data_direction = SCSI_DATA_NONE;
break; break;
case ACTION_IDENTIFY: case ACTION_IDENTIFY:
US_DEBUGP(" isd200_action(IDENTIFY)\n"); US_DEBUGP(" isd200_action(IDENTIFY)\n");
ata.write.SelectCommand = 1; ata.generic.RegisterSelect = REG_COMMAND;
ata.write.CommandByte = WIN_IDENTIFY; ata.write.CommandByte = WIN_IDENTIFY;
srb.sc_data_direction = SCSI_DATA_READ; srb.sc_data_direction = SCSI_DATA_READ;
srb.request_buffer = (void *)&info->drive; srb.request_buffer = (void *)&info->drive;
...@@ -886,6 +867,43 @@ void isd200_invoke_transport( struct us_data *us, ...@@ -886,6 +867,43 @@ void isd200_invoke_transport( struct us_data *us,
srb->result = CHECK_CONDITION; 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 * isd200_write_config
...@@ -901,26 +919,11 @@ int isd200_write_config( struct us_data *us ) ...@@ -901,26 +919,11 @@ int isd200_write_config( struct us_data *us )
int retStatus = ISD200_GOOD; int retStatus = ISD200_GOOD;
int result; int result;
#ifdef CONFIG_USB_STORAGE_DEBUG
US_DEBUGP("Entering isd200_write_config\n"); US_DEBUGP("Entering isd200_write_config\n");
US_DEBUGP(" Writing the following ISD200 Config Data:\n"); US_DEBUGP(" Writing the following ISD200 Config Data:\n");
US_DEBUGP(" Event Notification: 0x%x\n", info->ConfigData.EventNotification); isd200_log_config(info);
US_DEBUGP(" External Clock: 0x%x\n", info->ConfigData.ExternalClock); #endif
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);
/* let's send the command via the control pipe */ /* let's send the command via the control pipe */
result = usb_stor_control_msg( result = usb_stor_control_msg(
...@@ -941,8 +944,8 @@ int isd200_write_config( struct us_data *us ) ...@@ -941,8 +944,8 @@ int isd200_write_config( struct us_data *us )
/* STALL must be cleared when they are detected */ /* STALL must be cleared when they are detected */
if (result == -EPIPE) { if (result == -EPIPE) {
US_DEBUGP("-- Stall on control pipe. Clearing\n"); US_DEBUGP("-- Stall on control pipe. Clearing\n");
result = usb_stor_clear_halt(us->pusb_dev, result = usb_stor_clear_halt(us,
usb_sndctrlpipe(us->pusb_dev, 0)); usb_sndctrlpipe(us->pusb_dev, 0));
US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result); US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result);
} }
...@@ -986,30 +989,17 @@ int isd200_read_config( struct us_data *us ) ...@@ -986,30 +989,17 @@ int isd200_read_config( struct us_data *us )
if (result >= 0) { if (result >= 0) {
US_DEBUGP(" Retrieved the following ISD200 Config Data:\n"); US_DEBUGP(" Retrieved the following ISD200 Config Data:\n");
US_DEBUGP(" Event Notification: 0x%x\n", info->ConfigData.EventNotification); #ifdef CONFIG_USB_STORAGE_DEBUG
US_DEBUGP(" External Clock: 0x%x\n", info->ConfigData.ExternalClock); isd200_log_config(info);
US_DEBUGP(" ATA Init Timeout: 0x%x\n", info->ConfigData.ATAInitTimeout); #endif
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);
} else { } else {
US_DEBUGP(" Request to get ISD200 Config Data failed!\n"); US_DEBUGP(" Request to get ISD200 Config Data failed!\n");
/* STALL must be cleared when they are detected */ /* STALL must be cleared when they are detected */
if (result == -EPIPE) { if (result == -EPIPE) {
US_DEBUGP("-- Stall on control pipe. Clearing\n"); US_DEBUGP("-- Stall on control pipe. Clearing\n");
result = usb_stor_clear_halt(us->pusb_dev, result = usb_stor_clear_halt(us,
usb_sndctrlpipe(us->pusb_dev, 0)); usb_sndctrlpipe(us->pusb_dev, 0));
US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result); US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result);
} }
...@@ -1175,11 +1165,12 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave, ...@@ -1175,11 +1165,12 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave,
break; break;
} }
} else { } else {
US_DEBUGP(" Not ATA, not ATAPI. Weird.\n"); US_DEBUGP(" Not ATA, not ATAPI. Weird.\n");
break;
} }
/* check for timeout on this request */ /* check for timeout on this request */
if (jiffies >= endTime) { if (time_after_eq(jiffies, endTime)) {
if (!detect) if (!detect)
US_DEBUGP(" BSY check timeout, just continue with next operation...\n"); US_DEBUGP(" BSY check timeout, just continue with next operation...\n");
else else
...@@ -1223,9 +1214,10 @@ int isd200_manual_enum(struct us_data *us) ...@@ -1223,9 +1214,10 @@ int isd200_manual_enum(struct us_data *us)
} }
isslave = (info->DeviceHead & ATA_ADDRESS_DEVHEAD_SLAVE) ? 1 : 0; 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); 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); retStatus = isd200_write_config(us);
} }
} }
...@@ -1272,6 +1264,8 @@ int isd200_get_inquiry_data( struct us_data *us ) ...@@ -1272,6 +1264,8 @@ int isd200_get_inquiry_data( struct us_data *us )
} else { } else {
/* ATA Command Identify successful */ /* ATA Command Identify successful */
int i; int i;
__u16 *src, *dest;
ide_fix_driveid(&info->drive);
US_DEBUGP(" Identify Data Structure:\n"); US_DEBUGP(" Identify Data Structure:\n");
US_DEBUGP(" config = 0x%x\n", info->drive.config); US_DEBUGP(" config = 0x%x\n", info->drive.config);
...@@ -1317,31 +1311,25 @@ int isd200_get_inquiry_data( struct us_data *us ) ...@@ -1317,31 +1311,25 @@ int isd200_get_inquiry_data( struct us_data *us )
if (info->drive.command_set_1 & COMMANDSET_MEDIA_STATUS) { if (info->drive.command_set_1 & COMMANDSET_MEDIA_STATUS) {
/* set the removable bit */ /* set the removable bit */
info->InquiryData.RemovableMedia = 1; info->InquiryData.DeviceTypeModifier = DEVICE_REMOVABLE;
info->DeviceFlags |= DF_REMOVABLE_MEDIA; info->DeviceFlags |= DF_REMOVABLE_MEDIA;
} }
/* Fill in vendor identification fields */ /* Fill in vendor identification fields */
for (i = 0; i < 20; i += 2) { src = (__u16*)info->drive.model;
info->InquiryData.VendorId[i] = dest = (__u16*)info->InquiryData.VendorId;
info->drive.model[i + 1]; for (i=0;i<4;i++)
info->InquiryData.VendorId[i+1] = dest[i] = be16_to_cpu(src[i]);
info->drive.model[i];
}
/* Initialize unused portion of product id */ src = (__u16*)(info->drive.model+8);
for (i = 0; i < 4; i++) { dest = (__u16*)info->InquiryData.ProductId;
info->InquiryData.ProductId[12+i] = ' '; for (i=0;i<8;i++)
} dest[i] = be16_to_cpu(src[i]);
/* Move firmware revision from IDENTIFY data to */ src = (__u16*)info->drive.fw_rev;
/* product revision in INQUIRY data */ dest = (__u16*)info->InquiryData.ProductRevisionLevel;
for (i = 0; i < 4; i += 2) { for (i=0;i<2;i++)
info->InquiryData.ProductRevisionLevel[i] = dest[i] = be16_to_cpu(src[i]);
info->drive.fw_rev[i+1];
info->InquiryData.ProductRevisionLevel[i+1] =
info->drive.fw_rev[i];
}
/* determine if it supports Media Status Notification */ /* determine if it supports Media Status Notification */
if (info->drive.command_set_2 & COMMANDSET_MEDIA_STATUS) { if (info->drive.command_set_2 & COMMANDSET_MEDIA_STATUS) {
...@@ -1483,7 +1471,7 @@ int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us, ...@@ -1483,7 +1471,7 @@ int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us,
ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
ataCdb->generic.TransferBlockSize = 1; ataCdb->generic.TransferBlockSize = 1;
ataCdb->write.SelectCommand = 1; ataCdb->generic.RegisterSelect = REG_COMMAND;
ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
srb->request_bufflen = 0; srb->request_bufflen = 0;
} else { } else {
...@@ -1504,7 +1492,7 @@ int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us, ...@@ -1504,7 +1492,7 @@ int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us,
ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
ataCdb->generic.TransferBlockSize = 1; ataCdb->generic.TransferBlockSize = 1;
ataCdb->write.SelectCommand = 1; ataCdb->generic.RegisterSelect = REG_COMMAND;
ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
srb->request_bufflen = 0; srb->request_bufflen = 0;
} else { } else {
...@@ -1561,17 +1549,15 @@ int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us, ...@@ -1561,17 +1549,15 @@ int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us,
ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
ataCdb->generic.TransferBlockSize = 1; 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.SectorCountByte = (unsigned char)blockCount;
ataCdb->write.SelectSectorNumber = 1;
ataCdb->write.SectorNumberByte = sectnum; ataCdb->write.SectorNumberByte = sectnum;
ataCdb->write.SelectCylinderHigh = 1;
ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8); ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8);
ataCdb->write.SelectCylinderLow = 1;
ataCdb->write.CylinderLowByte = (unsigned char)cylinder; ataCdb->write.CylinderLowByte = (unsigned char)cylinder;
ataCdb->write.SelectDeviceHead = 1;
ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD); ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD);
ataCdb->write.SelectCommand = 1;
ataCdb->write.CommandByte = WIN_READ; ataCdb->write.CommandByte = WIN_READ;
break; break;
...@@ -1594,17 +1580,15 @@ int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us, ...@@ -1594,17 +1580,15 @@ int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us,
ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
ataCdb->generic.TransferBlockSize = 1; 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.SectorCountByte = (unsigned char)blockCount;
ataCdb->write.SelectSectorNumber = 1;
ataCdb->write.SectorNumberByte = sectnum; ataCdb->write.SectorNumberByte = sectnum;
ataCdb->write.SelectCylinderHigh = 1;
ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8); ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8);
ataCdb->write.SelectCylinderLow = 1;
ataCdb->write.CylinderLowByte = (unsigned char)cylinder; ataCdb->write.CylinderLowByte = (unsigned char)cylinder;
ataCdb->write.SelectDeviceHead = 1;
ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD); ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD);
ataCdb->write.SelectCommand = 1;
ataCdb->write.CommandByte = WIN_WRITE; ataCdb->write.CommandByte = WIN_WRITE;
break; break;
...@@ -1617,7 +1601,7 @@ int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us, ...@@ -1617,7 +1601,7 @@ int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us,
ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
ataCdb->generic.TransferBlockSize = 1; ataCdb->generic.TransferBlockSize = 1;
ataCdb->write.SelectCommand = 1; ataCdb->generic.RegisterSelect = REG_COMMAND;
ataCdb->write.CommandByte = (srb->cmnd[4] & 0x1) ? ataCdb->write.CommandByte = (srb->cmnd[4] & 0x1) ?
WIN_DOORLOCK : WIN_DOORUNLOCK; WIN_DOORLOCK : WIN_DOORUNLOCK;
srb->request_bufflen = 0; srb->request_bufflen = 0;
...@@ -1640,14 +1624,14 @@ int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us, ...@@ -1640,14 +1624,14 @@ int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us,
ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
ataCdb->generic.TransferBlockSize = 0; ataCdb->generic.TransferBlockSize = 0;
ataCdb->write.SelectCommand = 1; ataCdb->generic.RegisterSelect = REG_COMMAND;
ataCdb->write.CommandByte = ATA_COMMAND_MEDIA_EJECT; ataCdb->write.CommandByte = ATA_COMMAND_MEDIA_EJECT;
} else if ((srb->cmnd[4] & 0x3) == 0x1) { } else if ((srb->cmnd[4] & 0x3) == 0x1) {
US_DEBUGP(" Get Media Status\n"); US_DEBUGP(" Get Media Status\n");
ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
ataCdb->generic.TransferBlockSize = 1; ataCdb->generic.TransferBlockSize = 1;
ataCdb->write.SelectCommand = 1; ataCdb->generic.RegisterSelect = REG_COMMAND;
ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
srb->request_bufflen = 0; srb->request_bufflen = 0;
} else { } else {
......
/* Driver for Lexar "Jumpshot" Compact Flash reader /* 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: * jumpshot driver v0.1:
* *
...@@ -6,11 +8,19 @@ ...@@ -6,11 +8,19 @@
* *
* Current development and maintenance by: * Current development and maintenance by:
* (c) 2000 Jimmie Mayfield (mayfield+usb@sackheads.org) * (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. * which I used as a template for this driver.
*
* Some bugfixes and scatter-gather code by Gregory P. Smith * Some bugfixes and scatter-gather code by Gregory P. Smith
* (greg-usb@electricrain.com) * (greg-usb@electricrain.com)
* *
* Fix for media change by Joerg Schneider (js@joergschneider.com)
*
* Developed with the assistance of:
*
* (C) 2002 Alan Stern <stern@rowland.org>
*
* This program is free software; you can redistribute it and/or modify it * 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 * under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any * Free Software Foundation; either version 2, or (at your option) any
...@@ -128,8 +138,8 @@ static int jumpshot_send_control(struct us_data *us, ...@@ -128,8 +138,8 @@ static int jumpshot_send_control(struct us_data *us,
/* a stall is a fatal condition from the device */ /* a stall is a fatal condition from the device */
if (result == -EPIPE) { if (result == -EPIPE) {
US_DEBUGP("jumpshot_send_control: -- Stall on control pipe. Clearing\n"); US_DEBUGP("jumpshot_send_control: -- Stall on control pipe. Clearing\n");
result = usb_clear_halt(us->pusb_dev, pipe); result = usb_stor_clear_halt(us, pipe);
US_DEBUGP("jumpshot_send_control: -- usb_clear_halt() returns %d\n", result); US_DEBUGP("jumpshot_send_control: -- usb_stor_clear_halt() returns %d\n", result);
return USB_STOR_TRANSPORT_FAILED; return USB_STOR_TRANSPORT_FAILED;
} }
...@@ -161,7 +171,7 @@ static int jumpshot_raw_bulk(int direction, ...@@ -161,7 +171,7 @@ static int jumpshot_raw_bulk(int direction,
if (result == -EPIPE) { if (result == -EPIPE) {
US_DEBUGP("jumpshot_raw_bulk: EPIPE. clearing endpoint halt for" US_DEBUGP("jumpshot_raw_bulk: EPIPE. clearing endpoint halt for"
" pipe 0x%x, stalled at %d bytes\n", pipe, act_len); " 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) { if (result) {
...@@ -798,6 +808,23 @@ int jumpshot_transport(Scsi_Cmnd * srb, struct us_data *us) ...@@ -798,6 +808,23 @@ int jumpshot_transport(Scsi_Cmnd * srb, struct us_data *us)
// //
return USB_STOR_TRANSPORT_GOOD; 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]); US_DEBUGP("jumpshot_transport: Gah! Unknown command: %d (0x%x)\n", srb->cmnd[0], srb->cmnd[0]);
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
......
/* Driver for USB Mass Storage compliant devices /* 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: * 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: * Developed with the assistance of:
* (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
* (c) 2002 Alan Stern (stern@rowland.org)
* *
* Initial work by: * Initial work by:
* (c) 1999 Michael Gee (michael@linuxspecific.com) * (c) 1999 Michael Gee (michael@linuxspecific.com)
...@@ -67,10 +68,16 @@ void fix_inquiry_data(Scsi_Cmnd *srb) ...@@ -67,10 +68,16 @@ void fix_inquiry_data(Scsi_Cmnd *srb)
US_DEBUGP("Fixing INQUIRY data to show SCSI rev 2\n"); US_DEBUGP("Fixing INQUIRY data to show SCSI rev 2\n");
/* find the location of the data */ /* find the location of the data */
if (srb->use_sg) if (srb->use_sg) {
BUG(); /* 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;
data_ptr = (unsigned char *) srb->request_buffer; 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 */ /* Change the SCSI revision number */
data_ptr[2] = (data_ptr[2] & ~7) | 2; data_ptr[2] = (data_ptr[2] & ~7) | 2;
...@@ -94,9 +101,11 @@ void usb_stor_qic157_command(Scsi_Cmnd *srb, struct us_data *us) ...@@ -94,9 +101,11 @@ void usb_stor_qic157_command(Scsi_Cmnd *srb, struct us_data *us)
/* send the command to the transport layer */ /* send the command to the transport layer */
usb_stor_invoke_transport(srb, us); usb_stor_invoke_transport(srb, us);
if (srb->result == GOOD << 1) {
/* fix the INQUIRY data if necessary */ /* fix the INQUIRY data if necessary */
fix_inquiry_data(srb); fix_inquiry_data(srb);
}
} }
void usb_stor_ATAPI_command(Scsi_Cmnd *srb, struct us_data *us) void usb_stor_ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
...@@ -165,13 +174,15 @@ void usb_stor_ATAPI_command(Scsi_Cmnd *srb, struct us_data *us) ...@@ -165,13 +174,15 @@ void usb_stor_ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
/* send the command to the transport layer */ /* send the command to the transport layer */
usb_stor_invoke_transport(srb, us); usb_stor_invoke_transport(srb, us);
if (srb->result == GOOD << 1) {
/* Fix the MODE_SENSE data if we translated the command */ /* Fix the MODE_SENSE data if we translated the command */
if ((old_cmnd == MODE_SENSE) && (status_byte(srb->result) == GOOD)) if (old_cmnd == MODE_SENSE)
usb_stor_scsiSense10to6(srb); usb_stor_scsiSense10to6(srb);
/* fix the INQUIRY data if necessary */ /* fix the INQUIRY data if necessary */
fix_inquiry_data(srb); fix_inquiry_data(srb);
}
} }
...@@ -260,13 +271,15 @@ void usb_stor_ufi_command(Scsi_Cmnd *srb, struct us_data *us) ...@@ -260,13 +271,15 @@ void usb_stor_ufi_command(Scsi_Cmnd *srb, struct us_data *us)
/* send the command to the transport layer */ /* send the command to the transport layer */
usb_stor_invoke_transport(srb, us); usb_stor_invoke_transport(srb, us);
if (srb->result == GOOD << 1) {
/* Fix the MODE_SENSE data if we translated the command */ /* Fix the MODE_SENSE data if we translated the command */
if ((old_cmnd == MODE_SENSE) && (status_byte(srb->result) == GOOD)) if (old_cmnd == MODE_SENSE)
usb_stor_scsiSense10to6(srb); usb_stor_scsiSense10to6(srb);
/* Fix the data for an INQUIRY, if necessary */ /* Fix the data for an INQUIRY, if necessary */
fix_inquiry_data(srb); fix_inquiry_data(srb);
}
} }
void usb_stor_transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us) void usb_stor_transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us)
...@@ -327,13 +340,14 @@ void usb_stor_transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us) ...@@ -327,13 +340,14 @@ void usb_stor_transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us)
/* send the command to the transport layer */ /* send the command to the transport layer */
usb_stor_invoke_transport(srb, us); usb_stor_invoke_transport(srb, us);
if (srb->result == GOOD << 1) {
/* Fix the MODE_SENSE data if we translated the command */ /* Fix the MODE_SENSE data if we translated the command */
if ((us->flags & US_FL_MODE_XLATE) && (old_cmnd == MODE_SENSE) if ((us->flags & US_FL_MODE_XLATE) && (old_cmnd == MODE_SENSE))
&& (status_byte(srb->result) == GOOD)) usb_stor_scsiSense10to6(srb);
usb_stor_scsiSense10to6(srb);
/* fix the INQUIRY data if necessary */ /* fix the INQUIRY data if necessary */
fix_inquiry_data(srb); fix_inquiry_data(srb);
}
} }
/* Driver for USB Mass Storage compliant devices /* Driver for USB Mass Storage compliant devices
* SCSI layer glue code * 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: * Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
...@@ -177,22 +177,8 @@ static int command_abort( Scsi_Cmnd *srb ) ...@@ -177,22 +177,8 @@ static int command_abort( Scsi_Cmnd *srb )
US_DEBUGP("command_abort() called\n"); US_DEBUGP("command_abort() called\n");
/* if we're stuck waiting for an IRQ, simulate it */ if (atomic_read(&us->sm_state) == US_STATE_RUNNING) {
if (atomic_read(us->ip_wanted)) { usb_stor_abort_transport(us);
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);
/* wait for us to be done */ /* wait for us to be done */
wait_for_completion(&(us->notify)); wait_for_completion(&(us->notify));
...@@ -208,47 +194,57 @@ static int command_abort( Scsi_Cmnd *srb ) ...@@ -208,47 +194,57 @@ static int command_abort( Scsi_Cmnd *srb )
static int device_reset( Scsi_Cmnd *srb ) static int device_reset( Scsi_Cmnd *srb )
{ {
struct us_data *us = (struct us_data *)srb->host->hostdata[0]; struct us_data *us = (struct us_data *)srb->host->hostdata[0];
int result;
US_DEBUGP("device_reset() called\n" ); 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 /* This resets the device port, and simulates the device
* disconnect/reconnect for all drivers which have claimed other * disconnect/reconnect for all drivers which have claimed
* interfaces. */ * interfaces, including ourself. */
static int bus_reset( Scsi_Cmnd *srb ) static int bus_reset( Scsi_Cmnd *srb )
{ {
struct us_data *us = (struct us_data *)srb->host->hostdata[0]; struct us_data *us = (struct us_data *)srb->host->hostdata[0];
int i; int i;
int result; int result;
struct usb_device *pusb_dev_save = us->pusb_dev;
/* we use the usb_reset_device() function to handle this for us */ /* we use the usb_reset_device() function to handle this for us */
US_DEBUGP("bus_reset() called\n"); US_DEBUGP("bus_reset() called\n");
/* if the device has been removed, this worked */ /* 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"); US_DEBUGP("-- device removed already\n");
return SUCCESS; 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 */ /* 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; return FAILED;
/* FIXME: This needs to lock out driver probing while it's working /* FIXME: This needs to lock out driver probing while it's working
* or we can have race conditions */ * 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 = struct usb_interface *intf =
&us->pusb_dev->actconfig->interface[i]; &pusb_dev_save->actconfig->interface[i];
const struct usb_device_id *id; const struct usb_device_id *id;
/* if this is an unclaimed interface, skip it */ /* if this is an unclaimed interface, skip it */
...@@ -256,33 +252,17 @@ static int bus_reset( Scsi_Cmnd *srb ) ...@@ -256,33 +252,17 @@ static int bus_reset( Scsi_Cmnd *srb )
continue; continue;
} }
US_DEBUGP("Examinging driver %s...", intf->driver->name); US_DEBUGP("Examining driver %s...", intf->driver->name);
/* skip interfaces which we've claimed */
if (intf->driver == &usb_storage_driver) {
US_DEBUGPX("skipping ourselves.\n");
continue;
}
/* simulate a disconnect and reconnect for all interfaces */ /* simulate a disconnect and reconnect for all interfaces */
US_DEBUGPX("simulating disconnect/reconnect.\n"); US_DEBUGPX("simulating disconnect/reconnect.\n");
down(&intf->driver->serialize); down(&intf->driver->serialize);
intf->driver->disconnect(us->pusb_dev, intf->private_data); intf->driver->disconnect(pusb_dev_save, intf->private_data);
id = usb_match_id(us->pusb_dev, intf, intf->driver->id_table); id = usb_match_id(pusb_dev_save, intf, intf->driver->id_table);
intf->driver->probe(us->pusb_dev, i, id); intf->driver->probe(pusb_dev_save, i, id);
up(&intf->driver->serialize); 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"); US_DEBUGP("bus_reset() complete\n");
return SUCCESS; return SUCCESS;
} }
...@@ -346,7 +326,8 @@ static int proc_info (char *buffer, char **start, off_t offset, int length, ...@@ -346,7 +326,8 @@ static int proc_info (char *buffer, char **start, off_t offset, int length,
/* show the GUID of the device */ /* show the GUID of the device */
SPRINTF(" GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid)); 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. * Calculate start of next buffer, and return value.
...@@ -565,11 +546,11 @@ int usb_stor_scsiSense10to6( Scsi_Cmnd* the10 ) ...@@ -565,11 +546,11 @@ int usb_stor_scsiSense10to6( Scsi_Cmnd* the10 )
/* copy one byte */ /* copy one byte */
{ {
char *src = page_address(sg[sb].page) + sg[sb].offset + si; char *src = page_address(sg[sb].page) + sg[sb].offset + si;
char *dst = page_address(sg[db].page) + sg[db].offset + di; char *dst = page_address(sg[db].page) + sg[db].offset + di;
*dst = *src; *dst = *src;
} }
/* get next destination */ /* get next destination */
if ( sg[db].length-1 == di ) if ( sg[db].length-1 == di )
...@@ -607,7 +588,7 @@ int usb_stor_scsiSense10to6( Scsi_Cmnd* the10 ) ...@@ -607,7 +588,7 @@ int usb_stor_scsiSense10to6( Scsi_Cmnd* the10 )
break; break;
} }
*(char *)(page_address(sg[db].page) + sg[db].offset) = 0; *(char*)(page_address(sg[db].page) + sg[db].offset) = 0;
/* get next destination */ /* get next destination */
if ( sg[db].length-1 == di ) if ( sg[db].length-1 == di )
...@@ -758,11 +739,11 @@ int usb_stor_scsiSense6to10( Scsi_Cmnd* the6 ) ...@@ -758,11 +739,11 @@ int usb_stor_scsiSense6to10( Scsi_Cmnd* the6 )
/* copy one byte */ /* copy one byte */
{ {
char *src = page_address(sg[sb].page) + sg[sb].offset + si; char *src = page_address(sg[sb].page) + sg[sb].offset + si;
char *dst = page_address(sg[db].page) + sg[db].offset + di; char *dst = page_address(sg[db].page) + sg[db].offset + di;
*dst = *src; *dst = *src;
} }
/* get next destination */ /* get next destination */
if ( di == 0 ) if ( di == 0 )
...@@ -799,11 +780,12 @@ int usb_stor_scsiSense6to10( Scsi_Cmnd* the6 ) ...@@ -799,11 +780,12 @@ int usb_stor_scsiSense6to10( Scsi_Cmnd* the6 )
break; 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 */ /* get next destination */
if ( di == 0 ) if ( di == 0 )
...@@ -853,19 +835,18 @@ void usb_stor_scsiSenseParseBuffer( Scsi_Cmnd* srb, Usb_Stor_Scsi_Sense_Hdr_u* t ...@@ -853,19 +835,18 @@ void usb_stor_scsiSenseParseBuffer( Scsi_Cmnd* srb, Usb_Stor_Scsi_Sense_Hdr_u* t
if ( element < USB_STOR_SCSI_SENSE_HDRSZ ) if ( element < USB_STOR_SCSI_SENSE_HDRSZ )
{ {
/* fill in the pointers for both header types */ /* fill in the pointers for both header types */
the6->array[element] = the6->array[element] = page_address(sg[i].page) +
page_address(sg[i].page) + sg[i].offset + j;
sg[i].offset + j; the10->array[element] = page_address(sg[i].page) +
the10->array[element] = sg[i].offset + j;
page_address(sg[i].page) +
sg[i].offset + j;
} }
else if ( element < USB_STOR_SCSI_SENSE_10_HDRSZ ) else if ( element < USB_STOR_SCSI_SENSE_10_HDRSZ )
{ {
/* only the longer headers still cares now */ /* only the longer headers still cares now */
the10->array[element] = the10->array[element] = page_address(sg[i].page) +
page_address(sg[i].page) + sg[i].offset + j;
sg[i].offset + j;
} }
/* increase element counter */ /* increase element counter */
element++; element++;
......
/* Driver for SanDisk SDDR-09 SmartMedia reader /* 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) 2000, 2001 Robert Baruch (autophile@starband.net)
* (c) 2002 Andries Brouwer (aeb@cwi.nl) * (c) 2002 Andries Brouwer (aeb@cwi.nl)
* Developed with the assistance of:
* (c) 2002 Alan Stern <stern@rowland.org>
* *
* The SanDisk SDDR-09 SmartMedia reader uses the Shuttle EUSB-01 chip. * 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 * This chip is a programmable USB controller. In the SDDR-09, it has
...@@ -262,8 +265,8 @@ sddr09_send_control(struct us_data *us, ...@@ -262,8 +265,8 @@ sddr09_send_control(struct us_data *us,
/* a stall is a fatal condition from the device */ /* a stall is a fatal condition from the device */
if (result == -EPIPE) { if (result == -EPIPE) {
US_DEBUGP("-- Stall on control pipe. Clearing\n"); US_DEBUGP("-- Stall on control pipe. Clearing\n");
result = usb_clear_halt(us->pusb_dev, pipe); result = usb_stor_clear_halt(us, pipe);
US_DEBUGP("-- usb_clear_halt() returns %d\n", result); US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result);
return USB_STOR_TRANSPORT_FAILED; return USB_STOR_TRANSPORT_FAILED;
} }
...@@ -317,13 +320,13 @@ sddr09_raw_bulk(struct us_data *us, int direction, ...@@ -317,13 +320,13 @@ sddr09_raw_bulk(struct us_data *us, int direction,
result = usb_stor_bulk_msg(us, data, pipe, len, &act_len); result = usb_stor_bulk_msg(us, data, pipe, len, &act_len);
/* if we stall, we need to clear it before we go on */ /* if we stall, we need to clear it before we go on */
if (result == -EPIPE) { if (result == -EPIPE) {
US_DEBUGP("EPIPE: clearing endpoint halt for" US_DEBUGP("EPIPE: clearing endpoint halt for"
" pipe 0x%x, stalled at %d bytes\n", " pipe 0x%x, stalled at %d bytes\n",
pipe, act_len); pipe, act_len);
usb_clear_halt(us->pusb_dev, pipe); usb_stor_clear_halt(us, pipe);
} }
if (result) { if (result) {
/* -ENOENT -- we canceled this transfer */ /* -ENOENT -- we canceled this transfer */
...@@ -1386,15 +1389,6 @@ sddr09_read_map(struct us_data *us) { ...@@ -1386,15 +1389,6 @@ sddr09_read_map(struct us_data *us) {
// Each block is 64 bytes of control data, so block i is located in // 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) // scatterlist block i*64/128k = i*(2^6)*(2^-17) = i*(2^-11)
#if 0
/* No translation */
for (i=0; i<numblocks; i++) {
lba = i;
info->pba_to_lba[i] = lba;
info->lba_to_pba[lba] = i;
}
printk("sddr09: no translation today\n");
#else
for (i=0; i<numblocks; i++) { for (i=0; i<numblocks; i++) {
ptr = page_address(sg[i>>11].page) + ptr = page_address(sg[i>>11].page) +
sg[i>>11].offset + ((i&0x7ff)<<6); sg[i>>11].offset + ((i&0x7ff)<<6);
...@@ -1482,7 +1476,6 @@ sddr09_read_map(struct us_data *us) { ...@@ -1482,7 +1476,6 @@ sddr09_read_map(struct us_data *us) {
info->pba_to_lba[i] = lba; info->pba_to_lba[i] = lba;
info->lba_to_pba[lba] = i; info->lba_to_pba[lba] = i;
} }
#endif
/* /*
* Approximate capacity. This is not entirely correct yet, * Approximate capacity. This is not entirely correct yet,
...@@ -1508,7 +1501,7 @@ sddr09_read_map(struct us_data *us) { ...@@ -1508,7 +1501,7 @@ sddr09_read_map(struct us_data *us) {
US_DEBUGP("Found %d LBA's\n", lbact); US_DEBUGP("Found %d LBA's\n", lbact);
for (i=0; i<alloc_blocks; i++) for (i=0; i<alloc_blocks; i++)
kfree(page_address(sg[i].page)+sg[i].offset); kfree(page_address(sg[i].page) + sg[i].offset);
kfree(sg); kfree(sg);
return 0; return 0;
} }
......
/* Driver for SCM Microsystems USB-ATAPI cable /* 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.17 2002/04/22 03:39:43 mdharm Exp $
* *
* Current development and maintenance by: * Current development and maintenance by:
* (c) 2000, 2001 Robert Baruch (autophile@starband.net) * (c) 2000, 2001 Robert Baruch (autophile@starband.net)
* *
* Developed with the assistance of:
* (c) 2002 Alan Stern <stern@rowland.org>
*
* Many originally ATAPI devices were slightly modified to meet the USB * 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, * market by using some kind of translation from ATAPI to USB on the host,
* and the peripheral would translate from USB back to ATAPI. * and the peripheral would translate from USB back to ATAPI.
...@@ -107,8 +110,8 @@ static int usbat_send_control(struct us_data *us, ...@@ -107,8 +110,8 @@ static int usbat_send_control(struct us_data *us,
/* a stall is a fatal condition from the device */ /* a stall is a fatal condition from the device */
if (result == -EPIPE) { if (result == -EPIPE) {
US_DEBUGP("-- Stall on control pipe. Clearing\n"); US_DEBUGP("-- Stall on control pipe. Clearing\n");
result = usb_clear_halt(us->pusb_dev, pipe); result = usb_stor_clear_halt(us, pipe);
US_DEBUGP("-- usb_clear_halt() returns %d\n", result); US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result);
return USB_STOR_TRANSPORT_FAILED; return USB_STOR_TRANSPORT_FAILED;
} }
...@@ -140,7 +143,7 @@ static int usbat_raw_bulk(struct us_data *us, ...@@ -140,7 +143,7 @@ static int usbat_raw_bulk(struct us_data *us,
US_DEBUGP("EPIPE: clearing endpoint halt for" US_DEBUGP("EPIPE: clearing endpoint halt for"
" pipe 0x%x, stalled at %d bytes\n", " pipe 0x%x, stalled at %d bytes\n",
pipe, act_len); pipe, act_len);
usb_clear_halt(us->pusb_dev, pipe); usb_stor_clear_halt(us, pipe);
} }
if (result) { if (result) {
...@@ -214,7 +217,7 @@ static int usbat_bulk_transport(struct us_data *us, ...@@ -214,7 +217,7 @@ static int usbat_bulk_transport(struct us_data *us,
sg = (struct scatterlist *)data; sg = (struct scatterlist *)data;
for (i=0; i<use_sg && transferred<len; i++) { for (i=0; i<use_sg && transferred<len; i++) {
result = usbat_raw_bulk(us, direction, result = usbat_raw_bulk(us, direction,
page_address(sg[i].page) + sg[i].offset, page_address(sg[i].page) + sg[i].offset,
len-transferred > sg[i].length ? len-transferred > sg[i].length ?
sg[i].length : len-transferred); sg[i].length : len-transferred);
if (result!=US_BULK_TRANSFER_GOOD) if (result!=US_BULK_TRANSFER_GOOD)
...@@ -515,7 +518,7 @@ int usbat_rw_block_test(struct us_data *us, ...@@ -515,7 +518,7 @@ int usbat_rw_block_test(struct us_data *us,
*/ */
if (direction==SCSI_DATA_READ && i==0) if (direction==SCSI_DATA_READ && i==0)
usb_clear_halt(us->pusb_dev, usb_stor_clear_halt(us,
usb_sndbulkpipe(us->pusb_dev, usb_sndbulkpipe(us->pusb_dev,
us->ep_out)); us->ep_out));
/* /*
...@@ -675,9 +678,15 @@ int usbat_handle_read10(struct us_data *us, ...@@ -675,9 +678,15 @@ int usbat_handle_read10(struct us_data *us,
len = short_pack(data[7+9], data[7+8]); len = short_pack(data[7+9], data[7+8]);
len <<= 16; len <<= 16;
len |= data[7+7]; len |= data[7+7];
US_DEBUGP("handle_read10: GPCMD_READ_CD: len %d\n", len);
srb->transfersize = srb->request_bufflen/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; len = (65535/srb->transfersize) * srb->transfersize;
US_DEBUGP("Max read is %d bytes\n", len); US_DEBUGP("Max read is %d bytes\n", len);
...@@ -734,7 +743,7 @@ int usbat_handle_read10(struct us_data *us, ...@@ -734,7 +743,7 @@ int usbat_handle_read10(struct us_data *us,
if (len - amount >= if (len - amount >=
sg[sg_segment].length-sg_offset) { sg[sg_segment].length-sg_offset) {
memcpy(page_address(sg[sg_segment].page) + memcpy(page_address(sg[sg_segment].page) +
sg[sg_segment].offset + sg_offset, sg[sg_sgement].offset + sg_offset,
buffer + amount, buffer + amount,
sg[sg_segment].length - sg_offset); sg[sg_segment].length - sg_offset);
amount += amount +=
......
/* Driver for USB Mass Storage compliant devices /* 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: * 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: * Developed with the assistance of:
* (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
* (c) 2000 Stephen J. Gowdy (SGowdy@lbl.gov) * (c) 2000 Stephen J. Gowdy (SGowdy@lbl.gov)
* (c) 2002 Alan Stern <stern@rowland.org>
* *
* Initial work by: * Initial work by:
* (c) 1999 Michael Gee (michael@linuxspecific.com) * (c) 1999 Michael Gee (michael@linuxspecific.com)
...@@ -329,37 +330,21 @@ unsigned int usb_stor_transfer_length(Scsi_Cmnd *srb) ...@@ -329,37 +330,21 @@ unsigned int usb_stor_transfer_length(Scsi_Cmnd *srb)
for (i = 0; i < srb->use_sg; i++) for (i = 0; i < srb->use_sg; i++)
total += sg[i].length; total += sg[i].length;
len = total; 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 else
/* Just return the length of the buffer */ /* Just return the length of the buffer */
len = srb->request_bufflen; len = srb->request_bufflen;
} }
return len; 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;
} }
/*********************************************************************** /***********************************************************************
...@@ -376,109 +361,142 @@ static void usb_stor_blocking_completion(struct urb *urb) ...@@ -376,109 +361,142 @@ static void usb_stor_blocking_completion(struct urb *urb)
complete(urb_done_ptr); complete(urb_done_ptr);
} }
/* This is our function to emulate usb_control_msg() but give us enough /* This is the common part of the URB message submission code
* access to make aborts/resets work * 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, int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
u8 request, u8 requesttype, u16 value, u16 index, u8 request, u8 requesttype, u16 value, u16 index,
void *data, u16 size) void *data, u16 size)
{ {
struct completion urb_done;
int status; int status;
struct usb_ctrlrequest *dr; struct usb_ctrlrequest *dr;
/* allocate the device request structure */
dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO); dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
if (!dr) if (!dr)
return -ENOMEM; return -ENOMEM;
/* fill in the structure */ /* fill in the devrequest structure */
dr->bRequestType = requesttype; dr->bRequestType = requesttype;
dr->bRequest = request; dr->bRequest = request;
dr->wValue = cpu_to_le16(value); dr->wValue = cpu_to_le16(value);
dr->wIndex = cpu_to_le16(index); dr->wIndex = cpu_to_le16(index);
dr->wLength = cpu_to_le16(size); dr->wLength = cpu_to_le16(size);
/* set up data structures for the wakeup system */
init_completion(&urb_done);
/* lock the URB */ /* lock the URB */
down(&(us->current_urb_sem)); down(&(us->current_urb_sem));
/* fill the URB */ /* fill the URB */
FILL_CONTROL_URB(us->current_urb, us->pusb_dev, pipe, FILL_CONTROL_URB(us->current_urb, us->pusb_dev, pipe,
(unsigned char*) dr, data, size, (unsigned char*) &dr, data, size,
usb_stor_blocking_completion, &urb_done); usb_stor_blocking_completion, NULL);
us->current_urb->actual_length = 0;
us->current_urb->error_count = 0;
us->current_urb->transfer_flags = USB_ASYNC_UNLINK;
/* submit the URB */ /* submit the URB */
status = usb_submit_urb(us->current_urb, GFP_NOIO); status = usb_stor_msg_common(us);
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));
/* return the actual length of the data transferred if no error*/ /* return the actual length of the data transferred if no error*/
status = us->current_urb->status;
if (status >= 0) if (status >= 0)
status = us->current_urb->actual_length; status = us->current_urb->actual_length;
/* release the lock and return status */ /* release the lock and return status */
up(&(us->current_urb_sem)); up(&(us->current_urb_sem));
kfree(dr); return status;
return status;
} }
/* This is our function to emulate usb_bulk_msg() but give us enough /* This is our function to emulate usb_bulk_msg() with enough control
* access to make aborts/resets work * to make aborts/resets/timeouts work
*/ */
int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe, int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe,
unsigned int len, unsigned int *act_len) unsigned int len, unsigned int *act_len)
{ {
struct completion urb_done;
int status; int status;
/* set up data structures for the wakeup system */
init_completion(&urb_done);
/* lock the URB */ /* lock the URB */
down(&(us->current_urb_sem)); down(&(us->current_urb_sem));
/* fill the URB */ /* fill the URB */
FILL_BULK_URB(us->current_urb, us->pusb_dev, pipe, data, len, FILL_BULK_URB(us->current_urb, us->pusb_dev, pipe, data, len,
usb_stor_blocking_completion, &urb_done); usb_stor_blocking_completion, NULL);
us->current_urb->actual_length = 0;
us->current_urb->error_count = 0;
us->current_urb->transfer_flags = USB_ASYNC_UNLINK;
/* submit the URB */ /* submit the URB */
status = usb_submit_urb(us->current_urb, GFP_NOIO); status = usb_stor_msg_common(us);
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));
/* return the actual length of the data transferred */ /* return the actual length of the data transferred */
*act_len = us->current_urb->actual_length; *act_len = us->current_urb->actual_length;
/* release the lock and return status */ /* release the lock and return status */
up(&(us->current_urb_sem)); 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 @@ int usb_stor_transfer_partial(struct us_data *us, char *buf, int length) ...@@ -513,7 +531,13 @@ int usb_stor_transfer_partial(struct us_data *us, char *buf, int length)
/* if we stall, we need to clear it before we go on */ /* if we stall, we need to clear it before we go on */
if (result == -EPIPE) { if (result == -EPIPE) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); 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? */ /* did we send all the data? */
...@@ -522,21 +546,14 @@ int usb_stor_transfer_partial(struct us_data *us, char *buf, int length) ...@@ -522,21 +546,14 @@ int usb_stor_transfer_partial(struct us_data *us, char *buf, int length)
return US_BULK_TRANSFER_GOOD; return US_BULK_TRANSFER_GOOD;
} }
/* uh oh... we have an error code, so something went wrong. */ /* NAK - that means we've retried a few times already */
if (result) { if (result == -ETIMEDOUT) {
/* NAK - that means we've retried a few times already */ US_DEBUGP("usb_stor_transfer_partial(): device NAKed\n");
if (result == -ETIMEDOUT) { return US_BULK_TRANSFER_FAILED;
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;
}
/* the catch-all case */ /* the catch-all error case */
if (result) {
US_DEBUGP("usb_stor_transfer_partial(): unknown error\n"); US_DEBUGP("usb_stor_transfer_partial(): unknown error\n");
return US_BULK_TRANSFER_FAILED; return US_BULK_TRANSFER_FAILED;
} }
...@@ -550,7 +567,7 @@ int usb_stor_transfer_partial(struct us_data *us, char *buf, int length) ...@@ -550,7 +567,7 @@ int usb_stor_transfer_partial(struct us_data *us, char *buf, int length)
* Transfer an entire SCSI command's worth of data payload over the bulk * Transfer an entire SCSI command's worth of data payload over the bulk
* pipe. * 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, * 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. * and acts appropriately. For now, it also re-interprets the error codes.
*/ */
...@@ -631,6 +648,14 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -631,6 +648,14 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
return; 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 /* Determine if we need to auto-sense
* *
* I normally don't use a flag like this, but it's almost impossible * I normally don't use a flag like this, but it's almost impossible
...@@ -660,7 +685,7 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -660,7 +685,7 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
} }
/* /*
* 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 * automatically. Note that we differentiate between a command
* "failure" and an "error" in the transport mechanism. * "failure" and an "error" in the transport mechanism.
*/ */
...@@ -668,13 +693,6 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -668,13 +693,6 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
US_DEBUGP("-- transport indicates command failure\n"); US_DEBUGP("-- transport indicates command failure\n");
need_auto_sense = 1; 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 * Also, if we have a short transfer on a command that can't have
...@@ -730,6 +748,19 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -730,6 +748,19 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
/* issue the auto-sense command */ /* issue the auto-sense command */
temp_result = us->transport(us->srb, us); 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) { if (temp_result != USB_STOR_TRANSPORT_GOOD) {
US_DEBUGP("-- auto-sense failure\n"); US_DEBUGP("-- auto-sense failure\n");
...@@ -760,13 +791,6 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -760,13 +791,6 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
/* set the result so the higher layers expect this data */ /* set the result so the higher layers expect this data */
srb->result = CHECK_CONDITION << 1; 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 things are really okay, then let's show that */
if ((srb->sense_buffer[2] & 0xf) == 0x0) if ((srb->sense_buffer[2] & 0xf) == 0x0)
srb->result = GOOD << 1; srb->result = GOOD << 1;
...@@ -789,6 +813,39 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -789,6 +813,39 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
srb->sense_buffer[0] = 0x0; 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 * Control/Bulk/Interrupt transport
*/ */
...@@ -804,15 +861,40 @@ void usb_stor_CBI_irq(struct urb *urb) ...@@ -804,15 +861,40 @@ void usb_stor_CBI_irq(struct urb *urb)
US_DEBUGP("-- Interrupt Status (0x%x, 0x%x)\n", US_DEBUGP("-- Interrupt Status (0x%x, 0x%x)\n",
us->irqbuf[0], us->irqbuf[1]); us->irqbuf[0], us->irqbuf[1]);
/* reject improper IRQs */ /* has the current command been aborted? */
if (urb->actual_length != 2) { if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("-- IRQ too short\n");
/* 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; return;
} }
/* is the device removed? */ /* is the device removed? */
if (urb->status == -ENOENT) { if (urb->status == -ENOENT) {
US_DEBUGP("-- device has been removed\n"); 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; return;
} }
...@@ -823,21 +905,16 @@ void usb_stor_CBI_irq(struct urb *urb) ...@@ -823,21 +905,16 @@ void usb_stor_CBI_irq(struct urb *urb)
} }
/* was this a wanted interrupt? */ /* 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"); US_DEBUGP("ERROR: Unwanted interrupt received!\n");
return; return;
} }
/* adjust the flag */
atomic_set(us->ip_wanted, 0);
/* copy the valid data */ /* copy the valid data */
us->irqdata[0] = us->irqbuf[0]; us->irqdata[0] = us->irqbuf[0];
us->irqdata[1] = us->irqbuf[1]; us->irqdata[1] = us->irqbuf[1];
/* wake up the command thread */ /* 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)); up(&(us->ip_waitq));
} }
...@@ -845,13 +922,13 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -845,13 +922,13 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
{ {
int result; int result;
/* Set up for status notification */
atomic_set(us->ip_wanted, 1);
/* re-initialize the mutex so that we avoid any races with /* re-initialize the mutex so that we avoid any races with
* early/late IRQs from previous commands */ * early/late IRQs from previous commands */
init_MUTEX_LOCKED(&(us->ip_waitq)); init_MUTEX_LOCKED(&(us->ip_waitq));
/* Set up for status notification */
set_bit(IP_WANTED, &us->bitflags);
/* COMMAND STAGE */ /* COMMAND STAGE */
/* let's send the command via the control pipe */ /* let's send the command via the control pipe */
result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0), result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0),
...@@ -863,22 +940,26 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -863,22 +940,26 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result); US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result);
if (result < 0) { if (result < 0) {
/* Reset flag for status notification */ /* 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 the command was aborted, indicate that */
if (result == -ENOENT) if (result == -ENOENT)
return USB_STOR_TRANSPORT_ABORTED; return USB_STOR_TRANSPORT_ABORTED;
return USB_STOR_TRANSPORT_FAILED;
}
/* STALL must be cleared when they are detected */ if (result < 0) {
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;
}
/* Uh oh... serious problem here */ /* Uh oh... serious problem here */
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
} }
...@@ -887,24 +968,28 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -887,24 +968,28 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
/* transfer the data payload for this command, if one exists*/ /* transfer the data payload for this command, if one exists*/
if (usb_stor_transfer_length(srb)) { if (usb_stor_transfer_length(srb)) {
usb_stor_transfer(srb, us); 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 */ /* report any errors */
if (srb->result == USB_STOR_TRANSPORT_ABORTED) { if (result == US_BULK_TRANSFER_ABORTED) {
clear_bit(IP_WANTED, &us->bitflags);
return USB_STOR_TRANSPORT_ABORTED; return USB_STOR_TRANSPORT_ABORTED;
} }
if (result == US_BULK_TRANSFER_FAILED) {
clear_bit(IP_WANTED, &us->bitflags);
return USB_STOR_TRANSPORT_FAILED;
}
} }
/* STATUS STAGE */ /* STATUS STAGE */
/* go to sleep until we get this interrupt */ /* 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)); down(&(us->ip_waitq));
/* if we were woken up by an abort instead of the actual interrupt */ /* has the current command been aborted? */
if (atomic_read(us->ip_wanted)) { if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("Did not get interrupt on CBI\n"); US_DEBUGP("CBI interrupt aborted\n");
atomic_set(us->ip_wanted, 0);
return USB_STOR_TRANSPORT_ABORTED; return USB_STOR_TRANSPORT_ABORTED;
} }
...@@ -922,11 +1007,12 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -922,11 +1007,12 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
if (srb->cmnd[0] == REQUEST_SENSE || if (srb->cmnd[0] == REQUEST_SENSE ||
srb->cmnd[0] == INQUIRY) srb->cmnd[0] == INQUIRY)
return USB_STOR_TRANSPORT_GOOD; return USB_STOR_TRANSPORT_GOOD;
else else {
if (((unsigned char*)us->irq_urb->transfer_buffer)[0]) if (us->irqdata[0])
return USB_STOR_TRANSPORT_FAILED; return USB_STOR_TRANSPORT_FAILED;
else else
return USB_STOR_TRANSPORT_GOOD; return USB_STOR_TRANSPORT_GOOD;
}
} }
/* If not UFI, we interpret the data as a result code /* If not UFI, we interpret the data as a result code
...@@ -976,10 +1062,12 @@ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -976,10 +1062,12 @@ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us)
/* a stall is a fatal condition from the device */ /* a stall is a fatal condition from the device */
if (result == -EPIPE) { if (result == -EPIPE) {
US_DEBUGP("-- Stall on control pipe. Clearing\n"); US_DEBUGP("-- Stall on control pipe. Clearing\n");
result = usb_stor_clear_halt(us->pusb_dev, result = usb_stor_clear_halt(us,
usb_sndctrlpipe(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0));
0));
US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result); /* if the command was aborted, indicate that */
if (result == -ENOENT)
return USB_STOR_TRANSPORT_ABORTED;
return USB_STOR_TRANSPORT_FAILED; return USB_STOR_TRANSPORT_FAILED;
} }
...@@ -991,11 +1079,16 @@ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -991,11 +1079,16 @@ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us)
/* transfer the data payload for this command, if one exists*/ /* transfer the data payload for this command, if one exists*/
if (usb_stor_transfer_length(srb)) { if (usb_stor_transfer_length(srb)) {
usb_stor_transfer(srb, us); 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 */ /* report any errors */
if (srb->result == USB_STOR_TRANSPORT_ABORTED) if (result == US_BULK_TRANSFER_ABORTED) {
return USB_STOR_TRANSPORT_ABORTED; return USB_STOR_TRANSPORT_ABORTED;
}
if (result == US_BULK_TRANSFER_FAILED) {
return USB_STOR_TRANSPORT_FAILED;
}
} }
/* STATUS STAGE */ /* STATUS STAGE */
...@@ -1016,7 +1109,8 @@ int usb_stor_Bulk_max_lun(struct us_data *us) ...@@ -1016,7 +1109,8 @@ int usb_stor_Bulk_max_lun(struct us_data *us)
int result; int result;
int pipe; 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); pipe = usb_rcvctrlpipe(us->pusb_dev, 0);
result = usb_control_msg(us->pusb_dev, pipe, result = usb_control_msg(us->pusb_dev, pipe,
US_BULK_GET_MAX_LUN, US_BULK_GET_MAX_LUN,
...@@ -1034,15 +1128,16 @@ int usb_stor_Bulk_max_lun(struct us_data *us) ...@@ -1034,15 +1128,16 @@ int usb_stor_Bulk_max_lun(struct us_data *us)
/* if we get a STALL, clear the stall */ /* if we get a STALL, clear the stall */
if (result == -EPIPE) { if (result == -EPIPE) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); 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 the default -- no LUNs */
return 0; return 0;
} }
int usb_stor_Bulk_reset(struct us_data *us);
int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
{ {
struct bulk_cb_wrap bcb; struct bulk_cb_wrap bcb;
...@@ -1051,10 +1146,6 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -1051,10 +1146,6 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
int pipe; int pipe;
int partial; int partial;
/* if the device was removed, then we're already reset */
if (!us->pusb_dev)
return SUCCESS;
/* set up the command wrapper */ /* set up the command wrapper */
bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN); bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb.DataTransferLength = cpu_to_le32(usb_stor_transfer_length(srb)); bcb.DataTransferLength = cpu_to_le32(usb_stor_transfer_length(srb));
...@@ -1088,7 +1179,12 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -1088,7 +1179,12 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
/* if we stall, we need to clear it before we go on */ /* if we stall, we need to clear it before we go on */
if (result == -EPIPE) { if (result == -EPIPE) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); 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) { } else if (result) {
/* unknown error -- we've got a problem */ /* unknown error -- we've got a problem */
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
...@@ -1099,11 +1195,11 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -1099,11 +1195,11 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
/* send/receive data payload, if there is any */ /* send/receive data payload, if there is any */
if (bcb.DataTransferLength) { if (bcb.DataTransferLength) {
usb_stor_transfer(srb, us); usb_stor_transfer(srb, us);
US_DEBUGP("Bulk data transfer result 0x%x\n", result = srb->result;
srb->result); US_DEBUGP("Bulk data transfer result 0x%x\n", result);
/* if it was aborted, we need to indicate that */ /* 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; return USB_STOR_TRANSPORT_ABORTED;
} }
} }
...@@ -1127,8 +1223,12 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -1127,8 +1223,12 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
/* did the attempt to read the CSW fail? */ /* did the attempt to read the CSW fail? */
if (result == -EPIPE) { if (result == -EPIPE) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); 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 */ /* get the status again */
US_DEBUGP("Attempting to get CSW (2nd try)...\n"); US_DEBUGP("Attempting to get CSW (2nd try)...\n");
result = usb_stor_bulk_msg(us, &bcs, pipe, result = usb_stor_bulk_msg(us, &bcs, pipe,
...@@ -1141,7 +1241,11 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -1141,7 +1241,11 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
/* if it fails again, we need a reset and return an error*/ /* if it fails again, we need a reset and return an error*/
if (result == -EPIPE) { if (result == -EPIPE) {
US_DEBUGP("clearing halt for pipe 0x%x\n", pipe); 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; return USB_STOR_TRANSPORT_ERROR;
} }
} }
...@@ -1188,46 +1292,117 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -1188,46 +1292,117 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
* Reset routines * 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__)
{
struct us_timeout *to = (struct us_timeout *) to__;
struct us_data *us = to->us;
US_DEBUGP("Timeout occurred\n");
/* abort the current request */
usb_stor_abort_transport(us);
/* let the reset routine know we have finished */
spin_unlock(&to->timer_lock);
}
/* 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)
{ {
unsigned char cmd[12];
int result; int result;
struct us_timeout timeout_data = {us, SPIN_LOCK_UNLOCKED};
struct timer_list timeout_list;
US_DEBUGP("CB_reset() called\n"); /* prepare the timeout handler */
spin_lock(&timeout_data.timer_lock);
init_timer(&timeout_list);
/* if the device was removed, then we're already reset */ /* A 20-second timeout may seem rather long, but a LaCie
if (!us->pusb_dev) * StudioDrive USB2 device takes 16+ seconds to get going
return SUCCESS; * following a powerup or USB attach event. */
memset(cmd, 0xFF, sizeof(cmd)); timeout_list.expires = jiffies + 20 * HZ;
cmd[0] = SEND_DIAGNOSTIC; timeout_list.data = (unsigned long) &timeout_data;
cmd[1] = 4; timeout_list.function = usb_stor_timeout_handler;
result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), add_timer(&timeout_list);
US_CBI_ADSC,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, us->ifnum, cmd, sizeof(cmd), HZ*5);
if (result < 0) { result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0),
US_DEBUGP("CB[I] soft reset failed %d\n", result); request, requesttype, value, index, data, size);
return FAILED; if (result < 0)
} goto Done;
/* long wait for reset */ /* long wait for reset */
set_current_state(TASK_UNINTERRUPTIBLE); set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ*6); schedule_timeout(HZ*6);
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
US_DEBUGP("CB_reset: clearing endpoint halt\n"); US_DEBUGP("Soft reset: clearing bulk-in endpoint halt\n");
usb_stor_clear_halt(us->pusb_dev, result = usb_stor_clear_halt(us,
usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
usb_stor_clear_halt(us->pusb_dev, if (result < 0)
usb_rcvbulkpipe(us->pusb_dev, us->ep_out)); 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 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 /* This issues a Bulk-only Reset to the device in question, including
...@@ -1235,34 +1410,10 @@ int usb_stor_CB_reset(struct us_data *us) ...@@ -1235,34 +1410,10 @@ int usb_stor_CB_reset(struct us_data *us)
*/ */
int usb_stor_Bulk_reset(struct us_data *us) int usb_stor_Bulk_reset(struct us_data *us)
{ {
int result;
US_DEBUGP("Bulk reset requested\n"); US_DEBUGP("Bulk reset requested\n");
/* if the device was removed, then we're already reset */ usb_stor_reset_common(us, US_BULK_RESET_REQUEST,
if (!us->pusb_dev)
return SUCCESS;
result = usb_control_msg(us->pusb_dev,
usb_sndctrlpipe(us->pusb_dev,0),
US_BULK_RESET_REQUEST,
USB_TYPE_CLASS | USB_RECIP_INTERFACE, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, us->ifnum, NULL, 0, HZ*5); 0, us->ifnum, NULL, 0);
return (us->srb->result == GOOD << 1 ? SUCCESS : FAILED);
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;
} }
/* Driver for USB Mass Storage compliant devices /* Driver for USB Mass Storage compliant devices
* Transport Functions Header File * 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: * Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
...@@ -146,11 +146,12 @@ extern int usb_stor_Bulk_reset(struct us_data*); ...@@ -146,11 +146,12 @@ extern int usb_stor_Bulk_reset(struct us_data*);
extern unsigned int usb_stor_transfer_length(Scsi_Cmnd*); extern unsigned int usb_stor_transfer_length(Scsi_Cmnd*);
extern void usb_stor_invoke_transport(Scsi_Cmnd*, struct us_data*); 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_transfer_partial(struct us_data*, char*, int);
extern int usb_stor_bulk_msg(struct us_data*, void*, int, unsigned int, extern int usb_stor_bulk_msg(struct us_data*, void*, int, unsigned int,
unsigned int*); unsigned int*);
extern int usb_stor_control_msg(struct us_data*, unsigned int, u8, u8, extern int usb_stor_control_msg(struct us_data*, unsigned int, u8, u8,
u16, u16, void*, u16); 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 void usb_stor_transfer(Scsi_Cmnd*, struct us_data*);
extern int usb_stor_clear_halt(struct usb_device*, int );
#endif #endif
/* Driver for USB Mass Storage compliant devices /* Driver for USB Mass Storage compliant devices
* Ununsual Devices File * 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: * 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: * Initial work by:
* (c) 2000 Adam J. Richter (adam@yggdrasil.com), Yggdrasil Computing, Inc. * (c) 2000 Adam J. Richter (adam@yggdrasil.com), Yggdrasil Computing, Inc.
...@@ -110,6 +110,13 @@ UNUSUAL_DEV( 0x04da, 0x0901, 0x0100, 0x0200, ...@@ -110,6 +110,13 @@ UNUSUAL_DEV( 0x04da, 0x0901, 0x0100, 0x0200,
"LS-120 Camera", "LS-120 Camera",
US_SC_UFI, US_PR_CBI, NULL, 0), US_SC_UFI, US_PR_CBI, NULL, 0),
/* Reported by Peter Wchtler <pwaechtler@loewe-komp.de> */
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 /* Most of the following entries were developed with the help of
* Shuttle/SCM directly. * Shuttle/SCM directly.
*/ */
...@@ -198,7 +205,7 @@ UNUSUAL_DEV( 0x0525, 0xa140, 0x0100, 0x0100, ...@@ -198,7 +205,7 @@ UNUSUAL_DEV( 0x0525, 0xa140, 0x0100, 0x0100,
/* This entry is needed because the device reports Sub=ff */ /* This entry is needed because the device reports Sub=ff */
UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0422, UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0422,
"Sony", "Sony",
"DSC-S30/S70/S75/505V/F505", "DSC-S30/S70/S75/505V/F505/F707",
US_SC_SCSI, US_PR_CB, NULL, US_SC_SCSI, US_PR_CB, NULL,
US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE ), US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE ),
...@@ -289,9 +296,36 @@ UNUSUAL_DEV( 0x05dc, 0x0001, 0x0000, 0x0001, ...@@ -289,9 +296,36 @@ UNUSUAL_DEV( 0x05dc, 0x0001, 0x0000, 0x0001,
"Lexar", "Lexar",
"Jumpshot USB CF Reader", "Jumpshot USB CF Reader",
US_SC_SCSI, US_PR_JUMPSHOT, NULL, US_SC_SCSI, US_PR_JUMPSHOT, NULL,
US_FL_MODE_XLATE | US_FL_START_STOP ), US_FL_MODE_XLATE ),
#endif #endif
/* Reported by Carlos Villegas <cav@uniscope.co.jp>
* 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 <peter.marks@turner.com>
* 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, UNUSUAL_DEV( 0x0644, 0x0000, 0x0100, 0x0100,
"TEAC", "TEAC",
"Floppy Drive", "Floppy Drive",
...@@ -305,6 +339,14 @@ UNUSUAL_DEV( 0x066b, 0x0105, 0x0100, 0x0100, ...@@ -305,6 +339,14 @@ UNUSUAL_DEV( 0x066b, 0x0105, 0x0100, 0x0100,
US_FL_SINGLE_LUN | US_FL_START_STOP ), US_FL_SINGLE_LUN | US_FL_START_STOP ),
#endif #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 /* Submitted by f.brugmans@hccnet.nl
* Needed for START_STOP flag */ * Needed for START_STOP flag */
UNUSUAL_DEV( 0x0686, 0x4007, 0x0001, 0x0001, UNUSUAL_DEV( 0x0686, 0x4007, 0x0001, 0x0001,
...@@ -381,7 +423,7 @@ UNUSUAL_DEV( 0x07c4, 0xa000, 0x0000, 0x0015, ...@@ -381,7 +423,7 @@ UNUSUAL_DEV( 0x07c4, 0xa000, 0x0000, 0x0015,
"Datafab", "Datafab",
"MDCFE-B USB CF Reader", "MDCFE-B USB CF Reader",
US_SC_SCSI, US_PR_DATAFAB, NULL, 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 * The following Datafab-based devices may or may not work
...@@ -398,38 +440,38 @@ UNUSUAL_DEV( 0x07c4, 0xa001, 0x0000, 0xffff, ...@@ -398,38 +440,38 @@ UNUSUAL_DEV( 0x07c4, 0xa001, 0x0000, 0xffff,
"SIIG/Datafab", "SIIG/Datafab",
"SIIG/Datafab Memory Stick+CF Reader/Writer", "SIIG/Datafab Memory Stick+CF Reader/Writer",
US_SC_SCSI, US_PR_DATAFAB, NULL, 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, UNUSUAL_DEV( 0x07c4, 0xa003, 0x0000, 0xffff,
"Datafab/Unknown", "Datafab/Unknown",
"Datafab-based Reader", "Datafab-based Reader",
US_SC_SCSI, US_PR_DATAFAB, NULL, 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, UNUSUAL_DEV( 0x07c4, 0xa004, 0x0000, 0xffff,
"Datafab/Unknown", "Datafab/Unknown",
"Datafab-based Reader", "Datafab-based Reader",
US_SC_SCSI, US_PR_DATAFAB, NULL, 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, UNUSUAL_DEV( 0x07c4, 0xa005, 0x0000, 0xffff,
"PNY/Datafab", "PNY/Datafab",
"PNY/Datafab CF+SM Reader", "PNY/Datafab CF+SM Reader",
US_SC_SCSI, US_PR_DATAFAB, NULL, 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, UNUSUAL_DEV( 0x07c4, 0xa006, 0x0000, 0xffff,
"Simple Tech/Datafab", "Simple Tech/Datafab",
"Simple Tech/Datafab CF+SM Reader", "Simple Tech/Datafab CF+SM Reader",
US_SC_SCSI, US_PR_DATAFAB, NULL, US_SC_SCSI, US_PR_DATAFAB, NULL,
US_FL_MODE_XLATE | US_FL_START_STOP ), US_FL_MODE_XLATE ),
/* Submitted by Olaf Hering <olh@suse.de> */ /* Submitted by Olaf Hering <olh@suse.de> */
UNUSUAL_DEV( 0x07c4, 0xa109, 0x0000, 0xffff, UNUSUAL_DEV( 0x07c4, 0xa109, 0x0000, 0xffff,
"Datafab Systems, Inc.", "Datafab Systems, Inc.",
"USB to CF + SM Combo (LC1)", "USB to CF + SM Combo (LC1)",
US_SC_SCSI, US_PR_DATAFAB, NULL, US_SC_SCSI, US_PR_DATAFAB, NULL,
US_FL_MODE_XLATE | US_FL_START_STOP ), US_FL_MODE_XLATE ),
#endif #endif
/* Casio QV 2x00/3x00/4000/8000 digital still cameras are not conformant /* Casio QV 2x00/3x00/4000/8000 digital still cameras are not conformant
...@@ -451,6 +493,12 @@ UNUSUAL_DEV( 0x097a, 0x0001, 0x0000, 0x0001, ...@@ -451,6 +493,12 @@ UNUSUAL_DEV( 0x097a, 0x0001, 0x0000, 0x0001,
US_SC_SCSI, US_PR_CB, NULL, US_SC_SCSI, US_PR_CB, NULL,
US_FL_MODE_XLATE ), 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 #ifdef CONFIG_USB_STORAGE_ISD200
UNUSUAL_DEV( 0x0bf6, 0xa001, 0x0100, 0x0110, UNUSUAL_DEV( 0x0bf6, 0xa001, 0x0100, 0x0110,
"ATI", "ATI",
...@@ -459,6 +507,13 @@ UNUSUAL_DEV( 0x0bf6, 0xa001, 0x0100, 0x0110, ...@@ -459,6 +507,13 @@ UNUSUAL_DEV( 0x0bf6, 0xa001, 0x0100, 0x0110,
0 ), 0 ),
#endif #endif
/* EasyDisk support. Submitted by Stanislav Karchebny <berk@madfire.net> */
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 <brihall@bigfoot.com> /* Submitted by Brian Hall <brihall@bigfoot.com>
* Needed for START_STOP flag */ * Needed for START_STOP flag */
UNUSUAL_DEV( 0x0c76, 0x0003, 0x0100, 0x0100, UNUSUAL_DEV( 0x0c76, 0x0003, 0x0100, 0x0100,
...@@ -469,6 +524,8 @@ UNUSUAL_DEV( 0x0c76, 0x0003, 0x0100, 0x0100, ...@@ -469,6 +524,8 @@ UNUSUAL_DEV( 0x0c76, 0x0003, 0x0100, 0x0100,
/* Reported by Dan Pilone <pilone@slac.com> /* Reported by Dan Pilone <pilone@slac.com>
* The device needs the flags only. * The device needs the flags only.
* Also reported by Brian Hall <brihall@bigfoot.com>, again for flags.
* I also suspect this device may have a broken serial number.
*/ */
UNUSUAL_DEV( 0x1065, 0x2136, 0x0000, 0x9999, UNUSUAL_DEV( 0x1065, 0x2136, 0x0000, 0x9999,
"CCYU TECHNOLOGY", "CCYU TECHNOLOGY",
......
/* Driver for USB Mass Storage compliant devices /* 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: * 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: * Developed with the assistance of:
* (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
...@@ -315,6 +315,7 @@ static int usb_stor_control_thread(void * __us) ...@@ -315,6 +315,7 @@ static int usb_stor_control_thread(void * __us)
* so get rid of all our resources.. * so get rid of all our resources..
*/ */
daemonize(); daemonize();
reparent_to_init();
/* avoid getting signals */ /* avoid getting signals */
spin_lock_irq(&current->sigmask_lock); spin_lock_irq(&current->sigmask_lock);
...@@ -409,7 +410,7 @@ static int usb_stor_control_thread(void * __us) ...@@ -409,7 +410,7 @@ static int usb_stor_control_thread(void * __us)
down(&(us->dev_semaphore)); down(&(us->dev_semaphore));
/* our device has gone - pretend not ready */ /* 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"); US_DEBUGP("Request is for removed device\n");
/* For REQUEST_SENSE, it's the data. But /* For REQUEST_SENSE, it's the data. But
* for anything else, it should look like * for anything else, it should look like
...@@ -433,7 +434,7 @@ static int usb_stor_control_thread(void * __us) ...@@ -433,7 +434,7 @@ static int usb_stor_control_thread(void * __us)
sizeof(usb_stor_sense_notready)); sizeof(usb_stor_sense_notready));
us->srb->result = CHECK_CONDITION << 1; 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 /* Handle those devices which need us to fake
* their inquiry data */ * their inquiry data */
...@@ -449,7 +450,9 @@ static int usb_stor_control_thread(void * __us) ...@@ -449,7 +450,9 @@ static int usb_stor_control_thread(void * __us)
} else { } else {
/* we've got a command, let's do it! */ /* we've got a command, let's do it! */
US_DEBUG(usb_stor_show_command(us->srb)); US_DEBUG(usb_stor_show_command(us->srb));
atomic_set(&us->sm_state, US_STATE_RUNNING);
us->proto_handler(us->srb, us); us->proto_handler(us->srb, us);
atomic_set(&us->sm_state, US_STATE_IDLE);
} }
} }
...@@ -713,6 +716,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -713,6 +716,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
/* establish the connection to the new device upon reconnect */ /* establish the connection to the new device upon reconnect */
ss->ifnum = ifnum; ss->ifnum = ifnum;
ss->pusb_dev = dev; ss->pusb_dev = dev;
atomic_set(&ss->sm_state, US_STATE_IDLE);
/* copy over the endpoint data */ /* copy over the endpoint data */
if (ep_in) if (ep_in)
...@@ -955,6 +959,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -955,6 +959,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
ss->protocol_name = "Unknown"; ss->protocol_name = "Unknown";
kfree(ss->current_urb); kfree(ss->current_urb);
kfree(ss); kfree(ss);
usb_dec_dev_use(dev);
return NULL; return NULL;
break; break;
} }
...@@ -962,6 +967,8 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -962,6 +967,8 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
/* allocate an IRQ callback if one is needed */ /* allocate an IRQ callback if one is needed */
if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss)) { if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss)) {
kfree(ss->current_urb);
kfree(ss);
usb_dec_dev_use(dev); usb_dec_dev_use(dev);
return NULL; return NULL;
} }
...@@ -990,6 +997,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -990,6 +997,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
unusual_dev->initFunction(ss); unusual_dev->initFunction(ss);
/* start up our control thread */ /* start up our control thread */
atomic_set(&ss->sm_state, US_STATE_IDLE);
ss->pid = kernel_thread(usb_stor_control_thread, ss, ss->pid = kernel_thread(usb_stor_control_thread, ss,
CLONE_VM); CLONE_VM);
if (ss->pid < 0) { if (ss->pid < 0) {
...@@ -1006,7 +1014,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -1006,7 +1014,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
/* now register - our detect function will be called */ /* now register - our detect function will be called */
ss->htmplt.module = THIS_MODULE; ss->htmplt.module = THIS_MODULE;
scsi_register_host(&ss->htmplt); scsi_register_host(&(ss->htmplt));
/* lock access to the data structures */ /* lock access to the data structures */
down(&us_list_semaphore); down(&us_list_semaphore);
...@@ -1066,6 +1074,7 @@ static void storage_disconnect(struct usb_device *dev, void *ptr) ...@@ -1066,6 +1074,7 @@ static void storage_disconnect(struct usb_device *dev, void *ptr)
/* mark the device as gone */ /* mark the device as gone */
usb_dec_dev_use(ss->pusb_dev); usb_dec_dev_use(ss->pusb_dev);
ss->pusb_dev = NULL; ss->pusb_dev = NULL;
atomic_set(&ss->sm_state, US_STATE_DETACHED);
/* unlock access to the device data structure */ /* unlock access to the device data structure */
up(&(ss->dev_semaphore)); up(&(ss->dev_semaphore));
...@@ -1112,7 +1121,7 @@ void __exit usb_stor_exit(void) ...@@ -1112,7 +1121,7 @@ void __exit usb_stor_exit(void)
*/ */
for (next = us_list; next; next = next->next) { for (next = us_list; next; next = next->next) {
US_DEBUGP("-- calling scsi_unregister_host()\n"); 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 /* While there are still structures, free them. Note that we are
......
/* Driver for USB Mass Storage compliant devices /* Driver for USB Mass Storage compliant devices
* Main Header File * 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: * Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
...@@ -102,6 +102,12 @@ struct us_unusual_dev { ...@@ -102,6 +102,12 @@ struct us_unusual_dev {
#define US_FL_SCM_MULT_TARG 0x00000020 /* supports multiple targets */ #define US_FL_SCM_MULT_TARG 0x00000020 /* supports multiple targets */
#define US_FL_FIX_INQUIRY 0x00000040 /* INQUIRY response needs fixing */ #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 #define USB_STOR_STRING_LEN 32
typedef int (*trans_cmnd)(Scsi_Cmnd*, struct us_data*); typedef int (*trans_cmnd)(Scsi_Cmnd*, struct us_data*);
...@@ -152,10 +158,12 @@ struct us_data { ...@@ -152,10 +158,12 @@ struct us_data {
Scsi_Cmnd *queue_srb; /* the single queue slot */ Scsi_Cmnd *queue_srb; /* the single queue slot */
int action; /* what to do */ int action; /* what to do */
int pid; /* control thread */ int pid; /* control thread */
atomic_t sm_state;
/* interrupt info for CBI devices -- only good if attached */ /* interrupt info for CBI devices -- only good if attached */
struct semaphore ip_waitq; /* for CBI interrupts */ 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 */ /* interrupt communications data */
struct semaphore irq_urb_sem; /* to protect irq_urb */ struct semaphore irq_urb_sem; /* to protect irq_urb */
...@@ -188,4 +196,5 @@ extern struct usb_driver usb_storage_driver; ...@@ -188,4 +196,5 @@ extern struct usb_driver usb_storage_driver;
/* Function to fill an inquiry response. See usb.c for details */ /* Function to fill an inquiry response. See usb.c for details */
extern void fill_inquiry_response(struct us_data *us, extern void fill_inquiry_response(struct us_data *us,
unsigned char *data, unsigned int data_len); unsigned char *data, unsigned int data_len);
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment