2007-04-27 08:19:23 +04:00
/* sun_esp.c: ESP front-end for Sparc SBUS systems.
*
2008-08-28 04:01:57 +04:00
* Copyright ( C ) 2007 , 2008 David S . Miller ( davem @ davemloft . net )
2007-04-27 08:19:23 +04:00
*/
# include <linux/kernel.h>
# include <linux/types.h>
2007-04-30 03:12:29 +04:00
# include <linux/delay.h>
2007-04-27 08:19:23 +04:00
# include <linux/module.h>
2008-07-24 08:28:13 +04:00
# include <linux/mm.h>
2007-04-27 08:19:23 +04:00
# include <linux/init.h>
2008-08-28 05:09:11 +04:00
# include <linux/dma-mapping.h>
2008-08-27 11:20:58 +04:00
# include <linux/of.h>
# include <linux/of_device.h>
2007-04-27 08:19:23 +04:00
# include <asm/irq.h>
# include <asm/io.h>
# include <asm/dma.h>
# include <scsi/scsi_host.h>
# include "esp_scsi.h"
# define DRV_MODULE_NAME "sun_esp"
# define PFX DRV_MODULE_NAME ": "
2008-08-27 11:20:58 +04:00
# define DRV_VERSION "1.100"
# define DRV_MODULE_RELDATE "August 27, 2008"
2007-04-27 08:19:23 +04:00
# define dma_read32(REG) \
sbus_readl ( esp - > dma_regs + ( REG ) )
# define dma_write32(VAL, REG) \
sbus_writel ( ( VAL ) , esp - > dma_regs + ( REG ) )
2008-08-28 04:01:57 +04:00
/* DVMA chip revisions */
enum dvma_rev {
dvmarev0 ,
dvmaesc1 ,
dvmarev1 ,
dvmarev2 ,
dvmarev3 ,
dvmarevplus ,
dvmahme
} ;
2007-04-27 08:19:23 +04:00
2008-08-28 04:01:57 +04:00
static int __devinit esp_sbus_setup_dma ( struct esp * esp ,
struct of_device * dma_of )
{
esp - > dma = dma_of ;
2007-04-27 08:19:23 +04:00
2008-08-28 04:01:57 +04:00
esp - > dma_regs = of_ioremap ( & dma_of - > resource [ 0 ] , 0 ,
resource_size ( & dma_of - > resource [ 0 ] ) ,
" espdma " ) ;
if ( ! esp - > dma_regs )
return - ENOMEM ;
2007-04-27 08:19:23 +04:00
2008-08-28 04:01:57 +04:00
switch ( dma_read32 ( DMA_CSR ) & DMA_DEVICE_ID ) {
case DMA_VERS0 :
esp - > dmarev = dvmarev0 ;
break ;
case DMA_ESCV1 :
esp - > dmarev = dvmaesc1 ;
break ;
case DMA_VERS1 :
esp - > dmarev = dvmarev1 ;
break ;
case DMA_VERS2 :
esp - > dmarev = dvmarev2 ;
break ;
case DMA_VERHME :
esp - > dmarev = dvmahme ;
break ;
case DMA_VERSPLUS :
esp - > dmarev = dvmarevplus ;
break ;
2007-04-27 08:19:23 +04:00
}
return 0 ;
}
static int __devinit esp_sbus_map_regs ( struct esp * esp , int hme )
{
2008-08-27 11:20:58 +04:00
struct of_device * op = esp - > dev ;
2007-04-27 08:19:23 +04:00
struct resource * res ;
/* On HME, two reg sets exist, first is DVMA,
* second is ESP registers .
*/
if ( hme )
2008-08-27 11:20:58 +04:00
res = & op - > resource [ 1 ] ;
2007-04-27 08:19:23 +04:00
else
2008-08-27 11:20:58 +04:00
res = & op - > resource [ 0 ] ;
2007-04-27 08:19:23 +04:00
2008-08-27 11:20:58 +04:00
esp - > regs = of_ioremap ( res , 0 , SBUS_ESP_REG_SIZE , " ESP " ) ;
2007-04-27 08:19:23 +04:00
if ( ! esp - > regs )
return - ENOMEM ;
return 0 ;
}
static int __devinit esp_sbus_map_command_block ( struct esp * esp )
{
2008-08-27 11:20:58 +04:00
struct of_device * op = esp - > dev ;
2007-04-27 08:19:23 +04:00
2008-08-27 11:20:58 +04:00
esp - > command_block = dma_alloc_coherent ( & op - > dev , 16 ,
2008-08-28 05:09:11 +04:00
& esp - > command_block_dma ,
GFP_ATOMIC ) ;
2007-04-27 08:19:23 +04:00
if ( ! esp - > command_block )
return - ENOMEM ;
return 0 ;
}
static int __devinit esp_sbus_register_irq ( struct esp * esp )
{
struct Scsi_Host * host = esp - > host ;
2008-08-27 11:20:58 +04:00
struct of_device * op = esp - > dev ;
2007-04-27 08:19:23 +04:00
2008-08-27 11:20:58 +04:00
host - > irq = op - > irqs [ 0 ] ;
2007-04-27 08:19:23 +04:00
return request_irq ( host - > irq , scsi_esp_intr , IRQF_SHARED , " ESP " , esp ) ;
}
2008-08-27 11:20:58 +04:00
static void __devinit esp_get_scsi_id ( struct esp * esp , struct of_device * espdma )
2007-04-27 08:19:23 +04:00
{
2008-08-27 11:20:58 +04:00
struct of_device * op = esp - > dev ;
struct device_node * dp ;
2007-04-27 08:19:23 +04:00
2008-08-27 11:20:58 +04:00
dp = op - > node ;
2007-04-27 08:19:23 +04:00
esp - > scsi_id = of_getintprop_default ( dp , " initiator-id " , 0xff ) ;
if ( esp - > scsi_id ! = 0xff )
goto done ;
esp - > scsi_id = of_getintprop_default ( dp , " scsi-initiator-id " , 0xff ) ;
if ( esp - > scsi_id ! = 0xff )
goto done ;
2008-08-27 11:20:58 +04:00
esp - > scsi_id = of_getintprop_default ( espdma - > node ,
2007-04-27 08:19:23 +04:00
" scsi-initiator-id " , 7 ) ;
done :
esp - > host - > this_id = esp - > scsi_id ;
esp - > scsi_id_mask = ( 1 < < esp - > scsi_id ) ;
}
static void __devinit esp_get_differential ( struct esp * esp )
{
2008-08-27 11:20:58 +04:00
struct of_device * op = esp - > dev ;
struct device_node * dp ;
2007-04-27 08:19:23 +04:00
2008-08-27 11:20:58 +04:00
dp = op - > node ;
2007-04-27 08:19:23 +04:00
if ( of_find_property ( dp , " differential " , NULL ) )
esp - > flags | = ESP_FLAG_DIFFERENTIAL ;
else
esp - > flags & = ~ ESP_FLAG_DIFFERENTIAL ;
}
static void __devinit esp_get_clock_params ( struct esp * esp )
{
2008-08-27 11:20:58 +04:00
struct of_device * op = esp - > dev ;
struct device_node * bus_dp , * dp ;
2007-04-27 08:19:23 +04:00
int fmhz ;
2008-08-27 11:20:58 +04:00
dp = op - > node ;
bus_dp = dp - > parent ;
2007-04-27 08:19:23 +04:00
fmhz = of_getintprop_default ( dp , " clock-frequency " , 0 ) ;
if ( fmhz = = 0 )
2008-08-27 11:20:58 +04:00
fmhz = of_getintprop_default ( bus_dp , " clock-frequency " , 0 ) ;
2007-04-27 08:19:23 +04:00
esp - > cfreq = fmhz ;
}
2008-08-28 04:01:57 +04:00
static void __devinit esp_get_bursts ( struct esp * esp , struct of_device * dma_of )
2007-04-27 08:19:23 +04:00
{
2008-08-28 04:01:57 +04:00
struct device_node * dma_dp = dma_of - > node ;
2008-08-27 11:20:58 +04:00
struct of_device * op = esp - > dev ;
2008-08-28 04:01:57 +04:00
struct device_node * dp ;
u8 bursts , val ;
2007-04-27 08:19:23 +04:00
2008-08-27 11:20:58 +04:00
dp = op - > node ;
2007-04-27 08:19:23 +04:00
bursts = of_getintprop_default ( dp , " burst-sizes " , 0xff ) ;
2008-08-28 04:01:57 +04:00
val = of_getintprop_default ( dma_dp , " burst-sizes " , 0xff ) ;
if ( val ! = 0xff )
bursts & = val ;
2007-04-27 08:19:23 +04:00
2008-08-27 11:20:58 +04:00
val = of_getintprop_default ( dma_dp - > parent , " burst-sizes " , 0xff ) ;
if ( val ! = 0xff )
bursts & = val ;
2007-04-27 08:19:23 +04:00
if ( bursts = = 0xff | |
( bursts & DMA_BURST16 ) = = 0 | |
( bursts & DMA_BURST32 ) = = 0 )
bursts = ( DMA_BURST32 - 1 ) ;
esp - > bursts = bursts ;
}
2008-08-28 04:01:57 +04:00
static void __devinit esp_sbus_get_props ( struct esp * esp , struct of_device * espdma )
2007-04-27 08:19:23 +04:00
{
2008-08-27 11:20:58 +04:00
esp_get_scsi_id ( esp , espdma ) ;
2007-04-27 08:19:23 +04:00
esp_get_differential ( esp ) ;
esp_get_clock_params ( esp ) ;
esp_get_bursts ( esp , espdma ) ;
}
static void sbus_esp_write8 ( struct esp * esp , u8 val , unsigned long reg )
{
sbus_writeb ( val , esp - > regs + ( reg * 4UL ) ) ;
}
static u8 sbus_esp_read8 ( struct esp * esp , unsigned long reg )
{
return sbus_readb ( esp - > regs + ( reg * 4UL ) ) ;
}
static dma_addr_t sbus_esp_map_single ( struct esp * esp , void * buf ,
size_t sz , int dir )
{
2008-08-27 11:20:58 +04:00
struct of_device * op = esp - > dev ;
2008-08-28 05:37:58 +04:00
2008-08-27 11:20:58 +04:00
return dma_map_single ( & op - > dev , buf , sz , dir ) ;
2007-04-27 08:19:23 +04:00
}
static int sbus_esp_map_sg ( struct esp * esp , struct scatterlist * sg ,
int num_sg , int dir )
{
2008-08-27 11:20:58 +04:00
struct of_device * op = esp - > dev ;
2008-08-28 05:37:58 +04:00
2008-08-27 11:20:58 +04:00
return dma_map_sg ( & op - > dev , sg , num_sg , dir ) ;
2007-04-27 08:19:23 +04:00
}
static void sbus_esp_unmap_single ( struct esp * esp , dma_addr_t addr ,
size_t sz , int dir )
{
2008-08-27 11:20:58 +04:00
struct of_device * op = esp - > dev ;
2008-08-28 05:37:58 +04:00
2008-08-27 11:20:58 +04:00
dma_unmap_single ( & op - > dev , addr , sz , dir ) ;
2007-04-27 08:19:23 +04:00
}
static void sbus_esp_unmap_sg ( struct esp * esp , struct scatterlist * sg ,
int num_sg , int dir )
{
2008-08-27 11:20:58 +04:00
struct of_device * op = esp - > dev ;
2008-08-28 05:37:58 +04:00
2008-08-27 11:20:58 +04:00
dma_unmap_sg ( & op - > dev , sg , num_sg , dir ) ;
2007-04-27 08:19:23 +04:00
}
static int sbus_esp_irq_pending ( struct esp * esp )
{
if ( dma_read32 ( DMA_CSR ) & ( DMA_HNDL_INTR | DMA_HNDL_ERROR ) )
return 1 ;
return 0 ;
}
static void sbus_esp_reset_dma ( struct esp * esp )
{
int can_do_burst16 , can_do_burst32 , can_do_burst64 ;
int can_do_sbus64 , lim ;
2008-08-27 11:20:58 +04:00
struct of_device * op ;
2007-04-27 08:19:23 +04:00
u32 val ;
can_do_burst16 = ( esp - > bursts & DMA_BURST16 ) ! = 0 ;
can_do_burst32 = ( esp - > bursts & DMA_BURST32 ) ! = 0 ;
can_do_burst64 = 0 ;
can_do_sbus64 = 0 ;
2008-08-27 11:20:58 +04:00
op = esp - > dev ;
2008-08-27 10:33:42 +04:00
if ( sbus_can_dma_64bit ( ) )
2007-04-27 08:19:23 +04:00
can_do_sbus64 = 1 ;
2008-08-27 10:33:42 +04:00
if ( sbus_can_burst64 ( ) )
2007-04-27 08:19:23 +04:00
can_do_burst64 = ( esp - > bursts & DMA_BURST64 ) ! = 0 ;
/* Put the DVMA into a known state. */
2008-08-28 04:01:57 +04:00
if ( esp - > dmarev ! = dvmahme ) {
2007-04-27 08:19:23 +04:00
val = dma_read32 ( DMA_CSR ) ;
dma_write32 ( val | DMA_RST_SCSI , DMA_CSR ) ;
dma_write32 ( val & ~ DMA_RST_SCSI , DMA_CSR ) ;
}
2008-08-28 04:01:57 +04:00
switch ( esp - > dmarev ) {
2007-04-27 08:19:23 +04:00
case dvmahme :
dma_write32 ( DMA_RESET_FAS366 , DMA_CSR ) ;
dma_write32 ( DMA_RST_SCSI , DMA_CSR ) ;
esp - > prev_hme_dmacsr = ( DMA_PARITY_OFF | DMA_2CLKS |
DMA_SCSI_DISAB | DMA_INT_ENAB ) ;
esp - > prev_hme_dmacsr & = ~ ( DMA_ENABLE | DMA_ST_WRITE |
DMA_BRST_SZ ) ;
if ( can_do_burst64 )
esp - > prev_hme_dmacsr | = DMA_BRST64 ;
else if ( can_do_burst32 )
esp - > prev_hme_dmacsr | = DMA_BRST32 ;
if ( can_do_sbus64 ) {
esp - > prev_hme_dmacsr | = DMA_SCSI_SBUS64 ;
2008-08-27 11:20:58 +04:00
sbus_set_sbus64 ( & op - > dev , esp - > bursts ) ;
2007-04-27 08:19:23 +04:00
}
lim = 1000 ;
while ( dma_read32 ( DMA_CSR ) & DMA_PEND_READ ) {
if ( - - lim = = 0 ) {
printk ( KERN_ALERT PFX " esp%d: DMA_PEND_READ "
" will not clear! \n " ,
esp - > host - > unique_id ) ;
break ;
}
udelay ( 1 ) ;
}
dma_write32 ( 0 , DMA_CSR ) ;
dma_write32 ( esp - > prev_hme_dmacsr , DMA_CSR ) ;
dma_write32 ( 0 , DMA_ADDR ) ;
break ;
case dvmarev2 :
if ( esp - > rev ! = ESP100 ) {
val = dma_read32 ( DMA_CSR ) ;
dma_write32 ( val | DMA_3CLKS , DMA_CSR ) ;
}
break ;
case dvmarev3 :
val = dma_read32 ( DMA_CSR ) ;
val & = ~ DMA_3CLKS ;
val | = DMA_2CLKS ;
if ( can_do_burst32 ) {
val & = ~ DMA_BRST_SZ ;
val | = DMA_BRST32 ;
}
dma_write32 ( val , DMA_CSR ) ;
break ;
case dvmaesc1 :
val = dma_read32 ( DMA_CSR ) ;
val | = DMA_ADD_ENABLE ;
val & = ~ DMA_BCNT_ENAB ;
if ( ! can_do_burst32 & & can_do_burst16 ) {
val | = DMA_ESC_BURST ;
} else {
val & = ~ ( DMA_ESC_BURST ) ;
}
dma_write32 ( val , DMA_CSR ) ;
break ;
default :
break ;
}
/* Enable interrupts. */
val = dma_read32 ( DMA_CSR ) ;
dma_write32 ( val | DMA_INT_ENAB , DMA_CSR ) ;
}
static void sbus_esp_dma_drain ( struct esp * esp )
{
u32 csr ;
int lim ;
2008-08-28 04:01:57 +04:00
if ( esp - > dmarev = = dvmahme )
2007-04-27 08:19:23 +04:00
return ;
csr = dma_read32 ( DMA_CSR ) ;
if ( ! ( csr & DMA_FIFO_ISDRAIN ) )
return ;
2008-08-28 04:01:57 +04:00
if ( esp - > dmarev ! = dvmarev3 & & esp - > dmarev ! = dvmaesc1 )
2007-04-27 08:19:23 +04:00
dma_write32 ( csr | DMA_FIFO_STDRAIN , DMA_CSR ) ;
lim = 1000 ;
while ( dma_read32 ( DMA_CSR ) & DMA_FIFO_ISDRAIN ) {
if ( - - lim = = 0 ) {
printk ( KERN_ALERT PFX " esp%d: DMA will not drain! \n " ,
esp - > host - > unique_id ) ;
break ;
}
udelay ( 1 ) ;
}
}
static void sbus_esp_dma_invalidate ( struct esp * esp )
{
2008-08-28 04:01:57 +04:00
if ( esp - > dmarev = = dvmahme ) {
2007-04-27 08:19:23 +04:00
dma_write32 ( DMA_RST_SCSI , DMA_CSR ) ;
esp - > prev_hme_dmacsr = ( ( esp - > prev_hme_dmacsr |
( DMA_PARITY_OFF | DMA_2CLKS |
DMA_SCSI_DISAB | DMA_INT_ENAB ) ) &
~ ( DMA_ST_WRITE | DMA_ENABLE ) ) ;
dma_write32 ( 0 , DMA_CSR ) ;
dma_write32 ( esp - > prev_hme_dmacsr , DMA_CSR ) ;
/* This is necessary to avoid having the SCSI channel
* engine lock up on us .
*/
dma_write32 ( 0 , DMA_ADDR ) ;
} else {
u32 val ;
int lim ;
lim = 1000 ;
while ( ( val = dma_read32 ( DMA_CSR ) ) & DMA_PEND_READ ) {
if ( - - lim = = 0 ) {
printk ( KERN_ALERT PFX " esp%d: DMA will not "
" invalidate! \n " , esp - > host - > unique_id ) ;
break ;
}
udelay ( 1 ) ;
}
val & = ~ ( DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB ) ;
val | = DMA_FIFO_INV ;
dma_write32 ( val , DMA_CSR ) ;
val & = ~ DMA_FIFO_INV ;
dma_write32 ( val , DMA_CSR ) ;
}
}
static void sbus_esp_send_dma_cmd ( struct esp * esp , u32 addr , u32 esp_count ,
u32 dma_count , int write , u8 cmd )
{
u32 csr ;
BUG_ON ( ! ( cmd & ESP_CMD_DMA ) ) ;
sbus_esp_write8 ( esp , ( esp_count > > 0 ) & 0xff , ESP_TCLOW ) ;
sbus_esp_write8 ( esp , ( esp_count > > 8 ) & 0xff , ESP_TCMED ) ;
if ( esp - > rev = = FASHME ) {
sbus_esp_write8 ( esp , ( esp_count > > 16 ) & 0xff , FAS_RLO ) ;
sbus_esp_write8 ( esp , 0 , FAS_RHI ) ;
scsi_esp_cmd ( esp , cmd ) ;
csr = esp - > prev_hme_dmacsr ;
csr | = DMA_SCSI_DISAB | DMA_ENABLE ;
if ( write )
csr | = DMA_ST_WRITE ;
else
csr & = ~ DMA_ST_WRITE ;
esp - > prev_hme_dmacsr = csr ;
dma_write32 ( dma_count , DMA_COUNT ) ;
dma_write32 ( addr , DMA_ADDR ) ;
dma_write32 ( csr , DMA_CSR ) ;
} else {
csr = dma_read32 ( DMA_CSR ) ;
csr | = DMA_ENABLE ;
if ( write )
csr | = DMA_ST_WRITE ;
else
csr & = ~ DMA_ST_WRITE ;
dma_write32 ( csr , DMA_CSR ) ;
2008-08-28 04:01:57 +04:00
if ( esp - > dmarev = = dvmaesc1 ) {
2007-04-27 08:19:23 +04:00
u32 end = PAGE_ALIGN ( addr + dma_count + 16U ) ;
dma_write32 ( end - addr , DMA_COUNT ) ;
}
dma_write32 ( addr , DMA_ADDR ) ;
scsi_esp_cmd ( esp , cmd ) ;
}
}
static int sbus_esp_dma_error ( struct esp * esp )
{
u32 csr = dma_read32 ( DMA_CSR ) ;
if ( csr & DMA_HNDL_ERROR )
return 1 ;
return 0 ;
}
static const struct esp_driver_ops sbus_esp_ops = {
. esp_write8 = sbus_esp_write8 ,
. esp_read8 = sbus_esp_read8 ,
. map_single = sbus_esp_map_single ,
. map_sg = sbus_esp_map_sg ,
. unmap_single = sbus_esp_unmap_single ,
. unmap_sg = sbus_esp_unmap_sg ,
. irq_pending = sbus_esp_irq_pending ,
. reset_dma = sbus_esp_reset_dma ,
. dma_drain = sbus_esp_dma_drain ,
. dma_invalidate = sbus_esp_dma_invalidate ,
. send_dma_cmd = sbus_esp_send_dma_cmd ,
. dma_error = sbus_esp_dma_error ,
} ;
2008-08-27 11:20:58 +04:00
static int __devinit esp_sbus_probe_one ( struct of_device * op ,
2008-08-28 04:01:57 +04:00
struct of_device * espdma ,
2007-04-27 08:19:23 +04:00
int hme )
{
struct scsi_host_template * tpnt = & scsi_esp_template ;
struct Scsi_Host * host ;
struct esp * esp ;
int err ;
host = scsi_host_alloc ( tpnt , sizeof ( struct esp ) ) ;
err = - ENOMEM ;
if ( ! host )
goto fail ;
host - > max_id = ( hme ? 16 : 8 ) ;
2007-05-31 22:12:32 +04:00
esp = shost_priv ( host ) ;
2007-04-27 08:19:23 +04:00
esp - > host = host ;
2008-08-27 11:20:58 +04:00
esp - > dev = op ;
2007-04-27 08:19:23 +04:00
esp - > ops = & sbus_esp_ops ;
if ( hme )
esp - > flags | = ESP_FLAG_WIDE_CAPABLE ;
2008-08-28 04:01:57 +04:00
err = esp_sbus_setup_dma ( esp , espdma ) ;
2007-04-27 08:19:23 +04:00
if ( err < 0 )
goto fail_unlink ;
err = esp_sbus_map_regs ( esp , hme ) ;
if ( err < 0 )
goto fail_unlink ;
err = esp_sbus_map_command_block ( esp ) ;
if ( err < 0 )
goto fail_unmap_regs ;
err = esp_sbus_register_irq ( esp ) ;
if ( err < 0 )
goto fail_unmap_command_block ;
esp_sbus_get_props ( esp , espdma ) ;
/* Before we try to touch the ESP chip, ESC1 dma can
* come up with the reset bit set , so make sure that
* is clear first .
*/
2008-08-28 04:01:57 +04:00
if ( esp - > dmarev = = dvmaesc1 ) {
2007-04-27 08:19:23 +04:00
u32 val = dma_read32 ( DMA_CSR ) ;
dma_write32 ( val & ~ DMA_RST_SCSI , DMA_CSR ) ;
}
2008-08-27 11:20:58 +04:00
dev_set_drvdata ( & op - > dev , esp ) ;
2007-04-27 08:19:23 +04:00
2008-08-27 11:20:58 +04:00
err = scsi_esp_register ( esp , & op - > dev ) ;
2007-04-27 08:19:23 +04:00
if ( err )
goto fail_free_irq ;
return 0 ;
fail_free_irq :
free_irq ( host - > irq , esp ) ;
fail_unmap_command_block :
2008-08-27 11:20:58 +04:00
dma_free_coherent ( & op - > dev , 16 ,
2008-08-28 05:09:11 +04:00
esp - > command_block ,
esp - > command_block_dma ) ;
2007-04-27 08:19:23 +04:00
fail_unmap_regs :
2008-08-27 11:20:58 +04:00
of_iounmap ( & op - > resource [ ( hme ? 1 : 0 ) ] , esp - > regs , SBUS_ESP_REG_SIZE ) ;
2007-04-27 08:19:23 +04:00
fail_unlink :
scsi_host_put ( host ) ;
fail :
return err ;
}
2008-08-27 11:20:58 +04:00
static int __devinit esp_sbus_probe ( struct of_device * op , const struct of_device_id * match )
2007-04-27 08:19:23 +04:00
{
2008-08-28 04:01:57 +04:00
struct device_node * dma_node = NULL ;
2008-08-27 11:20:58 +04:00
struct device_node * dp = op - > node ;
2008-08-28 04:01:57 +04:00
struct of_device * dma_of = NULL ;
2007-04-27 08:19:23 +04:00
int hme = 0 ;
if ( dp - > parent & &
( ! strcmp ( dp - > parent - > name , " espdma " ) | |
! strcmp ( dp - > parent - > name , " dma " ) ) )
2008-08-28 04:01:57 +04:00
dma_node = dp - > parent ;
2007-04-27 08:19:23 +04:00
else if ( ! strcmp ( dp - > name , " SUNW,fas " ) ) {
2008-08-27 11:20:58 +04:00
dma_node = op - > node ;
2007-04-27 08:19:23 +04:00
hme = 1 ;
}
2008-08-28 04:01:57 +04:00
if ( dma_node )
dma_of = of_find_device_by_node ( dma_node ) ;
if ( ! dma_of )
return - ENODEV ;
2007-04-27 08:19:23 +04:00
2008-08-27 11:20:58 +04:00
return esp_sbus_probe_one ( op , dma_of , hme ) ;
2007-04-27 08:19:23 +04:00
}
2008-08-27 11:20:58 +04:00
static int __devexit esp_sbus_remove ( struct of_device * op )
2007-04-27 08:19:23 +04:00
{
2008-08-27 11:20:58 +04:00
struct esp * esp = dev_get_drvdata ( & op - > dev ) ;
2008-08-28 04:01:57 +04:00
struct of_device * dma_of = esp - > dma ;
2007-04-27 08:19:23 +04:00
unsigned int irq = esp - > host - > irq ;
2008-08-27 11:20:58 +04:00
bool is_hme ;
2007-04-27 08:19:23 +04:00
u32 val ;
scsi_esp_unregister ( esp ) ;
/* Disable interrupts. */
val = dma_read32 ( DMA_CSR ) ;
dma_write32 ( val & ~ DMA_INT_ENAB , DMA_CSR ) ;
free_irq ( irq , esp ) ;
2008-08-27 11:20:58 +04:00
is_hme = ( esp - > dmarev = = dvmahme ) ;
dma_free_coherent ( & op - > dev , 16 ,
2008-08-28 05:09:11 +04:00
esp - > command_block ,
esp - > command_block_dma ) ;
2008-08-27 11:20:58 +04:00
of_iounmap ( & op - > resource [ ( is_hme ? 1 : 0 ) ] , esp - > regs ,
SBUS_ESP_REG_SIZE ) ;
2008-08-28 04:01:57 +04:00
of_iounmap ( & dma_of - > resource [ 0 ] , esp - > dma_regs ,
resource_size ( & dma_of - > resource [ 0 ] ) ) ;
2007-04-27 08:19:23 +04:00
scsi_host_put ( esp - > host ) ;
2008-08-27 11:20:58 +04:00
dev_set_drvdata ( & op - > dev , NULL ) ;
2007-04-27 08:19:23 +04:00
return 0 ;
}
2008-08-31 12:23:17 +04:00
static const struct of_device_id esp_match [ ] = {
2007-04-27 08:19:23 +04:00
{
. name = " SUNW,esp " ,
} ,
{
. name = " SUNW,fas " ,
} ,
{
. name = " esp " ,
} ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , esp_match ) ;
static struct of_platform_driver esp_sbus_driver = {
. name = " esp " ,
. match_table = esp_match ,
. probe = esp_sbus_probe ,
. remove = __devexit_p ( esp_sbus_remove ) ,
} ;
static int __init sunesp_init ( void )
{
2008-08-27 11:20:58 +04:00
return of_register_driver ( & esp_sbus_driver , & of_bus_type ) ;
2007-04-27 08:19:23 +04:00
}
static void __exit sunesp_exit ( void )
{
of_unregister_driver ( & esp_sbus_driver ) ;
}
MODULE_DESCRIPTION ( " Sun ESP SCSI driver " ) ;
MODULE_AUTHOR ( " David S. Miller (davem@davemloft.net) " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_VERSION ( DRV_VERSION ) ;
module_init ( sunesp_init ) ;
module_exit ( sunesp_exit ) ;