1*1b99d52fSWarner Losh /*- 2*1b99d52fSWarner Losh * Copyright (c) 2013 Ilya Bakulin. All rights reserved. 3*1b99d52fSWarner Losh * 4*1b99d52fSWarner Losh * Redistribution and use in source and binary forms, with or without 5*1b99d52fSWarner Losh * modification, are permitted provided that the following conditions 6*1b99d52fSWarner Losh * are met: 7*1b99d52fSWarner Losh * 1. Redistributions of source code must retain the above copyright 8*1b99d52fSWarner Losh * notice, this list of conditions and the following disclaimer. 9*1b99d52fSWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 10*1b99d52fSWarner Losh * notice, this list of conditions and the following disclaimer in the 11*1b99d52fSWarner Losh * documentation and/or other materials provided with the distribution. 12*1b99d52fSWarner Losh * 13*1b99d52fSWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14*1b99d52fSWarner Losh * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15*1b99d52fSWarner Losh * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16*1b99d52fSWarner Losh * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17*1b99d52fSWarner Losh * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18*1b99d52fSWarner Losh * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19*1b99d52fSWarner Losh * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20*1b99d52fSWarner Losh * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21*1b99d52fSWarner Losh * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22*1b99d52fSWarner Losh * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23*1b99d52fSWarner Losh * 24*1b99d52fSWarner Losh */ 25*1b99d52fSWarner Losh 26*1b99d52fSWarner Losh #include <sys/cdefs.h> 27*1b99d52fSWarner Losh __FBSDID("$FreeBSD$"); 28*1b99d52fSWarner Losh 29*1b99d52fSWarner Losh #include <sys/param.h> 30*1b99d52fSWarner Losh #include <sys/module.h> 31*1b99d52fSWarner Losh #include <sys/kernel.h> 32*1b99d52fSWarner Losh #include <sys/malloc.h> 33*1b99d52fSWarner Losh #include <sys/systm.h> 34*1b99d52fSWarner Losh #include <sys/lock.h> 35*1b99d52fSWarner Losh #include <sys/mutex.h> 36*1b99d52fSWarner Losh #include <sys/bus.h> 37*1b99d52fSWarner Losh #include <sys/endian.h> 38*1b99d52fSWarner Losh #include <sys/sysctl.h> 39*1b99d52fSWarner Losh 40*1b99d52fSWarner Losh #include <cam/cam.h> 41*1b99d52fSWarner Losh #include <cam/cam_ccb.h> 42*1b99d52fSWarner Losh #include <cam/cam_debug.h> 43*1b99d52fSWarner Losh #include <cam/cam_sim.h> 44*1b99d52fSWarner Losh #include <cam/cam_xpt_sim.h> 45*1b99d52fSWarner Losh #include <cam/scsi/scsi_all.h> 46*1b99d52fSWarner Losh 47*1b99d52fSWarner Losh static int is_sdio_mode = 1; 48*1b99d52fSWarner Losh 49*1b99d52fSWarner Losh struct mmcnull_softc { 50*1b99d52fSWarner Losh device_t dev; 51*1b99d52fSWarner Losh struct mtx sc_mtx; 52*1b99d52fSWarner Losh 53*1b99d52fSWarner Losh struct cam_devq *devq; 54*1b99d52fSWarner Losh struct cam_sim *sim; 55*1b99d52fSWarner Losh struct cam_path *path; 56*1b99d52fSWarner Losh 57*1b99d52fSWarner Losh struct callout tick; 58*1b99d52fSWarner Losh union ccb *cur_ccb; 59*1b99d52fSWarner Losh }; 60*1b99d52fSWarner Losh 61*1b99d52fSWarner Losh static void mmcnull_identify(driver_t *, device_t); 62*1b99d52fSWarner Losh static int mmcnull_probe(device_t); 63*1b99d52fSWarner Losh static int mmcnull_attach(device_t); 64*1b99d52fSWarner Losh static int mmcnull_detach(device_t); 65*1b99d52fSWarner Losh static void mmcnull_action_sd(struct cam_sim *, union ccb *); 66*1b99d52fSWarner Losh static void mmcnull_action_sdio(struct cam_sim *, union ccb *); 67*1b99d52fSWarner Losh static void mmcnull_intr_sd(void *xsc); 68*1b99d52fSWarner Losh static void mmcnull_intr_sdio(void *xsc); 69*1b99d52fSWarner Losh static void mmcnull_poll(struct cam_sim *); 70*1b99d52fSWarner Losh 71*1b99d52fSWarner Losh static void 72*1b99d52fSWarner Losh mmcnull_identify(driver_t *driver, device_t parent) 73*1b99d52fSWarner Losh { 74*1b99d52fSWarner Losh device_t child; 75*1b99d52fSWarner Losh 76*1b99d52fSWarner Losh if (resource_disabled("mmcnull", 0)) 77*1b99d52fSWarner Losh return; 78*1b99d52fSWarner Losh 79*1b99d52fSWarner Losh if (device_get_unit(parent) != 0) 80*1b99d52fSWarner Losh return; 81*1b99d52fSWarner Losh 82*1b99d52fSWarner Losh /* Avoid duplicates. */ 83*1b99d52fSWarner Losh if (device_find_child(parent, "mmcnull", -1)) 84*1b99d52fSWarner Losh return; 85*1b99d52fSWarner Losh 86*1b99d52fSWarner Losh child = BUS_ADD_CHILD(parent, 20, "mmcnull", 0); 87*1b99d52fSWarner Losh if (child == NULL) { 88*1b99d52fSWarner Losh device_printf(parent, "add MMCNULL child failed\n"); 89*1b99d52fSWarner Losh return; 90*1b99d52fSWarner Losh } 91*1b99d52fSWarner Losh } 92*1b99d52fSWarner Losh 93*1b99d52fSWarner Losh 94*1b99d52fSWarner Losh static int 95*1b99d52fSWarner Losh mmcnull_probe(device_t dev) 96*1b99d52fSWarner Losh { 97*1b99d52fSWarner Losh device_set_desc(dev, "Emulated MMC controller"); 98*1b99d52fSWarner Losh return (BUS_PROBE_DEFAULT); 99*1b99d52fSWarner Losh } 100*1b99d52fSWarner Losh 101*1b99d52fSWarner Losh static int 102*1b99d52fSWarner Losh mmcnull_attach(device_t dev) 103*1b99d52fSWarner Losh { 104*1b99d52fSWarner Losh struct mmcnull_softc *sc; 105*1b99d52fSWarner Losh sim_action_func action_func; 106*1b99d52fSWarner Losh 107*1b99d52fSWarner Losh sc = device_get_softc(dev); 108*1b99d52fSWarner Losh sc->dev = dev; 109*1b99d52fSWarner Losh 110*1b99d52fSWarner Losh mtx_init(&sc->sc_mtx, "mmcnullmtx", NULL, MTX_DEF); 111*1b99d52fSWarner Losh 112*1b99d52fSWarner Losh if ((sc->devq = cam_simq_alloc(1)) == NULL) 113*1b99d52fSWarner Losh return (ENOMEM); 114*1b99d52fSWarner Losh 115*1b99d52fSWarner Losh if (is_sdio_mode) 116*1b99d52fSWarner Losh action_func = mmcnull_action_sdio; 117*1b99d52fSWarner Losh else 118*1b99d52fSWarner Losh action_func = mmcnull_action_sd; 119*1b99d52fSWarner Losh sc->sim = cam_sim_alloc(action_func, mmcnull_poll, "mmcnull", sc, 120*1b99d52fSWarner Losh device_get_unit(dev), &sc->sc_mtx, 1, 1, 121*1b99d52fSWarner Losh sc->devq); 122*1b99d52fSWarner Losh 123*1b99d52fSWarner Losh if (sc->sim == NULL) { 124*1b99d52fSWarner Losh cam_simq_free(sc->devq); 125*1b99d52fSWarner Losh device_printf(dev, "cannot allocate CAM SIM\n"); 126*1b99d52fSWarner Losh return (EINVAL); 127*1b99d52fSWarner Losh } 128*1b99d52fSWarner Losh 129*1b99d52fSWarner Losh mtx_lock(&sc->sc_mtx); 130*1b99d52fSWarner Losh if (xpt_bus_register(sc->sim, dev, 0) != 0) { 131*1b99d52fSWarner Losh device_printf(dev, 132*1b99d52fSWarner Losh "cannot register SCSI pass-through bus\n"); 133*1b99d52fSWarner Losh cam_sim_free(sc->sim, FALSE); 134*1b99d52fSWarner Losh cam_simq_free(sc->devq); 135*1b99d52fSWarner Losh mtx_unlock(&sc->sc_mtx); 136*1b99d52fSWarner Losh return (EINVAL); 137*1b99d52fSWarner Losh } 138*1b99d52fSWarner Losh mtx_unlock(&sc->sc_mtx); 139*1b99d52fSWarner Losh 140*1b99d52fSWarner Losh callout_init_mtx(&sc->tick, &sc->sc_mtx, 0); /* Callout to emulate interrupts */ 141*1b99d52fSWarner Losh 142*1b99d52fSWarner Losh device_printf(dev, "attached OK\n"); 143*1b99d52fSWarner Losh 144*1b99d52fSWarner Losh return (0); 145*1b99d52fSWarner Losh } 146*1b99d52fSWarner Losh 147*1b99d52fSWarner Losh static int 148*1b99d52fSWarner Losh mmcnull_detach(device_t dev) 149*1b99d52fSWarner Losh { 150*1b99d52fSWarner Losh struct mmcnull_softc *sc; 151*1b99d52fSWarner Losh 152*1b99d52fSWarner Losh sc = device_get_softc(dev); 153*1b99d52fSWarner Losh 154*1b99d52fSWarner Losh if (sc == NULL) 155*1b99d52fSWarner Losh return (EINVAL); 156*1b99d52fSWarner Losh 157*1b99d52fSWarner Losh if (sc->sim != NULL) { 158*1b99d52fSWarner Losh mtx_lock(&sc->sc_mtx); 159*1b99d52fSWarner Losh xpt_bus_deregister(cam_sim_path(sc->sim)); 160*1b99d52fSWarner Losh cam_sim_free(sc->sim, FALSE); 161*1b99d52fSWarner Losh mtx_unlock(&sc->sc_mtx); 162*1b99d52fSWarner Losh } 163*1b99d52fSWarner Losh 164*1b99d52fSWarner Losh if (sc->devq != NULL) 165*1b99d52fSWarner Losh cam_simq_free(sc->devq); 166*1b99d52fSWarner Losh 167*1b99d52fSWarner Losh callout_drain(&sc->tick); 168*1b99d52fSWarner Losh mtx_destroy(&sc->sc_mtx); 169*1b99d52fSWarner Losh 170*1b99d52fSWarner Losh device_printf(dev, "detached OK\n"); 171*1b99d52fSWarner Losh return (0); 172*1b99d52fSWarner Losh } 173*1b99d52fSWarner Losh 174*1b99d52fSWarner Losh /* 175*1b99d52fSWarner Losh * The interrupt handler 176*1b99d52fSWarner Losh * This implementation calls it via callout(9) 177*1b99d52fSWarner Losh * with the mutex already taken 178*1b99d52fSWarner Losh */ 179*1b99d52fSWarner Losh static void 180*1b99d52fSWarner Losh mmcnull_intr_sd(void *xsc) { 181*1b99d52fSWarner Losh struct mmcnull_softc *sc; 182*1b99d52fSWarner Losh union ccb *ccb; 183*1b99d52fSWarner Losh struct ccb_mmcio *mmcio; 184*1b99d52fSWarner Losh 185*1b99d52fSWarner Losh sc = (struct mmcnull_softc *) xsc; 186*1b99d52fSWarner Losh mtx_assert(&sc->sc_mtx, MA_OWNED); 187*1b99d52fSWarner Losh 188*1b99d52fSWarner Losh ccb = sc->cur_ccb; 189*1b99d52fSWarner Losh mmcio = &ccb->mmcio; 190*1b99d52fSWarner Losh device_printf(sc->dev, "mmcnull_intr: MMC command = %d\n", 191*1b99d52fSWarner Losh mmcio->cmd.opcode); 192*1b99d52fSWarner Losh 193*1b99d52fSWarner Losh switch (mmcio->cmd.opcode) { 194*1b99d52fSWarner Losh case MMC_GO_IDLE_STATE: 195*1b99d52fSWarner Losh device_printf(sc->dev, "Reset device\n"); 196*1b99d52fSWarner Losh break; 197*1b99d52fSWarner Losh case SD_SEND_IF_COND: 198*1b99d52fSWarner Losh mmcio->cmd.resp[0] = 0x1AA; // To match mmc_xpt expectations :-) 199*1b99d52fSWarner Losh break; 200*1b99d52fSWarner Losh case MMC_APP_CMD: 201*1b99d52fSWarner Losh mmcio->cmd.resp[0] = R1_APP_CMD; 202*1b99d52fSWarner Losh break; 203*1b99d52fSWarner Losh case SD_SEND_RELATIVE_ADDR: 204*1b99d52fSWarner Losh case MMC_SELECT_CARD: 205*1b99d52fSWarner Losh mmcio->cmd.resp[0] = 0x1 << 16; 206*1b99d52fSWarner Losh break; 207*1b99d52fSWarner Losh case ACMD_SD_SEND_OP_COND: 208*1b99d52fSWarner Losh mmcio->cmd.resp[0] = 0xc0ff8000; 209*1b99d52fSWarner Losh mmcio->cmd.resp[0] |= MMC_OCR_CARD_BUSY; 210*1b99d52fSWarner Losh break; 211*1b99d52fSWarner Losh case MMC_ALL_SEND_CID: 212*1b99d52fSWarner Losh /* Note: this is a real CID from Wandboard int mmc */ 213*1b99d52fSWarner Losh mmcio->cmd.resp[0] = 0x1b534d30; 214*1b99d52fSWarner Losh mmcio->cmd.resp[1] = 0x30303030; 215*1b99d52fSWarner Losh mmcio->cmd.resp[2] = 0x10842806; 216*1b99d52fSWarner Losh mmcio->cmd.resp[3] = 0x5700e900; 217*1b99d52fSWarner Losh break; 218*1b99d52fSWarner Losh case MMC_SEND_CSD: 219*1b99d52fSWarner Losh /* Note: this is a real CSD from Wandboard int mmc */ 220*1b99d52fSWarner Losh mmcio->cmd.resp[0] = 0x400e0032; 221*1b99d52fSWarner Losh mmcio->cmd.resp[1] = 0x5b590000; 222*1b99d52fSWarner Losh mmcio->cmd.resp[2] = 0x751f7f80; 223*1b99d52fSWarner Losh mmcio->cmd.resp[3] = 0x0a404000; 224*1b99d52fSWarner Losh break; 225*1b99d52fSWarner Losh case MMC_READ_SINGLE_BLOCK: 226*1b99d52fSWarner Losh case MMC_READ_MULTIPLE_BLOCK: 227*1b99d52fSWarner Losh strcpy(mmcio->cmd.data->data, "WTF?!"); 228*1b99d52fSWarner Losh break; 229*1b99d52fSWarner Losh default: 230*1b99d52fSWarner Losh device_printf(sc->dev, "mmcnull_intr_sd: unknown command\n"); 231*1b99d52fSWarner Losh mmcio->cmd.error = 1; 232*1b99d52fSWarner Losh } 233*1b99d52fSWarner Losh ccb->ccb_h.status = CAM_REQ_CMP; 234*1b99d52fSWarner Losh 235*1b99d52fSWarner Losh sc->cur_ccb = NULL; 236*1b99d52fSWarner Losh xpt_done(ccb); 237*1b99d52fSWarner Losh } 238*1b99d52fSWarner Losh 239*1b99d52fSWarner Losh static void 240*1b99d52fSWarner Losh mmcnull_intr_sdio_newintr(void *xsc) { 241*1b99d52fSWarner Losh struct mmcnull_softc *sc; 242*1b99d52fSWarner Losh struct cam_path *dpath; 243*1b99d52fSWarner Losh 244*1b99d52fSWarner Losh sc = (struct mmcnull_softc *) xsc; 245*1b99d52fSWarner Losh mtx_assert(&sc->sc_mtx, MA_OWNED); 246*1b99d52fSWarner Losh device_printf(sc->dev, "mmcnull_intr_sdio_newintr()\n"); 247*1b99d52fSWarner Losh 248*1b99d52fSWarner Losh /* Our path */ 249*1b99d52fSWarner Losh if (xpt_create_path(&dpath, NULL, cam_sim_path(sc->sim), 0, 0) != CAM_REQ_CMP) { 250*1b99d52fSWarner Losh device_printf(sc->dev, "mmcnull_intr_sdio_newintr(): cannot create path\n"); 251*1b99d52fSWarner Losh return; 252*1b99d52fSWarner Losh } 253*1b99d52fSWarner Losh xpt_async(AC_UNIT_ATTENTION, dpath, NULL); 254*1b99d52fSWarner Losh xpt_free_path(dpath); 255*1b99d52fSWarner Losh } 256*1b99d52fSWarner Losh 257*1b99d52fSWarner Losh static void 258*1b99d52fSWarner Losh mmcnull_intr_sdio(void *xsc) { 259*1b99d52fSWarner Losh struct mmcnull_softc *sc; 260*1b99d52fSWarner Losh union ccb *ccb; 261*1b99d52fSWarner Losh struct ccb_mmcio *mmcio; 262*1b99d52fSWarner Losh 263*1b99d52fSWarner Losh sc = (struct mmcnull_softc *) xsc; 264*1b99d52fSWarner Losh mtx_assert(&sc->sc_mtx, MA_OWNED); 265*1b99d52fSWarner Losh 266*1b99d52fSWarner Losh ccb = sc->cur_ccb; 267*1b99d52fSWarner Losh mmcio = &ccb->mmcio; 268*1b99d52fSWarner Losh device_printf(sc->dev, "mmcnull_intr: MMC command = %d\n", 269*1b99d52fSWarner Losh mmcio->cmd.opcode); 270*1b99d52fSWarner Losh 271*1b99d52fSWarner Losh switch (mmcio->cmd.opcode) { 272*1b99d52fSWarner Losh case MMC_GO_IDLE_STATE: 273*1b99d52fSWarner Losh device_printf(sc->dev, "Reset device\n"); 274*1b99d52fSWarner Losh break; 275*1b99d52fSWarner Losh case SD_SEND_IF_COND: 276*1b99d52fSWarner Losh mmcio->cmd.resp[0] = 0x1AA; // To match mmc_xpt expectations :-) 277*1b99d52fSWarner Losh break; 278*1b99d52fSWarner Losh case MMC_APP_CMD: 279*1b99d52fSWarner Losh mmcio->cmd.resp[0] = R1_APP_CMD; 280*1b99d52fSWarner Losh break; 281*1b99d52fSWarner Losh case IO_SEND_OP_COND: 282*1b99d52fSWarner Losh mmcio->cmd.resp[0] = 0x12345678; 283*1b99d52fSWarner Losh mmcio->cmd.resp[0] |= ~ R4_IO_MEM_PRESENT; 284*1b99d52fSWarner Losh break; 285*1b99d52fSWarner Losh case SD_SEND_RELATIVE_ADDR: 286*1b99d52fSWarner Losh case MMC_SELECT_CARD: 287*1b99d52fSWarner Losh mmcio->cmd.resp[0] = 0x1 << 16; 288*1b99d52fSWarner Losh break; 289*1b99d52fSWarner Losh case ACMD_SD_SEND_OP_COND: 290*1b99d52fSWarner Losh /* TODO: steal valid OCR from somewhere :-) */ 291*1b99d52fSWarner Losh mmcio->cmd.resp[0] = 0x123; 292*1b99d52fSWarner Losh mmcio->cmd.resp[0] |= MMC_OCR_CARD_BUSY; 293*1b99d52fSWarner Losh break; 294*1b99d52fSWarner Losh case MMC_ALL_SEND_CID: 295*1b99d52fSWarner Losh mmcio->cmd.resp[0] = 0x1234; 296*1b99d52fSWarner Losh mmcio->cmd.resp[1] = 0x5678; 297*1b99d52fSWarner Losh mmcio->cmd.resp[2] = 0x9ABC; 298*1b99d52fSWarner Losh mmcio->cmd.resp[3] = 0xDEF0; 299*1b99d52fSWarner Losh break; 300*1b99d52fSWarner Losh case MMC_READ_SINGLE_BLOCK: 301*1b99d52fSWarner Losh case MMC_READ_MULTIPLE_BLOCK: 302*1b99d52fSWarner Losh strcpy(mmcio->cmd.data->data, "WTF?!"); 303*1b99d52fSWarner Losh break; 304*1b99d52fSWarner Losh case SD_IO_RW_DIRECT: 305*1b99d52fSWarner Losh device_printf(sc->dev, "Scheduling interrupt generation...\n"); 306*1b99d52fSWarner Losh callout_reset(&sc->tick, hz / 10, mmcnull_intr_sdio_newintr, sc); 307*1b99d52fSWarner Losh break; 308*1b99d52fSWarner Losh default: 309*1b99d52fSWarner Losh device_printf(sc->dev, "mmcnull_intr_sdio: unknown command\n"); 310*1b99d52fSWarner Losh } 311*1b99d52fSWarner Losh ccb->ccb_h.status = CAM_REQ_CMP; 312*1b99d52fSWarner Losh 313*1b99d52fSWarner Losh sc->cur_ccb = NULL; 314*1b99d52fSWarner Losh xpt_done(ccb); 315*1b99d52fSWarner Losh } 316*1b99d52fSWarner Losh 317*1b99d52fSWarner Losh /* 318*1b99d52fSWarner Losh * This is a MMC IO handler 319*1b99d52fSWarner Losh * It extracts MMC command from CCB and sends it 320*1b99d52fSWarner Losh * to the h/w 321*1b99d52fSWarner Losh */ 322*1b99d52fSWarner Losh static void 323*1b99d52fSWarner Losh mmcnull_handle_mmcio(struct cam_sim *sim, union ccb *ccb) 324*1b99d52fSWarner Losh { 325*1b99d52fSWarner Losh struct mmcnull_softc *sc; 326*1b99d52fSWarner Losh struct ccb_mmcio *mmcio; 327*1b99d52fSWarner Losh 328*1b99d52fSWarner Losh sc = cam_sim_softc(sim); 329*1b99d52fSWarner Losh mmcio = &ccb->mmcio; 330*1b99d52fSWarner Losh ccb->ccb_h.status = CAM_REQ_INPROG; 331*1b99d52fSWarner Losh sc->cur_ccb = ccb; 332*1b99d52fSWarner Losh 333*1b99d52fSWarner Losh /* Real h/w will wait for the interrupt */ 334*1b99d52fSWarner Losh if (is_sdio_mode) 335*1b99d52fSWarner Losh callout_reset(&sc->tick, hz / 10, mmcnull_intr_sdio, sc); 336*1b99d52fSWarner Losh else 337*1b99d52fSWarner Losh callout_reset(&sc->tick, hz / 10, mmcnull_intr_sd, sc); 338*1b99d52fSWarner Losh } 339*1b99d52fSWarner Losh 340*1b99d52fSWarner Losh static void 341*1b99d52fSWarner Losh mmcnull_action_sd(struct cam_sim *sim, union ccb *ccb) 342*1b99d52fSWarner Losh { 343*1b99d52fSWarner Losh struct mmcnull_softc *sc; 344*1b99d52fSWarner Losh 345*1b99d52fSWarner Losh sc = cam_sim_softc(sim); 346*1b99d52fSWarner Losh if (sc == NULL) { 347*1b99d52fSWarner Losh ccb->ccb_h.status = CAM_SEL_TIMEOUT; 348*1b99d52fSWarner Losh xpt_done(ccb); 349*1b99d52fSWarner Losh return; 350*1b99d52fSWarner Losh } 351*1b99d52fSWarner Losh 352*1b99d52fSWarner Losh mtx_assert(&sc->sc_mtx, MA_OWNED); 353*1b99d52fSWarner Losh 354*1b99d52fSWarner Losh device_printf(sc->dev, "action: func_code %0x\n", ccb->ccb_h.func_code); 355*1b99d52fSWarner Losh 356*1b99d52fSWarner Losh switch (ccb->ccb_h.func_code) { 357*1b99d52fSWarner Losh case XPT_PATH_INQ: 358*1b99d52fSWarner Losh { 359*1b99d52fSWarner Losh struct ccb_pathinq *cpi; 360*1b99d52fSWarner Losh 361*1b99d52fSWarner Losh cpi = &ccb->cpi; 362*1b99d52fSWarner Losh cpi->version_num = 1; 363*1b99d52fSWarner Losh cpi->hba_inquiry = PI_SDTR_ABLE | PI_TAG_ABLE | PI_WIDE_16; 364*1b99d52fSWarner Losh cpi->target_sprt = 0; 365*1b99d52fSWarner Losh cpi->hba_misc = PIM_NOBUSRESET | PIM_SEQSCAN; 366*1b99d52fSWarner Losh cpi->hba_eng_cnt = 0; 367*1b99d52fSWarner Losh cpi->max_target = 0; 368*1b99d52fSWarner Losh cpi->max_lun = 0; 369*1b99d52fSWarner Losh cpi->initiator_id = 1; 370*1b99d52fSWarner Losh strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 371*1b99d52fSWarner Losh strncpy(cpi->hba_vid, "FreeBSD Foundation", HBA_IDLEN); 372*1b99d52fSWarner Losh strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 373*1b99d52fSWarner Losh cpi->unit_number = cam_sim_unit(sim); 374*1b99d52fSWarner Losh cpi->bus_id = cam_sim_bus(sim); 375*1b99d52fSWarner Losh cpi->base_transfer_speed = 100; /* XXX WTF? */ 376*1b99d52fSWarner Losh cpi->protocol = PROTO_MMCSD; 377*1b99d52fSWarner Losh cpi->protocol_version = SCSI_REV_0; 378*1b99d52fSWarner Losh cpi->transport = XPORT_MMCSD; 379*1b99d52fSWarner Losh cpi->transport_version = 0; 380*1b99d52fSWarner Losh 381*1b99d52fSWarner Losh cpi->ccb_h.status = CAM_REQ_CMP; 382*1b99d52fSWarner Losh break; 383*1b99d52fSWarner Losh } 384*1b99d52fSWarner Losh case XPT_GET_TRAN_SETTINGS: 385*1b99d52fSWarner Losh { 386*1b99d52fSWarner Losh struct ccb_trans_settings *cts = &ccb->cts; 387*1b99d52fSWarner Losh struct ccb_trans_settings_mmc *mcts; 388*1b99d52fSWarner Losh mcts = &ccb->cts.proto_specific.mmc; 389*1b99d52fSWarner Losh 390*1b99d52fSWarner Losh device_printf(sc->dev, "Got XPT_GET_TRAN_SETTINGS\n"); 391*1b99d52fSWarner Losh 392*1b99d52fSWarner Losh cts->protocol = PROTO_MMCSD; 393*1b99d52fSWarner Losh cts->protocol_version = 0; 394*1b99d52fSWarner Losh cts->transport = XPORT_MMCSD; 395*1b99d52fSWarner Losh cts->transport_version = 0; 396*1b99d52fSWarner Losh cts->xport_specific.valid = 0; 397*1b99d52fSWarner Losh mcts->host_f_max = 12000000; 398*1b99d52fSWarner Losh mcts->host_f_min = 200000; 399*1b99d52fSWarner Losh mcts->host_ocr = 1; /* Fix this */ 400*1b99d52fSWarner Losh ccb->ccb_h.status = CAM_REQ_CMP; 401*1b99d52fSWarner Losh break; 402*1b99d52fSWarner Losh } 403*1b99d52fSWarner Losh case XPT_SET_TRAN_SETTINGS: 404*1b99d52fSWarner Losh device_printf(sc->dev, "Got XPT_SET_TRAN_SETTINGS, should update IOS...\n"); 405*1b99d52fSWarner Losh ccb->ccb_h.status = CAM_REQ_CMP; 406*1b99d52fSWarner Losh break; 407*1b99d52fSWarner Losh case XPT_RESET_BUS: 408*1b99d52fSWarner Losh device_printf(sc->dev, "Got XPT_RESET_BUS, ACK it...\n"); 409*1b99d52fSWarner Losh ccb->ccb_h.status = CAM_REQ_CMP; 410*1b99d52fSWarner Losh break; 411*1b99d52fSWarner Losh case XPT_MMC_IO: 412*1b99d52fSWarner Losh /* 413*1b99d52fSWarner Losh * Here is the HW-dependent part of 414*1b99d52fSWarner Losh * sending the command to the underlying h/w 415*1b99d52fSWarner Losh * At some point in the future an interrupt comes. 416*1b99d52fSWarner Losh * Then the request will be marked as completed. 417*1b99d52fSWarner Losh */ 418*1b99d52fSWarner Losh device_printf(sc->dev, "Got XPT_MMC_IO\n"); 419*1b99d52fSWarner Losh mmcnull_handle_mmcio(sim, ccb); 420*1b99d52fSWarner Losh return; 421*1b99d52fSWarner Losh break; 422*1b99d52fSWarner Losh case XPT_RESET_DEV: 423*1b99d52fSWarner Losh /* This is sent by `camcontrol reset`*/ 424*1b99d52fSWarner Losh device_printf(sc->dev, "Got XPT_RESET_DEV\n"); 425*1b99d52fSWarner Losh ccb->ccb_h.status = CAM_REQ_CMP; 426*1b99d52fSWarner Losh break; 427*1b99d52fSWarner Losh default: 428*1b99d52fSWarner Losh device_printf(sc->dev, "Func code %d is unknown\n", ccb->ccb_h.func_code); 429*1b99d52fSWarner Losh ccb->ccb_h.status = CAM_REQ_INVALID; 430*1b99d52fSWarner Losh break; 431*1b99d52fSWarner Losh } 432*1b99d52fSWarner Losh xpt_done(ccb); 433*1b99d52fSWarner Losh return; 434*1b99d52fSWarner Losh } 435*1b99d52fSWarner Losh 436*1b99d52fSWarner Losh static void 437*1b99d52fSWarner Losh mmcnull_action_sdio(struct cam_sim *sim, union ccb *ccb) { 438*1b99d52fSWarner Losh mmcnull_action_sd(sim, ccb); 439*1b99d52fSWarner Losh } 440*1b99d52fSWarner Losh 441*1b99d52fSWarner Losh static void 442*1b99d52fSWarner Losh mmcnull_poll(struct cam_sim *sim) 443*1b99d52fSWarner Losh { 444*1b99d52fSWarner Losh return; 445*1b99d52fSWarner Losh } 446*1b99d52fSWarner Losh 447*1b99d52fSWarner Losh 448*1b99d52fSWarner Losh static device_method_t mmcnull_methods[] = { 449*1b99d52fSWarner Losh /* Device interface */ 450*1b99d52fSWarner Losh DEVMETHOD(device_identify, mmcnull_identify), 451*1b99d52fSWarner Losh DEVMETHOD(device_probe, mmcnull_probe), 452*1b99d52fSWarner Losh DEVMETHOD(device_attach, mmcnull_attach), 453*1b99d52fSWarner Losh DEVMETHOD(device_detach, mmcnull_detach), 454*1b99d52fSWarner Losh DEVMETHOD_END 455*1b99d52fSWarner Losh }; 456*1b99d52fSWarner Losh 457*1b99d52fSWarner Losh static driver_t mmcnull_driver = { 458*1b99d52fSWarner Losh "mmcnull", mmcnull_methods, sizeof(struct mmcnull_softc) 459*1b99d52fSWarner Losh }; 460*1b99d52fSWarner Losh 461*1b99d52fSWarner Losh static devclass_t mmcnull_devclass; 462*1b99d52fSWarner Losh 463*1b99d52fSWarner Losh DRIVER_MODULE(mmcnull, isa, mmcnull_driver, mmcnull_devclass, 0, 0); 464