2019-05-19 15:08:20 +03:00
// SPDX-License-Identifier: GPL-2.0-only
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>
2011-05-27 17:47:43 +04:00
# include <linux/module.h>
2005-04-17 02:20:36 +04:00
# include <asm/page.h>
# include <asm/amigaints.h>
# include <asm/amigahw.h>
# include "scsi.h"
# include "wd33c93.h"
# include "gvp11.h"
2009-05-17 22:44:16 +04:00
# define CHECK_WD33C93
2010-04-12 23:55:25 +04:00
struct gvp11_hostdata {
struct WD33C93_hostdata wh ;
struct gvp11_scsiregs * regs ;
} ;
2009-05-17 14:17:28 +04:00
static irqreturn_t gvp11_intr ( int irq , void * data )
2005-04-17 02:20:36 +04:00
{
2009-05-17 14:17:28 +04:00
struct Scsi_Host * instance = data ;
2010-04-12 23:55:25 +04:00
struct gvp11_hostdata * hdata = shost_priv ( instance ) ;
unsigned int status = hdata - > regs - > CNTR ;
2010-04-04 13:00:33 +04:00
unsigned long flags ;
if ( ! ( status & GVP11_DMAC_INT_PENDING ) )
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
}
static int gvp11_xfer_mask = 0 ;
2010-04-04 13:00:33 +04:00
void gvp11_setup ( char * str , int * ints )
2005-04-17 02:20:36 +04:00
{
2010-04-04 13:00:33 +04:00
gvp11_xfer_mask = ints [ 1 ] ;
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:37 +04:00
struct Scsi_Host * instance = cmd - > device - > host ;
2010-04-12 23:55:25 +04:00
struct gvp11_hostdata * hdata = shost_priv ( instance ) ;
struct WD33C93_hostdata * wh = & hdata - > wh ;
struct gvp11_scsiregs * regs = hdata - > regs ;
2010-04-04 13:00:33 +04:00
unsigned short cntr = GVP11_DMAC_INT_ENABLE ;
unsigned long addr = virt_to_bus ( cmd - > SCp . ptr ) ;
int bank_mask ;
static int scsi_alloc_out_of_range = 0 ;
2005-04-17 02:20:36 +04:00
2010-04-04 13:00:33 +04:00
/* use bounce buffer if the physical address is bad */
2010-04-12 23:55:25 +04:00
if ( addr & wh - > dma_xfer_mask ) {
wh - > dma_bounce_len = ( cmd - > SCp . this_residual + 511 ) & ~ 0x1ff ;
2010-04-04 13:00:33 +04:00
if ( ! scsi_alloc_out_of_range ) {
2010-04-12 23:55:25 +04:00
wh - > dma_bounce_buffer =
kmalloc ( wh - > dma_bounce_len , GFP_KERNEL ) ;
wh - > dma_buffer_pool = BUF_SCSI_ALLOCED ;
2010-04-04 13:00:33 +04:00
}
2005-04-17 02:20:36 +04:00
2010-04-04 13:00:33 +04:00
if ( scsi_alloc_out_of_range | |
2010-04-12 23:55:25 +04:00
! wh - > dma_bounce_buffer ) {
wh - > dma_bounce_buffer =
amiga_chip_alloc ( wh - > dma_bounce_len ,
2010-04-04 13:00:33 +04:00
" GVP II SCSI Bounce Buffer " ) ;
2005-04-17 02:20:36 +04:00
2010-04-12 23:55:25 +04:00
if ( ! wh - > dma_bounce_buffer ) {
wh - > dma_bounce_len = 0 ;
2010-04-04 13:00:33 +04:00
return 1 ;
}
2005-04-17 02:20:36 +04:00
2010-04-12 23:55:25 +04:00
wh - > dma_buffer_pool = BUF_CHIP_ALLOCED ;
2010-04-04 13:00:33 +04:00
}
2005-04-17 02:20:36 +04:00
2010-04-04 13:00:33 +04:00
/* check if the address of the bounce buffer is OK */
2010-04-12 23:55:25 +04:00
addr = virt_to_bus ( wh - > dma_bounce_buffer ) ;
2010-04-04 13:00:33 +04:00
2010-04-12 23:55:25 +04:00
if ( addr & wh - > dma_xfer_mask ) {
2010-04-04 13:00:33 +04:00
/* fall back to Chip RAM if address out of range */
2010-04-12 23:55:25 +04:00
if ( wh - > dma_buffer_pool = = BUF_SCSI_ALLOCED ) {
kfree ( wh - > dma_bounce_buffer ) ;
2010-04-04 13:00:33 +04:00
scsi_alloc_out_of_range = 1 ;
} else {
2010-04-12 23:55:25 +04:00
amiga_chip_free ( wh - > dma_bounce_buffer ) ;
2010-04-04 13:00:33 +04:00
}
2010-04-12 23:55:25 +04:00
wh - > dma_bounce_buffer =
amiga_chip_alloc ( wh - > dma_bounce_len ,
2010-04-04 13:00:33 +04:00
" GVP II SCSI Bounce Buffer " ) ;
2010-04-12 23:55:25 +04:00
if ( ! wh - > dma_bounce_buffer ) {
wh - > dma_bounce_len = 0 ;
2010-04-04 13:00:33 +04:00
return 1 ;
}
2010-04-12 23:55:25 +04:00
addr = virt_to_bus ( wh - > dma_bounce_buffer ) ;
wh - > dma_buffer_pool = BUF_CHIP_ALLOCED ;
2010-04-04 13:00:33 +04:00
}
if ( ! dir_in ) {
/* copy to bounce buffer for a write */
2010-04-12 23:55:25 +04:00
memcpy ( wh - > dma_bounce_buffer , cmd - > SCp . ptr ,
2010-04-04 13:00:37 +04:00
cmd - > SCp . this_residual ) ;
2010-04-04 13:00:33 +04:00
}
2005-04-17 02:20:36 +04:00
}
2010-04-04 13:00:33 +04:00
/* setup dma direction */
if ( ! dir_in )
cntr | = GVP11_DMAC_DIR_WRITE ;
2005-04-17 02:20:36 +04:00
2010-04-12 23:55:25 +04:00
wh - > dma_dir = dir_in ;
2009-05-17 14:17:28 +04:00
regs - > CNTR = cntr ;
2005-04-17 02:20:36 +04:00
2010-04-04 13:00:33 +04:00
/* setup DMA *physical* address */
2009-05-17 14:17:28 +04:00
regs - > ACR = addr ;
2005-04-17 02:20:36 +04:00
2010-04-04 13:00:33 +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 ) ;
}
2005-04-17 02:20:36 +04:00
2010-04-12 23:55:25 +04:00
bank_mask = ( ~ wh - > dma_xfer_mask > > 18 ) & 0x01c0 ;
2010-04-04 13:00:37 +04:00
if ( bank_mask )
2009-05-17 14:17:28 +04:00
regs - > BANK = bank_mask & ( addr > > 18 ) ;
2005-04-17 02:20:36 +04:00
2010-04-04 13:00:33 +04:00
/* start DMA */
2009-05-17 14:17:28 +04:00
regs - > ST_DMA = 1 ;
2005-04-17 02:20:36 +04:00
2010-04-04 13:00:33 +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 ,
int status )
2005-04-17 02:20:36 +04:00
{
2010-04-12 23:55:25 +04:00
struct gvp11_hostdata * hdata = shost_priv ( instance ) ;
struct WD33C93_hostdata * wh = & hdata - > wh ;
struct gvp11_scsiregs * regs = hdata - > regs ;
2010-04-04 13:00:37 +04:00
2010-04-04 13:00:33 +04:00
/* stop DMA */
2009-05-17 14:17:28 +04:00
regs - > SP_DMA = 1 ;
2010-04-04 13:00:33 +04:00
/* remove write bit from CONTROL bits */
2009-05-17 14:17:28 +04:00
regs - > CNTR = GVP11_DMAC_INT_ENABLE ;
2010-04-04 13:00:33 +04:00
/* copy from a bounce buffer, if necessary */
2010-04-12 23:55:25 +04:00
if ( status & & wh - > dma_bounce_buffer ) {
if ( wh - > dma_dir & & SCpnt )
memcpy ( SCpnt - > SCp . ptr , wh - > dma_bounce_buffer ,
2010-04-04 13:00:33 +04:00
SCpnt - > SCp . this_residual ) ;
2010-04-12 23:55:25 +04:00
if ( wh - > dma_buffer_pool = = BUF_SCSI_ALLOCED )
kfree ( wh - > dma_bounce_buffer ) ;
2010-04-04 13:00:33 +04:00
else
2010-04-12 23:55:25 +04:00
amiga_chip_free ( wh - > dma_bounce_buffer ) ;
2010-04-04 13:00:33 +04:00
2010-04-12 23:55:25 +04:00
wh - > dma_bounce_buffer = NULL ;
wh - > dma_bounce_len = 0 ;
2010-04-04 13:00:33 +04:00
}
2005-04-17 02:20:36 +04:00
}
2009-08-16 13:17:35 +04:00
static struct scsi_host_template gvp11_scsi_template = {
. module = THIS_MODULE ,
. name = " GVP Series II SCSI " ,
2013-03-31 08:30:35 +04:00
. show_info = wd33c93_show_info ,
. write_info = wd33c93_write_info ,
2009-08-16 13:17:35 +04:00
. proc_name = " GVP11 " ,
. queuecommand = wd33c93_queuecommand ,
. eh_abort_handler = wd33c93_abort ,
. eh_host_reset_handler = wd33c93_host_reset ,
. can_queue = CAN_QUEUE ,
. this_id = 7 ,
. sg_tablesize = SG_ALL ,
. cmd_per_lun = CMD_PER_LUN ,
2018-12-13 18:17:09 +03:00
. dma_boundary = PAGE_SIZE - 1 ,
2009-08-16 13:17:35 +04:00
} ;
2012-12-22 01:08:55 +04:00
static int check_wd33c93 ( struct gvp11_scsiregs * regs )
2009-05-17 22:44:16 +04:00
{
# ifdef CHECK_WD33C93
volatile unsigned char * sasr_3393 , * scmd_3393 ;
unsigned char save_sasr ;
unsigned char q , qq ;
/*
* These darn GVP boards are a problem - it can be tough to tell
* whether or not they include a SCSI controller . This is the
* ultimate Yet - Another - GVP - Detection - Hack in that it actually
* probes for a WD33c93 chip : If we find one , it ' s extremely
* likely that this card supports SCSI , regardless of Product_
* Code , Board_Size , etc .
*/
/* Get pointers to the presumed register locations and save contents */
sasr_3393 = & regs - > SASR ;
scmd_3393 = & regs - > SCMD ;
save_sasr = * sasr_3393 ;
/* First test the AuxStatus Reg */
q = * sasr_3393 ; /* read it */
if ( q & 0x08 ) /* bit 3 should always be clear */
return - ENODEV ;
* sasr_3393 = WD_AUXILIARY_STATUS ; /* setup indirect address */
if ( * sasr_3393 = = WD_AUXILIARY_STATUS ) { /* shouldn't retain the write */
* sasr_3393 = save_sasr ; /* Oops - restore this byte */
return - ENODEV ;
}
if ( * sasr_3393 ! = q ) { /* should still read the same */
* sasr_3393 = save_sasr ; /* Oops - restore this byte */
return - ENODEV ;
}
if ( * scmd_3393 ! = q ) /* and so should the image at 0x1f */
return - ENODEV ;
/*
* Ok , we probably have a wd33c93 , but let ' s check a few other places
* for good measure . Make sure that this works for both ' A and ' B
* chip versions .
*/
* sasr_3393 = WD_SCSI_STATUS ;
q = * scmd_3393 ;
* sasr_3393 = WD_SCSI_STATUS ;
* scmd_3393 = ~ q ;
* sasr_3393 = WD_SCSI_STATUS ;
qq = * scmd_3393 ;
* sasr_3393 = WD_SCSI_STATUS ;
* scmd_3393 = q ;
if ( qq ! = q ) /* should be read only */
return - ENODEV ;
* sasr_3393 = 0x1e ; /* this register is unimplemented */
q = * scmd_3393 ;
* sasr_3393 = 0x1e ;
* scmd_3393 = ~ q ;
* sasr_3393 = 0x1e ;
qq = * scmd_3393 ;
* sasr_3393 = 0x1e ;
* scmd_3393 = q ;
if ( qq ! = q | | qq ! = 0xff ) /* should be read only, all 1's */
return - ENODEV ;
* sasr_3393 = WD_TIMEOUT_PERIOD ;
q = * scmd_3393 ;
* sasr_3393 = WD_TIMEOUT_PERIOD ;
* scmd_3393 = ~ q ;
* sasr_3393 = WD_TIMEOUT_PERIOD ;
qq = * scmd_3393 ;
* sasr_3393 = WD_TIMEOUT_PERIOD ;
* scmd_3393 = q ;
if ( qq ! = ( ~ q & 0xff ) ) /* should be read/write */
return - ENODEV ;
# endif /* CHECK_WD33C93 */
return 0 ;
}
2005-04-17 02:20:36 +04:00
2012-12-22 01:08:55 +04:00
static int gvp11_probe ( struct zorro_dev * z , const struct zorro_device_id * ent )
2005-04-17 02:20:36 +04:00
{
2010-04-04 13:00:33 +04:00
struct Scsi_Host * instance ;
unsigned long address ;
2009-08-16 13:17:35 +04:00
int error ;
2010-04-04 13:00:33 +04:00
unsigned int epc ;
unsigned int default_dma_xfer_mask ;
2010-04-12 23:55:25 +04:00
struct gvp11_hostdata * hdata ;
2009-05-17 23:05:55 +04:00
struct gvp11_scsiregs * regs ;
2009-05-17 14:17:28 +04:00
wd33c93_regs wdregs ;
2009-08-16 13:17:35 +04:00
default_dma_xfer_mask = ent - > driver_data ;
/*
* Rumors state that some GVP ram boards use the same product
* code as the SCSI controllers . Therefore if the board - size
2011-03-31 05:57:33 +04:00
* is not 64 KB we assume it is a ram board and bail out .
2009-08-16 13:17:35 +04:00
*/
if ( zorro_resource_len ( z ) ! = 0x10000 )
return - ENODEV ;
address = z - > resource . start ;
if ( ! request_mem_region ( address , 256 , " wd33c93 " ) )
return - EBUSY ;
2011-01-09 13:03:43 +03:00
regs = ZTWO_VADDR ( address ) ;
2009-08-16 13:17:35 +04:00
error = check_wd33c93 ( regs ) ;
if ( error )
goto fail_check_or_alloc ;
instance = scsi_host_alloc ( & gvp11_scsi_template ,
2010-04-12 23:55:25 +04:00
sizeof ( struct gvp11_hostdata ) ) ;
2009-08-16 13:17:35 +04:00
if ( ! instance ) {
error = - ENOMEM ;
goto fail_check_or_alloc ;
2010-04-04 13:00:33 +04:00
}
2005-04-17 02:20:36 +04:00
2009-08-16 13:17:35 +04:00
instance - > irq = IRQ_AMIGA_PORTS ;
instance - > unique_id = z - > slotaddr ;
2005-04-17 02:20:36 +04:00
2009-08-16 13:17:35 +04:00
regs - > secret2 = 1 ;
regs - > secret1 = 0 ;
regs - > secret3 = 15 ;
while ( regs - > CNTR & GVP11_DMAC_BUSY )
;
regs - > CNTR = 0 ;
regs - > BANK = 0 ;
2005-05-28 15:56:31 +04:00
2009-08-16 13:17:35 +04:00
wdregs . SASR = & regs - > SASR ;
wdregs . SCMD = & regs - > SCMD ;
2005-05-28 15:57:14 +04:00
2009-08-16 13:17:35 +04:00
hdata = shost_priv ( instance ) ;
if ( gvp11_xfer_mask )
2010-04-12 23:55:25 +04:00
hdata - > wh . dma_xfer_mask = gvp11_xfer_mask ;
2009-08-16 13:17:35 +04:00
else
2010-04-12 23:55:25 +04:00
hdata - > wh . dma_xfer_mask = default_dma_xfer_mask ;
2005-05-28 15:56:31 +04:00
2010-04-12 23:55:25 +04:00
hdata - > wh . no_sync = 0xff ;
hdata - > wh . fast = 0 ;
hdata - > wh . dma_mode = CTRL_DMA ;
hdata - > regs = regs ;
2005-04-17 02:20:36 +04:00
2009-08-16 13:17:35 +04:00
/*
* Check for 14 MHz SCSI clock
*/
epc = * ( unsigned short * ) ( ZTWO_VADDR ( address ) + 0x8000 ) ;
wd33c93_init ( instance , wdregs , dma_setup , dma_stop ,
( epc & GVP_SCSICLKMASK ) ? WD33C93_FS_8_10
: WD33C93_FS_12_15 ) ;
2005-04-17 02:20:36 +04:00
2009-08-16 13:17:35 +04:00
error = request_irq ( IRQ_AMIGA_PORTS , gvp11_intr , IRQF_SHARED ,
" GVP11 SCSI " , instance ) ;
if ( error )
goto fail_irq ;
2005-04-17 02:20:36 +04:00
2009-08-16 13:17:35 +04:00
regs - > CNTR = GVP11_DMAC_INT_ENABLE ;
2005-04-17 02:20:36 +04:00
2009-08-16 13:17:35 +04:00
error = scsi_add_host ( instance , NULL ) ;
if ( error )
goto fail_host ;
2005-04-17 02:20:36 +04:00
2009-08-16 13:17:35 +04:00
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_check_or_alloc :
release_mem_region ( address , 256 ) ;
return error ;
}
2005-04-17 02:20:36 +04:00
2012-12-22 01:08:55 +04:00
static void gvp11_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:25 +04:00
struct gvp11_hostdata * hdata = shost_priv ( instance ) ;
2009-05-17 14:17:28 +04:00
2010-04-12 23:55:25 +04:00
hdata - > regs - > CNTR = 0 ;
2009-08-16 13:17:35 +04:00
scsi_remove_host ( instance ) ;
2010-04-04 13:00:33 +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 ) ;
}
/*
* This should ( hopefully ) be the correct way to identify
* all the different GVP SCSI controllers ( except for the
* SERIES I though ) .
*/
2012-12-22 01:08:55 +04:00
static struct zorro_device_id gvp11_zorro_tbl [ ] = {
2009-08-16 13:17:35 +04:00
{ ZORRO_PROD_GVP_COMBO_030_R3_SCSI , ~ 0x00ffffff } ,
{ ZORRO_PROD_GVP_SERIES_II , ~ 0x00ffffff } ,
{ ZORRO_PROD_GVP_GFORCE_030_SCSI , ~ 0x01ffffff } ,
{ ZORRO_PROD_GVP_A530_SCSI , ~ 0x01ffffff } ,
{ ZORRO_PROD_GVP_COMBO_030_R4_SCSI , ~ 0x01ffffff } ,
{ ZORRO_PROD_GVP_A1291 , ~ 0x07ffffff } ,
{ ZORRO_PROD_GVP_GFORCE_040_SCSI_1 , ~ 0x07ffffff } ,
{ 0 }
} ;
MODULE_DEVICE_TABLE ( zorro , gvp11_zorro_tbl ) ;
static struct zorro_driver gvp11_driver = {
. name = " gvp11 " ,
. id_table = gvp11_zorro_tbl ,
. probe = gvp11_probe ,
2012-12-22 01:08:55 +04:00
. remove = gvp11_remove ,
2009-08-16 13:17:35 +04:00
} ;
static int __init gvp11_init ( void )
{
return zorro_register_driver ( & gvp11_driver ) ;
}
module_init ( gvp11_init ) ;
static void __exit gvp11_exit ( void )
{
zorro_unregister_driver ( & gvp11_driver ) ;
2005-04-17 02:20:36 +04:00
}
2009-08-16 13:17:35 +04:00
module_exit ( gvp11_exit ) ;
2005-04-17 02:20:36 +04:00
2009-08-16 13:17:35 +04:00
MODULE_DESCRIPTION ( " GVP Series II SCSI " ) ;
2005-04-17 02:20:36 +04:00
MODULE_LICENSE ( " GPL " ) ;