2005-04-17 02:20:36 +04:00
/*
* Generic Generic NCR5380 driver
*
* Copyright 1995 - 2002 , Russell King
*/
# include <linux/module.h>
# include <linux/ioport.h>
# include <linux/blkdev.h>
# include <linux/init.h>
# include <asm/ecard.h>
# include <asm/io.h>
# include <scsi/scsi_host.h>
2007-07-20 13:38:54 +04:00
# define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata)
2016-01-03 08:05:06 +03:00
# define NCR5380_read(reg) cumanascsi_read(instance, reg)
# define NCR5380_write(reg, value) cumanascsi_write(instance, reg, value)
2016-01-03 08:05:25 +03:00
# define NCR5380_dma_xfer_len(instance, cmd, phase) (cmd->transfersize)
2016-03-23 13:10:17 +03:00
# define NCR5380_dma_recv_setup cumanascsi_pread
# define NCR5380_dma_send_setup cumanascsi_pwrite
2016-01-03 08:05:25 +03:00
2005-04-17 02:20:36 +04:00
# define NCR5380_intr cumanascsi_intr
# define NCR5380_queue_command cumanascsi_queue_command
2014-11-12 08:11:58 +03:00
# define NCR5380_info cumanascsi_info
2005-04-17 02:20:36 +04:00
2007-07-20 13:38:54 +04:00
# define NCR5380_implementation_fields \
unsigned ctrl ; \
void __iomem * base ; \
void __iomem * dma
2005-04-17 02:20:36 +04:00
# include "../NCR5380.h"
void cumanascsi_setup ( char * str , int * ints )
{
}
2007-07-20 13:38:54 +04:00
# define CTRL 0x16fc
# define STAT 0x2004
# define L(v) (((v)<<16)|((v) & 0x0000ffff))
# define H(v) (((v)>>16)|((v) & 0xffff0000))
2005-04-17 02:20:36 +04:00
2016-03-23 13:10:17 +03:00
static inline int cumanascsi_pwrite ( struct Scsi_Host * host ,
unsigned char * addr , int len )
2005-04-17 02:20:36 +04:00
{
unsigned long * laddr ;
2007-07-20 13:38:54 +04:00
void __iomem * dma = priv ( host ) - > dma + 0x2000 ;
2005-04-17 02:20:36 +04:00
if ( ! len ) return 0 ;
2007-07-20 13:38:54 +04:00
writeb ( 0x02 , priv ( host ) - > base + CTRL ) ;
2005-04-17 02:20:36 +04:00
laddr = ( unsigned long * ) addr ;
while ( len > = 32 )
{
2007-07-20 13:38:54 +04:00
unsigned int status ;
2005-04-17 02:20:36 +04:00
unsigned long v ;
2007-07-20 13:38:54 +04:00
status = readb ( priv ( host ) - > base + STAT ) ;
2005-04-17 02:20:36 +04:00
if ( status & 0x80 )
goto end ;
if ( ! ( status & 0x40 ) )
continue ;
2007-07-20 13:38:54 +04:00
v = * laddr + + ; writew ( L ( v ) , dma ) ; writew ( H ( v ) , dma ) ;
v = * laddr + + ; writew ( L ( v ) , dma ) ; writew ( H ( v ) , dma ) ;
v = * laddr + + ; writew ( L ( v ) , dma ) ; writew ( H ( v ) , dma ) ;
v = * laddr + + ; writew ( L ( v ) , dma ) ; writew ( H ( v ) , dma ) ;
v = * laddr + + ; writew ( L ( v ) , dma ) ; writew ( H ( v ) , dma ) ;
v = * laddr + + ; writew ( L ( v ) , dma ) ; writew ( H ( v ) , dma ) ;
v = * laddr + + ; writew ( L ( v ) , dma ) ; writew ( H ( v ) , dma ) ;
v = * laddr + + ; writew ( L ( v ) , dma ) ; writew ( H ( v ) , dma ) ;
2005-04-17 02:20:36 +04:00
len - = 32 ;
if ( len = = 0 )
break ;
}
addr = ( unsigned char * ) laddr ;
2007-07-20 13:38:54 +04:00
writeb ( 0x12 , priv ( host ) - > base + CTRL ) ;
2005-04-17 02:20:36 +04:00
while ( len > 0 )
{
2007-07-20 13:38:54 +04:00
unsigned int status ;
status = readb ( priv ( host ) - > base + STAT ) ;
2005-04-17 02:20:36 +04:00
if ( status & 0x80 )
goto end ;
if ( status & 0x40 )
{
2007-07-20 13:38:54 +04:00
writeb ( * addr + + , dma ) ;
2005-04-17 02:20:36 +04:00
if ( - - len = = 0 )
break ;
}
2007-07-20 13:38:54 +04:00
status = readb ( priv ( host ) - > base + STAT ) ;
2005-04-17 02:20:36 +04:00
if ( status & 0x80 )
goto end ;
if ( status & 0x40 )
{
2007-07-20 13:38:54 +04:00
writeb ( * addr + + , dma ) ;
2005-04-17 02:20:36 +04:00
if ( - - len = = 0 )
break ;
}
}
end :
2007-07-20 13:38:54 +04:00
writeb ( priv ( host ) - > ctrl | 0x40 , priv ( host ) - > base + CTRL ) ;
2016-03-23 13:10:18 +03:00
if ( len )
return - 1 ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2016-03-23 13:10:17 +03:00
static inline int cumanascsi_pread ( struct Scsi_Host * host ,
unsigned char * addr , int len )
2005-04-17 02:20:36 +04:00
{
unsigned long * laddr ;
2007-07-20 13:38:54 +04:00
void __iomem * dma = priv ( host ) - > dma + 0x2000 ;
2005-04-17 02:20:36 +04:00
if ( ! len ) return 0 ;
2007-07-20 13:38:54 +04:00
writeb ( 0x00 , priv ( host ) - > base + CTRL ) ;
2005-04-17 02:20:36 +04:00
laddr = ( unsigned long * ) addr ;
while ( len > = 32 )
{
2007-07-20 13:38:54 +04:00
unsigned int status ;
status = readb ( priv ( host ) - > base + STAT ) ;
2005-04-17 02:20:36 +04:00
if ( status & 0x80 )
goto end ;
if ( ! ( status & 0x40 ) )
continue ;
2007-07-20 13:38:54 +04:00
* laddr + + = readw ( dma ) | ( readw ( dma ) < < 16 ) ;
* laddr + + = readw ( dma ) | ( readw ( dma ) < < 16 ) ;
* laddr + + = readw ( dma ) | ( readw ( dma ) < < 16 ) ;
* laddr + + = readw ( dma ) | ( readw ( dma ) < < 16 ) ;
* laddr + + = readw ( dma ) | ( readw ( dma ) < < 16 ) ;
* laddr + + = readw ( dma ) | ( readw ( dma ) < < 16 ) ;
* laddr + + = readw ( dma ) | ( readw ( dma ) < < 16 ) ;
* laddr + + = readw ( dma ) | ( readw ( dma ) < < 16 ) ;
2005-04-17 02:20:36 +04:00
len - = 32 ;
if ( len = = 0 )
break ;
}
addr = ( unsigned char * ) laddr ;
2007-07-20 13:38:54 +04:00
writeb ( 0x10 , priv ( host ) - > base + CTRL ) ;
2005-04-17 02:20:36 +04:00
while ( len > 0 )
{
2007-07-20 13:38:54 +04:00
unsigned int status ;
status = readb ( priv ( host ) - > base + STAT ) ;
2005-04-17 02:20:36 +04:00
if ( status & 0x80 )
goto end ;
if ( status & 0x40 )
{
2007-07-20 13:38:54 +04:00
* addr + + = readb ( dma ) ;
2005-04-17 02:20:36 +04:00
if ( - - len = = 0 )
break ;
}
2007-07-20 13:38:54 +04:00
status = readb ( priv ( host ) - > base + STAT ) ;
2005-04-17 02:20:36 +04:00
if ( status & 0x80 )
goto end ;
if ( status & 0x40 )
{
2007-07-20 13:38:54 +04:00
* addr + + = readb ( dma ) ;
2005-04-17 02:20:36 +04:00
if ( - - len = = 0 )
break ;
}
}
end :
2007-07-20 13:38:54 +04:00
writeb ( priv ( host ) - > ctrl | 0x40 , priv ( host ) - > base + CTRL ) ;
2016-03-23 13:10:18 +03:00
if ( len )
return - 1 ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-07-20 13:38:54 +04:00
static unsigned char cumanascsi_read ( struct Scsi_Host * host , unsigned int reg )
{
void __iomem * base = priv ( host ) - > base ;
unsigned char val ;
2005-04-17 02:20:36 +04:00
2007-07-20 13:38:54 +04:00
writeb ( 0 , base + CTRL ) ;
2005-04-17 02:20:36 +04:00
2007-07-20 13:38:54 +04:00
val = readb ( base + 0x2100 + ( reg < < 2 ) ) ;
2005-04-17 02:20:36 +04:00
2007-07-20 13:38:54 +04:00
priv ( host ) - > ctrl = 0x40 ;
writeb ( 0x40 , base + CTRL ) ;
2005-04-17 02:20:36 +04:00
2007-07-20 13:38:54 +04:00
return val ;
2005-04-17 02:20:36 +04:00
}
2007-07-20 13:38:54 +04:00
static void cumanascsi_write ( struct Scsi_Host * host , unsigned int reg , unsigned int value )
2005-04-17 02:20:36 +04:00
{
2007-07-20 13:38:54 +04:00
void __iomem * base = priv ( host ) - > base ;
2005-04-17 02:20:36 +04:00
2007-07-20 13:38:54 +04:00
writeb ( 0 , base + CTRL ) ;
2005-04-17 02:20:36 +04:00
2007-07-20 13:38:54 +04:00
writeb ( value , base + 0x2100 + ( reg < < 2 ) ) ;
priv ( host ) - > ctrl = 0x40 ;
writeb ( 0x40 , base + CTRL ) ;
}
2005-04-17 02:20:36 +04:00
# include "../NCR5380.c"
2005-10-31 20:31:40 +03:00
static struct scsi_host_template cumanascsi_template = {
2005-04-17 02:20:36 +04:00
. module = THIS_MODULE ,
. name = " Cumana 16-bit SCSI " ,
. info = cumanascsi_info ,
. queuecommand = cumanascsi_queue_command ,
. eh_abort_handler = NCR5380_abort ,
. eh_bus_reset_handler = NCR5380_bus_reset ,
. can_queue = 16 ,
. this_id = 7 ,
. sg_tablesize = SG_ALL ,
. cmd_per_lun = 2 ,
. use_clustering = DISABLE_CLUSTERING ,
. proc_name = " CumanaSCSI-1 " ,
2016-01-03 08:05:58 +03:00
. cmd_size = NCR5380_CMD_SIZE ,
2016-01-03 08:06:07 +03:00
. max_sectors = 128 ,
2005-04-17 02:20:36 +04:00
} ;
2012-12-22 01:08:55 +04:00
static int cumanascsi1_probe ( struct expansion_card * ec ,
const struct ecard_id * id )
2005-04-17 02:20:36 +04:00
{
struct Scsi_Host * host ;
2007-07-20 13:38:54 +04:00
int ret ;
2005-04-17 02:20:36 +04:00
2007-07-20 13:38:54 +04:00
ret = ecard_request_resources ( ec ) ;
if ( ret )
2005-04-17 02:20:36 +04:00
goto out ;
2007-07-20 13:38:54 +04:00
host = scsi_host_alloc ( & cumanascsi_template , sizeof ( struct NCR5380_hostdata ) ) ;
if ( ! host ) {
ret = - ENOMEM ;
goto out_release ;
}
priv ( host ) - > base = ioremap ( ecard_resource_start ( ec , ECARD_RES_IOCSLOW ) ,
ecard_resource_len ( ec , ECARD_RES_IOCSLOW ) ) ;
priv ( host ) - > dma = ioremap ( ecard_resource_start ( ec , ECARD_RES_MEMC ) ,
ecard_resource_len ( ec , ECARD_RES_MEMC ) ) ;
if ( ! priv ( host ) - > base | | ! priv ( host ) - > dma ) {
ret = - ENOMEM ;
goto out_unmap ;
}
2005-04-17 02:20:36 +04:00
host - > irq = ec - > irq ;
2016-03-23 13:10:14 +03:00
ret = NCR5380_init ( host , FLAG_DMA_FIXUP ) ;
2016-01-03 08:05:21 +03:00
if ( ret )
goto out_unmap ;
2005-04-17 02:20:36 +04:00
2016-01-03 08:05:08 +03:00
NCR5380_maybe_reset_bus ( host ) ;
2007-07-20 13:38:54 +04:00
priv ( host ) - > ctrl = 0 ;
writeb ( 0 , priv ( host ) - > base + CTRL ) ;
2014-03-05 09:09:41 +04:00
ret = request_irq ( host - > irq , cumanascsi_intr , 0 ,
2005-04-17 02:20:36 +04:00
" CumanaSCSI-1 " , host ) ;
if ( ret ) {
printk ( " scsi%d: IRQ%d not free: %d \n " ,
host - > host_no , host - > irq , ret ) ;
2016-01-03 08:05:21 +03:00
goto out_exit ;
2005-04-17 02:20:36 +04:00
}
ret = scsi_add_host ( host , & ec - > dev ) ;
if ( ret )
goto out_free_irq ;
scsi_scan_host ( host ) ;
goto out ;
out_free_irq :
free_irq ( host - > irq , host ) ;
2016-01-03 08:05:21 +03:00
out_exit :
NCR5380_exit ( host ) ;
2007-07-20 13:38:54 +04:00
out_unmap :
iounmap ( priv ( host ) - > base ) ;
iounmap ( priv ( host ) - > dma ) ;
2005-04-17 02:20:36 +04:00
scsi_host_put ( host ) ;
2007-07-20 13:38:54 +04:00
out_release :
ecard_release_resources ( ec ) ;
2005-04-17 02:20:36 +04:00
out :
return ret ;
}
2012-12-22 01:08:55 +04:00
static void cumanascsi1_remove ( struct expansion_card * ec )
2005-04-17 02:20:36 +04:00
{
struct Scsi_Host * host = ecard_get_drvdata ( ec ) ;
ecard_set_drvdata ( ec , NULL ) ;
scsi_remove_host ( host ) ;
free_irq ( host - > irq , host ) ;
NCR5380_exit ( host ) ;
2007-07-20 13:38:54 +04:00
iounmap ( priv ( host ) - > base ) ;
iounmap ( priv ( host ) - > dma ) ;
2005-04-17 02:20:36 +04:00
scsi_host_put ( host ) ;
2007-07-20 13:38:54 +04:00
ecard_release_resources ( ec ) ;
2005-04-17 02:20:36 +04:00
}
static const struct ecard_id cumanascsi1_cids [ ] = {
{ MANU_CUMANA , PROD_CUMANA_SCSI_1 } ,
{ 0xffff , 0xffff }
} ;
static struct ecard_driver cumanascsi1_driver = {
. probe = cumanascsi1_probe ,
2012-12-22 01:08:55 +04:00
. remove = cumanascsi1_remove ,
2005-04-17 02:20:36 +04:00
. id_table = cumanascsi1_cids ,
. drv = {
. name = " cumanascsi1 " ,
} ,
} ;
static int __init cumanascsi_init ( void )
{
return ecard_register_driver ( & cumanascsi1_driver ) ;
}
static void __exit cumanascsi_exit ( void )
{
ecard_remove_driver ( & cumanascsi1_driver ) ;
}
module_init ( cumanascsi_init ) ;
module_exit ( cumanascsi_exit ) ;
MODULE_DESCRIPTION ( " Cumana SCSI-1 driver for Acorn machines " ) ;
MODULE_LICENSE ( " GPL " ) ;