[BACK]Return to ncr5380sbc.c CVS log [TXT][DIR] Up to [local] / sys / dev / ic

Annotation of sys/dev/ic/ncr5380sbc.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: ncr5380sbc.c,v 1.19 2006/12/10 16:15:37 miod Exp $    */
        !             2: /*     $NetBSD: ncr5380sbc.c,v 1.13 1996/10/13 01:37:25 christos Exp $ */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1995 David Jones, Gordon W. Ross
        !             6:  * Copyright (c) 1994 Jarle Greipsland
        !             7:  * All rights reserved.
        !             8:  *
        !             9:  * Redistribution and use in source and binary forms, with or without
        !            10:  * modification, are permitted provided that the following conditions
        !            11:  * are met:
        !            12:  * 1. Redistributions of source code must retain the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer.
        !            14:  * 2. Redistributions in binary form must reproduce the above copyright
        !            15:  *    notice, this list of conditions and the following disclaimer in the
        !            16:  *    documentation and/or other materials provided with the distribution.
        !            17:  * 3. The name of the authors may not be used to endorse or promote products
        !            18:  *    derived from this software without specific prior written permission.
        !            19:  * 4. All advertising materials mentioning features or use of this software
        !            20:  *    must display the following acknowledgement:
        !            21:  *      This product includes software developed by
        !            22:  *      David Jones and Gordon Ross
        !            23:  *
        !            24:  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
        !            25:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            26:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            27:  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            28:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            29:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            30:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            31:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            32:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            33:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            34:  */
        !            35:
        !            36: /*
        !            37:  * This is a machine-independent driver for the NCR5380
        !            38:  * SCSI Bus Controller (SBC), also known as the Am5380.
        !            39:  *
        !            40:  * This code should work with any memory-mapped 5380,
        !            41:  * and can be shared by multiple adapters that address
        !            42:  * the 5380 with different register offset spacings.
        !            43:  * (This can happen on the atari, for example.)
        !            44:  * For porting/design info. see: ncr5380.doc
        !            45:  *
        !            46:  * Credits, history:
        !            47:  *
        !            48:  * David Jones is the author of most of the code that now
        !            49:  * appears in this file, and was the architect of the
        !            50:  * current overall structure (MI/MD code separation, etc.)
        !            51:  *
        !            52:  * Gordon Ross integrated the message phase code, added lots of
        !            53:  * comments about what happens when and why (re. SCSI spec.),
        !            54:  * debugged some reentrance problems, and added several new
        !            55:  * "hooks" needed for the Sun3 "si" adapters.
        !            56:  *
        !            57:  * The message in/out code was taken nearly verbatim from
        !            58:  * the aic6360 driver by Jarle Greipsland.
        !            59:  *
        !            60:  * Several other NCR5380 drivers were used for reference
        !            61:  * while developing this driver, including work by:
        !            62:  *   The Alice Group (mac68k port) namely:
        !            63:  *       Allen K. Briggs, Chris P. Caputo, Michael L. Finch,
        !            64:  *       Bradley A. Grantham, and Lawrence A. Kesteloot
        !            65:  *   Michael L. Hitch (amiga drivers: sci.c)
        !            66:  *   Leo Weppelman (atari driver: ncr5380.c)
        !            67:  * There are others too.  Thanks, everyone.
        !            68:  */
        !            69:
        !            70: #include <sys/types.h>
        !            71: #include <sys/param.h>
        !            72: #include <sys/systm.h>
        !            73: #include <sys/kernel.h>
        !            74: #include <sys/errno.h>
        !            75: #include <sys/device.h>
        !            76: #include <sys/buf.h>
        !            77: #include <sys/proc.h>
        !            78: #include <sys/user.h>
        !            79:
        !            80: #include <scsi/scsi_all.h>
        !            81: #include <scsi/scsi_debug.h>
        !            82: #include <scsi/scsi_message.h>
        !            83: #include <scsi/scsiconf.h>
        !            84:
        !            85: #ifdef DDB
        !            86: #include <ddb/db_output.h>
        !            87: #endif
        !            88:
        !            89: #include <dev/ic/ncr5380reg.h>
        !            90: #include <dev/ic/ncr5380var.h>
        !            91:
        !            92: static void    ncr5380_sched(struct ncr5380_softc *);
        !            93: static void    ncr5380_done(struct ncr5380_softc *);
        !            94:
        !            95: static int     ncr5380_select(struct ncr5380_softc *, struct sci_req *);
        !            96: static void    ncr5380_reselect(struct ncr5380_softc *);
        !            97:
        !            98: static int     ncr5380_msg_in(struct ncr5380_softc *);
        !            99: static int     ncr5380_msg_out(struct ncr5380_softc *);
        !           100: static int     ncr5380_data_xfer(struct ncr5380_softc *, int);
        !           101: static int     ncr5380_command(struct ncr5380_softc *);
        !           102: static int     ncr5380_status(struct ncr5380_softc *);
        !           103: static void    ncr5380_machine(struct ncr5380_softc *);
        !           104:
        !           105: void   ncr5380_abort(struct ncr5380_softc *);
        !           106: void   ncr5380_cmd_timeout(void *);
        !           107: /*
        !           108:  * Action flags returned by the info_transfer functions:
        !           109:  * (These determine what happens next.)
        !           110:  */
        !           111: #define ACT_CONTINUE   0x00    /* No flags: expect another phase */
        !           112: #define ACT_DISCONNECT 0x01    /* Target is disconnecting */
        !           113: #define ACT_CMD_DONE   0x02    /* Need to call scsi_done() */
        !           114: #define ACT_RESET_BUS  0x04    /* Need bus reset (cmd timeout) */
        !           115: #define ACT_WAIT_DMA   0x10    /* Wait for DMA to complete */
        !           116:
        !           117: /*****************************************************************
        !           118:  * Debugging stuff
        !           119:  *****************************************************************/
        !           120:
        !           121: #ifndef DDB
        !           122: /* This is used only in recoverable places. */
        !           123: #define Debugger() printf("Debug: ncr5380.c:%d\n", __LINE__)
        !           124: #endif
        !           125:
        !           126: #ifdef NCR5380_DEBUG
        !           127:
        !           128: #define        NCR_DBG_BREAK   1
        !           129: #define        NCR_DBG_CMDS    2
        !           130: int ncr5380_debug = NCR_DBG_BREAK|NCR_DBG_CMDS;
        !           131: struct ncr5380_softc *ncr5380_debug_sc;
        !           132:
        !           133: #define        NCR_BREAK() \
        !           134:        do { if (ncr5380_debug & NCR_DBG_BREAK) Debugger(); } while (0)
        !           135:
        !           136: static void ncr5380_show_scsi_cmd(struct scsi_xfer *);
        !           137: static void ncr5380_show_sense(struct scsi_xfer *);
        !           138:
        !           139: #ifdef DDB
        !           140: void ncr5380_trace(char *, long);
        !           141: void ncr5380_clear_trace(void);
        !           142: void ncr5380_show_trace(void);
        !           143: void ncr5380_show_req(struct sci_req *);
        !           144: void ncr5380_show_req(struct sci_req *);
        !           145: void ncr5380_show_state(void);
        !           146: #endif /* DDB */
        !           147: #else  /* NCR5380_DEBUG */
        !           148:
        !           149: #define        NCR_BREAK()             /* nada */
        !           150: #define ncr5380_show_scsi_cmd(xs) /* nada */
        !           151: #define ncr5380_show_sense(xs) /* nada */
        !           152:
        !           153: #endif /* NCR5380_DEBUG */
        !           154:
        !           155: static char *
        !           156: phase_names[8] = {
        !           157:        "DATA_OUT",
        !           158:        "DATA_IN",
        !           159:        "COMMAND",
        !           160:        "STATUS",
        !           161:        "UNSPEC1",
        !           162:        "UNSPEC2",
        !           163:        "MSG_OUT",
        !           164:        "MSG_IN",
        !           165: };
        !           166:
        !           167: /*****************************************************************
        !           168:  * Actual chip control
        !           169:  *****************************************************************/
        !           170:
        !           171: /*
        !           172:  * XXX: These timeouts might need to be tuned...
        !           173:  */
        !           174:
        !           175: /* This one is used when waiting for a phase change. (X100uS.) */
        !           176: int ncr5380_wait_phase_timo = 1000 * 10 * 300; /* 5 min. */
        !           177:
        !           178: /* These are used in the following inline functions. */
        !           179: int ncr5380_wait_req_timo = 1000 * 50; /* X2 = 100 mS. */
        !           180: int ncr5380_wait_nrq_timo = 1000 * 25; /* X2 =  50 mS. */
        !           181:
        !           182: static __inline int ncr5380_wait_req(struct ncr5380_softc *);
        !           183: static __inline int ncr5380_wait_not_req(struct ncr5380_softc *);
        !           184: static __inline void ncr_sched_msgout(struct ncr5380_softc *, int);
        !           185:
        !           186: /* Return zero on success. */
        !           187: static __inline int ncr5380_wait_req(sc)
        !           188:        struct ncr5380_softc *sc;
        !           189: {
        !           190:        register int timo = ncr5380_wait_req_timo;
        !           191:        for (;;) {
        !           192:                if (*sc->sci_bus_csr & SCI_BUS_REQ) {
        !           193:                        timo = 0;       /* return 0 */
        !           194:                        break;
        !           195:                }
        !           196:                if (--timo < 0)
        !           197:                        break;  /* return -1 */
        !           198:                delay(2);
        !           199:        }
        !           200:        return (timo);
        !           201: }
        !           202:
        !           203: /* Return zero on success. */
        !           204: static __inline int ncr5380_wait_not_req(sc)
        !           205:        struct ncr5380_softc *sc;
        !           206: {
        !           207:        register int timo = ncr5380_wait_nrq_timo;
        !           208:        for (;;) {
        !           209:                if ((*sc->sci_bus_csr & SCI_BUS_REQ) == 0) {
        !           210:                        timo = 0;       /* return 0 */
        !           211:                        break;
        !           212:                }
        !           213:                if (--timo < 0)
        !           214:                        break;  /* return -1 */
        !           215:                delay(2);
        !           216:        }
        !           217:        return (timo);
        !           218: }
        !           219:
        !           220: /* Ask the target for a MSG_OUT phase. */
        !           221: static __inline void
        !           222: ncr_sched_msgout(sc, msg_code)
        !           223:        struct ncr5380_softc *sc;
        !           224:        int msg_code;
        !           225: {
        !           226:        /* First time, raise ATN line. */
        !           227:        if (sc->sc_msgpriq == 0) {
        !           228:                register u_char icmd;
        !           229:                icmd = *sc->sci_icmd & SCI_ICMD_RMASK;
        !           230:                *sc->sci_icmd = icmd | SCI_ICMD_ATN;
        !           231:                delay(2);
        !           232:        }
        !           233:        sc->sc_msgpriq |= msg_code;
        !           234: }
        !           235:
        !           236:
        !           237: int
        !           238: ncr5380_pio_out(sc, phase, count, data)
        !           239:        struct ncr5380_softc *sc;
        !           240:        int phase, count;
        !           241:        unsigned char           *data;
        !           242: {
        !           243:        register u_char         icmd;
        !           244:        register int            resid;
        !           245:        register int            error;
        !           246:
        !           247:        icmd = *(sc->sci_icmd) & SCI_ICMD_RMASK;
        !           248:
        !           249:        icmd |= SCI_ICMD_DATA;
        !           250:        *sc->sci_icmd = icmd;
        !           251:
        !           252:        resid = count;
        !           253:        while (resid > 0) {
        !           254:                if (!SCI_BUSY(sc)) {
        !           255:                        NCR_TRACE("pio_out: lost BSY, resid=%d\n", resid);
        !           256:                        break;
        !           257:                }
        !           258:                if (ncr5380_wait_req(sc)) {
        !           259:                        NCR_TRACE("pio_out: no REQ, resid=%d\n", resid);
        !           260:                        break;
        !           261:                }
        !           262:                if (SCI_BUS_PHASE(*sc->sci_bus_csr) != phase)
        !           263:                        break;
        !           264:
        !           265:                /* Put the data on the bus. */
        !           266:                if (data)
        !           267:                        *sc->sci_odata = *data++;
        !           268:                else
        !           269:                        *sc->sci_odata = 0;
        !           270:
        !           271:                /* Tell the target it's there. */
        !           272:                icmd |= SCI_ICMD_ACK;
        !           273:                *sc->sci_icmd = icmd;
        !           274:
        !           275:                /* Wait for target to get it. */
        !           276:                error = ncr5380_wait_not_req(sc);
        !           277:
        !           278:                /* OK, it's got it (or we gave up waiting). */
        !           279:                icmd &= ~SCI_ICMD_ACK;
        !           280:                *sc->sci_icmd = icmd;
        !           281:
        !           282:                if (error) {
        !           283:                        NCR_TRACE("pio_out: stuck REQ, resid=%d\n", resid);
        !           284:                        break;
        !           285:                }
        !           286:
        !           287:                --resid;
        !           288:        }
        !           289:
        !           290:        /* Stop driving the data bus. */
        !           291:        icmd &= ~SCI_ICMD_DATA;
        !           292:        *sc->sci_icmd = icmd;
        !           293:
        !           294:        return (count - resid);
        !           295: }
        !           296:
        !           297:
        !           298: int
        !           299: ncr5380_pio_in(sc, phase, count, data)
        !           300:        struct ncr5380_softc *sc;
        !           301:        int phase, count;
        !           302:        unsigned char                   *data;
        !           303: {
        !           304:        register u_char         icmd;
        !           305:        register int            resid;
        !           306:        register int            error;
        !           307:
        !           308:        icmd = *(sc->sci_icmd) & SCI_ICMD_RMASK;
        !           309:
        !           310:        resid = count;
        !           311:        while (resid > 0) {
        !           312:                if (!SCI_BUSY(sc)) {
        !           313:                        NCR_TRACE("pio_in: lost BSY, resid=%d\n", resid);
        !           314:                        break;
        !           315:                }
        !           316:                if (ncr5380_wait_req(sc)) {
        !           317:                        NCR_TRACE("pio_in: no REQ, resid=%d\n", resid);
        !           318:                        break;
        !           319:                }
        !           320:                /* A phase change is not valid until AFTER REQ rises! */
        !           321:                if (SCI_BUS_PHASE(*sc->sci_bus_csr) != phase)
        !           322:                        break;
        !           323:
        !           324:                /* Read the data bus. */
        !           325:                if (data)
        !           326:                        *data++ = *sc->sci_data;
        !           327:                else
        !           328:                        (void) *sc->sci_data;
        !           329:
        !           330:                /* Tell target we got it. */
        !           331:                icmd |= SCI_ICMD_ACK;
        !           332:                *sc->sci_icmd = icmd;
        !           333:
        !           334:                /* Wait for target to drop REQ... */
        !           335:                error = ncr5380_wait_not_req(sc);
        !           336:
        !           337:                /* OK, we can drop ACK. */
        !           338:                icmd &= ~SCI_ICMD_ACK;
        !           339:                *sc->sci_icmd = icmd;
        !           340:
        !           341:                if (error) {
        !           342:                        NCR_TRACE("pio_in: stuck REQ, resid=%d\n", resid);
        !           343:                        break;
        !           344:                }
        !           345:
        !           346:                --resid;
        !           347:        }
        !           348:
        !           349:        return (count - resid);
        !           350: }
        !           351:
        !           352:
        !           353: void
        !           354: ncr5380_init(sc)
        !           355:        struct ncr5380_softc *sc;
        !           356: {
        !           357:        int i, j;
        !           358:        struct sci_req *sr;
        !           359:
        !           360: #ifdef NCR5380_DEBUG
        !           361:        ncr5380_debug_sc = sc;
        !           362: #endif
        !           363:
        !           364:        for (i = 0; i < SCI_OPENINGS; i++) {
        !           365:                sr = &sc->sc_ring[i];
        !           366:                sr->sr_xs = NULL;
        !           367:                timeout_set(&sr->sr_timeout, ncr5380_cmd_timeout, sr);
        !           368:        }
        !           369:        for (i = 0; i < 8; i++)
        !           370:                for (j = 0; j < 8; j++)
        !           371:                        sc->sc_matrix[i][j] = NULL;
        !           372:
        !           373:        sc->sc_link.openings = 2;       /* XXX - Not SCI_OPENINGS */
        !           374:        sc->sc_prevphase = PHASE_INVALID;
        !           375:        sc->sc_state = NCR_IDLE;
        !           376:
        !           377:        *sc->sci_tcmd = PHASE_INVALID;
        !           378:        *sc->sci_icmd = 0;
        !           379:        *sc->sci_mode = 0;
        !           380:        *sc->sci_sel_enb = 0;
        !           381:        SCI_CLR_INTR(sc);
        !           382:
        !           383:        /* XXX: Enable reselect interrupts... */
        !           384:        *sc->sci_sel_enb = 0x80;
        !           385:
        !           386:        /* Another hack (Er.. hook!) for the sun3 si: */
        !           387:        if (sc->sc_intr_on) {
        !           388:                NCR_TRACE("init: intr ON\n", 0);
        !           389:                sc->sc_intr_on(sc);
        !           390:        }
        !           391: }
        !           392:
        !           393:
        !           394: void
        !           395: ncr5380_reset_scsibus(sc)
        !           396:        struct ncr5380_softc *sc;
        !           397: {
        !           398:
        !           399:        NCR_TRACE("reset_scsibus, cur=0x%x\n",
        !           400:                          (long) sc->sc_current);
        !           401:
        !           402:        *sc->sci_icmd = SCI_ICMD_RST;
        !           403:        delay(500);
        !           404:        *sc->sci_icmd = 0;
        !           405:
        !           406:        *sc->sci_mode = 0;
        !           407:        *sc->sci_tcmd = PHASE_INVALID;
        !           408:
        !           409:        SCI_CLR_INTR(sc);
        !           410:        /* XXX - Need long delay here! */
        !           411:        delay(100000);
        !           412:
        !           413:        /* XXX - Need to cancel disconnected requests. */
        !           414: }
        !           415:
        !           416:
        !           417: /*
        !           418:  * Interrupt handler for the SCSI Bus Controller (SBC)
        !           419:  * This may also called for a DMA timeout (at splbio).
        !           420:  */
        !           421: int
        !           422: ncr5380_intr(sc)
        !           423:        struct ncr5380_softc *sc;
        !           424: {
        !           425:        int claimed = 0;
        !           426:
        !           427:        /*
        !           428:         * Do not touch SBC regs here unless sc_current == NULL
        !           429:         * or it will complain about "register conflict" errors.
        !           430:         * Instead, just let ncr5380_machine() deal with it.
        !           431:         */
        !           432:        NCR_TRACE("intr: top, state=%d\n", sc->sc_state);
        !           433:
        !           434:        if (sc->sc_state == NCR_IDLE) {
        !           435:                /*
        !           436:                 * Might be reselect.  ncr5380_reselect() will check,
        !           437:                 * and set up the connection if so.  This will verify
        !           438:                 * that sc_current == NULL at the beginning...
        !           439:                 */
        !           440:
        !           441:                /* Another hack (Er.. hook!) for the sun3 si: */
        !           442:                if (sc->sc_intr_off) {
        !           443:                        NCR_TRACE("intr: for reselect, intr off\n", 0);
        !           444:                    sc->sc_intr_off(sc);
        !           445:                }
        !           446:
        !           447:                ncr5380_reselect(sc);
        !           448:        }
        !           449:
        !           450:        /*
        !           451:         * The remaining documented interrupt causes are phase mismatch and
        !           452:         * disconnect.  In addition, the sunsi controller may produce a state
        !           453:         * where SCI_CSR_DONE is false, yet DMA is complete.
        !           454:         *
        !           455:         * The procedure in all these cases is to let ncr5380_machine()
        !           456:         * figure out what to do next.
        !           457:         */
        !           458:        if (sc->sc_state & NCR_WORKING) {
        !           459:                NCR_TRACE("intr: call machine, cur=0x%x\n",
        !           460:                                  (long) sc->sc_current);
        !           461:                /* This will usually free-up the nexus. */
        !           462:                ncr5380_machine(sc);
        !           463:                NCR_TRACE("intr: machine done, cur=0x%x\n",
        !           464:                                  (long) sc->sc_current);
        !           465:                claimed = 1;
        !           466:        }
        !           467:
        !           468:        /* Maybe we can run some commands now... */
        !           469:        if (sc->sc_state == NCR_IDLE) {
        !           470:                NCR_TRACE("intr: call sched, cur=0x%x\n",
        !           471:                                  (long) sc->sc_current);
        !           472:                ncr5380_sched(sc);
        !           473:                NCR_TRACE("intr: sched done, cur=0x%x\n",
        !           474:                                  (long) sc->sc_current);
        !           475:        }
        !           476:
        !           477:        return claimed;
        !           478: }
        !           479:
        !           480:
        !           481: /*
        !           482:  * Abort the current command (i.e. due to timeout)
        !           483:  */
        !           484: void
        !           485: ncr5380_abort(sc)
        !           486:        struct ncr5380_softc *sc;
        !           487: {
        !           488:
        !           489:        /*
        !           490:         * Finish it now.  If DMA is in progress, we
        !           491:         * can not call ncr_sched_msgout() because
        !           492:         * that hits the SBC (avoid DMA conflict).
        !           493:         */
        !           494:
        !           495:        /* Another hack (Er.. hook!) for the sun3 si: */
        !           496:        if (sc->sc_intr_off) {
        !           497:                NCR_TRACE("abort: intr off\n", 0);
        !           498:                sc->sc_intr_off(sc);
        !           499:        }
        !           500:
        !           501:        sc->sc_state |= NCR_ABORTING;
        !           502:        if ((sc->sc_state & NCR_DOINGDMA) == 0) {
        !           503:                ncr_sched_msgout(sc, SEND_ABORT);
        !           504:        }
        !           505:        NCR_TRACE("abort: call machine, cur=0x%x\n",
        !           506:                          (long) sc->sc_current);
        !           507:        ncr5380_machine(sc);
        !           508:        NCR_TRACE("abort: machine done, cur=0x%x\n",
        !           509:                          (long) sc->sc_current);
        !           510:
        !           511:        /* Another hack (Er.. hook!) for the sun3 si: */
        !           512:        if (sc->sc_intr_on) {
        !           513:                NCR_TRACE("abort: intr ON\n", 0);
        !           514:            sc->sc_intr_on(sc);
        !           515:        }
        !           516: }
        !           517:
        !           518: /*
        !           519:  * Timeout handler, scheduled for each SCSI command.
        !           520:  */
        !           521: void
        !           522: ncr5380_cmd_timeout(arg)
        !           523:        void *arg;
        !           524: {
        !           525:        struct sci_req *sr = arg;
        !           526:        struct scsi_xfer *xs;
        !           527:        struct scsi_link *sc_link;
        !           528:        struct ncr5380_softc *sc;
        !           529:        int s;
        !           530:
        !           531:        s = splbio();
        !           532:
        !           533:        /* Get all our variables... */
        !           534:        xs = sr->sr_xs;
        !           535:        if (xs == NULL) {
        !           536:                printf("ncr5380_cmd_timeout: no scsi_xfer\n");
        !           537:                goto out;
        !           538:        }
        !           539:        sc_link = xs->sc_link;
        !           540:        sc = sc_link->adapter_softc;
        !           541:
        !           542:        printf("%s: cmd timeout, targ=%d, lun=%d\n",
        !           543:            sc->sc_dev.dv_xname,
        !           544:            sr->sr_target, sr->sr_lun);
        !           545:
        !           546:        /*
        !           547:         * Mark the overdue job as failed, and arrange for
        !           548:         * ncr5380_machine to terminate it.  If the victim
        !           549:         * is the current job, call ncr5380_machine() now.
        !           550:         * Otherwise arrange for ncr5380_sched() to do it.
        !           551:         */
        !           552:        sr->sr_flags |= SR_OVERDUE;
        !           553:        if (sc->sc_current == sr) {
        !           554:                NCR_TRACE("cmd_tmo: call abort, sr=0x%x\n", (long) sr);
        !           555:                ncr5380_abort(sc);
        !           556:        } else {
        !           557:                /*
        !           558:                 * The driver may be idle, or busy with another job.
        !           559:                 * Arrange for ncr5380_sched() to do the deed.
        !           560:                 */
        !           561:                NCR_TRACE("cmd_tmo: clear matrix, t/l=0x%02x\n",
        !           562:                                  (sr->sr_target << 4) | sr->sr_lun);
        !           563:                sc->sc_matrix[sr->sr_target][sr->sr_lun] = NULL;
        !           564:        }
        !           565:
        !           566:        /*
        !           567:         * We may have aborted the current job, or may have
        !           568:         * already been idle. In either case, we should now
        !           569:         * be idle, so try to start another job.
        !           570:         */
        !           571:        if (sc->sc_state == NCR_IDLE) {
        !           572:                NCR_TRACE("cmd_tmo: call sched, cur=0x%x\n",
        !           573:                                  (long) sc->sc_current);
        !           574:                ncr5380_sched(sc);
        !           575:                NCR_TRACE("cmd_tmo: sched done, cur=0x%x\n",
        !           576:                                  (long) sc->sc_current);
        !           577:        }
        !           578:
        !           579: out:
        !           580:        splx(s);
        !           581: }
        !           582:
        !           583:
        !           584: /*****************************************************************
        !           585:  * Interface to higher level
        !           586:  *****************************************************************/
        !           587:
        !           588:
        !           589: /*
        !           590:  * Enter a new SCSI command into the "issue" queue, and
        !           591:  * if there is work to do, start it going.
        !           592:  *
        !           593:  * WARNING:  This can be called recursively!
        !           594:  * (see comment in ncr5380_done)
        !           595:  */
        !           596: int
        !           597: ncr5380_scsi_cmd(xs)
        !           598:        struct scsi_xfer *xs;
        !           599: {
        !           600:        struct  ncr5380_softc *sc;
        !           601:        struct sci_req  *sr;
        !           602:        int s, rv, i, flags;
        !           603:
        !           604:        sc = xs->sc_link->adapter_softc;
        !           605:        flags = xs->flags;
        !           606:
        !           607:        if (sc->sc_flags & NCR5380_FORCE_POLLING)
        !           608:                flags |= SCSI_POLL;
        !           609:
        !           610:        if (flags & SCSI_DATA_UIO)
        !           611:                panic("ncr5380: scsi data uio requested");
        !           612:
        !           613:        s = splbio();
        !           614:
        !           615:        if (flags & SCSI_POLL) {
        !           616:                /* Terminate any current command. */
        !           617:                sr = sc->sc_current;
        !           618:                if (sr) {
        !           619:                        printf("%s: polled request aborting %d/%d\n",
        !           620:                            sc->sc_dev.dv_xname,
        !           621:                            sr->sr_target, sr->sr_lun);
        !           622:                        ncr5380_abort(sc);
        !           623:                }
        !           624:                if (sc->sc_state != NCR_IDLE) {
        !           625:                        panic("ncr5380_scsi_cmd: polled request, abort failed");
        !           626:                }
        !           627:        }
        !           628:
        !           629:        /*
        !           630:         * Find lowest empty slot in ring buffer.
        !           631:         * XXX: What about "fairness" and cmd order?
        !           632:         */
        !           633:        for (i = 0; i < SCI_OPENINGS; i++)
        !           634:                if (sc->sc_ring[i].sr_xs == NULL)
        !           635:                        goto new;
        !           636:
        !           637:        rv = TRY_AGAIN_LATER;
        !           638:        NCR_TRACE("scsi_cmd: no openings, rv=%d\n", rv);
        !           639:        goto out;
        !           640:
        !           641: new:
        !           642:        /* Create queue entry */
        !           643:        sr = &sc->sc_ring[i];
        !           644:        sr->sr_xs = xs;
        !           645:        sr->sr_target = xs->sc_link->target;
        !           646:        sr->sr_lun = xs->sc_link->lun;
        !           647:        sr->sr_dma_hand = NULL;
        !           648:        sr->sr_dataptr = xs->data;
        !           649:        sr->sr_datalen = xs->datalen;
        !           650:        sr->sr_flags = (flags & SCSI_POLL) ? SR_IMMED : 0;
        !           651:        sr->sr_status = -1;     /* no value */
        !           652:        sc->sc_ncmds++;
        !           653:        rv = SUCCESSFULLY_QUEUED;
        !           654:
        !           655:        NCR_TRACE("scsi_cmd: new sr=0x%x\n", (long)sr);
        !           656:
        !           657:        if (flags & SCSI_POLL) {
        !           658:                /* Force this new command to be next. */
        !           659:                sc->sc_rr = i;
        !           660:        }
        !           661:
        !           662:        /*
        !           663:         * If we were idle, run some commands...
        !           664:         */
        !           665:        if (sc->sc_state == NCR_IDLE) {
        !           666:                NCR_TRACE("scsi_cmd: call sched, cur=0x%x\n",
        !           667:                                  (long) sc->sc_current);
        !           668:                ncr5380_sched(sc);
        !           669:                NCR_TRACE("scsi_cmd: sched done, cur=0x%x\n",
        !           670:                                  (long) sc->sc_current);
        !           671:        }
        !           672:
        !           673:        if (flags & SCSI_POLL) {
        !           674: #ifdef DIAGNOSTIC
        !           675:                /* Make sure ncr5380_sched() finished it. */
        !           676:                if (sc->sc_state != NCR_IDLE)
        !           677:                        panic("ncr5380_scsi_cmd: poll didn't finish");
        !           678: #endif
        !           679:                rv = COMPLETE;
        !           680:        }
        !           681:
        !           682: out:
        !           683:        splx(s);
        !           684:        return (rv);
        !           685: }
        !           686:
        !           687:
        !           688: /*
        !           689:  * POST PROCESSING OF SCSI_CMD (usually current)
        !           690:  * Called by ncr5380_sched(), ncr5380_machine()
        !           691:  */
        !           692: static void
        !           693: ncr5380_done(sc)
        !           694:        struct ncr5380_softc *sc;
        !           695: {
        !           696:        struct  sci_req *sr;
        !           697:        struct  scsi_xfer *xs;
        !           698:
        !           699: #ifdef DIAGNOSTIC
        !           700:        if (sc->sc_state == NCR_IDLE)
        !           701:                panic("ncr5380_done: state=idle");
        !           702:        if (sc->sc_current == NULL)
        !           703:                panic("ncr5380_done: current=0");
        !           704: #endif
        !           705:
        !           706:        sr = sc->sc_current;
        !           707:        xs = sr->sr_xs;
        !           708:
        !           709:        NCR_TRACE("done: top, cur=0x%x\n", (long) sc->sc_current);
        !           710:
        !           711:        /*
        !           712:         * Clean up DMA resources for this command.
        !           713:         */
        !           714:        if (sr->sr_dma_hand) {
        !           715:                NCR_TRACE("done: dma_free, dh=0x%x\n",
        !           716:                                  (long) sr->sr_dma_hand);
        !           717:                (*sc->sc_dma_free)(sc);
        !           718:        }
        !           719: #ifdef DIAGNOSTIC
        !           720:        if (sr->sr_dma_hand)
        !           721:                panic("ncr5380_done: dma free did not");
        !           722: #endif
        !           723:
        !           724:        if (sc->sc_state & NCR_ABORTING) {
        !           725:                NCR_TRACE("done: aborting, error=%d\n", xs->error);
        !           726:                if (xs->error == XS_NOERROR)
        !           727:                        xs->error = XS_TIMEOUT;
        !           728:        }
        !           729:
        !           730:        NCR_TRACE("done: check error=%d\n", (long) xs->error);
        !           731:
        !           732:        /* If error is already set, ignore sr_status value. */
        !           733:        if (xs->error != XS_NOERROR)
        !           734:                goto finish;
        !           735:
        !           736:        NCR_TRACE("done: check status=%d\n", sr->sr_status);
        !           737:
        !           738:        switch (sr->sr_status) {
        !           739:        case SCSI_OK:   /* 0 */
        !           740:                if (sr->sr_flags & SR_SENSE) {
        !           741: #ifdef NCR5380_DEBUG
        !           742:                        if (ncr5380_debug & NCR_DBG_CMDS) {
        !           743:                                ncr5380_show_sense(xs);
        !           744:                        }
        !           745: #endif
        !           746:                        xs->error = XS_SENSE;
        !           747:                }
        !           748:                break;
        !           749:
        !           750:        case SCSI_CHECK:
        !           751:                if (sr->sr_flags & SR_SENSE) {
        !           752:                        /* Sense command also asked for sense? */
        !           753:                        printf("ncr5380_done: sense asked for sense\n");
        !           754:                        NCR_BREAK();
        !           755:                        xs->error = XS_DRIVER_STUFFUP;
        !           756:                        break;
        !           757:                }
        !           758:                sr->sr_flags |= SR_SENSE;
        !           759:                NCR_TRACE("done: get sense, sr=0x%x\n", (long) sr);
        !           760:                /*
        !           761:                 * Leave queued, but clear sc_current so we start over
        !           762:                 * with selection.  Guaranteed to get the same request.
        !           763:                 */
        !           764:                sc->sc_state = NCR_IDLE;
        !           765:                sc->sc_current = NULL;
        !           766:                sc->sc_matrix[sr->sr_target][sr->sr_lun] = NULL;
        !           767:                return;         /* XXX */
        !           768:
        !           769:        case SCSI_BUSY:
        !           770:                xs->error = XS_BUSY;
        !           771:                break;
        !           772:
        !           773:        case -1:
        !           774:                /* This is our "impossible" initial value. */
        !           775:                /* fallthrough */
        !           776:        default:
        !           777:                printf("%s: target %d, bad status=%d\n",
        !           778:                    sc->sc_dev.dv_xname, sr->sr_target, sr->sr_status);
        !           779:                xs->error = XS_DRIVER_STUFFUP;
        !           780:                break;
        !           781:        }
        !           782:
        !           783: finish:
        !           784:
        !           785:        NCR_TRACE("done: finish, error=%d\n", xs->error);
        !           786:
        !           787:        /*
        !           788:         * Dequeue the finished command, but don't clear sc_state until
        !           789:         * after the call to scsi_done(), because that may call back to
        !           790:         * ncr5380_scsi_cmd() - unwanted recursion!
        !           791:         *
        !           792:         * Keeping sc->sc_state != idle terminates the recursion.
        !           793:         */
        !           794: #ifdef DIAGNOSTIC
        !           795:        if ((sc->sc_state & NCR_WORKING) == 0)
        !           796:                panic("ncr5380_done: bad state");
        !           797: #endif
        !           798:
        !           799:        /* Clear our pointers to the request. */
        !           800:        sc->sc_current = NULL;
        !           801:        sc->sc_matrix[sr->sr_target][sr->sr_lun] = NULL;
        !           802:        timeout_del(&sr->sr_timeout);
        !           803:
        !           804:        /* Make the request free. */
        !           805:        sr->sr_xs = NULL;
        !           806:        sc->sc_ncmds--;
        !           807:
        !           808:        /* Tell common SCSI code it is done. */
        !           809:        xs->flags |= ITSDONE;
        !           810:        scsi_done(xs);
        !           811:
        !           812:        sc->sc_state = NCR_IDLE;
        !           813:        /* Now ncr5380_sched() may be called again. */
        !           814: }
        !           815:
        !           816:
        !           817: /*
        !           818:  * Schedule a SCSI operation.  This routine should return
        !           819:  * only after it achieves one of the following conditions:
        !           820:  *     Busy (sc->sc_state != NCR_IDLE)
        !           821:  *     No more work can be started.
        !           822:  */
        !           823: static void
        !           824: ncr5380_sched(sc)
        !           825:        struct  ncr5380_softc *sc;
        !           826: {
        !           827:        struct sci_req  *sr;
        !           828:        struct scsi_xfer *xs;
        !           829:        int     target = 0, lun = 0;
        !           830:        int     error, i;
        !           831:
        !           832:        /* Another hack (Er.. hook!) for the sun3 si: */
        !           833:        if (sc->sc_intr_off) {
        !           834:                NCR_TRACE("sched: top, intr off\n", 0);
        !           835:            sc->sc_intr_off(sc);
        !           836:        }
        !           837:
        !           838: next_job:
        !           839:        /*
        !           840:         * Grab the next job from queue.  Must be idle.
        !           841:         */
        !           842: #ifdef DIAGNOSTIC
        !           843:        if (sc->sc_state != NCR_IDLE)
        !           844:                panic("ncr5380_sched: not idle");
        !           845:        if (sc->sc_current)
        !           846:                panic("ncr5380_sched: current set");
        !           847: #endif
        !           848:
        !           849:        /*
        !           850:         * Always start the search where we last looked.
        !           851:         * The REQUEST_SENSE logic depends on this to
        !           852:         * choose the same job as was last picked, so it
        !           853:         * can just clear sc_current and reschedule.
        !           854:         * (Avoids loss of "contingent allegiance".)
        !           855:         */
        !           856:        i = sc->sc_rr;
        !           857:        sr = NULL;
        !           858:        do {
        !           859:                if (sc->sc_ring[i].sr_xs) {
        !           860:                        target = sc->sc_ring[i].sr_target;
        !           861:                        lun = sc->sc_ring[i].sr_lun;
        !           862:                        if (sc->sc_matrix[target][lun] == NULL) {
        !           863:                                /*
        !           864:                                 * Do not mark the  target/LUN busy yet,
        !           865:                                 * because reselect may cause some other
        !           866:                                 * job to become the current one, so we
        !           867:                                 * might not actually start this job.
        !           868:                                 * Instead, set sc_matrix later on.
        !           869:                                 */
        !           870:                                sc->sc_rr = i;
        !           871:                                sr = &sc->sc_ring[i];
        !           872:                                break;
        !           873:                        }
        !           874:                }
        !           875:                i++;
        !           876:                if (i == SCI_OPENINGS)
        !           877:                        i = 0;
        !           878:        } while (i != sc->sc_rr);
        !           879:
        !           880:        if (sr == NULL) {
        !           881:                NCR_TRACE("sched: no work, cur=0x%x\n",
        !           882:                                  (long) sc->sc_current);
        !           883:
        !           884:                /* Another hack (Er.. hook!) for the sun3 si: */
        !           885:                if (sc->sc_intr_on) {
        !           886:                        NCR_TRACE("sched: ret, intr ON\n", 0);
        !           887:                        sc->sc_intr_on(sc);
        !           888:                }
        !           889:
        !           890:                return;         /* No more work to do. */
        !           891:        }
        !           892:
        !           893:        NCR_TRACE("sched: select for t/l=0x%02x\n",
        !           894:                          (sr->sr_target << 4) | sr->sr_lun);
        !           895:
        !           896:        sc->sc_state = NCR_WORKING;
        !           897:        error = ncr5380_select(sc, sr);
        !           898:        if (sc->sc_current) {
        !           899:                /* Lost the race!  reselected out from under us! */
        !           900:                /* Work with the reselected job. */
        !           901:                if (sr->sr_flags & SR_IMMED) {
        !           902:                        printf("%s: reselected while polling (abort)\n",
        !           903:                            sc->sc_dev.dv_xname);
        !           904:                        /* Abort the reselected job. */
        !           905:                        sc->sc_state |= NCR_ABORTING;
        !           906:                        sc->sc_msgpriq |= SEND_ABORT;
        !           907:                }
        !           908:                sr = sc->sc_current;
        !           909:                xs = sr->sr_xs;
        !           910:                NCR_TRACE("sched: reselect, new sr=0x%x\n", (long)sr);
        !           911:                goto have_nexus;
        !           912:        }
        !           913:
        !           914:        /* Normal selection result.  Target/LUN is now busy. */
        !           915:        sc->sc_matrix[target][lun] = sr;
        !           916:        sc->sc_current = sr;    /* connected */
        !           917:        xs = sr->sr_xs;
        !           918:
        !           919:        /*
        !           920:         * Initialize pointers, etc. for this job
        !           921:         */
        !           922:        sc->sc_dataptr  = sr->sr_dataptr;
        !           923:        sc->sc_datalen  = sr->sr_datalen;
        !           924:        sc->sc_prevphase = PHASE_INVALID;
        !           925:        sc->sc_msgpriq = SEND_IDENTIFY;
        !           926:        sc->sc_msgoutq = 0;
        !           927:        sc->sc_msgout  = 0;
        !           928:
        !           929:        NCR_TRACE("sched: select rv=%d\n", error);
        !           930:
        !           931:        switch (error) {
        !           932:        case XS_NOERROR:
        !           933:                break;
        !           934:
        !           935:        case XS_BUSY:
        !           936:                /* XXX - Reset and try again. */
        !           937:                printf("%s: select found SCSI bus busy, resetting...\n",
        !           938:                    sc->sc_dev.dv_xname);
        !           939:                ncr5380_reset_scsibus(sc);
        !           940:                /* fallthrough */
        !           941:        case XS_SELTIMEOUT:
        !           942:        default:
        !           943:                xs->error = error;      /* from select */
        !           944:                NCR_TRACE("sched: call done, sr=0x%x\n", (long)sr);
        !           945:                ncr5380_done(sc);
        !           946:
        !           947:                /* Paranoia: clear everything. */
        !           948:                sc->sc_dataptr = NULL;
        !           949:                sc->sc_datalen = 0;
        !           950:                sc->sc_prevphase = PHASE_INVALID;
        !           951:                sc->sc_msgpriq = 0;
        !           952:                sc->sc_msgoutq = 0;
        !           953:                sc->sc_msgout  = 0;
        !           954:
        !           955:                goto next_job;
        !           956:        }
        !           957:
        !           958:        /*
        !           959:         * Selection was successful.  Normally, this means
        !           960:         * we are starting a new command.  However, this
        !           961:         * might be the termination of an overdue job.
        !           962:         */
        !           963:        if (sr->sr_flags & SR_OVERDUE) {
        !           964:                NCR_TRACE("sched: overdue, sr=0x%x\n", (long)sr);
        !           965:                sc->sc_state |= NCR_ABORTING;
        !           966:                sc->sc_msgpriq |= SEND_ABORT;
        !           967:                goto have_nexus;
        !           968:        }
        !           969:
        !           970:        /*
        !           971:         * This may be the continuation of some job that
        !           972:         * completed with a "check condition" code.
        !           973:         */
        !           974:        if (sr->sr_flags & SR_SENSE) {
        !           975:                NCR_TRACE("sched: get sense, sr=0x%x\n", (long)sr);
        !           976:                /* Do not allocate DMA, nor set timeout. */
        !           977:                goto have_nexus;
        !           978:        }
        !           979:
        !           980:        /*
        !           981:         * OK, we are starting a new command.
        !           982:         * Initialize and allocate resources for the new command.
        !           983:         * Device reset is special (only uses MSG_OUT phase).
        !           984:         * Normal commands start in MSG_OUT phase where we will
        !           985:         * send and IDENDIFY message, and then expect CMD phase.
        !           986:         */
        !           987: #ifdef NCR5380_DEBUG
        !           988:        if (ncr5380_debug & NCR_DBG_CMDS) {
        !           989:                printf("ncr5380_sched: begin, target=%d, LUN=%d\n",
        !           990:                    xs->sc_link->target, xs->sc_link->lun);
        !           991:                ncr5380_show_scsi_cmd(xs);
        !           992:        }
        !           993: #endif
        !           994:        if (xs->flags & SCSI_RESET) {
        !           995:                NCR_TRACE("sched: cmd=reset, sr=0x%x\n", (long)sr);
        !           996:                /* Not an error, so do not set NCR_ABORTING */
        !           997:                sc->sc_msgpriq |= SEND_DEV_RESET;
        !           998:                goto have_nexus;
        !           999:        }
        !          1000:
        !          1001: #ifdef DIAGNOSTIC
        !          1002:        if ((xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) == 0) {
        !          1003:                if (sc->sc_dataptr) {
        !          1004:                        printf("%s: ptr but no data in/out flags?\n",
        !          1005:                            sc->sc_dev.dv_xname);
        !          1006:                        NCR_BREAK();
        !          1007:                        sc->sc_dataptr = NULL;
        !          1008:                }
        !          1009:        }
        !          1010: #endif
        !          1011:
        !          1012:        /* Allocate DMA space (maybe) */
        !          1013:        if (sc->sc_dataptr && sc->sc_dma_alloc &&
        !          1014:                (sc->sc_datalen >= sc->sc_min_dma_len))
        !          1015:        {
        !          1016:                NCR_TRACE("sched: dma_alloc, len=%d\n", sc->sc_datalen);
        !          1017:                (*sc->sc_dma_alloc)(sc);
        !          1018:        }
        !          1019:
        !          1020:        /*
        !          1021:         * Initialization hook called just after select,
        !          1022:         * at the beginning of COMMAND phase.
        !          1023:         * (but AFTER the DMA allocation is done)
        !          1024:         *
        !          1025:         * The evil Sun "si" adapter (OBIO variant) needs some
        !          1026:         * setup done to the DMA engine BEFORE the target puts
        !          1027:         * the SCSI bus into any DATA phase.
        !          1028:         */
        !          1029:        if (sr->sr_dma_hand && sc->sc_dma_setup) {
        !          1030:                NCR_TRACE("sched: dma_setup, dh=0x%x\n",
        !          1031:                                  (long) sr->sr_dma_hand);
        !          1032:            sc->sc_dma_setup(sc);
        !          1033:        }
        !          1034:
        !          1035:        /*
        !          1036:         * Schedule a timeout for the job we are starting.
        !          1037:         */
        !          1038:        if ((sr->sr_flags & SR_IMMED) == 0) {
        !          1039:                i = (xs->timeout * hz) / 1000;
        !          1040:                NCR_TRACE("sched: set timeout=%d\n", i);
        !          1041:                timeout_add(&sr->sr_timeout, i);
        !          1042:        }
        !          1043:
        !          1044: have_nexus:
        !          1045:        NCR_TRACE("sched: call machine, cur=0x%x\n",
        !          1046:                          (long) sc->sc_current);
        !          1047:        ncr5380_machine(sc);
        !          1048:        NCR_TRACE("sched: machine done, cur=0x%x\n",
        !          1049:                          (long) sc->sc_current);
        !          1050:
        !          1051:        /*
        !          1052:         * What state did ncr5380_machine() leave us in?
        !          1053:         * Hopefully it sometimes completes a job...
        !          1054:         */
        !          1055:        if (sc->sc_state == NCR_IDLE)
        !          1056:                goto next_job;
        !          1057:
        !          1058:        return;         /* Have work in progress. */
        !          1059: }
        !          1060:
        !          1061:
        !          1062: /*
        !          1063:  *  Reselect handler: checks for reselection, and if we are being
        !          1064:  *     reselected, it sets up sc->sc_current.
        !          1065:  *
        !          1066:  *  We are reselected when:
        !          1067:  *     SEL is TRUE
        !          1068:  *     IO  is TRUE
        !          1069:  *     BSY is FALSE
        !          1070:  */
        !          1071: void
        !          1072: ncr5380_reselect(sc)
        !          1073:        struct ncr5380_softc *sc;
        !          1074: {
        !          1075:        struct sci_req *sr;
        !          1076:        int target, lun, phase, timo;
        !          1077:        int target_mask;
        !          1078:        u_char bus, data, icmd, msg;
        !          1079:
        !          1080: #ifdef DIAGNOSTIC
        !          1081:        /*
        !          1082:         * Note: sc_state will be "idle" when ncr5380_intr()
        !          1083:         * calls, or "working" when ncr5380_select() calls.
        !          1084:         * (So don't test that in this DIAGNOSTIC)
        !          1085:         */
        !          1086:        if (sc->sc_current)
        !          1087:                panic("ncr5380_reselect: current set");
        !          1088: #endif
        !          1089:
        !          1090:        /*
        !          1091:         * First, check the select line.
        !          1092:         * (That has to be set first.)
        !          1093:         */
        !          1094:        bus = *(sc->sci_bus_csr);
        !          1095:        if ((bus & SCI_BUS_SEL) == 0) {
        !          1096:                /* Not a selection or reselection. */
        !          1097:                return;
        !          1098:        }
        !          1099:
        !          1100:        /*
        !          1101:         * The target will assert BSY first (for bus arbitration),
        !          1102:         * then raise SEL, and finally drop BSY.  Only then is the
        !          1103:         * data bus required to have valid selection ID bits set.
        !          1104:         * Wait for: SEL==1, BSY==0 before reading the data bus.
        !          1105:         * While this theoretically can happen, we are apparently
        !          1106:         * never fast enough to get here before BSY drops.
        !          1107:         */
        !          1108:        timo = ncr5380_wait_nrq_timo;
        !          1109:        for (;;) {
        !          1110:                if ((bus & SCI_BUS_BSY) == 0)
        !          1111:                        break;
        !          1112:                /* Probably never get here... */
        !          1113:                if (--timo <= 0) {
        !          1114:                        printf("%s: reselect, BSY stuck, bus=0x%x\n",
        !          1115:                            sc->sc_dev.dv_xname, bus);
        !          1116:                        /* Not much we can do. Reset the bus. */
        !          1117:                        ncr5380_reset_scsibus(sc);
        !          1118:                        return;
        !          1119:                }
        !          1120:                delay(2);
        !          1121:                bus = *(sc->sci_bus_csr);
        !          1122:                /* If SEL went away, forget it. */
        !          1123:                if ((bus & SCI_BUS_SEL) == 0)
        !          1124:                        return;
        !          1125:                /* Still have SEL, check BSY. */
        !          1126:        }
        !          1127:        NCR_TRACE("reselect, valid data after %d loops\n",
        !          1128:                          ncr5380_wait_nrq_timo - timo);
        !          1129:
        !          1130:        /*
        !          1131:         * Good.  We have SEL=1 and BSY=0.  Now wait for a
        !          1132:         * "bus settle delay" before we sample the data bus
        !          1133:         */
        !          1134:        delay(2);
        !          1135:        data = *(sc->sci_data) & 0xFF;
        !          1136:        /* Parity check is implicit in data validation below. */
        !          1137:
        !          1138:        /*
        !          1139:         * Is this a reselect (I/O == 1) or have we been
        !          1140:         * selected as a target? (I/O == 0)
        !          1141:         */
        !          1142:        if ((bus & SCI_BUS_IO) == 0) {
        !          1143:                printf("%s: selected as target, data=0x%x\n",
        !          1144:                    sc->sc_dev.dv_xname, data);
        !          1145:                /* Not much we can do. Reset the bus. */
        !          1146:                /* XXX: send some sort of message? */
        !          1147:                ncr5380_reset_scsibus(sc);
        !          1148:                return;
        !          1149:        }
        !          1150:
        !          1151:        /*
        !          1152:         * OK, this is a reselection.
        !          1153:         */
        !          1154:        for (target = 0; target < 7; target++) {
        !          1155:                target_mask = (1 << target);
        !          1156:                if (data & target_mask)
        !          1157:                        break;
        !          1158:        }
        !          1159:        if ((data & 0x7F) != target_mask) {
        !          1160:                /* No selecting ID? or >2 IDs on bus? */
        !          1161:                printf("%s: bad reselect, data=0x%x\n",
        !          1162:                    sc->sc_dev.dv_xname, data);
        !          1163:                return;
        !          1164:        }
        !          1165:
        !          1166:        NCR_TRACE("reselect: target=0x%x\n", target);
        !          1167:
        !          1168:        /* Raise BSY to acknowledge target reselection. */
        !          1169:        *(sc->sci_icmd) = SCI_ICMD_BSY;
        !          1170:
        !          1171:        /* Wait for target to drop SEL. */
        !          1172:        timo = ncr5380_wait_nrq_timo;
        !          1173:        for (;;) {
        !          1174:                bus = *(sc->sci_bus_csr);
        !          1175:                if ((bus & SCI_BUS_SEL) == 0)
        !          1176:                        break;  /* success */
        !          1177:                if (--timo <= 0) {
        !          1178:                        printf("%s: reselect, SEL stuck, bus=0x%x\n",
        !          1179:                            sc->sc_dev.dv_xname, bus);
        !          1180:                        NCR_BREAK();
        !          1181:                        /* assume connected (fail later if not) */
        !          1182:                        break;
        !          1183:                }
        !          1184:                delay(2);
        !          1185:        }
        !          1186:
        !          1187:        /* Now we drop BSY, and we are connected. */
        !          1188:        *(sc->sci_icmd) = 0;
        !          1189:        *sc->sci_sel_enb = 0;
        !          1190:        SCI_CLR_INTR(sc);
        !          1191:
        !          1192:        /*
        !          1193:         * At this point the target should send an IDENTIFY message,
        !          1194:         * which will permit us to determine the reselecting LUN.
        !          1195:         * If not, we assume LUN 0.
        !          1196:         */
        !          1197:        lun = 0;
        !          1198:        /* Wait for REQ before reading bus phase. */
        !          1199:        if (ncr5380_wait_req(sc)) {
        !          1200:                printf("%s: reselect, no REQ\n",
        !          1201:                    sc->sc_dev.dv_xname);
        !          1202:                /* Try to send an ABORT message. */
        !          1203:                goto abort;
        !          1204:        }
        !          1205:        phase = SCI_BUS_PHASE(*sc->sci_bus_csr);
        !          1206:        if (phase != PHASE_MSG_IN) {
        !          1207:                printf("%s: reselect, phase=%d\n",
        !          1208:                    sc->sc_dev.dv_xname, phase);
        !          1209:                goto abort;
        !          1210:        }
        !          1211:
        !          1212:        /* Ack. the change to PHASE_MSG_IN */
        !          1213:        *(sc->sci_tcmd) = PHASE_MSG_IN;
        !          1214:
        !          1215:        /* Peek at the message byte without consuming it! */
        !          1216:        msg = *(sc->sci_data);
        !          1217:        if ((msg & 0x80) == 0) {
        !          1218:                printf("%s: reselect, not identify, msg=%d\n",
        !          1219:                    sc->sc_dev.dv_xname, msg);
        !          1220:                goto abort;
        !          1221:        }
        !          1222:        lun = msg & 7;
        !          1223:
        !          1224:        /* We now know target/LUN.  Do we have the request? */
        !          1225:        sr = sc->sc_matrix[target][lun];
        !          1226:        if (sr) {
        !          1227:                /* We now have a nexus. */
        !          1228:                sc->sc_state |= NCR_WORKING;
        !          1229:                sc->sc_current = sr;
        !          1230:                NCR_TRACE("reselect: resume sr=0x%x\n", (long)sr);
        !          1231:
        !          1232:                /* Implicit restore pointers message */
        !          1233:                sc->sc_dataptr = sr->sr_dataptr;
        !          1234:                sc->sc_datalen = sr->sr_datalen;
        !          1235:
        !          1236:                sc->sc_prevphase = PHASE_INVALID;
        !          1237:                sc->sc_msgpriq = 0;
        !          1238:                sc->sc_msgoutq = 0;
        !          1239:                sc->sc_msgout  = 0;
        !          1240:
        !          1241:                /* XXX: Restore the normal mode register. */
        !          1242:                /* If this target's bit is set, do NOT check parity. */
        !          1243:                if (sc->sc_parity_disable & target_mask)
        !          1244:                        *sc->sci_mode = (SCI_MODE_MONBSY);
        !          1245:                else
        !          1246:                        *sc->sci_mode = (SCI_MODE_MONBSY | SCI_MODE_PAR_CHK);
        !          1247:
        !          1248:                /*
        !          1249:                 * Another hack for the Sun3 "si", which needs
        !          1250:                 * some setup done to its DMA engine before the
        !          1251:                 * target puts the SCSI bus into any DATA phase.
        !          1252:                 */
        !          1253:                if (sr->sr_dma_hand && sc->sc_dma_setup) {
        !          1254:                        NCR_TRACE("reselect: call DMA setup, dh=0x%x\n",
        !          1255:                                          (long) sr->sr_dma_hand);
        !          1256:                    sc->sc_dma_setup(sc);
        !          1257:                }
        !          1258:
        !          1259:                /* Now consume the IDENTIFY message. */
        !          1260:                ncr5380_pio_in(sc, PHASE_MSG_IN, 1, &msg);
        !          1261:                return;
        !          1262:        }
        !          1263:
        !          1264:        printf("%s: phantom reselect: target=%d, LUN=%d\n",
        !          1265:            sc->sc_dev.dv_xname, target, lun);
        !          1266: abort:
        !          1267:        /*
        !          1268:         * Try to send an ABORT message.  This makes us
        !          1269:         * temporarily busy, but no current command...
        !          1270:         */
        !          1271:        sc->sc_state |= NCR_ABORTING;
        !          1272:
        !          1273:        /* Raise ATN, delay, raise ACK... */
        !          1274:        icmd = SCI_ICMD_ATN;
        !          1275:        *sc->sci_icmd = icmd;
        !          1276:        delay(2);
        !          1277:
        !          1278:        /* Now consume the IDENTIFY message. */
        !          1279:        ncr5380_pio_in(sc, PHASE_MSG_IN, 1, &msg);
        !          1280:
        !          1281:        /* Finally try to send the ABORT. */
        !          1282:        sc->sc_prevphase = PHASE_INVALID;
        !          1283:        sc->sc_msgpriq = SEND_ABORT;
        !          1284:        ncr5380_msg_out(sc);
        !          1285:
        !          1286:        *(sc->sci_tcmd) = PHASE_INVALID;
        !          1287:        *sc->sci_sel_enb = 0;
        !          1288:        SCI_CLR_INTR(sc);
        !          1289:        *sc->sci_sel_enb = 0x80;
        !          1290:
        !          1291:        sc->sc_state &= ~NCR_ABORTING;
        !          1292: }
        !          1293:
        !          1294:
        !          1295: /*
        !          1296:  *  Select target: xs is the transfer that we are selecting for.
        !          1297:  *  sc->sc_current should be NULL.
        !          1298:  *
        !          1299:  *  Returns:
        !          1300:  *     sc->sc_current != NULL  ==> we were reselected (race!)
        !          1301:  *     XS_NOERROR              ==> selection worked
        !          1302:  *     XS_BUSY                 ==> lost arbitration
        !          1303:  *     XS_SELTIMEOUT           ==> no response to selection
        !          1304:  */
        !          1305: static int
        !          1306: ncr5380_select(sc, sr)
        !          1307:        struct ncr5380_softc *sc;
        !          1308:        struct sci_req *sr;
        !          1309: {
        !          1310:        int timo, s, target_mask;
        !          1311:        u_char data, icmd;
        !          1312:
        !          1313:        /* Check for reselect */
        !          1314:        ncr5380_reselect(sc);
        !          1315:        if (sc->sc_current) {
        !          1316:                NCR_TRACE("select: reselect, cur=0x%x\n",
        !          1317:                                  (long) sc->sc_current);
        !          1318:                return XS_BUSY; /* reselected */
        !          1319:        }
        !          1320:
        !          1321:        /*
        !          1322:         * Set phase bits to 0, otherwise the 5380 won't drive the bus during
        !          1323:         * selection.
        !          1324:         */
        !          1325:        *sc->sci_tcmd = PHASE_DATA_OUT;
        !          1326:        *sc->sci_icmd = icmd = 0;
        !          1327:        *sc->sci_mode = 0;
        !          1328:
        !          1329:        /*
        !          1330:         * Arbitrate for the bus.  The 5380 takes care of the
        !          1331:         * time-critical bus interactions.  We set our ID bit
        !          1332:         * in the output data register and set MODE_ARB.  The
        !          1333:         * 5380 watches for the required "bus free" period.
        !          1334:         * If and when the "bus free" period is detected, the
        !          1335:         * 5380 drives BSY, drives the data bus, and sets the
        !          1336:         * "arbitration in progress" (AIP) bit to let us know
        !          1337:         * arbitration has started (and that it asserts BSY).
        !          1338:         * We then wait for one arbitration delay (2.2uS) and
        !          1339:         * check the ICMD_LST bit, which will be set if some
        !          1340:         * other target drives SEL during arbitration.
        !          1341:         *
        !          1342:         * There is a time-critical section during the period
        !          1343:         * after we enter arbitration up until we assert SEL.
        !          1344:         * Avoid long interrupts during this period.
        !          1345:         */
        !          1346:        s = splvm();    /* XXX: Begin time-critical section */
        !          1347:
        !          1348:        *(sc->sci_odata) = 0x80;        /* OUR_ID */
        !          1349:        *(sc->sci_mode) = SCI_MODE_ARB;
        !          1350:
        !          1351: #define        WAIT_AIP_USEC   20      /* pleanty of time */
        !          1352:        /* Wait for the AIP bit to turn on. */
        !          1353:        timo = WAIT_AIP_USEC;
        !          1354:        for (;;) {
        !          1355:                if (*(sc->sci_icmd) & SCI_ICMD_AIP)
        !          1356:                        break;
        !          1357:                if (timo <= 0) {
        !          1358:                        /*
        !          1359:                         * Did not see any "bus free" period.
        !          1360:                         * The usual reason is a reselection,
        !          1361:                         * so treat this as arbitration loss.
        !          1362:                         */
        !          1363:                        NCR_TRACE("select: bus busy, rc=%d\n", XS_BUSY);
        !          1364:                        goto lost_arb;
        !          1365:                }
        !          1366:                timo -= 2;
        !          1367:                delay(2);
        !          1368:        }
        !          1369:        NCR_TRACE("select: have AIP after %d uSec.\n",
        !          1370:                          WAIT_AIP_USEC - timo);
        !          1371:
        !          1372:        /* Got AIP.  Wait one arbitration delay (2.2 uS.) */
        !          1373:        delay(3);
        !          1374:
        !          1375:        /* Check for ICMD_LST */
        !          1376:        if (*(sc->sci_icmd) & SCI_ICMD_LST) {
        !          1377:                /* Some other target asserted SEL. */
        !          1378:                NCR_TRACE("select: lost one, rc=%d\n", XS_BUSY);
        !          1379:                goto lost_arb;
        !          1380:        }
        !          1381:
        !          1382:        /*
        !          1383:         * No other device has declared itself the winner.
        !          1384:         * The spec. says to check for higher IDs, but we
        !          1385:         * are always the highest (ID=7) so don't bother.
        !          1386:         * We can now declare victory by asserting SEL.
        !          1387:         *
        !          1388:         * Note that the 5380 is asserting BSY because we
        !          1389:         * have entered arbitration mode.  We will now hold
        !          1390:         * BSY directly so we can turn off ARB mode.
        !          1391:         */
        !          1392:        icmd = (SCI_ICMD_BSY | SCI_ICMD_SEL);
        !          1393:        *sc->sci_icmd = icmd;
        !          1394:
        !          1395:        /*
        !          1396:         * "The SCSI device that wins arbitration shall wait
        !          1397:         *  at least a bus clear delay plus a bus settle delay
        !          1398:         *  after asserting the SEL signal before changing
        !          1399:         *  any [other] signal."  (1.2uS. total)
        !          1400:         */
        !          1401:        delay(2);
        !          1402:
        !          1403:        /*
        !          1404:         * Check one last time to see if we really did
        !          1405:         * win arbitration.  This might only happen if
        !          1406:         * there can be a higher selection ID than ours.
        !          1407:         * Keep this code for reference anyway...
        !          1408:         */
        !          1409:        if (*(sc->sci_icmd) & SCI_ICMD_LST) {
        !          1410:                /* Some other target asserted SEL. */
        !          1411:                NCR_TRACE("select: lost two, rc=%d\n", XS_BUSY);
        !          1412:
        !          1413:        lost_arb:
        !          1414:                *sc->sci_icmd = 0;
        !          1415:                *sc->sci_mode = 0;
        !          1416:
        !          1417:                splx(s);        /* XXX: End of time-critical section. */
        !          1418:
        !          1419:                /*
        !          1420:                 * When we lose arbitration, it usually means
        !          1421:                 * there is a target trying to reselect us.
        !          1422:                 */
        !          1423:                ncr5380_reselect(sc);
        !          1424:                return XS_BUSY;
        !          1425:        }
        !          1426:
        !          1427:        /* Leave ARB mode Now that we drive BSY+SEL */
        !          1428:        *sc->sci_mode = 0;
        !          1429:        *sc->sci_sel_enb = 0;
        !          1430:
        !          1431:        splx(s);        /* XXX: End of time-critical section. */
        !          1432:
        !          1433:        /*
        !          1434:         * Arbitration is complete.  Now do selection:
        !          1435:         * Drive the data bus with the ID bits for both
        !          1436:         * the host and target.  Also set ATN now, to
        !          1437:         * ask the target for a message out phase.
        !          1438:         */
        !          1439:        target_mask = (1 << sr->sr_target);
        !          1440:        data = 0x80 | target_mask;
        !          1441:        *(sc->sci_odata) = data;
        !          1442:        icmd |= (SCI_ICMD_DATA | SCI_ICMD_ATN);
        !          1443:        *(sc->sci_icmd) = icmd;
        !          1444:        delay(2);       /* two deskew delays. */
        !          1445:
        !          1446:        /* De-assert BSY (targets sample the data now). */
        !          1447:        icmd &= ~SCI_ICMD_BSY;
        !          1448:        *(sc->sci_icmd) = icmd;
        !          1449:        delay(3);       /* Bus settle delay. */
        !          1450:
        !          1451:        /*
        !          1452:         * Wait for the target to assert BSY.
        !          1453:         * SCSI spec. says wait for 250 mS.
        !          1454:         */
        !          1455:        for (timo = 25000;;) {
        !          1456:                if (*sc->sci_bus_csr & SCI_BUS_BSY)
        !          1457:                        goto success;
        !          1458:                if (--timo <= 0)
        !          1459:                        break;
        !          1460:                delay(10);
        !          1461:        }
        !          1462:
        !          1463:        /*
        !          1464:         * There is no reaction from the target.  Start the selection
        !          1465:         * timeout procedure. We release the databus but keep SEL+ATN
        !          1466:         * asserted. After that we wait a 'selection abort time' (200
        !          1467:         * usecs) and 2 deskew delays (90 ns) and check BSY again.
        !          1468:         * When BSY is asserted, we assume the selection succeeded,
        !          1469:         * otherwise we release the bus.
        !          1470:         */
        !          1471:        icmd &= ~SCI_ICMD_DATA;
        !          1472:        *(sc->sci_icmd) = icmd;
        !          1473:        delay(201);
        !          1474:        if ((*sc->sci_bus_csr & SCI_BUS_BSY) == 0) {
        !          1475:                /* Really no device on bus */
        !          1476:                *sc->sci_tcmd = PHASE_INVALID;
        !          1477:                *sc->sci_icmd = 0;
        !          1478:                *sc->sci_mode = 0;
        !          1479:                *sc->sci_sel_enb = 0;
        !          1480:                SCI_CLR_INTR(sc);
        !          1481:                *sc->sci_sel_enb = 0x80;
        !          1482:                NCR_TRACE("select: device down, rc=%d\n", XS_SELTIMEOUT);
        !          1483:                return XS_SELTIMEOUT;
        !          1484:        }
        !          1485:
        !          1486: success:
        !          1487:        /*
        !          1488:         * The target is now driving BSY, so we can stop
        !          1489:         * driving SEL and the data bus (keep ATN true).
        !          1490:         * Configure the ncr5380 to monitor BSY, parity.
        !          1491:         */
        !          1492:        icmd &= ~(SCI_ICMD_DATA | SCI_ICMD_SEL);
        !          1493:        *sc->sci_icmd = icmd;
        !          1494:
        !          1495:        /* If this target's bit is set, do NOT check parity. */
        !          1496:        if (sc->sc_parity_disable & target_mask)
        !          1497:                *sc->sci_mode = (SCI_MODE_MONBSY);
        !          1498:        else
        !          1499:                *sc->sci_mode = (SCI_MODE_MONBSY | SCI_MODE_PAR_CHK);
        !          1500:
        !          1501:        return XS_NOERROR;
        !          1502: }
        !          1503:
        !          1504:
        !          1505: /*****************************************************************
        !          1506:  * Functions to handle each info. transfer phase:
        !          1507:  *****************************************************************/
        !          1508:
        !          1509: /*
        !          1510:  * The message system:
        !          1511:  *
        !          1512:  * This is a revamped message system that now should easier accommodate
        !          1513:  * new messages, if necessary.
        !          1514:  *
        !          1515:  * Currently we accept these messages:
        !          1516:  * IDENTIFY (when reselecting)
        !          1517:  * COMMAND COMPLETE # (expect bus free after messages marked #)
        !          1518:  * NOOP
        !          1519:  * MESSAGE REJECT
        !          1520:  * SYNCHRONOUS DATA TRANSFER REQUEST
        !          1521:  * SAVE DATA POINTER
        !          1522:  * RESTORE POINTERS
        !          1523:  * DISCONNECT #
        !          1524:  *
        !          1525:  * We may send these messages in prioritized order:
        !          1526:  * BUS DEVICE RESET #          if SCSI_RESET & xs->flags (or in weird sits.)
        !          1527:  * MESSAGE PARITY ERROR                par. err. during MSGI
        !          1528:  * MESSAGE REJECT              If we get a message we don't know how to handle
        !          1529:  * ABORT #                     send on errors
        !          1530:  * INITIATOR DETECTED ERROR    also on errors (SCSI2) (during info xfer)
        !          1531:  * IDENTIFY                    At the start of each transfer
        !          1532:  * SYNCHRONOUS DATA TRANSFER REQUEST   if appropriate
        !          1533:  * NOOP                                if nothing else fits the bill ...
        !          1534:  */
        !          1535:
        !          1536: #define IS1BYTEMSG(m) (((m) != 0x01 && (m) < 0x20) || (m) >= 0x80)
        !          1537: #define IS2BYTEMSG(m) (((m) & 0xf0) == 0x20)
        !          1538: #define ISEXTMSG(m) ((m) == 0x01)
        !          1539:
        !          1540: /*
        !          1541:  * Precondition:
        !          1542:  * The SCSI bus is already in the MSGI phase and there is a message byte
        !          1543:  * on the bus, along with an asserted REQ signal.
        !          1544:  *
        !          1545:  * Our return value determines whether our caller, ncr5380_machine()
        !          1546:  * will expect to see another REQ (and possibly phase change).
        !          1547:  */
        !          1548: static int
        !          1549: ncr5380_msg_in(sc)
        !          1550:        register struct ncr5380_softc *sc;
        !          1551: {
        !          1552:        struct sci_req *sr = sc->sc_current;
        !          1553:        struct scsi_xfer *xs = sr->sr_xs;
        !          1554:        int n, phase;
        !          1555:        int act_flags;
        !          1556:        register u_char icmd;
        !          1557:
        !          1558:        /* acknowledge phase change */
        !          1559:        *sc->sci_tcmd = PHASE_MSG_IN;
        !          1560:
        !          1561:        act_flags = ACT_CONTINUE;
        !          1562:        icmd = *sc->sci_icmd & SCI_ICMD_RMASK;
        !          1563:
        !          1564:        if (sc->sc_prevphase == PHASE_MSG_IN) {
        !          1565:                /* This is a continuation of the previous message. */
        !          1566:                n = sc->sc_imp - sc->sc_imess;
        !          1567:                NCR_TRACE("msg_in: continuation, n=%d\n", n);
        !          1568:                goto nextbyte;
        !          1569:        }
        !          1570:
        !          1571:        /* This is a new MESSAGE IN phase.  Clean up our state. */
        !          1572:        sc->sc_state &= ~NCR_DROP_MSGIN;
        !          1573:
        !          1574: nextmsg:
        !          1575:        n = 0;
        !          1576:        sc->sc_imp = &sc->sc_imess[n];
        !          1577:
        !          1578: nextbyte:
        !          1579:        /*
        !          1580:         * Read a whole message, but don't ack the last byte.  If we reject the
        !          1581:         * message, we have to assert ATN during the message transfer phase
        !          1582:         * itself.
        !          1583:         */
        !          1584:        for (;;) {
        !          1585:                /*
        !          1586:                 * Read a message byte.
        !          1587:                 * First, check BSY, REQ, phase...
        !          1588:                 */
        !          1589:                if (!SCI_BUSY(sc)) {
        !          1590:                        NCR_TRACE("msg_in: lost BSY, n=%d\n", n);
        !          1591:                        /* XXX - Assume the command completed? */
        !          1592:                        act_flags |= (ACT_DISCONNECT | ACT_CMD_DONE);
        !          1593:                        return (act_flags);
        !          1594:                }
        !          1595:                if (ncr5380_wait_req(sc)) {
        !          1596:                        NCR_TRACE("msg_in: BSY but no REQ, n=%d\n", n);
        !          1597:                        /* Just let ncr5380_machine() handle it... */
        !          1598:                        return (act_flags);
        !          1599:                }
        !          1600:                phase = SCI_BUS_PHASE(*sc->sci_bus_csr);
        !          1601:                if (phase != PHASE_MSG_IN) {
        !          1602:                        /*
        !          1603:                         * Target left MESSAGE IN, probably because it
        !          1604:                         * a) noticed our ATN signal, or
        !          1605:                         * b) ran out of messages.
        !          1606:                         */
        !          1607:                        return (act_flags);
        !          1608:                }
        !          1609:                /* Still in MESSAGE IN phase, and REQ is asserted. */
        !          1610:                if (*sc->sci_csr & SCI_CSR_PERR) {
        !          1611:                        ncr_sched_msgout(sc, SEND_PARITY_ERROR);
        !          1612:                        sc->sc_state |= NCR_DROP_MSGIN;
        !          1613:                }
        !          1614:
        !          1615:                /* Gather incoming message bytes if needed. */
        !          1616:                if ((sc->sc_state & NCR_DROP_MSGIN) == 0) {
        !          1617:                        if (n >= NCR_MAX_MSG_LEN) {
        !          1618:                                ncr_sched_msgout(sc, SEND_REJECT);
        !          1619:                                sc->sc_state |= NCR_DROP_MSGIN;
        !          1620:                        } else {
        !          1621:                                *sc->sc_imp++ = *sc->sci_data;
        !          1622:                                n++;
        !          1623:                                /*
        !          1624:                                 * This testing is suboptimal, but most
        !          1625:                                 * messages will be of the one byte variety, so
        !          1626:                                 * it should not affect performance
        !          1627:                                 * significantly.
        !          1628:                                 */
        !          1629:                                if (n == 1 && IS1BYTEMSG(sc->sc_imess[0]))
        !          1630:                                        goto have_msg;
        !          1631:                                if (n == 2 && IS2BYTEMSG(sc->sc_imess[0]))
        !          1632:                                        goto have_msg;
        !          1633:                                if (n >= 3 && ISEXTMSG(sc->sc_imess[0]) &&
        !          1634:                                        n == sc->sc_imess[1] + 2)
        !          1635:                                        goto have_msg;
        !          1636:                        }
        !          1637:                }
        !          1638:
        !          1639:                /*
        !          1640:                 * If we reach this spot we're either:
        !          1641:                 * a) in the middle of a multi-byte message, or
        !          1642:                 * b) dropping bytes.
        !          1643:                 */
        !          1644:
        !          1645:                /* Ack the last byte read. */
        !          1646:                icmd |= SCI_ICMD_ACK;
        !          1647:                *sc->sci_icmd = icmd;
        !          1648:
        !          1649:                if (ncr5380_wait_not_req(sc)) {
        !          1650:                        NCR_TRACE("msg_in: drop, stuck REQ, n=%d\n", n);
        !          1651:                        act_flags |= ACT_RESET_BUS;
        !          1652:                }
        !          1653:
        !          1654:                icmd &= ~SCI_ICMD_ACK;
        !          1655:                *sc->sci_icmd = icmd;
        !          1656:
        !          1657:                if (act_flags != ACT_CONTINUE)
        !          1658:                        return (act_flags);
        !          1659:
        !          1660:                /* back to nextbyte */
        !          1661:        }
        !          1662:
        !          1663: have_msg:
        !          1664:        /* We now have a complete message.  Parse it. */
        !          1665:
        !          1666:        switch (sc->sc_imess[0]) {
        !          1667:        case MSG_CMDCOMPLETE:
        !          1668:                NCR_TRACE("msg_in: CMDCOMPLETE\n", 0);
        !          1669:                /* Target is about to disconnect. */
        !          1670:                act_flags |= (ACT_DISCONNECT | ACT_CMD_DONE);
        !          1671:                break;
        !          1672:
        !          1673:        case MSG_PARITY_ERROR:
        !          1674:                NCR_TRACE("msg_in: PARITY_ERROR\n", 0);
        !          1675:                /* Resend the last message. */
        !          1676:                ncr_sched_msgout(sc, sc->sc_msgout);
        !          1677:                /* Reset icmd after scheduling the REJECT cmd - jwg */
        !          1678:                icmd = *sc->sci_icmd & SCI_ICMD_RMASK;
        !          1679:                break;
        !          1680:
        !          1681:        case MSG_MESSAGE_REJECT:
        !          1682:                /* The target rejects the last message we sent. */
        !          1683:                NCR_TRACE("msg_in: got reject for 0x%x\n", sc->sc_msgout);
        !          1684:                switch (sc->sc_msgout) {
        !          1685:                case SEND_IDENTIFY:
        !          1686:                        /* Really old target controller? */
        !          1687:                        /* XXX ... */
        !          1688:                        break;
        !          1689:                case SEND_INIT_DET_ERR:
        !          1690:                        goto abort;
        !          1691:                }
        !          1692:                break;
        !          1693:
        !          1694:        case MSG_NOOP:
        !          1695:                NCR_TRACE("msg_in: NOOP\n", 0);
        !          1696:                break;
        !          1697:
        !          1698:        case MSG_DISCONNECT:
        !          1699:                NCR_TRACE("msg_in: DISCONNECT\n", 0);
        !          1700:                /* Target is about to disconnect. */
        !          1701:                act_flags |= ACT_DISCONNECT;
        !          1702:                if ((xs->sc_link->quirks & SDEV_AUTOSAVE) == 0)
        !          1703:                        break;
        !          1704:                /*FALLTHROUGH*/
        !          1705:
        !          1706:        case MSG_SAVEDATAPOINTER:
        !          1707:                NCR_TRACE("msg_in: SAVE_PTRS\n", 0);
        !          1708:                sr->sr_dataptr = sc->sc_dataptr;
        !          1709:                sr->sr_datalen = sc->sc_datalen;
        !          1710:                break;
        !          1711:
        !          1712:        case MSG_RESTOREPOINTERS:
        !          1713:                NCR_TRACE("msg_in: RESTORE_PTRS\n", 0);
        !          1714:                sc->sc_dataptr = sr->sr_dataptr;
        !          1715:                sc->sc_datalen = sr->sr_datalen;
        !          1716:                break;
        !          1717:
        !          1718:        case MSG_EXTENDED:
        !          1719:                switch (sc->sc_imess[2]) {
        !          1720:                case MSG_EXT_SDTR:
        !          1721:                case MSG_EXT_WDTR:
        !          1722:                        /* The ncr5380 can not do synchronous mode. */
        !          1723:                        goto reject;
        !          1724:                default:
        !          1725:                        printf("%s: unrecognized MESSAGE EXTENDED; sending REJECT\n",
        !          1726:                            sc->sc_dev.dv_xname);
        !          1727:                        NCR_BREAK();
        !          1728:                        goto reject;
        !          1729:                }
        !          1730:                break;
        !          1731:
        !          1732:        default:
        !          1733:                NCR_TRACE("msg_in: eh? imsg=0x%x\n", sc->sc_imess[0]);
        !          1734:                printf("%s: unrecognized MESSAGE; sending REJECT\n",
        !          1735:                    sc->sc_dev.dv_xname);
        !          1736:                NCR_BREAK();
        !          1737:                /* fallthrough */
        !          1738:        reject:
        !          1739:                ncr_sched_msgout(sc, SEND_REJECT);
        !          1740:                /* Reset icmd after scheduling the REJECT cmd - jwg */
        !          1741:                icmd = *sc->sci_icmd & SCI_ICMD_RMASK;
        !          1742:                break;
        !          1743:
        !          1744:        abort:
        !          1745:                sc->sc_state |= NCR_ABORTING;
        !          1746:                ncr_sched_msgout(sc, SEND_ABORT);
        !          1747:                break;
        !          1748:        }
        !          1749:
        !          1750:        /* Ack the last byte read. */
        !          1751:        icmd |= SCI_ICMD_ACK;
        !          1752:        *sc->sci_icmd = icmd;
        !          1753:
        !          1754:        if (ncr5380_wait_not_req(sc)) {
        !          1755:                NCR_TRACE("msg_in: last, stuck REQ, n=%d\n", n);
        !          1756:                act_flags |= ACT_RESET_BUS;
        !          1757:        }
        !          1758:
        !          1759:        icmd &= ~SCI_ICMD_ACK;
        !          1760:        *sc->sci_icmd = icmd;
        !          1761:
        !          1762:        /* Go get the next message, if any. */
        !          1763:        if (act_flags == ACT_CONTINUE)
        !          1764:                goto nextmsg;
        !          1765:
        !          1766:        return (act_flags);
        !          1767: }
        !          1768:
        !          1769:
        !          1770: /*
        !          1771:  * The message out (and in) stuff is a bit complicated:
        !          1772:  * If the target requests another message (sequence) without
        !          1773:  * having changed phase in between it really asks for a
        !          1774:  * retransmit, probably due to parity error(s).
        !          1775:  * The following messages can be sent:
        !          1776:  * IDENTIFY       @ These 4 stem from SCSI command activity
        !          1777:  * SDTR                   @
        !          1778:  * WDTR                   @
        !          1779:  * DEV_RESET      @
        !          1780:  * REJECT if MSGI doesn't make sense
        !          1781:  * PARITY_ERROR if parity error while in MSGI
        !          1782:  * INIT_DET_ERR if parity error while not in MSGI
        !          1783:  * ABORT if INIT_DET_ERR rejected
        !          1784:  * NOOP if asked for a message and there's nothing to send
        !          1785:  *
        !          1786:  * Note that we call this one with (sc_current == NULL)
        !          1787:  * when sending ABORT for unwanted reselections.
        !          1788:  */
        !          1789: static int
        !          1790: ncr5380_msg_out(sc)
        !          1791:        register struct ncr5380_softc *sc;
        !          1792: {
        !          1793:        struct sci_req *sr = sc->sc_current;
        !          1794:        int act_flags, n, phase, progress;
        !          1795:        register u_char icmd, msg;
        !          1796:
        !          1797:        /* acknowledge phase change */
        !          1798:        *sc->sci_tcmd = PHASE_MSG_OUT;
        !          1799:
        !          1800:        progress = 0;   /* did we send any messages? */
        !          1801:        act_flags = ACT_CONTINUE;
        !          1802:
        !          1803:        /*
        !          1804:         * Set ATN.  If we're just sending a trivial 1-byte message,
        !          1805:         * we'll clear ATN later on anyway.  Also drive the data bus.
        !          1806:         */
        !          1807:        icmd = *sc->sci_icmd & SCI_ICMD_RMASK;
        !          1808:        icmd |= (SCI_ICMD_ATN | SCI_ICMD_DATA);
        !          1809:        *sc->sci_icmd = icmd;
        !          1810:
        !          1811:        if (sc->sc_prevphase == PHASE_MSG_OUT) {
        !          1812:                if (sc->sc_omp == sc->sc_omess) {
        !          1813:                        /*
        !          1814:                         * This is a retransmission.
        !          1815:                         *
        !          1816:                         * We get here if the target stayed in MESSAGE OUT
        !          1817:                         * phase.  Section 5.1.9.2 of the SCSI 2 spec indicates
        !          1818:                         * that all of the previously transmitted messages must
        !          1819:                         * be sent again, in the same order.  Therefore, we
        !          1820:                         * requeue all the previously transmitted messages, and
        !          1821:                         * start again from the top.  Our simple priority
        !          1822:                         * scheme keeps the messages in the right order.
        !          1823:                         */
        !          1824:                        sc->sc_msgpriq |= sc->sc_msgoutq;
        !          1825:                        NCR_TRACE("msg_out: retrans priq=0x%x\n", sc->sc_msgpriq);
        !          1826:                } else {
        !          1827:                        /* This is a continuation of the previous message. */
        !          1828:                        n = sc->sc_omp - sc->sc_omess;
        !          1829:                        NCR_TRACE("msg_out: continuation, n=%d\n", n);
        !          1830:                        goto nextbyte;
        !          1831:                }
        !          1832:        }
        !          1833:
        !          1834:        /* No messages transmitted so far. */
        !          1835:        sc->sc_msgoutq = 0;
        !          1836:
        !          1837: nextmsg:
        !          1838:        /* Pick up highest priority message. */
        !          1839:        sc->sc_msgout = sc->sc_msgpriq & -sc->sc_msgpriq;
        !          1840:        sc->sc_msgpriq &= ~sc->sc_msgout;
        !          1841:        sc->sc_msgoutq |= sc->sc_msgout;
        !          1842:
        !          1843:        /* Build the outgoing message data. */
        !          1844:        switch (sc->sc_msgout) {
        !          1845:        case SEND_IDENTIFY:
        !          1846:                NCR_TRACE("msg_out: SEND_IDENTIFY\n", 0);
        !          1847:                if (sr == NULL) {
        !          1848:                        printf("%s: SEND_IDENTIFY while not connected; sending NOOP\n",
        !          1849:                            sc->sc_dev.dv_xname);
        !          1850:                        NCR_BREAK();
        !          1851:                        goto noop;
        !          1852:                }
        !          1853:                /*
        !          1854:                 * The identify message we send determines whether
        !          1855:                 * disconnect/reselect is allowed for this command.
        !          1856:                 * 0xC0+LUN: allows it, 0x80+LUN disallows it.
        !          1857:                 */
        !          1858:                msg = 0xc0;     /* MSG_IDENTIFY(0,1) */
        !          1859:                if (sc->sc_no_disconnect & (1 << sr->sr_target))
        !          1860:                        msg = 0x80;
        !          1861:                if (sr->sr_flags & (SR_IMMED | SR_SENSE))
        !          1862:                        msg = 0x80;
        !          1863:                sc->sc_omess[0] = msg | sr->sr_lun;
        !          1864:                n = 1;
        !          1865:                break;
        !          1866:
        !          1867:        case SEND_DEV_RESET:
        !          1868:                NCR_TRACE("msg_out: SEND_DEV_RESET\n", 0);
        !          1869:                /* Expect disconnect after this! */
        !          1870:                /* XXX: Kill jobs for this target? */
        !          1871:                act_flags |= (ACT_DISCONNECT | ACT_CMD_DONE);
        !          1872:                sc->sc_omess[0] = MSG_BUS_DEV_RESET;
        !          1873:                n = 1;
        !          1874:                break;
        !          1875:
        !          1876:        case SEND_REJECT:
        !          1877:                NCR_TRACE("msg_out: SEND_REJECT\n", 0);
        !          1878:                sc->sc_omess[0] = MSG_MESSAGE_REJECT;
        !          1879:                n = 1;
        !          1880:                break;
        !          1881:
        !          1882:        case SEND_PARITY_ERROR:
        !          1883:                NCR_TRACE("msg_out: SEND_PARITY_ERROR\n", 0);
        !          1884:                sc->sc_omess[0] = MSG_PARITY_ERROR;
        !          1885:                n = 1;
        !          1886:                break;
        !          1887:
        !          1888:        case SEND_INIT_DET_ERR:
        !          1889:                NCR_TRACE("msg_out: SEND_INIT_DET_ERR\n", 0);
        !          1890:                sc->sc_omess[0] = MSG_INITIATOR_DET_ERR;
        !          1891:                n = 1;
        !          1892:                break;
        !          1893:
        !          1894:        case SEND_ABORT:
        !          1895:                NCR_TRACE("msg_out: SEND_ABORT\n", 0);
        !          1896:                /* Expect disconnect after this! */
        !          1897:                /* XXX: Set error flag? */
        !          1898:                act_flags |= (ACT_DISCONNECT | ACT_CMD_DONE);
        !          1899:                sc->sc_omess[0] = MSG_ABORT;
        !          1900:                n = 1;
        !          1901:                break;
        !          1902:
        !          1903:        case 0:
        !          1904:                printf("%s: unexpected MESSAGE OUT; sending NOOP\n",
        !          1905:                    sc->sc_dev.dv_xname);
        !          1906:                NCR_BREAK();
        !          1907:        noop:
        !          1908:                NCR_TRACE("msg_out: send NOOP\n", 0);
        !          1909:                sc->sc_omess[0] = MSG_NOOP;
        !          1910:                n = 1;
        !          1911:                break;
        !          1912:
        !          1913:        default:
        !          1914:                printf("%s: weird MESSAGE OUT; sending NOOP\n",
        !          1915:                    sc->sc_dev.dv_xname);
        !          1916:                NCR_BREAK();
        !          1917:                goto noop;
        !          1918:        }
        !          1919:        sc->sc_omp = &sc->sc_omess[n];
        !          1920:
        !          1921: nextbyte:
        !          1922:        /* Send message bytes. */
        !          1923:        while (n > 0) {
        !          1924:                /*
        !          1925:                 * Send a message byte.
        !          1926:                 * First check BSY, REQ, phase...
        !          1927:                 */
        !          1928:                if (!SCI_BUSY(sc)) {
        !          1929:                        NCR_TRACE("msg_out: lost BSY, n=%d\n", n);
        !          1930:                        goto out;
        !          1931:                }
        !          1932:                if (ncr5380_wait_req(sc)) {
        !          1933:                        NCR_TRACE("msg_out: no REQ, n=%d\n", n);
        !          1934:                        goto out;
        !          1935:                }
        !          1936:                phase = SCI_BUS_PHASE(*sc->sci_bus_csr);
        !          1937:                if (phase != PHASE_MSG_OUT) {
        !          1938:                        /*
        !          1939:                         * Target left MESSAGE OUT, possibly to reject
        !          1940:                         * our message.
        !          1941:                         */
        !          1942:                        NCR_TRACE("msg_out: new phase=%d\n", phase);
        !          1943:                        goto out;
        !          1944:                }
        !          1945:
        !          1946:                /* Yes, we can send this message byte. */
        !          1947:                --n;
        !          1948:
        !          1949:                /* Clear ATN before last byte if this is the last message. */
        !          1950:                if (n == 0 && sc->sc_msgpriq == 0) {
        !          1951:                        icmd &= ~SCI_ICMD_ATN;
        !          1952:                        *sc->sci_icmd = icmd;
        !          1953:                        /* 2 deskew delays */
        !          1954:                        delay(2);       /* XXX */
        !          1955:                }
        !          1956:
        !          1957:                /* Put data on the bus. */
        !          1958:                *sc->sci_odata = *--sc->sc_omp;
        !          1959:
        !          1960:                /* Raise ACK to tell target data is on the bus. */
        !          1961:                icmd |= SCI_ICMD_ACK;
        !          1962:                *sc->sci_icmd = icmd;
        !          1963:
        !          1964:                /* Wait for REQ to be negated. */
        !          1965:                if (ncr5380_wait_not_req(sc)) {
        !          1966:                        NCR_TRACE("msg_out: stuck REQ, n=%d\n", n);
        !          1967:                        act_flags |= ACT_RESET_BUS;
        !          1968:                }
        !          1969:
        !          1970:                /* Finally, drop ACK. */
        !          1971:                icmd &= ~SCI_ICMD_ACK;
        !          1972:                *sc->sci_icmd = icmd;
        !          1973:
        !          1974:                /* Stuck bus or something... */
        !          1975:                if (act_flags & ACT_RESET_BUS)
        !          1976:                        goto out;
        !          1977:
        !          1978:        }
        !          1979:        progress++;
        !          1980:
        !          1981:        /* We get here only if the entire message has been transmitted. */
        !          1982:        if (sc->sc_msgpriq != 0) {
        !          1983:                /* There are more outgoing messages. */
        !          1984:                goto nextmsg;
        !          1985:        }
        !          1986:
        !          1987:        /*
        !          1988:         * The last message has been transmitted.  We need to remember the last
        !          1989:         * message transmitted (in case the target switches to MESSAGE IN phase
        !          1990:         * and sends a MESSAGE REJECT), and the list of messages transmitted
        !          1991:         * this time around (in case the target stays in MESSAGE OUT phase to
        !          1992:         * request a retransmit).
        !          1993:         */
        !          1994:
        !          1995: out:
        !          1996:        /* Stop driving the data bus. */
        !          1997:        icmd &= ~SCI_ICMD_DATA;
        !          1998:        *sc->sci_icmd = icmd;
        !          1999:
        !          2000:        if (!progress)
        !          2001:                act_flags |= ACT_RESET_BUS;
        !          2002:
        !          2003:        return (act_flags);
        !          2004: }
        !          2005:
        !          2006:
        !          2007: /*
        !          2008:  * Handle command phase.
        !          2009:  */
        !          2010: static int
        !          2011: ncr5380_command(sc)
        !          2012:        struct ncr5380_softc *sc;
        !          2013: {
        !          2014:        struct sci_req *sr = sc->sc_current;
        !          2015:        struct scsi_xfer *xs = sr->sr_xs;
        !          2016:        struct scsi_sense rqs;
        !          2017:        int len;
        !          2018:
        !          2019:        /* acknowledge phase change */
        !          2020:        *sc->sci_tcmd = PHASE_COMMAND;
        !          2021:
        !          2022:        if (sr->sr_flags & SR_SENSE) {
        !          2023:                rqs.opcode = REQUEST_SENSE;
        !          2024:                rqs.byte2 = xs->sc_link->lun << 5;
        !          2025:                rqs.length = sizeof(xs->sense);
        !          2026:
        !          2027:                rqs.unused[0] = rqs.unused[1] = rqs.control = 0;
        !          2028:                len = ncr5380_pio_out(sc, PHASE_COMMAND, sizeof(rqs),
        !          2029:                        (u_char *)&rqs);
        !          2030:        }
        !          2031:        else {
        !          2032:                /* Assume command can be sent in one go. */
        !          2033:                /* XXX: Do this using DMA, and get a phase change intr? */
        !          2034:                len = ncr5380_pio_out(sc, PHASE_COMMAND, xs->cmdlen,
        !          2035:                        (u_char *)xs->cmd);
        !          2036:        }
        !          2037:
        !          2038:        if (len != xs->cmdlen) {
        !          2039: #ifdef NCR5380_DEBUG
        !          2040:                printf("ncr5380_command: short transfer: wanted %d got %d.\n",
        !          2041:                    xs->cmdlen, len);
        !          2042:                ncr5380_show_scsi_cmd(xs);
        !          2043:                NCR_BREAK();
        !          2044: #endif
        !          2045:                if (len < 6) {
        !          2046:                        xs->error = XS_DRIVER_STUFFUP;
        !          2047:                        sc->sc_state |= NCR_ABORTING;
        !          2048:                        ncr_sched_msgout(sc, SEND_ABORT);
        !          2049:                }
        !          2050:
        !          2051:        }
        !          2052:
        !          2053:        return ACT_CONTINUE;
        !          2054: }
        !          2055:
        !          2056:
        !          2057: /*
        !          2058:  * Handle either data_in or data_out
        !          2059:  */
        !          2060: static int
        !          2061: ncr5380_data_xfer(sc, phase)
        !          2062:        struct ncr5380_softc *sc;
        !          2063:        int phase;
        !          2064: {
        !          2065:        struct sci_req *sr = sc->sc_current;
        !          2066:        struct scsi_xfer *xs = sr->sr_xs;
        !          2067:        int expected_phase;
        !          2068:        int len;
        !          2069:
        !          2070:        if (sr->sr_flags & SR_SENSE) {
        !          2071:                NCR_TRACE("data_xfer: get sense, sr=0x%x\n", (long)sr);
        !          2072:                if (phase != PHASE_DATA_IN) {
        !          2073:                        printf("%s: sense phase error\n", sc->sc_dev.dv_xname);
        !          2074:                        goto abort;
        !          2075:                }
        !          2076:                /* acknowledge phase change */
        !          2077:                *sc->sci_tcmd = PHASE_DATA_IN;
        !          2078:                len = ncr5380_pio_in(sc, phase, sizeof(xs->sense),
        !          2079:                                (u_char *)&xs->sense);
        !          2080:                return ACT_CONTINUE;
        !          2081:        }
        !          2082:
        !          2083:        /*
        !          2084:         * When aborting a command, disallow any data phase.
        !          2085:         */
        !          2086:        if (sc->sc_state & NCR_ABORTING) {
        !          2087:                printf("%s: aborting, but phase=%s (reset)\n",
        !          2088:                    sc->sc_dev.dv_xname, phase_names[phase & 7]);
        !          2089:                return ACT_RESET_BUS;   /* XXX */
        !          2090:        }
        !          2091:
        !          2092:        /* Validate expected phase (data_in or data_out) */
        !          2093:        expected_phase = (xs->flags & SCSI_DATA_OUT) ?
        !          2094:                PHASE_DATA_OUT : PHASE_DATA_IN;
        !          2095:        if (phase != expected_phase) {
        !          2096:                printf("%s: data phase error\n", sc->sc_dev.dv_xname);
        !          2097:                goto abort;
        !          2098:        }
        !          2099:
        !          2100:        /* Make sure we have some data to move. */
        !          2101:        if (sc->sc_datalen <= 0) {
        !          2102:                /* Device needs padding. */
        !          2103:                if (phase == PHASE_DATA_IN)
        !          2104:                        ncr5380_pio_in(sc, phase, 4096, NULL);
        !          2105:                else
        !          2106:                        ncr5380_pio_out(sc, phase, 4096, NULL);
        !          2107:                /* Make sure that caused a phase change. */
        !          2108:                if (SCI_BUS_PHASE(*sc->sci_bus_csr) == phase) {
        !          2109:                        /* More than 4k is just too much! */
        !          2110:                        printf("%s: too much data padding\n",
        !          2111:                               sc->sc_dev.dv_xname);
        !          2112:                        goto abort;
        !          2113:                }
        !          2114:                return ACT_CONTINUE;
        !          2115:        }
        !          2116:
        !          2117:        /*
        !          2118:         * Attempt DMA only if dma_alloc gave us a DMA handle AND
        !          2119:         * there is enough left to transfer so DMA is worth while.
        !          2120:         */
        !          2121:        if (sr->sr_dma_hand &&
        !          2122:                (sc->sc_datalen >= sc->sc_min_dma_len))
        !          2123:        {
        !          2124:                /*
        !          2125:                 * OK, really start DMA.  Note, the MD start function
        !          2126:                 * is responsible for setting the TCMD register, etc.
        !          2127:                 * (Acknowledge the phase change there, not here.)
        !          2128:                 */
        !          2129:                NCR_TRACE("data_xfer: dma_start, dh=0x%x\n",
        !          2130:                          (long) sr->sr_dma_hand);
        !          2131:                (*sc->sc_dma_start)(sc);
        !          2132:                return ACT_WAIT_DMA;
        !          2133:        }
        !          2134:
        !          2135:        /*
        !          2136:         * Doing PIO for data transfer.  (Possibly "Pseudo DMA")
        !          2137:         * XXX:  Do PDMA functions need to set tcmd later?
        !          2138:         */
        !          2139:        NCR_TRACE("data_xfer: doing PIO, len=%d\n", sc->sc_datalen);
        !          2140:        /* acknowledge phase change */
        !          2141:        *sc->sci_tcmd = phase;  /* XXX: OK for PDMA? */
        !          2142:        if (phase == PHASE_DATA_OUT) {
        !          2143:                len = (*sc->sc_pio_out)(sc, phase, sc->sc_datalen, sc->sc_dataptr);
        !          2144:        } else {
        !          2145:                len = (*sc->sc_pio_in) (sc, phase, sc->sc_datalen, sc->sc_dataptr);
        !          2146:        }
        !          2147:        sc->sc_dataptr += len;
        !          2148:        sc->sc_datalen -= len;
        !          2149:
        !          2150:        NCR_TRACE("data_xfer: did PIO, resid=%d\n", sc->sc_datalen);
        !          2151:        return (ACT_CONTINUE);
        !          2152:
        !          2153: abort:
        !          2154:        sc->sc_state |= NCR_ABORTING;
        !          2155:        ncr_sched_msgout(sc, SEND_ABORT);
        !          2156:        return (ACT_CONTINUE);
        !          2157: }
        !          2158:
        !          2159:
        !          2160: static int
        !          2161: ncr5380_status(sc)
        !          2162:        struct ncr5380_softc *sc;
        !          2163: {
        !          2164:        int len;
        !          2165:        u_char status;
        !          2166:        struct sci_req *sr = sc->sc_current;
        !          2167:
        !          2168:        /* acknowledge phase change */
        !          2169:        *sc->sci_tcmd = PHASE_STATUS;
        !          2170:
        !          2171:        len = ncr5380_pio_in(sc, PHASE_STATUS, 1, &status);
        !          2172:        if (len) {
        !          2173:                sr->sr_status = status;
        !          2174:        } else {
        !          2175:                printf("ncr5380_status: none?\n");
        !          2176:        }
        !          2177:
        !          2178:        return ACT_CONTINUE;
        !          2179: }
        !          2180:
        !          2181:
        !          2182: /*
        !          2183:  * This is the big state machine that follows SCSI phase changes.
        !          2184:  * This is somewhat like a co-routine.  It will do a SCSI command,
        !          2185:  * and exit if the command is complete, or if it must wait, i.e.
        !          2186:  * for DMA to complete or for reselect to resume the job.
        !          2187:  *
        !          2188:  * The bus must be selected, and we need to know which command is
        !          2189:  * being undertaken.
        !          2190:  */
        !          2191: static void
        !          2192: ncr5380_machine(sc)
        !          2193:        struct ncr5380_softc *sc;
        !          2194: {
        !          2195:        struct sci_req *sr;
        !          2196:        struct scsi_xfer *xs;
        !          2197:        int act_flags, phase, timo;
        !          2198:
        !          2199: #ifdef DIAGNOSTIC
        !          2200:        if (sc->sc_state == NCR_IDLE)
        !          2201:                panic("ncr5380_machine: state=idle");
        !          2202:        if (sc->sc_current == NULL)
        !          2203:                panic("ncr5380_machine: no current cmd");
        !          2204: #endif
        !          2205:
        !          2206:        sr = sc->sc_current;
        !          2207:        xs = sr->sr_xs;
        !          2208:        act_flags = ACT_CONTINUE;
        !          2209:
        !          2210:        /*
        !          2211:         * This will be called by ncr5380_intr() when DMA is
        !          2212:         * complete.  Must stop DMA before touching the 5380 or
        !          2213:         * there will be "register conflict" errors.
        !          2214:         */
        !          2215:        if (sc->sc_state & NCR_DOINGDMA) {
        !          2216:                /* Pick-up where where we left off... */
        !          2217:                goto dma_done;
        !          2218:        }
        !          2219:
        !          2220: next_phase:
        !          2221:
        !          2222:        if (!SCI_BUSY(sc)) {
        !          2223:                /* Unexpected disconnect */
        !          2224:                printf("ncr5380_machine: unexpected disconnect.\n");
        !          2225:                xs->error = XS_DRIVER_STUFFUP;
        !          2226:                act_flags |= (ACT_DISCONNECT | ACT_CMD_DONE);
        !          2227:                goto do_actions;
        !          2228:        }
        !          2229:
        !          2230:        /*
        !          2231:         * Wait for REQ before reading the phase.
        !          2232:         * Need to wait longer than usual here, because
        !          2233:         * some devices are just plain slow...
        !          2234:         */
        !          2235:        timo = ncr5380_wait_phase_timo;
        !          2236:        for (;;) {
        !          2237:                if (*sc->sci_bus_csr & SCI_BUS_REQ)
        !          2238:                        break;
        !          2239:                if (--timo <= 0) {
        !          2240:                        if (sc->sc_state & NCR_ABORTING) {
        !          2241:                                printf("%s: no REQ while aborting, reset\n",
        !          2242:                                    sc->sc_dev.dv_xname);
        !          2243:                                act_flags |= ACT_RESET_BUS;
        !          2244:                                goto do_actions;
        !          2245:                        }
        !          2246:                        printf("%s: no REQ for next phase, abort\n",
        !          2247:                            sc->sc_dev.dv_xname);
        !          2248:                        sc->sc_state |= NCR_ABORTING;
        !          2249:                        ncr_sched_msgout(sc, SEND_ABORT);
        !          2250:                        goto next_phase;
        !          2251:                }
        !          2252:                delay(100);
        !          2253:        }
        !          2254:
        !          2255:        phase = SCI_BUS_PHASE(*sc->sci_bus_csr);
        !          2256:        NCR_TRACE("machine: phase=%s\n",
        !          2257:                          (long) phase_names[phase & 7]);
        !          2258:
        !          2259:        /*
        !          2260:         * We assume that the device knows what it's doing,
        !          2261:         * so any phase is good.
        !          2262:         */
        !          2263:
        !          2264: #if 0
        !          2265:        /*
        !          2266:         * XXX: Do not ACK the phase yet! do it later...
        !          2267:         * XXX: ... each phase routine does that itself.
        !          2268:         * In particular, DMA needs it done LATER.
        !          2269:         */
        !          2270:        *sc->sci_tcmd = phase;  /* acknowledge phase change */
        !          2271: #endif
        !          2272:
        !          2273:        switch (phase) {
        !          2274:
        !          2275:        case PHASE_DATA_OUT:
        !          2276:        case PHASE_DATA_IN:
        !          2277:                act_flags = ncr5380_data_xfer(sc, phase);
        !          2278:                break;
        !          2279:
        !          2280:        case PHASE_COMMAND:
        !          2281:                act_flags = ncr5380_command(sc);
        !          2282:                break;
        !          2283:
        !          2284:        case PHASE_STATUS:
        !          2285:                act_flags = ncr5380_status(sc);
        !          2286:                break;
        !          2287:
        !          2288:        case PHASE_MSG_OUT:
        !          2289:                act_flags = ncr5380_msg_out(sc);
        !          2290:                break;
        !          2291:
        !          2292:        case PHASE_MSG_IN:
        !          2293:                act_flags = ncr5380_msg_in(sc);
        !          2294:                break;
        !          2295:
        !          2296:        default:
        !          2297:                printf("ncr5380_machine: Unexpected phase 0x%x\n", phase);
        !          2298:                sc->sc_state |= NCR_ABORTING;
        !          2299:                ncr_sched_msgout(sc, SEND_ABORT);
        !          2300:                goto next_phase;
        !          2301:
        !          2302:        } /* switch */
        !          2303:        sc->sc_prevphase = phase;
        !          2304:
        !          2305: do_actions:
        !          2306:        __asm("_ncr5380_actions:");
        !          2307:
        !          2308:        if (act_flags & ACT_WAIT_DMA) {
        !          2309:                act_flags &= ~ACT_WAIT_DMA;
        !          2310:                /* Wait for DMA to complete (polling, or interrupt). */
        !          2311:                if ((sr->sr_flags & SR_IMMED) == 0) {
        !          2312:                        NCR_TRACE("machine: wait for DMA intr.\n", 0);
        !          2313:                        return;         /* will resume at dma_done */
        !          2314:                }
        !          2315:                /* Busy-wait for it to finish. */
        !          2316:                NCR_TRACE("machine: dma_poll, dh=0x%x\n",
        !          2317:                                  (long) sr->sr_dma_hand);
        !          2318:                (*sc->sc_dma_poll)(sc);
        !          2319:        dma_done:
        !          2320:                /* Return here after interrupt. */
        !          2321:                if (sr->sr_flags & SR_OVERDUE)
        !          2322:                        sc->sc_state |= NCR_ABORTING;
        !          2323:                NCR_TRACE("machine: dma_stop, dh=0x%x\n",
        !          2324:                                  (long) sr->sr_dma_hand);
        !          2325:                (*sc->sc_dma_stop)(sc);
        !          2326:                SCI_CLR_INTR(sc);       /* XXX */
        !          2327:                /*
        !          2328:                 * While DMA is running we can not touch the SBC,
        !          2329:                 * so various places just set NCR_ABORTING and
        !          2330:                 * expect us the "kick it" when DMA is done.
        !          2331:                 */
        !          2332:                if (sc->sc_state & NCR_ABORTING) {
        !          2333:                        ncr_sched_msgout(sc, SEND_ABORT);
        !          2334:                }
        !          2335:        }
        !          2336:
        !          2337:        /*
        !          2338:         * Check for parity error.
        !          2339:         * XXX - better place to check?
        !          2340:         */
        !          2341:        if (*(sc->sci_csr) & SCI_CSR_PERR) {
        !          2342:                printf("%s: parity error!\n", sc->sc_dev.dv_xname);
        !          2343:                /* XXX: sc->sc_state |= NCR_ABORTING; */
        !          2344:                ncr_sched_msgout(sc, SEND_PARITY_ERROR);
        !          2345:        }
        !          2346:
        !          2347:        if (act_flags == ACT_CONTINUE)
        !          2348:                goto next_phase;
        !          2349:        /* All other actions "break" from the loop. */
        !          2350:
        !          2351:        NCR_TRACE("machine: act_flags=0x%x\n", act_flags);
        !          2352:
        !          2353:        if (act_flags & ACT_RESET_BUS) {
        !          2354:                act_flags |= ACT_CMD_DONE;
        !          2355:                /*
        !          2356:                 * Reset the SCSI bus, usually due to a timeout.
        !          2357:                 * The error code XS_TIMEOUT allows retries.
        !          2358:                 */
        !          2359:                sc->sc_state |= NCR_ABORTING;
        !          2360:                printf("%s: reset SCSI bus for TID=%d LUN=%d\n",
        !          2361:                    sc->sc_dev.dv_xname, sr->sr_target, sr->sr_lun);
        !          2362:                ncr5380_reset_scsibus(sc);
        !          2363:        }
        !          2364:
        !          2365:        if (act_flags & ACT_CMD_DONE) {
        !          2366:                act_flags |= ACT_DISCONNECT;
        !          2367:                /* Need to call scsi_done() */
        !          2368:                /* XXX: from the aic6360 driver, but why? */
        !          2369:                if (sc->sc_datalen < 0) {
        !          2370:                        printf("%s: %d extra bytes from %d:%d\n",
        !          2371:                            sc->sc_dev.dv_xname, -sc->sc_datalen,
        !          2372:                            sr->sr_target, sr->sr_lun);
        !          2373:                        sc->sc_datalen = 0;
        !          2374:                }
        !          2375:                xs->resid = sc->sc_datalen;
        !          2376:                /* Note: this will clear sc_current */
        !          2377:                NCR_TRACE("machine: call done, cur=0x%x\n", (long)sr);
        !          2378:                ncr5380_done(sc);
        !          2379:        }
        !          2380:
        !          2381:        if (act_flags & ACT_DISCONNECT) {
        !          2382:                /*
        !          2383:                 * The device has dropped BSY (or will soon).
        !          2384:                 * We have to wait here for BSY to drop, otherwise
        !          2385:                 * the next command may decide we need a bus reset.
        !          2386:                 */
        !          2387:                timo = ncr5380_wait_req_timo;   /* XXX */
        !          2388:                for (;;) {
        !          2389:                        if (!SCI_BUSY(sc))
        !          2390:                                goto busfree;
        !          2391:                        if (--timo <= 0)
        !          2392:                                break;
        !          2393:                        delay(2);
        !          2394:                }
        !          2395:                /* Device is sitting on the bus! */
        !          2396:                printf("%s: Target %d LUN %d stuck busy, resetting...\n",
        !          2397:                    sc->sc_dev.dv_xname, sr->sr_target, sr->sr_lun);
        !          2398:                ncr5380_reset_scsibus(sc);
        !          2399:        busfree:
        !          2400:                NCR_TRACE("machine: discon, waited %d\n",
        !          2401:                        ncr5380_wait_req_timo - timo);
        !          2402:
        !          2403:                *sc->sci_icmd = 0;
        !          2404:                *sc->sci_mode = 0;
        !          2405:                *sc->sci_tcmd = PHASE_INVALID;
        !          2406:                *sc->sci_sel_enb = 0;
        !          2407:                SCI_CLR_INTR(sc);
        !          2408:                *sc->sci_sel_enb = 0x80;
        !          2409:
        !          2410:                if ((act_flags & ACT_CMD_DONE) == 0) {
        !          2411:                        __asm("_ncr5380_disconnected:");
        !          2412:                        NCR_TRACE("machine: discon, cur=0x%x\n", (long)sr);
        !          2413:                }
        !          2414:
        !          2415:                /*
        !          2416:                 * We may be here due to a disconnect message,
        !          2417:                 * in which case we did NOT call ncr5380_done,
        !          2418:                 * and we need to clear sc_current.
        !          2419:                 */
        !          2420:                sc->sc_state = NCR_IDLE;
        !          2421:                sc->sc_current = NULL;
        !          2422:
        !          2423:                /* Paranoia: clear everything. */
        !          2424:                sc->sc_dataptr = NULL;
        !          2425:                sc->sc_datalen = 0;
        !          2426:                sc->sc_prevphase = PHASE_INVALID;
        !          2427:                sc->sc_msgpriq = 0;
        !          2428:                sc->sc_msgoutq = 0;
        !          2429:                sc->sc_msgout  = 0;
        !          2430:
        !          2431:                /* Our caller will re-enable interrupts. */
        !          2432:        }
        !          2433: }
        !          2434:
        !          2435:
        !          2436: #ifdef NCR5380_DEBUG
        !          2437:
        !          2438: static void
        !          2439: ncr5380_show_scsi_cmd(xs)
        !          2440:        struct scsi_xfer *xs;
        !          2441: {
        !          2442:        u_char  *b = (u_char *) xs->cmd;
        !          2443:        int     i  = 0;
        !          2444:
        !          2445:        if ( ! ( xs->flags & SCSI_RESET ) ) {
        !          2446:                printf("si(%d:%d:%d)-",
        !          2447:                    xs->sc_link->scsibus, xs->sc_link->target,
        !          2448:                    xs->sc_link->lun);
        !          2449:                while (i < xs->cmdlen) {
        !          2450:                        if (i) printf(",");
        !          2451:                        printf("%x",b[i++]);
        !          2452:                }
        !          2453:                printf("-\n");
        !          2454:        } else {
        !          2455:                printf("si(%d:%d:%d)-RESET-\n",
        !          2456:                    xs->sc_link->scsibus, xs->sc_link->target,
        !          2457:                    xs->sc_link->lun);
        !          2458:        }
        !          2459: }
        !          2460:
        !          2461:
        !          2462: static void
        !          2463: ncr5380_show_sense(xs)
        !          2464:        struct scsi_xfer *xs;
        !          2465: {
        !          2466:        u_char  *b = (u_char *)&xs->sense;
        !          2467:        int     i;
        !          2468:
        !          2469:        printf("sense:");
        !          2470:        for (i = 0; i < sizeof(xs->sense); i++)
        !          2471:                printf(" %02x", b[i]);
        !          2472:        printf("\n");
        !          2473: }
        !          2474:
        !          2475: int ncr5380_traceidx = 0;
        !          2476:
        !          2477: #define        TRACE_MAX       1024
        !          2478: struct trace_ent {
        !          2479:        char *msg;
        !          2480:        long  val;
        !          2481: } ncr5380_tracebuf[TRACE_MAX];
        !          2482:
        !          2483: void
        !          2484: ncr5380_trace(msg, val)
        !          2485:        char *msg;
        !          2486:        long  val;
        !          2487: {
        !          2488:        register struct trace_ent *tr;
        !          2489:        register int s;
        !          2490:
        !          2491:        s = splbio();
        !          2492:
        !          2493:        tr = &ncr5380_tracebuf[ncr5380_traceidx];
        !          2494:
        !          2495:        ncr5380_traceidx++;
        !          2496:        if (ncr5380_traceidx >= TRACE_MAX)
        !          2497:                ncr5380_traceidx = 0;
        !          2498:
        !          2499:        tr->msg = msg;
        !          2500:        tr->val = val;
        !          2501:
        !          2502:        splx(s);
        !          2503: }
        !          2504:
        !          2505: #ifdef DDB
        !          2506: void
        !          2507: ncr5380_clear_trace()
        !          2508: {
        !          2509:        ncr5380_traceidx = 0;
        !          2510:        bzero((char *) ncr5380_tracebuf, sizeof(ncr5380_tracebuf));
        !          2511: }
        !          2512:
        !          2513: void
        !          2514: ncr5380_show_trace()
        !          2515: {
        !          2516:        struct trace_ent *tr;
        !          2517:        int idx;
        !          2518:
        !          2519:        idx = ncr5380_traceidx;
        !          2520:        do {
        !          2521:                tr = &ncr5380_tracebuf[idx];
        !          2522:                idx++;
        !          2523:                if (idx >= TRACE_MAX)
        !          2524:                        idx = 0;
        !          2525:                if (tr->msg)
        !          2526:                        db_printf(tr->msg, tr->val);
        !          2527:        } while (idx != ncr5380_traceidx);
        !          2528: }
        !          2529:
        !          2530: void
        !          2531: ncr5380_show_req(sr)
        !          2532:        struct sci_req *sr;
        !          2533: {
        !          2534:        struct scsi_xfer *xs = sr->sr_xs;
        !          2535:
        !          2536:        db_printf("TID=%d ",    sr->sr_target);
        !          2537:        db_printf("LUN=%d ",    sr->sr_lun);
        !          2538:        db_printf("dh=%p ",     sr->sr_dma_hand);
        !          2539:        db_printf("dptr=%p ",   sr->sr_dataptr);
        !          2540:        db_printf("dlen=0x%x ", sr->sr_datalen);
        !          2541:        db_printf("flags=%d ",  sr->sr_flags);
        !          2542:        db_printf("stat=%d ",   sr->sr_status);
        !          2543:
        !          2544:        if (xs == NULL) {
        !          2545:                db_printf("(xs=NULL)\n");
        !          2546:                return;
        !          2547:        }
        !          2548:        db_printf("\n");
        !          2549: #ifdef SCSIDEBUG
        !          2550:        show_scsi_xs(xs);
        !          2551: #else
        !          2552:        db_printf("xs=%p\n", xs);
        !          2553: #endif
        !          2554: }
        !          2555:
        !          2556: void
        !          2557: ncr5380_show_state()
        !          2558: {
        !          2559:        struct ncr5380_softc *sc;
        !          2560:        struct sci_req *sr;
        !          2561:        int i, j, k;
        !          2562:
        !          2563:        sc = ncr5380_debug_sc;
        !          2564:
        !          2565:        if (sc == NULL) {
        !          2566:                db_printf("ncr5380_debug_sc == NULL\n");
        !          2567:                return;
        !          2568:        }
        !          2569:
        !          2570:        db_printf("sc_ncmds=%d\n",      sc->sc_ncmds);
        !          2571:        k = -1; /* which is current? */
        !          2572:        for (i = 0; i < SCI_OPENINGS; i++) {
        !          2573:                sr = &sc->sc_ring[i];
        !          2574:                if (sr->sr_xs) {
        !          2575:                        if (sr == sc->sc_current)
        !          2576:                                k = i;
        !          2577:                        db_printf("req %d: (sr=%p)", i, (long)sr);
        !          2578:                        ncr5380_show_req(sr);
        !          2579:                }
        !          2580:        }
        !          2581:        db_printf("sc_rr=%d, current=%d\n", sc->sc_rr, k);
        !          2582:
        !          2583:        db_printf("Active request matrix:\n");
        !          2584:        for(i = 0; i < 8; i++) {                /* targets */
        !          2585:                for (j = 0; j < 8; j++) {       /* LUN */
        !          2586:                        sr = sc->sc_matrix[i][j];
        !          2587:                        if (sr) {
        !          2588:                                db_printf("TID=%d LUN=%d sr=0x%x\n", i, j, (long)sr);
        !          2589:                        }
        !          2590:                }
        !          2591:        }
        !          2592:
        !          2593:        db_printf("sc_state=0x%x\n",    sc->sc_state);
        !          2594:        db_printf("sc_current=%p\n",    sc->sc_current);
        !          2595:        db_printf("sc_dataptr=%p\n",    sc->sc_dataptr);
        !          2596:        db_printf("sc_datalen=0x%x\n",  sc->sc_datalen);
        !          2597:
        !          2598:        db_printf("sc_prevphase=%d\n",  sc->sc_prevphase);
        !          2599:        db_printf("sc_msgpriq=0x%x\n",  sc->sc_msgpriq);
        !          2600: }
        !          2601:
        !          2602: #endif /* DDB */
        !          2603: #endif /* NCR5380_DEBUG */

CVSweb