2005-04-17 02:20:36 +04:00
/*
* sata_promise . c - Promise SATA
*
* Maintained by : Jeff Garzik < jgarzik @ pobox . com >
* Please ALWAYS copy linux - ide @ vger . kernel . org
* on emails .
*
* Copyright 2003 - 2004 Red Hat , Inc .
*
*
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 information only available under NDA .
2005-04-17 02:20:36 +04:00
*
*/
# 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>
# include <linux/sched.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>
2005-11-07 08:59:37 +03:00
# include <scsi/scsi_cmnd.h>
2005-04-17 02:20:36 +04:00
# include <linux/libata.h>
# include <asm/io.h>
# include "sata_promise.h"
# define DRV_NAME "sata_promise"
2006-01-28 20:39:29 +03:00
# define DRV_VERSION "1.04"
2005-04-17 02:20:36 +04:00
enum {
PDC_PKT_SUBMIT = 0x40 , /* Command packet pointer addr */
PDC_INT_SEQMASK = 0x40 , /* Mask of asserted SEQ INTs */
PDC_TBG_MODE = 0x41 , /* TBG mode */
PDC_FLASH_CTL = 0x44 , /* Flash control register */
PDC_PCI_CTL = 0x48 , /* PCI control and status register */
PDC_GLOBAL_CTL = 0x48 , /* Global control/status (per port) */
PDC_CTLSTAT = 0x60 , /* IDE control and status (per port) */
PDC_SATA_PLUG_CSR = 0x6C , /* SATA Plug control/status reg */
2006-01-28 20:39:29 +03:00
PDC2_SATA_PLUG_CSR = 0x60 , /* SATAII Plug control/status reg */
2005-04-17 02:20:36 +04:00
PDC_SLEW_CTL = 0x470 , /* slew rate control reg */
PDC_ERR_MASK = ( 1 < < 19 ) | ( 1 < < 20 ) | ( 1 < < 21 ) | ( 1 < < 22 ) |
( 1 < < 8 ) | ( 1 < < 9 ) | ( 1 < < 10 ) ,
board_2037x = 0 , /* FastTrak S150 TX2plus */
board_20319 = 1 , /* FastTrak S150 TX4 */
2005-05-12 23:51:01 +04:00
board_20619 = 2 , /* FastTrak TX4000 */
2006-01-17 16:06:21 +03:00
board_20771 = 3 , /* FastTrak TX2300 */
2006-01-28 20:39:29 +03:00
board_2057x = 4 , /* SATAII150 Tx2plus */
board_40518 = 5 , /* SATAII150 Tx4 */
2005-04-17 02:20:36 +04:00
2006-01-28 20:39:29 +03:00
PDC_HAS_PATA = ( 1 < < 1 ) , /* PDC20375/20575 has PATA */
2005-04-17 02:20:36 +04:00
PDC_RESET = ( 1 < < 11 ) , /* HDMA reset */
2005-12-13 10:29:45 +03:00
PDC_COMMON_FLAGS = ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST |
2005-12-14 06:28:19 +03:00
ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI |
ATA_FLAG_PIO_POLLING ,
2005-04-17 02:20:36 +04:00
} ;
struct pdc_port_priv {
u8 * pkt ;
dma_addr_t pkt_dma ;
} ;
2006-01-28 20:39:29 +03:00
struct pdc_host_priv {
int hotplug_offset ;
} ;
2005-04-17 02:20:36 +04:00
static u32 pdc_sata_scr_read ( struct ata_port * ap , unsigned int sc_reg ) ;
static void pdc_sata_scr_write ( struct ata_port * ap , unsigned int sc_reg , u32 val ) ;
static int pdc_ata_init_one ( struct pci_dev * pdev , const struct pci_device_id * ent ) ;
static irqreturn_t pdc_interrupt ( int irq , void * dev_instance , struct pt_regs * regs ) ;
static void pdc_eng_timeout ( struct ata_port * ap ) ;
static int pdc_port_start ( struct ata_port * ap ) ;
static void pdc_port_stop ( struct ata_port * ap ) ;
2005-08-29 13:12:30 +04:00
static void pdc_pata_phy_reset ( struct ata_port * ap ) ;
static void pdc_sata_phy_reset ( struct ata_port * ap ) ;
2005-04-17 02:20:36 +04:00
static void pdc_qc_prep ( struct ata_queued_cmd * qc ) ;
2005-10-22 22:27:05 +04:00
static void pdc_tf_load_mmio ( struct ata_port * ap , const struct ata_taskfile * tf ) ;
static void pdc_exec_command_mmio ( struct ata_port * ap , const struct ata_taskfile * tf ) ;
2005-04-17 02:20:36 +04:00
static void pdc_irq_clear ( struct ata_port * ap ) ;
2006-01-23 07:09:36 +03:00
static unsigned int pdc_qc_issue_prot ( struct ata_queued_cmd * qc ) ;
2006-01-28 20:39:29 +03:00
static void pdc_host_stop ( struct ata_host_set * host_set ) ;
2005-04-17 02:20:36 +04:00
2005-08-30 13:42:52 +04:00
2005-11-07 08:59:37 +03:00
static struct scsi_host_template pdc_ata_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 ,
2006-05-31 13:28:09 +04:00
. slave_destroy = ata_scsi_slave_destroy ,
2005-04-17 02:20:36 +04:00
. bios_param = ata_std_bios_param ,
} ;
2005-10-22 22:27:05 +04:00
static const struct ata_port_operations pdc_sata_ops = {
2005-04-17 02:20:36 +04:00
. port_disable = ata_port_disable ,
. tf_load = pdc_tf_load_mmio ,
. tf_read = ata_tf_read ,
. check_status = ata_check_status ,
. exec_command = pdc_exec_command_mmio ,
. dev_select = ata_std_dev_select ,
2005-08-29 13:12:30 +04:00
. phy_reset = pdc_sata_phy_reset ,
2005-04-17 02:20:36 +04:00
. qc_prep = pdc_qc_prep ,
. qc_issue = pdc_qc_issue_prot ,
. eng_timeout = pdc_eng_timeout ,
2006-05-22 19:59:59 +04:00
. data_xfer = ata_mmio_data_xfer ,
2005-04-17 02:20:36 +04:00
. irq_handler = pdc_interrupt ,
. irq_clear = pdc_irq_clear ,
2005-08-29 13:12:30 +04:00
2005-04-17 02:20:36 +04:00
. scr_read = pdc_sata_scr_read ,
. scr_write = pdc_sata_scr_write ,
. port_start = pdc_port_start ,
. port_stop = pdc_port_stop ,
2006-01-28 20:39:29 +03:00
. host_stop = pdc_host_stop ,
2005-04-17 02:20:36 +04:00
} ;
2005-10-22 22:27:05 +04:00
static const struct ata_port_operations pdc_pata_ops = {
2005-08-29 13:12:30 +04:00
. port_disable = ata_port_disable ,
. tf_load = pdc_tf_load_mmio ,
. tf_read = ata_tf_read ,
. check_status = ata_check_status ,
. exec_command = pdc_exec_command_mmio ,
. dev_select = ata_std_dev_select ,
. phy_reset = pdc_pata_phy_reset ,
. qc_prep = pdc_qc_prep ,
. qc_issue = pdc_qc_issue_prot ,
2006-05-22 19:59:59 +04:00
. data_xfer = ata_mmio_data_xfer ,
2005-08-29 13:12:30 +04:00
. eng_timeout = pdc_eng_timeout ,
. irq_handler = pdc_interrupt ,
. irq_clear = pdc_irq_clear ,
. port_start = pdc_port_start ,
. port_stop = pdc_port_stop ,
2006-01-28 20:39:29 +03:00
. host_stop = pdc_host_stop ,
2005-08-29 13:12:30 +04:00
} ;
2005-11-28 12:06:23 +03:00
static const struct ata_port_info pdc_port_info [ ] = {
2005-04-17 02:20:36 +04:00
/* board_2037x */
{
. sht = & pdc_ata_sht ,
2005-12-13 10:29:45 +03:00
. host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA ,
2005-04-17 02:20:36 +04:00
. pio_mask = 0x1f , /* pio0-4 */
. mwdma_mask = 0x07 , /* mwdma0-2 */
. udma_mask = 0x7f , /* udma0-6 ; FIXME */
2005-08-29 13:12:30 +04:00
. port_ops = & pdc_sata_ops ,
2005-04-17 02:20:36 +04:00
} ,
/* board_20319 */
{
. sht = & pdc_ata_sht ,
2005-12-13 10:29:45 +03:00
. host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA ,
2005-04-17 02:20:36 +04:00
. pio_mask = 0x1f , /* pio0-4 */
. mwdma_mask = 0x07 , /* mwdma0-2 */
. udma_mask = 0x7f , /* udma0-6 ; FIXME */
2005-08-29 13:12:30 +04:00
. port_ops = & pdc_sata_ops ,
2005-04-17 02:20:36 +04:00
} ,
2005-05-12 23:51:01 +04:00
/* board_20619 */
{
. sht = & pdc_ata_sht ,
2005-12-13 10:29:45 +03:00
. host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS ,
2005-05-12 23:51:01 +04:00
. pio_mask = 0x1f , /* pio0-4 */
. mwdma_mask = 0x07 , /* mwdma0-2 */
. udma_mask = 0x7f , /* udma0-6 ; FIXME */
2005-08-29 13:12:30 +04:00
. port_ops = & pdc_pata_ops ,
2005-05-12 23:51:01 +04:00
} ,
2006-01-17 16:06:21 +03:00
/* board_20771 */
{
. sht = & pdc_ata_sht ,
. host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA ,
. pio_mask = 0x1f , /* pio0-4 */
. mwdma_mask = 0x07 , /* mwdma0-2 */
. udma_mask = 0x7f , /* udma0-6 ; FIXME */
. port_ops = & pdc_sata_ops ,
} ,
2006-01-28 20:39:29 +03:00
/* board_2057x */
{
. sht = & pdc_ata_sht ,
. host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA ,
. pio_mask = 0x1f , /* pio0-4 */
. mwdma_mask = 0x07 , /* mwdma0-2 */
. udma_mask = 0x7f , /* udma0-6 ; FIXME */
. port_ops = & pdc_sata_ops ,
} ,
/* board_40518 */
{
. sht = & pdc_ata_sht ,
. host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA ,
. pio_mask = 0x1f , /* pio0-4 */
. mwdma_mask = 0x07 , /* mwdma0-2 */
. udma_mask = 0x7f , /* udma0-6 ; FIXME */
. port_ops = & pdc_sata_ops ,
} ,
2005-04-17 02:20:36 +04:00
} ;
2005-11-10 19:04:11 +03:00
static const struct pci_device_id pdc_ata_pci_tbl [ ] = {
2005-04-17 02:20:36 +04:00
{ PCI_VENDOR_ID_PROMISE , 0x3371 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 ,
board_2037x } ,
2005-10-29 01:00:31 +04:00
{ PCI_VENDOR_ID_PROMISE , 0x3570 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 ,
board_2037x } ,
2005-05-26 03:29:37 +04:00
{ PCI_VENDOR_ID_PROMISE , 0x3571 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 ,
board_2037x } ,
2005-04-17 02:20:36 +04:00
{ PCI_VENDOR_ID_PROMISE , 0x3373 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 ,
board_2037x } ,
{ PCI_VENDOR_ID_PROMISE , 0x3375 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 ,
board_2037x } ,
{ PCI_VENDOR_ID_PROMISE , 0x3376 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 ,
board_2037x } ,
{ PCI_VENDOR_ID_PROMISE , 0x3574 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 ,
2006-01-28 20:39:29 +03:00
board_2057x } ,
2005-04-17 02:20:36 +04:00
{ PCI_VENDOR_ID_PROMISE , 0x3d75 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 ,
2006-01-28 20:39:29 +03:00
board_2057x } ,
2005-07-17 07:32:19 +04:00
{ PCI_VENDOR_ID_PROMISE , 0x3d73 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 ,
board_2037x } ,
2005-04-17 02:20:36 +04:00
{ PCI_VENDOR_ID_PROMISE , 0x3318 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 ,
board_20319 } ,
{ PCI_VENDOR_ID_PROMISE , 0x3319 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 ,
board_20319 } ,
2006-03-04 18:36:21 +03:00
{ PCI_VENDOR_ID_PROMISE , 0x3515 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 ,
board_20319 } ,
2005-08-22 17:59:23 +04:00
{ PCI_VENDOR_ID_PROMISE , 0x3519 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 ,
board_20319 } ,
2005-08-22 17:58:57 +04:00
{ PCI_VENDOR_ID_PROMISE , 0x3d17 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 ,
board_20319 } ,
2005-04-17 02:20:36 +04:00
{ PCI_VENDOR_ID_PROMISE , 0x3d18 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 ,
2006-01-28 20:39:29 +03:00
board_40518 } ,
2005-04-17 02:20:36 +04:00
2005-05-12 23:51:01 +04:00
{ PCI_VENDOR_ID_PROMISE , 0x6629 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 ,
board_20619 } ,
2006-07-24 11:37:52 +04:00
/* TODO: remove all associated board_20771 code, as it completely
* duplicates board_2037x code , unless reason for separation can be
* divined .
*/
#if 0
2006-01-17 16:06:21 +03:00
{ PCI_VENDOR_ID_PROMISE , 0x3570 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 ,
board_20771 } ,
2006-07-24 11:37:52 +04:00
# endif
2005-04-17 02:20:36 +04:00
{ } /* terminate list */
} ;
static struct pci_driver pdc_ata_pci_driver = {
. name = DRV_NAME ,
. id_table = pdc_ata_pci_tbl ,
. probe = pdc_ata_init_one ,
. remove = ata_pci_remove_one ,
} ;
static int pdc_port_start ( struct ata_port * ap )
{
struct device * dev = ap - > host_set - > dev ;
struct pdc_port_priv * pp ;
int rc ;
rc = ata_port_start ( ap ) ;
if ( rc )
return rc ;
2006-01-28 20:39:29 +03:00
pp = kzalloc ( sizeof ( * pp ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! pp ) {
rc = - ENOMEM ;
goto err_out ;
}
pp - > pkt = dma_alloc_coherent ( dev , 128 , & pp - > pkt_dma , GFP_KERNEL ) ;
if ( ! pp - > pkt ) {
rc = - ENOMEM ;
goto err_out_kfree ;
}
ap - > private_data = pp ;
return 0 ;
err_out_kfree :
kfree ( pp ) ;
err_out :
ata_port_stop ( ap ) ;
return rc ;
}
static void pdc_port_stop ( struct ata_port * ap )
{
struct device * dev = ap - > host_set - > dev ;
struct pdc_port_priv * pp = ap - > private_data ;
ap - > private_data = NULL ;
dma_free_coherent ( dev , 128 , pp - > pkt , pp - > pkt_dma ) ;
kfree ( pp ) ;
ata_port_stop ( ap ) ;
}
2006-01-28 20:39:29 +03:00
static void pdc_host_stop ( struct ata_host_set * host_set )
{
struct pdc_host_priv * hp = host_set - > private_data ;
ata_pci_host_stop ( host_set ) ;
kfree ( hp ) ;
}
2005-04-17 02:20:36 +04:00
static void pdc_reset_port ( struct ata_port * ap )
{
2005-08-30 13:18:18 +04:00
void __iomem * mmio = ( void __iomem * ) ap - > ioaddr . cmd_addr + PDC_CTLSTAT ;
2005-04-17 02:20:36 +04:00
unsigned int i ;
u32 tmp ;
for ( i = 11 ; i > 0 ; i - - ) {
tmp = readl ( mmio ) ;
if ( tmp & PDC_RESET )
break ;
udelay ( 100 ) ;
tmp | = PDC_RESET ;
writel ( tmp , mmio ) ;
}
tmp & = ~ PDC_RESET ;
writel ( tmp , mmio ) ;
readl ( mmio ) ; /* flush */
}
2005-08-29 13:12:30 +04:00
static void pdc_sata_phy_reset ( struct ata_port * ap )
2005-04-17 02:20:36 +04:00
{
pdc_reset_port ( ap ) ;
sata_phy_reset ( ap ) ;
}
2006-05-24 09:43:25 +04:00
static void pdc_pata_cbl_detect ( struct ata_port * ap )
2005-08-29 13:12:30 +04:00
{
2006-05-24 09:43:25 +04:00
u8 tmp ;
void __iomem * mmio = ( void * ) ap - > ioaddr . cmd_addr + PDC_CTLSTAT + 0x03 ;
tmp = readb ( mmio ) ;
if ( tmp & 0x01 ) {
ap - > cbl = ATA_CBL_PATA40 ;
ap - > udma_mask & = ATA_UDMA_MASK_40C ;
} else
ap - > cbl = ATA_CBL_PATA80 ;
}
2005-08-29 13:12:30 +04:00
2006-05-24 09:43:25 +04:00
static void pdc_pata_phy_reset ( struct ata_port * ap )
{
pdc_pata_cbl_detect ( ap ) ;
2005-08-29 13:12:30 +04:00
pdc_reset_port ( ap ) ;
ata_port_probe ( ap ) ;
ata_bus_reset ( ap ) ;
}
2005-04-17 02:20:36 +04:00
static u32 pdc_sata_scr_read ( struct ata_port * ap , unsigned int sc_reg )
{
if ( sc_reg > SCR_CONTROL )
return 0xffffffffU ;
2005-10-21 09:46:02 +04:00
return readl ( ( void __iomem * ) ap - > ioaddr . scr_addr + ( sc_reg * 4 ) ) ;
2005-04-17 02:20:36 +04:00
}
static void pdc_sata_scr_write ( struct ata_port * ap , unsigned int sc_reg ,
u32 val )
{
if ( sc_reg > SCR_CONTROL )
return ;
2005-10-21 09:46:02 +04:00
writel ( val , ( void __iomem * ) ap - > ioaddr . scr_addr + ( sc_reg * 4 ) ) ;
2005-04-17 02:20:36 +04:00
}
static void pdc_qc_prep ( struct ata_queued_cmd * qc )
{
struct pdc_port_priv * pp = qc - > ap - > private_data ;
unsigned int i ;
VPRINTK ( " ENTER \n " ) ;
switch ( qc - > tf . protocol ) {
case ATA_PROT_DMA :
ata_qc_prep ( qc ) ;
/* fall through */
case ATA_PROT_NODATA :
i = pdc_pkt_header ( & qc - > tf , qc - > ap - > prd_dma ,
qc - > dev - > devno , pp - > pkt ) ;
if ( qc - > tf . flags & ATA_TFLAG_LBA48 )
i = pdc_prep_lba48 ( & qc - > tf , pp - > pkt , i ) ;
else
i = pdc_prep_lba28 ( & qc - > tf , pp - > pkt , i ) ;
pdc_pkt_footer ( & qc - > tf , pp - > pkt , i ) ;
break ;
default :
break ;
}
}
static void pdc_eng_timeout ( struct ata_port * ap )
{
2005-08-26 06:01:20 +04:00
struct ata_host_set * host_set = ap - > host_set ;
2005-04-17 02:20:36 +04:00
u8 drv_stat ;
struct ata_queued_cmd * qc ;
2005-08-26 06:01:20 +04:00
unsigned long flags ;
2005-04-17 02:20:36 +04:00
DPRINTK ( " ENTER \n " ) ;
2005-08-26 06:01:20 +04:00
spin_lock_irqsave ( & host_set - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
qc = ata_qc_from_tag ( ap , ap - > active_tag ) ;
switch ( qc - > tf . protocol ) {
case ATA_PROT_DMA :
case ATA_PROT_NODATA :
2006-05-15 15:57:56 +04:00
ata_port_printk ( ap , KERN_ERR , " command timeout \n " ) ;
2005-10-30 12:44:42 +03:00
drv_stat = ata_wait_idle ( ap ) ;
2005-12-05 10:38:02 +03:00
qc - > err_mask | = __ac_err_mask ( drv_stat ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
drv_stat = ata_busy_wait ( ap , ATA_BUSY | ATA_DRQ , 1000 ) ;
2006-05-15 15:57:56 +04:00
ata_port_printk ( ap , KERN_ERR ,
" unknown timeout, cmd 0x%x stat 0x%x \n " ,
qc - > tf . command , drv_stat ) ;
2005-04-17 02:20:36 +04:00
2005-12-05 10:38:02 +03:00
qc - > err_mask | = ac_err_mask ( drv_stat ) ;
2005-04-17 02:20:36 +04:00
break ;
}
2005-08-26 06:01:20 +04:00
spin_unlock_irqrestore ( & host_set - > lock , flags ) ;
2006-02-10 09:10:48 +03:00
ata_eh_qc_complete ( qc ) ;
2005-04-17 02:20:36 +04:00
DPRINTK ( " EXIT \n " ) ;
}
static inline unsigned int pdc_host_intr ( struct ata_port * ap ,
struct ata_queued_cmd * qc )
{
2005-12-05 10:38:02 +03:00
unsigned int handled = 0 ;
2005-04-17 02:20:36 +04:00
u32 tmp ;
2005-08-30 13:18:18 +04:00
void __iomem * mmio = ( void __iomem * ) ap - > ioaddr . cmd_addr + PDC_GLOBAL_CTL ;
2005-04-17 02:20:36 +04:00
tmp = readl ( mmio ) ;
if ( tmp & PDC_ERR_MASK ) {
2005-12-05 10:38:02 +03:00
qc - > err_mask | = AC_ERR_DEV ;
2005-04-17 02:20:36 +04:00
pdc_reset_port ( ap ) ;
}
switch ( qc - > tf . protocol ) {
case ATA_PROT_DMA :
case ATA_PROT_NODATA :
2005-12-05 10:38:02 +03:00
qc - > err_mask | = ac_err_mask ( ata_wait_idle ( ap ) ) ;
ata_qc_complete ( qc ) ;
2005-04-17 02:20:36 +04:00
handled = 1 ;
break ;
default :
2005-09-27 13:34:38 +04:00
ap - > stats . idle_irq + + ;
break ;
2005-04-17 02:20:36 +04:00
}
2005-09-27 13:34:38 +04:00
return handled ;
2005-04-17 02:20:36 +04:00
}
static void pdc_irq_clear ( struct ata_port * ap )
{
struct ata_host_set * host_set = ap - > host_set ;
2005-08-30 13:18:18 +04:00
void __iomem * mmio = host_set - > mmio_base ;
2005-04-17 02:20:36 +04:00
readl ( mmio + PDC_INT_SEQMASK ) ;
}
static irqreturn_t pdc_interrupt ( int irq , void * dev_instance , struct pt_regs * regs )
{
struct ata_host_set * host_set = dev_instance ;
struct ata_port * ap ;
u32 mask = 0 ;
unsigned int i , tmp ;
unsigned int handled = 0 ;
2005-08-30 13:18:18 +04:00
void __iomem * mmio_base ;
2005-04-17 02:20:36 +04:00
VPRINTK ( " ENTER \n " ) ;
if ( ! host_set | | ! host_set - > mmio_base ) {
VPRINTK ( " QUICK EXIT \n " ) ;
return IRQ_NONE ;
}
mmio_base = host_set - > mmio_base ;
/* reading should also clear interrupts */
mask = readl ( mmio_base + PDC_INT_SEQMASK ) ;
if ( mask = = 0xffffffff ) {
VPRINTK ( " QUICK EXIT 2 \n " ) ;
return IRQ_NONE ;
}
2006-01-28 20:39:29 +03:00
spin_lock ( & host_set - > lock ) ;
2005-04-17 02:20:36 +04:00
mask & = 0xffff ; /* only 16 tags possible */
if ( ! mask ) {
VPRINTK ( " QUICK EXIT 3 \n " ) ;
2006-01-28 20:39:29 +03:00
goto done_irq ;
2005-04-17 02:20:36 +04:00
}
writel ( mask , mmio_base + PDC_INT_SEQMASK ) ;
for ( i = 0 ; i < host_set - > n_ports ; i + + ) {
VPRINTK ( " port %u \n " , i ) ;
ap = host_set - > ports [ i ] ;
tmp = mask & ( 1 < < ( i + 1 ) ) ;
2005-08-22 09:59:24 +04:00
if ( tmp & & ap & &
2006-04-02 18:30:40 +04:00
! ( ap - > flags & ATA_FLAG_DISABLED ) ) {
2005-04-17 02:20:36 +04:00
struct ata_queued_cmd * qc ;
qc = ata_qc_from_tag ( ap , ap - > active_tag ) ;
2005-09-27 13:39:50 +04:00
if ( qc & & ( ! ( qc - > tf . flags & ATA_TFLAG_POLLING ) ) )
2005-04-17 02:20:36 +04:00
handled + = pdc_host_intr ( ap , qc ) ;
}
}
VPRINTK ( " EXIT \n " ) ;
2006-01-28 20:39:29 +03:00
done_irq :
spin_unlock ( & host_set - > lock ) ;
2005-04-17 02:20:36 +04:00
return IRQ_RETVAL ( handled ) ;
}
static inline void pdc_packet_start ( struct ata_queued_cmd * qc )
{
struct ata_port * ap = qc - > ap ;
struct pdc_port_priv * pp = ap - > private_data ;
unsigned int port_no = ap - > port_no ;
u8 seq = ( u8 ) ( port_no + 1 ) ;
VPRINTK ( " ENTER, ap %p \n " , ap ) ;
writel ( 0x00000001 , ap - > host_set - > mmio_base + ( seq * 4 ) ) ;
readl ( ap - > host_set - > mmio_base + ( seq * 4 ) ) ; /* flush */
pp - > pkt [ 2 ] = seq ;
wmb ( ) ; /* flush PRD, pkt writes */
2005-10-21 09:46:02 +04:00
writel ( pp - > pkt_dma , ( void __iomem * ) ap - > ioaddr . cmd_addr + PDC_PKT_SUBMIT ) ;
readl ( ( void __iomem * ) ap - > ioaddr . cmd_addr + PDC_PKT_SUBMIT ) ; /* flush */
2005-04-17 02:20:36 +04:00
}
2006-01-23 07:09:36 +03:00
static unsigned int pdc_qc_issue_prot ( struct ata_queued_cmd * qc )
2005-04-17 02:20:36 +04:00
{
switch ( qc - > tf . protocol ) {
case ATA_PROT_DMA :
case ATA_PROT_NODATA :
pdc_packet_start ( qc ) ;
return 0 ;
case ATA_PROT_ATAPI_DMA :
BUG ( ) ;
break ;
default :
break ;
}
return ata_qc_issue_prot ( qc ) ;
}
2005-10-22 22:27:05 +04:00
static void pdc_tf_load_mmio ( struct ata_port * ap , const struct ata_taskfile * tf )
2005-04-17 02:20:36 +04:00
{
WARN_ON ( tf - > protocol = = ATA_PROT_DMA | |
tf - > protocol = = ATA_PROT_NODATA ) ;
ata_tf_load ( ap , tf ) ;
}
2005-10-22 22:27:05 +04:00
static void pdc_exec_command_mmio ( struct ata_port * ap , const struct ata_taskfile * tf )
2005-04-17 02:20:36 +04:00
{
WARN_ON ( tf - > protocol = = ATA_PROT_DMA | |
tf - > protocol = = ATA_PROT_NODATA ) ;
ata_exec_command ( ap , tf ) ;
}
static void pdc_ata_setup_port ( struct ata_ioports * port , unsigned long base )
{
port - > cmd_addr = base ;
port - > data_addr = base ;
port - > feature_addr =
port - > error_addr = base + 0x4 ;
port - > nsect_addr = base + 0x8 ;
port - > lbal_addr = base + 0xc ;
port - > lbam_addr = base + 0x10 ;
port - > lbah_addr = base + 0x14 ;
port - > device_addr = base + 0x18 ;
port - > command_addr =
port - > status_addr = base + 0x1c ;
port - > altstatus_addr =
port - > ctl_addr = base + 0x38 ;
}
static void pdc_host_init ( unsigned int chip_id , struct ata_probe_ent * pe )
{
2005-08-30 13:18:18 +04:00
void __iomem * mmio = pe - > mmio_base ;
2006-01-28 20:39:29 +03:00
struct pdc_host_priv * hp = pe - > private_data ;
int hotplug_offset = hp - > hotplug_offset ;
2005-04-17 02:20:36 +04:00
u32 tmp ;
/*
* Except for the hotplug stuff , this is voodoo from the
* Promise driver . Label this entire section
* " TODO: figure out why we do this "
*/
/* change FIFO_SHD to 8 dwords, enable BMR_BURST */
tmp = readl ( mmio + PDC_FLASH_CTL ) ;
tmp | = 0x12000 ; /* bit 16 (fifo 8 dw) and 13 (bmr burst?) */
writel ( tmp , mmio + PDC_FLASH_CTL ) ;
/* clear plug/unplug flags for all ports */
2006-01-28 20:39:29 +03:00
tmp = readl ( mmio + hotplug_offset ) ;
writel ( tmp | 0xff , mmio + hotplug_offset ) ;
2005-04-17 02:20:36 +04:00
/* mask plug/unplug ints */
2006-01-28 20:39:29 +03:00
tmp = readl ( mmio + hotplug_offset ) ;
writel ( tmp | 0xff0000 , mmio + hotplug_offset ) ;
2005-04-17 02:20:36 +04:00
/* reduce TBG clock to 133 Mhz. */
tmp = readl ( mmio + PDC_TBG_MODE ) ;
tmp & = ~ 0x30000 ; /* clear bit 17, 16*/
tmp | = 0x10000 ; /* set bit 17:16 = 0:1 */
writel ( tmp , mmio + PDC_TBG_MODE ) ;
readl ( mmio + PDC_TBG_MODE ) ; /* flush */
msleep ( 10 ) ;
/* adjust slew rate control register. */
tmp = readl ( mmio + PDC_SLEW_CTL ) ;
tmp & = 0xFFFFF03F ; /* clear bit 11 ~ 6 */
tmp | = 0x00000900 ; /* set bit 11-9 = 100b , bit 8-6 = 100 */
writel ( tmp , mmio + PDC_SLEW_CTL ) ;
}
static int pdc_ata_init_one ( struct pci_dev * pdev , const struct pci_device_id * ent )
{
static int printed_version ;
struct ata_probe_ent * probe_ent = NULL ;
2006-01-28 20:39:29 +03:00
struct pdc_host_priv * hp ;
2005-04-17 02:20:36 +04:00
unsigned long base ;
2005-08-30 13:18:18 +04:00
void __iomem * mmio_base ;
2005-04-17 02:20:36 +04:00
unsigned int board_idx = ( unsigned int ) ent - > driver_data ;
int pci_dev_busy = 0 ;
int rc ;
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
rc = pci_enable_device ( pdev ) ;
if ( rc )
return rc ;
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 ;
2006-01-28 20:39:29 +03:00
probe_ent = kzalloc ( sizeof ( * probe_ent ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( probe_ent = = NULL ) {
rc = - ENOMEM ;
goto err_out_regions ;
}
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 , 3 , 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 ;
2006-01-28 20:39:29 +03:00
hp = kzalloc ( sizeof ( * hp ) , GFP_KERNEL ) ;
if ( hp = = NULL ) {
rc = - ENOMEM ;
goto err_out_free_ent ;
}
/* Set default hotplug offset */
hp - > hotplug_offset = PDC_SATA_PLUG_CSR ;
probe_ent - > private_data = hp ;
2005-04-17 02:20:36 +04:00
probe_ent - > sht = pdc_port_info [ board_idx ] . sht ;
probe_ent - > host_flags = pdc_port_info [ board_idx ] . host_flags ;
probe_ent - > pio_mask = pdc_port_info [ board_idx ] . pio_mask ;
probe_ent - > mwdma_mask = pdc_port_info [ board_idx ] . mwdma_mask ;
probe_ent - > udma_mask = pdc_port_info [ board_idx ] . udma_mask ;
probe_ent - > port_ops = pdc_port_info [ board_idx ] . port_ops ;
probe_ent - > irq = pdev - > irq ;
2006-07-02 06:29:42 +04:00
probe_ent - > irq_flags = IRQF_SHARED ;
2005-04-17 02:20:36 +04:00
probe_ent - > mmio_base = mmio_base ;
pdc_ata_setup_port ( & probe_ent - > port [ 0 ] , base + 0x200 ) ;
pdc_ata_setup_port ( & probe_ent - > port [ 1 ] , base + 0x280 ) ;
probe_ent - > port [ 0 ] . scr_addr = base + 0x400 ;
probe_ent - > port [ 1 ] . scr_addr = base + 0x500 ;
/* notice 4-port boards */
switch ( board_idx ) {
2006-01-28 20:39:29 +03:00
case board_40518 :
/* Override hotplug offset for SATAII150 */
hp - > hotplug_offset = PDC2_SATA_PLUG_CSR ;
/* Fall through */
2005-04-17 02:20:36 +04:00
case board_20319 :
probe_ent - > n_ports = 4 ;
pdc_ata_setup_port ( & probe_ent - > port [ 2 ] , base + 0x300 ) ;
pdc_ata_setup_port ( & probe_ent - > port [ 3 ] , base + 0x380 ) ;
probe_ent - > port [ 2 ] . scr_addr = base + 0x600 ;
probe_ent - > port [ 3 ] . scr_addr = base + 0x700 ;
break ;
2006-01-28 20:39:29 +03:00
case board_2057x :
/* Override hotplug offset for SATAII150 */
hp - > hotplug_offset = PDC2_SATA_PLUG_CSR ;
/* Fall through */
2005-04-17 02:20:36 +04:00
case board_2037x :
2005-12-01 00:42:55 +03:00
probe_ent - > n_ports = 2 ;
2005-04-17 02:20:36 +04:00
break ;
2006-01-17 16:06:21 +03:00
case board_20771 :
probe_ent - > n_ports = 2 ;
break ;
2005-05-12 23:51:01 +04:00
case board_20619 :
probe_ent - > n_ports = 4 ;
pdc_ata_setup_port ( & probe_ent - > port [ 2 ] , base + 0x300 ) ;
pdc_ata_setup_port ( & probe_ent - > port [ 3 ] , base + 0x380 ) ;
probe_ent - > port [ 2 ] . scr_addr = base + 0x600 ;
probe_ent - > port [ 3 ] . scr_addr = base + 0x700 ;
2005-12-01 00:42:55 +03:00
break ;
2005-04-17 02:20:36 +04:00
default :
BUG ( ) ;
break ;
}
pci_set_master ( pdev ) ;
/* initialize adapter */
pdc_host_init ( board_idx , probe_ent ) ;
2006-01-28 20:39:29 +03:00
/* FIXME: Need any other frees than hp? */
if ( ! ata_device_add ( probe_ent ) )
kfree ( hp ) ;
2005-04-17 02:20:36 +04:00
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 ;
}
static int __init pdc_ata_init ( void )
{
2006-08-10 13:13:18 +04:00
return pci_register_driver ( & pdc_ata_pci_driver ) ;
2005-04-17 02:20:36 +04:00
}
static void __exit pdc_ata_exit ( void )
{
pci_unregister_driver ( & pdc_ata_pci_driver ) ;
}
MODULE_AUTHOR ( " Jeff Garzik " ) ;
2005-05-12 23:51:01 +04:00
MODULE_DESCRIPTION ( " Promise ATA TX2/TX4/TX4000 low-level driver " ) ;
2005-04-17 02:20:36 +04:00
MODULE_LICENSE ( " GPL " ) ;
MODULE_DEVICE_TABLE ( pci , pdc_ata_pci_tbl ) ;
MODULE_VERSION ( DRV_VERSION ) ;
module_init ( pdc_ata_init ) ;
module_exit ( pdc_ata_exit ) ;