* Rewrite asc driver with ``mi'' backend and parent-specific front-end

cfattach code for TC SCSI option cards  and ioasic 53c94 baseboard SCSI.
    ascvar.h:  shared softc  declarations
    asc_ioasic.c: ioasic front-end code.
    asc_tc.c: Turbochannel option (and 5000/200 basebard) front-end code.
* ioasic_attach meeds more work to eliminate pmax_type dependency
   and to verify the clocks speed passed to 53c94.
* Add prototypes for asc script entry points; should compile with
  -Wstrict-prototypes -Wmissing-prototypes.
* Use tcvar.h interface.  The usage of tc_syncbus() and tc_mb() may
  not be quite stylistically on an Alhpa, but it apparently makes no
  difference on the eerly-generation Alpha CPUs in TC Alphas.
This commit is contained in:
jonathan 1996-09-25 21:07:46 +00:00
parent 3f15a06497
commit 8eca2b2bb4
4 changed files with 583 additions and 329 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: asc.c,v 1.27 1996/08/28 19:01:36 cgd Exp $ */
/* $NetBSD: asc.c,v 1.28 1996/09/25 21:07:46 jonathan Exp $ */
/*-
* Copyright (c) 1992, 1993
@ -148,12 +148,10 @@
#include <pmax/pmax/asic.h>
#include <pmax/pmax/kmin.h>
#include <pmax/pmax/pmaxtype.h>
/*#define readback(a) { register int foo; wbflush(); foo = (a); }*/
#define readback(a) { register int foo; foo = (a); }
extern int pmax_boardtype;
/*
* In 4ns ticks.
@ -194,10 +192,8 @@ int asc_to_scsi_period[] = {
};
/*
* Internal forward declarations.
* Debugging log of SCSI operations.
*/
static void asc_reset();
static void asc_startcmd();
#ifdef DEBUG
int asc_debug = 1;
@ -217,6 +213,14 @@ struct asc_log {
void asc_DumpLog __P((char *str));
#endif
/*
* Script, scsi state, and device softc structure declarations.
* script pointers occur in both scsi state and the softc,
* so they are defined first.
*/
/*
* Scripts are entries in a state machine table.
* A script has four parts: a pre-condition, an action, a command to the chip,
@ -230,32 +234,49 @@ void asc_DumpLog __P((char *str));
* script proceeds if the action routine returns TRUE.
* See asc_intr() for how and where this is all done.
*/
struct asc_softc;
typedef struct script {
int condition; /* expected state at interrupt time */
int (*action)(); /* extra operations */
int (*action) /* extra operations */
__P((register struct asc_softc *asc, register int status,
register int ss, register int ir));
int command; /* command to the chip */
struct script *next; /* index into asc_scripts for next state */
} script_t;
/*
* script definitions
*/
/* Matching on the condition value */
#define SCRIPT_MATCH(ir, csr) ((ir) | (((csr) & 0x67) << 8))
/*
* A typedef for a script function, to use in forward declarations.
*/
typedef int
script_fn_t __P((register struct asc_softc *asc, register int status,
register int ss, register int ir));
/* forward decls of script actions */
static int script_nop(); /* when nothing needed */
static int asc_end(); /* all come to an end */
static int asc_get_status(); /* get status from target */
static int asc_dma_in(); /* start reading data from target */
static int asc_last_dma_in(); /* cleanup after all data is read */
static int asc_resume_in(); /* resume data in after a message */
static int asc_resume_dma_in(); /* resume DMA after a disconnect */
static int asc_dma_out(); /* send data to target via dma */
static int asc_last_dma_out(); /* cleanup after all data is written */
static int asc_resume_out(); /* resume data out after a message */
static int asc_resume_dma_out(); /* resume DMA after a disconnect */
static int asc_sendsync(); /* negotiate sync xfer */
static int asc_replysync(); /* negotiate sync xfer */
static int asc_msg_in(); /* process a message byte */
static int asc_disconnect(); /* process an expected disconnect */
static script_fn_t script_nop; /* when nothing needed */
static script_fn_t asc_end; /* all come to an end */
static script_fn_t asc_get_status; /* get status from target */
static script_fn_t asc_dma_in; /* start reading data from target */
static script_fn_t asc_last_dma_in; /* cleanup after all data is read */
static script_fn_t asc_resume_in; /* resume data in after a message */
static script_fn_t asc_resume_dma_in; /* resume DMA after a disconnect */
static script_fn_t asc_dma_out; /* send data to target via dma */
static script_fn_t asc_last_dma_out; /* cleanup after all data is written */
static script_fn_t asc_resume_out; /* resume data out after a message */
static script_fn_t asc_resume_dma_out; /* resume DMA after a disconnect */
static script_fn_t asc_sendsync; /* negotiate sync xfer */
static script_fn_t asc_replysync; /* negotiate sync xfer */
static script_fn_t asc_msg_in; /* process a message byte */
static script_fn_t asc_disconnect; /* process an expected disconnect */
/* Define the index into asc_scripts for various state transitions */
#define SCRIPT_DATA_IN 0
@ -379,92 +400,14 @@ script_t asc_scripts[] = {
&asc_scripts[SCRIPT_GET_STATUS]},
};
/*
* State kept for each active SCSI device.
*/
typedef struct scsi_state {
script_t *script; /* saved script while processing error */
int statusByte; /* status byte returned during STATUS_PHASE */
int error; /* errno to pass back to device driver */
u_char *dmaBufAddr; /* DMA buffer address */
u_int dmaBufSize; /* DMA buffer size */
int dmalen; /* amount to transfer in this chunk */
int dmaresid; /* amount not transfered if chunk suspended */
int buflen; /* total remaining amount of data to transfer */
char *buf; /* current pointer within scsicmd->buf */
int flags; /* see below */
int msglen; /* number of message bytes to read */
int msgcnt; /* number of message bytes received */
u_char sync_period; /* DMA synchronous period */
u_char sync_offset; /* DMA synchronous xfer offset or 0 if async */
u_char msg_out; /* next MSG_OUT byte to send */
u_char msg_in[16]; /* buffer for multibyte messages */
} State;
/* state flags */
#define DISCONN 0x001 /* true if currently disconnected from bus */
#define DMA_IN_PROGRESS 0x002 /* true if data DMA started */
#define DMA_IN 0x004 /* true if reading from SCSI device */
#define DMA_OUT 0x010 /* true if writing to SCSI device */
#define DID_SYNC 0x020 /* true if synchronous offset was negotiated */
#define TRY_SYNC 0x040 /* true if try neg. synchronous offset */
#define PARITY_ERR 0x080 /* true if parity error seen */
#define CHECK_SENSE 0x100 /* true if doing sense command */
#include <dev/tc/ascvar.h>
/*
* State kept for each active SCSI host interface (53C94).
* Internal forward declarations.
*/
struct asc_softc {
struct device sc_dev; /* us as a device */
asc_regmap_t *regs; /* chip address */
volatile int *dmar; /* DMA address register address */
u_char *buff; /* RAM buffer address (uncached) */
int sc_id; /* SCSI ID of this interface */
int myidmask; /* ~(1 << myid) */
int state; /* current SCSI connection state */
int target; /* target SCSI ID if busy */
script_t *script; /* next expected interrupt & action */
ScsiCmd *cmd[ASC_NCMD]; /* active command indexed by SCSI ID */
State st[ASC_NCMD]; /* state info for each active command */
void (*dma_start)(); /* Start dma routine */
void (*dma_end)(); /* End dma routine */
u_char *dma_next;
int dma_xfer; /* Dma len still to go */
int min_period; /* Min transfer period clk/byte */
int max_period; /* Max transfer period clk/byte */
int ccf; /* CCF, whatever that really is? */
int timeout_250; /* 250ms timeout */
int tb_ticks; /* 4ns. ticks/tb channel ticks */
#ifdef USE_NEW_SCSI
struct scsi_link sc_link; /* scsi link struct */
#endif
};
#define ASC_STATE_IDLE 0 /* idle state */
#define ASC_STATE_BUSY 1 /* selecting or currently connected */
#define ASC_STATE_TARGET 2 /* currently selected as target */
#define ASC_STATE_RESEL 3 /* currently waiting for reselect */
typedef struct asc_softc *asc_softc_t;
/*
* Dma operations.
*/
#define ASCDMA_READ 1
#define ASCDMA_WRITE 2
static void tb_dma_start(), tb_dma_end(), asic_dma_start(), asic_dma_end();
extern u_long asc_iomem;
/*
* Autoconfiguration data for config.
*/
int ascmatch __P((struct device * parent, void *cfdata, void *aux));
void ascattach __P((struct device *parent, struct device *self, void *aux));
struct cfattach asc_ca = {
sizeof(struct asc_softc), ascmatch, ascattach
};
static void asc_reset __P((asc_softc_t asc, asc_regmap_t *regs));
static void asc_startcmd __P((asc_softc_t asc, int target));
extern struct cfdriver asc_cd;
struct cfdriver asc_cd = {
@ -492,112 +435,51 @@ struct scsi_device asc_dev = {
/*
* Definition of the controller for the old auto-configuration program.
*/
void asc_start();
void asc_start __P((register ScsiCmd *scsicmd));
int asc_intr __P ((void *asc));
struct pmax_driver ascdriver = {
"asc", NULL, asc_start, 0, asc_intr,
};
void asc_minphys __P((struct buf *bp));
extern struct cfdriver ioasic_cd; /* XXX */
/*
* Match driver based on name
* bus-parent shared attach function
*/
int
ascmatch(parent, match, aux)
struct device *parent;
void *match;
void *aux;
{
struct ioasicdev_attach_args *d = aux;
struct tc_attach_args *t = aux;
void *ascaddr;
/*if (parent->dv_cfdata->cf_driver == &ioasic_cd) */
if (strncmp(d->iada_modname, "asc", TC_ROM_LLEN) &&
strncmp(d->iada_modname, "PMAZ-AA ", TC_ROM_LLEN))
return (0);
if (parent->dv_cfdata->cf_driver == &ioasic_cd)
ascaddr = (void*)d->iada_addr;
else
ascaddr = (void*)t->ta_addr;
if (badaddr(ascaddr + ASC_OFFSET_53C94, 4))
return (0);
return (1);
}
void
ascattach(parent, self, aux)
struct device *parent;
struct device *self;
void *aux;
ascattach(asc, dmabufsize, bus_speed)
register asc_softc_t asc;
int dmabufsize;
{
register struct ioasicdev_attach_args *d = aux;
register struct tc_attach_args *t = aux;
register asc_softc_t asc = (asc_softc_t) self;
register asc_regmap_t *regs;
int id, s, i;
int bufsiz;
void *ascaddr;
int unit;
if (asc->sc_dev.dv_parent->dv_cfdata->cf_driver == &ioasic_cd) {
ascaddr = (void*)MACH_PHYS_TO_UNCACHED(d->iada_addr);
} else {
ascaddr = (void*)MACH_PHYS_TO_UNCACHED(t->ta_addr);
}
unit = asc->sc_dev.dv_unit;
/*
* Initialize hw descriptor, cache some pointers
*/
asc->regs = (asc_regmap_t *)(ascaddr + ASC_OFFSET_53C94);
/*
* Set up machine dependencies.
* (1) how to do dma
* (2) timing based on turbochannel frequency
* (1) timing based on turbochannel frequency
*/
if (asc->sc_dev.dv_parent->dv_cfdata->cf_driver == &ioasic_cd) {
asc->buff = (u_char *)MACH_PHYS_TO_UNCACHED(asc_iomem);
bufsiz = 8192;
*((volatile int *)IOASIC_REG_SCSI_DMAPTR(ioasic_base)) = -1;
*((volatile int *)IOASIC_REG_SCSI_DMANPTR(ioasic_base)) = -1;
*((volatile int *)IOASIC_REG_SCSI_SCR(ioasic_base)) = 0;
asc->dma_start = asic_dma_start;
asc->dma_end = asic_dma_end;
} else
{
/*
* Fall through for turbochannel option.
*/
asc->dmar = (volatile int *)(ascaddr + ASC_OFFSET_DMAR);
asc->buff = (u_char *)(ascaddr + ASC_OFFSET_RAM);
bufsiz = PER_TGT_DMA_SIZE;
asc->dma_start = tb_dma_start;
asc->dma_end = tb_dma_end;
};
/* dma setup done in parent-specific attach code */
/*
* Now for timing. The 3max has a 25Mhz tb whereas the 3min and
* maxine are 12.5Mhz.
*/
switch (pmax_boardtype) {
case DS_3MAX:
case DS_3MAXPLUS:
switch (bus_speed) {
case ASC_SPEED_25_MHZ:
asc->min_period = ASC_MIN_PERIOD25;
asc->max_period = ASC_MAX_PERIOD25;
asc->ccf = ASC_CCF(25);
asc->timeout_250 = ASC_TIMEOUT_250(25, asc->ccf);
asc->tb_ticks = 10;
break;
case DS_3MIN:
case DS_MAXINE:
case ASC_SPEED_12_5_MHZ:
default:
asc->min_period = ASC_MIN_PERIOD12;
asc->max_period = ASC_MAX_PERIOD12;
@ -649,21 +531,13 @@ ascattach(parent, self, aux)
* We may want to try ping ponging buffers later.
*/
for (i = 0; i < ASC_NCMD; i++) {
asc->st[i].dmaBufAddr = asc->buff + bufsiz * i;
asc->st[i].dmaBufSize = bufsiz;
asc->st[i].dmaBufAddr = asc->buff + dmabufsize * i;
asc->st[i].dmaBufSize = dmabufsize;
}
/* Hack for old-sytle SCSI-device probe */
(void) pmax_add_scsi(&ascdriver, unit);
/* tie pseudo-slot to device */
if (asc->sc_dev.dv_parent->dv_cfdata->cf_driver == &ioasic_cd)
ioasic_intr_establish(parent, d->iada_cookie, TC_IPL_BIO,
asc_intr, asc);
else
tc_intr_establish(parent, t->ta_cookie, TC_IPL_BIO,
asc_intr, asc);
printf(": target %d\n", id);
@ -765,17 +639,17 @@ asc_reset(asc, regs)
* Reset chip and wait till done
*/
regs->asc_cmd = ASC_CMD_RESET;
wbflush(); DELAY(25);
tc_syncbus(); DELAY(25);
/* spec says this is needed after reset */
regs->asc_cmd = ASC_CMD_NOP;
wbflush(); DELAY(25);
tc_syncbus(); DELAY(25);
/*
* Set up various chip parameters
*/
regs->asc_ccf = asc->ccf;
wbflush(); DELAY(25);
tc_syncbus(); DELAY(25);
regs->asc_sel_timo = asc->timeout_250;
/* restore our ID */
regs->asc_cnfg1 = asc->sc_id | ASC_CNFG1_P_CHECK;
@ -786,7 +660,7 @@ asc_reset(asc, regs)
ASC_TC_PUT(regs, 0);
regs->asc_syn_p = asc->min_period;
regs->asc_syn_o = 0; /* async for now */
wbflush();
tc_mb();
}
/*
@ -895,7 +769,7 @@ asc_startcmd(asc, target)
/* preload the FIFO with the message to be sent */
regs->asc_fifo = SCSI_DIS_REC_IDENTIFY;
wbflush();
tc_mb();
/* initialize the DMA */
(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE);
@ -1051,7 +925,7 @@ again:
ASC_TC_GET(regs, len);
fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
printf("asc_intr: ignoring strange interrupt");
printf(" tc %d fifo residue\n", len, fifo);
printf(" tc %d fifo residue %d\n", len, fifo);
goto done;
}
/* FALLTHROUGH */
@ -1113,7 +987,7 @@ again:
printf("asc_intr: dmalen %d len %d fifo %d\n",
state->dmalen, len, fifo); /* XXX */
regs->asc_cmd = ASC_CMD_FLUSH;
wbflush();
tc_mb();
readback(regs->asc_cmd);
DELAY(2);
}
@ -1342,7 +1216,7 @@ again:
*/
done:
wbflush();
tc_mb();
/* watch out for HW race conditions and setup & hold time violations */
ir = regs->asc_status;
while (ir != (status = regs->asc_status))
@ -1874,13 +1748,13 @@ asc_sendsync(asc, status, ss, ir)
/* send the extended synchronous negotiation message */
regs->asc_fifo = SCSI_EXTENDED_MSG;
wbflush();
tc_mb();
regs->asc_fifo = 3;
wbflush();
tc_mb();
regs->asc_fifo = SCSI_SYNCHRONOUS_XFER;
wbflush();
tc_mb();
regs->asc_fifo = SCSI_MIN_PERIOD;
wbflush();
tc_mb();
regs->asc_fifo = ASC_MAX_OFFSET;
/* state to resume after we see the sync reply message */
state->script = asc->script + 2;
@ -1905,13 +1779,13 @@ asc_replysync(asc, status, ss, ir)
#endif
/* send synchronous transfer in response to a request */
regs->asc_fifo = SCSI_EXTENDED_MSG;
wbflush();
tc_mb();
regs->asc_fifo = 3;
wbflush();
tc_mb();
regs->asc_fifo = SCSI_SYNCHRONOUS_XFER;
wbflush();
tc_mb();
regs->asc_fifo = asc_to_scsi_period[state->sync_period] * asc->tb_ticks;
wbflush();
tc_mb();
regs->asc_fifo = state->sync_offset;
regs->asc_cmd = ASC_CMD_XFER_INFO;
readback(regs->asc_cmd);
@ -2136,131 +2010,6 @@ asc_disconnect(asc, status, ss, ir)
return (1);
}
/*
* DMA handling routines. For a turbochannel device, just set the dmar.
* For the I/O ASIC, handle the actual DMA interface.
*/
static void
tb_dma_start(asc, state, cp, flag)
asc_softc_t asc;
State *state;
caddr_t cp;
int flag;
{
if (flag == ASCDMA_WRITE)
*asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(cp);
else
*asc->dmar = ASC_DMA_ADDR(cp);
}
static void
tb_dma_end(asc, state, flag)
asc_softc_t asc;
State *state;
int flag;
{
}
static void
asic_dma_start(asc, state, cp, flag)
asc_softc_t asc;
State *state;
caddr_t cp;
int flag;
{
register volatile u_int *ssr = (volatile u_int *)
IOASIC_REG_CSR(ioasic_base);
u_int phys, nphys;
/* stop DMA engine first */
*ssr &= ~IOASIC_CSR_DMAEN_SCSI;
*((volatile int *)IOASIC_REG_SCSI_SCR(ioasic_base)) = 0;
phys = MACH_CACHED_TO_PHYS(cp);
cp = (caddr_t)mips_trunc_page(cp + NBPG);
nphys = MACH_CACHED_TO_PHYS(cp);
asc->dma_next = cp;
asc->dma_xfer = state->dmalen - (nphys - phys);
*(volatile int *)IOASIC_REG_SCSI_DMAPTR(ioasic_base) =
IOASIC_DMA_ADDR(phys);
*(volatile int *)IOASIC_REG_SCSI_DMANPTR(ioasic_base) =
IOASIC_DMA_ADDR(nphys);
if (flag == ASCDMA_READ)
*ssr |= IOASIC_CSR_SCSI_DIR | IOASIC_CSR_DMAEN_SCSI;
else
*ssr = (*ssr & ~IOASIC_CSR_SCSI_DIR) | IOASIC_CSR_DMAEN_SCSI;
wbflush();
}
static void
asic_dma_end(asc, state, flag)
asc_softc_t asc;
State *state;
int flag;
{
register volatile u_int *ssr = (volatile u_int *)
IOASIC_REG_CSR(ioasic_base);
register volatile u_int *dmap = (volatile u_int *)
IOASIC_REG_SCSI_DMAPTR(ioasic_base);
register u_short *to;
register int w;
int nb;
*ssr &= ~IOASIC_CSR_DMAEN_SCSI;
to = (u_short *)MACH_PHYS_TO_CACHED(*dmap >> 3);
*dmap = -1;
*((volatile int *)IOASIC_REG_SCSI_DMANPTR(ioasic_base)) = -1;
wbflush();
if (flag == ASCDMA_READ) {
MachFlushDCache(MACH_PHYS_TO_CACHED(
MACH_UNCACHED_TO_PHYS(state->dmaBufAddr)), state->dmalen);
if ( (nb = *((int *)IOASIC_REG_SCSI_SCR(ioasic_base))) != 0) {
/* pick up last upto6 bytes, sigh. */
/* Last byte really xferred is.. */
w = *(int *)IOASIC_REG_SCSI_SDR0(ioasic_base);
*to++ = w;
if (--nb > 0) {
w >>= 16;
*to++ = w;
}
if (--nb > 0) {
w = *(int *)IOASIC_REG_SCSI_SDR1(ioasic_base);
*to++ = w;
}
}
}
}
#ifdef notdef
/*
* Called by asic_intr() for scsi dma pointer update interrupts.
*/
void
asc_dma_intr()
{
asc_softc_t asc = &asc_cd.cd_devs[0]; /*XXX*/
u_int next_phys;
asc->dma_xfer -= NBPG;
if (asc->dma_xfer <= -NBPG) {
volatile u_int *ssr = (volatile u_int *)
IOASIC_REG_CSR(ioasic_base);
*ssr &= ~IOASIC_CSR_DMAEN_SCSI;
} else {
asc->dma_next += NBPG;
next_phys = MACH_CACHED_TO_PHYS(asc->dma_next);
}
*(volatile int *)IOASIC_REG_SCSI_DMANPTR(ioasic_base) =
IOASIC_DMA_ADDR(next_phys);
wbflush();
}
#endif /*notdef*/
#ifdef DEBUG
void

244
sys/dev/tc/asc_ioasic.c Normal file
View File

@ -0,0 +1,244 @@
/* $NetBSD: asc_ioasic.c,v 1.1 1996/09/25 21:07:54 jonathan Exp $ */
/*
* Copyright 1996 The Board of Trustees of The Leland Stanford
* Junior University. All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies. Stanford University
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
*
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <dev/tc/tcvar.h>
#include <dev/tc/ioasicvar.h>
#include <machine/autoconf.h>
#include <pmax/dev/device.h> /* XXX */
#include <pmax/dev/scsi.h> /* XXX */
#include <pmax/dev/ascreg.h> /* XXX */
#include <dev/tc/ascvar.h>
#include <mips/locore.h> /* XXX XXX bus.h needs cache-consistency*/
/*XXX*/
#include <pmax/pmax/asic.h> /* XXX ioasic register defs? */
#include <pmax/pmax/kmin.h> /* XXX ioasic register defs? */
#include <pmax/pmax/pmaxtype.h>
extern int pmax_boardtype;
/*
* Autoconfiguration data for config.
*/
int asc_ioasic_match __P((struct device *, void *, void *));
void asc_ioasic_attach __P((struct device *, struct device *, void *));
struct cfattach asc_ioasic_ca = {
sizeof(struct asc_softc), asc_ioasic_match, asc_ioasic_attach
};
/*
* DMA callback declarations
*/
extern u_long asc_iomem;
static void
asic_dma_start __P((asc_softc_t asc, State *state, caddr_t cp, int flag));
static void
asic_dma_end __P((asc_softc_t asc, State *state, int flag));
int
asc_ioasic_match(parent, match, aux)
struct device *parent;
void *match;
void *aux;
{
struct ioasicdev_attach_args *d = aux;
void *ascaddr;
if (strncmp(d->iada_modname, "asc", TC_ROM_LLEN) &&
strncmp(d->iada_modname, "PMAZ-AA ", TC_ROM_LLEN))
return (0);
/* probe for chip */
ascaddr = (void*)d->iada_addr;
if (tc_badaddr(ascaddr + ASC_OFFSET_53C94))
return (0);
return (1);
}
void
asc_ioasic_attach(parent, self, aux)
struct device *parent;
struct device *self;
void *aux;
{
register struct ioasicdev_attach_args *d = aux;
register asc_softc_t asc = (asc_softc_t) self;
int bufsiz, speed;
void *ascaddr;
int unit;
ascaddr = (void*)MACH_PHYS_TO_UNCACHED(d->iada_addr);
unit = asc->sc_dev.dv_unit;
/*
* Initialize hw descriptor, cache some pointers
*/
asc->regs = (asc_regmap_t *)(ascaddr + ASC_OFFSET_53C94);
/*
* Set up machine dependencies.
* (1) how to do dma
* (2) timing based on turbochannel frequency
*/
asc->buff = (u_char *)MACH_PHYS_TO_UNCACHED(asc_iomem);
bufsiz = 8192;
*((volatile int *)IOASIC_REG_SCSI_DMAPTR(ioasic_base)) = -1;
*((volatile int *)IOASIC_REG_SCSI_DMANPTR(ioasic_base)) = -1;
*((volatile int *)IOASIC_REG_SCSI_SCR(ioasic_base)) = 0;
asc->dma_start = asic_dma_start;
asc->dma_end = asic_dma_end;
/*
* Now for timing. The 3max has a 25Mhz tb whereas the 3min and
* maxine are 12.5Mhz.
*/
/*printf(" (bus speed: %d) ", t->ta_busspeed);*/
/* XXX don't these run at 25MHz on any ioasic??*/
switch (pmax_boardtype) {
case DS_3MAX:
case DS_3MAXPLUS:
speed = ASC_SPEED_25_MHZ;
break;
case DS_3MIN:
case DS_MAXINE:
default:
speed = ASC_SPEED_12_5_MHZ;
break;
};
ascattach(asc, bufsiz, speed);
/* tie pseudo-slot to device */
ioasic_intr_establish(parent, d->iada_cookie, TC_IPL_BIO,
asc_intr, asc);
}
/*
* DMA handling routines. For a turbochannel device, just set the dmar.
* For the I/O ASIC, handle the actual DMA interface.
*/
static void
asic_dma_start(asc, state, cp, flag)
asc_softc_t asc;
State *state;
caddr_t cp;
int flag;
{
register volatile u_int *ssr = (volatile u_int *)
IOASIC_REG_CSR(ioasic_base);
u_int phys, nphys;
/* stop DMA engine first */
*ssr &= ~IOASIC_CSR_DMAEN_SCSI;
*((volatile int *)IOASIC_REG_SCSI_SCR(ioasic_base)) = 0;
phys = MACH_CACHED_TO_PHYS(cp);
cp = (caddr_t)mips_trunc_page(cp + NBPG);
nphys = MACH_CACHED_TO_PHYS(cp);
asc->dma_next = cp;
asc->dma_xfer = state->dmalen - (nphys - phys);
*(volatile int *)IOASIC_REG_SCSI_DMAPTR(ioasic_base) =
IOASIC_DMA_ADDR(phys);
*(volatile int *)IOASIC_REG_SCSI_DMANPTR(ioasic_base) =
IOASIC_DMA_ADDR(nphys);
if (flag == ASCDMA_READ)
*ssr |= IOASIC_CSR_SCSI_DIR | IOASIC_CSR_DMAEN_SCSI;
else
*ssr = (*ssr & ~IOASIC_CSR_SCSI_DIR) | IOASIC_CSR_DMAEN_SCSI;
wbflush();
}
static void
asic_dma_end(asc, state, flag)
asc_softc_t asc;
State *state;
int flag;
{
register volatile u_int *ssr = (volatile u_int *)
IOASIC_REG_CSR(ioasic_base);
register volatile u_int *dmap = (volatile u_int *)
IOASIC_REG_SCSI_DMAPTR(ioasic_base);
register u_short *to;
register int w;
int nb;
*ssr &= ~IOASIC_CSR_DMAEN_SCSI;
to = (u_short *)MACH_PHYS_TO_CACHED(*dmap >> 3);
*dmap = -1;
*((volatile int *)IOASIC_REG_SCSI_DMANPTR(ioasic_base)) = -1;
wbflush();
if (flag == ASCDMA_READ) {
MachFlushDCache(MACH_PHYS_TO_CACHED(
MACH_UNCACHED_TO_PHYS(state->dmaBufAddr)), state->dmalen);
if ( (nb = *((int *)IOASIC_REG_SCSI_SCR(ioasic_base))) != 0) {
/* pick up last upto6 bytes, sigh. */
/* Last byte really xferred is.. */
w = *(int *)IOASIC_REG_SCSI_SDR0(ioasic_base);
*to++ = w;
if (--nb > 0) {
w >>= 16;
*to++ = w;
}
if (--nb > 0) {
w = *(int *)IOASIC_REG_SCSI_SDR1(ioasic_base);
*to++ = w;
}
}
}
}
#ifdef notdef
/*
* Called by asic_intr() for scsi dma pointer update interrupts.
*/
void
asc_dma_intr()
{
asc_softc_t asc = &asc_cd.cd_devs[0]; /*XXX*/
u_int next_phys;
asc->dma_xfer -= NBPG;
if (asc->dma_xfer <= -NBPG) {
volatile u_int *ssr = (volatile u_int *)
IOASIC_REG_CSR(ioasic_base);
*ssr &= ~IOASIC_CSR_DMAEN_SCSI;
} else {
asc->dma_next += NBPG;
next_phys = MACH_CACHED_TO_PHYS(asc->dma_next);
}
*(volatile int *)IOASIC_REG_SCSI_DMANPTR(ioasic_base) =
IOASIC_DMA_ADDR(next_phys);
wbflush();
}
#endif /*notdef*/

169
sys/dev/tc/asc_tc.c Normal file
View File

@ -0,0 +1,169 @@
/* $NetBSD: asc_tc.c,v 1.1 1996/09/25 21:07:53 jonathan Exp $ */
/*
* Copyright 1996 The Board of Trustees of The Leland Stanford
* Junior University. All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies. Stanford University
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
*
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/types.h>
#include <sys/device.h>
#include <dev/tc/tcvar.h>
#include <machine/autoconf.h>
#include <dev/tc/ioasicvar.h>
#include <pmax/dev/device.h> /* XXX */
#include <pmax/dev/scsi.h> /* XXX */
#include <pmax/dev/ascreg.h> /* XXX */
#include <dev/tc/ascvar.h>
/*XXX*/
/*
* Autoconfiguration data for config.
*/
int asc_tc_match __P((struct device *, void *, void *));
void asc_tc_attach __P((struct device *, struct device *, void *));
struct cfattach asc_tc_ca = {
sizeof(struct asc_softc), asc_tc_match, asc_tc_attach
};
/*
* DMA callbacks
*/
static void
tc_dma_start __P((struct asc_softc *asc, struct scsi_state *state,
caddr_t cp, int flag));
static void
tc_dma_end __P((struct asc_softc *asc, struct scsi_state *state,
int flag));
int
asc_tc_match(parent, match, aux)
struct device *parent;
void *match;
void *aux;
{
struct tc_attach_args *t = aux;
void *ascaddr;
if (strncmp(t->ta_modname, "PMAZ-AA ", TC_ROM_LLEN))
return (0);
ascaddr = (void*)t->ta_addr;
if (tc_badaddr(ascaddr + ASC_OFFSET_53C94))
return (0);
return (1);
}
void
asc_tc_attach(parent, self, aux)
struct device *parent;
struct device *self;
void *aux;
{
register struct tc_attach_args *t = aux;
register asc_softc_t asc = (asc_softc_t) self;
int bufsiz, speed;
void *ascaddr;
int unit;
ascaddr = (void*)MACH_PHYS_TO_UNCACHED(t->ta_addr);
unit = asc->sc_dev.dv_unit;
/*
* Initialize hw descriptor, cache some pointers
*/
asc->regs = (asc_regmap_t *)(ascaddr + ASC_OFFSET_53C94);
/*
* Set up machine dependencies.
* (1) how to do dma
* (2) timing based on turbochannel frequency
*/
/*
* Fall through for turbochannel option.
*/
asc->dmar = (volatile int *)(ascaddr + ASC_OFFSET_DMAR);
asc->buff = (u_char *)(ascaddr + ASC_OFFSET_RAM);
bufsiz = PER_TGT_DMA_SIZE;
asc->dma_start = tc_dma_start;
asc->dma_end = tc_dma_end;
/*
* Now for timing. The 3max has a 25Mhz tb whereas the 3min and
* maxine are 12.5Mhz.
*/
printf(" (bus speed: %d) ", t->ta_busspeed);
switch (t->ta_busspeed) {
case TC_SPEED_25_MHZ:
speed = ASC_SPEED_25_MHZ;
break;
default:
printf(" (unknown TC speed, assuming 12.5MHz) ");
/* FALLTHROUGH*/
case TC_SPEED_12_5_MHZ:
speed = ASC_SPEED_12_5_MHZ;
break;
};
ascattach(asc, bufsiz, speed);
/* tie pseudo-slot to device */
tc_intr_establish(parent, t->ta_cookie, TC_IPL_BIO,
asc_intr, asc);
printf(": target %d\n", asc->sc_id);
}
/*
* DMA handling routines. For a turbochannel device, just set the dmar.
* For the I/O ASIC, handle the actual DMA interface.
*/
static void
tc_dma_start(asc, state, cp, flag)
asc_softc_t asc;
State *state;
caddr_t cp;
int flag;
{
if (flag == ASCDMA_WRITE)
*asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(cp);
else
*asc->dmar = ASC_DMA_ADDR(cp);
}
static void
tc_dma_end(asc, state, flag)
asc_softc_t asc;
State *state;
int flag;
{
}

92
sys/dev/tc/ascvar.h Normal file
View File

@ -0,0 +1,92 @@
/* $NetBSD: ascvar.h,v 1.1 1996/09/25 21:07:56 jonathan Exp $ */
/*
* State kept for each active SCSI device.
*/
struct script;
typedef struct scsi_state {
struct script *script; /* saved script while processing error */
int statusByte; /* status byte returned during STATUS_PHASE */
int error; /* errno to pass back to device driver */
u_char *dmaBufAddr; /* DMA buffer address */
u_int dmaBufSize; /* DMA buffer size */
int dmalen; /* amount to transfer in this chunk */
int dmaresid; /* amount not transfered if chunk suspended */
int buflen; /* total remaining amount of data to transfer */
char *buf; /* current pointer within scsicmd->buf */
int flags; /* see below */
int msglen; /* number of message bytes to read */
int msgcnt; /* number of message bytes received */
u_char sync_period; /* DMA synchronous period */
u_char sync_offset; /* DMA synchronous xfer offset or 0 if async */
u_char msg_out; /* next MSG_OUT byte to send */
u_char msg_in[16]; /* buffer for multibyte messages */
} State;
/* state flags */
#define DISCONN 0x001 /* true if currently disconnected from bus */
#define DMA_IN_PROGRESS 0x002 /* true if data DMA started */
#define DMA_IN 0x004 /* true if reading from SCSI device */
#define DMA_OUT 0x010 /* true if writing to SCSI device */
#define DID_SYNC 0x020 /* true if synchronous offset was negotiated */
#define TRY_SYNC 0x040 /* true if try neg. synchronous offset */
#define PARITY_ERR 0x080 /* true if parity error seen */
#define CHECK_SENSE 0x100 /* true if doing sense command */
/*
* State kept for each active SCSI host interface (53C94).
*/
struct asc_softc {
struct device sc_dev; /* us as a device */
asc_regmap_t *regs; /* chip address */
volatile int *dmar; /* DMA address register address */
u_char *buff; /* RAM buffer address (uncached) */
int sc_id; /* SCSI ID of this interface */
int myidmask; /* ~(1 << myid) */
int state; /* current SCSI connection state */
int target; /* target SCSI ID if busy */
struct script *script; /* next expected interrupt & action */
ScsiCmd *cmd[ASC_NCMD]; /* active command indexed by SCSI ID */
State st[ASC_NCMD]; /* state info for each active command */
/* Start dma routine */
void (*dma_start) __P((struct asc_softc *asc,
struct scsi_state *state,
caddr_t cp, int flag));
/* End dma routine */
void (*dma_end) __P((struct asc_softc *asc,
struct scsi_state *state, int flag));
u_char *dma_next;
int dma_xfer; /* Dma len still to go */
int min_period; /* Min transfer period clk/byte */
int max_period; /* Max transfer period clk/byte */
int ccf; /* CCF, whatever that really is? */
int timeout_250; /* 250ms timeout */
int tb_ticks; /* 4ns. ticks/tb channel ticks */
#ifdef USE_NEW_SCSI
struct scsi_link sc_link; /* scsi link struct */
#endif
};
typedef struct asc_softc *asc_softc_t;
#define ASC_STATE_IDLE 0 /* idle state */
#define ASC_STATE_BUSY 1 /* selecting or currently connected */
#define ASC_STATE_TARGET 2 /* currently selected as target */
#define ASC_STATE_RESEL 3 /* currently waiting for reselect */
#define ASC_SPEED_25_MHZ 250
#define ASC_SPEED_12_5_MHZ 125
void ascattach __P((struct asc_softc *asc, int dmabufsiz, int bus_speed));
int asc_intr __P ((void *asc));
/*
* Dma operations.
*/
#define ASCDMA_READ 1
#define ASCDMA_WRITE 2