2006-08-30 02:12:40 +04:00
/*
* ata - serverworks . c - Serverworks PATA for new ATA layer
* ( C ) 2005 Red Hat Inc
* Alan Cox < alan @ redhat . com >
*
* based upon
*
* serverworks . c
2006-08-31 08:03:49 +04:00
*
2006-08-30 02:12:40 +04:00
* Copyright ( C ) 1998 - 2000 Michel Aubry
* Copyright ( C ) 1998 - 2000 Andrzej Krzysztofowicz
* Copyright ( C ) 1998 - 2000 Andre Hedrick < andre @ linux - ide . org >
* Portions copyright ( c ) 2001 Sun Microsystems
*
*
* RCC / ServerWorks IDE driver for Linux
*
* OSB4 : ` Open South Bridge ' IDE Interface ( fn 1 )
* supports UDMA mode 2 ( 33 MB / s )
*
* CSB5 : ` Champion South Bridge ' IDE Interface ( fn 1 )
* all revisions support UDMA mode 4 ( 66 MB / s )
* revision A2 .0 and up support UDMA mode 5 ( 100 MB / s )
*
* * * * The CSB5 does not provide ANY register * * *
* * * * to detect 80 - conductor cable presence . * * *
*
* CSB6 : ` Champion South Bridge ' IDE Interface ( optional : third channel )
*
* Documentation :
* Available under NDA only . Errata info very hard to get .
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/pci.h>
# include <linux/init.h>
# include <linux/blkdev.h>
# include <linux/delay.h>
# include <scsi/scsi_host.h>
# include <linux/libata.h>
# define DRV_NAME "pata_serverworks"
2006-11-27 19:16:35 +03:00
# define DRV_VERSION "0.3.9"
2006-08-30 02:12:40 +04:00
# define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
# define SVWKS_CSB6_REVISION 0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */
/* Seagate Barracuda ATA IV Family drives in UDMA mode 5
* can overrun their FIFOs when used with the CSB5 */
static const char * csb_bad_ata100 [ ] = {
" ST320011A " ,
" ST340016A " ,
" ST360021A " ,
" ST380021A " ,
NULL
} ;
/**
* dell_cable - Dell serverworks cable detection
* @ ap : ATA port to do cable detect
*
* Dell hide the 40 / 80 pin select for their interfaces in the top two
2006-08-31 08:03:49 +04:00
* bits of the subsystem ID .
2006-08-30 02:12:40 +04:00
*/
2006-08-31 08:03:49 +04:00
2006-08-30 02:12:40 +04:00
static int dell_cable ( struct ata_port * ap ) {
struct pci_dev * pdev = to_pci_dev ( ap - > host - > dev ) ;
2006-08-31 08:03:49 +04:00
2006-08-30 02:12:40 +04:00
if ( pdev - > subsystem_device & ( 1 < < ( ap - > port_no + 14 ) ) )
return ATA_CBL_PATA80 ;
return ATA_CBL_PATA40 ;
}
/**
* sun_cable - Sun Cobalt ' Alpine ' cable detection
* @ ap : ATA port to do cable select
*
* Cobalt CSB5 IDE hides the 40 / 80 pin in the top two bits of the
* subsystem ID the same as dell . We could use one function but we may
* need to extend the Dell one in future
*/
2006-08-31 08:03:49 +04:00
2006-08-30 02:12:40 +04:00
static int sun_cable ( struct ata_port * ap ) {
struct pci_dev * pdev = to_pci_dev ( ap - > host - > dev ) ;
2006-08-31 08:03:49 +04:00
2006-08-30 02:12:40 +04:00
if ( pdev - > subsystem_device & ( 1 < < ( ap - > port_no + 14 ) ) )
return ATA_CBL_PATA80 ;
return ATA_CBL_PATA40 ;
}
/**
* osb4_cable - OSB4 cable detect
* @ ap : ATA port to check
*
* The OSB4 isn ' t UDMA66 capable so this is easy
*/
static int osb4_cable ( struct ata_port * ap ) {
return ATA_CBL_PATA40 ;
}
/**
* csb4_cable - CSB5 / 6 cable detect
* @ ap : ATA port to check
*
* Serverworks default arrangement is to use the drive side detection
* only .
*/
static int csb_cable ( struct ata_port * ap ) {
return ATA_CBL_PATA80 ;
}
struct sv_cable_table {
int device ;
int subvendor ;
int ( * cable_detect ) ( struct ata_port * ap ) ;
} ;
/*
* Note that we don ' t copy the old serverworks code because the old
* code contains obvious mistakes
*/
2006-08-31 08:03:49 +04:00
2006-08-30 02:12:40 +04:00
static struct sv_cable_table cable_detect [ ] = {
{ PCI_DEVICE_ID_SERVERWORKS_CSB5IDE , PCI_VENDOR_ID_DELL , dell_cable } ,
{ PCI_DEVICE_ID_SERVERWORKS_CSB6IDE , PCI_VENDOR_ID_DELL , dell_cable } ,
{ PCI_DEVICE_ID_SERVERWORKS_CSB5IDE , PCI_VENDOR_ID_SUN , sun_cable } ,
2006-09-27 01:24:31 +04:00
{ PCI_DEVICE_ID_SERVERWORKS_OSB4IDE , PCI_ANY_ID , osb4_cable } ,
2006-08-30 02:12:40 +04:00
{ PCI_DEVICE_ID_SERVERWORKS_CSB5IDE , PCI_ANY_ID , csb_cable } ,
{ PCI_DEVICE_ID_SERVERWORKS_CSB6IDE , PCI_ANY_ID , csb_cable } ,
{ PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2 , PCI_ANY_ID , csb_cable } ,
{ PCI_DEVICE_ID_SERVERWORKS_HT1000IDE , PCI_ANY_ID , csb_cable } ,
{ }
} ;
/**
* serverworks_pre_reset - cable detection
* @ ap : ATA port
*
2006-08-31 08:03:49 +04:00
* Perform cable detection according to the device and subvendor
2006-08-30 02:12:40 +04:00
* identifications
*/
2006-08-31 08:03:49 +04:00
2006-08-30 02:12:40 +04:00
static int serverworks_pre_reset ( struct ata_port * ap ) {
struct pci_dev * pdev = to_pci_dev ( ap - > host - > dev ) ;
struct sv_cable_table * cb = cable_detect ;
while ( cb - > device ) {
2006-08-31 08:03:49 +04:00
if ( cb - > device = = pdev - > device & &
2006-08-30 02:12:40 +04:00
( cb - > subvendor = = pdev - > subsystem_vendor | |
cb - > subvendor = = PCI_ANY_ID ) ) {
ap - > cbl = cb - > cable_detect ( ap ) ;
return ata_std_prereset ( ap ) ;
}
cb + + ;
}
BUG ( ) ;
return - 1 ; /* kill compiler warning */
}
static void serverworks_error_handler ( struct ata_port * ap )
{
return ata_bmdma_drive_eh ( ap , serverworks_pre_reset , ata_std_softreset , NULL , ata_std_postreset ) ;
}
/**
* serverworks_is_csb - Check for CSB or OSB
* @ pdev : PCI device to check
*
* Returns true if the device being checked is known to be a CSB
* series device .
*/
2006-08-31 08:03:49 +04:00
2006-08-30 02:12:40 +04:00
static u8 serverworks_is_csb ( struct pci_dev * pdev )
{
switch ( pdev - > device ) {
case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE :
case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE :
case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2 :
case PCI_DEVICE_ID_SERVERWORKS_HT1000IDE :
return 1 ;
default :
break ;
}
return 0 ;
}
/**
* serverworks_osb4_filter - mode selection filter
* @ ap : ATA interface
* @ adev : ATA device
*
* Filter the offered modes for the device to apply controller
* specific rules . OSB4 requires no UDMA for disks due to a FIFO
* bug we hit .
*/
2006-08-31 08:03:49 +04:00
2006-08-30 02:12:40 +04:00
static unsigned long serverworks_osb4_filter ( const struct ata_port * ap , struct ata_device * adev , unsigned long mask )
{
if ( adev - > class = = ATA_DEV_ATA )
mask & = ~ ATA_MASK_UDMA ;
return ata_pci_default_filter ( ap , adev , mask ) ;
}
/**
* serverworks_csb_filter - mode selection filter
* @ ap : ATA interface
* @ adev : ATA device
*
* Check the blacklist and disable UDMA5 if matched
*/
static unsigned long serverworks_csb_filter ( const struct ata_port * ap , struct ata_device * adev , unsigned long mask )
{
const char * p ;
char model_num [ 40 ] ;
int len , i ;
2006-08-31 08:03:49 +04:00
/* Disk, UDMA */
2006-08-30 02:12:40 +04:00
if ( adev - > class ! = ATA_DEV_ATA )
return ata_pci_default_filter ( ap , adev , mask ) ;
/* Actually do need to check */
ata_id_string ( adev - > id , model_num , ATA_ID_PROD_OFS , sizeof ( model_num ) ) ;
/* Precuationary - why not do this in the libata core ?? */
2006-08-31 08:03:49 +04:00
2006-08-30 02:12:40 +04:00
len = strlen ( model_num ) ;
while ( ( len > 0 ) & & ( model_num [ len - 1 ] = = ' ' ) ) {
len - - ;
model_num [ len ] = 0 ;
}
for ( i = 0 ; ( p = csb_bad_ata100 [ i ] ) ! = NULL ; i + + ) {
if ( ! strncmp ( p , model_num , len ) )
mask & = ~ ( 0x1F < < ATA_SHIFT_UDMA ) ;
}
return ata_pci_default_filter ( ap , adev , mask ) ;
}
/**
* serverworks_set_piomode - set initial PIO mode data
* @ ap : ATA interface
* @ adev : ATA device
*
* Program the OSB4 / CSB5 timing registers for PIO . The PIO register
* load is done as a simple lookup .
*/
static void serverworks_set_piomode ( struct ata_port * ap , struct ata_device * adev )
{
static const u8 pio_mode [ ] = { 0x5d , 0x47 , 0x34 , 0x22 , 0x20 } ;
int offset = 1 + ( 2 * ap - > port_no ) - adev - > devno ;
int devbits = ( 2 * ap - > port_no + adev - > devno ) * 4 ;
u16 csb5_pio ;
struct pci_dev * pdev = to_pci_dev ( ap - > host - > dev ) ;
int pio = adev - > pio_mode - XFER_PIO_0 ;
pci_write_config_byte ( pdev , 0x40 + offset , pio_mode [ pio ] ) ;
2006-08-31 08:03:49 +04:00
2006-08-30 02:12:40 +04:00
/* The OSB4 just requires the timing but the CSB series want the
mode number as well */
if ( serverworks_is_csb ( pdev ) ) {
pci_read_config_word ( pdev , 0x4A , & csb5_pio ) ;
csb5_pio & = ~ ( 0x0F < < devbits ) ;
pci_write_config_byte ( pdev , 0x4A , csb5_pio | ( pio < < devbits ) ) ;
}
}
/**
* serverworks_set_dmamode - set initial DMA mode data
* @ ap : ATA interface
* @ adev : ATA device
*
* Program the MWDMA / UDMA modes for the serverworks OSB4 / CSB5
* chipset . The MWDMA mode values are pulled from a lookup table
* while the chipset uses mode number for UDMA .
*/
static void serverworks_set_dmamode ( struct ata_port * ap , struct ata_device * adev )
{
static const u8 dma_mode [ ] = { 0x77 , 0x21 , 0x20 } ;
int offset = 1 + 2 * ap - > port_no - adev - > devno ;
int devbits = ( 2 * ap - > port_no + adev - > devno ) ;
u8 ultra ;
u8 ultra_cfg ;
struct pci_dev * pdev = to_pci_dev ( ap - > host - > dev ) ;
pci_read_config_byte ( pdev , 0x54 , & ultra_cfg ) ;
if ( adev - > dma_mode > = XFER_UDMA_0 ) {
pci_write_config_byte ( pdev , 0x44 + offset , 0x20 ) ;
pci_read_config_byte ( pdev , 0x56 + ap - > port_no , & ultra ) ;
ultra & = ~ ( 0x0F < < ( ap - > port_no * 4 ) ) ;
ultra | = ( adev - > dma_mode - XFER_UDMA_0 )
< < ( ap - > port_no * 4 ) ;
pci_write_config_byte ( pdev , 0x56 + ap - > port_no , ultra ) ;
ultra_cfg | = ( 1 < < devbits ) ;
} else {
2006-08-31 08:03:49 +04:00
pci_write_config_byte ( pdev , 0x44 + offset ,
2006-08-30 02:12:40 +04:00
dma_mode [ adev - > dma_mode - XFER_MW_DMA_0 ] ) ;
ultra_cfg & = ~ ( 1 < < devbits ) ;
}
pci_write_config_byte ( pdev , 0x54 , ultra_cfg ) ;
}
static struct scsi_host_template serverworks_sht = {
. module = THIS_MODULE ,
. name = DRV_NAME ,
. ioctl = ata_scsi_ioctl ,
. queuecommand = ata_scsi_queuecmd ,
. can_queue = ATA_DEF_QUEUE ,
. this_id = ATA_SHT_THIS_ID ,
. sg_tablesize = LIBATA_MAX_PRD ,
. max_sectors = ATA_MAX_SECTORS ,
. cmd_per_lun = ATA_SHT_CMD_PER_LUN ,
. emulated = ATA_SHT_EMULATED ,
. use_clustering = ATA_SHT_USE_CLUSTERING ,
. proc_name = DRV_NAME ,
. dma_boundary = ATA_DMA_BOUNDARY ,
. slave_configure = ata_scsi_slave_config ,
2006-11-29 05:26:47 +03:00
. slave_destroy = ata_scsi_slave_destroy ,
2006-08-30 02:12:40 +04:00
. bios_param = ata_std_bios_param ,
2006-11-27 19:16:35 +03:00
. resume = ata_scsi_device_resume ,
. suspend = ata_scsi_device_suspend ,
2006-08-30 02:12:40 +04:00
} ;
static struct ata_port_operations serverworks_osb4_port_ops = {
. port_disable = ata_port_disable ,
. set_piomode = serverworks_set_piomode ,
. set_dmamode = serverworks_set_dmamode ,
. mode_filter = serverworks_osb4_filter ,
2006-08-31 08:03:49 +04:00
2006-08-30 02:12:40 +04:00
. tf_load = ata_tf_load ,
. tf_read = ata_tf_read ,
. check_status = ata_check_status ,
. exec_command = ata_exec_command ,
. dev_select = ata_std_dev_select ,
. freeze = ata_bmdma_freeze ,
. thaw = ata_bmdma_thaw ,
. error_handler = serverworks_error_handler ,
. post_internal_cmd = ata_bmdma_post_internal_cmd ,
. bmdma_setup = ata_bmdma_setup ,
. bmdma_start = ata_bmdma_start ,
. bmdma_stop = ata_bmdma_stop ,
. bmdma_status = ata_bmdma_status ,
. qc_prep = ata_qc_prep ,
. qc_issue = ata_qc_issue_prot ,
2006-09-27 13:41:13 +04:00
2006-08-30 02:12:40 +04:00
. data_xfer = ata_pio_data_xfer ,
2006-08-31 08:03:49 +04:00
2006-08-30 02:12:40 +04:00
. irq_handler = ata_interrupt ,
2006-09-27 01:10:53 +04:00
. irq_clear = ata_bmdma_irq_clear ,
2006-08-30 02:12:40 +04:00
. port_start = ata_port_start ,
. port_stop = ata_port_stop ,
. host_stop = ata_host_stop
2006-08-31 08:03:49 +04:00
} ;
2006-08-30 02:12:40 +04:00
static struct ata_port_operations serverworks_csb_port_ops = {
. port_disable = ata_port_disable ,
. set_piomode = serverworks_set_piomode ,
. set_dmamode = serverworks_set_dmamode ,
. mode_filter = serverworks_csb_filter ,
2006-08-31 08:03:49 +04:00
2006-08-30 02:12:40 +04:00
. tf_load = ata_tf_load ,
. tf_read = ata_tf_read ,
. check_status = ata_check_status ,
. exec_command = ata_exec_command ,
. dev_select = ata_std_dev_select ,
. freeze = ata_bmdma_freeze ,
. thaw = ata_bmdma_thaw ,
. error_handler = serverworks_error_handler ,
. post_internal_cmd = ata_bmdma_post_internal_cmd ,
. bmdma_setup = ata_bmdma_setup ,
. bmdma_start = ata_bmdma_start ,
. bmdma_stop = ata_bmdma_stop ,
. bmdma_status = ata_bmdma_status ,
. qc_prep = ata_qc_prep ,
. qc_issue = ata_qc_issue_prot ,
2006-09-27 13:41:13 +04:00
2006-08-30 02:12:40 +04:00
. data_xfer = ata_pio_data_xfer ,
2006-08-31 08:03:49 +04:00
2006-08-30 02:12:40 +04:00
. irq_handler = ata_interrupt ,
2006-09-27 01:10:53 +04:00
. irq_clear = ata_bmdma_irq_clear ,
2006-08-30 02:12:40 +04:00
. port_start = ata_port_start ,
. port_stop = ata_port_stop ,
. host_stop = ata_host_stop
2006-08-31 08:03:49 +04:00
} ;
2006-08-30 02:12:40 +04:00
static int serverworks_fixup_osb4 ( struct pci_dev * pdev )
{
u32 reg ;
struct pci_dev * isa_dev = pci_get_device ( PCI_VENDOR_ID_SERVERWORKS ,
PCI_DEVICE_ID_SERVERWORKS_OSB4 , NULL ) ;
if ( isa_dev ) {
pci_read_config_dword ( isa_dev , 0x64 , & reg ) ;
reg & = ~ 0x00002000 ; /* disable 600ns interrupt mask */
if ( ! ( reg & 0x00004000 ) )
printk ( KERN_DEBUG DRV_NAME " : UDMA not BIOS enabled. \n " ) ;
reg | = 0x00004000 ; /* enable UDMA/33 support */
pci_write_config_dword ( isa_dev , 0x64 , reg ) ;
pci_dev_put ( isa_dev ) ;
return 0 ;
}
printk ( KERN_WARNING " ata_serverworks: Unable to find bridge. \n " ) ;
return - ENODEV ;
}
static int serverworks_fixup_csb ( struct pci_dev * pdev )
{
u8 rev ;
u8 btr ;
2006-08-31 08:03:49 +04:00
2006-08-30 02:12:40 +04:00
pci_read_config_byte ( pdev , PCI_REVISION_ID , & rev ) ;
/* Third Channel Test */
if ( ! ( PCI_FUNC ( pdev - > devfn ) & 1 ) ) {
struct pci_dev * findev = NULL ;
u32 reg4c = 0 ;
findev = pci_get_device ( PCI_VENDOR_ID_SERVERWORKS ,
PCI_DEVICE_ID_SERVERWORKS_CSB5 , NULL ) ;
if ( findev ) {
pci_read_config_dword ( findev , 0x4C , & reg4c ) ;
reg4c & = ~ 0x000007FF ;
reg4c | = 0x00000040 ;
reg4c | = 0x00000020 ;
pci_write_config_dword ( findev , 0x4C , reg4c ) ;
pci_dev_put ( findev ) ;
}
} else {
struct pci_dev * findev = NULL ;
u8 reg41 = 0 ;
findev = pci_get_device ( PCI_VENDOR_ID_SERVERWORKS ,
PCI_DEVICE_ID_SERVERWORKS_CSB6 , NULL ) ;
if ( findev ) {
pci_read_config_byte ( findev , 0x41 , & reg41 ) ;
reg41 & = ~ 0x40 ;
pci_write_config_byte ( findev , 0x41 , reg41 ) ;
pci_dev_put ( findev ) ;
}
}
/* setup the UDMA Control register
*
* 1. clear bit 6 to enable DMA
* 2. enable DMA modes with bits 0 - 1
* 00 : legacy
* 01 : udma2
* 10 : udma2 / udma4
* 11 : udma2 / udma4 / udma5
*/
pci_read_config_byte ( pdev , 0x5A , & btr ) ;
btr & = ~ 0x40 ;
if ( ! ( PCI_FUNC ( pdev - > devfn ) & 1 ) )
btr | = 0x2 ;
else
btr | = ( rev > = SVWKS_CSB5_REVISION_NEW ) ? 0x3 : 0x2 ;
pci_write_config_byte ( pdev , 0x5A , btr ) ;
2006-08-31 08:03:49 +04:00
2006-08-30 02:12:40 +04:00
return btr ;
}
static void serverworks_fixup_ht1000 ( struct pci_dev * pdev )
{
u8 btr ;
/* Setup HT1000 SouthBridge Controller - Single Channel Only */
pci_read_config_byte ( pdev , 0x5A , & btr ) ;
btr & = ~ 0x40 ;
btr | = 0x3 ;
pci_write_config_byte ( pdev , 0x5A , btr ) ;
}
static int serverworks_init_one ( struct pci_dev * pdev , const struct pci_device_id * id )
{
int ports = 2 ;
static struct ata_port_info info [ 4 ] = {
{ /* OSB4 */
. sht = & serverworks_sht ,
. flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST ,
. pio_mask = 0x1f ,
. mwdma_mask = 0x07 ,
. udma_mask = 0x07 ,
. port_ops = & serverworks_osb4_port_ops
} , { /* OSB4 no UDMA */
. sht = & serverworks_sht ,
. flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST ,
. pio_mask = 0x1f ,
. mwdma_mask = 0x07 ,
. udma_mask = 0x00 ,
. port_ops = & serverworks_osb4_port_ops
} , { /* CSB5 */
. sht = & serverworks_sht ,
. flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST ,
. pio_mask = 0x1f ,
. mwdma_mask = 0x07 ,
. udma_mask = 0x1f ,
. port_ops = & serverworks_csb_port_ops
} , { /* CSB5 - later revisions*/
. sht = & serverworks_sht ,
. flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST ,
. pio_mask = 0x1f ,
. mwdma_mask = 0x07 ,
. udma_mask = 0x3f ,
. port_ops = & serverworks_csb_port_ops
}
} ;
static struct ata_port_info * port_info [ 2 ] ;
struct ata_port_info * devinfo = & info [ id - > driver_data ] ;
2006-08-31 08:03:49 +04:00
2006-08-30 02:12:40 +04:00
/* Force master latency timer to 64 PCI clocks */
pci_write_config_byte ( pdev , PCI_LATENCY_TIMER , 0x40 ) ;
/* OSB4 : South Bridge and IDE */
if ( pdev - > device = = PCI_DEVICE_ID_SERVERWORKS_OSB4IDE ) {
/* Select non UDMA capable OSB4 if we can't do fixups */
if ( serverworks_fixup_osb4 ( pdev ) < 0 )
devinfo = & info [ 1 ] ;
}
/* setup CSB5/CSB6 : South Bridge and IDE option RAID */
else if ( ( pdev - > device = = PCI_DEVICE_ID_SERVERWORKS_CSB5IDE ) | |
( pdev - > device = = PCI_DEVICE_ID_SERVERWORKS_CSB6IDE ) | |
( pdev - > device = = PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2 ) ) {
2006-08-31 08:03:49 +04:00
2006-08-30 02:12:40 +04:00
/* If the returned btr is the newer revision then
select the right info block */
if ( serverworks_fixup_csb ( pdev ) = = 3 )
devinfo = & info [ 3 ] ;
2006-08-31 08:03:49 +04:00
2006-08-30 02:12:40 +04:00
/* Is this the 3rd channel CSB6 IDE ? */
if ( pdev - > device = = PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2 )
ports = 1 ;
}
/* setup HT1000E */
else if ( pdev - > device = = PCI_DEVICE_ID_SERVERWORKS_HT1000IDE )
serverworks_fixup_ht1000 ( pdev ) ;
2006-08-31 08:03:49 +04:00
2006-08-30 02:12:40 +04:00
if ( pdev - > device = = PCI_DEVICE_ID_SERVERWORKS_CSB5IDE )
ata_pci_clear_simplex ( pdev ) ;
2006-08-31 08:03:49 +04:00
2006-08-30 02:12:40 +04:00
port_info [ 0 ] = port_info [ 1 ] = devinfo ;
return ata_pci_init_one ( pdev , port_info , ports ) ;
}
2006-11-27 19:16:35 +03:00
static int serverworks_reinit_one ( struct pci_dev * pdev )
{
/* Force master latency timer to 64 PCI clocks */
pci_write_config_byte ( pdev , PCI_LATENCY_TIMER , 0x40 ) ;
switch ( pdev - > device )
{
case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE :
serverworks_fixup_osb4 ( pdev ) ;
break ;
case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE :
ata_pci_clear_simplex ( pdev ) ;
/* fall through */
case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE :
case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2 :
serverworks_fixup_csb ( pdev ) ;
break ;
case PCI_DEVICE_ID_SERVERWORKS_HT1000IDE :
serverworks_fixup_ht1000 ( pdev ) ;
break ;
}
return ata_pci_device_resume ( pdev ) ;
}
2006-09-29 04:21:59 +04:00
static const struct pci_device_id serverworks [ ] = {
{ PCI_VDEVICE ( SERVERWORKS , PCI_DEVICE_ID_SERVERWORKS_OSB4IDE ) , 0 } ,
{ PCI_VDEVICE ( SERVERWORKS , PCI_DEVICE_ID_SERVERWORKS_CSB5IDE ) , 2 } ,
{ PCI_VDEVICE ( SERVERWORKS , PCI_DEVICE_ID_SERVERWORKS_CSB6IDE ) , 2 } ,
{ PCI_VDEVICE ( SERVERWORKS , PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2 ) , 2 } ,
{ PCI_VDEVICE ( SERVERWORKS , PCI_DEVICE_ID_SERVERWORKS_HT1000IDE ) , 2 } ,
{ } ,
2006-08-30 02:12:40 +04:00
} ;
static struct pci_driver serverworks_pci_driver = {
. name = DRV_NAME ,
. id_table = serverworks ,
. probe = serverworks_init_one ,
2006-11-27 19:16:35 +03:00
. remove = ata_pci_remove_one ,
. suspend = ata_pci_device_suspend ,
. resume = serverworks_reinit_one ,
2006-08-30 02:12:40 +04:00
} ;
static int __init serverworks_init ( void )
{
return pci_register_driver ( & serverworks_pci_driver ) ;
}
static void __exit serverworks_exit ( void )
{
pci_unregister_driver ( & serverworks_pci_driver ) ;
}
MODULE_AUTHOR ( " Alan Cox " ) ;
MODULE_DESCRIPTION ( " low-level driver for Serverworks OSB4/CSB5/CSB6 " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DEVICE_TABLE ( pci , serverworks ) ;
MODULE_VERSION ( DRV_VERSION ) ;
module_init ( serverworks_init ) ;
module_exit ( serverworks_exit ) ;