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

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

1.1     ! nbrk        1: /*     $OpenBSD: adv.c,v 1.17 2006/11/29 01:00:47 grange Exp $ */
        !             2: /*     $NetBSD: adv.c,v 1.6 1998/10/28 20:39:45 dante Exp $    */
        !             3:
        !             4: /*
        !             5:  * Generic driver for the Advanced Systems Inc. Narrow SCSI controllers
        !             6:  *
        !             7:  * Copyright (c) 1998 The NetBSD Foundation, Inc.
        !             8:  * All rights reserved.
        !             9:  *
        !            10:  * Author: Baldassare Dante Profeta <dante@mclink.it>
        !            11:  *
        !            12:  * Redistribution and use in source and binary forms, with or without
        !            13:  * modification, are permitted provided that the following conditions
        !            14:  * are met:
        !            15:  * 1. Redistributions of source code must retain the above copyright
        !            16:  *    notice, this list of conditions and the following disclaimer.
        !            17:  * 2. Redistributions in binary form must reproduce the above copyright
        !            18:  *    notice, this list of conditions and the following disclaimer in the
        !            19:  *    documentation and/or other materials provided with the distribution.
        !            20:  * 3. All advertising materials mentioning features or use of this software
        !            21:  *    must display the following acknowledgement:
        !            22:  *        This product includes software developed by the NetBSD
        !            23:  *        Foundation, Inc. and its contributors.
        !            24:  * 4. Neither the name of The NetBSD Foundation nor the names of its
        !            25:  *    contributors may be used to endorse or promote products derived
        !            26:  *    from this software without specific prior written permission.
        !            27:  *
        !            28:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
        !            29:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            30:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            31:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
        !            32:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            33:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            34:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            35:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            36:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            37:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            38:  * POSSIBILITY OF SUCH DAMAGE.
        !            39:  */
        !            40:
        !            41: #include <sys/types.h>
        !            42: #include <sys/param.h>
        !            43: #include <sys/systm.h>
        !            44: #include <sys/kernel.h>
        !            45: #include <sys/errno.h>
        !            46: #include <sys/ioctl.h>
        !            47: #include <sys/device.h>
        !            48: #include <sys/malloc.h>
        !            49: #include <sys/buf.h>
        !            50: #include <sys/proc.h>
        !            51: #include <sys/user.h>
        !            52:
        !            53: #include <machine/bus.h>
        !            54: #include <machine/intr.h>
        !            55:
        !            56: #include <scsi/scsi_all.h>
        !            57: #include <scsi/scsiconf.h>
        !            58:
        !            59: #include <dev/ic/adv.h>
        !            60: #include <dev/ic/advlib.h>
        !            61:
        !            62: #ifndef DDB
        !            63: #define        Debugger()      panic("should call debugger here (adv.c)")
        !            64: #endif /* ! DDB */
        !            65:
        !            66:
        !            67: /* #define ASC_DEBUG */
        !            68:
        !            69: /******************************************************************************/
        !            70:
        !            71:
        !            72: static void adv_enqueue(ASC_SOFTC *, struct scsi_xfer *, int);
        !            73: static struct scsi_xfer *adv_dequeue(ASC_SOFTC *);
        !            74:
        !            75: static int adv_alloc_ccbs(ASC_SOFTC *);
        !            76: static int adv_create_ccbs(ASC_SOFTC *, ADV_CCB *, int);
        !            77: static void adv_free_ccb(ASC_SOFTC *, ADV_CCB *);
        !            78: static void adv_reset_ccb(ADV_CCB *);
        !            79: static int adv_init_ccb(ASC_SOFTC *, ADV_CCB *);
        !            80: static ADV_CCB *adv_get_ccb(ASC_SOFTC *, int);
        !            81: static void adv_queue_ccb(ASC_SOFTC *, ADV_CCB *);
        !            82: static void adv_start_ccbs(ASC_SOFTC *);
        !            83:
        !            84: static u_int8_t *adv_alloc_overrunbuf(char *dvname, bus_dma_tag_t);
        !            85:
        !            86: static int adv_scsi_cmd(struct scsi_xfer *);
        !            87: static void advminphys(struct buf *);
        !            88: static void adv_narrow_isr_callback(ASC_SOFTC *, ASC_QDONE_INFO *);
        !            89:
        !            90: static int adv_poll(ASC_SOFTC *, struct scsi_xfer *, int);
        !            91: static void adv_timeout(void *);
        !            92: static void adv_watchdog(void *);
        !            93:
        !            94:
        !            95: /******************************************************************************/
        !            96:
        !            97:
        !            98: struct cfdriver adv_cd = {
        !            99:        NULL, "adv", DV_DULL
        !           100: };
        !           101:
        !           102:
        !           103: struct scsi_adapter adv_switch =
        !           104: {
        !           105:        adv_scsi_cmd,           /* called to start/enqueue a SCSI command */
        !           106:        advminphys,             /* to limit the transfer to max device can do */
        !           107:        0,                      /* IT SEEMS IT IS NOT USED YET */
        !           108:        0,                      /* as above... */
        !           109: };
        !           110:
        !           111:
        !           112: /* the below structure is so we have a default dev struct for out link struct */
        !           113: struct scsi_device adv_dev =
        !           114: {
        !           115:        NULL,                   /* Use default error handler */
        !           116:        NULL,                   /* have a queue, served by this */
        !           117:        NULL,                   /* have no async handler */
        !           118:        NULL,                   /* Use default 'done' routine */
        !           119: };
        !           120:
        !           121:
        !           122: #define ADV_ABORT_TIMEOUT       2000   /* time to wait for abort (mSec) */
        !           123: #define ADV_WATCH_TIMEOUT       1000   /* time to wait for watchdog (mSec) */
        !           124:
        !           125:
        !           126: /******************************************************************************/
        !           127: /*                            scsi_xfer queue routines                      */
        !           128: /******************************************************************************/
        !           129:
        !           130:
        !           131: /*
        !           132:  * Insert a scsi_xfer into the software queue.  We overload xs->free_list
        !           133:  * to avoid having to allocate additional resources (since we're used
        !           134:  * only during resource shortages anyhow.
        !           135:  */
        !           136: static void
        !           137: adv_enqueue(sc, xs, infront)
        !           138:        ASC_SOFTC      *sc;
        !           139:        struct scsi_xfer *xs;
        !           140:        int             infront;
        !           141: {
        !           142:
        !           143:        if (infront || LIST_EMPTY(&sc->sc_queue)) {
        !           144:                if (LIST_EMPTY(&sc->sc_queue))
        !           145:                        sc->sc_queuelast = xs;
        !           146:                LIST_INSERT_HEAD(&sc->sc_queue, xs, free_list);
        !           147:                return;
        !           148:        }
        !           149:        LIST_INSERT_AFTER(sc->sc_queuelast, xs, free_list);
        !           150:        sc->sc_queuelast = xs;
        !           151: }
        !           152:
        !           153:
        !           154: /*
        !           155:  * Pull a scsi_xfer off the front of the software queue.
        !           156:  */
        !           157: static struct scsi_xfer *
        !           158: adv_dequeue(sc)
        !           159:        ASC_SOFTC      *sc;
        !           160: {
        !           161:        struct scsi_xfer *xs;
        !           162:
        !           163:        xs = LIST_FIRST(&sc->sc_queue);
        !           164:        LIST_REMOVE(xs, free_list);
        !           165:
        !           166:        if (LIST_EMPTY(&sc->sc_queue))
        !           167:                sc->sc_queuelast = NULL;
        !           168:
        !           169:        return (xs);
        !           170: }
        !           171:
        !           172:
        !           173: /******************************************************************************/
        !           174: /*                             Control Blocks routines                        */
        !           175: /******************************************************************************/
        !           176:
        !           177:
        !           178: static int
        !           179: adv_alloc_ccbs(sc)
        !           180:        ASC_SOFTC      *sc;
        !           181: {
        !           182:        bus_dma_segment_t seg;
        !           183:        int             error, rseg;
        !           184:
        !           185:        /*
        !           186:          * Allocate the control blocks.
        !           187:          */
        !           188:        if ((error = bus_dmamem_alloc(sc->sc_dmat, sizeof(struct adv_control),
        !           189:                           NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
        !           190:                printf("%s: unable to allocate control structures,"
        !           191:                       " error = %d\n", sc->sc_dev.dv_xname, error);
        !           192:                return (error);
        !           193:        }
        !           194:        if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg,
        !           195:                   sizeof(struct adv_control), (caddr_t *) & sc->sc_control,
        !           196:                                 BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
        !           197:                printf("%s: unable to map control structures, error = %d\n",
        !           198:                       sc->sc_dev.dv_xname, error);
        !           199:                return (error);
        !           200:        }
        !           201:        /*
        !           202:          * Create and load the DMA map used for the control blocks.
        !           203:          */
        !           204:        if ((error = bus_dmamap_create(sc->sc_dmat, sizeof(struct adv_control),
        !           205:                           1, sizeof(struct adv_control), 0, BUS_DMA_NOWAIT,
        !           206:                                       &sc->sc_dmamap_control)) != 0) {
        !           207:                printf("%s: unable to create control DMA map, error = %d\n",
        !           208:                       sc->sc_dev.dv_xname, error);
        !           209:                return (error);
        !           210:        }
        !           211:        if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap_control,
        !           212:                           sc->sc_control, sizeof(struct adv_control), NULL,
        !           213:                                     BUS_DMA_NOWAIT)) != 0) {
        !           214:                printf("%s: unable to load control DMA map, error = %d\n",
        !           215:                       sc->sc_dev.dv_xname, error);
        !           216:                return (error);
        !           217:        }
        !           218:        return (0);
        !           219: }
        !           220:
        !           221:
        !           222: /*
        !           223:  * Create a set of ccbs and add them to the free list.  Called once
        !           224:  * by adv_init().  We return the number of CCBs successfully created.
        !           225:  */
        !           226: static int
        !           227: adv_create_ccbs(sc, ccbstore, count)
        !           228:        ASC_SOFTC      *sc;
        !           229:        ADV_CCB        *ccbstore;
        !           230:        int             count;
        !           231: {
        !           232:        ADV_CCB        *ccb;
        !           233:        int             i, error;
        !           234:
        !           235:        bzero(ccbstore, sizeof(ADV_CCB) * count);
        !           236:        for (i = 0; i < count; i++) {
        !           237:                ccb = &ccbstore[i];
        !           238:                if ((error = adv_init_ccb(sc, ccb)) != 0) {
        !           239:                        printf("%s: unable to initialize ccb, error = %d\n",
        !           240:                               sc->sc_dev.dv_xname, error);
        !           241:                        return (i);
        !           242:                }
        !           243:                TAILQ_INSERT_TAIL(&sc->sc_free_ccb, ccb, chain);
        !           244:        }
        !           245:
        !           246:        return (i);
        !           247: }
        !           248:
        !           249:
        !           250: /*
        !           251:  * A ccb is put onto the free list.
        !           252:  */
        !           253: static void
        !           254: adv_free_ccb(sc, ccb)
        !           255:        ASC_SOFTC      *sc;
        !           256:        ADV_CCB        *ccb;
        !           257: {
        !           258:        int             s;
        !           259:
        !           260:        s = splbio();
        !           261:
        !           262:        adv_reset_ccb(ccb);
        !           263:        TAILQ_INSERT_HEAD(&sc->sc_free_ccb, ccb, chain);
        !           264:
        !           265:        /*
        !           266:          * If there were none, wake anybody waiting for one to come free,
        !           267:          * starting with queued entries.
        !           268:          */
        !           269:        if (TAILQ_NEXT(ccb, chain) == NULL)
        !           270:                wakeup(&sc->sc_free_ccb);
        !           271:
        !           272:        splx(s);
        !           273: }
        !           274:
        !           275:
        !           276: static void
        !           277: adv_reset_ccb(ccb)
        !           278:        ADV_CCB        *ccb;
        !           279: {
        !           280:
        !           281:        ccb->flags = 0;
        !           282: }
        !           283:
        !           284:
        !           285: static int
        !           286: adv_init_ccb(sc, ccb)
        !           287:        ASC_SOFTC      *sc;
        !           288:        ADV_CCB        *ccb;
        !           289: {
        !           290:        int             error;
        !           291:
        !           292:        /*
        !           293:          * Create the DMA map for this CCB.
        !           294:          */
        !           295:        error = bus_dmamap_create(sc->sc_dmat,
        !           296:                                  (ASC_MAX_SG_LIST - 1) * PAGE_SIZE,
        !           297:                         ASC_MAX_SG_LIST, (ASC_MAX_SG_LIST - 1) * PAGE_SIZE,
        !           298:                   0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ccb->dmamap_xfer);
        !           299:        if (error) {
        !           300:                printf("%s: unable to create DMA map, error = %d\n",
        !           301:                       sc->sc_dev.dv_xname, error);
        !           302:                return (error);
        !           303:        }
        !           304:        adv_reset_ccb(ccb);
        !           305:        return (0);
        !           306: }
        !           307:
        !           308:
        !           309: /*
        !           310:  * Get a free ccb
        !           311:  *
        !           312:  * If there are none, see if we can allocate a new one
        !           313:  */
        !           314: static ADV_CCB *
        !           315: adv_get_ccb(sc, flags)
        !           316:        ASC_SOFTC      *sc;
        !           317:        int             flags;
        !           318: {
        !           319:        ADV_CCB        *ccb = 0;
        !           320:        int             s;
        !           321:
        !           322:        s = splbio();
        !           323:
        !           324:        /*
        !           325:          * If we can and have to, sleep waiting for one to come free
        !           326:          * but only if we can't allocate a new one.
        !           327:          */
        !           328:        for (;;) {
        !           329:                ccb = TAILQ_FIRST(&sc->sc_free_ccb);
        !           330:                if (ccb) {
        !           331:                        TAILQ_REMOVE(&sc->sc_free_ccb, ccb, chain);
        !           332:                        break;
        !           333:                }
        !           334:                if ((flags & SCSI_NOSLEEP) != 0)
        !           335:                        goto out;
        !           336:
        !           337:                tsleep(&sc->sc_free_ccb, PRIBIO, "advccb", 0);
        !           338:        }
        !           339:
        !           340:        ccb->flags |= CCB_ALLOC;
        !           341:
        !           342: out:
        !           343:        splx(s);
        !           344:        return (ccb);
        !           345: }
        !           346:
        !           347:
        !           348: /*
        !           349:  * Queue a CCB to be sent to the controller, and send it if possible.
        !           350:  */
        !           351: static void
        !           352: adv_queue_ccb(sc, ccb)
        !           353:        ASC_SOFTC      *sc;
        !           354:        ADV_CCB        *ccb;
        !           355: {
        !           356:
        !           357:        timeout_set(&ccb->xs->stimeout, adv_timeout, ccb);
        !           358:        TAILQ_INSERT_TAIL(&sc->sc_waiting_ccb, ccb, chain);
        !           359:
        !           360:        adv_start_ccbs(sc);
        !           361: }
        !           362:
        !           363:
        !           364: static void
        !           365: adv_start_ccbs(sc)
        !           366:        ASC_SOFTC      *sc;
        !           367: {
        !           368:        ADV_CCB        *ccb;
        !           369:        struct scsi_xfer *xs;
        !           370:
        !           371:        while ((ccb = TAILQ_FIRST(&sc->sc_waiting_ccb)) != NULL) {
        !           372:
        !           373:                xs = ccb->xs;
        !           374:                if (ccb->flags & CCB_WATCHDOG)
        !           375:                        timeout_del(&xs->stimeout);
        !           376:
        !           377:                if (AscExeScsiQueue(sc, &ccb->scsiq) == ASC_BUSY) {
        !           378:                        ccb->flags |= CCB_WATCHDOG;
        !           379:                        timeout_set(&xs->stimeout, adv_watchdog, ccb);
        !           380:                        timeout_add(&xs->stimeout,
        !           381:                                (ADV_WATCH_TIMEOUT * hz) / 1000);
        !           382:                        break;
        !           383:                }
        !           384:                TAILQ_REMOVE(&sc->sc_waiting_ccb, ccb, chain);
        !           385:
        !           386:                if ((ccb->xs->flags & SCSI_POLL) == 0) {
        !           387:                        timeout_set(&xs->stimeout, adv_timeout, ccb);
        !           388:                        timeout_add(&xs->stimeout, (ccb->timeout * hz) / 1000);
        !           389:                }
        !           390:        }
        !           391: }
        !           392:
        !           393:
        !           394: /******************************************************************************/
        !           395: /*                      DMA able memory allocation routines                   */
        !           396: /******************************************************************************/
        !           397:
        !           398:
        !           399: /*
        !           400:  * Allocate a DMA able memory for overrun_buffer.
        !           401:  * This memory can be safely shared among all the AdvanSys boards.
        !           402:  */
        !           403: u_int8_t       *
        !           404: adv_alloc_overrunbuf(dvname, dmat)
        !           405:        char           *dvname;
        !           406:        bus_dma_tag_t   dmat;
        !           407: {
        !           408:        static u_int8_t *overrunbuf = NULL;
        !           409:
        !           410:        bus_dmamap_t    ovrbuf_dmamap;
        !           411:        bus_dma_segment_t seg;
        !           412:        int             rseg, error;
        !           413:
        !           414:
        !           415:        /*
        !           416:          * if an overrun buffer has been already allocated don't allocate it
        !           417:          * again. Instead return the address of the allocated buffer.
        !           418:          */
        !           419:        if (overrunbuf)
        !           420:                return (overrunbuf);
        !           421:
        !           422:
        !           423:        if ((error = bus_dmamem_alloc(dmat, ASC_OVERRUN_BSIZE,
        !           424:                           NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
        !           425:                printf("%s: unable to allocate overrun buffer, error = %d\n",
        !           426:                       dvname, error);
        !           427:                return (0);
        !           428:        }
        !           429:        if ((error = bus_dmamem_map(dmat, &seg, rseg, ASC_OVERRUN_BSIZE,
        !           430:        (caddr_t *) & overrunbuf, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
        !           431:                printf("%s: unable to map overrun buffer, error = %d\n",
        !           432:                       dvname, error);
        !           433:
        !           434:                bus_dmamem_free(dmat, &seg, 1);
        !           435:                return (0);
        !           436:        }
        !           437:        if ((error = bus_dmamap_create(dmat, ASC_OVERRUN_BSIZE, 1,
        !           438:              ASC_OVERRUN_BSIZE, 0, BUS_DMA_NOWAIT, &ovrbuf_dmamap)) != 0) {
        !           439:                printf("%s: unable to create overrun buffer DMA map,"
        !           440:                       " error = %d\n", dvname, error);
        !           441:
        !           442:                bus_dmamem_unmap(dmat, overrunbuf, ASC_OVERRUN_BSIZE);
        !           443:                bus_dmamem_free(dmat, &seg, 1);
        !           444:                return (0);
        !           445:        }
        !           446:        if ((error = bus_dmamap_load(dmat, ovrbuf_dmamap, overrunbuf,
        !           447:                           ASC_OVERRUN_BSIZE, NULL, BUS_DMA_NOWAIT)) != 0) {
        !           448:                printf("%s: unable to load overrun buffer DMA map,"
        !           449:                       " error = %d\n", dvname, error);
        !           450:
        !           451:                bus_dmamap_destroy(dmat, ovrbuf_dmamap);
        !           452:                bus_dmamem_unmap(dmat, overrunbuf, ASC_OVERRUN_BSIZE);
        !           453:                bus_dmamem_free(dmat, &seg, 1);
        !           454:                return (0);
        !           455:        }
        !           456:        return (overrunbuf);
        !           457: }
        !           458:
        !           459:
        !           460: /******************************************************************************/
        !           461: /*                         SCSI layer interfacing routines                    */
        !           462: /******************************************************************************/
        !           463:
        !           464:
        !           465: int
        !           466: adv_init(sc)
        !           467:        ASC_SOFTC      *sc;
        !           468: {
        !           469:        int             warn;
        !           470:
        !           471:        if (!AscFindSignature(sc->sc_iot, sc->sc_ioh))
        !           472:                panic("adv_init: adv_find_signature failed");
        !           473:
        !           474:        /*
        !           475:          * Read the board configuration
        !           476:          */
        !           477:        AscInitASC_SOFTC(sc);
        !           478:        warn = AscInitFromEEP(sc);
        !           479:        if (warn) {
        !           480:                printf("%s -get: ", sc->sc_dev.dv_xname);
        !           481:                switch (warn) {
        !           482:                case -1:
        !           483:                        printf("Chip is not halted\n");
        !           484:                        break;
        !           485:
        !           486:                case -2:
        !           487:                        printf("Couldn't get MicroCode Start"
        !           488:                               " address\n");
        !           489:                        break;
        !           490:
        !           491:                case ASC_WARN_IO_PORT_ROTATE:
        !           492:                        printf("I/O port address modified\n");
        !           493:                        break;
        !           494:
        !           495:                case ASC_WARN_AUTO_CONFIG:
        !           496:                        printf("I/O port increment switch enabled\n");
        !           497:                        break;
        !           498:
        !           499:                case ASC_WARN_EEPROM_CHKSUM:
        !           500:                        printf("EEPROM checksum error\n");
        !           501:                        break;
        !           502:
        !           503:                case ASC_WARN_IRQ_MODIFIED:
        !           504:                        printf("IRQ modified\n");
        !           505:                        break;
        !           506:
        !           507:                case ASC_WARN_CMD_QNG_CONFLICT:
        !           508:                        printf("tag queuing enabled w/o disconnects\n");
        !           509:                        break;
        !           510:
        !           511:                default:
        !           512:                        printf("unknown warning %d\n", warn);
        !           513:                }
        !           514:        }
        !           515:        if (sc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT)
        !           516:                sc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
        !           517:
        !           518:        /*
        !           519:          * Modify the board configuration
        !           520:          */
        !           521:        warn = AscInitFromASC_SOFTC(sc);
        !           522:        if (warn) {
        !           523:                printf("%s -set: ", sc->sc_dev.dv_xname);
        !           524:                switch (warn) {
        !           525:                case ASC_WARN_CMD_QNG_CONFLICT:
        !           526:                        printf("tag queuing enabled w/o disconnects\n");
        !           527:                        break;
        !           528:
        !           529:                case ASC_WARN_AUTO_CONFIG:
        !           530:                        printf("I/O port increment switch enabled\n");
        !           531:                        break;
        !           532:
        !           533:                default:
        !           534:                        printf("unknown warning %d\n", warn);
        !           535:                }
        !           536:        }
        !           537:        sc->isr_callback = (ulong) adv_narrow_isr_callback;
        !           538:
        !           539:        if (!(sc->overrun_buf = adv_alloc_overrunbuf(sc->sc_dev.dv_xname,
        !           540:                                                     sc->sc_dmat))) {
        !           541:                return (1);
        !           542:        }
        !           543:
        !           544:        return (0);
        !           545: }
        !           546:
        !           547:
        !           548: void
        !           549: adv_attach(sc)
        !           550:        ASC_SOFTC      *sc;
        !           551: {
        !           552:        struct scsibus_attach_args      saa;
        !           553:        int                             i, error;
        !           554:
        !           555:        /*
        !           556:          * Initialize board RISC chip and enable interrupts.
        !           557:          */
        !           558:        switch (AscInitDriver(sc)) {
        !           559:        case 0:
        !           560:                /* AllOK */
        !           561:                break;
        !           562:
        !           563:        case 1:
        !           564:                panic("%s: bad signature", sc->sc_dev.dv_xname);
        !           565:                break;
        !           566:
        !           567:        case 2:
        !           568:                panic("%s: unable to load MicroCode",
        !           569:                      sc->sc_dev.dv_xname);
        !           570:                break;
        !           571:
        !           572:        case 3:
        !           573:                panic("%s: unable to initialize MicroCode",
        !           574:                      sc->sc_dev.dv_xname);
        !           575:                break;
        !           576:
        !           577:        default:
        !           578:                panic("%s: unable to initialize board RISC chip",
        !           579:                      sc->sc_dev.dv_xname);
        !           580:        }
        !           581:
        !           582:
        !           583:        /*
        !           584:          * fill in the prototype scsi_link.
        !           585:          */
        !           586:        sc->sc_link.adapter_softc = sc;
        !           587:        sc->sc_link.adapter_target = sc->chip_scsi_id;
        !           588:        sc->sc_link.adapter = &adv_switch;
        !           589:        sc->sc_link.device = &adv_dev;
        !           590:        sc->sc_link.openings = 4;
        !           591:        sc->sc_link.adapter_buswidth = 7;
        !           592:
        !           593:
        !           594:        TAILQ_INIT(&sc->sc_free_ccb);
        !           595:        TAILQ_INIT(&sc->sc_waiting_ccb);
        !           596:        LIST_INIT(&sc->sc_queue);
        !           597:
        !           598:
        !           599:        /*
        !           600:          * Allocate the Control Blocks.
        !           601:          */
        !           602:        error = adv_alloc_ccbs(sc);
        !           603:        if (error)
        !           604:                return; /* (error) */ ;
        !           605:
        !           606:        /*
        !           607:          * Create and initialize the Control Blocks.
        !           608:          */
        !           609:        i = adv_create_ccbs(sc, sc->sc_control->ccbs, ADV_MAX_CCB);
        !           610:        if (i == 0) {
        !           611:                printf("%s: unable to create control blocks\n",
        !           612:                       sc->sc_dev.dv_xname);
        !           613:                return; /* (ENOMEM) */ ;
        !           614:        } else if (i != ADV_MAX_CCB) {
        !           615:                printf("%s: WARNING: only %d of %d control blocks created\n",
        !           616:                       sc->sc_dev.dv_xname, i, ADV_MAX_CCB);
        !           617:        }
        !           618:
        !           619:        bzero(&saa, sizeof(saa));
        !           620:        saa.saa_sc_link = &sc->sc_link;
        !           621:        config_found(&sc->sc_dev, &saa, scsiprint);
        !           622: }
        !           623:
        !           624:
        !           625: static void
        !           626: advminphys(bp)
        !           627:        struct buf     *bp;
        !           628: {
        !           629:
        !           630:        if (bp->b_bcount > ((ASC_MAX_SG_LIST - 1) * PAGE_SIZE))
        !           631:                bp->b_bcount = ((ASC_MAX_SG_LIST - 1) * PAGE_SIZE);
        !           632:        minphys(bp);
        !           633: }
        !           634:
        !           635:
        !           636: /*
        !           637:  * start a scsi operation given the command and the data address.  Also needs
        !           638:  * the unit, target and lu.
        !           639:  */
        !           640: static int
        !           641: adv_scsi_cmd(xs)
        !           642:        struct scsi_xfer *xs;
        !           643: {
        !           644:        struct scsi_link *sc_link = xs->sc_link;
        !           645:        ASC_SOFTC      *sc = sc_link->adapter_softc;
        !           646:        bus_dma_tag_t   dmat = sc->sc_dmat;
        !           647:        ADV_CCB        *ccb;
        !           648:        int             s, flags, error, nsegs;
        !           649:        int             fromqueue = 1, dontqueue = 0;
        !           650:
        !           651:
        !           652:        s = splbio();           /* protect the queue */
        !           653:
        !           654:        /*
        !           655:          * If we're running the queue from adv_done(), we've been
        !           656:          * called with the first queue entry as our argument.
        !           657:          */
        !           658:        if (xs == LIST_FIRST(&sc->sc_queue)) {
        !           659:                xs = adv_dequeue(sc);
        !           660:                fromqueue = 1;
        !           661:        } else {
        !           662:
        !           663:                /* Polled requests can't be queued for later. */
        !           664:                dontqueue = xs->flags & SCSI_POLL;
        !           665:
        !           666:                /*
        !           667:                  * If there are jobs in the queue, run them first.
        !           668:                  */
        !           669:                if (!LIST_EMPTY(&sc->sc_queue)) {
        !           670:                        /*
        !           671:                          * If we can't queue, we have to abort, since
        !           672:                          * we have to preserve order.
        !           673:                          */
        !           674:                        if (dontqueue) {
        !           675:                                splx(s);
        !           676:                                return (TRY_AGAIN_LATER);
        !           677:                        }
        !           678:                        /*
        !           679:                          * Swap with the first queue entry.
        !           680:                          */
        !           681:                        adv_enqueue(sc, xs, 0);
        !           682:                        xs = adv_dequeue(sc);
        !           683:                        fromqueue = 1;
        !           684:                }
        !           685:        }
        !           686:
        !           687:
        !           688:        /*
        !           689:          * get a ccb to use. If the transfer
        !           690:          * is from a buf (possibly from interrupt time)
        !           691:          * then we can't allow it to sleep
        !           692:          */
        !           693:
        !           694:        flags = xs->flags;
        !           695:        if ((ccb = adv_get_ccb(sc, flags)) == NULL) {
        !           696:                /*
        !           697:                  * If we can't queue, we lose.
        !           698:                  */
        !           699:                if (dontqueue) {
        !           700:                        splx(s);
        !           701:                        return (TRY_AGAIN_LATER);
        !           702:                }
        !           703:                /*
        !           704:                  * Stuff ourselves into the queue, in front
        !           705:                  * if we came off in the first place.
        !           706:                  */
        !           707:                adv_enqueue(sc, xs, fromqueue);
        !           708:                splx(s);
        !           709:                return (SUCCESSFULLY_QUEUED);
        !           710:        }
        !           711:        splx(s);                /* done playing with the queue */
        !           712:
        !           713:        ccb->xs = xs;
        !           714:        ccb->timeout = xs->timeout;
        !           715:
        !           716:        /*
        !           717:          * Build up the request
        !           718:          */
        !           719:        memset(&ccb->scsiq, 0, sizeof(ASC_SCSI_Q));
        !           720:
        !           721:        ccb->scsiq.q2.ccb_ptr = (ulong) ccb;
        !           722:
        !           723:        ccb->scsiq.cdbptr = &xs->cmd->opcode;
        !           724:        ccb->scsiq.q2.cdb_len = xs->cmdlen;
        !           725:        ccb->scsiq.q1.target_id = ASC_TID_TO_TARGET_ID(sc_link->target);
        !           726:        ccb->scsiq.q1.target_lun = sc_link->lun;
        !           727:        ccb->scsiq.q2.target_ix = ASC_TIDLUN_TO_IX(sc_link->target,
        !           728:                                                   sc_link->lun);
        !           729:        ccb->scsiq.q1.sense_addr = sc->sc_dmamap_control->dm_segs[0].ds_addr +
        !           730:                ADV_CCB_OFF(ccb) + offsetof(struct adv_ccb, scsi_sense);
        !           731:        ccb->scsiq.q1.sense_len = sizeof(struct scsi_sense_data);
        !           732:
        !           733:        /*
        !           734:          * If  there  are  any  outstanding  requests  for  the  current target,
        !           735:          * then  every  255th request  send an  ORDERED request.  This heuristic
        !           736:          * tries  to  retain  the  benefit  of request  sorting while preventing
        !           737:          * request starvation. 255 is the max number of tags or pending commands
        !           738:          * a device may have outstanding.
        !           739:          */
        !           740:        sc->reqcnt[sc_link->target]++;
        !           741:        if ((sc->reqcnt[sc_link->target] > 0) &&
        !           742:            (sc->reqcnt[sc_link->target] % 255) == 0) {
        !           743:                ccb->scsiq.q2.tag_code = M2_QTAG_MSG_ORDERED;
        !           744:        } else {
        !           745:                ccb->scsiq.q2.tag_code = M2_QTAG_MSG_SIMPLE;
        !           746:        }
        !           747:
        !           748:
        !           749:        if (xs->datalen) {
        !           750:                /*
        !           751:                  * Map the DMA transfer.
        !           752:                  */
        !           753: #ifdef TFS
        !           754:                if (flags & SCSI_DATA_UIO) {
        !           755:                        error = bus_dmamap_load_uio(dmat,
        !           756:                                  ccb->dmamap_xfer, (struct uio *) xs->data,
        !           757:                                                    (flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
        !           758:                } else
        !           759: #endif                         /* TFS */
        !           760:                {
        !           761:                        error = bus_dmamap_load(dmat,
        !           762:                              ccb->dmamap_xfer, xs->data, xs->datalen, NULL,
        !           763:                                                (flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
        !           764:                }
        !           765:
        !           766:                if (error) {
        !           767:                        if (error == EFBIG) {
        !           768:                                printf("%s: adv_scsi_cmd, more than %d dma"
        !           769:                                       " segments\n",
        !           770:                                       sc->sc_dev.dv_xname, ASC_MAX_SG_LIST);
        !           771:                        } else {
        !           772:                                printf("%s: adv_scsi_cmd, error %d loading"
        !           773:                                       " dma map\n",
        !           774:                                       sc->sc_dev.dv_xname, error);
        !           775:                        }
        !           776:
        !           777:                        xs->error = XS_DRIVER_STUFFUP;
        !           778:                        adv_free_ccb(sc, ccb);
        !           779:                        return (COMPLETE);
        !           780:                }
        !           781:                bus_dmamap_sync(dmat, ccb->dmamap_xfer,
        !           782:                    0, ccb->dmamap_xfer->dm_mapsize,
        !           783:                    ((flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD :
        !           784:                        BUS_DMASYNC_PREWRITE));
        !           785:
        !           786:
        !           787:                memset(&ccb->sghead, 0, sizeof(ASC_SG_HEAD));
        !           788:
        !           789:                for (nsegs = 0; nsegs < ccb->dmamap_xfer->dm_nsegs; nsegs++) {
        !           790:
        !           791:                        ccb->sghead.sg_list[nsegs].addr =
        !           792:                                ccb->dmamap_xfer->dm_segs[nsegs].ds_addr;
        !           793:                        ccb->sghead.sg_list[nsegs].bytes =
        !           794:                                ccb->dmamap_xfer->dm_segs[nsegs].ds_len;
        !           795:                }
        !           796:
        !           797:                ccb->sghead.entry_cnt = ccb->scsiq.q1.sg_queue_cnt =
        !           798:                        ccb->dmamap_xfer->dm_nsegs;
        !           799:
        !           800:                ccb->scsiq.q1.cntl |= ASC_QC_SG_HEAD;
        !           801:                ccb->scsiq.sg_head = &ccb->sghead;
        !           802:                ccb->scsiq.q1.data_addr = 0;
        !           803:                ccb->scsiq.q1.data_cnt = 0;
        !           804:        } else {
        !           805:                /*
        !           806:                  * No data xfer, use non S/G values.
        !           807:                  */
        !           808:                ccb->scsiq.q1.data_addr = 0;
        !           809:                ccb->scsiq.q1.data_cnt = 0;
        !           810:        }
        !           811:
        !           812: #ifdef ASC_DEBUG
        !           813:        printf("id = %d, lun = %d, cmd = %d, ccb = 0x%lX \n",
        !           814:                        sc_link->scsipi_scsi.target,
        !           815:                        sc_link->scsipi_scsi.lun, xs->cmd->opcode,
        !           816:                        (unsigned long)ccb);
        !           817: #endif
        !           818:        s = splbio();
        !           819:        adv_queue_ccb(sc, ccb);
        !           820:        splx(s);
        !           821:
        !           822:        /*
        !           823:          * Usually return SUCCESSFULLY QUEUED
        !           824:          */
        !           825:        if ((flags & SCSI_POLL) == 0)
        !           826:                return (SUCCESSFULLY_QUEUED);
        !           827:
        !           828:        /*
        !           829:          * If we can't use interrupts, poll on completion
        !           830:          */
        !           831:        if (adv_poll(sc, xs, ccb->timeout)) {
        !           832:                adv_timeout(ccb);
        !           833:                if (adv_poll(sc, xs, ccb->timeout))
        !           834:                        adv_timeout(ccb);
        !           835:        }
        !           836:        return (COMPLETE);
        !           837: }
        !           838:
        !           839:
        !           840: int
        !           841: adv_intr(arg)
        !           842:        void           *arg;
        !           843: {
        !           844:        ASC_SOFTC      *sc = arg;
        !           845:        struct scsi_xfer *xs;
        !           846:
        !           847: #ifdef ASC_DEBUG
        !           848:        int int_pend = FALSE;
        !           849:
        !           850:        if(ASC_IS_INT_PENDING(sc->sc_iot, sc->sc_ioh))
        !           851:        {
        !           852:                int_pend = TRUE;
        !           853:                printf("ISR - ");
        !           854:        }
        !           855: #endif
        !           856:        AscISR(sc);
        !           857: #ifdef ASC_DEBUG
        !           858:        if(int_pend)
        !           859:                printf("\n");
        !           860: #endif
        !           861:
        !           862:        /*
        !           863:          * If there are queue entries in the software queue, try to
        !           864:          * run the first one.  We should be more or less guaranteed
        !           865:          * to succeed, since we just freed a CCB.
        !           866:          *
        !           867:          * NOTE: adv_scsi_cmd() relies on our calling it with
        !           868:          * the first entry in the queue.
        !           869:          */
        !           870:        if ((xs = LIST_FIRST(&sc->sc_queue)) != NULL)
        !           871:                (void) adv_scsi_cmd(xs);
        !           872:
        !           873:        return (1);
        !           874: }
        !           875:
        !           876:
        !           877: /*
        !           878:  * Poll a particular unit, looking for a particular xs
        !           879:  */
        !           880: static int
        !           881: adv_poll(sc, xs, count)
        !           882:        ASC_SOFTC      *sc;
        !           883:        struct scsi_xfer *xs;
        !           884:        int             count;
        !           885: {
        !           886:
        !           887:        /* timeouts are in msec, so we loop in 1000 usec cycles */
        !           888:        while (count) {
        !           889:                adv_intr(sc);
        !           890:                if (xs->flags & ITSDONE)
        !           891:                        return (0);
        !           892:                delay(1000);    /* only happens in boot so ok */
        !           893:                count--;
        !           894:        }
        !           895:        return (1);
        !           896: }
        !           897:
        !           898:
        !           899: static void
        !           900: adv_timeout(arg)
        !           901:        void           *arg;
        !           902: {
        !           903:        ADV_CCB        *ccb = arg;
        !           904:        struct scsi_xfer *xs = ccb->xs;
        !           905:        struct scsi_link *sc_link = xs->sc_link;
        !           906:        ASC_SOFTC      *sc = sc_link->adapter_softc;
        !           907:        int             s;
        !           908:
        !           909:        sc_print_addr(sc_link);
        !           910:        printf("timed out");
        !           911:
        !           912:        s = splbio();
        !           913:
        !           914:        /*
        !           915:          * If it has been through before, then a previous abort has failed,
        !           916:          * don't try abort again, reset the bus instead.
        !           917:          */
        !           918:        if (ccb->flags & CCB_ABORT) {
        !           919:                /* abort timed out */
        !           920:                printf(" AGAIN. Resetting Bus\n");
        !           921:                /* Lets try resetting the bus! */
        !           922:                if (AscResetBus(sc) == ASC_ERROR) {
        !           923:                        ccb->timeout = sc->scsi_reset_wait;
        !           924:                        adv_queue_ccb(sc, ccb);
        !           925:                }
        !           926:        } else {
        !           927:                /* abort the operation that has timed out */
        !           928:                printf("\n");
        !           929:                AscAbortCCB(sc, (u_int32_t) ccb);
        !           930:                ccb->xs->error = XS_TIMEOUT;
        !           931:                ccb->timeout = ADV_ABORT_TIMEOUT;
        !           932:                ccb->flags |= CCB_ABORT;
        !           933:                adv_queue_ccb(sc, ccb);
        !           934:        }
        !           935:
        !           936:        splx(s);
        !           937: }
        !           938:
        !           939:
        !           940: static void
        !           941: adv_watchdog(arg)
        !           942:        void           *arg;
        !           943: {
        !           944:        ADV_CCB        *ccb = arg;
        !           945:        struct scsi_xfer *xs = ccb->xs;
        !           946:        struct scsi_link *sc_link = xs->sc_link;
        !           947:        ASC_SOFTC      *sc = sc_link->adapter_softc;
        !           948:        int             s;
        !           949:
        !           950:        s = splbio();
        !           951:
        !           952:        ccb->flags &= ~CCB_WATCHDOG;
        !           953:        adv_start_ccbs(sc);
        !           954:
        !           955:        splx(s);
        !           956: }
        !           957:
        !           958:
        !           959: /******************************************************************************/
        !           960: /*                  NARROW and WIDE boards Interrupt callbacks                */
        !           961: /******************************************************************************/
        !           962:
        !           963:
        !           964: /*
        !           965:  * adv_narrow_isr_callback() - Second Level Interrupt Handler called by AscISR()
        !           966:  *
        !           967:  * Interrupt callback function for the Narrow SCSI Asc Library.
        !           968:  */
        !           969: static void
        !           970: adv_narrow_isr_callback(sc, qdonep)
        !           971:        ASC_SOFTC      *sc;
        !           972:        ASC_QDONE_INFO *qdonep;
        !           973: {
        !           974:        bus_dma_tag_t   dmat = sc->sc_dmat;
        !           975:        ADV_CCB        *ccb = (ADV_CCB *) qdonep->d2.ccb_ptr;
        !           976:        struct scsi_xfer *xs = ccb->xs;
        !           977:        struct scsi_sense_data *s1, *s2;
        !           978:
        !           979:
        !           980: #ifdef ASC_DEBUG
        !           981:        printf(" - ccb=0x%lx, id=%d, lun=%d, cmd=%d, ",
        !           982:                        (unsigned long)ccb,
        !           983:                        xs->sc_link->scsipi_scsi.target,
        !           984:                        xs->sc_link->scsipi_scsi.lun, xs->cmd->opcode);
        !           985: #endif
        !           986:        timeout_del(&xs->stimeout);
        !           987:
        !           988:        /*
        !           989:          * If we were a data transfer, unload the map that described
        !           990:          * the data buffer.
        !           991:          */
        !           992:        if (xs->datalen) {
        !           993:                bus_dmamap_sync(dmat, ccb->dmamap_xfer,
        !           994:                    0, ccb->dmamap_xfer->dm_mapsize,
        !           995:                    ((xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD :
        !           996:                        BUS_DMASYNC_POSTWRITE));
        !           997:                bus_dmamap_unload(dmat, ccb->dmamap_xfer);
        !           998:        }
        !           999:        if ((ccb->flags & CCB_ALLOC) == 0) {
        !          1000:                printf("%s: exiting ccb not allocated!\n", sc->sc_dev.dv_xname);
        !          1001:                Debugger();
        !          1002:                return;
        !          1003:        }
        !          1004:        /*
        !          1005:          * 'qdonep' contains the command's ending status.
        !          1006:          */
        !          1007: #ifdef ASC_DEBUG
        !          1008:        printf("d_s=%d, h_s=%d", qdonep->d3.done_stat, qdonep->d3.host_stat);
        !          1009: #endif
        !          1010:        switch (qdonep->d3.done_stat) {
        !          1011:        case ASC_QD_NO_ERROR:
        !          1012:                switch (qdonep->d3.host_stat) {
        !          1013:                case ASC_QHSTA_NO_ERROR:
        !          1014:                        xs->error = XS_NOERROR;
        !          1015:                        xs->resid = 0;
        !          1016:                        break;
        !          1017:
        !          1018:                default:
        !          1019:                        /* QHSTA error occurred */
        !          1020:                        xs->error = XS_DRIVER_STUFFUP;
        !          1021:                        break;
        !          1022:                }
        !          1023:
        !          1024:                /*
        !          1025:                  * If an INQUIRY command completed successfully, then call
        !          1026:                  * the AscInquiryHandling() function to patch bugged boards.
        !          1027:                  */
        !          1028:                if ((xs->cmd->opcode == SCSICMD_Inquiry) &&
        !          1029:                    (xs->sc_link->lun == 0) &&
        !          1030:                    (xs->datalen - qdonep->remain_bytes) >= 8) {
        !          1031:                        AscInquiryHandling(sc,
        !          1032:                                      xs->sc_link->target & 0x7,
        !          1033:                                           (ASC_SCSI_INQUIRY *) xs->data);
        !          1034:                }
        !          1035:                break;
        !          1036:
        !          1037:        case ASC_QD_WITH_ERROR:
        !          1038:                switch (qdonep->d3.host_stat) {
        !          1039:                case ASC_QHSTA_NO_ERROR:
        !          1040:                        if (qdonep->d3.scsi_stat == SS_CHK_CONDITION) {
        !          1041:                                s1 = &ccb->scsi_sense;
        !          1042:                                s2 = &xs->sense;
        !          1043:                                *s2 = *s1;
        !          1044:                                xs->error = XS_SENSE;
        !          1045:                        } else {
        !          1046:                                xs->error = XS_DRIVER_STUFFUP;
        !          1047:                        }
        !          1048:                        break;
        !          1049:
        !          1050:                default:
        !          1051:                        /* QHSTA error occurred */
        !          1052:                        xs->error = XS_DRIVER_STUFFUP;
        !          1053:                        break;
        !          1054:                }
        !          1055:                break;
        !          1056:
        !          1057:        case ASC_QD_ABORTED_BY_HOST:
        !          1058:        default:
        !          1059:                xs->error = XS_DRIVER_STUFFUP;
        !          1060:                break;
        !          1061:        }
        !          1062:
        !          1063:
        !          1064:        adv_free_ccb(sc, ccb);
        !          1065:        xs->flags |= ITSDONE;
        !          1066:        scsi_done(xs);
        !          1067: }

CVSweb