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

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

1.1     ! nbrk        1: /*     $OpenBSD: aic7xxx_openbsd.c,v 1.35 2007/08/04 14:37:34 krw Exp $        */
        !             2: /*     $NetBSD: aic7xxx_osm.c,v 1.14 2003/11/02 11:07:44 wiz Exp $     */
        !             3:
        !             4: /*
        !             5:  * Bus independent OpenBSD shim for the aic7xxx based adaptec SCSI controllers
        !             6:  *
        !             7:  * Copyright (c) 1994-2001 Justin T. Gibbs.
        !             8:  * Copyright (c) 2001-2002 Steve Murphree, Jr.
        !             9:  * All rights reserved.
        !            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:  *    without modification.
        !            17:  * 2. The name of the author may not be used to endorse or promote products
        !            18:  *    derived from this software without specific prior written permission.
        !            19:  *
        !            20:  * Alternatively, this software may be distributed under the terms of the
        !            21:  * GNU Public License ("GPL").
        !            22:  *
        !            23:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
        !            24:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            25:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            26:  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
        !            27:  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            28:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            29:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            31:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            32:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            33:  * SUCH DAMAGE.
        !            34:  *
        !            35:  * //depot/aic7xxx/freebsd/dev/aic7xxx/aic7xxx_osm.c#12 $
        !            36:  *
        !            37:  * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_osm.c,v 1.31 2002/11/30 19:08:58 scottl Exp $
        !            38:  */
        !            39: /*
        !            40:  * Ported from FreeBSD by Pascal Renauld, Network Storage Solutions, Inc. - April 2003
        !            41:  */
        !            42:
        !            43: #include <sys/cdefs.h>
        !            44: /* __KERNEL_RCSID(0, "$NetBSD: aic7xxx_osm.c,v 1.14 2003/11/02 11:07:44 wiz Exp $"); */
        !            45:
        !            46: #include <dev/ic/aic7xxx_openbsd.h>
        !            47: #include <dev/ic/aic7xxx_inline.h>
        !            48:
        !            49: #ifndef AHC_TMODE_ENABLE
        !            50: #define AHC_TMODE_ENABLE 0
        !            51: #endif
        !            52:
        !            53:
        !            54: int    ahc_action(struct scsi_xfer *);
        !            55: int    ahc_execute_scb(void *, bus_dma_segment_t *, int);
        !            56: int    ahc_poll(struct ahc_softc *, int);
        !            57: int    ahc_setup_data(struct ahc_softc *, struct scsi_xfer *, struct scb *);
        !            58:
        !            59: void   ahc_minphys(struct buf *);
        !            60: void   ahc_adapter_req_set_xfer_mode(struct ahc_softc *, struct scb *);
        !            61:
        !            62:
        !            63: struct cfdriver ahc_cd = {
        !            64:        NULL, "ahc", DV_DULL
        !            65: };
        !            66:
        !            67: static struct scsi_adapter ahc_switch =
        !            68: {
        !            69:        ahc_action,
        !            70:        ahc_minphys,
        !            71:        0,
        !            72:        0,
        !            73: };
        !            74:
        !            75: /* the below structure is so we have a default dev struct for our link struct */
        !            76: static struct scsi_device ahc_dev =
        !            77: {
        !            78:        NULL, /* Use default error handler */
        !            79:        NULL, /* have a queue, served by this */
        !            80:        NULL, /* have no async handler */
        !            81:        NULL, /* Use default 'done' routine */
        !            82: };
        !            83:
        !            84: /*
        !            85:  * Attach all the sub-devices we can find
        !            86:  */
        !            87: int
        !            88: ahc_attach(struct ahc_softc *ahc)
        !            89: {
        !            90:        struct scsibus_attach_args saa;
        !            91:        int s;
        !            92:
        !            93:         s = splbio();
        !            94:
        !            95:        /*
        !            96:         * fill in the prototype scsi_links.
        !            97:         */
        !            98:        ahc->sc_channel.adapter_target = ahc->our_id;
        !            99:        if (ahc->features & AHC_WIDE)
        !           100:                ahc->sc_channel.adapter_buswidth = 16;
        !           101:        ahc->sc_channel.adapter_softc = ahc;
        !           102:        ahc->sc_channel.adapter = &ahc_switch;
        !           103:        ahc->sc_channel.openings = 16;
        !           104:        ahc->sc_channel.device = &ahc_dev;
        !           105:
        !           106:        if (ahc->features & AHC_TWIN) {
        !           107:                /* Configure the second scsi bus */
        !           108:                ahc->sc_channel_b = ahc->sc_channel;
        !           109:                ahc->sc_channel_b.adapter_target = ahc->our_id_b;
        !           110:        }
        !           111:
        !           112: #ifndef DEBUG
        !           113:        if (bootverbose) {
        !           114:                char ahc_info[256];
        !           115:                ahc_controller_info(ahc, ahc_info, sizeof ahc_info);
        !           116:                printf("%s: %s\n", ahc->sc_dev.dv_xname, ahc_info);
        !           117:        }
        !           118: #endif
        !           119:
        !           120:        ahc_intr_enable(ahc, TRUE);
        !           121:
        !           122:        if (ahc->flags & AHC_RESET_BUS_A)
        !           123:                ahc_reset_channel(ahc, 'A', TRUE);
        !           124:        if ((ahc->features & AHC_TWIN) && ahc->flags & AHC_RESET_BUS_B)
        !           125:                ahc_reset_channel(ahc, 'B', TRUE);
        !           126:
        !           127:        bzero(&saa, sizeof(saa));
        !           128:        if ((ahc->flags & AHC_PRIMARY_CHANNEL) == 0) {
        !           129:                saa.saa_sc_link = &ahc->sc_channel;
        !           130:                ahc->sc_child = config_found((void *)&ahc->sc_dev,
        !           131:                    &saa, scsiprint);
        !           132:                if (ahc->features & AHC_TWIN) {
        !           133:                        saa.saa_sc_link = &ahc->sc_channel_b;
        !           134:                        ahc->sc_child_b = config_found((void *)&ahc->sc_dev,
        !           135:                            &saa, scsiprint);
        !           136:                }
        !           137:        } else {
        !           138:                if (ahc->features & AHC_TWIN) {
        !           139:                        saa.saa_sc_link = &ahc->sc_channel_b;
        !           140:                        ahc->sc_child = config_found((void *)&ahc->sc_dev,
        !           141:                            &saa, scsiprint);
        !           142:                }
        !           143:                saa.saa_sc_link = &ahc->sc_channel;
        !           144:                ahc->sc_child_b = config_found((void *)&ahc->sc_dev,
        !           145:                    &saa, scsiprint);
        !           146:        }
        !           147:
        !           148:        splx(s);
        !           149:        return (1);
        !           150: }
        !           151:
        !           152: /*
        !           153:  * Catch an interrupt from the adapter
        !           154:  */
        !           155: int
        !           156: ahc_platform_intr(void *arg)
        !           157: {
        !           158:        struct  ahc_softc *ahc = (struct ahc_softc *)arg;
        !           159:
        !           160:        bus_dmamap_sync(ahc->parent_dmat, ahc->scb_data->hscb_dmamap,
        !           161:            0, ahc->scb_data->hscb_dmamap->dm_mapsize,
        !           162:            BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
        !           163:
        !           164:        return ahc_intr(ahc);
        !           165: }
        !           166:
        !           167: /*
        !           168:  * We have an scb which has been processed by the
        !           169:  * adaptor, now we look to see how the operation
        !           170:  * went.
        !           171:  */
        !           172: void
        !           173: ahc_done(struct ahc_softc *ahc, struct scb *scb)
        !           174: {
        !           175:        struct scsi_xfer *xs = scb->xs;
        !           176:        int s;
        !           177:
        !           178:        bus_dmamap_sync(ahc->parent_dmat, ahc->scb_data->hscb_dmamap,
        !           179:            0, ahc->scb_data->hscb_dmamap->dm_mapsize,
        !           180:            BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
        !           181:
        !           182:        LIST_REMOVE(scb, pending_links);
        !           183:        if ((scb->flags & SCB_UNTAGGEDQ) != 0) {
        !           184:                struct scb_tailq *untagged_q;
        !           185:                int target_offset;
        !           186:
        !           187:                target_offset = SCB_GET_TARGET_OFFSET(ahc, scb);
        !           188:                untagged_q = &ahc->untagged_queues[target_offset];
        !           189:                TAILQ_REMOVE(untagged_q, scb, links.tqe);
        !           190:                scb->flags &= ~SCB_UNTAGGEDQ;
        !           191:                ahc_run_untagged_queue(ahc, untagged_q);
        !           192:        }
        !           193:
        !           194:        timeout_del(&xs->stimeout);
        !           195:
        !           196:        if (xs->datalen) {
        !           197:                int op;
        !           198:
        !           199:                if ((xs->flags & SCSI_DATA_IN) != 0)
        !           200:                        op = BUS_DMASYNC_POSTREAD;
        !           201:                else
        !           202:                        op = BUS_DMASYNC_POSTWRITE;
        !           203:                bus_dmamap_sync(ahc->parent_dmat, scb->dmamap, 0,
        !           204:                                scb->dmamap->dm_mapsize, op);
        !           205:                bus_dmamap_unload(ahc->parent_dmat, scb->dmamap);
        !           206:        }
        !           207:
        !           208:        /* Translate the CAM status code to a SCSI error code. */
        !           209:        switch (xs->error) {
        !           210:        case CAM_SCSI_STATUS_ERROR:
        !           211:        case CAM_REQ_INPROG:
        !           212:        case CAM_REQ_CMP:
        !           213:                switch (xs->status) {
        !           214:                case SCSI_TASKSET_FULL:
        !           215:                        /* SCSI Layer won't requeue, so we force infinite
        !           216:                         * retries until queue space is available. XS_BUSY
        !           217:                         * is dangerous because if the NOSLEEP flag is set
        !           218:                         * it can cause the I/O to return EIO. XS_BUSY code
        !           219:                         * falls through to XS_TIMEOUT anyway.
        !           220:                         */
        !           221:                        xs->error = XS_TIMEOUT;
        !           222:                        xs->retries++;
        !           223:                        break;
        !           224:                case SCSI_BUSY:
        !           225:                        xs->error = XS_BUSY;
        !           226:                        break;
        !           227:                case SCSI_CHECK:
        !           228:                case SCSI_TERMINATED:
        !           229:                        if ((scb->flags & SCB_SENSE) == 0) {
        !           230:                                /* CHECK on CHECK? */
        !           231:                                xs->error = XS_DRIVER_STUFFUP;
        !           232:                        } else
        !           233:                                xs->error = XS_NOERROR;
        !           234:                        break;
        !           235:                default:
        !           236:                        xs->error = XS_NOERROR;
        !           237:                        break;
        !           238:                }
        !           239:                break;
        !           240:        case CAM_BUSY:
        !           241:                xs->error = XS_BUSY;
        !           242:                break;
        !           243:        case CAM_CMD_TIMEOUT:
        !           244:                xs->error = XS_TIMEOUT;
        !           245:                break;
        !           246:        case CAM_BDR_SENT:
        !           247:        case CAM_SCSI_BUS_RESET:
        !           248:                xs->error = XS_RESET;
        !           249:                break;
        !           250:        case CAM_REQUEUE_REQ:
        !           251:                xs->error = XS_TIMEOUT;
        !           252:                xs->retries++;
        !           253:                break;
        !           254:        case CAM_SEL_TIMEOUT:
        !           255:                xs->error = XS_SELTIMEOUT;
        !           256:                break;
        !           257:        default:
        !           258:                xs->error = XS_DRIVER_STUFFUP;
        !           259:                break;
        !           260:        }
        !           261:
        !           262:        /* Don't clobber any existing error state */
        !           263:        if (xs->error != XS_NOERROR) {
        !           264:          /* Don't clobber any existing error state */
        !           265:        } else if ((scb->flags & SCB_SENSE) != 0) {
        !           266:                /*
        !           267:                 * We performed autosense retrieval.
        !           268:                 *
        !           269:                 * Zero any sense not transferred by the
        !           270:                 * device.  The SCSI spec mandates that any
        !           271:                 * untransferred data should be assumed to be
        !           272:                 * zero.  Complete the 'bounce' of sense information
        !           273:                 * through buffers accessible via bus-space by
        !           274:                 * copying it into the clients csio.
        !           275:                 */
        !           276:                memset(&xs->sense, 0, sizeof(struct scsi_sense_data));
        !           277:                memcpy(&xs->sense, ahc_get_sense_buf(ahc, scb),
        !           278:                    aic_le32toh(scb->sg_list->len) & AHC_SG_LEN_MASK);
        !           279:                xs->error = XS_SENSE;
        !           280:        }
        !           281:
        !           282:         s = splbio();
        !           283:        ahc_free_scb(ahc, scb);
        !           284:         splx(s);
        !           285:
        !           286:        xs->flags |= ITSDONE;
        !           287:        scsi_done(xs);
        !           288: }
        !           289:
        !           290: void
        !           291: ahc_minphys(bp)
        !           292:        struct buf *bp;
        !           293: {
        !           294:        /*
        !           295:         * Even though the card can transfer up to 16megs per command
        !           296:         * we are limited by the number of segments in the dma segment
        !           297:         * list that we can hold.  The worst case is that all pages are
        !           298:         * discontinuous physically, hence the "page per segment" limit
        !           299:         * enforced here.
        !           300:         */
        !           301:        if (bp->b_bcount > ((AHC_NSEG - 1) * PAGE_SIZE)) {
        !           302:                bp->b_bcount = ((AHC_NSEG - 1) * PAGE_SIZE);
        !           303:        }
        !           304:        minphys(bp);
        !           305: }
        !           306:
        !           307: int32_t
        !           308: ahc_action(struct scsi_xfer *xs)
        !           309: {
        !           310:        struct ahc_softc *ahc;
        !           311:        struct scb *scb;
        !           312:        struct hardware_scb *hscb;
        !           313:        u_int target_id;
        !           314:        u_int our_id;
        !           315:        int s;
        !           316:        int dontqueue = 0;
        !           317:
        !           318:        SC_DEBUG(xs->sc_link, SDEV_DB3, ("ahc_action\n"));
        !           319:        ahc = (struct ahc_softc *)xs->sc_link->adapter_softc;
        !           320:
        !           321:        /* determine safety of software queueing */
        !           322:        dontqueue = xs->flags & SCSI_POLL;
        !           323:
        !           324:        target_id = xs->sc_link->target;
        !           325:        our_id = SCSI_SCSI_ID(ahc, xs->sc_link);
        !           326:
        !           327:        /*
        !           328:         * get an scb to use.
        !           329:         */
        !           330:        s = splbio();
        !           331:        if ((scb = ahc_get_scb(ahc)) == NULL) {
        !           332:                splx(s);
        !           333:                return (TRY_AGAIN_LATER);
        !           334:        }
        !           335:        splx(s);
        !           336:
        !           337:        hscb = scb->hscb;
        !           338:
        !           339:        SC_DEBUG(xs->sc_link, SDEV_DB3, ("start scb(%p)\n", scb));
        !           340:        scb->xs = xs;
        !           341:        timeout_set(&xs->stimeout, ahc_timeout, scb);
        !           342:
        !           343:        /*
        !           344:         * Put all the arguments for the xfer in the scb
        !           345:         */
        !           346:        hscb->control = 0;
        !           347:        hscb->scsiid = BUILD_SCSIID(ahc, xs->sc_link, target_id, our_id);
        !           348:        hscb->lun = xs->sc_link->lun;
        !           349:        if (xs->xs_control & XS_CTL_RESET) {
        !           350:                hscb->cdb_len = 0;
        !           351:                scb->flags |= SCB_DEVICE_RESET;
        !           352:                hscb->control |= MK_MESSAGE;
        !           353:                return (ahc_execute_scb(scb, NULL, 0));
        !           354:        }
        !           355:
        !           356:        return (ahc_setup_data(ahc, xs, scb));
        !           357: }
        !           358:
        !           359: int
        !           360: ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments)
        !           361: {
        !           362:        struct  scb *scb;
        !           363:        struct  scsi_xfer *xs;
        !           364:        struct  ahc_softc *ahc;
        !           365:        struct  ahc_initiator_tinfo *tinfo;
        !           366:        struct  ahc_tmode_tstate *tstate;
        !           367:
        !           368:        u_int   mask;
        !           369:        int     s;
        !           370:
        !           371:        scb = (struct scb *)arg;
        !           372:        xs = scb->xs;
        !           373:        xs->error = CAM_REQ_INPROG;
        !           374:        xs->status = 0;
        !           375:        ahc = (struct ahc_softc *)xs->sc_link->adapter_softc;
        !           376:
        !           377:        if (nsegments != 0) {
        !           378:                struct    ahc_dma_seg *sg;
        !           379:                bus_dma_segment_t *end_seg;
        !           380:                int op;
        !           381:
        !           382:                end_seg = dm_segs + nsegments;
        !           383:
        !           384:                /* Copy the segments into our SG list */
        !           385:                sg = scb->sg_list;
        !           386:                while (dm_segs < end_seg) {
        !           387:                        uint32_t len;
        !           388:
        !           389:                        sg->addr = aic_htole32(dm_segs->ds_addr);
        !           390:                        len = dm_segs->ds_len
        !           391:                            | ((dm_segs->ds_addr >> 8) & 0x7F000000);
        !           392:                        sg->len = aic_htole32(len);
        !           393:                        sg++;
        !           394:                        dm_segs++;
        !           395:                }
        !           396:
        !           397:                /*
        !           398:                 * Note where to find the SG entries in bus space.
        !           399:                 * We also set the full residual flag which the
        !           400:                 * sequencer will clear as soon as a data transfer
        !           401:                 * occurs.
        !           402:                 */
        !           403:                scb->hscb->sgptr = aic_htole32(scb->sg_list_phys|SG_FULL_RESID);
        !           404:
        !           405:                if ((xs->flags & SCSI_DATA_IN) != 0)
        !           406:                        op = BUS_DMASYNC_PREREAD;
        !           407:                else
        !           408:                        op = BUS_DMASYNC_PREWRITE;
        !           409:
        !           410:                bus_dmamap_sync(ahc->parent_dmat, scb->dmamap, 0,
        !           411:                                scb->dmamap->dm_mapsize, op);
        !           412:
        !           413:                sg--;
        !           414:                sg->len |= aic_htole32(AHC_DMA_LAST_SEG);
        !           415:
        !           416:                bus_dmamap_sync(ahc->parent_dmat, scb->sg_map->sg_dmamap,
        !           417:                    0, scb->sg_map->sg_dmamap->dm_mapsize,
        !           418:                    BUS_DMASYNC_PREWRITE);
        !           419:
        !           420:                /* Copy the first SG into the "current" data pointer area */
        !           421:                scb->hscb->dataptr = scb->sg_list->addr;
        !           422:                scb->hscb->datacnt = scb->sg_list->len;
        !           423:        } else {
        !           424:                scb->hscb->sgptr = aic_htole32(SG_LIST_NULL);
        !           425:                scb->hscb->dataptr = 0;
        !           426:                scb->hscb->datacnt = 0;
        !           427:        }
        !           428:
        !           429:        scb->sg_count = nsegments;
        !           430:
        !           431:        s = splbio();
        !           432:
        !           433:        /*
        !           434:         * Last time we need to check if this SCB needs to
        !           435:         * be aborted.
        !           436:         */
        !           437:        if (xs->flags & ITSDONE) {
        !           438:                if (nsegments != 0)
        !           439:                        bus_dmamap_unload(ahc->parent_dmat, scb->dmamap);
        !           440:
        !           441:                ahc_free_scb(ahc, scb);
        !           442:                splx(s);
        !           443:                return (COMPLETE);
        !           444:        }
        !           445:
        !           446:        tinfo = ahc_fetch_transinfo(ahc, SCSIID_CHANNEL(ahc, scb->hscb->scsiid),
        !           447:                                    SCSIID_OUR_ID(scb->hscb->scsiid),
        !           448:                                    SCSIID_TARGET(ahc, scb->hscb->scsiid),
        !           449:                                    &tstate);
        !           450:
        !           451:        mask = SCB_GET_TARGET_MASK(ahc, scb);
        !           452:        scb->hscb->scsirate = tinfo->scsirate;
        !           453:        scb->hscb->scsioffset = tinfo->curr.offset;
        !           454:
        !           455:        if ((tstate->ultraenb & mask) != 0)
        !           456:                scb->hscb->control |= ULTRAENB;
        !           457:
        !           458:        if ((tstate->discenable & mask) != 0)
        !           459:                scb->hscb->control |= DISCENB;
        !           460:
        !           461:        if ((tstate->auto_negotiate & mask) != 0) {
        !           462:                scb->flags |= SCB_AUTO_NEGOTIATE;
        !           463:                scb->hscb->control |= MK_MESSAGE;
        !           464:        }
        !           465:
        !           466:        if ((tstate->tagenable & mask) != 0)
        !           467:                scb->hscb->control |= TAG_ENB;
        !           468:
        !           469:        bus_dmamap_sync(ahc->parent_dmat, ahc->scb_data->hscb_dmamap,
        !           470:            0, ahc->scb_data->hscb_dmamap->dm_mapsize,
        !           471:            BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
        !           472:
        !           473:        LIST_INSERT_HEAD(&ahc->pending_scbs, scb, pending_links);
        !           474:
        !           475:        if (!(xs->flags & SCSI_POLL))
        !           476:                timeout_add(&xs->stimeout, (xs->timeout * hz) / 1000);
        !           477:
        !           478:        /*
        !           479:         * We only allow one untagged transaction
        !           480:         * per target in the initiator role unless
        !           481:         * we are storing a full busy target *lun*
        !           482:         * table in SCB space.
        !           483:         *
        !           484:         * This really should not be of any
        !           485:         * concern, as we take care to avoid this
        !           486:         * in ahc_done().  XXX smurph
        !           487:         */
        !           488:        if ((scb->hscb->control & (TARGET_SCB|TAG_ENB)) == 0
        !           489:            && (ahc->flags & AHC_SCB_BTT) == 0) {
        !           490:                struct scb_tailq *untagged_q;
        !           491:                int target_offset;
        !           492:
        !           493:                target_offset = SCB_GET_TARGET_OFFSET(ahc, scb);
        !           494:                untagged_q = &(ahc->untagged_queues[target_offset]);
        !           495:                TAILQ_INSERT_TAIL(untagged_q, scb, links.tqe);
        !           496:                scb->flags |= SCB_UNTAGGEDQ;
        !           497:                if (TAILQ_FIRST(untagged_q) != scb) {
        !           498:                        if (xs->flags & SCSI_POLL)
        !           499:                                goto poll;
        !           500:                        else {
        !           501:                                splx(s);
        !           502:                                return (SUCCESSFULLY_QUEUED);
        !           503:                        }
        !           504:                }
        !           505:        }
        !           506:        scb->flags |= SCB_ACTIVE;
        !           507:
        !           508:        if ((scb->flags & SCB_TARGET_IMMEDIATE) != 0) {
        !           509:                /* Define a mapping from our tag to the SCB. */
        !           510:                ahc->scb_data->scbindex[scb->hscb->tag] = scb;
        !           511:                ahc_pause(ahc);
        !           512:                if ((ahc->flags & AHC_PAGESCBS) == 0)
        !           513:                        ahc_outb(ahc, SCBPTR, scb->hscb->tag);
        !           514:                ahc_outb(ahc, TARG_IMMEDIATE_SCB, scb->hscb->tag);
        !           515:                ahc_unpause(ahc);
        !           516:        } else {
        !           517:                ahc_queue_scb(ahc, scb);
        !           518:        }
        !           519:
        !           520:        if (!(xs->flags & SCSI_POLL)) {
        !           521:                if (ahc->inited_target[xs->sc_link->target] == 0) {
        !           522:                        struct  ahc_devinfo devinfo;
        !           523:
        !           524:                        ahc_adapter_req_set_xfer_mode(ahc, scb);
        !           525:                        ahc_scb_devinfo(ahc, &devinfo, scb);
        !           526:                        ahc_update_neg_request(ahc, &devinfo, tstate, tinfo,
        !           527:                            AHC_NEG_IF_NON_ASYNC);
        !           528:
        !           529:                        ahc->inited_target[xs->sc_link->target] = 1;
        !           530:                }
        !           531:                splx(s);
        !           532:                return (SUCCESSFULLY_QUEUED);
        !           533:        }
        !           534:
        !           535:        /*
        !           536:         * If we can't use interrupts, poll for completion
        !           537:         */
        !           538: poll:
        !           539:        SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_poll\n"));
        !           540:
        !           541:        do {
        !           542:                if (ahc_poll(ahc, xs->timeout)) {
        !           543:                        if (!(xs->flags & SCSI_SILENT))
        !           544:                                printf("cmd fail\n");
        !           545:                        ahc_timeout(scb);
        !           546:                        break;
        !           547:                }
        !           548:        } while (!(xs->flags & ITSDONE));
        !           549:
        !           550:        splx(s);
        !           551:        return (COMPLETE);
        !           552: }
        !           553:
        !           554: int
        !           555: ahc_poll(struct ahc_softc *ahc, int wait)
        !           556: {
        !           557:        while (--wait) {
        !           558:                DELAY(1000);
        !           559:                if (ahc_inb(ahc, INTSTAT) & INT_PEND)
        !           560:                        break;
        !           561:        }
        !           562:
        !           563:        if (wait == 0) {
        !           564:                printf("%s: board is not responding\n", ahc_name(ahc));
        !           565:                return (EIO);
        !           566:        }
        !           567:
        !           568:        ahc_intr((void *)ahc);
        !           569:        return (0);
        !           570: }
        !           571:
        !           572: int
        !           573: ahc_setup_data(struct ahc_softc *ahc, struct scsi_xfer *xs,
        !           574:               struct scb *scb)
        !           575: {
        !           576:        struct hardware_scb *hscb;
        !           577:        int s;
        !           578:
        !           579:        hscb = scb->hscb;
        !           580:        xs->resid = xs->status = 0;
        !           581:        xs->error = CAM_REQ_INPROG;
        !           582:
        !           583:        hscb->cdb_len = xs->cmdlen;
        !           584:        if (hscb->cdb_len > sizeof(hscb->cdb32)) {
        !           585:                s = splbio();
        !           586:                ahc_free_scb(ahc, scb);
        !           587:                splx(s);
        !           588:                xs->error = XS_DRIVER_STUFFUP;
        !           589:                xs->flags |= ITSDONE;
        !           590:                scsi_done(xs);
        !           591:                return (COMPLETE);
        !           592:        }
        !           593:
        !           594:        if (hscb->cdb_len > 12) {
        !           595:                memcpy(hscb->cdb32, xs->cmd, hscb->cdb_len);
        !           596:                scb->flags |= SCB_CDB32_PTR;
        !           597:        } else {
        !           598:                memcpy(hscb->shared_data.cdb, xs->cmd, hscb->cdb_len);
        !           599:        }
        !           600:
        !           601:        /* Only use S/G if there is a transfer */
        !           602:        if (xs->datalen) {
        !           603:                int error;
        !           604:
        !           605:                 error = bus_dmamap_load(ahc->parent_dmat,
        !           606:                                        scb->dmamap, xs->data,
        !           607:                                        xs->datalen, NULL,
        !           608:                                        (xs->flags & SCSI_NOSLEEP) ?
        !           609:                                        BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
        !           610:                if (error) {
        !           611: #ifdef AHC_DEBUG
        !           612:                         printf("%s: in ahc_setup_data(): bus_dmamap_load() "
        !           613:                               "= %d\n",
        !           614:                               ahc_name(ahc), error);
        !           615: #endif
        !           616:                        s = splbio();
        !           617:                        ahc_free_scb(ahc, scb);
        !           618:                        splx(s);
        !           619:                        return (TRY_AGAIN_LATER);       /* XXX fvdl */
        !           620: }
        !           621:                error = ahc_execute_scb(scb,
        !           622:                                        scb->dmamap->dm_segs,
        !           623:                                        scb->dmamap->dm_nsegs);
        !           624:                return error;
        !           625:        } else {
        !           626:                return ahc_execute_scb(scb, NULL, 0);
        !           627:        }
        !           628: }
        !           629:
        !           630: void
        !           631: ahc_timeout(void *arg)
        !           632: {
        !           633:        struct  scb *scb, *list_scb;
        !           634:        struct  ahc_softc *ahc;
        !           635:        int     s;
        !           636:        int     found;
        !           637:        char    channel;
        !           638:
        !           639:        scb = (struct scb *)arg;
        !           640:        ahc = (struct ahc_softc *)scb->xs->sc_link->adapter_softc;
        !           641:
        !           642:        s = splbio();
        !           643:
        !           644: #ifdef AHC_DEBUG
        !           645:        printf("%s: SCB %d timed out\n", ahc_name(ahc), scb->hscb->tag);
        !           646:        ahc_dump_card_state(ahc);
        !           647: #endif
        !           648:
        !           649:        ahc_pause(ahc);
        !           650:
        !           651:        if (scb->flags & SCB_ACTIVE) {
        !           652:                channel = SCB_GET_CHANNEL(ahc, scb);
        !           653:                ahc_set_transaction_status(scb, CAM_CMD_TIMEOUT);
        !           654:                /*
        !           655:                 * Go through all of our pending SCBs and remove
        !           656:                 * any scheduled timeouts for them. They're about to be
        !           657:                 * aborted so no need for them to timeout.
        !           658:                 */
        !           659:                LIST_FOREACH(list_scb, &ahc->pending_scbs, pending_links) {
        !           660:                        if (list_scb->xs)
        !           661:                                timeout_del(&list_scb->xs->stimeout);
        !           662:                }
        !           663:                found = ahc_reset_channel(ahc, channel, /*Initiate Reset*/TRUE);
        !           664: #ifdef AHC_DEBUG
        !           665:                printf("%s: Issued Channel %c Bus Reset %d SCBs aborted\n",
        !           666:                    ahc_name(ahc), channel, found);
        !           667: #endif
        !           668:        }
        !           669:
        !           670:        ahc_unpause(ahc);
        !           671:        splx(s);
        !           672: }
        !           673:
        !           674:
        !           675: void
        !           676: ahc_platform_set_tags(struct ahc_softc *ahc,
        !           677:                      struct ahc_devinfo *devinfo, int alg)
        !           678: {
        !           679:        struct ahc_tmode_tstate *tstate;
        !           680:
        !           681:        ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid,
        !           682:                            devinfo->target, &tstate);
        !           683:
        !           684:        /* XXXX Need to check quirks before doing this! XXXX */
        !           685:
        !           686:        switch (alg) {
        !           687:        case AHC_QUEUE_BASIC:
        !           688:        case AHC_QUEUE_TAGGED:
        !           689:                tstate->tagenable |= devinfo->target_mask;
        !           690:                break;
        !           691:        case AHC_QUEUE_NONE:
        !           692:                tstate->tagenable &= ~devinfo->target_mask;
        !           693:                break;
        !           694:        }
        !           695: }
        !           696:
        !           697: int
        !           698: ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg)
        !           699: {
        !           700:        if (sizeof(struct ahc_platform_data) > 0) {
        !           701:                ahc->platform_data = malloc(sizeof(struct ahc_platform_data),
        !           702:                    M_DEVBUF, M_NOWAIT);
        !           703:                if (ahc->platform_data == NULL)
        !           704:                        return (ENOMEM);
        !           705:                bzero(ahc->platform_data, sizeof(struct ahc_platform_data));
        !           706:        }
        !           707:
        !           708:        return (0);
        !           709: }
        !           710:
        !           711: void
        !           712: ahc_platform_free(struct ahc_softc *ahc)
        !           713: {
        !           714:        if (sizeof(struct ahc_platform_data) > 0)
        !           715:                free(ahc->platform_data, M_DEVBUF);
        !           716: }
        !           717:
        !           718: int
        !           719: ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc)
        !           720: {
        !           721:        return (0);
        !           722: }
        !           723:
        !           724: void
        !           725: ahc_send_async(struct ahc_softc *ahc, char channel, u_int target, u_int lun,
        !           726:                ac_code code, void *opt_arg)
        !           727: {
        !           728:        /* Nothing to do here for OpenBSD */
        !           729: }
        !           730:
        !           731: void
        !           732: ahc_adapter_req_set_xfer_mode(struct ahc_softc *ahc, struct scb *scb)
        !           733: {
        !           734:        struct ahc_initiator_tinfo *tinfo;
        !           735:        struct ahc_tmode_tstate *tstate;
        !           736:        struct ahc_syncrate *syncrate;
        !           737:        struct ahc_devinfo devinfo;
        !           738:        u_int16_t quirks;
        !           739:        u_int width, ppr_options, period, offset;
        !           740:        int s;
        !           741:
        !           742:        s = splbio();
        !           743:
        !           744:        ahc_scb_devinfo(ahc, &devinfo, scb);
        !           745:        quirks = scb->xs->sc_link->quirks;
        !           746:        tinfo = ahc_fetch_transinfo(ahc, devinfo.channel,
        !           747:            devinfo.our_scsiid, devinfo.target, &tstate);
        !           748:
        !           749:        tstate->discenable |= (ahc->user_discenable & devinfo.target_mask);
        !           750:
        !           751:        if (quirks & SDEV_NOTAGS)
        !           752:                tstate->tagenable &= ~devinfo.target_mask;
        !           753:        else if (ahc->user_tagenable & devinfo.target_mask)
        !           754:                tstate->tagenable |= devinfo.target_mask;
        !           755:
        !           756:        if (quirks & SDEV_NOWIDE)
        !           757:                width = MSG_EXT_WDTR_BUS_8_BIT;
        !           758:        else
        !           759:                width = MSG_EXT_WDTR_BUS_16_BIT;
        !           760:
        !           761:        ahc_validate_width(ahc, NULL, &width, ROLE_UNKNOWN);
        !           762:        if (width > tinfo->user.width)
        !           763:                width = tinfo->user.width;
        !           764:        ahc_set_width(ahc, &devinfo, width, AHC_TRANS_GOAL, FALSE);
        !           765:
        !           766:        if (quirks & SDEV_NOSYNC) {
        !           767:                period = 0;
        !           768:                offset = 0;
        !           769:        } else {
        !           770:                period = tinfo->user.period;
        !           771:                offset = tinfo->user.offset;
        !           772:        }
        !           773:
        !           774:        /* XXX Look at saved INQUIRY flags for PPR capabilities XXX */
        !           775:        ppr_options = tinfo->user.ppr_options;
        !           776:        /* XXX Other reasons to avoid ppr? XXX */
        !           777:        if (width < MSG_EXT_WDTR_BUS_16_BIT)
        !           778:                ppr_options = 0;
        !           779:
        !           780:        if ((tstate->discenable & devinfo.target_mask) == 0 ||
        !           781:            (tstate->tagenable & devinfo.target_mask) == 0)
        !           782:                ppr_options &= ~MSG_EXT_PPR_PROT_IUS;
        !           783:
        !           784:        syncrate = ahc_find_syncrate(ahc, &period, &ppr_options,
        !           785:            AHC_SYNCRATE_MAX);
        !           786:        ahc_validate_offset(ahc, NULL, syncrate, &offset, width,
        !           787:            ROLE_UNKNOWN);
        !           788:
        !           789:        if (offset == 0) {
        !           790:                period = 0;
        !           791:                ppr_options = 0;
        !           792:        }
        !           793:
        !           794:        if (ppr_options != 0 && tinfo->user.transport_version >= 3) {
        !           795:                tinfo->goal.transport_version = tinfo->user.transport_version;
        !           796:                tinfo->curr.transport_version = tinfo->user.transport_version;
        !           797:        }
        !           798:
        !           799:        ahc_set_syncrate(ahc, &devinfo, syncrate, period, offset, ppr_options,
        !           800:            AHC_TRANS_GOAL, FALSE);
        !           801:
        !           802:        splx(s);
        !           803: }

CVSweb