1012 lines
27 KiB
C
1012 lines
27 KiB
C
/* $NetBSD: asc_poll.c,v 1.1 1996/01/31 23:25:32 mark Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 1995 Mark Brinicombe.
|
|
* Copyright (c) 1995 Brini.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by Brini.
|
|
* 4. The name of the company nor the name of the author may be used to
|
|
* endorse or promote products derived from this software without specific
|
|
* prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*
|
|
* RiscBSD kernel project
|
|
*
|
|
* asc.c
|
|
*
|
|
* Acorn SCSI card driver
|
|
*
|
|
* Created : 01/07/95
|
|
* Last updated : 01/07/95
|
|
*
|
|
* $Id: asc_poll.c,v 1.1 1996/01/31 23:25:32 mark Exp $
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/conf.h>
|
|
#include <sys/malloc.h>
|
|
#include <sys/device.h>
|
|
#include <sys/buf.h>
|
|
#include <scsi/scsi_all.h>
|
|
#include <scsi/scsiconf.h>
|
|
#include <machine/io.h>
|
|
#include <machine/irqhandler.h>
|
|
#include <machine/katelib.h>
|
|
#include <machine/psl.h>
|
|
#include <arm32/podulebus/podulebus.h>
|
|
#include <arm32/podulebus/ascreg.h>
|
|
|
|
#define ASC_DEBUG
|
|
|
|
#ifdef ASC_DEBUG
|
|
#define dprintf(x) { int s = spltty(); printf x ; (void)splx(s); }
|
|
int ascdebug = 1;
|
|
#else
|
|
#define dprintf(x)
|
|
#endif
|
|
|
|
#define MY_MANUFACTURER 0x00
|
|
#define MY_PODULE 0x02
|
|
|
|
#define SEVERELY_BROKEN 0x01
|
|
|
|
struct asc_softc {
|
|
struct device sc_device;
|
|
int sc_podule_number;
|
|
podule_t *sc_podule;
|
|
irqhandler_t sc_ih;
|
|
u_int sc_pagereg;
|
|
u_int sc_sbic_base;
|
|
u_int sc_dmac_base;
|
|
u_int sc_intstat;
|
|
int sc_state;
|
|
struct scsi_link sc_link; /* proto for sub devices */
|
|
TAILQ_HEAD(,sbic_pending) sc_xslist; /* LIFO */
|
|
struct scsi_xfer *sc_xs; /* transfer from high level code */
|
|
int sc_timelimits[8];
|
|
};
|
|
|
|
int asc_scsi_cmd __P((struct scsi_xfer *));
|
|
void asc_minphys __P((struct buf *));
|
|
|
|
struct scsi_adapter asc_scsiswitch = {
|
|
asc_scsi_cmd, /* SCSI CMD */
|
|
asc_minphys, /* SCSI MINPHYS */
|
|
0, /* close target lun */
|
|
0, /* close target lun */
|
|
};
|
|
|
|
struct scsi_device asc_scsidev = {
|
|
NULL, /* use default error handler */
|
|
NULL, /* do not have a start function */
|
|
NULL, /* have no async handler */
|
|
NULL, /* Use default done routine */
|
|
};
|
|
|
|
#define ASC_NSEG 4
|
|
|
|
/* Declare prototypes */
|
|
|
|
int ascprint __P((void *, char *));
|
|
|
|
void init_dmac __P((struct asc_softc *));
|
|
int ascreset __P((struct asc_softc *));
|
|
int ascintr __P((void *));
|
|
int asc_scsi_cdb __P((struct asc_softc */*sc*/, char */*cdb*/, int /*cdb_size*/,
|
|
int /*device_ID*/, u_char */*data_p*/, int */*p_txcnt*/, int /*dir*/,
|
|
int /*lun*/));
|
|
|
|
int asc_asm_tx_data(int /*sbic_base*/, int /*txaddr*/, int /*txlen*/, int /*rw*/);
|
|
|
|
int asc_intwait __P((struct asc_softc */*sc*/, int /*id*/));
|
|
int tc_wait __P((struct asc_softc */*sc*/, int /*id*/));
|
|
|
|
/* I/O prototypes */
|
|
|
|
void read_sram __P((u_int /*sramaddr*/, u_int /*len*/, u_int /*dest*/));
|
|
void write_sram __P((u_int /*sramaddr*/, u_int /*len*/, u_int /*src*/));
|
|
|
|
/* Debugging prototypes */
|
|
|
|
void binary __P((int));
|
|
void dump_dmac __P((struct asc_softc *));
|
|
int dump_sbic __P((struct asc_softc *));
|
|
|
|
|
|
static char message[256];
|
|
static char status[32];
|
|
static int debug = 0;
|
|
static int txdebug = 0;
|
|
static int error_code = 0;
|
|
static int data_count = 0;
|
|
static int mess_count = 0;
|
|
static int status_count = 0;
|
|
|
|
static int current_id;
|
|
static struct scsi_xfer *current_xs;
|
|
static int current_txlen;
|
|
static int current_txdata;
|
|
|
|
/*
|
|
* int poduleprobe(struct device *parent, void *match, void *aux)
|
|
*
|
|
* Probe for the podule.
|
|
*/
|
|
|
|
int
|
|
ascprobe(parent, match, aux)
|
|
struct device *parent;
|
|
void *match;
|
|
void *aux;
|
|
{
|
|
struct podule_attach_args *pa = (void *)aux;
|
|
int podule;
|
|
|
|
podule = findpodule(MY_MANUFACTURER, MY_PODULE, pa->pa_podule_number);
|
|
|
|
/* Fail if we did not find it */
|
|
|
|
if (podule == -1)
|
|
return(0);
|
|
|
|
/* We found it */
|
|
|
|
pa->pa_podule_number = podule;
|
|
pa->pa_podule = &podules[podule];
|
|
|
|
return(1);
|
|
}
|
|
|
|
|
|
/*
|
|
* void poduleattach(struct device *parent, struct device *dev, void *aux)
|
|
*
|
|
* Attach podule.
|
|
*/
|
|
|
|
void
|
|
ascattach(parent, self, aux)
|
|
struct device *parent;
|
|
struct device *self;
|
|
void *aux;
|
|
{
|
|
struct asc_softc *sc = (void *)self;
|
|
struct podule_attach_args *pa = (void *)aux;
|
|
int error;
|
|
|
|
sc->sc_podule_number = pa->pa_podule_number;
|
|
if (sc->sc_podule_number == -1)
|
|
panic("Podule has disappeared !");
|
|
|
|
sc->sc_podule = &podules[sc->sc_podule_number];
|
|
podules[sc->sc_podule_number].attached = 1;
|
|
|
|
printf("\n");
|
|
|
|
sc->sc_pagereg = sc->sc_podule->fast_base + ASC_PAGEREG;
|
|
sc->sc_sbic_base = sc->sc_podule->mod_base + ASC_SBIC;
|
|
sc->sc_dmac_base = sc->sc_podule->mod_base + ASC_DMAC;
|
|
sc->sc_intstat = sc->sc_podule->fast_base + ASC_INTSTATUS;
|
|
|
|
|
|
/* Claiming a podule IRQ is something like this */
|
|
|
|
sc->sc_ih.ih_func = ascintr;
|
|
sc->sc_ih.ih_arg = sc;
|
|
sc->sc_ih.ih_level = IPL_BIO;
|
|
if (irq_claim(IRQ_PODULE /*IRQ_EXPCARD0 + sc->sc_podule_number*/, &sc->sc_ih))
|
|
panic("Cannot install IRQ handler\n");
|
|
|
|
sc->sc_link.adapter_softc = sc;
|
|
sc->sc_link.adapter_target = 7;
|
|
sc->sc_link.adapter = &asc_scsiswitch;
|
|
sc->sc_link.device = &asc_scsidev;
|
|
sc->sc_link.openings = 1;
|
|
TAILQ_INIT(&sc->sc_xslist);
|
|
|
|
sc->sc_state = 0;
|
|
error = ascreset(sc);
|
|
|
|
if (error != ASC_SUCCESS) {
|
|
sc->sc_state = SEVERELY_BROKEN;
|
|
printf("asc: reset failed err=%d - DRIVER IS DEAD\n", error);
|
|
}
|
|
|
|
/*
|
|
* attach all scsi units on us
|
|
*/
|
|
|
|
config_found(self, &sc->sc_link, ascprint);
|
|
}
|
|
|
|
|
|
/*
|
|
* print diag if pnp is NULL else just extra
|
|
*/
|
|
|
|
int
|
|
ascprint(auxp, pnp)
|
|
void *auxp;
|
|
char *pnp;
|
|
{
|
|
if (pnp == NULL)
|
|
return(UNCONF);
|
|
return(QUIET);
|
|
}
|
|
|
|
|
|
struct cfdriver asccd = {
|
|
NULL, "asc", ascprobe, ascattach, DV_DULL, sizeof(struct asc_softc),
|
|
NULL, 0
|
|
};
|
|
|
|
|
|
int
|
|
asc_intwait(sc, id)
|
|
struct asc_softc *sc;
|
|
int id;
|
|
{
|
|
int i = 0;
|
|
int intr;
|
|
|
|
while (((intr = ReadByte(sc->sc_intstat)) & IS_SBIC_IRQ) == 0) {
|
|
if (++i > sc->sc_timelimits[id]) {
|
|
dprintf(("SBIC interrupt timed out %02x\n", intr));
|
|
return(ASC_IRQ_TIMED_OUT);
|
|
}
|
|
DELAY(1);
|
|
}
|
|
return(ASC_SUCCESS);
|
|
}
|
|
|
|
|
|
int tc_wait(sc, id)
|
|
struct asc_softc *sc;
|
|
int id;
|
|
{
|
|
u_int dmac_base = sc->sc_dmac_base;
|
|
u_int intstat = sc->sc_intstat;
|
|
u_int clearint = sc->sc_podule->fast_base + ASC_CLRINT;
|
|
int i = 0;
|
|
|
|
dprintf(("Waiting for DMAC interrupt\n"));
|
|
|
|
while ((ReadByte(intstat) & IS_DMAC_IRQ) == 0) {
|
|
if (++i > sc->sc_timelimits[id]) {
|
|
dprintf(("\nDMAC interrupt timed out\n"));
|
|
#ifdef ASC_DEBUG
|
|
if (ascdebug) {
|
|
/* dump_dmac(sc);*/
|
|
/* dump_sbic(sc);*/
|
|
}
|
|
#endif
|
|
return(ASC_DMA_TX_TIMED_OUT);
|
|
}
|
|
}
|
|
|
|
WriteByte(clearint, 0); /* clear TC int on new board */
|
|
|
|
WriteDMAC(DMAC_MASKREG, DMAC_SET_MASK); /* Set DMA mask */
|
|
return(0);
|
|
}
|
|
|
|
|
|
void
|
|
init_dmac(sc)
|
|
struct asc_softc *sc;
|
|
{
|
|
u_int dmac_base = sc->sc_dmac_base;
|
|
|
|
dprintf(("init_dmac:\n"));
|
|
WriteDMAC(DMAC_INITIALISE, 0);
|
|
WriteDMAC(DMAC_INITIALISE, DMAC_Bits);
|
|
WriteDMAC(DMAC_CHANNEL, 0);
|
|
WriteDMAC(DMAC_DEVCON1, DMAC_Ctrl1);
|
|
WriteDMAC(DMAC_DEVCON2, DMAC_Ctrl2);
|
|
}
|
|
|
|
|
|
int
|
|
ascreset(sc)
|
|
struct asc_softc *sc;
|
|
{
|
|
u_int pagereg = sc->sc_pagereg;
|
|
u_int sbic_base = sc->sc_sbic_base;
|
|
u_int dmac_base = sc->sc_dmac_base;
|
|
int loop;
|
|
int error;
|
|
|
|
dprintf(("ascreset:\n"));
|
|
/* dprintf(("pagereg=%08x\n", (u_int) sc->sc_pagereg));
|
|
dprintf(("sbic=%08x\n", (u_int) sc->sc_sbic_base));
|
|
dprintf(("dmac=%08x\n", (u_int) sc->sc_dmac_base));
|
|
dprintf(("adapter=%d\n", sc->sc_link.adapter_target));*/
|
|
|
|
/* Set up timeouts */
|
|
|
|
for (loop = 0; loop < 8; ++loop)
|
|
sc->sc_timelimits[loop] = 500000;
|
|
|
|
/* Reset the hardware */
|
|
|
|
WriteByte(pagereg, 0x80);
|
|
DELAY(500000);
|
|
WriteByte(pagereg, 0x00);
|
|
DELAY(250000);
|
|
|
|
init_dmac(sc);
|
|
|
|
WriteSBIC(SBIC_OWNID, sc->sc_link.adapter_target
|
|
| SBIC_ID_FS_8_10 | SBIC_ID_EAF);
|
|
|
|
WriteSBIC(SBIC_COMMAND, SBIC_CMD_Reset);
|
|
|
|
/* Any responce ? */
|
|
|
|
if (asc_intwait(sc, sc->sc_link.adapter_target) == ASC_SUCCESS) {
|
|
dprintf(("aux status = %02x\n", ReadByte(sc->sc_sbic_base + SBIC_AUX_STATUS)));
|
|
error = ReadSBIC(SBIC_SCSISTAT);
|
|
if (error == SBIC_ResetOk || error == SBIC_ResetAFOk) {
|
|
if (error == SBIC_ResetOk)
|
|
printf("asc: WD33C93 advanced features not enabled\n");
|
|
WriteSBIC(SBIC_CONTROL, SBIC_CTL_NO_DMA); /* Burst DMA mode */
|
|
WriteSBIC(SBIC_TIMEREG, 0x20); /* timeout 250mS */
|
|
WriteSBIC(SBIC_SYNCTX, 0x20); /* min tx time */
|
|
WriteSBIC(SBIC_TARGETLUN, 0x00);
|
|
WriteSBIC(SBIC_SOURCEID, 0x20);
|
|
return(ASC_SUCCESS);
|
|
} else {
|
|
printf("asc: WD33C39 reset status = %02x\n", error);
|
|
return(ASC_CHECK_STATUS);
|
|
}
|
|
} else {
|
|
return(ASC_IRQ_TIMED_OUT);
|
|
}
|
|
}
|
|
|
|
/* Do a scsi command. */
|
|
|
|
struct scsi_xfer *cur_xs;
|
|
|
|
int
|
|
asc_scsi_cmd(xs)
|
|
struct scsi_xfer *xs;
|
|
{
|
|
struct scsi_link *sl = xs->sc_link;
|
|
struct asc_softc *sc = (struct asc_softc *)sl->adapter_softc;
|
|
int size;
|
|
int err;
|
|
|
|
if (sl->target == sl->adapter_target)
|
|
return(ESCAPE_NOT_SUPPORTED);
|
|
|
|
if (sc->sc_state == SEVERELY_BROKEN) {
|
|
xs->error = XS_DRIVER_STUFFUP;
|
|
scsi_done(xs);
|
|
return(COMPLETE);
|
|
}
|
|
|
|
if (debug) {
|
|
dprintf(("id=%d lun=%d cmdlen=%d datalen=%d opcode=%02x flags=%08x status=%02x retries=%02x\n",
|
|
sl->target, sl->lun, xs->cmdlen, xs->datalen, xs->cmd->opcode,
|
|
xs->flags, xs->status, xs->retries));
|
|
}
|
|
|
|
size = xs->datalen;
|
|
err = asc_scsi_cdb(sc, (char *)xs->cmd, xs->cmdlen, sl->target, (u_char *)xs->data, &size, xs->flags, sl->lun);
|
|
xs->resid = size;
|
|
xs->status = 0;
|
|
if (err == 0 && status_count > 0) {
|
|
struct scsi_sense ss;
|
|
int ss_err;
|
|
int loop;
|
|
|
|
xs->status = status[0];
|
|
|
|
printf("ascstatus (%d) = ", status_count);
|
|
for (loop = 0; loop < status_count; ++loop)
|
|
printf("%02x ", status[status_count]);
|
|
printf("\n");
|
|
|
|
if (status[0] != 0) {
|
|
char *ptr = (char *)xs->cmd;
|
|
u_int sbic_base = sc->sc_sbic_base;
|
|
int loop;
|
|
|
|
dprintf(("id=%d lun=%d cmdlen=%d datalen=%d opcode=%02x flags=%08x status=%02x retries=%02x\n",
|
|
sl->target, sl->lun, xs->cmdlen, xs->datalen, xs->cmd->opcode,
|
|
xs->flags, xs->status, xs->retries));
|
|
|
|
for (loop = 0; loop < xs->cmdlen; ++loop)
|
|
printf("%02x ", ptr[loop]);
|
|
printf("\n");
|
|
|
|
WriteByte(sbic_base + SBIC_ADDRREG, SBIC_CDB1TSECT);
|
|
|
|
for (loop = 0; loop < xs->cmdlen; loop++) {
|
|
printf("%02x ", ReadByte(sbic_base + SBIC_DATAREG));
|
|
}
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
|
|
switch (status[0] & 0xfe) { /* Bit 0 of status is reserved */
|
|
case SCSI_OK : /* GOOD */
|
|
break;
|
|
case SCSI_CHECK : /* CHECK CONDITION */
|
|
if (debug) {
|
|
dprintf(("Getting sense"));
|
|
}
|
|
ss.opcode = REQUEST_SENSE;
|
|
ss.byte2 = sl->lun << 5;
|
|
ss.unused[0] = 0;
|
|
ss.unused[1] = 0;
|
|
ss.length = sizeof(struct scsi_sense_data);
|
|
ss.control = 0;
|
|
|
|
size = sizeof(struct scsi_sense_data);
|
|
ss_err = asc_scsi_cdb(sc, (char *)&ss, sizeof(struct scsi_sense),
|
|
sl->target, (u_char *)&xs->sense, &size,
|
|
SCSI_DATA_IN, sl->lun);
|
|
if (ss_err != 0) {
|
|
dprintf(("Failed to get sense data err = %d stcount=%d %02x", ss_err, status_count, status[0]));
|
|
} else {
|
|
if (debug) {
|
|
dprintf((" => %02x %02x\n", xs->sense.extended_flags,
|
|
xs->sense.extended_extra_bytes[3]));
|
|
}
|
|
}
|
|
|
|
err = ASC_READ_SENSE;
|
|
break;
|
|
case SCSI_BUSY : /* BUSY */
|
|
err = ASC_BUSY;
|
|
break;
|
|
default :
|
|
dprintf(("Non zero status - %02x count=%d", status[0], status_count));
|
|
err = ASC_READ_SENSE;
|
|
break;
|
|
}
|
|
}
|
|
if (debug)
|
|
dprintf(("err = %02x resid=%d\n", err, xs->resid));
|
|
switch (err) {
|
|
case ASC_SUCCESS :
|
|
xs->error = XS_NOERROR;
|
|
break;
|
|
case ASC_CHECK_STATUS :
|
|
xs->error = XS_DRIVER_STUFFUP;
|
|
break;
|
|
case ASC_IRQ_TIMED_OUT :
|
|
xs->error = XS_TIMEOUT;
|
|
break;
|
|
case ASC_UNEXPECTED_STATUS :
|
|
xs->error = XS_TIMEOUT;
|
|
break;
|
|
case ASC_DMA_TX_TIMED_OUT :
|
|
xs->error = XS_TIMEOUT;
|
|
break;
|
|
case ASC_SELECT_TIMED_OUT :
|
|
xs->error = XS_TIMEOUT;
|
|
break;
|
|
case ASC_READ_SENSE:
|
|
xs->error = XS_SENSE;
|
|
break;
|
|
case ASC_BUSY:
|
|
xs->error = XS_BUSY;
|
|
break;
|
|
default:
|
|
xs->error = XS_DRIVER_STUFFUP;
|
|
break;
|
|
}
|
|
|
|
scsi_done(xs);
|
|
|
|
return(COMPLETE);
|
|
}
|
|
|
|
|
|
void
|
|
asc_minphys(bp)
|
|
struct buf *bp;
|
|
{
|
|
/* if (bp->b_bcount > (ASC_NSEG * NBPG))
|
|
bp->b_bcount = (ASC_NSEG * NBPG);*/
|
|
minphys(bp);
|
|
}
|
|
|
|
int
|
|
ascintr(arg)
|
|
void *arg;
|
|
{
|
|
struct asc_softc *sc = (struct asc_softc *)arg;
|
|
int intr;
|
|
|
|
dprintf(("ascintr:"));
|
|
intr = ReadByte(sc->sc_intstat);
|
|
dprintf(("%02x\n", intr));
|
|
|
|
#if notyet
|
|
if (!(intr & IS_IRQ_REQ)) {
|
|
disable_irq(IRQ_PODULE);
|
|
return(0);
|
|
}
|
|
if (intr & IS_SBIC_IRQ)
|
|
asc_sbicintr(sc);
|
|
if (intr & IS_DMAC_IRQ)
|
|
asc_dmacintr(sc);
|
|
#endif
|
|
|
|
disable_irq(IRQ_PODULE);
|
|
return(0);
|
|
}
|
|
|
|
|
|
#if 0
|
|
/* I/O transfer routines. */
|
|
|
|
void
|
|
read_sram(sramaddr, len, dest)
|
|
u_int sramaddr;
|
|
u_int len;
|
|
u_int dest;
|
|
{
|
|
int loop;
|
|
u_short *addr;
|
|
|
|
addr = (u_short *)dest;
|
|
for (loop = 0; loop < len; loop +=2 ) {
|
|
*addr++ = ReadShort(sramaddr);
|
|
sramaddr += 4;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
write_sram(sramaddr, len, src)
|
|
u_int sramaddr;
|
|
u_int len;
|
|
u_int src;
|
|
{
|
|
int loop;
|
|
u_short *addr;
|
|
|
|
addr = (u_short *)src;
|
|
for (loop = 0; loop < len; loop +=2 ) {
|
|
WriteShort(sramaddr, *addr++);
|
|
sramaddr += 4;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#ifdef ASC_DEBUG
|
|
|
|
/* Debugging functions */
|
|
|
|
void binary(i)
|
|
int i;
|
|
{
|
|
int j = 128;
|
|
|
|
dprintf((" ="));
|
|
while (j) {
|
|
if (j & i) {
|
|
dprintf((" 1"));
|
|
} else {
|
|
dprintf((" 0"));
|
|
}
|
|
j = j / 2;
|
|
}
|
|
dprintf(("\n"));
|
|
}
|
|
|
|
void dump_dmac(sc)
|
|
struct asc_softc *sc;
|
|
{
|
|
unsigned int dmac_base = sc->sc_podule->mod_base + ASC_DMAC;
|
|
int sum;
|
|
|
|
printf("\n\n");
|
|
printf("\nContents of DMA Controller Registers :-\n");
|
|
printf("Channel Select ---- ---- ---- BASE SEL3 SEL2 SEL1 SEL0");
|
|
binary(ReadDMAC(DMAC_CHANNEL));
|
|
printf("Device Control AKL RQL EXW ROT CMP DDMA AHLD MTM");
|
|
binary(ReadDMAC(DMAC_DEVCON1));
|
|
printf("Device Control ---- ---- ---- ---- ---- ---- WEV BHLD");
|
|
binary(ReadDMAC(DMAC_DEVCON2));
|
|
printf("Channel 0 Mode **TMODE** ADIR AUTI **TDIR*** ---- WORD");
|
|
binary(ReadDMAC(DMAC_MODECON));
|
|
printf("Status Register RQ3 RQ2 RQ1 RQ0 TC3 TC2 TC1 TC0");
|
|
binary(ReadDMAC(DMAC_STATUS));
|
|
printf("Request Register -- ---- ---- ---- SRQ3 SRQ2 SRQ1 SRQ0");
|
|
binary(ReadDMAC(DMAC_REQREG));
|
|
printf("Mask Register ---- ---- ---- ---- M3 M2 M1 M0");
|
|
binary(ReadDMAC(DMAC_MASKREG));
|
|
|
|
WriteDMAC(DMAC_CHANNEL, 0); /* ch0 */
|
|
sum = ReadDMAC(DMAC_TXCNTLO);
|
|
sum = sum + ReadDMAC(DMAC_TXCNTHI)*256;
|
|
printf("Channel 0 Transfer Count $%x \n", sum);
|
|
sum = ReadDMAC(DMAC_TXADRLO);
|
|
sum = sum + ReadDMAC(DMAC_TXADRMD)*256;
|
|
sum = sum + ReadDMAC(DMAC_TXADRHI)*65536;
|
|
printf("Channel 0 Transfer Address $%x \n", sum);
|
|
|
|
WriteDMAC(DMAC_CHANNEL, 1); /* ch0 */
|
|
sum = ReadDMAC(DMAC_TXCNTLO);
|
|
sum = sum + ReadDMAC(DMAC_TXCNTHI)*256;
|
|
printf("Channel 1 Transfer Count $%x \n", sum);
|
|
sum = ReadDMAC(DMAC_TXADRLO);
|
|
sum = sum + ReadDMAC(DMAC_TXADRMD)*256;
|
|
sum = sum + ReadDMAC(DMAC_TXADRHI)*65536;
|
|
printf("Channel 1 Transfer Address $%x \n", sum);
|
|
}
|
|
|
|
|
|
int dump_sbic(sc)
|
|
struct asc_softc *sc;
|
|
{
|
|
u_int sbic_base = sc->sc_sbic_base;
|
|
int i, j;
|
|
|
|
printf("\n\n");
|
|
printf("\nAuxiliary status INT LCI BSY CIP 0 0 PE DBR");
|
|
binary(ReadByte(sbic_base + SBIC_AUX_STATUS));
|
|
printf("Own ID FS1 FS0 0 EHP EAF ID2 ID1 ID0");
|
|
binary(ReadSBIC(SBIC_OWNID));
|
|
printf("Control register DM2 DM1 DM0 HHP EDI IDI HA HSP");
|
|
binary(ReadSBIC(SBIC_CONTROL));
|
|
printf("Target LUN TLV DOK 0 0 0 TL2 TL1 TL0");
|
|
binary(ReadSBIC(SBIC_TARGETLUN));
|
|
printf("Synchronous Tx 0 TP2 TP1 TP0 OF3 OF2 OF1 OF0");
|
|
binary(ReadSBIC(SBIC_SYNCTX));
|
|
printf("Destination ID SCC DPD 0 0 0 DI2 DI1 DI0");
|
|
binary(ReadSBIC(SBIC_DESTID));
|
|
printf("Source ID ER ES DSP 0 SIV SI2 SI1 SI0");
|
|
binary(ReadSBIC(SBIC_SOURCEID));
|
|
printf("SCSI status **Interrupt type*** **Int. qualifier**");
|
|
j = ReadSBIC(SBIC_SCSISTAT); binary(j);
|
|
printf("Timeout period");
|
|
binary(ReadSBIC(SBIC_TIMEREG));
|
|
printf("Command Phase ");
|
|
binary(ReadSBIC(SBIC_COMPHASE));
|
|
printf("Command code = %x\n", ReadSBIC(SBIC_COMMAND));
|
|
|
|
i = WriteByte(sbic_base + SBIC_ADDRREG, SBIC_CDB1TSECT); /* pre-select reg. */
|
|
printf("CDB contents:-\n");
|
|
for (i = 0; i < 6; ++i) {
|
|
printf("%2d ", i);
|
|
binary(ReadByte(sbic_base + SBIC_DATAREG));
|
|
}
|
|
|
|
i = WriteByte(sbic_base + SBIC_ADDRREG, SBIC_TXCOUNT1); /* pre-select reg. */
|
|
i = ReadByte(sbic_base + SBIC_DATAREG) * 0x10000;
|
|
i = i + ReadByte(sbic_base + SBIC_DATAREG) * 0x100;
|
|
i = i + ReadByte(sbic_base + SBIC_DATAREG);
|
|
printf("Transfer count = $%x\n", i);
|
|
|
|
return(j);
|
|
}
|
|
|
|
#endif
|
|
#endif
|
|
|
|
int asc_tx_data(sc, txaddr, txlen, rw, device_ID)
|
|
struct asc_softc *sc;
|
|
int txaddr; /* address in main memory to read/write data */
|
|
int txlen; /* transfer length in bytes */
|
|
int rw; /* 0 = read from target, 1 = write to target */
|
|
int device_ID;
|
|
/* break transfer up into 'blklen' blocks and check interrupt between blocks */
|
|
{
|
|
u_int sbic_base = sc->sc_sbic_base;
|
|
int byte;
|
|
int i;
|
|
int status;
|
|
|
|
if (rw & SCSI_DATA_OUT) {
|
|
WriteSBIC(SBIC_COMMAND, SBIC_Sel_tx_wATN); /* initiate command */
|
|
|
|
if (txdebug)
|
|
dprintf(("Writing %d bytes\n", txlen));
|
|
|
|
while (txlen > 0) {
|
|
do {
|
|
status = ReadByte(sbic_base + SBIC_AUX_STATUS);
|
|
} while ((status & 1) == 0 && (status & 128) == 0);
|
|
if (status & 128) break;
|
|
byte = *((u_char *)txaddr);
|
|
WriteSBIC(SBIC_DATA, byte);
|
|
++txaddr;
|
|
--txlen;
|
|
}
|
|
if (txdebug)
|
|
dprintf(("tx left = %d\n", txlen));
|
|
return(txlen);
|
|
}
|
|
if (rw & SCSI_DATA_IN) { /* data transfer in, ie read */
|
|
WriteSBIC(SBIC_COMMAND, SBIC_Sel_tx_wATN); /* initiate command */
|
|
|
|
if (txdebug)
|
|
dprintf(("Reading %d bytes ... ", txlen));
|
|
|
|
while (txlen > 0) {
|
|
do {
|
|
status = ReadByte(sbic_base + SBIC_AUX_STATUS);
|
|
} while ((status & 1) == 0 && (status & 128) == 0);
|
|
if (status & 128) break;
|
|
byte = ReadSBIC(SBIC_DATA);
|
|
*((u_char *)txaddr) = byte;
|
|
++txaddr;
|
|
--txlen;
|
|
}
|
|
if (txdebug)
|
|
dprintf(("tx left = %d\n", txlen));
|
|
return(txlen);
|
|
}
|
|
return(txlen);
|
|
}
|
|
|
|
|
|
int end_of_com(sc, device_ID, data_p, p_txcnt)
|
|
struct asc_softc *sc;
|
|
int device_ID; /* current device number */
|
|
u_char *data_p; /* current data pointer */
|
|
int *p_txcnt;
|
|
{
|
|
u_int sbic_base = sc->sc_sbic_base;
|
|
int i;
|
|
int end_found = 0;
|
|
char *mess_p = message;
|
|
char *status_p = status;
|
|
int phase;
|
|
int aux;
|
|
int dummy;
|
|
int ddone = 0;
|
|
int dst = 0;
|
|
|
|
if (p_txcnt && *p_txcnt > 0) {
|
|
printf("p_txcnt=%d\n", *p_txcnt);
|
|
debug = 1;
|
|
dst = 1;
|
|
} else debug = 0;
|
|
|
|
do {
|
|
error_code = asc_intwait(sc, device_ID);
|
|
|
|
if ((error_code == ASC_IRQ_TIMED_OUT) & debug) {
|
|
dprintf(("IRQ timedout\n"));
|
|
dprintf(("Aborting "));
|
|
WriteSBIC(SBIC_COMMAND, SBIC_Abort); /* Initiate command */
|
|
error_code = asc_intwait(sc, device_ID);
|
|
dprintf((" - %02x\n", error_code));
|
|
return(ASC_IRQ_TIMED_OUT);
|
|
}
|
|
|
|
aux = ReadByte(sbic_base + SBIC_AUX_STATUS);
|
|
i = ReadSBIC(SBIC_SCSISTAT); /* read SCSI status */
|
|
phase = ReadSBIC(SBIC_COMPHASE); /* read SCSI command phase*/
|
|
|
|
if (debug && !(i == 0x19 && ddone != 0))
|
|
dprintf(("SCSI status for switch is %02x cp=%02x aux=%02x\n", i, phase, aux));
|
|
|
|
switch(i) {
|
|
|
|
case 0x42:
|
|
if (debug)
|
|
dprintf(("Select timeout - Disconnected\n"));
|
|
error_code = ASC_SELECT_TIMED_OUT;
|
|
end_found = 1;
|
|
break;
|
|
|
|
case 0x85 :
|
|
if (debug)
|
|
dprintf(("Disconnected\n"));
|
|
end_found = 1;
|
|
break;
|
|
|
|
case 0x16: /* Select and transfer completed OK */
|
|
if (debug)
|
|
dprintf(("Select and transfer complete\n"));
|
|
break;
|
|
|
|
case 0x49: /* unexpected data in */
|
|
if (debug)
|
|
dprintf(("Unexpected data in phase\n"));
|
|
WriteSBIC(SBIC_COMMAND, 0xa0); /* transfer info, single byte */
|
|
while (!(ReadByte(sbic_base + SBIC_AUX_STATUS) & 1)); /* wait for DBR set */
|
|
if (*p_txcnt > 0) {
|
|
*data_p++ = ReadSBIC(SBIC_DATA); /* read out a byte */
|
|
*p_txcnt -= 1;
|
|
} else {
|
|
dummy = ReadSBIC(SBIC_DATA);
|
|
}
|
|
break;
|
|
|
|
case 0x19: /* expected data in */
|
|
if (debug && ddone == 0)
|
|
dprintf(("Data in phase requested\n"));
|
|
WriteSBIC(SBIC_COMMAND, 0xa0); /* transfer info, single byte */
|
|
while (!(ReadByte(sbic_base + SBIC_AUX_STATUS) & 1)); /* wait for DBR set */
|
|
if (*p_txcnt > 0) {
|
|
*data_p++ = ReadSBIC(SBIC_DATA); /* read out a byte */
|
|
*p_txcnt -= 1;
|
|
} else {
|
|
dummy = ReadSBIC(SBIC_DATA);
|
|
}
|
|
ddone = 1;
|
|
break;
|
|
|
|
case 0x48: /* unexpected data out */
|
|
if (debug)
|
|
dprintf(("Unexpected data out phase\n"));
|
|
WriteSBIC(SBIC_COMMAND, 0xa0); /* transfer info, single byte */
|
|
while (!(ReadByte(sbic_base + SBIC_AUX_STATUS) & 1)); /* wait for DBR set */
|
|
if (*p_txcnt > 0) {
|
|
WriteSBIC(SBIC_DATA, *data_p++);
|
|
*p_txcnt -= 1;
|
|
} else {
|
|
WriteSBIC(SBIC_DATA, 0);
|
|
}
|
|
break;
|
|
case 0x18: /* expected data out */
|
|
if (debug)
|
|
dprintf(("Data out phase requested\n"));
|
|
WriteSBIC(SBIC_COMMAND, 0xa0); /* transfer info, single byte */
|
|
while (!(ReadByte(sbic_base + SBIC_AUX_STATUS) & 1)); /* wait for DBR set */
|
|
if (*p_txcnt > 0) {
|
|
WriteSBIC(SBIC_DATA, *data_p++);
|
|
*p_txcnt -= 1;
|
|
} else {
|
|
WriteSBIC(SBIC_DATA, 0);
|
|
}
|
|
break;
|
|
|
|
case 0x4b: /* unexpected status in */
|
|
if (debug)
|
|
dprintf(("unexpected status in\n"));
|
|
WriteSBIC(SBIC_COMMAND, 0xa0); /* transfer info, single byte */
|
|
while (!(ReadByte(sbic_base + SBIC_AUX_STATUS) & 1)); /* wait for DBR set */
|
|
*status_p++ = ReadSBIC(SBIC_DATA); /* read out a byte */
|
|
if (debug) dprintf(("Message or status byte was %x\n", *(status_p-1)));
|
|
status_count++;
|
|
if (status_count > 32) status_p = status;
|
|
break;
|
|
|
|
case 0x1b: /* status in */
|
|
if (debug)
|
|
dprintf(("Status in\n"));
|
|
WriteSBIC(SBIC_COMMAND, 0xa0); /* transfer info, single byte */
|
|
while (!(ReadByte(sbic_base + SBIC_AUX_STATUS) & 1)); /* wait for DBR set */
|
|
*status_p++ = ReadSBIC(SBIC_DATA); /* read out a byte */
|
|
if (debug) dprintf(("Message or status byte was %x\n", *(status_p-1)));
|
|
status_count++;
|
|
if (status_count > 255) status_p = status;
|
|
break;
|
|
|
|
case 0x1f: /* message in */
|
|
if (debug)
|
|
dprintf(("Message in\n"));
|
|
WriteSBIC(SBIC_COMMAND, 0xa0); /* transfer info, single byte */
|
|
while (!(ReadByte(sbic_base + SBIC_AUX_STATUS) & 1)); /* wait for DBR set */
|
|
*mess_p++ = ReadSBIC(SBIC_DATA); /* read out a byte */
|
|
if (debug) dprintf(("Message or status byte was %x\n", *(mess_p-1)));
|
|
mess_count++;
|
|
if (mess_count > 255) mess_p = message;
|
|
break;
|
|
|
|
|
|
case 0x20: /* message in paused */
|
|
if (debug)
|
|
dprintf(("Message in paused\n"));
|
|
WriteSBIC(SBIC_COMMAND, 0x03); /* negate ACK */
|
|
break;
|
|
|
|
default:
|
|
error_code = ASC_UNEXPECTED_STATUS;
|
|
break;
|
|
}
|
|
} while (!end_found);
|
|
|
|
if (ReadByte(sbic_base + SBIC_AUX_STATUS) & 0x80) {
|
|
if (debug)
|
|
dprintf(("Interrupt still pending\n"));
|
|
end_of_com(sc, device_ID, data_p, p_txcnt);
|
|
}
|
|
|
|
return(error_code);
|
|
|
|
}
|
|
|
|
|
|
int asc_scsi_cdb(sc, cdb, cdb_size, device_ID, data_p, p_txcnt, dir, lun)
|
|
struct asc_softc *sc;
|
|
char *cdb; /* pointer to cdb array of bytes */
|
|
int cdb_size; /* number of bytes in the cdb 6, 10 or 12 */
|
|
int device_ID; /* target ID, range 0 to 6 */
|
|
u_char *data_p; /* pointer to data */
|
|
int *p_txcnt; /* pointer to number of bytes to transfer */
|
|
int dir; /* direction of transfer, 0=read from peripheral, 1=write to it */
|
|
int lun;
|
|
{
|
|
u_int sbic_base = sc->sc_sbic_base;
|
|
int i;
|
|
int items = *p_txcnt;
|
|
|
|
status_count = 0;
|
|
mess_count = 0;
|
|
|
|
if (ReadByte(sbic_base + SBIC_AUX_STATUS) & 0x10)
|
|
dprintf(("Command in progress\n"));
|
|
if (ReadByte(sbic_base + SBIC_AUX_STATUS) & 0x20)
|
|
dprintf(("Busy\n"));
|
|
if (ReadByte(sbic_base + SBIC_AUX_STATUS) & 0x40)
|
|
if (debug)
|
|
dprintf(("Last command ignored\n"));
|
|
if (ReadByte(sbic_base + SBIC_AUX_STATUS) & 0x80) {
|
|
dprintf(("Interrupt pending\n"));
|
|
end_of_com(sc, device_ID, data_p);
|
|
}
|
|
|
|
if (dir & SCSI_DATA_IN) {
|
|
WriteSBIC(SBIC_DESTID, device_ID | SBIC_DID_DPD); /* set target ID */
|
|
} else {
|
|
WriteSBIC(SBIC_DESTID, device_ID); /* set target ID */
|
|
}
|
|
|
|
WriteSBIC(SBIC_TARGETLUN, lun);
|
|
|
|
/* Preselect the CDB register */
|
|
|
|
WriteByte(sbic_base + SBIC_ADDRREG, SBIC_CDB1TSECT);
|
|
|
|
for (i = 0; i < cdb_size; i++) {
|
|
/* binary(cdb[i]); */
|
|
WriteByte(sbic_base + SBIC_DATAREG, cdb[i]);
|
|
}
|
|
|
|
/* set SBIC transfer count */
|
|
|
|
WriteSBIC(SBIC_TXCOUNT1, (items >> 16) & 0xff);
|
|
WriteSBIC(SBIC_TXCOUNT2, (items >> 8) & 0xff);
|
|
WriteSBIC(SBIC_TXCOUNT3, items & 0xff);
|
|
|
|
if (data_p) {
|
|
/* *p_txcnt = asc_tx_data(sc, (int)data_p, items, dir, device_ID);*/
|
|
*p_txcnt = asc_asm_tx_data(sc->sc_sbic_base, (int)data_p, items, dir);
|
|
} else {
|
|
WriteSBIC(SBIC_COMMAND, SBIC_Sel_tx_wATN); /* Initiate command */
|
|
}
|
|
|
|
i = end_of_com(sc, device_ID, data_p, p_txcnt);
|
|
return(i);
|
|
}
|
|
|
|
/* End of asc.c */
|