[BACK]Return to scsipi_base.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / scsipi

Annotation of src/sys/dev/scsipi/scsipi_base.c, Revision 1.26.2.17

1.26.2.17! bouyer      1: /*     $NetBSD$        */
1.2       bouyer      2:
1.8       mycroft     3: /*-
1.26.2.7  thorpej     4:  * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
1.8       mycroft     5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to The NetBSD Foundation
1.26.2.1  thorpej     8:  * by Charles M. Hannum; by Jason R. Thorpe of the Numerical Aerospace
                      9:  * Simulation Facility, NASA Ames Research Center.
1.2       bouyer     10:  *
                     11:  * Redistribution and use in source and binary forms, with or without
                     12:  * modification, are permitted provided that the following conditions
                     13:  * are met:
                     14:  * 1. Redistributions of source code must retain the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer.
                     16:  * 2. Redistributions in binary form must reproduce the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer in the
                     18:  *    documentation and/or other materials provided with the distribution.
                     19:  * 3. All advertising materials mentioning features or use of this software
                     20:  *    must display the following acknowledgement:
1.8       mycroft    21:  *        This product includes software developed by the NetBSD
                     22:  *        Foundation, Inc. and its contributors.
                     23:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     24:  *    contributors may be used to endorse or promote products derived
                     25:  *    from this software without specific prior written permission.
1.2       bouyer     26:  *
1.8       mycroft    27:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     28:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     29:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     30:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     31:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     32:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     33:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     34:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     35:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     36:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     37:  * POSSIBILITY OF SUCH DAMAGE.
1.2       bouyer     38:  */
                     39:
1.13      bouyer     40: #include "opt_scsi.h"
                     41:
1.2       bouyer     42: #include <sys/types.h>
                     43: #include <sys/param.h>
                     44: #include <sys/systm.h>
                     45: #include <sys/kernel.h>
                     46: #include <sys/buf.h>
                     47: #include <sys/uio.h>
                     48: #include <sys/malloc.h>
1.6       thorpej    49: #include <sys/pool.h>
1.2       bouyer     50: #include <sys/errno.h>
                     51: #include <sys/device.h>
                     52: #include <sys/proc.h>
1.26.2.1  thorpej    53: #include <sys/kthread.h>
1.2       bouyer     54:
                     55: #include <dev/scsipi/scsipi_all.h>
                     56: #include <dev/scsipi/scsipi_disk.h>
                     57: #include <dev/scsipi/scsipiconf.h>
                     58: #include <dev/scsipi/scsipi_base.h>
                     59:
1.26.2.1  thorpej    60: #include <dev/scsipi/scsi_all.h>
                     61: #include <dev/scsipi/scsi_message.h>
                     62:
                     63: int    scsipi_complete __P((struct scsipi_xfer *));
1.26.2.9  bouyer     64: void   scsipi_request_sense __P((struct scsipi_xfer *));
1.26.2.1  thorpej    65: int    scsipi_enqueue __P((struct scsipi_xfer *));
                     66: void   scsipi_run_queue __P((struct scsipi_channel *chan));
                     67:
                     68: void   scsipi_completion_thread __P((void *));
                     69:
                     70: void   scsipi_get_tag __P((struct scsipi_xfer *));
                     71: void   scsipi_put_tag __P((struct scsipi_xfer *));
1.6       thorpej    72:
1.26.2.7  thorpej    73: int    scsipi_get_resource __P((struct scsipi_channel *));
                     74: void   scsipi_put_resource __P((struct scsipi_channel *));
                     75: __inline int scsipi_grow_resources __P((struct scsipi_channel *));
                     76:
1.26.2.1  thorpej    77: void   scsipi_async_event_max_openings __P((struct scsipi_channel *,
                     78:            struct scsipi_max_openings *));
1.26.2.2  thorpej    79: void   scsipi_async_event_xfer_mode __P((struct scsipi_channel *,
                     80:            struct scsipi_xfer_mode *));
1.26.2.9  bouyer     81: void   scsipi_async_event_channel_reset __P((struct scsipi_channel *));
1.26.2.1  thorpej    82:
                     83: struct pool scsipi_xfer_pool;
1.2       bouyer     84:
                     85: /*
1.26.2.1  thorpej    86:  * scsipi_init:
                     87:  *
                     88:  *     Called when a scsibus or atapibus is attached to the system
                     89:  *     to initialize shared data structures.
1.6       thorpej    90:  */
                     91: void
                     92: scsipi_init()
                     93: {
                     94:        static int scsipi_init_done;
                     95:
                     96:        if (scsipi_init_done)
                     97:                return;
                     98:        scsipi_init_done = 1;
                     99:
                    100:        /* Initialize the scsipi_xfer pool. */
                    101:        pool_init(&scsipi_xfer_pool, sizeof(struct scsipi_xfer), 0,
                    102:            0, 0, "scxspl", 0, NULL, NULL, M_DEVBUF);
                    103: }
                    104:
                    105: /*
1.26.2.1  thorpej   106:  * scsipi_channel_init:
                    107:  *
                    108:  *     Initialize a scsipi_channel when it is attached.
                    109:  */
1.26.2.14  mjacob    110: int
1.26.2.1  thorpej   111: scsipi_channel_init(chan)
                    112:        struct scsipi_channel *chan;
                    113: {
                    114:        size_t nbytes;
                    115:        int i;
                    116:
                    117:        /* Initialize shared data. */
                    118:        scsipi_init();
                    119:
                    120:        /* Initialize the queues. */
                    121:        TAILQ_INIT(&chan->chan_queue);
                    122:        TAILQ_INIT(&chan->chan_complete);
                    123:
1.26.2.11  bouyer    124:        nbytes = chan->chan_ntargets * sizeof(struct scsipi_periph **);
1.26.2.14  mjacob    125:        chan->chan_periphs = malloc(nbytes, M_DEVBUF, M_NOWAIT);
                    126:        if (chan->chan_periphs == NULL)
                    127:                return (ENOMEM);
                    128:
1.26.2.1  thorpej   129:
                    130:        nbytes = chan->chan_nluns * sizeof(struct scsipi_periph *);
                    131:        for (i = 0; i < chan->chan_ntargets; i++) {
1.26.2.14  mjacob    132:                chan->chan_periphs[i] = malloc(nbytes, M_DEVBUF, M_NOWAIT);
                    133:                if (chan->chan_periphs[i] == NULL) {
                    134:                        while (--i >= 0) {
                    135:                                free(chan->chan_periphs[i], M_DEVBUF);
                    136:                        }
                    137:                        return (ENOMEM);
                    138:                }
1.26.2.1  thorpej   139:                memset(chan->chan_periphs[i], 0, nbytes);
                    140:        }
                    141:
                    142:        /*
                    143:         * Create the asynchronous completion thread.
                    144:         */
                    145:        kthread_create(scsipi_create_completion_thread, chan);
1.26.2.14  mjacob    146:        return (0);
1.26.2.1  thorpej   147: }
                    148:
                    149: /*
1.26.2.7  thorpej   150:  * scsipi_channel_shutdown:
                    151:  *
                    152:  *     Shutdown a scsipi_channel.
                    153:  */
                    154: void
                    155: scsipi_channel_shutdown(chan)
                    156:        struct scsipi_channel *chan;
                    157: {
                    158:
                    159:        /*
                    160:         * Shut down the completion thread.
                    161:         */
                    162:        chan->chan_flags |= SCSIPI_CHAN_SHUTDOWN;
                    163:        wakeup(&chan->chan_complete);
                    164:
                    165:        /*
                    166:         * Now wait for the thread to exit.
                    167:         */
                    168:        while (chan->chan_thread != NULL)
                    169:                (void) tsleep(&chan->chan_thread, PRIBIO, "scshut", 0);
                    170: }
                    171:
                    172: /*
                    173:  * scsipi_insert_periph:
                    174:  *
                    175:  *     Insert a periph into the channel.
                    176:  */
                    177: void
                    178: scsipi_insert_periph(chan, periph)
                    179:        struct scsipi_channel *chan;
                    180:        struct scsipi_periph *periph;
                    181: {
                    182:        int s;
                    183:
                    184:        s = splbio();
                    185:        chan->chan_periphs[periph->periph_target][periph->periph_lun] = periph;
                    186:        splx(s);
                    187: }
                    188:
                    189: /*
                    190:  * scsipi_remove_periph:
                    191:  *
                    192:  *     Remove a periph from the channel.
                    193:  */
                    194: void
                    195: scsipi_remove_periph(chan, periph)
                    196:        struct scsipi_channel *chan;
                    197:        struct scsipi_periph *periph;
                    198: {
                    199:        int s;
                    200:
                    201:        s = splbio();
                    202:        chan->chan_periphs[periph->periph_target][periph->periph_lun] = NULL;
                    203:        splx(s);
                    204: }
                    205:
                    206: /*
1.26.2.1  thorpej   207:  * scsipi_lookup_periph:
                    208:  *
                    209:  *     Lookup a periph on the specified channel.
                    210:  */
                    211: struct scsipi_periph *
                    212: scsipi_lookup_periph(chan, target, lun)
                    213:        struct scsipi_channel *chan;
                    214:        int target, lun;
                    215: {
                    216:        struct scsipi_periph *periph;
                    217:        int s;
                    218:
                    219:        if (target >= chan->chan_ntargets ||
                    220:            lun >= chan->chan_nluns)
                    221:                return (NULL);
                    222:
                    223:        s = splbio();
                    224:        periph = chan->chan_periphs[target][lun];
                    225:        splx(s);
                    226:
                    227:        return (periph);
                    228: }
                    229:
                    230: /*
                    231:  * scsipi_get_resource:
                    232:  *
                    233:  *     Allocate a single xfer `resource' from the channel.
                    234:  *
                    235:  *     NOTE: Must be called at splbio().
                    236:  */
                    237: int
                    238: scsipi_get_resource(chan)
                    239:        struct scsipi_channel *chan;
                    240: {
                    241:        struct scsipi_adapter *adapt = chan->chan_adapter;
                    242:
                    243:        if (chan->chan_flags & SCSIPI_CHAN_OPENINGS) {
                    244:                if (chan->chan_openings > 0) {
                    245:                        chan->chan_openings--;
                    246:                        return (1);
                    247:                }
                    248:                return (0);
                    249:        }
                    250:
                    251:        if (adapt->adapt_openings > 0) {
                    252:                adapt->adapt_openings--;
                    253:                return (1);
                    254:        }
                    255:        return (0);
                    256: }
                    257:
                    258: /*
                    259:  * scsipi_grow_resources:
                    260:  *
                    261:  *     Attempt to grow resources for a channel.  If this succeeds,
                    262:  *     we allocate one for our caller.
                    263:  *
                    264:  *     NOTE: Must be called at splbio().
                    265:  */
1.26.2.7  thorpej   266: __inline int
1.26.2.1  thorpej   267: scsipi_grow_resources(chan)
                    268:        struct scsipi_channel *chan;
                    269: {
                    270:
                    271:        if (chan->chan_flags & SCSIPI_CHAN_CANGROW) {
                    272:                scsipi_adapter_request(chan, ADAPTER_REQ_GROW_RESOURCES, NULL);
                    273:                return (scsipi_get_resource(chan));
                    274:        }
                    275:
                    276:        return (0);
                    277: }
                    278:
                    279: /*
                    280:  * scsipi_put_resource:
                    281:  *
                    282:  *     Free a single xfer `resource' to the channel.
                    283:  *
                    284:  *     NOTE: Must be called at splbio().
                    285:  */
                    286: void
                    287: scsipi_put_resource(chan)
                    288:        struct scsipi_channel *chan;
                    289: {
                    290:        struct scsipi_adapter *adapt = chan->chan_adapter;
                    291:
                    292:        if (chan->chan_flags & SCSIPI_CHAN_OPENINGS)
                    293:                chan->chan_openings++;
                    294:        else
                    295:                adapt->adapt_openings++;
                    296: }
                    297:
                    298: /*
                    299:  * scsipi_get_tag:
                    300:  *
                    301:  *     Get a tag ID for the specified xfer.
                    302:  *
                    303:  *     NOTE: Must be called at splbio().
                    304:  */
                    305: void
                    306: scsipi_get_tag(xs)
                    307:        struct scsipi_xfer *xs;
                    308: {
                    309:        struct scsipi_periph *periph = xs->xs_periph;
                    310:        int word, bit, tag;
                    311:
                    312:        for (word = 0; word < PERIPH_NTAGWORDS; word++) {
                    313:                bit = ffs(periph->periph_freetags[word]);
                    314:                if (bit != 0)
                    315:                        break;
                    316:        }
                    317: #ifdef DIAGNOSTIC
                    318:        if (word == PERIPH_NTAGWORDS) {
                    319:                scsipi_printaddr(periph);
                    320:                printf("no free tags\n");
                    321:                panic("scsipi_get_tag");
                    322:        }
                    323: #endif
                    324:
                    325:        bit -= 1;
                    326:        periph->periph_freetags[word] &= ~(1 << bit);
                    327:        tag = (word << 5) | bit;
                    328:
                    329:        /* XXX Should eventually disallow this completely. */
                    330:        if (tag >= periph->periph_openings) {
                    331:                scsipi_printaddr(periph);
                    332:                printf("WARNING: tag %d greater than available openings %d\n",
                    333:                    tag, periph->periph_openings);
                    334:        }
                    335:
                    336:        xs->xs_tag_id = tag;
                    337: }
                    338:
                    339: /*
                    340:  * scsipi_put_tag:
                    341:  *
                    342:  *     Put the tag ID for the specified xfer back into the pool.
                    343:  *
                    344:  *     NOTE: Must be called at splbio().
1.2       bouyer    345:  */
1.26.2.1  thorpej   346: void
                    347: scsipi_put_tag(xs)
                    348:        struct scsipi_xfer *xs;
                    349: {
                    350:        struct scsipi_periph *periph = xs->xs_periph;
                    351:        int word, bit;
                    352:
                    353:        word = xs->xs_tag_id >> 5;
                    354:        bit = xs->xs_tag_id & 0x1f;
                    355:
                    356:        periph->periph_freetags[word] |= (1 << bit);
                    357: }
1.2       bouyer    358:
1.26.2.1  thorpej   359: /*
                    360:  * scsipi_get_xs:
                    361:  *
                    362:  *     Allocate an xfer descriptor and associate it with the
                    363:  *     specified peripherial.  If the peripherial has no more
                    364:  *     available command openings, we either block waiting for
                    365:  *     one to become available, or fail.
                    366:  */
1.2       bouyer    367: struct scsipi_xfer *
1.26.2.1  thorpej   368: scsipi_get_xs(periph, flags)
                    369:        struct scsipi_periph *periph;
                    370:        int flags;
1.2       bouyer    371: {
                    372:        struct scsipi_xfer *xs;
                    373:        int s;
                    374:
1.26.2.6  thorpej   375:        SC_DEBUG(periph, SCSIPI_DB3, ("scsipi_get_xs\n"));
1.6       thorpej   376:
1.24      thorpej   377:        /*
                    378:         * If we're cold, make sure we poll.
                    379:         */
                    380:        if (cold)
                    381:                flags |= XS_CTL_NOSLEEP | XS_CTL_POLL;
                    382:
1.26.2.1  thorpej   383: #ifdef DIAGNOSTIC
                    384:        /*
                    385:         * URGENT commands can never be ASYNC.
                    386:         */
                    387:        if ((flags & (XS_CTL_URGENT|XS_CTL_ASYNC)) ==
                    388:            (XS_CTL_URGENT|XS_CTL_ASYNC)) {
                    389:                scsipi_printaddr(periph);
                    390:                printf("URGENT and ASYNC\n");
                    391:                panic("scsipi_get_xs");
                    392:        }
                    393: #endif
                    394:
1.2       bouyer    395:        s = splbio();
1.26.2.1  thorpej   396:        /*
                    397:         * Wait for a command opening to become available.  Rules:
                    398:         *
                    399:         *      - All xfers must wait for an available opening.
                    400:         *        Exception: URGENT xfers can proceed when
                    401:         *        active == openings, because we use the opening
                    402:         *        of the command we're recovering for.
1.26.2.9  bouyer    403:         *      - if the periph has sense pending, only URGENT & REQSENSE
                    404:         *        xfers may proceed.
1.26.2.1  thorpej   405:         *
                    406:         *      - If the periph is recovering, only URGENT xfers may
                    407:         *        proceed.
                    408:         *
                    409:         *      - If the periph is currently executing a recovery
                    410:         *        command, URGENT commands must block, because only
                    411:         *        one recovery command can execute at a time.
                    412:         */
                    413:        for (;;) {
                    414:                if (flags & XS_CTL_URGENT) {
1.26.2.9  bouyer    415:                        if (periph->periph_active > periph->periph_openings)
1.26.2.1  thorpej   416:                                goto wait_for_opening;
1.26.2.9  bouyer    417:                        if (periph->periph_flags & PERIPH_SENSE) {
                    418:                                if ((flags & XS_CTL_REQSENSE) == 0)
                    419:                                        goto wait_for_opening;
                    420:                        } else {
                    421:                                if ((periph->periph_flags &
                    422:                                    PERIPH_RECOVERY_ACTIVE) != 0)
                    423:                                        goto wait_for_opening;
                    424:                                periph->periph_flags |= PERIPH_RECOVERY_ACTIVE;
                    425:                        }
1.26.2.1  thorpej   426:                        break;
                    427:                }
                    428:                if (periph->periph_active >= periph->periph_openings ||
                    429:                    (periph->periph_flags & PERIPH_RECOVERING) != 0)
                    430:                        goto wait_for_opening;
                    431:                periph->periph_active++;
                    432:                break;
                    433:
                    434:  wait_for_opening:
                    435:                if (flags & XS_CTL_NOSLEEP) {
1.2       bouyer    436:                        splx(s);
1.26.2.1  thorpej   437:                        return (NULL);
1.2       bouyer    438:                }
1.26.2.6  thorpej   439:                SC_DEBUG(periph, SCSIPI_DB3, ("sleeping\n"));
1.26.2.1  thorpej   440:                periph->periph_flags |= PERIPH_WAITING;
                    441:                (void) tsleep(periph, PRIBIO, "getxs", 0);
1.2       bouyer    442:        }
1.26.2.6  thorpej   443:        SC_DEBUG(periph, SCSIPI_DB3, ("calling pool_get\n"));
1.6       thorpej   444:        xs = pool_get(&scsipi_xfer_pool,
1.24      thorpej   445:            ((flags & XS_CTL_NOSLEEP) != 0 ? PR_NOWAIT : PR_WAITOK));
1.26.2.1  thorpej   446:        if (xs == NULL) {
1.26.2.9  bouyer    447:                if (flags & XS_CTL_URGENT) {
                    448:                        if ((flags & XS_CTL_REQSENSE) == 0)
                    449:                                periph->periph_flags &= ~PERIPH_RECOVERY_ACTIVE;
                    450:                } else
1.26.2.1  thorpej   451:                        periph->periph_active--;
                    452:                scsipi_printaddr(periph);
                    453:                printf("unable to allocate %sscsipi_xfer\n",
                    454:                    (flags & XS_CTL_URGENT) ? "URGENT " : "");
1.2       bouyer    455:        }
1.6       thorpej   456:        splx(s);
1.2       bouyer    457:
1.26.2.6  thorpej   458:        SC_DEBUG(periph, SCSIPI_DB3, ("returning\n"));
1.6       thorpej   459:
1.7       scottr    460:        if (xs != NULL) {
1.26.2.8  bouyer    461:                callout_init(&xs->xs_callout);
1.26.2.1  thorpej   462:                memset(xs, 0, sizeof(*xs));
                    463:                xs->xs_periph = periph;
1.24      thorpej   464:                xs->xs_control = flags;
1.26.2.8  bouyer    465:                xs->xs_status = 0;
1.26.2.1  thorpej   466:                s = splbio();
                    467:                TAILQ_INSERT_TAIL(&periph->periph_xferq, xs, device_q);
                    468:                splx(s);
1.7       scottr    469:        }
1.3       enami     470:        return (xs);
1.2       bouyer    471: }
                    472:
                    473: /*
1.26.2.1  thorpej   474:  * scsipi_put_xs:
1.6       thorpej   475:  *
1.26.2.1  thorpej   476:  *     Release an xfer descriptor, decreasing the outstanding command
                    477:  *     count for the peripherial.  If there is a thread waiting for
                    478:  *     an opening, wake it up.  If not, kick any queued I/O the
                    479:  *     peripherial may have.
                    480:  *
                    481:  *     NOTE: Must be called at splbio().
1.2       bouyer    482:  */
1.3       enami     483: void
1.26.2.1  thorpej   484: scsipi_put_xs(xs)
1.2       bouyer    485:        struct scsipi_xfer *xs;
                    486: {
1.26.2.1  thorpej   487:        struct scsipi_periph *periph = xs->xs_periph;
                    488:        int flags = xs->xs_control;
1.2       bouyer    489:
1.26.2.6  thorpej   490:        SC_DEBUG(periph, SCSIPI_DB3, ("scsipi_free_xs\n"));
1.26.2.1  thorpej   491:
                    492:        TAILQ_REMOVE(&periph->periph_xferq, xs, device_q);
1.6       thorpej   493:        pool_put(&scsipi_xfer_pool, xs);
1.2       bouyer    494:
1.26.2.1  thorpej   495: #ifdef DIAGNOSTIC
                    496:        if ((periph->periph_flags & PERIPH_RECOVERY_ACTIVE) != 0 &&
                    497:            periph->periph_active == 0) {
                    498:                scsipi_printaddr(periph);
                    499:                printf("recovery without a command to recovery for\n");
                    500:                panic("scsipi_put_xs");
                    501:        }
                    502: #endif
                    503:
1.26.2.9  bouyer    504:        if (flags & XS_CTL_URGENT) {
                    505:                if ((flags & XS_CTL_REQSENSE) == 0)
                    506:                        periph->periph_flags &= ~PERIPH_RECOVERY_ACTIVE;
                    507:        } else
1.26.2.1  thorpej   508:                periph->periph_active--;
                    509:        if (periph->periph_active == 0 &&
                    510:            (periph->periph_flags & PERIPH_WAITDRAIN) != 0) {
                    511:                periph->periph_flags &= ~PERIPH_WAITDRAIN;
                    512:                wakeup(&periph->periph_active);
                    513:        }
                    514:
                    515:        if (periph->periph_flags & PERIPH_WAITING) {
                    516:                periph->periph_flags &= ~PERIPH_WAITING;
                    517:                wakeup(periph);
1.2       bouyer    518:        } else {
1.26.2.1  thorpej   519:                if (periph->periph_switch->psw_start != NULL) {
1.26.2.6  thorpej   520:                        SC_DEBUG(periph, SCSIPI_DB2,
1.3       enami     521:                            ("calling private start()\n"));
1.26.2.1  thorpej   522:                        (*periph->periph_switch->psw_start)(periph);
1.2       bouyer    523:                }
                    524:        }
1.15      thorpej   525: }
                    526:
                    527: /*
1.26.2.3  thorpej   528:  * scsipi_channel_freeze:
                    529:  *
                    530:  *     Freeze a channel's xfer queue.
                    531:  */
                    532: void
                    533: scsipi_channel_freeze(chan, count)
                    534:        struct scsipi_channel *chan;
                    535:        int count;
                    536: {
                    537:        int s;
                    538:
                    539:        s = splbio();
                    540:        chan->chan_qfreeze += count;
                    541:        splx(s);
                    542: }
                    543:
                    544: /*
                    545:  * scsipi_channel_thaw:
                    546:  *
                    547:  *     Thaw a channel's xfer queue.
                    548:  */
                    549: void
                    550: scsipi_channel_thaw(chan, count)
                    551:        struct scsipi_channel *chan;
                    552:        int count;
                    553: {
                    554:        int s;
                    555:
                    556:        s = splbio();
                    557:        chan->chan_qfreeze -= count;
1.26.2.16  mjacob    558:        /*
                    559:         * Don't let the freeze count go negative.
                    560:         *
                    561:         * Presumably the adapter driver could keep track of this,
                    562:         * but it might just be easier to do this here so as to allow
                    563:         * multiple callers, including those outside the adapter driver.
                    564:         */
                    565:        if (chan->chan_qfreeze < 0) {
                    566:                chan->chan_qfreeze = 0;
                    567:        }
1.26.2.3  thorpej   568:        splx(s);
                    569: }
                    570:
                    571: /*
                    572:  * scsipi_channel_timed_thaw:
                    573:  *
                    574:  *     Thaw a channel after some time has expired.
                    575:  */
                    576: void
                    577: scsipi_channel_timed_thaw(arg)
                    578:        void *arg;
                    579: {
                    580:        struct scsipi_channel *chan = arg;
                    581:
                    582:        scsipi_channel_thaw(chan, 1);
                    583:
                    584:        /*
                    585:         * Kick the channel's queue here.  Note, we're running in
                    586:         * interrupt context (softclock), so the adapter driver
                    587:         * had better not sleep.
                    588:         */
                    589:        scsipi_run_queue(chan);
                    590: }
                    591:
                    592: /*
1.26.2.1  thorpej   593:  * scsipi_periph_freeze:
                    594:  *
                    595:  *     Freeze a device's xfer queue.
                    596:  */
                    597: void
                    598: scsipi_periph_freeze(periph, count)
                    599:        struct scsipi_periph *periph;
                    600:        int count;
                    601: {
                    602:        int s;
                    603:
                    604:        s = splbio();
                    605:        periph->periph_qfreeze += count;
                    606:        splx(s);
                    607: }
                    608:
                    609: /*
                    610:  * scsipi_periph_thaw:
                    611:  *
                    612:  *     Thaw a device's xfer queue.
                    613:  */
                    614: void
                    615: scsipi_periph_thaw(periph, count)
                    616:        struct scsipi_periph *periph;
                    617:        int count;
                    618: {
                    619:        int s;
                    620:
                    621:        s = splbio();
                    622:        periph->periph_qfreeze -= count;
                    623:        if (periph->periph_qfreeze == 0 &&
                    624:            (periph->periph_flags & PERIPH_WAITING) != 0)
                    625:                wakeup(periph);
                    626:        splx(s);
                    627: }
                    628:
                    629: /*
                    630:  * scsipi_periph_timed_thaw:
                    631:  *
                    632:  *     Thaw a device after some time has expired.
                    633:  */
                    634: void
                    635: scsipi_periph_timed_thaw(arg)
                    636:        void *arg;
                    637: {
                    638:        struct scsipi_periph *periph = arg;
                    639:
1.26.2.8  bouyer    640:        callout_stop(&periph->periph_callout);
1.26.2.1  thorpej   641:        scsipi_periph_thaw(periph, 1);
                    642:
1.26.2.3  thorpej   643:        /*
                    644:         * Kick the channel's queue here.  Note, we're running in
                    645:         * interrupt context (softclock), so the adapter driver
                    646:         * had better not sleep.
                    647:         */
                    648:        scsipi_run_queue(periph->periph_channel);
1.26.2.1  thorpej   649: }
                    650:
                    651: /*
                    652:  * scsipi_wait_drain:
                    653:  *
                    654:  *     Wait for a periph's pending xfers to drain.
1.15      thorpej   655:  */
                    656: void
1.26.2.1  thorpej   657: scsipi_wait_drain(periph)
                    658:        struct scsipi_periph *periph;
1.15      thorpej   659: {
                    660:        int s;
                    661:
                    662:        s = splbio();
1.26.2.1  thorpej   663:        while (periph->periph_active != 0) {
                    664:                periph->periph_flags |= PERIPH_WAITDRAIN;
                    665:                (void) tsleep(&periph->periph_active, PRIBIO, "sxdrn", 0);
1.15      thorpej   666:        }
                    667:        splx(s);
1.23      thorpej   668: }
                    669:
                    670: /*
1.26.2.1  thorpej   671:  * scsipi_kill_pending:
1.23      thorpej   672:  *
1.26.2.1  thorpej   673:  *     Kill off all pending xfers for a periph.
                    674:  *
                    675:  *     NOTE: Must be called at splbio().
1.23      thorpej   676:  */
                    677: void
1.26.2.1  thorpej   678: scsipi_kill_pending(periph)
                    679:        struct scsipi_periph *periph;
1.23      thorpej   680: {
                    681:
1.26.2.4  thorpej   682:        (*periph->periph_channel->chan_bustype->bustype_kill_pending)(periph);
                    683: #ifdef DIAGNOSTIC
                    684:        if (TAILQ_FIRST(&periph->periph_xferq) != NULL)
                    685:                panic("scsipi_kill_pending");
                    686: #endif
1.26.2.8  bouyer    687:        scsipi_wait_drain(periph);
1.2       bouyer    688: }
                    689:
                    690: /*
1.26.2.1  thorpej   691:  * scsipi_interpret_sense:
                    692:  *
                    693:  *     Look at the returned sense and act on the error, determining
                    694:  *     the unix error number to pass back.  (0 = report no error)
1.13      bouyer    695:  *
1.26.2.1  thorpej   696:  *     NOTE: If we return ERESTART, we are expected to haved
                    697:  *     thawed the device!
                    698:  *
                    699:  *     THIS IS THE DEFAULT ERROR HANDLER FOR SCSI DEVICES.
1.13      bouyer    700:  */
                    701: int
                    702: scsipi_interpret_sense(xs)
                    703:        struct scsipi_xfer *xs;
                    704: {
                    705:        struct scsipi_sense_data *sense;
1.26.2.1  thorpej   706:        struct scsipi_periph *periph = xs->xs_periph;
1.13      bouyer    707:        u_int8_t key;
                    708:        u_int32_t info;
                    709:        int error;
                    710: #ifndef        SCSIVERBOSE
                    711:        static char *error_mes[] = {
                    712:                "soft error (corrected)",
                    713:                "not ready", "medium error",
                    714:                "non-media hardware failure", "illegal request",
                    715:                "unit attention", "readonly device",
                    716:                "no data found", "vendor unique",
                    717:                "copy aborted", "command aborted",
                    718:                "search returned equal", "volume overflow",
                    719:                "verify miscompare", "unknown error key"
                    720:        };
                    721: #endif
                    722:
                    723:        sense = &xs->sense.scsi_sense;
1.26.2.6  thorpej   724: #ifdef SCSIPI_DEBUG
                    725:        if (periph->periph_flags & SCSIPI_DB1) {
1.13      bouyer    726:                int count;
1.26.2.6  thorpej   727:                scsipi_printaddr(periph);
                    728:                printf(" sense debug information:\n");
                    729:                printf("\tcode 0x%x valid 0x%x\n",
1.13      bouyer    730:                        sense->error_code & SSD_ERRCODE,
                    731:                        sense->error_code & SSD_ERRCODE_VALID ? 1 : 0);
1.26.2.6  thorpej   732:                printf("\tseg 0x%x key 0x%x ili 0x%x eom 0x%x fmark 0x%x\n",
1.13      bouyer    733:                        sense->segment,
                    734:                        sense->flags & SSD_KEY,
                    735:                        sense->flags & SSD_ILI ? 1 : 0,
                    736:                        sense->flags & SSD_EOM ? 1 : 0,
                    737:                        sense->flags & SSD_FILEMARK ? 1 : 0);
1.26.2.6  thorpej   738:                printf("\ninfo: 0x%x 0x%x 0x%x 0x%x followed by %d "
                    739:                        "extra bytes\n",
1.13      bouyer    740:                        sense->info[0],
                    741:                        sense->info[1],
                    742:                        sense->info[2],
                    743:                        sense->info[3],
                    744:                        sense->extra_len);
1.26.2.6  thorpej   745:                printf("\textra: ");
1.13      bouyer    746:                for (count = 0; count < ADD_BYTES_LIM(sense); count++)
                    747:                        printf("0x%x ", sense->cmd_spec_info[count]);
                    748:                printf("\n");
                    749:        }
1.26.2.6  thorpej   750: #endif
1.26.2.1  thorpej   751:
1.13      bouyer    752:        /*
1.26.2.1  thorpej   753:         * If the periph has it's own error handler, call it first.
1.13      bouyer    754:         * If it returns a legit error value, return that, otherwise
                    755:         * it wants us to continue with normal error processing.
                    756:         */
1.26.2.1  thorpej   757:        if (periph->periph_switch->psw_error != NULL) {
1.26.2.6  thorpej   758:                SC_DEBUG(periph, SCSIPI_DB2,
1.13      bouyer    759:                    ("calling private err_handler()\n"));
1.26.2.1  thorpej   760:                error = (*periph->periph_switch->psw_error)(xs);
                    761:                if (error != EJUSTRETURN)
                    762:                        return (error);
1.13      bouyer    763:        }
                    764:        /* otherwise use the default */
                    765:        switch (sense->error_code & SSD_ERRCODE) {
                    766:                /*
                    767:                 * If it's code 70, use the extended stuff and
                    768:                 * interpret the key
                    769:                 */
                    770:        case 0x71:              /* delayed error */
1.26.2.1  thorpej   771:                scsipi_printaddr(periph);
1.13      bouyer    772:                key = sense->flags & SSD_KEY;
                    773:                printf(" DEFERRED ERROR, key = 0x%x\n", key);
                    774:                /* FALLTHROUGH */
                    775:        case 0x70:
                    776:                if ((sense->error_code & SSD_ERRCODE_VALID) != 0)
                    777:                        info = _4btol(sense->info);
                    778:                else
                    779:                        info = 0;
                    780:                key = sense->flags & SSD_KEY;
                    781:
                    782:                switch (key) {
                    783:                case SKEY_NO_SENSE:
                    784:                case SKEY_RECOVERED_ERROR:
                    785:                        if (xs->resid == xs->datalen && xs->datalen) {
                    786:                                /*
                    787:                                 * Why is this here?
                    788:                                 */
                    789:                                xs->resid = 0;  /* not short read */
                    790:                        }
                    791:                case SKEY_EQUAL:
                    792:                        error = 0;
                    793:                        break;
                    794:                case SKEY_NOT_READY:
1.26.2.1  thorpej   795:                        if ((periph->periph_flags & PERIPH_REMOVABLE) != 0)
                    796:                                periph->periph_flags &= ~PERIPH_MEDIA_LOADED;
1.24      thorpej   797:                        if ((xs->xs_control & XS_CTL_IGNORE_NOT_READY) != 0)
1.13      bouyer    798:                                return (0);
1.19      bouyer    799:                        if (sense->add_sense_code == 0x3A &&
                    800:                            sense->add_sense_code_qual == 0x00)
                    801:                                error = ENODEV; /* Medium not present */
                    802:                        else
                    803:                                error = EIO;
1.24      thorpej   804:                        if ((xs->xs_control & XS_CTL_SILENT) != 0)
1.19      bouyer    805:                                return (error);
1.13      bouyer    806:                        break;
                    807:                case SKEY_ILLEGAL_REQUEST:
1.24      thorpej   808:                        if ((xs->xs_control &
                    809:                             XS_CTL_IGNORE_ILLEGAL_REQUEST) != 0)
1.13      bouyer    810:                                return (0);
1.24      thorpej   811:                        /*
                    812:                         * Handle the case where a device reports
                    813:                         * Logical Unit Not Supported during discovery.
                    814:                         */
                    815:                        if ((xs->xs_control & XS_CTL_DISCOVERY) != 0 &&
                    816:                            sense->add_sense_code == 0x25 &&
                    817:                            sense->add_sense_code_qual == 0x00)
                    818:                                return (EINVAL);
                    819:                        if ((xs->xs_control & XS_CTL_SILENT) != 0)
1.13      bouyer    820:                                return (EIO);
                    821:                        error = EINVAL;
                    822:                        break;
                    823:                case SKEY_UNIT_ATTENTION:
1.20      bouyer    824:                        if (sense->add_sense_code == 0x29 &&
1.26.2.1  thorpej   825:                            sense->add_sense_code_qual == 0x00) {
                    826:                                /* device or bus reset */
                    827:                                return (ERESTART);
                    828:                        }
                    829:                        if ((periph->periph_flags & PERIPH_REMOVABLE) != 0)
                    830:                                periph->periph_flags &= ~PERIPH_MEDIA_LOADED;
1.24      thorpej   831:                        if ((xs->xs_control &
                    832:                             XS_CTL_IGNORE_MEDIA_CHANGE) != 0 ||
1.13      bouyer    833:                                /* XXX Should reupload any transient state. */
1.26.2.1  thorpej   834:                                (periph->periph_flags &
                    835:                                 PERIPH_REMOVABLE) == 0) {
1.13      bouyer    836:                                return (ERESTART);
1.26.2.1  thorpej   837:                        }
1.24      thorpej   838:                        if ((xs->xs_control & XS_CTL_SILENT) != 0)
1.13      bouyer    839:                                return (EIO);
                    840:                        error = EIO;
                    841:                        break;
                    842:                case SKEY_WRITE_PROTECT:
                    843:                        error = EROFS;
                    844:                        break;
                    845:                case SKEY_BLANK_CHECK:
                    846:                        error = 0;
                    847:                        break;
                    848:                case SKEY_ABORTED_COMMAND:
                    849:                        error = ERESTART;
                    850:                        break;
                    851:                case SKEY_VOLUME_OVERFLOW:
                    852:                        error = ENOSPC;
                    853:                        break;
                    854:                default:
                    855:                        error = EIO;
                    856:                        break;
                    857:                }
                    858:
                    859: #ifdef SCSIVERBOSE
1.26.2.8  bouyer    860:                if (key && (xs->xs_control & XS_CTL_SILENT) == 0)
1.13      bouyer    861:                        scsipi_print_sense(xs, 0);
                    862: #else
                    863:                if (key) {
1.26.2.1  thorpej   864:                        scsipi_printaddr(periph);
1.13      bouyer    865:                        printf("%s", error_mes[key - 1]);
                    866:                        if ((sense->error_code & SSD_ERRCODE_VALID) != 0) {
                    867:                                switch (key) {
                    868:                                case SKEY_NOT_READY:
                    869:                                case SKEY_ILLEGAL_REQUEST:
                    870:                                case SKEY_UNIT_ATTENTION:
                    871:                                case SKEY_WRITE_PROTECT:
                    872:                                        break;
                    873:                                case SKEY_BLANK_CHECK:
                    874:                                        printf(", requested size: %d (decimal)",
                    875:                                            info);
                    876:                                        break;
                    877:                                case SKEY_ABORTED_COMMAND:
1.26.2.1  thorpej   878:                                        if (xs->xs_retries)
1.13      bouyer    879:                                                printf(", retrying");
                    880:                                        printf(", cmd 0x%x, info 0x%x",
                    881:                                            xs->cmd->opcode, info);
                    882:                                        break;
                    883:                                default:
                    884:                                        printf(", info = %d (decimal)", info);
                    885:                                }
                    886:                        }
                    887:                        if (sense->extra_len != 0) {
                    888:                                int n;
                    889:                                printf(", data =");
                    890:                                for (n = 0; n < sense->extra_len; n++)
                    891:                                        printf(" %02x",
                    892:                                            sense->cmd_spec_info[n]);
                    893:                        }
                    894:                        printf("\n");
                    895:                }
                    896: #endif
                    897:                return (error);
                    898:
                    899:        /*
                    900:         * Not code 70, just report it
                    901:         */
                    902:        default:
1.26.2.8  bouyer    903: #if    defined(SCSIDEBUG) || defined(DEBUG)
                    904:        {
                    905:                static char *uc = "undecodable sense error";
                    906:                int i;
                    907:                u_int8_t *cptr = (u_int8_t *) sense;
                    908:                scsipi_printaddr(periph);
                    909:                if (xs->cmd == &xs->cmdstore) {
                    910:                        printf("%s for opcode 0x%x, data=",
                    911:                            uc, xs->cmdstore.opcode);
                    912:                } else {
                    913:                        printf("%s, data=", uc);
                    914:                }
                    915:                for (i = 0; i < sizeof (sense); i++)
                    916:                        printf(" 0x%02x", *(cptr++) & 0xff);
                    917:                printf("\n");
                    918:        }
                    919: #else
                    920:
1.26.2.1  thorpej   921:                scsipi_printaddr(periph);
1.17      mjacob    922:                printf("Sense Error Code 0x%x",
                    923:                        sense->error_code & SSD_ERRCODE);
1.13      bouyer    924:                if ((sense->error_code & SSD_ERRCODE_VALID) != 0) {
                    925:                        struct scsipi_sense_data_unextended *usense =
                    926:                            (struct scsipi_sense_data_unextended *)sense;
                    927:                        printf(" at block no. %d (decimal)",
                    928:                            _3btol(usense->block));
                    929:                }
                    930:                printf("\n");
1.26.2.8  bouyer    931: #endif
1.13      bouyer    932:                return (EIO);
                    933:        }
                    934: }
                    935:
                    936: /*
1.26.2.1  thorpej   937:  * scsipi_size:
                    938:  *
                    939:  *     Find out from the device what its capacity is.
1.2       bouyer    940:  */
                    941: u_long
1.26.2.1  thorpej   942: scsipi_size(periph, flags)
                    943:        struct scsipi_periph *periph;
1.2       bouyer    944:        int flags;
                    945: {
                    946:        struct scsipi_read_cap_data rdcap;
                    947:        struct scsipi_read_capacity scsipi_cmd;
                    948:
                    949:        bzero(&scsipi_cmd, sizeof(scsipi_cmd));
                    950:        scsipi_cmd.opcode = READ_CAPACITY;
                    951:
                    952:        /*
                    953:         * If the command works, interpret the result as a 4 byte
                    954:         * number of blocks
                    955:         */
1.26.2.1  thorpej   956:        if (scsipi_command(periph, (struct scsipi_generic *)&scsipi_cmd,
1.3       enami     957:            sizeof(scsipi_cmd), (u_char *)&rdcap, sizeof(rdcap),
1.26.2.8  bouyer    958:            SCSIPIRETRIES, 20000, NULL,
                    959:            flags | XS_CTL_DATA_IN | XS_CTL_DATA_ONSTACK) != 0) {
1.26.2.1  thorpej   960:                scsipi_printaddr(periph);
1.2       bouyer    961:                printf("could not get size\n");
1.3       enami     962:                return (0);
1.2       bouyer    963:        }
                    964:
1.3       enami     965:        return (_4btol(rdcap.addr) + 1);
1.2       bouyer    966: }
                    967:
                    968: /*
1.26.2.1  thorpej   969:  * scsipi_test_unit_ready:
                    970:  *
                    971:  *     Issue a `test unit ready' request.
1.2       bouyer    972:  */
1.3       enami     973: int
1.26.2.1  thorpej   974: scsipi_test_unit_ready(periph, flags)
                    975:        struct scsipi_periph *periph;
1.2       bouyer    976:        int flags;
                    977: {
                    978:        struct scsipi_test_unit_ready scsipi_cmd;
                    979:
                    980:        /* some ATAPI drives don't support TEST_UNIT_READY. Sigh */
1.26.2.1  thorpej   981:        if (periph->periph_quirks & PQUIRK_NOTUR)
1.3       enami     982:                return (0);
1.2       bouyer    983:
                    984:        bzero(&scsipi_cmd, sizeof(scsipi_cmd));
                    985:        scsipi_cmd.opcode = TEST_UNIT_READY;
                    986:
1.26.2.1  thorpej   987:        return (scsipi_command(periph,
1.3       enami     988:            (struct scsipi_generic *)&scsipi_cmd, sizeof(scsipi_cmd),
1.26.2.8  bouyer    989:            0, 0, SCSIPIRETRIES, 10000, NULL, flags));
1.2       bouyer    990: }
                    991:
                    992: /*
1.26.2.1  thorpej   993:  * scsipi_inquire:
                    994:  *
                    995:  *     Ask the device about itself.
1.2       bouyer    996:  */
1.3       enami     997: int
1.26.2.1  thorpej   998: scsipi_inquire(periph, inqbuf, flags)
                    999:        struct scsipi_periph *periph;
1.2       bouyer   1000:        struct scsipi_inquiry_data *inqbuf;
                   1001:        int flags;
                   1002: {
                   1003:        struct scsipi_inquiry scsipi_cmd;
                   1004:
                   1005:        bzero(&scsipi_cmd, sizeof(scsipi_cmd));
                   1006:        scsipi_cmd.opcode = INQUIRY;
                   1007:        scsipi_cmd.length = sizeof(struct scsipi_inquiry_data);
                   1008:
1.26.2.1  thorpej  1009:        return (scsipi_command(periph,
1.3       enami    1010:            (struct scsipi_generic *) &scsipi_cmd, sizeof(scsipi_cmd),
                   1011:            (u_char *) inqbuf, sizeof(struct scsipi_inquiry_data),
1.26.2.8  bouyer   1012:            SCSIPIRETRIES, 10000, NULL, XS_CTL_DATA_IN | flags));
1.2       bouyer   1013: }
                   1014:
                   1015: /*
1.26.2.1  thorpej  1016:  * scsipi_prevent:
                   1017:  *
                   1018:  *     Prevent or allow the user to remove the media
1.2       bouyer   1019:  */
1.3       enami    1020: int
1.26.2.1  thorpej  1021: scsipi_prevent(periph, type, flags)
                   1022:        struct scsipi_periph *periph;
1.2       bouyer   1023:        int type, flags;
                   1024: {
                   1025:        struct scsipi_prevent scsipi_cmd;
                   1026:
1.26.2.1  thorpej  1027:        if (periph->periph_quirks & PQUIRK_NODOORLOCK)
1.3       enami    1028:                return (0);
1.2       bouyer   1029:
                   1030:        bzero(&scsipi_cmd, sizeof(scsipi_cmd));
                   1031:        scsipi_cmd.opcode = PREVENT_ALLOW;
                   1032:        scsipi_cmd.how = type;
1.26.2.1  thorpej  1033:
                   1034:        return (scsipi_command(periph,
1.3       enami    1035:            (struct scsipi_generic *) &scsipi_cmd, sizeof(scsipi_cmd),
1.26.2.8  bouyer   1036:            0, 0, SCSIPIRETRIES, 5000, NULL, flags));
1.2       bouyer   1037: }
                   1038:
                   1039: /*
1.26.2.1  thorpej  1040:  * scsipi_start:
                   1041:  *
                   1042:  *     Send a START UNIT.
1.2       bouyer   1043:  */
1.3       enami    1044: int
1.26.2.1  thorpej  1045: scsipi_start(periph, type, flags)
                   1046:        struct scsipi_periph *periph;
1.2       bouyer   1047:        int type, flags;
                   1048: {
                   1049:        struct scsipi_start_stop scsipi_cmd;
1.18      bouyer   1050:
1.26.2.1  thorpej  1051:        if (periph->periph_quirks & PQUIRK_NOSTARTUNIT)
1.18      bouyer   1052:                return 0;
1.2       bouyer   1053:
                   1054:        bzero(&scsipi_cmd, sizeof(scsipi_cmd));
                   1055:        scsipi_cmd.opcode = START_STOP;
                   1056:        scsipi_cmd.byte2 = 0x00;
                   1057:        scsipi_cmd.how = type;
1.26.2.1  thorpej  1058:
                   1059:        return (scsipi_command(periph,
1.3       enami    1060:            (struct scsipi_generic *) &scsipi_cmd, sizeof(scsipi_cmd),
1.26.2.8  bouyer   1061:            0, 0, SCSIPIRETRIES, (type & SSS_START) ? 60000 : 10000,
                   1062:            NULL, flags));
1.2       bouyer   1063: }
                   1064:
                   1065: /*
1.26.2.1  thorpej  1066:  * scsipi_done:
                   1067:  *
                   1068:  *     This routine is called by an adapter's interrupt handler when
                   1069:  *     an xfer is completed.
1.2       bouyer   1070:  */
1.3       enami    1071: void
1.2       bouyer   1072: scsipi_done(xs)
                   1073:        struct scsipi_xfer *xs;
                   1074: {
1.26.2.1  thorpej  1075:        struct scsipi_periph *periph = xs->xs_periph;
                   1076:        struct scsipi_channel *chan = periph->periph_channel;
                   1077:        int s, freezecnt;
1.2       bouyer   1078:
1.26.2.6  thorpej  1079:        SC_DEBUG(periph, SCSIPI_DB2, ("scsipi_done\n"));
                   1080: #ifdef SCSIPI_DEBUG
                   1081:        if (periph->periph_dbflags & SCSIPI_DB1)
1.2       bouyer   1082:                show_scsipi_cmd(xs);
1.26.2.6  thorpej  1083: #endif
1.2       bouyer   1084:
1.26.2.1  thorpej  1085:        s = splbio();
                   1086:        /*
                   1087:         * The resource this command was using is now free.
                   1088:         */
                   1089:        scsipi_put_resource(chan);
1.26.2.15  bouyer   1090:        xs->xs_periph->periph_sent--;
1.26.2.1  thorpej  1091:
                   1092:        /*
                   1093:         * If the command was tagged, free the tag.
                   1094:         */
                   1095:        if (XS_CTL_TAGTYPE(xs) != 0)
                   1096:                scsipi_put_tag(xs);
1.26.2.13  bouyer   1097:        else
                   1098:                periph->periph_flags &= ~PERIPH_UNTAG;
1.26.2.1  thorpej  1099:
                   1100:        /* Mark the command as `done'. */
                   1101:        xs->xs_status |= XS_STS_DONE;
                   1102:
                   1103: #ifdef DIAGNOSTIC
                   1104:        if ((xs->xs_control & (XS_CTL_ASYNC|XS_CTL_POLL)) ==
                   1105:            (XS_CTL_ASYNC|XS_CTL_POLL))
                   1106:                panic("scsipi_done: ASYNC and POLL");
                   1107: #endif
                   1108:
                   1109:        /*
                   1110:         * If the xfer had an error of any sort, freeze the
                   1111:         * periph's queue.  Freeze it again if we were requested
                   1112:         * to do so in the xfer.
                   1113:         */
                   1114:        freezecnt = 0;
                   1115:        if (xs->error != XS_NOERROR)
                   1116:                freezecnt++;
                   1117:        if (xs->xs_control & XS_CTL_FREEZE_PERIPH)
                   1118:                freezecnt++;
                   1119:        if (freezecnt != 0)
                   1120:                scsipi_periph_freeze(periph, freezecnt);
                   1121:
                   1122:        /*
1.26.2.9  bouyer   1123:         * record the xfer with a pending sense, in case a SCSI reset is
                   1124:         * received before the thread is waked up.
                   1125:         */
                   1126:        if (xs->error == XS_BUSY && xs->status == SCSI_CHECK) {
                   1127:                periph->periph_flags |= PERIPH_SENSE;
                   1128:                periph->periph_xscheck = xs;
                   1129:        }
                   1130:
                   1131:        /*
1.26.2.1  thorpej  1132:         * If this was an xfer that was not to complete asynchrnously,
                   1133:         * let the requesting thread perform error checking/handling
                   1134:         * in its context.
                   1135:         */
1.24      thorpej  1136:        if ((xs->xs_control & XS_CTL_ASYNC) == 0) {
1.26.2.1  thorpej  1137:                splx(s);
1.2       bouyer   1138:                /*
1.26.2.1  thorpej  1139:                 * If it's a polling job, just return, to unwind the
                   1140:                 * call graph.  We don't need to restart the queue,
                   1141:                 * because pollings jobs are treated specially, and
                   1142:                 * are really only used during crash dumps anyway
                   1143:                 * (XXX or during boot-time autconfiguration of
                   1144:                 * ATAPI devices).
1.2       bouyer   1145:                 */
1.26.2.1  thorpej  1146:                if (xs->xs_control & XS_CTL_POLL)
                   1147:                        return;
1.2       bouyer   1148:                wakeup(xs);
1.26.2.1  thorpej  1149:                goto out;
1.2       bouyer   1150:        }
                   1151:
                   1152:        /*
1.26.2.1  thorpej  1153:         * Catch the extremely common case of I/O completing
                   1154:         * without error; no use in taking a context switch
                   1155:         * if we can handle it in interrupt context.
1.2       bouyer   1156:         */
1.26.2.1  thorpej  1157:        if (xs->error == XS_NOERROR) {
                   1158:                splx(s);
                   1159:                (void) scsipi_complete(xs);
                   1160:                goto out;
1.20      bouyer   1161:        }
1.2       bouyer   1162:
1.9       scottr   1163:        /*
1.26.2.1  thorpej  1164:         * There is an error on this xfer.  Put it on the channel's
                   1165:         * completion queue, and wake up the completion thread.
1.9       scottr   1166:         */
1.26.2.1  thorpej  1167:        TAILQ_INSERT_TAIL(&chan->chan_complete, xs, channel_q);
                   1168:        splx(s);
                   1169:        wakeup(&chan->chan_complete);
                   1170:
                   1171:  out:
                   1172:        /*
                   1173:         * If there are more xfers on the channel's queue, attempt to
                   1174:         * run them.
                   1175:         */
                   1176:        scsipi_run_queue(chan);
1.2       bouyer   1177: }
                   1178:
1.26.2.1  thorpej  1179: /*
                   1180:  * scsipi_complete:
                   1181:  *
                   1182:  *     Completion of a scsipi_xfer.  This is the guts of scsipi_done().
                   1183:  *
                   1184:  *     NOTE: This routine MUST be called with valid thread context
                   1185:  *     except for the case where the following two conditions are
                   1186:  *     true:
                   1187:  *
                   1188:  *             xs->error == XS_NOERROR
                   1189:  *             XS_CTL_ASYNC is set in xs->xs_control
                   1190:  *
                   1191:  *     The semantics of this routine can be tricky, so here is an
                   1192:  *     explanation:
                   1193:  *
                   1194:  *             0               Xfer completed successfully.
                   1195:  *
                   1196:  *             ERESTART        Xfer had an error, but was restarted.
                   1197:  *
                   1198:  *             anything else   Xfer had an error, return value is Unix
                   1199:  *                             errno.
                   1200:  *
                   1201:  *     If the return value is anything but ERESTART:
                   1202:  *
                   1203:  *             - If XS_CTL_ASYNC is set, `xs' has been freed back to
                   1204:  *               the pool.
                   1205:  *             - If there is a buf associated with the xfer,
                   1206:  *               it has been biodone()'d.
                   1207:  */
1.2       bouyer   1208: int
1.26.2.1  thorpej  1209: scsipi_complete(xs)
1.2       bouyer   1210:        struct scsipi_xfer *xs;
                   1211: {
1.26.2.1  thorpej  1212:        struct scsipi_periph *periph = xs->xs_periph;
                   1213:        struct scsipi_channel *chan = periph->periph_channel;
                   1214:        struct buf *bp;
                   1215:        int error, s;
1.2       bouyer   1216:
1.26.2.1  thorpej  1217: #ifdef DIAGNOSTIC
                   1218:        if ((xs->xs_control & XS_CTL_ASYNC) != 0 && xs->bp == NULL)
                   1219:                panic("scsipi_complete: XS_CTL_ASYNC but no buf");
                   1220: #endif
1.26.2.9  bouyer   1221:        /*
                   1222:         * If command terminated with a CHECK CONDITION, we need to issue a
                   1223:         * REQUEST_SENSE command. Once the REQUEST_SENSE has been processed
                   1224:         * we'll have the real status.
                   1225:         * Must be processed at splbio() to avoid missing a SCSI bus reset
                   1226:         * for this command.
                   1227:         */
                   1228:        s = splbio();
                   1229:        if (xs->error == XS_BUSY && xs->status == SCSI_CHECK) {
                   1230:                /* request sense for a request sense ? */
                   1231:                if (xs->xs_control & XS_CTL_REQSENSE) {
                   1232:                        scsipi_printaddr(periph);
1.26.2.12  bouyer   1233:                        /* XXX maybe we should reset the device ? */
1.26.2.10  bouyer   1234:                        /* we've been frozen because xs->error != XS_NOERROR */
                   1235:                        scsipi_periph_thaw(periph, 1);
                   1236:                        splx(s);
1.26.2.12  bouyer   1237:                        return EINVAL;
1.26.2.9  bouyer   1238:                }
                   1239:                scsipi_request_sense(xs);
                   1240:        }
                   1241:        splx(s);
                   1242:        /*
                   1243:         * If it's a user level request, bypass all usual completion
                   1244:         * processing, let the user work it out..
                   1245:         */
                   1246:        if ((xs->xs_control & XS_CTL_USERCMD) != 0) {
                   1247:                SC_DEBUG(periph, SCSIPI_DB3, ("calling user done()\n"));
1.26.2.10  bouyer   1248:                if (xs->error != XS_NOERROR)
                   1249:                        scsipi_periph_thaw(periph, 1);
1.26.2.9  bouyer   1250:                scsipi_user_done(xs);
                   1251:                SC_DEBUG(periph, SCSIPI_DB3, ("returned from user done()\n "));
                   1252:                return 0;
                   1253:        }
                   1254:
1.2       bouyer   1255:
1.26.2.1  thorpej  1256:        switch (xs->error) {
                   1257:        case XS_NOERROR:
                   1258:                error = 0;
                   1259:                break;
                   1260:
                   1261:        case XS_SENSE:
                   1262:        case XS_SHORTSENSE:
                   1263:                error = (*chan->chan_bustype->bustype_interpret_sense)(xs);
                   1264:                break;
                   1265:
                   1266:        case XS_RESOURCE_SHORTAGE:
                   1267:                /*
                   1268:                 * XXX Should freeze channel's queue.
                   1269:                 */
                   1270:                scsipi_printaddr(periph);
                   1271:                printf("adapter resource shortage\n");
                   1272:                /* FALLTHROUGH */
                   1273:
                   1274:        case XS_BUSY:
                   1275:                if (xs->error == XS_BUSY && xs->status == SCSI_QUEUE_FULL) {
                   1276:                        struct scsipi_max_openings mo;
                   1277:
                   1278:                        /*
                   1279:                         * We set the openings to active - 1, assuming that
                   1280:                         * the command that got us here is the first one that
                   1281:                         * can't fit into the device's queue.  If that's not
                   1282:                         * the case, I guess we'll find out soon enough.
                   1283:                         */
                   1284:                        mo.mo_target = periph->periph_target;
                   1285:                        mo.mo_lun = periph->periph_lun;
                   1286:                        mo.mo_openings = periph->periph_active - 1;
1.2       bouyer   1287: #ifdef DIAGNOSTIC
1.26.2.1  thorpej  1288:                        if (mo.mo_openings < 0) {
                   1289:                                scsipi_printaddr(periph);
                   1290:                                printf("QUEUE FULL resulted in < 0 openings\n");
                   1291:                                panic("scsipi_done");
                   1292:                        }
1.2       bouyer   1293: #endif
1.26.2.1  thorpej  1294:                        if (mo.mo_openings == 0) {
                   1295:                                scsipi_printaddr(periph);
                   1296:                                printf("QUEUE FULL resulted in 0 openings\n");
                   1297:                                mo.mo_openings = 1;
                   1298:                        }
                   1299:                        scsipi_async_event(chan, ASYNC_EVENT_MAX_OPENINGS, &mo);
                   1300:                        error = ERESTART;
                   1301:                } else if (xs->xs_retries != 0) {
                   1302:                        xs->xs_retries--;
                   1303:                        /*
                   1304:                         * Wait one second, and try again.
                   1305:                         */
                   1306:                        if (xs->xs_control & XS_CTL_POLL)
                   1307:                                delay(1000000);
                   1308:                        else {
                   1309:                                scsipi_periph_freeze(periph, 1);
1.26.2.8  bouyer   1310:                                callout_reset(&periph->periph_callout,
                   1311:                                    hz, scsipi_periph_timed_thaw, periph);
1.26.2.1  thorpej  1312:                        }
                   1313:                        error = ERESTART;
                   1314:                } else
                   1315:                        error = EBUSY;
                   1316:                break;
1.2       bouyer   1317:
1.26.2.10  bouyer   1318:        case XS_REQUEUE:
                   1319:                error = ERESTART;
                   1320:                break;
                   1321:
1.26.2.1  thorpej  1322:        case XS_TIMEOUT:
                   1323:                if (xs->xs_retries != 0) {
                   1324:                        xs->xs_retries--;
                   1325:                        error = ERESTART;
                   1326:                } else
                   1327:                        error = EIO;
                   1328:                break;
                   1329:
                   1330:        case XS_SELTIMEOUT:
                   1331:                /* XXX Disable device? */
                   1332:                error = EIO;
                   1333:                break;
                   1334:
                   1335:        case XS_RESET:
1.26.2.9  bouyer   1336:                if (xs->xs_control & XS_CTL_REQSENSE) {
                   1337:                        /*
                   1338:                         * request sense interrupted by reset: signal it
                   1339:                         * with EINTR return code.
                   1340:                         */
                   1341:                        error = EINTR;
                   1342:                } else {
                   1343:                        if (xs->xs_retries != 0) {
                   1344:                                xs->xs_retries--;
                   1345:                                error = ERESTART;
                   1346:                        } else
                   1347:                                error = EIO;
                   1348:                }
1.26.2.1  thorpej  1349:                break;
1.2       bouyer   1350:
                   1351:        default:
1.26.2.1  thorpej  1352:                scsipi_printaddr(periph);
                   1353:                printf("invalid return code from adapter: %d\n", xs->error);
                   1354:                error = EIO;
                   1355:                break;
1.2       bouyer   1356:        }
                   1357:
1.26.2.1  thorpej  1358:        s = splbio();
                   1359:        if (error == ERESTART) {
                   1360:                /*
                   1361:                 * If we get here, the periph has been thawed and frozen
                   1362:                 * again if we had to issue recovery commands.  Alternatively,
                   1363:                 * it may have been frozen again and in a timed thaw.  In
                   1364:                 * any case, we thaw the periph once we re-enqueue the
                   1365:                 * command.  Once the periph is fully thawed, it will begin
                   1366:                 * operation again.
                   1367:                 */
                   1368:                xs->error = XS_NOERROR;
                   1369:                xs->status = SCSI_OK;
                   1370:                xs->xs_status &= ~XS_STS_DONE;
                   1371:                xs->xs_requeuecnt++;
                   1372:                error = scsipi_enqueue(xs);
                   1373:                if (error == 0) {
                   1374:                        scsipi_periph_thaw(periph, 1);
                   1375:                        splx(s);
                   1376:                        return (ERESTART);
                   1377:                }
                   1378:        }
                   1379:
                   1380:        /*
                   1381:         * scsipi_done() freezes the queue if not XS_NOERROR.
                   1382:         * Thaw it here.
                   1383:         */
                   1384:        if (xs->error != XS_NOERROR)
                   1385:                scsipi_periph_thaw(periph, 1);
                   1386:
                   1387:        if ((bp = xs->bp) != NULL) {
                   1388:                if (error) {
                   1389:                        bp->b_error = error;
                   1390:                        bp->b_flags |= B_ERROR;
                   1391:                        bp->b_resid = bp->b_bcount;
                   1392:                } else {
                   1393:                        bp->b_error = 0;
                   1394:                        bp->b_resid = xs->resid;
                   1395:                }
                   1396:                biodone(bp);
                   1397:        }
                   1398:
                   1399:        if (xs->xs_control & XS_CTL_ASYNC)
                   1400:                scsipi_put_xs(xs);
                   1401:        splx(s);
                   1402:
                   1403:        return (error);
                   1404: }
                   1405:
                   1406: /*
1.26.2.9  bouyer   1407:  * Issue a request sense for the given scsipi_xfer. Called when the xfer
                   1408:  * returns with a CHECK_CONDITION status. Must be called in valid thread
                   1409:  * context and at splbio().
                   1410:  */
                   1411:
                   1412: void
                   1413: scsipi_request_sense(xs)
                   1414:        struct scsipi_xfer *xs;
                   1415: {
                   1416:        struct scsipi_periph *periph = xs->xs_periph;
                   1417:        int flags, error;
                   1418:        struct scsipi_sense cmd;
                   1419:
                   1420:        periph->periph_flags |= PERIPH_SENSE;
                   1421:
                   1422:        /* if command was polling, request sense will too */
                   1423:        flags = xs->xs_control & XS_CTL_POLL;
                   1424:        /* Polling commands can't sleep */
                   1425:        if (flags)
                   1426:                flags |= XS_CTL_NOSLEEP;
                   1427:
                   1428:        flags |= XS_CTL_REQSENSE | XS_CTL_URGENT | XS_CTL_DATA_IN |
                   1429:            XS_CTL_THAW_PERIPH | XS_CTL_FREEZE_PERIPH;
                   1430:
                   1431:        bzero(&cmd, sizeof(cmd));
                   1432:        cmd.opcode = REQUEST_SENSE;
                   1433:        cmd.length = sizeof(struct scsipi_sense_data);
                   1434:
                   1435:        error = scsipi_command(periph,
                   1436:            (struct scsipi_generic *) &cmd, sizeof(cmd),
                   1437:            (u_char*)&xs->sense.scsi_sense, sizeof(struct scsipi_sense_data),
                   1438:            0, 1000, NULL, flags);
                   1439:        periph->periph_flags &= ~PERIPH_SENSE;
                   1440:        periph->periph_xscheck = NULL;
                   1441:        switch(error) {
                   1442:        case 0:
                   1443:                /* we have a valid sense */
                   1444:                xs->error = XS_SENSE;
                   1445:                return;
                   1446:        case EINTR:
                   1447:                /* REQUEST_SENSE interrupted by bus reset. */
                   1448:                xs->error = XS_RESET;
1.26.2.12  bouyer   1449:                return;
                   1450:        case EIO:
                   1451:                 /* request sense coudn't be performed */
                   1452:                /*
                   1453:                 * XXX this isn't quite rigth but we don't have anything
                   1454:                 * better for now
                   1455:                 */
                   1456:                xs->error = XS_DRIVER_STUFFUP;
1.26.2.9  bouyer   1457:                return;
                   1458:        default:
                   1459:                 /* Notify that request sense failed. */
                   1460:                xs->error = XS_DRIVER_STUFFUP;
                   1461:                scsipi_printaddr(periph);
                   1462:                printf("request sense failed with error %d\n", error);
                   1463:                return;
                   1464:        }
                   1465: }
                   1466:
                   1467: /*
1.26.2.1  thorpej  1468:  * scsipi_enqueue:
                   1469:  *
                   1470:  *     Enqueue an xfer on a channel.
                   1471:  */
                   1472: int
                   1473: scsipi_enqueue(xs)
                   1474:        struct scsipi_xfer *xs;
                   1475: {
                   1476:        struct scsipi_channel *chan = xs->xs_periph->periph_channel;
                   1477:        struct scsipi_xfer *qxs;
                   1478:        int s;
                   1479:
                   1480:        s = splbio();
                   1481:
                   1482:        /*
                   1483:         * If the xfer is to be polled, and there are already jobs on
                   1484:         * the queue, we can't proceed.
                   1485:         */
                   1486:        if ((xs->xs_control & XS_CTL_POLL) != 0 &&
                   1487:            TAILQ_FIRST(&chan->chan_queue) != NULL) {
                   1488:                splx(s);
                   1489:                xs->error = XS_DRIVER_STUFFUP;
                   1490:                return (EAGAIN);
                   1491:        }
                   1492:
                   1493:        /*
                   1494:         * If we have an URGENT xfer, it's an error recovery command
                   1495:         * and it should just go on the head of the channel's queue.
                   1496:         */
                   1497:        if (xs->xs_control & XS_CTL_URGENT) {
                   1498:                TAILQ_INSERT_HEAD(&chan->chan_queue, xs, channel_q);
                   1499:                goto out;
                   1500:        }
                   1501:
                   1502:        /*
                   1503:         * If this xfer has already been on the queue before, we
                   1504:         * need to reinsert it in the correct order.  That order is:
                   1505:         *
                   1506:         *      Immediately before the first xfer for this periph
                   1507:         *      with a requeuecnt less than xs->xs_requeuecnt.
                   1508:         *
                   1509:         * Failing that, at the end of the queue.  (We'll end up
                   1510:         * there naturally.)
                   1511:         */
                   1512:        if (xs->xs_requeuecnt != 0) {
                   1513:                for (qxs = TAILQ_FIRST(&chan->chan_queue); qxs != NULL;
                   1514:                     qxs = TAILQ_NEXT(qxs, channel_q)) {
                   1515:                        if (qxs->xs_periph == xs->xs_periph &&
                   1516:                            qxs->xs_requeuecnt < xs->xs_requeuecnt)
                   1517:                                break;
                   1518:                }
                   1519:                if (qxs != NULL) {
                   1520:                        TAILQ_INSERT_AFTER(&chan->chan_queue, qxs, xs,
                   1521:                            channel_q);
                   1522:                        goto out;
                   1523:                }
                   1524:        }
                   1525:        TAILQ_INSERT_TAIL(&chan->chan_queue, xs, channel_q);
                   1526:  out:
                   1527:        if (xs->xs_control & XS_CTL_THAW_PERIPH)
                   1528:                scsipi_periph_thaw(xs->xs_periph, 1);
                   1529:        splx(s);
                   1530:        return (0);
                   1531: }
                   1532:
                   1533: /*
                   1534:  * scsipi_run_queue:
                   1535:  *
                   1536:  *     Start as many xfers as possible running on the channel.
                   1537:  */
                   1538: void
                   1539: scsipi_run_queue(chan)
                   1540:        struct scsipi_channel *chan;
                   1541: {
                   1542:        struct scsipi_xfer *xs;
                   1543:        struct scsipi_periph *periph;
                   1544:        int s;
                   1545:
                   1546:        for (;;) {
                   1547:                s = splbio();
1.26.2.3  thorpej  1548:
                   1549:                /*
                   1550:                 * If the channel is frozen, we can't do any work right
                   1551:                 * now.
                   1552:                 */
                   1553:                if (chan->chan_qfreeze != 0) {
                   1554:                        splx(s);
                   1555:                        return;
                   1556:                }
                   1557:
1.26.2.1  thorpej  1558:                /*
                   1559:                 * Look for work to do, and make sure we can do it.
                   1560:                 */
                   1561:                for (xs = TAILQ_FIRST(&chan->chan_queue); xs != NULL;
                   1562:                     xs = TAILQ_NEXT(xs, channel_q)) {
                   1563:                        periph = xs->xs_periph;
                   1564:
1.26.2.15  bouyer   1565:                        if ((periph->periph_sent >= periph->periph_openings) ||
                   1566:                            periph->periph_qfreeze != 0 ||
1.26.2.13  bouyer   1567:                            (periph->periph_flags & PERIPH_UNTAG) != 0)
1.26.2.1  thorpej  1568:                                continue;
                   1569:
1.26.2.9  bouyer   1570:                        if ((periph->periph_flags &
                   1571:                            (PERIPH_RECOVERING | PERIPH_SENSE)) != 0 &&
1.26.2.1  thorpej  1572:                            (xs->xs_control & XS_CTL_URGENT) == 0)
                   1573:                                continue;
                   1574:
                   1575:                        /*
                   1576:                         * We can issue this xfer!
                   1577:                         */
                   1578:                        goto got_one;
                   1579:                }
                   1580:
                   1581:                /*
                   1582:                 * Can't find any work to do right now.
                   1583:                 */
                   1584:                splx(s);
                   1585:                return;
                   1586:
                   1587:  got_one:
                   1588:                /*
                   1589:                 * Have an xfer to run.  Allocate a resource from
                   1590:                 * the adapter to run it.  If we can't allocate that
                   1591:                 * resource, we don't dequeue the xfer.
                   1592:                 */
                   1593:                if (scsipi_get_resource(chan) == 0) {
                   1594:                        /*
                   1595:                         * Adapter is out of resources.  If the adapter
                   1596:                         * supports it, attempt to grow them.
                   1597:                         */
                   1598:                        if (scsipi_grow_resources(chan) == 0) {
                   1599:                                /*
                   1600:                                 * Wasn't able to grow resources,
                   1601:                                 * nothing more we can do.
                   1602:                                 */
                   1603:                                if (xs->xs_control & XS_CTL_POLL) {
                   1604:                                        scsipi_printaddr(xs->xs_periph);
                   1605:                                        printf("polling command but no "
                   1606:                                            "adapter resources");
                   1607:                                        /* We'll panic shortly... */
                   1608:                                }
                   1609:                                splx(s);
1.26.2.16  mjacob   1610:
                   1611:                                /*
                   1612:                                 * XXX: We should be able to note that
                   1613:                                 * XXX: that resources are needed here!
                   1614:                                 */
1.26.2.1  thorpej  1615:                                return;
                   1616:                        }
                   1617:                        /*
                   1618:                         * scsipi_grow_resources() allocated the resource
                   1619:                         * for us.
                   1620:                         */
                   1621:                }
                   1622:
                   1623:                /*
                   1624:                 * We have a resource to run this xfer, do it!
                   1625:                 */
                   1626:                TAILQ_REMOVE(&chan->chan_queue, xs, channel_q);
                   1627:
                   1628:                /*
                   1629:                 * If the command is to be tagged, allocate a tag ID
                   1630:                 * for it.
                   1631:                 */
                   1632:                if (XS_CTL_TAGTYPE(xs) != 0)
                   1633:                        scsipi_get_tag(xs);
1.26.2.13  bouyer   1634:                else
                   1635:                        periph->periph_flags |= PERIPH_UNTAG;
1.26.2.15  bouyer   1636:                periph->periph_sent++;
1.26.2.1  thorpej  1637:                splx(s);
                   1638:
                   1639:                scsipi_adapter_request(chan, ADAPTER_REQ_RUN_XFER, xs);
                   1640:        }
1.2       bouyer   1641: #ifdef DIAGNOSTIC
1.26.2.1  thorpej  1642:        panic("scsipi_run_queue: impossible");
1.2       bouyer   1643: #endif
                   1644: }
                   1645:
1.26.2.1  thorpej  1646: /*
                   1647:  * scsipi_execute_xs:
                   1648:  *
                   1649:  *     Begin execution of an xfer, waiting for it to complete, if necessary.
                   1650:  */
1.3       enami    1651: int
1.26.2.1  thorpej  1652: scsipi_execute_xs(xs)
1.2       bouyer   1653:        struct scsipi_xfer *xs;
                   1654: {
1.26.2.1  thorpej  1655:        struct scsipi_periph *periph = xs->xs_periph;
                   1656:        struct scsipi_channel *chan = periph->periph_channel;
                   1657:        int async, poll, retries, error, s;
                   1658:
                   1659:        xs->xs_status &= ~XS_STS_DONE;
                   1660:        xs->error = XS_NOERROR;
                   1661:        xs->resid = xs->datalen;
                   1662:        xs->status = SCSI_OK;
                   1663:
1.26.2.6  thorpej  1664: #ifdef SCSIPI_DEBUG
                   1665:        if (xs->xs_periph->periph_dbflags & SCSIPI_DB3) {
                   1666:                printf("scsipi_execute_xs: ");
1.26.2.1  thorpej  1667:                show_scsipi_xs(xs);
                   1668:                printf("\n");
                   1669:        }
                   1670: #endif
1.2       bouyer   1671:
1.26.2.1  thorpej  1672:        /*
                   1673:         * Deal with command tagging:
                   1674:         *
                   1675:         *      - If the device's current operating mode doesn't
                   1676:         *        include tagged queueing, clear the tag mask.
                   1677:         *
                   1678:         *      - If the device's current operating mode *does*
                   1679:         *        include tagged queueing, set the tag_type in
                   1680:         *        the xfer to the appropriate byte for the tag
                   1681:         *        message.
                   1682:         */
1.26.2.9  bouyer   1683:        if ((PERIPH_XFER_MODE(periph) & PERIPH_CAP_TQING) == 0 ||
                   1684:                (xs->xs_control & XS_CTL_REQSENSE)) {
1.26.2.1  thorpej  1685:                xs->xs_control &= ~XS_CTL_TAGMASK;
                   1686:                xs->xs_tag_type = 0;
                   1687:        } else {
                   1688:                /*
                   1689:                 * If the request doesn't specify a tag, give Head
                   1690:                 * tags to URGENT operations and Ordered tags to
                   1691:                 * everything else.
                   1692:                 */
                   1693:                if (XS_CTL_TAGTYPE(xs) == 0) {
                   1694:                        if (xs->xs_control & XS_CTL_URGENT)
                   1695:                                xs->xs_control |= XS_CTL_HEAD_TAG;
                   1696:                        else
                   1697:                                xs->xs_control |= XS_CTL_ORDERED_TAG;
                   1698:                }
                   1699:
                   1700:                switch (XS_CTL_TAGTYPE(xs)) {
                   1701:                case XS_CTL_ORDERED_TAG:
                   1702:                        xs->xs_tag_type = MSG_ORDERED_Q_TAG;
                   1703:                        break;
                   1704:
                   1705:                case XS_CTL_SIMPLE_TAG:
                   1706:                        xs->xs_tag_type = MSG_SIMPLE_Q_TAG;
                   1707:                        break;
                   1708:
                   1709:                case XS_CTL_HEAD_TAG:
                   1710:                        xs->xs_tag_type = MSG_HEAD_OF_Q_TAG;
                   1711:                        break;
                   1712:
                   1713:                default:
                   1714:                        scsipi_printaddr(periph);
                   1715:                        printf("invalid tag mask 0x%08x\n",
                   1716:                            XS_CTL_TAGTYPE(xs));
                   1717:                        panic("scsipi_execute_xs");
                   1718:                }
                   1719:        }
1.2       bouyer   1720:
                   1721:        /*
1.26.2.1  thorpej  1722:         * If we don't yet have a completion thread, or we are to poll for
                   1723:         * completion, clear the ASYNC flag.
1.2       bouyer   1724:         */
1.26.2.1  thorpej  1725:        if (chan->chan_thread == NULL || (xs->xs_control & XS_CTL_POLL) != 0)
                   1726:                xs->xs_control &= ~XS_CTL_ASYNC;
1.2       bouyer   1727:
1.26.2.1  thorpej  1728:        async = (xs->xs_control & XS_CTL_ASYNC);
                   1729:        poll = (xs->xs_control & XS_CTL_POLL);
                   1730:        retries = xs->xs_retries;               /* for polling commands */
1.2       bouyer   1731:
1.26.2.1  thorpej  1732: #ifdef DIAGNOSTIC
                   1733:        if (async != 0 && xs->bp == NULL)
                   1734:                panic("scsipi_execute_xs: XS_CTL_ASYNC but no buf");
1.2       bouyer   1735: #endif
1.26.2.1  thorpej  1736:
                   1737:        /*
                   1738:         * Enqueue the transfer.  If we're not polling for completion, this
                   1739:         * should ALWAYS return `no error'.
                   1740:         */
                   1741:  try_again:
                   1742:        error = scsipi_enqueue(xs);
                   1743:        if (error) {
                   1744:                if (poll == 0) {
                   1745:                        scsipi_printaddr(periph);
                   1746:                        printf("not polling, but enqueue failed with %d\n",
                   1747:                            error);
                   1748:                        panic("scsipi_execute_xs");
1.2       bouyer   1749:                }
1.26.2.1  thorpej  1750:
                   1751:                scsipi_printaddr(periph);
                   1752:                printf("failed to enqueue polling command");
                   1753:                if (retries != 0) {
                   1754:                        printf(", retrying...\n");
                   1755:                        delay(1000000);
                   1756:                        retries--;
                   1757:                        goto try_again;
1.2       bouyer   1758:                }
1.26.2.1  thorpej  1759:                printf("\n");
                   1760:                goto free_xs;
                   1761:        }
1.2       bouyer   1762:
1.26.2.1  thorpej  1763:  restarted:
                   1764:        scsipi_run_queue(chan);
1.12      thorpej  1765:
1.26.2.1  thorpej  1766:        /*
                   1767:         * The xfer is enqueued, and possibly running.  If it's to be
                   1768:         * completed asynchronously, just return now.
                   1769:         */
                   1770:        if (async)
                   1771:                return (EJUSTRETURN);
                   1772:
                   1773:        /*
                   1774:         * Not an asynchronous command; wait for it to complete.
                   1775:         */
1.26.2.16  mjacob   1776:        s = splbio();
1.26.2.1  thorpej  1777:        while ((xs->xs_status & XS_STS_DONE) == 0) {
                   1778:                if (poll) {
                   1779:                        scsipi_printaddr(periph);
                   1780:                        printf("polling command not done\n");
                   1781:                        panic("scsipi_execute_xs");
1.12      thorpej  1782:                }
1.26.2.1  thorpej  1783:                (void) tsleep(xs, PRIBIO, "xscmd", 0);
                   1784:        }
1.26.2.16  mjacob   1785:        splx(s);
1.2       bouyer   1786:
1.26.2.1  thorpej  1787:        /*
                   1788:         * Command is complete.  scsipi_done() has awakened us to perform
                   1789:         * the error handling.
                   1790:         */
                   1791:        error = scsipi_complete(xs);
                   1792:        if (error == ERESTART)
                   1793:                goto restarted;
                   1794:
                   1795:        /*
                   1796:         * Command completed successfully or fatal error occurred.  Fall
                   1797:         * into....
                   1798:         */
                   1799:  free_xs:
                   1800:        s = splbio();
                   1801:        scsipi_put_xs(xs);
                   1802:        splx(s);
                   1803:
                   1804:        /*
                   1805:         * Kick the queue, keep it running in case it stopped for some
                   1806:         * reason.
                   1807:         */
                   1808:        scsipi_run_queue(chan);
                   1809:
                   1810:        return (error);
                   1811: }
                   1812:
                   1813: /*
                   1814:  * scsipi_completion_thread:
                   1815:  *
                   1816:  *     This is the completion thread.  We wait for errors on
                   1817:  *     asynchronous xfers, and perform the error handling
                   1818:  *     function, restarting the command, if necessary.
                   1819:  */
                   1820: void
                   1821: scsipi_completion_thread(arg)
                   1822:        void *arg;
                   1823: {
                   1824:        struct scsipi_channel *chan = arg;
                   1825:        struct scsipi_xfer *xs;
                   1826:        int s;
                   1827:
1.26.2.7  thorpej  1828:        for (;;) {
1.26.2.1  thorpej  1829:                s = splbio();
1.26.2.7  thorpej  1830:                xs = TAILQ_FIRST(&chan->chan_complete);
                   1831:                if (xs == NULL &&
                   1832:                    (chan->chan_flags & SCSIPI_CHAN_SHUTDOWN) == 0) {
1.26.2.1  thorpej  1833:                        (void) tsleep(&chan->chan_complete, PRIBIO,
                   1834:                            "sccomp", 0);
1.26.2.17! bouyer   1835:                        splx(s);
1.26.2.1  thorpej  1836:                        continue;
1.26.2.7  thorpej  1837:                }
                   1838:                if (chan->chan_flags & SCSIPI_CHAN_SHUTDOWN) {
                   1839:                        splx(s);
                   1840:                        break;
1.26.2.1  thorpej  1841:                }
                   1842:                TAILQ_REMOVE(&chan->chan_complete, xs, channel_q);
                   1843:                splx(s);
                   1844:
                   1845:                /*
                   1846:                 * Have an xfer with an error; process it.
                   1847:                 */
                   1848:                (void) scsipi_complete(xs);
                   1849:
                   1850:                /*
                   1851:                 * Kick the queue; keep it running if it was stopped
                   1852:                 * for some reason.
                   1853:                 */
                   1854:                scsipi_run_queue(chan);
                   1855:        }
                   1856:
                   1857:        chan->chan_thread = NULL;
                   1858:
                   1859:        /* In case parent is waiting for us to exit. */
                   1860:        wakeup(&chan->chan_thread);
                   1861:
                   1862:        kthread_exit(0);
                   1863: }
                   1864:
                   1865: /*
                   1866:  * scsipi_create_completion_thread:
                   1867:  *
                   1868:  *     Callback to actually create the completion thread.
                   1869:  */
                   1870: void
                   1871: scsipi_create_completion_thread(arg)
                   1872:        void *arg;
                   1873: {
                   1874:        struct scsipi_channel *chan = arg;
                   1875:        struct scsipi_adapter *adapt = chan->chan_adapter;
                   1876:
                   1877:        if (kthread_create1(scsipi_completion_thread, chan,
                   1878:            &chan->chan_thread, "%s:%d", adapt->adapt_dev->dv_xname,
                   1879:            chan->chan_channel)) {
                   1880:                printf("%s: unable to create completion thread for "
                   1881:                    "channel %d\n", adapt->adapt_dev->dv_xname,
                   1882:                    chan->chan_channel);
                   1883:                panic("scsipi_create_completion_thread");
                   1884:        }
                   1885: }
                   1886:
                   1887: /*
                   1888:  * scsipi_async_event:
                   1889:  *
                   1890:  *     Handle an asynchronous event from an adapter.
                   1891:  */
                   1892: void
                   1893: scsipi_async_event(chan, event, arg)
                   1894:        struct scsipi_channel *chan;
                   1895:        scsipi_async_event_t event;
                   1896:        void *arg;
                   1897: {
                   1898:        int s;
                   1899:
                   1900:        s = splbio();
                   1901:        switch (event) {
                   1902:        case ASYNC_EVENT_MAX_OPENINGS:
                   1903:                scsipi_async_event_max_openings(chan,
                   1904:                    (struct scsipi_max_openings *)arg);
1.2       bouyer   1905:                break;
1.26.2.2  thorpej  1906:
                   1907:        case ASYNC_EVENT_XFER_MODE:
                   1908:                scsipi_async_event_xfer_mode(chan,
                   1909:                    (struct scsipi_xfer_mode *)arg);
                   1910:                break;
1.26.2.9  bouyer   1911:        case ASYNC_EVENT_RESET:
                   1912:                scsipi_async_event_channel_reset(chan);
                   1913:                break;
1.2       bouyer   1914:        }
1.26.2.1  thorpej  1915:        splx(s);
                   1916: }
1.2       bouyer   1917:
1.26.2.1  thorpej  1918: /*
                   1919:  * scsipi_print_xfer_mode:
                   1920:  *
                   1921:  *     Print a periph's capabilities.
                   1922:  */
                   1923: void
                   1924: scsipi_print_xfer_mode(periph)
                   1925:        struct scsipi_periph *periph;
                   1926: {
                   1927:        int period, freq, speed, mbs;
                   1928:
                   1929:        if ((periph->periph_flags & PERIPH_MODE_VALID) == 0)
                   1930:                return;
                   1931:
                   1932:        printf("%s: ", periph->periph_dev->dv_xname);
                   1933:        if (periph->periph_mode & PERIPH_CAP_SYNC) {
                   1934:                period = scsipi_sync_factor_to_period(periph->periph_period);
                   1935:                printf("Sync (%d.%dns offset %d)",
                   1936:                    period / 10, period % 10, periph->periph_offset);
                   1937:        } else
                   1938:                printf("Async");
                   1939:
                   1940:        if (periph->periph_mode & PERIPH_CAP_WIDE32)
                   1941:                printf(", 32-bit");
                   1942:        else if (periph->periph_mode & PERIPH_CAP_WIDE16)
                   1943:                printf(", 16-bit");
                   1944:        else
                   1945:                printf(", 8-bit");
                   1946:
                   1947:        if (periph->periph_mode & PERIPH_CAP_SYNC) {
                   1948:                freq = scsipi_sync_factor_to_freq(periph->periph_period);
                   1949:                speed = freq;
                   1950:                if (periph->periph_mode & PERIPH_CAP_WIDE32)
                   1951:                        speed *= 4;
                   1952:                else if (periph->periph_mode & PERIPH_CAP_WIDE16)
                   1953:                        speed *= 2;
                   1954:                mbs = speed / 1000;
                   1955:                if (mbs > 0)
                   1956:                        printf(" (%d.%03dMB/s)", mbs, speed % 1000);
                   1957:                else
                   1958:                        printf(" (%dKB/s)", speed % 1000);
                   1959:        }
                   1960:
                   1961:        printf(" transfers");
                   1962:
                   1963:        if (periph->periph_mode & PERIPH_CAP_TQING)
                   1964:                printf(", tagged queueing");
                   1965:
                   1966:        printf("\n");
1.2       bouyer   1967: }
                   1968:
1.14      thorpej  1969: /*
1.26.2.1  thorpej  1970:  * scsipi_async_event_max_openings:
                   1971:  *
                   1972:  *     Update the maximum number of outstanding commands a
                   1973:  *     device may have.
                   1974:  */
                   1975: void
                   1976: scsipi_async_event_max_openings(chan, mo)
                   1977:        struct scsipi_channel *chan;
                   1978:        struct scsipi_max_openings *mo;
                   1979: {
                   1980:        struct scsipi_periph *periph;
1.26.2.6  thorpej  1981:        int minlun, maxlun;
1.26.2.1  thorpej  1982:
1.26.2.6  thorpej  1983:        if (mo->mo_lun == -1) {
                   1984:                /*
                   1985:                 * Wildcarded; apply it to all LUNs.
                   1986:                 */
                   1987:                minlun = 0;
                   1988:                maxlun = chan->chan_nluns - 1;
                   1989:        } else
                   1990:                minlun = maxlun = mo->mo_lun;
                   1991:
                   1992:        for (; minlun <= maxlun; minlun++) {
                   1993:                periph = scsipi_lookup_periph(chan, mo->mo_target, minlun);
                   1994:                if (periph == NULL)
                   1995:                        continue;
1.26.2.1  thorpej  1996:
1.26.2.6  thorpej  1997:                if (mo->mo_openings < periph->periph_openings)
                   1998:                        periph->periph_openings = mo->mo_openings;
                   1999:                else if (mo->mo_openings > periph->periph_openings &&
                   2000:                    (periph->periph_flags & PERIPH_GROW_OPENINGS) != 0)
                   2001:                        periph->periph_openings = mo->mo_openings;
                   2002:        }
1.26.2.2  thorpej  2003: }
                   2004:
                   2005: /*
                   2006:  * scsipi_async_event_xfer_mode:
                   2007:  *
                   2008:  *     Update the xfer mode for all periphs sharing the
                   2009:  *     specified I_T Nexus.
                   2010:  */
                   2011: void
                   2012: scsipi_async_event_xfer_mode(chan, xm)
                   2013:        struct scsipi_channel *chan;
                   2014:        struct scsipi_xfer_mode *xm;
                   2015: {
                   2016:        struct scsipi_periph *periph;
1.26.2.5  thorpej  2017:        int lun, announce, mode, period, offset;
1.26.2.2  thorpej  2018:
                   2019:        for (lun = 0; lun < chan->chan_nluns; lun++) {
                   2020:                periph = scsipi_lookup_periph(chan, xm->xm_target, lun);
                   2021:                if (periph == NULL)
                   2022:                        continue;
1.26.2.5  thorpej  2023:                announce = 0;
                   2024:
                   2025:                /*
                   2026:                 * Clamp the xfer mode down to this periph's capabilities.
                   2027:                 */
                   2028:                mode = xm->xm_mode & periph->periph_cap;
                   2029:                if (mode & PERIPH_CAP_SYNC) {
                   2030:                        period = xm->xm_period;
                   2031:                        offset = xm->xm_offset;
                   2032:                } else {
                   2033:                        period = 0;
                   2034:                        offset = 0;
                   2035:                }
                   2036:
                   2037:                /*
                   2038:                 * If we do not have a valid xfer mode yet, or the parameters
                   2039:                 * are different, announce them.
                   2040:                 */
                   2041:                if ((periph->periph_flags & PERIPH_MODE_VALID) == 0 ||
                   2042:                    periph->periph_mode != mode ||
                   2043:                    periph->periph_period != period ||
                   2044:                    periph->periph_offset != offset)
                   2045:                        announce = 1;
                   2046:
                   2047:                periph->periph_mode = mode;
                   2048:                periph->periph_period = period;
                   2049:                periph->periph_offset = offset;
                   2050:                periph->periph_flags |= PERIPH_MODE_VALID;
                   2051:
                   2052:                if (announce)
                   2053:                        scsipi_print_xfer_mode(periph);
                   2054:        }
                   2055: }
                   2056:
                   2057: /*
                   2058:  * scsipi_set_xfer_mode:
                   2059:  *
                   2060:  *     Set the xfer mode for the specified I_T Nexus.
                   2061:  */
                   2062: void
                   2063: scsipi_set_xfer_mode(chan, target, immed)
                   2064:        struct scsipi_channel *chan;
                   2065:        int target, immed;
                   2066: {
                   2067:        struct scsipi_xfer_mode xm;
                   2068:        struct scsipi_periph *itperiph;
                   2069:        int lun, s;
                   2070:
                   2071:        /*
                   2072:         * Go to the minimal xfer mode.
                   2073:         */
                   2074:        xm.xm_target = target;
                   2075:        xm.xm_mode = 0;
                   2076:        xm.xm_period = 0;                       /* ignored */
                   2077:        xm.xm_offset = 0;                       /* ignored */
                   2078:
                   2079:        /*
                   2080:         * Find the first LUN we know about on this I_T Nexus.
                   2081:         */
                   2082:        for (lun = 0; lun < chan->chan_nluns; lun++) {
                   2083:                itperiph = scsipi_lookup_periph(chan, target, lun);
                   2084:                if (itperiph != NULL)
                   2085:                        break;
                   2086:        }
                   2087:        if (itperiph != NULL)
                   2088:                xm.xm_mode = itperiph->periph_cap;
                   2089:
                   2090:        /*
                   2091:         * Now issue the request to the adapter.
                   2092:         */
                   2093:        s = splbio();
                   2094:        scsipi_adapter_request(chan, ADAPTER_REQ_SET_XFER_MODE, &xm);
                   2095:        splx(s);
                   2096:
                   2097:        /*
                   2098:         * If we want this to happen immediately, issue a dummy command,
                   2099:         * since most adapters can't really negotiate unless they're
                   2100:         * executing a job.
                   2101:         */
                   2102:        if (immed != 0 && itperiph != NULL) {
                   2103:                (void) scsipi_test_unit_ready(itperiph,
                   2104:                    XS_CTL_DISCOVERY | XS_CTL_IGNORE_ILLEGAL_REQUEST |
                   2105:                    XS_CTL_IGNORE_NOT_READY |
                   2106:                    XS_CTL_IGNORE_MEDIA_CHANGE);
1.26.2.2  thorpej  2107:        }
1.26.2.1  thorpej  2108: }
1.26.2.9  bouyer   2109:
                   2110: /*
                   2111:  * scsipi_channel_reset:
                   2112:  *
                   2113:  *     handle scsi bus reset
1.26.2.15  bouyer   2114:  * called at splbio
1.26.2.9  bouyer   2115:  */
                   2116: void
                   2117: scsipi_async_event_channel_reset(chan)
                   2118:        struct scsipi_channel *chan;
                   2119: {
                   2120:        struct scsipi_xfer *xs, *xs_next;
                   2121:        struct scsipi_periph *periph;
                   2122:        int target, lun;
                   2123:
                   2124:        /*
                   2125:         * Channel has been reset. Also mark as reset pending REQUEST_SENSE
                   2126:         * commands; as the sense is not available any more.
1.26.2.15  bouyer   2127:         * can't call scsipi_done() from here, as the command has not been
                   2128:         * sent to the adapter yet (this would corrupt accounting).
1.26.2.9  bouyer   2129:         */
                   2130:
                   2131:        for (xs = TAILQ_FIRST(&chan->chan_queue); xs != NULL; xs = xs_next) {
                   2132:                xs_next = TAILQ_NEXT(xs, channel_q);
                   2133:                if (xs->xs_control & XS_CTL_REQSENSE) {
1.26.2.10  bouyer   2134:                        TAILQ_REMOVE(&chan->chan_queue, xs, channel_q);
1.26.2.9  bouyer   2135:                        xs->error = XS_RESET;
1.26.2.15  bouyer   2136:                        if ((xs->xs_control & XS_CTL_ASYNC) != 0)
                   2137:                                TAILQ_INSERT_TAIL(&chan->chan_complete, xs,
                   2138:                                    channel_q);
1.26.2.9  bouyer   2139:                }
                   2140:        }
1.26.2.15  bouyer   2141:        wakeup(&chan->chan_complete);
1.26.2.9  bouyer   2142:        /* Catch xs with pending sense which may not have a REQSENSE xs yet */
                   2143:        for (target = 0; target < chan->chan_ntargets; target++) {
                   2144:                if (target == chan->chan_id)
                   2145:                        continue;
                   2146:                for (lun = 0; lun <  chan->chan_nluns; lun++) {
                   2147:                        periph = chan->chan_periphs[target][lun];
                   2148:                        if (periph) {
                   2149:                                xs = periph->periph_xscheck;
                   2150:                                if (xs)
                   2151:                                        xs->error = XS_RESET;
                   2152:                        }
                   2153:                }
                   2154:        }
                   2155: }
                   2156:
1.26.2.1  thorpej  2157:
                   2158: /*
                   2159:  * scsipi_adapter_addref:
                   2160:  *
                   2161:  *     Add a reference to the adapter pointed to by the provided
                   2162:  *     link, enabling the adapter if necessary.
1.14      thorpej  2163:  */
                   2164: int
1.26.2.1  thorpej  2165: scsipi_adapter_addref(adapt)
                   2166:        struct scsipi_adapter *adapt;
1.14      thorpej  2167: {
                   2168:        int s, error = 0;
                   2169:
                   2170:        s = splbio();
1.26.2.1  thorpej  2171:        if (adapt->adapt_refcnt++ == 0 && adapt->adapt_enable != NULL) {
                   2172:                error = (*adapt->adapt_enable)(adapt->adapt_dev, 1);
1.14      thorpej  2173:                if (error)
1.26.2.1  thorpej  2174:                        adapt->adapt_refcnt--;
1.14      thorpej  2175:        }
                   2176:        splx(s);
                   2177:        return (error);
                   2178: }
                   2179:
                   2180: /*
1.26.2.1  thorpej  2181:  * scsipi_adapter_delref:
                   2182:  *
                   2183:  *     Delete a reference to the adapter pointed to by the provided
                   2184:  *     link, disabling the adapter if possible.
1.14      thorpej  2185:  */
                   2186: void
1.26.2.1  thorpej  2187: scsipi_adapter_delref(adapt)
                   2188:        struct scsipi_adapter *adapt;
1.14      thorpej  2189: {
                   2190:        int s;
                   2191:
                   2192:        s = splbio();
1.26.2.1  thorpej  2193:        if (adapt->adapt_refcnt-- == 1 && adapt->adapt_enable != NULL)
                   2194:                (void) (*adapt->adapt_enable)(adapt->adapt_dev, 0);
1.14      thorpej  2195:        splx(s);
                   2196: }
                   2197:
1.26.2.1  thorpej  2198: struct scsipi_syncparam {
                   2199:        int     ss_factor;
                   2200:        int     ss_period;      /* ns * 10 */
                   2201: } scsipi_syncparams[] = {
                   2202:        { 0x0a,         250 },
                   2203:        { 0x0b,         303 },
                   2204:        { 0x0c,         500 },
                   2205: };
                   2206: const int scsipi_nsyncparams =
                   2207:     sizeof(scsipi_syncparams) / sizeof(scsipi_syncparams[0]);
                   2208:
                   2209: int
                   2210: scsipi_sync_period_to_factor(period)
                   2211:        int period;             /* ns * 10 */
                   2212: {
                   2213:        int i;
                   2214:
                   2215:        for (i = 0; i < scsipi_nsyncparams; i++) {
                   2216:                if (period <= scsipi_syncparams[i].ss_period)
                   2217:                        return (scsipi_syncparams[i].ss_factor);
                   2218:        }
                   2219:
                   2220:        return ((period / 10) / 4);
                   2221: }
                   2222:
                   2223: int
                   2224: scsipi_sync_factor_to_period(factor)
                   2225:        int factor;
                   2226: {
                   2227:        int i;
                   2228:
                   2229:        for (i = 0; i < scsipi_nsyncparams; i++) {
                   2230:                if (factor == scsipi_syncparams[i].ss_factor)
                   2231:                        return (scsipi_syncparams[i].ss_period);
                   2232:        }
                   2233:
                   2234:        return ((factor * 4) * 10);
                   2235: }
                   2236:
                   2237: int
                   2238: scsipi_sync_factor_to_freq(factor)
                   2239:        int factor;
                   2240: {
                   2241:        int i;
                   2242:
                   2243:        for (i = 0; i < scsipi_nsyncparams; i++) {
                   2244:                if (factor == scsipi_syncparams[i].ss_factor)
                   2245:                        return (10000000 / scsipi_syncparams[i].ss_period);
                   2246:        }
                   2247:
                   2248:        return (10000000 / ((factor * 4) * 10));
                   2249: }
                   2250:
1.26.2.6  thorpej  2251: #ifdef SCSIPI_DEBUG
1.2       bouyer   2252: /*
                   2253:  * Given a scsipi_xfer, dump the request, in all it's glory
                   2254:  */
                   2255: void
                   2256: show_scsipi_xs(xs)
                   2257:        struct scsipi_xfer *xs;
                   2258: {
1.3       enami    2259:
1.2       bouyer   2260:        printf("xs(%p): ", xs);
1.24      thorpej  2261:        printf("xs_control(0x%08x)", xs->xs_control);
                   2262:        printf("xs_status(0x%08x)", xs->xs_status);
1.26.2.6  thorpej  2263:        printf("periph(%p)", xs->xs_periph);
1.26.2.1  thorpej  2264:        printf("retr(0x%x)", xs->xs_retries);
1.2       bouyer   2265:        printf("timo(0x%x)", xs->timeout);
                   2266:        printf("cmd(%p)", xs->cmd);
                   2267:        printf("len(0x%x)", xs->cmdlen);
                   2268:        printf("data(%p)", xs->data);
                   2269:        printf("len(0x%x)", xs->datalen);
                   2270:        printf("res(0x%x)", xs->resid);
                   2271:        printf("err(0x%x)", xs->error);
                   2272:        printf("bp(%p)", xs->bp);
                   2273:        show_scsipi_cmd(xs);
                   2274: }
                   2275:
                   2276: void
                   2277: show_scsipi_cmd(xs)
                   2278:        struct scsipi_xfer *xs;
                   2279: {
                   2280:        u_char *b = (u_char *) xs->cmd;
1.3       enami    2281:        int i = 0;
1.2       bouyer   2282:
1.26.2.6  thorpej  2283:        scsipi_printaddr(xs->xs_periph);
                   2284:        printf(" command: ");
1.2       bouyer   2285:
1.24      thorpej  2286:        if ((xs->xs_control & XS_CTL_RESET) == 0) {
1.2       bouyer   2287:                while (i < xs->cmdlen) {
                   2288:                        if (i)
                   2289:                                printf(",");
                   2290:                        printf("0x%x", b[i++]);
                   2291:                }
                   2292:                printf("-[%d bytes]\n", xs->datalen);
                   2293:                if (xs->datalen)
                   2294:                        show_mem(xs->data, min(64, xs->datalen));
                   2295:        } else
                   2296:                printf("-RESET-\n");
                   2297: }
                   2298:
                   2299: void
                   2300: show_mem(address, num)
                   2301:        u_char *address;
                   2302:        int num;
                   2303: {
                   2304:        int x;
                   2305:
                   2306:        printf("------------------------------");
                   2307:        for (x = 0; x < num; x++) {
                   2308:                if ((x % 16) == 0)
                   2309:                        printf("\n%03d: ", x);
                   2310:                printf("%02x ", *address++);
                   2311:        }
                   2312:        printf("\n------------------------------\n");
                   2313: }
1.26.2.6  thorpej  2314: #endif /* SCSIPI_DEBUG */

CVSweb <webmaster@jp.NetBSD.org>