/*
 * atari_scsi.c -- Device dependant functions for the Atari generic SCSI port
 *
 * Copyright 1994 Roman Hodek
 *   EMail: rnhodek@cip.informatik.uni-erlangen.de (Internet)
 *      or: Roman_Hodek@n.maus.de (MausNet, NO mail > 16 KB!)
 *
 *   Loosely based on the work of Robert De Vries' team and added:
 *    - working real DMA
 *    - Falcon support (untested yet!)   ++bjoern fixed and now it works
 *    - lots of extensions and bug fixes.
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file README.legal in the main directory of this archive
 * for more details.
 *
 */


/**************************************************************************/
/*                                                                        */
/* Notes for Falcon SCSI:                                                 */
/* ----------------------                                                 */
/*                                                                        */
/* Since the Falcon SCSI uses the ST-DMA chip, that is shared among       */
/* several device drivers, locking and unlocking the access to this       */
/* chip is required. But locking is not possible from an interrupt,       */
/* since it puts the process to sleep if the lock is not available.       */
/* This prevents "late" locking of the DMA chip, i.e. locking it just     */
/* before using it, since in case of disconnection-reconnection           */
/* commands, the DMA is started from the reselection interrupt.           */
/*                                                                        */
/* Two possible schemes for ST-DMA-locking would be:                      */
/*  1) The lock is taken for each command separately and disconnecting    */
/*     is forbidden (i.e. can_queue = 1).                                 */
/*  2) The DMA chip is locked when the first command comes in and         */
/*     released when the last command is finished and all queues are      */
/*     empty.                                                             */
/* The first alternative would result in bad performance, since the       */
/* interleaving of commands would not be used. The second is unfair to    */
/* other drivers using the ST-DMA, because the queues will seldom be      */
/* totally empty if there is a lot of disk traffic.                       */
/*                                                                        */
/* For this reasons I decided to employ a more elaborate scheme:          */
/*  - First, we give up the lock everytime we can (for fairness), this    */
/*    means every time a command finishes and there are no other commands */
/*    on the disconnected queue.                                          */
/*  - If there are others waiting to lock the DMA chip, we stop           */
/*    issueing commands, i.e. moving them onto the issue queue.           */
/*    Because of that, the disconnected queue will run empty in a         */
/*    while. Instead we go to sleep on a 'fairness_queue'.                */
/*  - If the lock is released, all processes waiting on the fairness      */
/*    queue will be woken. The first of them trys to re-lock the DMA,     */
/*    the others wait for the first to finish this task. After that,      */
/*    they can all run on and do their commands...                        */
/* This sounds complicated (and it is it :-(), but it seems to be a       */
/* good compromise between fairness and performance: As long as noone     */
/* else wants to work with the ST-DMA chip, SCSI can go along as          */
/* usual. If now someone else comes, this behaviour is changed to a       */
/* "fairness mode": just already initiated commands are finished and      */
/* then the lock is released. The other one waiting will probably win     */
/* the race for locking the DMA, since it was waiting for longer. And     */
/* after it has finished, SCSI can go ahead again. Finally: I hope I      */
/* have not produced any deadlock possibilites!                           */
/*                                                                        */
/**************************************************************************/



#include <linux/config.h>

#ifdef CONFIG_ATARI_SCSI

/* #define NDEBUG (NDEBUG_DMA) */

#define AUTOSENSE
/* For the Atari version, use only polled IO or REAL_DMA */
#define	REAL_DMA

#if I_HAVE_OVERRUNS == 1 || I_HAVE_OVERRUNS == 2
#define	READ_OVERRUNS
#endif

#include <linux/stddef.h>
#include <linux/interrupt.h>
#include <linux/bootinfo.h>
#include <linux/atarihw.h>
#include <linux/atariints.h>
#include "../block/blk.h"
#include "scsi.h"
#include "hosts.h"
#include "atari_scsi.h"
#include "NCR5380.h"
#include "constants.h"
#include <linux/atari_stdma.h>


#define	IS_A_TT()	(boot_info.bi_atari.model == ATARI_TT)

#define	SCSI_DMA_WRITE_P(elt,val)									\
    __asm__ __volatile__ ( "movepl %0,%1@(0)" : : "d" (val),		\
						       "a" (&tt_scsi_dma.elt) );

#define	SCSI_DMA_READ_P(elt) ({											\
	unsigned long __val;												\
    __asm__ __volatile__ ( "movepl %1@(0),%0"							\
						   : "=d" (__val) : "a" (&tt_scsi_dma.elt));	\
	__val; })

#define	SCSI_DMA_SETADR(adr)					\
    do {										\
		unsigned long __adr = (adr);			\
		st_dma.dma_lo = (unsigned char)__adr;	\
		__adr >>= 8;							\
		st_dma.dma_md = (unsigned char)__adr;	\
		__adr >>= 8;							\
		st_dma.dma_hi = (unsigned char)__adr;	\
	} while(0)

#define	SCSI_DMA_GETADR() ({					\
    unsigned long	__adr;						\
	__adr = st_dma.dma_lo;						\
    __asm__ __volatile__ ("nop");				\
    __adr |= (st_dma.dma_md & 0xff) << 8;		\
	__adr |= (st_dma.dma_hi & 0xff) << 16;		\
	__adr;										\
})



/***************************** Prototypes *****************************/

static void scsi_dma_buserr( struct intframe *fp, void *data);
static void scsi_tt_intr( struct intframe *fp, void *data);
static void scsi_falcon_intr( struct intframe *fp, void *data);
static void atari_scsi_fetch_restbytes( void );
static void falcon_release_lock_if_possible( struct NCR5380_hostdata *
                                             hostdata );
static void falcon_get_lock( void );
static long atari_scsi_dma_residual( struct Scsi_Host *instance );
static unsigned long atari_dma_xfer_len( unsigned long wanted_len );
static unsigned char atari_scsi_tt_reg_read( unsigned char reg );
static void atari_scsi_tt_reg_write( unsigned char reg, unsigned char value
                                     );
static unsigned char atari_scsi_falcon_reg_read( unsigned char reg );
static void atari_scsi_falcon_reg_write( unsigned char reg, unsigned char
                                         value );

/************************* End of Prototypes **************************/


static struct Scsi_Host *atari_scsi_host = NULL;
static unsigned char (*atari_scsi_reg_read)( unsigned char reg );
static void (*atari_scsi_reg_write)( unsigned char reg, unsigned char value );

#ifdef REAL_DMA
static unsigned long	atari_dma_residual, atari_dma_startaddr;
static short			atari_dma_active;
#endif


#if defined(REAL_DMA)

static int scsi_dma_is_ignored_buserr( unsigned char dma_stat )

{	int				i;
	unsigned long	addr = SCSI_DMA_READ_P( dma_addr_hi ), end_addr;

	if (dma_stat & 0x01) {

		/* A bus error happens when DMA-ing from the last page of a
		 * physical memory chunk (DMA prefetch!), but that doesn't hurt.
		 * Check for this case:
		 */
		
		for( i = 0; i < boot_info.num_memory; ++i ) {
			end_addr = boot_info.memory[i].addr +
				boot_info.memory[i].size;
			if (end_addr <= addr && addr <= end_addr + 4)
				return( 1 );
		}
	}
	return( 0 );
}


static void scsi_dma_buserr (struct intframe *fp, void *data)

{	unsigned char	dma_stat = tt_scsi_dma.dma_ctrl;

	printk( "Bad SCSI DMA inmterrupt! dma_addr=0x%08lx dma_stat=%02x dma_cnt=%08lx\n",
			SCSI_DMA_READ_P( dma_addr_hi ), dma_stat, SCSI_DMA_READ_P( dma_cnt_hi ) );
	if (dma_stat & 0x80) {
		if (!scsi_dma_is_ignored_buserr( dma_stat ))
			panic( "SCSI DMA bus error -- bad DMA programming!" );
	}
	else {
		/* Under normal circumstances we never should get to this point,
		 * since both interrupts are triggered simultaneosly and the 5380
		 * int has more priotity. When this irq is handled, that DMA
		 * interrupt is cleared. So a warning message is printed here.
		 */
		printk( "SCSI DMA intr ?? -- this shouldn't happen!\n" );
	}
}

#endif

#undef	LOST_INTR

#ifdef LOST_INTR
extern volatile unsigned long intr_count;
unsigned long curr_intr_count;

#define	CHECK_ICNT(pos) do {					\
 if (intr_count != curr_intr_count) {			\
	 printk( "INTR_COUNT changed before " pos	\
			 ": curr_cnt=%lu intr_cnt=%lu\n",	\
			 curr_intr_count, intr_count );		\
 }												\
} while( 0 )

#else

#define	CHECK_ICNT(pos)

#endif


static void scsi_tt_intr (struct intframe *fp, void *data)

{	int				dma_stat;
	unsigned long	flags;
#ifdef LOST_INTR
	unsigned long	prev_intr_count;

	prev_intr_count = curr_intr_count;
	curr_intr_count = intr_count;
#endif
	
#ifdef REAL_DMA

	dma_stat = tt_scsi_dma.dma_ctrl;

#if (NDEBUG & NDEBUG_INTR)
	printk( "scsi%d: NCR5380 interupt, DMA status = %02x\n",
			atari_scsi_host->host_no, dma_stat & 0xff );
#endif

	/* Look if it was the DMA that has interrupted: First possibility
	 * is that a bus error occured...
	 */
	if (dma_stat & 0x80) {
		if (!scsi_dma_is_ignored_buserr( dma_stat )) {
			printk( "SCSI DMA caused bus error near 0x%08lx\n",
					SCSI_DMA_READ_P( dma_addr_hi ));
			panic( "SCSI DMA bus error -- bad DMA programming!" );
		}
	}

	/* If the DMA is active but not finished, we have the the case
	 * that some other 5380 interrupt occured within the DMA transfer.
	 * This means we have residual bytes, if the desired end address
	 * is not yet reached. Maybe we have to fetch some bytes from the
	 * rest data register, too. The residual must be calculated from
	 * the address pointer, not the counter register, because only the
	 * addr reg counts bytes not yet written and pending in the rest
	 * data reg!
	 */
	if ((dma_stat & 0x02) && !(dma_stat & 0x40)) {
		atari_dma_residual =
			((struct NCR5380_hostdata *)(atari_scsi_host->hostdata))->dma_len -
				(SCSI_DMA_READ_P( dma_addr_hi ) - atari_dma_startaddr);
#if (NDEBUG & NDEBUG_DMA)
		printk( "SCSI DMA: There are %ld residual bytes.\n",
				atari_dma_residual );
#endif
		atari_scsi_fetch_restbytes();
		tt_scsi_dma.dma_ctrl = 0;
	}

	/* If the DMA is finished, fetch the rest bytes and turn it off */
	if (dma_stat & 0x40) {
		atari_dma_residual = 0;
		atari_scsi_fetch_restbytes();
		tt_scsi_dma.dma_ctrl = 0;
	}

#endif /* REAL_DMA */
	
	/* If we got this interrupt, we don't need the other one any more */
	tt_mfp.int_pn_b = (unsigned char)~0x80;

	CHECK_ICNT("calling NCR5380_intr");

	save_flags(flags);
	NCR5380_intr( 0 );
	restore_flags(flags);

#ifdef LOST_INTR
	CHECK_ICNT("returning, after NCR5380_intr");
	curr_intr_count = prev_intr_count;
#endif
}


static void scsi_falcon_intr (struct intframe *fp, void *data)

{	int				dma_stat;
	unsigned long	flags;
#ifdef LOST_INTR
	unsigned long	prev_intr_count;

	prev_intr_count = curr_intr_count;
	curr_intr_count = intr_count;
#endif
	
#ifdef REAL_DMA

	/* Turn off DMA and select sector counter register before
	 * accessing the status register (Atari recommendation!)
	 */
	st_dma.dma_mode_status = 0x90;
	dma_stat = st_dma.dma_mode_status;

	/* Bit 0 indicates some error in the DMA process... don't know
	 * what happened exactly (no further docu).
	 */
	if (!(dma_stat & 0x01)) {
		/* DMA error */
		printk( "SCSI DMA error near 0x%08lx!\n", SCSI_DMA_GETADR() );
	}

	/* If the DMA was active, but now bit 1 is not clear, it is some
	 * other 5380 interrupt that finishes the DMA transfer. We have to
	 * calculate the number of residual bytes and give a warning if
	 * bytes are stuck in the ST-DMA fifo (there's no way to reach them!)
	 */
	if (atari_dma_active && (dma_stat & 0x02)) {
		unsigned long	transferred;

		transferred = SCSI_DMA_GETADR() - atari_dma_startaddr;
		/* The ST-DMA address is incremented in 2-byte steps, but the
		 * data are written only in 16-byte chunks. If the number of
		 * transferred bytes is not divisible by 16, the remainder is
		 * lost somewhere in outer space.
		 */
		if (transferred & 15)
			printk( "SCSI DMA error: %ld bytes lost in ST-DMA fifo :-((\n",
					transferred & 15 );

		atari_dma_residual =
			((struct NCR5380_hostdata *)(atari_scsi_host->hostdata))->dma_len -
				transferred;
#if (NDEBUG & NDEBUG_DMA)
		printk( "SCSI DMA: There are %ld residual bytes.\n",
				atari_dma_residual );
#endif
	}
	else
		atari_dma_residual = 0;
	atari_dma_active = 0;
	
#endif /* REAL_DMA */

	CHECK_ICNT("calling NCR5380_intr");

	save_flags(flags);
	NCR5380_intr( 0 );
	restore_flags(flags);

#ifdef LOST_INTR
	CHECK_ICNT("returning, after NCR5380_intr");
	curr_intr_count = prev_intr_count;
#endif
}


static void atari_scsi_fetch_restbytes( void )

{	int		nr;
	char	*src, *dst;

	/* fetch rest bytes in the DMA register */
	dst = (char *)SCSI_DMA_READ_P( dma_addr_hi );
	if ((nr = ((long)dst & 3))) {
		/* there are 'nr' bytes left for the last long address before the
		   DMA pointer */
		dst = (char *)( (unsigned long)dst & ~3 );
#if (NDEBUG & NDEBUG_DMA)
		printk( "SCSI DMA: there are %d rest bytes for phys addr 0x%08lx",
				nr, (long)dst );
#endif
		dst = (char *)PTOV(dst);  /* The content of the DMA pointer
								   * is a physical address! */
#if (NDEBUG & NDEBUG_DMA)
		printk( " = virt addr 0x%08lx\n", (long)dst );
#endif
		for( src = (char *)&tt_scsi_dma.dma_restdata; nr > 0; --nr )
			*dst++ = *src++;
	}
}


static int					falcon_got_lock = 0;
static struct wait_queue	*falcon_fairness_wait = NULL;
static int					falcon_trying_lock = 0;
static struct wait_queue	*falcon_try_wait = NULL;

/* This function releases the lock on the DMA chip if there is no
 * connected command and the disconnected queue is empty. On
 * releasing, instances of falcon_get_lock are awoken, that put
 * themselves to sleep for fairness. They can now try to get the lock
 * again (but others waiting longer more probably will win).
 */

static void
falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata )

{
	if (IS_A_TT()) return;
	
	if (falcon_got_lock &&
		!hostdata->disconnected_queue &&
		!hostdata->issue_queue &&
		!hostdata->connected) {

		unsigned long	oldflags;

		save_flags(oldflags);
		cli();
		
		falcon_got_lock = 0;
		stdma_release();
		wake_up( &falcon_fairness_wait );

		restore_flags(oldflags);
	}
}

/* This function manages the locking of the ST-DMA.
 * If the DMA isn't locked already for SCSI, it trys to lock it by
 * calling stdma_lock(). But if the DMA is locked by the SCSI code and
 * there are other drivers waiting for the chip, we do not issue the
 * command immediatly but wait on 'falcon_fairness_queue'. We will be
 * waked up when the DMA is unlocked by some SCSI interrupt. After that
 * we try to get the lock again.
 * But we must be prepared that more then one instance of
 * falcon_get_lock() is waiting on the fairness queue. They should not
 * try all at once to call stdma_lock(), one is enough! For that, the
 * first one sets 'falcon_trying_lock', others that see that variable
 * set wait on the queue 'falcon_try_wait'.
 * Complicated, complicated.... Sigh...
 */

static void falcon_get_lock( void )

{
	unsigned long	oldflags;
	
	if (IS_A_TT()) return;

	save_flags(oldflags);
	cli();
	
	while( falcon_got_lock && stdma_others_waiting() )
		sleep_on( &falcon_fairness_wait );

	if (!falcon_got_lock) {
		if (!falcon_trying_lock) {
			falcon_trying_lock = 1;
			stdma_lock( scsi_falcon_intr, 0 );
			falcon_got_lock = 1;
			falcon_trying_lock = 0;
			wake_up( &falcon_try_wait );
		}
		else {
			sleep_on( &falcon_try_wait );
		}
	}	

	restore_flags(oldflags);
}


/* This is the wrapper function for NCR5380_queue_command(). It just
 * trys to get the lock on the ST-DMA (see above) and then calls the
 * original function.
 */

int atari_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))

{
	falcon_get_lock();
	return( NCR5380_queue_command( cmd, done ) );
}


				   
int atari_scsi_detect (int hostno)

{	static int called = 0;
	struct Scsi_Host *instance;

	if (boot_info.machtype != MACH_ATARI || called)
		return( 0 );
	
	atari_scsi_reg_read  = IS_A_TT() ? atari_scsi_tt_reg_read :
									   atari_scsi_falcon_reg_read;
	atari_scsi_reg_write = IS_A_TT() ? atari_scsi_tt_reg_write :
									   atari_scsi_falcon_reg_write;

	instance = scsi_register (hostno, sizeof (struct NCR5380_hostdata));
	atari_scsi_host = instance;

	NCR5380_init (instance);
	instance->irq = 0;	/* not needed, but tested in NCR5380.c */

	if (IS_A_TT()) {
		
		add_isr( IRQ_TT_MFP_SCSI, scsi_tt_intr, 0, NULL);
		tt_mfp.active_edge |= 0x80;		/* SCSI int on L->H */
		tt_mfp.int_en_a |= 0x80;		/* enabled */
		tt_mfp.int_mk_a |= 0x80;		/* not masked */
#ifdef REAL_DMA
		/* On the TT, we got a second interrupt for DMA ready and DMA buserror.
		 * Since on DMA ready we get a "normal" interrupt, too, the service
		 * routine for the second int just checks for buserrs.
		 */
		add_isr( IRQ_TT_MFP_SCSIDMA, scsi_dma_buserr, 0, NULL);
		tt_mfp.active_edge &= ~0x20;	/* DMA int on H->L */
		tt_mfp.int_en_b |= 0x80;		/* enabled */
		tt_mfp.int_mk_b |= 0x80;		/* not masked */

		tt_scsi_dma.dma_ctrl = 0;
		atari_dma_residual = 0;
#endif /* REAL_DMA */

	}
	else { /* ! IS_A_TT */
		
		/* Nothing to do for the interrupt: the ST-DMA is initialized
		 * already by atari_init_INTS()
		 */

#ifdef REAL_DMA
		atari_dma_residual = 0;
		atari_dma_active = 0;
#endif

		/* Falcon's ST-DMA can work only in lower 16 MB, so
		 * unchecked_isa_dma has to be set. But... the high level
		 * codes allocates lots (!) of memory for buffers if this is
		 * done. So the values for sg_tablesize and cmd_per_lun get
		 * lowered a bit (you can leave this out if you have 16MB of
		 * ST-Ram).
		 */
		atari_scsi_host->unchecked_isa_dma =
		atari_scsi_host->hostt->unchecked_isa_dma = 1;
#if I_HAVE_OVERRUNS == 3
		atari_scsi_host->sg_tablesize =
		atari_scsi_host->hostt->sg_tablesize = SG_NONE;
#else
		atari_scsi_host->sg_tablesize =
		atari_scsi_host->hostt->sg_tablesize = 8;
#endif
		atari_scsi_host->hostt->cmd_per_lun = 8;
	}
	
	printk( "scsi%d: options CAN_QUEUE=%d CMD_PER_LUN=%d SCATTERGATHER=%d",
			instance->host_no, instance->hostt->can_queue,
			instance->hostt->cmd_per_lun,
			instance->hostt->sg_tablesize );
	NCR5380_print_options (instance);
	printk ("\n");

	called = 1;

	return( 1 );
}

int atari_scsi_reset( Scsi_Cmnd *cmd )

{	int		rv;
	
	/* For doing the reset, SCSI interrupts must be disabled first,
	 * since the 5380 raises its IRQ line while _RST is active and we
	 * can't disable interrupts completely, since we need the timer.
	 */
	
	if (IS_A_TT())
		tt_mfp.int_en_a &= ~0x80;
	else
		mfp.int_en_b &= ~0x80;
	
	rv = NCR5380_reset( cmd );

	/* Re-enable ints and abort a maybe active DMA transfer */
	if (IS_A_TT()) {
#ifdef REAL_DMA
		tt_scsi_dma.dma_ctrl = 0;
#endif /* REAL_DMA */
		tt_mfp.int_en_a |= 0x80;
	}
	else {
#ifdef REAL_DMA
		st_dma.dma_mode_status = 0x90;
		atari_dma_active = 0;
#endif /* REAL_DMA */
		mfp.int_en_b |= 0x80;
	}

	return( rv );
}

	
const char * atari_scsi_info( void )

{	/* atari_scsi_detect() is verbose enough... */
	static const char string[] = "";
	return string;
}


#if defined(REAL_DMA) || defined(REAL_DMA_POLL) || defined(PSEUDO_DMA)

unsigned long atari_scsi_dma_setup( struct Scsi_Host *instance, void *data,
									unsigned long count, int dir )
{
	unsigned long addr = VTOP( data ),
	              cando = atari_dma_xfer_len( count );

#if (NDEBUG & NDEBUG_DMA)
	printk ("scsi%d: setting up dma, data = %p, phys = %lx, count = %ld, cando = %ld, dir = %d\n",
			instance->host_no, data, addr, count, cando, dir);
#endif

	atari_dma_startaddr = addr;	/* Needed for calculating residual later. */
  
	if (dir)
		/* write: push any dirty cache out before sending it to the
		 * peripheral. (Must be done before DMA setup, since at least the
		 * ST-DMA begins to fill internal buffers right after setup.
		 */
		cache_push( addr, cando );
	else
		/* read: invalidate any cache, may be altered after DMA without CPU
		 * knowledge
		 */
		cache_clear( addr, cando );

	if (cando == 0)
		printk( "SCSI warning: DMA programed for 0 bytes !\n" );

	if (IS_A_TT()) {
	
		tt_scsi_dma.dma_ctrl = dir;
		SCSI_DMA_WRITE_P( dma_addr_hi, addr );
		SCSI_DMA_WRITE_P( dma_cnt_hi, cando );
		tt_scsi_dma.dma_ctrl = dir | 2;
	}
	else { /* ! IS_A_TT */
  
		/* set address */
		SCSI_DMA_SETADR( addr );

		/* toggle direction bit to clear FIFO and set DMA direction */
		dir <<= 8;
		st_dma.dma_mode_status = 0x90 | dir;
		st_dma.dma_mode_status = 0x90 | (dir ^ 0x100);
		st_dma.dma_mode_status = 0x90 | dir;
		st_dma.fdc_acces_seccount = cando >> 9;

		st_dma.dma_mode_status = 0x10 | dir;
		/* need not restore value of dir, only boolean value is tested */
		atari_dma_active = 1;
	}
	
	return( cando );
}


static long atari_scsi_dma_residual( struct Scsi_Host *instance )

{
	return( atari_dma_residual );
}

/* This function calculates the number of bytes that can be transferred
 * via DMA. On the TT, this is arbitrary, but on the Falcon we have to use
 * the ST-DMA chip. There are only multiples of 512 bytes possible and
 * max. 256*512 bytes :-( This means also, that defining READ_OVERRUNS is
 * not possible, since that would require to program the DMA for n*512 - 2
 * bytes.
 */

static unsigned long atari_dma_xfer_len( unsigned long wanted_len )

{
	unsigned long	possible_len;

	if (IS_A_TT())
		/* TT SCSI DMA can transfer arbitrary #bytes */
		return( wanted_len );
	
	/* ST DMA chip is stupid -- only multiples of 512 bytes! (and max.
	 * 255*512 bytes, but this should be enough)
	 */
	possible_len =wanted_len & ~0x1ff;
	if (possible_len > 255*512)
		possible_len = 255*512;

#if (NDEBUG & NDEBUG_DMA)
	if (possible_len != wanted_len)
		printk( "Sorry, must cut DMA transfer size to %ld bytes instead of %ld\n",
				possible_len, wanted_len );
#endif

	return( possible_len );
}


#endif	/* REAL_DMA || REAL_DMA_POLL || PSEUDO_DMA */


/* NCR5380 register access functions
 *
 * There are seperate functions for TT and Falcon, because the access
 * methods are quite different. The calling macros NCR5380_read and
 * NCR5380_write call these functions via function pointers.
 */

static unsigned char atari_scsi_tt_reg_read( unsigned char reg )

{
	return( tt_scsi_regp[reg * 2] );
}

static void atari_scsi_tt_reg_write( unsigned char reg, unsigned char value )

{
	tt_scsi_regp[reg * 2] = value;
}

static unsigned char atari_scsi_falcon_reg_read( unsigned char reg )

{
	dma_wd.dma_mode_status= (u_short)(0x88 + reg);
    return( (u_char)dma_wd.fdc_acces_seccount );
}

static void atari_scsi_falcon_reg_write( unsigned char reg, unsigned char value )

{
	dma_wd.dma_mode_status = (u_short)(0x88 + reg);
	dma_wd.fdc_acces_seccount = (u_short)value;
}


#include "atari_NCR5380.c"

#endif /* CONFIG_ATARI_*_SCSI */









