2005-04-17 02:20:36 +04:00
/*
* sata_svw . c - ServerWorks / Apple K2 SATA
*
* Maintained by : Benjamin Herrenschmidt < benh @ kernel . crashing . org > and
* Jeff Garzik < jgarzik @ pobox . com >
* Please ALWAYS copy linux - ide @ vger . kernel . org
* on emails .
*
* Copyright 2003 Benjamin Herrenschmidt < benh @ kernel . crashing . org >
*
* Bits from Jeff Garzik , Copyright RedHat , Inc .
*
* This driver probably works with non - Apple versions of the
* Broadcom chipset . . .
*
2005-08-29 04:18:39 +04:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 , or ( at your option )
* any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; see the file COPYING . If not , write to
* the Free Software Foundation , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*
*
* libata documentation is available via ' make { ps | pdf } docs ' ,
* as Documentation / DocBook / libata . *
*
* Hardware documentation available under NDA .
2005-04-17 02:20:36 +04:00
*
*/
# include <linux/config.h>
# 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 <linux/interrupt.h>
2005-10-30 22:39:11 +03:00
# include <linux/device.h>
2005-04-17 02:20:36 +04:00
# include <scsi/scsi_host.h>
# include <linux/libata.h>
# ifdef CONFIG_PPC_OF
# include <asm/prom.h>
# include <asm/pci-bridge.h>
# endif /* CONFIG_PPC_OF */
# define DRV_NAME "sata_svw"
2006-04-03 04:41:36 +04:00
# define DRV_VERSION "1.8"
2005-04-17 02:20:36 +04:00
2006-03-22 06:14:17 +03:00
enum {
/* Taskfile registers offsets */
K2_SATA_TF_CMD_OFFSET = 0x00 ,
K2_SATA_TF_DATA_OFFSET = 0x00 ,
K2_SATA_TF_ERROR_OFFSET = 0x04 ,
K2_SATA_TF_NSECT_OFFSET = 0x08 ,
K2_SATA_TF_LBAL_OFFSET = 0x0c ,
K2_SATA_TF_LBAM_OFFSET = 0x10 ,
K2_SATA_TF_LBAH_OFFSET = 0x14 ,
K2_SATA_TF_DEVICE_OFFSET = 0x18 ,
K2_SATA_TF_CMDSTAT_OFFSET = 0x1c ,
K2_SATA_TF_CTL_OFFSET = 0x20 ,
2005-04-17 02:20:36 +04:00
2006-03-22 06:14:17 +03:00
/* DMA base */
K2_SATA_DMA_CMD_OFFSET = 0x30 ,
2005-04-17 02:20:36 +04:00
2006-03-22 06:14:17 +03:00
/* SCRs base */
K2_SATA_SCR_STATUS_OFFSET = 0x40 ,
K2_SATA_SCR_ERROR_OFFSET = 0x44 ,
K2_SATA_SCR_CONTROL_OFFSET = 0x48 ,
2005-04-17 02:20:36 +04:00
2006-03-22 06:14:17 +03:00
/* Others */
K2_SATA_SICR1_OFFSET = 0x80 ,
K2_SATA_SICR2_OFFSET = 0x84 ,
K2_SATA_SIM_OFFSET = 0x88 ,
2005-04-17 02:20:36 +04:00
2006-03-22 06:14:17 +03:00
/* Port stride */
K2_SATA_PORT_OFFSET = 0x100 ,
} ;
2005-04-17 02:20:36 +04:00
2005-10-29 21:58:21 +04:00
static u8 k2_stat_check_status ( struct ata_port * ap ) ;
2005-04-17 02:20:36 +04:00
static u32 k2_sata_scr_read ( struct ata_port * ap , unsigned int sc_reg )
{
if ( sc_reg > SCR_CONTROL )
return 0xffffffffU ;
return readl ( ( void * ) ap - > ioaddr . scr_addr + ( sc_reg * 4 ) ) ;
}
static void k2_sata_scr_write ( struct ata_port * ap , unsigned int sc_reg ,
u32 val )
{
if ( sc_reg > SCR_CONTROL )
return ;
writel ( val , ( void * ) ap - > ioaddr . scr_addr + ( sc_reg * 4 ) ) ;
}
2005-10-22 22:27:05 +04:00
static void k2_sata_tf_load ( struct ata_port * ap , const struct ata_taskfile * tf )
2005-04-17 02:20:36 +04:00
{
struct ata_ioports * ioaddr = & ap - > ioaddr ;
unsigned int is_addr = tf - > flags & ATA_TFLAG_ISADDR ;
if ( tf - > ctl ! = ap - > last_ctl ) {
writeb ( tf - > ctl , ioaddr - > ctl_addr ) ;
ap - > last_ctl = tf - > ctl ;
ata_wait_idle ( ap ) ;
}
if ( is_addr & & ( tf - > flags & ATA_TFLAG_LBA48 ) ) {
writew ( tf - > feature | ( ( ( u16 ) tf - > hob_feature ) < < 8 ) , ioaddr - > feature_addr ) ;
writew ( tf - > nsect | ( ( ( u16 ) tf - > hob_nsect ) < < 8 ) , ioaddr - > nsect_addr ) ;
writew ( tf - > lbal | ( ( ( u16 ) tf - > hob_lbal ) < < 8 ) , ioaddr - > lbal_addr ) ;
writew ( tf - > lbam | ( ( ( u16 ) tf - > hob_lbam ) < < 8 ) , ioaddr - > lbam_addr ) ;
writew ( tf - > lbah | ( ( ( u16 ) tf - > hob_lbah ) < < 8 ) , ioaddr - > lbah_addr ) ;
} else if ( is_addr ) {
writew ( tf - > feature , ioaddr - > feature_addr ) ;
writew ( tf - > nsect , ioaddr - > nsect_addr ) ;
writew ( tf - > lbal , ioaddr - > lbal_addr ) ;
writew ( tf - > lbam , ioaddr - > lbam_addr ) ;
writew ( tf - > lbah , ioaddr - > lbah_addr ) ;
}
if ( tf - > flags & ATA_TFLAG_DEVICE )
writeb ( tf - > device , ioaddr - > device_addr ) ;
ata_wait_idle ( ap ) ;
}
static void k2_sata_tf_read ( struct ata_port * ap , struct ata_taskfile * tf )
{
struct ata_ioports * ioaddr = & ap - > ioaddr ;
2005-10-29 21:58:21 +04:00
u16 nsect , lbal , lbam , lbah , feature ;
2005-04-17 02:20:36 +04:00
2005-10-29 21:58:21 +04:00
tf - > command = k2_stat_check_status ( ap ) ;
2005-04-17 02:20:36 +04:00
tf - > device = readw ( ioaddr - > device_addr ) ;
2005-10-29 21:58:21 +04:00
feature = readw ( ioaddr - > error_addr ) ;
nsect = readw ( ioaddr - > nsect_addr ) ;
lbal = readw ( ioaddr - > lbal_addr ) ;
lbam = readw ( ioaddr - > lbam_addr ) ;
lbah = readw ( ioaddr - > lbah_addr ) ;
tf - > feature = feature ;
tf - > nsect = nsect ;
tf - > lbal = lbal ;
tf - > lbam = lbam ;
tf - > lbah = lbah ;
2005-04-17 02:20:36 +04:00
if ( tf - > flags & ATA_TFLAG_LBA48 ) {
2005-10-29 21:58:21 +04:00
tf - > hob_feature = feature > > 8 ;
2005-04-17 02:20:36 +04:00
tf - > hob_nsect = nsect > > 8 ;
tf - > hob_lbal = lbal > > 8 ;
tf - > hob_lbam = lbam > > 8 ;
tf - > hob_lbah = lbah > > 8 ;
}
}
/**
* k2_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction ( MMIO )
* @ qc : Info associated with this ATA transaction .
*
* LOCKING :
* spin_lock_irqsave ( host_set lock )
*/
static void k2_bmdma_setup_mmio ( struct ata_queued_cmd * qc )
{
struct ata_port * ap = qc - > ap ;
unsigned int rw = ( qc - > tf . flags & ATA_TFLAG_WRITE ) ;
u8 dmactl ;
void * mmio = ( void * ) ap - > ioaddr . bmdma_addr ;
/* load PRD table addr. */
mb ( ) ; /* make sure PRD table writes are visible to controller */
writel ( ap - > prd_dma , mmio + ATA_DMA_TABLE_OFS ) ;
/* specify data direction, triple-check start bit is clear */
dmactl = readb ( mmio + ATA_DMA_CMD ) ;
dmactl & = ~ ( ATA_DMA_WR | ATA_DMA_START ) ;
if ( ! rw )
dmactl | = ATA_DMA_WR ;
writeb ( dmactl , mmio + ATA_DMA_CMD ) ;
/* issue r/w command if this is not a ATA DMA command*/
if ( qc - > tf . protocol ! = ATA_PROT_DMA )
ap - > ops - > exec_command ( ap , & qc - > tf ) ;
}
/**
* k2_bmdma_start_mmio - Start a PCI IDE BMDMA transaction ( MMIO )
* @ qc : Info associated with this ATA transaction .
*
* LOCKING :
* spin_lock_irqsave ( host_set lock )
*/
static void k2_bmdma_start_mmio ( struct ata_queued_cmd * qc )
{
struct ata_port * ap = qc - > ap ;
void * mmio = ( void * ) ap - > ioaddr . bmdma_addr ;
u8 dmactl ;
/* start host DMA transaction */
dmactl = readb ( mmio + ATA_DMA_CMD ) ;
writeb ( dmactl | ATA_DMA_START , mmio + ATA_DMA_CMD ) ;
2005-07-31 21:13:24 +04:00
/* There is a race condition in certain SATA controllers that can
be seen when the r / w command is given to the controller before the
2005-04-17 02:20:36 +04:00
host DMA is started . On a Read command , the controller would initiate
the command to the drive even before it sees the DMA start . When there
2005-07-31 21:13:24 +04:00
are very fast drives connected to the controller , or when the data request
2005-04-17 02:20:36 +04:00
hits in the drive cache , there is the possibility that the drive returns a part
or all of the requested data to the controller before the DMA start is issued .
In this case , the controller would become confused as to what to do with the data .
In the worst case when all the data is returned back to the controller , the
controller could hang . In other cases it could return partial data returning
in data corruption . This problem has been seen in PPC systems and can also appear
2005-07-31 21:13:24 +04:00
on an system with very fast disks , where the SATA controller is sitting behind a
2005-04-17 02:20:36 +04:00
number of bridges , and hence there is significant latency between the r / w command
and the start command . */
/* issue r/w command if the access is to ATA*/
if ( qc - > tf . protocol = = ATA_PROT_DMA )
ap - > ops - > exec_command ( ap , & qc - > tf ) ;
}
2005-07-31 21:13:24 +04:00
2005-04-17 02:20:36 +04:00
static u8 k2_stat_check_status ( struct ata_port * ap )
{
return readl ( ( void * ) ap - > ioaddr . status_addr ) ;
}
# ifdef CONFIG_PPC_OF
/*
* k2_sata_proc_info
* inout : decides on the direction of the dataflow and the meaning of the
* variables
* buffer : If inout = = FALSE data is being written to it else read from it
* * start : If inout = = FALSE start of the valid data in the buffer
* offset : If inout = = FALSE offset from the beginning of the imaginary file
* from which we start writing into the buffer
* length : If inout = = FALSE max number of bytes to be written into the buffer
* else number of bytes in the buffer
*/
static int k2_sata_proc_info ( struct Scsi_Host * shost , char * page , char * * start ,
off_t offset , int count , int inout )
{
struct ata_port * ap ;
struct device_node * np ;
int len , index ;
/* Find the ata_port */
ap = ( struct ata_port * ) & shost - > hostdata [ 0 ] ;
if ( ap = = NULL )
return 0 ;
/* Find the OF node for the PCI device proper */
np = pci_device_to_OF_node ( to_pci_dev ( ap - > host_set - > dev ) ) ;
if ( np = = NULL )
return 0 ;
/* Match it to a port node */
index = ( ap = = ap - > host_set - > ports [ 0 ] ) ? 0 : 1 ;
for ( np = np - > child ; np ! = NULL ; np = np - > sibling ) {
u32 * reg = ( u32 * ) get_property ( np , " reg " , NULL ) ;
if ( ! reg )
continue ;
if ( index = = * reg )
break ;
}
if ( np = = NULL )
return 0 ;
len = sprintf ( page , " devspec: %s \n " , np - > full_name ) ;
return len ;
}
# endif /* CONFIG_PPC_OF */
2005-11-07 08:59:37 +03:00
static struct scsi_host_template k2_sata_sht = {
2005-04-17 02:20:36 +04:00
. 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 ,
. 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 ,
# ifdef CONFIG_PPC_OF
. proc_info = k2_sata_proc_info ,
# endif
. bios_param = ata_std_bios_param ,
} ;
2005-10-22 22:27:05 +04:00
static const struct ata_port_operations k2_sata_ops = {
2005-04-17 02:20:36 +04:00
. port_disable = ata_port_disable ,
. tf_load = k2_sata_tf_load ,
. tf_read = k2_sata_tf_read ,
. check_status = k2_stat_check_status ,
. exec_command = ata_exec_command ,
. dev_select = ata_std_dev_select ,
. phy_reset = sata_phy_reset ,
. bmdma_setup = k2_bmdma_setup_mmio ,
. bmdma_start = k2_bmdma_start_mmio ,
. bmdma_stop = ata_bmdma_stop ,
. bmdma_status = ata_bmdma_status ,
. qc_prep = ata_qc_prep ,
. qc_issue = ata_qc_issue_prot ,
. eng_timeout = ata_eng_timeout ,
. irq_handler = ata_interrupt ,
. irq_clear = ata_bmdma_irq_clear ,
. scr_read = k2_sata_scr_read ,
. scr_write = k2_sata_scr_write ,
. port_start = ata_port_start ,
. port_stop = ata_port_stop ,
2005-08-30 13:42:52 +04:00
. host_stop = ata_pci_host_stop ,
2005-04-17 02:20:36 +04:00
} ;
static void k2_sata_setup_port ( struct ata_ioports * port , unsigned long base )
{
port - > cmd_addr = base + K2_SATA_TF_CMD_OFFSET ;
port - > data_addr = base + K2_SATA_TF_DATA_OFFSET ;
port - > feature_addr =
port - > error_addr = base + K2_SATA_TF_ERROR_OFFSET ;
port - > nsect_addr = base + K2_SATA_TF_NSECT_OFFSET ;
port - > lbal_addr = base + K2_SATA_TF_LBAL_OFFSET ;
port - > lbam_addr = base + K2_SATA_TF_LBAM_OFFSET ;
port - > lbah_addr = base + K2_SATA_TF_LBAH_OFFSET ;
port - > device_addr = base + K2_SATA_TF_DEVICE_OFFSET ;
port - > command_addr =
port - > status_addr = base + K2_SATA_TF_CMDSTAT_OFFSET ;
port - > altstatus_addr =
port - > ctl_addr = base + K2_SATA_TF_CTL_OFFSET ;
port - > bmdma_addr = base + K2_SATA_DMA_CMD_OFFSET ;
port - > scr_addr = base + K2_SATA_SCR_STATUS_OFFSET ;
}
static int k2_sata_init_one ( struct pci_dev * pdev , const struct pci_device_id * ent )
{
static int printed_version ;
struct ata_probe_ent * probe_ent = NULL ;
unsigned long base ;
2005-08-30 13:18:18 +04:00
void __iomem * mmio_base ;
2005-04-17 02:20:36 +04:00
int pci_dev_busy = 0 ;
int rc ;
2005-05-26 03:51:00 +04:00
int i ;
2005-04-17 02:20:36 +04:00
if ( ! printed_version + + )
2005-10-30 22:39:11 +03:00
dev_printk ( KERN_DEBUG , & pdev - > dev , " version " DRV_VERSION " \n " ) ;
2005-04-17 02:20:36 +04:00
/*
* If this driver happens to only be useful on Apple ' s K2 , then
* we should check that here as it has a normal Serverworks ID
*/
rc = pci_enable_device ( pdev ) ;
if ( rc )
return rc ;
/*
* Check if we have resources mapped at all ( second function may
* have been disabled by firmware )
*/
if ( pci_resource_len ( pdev , 5 ) = = 0 )
return - ENODEV ;
/* Request PCI regions */
rc = pci_request_regions ( pdev , DRV_NAME ) ;
if ( rc ) {
pci_dev_busy = 1 ;
goto err_out ;
}
rc = pci_set_dma_mask ( pdev , ATA_DMA_MASK ) ;
if ( rc )
goto err_out_regions ;
rc = pci_set_consistent_dma_mask ( pdev , ATA_DMA_MASK ) ;
if ( rc )
goto err_out_regions ;
probe_ent = kmalloc ( sizeof ( * probe_ent ) , GFP_KERNEL ) ;
if ( probe_ent = = NULL ) {
rc = - ENOMEM ;
goto err_out_regions ;
}
memset ( probe_ent , 0 , sizeof ( * probe_ent ) ) ;
probe_ent - > dev = pci_dev_to_dev ( pdev ) ;
INIT_LIST_HEAD ( & probe_ent - > node ) ;
2005-08-30 13:42:52 +04:00
mmio_base = pci_iomap ( pdev , 5 , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( mmio_base = = NULL ) {
rc = - ENOMEM ;
goto err_out_free_ent ;
}
base = ( unsigned long ) mmio_base ;
/* Clear a magic bit in SCR1 according to Darwin, those help
* some funky seagate drives ( though so far , those were already
2005-03-27 17:50:38 +04:00
* set by the firmware on the machines I had access to )
2005-04-17 02:20:36 +04:00
*/
writel ( readl ( mmio_base + K2_SATA_SICR1_OFFSET ) & ~ 0x00040000 ,
mmio_base + K2_SATA_SICR1_OFFSET ) ;
/* Clear SATA error & interrupts we don't use */
writel ( 0xffffffff , mmio_base + K2_SATA_SCR_ERROR_OFFSET ) ;
writel ( 0x0 , mmio_base + K2_SATA_SIM_OFFSET ) ;
probe_ent - > sht = & k2_sata_sht ;
probe_ent - > host_flags = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET |
ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO ;
probe_ent - > port_ops = & k2_sata_ops ;
probe_ent - > n_ports = 4 ;
probe_ent - > irq = pdev - > irq ;
probe_ent - > irq_flags = SA_SHIRQ ;
probe_ent - > mmio_base = mmio_base ;
/* We don't care much about the PIO/UDMA masks, but the core won't like us
* if we don ' t fill these
*/
probe_ent - > pio_mask = 0x1f ;
probe_ent - > mwdma_mask = 0x7 ;
probe_ent - > udma_mask = 0x7f ;
2005-05-26 03:51:00 +04:00
/* different controllers have different number of ports - currently 4 or 8 */
/* All ports are on the same function. Multi-function device is no
* longer available . This should not be seen in any system . */
for ( i = 0 ; i < ent - > driver_data ; i + + )
k2_sata_setup_port ( & probe_ent - > port [ i ] , base + i * K2_SATA_PORT_OFFSET ) ;
2005-04-17 02:20:36 +04:00
pci_set_master ( pdev ) ;
/* FIXME: check ata_device_add return value */
ata_device_add ( probe_ent ) ;
kfree ( probe_ent ) ;
return 0 ;
err_out_free_ent :
kfree ( probe_ent ) ;
err_out_regions :
pci_release_regions ( pdev ) ;
err_out :
if ( ! pci_dev_busy )
pci_disable_device ( pdev ) ;
return rc ;
}
2005-05-26 03:51:00 +04:00
/* 0x240 is device ID for Apple K2 device
* 0x241 is device ID for Serverworks Frodo4
* 0x242 is device ID for Serverworks Frodo8
* 0x24a is device ID for BCM5785 ( aka HT1000 ) HT southbridge integrated SATA
* controller
* */
2005-11-10 19:04:11 +03:00
static const struct pci_device_id k2_sata_pci_tbl [ ] = {
2005-05-26 03:51:00 +04:00
{ 0x1166 , 0x0240 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 4 } ,
{ 0x1166 , 0x0241 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 4 } ,
{ 0x1166 , 0x0242 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 8 } ,
{ 0x1166 , 0x024a , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 4 } ,
2006-01-17 15:58:42 +03:00
{ 0x1166 , 0x024b , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 4 } ,
2005-04-17 02:20:36 +04:00
{ }
} ;
static struct pci_driver k2_sata_pci_driver = {
. name = DRV_NAME ,
. id_table = k2_sata_pci_tbl ,
. probe = k2_sata_init_one ,
. remove = ata_pci_remove_one ,
} ;
static int __init k2_sata_init ( void )
{
return pci_module_init ( & k2_sata_pci_driver ) ;
}
static void __exit k2_sata_exit ( void )
{
pci_unregister_driver ( & k2_sata_pci_driver ) ;
}
MODULE_AUTHOR ( " Benjamin Herrenschmidt " ) ;
MODULE_DESCRIPTION ( " low-level driver for K2 SATA controller " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DEVICE_TABLE ( pci , k2_sata_pci_tbl ) ;
MODULE_VERSION ( DRV_VERSION ) ;
module_init ( k2_sata_init ) ;
module_exit ( k2_sata_exit ) ;