[BACK]Return to mscp.c CVS log [TXT][DIR] Up to [local] / sys / arch / vax / mscp

Annotation of sys/arch/vax/mscp/mscp.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: mscp.c,v 1.9 2005/11/24 04:53:56 brad Exp $   */
        !             2: /*     $NetBSD: mscp.c,v 1.16 2001/11/13 07:38:28 lukem Exp $  */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1996 Ludd, University of Lule}, Sweden.
        !             6:  * Copyright (c) 1988 Regents of the University of California.
        !             7:  * All rights reserved.
        !             8:  *
        !             9:  * This code is derived from software contributed to Berkeley by
        !            10:  * Chris Torek.
        !            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. Neither the name of the University nor the names of its contributors
        !            21:  *    may be used to endorse or promote products derived from this software
        !            22:  *    without specific prior written permission.
        !            23:  *
        !            24:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            25:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            34:  * SUCH DAMAGE.
        !            35:  *
        !            36:  *     @(#)mscp.c      7.5 (Berkeley) 12/16/90
        !            37:  */
        !            38:
        !            39: /*
        !            40:  * MSCP generic driver routines
        !            41:  */
        !            42:
        !            43: #include <sys/cdefs.h>
        !            44:
        !            45: #include <sys/param.h>
        !            46: #include <sys/buf.h>
        !            47: #include <sys/malloc.h>
        !            48: #include <sys/device.h>
        !            49: #include <sys/proc.h>
        !            50: #include <sys/systm.h>
        !            51:
        !            52: #include <machine/bus.h>
        !            53:
        !            54: #include <arch/vax/mscp/mscp.h>
        !            55: #include <arch/vax/mscp/mscpreg.h>
        !            56: #include <arch/vax/mscp/mscpvar.h>
        !            57:
        !            58: #define PCMD   PSWP            /* priority for command packet waits */
        !            59:
        !            60: /*
        !            61:  * Get a command packet.  Second argument is true iff we are
        !            62:  * to wait if necessary.  Return NULL if none are available and
        !            63:  * we cannot wait.
        !            64:  */
        !            65: struct mscp *
        !            66: mscp_getcp(mi, canwait)
        !            67:        struct mscp_softc *mi;
        !            68:        int canwait;
        !            69: {
        !            70: #define mri    (&mi->mi_cmd)
        !            71:        struct mscp *mp;
        !            72:        int i;
        !            73:        int s = splbio();
        !            74:
        !            75: again:
        !            76:        /*
        !            77:         * Ensure that we have some command credits, and
        !            78:         * that the next command packet is free.
        !            79:         */
        !            80:        if (mi->mi_credits <= MSCP_MINCREDITS) {
        !            81:                if (!canwait) {
        !            82:                        splx(s);
        !            83:                        return (NULL);
        !            84:                }
        !            85:                mi->mi_wantcredits = 1;
        !            86:                (void) tsleep(&mi->mi_wantcredits, PCMD, "mscpwcrd", 0);
        !            87:                goto again;
        !            88:        }
        !            89:        i = mri->mri_next;
        !            90:        if (mri->mri_desc[i] & MSCP_OWN) {
        !            91:                if (!canwait) {
        !            92:                        splx(s);
        !            93:                        return (NULL);
        !            94:                }
        !            95:                mi->mi_wantcmd = 1;
        !            96:                (void) tsleep(&mi->mi_wantcmd, PCMD, "mscpwcmd", 0);
        !            97:                goto again;
        !            98:        }
        !            99:        mi->mi_credits--;
        !           100:        mri->mri_desc[i] &= ~MSCP_INT;
        !           101:        mri->mri_next = (mri->mri_next + 1) % mri->mri_size;
        !           102:        splx(s);
        !           103:        mp = &mri->mri_ring[i];
        !           104:
        !           105:        /*
        !           106:         * Initialise some often-zero fields.
        !           107:         * ARE THE LAST TWO NECESSARY IN GENERAL?  IT SURE WOULD BE
        !           108:         * NICE IF DEC SOLD DOCUMENTATION FOR THEIR OWN CONTROLLERS.
        !           109:         */
        !           110:        mp->mscp_msglen = MSCP_MSGLEN;
        !           111:        mp->mscp_flags = 0;
        !           112:        mp->mscp_modifier = 0;
        !           113:        mp->mscp_seq.seq_bytecount = 0;
        !           114:        mp->mscp_seq.seq_buffer = 0;
        !           115:        mp->mscp_seq.seq_mapbase = 0;
        !           116: /*???*/ mp->mscp_sccc.sccc_errlgfl = 0;
        !           117: /*???*/ mp->mscp_sccc.sccc_copyspd = 0;
        !           118:        return (mp);
        !           119: #undef mri
        !           120: }
        !           121:
        !           122: #ifdef AVOID_EMULEX_BUG
        !           123: int    mscp_aeb_xor = 0x8000bb80;
        !           124: #endif
        !           125:
        !           126: /*
        !           127:  * Handle a response ring transition.
        !           128:  */
        !           129: void
        !           130: mscp_dorsp(mi)
        !           131:        struct mscp_softc *mi;
        !           132: {
        !           133:        struct device *drive;
        !           134:        struct mscp_device *me = mi->mi_me;
        !           135:        struct mscp_ctlr *mc = mi->mi_mc;
        !           136:        struct buf *bp;
        !           137:        struct mscp *mp;
        !           138:        struct mscp_xi *mxi;
        !           139:        int nextrsp;
        !           140:        int st, error;
        !           141:        extern int cold;
        !           142:        extern struct mscp slavereply;
        !           143:
        !           144:        nextrsp = mi->mi_rsp.mri_next;
        !           145: loop:
        !           146:        if (mi->mi_rsp.mri_desc[nextrsp] & MSCP_OWN) {
        !           147:                /*
        !           148:                 * No more responses.  Remember the next expected
        !           149:                 * response index.  Check to see if we have some
        !           150:                 * credits back, and wake up sleepers if so.
        !           151:                 */
        !           152:                mi->mi_rsp.mri_next = nextrsp;
        !           153:                if (mi->mi_wantcredits && mi->mi_credits > MSCP_MINCREDITS) {
        !           154:                        mi->mi_wantcredits = 0;
        !           155:                        wakeup((caddr_t) &mi->mi_wantcredits);
        !           156:                }
        !           157:                return;
        !           158:        }
        !           159:
        !           160:        mp = &mi->mi_rsp.mri_ring[nextrsp];
        !           161:        mi->mi_credits += MSCP_CREDITS(mp->mscp_msgtc);
        !           162:        /*
        !           163:         * Controllers are allowed to interrupt as any drive, so we
        !           164:         * must check the command before checking for a drive.
        !           165:         */
        !           166:        if (mp->mscp_opcode == (M_OP_SETCTLRC | M_OP_END)) {
        !           167:                if ((mp->mscp_status & M_ST_MASK) == M_ST_SUCCESS) {
        !           168:                        mi->mi_flags |= MSC_READY;
        !           169:                } else {
        !           170:                        printf("%s: SETCTLRC failed: %d ",
        !           171:                            mi->mi_dev.dv_xname, mp->mscp_status);
        !           172:                        mscp_printevent(mp);
        !           173:                }
        !           174:                goto done;
        !           175:        }
        !           176:
        !           177:        /*
        !           178:         * Found a response.  Update credit information.  If there is
        !           179:         * nothing else to do, jump to `done' to get the next response.
        !           180:         */
        !           181:        if (mp->mscp_unit >= mi->mi_driveno) { /* Must expand drive table */
        !           182:                int tmpno = ((mp->mscp_unit + 32) & 0xffe0) * sizeof(void *);
        !           183:                struct device **tmp = (struct device **)
        !           184:                    malloc(tmpno, M_DEVBUF, M_NOWAIT);
        !           185:                if (tmp == NULL)
        !           186:                        panic("mscp_dorsp");
        !           187:                bzero(tmp, tmpno);
        !           188:                if (mi->mi_driveno) {
        !           189:                        bcopy(mi->mi_dp, tmp, mi->mi_driveno);
        !           190:                        free(mi->mi_dp, mi->mi_driveno);
        !           191:                }
        !           192:                mi->mi_driveno = tmpno;
        !           193:                mi->mi_dp = tmp;
        !           194:        }
        !           195:
        !           196:        drive = mi->mi_dp[mp->mscp_unit];
        !           197:
        !           198:        switch (MSCP_MSGTYPE(mp->mscp_msgtc)) {
        !           199:
        !           200:        case MSCPT_SEQ:
        !           201:                break;
        !           202:
        !           203:        case MSCPT_DATAGRAM:
        !           204:                (*me->me_dgram)(drive, mp, mi);
        !           205:                goto done;
        !           206:
        !           207:        case MSCPT_CREDITS:
        !           208:                goto done;
        !           209:
        !           210:        case MSCPT_MAINTENANCE:
        !           211:        default:
        !           212:                printf("%s: unit %d: unknown message type 0x%x ignored\n",
        !           213:                        mi->mi_dev.dv_xname, mp->mscp_unit,
        !           214:                        MSCP_MSGTYPE(mp->mscp_msgtc));
        !           215:                goto done;
        !           216:        }
        !           217:
        !           218:        /*
        !           219:         * Handle individual responses.
        !           220:         */
        !           221:        st = mp->mscp_status & M_ST_MASK;
        !           222:        error = 0;
        !           223:        switch (mp->mscp_opcode) {
        !           224:
        !           225:        case M_OP_END:
        !           226:                /*
        !           227:                 * The controller presents a bogus END packet when
        !           228:                 * a read/write command is given with an illegal
        !           229:                 * block number.  This is contrary to the MSCP
        !           230:                 * specification (ENDs are to be given only for
        !           231:                 * invalid commands), but that is the way of it.
        !           232:                 */
        !           233:                if (st == M_ST_INVALCMD && mp->mscp_cmdref != 0) {
        !           234:                        printf("%s: bad lbn (%d)?\n", drive->dv_xname,
        !           235:                                (int)mp->mscp_seq.seq_lbn);
        !           236:                        error = EIO;
        !           237:                        goto rwend;
        !           238:                }
        !           239:                goto unknown;
        !           240:
        !           241:        case M_OP_ONLINE | M_OP_END:
        !           242:                /*
        !           243:                 * Finished an ON LINE request.  Call the driver to
        !           244:                 * find out whether it succeeded.  If so, mark it on
        !           245:                 * line.
        !           246:                 */
        !           247:                (*me->me_online)(drive, mp);
        !           248:                break;
        !           249:
        !           250:        case M_OP_GETUNITST | M_OP_END:
        !           251:                /*
        !           252:                 * Got unit status.  If we are autoconfiguring, save
        !           253:                 * the mscp struct so that mscp_attach know what to do.
        !           254:                 * If the drive isn't configured, call config_found()
        !           255:                 * to set it up, otherwise it's just a "normal" unit
        !           256:                 * status.
        !           257:                 */
        !           258:                if (cold)
        !           259:                        bcopy(mp, &slavereply, sizeof(struct mscp));
        !           260:
        !           261:                if (mp->mscp_status == (M_ST_OFFLINE|M_OFFLINE_UNKNOWN))
        !           262:                        break;
        !           263:
        !           264:                if (drive == 0) {
        !           265:                        struct  drive_attach_args da;
        !           266:
        !           267:                        da.da_mp = (struct mscp *)mp;
        !           268:                        da.da_typ = mi->mi_type;
        !           269:                        config_found(&mi->mi_dev, (void *)&da, mscp_print);
        !           270:                } else
        !           271:                        /* Hack to avoid complaints */
        !           272:                        if (!(((mp->mscp_event & M_ST_MASK) == M_ST_AVAILABLE)
        !           273:                            && cold))
        !           274:                                (*me->me_gotstatus)(drive, mp);
        !           275:                break;
        !           276:
        !           277:        case M_OP_AVAILATTN:
        !           278:                /*
        !           279:                 * The drive went offline and we did not notice.
        !           280:                 * Mark it off line now, to force an on line request
        !           281:                 * next, so we can make sure it is still the same
        !           282:                 * drive.
        !           283:                 *
        !           284:                 * IF THE UDA DRIVER HAS A COMMAND AWAITING UNIBUS
        !           285:                 * RESOURCES, THAT COMMAND MAY GO OUT BEFORE THE ON
        !           286:                 * LINE.  IS IT WORTH FIXING??
        !           287:                 */
        !           288: #ifdef notyet
        !           289:                (*md->md_offline)(ui, mp);
        !           290: #endif
        !           291:                break;
        !           292:
        !           293:        case M_OP_POS | M_OP_END:
        !           294:        case M_OP_WRITM | M_OP_END:
        !           295:        case M_OP_AVAILABLE | M_OP_END:
        !           296:                /*
        !           297:                 * A non-data transfer operation completed.
        !           298:                 */
        !           299:                (*me->me_cmddone)(drive, mp);
        !           300:                break;
        !           301:
        !           302:        case M_OP_READ | M_OP_END:
        !           303:        case M_OP_WRITE | M_OP_END:
        !           304:                /*
        !           305:                 * A transfer finished.  Get the buffer, and release its
        !           306:                 * map registers via ubadone().  If the command finished
        !           307:                 * with an off line or available status, the drive went
        !           308:                 * off line (the idiot controller does not tell us until
        !           309:                 * it comes back *on* line, or until we try to use it).
        !           310:                 */
        !           311: rwend:
        !           312: #ifdef DIAGNOSTIC
        !           313:                if (mp->mscp_cmdref >= NCMD) {
        !           314:                        /*
        !           315:                         * No buffer means there is a bug somewhere!
        !           316:                         */
        !           317:                        printf("%s: io done, but bad xfer number?\n",
        !           318:                            drive->dv_xname);
        !           319:                        mscp_hexdump(mp);
        !           320:                        break;
        !           321:                }
        !           322: #endif
        !           323:
        !           324:                if (mp->mscp_cmdref == -1) {
        !           325:                        (*me->me_cmddone)(drive, mp);
        !           326:                        break;
        !           327:                }
        !           328:                mxi = &mi->mi_xi[mp->mscp_cmdref];
        !           329:                if (mxi->mxi_inuse == 0)
        !           330:                        panic("mxi not inuse");
        !           331:                bp = mxi->mxi_bp;
        !           332:                /*
        !           333:                 * Mark any error-due-to-bad-LBN (via `goto rwend').
        !           334:                 * WHAT STATUS WILL THESE HAVE?  IT SURE WOULD BE NICE
        !           335:                 * IF DEC SOLD DOCUMENTATION FOR THEIR OWN CONTROLLERS.
        !           336:                 */
        !           337:                if (error) {
        !           338:                        bp->b_flags |= B_ERROR;
        !           339:                        bp->b_error = error;
        !           340:                }
        !           341:                if (st == M_ST_OFFLINE || st == M_ST_AVAILABLE) {
        !           342: #ifdef notyet
        !           343:                        (*md->md_offline)(ui, mp);
        !           344: #endif
        !           345:                }
        !           346:
        !           347:                /*
        !           348:                 * If the transfer has something to do with bad
        !           349:                 * block forwarding, let the driver handle the
        !           350:                 * rest.
        !           351:                 */
        !           352:                if ((bp->b_flags & B_BAD) != 0 && me->me_bb != NULL) {
        !           353:                        (*me->me_bb)(drive, mp, bp);
        !           354:                        goto out;
        !           355:                }
        !           356:
        !           357:                /*
        !           358:                 * If the transfer failed, give the driver a crack
        !           359:                 * at fixing things up.
        !           360:                 */
        !           361:                if (st != M_ST_SUCCESS) {
        !           362:                        switch ((*me->me_ioerr)(drive, mp, bp)) {
        !           363:
        !           364:                        case MSCP_DONE:         /* fixed */
        !           365:                                break;
        !           366:
        !           367:                        case MSCP_RESTARTED:    /* still working on it */
        !           368:                                goto out;
        !           369:
        !           370:                        case MSCP_FAILED:       /* no luck */
        !           371:                                /* XXX must move to ra.c */
        !           372:                                mscp_printevent(mp);
        !           373:                                break;
        !           374:                        }
        !           375:                }
        !           376:
        !           377:                /*
        !           378:                 * Set the residual count and mark the transfer as
        !           379:                 * done.  If the I/O wait queue is now empty, release
        !           380:                 * the shared BDP, if any.
        !           381:                 */
        !           382:                bp->b_resid = bp->b_bcount - mp->mscp_seq.seq_bytecount;
        !           383:                bus_dmamap_unload(mi->mi_dmat, mxi->mxi_dmam);
        !           384:
        !           385:                (*mc->mc_ctlrdone)(mi->mi_dev.dv_parent);
        !           386:                (*me->me_iodone)(drive, bp);
        !           387: out:
        !           388:                mxi->mxi_inuse = 0;
        !           389:                mi->mi_mxiuse |= (1 << mp->mscp_cmdref);
        !           390:                break;
        !           391:
        !           392:        case M_OP_REPLACE | M_OP_END:
        !           393:                /*
        !           394:                 * A replace operation finished.  Just let the driver
        !           395:                 * handle it (if it does replaces).
        !           396:                 */
        !           397:                if (me->me_replace == NULL)
        !           398:                        printf("%s: bogus REPLACE end\n", drive->dv_xname);
        !           399:                else
        !           400:                        (*me->me_replace)(drive, mp);
        !           401:                break;
        !           402:
        !           403:        default:
        !           404:                /*
        !           405:                 * If it is not one of the above, we cannot handle it.
        !           406:                 * (And we should not have received it, for that matter.)
        !           407:                 */
        !           408: unknown:
        !           409:                printf("%s: unknown opcode 0x%x status 0x%x ignored\n",
        !           410:                        drive->dv_xname, mp->mscp_opcode, mp->mscp_status);
        !           411: #ifdef DIAGNOSTIC
        !           412:                mscp_hexdump(mp);
        !           413: #endif
        !           414:                break;
        !           415:        }
        !           416:
        !           417:        /*
        !           418:         * If the drive needs to be put back in the controller queue,
        !           419:         * do that now.  (`bp' below ought to be `dp', but they are all
        !           420:         * struct buf *.)  Note that b_active was cleared in the driver;
        !           421:         * we presume that there is something to be done, hence reassert it.
        !           422:         */
        !           423: #ifdef notyet /* XXX */
        !           424:        if (ui->ui_flags & UNIT_REQUEUE) {
        !           425:                ...
        !           426:        }
        !           427: #endif
        !           428: done:
        !           429:        /*
        !           430:         * Give back the response packet, and take a look at the next.
        !           431:         */
        !           432:        mp->mscp_msglen = MSCP_MSGLEN;
        !           433:        mi->mi_rsp.mri_desc[nextrsp] |= MSCP_OWN;
        !           434:        nextrsp = (nextrsp + 1) % mi->mi_rsp.mri_size;
        !           435:        goto loop;
        !           436: }
        !           437:
        !           438: /*
        !           439:  * Requeue outstanding transfers, e.g., after bus reset.
        !           440:  * Also requeue any drives that have on line or unit status
        !           441:  * info pending.
        !           442:  */
        !           443: void
        !           444: mscp_requeue(mi)
        !           445:        struct mscp_softc *mi;
        !           446: {
        !           447:        panic("mscp_requeue");
        !           448: }
        !           449:

CVSweb