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

Annotation of sys/dev/isa/aha.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: aha.c,v 1.57 2007/08/15 02:04:30 krw Exp $    */
        !             2: /*     $NetBSD: aha.c,v 1.11 1996/05/12 23:51:23 mycroft Exp $ */
        !             3:
        !             4: #undef AHADIAG
        !             5:
        !             6: /*
        !             7:  * Copyright (c) 1994, 1996 Charles M. Hannum.  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. All advertising materials mentioning features or use of this software
        !            18:  *    must display the following acknowledgement:
        !            19:  *     This product includes software developed by Charles M. Hannum.
        !            20:  * 4. The name of the author may not be used to endorse or promote products
        !            21:  *    derived from this software without specific prior written permission.
        !            22:  *
        !            23:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            24:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            25:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            26:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            27:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            28:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            29:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            30:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            31:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            32:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            33:  */
        !            34:
        !            35: /*
        !            36:  * Originally written by Julian Elischer (julian@tfs.com)
        !            37:  * for TRW Financial Systems for use under the MACH(2.5) operating system.
        !            38:  *
        !            39:  * TRW Financial Systems, in accordance with their agreement with Carnegie
        !            40:  * Mellon University, makes this software available to CMU to distribute
        !            41:  * or use in any manner that they see fit as long as this message is kept with
        !            42:  * the software. For this reason TFS also grants any other persons or
        !            43:  * organisations permission to use or modify this software.
        !            44:  *
        !            45:  * TFS supplies this software to be publicly redistributed
        !            46:  * on the understanding that TFS is not responsible for the correct
        !            47:  * functioning of this software in any circumstances.
        !            48:  */
        !            49:
        !            50: #include <sys/types.h>
        !            51: #include <sys/param.h>
        !            52: #include <sys/systm.h>
        !            53: #include <sys/kernel.h>
        !            54: #include <sys/errno.h>
        !            55: #include <sys/ioctl.h>
        !            56: #include <sys/device.h>
        !            57: #include <sys/malloc.h>
        !            58: #include <sys/buf.h>
        !            59: #include <sys/proc.h>
        !            60: #include <sys/user.h>
        !            61: #include <sys/timeout.h>
        !            62:
        !            63: #include <uvm/uvm.h>
        !            64: #include <uvm/uvm_extern.h>
        !            65:
        !            66: #include <machine/intr.h>
        !            67: #include <machine/bus.h>
        !            68:
        !            69: #include <scsi/scsi_all.h>
        !            70: #include <scsi/scsiconf.h>
        !            71:
        !            72: #include <dev/isa/isavar.h>
        !            73: #include <dev/isa/isadmavar.h>
        !            74: #include <dev/isa/ahareg.h>
        !            75:
        !            76: #ifndef DDB
        !            77: #define Debugger() panic("should call debugger here (aha1542.c)")
        !            78: #endif /* ! DDB */
        !            79:
        !            80: /* XXX fixme:
        !            81:  * on i386 at least, xfers to/from user memory
        !            82:  * cannot be serviced at interrupt time.
        !            83:  */
        !            84: #ifdef i386
        !            85: #define VOLATILE_XS(xs) \
        !            86:        ((xs)->datalen > 0 && (xs)->bp == NULL && \
        !            87:        ((xs)->flags & SCSI_POLL) == 0)
        !            88: #else
        !            89: #define VOLATILE_XS(xs)        0
        !            90: #endif
        !            91:
        !            92: /*
        !            93:  * Mail box defs  etc.
        !            94:  * these could be bigger but we need the aha_softc to fit on a single page..
        !            95:  */
        !            96: #define AHA_MBX_SIZE   16      /* mail box size */
        !            97:
        !            98: #define        AHA_CCB_MAX     16      /* store up to 32 CCBs at one time */
        !            99: #define        CCB_HASH_SIZE   16      /* hash table size for phystokv */
        !           100: #define        CCB_HASH_SHIFT  9
        !           101: #define        CCB_HASH(x)     ((((long)(x))>>CCB_HASH_SHIFT) & (CCB_HASH_SIZE - 1))
        !           102:
        !           103: #define aha_nextmbx(wmb, mbx, mbio) \
        !           104:        if ((wmb) == &(mbx)->mbio[AHA_MBX_SIZE - 1])    \
        !           105:                (wmb) = &(mbx)->mbio[0];                \
        !           106:        else                                            \
        !           107:                (wmb)++;
        !           108:
        !           109: struct aha_mbx {
        !           110:        struct aha_mbx_out mbo[AHA_MBX_SIZE];
        !           111:        struct aha_mbx_in mbi[AHA_MBX_SIZE];
        !           112:        struct aha_mbx_out *cmbo;       /* Collection Mail Box out */
        !           113:        struct aha_mbx_out *tmbo;       /* Target Mail Box out */
        !           114:        struct aha_mbx_in *tmbi;        /* Target Mail Box in */
        !           115: };
        !           116:
        !           117: struct aha_softc {
        !           118:        struct device sc_dev;
        !           119:        struct isadev sc_id;
        !           120:        void *sc_ih;
        !           121:        bus_dma_tag_t sc_dmat;
        !           122:
        !           123:        int sc_iobase;
        !           124:        int sc_irq, sc_drq;
        !           125:
        !           126:        char sc_model[18],
        !           127:             sc_firmware[4];
        !           128:
        !           129:        struct aha_mbx *sc_mbx;         /* all the mailboxes */
        !           130: #define        wmbx    (sc->sc_mbx)
        !           131:        struct aha_ccb *sc_ccbhash[CCB_HASH_SIZE];
        !           132:        TAILQ_HEAD(, aha_ccb) sc_free_ccb, sc_waiting_ccb;
        !           133:        int sc_numccbs, sc_mbofull;
        !           134:        int sc_scsi_dev;                /* our scsi id */
        !           135:        struct scsi_link sc_link;
        !           136: };
        !           137:
        !           138: #ifdef AHADEBUG
        !           139: int    aha_debug = 1;
        !           140: #endif /* AHADEBUG */
        !           141:
        !           142: int aha_cmd(int, struct aha_softc *, int, u_char *, int, u_char *);
        !           143: void aha_finish_ccbs(struct aha_softc *);
        !           144: int ahaintr(void *);
        !           145: void aha_reset_ccb(struct aha_softc *, struct aha_ccb *);
        !           146: void aha_free_ccb(struct aha_softc *, struct aha_ccb *);
        !           147: int aha_init_ccb(struct aha_softc *, struct aha_ccb *, int);
        !           148: struct aha_ccb *aha_get_ccb(struct aha_softc *, int);
        !           149: struct aha_ccb *aha_ccb_phys_kv(struct aha_softc *, u_long);
        !           150: void aha_queue_ccb(struct aha_softc *, struct aha_ccb *);
        !           151: void aha_collect_mbo(struct aha_softc *);
        !           152: void aha_start_ccbs(struct aha_softc *);
        !           153: void aha_done(struct aha_softc *, struct aha_ccb *);
        !           154: int aha_find(struct isa_attach_args *, struct aha_softc *, int);
        !           155: void aha_init(struct aha_softc *);
        !           156: void aha_inquire_setup_information(struct aha_softc *);
        !           157: void ahaminphys(struct buf *);
        !           158: int aha_scsi_cmd(struct scsi_xfer *);
        !           159: int aha_poll(struct aha_softc *, struct scsi_xfer *, int);
        !           160: void aha_timeout(void *arg);
        !           161:
        !           162: struct scsi_adapter aha_switch = {
        !           163:        aha_scsi_cmd,
        !           164:        ahaminphys,
        !           165:        0,
        !           166:        0,
        !           167: };
        !           168:
        !           169: /* the below structure is so we have a default dev struct for out link struct */
        !           170: struct scsi_device aha_dev = {
        !           171:        NULL,                   /* Use default error handler */
        !           172:        NULL,                   /* have a queue, served by this */
        !           173:        NULL,                   /* have no async handler */
        !           174:        NULL,                   /* Use default 'done' routine */
        !           175: };
        !           176:
        !           177: int    aha_isapnp_probe(struct device *, void *, void *);
        !           178: int    ahaprobe(struct device *, void *, void *);
        !           179: void   ahaattach(struct device *, struct device *, void *);
        !           180:
        !           181: struct cfattach aha_isapnp_ca = {
        !           182:        sizeof(struct aha_softc), aha_isapnp_probe, ahaattach
        !           183: };
        !           184:
        !           185: struct cfattach aha_isa_ca = {
        !           186:        sizeof(struct aha_softc), ahaprobe, ahaattach
        !           187: };
        !           188:
        !           189: struct cfdriver aha_cd = {
        !           190:        NULL, "aha", DV_DULL
        !           191: };
        !           192:
        !           193: #define AHA_RESET_TIMEOUT      2000    /* time to wait for reset (mSec) */
        !           194: #define        AHA_ABORT_TIMEOUT       2000    /* time to wait for abort (mSec) */
        !           195:
        !           196: #include "bha.h"
        !           197:
        !           198: /*
        !           199:  * aha_cmd(iobase, sc, icnt, ibuf, ocnt, obuf)
        !           200:  *
        !           201:  * Activate Adapter command
        !           202:  *    icnt:   number of args (outbound bytes including opcode)
        !           203:  *    ibuf:   argument buffer
        !           204:  *    ocnt:   number of expected returned bytes
        !           205:  *    obuf:   result buffer
        !           206:  *    wait:   number of seconds to wait for response
        !           207:  *
        !           208:  * Performs an adapter command through the ports.  Not to be confused with a
        !           209:  * scsi command, which is read in via the dma; one of the adapter commands
        !           210:  * tells it to read in a scsi command.
        !           211:  */
        !           212: int
        !           213: aha_cmd(iobase, sc, icnt, ibuf, ocnt, obuf)
        !           214:        int iobase;
        !           215:        struct aha_softc *sc;
        !           216:        int icnt, ocnt;
        !           217:        u_char *ibuf, *obuf;
        !           218: {
        !           219:        const char *name;
        !           220:        register int i;
        !           221:        int wait;
        !           222:        u_char sts;
        !           223:        u_char opcode = ibuf[0];
        !           224:
        !           225:        if (sc != NULL)
        !           226:                name = sc->sc_dev.dv_xname;
        !           227:        else
        !           228:                name = "(aha probe)";
        !           229:
        !           230:        /*
        !           231:         * Calculate a reasonable timeout for the command.
        !           232:         */
        !           233:        switch (opcode) {
        !           234:        case AHA_INQUIRE_DEVICES:
        !           235:                wait = 15 * 20000;
        !           236:                break;
        !           237:        default:
        !           238:                wait = 1 * 20000;
        !           239:                break;
        !           240:        }
        !           241:
        !           242:        /*
        !           243:         * Wait for the adapter to go idle, unless it's one of
        !           244:         * the commands which don't need this
        !           245:         */
        !           246:        if (opcode != AHA_MBO_INTR_EN) {
        !           247:                for (i = 20000; i; i--) {       /* 1 sec? */
        !           248:                        sts = inb(iobase + AHA_STAT_PORT);
        !           249:                        if (sts & AHA_STAT_IDLE)
        !           250:                                break;
        !           251:                        delay(50);
        !           252:                }
        !           253:                if (!i) {
        !           254:                        printf("%s: aha_cmd, host not idle(0x%x)\n",
        !           255:                            name, sts);
        !           256:                        return (ENXIO);
        !           257:                }
        !           258:        }
        !           259:        /*
        !           260:         * Now that it is idle, if we expect output, preflush the
        !           261:         * queue feeding to us.
        !           262:         */
        !           263:        if (ocnt) {
        !           264:                while ((inb(iobase + AHA_STAT_PORT)) & AHA_STAT_DF)
        !           265:                        inb(iobase + AHA_DATA_PORT);
        !           266:        }
        !           267:        /*
        !           268:         * Output the command and the number of arguments given
        !           269:         * for each byte, first check the port is empty.
        !           270:         */
        !           271:        while (icnt--) {
        !           272:                for (i = wait; i; i--) {
        !           273:                        sts = inb(iobase + AHA_STAT_PORT);
        !           274:                        if (!(sts & AHA_STAT_CDF))
        !           275:                                break;
        !           276:                        delay(50);
        !           277:                }
        !           278:                if (!i) {
        !           279:                        if (opcode != AHA_INQUIRE_REVISION)
        !           280:                                printf("%s: aha_cmd, cmd/data port full\n",
        !           281:                                    name);
        !           282:                        outb(iobase + AHA_CTRL_PORT, AHA_CTRL_SRST);
        !           283:                        return (ENXIO);
        !           284:                }
        !           285:                outb(iobase + AHA_CMD_PORT, *ibuf++);
        !           286:        }
        !           287:        /*
        !           288:         * If we expect input, loop that many times, each time,
        !           289:         * looking for the data register to have valid data
        !           290:         */
        !           291:        while (ocnt--) {
        !           292:                for (i = wait; i; i--) {
        !           293:                        sts = inb(iobase + AHA_STAT_PORT);
        !           294:                        if (sts & AHA_STAT_DF)
        !           295:                                break;
        !           296:                        delay(50);
        !           297:                }
        !           298:                if (!i) {
        !           299:                        if (opcode != AHA_INQUIRE_REVISION)
        !           300:                                printf("%s: aha_cmd, cmd/data port empty %d\n",
        !           301:                                    name, ocnt);
        !           302:                        outb(iobase + AHA_CTRL_PORT, AHA_CTRL_SRST);
        !           303:                        return (ENXIO);
        !           304:                }
        !           305:                *obuf++ = inb(iobase + AHA_DATA_PORT);
        !           306:        }
        !           307:        /*
        !           308:         * Wait for the board to report a finished instruction.
        !           309:         * We may get an extra interrupt for the HACC signal, but this is
        !           310:         * unimportant.
        !           311:         */
        !           312:        if (opcode != AHA_MBO_INTR_EN) {
        !           313:                for (i = 20000; i; i--) {       /* 1 sec? */
        !           314:                        sts = inb(iobase + AHA_INTR_PORT);
        !           315:                        /* XXX Need to save this in the interrupt handler? */
        !           316:                        if (sts & AHA_INTR_HACC)
        !           317:                                break;
        !           318:                        delay(50);
        !           319:                }
        !           320:                if (!i) {
        !           321:                        printf("%s: aha_cmd, host not finished(0x%x)\n",
        !           322:                            name, sts);
        !           323:                        return (ENXIO);
        !           324:                }
        !           325:        }
        !           326:        outb(iobase + AHA_CTRL_PORT, AHA_CTRL_IRST);
        !           327:        return (0);
        !           328: }
        !           329:
        !           330: int
        !           331: aha_isapnp_probe(parent, match, aux)
        !           332:        struct device *parent;
        !           333:        void *match, *aux;
        !           334: {
        !           335:        return (1);
        !           336: }
        !           337:
        !           338:
        !           339: /*
        !           340:  * Check if the device can be found at the port given
        !           341:  * and if so, set it up ready for further work
        !           342:  * as an argument, takes the isa_device structure from
        !           343:  * autoconf.c
        !           344:  */
        !           345: int
        !           346: ahaprobe(parent, match, aux)
        !           347:        struct device *parent;
        !           348:        void *match, *aux;
        !           349: {
        !           350:        register struct isa_attach_args *ia = aux;
        !           351: #if NBHA > 0
        !           352:        extern int btports[], nbtports;
        !           353:        int i;
        !           354:
        !           355:        for (i = 0; i < nbtports; i++)
        !           356:                if (btports[i] == ia->ia_iobase)
        !           357:                        return (0);
        !           358: #endif
        !           359:
        !           360:        /* See if there is a unit at this location. */
        !           361:        if (aha_find(ia, NULL, 0) != 0)
        !           362:                return (0);
        !           363:
        !           364:        ia->ia_msize = 0;
        !           365:        ia->ia_iosize = 4;
        !           366:        /* IRQ and DRQ set by aha_find(). */
        !           367:        return (1);
        !           368: }
        !           369:
        !           370: /*
        !           371:  * Attach all the sub-devices we can find
        !           372:  */
        !           373: void
        !           374: ahaattach(parent, self, aux)
        !           375:        struct device *parent, *self;
        !           376:        void *aux;
        !           377: {
        !           378:        struct isa_attach_args *ia = aux;
        !           379:        struct aha_softc *sc = (void *)self;
        !           380:        struct scsibus_attach_args saa;
        !           381:        int isapnp = !strcmp(parent->dv_cfdata->cf_driver->cd_name, "isapnp");
        !           382:
        !           383:        if (isapnp) {
        !           384:                ia->ia_iobase = ia->ipa_io[0].base;
        !           385:                isadma_cascade(ia->ia_drq);
        !           386:        }
        !           387:
        !           388:        if (aha_find(ia, sc, isapnp) != 0)
        !           389:                panic("ahaattach: aha_find of %s failed", self->dv_xname);
        !           390:        sc->sc_iobase = ia->ia_iobase;
        !           391:        sc->sc_dmat = ia->ia_dmat;
        !           392:
        !           393:        if (sc->sc_drq != DRQUNK && isapnp == 0)
        !           394:                isadma_cascade(sc->sc_drq);
        !           395:
        !           396:        aha_inquire_setup_information(sc);
        !           397:        aha_init(sc);
        !           398:        TAILQ_INIT(&sc->sc_free_ccb);
        !           399:        TAILQ_INIT(&sc->sc_waiting_ccb);
        !           400:
        !           401:        /*
        !           402:         * fill in the prototype scsi_link.
        !           403:         */
        !           404:        sc->sc_link.adapter_softc = sc;
        !           405:        sc->sc_link.adapter_target = sc->sc_scsi_dev;
        !           406:        sc->sc_link.adapter = &aha_switch;
        !           407:        sc->sc_link.device = &aha_dev;
        !           408:        sc->sc_link.openings = 2;
        !           409:
        !           410:        bzero(&saa, sizeof(saa));
        !           411:        saa.saa_sc_link = &sc->sc_link;
        !           412:
        !           413:        sc->sc_ih = isa_intr_establish(ia->ia_ic, sc->sc_irq, IST_EDGE,
        !           414:            IPL_BIO, ahaintr, sc, sc->sc_dev.dv_xname);
        !           415:
        !           416:        /*
        !           417:         * ask the adapter what subunits are present
        !           418:         */
        !           419:        config_found(self, &saa, scsiprint);
        !           420: }
        !           421:
        !           422: void
        !           423: aha_finish_ccbs(sc)
        !           424:        struct aha_softc *sc;
        !           425: {
        !           426:        struct aha_mbx_in *wmbi;
        !           427:        struct aha_ccb *ccb;
        !           428:        int i;
        !           429:
        !           430:        wmbi = wmbx->tmbi;
        !           431:
        !           432:        if (wmbi->stat == AHA_MBI_FREE) {
        !           433:                for (i = 0; i < AHA_MBX_SIZE; i++) {
        !           434:                        if (wmbi->stat != AHA_MBI_FREE) {
        !           435:                                printf("%s: mbi not in round-robin order\n",
        !           436:                                    sc->sc_dev.dv_xname);
        !           437:                                goto AGAIN;
        !           438:                        }
        !           439:                        aha_nextmbx(wmbi, wmbx, mbi);
        !           440:                }
        !           441: #ifdef AHADIAGnot
        !           442:                printf("%s: mbi interrupt with no full mailboxes\n",
        !           443:                    sc->sc_dev.dv_xname);
        !           444: #endif
        !           445:                return;
        !           446:        }
        !           447:
        !           448: AGAIN:
        !           449:        do {
        !           450:                ccb = aha_ccb_phys_kv(sc, phystol(wmbi->ccb_addr));
        !           451:                if (!ccb) {
        !           452:                        printf("%s: bad mbi ccb pointer; skipping\n",
        !           453:                            sc->sc_dev.dv_xname);
        !           454:                        goto next;
        !           455:                }
        !           456:
        !           457: #ifdef AHADEBUG
        !           458:                if (aha_debug) {
        !           459:                        u_char *cp = (u_char *)&ccb->scsi_cmd;
        !           460:                        printf("op=%x %x %x %x %x %x\n",
        !           461:                            cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
        !           462:                        printf("stat %x for mbi addr = 0x%08x, ",
        !           463:                            wmbi->stat, wmbi);
        !           464:                        printf("ccb addr = 0x%x\n", ccb);
        !           465:                }
        !           466: #endif /* AHADEBUG */
        !           467:
        !           468:                switch (wmbi->stat) {
        !           469:                case AHA_MBI_OK:
        !           470:                case AHA_MBI_ERROR:
        !           471:                        if ((ccb->flags & CCB_ABORT) != 0) {
        !           472:                                /*
        !           473:                                 * If we already started an abort, wait for it
        !           474:                                 * to complete before clearing the CCB.  We
        !           475:                                 * could instead just clear CCB_SENDING, but
        !           476:                                 * what if the mailbox was already received?
        !           477:                                 * The worst that happens here is that we clear
        !           478:                                 * the CCB a bit later than we need to.  BFD.
        !           479:                                 */
        !           480:                                goto next;
        !           481:                        }
        !           482:                        break;
        !           483:
        !           484:                case AHA_MBI_ABORT:
        !           485:                case AHA_MBI_UNKNOWN:
        !           486:                        /*
        !           487:                         * Even if the CCB wasn't found, we clear it anyway.
        !           488:                         * See preceding comment.
        !           489:                         */
        !           490:                        break;
        !           491:
        !           492:                default:
        !           493:                        printf("%s: bad mbi status %02x; skipping\n",
        !           494:                            sc->sc_dev.dv_xname, wmbi->stat);
        !           495:                        goto next;
        !           496:                }
        !           497:
        !           498:                if ((ccb->xs->flags & SCSI_POLL) == 0)
        !           499:                        timeout_del(&ccb->xs->stimeout);
        !           500:                bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmam, 0,
        !           501:                    ccb->ccb_dmam->dm_mapsize, BUS_DMASYNC_POSTREAD);
        !           502:                aha_done(sc, ccb);
        !           503:
        !           504:        next:
        !           505:                wmbi->stat = AHA_MBI_FREE;
        !           506:                aha_nextmbx(wmbi, wmbx, mbi);
        !           507:        } while (wmbi->stat != AHA_MBI_FREE);
        !           508:
        !           509:        wmbx->tmbi = wmbi;
        !           510: }
        !           511:
        !           512: /*
        !           513:  * Catch an interrupt from the adaptor
        !           514:  */
        !           515: int
        !           516: ahaintr(arg)
        !           517:        void *arg;
        !           518: {
        !           519:        struct aha_softc *sc = arg;
        !           520:        int iobase = sc->sc_iobase;
        !           521:        u_char sts;
        !           522:
        !           523: #ifdef AHADEBUG
        !           524:        if (aha_debug)
        !           525:                printf("%s: ahaintr ", sc->sc_dev.dv_xname);
        !           526: #endif /*AHADEBUG */
        !           527:
        !           528:        /*
        !           529:         * First acknowlege the interrupt, Then if it's not telling about
        !           530:         * a completed operation just return.
        !           531:         */
        !           532:        sts = inb(iobase + AHA_INTR_PORT);
        !           533:        if ((sts & AHA_INTR_ANYINTR) == 0)
        !           534:                return (0);
        !           535:        outb(iobase + AHA_CTRL_PORT, AHA_CTRL_IRST);
        !           536:
        !           537: #ifdef AHADIAG
        !           538:        /* Make sure we clear CCB_SENDING before finishing a CCB. */
        !           539:        aha_collect_mbo(sc);
        !           540: #endif
        !           541:
        !           542:        /* Mail box out empty? */
        !           543:        if (sts & AHA_INTR_MBOA) {
        !           544:                struct aha_toggle toggle;
        !           545:
        !           546:                toggle.cmd.opcode = AHA_MBO_INTR_EN;
        !           547:                toggle.cmd.enable = 0;
        !           548:                aha_cmd(iobase, sc, sizeof(toggle.cmd), (u_char *)&toggle.cmd,
        !           549:                    0, (u_char *)0);
        !           550:                aha_start_ccbs(sc);
        !           551:        }
        !           552:
        !           553:        /* Mail box in full? */
        !           554:        if (sts & AHA_INTR_MBIF)
        !           555:                aha_finish_ccbs(sc);
        !           556:
        !           557:        return (1);
        !           558: }
        !           559:
        !           560: void
        !           561: aha_reset_ccb(sc, ccb)
        !           562:        struct aha_softc *sc;
        !           563:        struct aha_ccb *ccb;
        !           564: {
        !           565:
        !           566:        ccb->flags = 0;
        !           567: }
        !           568:
        !           569: /*
        !           570:  * A ccb is put onto the free list.
        !           571:  */
        !           572: void
        !           573: aha_free_ccb(sc, ccb)
        !           574:        struct aha_softc *sc;
        !           575:        struct aha_ccb *ccb;
        !           576: {
        !           577:        int s, hashnum;
        !           578:        struct aha_ccb **hashccb;
        !           579:
        !           580:        s = splbio();
        !           581:
        !           582:        if (ccb->ccb_dmam->dm_segs[0].ds_addr != 0)
        !           583:                bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmam);
        !           584:
        !           585:        /* remove from hash table */
        !           586:
        !           587:        hashnum = CCB_HASH(ccb->ccb_dmam->dm_segs[0].ds_addr);
        !           588:        hashccb = &sc->sc_ccbhash[hashnum];
        !           589:
        !           590:        while (*hashccb) {
        !           591:                if ((*hashccb)->ccb_dmam->dm_segs[0].ds_addr ==
        !           592:                    ccb->ccb_dmam->dm_segs[0].ds_addr) {
        !           593:                        *hashccb = (*hashccb)->nexthash;
        !           594:                        break;
        !           595:                }
        !           596:                hashccb = &(*hashccb)->nexthash;
        !           597:        }
        !           598:
        !           599:        aha_reset_ccb(sc, ccb);
        !           600:        TAILQ_INSERT_HEAD(&sc->sc_free_ccb, ccb, chain);
        !           601:
        !           602:        /*
        !           603:         * If there were none, wake anybody waiting for one to come free,
        !           604:         * starting with queued entries.
        !           605:         */
        !           606:        if (TAILQ_NEXT(ccb, chain) == NULL)
        !           607:                wakeup(&sc->sc_free_ccb);
        !           608:
        !           609:        splx(s);
        !           610: }
        !           611:
        !           612: int
        !           613: aha_init_ccb(sc, ccb, flags)
        !           614:        struct aha_softc *sc;
        !           615:        struct aha_ccb *ccb;
        !           616:        int flags;
        !           617: {
        !           618:        int error, wait, state = 0;
        !           619:
        !           620:        bzero(ccb, sizeof(struct aha_ccb));
        !           621:        aha_reset_ccb(sc, ccb);
        !           622:
        !           623:        wait = (flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK;
        !           624:        /* Create a DMA map for the data area.  */
        !           625:        error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, (MAXPHYS / NBPG) + 1,
        !           626:            MAXPHYS, 0, wait | BUS_DMA_ALLOCNOW, &ccb->dmam);
        !           627:        if (error)
        !           628:                goto fail;
        !           629:        state++;
        !           630:
        !           631:        /* Create a DMA map for the command control block.  */
        !           632:        error = bus_dmamap_create(sc->sc_dmat, CCB_PHYS_SIZE, 1, CCB_PHYS_SIZE,
        !           633:            0, wait | BUS_DMA_ALLOCNOW, &ccb->ccb_dmam);
        !           634:        if (error)
        !           635:                goto fail;
        !           636:
        !           637:        return (0);
        !           638:
        !           639:  fail:
        !           640:        if (state > 0)
        !           641:                bus_dmamap_destroy(sc->sc_dmat, ccb->dmam);
        !           642:        return (error);
        !           643: }
        !           644:
        !           645: /*
        !           646:  * Get a free ccb
        !           647:  *
        !           648:  * If there are none, see if we can allocate a new one.  If so, put it in
        !           649:  * the hash table too otherwise either return an error or sleep.
        !           650:  */
        !           651: struct aha_ccb *
        !           652: aha_get_ccb(sc, flags)
        !           653:        struct aha_softc *sc;
        !           654:        int flags;
        !           655: {
        !           656:        struct aha_ccb *ccb;
        !           657:        int hashnum, s;
        !           658:
        !           659:        s = splbio();
        !           660:
        !           661:        /*
        !           662:         * If we can and have to, sleep waiting for one to come free
        !           663:         * but only if we can't allocate a new one.
        !           664:         */
        !           665:        for (;;) {
        !           666:                ccb = TAILQ_FIRST(&sc->sc_free_ccb);
        !           667:                if (ccb) {
        !           668:                        TAILQ_REMOVE(&sc->sc_free_ccb, ccb, chain);
        !           669:                        break;
        !           670:                }
        !           671:                if (sc->sc_numccbs < AHA_CCB_MAX) {
        !           672:                        MALLOC(ccb, struct aha_ccb *, sizeof *ccb, M_DEVBUF,
        !           673:                            (flags & SCSI_NOSLEEP) ? M_NOWAIT : M_WAITOK);
        !           674:                        if (ccb == NULL) {
        !           675:                                printf("%s: can't malloc ccb\n",
        !           676:                                    sc->sc_dev.dv_xname);
        !           677:                                goto out;
        !           678:                        }
        !           679:                        if (aha_init_ccb(sc, ccb, flags) == 0) {
        !           680:                                sc->sc_numccbs++;
        !           681:                                break;
        !           682:                        }
        !           683:                        FREE(ccb, M_DEVBUF);
        !           684:                        ccb = NULL;
        !           685:                }
        !           686:                if (flags & SCSI_NOSLEEP)
        !           687:                        goto out;
        !           688:                tsleep(&sc->sc_free_ccb, PRIBIO, "ahaccb", 0);
        !           689:        }
        !           690:
        !           691:        ccb->flags |= CCB_ALLOC;
        !           692:
        !           693:        if (bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmam, ccb, CCB_PHYS_SIZE,
        !           694:            NULL, BUS_DMA_NOWAIT) != 0) {
        !           695:                aha_free_ccb(sc, ccb);
        !           696:                ccb = NULL;
        !           697:        } else {
        !           698:                hashnum = CCB_HASH(ccb->ccb_dmam->dm_segs[0].ds_addr);
        !           699:                ccb->nexthash = sc->sc_ccbhash[hashnum];
        !           700:                sc->sc_ccbhash[hashnum] = ccb;
        !           701:        }
        !           702: out:
        !           703:        splx(s);
        !           704:        return (ccb);
        !           705: }
        !           706:
        !           707: /*
        !           708:  * Given a physical address, find the ccb that it corresponds to.
        !           709:  */
        !           710: struct aha_ccb *
        !           711: aha_ccb_phys_kv(sc, ccb_phys)
        !           712:        struct aha_softc *sc;
        !           713:        u_long ccb_phys;
        !           714: {
        !           715:        int hashnum = CCB_HASH(ccb_phys);
        !           716:        struct aha_ccb *ccb = sc->sc_ccbhash[hashnum];
        !           717:
        !           718:        while (ccb) {
        !           719:                if (ccb->ccb_dmam->dm_segs[0].ds_addr == ccb_phys)
        !           720:                        break;
        !           721:                ccb = ccb->nexthash;
        !           722:        }
        !           723:        return (ccb);
        !           724: }
        !           725:
        !           726: /*
        !           727:  * Queue a CCB to be sent to the controller, and send it if possible.
        !           728:  */
        !           729: void
        !           730: aha_queue_ccb(sc, ccb)
        !           731:        struct aha_softc *sc;
        !           732:        struct aha_ccb *ccb;
        !           733: {
        !           734:
        !           735:        TAILQ_INSERT_TAIL(&sc->sc_waiting_ccb, ccb, chain);
        !           736:        aha_start_ccbs(sc);
        !           737: }
        !           738:
        !           739: /*
        !           740:  * Garbage collect mailboxes that are no longer in use.
        !           741:  */
        !           742: void
        !           743: aha_collect_mbo(sc)
        !           744:        struct aha_softc *sc;
        !           745: {
        !           746:        struct aha_mbx_out *wmbo;       /* Mail Box Out pointer */
        !           747: #ifdef AHADIAG
        !           748:        struct aha_ccb *ccb;
        !           749: #endif
        !           750:
        !           751:        wmbo = wmbx->cmbo;
        !           752:
        !           753:        while (sc->sc_mbofull > 0) {
        !           754:                if (wmbo->cmd != AHA_MBO_FREE)
        !           755:                        break;
        !           756:
        !           757: #ifdef AHADIAG
        !           758:                ccb = aha_ccb_phys_kv(sc, phystol(wmbo->ccb_addr));
        !           759:                if (!ccb) {
        !           760:                        printf("%s: bad mbo ccb pointer; skipping\n",
        !           761:                            sc->sc_dev.dv_xname);
        !           762:                } else
        !           763:                        ccb->flags &= ~CCB_SENDING;
        !           764: #endif
        !           765:
        !           766:                --sc->sc_mbofull;
        !           767:                aha_nextmbx(wmbo, wmbx, mbo);
        !           768:        }
        !           769:
        !           770:        wmbx->cmbo = wmbo;
        !           771: }
        !           772:
        !           773: /*
        !           774:  * Send as many CCBs as we have empty mailboxes for.
        !           775:  */
        !           776: void
        !           777: aha_start_ccbs(sc)
        !           778:        struct aha_softc *sc;
        !           779: {
        !           780:        int iobase = sc->sc_iobase;
        !           781:        struct aha_mbx_out *wmbo;       /* Mail Box Out pointer */
        !           782:        struct aha_ccb *ccb;
        !           783:
        !           784:        wmbo = wmbx->tmbo;
        !           785:
        !           786:        while ((ccb = TAILQ_FIRST(&sc->sc_waiting_ccb)) != NULL) {
        !           787:                if (sc->sc_mbofull >= AHA_MBX_SIZE) {
        !           788:                        aha_collect_mbo(sc);
        !           789:                        if (sc->sc_mbofull >= AHA_MBX_SIZE) {
        !           790:                                struct aha_toggle toggle;
        !           791:
        !           792:                                toggle.cmd.opcode = AHA_MBO_INTR_EN;
        !           793:                                toggle.cmd.enable = 1;
        !           794:                                aha_cmd(iobase, sc, sizeof(toggle.cmd),
        !           795:                                    (u_char *)&toggle.cmd, 0, (u_char *)0);
        !           796:                                break;
        !           797:                        }
        !           798:                }
        !           799:
        !           800:                TAILQ_REMOVE(&sc->sc_waiting_ccb, ccb, chain);
        !           801: #ifdef AHADIAG
        !           802:                ccb->flags |= CCB_SENDING;
        !           803: #endif
        !           804:
        !           805:                /* Link ccb to mbo. */
        !           806:                bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmam, 0,
        !           807:                    ccb->ccb_dmam->dm_mapsize, BUS_DMASYNC_PREWRITE);
        !           808:                ltophys(ccb->ccb_dmam->dm_segs[0].ds_addr, wmbo->ccb_addr);
        !           809:                if (ccb->flags & CCB_ABORT)
        !           810:                        wmbo->cmd = AHA_MBO_ABORT;
        !           811:                else
        !           812:                        wmbo->cmd = AHA_MBO_START;
        !           813:
        !           814:                /* Tell the card to poll immediately. */
        !           815:                outb(iobase + AHA_CMD_PORT, AHA_START_SCSI);
        !           816:
        !           817:                if ((ccb->xs->flags & SCSI_POLL) == 0) {
        !           818:                        timeout_set(&ccb->xs->stimeout, aha_timeout, ccb);
        !           819:                        timeout_add(&ccb->xs->stimeout, (ccb->timeout * hz) / 1000);
        !           820:                }
        !           821:
        !           822:                ++sc->sc_mbofull;
        !           823:                aha_nextmbx(wmbo, wmbx, mbo);
        !           824:        }
        !           825:
        !           826:        wmbx->tmbo = wmbo;
        !           827: }
        !           828:
        !           829: /*
        !           830:  * We have a ccb which has been processed by the
        !           831:  * adaptor, now we look to see how the operation
        !           832:  * went. Wake up the owner if waiting
        !           833:  */
        !           834: void
        !           835: aha_done(sc, ccb)
        !           836:        struct aha_softc *sc;
        !           837:        struct aha_ccb *ccb;
        !           838: {
        !           839:        struct scsi_sense_data *s1, *s2;
        !           840:        struct scsi_xfer *xs = ccb->xs;
        !           841:
        !           842:        SC_DEBUG(xs->sc_link, SDEV_DB2, ("aha_done\n"));
        !           843:        /*
        !           844:         * Otherwise, put the results of the operation
        !           845:         * into the xfer and call whoever started it
        !           846:         */
        !           847: #ifdef AHADIAG
        !           848:        if (ccb->flags & CCB_SENDING) {
        !           849:                printf("%s: exiting ccb still in transit!\n",
        !           850:                    sc->sc_dev.dv_xname);
        !           851:                Debugger();
        !           852:                return;
        !           853:        }
        !           854: #endif
        !           855:        if ((ccb->flags & CCB_ALLOC) == 0) {
        !           856:                printf("%s: exiting ccb not allocated!\n",
        !           857:                    sc->sc_dev.dv_xname);
        !           858:                Debugger();
        !           859:                return;
        !           860:        }
        !           861:        if (xs->error == XS_NOERROR) {
        !           862:                if (ccb->host_stat != AHA_OK) {
        !           863:                        switch (ccb->host_stat) {
        !           864:                        case AHA_SEL_TIMEOUT:   /* No response */
        !           865:                                xs->error = XS_SELTIMEOUT;
        !           866:                                break;
        !           867:                        default:        /* Other scsi protocol messes */
        !           868:                                printf("%s: host_stat %x\n",
        !           869:                                    sc->sc_dev.dv_xname, ccb->host_stat);
        !           870:                                xs->error = XS_DRIVER_STUFFUP;
        !           871:                                break;
        !           872:                        }
        !           873:                } else if (ccb->target_stat != SCSI_OK) {
        !           874:                        switch (ccb->target_stat) {
        !           875:                        case SCSI_CHECK:
        !           876:                                s1 = (struct scsi_sense_data *)
        !           877:                                    (((char *)(&ccb->scsi_cmd)) +
        !           878:                                    ccb->scsi_cmd_length);
        !           879:                                s2 = &xs->sense;
        !           880:                                *s2 = *s1;
        !           881:                                xs->error = XS_SENSE;
        !           882:                                break;
        !           883:                        case SCSI_BUSY:
        !           884:                                xs->error = XS_BUSY;
        !           885:                                break;
        !           886:                        default:
        !           887:                                printf("%s: target_stat %x\n",
        !           888:                                    sc->sc_dev.dv_xname, ccb->target_stat);
        !           889:                                xs->error = XS_DRIVER_STUFFUP;
        !           890:                                break;
        !           891:                        }
        !           892:                } else
        !           893:                        xs->resid = 0;
        !           894:        }
        !           895:        xs->flags |= ITSDONE;
        !           896:
        !           897:        if (VOLATILE_XS(xs)) {
        !           898:                wakeup(ccb);
        !           899:                return;
        !           900:        }
        !           901:
        !           902:        if (ccb->dmam->dm_nsegs > 0) {
        !           903:                if (xs->flags & SCSI_DATA_IN)
        !           904:                        bus_dmamap_sync(sc->sc_dmat, ccb->dmam, 0,
        !           905:                            ccb->dmam->dm_mapsize, BUS_DMASYNC_POSTREAD);
        !           906:                if (xs->flags & SCSI_DATA_OUT)
        !           907:                        bus_dmamap_sync(sc->sc_dmat, ccb->dmam, 0,
        !           908:                            ccb->dmam->dm_mapsize, BUS_DMASYNC_POSTWRITE);
        !           909:                bus_dmamap_unload(sc->sc_dmat, ccb->dmam);
        !           910:        }
        !           911:        aha_free_ccb(sc, ccb);
        !           912:        scsi_done(xs);
        !           913: }
        !           914:
        !           915: /*
        !           916:  * Find the board and find its irq/drq
        !           917:  */
        !           918: int
        !           919: aha_find(ia, sc, isapnp)
        !           920:        struct isa_attach_args *ia;
        !           921:        struct aha_softc *sc;
        !           922:        int isapnp;
        !           923: {
        !           924:        int iobase = ia->ia_iobase;
        !           925:        int i;
        !           926:        u_char sts;
        !           927:        struct aha_config config;
        !           928:        int irq, drq;
        !           929:
        !           930:        /*
        !           931:         * reset board, If it doesn't respond, assume
        !           932:         * that it's not there.. good for the probe
        !           933:         */
        !           934:
        !           935:        outb(iobase + AHA_CTRL_PORT, AHA_CTRL_HRST | AHA_CTRL_SRST);
        !           936:
        !           937:        delay(100);
        !           938:        for (i = AHA_RESET_TIMEOUT; i; i--) {
        !           939:                sts = inb(iobase + AHA_STAT_PORT);
        !           940:                if (sts == (AHA_STAT_IDLE | AHA_STAT_INIT))
        !           941:                        break;
        !           942:                delay(1000);    /* calibrated in msec */
        !           943:        }
        !           944:        if (!i) {
        !           945: #ifdef AHADEBUG
        !           946:                if (aha_debug)
        !           947:                        printf("aha_find: No answer from adaptec board\n");
        !           948: #endif /* AHADEBUG */
        !           949:                return (1);
        !           950:        }
        !           951:
        !           952:        /*
        !           953:         * setup dma channel from jumpers and save int
        !           954:         * level
        !           955:         */
        !           956:        delay(1000);            /* for Bustek 545 */
        !           957:        config.cmd.opcode = AHA_INQUIRE_CONFIG;
        !           958:        aha_cmd(iobase, sc, sizeof(config.cmd), (u_char *)&config.cmd,
        !           959:            sizeof(config.reply), (u_char *)&config.reply);
        !           960:        switch (config.reply.chan) {
        !           961:        case EISADMA:
        !           962:                drq = DRQUNK;   /* for EISA/VLB/PCI clones */
        !           963:                break;
        !           964:        case CHAN0:
        !           965:                drq = 0;
        !           966:                break;
        !           967:        case CHAN5:
        !           968:                drq = 5;
        !           969:                break;
        !           970:        case CHAN6:
        !           971:                drq = 6;
        !           972:                break;
        !           973:        case CHAN7:
        !           974:                drq = 7;
        !           975:                break;
        !           976:        default:
        !           977:                printf("aha_find: illegal drq setting %x\n",
        !           978:                    config.reply.chan);
        !           979:                return (1);
        !           980:        }
        !           981:        if (isapnp)
        !           982:                irq = ia->ia_irq;
        !           983:
        !           984:        switch (config.reply.intr) {
        !           985:        case INT9:
        !           986:                irq = 9;
        !           987:                break;
        !           988:        case INT10:
        !           989:                irq = 10;
        !           990:                break;
        !           991:        case INT11:
        !           992:                irq = 11;
        !           993:                break;
        !           994:        case INT12:
        !           995:                irq = 12;
        !           996:                break;
        !           997:        case INT14:
        !           998:                irq = 14;
        !           999:                break;
        !          1000:        case INT15:
        !          1001:                irq = 15;
        !          1002:                break;
        !          1003:        default:
        !          1004:                printf("aha_find: illegal irq setting %x\n",
        !          1005:                    config.reply.intr);
        !          1006:                return (EIO);
        !          1007:        }
        !          1008:        if (isapnp)
        !          1009:                drq = ia->ia_drq;
        !          1010:
        !          1011:        if (sc != NULL) {
        !          1012:                /* who are we on the scsi bus? */
        !          1013:                sc->sc_scsi_dev = config.reply.scsi_dev;
        !          1014:
        !          1015:                sc->sc_iobase = iobase;
        !          1016:                sc->sc_irq = irq;
        !          1017:                sc->sc_drq = drq;
        !          1018:        } else {
        !          1019:                if (isapnp)
        !          1020:                        return (0);
        !          1021:                if (ia->ia_irq == IRQUNK)
        !          1022:                        ia->ia_irq = irq;
        !          1023:                else if (ia->ia_irq != irq)
        !          1024:                        return (1);
        !          1025:                if (ia->ia_drq == DRQUNK)
        !          1026:                        ia->ia_drq = drq;
        !          1027:                else if (ia->ia_drq != drq)
        !          1028:                        return (1);
        !          1029:        }
        !          1030:
        !          1031:        return (0);
        !          1032: }
        !          1033:
        !          1034: /*
        !          1035:  * Start the board, ready for normal operation
        !          1036:  */
        !          1037: void
        !          1038: aha_init(sc)
        !          1039:        struct aha_softc *sc;
        !          1040: {
        !          1041:        int iobase = sc->sc_iobase;
        !          1042:        struct aha_devices devices;
        !          1043:        struct aha_setup setup;
        !          1044:        struct aha_mailbox mailbox;
        !          1045:        struct pglist pglist;
        !          1046:        struct vm_page *pg;
        !          1047:        vaddr_t va;
        !          1048:        vsize_t size;
        !          1049:        int i;
        !          1050:
        !          1051:        /*
        !          1052:         * XXX
        !          1053:         * If we are a 1542C or later, disable the extended BIOS so that the
        !          1054:         * mailbox interface is unlocked.
        !          1055:         * No need to check the extended BIOS flags as some of the
        !          1056:         * extensions that cause us problems are not flagged in that byte.
        !          1057:         */
        !          1058:        if (!strncmp(sc->sc_model, "1542C", 5)) {
        !          1059:                struct aha_extbios extbios;
        !          1060:                struct aha_unlock unlock;
        !          1061:
        !          1062:                printf("%s: unlocking mailbox interface\n",
        !          1063:                    sc->sc_dev.dv_xname);
        !          1064:                extbios.cmd.opcode = AHA_EXT_BIOS;
        !          1065:                aha_cmd(iobase, sc, sizeof(extbios.cmd),
        !          1066:                    (u_char *)&extbios.cmd, sizeof(extbios.reply),
        !          1067:                    (u_char *)&extbios.reply);
        !          1068:
        !          1069: #ifdef AHADEBUG
        !          1070:                printf("%s: flags=%02x, mailboxlock=%02x\n",
        !          1071:                    sc->sc_dev.dv_xname,
        !          1072:                    extbios.reply.flags, extbios.reply.mailboxlock);
        !          1073: #endif /* AHADEBUG */
        !          1074:
        !          1075:                unlock.cmd.opcode = AHA_MBX_ENABLE;
        !          1076:                unlock.cmd.junk = 0;
        !          1077:                unlock.cmd.magic = extbios.reply.mailboxlock;
        !          1078:                aha_cmd(iobase, sc, sizeof(unlock.cmd), (u_char *)&unlock.cmd,
        !          1079:                    0, (u_char *)0);
        !          1080:        }
        !          1081:
        !          1082: #if 0
        !          1083:        /*
        !          1084:         * Change the bus on/off times to not clash with other dma users.
        !          1085:         */
        !          1086:        aha_cmd(sc, 1, 0, 0, 0, AHA_BUS_ON_TIME_SET, 7);
        !          1087:        aha_cmd(sc, 1, 0, 0, 0, AHA_BUS_OFF_TIME_SET, 4);
        !          1088: #endif
        !          1089:
        !          1090:        /* Inquire Installed Devices (to force synchronous negotiation). */
        !          1091:        devices.cmd.opcode = AHA_INQUIRE_DEVICES;
        !          1092:        aha_cmd(iobase, sc, sizeof(devices.cmd), (u_char *)&devices.cmd,
        !          1093:            sizeof(devices.reply), (u_char *)&devices.reply);
        !          1094:
        !          1095:        /* Obtain setup information from. */
        !          1096:        setup.cmd.opcode = AHA_INQUIRE_SETUP;
        !          1097:        setup.cmd.len = sizeof(setup.reply);
        !          1098:        aha_cmd(iobase, sc, sizeof(setup.cmd), (u_char *)&setup.cmd,
        !          1099:            sizeof(setup.reply), (u_char *)&setup.reply);
        !          1100:
        !          1101:        printf("%s: %s, %s\n",
        !          1102:            sc->sc_dev.dv_xname,
        !          1103:            setup.reply.sync_neg ? "sync" : "async",
        !          1104:            setup.reply.parity ? "parity" : "no parity");
        !          1105:
        !          1106:        for (i = 0; i < 8; i++) {
        !          1107:                if (!setup.reply.sync[i].valid ||
        !          1108:                    (!setup.reply.sync[i].offset &&
        !          1109:                    !setup.reply.sync[i].period))
        !          1110:                        continue;
        !          1111:                printf("%s targ %d: sync, offset %d, period %dnsec\n",
        !          1112:                    sc->sc_dev.dv_xname, i, setup.reply.sync[i].offset,
        !          1113:                    setup.reply.sync[i].period * 50 + 200);
        !          1114:        }
        !          1115:
        !          1116:        /*
        !          1117:         * Set up initial mail box for round-robin operation.
        !          1118:         */
        !          1119:
        !          1120:        /*
        !          1121:         * XXX - this vm juggling is so wrong. use bus_dma instead!
        !          1122:         */
        !          1123:        size = round_page(sizeof(struct aha_mbx));
        !          1124:        TAILQ_INIT(&pglist);
        !          1125:        if (uvm_pglistalloc(size, 0, 0xffffff, PAGE_SIZE, 0, &pglist, 1, 0) ||
        !          1126:            uvm_map(kernel_map, &va, size, NULL, UVM_UNKNOWN_OFFSET, 0,
        !          1127:                UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL, UVM_INH_NONE,
        !          1128:                        UVM_ADV_RANDOM, 0)))
        !          1129:                panic("aha_init: could not allocate mailbox");
        !          1130:
        !          1131:        wmbx = (struct aha_mbx *)va;
        !          1132:        for (pg = TAILQ_FIRST(&pglist); pg != NULL;
        !          1133:            pg = TAILQ_NEXT(pg, pageq)) {
        !          1134:                pmap_kenter_pa(va, VM_PAGE_TO_PHYS(pg),
        !          1135:                        VM_PROT_READ|VM_PROT_WRITE);
        !          1136:                va += PAGE_SIZE;
        !          1137:        }
        !          1138:        pmap_update(pmap_kernel());
        !          1139:        /*
        !          1140:         * XXXEND
        !          1141:         */
        !          1142:
        !          1143:        for (i = 0; i < AHA_MBX_SIZE; i++) {
        !          1144:                wmbx->mbo[i].cmd = AHA_MBO_FREE;
        !          1145:                wmbx->mbi[i].stat = AHA_MBI_FREE;
        !          1146:        }
        !          1147:        wmbx->cmbo = wmbx->tmbo = &wmbx->mbo[0];
        !          1148:        wmbx->tmbi = &wmbx->mbi[0];
        !          1149:        sc->sc_mbofull = 0;
        !          1150:
        !          1151:        /* Initialize mail box. */
        !          1152:        mailbox.cmd.opcode = AHA_MBX_INIT;
        !          1153:        mailbox.cmd.nmbx = AHA_MBX_SIZE;
        !          1154:        ltophys(vtophys((vaddr_t)wmbx), mailbox.cmd.addr);
        !          1155:        aha_cmd(iobase, sc, sizeof(mailbox.cmd), (u_char *)&mailbox.cmd,
        !          1156:            0, (u_char *)0);
        !          1157: }
        !          1158:
        !          1159: void
        !          1160: aha_inquire_setup_information(sc)
        !          1161:        struct aha_softc *sc;
        !          1162: {
        !          1163:        int iobase = sc->sc_iobase;
        !          1164:        struct aha_revision revision;
        !          1165:        u_char sts;
        !          1166:        int i;
        !          1167:        char *p;
        !          1168:
        !          1169:        strlcpy(sc->sc_model, "unknown", sizeof sc->sc_model);
        !          1170:
        !          1171:        /*
        !          1172:         * Assume we have a board at this stage, do an adapter inquire
        !          1173:         * to find out what type of controller it is.  If the command
        !          1174:         * fails, we assume it's either a crusty board or an old 1542
        !          1175:         * clone, and skip the board-specific stuff.
        !          1176:         */
        !          1177:        revision.cmd.opcode = AHA_INQUIRE_REVISION;
        !          1178:        if (aha_cmd(iobase, sc, sizeof(revision.cmd), (u_char *)&revision.cmd,
        !          1179:            sizeof(revision.reply), (u_char *)&revision.reply)) {
        !          1180:                /*
        !          1181:                 * aha_cmd() already started the reset.  It's not clear we
        !          1182:                 * even need to bother here.
        !          1183:                 */
        !          1184:                for (i = AHA_RESET_TIMEOUT; i; i--) {
        !          1185:                        sts = inb(iobase + AHA_STAT_PORT);
        !          1186:                        if (sts == (AHA_STAT_IDLE | AHA_STAT_INIT))
        !          1187:                                break;
        !          1188:                        delay(1000);
        !          1189:                }
        !          1190:                if (!i) {
        !          1191: #ifdef AHADEBUG
        !          1192:                        printf("aha_init: soft reset failed\n");
        !          1193: #endif /* AHADEBUG */
        !          1194:                        return;
        !          1195:                }
        !          1196: #ifdef AHADEBUG
        !          1197:                printf("aha_init: inquire command failed\n");
        !          1198: #endif /* AHADEBUG */
        !          1199:                goto noinquire;
        !          1200:        }
        !          1201:
        !          1202: #ifdef AHADEBUG
        !          1203:        printf("%s: inquire %x, %x, %x, %x\n",
        !          1204:            sc->sc_dev.dv_xname,
        !          1205:            revision.reply.boardid, revision.reply.spec_opts,
        !          1206:            revision.reply.revision_1, revision.reply.revision_2);
        !          1207: #endif /* AHADEBUG */
        !          1208:
        !          1209:        switch (revision.reply.boardid) {
        !          1210:        case 0x31:
        !          1211:                strlcpy(sc->sc_model, "1540", sizeof sc->sc_model);
        !          1212:                break;
        !          1213:        case 0x41:
        !          1214:                strlcpy(sc->sc_model, "1540A/1542A/1542B", sizeof sc->sc_model);
        !          1215:                break;
        !          1216:        case 0x42:
        !          1217:                strlcpy(sc->sc_model, "1640", sizeof sc->sc_model);
        !          1218:                break;
        !          1219:        case 0x43:
        !          1220:        case 0x44:              /* Is this 1542C or -CF? */
        !          1221:                strlcpy(sc->sc_model, "1542C", sizeof sc->sc_model);
        !          1222:                break;
        !          1223:        case 0x45:
        !          1224:                strlcpy(sc->sc_model, "1542CF", sizeof sc->sc_model);
        !          1225:                break;
        !          1226:        case 0x46:
        !          1227:                strlcpy(sc->sc_model, "1542CP", sizeof sc->sc_model);
        !          1228:                break;
        !          1229:        }
        !          1230:
        !          1231:        p = sc->sc_firmware;
        !          1232:        *p++ = revision.reply.revision_1;
        !          1233:        *p++ = '.';
        !          1234:        *p++ = revision.reply.revision_2;
        !          1235:        *p = '\0';
        !          1236:
        !          1237: noinquire:
        !          1238:        printf(": model AHA-%s, firmware %s\n", sc->sc_model, sc->sc_firmware);
        !          1239: }
        !          1240:
        !          1241: void
        !          1242: ahaminphys(bp)
        !          1243:        struct buf *bp;
        !          1244: {
        !          1245:
        !          1246:        if (bp->b_bcount > ((AHA_NSEG - 1) << PGSHIFT))
        !          1247:                bp->b_bcount = ((AHA_NSEG - 1) << PGSHIFT);
        !          1248:        minphys(bp);
        !          1249: }
        !          1250:
        !          1251: /*
        !          1252:  * start a scsi operation given the command and the data address. Also needs
        !          1253:  * the unit, target and lu.
        !          1254:  */
        !          1255: int
        !          1256: aha_scsi_cmd(xs)
        !          1257:        struct scsi_xfer *xs;
        !          1258: {
        !          1259:        struct scsi_link *sc_link = xs->sc_link;
        !          1260:        struct aha_softc *sc = sc_link->adapter_softc;
        !          1261:        struct aha_ccb *ccb;
        !          1262:        struct aha_scat_gath *sg;
        !          1263:        int seg, flags;
        !          1264: #ifdef TFS
        !          1265:        struct iovec *iovp;
        !          1266:        int datalen;
        !          1267: #endif
        !          1268:        int s;
        !          1269:
        !          1270:        SC_DEBUG(sc_link, SDEV_DB2, ("aha_scsi_cmd\n"));
        !          1271:        /*
        !          1272:         * get a ccb to use. If the transfer
        !          1273:         * is from a buf (possibly from interrupt time)
        !          1274:         * then we can't allow it to sleep
        !          1275:         */
        !          1276:        flags = xs->flags;
        !          1277:        if ((ccb = aha_get_ccb(sc, flags)) == NULL) {
        !          1278:                return (TRY_AGAIN_LATER);
        !          1279:        }
        !          1280:        ccb->xs = xs;
        !          1281:        ccb->timeout = xs->timeout;
        !          1282:
        !          1283:        /*
        !          1284:         * Put all the arguments for the xfer in the ccb
        !          1285:         */
        !          1286:        if (flags & SCSI_RESET) {
        !          1287:                ccb->opcode = AHA_RESET_CCB;
        !          1288:                ccb->scsi_cmd_length = 0;
        !          1289:        } else {
        !          1290:                /* can't use S/G if zero length */
        !          1291:                ccb->opcode =
        !          1292:                    (xs->datalen ? AHA_INIT_SCAT_GATH_CCB : AHA_INITIATOR_CCB);
        !          1293:                bcopy(xs->cmd, &ccb->scsi_cmd,
        !          1294:                    ccb->scsi_cmd_length = xs->cmdlen);
        !          1295:        }
        !          1296:
        !          1297:        if (xs->datalen) {
        !          1298:                sg = ccb->scat_gath;
        !          1299:                seg = 0;
        !          1300: #ifdef TFS
        !          1301:                if (flags & SCSI_DATA_UIO) {
        !          1302:                        iovp = ((struct uio *)xs->data)->uio_iov;
        !          1303:                        datalen = ((struct uio *)xs->data)->uio_iovcnt;
        !          1304:                        xs->datalen = 0;
        !          1305:                        while (datalen && seg < AHA_NSEG) {
        !          1306:                                ltophys(iovp->iov_base, sg->seg_addr);
        !          1307:                                ltophys(iovp->iov_len, sg->seg_len);
        !          1308:                                xs->datalen += iovp->iov_len;
        !          1309:                                SC_DEBUGN(sc_link, SDEV_DB4, ("UIO(0x%x@0x%x)",
        !          1310:                                    iovp->iov_len, iovp->iov_base));
        !          1311:                                sg++;
        !          1312:                                iovp++;
        !          1313:                                seg++;
        !          1314:                                datalen--;
        !          1315:                        }
        !          1316:                } else
        !          1317: #endif /* TFS */
        !          1318:                {
        !          1319:                        /*
        !          1320:                         * Set up the scatter-gather block.
        !          1321:                         */
        !          1322:                        if (bus_dmamap_load(sc->sc_dmat, ccb->dmam, xs->data,
        !          1323:                            xs->datalen, NULL, BUS_DMA_NOWAIT) != 0) {
        !          1324:                                aha_free_ccb(sc, ccb);
        !          1325:                                xs->error = XS_DRIVER_STUFFUP;
        !          1326:                                return (TRY_AGAIN_LATER);
        !          1327:                        }
        !          1328:                        for (seg = 0; seg < ccb->dmam->dm_nsegs; seg++) {
        !          1329:                                ltophys(ccb->dmam->dm_segs[seg].ds_addr,
        !          1330:                                    sg[seg].seg_addr);
        !          1331:                                ltophys(ccb->dmam->dm_segs[seg].ds_len,
        !          1332:                                    sg[seg].seg_len);
        !          1333:                        }
        !          1334:                }
        !          1335:                if (flags & SCSI_DATA_OUT)
        !          1336:                        bus_dmamap_sync(sc->sc_dmat, ccb->dmam, 0,
        !          1337:                            ccb->dmam->dm_mapsize, BUS_DMASYNC_PREWRITE);
        !          1338:                if (flags & SCSI_DATA_IN)
        !          1339:                        bus_dmamap_sync(sc->sc_dmat, ccb->dmam, 0,
        !          1340:                            ccb->dmam->dm_mapsize, BUS_DMASYNC_PREREAD);
        !          1341:                ltophys((unsigned)
        !          1342:                    ((struct aha_ccb *)(ccb->ccb_dmam->dm_segs[0].ds_addr))->
        !          1343:                    scat_gath,
        !          1344:                    ccb->data_addr);
        !          1345:                ltophys(ccb->dmam->dm_nsegs * sizeof(struct aha_scat_gath),
        !          1346:                    ccb->data_length);
        !          1347:        } else {                /* No data xfer, use non S/G values */
        !          1348:                ltophys(0, ccb->data_addr);
        !          1349:                ltophys(0, ccb->data_length);
        !          1350:        }
        !          1351:
        !          1352:        ccb->data_out = 0;
        !          1353:        ccb->data_in = 0;
        !          1354:        ccb->target = sc_link->target;
        !          1355:        ccb->lun = sc_link->lun;
        !          1356:        ccb->req_sense_length = sizeof(ccb->scsi_sense);
        !          1357:        ccb->host_stat = 0x00;
        !          1358:        ccb->target_stat = 0x00;
        !          1359:        ccb->link_id = 0;
        !          1360:        ltophys(0, ccb->link_addr);
        !          1361:
        !          1362:        s = splbio();
        !          1363:        aha_queue_ccb(sc, ccb);
        !          1364:
        !          1365:        /*
        !          1366:         * Usually return SUCCESSFULLY QUEUED
        !          1367:         */
        !          1368:        SC_DEBUG(sc_link, SDEV_DB3, ("cmd_sent\n"));
        !          1369:
        !          1370:        if (VOLATILE_XS(xs)) {
        !          1371:                while ((ccb->xs->flags & ITSDONE) == 0) {
        !          1372:                        tsleep(ccb, PRIBIO, "ahawait", 0);
        !          1373:                }
        !          1374:                if (ccb->dmam->dm_nsegs > 0) {
        !          1375:                        if (flags & SCSI_DATA_OUT)
        !          1376:                                bus_dmamap_sync(sc->sc_dmat, ccb->dmam, 0,
        !          1377:                                    ccb->dmam->dm_mapsize,
        !          1378:                                    BUS_DMASYNC_POSTWRITE);
        !          1379:                        if (flags & SCSI_DATA_IN)
        !          1380:                                bus_dmamap_sync(sc->sc_dmat, ccb->dmam, 0,
        !          1381:                                    ccb->dmam->dm_mapsize,
        !          1382:                                    BUS_DMASYNC_POSTREAD);
        !          1383:                        bus_dmamap_unload(sc->sc_dmat, ccb->dmam);
        !          1384:                }
        !          1385:                aha_free_ccb(sc, ccb);
        !          1386:                scsi_done(xs);
        !          1387:                splx(s);
        !          1388:                return (COMPLETE);
        !          1389:        }
        !          1390:        splx(s);
        !          1391:
        !          1392:        if ((flags & SCSI_POLL) == 0)
        !          1393:                return (SUCCESSFULLY_QUEUED);
        !          1394:
        !          1395:        /*
        !          1396:         * If we can't use interrupts, poll on completion
        !          1397:         */
        !          1398:        if (aha_poll(sc, xs, ccb->timeout)) {
        !          1399:                aha_timeout(ccb);
        !          1400:                if (aha_poll(sc, xs, ccb->timeout))
        !          1401:                        aha_timeout(ccb);
        !          1402:        }
        !          1403:        return (COMPLETE);
        !          1404: }
        !          1405:
        !          1406: /*
        !          1407:  * Poll a particular unit, looking for a particular xs
        !          1408:  */
        !          1409: int
        !          1410: aha_poll(sc, xs, count)
        !          1411:        struct aha_softc *sc;
        !          1412:        struct scsi_xfer *xs;
        !          1413:        int count;
        !          1414: {
        !          1415:        int iobase = sc->sc_iobase;
        !          1416:        int s;
        !          1417:
        !          1418:        /* timeouts are in msec, so we loop in 1000 usec cycles */
        !          1419:        while (count) {
        !          1420:                /*
        !          1421:                 * If we had interrupts enabled, would we
        !          1422:                 * have got an interrupt?
        !          1423:                 */
        !          1424:                if (inb(iobase + AHA_INTR_PORT) & AHA_INTR_ANYINTR) {
        !          1425:                        s = splbio();
        !          1426:                        ahaintr(sc);
        !          1427:                        splx(s);
        !          1428:                }
        !          1429:                if (xs->flags & ITSDONE)
        !          1430:                        return (0);
        !          1431:                delay(1000);    /* only happens in boot so ok */
        !          1432:                count--;
        !          1433:        }
        !          1434:        return (1);
        !          1435: }
        !          1436:
        !          1437: void
        !          1438: aha_timeout(arg)
        !          1439:        void *arg;
        !          1440: {
        !          1441:        struct aha_ccb *ccb = arg;
        !          1442:        struct scsi_xfer *xs;
        !          1443:        struct scsi_link *sc_link;
        !          1444:        struct aha_softc *sc;
        !          1445:        int s;
        !          1446:
        !          1447:        s = splbio();
        !          1448:        bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmam, 0,
        !          1449:            ccb->ccb_dmam->dm_mapsize, BUS_DMASYNC_POSTREAD);
        !          1450:        xs = ccb->xs;
        !          1451:        sc_link = xs->sc_link;
        !          1452:        sc = sc_link->adapter_softc;
        !          1453:
        !          1454:        sc_print_addr(sc_link);
        !          1455:        printf("timed out");
        !          1456:
        !          1457: #ifdef AHADIAG
        !          1458:        /*
        !          1459:         * If The ccb's mbx is not free, then the board has gone south?
        !          1460:         */
        !          1461:        aha_collect_mbo(sc);
        !          1462:        if (ccb->flags & CCB_SENDING) {
        !          1463:                printf("%s: not taking commands!\n", sc->sc_dev.dv_xname);
        !          1464:                Debugger();
        !          1465:        }
        !          1466: #endif
        !          1467:
        !          1468:        /*
        !          1469:         * If it has been through before, then
        !          1470:         * a previous abort has failed, don't
        !          1471:         * try abort again
        !          1472:         */
        !          1473:        if (ccb->flags & CCB_ABORT) {
        !          1474:                /* abort timed out */
        !          1475:                printf(" AGAIN\n");
        !          1476:                /* XXX Must reset! */
        !          1477:        } else {
        !          1478:                /* abort the operation that has timed out */
        !          1479:                printf("\n");
        !          1480:                ccb->xs->error = XS_TIMEOUT;
        !          1481:                ccb->timeout = AHA_ABORT_TIMEOUT;
        !          1482:                ccb->flags |= CCB_ABORT;
        !          1483:                aha_queue_ccb(sc, ccb);
        !          1484:        }
        !          1485:
        !          1486:        splx(s);
        !          1487: }
        !          1488:

CVSweb