2005-04-17 02:20:36 +04:00
/*
* Copyright ( C ) 2000 - 2002 Andre Hedrick < andre @ linux - ide . org >
2008-11-02 23:40:08 +03:00
* Copyright ( C ) 2003 Red Hat
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/blkpg.h>
# include <linux/slab.h>
# include <linux/pci.h>
# include <linux/delay.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>
2008-07-15 23:21:48 +04:00
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-07-23 21:55:53 +04:00
u8 ide_read_error ( ide_drive_t * drive )
{
2009-04-08 16:13:03 +04:00
struct ide_taskfile tf ;
2008-07-23 21:55:53 +04:00
2009-04-08 16:13:03 +04:00
drive - > hwif - > tp_ops - > tf_read ( drive , & tf , IDE_VALID_ERROR ) ;
2008-07-23 21:55:53 +04:00
2009-04-08 16:13:03 +04:00
return tf . error ;
2008-07-23 21:55:53 +04:00
}
EXPORT_SYMBOL_GPL ( ide_read_error ) ;
2008-10-11 00:39:19 +04:00
void ide_fix_driveid ( u16 * id )
2005-04-17 02:20:36 +04:00
{
# ifndef __LITTLE_ENDIAN
# ifdef __BIG_ENDIAN
int i ;
2008-10-11 00:39:18 +04:00
2008-10-11 00:39:19 +04:00
for ( i = 0 ; i < 256 ; i + + )
2008-10-11 00:39:18 +04:00
id [ i ] = __le16_to_cpu ( id [ i ] ) ;
2005-04-17 02:20:36 +04:00
# 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
2008-10-11 00:39:21 +04:00
* returned by the ATA_CMD_ID_ATA [ PI ] commands .
2007-11-05 23:42:29 +03:00
*/
2009-03-25 01:22:47 +03:00
void ide_fixstring ( u8 * s , const int bytecount , const int byteswap )
2005-04-17 02:20:36 +04:00
{
ide: re-code ide_fixstring() loop to be less evil
On Friday 25 July 2008, Linus Torvalds wrote:
>
> On Fri, 25 Jul 2008, Ben Dooks wrote:
> >
> > personally, i would much prefer to see the loop being less evil
> > like:
> >
> > for (p = s; p < end; p += 2)
> > be16_to_cpus((u16 *)p);
>
> Well, in this case, the code actually depends on 'p' being back at the
> start of the buffer by the end of it all, so it would need some more
> changes than that.
>
> But yes, I applied David's patch, but I _also_ suspect that we would be
> better off without code that does horrid things like casts and assignments
> inside the function arguments.
>
> So it would be nice to re-code that loop to be more readable. But due to
> the reliance of 'p' being 's' after the loop, the minimal patch would be
> something like the appended.
>
> Bartlomiej - take this or not, I'm not going to commit it - I haven't
> tested it, nor do I even have any machines that would trigger it. So this
> is more a "maybe something like this" than anything else.
From: Linus Torvalds <torvalds@linux-foundation.org>
CC: Ben Dooks <ben-linux@fluff.org>
Cc: David Miller <davem@davemloft.net>
Cc: harvey.harrison@gmail.com
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
2008-10-11 00:39:22 +04:00
u8 * p , * end = & s [ bytecount & ~ 1 ] ; /* bytecount must be even */
2005-04-17 02:20:36 +04:00
if ( byteswap ) {
/* convert from big-endian to host byte order */
ide: re-code ide_fixstring() loop to be less evil
On Friday 25 July 2008, Linus Torvalds wrote:
>
> On Fri, 25 Jul 2008, Ben Dooks wrote:
> >
> > personally, i would much prefer to see the loop being less evil
> > like:
> >
> > for (p = s; p < end; p += 2)
> > be16_to_cpus((u16 *)p);
>
> Well, in this case, the code actually depends on 'p' being back at the
> start of the buffer by the end of it all, so it would need some more
> changes than that.
>
> But yes, I applied David's patch, but I _also_ suspect that we would be
> better off without code that does horrid things like casts and assignments
> inside the function arguments.
>
> So it would be nice to re-code that loop to be more readable. But due to
> the reliance of 'p' being 's' after the loop, the minimal patch would be
> something like the appended.
>
> Bartlomiej - take this or not, I'm not going to commit it - I haven't
> tested it, nor do I even have any machines that would trigger it. So this
> is more a "maybe something like this" than anything else.
From: Linus Torvalds <torvalds@linux-foundation.org>
CC: Ben Dooks <ben-linux@fluff.org>
Cc: David Miller <davem@davemloft.net>
Cc: harvey.harrison@gmail.com
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
2008-10-11 00:39:22 +04:00
for ( p = s ; p ! = end ; p + = 2 )
be16_to_cpus ( ( u16 * ) p ) ;
2005-04-17 02:20:36 +04:00
}
ide: re-code ide_fixstring() loop to be less evil
On Friday 25 July 2008, Linus Torvalds wrote:
>
> On Fri, 25 Jul 2008, Ben Dooks wrote:
> >
> > personally, i would much prefer to see the loop being less evil
> > like:
> >
> > for (p = s; p < end; p += 2)
> > be16_to_cpus((u16 *)p);
>
> Well, in this case, the code actually depends on 'p' being back at the
> start of the buffer by the end of it all, so it would need some more
> changes than that.
>
> But yes, I applied David's patch, but I _also_ suspect that we would be
> better off without code that does horrid things like casts and assignments
> inside the function arguments.
>
> So it would be nice to re-code that loop to be more readable. But due to
> the reliance of 'p' being 's' after the loop, the minimal patch would be
> something like the appended.
>
> Bartlomiej - take this or not, I'm not going to commit it - I haven't
> tested it, nor do I even have any machines that would trigger it. So this
> is more a "maybe something like this" than anything else.
From: Linus Torvalds <torvalds@linux-foundation.org>
CC: Ben Dooks <ben-linux@fluff.org>
Cc: David Miller <davem@davemloft.net>
Cc: harvey.harrison@gmail.com
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
2008-10-11 00:39:22 +04:00
2005-04-17 02:20:36 +04:00
/* strip leading blanks */
ide: re-code ide_fixstring() loop to be less evil
On Friday 25 July 2008, Linus Torvalds wrote:
>
> On Fri, 25 Jul 2008, Ben Dooks wrote:
> >
> > personally, i would much prefer to see the loop being less evil
> > like:
> >
> > for (p = s; p < end; p += 2)
> > be16_to_cpus((u16 *)p);
>
> Well, in this case, the code actually depends on 'p' being back at the
> start of the buffer by the end of it all, so it would need some more
> changes than that.
>
> But yes, I applied David's patch, but I _also_ suspect that we would be
> better off without code that does horrid things like casts and assignments
> inside the function arguments.
>
> So it would be nice to re-code that loop to be more readable. But due to
> the reliance of 'p' being 's' after the loop, the minimal patch would be
> something like the appended.
>
> Bartlomiej - take this or not, I'm not going to commit it - I haven't
> tested it, nor do I even have any machines that would trigger it. So this
> is more a "maybe something like this" than anything else.
From: Linus Torvalds <torvalds@linux-foundation.org>
CC: Ben Dooks <ben-linux@fluff.org>
Cc: David Miller <davem@davemloft.net>
Cc: harvey.harrison@gmail.com
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
2008-10-11 00:39:22 +04:00
p = s ;
2005-04-17 02:20:36 +04:00
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 ) ;
/*
* 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 .
*/
2009-06-23 15:29:11 +04:00
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
{
2008-07-23 21:55:52 +04:00
ide_hwif_t * hwif = drive - > hwif ;
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
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-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 ( stat & ATA_BUSY ) {
2009-01-14 21:19:02 +03:00
local_save_flags ( flags ) ;
2009-01-06 19:20:52 +03:00
local_irq_enable_in_hardirq ( ) ;
2005-04-17 02:20:36 +04:00
timeout + = jiffies ;
2008-10-11 00:39:21 +04:00
while ( ( stat = tp_ops - > read_status ( hwif ) ) & ATA_BUSY ) {
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-07-23 21:55:56 +04:00
stat = tp_ops - > read_status ( hwif ) ;
2008-10-11 00:39:21 +04:00
if ( ( stat & ATA_BUSY ) = = 0 )
2005-04-17 02:20:36 +04:00
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-07-23 21:55:56 +04:00
stat = tp_ops - > read_status ( hwif ) ;
2008-02-06 04:57:51 +03:00
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.
*/
2009-03-25 01:22:47 +03:00
int ide_wait_stat ( ide_startstop_t * startstop , ide_drive_t * drive , u8 good ,
u8 bad , unsigned long timeout )
2007-10-13 19:47:49 +04:00
{
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
2008-10-11 00:39:19 +04:00
* @ table : list to inspect
2007-08-21 00:42:56 +04:00
*
* Look for a drive in the blacklist and the whitelist tables
* Returns 1 if the drive is found in the table .
*/
2008-10-11 00:39:19 +04:00
int ide_in_drive_list ( u16 * id , const struct drive_list_entry * table )
2007-08-21 00:42:56 +04:00
{
2008-10-11 00:39:19 +04:00
for ( ; table - > id_model ; table + + )
if ( ( ! strcmp ( table - > id_model , ( char * ) & id [ ATA_ID_PROD ] ) ) & &
( ! table - > id_firmware | |
strstr ( ( char * ) & id [ ATA_ID_FW_REV ] , table - > id_firmware ) ) )
2007-08-21 00:42:56 +04:00
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 .
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 " } ,
2009-06-24 03:11:10 +04:00
{ " QUANTUM FIREBALLlct20 30 " , " APL.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 " } ,
2008-12-02 22:40:03 +03:00
{ " SAMSUNG SP0822N " , " WA100-10 " } ,
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 .
*/
2009-03-25 01:22:47 +03:00
u8 eighty_ninty_three ( ide_drive_t * drive )
2005-04-17 02:20:36 +04:00
{
2007-05-10 02:01:10 +04:00
ide_hwif_t * hwif = drive - > hwif ;
2008-10-11 00:39:19 +04:00
u16 * 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
2010-01-18 10:19:44 +03:00
if ( hwif - > cbl = = ATA_CBL_SATA | | hwif - > cbl = = ATA_CBL_PATA40_SHORT )
2007-07-10 01:17:58 +04:00
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-10-11 00:39:30 +04:00
if ( ata_id_is_sata ( id ) & & ! ivb )
2008-01-11 01:03:42 +03:00
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 )
*/
2009-05-22 18:23:36 +04:00
if ( id [ ATA_ID_HW_CONFIG ] & 0x4000 )
2007-05-10 02:01:10 +04:00
return 1 ;
2009-05-22 18:23:36 +04:00
if ( ivb ) {
const char * model = ( char * ) & id [ ATA_ID_PROD ] ;
if ( strstr ( model , " TSSTcorp CDDVDW SH-S202 " ) ) {
/*
* These ATAPI devices always report 80 c cable
* so we have to depend on the host in this case .
*/
if ( hwif - > cbl = = ATA_CBL_PATA80 )
return 1 ;
} else {
/* Depend on the device side cable detection. */
if ( id [ ATA_ID_HW_CONFIG ] & 0x2000 )
return 1 ;
}
}
2007-05-10 02:01:10 +04:00
no_80w :
2008-10-13 23:39:36 +04:00
if ( drive - > dev_flags & IDE_DFLAG_UDMA33_WARNED )
2007-05-10 02:01:10 +04:00
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
2008-10-13 23:39:36 +04:00
drive - > dev_flags | = IDE_DFLAG_UDMA33_WARNED ;
2007-05-10 02:01:10 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2009-06-07 17:37:09 +04:00
static const char * nien_quirk_list [ ] = {
" QUANTUM FIREBALLlct08 08 " ,
" QUANTUM FIREBALLP KA6.4 " ,
" QUANTUM FIREBALLP KA9.1 " ,
" QUANTUM FIREBALLP KX13.6 " ,
" QUANTUM FIREBALLP KX20.5 " ,
" QUANTUM FIREBALLP KX27.3 " ,
" QUANTUM FIREBALLP LM20.4 " ,
" QUANTUM FIREBALLP LM20.5 " ,
2009-09-15 12:36:25 +04:00
" FUJITSU MHZ2160BH G2 " ,
2009-06-07 17:37:09 +04:00
NULL
} ;
void ide_check_nien_quirk_list ( ide_drive_t * drive )
{
const char * * list , * m = ( char * ) & drive - > id [ ATA_ID_PROD ] ;
for ( list = nien_quirk_list ; * list ! = NULL ; list + + )
if ( strstr ( m , * list ) ! = NULL ) {
2009-06-07 17:37:10 +04:00
drive - > dev_flags | = IDE_DFLAG_NIEN_QUIRK ;
2009-06-07 17:37:09 +04:00
return ;
}
}
2007-10-20 02:32:36 +04:00
int ide_driveid_update ( ide_drive_t * drive )
2005-04-17 02:20:36 +04:00
{
2008-10-11 00:39:19 +04:00
u16 * id ;
2009-03-25 01:22:59 +03:00
int rc ;
2009-03-25 01:22:54 +03:00
id = kmalloc ( SECTOR_SIZE , GFP_ATOMIC ) ;
if ( id = = NULL )
return 0 ;
2005-04-17 02:20:36 +04:00
SELECT_MASK ( drive , 1 ) ;
2009-06-23 15:29:11 +04:00
rc = ide_dev_read_id ( drive , ATA_CMD_ID_ATA , id , 1 ) ;
2009-03-25 01:22:59 +03:00
SELECT_MASK ( drive , 0 ) ;
2009-03-25 01:22:54 +03:00
2009-03-25 01:22:59 +03:00
if ( rc )
2009-03-25 01:22:54 +03:00
goto out_err ;
2009-03-25 01:22:58 +03:00
2008-10-11 00:39:19 +04:00
drive - > id [ ATA_ID_UDMA_MODES ] = id [ ATA_ID_UDMA_MODES ] ;
drive - > id [ ATA_ID_MWDMA_MODES ] = id [ ATA_ID_MWDMA_MODES ] ;
drive - > id [ ATA_ID_SWDMA_MODES ] = id [ ATA_ID_SWDMA_MODES ] ;
2009-03-31 22:15:28 +04:00
drive - > id [ ATA_ID_CFA_MODES ] = id [ ATA_ID_CFA_MODES ] ;
2008-10-11 00:39:19 +04:00
/* anything more ? */
kfree ( id ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
2009-03-25 01:22:54 +03:00
out_err :
if ( rc = = 2 )
printk ( KERN_ERR " %s: %s: bad status \n " , drive - > name , __func__ ) ;
kfree ( id ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
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-07-23 21:55:56 +04:00
const struct ide_tp_ops * tp_ops = hwif - > tp_ops ;
2009-04-08 16:13:03 +04:00
struct ide_taskfile tf ;
2008-10-11 00:39:19 +04:00
u16 * id = drive - > id , i ;
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 */
2008-10-11 00:39:19 +04:00
if ( ( speed & 0xf8 ) = = XFER_PIO_0 & & ata_id_has_iordy ( drive - > id ) = = 0 )
2007-11-27 23:35:52 +03:00
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 ) .
*/
2009-03-25 01:22:47 +03:00
2005-04-17 02:20:36 +04:00
udelay ( 1 ) ;
2009-03-31 22:15:33 +04:00
tp_ops - > dev_select ( drive ) ;
2008-10-17 20:09:15 +04:00
SELECT_MASK ( drive , 1 ) ;
2005-04-17 02:20:36 +04:00
udelay ( 1 ) ;
2009-03-31 22:15:30 +04:00
tp_ops - > write_devctl ( hwif , ATA_NIEN | ATA_DEVCTL_OBS ) ;
2008-07-23 21:55:52 +04:00
2009-04-08 16:13:03 +04:00
memset ( & tf , 0 , sizeof ( tf ) ) ;
tf . feature = SETFEATURES_XFER ;
tf . nsect = speed ;
2008-07-23 21:55:52 +04:00
2009-04-08 16:13:03 +04:00
tp_ops - > tf_load ( drive , & tf , IDE_VALID_FEATURE | IDE_VALID_NSECT ) ;
2008-07-23 21:55:52 +04:00
2008-10-11 00:39:21 +04:00
tp_ops - > exec_command ( hwif , ATA_CMD_SET_FEATURES ) ;
2008-07-23 21:55:52 +04:00
2009-06-07 17:37:10 +04:00
if ( drive - > dev_flags & IDE_DFLAG_NIEN_QUIRK )
2009-03-31 22:15:30 +04:00
tp_ops - > write_devctl ( hwif , ATA_DEVCTL_OBS ) ;
2005-04-17 02:20:36 +04:00
2007-10-13 19:47:49 +04:00
error = __ide_wait_stat ( drive , drive - > ready_stat ,
2008-10-11 00:39:21 +04:00
ATA_BUSY | ATA_DRQ | ATA_ERR ,
2007-10-13 19:47:49 +04:00
WAIT_CMD , & stat ) ;
2005-04-17 02:20:36 +04:00
SELECT_MASK ( drive , 0 ) ;
if ( error ) {
( void ) ide_dump_status ( drive , " set_drive_speed_status " , stat ) ;
return error ;
}
2009-03-31 22:15:27 +04:00
if ( speed > = XFER_SW_DMA_0 ) {
id [ ATA_ID_UDMA_MODES ] & = ~ 0xFF00 ;
id [ ATA_ID_MWDMA_MODES ] & = ~ 0x0700 ;
id [ ATA_ID_SWDMA_MODES ] & = ~ 0x0700 ;
2009-03-31 22:15:28 +04:00
if ( ata_id_is_cfa ( id ) )
id [ ATA_ID_CFA_MODES ] & = ~ 0x0E00 ;
} else if ( ata_id_is_cfa ( id ) )
id [ ATA_ID_CFA_MODES ] & = ~ 0x01C0 ;
2005-04-17 02:20:36 +04:00
2007-11-27 23:35:52 +03:00
skip :
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_BLK_DEV_IDEDMA
2008-10-13 23:39:36 +04:00
if ( speed > = XFER_SW_DMA_0 & & ( drive - > dev_flags & IDE_DFLAG_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
2008-10-11 00:39:19 +04:00
if ( speed > = XFER_UDMA_0 ) {
i = 1 < < ( speed - XFER_UDMA_0 ) ;
id [ ATA_ID_UDMA_MODES ] | = ( i < < 8 | i ) ;
2009-03-31 22:15:28 +04:00
} else if ( ata_id_is_cfa ( id ) & & speed > = XFER_MW_DMA_3 ) {
i = speed - XFER_MW_DMA_2 ;
id [ ATA_ID_CFA_MODES ] | = i < < 9 ;
2008-10-11 00:39:19 +04:00
} else if ( speed > = XFER_MW_DMA_0 ) {
i = 1 < < ( speed - XFER_MW_DMA_0 ) ;
id [ ATA_ID_MWDMA_MODES ] | = ( i < < 8 | i ) ;
} else if ( speed > = XFER_SW_DMA_0 ) {
i = 1 < < ( speed - XFER_SW_DMA_0 ) ;
id [ ATA_ID_SWDMA_MODES ] | = ( i < < 8 | i ) ;
2009-03-31 22:15:28 +04:00
} else if ( ata_id_is_cfa ( id ) & & speed > = XFER_PIO_5 ) {
i = speed - XFER_PIO_4 ;
id [ ATA_ID_CFA_MODES ] | = i < < 6 ;
2005-04-17 02:20:36 +04:00
}
2008-10-11 00:39:19 +04:00
2005-04-17 02:20:36 +04:00
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
*/
2009-03-25 01:22:47 +03:00
void __ide_set_handler ( ide_drive_t * drive , ide_handler_t * handler ,
2009-03-27 14:46:46 +03:00
unsigned int timeout )
2005-04-17 02:20:36 +04:00
{
2009-01-06 19:20:50 +03:00
ide_hwif_t * hwif = drive - > hwif ;
BUG_ON ( hwif - > handler ) ;
hwif - > handler = handler ;
hwif - > timer . expires = jiffies + timeout ;
hwif - > req_gen_timer = hwif - > req_gen ;
add_timer ( & hwif - > timer ) ;
2005-04-17 02:20:36 +04:00
}
2009-03-27 14:46:46 +03:00
void ide_set_handler ( ide_drive_t * drive , ide_handler_t * handler ,
unsigned int timeout )
2005-04-17 02:20:36 +04:00
{
2009-01-06 19:20:50 +03:00
ide_hwif_t * hwif = drive - > hwif ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
2008-12-29 22:27:31 +03:00
2009-01-06 19:20:50 +03:00
spin_lock_irqsave ( & hwif - > lock , flags ) ;
2009-03-27 14:46:46 +03:00
__ide_set_handler ( drive , handler , timeout ) ;
2009-01-06 19:20:50 +03:00
spin_unlock_irqrestore ( & hwif - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
}
EXPORT_SYMBOL ( ide_set_handler ) ;
2009-03-25 01:22:47 +03:00
2005-04-17 02:20:36 +04:00
/**
* ide_execute_command - execute an IDE command
* @ drive : IDE drive to issue the command against
2009-03-27 14:46:47 +03:00
* @ cmd : command
2005-04-17 02:20:36 +04:00
* @ handler : handler for next phase
* @ timeout : timeout for command
*
* Helper function to issue an IDE command . This handles the
2009-03-25 01:22:47 +03:00
* atomicity requirements , command timing and ensures that the
2005-04-17 02:20:36 +04:00
* 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
2009-03-27 14:46:47 +03:00
void ide_execute_command ( ide_drive_t * drive , struct ide_cmd * cmd ,
ide_handler_t * handler , unsigned timeout )
2005-04-17 02:20:36 +04:00
{
2008-12-29 22:27:31 +03:00
ide_hwif_t * hwif = drive - > hwif ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
2008-02-02 21:56:46 +03:00
2009-01-06 19:20:50 +03:00
spin_lock_irqsave ( & hwif - > lock , flags ) ;
2009-03-27 14:46:47 +03:00
if ( ( cmd - > protocol ! = ATAPI_PROT_DMA & &
cmd - > protocol ! = ATAPI_PROT_PIO ) | |
( drive - > atapi_flags & IDE_AFLAG_DRQ_INTERRUPT ) )
__ide_set_handler ( drive , handler , timeout ) ;
hwif - > tp_ops - > exec_command ( hwif , cmd - > tf . command ) ;
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 ) ;
2009-01-06 19:20:50 +03:00
spin_unlock_irqrestore ( & hwif - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
}
/*
* 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 ;
2009-03-25 01:22:47 +03:00
while ( timeout - - ) {
2005-04-17 02:20:36 +04:00
/*
* Turn this into a schedule ( ) sleep once I ' m sure
* about locking issues ( 2.5 work ? ) .
*/
mdelay ( 1 ) ;
2008-07-23 21:55:56 +04:00
stat = hwif - > tp_ops - > read_status ( hwif ) ;
2008-10-11 00:39:21 +04:00
if ( ( stat & ATA_BUSY ) = = 0 )
2005-04-17 02:20:36 +04:00
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 ;
}