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

Annotation of sys/dev/sdmmc/sdmmc_scsi.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: sdmmc_scsi.c,v 1.7 2006/11/28 23:59:45 dlg Exp $      */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
        !             5:  *
        !             6:  * Permission to use, copy, modify, and distribute this software for any
        !             7:  * purpose with or without fee is hereby granted, provided that the above
        !             8:  * copyright notice and this permission notice appear in all copies.
        !             9:  *
        !            10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            17:  */
        !            18:
        !            19: /* A SCSI adapter emulation to access SD/MMC memory cards */
        !            20:
        !            21: #include <sys/param.h>
        !            22: #include <sys/buf.h>
        !            23: #include <sys/kernel.h>
        !            24: #include <sys/malloc.h>
        !            25: #include <sys/proc.h>
        !            26: #include <sys/systm.h>
        !            27:
        !            28: #include <scsi/scsi_all.h>
        !            29: #include <scsi/scsi_disk.h>
        !            30: #include <scsi/scsiconf.h>
        !            31:
        !            32: #include <dev/sdmmc/sdmmc_scsi.h>
        !            33: #include <dev/sdmmc/sdmmcvar.h>
        !            34:
        !            35: #define SDMMC_SCSIID_HOST      0x00
        !            36: #define SDMMC_SCSIID_MAX       0x0f
        !            37:
        !            38: #define SDMMC_SCSI_MAXCMDS     8
        !            39:
        !            40: struct sdmmc_scsi_target {
        !            41:        struct sdmmc_function *card;
        !            42: };
        !            43:
        !            44: struct sdmmc_ccb {
        !            45:        struct sdmmc_scsi_softc *ccb_scbus;
        !            46:        struct scsi_xfer *ccb_xs;
        !            47:        int ccb_flags;
        !            48: #define SDMMC_CCB_F_ERR                0x0001
        !            49:        void (*ccb_done)(struct sdmmc_ccb *);
        !            50:        u_int32_t ccb_blockno;
        !            51:        u_int32_t ccb_blockcnt;
        !            52:        volatile enum {
        !            53:                SDMMC_CCB_FREE,
        !            54:                SDMMC_CCB_READY,
        !            55:                SDMMC_CCB_QUEUED
        !            56:        } ccb_state;
        !            57:        struct sdmmc_command ccb_cmd;
        !            58:        struct sdmmc_task ccb_task;
        !            59:        TAILQ_ENTRY(sdmmc_ccb) ccb_link;
        !            60: };
        !            61:
        !            62: TAILQ_HEAD(sdmmc_ccb_list, sdmmc_ccb);
        !            63:
        !            64: struct sdmmc_scsi_softc {
        !            65:        struct scsi_adapter sc_adapter;
        !            66:        struct scsi_link sc_link;
        !            67:        struct device *sc_child;
        !            68:        struct sdmmc_scsi_target *sc_tgt;
        !            69:        int sc_ntargets;
        !            70:        struct sdmmc_ccb *sc_ccbs;              /* allocated ccbs */
        !            71:        struct sdmmc_ccb_list sc_ccb_freeq;     /* free ccbs */
        !            72:        struct sdmmc_ccb_list sc_ccb_runq;      /* queued ccbs */
        !            73: };
        !            74:
        !            75: int    sdmmc_alloc_ccbs(struct sdmmc_scsi_softc *, int);
        !            76: void   sdmmc_free_ccbs(struct sdmmc_scsi_softc *);
        !            77: struct sdmmc_ccb *sdmmc_get_ccb(struct sdmmc_scsi_softc *, int);
        !            78: void   sdmmc_put_ccb(struct sdmmc_ccb *);
        !            79:
        !            80: int    sdmmc_scsi_cmd(struct scsi_xfer *);
        !            81: int    sdmmc_start_xs(struct sdmmc_softc *, struct sdmmc_ccb *);
        !            82: void   sdmmc_complete_xs(void *);
        !            83: void   sdmmc_done_xs(struct sdmmc_ccb *);
        !            84: void   sdmmc_stimeout(void *);
        !            85: void   sdmmc_scsi_minphys(struct buf *);
        !            86:
        !            87: #define DEVNAME(sc)    SDMMCDEVNAME(sc)
        !            88:
        !            89: #ifdef SDMMC_DEBUG
        !            90: #define DPRINTF(s)     printf s
        !            91: #else
        !            92: #define DPRINTF(s)     /**/
        !            93: #endif
        !            94:
        !            95: void
        !            96: sdmmc_scsi_attach(struct sdmmc_softc *sc)
        !            97: {
        !            98:        struct scsibus_attach_args saa;
        !            99:        struct sdmmc_scsi_softc *scbus;
        !           100:        struct sdmmc_function *sf;
        !           101:
        !           102:        MALLOC(scbus, struct sdmmc_scsi_softc *,
        !           103:            sizeof *scbus, M_DEVBUF, M_WAITOK);
        !           104:        bzero(scbus, sizeof *scbus);
        !           105:
        !           106:        MALLOC(scbus->sc_tgt, struct sdmmc_scsi_target *,
        !           107:            sizeof(*scbus->sc_tgt) * (SDMMC_SCSIID_MAX+1),
        !           108:            M_DEVBUF, M_WAITOK);
        !           109:        bzero(scbus->sc_tgt, sizeof(*scbus->sc_tgt) * (SDMMC_SCSIID_MAX+1));
        !           110:
        !           111:        /*
        !           112:         * Each card that sent us a CID in the identification stage
        !           113:         * gets a SCSI ID > 0, whether it is a memory card or not.
        !           114:         */
        !           115:        scbus->sc_ntargets = 1;
        !           116:        SIMPLEQ_FOREACH(sf, &sc->sf_head, sf_list) {
        !           117:                if (scbus->sc_ntargets >= SDMMC_SCSIID_MAX+1)
        !           118:                        break;
        !           119:                scbus->sc_tgt[scbus->sc_ntargets].card = sf;
        !           120:                scbus->sc_ntargets++;
        !           121:        }
        !           122:
        !           123:        /* Preallocate some CCBs and initialize the CCB lists. */
        !           124:        if (sdmmc_alloc_ccbs(scbus, SDMMC_SCSI_MAXCMDS) != 0) {
        !           125:                printf("%s: can't allocate ccbs\n", sc->sc_dev.dv_xname);
        !           126:                goto free_sctgt;
        !           127:        }
        !           128:
        !           129:        sc->sc_scsibus = scbus;
        !           130:
        !           131:        scbus->sc_adapter.scsi_cmd = sdmmc_scsi_cmd;
        !           132:        scbus->sc_adapter.scsi_minphys = sdmmc_scsi_minphys;
        !           133:
        !           134:        scbus->sc_link.adapter_target = SDMMC_SCSIID_HOST;
        !           135:        scbus->sc_link.adapter_buswidth = scbus->sc_ntargets;
        !           136:        scbus->sc_link.adapter_softc = sc;
        !           137:        scbus->sc_link.luns = 1;
        !           138:        scbus->sc_link.openings = 1;
        !           139:        scbus->sc_link.adapter = &scbus->sc_adapter;
        !           140:
        !           141:        bzero(&saa, sizeof(saa));
        !           142:        saa.saa_sc_link = &scbus->sc_link;
        !           143:
        !           144:        scbus->sc_child = config_found(&sc->sc_dev, &saa, scsiprint);
        !           145:        if (scbus->sc_child == NULL) {
        !           146:                printf("%s: can't attach scsibus\n", sc->sc_dev.dv_xname);
        !           147:                goto free_ccbs;
        !           148:        }
        !           149:        return;
        !           150:
        !           151:  free_ccbs:
        !           152:        sc->sc_scsibus = NULL;
        !           153:        sdmmc_free_ccbs(scbus);
        !           154:  free_sctgt:
        !           155:        free(scbus->sc_tgt, M_DEVBUF);
        !           156:        free(scbus, M_DEVBUF);
        !           157: }
        !           158:
        !           159: void
        !           160: sdmmc_scsi_detach(struct sdmmc_softc *sc)
        !           161: {
        !           162:        struct sdmmc_scsi_softc *scbus;
        !           163:        struct sdmmc_ccb *ccb;
        !           164:        int s;
        !           165:
        !           166:        scbus = sc->sc_scsibus;
        !           167:        if (scbus == NULL)
        !           168:                return;
        !           169:
        !           170:        /* Complete all open scsi xfers. */
        !           171:        s = splbio();
        !           172:        for (ccb = TAILQ_FIRST(&scbus->sc_ccb_runq); ccb != NULL;
        !           173:             ccb = TAILQ_FIRST(&scbus->sc_ccb_runq))
        !           174:                sdmmc_stimeout(ccb);
        !           175:        splx(s);
        !           176:
        !           177:        if (scbus->sc_child != NULL)
        !           178:                config_detach(scbus->sc_child, DETACH_FORCE);
        !           179:
        !           180:        if (scbus->sc_tgt != NULL)
        !           181:                FREE(scbus->sc_tgt, M_DEVBUF);
        !           182:
        !           183:        sdmmc_free_ccbs(scbus);
        !           184:        FREE(scbus, M_DEVBUF);
        !           185:        sc->sc_scsibus = NULL;
        !           186: }
        !           187:
        !           188: /*
        !           189:  * CCB management
        !           190:  */
        !           191:
        !           192: int
        !           193: sdmmc_alloc_ccbs(struct sdmmc_scsi_softc *scbus, int nccbs)
        !           194: {
        !           195:        struct sdmmc_ccb *ccb;
        !           196:        int i;
        !           197:
        !           198:        scbus->sc_ccbs = malloc(sizeof(struct sdmmc_ccb) * nccbs,
        !           199:            M_DEVBUF, M_NOWAIT);
        !           200:        if (scbus->sc_ccbs == NULL)
        !           201:                return 1;
        !           202:
        !           203:        TAILQ_INIT(&scbus->sc_ccb_freeq);
        !           204:        TAILQ_INIT(&scbus->sc_ccb_runq);
        !           205:
        !           206:        for (i = 0; i < nccbs; i++) {
        !           207:                ccb = &scbus->sc_ccbs[i];
        !           208:                ccb->ccb_scbus = scbus;
        !           209:                ccb->ccb_state = SDMMC_CCB_FREE;
        !           210:                ccb->ccb_flags = 0;
        !           211:                ccb->ccb_xs = NULL;
        !           212:                ccb->ccb_done = NULL;
        !           213:
        !           214:                TAILQ_INSERT_TAIL(&scbus->sc_ccb_freeq, ccb, ccb_link);
        !           215:        }
        !           216:        return 0;
        !           217: }
        !           218:
        !           219: void
        !           220: sdmmc_free_ccbs(struct sdmmc_scsi_softc *scbus)
        !           221: {
        !           222:        if (scbus->sc_ccbs != NULL) {
        !           223:                free(scbus->sc_ccbs, M_DEVBUF);
        !           224:                scbus->sc_ccbs = NULL;
        !           225:        }
        !           226: }
        !           227:
        !           228: struct sdmmc_ccb *
        !           229: sdmmc_get_ccb(struct sdmmc_scsi_softc *scbus, int flags)
        !           230: {
        !           231:        struct sdmmc_ccb *ccb;
        !           232:        int s;
        !           233:
        !           234:        s = splbio();
        !           235:        while ((ccb = TAILQ_FIRST(&scbus->sc_ccb_freeq)) == NULL &&
        !           236:            !ISSET(flags, SCSI_NOSLEEP))
        !           237:                tsleep(&scbus->sc_ccb_freeq, PRIBIO, "getccb", 0);
        !           238:        if (ccb != NULL) {
        !           239:                TAILQ_REMOVE(&scbus->sc_ccb_freeq, ccb, ccb_link);
        !           240:                ccb->ccb_state = SDMMC_CCB_READY;
        !           241:        }
        !           242:        splx(s);
        !           243:        return ccb;
        !           244: }
        !           245:
        !           246: void
        !           247: sdmmc_put_ccb(struct sdmmc_ccb *ccb)
        !           248: {
        !           249:        struct sdmmc_scsi_softc *scbus = ccb->ccb_scbus;
        !           250:        int s;
        !           251:
        !           252:        s = splbio();
        !           253:        if (ccb->ccb_state == SDMMC_CCB_QUEUED)
        !           254:                TAILQ_REMOVE(&scbus->sc_ccb_runq, ccb, ccb_link);
        !           255:        ccb->ccb_state = SDMMC_CCB_FREE;
        !           256:        ccb->ccb_flags = 0;
        !           257:        ccb->ccb_xs = NULL;
        !           258:        ccb->ccb_done = NULL;
        !           259:        TAILQ_INSERT_TAIL(&scbus->sc_ccb_freeq, ccb, ccb_link);
        !           260:        if (TAILQ_NEXT(ccb, ccb_link) == NULL)
        !           261:                wakeup(&scbus->sc_ccb_freeq);
        !           262:        splx(s);
        !           263: }
        !           264:
        !           265: /*
        !           266:  * SCSI command emulation
        !           267:  */
        !           268:
        !           269: /* XXX move to some sort of "scsi emulation layer". */
        !           270: static void
        !           271: sdmmc_scsi_decode_rw(struct scsi_xfer *xs, u_int32_t *blocknop,
        !           272:     u_int32_t *blockcntp)
        !           273: {
        !           274:        struct scsi_rw *rw;
        !           275:        struct scsi_rw_big *rwb;
        !           276:
        !           277:        if (xs->cmdlen == 6) {
        !           278:                rw = (struct scsi_rw *)xs->cmd;
        !           279:                *blocknop = _3btol(rw->addr) & (SRW_TOPADDR << 16 | 0xffff);
        !           280:                *blockcntp = rw->length ? rw->length : 0x100;
        !           281:        } else {
        !           282:                rwb = (struct scsi_rw_big *)xs->cmd;
        !           283:                *blocknop = _4btol(rwb->addr);
        !           284:                *blockcntp = _2btol(rwb->length);
        !           285:        }
        !           286: }
        !           287:
        !           288: int
        !           289: sdmmc_scsi_cmd(struct scsi_xfer *xs)
        !           290: {
        !           291:        struct scsi_link *link = xs->sc_link;
        !           292:        struct sdmmc_softc *sc = link->adapter_softc;
        !           293:        struct sdmmc_scsi_softc *scbus = sc->sc_scsibus;
        !           294:        struct sdmmc_scsi_target *tgt = &scbus->sc_tgt[link->target];
        !           295:        struct scsi_inquiry_data inq;
        !           296:        struct scsi_read_cap_data rcd;
        !           297:        u_int32_t blockno;
        !           298:        u_int32_t blockcnt;
        !           299:        struct sdmmc_ccb *ccb;
        !           300:        int s;
        !           301:
        !           302:        if (link->target >= scbus->sc_ntargets || tgt->card == NULL ||
        !           303:            link->lun != 0) {
        !           304:                DPRINTF(("%s: sdmmc_scsi_cmd: no target %d\n",
        !           305:                    DEVNAME(sc), link->target));
        !           306:                /* XXX should be XS_SENSE and sense filled out */
        !           307:                xs->error = XS_DRIVER_STUFFUP;
        !           308:                xs->flags |= ITSDONE;
        !           309:                s = splbio();
        !           310:                scsi_done(xs);
        !           311:                splx(s);
        !           312:                return COMPLETE;
        !           313:        }
        !           314:
        !           315:        DPRINTF(("%s: scsi cmd target=%d opcode=%#x proc=\"%s\" (poll=%#x)\n",
        !           316:            DEVNAME(sc), link->target, xs->cmd->opcode, curproc ?
        !           317:            curproc->p_comm : "", xs->flags & SCSI_POLL));
        !           318:
        !           319:        xs->error = XS_NOERROR;
        !           320:
        !           321:        switch (xs->cmd->opcode) {
        !           322:        case READ_COMMAND:
        !           323:        case READ_BIG:
        !           324:        case WRITE_COMMAND:
        !           325:        case WRITE_BIG:
        !           326:                /* Deal with I/O outside the switch. */
        !           327:                break;
        !           328:
        !           329:        case INQUIRY:
        !           330:                bzero(&inq, sizeof inq);
        !           331:                inq.device = T_DIRECT;
        !           332:                inq.version = 2;
        !           333:                inq.response_format = 2;
        !           334:                inq.additional_length = 32;
        !           335:                strlcpy(inq.vendor, "SD/MMC ", sizeof(inq.vendor));
        !           336:                snprintf(inq.product, sizeof(inq.product),
        !           337:                    "Drive #%02d", link->target);
        !           338:                strlcpy(inq.revision, "   ", sizeof(inq.revision));
        !           339:                bcopy(&inq, xs->data, MIN(xs->datalen, sizeof inq));
        !           340:                s = splbio();
        !           341:                scsi_done(xs);
        !           342:                splx(s);
        !           343:                return COMPLETE;
        !           344:
        !           345:        case TEST_UNIT_READY:
        !           346:        case START_STOP:
        !           347:        case SYNCHRONIZE_CACHE:
        !           348:                return COMPLETE;
        !           349:
        !           350:        case READ_CAPACITY:
        !           351:                bzero(&rcd, sizeof rcd);
        !           352:                _lto4b(tgt->card->csd.capacity - 1, rcd.addr);
        !           353:                _lto4b(tgt->card->csd.sector_size, rcd.length);
        !           354:                bcopy(&rcd, xs->data, MIN(xs->datalen, sizeof rcd));
        !           355:                s = splbio();
        !           356:                scsi_done(xs);
        !           357:                splx(s);
        !           358:                return COMPLETE;
        !           359:
        !           360:        default:
        !           361:                DPRINTF(("%s: unsupported scsi command %#x\n",
        !           362:                    DEVNAME(sc), xs->cmd->opcode));
        !           363:                xs->error = XS_DRIVER_STUFFUP;
        !           364:                s = splbio();
        !           365:                scsi_done(xs);
        !           366:                splx(s);
        !           367:                return COMPLETE;
        !           368:        }
        !           369:
        !           370:        /* A read or write operation. */
        !           371:        sdmmc_scsi_decode_rw(xs, &blockno, &blockcnt);
        !           372:
        !           373:        if (blockno >= tgt->card->csd.capacity ||
        !           374:            blockno + blockcnt > tgt->card->csd.capacity) {
        !           375:                DPRINTF(("%s: out of bounds %u-%u >= %u\n", DEVNAME(sc),
        !           376:                    blockno, blockcnt, tgt->card->csd.capacity));
        !           377:                xs->error = XS_DRIVER_STUFFUP;
        !           378:                s = splbio();
        !           379:                scsi_done(xs);
        !           380:                splx(s);
        !           381:                return COMPLETE;
        !           382:        }
        !           383:
        !           384:        ccb = sdmmc_get_ccb(sc->sc_scsibus, xs->flags);
        !           385:        if (ccb == NULL) {
        !           386:                printf("%s: out of ccbs\n", DEVNAME(sc));
        !           387:                xs->error = XS_DRIVER_STUFFUP;
        !           388:                s = splbio();
        !           389:                scsi_done(xs);
        !           390:                splx(s);
        !           391:                return COMPLETE;
        !           392:        }
        !           393:
        !           394:        ccb->ccb_xs = xs;
        !           395:        ccb->ccb_done = sdmmc_done_xs;
        !           396:
        !           397:        ccb->ccb_blockcnt = blockcnt;
        !           398:        ccb->ccb_blockno = blockno;
        !           399:
        !           400:        return sdmmc_start_xs(sc, ccb);
        !           401: }
        !           402:
        !           403: int
        !           404: sdmmc_start_xs(struct sdmmc_softc *sc, struct sdmmc_ccb *ccb)
        !           405: {
        !           406:        struct sdmmc_scsi_softc *scbus = sc->sc_scsibus;
        !           407:        struct scsi_xfer *xs = ccb->ccb_xs;
        !           408:        int s;
        !           409:
        !           410:        timeout_set(&xs->stimeout, sdmmc_stimeout, ccb);
        !           411:        sdmmc_init_task(&ccb->ccb_task, sdmmc_complete_xs, ccb);
        !           412:
        !           413:        s = splbio();
        !           414:        TAILQ_INSERT_TAIL(&scbus->sc_ccb_runq, ccb, ccb_link);
        !           415:        ccb->ccb_state = SDMMC_CCB_QUEUED;
        !           416:        splx(s);
        !           417:
        !           418:        if (ISSET(xs->flags, SCSI_POLL)) {
        !           419:                sdmmc_complete_xs(ccb);
        !           420:                return COMPLETE;
        !           421:        }
        !           422:
        !           423:        timeout_add(&xs->stimeout, (xs->timeout * hz) / 1000);
        !           424:        sdmmc_add_task(sc, &ccb->ccb_task);
        !           425:        return SUCCESSFULLY_QUEUED;
        !           426: }
        !           427:
        !           428: void
        !           429: sdmmc_complete_xs(void *arg)
        !           430: {
        !           431:        struct sdmmc_ccb *ccb = arg;
        !           432:        struct scsi_xfer *xs = ccb->ccb_xs;
        !           433:        struct scsi_link *link = xs->sc_link;
        !           434:        struct sdmmc_softc *sc = link->adapter_softc;
        !           435:        struct sdmmc_scsi_softc *scbus = sc->sc_scsibus;
        !           436:        struct sdmmc_scsi_target *tgt = &scbus->sc_tgt[link->target];
        !           437:        int error;
        !           438:        int s;
        !           439:
        !           440:        DPRINTF(("%s: scsi cmd target=%d opcode=%#x proc=\"%s\" (poll=%#x)"
        !           441:            " complete\n", DEVNAME(sc), link->target, xs->cmd->opcode,
        !           442:            curproc ? curproc->p_comm : "", xs->flags & SCSI_POLL));
        !           443:
        !           444:        s = splbio();
        !           445:
        !           446:        if (ISSET(xs->flags, SCSI_DATA_IN))
        !           447:                error = sdmmc_mem_read_block(tgt->card, ccb->ccb_blockno,
        !           448:                    xs->data, ccb->ccb_blockcnt * DEV_BSIZE);
        !           449:        else
        !           450:                error = sdmmc_mem_write_block(tgt->card, ccb->ccb_blockno,
        !           451:                    xs->data, ccb->ccb_blockcnt * DEV_BSIZE);
        !           452:
        !           453:        if (error != 0)
        !           454:                xs->error = XS_DRIVER_STUFFUP;
        !           455:
        !           456:        ccb->ccb_done(ccb);
        !           457:        splx(s);
        !           458: }
        !           459:
        !           460: void
        !           461: sdmmc_done_xs(struct sdmmc_ccb *ccb)
        !           462: {
        !           463:        struct scsi_xfer *xs = ccb->ccb_xs;
        !           464: #ifdef SDMMC_DEBUG
        !           465:        struct scsi_link *link = xs->sc_link;
        !           466:        struct sdmmc_softc *sc = link->adapter_softc;
        !           467: #endif
        !           468:
        !           469:        timeout_del(&xs->stimeout);
        !           470:
        !           471:        DPRINTF(("%s: scsi cmd target=%d opcode=%#x proc=\"%s\" (error=%#x)"
        !           472:            " done\n", DEVNAME(sc), link->target, xs->cmd->opcode,
        !           473:            curproc ? curproc->p_comm : "", xs->error));
        !           474:
        !           475:        xs->resid = 0;
        !           476:        xs->flags |= ITSDONE;
        !           477:
        !           478:        if (ISSET(ccb->ccb_flags, SDMMC_CCB_F_ERR))
        !           479:                xs->error = XS_DRIVER_STUFFUP;
        !           480:
        !           481:        sdmmc_put_ccb(ccb);
        !           482:        scsi_done(xs);
        !           483: }
        !           484:
        !           485: void
        !           486: sdmmc_stimeout(void *arg)
        !           487: {
        !           488:        struct sdmmc_ccb *ccb = arg;
        !           489:        int s;
        !           490:
        !           491:        s = splbio();
        !           492:        ccb->ccb_flags |= SDMMC_CCB_F_ERR;
        !           493:        if (sdmmc_task_pending(&ccb->ccb_task)) {
        !           494:                sdmmc_del_task(&ccb->ccb_task);
        !           495:                ccb->ccb_done(ccb);
        !           496:        }
        !           497:        splx(s);
        !           498: }
        !           499:
        !           500: void
        !           501: sdmmc_scsi_minphys(struct buf *bp)
        !           502: {
        !           503:        /* XXX limit to max. transfer size supported by card/host? */
        !           504:        if (bp->b_bcount > DEV_BSIZE)
        !           505:                bp->b_bcount = DEV_BSIZE;
        !           506:        minphys(bp);
        !           507: }

CVSweb