Annotation of 43BSDReno/sys/hpdev/scsi.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1990 The Regents of the University of California.
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * This code is derived from software contributed to Berkeley by
        !             6:  * Van Jacobson of Lawrence Berkeley Laboratory.
        !             7:  *
        !             8:  * Redistribution is only permitted until one year after the first shipment
        !             9:  * of 4.4BSD by the Regents.  Otherwise, redistribution and use in source and
        !            10:  * binary forms are permitted provided that: (1) source distributions retain
        !            11:  * this entire copyright notice and comment, and (2) distributions including
        !            12:  * binaries display the following acknowledgement:  This product includes
        !            13:  * software developed by the University of California, Berkeley and its
        !            14:  * contributors'' in the documentation or other materials provided with the
        !            15:  * distribution and in all advertising materials mentioning features or use
        !            16:  * of this software.  Neither the name of the University nor the names of
        !            17:  * its contributors may be used to endorse or promote products derived from
        !            18:  * this software without specific prior written permission.
        !            19:  * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
        !            20:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
        !            21:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
        !            22:  *
        !            23:  *     @(#)scsi.c      7.1 (Berkeley) 5/8/90
        !            24:  */
        !            25: 
        !            26: /*
        !            27:  * HP9000/3xx 98658 SCSI host adaptor driver.
        !            28:  */
        !            29: #include "scsi.h"
        !            30: #if NSCSI > 0
        !            31: 
        !            32: #ifndef lint
        !            33: static char rcsid[] = "$Header: scsi.c,v 1.3 90/01/06 04:56:50 van Exp $";
        !            34: #endif
        !            35: 
        !            36: #include "param.h"
        !            37: #include "systm.h"
        !            38: #include "buf.h"
        !            39: #include "device.h"
        !            40: #include "scsivar.h"
        !            41: #include "scsireg.h"
        !            42: #include "dmavar.h"
        !            43: 
        !            44: #include "machine/cpu.h"
        !            45: #include "machine/isr.h"
        !            46: 
        !            47: extern void isrlink();
        !            48: extern void printf();
        !            49: extern void _insque();
        !            50: extern void _remque();
        !            51: extern void bzero();
        !            52: 
        !            53: int    scsiinit(), scsigo(), scsiintr(), scsixfer();
        !            54: void   scsistart(), scsidone(), scsifree(), scsireset();
        !            55: struct driver scsidriver = {
        !            56:        scsiinit, "scsi", (int (*)())scsistart, scsigo, scsiintr,
        !            57:        (int (*)())scsidone,
        !            58: };
        !            59: 
        !            60: struct scsi_softc scsi_softc[NSCSI];
        !            61: struct isr scsi_isr[NSCSI];
        !            62: 
        !            63: int scsi_cmd_wait = 512;       /* microsec wait per step of 'immediate' cmds */
        !            64: int scsi_data_wait = 512;      /* wait per data in/out step */
        !            65: int scsi_nosync = 1;           /* inhibit sync xfers if 1 */
        !            66: 
        !            67: #ifdef DEBUG
        !            68: int    scsi_debug = 0;
        !            69: #define WAITHIST
        !            70: #endif
        !            71: 
        !            72: #ifdef WAITHIST
        !            73: #define MAXWAIT        2048
        !            74: u_int  ixstart_wait[MAXWAIT+2];
        !            75: u_int  ixin_wait[MAXWAIT+2];
        !            76: u_int  ixout_wait[MAXWAIT+2];
        !            77: u_int  mxin_wait[MAXWAIT+2];
        !            78: u_int  cxin_wait[MAXWAIT+2];
        !            79: u_int  fxfr_wait[MAXWAIT+2];
        !            80: u_int  sgo_wait[MAXWAIT+2];
        !            81: #define HIST(h,w) (++h[((w)>MAXWAIT? MAXWAIT : ((w) < 0 ? -1 : (w))) + 1]);
        !            82: #else
        !            83: #define HIST(h,w)
        !            84: #endif
        !            85: 
        !            86: #define        b_cylin         b_resid
        !            87: 
        !            88: static void
        !            89: scsiabort(hs, hd, where)
        !            90:        register struct scsi_softc *hs;
        !            91:        volatile register struct scsidevice *hd;
        !            92:        char *where;
        !            93: {
        !            94:        int len;
        !            95:        u_char junk;
        !            96: 
        !            97:        printf("scsi%d: abort from %s: phase=0x%x, ssts=0x%x, ints=0x%x\n",
        !            98:                hs->sc_hc->hp_unit, where, hd->scsi_psns, hd->scsi_ssts,
        !            99:                hd->scsi_ints);
        !           100: 
        !           101:        hd->scsi_ints = hd->scsi_ints;
        !           102:        hd->scsi_csr = 0;
        !           103:        if (hd->scsi_psns == 0 || (hd->scsi_ssts & SSTS_INITIATOR) == 0)
        !           104:                /* no longer connected to scsi target */
        !           105:                return;
        !           106: 
        !           107:        /* get the number of bytes remaining in current xfer + fudge */
        !           108:        len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) | hd->scsi_tcl;
        !           109: 
        !           110:        /* for that many bus cycles, try to send an abort msg */
        !           111:        for (len += 1024; (hd->scsi_ssts & SSTS_INITIATOR) && --len >= 0; ) {
        !           112:                hd->scsi_scmd = SCMD_SET_ATN;
        !           113:                while ((hd->scsi_psns & PSNS_REQ) == 0) {
        !           114:                        if (! (hd->scsi_ssts & SSTS_INITIATOR))
        !           115:                                goto out;
        !           116:                        DELAY(1);
        !           117:                }
        !           118:                if ((hd->scsi_psns & PHASE) == MESG_OUT_PHASE)
        !           119:                        hd->scsi_scmd = SCMD_RST_ATN;
        !           120:                hd->scsi_pctl = hd->scsi_psns & PHASE;
        !           121:                if (hd->scsi_psns & PHASE_IO) {
        !           122:                        /* one of the input phases - read & discard a byte */
        !           123:                        hd->scsi_scmd = SCMD_SET_ACK;
        !           124:                        if (hd->scsi_tmod == 0)
        !           125:                                while (hd->scsi_psns & PSNS_REQ)
        !           126:                                        DELAY(1);
        !           127:                        junk = hd->scsi_temp;
        !           128:                } else {
        !           129:                        /* one of the output phases - send an abort msg */
        !           130:                        hd->scsi_temp = MSG_ABORT;
        !           131:                        hd->scsi_scmd = SCMD_SET_ACK;
        !           132:                        if (hd->scsi_tmod == 0)
        !           133:                                while (hd->scsi_psns & PSNS_REQ)
        !           134:                                        DELAY(1);
        !           135:                }
        !           136:                hd->scsi_scmd = SCMD_RST_ACK;
        !           137:        }
        !           138: out:
        !           139:        /*
        !           140:         * Either the abort was successful & the bus is disconnected or
        !           141:         * the device didn't listen.  If the latter, announce the problem.
        !           142:         * Either way, reset the card & the SPC.
        !           143:         */
        !           144:        if (len < 0 && hs)
        !           145:                printf("scsi%d: abort failed.  phase=0x%x, ssts=0x%x\n",
        !           146:                        hs->sc_hc->hp_unit, hd->scsi_psns, hd->scsi_ssts);
        !           147: 
        !           148:        if (! ((junk = hd->scsi_ints) & INTS_RESEL)) {
        !           149:                hd->scsi_sctl |= SCTL_CTRLRST;
        !           150:                DELAY(1);
        !           151:                hd->scsi_sctl &=~ SCTL_CTRLRST;
        !           152:                hd->scsi_hconf = 0;
        !           153:                hd->scsi_ints = hd->scsi_ints;
        !           154:        }
        !           155: }
        !           156: 
        !           157: int
        !           158: scsiinit(hc)
        !           159:        register struct hp_ctlr *hc;
        !           160: {
        !           161:        register struct scsi_softc *hs = &scsi_softc[hc->hp_unit];
        !           162:        register struct scsidevice *hd = (struct scsidevice *)hc->hp_addr;
        !           163:        
        !           164:        if ((hd->scsi_id & ID_MASK) != SCSI_ID)
        !           165:                return(0);
        !           166:        hc->hp_ipl = SCSI_IPL(hd->scsi_csr);
        !           167:        hs->sc_hc = hc;
        !           168:        hs->sc_dq.dq_unit = hc->hp_unit;
        !           169:        hs->sc_dq.dq_driver = &scsidriver;
        !           170:        hs->sc_sq.dq_forw = hs->sc_sq.dq_back = &hs->sc_sq;
        !           171:        scsi_isr[hc->hp_unit].isr_intr = scsiintr;
        !           172:        scsi_isr[hc->hp_unit].isr_ipl = hc->hp_ipl;
        !           173:        scsi_isr[hc->hp_unit].isr_arg = hc->hp_unit;
        !           174:        isrlink(&scsi_isr[hc->hp_unit]);
        !           175:        scsireset(hc->hp_unit);
        !           176:        return(1);
        !           177: }
        !           178: 
        !           179: void
        !           180: scsireset(unit)
        !           181:        register int unit;
        !           182: {
        !           183:        register struct scsi_softc *hs = &scsi_softc[unit];
        !           184:        volatile register struct scsidevice *hd =
        !           185:                                (struct scsidevice *)hs->sc_hc->hp_addr;
        !           186:        u_int i;
        !           187: 
        !           188:        if (hs->sc_flags & SCSI_ALIVE)
        !           189:                scsiabort(hs, hd, "reset");
        !           190:                
        !           191:        printf("scsi%d: ", unit);
        !           192: 
        !           193:        hd->scsi_id = 0xFF;
        !           194:        DELAY(100);
        !           195:        /*
        !           196:         * Disable interrupts then reset the FUJI chip.
        !           197:         */
        !           198:        hd->scsi_csr  = 0;
        !           199:        hd->scsi_sctl = SCTL_DISABLE | SCTL_CTRLRST;
        !           200:        hd->scsi_scmd = 0;
        !           201:        hd->scsi_tmod = 0;
        !           202:        hd->scsi_pctl = 0;
        !           203:        hd->scsi_temp = 0;
        !           204:        hd->scsi_tch  = 0;
        !           205:        hd->scsi_tcm  = 0;
        !           206:        hd->scsi_tcl  = 0;
        !           207:        hd->scsi_ints = 0;
        !           208: 
        !           209:        if ((hd->scsi_id & ID_WORD_DMA) == 0) {
        !           210:                hs->sc_flags |= SCSI_DMA32;
        !           211:                printf("32 bit dma, ");
        !           212:        }
        !           213: 
        !           214:        /* Determine Max Synchronous Transfer Rate */
        !           215:        if (scsi_nosync)
        !           216:                i = 3;
        !           217:        else
        !           218:                i = SCSI_SYNC_XFER(hd->scsi_hconf);
        !           219:        switch (i) {
        !           220:                case 0:
        !           221:                        hs->sc_sync = TMOD_SYNC | 0x3e; /* 250 nsecs */
        !           222:                        printf("250ns sync");
        !           223:                        break;
        !           224:                case 1:
        !           225:                        hs->sc_sync = TMOD_SYNC | 0x5e; /* 375 nsecs */
        !           226:                        printf("375ns sync");
        !           227:                        break;
        !           228:                case 2:
        !           229:                        hs->sc_sync = TMOD_SYNC | 0x7d; /* 500 nsecs */
        !           230:                        printf("500ns sync");
        !           231:                        break;
        !           232:                case 3:
        !           233:                        hs->sc_sync = 0;
        !           234:                        printf("async");
        !           235:                        break;
        !           236:                }
        !           237: 
        !           238:        /*
        !           239:         * Configure the FUJI chip with its SCSI address, all
        !           240:         * interrupts enabled & appropriate parity.
        !           241:         */
        !           242:        i = (~hd->scsi_hconf) & 0x7;
        !           243:        hs->sc_scsi_addr = 1 << i;
        !           244:        hd->scsi_bdid = i;
        !           245:        if (hd->scsi_hconf & HCONF_PARITY)
        !           246:                hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB |
        !           247:                                SCTL_SEL_ENAB | SCTL_RESEL_ENAB |
        !           248:                                SCTL_INTR_ENAB | SCTL_PARITY_ENAB;
        !           249:        else {
        !           250:                hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB |
        !           251:                                SCTL_SEL_ENAB | SCTL_RESEL_ENAB |
        !           252:                                SCTL_INTR_ENAB;
        !           253:                printf(", no parity");
        !           254:        }
        !           255:        hd->scsi_sctl &=~ SCTL_DISABLE;
        !           256: 
        !           257:        printf(", scsi id %d\n", i);
        !           258:        hs->sc_flags |= SCSI_ALIVE;
        !           259: }
        !           260: 
        !           261: static void
        !           262: scsierror(hs, hd, ints)
        !           263:        register struct scsi_softc *hs;
        !           264:        volatile register struct scsidevice *hd;
        !           265:        u_char ints;
        !           266: {
        !           267:        int unit = hs->sc_hc->hp_unit;
        !           268:        char *sep = "";
        !           269: 
        !           270:        printf("scsi%d: ", unit);
        !           271:        if (ints & INTS_RST) {
        !           272:                DELAY(100);
        !           273:                if (hd->scsi_hconf & HCONF_SD)
        !           274:                        printf("spurious RST interrupt");
        !           275:                else
        !           276:                        printf("hardware error - check fuse");
        !           277:                sep = ", ";
        !           278:        }
        !           279:        if ((ints & INTS_HARD_ERR) || hd->scsi_serr) {
        !           280:                if (hd->scsi_serr & SERR_SCSI_PAR) {
        !           281:                        printf("%sparity err", sep);
        !           282:                        sep = ", ";
        !           283:                }
        !           284:                if (hd->scsi_serr & SERR_SPC_PAR) {
        !           285:                        printf("%sSPC parity err", sep);
        !           286:                        sep = ", ";
        !           287:                }
        !           288:                if (hd->scsi_serr & SERR_TC_PAR) {
        !           289:                        printf("%sTC parity err", sep);
        !           290:                        sep = ", ";
        !           291:                }
        !           292:                if (hd->scsi_serr & SERR_PHASE_ERR) {
        !           293:                        printf("%sphase err", sep);
        !           294:                        sep = ", ";
        !           295:                }
        !           296:                if (hd->scsi_serr & SERR_SHORT_XFR) {
        !           297:                        printf("%ssync short transfer err", sep);
        !           298:                        sep = ", ";
        !           299:                }
        !           300:                if (hd->scsi_serr & SERR_OFFSET) {
        !           301:                        printf("%ssync offset error", sep);
        !           302:                        sep = ", ";
        !           303:                }
        !           304:        }
        !           305:        if (ints & INTS_TIMEOUT)
        !           306:                printf("%sSPC select timeout error", sep);
        !           307:        if (ints & INTS_SRV_REQ)
        !           308:                printf("%sspurious SRV_REQ interrupt", sep);
        !           309:        if (ints & INTS_CMD_DONE)
        !           310:                printf("%sspurious CMD_DONE interrupt", sep);
        !           311:        if (ints & INTS_DISCON)
        !           312:                printf("%sspurious disconnect interrupt", sep);
        !           313:        if (ints & INTS_RESEL)
        !           314:                printf("%sspurious reselect interrupt", sep);
        !           315:        if (ints & INTS_SEL)
        !           316:                printf("%sspurious select interrupt", sep);
        !           317:        printf("\n");
        !           318: }
        !           319: 
        !           320: static int
        !           321: issue_select(hd, target, our_addr)
        !           322:        volatile register struct scsidevice *hd;
        !           323:        u_char target, our_addr;
        !           324: {
        !           325:        if (hd->scsi_ssts & (SSTS_INITIATOR|SSTS_TARGET|SSTS_BUSY))
        !           326:                return (1);
        !           327: 
        !           328:        if (hd->scsi_ints & INTS_DISCON)
        !           329:                hd->scsi_ints = INTS_DISCON;
        !           330: 
        !           331:        hd->scsi_pctl = 0;
        !           332:        hd->scsi_temp = (1 << target) | our_addr;
        !           333:        /* select timeout is hardcoded to 2ms */
        !           334:        hd->scsi_tch = 0;
        !           335:        hd->scsi_tcm = 32;
        !           336:        hd->scsi_tcl = 4;
        !           337: 
        !           338:        hd->scsi_scmd = SCMD_SELECT;
        !           339:        return (0);
        !           340: }
        !           341: 
        !           342: static int
        !           343: wait_for_select(hd)
        !           344:        volatile register struct scsidevice *hd;
        !           345: {
        !           346:        u_char ints;
        !           347: 
        !           348:        while ((ints = hd->scsi_ints) == 0)
        !           349:                DELAY(1);
        !           350:        hd->scsi_ints = ints;
        !           351:        return (!(hd->scsi_ssts & SSTS_INITIATOR));
        !           352: }
        !           353: 
        !           354: static int
        !           355: ixfer_start(hd, len, phase, wait)
        !           356:        volatile register struct scsidevice *hd;
        !           357:        int len;
        !           358:        u_char phase;
        !           359:        register int wait;
        !           360: {
        !           361: 
        !           362:        hd->scsi_tch = len >> 16;
        !           363:        hd->scsi_tcm = len >> 8;
        !           364:        hd->scsi_tcl = len;
        !           365:        hd->scsi_pctl = phase;
        !           366:        hd->scsi_tmod = 0; /*XXX*/
        !           367:        hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR;
        !           368: 
        !           369:        /* wait for xfer to start or svc_req interrupt */
        !           370:        while ((hd->scsi_ssts & SSTS_BUSY) == 0) {
        !           371:                if (hd->scsi_ints || --wait < 0) {
        !           372: #ifdef DEBUG
        !           373:                        if (scsi_debug)
        !           374:                                printf("ixfer_start fail: i%x, w%d\n",
        !           375:                                       hd->scsi_ints, wait);
        !           376: #endif
        !           377:                        HIST(ixstart_wait, wait)
        !           378:                        return (0);
        !           379:                }
        !           380:                DELAY(1);
        !           381:        }
        !           382:        HIST(ixstart_wait, wait)
        !           383:        return (1);
        !           384: }
        !           385: 
        !           386: static int
        !           387: ixfer_out(hd, len, buf)
        !           388:        volatile register struct scsidevice *hd;
        !           389:        int len;
        !           390:        register u_char *buf;
        !           391: {
        !           392:        register int wait = scsi_data_wait;
        !           393: 
        !           394:        for (; len > 0; --len) {
        !           395:                while (hd->scsi_ssts & SSTS_DREG_FULL) {
        !           396:                        if (hd->scsi_ints || --wait < 0) {
        !           397: #ifdef DEBUG
        !           398:                                if (scsi_debug)
        !           399:                                        printf("ixfer_out fail: l%d i%x w%d\n",
        !           400:                                               len, hd->scsi_ints, wait);
        !           401: #endif
        !           402:                                HIST(ixout_wait, wait)
        !           403:                                return (len);
        !           404:                        }
        !           405:                        DELAY(1);
        !           406:                }
        !           407:                hd->scsi_dreg = *buf++;
        !           408:        }
        !           409:        HIST(ixout_wait, wait)
        !           410:        return (0);
        !           411: }
        !           412: 
        !           413: static void
        !           414: ixfer_in(hd, len, buf)
        !           415:        volatile register struct scsidevice *hd;
        !           416:        int len;
        !           417:        register u_char *buf;
        !           418: {
        !           419:        register int wait = scsi_data_wait;
        !           420: 
        !           421:        for (; len > 0; --len) {
        !           422:                while (hd->scsi_ssts & SSTS_DREG_EMPTY) {
        !           423:                        if (hd->scsi_ints || --wait < 0) {
        !           424:                                while (! (hd->scsi_ssts & SSTS_DREG_EMPTY)) {
        !           425:                                        *buf++ = hd->scsi_dreg;
        !           426:                                        --len;
        !           427:                                }
        !           428: #ifdef DEBUG
        !           429:                                if (scsi_debug)
        !           430:                                        printf("ixfer_in fail: l%d i%x w%d\n",
        !           431:                                               len, hd->scsi_ints, wait);
        !           432: #endif
        !           433:                                HIST(ixin_wait, wait)
        !           434:                                return;
        !           435:                        }
        !           436:                        DELAY(1);
        !           437:                }
        !           438:                *buf++ = hd->scsi_dreg;
        !           439:        }
        !           440:        HIST(ixin_wait, wait)
        !           441: }
        !           442: 
        !           443: static int
        !           444: mxfer_in(hd, len, buf, phase)
        !           445:        volatile register struct scsidevice *hd;
        !           446:        register int len;
        !           447:        register u_char *buf;
        !           448:        register u_char phase;
        !           449: {
        !           450:        register int wait = scsi_cmd_wait;
        !           451:        register int i;
        !           452: 
        !           453:        hd->scsi_tmod = 0;
        !           454:        for (i = 0; i < len; ++i) {
        !           455:                /*
        !           456:                 * wait for the request line (which says the target
        !           457:                 * wants to give us data).  If the phase changes while
        !           458:                 * we're waiting, we're done.
        !           459:                 */
        !           460:                while ((hd->scsi_psns & PSNS_REQ) == 0) {
        !           461:                        if (--wait < 0) {
        !           462:                                HIST(mxin_wait, wait)
        !           463:                                return (-1);
        !           464:                        }
        !           465:                        if ((hd->scsi_psns & PHASE) != phase ||
        !           466:                            (hd->scsi_ssts & SSTS_INITIATOR) == 0)
        !           467:                                goto out;
        !           468: 
        !           469:                        DELAY(1);
        !           470:                }
        !           471:                /*
        !           472:                 * set ack (which says we're ready for the data, wait for
        !           473:                 * req to go away (target says data is available), grab the
        !           474:                 * data, then reset ack (say we've got the data).
        !           475:                 */
        !           476:                hd->scsi_pctl = phase;
        !           477:                hd->scsi_scmd = SCMD_SET_ACK;
        !           478:                while (hd->scsi_psns & PSNS_REQ) {
        !           479:                        if (--wait < 0) {
        !           480:                                HIST(mxin_wait, wait)
        !           481:                                return (-2);
        !           482:                        }
        !           483:                        DELAY(1);
        !           484:                }
        !           485:                *buf++ = hd->scsi_temp;
        !           486:                hd->scsi_scmd = SCMD_RST_ACK;
        !           487:                if (hd->scsi_psns & PSNS_ATN)
        !           488:                        hd->scsi_scmd = SCMD_RST_ATN;
        !           489:        }
        !           490: out:
        !           491:        HIST(mxin_wait, wait)
        !           492:        return (i);
        !           493: }
        !           494: 
        !           495: /*
        !           496:  * SCSI 'immediate' command:  issue a command to some SCSI device
        !           497:  * and get back an 'immediate' response (i.e., do programmed xfer
        !           498:  * to get the response data).  'cbuf' is a buffer containing a scsi
        !           499:  * command of length clen bytes.  'buf' is a buffer of length 'len'
        !           500:  * bytes for data.  The transfer direction is determined by the device
        !           501:  * (i.e., by the scsi bus data xfer phase).  If 'len' is zero, the
        !           502:  * command must supply no data.  'xferphase' is the bus phase the
        !           503:  * caller expects to happen after the command is issued.  It should
        !           504:  * be one of DATA_IN_PHASE, DATA_OUT_PHASE or STATUS_PHASE.
        !           505:  */
        !           506: static int
        !           507: scsiicmd(hs, target, cbuf, clen, buf, len, xferphase)
        !           508:        struct scsi_softc *hs;
        !           509:        int target;
        !           510:        u_char *cbuf;
        !           511:        int clen;
        !           512:        u_char *buf;
        !           513:        int len;
        !           514:        u_char xferphase;
        !           515: {
        !           516:        volatile register struct scsidevice *hd =
        !           517:                                (struct scsidevice *)hs->sc_hc->hp_addr;
        !           518:        u_char phase, ints;
        !           519:        register int wait;
        !           520: 
        !           521:        /* select the SCSI bus (it's an error if bus isn't free) */
        !           522:        if (issue_select(hd, target, hs->sc_scsi_addr))
        !           523:                return (-1);
        !           524:        if (wait_for_select(hd))
        !           525:                return (-1);
        !           526:        /*
        !           527:         * Wait for a phase change (or error) then let the device
        !           528:         * sequence us through the various SCSI phases.
        !           529:         */
        !           530:        hs->sc_stat[0] = 0xff;
        !           531:        hs->sc_msg[0] = 0xff;
        !           532:        phase = CMD_PHASE;
        !           533:        while (1) {
        !           534:                wait = scsi_cmd_wait;
        !           535:                switch (phase) {
        !           536: 
        !           537:                case CMD_PHASE:
        !           538:                        if (ixfer_start(hd, clen, phase, wait))
        !           539:                                if (ixfer_out(hd, clen, cbuf))
        !           540:                                        goto abort;
        !           541:                        phase = xferphase;
        !           542:                        break;
        !           543: 
        !           544:                case DATA_IN_PHASE:
        !           545:                        if (len <= 0)
        !           546:                                goto abort;
        !           547:                        wait = scsi_data_wait;
        !           548:                        if (ixfer_start(hd, len, phase, wait) ||
        !           549:                            !(hd->scsi_ssts & SSTS_DREG_EMPTY))
        !           550:                                ixfer_in(hd, len, buf);
        !           551:                        phase = STATUS_PHASE;
        !           552:                        break;
        !           553: 
        !           554:                case DATA_OUT_PHASE:
        !           555:                        if (len <= 0)
        !           556:                                goto abort;
        !           557:                        wait = scsi_data_wait;
        !           558:                        if (ixfer_start(hd, len, phase, wait)) {
        !           559:                                if (ixfer_out(hd, len, buf))
        !           560:                                        goto abort;
        !           561:                        }
        !           562:                        phase = STATUS_PHASE;
        !           563:                        break;
        !           564: 
        !           565:                case STATUS_PHASE:
        !           566:                        wait = scsi_data_wait;
        !           567:                        if (ixfer_start(hd, sizeof(hs->sc_stat), phase, wait) ||
        !           568:                            !(hd->scsi_ssts & SSTS_DREG_EMPTY))
        !           569:                                ixfer_in(hd, sizeof(hs->sc_stat), hs->sc_stat);
        !           570:                        phase = MESG_IN_PHASE;
        !           571:                        break;
        !           572: 
        !           573:                case MESG_IN_PHASE:
        !           574:                        if (ixfer_start(hd, sizeof(hs->sc_msg), phase, wait) ||
        !           575:                            !(hd->scsi_ssts & SSTS_DREG_EMPTY)) {
        !           576:                                ixfer_in(hd, sizeof(hs->sc_msg), hs->sc_msg);
        !           577:                                hd->scsi_scmd = SCMD_RST_ACK;
        !           578:                        }
        !           579:                        phase = BUS_FREE_PHASE;
        !           580:                        break;
        !           581: 
        !           582:                case BUS_FREE_PHASE:
        !           583:                        goto out;
        !           584: 
        !           585:                default:
        !           586:                        printf("scsi%d: unexpected phase %d in icmd from %d\n",
        !           587:                                hs->sc_hc->hp_unit, phase, target);
        !           588:                        goto abort;
        !           589:                }
        !           590:                /* wait for last command to complete */
        !           591:                while ((ints = hd->scsi_ints) == 0) {
        !           592:                        if (--wait < 0) {
        !           593:                                HIST(cxin_wait, wait)
        !           594:                                goto abort;
        !           595:                        }
        !           596:                        DELAY(1);
        !           597:                }
        !           598:                HIST(cxin_wait, wait)
        !           599:                hd->scsi_ints = ints;
        !           600:                if (ints & INTS_SRV_REQ)
        !           601:                        phase = hd->scsi_psns & PHASE;
        !           602:                else if (ints & INTS_DISCON)
        !           603:                        goto out;
        !           604:                else if ((ints & INTS_CMD_DONE) == 0) {
        !           605:                        scsierror(hs, hd, ints);
        !           606:                        goto abort;
        !           607:                }
        !           608:        }
        !           609: abort:
        !           610:        scsiabort(hs, hd, "icmd");
        !           611: out:
        !           612:        return (hs->sc_stat[0]);
        !           613: }
        !           614: 
        !           615: /*
        !           616:  * Finish SCSI xfer command:  After the completion interrupt from
        !           617:  * a read/write operation, sequence through the final phases in
        !           618:  * programmed i/o.  This routine is a lot like scsiicmd except we
        !           619:  * skip (and don't allow) the select, cmd out and data in/out phases.
        !           620:  */
        !           621: static void
        !           622: finishxfer(hs, hd, target)
        !           623:        struct scsi_softc *hs;
        !           624:        volatile register struct scsidevice *hd;
        !           625:        int target;
        !           626: {
        !           627:        u_char phase, ints;
        !           628: 
        !           629:        /*
        !           630:         * We specified padding xfer so we ended with either a phase
        !           631:         * change interrupt (normal case) or an error interrupt (handled
        !           632:         * elsewhere).  Reset the board dma logic then try to get the
        !           633:         * completion status & command done msg.  The reset confuses
        !           634:         * the SPC REQ/ACK logic so we have to do any status/msg input
        !           635:         * operations via 'manual xfer'.
        !           636:         */
        !           637:        if (hd->scsi_ssts & SSTS_BUSY) {
        !           638:                int wait = scsi_cmd_wait;
        !           639: 
        !           640:                /* wait for dma operation to finish */
        !           641:                while (hd->scsi_ssts & SSTS_BUSY) {
        !           642:                        if (--wait < 0) {
        !           643: #ifdef DEBUG
        !           644:                                if (scsi_debug)
        !           645:                                        printf("finishxfer fail: ssts %x\n",
        !           646:                                               hd->scsi_ssts);
        !           647: #endif
        !           648:                                HIST(fxfr_wait, wait)
        !           649:                                goto abort;
        !           650:                        }
        !           651:                }
        !           652:                HIST(fxfr_wait, wait)
        !           653:        }
        !           654:        hd->scsi_scmd |= SCMD_PROG_XFR;
        !           655:        hd->scsi_sctl |= SCTL_CTRLRST;
        !           656:        DELAY(1);
        !           657:        hd->scsi_sctl &=~ SCTL_CTRLRST;
        !           658:        hd->scsi_hconf = 0;
        !           659:        hs->sc_stat[0] = 0xff;
        !           660:        hs->sc_msg[0] = 0xff;
        !           661:        hd->scsi_csr = 0;
        !           662:        hd->scsi_ints = ints = hd->scsi_ints;
        !           663:        while (1) {
        !           664:                phase = hd->scsi_psns & PHASE;
        !           665:                switch (phase) {
        !           666: 
        !           667:                case STATUS_PHASE:
        !           668:                        if (mxfer_in(hd, sizeof(hs->sc_stat), hs->sc_stat,
        !           669:                                     phase) <= 0)
        !           670:                                goto abort;
        !           671:                        break;
        !           672: 
        !           673:                case MESG_IN_PHASE:
        !           674:                        if (mxfer_in(hd, sizeof(hs->sc_msg), hs->sc_msg,
        !           675:                                     phase) < 0)
        !           676:                                goto abort;
        !           677:                        break;
        !           678: 
        !           679:                case BUS_FREE_PHASE:
        !           680:                        return;
        !           681: 
        !           682:                default:
        !           683:                        printf("scsi%d: unexpected phase %d in finishxfer from %d\n",
        !           684:                                hs->sc_hc->hp_unit, phase, target);
        !           685:                        goto abort;
        !           686:                }
        !           687:                if (ints = hd->scsi_ints) {
        !           688:                        hd->scsi_ints = ints;
        !           689:                        if (ints & INTS_DISCON)
        !           690:                                return;
        !           691:                        else if (ints & ~(INTS_SRV_REQ|INTS_CMD_DONE)) {
        !           692:                                scsierror(hs, hd, ints);
        !           693:                                break;
        !           694:                        }
        !           695:                }
        !           696:                if ((hd->scsi_ssts & SSTS_INITIATOR) == 0)
        !           697:                        return;
        !           698:        }
        !           699: abort:
        !           700:        scsiabort(hs, hd, "finishxfer");
        !           701:        hs->sc_stat[0] = 0xfe;
        !           702: }
        !           703: 
        !           704: int
        !           705: scsi_test_unit_rdy(ctlr, slave, unit)
        !           706:        int ctlr, slave, unit;
        !           707: {
        !           708:        register struct scsi_softc *hs = &scsi_softc[ctlr];
        !           709:        static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY };
        !           710: 
        !           711:        cdb.lun = unit;
        !           712:        return (scsiicmd(hs, slave, &cdb, sizeof(cdb), (u_char *)0, 0,
        !           713:                         STATUS_PHASE));
        !           714: }
        !           715: 
        !           716: int
        !           717: scsi_request_sense(ctlr, slave, unit, buf, len)
        !           718:        int ctlr, slave, unit;
        !           719:        u_char *buf;
        !           720:        unsigned len;
        !           721: {
        !           722:        register struct scsi_softc *hs = &scsi_softc[ctlr];
        !           723:        static struct scsi_cdb6 cdb = { CMD_REQUEST_SENSE };
        !           724: 
        !           725:        cdb.lun = unit;
        !           726:        cdb.len = len;
        !           727:        return (scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_IN_PHASE));
        !           728: }
        !           729: 
        !           730: int
        !           731: scsi_immed_command(ctlr, slave, unit, cdb, buf, len, rd)
        !           732:        int ctlr, slave, unit;
        !           733:        struct scsi_fmt_cdb *cdb;
        !           734:        u_char *buf;
        !           735:        unsigned len;
        !           736: {
        !           737:        register struct scsi_softc *hs = &scsi_softc[ctlr];
        !           738: 
        !           739:        cdb->cdb[1] |= unit << 5;
        !           740:        return (scsiicmd(hs, slave, cdb->cdb, cdb->len, buf, len,
        !           741:                         rd != 0? DATA_IN_PHASE : DATA_OUT_PHASE));
        !           742: }
        !           743: 
        !           744: /*
        !           745:  * The following routines are test-and-transfer i/o versions of read/write
        !           746:  * for things like reading disk labels and writing core dumps.  The
        !           747:  * routine scsigo should be used for normal data transfers, NOT these
        !           748:  * routines.
        !           749:  */
        !           750: int
        !           751: scsi_tt_read(ctlr, slave, unit, buf, len, blk, bshift)
        !           752:        int ctlr, slave, unit;
        !           753:        u_char *buf;
        !           754:        u_int len;
        !           755:        daddr_t blk;
        !           756:        int bshift;
        !           757: {
        !           758:        register struct scsi_softc *hs = &scsi_softc[ctlr];
        !           759:        struct scsi_cdb10 cdb;
        !           760:        int stat;
        !           761:        int old_wait = scsi_data_wait;
        !           762: 
        !           763:        scsi_data_wait = 300000;
        !           764:        bzero(&cdb, sizeof(cdb));
        !           765:        cdb.cmd = CMD_READ_EXT;
        !           766:        cdb.lun = unit;
        !           767:        blk >>= bshift;
        !           768:        cdb.lbah = blk >> 24;
        !           769:        cdb.lbahm = blk >> 16;
        !           770:        cdb.lbalm = blk >> 8;
        !           771:        cdb.lbal = blk;
        !           772:        cdb.lenh = len >> (8 + DEV_BSHIFT + bshift);
        !           773:        cdb.lenl = len >> (DEV_BSHIFT + bshift);
        !           774:        stat = scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_IN_PHASE);
        !           775:        scsi_data_wait = old_wait;
        !           776:        return (stat);
        !           777: }
        !           778: 
        !           779: int
        !           780: scsi_tt_write(ctlr, slave, unit, buf, len, blk, bshift)
        !           781:        int ctlr, slave, unit;
        !           782:        u_char *buf;
        !           783:        u_int len;
        !           784:        daddr_t blk;
        !           785:        int bshift;
        !           786: {
        !           787:        register struct scsi_softc *hs = &scsi_softc[ctlr];
        !           788:        struct scsi_cdb10 cdb;
        !           789:        int stat;
        !           790:        int old_wait = scsi_data_wait;
        !           791: 
        !           792:        scsi_data_wait = 300000;
        !           793: 
        !           794:        bzero(&cdb, sizeof(cdb));
        !           795:        cdb.cmd = CMD_WRITE_EXT;
        !           796:        cdb.lun = unit;
        !           797:        blk >>= bshift;
        !           798:        cdb.lbah = blk >> 24;
        !           799:        cdb.lbahm = blk >> 16;
        !           800:        cdb.lbalm = blk >> 8;
        !           801:        cdb.lbal = blk;
        !           802:        cdb.lenh = len >> (8 + DEV_BSHIFT + bshift);
        !           803:        cdb.lenl = len >> (DEV_BSHIFT + bshift);
        !           804:        stat = scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_OUT_PHASE);
        !           805:        scsi_data_wait = old_wait;
        !           806:        return (stat);
        !           807: }
        !           808: 
        !           809: 
        !           810: int
        !           811: scsireq(dq)
        !           812:        register struct devqueue *dq;
        !           813: {
        !           814:        register struct devqueue *hq;
        !           815: 
        !           816:        hq = &scsi_softc[dq->dq_ctlr].sc_sq;
        !           817:        insque(dq, hq->dq_back);
        !           818:        if (dq->dq_back == hq)
        !           819:                return(1);
        !           820:        return(0);
        !           821: }
        !           822: 
        !           823: int
        !           824: scsiustart(unit)
        !           825:        int unit;
        !           826: {
        !           827:        register struct scsi_softc *hs = &scsi_softc[unit];
        !           828: 
        !           829:        hs->sc_dq.dq_ctlr = DMA0 | DMA1;
        !           830:        if (dmareq(&hs->sc_dq))
        !           831:                return(1);
        !           832:        return(0);
        !           833: }
        !           834: 
        !           835: void
        !           836: scsistart(unit)
        !           837:        int unit;
        !           838: {
        !           839:        register struct devqueue *dq;
        !           840:        
        !           841:        dq = scsi_softc[unit].sc_sq.dq_forw;
        !           842:        (dq->dq_driver->d_go)(dq->dq_unit);
        !           843: }
        !           844: 
        !           845: int
        !           846: scsigo(ctlr, slave, unit, bp, cdb, pad)
        !           847:        int ctlr, slave, unit;
        !           848:        struct buf *bp;
        !           849:        struct scsi_fmt_cdb *cdb;
        !           850:        int pad;
        !           851: {
        !           852:        register struct scsi_softc *hs = &scsi_softc[ctlr];
        !           853:        volatile register struct scsidevice *hd =
        !           854:                                (struct scsidevice *)hs->sc_hc->hp_addr;
        !           855:        int i, dmaflags;
        !           856:        u_char phase, ints, cmd;
        !           857: 
        !           858:        cdb->cdb[1] |= unit << 5;
        !           859: 
        !           860:        /* select the SCSI bus (it's an error if bus isn't free) */
        !           861:        if (issue_select(hd, slave, hs->sc_scsi_addr) || wait_for_select(hd)) {
        !           862:                dmafree(&hs->sc_dq);
        !           863:                return (1);
        !           864:        }
        !           865:        /*
        !           866:         * Wait for a phase change (or error) then let the device
        !           867:         * sequence us through command phase (we may have to take
        !           868:         * a msg in/out before doing the command).  If the disk has
        !           869:         * to do a seek, it may be a long time until we get a change
        !           870:         * to data phase so, in the absense of an explicit phase
        !           871:         * change, we assume data phase will be coming up and tell
        !           872:         * the SPC to start a transfer whenever it does.  We'll get
        !           873:         * a service required interrupt later if this assumption is
        !           874:         * wrong.  Otherwise we'll get a service required int when
        !           875:         * the transfer changes to status phase.
        !           876:         */
        !           877:        phase = CMD_PHASE;
        !           878:        while (1) {
        !           879:                register int wait = scsi_cmd_wait;
        !           880: 
        !           881:                switch (phase) {
        !           882: 
        !           883:                case CMD_PHASE:
        !           884:                        if (ixfer_start(hd, cdb->len, phase, wait))
        !           885:                                if (ixfer_out(hd, cdb->len, cdb->cdb))
        !           886:                                        goto abort;
        !           887:                        break;
        !           888: 
        !           889:                case MESG_IN_PHASE:
        !           890:                        if (ixfer_start(hd, sizeof(hs->sc_msg), phase, wait)||
        !           891:                            !(hd->scsi_ssts & SSTS_DREG_EMPTY)) {
        !           892:                                ixfer_in(hd, sizeof(hs->sc_msg), hs->sc_msg);
        !           893:                                hd->scsi_scmd = SCMD_RST_ACK;
        !           894:                        }
        !           895:                        phase = BUS_FREE_PHASE;
        !           896:                        break;
        !           897: 
        !           898:                case DATA_IN_PHASE:
        !           899:                case DATA_OUT_PHASE:
        !           900:                        goto out;
        !           901: 
        !           902:                default:
        !           903:                        printf("scsi%d: unexpected phase %d in go from %d\n",
        !           904:                                hs->sc_hc->hp_unit, phase, slave);
        !           905:                        goto abort;
        !           906:                }
        !           907:                while ((ints = hd->scsi_ints) == 0) {
        !           908:                        if (--wait < 0) {
        !           909:                                HIST(sgo_wait, wait)
        !           910:                                goto abort;
        !           911:                        }
        !           912:                        DELAY(1);
        !           913:                }
        !           914:                HIST(sgo_wait, wait)
        !           915:                hd->scsi_ints = ints;
        !           916:                if (ints & INTS_SRV_REQ)
        !           917:                        phase = hd->scsi_psns & PHASE;
        !           918:                else if (ints & INTS_CMD_DONE)
        !           919:                        goto out;
        !           920:                else {
        !           921:                        scsierror(hs, hd, ints);
        !           922:                        goto abort;
        !           923:                }
        !           924:        }
        !           925: out:
        !           926:        /*
        !           927:         * Reset the card dma logic, setup the dma channel then
        !           928:         * get the dio part of the card set for a dma xfer.
        !           929:         */
        !           930:        hd->scsi_hconf = 0;
        !           931:        cmd = CSR_IE | (CSR_DE0 << hs->sc_dq.dq_ctlr);
        !           932:        dmaflags = DMAGO_NOINT;
        !           933:        if (bp->b_flags & B_READ)
        !           934:                dmaflags |= DMAGO_READ;
        !           935:        if ((hs->sc_flags & SCSI_DMA32) &&
        !           936:            ((int)bp->b_un.b_addr & 3) == 0 && (bp->b_bcount & 3) == 0) {
        !           937:                cmd |= CSR_DMA32;
        !           938:                dmaflags |= DMAGO_LWORD;
        !           939:        } else
        !           940:                dmaflags |= DMAGO_WORD;
        !           941:        dmago(hs->sc_dq.dq_ctlr, bp->b_un.b_addr, bp->b_bcount, dmaflags);
        !           942: 
        !           943:        if (bp->b_flags & B_READ) {
        !           944:                cmd |= CSR_DMAIN;
        !           945:                phase = DATA_IN_PHASE;
        !           946:        } else
        !           947:                phase = DATA_OUT_PHASE;
        !           948:        hd->scsi_csr = cmd;
        !           949:        /*
        !           950:         * Setup the SPC for the transfer.  We don't want to take
        !           951:         * first a command complete then a service required interrupt
        !           952:         * at the end of the transfer so we try to disable the cmd
        !           953:         * complete by setting the transfer counter to more bytes
        !           954:         * than we expect.  (XXX - This strategy may have to be
        !           955:         * modified to deal with devices that return variable length
        !           956:         * blocks, e.g., some tape drives.)
        !           957:         */
        !           958:        cmd = SCMD_XFR;
        !           959:        i = (unsigned)bp->b_bcount;
        !           960:        if (pad) {
        !           961:                cmd |= SCMD_PAD;
        !           962:                /*
        !           963:                 * XXX - If we don't do this, the last 2 or 4 bytes
        !           964:                 * (depending on word/lword DMA) of a read get trashed.
        !           965:                 * It looks like it is necessary for the DMA to complete
        !           966:                 * before the SPC goes into "pad mode"???  Note: if we
        !           967:                 * also do this on a write, the request never completes.
        !           968:                 */
        !           969:                if (bp->b_flags & B_READ)
        !           970:                        i += 2;
        !           971: #ifdef DEBUG
        !           972:                hs->sc_flags |= SCSI_PAD;
        !           973:                if (i & 1)
        !           974:                        printf("scsi%d: odd byte count: %d bytes @ %d\n",
        !           975:                                ctlr, i, bp->b_cylin);
        !           976: #endif
        !           977:        } else
        !           978:                i += 4;
        !           979:        hd->scsi_tch = i >> 16;
        !           980:        hd->scsi_tcm = i >> 8;
        !           981:        hd->scsi_tcl = i;
        !           982:        hd->scsi_pctl = phase;
        !           983:        hd->scsi_tmod = 0;
        !           984:        hd->scsi_scmd = cmd;
        !           985:        hs->sc_flags |= SCSI_IO;
        !           986:        return (0);
        !           987: abort:
        !           988:        scsiabort(hs, hd, "go");
        !           989:        dmafree(&hs->sc_dq);
        !           990:        return (1);
        !           991: }
        !           992: 
        !           993: void
        !           994: scsidone(unit)
        !           995:        register int unit;
        !           996: {
        !           997:        volatile register struct scsidevice *hd =
        !           998:                        (struct scsidevice *)scsi_softc[unit].sc_hc->hp_addr;
        !           999: 
        !          1000:        /* dma operation is done -- turn off card dma */
        !          1001:        hd->scsi_csr &=~ (CSR_DE1|CSR_DE0);
        !          1002: }
        !          1003: 
        !          1004: int
        !          1005: scsiintr(unit)
        !          1006:        register int unit;
        !          1007: {
        !          1008:        register struct scsi_softc *hs = &scsi_softc[unit];
        !          1009:        volatile register struct scsidevice *hd =
        !          1010:                                (struct scsidevice *)hs->sc_hc->hp_addr;
        !          1011:        register u_char ints;
        !          1012:        register struct devqueue *dq;
        !          1013: 
        !          1014:        if ((hd->scsi_csr & (CSR_IE|CSR_IR)) != (CSR_IE|CSR_IR))
        !          1015:                return (0);
        !          1016: 
        !          1017:        ints = hd->scsi_ints;
        !          1018:        if ((ints & INTS_SRV_REQ) && (hs->sc_flags & SCSI_IO)) {
        !          1019:                /*
        !          1020:                 * this should be the normal i/o completion case.
        !          1021:                 * get the status & cmd complete msg then let the
        !          1022:                 * device driver look at what happened.
        !          1023:                 */
        !          1024: #ifdef DEBUG
        !          1025:                int len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) |
        !          1026:                          hd->scsi_tcl;
        !          1027:                if (!(hs->sc_flags & SCSI_PAD))
        !          1028:                        len -= 4;
        !          1029:                if (len)
        !          1030:                        printf("scsi%d: transfer length error %d\n", unit, len);
        !          1031:                hs->sc_flags &=~ SCSI_PAD;
        !          1032: #endif
        !          1033:                dq = hs->sc_sq.dq_forw;
        !          1034:                finishxfer(hs, hd, dq->dq_unit);
        !          1035:                hs->sc_flags &=~ SCSI_IO;
        !          1036:                dmafree(&hs->sc_dq);
        !          1037:                (dq->dq_driver->d_intr)(dq->dq_unit, hs->sc_stat[0]);
        !          1038:        } else {
        !          1039:                /* Something unexpected happened -- deal with it. */
        !          1040:                hd->scsi_ints = ints;
        !          1041:                hd->scsi_csr = 0;
        !          1042:                scsierror(hs, hd, ints);
        !          1043:                scsiabort(hs, hd, "intr");
        !          1044:                if (hs->sc_flags & SCSI_IO) {
        !          1045:                        hs->sc_flags &=~ SCSI_IO;
        !          1046:                        dmafree(&hs->sc_dq);
        !          1047:                        dq = hs->sc_sq.dq_forw;
        !          1048:                        (dq->dq_driver->d_intr)(dq->dq_unit, -1);
        !          1049:                }
        !          1050:        }
        !          1051:        return(1);
        !          1052: }
        !          1053: 
        !          1054: void
        !          1055: scsifree(dq)
        !          1056:        register struct devqueue *dq;
        !          1057: {
        !          1058:        register struct devqueue *hq;
        !          1059: 
        !          1060:        hq = &scsi_softc[dq->dq_ctlr].sc_sq;
        !          1061:        remque(dq);
        !          1062:        if ((dq = hq->dq_forw) != hq)
        !          1063:                (dq->dq_driver->d_start)(dq->dq_unit);
        !          1064: }
        !          1065: #endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.