2007-01-26 10:28:18 +03:00
/*
* Support for IDE interfaces on Celleb platform
*
* ( C ) Copyright 2006 TOSHIBA CORPORATION
*
* This code is based on drivers / ata / ata_piix . c :
* Copyright 2003 - 2005 Red Hat Inc
* Copyright 2003 - 2005 Jeff Garzik
* Copyright ( C ) 1998 - 1999 Andrzej Krzysztofowicz , Author and Maintainer
* Copyright ( C ) 1998 - 2000 Andre Hedrick < andre @ linux - ide . org >
* Copyright ( C ) 2003 Red Hat Inc < alan @ redhat . com >
*
* and drivers / ata / ahci . c :
* Copyright 2004 - 2005 Red Hat , Inc .
*
* and drivers / ata / libata - core . c :
* Copyright 2003 - 2004 Red Hat , Inc . All rights reserved .
* Copyright 2003 - 2004 Jeff Garzik
*
* 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 of the License , 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 ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*/
# 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/device.h>
# include <scsi/scsi_host.h>
# include <linux/libata.h>
# define DRV_NAME "pata_scc"
2007-08-31 12:54:06 +04:00
# define DRV_VERSION "0.3"
2007-01-26 10:28:18 +03:00
# define PCI_DEVICE_ID_TOSHIBA_SCC_ATA 0x01b4
/* PCI BARs */
# define SCC_CTRL_BAR 0
# define SCC_BMID_BAR 1
/* offset of CTRL registers */
# define SCC_CTL_PIOSHT 0x000
# define SCC_CTL_PIOCT 0x004
# define SCC_CTL_MDMACT 0x008
# define SCC_CTL_MCRCST 0x00C
# define SCC_CTL_SDMACT 0x010
# define SCC_CTL_SCRCST 0x014
# define SCC_CTL_UDENVT 0x018
# define SCC_CTL_TDVHSEL 0x020
# define SCC_CTL_MODEREG 0x024
# define SCC_CTL_ECMODE 0xF00
# define SCC_CTL_MAEA0 0xF50
# define SCC_CTL_MAEC0 0xF54
# define SCC_CTL_CCKCTRL 0xFF0
/* offset of BMID registers */
# define SCC_DMA_CMD 0x000
# define SCC_DMA_STATUS 0x004
# define SCC_DMA_TABLE_OFS 0x008
# define SCC_DMA_INTMASK 0x010
# define SCC_DMA_INTST 0x014
# define SCC_DMA_PTERADD 0x018
# define SCC_REG_CMD_ADDR 0x020
# define SCC_REG_DATA 0x000
# define SCC_REG_ERR 0x004
# define SCC_REG_FEATURE 0x004
# define SCC_REG_NSECT 0x008
# define SCC_REG_LBAL 0x00C
# define SCC_REG_LBAM 0x010
# define SCC_REG_LBAH 0x014
# define SCC_REG_DEVICE 0x018
# define SCC_REG_STATUS 0x01C
# define SCC_REG_CMD 0x01C
# define SCC_REG_ALTSTATUS 0x020
/* register value */
# define TDVHSEL_MASTER 0x00000001
# define TDVHSEL_SLAVE 0x00000004
# define MODE_JCUSFEN 0x00000080
# define ECMODE_VALUE 0x01
# define CCKCTRL_ATARESET 0x00040000
# define CCKCTRL_BUFCNT 0x00020000
# define CCKCTRL_CRST 0x00010000
# define CCKCTRL_OCLKEN 0x00000100
# define CCKCTRL_ATACLKOEN 0x00000002
# define CCKCTRL_LCLKEN 0x00000001
# define QCHCD_IOS_SS 0x00000001
# define QCHSD_STPDIAG 0x00020000
# define INTMASK_MSK 0xD1000012
# define INTSTS_SERROR 0x80000000
# define INTSTS_PRERR 0x40000000
# define INTSTS_RERR 0x10000000
# define INTSTS_ICERR 0x01000000
# define INTSTS_BMSINT 0x00000010
# define INTSTS_BMHE 0x00000008
# define INTSTS_IOIRQS 0x00000004
# define INTSTS_INTRQ 0x00000002
# define INTSTS_ACTEINT 0x00000001
/* PIO transfer mode table */
/* JCHST */
static const unsigned long JCHSTtbl [ 2 ] [ 7 ] = {
{ 0x0E , 0x05 , 0x02 , 0x03 , 0x02 , 0x00 , 0x00 } , /* 100MHz */
{ 0x13 , 0x07 , 0x04 , 0x04 , 0x03 , 0x00 , 0x00 } /* 133MHz */
} ;
/* JCHHT */
static const unsigned long JCHHTtbl [ 2 ] [ 7 ] = {
{ 0x0E , 0x02 , 0x02 , 0x02 , 0x02 , 0x00 , 0x00 } , /* 100MHz */
{ 0x13 , 0x03 , 0x03 , 0x03 , 0x03 , 0x00 , 0x00 } /* 133MHz */
} ;
/* JCHCT */
static const unsigned long JCHCTtbl [ 2 ] [ 7 ] = {
{ 0x1D , 0x1D , 0x1C , 0x0B , 0x06 , 0x00 , 0x00 } , /* 100MHz */
{ 0x27 , 0x26 , 0x26 , 0x0E , 0x09 , 0x00 , 0x00 } /* 133MHz */
} ;
/* DMA transfer mode table */
/* JCHDCTM/JCHDCTS */
static const unsigned long JCHDCTxtbl [ 2 ] [ 7 ] = {
{ 0x0A , 0x06 , 0x04 , 0x03 , 0x01 , 0x00 , 0x00 } , /* 100MHz */
{ 0x0E , 0x09 , 0x06 , 0x04 , 0x02 , 0x01 , 0x00 } /* 133MHz */
} ;
/* JCSTWTM/JCSTWTS */
static const unsigned long JCSTWTxtbl [ 2 ] [ 7 ] = {
{ 0x06 , 0x04 , 0x03 , 0x02 , 0x02 , 0x02 , 0x00 } , /* 100MHz */
{ 0x09 , 0x06 , 0x04 , 0x02 , 0x02 , 0x02 , 0x02 } /* 133MHz */
} ;
/* JCTSS */
static const unsigned long JCTSStbl [ 2 ] [ 7 ] = {
{ 0x05 , 0x05 , 0x05 , 0x05 , 0x05 , 0x05 , 0x00 } , /* 100MHz */
{ 0x05 , 0x05 , 0x05 , 0x05 , 0x05 , 0x05 , 0x05 } /* 133MHz */
} ;
/* JCENVT */
static const unsigned long JCENVTtbl [ 2 ] [ 7 ] = {
{ 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x00 } , /* 100MHz */
{ 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 } /* 133MHz */
} ;
/* JCACTSELS/JCACTSELM */
static const unsigned long JCACTSELtbl [ 2 ] [ 7 ] = {
{ 0x00 , 0x00 , 0x00 , 0x00 , 0x01 , 0x01 , 0x00 } , /* 100MHz */
{ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x01 } /* 133MHz */
} ;
static const struct pci_device_id scc_pci_tbl [ ] = {
{ PCI_VENDOR_ID_TOSHIBA_2 , PCI_DEVICE_ID_TOSHIBA_SCC_ATA ,
PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
{ } /* terminate list */
} ;
/**
* scc_set_piomode - Initialize host controller PATA PIO timings
* @ ap : Port whose timings we are configuring
* @ adev : um
*
* Set PIO mode for device .
*
* LOCKING :
* None ( inherited from caller ) .
*/
static void scc_set_piomode ( struct ata_port * ap , struct ata_device * adev )
{
unsigned int pio = adev - > pio_mode - XFER_PIO_0 ;
void __iomem * ctrl_base = ap - > host - > iomap [ SCC_CTRL_BAR ] ;
void __iomem * cckctrl_port = ctrl_base + SCC_CTL_CCKCTRL ;
void __iomem * piosht_port = ctrl_base + SCC_CTL_PIOSHT ;
void __iomem * pioct_port = ctrl_base + SCC_CTL_PIOCT ;
unsigned long reg ;
int offset ;
reg = in_be32 ( cckctrl_port ) ;
if ( reg & CCKCTRL_ATACLKOEN )
offset = 1 ; /* 133MHz */
else
offset = 0 ; /* 100MHz */
reg = JCHSTtbl [ offset ] [ pio ] < < 16 | JCHHTtbl [ offset ] [ pio ] ;
out_be32 ( piosht_port , reg ) ;
reg = JCHCTtbl [ offset ] [ pio ] ;
out_be32 ( pioct_port , reg ) ;
}
/**
* scc_set_dmamode - Initialize host controller PATA DMA timings
* @ ap : Port whose timings we are configuring
* @ adev : um
* @ udma : udma mode , 0 - 6
*
* Set UDMA mode for device .
*
* LOCKING :
* None ( inherited from caller ) .
*/
static void scc_set_dmamode ( struct ata_port * ap , struct ata_device * adev )
{
unsigned int udma = adev - > dma_mode ;
unsigned int is_slave = ( adev - > devno ! = 0 ) ;
u8 speed = udma ;
void __iomem * ctrl_base = ap - > host - > iomap [ SCC_CTRL_BAR ] ;
void __iomem * cckctrl_port = ctrl_base + SCC_CTL_CCKCTRL ;
void __iomem * mdmact_port = ctrl_base + SCC_CTL_MDMACT ;
void __iomem * mcrcst_port = ctrl_base + SCC_CTL_MCRCST ;
void __iomem * sdmact_port = ctrl_base + SCC_CTL_SDMACT ;
void __iomem * scrcst_port = ctrl_base + SCC_CTL_SCRCST ;
void __iomem * udenvt_port = ctrl_base + SCC_CTL_UDENVT ;
void __iomem * tdvhsel_port = ctrl_base + SCC_CTL_TDVHSEL ;
int offset , idx ;
2007-02-26 13:51:33 +03:00
if ( in_be32 ( cckctrl_port ) & CCKCTRL_ATACLKOEN )
2007-01-26 10:28:18 +03:00
offset = 1 ; /* 133MHz */
else
offset = 0 ; /* 100MHz */
if ( speed > = XFER_UDMA_0 )
idx = speed - XFER_UDMA_0 ;
else
return ;
if ( is_slave ) {
out_be32 ( sdmact_port , JCHDCTxtbl [ offset ] [ idx ] ) ;
out_be32 ( scrcst_port , JCSTWTxtbl [ offset ] [ idx ] ) ;
out_be32 ( tdvhsel_port ,
( in_be32 ( tdvhsel_port ) & ~ TDVHSEL_SLAVE ) | ( JCACTSELtbl [ offset ] [ idx ] < < 2 ) ) ;
} else {
out_be32 ( mdmact_port , JCHDCTxtbl [ offset ] [ idx ] ) ;
out_be32 ( mcrcst_port , JCSTWTxtbl [ offset ] [ idx ] ) ;
out_be32 ( tdvhsel_port ,
( in_be32 ( tdvhsel_port ) & ~ TDVHSEL_MASTER ) | JCACTSELtbl [ offset ] [ idx ] ) ;
}
out_be32 ( udenvt_port ,
JCTSStbl [ offset ] [ idx ] < < 16 | JCENVTtbl [ offset ] [ idx ] ) ;
}
2007-07-17 07:10:17 +04:00
unsigned long scc_mode_filter ( struct ata_device * adev , unsigned long mask )
{
/* errata A308 workaround: limit ATAPI UDMA mode to UDMA4 */
if ( adev - > class = = ATA_DEV_ATAPI & &
( mask & ( 0xE0 < < ATA_SHIFT_UDMA ) ) ) {
printk ( KERN_INFO " %s: limit ATAPI UDMA to UDMA4 \n " , DRV_NAME ) ;
mask & = ~ ( 0xE0 < < ATA_SHIFT_UDMA ) ;
}
return ata_pci_default_filter ( adev , mask ) ;
}
2007-01-26 10:28:18 +03:00
/**
* scc_tf_load - send taskfile registers to host controller
* @ ap : Port to which output is sent
* @ tf : ATA taskfile register set
*
* Note : Original code is ata_tf_load ( ) .
*/
static void scc_tf_load ( struct ata_port * ap , const struct ata_taskfile * tf )
{
struct ata_ioports * ioaddr = & ap - > ioaddr ;
unsigned int is_addr = tf - > flags & ATA_TFLAG_ISADDR ;
if ( tf - > ctl ! = ap - > last_ctl ) {
out_be32 ( ioaddr - > ctl_addr , tf - > ctl ) ;
ap - > last_ctl = tf - > ctl ;
ata_wait_idle ( ap ) ;
}
if ( is_addr & & ( tf - > flags & ATA_TFLAG_LBA48 ) ) {
out_be32 ( ioaddr - > feature_addr , tf - > hob_feature ) ;
out_be32 ( ioaddr - > nsect_addr , tf - > hob_nsect ) ;
out_be32 ( ioaddr - > lbal_addr , tf - > hob_lbal ) ;
out_be32 ( ioaddr - > lbam_addr , tf - > hob_lbam ) ;
out_be32 ( ioaddr - > lbah_addr , tf - > hob_lbah ) ;
VPRINTK ( " hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X \n " ,
tf - > hob_feature ,
tf - > hob_nsect ,
tf - > hob_lbal ,
tf - > hob_lbam ,
tf - > hob_lbah ) ;
}
if ( is_addr ) {
out_be32 ( ioaddr - > feature_addr , tf - > feature ) ;
out_be32 ( ioaddr - > nsect_addr , tf - > nsect ) ;
out_be32 ( ioaddr - > lbal_addr , tf - > lbal ) ;
out_be32 ( ioaddr - > lbam_addr , tf - > lbam ) ;
out_be32 ( ioaddr - > lbah_addr , tf - > lbah ) ;
VPRINTK ( " feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X \n " ,
tf - > feature ,
tf - > nsect ,
tf - > lbal ,
tf - > lbam ,
tf - > lbah ) ;
}
if ( tf - > flags & ATA_TFLAG_DEVICE ) {
out_be32 ( ioaddr - > device_addr , tf - > device ) ;
VPRINTK ( " device 0x%X \n " , tf - > device ) ;
}
ata_wait_idle ( ap ) ;
}
/**
* scc_check_status - Read device status reg & clear interrupt
* @ ap : port where the device is
*
* Note : Original code is ata_check_status ( ) .
*/
static u8 scc_check_status ( struct ata_port * ap )
{
return in_be32 ( ap - > ioaddr . status_addr ) ;
}
/**
* scc_tf_read - input device ' s ATA taskfile shadow registers
* @ ap : Port from which input is read
* @ tf : ATA taskfile register set for storing input
*
* Note : Original code is ata_tf_read ( ) .
*/
static void scc_tf_read ( struct ata_port * ap , struct ata_taskfile * tf )
{
struct ata_ioports * ioaddr = & ap - > ioaddr ;
tf - > command = scc_check_status ( ap ) ;
tf - > feature = in_be32 ( ioaddr - > error_addr ) ;
tf - > nsect = in_be32 ( ioaddr - > nsect_addr ) ;
tf - > lbal = in_be32 ( ioaddr - > lbal_addr ) ;
tf - > lbam = in_be32 ( ioaddr - > lbam_addr ) ;
tf - > lbah = in_be32 ( ioaddr - > lbah_addr ) ;
tf - > device = in_be32 ( ioaddr - > device_addr ) ;
if ( tf - > flags & ATA_TFLAG_LBA48 ) {
out_be32 ( ioaddr - > ctl_addr , tf - > ctl | ATA_HOB ) ;
tf - > hob_feature = in_be32 ( ioaddr - > error_addr ) ;
tf - > hob_nsect = in_be32 ( ioaddr - > nsect_addr ) ;
tf - > hob_lbal = in_be32 ( ioaddr - > lbal_addr ) ;
tf - > hob_lbam = in_be32 ( ioaddr - > lbam_addr ) ;
tf - > hob_lbah = in_be32 ( ioaddr - > lbah_addr ) ;
2007-07-20 15:44:44 +04:00
out_be32 ( ioaddr - > ctl_addr , tf - > ctl ) ;
ap - > last_ctl = tf - > ctl ;
2007-01-26 10:28:18 +03:00
}
}
/**
* scc_exec_command - issue ATA command to host controller
* @ ap : port to which command is being issued
* @ tf : ATA taskfile register set
*
* Note : Original code is ata_exec_command ( ) .
*/
static void scc_exec_command ( struct ata_port * ap ,
const struct ata_taskfile * tf )
{
2007-02-21 10:36:33 +03:00
DPRINTK ( " ata%u: cmd 0x%X \n " , ap - > print_id , tf - > command ) ;
2007-01-26 10:28:18 +03:00
out_be32 ( ap - > ioaddr . command_addr , tf - > command ) ;
ata_pause ( ap ) ;
}
/**
* scc_check_altstatus - Read device alternate status reg
* @ ap : port where the device is
*/
static u8 scc_check_altstatus ( struct ata_port * ap )
{
return in_be32 ( ap - > ioaddr . altstatus_addr ) ;
}
/**
* scc_std_dev_select - Select device 0 / 1 on ATA bus
* @ ap : ATA channel to manipulate
* @ device : ATA device ( numbered from zero ) to select
*
* Note : Original code is ata_std_dev_select ( ) .
*/
static void scc_std_dev_select ( struct ata_port * ap , unsigned int device )
{
u8 tmp ;
if ( device = = 0 )
tmp = ATA_DEVICE_OBS ;
else
tmp = ATA_DEVICE_OBS | ATA_DEV1 ;
out_be32 ( ap - > ioaddr . device_addr , tmp ) ;
ata_pause ( ap ) ;
}
/**
* scc_bmdma_setup - Set up PCI IDE BMDMA transaction
* @ qc : Info associated with this ATA transaction .
*
* Note : Original code is ata_bmdma_setup ( ) .
*/
static void scc_bmdma_setup ( struct ata_queued_cmd * qc )
{
struct ata_port * ap = qc - > ap ;
unsigned int rw = ( qc - > tf . flags & ATA_TFLAG_WRITE ) ;
u8 dmactl ;
void __iomem * mmio = ap - > ioaddr . bmdma_addr ;
/* load PRD table addr */
out_be32 ( mmio + SCC_DMA_TABLE_OFS , ap - > prd_dma ) ;
/* specify data direction, triple-check start bit is clear */
dmactl = in_be32 ( mmio + SCC_DMA_CMD ) ;
dmactl & = ~ ( ATA_DMA_WR | ATA_DMA_START ) ;
if ( ! rw )
dmactl | = ATA_DMA_WR ;
out_be32 ( mmio + SCC_DMA_CMD , dmactl ) ;
/* issue r/w command */
ap - > ops - > exec_command ( ap , & qc - > tf ) ;
}
/**
* scc_bmdma_start - Start a PCI IDE BMDMA transaction
* @ qc : Info associated with this ATA transaction .
*
* Note : Original code is ata_bmdma_start ( ) .
*/
static void scc_bmdma_start ( struct ata_queued_cmd * qc )
{
struct ata_port * ap = qc - > ap ;
u8 dmactl ;
void __iomem * mmio = ap - > ioaddr . bmdma_addr ;
/* start host DMA transaction */
dmactl = in_be32 ( mmio + SCC_DMA_CMD ) ;
out_be32 ( mmio + SCC_DMA_CMD , dmactl | ATA_DMA_START ) ;
}
/**
* scc_devchk - PATA device presence detection
* @ ap : ATA channel to examine
* @ device : Device to examine ( starting at zero )
*
* Note : Original code is ata_devchk ( ) .
*/
static unsigned int scc_devchk ( struct ata_port * ap ,
unsigned int device )
{
struct ata_ioports * ioaddr = & ap - > ioaddr ;
u8 nsect , lbal ;
ap - > ops - > dev_select ( ap , device ) ;
out_be32 ( ioaddr - > nsect_addr , 0x55 ) ;
out_be32 ( ioaddr - > lbal_addr , 0xaa ) ;
out_be32 ( ioaddr - > nsect_addr , 0xaa ) ;
out_be32 ( ioaddr - > lbal_addr , 0x55 ) ;
out_be32 ( ioaddr - > nsect_addr , 0x55 ) ;
out_be32 ( ioaddr - > lbal_addr , 0xaa ) ;
nsect = in_be32 ( ioaddr - > nsect_addr ) ;
lbal = in_be32 ( ioaddr - > lbal_addr ) ;
if ( ( nsect = = 0x55 ) & & ( lbal = = 0xaa ) )
return 1 ; /* we found a device */
return 0 ; /* nothing found */
}
/**
* scc_bus_post_reset - PATA device post reset
*
* Note : Original code is ata_bus_post_reset ( ) .
*/
2007-05-24 01:26:43 +04:00
static int scc_bus_post_reset ( struct ata_port * ap , unsigned int devmask ,
unsigned long deadline )
2007-01-26 10:28:18 +03:00
{
struct ata_ioports * ioaddr = & ap - > ioaddr ;
unsigned int dev0 = devmask & ( 1 < < 0 ) ;
unsigned int dev1 = devmask & ( 1 < < 1 ) ;
2007-05-24 01:26:43 +04:00
int rc ;
2007-01-26 10:28:18 +03:00
/* if device 0 was found in ata_devchk, wait for its
* BSY bit to clear
*/
2007-05-24 01:26:43 +04:00
if ( dev0 ) {
rc = ata_wait_ready ( ap , deadline ) ;
if ( rc & & rc ! = - ENODEV )
return rc ;
}
2007-01-26 10:28:18 +03:00
/* if device 1 was found in ata_devchk, wait for
* register access , then wait for BSY to clear
*/
while ( dev1 ) {
u8 nsect , lbal ;
ap - > ops - > dev_select ( ap , 1 ) ;
nsect = in_be32 ( ioaddr - > nsect_addr ) ;
lbal = in_be32 ( ioaddr - > lbal_addr ) ;
if ( ( nsect = = 1 ) & & ( lbal = = 1 ) )
break ;
2007-05-24 01:26:43 +04:00
if ( time_after ( jiffies , deadline ) )
return - EBUSY ;
2007-01-26 10:28:18 +03:00
msleep ( 50 ) ; /* give drive a breather */
}
2007-05-24 01:26:43 +04:00
if ( dev1 ) {
rc = ata_wait_ready ( ap , deadline ) ;
if ( rc & & rc ! = - ENODEV )
return rc ;
}
2007-01-26 10:28:18 +03:00
/* is all this really necessary? */
ap - > ops - > dev_select ( ap , 0 ) ;
if ( dev1 )
ap - > ops - > dev_select ( ap , 1 ) ;
if ( dev0 )
ap - > ops - > dev_select ( ap , 0 ) ;
2007-05-24 01:26:43 +04:00
return 0 ;
2007-01-26 10:28:18 +03:00
}
/**
* scc_bus_softreset - PATA device software reset
*
* Note : Original code is ata_bus_softreset ( ) .
*/
2007-05-24 01:26:43 +04:00
static unsigned int scc_bus_softreset ( struct ata_port * ap , unsigned int devmask ,
unsigned long deadline )
2007-01-26 10:28:18 +03:00
{
struct ata_ioports * ioaddr = & ap - > ioaddr ;
2007-02-21 10:36:33 +03:00
DPRINTK ( " ata%u: bus reset via SRST \n " , ap - > print_id ) ;
2007-01-26 10:28:18 +03:00
/* software reset. causes dev0 to be selected */
out_be32 ( ioaddr - > ctl_addr , ap - > ctl ) ;
udelay ( 20 ) ;
out_be32 ( ioaddr - > ctl_addr , ap - > ctl | ATA_SRST ) ;
udelay ( 20 ) ;
out_be32 ( ioaddr - > ctl_addr , ap - > ctl ) ;
/* spec mandates ">= 2ms" before checking status.
* We wait 150 ms , because that was the magic delay used for
* ATAPI devices in Hale Landis ' s ATADRVR , for the period of time
* between when the ATA command register is written , and then
* status is checked . Because waiting for " a while " before
* checking status is fine , post SRST , we perform this magic
* delay here as well .
*
* Old drivers / ide uses the 2 mS rule and then waits for ready
*/
msleep ( 150 ) ;
/* Before we perform post reset processing we want to see if
* the bus shows 0xFF because the odd clown forgets the D7
* pulldown resistor .
*/
if ( scc_check_status ( ap ) = = 0xFF )
return 0 ;
2007-05-24 01:26:43 +04:00
scc_bus_post_reset ( ap , devmask , deadline ) ;
2007-01-26 10:28:18 +03:00
return 0 ;
}
/**
* scc_std_softreset - reset host port via ATA SRST
* @ ap : port to reset
* @ classes : resulting classes of attached devices
2007-05-24 01:26:43 +04:00
* @ deadline : deadline jiffies for the operation
2007-01-26 10:28:18 +03:00
*
* Note : Original code is ata_std_softreset ( ) .
*/
2007-09-22 06:50:09 +04:00
static int scc_std_softreset ( struct ata_link * link , unsigned int * classes ,
unsigned long deadline )
2007-01-26 10:28:18 +03:00
{
2007-09-22 06:50:09 +04:00
struct ata_port * ap = link - > ap ;
2007-01-26 10:28:18 +03:00
unsigned int slave_possible = ap - > flags & ATA_FLAG_SLAVE_POSS ;
unsigned int devmask = 0 , err_mask ;
u8 err ;
DPRINTK ( " ENTER \n " ) ;
2007-09-22 06:50:09 +04:00
if ( ata_link_offline ( link ) ) {
2007-01-26 10:28:18 +03:00
classes [ 0 ] = ATA_DEV_NONE ;
goto out ;
}
/* determine if device 0/1 are present */
if ( scc_devchk ( ap , 0 ) )
devmask | = ( 1 < < 0 ) ;
if ( slave_possible & & scc_devchk ( ap , 1 ) )
devmask | = ( 1 < < 1 ) ;
/* select device 0 again */
ap - > ops - > dev_select ( ap , 0 ) ;
/* issue bus reset */
DPRINTK ( " about to softreset, devmask=%x \n " , devmask ) ;
2007-05-24 01:26:43 +04:00
err_mask = scc_bus_softreset ( ap , devmask , deadline ) ;
2007-01-26 10:28:18 +03:00
if ( err_mask ) {
ata_port_printk ( ap , KERN_ERR , " SRST failed (err_mask=0x%x) \n " ,
err_mask ) ;
return - EIO ;
}
/* determine by signature whether we have ATA or ATAPI devices */
2007-09-02 18:23:57 +04:00
classes [ 0 ] = ata_dev_try_classify ( & ap - > link . device [ 0 ] ,
devmask & ( 1 < < 0 ) , & err ) ;
2007-01-26 10:28:18 +03:00
if ( slave_possible & & err ! = 0x81 )
2007-09-02 18:23:57 +04:00
classes [ 1 ] = ata_dev_try_classify ( & ap - > link . device [ 1 ] ,
devmask & ( 1 < < 1 ) , & err ) ;
2007-01-26 10:28:18 +03:00
out :
DPRINTK ( " EXIT, classes[0]=%u [1]=%u \n " , classes [ 0 ] , classes [ 1 ] ) ;
return 0 ;
}
/**
* scc_bmdma_stop - Stop PCI IDE BMDMA transfer
* @ qc : Command we are ending DMA for
*/
static void scc_bmdma_stop ( struct ata_queued_cmd * qc )
{
struct ata_port * ap = qc - > ap ;
void __iomem * ctrl_base = ap - > host - > iomap [ SCC_CTRL_BAR ] ;
void __iomem * bmid_base = ap - > host - > iomap [ SCC_BMID_BAR ] ;
u32 reg ;
while ( 1 ) {
reg = in_be32 ( bmid_base + SCC_DMA_INTST ) ;
if ( reg & INTSTS_SERROR ) {
printk ( KERN_WARNING " %s: SERROR \n " , DRV_NAME ) ;
out_be32 ( bmid_base + SCC_DMA_INTST , INTSTS_SERROR | INTSTS_BMSINT ) ;
out_be32 ( bmid_base + SCC_DMA_CMD ,
in_be32 ( bmid_base + SCC_DMA_CMD ) & ~ ATA_DMA_START ) ;
continue ;
}
if ( reg & INTSTS_PRERR ) {
u32 maea0 , maec0 ;
maea0 = in_be32 ( ctrl_base + SCC_CTL_MAEA0 ) ;
maec0 = in_be32 ( ctrl_base + SCC_CTL_MAEC0 ) ;
printk ( KERN_WARNING " %s: PRERR [addr:%x cmd:%x] \n " , DRV_NAME , maea0 , maec0 ) ;
out_be32 ( bmid_base + SCC_DMA_INTST , INTSTS_PRERR | INTSTS_BMSINT ) ;
out_be32 ( bmid_base + SCC_DMA_CMD ,
in_be32 ( bmid_base + SCC_DMA_CMD ) & ~ ATA_DMA_START ) ;
continue ;
}
if ( reg & INTSTS_RERR ) {
printk ( KERN_WARNING " %s: Response Error \n " , DRV_NAME ) ;
out_be32 ( bmid_base + SCC_DMA_INTST , INTSTS_RERR | INTSTS_BMSINT ) ;
out_be32 ( bmid_base + SCC_DMA_CMD ,
in_be32 ( bmid_base + SCC_DMA_CMD ) & ~ ATA_DMA_START ) ;
continue ;
}
if ( reg & INTSTS_ICERR ) {
out_be32 ( bmid_base + SCC_DMA_CMD ,
in_be32 ( bmid_base + SCC_DMA_CMD ) & ~ ATA_DMA_START ) ;
printk ( KERN_WARNING " %s: Illegal Configuration \n " , DRV_NAME ) ;
out_be32 ( bmid_base + SCC_DMA_INTST , INTSTS_ICERR | INTSTS_BMSINT ) ;
continue ;
}
if ( reg & INTSTS_BMSINT ) {
unsigned int classes ;
2007-05-24 01:26:43 +04:00
unsigned long deadline = jiffies + ATA_TMOUT_BOOT ;
2007-01-26 10:28:18 +03:00
printk ( KERN_WARNING " %s: Internal Bus Error \n " , DRV_NAME ) ;
out_be32 ( bmid_base + SCC_DMA_INTST , INTSTS_BMSINT ) ;
/* TBD: SW reset */
2007-09-22 06:50:09 +04:00
scc_std_softreset ( & ap - > link , & classes , deadline ) ;
2007-01-26 10:28:18 +03:00
continue ;
}
if ( reg & INTSTS_BMHE ) {
out_be32 ( bmid_base + SCC_DMA_INTST , INTSTS_BMHE ) ;
continue ;
}
if ( reg & INTSTS_ACTEINT ) {
out_be32 ( bmid_base + SCC_DMA_INTST , INTSTS_ACTEINT ) ;
continue ;
}
if ( reg & INTSTS_IOIRQS ) {
out_be32 ( bmid_base + SCC_DMA_INTST , INTSTS_IOIRQS ) ;
continue ;
}
break ;
}
/* clear start/stop bit */
out_be32 ( bmid_base + SCC_DMA_CMD ,
in_be32 ( bmid_base + SCC_DMA_CMD ) & ~ ATA_DMA_START ) ;
/* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
ata_altstatus ( ap ) ; /* dummy read */
}
/**
* scc_bmdma_status - Read PCI IDE BMDMA status
* @ ap : Port associated with this ATA transaction .
*/
static u8 scc_bmdma_status ( struct ata_port * ap )
{
void __iomem * mmio = ap - > ioaddr . bmdma_addr ;
2007-07-10 13:29:34 +04:00
u8 host_stat = in_be32 ( mmio + SCC_DMA_STATUS ) ;
u32 int_status = in_be32 ( mmio + SCC_DMA_INTST ) ;
2007-09-22 06:50:09 +04:00
struct ata_queued_cmd * qc = ata_qc_from_tag ( ap , ap - > link . active_tag ) ;
2007-07-10 13:29:34 +04:00
static int retry = 0 ;
/* return if IOS_SS is cleared */
if ( ! ( in_be32 ( mmio + SCC_DMA_CMD ) & ATA_DMA_START ) )
return host_stat ;
/* errata A252,A308 workaround: Step4 */
2007-07-17 07:10:17 +04:00
if ( ( ata_altstatus ( ap ) & ATA_ERR ) & & ( int_status & INTSTS_INTRQ ) )
2007-07-10 13:29:34 +04:00
return ( host_stat | ATA_DMA_INTR ) ;
/* errata A308 workaround Step5 */
if ( int_status & INTSTS_IOIRQS ) {
host_stat | = ATA_DMA_INTR ;
/* We don't check ATAPI DMA because it is limited to UDMA4 */
if ( ( qc - > tf . protocol = = ATA_PROT_DMA & &
qc - > dev - > xfer_mode > XFER_UDMA_4 ) ) {
if ( ! ( int_status & INTSTS_ACTEINT ) ) {
2007-07-17 07:10:17 +04:00
printk ( KERN_WARNING " ata%u: operation failed (transfer data loss) \n " ,
ap - > print_id ) ;
2007-07-10 13:29:34 +04:00
host_stat | = ATA_DMA_ERR ;
if ( retry + + )
2007-07-17 07:10:17 +04:00
ap - > udma_mask & = ~ ( 1 < < qc - > dev - > xfer_mode ) ;
2007-07-10 13:29:34 +04:00
} else
retry = 0 ;
}
2007-01-26 10:28:18 +03:00
}
return host_stat ;
}
/**
* scc_data_xfer - Transfer data by PIO
* @ adev : device for this I / O
* @ buf : data buffer
* @ buflen : buffer length
* @ write_data : read / write
*
* Note : Original code is ata_data_xfer ( ) .
*/
static void scc_data_xfer ( struct ata_device * adev , unsigned char * buf ,
unsigned int buflen , int write_data )
{
2007-08-06 13:36:22 +04:00
struct ata_port * ap = adev - > link - > ap ;
2007-01-26 10:28:18 +03:00
unsigned int words = buflen > > 1 ;
unsigned int i ;
u16 * buf16 = ( u16 * ) buf ;
void __iomem * mmio = ap - > ioaddr . data_addr ;
/* Transfer multiple of 2 bytes */
if ( write_data ) {
for ( i = 0 ; i < words ; i + + )
out_be32 ( mmio , cpu_to_le16 ( buf16 [ i ] ) ) ;
} else {
for ( i = 0 ; i < words ; i + + )
buf16 [ i ] = le16_to_cpu ( in_be32 ( mmio ) ) ;
}
/* Transfer trailing 1 byte, if any. */
if ( unlikely ( buflen & 0x01 ) ) {
u16 align_buf [ 1 ] = { 0 } ;
unsigned char * trailing_buf = buf + buflen - 1 ;
if ( write_data ) {
memcpy ( align_buf , trailing_buf , 1 ) ;
out_be32 ( mmio , cpu_to_le16 ( align_buf [ 0 ] ) ) ;
} else {
align_buf [ 0 ] = le16_to_cpu ( in_be32 ( mmio ) ) ;
memcpy ( trailing_buf , align_buf , 1 ) ;
}
}
}
/**
* scc_irq_on - Enable interrupts on a port .
* @ ap : Port on which interrupts are enabled .
*
* Note : Original code is ata_irq_on ( ) .
*/
static u8 scc_irq_on ( struct ata_port * ap )
{
struct ata_ioports * ioaddr = & ap - > ioaddr ;
u8 tmp ;
ap - > ctl & = ~ ATA_NIEN ;
ap - > last_ctl = ap - > ctl ;
out_be32 ( ioaddr - > ctl_addr , ap - > ctl ) ;
tmp = ata_wait_idle ( ap ) ;
ap - > ops - > irq_clear ( ap ) ;
return tmp ;
}
/**
* scc_bmdma_freeze - Freeze BMDMA controller port
* @ ap : port to freeze
*
* Note : Original code is ata_bmdma_freeze ( ) .
*/
static void scc_bmdma_freeze ( struct ata_port * ap )
{
struct ata_ioports * ioaddr = & ap - > ioaddr ;
ap - > ctl | = ATA_NIEN ;
ap - > last_ctl = ap - > ctl ;
out_be32 ( ioaddr - > ctl_addr , ap - > ctl ) ;
/* Under certain circumstances, some controllers raise IRQ on
* ATA_NIEN manipulation . Also , many controllers fail to mask
* previously pending IRQ on ATA_NIEN assertion . Clear it .
*/
ata_chk_status ( ap ) ;
ap - > ops - > irq_clear ( ap ) ;
}
/**
* scc_pata_prereset - prepare for reset
* @ ap : ATA port to be reset
2007-05-24 01:26:43 +04:00
* @ deadline : deadline jiffies for the operation
2007-01-26 10:28:18 +03:00
*/
2007-09-22 06:50:09 +04:00
static int scc_pata_prereset ( struct ata_link * link , unsigned long deadline )
2007-01-26 10:28:18 +03:00
{
2007-09-22 06:50:09 +04:00
link - > ap - > cbl = ATA_CBL_PATA80 ;
return ata_std_prereset ( link , deadline ) ;
2007-01-26 10:28:18 +03:00
}
/**
* scc_std_postreset - standard postreset callback
* @ ap : the target ata_port
* @ classes : classes of attached devices
*
* Note : Original code is ata_std_postreset ( ) .
*/
2007-09-22 06:50:09 +04:00
static void scc_std_postreset ( struct ata_link * link , unsigned int * classes )
2007-01-26 10:28:18 +03:00
{
2007-09-22 06:50:09 +04:00
struct ata_port * ap = link - > ap ;
2007-01-26 10:28:18 +03:00
DPRINTK ( " ENTER \n " ) ;
/* is double-select really necessary? */
if ( classes [ 0 ] ! = ATA_DEV_NONE )
ap - > ops - > dev_select ( ap , 1 ) ;
if ( classes [ 1 ] ! = ATA_DEV_NONE )
ap - > ops - > dev_select ( ap , 0 ) ;
/* bail out if no device is present */
if ( classes [ 0 ] = = ATA_DEV_NONE & & classes [ 1 ] = = ATA_DEV_NONE ) {
DPRINTK ( " EXIT, no device \n " ) ;
return ;
}
/* set up device control */
if ( ap - > ioaddr . ctl_addr )
out_be32 ( ap - > ioaddr . ctl_addr , ap - > ctl ) ;
DPRINTK ( " EXIT \n " ) ;
}
/**
* scc_error_handler - Stock error handler for BMDMA controller
* @ ap : port to handle error for
*/
static void scc_error_handler ( struct ata_port * ap )
{
ata_bmdma_drive_eh ( ap , scc_pata_prereset , scc_std_softreset , NULL ,
scc_std_postreset ) ;
}
/**
* scc_bmdma_irq_clear - Clear PCI IDE BMDMA interrupt .
* @ ap : Port associated with this ATA transaction .
*
* Note : Original code is ata_bmdma_irq_clear ( ) .
*/
static void scc_bmdma_irq_clear ( struct ata_port * ap )
{
void __iomem * mmio = ap - > ioaddr . bmdma_addr ;
if ( ! mmio )
return ;
out_be32 ( mmio + SCC_DMA_STATUS , in_be32 ( mmio + SCC_DMA_STATUS ) ) ;
}
/**
* scc_port_start - Set port up for dma .
* @ ap : Port to initialize
*
* Allocate space for PRD table using ata_port_start ( ) .
* Set PRD table address for PTERADD . ( PRD Transfer End Read )
*/
static int scc_port_start ( struct ata_port * ap )
{
void __iomem * mmio = ap - > ioaddr . bmdma_addr ;
int rc ;
rc = ata_port_start ( ap ) ;
if ( rc )
return rc ;
out_be32 ( mmio + SCC_DMA_PTERADD , ap - > prd_dma ) ;
return 0 ;
}
/**
* scc_port_stop - Undo scc_port_start ( )
* @ ap : Port to shut down
*
* Reset PTERADD .
*/
static void scc_port_stop ( struct ata_port * ap )
{
void __iomem * mmio = ap - > ioaddr . bmdma_addr ;
out_be32 ( mmio + SCC_DMA_PTERADD , 0 ) ;
}
static struct scsi_host_template scc_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 ,
. 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 ,
. slave_destroy = ata_scsi_slave_destroy ,
. bios_param = ata_std_bios_param ,
} ;
static const struct ata_port_operations scc_pata_ops = {
. set_piomode = scc_set_piomode ,
. set_dmamode = scc_set_dmamode ,
2007-07-17 07:10:17 +04:00
. mode_filter = scc_mode_filter ,
2007-01-26 10:28:18 +03:00
. tf_load = scc_tf_load ,
. tf_read = scc_tf_read ,
. exec_command = scc_exec_command ,
. check_status = scc_check_status ,
. check_altstatus = scc_check_altstatus ,
. dev_select = scc_std_dev_select ,
. bmdma_setup = scc_bmdma_setup ,
. bmdma_start = scc_bmdma_start ,
. bmdma_stop = scc_bmdma_stop ,
. bmdma_status = scc_bmdma_status ,
. data_xfer = scc_data_xfer ,
. qc_prep = ata_qc_prep ,
. qc_issue = ata_qc_issue_prot ,
. freeze = scc_bmdma_freeze ,
. error_handler = scc_error_handler ,
. post_internal_cmd = scc_bmdma_stop ,
. irq_clear = scc_bmdma_irq_clear ,
. irq_on = scc_irq_on ,
. port_start = scc_port_start ,
. port_stop = scc_port_stop ,
} ;
static struct ata_port_info scc_port_info [ ] = {
{
. flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY ,
. pio_mask = 0x1f , /* pio0-4 */
. mwdma_mask = 0x00 ,
. udma_mask = ATA_UDMA6 ,
. port_ops = & scc_pata_ops ,
} ,
} ;
/**
* scc_reset_controller - initialize SCC PATA controller .
*/
libata: convert the remaining PATA drivers to new init model
Convert pdc_adma, pata_cs5520, pata_isapnp, pata_ixp4xx_cf,
pata_legacy, pata_mpc52xx, pata_mpiix, pata_pcmcia, pata_pdc2027x,
pata_platform, pata_qdi, pata_scc and pata_winbond to new init model.
* init_one()'s now follow more consistent init order
* cs5520 now registers one host with two ports, not two hosts. If any
of the two ports are disabled, it's made dummy as other drivers do.
Tested pdc_adma and pata_legacy. Both are as broken as before. The
rest are compile tested only.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
2007-04-17 18:44:08 +04:00
static int scc_reset_controller ( struct ata_host * host )
2007-01-26 10:28:18 +03:00
{
libata: convert the remaining PATA drivers to new init model
Convert pdc_adma, pata_cs5520, pata_isapnp, pata_ixp4xx_cf,
pata_legacy, pata_mpc52xx, pata_mpiix, pata_pcmcia, pata_pdc2027x,
pata_platform, pata_qdi, pata_scc and pata_winbond to new init model.
* init_one()'s now follow more consistent init order
* cs5520 now registers one host with two ports, not two hosts. If any
of the two ports are disabled, it's made dummy as other drivers do.
Tested pdc_adma and pata_legacy. Both are as broken as before. The
rest are compile tested only.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
2007-04-17 18:44:08 +04:00
void __iomem * ctrl_base = host - > iomap [ SCC_CTRL_BAR ] ;
void __iomem * bmid_base = host - > iomap [ SCC_BMID_BAR ] ;
2007-01-26 10:28:18 +03:00
void __iomem * cckctrl_port = ctrl_base + SCC_CTL_CCKCTRL ;
void __iomem * mode_port = ctrl_base + SCC_CTL_MODEREG ;
void __iomem * ecmode_port = ctrl_base + SCC_CTL_ECMODE ;
void __iomem * intmask_port = bmid_base + SCC_DMA_INTMASK ;
void __iomem * dmastatus_port = bmid_base + SCC_DMA_STATUS ;
u32 reg = 0 ;
out_be32 ( cckctrl_port , reg ) ;
reg | = CCKCTRL_ATACLKOEN ;
out_be32 ( cckctrl_port , reg ) ;
reg | = CCKCTRL_LCLKEN | CCKCTRL_OCLKEN ;
out_be32 ( cckctrl_port , reg ) ;
reg | = CCKCTRL_CRST ;
out_be32 ( cckctrl_port , reg ) ;
for ( ; ; ) {
reg = in_be32 ( cckctrl_port ) ;
if ( reg & CCKCTRL_CRST )
break ;
udelay ( 5000 ) ;
}
reg | = CCKCTRL_ATARESET ;
out_be32 ( cckctrl_port , reg ) ;
out_be32 ( ecmode_port , ECMODE_VALUE ) ;
out_be32 ( mode_port , MODE_JCUSFEN ) ;
out_be32 ( intmask_port , INTMASK_MSK ) ;
if ( in_be32 ( dmastatus_port ) & QCHSD_STPDIAG ) {
printk ( KERN_WARNING " %s: failed to detect 80c cable. (PDIAG# is high) \n " , DRV_NAME ) ;
return - EIO ;
}
return 0 ;
}
/**
* scc_setup_ports - initialize ioaddr with SCC PATA port offsets .
* @ ioaddr : IO address structure to be initialized
* @ base : base address of BMID region
*/
static void scc_setup_ports ( struct ata_ioports * ioaddr , void __iomem * base )
{
ioaddr - > cmd_addr = base + SCC_REG_CMD_ADDR ;
ioaddr - > altstatus_addr = ioaddr - > cmd_addr + SCC_REG_ALTSTATUS ;
ioaddr - > ctl_addr = ioaddr - > cmd_addr + SCC_REG_ALTSTATUS ;
ioaddr - > bmdma_addr = base ;
ioaddr - > data_addr = ioaddr - > cmd_addr + SCC_REG_DATA ;
ioaddr - > error_addr = ioaddr - > cmd_addr + SCC_REG_ERR ;
ioaddr - > feature_addr = ioaddr - > cmd_addr + SCC_REG_FEATURE ;
ioaddr - > nsect_addr = ioaddr - > cmd_addr + SCC_REG_NSECT ;
ioaddr - > lbal_addr = ioaddr - > cmd_addr + SCC_REG_LBAL ;
ioaddr - > lbam_addr = ioaddr - > cmd_addr + SCC_REG_LBAM ;
ioaddr - > lbah_addr = ioaddr - > cmd_addr + SCC_REG_LBAH ;
ioaddr - > device_addr = ioaddr - > cmd_addr + SCC_REG_DEVICE ;
ioaddr - > status_addr = ioaddr - > cmd_addr + SCC_REG_STATUS ;
ioaddr - > command_addr = ioaddr - > cmd_addr + SCC_REG_CMD ;
}
libata: convert the remaining PATA drivers to new init model
Convert pdc_adma, pata_cs5520, pata_isapnp, pata_ixp4xx_cf,
pata_legacy, pata_mpc52xx, pata_mpiix, pata_pcmcia, pata_pdc2027x,
pata_platform, pata_qdi, pata_scc and pata_winbond to new init model.
* init_one()'s now follow more consistent init order
* cs5520 now registers one host with two ports, not two hosts. If any
of the two ports are disabled, it's made dummy as other drivers do.
Tested pdc_adma and pata_legacy. Both are as broken as before. The
rest are compile tested only.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
2007-04-17 18:44:08 +04:00
static int scc_host_init ( struct ata_host * host )
2007-01-26 10:28:18 +03:00
{
libata: convert the remaining PATA drivers to new init model
Convert pdc_adma, pata_cs5520, pata_isapnp, pata_ixp4xx_cf,
pata_legacy, pata_mpc52xx, pata_mpiix, pata_pcmcia, pata_pdc2027x,
pata_platform, pata_qdi, pata_scc and pata_winbond to new init model.
* init_one()'s now follow more consistent init order
* cs5520 now registers one host with two ports, not two hosts. If any
of the two ports are disabled, it's made dummy as other drivers do.
Tested pdc_adma and pata_legacy. Both are as broken as before. The
rest are compile tested only.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
2007-04-17 18:44:08 +04:00
struct pci_dev * pdev = to_pci_dev ( host - > dev ) ;
2007-01-26 10:28:18 +03:00
int rc ;
libata: convert the remaining PATA drivers to new init model
Convert pdc_adma, pata_cs5520, pata_isapnp, pata_ixp4xx_cf,
pata_legacy, pata_mpc52xx, pata_mpiix, pata_pcmcia, pata_pdc2027x,
pata_platform, pata_qdi, pata_scc and pata_winbond to new init model.
* init_one()'s now follow more consistent init order
* cs5520 now registers one host with two ports, not two hosts. If any
of the two ports are disabled, it's made dummy as other drivers do.
Tested pdc_adma and pata_legacy. Both are as broken as before. The
rest are compile tested only.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
2007-04-17 18:44:08 +04:00
rc = scc_reset_controller ( host ) ;
2007-01-26 10:28:18 +03:00
if ( rc )
return rc ;
rc = pci_set_dma_mask ( pdev , ATA_DMA_MASK ) ;
if ( rc )
return rc ;
rc = pci_set_consistent_dma_mask ( pdev , ATA_DMA_MASK ) ;
if ( rc )
return rc ;
libata: convert the remaining PATA drivers to new init model
Convert pdc_adma, pata_cs5520, pata_isapnp, pata_ixp4xx_cf,
pata_legacy, pata_mpc52xx, pata_mpiix, pata_pcmcia, pata_pdc2027x,
pata_platform, pata_qdi, pata_scc and pata_winbond to new init model.
* init_one()'s now follow more consistent init order
* cs5520 now registers one host with two ports, not two hosts. If any
of the two ports are disabled, it's made dummy as other drivers do.
Tested pdc_adma and pata_legacy. Both are as broken as before. The
rest are compile tested only.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
2007-04-17 18:44:08 +04:00
scc_setup_ports ( & host - > ports [ 0 ] - > ioaddr , host - > iomap [ SCC_BMID_BAR ] ) ;
2007-01-26 10:28:18 +03:00
pci_set_master ( pdev ) ;
return 0 ;
}
/**
* scc_init_one - Register SCC PATA device with kernel services
* @ pdev : PCI device to register
* @ ent : Entry in scc_pci_tbl matching with @ pdev
*
* LOCKING :
* Inherited from PCI layer ( may sleep ) .
*
* RETURNS :
* Zero on success , or - ERRNO value .
*/
static int scc_init_one ( struct pci_dev * pdev , const struct pci_device_id * ent )
{
static int printed_version ;
unsigned int board_idx = ( unsigned int ) ent - > driver_data ;
libata: convert the remaining PATA drivers to new init model
Convert pdc_adma, pata_cs5520, pata_isapnp, pata_ixp4xx_cf,
pata_legacy, pata_mpc52xx, pata_mpiix, pata_pcmcia, pata_pdc2027x,
pata_platform, pata_qdi, pata_scc and pata_winbond to new init model.
* init_one()'s now follow more consistent init order
* cs5520 now registers one host with two ports, not two hosts. If any
of the two ports are disabled, it's made dummy as other drivers do.
Tested pdc_adma and pata_legacy. Both are as broken as before. The
rest are compile tested only.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
2007-04-17 18:44:08 +04:00
const struct ata_port_info * ppi [ ] = { & scc_port_info [ board_idx ] , NULL } ;
2007-05-03 23:44:59 +04:00
struct ata_host * host ;
2007-01-26 10:28:18 +03:00
int rc ;
if ( ! printed_version + + )
dev_printk ( KERN_DEBUG , & pdev - > dev ,
" version " DRV_VERSION " \n " ) ;
2007-05-03 23:44:59 +04:00
host = ata_host_alloc_pinfo ( & pdev - > dev , ppi , 1 ) ;
libata: convert the remaining PATA drivers to new init model
Convert pdc_adma, pata_cs5520, pata_isapnp, pata_ixp4xx_cf,
pata_legacy, pata_mpc52xx, pata_mpiix, pata_pcmcia, pata_pdc2027x,
pata_platform, pata_qdi, pata_scc and pata_winbond to new init model.
* init_one()'s now follow more consistent init order
* cs5520 now registers one host with two ports, not two hosts. If any
of the two ports are disabled, it's made dummy as other drivers do.
Tested pdc_adma and pata_legacy. Both are as broken as before. The
rest are compile tested only.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
2007-04-17 18:44:08 +04:00
if ( ! host )
return - ENOMEM ;
2007-01-26 10:28:18 +03:00
rc = pcim_enable_device ( pdev ) ;
if ( rc )
return rc ;
rc = pcim_iomap_regions ( pdev , ( 1 < < SCC_CTRL_BAR ) | ( 1 < < SCC_BMID_BAR ) , DRV_NAME ) ;
if ( rc = = - EBUSY )
pcim_pin_device ( pdev ) ;
if ( rc )
return rc ;
libata: convert the remaining PATA drivers to new init model
Convert pdc_adma, pata_cs5520, pata_isapnp, pata_ixp4xx_cf,
pata_legacy, pata_mpc52xx, pata_mpiix, pata_pcmcia, pata_pdc2027x,
pata_platform, pata_qdi, pata_scc and pata_winbond to new init model.
* init_one()'s now follow more consistent init order
* cs5520 now registers one host with two ports, not two hosts. If any
of the two ports are disabled, it's made dummy as other drivers do.
Tested pdc_adma and pata_legacy. Both are as broken as before. The
rest are compile tested only.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
2007-04-17 18:44:08 +04:00
host - > iomap = pcim_iomap_table ( pdev ) ;
2007-01-26 10:28:18 +03:00
2007-08-18 08:14:55 +04:00
ata_port_pbar_desc ( host - > ports [ 0 ] , SCC_CTRL_BAR , - 1 , " ctrl " ) ;
ata_port_pbar_desc ( host - > ports [ 0 ] , SCC_BMID_BAR , - 1 , " bmid " ) ;
libata: convert the remaining PATA drivers to new init model
Convert pdc_adma, pata_cs5520, pata_isapnp, pata_ixp4xx_cf,
pata_legacy, pata_mpc52xx, pata_mpiix, pata_pcmcia, pata_pdc2027x,
pata_platform, pata_qdi, pata_scc and pata_winbond to new init model.
* init_one()'s now follow more consistent init order
* cs5520 now registers one host with two ports, not two hosts. If any
of the two ports are disabled, it's made dummy as other drivers do.
Tested pdc_adma and pata_legacy. Both are as broken as before. The
rest are compile tested only.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
2007-04-17 18:44:08 +04:00
rc = scc_host_init ( host ) ;
2007-01-26 10:28:18 +03:00
if ( rc )
return rc ;
libata: convert the remaining PATA drivers to new init model
Convert pdc_adma, pata_cs5520, pata_isapnp, pata_ixp4xx_cf,
pata_legacy, pata_mpc52xx, pata_mpiix, pata_pcmcia, pata_pdc2027x,
pata_platform, pata_qdi, pata_scc and pata_winbond to new init model.
* init_one()'s now follow more consistent init order
* cs5520 now registers one host with two ports, not two hosts. If any
of the two ports are disabled, it's made dummy as other drivers do.
Tested pdc_adma and pata_legacy. Both are as broken as before. The
rest are compile tested only.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
2007-04-17 18:44:08 +04:00
return ata_host_activate ( host , pdev - > irq , ata_interrupt , IRQF_SHARED ,
& scc_sht ) ;
2007-01-26 10:28:18 +03:00
}
static struct pci_driver scc_pci_driver = {
. name = DRV_NAME ,
. id_table = scc_pci_tbl ,
. probe = scc_init_one ,
. remove = ata_pci_remove_one ,
# ifdef CONFIG_PM
. suspend = ata_pci_device_suspend ,
. resume = ata_pci_device_resume ,
# endif
} ;
static int __init scc_init ( void )
{
int rc ;
DPRINTK ( " pci_register_driver \n " ) ;
rc = pci_register_driver ( & scc_pci_driver ) ;
if ( rc )
return rc ;
DPRINTK ( " done \n " ) ;
return 0 ;
}
static void __exit scc_exit ( void )
{
pci_unregister_driver ( & scc_pci_driver ) ;
}
module_init ( scc_init ) ;
module_exit ( scc_exit ) ;
MODULE_AUTHOR ( " Toshiba corp " ) ;
MODULE_DESCRIPTION ( " SCSI low-level driver for Toshiba SCC PATA controller " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DEVICE_TABLE ( pci , scc_pci_tbl ) ;
MODULE_VERSION ( DRV_VERSION ) ;