2005-04-17 02:20:36 +04:00
/* Driver for Datafab USB Compact Flash reader
*
* $ Id : datafab . c , v 1.7 2002 / 02 / 25 00 : 40 : 13 mdharm Exp $
*
* datafab driver v0 .1 :
*
* First release
*
* Current development and maintenance by :
* ( c ) 2000 Jimmie Mayfield ( mayfield + datafab @ sackheads . org )
*
* Many thanks to Robert Baruch for the SanDisk SmartMedia reader driver
* which I used as a template for this driver .
*
* Some bugfixes and scatter - gather code by Gregory P . Smith
* ( greg - usb @ electricrain . com )
*
* Fix for media change by Joerg Schneider ( js @ joergschneider . com )
*
* Other contributors :
* ( c ) 2002 Alan Stern < stern @ rowland . org >
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; either version 2 , or ( at your option ) any
* later version .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
/*
* This driver attempts to support USB CompactFlash reader / writer devices
* based on Datafab USB - to - ATA chips . It was specifically developed for the
* Datafab MDCFE - B USB CompactFlash reader but has since been found to work
* with a variety of Datafab - based devices from a number of manufacturers .
* I ' ve received a report of this driver working with a Datafab - based
* SmartMedia device though please be aware that I ' m personally unable to
* test SmartMedia support .
*
* This driver supports reading and writing . If you ' re truly paranoid ,
* however , you can force the driver into a write - protected state by setting
* the WP enable bits in datafab_handle_mode_sense ( ) . See the comments
* in that routine .
*/
# include <linux/sched.h>
# include <linux/errno.h>
# include <linux/slab.h>
# include <scsi/scsi.h>
# include <scsi/scsi_cmnd.h>
# include "usb.h"
# include "transport.h"
# include "protocol.h"
# include "debug.h"
# include "datafab.h"
static int datafab_determine_lun ( struct us_data * us ,
struct datafab_info * info ) ;
static inline int
datafab_bulk_read ( struct us_data * us , unsigned char * data , unsigned int len ) {
if ( len = = 0 )
return USB_STOR_XFER_GOOD ;
US_DEBUGP ( " datafab_bulk_read: len = %d \n " , len ) ;
return usb_stor_bulk_transfer_buf ( us , us - > recv_bulk_pipe ,
data , len , NULL ) ;
}
static inline int
datafab_bulk_write ( struct us_data * us , unsigned char * data , unsigned int len ) {
if ( len = = 0 )
return USB_STOR_XFER_GOOD ;
US_DEBUGP ( " datafab_bulk_write: len = %d \n " , len ) ;
return usb_stor_bulk_transfer_buf ( us , us - > send_bulk_pipe ,
data , len , NULL ) ;
}
static int datafab_read_data ( struct us_data * us ,
struct datafab_info * info ,
u32 sector ,
u32 sectors )
{
unsigned char * command = us - > iobuf ;
unsigned char * buffer ;
unsigned char thistime ;
unsigned int totallen , alloclen ;
int len , result ;
unsigned int sg_idx = 0 , sg_offset = 0 ;
// we're working in LBA mode. according to the ATA spec,
// we can support up to 28-bit addressing. I don't know if Datafab
// supports beyond 24-bit addressing. It's kind of hard to test
// since it requires > 8GB CF card.
//
if ( sectors > 0x0FFFFFFF )
return USB_STOR_TRANSPORT_ERROR ;
if ( info - > lun = = - 1 ) {
result = datafab_determine_lun ( us , info ) ;
if ( result ! = USB_STOR_TRANSPORT_GOOD )
return result ;
}
totallen = sectors * info - > ssize ;
// Since we don't read more than 64 KB at a time, we have to create
// a bounce buffer and move the data a piece at a time between the
// bounce buffer and the actual transfer buffer.
alloclen = min ( totallen , 65536u ) ;
buffer = kmalloc ( alloclen , GFP_NOIO ) ;
if ( buffer = = NULL )
return USB_STOR_TRANSPORT_ERROR ;
do {
// loop, never allocate or transfer more than 64k at once
// (min(128k, 255*info->ssize) is the real limit)
len = min ( totallen , alloclen ) ;
thistime = ( len / info - > ssize ) & 0xff ;
command [ 0 ] = 0 ;
command [ 1 ] = thistime ;
command [ 2 ] = sector & 0xFF ;
command [ 3 ] = ( sector > > 8 ) & 0xFF ;
command [ 4 ] = ( sector > > 16 ) & 0xFF ;
command [ 5 ] = 0xE0 + ( info - > lun < < 4 ) ;
command [ 5 ] | = ( sector > > 24 ) & 0x0F ;
command [ 6 ] = 0x20 ;
command [ 7 ] = 0x01 ;
// send the read command
result = datafab_bulk_write ( us , command , 8 ) ;
if ( result ! = USB_STOR_XFER_GOOD )
goto leave ;
// read the result
result = datafab_bulk_read ( us , buffer , len ) ;
if ( result ! = USB_STOR_XFER_GOOD )
goto leave ;
// Store the data in the transfer buffer
usb_stor_access_xfer_buf ( buffer , len , us - > srb ,
& sg_idx , & sg_offset , TO_XFER_BUF ) ;
sector + = thistime ;
totallen - = len ;
} while ( totallen > 0 ) ;
kfree ( buffer ) ;
return USB_STOR_TRANSPORT_GOOD ;
leave :
kfree ( buffer ) ;
return USB_STOR_TRANSPORT_ERROR ;
}
static int datafab_write_data ( struct us_data * us ,
struct datafab_info * info ,
u32 sector ,
u32 sectors )
{
unsigned char * command = us - > iobuf ;
unsigned char * reply = us - > iobuf ;
unsigned char * buffer ;
unsigned char thistime ;
unsigned int totallen , alloclen ;
int len , result ;
unsigned int sg_idx = 0 , sg_offset = 0 ;
// we're working in LBA mode. according to the ATA spec,
// we can support up to 28-bit addressing. I don't know if Datafab
// supports beyond 24-bit addressing. It's kind of hard to test
// since it requires > 8GB CF card.
//
if ( sectors > 0x0FFFFFFF )
return USB_STOR_TRANSPORT_ERROR ;
if ( info - > lun = = - 1 ) {
result = datafab_determine_lun ( us , info ) ;
if ( result ! = USB_STOR_TRANSPORT_GOOD )
return result ;
}
totallen = sectors * info - > ssize ;
// Since we don't write more than 64 KB at a time, we have to create
// a bounce buffer and move the data a piece at a time between the
// bounce buffer and the actual transfer buffer.
alloclen = min ( totallen , 65536u ) ;
buffer = kmalloc ( alloclen , GFP_NOIO ) ;
if ( buffer = = NULL )
return USB_STOR_TRANSPORT_ERROR ;
do {
// loop, never allocate or transfer more than 64k at once
// (min(128k, 255*info->ssize) is the real limit)
len = min ( totallen , alloclen ) ;
thistime = ( len / info - > ssize ) & 0xff ;
// Get the data from the transfer buffer
usb_stor_access_xfer_buf ( buffer , len , us - > srb ,
& sg_idx , & sg_offset , FROM_XFER_BUF ) ;
command [ 0 ] = 0 ;
command [ 1 ] = thistime ;
command [ 2 ] = sector & 0xFF ;
command [ 3 ] = ( sector > > 8 ) & 0xFF ;
command [ 4 ] = ( sector > > 16 ) & 0xFF ;
command [ 5 ] = 0xE0 + ( info - > lun < < 4 ) ;
command [ 5 ] | = ( sector > > 24 ) & 0x0F ;
command [ 6 ] = 0x30 ;
command [ 7 ] = 0x02 ;
// send the command
result = datafab_bulk_write ( us , command , 8 ) ;
if ( result ! = USB_STOR_XFER_GOOD )
goto leave ;
// send the data
result = datafab_bulk_write ( us , buffer , len ) ;
if ( result ! = USB_STOR_XFER_GOOD )
goto leave ;
// read the result
result = datafab_bulk_read ( us , reply , 2 ) ;
if ( result ! = USB_STOR_XFER_GOOD )
goto leave ;
if ( reply [ 0 ] ! = 0x50 & & reply [ 1 ] ! = 0 ) {
US_DEBUGP ( " datafab_write_data: Gah! "
" write return code: %02x %02x \n " ,
reply [ 0 ] , reply [ 1 ] ) ;
result = USB_STOR_TRANSPORT_ERROR ;
goto leave ;
}
sector + = thistime ;
totallen - = len ;
} while ( totallen > 0 ) ;
kfree ( buffer ) ;
return USB_STOR_TRANSPORT_GOOD ;
leave :
kfree ( buffer ) ;
return USB_STOR_TRANSPORT_ERROR ;
}
static int datafab_determine_lun ( struct us_data * us ,
struct datafab_info * info )
{
// Dual-slot readers can be thought of as dual-LUN devices.
// We need to determine which card slot is being used.
// We'll send an IDENTIFY DEVICE command and see which LUN responds...
//
// There might be a better way of doing this?
static unsigned char scommand [ 8 ] = { 0 , 1 , 0 , 0 , 0 , 0xa0 , 0xec , 1 } ;
unsigned char * command = us - > iobuf ;
unsigned char * buf ;
int count = 0 , rc ;
if ( ! us | | ! info )
return USB_STOR_TRANSPORT_ERROR ;
memcpy ( command , scommand , 8 ) ;
buf = kmalloc ( 512 , GFP_NOIO ) ;
if ( ! buf )
return USB_STOR_TRANSPORT_ERROR ;
US_DEBUGP ( " datafab_determine_lun: locating... \n " ) ;
// we'll try 3 times before giving up...
//
while ( count + + < 3 ) {
command [ 5 ] = 0xa0 ;
rc = datafab_bulk_write ( us , command , 8 ) ;
if ( rc ! = USB_STOR_XFER_GOOD ) {
rc = USB_STOR_TRANSPORT_ERROR ;
goto leave ;
}
rc = datafab_bulk_read ( us , buf , 512 ) ;
if ( rc = = USB_STOR_XFER_GOOD ) {
info - > lun = 0 ;
rc = USB_STOR_TRANSPORT_GOOD ;
goto leave ;
}
command [ 5 ] = 0xb0 ;
rc = datafab_bulk_write ( us , command , 8 ) ;
if ( rc ! = USB_STOR_XFER_GOOD ) {
rc = USB_STOR_TRANSPORT_ERROR ;
goto leave ;
}
rc = datafab_bulk_read ( us , buf , 512 ) ;
if ( rc = = USB_STOR_XFER_GOOD ) {
info - > lun = 1 ;
rc = USB_STOR_TRANSPORT_GOOD ;
goto leave ;
}
msleep ( 20 ) ;
}
rc = USB_STOR_TRANSPORT_ERROR ;
leave :
kfree ( buf ) ;
return rc ;
}
static int datafab_id_device ( struct us_data * us ,
struct datafab_info * info )
{
// this is a variation of the ATA "IDENTIFY DEVICE" command...according
// to the ATA spec, 'Sector Count' isn't used but the Windows driver
// sets this bit so we do too...
//
static unsigned char scommand [ 8 ] = { 0 , 1 , 0 , 0 , 0 , 0xa0 , 0xec , 1 } ;
unsigned char * command = us - > iobuf ;
unsigned char * reply ;
int rc ;
if ( ! us | | ! info )
return USB_STOR_TRANSPORT_ERROR ;
if ( info - > lun = = - 1 ) {
rc = datafab_determine_lun ( us , info ) ;
if ( rc ! = USB_STOR_TRANSPORT_GOOD )
return rc ;
}
memcpy ( command , scommand , 8 ) ;
reply = kmalloc ( 512 , GFP_NOIO ) ;
if ( ! reply )
return USB_STOR_TRANSPORT_ERROR ;
command [ 5 ] + = ( info - > lun < < 4 ) ;
rc = datafab_bulk_write ( us , command , 8 ) ;
if ( rc ! = USB_STOR_XFER_GOOD ) {
rc = USB_STOR_TRANSPORT_ERROR ;
goto leave ;
}
// we'll go ahead and extract the media capacity while we're here...
//
rc = datafab_bulk_read ( us , reply , 512 ) ;
if ( rc = = USB_STOR_XFER_GOOD ) {
// capacity is at word offset 57-58
//
info - > sectors = ( ( u32 ) ( reply [ 117 ] ) < < 24 ) |
( ( u32 ) ( reply [ 116 ] ) < < 16 ) |
( ( u32 ) ( reply [ 115 ] ) < < 8 ) |
( ( u32 ) ( reply [ 114 ] ) ) ;
rc = USB_STOR_TRANSPORT_GOOD ;
goto leave ;
}
rc = USB_STOR_TRANSPORT_ERROR ;
leave :
kfree ( reply ) ;
return rc ;
}
static int datafab_handle_mode_sense ( struct us_data * us ,
struct scsi_cmnd * srb ,
int sense_6 )
{
static unsigned char rw_err_page [ 12 ] = {
0x1 , 0xA , 0x21 , 1 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0
} ;
static unsigned char cache_page [ 12 ] = {
0x8 , 0xA , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
} ;
static unsigned char rbac_page [ 12 ] = {
0x1B , 0xA , 0 , 0x81 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
} ;
static unsigned char timer_page [ 8 ] = {
0x1C , 0x6 , 0 , 0 , 0 , 0
} ;
unsigned char pc , page_code ;
unsigned int i = 0 ;
struct datafab_info * info = ( struct datafab_info * ) ( us - > extra ) ;
unsigned char * ptr = us - > iobuf ;
// most of this stuff is just a hack to get things working. the
// datafab reader doesn't present a SCSI interface so we
// fudge the SCSI commands...
//
pc = srb - > cmnd [ 2 ] > > 6 ;
page_code = srb - > cmnd [ 2 ] & 0x3F ;
switch ( pc ) {
case 0x0 :
US_DEBUGP ( " datafab_handle_mode_sense: Current values \n " ) ;
break ;
case 0x1 :
US_DEBUGP ( " datafab_handle_mode_sense: Changeable values \n " ) ;
break ;
case 0x2 :
US_DEBUGP ( " datafab_handle_mode_sense: Default values \n " ) ;
break ;
case 0x3 :
US_DEBUGP ( " datafab_handle_mode_sense: Saves values \n " ) ;
break ;
}
memset ( ptr , 0 , 8 ) ;
if ( sense_6 ) {
ptr [ 2 ] = 0x00 ; // WP enable: 0x80
i = 4 ;
} else {
ptr [ 3 ] = 0x00 ; // WP enable: 0x80
i = 8 ;
}
switch ( page_code ) {
default :
// vendor-specific mode
info - > sense_key = 0x05 ;
info - > sense_asc = 0x24 ;
info - > sense_ascq = 0x00 ;
return USB_STOR_TRANSPORT_FAILED ;
case 0x1 :
memcpy ( ptr + i , rw_err_page , sizeof ( rw_err_page ) ) ;
i + = sizeof ( rw_err_page ) ;
break ;
case 0x8 :
memcpy ( ptr + i , cache_page , sizeof ( cache_page ) ) ;
i + = sizeof ( cache_page ) ;
break ;
case 0x1B :
memcpy ( ptr + i , rbac_page , sizeof ( rbac_page ) ) ;
i + = sizeof ( rbac_page ) ;
break ;
case 0x1C :
memcpy ( ptr + i , timer_page , sizeof ( timer_page ) ) ;
i + = sizeof ( timer_page ) ;
break ;
case 0x3F : // retrieve all pages
memcpy ( ptr + i , timer_page , sizeof ( timer_page ) ) ;
i + = sizeof ( timer_page ) ;
memcpy ( ptr + i , rbac_page , sizeof ( rbac_page ) ) ;
i + = sizeof ( rbac_page ) ;
memcpy ( ptr + i , cache_page , sizeof ( cache_page ) ) ;
i + = sizeof ( cache_page ) ;
memcpy ( ptr + i , rw_err_page , sizeof ( rw_err_page ) ) ;
i + = sizeof ( rw_err_page ) ;
break ;
}
if ( sense_6 )
ptr [ 0 ] = i - 1 ;
else
( ( __be16 * ) ptr ) [ 0 ] = cpu_to_be16 ( i - 2 ) ;
usb_stor_set_xfer_buf ( ptr , i , srb ) ;
return USB_STOR_TRANSPORT_GOOD ;
}
static void datafab_info_destructor ( void * extra )
{
// this routine is a placeholder...
// currently, we don't allocate any extra memory so we're okay
}
// Transport for the Datafab MDCFE-B
//
int datafab_transport ( struct scsi_cmnd * srb , struct us_data * us )
{
struct datafab_info * info ;
int rc ;
unsigned long block , blocks ;
unsigned char * ptr = us - > iobuf ;
static unsigned char inquiry_reply [ 8 ] = {
0x00 , 0x80 , 0x00 , 0x01 , 0x1F , 0x00 , 0x00 , 0x00
} ;
if ( ! us - > extra ) {
2006-01-08 14:33:45 +03:00
us - > extra = kzalloc ( sizeof ( struct datafab_info ) , GFP_NOIO ) ;
2005-04-17 02:20:36 +04:00
if ( ! us - > extra ) {
US_DEBUGP ( " datafab_transport: Gah! "
" Can't allocate storage for Datafab info struct! \n " ) ;
return USB_STOR_TRANSPORT_ERROR ;
}
us - > extra_destructor = datafab_info_destructor ;
( ( struct datafab_info * ) us - > extra ) - > lun = - 1 ;
}
info = ( struct datafab_info * ) ( us - > extra ) ;
if ( srb - > cmnd [ 0 ] = = INQUIRY ) {
US_DEBUGP ( " datafab_transport: INQUIRY. Returning bogus response " ) ;
memcpy ( ptr , inquiry_reply , sizeof ( inquiry_reply ) ) ;
fill_inquiry_response ( us , ptr , 36 ) ;
return USB_STOR_TRANSPORT_GOOD ;
}
if ( srb - > cmnd [ 0 ] = = READ_CAPACITY ) {
info - > ssize = 0x200 ; // hard coded 512 byte sectors as per ATA spec
rc = datafab_id_device ( us , info ) ;
if ( rc ! = USB_STOR_TRANSPORT_GOOD )
return rc ;
US_DEBUGP ( " datafab_transport: READ_CAPACITY: %ld sectors, %ld bytes per sector \n " ,
info - > sectors , info - > ssize ) ;
// build the reply
// we need the last sector, not the number of sectors
( ( __be32 * ) ptr ) [ 0 ] = cpu_to_be32 ( info - > sectors - 1 ) ;
( ( __be32 * ) ptr ) [ 1 ] = cpu_to_be32 ( info - > ssize ) ;
usb_stor_set_xfer_buf ( ptr , 8 , srb ) ;
return USB_STOR_TRANSPORT_GOOD ;
}
if ( srb - > cmnd [ 0 ] = = MODE_SELECT_10 ) {
US_DEBUGP ( " datafab_transport: Gah! MODE_SELECT_10. \n " ) ;
return USB_STOR_TRANSPORT_ERROR ;
}
// don't bother implementing READ_6 or WRITE_6.
//
if ( srb - > cmnd [ 0 ] = = READ_10 ) {
block = ( ( u32 ) ( srb - > cmnd [ 2 ] ) < < 24 ) | ( ( u32 ) ( srb - > cmnd [ 3 ] ) < < 16 ) |
( ( u32 ) ( srb - > cmnd [ 4 ] ) < < 8 ) | ( ( u32 ) ( srb - > cmnd [ 5 ] ) ) ;
blocks = ( ( u32 ) ( srb - > cmnd [ 7 ] ) < < 8 ) | ( ( u32 ) ( srb - > cmnd [ 8 ] ) ) ;
US_DEBUGP ( " datafab_transport: READ_10: read block 0x%04lx count %ld \n " , block , blocks ) ;
return datafab_read_data ( us , info , block , blocks ) ;
}
if ( srb - > cmnd [ 0 ] = = READ_12 ) {
// we'll probably never see a READ_12 but we'll do it anyway...
//
block = ( ( u32 ) ( srb - > cmnd [ 2 ] ) < < 24 ) | ( ( u32 ) ( srb - > cmnd [ 3 ] ) < < 16 ) |
( ( u32 ) ( srb - > cmnd [ 4 ] ) < < 8 ) | ( ( u32 ) ( srb - > cmnd [ 5 ] ) ) ;
blocks = ( ( u32 ) ( srb - > cmnd [ 6 ] ) < < 24 ) | ( ( u32 ) ( srb - > cmnd [ 7 ] ) < < 16 ) |
( ( u32 ) ( srb - > cmnd [ 8 ] ) < < 8 ) | ( ( u32 ) ( srb - > cmnd [ 9 ] ) ) ;
US_DEBUGP ( " datafab_transport: READ_12: read block 0x%04lx count %ld \n " , block , blocks ) ;
return datafab_read_data ( us , info , block , blocks ) ;
}
if ( srb - > cmnd [ 0 ] = = WRITE_10 ) {
block = ( ( u32 ) ( srb - > cmnd [ 2 ] ) < < 24 ) | ( ( u32 ) ( srb - > cmnd [ 3 ] ) < < 16 ) |
( ( u32 ) ( srb - > cmnd [ 4 ] ) < < 8 ) | ( ( u32 ) ( srb - > cmnd [ 5 ] ) ) ;
blocks = ( ( u32 ) ( srb - > cmnd [ 7 ] ) < < 8 ) | ( ( u32 ) ( srb - > cmnd [ 8 ] ) ) ;
US_DEBUGP ( " datafab_transport: WRITE_10: write block 0x%04lx count %ld \n " , block , blocks ) ;
return datafab_write_data ( us , info , block , blocks ) ;
}
if ( srb - > cmnd [ 0 ] = = WRITE_12 ) {
// we'll probably never see a WRITE_12 but we'll do it anyway...
//
block = ( ( u32 ) ( srb - > cmnd [ 2 ] ) < < 24 ) | ( ( u32 ) ( srb - > cmnd [ 3 ] ) < < 16 ) |
( ( u32 ) ( srb - > cmnd [ 4 ] ) < < 8 ) | ( ( u32 ) ( srb - > cmnd [ 5 ] ) ) ;
blocks = ( ( u32 ) ( srb - > cmnd [ 6 ] ) < < 24 ) | ( ( u32 ) ( srb - > cmnd [ 7 ] ) < < 16 ) |
( ( u32 ) ( srb - > cmnd [ 8 ] ) < < 8 ) | ( ( u32 ) ( srb - > cmnd [ 9 ] ) ) ;
US_DEBUGP ( " datafab_transport: WRITE_12: write block 0x%04lx count %ld \n " , block , blocks ) ;
return datafab_write_data ( us , info , block , blocks ) ;
}
if ( srb - > cmnd [ 0 ] = = TEST_UNIT_READY ) {
US_DEBUGP ( " datafab_transport: TEST_UNIT_READY. \n " ) ;
return datafab_id_device ( us , info ) ;
}
if ( srb - > cmnd [ 0 ] = = REQUEST_SENSE ) {
US_DEBUGP ( " datafab_transport: REQUEST_SENSE. Returning faked response \n " ) ;
// this response is pretty bogus right now. eventually if necessary
// we can set the correct sense data. so far though it hasn't been
// necessary
//
memset ( ptr , 0 , 18 ) ;
ptr [ 0 ] = 0xF0 ;
ptr [ 2 ] = info - > sense_key ;
ptr [ 7 ] = 11 ;
ptr [ 12 ] = info - > sense_asc ;
ptr [ 13 ] = info - > sense_ascq ;
usb_stor_set_xfer_buf ( ptr , 18 , srb ) ;
return USB_STOR_TRANSPORT_GOOD ;
}
if ( srb - > cmnd [ 0 ] = = MODE_SENSE ) {
US_DEBUGP ( " datafab_transport: MODE_SENSE_6 detected \n " ) ;
return datafab_handle_mode_sense ( us , srb , 1 ) ;
}
if ( srb - > cmnd [ 0 ] = = MODE_SENSE_10 ) {
US_DEBUGP ( " datafab_transport: MODE_SENSE_10 detected \n " ) ;
return datafab_handle_mode_sense ( us , srb , 0 ) ;
}
if ( srb - > cmnd [ 0 ] = = ALLOW_MEDIUM_REMOVAL ) {
// sure. whatever. not like we can stop the user from
// popping the media out of the device (no locking doors, etc)
//
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 = SAM_STAT_CHECK_CONDITION ;
}
return rc ;
}
US_DEBUGP ( " datafab_transport: Gah! Unknown command: %d (0x%x) \n " ,
srb - > cmnd [ 0 ] , srb - > cmnd [ 0 ] ) ;
info - > sense_key = 0x05 ;
info - > sense_asc = 0x20 ;
info - > sense_ascq = 0x00 ;
return USB_STOR_TRANSPORT_FAILED ;
}