[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

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