2005-04-17 02:20:36 +04:00
/*
* Generic Generic NCR5380 driver
*
* Copyright 1993 , Drew Eckhardt
* Visionary Computing
* ( Unix and Linux consulting and custom programming )
* drew @ colorado . edu
* + 1 ( 303 ) 440 - 4894
*
* NCR53C400 extensions ( c ) 1994 , 1995 , 1996 , Kevin Lentin
* K . Lentin @ cs . monash . edu . au
*
* NCR53C400A extensions ( c ) 1996 , Ingmar Baumgart
* ingmar @ gonzo . schwaben . de
*
* DTC3181E extensions ( c ) 1997 , Ronald van Cuijlenborg
* ronald . van . cuijlenborg @ tip . nl or nutty @ dds . nl
*
* Added ISAPNP support for DTC436 adapters ,
* Thomas Sailer , sailer @ ife . ee . ethz . ch
*
2016-03-23 13:10:28 +03:00
* See Documentation / scsi / g_NCR5380 . txt for more info .
2005-04-17 02:20:36 +04:00
*/
# include <asm/io.h>
# include <linux/blkdev.h>
2016-01-03 08:05:46 +03:00
# include <linux/module.h>
2005-04-17 02:20:36 +04:00
# include <scsi/scsi_host.h>
# include <linux/init.h>
# include <linux/ioport.h>
2016-09-27 22:00:25 +03:00
# include <linux/isa.h>
# include <linux/pnp.h>
2005-04-17 02:20:36 +04:00
# include <linux/interrupt.h>
2017-01-16 02:50:57 +03:00
/* Definitions for the core NCR5380 driver. */
# define NCR5380_read(reg) \
ioread8 ( hostdata - > io + hostdata - > offset + ( reg ) )
# define NCR5380_write(reg, value) \
iowrite8 ( value , hostdata - > io + hostdata - > offset + ( reg ) )
# define NCR5380_implementation_fields \
int offset ; \
int c400_ctl_status ; \
int c400_blk_cnt ; \
int c400_host_buf ; \
int io_width
# define NCR5380_dma_xfer_len generic_NCR5380_dma_xfer_len
# define NCR5380_dma_recv_setup generic_NCR5380_pread
# define NCR5380_dma_send_setup generic_NCR5380_pwrite
# define NCR5380_dma_residual NCR5380_dma_residual_none
# define NCR5380_intr generic_NCR5380_intr
# define NCR5380_queue_command generic_NCR5380_queue_command
# define NCR5380_abort generic_NCR5380_abort
# define NCR5380_bus_reset generic_NCR5380_bus_reset
# define NCR5380_info generic_NCR5380_info
# define NCR5380_io_delay(x) udelay(x)
# include "NCR5380.h"
# define DRV_MODULE_NAME "g_NCR5380"
# define NCR53C400_mem_base 0x3880
# define NCR53C400_host_buffer 0x3900
# define NCR53C400_region_size 0x3a00
# define BOARD_NCR5380 0
# define BOARD_NCR53C400 1
# define BOARD_NCR53C400A 2
# define BOARD_DTC3181E 3
# define BOARD_HP_C2502 4
# define IRQ_AUTO 254
2016-09-27 22:00:25 +03:00
# define MAX_CARDS 8
/* old-style parameters for compatibility */
2016-12-05 09:07:20 +03:00
static int ncr_irq = - 1 ;
2016-01-03 08:05:05 +03:00
static int ncr_addr ;
static int ncr_5380 ;
static int ncr_53c400 ;
static int ncr_53c400a ;
static int dtc_3181e ;
2016-01-03 08:06:19 +03:00
static int hp_c2502 ;
2017-04-04 18:54:27 +03:00
module_param_hw ( ncr_irq , int , irq , 0 ) ;
module_param_hw ( ncr_addr , int , ioport , 0 ) ;
2016-09-27 22:00:25 +03:00
module_param ( ncr_5380 , int , 0 ) ;
module_param ( ncr_53c400 , int , 0 ) ;
module_param ( ncr_53c400a , int , 0 ) ;
module_param ( dtc_3181e , int , 0 ) ;
module_param ( hp_c2502 , int , 0 ) ;
2016-12-05 09:07:20 +03:00
static int irq [ ] = { - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 } ;
2017-04-04 18:54:27 +03:00
module_param_hw_array ( irq , int , irq , NULL , 0 ) ;
2016-12-05 09:07:20 +03:00
MODULE_PARM_DESC ( irq , " IRQ number(s) (0=none, 254=auto [default]) " ) ;
2005-04-17 02:20:36 +04:00
2016-09-27 22:00:25 +03:00
static int base [ ] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
2017-04-04 18:54:27 +03:00
module_param_hw_array ( base , int , ioport , NULL , 0 ) ;
2016-09-27 22:00:25 +03:00
MODULE_PARM_DESC ( base , " base address(es) " ) ;
static int card [ ] = { - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 } ;
module_param_array ( card , int , NULL , 0 ) ;
MODULE_PARM_DESC ( card , " card type (0=NCR5380, 1=NCR53C400, 2=NCR53C400A, 3=DTC3181E, 4=HP C2502) " ) ;
2016-10-10 07:46:52 +03:00
MODULE_ALIAS ( " g_NCR5380_mmio " ) ;
2016-09-27 22:00:25 +03:00
MODULE_LICENSE ( " GPL " ) ;
2005-04-17 02:20:36 +04:00
2016-12-05 09:07:20 +03:00
static void g_NCR5380_trigger_irq ( struct Scsi_Host * instance )
{
struct NCR5380_hostdata * hostdata = shost_priv ( instance ) ;
/*
* An interrupt is triggered whenever BSY = false , SEL = true
* and a bit set in the SELECT_ENABLE_REG is asserted on the
* SCSI bus .
*
* Note that the bus is only driven when the phase control signals
* ( I / O , C / D , and MSG ) match those in the TCR .
*/
NCR5380_write ( TARGET_COMMAND_REG ,
PHASE_SR_TO_TCR ( NCR5380_read ( STATUS_REG ) & PHASE_MASK ) ) ;
NCR5380_write ( SELECT_ENABLE_REG , hostdata - > id_mask ) ;
NCR5380_write ( OUTPUT_DATA_REG , hostdata - > id_mask ) ;
NCR5380_write ( INITIATOR_COMMAND_REG ,
ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_SEL ) ;
msleep ( 1 ) ;
NCR5380_write ( INITIATOR_COMMAND_REG , ICR_BASE ) ;
NCR5380_write ( SELECT_ENABLE_REG , 0 ) ;
NCR5380_write ( TARGET_COMMAND_REG , 0 ) ;
}
/**
* g_NCR5380_probe_irq - find the IRQ of a NCR5380 or equivalent
* @ instance : SCSI host instance
*
* Autoprobe for the IRQ line used by the card by triggering an IRQ
* and then looking to see what interrupt actually turned up .
*/
static int g_NCR5380_probe_irq ( struct Scsi_Host * instance )
{
struct NCR5380_hostdata * hostdata = shost_priv ( instance ) ;
int irq_mask , irq ;
NCR5380_read ( RESET_PARITY_INTERRUPT_REG ) ;
irq_mask = probe_irq_on ( ) ;
g_NCR5380_trigger_irq ( instance ) ;
irq = probe_irq_off ( irq_mask ) ;
NCR5380_read ( RESET_PARITY_INTERRUPT_REG ) ;
if ( irq < = 0 )
return NO_IRQ ;
return irq ;
}
2016-01-03 08:06:19 +03:00
/*
* Configure I / O address of 53 C400A or DTC436 by writing magic numbers
* to ports 0x779 and 0x379 .
*/
static void magic_configure ( int idx , u8 irq , u8 magic [ ] )
{
u8 cfg = 0 ;
outb ( magic [ 0 ] , 0x779 ) ;
outb ( magic [ 1 ] , 0x379 ) ;
outb ( magic [ 2 ] , 0x379 ) ;
outb ( magic [ 3 ] , 0x379 ) ;
outb ( magic [ 4 ] , 0x379 ) ;
2016-12-05 09:07:20 +03:00
if ( irq = = 9 )
irq = 2 ;
2016-01-03 08:06:19 +03:00
if ( idx > = 0 & & idx < = 7 )
cfg = 0x80 | idx | ( irq < < 4 ) ;
outb ( cfg , 0x379 ) ;
}
2016-10-10 07:46:52 +03:00
2016-12-05 09:07:20 +03:00
static irqreturn_t legacy_empty_irq_handler ( int irq , void * dev_id )
{
return IRQ_HANDLED ;
}
static int legacy_find_free_irq ( int * irq_table )
{
while ( * irq_table ! = - 1 ) {
if ( ! request_irq ( * irq_table , legacy_empty_irq_handler ,
IRQF_PROBE_SHARED , " Test IRQ " ,
( void * ) irq_table ) ) {
free_irq ( * irq_table , ( void * ) irq_table ) ;
return * irq_table ;
}
irq_table + + ;
}
return - 1 ;
}
2016-10-10 07:46:52 +03:00
static unsigned int ncr_53c400a_ports [ ] = {
0x280 , 0x290 , 0x300 , 0x310 , 0x330 , 0x340 , 0x348 , 0x350 , 0
} ;
static unsigned int dtc_3181e_ports [ ] = {
0x220 , 0x240 , 0x280 , 0x2a0 , 0x2c0 , 0x300 , 0x320 , 0x340 , 0
} ;
static u8 ncr_53c400a_magic [ ] = { /* 53C400A & DTC436 */
0x59 , 0xb9 , 0xc5 , 0xae , 0xa6
} ;
static u8 hp_c2502_magic [ ] = { /* HP C2502 */
0x0f , 0x22 , 0xf0 , 0x20 , 0x80
} ;
2016-12-05 09:07:20 +03:00
static int hp_c2502_irqs [ ] = {
9 , 5 , 7 , 3 , 4 , - 1
} ;
2016-01-03 08:06:19 +03:00
2016-09-27 22:00:25 +03:00
static int generic_NCR5380_init_one ( struct scsi_host_template * tpnt ,
struct device * pdev , int base , int irq , int board )
2005-04-17 02:20:36 +04:00
{
2016-10-10 07:46:52 +03:00
bool is_pmio = base < = 0xffff ;
int ret ;
int flags = 0 ;
unsigned int * ports = NULL ;
2016-01-03 08:06:19 +03:00
u8 * magic = NULL ;
2010-08-11 05:01:16 +04:00
int i ;
2016-01-03 08:06:19 +03:00
int port_idx = - 1 ;
2016-03-23 13:10:10 +03:00
unsigned long region_size ;
2005-04-17 02:20:36 +04:00
struct Scsi_Host * instance ;
2016-01-03 08:06:15 +03:00
struct NCR5380_hostdata * hostdata ;
2016-10-10 07:46:53 +03:00
u8 __iomem * iomem ;
2005-04-17 02:20:36 +04:00
2016-09-27 22:00:25 +03:00
switch ( board ) {
2016-09-27 22:00:24 +03:00
case BOARD_NCR5380 :
flags = FLAG_NO_PSEUDO_DMA | FLAG_DMA_FIXUP ;
break ;
case BOARD_NCR53C400A :
ports = ncr_53c400a_ports ;
magic = ncr_53c400a_magic ;
break ;
case BOARD_HP_C2502 :
ports = ncr_53c400a_ports ;
magic = hp_c2502_magic ;
break ;
case BOARD_DTC3181E :
ports = dtc_3181e_ports ;
magic = ncr_53c400a_magic ;
break ;
}
2005-04-17 02:20:36 +04:00
2016-10-10 07:46:52 +03:00
if ( is_pmio & & ports & & magic ) {
2016-09-27 22:00:24 +03:00
/* wakeup sequence for the NCR53C400A and DTC3181E */
2005-04-17 02:20:36 +04:00
2016-09-27 22:00:24 +03:00
/* Disable the adapter and look for a free io port */
magic_configure ( - 1 , 0 , magic ) ;
2005-04-17 02:20:36 +04:00
2016-09-27 22:00:24 +03:00
region_size = 16 ;
2016-09-27 22:00:25 +03:00
if ( base )
2016-09-27 22:00:24 +03:00
for ( i = 0 ; ports [ i ] ; i + + ) {
2016-09-27 22:00:25 +03:00
if ( base = = ports [ i ] ) { /* index found */
if ( ! request_region ( ports [ i ] ,
region_size ,
" ncr53c80 " ) )
return - EBUSY ;
2016-09-27 22:00:24 +03:00
break ;
2016-09-27 22:00:25 +03:00
}
}
else
2016-09-27 22:00:24 +03:00
for ( i = 0 ; ports [ i ] ; i + + ) {
2016-09-27 22:00:25 +03:00
if ( ! request_region ( ports [ i ] , region_size ,
" ncr53c80 " ) )
2016-09-27 22:00:24 +03:00
continue ;
if ( inb ( ports [ i ] ) = = 0xff )
break ;
release_region ( ports [ i ] , region_size ) ;
}
if ( ports [ i ] ) {
/* At this point we have our region reserved */
magic_configure ( i , 0 , magic ) ; /* no IRQ yet */
2016-11-11 02:00:20 +03:00
base = ports [ i ] ;
outb ( 0xc0 , base + 9 ) ;
if ( inb ( base + 9 ) ! = 0x80 ) {
2016-09-27 22:00:25 +03:00
ret = - ENODEV ;
goto out_release ;
}
2016-09-27 22:00:24 +03:00
port_idx = i ;
} else
2016-09-27 22:00:25 +03:00
return - EINVAL ;
2016-10-10 07:46:52 +03:00
} else if ( is_pmio ) {
2016-09-27 22:00:25 +03:00
/* NCR5380 - no configuration, just grab */
2016-09-27 22:00:24 +03:00
region_size = 8 ;
2016-09-27 22:00:25 +03:00
if ( ! base | | ! request_region ( base , region_size , " ncr5380 " ) )
return - EBUSY ;
2016-10-10 07:46:52 +03:00
} else { /* MMIO */
region_size = NCR53C400_region_size ;
if ( ! request_mem_region ( base , region_size , " ncr5380 " ) )
return - EBUSY ;
2016-09-27 22:00:24 +03:00
}
2016-10-10 07:46:52 +03:00
if ( is_pmio )
iomem = ioport_map ( base , region_size ) ;
else
iomem = ioremap ( base , region_size ) ;
2016-09-27 22:00:24 +03:00
if ( ! iomem ) {
2016-10-10 07:46:52 +03:00
ret = - ENOMEM ;
goto out_release ;
2016-09-27 22:00:24 +03:00
}
2016-10-10 07:46:52 +03:00
2016-09-27 22:00:25 +03:00
instance = scsi_host_alloc ( tpnt , sizeof ( struct NCR5380_hostdata ) ) ;
if ( instance = = NULL ) {
ret = - ENOMEM ;
2016-10-10 07:46:52 +03:00
goto out_unmap ;
2016-09-27 22:00:25 +03:00
}
2016-09-27 22:00:24 +03:00
hostdata = shost_priv ( instance ) ;
2005-04-17 02:20:36 +04:00
2016-10-10 07:46:53 +03:00
hostdata - > io = iomem ;
hostdata - > region_size = region_size ;
2016-10-10 07:46:52 +03:00
if ( is_pmio ) {
2016-10-10 07:46:53 +03:00
hostdata - > io_port = base ;
2016-10-10 07:46:52 +03:00
hostdata - > io_width = 1 ; /* 8-bit PDMA by default */
hostdata - > offset = 0 ;
/*
* On NCR53C400 boards , NCR5380 registers are mapped 8 past
* the base address .
*/
switch ( board ) {
case BOARD_NCR53C400 :
2016-10-10 07:46:53 +03:00
hostdata - > io_port + = 8 ;
2016-10-10 07:46:52 +03:00
hostdata - > c400_ctl_status = 0 ;
hostdata - > c400_blk_cnt = 1 ;
hostdata - > c400_host_buf = 4 ;
break ;
case BOARD_DTC3181E :
hostdata - > io_width = 2 ; /* 16-bit PDMA */
/* fall through */
case BOARD_NCR53C400A :
case BOARD_HP_C2502 :
hostdata - > c400_ctl_status = 9 ;
hostdata - > c400_blk_cnt = 10 ;
hostdata - > c400_host_buf = 8 ;
break ;
}
} else {
2016-10-10 07:46:53 +03:00
hostdata - > base = base ;
2016-10-10 07:46:52 +03:00
hostdata - > offset = NCR53C400_mem_base ;
switch ( board ) {
case BOARD_NCR53C400 :
hostdata - > c400_ctl_status = 0x100 ;
hostdata - > c400_blk_cnt = 0x101 ;
hostdata - > c400_host_buf = 0x104 ;
break ;
case BOARD_DTC3181E :
case BOARD_NCR53C400A :
case BOARD_HP_C2502 :
pr_err ( DRV_MODULE_NAME " : unknown register offsets \n " ) ;
ret = - EINVAL ;
goto out_unregister ;
}
2016-09-27 22:00:24 +03:00
}
2005-04-17 02:20:36 +04:00
2016-12-05 09:07:19 +03:00
/* Check for vacant slot */
NCR5380_write ( MODE_REG , 0 ) ;
if ( NCR5380_read ( MODE_REG ) ! = 0 ) {
ret = - ENODEV ;
goto out_unregister ;
}
2016-09-27 22:00:25 +03:00
ret = NCR5380_init ( instance , flags | FLAG_LATE_DMA_SETUP ) ;
if ( ret )
2016-09-27 22:00:24 +03:00
goto out_unregister ;
2005-04-17 02:20:36 +04:00
2016-09-27 22:00:25 +03:00
switch ( board ) {
2016-09-27 22:00:24 +03:00
case BOARD_NCR53C400 :
case BOARD_DTC3181E :
case BOARD_NCR53C400A :
case BOARD_HP_C2502 :
NCR5380_write ( hostdata - > c400_ctl_status , CSR_BASE ) ;
}
2016-01-03 08:05:09 +03:00
2016-09-27 22:00:24 +03:00
NCR5380_maybe_reset_bus ( instance ) ;
2016-01-03 08:05:08 +03:00
2016-09-27 22:00:24 +03:00
/* Compatibility with documented NCR5380 kernel parameters */
2016-12-05 09:07:20 +03:00
if ( irq = = 255 | | irq = = 0 )
irq = NO_IRQ ;
2016-12-05 09:07:20 +03:00
else if ( irq = = - 1 )
irq = IRQ_AUTO ;
2016-12-05 09:07:20 +03:00
if ( board = = BOARD_HP_C2502 ) {
int * irq_table = hp_c2502_irqs ;
int board_irq = - 1 ;
switch ( irq ) {
case NO_IRQ :
board_irq = 0 ;
break ;
case IRQ_AUTO :
board_irq = legacy_find_free_irq ( irq_table ) ;
break ;
default :
while ( * irq_table ! = - 1 )
if ( * irq_table + + = = irq )
board_irq = irq ;
}
if ( board_irq < = 0 ) {
board_irq = 0 ;
irq = NO_IRQ ;
}
magic_configure ( port_idx , board_irq , magic ) ;
}
2016-12-05 09:07:20 +03:00
if ( irq = = IRQ_AUTO ) {
2016-12-05 09:07:20 +03:00
instance - > irq = g_NCR5380_probe_irq ( instance ) ;
2016-12-05 09:07:20 +03:00
if ( instance - > irq = = NO_IRQ )
shost_printk ( KERN_INFO , instance , " no irq detected \n " ) ;
} else {
2016-12-05 09:07:20 +03:00
instance - > irq = irq ;
2016-12-05 09:07:20 +03:00
if ( instance - > irq = = NO_IRQ )
shost_printk ( KERN_INFO , instance , " no irq provided \n " ) ;
}
2014-11-12 08:11:56 +03:00
2016-09-27 22:00:24 +03:00
if ( instance - > irq ! = NO_IRQ ) {
if ( request_irq ( instance - > irq , generic_NCR5380_intr ,
0 , " NCR5380 " , instance ) ) {
instance - > irq = NO_IRQ ;
2016-12-05 09:07:20 +03:00
shost_printk ( KERN_INFO , instance ,
" irq %d denied \n " , instance - > irq ) ;
} else {
shost_printk ( KERN_INFO , instance ,
" irq %d acquired \n " , instance - > irq ) ;
2005-04-17 02:20:36 +04:00
}
2016-09-27 22:00:24 +03:00
}
2005-04-17 02:20:36 +04:00
2016-09-27 22:00:25 +03:00
ret = scsi_add_host ( instance , pdev ) ;
if ( ret )
goto out_free_irq ;
scsi_scan_host ( instance ) ;
dev_set_drvdata ( pdev , instance ) ;
return 0 ;
2016-01-03 08:05:21 +03:00
2016-09-27 22:00:25 +03:00
out_free_irq :
if ( instance - > irq ! = NO_IRQ )
free_irq ( instance - > irq , instance ) ;
NCR5380_exit ( instance ) ;
2016-01-03 08:05:21 +03:00
out_unregister :
2016-09-27 22:00:25 +03:00
scsi_host_put ( instance ) ;
2016-10-10 07:46:52 +03:00
out_unmap :
2016-01-03 08:05:21 +03:00
iounmap ( iomem ) ;
2016-10-10 07:46:52 +03:00
out_release :
if ( is_pmio )
release_region ( base , region_size ) ;
else
release_mem_region ( base , region_size ) ;
2016-09-27 22:00:25 +03:00
return ret ;
2005-04-17 02:20:36 +04:00
}
2016-09-27 22:00:25 +03:00
static void generic_NCR5380_release_resources ( struct Scsi_Host * instance )
2005-04-17 02:20:36 +04:00
{
2016-10-10 07:46:52 +03:00
struct NCR5380_hostdata * hostdata = shost_priv ( instance ) ;
2016-10-10 07:46:53 +03:00
void __iomem * iomem = hostdata - > io ;
unsigned long io_port = hostdata - > io_port ;
unsigned long base = hostdata - > base ;
unsigned long region_size = hostdata - > region_size ;
2016-10-10 07:46:52 +03:00
2016-09-27 22:00:25 +03:00
scsi_remove_host ( instance ) ;
2014-11-12 08:11:56 +03:00
if ( instance - > irq ! = NO_IRQ )
2007-11-12 03:52:05 +03:00
free_irq ( instance - > irq , instance ) ;
2005-04-17 02:20:36 +04:00
NCR5380_exit ( instance ) ;
2016-09-27 22:00:25 +03:00
scsi_host_put ( instance ) ;
2016-10-10 07:46:53 +03:00
iounmap ( iomem ) ;
if ( io_port )
release_region ( io_port , region_size ) ;
else
release_mem_region ( base , region_size ) ;
2005-04-17 02:20:36 +04:00
}
/**
2016-03-23 13:10:17 +03:00
* generic_NCR5380_pread - pseudo DMA read
2016-10-10 07:46:53 +03:00
* @ hostdata : scsi host private data
2005-04-17 02:20:36 +04:00
* @ dst : buffer to read into
* @ len : buffer length
*
2011-03-31 05:57:33 +04:00
* Perform a pseudo DMA mode read from an NCR53C400 or equivalent
2005-04-17 02:20:36 +04:00
* controller
*/
2016-10-10 07:46:53 +03:00
static inline int generic_NCR5380_pread ( struct NCR5380_hostdata * hostdata ,
2016-03-23 13:10:17 +03:00
unsigned char * dst , int len )
2005-04-17 02:20:36 +04:00
{
int blocks = len / 128 ;
int start = 0 ;
2016-01-03 08:06:15 +03:00
NCR5380_write ( hostdata - > c400_ctl_status , CSR_BASE | CSR_TRANS_DIR ) ;
NCR5380_write ( hostdata - > c400_blk_cnt , blocks ) ;
2005-04-17 02:20:36 +04:00
while ( 1 ) {
2016-01-03 08:06:15 +03:00
if ( NCR5380_read ( hostdata - > c400_blk_cnt ) = = 0 )
2005-04-17 02:20:36 +04:00
break ;
2016-01-03 08:06:15 +03:00
if ( NCR5380_read ( hostdata - > c400_ctl_status ) & CSR_GATED_53C80_IRQ ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " 53C400r: Got 53C80_IRQ start=%d, blocks=%d \n " , start , blocks ) ;
return - 1 ;
}
2016-01-03 08:06:15 +03:00
while ( NCR5380_read ( hostdata - > c400_ctl_status ) & CSR_HOST_BUF_NOT_RDY )
; /* FIXME - no timeout */
2005-04-17 02:20:36 +04:00
2016-10-10 07:46:53 +03:00
if ( hostdata - > io_port & & hostdata - > io_width = = 2 )
insw ( hostdata - > io_port + hostdata - > c400_host_buf ,
2016-01-03 08:06:17 +03:00
dst + start , 64 ) ;
2016-10-10 07:46:53 +03:00
else if ( hostdata - > io_port )
insb ( hostdata - > io_port + hostdata - > c400_host_buf ,
2016-01-03 08:06:15 +03:00
dst + start , 128 ) ;
2016-10-10 07:46:52 +03:00
else
memcpy_fromio ( dst + start ,
2016-10-10 07:46:53 +03:00
hostdata - > io + NCR53C400_host_buffer , 128 ) ;
2016-10-10 07:46:52 +03:00
2005-04-17 02:20:36 +04:00
start + = 128 ;
blocks - - ;
}
if ( blocks ) {
2016-01-03 08:06:15 +03:00
while ( NCR5380_read ( hostdata - > c400_ctl_status ) & CSR_HOST_BUF_NOT_RDY )
; /* FIXME - no timeout */
2005-04-17 02:20:36 +04:00
2016-10-10 07:46:53 +03:00
if ( hostdata - > io_port & & hostdata - > io_width = = 2 )
insw ( hostdata - > io_port + hostdata - > c400_host_buf ,
2016-01-03 08:06:17 +03:00
dst + start , 64 ) ;
2016-10-10 07:46:53 +03:00
else if ( hostdata - > io_port )
insb ( hostdata - > io_port + hostdata - > c400_host_buf ,
2016-01-03 08:06:15 +03:00
dst + start , 128 ) ;
2016-10-10 07:46:52 +03:00
else
memcpy_fromio ( dst + start ,
2016-10-10 07:46:53 +03:00
hostdata - > io + NCR53C400_host_buffer , 128 ) ;
2016-10-10 07:46:52 +03:00
2005-04-17 02:20:36 +04:00
start + = 128 ;
blocks - - ;
}
2016-01-03 08:06:15 +03:00
if ( ! ( NCR5380_read ( hostdata - > c400_ctl_status ) & CSR_GATED_53C80_IRQ ) )
2005-04-17 02:20:36 +04:00
printk ( " 53C400r: no 53C80 gated irq after transfer " ) ;
2016-01-03 08:06:18 +03:00
/* wait for 53C80 registers to be available */
while ( ! ( NCR5380_read ( hostdata - > c400_ctl_status ) & CSR_53C80_REG ) )
2005-04-17 02:20:36 +04:00
;
2016-01-03 08:06:18 +03:00
2005-04-17 02:20:36 +04:00
if ( ! ( NCR5380_read ( BUS_AND_STATUS_REG ) & BASR_END_DMA_TRANSFER ) )
printk ( KERN_ERR " 53C400r: no end dma signal \n " ) ;
return 0 ;
}
/**
2016-03-23 13:10:17 +03:00
* generic_NCR5380_pwrite - pseudo DMA write
2016-10-10 07:46:53 +03:00
* @ hostdata : scsi host private data
2005-04-17 02:20:36 +04:00
* @ dst : buffer to read into
* @ len : buffer length
*
2011-03-31 05:57:33 +04:00
* Perform a pseudo DMA mode read from an NCR53C400 or equivalent
2005-04-17 02:20:36 +04:00
* controller
*/
2016-10-10 07:46:53 +03:00
static inline int generic_NCR5380_pwrite ( struct NCR5380_hostdata * hostdata ,
2016-03-23 13:10:17 +03:00
unsigned char * src , int len )
2005-04-17 02:20:36 +04:00
{
int blocks = len / 128 ;
int start = 0 ;
2016-01-03 08:06:15 +03:00
NCR5380_write ( hostdata - > c400_ctl_status , CSR_BASE ) ;
NCR5380_write ( hostdata - > c400_blk_cnt , blocks ) ;
2005-04-17 02:20:36 +04:00
while ( 1 ) {
2016-01-03 08:06:15 +03:00
if ( NCR5380_read ( hostdata - > c400_ctl_status ) & CSR_GATED_53C80_IRQ ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " 53C400w: Got 53C80_IRQ start=%d, blocks=%d \n " , start , blocks ) ;
return - 1 ;
}
2016-01-03 08:06:15 +03:00
if ( NCR5380_read ( hostdata - > c400_blk_cnt ) = = 0 )
2005-04-17 02:20:36 +04:00
break ;
2016-01-03 08:06:15 +03:00
while ( NCR5380_read ( hostdata - > c400_ctl_status ) & CSR_HOST_BUF_NOT_RDY )
2005-04-17 02:20:36 +04:00
; // FIXME - timeout
2016-10-10 07:46:52 +03:00
2016-10-10 07:46:53 +03:00
if ( hostdata - > io_port & & hostdata - > io_width = = 2 )
outsw ( hostdata - > io_port + hostdata - > c400_host_buf ,
2016-01-03 08:06:17 +03:00
src + start , 64 ) ;
2016-10-10 07:46:53 +03:00
else if ( hostdata - > io_port )
outsb ( hostdata - > io_port + hostdata - > c400_host_buf ,
2016-01-03 08:06:15 +03:00
src + start , 128 ) ;
2016-10-10 07:46:52 +03:00
else
2016-10-10 07:46:53 +03:00
memcpy_toio ( hostdata - > io + NCR53C400_host_buffer ,
2016-10-10 07:46:52 +03:00
src + start , 128 ) ;
2005-04-17 02:20:36 +04:00
start + = 128 ;
blocks - - ;
}
if ( blocks ) {
2016-01-03 08:06:15 +03:00
while ( NCR5380_read ( hostdata - > c400_ctl_status ) & CSR_HOST_BUF_NOT_RDY )
2005-04-17 02:20:36 +04:00
; // FIXME - no timeout
2016-10-10 07:46:53 +03:00
if ( hostdata - > io_port & & hostdata - > io_width = = 2 )
outsw ( hostdata - > io_port + hostdata - > c400_host_buf ,
2016-01-03 08:06:17 +03:00
src + start , 64 ) ;
2016-10-10 07:46:53 +03:00
else if ( hostdata - > io_port )
outsb ( hostdata - > io_port + hostdata - > c400_host_buf ,
2016-01-03 08:06:15 +03:00
src + start , 128 ) ;
2016-10-10 07:46:52 +03:00
else
2016-10-10 07:46:53 +03:00
memcpy_toio ( hostdata - > io + NCR53C400_host_buffer ,
2016-10-10 07:46:52 +03:00
src + start , 128 ) ;
2005-04-17 02:20:36 +04:00
start + = 128 ;
blocks - - ;
}
2016-01-03 08:06:18 +03:00
/* wait for 53C80 registers to be available */
while ( ! ( NCR5380_read ( hostdata - > c400_ctl_status ) & CSR_53C80_REG ) ) {
2016-01-03 08:06:17 +03:00
udelay ( 4 ) ; /* DTC436 chip hangs without this */
/* FIXME - no timeout */
}
2005-04-17 02:20:36 +04:00
if ( ! ( NCR5380_read ( BUS_AND_STATUS_REG ) & BASR_END_DMA_TRANSFER ) ) {
printk ( KERN_ERR " 53C400w: no end dma signal \n " ) ;
}
2016-01-03 08:06:18 +03:00
2005-04-17 02:20:36 +04:00
while ( ! ( NCR5380_read ( TARGET_COMMAND_REG ) & TCR_LAST_BYTE_SENT ) )
; // TIMEOUT
return 0 ;
}
2016-01-03 08:05:25 +03:00
2016-10-10 07:46:53 +03:00
static int generic_NCR5380_dma_xfer_len ( struct NCR5380_hostdata * hostdata ,
2016-03-23 13:10:11 +03:00
struct scsi_cmnd * cmd )
2016-01-03 08:05:25 +03:00
{
int transfersize = cmd - > transfersize ;
2016-03-23 13:10:11 +03:00
if ( hostdata - > flags & FLAG_NO_PSEUDO_DMA )
return 0 ;
2016-01-03 08:05:25 +03:00
/* Limit transfers to 32K, for xx400 & xx406
* pseudoDMA that transfers in 128 bytes blocks .
*/
if ( transfersize > 32 * 1024 & & cmd - > SCp . this_residual & &
! ( cmd - > SCp . this_residual % transfersize ) )
transfersize = 32 * 1024 ;
2016-01-03 08:06:14 +03:00
/* 53C400 datasheet: non-modulo-128-byte transfers should use PIO */
if ( transfersize % 128 )
transfersize = 0 ;
2016-01-03 08:05:25 +03:00
return transfersize ;
}
2005-04-17 02:20:36 +04:00
/*
* Include the NCR5380 core code that we build our driver around
*/
# include "NCR5380.c"
2005-10-31 20:31:40 +03:00
static struct scsi_host_template driver_template = {
2016-09-27 22:00:25 +03:00
. module = THIS_MODULE ,
2016-01-03 08:05:48 +03:00
. proc_name = DRV_MODULE_NAME ,
. name = " Generic NCR5380/NCR53C400 SCSI " ,
. info = generic_NCR5380_info ,
. queuecommand = generic_NCR5380_queue_command ,
2005-04-17 02:20:36 +04:00
. eh_abort_handler = generic_NCR5380_abort ,
. eh_bus_reset_handler = generic_NCR5380_bus_reset ,
2016-01-03 08:05:48 +03:00
. can_queue = 16 ,
. this_id = 7 ,
. sg_tablesize = SG_ALL ,
. cmd_per_lun = 2 ,
. use_clustering = DISABLE_CLUSTERING ,
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
} ;
2016-01-03 08:05:46 +03:00
2005-04-17 02:20:36 +04:00
2016-09-27 22:00:25 +03:00
static int generic_NCR5380_isa_match ( struct device * pdev , unsigned int ndev )
{
int ret = generic_NCR5380_init_one ( & driver_template , pdev , base [ ndev ] ,
irq [ ndev ] , card [ ndev ] ) ;
if ( ret ) {
if ( base [ ndev ] )
printk ( KERN_WARNING " Card not found at address 0x%03x \n " ,
base [ ndev ] ) ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
2016-09-27 22:00:25 +03:00
return 1 ;
}
static int generic_NCR5380_isa_remove ( struct device * pdev ,
unsigned int ndev )
{
generic_NCR5380_release_resources ( dev_get_drvdata ( pdev ) ) ;
dev_set_drvdata ( pdev , NULL ) ;
return 0 ;
}
static struct isa_driver generic_NCR5380_isa_driver = {
. match = generic_NCR5380_isa_match ,
. remove = generic_NCR5380_isa_remove ,
. driver = {
. name = DRV_MODULE_NAME
} ,
} ;
2016-10-10 07:46:52 +03:00
# ifdef CONFIG_PNP
2016-09-27 22:00:25 +03:00
static struct pnp_device_id generic_NCR5380_pnp_ids [ ] = {
{ . id = " DTC436e " , . driver_data = BOARD_DTC3181E } ,
{ . id = " " }
} ;
MODULE_DEVICE_TABLE ( pnp , generic_NCR5380_pnp_ids ) ;
static int generic_NCR5380_pnp_probe ( struct pnp_dev * pdev ,
const struct pnp_device_id * id )
{
int base , irq ;
if ( pnp_activate_dev ( pdev ) < 0 )
return - EBUSY ;
base = pnp_port_start ( pdev , 0 ) ;
irq = pnp_irq ( pdev , 0 ) ;
return generic_NCR5380_init_one ( & driver_template , & pdev - > dev , base , irq ,
id - > driver_data ) ;
}
static void generic_NCR5380_pnp_remove ( struct pnp_dev * pdev )
{
generic_NCR5380_release_resources ( pnp_get_drvdata ( pdev ) ) ;
pnp_set_drvdata ( pdev , NULL ) ;
}
static struct pnp_driver generic_NCR5380_pnp_driver = {
. name = DRV_MODULE_NAME ,
. id_table = generic_NCR5380_pnp_ids ,
. probe = generic_NCR5380_pnp_probe ,
. remove = generic_NCR5380_pnp_remove ,
2005-04-17 02:20:36 +04:00
} ;
2016-10-10 07:46:52 +03:00
# endif /* defined(CONFIG_PNP) */
2005-04-17 02:20:36 +04:00
2016-09-27 22:00:25 +03:00
static int pnp_registered , isa_registered ;
static int __init generic_NCR5380_init ( void )
{
int ret = 0 ;
/* compatibility with old-style parameters */
2016-12-05 09:07:20 +03:00
if ( irq [ 0 ] = = - 1 & & base [ 0 ] = = 0 & & card [ 0 ] = = - 1 ) {
2016-09-27 22:00:25 +03:00
irq [ 0 ] = ncr_irq ;
base [ 0 ] = ncr_addr ;
if ( ncr_5380 )
card [ 0 ] = BOARD_NCR5380 ;
if ( ncr_53c400 )
card [ 0 ] = BOARD_NCR53C400 ;
if ( ncr_53c400a )
card [ 0 ] = BOARD_NCR53C400A ;
if ( dtc_3181e )
card [ 0 ] = BOARD_DTC3181E ;
if ( hp_c2502 )
card [ 0 ] = BOARD_HP_C2502 ;
}
2016-10-10 07:46:52 +03:00
# ifdef CONFIG_PNP
2016-09-27 22:00:25 +03:00
if ( ! pnp_register_driver ( & generic_NCR5380_pnp_driver ) )
pnp_registered = 1 ;
2010-08-11 05:01:16 +04:00
# endif
2016-09-27 22:00:25 +03:00
ret = isa_register_driver ( & generic_NCR5380_isa_driver , MAX_CARDS ) ;
if ( ! ret )
isa_registered = 1 ;
return ( pnp_registered | | isa_registered ) ? 0 : ret ;
}
static void __exit generic_NCR5380_exit ( void )
{
2016-10-10 07:46:52 +03:00
# ifdef CONFIG_PNP
2016-09-27 22:00:25 +03:00
if ( pnp_registered )
pnp_unregister_driver ( & generic_NCR5380_pnp_driver ) ;
# endif
if ( isa_registered )
isa_unregister_driver ( & generic_NCR5380_isa_driver ) ;
}
module_init ( generic_NCR5380_init ) ;
module_exit ( generic_NCR5380_exit ) ;