root/dev/sdmmc/sdmmc_scsi.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sdmmc_scsi_attach
  2. sdmmc_scsi_detach
  3. sdmmc_alloc_ccbs
  4. sdmmc_free_ccbs
  5. sdmmc_get_ccb
  6. sdmmc_put_ccb
  7. sdmmc_scsi_decode_rw
  8. sdmmc_scsi_cmd
  9. sdmmc_start_xs
  10. sdmmc_complete_xs
  11. sdmmc_done_xs
  12. sdmmc_stimeout
  13. sdmmc_scsi_minphys

    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 }

/* [<][>][^][v][top][bottom][index][help] */