2005-04-17 02:20:36 +04:00
# include <linux/types.h>
# include <linux/init.h>
# include <linux/interrupt.h>
2009-08-16 13:17:35 +04:00
# include <linux/mm.h>
# include <linux/slab.h>
# include <linux/spinlock.h>
# include <linux/zorro.h>
2005-04-17 02:20:36 +04:00
# include <asm/page.h>
# include <asm/pgtable.h>
# include <asm/amigaints.h>
# include <asm/amigahw.h>
# include "scsi.h"
# include "wd33c93.h"
# include "a2091.h"
2009-03-04 23:06:07 +03:00
2010-04-12 23:55:03 +04:00
struct a2091_hostdata {
struct WD33C93_hostdata wh ;
struct a2091_scsiregs * regs ;
} ;
2010-04-04 13:00:40 +04:00
static irqreturn_t a2091_intr ( int irq , void * data )
2005-04-17 02:20:36 +04:00
{
2010-04-04 13:00:40 +04:00
struct Scsi_Host * instance = data ;
2010-04-12 23:55:03 +04:00
struct a2091_hostdata * hdata = shost_priv ( instance ) ;
unsigned int status = hdata - > regs - > ISTR ;
2010-04-04 13:00:32 +04:00
unsigned long flags ;
if ( ! ( status & ( ISTR_INT_F | ISTR_INT_P ) ) | | ! ( status & ISTR_INTS ) )
return IRQ_NONE ;
spin_lock_irqsave ( instance - > host_lock , flags ) ;
wd33c93_intr ( instance ) ;
spin_unlock_irqrestore ( instance - > host_lock , flags ) ;
return IRQ_HANDLED ;
2005-04-17 02:20:36 +04:00
}
2006-09-13 01:49:33 +04:00
static int dma_setup ( struct scsi_cmnd * cmd , int dir_in )
2005-04-17 02:20:36 +04:00
{
2010-04-04 13:00:36 +04:00
struct Scsi_Host * instance = cmd - > device - > host ;
2010-04-12 23:55:03 +04:00
struct a2091_hostdata * hdata = shost_priv ( instance ) ;
struct WD33C93_hostdata * wh = & hdata - > wh ;
struct a2091_scsiregs * regs = hdata - > regs ;
2010-04-04 13:00:32 +04:00
unsigned short cntr = CNTR_PDMD | CNTR_INTEN ;
unsigned long addr = virt_to_bus ( cmd - > SCp . ptr ) ;
2005-04-17 02:20:36 +04:00
2010-04-04 13:00:32 +04:00
/* don't allow DMA if the physical address is bad */
2005-04-17 02:20:36 +04:00
if ( addr & A2091_XFER_MASK ) {
2010-04-12 23:55:03 +04:00
wh - > dma_bounce_len = ( cmd - > SCp . this_residual + 511 ) & ~ 0x1ff ;
wh - > dma_bounce_buffer = kmalloc ( wh - > dma_bounce_len ,
GFP_KERNEL ) ;
2010-04-04 13:00:32 +04:00
/* can't allocate memory; use PIO */
2010-04-12 23:55:03 +04:00
if ( ! wh - > dma_bounce_buffer ) {
wh - > dma_bounce_len = 0 ;
2010-04-04 13:00:32 +04:00
return 1 ;
}
/* get the physical address of the bounce buffer */
2010-04-12 23:55:03 +04:00
addr = virt_to_bus ( wh - > dma_bounce_buffer ) ;
2010-04-04 13:00:32 +04:00
/* the bounce buffer may not be in the first 16M of physmem */
if ( addr & A2091_XFER_MASK ) {
/* we could use chipmem... maybe later */
2010-04-12 23:55:03 +04:00
kfree ( wh - > dma_bounce_buffer ) ;
wh - > dma_bounce_buffer = NULL ;
wh - > dma_bounce_len = 0 ;
2010-04-04 13:00:32 +04:00
return 1 ;
}
if ( ! dir_in ) {
/* copy to bounce buffer for a write */
2010-04-12 23:55:03 +04:00
memcpy ( wh - > dma_bounce_buffer , cmd - > SCp . ptr ,
2010-04-04 13:00:36 +04:00
cmd - > SCp . this_residual ) ;
2010-04-04 13:00:32 +04:00
}
2005-04-17 02:20:36 +04:00
}
2010-04-04 13:00:32 +04:00
/* setup dma direction */
if ( ! dir_in )
cntr | = CNTR_DDIR ;
2005-04-17 02:20:36 +04:00
2010-04-04 13:00:32 +04:00
/* remember direction */
2010-04-12 23:55:03 +04:00
wh - > dma_dir = dir_in ;
2005-04-17 02:20:36 +04:00
2010-04-04 13:00:40 +04:00
regs - > CNTR = cntr ;
2005-04-17 02:20:36 +04:00
2010-04-04 13:00:32 +04:00
/* setup DMA *physical* address */
2010-04-04 13:00:40 +04:00
regs - > ACR = addr ;
2005-04-17 02:20:36 +04:00
2010-04-04 13:00:32 +04:00
if ( dir_in ) {
/* invalidate any cache */
cache_clear ( addr , cmd - > SCp . this_residual ) ;
} else {
/* push any dirty cache */
cache_push ( addr , cmd - > SCp . this_residual ) ;
}
/* start DMA */
2010-04-04 13:00:40 +04:00
regs - > ST_DMA = 1 ;
2005-04-17 02:20:36 +04:00
2010-04-04 13:00:32 +04:00
/* return success */
return 0 ;
2005-04-17 02:20:36 +04:00
}
2006-09-13 01:49:33 +04:00
static void dma_stop ( struct Scsi_Host * instance , struct scsi_cmnd * SCpnt ,
2010-04-04 13:00:32 +04:00
int status )
2005-04-17 02:20:36 +04:00
{
2010-04-12 23:55:03 +04:00
struct a2091_hostdata * hdata = shost_priv ( instance ) ;
struct WD33C93_hostdata * wh = & hdata - > wh ;
struct a2091_scsiregs * regs = hdata - > regs ;
2010-04-04 13:00:36 +04:00
2010-04-04 13:00:32 +04:00
/* disable SCSI interrupts */
unsigned short cntr = CNTR_PDMD ;
2010-04-12 23:55:03 +04:00
if ( ! wh - > dma_dir )
2010-04-04 13:00:32 +04:00
cntr | = CNTR_DDIR ;
/* disable SCSI interrupts */
2010-04-04 13:00:40 +04:00
regs - > CNTR = cntr ;
2010-04-04 13:00:32 +04:00
/* flush if we were reading */
2010-04-12 23:55:03 +04:00
if ( wh - > dma_dir ) {
2010-04-04 13:00:40 +04:00
regs - > FLUSH = 1 ;
while ( ! ( regs - > ISTR & ISTR_FE_FLG ) )
2010-04-04 13:00:32 +04:00
;
}
/* clear a possible interrupt */
2010-04-04 13:00:40 +04:00
regs - > CINT = 1 ;
2010-04-04 13:00:32 +04:00
/* stop DMA */
2010-04-04 13:00:40 +04:00
regs - > SP_DMA = 1 ;
2010-04-04 13:00:32 +04:00
/* restore the CONTROL bits (minus the direction flag) */
2010-04-04 13:00:40 +04:00
regs - > CNTR = CNTR_PDMD | CNTR_INTEN ;
2010-04-04 13:00:32 +04:00
/* copy from a bounce buffer, if necessary */
2010-04-12 23:55:03 +04:00
if ( status & & wh - > dma_bounce_buffer ) {
if ( wh - > dma_dir )
memcpy ( SCpnt - > SCp . ptr , wh - > dma_bounce_buffer ,
2010-04-04 13:00:32 +04:00
SCpnt - > SCp . this_residual ) ;
2010-04-12 23:55:03 +04:00
kfree ( wh - > dma_bounce_buffer ) ;
wh - > dma_bounce_buffer = NULL ;
wh - > dma_bounce_len = 0 ;
2010-04-04 13:00:32 +04:00
}
2005-04-17 02:20:36 +04:00
}
2006-09-13 01:49:33 +04:00
static int a2091_bus_reset ( struct scsi_cmnd * cmd )
2005-04-17 02:20:36 +04:00
{
2009-08-16 13:17:35 +04:00
struct Scsi_Host * instance = cmd - > device - > host ;
2005-04-17 02:20:36 +04:00
/* FIXME perform bus-specific reset */
2005-05-28 15:56:31 +04:00
2005-05-28 15:57:14 +04:00
/* FIXME 2: kill this function, and let midlayer fall back
to the same action , calling wd33c93_host_reset ( ) */
2009-08-16 13:17:35 +04:00
spin_lock_irq ( instance - > host_lock ) ;
2005-04-17 02:20:36 +04:00
wd33c93_host_reset ( cmd ) ;
2009-08-16 13:17:35 +04:00
spin_unlock_irq ( instance - > host_lock ) ;
2005-05-28 15:56:31 +04:00
2005-04-17 02:20:36 +04:00
return SUCCESS ;
}
2009-08-16 13:17:35 +04:00
static struct scsi_host_template a2091_scsi_template = {
. module = THIS_MODULE ,
2005-04-17 02:20:36 +04:00
. name = " Commodore A2091/A590 SCSI " ,
2009-08-16 13:17:35 +04:00
. proc_info = wd33c93_proc_info ,
. proc_name = " A2901 " ,
2005-04-17 02:20:36 +04:00
. queuecommand = wd33c93_queuecommand ,
. eh_abort_handler = wd33c93_abort ,
. eh_bus_reset_handler = a2091_bus_reset ,
. eh_host_reset_handler = wd33c93_host_reset ,
. can_queue = CAN_QUEUE ,
. this_id = 7 ,
. sg_tablesize = SG_ALL ,
. cmd_per_lun = CMD_PER_LUN ,
. use_clustering = DISABLE_CLUSTERING
} ;
2009-08-16 13:17:35 +04:00
static int __devinit a2091_probe ( struct zorro_dev * z ,
const struct zorro_device_id * ent )
{
struct Scsi_Host * instance ;
int error ;
struct a2091_scsiregs * regs ;
wd33c93_regs wdregs ;
2010-04-12 23:55:03 +04:00
struct a2091_hostdata * hdata ;
2009-08-16 13:17:35 +04:00
if ( ! request_mem_region ( z - > resource . start , 256 , " wd33c93 " ) )
return - EBUSY ;
instance = scsi_host_alloc ( & a2091_scsi_template ,
2010-04-12 23:55:03 +04:00
sizeof ( struct a2091_hostdata ) ) ;
2009-08-16 13:17:35 +04:00
if ( ! instance ) {
error = - ENOMEM ;
goto fail_alloc ;
}
instance - > irq = IRQ_AMIGA_PORTS ;
instance - > unique_id = z - > slotaddr ;
2010-04-12 23:55:03 +04:00
regs = ( struct a2091_scsiregs * ) ZTWO_VADDR ( z - > resource . start ) ;
2009-08-16 13:17:35 +04:00
regs - > DAWR = DAWR_A2091 ;
wdregs . SASR = & regs - > SASR ;
wdregs . SCMD = & regs - > SCMD ;
2005-04-17 02:20:36 +04:00
2009-08-16 13:17:35 +04:00
hdata = shost_priv ( instance ) ;
2010-04-12 23:55:03 +04:00
hdata - > wh . no_sync = 0xff ;
hdata - > wh . fast = 0 ;
hdata - > wh . dma_mode = CTRL_DMA ;
hdata - > regs = regs ;
2009-08-16 13:17:35 +04:00
wd33c93_init ( instance , wdregs , dma_setup , dma_stop , WD33C93_FS_8_10 ) ;
error = request_irq ( IRQ_AMIGA_PORTS , a2091_intr , IRQF_SHARED ,
" A2091 SCSI " , instance ) ;
if ( error )
goto fail_irq ;
regs - > CNTR = CNTR_PDMD | CNTR_INTEN ;
error = scsi_add_host ( instance , NULL ) ;
if ( error )
goto fail_host ;
zorro_set_drvdata ( z , instance ) ;
scsi_scan_host ( instance ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
2009-08-16 13:17:35 +04:00
fail_host :
free_irq ( IRQ_AMIGA_PORTS , instance ) ;
fail_irq :
scsi_host_put ( instance ) ;
fail_alloc :
release_mem_region ( z - > resource . start , 256 ) ;
return error ;
}
static void __devexit a2091_remove ( struct zorro_dev * z )
2005-04-17 02:20:36 +04:00
{
2009-08-16 13:17:35 +04:00
struct Scsi_Host * instance = zorro_get_drvdata ( z ) ;
2010-04-12 23:55:03 +04:00
struct a2091_hostdata * hdata = shost_priv ( instance ) ;
2010-04-04 13:00:40 +04:00
2010-04-12 23:55:03 +04:00
hdata - > regs - > CNTR = 0 ;
2009-08-16 13:17:35 +04:00
scsi_remove_host ( instance ) ;
2005-04-17 02:20:36 +04:00
free_irq ( IRQ_AMIGA_PORTS , instance ) ;
2009-08-16 13:17:35 +04:00
scsi_host_put ( instance ) ;
release_mem_region ( z - > resource . start , 256 ) ;
}
static struct zorro_device_id a2091_zorro_tbl [ ] __devinitdata = {
{ ZORRO_PROD_CBM_A590_A2091_1 } ,
{ ZORRO_PROD_CBM_A590_A2091_2 } ,
{ 0 }
} ;
MODULE_DEVICE_TABLE ( zorro , a2091_zorro_tbl ) ;
static struct zorro_driver a2091_driver = {
. name = " a2091 " ,
. id_table = a2091_zorro_tbl ,
. probe = a2091_probe ,
. remove = __devexit_p ( a2091_remove ) ,
} ;
static int __init a2091_init ( void )
{
return zorro_register_driver ( & a2091_driver ) ;
}
module_init ( a2091_init ) ;
static void __exit a2091_exit ( void )
{
zorro_unregister_driver ( & a2091_driver ) ;
2005-04-17 02:20:36 +04:00
}
2009-08-16 13:17:35 +04:00
module_exit ( a2091_exit ) ;
2005-04-17 02:20:36 +04:00
2009-08-16 13:17:35 +04:00
MODULE_DESCRIPTION ( " Commodore A2091/A590 SCSI " ) ;
2005-04-17 02:20:36 +04:00
MODULE_LICENSE ( " GPL " ) ;