2005-04-17 02:20:36 +04:00
/*
* sd . c Copyright ( C ) 1992 Drew Eckhardt
* Copyright ( C ) 1993 , 1994 , 1995 , 1999 Eric Youngdale
*
* Linux scsi disk driver
* Initial versions : Drew Eckhardt
* Subsequent revisions : Eric Youngdale
* Modification history :
* - Drew Eckhardt < drew @ colorado . edu > original
* - Eric Youngdale < eric @ andante . org > add scatter - gather , multiple
* outstanding request , and other enhancements .
* Support loadable low - level scsi drivers .
* - Jirka Hanika < geo @ ff . cuni . cz > support more scsi disks using
* eight major numbers .
* - Richard Gooch < rgooch @ atnf . csiro . au > support devfs .
* - Torben Mathiasen < tmm @ image . dk > Resource allocation fixes in
* sd_init and cleanups .
* - Alex Davis < letmein @ erols . com > Fix problem where partition info
* not being read in sd_open . Fix problem where removable media
* could be ejected after sd_open .
* - Douglas Gilbert < dgilbert @ interlog . com > cleanup for lk 2.5 . x
* - Badari Pulavarty < pbadari @ us . ibm . com > , Matthew Wilcox
* < willy @ debian . org > , Kurt Garloff < garloff @ suse . de > :
* Support 32 k / 1 M disks .
*
* Logging policy ( needs CONFIG_SCSI_LOGGING defined ) :
* - setting up transfer : SCSI_LOG_HLQUEUE levels 1 and 2
* - end of transfer ( bh + scsi_lib ) : SCSI_LOG_HLCOMPLETE level 1
* - entering sd_ioctl : SCSI_LOG_IOCTL level 1
* - entering other commands : SCSI_LOG_HLQUEUE level 3
* Note : when the logging level is set by the user , it must be greater
* than the level indicated above to trigger output .
*/
# include <linux/module.h>
# include <linux/fs.h>
# include <linux/kernel.h>
# include <linux/sched.h>
# include <linux/mm.h>
# include <linux/bio.h>
# include <linux/genhd.h>
# include <linux/hdreg.h>
# include <linux/errno.h>
# include <linux/idr.h>
# include <linux/interrupt.h>
# include <linux/init.h>
# include <linux/blkdev.h>
# include <linux/blkpg.h>
# include <linux/delay.h>
2006-01-11 15:16:10 +03:00
# include <linux/mutex.h>
2005-04-17 02:20:36 +04:00
# include <asm/uaccess.h>
# include <scsi/scsi.h>
# include <scsi/scsi_cmnd.h>
# include <scsi/scsi_dbg.h>
# include <scsi/scsi_device.h>
# include <scsi/scsi_driver.h>
# include <scsi/scsi_eh.h>
# include <scsi/scsi_host.h>
# include <scsi/scsi_ioctl.h>
# include <scsi/scsicam.h>
# include "scsi_logging.h"
/*
* More than enough for everybody ; ) The huge number of majors
* is a leftover from 16 bit dev_t days , we don ' t really need that
* much numberspace .
*/
# define SD_MAJORS 16
2006-03-08 11:14:20 +03:00
MODULE_AUTHOR ( " Eric Youngdale " ) ;
MODULE_DESCRIPTION ( " SCSI disk (sd) driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS_BLOCKDEV_MAJOR ( SCSI_DISK0_MAJOR ) ;
MODULE_ALIAS_BLOCKDEV_MAJOR ( SCSI_DISK1_MAJOR ) ;
MODULE_ALIAS_BLOCKDEV_MAJOR ( SCSI_DISK2_MAJOR ) ;
MODULE_ALIAS_BLOCKDEV_MAJOR ( SCSI_DISK3_MAJOR ) ;
MODULE_ALIAS_BLOCKDEV_MAJOR ( SCSI_DISK4_MAJOR ) ;
MODULE_ALIAS_BLOCKDEV_MAJOR ( SCSI_DISK5_MAJOR ) ;
MODULE_ALIAS_BLOCKDEV_MAJOR ( SCSI_DISK6_MAJOR ) ;
MODULE_ALIAS_BLOCKDEV_MAJOR ( SCSI_DISK7_MAJOR ) ;
MODULE_ALIAS_BLOCKDEV_MAJOR ( SCSI_DISK8_MAJOR ) ;
MODULE_ALIAS_BLOCKDEV_MAJOR ( SCSI_DISK9_MAJOR ) ;
MODULE_ALIAS_BLOCKDEV_MAJOR ( SCSI_DISK10_MAJOR ) ;
MODULE_ALIAS_BLOCKDEV_MAJOR ( SCSI_DISK11_MAJOR ) ;
MODULE_ALIAS_BLOCKDEV_MAJOR ( SCSI_DISK12_MAJOR ) ;
MODULE_ALIAS_BLOCKDEV_MAJOR ( SCSI_DISK13_MAJOR ) ;
MODULE_ALIAS_BLOCKDEV_MAJOR ( SCSI_DISK14_MAJOR ) ;
MODULE_ALIAS_BLOCKDEV_MAJOR ( SCSI_DISK15_MAJOR ) ;
2005-04-17 02:20:36 +04:00
/*
* This is limited by the naming scheme enforced in sd_probe ,
* add another character to it if you really need more disks .
*/
# define SD_MAX_DISKS (((26 * 26) + 26 + 1) * 26)
/*
* Time out in seconds for disks and Magneto - opticals ( which are slower ) .
*/
# define SD_TIMEOUT (30 * HZ)
# define SD_MOD_TIMEOUT (75 * HZ)
/*
* Number of allowed retries
*/
# define SD_MAX_RETRIES 5
# define SD_PASSTHROUGH_RETRIES 1
2006-02-26 17:34:10 +03:00
/*
* Size of the initial data buffer for mode and read capacity data
*/
# define SD_BUF_SIZE 512
2005-04-17 02:20:36 +04:00
struct scsi_disk {
struct scsi_driver * driver ; /* always &sd_template */
struct scsi_device * device ;
2006-03-18 23:14:21 +03:00
struct class_device cdev ;
2005-04-17 02:20:36 +04:00
struct gendisk * disk ;
unsigned int openers ; /* protected by BKL for now, yuck */
sector_t capacity ; /* size in 512-byte sectors */
u32 index ;
u8 media_present ;
u8 write_prot ;
unsigned WCE : 1 ; /* state of disk WCE bit */
unsigned RCD : 1 ; /* state of disk RCD bit, unused */
2006-01-06 11:53:52 +03:00
unsigned DPOFUA : 1 ; /* state of disk DPOFUA bit */
2005-04-17 02:20:36 +04:00
} ;
2006-03-18 23:14:21 +03:00
# define to_scsi_disk(obj) container_of(obj,struct scsi_disk,cdev)
2005-04-17 02:20:36 +04:00
static DEFINE_IDR ( sd_index_idr ) ;
static DEFINE_SPINLOCK ( sd_index_lock ) ;
/* This semaphore is used to mediate the 0->1 reference get in the
* face of object destruction ( i . e . we can ' t allow a get on an
* object after last put ) */
2006-01-11 15:16:10 +03:00
static DEFINE_MUTEX ( sd_ref_mutex ) ;
2005-04-17 02:20:36 +04:00
static int sd_revalidate_disk ( struct gendisk * disk ) ;
static void sd_rw_intr ( struct scsi_cmnd * SCpnt ) ;
static int sd_probe ( struct device * ) ;
static int sd_remove ( struct device * ) ;
static void sd_shutdown ( struct device * dev ) ;
static void sd_rescan ( struct device * ) ;
static int sd_init_command ( struct scsi_cmnd * ) ;
static int sd_issue_flush ( struct device * , sector_t * ) ;
2006-01-06 11:52:55 +03:00
static void sd_prepare_flush ( request_queue_t * , struct request * ) ;
2005-04-17 02:20:36 +04:00
static void sd_read_capacity ( struct scsi_disk * sdkp , char * diskname ,
2005-08-28 20:33:52 +04:00
unsigned char * buffer ) ;
2006-03-18 23:14:21 +03:00
static void scsi_disk_release ( struct class_device * cdev ) ;
static const char * sd_cache_types [ ] = {
" write through " , " none " , " write back " ,
" write back, no read (daft) "
} ;
static ssize_t sd_store_cache_type ( struct class_device * cdev , const char * buf ,
size_t count )
{
int i , ct = - 1 , rcd , wce , sp ;
struct scsi_disk * sdkp = to_scsi_disk ( cdev ) ;
struct scsi_device * sdp = sdkp - > device ;
char buffer [ 64 ] ;
char * buffer_data ;
struct scsi_mode_data data ;
struct scsi_sense_hdr sshdr ;
int len ;
if ( sdp - > type ! = TYPE_DISK )
/* no cache control on RBC devices; theoretically they
* can do it , but there ' s probably so many exceptions
* it ' s not worth the risk */
return - EINVAL ;
2006-06-09 09:23:48 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( sd_cache_types ) ; i + + ) {
2006-03-18 23:14:21 +03:00
const int len = strlen ( sd_cache_types [ i ] ) ;
if ( strncmp ( sd_cache_types [ i ] , buf , len ) = = 0 & &
buf [ len ] = = ' \n ' ) {
ct = i ;
break ;
}
}
if ( ct < 0 )
return - EINVAL ;
rcd = ct & 0x01 ? 1 : 0 ;
wce = ct & 0x02 ? 1 : 0 ;
if ( scsi_mode_sense ( sdp , 0x08 , 8 , buffer , sizeof ( buffer ) , SD_TIMEOUT ,
SD_MAX_RETRIES , & data , NULL ) )
return - EINVAL ;
2006-03-25 14:08:30 +03:00
len = min_t ( size_t , sizeof ( buffer ) , data . length - data . header_length -
2006-03-18 23:14:21 +03:00
data . block_descriptor_length ) ;
buffer_data = buffer + data . header_length +
data . block_descriptor_length ;
buffer_data [ 2 ] & = ~ 0x05 ;
buffer_data [ 2 ] | = wce < < 2 | rcd ;
sp = buffer_data [ 0 ] & 0x80 ? 1 : 0 ;
if ( scsi_mode_select ( sdp , 1 , sp , 8 , buffer_data , len , SD_TIMEOUT ,
SD_MAX_RETRIES , & data , & sshdr ) ) {
if ( scsi_sense_valid ( & sshdr ) )
scsi_print_sense_hdr ( sdkp - > disk - > disk_name , & sshdr ) ;
return - EINVAL ;
}
sd_revalidate_disk ( sdkp - > disk ) ;
return count ;
}
2006-06-27 20:10:31 +04:00
static ssize_t sd_store_allow_restart ( struct class_device * cdev , const char * buf ,
size_t count )
{
struct scsi_disk * sdkp = to_scsi_disk ( cdev ) ;
struct scsi_device * sdp = sdkp - > device ;
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EACCES ;
if ( sdp - > type ! = TYPE_DISK )
return - EINVAL ;
sdp - > allow_restart = simple_strtoul ( buf , NULL , 10 ) ;
return count ;
}
2006-03-18 23:14:21 +03:00
static ssize_t sd_show_cache_type ( struct class_device * cdev , char * buf )
{
struct scsi_disk * sdkp = to_scsi_disk ( cdev ) ;
int ct = sdkp - > RCD + 2 * sdkp - > WCE ;
return snprintf ( buf , 40 , " %s \n " , sd_cache_types [ ct ] ) ;
}
static ssize_t sd_show_fua ( struct class_device * cdev , char * buf )
{
struct scsi_disk * sdkp = to_scsi_disk ( cdev ) ;
return snprintf ( buf , 20 , " %u \n " , sdkp - > DPOFUA ) ;
}
2006-06-27 20:10:31 +04:00
static ssize_t sd_show_allow_restart ( struct class_device * cdev , char * buf )
{
struct scsi_disk * sdkp = to_scsi_disk ( cdev ) ;
return snprintf ( buf , 40 , " %d \n " , sdkp - > device - > allow_restart ) ;
}
2006-03-18 23:14:21 +03:00
static struct class_device_attribute sd_disk_attrs [ ] = {
__ATTR ( cache_type , S_IRUGO | S_IWUSR , sd_show_cache_type ,
sd_store_cache_type ) ,
__ATTR ( FUA , S_IRUGO , sd_show_fua , NULL ) ,
2006-06-27 20:10:31 +04:00
__ATTR ( allow_restart , S_IRUGO | S_IWUSR , sd_show_allow_restart ,
sd_store_allow_restart ) ,
2006-03-18 23:14:21 +03:00
__ATTR_NULL ,
} ;
static struct class sd_disk_class = {
. name = " scsi_disk " ,
. owner = THIS_MODULE ,
. release = scsi_disk_release ,
. class_dev_attrs = sd_disk_attrs ,
} ;
2005-04-17 02:20:36 +04:00
static struct scsi_driver sd_template = {
. owner = THIS_MODULE ,
. gendrv = {
. name = " sd " ,
. probe = sd_probe ,
. remove = sd_remove ,
. shutdown = sd_shutdown ,
} ,
. rescan = sd_rescan ,
. init_command = sd_init_command ,
. issue_flush = sd_issue_flush ,
} ;
/*
* Device no to disk mapping :
*
* major disc2 disc p1
* | . . . . . . . . . . . . | . . . . . . . . . . . . . | . . . . | . . . . | < - dev_t
* 31 20 19 8 7 4 3 0
*
* Inside a major , we have 16 k disks , however mapped non -
* contiguously . The first 16 disks are for major0 , the next
* ones with major1 , . . . Disk 256 is for major0 again , disk 272
* for major1 , . . .
* As we stay compatible with our numbering scheme , we can reuse
* the well - know SCSI majors 8 , 65 - - 71 , 136 - - 143.
*/
static int sd_major ( int major_idx )
{
switch ( major_idx ) {
case 0 :
return SCSI_DISK0_MAJOR ;
case 1 . . . 7 :
return SCSI_DISK1_MAJOR + major_idx - 1 ;
case 8 . . . 15 :
return SCSI_DISK8_MAJOR + major_idx - 8 ;
default :
BUG ( ) ;
return 0 ; /* shut up gcc */
}
}
static inline struct scsi_disk * scsi_disk ( struct gendisk * disk )
{
return container_of ( disk - > private_data , struct scsi_disk , driver ) ;
}
2005-11-04 22:44:41 +03:00
static struct scsi_disk * __scsi_disk_get ( struct gendisk * disk )
2005-04-17 02:20:36 +04:00
{
struct scsi_disk * sdkp = NULL ;
2005-11-04 22:44:41 +03:00
if ( disk - > private_data ) {
sdkp = scsi_disk ( disk ) ;
if ( scsi_device_get ( sdkp - > device ) = = 0 )
2006-03-18 23:14:21 +03:00
class_device_get ( & sdkp - > cdev ) ;
2005-11-04 22:44:41 +03:00
else
sdkp = NULL ;
}
return sdkp ;
}
static struct scsi_disk * scsi_disk_get ( struct gendisk * disk )
{
struct scsi_disk * sdkp ;
2006-01-11 15:16:10 +03:00
mutex_lock ( & sd_ref_mutex ) ;
2005-11-04 22:44:41 +03:00
sdkp = __scsi_disk_get ( disk ) ;
2006-01-11 15:16:10 +03:00
mutex_unlock ( & sd_ref_mutex ) ;
2005-04-17 02:20:36 +04:00
return sdkp ;
2005-11-04 22:44:41 +03:00
}
2005-04-17 02:20:36 +04:00
2005-11-04 22:44:41 +03:00
static struct scsi_disk * scsi_disk_get_from_dev ( struct device * dev )
{
struct scsi_disk * sdkp ;
2006-01-11 15:16:10 +03:00
mutex_lock ( & sd_ref_mutex ) ;
2005-11-04 22:44:41 +03:00
sdkp = dev_get_drvdata ( dev ) ;
if ( sdkp )
sdkp = __scsi_disk_get ( sdkp - > disk ) ;
2006-01-11 15:16:10 +03:00
mutex_unlock ( & sd_ref_mutex ) ;
2005-04-17 02:20:36 +04:00
return sdkp ;
}
static void scsi_disk_put ( struct scsi_disk * sdkp )
{
struct scsi_device * sdev = sdkp - > device ;
2006-01-11 15:16:10 +03:00
mutex_lock ( & sd_ref_mutex ) ;
2006-03-18 23:14:21 +03:00
class_device_put ( & sdkp - > cdev ) ;
2005-04-17 02:20:36 +04:00
scsi_device_put ( sdev ) ;
2006-01-11 15:16:10 +03:00
mutex_unlock ( & sd_ref_mutex ) ;
2005-04-17 02:20:36 +04:00
}
/**
* sd_init_command - build a scsi ( read or write ) command from
* information in the request structure .
* @ SCpnt : pointer to mid - level ' s per scsi command structure that
* contains request and into which the scsi command is written
*
* Returns 1 if successful and 0 if error ( or cannot be done now ) .
* */
static int sd_init_command ( struct scsi_cmnd * SCpnt )
{
struct scsi_device * sdp = SCpnt - > device ;
struct request * rq = SCpnt - > request ;
2006-01-06 20:34:07 +03:00
struct gendisk * disk = rq - > rq_disk ;
sector_t block = rq - > sector ;
unsigned int this_count = SCpnt - > request_bufflen > > 9 ;
unsigned int timeout = sdp - > timeout ;
2005-04-17 02:20:36 +04:00
SCSI_LOG_HLQUEUE ( 1 , printk ( " sd_init_command: disk=%s, block=%llu, "
" count=%d \n " , disk - > disk_name ,
( unsigned long long ) block , this_count ) ) ;
if ( ! sdp | | ! scsi_device_online ( sdp ) | |
block + rq - > nr_sectors > get_capacity ( disk ) ) {
SCSI_LOG_HLQUEUE ( 2 , printk ( " Finishing %ld sectors \n " ,
rq - > nr_sectors ) ) ;
SCSI_LOG_HLQUEUE ( 2 , printk ( " Retry with 0x%p \n " , SCpnt ) ) ;
return 0 ;
}
if ( sdp - > changed ) {
/*
* quietly refuse to do anything to a changed disc until
* the changed bit has been reset
*/
/* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */
return 0 ;
}
SCSI_LOG_HLQUEUE ( 2 , printk ( " %s : block=%llu \n " ,
disk - > disk_name , ( unsigned long long ) block ) ) ;
/*
* If we have a 1 K hardware sectorsize , prevent access to single
* 512 byte sectors . In theory we could handle this - in fact
* the scsi cdrom driver must be able to handle this because
* we typically use 1 K blocksizes , and cdroms typically have
* 2 K hardware sectorsizes . Of course , things are simpler
* with the cdrom , since it is read - only . For performance
* reasons , the filesystems should be able to handle this
* and not force the scsi disk driver to use bounce buffers
* for this .
*/
if ( sdp - > sector_size = = 1024 ) {
if ( ( block & 1 ) | | ( rq - > nr_sectors & 1 ) ) {
printk ( KERN_ERR " sd: Bad block number requested " ) ;
return 0 ;
} else {
block = block > > 1 ;
this_count = this_count > > 1 ;
}
}
if ( sdp - > sector_size = = 2048 ) {
if ( ( block & 3 ) | | ( rq - > nr_sectors & 3 ) ) {
printk ( KERN_ERR " sd: Bad block number requested " ) ;
return 0 ;
} else {
block = block > > 2 ;
this_count = this_count > > 2 ;
}
}
if ( sdp - > sector_size = = 4096 ) {
if ( ( block & 7 ) | | ( rq - > nr_sectors & 7 ) ) {
printk ( KERN_ERR " sd: Bad block number requested " ) ;
return 0 ;
} else {
block = block > > 3 ;
this_count = this_count > > 3 ;
}
}
if ( rq_data_dir ( rq ) = = WRITE ) {
if ( ! sdp - > writeable ) {
return 0 ;
}
SCpnt - > cmnd [ 0 ] = WRITE_6 ;
SCpnt - > sc_data_direction = DMA_TO_DEVICE ;
} else if ( rq_data_dir ( rq ) = = READ ) {
SCpnt - > cmnd [ 0 ] = READ_6 ;
SCpnt - > sc_data_direction = DMA_FROM_DEVICE ;
} else {
printk ( KERN_ERR " sd: Unknown command %lx \n " , rq - > flags ) ;
/* overkill panic("Unknown sd command %lx\n", rq->flags); */
return 0 ;
}
SCSI_LOG_HLQUEUE ( 2 , printk ( " %s : %s %d/%ld 512 byte blocks. \n " ,
disk - > disk_name , ( rq_data_dir ( rq ) = = WRITE ) ?
" writing " : " reading " , this_count , rq - > nr_sectors ) ) ;
SCpnt - > cmnd [ 1 ] = 0 ;
if ( block > 0xffffffff ) {
SCpnt - > cmnd [ 0 ] + = READ_16 - READ_6 ;
2006-01-06 11:53:52 +03:00
SCpnt - > cmnd [ 1 ] | = blk_fua_rq ( rq ) ? 0x8 : 0 ;
2005-04-17 02:20:36 +04:00
SCpnt - > cmnd [ 2 ] = sizeof ( block ) > 4 ? ( unsigned char ) ( block > > 56 ) & 0xff : 0 ;
SCpnt - > cmnd [ 3 ] = sizeof ( block ) > 4 ? ( unsigned char ) ( block > > 48 ) & 0xff : 0 ;
SCpnt - > cmnd [ 4 ] = sizeof ( block ) > 4 ? ( unsigned char ) ( block > > 40 ) & 0xff : 0 ;
SCpnt - > cmnd [ 5 ] = sizeof ( block ) > 4 ? ( unsigned char ) ( block > > 32 ) & 0xff : 0 ;
SCpnt - > cmnd [ 6 ] = ( unsigned char ) ( block > > 24 ) & 0xff ;
SCpnt - > cmnd [ 7 ] = ( unsigned char ) ( block > > 16 ) & 0xff ;
SCpnt - > cmnd [ 8 ] = ( unsigned char ) ( block > > 8 ) & 0xff ;
SCpnt - > cmnd [ 9 ] = ( unsigned char ) block & 0xff ;
SCpnt - > cmnd [ 10 ] = ( unsigned char ) ( this_count > > 24 ) & 0xff ;
SCpnt - > cmnd [ 11 ] = ( unsigned char ) ( this_count > > 16 ) & 0xff ;
SCpnt - > cmnd [ 12 ] = ( unsigned char ) ( this_count > > 8 ) & 0xff ;
SCpnt - > cmnd [ 13 ] = ( unsigned char ) this_count & 0xff ;
SCpnt - > cmnd [ 14 ] = SCpnt - > cmnd [ 15 ] = 0 ;
} else if ( ( this_count > 0xff ) | | ( block > 0x1fffff ) | |
SCpnt - > device - > use_10_for_rw ) {
if ( this_count > 0xffff )
this_count = 0xffff ;
SCpnt - > cmnd [ 0 ] + = READ_10 - READ_6 ;
2006-01-06 11:53:52 +03:00
SCpnt - > cmnd [ 1 ] | = blk_fua_rq ( rq ) ? 0x8 : 0 ;
2005-04-17 02:20:36 +04:00
SCpnt - > cmnd [ 2 ] = ( unsigned char ) ( block > > 24 ) & 0xff ;
SCpnt - > cmnd [ 3 ] = ( unsigned char ) ( block > > 16 ) & 0xff ;
SCpnt - > cmnd [ 4 ] = ( unsigned char ) ( block > > 8 ) & 0xff ;
SCpnt - > cmnd [ 5 ] = ( unsigned char ) block & 0xff ;
SCpnt - > cmnd [ 6 ] = SCpnt - > cmnd [ 9 ] = 0 ;
SCpnt - > cmnd [ 7 ] = ( unsigned char ) ( this_count > > 8 ) & 0xff ;
SCpnt - > cmnd [ 8 ] = ( unsigned char ) this_count & 0xff ;
} else {
2006-01-06 11:53:52 +03:00
if ( unlikely ( blk_fua_rq ( rq ) ) ) {
/*
* This happens only if this drive failed
* 10 byte rw command with ILLEGAL_REQUEST
* during operation and thus turned off
* use_10_for_rw .
*/
printk ( KERN_ERR " sd: FUA write on READ/WRITE(6) drive \n " ) ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
SCpnt - > cmnd [ 1 ] | = ( unsigned char ) ( ( block > > 16 ) & 0x1f ) ;
SCpnt - > cmnd [ 2 ] = ( unsigned char ) ( ( block > > 8 ) & 0xff ) ;
SCpnt - > cmnd [ 3 ] = ( unsigned char ) block & 0xff ;
SCpnt - > cmnd [ 4 ] = ( unsigned char ) this_count ;
SCpnt - > cmnd [ 5 ] = 0 ;
}
2006-07-08 22:42:15 +04:00
SCpnt - > request_bufflen = this_count * sdp - > sector_size ;
2005-04-17 02:20:36 +04:00
/*
* We shouldn ' t disconnect in the middle of a sector , so with a dumb
* host adapter , it ' s safe to assume that we can at least transfer
* this many bytes between each connect / disconnect .
*/
SCpnt - > transfersize = sdp - > sector_size ;
SCpnt - > underflow = this_count < < 9 ;
SCpnt - > allowed = SD_MAX_RETRIES ;
SCpnt - > timeout_per_command = timeout ;
/*
* This is the completion routine we use . This is matched in terms
* of capability to this function .
*/
SCpnt - > done = sd_rw_intr ;
/*
* This indicates that the command is ready from our end to be
* queued .
*/
return 1 ;
}
/**
* sd_open - open a scsi disk device
* @ inode : only i_rdev member may be used
* @ filp : only f_mode and f_flags may be used
*
* Returns 0 if successful . Returns a negated errno value in case
* of error .
*
* Note : This can be called from a user context ( e . g . fsck ( 1 ) )
* or from within the kernel ( e . g . as a result of a mount ( 1 ) ) .
* In the latter case @ inode and @ filp carry an abridged amount
* of information as noted above .
* */
static int sd_open ( struct inode * inode , struct file * filp )
{
struct gendisk * disk = inode - > i_bdev - > bd_disk ;
struct scsi_disk * sdkp ;
struct scsi_device * sdev ;
int retval ;
if ( ! ( sdkp = scsi_disk_get ( disk ) ) )
return - ENXIO ;
SCSI_LOG_HLQUEUE ( 3 , printk ( " sd_open: disk=%s \n " , disk - > disk_name ) ) ;
sdev = sdkp - > device ;
/*
* If the device is in error recovery , wait until it is done .
* If the device is offline , then disallow any access to it .
*/
retval = - ENXIO ;
if ( ! scsi_block_when_processing_errors ( sdev ) )
goto error_out ;
if ( sdev - > removable | | sdkp - > write_prot )
check_disk_change ( inode - > i_bdev ) ;
/*
* If the drive is empty , just let the open fail .
*/
retval = - ENOMEDIUM ;
if ( sdev - > removable & & ! sdkp - > media_present & &
! ( filp - > f_flags & O_NDELAY ) )
goto error_out ;
/*
* If the device has the write protect tab set , have the open fail
* if the user expects to be able to write to the thing .
*/
retval = - EROFS ;
if ( sdkp - > write_prot & & ( filp - > f_mode & FMODE_WRITE ) )
goto error_out ;
/*
* It is possible that the disk changing stuff resulted in
* the device being taken offline . If this is the case ,
* report this to the user , and don ' t pretend that the
* open actually succeeded .
*/
retval = - ENXIO ;
if ( ! scsi_device_online ( sdev ) )
goto error_out ;
if ( ! sdkp - > openers + + & & sdev - > removable ) {
if ( scsi_block_when_processing_errors ( sdev ) )
scsi_set_medium_removal ( sdev , SCSI_REMOVAL_PREVENT ) ;
}
return 0 ;
error_out :
scsi_disk_put ( sdkp ) ;
return retval ;
}
/**
* sd_release - invoked when the ( last ) close ( 2 ) is called on this
* scsi disk .
* @ inode : only i_rdev member may be used
* @ filp : only f_mode and f_flags may be used
*
* Returns 0.
*
* Note : may block ( uninterruptible ) if error recovery is underway
* on this disk .
* */
static int sd_release ( struct inode * inode , struct file * filp )
{
struct gendisk * disk = inode - > i_bdev - > bd_disk ;
struct scsi_disk * sdkp = scsi_disk ( disk ) ;
struct scsi_device * sdev = sdkp - > device ;
SCSI_LOG_HLQUEUE ( 3 , printk ( " sd_release: disk=%s \n " , disk - > disk_name ) ) ;
if ( ! - - sdkp - > openers & & sdev - > removable ) {
if ( scsi_block_when_processing_errors ( sdev ) )
scsi_set_medium_removal ( sdev , SCSI_REMOVAL_ALLOW ) ;
}
/*
* XXX and what if there are packets in flight and this close ( )
* XXX is followed by a " rmmod sd_mod " ?
*/
scsi_disk_put ( sdkp ) ;
return 0 ;
}
2006-01-08 12:02:50 +03:00
static int sd_getgeo ( struct block_device * bdev , struct hd_geometry * geo )
2005-04-17 02:20:36 +04:00
{
struct scsi_disk * sdkp = scsi_disk ( bdev - > bd_disk ) ;
struct scsi_device * sdp = sdkp - > device ;
struct Scsi_Host * host = sdp - > host ;
int diskinfo [ 4 ] ;
/* default to most commonly used values */
diskinfo [ 0 ] = 0x40 ; /* 1 << 6 */
diskinfo [ 1 ] = 0x20 ; /* 1 << 5 */
diskinfo [ 2 ] = sdkp - > capacity > > 11 ;
/* override with calculated, extended default, or driver values */
if ( host - > hostt - > bios_param )
host - > hostt - > bios_param ( sdp , bdev , sdkp - > capacity , diskinfo ) ;
else
scsicam_bios_param ( bdev , sdkp - > capacity , diskinfo ) ;
2006-01-08 12:02:50 +03:00
geo - > heads = diskinfo [ 0 ] ;
geo - > sectors = diskinfo [ 1 ] ;
geo - > cylinders = diskinfo [ 2 ] ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/**
* sd_ioctl - process an ioctl
* @ inode : only i_rdev / i_bdev members may be used
* @ filp : only f_mode and f_flags may be used
* @ cmd : ioctl command number
* @ arg : this is third argument given to ioctl ( 2 ) system call .
* Often contains a pointer .
*
* Returns 0 if successful ( some ioctls return postive numbers on
* success as well ) . Returns a negated errno value in case of error .
*
* Note : most ioctls are forward onto the block subsystem or further
* down in the scsi subsytem .
* */
static int sd_ioctl ( struct inode * inode , struct file * filp ,
unsigned int cmd , unsigned long arg )
{
struct block_device * bdev = inode - > i_bdev ;
struct gendisk * disk = bdev - > bd_disk ;
struct scsi_device * sdp = scsi_disk ( disk ) - > device ;
void __user * p = ( void __user * ) arg ;
int error ;
SCSI_LOG_IOCTL ( 1 , printk ( " sd_ioctl: disk=%s, cmd=0x%x \n " ,
disk - > disk_name , cmd ) ) ;
/*
* If we are in the middle of error recovery , don ' t let anyone
* else try and use this device . Also , if error recovery fails , it
* may try and take the device offline , in which case all further
* access to the device is prohibited .
*/
error = scsi_nonblockable_ioctl ( sdp , cmd , p , filp ) ;
if ( ! scsi_block_when_processing_errors ( sdp ) | | ! error )
return error ;
/*
* Send SCSI addressing ioctls directly to mid level , send other
* ioctls to block level and then onto mid level if they can ' t be
* resolved .
*/
switch ( cmd ) {
case SCSI_IOCTL_GET_IDLUN :
case SCSI_IOCTL_GET_BUS_NUMBER :
return scsi_ioctl ( sdp , cmd , p ) ;
default :
error = scsi_cmd_ioctl ( filp , disk , cmd , p ) ;
if ( error ! = - ENOTTY )
return error ;
}
return scsi_ioctl ( sdp , cmd , p ) ;
}
static void set_media_not_present ( struct scsi_disk * sdkp )
{
sdkp - > media_present = 0 ;
sdkp - > capacity = 0 ;
sdkp - > device - > changed = 1 ;
}
/**
* sd_media_changed - check if our medium changed
* @ disk : kernel device descriptor
*
* Returns 0 if not applicable or no change ; 1 if change
*
* Note : this function is invoked from the block subsystem .
* */
static int sd_media_changed ( struct gendisk * disk )
{
struct scsi_disk * sdkp = scsi_disk ( disk ) ;
struct scsi_device * sdp = sdkp - > device ;
int retval ;
SCSI_LOG_HLQUEUE ( 3 , printk ( " sd_media_changed: disk=%s \n " ,
disk - > disk_name ) ) ;
if ( ! sdp - > removable )
return 0 ;
/*
* If the device is offline , don ' t send any commands - just pretend as
* if the command failed . If the device ever comes back online , we
* can deal with it then . It is only because of unrecoverable errors
* that we would ever take a device offline in the first place .
*/
if ( ! scsi_device_online ( sdp ) )
goto not_present ;
/*
* Using TEST_UNIT_READY enables differentiation between drive with
* no cartridge loaded - NOT READY , drive with changed cartridge -
* UNIT ATTENTION , or with same cartridge - GOOD STATUS .
*
* Drives that auto spin down . eg iomega jaz 1 G , will be started
* by sd_spinup_disk ( ) from sd_revalidate_disk ( ) , which happens whenever
* sd_revalidate ( ) is called .
*/
retval = - ENODEV ;
if ( scsi_block_when_processing_errors ( sdp ) )
retval = scsi_test_unit_ready ( sdp , SD_TIMEOUT , SD_MAX_RETRIES ) ;
/*
* Unable to test , unit probably not ready . This usually
* means there is no disc in the drive . Mark as changed ,
* and we will figure it out later once the drive is
* available again .
*/
if ( retval )
goto not_present ;
/*
* For removable scsi disk we have to recognise the presence
* of a disk in the drive . This is kept in the struct scsi_disk
* struct and tested at open ! Daniel Roche ( dan @ lectra . fr )
*/
sdkp - > media_present = 1 ;
retval = sdp - > changed ;
sdp - > changed = 0 ;
return retval ;
not_present :
set_media_not_present ( sdkp ) ;
return 1 ;
}
static int sd_sync_cache ( struct scsi_device * sdp )
{
int retries , res ;
2005-08-28 20:33:52 +04:00
struct scsi_sense_hdr sshdr ;
2005-04-17 02:20:36 +04:00
if ( ! scsi_device_online ( sdp ) )
return - ENODEV ;
for ( retries = 3 ; retries > 0 ; - - retries ) {
unsigned char cmd [ 10 ] = { 0 } ;
cmd [ 0 ] = SYNCHRONIZE_CACHE ;
/*
* Leave the rest of the command zero to indicate
* flush everything .
*/
2005-08-28 20:33:52 +04:00
res = scsi_execute_req ( sdp , cmd , DMA_NONE , NULL , 0 , & sshdr ,
SD_TIMEOUT , SD_MAX_RETRIES ) ;
if ( res = = 0 )
2005-04-17 02:20:36 +04:00
break ;
}
2005-08-28 20:33:52 +04:00
if ( res ) { printk ( KERN_WARNING " FAILED \n status = %x, message = %02x, "
2005-04-17 02:20:36 +04:00
" host = %d, driver = %02x \n " ,
status_byte ( res ) , msg_byte ( res ) ,
host_byte ( res ) , driver_byte ( res ) ) ;
if ( driver_byte ( res ) & DRIVER_SENSE )
2005-08-28 20:33:52 +04:00
scsi_print_sense_hdr ( " sd " , & sshdr ) ;
2005-04-17 02:20:36 +04:00
}
return res ;
}
static int sd_issue_flush ( struct device * dev , sector_t * error_sector )
{
2005-11-04 22:44:41 +03:00
int ret = 0 ;
2005-04-17 02:20:36 +04:00
struct scsi_device * sdp = to_scsi_device ( dev ) ;
2005-11-04 22:44:41 +03:00
struct scsi_disk * sdkp = scsi_disk_get_from_dev ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( ! sdkp )
return - ENODEV ;
2005-11-04 22:44:41 +03:00
if ( sdkp - > WCE )
ret = sd_sync_cache ( sdp ) ;
scsi_disk_put ( sdkp ) ;
return ret ;
2005-04-17 02:20:36 +04:00
}
2006-01-06 11:52:55 +03:00
static void sd_prepare_flush ( request_queue_t * q , struct request * rq )
2005-04-17 02:20:36 +04:00
{
2005-11-08 17:21:07 +03:00
memset ( rq - > cmd , 0 , sizeof ( rq - > cmd ) ) ;
2006-01-06 11:52:55 +03:00
rq - > flags | = REQ_BLOCK_PC ;
2005-11-08 17:21:07 +03:00
rq - > timeout = SD_TIMEOUT ;
rq - > cmd [ 0 ] = SYNCHRONIZE_CACHE ;
2006-01-06 11:52:55 +03:00
rq - > cmd_len = 10 ;
2005-04-17 02:20:36 +04:00
}
static void sd_rescan ( struct device * dev )
{
2005-11-04 22:44:41 +03:00
struct scsi_disk * sdkp = scsi_disk_get_from_dev ( dev ) ;
if ( sdkp ) {
sd_revalidate_disk ( sdkp - > disk ) ;
scsi_disk_put ( sdkp ) ;
}
2005-04-17 02:20:36 +04:00
}
# ifdef CONFIG_COMPAT
/*
* This gets directly called from VFS . When the ioctl
* is not recognized we go back to the other translation paths .
*/
static long sd_compat_ioctl ( struct file * file , unsigned int cmd , unsigned long arg )
{
struct block_device * bdev = file - > f_dentry - > d_inode - > i_bdev ;
struct gendisk * disk = bdev - > bd_disk ;
struct scsi_device * sdev = scsi_disk ( disk ) - > device ;
/*
* If we are in the middle of error recovery , don ' t let anyone
* else try and use this device . Also , if error recovery fails , it
* may try and take the device offline , in which case all further
* access to the device is prohibited .
*/
if ( ! scsi_block_when_processing_errors ( sdev ) )
return - ENODEV ;
if ( sdev - > host - > hostt - > compat_ioctl ) {
int ret ;
ret = sdev - > host - > hostt - > compat_ioctl ( sdev , cmd , ( void __user * ) arg ) ;
return ret ;
}
/*
* Let the static ioctl translation table take care of it .
*/
return - ENOIOCTLCMD ;
}
# endif
static struct block_device_operations sd_fops = {
. owner = THIS_MODULE ,
. open = sd_open ,
. release = sd_release ,
. ioctl = sd_ioctl ,
2006-01-08 12:02:50 +03:00
. getgeo = sd_getgeo ,
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_COMPAT
. compat_ioctl = sd_compat_ioctl ,
# endif
. media_changed = sd_media_changed ,
. revalidate_disk = sd_revalidate_disk ,
} ;
/**
* sd_rw_intr - bottom half handler : called when the lower level
* driver has completed ( successfully or otherwise ) a scsi command .
* @ SCpnt : mid - level ' s per command structure .
*
* Note : potentially run from within an ISR . Must not block .
* */
static void sd_rw_intr ( struct scsi_cmnd * SCpnt )
{
int result = SCpnt - > result ;
2006-06-23 20:39:09 +04:00
unsigned int xfer_size = SCpnt - > request_bufflen ;
unsigned int good_bytes = result ? 0 : xfer_size ;
u64 start_lba = SCpnt - > request - > sector ;
u64 bad_lba ;
2005-04-17 02:20:36 +04:00
struct scsi_sense_hdr sshdr ;
int sense_valid = 0 ;
int sense_deferred = 0 ;
int info_valid ;
if ( result ) {
sense_valid = scsi_command_normalize_sense ( SCpnt , & sshdr ) ;
if ( sense_valid )
sense_deferred = scsi_sense_is_deferred ( & sshdr ) ;
}
# ifdef CONFIG_SCSI_LOGGING
SCSI_LOG_HLCOMPLETE ( 1 , printk ( " sd_rw_intr: %s: res=0x%x \n " ,
SCpnt - > request - > rq_disk - > disk_name , result ) ) ;
if ( sense_valid ) {
SCSI_LOG_HLCOMPLETE ( 1 , printk ( " sd_rw_intr: sb[respc,sk,asc, "
" ascq]=%x,%x,%x,%x \n " , sshdr . response_code ,
sshdr . sense_key , sshdr . asc , sshdr . ascq ) ) ;
}
# endif
2006-06-23 20:39:09 +04:00
if ( driver_byte ( result ) ! = DRIVER_SENSE & &
( ! sense_valid | | sense_deferred ) )
goto out ;
switch ( sshdr . sense_key ) {
case HARDWARE_ERROR :
case MEDIUM_ERROR :
if ( ! blk_fs_request ( SCpnt - > request ) )
goto out ;
info_valid = scsi_get_sense_info_fld ( SCpnt - > sense_buffer ,
SCSI_SENSE_BUFFERSIZE ,
& bad_lba ) ;
if ( ! info_valid )
goto out ;
if ( xfer_size < = SCpnt - > device - > sector_size )
goto out ;
switch ( SCpnt - > device - > sector_size ) {
case 256 :
start_lba < < = 1 ;
2005-04-17 02:20:36 +04:00
break ;
2006-06-23 20:39:09 +04:00
case 512 :
2005-04-17 02:20:36 +04:00
break ;
2006-06-23 20:39:09 +04:00
case 1024 :
start_lba > > = 1 ;
break ;
case 2048 :
start_lba > > = 2 ;
break ;
case 4096 :
start_lba > > = 3 ;
2005-04-17 02:20:36 +04:00
break ;
default :
2006-06-23 20:39:09 +04:00
/* Print something here with limiting frequency. */
goto out ;
2005-04-17 02:20:36 +04:00
break ;
}
2006-06-23 20:39:09 +04:00
/* This computation should always be done in terms of
* the resolution of the device ' s medium .
*/
good_bytes = ( bad_lba - start_lba ) * SCpnt - > device - > sector_size ;
break ;
case RECOVERED_ERROR :
case NO_SENSE :
/* Inform the user, but make sure that it's not treated
* as a hard error .
*/
scsi_print_sense ( " sd " , SCpnt ) ;
SCpnt - > result = 0 ;
memset ( SCpnt - > sense_buffer , 0 , SCSI_SENSE_BUFFERSIZE ) ;
good_bytes = xfer_size ;
break ;
case ILLEGAL_REQUEST :
if ( SCpnt - > device - > use_10_for_rw & &
( SCpnt - > cmnd [ 0 ] = = READ_10 | |
SCpnt - > cmnd [ 0 ] = = WRITE_10 ) )
SCpnt - > device - > use_10_for_rw = 0 ;
if ( SCpnt - > device - > use_10_for_ms & &
( SCpnt - > cmnd [ 0 ] = = MODE_SENSE_10 | |
SCpnt - > cmnd [ 0 ] = = MODE_SELECT_10 ) )
SCpnt - > device - > use_10_for_ms = 0 ;
break ;
default :
break ;
2005-04-17 02:20:36 +04:00
}
2006-06-23 20:39:09 +04:00
out :
scsi_io_completion ( SCpnt , good_bytes ) ;
2005-04-17 02:20:36 +04:00
}
2005-08-28 20:33:52 +04:00
static int media_not_present ( struct scsi_disk * sdkp ,
struct scsi_sense_hdr * sshdr )
2005-04-17 02:20:36 +04:00
{
2005-08-28 20:33:52 +04:00
if ( ! scsi_sense_valid ( sshdr ) )
2005-04-17 02:20:36 +04:00
return 0 ;
/* not invoked for commands that could return deferred errors */
2005-08-28 20:33:52 +04:00
if ( sshdr - > sense_key ! = NOT_READY & &
sshdr - > sense_key ! = UNIT_ATTENTION )
return 0 ;
if ( sshdr - > asc ! = 0x3A ) /* medium not present */
return 0 ;
2005-04-17 02:20:36 +04:00
set_media_not_present ( sdkp ) ;
return 1 ;
}
/*
* spinup disk - called only in sd_revalidate_disk ( )
*/
static void
2005-08-28 20:33:52 +04:00
sd_spinup_disk ( struct scsi_disk * sdkp , char * diskname )
{
2005-04-17 02:20:36 +04:00
unsigned char cmd [ 10 ] ;
2005-07-12 18:45:17 +04:00
unsigned long spintime_expire = 0 ;
2005-04-17 02:20:36 +04:00
int retries , spintime ;
unsigned int the_result ;
struct scsi_sense_hdr sshdr ;
int sense_valid = 0 ;
spintime = 0 ;
/* Spin up drives, as required. Only do this at boot time */
/* Spinup needs to be done for module loads too. */
do {
retries = 0 ;
do {
cmd [ 0 ] = TEST_UNIT_READY ;
memset ( ( void * ) & cmd [ 1 ] , 0 , 9 ) ;
2005-08-28 20:33:52 +04:00
the_result = scsi_execute_req ( sdkp - > device , cmd ,
DMA_NONE , NULL , 0 ,
& sshdr , SD_TIMEOUT ,
SD_MAX_RETRIES ) ;
2005-04-17 02:20:36 +04:00
if ( the_result )
2005-08-28 20:33:52 +04:00
sense_valid = scsi_sense_valid ( & sshdr ) ;
2005-04-17 02:20:36 +04:00
retries + + ;
} while ( retries < 3 & &
( ! scsi_status_is_good ( the_result ) | |
( ( driver_byte ( the_result ) & DRIVER_SENSE ) & &
sense_valid & & sshdr . sense_key = = UNIT_ATTENTION ) ) ) ;
/*
* If the drive has indicated to us that it doesn ' t have
* any media in it , don ' t bother with any of the rest of
* this crap .
*/
2005-08-28 20:33:52 +04:00
if ( media_not_present ( sdkp , & sshdr ) )
2005-04-17 02:20:36 +04:00
return ;
if ( ( driver_byte ( the_result ) & DRIVER_SENSE ) = = 0 ) {
/* no sense, TUR either succeeded or failed
* with a status error */
if ( ! spintime & & ! scsi_status_is_good ( the_result ) )
printk ( KERN_NOTICE " %s: Unit Not Ready, "
" error = 0x%x \n " , diskname , the_result ) ;
break ;
}
/*
* The device does not want the automatic start to be issued .
*/
if ( sdkp - > device - > no_start_on_add ) {
break ;
}
/*
* If manual intervention is required , or this is an
* absent USB storage device , a spinup is meaningless .
*/
if ( sense_valid & &
sshdr . sense_key = = NOT_READY & &
sshdr . asc = = 4 & & sshdr . ascq = = 3 ) {
break ; /* manual intervention required */
/*
* Issue command to spin up drive when not ready
*/
} else if ( sense_valid & & sshdr . sense_key = = NOT_READY ) {
if ( ! spintime ) {
printk ( KERN_NOTICE " %s: Spinning up disk... " ,
diskname ) ;
cmd [ 0 ] = START_STOP ;
cmd [ 1 ] = 1 ; /* Return immediately */
memset ( ( void * ) & cmd [ 2 ] , 0 , 8 ) ;
cmd [ 4 ] = 1 ; /* Start spin cycle */
2005-08-28 20:33:52 +04:00
scsi_execute_req ( sdkp - > device , cmd , DMA_NONE ,
NULL , 0 , & sshdr ,
SD_TIMEOUT , SD_MAX_RETRIES ) ;
2005-07-12 18:45:17 +04:00
spintime_expire = jiffies + 100 * HZ ;
spintime = 1 ;
2005-04-17 02:20:36 +04:00
}
/* Wait 1 second for next try */
msleep ( 1000 ) ;
printk ( " . " ) ;
2005-07-12 18:45:17 +04:00
/*
* Wait for USB flash devices with slow firmware .
* Yes , this sense key / ASC combination shouldn ' t
* occur here . It ' s characteristic of these devices .
*/
} else if ( sense_valid & &
sshdr . sense_key = = UNIT_ATTENTION & &
sshdr . asc = = 0x28 ) {
if ( ! spintime ) {
spintime_expire = jiffies + 5 * HZ ;
spintime = 1 ;
}
/* Wait 1 second for next try */
msleep ( 1000 ) ;
2005-04-17 02:20:36 +04:00
} else {
/* we don't understand the sense code, so it's
* probably pointless to loop */
if ( ! spintime ) {
printk ( KERN_NOTICE " %s: Unit Not Ready, "
" sense: \n " , diskname ) ;
2005-08-28 20:33:52 +04:00
scsi_print_sense_hdr ( " " , & sshdr ) ;
2005-04-17 02:20:36 +04:00
}
break ;
}
2005-07-12 18:45:17 +04:00
} while ( spintime & & time_before_eq ( jiffies , spintime_expire ) ) ;
2005-04-17 02:20:36 +04:00
if ( spintime ) {
if ( scsi_status_is_good ( the_result ) )
printk ( " ready \n " ) ;
else
printk ( " not responding... \n " ) ;
}
}
/*
* read disk capacity
*/
static void
sd_read_capacity ( struct scsi_disk * sdkp , char * diskname ,
2005-08-28 20:33:52 +04:00
unsigned char * buffer )
{
2005-04-17 02:20:36 +04:00
unsigned char cmd [ 16 ] ;
int the_result , retries ;
int sector_size = 0 ;
int longrc = 0 ;
struct scsi_sense_hdr sshdr ;
int sense_valid = 0 ;
2005-08-28 20:33:52 +04:00
struct scsi_device * sdp = sdkp - > device ;
2005-04-17 02:20:36 +04:00
repeat :
retries = 3 ;
do {
if ( longrc ) {
memset ( ( void * ) cmd , 0 , 16 ) ;
cmd [ 0 ] = SERVICE_ACTION_IN ;
cmd [ 1 ] = SAI_READ_CAPACITY_16 ;
cmd [ 13 ] = 12 ;
memset ( ( void * ) buffer , 0 , 12 ) ;
} else {
cmd [ 0 ] = READ_CAPACITY ;
memset ( ( void * ) & cmd [ 1 ] , 0 , 9 ) ;
memset ( ( void * ) buffer , 0 , 8 ) ;
}
2005-08-28 20:33:52 +04:00
the_result = scsi_execute_req ( sdp , cmd , DMA_FROM_DEVICE ,
buffer , longrc ? 12 : 8 , & sshdr ,
SD_TIMEOUT , SD_MAX_RETRIES ) ;
2005-04-17 02:20:36 +04:00
2005-08-28 20:33:52 +04:00
if ( media_not_present ( sdkp , & sshdr ) )
2005-04-17 02:20:36 +04:00
return ;
if ( the_result )
2005-08-28 20:33:52 +04:00
sense_valid = scsi_sense_valid ( & sshdr ) ;
2005-04-17 02:20:36 +04:00
retries - - ;
} while ( the_result & & retries ) ;
if ( the_result & & ! longrc ) {
printk ( KERN_NOTICE " %s : READ CAPACITY failed. \n "
" %s : status=%x, message=%02x, host=%d, driver=%02x \n " ,
diskname , diskname ,
status_byte ( the_result ) ,
msg_byte ( the_result ) ,
host_byte ( the_result ) ,
driver_byte ( the_result ) ) ;
if ( driver_byte ( the_result ) & DRIVER_SENSE )
2005-08-28 20:33:52 +04:00
scsi_print_sense_hdr ( " sd " , & sshdr ) ;
2005-04-17 02:20:36 +04:00
else
printk ( " %s : sense not available. \n " , diskname ) ;
/* Set dirty bit for removable devices if not ready -
* sometimes drives will not report this properly . */
if ( sdp - > removable & &
sense_valid & & sshdr . sense_key = = NOT_READY )
sdp - > changed = 1 ;
/* Either no media are present but the drive didn't tell us,
or they are present but the read capacity command fails */
/* sdkp->media_present = 0; -- not always correct */
2006-09-01 17:50:23 +04:00
sdkp - > capacity = 0 ; /* unknown mapped to zero - as usual */
2005-04-17 02:20:36 +04:00
return ;
} else if ( the_result & & longrc ) {
/* READ CAPACITY(16) has been failed */
printk ( KERN_NOTICE " %s : READ CAPACITY(16) failed. \n "
" %s : status=%x, message=%02x, host=%d, driver=%02x \n " ,
diskname , diskname ,
status_byte ( the_result ) ,
msg_byte ( the_result ) ,
host_byte ( the_result ) ,
driver_byte ( the_result ) ) ;
printk ( KERN_NOTICE " %s : use 0xffffffff as device size \n " ,
diskname ) ;
sdkp - > capacity = 1 + ( sector_t ) 0xffffffff ;
goto got_data ;
}
if ( ! longrc ) {
sector_size = ( buffer [ 4 ] < < 24 ) |
( buffer [ 5 ] < < 16 ) | ( buffer [ 6 ] < < 8 ) | buffer [ 7 ] ;
if ( buffer [ 0 ] = = 0xff & & buffer [ 1 ] = = 0xff & &
buffer [ 2 ] = = 0xff & & buffer [ 3 ] = = 0xff ) {
if ( sizeof ( sdkp - > capacity ) > 4 ) {
printk ( KERN_NOTICE " %s : very big device. try to use "
" READ CAPACITY(16). \n " , diskname ) ;
longrc = 1 ;
goto repeat ;
}
printk ( KERN_ERR " %s: too big for this kernel. Use a "
" kernel compiled with support for large block "
" devices. \n " , diskname ) ;
sdkp - > capacity = 0 ;
goto got_data ;
}
sdkp - > capacity = 1 + ( ( ( sector_t ) buffer [ 0 ] < < 24 ) |
( buffer [ 1 ] < < 16 ) |
( buffer [ 2 ] < < 8 ) |
buffer [ 3 ] ) ;
} else {
sdkp - > capacity = 1 + ( ( ( u64 ) buffer [ 0 ] < < 56 ) |
( ( u64 ) buffer [ 1 ] < < 48 ) |
( ( u64 ) buffer [ 2 ] < < 40 ) |
( ( u64 ) buffer [ 3 ] < < 32 ) |
( ( sector_t ) buffer [ 4 ] < < 24 ) |
( ( sector_t ) buffer [ 5 ] < < 16 ) |
( ( sector_t ) buffer [ 6 ] < < 8 ) |
( sector_t ) buffer [ 7 ] ) ;
sector_size = ( buffer [ 8 ] < < 24 ) |
( buffer [ 9 ] < < 16 ) | ( buffer [ 10 ] < < 8 ) | buffer [ 11 ] ;
}
/* Some devices return the total number of sectors, not the
* highest sector number . Make the necessary adjustment . */
if ( sdp - > fix_capacity )
- - sdkp - > capacity ;
got_data :
if ( sector_size = = 0 ) {
sector_size = 512 ;
printk ( KERN_NOTICE " %s : sector size 0 reported, "
" assuming 512. \n " , diskname ) ;
}
if ( sector_size ! = 512 & &
sector_size ! = 1024 & &
sector_size ! = 2048 & &
sector_size ! = 4096 & &
sector_size ! = 256 ) {
printk ( KERN_NOTICE " %s : unsupported sector size "
" %d. \n " , diskname , sector_size ) ;
/*
* The user might want to re - format the drive with
* a supported sectorsize . Once this happens , it
* would be relatively trivial to set the thing up .
* For this reason , we leave the thing in the table .
*/
sdkp - > capacity = 0 ;
/*
* set a bogus sector size so the normal read / write
* logic in the block layer will eventually refuse any
* request on this device without tripping over power
* of two sector size assumptions
*/
sector_size = 512 ;
}
{
/*
* The msdos fs needs to know the hardware sector size
* So I have created this table . See ll_rw_blk . c
* Jacques Gelinas ( Jacques @ solucorp . qc . ca )
*/
int hard_sector = sector_size ;
2005-10-28 22:17:30 +04:00
sector_t sz = ( sdkp - > capacity / 2 ) * ( hard_sector / 256 ) ;
2005-04-17 02:20:36 +04:00
request_queue_t * queue = sdp - > request_queue ;
2005-10-28 22:17:30 +04:00
sector_t mb = sz ;
2005-04-17 02:20:36 +04:00
blk_queue_hardsect_size ( queue , hard_sector ) ;
/* avoid 64-bit division on 32-bit platforms */
2005-10-28 22:17:30 +04:00
sector_div ( sz , 625 ) ;
2005-04-17 02:20:36 +04:00
mb - = sz - 974 ;
sector_div ( mb , 1950 ) ;
printk ( KERN_NOTICE " SCSI device %s: "
" %llu %d-byte hdwr sectors (%llu MB) \n " ,
diskname , ( unsigned long long ) sdkp - > capacity ,
hard_sector , ( unsigned long long ) mb ) ;
}
/* Rescale capacity to 512-byte units */
if ( sector_size = = 4096 )
sdkp - > capacity < < = 3 ;
else if ( sector_size = = 2048 )
sdkp - > capacity < < = 2 ;
else if ( sector_size = = 1024 )
sdkp - > capacity < < = 1 ;
else if ( sector_size = = 256 )
sdkp - > capacity > > = 1 ;
sdkp - > device - > sector_size = sector_size ;
}
/* called with buffer of length 512 */
static inline int
2005-08-28 20:33:52 +04:00
sd_do_mode_sense ( struct scsi_device * sdp , int dbd , int modepage ,
unsigned char * buffer , int len , struct scsi_mode_data * data ,
struct scsi_sense_hdr * sshdr )
2005-04-17 02:20:36 +04:00
{
2005-08-28 20:33:52 +04:00
return scsi_mode_sense ( sdp , dbd , modepage , buffer , len ,
2005-08-28 20:27:01 +04:00
SD_TIMEOUT , SD_MAX_RETRIES , data ,
2005-08-28 20:33:52 +04:00
sshdr ) ;
2005-04-17 02:20:36 +04:00
}
/*
* read write protect setting , if possible - called only in sd_revalidate_disk ( )
2006-02-26 17:34:10 +03:00
* called with buffer of length SD_BUF_SIZE
2005-04-17 02:20:36 +04:00
*/
static void
sd_read_write_protect_flag ( struct scsi_disk * sdkp , char * diskname ,
2005-08-28 20:33:52 +04:00
unsigned char * buffer )
{
2005-04-17 02:20:36 +04:00
int res ;
2005-08-28 20:33:52 +04:00
struct scsi_device * sdp = sdkp - > device ;
2005-04-17 02:20:36 +04:00
struct scsi_mode_data data ;
set_disk_ro ( sdkp - > disk , 0 ) ;
2005-08-28 20:33:52 +04:00
if ( sdp - > skip_ms_page_3f ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_NOTICE " %s: assuming Write Enabled \n " , diskname ) ;
return ;
}
2005-08-28 20:33:52 +04:00
if ( sdp - > use_192_bytes_for_3f ) {
res = sd_do_mode_sense ( sdp , 0 , 0x3F , buffer , 192 , & data , NULL ) ;
2005-04-17 02:20:36 +04:00
} else {
/*
* First attempt : ask for all pages ( 0x3F ) , but only 4 bytes .
* We have to start carefully : some devices hang if we ask
* for more than is available .
*/
2005-08-28 20:33:52 +04:00
res = sd_do_mode_sense ( sdp , 0 , 0x3F , buffer , 4 , & data , NULL ) ;
2005-04-17 02:20:36 +04:00
/*
* Second attempt : ask for page 0 When only page 0 is
* implemented , a request for page 3F may return Sense Key
* 5 : Illegal Request , Sense Code 24 : Invalid field in
* CDB .
*/
if ( ! scsi_status_is_good ( res ) )
2005-08-28 20:33:52 +04:00
res = sd_do_mode_sense ( sdp , 0 , 0 , buffer , 4 , & data , NULL ) ;
2005-04-17 02:20:36 +04:00
/*
* Third attempt : ask 255 bytes , as we did earlier .
*/
if ( ! scsi_status_is_good ( res ) )
2005-08-28 20:33:52 +04:00
res = sd_do_mode_sense ( sdp , 0 , 0x3F , buffer , 255 ,
& data , NULL ) ;
2005-04-17 02:20:36 +04:00
}
if ( ! scsi_status_is_good ( res ) ) {
printk ( KERN_WARNING
" %s: test WP failed, assume Write Enabled \n " , diskname ) ;
} else {
sdkp - > write_prot = ( ( data . device_specific & 0x80 ) ! = 0 ) ;
set_disk_ro ( sdkp - > disk , sdkp - > write_prot ) ;
printk ( KERN_NOTICE " %s: Write Protect is %s \n " , diskname ,
sdkp - > write_prot ? " on " : " off " ) ;
printk ( KERN_DEBUG " %s: Mode Sense: %02x %02x %02x %02x \n " ,
diskname , buffer [ 0 ] , buffer [ 1 ] , buffer [ 2 ] , buffer [ 3 ] ) ;
}
}
/*
* sd_read_cache_type - called only from sd_revalidate_disk ( )
2006-02-26 17:34:10 +03:00
* called with buffer of length SD_BUF_SIZE
2005-04-17 02:20:36 +04:00
*/
static void
sd_read_cache_type ( struct scsi_disk * sdkp , char * diskname ,
2005-08-28 20:33:52 +04:00
unsigned char * buffer )
2005-05-16 04:59:55 +04:00
{
2005-04-17 02:20:36 +04:00
int len = 0 , res ;
2005-08-28 20:33:52 +04:00
struct scsi_device * sdp = sdkp - > device ;
2005-04-17 02:20:36 +04:00
2005-05-16 04:59:55 +04:00
int dbd ;
int modepage ;
2005-04-17 02:20:36 +04:00
struct scsi_mode_data data ;
struct scsi_sense_hdr sshdr ;
2005-08-28 20:33:52 +04:00
if ( sdp - > skip_ms_page_8 )
2005-04-17 02:20:36 +04:00
goto defaults ;
2005-08-28 20:33:52 +04:00
if ( sdp - > type = = TYPE_RBC ) {
2005-05-16 04:59:55 +04:00
modepage = 6 ;
dbd = 8 ;
} else {
modepage = 8 ;
dbd = 0 ;
}
2005-04-17 02:20:36 +04:00
/* cautiously ask */
2005-08-28 20:33:52 +04:00
res = sd_do_mode_sense ( sdp , dbd , modepage , buffer , 4 , & data , & sshdr ) ;
2005-04-17 02:20:36 +04:00
if ( ! scsi_status_is_good ( res ) )
goto bad_sense ;
2006-02-23 04:03:16 +03:00
if ( ! data . header_length ) {
modepage = 6 ;
printk ( KERN_ERR " %s: missing header in MODE_SENSE response \n " ,
diskname ) ;
}
2005-04-17 02:20:36 +04:00
/* that went OK, now ask for the proper length */
len = data . length ;
/*
* We ' re only interested in the first three bytes , actually .
* But the data cache page is defined for the first 20.
*/
if ( len < 3 )
goto bad_sense ;
if ( len > 20 )
len = 20 ;
/* Take headers and block descriptors into account */
len + = data . header_length + data . block_descriptor_length ;
2006-02-26 17:34:10 +03:00
if ( len > SD_BUF_SIZE )
goto bad_sense ;
2005-04-17 02:20:36 +04:00
/* Get the data */
2005-08-28 20:33:52 +04:00
res = sd_do_mode_sense ( sdp , dbd , modepage , buffer , len , & data , & sshdr ) ;
2005-04-17 02:20:36 +04:00
if ( scsi_status_is_good ( res ) ) {
int ct = 0 ;
2005-05-16 04:59:55 +04:00
int offset = data . header_length + data . block_descriptor_length ;
2005-04-17 02:20:36 +04:00
2006-02-26 17:34:10 +03:00
if ( offset > = SD_BUF_SIZE - 2 ) {
printk ( KERN_ERR " %s: malformed MODE SENSE response " ,
diskname ) ;
goto defaults ;
}
2005-05-16 04:59:55 +04:00
if ( ( buffer [ offset ] & 0x3f ) ! = modepage ) {
printk ( KERN_ERR " %s: got wrong page \n " , diskname ) ;
goto defaults ;
}
if ( modepage = = 8 ) {
sdkp - > WCE = ( ( buffer [ offset + 2 ] & 0x04 ) ! = 0 ) ;
sdkp - > RCD = ( ( buffer [ offset + 2 ] & 0x01 ) ! = 0 ) ;
} else {
sdkp - > WCE = ( ( buffer [ offset + 2 ] & 0x01 ) = = 0 ) ;
sdkp - > RCD = 0 ;
}
2005-04-17 02:20:36 +04:00
2006-01-06 11:53:52 +03:00
sdkp - > DPOFUA = ( data . device_specific & 0x10 ) ! = 0 ;
if ( sdkp - > DPOFUA & & ! sdkp - > device - > use_10_for_rw ) {
printk ( KERN_NOTICE " SCSI device %s: uses "
" READ/WRITE(6), disabling FUA \n " , diskname ) ;
sdkp - > DPOFUA = 0 ;
}
2005-04-17 02:20:36 +04:00
ct = sdkp - > RCD + 2 * sdkp - > WCE ;
2006-01-06 11:53:52 +03:00
printk ( KERN_NOTICE " SCSI device %s: drive cache: %s%s \n " ,
2006-03-18 23:14:21 +03:00
diskname , sd_cache_types [ ct ] ,
2006-01-06 11:53:52 +03:00
sdkp - > DPOFUA ? " w/ FUA " : " " ) ;
2005-04-17 02:20:36 +04:00
return ;
}
bad_sense :
2005-08-28 20:33:52 +04:00
if ( scsi_sense_valid ( & sshdr ) & &
2005-04-17 02:20:36 +04:00
sshdr . sense_key = = ILLEGAL_REQUEST & &
sshdr . asc = = 0x24 & & sshdr . ascq = = 0x0 )
printk ( KERN_NOTICE " %s: cache data unavailable \n " ,
diskname ) ; /* Invalid field in CDB */
else
printk ( KERN_ERR " %s: asking for cache data failed \n " ,
diskname ) ;
defaults :
printk ( KERN_ERR " %s: assuming drive cache: write through \n " ,
diskname ) ;
sdkp - > WCE = 0 ;
sdkp - > RCD = 0 ;
2006-02-26 17:34:10 +03:00
sdkp - > DPOFUA = 0 ;
2005-04-17 02:20:36 +04:00
}
/**
* sd_revalidate_disk - called the first time a new disk is seen ,
* performs disk spin up , read_capacity , etc .
* @ disk : struct gendisk we care about
* */
static int sd_revalidate_disk ( struct gendisk * disk )
{
struct scsi_disk * sdkp = scsi_disk ( disk ) ;
struct scsi_device * sdp = sdkp - > device ;
unsigned char * buffer ;
2006-01-06 11:52:55 +03:00
unsigned ordered ;
2005-04-17 02:20:36 +04:00
SCSI_LOG_HLQUEUE ( 3 , printk ( " sd_revalidate_disk: disk=%s \n " , disk - > disk_name ) ) ;
/*
* If the device is offline , don ' t try and read capacity or any
* of the other niceties .
*/
if ( ! scsi_device_online ( sdp ) )
goto out ;
2006-02-26 17:34:10 +03:00
buffer = kmalloc ( SD_BUF_SIZE , GFP_KERNEL | __GFP_DMA ) ;
2005-04-17 02:20:36 +04:00
if ( ! buffer ) {
printk ( KERN_WARNING " (sd_revalidate_disk:) Memory allocation "
" failure. \n " ) ;
2005-08-28 20:33:52 +04:00
goto out ;
2005-04-17 02:20:36 +04:00
}
/* defaults, until the device tells us otherwise */
sdp - > sector_size = 512 ;
sdkp - > capacity = 0 ;
sdkp - > media_present = 1 ;
sdkp - > write_prot = 0 ;
sdkp - > WCE = 0 ;
sdkp - > RCD = 0 ;
2005-08-28 20:33:52 +04:00
sd_spinup_disk ( sdkp , disk - > disk_name ) ;
2005-04-17 02:20:36 +04:00
/*
* Without media there is no reason to ask ; moreover , some devices
* react badly if we do .
*/
if ( sdkp - > media_present ) {
2005-08-28 20:33:52 +04:00
sd_read_capacity ( sdkp , disk - > disk_name , buffer ) ;
2005-12-09 19:34:45 +03:00
sd_read_write_protect_flag ( sdkp , disk - > disk_name , buffer ) ;
2005-08-28 20:33:52 +04:00
sd_read_cache_type ( sdkp , disk - > disk_name , buffer ) ;
2005-04-17 02:20:36 +04:00
}
2006-01-06 11:52:55 +03:00
/*
* We now have all cache related info , determine how we deal
* with ordered requests . Note that as the current SCSI
* dispatch function can alter request order , we cannot use
* QUEUE_ORDERED_TAG_ * even when ordered tag is supported .
*/
if ( sdkp - > WCE )
2006-01-06 11:53:52 +03:00
ordered = sdkp - > DPOFUA
? QUEUE_ORDERED_DRAIN_FUA : QUEUE_ORDERED_DRAIN_FLUSH ;
2006-01-06 11:52:55 +03:00
else
ordered = QUEUE_ORDERED_DRAIN ;
blk_queue_ordered ( sdkp - > disk - > queue , ordered , sd_prepare_flush ) ;
2005-04-17 02:20:36 +04:00
set_capacity ( disk , sdkp - > capacity ) ;
kfree ( buffer ) ;
out :
return 0 ;
}
/**
* sd_probe - called during driver initialization and whenever a
* new scsi device is attached to the system . It is called once
* for each scsi device ( not just disks ) present .
* @ dev : pointer to device object
*
* Returns 0 if successful ( or not interested in this scsi device
* ( e . g . scanner ) ) ; 1 when there is an error .
*
* Note : this function is invoked from the scsi mid - level .
* This function sets up the mapping between a given
* < host , channel , id , lun > ( found in sdp ) and new device name
* ( e . g . / dev / sda ) . More precisely it is the block device major
* and minor number that is chosen here .
*
* Assume sd_attach is not re - entrant ( for time being )
* Also think about sd_attach ( ) and sd_remove ( ) running coincidentally .
* */
static int sd_probe ( struct device * dev )
{
struct scsi_device * sdp = to_scsi_device ( dev ) ;
struct scsi_disk * sdkp ;
struct gendisk * gd ;
u32 index ;
int error ;
error = - ENODEV ;
2005-05-16 04:59:55 +04:00
if ( sdp - > type ! = TYPE_DISK & & sdp - > type ! = TYPE_MOD & & sdp - > type ! = TYPE_RBC )
2005-04-17 02:20:36 +04:00
goto out ;
2005-10-02 20:45:08 +04:00
SCSI_LOG_HLQUEUE ( 3 , sdev_printk ( KERN_INFO , sdp ,
" sd_attach \n " ) ) ;
2005-04-17 02:20:36 +04:00
error = - ENOMEM ;
2006-01-16 18:31:18 +03:00
sdkp = kzalloc ( sizeof ( * sdkp ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! sdkp )
goto out ;
gd = alloc_disk ( 16 ) ;
if ( ! gd )
goto out_free ;
if ( ! idr_pre_get ( & sd_index_idr , GFP_KERNEL ) )
goto out_put ;
spin_lock ( & sd_index_lock ) ;
error = idr_get_new ( & sd_index_idr , NULL , & index ) ;
spin_unlock ( & sd_index_lock ) ;
if ( index > = SD_MAX_DISKS )
error = - EBUSY ;
if ( error )
goto out_put ;
2006-03-18 23:14:21 +03:00
class_device_initialize ( & sdkp - > cdev ) ;
sdkp - > cdev . dev = & sdp - > sdev_gendev ;
sdkp - > cdev . class = & sd_disk_class ;
strncpy ( sdkp - > cdev . class_id , sdp - > sdev_gendev . bus_id , BUS_ID_SIZE ) ;
if ( class_device_add ( & sdkp - > cdev ) )
goto out_put ;
2005-11-04 22:44:41 +03:00
get_device ( & sdp - > sdev_gendev ) ;
2006-03-18 23:14:21 +03:00
2005-04-17 02:20:36 +04:00
sdkp - > device = sdp ;
sdkp - > driver = & sd_template ;
sdkp - > disk = gd ;
sdkp - > index = index ;
sdkp - > openers = 0 ;
if ( ! sdp - > timeout ) {
2005-05-16 04:59:55 +04:00
if ( sdp - > type ! = TYPE_MOD )
2005-04-17 02:20:36 +04:00
sdp - > timeout = SD_TIMEOUT ;
else
sdp - > timeout = SD_MOD_TIMEOUT ;
}
gd - > major = sd_major ( ( index & 0xf0 ) > > 4 ) ;
gd - > first_minor = ( ( index & 0xf ) < < 4 ) | ( index & 0xfff00 ) ;
gd - > minors = 16 ;
gd - > fops = & sd_fops ;
if ( index < 26 ) {
sprintf ( gd - > disk_name , " sd%c " , ' a ' + index % 26 ) ;
} else if ( index < ( 26 + 1 ) * 26 ) {
sprintf ( gd - > disk_name , " sd%c%c " ,
' a ' + index / 26 - 1 , ' a ' + index % 26 ) ;
} else {
const unsigned int m1 = ( index / 26 - 1 ) / 26 - 1 ;
const unsigned int m2 = ( index / 26 - 1 ) % 26 ;
const unsigned int m3 = index % 26 ;
sprintf ( gd - > disk_name , " sd%c%c%c " ,
' a ' + m1 , ' a ' + m2 , ' a ' + m3 ) ;
}
gd - > private_data = & sdkp - > driver ;
2006-01-06 11:52:55 +03:00
gd - > queue = sdkp - > device - > request_queue ;
2005-04-17 02:20:36 +04:00
sd_revalidate_disk ( gd ) ;
gd - > driverfs_dev = & sdp - > sdev_gendev ;
gd - > flags = GENHD_FL_DRIVERFS ;
if ( sdp - > removable )
gd - > flags | = GENHD_FL_REMOVABLE ;
dev_set_drvdata ( dev , sdkp ) ;
add_disk ( gd ) ;
2005-10-02 20:45:08 +04:00
sdev_printk ( KERN_NOTICE , sdp , " Attached scsi %sdisk %s \n " ,
sdp - > removable ? " removable " : " " , gd - > disk_name ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
2006-03-18 23:14:21 +03:00
out_put :
2005-04-17 02:20:36 +04:00
put_disk ( gd ) ;
2006-03-18 23:14:21 +03:00
out_free :
2005-04-17 02:20:36 +04:00
kfree ( sdkp ) ;
2006-03-18 23:14:21 +03:00
out :
2005-04-17 02:20:36 +04:00
return error ;
}
/**
* sd_remove - called whenever a scsi disk ( previously recognized by
* sd_probe ) is detached from the system . It is called ( potentially
* multiple times ) during sd module unload .
* @ sdp : pointer to mid level scsi device object
*
* Note : this function is invoked from the scsi mid - level .
* This function potentially frees up a device name ( e . g . / dev / sdc )
* that could be re - used by a subsequent sd_probe ( ) .
* This function is not called when the built - in sd driver is " exit-ed " .
* */
static int sd_remove ( struct device * dev )
{
struct scsi_disk * sdkp = dev_get_drvdata ( dev ) ;
2006-03-18 23:14:21 +03:00
class_device_del ( & sdkp - > cdev ) ;
2005-04-17 02:20:36 +04:00
del_gendisk ( sdkp - > disk ) ;
sd_shutdown ( dev ) ;
2005-11-04 22:44:41 +03:00
2006-01-11 15:16:10 +03:00
mutex_lock ( & sd_ref_mutex ) ;
2005-11-04 22:44:41 +03:00
dev_set_drvdata ( dev , NULL ) ;
2006-03-18 23:14:21 +03:00
class_device_put ( & sdkp - > cdev ) ;
2006-01-11 15:16:10 +03:00
mutex_unlock ( & sd_ref_mutex ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/**
* scsi_disk_release - Called to free the scsi_disk structure
2006-03-18 23:14:21 +03:00
* @ cdev : pointer to embedded class device
2005-04-17 02:20:36 +04:00
*
2006-01-11 15:16:10 +03:00
* sd_ref_mutex must be held entering this routine . Because it is
2005-04-17 02:20:36 +04:00
* called on last put , you should always use the scsi_disk_get ( )
* scsi_disk_put ( ) helpers which manipulate the semaphore directly
2006-03-18 23:14:21 +03:00
* and never do a direct class_device_put ( ) .
2005-04-17 02:20:36 +04:00
* */
2006-03-18 23:14:21 +03:00
static void scsi_disk_release ( struct class_device * cdev )
2005-04-17 02:20:36 +04:00
{
2006-03-18 23:14:21 +03:00
struct scsi_disk * sdkp = to_scsi_disk ( cdev ) ;
2005-04-17 02:20:36 +04:00
struct gendisk * disk = sdkp - > disk ;
spin_lock ( & sd_index_lock ) ;
idr_remove ( & sd_index_idr , sdkp - > index ) ;
spin_unlock ( & sd_index_lock ) ;
disk - > private_data = NULL ;
put_disk ( disk ) ;
2005-11-04 22:44:41 +03:00
put_device ( & sdkp - > device - > sdev_gendev ) ;
2005-04-17 02:20:36 +04:00
kfree ( sdkp ) ;
}
/*
* Send a SYNCHRONIZE CACHE instruction down to the device through
* the normal SCSI command structure . Wait for the command to
* complete .
*/
static void sd_shutdown ( struct device * dev )
{
struct scsi_device * sdp = to_scsi_device ( dev ) ;
2005-11-04 22:44:41 +03:00
struct scsi_disk * sdkp = scsi_disk_get_from_dev ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( ! sdkp )
return ; /* this can happen */
2005-11-04 22:44:41 +03:00
if ( sdkp - > WCE ) {
printk ( KERN_NOTICE " Synchronizing SCSI cache for disk %s: \n " ,
sdkp - > disk - > disk_name ) ;
sd_sync_cache ( sdp ) ;
}
scsi_disk_put ( sdkp ) ;
}
2005-04-17 02:20:36 +04:00
/**
* init_sd - entry point for this driver ( both when built in or when
* a module ) .
*
* Note : this function registers this driver with the scsi mid - level .
* */
static int __init init_sd ( void )
{
2006-10-04 13:32:54 +04:00
int majors = 0 , i , err ;
2005-04-17 02:20:36 +04:00
SCSI_LOG_HLQUEUE ( 3 , printk ( " init_sd: sd driver entry point \n " ) ) ;
for ( i = 0 ; i < SD_MAJORS ; i + + )
if ( register_blkdev ( sd_major ( i ) , " sd " ) = = 0 )
majors + + ;
if ( ! majors )
return - ENODEV ;
2006-10-04 13:32:54 +04:00
err = class_register ( & sd_disk_class ) ;
if ( err )
goto err_out ;
2006-03-18 23:14:21 +03:00
2006-10-04 13:32:54 +04:00
err = scsi_register_driver ( & sd_template . gendrv ) ;
if ( err )
goto err_out_class ;
return 0 ;
err_out_class :
class_unregister ( & sd_disk_class ) ;
err_out :
for ( i = 0 ; i < SD_MAJORS ; i + + )
unregister_blkdev ( sd_major ( i ) , " sd " ) ;
return err ;
2005-04-17 02:20:36 +04:00
}
/**
* exit_sd - exit point for this driver ( when it is a module ) .
*
* Note : this function unregisters this driver from the scsi mid - level .
* */
static void __exit exit_sd ( void )
{
int i ;
SCSI_LOG_HLQUEUE ( 3 , printk ( " exit_sd: exiting sd driver \n " ) ) ;
scsi_unregister_driver ( & sd_template . gendrv ) ;
2006-10-04 13:32:54 +04:00
class_unregister ( & sd_disk_class ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < SD_MAJORS ; i + + )
unregister_blkdev ( sd_major ( i ) , " sd " ) ;
}
module_init ( init_sd ) ;
module_exit ( exit_sd ) ;