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

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

1.1     ! nbrk        1: /*     $OpenBSD: aic79xx_openbsd.c,v 1.26 2006/11/28 23:59:45 dlg Exp $        */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2004 Milos Urbanek, Kenneth R. Westerback & Marco Peereboom
        !             5:  * All rights reserved.
        !             6:  *
        !             7:  * Redistribution and use in source and binary forms, with or without
        !             8:  * modification, are permitted provided that the following conditions
        !             9:  * are met:
        !            10:  * 1. Redistributions of source code must retain the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer.
        !            12:  * 2. Redistributions in binary form must reproduce the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer in the
        !            14:  *    documentation and/or other materials provided with the distribution.
        !            15:  *
        !            16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
        !            17:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            18:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            19:  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
        !            20:  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            21:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            22:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            23:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            24:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            25:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            26:  * SUCH DAMAGE.
        !            27:  *
        !            28:  */
        !            29:
        !            30: /*
        !            31:  * Bus independent OpenBSD shim for the aic79xx based Adaptec SCSI controllers
        !            32:  *
        !            33:  * Copyright (c) 1994-2002 Justin T. Gibbs.
        !            34:  * Copyright (c) 2001-2002 Adaptec Inc.
        !            35:  * All rights reserved.
        !            36:  *
        !            37:  * Redistribution and use in source and binary forms, with or without
        !            38:  * modification, are permitted provided that the following conditions
        !            39:  * are met:
        !            40:  * 1. Redistributions of source code must retain the above copyright
        !            41:  *    notice, this list of conditions, and the following disclaimer,
        !            42:  *    without modification.
        !            43:  * 2. The name of the author may not be used to endorse or promote products
        !            44:  *    derived from this software without specific prior written permission.
        !            45:  *
        !            46:  * Alternatively, this software may be distributed under the terms of the
        !            47:  * GNU Public License ("GPL").
        !            48:  *
        !            49:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
        !            50:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            51:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            52:  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
        !            53:  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            54:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            55:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            56:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            57:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            58:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            59:  * SUCH DAMAGE.
        !            60:  *
        !            61:  */
        !            62:
        !            63: #include <sys/cdefs.h>
        !            64: /*
        !            65: __FBSDID("$FreeBSD: src/sys/dev/aic7xxx/aic79xx_osm.c,v 1.16 2003/12/17 00:02:09 gibbs Exp $");
        !            66: */
        !            67:
        !            68: #include <dev/ic/aic79xx_openbsd.h>
        !            69: #include <dev/ic/aic79xx_inline.h>
        !            70: #include <dev/ic/aic79xx.h>
        !            71:
        !            72: #ifndef AHD_TMODE_ENABLE
        !            73: #define AHD_TMODE_ENABLE 0
        !            74: #endif
        !            75:
        !            76: /* XXX milos add ahd_ioctl */
        !            77: int    ahd_action(struct scsi_xfer *);
        !            78: int    ahd_execute_scb(void *, bus_dma_segment_t *, int);
        !            79: int    ahd_poll(struct ahd_softc *, int);
        !            80: int    ahd_setup_data(struct ahd_softc *, struct scsi_xfer *,
        !            81:                    struct scb *);
        !            82:
        !            83: void   ahd_adapter_req_set_xfer_mode(struct ahd_softc *, struct scb *);
        !            84: void    ahd_minphys(struct buf *);
        !            85:
        !            86: struct cfdriver ahd_cd = {
        !            87:        NULL, "ahd", DV_DULL
        !            88: };
        !            89:
        !            90: static struct scsi_adapter ahd_switch =
        !            91: {
        !            92:        ahd_action,
        !            93:        ahd_minphys,
        !            94:        0,
        !            95:        0,
        !            96: };
        !            97:
        !            98: /* the below structure is so we have a default dev struct for our link struct */
        !            99: static struct scsi_device ahd_dev =
        !           100: {
        !           101:        NULL, /* Use default error handler */
        !           102:        NULL, /* have a queue, served by this */
        !           103:        NULL, /* have no async handler */
        !           104:        NULL, /* Use default 'done' routine */
        !           105: };
        !           106:
        !           107: /*
        !           108:  * Attach all the sub-devices we can find
        !           109:  */
        !           110: int
        !           111: ahd_attach(struct ahd_softc *ahd)
        !           112: {
        !           113:        struct scsibus_attach_args saa;
        !           114:        char   ahd_info[256];
        !           115:        int     s;
        !           116:
        !           117:        ahd_controller_info(ahd, ahd_info, sizeof ahd_info);
        !           118:        printf("%s\n", ahd_info);
        !           119:        ahd_lock(ahd, &s);
        !           120:
        !           121:        /*
        !           122:         * fill in the prototype scsi_links.
        !           123:         */
        !           124:        ahd->sc_channel.adapter_target = ahd->our_id;
        !           125:        if (ahd->features & AHD_WIDE)
        !           126:                ahd->sc_channel.adapter_buswidth = 16;
        !           127:        ahd->sc_channel.adapter_softc = ahd;
        !           128:        ahd->sc_channel.adapter = &ahd_switch;
        !           129:        ahd->sc_channel.openings = 16;
        !           130:        ahd->sc_channel.device = &ahd_dev;
        !           131:
        !           132:        if (bootverbose) {
        !           133:                ahd_controller_info(ahd, ahd_info, sizeof ahd_info);
        !           134:                printf("%s: %s\n", ahd->sc_dev.dv_xname, ahd_info);
        !           135:        }
        !           136:
        !           137:        ahd_intr_enable(ahd, TRUE);
        !           138:
        !           139:        if (ahd->flags & AHD_RESET_BUS_A)
        !           140:                ahd_reset_channel(ahd, 'A', TRUE);
        !           141:
        !           142:        bzero(&saa, sizeof(saa));
        !           143:        saa.saa_sc_link = &ahd->sc_channel;
        !           144:
        !           145:        ahd->sc_child = config_found((void *)&ahd->sc_dev, &saa, scsiprint);
        !           146:
        !           147:        ahd_unlock(ahd, &s);
        !           148:
        !           149:        return (1);
        !           150:
        !           151: }
        !           152:
        !           153: /*
        !           154:  * Catch an interrupt from the adapter
        !           155:  */
        !           156: int
        !           157: ahd_platform_intr(void *arg)
        !           158: {
        !           159:        struct  ahd_softc *ahd;
        !           160:
        !           161:        /* XXX in ahc there is some bus_dmamap_sync(PREREAD|PREWRITE); */
        !           162:
        !           163:        ahd = (struct ahd_softc *)arg;
        !           164:        return ahd_intr(ahd);
        !           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: ahd_done(struct ahd_softc *ahd, struct scb *scb)
        !           174: {
        !           175:        struct scsi_xfer *xs = scb->xs;
        !           176:        int s;
        !           177:
        !           178:        /* XXX in ahc there is some bus_dmamap_sync(PREREAD|PREWRITE); */
        !           179:
        !           180:        LIST_REMOVE(scb, pending_links);
        !           181:
        !           182:        timeout_del(&xs->stimeout);
        !           183:
        !           184:        if (xs->datalen) {
        !           185:                int op;
        !           186:
        !           187:                if ((xs->flags & SCSI_DATA_IN) != 0)
        !           188:                        op = BUS_DMASYNC_POSTREAD;
        !           189:                else
        !           190:                        op = BUS_DMASYNC_POSTWRITE;
        !           191:                bus_dmamap_sync(ahd->parent_dmat, scb->dmamap, 0,
        !           192:                    scb->dmamap->dm_mapsize, op);
        !           193:                bus_dmamap_unload(ahd->parent_dmat, scb->dmamap);
        !           194:        }
        !           195:
        !           196:        /* Translate the CAM status code to a SCSI error code. */
        !           197:        switch (xs->error) {
        !           198:        case CAM_SCSI_STATUS_ERROR:
        !           199:        case CAM_REQ_INPROG:
        !           200:        case CAM_REQ_CMP:
        !           201:                switch (xs->status) {
        !           202:                case SCSI_TASKSET_FULL:
        !           203:                        /* SCSI Layer won't requeue, so we force infinite
        !           204:                         * retries until queue space is available. XS_BUSY
        !           205:                         * is dangerous because if the NOSLEEP flag is set
        !           206:                         * it can cause the I/O to return EIO. XS_BUSY code
        !           207:                         * falls through to XS_TIMEOUT anyway.
        !           208:                         */
        !           209:                        xs->error = XS_TIMEOUT;
        !           210:                        xs->retries++;
        !           211:                        break;
        !           212:                case SCSI_BUSY:
        !           213:                        xs->error = XS_BUSY;
        !           214:                        break;
        !           215:                case SCSI_CHECK:
        !           216:                case SCSI_TERMINATED:
        !           217:                        if ((scb->flags & SCB_SENSE) == 0) {
        !           218:                                /* CHECK on CHECK? */
        !           219:                                xs->error = XS_DRIVER_STUFFUP;
        !           220:                        } else
        !           221:                                xs->error = XS_NOERROR;
        !           222:                        break;
        !           223:                default:
        !           224:                        xs->error = XS_NOERROR;
        !           225:                        break;
        !           226:                }
        !           227:                break;
        !           228:        case CAM_BUSY:
        !           229:                xs->error = XS_BUSY;
        !           230:                break;
        !           231:        case CAM_CMD_TIMEOUT:
        !           232:                xs->error = XS_TIMEOUT;
        !           233:                break;
        !           234:        case CAM_BDR_SENT:
        !           235:        case CAM_SCSI_BUS_RESET:
        !           236:                xs->error = XS_RESET;
        !           237:                break;
        !           238:        case CAM_REQUEUE_REQ:
        !           239:                xs->error = XS_TIMEOUT;
        !           240:                xs->retries++;
        !           241:                break;
        !           242:        case CAM_SEL_TIMEOUT:
        !           243:                xs->error = XS_SELTIMEOUT;
        !           244:                break;
        !           245:        default:
        !           246:                xs->error = XS_DRIVER_STUFFUP;
        !           247:                break;
        !           248:        }
        !           249:
        !           250:        if (xs->error != XS_NOERROR) {
        !           251:                /* Don't clobber any existing error state */
        !           252:        } else if ((scb->flags & SCB_SENSE) != 0) {
        !           253:                /*
        !           254:                 * We performed autosense retrieval.
        !           255:                 *
        !           256:                 * Zero any sense not transferred by the
        !           257:                 * device.  The SCSI spec mandates that any
        !           258:                 * untransfered data should be assumed to be
        !           259:                 * zero.  Complete the 'bounce' of sense information
        !           260:                 * through buffers accessible via bus-space by
        !           261:                 * copying it into the clients csio.
        !           262:                 */
        !           263:                memset(&xs->sense, 0, sizeof(struct scsi_sense_data));
        !           264:                memcpy(&xs->sense, ahd_get_sense_buf(ahd, scb),
        !           265:                    sizeof(struct scsi_sense_data));
        !           266:                xs->error = XS_SENSE;
        !           267:        } else if ((scb->flags & SCB_PKT_SENSE) != 0) {
        !           268:                struct scsi_status_iu_header *siu;
        !           269:                u_int32_t len;
        !           270:
        !           271:                siu = (struct scsi_status_iu_header *)scb->sense_data;
        !           272:                len = SIU_SENSE_LENGTH(siu);
        !           273:                memset(&xs->sense, 0, sizeof(xs->sense));
        !           274:                memcpy(&xs->sense, SIU_SENSE_DATA(siu),
        !           275:                    ulmin(len, sizeof(xs->sense)));
        !           276:                xs->error = XS_SENSE;
        !           277:        }
        !           278:
        !           279:        ahd_lock(ahd, &s);
        !           280:        ahd_free_scb(ahd, scb);
        !           281:        ahd_unlock(ahd, &s);
        !           282:
        !           283:        xs->flags |= ITSDONE;
        !           284:        scsi_done(xs);
        !           285: }
        !           286:
        !           287: void
        !           288: ahd_minphys(struct buf *bp)
        !           289: {
        !           290:        /*
        !           291:         * Even though the card can transfer up to 16megs per command
        !           292:         * we are limited by the number of segments in the dma segment
        !           293:         * list that we can hold.  The worst case is that all pages are
        !           294:         * discontinuous physically, hence the "page per segment" limit
        !           295:         * enforced here.
        !           296:         */
        !           297:        if (bp->b_bcount > ((AHD_NSEG - 1) * PAGE_SIZE)) {
        !           298:                bp->b_bcount = ((AHD_NSEG - 1) * PAGE_SIZE);
        !           299:        }
        !           300:        minphys(bp);
        !           301: }
        !           302:
        !           303: int32_t
        !           304: ahd_action(struct scsi_xfer *xs)
        !           305: {
        !           306:        struct  ahd_softc *ahd;
        !           307:        struct scb *scb;
        !           308:        struct hardware_scb *hscb;
        !           309:        u_int   target_id;
        !           310:        u_int   our_id;
        !           311:        int     s;
        !           312:        int     dontqueue = 0;
        !           313:        struct  ahd_initiator_tinfo *tinfo;
        !           314:        struct  ahd_tmode_tstate *tstate;
        !           315:        u_int   col_idx;
        !           316:        u_int16_t quirks;
        !           317:
        !           318:        SC_DEBUG(xs->sc_link, SDEV_DB3, ("ahd_action\n"));
        !           319:        ahd = (struct ahd_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(ahd, xs->sc_link);
        !           326:
        !           327:        if ((ahd->flags & AHD_INITIATORROLE) == 0) {
        !           328:                xs->error = XS_DRIVER_STUFFUP;
        !           329:                xs->flags |= ITSDONE;
        !           330:                scsi_done(xs);
        !           331:                return (COMPLETE);
        !           332:                /* return       ccb->ccb_h.status = CAM_PROVIDE_FAIL; */
        !           333:        }
        !           334:        /*
        !           335:         * get an scb to use.
        !           336:         */
        !           337:        ahd_lock(ahd, &s);
        !           338:        tinfo = ahd_fetch_transinfo(ahd, 'A', our_id, target_id, &tstate);
        !           339:
        !           340:        quirks = xs->sc_link->quirks;
        !           341:
        !           342:        if ((quirks & SDEV_NOTAGS) != 0 ||
        !           343:            (tinfo->curr.ppr_options & MSG_EXT_PPR_PROT_IUS) != 0)
        !           344:                col_idx = AHD_NEVER_COL_IDX;
        !           345:        else
        !           346:                col_idx = AHD_BUILD_COL_IDX(target_id, xs->sc_link->lun);
        !           347:
        !           348:        if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) {
        !           349:                ahd->flags |= AHD_RESOURCE_SHORTAGE;
        !           350:                ahd_unlock(ahd, &s);
        !           351:                return (TRY_AGAIN_LATER);
        !           352:        }
        !           353:        ahd_unlock(ahd, &s);
        !           354:
        !           355:        hscb = scb->hscb;
        !           356:
        !           357:        SC_DEBUG(xs->sc_link, SDEV_DB3, ("start scb(%p)\n", scb));
        !           358:
        !           359:        scb->xs = xs;
        !           360:        timeout_set(&xs->stimeout, ahd_timeout, scb);
        !           361:
        !           362:        /*
        !           363:         * Put all the arguments for the xfer in the scb
        !           364:         */
        !           365:        hscb->control = 0;
        !           366:        hscb->scsiid = BUILD_SCSIID(ahd, xs->sc_link, target_id, our_id);
        !           367:        hscb->lun = xs->sc_link->lun;
        !           368:        if (xs->xs_control & XS_CTL_RESET) {
        !           369:                hscb->cdb_len = 0;
        !           370:                scb->flags |= SCB_DEVICE_RESET;
        !           371:                hscb->control |= MK_MESSAGE;
        !           372:                hscb->task_management = SIU_TASKMGMT_LUN_RESET;
        !           373:                return (ahd_execute_scb(scb, NULL, 0));
        !           374:        } else {
        !           375:                hscb->task_management = 0;
        !           376:                return (ahd_setup_data(ahd, xs, scb));
        !           377:        }
        !           378: }
        !           379:
        !           380: int
        !           381: ahd_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments)
        !           382: {
        !           383:        struct  scb *scb;
        !           384:        struct  scsi_xfer *xs;
        !           385:        struct  ahd_softc *ahd;
        !           386:        struct  ahd_initiator_tinfo *tinfo;
        !           387:        struct  ahd_tmode_tstate *tstate;
        !           388:        u_int   mask;
        !           389:        int     s;
        !           390:
        !           391:        scb = (struct scb *)arg;
        !           392:        xs = scb->xs;
        !           393:        xs->error = CAM_REQ_INPROG;
        !           394:        xs->status = 0;
        !           395:        ahd = (struct ahd_softc *)xs->sc_link->adapter_softc;
        !           396:
        !           397:        if (nsegments != 0) {
        !           398:                void *sg;
        !           399:                int op;
        !           400:                u_int i;
        !           401:
        !           402:                ahd_setup_data_scb(ahd, scb);
        !           403:
        !           404:                /* Copy the segments into our SG list */
        !           405:                for (i = nsegments, sg = scb->sg_list; i > 0; i--) {
        !           406:
        !           407:                        sg = ahd_sg_setup(ahd, scb, sg, dm_segs->ds_addr,
        !           408:                                          dm_segs->ds_len,
        !           409:                                          /*last*/i == 1);
        !           410:                        dm_segs++;
        !           411:                }
        !           412:
        !           413:                if ((xs->flags & SCSI_DATA_IN) != 0)
        !           414:                        op = BUS_DMASYNC_PREREAD;
        !           415:                else
        !           416:                        op = BUS_DMASYNC_PREWRITE;
        !           417:
        !           418:                bus_dmamap_sync(ahd->parent_dmat, scb->dmamap, 0,
        !           419:                                scb->dmamap->dm_mapsize, op);
        !           420:
        !           421:        }
        !           422:
        !           423:        ahd_lock(ahd, &s);
        !           424:
        !           425:        /*
        !           426:         * Last time we need to check if this SCB needs to
        !           427:         * be aborted.
        !           428:         */
        !           429:        if (xs->flags & ITSDONE) {
        !           430:                if (nsegments != 0)
        !           431:                        bus_dmamap_unload(ahd->parent_dmat,
        !           432:                                          scb->dmamap);
        !           433:                ahd_free_scb(ahd, scb);
        !           434:                ahd_unlock(ahd, &s);
        !           435:                return (COMPLETE);
        !           436:        }
        !           437:
        !           438:        tinfo = ahd_fetch_transinfo(ahd, SCSIID_CHANNEL(ahd, scb->hscb->scsiid),
        !           439:                                    SCSIID_OUR_ID(scb->hscb->scsiid),
        !           440:                                    SCSIID_TARGET(ahd, scb->hscb->scsiid),
        !           441:                                    &tstate);
        !           442:
        !           443:        mask = SCB_GET_TARGET_MASK(ahd, scb);
        !           444:
        !           445:        if ((tstate->discenable & mask) != 0)
        !           446:                scb->hscb->control |= DISCENB;
        !           447:
        !           448:        if ((tstate->tagenable & mask) != 0)
        !           449:                scb->hscb->control |= TAG_ENB;
        !           450:
        !           451:        if ((tinfo->curr.ppr_options & MSG_EXT_PPR_PROT_IUS) != 0) {
        !           452:                scb->flags |= SCB_PACKETIZED;
        !           453:                if (scb->hscb->task_management != 0)
        !           454:                        scb->hscb->control &= ~MK_MESSAGE;
        !           455:        }
        !           456:
        !           457:        if ((tstate->auto_negotiate & mask) != 0) {
        !           458:                scb->flags |= SCB_AUTO_NEGOTIATE;
        !           459:                scb->hscb->control |= MK_MESSAGE;
        !           460:        }
        !           461:
        !           462:        /* XXX with ahc there was some bus_dmamap_sync(PREREAD|PREWRITE); */
        !           463:
        !           464:        LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links);
        !           465:
        !           466:        if (!(xs->flags & SCSI_POLL))
        !           467:                timeout_add(&xs->stimeout, (xs->timeout * hz) / 1000);
        !           468:
        !           469:        scb->flags |= SCB_ACTIVE;
        !           470:
        !           471:        if ((scb->flags & SCB_TARGET_IMMEDIATE) != 0) {
        !           472:                /* Define a mapping from our tag to the SCB. */
        !           473:                ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb;
        !           474:                ahd_pause(ahd);
        !           475:                ahd_set_scbptr(ahd, SCB_GET_TAG(scb));
        !           476:                ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_TARG);
        !           477:                ahd_unpause(ahd);
        !           478:        } else {
        !           479:                ahd_queue_scb(ahd, scb);
        !           480:        }
        !           481:
        !           482:        if (!(xs->flags & SCSI_POLL)) {
        !           483:                int target = xs->sc_link->target;
        !           484:                int lun = SCB_GET_LUN(scb);
        !           485:
        !           486:                if (ahd->inited_target[target] == 0) {
        !           487:                        struct  ahd_devinfo devinfo;
        !           488:
        !           489:                        ahd_adapter_req_set_xfer_mode(ahd, scb);
        !           490:                        ahd_compile_devinfo(&devinfo, ahd->our_id, target, lun,
        !           491:                            'A', /*XXX milos*/ROLE_UNKNOWN);
        !           492:                        ahd_scb_devinfo(ahd, &devinfo, scb);
        !           493:                        ahd_update_neg_request(ahd, &devinfo, tstate, tinfo,
        !           494:                                AHD_NEG_IF_NON_ASYNC);
        !           495:                        ahd->inited_target[target] = 1;
        !           496:                }
        !           497:
        !           498:                ahd_unlock(ahd, &s);
        !           499:                return (SUCCESSFULLY_QUEUED);
        !           500:        }
        !           501:
        !           502:        /*
        !           503:         * If we can't use interrupts, poll for completion
        !           504:         */
        !           505:        SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_poll\n"));
        !           506:
        !           507:        do {
        !           508:                if (ahd_poll(ahd, xs->timeout)) {
        !           509:                        if (!(xs->flags & SCSI_SILENT))
        !           510:                                printf("cmd fail\n");
        !           511:                        ahd_timeout(scb);
        !           512:                        break;
        !           513:                }
        !           514:        } while (!(xs->flags & ITSDONE));
        !           515:
        !           516:        ahd_unlock(ahd, &s);
        !           517:        return (COMPLETE);
        !           518: }
        !           519:
        !           520: int
        !           521: ahd_poll(struct ahd_softc *ahd, int wait)
        !           522: {
        !           523:        while (--wait) {
        !           524:                DELAY(1000);
        !           525:                if (ahd_inb(ahd, INTSTAT) & INT_PEND)
        !           526:                        break;
        !           527:        }
        !           528:
        !           529:        if (wait == 0) {
        !           530:                printf("%s: board is not responding\n", ahd_name(ahd));
        !           531:                return (EIO);
        !           532:        }
        !           533:
        !           534:        ahd_intr((void *)ahd);
        !           535:        return (0);
        !           536: }
        !           537:
        !           538: int
        !           539: ahd_setup_data(struct ahd_softc *ahd, struct scsi_xfer *xs,
        !           540:               struct scb *scb)
        !           541: {
        !           542:        struct hardware_scb *hscb;
        !           543:        int s;
        !           544:
        !           545:        hscb = scb->hscb;
        !           546:        xs->resid = xs->status = 0;
        !           547:        xs->error = CAM_REQ_INPROG;
        !           548:
        !           549:        hscb->cdb_len = xs->cmdlen;
        !           550:        if (hscb->cdb_len > MAX_CDB_LEN) {
        !           551:                ahd_lock(ahd, &s);
        !           552:                ahd_free_scb(ahd, scb);
        !           553:                ahd_unlock(ahd, &s);
        !           554:                xs->error = XS_DRIVER_STUFFUP;
        !           555:                xs->flags |= ITSDONE;
        !           556:                scsi_done(xs);
        !           557:                return (COMPLETE);
        !           558:        }
        !           559:
        !           560:        memcpy(hscb->shared_data.idata.cdb, xs->cmd, hscb->cdb_len);
        !           561:
        !           562:        /* Only use S/G if there is a transfer */
        !           563:        if (xs->datalen) {
        !           564:                int error;
        !           565:
        !           566:                error = bus_dmamap_load(ahd->parent_dmat,
        !           567:                                        scb->dmamap, xs->data,
        !           568:                                        xs->datalen, NULL,
        !           569:                                        ((xs->flags & SCSI_NOSLEEP) ?
        !           570:                                        BUS_DMA_NOWAIT : BUS_DMA_WAITOK) |
        !           571:                                        BUS_DMA_STREAMING |
        !           572:                                        ((xs->flags & XS_CTL_DATA_IN) ?
        !           573:                                        BUS_DMA_READ : BUS_DMA_WRITE));
        !           574:                if (error) {
        !           575: #ifdef AHD_DEBUG
        !           576:                        printf("%s: in ahd_setup_data(): bus_dmamap_load() "
        !           577:                            "= %d\n", ahd_name(ahd), error);
        !           578: #endif
        !           579:                        ahd_lock(ahd, &s);
        !           580:                        ahd_free_scb(ahd, scb);
        !           581:                        ahd_unlock(ahd, &s);
        !           582:                        return (TRY_AGAIN_LATER);       /* XXX fvdl */
        !           583:                }
        !           584:                error = ahd_execute_scb(scb, scb->dmamap->dm_segs,
        !           585:                    scb->dmamap->dm_nsegs);
        !           586:                return error;
        !           587:        } else {
        !           588:                return ahd_execute_scb(scb, NULL, 0);
        !           589:        }
        !           590: }
        !           591:
        !           592: void
        !           593: ahd_platform_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
        !           594:     ahd_queue_alg alg)
        !           595: {
        !           596:        struct ahd_tmode_tstate *tstate;
        !           597:
        !           598:        ahd_fetch_transinfo(ahd, devinfo->channel, devinfo->our_scsiid,
        !           599:            devinfo->target, &tstate);
        !           600:
        !           601:        if (alg != AHD_QUEUE_NONE)
        !           602:                tstate->tagenable |= devinfo->target_mask;
        !           603:        else
        !           604:                tstate->tagenable &= ~devinfo->target_mask;
        !           605: }
        !           606:
        !           607: int
        !           608: ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg)
        !           609: {
        !           610:        if (sizeof(struct ahd_platform_data) > 0) {
        !           611:                ahd->platform_data = malloc(sizeof(struct ahd_platform_data),
        !           612:                    M_DEVBUF, M_NOWAIT);
        !           613:                if (ahd->platform_data == NULL)
        !           614:                        return (ENOMEM);
        !           615:                bzero(ahd->platform_data, sizeof(struct ahd_platform_data));
        !           616:        }
        !           617:
        !           618:        return (0);
        !           619: }
        !           620:
        !           621: void
        !           622: ahd_platform_free(struct ahd_softc *ahd)
        !           623: {
        !           624:        if (sizeof(struct ahd_platform_data) > 0)
        !           625:                free(ahd->platform_data, M_DEVBUF);
        !           626: }
        !           627:
        !           628: int
        !           629: ahd_softc_comp(struct ahd_softc *lahd, struct ahd_softc *rahd)
        !           630: {
        !           631:        /* We don't sort softcs under OpenBSD so report equal always */
        !           632:        return (0);
        !           633: }
        !           634:
        !           635: int
        !           636: ahd_detach(struct device *self, int flags)
        !           637: {
        !           638:        int rv = 0;
        !           639:
        !           640:        struct ahd_softc *ahd = (struct ahd_softc*)self;
        !           641:
        !           642:        if (ahd->sc_child != NULL)
        !           643:                rv = config_detach((void *)ahd->sc_child, flags);
        !           644:
        !           645:        if (ahd->shutdown_hook != NULL)
        !           646:                shutdownhook_disestablish(ahd->shutdown_hook);
        !           647:
        !           648:        ahd_free(ahd);
        !           649:
        !           650:        return rv;
        !           651: }
        !           652:
        !           653: void
        !           654: ahd_adapter_req_set_xfer_mode(struct ahd_softc *ahd, struct scb *scb)
        !           655: {
        !           656:        struct ahd_initiator_tinfo *tinfo;
        !           657:        struct ahd_tmode_tstate *tstate;
        !           658:        int target_id, our_id;
        !           659:        struct ahd_devinfo devinfo;
        !           660:        u_int16_t quirks;
        !           661:        u_int width, ppr_options, period, offset;
        !           662:        int s;
        !           663:
        !           664:        target_id = scb->xs->sc_link->target;
        !           665:        our_id = SCSI_SCSI_ID(ahd, scb->xs->sc_link);
        !           666:
        !           667:        s = splbio();
        !           668:
        !           669:        quirks = scb->xs->sc_link->quirks;
        !           670:        tinfo = ahd_fetch_transinfo(ahd, 'A', our_id, target_id, &tstate);
        !           671:        ahd_compile_devinfo(&devinfo, our_id, target_id, 0, 'A',
        !           672:            ROLE_INITIATOR);
        !           673:
        !           674:        tstate->discenable |= (ahd->user_discenable & devinfo.target_mask);
        !           675:
        !           676:        if (quirks & SDEV_NOTAGS)
        !           677:                tstate->tagenable &= ~devinfo.target_mask;
        !           678:        else if (ahd->user_tagenable & devinfo.target_mask)
        !           679:                tstate->tagenable |= devinfo.target_mask;
        !           680:
        !           681:        if (quirks & SDEV_NOWIDE)
        !           682:                width = MSG_EXT_WDTR_BUS_8_BIT;
        !           683:        else
        !           684:                width = MSG_EXT_WDTR_BUS_16_BIT;
        !           685:
        !           686:        ahd_validate_width(ahd, NULL, &width, ROLE_UNKNOWN);
        !           687:        if (width > tinfo->user.width)
        !           688:                width = tinfo->user.width;
        !           689:        ahd_set_width(ahd, &devinfo, width, AHD_TRANS_GOAL, FALSE);
        !           690:
        !           691:        if (quirks & SDEV_NOSYNC) {
        !           692:                period = 0;
        !           693:                offset = 0;
        !           694:        } else {
        !           695:                period = tinfo->user.period;
        !           696:                offset = tinfo->user.offset;
        !           697:        }
        !           698:
        !           699:        /* XXX Look at saved INQUIRY flags for PPR capabilities XXX */
        !           700:        ppr_options = tinfo->user.ppr_options;
        !           701:        /* XXX Other reasons to avoid ppr? XXX */
        !           702:        if (width < MSG_EXT_WDTR_BUS_16_BIT)
        !           703:                ppr_options = 0;
        !           704:
        !           705:        if ((tstate->discenable & devinfo.target_mask) == 0 ||
        !           706:            (tstate->tagenable & devinfo.target_mask) == 0)
        !           707:                ppr_options &= ~MSG_EXT_PPR_PROT_IUS;
        !           708:
        !           709:        ahd_find_syncrate(ahd, &period, &ppr_options, AHD_SYNCRATE_MAX);
        !           710:        ahd_validate_offset(ahd, NULL, period, &offset, width, ROLE_UNKNOWN);
        !           711:
        !           712:        if (offset == 0) {
        !           713:                period = 0;
        !           714:                ppr_options = 0;
        !           715:        }
        !           716:
        !           717:        if (ppr_options != 0 && tinfo->user.transport_version >= 3) {
        !           718:                tinfo->goal.transport_version = tinfo->user.transport_version;
        !           719:                tinfo->curr.transport_version = tinfo->user.transport_version;
        !           720:        }
        !           721:
        !           722:        ahd_set_syncrate(ahd, &devinfo, period, offset, ppr_options,
        !           723:                AHD_TRANS_GOAL, FALSE);
        !           724:
        !           725:        splx(s);
        !           726: }
        !           727:
        !           728: void
        !           729: aic_timer_reset(aic_timer_t *timer, u_int msec, ahd_callback_t *func,
        !           730:     void *arg)
        !           731: {
        !           732:        uint64_t ticks;
        !           733:
        !           734:        ticks = msec;
        !           735:        ticks *= hz;
        !           736:        ticks /= 1000;
        !           737:        callout_reset(timer, ticks, func, arg);
        !           738: }
        !           739:
        !           740: void
        !           741: aic_scb_timer_reset(struct scb *scb, u_int msec)
        !           742: {
        !           743:        uint64_t ticks;
        !           744:
        !           745:        ticks = msec;
        !           746:        ticks *= hz;
        !           747:        ticks /= 1000;
        !           748:        if (!(scb->xs->xs_control & XS_CTL_POLL))
        !           749:                callout_reset(&scb->xs->xs_callout, ticks, ahd_timeout, scb);
        !           750: }
        !           751:
        !           752: void
        !           753: ahd_flush_device_writes(struct ahd_softc *ahd)
        !           754: {
        !           755:        /* XXX Is this sufficient for all architectures??? */
        !           756:        ahd_inb(ahd, INTSTAT);
        !           757: }
        !           758:
        !           759: void
        !           760: aic_platform_scb_free(struct ahd_softc *ahd, struct scb *scb)
        !           761: {
        !           762:        int s;
        !           763:
        !           764:        ahd_lock(ahd, &s);
        !           765:
        !           766:        if ((ahd->flags & AHD_RESOURCE_SHORTAGE) != 0) {
        !           767:                ahd->flags &= ~AHD_RESOURCE_SHORTAGE;
        !           768:        }
        !           769:
        !           770:        if (!cold) {
        !           771:                /* we are no longer in autoconf */
        !           772:                timeout_del(&scb->xs->stimeout);
        !           773:        }
        !           774:
        !           775:        ahd_unlock(ahd, &s);
        !           776: }
        !           777:
        !           778: void
        !           779: ahd_print_path(struct ahd_softc *ahd, struct scb *scb)
        !           780: {
        !           781:        sc_print_addr(scb->xs->sc_link);
        !           782: }
        !           783:
        !           784: void
        !           785: ahd_platform_dump_card_state(struct ahd_softc *ahd)
        !           786: {
        !           787:        /* Nothing to do here for OpenBSD */
        !           788:        printf("FEATURES = 0x%x, FLAGS = 0x%x, CHIP = 0x%x BUGS =0x%x\n",
        !           789:                ahd->features, ahd->flags, ahd->chip, ahd->bugs);
        !           790: }
        !           791:
        !           792: void
        !           793: ahd_platform_flushwork(struct ahd_softc *ahd)
        !           794: {
        !           795: }

CVSweb