2019-05-19 13:08:20 +01:00
// SPDX-License-Identifier: GPL-2.0-only
2005-04-16 15:20:36 -07:00
/*
* Oak 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 10:38:54 +01:00
# define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata)
2016-10-10 00:46:53 -04:00
# define NCR5380_read(reg) readb(hostdata->io + ((reg) << 2))
# define NCR5380_write(reg, value) writeb(value, hostdata->io + ((reg) << 2))
2016-01-03 16:05:06 +11:00
2016-10-10 00:46:53 -04:00
# define NCR5380_dma_xfer_len NCR5380_dma_xfer_none
2016-03-23 21:10:17 +11:00
# define NCR5380_dma_recv_setup oakscsi_pread
# define NCR5380_dma_send_setup oakscsi_pwrite
2016-10-10 00:46:53 -04:00
# define NCR5380_dma_residual NCR5380_dma_residual_none
2016-01-03 16:05:25 +11:00
2005-04-16 15:20:36 -07:00
# define NCR5380_queue_command oakscsi_queue_command
2014-11-12 16:11:58 +11:00
# define NCR5380_info oakscsi_info
2005-04-16 15:20:36 -07:00
2016-10-10 00:46:53 -04:00
# define NCR5380_implementation_fields /* none */
2005-04-16 15:20:36 -07:00
# include "../NCR5380.h"
# undef START_DMA_INITIATOR_RECEIVE_REG
2007-07-20 10:38:54 +01:00
# define START_DMA_INITIATOR_RECEIVE_REG (128 + 7)
2005-04-16 15:20:36 -07:00
2007-07-20 10:38:54 +01:00
# define STAT ((128 + 16) << 2)
# define DATA ((128 + 8) << 2)
2005-04-16 15:20:36 -07:00
2016-10-10 00:46:53 -04:00
static inline int oakscsi_pwrite ( struct NCR5380_hostdata * hostdata ,
2016-03-23 21:10:17 +11:00
unsigned char * addr , int len )
2005-04-16 15:20:36 -07:00
{
2016-10-10 00:46:53 -04:00
u8 __iomem * base = hostdata - > io ;
2007-07-20 10:38:54 +01:00
2005-04-16 15:20:36 -07:00
printk ( " writing %p len %d \n " , addr , len ) ;
while ( 1 )
{
int status ;
2007-07-20 10:38:54 +01:00
while ( ( ( status = readw ( base + STAT ) ) & 0x100 ) = = 0 ) ;
2005-04-16 15:20:36 -07:00
}
2016-03-23 21:10:18 +11:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
2016-10-10 00:46:53 -04:00
static inline int oakscsi_pread ( struct NCR5380_hostdata * hostdata ,
2016-03-23 21:10:17 +11:00
unsigned char * addr , int len )
2005-04-16 15:20:36 -07:00
{
2016-10-10 00:46:53 -04:00
u8 __iomem * base = hostdata - > io ;
2005-04-16 15:20:36 -07:00
printk ( " reading %p len %d \n " , addr , len ) ;
while ( len > 0 )
{
2007-07-20 10:38:54 +01:00
unsigned int status , timeout ;
2005-04-16 15:20:36 -07:00
unsigned long b ;
timeout = 0x01FFFFFF ;
2007-07-20 10:38:54 +01:00
while ( ( ( status = readw ( base + STAT ) ) & 0x100 ) = = 0 )
2005-04-16 15:20:36 -07:00
{
timeout - - ;
if ( status & 0x200 | | ! timeout )
{
2007-07-20 10:38:54 +01:00
printk ( " status = %08X \n " , status ) ;
2016-03-23 21:10:18 +11:00
return - 1 ;
2005-04-16 15:20:36 -07:00
}
}
2007-07-20 10:38:54 +01:00
2005-04-16 15:20:36 -07:00
if ( len > = 128 )
{
2007-07-20 10:38:54 +01:00
readsw ( base + DATA , addr , 128 ) ;
2005-04-16 15:20:36 -07:00
addr + = 128 ;
len - = 128 ;
}
else
{
2007-07-20 10:38:54 +01:00
b = ( unsigned long ) readw ( base + DATA ) ;
2005-04-16 15:20:36 -07:00
* addr + + = b ;
len - = 1 ;
if ( len )
* addr + + = b > > 8 ;
len - = 1 ;
}
}
return 0 ;
}
# undef STAT
2007-07-20 10:38:54 +01:00
# undef DATA
2005-04-16 15:20:36 -07:00
# include "../NCR5380.c"
2005-10-31 18:31:40 +01:00
static struct scsi_host_template oakscsi_template = {
2005-04-16 15:20:36 -07:00
. module = THIS_MODULE ,
. name = " Oak 16-bit SCSI " ,
. info = oakscsi_info ,
. queuecommand = oakscsi_queue_command ,
. eh_abort_handler = NCR5380_abort ,
2017-08-25 13:57:10 +02:00
. eh_host_reset_handler = NCR5380_host_reset ,
2005-04-16 15:20:36 -07:00
. can_queue = 16 ,
. this_id = 7 ,
. sg_tablesize = SG_ALL ,
. cmd_per_lun = 2 ,
2018-12-13 16:17:09 +01:00
. dma_boundary = PAGE_SIZE - 1 ,
2005-04-16 15:20:36 -07:00
. proc_name = " oakscsi " ,
2016-01-03 16:05:58 +11:00
. cmd_size = NCR5380_CMD_SIZE ,
2016-01-03 16:06:07 +11:00
. max_sectors = 128 ,
2005-04-16 15:20:36 -07:00
} ;
2012-12-21 13:08:55 -08:00
static int oakscsi_probe ( struct expansion_card * ec , const struct ecard_id * id )
2005-04-16 15:20:36 -07:00
{
struct Scsi_Host * host ;
int ret = - ENOMEM ;
2007-07-20 10:38:54 +01:00
ret = ecard_request_resources ( ec ) ;
if ( ret )
2005-04-16 15:20:36 -07:00
goto out ;
2007-07-20 10:38:54 +01:00
host = scsi_host_alloc ( & oakscsi_template , sizeof ( struct NCR5380_hostdata ) ) ;
if ( ! host ) {
ret = - ENOMEM ;
goto release ;
}
2016-10-10 00:46:53 -04:00
priv ( host ) - > io = ioremap ( ecard_resource_start ( ec , ECARD_RES_MEMC ) ,
ecard_resource_len ( ec , ECARD_RES_MEMC ) ) ;
if ( ! priv ( host ) - > io ) {
2007-07-20 10:38:54 +01:00
ret = - ENOMEM ;
goto unreg ;
}
2014-11-12 16:11:56 +11:00
host - > irq = NO_IRQ ;
2005-04-16 15:20:36 -07:00
2016-03-23 21:10:19 +11:00
ret = NCR5380_init ( host , FLAG_DMA_FIXUP | FLAG_LATE_DMA_SETUP ) ;
2016-01-03 16:05:21 +11:00
if ( ret )
goto out_unmap ;
2005-04-16 15:20:36 -07:00
2016-01-03 16:05:08 +11:00
NCR5380_maybe_reset_bus ( host ) ;
2005-04-16 15:20:36 -07:00
ret = scsi_add_host ( host , & ec - > dev ) ;
if ( ret )
2016-01-03 16:05:21 +11:00
goto out_exit ;
2005-04-16 15:20:36 -07:00
scsi_scan_host ( host ) ;
goto out ;
2016-01-03 16:05:21 +11:00
out_exit :
NCR5380_exit ( host ) ;
2007-07-20 10:38:54 +01:00
out_unmap :
2016-10-10 00:46:53 -04:00
iounmap ( priv ( host ) - > io ) ;
2005-04-16 15:20:36 -07:00
unreg :
scsi_host_put ( host ) ;
2007-07-20 10:38:54 +01:00
release :
ecard_release_resources ( ec ) ;
2005-04-16 15:20:36 -07:00
out :
return ret ;
}
2012-12-21 13:08:55 -08:00
static void oakscsi_remove ( struct expansion_card * ec )
2005-04-16 15:20:36 -07:00
{
struct Scsi_Host * host = ecard_get_drvdata ( ec ) ;
2016-10-10 00:46:53 -04:00
void __iomem * base = priv ( host ) - > io ;
2005-04-16 15:20:36 -07:00
ecard_set_drvdata ( ec , NULL ) ;
scsi_remove_host ( host ) ;
NCR5380_exit ( host ) ;
scsi_host_put ( host ) ;
2016-10-10 00:46:53 -04:00
iounmap ( base ) ;
2007-07-20 10:38:54 +01:00
ecard_release_resources ( ec ) ;
2005-04-16 15:20:36 -07: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-21 13:08:55 -08:00
. remove = oakscsi_remove ,
2005-04-16 15:20:36 -07: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 " ) ;