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 )
{
2008-10-11 00:39:19 +04:00
u16 * id = drive - > id ;
id [ ATA_ID_CUR_CYLS ] = id [ ATA_ID_CYLS ] = drive - > cyl ;
id [ ATA_ID_CUR_HEADS ] = id [ ATA_ID_HEADS ] = drive - > head ;
id [ ATA_ID_CUR_SECTORS ] = id [ ATA_ID_SECTORS ] = drive - > sect ;
2005-04-17 02:20:36 +04:00
}
static void ide_disk_init_chs ( ide_drive_t * drive )
{
2008-10-11 00:39:19 +04:00
u16 * id = drive - > id ;
2005-04-17 02:20:36 +04:00
/* Extract geometry if we did not already have one for the drive */
if ( ! drive - > cyl | | ! drive - > head | | ! drive - > sect ) {
2008-10-11 00:39:19 +04:00
drive - > cyl = drive - > bios_cyl = id [ ATA_ID_CYLS ] ;
drive - > head = drive - > bios_head = id [ ATA_ID_HEADS ] ;
drive - > sect = drive - > bios_sect = id [ ATA_ID_SECTORS ] ;
2005-04-17 02:20:36 +04:00
}
/* Handle logical geometry translation by the drive */
2008-10-11 00:39:19 +04:00
if ( ata_id_current_chs_valid ( id ) ) {
2008-10-11 00:39:19 +04:00
drive - > cyl = id [ ATA_ID_CUR_CYLS ] ;
drive - > head = id [ ATA_ID_CUR_HEADS ] ;
drive - > sect = id [ ATA_ID_CUR_SECTORS ] ;
2005-04-17 02:20:36 +04:00
}
/* Use physical geometry if what we have still makes no sense */
2008-10-11 00:39:19 +04:00
if ( drive - > head > 16 & & id [ ATA_ID_HEADS ] & & id [ ATA_ID_HEADS ] < = 16 ) {
drive - > cyl = id [ ATA_ID_CYLS ] ;
drive - > head = id [ ATA_ID_HEADS ] ;
drive - > sect = id [ ATA_ID_SECTORS ] ;
2005-04-17 02:20:36 +04:00
}
}
static void ide_disk_init_mult_count ( ide_drive_t * drive )
{
2008-10-11 00:39:19 +04:00
u16 * id = drive - > id ;
u8 max_multsect = id [ ATA_ID_MAX_MULTSECT ] & 0xff ;
2005-04-17 02:20:36 +04:00
2008-10-11 00:39:19 +04:00
if ( max_multsect ) {
if ( ( max_multsect / 2 ) > 1 )
id [ ATA_ID_MULTSECT ] = max_multsect | 0x100 ;
else
id [ ATA_ID_MULTSECT ] & = ~ 0x1ff ;
drive - > mult_req = id [ ATA_ID_MULTSECT ] & 0xff ;
2008-10-11 00:39:26 +04:00
if ( drive - > mult_req )
2008-10-11 00:39:18 +04:00
drive - > special . b . set_multmode = 1 ;
2005-04-17 02:20:36 +04:00
}
}
/**
* 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 ) ;
2008-10-11 00:39:19 +04:00
u16 * id = drive - > id ;
char * m = ( char * ) & id [ ATA_ID_PROD ] ;
2008-10-11 00:39:31 +04:00
int bswap = 1 , is_cfa ;
2005-04-17 02:20:36 +04:00
/* read 512 bytes of id info */
2008-07-23 21:55:56 +04:00
hwif - > tp_ops - > input_data ( drive , NULL , id , SECTOR_SIZE ) ;
2005-04-17 02:20:36 +04:00
2008-10-13 23:39:36 +04:00
drive - > dev_flags | = IDE_DFLAG_ID_READ ;
2005-04-17 02:20:36 +04:00
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 ) ;
/*
2008-10-11 00:39:21 +04:00
* ATA_CMD_ID_ATA returns little - endian info ,
* ATA_CMD_ID_ATAPI * usually * returns little - endian info .
2005-04-17 02:20:36 +04:00
*/
2008-10-11 00:39:21 +04:00
if ( cmd = = ATA_CMD_ID_ATAPI ) {
2008-10-11 00:39:19 +04:00
if ( ( m [ 0 ] = = ' N ' & & m [ 1 ] = = ' E ' ) | | /* NEC */
( m [ 0 ] = = ' F ' & & m [ 1 ] = = ' X ' ) | | /* Mitsumi */
( m [ 0 ] = = ' P ' & & m [ 1 ] = = ' i ' ) ) /* Pioneer */
2005-04-17 02:20:36 +04:00
/* Vertos drives may still be weird */
2008-10-11 00:39:19 +04:00
bswap ^ = 1 ;
2005-04-17 02:20:36 +04:00
}
2008-10-11 00:39:19 +04:00
ide_fixstring ( m , ATA_ID_PROD_LEN , bswap ) ;
ide_fixstring ( ( char * ) & id [ ATA_ID_FW_REV ] , ATA_ID_FW_REV_LEN , bswap ) ;
ide_fixstring ( ( char * ) & id [ ATA_ID_SERNO ] , ATA_ID_SERNO_LEN , bswap ) ;
2005-04-17 02:20:36 +04:00
2007-11-05 23:42:25 +03:00
/* we depend on this a lot! */
2008-10-11 00:39:19 +04:00
m [ ATA_ID_PROD_LEN - 1 ] = ' \0 ' ;
2007-11-05 23:42:25 +03:00
2008-10-11 00:39:19 +04:00
if ( strstr ( m , " E X A B Y T E N E S T " ) )
2005-04-17 02:20:36 +04:00
goto err_misc ;
2008-10-11 00:39:19 +04:00
printk ( KERN_INFO " %s: %s, " , drive - > name , m ) ;
2008-07-25 00:53:36 +04:00
2008-10-13 23:39:36 +04:00
drive - > dev_flags | = IDE_DFLAG_PRESENT ;
drive - > dev_flags & = ~ IDE_DFLAG_DEAD ;
2005-04-17 02:20:36 +04:00
/*
* Check for an ATAPI device
*/
2008-10-11 00:39:21 +04:00
if ( cmd = = ATA_CMD_ID_ATAPI ) {
2008-10-11 00:39:19 +04:00
u8 type = ( id [ ATA_ID_CONFIG ] > > 8 ) & 0x1f ;
2008-07-25 00:53:36 +04:00
printk ( KERN_CONT " ATAPI " ) ;
2005-04-17 02:20:36 +04:00
switch ( type ) {
case ide_floppy :
2008-10-11 00:39:19 +04:00
if ( ! strstr ( m , " CD-ROM " ) ) {
if ( ! strstr ( m , " oppy " ) & &
! strstr ( m , " poyp " ) & &
! strstr ( m , " ZIP " ) )
2008-07-25 00:53:36 +04:00
printk ( KERN_CONT " cdrom or floppy?, assuming " ) ;
2005-04-17 02:20:36 +04:00
if ( drive - > media ! = ide_cdrom ) {
2008-07-25 00:53:36 +04:00
printk ( KERN_CONT " FLOPPY " ) ;
2008-10-13 23:39:36 +04:00
drive - > dev_flags | = IDE_DFLAG_REMOVABLE ;
2005-04-17 02:20:36 +04:00
break ;
}
}
/* Early cdrom models used zero */
type = ide_cdrom ;
case ide_cdrom :
2008-10-13 23:39:36 +04:00
drive - > dev_flags | = IDE_DFLAG_REMOVABLE ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_PPC
/* kludge for Apple PowerBook internal zip */
2008-10-11 00:39:19 +04:00
if ( ! strstr ( m , " CD-ROM " ) & & strstr ( m , " ZIP " ) ) {
2008-07-25 00:53:36 +04:00
printk ( KERN_CONT " FLOPPY " ) ;
2005-04-17 02:20:36 +04:00
type = ide_floppy ;
break ;
}
# endif
2008-07-25 00:53:36 +04:00
printk ( KERN_CONT " CD/DVD-ROM " ) ;
2005-04-17 02:20:36 +04:00
break ;
case ide_tape :
2008-07-25 00:53:36 +04:00
printk ( KERN_CONT " TAPE " ) ;
2005-04-17 02:20:36 +04:00
break ;
case ide_optical :
2008-07-25 00:53:36 +04:00
printk ( KERN_CONT " OPTICAL " ) ;
2008-10-13 23:39:36 +04:00
drive - > dev_flags | = IDE_DFLAG_REMOVABLE ;
2005-04-17 02:20:36 +04:00
break ;
default :
2008-07-25 00:53:36 +04:00
printk ( KERN_CONT " UNKNOWN (type %d) " , type ) ;
2005-04-17 02:20:36 +04:00
break ;
}
2008-07-25 00:53:36 +04:00
printk ( KERN_CONT " drive \n " ) ;
2005-04-17 02:20:36 +04:00
drive - > media = type ;
/* an ATAPI device ignores DRDY */
drive - > ready_stat = 0 ;
2008-10-13 23:39:43 +04:00
if ( ata_id_cdb_intr ( id ) )
drive - > atapi_flags | = IDE_AFLAG_DRQ_INTERRUPT ;
2008-10-13 23:39:50 +04:00
/* we don't do head unloading on ATAPI devices */
drive - > dev_flags | = IDE_DFLAG_NO_UNLOAD ;
2005-04-17 02:20:36 +04:00
return ;
}
/*
* Not an ATAPI device : looks like a " regular " hard disk
*/
2006-02-03 14:04:55 +03:00
2008-10-11 00:39:31 +04:00
is_cfa = ata_id_is_cfa ( id ) ;
/* CF devices are *not* removable in Linux definition of the term */
if ( is_cfa = = 0 & & ( id [ ATA_ID_CONFIG ] & ( 1 < < 7 ) ) )
2008-10-13 23:39:36 +04:00
drive - > dev_flags | = IDE_DFLAG_REMOVABLE ;
2005-04-17 02:20:36 +04:00
drive - > media = ide_disk ;
2008-07-25 00:53:36 +04:00
2008-10-13 23:39:50 +04:00
if ( ! ata_id_has_unload ( drive - > id ) )
drive - > dev_flags | = IDE_DFLAG_NO_UNLOAD ;
2008-10-11 00:39:31 +04:00
printk ( KERN_CONT " %s DISK drive \n " , is_cfa ? " CFA " : " ATA " ) ;
2008-01-26 00:17:13 +03:00
2005-04-17 02:20:36 +04:00
return ;
err_misc :
kfree ( id ) ;
2008-10-13 23:39:36 +04:00
drive - > dev_flags & = ~ IDE_DFLAG_PRESENT ;
2005-04-17 02:20:36 +04:00
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-04-27 17:38:32 +04:00
struct ide_io_ports * io_ports = & hwif - > io_ports ;
2008-07-23 21:55:56 +04:00
const struct ide_tp_ops * tp_ops = hwif - > tp_ops ;
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 ) ;
2008-04-27 17:38:32 +04:00
if ( io_ports - > ctl_addr ) {
2008-07-23 21:55:56 +04:00
a = tp_ops - > read_altstatus ( hwif ) ;
s = tp_ops - > read_status ( hwif ) ;
2008-10-11 00:39:21 +04:00
if ( ( a ^ s ) & ~ ATA_IDX )
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
*/
2008-10-11 00:39:21 +04:00
if ( cmd = = ATA_CMD_ID_ATAPI ) {
2008-07-23 21:55:53 +04:00
ide_task_t task ;
memset ( & task , 0 , sizeof ( task ) ) ;
/* disable DMA & overlap */
task . tf_flags = IDE_TFLAG_OUT_FEATURE ;
2008-07-23 21:55:56 +04:00
tp_ops - > tf_load ( drive , & task ) ;
2008-07-23 21:55:53 +04:00
}
2005-04-17 02:20:36 +04:00
/* ask drive for ID */
2008-07-23 21:55:56 +04:00
tp_ops - > exec_command ( hwif , cmd ) ;
2005-04-17 02:20:36 +04:00
2008-10-11 00:39:21 +04:00
timeout = ( ( cmd = = ATA_CMD_ID_ATA ) ? WAIT_WORSTCASE : WAIT_PIDENTIFY ) / 2 ;
2008-10-11 00:39:23 +04:00
if ( ide_busy_sleep ( hwif , timeout , use_altstatus ) )
return 1 ;
2005-04-17 02:20:36 +04:00
2008-10-11 00:39:21 +04:00
/* wait for IRQ and ATA_DRQ */
2005-04-17 02:20:36 +04:00
msleep ( 50 ) ;
2008-07-23 21:55:56 +04:00
s = tp_ops - > read_status ( hwif ) ;
2008-02-06 04:57:51 +03:00
2008-10-11 00:39:21 +04:00
if ( OK_STAT ( s , ATA_DRQ , 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-07-23 21:55:56 +04:00
( void ) tp_ops - > read_status ( hwif ) ;
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 ) ;
2008-07-23 21:55:56 +04:00
const struct ide_tp_ops * tp_ops = hwif - > tp_ops ;
2005-04-17 02:20:36 +04:00
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 .
*/
2008-04-27 17:38:32 +04:00
if ( hwif - > io_ports . ctl_addr ) {
2005-04-17 02:20:36 +04:00
if ( ! hwif - > irq ) {
autoprobe = 1 ;
cookie = probe_irq_on ( ) ;
}
2008-07-23 21:55:56 +04:00
tp_ops - > set_irq ( hwif , 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
2008-07-23 21:55:56 +04:00
tp_ops - > set_irq ( hwif , 0 ) ;
2005-04-17 02:20:36 +04:00
/* clear drive IRQ */
2008-07-23 21:55:56 +04:00
( void ) tp_ops - > read_status ( hwif ) ;
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
*/
2008-07-25 00:53:36 +04:00
printk ( KERN_ERR " %s: IRQ probe failed (0x%lx) \n " ,
2005-04-17 02:20:36 +04:00
drive - > name , cookie ) ;
}
}
}
return retval ;
}
2008-10-11 00:39:23 +04:00
int ide_busy_sleep ( ide_hwif_t * hwif , unsigned long timeout , int altstatus )
2008-01-26 22:13:09 +03:00
{
u8 stat ;
2008-10-11 00:39:23 +04:00
timeout + = jiffies ;
2008-01-26 22:13:09 +03:00
do {
2008-10-11 00:39:23 +04:00
msleep ( 50 ) ; /* give drive a breather */
stat = altstatus ? hwif - > tp_ops - > read_altstatus ( hwif )
: hwif - > tp_ops - > read_status ( hwif ) ;
2008-10-11 00:39:21 +04:00
if ( ( stat & ATA_BUSY ) = = 0 )
2008-01-26 22:13:09 +03:00
return 0 ;
} while ( time_before ( jiffies , timeout ) ) ;
2008-10-11 00:39:23 +04:00
return 1 ; /* drive timed-out */
2008-01-26 22:13:09 +03:00
}
2005-04-17 02:20:36 +04:00
2008-07-23 21:55:54 +04:00
static u8 ide_read_device ( ide_drive_t * drive )
{
ide_task_t task ;
memset ( & task , 0 , sizeof ( task ) ) ;
task . tf_flags = IDE_TFLAG_IN_DEVICE ;
2008-07-23 21:55:56 +04:00
drive - > hwif - > tp_ops - > tf_read ( drive , & task ) ;
2008-07-23 21:55:54 +04:00
return task . tf . device ;
}
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-07-23 21:55:56 +04:00
const struct ide_tp_ops * tp_ops = hwif - > tp_ops ;
2008-02-02 21:56:45 +03:00
int rc ;
2008-10-13 23:39:36 +04:00
u8 present = ! ! ( drive - > dev_flags & IDE_DFLAG_PRESENT ) , stat ;
/* avoid waiting for inappropriate probes */
if ( present & & drive - > media ! = ide_disk & & cmd = = ATA_CMD_ID_ATA )
return 4 ;
2005-04-17 02:20:36 +04:00
# ifdef DEBUG
2008-07-25 00:53:36 +04:00
printk ( KERN_INFO " probing for %s: present=%d, media=%d, probetype=%s \n " ,
2008-10-13 23:39:36 +04:00
drive - > name , present , drive - > media ,
2008-10-11 00:39:21 +04:00
( cmd = = ATA_CMD_ID_ATA ) ? " ATA " : " ATAPI " ) ;
2005-04-17 02:20:36 +04:00
# endif
/* needed for some systems
* ( e . g . crw9624 as drive0 with disk as slave )
*/
msleep ( 50 ) ;
SELECT_DRIVE ( drive ) ;
msleep ( 50 ) ;
2008-07-23 21:55:54 +04:00
2008-10-13 23:39:40 +04:00
if ( ide_read_device ( drive ) ! = drive - > select & & present = = 0 ) {
2008-10-13 23:39:40 +04:00
if ( drive - > dn & 1 ) {
2005-04-17 02:20:36 +04:00
/* exit with drive0 selected */
SELECT_DRIVE ( & hwif - > drives [ 0 ] ) ;
2008-10-11 00:39:21 +04:00
/* allow ATA_BUSY to assert & clear */
2005-04-17 02:20:36 +04:00
msleep ( 50 ) ;
}
/* no i/f present: mmm.. this should be a 4 -ml */
return 3 ;
}
2008-07-23 21:55:56 +04:00
stat = tp_ops - > read_status ( hwif ) ;
2008-02-06 04:57:51 +03:00
2008-10-11 00:39:21 +04:00
if ( OK_STAT ( stat , ATA_DRDY , ATA_BUSY ) | |
2008-10-13 23:39:36 +04:00
present | | cmd = = ATA_CMD_ID_ATAPI ) {
2005-04-17 02:20:36 +04:00
/* 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-07-23 21:55:56 +04:00
stat = tp_ops - > read_status ( hwif ) ;
2008-02-02 21:56:45 +03:00
2008-10-11 00:39:21 +04:00
if ( stat = = ( ATA_BUSY | ATA_DRDY ) )
2005-04-17 02:20:36 +04:00
return 4 ;
2008-10-11 00:39:21 +04:00
if ( rc = = 1 & & cmd = = ATA_CMD_ID_ATAPI ) {
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 ) ;
2008-07-15 23:21:48 +04:00
SELECT_DRIVE ( drive ) ;
2005-04-17 02:20:36 +04:00
msleep ( 50 ) ;
2008-10-11 00:39:21 +04:00
tp_ops - > exec_command ( hwif , ATA_CMD_DEV_RESET ) ;
2008-10-11 00:39:23 +04:00
( void ) ide_busy_sleep ( hwif , WAIT_WORSTCASE , 0 ) ;
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-07-23 21:55:56 +04:00
stat = tp_ops - > read_status ( hwif ) ;
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 ;
}
2008-10-13 23:39:40 +04:00
if ( drive - > dn & 1 ) {
2005-04-17 02:20:36 +04:00
/* exit with drive0 selected */
SELECT_DRIVE ( & hwif - > drives [ 0 ] ) ;
msleep ( 50 ) ;
/* ensure drive irq is clear */
2008-07-23 21:55:56 +04:00
( void ) tp_ops - > read_status ( hwif ) ;
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-07-23 21:55:56 +04:00
const struct ide_tp_ops * tp_ops = hwif - > tp_ops ;
2008-02-02 21:56:45 +03:00
u8 stat ;
2005-04-17 02:20:36 +04:00
2008-10-11 00:39:19 +04:00
printk ( KERN_INFO " %s: enabling %s -- " ,
hwif - > name , ( char * ) & drive - > id [ ATA_ID_PROD ] ) ;
2008-07-25 00:53:36 +04:00
2005-04-17 02:20:36 +04:00
SELECT_DRIVE ( drive ) ;
msleep ( 50 ) ;
2008-10-11 00:39:21 +04:00
tp_ops - > exec_command ( hwif , ATA_EXABYTE_ENABLE_NEST ) ;
2008-01-26 22:13:09 +03:00
2008-10-11 00:39:23 +04:00
if ( ide_busy_sleep ( hwif , WAIT_WORSTCASE , 0 ) ) {
2008-01-26 22:13:09 +03:00
printk ( KERN_CONT " failed (timeout) \n " ) ;
return ;
}
2005-04-17 02:20:36 +04:00
msleep ( 50 ) ;
2008-07-23 21:55:56 +04:00
stat = tp_ops - > read_status ( hwif ) ;
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
}
/**
* 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
2008-10-13 23:39:36 +04:00
* 1 device was found
* ( note : IDE_DFLAG_PRESENT might still be not set )
2005-04-17 02:20:36 +04:00
*/
static inline u8 probe_for_drive ( ide_drive_t * drive )
{
2008-10-11 00:39:19 +04:00
char * m ;
2005-04-17 02:20:36 +04:00
/*
* 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 "
*/
2008-10-13 23:39:36 +04:00
drive - > dev_flags & = ~ IDE_DFLAG_ID_READ ;
2008-10-11 00:39:28 +04:00
drive - > id = kzalloc ( SECTOR_SIZE , GFP_KERNEL ) ;
2008-10-13 23:39:36 +04:00
if ( drive - > id = = NULL ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " ide: out of memory for id data. \n " ) ;
return 0 ;
}
2008-10-11 00:39:19 +04:00
m = ( char * ) & drive - > id [ ATA_ID_PROD ] ;
strcpy ( m , " UNKNOWN " ) ;
2005-04-17 02:20:36 +04:00
/* skip probing? */
2008-10-13 23:39:36 +04:00
if ( ( drive - > dev_flags & IDE_DFLAG_NOPROBE ) = = 0 ) {
2008-10-11 00:39:23 +04:00
retry :
2005-04-17 02:20:36 +04:00
/* if !(success||timed-out) */
2008-10-11 00:39:21 +04:00
if ( do_probe ( drive , ATA_CMD_ID_ATA ) > = 2 )
2005-04-17 02:20:36 +04:00
/* look for ATAPI device */
2008-10-11 00:39:21 +04:00
( void ) do_probe ( drive , ATA_CMD_ID_ATAPI ) ;
2008-10-11 00:39:23 +04:00
2008-10-13 23:39:36 +04:00
if ( ( drive - > dev_flags & IDE_DFLAG_PRESENT ) = = 0 )
2005-04-17 02:20:36 +04:00
/* drive not found */
return 0 ;
2008-10-11 00:39:19 +04:00
2008-10-11 00:39:23 +04:00
if ( strstr ( m , " E X A B Y T E N E S T " ) ) {
2007-07-04 00:28:35 +04:00
enable_nest ( drive ) ;
2008-10-11 00:39:23 +04:00
goto retry ;
}
2005-04-17 02:20:36 +04:00
/* identification failed? */
2008-10-13 23:39:36 +04:00
if ( ( drive - > dev_flags & IDE_DFLAG_ID_READ ) = = 0 ) {
2005-04-17 02:20:36 +04:00
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 ) ;
2008-10-13 23:39:36 +04:00
drive - > dev_flags & = ~ IDE_DFLAG_PRESENT ;
2005-04-17 02:20:36 +04:00
}
}
/* drive was found */
}
2008-10-13 23:39:36 +04:00
if ( ( drive - > dev_flags & IDE_DFLAG_PRESENT ) = = 0 )
2005-04-17 02:20:36 +04:00
return 0 ;
2008-10-13 23:39:36 +04:00
2005-04-17 02:20:36 +04:00
/* The drive wasn't being helpful. Add generic info only */
2008-10-13 23:39:36 +04:00
if ( ( drive - > dev_flags & IDE_DFLAG_ID_READ ) = = 0 ) {
2005-04-17 02:20:36 +04:00
generic_id ( drive ) ;
return 1 ;
}
if ( drive - > media = = ide_disk ) {
ide_disk_init_chs ( drive ) ;
ide_disk_init_mult_count ( drive ) ;
}
2008-10-13 23:39:36 +04:00
return ! ! ( drive - > dev_flags & IDE_DFLAG_PRESENT ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-23 21:56:02 +04:00
static void hwif_release_dev ( struct device * dev )
2005-04-17 02:20:36 +04:00
{
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 " ,
2008-04-27 00:25:20 +04:00
__func__ , ret ) ;
2008-04-18 02:46:23 +04:00
goto out ;
}
2008-07-22 07:03:34 +04:00
hwif - > portdev = device_create ( ide_port_class , & hwif - > gendev ,
MKDEV ( 0 , 0 ) , hwif , hwif - > name ) ;
2008-04-18 02:46:23 +04:00
if ( IS_ERR ( hwif - > portdev ) ) {
ret = PTR_ERR ( hwif - > portdev ) ;
device_unregister ( & hwif - > gendev ) ;
}
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. */
2008-10-13 23:39:36 +04:00
if ( ( drive - > dev_flags & IDE_DFLAG_NOPROBE ) = = 0 | |
( drive - > dev_flags & IDE_DFLAG_PRESENT ) ) {
2007-11-27 23:35:53 +03:00
SELECT_DRIVE ( drive ) ;
2008-07-23 21:55:56 +04:00
hwif - > tp_ops - > set_irq ( hwif , 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-10-11 00:39:19 +04:00
* @ dev1 : slave device
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-10-11 00:39:19 +04:00
void ide_undecoded_slave ( ide_drive_t * dev1 )
2005-04-17 02:20:36 +04:00
{
2008-10-11 00:39:19 +04:00
ide_drive_t * dev0 = & dev1 - > hwif - > drives [ 0 ] ;
2005-04-17 02:20:36 +04:00
2008-10-13 23:39:36 +04:00
if ( ( dev1 - > dn & 1 ) = = 0 | | ( dev0 - > dev_flags & IDE_DFLAG_PRESENT ) = = 0 )
2005-04-17 02:20:36 +04:00
return ;
/* If the models don't match they are not the same product */
2008-10-11 00:39:19 +04:00
if ( strcmp ( ( char * ) & dev0 - > id [ ATA_ID_PROD ] ,
( char * ) & dev1 - > id [ ATA_ID_PROD ] ) )
2005-04-17 02:20:36 +04:00
return ;
/* Serial numbers do not match */
2008-10-11 00:39:19 +04:00
if ( strncmp ( ( char * ) & dev0 - > id [ ATA_ID_SERNO ] ,
( char * ) & dev1 - > id [ ATA_ID_SERNO ] , ATA_ID_SERNO_LEN ) )
2005-04-17 02:20:36 +04:00
return ;
/* No serial number, thankfully very rare for CF */
2008-10-11 00:39:19 +04:00
if ( * ( char * ) & dev0 - > id [ ATA_ID_SERNO ] = = 0 )
2005-04-17 02:20:36 +04:00
return ;
/* Appears to be an IDE flash adapter with decode bugs */
printk ( KERN_WARNING " ide-probe: ignoring undecoded slave \n " ) ;
2008-10-13 23:39:36 +04:00
dev1 - > dev_flags & = ~ IDE_DFLAG_PRESENT ;
2005-04-17 02:20:36 +04:00
}
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-10-13 23:39:36 +04:00
if ( ( hwif - > drives [ 0 ] . dev_flags & IDE_DFLAG_NOPROBE ) & &
( hwif - > drives [ 1 ] . dev_flags & IDE_DFLAG_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 ] ;
2008-10-13 23:39:40 +04:00
2005-04-17 02:20:36 +04:00
( void ) probe_for_drive ( drive ) ;
2008-10-13 23:39:36 +04:00
if ( drive - > dev_flags & IDE_DFLAG_PRESENT )
2008-02-02 01:09:36 +03:00
rc = 0 ;
2005-04-17 02:20:36 +04:00
}
2008-04-27 17:38:24 +04:00
2005-04-17 02:20:36 +04:00
local_irq_restore ( flags ) ;
2008-04-27 17:38:24 +04:00
2005-04-17 02:20:36 +04:00
/*
* 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 )
{
2008-04-27 00:25:14 +04:00
const struct ide_port_ops * port_ops = hwif - > port_ops ;
2008-02-02 01:09:36 +03:00
int unit ;
2008-01-26 22:13:03 +03:00
for ( unit = 0 ; unit < MAX_DRIVES ; unit + + ) {
ide_drive_t * drive = & hwif - > drives [ unit ] ;
2008-10-13 23:39:36 +04:00
if ( drive - > dev_flags & IDE_DFLAG_PRESENT ) {
if ( port_ops & & port_ops - > quirkproc )
port_ops - > quirkproc ( drive ) ;
}
2008-01-26 22:13:03 +03:00
}
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 ] ;
2008-10-13 23:39:36 +04:00
if ( drive - > dev_flags & IDE_DFLAG_PRESENT ) {
2008-04-27 17:38:29 +04:00
ide_set_max_pio ( drive ) ;
2005-04-17 02:20:36 +04:00
2008-10-13 23:39:36 +04:00
drive - > dev_flags | = IDE_DFLAG_NICE1 ;
2005-04-17 02:20:36 +04:00
2008-04-27 00:25:24 +04:00
if ( hwif - > dma_ops )
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-10-13 23:39:36 +04:00
if ( ( hwif - > host_flags & IDE_HFLAG_NO_IO_32BIT ) | |
drive - > id [ ATA_ID_DWORD_IO ] )
drive - > dev_flags | = IDE_DFLAG_NO_IO_32BIT ;
2006-03-24 14:18:21 +03:00
else
2008-10-13 23:39:36 +04:00
drive - > dev_flags & = ~ IDE_DFLAG_NO_IO_32BIT ;
2006-03-24 14:18:21 +03:00
}
2005-04-17 02:20:36 +04:00
}
/*
* 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 ;
2008-07-25 00:53:36 +04:00
printk ( KERN_WARNING " %s: potential IRQ problem with %s and %s \n " ,
2005-04-17 02:20:36 +04:00
hwif - > name , new - > name , m - > name ) ;
}
if ( ! m | | m - > irq ! = hwif - > irq ) /* don't undo a prior perfect match */
* match = new ;
}
/*
* 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
*/
2008-10-13 23:39:45 +04:00
static int ide_port_setup_devices ( ide_hwif_t * hwif )
2008-02-02 21:56:41 +03:00
{
2008-10-13 23:39:45 +04:00
int i , j = 0 ;
2008-02-02 21:56:41 +03:00
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 ] ;
2008-10-13 23:39:36 +04:00
if ( ( drive - > dev_flags & IDE_DFLAG_PRESENT ) = = 0 )
2008-02-02 21:56:41 +03:00
continue ;
if ( ide_init_queue ( drive ) ) {
printk ( KERN_ERR " ide: failed to init %s \n " ,
drive - > name ) ;
2008-10-13 23:39:45 +04:00
kfree ( drive - > id ) ;
drive - > id = NULL ;
drive - > dev_flags & = ~ IDE_DFLAG_PRESENT ;
2008-02-02 21:56:41 +03:00
continue ;
}
2008-10-13 23:39:45 +04:00
j + + ;
2008-02-02 21:56:41 +03:00
ide_add_drive_to_hwgroup ( drive ) ;
}
2008-04-18 02:46:22 +04:00
mutex_unlock ( & ide_cfg_mtx ) ;
2008-10-13 23:39:45 +04:00
return j ;
2008-02-02 21:56:41 +03:00
}
2008-07-23 21:55:58 +04:00
static ide_hwif_t * ide_ports [ MAX_HWIFS ] ;
2008-07-23 21:55:58 +04:00
void ide_remove_port_from_hwgroup ( ide_hwif_t * hwif )
{
ide_hwgroup_t * hwgroup = hwif - > hwgroup ;
2008-07-23 21:55:58 +04:00
ide_ports [ hwif - > index ] = NULL ;
2008-07-23 21:55:58 +04:00
spin_lock_irq ( & ide_lock ) ;
/*
* Remove us from the hwgroup , and free
* the hwgroup if we were the only member
*/
if ( hwif - > next = = hwif ) {
BUG_ON ( hwgroup - > hwif ! = hwif ) ;
kfree ( hwgroup ) ;
} else {
/* There is another interface in hwgroup.
* Unlink us , and set hwgroup - > drive and - > hwif to
* something sane .
*/
ide_hwif_t * g = hwgroup - > hwif ;
while ( g - > next ! = hwif )
g = g - > next ;
g - > next = hwif - > next ;
if ( hwgroup - > hwif = = hwif ) {
/* Chose a random hwif for hwgroup->hwif.
* It ' s guaranteed that there are no drives
* left in the hwgroup .
*/
BUG_ON ( hwgroup - > drive ! = NULL ) ;
hwgroup - > hwif = g ;
}
BUG_ON ( hwgroup - > hwif = = hwif ) ;
}
spin_unlock_irq ( & ide_lock ) ;
}
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 )
{
2008-04-27 17:38:32 +04:00
struct ide_io_ports * io_ports = & hwif - > io_ports ;
2005-04-17 02:20:36 +04:00
unsigned int index ;
ide_hwgroup_t * hwgroup ;
ide_hwif_t * match = 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 ;
2008-10-13 23:39:33 +04:00
2005-04-17 02:20:36 +04:00
/*
* Group up with any other hwifs that share our irq ( s ) .
*/
for ( index = 0 ; index < MAX_HWIFS ; index + + ) {
2008-07-23 21:55:58 +04:00
ide_hwif_t * h = ide_ports [ index ] ;
if ( h & & h - > hwgroup ) { /* scan only initialized ports */
2005-04-17 02:20:36 +04:00
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 ) ;
}
}
}
2008-10-13 23:39:33 +04:00
2005-04-17 02:20:36 +04:00
/*
* 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 ;
}
2008-07-23 21:55:58 +04:00
ide_ports [ hwif - > index ] = hwif ;
2005-04-17 02:20:36 +04:00
/*
* 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-10-11 00:39:24 +04:00
if ( hwif - > chipset = = ide_pci | | hwif - > chipset = = ide_cmd646 | |
hwif - > chipset = = ide_ali14xx )
2006-07-02 06:29:34 +04:00
sa = IRQF_SHARED ;
2005-04-17 02:20:36 +04:00
2008-04-27 17:38:32 +04:00
if ( io_ports - > ctl_addr )
2008-07-23 21:55:56 +04:00
hwif - > tp_ops - > set_irq ( hwif , 1 ) ;
2005-04-17 02:20:36 +04:00
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__)
2008-07-25 00:53:36 +04:00
printk ( KERN_INFO " %s at 0x%03lx-0x%03lx,0x%03lx on irq %d " , hwif - > name ,
2008-04-27 17:38:32 +04:00
io_ports - > data_addr , io_ports - > status_addr ,
io_ports - > ctl_addr , hwif - > irq ) ;
2005-04-17 02:20:36 +04:00
# else
2008-07-25 00:53:36 +04:00
printk ( KERN_INFO " %s at 0x%08lx on irq %d " , hwif - > name ,
2008-04-27 17:38:32 +04:00
io_ports - > data_addr , hwif - > irq ) ;
2008-02-06 12:36:29 +03:00
# endif /* __mc68000__ */
2005-04-17 02:20:36 +04:00
if ( match )
2008-07-25 00:53:36 +04:00
printk ( KERN_CONT " (%sed with %s) " ,
2005-04-17 02:20:36 +04:00
hwif - > sharing_irq ? " shar " : " serializ " , match - > name ) ;
2008-07-25 00:53:36 +04:00
printk ( KERN_CONT " \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 ] ;
2008-10-13 23:39:36 +04:00
if ( ( drive - > dev_flags & IDE_DFLAG_PRESENT ) = = 0 )
2005-04-17 02:20:36 +04:00
return NULL ;
if ( drive - > media = = ide_disk )
request_module ( " ide-disk " ) ;
2008-10-13 23:39:36 +04:00
if ( drive - > dev_flags & IDE_DFLAG_SCSI )
2005-04-17 02:20:36 +04:00
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 ;
2008-08-25 14:56:05 +04:00
return & disk_to_dev ( p ) - > 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 ;
2008-10-13 23:39:40 +04:00
unsigned int unit = drive - > dn & 1 ;
2005-04-17 02:20:36 +04:00
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 ;
2008-10-13 23:39:36 +04:00
drive - > dev_flags & = ~ IDE_DFLAG_PRESENT ;
2005-05-26 16:55:34 +04:00
/* 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 ) {
2008-07-08 21:27:22 +04:00
hwif - > irq = __ide_default_irq ( hwif - > io_ports . data_addr ) ;
2008-04-27 17:38:32 +04:00
if ( ! hwif - > irq ) {
2008-07-25 00:53:36 +04:00
printk ( KERN_ERR " %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 .
*/
2008-07-08 21:27:22 +04:00
hwif - > irq = __ide_default_irq ( hwif - > io_ports . data_addr ) ;
2008-04-27 17:38:32 +04:00
if ( ! hwif - > irq ) {
2008-07-25 00:53:36 +04:00
printk ( KERN_ERR " %s: disabled, unable to get IRQ %d \n " ,
2005-04-17 02:20:36 +04:00
hwif - > name , old_irq ) ;
goto out ;
}
if ( init_irq ( hwif ) ) {
2008-07-25 00:53:36 +04:00
printk ( KERN_ERR " %s: probed IRQ %d and default IRQ %d failed \n " ,
2005-04-17 02:20:36 +04:00
hwif - > name , old_irq , hwif - > irq ) ;
goto out ;
}
2008-07-25 00:53:36 +04:00
printk ( KERN_WARNING " %s: probed IRQ %d failed, using default \n " ,
2005-04-17 02:20:36 +04:00
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-10-13 23:39:36 +04:00
if ( ( drive - > dev_flags & IDE_DFLAG_PRESENT ) = = 0 )
2008-02-02 21:56:41 +03:00
continue ;
2007-10-20 02:32:29 +04:00
2008-02-02 21:56:41 +03:00
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 )
{
2008-04-27 00:25:14 +04:00
const struct ide_port_ops * port_ops = hwif - > port_ops ;
2008-02-02 21:56:39 +03:00
int i ;
for ( i = 0 ; i < MAX_DRIVES ; i + + ) {
ide_drive_t * drive = & hwif - > drives [ i ] ;
2008-10-13 23:39:40 +04:00
drive - > dn = i + hwif - > channel * 2 ;
2008-02-02 21:56:39 +03:00
if ( hwif - > host_flags & IDE_HFLAG_IO_32BIT )
drive - > io_32bit = 1 ;
if ( hwif - > host_flags & IDE_HFLAG_UNMASK_IRQS )
2008-10-13 23:39:36 +04:00
drive - > dev_flags | = IDE_DFLAG_UNMASK ;
2008-02-02 21:56:40 +03:00
if ( hwif - > host_flags & IDE_HFLAG_NO_UNMASK_IRQS )
2008-10-13 23:39:36 +04:00
drive - > dev_flags | = IDE_DFLAG_NO_UNMASK ;
2008-02-02 21:56:40 +03:00
2008-07-16 22:33:42 +04:00
if ( port_ops & & port_ops - > init_dev )
port_ops - > init_dev ( drive ) ;
}
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-06-10 22:56:36 +04:00
hwif - > channel = port ;
2008-02-02 21:56:31 +03:00
if ( d - > chipset )
hwif - > chipset = d - > chipset ;
if ( d - > init_iops )
d - > init_iops ( hwif ) ;
if ( ( ! hwif - > irq & & ( d - > host_flags & IDE_HFLAG_LEGACY_IRQS ) ) | |
( d - > host_flags & IDE_HFLAG_FORCE_LEGACY_IRQS ) )
hwif - > irq = port ? 15 : 14 ;
ide: fix early setup of hwif->host_flags
On Thursday 01 May 2008, Jeremy Kerr wrote:
> Hi all,
>
> On QS20 Cell machines, Linus' current git tree explodes on boot:
>
> SiI680: IDE controller (0x1095:0x0680 rev 0x02) at PCI slot
> 0000:00:0a.0
> SiI680: BASE CLOCK == 133
> SiI680: 100% native mode on irq 51
> ide0: MMIO-DMA
> ide1: MMIO-DMA
> Unable to handle kernel paging request for data at address
> 0xa000100081220080
> Faulting instruction address: 0xc000000000024748
> cpu 0x2: Vector: 300 (Data Access) at [c00000001e143420]
> pc: c000000000024748: ._insw_ns+0x10/0x30
> lr: c000000000037fc4: .spiderpci_readsw+0x24/0x6c
> sp: c00000001e1436a0
> msr: 9000000000001032
> dar: a000100081220080
> dsisr: 40000000
> current = 0xc00000003d060000
> paca = 0xc000000000623880
> pid = 1, comm = swapper
> enter ? for help
> [link register ] c000000000037fc4 .spiderpci_readsw+0x24/0x6c
> [c00000001e1436a0] c00000000062ce63 (unreliable)
> [c00000001e143730] c0000000000379d4 .iowa_readsw+0x78/0xa8
> [c00000001e1437c0] c000000000037a98 .iowa_insw+0x94/0xd4
> [c00000001e143850] c00000000022a190 .ata_input_data+0x298/0x2ec
> [c00000001e143910] c00000000022b600 .try_to_identify+0x2c0/0x6d4
> [c00000001e1439d0] c00000000022bb54 .do_probe+0x140/0x35c
> [c00000001e143a80] c00000000022bfbc .ide_probe_port+0x24c/0x670
> [c00000001e143b50] c00000000022d09c .ide_device_add_all+0x2ec/0x690
> [c00000001e143c00] c00000000022d4a4 .ide_device_add+0x64/0x74
> [c00000001e143c90] c00000000022f834 .ide_setup_pci_device+0x58/0x7c
> [c00000001e143d30] c00000000038bdf8
> [c00000001e143e10] c000000000486fb0 .ide_scan_pcibus+0x8c/0x178
> [c00000001e143ea0] c000000000460c00 .kernel_init+0x1c4/0x344
> [c00000001e143f90] c000000000024a1c .kernel_thread+0x4c/0x68
>
> It looks like we're trying to do PIO accesses (which appear to be
> broken, but that's another issue) to this MMIO device. In
> ata_input_data, we see that:
>
> u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
>
> Gives mmio == 0.
>
> (what's the difference between hwif->mmio and ID_HFLAG_MMIO?)
>
> In the siimage driver, hwif->host flags is initially set up correctly
> (host_flags includes IDE_HFLAG_MMIO), but we then *clear* this bit in
> ide_init_port:
>
> hwif->host_flags = d->host_flags;
>
> where d is the struct ide_port_info for this chipset. In my case,
> d->host_flags is 0x0. It looks like this will be the same for all of
> the siimage chipsets.
Don't over-write hwif->host_flags in ide_init_port(), some host drivers
set IDE_HFLAG_MMIO or IDE_HFLAG_NO_IO_32BIT host flag early.
Thanks to Jeremy Kerr for the excellent analysis of the bug.
Reported-by: Jeremy Kerr <jk@ozlabs.org>
Tested-by: Jeremy Kerr <jk@ozlabs.org>
Cc: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Cc: Ben Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
2008-05-01 16:08:51 +04:00
/* ->host_flags may be set by ->init_iops (or even earlier...) */
hwif - > host_flags | = d - > host_flags ;
2008-02-02 21:56:31 +03:00
hwif - > pio_mask = d - > pio_mask ;
2008-07-23 21:55:56 +04:00
if ( d - > tp_ops )
hwif - > tp_ops = d - > tp_ops ;
2008-04-27 00:25:14 +04:00
/* ->set_pio_mode for DTC2278 is currently limited to port 0 */
if ( hwif - > chipset ! = ide_dtc2278 | | hwif - > channel = = 0 )
hwif - > port_ops = d - > port_ops ;
2008-02-02 21:56:31 +03:00
hwif - > swdma_mask = d - > swdma_mask ;
hwif - > mwdma_mask = d - > mwdma_mask ;
hwif - > ultra_mask = d - > udma_mask ;
2008-04-27 00:25:22 +04:00
if ( ( d - > host_flags & IDE_HFLAG_NO_DMA ) = = 0 ) {
int rc ;
if ( d - > init_dma )
rc = d - > init_dma ( hwif , d ) ;
else
rc = ide_hwif_setup_dma ( hwif , d ) ;
if ( rc < 0 ) {
printk ( KERN_INFO " %s: DMA disabled \n " , hwif - > name ) ;
2008-07-23 21:55:51 +04:00
hwif - > dma_base = 0 ;
2008-04-27 00:25:22 +04:00
hwif - > swdma_mask = 0 ;
hwif - > mwdma_mask = 0 ;
hwif - > ultra_mask = 0 ;
2008-04-27 00:25:24 +04:00
} else if ( d - > dma_ops )
hwif - > dma_ops = d - > dma_ops ;
2008-04-27 00:25:22 +04:00
}
2008-02-02 21:56:31 +03:00
2008-05-04 19:03:41 +04:00
if ( ( d - > host_flags & IDE_HFLAG_SERIALIZE ) | |
( ( d - > host_flags & IDE_HFLAG_SERIALIZE_DMA ) & & hwif - > dma_base ) ) {
if ( hwif - > mate )
hwif - > mate - > serialized = hwif - > serialized = 1 ;
}
2008-02-02 21:56:31 +03:00
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-04-27 00:25:14 +04:00
const struct ide_port_ops * port_ops = hwif - > port_ops ;
if ( port_ops & & port_ops - > cable_detect & & ( hwif - > ultra_mask & 0x78 ) ) {
2008-02-02 21:56:31 +03:00
if ( hwif - > cbl ! = ATA_CBL_PATA40_SHORT )
2008-04-27 00:25:14 +04:00
hwif - > cbl = port_ops - > cable_detect ( hwif ) ;
2008-02-02 21:56:31 +03:00
}
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 )
{
2008-10-05 20:23:28 +04:00
int i , uninitialized_var ( rc ) ;
2008-04-18 02:46:23 +04:00
for ( i = 0 ; ide_port_attrs [ i ] ; i + + ) {
rc = device_create_file ( hwif - > portdev , ide_port_attrs [ i ] ) ;
if ( rc )
break ;
}
return rc ;
}
2008-07-23 21:55:57 +04:00
static unsigned int ide_indexes ;
2008-04-26 19:36:36 +04:00
/**
2008-07-23 21:55:57 +04:00
* ide_find_port_slot - find free port slot
2008-04-26 19:36:36 +04:00
* @ d : IDE port info
*
2008-07-23 21:55:57 +04:00
* Return the new port slot index or - ENOENT if we are out of free slots .
2008-04-26 19:36:36 +04:00
*/
2008-07-23 21:55:57 +04:00
static int ide_find_port_slot ( const struct ide_port_info * d )
2008-04-26 19:36:36 +04:00
{
2008-07-23 21:55:57 +04:00
int idx = - ENOENT ;
2008-04-26 19:36:36 +04:00
u8 bootable = ( d & & ( d - > host_flags & IDE_HFLAG_NON_BOOTABLE ) ) ? 0 : 1 ;
2008-07-23 21:55:57 +04:00
u8 i = ( d & & ( d - > host_flags & IDE_HFLAG_QD_2ND_PORT ) ) ? 1 : 0 ; ;
2008-04-26 19:36:36 +04:00
/*
* Claim an unassigned slot .
*
* Give preference to claiming other slots before claiming ide0 / ide1 ,
* just in case there ' s another interface yet - to - be - scanned
* which uses ports 0x1f0 / 0x170 ( the ide0 / ide1 defaults ) .
*
* Unless there is a bootable card that does not use the standard
* ports 0x1f0 / 0x170 ( the ide0 / ide1 defaults ) .
*/
2008-07-23 21:55:57 +04:00
mutex_lock ( & ide_cfg_mtx ) ;
2008-10-13 23:39:33 +04:00
if ( bootable ) {
if ( ( ide_indexes | i ) ! = ( 1 < < MAX_HWIFS ) - 1 )
idx = ffz ( ide_indexes | i ) ;
2008-04-26 19:36:36 +04:00
} else {
2008-10-13 23:39:33 +04:00
if ( ( ide_indexes | 3 ) ! = ( 1 < < MAX_HWIFS ) - 1 )
idx = ffz ( ide_indexes | 3 ) ;
else if ( ( ide_indexes & 3 ) ! = 3 )
idx = ffz ( ide_indexes ) ;
2008-04-26 19:36:36 +04:00
}
2008-07-23 21:55:57 +04:00
if ( idx > = 0 )
ide_indexes | = ( 1 < < idx ) ;
mutex_unlock ( & ide_cfg_mtx ) ;
2008-04-26 19:36:36 +04:00
2008-07-23 21:55:57 +04:00
return idx ;
}
2008-07-16 22:33:39 +04:00
2008-07-23 21:55:57 +04:00
static void ide_free_port_slot ( int idx )
{
mutex_lock ( & ide_cfg_mtx ) ;
ide_indexes & = ~ ( 1 < < idx ) ;
mutex_unlock ( & ide_cfg_mtx ) ;
2008-04-26 19:36:36 +04:00
}
2008-10-13 23:39:43 +04:00
struct ide_host * ide_host_alloc ( const struct ide_port_info * d , hw_regs_t * * hws )
2008-07-23 21:55:57 +04:00
{
struct ide_host * host ;
int i ;
host = kzalloc ( sizeof ( * host ) , GFP_KERNEL ) ;
if ( host = = NULL )
return NULL ;
2008-10-13 23:39:43 +04:00
for ( i = 0 ; i < MAX_HOST_PORTS ; i + + ) {
2008-07-23 21:55:57 +04:00
ide_hwif_t * hwif ;
2008-07-23 21:55:57 +04:00
int idx ;
2008-07-23 21:55:57 +04:00
if ( hws [ i ] = = NULL )
continue ;
2008-07-23 21:55:58 +04:00
hwif = kzalloc ( sizeof ( * hwif ) , GFP_KERNEL ) ;
if ( hwif = = NULL )
continue ;
2008-07-23 21:55:57 +04:00
idx = ide_find_port_slot ( d ) ;
if ( idx < 0 ) {
printk ( KERN_ERR " %s: no free slot for interface \n " ,
d ? d - > name : " ide " ) ;
2008-07-23 21:55:58 +04:00
kfree ( hwif ) ;
2008-07-23 21:55:57 +04:00
continue ;
2008-07-23 21:55:57 +04:00
}
2008-07-23 21:55:57 +04:00
ide_init_port_data ( hwif , idx ) ;
2008-07-25 00:53:15 +04:00
hwif - > host = host ;
2008-07-23 21:55:57 +04:00
host - > ports [ i ] = hwif ;
host - > n_ports + + ;
2008-07-23 21:55:57 +04:00
}
if ( host - > n_ports = = 0 ) {
kfree ( host ) ;
return NULL ;
}
2008-07-25 00:53:14 +04:00
if ( hws [ 0 ] )
host - > dev [ 0 ] = hws [ 0 ] - > dev ;
2008-10-11 00:39:32 +04:00
if ( d ) {
host - > init_chipset = d - > init_chipset ;
2008-07-25 00:53:19 +04:00
host - > host_flags = d - > host_flags ;
2008-10-11 00:39:32 +04:00
}
2008-07-25 00:53:19 +04:00
2008-07-23 21:55:57 +04:00
return host ;
}
EXPORT_SYMBOL_GPL ( ide_host_alloc ) ;
int ide_host_register ( struct ide_host * host , const struct ide_port_info * d ,
hw_regs_t * * hws )
2008-02-02 21:56:31 +03:00
{
ide_hwif_t * hwif , * mate = NULL ;
2008-07-23 21:55:57 +04:00
int i , j = 0 ;
2007-10-20 02:32:31 +04:00
2008-10-13 23:39:43 +04:00
for ( i = 0 ; i < MAX_HOST_PORTS ; i + + ) {
2008-07-23 21:55:57 +04:00
hwif = host - > ports [ i ] ;
2008-07-23 21:55:57 +04:00
2008-07-23 21:55:57 +04:00
if ( hwif = = NULL ) {
2008-02-02 21:56:31 +03:00
mate = NULL ;
continue ;
}
2008-07-23 21:55:50 +04:00
ide_init_port_hw ( hwif , hws [ i ] ) ;
2008-04-27 17:38:23 +04:00
ide_port_apply_params ( hwif ) ;
if ( d = = NULL ) {
mate = NULL ;
2008-10-13 23:39:40 +04:00
} else {
if ( ( i & 1 ) & & mate ) {
hwif - > mate = mate ;
mate - > mate = hwif ;
}
2008-04-27 17:38:23 +04:00
2008-10-13 23:39:40 +04:00
mate = ( i & 1 ) ? NULL : hwif ;
2008-02-02 21:56:31 +03:00
2008-10-13 23:39:40 +04:00
ide_init_port ( hwif , i & 1 , d ) ;
ide_port_cable_detect ( hwif ) ;
}
2008-02-02 21:56:31 +03:00
2008-02-02 21:56:39 +03:00
ide_port_init_devices ( hwif ) ;
2008-02-02 21:56:31 +03:00
}
2008-10-13 23:39:43 +04:00
for ( i = 0 ; i < MAX_HOST_PORTS ; i + + ) {
2008-07-23 21:55:57 +04:00
hwif = host - > ports [ i ] ;
2008-01-26 22:13:04 +03:00
2008-07-23 21:55:57 +04:00
if ( hwif = = NULL )
continue ;
2008-02-02 01:09:36 +03:00
2008-04-27 00:25:17 +04:00
if ( ide_probe_port ( hwif ) = = 0 )
hwif - > present = 1 ;
2008-02-02 01:09:36 +03:00
if ( hwif - > chipset ! = ide_4drives | | ! hwif - > mate | |
! hwif - > mate - > present )
ide_register_port ( hwif ) ;
2008-04-27 00:25:17 +04:00
if ( hwif - > present )
ide_port_tune_devices ( hwif ) ;
2008-01-26 22:13:04 +03:00
}
2008-01-26 22:13:04 +03:00
2008-10-13 23:39:43 +04:00
for ( i = 0 ; i < MAX_HOST_PORTS ; i + + ) {
2008-07-23 21:55:57 +04:00
hwif = host - > ports [ i ] ;
2008-01-26 22:13:04 +03:00
2008-07-23 21:55:57 +04:00
if ( hwif = = NULL )
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
continue ;
}
2008-02-02 21:56:41 +03:00
2008-04-27 00:25:17 +04:00
if ( hwif - > present )
2008-10-13 23:39:45 +04:00
if ( ide_port_setup_devices ( hwif ) = = 0 ) {
hwif - > present = 0 ;
continue ;
}
j + + ;
2008-04-18 02:46:22 +04:00
2008-02-02 21:56:41 +03:00
ide_acpi_init ( hwif ) ;
2008-04-27 00:25:17 +04:00
if ( hwif - > present )
ide_acpi_port_init_devices ( hwif ) ;
2008-01-26 22:13:04 +03:00
}
2008-10-13 23:39:43 +04:00
for ( i = 0 ; i < MAX_HOST_PORTS ; i + + ) {
2008-07-23 21:55:57 +04:00
hwif = host - > ports [ i ] ;
2008-01-26 22:13:04 +03:00
2008-07-23 21:55:57 +04:00
if ( hwif = = NULL )
continue ;
2008-01-26 22:13:04 +03:00
2008-04-27 00:25:17 +04:00
if ( hwif - > chipset = = ide_unknown )
hwif - > chipset = ide_generic ;
if ( hwif - > present )
2008-01-26 22:13:04 +03:00
hwif_register_devices ( hwif ) ;
2007-10-20 02:32:31 +04:00
}
2008-10-13 23:39:43 +04:00
for ( i = 0 ; i < MAX_HOST_PORTS ; i + + ) {
2008-07-23 21:55:57 +04:00
hwif = host - > ports [ i ] ;
2008-02-02 21:56:43 +03:00
2008-07-23 21:55:57 +04:00
if ( hwif = = NULL )
continue ;
2008-02-02 21:56:43 +03:00
2008-04-27 00:25:17 +04:00
ide_sysfs_register_port ( hwif ) ;
ide_proc_register_port ( hwif ) ;
if ( hwif - > present )
2008-02-02 21:56:43 +03:00
ide_proc_port_register_devices ( hwif ) ;
2007-10-20 02:32:31 +04:00
}
2008-07-23 21:55:57 +04:00
return j ? 0 : - 1 ;
2007-10-20 02:32:31 +04:00
}
2008-07-23 21:55:57 +04:00
EXPORT_SYMBOL_GPL ( ide_host_register ) ;
2008-01-26 22:13:05 +03:00
ide: add ide_host_add() helper
Add ide_host_add() helper which does ide_host_alloc()+ide_host_register(),
then convert ide_setup_pci_device[s](), ide_legacy_device_add() and some
host drivers to use it.
While at it:
* Fix ide_setup_pci_device[s](), ide_arm.c, gayle.c, ide-4drives.c,
macide.c, q40ide.c, cmd640.c and cs5520.c to return correct error value.
* -ENOENT -> -ENOMEM in rapide.c, ide-h8300.c, ide-generic.c, au1xxx-ide.c
and pmac.c
* -ENODEV -> -ENOMEM in palm_bk3710.c, ide_platform.c and delkin_cb.c
* -1 -> -ENOMEM in ide-pnp.c
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
2008-07-23 21:55:57 +04:00
int ide_host_add ( const struct ide_port_info * d , hw_regs_t * * hws ,
struct ide_host * * hostp )
{
struct ide_host * host ;
2008-07-23 21:55:59 +04:00
int rc ;
ide: add ide_host_add() helper
Add ide_host_add() helper which does ide_host_alloc()+ide_host_register(),
then convert ide_setup_pci_device[s](), ide_legacy_device_add() and some
host drivers to use it.
While at it:
* Fix ide_setup_pci_device[s](), ide_arm.c, gayle.c, ide-4drives.c,
macide.c, q40ide.c, cmd640.c and cs5520.c to return correct error value.
* -ENOENT -> -ENOMEM in rapide.c, ide-h8300.c, ide-generic.c, au1xxx-ide.c
and pmac.c
* -ENODEV -> -ENOMEM in palm_bk3710.c, ide_platform.c and delkin_cb.c
* -1 -> -ENOMEM in ide-pnp.c
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
2008-07-23 21:55:57 +04:00
host = ide_host_alloc ( d , hws ) ;
if ( host = = NULL )
return - ENOMEM ;
2008-07-23 21:55:59 +04:00
rc = ide_host_register ( host , d , hws ) ;
if ( rc ) {
ide_host_free ( host ) ;
return rc ;
}
ide: add ide_host_add() helper
Add ide_host_add() helper which does ide_host_alloc()+ide_host_register(),
then convert ide_setup_pci_device[s](), ide_legacy_device_add() and some
host drivers to use it.
While at it:
* Fix ide_setup_pci_device[s](), ide_arm.c, gayle.c, ide-4drives.c,
macide.c, q40ide.c, cmd640.c and cs5520.c to return correct error value.
* -ENOENT -> -ENOMEM in rapide.c, ide-h8300.c, ide-generic.c, au1xxx-ide.c
and pmac.c
* -ENODEV -> -ENOMEM in palm_bk3710.c, ide_platform.c and delkin_cb.c
* -1 -> -ENOMEM in ide-pnp.c
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
2008-07-23 21:55:57 +04:00
if ( hostp )
* hostp = host ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( ide_host_add ) ;
2008-07-23 21:55:59 +04:00
void ide_host_free ( struct ide_host * host )
2008-01-26 22:13:05 +03:00
{
2008-07-23 21:55:57 +04:00
ide_hwif_t * hwif ;
2008-01-26 22:13:05 +03:00
int i ;
2007-10-20 02:32:31 +04:00
2008-10-13 23:39:43 +04:00
for ( i = 0 ; i < MAX_HOST_PORTS ; i + + ) {
2008-07-23 21:55:57 +04:00
hwif = host - > ports [ i ] ;
if ( hwif = = NULL )
continue ;
ide_free_port_slot ( hwif - > index ) ;
2008-07-23 21:55:58 +04:00
kfree ( hwif ) ;
2008-07-23 21:55:50 +04:00
}
2008-01-26 22:13:05 +03:00
2008-07-23 21:55:57 +04:00
kfree ( host ) ;
2008-01-26 22:13:05 +03:00
}
2008-07-23 21:55:59 +04:00
EXPORT_SYMBOL_GPL ( ide_host_free ) ;
void ide_host_remove ( struct ide_host * host )
{
int i ;
2008-10-13 23:39:43 +04:00
for ( i = 0 ; i < MAX_HOST_PORTS ; i + + ) {
2008-07-23 21:55:59 +04:00
if ( host - > ports [ i ] )
ide_unregister ( host - > ports [ i ] ) ;
}
ide_host_free ( host ) ;
}
2008-07-23 21:55:57 +04:00
EXPORT_SYMBOL_GPL ( ide_host_remove ) ;
2008-04-18 02:46:23 +04:00
void ide_port_scan ( ide_hwif_t * hwif )
{
2008-04-27 17:38:23 +04:00
ide_port_apply_params ( hwif ) ;
2008-04-18 02:46:23 +04:00
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 ) ;
2008-04-27 00:25:16 +04:00
2008-07-23 21:55:57 +04:00
static void ide_legacy_init_one ( hw_regs_t * * hws , hw_regs_t * hw ,
2008-07-23 21:55:50 +04:00
u8 port_no , const struct ide_port_info * d ,
2008-04-27 00:25:18 +04:00
unsigned long config )
2008-04-27 00:25:16 +04:00
{
2008-04-27 00:25:18 +04:00
unsigned long base , ctl ;
int irq ;
2008-04-27 00:25:16 +04:00
2008-04-27 00:25:18 +04:00
if ( port_no = = 0 ) {
base = 0x1f0 ;
ctl = 0x3f6 ;
irq = 14 ;
} else {
base = 0x170 ;
ctl = 0x376 ;
irq = 15 ;
}
2008-04-27 00:25:16 +04:00
2008-04-27 00:25:18 +04:00
if ( ! request_region ( base , 8 , d - > name ) ) {
printk ( KERN_ERR " %s: I/O resource 0x%lX-0x%lX not free. \n " ,
d - > name , base , base + 7 ) ;
return ;
}
if ( ! request_region ( ctl , 1 , d - > name ) ) {
printk ( KERN_ERR " %s: I/O resource 0x%lX not free. \n " ,
d - > name , ctl ) ;
release_region ( base , 8 ) ;
return ;
}
2008-04-27 00:25:18 +04:00
ide_std_init_ports ( hw , base , ctl ) ;
hw - > irq = irq ;
2008-06-10 22:56:37 +04:00
hw - > chipset = d - > chipset ;
2008-07-23 21:55:56 +04:00
hw - > config = config ;
2008-04-27 00:25:16 +04:00
2008-07-23 21:55:57 +04:00
hws [ port_no ] = hw ;
2008-04-27 00:25:18 +04:00
}
2008-04-27 00:25:16 +04:00
2008-04-27 00:25:18 +04:00
int ide_legacy_device_add ( const struct ide_port_info * d , unsigned long config )
{
2008-07-23 21:55:50 +04:00
hw_regs_t hw [ 2 ] , * hws [ ] = { NULL , NULL , NULL , NULL } ;
2008-04-27 00:25:16 +04:00
2008-04-27 00:25:18 +04:00
memset ( & hw , 0 , sizeof ( hw ) ) ;
if ( ( d - > host_flags & IDE_HFLAG_QD_2ND_PORT ) = = 0 )
2008-07-23 21:55:57 +04:00
ide_legacy_init_one ( hws , & hw [ 0 ] , 0 , d , config ) ;
ide_legacy_init_one ( hws , & hw [ 1 ] , 1 , d , config ) ;
2008-04-27 00:25:18 +04:00
2008-07-23 21:55:57 +04:00
if ( hws [ 0 ] = = NULL & & hws [ 1 ] = = NULL & &
2008-04-27 00:25:18 +04:00
( d - > host_flags & IDE_HFLAG_SINGLE ) )
return - ENOENT ;
2008-04-27 00:25:16 +04:00
ide: add ide_host_add() helper
Add ide_host_add() helper which does ide_host_alloc()+ide_host_register(),
then convert ide_setup_pci_device[s](), ide_legacy_device_add() and some
host drivers to use it.
While at it:
* Fix ide_setup_pci_device[s](), ide_arm.c, gayle.c, ide-4drives.c,
macide.c, q40ide.c, cmd640.c and cs5520.c to return correct error value.
* -ENOENT -> -ENOMEM in rapide.c, ide-h8300.c, ide-generic.c, au1xxx-ide.c
and pmac.c
* -ENODEV -> -ENOMEM in palm_bk3710.c, ide_platform.c and delkin_cb.c
* -1 -> -ENOMEM in ide-pnp.c
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
2008-07-23 21:55:57 +04:00
return ide_host_add ( d , hws , NULL ) ;
2008-04-27 00:25:16 +04:00
}
EXPORT_SYMBOL_GPL ( ide_legacy_device_add ) ;