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

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

1.1     ! nbrk        1: /*     $OpenBSD: isp_openbsd.c,v 1.30 2007/04/10 17:47:55 miod Exp $ */
        !             2: /*
        !             3:  * Platform (OpenBSD) dependent common attachment code for Qlogic adapters.
        !             4:  *
        !             5:  * Copyright (c) 1999, 2000, 2001 by Matthew Jacob
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * Redistribution and use in source and binary forms, with or without
        !             9:  * modification, are permitted provided that the following conditions
        !            10:  * are met:
        !            11:  * 1. Redistributions of source code must retain the above copyright
        !            12:  *    notice immediately at the beginning of the file, without modification,
        !            13:  *    this list of conditions, and the following disclaimer.
        !            14:  *    documentation and/or other materials provided with the distribution.
        !            15:  * 2. The name of the author may not be used to endorse or promote products
        !            16:  *    derived from this software without specific prior written permission.
        !            17:  *
        !            18:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
        !            19:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            20:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            21:  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
        !            22:  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            23:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            24:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            25:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            26:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            27:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            28:  * SUCH DAMAGE.
        !            29:  *
        !            30:  * The author may be reached via electronic communications at
        !            31:  *
        !            32:  *  mjacob@feral.com
        !            33:  *
        !            34:  * or, via United States Postal Address
        !            35:  *
        !            36:  *  Matthew Jacob
        !            37:  *  Feral Software
        !            38:  *  PMB#825
        !            39:  *  5214-F Diamond Heights Blvd.
        !            40:  *  San Francisco, CA, 94131
        !            41:  */
        !            42:
        !            43: /* expand expensive inline functions here. */
        !            44: #define EXPENSIVE_INLINE
        !            45: #include <dev/ic/isp_openbsd.h>
        !            46:
        !            47: /*
        !            48:  * Set a timeout for the watchdogging of a command.
        !            49:  *
        !            50:  * The dimensional analysis is
        !            51:  *
        !            52:  *     milliseconds * (seconds/millisecond) * (ticks/second) = ticks
        !            53:  *
        !            54:  *                     =
        !            55:  *
        !            56:  *     (milliseconds / 1000) * hz = ticks
        !            57:  *
        !            58:  *
        !            59:  * For timeouts less than 1 second, we'll get zero. Because of this, and
        !            60:  * because we want to establish *our* timeout to be longer than what the
        !            61:  * firmware might do, we just add 3 seconds at the back end.
        !            62:  */
        !            63: #define        _XT(xs) ((((xs)->timeout/1000) * hz) + (3 * hz))
        !            64:
        !            65: static void ispminphys(struct buf *);
        !            66: static int32_t ispcmd_slow(XS_T *);
        !            67: static int32_t ispcmd(XS_T *);
        !            68:
        !            69: static struct scsi_device isp_dev = { NULL, NULL, NULL, NULL };
        !            70:
        !            71: static int isp_polled_cmd (struct ispsoftc *, XS_T *);
        !            72: static void isp_wdog (void *);
        !            73: static void isp_requeue(void *);
        !            74: static void isp_trestart(void *);
        !            75: static void isp_restart(struct ispsoftc *);
        !            76:
        !            77: struct cfdriver isp_cd = {
        !            78:        NULL, "isp", DV_DULL
        !            79: };
        !            80:
        !            81:
        !            82: /*
        !            83:  * Complete attachment of hardware, include subdevices.
        !            84:  */
        !            85: void
        !            86: isp_attach(struct ispsoftc *isp)
        !            87: {
        !            88:        struct scsibus_attach_args saa;
        !            89:        struct scsi_link *lptr = &isp->isp_osinfo._link[0];
        !            90:        isp->isp_osinfo._adapter.scsi_minphys = ispminphys;
        !            91:
        !            92:        isp->isp_state = ISP_RUNSTATE;
        !            93:
        !            94:        /*
        !            95:         * We only manage a single wait queues for dual bus controllers.
        !            96:         * This is arguably broken.
        !            97:         */
        !            98:        isp->isp_osinfo.wqf = isp->isp_osinfo.wqt = NULL;
        !            99:
        !           100:        lptr->adapter_softc = isp;
        !           101:        lptr->device = &isp_dev;
        !           102:        lptr->adapter = &isp->isp_osinfo._adapter;
        !           103:        lptr->openings = imin(isp->isp_maxcmds, MAXISPREQUEST(isp));
        !           104:        isp->isp_osinfo._adapter.scsi_cmd = ispcmd_slow;
        !           105:        if (IS_FC(isp)) {
        !           106:                lptr->adapter_buswidth = MAX_FC_TARG;
        !           107:                /* We can set max lun width here */
        !           108:                /* loopid set below */
        !           109:        } else {
        !           110:                sdparam *sdp = isp->isp_param;
        !           111:                lptr->adapter_buswidth = MAX_TARGETS;
        !           112:                /* We can set max lun width here */
        !           113:                lptr->adapter_target = sdp->isp_initiator_id;
        !           114:                isp->isp_osinfo.discovered[0] = 1 << sdp->isp_initiator_id;
        !           115:                if (IS_DUALBUS(isp)) {
        !           116:                        struct scsi_link *lptrb = &isp->isp_osinfo._link[1];
        !           117:                        lptrb->adapter_softc = isp;
        !           118:                        lptrb->device = &isp_dev;
        !           119:                        lptrb->adapter = &isp->isp_osinfo._adapter;
        !           120:                        lptrb->openings = lptr->openings;
        !           121:                        lptrb->adapter_buswidth = MAX_TARGETS;
        !           122:                        lptrb->adapter_target = sdp->isp_initiator_id;
        !           123:                        lptrb->flags = SDEV_2NDBUS;
        !           124:                        isp->isp_osinfo.discovered[1] =
        !           125:                            1 << (sdp+1)->isp_initiator_id;
        !           126:                }
        !           127:        }
        !           128:
        !           129:        /*
        !           130:         * Send a SCSI Bus Reset (used to be done as part of attach,
        !           131:         * but now left to the OS outer layers).
        !           132:         *
        !           133:         * We don't do 'bus resets' for FC because the LIP that occurs
        !           134:         * when we start the firmware does all that for us.
        !           135:         */
        !           136:        if (IS_SCSI(isp)) {
        !           137:                int bus = 0;
        !           138:                ISP_LOCK(isp);
        !           139:                (void) isp_control(isp, ISPCTL_RESET_BUS, &bus);
        !           140:                if (IS_DUALBUS(isp)) {
        !           141:                        bus++;
        !           142:                        (void) isp_control(isp, ISPCTL_RESET_BUS, &bus);
        !           143:                }
        !           144:                ISP_UNLOCK(isp);
        !           145:                /*
        !           146:                 * wait for the bus to settle.
        !           147:                 */
        !           148:                delay(4 * 1000000);
        !           149:        } else {
        !           150:                fcparam *fcp = isp->isp_param;
        !           151:                int defid = MAX_FC_TARG;
        !           152:                delay(2 * 1000000);
        !           153:                ISP_LOCK(isp);
        !           154:                isp_fc_runstate(isp, 10 * 1000000);
        !           155:                if (fcp->isp_fwstate == FW_READY &&
        !           156:                    fcp->isp_loopstate >= LOOP_PDB_RCVD) {
        !           157:                        defid = fcp->isp_loopid;
        !           158:                }
        !           159:                ISP_UNLOCK(isp);
        !           160:                lptr->adapter_target = defid;
        !           161:        }
        !           162:
        !           163:        bzero(&saa, sizeof(saa));
        !           164:        saa.saa_sc_link = lptr;
        !           165:
        !           166:        /*
        !           167:         * And attach children (if any).
        !           168:         */
        !           169:        config_found((void *)isp, &saa, scsiprint);
        !           170:        if (IS_DUALBUS(isp)) {
        !           171:                lptr++;
        !           172:                bzero(&saa, sizeof(saa));
        !           173:                saa.saa_sc_link = lptr;
        !           174:                config_found((void *)isp, &saa, scsiprint);
        !           175:        }
        !           176: }
        !           177:
        !           178: /*
        !           179:  * minphys our xfers
        !           180:  *
        !           181:  * Unfortunately, the buffer pointer describes the target device- not the
        !           182:  * adapter device, so we can't use the pointer to find out what kind of
        !           183:  * adapter we are and adjust accordingly.
        !           184:  */
        !           185:
        !           186: static void
        !           187: ispminphys(struct buf *bp)
        !           188: {
        !           189:        /*
        !           190:         * XX: Only the 1020 has a 24 bit limit.
        !           191:         */
        !           192:        if (bp->b_bcount >= (1 << 24)) {
        !           193:                bp->b_bcount = (1 << 24);
        !           194:        }
        !           195:        minphys(bp);
        !           196: }
        !           197:
        !           198: static int32_t
        !           199: ispcmd_slow(XS_T *xs)
        !           200: {
        !           201:        sdparam *sdp;
        !           202:        int tgt, chan;
        !           203:        u_int16_t f;
        !           204:        struct ispsoftc *isp = XS_ISP(xs);
        !           205:
        !           206:        if (IS_FC(isp)) {
        !           207:                if (cold == 0) {
        !           208:                        isp->isp_osinfo.no_mbox_ints = 0;
        !           209:                        isp->isp_osinfo._adapter.scsi_cmd = ispcmd;
        !           210:                }
        !           211:                return (ispcmd(xs));
        !           212:        }
        !           213:
        !           214:        /*
        !           215:         * Have we completed discovery for this target on this adapter?
        !           216:         */
        !           217:        sdp = isp->isp_param;
        !           218:        tgt = XS_TGT(xs);
        !           219:        chan = XS_CHANNEL(xs);
        !           220:        sdp += chan;
        !           221:        if ((xs->flags & SCSI_POLL) != 0 ||
        !           222:            (isp->isp_osinfo.discovered[chan] & (1 << tgt)) != 0) {
        !           223:                return (ispcmd(xs));
        !           224:        }
        !           225:        if (cold == 0) {
        !           226:                isp->isp_osinfo.no_mbox_ints = 0;
        !           227:        }
        !           228:
        !           229:        f = DPARM_DEFAULT;
        !           230:        if (xs->sc_link->quirks & SDEV_NOSYNC) {
        !           231:                f &= ~DPARM_SYNC;
        !           232:        }
        !           233:        if (xs->sc_link->quirks & SDEV_NOWIDE) {
        !           234:                f &= ~DPARM_WIDE;
        !           235:        }
        !           236:        if (xs->sc_link->quirks & SDEV_NOTAGS) {
        !           237:                f &= ~DPARM_TQING;
        !           238:        }
        !           239:
        !           240:        /*
        !           241:         * Okay, we know about this device now,
        !           242:         * so mark parameters to be updated for it.
        !           243:         */
        !           244:        sdp->isp_devparam[tgt].goal_flags = f;
        !           245:        sdp->isp_devparam[tgt].dev_update = 1;
        !           246:        isp->isp_update |= (1 << chan);
        !           247:
        !           248:        /*
        !           249:         * Now check to see whether we can get out of this checking mode now.
        !           250:         * XXX: WE CANNOT AS YET BECAUSE THERE IS NO MECHANISM TO TELL US
        !           251:         * XXX: WHEN WE'RE DONE DISCOVERY BECAUSE WE NEED ONE COMMAND AFTER
        !           252:         * XXX: DISCOVERY IS DONE FOR EACH TARGET TO TELL US THAT WE'RE DONE
        !           253:         * XXX: AND THAT DOESN'T HAPPEN HERE. AT BEST WE CAN MARK OURSELVES
        !           254:         * XXX: DONE WITH DISCOVERY FOR THIS TARGET AND SO SAVE MAYBE 20
        !           255:         * XXX: LINES OF C CODE.
        !           256:         */
        !           257:        isp->isp_osinfo.discovered[chan] |= (1 << tgt);
        !           258:        /* do not bother with these lines- they'll never execute correctly */
        !           259: #if    0
        !           260:        sdp = isp->isp_param;
        !           261:        for (chan = 0; chan < (IS_12X0(isp)? 2 : 1); chan++, sdp++) {
        !           262:                f = 0xffff & ~(1 << sdp->isp_initiator_id);
        !           263:                if (isp->isp_osinfo.discovered[chan] != f) {
        !           264:                        break;
        !           265:                }
        !           266:        }
        !           267:        if (chan == (IS_12X0(isp)? 2 : 1)) {
        !           268:                isp->isp_osinfo._adapter.scsipi_cmd = ispcmd;
        !           269:                if (IS_12X0(isp))
        !           270:                        isp->isp_update |= 2;
        !           271:        }
        !           272: #endif
        !           273:        return (ispcmd(xs));
        !           274: }
        !           275:
        !           276: static INLINE void isp_add2_blocked_queue(struct ispsoftc *, XS_T *);
        !           277:
        !           278: static INLINE void
        !           279: isp_add2_blocked_queue(struct ispsoftc *isp, XS_T *xs)
        !           280: {
        !           281:        if (isp->isp_osinfo.wqf != NULL) {
        !           282:                isp->isp_osinfo.wqt->free_list.le_next = xs;
        !           283:        } else {
        !           284:                isp->isp_osinfo.wqf = xs;
        !           285:        }
        !           286:        isp->isp_osinfo.wqt = xs;
        !           287:        xs->free_list.le_next = NULL;
        !           288: }
        !           289:
        !           290: static int32_t
        !           291: ispcmd(XS_T *xs)
        !           292: {
        !           293:        struct ispsoftc *isp;
        !           294:        int result;
        !           295:
        !           296:
        !           297:        /*
        !           298:         * Make sure that there's *some* kind of sane setting.
        !           299:         */
        !           300:        isp = XS_ISP(xs);
        !           301:
        !           302:        timeout_set(&xs->stimeout, isp_wdog, isp);
        !           303:
        !           304:        if (XS_LUN(xs) >= isp->isp_maxluns) {
        !           305:                xs->error = XS_SELTIMEOUT;
        !           306:                return (COMPLETE);
        !           307:        }
        !           308:
        !           309:        ISP_LOCK(isp);
        !           310:        if (isp->isp_state < ISP_RUNSTATE) {
        !           311:                DISABLE_INTS(isp);
        !           312:                isp_init(isp);
        !           313:                if (isp->isp_state != ISP_INITSTATE) {
        !           314:                        ENABLE_INTS(isp);
        !           315:                        ISP_UNLOCK(isp);
        !           316:                        XS_SETERR(xs, HBA_BOTCH);
        !           317:                        return (CMD_COMPLETE);
        !           318:                }
        !           319:                isp->isp_state = ISP_RUNSTATE;
        !           320:                ENABLE_INTS(isp);
        !           321:        }
        !           322:
        !           323:        /*
        !           324:         * Check for queue blockage...
        !           325:         */
        !           326:        if (isp->isp_osinfo.blocked) {
        !           327:                if (xs->flags & SCSI_POLL) {
        !           328:                        ISP_UNLOCK(isp);
        !           329:                        return (TRY_AGAIN_LATER);
        !           330:                }
        !           331:                if (isp->isp_osinfo.blocked == 2) {
        !           332:                        isp_restart(isp);
        !           333:                }
        !           334:                if (isp->isp_osinfo.blocked) {
        !           335:                        isp_add2_blocked_queue(isp, xs);
        !           336:                        ISP_UNLOCK(isp);
        !           337:                        isp_prt(isp, ISP_LOGDEBUG0, "added to blocked queue");
        !           338:                        return (SUCCESSFULLY_QUEUED);
        !           339:                }
        !           340:        }
        !           341:
        !           342:        if (xs->flags & SCSI_POLL) {
        !           343:                volatile u_int8_t ombi = isp->isp_osinfo.no_mbox_ints;
        !           344:                isp->isp_osinfo.no_mbox_ints = 1;
        !           345:                result = isp_polled_cmd(isp, xs);
        !           346:                isp->isp_osinfo.no_mbox_ints = ombi;
        !           347:                ISP_UNLOCK(isp);
        !           348:                return (result);
        !           349:        }
        !           350:
        !           351:        result = isp_start(xs);
        !           352:
        !           353:        switch (result) {
        !           354:        case CMD_QUEUED:
        !           355:                result = SUCCESSFULLY_QUEUED;
        !           356:                if (xs->timeout) {
        !           357:                        timeout_add(&xs->stimeout, _XT(xs));
        !           358:                        XS_CMD_S_TIMER(xs);
        !           359:                }
        !           360:                if (isp->isp_osinfo.hiwater < isp->isp_nactive) {
        !           361:                        isp->isp_osinfo.hiwater = isp->isp_nactive;
        !           362:                        isp_prt(isp, ISP_LOGDEBUG0,
        !           363:                            "Active Hiwater Mark=%d", isp->isp_nactive);
        !           364:                }
        !           365:                break;
        !           366:        case CMD_EAGAIN:
        !           367:                isp->isp_osinfo.blocked |= 2;
        !           368:                isp_prt(isp, ISP_LOGDEBUG0, "blocking queue");
        !           369:                isp_add2_blocked_queue(isp, xs);
        !           370:                result = SUCCESSFULLY_QUEUED;
        !           371:                break;
        !           372:        case CMD_RQLATER:
        !           373:                result = SUCCESSFULLY_QUEUED;   /* Lie */
        !           374:                isp_prt(isp, ISP_LOGDEBUG1, "retrying later for %d.%d",
        !           375:                    XS_TGT(xs), XS_LUN(xs));
        !           376:                timeout_set(&xs->stimeout, isp_requeue, xs);
        !           377:                timeout_add(&xs->stimeout, hz);
        !           378:                XS_CMD_S_TIMER(xs);
        !           379:                break;
        !           380:        case CMD_COMPLETE:
        !           381:                result = COMPLETE;
        !           382:                break;
        !           383:        }
        !           384:        ISP_UNLOCK(isp);
        !           385:        return (result);
        !           386: }
        !           387:
        !           388: static int
        !           389: isp_polled_cmd(struct ispsoftc *isp, XS_T *xs)
        !           390: {
        !           391:        int result;
        !           392:        int infinite = 0, mswait;
        !           393:
        !           394:        result = isp_start(xs);
        !           395:
        !           396:        switch (result) {
        !           397:        case CMD_QUEUED:
        !           398:                result = SUCCESSFULLY_QUEUED;
        !           399:                break;
        !           400:        case CMD_RQLATER:
        !           401:        case CMD_EAGAIN:
        !           402:                result = TRY_AGAIN_LATER;
        !           403:                break;
        !           404:        case CMD_COMPLETE:
        !           405:                result = COMPLETE;
        !           406:                break;
        !           407:
        !           408:        }
        !           409:
        !           410:        if (result != SUCCESSFULLY_QUEUED) {
        !           411:                return (result);
        !           412:        }
        !           413:
        !           414:        /*
        !           415:         * If we can't use interrupts, poll on completion.
        !           416:         */
        !           417:        if ((mswait = XS_TIME(xs)) == 0)
        !           418:                infinite = 1;
        !           419:
        !           420:        while (mswait || infinite) {
        !           421:                u_int16_t isr, sema, mbox;
        !           422:                if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
        !           423:                        isp_intr(isp, isr, sema, mbox);
        !           424:                        if (XS_CMD_DONE_P(xs)) {
        !           425:                                break;
        !           426:                        }
        !           427:                }
        !           428:                USEC_DELAY(1000);
        !           429:                mswait -= 1;
        !           430:        }
        !           431:
        !           432:        /*
        !           433:         * If no other error occurred but we didn't finish,
        !           434:         * something bad happened.
        !           435:         */
        !           436:        if (XS_CMD_DONE_P(xs) == 0) {
        !           437:                if (isp_control(isp, ISPCTL_ABORT_CMD, xs)) {
        !           438:                        isp_reinit(isp);
        !           439:                }
        !           440:                if (XS_NOERR(xs)) {
        !           441:                        XS_SETERR(xs, HBA_BOTCH);
        !           442:                }
        !           443:        }
        !           444:        result = COMPLETE;
        !           445:        return (result);
        !           446: }
        !           447:
        !           448: void
        !           449: isp_done(XS_T *xs)
        !           450: {
        !           451:        XS_CMD_S_DONE(xs);
        !           452:        if (XS_CMD_WDOG_P(xs) == 0) {
        !           453:                struct ispsoftc *isp = XS_ISP(xs);
        !           454:                if (XS_CMD_TIMER_P(xs)) {
        !           455:                        timeout_del(&xs->stimeout);
        !           456:                        XS_CMD_C_TIMER(xs);
        !           457:                }
        !           458:                if (XS_CMD_GRACE_P(xs)) {
        !           459:                        struct ispsoftc *isp = XS_ISP(xs);
        !           460:                        isp_prt(isp, ISP_LOGWARN,
        !           461:                            "finished command on borrowed time");
        !           462:                }
        !           463:                XS_CMD_S_CLEAR(xs);
        !           464:                scsi_done(xs);
        !           465:                if (isp->isp_osinfo.blocked == 2) {
        !           466:                        isp->isp_osinfo.blocked = 0;
        !           467:                        isp_prt(isp, ISP_LOGDEBUG0, "restarting blocked queue");
        !           468:                        isp_restart(isp);
        !           469:                }
        !           470:        }
        !           471: }
        !           472:
        !           473: static void
        !           474: isp_wdog(void *arg)
        !           475: {
        !           476:        XS_T *xs = arg;
        !           477:        struct ispsoftc *isp = XS_ISP(xs);
        !           478:        u_int32_t handle;
        !           479:
        !           480:        /*
        !           481:         * We've decided this command is dead. Make sure we're not trying
        !           482:         * to kill a command that's already dead by getting its handle and
        !           483:         * and seeing whether it's still alive.
        !           484:         */
        !           485:        ISP_LOCK(isp);
        !           486:        handle = isp_find_handle(isp, xs);
        !           487:        if (handle) {
        !           488:                u_int16_t isr, sema, mbox;
        !           489:
        !           490:                if (XS_CMD_DONE_P(xs)) {
        !           491:                        isp_prt(isp, ISP_LOGDEBUG1,
        !           492:                            "watchdog found done cmd (handle 0x%x)",
        !           493:                            handle);
        !           494:                        ISP_UNLOCK(isp);
        !           495:                        return;
        !           496:                }
        !           497:
        !           498:                if (XS_CMD_WDOG_P(xs)) {
        !           499:                        isp_prt(isp, ISP_LOGDEBUG1,
        !           500:                            "recursive watchdog (handle 0x%x)",
        !           501:                            handle);
        !           502:                        ISP_UNLOCK(isp);
        !           503:                        return;
        !           504:                }
        !           505:
        !           506:                XS_CMD_S_WDOG(xs);
        !           507:
        !           508:                if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) {
        !           509:                        isp_intr(isp, isr, sema, mbox);
        !           510:                }
        !           511:
        !           512:                if (XS_CMD_DONE_P(xs)) {
        !           513:                        isp_prt(isp, ISP_LOGINFO,
        !           514:                            "watchdog cleanup for handle 0x%x", handle);
        !           515:                        XS_CMD_C_WDOG(xs);
        !           516:                        isp_done(xs);
        !           517:                } else if (XS_CMD_GRACE_P(xs)) {
        !           518:                        /*
        !           519:                         * Make sure the command is *really* dead before we
        !           520:                         * release the handle (and DMA resources) for reuse.
        !           521:                         */
        !           522:                        (void) isp_control(isp, ISPCTL_ABORT_CMD, arg);
        !           523:
        !           524:                        /*
        !           525:                         * After this point, the command is really dead.
        !           526:                         */
        !           527:                        if (XS_XFRLEN(xs)) {
        !           528:                                ISP_DMAFREE(isp, xs, handle);
        !           529:                        }
        !           530:                        isp_prt(isp, ISP_LOGWARN,
        !           531:                            "watchdog timeout on handle %x", handle);
        !           532:                        isp_destroy_handle(isp, handle);
        !           533:                        XS_SETERR(xs, XS_TIMEOUT);
        !           534:                        XS_CMD_S_CLEAR(xs);
        !           535:                        isp_done(xs);
        !           536:                } else {
        !           537:                        u_int16_t nxti, optr;
        !           538:                        ispreq_t local, *mp = &local, *qe;
        !           539:
        !           540:                        isp_prt(isp, ISP_LOGWARN,
        !           541:                            "possible command timeout on handle %x", handle);
        !           542:
        !           543:                        XS_CMD_C_WDOG(xs);
        !           544:                        timeout_add(&xs->stimeout, _XT(xs));
        !           545:                        XS_CMD_S_TIMER(xs);
        !           546:                        if (isp_getrqentry(isp, &nxti, &optr, (void **) &qe)) {
        !           547:                                ISP_UNLOCK(isp);
        !           548:                                return;
        !           549:                        }
        !           550:                        XS_CMD_S_GRACE(xs);
        !           551:                        MEMZERO((void *) mp, sizeof (*mp));
        !           552:                        mp->req_header.rqs_entry_count = 1;
        !           553:                        mp->req_header.rqs_entry_type = RQSTYPE_MARKER;
        !           554:                        mp->req_modifier = SYNC_ALL;
        !           555:                        mp->req_target = XS_CHANNEL(xs) << 7;
        !           556:                        isp_put_request(isp, mp, qe);
        !           557:                        ISP_ADD_REQUEST(isp, nxti);
        !           558:                }
        !           559:        } else if (isp->isp_dblev) {
        !           560:                isp_prt(isp, ISP_LOGDEBUG1, "watchdog with no command");
        !           561:        }
        !           562:        ISP_UNLOCK(isp);
        !           563: }
        !           564:
        !           565: /*
        !           566:  * Free any associated resources prior to decommissioning and
        !           567:  * set the card to a known state (so it doesn't wake up and kick
        !           568:  * us when we aren't expecting it to).
        !           569:  *
        !           570:  * Locks are held before coming here.
        !           571:  */
        !           572: void
        !           573: isp_uninit(struct ispsoftc *isp)
        !           574: {
        !           575:        ISP_LOCK(isp);
        !           576:        /*
        !           577:         * Leave with interrupts disabled.
        !           578:         */
        !           579:        DISABLE_INTS(isp);
        !           580:
        !           581:        ISP_UNLOCK(isp);
        !           582: }
        !           583:
        !           584: /*
        !           585:  * Restart function for a command to be requeued later.
        !           586:  */
        !           587: static void
        !           588: isp_requeue(void *arg)
        !           589: {
        !           590:        int r;
        !           591:        struct scsi_xfer *xs = arg;
        !           592:        struct ispsoftc *isp = XS_ISP(xs);
        !           593:        ISP_LOCK(isp);
        !           594:        r = isp_start(xs);
        !           595:        switch (r) {
        !           596:        case CMD_QUEUED:
        !           597:                isp_prt(isp, ISP_LOGDEBUG1, "restarted command for %d.%d",
        !           598:                    XS_TGT(xs), XS_LUN(xs));
        !           599:                if (xs->timeout) {
        !           600:                        timeout_set(&xs->stimeout, isp_wdog, isp);
        !           601:                        timeout_add(&xs->stimeout, _XT(xs));
        !           602:                        XS_CMD_S_TIMER(xs);
        !           603:                }
        !           604:                break;
        !           605:        case CMD_EAGAIN:
        !           606:                isp_prt(isp, ISP_LOGDEBUG0, "blocked cmd again");
        !           607:                isp->isp_osinfo.blocked |= 2;
        !           608:                isp_add2_blocked_queue(isp, xs);
        !           609:                break;
        !           610:        case CMD_RQLATER:
        !           611:                isp_prt(isp, ISP_LOGDEBUG0, "%s for %d.%d",
        !           612:                    (r == CMD_EAGAIN)? "CMD_EAGAIN" : "CMD_RQLATER",
        !           613:                    XS_TGT(xs), XS_LUN(xs));
        !           614:                timeout_set(&xs->stimeout, isp_requeue, xs);
        !           615:                timeout_add(&xs->stimeout, hz);
        !           616:                XS_CMD_S_TIMER(xs);
        !           617:                break;
        !           618:        case CMD_COMPLETE:
        !           619:                /* can only be an error */
        !           620:                if (XS_NOERR(xs))
        !           621:                        XS_SETERR(xs, XS_DRIVER_STUFFUP);
        !           622:                isp_done(xs);
        !           623:                break;
        !           624:        }
        !           625:        ISP_UNLOCK(isp);
        !           626: }
        !           627:
        !           628: /*
        !           629:  * Restart function after a LOOP UP event or a command completing,
        !           630:  * sometimes done as a timeout for some hysteresis.
        !           631:  */
        !           632: static void
        !           633: isp_trestart(void *arg)
        !           634: {
        !           635:        struct ispsoftc *isp = arg;
        !           636:        struct scsi_xfer *list;
        !           637:
        !           638:        ISP_LOCK(isp);
        !           639:        isp->isp_osinfo.rtpend = 0;
        !           640:        list = isp->isp_osinfo.wqf;
        !           641:        if (isp->isp_osinfo.blocked == 0 && list != NULL) {
        !           642:                int nrestarted = 0;
        !           643:
        !           644:                isp->isp_osinfo.wqf = NULL;
        !           645:                ISP_UNLOCK(isp);
        !           646:                do {
        !           647:                        struct scsi_xfer *xs = list;
        !           648:                        list = xs->free_list.le_next;
        !           649:                        xs->free_list.le_next = NULL;
        !           650:                        isp_requeue(xs);
        !           651:                        if (isp->isp_osinfo.wqf == NULL)
        !           652:                                nrestarted++;
        !           653:                } while (list != NULL);
        !           654:                isp_prt(isp, ISP_LOGDEBUG0, "requeued %d commands", nrestarted);
        !           655:        } else {
        !           656:                ISP_UNLOCK(isp);
        !           657:        }
        !           658: }
        !           659:
        !           660: static void
        !           661: isp_restart(struct ispsoftc *isp)
        !           662: {
        !           663:        struct scsi_xfer *list;
        !           664:
        !           665:        list = isp->isp_osinfo.wqf;
        !           666:        if (isp->isp_osinfo.blocked == 0 && list != NULL) {
        !           667:                int nrestarted = 0;
        !           668:
        !           669:                isp->isp_osinfo.wqf = NULL;
        !           670:                do {
        !           671:                        struct scsi_xfer *xs = list;
        !           672:                        list = xs->free_list.le_next;
        !           673:                        xs->free_list.le_next = NULL;
        !           674:                        isp_requeue(xs);
        !           675:                        if (isp->isp_osinfo.wqf == NULL)
        !           676:                                nrestarted++;
        !           677:                } while (list != NULL);
        !           678:                isp_prt(isp, ISP_LOGDEBUG0, "requeued %d commands", nrestarted);
        !           679:        }
        !           680: }
        !           681:
        !           682: int
        !           683: isp_async(struct ispsoftc *isp, ispasync_t cmd, void *arg)
        !           684: {
        !           685:        int bus, tgt;
        !           686:
        !           687:        switch (cmd) {
        !           688:        case ISPASYNC_NEW_TGT_PARAMS:
        !           689:        if (IS_SCSI(isp) && isp->isp_dblev) {
        !           690:                sdparam *sdp = isp->isp_param;
        !           691:                char *wt;
        !           692:                int mhz, flags, period;
        !           693:
        !           694:                tgt = *((int *) arg);
        !           695:                bus = (tgt >> 16) & 0xffff;
        !           696:                tgt &= 0xffff;
        !           697:                sdp += bus;
        !           698:                flags = sdp->isp_devparam[tgt].actv_flags;
        !           699:                period = sdp->isp_devparam[tgt].actv_period;
        !           700:
        !           701:                if ((flags & DPARM_SYNC) && period &&
        !           702:                    (sdp->isp_devparam[tgt].actv_offset) != 0) {
        !           703:                        /*
        !           704:                         * There's some ambiguity about our negotiated speed
        !           705:                         * if we haven't detected LVD mode correctly (which
        !           706:                         * seems to happen, unfortunately). If we're in LVD
        !           707:                         * mode, then different rules apply about speed.
        !           708:                         */
        !           709:                        if (sdp->isp_lvdmode || period < 0xc) {
        !           710:                                switch (period) {
        !           711:                                case 0x9:
        !           712:                                        mhz = 80;
        !           713:                                        break;
        !           714:                                case 0xa:
        !           715:                                        mhz = 40;
        !           716:                                        break;
        !           717:                                case 0xb:
        !           718:                                        mhz = 33;
        !           719:                                        break;
        !           720:                                case 0xc:
        !           721:                                        mhz = 25;
        !           722:                                        break;
        !           723:                                default:
        !           724:                                        mhz = 1000 / (period * 4);
        !           725:                                        break;
        !           726:                                }
        !           727:                        } else {
        !           728:                                mhz = 1000 / (period * 4);
        !           729:                        }
        !           730:                } else {
        !           731:                        mhz = 0;
        !           732:                }
        !           733:                switch (flags & (DPARM_WIDE|DPARM_TQING)) {
        !           734:                case DPARM_WIDE:
        !           735:                        wt = ", 16 bit wide";
        !           736:                        break;
        !           737:                case DPARM_TQING:
        !           738:                        wt = ", Tagged Queueing Enabled";
        !           739:                        break;
        !           740:                case DPARM_WIDE|DPARM_TQING:
        !           741:                        wt = ", 16 bit wide, Tagged Queueing Enabled";
        !           742:                        break;
        !           743:                default:
        !           744:                        wt = " ";
        !           745:                        break;
        !           746:                }
        !           747:                if (mhz) {
        !           748:                        isp_prt(isp, ISP_LOGINFO,
        !           749:                            "Bus %d Target %d at %dMHz Max Offset %d%s",
        !           750:                            bus, tgt, mhz, sdp->isp_devparam[tgt].actv_offset,
        !           751:                            wt);
        !           752:                } else {
        !           753:                        isp_prt(isp, ISP_LOGINFO,
        !           754:                            "Bus %d Target %d Async Mode%s", bus, tgt, wt);
        !           755:                }
        !           756:                break;
        !           757:        }
        !           758:        case ISPASYNC_BUS_RESET:
        !           759:                if (arg)
        !           760:                        bus = *((int *) arg);
        !           761:                else
        !           762:                        bus = 0;
        !           763:                isp_prt(isp, ISP_LOGINFO, "SCSI bus %d reset detected", bus);
        !           764:                break;
        !           765:        case ISPASYNC_LOOP_DOWN:
        !           766:                /*
        !           767:                 * Hopefully we get here in time to minimize the number
        !           768:                 * of commands we are firing off that are sure to die.
        !           769:                 */
        !           770:                isp->isp_osinfo.blocked |= 1;
        !           771:                isp_prt(isp, ISP_LOGINFO, "Loop DOWN");
        !           772:                break;
        !           773:         case ISPASYNC_LOOP_UP:
        !           774:                isp->isp_osinfo.blocked &= ~1;
        !           775:                if (isp->isp_osinfo.rtpend == 0) {
        !           776:                        timeout_set(&isp->isp_osinfo.rqt, isp_trestart, isp);
        !           777:                        isp->isp_osinfo.rtpend = 1;
        !           778:                }
        !           779:                timeout_add(&isp->isp_osinfo.rqt, 1);
        !           780:                isp_prt(isp, ISP_LOGINFO, "Loop UP");
        !           781:                break;
        !           782:        case ISPASYNC_PROMENADE:
        !           783:        if (IS_FC(isp) && isp->isp_dblev) {
        !           784:                const char *fmt = "Target %d (Loop 0x%x) Port ID 0x%x "
        !           785:                    "role %s %s\n Port WWN 0x%08x%08x\n Node WWN 0x%08x%08x";
        !           786:                const static char *roles[4] = {
        !           787:                    "No", "Target", "Initiator", "Target/Initiator"
        !           788:                };
        !           789:                fcparam *fcp = isp->isp_param;
        !           790:                int tgt = *((int *) arg);
        !           791:                struct lportdb *lp = &fcp->portdb[tgt];
        !           792:
        !           793:                isp_prt(isp, ISP_LOGINFO, fmt, tgt, lp->loopid, lp->portid,
        !           794:                    roles[lp->roles & 0x3],
        !           795:                    (lp->valid)? "Arrived" : "Departed",
        !           796:                    (u_int32_t) (lp->port_wwn >> 32),
        !           797:                    (u_int32_t) (lp->port_wwn & 0xffffffffLL),
        !           798:                    (u_int32_t) (lp->node_wwn >> 32),
        !           799:                    (u_int32_t) (lp->node_wwn & 0xffffffffLL));
        !           800:                break;
        !           801:        }
        !           802:        case ISPASYNC_CHANGE_NOTIFY:
        !           803:                if (arg == (void *) 1) {
        !           804:                        isp_prt(isp, ISP_LOGINFO,
        !           805:                            "Name Server Database Changed");
        !           806:                } else {
        !           807:                        isp_prt(isp, ISP_LOGINFO,
        !           808:                            "Name Server Database Changed");
        !           809:                }
        !           810:                break;
        !           811:        case ISPASYNC_FABRIC_DEV:
        !           812:        {
        !           813:                int target, base, lim;
        !           814:                fcparam *fcp = isp->isp_param;
        !           815:                struct lportdb *lp = NULL;
        !           816:                struct lportdb *clp = (struct lportdb *) arg;
        !           817:                char *pt;
        !           818:
        !           819:                switch (clp->port_type) {
        !           820:                case 1:
        !           821:                        pt = "   N_Port";
        !           822:                        break;
        !           823:                case 2:
        !           824:                        pt = "  NL_Port";
        !           825:                        break;
        !           826:                case 3:
        !           827:                        pt = "F/NL_Port";
        !           828:                        break;
        !           829:                case 0x7f:
        !           830:                        pt = "  Nx_Port";
        !           831:                        break;
        !           832:                case 0x81:
        !           833:                        pt = "  F_port";
        !           834:                        break;
        !           835:                case 0x82:
        !           836:                        pt = "  FL_Port";
        !           837:                        break;
        !           838:                case 0x84:
        !           839:                        pt = "   E_port";
        !           840:                        break;
        !           841:                default:
        !           842:                        pt = " ";
        !           843:                        break;
        !           844:                }
        !           845:
        !           846:                isp_prt(isp, ISP_LOGINFO,
        !           847:                    "%s Fabric Device @ PortID 0x%x", pt, clp->portid);
        !           848:
        !           849:                /*
        !           850:                 * If we don't have an initiator role we bail.
        !           851:                 *
        !           852:                 * We just use ISPASYNC_FABRIC_DEV for announcement purposes.
        !           853:                 */
        !           854:
        !           855:                if ((isp->isp_role & ISP_ROLE_INITIATOR) == 0) {
        !           856:                        break;
        !           857:                }
        !           858:
        !           859:                /*
        !           860:                 * Is this entry for us? If so, we bail.
        !           861:                 */
        !           862:
        !           863:                if (fcp->isp_portid == clp->portid) {
        !           864:                        break;
        !           865:                }
        !           866:
        !           867:                /*
        !           868:                 * Else, the default policy is to find room for it in
        !           869:                 * our local port database. Later, when we execute
        !           870:                 * the call to isp_pdb_sync either this newly arrived
        !           871:                 * or already logged in device will be (re)announced.
        !           872:                 */
        !           873:
        !           874:                if (fcp->isp_topo == TOPO_FL_PORT)
        !           875:                        base = FC_SNS_ID+1;
        !           876:                else
        !           877:                        base = 0;
        !           878:
        !           879:                if (fcp->isp_topo == TOPO_N_PORT)
        !           880:                        lim = 1;
        !           881:                else
        !           882:                        lim = MAX_FC_TARG;
        !           883:
        !           884:                /*
        !           885:                 * Is it already in our list?
        !           886:                 */
        !           887:                for (target = base; target < lim; target++) {
        !           888:                        if (target >= FL_PORT_ID && target <= FC_SNS_ID) {
        !           889:                                continue;
        !           890:                        }
        !           891:                        lp = &fcp->portdb[target];
        !           892:                        if (lp->port_wwn == clp->port_wwn &&
        !           893:                            lp->node_wwn == clp->node_wwn) {
        !           894:                                lp->fabric_dev = 1;
        !           895:                                break;
        !           896:                        }
        !           897:                }
        !           898:                if (target < lim) {
        !           899:                        break;
        !           900:                }
        !           901:                for (target = base; target < lim; target++) {
        !           902:                        if (target >= FL_PORT_ID && target <= FC_SNS_ID) {
        !           903:                                continue;
        !           904:                        }
        !           905:                        lp = &fcp->portdb[target];
        !           906:                        if (lp->port_wwn == 0) {
        !           907:                                break;
        !           908:                        }
        !           909:                }
        !           910:                if (target == lim) {
        !           911:                        isp_prt(isp, ISP_LOGWARN,
        !           912:                            "out of space for fabric devices");
        !           913:                        break;
        !           914:                }
        !           915:                lp->port_type = clp->port_type;
        !           916:                lp->fc4_type = clp->fc4_type;
        !           917:                lp->node_wwn = clp->node_wwn;
        !           918:                lp->port_wwn = clp->port_wwn;
        !           919:                lp->portid = clp->portid;
        !           920:                lp->fabric_dev = 1;
        !           921:                break;
        !           922:        }
        !           923:        case ISPASYNC_FW_CRASH:
        !           924:        {
        !           925:                u_int16_t mbox1, mbox6;
        !           926:                mbox1 = ISP_READ(isp, OUTMAILBOX1);
        !           927:                if (IS_DUALBUS(isp)) {
        !           928:                        mbox6 = ISP_READ(isp, OUTMAILBOX6);
        !           929:                } else {
        !           930:                        mbox6 = 0;
        !           931:                }
        !           932:                 isp_prt(isp, ISP_LOGERR,
        !           933:                     "Internal Firmware Error on bus %d @ RISC Address 0x%x",
        !           934:                     mbox6, mbox1);
        !           935: #ifdef ISP_FW_CRASH_DUMP
        !           936:                if (IS_FC(isp)) {
        !           937:                        isp->isp_osinfo.blocked |= 1;
        !           938:                        isp_fw_dump(isp);
        !           939:                }
        !           940:                isp_reinit(isp);
        !           941:                isp_async(isp, ISPASYNC_FW_RESTART, NULL);
        !           942: #endif
        !           943:                break;
        !           944:        }
        !           945:        default:
        !           946:                break;
        !           947:        }
        !           948:        return (0);
        !           949: }
        !           950:
        !           951: void
        !           952: isp_prt(struct ispsoftc *isp, int level, const char *fmt, ...)
        !           953: {
        !           954:        va_list ap;
        !           955:        if (level != ISP_LOGALL && (level & isp->isp_dblev) == 0) {
        !           956:                return;
        !           957:        }
        !           958:        printf("%s: ", isp->isp_name);
        !           959:        va_start(ap, fmt);
        !           960:        vprintf(fmt, ap);
        !           961:        va_end(ap);
        !           962:        printf("\n");
        !           963: }

CVSweb