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

Annotation of sys/dev/ic/uha.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: uha.c,v 1.9 2006/11/28 23:59:45 dlg Exp $     */
                      2: /*     $NetBSD: uha.c,v 1.3 1996/10/13 01:37:29 christos Exp $ */
                      3:
                      4: #undef UHADEBUG
                      5: #ifdef DDB
                      6: #define        integrate
                      7: #else
                      8: #define        integrate       static inline
                      9: #endif
                     10:
                     11: /*
                     12:  * Copyright (c) 1994, 1996 Charles M. Hannum.  All rights reserved.
                     13:  *
                     14:  * Redistribution and use in source and binary forms, with or without
                     15:  * modification, are permitted provided that the following conditions
                     16:  * are met:
                     17:  * 1. Redistributions of source code must retain the above copyright
                     18:  *    notice, this list of conditions and the following disclaimer.
                     19:  * 2. Redistributions in binary form must reproduce the above copyright
                     20:  *    notice, this list of conditions and the following disclaimer in the
                     21:  *    documentation and/or other materials provided with the distribution.
                     22:  * 3. All advertising materials mentioning features or use of this software
                     23:  *    must display the following acknowledgement:
                     24:  *     This product includes software developed by Charles M. Hannum.
                     25:  * 4. The name of the author may not be used to endorse or promote products
                     26:  *    derived from this software without specific prior written permission.
                     27:  *
                     28:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     29:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     30:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     31:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     32:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     33:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     34:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     35:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     36:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     37:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     38:  */
                     39:
                     40: /*
                     41:  * Ported for use with the UltraStor 14f by Gary Close (gclose@wvnvms.wvnet.edu)
                     42:  * Slight fixes to timeouts to run with the 34F
                     43:  * Thanks to Julian Elischer for advice and help with this port.
                     44:  *
                     45:  * Originally written by Julian Elischer (julian@tfs.com)
                     46:  * for TRW Financial Systems for use under the MACH(2.5) operating system.
                     47:  *
                     48:  * TRW Financial Systems, in accordance with their agreement with Carnegie
                     49:  * Mellon University, makes this software available to CMU to distribute
                     50:  * or use in any manner that they see fit as long as this message is kept with
                     51:  * the software. For this reason TFS also grants any other persons or
                     52:  * organisations permission to use or modify this software.
                     53:  *
                     54:  * TFS supplies this software to be publicly redistributed
                     55:  * on the understanding that TFS is not responsible for the correct
                     56:  * functioning of this software in any circumstances.
                     57:  *
                     58:  * commenced: Sun Sep 27 18:14:01 PDT 1992
                     59:  * slight mod to make work with 34F as well: Wed Jun  2 18:05:48 WST 1993
                     60:  */
                     61:
                     62: #include <sys/types.h>
                     63: #include <sys/param.h>
                     64: #include <sys/systm.h>
                     65: #include <sys/kernel.h>
                     66: #include <sys/errno.h>
                     67: #include <sys/ioctl.h>
                     68: #include <sys/device.h>
                     69: #include <sys/malloc.h>
                     70: #include <sys/buf.h>
                     71: #include <sys/proc.h>
                     72: #include <sys/user.h>
                     73:
                     74: #include <machine/bus.h>
                     75: #include <machine/intr.h>
                     76:
                     77: #include <scsi/scsi_all.h>
                     78: #include <scsi/scsiconf.h>
                     79:
                     80: #include <dev/ic/uhareg.h>
                     81: #include <dev/ic/uhavar.h>
                     82:
                     83: #ifndef        DDB
                     84: #define Debugger() panic("should call debugger here (ultra14f.c)")
                     85: #endif /* ! DDB */
                     86:
                     87: #define KVTOPHYS(x)    vtophys((vaddr_t)x)
                     88:
                     89: integrate void uha_reset_mscp(struct uha_softc *, struct uha_mscp *);
                     90: void uha_free_mscp(struct uha_softc *, struct uha_mscp *);
                     91: integrate void uha_init_mscp(struct uha_softc *, struct uha_mscp *);
                     92: struct uha_mscp *uha_get_mscp(struct uha_softc *, int);
                     93: void uhaminphys(struct buf *);
                     94: int uha_scsi_cmd(struct scsi_xfer *);
                     95:
                     96: struct scsi_adapter uha_switch = {
                     97:        uha_scsi_cmd,
                     98:        uhaminphys,
                     99:        0,
                    100:        0,
                    101: };
                    102:
                    103: /* the below structure is so we have a default dev struct for out link struct */
                    104: struct scsi_device uha_dev = {
                    105:        NULL,                   /* Use default error handler */
                    106:        NULL,                   /* have a queue, served by this */
                    107:        NULL,                   /* have no async handler */
                    108:        NULL,                   /* Use default 'done' routine */
                    109: };
                    110:
                    111: struct cfdriver uha_cd = {
                    112:        NULL, "uha", DV_DULL
                    113: };
                    114:
                    115: #define        UHA_ABORT_TIMEOUT       2000    /* time to wait for abort (mSec) */
                    116:
                    117: #ifdef __OpenBSD__
                    118: int    uhaprint(void *, const char *);
                    119:
                    120: int
                    121: uhaprint(aux, name)
                    122:        void *aux;
                    123:        const char *name;
                    124: {
                    125:
                    126:        if (name != NULL)
                    127:                printf("%s: scsibus ", name);
                    128:        return UNCONF;
                    129: }
                    130: #endif
                    131:
                    132: /*
                    133:  * Attach all the sub-devices we can find
                    134:  */
                    135: void
                    136: uha_attach(sc)
                    137:        struct uha_softc *sc;
                    138: {
                    139:        struct scsibus_attach_args saa;
                    140:
                    141:        (sc->init)(sc);
                    142:        TAILQ_INIT(&sc->sc_free_mscp);
                    143:
                    144:        /*
                    145:         * fill in the prototype scsi_link.
                    146:         */
                    147:        sc->sc_link.adapter_softc = sc;
                    148:        sc->sc_link.adapter_target = sc->sc_scsi_dev;
                    149:        sc->sc_link.adapter = &uha_switch;
                    150:        sc->sc_link.device = &uha_dev;
                    151:        sc->sc_link.openings = 2;
                    152:
                    153:        bzero(&saa, sizeof(saa));
                    154:        saa.saa_sc_link = &sc->sc_link;
                    155:
                    156:        /*
                    157:         * ask the adapter what subunits are present
                    158:         */
                    159:        config_found(&sc->sc_dev, &saa, uhaprint);
                    160: }
                    161:
                    162: integrate void
                    163: uha_reset_mscp(sc, mscp)
                    164:        struct uha_softc *sc;
                    165:        struct uha_mscp *mscp;
                    166: {
                    167:
                    168:        mscp->flags = 0;
                    169: }
                    170:
                    171: /*
                    172:  * A mscp (and hence a mbx-out) is put onto the free list.
                    173:  */
                    174: void
                    175: uha_free_mscp(sc, mscp)
                    176:        struct uha_softc *sc;
                    177:        struct uha_mscp *mscp;
                    178: {
                    179:        int s;
                    180:
                    181:        s = splbio();
                    182:
                    183:        uha_reset_mscp(sc, mscp);
                    184:        TAILQ_INSERT_HEAD(&sc->sc_free_mscp, mscp, chain);
                    185:
                    186:        /*
                    187:         * If there were none, wake anybody waiting for one to come free,
                    188:         * starting with queued entries.
                    189:         */
                    190:        if (TAILQ_NEXT(mscp, chain) == NULL)
                    191:                wakeup(&sc->sc_free_mscp);
                    192:
                    193:        splx(s);
                    194: }
                    195:
                    196: integrate void
                    197: uha_init_mscp(sc, mscp)
                    198:        struct uha_softc *sc;
                    199:        struct uha_mscp *mscp;
                    200: {
                    201:        int hashnum;
                    202:
                    203:        bzero(mscp, sizeof(struct uha_mscp));
                    204:        /*
                    205:         * put in the phystokv hash table
                    206:         * Never gets taken out.
                    207:         */
                    208:        mscp->hashkey = KVTOPHYS(mscp);
                    209:        hashnum = MSCP_HASH(mscp->hashkey);
                    210:        mscp->nexthash = sc->sc_mscphash[hashnum];
                    211:        sc->sc_mscphash[hashnum] = mscp;
                    212:        uha_reset_mscp(sc, mscp);
                    213: }
                    214:
                    215: /*
                    216:  * Get a free mscp
                    217:  *
                    218:  * If there are none, see if we can allocate a new one.  If so, put it in the
                    219:  * hash table too otherwise either return an error or sleep.
                    220:  */
                    221: struct uha_mscp *
                    222: uha_get_mscp(sc, flags)
                    223:        struct uha_softc *sc;
                    224:        int flags;
                    225: {
                    226:        struct uha_mscp *mscp;
                    227:        int s;
                    228:
                    229:        s = splbio();
                    230:
                    231:        /*
                    232:         * If we can and have to, sleep waiting for one to come free
                    233:         * but only if we can't allocate a new one
                    234:         */
                    235:        for (;;) {
                    236:                mscp = TAILQ_FIRST(&sc->sc_free_mscp);
                    237:                if (mscp) {
                    238:                        TAILQ_REMOVE(&sc->sc_free_mscp, mscp, chain);
                    239:                        break;
                    240:                }
                    241:                if (sc->sc_nummscps < UHA_MSCP_MAX) {
                    242:                        mscp = (struct uha_mscp *) malloc(sizeof(struct uha_mscp),
                    243:                            M_TEMP, M_NOWAIT);
                    244:                        if (!mscp) {
                    245:                                printf("%s: can't malloc mscp\n",
                    246:                                    sc->sc_dev.dv_xname);
                    247:                                goto out;
                    248:                        }
                    249:                        uha_init_mscp(sc, mscp);
                    250:                        sc->sc_nummscps++;
                    251:                        break;
                    252:                }
                    253:                if ((flags & SCSI_NOSLEEP) != 0)
                    254:                        goto out;
                    255:                tsleep(&sc->sc_free_mscp, PRIBIO, "uhamsc", 0);
                    256:        }
                    257:
                    258:        mscp->flags |= MSCP_ALLOC;
                    259:
                    260: out:
                    261:        splx(s);
                    262:        return (mscp);
                    263: }
                    264:
                    265: /*
                    266:  * given a physical address, find the mscp that it corresponds to.
                    267:  */
                    268: struct uha_mscp *
                    269: uha_mscp_phys_kv(sc, mscp_phys)
                    270:        struct uha_softc *sc;
                    271:        u_long mscp_phys;
                    272: {
                    273:        int hashnum = MSCP_HASH(mscp_phys);
                    274:        struct uha_mscp *mscp = sc->sc_mscphash[hashnum];
                    275:
                    276:        while (mscp) {
                    277:                if (mscp->hashkey == mscp_phys)
                    278:                        break;
                    279:                mscp = mscp->nexthash;
                    280:        }
                    281:        return (mscp);
                    282: }
                    283:
                    284: /*
                    285:  * We have a mscp which has been processed by the adaptor, now we look to see
                    286:  * how the operation went.
                    287:  */
                    288: void
                    289: uha_done(sc, mscp)
                    290:        struct uha_softc *sc;
                    291:        struct uha_mscp *mscp;
                    292: {
                    293:        struct scsi_sense_data *s1, *s2;
                    294:        struct scsi_xfer *xs = mscp->xs;
                    295:
                    296:        SC_DEBUG(xs->sc_link, SDEV_DB2, ("uha_done\n"));
                    297:        /*
                    298:         * Otherwise, put the results of the operation
                    299:         * into the xfer and call whoever started it
                    300:         */
                    301:        if ((mscp->flags & MSCP_ALLOC) == 0) {
                    302:                printf("%s: exiting ccb not allocated!\n", sc->sc_dev.dv_xname);
                    303:                Debugger();
                    304:                return;
                    305:        }
                    306:        if (xs->error == XS_NOERROR) {
                    307:                if (mscp->host_stat != UHA_NO_ERR) {
                    308:                        switch (mscp->host_stat) {
                    309:                        case UHA_SBUS_TIMEOUT:          /* No response */
                    310:                                xs->error = XS_SELTIMEOUT;
                    311:                                break;
                    312:                        default:        /* Other scsi protocol messes */
                    313:                                printf("%s: host_stat %x\n",
                    314:                                    sc->sc_dev.dv_xname, mscp->host_stat);
                    315:                                xs->error = XS_DRIVER_STUFFUP;
                    316:                        }
                    317:                } else if (mscp->target_stat != SCSI_OK) {
                    318:                        switch (mscp->target_stat) {
                    319:                        case SCSI_CHECK:
                    320:                                s1 = &mscp->mscp_sense;
                    321:                                s2 = &xs->sense;
                    322:                                *s2 = *s1;
                    323:                                xs->error = XS_SENSE;
                    324:                                break;
                    325:                        case SCSI_BUSY:
                    326:                                xs->error = XS_BUSY;
                    327:                                break;
                    328:                        default:
                    329:                                printf("%s: target_stat %x\n",
                    330:                                    sc->sc_dev.dv_xname, mscp->target_stat);
                    331:                                xs->error = XS_DRIVER_STUFFUP;
                    332:                        }
                    333:                } else
                    334:                        xs->resid = 0;
                    335:        }
                    336:        uha_free_mscp(sc, mscp);
                    337:        xs->flags |= ITSDONE;
                    338:        scsi_done(xs);
                    339: }
                    340:
                    341: void
                    342: uhaminphys(bp)
                    343:        struct buf *bp;
                    344: {
                    345:
                    346:        if (bp->b_bcount > ((UHA_NSEG - 1) << PGSHIFT))
                    347:                bp->b_bcount = ((UHA_NSEG - 1) << PGSHIFT);
                    348:        minphys(bp);
                    349: }
                    350:
                    351: /*
                    352:  * start a scsi operation given the command and the data address.  Also
                    353:  * needs the unit, target and lu.
                    354:  */
                    355: int
                    356: uha_scsi_cmd(xs)
                    357:        struct scsi_xfer *xs;
                    358: {
                    359:        struct scsi_link *sc_link = xs->sc_link;
                    360:        struct uha_softc *sc = sc_link->adapter_softc;
                    361:        struct uha_mscp *mscp;
                    362:        struct uha_dma_seg *sg;
                    363:        int seg;                /* scatter gather seg being worked on */
                    364:        u_long thiskv, thisphys, nextphys;
                    365:        int bytes_this_seg, bytes_this_page, datalen, flags;
                    366:        int s;
                    367:
                    368:        SC_DEBUG(sc_link, SDEV_DB2, ("uha_scsi_cmd\n"));
                    369:        /*
                    370:         * get a mscp (mbox-out) to use. If the transfer
                    371:         * is from a buf (possibly from interrupt time)
                    372:         * then we can't allow it to sleep
                    373:         */
                    374:        flags = xs->flags;
                    375:        if ((mscp = uha_get_mscp(sc, flags)) == NULL) {
                    376:                return (TRY_AGAIN_LATER);
                    377:        }
                    378:        mscp->xs = xs;
                    379:        mscp->timeout = xs->timeout;
                    380:        timeout_set(&xs->stimeout, uha_timeout, xs);
                    381:
                    382:        /*
                    383:         * Put all the arguments for the xfer in the mscp
                    384:         */
                    385:        if (flags & SCSI_RESET) {
                    386:                mscp->opcode = UHA_SDR;
                    387:                mscp->ca = 0x01;
                    388:        } else {
                    389:                mscp->opcode = UHA_TSP;
                    390:                /* XXX Not for tapes. */
                    391:                mscp->ca = 0x01;
                    392:                bcopy(xs->cmd, &mscp->scsi_cmd, mscp->scsi_cmd_length);
                    393:        }
                    394:        mscp->xdir = UHA_SDET;
                    395:        mscp->dcn = 0x00;
                    396:        mscp->chan = 0x00;
                    397:        mscp->target = sc_link->target;
                    398:        mscp->lun = sc_link->lun;
                    399:        mscp->scsi_cmd_length = xs->cmdlen;
                    400:        mscp->sense_ptr = KVTOPHYS(&mscp->mscp_sense);
                    401:        mscp->req_sense_length = sizeof(mscp->mscp_sense);
                    402:        mscp->host_stat = 0x00;
                    403:        mscp->target_stat = 0x00;
                    404:
                    405:        if (xs->datalen) {
                    406:                sg = mscp->uha_dma;
                    407:                seg = 0;
                    408: #ifdef TFS
                    409:                if (flags & SCSI_DATA_UIO) {
                    410:                        struct iovec *iovp;
                    411:                        iovp = ((struct uio *) xs->data)->uio_iov;
                    412:                        datalen = ((struct uio *) xs->data)->uio_iovcnt;
                    413:                        xs->datalen = 0;
                    414:                        while (datalen && seg < UHA_NSEG) {
                    415:                                sg->seg_addr = (physaddr)iovp->iov_base;
                    416:                                sg->seg_len = iovp->iov_len;
                    417:                                xs->datalen += iovp->iov_len;
                    418:                                SC_DEBUGN(sc_link, SDEV_DB4, ("(0x%x@0x%x)",
                    419:                                    iovp->iov_len, iovp->iov_base));
                    420:                                sg++;
                    421:                                iovp++;
                    422:                                seg++;
                    423:                                datalen--;
                    424:                        }
                    425:                } else
                    426: #endif /*TFS */
                    427:                {
                    428:                        /*
                    429:                         * Set up the scatter gather block
                    430:                         */
                    431:                        SC_DEBUG(sc_link, SDEV_DB4,
                    432:                            ("%d @0x%x:- ", xs->datalen, xs->data));
                    433:                        datalen = xs->datalen;
                    434:                        thiskv = (int) xs->data;
                    435:                        thisphys = KVTOPHYS(thiskv);
                    436:
                    437:                        while (datalen && seg < UHA_NSEG) {
                    438:                                bytes_this_seg = 0;
                    439:
                    440:                                /* put in the base address */
                    441:                                sg->seg_addr = thisphys;
                    442:
                    443:                                SC_DEBUGN(sc_link, SDEV_DB4, ("0x%x", thisphys));
                    444:
                    445:                                /* do it at least once */
                    446:                                nextphys = thisphys;
                    447:                                while (datalen && thisphys == nextphys) {
                    448:                                        /*
                    449:                                         * This page is contiguous (physically)
                    450:                                         * with the last, just extend the
                    451:                                         * length
                    452:                                         */
                    453:                                        /* how far to the end of the page */
                    454:                                        nextphys = (thisphys & ~PGOFSET) + NBPG;
                    455:                                        bytes_this_page = nextphys - thisphys;
                    456:                                        /**** or the data ****/
                    457:                                        bytes_this_page = min(bytes_this_page,
                    458:                                                              datalen);
                    459:                                        bytes_this_seg += bytes_this_page;
                    460:                                        datalen -= bytes_this_page;
                    461:
                    462:                                        /* get more ready for the next page */
                    463:                                        thiskv = (thiskv & ~PGOFSET) + NBPG;
                    464:                                        if (datalen)
                    465:                                                thisphys = KVTOPHYS(thiskv);
                    466:                                }
                    467:                                /*
                    468:                                 * next page isn't contiguous, finish the seg
                    469:                                 */
                    470:                                SC_DEBUGN(sc_link, SDEV_DB4,
                    471:                                    ("(0x%x)", bytes_this_seg));
                    472:                                sg->seg_len = bytes_this_seg;
                    473:                                sg++;
                    474:                                seg++;
                    475:                        }
                    476:                }
                    477:                /* end of iov/kv decision */
                    478:                SC_DEBUGN(sc_link, SDEV_DB4, ("\n"));
                    479:                if (datalen) {
                    480:                        /*
                    481:                         * there's still data, must have run out of segs!
                    482:                         */
                    483:                        printf("%s: uha_scsi_cmd, more than %d dma segs\n",
                    484:                            sc->sc_dev.dv_xname, UHA_NSEG);
                    485:                        goto bad;
                    486:                }
                    487:                mscp->data_addr = KVTOPHYS(mscp->uha_dma);
                    488:                mscp->data_length = xs->datalen;
                    489:                mscp->sgth = 0x01;
                    490:                mscp->sg_num = seg;
                    491:        } else {                /* No data xfer, use non S/G values */
                    492:                mscp->data_addr = (physaddr)0;
                    493:                mscp->data_length = 0;
                    494:                mscp->sgth = 0x00;
                    495:                mscp->sg_num = 0;
                    496:        }
                    497:        mscp->link_id = 0;
                    498:        mscp->link_addr = (physaddr)0;
                    499:
                    500:        s = splbio();
                    501:        (sc->start_mbox)(sc, mscp);
                    502:        splx(s);
                    503:
                    504:        /*
                    505:         * Usually return SUCCESSFULLY QUEUED
                    506:         */
                    507:        if ((flags & SCSI_POLL) == 0)
                    508:                return (SUCCESSFULLY_QUEUED);
                    509:
                    510:        /*
                    511:         * If we can't use interrupts, poll on completion
                    512:         */
                    513:        if ((sc->poll)(sc, xs, mscp->timeout)) {
                    514:                uha_timeout(mscp);
                    515:                if ((sc->poll)(sc, xs, mscp->timeout))
                    516:                        uha_timeout(mscp);
                    517:        }
                    518:        return (COMPLETE);
                    519:
                    520: bad:
                    521:        xs->error = XS_DRIVER_STUFFUP;
                    522:        uha_free_mscp(sc, mscp);
                    523:        return (COMPLETE);
                    524: }
                    525:
                    526: void
                    527: uha_timeout(arg)
                    528:        void *arg;
                    529: {
                    530:        struct uha_mscp *mscp = arg;
                    531:        struct scsi_xfer *xs = mscp->xs;
                    532:        struct scsi_link *sc_link = xs->sc_link;
                    533:        struct uha_softc *sc = sc_link->adapter_softc;
                    534:        int s;
                    535:
                    536:        sc_print_addr(sc_link);
                    537:        printf("timed out");
                    538:
                    539:        s = splbio();
                    540:
                    541:        if (mscp->flags & MSCP_ABORT) {
                    542:                /* abort timed out */
                    543:                printf(" AGAIN\n");
                    544:                /* XXX Must reset! */
                    545:        } else {
                    546:                /* abort the operation that has timed out */
                    547:                printf("\n");
                    548:                mscp->xs->error = XS_TIMEOUT;
                    549:                mscp->timeout = UHA_ABORT_TIMEOUT;
                    550:                mscp->flags |= MSCP_ABORT;
                    551:                (sc->start_mbox)(sc, mscp);
                    552:        }
                    553:
                    554:        splx(s);
                    555: }

CVSweb