2005-04-17 02:20:36 +04:00
/*
* Oak Generic NCR5380 driver
*
* Copyright 1995 - 2002 , Russell King
*/
# include <linux/module.h>
# include <linux/signal.h>
# include <linux/ioport.h>
# include <linux/delay.h>
# include <linux/blkdev.h>
# include <linux/init.h>
# include <asm/ecard.h>
# include <asm/io.h>
# include "../scsi.h"
# include <scsi/scsi_host.h>
# define AUTOSENSE
/*#define PSEUDO_DMA*/
# define OAKSCSI_PUBLIC_RELEASE 1
2012-04-30 20:26:31 +04:00
# define DONT_USE_INTR
2005-04-17 02:20:36 +04:00
2007-07-20 13:38:54 +04:00
# define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata)
# define NCR5380_local_declare() void __iomem *_base
# define NCR5380_setup(host) _base = priv(host)->base
# define NCR5380_read(reg) readb(_base + ((reg) << 2))
# define NCR5380_write(reg, value) writeb(value, _base + ((reg) << 2))
2005-04-17 02:20:36 +04:00
# define NCR5380_intr oakscsi_intr
# define NCR5380_queue_command oakscsi_queue_command
2013-03-31 09:15:54 +04:00
# define NCR5380_show_info oakscsi_show_info
# define NCR5380_write_info oakscsi_write_info
2005-04-17 02:20:36 +04:00
2007-07-20 13:38:54 +04:00
# define NCR5380_implementation_fields \
void __iomem * base
2005-04-17 02:20:36 +04:00
# define BOARD_NORMAL 0
# define BOARD_NCR53C400 1
# include "../NCR5380.h"
# undef START_DMA_INITIATOR_RECEIVE_REG
2007-07-20 13:38:54 +04:00
# define START_DMA_INITIATOR_RECEIVE_REG (128 + 7)
2005-04-17 02:20:36 +04:00
const char * oakscsi_info ( struct Scsi_Host * spnt )
{
return " " ;
}
2007-07-20 13:38:54 +04:00
# define STAT ((128 + 16) << 2)
# define DATA ((128 + 8) << 2)
2005-04-17 02:20:36 +04:00
static inline int NCR5380_pwrite ( struct Scsi_Host * instance , unsigned char * addr ,
int len )
{
2007-07-20 13:38:54 +04:00
void __iomem * base = priv ( instance ) - > base ;
2005-04-17 02:20:36 +04:00
printk ( " writing %p len %d \n " , addr , len ) ;
if ( ! len ) return - 1 ;
while ( 1 )
{
int status ;
2007-07-20 13:38:54 +04:00
while ( ( ( status = readw ( base + STAT ) ) & 0x100 ) = = 0 ) ;
2005-04-17 02:20:36 +04:00
}
}
static inline int NCR5380_pread ( struct Scsi_Host * instance , unsigned char * addr ,
int len )
{
2007-07-20 13:38:54 +04:00
void __iomem * base = priv ( instance ) - > base ;
2005-04-17 02:20:36 +04:00
printk ( " reading %p len %d \n " , addr , len ) ;
while ( len > 0 )
{
2007-07-20 13:38:54 +04:00
unsigned int status , timeout ;
2005-04-17 02:20:36 +04:00
unsigned long b ;
timeout = 0x01FFFFFF ;
2007-07-20 13:38:54 +04:00
while ( ( ( status = readw ( base + STAT ) ) & 0x100 ) = = 0 )
2005-04-17 02:20:36 +04:00
{
timeout - - ;
if ( status & 0x200 | | ! timeout )
{
2007-07-20 13:38:54 +04:00
printk ( " status = %08X \n " , status ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
}
}
2007-07-20 13:38:54 +04:00
2005-04-17 02:20:36 +04:00
if ( len > = 128 )
{
2007-07-20 13:38:54 +04:00
readsw ( base + DATA , addr , 128 ) ;
2005-04-17 02:20:36 +04:00
addr + = 128 ;
len - = 128 ;
}
else
{
2007-07-20 13:38:54 +04:00
b = ( unsigned long ) readw ( base + DATA ) ;
2005-04-17 02:20:36 +04:00
* addr + + = b ;
len - = 1 ;
if ( len )
* addr + + = b > > 8 ;
len - = 1 ;
}
}
return 0 ;
}
# undef STAT
2007-07-20 13:38:54 +04:00
# undef DATA
2005-04-17 02:20:36 +04:00
# include "../NCR5380.c"
2005-10-31 20:31:40 +03:00
static struct scsi_host_template oakscsi_template = {
2005-04-17 02:20:36 +04:00
. module = THIS_MODULE ,
2013-03-31 09:15:54 +04:00
. show_info = oakscsi_show_info ,
. write_info = oakscsi_write_info ,
2005-04-17 02:20:36 +04:00
. name = " Oak 16-bit SCSI " ,
. info = oakscsi_info ,
. queuecommand = oakscsi_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 = " oakscsi " ,
} ;
2012-12-22 01:08:55 +04:00
static int oakscsi_probe ( struct expansion_card * ec , const struct ecard_id * id )
2005-04-17 02:20:36 +04:00
{
struct Scsi_Host * host ;
int ret = - ENOMEM ;
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 ( & oakscsi_template , sizeof ( struct NCR5380_hostdata ) ) ;
if ( ! host ) {
ret = - ENOMEM ;
goto release ;
}
priv ( host ) - > base = ioremap ( ecard_resource_start ( ec , ECARD_RES_MEMC ) ,
ecard_resource_len ( ec , ECARD_RES_MEMC ) ) ;
if ( ! priv ( host ) - > base ) {
ret = - ENOMEM ;
goto unreg ;
}
2005-04-17 02:20:36 +04:00
host - > irq = IRQ_NONE ;
host - > n_io_port = 255 ;
NCR5380_init ( host , 0 ) ;
printk ( " scsi%d: at port 0x%08lx irqs disabled " ,
host - > host_no , host - > io_port ) ;
printk ( " options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d " ,
host - > can_queue , host - > cmd_per_lun , OAKSCSI_PUBLIC_RELEASE ) ;
printk ( " \n scsi%d: " , host - > host_no ) ;
NCR5380_print_options ( host ) ;
printk ( " \n " ) ;
ret = scsi_add_host ( host , & ec - > dev ) ;
if ( ret )
2007-07-20 13:38:54 +04:00
goto out_unmap ;
2005-04-17 02:20:36 +04:00
scsi_scan_host ( host ) ;
goto out ;
2007-07-20 13:38:54 +04:00
out_unmap :
iounmap ( priv ( host ) - > base ) ;
2005-04-17 02:20:36 +04:00
unreg :
scsi_host_put ( host ) ;
2007-07-20 13:38:54 +04:00
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 oakscsi_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 ) ;
NCR5380_exit ( host ) ;
2007-07-20 13:38:54 +04:00
iounmap ( priv ( host ) - > base ) ;
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 oakscsi_cids [ ] = {
{ MANU_OAK , PROD_OAK_SCSI } ,
{ 0xffff , 0xffff }
} ;
static struct ecard_driver oakscsi_driver = {
. probe = oakscsi_probe ,
2012-12-22 01:08:55 +04:00
. remove = oakscsi_remove ,
2005-04-17 02:20:36 +04:00
. id_table = oakscsi_cids ,
. drv = {
. name = " oakscsi " ,
} ,
} ;
static int __init oakscsi_init ( void )
{
return ecard_register_driver ( & oakscsi_driver ) ;
}
static void __exit oakscsi_exit ( void )
{
ecard_remove_driver ( & oakscsi_driver ) ;
}
module_init ( oakscsi_init ) ;
module_exit ( oakscsi_exit ) ;
MODULE_AUTHOR ( " Russell King " ) ;
MODULE_DESCRIPTION ( " Oak SCSI driver " ) ;
MODULE_LICENSE ( " GPL " ) ;