2006-09-28 11:29:01 -07:00
/*
* libata - acpi . c
* Provides ACPI support for PATA / SATA .
*
* Copyright ( C ) 2006 Intel Corp .
* Copyright ( C ) 2006 Randy Dunlap
*/
# include <linux/ata.h>
# include <linux/delay.h>
# include <linux/device.h>
# include <linux/errno.h>
# include <linux/kernel.h>
# include <linux/acpi.h>
# include <linux/libata.h>
# include <linux/pci.h>
# include "libata.h"
# include <acpi/acpi_bus.h>
# include <acpi/acnames.h>
# include <acpi/acnamesp.h>
# include <acpi/acparser.h>
# include <acpi/acexcep.h>
# include <acpi/acmacros.h>
# include <acpi/actypes.h>
# define SATA_ROOT_PORT(x) (((x) >> 16) & 0xffff)
# define SATA_PORT_NUMBER(x) ((x) & 0xffff) /* or NO_PORT_MULT */
# define NO_PORT_MULT 0xffff
# define SATA_ADR_RSVD 0xffffffff
# define REGS_PER_GTF 7
struct taskfile_array {
u8 tfa [ REGS_PER_GTF ] ; /* regs. 0x1f1 - 0x1f7 */
} ;
2007-03-08 23:13:50 +00:00
/*
* Helper - belongs in the PCI layer somewhere eventually
*/
static int is_pci_dev ( struct device * dev )
{
return ( dev - > bus = = & pci_bus_type ) ;
}
2006-09-28 11:29:01 -07:00
/**
* sata_get_dev_handle - finds acpi_handle and PCI device . function
* @ dev : device to locate
* @ handle : returned acpi_handle for @ dev
* @ pcidevfn : return PCI device . func for @ dev
*
* This function is somewhat SATA - specific . Or at least the
* PATA & SATA versions of this function are different ,
* so it ' s not entirely generic code .
*
* Returns 0 on success , < 0 on error .
*/
static int sata_get_dev_handle ( struct device * dev , acpi_handle * handle ,
acpi_integer * pcidevfn )
{
struct pci_dev * pci_dev ;
acpi_integer addr ;
2007-03-08 23:13:50 +00:00
if ( ! is_pci_dev ( dev ) )
return - ENODEV ;
2006-09-28 11:29:01 -07:00
pci_dev = to_pci_dev ( dev ) ; /* NOTE: PCI-specific */
/* Please refer to the ACPI spec for the syntax of _ADR. */
addr = ( PCI_SLOT ( pci_dev - > devfn ) < < 16 ) | PCI_FUNC ( pci_dev - > devfn ) ;
* pcidevfn = addr ;
* handle = acpi_get_child ( DEVICE_ACPI_HANDLE ( dev - > parent ) , addr ) ;
if ( ! * handle )
return - ENODEV ;
return 0 ;
}
/**
* pata_get_dev_handle - finds acpi_handle and PCI device . function
* @ dev : device to locate
* @ handle : returned acpi_handle for @ dev
* @ pcidevfn : return PCI device . func for @ dev
*
* The PATA and SATA versions of this function are different .
*
* Returns 0 on success , < 0 on error .
*/
static int pata_get_dev_handle ( struct device * dev , acpi_handle * handle ,
acpi_integer * pcidevfn )
{
unsigned int bus , devnum , func ;
acpi_integer addr ;
acpi_handle dev_handle , parent_handle ;
struct acpi_buffer buffer = { . length = ACPI_ALLOCATE_BUFFER ,
. pointer = NULL } ;
acpi_status status ;
struct acpi_device_info * dinfo = NULL ;
int ret = - ENODEV ;
2007-03-08 23:13:50 +00:00
struct pci_dev * pdev ;
if ( ! is_pci_dev ( dev ) )
return - ENODEV ;
pdev = to_pci_dev ( dev ) ;
2006-09-28 11:29:01 -07:00
bus = pdev - > bus - > number ;
devnum = PCI_SLOT ( pdev - > devfn ) ;
func = PCI_FUNC ( pdev - > devfn ) ;
dev_handle = DEVICE_ACPI_HANDLE ( dev ) ;
parent_handle = DEVICE_ACPI_HANDLE ( dev - > parent ) ;
status = acpi_get_object_info ( parent_handle , & buffer ) ;
if ( ACPI_FAILURE ( status ) )
goto err ;
dinfo = buffer . pointer ;
if ( dinfo & & ( dinfo - > valid & ACPI_VALID_ADR ) & &
dinfo - > address = = bus ) {
/* ACPI spec for _ADR for PCI bus: */
addr = ( acpi_integer ) ( devnum < < 16 | func ) ;
* pcidevfn = addr ;
* handle = dev_handle ;
} else {
goto err ;
}
if ( ! * handle )
goto err ;
ret = 0 ;
err :
kfree ( dinfo ) ;
return ret ;
}
struct walk_info { /* can be trimmed some */
struct device * dev ;
struct acpi_device * adev ;
acpi_handle handle ;
acpi_integer pcidevfn ;
unsigned int drivenum ;
acpi_handle obj_handle ;
struct ata_port * ataport ;
struct ata_device * atadev ;
u32 sata_adr ;
int status ;
char basepath [ ACPI_PATHNAME_MAX ] ;
int basepath_len ;
} ;
static acpi_status get_devices ( acpi_handle handle ,
u32 level , void * context , void * * return_value )
{
acpi_status status ;
struct walk_info * winfo = context ;
struct acpi_buffer namebuf = { ACPI_ALLOCATE_BUFFER , NULL } ;
char * pathname ;
struct acpi_buffer buffer ;
struct acpi_device_info * dinfo ;
status = acpi_get_name ( handle , ACPI_FULL_PATHNAME , & namebuf ) ;
if ( status )
goto ret ;
pathname = namebuf . pointer ;
buffer . length = ACPI_ALLOCATE_BUFFER ;
buffer . pointer = NULL ;
status = acpi_get_object_info ( handle , & buffer ) ;
if ( ACPI_FAILURE ( status ) )
goto out2 ;
dinfo = buffer . pointer ;
/* find full device path name for pcidevfn */
if ( dinfo & & ( dinfo - > valid & ACPI_VALID_ADR ) & &
dinfo - > address = = winfo - > pcidevfn ) {
if ( ata_msg_probe ( winfo - > ataport ) )
ata_dev_printk ( winfo - > atadev , KERN_DEBUG ,
" :%s: matches pcidevfn (0x%llx) \n " ,
pathname , winfo - > pcidevfn ) ;
strlcpy ( winfo - > basepath , pathname ,
sizeof ( winfo - > basepath ) ) ;
winfo - > basepath_len = strlen ( pathname ) ;
goto out ;
}
/* if basepath is not yet known, ignore this object */
if ( ! winfo - > basepath_len )
goto out ;
/* if this object is in scope of basepath, maybe use it */
if ( strncmp ( pathname , winfo - > basepath ,
winfo - > basepath_len ) = = 0 ) {
if ( ! ( dinfo - > valid & ACPI_VALID_ADR ) )
goto out ;
if ( ata_msg_probe ( winfo - > ataport ) )
ata_dev_printk ( winfo - > atadev , KERN_DEBUG ,
" GOT ONE: (%s) root_port = 0x%llx, "
" port_num = 0x%llx \n " , pathname ,
SATA_ROOT_PORT ( dinfo - > address ) ,
SATA_PORT_NUMBER ( dinfo - > address ) ) ;
/* heuristics: */
if ( SATA_PORT_NUMBER ( dinfo - > address ) ! = NO_PORT_MULT )
if ( ata_msg_probe ( winfo - > ataport ) )
ata_dev_printk ( winfo - > atadev ,
KERN_DEBUG , " warning: don't "
" know how to handle SATA port "
" multiplier \n " ) ;
if ( SATA_ROOT_PORT ( dinfo - > address ) = =
winfo - > ataport - > port_no & &
SATA_PORT_NUMBER ( dinfo - > address ) = = NO_PORT_MULT ) {
if ( ata_msg_probe ( winfo - > ataport ) )
ata_dev_printk ( winfo - > atadev ,
KERN_DEBUG ,
" THIS ^^^^^ is the requested "
" SATA drive (handle = 0x%p) \n " ,
handle ) ;
winfo - > sata_adr = dinfo - > address ;
winfo - > obj_handle = handle ;
}
}
out :
kfree ( dinfo ) ;
out2 :
kfree ( pathname ) ;
ret :
return status ;
}
/* Get the SATA drive _ADR object. */
static int get_sata_adr ( struct device * dev , acpi_handle handle ,
acpi_integer pcidevfn , unsigned int drive ,
struct ata_port * ap ,
struct ata_device * atadev , u32 * dev_adr )
{
acpi_status status ;
struct walk_info * winfo ;
int err = - ENOMEM ;
winfo = kzalloc ( sizeof ( struct walk_info ) , GFP_KERNEL ) ;
if ( ! winfo )
goto out ;
winfo - > dev = dev ;
winfo - > atadev = atadev ;
winfo - > ataport = ap ;
if ( acpi_bus_get_device ( handle , & winfo - > adev ) < 0 )
if ( ata_msg_probe ( ap ) )
ata_dev_printk ( winfo - > atadev , KERN_DEBUG ,
" acpi_bus_get_device failed \n " ) ;
winfo - > handle = handle ;
winfo - > pcidevfn = pcidevfn ;
winfo - > drivenum = drive ;
status = acpi_get_devices ( NULL , get_devices , winfo , NULL ) ;
if ( ACPI_FAILURE ( status ) ) {
if ( ata_msg_probe ( ap ) )
ata_dev_printk ( winfo - > atadev , KERN_DEBUG ,
" %s: acpi_get_devices failed \n " ,
__FUNCTION__ ) ;
err = - ENODEV ;
} else {
* dev_adr = winfo - > sata_adr ;
atadev - > obj_handle = winfo - > obj_handle ;
err = 0 ;
}
kfree ( winfo ) ;
out :
return err ;
}
/**
* do_drive_get_GTF - get the drive bootup default taskfile settings
2007-05-05 23:50:38 +09:00
* @ dev : target ATA device
2006-09-28 11:29:01 -07:00
* @ gtf_length : number of bytes of _GTF data returned at @ gtf_address
* @ gtf_address : buffer containing _GTF taskfile arrays
*
* This applies to both PATA and SATA drives .
*
* The _GTF method has no input parameters .
* It returns a variable number of register set values ( registers
* hex 1F 1. .1F 7 , taskfiles ) .
* The < variable number > is not known in advance , so have ACPI - CA
* allocate the buffer as needed and return it , then free it later .
*
* The returned @ gtf_length and @ gtf_address are only valid if the
* function return value is 0.
*/
2007-05-05 23:50:38 +09:00
static int do_drive_get_GTF ( struct ata_device * dev , unsigned int * gtf_length ,
unsigned long * gtf_address , unsigned long * obj_loc )
2006-09-28 11:29:01 -07:00
{
2007-05-05 23:50:38 +09:00
struct ata_port * ap = dev - > ap ;
acpi_status status ;
acpi_handle dev_handle = NULL ;
acpi_handle chan_handle , drive_handle ;
acpi_integer pcidevfn = 0 ;
u32 dev_adr ;
struct acpi_buffer output ;
union acpi_object * out_obj ;
struct device * gdev = ap - > host - > dev ;
int err = - ENODEV ;
2006-09-28 11:29:01 -07:00
* gtf_length = 0 ;
* gtf_address = 0UL ;
* obj_loc = 0UL ;
2007-03-28 01:57:37 -04:00
if ( libata_noacpi )
2006-09-28 11:29:01 -07:00
return 0 ;
if ( ata_msg_probe ( ap ) )
2007-05-05 23:50:38 +09:00
ata_dev_printk ( dev , KERN_DEBUG , " %s: ENTER: port#: %d \n " ,
2007-02-21 16:36:33 +09:00
__FUNCTION__ , ap - > port_no ) ;
2006-09-28 11:29:01 -07:00
2007-05-05 23:50:38 +09:00
if ( ! ata_dev_enabled ( dev ) | | ( ap - > flags & ATA_FLAG_DISABLED ) ) {
2006-09-28 11:29:01 -07:00
if ( ata_msg_probe ( ap ) )
2007-05-05 23:50:38 +09:00
ata_dev_printk ( dev , KERN_DEBUG , " %s: ERR: "
2006-09-28 11:29:01 -07:00
" ata_dev_present: %d, PORT_DISABLED: %lu \n " ,
2007-05-05 23:50:38 +09:00
__FUNCTION__ , ata_dev_enabled ( dev ) ,
2006-09-28 11:29:01 -07:00
ap - > flags & ATA_FLAG_DISABLED ) ;
goto out ;
}
/* Don't continue if device has no _ADR method.
* _GTF is intended for known motherboard devices . */
2007-05-15 03:28:15 +09:00
if ( ! ( ap - > flags & ATA_FLAG_ACPI_SATA ) ) {
2007-05-05 23:50:38 +09:00
err = pata_get_dev_handle ( gdev , & dev_handle , & pcidevfn ) ;
2006-09-28 11:29:01 -07:00
if ( err < 0 ) {
if ( ata_msg_probe ( ap ) )
2007-05-05 23:50:38 +09:00
ata_dev_printk ( dev , KERN_DEBUG ,
2006-09-28 11:29:01 -07:00
" %s: pata_get_dev_handle failed (%d) \n " ,
__FUNCTION__ , err ) ;
goto out ;
}
} else {
2007-05-05 23:50:38 +09:00
err = sata_get_dev_handle ( gdev , & dev_handle , & pcidevfn ) ;
2006-09-28 11:29:01 -07:00
if ( err < 0 ) {
if ( ata_msg_probe ( ap ) )
2007-05-05 23:50:38 +09:00
ata_dev_printk ( dev , KERN_DEBUG ,
2006-09-28 11:29:01 -07:00
" %s: sata_get_dev_handle failed (%d \n " ,
__FUNCTION__ , err ) ;
goto out ;
}
}
/* Get this drive's _ADR info. if not already known. */
2007-05-05 23:50:38 +09:00
if ( ! dev - > obj_handle ) {
2007-05-15 03:28:15 +09:00
if ( ! ( ap - > flags & ATA_FLAG_ACPI_SATA ) ) {
2006-09-28 11:29:01 -07:00
/* get child objects of dev_handle == channel objects,
* + _their_ children = = drive objects */
/* channel is ap->port_no */
chan_handle = acpi_get_child ( dev_handle ,
ap - > port_no ) ;
if ( ata_msg_probe ( ap ) )
2007-05-05 23:50:38 +09:00
ata_dev_printk ( dev , KERN_DEBUG ,
2006-09-28 11:29:01 -07:00
" %s: chan adr=%d: chan_handle=0x%p \n " ,
__FUNCTION__ , ap - > port_no ,
chan_handle ) ;
if ( ! chan_handle ) {
err = - ENODEV ;
goto out ;
}
/* TBD: could also check ACPI object VALID bits */
2007-05-05 23:50:38 +09:00
drive_handle = acpi_get_child ( chan_handle , dev - > devno ) ;
2006-09-28 11:29:01 -07:00
if ( ! drive_handle ) {
err = - ENODEV ;
goto out ;
}
2007-05-05 23:50:38 +09:00
dev_adr = dev - > devno ;
dev - > obj_handle = drive_handle ;
2006-09-28 11:29:01 -07:00
} else { /* for SATA mode */
dev_adr = SATA_ADR_RSVD ;
2007-05-05 23:50:38 +09:00
err = get_sata_adr ( gdev , dev_handle , pcidevfn , 0 ,
ap , dev , & dev_adr ) ;
2006-09-28 11:29:01 -07:00
}
if ( err < 0 | | dev_adr = = SATA_ADR_RSVD | |
2007-05-05 23:50:38 +09:00
! dev - > obj_handle ) {
2006-09-28 11:29:01 -07:00
if ( ata_msg_probe ( ap ) )
2007-05-05 23:50:38 +09:00
ata_dev_printk ( dev , KERN_DEBUG ,
2006-09-28 11:29:01 -07:00
" %s: get_sata/pata_adr failed: "
" err=%d, dev_adr=%u, obj_handle=0x%p \n " ,
__FUNCTION__ , err , dev_adr ,
2007-05-05 23:50:38 +09:00
dev - > obj_handle ) ;
2006-09-28 11:29:01 -07:00
goto out ;
}
}
/* Setting up output buffer */
output . length = ACPI_ALLOCATE_BUFFER ;
output . pointer = NULL ; /* ACPI-CA sets this; save/free it later */
/* _GTF has no input parameters */
err = - EIO ;
2007-05-05 23:50:38 +09:00
status = acpi_evaluate_object ( dev - > obj_handle , " _GTF " ,
2006-09-28 11:29:01 -07:00
NULL , & output ) ;
if ( ACPI_FAILURE ( status ) ) {
if ( ata_msg_probe ( ap ) )
2007-05-05 23:50:38 +09:00
ata_dev_printk ( dev , KERN_DEBUG ,
2006-09-28 11:29:01 -07:00
" %s: Run _GTF error: status = 0x%x \n " ,
__FUNCTION__ , status ) ;
goto out ;
}
if ( ! output . length | | ! output . pointer ) {
if ( ata_msg_probe ( ap ) )
2007-05-05 23:50:38 +09:00
ata_dev_printk ( dev , KERN_DEBUG , " %s: Run _GTF: "
2006-09-28 11:29:01 -07:00
" length or ptr is NULL (0x%llx, 0x%p) \n " ,
__FUNCTION__ ,
( unsigned long long ) output . length ,
output . pointer ) ;
kfree ( output . pointer ) ;
goto out ;
}
out_obj = output . pointer ;
if ( out_obj - > type ! = ACPI_TYPE_BUFFER ) {
kfree ( output . pointer ) ;
if ( ata_msg_probe ( ap ) )
2007-05-05 23:50:38 +09:00
ata_dev_printk ( dev , KERN_DEBUG , " %s: Run _GTF: "
2006-09-28 11:29:01 -07:00
" error: expected object type of "
" ACPI_TYPE_BUFFER, got 0x%x \n " ,
__FUNCTION__ , out_obj - > type ) ;
err = - ENOENT ;
goto out ;
}
if ( ! out_obj - > buffer . length | | ! out_obj - > buffer . pointer | |
out_obj - > buffer . length % REGS_PER_GTF ) {
if ( ata_msg_drv ( ap ) )
2007-05-05 23:50:38 +09:00
ata_dev_printk ( dev , KERN_ERR ,
2006-09-28 11:29:01 -07:00
" %s: unexpected GTF length (%d) or addr (0x%p) \n " ,
__FUNCTION__ , out_obj - > buffer . length ,
out_obj - > buffer . pointer ) ;
err = - ENOENT ;
goto out ;
}
* gtf_length = out_obj - > buffer . length ;
* gtf_address = ( unsigned long ) out_obj - > buffer . pointer ;
* obj_loc = ( unsigned long ) out_obj ;
if ( ata_msg_probe ( ap ) )
2007-05-05 23:50:38 +09:00
ata_dev_printk ( dev , KERN_DEBUG , " %s: returning "
2006-09-28 11:29:01 -07:00
" gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx \n " ,
__FUNCTION__ , * gtf_length , * gtf_address , * obj_loc ) ;
err = 0 ;
out :
return err ;
}
/**
* taskfile_load_raw - send taskfile registers to host controller
2007-05-05 23:50:38 +09:00
* @ dev : target ATA device
2006-09-28 11:29:01 -07:00
* @ gtf : raw ATA taskfile register set ( 0x1f1 - 0x1f7 )
*
* Outputs ATA taskfile to standard ATA host controller using MMIO
* or PIO as indicated by the ATA_FLAG_MMIO flag .
* Writes the control , feature , nsect , lbal , lbam , and lbah registers .
* Optionally ( ATA_TFLAG_LBA48 ) writes hob_feature , hob_nsect ,
* hob_lbal , hob_lbam , and hob_lbah .
*
* This function waits for idle ( ! BUSY and ! DRQ ) after writing
* registers . If the control register has a new value , this
* function also waits for idle after writing control and before
* writing the remaining registers .
*
* LOCKING : TBD :
* Inherited from caller .
*/
2007-05-05 23:50:38 +09:00
static void taskfile_load_raw ( struct ata_device * dev ,
const struct taskfile_array * gtf )
2006-09-28 11:29:01 -07:00
{
2007-05-05 23:50:38 +09:00
struct ata_port * ap = dev - > ap ;
2007-02-24 21:05:01 -05:00
struct ata_taskfile tf ;
unsigned int err ;
2006-09-28 11:29:01 -07:00
if ( ata_msg_probe ( ap ) )
2007-05-05 23:50:38 +09:00
ata_dev_printk ( dev , KERN_DEBUG , " %s: (0x1f1-1f7): hex: "
2006-09-28 11:29:01 -07:00
" %02x %02x %02x %02x %02x %02x %02x \n " ,
__FUNCTION__ ,
gtf - > tfa [ 0 ] , gtf - > tfa [ 1 ] , gtf - > tfa [ 2 ] ,
gtf - > tfa [ 3 ] , gtf - > tfa [ 4 ] , gtf - > tfa [ 5 ] , gtf - > tfa [ 6 ] ) ;
if ( ( gtf - > tfa [ 0 ] = = 0 ) & & ( gtf - > tfa [ 1 ] = = 0 ) & & ( gtf - > tfa [ 2 ] = = 0 )
& & ( gtf - > tfa [ 3 ] = = 0 ) & & ( gtf - > tfa [ 4 ] = = 0 ) & & ( gtf - > tfa [ 5 ] = = 0 )
& & ( gtf - > tfa [ 6 ] = = 0 ) )
return ;
2007-05-05 23:50:38 +09:00
ata_tf_init ( dev , & tf ) ;
2007-02-24 21:05:01 -05:00
/* convert gtf to tf */
tf . flags | = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE ; /* TBD */
2007-04-23 02:06:46 +09:00
tf . protocol = ATA_PROT_NODATA ;
2007-02-24 21:05:01 -05:00
tf . feature = gtf - > tfa [ 0 ] ; /* 0x1f1 */
tf . nsect = gtf - > tfa [ 1 ] ; /* 0x1f2 */
tf . lbal = gtf - > tfa [ 2 ] ; /* 0x1f3 */
tf . lbam = gtf - > tfa [ 3 ] ; /* 0x1f4 */
tf . lbah = gtf - > tfa [ 4 ] ; /* 0x1f5 */
tf . device = gtf - > tfa [ 5 ] ; /* 0x1f6 */
tf . command = gtf - > tfa [ 6 ] ; /* 0x1f7 */
2007-05-05 23:50:38 +09:00
err = ata_exec_internal ( dev , & tf , NULL , DMA_NONE , NULL , 0 ) ;
2007-02-24 21:05:01 -05:00
if ( err & & ata_msg_probe ( ap ) )
2007-05-05 23:50:38 +09:00
ata_dev_printk ( dev , KERN_ERR ,
2007-02-24 21:05:01 -05:00
" %s: ata_exec_internal failed: %u \n " ,
__FUNCTION__ , err ) ;
2006-09-28 11:29:01 -07:00
}
/**
* do_drive_set_taskfiles - write the drive taskfile settings from _GTF
2007-05-05 23:50:38 +09:00
* @ dev : target ATA device
2006-09-28 11:29:01 -07:00
* @ gtf_length : total number of bytes of _GTF taskfiles
* @ gtf_address : location of _GTF taskfile arrays
*
* This applies to both PATA and SATA drives .
*
* Write { gtf_address , length gtf_length } in groups of
* REGS_PER_GTF bytes .
*/
2007-05-05 23:50:38 +09:00
static int do_drive_set_taskfiles ( struct ata_device * dev ,
unsigned int gtf_length ,
unsigned long gtf_address )
2006-09-28 11:29:01 -07:00
{
2007-05-05 23:50:38 +09:00
struct ata_port * ap = dev - > ap ;
int err = - ENODEV ;
int gtf_count = gtf_length / REGS_PER_GTF ;
int ix ;
2006-09-28 11:29:01 -07:00
struct taskfile_array * gtf ;
if ( ata_msg_probe ( ap ) )
2007-05-05 23:50:38 +09:00
ata_dev_printk ( dev , KERN_DEBUG , " %s: ENTER: port#: %d \n " ,
2007-02-21 16:36:33 +09:00
__FUNCTION__ , ap - > port_no ) ;
2006-09-28 11:29:01 -07:00
2007-05-15 03:28:15 +09:00
if ( libata_noacpi | | ! ( ap - > flags & ATA_FLAG_ACPI_SATA ) )
2006-09-28 11:29:01 -07:00
return 0 ;
2007-05-05 23:50:38 +09:00
if ( ! ata_dev_enabled ( dev ) | | ( ap - > flags & ATA_FLAG_DISABLED ) )
2006-09-28 11:29:01 -07:00
goto out ;
if ( ! gtf_count ) /* shouldn't be here */
goto out ;
if ( gtf_length % REGS_PER_GTF ) {
if ( ata_msg_drv ( ap ) )
2007-05-05 23:50:38 +09:00
ata_dev_printk ( dev , KERN_ERR ,
2006-09-28 11:29:01 -07:00
" %s: unexpected GTF length (%d) \n " ,
__FUNCTION__ , gtf_length ) ;
goto out ;
}
for ( ix = 0 ; ix < gtf_count ; ix + + ) {
gtf = ( struct taskfile_array * )
( gtf_address + ix * REGS_PER_GTF ) ;
/* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */
2007-05-05 23:50:38 +09:00
taskfile_load_raw ( dev , gtf ) ;
2006-09-28 11:29:01 -07:00
}
err = 0 ;
out :
return err ;
}
/**
* ata_acpi_exec_tfs - get then write drive taskfile settings
* @ ap : the ata_port for the drive
*
* This applies to both PATA and SATA drives .
*/
int ata_acpi_exec_tfs ( struct ata_port * ap )
{
2007-05-05 23:50:38 +09:00
int ix ;
int ret = 0 ;
unsigned int gtf_length ;
unsigned long gtf_address ;
unsigned long obj_loc ;
2006-09-28 11:29:01 -07:00
2007-03-28 01:57:37 -04:00
if ( libata_noacpi )
2006-09-28 11:29:01 -07:00
return 0 ;
2007-03-09 18:15:33 -05:00
/*
* TBD - implement PATA support . For now ,
* we should not run GTF on PATA devices since some
* PATA require execution of GTM / STM before GTF .
*/
2007-05-15 03:28:15 +09:00
if ( ! ( ap - > flags & ATA_FLAG_ACPI_SATA ) )
2007-03-09 18:15:33 -05:00
return 0 ;
2006-09-28 11:29:01 -07:00
for ( ix = 0 ; ix < ATA_MAX_DEVICES ; ix + + ) {
2007-05-05 23:50:38 +09:00
struct ata_device * dev = & ap - > device [ ix ] ;
if ( ! ata_dev_enabled ( dev ) )
2006-09-28 11:29:01 -07:00
continue ;
2007-05-05 23:50:38 +09:00
ret = do_drive_get_GTF ( dev , & gtf_length , & gtf_address ,
& obj_loc ) ;
2006-09-28 11:29:01 -07:00
if ( ret < 0 ) {
if ( ata_msg_probe ( ap ) )
ata_port_printk ( ap , KERN_DEBUG ,
" %s: get_GTF error (%d) \n " ,
__FUNCTION__ , ret ) ;
break ;
}
2007-05-05 23:50:38 +09:00
ret = do_drive_set_taskfiles ( dev , gtf_length , gtf_address ) ;
2006-09-28 11:29:01 -07:00
kfree ( ( void * ) obj_loc ) ;
if ( ret < 0 ) {
if ( ata_msg_probe ( ap ) )
ata_port_printk ( ap , KERN_DEBUG ,
" %s: set_taskfiles error (%d) \n " ,
__FUNCTION__ , ret ) ;
break ;
}
}
return ret ;
}
2006-09-28 11:29:12 -07:00
/**
* ata_acpi_push_id - send Identify data to drive
2007-05-05 23:50:38 +09:00
* @ dev : target ATA device
2006-09-28 11:29:12 -07:00
*
* _SDD ACPI object : for SATA mode only
* Must be after Identify ( Packet ) Device - - uses its data
* ATM this function never returns a failure . It is an optional
* method and if it fails for whatever reason , we should still
* just keep going .
*/
2007-05-05 23:50:38 +09:00
int ata_acpi_push_id ( struct ata_device * dev )
2006-09-28 11:29:12 -07:00
{
2007-05-05 23:50:38 +09:00
struct ata_port * ap = dev - > ap ;
acpi_handle handle ;
acpi_integer pcidevfn ;
int err ;
struct device * gdev = ap - > host - > dev ;
u32 dev_adr ;
acpi_status status ;
struct acpi_object_list input ;
union acpi_object in_params [ 1 ] ;
2006-09-28 11:29:12 -07:00
2007-03-28 01:57:37 -04:00
if ( libata_noacpi )
2006-09-28 11:29:12 -07:00
return 0 ;
if ( ata_msg_probe ( ap ) )
2007-05-05 23:50:38 +09:00
ata_dev_printk ( dev , KERN_DEBUG , " %s: ix = %d, port#: %d \n " ,
__FUNCTION__ , dev - > devno , ap - > port_no ) ;
2006-09-28 11:29:12 -07:00
/* Don't continue if not a SATA device. */
2007-05-15 03:28:15 +09:00
if ( ! ( ap - > flags & ATA_FLAG_ACPI_SATA ) ) {
2006-09-28 11:29:12 -07:00
if ( ata_msg_probe ( ap ) )
2007-05-05 23:50:38 +09:00
ata_dev_printk ( dev , KERN_DEBUG ,
2006-09-28 11:29:12 -07:00
" %s: Not a SATA device \n " , __FUNCTION__ ) ;
goto out ;
}
/* Don't continue if device has no _ADR method.
* _SDD is intended for known motherboard devices . */
2007-05-05 23:50:38 +09:00
err = sata_get_dev_handle ( gdev , & handle , & pcidevfn ) ;
2006-09-28 11:29:12 -07:00
if ( err < 0 ) {
if ( ata_msg_probe ( ap ) )
2007-05-05 23:50:38 +09:00
ata_dev_printk ( dev , KERN_DEBUG ,
2006-09-28 11:29:12 -07:00
" %s: sata_get_dev_handle failed (%d \n " ,
__FUNCTION__ , err ) ;
goto out ;
}
/* Get this drive's _ADR info, if not already known */
2007-05-05 23:50:38 +09:00
if ( ! dev - > obj_handle ) {
2006-09-28 11:29:12 -07:00
dev_adr = SATA_ADR_RSVD ;
2007-05-05 23:50:38 +09:00
err = get_sata_adr ( gdev , handle , pcidevfn , dev - > devno , ap , dev ,
2006-09-28 11:29:12 -07:00
& dev_adr ) ;
if ( err < 0 | | dev_adr = = SATA_ADR_RSVD | |
2007-05-05 23:50:38 +09:00
! dev - > obj_handle ) {
2006-09-28 11:29:12 -07:00
if ( ata_msg_probe ( ap ) )
2007-05-05 23:50:38 +09:00
ata_dev_printk ( dev , KERN_DEBUG ,
2006-09-28 11:29:12 -07:00
" %s: get_sata_adr failed: "
" err=%d, dev_adr=%u, obj_handle=0x%p \n " ,
__FUNCTION__ , err , dev_adr ,
2007-05-05 23:50:38 +09:00
dev - > obj_handle ) ;
2006-09-28 11:29:12 -07:00
goto out ;
}
}
/* Give the drive Identify data to the drive via the _SDD method */
/* _SDD: set up input parameters */
input . count = 1 ;
input . pointer = in_params ;
in_params [ 0 ] . type = ACPI_TYPE_BUFFER ;
2007-05-05 23:50:38 +09:00
in_params [ 0 ] . buffer . length = sizeof ( dev - > id [ 0 ] ) * ATA_ID_WORDS ;
in_params [ 0 ] . buffer . pointer = ( u8 * ) dev - > id ;
2006-09-28 11:29:12 -07:00
/* Output buffer: _SDD has no output */
/* It's OK for _SDD to be missing too. */
2007-05-05 23:50:38 +09:00
swap_buf_le16 ( dev - > id , ATA_ID_WORDS ) ;
status = acpi_evaluate_object ( dev - > obj_handle , " _SDD " , & input , NULL ) ;
swap_buf_le16 ( dev - > id , ATA_ID_WORDS ) ;
2006-09-28 11:29:12 -07:00
err = ACPI_FAILURE ( status ) ? - EIO : 0 ;
if ( err < 0 ) {
if ( ata_msg_probe ( ap ) )
2007-05-05 23:50:38 +09:00
ata_dev_printk ( dev , KERN_DEBUG ,
2007-02-21 16:36:33 +09:00
" %s _SDD error: status = 0x%x \n " ,
__FUNCTION__ , status ) ;
2006-09-28 11:29:12 -07:00
}
/* always return success */
out :
return 0 ;
}