2005-04-17 02:20:36 +04:00
/*
2008-02-02 01:09:33 +03:00
* Copyright ( C ) 1994 - 1998 Linus Torvalds & authors ( see below )
* Copyright ( C ) 2005 , 2007 Bartlomiej Zolnierkiewicz
2005-04-17 02:20:36 +04:00
*/
/*
* Mostly written by Mark Lord < mlord @ pobox . com >
* and Gadi Oxman < gadio @ netvision . net . il >
* and Andre Hedrick < andre @ linux - ide . org >
*
* See linux / MAINTAINERS for address of current maintainer .
*
* This is the IDE probe module , as evolved from hd . c and ide . c .
*
2007-12-13 01:32:00 +03:00
* - - increase WAIT_PIDENTIFY to avoid CD - ROM locking at boot
* by Andrea Arcangeli
2005-04-17 02:20:36 +04:00
*/
# include <linux/module.h>
# include <linux/types.h>
# include <linux/string.h>
# include <linux/kernel.h>
# include <linux/timer.h>
# include <linux/mm.h>
# include <linux/interrupt.h>
# include <linux/major.h>
# include <linux/errno.h>
# include <linux/genhd.h>
# include <linux/slab.h>
# include <linux/delay.h>
# include <linux/ide.h>
# include <linux/spinlock.h>
# include <linux/kmod.h>
# include <linux/pci.h>
2007-10-23 11:29:58 +04:00
# include <linux/scatterlist.h>
2005-04-17 02:20:36 +04:00
# include <asm/byteorder.h>
# include <asm/irq.h>
# include <asm/uaccess.h>
# include <asm/io.h>
/**
* generic_id - add a generic drive id
* @ drive : drive to make an ID block for
*
* Add a fake id field to the drive we are passed . This allows
* use to skip a ton of NULL checks ( which people always miss )
* and make drive properties unconditional outside of this file
*/
static void generic_id ( ide_drive_t * drive )
{
drive - > id - > cyls = drive - > cyl ;
drive - > id - > heads = drive - > head ;
drive - > id - > sectors = drive - > sect ;
drive - > id - > cur_cyls = drive - > cyl ;
drive - > id - > cur_heads = drive - > head ;
drive - > id - > cur_sectors = drive - > sect ;
}
static void ide_disk_init_chs ( ide_drive_t * drive )
{
struct hd_driveid * id = drive - > id ;
/* Extract geometry if we did not already have one for the drive */
if ( ! drive - > cyl | | ! drive - > head | | ! drive - > sect ) {
drive - > cyl = drive - > bios_cyl = id - > cyls ;
drive - > head = drive - > bios_head = id - > heads ;
drive - > sect = drive - > bios_sect = id - > sectors ;
}
/* Handle logical geometry translation by the drive */
if ( ( id - > field_valid & 1 ) & & id - > cur_cyls & &
id - > cur_heads & & ( id - > cur_heads < = 16 ) & & id - > cur_sectors ) {
drive - > cyl = id - > cur_cyls ;
drive - > head = id - > cur_heads ;
drive - > sect = id - > cur_sectors ;
}
/* Use physical geometry if what we have still makes no sense */
if ( drive - > head > 16 & & id - > heads & & id - > heads < = 16 ) {
drive - > cyl = id - > cyls ;
drive - > head = id - > heads ;
drive - > sect = id - > sectors ;
}
}
static void ide_disk_init_mult_count ( ide_drive_t * drive )
{
struct hd_driveid * id = drive - > id ;
drive - > mult_count = 0 ;
if ( id - > max_multsect ) {
# ifdef CONFIG_IDEDISK_MULTI_MODE
id - > multsect = ( ( id - > max_multsect / 2 ) > 1 ) ? id - > max_multsect : 0 ;
id - > multsect_valid = id - > multsect ? 1 : 0 ;
2008-01-26 00:17:08 +03:00
drive - > mult_req = id - > multsect_valid ? id - > max_multsect : 0 ;
2005-04-17 02:20:36 +04:00
drive - > special . b . set_multmode = drive - > mult_req ? 1 : 0 ;
# else /* original, pre IDE-NFG, per request of AC */
2008-01-26 00:17:08 +03:00
drive - > mult_req = 0 ;
2005-04-17 02:20:36 +04:00
if ( drive - > mult_req > id - > max_multsect )
drive - > mult_req = id - > max_multsect ;
if ( drive - > mult_req | | ( ( id - > multsect_valid & 1 ) & & id - > multsect ) )
drive - > special . b . set_multmode = 1 ;
# endif
}
}
/**
* do_identify - identify a drive
* @ drive : drive to identify
* @ cmd : command used
*
* Called when we have issued a drive identify command to
* read and parse the results . This function is run with
* interrupts disabled .
*/
static inline void do_identify ( ide_drive_t * drive , u8 cmd )
{
ide_hwif_t * hwif = HWIF ( drive ) ;
int bswap = 1 ;
struct hd_driveid * id ;
id = drive - > id ;
/* read 512 bytes of id info */
hwif - > ata_input_data ( drive , id , SECTOR_WORDS ) ;
drive - > id_read = 1 ;
local_irq_enable ( ) ;
2008-02-02 01:09:28 +03:00
# ifdef DEBUG
printk ( KERN_INFO " %s: dumping identify data \n " , drive - > name ) ;
ide_dump_identify ( ( u8 * ) id ) ;
# endif
2005-04-17 02:20:36 +04:00
ide_fix_driveid ( id ) ;
2007-07-10 01:17:57 +04:00
# if defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA)
2005-04-17 02:20:36 +04:00
/*
* EATA SCSI controllers do a hardware ATA emulation :
* Ignore them if there is a driver for them available .
*/
if ( ( id - > model [ 0 ] = = ' P ' & & id - > model [ 1 ] = = ' M ' ) | |
( id - > model [ 0 ] = = ' S ' & & id - > model [ 1 ] = = ' K ' ) ) {
printk ( " %s: EATA SCSI HBA %.10s \n " , drive - > name , id - > model ) ;
goto err_misc ;
}
2007-07-10 01:17:57 +04:00
# endif /* CONFIG_SCSI_EATA || CONFIG_SCSI_EATA_PIO */
2005-04-17 02:20:36 +04:00
/*
* WIN_IDENTIFY returns little - endian info ,
* WIN_PIDENTIFY * usually * returns little - endian info .
*/
if ( cmd = = WIN_PIDENTIFY ) {
if ( ( id - > model [ 0 ] = = ' N ' & & id - > model [ 1 ] = = ' E ' ) /* NEC */
| | ( id - > model [ 0 ] = = ' F ' & & id - > model [ 1 ] = = ' X ' ) /* Mitsumi */
| | ( id - > model [ 0 ] = = ' P ' & & id - > model [ 1 ] = = ' i ' ) ) /* Pioneer */
/* Vertos drives may still be weird */
bswap ^ = 1 ;
}
ide_fixstring ( id - > model , sizeof ( id - > model ) , bswap ) ;
ide_fixstring ( id - > fw_rev , sizeof ( id - > fw_rev ) , bswap ) ;
ide_fixstring ( id - > serial_no , sizeof ( id - > serial_no ) , bswap ) ;
2007-11-05 23:42:25 +03:00
/* we depend on this a lot! */
id - > model [ sizeof ( id - > model ) - 1 ] = ' \0 ' ;
2005-04-17 02:20:36 +04:00
if ( strstr ( id - > model , " E X A B Y T E N E S T " ) )
goto err_misc ;
printk ( " %s: %s, " , drive - > name , id - > model ) ;
drive - > present = 1 ;
drive - > dead = 0 ;
/*
* Check for an ATAPI device
*/
if ( cmd = = WIN_PIDENTIFY ) {
u8 type = ( id - > config > > 8 ) & 0x1f ;
printk ( " ATAPI " ) ;
switch ( type ) {
case ide_floppy :
if ( ! strstr ( id - > model , " CD-ROM " ) ) {
if ( ! strstr ( id - > model , " oppy " ) & &
! strstr ( id - > model , " poyp " ) & &
! strstr ( id - > model , " ZIP " ) )
printk ( " cdrom or floppy?, assuming " ) ;
if ( drive - > media ! = ide_cdrom ) {
printk ( " FLOPPY " ) ;
drive - > removable = 1 ;
break ;
}
}
/* Early cdrom models used zero */
type = ide_cdrom ;
case ide_cdrom :
drive - > removable = 1 ;
# ifdef CONFIG_PPC
/* kludge for Apple PowerBook internal zip */
if ( ! strstr ( id - > model , " CD-ROM " ) & &
strstr ( id - > model , " ZIP " ) ) {
printk ( " FLOPPY " ) ;
type = ide_floppy ;
break ;
}
# endif
printk ( " CD/DVD-ROM " ) ;
break ;
case ide_tape :
printk ( " TAPE " ) ;
break ;
case ide_optical :
printk ( " OPTICAL " ) ;
drive - > removable = 1 ;
break ;
default :
printk ( " UNKNOWN (type %d) " , type ) ;
break ;
}
printk ( " drive \n " ) ;
drive - > media = type ;
/* an ATAPI device ignores DRDY */
drive - > ready_stat = 0 ;
return ;
}
/*
* Not an ATAPI device : looks like a " regular " hard disk
*/
2006-02-03 14:04:55 +03:00
/*
* 0x848a = CompactFlash device
* These are * not * removable in Linux definition of the term
*/
if ( ( id - > config ! = 0x848a ) & & ( id - > config & ( 1 < < 7 ) ) )
2005-04-17 02:20:36 +04:00
drive - > removable = 1 ;
drive - > media = ide_disk ;
2006-02-03 14:04:55 +03:00
printk ( " %s DISK drive \n " , ( id - > config = = 0x848a ) ? " CFA " : " ATA " ) ;
2008-01-26 00:17:13 +03:00
2005-04-17 02:20:36 +04:00
return ;
err_misc :
kfree ( id ) ;
drive - > present = 0 ;
return ;
}
/**
* actual_try_to_identify - send ata / atapi identify
* @ drive : drive to identify
* @ cmd : command to use
*
* try_to_identify ( ) sends an ATA ( PI ) IDENTIFY request to a drive
* and waits for a response . It also monitors irqs while this is
* happening , in hope of automatically determining which one is
* being used by the interface .
*
* Returns : 0 device was identified
* 1 device timed - out ( no response to identify request )
* 2 device aborted the command ( refused to identify itself )
*/
static int actual_try_to_identify ( ide_drive_t * drive , u8 cmd )
{
ide_hwif_t * hwif = HWIF ( drive ) ;
2008-02-06 04:57:51 +03:00
int use_altstatus = 0 , rc ;
2005-04-17 02:20:36 +04:00
unsigned long timeout ;
u8 s = 0 , a = 0 ;
/* take a deep breath */
msleep ( 50 ) ;
if ( IDE_CONTROL_REG ) {
2008-02-06 04:57:51 +03:00
a = ide_read_altstatus ( drive ) ;
s = ide_read_status ( drive ) ;
if ( ( a ^ s ) & ~ INDEX_STAT )
2005-04-17 02:20:36 +04:00
/* ancient Seagate drives, broken interfaces */
2008-02-06 04:57:51 +03:00
printk ( KERN_INFO " %s: probing with STATUS(0x%02x) "
" instead of ALTSTATUS(0x%02x) \n " ,
drive - > name , s , a ) ;
else
2005-04-17 02:20:36 +04:00
/* use non-intrusive polling */
2008-02-06 04:57:51 +03:00
use_altstatus = 1 ;
}
2005-04-17 02:20:36 +04:00
/* set features register for atapi
* identify command to be sure of reply
*/
if ( ( cmd = = WIN_PIDENTIFY ) )
/* disable dma & overlap */
hwif - > OUTB ( 0 , IDE_FEATURE_REG ) ;
/* ask drive for ID */
hwif - > OUTB ( cmd , IDE_COMMAND_REG ) ;
timeout = ( ( cmd = = WIN_IDENTIFY ) ? WAIT_WORSTCASE : WAIT_PIDENTIFY ) / 2 ;
timeout + = jiffies ;
do {
if ( time_after ( jiffies , timeout ) ) {
/* drive timed-out */
return 1 ;
}
/* give drive a breather */
msleep ( 50 ) ;
2008-02-06 04:57:51 +03:00
s = use_altstatus ? ide_read_altstatus ( drive )
: ide_read_status ( drive ) ;
} while ( s & BUSY_STAT ) ;
2005-04-17 02:20:36 +04:00
/* wait for IRQ and DRQ_STAT */
msleep ( 50 ) ;
2008-02-06 04:57:51 +03:00
s = ide_read_status ( drive ) ;
if ( OK_STAT ( s , DRQ_STAT , BAD_R_STAT ) ) {
2005-04-17 02:20:36 +04:00
unsigned long flags ;
/* local CPU only; some systems need this */
local_irq_save ( flags ) ;
/* drive returned ID */
do_identify ( drive , cmd ) ;
/* drive responded with ID */
rc = 0 ;
/* clear drive IRQ */
2008-02-06 04:57:51 +03:00
( void ) ide_read_status ( drive ) ;
2005-04-17 02:20:36 +04:00
local_irq_restore ( flags ) ;
} else {
/* drive refused ID */
rc = 2 ;
}
return rc ;
}
/**
* try_to_identify - try to identify a drive
* @ drive : drive to probe
* @ cmd : command to use
*
* Issue the identify command and then do IRQ probing to
* complete the identification when needed by finding the
* IRQ the drive is attached to
*/
static int try_to_identify ( ide_drive_t * drive , u8 cmd )
{
ide_hwif_t * hwif = HWIF ( drive ) ;
int retval ;
int autoprobe = 0 ;
unsigned long cookie = 0 ;
/*
* Disable device irq unless we need to
* probe for it . Otherwise we ' ll get spurious
* interrupts during the identify - phase that
* the irq handler isn ' t expecting .
*/
if ( IDE_CONTROL_REG ) {
if ( ! hwif - > irq ) {
autoprobe = 1 ;
cookie = probe_irq_on ( ) ;
}
2008-01-26 22:13:08 +03:00
ide_set_irq ( drive , autoprobe ) ;
2005-04-17 02:20:36 +04:00
}
retval = actual_try_to_identify ( drive , cmd ) ;
if ( autoprobe ) {
int irq ;
2008-01-26 22:13:08 +03:00
ide_set_irq ( drive , 0 ) ;
2005-04-17 02:20:36 +04:00
/* clear drive IRQ */
2008-02-06 04:57:51 +03:00
( void ) ide_read_status ( drive ) ;
2005-04-17 02:20:36 +04:00
udelay ( 5 ) ;
irq = probe_irq_off ( cookie ) ;
if ( ! hwif - > irq ) {
if ( irq > 0 ) {
hwif - > irq = irq ;
} else {
/* Mmmm.. multiple IRQs..
* don ' t know which was ours
*/
printk ( " %s: IRQ probe failed (0x%lx) \n " ,
drive - > name , cookie ) ;
}
}
}
return retval ;
}
2008-01-26 22:13:09 +03:00
static int ide_busy_sleep ( ide_hwif_t * hwif )
{
unsigned long timeout = jiffies + WAIT_WORSTCASE ;
u8 stat ;
do {
msleep ( 50 ) ;
stat = hwif - > INB ( hwif - > io_ports [ IDE_STATUS_OFFSET ] ) ;
if ( ( stat & BUSY_STAT ) = = 0 )
return 0 ;
} while ( time_before ( jiffies , timeout ) ) ;
return 1 ;
}
2005-04-17 02:20:36 +04:00
/**
* do_probe - probe an IDE device
* @ drive : drive to probe
* @ cmd : command to use
*
* do_probe ( ) has the difficult job of finding a drive if it exists ,
* without getting hung up if it doesn ' t exist , without trampling on
* ethernet cards , and without leaving any IRQs dangling to haunt us later .
*
* If a drive is " known " to exist ( from CMOS or kernel parameters ) ,
* but does not respond right away , the probe will " hang in there "
* for the maximum wait time ( about 30 seconds ) , otherwise it will
* exit much more quickly .
*
* Returns : 0 device was identified
* 1 device timed - out ( no response to identify request )
* 2 device aborted the command ( refused to identify itself )
* 3 bad status from device ( possible for ATAPI drives )
* 4 probe was not attempted because failure was obvious
*/
static int do_probe ( ide_drive_t * drive , u8 cmd )
{
ide_hwif_t * hwif = HWIF ( drive ) ;
2008-02-02 21:56:45 +03:00
int rc ;
u8 stat ;
2005-04-17 02:20:36 +04:00
if ( drive - > present ) {
/* avoid waiting for inappropriate probes */
if ( ( drive - > media ! = ide_disk ) & & ( cmd = = WIN_IDENTIFY ) )
return 4 ;
}
# ifdef DEBUG
printk ( " probing for %s: present=%d, media=%d, probetype=%s \n " ,
drive - > name , drive - > present , drive - > media ,
( cmd = = WIN_IDENTIFY ) ? " ATA " : " ATAPI " ) ;
# endif
/* needed for some systems
* ( e . g . crw9624 as drive0 with disk as slave )
*/
msleep ( 50 ) ;
SELECT_DRIVE ( drive ) ;
msleep ( 50 ) ;
if ( hwif - > INB ( IDE_SELECT_REG ) ! = drive - > select . all & & ! drive - > present ) {
if ( drive - > select . b . unit ! = 0 ) {
/* exit with drive0 selected */
SELECT_DRIVE ( & hwif - > drives [ 0 ] ) ;
/* allow BUSY_STAT to assert & clear */
msleep ( 50 ) ;
}
/* no i/f present: mmm.. this should be a 4 -ml */
return 3 ;
}
2008-02-06 04:57:51 +03:00
stat = ide_read_status ( drive ) ;
if ( OK_STAT ( stat , READY_STAT , BUSY_STAT ) | |
2005-04-17 02:20:36 +04:00
drive - > present | | cmd = = WIN_PIDENTIFY ) {
/* send cmd and wait */
if ( ( rc = try_to_identify ( drive , cmd ) ) ) {
/* failed: try again */
rc = try_to_identify ( drive , cmd ) ;
}
2008-02-02 21:56:45 +03:00
2008-02-06 04:57:51 +03:00
stat = ide_read_status ( drive ) ;
2008-02-02 21:56:45 +03:00
if ( stat = = ( BUSY_STAT | READY_STAT ) )
2005-04-17 02:20:36 +04:00
return 4 ;
if ( ( rc = = 1 & & cmd = = WIN_PIDENTIFY ) & &
( ( drive - > autotune = = IDE_TUNE_DEFAULT ) | |
( drive - > autotune = = IDE_TUNE_AUTO ) ) ) {
2008-02-02 21:56:45 +03:00
printk ( KERN_ERR " %s: no response (status = 0x%02x), "
" resetting drive \n " , drive - > name , stat ) ;
2005-04-17 02:20:36 +04:00
msleep ( 50 ) ;
hwif - > OUTB ( drive - > select . all , IDE_SELECT_REG ) ;
msleep ( 50 ) ;
hwif - > OUTB ( WIN_SRST , IDE_COMMAND_REG ) ;
2008-01-26 22:13:09 +03:00
( void ) ide_busy_sleep ( hwif ) ;
2005-04-17 02:20:36 +04:00
rc = try_to_identify ( drive , cmd ) ;
}
2008-02-02 21:56:45 +03:00
/* ensure drive IRQ is clear */
2008-02-06 04:57:51 +03:00
stat = ide_read_status ( drive ) ;
2008-02-02 21:56:45 +03:00
2005-04-17 02:20:36 +04:00
if ( rc = = 1 )
2008-02-02 21:56:45 +03:00
printk ( KERN_ERR " %s: no response (status = 0x%02x) \n " ,
drive - > name , stat ) ;
2005-04-17 02:20:36 +04:00
} else {
/* not present or maybe ATAPI */
rc = 3 ;
}
if ( drive - > select . b . unit ! = 0 ) {
/* exit with drive0 selected */
SELECT_DRIVE ( & hwif - > drives [ 0 ] ) ;
msleep ( 50 ) ;
/* ensure drive irq is clear */
2008-02-06 04:57:51 +03:00
( void ) ide_read_status ( drive ) ;
2005-04-17 02:20:36 +04:00
}
return rc ;
}
/*
*
*/
static void enable_nest ( ide_drive_t * drive )
{
ide_hwif_t * hwif = HWIF ( drive ) ;
2008-02-02 21:56:45 +03:00
u8 stat ;
2005-04-17 02:20:36 +04:00
printk ( " %s: enabling %s -- " , hwif - > name , drive - > id - > model ) ;
SELECT_DRIVE ( drive ) ;
msleep ( 50 ) ;
hwif - > OUTB ( EXABYTE_ENABLE_NEST , IDE_COMMAND_REG ) ;
2008-01-26 22:13:09 +03:00
if ( ide_busy_sleep ( hwif ) ) {
printk ( KERN_CONT " failed (timeout) \n " ) ;
return ;
}
2005-04-17 02:20:36 +04:00
msleep ( 50 ) ;
2008-02-06 04:57:51 +03:00
stat = ide_read_status ( drive ) ;
2008-02-02 21:56:45 +03:00
if ( ! OK_STAT ( stat , 0 , BAD_STAT ) )
printk ( KERN_CONT " failed (status = 0x%02x) \n " , stat ) ;
else
printk ( KERN_CONT " success \n " ) ;
2005-04-17 02:20:36 +04:00
/* if !(success||timed-out) */
if ( do_probe ( drive , WIN_IDENTIFY ) > = 2 ) {
/* look for ATAPI device */
( void ) do_probe ( drive , WIN_PIDENTIFY ) ;
}
}
/**
* probe_for_drives - upper level drive probe
* @ drive : drive to probe for
*
* probe_for_drive ( ) tests for existence of a given drive using do_probe ( )
* and presents things to the user as needed .
*
* Returns : 0 no device was found
* 1 device was found ( note : drive - > present might
* still be 0 )
*/
static inline u8 probe_for_drive ( ide_drive_t * drive )
{
/*
* In order to keep things simple we have an id
* block for all drives at all times . If the device
* is pre ATA or refuses ATA / ATAPI identify we
* will add faked data to this .
*
* Also note that 0 everywhere means " can't do X "
*/
2005-11-07 12:01:25 +03:00
drive - > id = kzalloc ( SECTOR_WORDS * 4 , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
drive - > id_read = 0 ;
if ( drive - > id = = NULL )
{
printk ( KERN_ERR " ide: out of memory for id data. \n " ) ;
return 0 ;
}
strcpy ( drive - > id - > model , " UNKNOWN " ) ;
/* skip probing? */
if ( ! drive - > noprobe )
{
/* if !(success||timed-out) */
if ( do_probe ( drive , WIN_IDENTIFY ) > = 2 ) {
/* look for ATAPI device */
( void ) do_probe ( drive , WIN_PIDENTIFY ) ;
}
if ( ! drive - > present )
/* drive not found */
return 0 ;
2007-07-04 00:28:35 +04:00
if ( strstr ( drive - > id - > model , " E X A B Y T E N E S T " ) )
enable_nest ( drive ) ;
2005-04-17 02:20:36 +04:00
/* identification failed? */
if ( ! drive - > id_read ) {
if ( drive - > media = = ide_disk ) {
printk ( KERN_INFO " %s: non-IDE drive, CHS=%d/%d/%d \n " ,
drive - > name , drive - > cyl ,
drive - > head , drive - > sect ) ;
} else if ( drive - > media = = ide_cdrom ) {
printk ( KERN_INFO " %s: ATAPI cdrom (?) \n " , drive - > name ) ;
} else {
/* nuke it */
printk ( KERN_WARNING " %s: Unknown device on bus refused identification. Ignoring. \n " , drive - > name ) ;
drive - > present = 0 ;
}
}
/* drive was found */
}
if ( ! drive - > present )
return 0 ;
/* The drive wasn't being helpful. Add generic info only */
if ( drive - > id_read = = 0 ) {
generic_id ( drive ) ;
return 1 ;
}
if ( drive - > media = = ide_disk ) {
ide_disk_init_chs ( drive ) ;
ide_disk_init_mult_count ( drive ) ;
}
return drive - > present ;
}
static void hwif_release_dev ( struct device * dev )
{
ide_hwif_t * hwif = container_of ( dev , ide_hwif_t , gendev ) ;
2006-01-10 02:59:27 +03:00
complete ( & hwif - > gendev_rel_comp ) ;
2005-04-17 02:20:36 +04:00
}
2008-04-18 02:46:23 +04:00
static int ide_register_port ( ide_hwif_t * hwif )
2005-04-17 02:20:36 +04:00
{
2006-10-03 12:14:23 +04:00
int ret ;
2005-04-17 02:20:36 +04:00
/* register with global device tree */
strlcpy ( hwif - > gendev . bus_id , hwif - > name , BUS_ID_SIZE ) ;
hwif - > gendev . driver_data = hwif ;
if ( hwif - > gendev . parent = = NULL ) {
2008-02-02 01:09:31 +03:00
if ( hwif - > dev )
hwif - > gendev . parent = hwif - > dev ;
2005-04-17 02:20:36 +04:00
else
/* Would like to do = &device_legacy */
hwif - > gendev . parent = NULL ;
}
hwif - > gendev . release = hwif_release_dev ;
2006-10-03 12:14:23 +04:00
ret = device_register ( & hwif - > gendev ) ;
2008-04-18 02:46:23 +04:00
if ( ret < 0 ) {
2006-10-03 12:14:23 +04:00
printk ( KERN_WARNING " IDE: %s: device_register error: %d \n " ,
__FUNCTION__ , ret ) ;
2008-04-18 02:46:23 +04:00
goto out ;
}
get_device ( & hwif - > gendev ) ;
hwif - > portdev = device_create ( ide_port_class , & hwif - > gendev ,
MKDEV ( 0 , 0 ) , hwif - > name ) ;
if ( IS_ERR ( hwif - > portdev ) ) {
ret = PTR_ERR ( hwif - > portdev ) ;
device_unregister ( & hwif - > gendev ) ;
}
dev_set_drvdata ( hwif - > portdev , hwif ) ;
out :
return ret ;
2005-04-17 02:20:36 +04:00
}
2008-02-02 01:09:34 +03:00
/**
* ide_port_wait_ready - wait for port to become ready
* @ hwif : IDE port
*
* This is needed on some PPCs and a bunch of BIOS - less embedded
* platforms . Typical cases are :
*
* - The firmware hard reset the disk before booting the kernel ,
* the drive is still doing it ' s poweron - reset sequence , that
* can take up to 30 seconds .
*
* - The firmware does nothing ( or no firmware ) , the device is
* still in POST state ( same as above actually ) .
*
* - Some CD / DVD / Writer combo drives tend to drive the bus during
* their reset sequence even when they are non - selected slave
* devices , thus preventing discovery of the main HD .
*
* Doing this wait - for - non - busy should not harm any existing
* configuration and fix some issues like the above .
*
* BenH .
*
* Returns 0 on success , error code ( < 0 ) otherwise .
*/
static int ide_port_wait_ready ( ide_hwif_t * hwif )
2005-04-17 02:20:36 +04:00
{
2007-11-27 23:35:53 +03:00
int unit , rc ;
2005-04-17 02:20:36 +04:00
printk ( KERN_DEBUG " Probing IDE interface %s... \n " , hwif - > name ) ;
/* Let HW settle down a bit from whatever init state we
* come from */
mdelay ( 2 ) ;
/* Wait for BSY bit to go away, spec timeout is 30 seconds,
* I know of at least one disk who takes 31 seconds , I use 35
* here to be safe
*/
rc = ide_wait_not_busy ( hwif , 35000 ) ;
if ( rc )
return rc ;
/* Now make sure both master & slave are ready */
2007-11-27 23:35:53 +03:00
for ( unit = 0 ; unit < MAX_DRIVES ; unit + + ) {
ide_drive_t * drive = & hwif - > drives [ unit ] ;
/* Ignore disks that we will not probe for later. */
if ( ! drive - > noprobe | | drive - > present ) {
SELECT_DRIVE ( drive ) ;
2008-01-26 22:13:08 +03:00
ide_set_irq ( drive , 1 ) ;
2007-11-27 23:35:53 +03:00
mdelay ( 2 ) ;
rc = ide_wait_not_busy ( hwif , 35000 ) ;
if ( rc )
goto out ;
} else
printk ( KERN_DEBUG " %s: ide_wait_not_busy() skipped \n " ,
drive - > name ) ;
}
out :
2005-04-17 02:20:36 +04:00
/* Exit function with master reselected (let's be sane) */
2007-11-27 23:35:53 +03:00
if ( unit )
SELECT_DRIVE ( & hwif - > drives [ 0 ] ) ;
2005-04-17 02:20:36 +04:00
return rc ;
}
/**
* ide_undecoded_slave - look for bad CF adapters
2008-01-26 22:13:03 +03:00
* @ drive1 : drive
2005-04-17 02:20:36 +04:00
*
* Analyse the drives on the interface and attempt to decide if we
* have the same drive viewed twice . This occurs with crap CF adapters
* and PCMCIA sometimes .
*/
2008-01-26 22:13:03 +03:00
void ide_undecoded_slave ( ide_drive_t * drive1 )
2005-04-17 02:20:36 +04:00
{
2008-01-26 22:13:03 +03:00
ide_drive_t * drive0 = & drive1 - > hwif - > drives [ 0 ] ;
2005-04-17 02:20:36 +04:00
2008-01-26 22:13:03 +03:00
if ( ( drive1 - > dn & 1 ) = = 0 | | drive0 - > present = = 0 )
2005-04-17 02:20:36 +04:00
return ;
/* If the models don't match they are not the same product */
if ( strcmp ( drive0 - > id - > model , drive1 - > id - > model ) )
return ;
/* Serial numbers do not match */
if ( strncmp ( drive0 - > id - > serial_no , drive1 - > id - > serial_no , 20 ) )
return ;
/* No serial number, thankfully very rare for CF */
if ( drive0 - > id - > serial_no [ 0 ] = = 0 )
return ;
/* Appears to be an IDE flash adapter with decode bugs */
printk ( KERN_WARNING " ide-probe: ignoring undecoded slave \n " ) ;
drive1 - > present = 0 ;
}
EXPORT_SYMBOL_GPL ( ide_undecoded_slave ) ;
2008-02-02 01:09:36 +03:00
static int ide_probe_port ( ide_hwif_t * hwif )
2005-04-17 02:20:36 +04:00
{
unsigned long flags ;
unsigned int irqd ;
2008-02-02 01:09:36 +03:00
int unit , rc = - ENODEV ;
BUG_ON ( hwif - > present ) ;
2005-04-17 02:20:36 +04:00
2008-02-26 23:50:34 +03:00
if ( hwif - > noprobe | |
( hwif - > drives [ 0 ] . noprobe & & hwif - > drives [ 1 ] . noprobe ) )
2008-02-02 01:09:36 +03:00
return - EACCES ;
2005-04-17 02:20:36 +04:00
/*
* We must always disable IRQ , as probe_for_drive will assert IRQ , but
* we ' ll install our IRQ driver much later . . .
*/
irqd = hwif - > irq ;
if ( irqd )
disable_irq ( hwif - > irq ) ;
local_irq_set ( flags ) ;
2008-02-02 01:09:34 +03:00
if ( ide_port_wait_ready ( hwif ) = = - EBUSY )
2005-04-17 02:20:36 +04:00
printk ( KERN_DEBUG " %s: Wait for ready failed before probe ! \n " , hwif - > name ) ;
/*
2008-03-29 21:48:21 +03:00
* Second drive should only exist if first drive was found ,
* but a lot of cdrom drives are configured as single slaves .
2005-04-17 02:20:36 +04:00
*/
2008-03-29 21:48:21 +03:00
for ( unit = 0 ; unit < MAX_DRIVES ; + + unit ) {
2005-04-17 02:20:36 +04:00
ide_drive_t * drive = & hwif - > drives [ unit ] ;
drive - > dn = ( hwif - > channel ? 2 : 0 ) + unit ;
( void ) probe_for_drive ( drive ) ;
2008-02-02 01:09:36 +03:00
if ( drive - > present )
rc = 0 ;
2005-04-17 02:20:36 +04:00
}
if ( hwif - > io_ports [ IDE_CONTROL_OFFSET ] & & hwif - > reset ) {
printk ( KERN_WARNING " %s: reset \n " , hwif - > name ) ;
hwif - > OUTB ( 12 , hwif - > io_ports [ IDE_CONTROL_OFFSET ] ) ;
udelay ( 10 ) ;
hwif - > OUTB ( 8 , hwif - > io_ports [ IDE_CONTROL_OFFSET ] ) ;
2008-01-26 22:13:09 +03:00
( void ) ide_busy_sleep ( hwif ) ;
2005-04-17 02:20:36 +04:00
}
local_irq_restore ( flags ) ;
/*
* Use cached IRQ number . It might be ( and is . . . ) changed by probe
* code above
*/
if ( irqd )
enable_irq ( irqd ) ;
2008-02-02 01:09:36 +03:00
return rc ;
2008-02-02 01:09:36 +03:00
}
static void ide_port_tune_devices ( ide_hwif_t * hwif )
{
int unit ;
2008-01-26 22:13:03 +03:00
for ( unit = 0 ; unit < MAX_DRIVES ; unit + + ) {
ide_drive_t * drive = & hwif - > drives [ unit ] ;
if ( drive - > present & & hwif - > quirkproc )
hwif - > quirkproc ( drive ) ;
}
2007-06-08 17:14:29 +04:00
2005-04-17 02:20:36 +04:00
for ( unit = 0 ; unit < MAX_DRIVES ; + + unit ) {
ide_drive_t * drive = & hwif - > drives [ unit ] ;
if ( drive - > present ) {
2007-10-12 01:54:00 +04:00
if ( drive - > autotune = = IDE_TUNE_AUTO )
ide_set_max_pio ( drive ) ;
2005-04-17 02:20:36 +04:00
if ( drive - > autotune ! = IDE_TUNE_DEFAULT & &
drive - > autotune ! = IDE_TUNE_AUTO )
continue ;
drive - > nice1 = 1 ;
2008-01-26 22:13:03 +03:00
if ( hwif - > dma_host_set )
2007-10-17 00:29:58 +04:00
ide_set_dma ( drive ) ;
2005-04-17 02:20:36 +04:00
}
}
2006-03-24 14:18:21 +03:00
for ( unit = 0 ; unit < MAX_DRIVES ; + + unit ) {
ide_drive_t * drive = & hwif - > drives [ unit ] ;
2008-02-02 21:56:40 +03:00
if ( hwif - > host_flags & IDE_HFLAG_NO_IO_32BIT )
2006-03-24 14:18:21 +03:00
drive - > no_io_32bit = 1 ;
else
drive - > no_io_32bit = drive - > id - > dword_io ? 1 : 0 ;
}
2005-04-17 02:20:36 +04:00
}
# if MAX_HWIFS > 1
/*
* save_match ( ) is used to simplify logic in init_irq ( ) below .
*
* A loophole here is that we may not know about a particular
* hwif ' s irq until after that hwif is actually probed / initialized . .
* This could be a problem for the case where an hwif is on a
* dual interface that requires serialization ( eg . cmd640 ) and another
* hwif using one of the same irqs is initialized beforehand .
*
* This routine detects and reports such situations , but does not fix them .
*/
static void save_match ( ide_hwif_t * hwif , ide_hwif_t * new , ide_hwif_t * * match )
{
ide_hwif_t * m = * match ;
if ( m & & m - > hwgroup & & m - > hwgroup ! = new - > hwgroup ) {
if ( ! new - > hwgroup )
return ;
printk ( " %s: potential irq problem with %s and %s \n " ,
hwif - > name , new - > name , m - > name ) ;
}
if ( ! m | | m - > irq ! = hwif - > irq ) /* don't undo a prior perfect match */
* match = new ;
}
# endif /* MAX_HWIFS > 1 */
/*
* init request queue
*/
static int ide_init_queue ( ide_drive_t * drive )
{
2007-07-24 11:28:11 +04:00
struct request_queue * q ;
2005-04-17 02:20:36 +04:00
ide_hwif_t * hwif = HWIF ( drive ) ;
int max_sectors = 256 ;
int max_sg_entries = PRD_ENTRIES ;
/*
* Our default set up assumes the normal IDE case ,
* that is 64 K segmenting , standard PRD setup
* and LBA28 . Some drivers then impose their own
* limits and LBA48 we could raise it but as yet
* do not .
*/
2005-06-23 11:08:19 +04:00
2005-08-04 23:53:26 +04:00
q = blk_init_queue_node ( do_ide_request , & ide_lock , hwif_to_node ( hwif ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! q )
return 1 ;
q - > queuedata = drive ;
blk_queue_segment_boundary ( q , 0xffff ) ;
if ( hwif - > rqsize < max_sectors )
max_sectors = hwif - > rqsize ;
blk_queue_max_sectors ( q , max_sectors ) ;
# ifdef CONFIG_PCI
/* When we have an IOMMU, we may have a problem where pci_map_sg()
* creates segments that don ' t completely match our boundary
* requirements and thus need to be broken up again . Because it
* doesn ' t align properly either , we may actually have to break up
* to more segments than what was we got in the first place , a max
* worst case is twice as many .
* This will be fixed once we teach pci_map_sg ( ) about our boundary
* requirements , hopefully soon . * FIXME *
*/
if ( ! PCI_DMA_BUS_IS_PHYS )
max_sg_entries > > = 1 ;
# endif /* CONFIG_PCI */
blk_queue_max_hw_segments ( q , max_sg_entries ) ;
blk_queue_max_phys_segments ( q , max_sg_entries ) ;
/* assign drive queue */
drive - > queue = q ;
/* needs drive->queue to be set */
ide_toggle_bounce ( drive , 1 ) ;
return 0 ;
}
2008-02-02 21:56:41 +03:00
static void ide_add_drive_to_hwgroup ( ide_drive_t * drive )
{
ide_hwgroup_t * hwgroup = drive - > hwif - > hwgroup ;
spin_lock_irq ( & ide_lock ) ;
if ( ! hwgroup - > drive ) {
/* first drive for hwgroup. */
drive - > next = drive ;
hwgroup - > drive = drive ;
hwgroup - > hwif = HWIF ( hwgroup - > drive ) ;
} else {
drive - > next = hwgroup - > drive - > next ;
hwgroup - > drive - > next = drive ;
}
spin_unlock_irq ( & ide_lock ) ;
}
2008-02-02 21:56:41 +03:00
/*
* For any present drive :
* - allocate the block device queue
* - link drive into the hwgroup
*/
static void ide_port_setup_devices ( ide_hwif_t * hwif )
{
int i ;
2008-04-18 02:46:22 +04:00
mutex_lock ( & ide_cfg_mtx ) ;
2008-02-02 21:56:41 +03:00
for ( i = 0 ; i < MAX_DRIVES ; i + + ) {
ide_drive_t * drive = & hwif - > drives [ i ] ;
if ( ! drive - > present )
continue ;
if ( ide_init_queue ( drive ) ) {
printk ( KERN_ERR " ide: failed to init %s \n " ,
drive - > name ) ;
continue ;
}
ide_add_drive_to_hwgroup ( drive ) ;
}
2008-04-18 02:46:22 +04:00
mutex_unlock ( & ide_cfg_mtx ) ;
2008-02-02 21:56:41 +03:00
}
2005-04-17 02:20:36 +04:00
/*
* This routine sets up the irq for an ide interface , and creates a new
* hwgroup for the irq / hwif if none was previously assigned .
*
* Much of the code is for correctly detecting / handling irq sharing
* and irq serialization situations . This is somewhat complex because
* it handles static as well as dynamic ( PCMCIA ) IDE interfaces .
*/
static int init_irq ( ide_hwif_t * hwif )
{
unsigned int index ;
ide_hwgroup_t * hwgroup ;
ide_hwif_t * match = NULL ;
BUG_ON ( in_interrupt ( ) ) ;
BUG_ON ( irqs_disabled ( ) ) ;
2005-08-04 23:53:26 +04:00
BUG_ON ( hwif = = NULL ) ;
2007-07-10 01:17:55 +04:00
mutex_lock ( & ide_cfg_mtx ) ;
2005-04-17 02:20:36 +04:00
hwif - > hwgroup = NULL ;
# if MAX_HWIFS > 1
/*
* Group up with any other hwifs that share our irq ( s ) .
*/
for ( index = 0 ; index < MAX_HWIFS ; index + + ) {
ide_hwif_t * h = & ide_hwifs [ index ] ;
if ( h - > hwgroup ) { /* scan only initialized hwif's */
if ( hwif - > irq = = h - > irq ) {
hwif - > sharing_irq = h - > sharing_irq = 1 ;
if ( hwif - > chipset ! = ide_pci | |
h - > chipset ! = ide_pci ) {
save_match ( hwif , h , & match ) ;
}
}
if ( hwif - > serialized ) {
if ( hwif - > mate & & hwif - > mate - > irq = = h - > irq )
save_match ( hwif , h , & match ) ;
}
if ( h - > serialized ) {
if ( h - > mate & & hwif - > irq = = h - > mate - > irq )
save_match ( hwif , h , & match ) ;
}
}
}
# endif /* MAX_HWIFS > 1 */
/*
* If we are still without a hwgroup , then form a new one
*/
if ( match ) {
hwgroup = match - > hwgroup ;
hwif - > hwgroup = hwgroup ;
/*
* Link us into the hwgroup .
* This must be done early , do ensure that unexpected_intr
* can find the hwif and prevent irq storms .
* No drives are attached to the new hwif , choose_drive
* can ' t do anything stupid ( yet ) .
* Add ourself as the 2 nd entry to the hwgroup - > hwif
* linked list , the first entry is the hwif that owns
* hwgroup - > handler - do not change that .
*/
spin_lock_irq ( & ide_lock ) ;
hwif - > next = hwgroup - > hwif - > next ;
hwgroup - > hwif - > next = hwif ;
2008-02-02 01:09:36 +03:00
BUG_ON ( hwif - > next = = hwif ) ;
2005-04-17 02:20:36 +04:00
spin_unlock_irq ( & ide_lock ) ;
} else {
2008-02-02 01:09:35 +03:00
hwgroup = kmalloc_node ( sizeof ( * hwgroup ) , GFP_KERNEL | __GFP_ZERO ,
hwif_to_node ( hwif ) ) ;
if ( hwgroup = = NULL )
goto out_up ;
2005-04-17 02:20:36 +04:00
hwif - > hwgroup = hwgroup ;
2008-02-02 01:09:35 +03:00
hwgroup - > hwif = hwif - > next = hwif ;
2005-04-17 02:20:36 +04:00
init_timer ( & hwgroup - > timer ) ;
hwgroup - > timer . function = & ide_timer_expiry ;
hwgroup - > timer . data = ( unsigned long ) hwgroup ;
}
/*
* Allocate the irq , if not already obtained for another hwif
*/
if ( ! match | | match - > irq ! = hwif - > irq ) {
2008-01-26 00:17:08 +03:00
int sa = 0 ;
2008-02-06 12:36:29 +03:00
# if defined(__mc68000__)
2006-07-02 06:29:34 +04:00
sa = IRQF_SHARED ;
2008-02-11 02:32:15 +03:00
# endif /* __mc68000__ */
2005-04-17 02:20:36 +04:00
2008-01-26 00:17:08 +03:00
if ( IDE_CHIPSET_IS_PCI ( hwif - > chipset ) )
2006-07-02 06:29:34 +04:00
sa = IRQF_SHARED ;
2005-04-17 02:20:36 +04:00
if ( hwif - > io_ports [ IDE_CONTROL_OFFSET ] )
/* clear nIEN */
hwif - > OUTB ( 0x08 , hwif - > io_ports [ IDE_CONTROL_OFFSET ] ) ;
if ( request_irq ( hwif - > irq , & ide_intr , sa , hwif - > name , hwgroup ) )
goto out_unlink ;
}
2008-02-02 21:56:41 +03:00
if ( ! hwif - > rqsize ) {
if ( ( hwif - > host_flags & IDE_HFLAG_NO_LBA48 ) | |
( hwif - > host_flags & IDE_HFLAG_NO_LBA48_DMA ) )
hwif - > rqsize = 256 ;
else
hwif - > rqsize = 65536 ;
}
2008-02-06 12:36:29 +03:00
# if !defined(__mc68000__)
2005-04-17 02:20:36 +04:00
printk ( " %s at 0x%03lx-0x%03lx,0x%03lx on irq %d " , hwif - > name ,
hwif - > io_ports [ IDE_DATA_OFFSET ] ,
hwif - > io_ports [ IDE_DATA_OFFSET ] + 7 ,
hwif - > io_ports [ IDE_CONTROL_OFFSET ] , hwif - > irq ) ;
# else
printk ( " %s at 0x%08lx on irq %d " , hwif - > name ,
hwif - > io_ports [ IDE_DATA_OFFSET ] , hwif - > irq ) ;
2008-02-06 12:36:29 +03:00
# endif /* __mc68000__ */
2005-04-17 02:20:36 +04:00
if ( match )
printk ( " (%sed with %s) " ,
hwif - > sharing_irq ? " shar " : " serializ " , match - > name ) ;
printk ( " \n " ) ;
2008-02-02 21:56:41 +03:00
2007-07-10 01:17:55 +04:00
mutex_unlock ( & ide_cfg_mtx ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
out_unlink :
2008-02-02 01:09:36 +03:00
ide_remove_port_from_hwgroup ( hwif ) ;
2005-04-17 02:20:36 +04:00
out_up :
2007-07-10 01:17:55 +04:00
mutex_unlock ( & ide_cfg_mtx ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
}
static int ata_lock ( dev_t dev , void * data )
{
/* FIXME: we want to pin hwif down */
return 0 ;
}
static struct kobject * ata_probe ( dev_t dev , int * part , void * data )
{
ide_hwif_t * hwif = data ;
int unit = * part > > PARTN_BITS ;
ide_drive_t * drive = & hwif - > drives [ unit ] ;
if ( ! drive - > present )
return NULL ;
if ( drive - > media = = ide_disk )
request_module ( " ide-disk " ) ;
if ( drive - > scsi )
request_module ( " ide-scsi " ) ;
if ( drive - > media = = ide_cdrom | | drive - > media = = ide_optical )
request_module ( " ide-cd " ) ;
if ( drive - > media = = ide_tape )
request_module ( " ide-tape " ) ;
if ( drive - > media = = ide_floppy )
request_module ( " ide-floppy " ) ;
return NULL ;
}
static struct kobject * exact_match ( dev_t dev , int * part , void * data )
{
struct gendisk * p = data ;
* part & = ( 1 < < PARTN_BITS ) - 1 ;
2007-05-22 00:08:01 +04:00
return & p - > dev . kobj ;
2005-04-17 02:20:36 +04:00
}
static int exact_lock ( dev_t dev , void * data )
{
struct gendisk * p = data ;
if ( ! get_disk ( p ) )
return - 1 ;
return 0 ;
}
void ide_register_region ( struct gendisk * disk )
{
blk_register_region ( MKDEV ( disk - > major , disk - > first_minor ) ,
disk - > minors , NULL , exact_match , exact_lock , disk ) ;
}
EXPORT_SYMBOL_GPL ( ide_register_region ) ;
void ide_unregister_region ( struct gendisk * disk )
{
blk_unregister_region ( MKDEV ( disk - > major , disk - > first_minor ) ,
disk - > minors ) ;
}
EXPORT_SYMBOL_GPL ( ide_unregister_region ) ;
void ide_init_disk ( struct gendisk * disk , ide_drive_t * drive )
{
ide_hwif_t * hwif = drive - > hwif ;
unsigned int unit = ( drive - > select . all > > 4 ) & 1 ;
disk - > major = hwif - > major ;
disk - > first_minor = unit < < PARTN_BITS ;
sprintf ( disk - > disk_name , " hd%c " , ' a ' + hwif - > index * MAX_DRIVES + unit ) ;
disk - > queue = drive - > queue ;
}
EXPORT_SYMBOL_GPL ( ide_init_disk ) ;
2005-05-26 16:55:34 +04:00
static void ide_remove_drive_from_hwgroup ( ide_drive_t * drive )
{
ide_hwgroup_t * hwgroup = drive - > hwif - > hwgroup ;
if ( drive = = drive - > next ) {
/* special case: last drive from hwgroup. */
BUG_ON ( hwgroup - > drive ! = drive ) ;
hwgroup - > drive = NULL ;
} else {
ide_drive_t * walk ;
walk = hwgroup - > drive ;
while ( walk - > next ! = drive )
walk = walk - > next ;
walk - > next = drive - > next ;
if ( hwgroup - > drive = = drive ) {
hwgroup - > drive = drive - > next ;
hwgroup - > hwif = hwgroup - > drive - > hwif ;
}
}
BUG_ON ( hwgroup - > drive = = drive ) ;
}
2005-04-17 02:20:36 +04:00
static void drive_release_dev ( struct device * dev )
{
ide_drive_t * drive = container_of ( dev , ide_drive_t , gendev ) ;
2008-04-18 02:46:22 +04:00
ide_proc_unregister_device ( drive ) ;
2005-05-26 16:55:34 +04:00
spin_lock_irq ( & ide_lock ) ;
ide_remove_drive_from_hwgroup ( drive ) ;
2005-11-07 12:01:32 +03:00
kfree ( drive - > id ) ;
drive - > id = NULL ;
2005-05-26 16:55:34 +04:00
drive - > present = 0 ;
/* Messed up locking ... */
spin_unlock_irq ( & ide_lock ) ;
blk_cleanup_queue ( drive - > queue ) ;
spin_lock_irq ( & ide_lock ) ;
drive - > queue = NULL ;
spin_unlock_irq ( & ide_lock ) ;
2006-01-10 02:59:27 +03:00
complete ( & drive - > gendev_rel_comp ) ;
2005-04-17 02:20:36 +04:00
}
static int hwif_init ( ide_hwif_t * hwif )
{
int old_irq ;
if ( ! hwif - > irq ) {
if ( ! ( hwif - > irq = ide_default_irq ( hwif - > io_ports [ IDE_DATA_OFFSET ] ) ) )
{
printk ( " %s: DISABLED, NO IRQ \n " , hwif - > name ) ;
2008-02-02 01:09:34 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
}
if ( register_blkdev ( hwif - > major , hwif - > name ) )
return 0 ;
if ( ! hwif - > sg_max_nents )
hwif - > sg_max_nents = PRD_ENTRIES ;
2007-10-22 23:19:53 +04:00
hwif - > sg_table = kmalloc ( sizeof ( struct scatterlist ) * hwif - > sg_max_nents ,
2005-04-17 02:20:36 +04:00
GFP_KERNEL ) ;
if ( ! hwif - > sg_table ) {
printk ( KERN_ERR " %s: unable to allocate SG table. \n " , hwif - > name ) ;
goto out ;
}
2007-10-22 23:19:53 +04:00
sg_init_table ( hwif - > sg_table , hwif - > sg_max_nents ) ;
2005-04-17 02:20:36 +04:00
if ( init_irq ( hwif ) = = 0 )
goto done ;
old_irq = hwif - > irq ;
/*
* It failed to initialise . Find the default IRQ for
* this port and try that .
*/
if ( ! ( hwif - > irq = ide_default_irq ( hwif - > io_ports [ IDE_DATA_OFFSET ] ) ) ) {
printk ( " %s: Disabled unable to get IRQ %d. \n " ,
hwif - > name , old_irq ) ;
goto out ;
}
if ( init_irq ( hwif ) ) {
printk ( " %s: probed IRQ %d and default IRQ %d failed. \n " ,
hwif - > name , old_irq , hwif - > irq ) ;
goto out ;
}
printk ( " %s: probed IRQ %d failed, using default. \n " ,
hwif - > name , hwif - > irq ) ;
done :
2008-02-02 21:56:40 +03:00
blk_register_region ( MKDEV ( hwif - > major , 0 ) , MAX_DRIVES < < PARTN_BITS ,
THIS_MODULE , ata_probe , ata_lock , hwif ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
out :
unregister_blkdev ( hwif - > major , hwif - > name ) ;
return 0 ;
}
2007-10-20 02:32:29 +04:00
static void hwif_register_devices ( ide_hwif_t * hwif )
{
unsigned int i ;
for ( i = 0 ; i < MAX_DRIVES ; i + + ) {
ide_drive_t * drive = & hwif - > drives [ i ] ;
2008-02-02 21:56:41 +03:00
struct device * dev = & drive - > gendev ;
int ret ;
2007-10-20 02:32:29 +04:00
2008-02-02 21:56:41 +03:00
if ( ! drive - > present )
continue ;
2007-10-20 02:32:29 +04:00
2008-02-02 21:56:41 +03:00
ide_add_generic_settings ( drive ) ;
snprintf ( dev - > bus_id , BUS_ID_SIZE , " %u.%u " , hwif - > index , i ) ;
dev - > parent = & hwif - > gendev ;
dev - > bus = & ide_bus_type ;
dev - > driver_data = drive ;
dev - > release = drive_release_dev ;
ret = device_register ( dev ) ;
if ( ret < 0 )
printk ( KERN_WARNING " IDE: %s: device_register error: "
" %d \n " , __func__ , ret ) ;
2007-10-20 02:32:29 +04:00
}
}
2008-02-02 21:56:39 +03:00
static void ide_port_init_devices ( ide_hwif_t * hwif )
{
int i ;
for ( i = 0 ; i < MAX_DRIVES ; i + + ) {
ide_drive_t * drive = & hwif - > drives [ i ] ;
if ( hwif - > host_flags & IDE_HFLAG_IO_32BIT )
drive - > io_32bit = 1 ;
if ( hwif - > host_flags & IDE_HFLAG_UNMASK_IRQS )
drive - > unmask = 1 ;
2008-02-02 21:56:40 +03:00
if ( hwif - > host_flags & IDE_HFLAG_NO_UNMASK_IRQS )
drive - > no_unmask = 1 ;
2008-02-02 21:56:39 +03:00
if ( ( hwif - > host_flags & IDE_HFLAG_NO_AUTOTUNE ) = = 0 )
drive - > autotune = 1 ;
}
2008-02-02 21:56:40 +03:00
if ( hwif - > port_init_devs )
hwif - > port_init_devs ( hwif ) ;
2008-02-02 21:56:39 +03:00
}
2008-02-02 21:56:31 +03:00
static void ide_init_port ( ide_hwif_t * hwif , unsigned int port ,
const struct ide_port_info * d )
2007-10-20 02:32:31 +04:00
{
2008-02-02 21:56:31 +03:00
if ( d - > chipset ! = ide_etrax100 )
hwif - > channel = port ;
if ( d - > chipset )
hwif - > chipset = d - > chipset ;
if ( d - > init_iops )
d - > init_iops ( hwif ) ;
if ( ( d - > host_flags & IDE_HFLAG_NO_DMA ) = = 0 )
ide_hwif_setup_dma ( hwif , d ) ;
if ( ( ! hwif - > irq & & ( d - > host_flags & IDE_HFLAG_LEGACY_IRQS ) ) | |
( d - > host_flags & IDE_HFLAG_FORCE_LEGACY_IRQS ) )
hwif - > irq = port ? 15 : 14 ;
hwif - > host_flags = d - > host_flags ;
hwif - > pio_mask = d - > pio_mask ;
if ( ( d - > host_flags & IDE_HFLAG_SERIALIZE ) & & hwif - > mate )
hwif - > mate - > serialized = hwif - > serialized = 1 ;
hwif - > swdma_mask = d - > swdma_mask ;
hwif - > mwdma_mask = d - > mwdma_mask ;
hwif - > ultra_mask = d - > udma_mask ;
/* reset DMA masks only for SFF-style DMA controllers */
2008-02-11 02:32:15 +03:00
if ( ( d - > host_flags & IDE_HFLAG_NO_DMA ) = = 0 & & hwif - > dma_base = = 0 )
2008-02-02 21:56:31 +03:00
hwif - > swdma_mask = hwif - > mwdma_mask = hwif - > ultra_mask = 0 ;
if ( d - > host_flags & IDE_HFLAG_RQSIZE_256 )
hwif - > rqsize = 256 ;
/* call chipset specific routine for each enabled port */
if ( d - > init_hwif )
d - > init_hwif ( hwif ) ;
2008-04-18 02:46:22 +04:00
}
2008-02-02 21:56:31 +03:00
2008-04-18 02:46:22 +04:00
static void ide_port_cable_detect ( ide_hwif_t * hwif )
{
2008-02-02 21:56:31 +03:00
if ( hwif - > cable_detect & & ( hwif - > ultra_mask & 0x78 ) ) {
if ( hwif - > cbl ! = ATA_CBL_PATA40_SHORT )
hwif - > cbl = hwif - > cable_detect ( hwif ) ;
}
2008-02-02 21:56:31 +03:00
}
2008-04-18 02:46:23 +04:00
static ssize_t store_delete_devices ( struct device * portdev ,
struct device_attribute * attr ,
const char * buf , size_t n )
{
ide_hwif_t * hwif = dev_get_drvdata ( portdev ) ;
if ( strncmp ( buf , " 1 " , n ) )
return - EINVAL ;
ide_port_unregister_devices ( hwif ) ;
return n ;
} ;
static DEVICE_ATTR ( delete_devices , S_IWUSR , NULL , store_delete_devices ) ;
static ssize_t store_scan ( struct device * portdev ,
struct device_attribute * attr ,
const char * buf , size_t n )
{
ide_hwif_t * hwif = dev_get_drvdata ( portdev ) ;
if ( strncmp ( buf , " 1 " , n ) )
return - EINVAL ;
ide_port_unregister_devices ( hwif ) ;
ide_port_scan ( hwif ) ;
return n ;
} ;
static DEVICE_ATTR ( scan , S_IWUSR , NULL , store_scan ) ;
static struct device_attribute * ide_port_attrs [ ] = {
& dev_attr_delete_devices ,
& dev_attr_scan ,
NULL
} ;
static int ide_sysfs_register_port ( ide_hwif_t * hwif )
{
int i , rc ;
for ( i = 0 ; ide_port_attrs [ i ] ; i + + ) {
rc = device_create_file ( hwif - > portdev , ide_port_attrs [ i ] ) ;
if ( rc )
break ;
}
return rc ;
}
2008-02-02 21:56:31 +03:00
int ide_device_add_all ( u8 * idx , const struct ide_port_info * d )
{
ide_hwif_t * hwif , * mate = NULL ;
2007-10-20 02:32:31 +04:00
int i , rc = 0 ;
2008-02-02 21:56:31 +03:00
for ( i = 0 ; i < MAX_HWIFS ; i + + ) {
if ( d = = NULL | | idx [ i ] = = 0xff ) {
mate = NULL ;
continue ;
}
hwif = & ide_hwifs [ idx [ i ] ] ;
if ( d - > chipset ! = ide_etrax100 & & ( i & 1 ) & & mate ) {
hwif - > mate = mate ;
mate - > mate = hwif ;
}
mate = ( i & 1 ) ? NULL : hwif ;
ide_init_port ( hwif , i & 1 , d ) ;
2008-04-18 02:46:22 +04:00
ide_port_cable_detect ( hwif ) ;
2008-02-02 21:56:39 +03:00
ide_port_init_devices ( hwif ) ;
2008-02-02 21:56:31 +03:00
}
2008-01-26 22:13:05 +03:00
for ( i = 0 ; i < MAX_HWIFS ; i + + ) {
2008-01-26 22:13:04 +03:00
if ( idx [ i ] = = 0xff )
continue ;
2008-02-02 01:09:36 +03:00
hwif = & ide_hwifs [ idx [ i ] ] ;
if ( ( hwif - > chipset ! = ide_4drives | | ! hwif - > mate | |
! hwif - > mate - > present ) & & ide_hwif_request_regions ( hwif ) ) {
printk ( KERN_ERR " %s: ports already in use, "
" skipping probe \n " , hwif - > name ) ;
continue ;
}
2008-02-02 01:09:36 +03:00
if ( ide_probe_port ( hwif ) < 0 ) {
2008-02-02 01:09:36 +03:00
ide_hwif_release_regions ( hwif ) ;
2008-02-02 01:09:36 +03:00
continue ;
}
2008-02-02 01:09:36 +03:00
hwif - > present = 1 ;
if ( hwif - > chipset ! = ide_4drives | | ! hwif - > mate | |
! hwif - > mate - > present )
ide_register_port ( hwif ) ;
2008-02-02 01:09:36 +03:00
ide_port_tune_devices ( hwif ) ;
2008-01-26 22:13:04 +03:00
}
2008-01-26 22:13:04 +03:00
2008-01-26 22:13:05 +03:00
for ( i = 0 ; i < MAX_HWIFS ; i + + ) {
2008-01-26 22:13:04 +03:00
if ( idx [ i ] = = 0xff )
continue ;
hwif = & ide_hwifs [ idx [ i ] ] ;
2008-01-26 22:13:04 +03:00
2008-02-02 01:09:34 +03:00
if ( ! hwif - > present )
continue ;
2008-01-26 22:13:04 +03:00
if ( hwif_init ( hwif ) = = 0 ) {
printk ( KERN_INFO " %s: failed to initialize IDE "
" interface \n " , hwif - > name ) ;
2008-02-02 01:09:34 +03:00
hwif - > present = 0 ;
2008-01-26 22:13:04 +03:00
rc = - 1 ;
continue ;
}
2008-02-02 21:56:41 +03:00
2008-04-18 02:46:22 +04:00
ide_port_setup_devices ( hwif ) ;
2008-02-02 21:56:41 +03:00
ide_acpi_init ( hwif ) ;
2008-02-02 21:56:43 +03:00
ide_acpi_port_init_devices ( hwif ) ;
2008-01-26 22:13:04 +03:00
}
2008-01-26 22:13:05 +03:00
for ( i = 0 ; i < MAX_HWIFS ; i + + ) {
2008-01-26 22:13:04 +03:00
if ( idx [ i ] = = 0xff )
continue ;
hwif = & ide_hwifs [ idx [ i ] ] ;
2008-01-26 22:13:04 +03:00
2008-01-26 22:13:04 +03:00
if ( hwif - > present ) {
if ( hwif - > chipset = = ide_unknown | |
hwif - > chipset = = ide_forced )
hwif - > chipset = ide_generic ;
2008-01-26 22:13:04 +03:00
hwif_register_devices ( hwif ) ;
2008-01-26 22:13:04 +03:00
}
2007-10-20 02:32:31 +04:00
}
2008-01-26 22:13:05 +03:00
for ( i = 0 ; i < MAX_HWIFS ; i + + ) {
2008-02-02 21:56:43 +03:00
if ( idx [ i ] = = 0xff )
continue ;
hwif = & ide_hwifs [ idx [ i ] ] ;
2008-02-02 21:56:43 +03:00
if ( hwif - > present ) {
2008-04-18 02:46:23 +04:00
ide_sysfs_register_port ( hwif ) ;
2008-02-02 21:56:43 +03:00
ide_proc_register_port ( hwif ) ;
2008-02-02 21:56:43 +03:00
ide_proc_port_register_devices ( hwif ) ;
}
2007-10-20 02:32:31 +04:00
}
return rc ;
}
2008-01-26 22:13:05 +03:00
EXPORT_SYMBOL_GPL ( ide_device_add_all ) ;
2008-02-02 21:56:31 +03:00
int ide_device_add ( u8 idx [ 4 ] , const struct ide_port_info * d )
2008-01-26 22:13:05 +03:00
{
u8 idx_all [ MAX_HWIFS ] ;
int i ;
2007-10-20 02:32:31 +04:00
2008-01-26 22:13:05 +03:00
for ( i = 0 ; i < MAX_HWIFS ; i + + )
idx_all [ i ] = ( i < 4 ) ? idx [ i ] : 0xff ;
2008-02-02 21:56:31 +03:00
return ide_device_add_all ( idx_all , d ) ;
2008-01-26 22:13:05 +03:00
}
2007-10-20 02:32:31 +04:00
EXPORT_SYMBOL_GPL ( ide_device_add ) ;
2008-04-18 02:46:23 +04:00
void ide_port_scan ( ide_hwif_t * hwif )
{
ide_port_cable_detect ( hwif ) ;
ide_port_init_devices ( hwif ) ;
if ( ide_probe_port ( hwif ) < 0 )
return ;
hwif - > present = 1 ;
ide_port_tune_devices ( hwif ) ;
ide_acpi_port_init_devices ( hwif ) ;
ide_port_setup_devices ( hwif ) ;
hwif_register_devices ( hwif ) ;
ide_proc_port_register_devices ( hwif ) ;
}
EXPORT_SYMBOL_GPL ( ide_port_scan ) ;