diff options
Diffstat (limited to 'sys/arch/sun3/dev/ncr5380sbc.c')
-rw-r--r-- | sys/arch/sun3/dev/ncr5380sbc.c | 2508 |
1 files changed, 0 insertions, 2508 deletions
diff --git a/sys/arch/sun3/dev/ncr5380sbc.c b/sys/arch/sun3/dev/ncr5380sbc.c index 3060cbb2a6f..e69de29bb2d 100644 --- a/sys/arch/sun3/dev/ncr5380sbc.c +++ b/sys/arch/sun3/dev/ncr5380sbc.c @@ -1,2508 +0,0 @@ -/* $NetBSD: ncr5380sbc.c,v 1.2 1995/11/17 23:27:45 gwr Exp $ */ - -/* - * Copyright (c) 1995 David Jones, Gordon W. Ross - * Copyright (c) 1994 Jarle Greipsland - * 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. The name of the authors may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * 4. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by - * David Jones and Gordon Ross - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 THE AUTHORS 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. - */ - -/* - * This is a machine-independent driver for the NCR5380 - * SCSI Bus Controller (SBC), also known as the Am5380. - * - * This code should work with any memory-mapped 5380, - * and can be shared by multiple adapters that address - * the 5380 with different register offset spacings. - * (This can happen on the atari, for example.) - * For porting/design info. see: ncr5380.doc - * - * Credits, history: - * - * David Jones is the author of most of the code that now - * appears in this file, and was the architect of the - * current overall structure (MI/MD code separation, etc.) - * - * Gordon Ross integrated the message phase code, added lots of - * comments about what happens when and why (re. SCSI spec.), - * debugged some reentrance problems, and added several new - * "hooks" needed for the Sun3 "si" adapters. - * - * The message in/out code was taken nearly verbatim from - * the aic6360 driver by Jarle Greipsland. - * - * Several other NCR5380 drivers were used for reference - * while developing this driver, including work by: - * The Alice Group (mac68k port) namely: - * Allen K. Briggs, Chris P. Caputo, Michael L. Finch, - * Bradley A. Grantham, and Lawrence A. Kesteloot - * Michael L. Hitch (amiga drivers: sci.c) - * Leo Weppelman (atari driver: ncr5380.c) - * There are others too. Thanks, everyone. - */ - -#include <sys/types.h> -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/errno.h> -#include <sys/device.h> -#include <sys/buf.h> -#include <sys/proc.h> -#include <sys/user.h> - -#include <scsi/scsi_all.h> -#include <scsi/scsi_debug.h> -#include <scsi/scsi_message.h> -#include <scsi/scsiconf.h> - -#define DEBUG XXX - -#if 0 /* XXX - not yet... */ -#include <dev/ic/ncr5380reg.h> -#include <dev/ic/ncr5380var.h> -#else -#include "ncr5380reg.h" -#include "ncr5380var.h" -#endif - -static int ncr5380_wait_req __P((struct ncr5380_softc *)); -static int ncr5380_wait_not_req __P((struct ncr5380_softc *)); - -static void ncr5380_sched __P((struct ncr5380_softc *)); -static void ncr5380_done __P((struct ncr5380_softc *)); - -static int ncr5380_select - __P((struct ncr5380_softc *, struct sci_req *)); -static void ncr5380_reselect __P((struct ncr5380_softc *)); - -static int ncr5380_msg_in __P((struct ncr5380_softc *)); -static int ncr5380_msg_out __P((struct ncr5380_softc *)); -static int ncr5380_data_xfer __P((struct ncr5380_softc *, int)); -static int ncr5380_command __P((struct ncr5380_softc *)); -static int ncr5380_status __P((struct ncr5380_softc *)); -static void ncr5380_machine __P((struct ncr5380_softc *)); - -/* - * Action flags returned by the info_tranfer functions: - * (These determine what happens next.) - */ -#define ACT_CONTINUE 0x00 /* No flags: expect another phase */ -#define ACT_DISCONNECT 0x01 /* Target is disconnecting */ -#define ACT_CMD_DONE 0x02 /* Need to call scsi_done() */ -#define ACT_RESET_BUS 0x04 /* Need bus reset (cmd timeout) */ -#define ACT_WAIT_DMA 0x10 /* Wait for DMA to complete */ - -/***************************************************************** - * Debugging stuff - *****************************************************************/ - -#ifdef DDB -int Debugger(); -#else -/* This is used only in recoverable places. */ -#define Debugger() printf("Debug: ncr5380.c:%d\n", __LINE__) -#endif - -#ifdef DEBUG - -#define NCR_DBG_BREAK 1 -#define NCR_DBG_CMDS 2 -int ncr5380_debug = NCR_DBG_BREAK; -#define NCR_BREAK() \ - do { if (ncr5380_debug & NCR_DBG_BREAK) Debugger(); } while (0) -static void ncr5380_show_scsi_cmd __P((struct scsi_xfer *)); -static void ncr5380_show_sense __P((struct scsi_xfer *)); -#else /* DEBUG */ -#define NCR_BREAK() /* nada */ -#define ncr5380_show_scsi_cmd(xs) /* nada */ -#define ncr5380_show_sense(xs) /* nada */ -#endif /* DEBUG */ - -static char * -phase_names[8] = { - "DATA_OUT", - "DATA_IN", - "COMMAND", - "STATUS", - "UNSPEC1", - "UNSPEC2", - "MSG_OUT", - "MSG_IN", -}; - -/***************************************************************** - * Actual chip control - *****************************************************************/ - -/* - * XXX: These timeouts might need to be tuned... - */ - -/* This one is used when waiting for a phase change. (X100uS.) */ -int ncr5380_wait_phase_timo = 1000 * 10 * 300; /* 5 min. */ - -/* These are used in the following inline functions. */ -int ncr5380_wait_req_timo = 1000 * 50; /* X2 = 100 mS. */ -int ncr5380_wait_nrq_timo = 1000 * 25; /* X2 = 50 mS. */ - -/* Return zero on success. */ -static __inline__ int ncr5380_wait_req(sc) - struct ncr5380_softc *sc; -{ - register int timo = ncr5380_wait_req_timo; - for (;;) { - if (*sc->sci_bus_csr & SCI_BUS_REQ) { - timo = 0; /* return 0 */ - break; - } - if (--timo < 0) - break; /* return -1 */ - delay(2); - } - return (timo); -} - -/* Return zero on success. */ -static __inline__ int ncr5380_wait_not_req(sc) - struct ncr5380_softc *sc; -{ - register int timo = ncr5380_wait_nrq_timo; - for (;;) { - if ((*sc->sci_bus_csr & SCI_BUS_REQ) == 0) { - timo = 0; /* return 0 */ - break; - } - if (--timo < 0) - break; /* return -1 */ - delay(2); - } - return (timo); -} - -/* Ask the target for a MSG_OUT phase. */ -static __inline__ void -ncr_sched_msgout(sc, msg_code) - struct ncr5380_softc *sc; - int msg_code; -{ - /* First time, raise ATN line. */ - if (sc->sc_msgpriq == 0) { - register u_char icmd; - icmd = *sc->sci_icmd & SCI_ICMD_RMASK; - *sc->sci_icmd = icmd | SCI_ICMD_ATN; - delay(2); - } - sc->sc_msgpriq |= msg_code; -} - - -int -ncr5380_pio_out(sc, phase, count, data) - struct ncr5380_softc *sc; - int phase, count; - unsigned char *data; -{ - register u_char icmd; - register int resid; - register int error; - - icmd = *(sc->sci_icmd) & SCI_ICMD_RMASK; - - icmd |= SCI_ICMD_DATA; - *sc->sci_icmd = icmd; - - resid = count; - while (resid > 0) { - if (!SCI_BUSY(sc)) { - NCR_TRACE("pio_out: lost BSY, resid=%d\n", resid); - break; - } - if (ncr5380_wait_req(sc)) { - NCR_TRACE("pio_out: no REQ, resid=%d\n", resid); - break; - } - if (SCI_BUS_PHASE(*sc->sci_bus_csr) != phase) - break; - - /* Put the data on the bus. */ - *sc->sci_odata = *data++; - - /* Tell the target it's there. */ - icmd |= SCI_ICMD_ACK; - *sc->sci_icmd = icmd; - - /* Wait for target to get it. */ - error = ncr5380_wait_not_req(sc); - - /* OK, it's got it (or we gave up waiting). */ - icmd &= ~SCI_ICMD_ACK; - *sc->sci_icmd = icmd; - - if (error) { - NCR_TRACE("pio_out: stuck REQ, resid=%d\n", resid); - break; - } - - --resid; - } - - /* Stop driving the data bus. */ - icmd &= ~SCI_ICMD_DATA; - *sc->sci_icmd = icmd; - - return (count - resid); -} - - -int -ncr5380_pio_in(sc, phase, count, data) - struct ncr5380_softc *sc; - int phase, count; - unsigned char *data; -{ - register u_char icmd; - register int resid; - register int error; - - icmd = *(sc->sci_icmd) & SCI_ICMD_RMASK; - - resid = count; - while (resid > 0) { - if (!SCI_BUSY(sc)) { - NCR_TRACE("pio_in: lost BSY, resid=%d\n", resid); - break; - } - if (ncr5380_wait_req(sc)) { - NCR_TRACE("pio_in: no REQ, resid=%d\n", resid); - break; - } - /* A phase change is not valid until AFTER REQ rises! */ - if (SCI_BUS_PHASE(*sc->sci_bus_csr) != phase) - break; - - /* Read the data bus. */ - *data++ = *sc->sci_data; - - /* Tell target we got it. */ - icmd |= SCI_ICMD_ACK; - *sc->sci_icmd = icmd; - - /* Wait for target to drop REQ... */ - error = ncr5380_wait_not_req(sc); - - /* OK, we can drop ACK. */ - icmd &= ~SCI_ICMD_ACK; - *sc->sci_icmd = icmd; - - if (error) { - NCR_TRACE("pio_in: stuck REQ, resid=%d\n", resid); - break; - } - - --resid; - } - - return (count - resid); -} - - -void -ncr5380_init(sc) - struct ncr5380_softc *sc; -{ - int i, j; - -#ifdef DEBUG - ncr5380_debug_sc = sc; -#endif - - for (i = 0; i < SCI_OPENINGS; i++) - sc->sc_ring[i].sr_xs = NULL; - for (i = 0; i < 8; i++) - for (j = 0; j < 8; j++) - sc->sc_matrix[i][j] = NULL; - - sc->sc_link.openings = 2; /* XXX - Not SCI_OPENINGS */ - sc->sc_prevphase = PHASE_INVALID; - sc->sc_state = NCR_IDLE; - - *sc->sci_tcmd = PHASE_INVALID; - *sc->sci_icmd = 0; - *sc->sci_mode = 0; - *sc->sci_sel_enb = 0; - SCI_CLR_INTR(sc); - - /* XXX: Enable reselect interrupts... */ - *sc->sci_sel_enb = 0x80; - - /* Another hack (Er.. hook!) for the sun3 si: */ - if (sc->sc_intr_on) { - NCR_TRACE("init: intr ON\n", 0); - sc->sc_intr_on(sc); - } -} - - -void -ncr5380_reset_scsibus(sc) - struct ncr5380_softc *sc; -{ - - NCR_TRACE("reset_scsibus, cur=0x%x\n", - (long) sc->sc_current); - - *sc->sci_icmd = SCI_ICMD_RST; - delay(500); - *sc->sci_icmd = 0; - - *sc->sci_mode = 0; - *sc->sci_tcmd = PHASE_INVALID; - - SCI_CLR_INTR(sc); - /* XXX - Need long delay here! */ - delay(100000); - - /* XXX - Need to cancel disconnected requests. */ -} - - -/* - * Interrupt handler for the SCSI Bus Controller (SBC) - * This may also called for a DMA timeout (at splbio). - */ -int -ncr5380_intr(sc) - struct ncr5380_softc *sc; -{ - int claimed = 0; - - /* - * Do not touch SBC regs here unless sc_current == NULL - * or it will complain about "register conflict" errors. - * Instead, just let ncr5380_machine() deal with it. - */ - NCR_TRACE("intr: top, state=%d\n", sc->sc_state); - - if (sc->sc_state == NCR_IDLE) { - /* - * Might be reselect. ncr5380_reselect() will check, - * and set up the connection if so. This will verify - * that sc_current == NULL at the beginning... - */ - - /* Another hack (Er.. hook!) for the sun3 si: */ - if (sc->sc_intr_off) { - NCR_TRACE("intr: for reselect, intr off\n", 0); - sc->sc_intr_off(sc); - } - - ncr5380_reselect(sc); - } - - /* - * The remaining documented interrupt causes are phase mismatch and - * disconnect. In addition, the sunsi controller may produce a state - * where SCI_CSR_DONE is false, yet DMA is complete. - * - * The procedure in all these cases is to let ncr5380_machine() - * figure out what to do next. - */ - if (sc->sc_state & NCR_WORKING) { - NCR_TRACE("intr: call machine, cur=0x%x\n", - (long) sc->sc_current); - /* This will usually free-up the nexus. */ - ncr5380_machine(sc); - NCR_TRACE("intr: machine done, cur=0x%x\n", - (long) sc->sc_current); - claimed = 1; - } - - /* Maybe we can run some commands now... */ - if (sc->sc_state == NCR_IDLE) { - NCR_TRACE("intr: call sched, cur=0x%x\n", - (long) sc->sc_current); - ncr5380_sched(sc); - NCR_TRACE("intr: sched done, cur=0x%x\n", - (long) sc->sc_current); - } - - return claimed; -} - - -/* - * Abort the current command (i.e. due to timeout) - */ -void -ncr5380_abort(sc) - struct ncr5380_softc *sc; -{ - - /* - * Finish it now. If DMA is in progress, we - * can not call ncr_sched_msgout() because - * that hits the SBC (avoid DMA conflict). - */ - - /* Another hack (Er.. hook!) for the sun3 si: */ - if (sc->sc_intr_off) { - NCR_TRACE("abort: intr off\n", 0); - sc->sc_intr_off(sc); - } - - sc->sc_state |= NCR_ABORTING; - if ((sc->sc_state & NCR_DOINGDMA) == 0) { - ncr_sched_msgout(sc, SEND_ABORT); - } - NCR_TRACE("abort: call machine, cur=0x%x\n", - (long) sc->sc_current); - ncr5380_machine(sc); - NCR_TRACE("abort: machine done, cur=0x%x\n", - (long) sc->sc_current); - - /* Another hack (Er.. hook!) for the sun3 si: */ - if (sc->sc_intr_on) { - NCR_TRACE("abort: intr ON\n", 0); - sc->sc_intr_on(sc); - } -} - -/* - * Timeout handler, scheduled for each SCSI command. - */ -void -ncr5380_cmd_timeout(arg) - void *arg; -{ - struct sci_req *sr = arg; - struct scsi_xfer *xs; - struct scsi_link *sc_link; - struct ncr5380_softc *sc; - int s; - - s = splbio(); - - /* Get all our variables... */ - xs = sr->sr_xs; - if (xs == NULL) { - printf("ncr5380_cmd_timeout: no scsi_xfer\n"); - goto out; - } - sc_link = xs->sc_link; - sc = sc_link->adapter_softc; - - printf("%s: cmd timeout, targ=%d, lun=%d\n", - sc->sc_dev.dv_xname, - sr->sr_target, sr->sr_lun); - - /* - * Mark the overdue job as failed, and arrange for - * ncr5380_machine to terminate it. If the victim - * is the current job, call ncr5380_machine() now. - * Otherwise arrange for ncr5380_sched() to do it. - */ - sr->sr_flags |= SR_OVERDUE; - if (sc->sc_current == sr) { - NCR_TRACE("cmd_tmo: call abort, sr=0x%x\n", (long) sr); - ncr5380_abort(sc); - } else { - /* - * The driver may be idle, or busy with another job. - * Arrange for ncr5380_sched() to do the deed. - */ - NCR_TRACE("cmd_tmo: clear matrix, t/l=0x%02x\n", - (sr->sr_target << 4) | sr->sr_lun); - sc->sc_matrix[sr->sr_target][sr->sr_lun] = NULL; - } - - /* - * We may have aborted the current job, or may have - * already been idle. In either case, we should now - * be idle, so try to start another job. - */ - if (sc->sc_state == NCR_IDLE) { - NCR_TRACE("cmd_tmo: call sched, cur=0x%x\n", - (long) sc->sc_current); - ncr5380_sched(sc); - NCR_TRACE("cmd_tmo: sched done, cur=0x%x\n", - (long) sc->sc_current); - } - -out: - splx(s); -} - - -/***************************************************************** - * Interface to higher level - *****************************************************************/ - - -/* - * Enter a new SCSI command into the "issue" queue, and - * if there is work to do, start it going. - * - * WARNING: This can be called recursively! - * (see comment in ncr5380_done) - */ -int -ncr5380_scsi_cmd(xs) - struct scsi_xfer *xs; -{ - struct ncr5380_softc *sc; - struct sci_req *sr; - int s, rv, i, flags; - extern int cold; /* XXX */ - - sc = xs->sc_link->adapter_softc; - - flags = xs->flags; - /* - * XXX: Hack: During autoconfig, force polling mode. - * Needed as long as sdsize() can be called while cold, - * otherwise timeouts will never call back (grumble). - */ - if (cold) - flags |= SCSI_POLL; - - if (sc->sc_flags & NCR5380_FORCE_POLLING) - flags |= SCSI_POLL; - - if (flags & SCSI_DATA_UIO) - panic("ncr5380: scsi data uio requested"); - - s = splbio(); - - if (flags & SCSI_POLL) { - /* Terminate any current command. */ - sr = sc->sc_current; - if (sr) { - printf("%s: polled request aborting %d/%d\n", - sc->sc_dev.dv_xname, - sr->sr_target, sr->sr_lun); - ncr5380_abort(sc); - } - if (sc->sc_state != NCR_IDLE) { - panic("ncr5380_scsi_cmd: polled request, abort failed"); - } - } - - /* - * Find lowest empty slot in ring buffer. - * XXX: What about "fairness" and cmd order? - */ - for (i = 0; i < SCI_OPENINGS; i++) - if (sc->sc_ring[i].sr_xs == NULL) - goto new; - - rv = TRY_AGAIN_LATER; - NCR_TRACE("scsi_cmd: no openings, rv=%d\n", rv); - goto out; - -new: - /* Create queue entry */ - sr = &sc->sc_ring[i]; - sr->sr_xs = xs; - sr->sr_target = xs->sc_link->target; - sr->sr_lun = xs->sc_link->lun; - sr->sr_dma_hand = NULL; - sr->sr_dataptr = xs->data; - sr->sr_datalen = xs->datalen; - sr->sr_flags = (flags & SCSI_POLL) ? SR_IMMED : 0; - sr->sr_status = -1; /* no value */ - sc->sc_ncmds++; - rv = SUCCESSFULLY_QUEUED; - - NCR_TRACE("scsi_cmd: new sr=0x%x\n", (long)sr); - - if (flags & SCSI_POLL) { - /* Force this new command to be next. */ - sc->sc_rr = i; - } - - /* - * If we were idle, run some commands... - */ - if (sc->sc_state == NCR_IDLE) { - NCR_TRACE("scsi_cmd: call sched, cur=0x%x\n", - (long) sc->sc_current); - ncr5380_sched(sc); - NCR_TRACE("scsi_cmd: sched done, cur=0x%x\n", - (long) sc->sc_current); - } - - if (flags & SCSI_POLL) { - /* Make sure ncr5380_sched() finished it. */ - if ((xs->flags & ITSDONE) == 0) - panic("ncr5380_scsi_cmd: poll didn't finish"); - rv = COMPLETE; - } - -out: - splx(s); - return (rv); -} - - -/* - * POST PROCESSING OF SCSI_CMD (usually current) - * Called by ncr5380_sched(), ncr5380_machine() - */ -static void -ncr5380_done(sc) - struct ncr5380_softc *sc; -{ - struct sci_req *sr; - struct scsi_xfer *xs; - -#ifdef DIAGNOSTIC - if ((getsr() & PSL_IPL) < PSL_IPL2) - panic("ncr5380_done: bad spl"); - if (sc->sc_state == NCR_IDLE) - panic("ncr5380_done: state=idle"); - if (sc->sc_current == NULL) - panic("ncr5380_done: current=0"); -#endif - - sr = sc->sc_current; - xs = sr->sr_xs; - - NCR_TRACE("done: top, cur=0x%x\n", (long) sc->sc_current); - - /* - * Clean up DMA resources for this command. - */ - if (sr->sr_dma_hand) { - NCR_TRACE("done: dma_free, dh=0x%x\n", - (long) sr->sr_dma_hand); - (*sc->sc_dma_free)(sc); - } -#ifdef DIAGNOSTIC - if (sr->sr_dma_hand) - panic("ncr5380_done: dma free did not"); -#endif - - if (sc->sc_state & NCR_ABORTING) { - NCR_TRACE("done: aborting, error=%d\n", xs->error); - if (xs->error == XS_NOERROR) - xs->error = XS_TIMEOUT; - } - - NCR_TRACE("done: check error=%d\n", (long) xs->error); - - /* If error is already set, ignore sr_status value. */ - if (xs->error != XS_NOERROR) - goto finish; - - NCR_TRACE("done: check status=%d\n", sr->sr_status); - - switch (sr->sr_status) { - case SCSI_OK: /* 0 */ - if (sr->sr_flags & SR_SENSE) { - if (ncr5380_debug & NCR_DBG_CMDS) { - ncr5380_show_sense(xs); - } - xs->error = XS_SENSE; - } - break; - - case SCSI_CHECK: - if (sr->sr_flags & SR_SENSE) { - /* Sense command also asked for sense? */ - printf("ncr5380_done: sense asked for sense\n"); - NCR_BREAK(); - xs->error = XS_DRIVER_STUFFUP; - break; - } - sr->sr_flags |= SR_SENSE; - NCR_TRACE("done: get sense, sr=0x%x\n", (long) sr); - /* - * Leave queued, but clear sc_current so we start over - * with selection. Guaranteed to get the same request. - */ - sc->sc_state = NCR_IDLE; - sc->sc_current = NULL; - sc->sc_matrix[sr->sr_target][sr->sr_lun] = NULL; - return; /* XXX */ - - case SCSI_BUSY: - xs->error = XS_BUSY; - break; - - case -1: - /* This is our "impossible" initial value. */ - /* fallthrough */ - default: - printf("%s: target %d, bad status=%d\n", - sc->sc_dev.dv_xname, sr->sr_target, sr->sr_status); - xs->error = XS_DRIVER_STUFFUP; - break; - } - -finish: - - NCR_TRACE("done: finish, error=%d\n", xs->error); - - /* - * Dequeue the finished command, but don't clear sc_state until - * after the call to scsi_done(), because that may call back to - * ncr5380_scsi_cmd() - unwanted recursion! - * - * Keeping sc->sc_state != idle terminates the recursion. - */ -#ifdef DIAGNOSTIC - if ((sc->sc_state & NCR_WORKING) == 0) - panic("ncr5380_done: bad state"); -#endif - - /* Clear our pointers to the request. */ - sc->sc_current = NULL; - sc->sc_matrix[sr->sr_target][sr->sr_lun] = NULL; - untimeout(ncr5380_cmd_timeout, sr); - - /* Make the request free. */ - sr->sr_xs = NULL; - sc->sc_ncmds--; - - /* Tell common SCSI code it is done. */ - xs->flags |= ITSDONE; - scsi_done(xs); - - sc->sc_state = NCR_IDLE; - /* Now ncr5380_sched() may be called again. */ -} - - -/* - * Schedule a SCSI operation. This routine should return - * only after it achieves one of the following conditions: - * Busy (sc->sc_state != NCR_IDLE) - * No more work can be started. - */ -static void -ncr5380_sched(sc) - struct ncr5380_softc *sc; -{ - struct sci_req *sr; - struct scsi_xfer *xs; - int target, lun; - int error, i; - -#ifdef DIAGNOSTIC - if ((getsr() & PSL_IPL) < PSL_IPL2) - panic("ncr5380_sched: bad spl"); -#endif - - /* Another hack (Er.. hook!) for the sun3 si: */ - if (sc->sc_intr_off) { - NCR_TRACE("sched: top, intr off\n", 0); - sc->sc_intr_off(sc); - } - -next_job: - /* - * Grab the next job from queue. Must be idle. - */ -#ifdef DIAGNOSTIC - if (sc->sc_state != NCR_IDLE) - panic("ncr5380_sched: not idle"); - if (sc->sc_current) - panic("ncr5380_sched: current set"); -#endif - - /* - * Always start the search where we last looked. - * The REQUEST_SENSE logic depends on this to - * choose the same job as was last picked, so it - * can just clear sc_current and reschedule. - * (Avoids loss of "contingent allegiance".) - */ - i = sc->sc_rr; - sr = NULL; - do { - if (sc->sc_ring[i].sr_xs) { - target = sc->sc_ring[i].sr_target; - lun = sc->sc_ring[i].sr_lun; - if (sc->sc_matrix[target][lun] == NULL) { - sc->sc_matrix[target][lun] = - sr = &sc->sc_ring[i]; - sc->sc_rr = i; - break; - } - } - i++; - if (i == SCI_OPENINGS) - i = 0; - } while (i != sc->sc_rr); - - if (sr == NULL) { - NCR_TRACE("sched: no work, cur=0x%x\n", - (long) sc->sc_current); - - /* Another hack (Er.. hook!) for the sun3 si: */ - if (sc->sc_intr_on) { - NCR_TRACE("sched: ret, intr ON\n", 0); - sc->sc_intr_on(sc); - } - - return; /* No more work to do. */ - } - - NCR_TRACE("sched: select for t/l=0x%02x\n", - (sr->sr_target << 4) | sr->sr_lun); - - sc->sc_state = NCR_WORKING; - error = ncr5380_select(sc, sr); - if (sc->sc_current) { - /* Lost the race! reselected out from under us! */ - /* Work with the reselected job. */ - if (sr->sr_flags & SR_IMMED) { - printf("%s: reselected while polling (abort)\n", - sc->sc_dev.dv_xname); - /* Abort the reselected job. */ - sc->sc_state |= NCR_ABORTING; - sc->sc_msgpriq |= SEND_ABORT; - } - sr = sc->sc_current; - xs = sr->sr_xs; - NCR_TRACE("sched: reselect, new sr=0x%x\n", (long)sr); - goto have_nexus; - } - - /* Normal selection result */ - sc->sc_current = sr; /* connected */ - xs = sr->sr_xs; - - /* - * Initialize pointers, etc. for this job - */ - sc->sc_dataptr = sr->sr_dataptr; - sc->sc_datalen = sr->sr_datalen; - sc->sc_prevphase = PHASE_INVALID; - sc->sc_msgpriq = SEND_IDENTIFY; - sc->sc_msgoutq = 0; - sc->sc_msgout = 0; - - NCR_TRACE("sched: select rv=%d\n", error); - - switch (error) { - case XS_NOERROR: - break; - - case XS_BUSY: - /* XXX - Reset and try again. */ - printf("%s: SCSI bus busy, resetting...\n", - sc->sc_dev.dv_xname); - ncr5380_reset_scsibus(sc); - /* fallthrough */ - case XS_SELTIMEOUT: - default: - xs->error = error; /* from select */ - NCR_TRACE("sched: call done, sr=0x%x\n", (long)sr); - ncr5380_done(sc); - - /* Paranoia: clear everything. */ - sc->sc_dataptr = NULL; - sc->sc_datalen = 0; - sc->sc_prevphase = PHASE_INVALID; - sc->sc_msgpriq = 0; - sc->sc_msgoutq = 0; - sc->sc_msgout = 0; - - goto next_job; - } - - /* - * Selection was successful. Normally, this means - * we are starting a new command. However, this - * might be the termination of an overdue job. - */ - if (sr->sr_flags & SR_OVERDUE) { - NCR_TRACE("sched: overdue, sr=0x%x\n", (long)sr); - sc->sc_state |= NCR_ABORTING; - sc->sc_msgpriq |= SEND_ABORT; - goto have_nexus; - } - - /* - * This may be the continuation of some job that - * completed with a "check condition" code. - */ - if (sr->sr_flags & SR_SENSE) { - NCR_TRACE("sched: get sense, sr=0x%x\n", (long)sr); - /* Do not allocate DMA, nor set timeout. */ - goto have_nexus; - } - - /* - * OK, we are starting a new command. - * Initialize and allocate resources for the new command. - * Device reset is special (only uses MSG_OUT phase). - * Normal commands start in MSG_OUT phase where we will - * send and IDENDIFY message, and then expect CMD phase. - */ - if (ncr5380_debug & NCR_DBG_CMDS) { - printf("ncr5380_sched: begin, target=%d, LUN=%d\n", - xs->sc_link->target, xs->sc_link->lun); - ncr5380_show_scsi_cmd(xs); - } - if (xs->flags & SCSI_RESET) { - NCR_TRACE("sched: cmd=reset, sr=0x%x\n", (long)sr); - /* Not an error, so do not set NCR_ABORTING */ - sc->sc_msgpriq |= SEND_DEV_RESET; - goto have_nexus; - } - -#ifdef DIAGNOSTIC - if ((xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) == 0) { - if (sc->sc_dataptr) { - printf("%s: ptr but no data in/out flags?\n"); - NCR_BREAK(); - sc->sc_dataptr = NULL; - } - } -#endif - - /* Allocate DMA space (maybe) */ - if (sc->sc_dataptr && sc->sc_dma_alloc && - (sc->sc_datalen >= sc->sc_min_dma_len)) - { - NCR_TRACE("sched: dma_alloc, len=%d\n", sc->sc_datalen); - (*sc->sc_dma_alloc)(sc); - } - - /* - * Initialization hook called just after select, - * at the beginning of COMMAND phase. - * (but AFTER the DMA allocation is done) - * - * The evil Sun "si" adapter (OBIO variant) needs some - * setup done to the DMA engine BEFORE the target puts - * the SCSI bus into any DATA phase. - */ - if (sr->sr_dma_hand && sc->sc_dma_setup) { - NCR_TRACE("sched: dma_setup, dh=0x%x\n", - (long) sr->sr_dma_hand); - sc->sc_dma_setup(sc); - } - - /* - * Schedule a timeout for the job we are starting. - */ - if ((sr->sr_flags & SR_IMMED) == 0) { - i = (xs->timeout * hz) / 1000; - NCR_TRACE("sched: set timeout=%d\n", i); - timeout(ncr5380_cmd_timeout, sr, i); - } - -have_nexus: - NCR_TRACE("sched: call machine, cur=0x%x\n", - (long) sc->sc_current); - ncr5380_machine(sc); - NCR_TRACE("sched: machine done, cur=0x%x\n", - (long) sc->sc_current); - - /* - * What state did ncr5380_machine() leave us in? - * Hopefully it sometimes completes a job... - */ - if (sc->sc_state == NCR_IDLE) - goto next_job; - - return; /* Have work in progress. */ -} - - -/* - * Reselect handler: checks for reselection, and if we are being - * reselected, it sets up sc->sc_current. - * - * We are reselected when: - * SEL is TRUE - * IO is TRUE - * BSY is FALSE - */ -void -ncr5380_reselect(sc) - struct ncr5380_softc *sc; -{ - struct sci_req *sr; - int target, lun, phase, timo; - u_char bus, data, icmd, msg; - -#ifdef DIAGNOSTIC - /* - * Note: sc_state will be "idle" when ncr5380_intr() - * calls, or "working" when ncr5380_select() calls. - * (So don't test that in this DIAGNOSTIC) - */ - if (sc->sc_current) - panic("ncr5380_reselect: current set"); -#endif - - /* - * First, check the select line. - * (That has to be set first.) - */ - bus = *(sc->sci_bus_csr); - if ((bus & SCI_BUS_SEL) == 0) { - /* Not a selection or reselection. */ - return; - } - - /* - * The target will assert BSY first (for bus arbitration), - * then raise SEL, and finally drop BSY. Only then is the - * data bus required to have valid selection ID bits set. - * Wait for: SEL==1, BSY==0 before reading the data bus. - */ - timo = ncr5380_wait_nrq_timo; - for (;;) { - if ((bus & SCI_BUS_BSY) == 0) - break; - /* Probably never get here... */ - if (--timo <= 0) { - printf("%s: reselect, BSY stuck, bus=0x%x\n", - sc->sc_dev.dv_xname, bus); - /* Not much we can do. Reset the bus. */ - ncr5380_reset_scsibus(sc); - return; - } - delay(10); - bus = *(sc->sci_bus_csr); - /* If SEL went away, forget it. */ - if ((bus & SCI_BUS_SEL) == 0) - return; - /* Still have SEL, check BSY. */ - } - NCR_TRACE("reselect, valid data after %d loops\n", - ncr5380_wait_nrq_timo - timo); - - /* - * Good. We have SEL=1 and BSY=0. Now wait for a - * "bus settle delay" before we sample the data bus - */ - delay(2); - data = *(sc->sci_data) & 0xFF; - /* XXX - Should check parity... */ - - /* - * Is this a reselect (I/O == 1) or have we been - * selected as a target? (I/O == 0) - */ - if ((bus & SCI_BUS_IO) == 0) { - printf("%s: selected as target, data=0x%x\n", - sc->sc_dev.dv_xname, data); - /* Not much we can do. Reset the bus. */ - ncr5380_reset_scsibus(sc); - return; - } - - /* - * OK, this is a reselection. - */ - for (target = 0; target < 7; target++) - if (data & (1 << target)) - break; - - if ((data & 0x7F) != (1 << target)) { - /* No selecting ID? or >2 IDs on bus? */ - printf("%s: bad reselect, data=0x%x\n", - sc->sc_dev.dv_xname, data); - return; - } - - NCR_TRACE("reselect: target=0x%x\n", target); - - /* Raise BSY to acknowledge target reselection. */ - *(sc->sci_icmd) = SCI_ICMD_BSY; - - /* Wait for target to drop SEL. */ - timo = ncr5380_wait_nrq_timo; - for (;;) { - bus = *(sc->sci_bus_csr); - if ((bus & SCI_BUS_SEL) == 0) - break; /* success */ - if (--timo <= 0) { - printf("%s: reselect, SEL stuck, bus=0x%x\n", - sc->sc_dev.dv_xname, bus); - NCR_BREAK(); - /* assume connected (fail later if not) */ - break; - } - delay(2); - } - - /* Now we drop BSY, and we are connected. */ - *(sc->sci_icmd) = 0; - *sc->sci_sel_enb = 0; - SCI_CLR_INTR(sc); - - /* - * At this point the target should send an IDENTIFY message, - * which will permit us to determine the reselecting LUN. - * If not, we assume LUN 0. - */ - lun = 0; - /* Wait for REQ before reading bus phase. */ - if (ncr5380_wait_req(sc)) { - printf("%s: reselect, no REQ\n", - sc->sc_dev.dv_xname); - /* Try to send an ABORT message. */ - goto abort; - } - phase = SCI_BUS_PHASE(*sc->sci_bus_csr); - if (phase != PHASE_MSG_IN) { - printf("%s: reselect, phase=%d\n", - sc->sc_dev.dv_xname, phase); - goto abort; - } - - /* Ack. the change to PHASE_MSG_IN */ - *(sc->sci_tcmd) = PHASE_MSG_IN; - - /* Peek at the message byte without consuming it! */ - msg = *(sc->sci_data); - if ((msg & 0x80) == 0) { - printf("%s: reselect, not identify, msg=%d\n", - sc->sc_dev.dv_xname, msg); - goto abort; - } - lun = msg & 7; - - /* We now know target/LUN. Do we have the request? */ - sr = sc->sc_matrix[target][lun]; - if (sr) { - /* We now have a nexus. */ - sc->sc_state |= NCR_WORKING; - sc->sc_current = sr; - NCR_TRACE("reselect: resume sr=0x%x\n", (long)sr); - - /* Implicit restore pointers message */ - sc->sc_dataptr = sr->sr_dataptr; - sc->sc_datalen = sr->sr_datalen; - - sc->sc_prevphase = PHASE_INVALID; - sc->sc_msgpriq = 0; - sc->sc_msgoutq = 0; - sc->sc_msgout = 0; - - /* - * Another hack for the Sun3 "si", which needs - * some setup done to its DMA engine before the - * target puts the SCSI bus into any DATA phase. - */ - if (sr->sr_dma_hand && sc->sc_dma_setup) { - NCR_TRACE("reselect: call DMA setup, dh=0x%x\n", - (long) sr->sr_dma_hand); - sc->sc_dma_setup(sc); - } - - /* Now consume the IDENTIFY message. */ - ncr5380_pio_in(sc, PHASE_MSG_IN, 1, &msg); - return; - } - - printf("%s: phantom reselect: target=%d, LUN=%d\n", - sc->sc_dev.dv_xname, target, lun); -abort: - /* - * Try to send an ABORT message. This makes us - * temporarily busy, but no current command... - */ - sc->sc_state |= NCR_ABORTING; - - /* Raise ATN, delay, raise ACK... */ - icmd = SCI_ICMD_ATN; - *sc->sci_icmd = icmd; - delay(2); - - /* Now consume the IDENTIFY message. */ - ncr5380_pio_in(sc, PHASE_MSG_IN, 1, &msg); - - /* Finally try to send the ABORT. */ - sc->sc_prevphase = PHASE_INVALID; - sc->sc_msgpriq = SEND_ABORT; - ncr5380_msg_out(sc); - - *(sc->sci_tcmd) = PHASE_INVALID; - *sc->sci_sel_enb = 0; - SCI_CLR_INTR(sc); - *sc->sci_sel_enb = 0x80; - - sc->sc_state &= ~NCR_ABORTING; -} - - -/* - * Select target: xs is the transfer that we are selecting for. - * sc->sc_current should be NULL. - * - * Returns: - * sc->sc_current != NULL ==> we were reselected (race!) - * XS_NOERROR ==> selection worked - * XS_BUSY ==> lost arbitration - * XS_SELTIMEOUT ==> no response to selection - */ -static int -ncr5380_select(sc, sr) - struct ncr5380_softc *sc; - struct sci_req *sr; -{ - int timo; - u_char bus, data, icmd; - - /* Check for reselect */ - ncr5380_reselect(sc); - if (sc->sc_current) { - NCR_TRACE("select: reselect, cur=0x%x\n", - (long) sc->sc_current); - return XS_BUSY; /* reselected */ - } - - /* - * Set phase bits to 0, otherwise the 5380 won't drive the bus during - * selection. - */ - *sc->sci_tcmd = PHASE_DATA_OUT; - *sc->sci_icmd = icmd = 0; - *sc->sci_mode = 0; - - /* - * Arbitrate for the bus. The 5380 takes care of the - * time-critical bus interactions. We set our ID bit - * in the output data register and set MODE_ARB. The - * 5380 watches for the required "bus free" period. - * If and when the "bus free" period is detected, the - * 5380 then drives BSY, drives the data bus, and sets - * the "arbitration in progress" (AIP) bit to let us - * know arbitration has started. We then wait for one - * arbitration delay (2.2uS) and check the ICMD_LST bit, - * which will be set if someone else drives SEL. - */ - *(sc->sci_odata) = 0x80; /* OUR_ID */ - *(sc->sci_mode) = SCI_MODE_ARB; - - /* Wait for ICMD_AIP. */ - timo = ncr5380_wait_req_timo; - for (;;) { - if (*(sc->sci_icmd) & SCI_ICMD_AIP) - break; - if (--timo <= 0) { - /* Did not see any "bus free" period. */ - *sc->sci_mode = 0; - NCR_TRACE("select: bus busy, rc=%d\n", XS_BUSY); - return XS_BUSY; - } - delay(2); - } - NCR_TRACE("select: have AIP after %d loops\n", - ncr5380_wait_req_timo - timo); - - /* Got AIP. Wait one arbitration delay (2.2 uS.) */ - delay(3); - - /* Check for ICMD_LST */ - if (*(sc->sci_icmd) & SCI_ICMD_LST) { - /* Some other target asserted SEL. */ - *sc->sci_mode = 0; - NCR_TRACE("select: lost one, rc=%d\n", XS_BUSY); - ncr5380_reselect(sc); /* XXX */ - return XS_BUSY; - } - - /* - * No other device has declared itself the winner. - * The spec. says to check for higher IDs, but we - * are always the highest (ID=7) so don't bother. - * We can now declare victory by asserting SEL. - * - * Note that the 5380 is asserting BSY because we - * asked it to do arbitration. We will now hold - * BSY directly so we can turn off ARB mode. - */ - icmd = (SCI_ICMD_BSY | SCI_ICMD_SEL); - *sc->sci_icmd = icmd; - - /* - * "The SCSI device that wins arbitration shall wait - * at least a bus clear delay plus a bus settle delay - * after asserting the SEL signal before changing - * any [other] signal." (1.2uS. total) - */ - delay(2); - -#if 1 - /* - * XXX: Check one last time to see if we really - * XXX: did win arbitration. (too paranoid?) - */ - if (*(sc->sci_icmd) & SCI_ICMD_LST) { - *sc->sci_icmd = 0; - *sc->sci_mode = 0; - NCR_TRACE("select: lost two, rc=%d\n", XS_BUSY); - return XS_BUSY; - } -#endif - /* Leave ARB mode Now that we drive BSY+SEL */ - *sc->sci_mode = 0; - *sc->sci_sel_enb = 0; - - /* - * Arbitration is complete. Now do selection: - * Drive the data bus with the ID bits for both - * the host and target. Also set ATN now, to - * ask the target for a messgae out phase. - */ - data = 0x80 | (1 << sr->sr_target); - *(sc->sci_odata) = data; - icmd |= (SCI_ICMD_DATA | SCI_ICMD_ATN); - *(sc->sci_icmd) = icmd; - delay(2); /* two deskew delays. */ - - /* De-assert BSY (targets sample the data now). */ - icmd &= ~SCI_ICMD_BSY; - *(sc->sci_icmd) = icmd; - delay(3); /* Bus settle delay. */ - - /* - * Wait for the target to assert BSY. - * SCSI spec. says wait for 250 mS. - */ - for (timo = 25000;;) { - if (*sc->sci_bus_csr & SCI_BUS_BSY) - goto success; - if (--timo <= 0) - break; - delay(10); - } - - /* - * There is no reaction from the target. Start the selection - * timeout procedure. We release the databus but keep SEL+ATN - * asserted. After that we wait a 'selection abort time' (200 - * usecs) and 2 deskew delays (90 ns) and check BSY again. - * When BSY is asserted, we assume the selection succeeded, - * otherwise we release the bus. - */ - icmd &= ~SCI_ICMD_DATA; - *(sc->sci_icmd) = icmd; - delay(201); - if ((*sc->sci_bus_csr & SCI_BUS_BSY) == 0) { - /* Really no device on bus */ - *sc->sci_tcmd = PHASE_INVALID; - *sc->sci_icmd = 0; - *sc->sci_mode = 0; - *sc->sci_sel_enb = 0; - SCI_CLR_INTR(sc); - *sc->sci_sel_enb = 0x80; - NCR_TRACE("select: device down, rc=%d\n", XS_SELTIMEOUT); - return XS_SELTIMEOUT; - } - -success: - /* - * The target is now driving BSY, so we can stop - * driving SEL and the data bus (keep ATN true). - * Configure the ncr5380 to monitor BSY, parity. - */ - icmd &= ~(SCI_ICMD_DATA | SCI_ICMD_SEL); - *sc->sci_icmd = icmd; - - /* XXX - Make parity checking optional? */ - *sc->sci_mode = (SCI_MODE_MONBSY | SCI_MODE_PAR_CHK); - - return XS_NOERROR; -} - - -/***************************************************************** - * Functions to handle each info. transfer phase: - *****************************************************************/ - -/* - * The message system: - * - * This is a revamped message system that now should easier accomodate - * new messages, if necessary. - * - * Currently we accept these messages: - * IDENTIFY (when reselecting) - * COMMAND COMPLETE # (expect bus free after messages marked #) - * NOOP - * MESSAGE REJECT - * SYNCHRONOUS DATA TRANSFER REQUEST - * SAVE DATA POINTER - * RESTORE POINTERS - * DISCONNECT # - * - * We may send these messages in prioritized order: - * BUS DEVICE RESET # if SCSI_RESET & xs->flags (or in weird sits.) - * MESSAGE PARITY ERROR par. err. during MSGI - * MESSAGE REJECT If we get a message we don't know how to handle - * ABORT # send on errors - * INITIATOR DETECTED ERROR also on errors (SCSI2) (during info xfer) - * IDENTIFY At the start of each transfer - * SYNCHRONOUS DATA TRANSFER REQUEST if appropriate - * NOOP if nothing else fits the bill ... - */ - -#define IS1BYTEMSG(m) (((m) != 0x01 && (m) < 0x20) || (m) >= 0x80) -#define IS2BYTEMSG(m) (((m) & 0xf0) == 0x20) -#define ISEXTMSG(m) ((m) == 0x01) - -/* - * Precondition: - * The SCSI bus is already in the MSGI phase and there is a message byte - * on the bus, along with an asserted REQ signal. - * - * Our return value determines whether our caller, ncr5380_machine() - * will expect to see another REQ (and possibly phase change). - */ -static int -ncr5380_msg_in(sc) - register struct ncr5380_softc *sc; -{ - struct sci_req *sr = sc->sc_current; - int n, phase, timo; - int act_flags; - register u_char icmd; - - /* acknowledge phase change */ - *sc->sci_tcmd = PHASE_MSG_IN; - - act_flags = ACT_CONTINUE; - icmd = *sc->sci_icmd & SCI_ICMD_RMASK; - - if (sc->sc_prevphase == PHASE_MSG_IN) { - /* This is a continuation of the previous message. */ - n = sc->sc_imp - sc->sc_imess; - NCR_TRACE("msg_in: continuation, n=%d\n", n); - goto nextbyte; - } - - /* This is a new MESSAGE IN phase. Clean up our state. */ - sc->sc_state &= ~NCR_DROP_MSGIN; - -nextmsg: - n = 0; - sc->sc_imp = &sc->sc_imess[n]; - -nextbyte: - /* - * Read a whole message, but don't ack the last byte. If we reject the - * message, we have to assert ATN during the message transfer phase - * itself. - */ - for (;;) { - /* - * Read a message byte. - * First, check BSY, REQ, phase... - */ - if (!SCI_BUSY(sc)) { - NCR_TRACE("msg_in: lost BSY, n=%d\n", n); - /* XXX - Assume the command completed? */ - act_flags |= (ACT_DISCONNECT | ACT_CMD_DONE); - return (act_flags); - } - if (ncr5380_wait_req(sc)) { - NCR_TRACE("msg_in: BSY but no REQ, n=%d\n", n); - /* Just let ncr5380_machine() handle it... */ - return (act_flags); - } - phase = SCI_BUS_PHASE(*sc->sci_bus_csr); - if (phase != PHASE_MSG_IN) { - /* - * Target left MESSAGE IN, probably because it - * a) noticed our ATN signal, or - * b) ran out of messages. - */ - return (act_flags); - } - /* Still in MESSAGE IN phase, and REQ is asserted. */ - if (*sc->sci_csr & SCI_CSR_PERR) { - ncr_sched_msgout(sc, SEND_PARITY_ERROR); - sc->sc_state |= NCR_DROP_MSGIN; - } - - /* Gather incoming message bytes if needed. */ - if ((sc->sc_state & NCR_DROP_MSGIN) == 0) { - if (n >= NCR_MAX_MSG_LEN) { - ncr_sched_msgout(sc, SEND_REJECT); - sc->sc_state |= NCR_DROP_MSGIN; - } else { - *sc->sc_imp++ = *sc->sci_data; - n++; - /* - * This testing is suboptimal, but most - * messages will be of the one byte variety, so - * it should not affect performance - * significantly. - */ - if (n == 1 && IS1BYTEMSG(sc->sc_imess[0])) - goto have_msg; - if (n == 2 && IS2BYTEMSG(sc->sc_imess[0])) - goto have_msg; - if (n >= 3 && ISEXTMSG(sc->sc_imess[0]) && - n == sc->sc_imess[1] + 2) - goto have_msg; - } - } - - /* - * If we reach this spot we're either: - * a) in the middle of a multi-byte message, or - * b) dropping bytes. - */ - - /* Ack the last byte read. */ - icmd |= SCI_ICMD_ACK; - *sc->sci_icmd = icmd; - - if (ncr5380_wait_not_req(sc)) { - NCR_TRACE("msg_in: drop, stuck REQ, n=%d\n", n); - act_flags |= ACT_RESET_BUS; - } - - icmd &= ~SCI_ICMD_ACK; - *sc->sci_icmd = icmd; - - if (act_flags != ACT_CONTINUE) - return (act_flags); - - /* back to nextbyte */ - } - -have_msg: - /* We now have a complete message. Parse it. */ - - switch (sc->sc_imess[0]) { - case MSG_CMDCOMPLETE: - NCR_TRACE("msg_in: CMDCOMPLETE\n", 0); - /* Target is about to disconnect. */ - act_flags |= (ACT_DISCONNECT | ACT_CMD_DONE); - break; - - case MSG_DISCONNECT: - NCR_TRACE("msg_in: DISCONNECT\n", 0); - /* Target is about to disconnect. */ - act_flags |= ACT_DISCONNECT; - break; - - case MSG_PARITY_ERROR: - NCR_TRACE("msg_in: PARITY_ERROR\n", 0); - /* Resend the last message. */ - ncr_sched_msgout(sc, sc->sc_msgout); - break; - - case MSG_MESSAGE_REJECT: - /* The target rejects the last message we sent. */ - NCR_TRACE("msg_in: got reject for 0x%x\n", sc->sc_msgout); - switch (sc->sc_msgout) { - case SEND_IDENTIFY: - /* Really old target controller? */ - /* XXX ... */ - break; - case SEND_INIT_DET_ERR: - goto abort; - } - break; - - case MSG_NOOP: - NCR_TRACE("msg_in: NOOP\n", 0); - break; - - case MSG_SAVEDATAPOINTER: - NCR_TRACE("msg_in: SAVE_PTRS\n", 0); - sr->sr_dataptr = sc->sc_dataptr; - sr->sr_datalen = sc->sc_datalen; - break; - - case MSG_RESTOREPOINTERS: - NCR_TRACE("msg_in: RESTORE_PTRS\n", 0); - sc->sc_dataptr = sr->sr_dataptr; - sc->sc_datalen = sr->sr_datalen; - break; - - case MSG_EXTENDED: - switch (sc->sc_imess[2]) { - case MSG_EXT_SDTR: - case MSG_EXT_WDTR: - /* The ncr5380 can not do synchronous mode. */ - goto reject; - default: - printf("%s: unrecognized MESSAGE EXTENDED; sending REJECT\n", - sc->sc_dev.dv_xname); - NCR_BREAK(); - goto reject; - } - break; - - default: - NCR_TRACE("msg_in: eh? imsg=0x%x\n", sc->sc_imess[0]); - printf("%s: unrecognized MESSAGE; sending REJECT\n", - sc->sc_dev.dv_xname); - NCR_BREAK(); - /* fallthrough */ - reject: - ncr_sched_msgout(sc, SEND_REJECT); - break; - - abort: - sc->sc_state |= NCR_ABORTING; - ncr_sched_msgout(sc, SEND_ABORT); - break; - } - - /* Ack the last byte read. */ - icmd |= SCI_ICMD_ACK; - *sc->sci_icmd = icmd; - - if (ncr5380_wait_not_req(sc)) { - NCR_TRACE("msg_in: last, stuck REQ, n=%d\n", n); - act_flags |= ACT_RESET_BUS; - } - - icmd &= ~SCI_ICMD_ACK; - *sc->sci_icmd = icmd; - - /* Go get the next message, if any. */ - if (act_flags == ACT_CONTINUE) - goto nextmsg; - - return (act_flags); -} - - -/* - * The message out (and in) stuff is a bit complicated: - * If the target requests another message (sequence) without - * having changed phase in between it really asks for a - * retransmit, probably due to parity error(s). - * The following messages can be sent: - * IDENTIFY @ These 4 stem from SCSI command activity - * SDTR @ - * WDTR @ - * DEV_RESET @ - * REJECT if MSGI doesn't make sense - * PARITY_ERROR if parity error while in MSGI - * INIT_DET_ERR if parity error while not in MSGI - * ABORT if INIT_DET_ERR rejected - * NOOP if asked for a message and there's nothing to send - * - * Note that we call this one with (sc_current == NULL) - * when sending ABORT for unwanted reselections. - */ -static int -ncr5380_msg_out(sc) - register struct ncr5380_softc *sc; -{ - struct sci_req *sr = sc->sc_current; - int n, phase, resel; - int progress, act_flags; - register u_char icmd; - - /* acknowledge phase change */ - *sc->sci_tcmd = PHASE_MSG_OUT; - - progress = 0; /* did we send any messages? */ - act_flags = ACT_CONTINUE; - - /* - * Set ATN. If we're just sending a trivial 1-byte message, - * we'll clear ATN later on anyway. Also drive the data bus. - */ - icmd = *sc->sci_icmd & SCI_ICMD_RMASK; - icmd |= (SCI_ICMD_ATN | SCI_ICMD_DATA); - *sc->sci_icmd = icmd; - - if (sc->sc_prevphase == PHASE_MSG_OUT) { - if (sc->sc_omp == sc->sc_omess) { - /* - * This is a retransmission. - * - * We get here if the target stayed in MESSAGE OUT - * phase. Section 5.1.9.2 of the SCSI 2 spec indicates - * that all of the previously transmitted messages must - * be sent again, in the same order. Therefore, we - * requeue all the previously transmitted messages, and - * start again from the top. Our simple priority - * scheme keeps the messages in the right order. - */ - sc->sc_msgpriq |= sc->sc_msgoutq; - NCR_TRACE("msg_out: retrans priq=0x%x\n", sc->sc_msgpriq); - } else { - /* This is a continuation of the previous message. */ - n = sc->sc_omp - sc->sc_omess; - NCR_TRACE("msg_out: continuation, n=%d\n", n); - goto nextbyte; - } - } - - /* No messages transmitted so far. */ - sc->sc_msgoutq = 0; - -nextmsg: - /* Pick up highest priority message. */ - sc->sc_msgout = sc->sc_msgpriq & -sc->sc_msgpriq; - sc->sc_msgpriq &= ~sc->sc_msgout; - sc->sc_msgoutq |= sc->sc_msgout; - - /* Build the outgoing message data. */ - switch (sc->sc_msgout) { - case SEND_IDENTIFY: - NCR_TRACE("msg_out: SEND_IDENTIFY\n", 0); - if (sr == NULL) { - printf("%s: SEND_IDENTIFY while not connected; sending NOOP\n", - sc->sc_dev.dv_xname); - NCR_BREAK(); - goto noop; - } - resel = (sc->sc_flags & NCR5380_PERMIT_RESELECT) ? 1 : 0; - resel &= (sr->sr_flags & (SR_IMMED | SR_SENSE)) ? 0 : 1; - sc->sc_omess[0] = MSG_IDENTIFY(sr->sr_lun, resel); - n = 1; - break; - - case SEND_DEV_RESET: - NCR_TRACE("msg_out: SEND_DEV_RESET\n", 0); - /* Expect disconnect after this! */ - /* XXX: Kill jobs for this target? */ - act_flags |= (ACT_DISCONNECT | ACT_CMD_DONE); - sc->sc_omess[0] = MSG_BUS_DEV_RESET; - n = 1; - break; - - case SEND_REJECT: - NCR_TRACE("msg_out: SEND_REJECT\n", 0); - sc->sc_omess[0] = MSG_MESSAGE_REJECT; - n = 1; - break; - - case SEND_PARITY_ERROR: - NCR_TRACE("msg_out: SEND_PARITY_ERROR\n", 0); - sc->sc_omess[0] = MSG_PARITY_ERROR; - n = 1; - break; - - case SEND_INIT_DET_ERR: - NCR_TRACE("msg_out: SEND_INIT_DET_ERR\n", 0); - sc->sc_omess[0] = MSG_INITIATOR_DET_ERR; - n = 1; - break; - - case SEND_ABORT: - NCR_TRACE("msg_out: SEND_ABORT\n", 0); - /* Expect disconnect after this! */ - /* XXX: Set error flag? */ - act_flags |= (ACT_DISCONNECT | ACT_CMD_DONE); - sc->sc_omess[0] = MSG_ABORT; - n = 1; - break; - - case 0: - printf("%s: unexpected MESSAGE OUT; sending NOOP\n", - sc->sc_dev.dv_xname); - NCR_BREAK(); - noop: - NCR_TRACE("msg_out: send NOOP\n", 0); - sc->sc_omess[0] = MSG_NOOP; - n = 1; - break; - - default: - printf("%s: weird MESSAGE OUT; sending NOOP\n", - sc->sc_dev.dv_xname); - NCR_BREAK(); - goto noop; - } - sc->sc_omp = &sc->sc_omess[n]; - -nextbyte: - /* Send message bytes. */ - while (n > 0) { - /* - * Send a message byte. - * First check BSY, REQ, phase... - */ - if (!SCI_BUSY(sc)) { - NCR_TRACE("msg_out: lost BSY, n=%d\n", n); - goto out; - } - if (ncr5380_wait_req(sc)) { - NCR_TRACE("msg_out: no REQ, n=%d\n", n); - goto out; - } - phase = SCI_BUS_PHASE(*sc->sci_bus_csr); - if (phase != PHASE_MSG_OUT) { - /* - * Target left MESSAGE OUT, possibly to reject - * our message. - */ - NCR_TRACE("msg_out: new phase=%d\n", phase); - goto out; - } - - /* Yes, we can send this message byte. */ - --n; - - /* Clear ATN before last byte if this is the last message. */ - if (n == 0 && sc->sc_msgpriq == 0) { - icmd &= ~SCI_ICMD_ATN; - *sc->sci_icmd = icmd; - /* 2 deskew delays */ - delay(2); /* XXX */ - } - - /* Put data on the bus. */ - *sc->sci_odata = *--sc->sc_omp; - - /* Raise ACK to tell target data is on the bus. */ - icmd |= SCI_ICMD_ACK; - *sc->sci_icmd = icmd; - - /* Wait for REQ to be negated. */ - if (ncr5380_wait_not_req(sc)) { - NCR_TRACE("msg_out: stuck REQ, n=%d\n", n); - act_flags |= ACT_RESET_BUS; - } - - /* Finally, drop ACK. */ - icmd &= ~SCI_ICMD_ACK; - *sc->sci_icmd = icmd; - - /* Stuck bus or something... */ - if (act_flags & ACT_RESET_BUS) - goto out; - - } - progress++; - - /* We get here only if the entire message has been transmitted. */ - if (sc->sc_msgpriq != 0) { - /* There are more outgoing messages. */ - goto nextmsg; - } - - /* - * The last message has been transmitted. We need to remember the last - * message transmitted (in case the target switches to MESSAGE IN phase - * and sends a MESSAGE REJECT), and the list of messages transmitted - * this time around (in case the target stays in MESSAGE OUT phase to - * request a retransmit). - */ - -out: - /* Stop driving the data bus. */ - icmd &= ~SCI_ICMD_DATA; - *sc->sci_icmd = icmd; - - if (!progress) - act_flags |= ACT_RESET_BUS; - - return (act_flags); -} - - -/* - * Handle command phase. - */ -static int -ncr5380_command(sc) - struct ncr5380_softc *sc; -{ - struct sci_req *sr = sc->sc_current; - struct scsi_xfer *xs = sr->sr_xs; - struct scsi_sense rqs; - int len; - - /* acknowledge phase change */ - *sc->sci_tcmd = PHASE_COMMAND; - - if (sr->sr_flags & SR_SENSE) { - rqs.opcode = REQUEST_SENSE; - rqs.byte2 = xs->sc_link->lun << 5; - rqs.length = sizeof(xs->sense); - - rqs.unused[0] = rqs.unused[1] = rqs.control = 0; - len = ncr5380_pio_out(sc, PHASE_COMMAND, sizeof(rqs), - (u_char *)&rqs); - } - else { - /* Assume command can be sent in one go. */ - /* XXX: Do this using DMA, and get a phase change intr? */ - len = ncr5380_pio_out(sc, PHASE_COMMAND, xs->cmdlen, - (u_char *)xs->cmd); - } - - if (len != xs->cmdlen) { -#ifdef DEBUG - printf("ncr5380_command: short transfer: wanted %d got %d.\n", - xs->cmdlen, len); - ncr5380_show_scsi_cmd(xs); - NCR_BREAK(); -#endif - if (len < 6) { - xs->error = XS_DRIVER_STUFFUP; - sc->sc_state |= NCR_ABORTING; - ncr_sched_msgout(sc, SEND_ABORT); - } - - } - - return ACT_CONTINUE; -} - - -/* - * Handle either data_in or data_out - */ -static int -ncr5380_data_xfer(sc, phase) - struct ncr5380_softc *sc; - int phase; -{ - struct sci_req *sr = sc->sc_current; - struct scsi_xfer *xs = sr->sr_xs; - int expected_phase; - int i, len; - - if (sr->sr_flags & SR_SENSE) { - NCR_TRACE("data_xfer: get sense, sr=0x%x\n", (long)sr); - if (phase != PHASE_DATA_IN) { - printf("%s: sense phase error\n", sc->sc_dev.dv_xname); - goto abort; - } - /* acknowledge phase change */ - *sc->sci_tcmd = PHASE_DATA_IN; - len = ncr5380_pio_in(sc, phase, sizeof(xs->sense), - (u_char *)&xs->sense); - return ACT_CONTINUE; - } - - /* - * When aborting a command, disallow any data phase. - */ - if (sc->sc_state & NCR_ABORTING) { - printf("%s: aborting, but phase=%s (reset)\n", - sc->sc_dev.dv_xname, - phase_names[phase & 7]); - return ACT_RESET_BUS; /* XXX */ - } - - /* Validate expected phase (data_in or data_out) */ - expected_phase = (xs->flags & SCSI_DATA_OUT) ? - PHASE_DATA_OUT : PHASE_DATA_IN; - if (phase != expected_phase) { - printf("%s: data phase error\n", - sc->sc_dev.dv_xname); - goto abort; - } - - /* Make sure we have some data to move. */ - if (sc->sc_datalen <= 0) { - printf("%s: can not transfer more data\n", - sc->sc_dev.dv_xname); - goto abort; - } - - /* - * Attempt DMA only if dma_alloc gave us a DMA handle AND - * there is enough left to transfer so DMA is worth while. - */ - if (sr->sr_dma_hand && - (sc->sc_datalen >= sc->sc_min_dma_len)) - { - /* - * OK, really start DMA. Note, the MI start function - * is responsible for setting the TCMD register, etc. - * (Acknowledge the phase change there, not here.) - */ - NCR_TRACE("data_xfer: dma_start, dh=0x%x\n", - (long) sr->sr_dma_hand); - (*sc->sc_dma_start)(sc); - return ACT_WAIT_DMA; - } - - NCR_TRACE("data_xfer: doing PIO, len=%d\n", sc->sc_datalen); - - /* acknowledge phase change */ - *sc->sci_tcmd = phase; - if (phase == PHASE_DATA_OUT) { - len = ncr5380_pio_out(sc, phase, sc->sc_datalen, sc->sc_dataptr); - } else { - len = ncr5380_pio_in (sc, phase, sc->sc_datalen, sc->sc_dataptr); - } - sc->sc_dataptr += len; - sc->sc_datalen -= len; - - NCR_TRACE("data_xfer: did PIO, resid=%d\n", sc->sc_datalen); - return (ACT_CONTINUE); - -abort: - sc->sc_state |= NCR_ABORTING; - ncr_sched_msgout(sc, SEND_ABORT); - return (ACT_CONTINUE); -} - - -static int -ncr5380_status(sc) - struct ncr5380_softc *sc; -{ - int len; - u_char status; - struct sci_req *sr = sc->sc_current; - struct scsi_xfer *xs = sr->sr_xs; - - /* acknowledge phase change */ - *sc->sci_tcmd = PHASE_STATUS; - - len = ncr5380_pio_in(sc, PHASE_STATUS, 1, &status); - if (len) { - sr->sr_status = status; - } else { - printf("ncr5380_status: none?\n"); - } - - return ACT_CONTINUE; -} - - -/* - * This is the big state machine that follows SCSI phase changes. - * This is somewhat like a co-routine. It will do a SCSI command, - * and exit if the command is complete, or if it must wait, i.e. - * for DMA to complete or for reselect to resume the job. - * - * The bus must be selected, and we need to know which command is - * being undertaken. - */ -static void -ncr5380_machine(sc) - struct ncr5380_softc *sc; -{ - struct sci_req *sr; - struct scsi_xfer *xs; - int act_flags, phase, timo; - -#ifdef DIAGNOSTIC - if ((getsr() & PSL_IPL) < PSL_IPL2) - panic("ncr5380_machine: bad spl"); - if (sc->sc_state == NCR_IDLE) - panic("ncr5380_machine: state=idle"); - if (sc->sc_current == NULL) - panic("ncr5380_machine: no current cmd"); -#endif - - sr = sc->sc_current; - xs = sr->sr_xs; - act_flags = ACT_CONTINUE; - - /* - * This will be called by ncr5380_intr() when DMA is - * complete. Must stop DMA before touching the 5380 or - * there will be "register conflict" errors. - */ - if (sc->sc_state & NCR_DOINGDMA) { - /* Pick-up where where we left off... */ - goto dma_done; - } - -next_phase: - - if (!SCI_BUSY(sc)) { - /* Unexpected disconnect */ - printf("ncr5380_machine: unexpected disconnect.\n"); - xs->error = XS_DRIVER_STUFFUP; - act_flags |= (ACT_DISCONNECT | ACT_CMD_DONE); - goto do_actions; - } - - /* - * Wait for REQ before reading the phase. - * Need to wait longer than usual here, because - * some devices are just plain slow... - */ - timo = ncr5380_wait_phase_timo; - for (;;) { - if (*sc->sci_bus_csr & SCI_BUS_REQ) - break; - if (--timo <= 0) { - if (sc->sc_state & NCR_ABORTING) { - printf("%s: no REQ while aborting, reset\n", - sc->sc_dev.dv_xname); - act_flags |= ACT_RESET_BUS; - goto do_actions; - } - printf("%s: no REQ for next phase, abort\n", - sc->sc_dev.dv_xname); - sc->sc_state |= NCR_ABORTING; - ncr_sched_msgout(sc, SEND_ABORT); - goto next_phase; - } - delay(100); - } - - phase = SCI_BUS_PHASE(*sc->sci_bus_csr); - NCR_TRACE("machine: phase=%s\n", - (long) phase_names[phase & 7]); - - /* - * We assume that the device knows what it's doing, - * so any phase is good. - */ - -#if 0 - /* - * XXX: Do not ACK the phase yet! do it later... - * XXX: ... each phase routine does that itself. - * In particular, DMA needs it done LATER. - */ - *sc->sci_tcmd = phase; /* acknowledge phase change */ -#endif - - switch (phase) { - - case PHASE_DATA_OUT: - case PHASE_DATA_IN: - act_flags = ncr5380_data_xfer(sc, phase); - break; - - case PHASE_COMMAND: - act_flags = ncr5380_command(sc); - break; - - case PHASE_STATUS: - act_flags = ncr5380_status(sc); - break; - - case PHASE_MSG_OUT: - act_flags = ncr5380_msg_out(sc); - break; - - case PHASE_MSG_IN: - act_flags = ncr5380_msg_in(sc); - break; - - default: - printf("ncr5380_machine: Unexpected phase 0x%x\n", phase); - sc->sc_state |= NCR_ABORTING; - ncr_sched_msgout(sc, SEND_ABORT); - goto next_phase; - - } /* switch */ - sc->sc_prevphase = phase; - -do_actions: - __asm("_ncr5380_actions:"); - - if (act_flags & ACT_WAIT_DMA) { - act_flags &= ~ACT_WAIT_DMA; - /* Wait for DMA to complete (polling, or interrupt). */ - if ((sr->sr_flags & SR_IMMED) == 0) { - NCR_TRACE("machine: wait for DMA intr.\n", 0); - return; /* will resume at dma_done */ - } - /* Busy-wait for it to finish. */ - NCR_TRACE("machine: dma_poll, dh=0x%x\n", - (long) sr->sr_dma_hand); - (*sc->sc_dma_poll)(sc); - dma_done: - /* Return here after interrupt. */ - if (sr->sr_flags & SR_OVERDUE) - sc->sc_state |= NCR_ABORTING; - NCR_TRACE("machine: dma_stop, dh=0x%x\n", - (long) sr->sr_dma_hand); - (*sc->sc_dma_stop)(sc); - SCI_CLR_INTR(sc); /* XXX */ - /* - * While DMA is running we can not touch the SBC, - * so various places just set NCR_ABORTING and - * expect us the "kick it" when DMA is done. - */ - if (sc->sc_state & NCR_ABORTING) { - ncr_sched_msgout(sc, SEND_ABORT); - } - } - - /* - * Check for parity error. - * XXX - better place to check? - */ - if (*(sc->sci_csr) & SCI_CSR_PERR) { - printf("%s: parity error!\n", - sc->sc_dev.dv_xname); - /* XXX: sc->sc_state |= NCR_ABORTING; */ - ncr_sched_msgout(sc, SEND_PARITY_ERROR); - } - - if (act_flags == ACT_CONTINUE) - goto next_phase; - /* All other actions "break" from the loop. */ - - NCR_TRACE("machine: act_flags=0x%x\n", act_flags); - - if (act_flags & ACT_RESET_BUS) { - act_flags |= ACT_CMD_DONE; - /* - * Reset the SCSI bus, usually due to a timeout. - * The error code XS_TIMEOUT allows retries. - */ - sc->sc_state |= NCR_ABORTING; - printf("%s: reset SCSI bus for TID=%d LUN=%d\n", - sc->sc_dev.dv_xname, - sr->sr_target, sr->sr_lun); - ncr5380_reset_scsibus(sc); - } - - if (act_flags & ACT_CMD_DONE) { - act_flags |= ACT_DISCONNECT; - /* Need to call scsi_done() */ - /* XXX: from the aic6360 driver, but why? */ - if (sc->sc_datalen < 0) { - printf("%s: %d extra bytes from %d:%d\n", - sc->sc_dev.dv_xname, -sc->sc_datalen, - sr->sr_target, sr->sr_lun); - sc->sc_datalen = 0; - } - xs->resid = sc->sc_datalen; - /* Note: this will clear sc_current */ - NCR_TRACE("machine: call done, cur=0x%x\n", (long)sr); - ncr5380_done(sc); - } - - if (act_flags & ACT_DISCONNECT) { - /* - * The device has dropped BSY (or will soon). - * Return and let ncr5380_sched() do its thing. - */ - *sc->sci_icmd = 0; - *sc->sci_mode = 0; - *sc->sci_tcmd = PHASE_INVALID; - *sc->sci_sel_enb = 0; - SCI_CLR_INTR(sc); - *sc->sci_sel_enb = 0x80; - - if ((act_flags & ACT_CMD_DONE) == 0) { - __asm("_ncr5380_disconnected:"); - NCR_TRACE("machine: discon, cur=0x%x\n", (long)sr); - } - - /* - * We may be here due to a disconnect message, - * in which case we did NOT call ncr5380_done, - * and we need to clear sc_current. - */ - sc->sc_state = NCR_IDLE; - sc->sc_current = NULL; - - /* Paranoia: clear everything. */ - sc->sc_dataptr = NULL; - sc->sc_datalen = 0; - sc->sc_prevphase = PHASE_INVALID; - sc->sc_msgpriq = 0; - sc->sc_msgoutq = 0; - sc->sc_msgout = 0; - - /* Our caller will re-enable interrupts. */ - } -} - - -#ifdef DEBUG - -static void -ncr5380_show_scsi_cmd(xs) - struct scsi_xfer *xs; -{ - u_char *b = (u_char *) xs->cmd; - int i = 0; - - if ( ! ( xs->flags & SCSI_RESET ) ) { - printf("si(%d:%d:%d)-", - xs->sc_link->scsibus, - xs->sc_link->target, - xs->sc_link->lun); - while (i < xs->cmdlen) { - if (i) printf(","); - printf("%x",b[i++]); - } - printf("-\n"); - } else { - printf("si(%d:%d:%d)-RESET-\n", - xs->sc_link->scsibus, - xs->sc_link->target, - xs->sc_link->lun); - } -} - - -static void -ncr5380_show_sense(xs) - struct scsi_xfer *xs; -{ - u_char *b = (u_char *)&xs->sense; - int i; - - printf("sense:"); - for (i = 0; i < sizeof(xs->sense); i++) - printf(" %02x", b[i]); - printf("\n"); -} - -int ncr5380_traceidx = 0; - -#define TRACE_MAX 1024 -struct trace_ent { - char *msg; - long val; -} ncr5380_tracebuf[TRACE_MAX]; - -void -ncr5380_trace(msg, val) - char *msg; - long val; -{ - register struct trace_ent *tr; - register int s; - - s = splhigh(); - - tr = &ncr5380_tracebuf[ncr5380_traceidx]; - - ncr5380_traceidx++; - if (ncr5380_traceidx >= TRACE_MAX) - ncr5380_traceidx = 0; - - tr->msg = msg; - tr->val = val; - - splx(s); -} - -#ifdef DDB -void -ncr5380_clear_trace() -{ - ncr5380_traceidx = 0; - bzero((char*) ncr5380_tracebuf, sizeof(ncr5380_tracebuf)); -} - -void -ncr5380_show_trace() -{ - struct trace_ent *tr; - int idx; - - idx = ncr5380_traceidx; - do { - tr = &ncr5380_tracebuf[idx]; - idx++; - if (idx >= TRACE_MAX) - idx = 0; - if (tr->msg) - db_printf(tr->msg, tr->val); - } while (idx != ncr5380_traceidx); -} - -void -ncr5380_show_req(sr) - struct sci_req *sr; -{ - struct scsi_xfer *xs = sr->sr_xs; - - db_printf("TID=%d ", sr->sr_target); - db_printf("LUN=%d ", sr->sr_lun); - db_printf("dh=0x%x ", sr->sr_dma_hand); - db_printf("dptr=0x%x ", sr->sr_dataptr); - db_printf("dlen=0x%x ", sr->sr_datalen); - db_printf("flags=%d ", sr->sr_flags); - db_printf("stat=%d ", sr->sr_status); - - if (xs == NULL) { - db_printf("(xs=NULL)\n"); - return; - } - db_printf("\n"); -#ifdef SCSIDEBUG - show_scsi_xs(xs); -#else - db_printf("xs=0x%x\n", xs); -#endif -} - -void -ncr5380_show_state() -{ - struct ncr5380_softc *sc; - struct sci_req *sr; - int i, j, k; - - sc = ncr5380_debug_sc; - - if (sc == NULL) { - db_printf("ncr5380_debug_sc == NULL\n"); - return; - } - - db_printf("sc_ncmds=%d\n", sc->sc_ncmds); - k = -1; /* which is current? */ - for (i = 0; i < SCI_OPENINGS; i++) { - sr = &sc->sc_ring[i]; - if (sr->sr_xs) { - if (sr == sc->sc_current) - k = i; - db_printf("req %d: (sr=0x%x)", i, (long)sr); - ncr5380_show_req(sr); - } - } - db_printf("sc_rr=%d, current=%d\n", sc->sc_rr, k); - - db_printf("Active request matrix:\n"); - for(i = 0; i < 8; i++) { /* targets */ - for (j = 0; j < 8; j++) { /* LUN */ - sr = sc->sc_matrix[i][j]; - if (sr) { - db_printf("TID=%d LUN=%d sr=0x%x\n", i, j, (long)sr); - } - } - } - - db_printf("sc_state=0x%x\n", sc->sc_state); - db_printf("sc_current=0x%x\n", sc->sc_current); - db_printf("sc_dataptr=0x%x\n", sc->sc_dataptr); - db_printf("sc_datalen=0x%x\n", sc->sc_datalen); - - db_printf("sc_prevphase=%d\n", sc->sc_prevphase); - db_printf("sc_msgpriq=0x%x\n", sc->sc_msgpriq); -} - -#endif /* DDB */ -#endif /* DEBUG */ |