/*
Device dependent functions for the Atari generic SCSI port
*/
/**************************************************************************/
/* */
/* 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 every time 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 */
/* issuing 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 tries 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 no one */
/* 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 possibilities! */
/* */
/**************************************************************************/
#include <linux/module.h>
#define NDEBUG (0)
#define NDEBUG_ABORT 0x00100000
#define NDEBUG_TAGS 0x00200000
#define NDEBUG_MERGING 0x00400000
#define AUTOSENSE
/* For the Atari version, use only polled IO or REAL_DMA */
#define REAL_DMA
/* Support tagged queuing? (on devices that are able to... :-) */
#define SUPPORT_TAGS
#define MAX_TAGS 32
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/ctype.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/blkdev.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/nvram.h>
#include <linux/bitops.h>
#include <asm/setup.h>
#include <asm/atarihw.h>
#include <asm/atariints.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/traps.h>
#include "scsi.h"
#include <scsi/scsi_host.h>
#include "atari_scsi.h"
#include "NCR5380.h"
#include <asm/atari_stdma.h>
#include <asm/atari_stram.h>
#include <asm/io.h>
#include <linux/stat.h>
#define IS_A_TT() ATARIHW_PRESENT(TT_SCSI)
#define SCSI_DMA_WRITE_P(elt,val) \
do { \
unsigned long v = val; \
tt_scsi_dma.elt##_lo = v & 0xff; \
v >>= 8; \
tt_scsi_dma.elt##_lmd = v & 0xff; \
v >>= 8; \
tt_scsi_dma.elt##_hmd = v & 0xff; \
v >>= 8; \
tt_scsi_dma.elt##_hi = v & 0xff; \
} while(0)
#define SCSI_DMA_READ_P(elt) \
(((((((unsigned long)tt_scsi_dma.elt##_hi << 8) | \
(unsigned long)tt_scsi_dma.elt##_hmd) << 8) | \
(unsigned long)tt_scsi_dma.elt##_lmd) << 8) | \
(unsigned long)tt_scsi_dma.elt##_lo)
static inline void SCSI_DMA_SETADR(unsigned long adr)
{
st_dma.dma_lo = (unsigned char)adr;
MFPDELAY();
adr >>= 8;
st_dma.dma_md = (unsigned char)adr;
MFPDELAY();
adr >>= 8;
st_dma.dma_hi = (unsigned char)adr;
MFPDELAY();
}
static inline unsigned long SCSI_DMA_GETADR(void)
{
unsigned long adr;
adr = st_dma.dma_lo;
MFPDELAY();
adr |= (st_dma.dma_md & 0xff) << 8;
MFPDELAY();
adr |= (st_dma.dma_hi & 0xff) << 16;
MFPDELAY();
return adr;
}
static inline void ENABLE_IRQ(void)
{
if (IS_A_TT())
atari_enable_irq(IRQ_TT_MFP_SCSI);
else
atari_enable_irq(IRQ_MFP_FSCSI);
}
static inline void DISABLE_IRQ(void)
{
if (IS_A_TT())
atari_disable_irq(IRQ_TT_MFP_SCSI);
else
atari_disable_irq(IRQ_MFP_FSCSI);
}
#define HOSTDATA_DMALEN (((struct NCR5380_hostdata *) \
(atari_scsi_host->hostdata))->dma_len)
/* Time (in jiffies) to wait after a reset; the SCSI standard calls for 250ms,
* we usually do 0.5s to be on the safe side. But Toshiba CD-ROMs once more
* need ten times the standard value... */
#ifndef CONFIG_ATARI_SCSI_TOSHIBA_DELAY
#define AFTER_RESET_DELAY (HZ/2)
#else
#define AFTER_RESET_DELAY (5*HZ/2)
#endif
/***************************** Prototypes *****************************/
#ifdef REAL_DMA
static int scsi_dma_is_ignored_buserr(unsigned char dma_stat);
static void atari_scsi_fetch_restbytes(void);
static long atari_scsi_dma_residual(struct Scsi_Host *instance);
static int falcon_classify_cmd(Scsi_Cmnd *cmd);
static unsigned long atari_dma_xfer_len(unsigned long wanted_len,
Scsi_Cmnd *cmd, int write_flag);
#endif
static irqreturn_t scsi_tt_intr(int irq, void *dummy);
static irqreturn_t scsi_falcon_intr(int irq, void *dummy);
static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata);
static void falcon_get_lock(void);
#ifdef CONFIG_ATARI_SCSI_RESET_BOOT
static void atari_scsi_reset_boot(void);
#endif
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;
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;
/* pointer to the dribble buffer */
static char *atari_dma_buffer;
/* precalculated physical address of the dribble buffer */
static unsigned long atari_dma_phys_buffer;
/* != 0 tells the Falcon int handler to co