2005-04-17 02:20:36 +04:00
/*
* Copyright ( C ) 2000 - 2002 Andre Hedrick < andre @ linux - ide . org >
* Copyright ( C ) 2003 Red Hat < alan @ redhat . com >
*
*/
# 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/blkpg.h>
# include <linux/slab.h>
# include <linux/pci.h>
# include <linux/delay.h>
# include <linux/hdreg.h>
# include <linux/ide.h>
# include <linux/bitops.h>
2006-07-30 14:03:29 +04:00
# include <linux/nmi.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>
/*
* Conventional PIO operations for ATA devices
*/
static u8 ide_inb ( unsigned long port )
{
return ( u8 ) inb ( port ) ;
}
static void ide_outb ( u8 val , unsigned long port )
{
outb ( val , port ) ;
}
static void ide_outbsync ( ide_drive_t * drive , u8 addr , unsigned long port )
{
outb ( addr , port ) ;
}
void default_hwif_iops ( ide_hwif_t * hwif )
{
hwif - > OUTB = ide_outb ;
hwif - > OUTBSYNC = ide_outbsync ;
hwif - > INB = ide_inb ;
}
/*
* MMIO operations , typically used for SATA controllers
*/
static u8 ide_mm_inb ( unsigned long port )
{
return ( u8 ) readb ( ( void __iomem * ) port ) ;
}
static void ide_mm_outb ( u8 value , unsigned long port )
{
writeb ( value , ( void __iomem * ) port ) ;
}
static void ide_mm_outbsync ( ide_drive_t * drive , u8 value , unsigned long port )
{
writeb ( value , ( void __iomem * ) port ) ;
}
void default_hwif_mmiops ( ide_hwif_t * hwif )
{
hwif - > OUTB = ide_mm_outb ;
/* Most systems will need to override OUTBSYNC, alas however
this one is controller specific ! */
hwif - > OUTBSYNC = ide_mm_outbsync ;
hwif - > INB = ide_mm_inb ;
}
EXPORT_SYMBOL ( default_hwif_mmiops ) ;
void SELECT_DRIVE ( ide_drive_t * drive )
{
2008-04-18 02:46:26 +04:00
ide_hwif_t * hwif = drive - > hwif ;
2008-04-27 00:25:14 +04:00
const struct ide_port_ops * port_ops = hwif - > port_ops ;
2008-04-18 02:46:26 +04:00
2008-04-27 00:25:14 +04:00
if ( port_ops & & port_ops - > selectproc )
port_ops - > selectproc ( drive ) ;
2008-04-18 02:46:26 +04:00
2008-04-27 17:38:32 +04:00
hwif - > OUTB ( drive - > select . all , hwif - > io_ports . device_addr ) ;
2005-04-17 02:20:36 +04:00
}
2008-05-15 01:06:15 +04:00
static void SELECT_MASK ( ide_drive_t * drive , int mask )
2005-04-17 02:20:36 +04:00
{
2008-04-27 00:25:14 +04:00
const struct ide_port_ops * port_ops = drive - > hwif - > port_ops ;
if ( port_ops & & port_ops - > maskproc )
port_ops - > maskproc ( drive , mask ) ;
2005-04-17 02:20:36 +04:00
}
2008-04-29 01:44:40 +04:00
static void ide_tf_load ( ide_drive_t * drive , ide_task_t * task )
2008-04-29 01:44:39 +04:00
{
ide_hwif_t * hwif = drive - > hwif ;
struct ide_io_ports * io_ports = & hwif - > io_ports ;
struct ide_taskfile * tf = & task - > tf ;
2008-04-29 01:44:41 +04:00
void ( * tf_outb ) ( u8 addr , unsigned long port ) ;
u8 mmio = ( hwif - > host_flags & IDE_HFLAG_MMIO ) ? 1 : 0 ;
2008-04-29 01:44:39 +04:00
u8 HIHI = ( task - > tf_flags & IDE_TFLAG_LBA48 ) ? 0xE0 : 0xEF ;
2008-04-29 01:44:41 +04:00
if ( mmio )
tf_outb = ide_mm_outb ;
else
tf_outb = ide_outb ;
2008-04-29 01:44:39 +04:00
if ( task - > tf_flags & IDE_TFLAG_FLAGGED )
HIHI = 0xFF ;
ide_set_irq ( drive , 1 ) ;
2008-07-15 23:21:48 +04:00
SELECT_MASK ( drive , 0 ) ;
2008-04-29 01:44:39 +04:00
2008-04-29 01:44:41 +04:00
if ( task - > tf_flags & IDE_TFLAG_OUT_DATA ) {
u16 data = ( tf - > hob_data < < 8 ) | tf - > data ;
if ( mmio )
writew ( data , ( void __iomem * ) io_ports - > data_addr ) ;
else
outw ( data , io_ports - > data_addr ) ;
}
2008-04-29 01:44:39 +04:00
if ( task - > tf_flags & IDE_TFLAG_OUT_HOB_FEATURE )
2008-04-29 01:44:41 +04:00
tf_outb ( tf - > hob_feature , io_ports - > feature_addr ) ;
2008-04-29 01:44:39 +04:00
if ( task - > tf_flags & IDE_TFLAG_OUT_HOB_NSECT )
2008-04-29 01:44:41 +04:00
tf_outb ( tf - > hob_nsect , io_ports - > nsect_addr ) ;
2008-04-29 01:44:39 +04:00
if ( task - > tf_flags & IDE_TFLAG_OUT_HOB_LBAL )
2008-04-29 01:44:41 +04:00
tf_outb ( tf - > hob_lbal , io_ports - > lbal_addr ) ;
2008-04-29 01:44:39 +04:00
if ( task - > tf_flags & IDE_TFLAG_OUT_HOB_LBAM )
2008-04-29 01:44:41 +04:00
tf_outb ( tf - > hob_lbam , io_ports - > lbam_addr ) ;
2008-04-29 01:44:39 +04:00
if ( task - > tf_flags & IDE_TFLAG_OUT_HOB_LBAH )
2008-04-29 01:44:41 +04:00
tf_outb ( tf - > hob_lbah , io_ports - > lbah_addr ) ;
2008-04-29 01:44:39 +04:00
if ( task - > tf_flags & IDE_TFLAG_OUT_FEATURE )
2008-04-29 01:44:41 +04:00
tf_outb ( tf - > feature , io_ports - > feature_addr ) ;
2008-04-29 01:44:39 +04:00
if ( task - > tf_flags & IDE_TFLAG_OUT_NSECT )
2008-04-29 01:44:41 +04:00
tf_outb ( tf - > nsect , io_ports - > nsect_addr ) ;
2008-04-29 01:44:39 +04:00
if ( task - > tf_flags & IDE_TFLAG_OUT_LBAL )
2008-04-29 01:44:41 +04:00
tf_outb ( tf - > lbal , io_ports - > lbal_addr ) ;
2008-04-29 01:44:39 +04:00
if ( task - > tf_flags & IDE_TFLAG_OUT_LBAM )
2008-04-29 01:44:41 +04:00
tf_outb ( tf - > lbam , io_ports - > lbam_addr ) ;
2008-04-29 01:44:39 +04:00
if ( task - > tf_flags & IDE_TFLAG_OUT_LBAH )
2008-04-29 01:44:41 +04:00
tf_outb ( tf - > lbah , io_ports - > lbah_addr ) ;
2008-04-29 01:44:39 +04:00
if ( task - > tf_flags & IDE_TFLAG_OUT_DEVICE )
2008-04-29 01:44:41 +04:00
tf_outb ( ( tf - > device & HIHI ) | drive - > select . all ,
io_ports - > device_addr ) ;
2008-04-29 01:44:39 +04:00
}
2008-04-29 01:44:40 +04:00
static void ide_tf_read ( ide_drive_t * drive , ide_task_t * task )
2008-04-29 01:44:39 +04:00
{
ide_hwif_t * hwif = drive - > hwif ;
struct ide_io_ports * io_ports = & hwif - > io_ports ;
struct ide_taskfile * tf = & task - > tf ;
2008-04-29 01:44:41 +04:00
void ( * tf_outb ) ( u8 addr , unsigned long port ) ;
u8 ( * tf_inb ) ( unsigned long port ) ;
u8 mmio = ( hwif - > host_flags & IDE_HFLAG_MMIO ) ? 1 : 0 ;
if ( mmio ) {
tf_outb = ide_mm_outb ;
tf_inb = ide_mm_inb ;
} else {
tf_outb = ide_outb ;
tf_inb = ide_inb ;
}
2008-04-29 01:44:39 +04:00
if ( task - > tf_flags & IDE_TFLAG_IN_DATA ) {
2008-04-29 01:44:41 +04:00
u16 data ;
if ( mmio )
data = readw ( ( void __iomem * ) io_ports - > data_addr ) ;
else
data = inw ( io_ports - > data_addr ) ;
2008-04-29 01:44:39 +04:00
tf - > data = data & 0xff ;
tf - > hob_data = ( data > > 8 ) & 0xff ;
}
/* be sure we're looking at the low order bits */
2008-04-29 01:44:41 +04:00
tf_outb ( drive - > ctl & ~ 0x80 , io_ports - > ctl_addr ) ;
2008-04-29 01:44:39 +04:00
if ( task - > tf_flags & IDE_TFLAG_IN_NSECT )
2008-04-29 01:44:41 +04:00
tf - > nsect = tf_inb ( io_ports - > nsect_addr ) ;
2008-04-29 01:44:39 +04:00
if ( task - > tf_flags & IDE_TFLAG_IN_LBAL )
2008-04-29 01:44:41 +04:00
tf - > lbal = tf_inb ( io_ports - > lbal_addr ) ;
2008-04-29 01:44:39 +04:00
if ( task - > tf_flags & IDE_TFLAG_IN_LBAM )
2008-04-29 01:44:41 +04:00
tf - > lbam = tf_inb ( io_ports - > lbam_addr ) ;
2008-04-29 01:44:39 +04:00
if ( task - > tf_flags & IDE_TFLAG_IN_LBAH )
2008-04-29 01:44:41 +04:00
tf - > lbah = tf_inb ( io_ports - > lbah_addr ) ;
2008-04-29 01:44:39 +04:00
if ( task - > tf_flags & IDE_TFLAG_IN_DEVICE )
2008-04-29 01:44:41 +04:00
tf - > device = tf_inb ( io_ports - > device_addr ) ;
2008-04-29 01:44:39 +04:00
if ( task - > tf_flags & IDE_TFLAG_LBA48 ) {
2008-04-29 01:44:41 +04:00
tf_outb ( drive - > ctl | 0x80 , io_ports - > ctl_addr ) ;
2008-04-29 01:44:39 +04:00
if ( task - > tf_flags & IDE_TFLAG_IN_HOB_FEATURE )
2008-04-29 01:44:41 +04:00
tf - > hob_feature = tf_inb ( io_ports - > feature_addr ) ;
2008-04-29 01:44:39 +04:00
if ( task - > tf_flags & IDE_TFLAG_IN_HOB_NSECT )
2008-04-29 01:44:41 +04:00
tf - > hob_nsect = tf_inb ( io_ports - > nsect_addr ) ;
2008-04-29 01:44:39 +04:00
if ( task - > tf_flags & IDE_TFLAG_IN_HOB_LBAL )
2008-04-29 01:44:41 +04:00
tf - > hob_lbal = tf_inb ( io_ports - > lbal_addr ) ;
2008-04-29 01:44:39 +04:00
if ( task - > tf_flags & IDE_TFLAG_IN_HOB_LBAM )
2008-04-29 01:44:41 +04:00
tf - > hob_lbam = tf_inb ( io_ports - > lbam_addr ) ;
2008-04-29 01:44:39 +04:00
if ( task - > tf_flags & IDE_TFLAG_IN_HOB_LBAH )
2008-04-29 01:44:41 +04:00
tf - > hob_lbah = tf_inb ( io_ports - > lbah_addr ) ;
2008-04-29 01:44:39 +04:00
}
}
2005-04-17 02:20:36 +04:00
/*
* Some localbus EIDE interfaces require a special access sequence
* when using 32 - bit I / O instructions to transfer data . We call this
* the " vlb_sync " sequence , which consists of three successive reads
* of the sector count register location , with interrupts disabled
* to ensure that the reads all happen together .
*/
2008-04-29 01:44:41 +04:00
static void ata_vlb_sync ( unsigned long port )
2005-04-17 02:20:36 +04:00
{
2008-04-29 01:44:41 +04:00
( void ) inb ( port ) ;
( void ) inb ( port ) ;
( void ) inb ( port ) ;
2005-04-17 02:20:36 +04:00
}
/*
* This is used for most PIO data transfers * from * the IDE interface
2008-04-29 01:44:36 +04:00
*
* These routines will round up any request for an odd number of bytes ,
* so if an odd len is specified , be sure that there ' s at least one
* extra byte allocated for the buffer .
2005-04-17 02:20:36 +04:00
*/
2008-04-29 01:44:36 +04:00
static void ata_input_data ( ide_drive_t * drive , struct request * rq ,
2008-04-29 01:44:36 +04:00
void * buf , unsigned int len )
2005-04-17 02:20:36 +04:00
{
2008-04-27 17:38:32 +04:00
ide_hwif_t * hwif = drive - > hwif ;
struct ide_io_ports * io_ports = & hwif - > io_ports ;
2008-04-29 01:44:36 +04:00
unsigned long data_addr = io_ports - > data_addr ;
2008-04-27 17:38:32 +04:00
u8 io_32bit = drive - > io_32bit ;
ide: remove ->INS{W,L} and ->OUTS{W,L} methods
* Use ins{w,l}()/outs{w,l}() and __ide_mm_ins{w,l}()/__ide_mm_outs{w,l}()
directly in ata_{in,out}put_data() (by using IDE_HFLAG_MMIO host flag to
decide which I/O ops are required).
* Remove no longer needed ->INS{W,L} and ->OUTS{W,L} methods (ide-h8300,
au1xxx-ide and scc_pata implement their own ->{in,out}put_data methods).
There should be no functional changes caused by this patch.
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
2008-04-29 01:44:37 +04:00
u8 mmio = ( hwif - > host_flags & IDE_HFLAG_MMIO ) ? 1 : 0 ;
2005-04-17 02:20:36 +04:00
2008-04-29 01:44:36 +04:00
len + + ;
2005-04-17 02:20:36 +04:00
if ( io_32bit ) {
ide: remove ->INS{W,L} and ->OUTS{W,L} methods
* Use ins{w,l}()/outs{w,l}() and __ide_mm_ins{w,l}()/__ide_mm_outs{w,l}()
directly in ata_{in,out}put_data() (by using IDE_HFLAG_MMIO host flag to
decide which I/O ops are required).
* Remove no longer needed ->INS{W,L} and ->OUTS{W,L} methods (ide-h8300,
au1xxx-ide and scc_pata implement their own ->{in,out}put_data methods).
There should be no functional changes caused by this patch.
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
2008-04-29 01:44:37 +04:00
unsigned long uninitialized_var ( flags ) ;
2008-04-18 02:46:26 +04:00
2008-04-29 01:44:41 +04:00
if ( ( io_32bit & 2 ) & & ! mmio ) {
2005-04-17 02:20:36 +04:00
local_irq_save ( flags ) ;
2008-04-29 01:44:41 +04:00
ata_vlb_sync ( io_ports - > nsect_addr ) ;
ide: remove ->INS{W,L} and ->OUTS{W,L} methods
* Use ins{w,l}()/outs{w,l}() and __ide_mm_ins{w,l}()/__ide_mm_outs{w,l}()
directly in ata_{in,out}put_data() (by using IDE_HFLAG_MMIO host flag to
decide which I/O ops are required).
* Remove no longer needed ->INS{W,L} and ->OUTS{W,L} methods (ide-h8300,
au1xxx-ide and scc_pata implement their own ->{in,out}put_data methods).
There should be no functional changes caused by this patch.
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
2008-04-29 01:44:37 +04:00
}
if ( mmio )
__ide_mm_insl ( ( void __iomem * ) data_addr , buf , len / 4 ) ;
else
insl ( data_addr , buf , len / 4 ) ;
2008-04-29 01:44:41 +04:00
if ( ( io_32bit & 2 ) & & ! mmio )
2005-04-17 02:20:36 +04:00
local_irq_restore ( flags ) ;
2008-04-29 01:44:36 +04:00
ide: remove ->INS{W,L} and ->OUTS{W,L} methods
* Use ins{w,l}()/outs{w,l}() and __ide_mm_ins{w,l}()/__ide_mm_outs{w,l}()
directly in ata_{in,out}put_data() (by using IDE_HFLAG_MMIO host flag to
decide which I/O ops are required).
* Remove no longer needed ->INS{W,L} and ->OUTS{W,L} methods (ide-h8300,
au1xxx-ide and scc_pata implement their own ->{in,out}put_data methods).
There should be no functional changes caused by this patch.
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
2008-04-29 01:44:37 +04:00
if ( ( len & 3 ) > = 2 ) {
if ( mmio )
__ide_mm_insw ( ( void __iomem * ) data_addr ,
( u8 * ) buf + ( len & ~ 3 ) , 1 ) ;
else
insw ( data_addr , ( u8 * ) buf + ( len & ~ 3 ) , 1 ) ;
}
} else {
if ( mmio )
__ide_mm_insw ( ( void __iomem * ) data_addr , buf , len / 2 ) ;
else
insw ( data_addr , buf , len / 2 ) ;
}
2005-04-17 02:20:36 +04:00
}
/*
* This is used for most PIO data transfers * to * the IDE interface
*/
2008-04-29 01:44:36 +04:00
static void ata_output_data ( ide_drive_t * drive , struct request * rq ,
2008-04-29 01:44:36 +04:00
void * buf , unsigned int len )
2005-04-17 02:20:36 +04:00
{
2008-04-27 17:38:32 +04:00
ide_hwif_t * hwif = drive - > hwif ;
struct ide_io_ports * io_ports = & hwif - > io_ports ;
2008-04-29 01:44:36 +04:00
unsigned long data_addr = io_ports - > data_addr ;
2008-04-27 17:38:32 +04:00
u8 io_32bit = drive - > io_32bit ;
ide: remove ->INS{W,L} and ->OUTS{W,L} methods
* Use ins{w,l}()/outs{w,l}() and __ide_mm_ins{w,l}()/__ide_mm_outs{w,l}()
directly in ata_{in,out}put_data() (by using IDE_HFLAG_MMIO host flag to
decide which I/O ops are required).
* Remove no longer needed ->INS{W,L} and ->OUTS{W,L} methods (ide-h8300,
au1xxx-ide and scc_pata implement their own ->{in,out}put_data methods).
There should be no functional changes caused by this patch.
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
2008-04-29 01:44:37 +04:00
u8 mmio = ( hwif - > host_flags & IDE_HFLAG_MMIO ) ? 1 : 0 ;
2005-04-17 02:20:36 +04:00
if ( io_32bit ) {
ide: remove ->INS{W,L} and ->OUTS{W,L} methods
* Use ins{w,l}()/outs{w,l}() and __ide_mm_ins{w,l}()/__ide_mm_outs{w,l}()
directly in ata_{in,out}put_data() (by using IDE_HFLAG_MMIO host flag to
decide which I/O ops are required).
* Remove no longer needed ->INS{W,L} and ->OUTS{W,L} methods (ide-h8300,
au1xxx-ide and scc_pata implement their own ->{in,out}put_data methods).
There should be no functional changes caused by this patch.
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
2008-04-29 01:44:37 +04:00
unsigned long uninitialized_var ( flags ) ;
2008-04-18 02:46:26 +04:00
2008-04-29 01:44:41 +04:00
if ( ( io_32bit & 2 ) & & ! mmio ) {
2005-04-17 02:20:36 +04:00
local_irq_save ( flags ) ;
2008-04-29 01:44:41 +04:00
ata_vlb_sync ( io_ports - > nsect_addr ) ;
ide: remove ->INS{W,L} and ->OUTS{W,L} methods
* Use ins{w,l}()/outs{w,l}() and __ide_mm_ins{w,l}()/__ide_mm_outs{w,l}()
directly in ata_{in,out}put_data() (by using IDE_HFLAG_MMIO host flag to
decide which I/O ops are required).
* Remove no longer needed ->INS{W,L} and ->OUTS{W,L} methods (ide-h8300,
au1xxx-ide and scc_pata implement their own ->{in,out}put_data methods).
There should be no functional changes caused by this patch.
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
2008-04-29 01:44:37 +04:00
}
if ( mmio )
__ide_mm_outsl ( ( void __iomem * ) data_addr , buf , len / 4 ) ;
else
outsl ( data_addr , buf , len / 4 ) ;
2008-04-29 01:44:41 +04:00
if ( ( io_32bit & 2 ) & & ! mmio )
2005-04-17 02:20:36 +04:00
local_irq_restore ( flags ) ;
ide: remove ->INS{W,L} and ->OUTS{W,L} methods
* Use ins{w,l}()/outs{w,l}() and __ide_mm_ins{w,l}()/__ide_mm_outs{w,l}()
directly in ata_{in,out}put_data() (by using IDE_HFLAG_MMIO host flag to
decide which I/O ops are required).
* Remove no longer needed ->INS{W,L} and ->OUTS{W,L} methods (ide-h8300,
au1xxx-ide and scc_pata implement their own ->{in,out}put_data methods).
There should be no functional changes caused by this patch.
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
2008-04-29 01:44:37 +04:00
if ( ( len & 3 ) > = 2 ) {
if ( mmio )
__ide_mm_outsw ( ( void __iomem * ) data_addr ,
( u8 * ) buf + ( len & ~ 3 ) , 1 ) ;
else
outsw ( data_addr , ( u8 * ) buf + ( len & ~ 3 ) , 1 ) ;
}
} else {
if ( mmio )
__ide_mm_outsw ( ( void __iomem * ) data_addr , buf , len / 2 ) ;
else
outsw ( data_addr , buf , len / 2 ) ;
}
2005-04-17 02:20:36 +04:00
}
void default_hwif_transport ( ide_hwif_t * hwif )
{
2008-04-29 01:44:40 +04:00
hwif - > tf_load = ide_tf_load ;
hwif - > tf_read = ide_tf_read ;
2008-04-29 01:44:36 +04:00
hwif - > input_data = ata_input_data ;
hwif - > output_data = ata_output_data ;
2005-04-17 02:20:36 +04:00
}
void ide_fix_driveid ( struct hd_driveid * id )
{
# ifndef __LITTLE_ENDIAN
# ifdef __BIG_ENDIAN
int i ;
u16 * stringcast ;
id - > config = __le16_to_cpu ( id - > config ) ;
id - > cyls = __le16_to_cpu ( id - > cyls ) ;
id - > reserved2 = __le16_to_cpu ( id - > reserved2 ) ;
id - > heads = __le16_to_cpu ( id - > heads ) ;
id - > track_bytes = __le16_to_cpu ( id - > track_bytes ) ;
id - > sector_bytes = __le16_to_cpu ( id - > sector_bytes ) ;
id - > sectors = __le16_to_cpu ( id - > sectors ) ;
id - > vendor0 = __le16_to_cpu ( id - > vendor0 ) ;
id - > vendor1 = __le16_to_cpu ( id - > vendor1 ) ;
id - > vendor2 = __le16_to_cpu ( id - > vendor2 ) ;
stringcast = ( u16 * ) & id - > serial_no [ 0 ] ;
for ( i = 0 ; i < ( 20 / 2 ) ; i + + )
stringcast [ i ] = __le16_to_cpu ( stringcast [ i ] ) ;
id - > buf_type = __le16_to_cpu ( id - > buf_type ) ;
id - > buf_size = __le16_to_cpu ( id - > buf_size ) ;
id - > ecc_bytes = __le16_to_cpu ( id - > ecc_bytes ) ;
stringcast = ( u16 * ) & id - > fw_rev [ 0 ] ;
for ( i = 0 ; i < ( 8 / 2 ) ; i + + )
stringcast [ i ] = __le16_to_cpu ( stringcast [ i ] ) ;
stringcast = ( u16 * ) & id - > model [ 0 ] ;
for ( i = 0 ; i < ( 40 / 2 ) ; i + + )
stringcast [ i ] = __le16_to_cpu ( stringcast [ i ] ) ;
id - > dword_io = __le16_to_cpu ( id - > dword_io ) ;
id - > reserved50 = __le16_to_cpu ( id - > reserved50 ) ;
id - > field_valid = __le16_to_cpu ( id - > field_valid ) ;
id - > cur_cyls = __le16_to_cpu ( id - > cur_cyls ) ;
id - > cur_heads = __le16_to_cpu ( id - > cur_heads ) ;
id - > cur_sectors = __le16_to_cpu ( id - > cur_sectors ) ;
id - > cur_capacity0 = __le16_to_cpu ( id - > cur_capacity0 ) ;
id - > cur_capacity1 = __le16_to_cpu ( id - > cur_capacity1 ) ;
id - > lba_capacity = __le32_to_cpu ( id - > lba_capacity ) ;
id - > dma_1word = __le16_to_cpu ( id - > dma_1word ) ;
id - > dma_mword = __le16_to_cpu ( id - > dma_mword ) ;
id - > eide_pio_modes = __le16_to_cpu ( id - > eide_pio_modes ) ;
id - > eide_dma_min = __le16_to_cpu ( id - > eide_dma_min ) ;
id - > eide_dma_time = __le16_to_cpu ( id - > eide_dma_time ) ;
id - > eide_pio = __le16_to_cpu ( id - > eide_pio ) ;
id - > eide_pio_iordy = __le16_to_cpu ( id - > eide_pio_iordy ) ;
for ( i = 0 ; i < 2 ; + + i )
id - > words69_70 [ i ] = __le16_to_cpu ( id - > words69_70 [ i ] ) ;
for ( i = 0 ; i < 4 ; + + i )
id - > words71_74 [ i ] = __le16_to_cpu ( id - > words71_74 [ i ] ) ;
id - > queue_depth = __le16_to_cpu ( id - > queue_depth ) ;
for ( i = 0 ; i < 4 ; + + i )
id - > words76_79 [ i ] = __le16_to_cpu ( id - > words76_79 [ i ] ) ;
id - > major_rev_num = __le16_to_cpu ( id - > major_rev_num ) ;
id - > minor_rev_num = __le16_to_cpu ( id - > minor_rev_num ) ;
id - > command_set_1 = __le16_to_cpu ( id - > command_set_1 ) ;
id - > command_set_2 = __le16_to_cpu ( id - > command_set_2 ) ;
id - > cfsse = __le16_to_cpu ( id - > cfsse ) ;
id - > cfs_enable_1 = __le16_to_cpu ( id - > cfs_enable_1 ) ;
id - > cfs_enable_2 = __le16_to_cpu ( id - > cfs_enable_2 ) ;
id - > csf_default = __le16_to_cpu ( id - > csf_default ) ;
id - > dma_ultra = __le16_to_cpu ( id - > dma_ultra ) ;
id - > trseuc = __le16_to_cpu ( id - > trseuc ) ;
id - > trsEuc = __le16_to_cpu ( id - > trsEuc ) ;
id - > CurAPMvalues = __le16_to_cpu ( id - > CurAPMvalues ) ;
id - > mprc = __le16_to_cpu ( id - > mprc ) ;
id - > hw_config = __le16_to_cpu ( id - > hw_config ) ;
id - > acoustic = __le16_to_cpu ( id - > acoustic ) ;
id - > msrqs = __le16_to_cpu ( id - > msrqs ) ;
id - > sxfert = __le16_to_cpu ( id - > sxfert ) ;
id - > sal = __le16_to_cpu ( id - > sal ) ;
id - > spg = __le32_to_cpu ( id - > spg ) ;
id - > lba_capacity_2 = __le64_to_cpu ( id - > lba_capacity_2 ) ;
for ( i = 0 ; i < 22 ; i + + )
id - > words104_125 [ i ] = __le16_to_cpu ( id - > words104_125 [ i ] ) ;
id - > last_lun = __le16_to_cpu ( id - > last_lun ) ;
id - > word127 = __le16_to_cpu ( id - > word127 ) ;
id - > dlf = __le16_to_cpu ( id - > dlf ) ;
id - > csfo = __le16_to_cpu ( id - > csfo ) ;
for ( i = 0 ; i < 26 ; i + + )
id - > words130_155 [ i ] = __le16_to_cpu ( id - > words130_155 [ i ] ) ;
id - > word156 = __le16_to_cpu ( id - > word156 ) ;
for ( i = 0 ; i < 3 ; i + + )
id - > words157_159 [ i ] = __le16_to_cpu ( id - > words157_159 [ i ] ) ;
id - > cfa_power = __le16_to_cpu ( id - > cfa_power ) ;
for ( i = 0 ; i < 14 ; i + + )
id - > words161_175 [ i ] = __le16_to_cpu ( id - > words161_175 [ i ] ) ;
for ( i = 0 ; i < 31 ; i + + )
id - > words176_205 [ i ] = __le16_to_cpu ( id - > words176_205 [ i ] ) ;
for ( i = 0 ; i < 48 ; i + + )
id - > words206_254 [ i ] = __le16_to_cpu ( id - > words206_254 [ i ] ) ;
id - > integrity_word = __le16_to_cpu ( id - > integrity_word ) ;
# else
# error "Please fix <asm / byteorder.h>"
# endif
# endif
}
2007-11-05 23:42:29 +03:00
/*
* ide_fixstring ( ) cleans up and ( optionally ) byte - swaps a text string ,
* removing leading / trailing blanks and compressing internal blanks .
* It is primarily used to tidy up the model name / number fields as
* returned by the WIN_ [ P ] IDENTIFY commands .
*/
2005-04-17 02:20:36 +04:00
void ide_fixstring ( u8 * s , const int bytecount , const int byteswap )
{
u8 * p = s , * end = & s [ bytecount & ~ 1 ] ; /* bytecount must be even */
if ( byteswap ) {
/* convert from big-endian to host byte order */
for ( p = end ; p ! = s ; ) {
unsigned short * pp = ( unsigned short * ) ( p - = 2 ) ;
* pp = ntohs ( * pp ) ;
}
}
/* strip leading blanks */
while ( s ! = end & & * s = = ' ' )
+ + s ;
/* compress internal blanks and strip trailing blanks */
while ( s ! = end & & * s ) {
if ( * s + + ! = ' ' | | ( s ! = end & & * s & & * s ! = ' ' ) )
* p + + = * ( s - 1 ) ;
}
/* wipe out trailing garbage */
while ( p ! = end )
* p + + = ' \0 ' ;
}
EXPORT_SYMBOL ( ide_fixstring ) ;
/*
* Needed for PCI irq sharing
*/
int drive_is_ready ( ide_drive_t * drive )
{
ide_hwif_t * hwif = HWIF ( drive ) ;
u8 stat = 0 ;
if ( drive - > waiting_for_dma )
2008-04-27 00:25:24 +04:00
return hwif - > dma_ops - > dma_test_irq ( drive ) ;
2005-04-17 02:20:36 +04:00
#if 0
/* need to guarantee 400ns since last command was issued */
udelay ( 1 ) ;
# endif
/*
* We do a passive status test under shared PCI interrupts on
* cards that truly share the ATA side interrupt , but may also share
* an interrupt with another pci card / device . We make no assumptions
* about possible isa - pnp and pci - pnp issues yet .
*/
2008-04-27 17:38:32 +04:00
if ( hwif - > io_ports . ctl_addr )
2008-02-06 04:57:51 +03:00
stat = ide_read_altstatus ( drive ) ;
2005-04-17 02:20:36 +04:00
else
/* Note: this may clear a pending IRQ!! */
2008-02-06 04:57:51 +03:00
stat = ide_read_status ( drive ) ;
2005-04-17 02:20:36 +04:00
if ( stat & BUSY_STAT )
/* drive busy: definitely not interrupting */
return 0 ;
/* drive ready: *might* be interrupting */
return 1 ;
}
EXPORT_SYMBOL ( drive_is_ready ) ;
/*
* This routine busy - waits for the drive status to be not " busy " .
* It then checks the status for all of the " good " bits and none
* of the " bad " bits , and if all is okay it returns 0. All other
2007-10-13 19:47:49 +04:00
* cases return error - - caller may then invoke ide_error ( ) .
2005-04-17 02:20:36 +04:00
*
* This routine should get fixed to not hog the cpu during extra long waits . .
* That could be done by busy - waiting for the first jiffy or two , and then
* setting a timer to wake up at half second intervals thereafter ,
* until timeout is achieved , before timing out .
*/
2007-10-13 19:47:50 +04:00
static int __ide_wait_stat ( ide_drive_t * drive , u8 good , u8 bad , unsigned long timeout , u8 * rstat )
2005-04-17 02:20:36 +04:00
{
unsigned long flags ;
2007-10-13 19:47:49 +04:00
int i ;
u8 stat ;
2005-04-17 02:20:36 +04:00
udelay ( 1 ) ; /* spec allows drive 400ns to assert "BUSY" */
2008-02-06 04:57:51 +03:00
stat = ide_read_status ( drive ) ;
if ( stat & BUSY_STAT ) {
2005-04-17 02:20:36 +04:00
local_irq_set ( flags ) ;
timeout + = jiffies ;
2008-02-06 04:57:51 +03:00
while ( ( stat = ide_read_status ( drive ) ) & BUSY_STAT ) {
2005-04-17 02:20:36 +04:00
if ( time_after ( jiffies , timeout ) ) {
/*
* One last read after the timeout in case
* heavy interrupt load made us not make any
* progress during the timeout . .
*/
2008-02-06 04:57:51 +03:00
stat = ide_read_status ( drive ) ;
2005-04-17 02:20:36 +04:00
if ( ! ( stat & BUSY_STAT ) )
break ;
local_irq_restore ( flags ) ;
2007-10-13 19:47:49 +04:00
* rstat = stat ;
return - EBUSY ;
2005-04-17 02:20:36 +04:00
}
}
local_irq_restore ( flags ) ;
}
/*
* Allow status to settle , then read it again .
* A few rare drives vastly violate the 400 ns spec here ,
* so we ' ll wait up to 10u sec for a " good " status
* rather than expensively fail things immediately .
* This fix courtesy of Matthew Faupel & Niccolo Rigacci .
*/
for ( i = 0 ; i < 10 ; i + + ) {
udelay ( 1 ) ;
2008-02-06 04:57:51 +03:00
stat = ide_read_status ( drive ) ;
if ( OK_STAT ( stat , good , bad ) ) {
2007-10-13 19:47:49 +04:00
* rstat = stat ;
2005-04-17 02:20:36 +04:00
return 0 ;
2007-10-13 19:47:49 +04:00
}
2005-04-17 02:20:36 +04:00
}
2007-10-13 19:47:49 +04:00
* rstat = stat ;
return - EFAULT ;
}
/*
* In case of error returns error value after doing " *startstop = ide_error() " .
* The caller should return the updated value of " startstop " in this case ,
* " startstop " is unchanged when the function returns 0.
*/
int ide_wait_stat ( ide_startstop_t * startstop , ide_drive_t * drive , u8 good , u8 bad , unsigned long timeout )
{
int err ;
u8 stat ;
/* bail early if we've exceeded max_failures */
if ( drive - > max_failures & & ( drive - > failures > drive - > max_failures ) ) {
* startstop = ide_stopped ;
return 1 ;
}
err = __ide_wait_stat ( drive , good , bad , timeout , & stat ) ;
if ( err ) {
char * s = ( err = = - EBUSY ) ? " status timeout " : " status error " ;
* startstop = ide_error ( drive , s , stat ) ;
}
return err ;
2005-04-17 02:20:36 +04:00
}
EXPORT_SYMBOL ( ide_wait_stat ) ;
2007-08-21 00:42:56 +04:00
/**
* ide_in_drive_list - look for drive in black / white list
* @ id : drive identifier
* @ drive_table : list to inspect
*
* Look for a drive in the blacklist and the whitelist tables
* Returns 1 if the drive is found in the table .
*/
int ide_in_drive_list ( struct hd_driveid * id , const struct drive_list_entry * drive_table )
{
for ( ; drive_table - > id_model ; drive_table + + )
if ( ( ! strcmp ( drive_table - > id_model , id - > model ) ) & &
( ! drive_table - > id_firmware | |
strstr ( id - > fw_rev , drive_table - > id_firmware ) ) )
return 1 ;
return 0 ;
}
2007-08-21 00:42:57 +04:00
EXPORT_SYMBOL_GPL ( ide_in_drive_list ) ;
2007-08-21 00:42:56 +04:00
/*
* Early UDMA66 devices don ' t set bit14 to 1 , only bit13 is valid .
* We list them here and depend on the device side cable detection for them .
2007-10-26 22:31:16 +04:00
*
* Some optical devices with the buggy firmwares have the same problem .
2007-08-21 00:42:56 +04:00
*/
static const struct drive_list_entry ivb_list [ ] = {
{ " QUANTUM FIREBALLlct10 05 " , " A03.0900 " } ,
2007-10-26 22:31:16 +04:00
{ " TSSTcorp CDDVDW SH-S202J " , " SB00 " } ,
2007-11-27 23:35:57 +03:00
{ " TSSTcorp CDDVDW SH-S202J " , " SB01 " } ,
{ " TSSTcorp CDDVDW SH-S202N " , " SB00 " } ,
{ " TSSTcorp CDDVDW SH-S202N " , " SB01 " } ,
2008-04-29 01:44:43 +04:00
{ " TSSTcorp CDDVDW SH-S202H " , " SB00 " } ,
{ " TSSTcorp CDDVDW SH-S202H " , " SB01 " } ,
2007-08-21 00:42:56 +04:00
{ NULL , NULL }
} ;
2005-04-17 02:20:36 +04:00
/*
* All hosts that use the 80 c ribbon must use !
* The name is derived from upper byte of word 93 and the 80 c ribbon .
*/
u8 eighty_ninty_three ( ide_drive_t * drive )
{
2007-05-10 02:01:10 +04:00
ide_hwif_t * hwif = drive - > hwif ;
struct hd_driveid * id = drive - > id ;
2007-08-21 00:42:56 +04:00
int ivb = ide_in_drive_list ( id , ivb_list ) ;
2007-05-10 02:01:10 +04:00
2007-07-10 01:17:58 +04:00
if ( hwif - > cbl = = ATA_CBL_PATA40_SHORT )
return 1 ;
2007-08-21 00:42:56 +04:00
if ( ivb )
printk ( KERN_DEBUG " %s: skipping word 93 validity check \n " ,
drive - > name ) ;
2008-01-11 01:03:42 +03:00
if ( ide_dev_is_sata ( id ) & & ! ivb )
return 1 ;
2007-08-21 00:42:56 +04:00
if ( hwif - > cbl ! = ATA_CBL_PATA80 & & ! ivb )
2007-05-10 02:01:10 +04:00
goto no_80w ;
2006-06-28 15:26:58 +04:00
2007-03-27 01:03:18 +04:00
/*
* FIXME :
2008-03-29 21:48:21 +03:00
* - change master / slave IDENTIFY order
2007-08-21 00:42:56 +04:00
* - force bit13 ( 80 c cable present ) check also for ! ivb devices
2007-03-27 01:03:18 +04:00
* ( unless the slave device is pre - ATA3 )
*/
2007-08-21 00:42:56 +04:00
if ( ( id - > hw_config & 0x4000 ) | | ( ivb & & ( id - > hw_config & 0x2000 ) ) )
2007-05-10 02:01:10 +04:00
return 1 ;
no_80w :
if ( drive - > udma33_warned = = 1 )
return 0 ;
printk ( KERN_WARNING " %s: %s side 80-wire cable detection failed, "
" limiting max speed to UDMA33 \n " ,
2007-07-10 01:17:58 +04:00
drive - > name ,
hwif - > cbl = = ATA_CBL_PATA80 ? " drive " : " host " ) ;
2007-05-10 02:01:10 +04:00
drive - > udma33_warned = 1 ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-10-20 02:32:36 +04:00
int ide_driveid_update ( ide_drive_t * drive )
2005-04-17 02:20:36 +04:00
{
2007-10-20 02:32:36 +04:00
ide_hwif_t * hwif = drive - > hwif ;
2005-04-17 02:20:36 +04:00
struct hd_driveid * id ;
2007-10-20 02:32:36 +04:00
unsigned long timeout , flags ;
2008-02-06 04:57:51 +03:00
u8 stat ;
2005-04-17 02:20:36 +04:00
/*
* Re - read drive - > id for possible DMA mode
* change ( copied from ide - probe . c )
*/
SELECT_MASK ( drive , 1 ) ;
2008-07-15 23:21:40 +04:00
ide_set_irq ( drive , 0 ) ;
2005-04-17 02:20:36 +04:00
msleep ( 50 ) ;
2008-04-29 01:44:38 +04:00
hwif - > OUTBSYNC ( drive , WIN_IDENTIFY , hwif - > io_ports . command_addr ) ;
2005-04-17 02:20:36 +04:00
timeout = jiffies + WAIT_WORSTCASE ;
do {
if ( time_after ( jiffies , timeout ) ) {
SELECT_MASK ( drive , 0 ) ;
return 0 ; /* drive timed-out */
}
2008-02-06 04:57:51 +03:00
2005-04-17 02:20:36 +04:00
msleep ( 50 ) ; /* give drive a breather */
2008-02-06 04:57:51 +03:00
stat = ide_read_altstatus ( drive ) ;
} while ( stat & BUSY_STAT ) ;
2005-04-17 02:20:36 +04:00
msleep ( 50 ) ; /* wait for IRQ and DRQ_STAT */
2008-02-06 04:57:51 +03:00
stat = ide_read_status ( drive ) ;
if ( ! OK_STAT ( stat , DRQ_STAT , BAD_R_STAT ) ) {
2005-04-17 02:20:36 +04:00
SELECT_MASK ( drive , 0 ) ;
printk ( " %s: CHECK for good STATUS \n " , drive - > name ) ;
return 0 ;
}
local_irq_save ( flags ) ;
SELECT_MASK ( drive , 0 ) ;
id = kmalloc ( SECTOR_WORDS * 4 , GFP_ATOMIC ) ;
if ( ! id ) {
local_irq_restore ( flags ) ;
return 0 ;
}
2008-04-29 01:44:36 +04:00
hwif - > input_data ( drive , NULL , id , SECTOR_SIZE ) ;
2008-02-06 04:57:51 +03:00
( void ) ide_read_status ( drive ) ; /* clear drive IRQ */
2005-04-17 02:20:36 +04:00
local_irq_enable ( ) ;
local_irq_restore ( flags ) ;
ide_fix_driveid ( id ) ;
if ( id ) {
drive - > id - > dma_ultra = id - > dma_ultra ;
drive - > id - > dma_mword = id - > dma_mword ;
drive - > id - > dma_1word = id - > dma_1word ;
/* anything more ? */
kfree ( id ) ;
2007-12-13 01:31:58 +03:00
if ( drive - > using_dma & & ide_id_dma_bug ( drive ) )
ide_dma_off ( drive ) ;
2005-04-17 02:20:36 +04:00
}
return 1 ;
}
2007-10-13 19:47:49 +04:00
int ide_config_drive_speed ( ide_drive_t * drive , u8 speed )
2005-04-17 02:20:36 +04:00
{
2007-10-13 19:47:49 +04:00
ide_hwif_t * hwif = drive - > hwif ;
2008-04-27 17:38:32 +04:00
struct ide_io_ports * io_ports = & hwif - > io_ports ;
2007-11-27 23:35:52 +03:00
int error = 0 ;
2005-04-17 02:20:36 +04:00
u8 stat ;
# ifdef CONFIG_BLK_DEV_IDEDMA
2008-04-27 00:25:24 +04:00
if ( hwif - > dma_ops ) /* check if host supports DMA */
hwif - > dma_ops - > dma_host_set ( drive , 0 ) ;
2005-04-17 02:20:36 +04:00
# endif
2007-11-27 23:35:52 +03:00
/* Skip setting PIO flow-control modes on pre-EIDE drives */
if ( ( speed & 0xf8 ) = = XFER_PIO_0 & & ! ( drive - > id - > capability & 0x08 ) )
goto skip ;
2005-04-17 02:20:36 +04:00
/*
* Don ' t use ide_wait_cmd here - it will
* attempt to set_geometry and recalibrate ,
* but for some reason these don ' t work at
* this point ( lost interrupt ) .
*/
/*
* Select the drive , and issue the SETFEATURES command
*/
disable_irq_nosync ( hwif - > irq ) ;
/*
* FIXME : we race against the running IRQ here if
* this is called from non IRQ context . If we use
* disable_irq ( ) we hang on the error path . Work
* is needed .
*/
udelay ( 1 ) ;
SELECT_DRIVE ( drive ) ;
SELECT_MASK ( drive , 0 ) ;
udelay ( 1 ) ;
2008-01-26 22:13:08 +03:00
ide_set_irq ( drive , 0 ) ;
2008-04-27 17:38:32 +04:00
hwif - > OUTB ( speed , io_ports - > nsect_addr ) ;
hwif - > OUTB ( SETFEATURES_XFER , io_ports - > feature_addr ) ;
hwif - > OUTBSYNC ( drive , WIN_SETFEATURES , io_ports - > command_addr ) ;
2008-01-26 22:13:08 +03:00
if ( drive - > quirk_list = = 2 )
ide_set_irq ( drive , 1 ) ;
2005-04-17 02:20:36 +04:00
2007-10-13 19:47:49 +04:00
error = __ide_wait_stat ( drive , drive - > ready_stat ,
BUSY_STAT | DRQ_STAT | ERR_STAT ,
WAIT_CMD , & stat ) ;
2005-04-17 02:20:36 +04:00
SELECT_MASK ( drive , 0 ) ;
enable_irq ( hwif - > irq ) ;
if ( error ) {
( void ) ide_dump_status ( drive , " set_drive_speed_status " , stat ) ;
return error ;
}
drive - > id - > dma_ultra & = ~ 0xFF00 ;
drive - > id - > dma_mword & = ~ 0x0F00 ;
drive - > id - > dma_1word & = ~ 0x0F00 ;
2007-11-27 23:35:52 +03:00
skip :
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_BLK_DEV_IDEDMA
2008-01-26 22:13:02 +03:00
if ( ( speed > = XFER_SW_DMA_0 | | ( hwif - > host_flags & IDE_HFLAG_VDMA ) ) & &
drive - > using_dma )
2008-04-27 00:25:24 +04:00
hwif - > dma_ops - > dma_host_set ( drive , 1 ) ;
else if ( hwif - > dma_ops ) /* check if host supports DMA */
2008-01-26 22:13:01 +03:00
ide_dma_off_quietly ( drive ) ;
2005-04-17 02:20:36 +04:00
# endif
switch ( speed ) {
case XFER_UDMA_7 : drive - > id - > dma_ultra | = 0x8080 ; break ;
case XFER_UDMA_6 : drive - > id - > dma_ultra | = 0x4040 ; break ;
case XFER_UDMA_5 : drive - > id - > dma_ultra | = 0x2020 ; break ;
case XFER_UDMA_4 : drive - > id - > dma_ultra | = 0x1010 ; break ;
case XFER_UDMA_3 : drive - > id - > dma_ultra | = 0x0808 ; break ;
case XFER_UDMA_2 : drive - > id - > dma_ultra | = 0x0404 ; break ;
case XFER_UDMA_1 : drive - > id - > dma_ultra | = 0x0202 ; break ;
case XFER_UDMA_0 : drive - > id - > dma_ultra | = 0x0101 ; break ;
case XFER_MW_DMA_2 : drive - > id - > dma_mword | = 0x0404 ; break ;
case XFER_MW_DMA_1 : drive - > id - > dma_mword | = 0x0202 ; break ;
case XFER_MW_DMA_0 : drive - > id - > dma_mword | = 0x0101 ; break ;
case XFER_SW_DMA_2 : drive - > id - > dma_1word | = 0x0404 ; break ;
case XFER_SW_DMA_1 : drive - > id - > dma_1word | = 0x0202 ; break ;
case XFER_SW_DMA_0 : drive - > id - > dma_1word | = 0x0101 ; break ;
default : break ;
}
if ( ! drive - > init_speed )
drive - > init_speed = speed ;
drive - > current_speed = speed ;
return error ;
}
/*
* This should get invoked any time we exit the driver to
* wait for an interrupt response from a drive . handler ( ) points
* at the appropriate code to handle the next interrupt , and a
* timer is started to prevent us from waiting forever in case
* something goes wrong ( see the ide_timer_expiry ( ) handler later on ) .
*
* See also ide_execute_command
*/
static void __ide_set_handler ( ide_drive_t * drive , ide_handler_t * handler ,
unsigned int timeout , ide_expiry_t * expiry )
{
ide_hwgroup_t * hwgroup = HWGROUP ( drive ) ;
2008-02-11 02:32:12 +03:00
BUG_ON ( hwgroup - > handler ) ;
2005-04-17 02:20:36 +04:00
hwgroup - > handler = handler ;
hwgroup - > expiry = expiry ;
hwgroup - > timer . expires = jiffies + timeout ;
2008-02-11 02:32:12 +03:00
hwgroup - > req_gen_timer = hwgroup - > req_gen ;
2005-04-17 02:20:36 +04:00
add_timer ( & hwgroup - > timer ) ;
}
void ide_set_handler ( ide_drive_t * drive , ide_handler_t * handler ,
unsigned int timeout , ide_expiry_t * expiry )
{
unsigned long flags ;
spin_lock_irqsave ( & ide_lock , flags ) ;
__ide_set_handler ( drive , handler , timeout , expiry ) ;
spin_unlock_irqrestore ( & ide_lock , flags ) ;
}
EXPORT_SYMBOL ( ide_set_handler ) ;
/**
* ide_execute_command - execute an IDE command
* @ drive : IDE drive to issue the command against
* @ command : command byte to write
* @ handler : handler for next phase
* @ timeout : timeout for command
* @ expiry : handler to run on timeout
*
* Helper function to issue an IDE command . This handles the
* atomicity requirements , command timing and ensures that the
* handler and IRQ setup do not race . All IDE command kick off
* should go via this function or do equivalent locking .
*/
2008-01-26 00:17:06 +03:00
void ide_execute_command ( ide_drive_t * drive , u8 cmd , ide_handler_t * handler ,
unsigned timeout , ide_expiry_t * expiry )
2005-04-17 02:20:36 +04:00
{
unsigned long flags ;
ide_hwif_t * hwif = HWIF ( drive ) ;
2008-02-02 21:56:46 +03:00
2005-04-17 02:20:36 +04:00
spin_lock_irqsave ( & ide_lock , flags ) ;
2008-02-02 21:56:46 +03:00
__ide_set_handler ( drive , handler , timeout , expiry ) ;
2008-04-27 17:38:32 +04:00
hwif - > OUTBSYNC ( drive , cmd , hwif - > io_ports . command_addr ) ;
2008-02-02 21:56:46 +03:00
/*
* Drive takes 400 nS to respond , we must avoid the IRQ being
* serviced before that .
*
* FIXME : we could skip this delay with care on non shared devices
*/
2005-04-17 02:20:36 +04:00
ndelay ( 400 ) ;
spin_unlock_irqrestore ( & ide_lock , flags ) ;
}
EXPORT_SYMBOL ( ide_execute_command ) ;
2008-04-29 01:44:39 +04:00
void ide_execute_pkt_cmd ( ide_drive_t * drive )
{
ide_hwif_t * hwif = drive - > hwif ;
unsigned long flags ;
spin_lock_irqsave ( & ide_lock , flags ) ;
hwif - > OUTBSYNC ( drive , WIN_PACKETCMD , hwif - > io_ports . command_addr ) ;
ndelay ( 400 ) ;
spin_unlock_irqrestore ( & ide_lock , flags ) ;
}
EXPORT_SYMBOL_GPL ( ide_execute_pkt_cmd ) ;
2005-04-17 02:20:36 +04:00
/* needed below */
static ide_startstop_t do_reset1 ( ide_drive_t * , int ) ;
/*
* atapi_reset_pollfunc ( ) gets invoked to poll the interface for completion every 50 ms
* during an atapi drive reset operation . If the drive has not yet responded ,
* and we have not yet hit our maximum waiting time , then the timer is restarted
* for another 50 ms .
*/
static ide_startstop_t atapi_reset_pollfunc ( ide_drive_t * drive )
{
ide_hwgroup_t * hwgroup = HWGROUP ( drive ) ;
u8 stat ;
SELECT_DRIVE ( drive ) ;
udelay ( 10 ) ;
2008-02-06 04:57:51 +03:00
stat = ide_read_status ( drive ) ;
2005-04-17 02:20:36 +04:00
2008-02-06 04:57:51 +03:00
if ( OK_STAT ( stat , 0 , BUSY_STAT ) )
2005-04-17 02:20:36 +04:00
printk ( " %s: ATAPI reset complete \n " , drive - > name ) ;
2008-02-06 04:57:51 +03:00
else {
2005-04-17 02:20:36 +04:00
if ( time_before ( jiffies , hwgroup - > poll_timeout ) ) {
ide_set_handler ( drive , & atapi_reset_pollfunc , HZ / 20 , NULL ) ;
/* continue polling */
return ide_started ;
}
/* end of polling */
hwgroup - > polling = 0 ;
printk ( " %s: ATAPI reset timed-out, status=0x%02x \n " ,
drive - > name , stat ) ;
/* do it the old fashioned way */
return do_reset1 ( drive , 1 ) ;
}
/* done polling */
hwgroup - > polling = 0 ;
2006-10-03 12:14:33 +04:00
hwgroup - > resetting = 0 ;
2005-04-17 02:20:36 +04:00
return ide_stopped ;
}
/*
* reset_pollfunc ( ) gets invoked to poll the interface for completion every 50 ms
* during an ide reset operation . If the drives have not yet responded ,
* and we have not yet hit our maximum waiting time , then the timer is restarted
* for another 50 ms .
*/
static ide_startstop_t reset_pollfunc ( ide_drive_t * drive )
{
ide_hwgroup_t * hwgroup = HWGROUP ( drive ) ;
ide_hwif_t * hwif = HWIF ( drive ) ;
2008-04-27 00:25:14 +04:00
const struct ide_port_ops * port_ops = hwif - > port_ops ;
2005-04-17 02:20:36 +04:00
u8 tmp ;
2008-04-27 00:25:14 +04:00
if ( port_ops & & port_ops - > reset_poll ) {
if ( port_ops - > reset_poll ( drive ) ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " %s: host reset_poll failure for %s. \n " ,
hwif - > name , drive - > name ) ;
return ide_stopped ;
}
}
2008-02-06 04:57:51 +03:00
tmp = ide_read_status ( drive ) ;
if ( ! OK_STAT ( tmp , 0 , BUSY_STAT ) ) {
2005-04-17 02:20:36 +04:00
if ( time_before ( jiffies , hwgroup - > poll_timeout ) ) {
ide_set_handler ( drive , & reset_pollfunc , HZ / 20 , NULL ) ;
/* continue polling */
return ide_started ;
}
printk ( " %s: reset timed-out, status=0x%02x \n " , hwif - > name , tmp ) ;
drive - > failures + + ;
} else {
printk ( " %s: reset: " , hwif - > name ) ;
2008-02-06 04:57:51 +03:00
tmp = ide_read_error ( drive ) ;
if ( tmp = = 1 ) {
2005-04-17 02:20:36 +04:00
printk ( " success \n " ) ;
drive - > failures = 0 ;
} else {
drive - > failures + + ;
printk ( " master: " ) ;
switch ( tmp & 0x7f ) {
case 1 : printk ( " passed " ) ;
break ;
case 2 : printk ( " formatter device error " ) ;
break ;
case 3 : printk ( " sector buffer error " ) ;
break ;
case 4 : printk ( " ECC circuitry error " ) ;
break ;
case 5 : printk ( " controlling MPU error " ) ;
break ;
default : printk ( " error (0x%02x?) " , tmp ) ;
}
if ( tmp & 0x80 )
printk ( " ; slave: failed " ) ;
printk ( " \n " ) ;
}
}
hwgroup - > polling = 0 ; /* done polling */
2006-10-03 12:14:33 +04:00
hwgroup - > resetting = 0 ; /* done reset attempt */
2005-04-17 02:20:36 +04:00
return ide_stopped ;
}
static void ide_disk_pre_reset ( ide_drive_t * drive )
{
int legacy = ( drive - > id - > cfs_enable_2 & 0x0400 ) ? 0 : 1 ;
drive - > special . all = 0 ;
drive - > special . b . set_geometry = legacy ;
drive - > special . b . recalibrate = legacy ;
2008-01-26 00:17:08 +03:00
drive - > mult_count = 0 ;
2005-04-17 02:20:36 +04:00
if ( ! drive - > keep_settings & & ! drive - > using_dma )
drive - > mult_req = 0 ;
if ( drive - > mult_req ! = drive - > mult_count )
drive - > special . b . set_multmode = 1 ;
}
static void pre_reset ( ide_drive_t * drive )
{
2008-04-27 00:25:14 +04:00
const struct ide_port_ops * port_ops = drive - > hwif - > port_ops ;
2005-04-17 02:20:36 +04:00
if ( drive - > media = = ide_disk )
ide_disk_pre_reset ( drive ) ;
else
drive - > post_reset = 1 ;
2008-02-02 21:56:47 +03:00
if ( drive - > using_dma ) {
if ( drive - > crc_count )
2008-02-02 21:56:47 +03:00
ide_check_dma_crc ( drive ) ;
2008-02-02 21:56:47 +03:00
else
ide_dma_off ( drive ) ;
}
if ( ! drive - > keep_settings ) {
if ( ! drive - > using_dma ) {
2005-04-17 02:20:36 +04:00
drive - > unmask = 0 ;
drive - > io_32bit = 0 ;
}
return ;
}
2008-04-27 00:25:14 +04:00
if ( port_ops & & port_ops - > pre_reset )
port_ops - > pre_reset ( drive ) ;
2005-04-17 02:20:36 +04:00
2007-03-27 01:03:20 +04:00
if ( drive - > current_speed ! = 0xff )
drive - > desired_speed = drive - > current_speed ;
drive - > current_speed = 0xff ;
2005-04-17 02:20:36 +04:00
}
/*
* do_reset1 ( ) attempts to recover a confused drive by resetting it .
* Unfortunately , resetting a disk drive actually resets all devices on
* the same interface , so it can really be thought of as resetting the
* interface rather than resetting the drive .
*
* ATAPI devices have their own reset mechanism which allows them to be
* individually reset without clobbering other devices on the same interface .
*
* Unfortunately , the IDE interface does not generate an interrupt to let
* us know when the reset operation has finished , so we must poll for this .
* Equally poor , though , is the fact that this may a very long time to complete ,
* ( up to 30 seconds worstcase ) . So , instead of busy - waiting here for it ,
* we set a timer to poll at 50 ms intervals .
*/
static ide_startstop_t do_reset1 ( ide_drive_t * drive , int do_not_try_atapi )
{
unsigned int unit ;
unsigned long flags ;
ide_hwif_t * hwif ;
ide_hwgroup_t * hwgroup ;
2008-04-27 17:38:32 +04:00
struct ide_io_ports * io_ports ;
2008-04-27 00:25:14 +04:00
const struct ide_port_ops * port_ops ;
2008-04-18 02:46:26 +04:00
u8 ctl ;
2005-04-17 02:20:36 +04:00
spin_lock_irqsave ( & ide_lock , flags ) ;
hwif = HWIF ( drive ) ;
hwgroup = HWGROUP ( drive ) ;
2008-04-27 17:38:32 +04:00
io_ports = & hwif - > io_ports ;
2005-04-17 02:20:36 +04:00
/* We must not reset with running handlers */
2006-06-23 13:06:06 +04:00
BUG_ON ( hwgroup - > handler ! = NULL ) ;
2005-04-17 02:20:36 +04:00
/* For an ATAPI device, first try an ATAPI SRST. */
if ( drive - > media ! = ide_disk & & ! do_not_try_atapi ) {
2006-10-03 12:14:33 +04:00
hwgroup - > resetting = 1 ;
2005-04-17 02:20:36 +04:00
pre_reset ( drive ) ;
SELECT_DRIVE ( drive ) ;
udelay ( 20 ) ;
2008-04-27 17:38:32 +04:00
hwif - > OUTBSYNC ( drive , WIN_SRST , io_ports - > command_addr ) ;
2005-06-28 02:24:25 +04:00
ndelay ( 400 ) ;
2005-04-17 02:20:36 +04:00
hwgroup - > poll_timeout = jiffies + WAIT_WORSTCASE ;
hwgroup - > polling = 1 ;
__ide_set_handler ( drive , & atapi_reset_pollfunc , HZ / 20 , NULL ) ;
spin_unlock_irqrestore ( & ide_lock , flags ) ;
return ide_started ;
}
/*
* First , reset any device state data we were maintaining
* for any of the drives on this interface .
*/
for ( unit = 0 ; unit < MAX_DRIVES ; + + unit )
pre_reset ( & hwif - > drives [ unit ] ) ;
2008-04-27 17:38:32 +04:00
if ( io_ports - > ctl_addr = = 0 ) {
2005-04-17 02:20:36 +04:00
spin_unlock_irqrestore ( & ide_lock , flags ) ;
return ide_stopped ;
}
2006-10-03 12:14:33 +04:00
hwgroup - > resetting = 1 ;
2005-04-17 02:20:36 +04:00
/*
* Note that we also set nIEN while resetting the device ,
* to mask unwanted interrupts from the interface during the reset .
* However , due to the design of PC hardware , this will cause an
* immediate interrupt due to the edge transition it produces .
* This single interrupt gives us a " fast poll " for drives that
* recover from reset very quickly , saving us the first 50 ms wait time .
*/
/* set SRST and nIEN */
2008-04-27 17:38:32 +04:00
hwif - > OUTBSYNC ( drive , drive - > ctl | 6 , io_ports - > ctl_addr ) ;
2005-04-17 02:20:36 +04:00
/* more than enough time */
udelay ( 10 ) ;
2008-04-18 02:46:26 +04:00
if ( drive - > quirk_list = = 2 )
ctl = drive - > ctl ; /* clear SRST and nIEN */
else
ctl = drive - > ctl | 2 ; /* clear SRST, leave nIEN */
2008-04-27 17:38:32 +04:00
hwif - > OUTBSYNC ( drive , ctl , io_ports - > ctl_addr ) ;
2005-04-17 02:20:36 +04:00
/* more than enough time */
udelay ( 10 ) ;
hwgroup - > poll_timeout = jiffies + WAIT_WORSTCASE ;
hwgroup - > polling = 1 ;
__ide_set_handler ( drive , & reset_pollfunc , HZ / 20 , NULL ) ;
/*
* Some weird controller like resetting themselves to a strange
* state when the disks are reset this way . At least , the Winbond
* 553 documentation says that
*/
2008-04-27 00:25:14 +04:00
port_ops = hwif - > port_ops ;
if ( port_ops & & port_ops - > resetproc )
port_ops - > resetproc ( drive ) ;
2005-04-17 02:20:36 +04:00
spin_unlock_irqrestore ( & ide_lock , flags ) ;
return ide_started ;
}
/*
* ide_do_reset ( ) is the entry point to the drive / interface reset code .
*/
ide_startstop_t ide_do_reset ( ide_drive_t * drive )
{
return do_reset1 ( drive , 0 ) ;
}
EXPORT_SYMBOL ( ide_do_reset ) ;
/*
* ide_wait_not_busy ( ) waits for the currently selected device on the hwif
2008-02-02 01:09:36 +03:00
* to report a non - busy status , see comments in ide_probe_port ( ) .
2005-04-17 02:20:36 +04:00
*/
int ide_wait_not_busy ( ide_hwif_t * hwif , unsigned long timeout )
{
u8 stat = 0 ;
while ( timeout - - ) {
/*
* Turn this into a schedule ( ) sleep once I ' m sure
* about locking issues ( 2.5 work ? ) .
*/
mdelay ( 1 ) ;
2008-04-27 17:38:32 +04:00
stat = hwif - > INB ( hwif - > io_ports . status_addr ) ;
2005-04-17 02:20:36 +04:00
if ( ( stat & BUSY_STAT ) = = 0 )
return 0 ;
/*
* Assume a value of 0xff means nothing is connected to
* the interface and it doesn ' t implement the pull - down
* resistor on D7 .
*/
if ( stat = = 0xff )
return - ENODEV ;
2006-02-03 14:04:55 +03:00
touch_softlockup_watchdog ( ) ;
2006-07-30 14:03:29 +04:00
touch_nmi_watchdog ( ) ;
2005-04-17 02:20:36 +04:00
}
return - EBUSY ;
}
EXPORT_SYMBOL_GPL ( ide_wait_not_busy ) ;