11b99d52fSWarner Losh /*- 21b99d52fSWarner Losh * Copyright (c) 2013 Ilya Bakulin. All rights reserved. 31b99d52fSWarner Losh * 41b99d52fSWarner Losh * Redistribution and use in source and binary forms, with or without 51b99d52fSWarner Losh * modification, are permitted provided that the following conditions 61b99d52fSWarner Losh * are met: 71b99d52fSWarner Losh * 1. Redistributions of source code must retain the above copyright 81b99d52fSWarner Losh * notice, this list of conditions and the following disclaimer. 91b99d52fSWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 101b99d52fSWarner Losh * notice, this list of conditions and the following disclaimer in the 111b99d52fSWarner Losh * documentation and/or other materials provided with the distribution. 121b99d52fSWarner Losh * 131b99d52fSWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 141b99d52fSWarner Losh * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 151b99d52fSWarner Losh * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 161b99d52fSWarner Losh * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 171b99d52fSWarner Losh * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 181b99d52fSWarner Losh * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 191b99d52fSWarner Losh * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 201b99d52fSWarner Losh * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 211b99d52fSWarner Losh * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 221b99d52fSWarner Losh * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 231b99d52fSWarner Losh * 241b99d52fSWarner Losh */ 251b99d52fSWarner Losh 261b99d52fSWarner Losh #include <sys/cdefs.h> 271b99d52fSWarner Losh __FBSDID("$FreeBSD$"); 281b99d52fSWarner Losh 291b99d52fSWarner Losh #include <sys/param.h> 301b99d52fSWarner Losh #include <sys/module.h> 311b99d52fSWarner Losh #include <sys/kernel.h> 321b99d52fSWarner Losh #include <sys/malloc.h> 331b99d52fSWarner Losh #include <sys/systm.h> 341b99d52fSWarner Losh #include <sys/lock.h> 351b99d52fSWarner Losh #include <sys/mutex.h> 361b99d52fSWarner Losh #include <sys/bus.h> 371b99d52fSWarner Losh #include <sys/endian.h> 381b99d52fSWarner Losh #include <sys/sysctl.h> 391b99d52fSWarner Losh 401b99d52fSWarner Losh #include <cam/cam.h> 411b99d52fSWarner Losh #include <cam/cam_ccb.h> 421b99d52fSWarner Losh #include <cam/cam_debug.h> 431b99d52fSWarner Losh #include <cam/cam_sim.h> 441b99d52fSWarner Losh #include <cam/cam_xpt_sim.h> 451b99d52fSWarner Losh #include <cam/scsi/scsi_all.h> 461b99d52fSWarner Losh 471b99d52fSWarner Losh static int is_sdio_mode = 1; 481b99d52fSWarner Losh 491b99d52fSWarner Losh struct mmcnull_softc { 501b99d52fSWarner Losh device_t dev; 511b99d52fSWarner Losh struct mtx sc_mtx; 521b99d52fSWarner Losh 531b99d52fSWarner Losh struct cam_devq *devq; 541b99d52fSWarner Losh struct cam_sim *sim; 551b99d52fSWarner Losh struct cam_path *path; 561b99d52fSWarner Losh 571b99d52fSWarner Losh struct callout tick; 581b99d52fSWarner Losh union ccb *cur_ccb; 591b99d52fSWarner Losh }; 601b99d52fSWarner Losh 611b99d52fSWarner Losh static void mmcnull_identify(driver_t *, device_t); 621b99d52fSWarner Losh static int mmcnull_probe(device_t); 631b99d52fSWarner Losh static int mmcnull_attach(device_t); 641b99d52fSWarner Losh static int mmcnull_detach(device_t); 651b99d52fSWarner Losh static void mmcnull_action_sd(struct cam_sim *, union ccb *); 661b99d52fSWarner Losh static void mmcnull_action_sdio(struct cam_sim *, union ccb *); 671b99d52fSWarner Losh static void mmcnull_intr_sd(void *xsc); 681b99d52fSWarner Losh static void mmcnull_intr_sdio(void *xsc); 691b99d52fSWarner Losh static void mmcnull_poll(struct cam_sim *); 701b99d52fSWarner Losh 711b99d52fSWarner Losh static void 721b99d52fSWarner Losh mmcnull_identify(driver_t *driver, device_t parent) 731b99d52fSWarner Losh { 741b99d52fSWarner Losh device_t child; 751b99d52fSWarner Losh 761b99d52fSWarner Losh if (resource_disabled("mmcnull", 0)) 771b99d52fSWarner Losh return; 781b99d52fSWarner Losh 791b99d52fSWarner Losh if (device_get_unit(parent) != 0) 801b99d52fSWarner Losh return; 811b99d52fSWarner Losh 821b99d52fSWarner Losh /* Avoid duplicates. */ 831b99d52fSWarner Losh if (device_find_child(parent, "mmcnull", -1)) 841b99d52fSWarner Losh return; 851b99d52fSWarner Losh 861b99d52fSWarner Losh child = BUS_ADD_CHILD(parent, 20, "mmcnull", 0); 871b99d52fSWarner Losh if (child == NULL) { 881b99d52fSWarner Losh device_printf(parent, "add MMCNULL child failed\n"); 891b99d52fSWarner Losh return; 901b99d52fSWarner Losh } 911b99d52fSWarner Losh } 921b99d52fSWarner Losh 931b99d52fSWarner Losh 941b99d52fSWarner Losh static int 951b99d52fSWarner Losh mmcnull_probe(device_t dev) 961b99d52fSWarner Losh { 971b99d52fSWarner Losh device_set_desc(dev, "Emulated MMC controller"); 981b99d52fSWarner Losh return (BUS_PROBE_DEFAULT); 991b99d52fSWarner Losh } 1001b99d52fSWarner Losh 1011b99d52fSWarner Losh static int 1021b99d52fSWarner Losh mmcnull_attach(device_t dev) 1031b99d52fSWarner Losh { 1041b99d52fSWarner Losh struct mmcnull_softc *sc; 1051b99d52fSWarner Losh sim_action_func action_func; 1061b99d52fSWarner Losh 1071b99d52fSWarner Losh sc = device_get_softc(dev); 1081b99d52fSWarner Losh sc->dev = dev; 1091b99d52fSWarner Losh 1101b99d52fSWarner Losh mtx_init(&sc->sc_mtx, "mmcnullmtx", NULL, MTX_DEF); 1111b99d52fSWarner Losh 1121b99d52fSWarner Losh if ((sc->devq = cam_simq_alloc(1)) == NULL) 1131b99d52fSWarner Losh return (ENOMEM); 1141b99d52fSWarner Losh 1151b99d52fSWarner Losh if (is_sdio_mode) 1161b99d52fSWarner Losh action_func = mmcnull_action_sdio; 1171b99d52fSWarner Losh else 1181b99d52fSWarner Losh action_func = mmcnull_action_sd; 1191b99d52fSWarner Losh sc->sim = cam_sim_alloc(action_func, mmcnull_poll, "mmcnull", sc, 1201b99d52fSWarner Losh device_get_unit(dev), &sc->sc_mtx, 1, 1, 1211b99d52fSWarner Losh sc->devq); 1221b99d52fSWarner Losh 1231b99d52fSWarner Losh if (sc->sim == NULL) { 1241b99d52fSWarner Losh cam_simq_free(sc->devq); 1251b99d52fSWarner Losh device_printf(dev, "cannot allocate CAM SIM\n"); 1261b99d52fSWarner Losh return (EINVAL); 1271b99d52fSWarner Losh } 1281b99d52fSWarner Losh 1291b99d52fSWarner Losh mtx_lock(&sc->sc_mtx); 1301b99d52fSWarner Losh if (xpt_bus_register(sc->sim, dev, 0) != 0) { 1311b99d52fSWarner Losh device_printf(dev, 1321b99d52fSWarner Losh "cannot register SCSI pass-through bus\n"); 1331b99d52fSWarner Losh cam_sim_free(sc->sim, FALSE); 1341b99d52fSWarner Losh cam_simq_free(sc->devq); 1351b99d52fSWarner Losh mtx_unlock(&sc->sc_mtx); 1361b99d52fSWarner Losh return (EINVAL); 1371b99d52fSWarner Losh } 1381b99d52fSWarner Losh mtx_unlock(&sc->sc_mtx); 1391b99d52fSWarner Losh 1401b99d52fSWarner Losh callout_init_mtx(&sc->tick, &sc->sc_mtx, 0); /* Callout to emulate interrupts */ 1411b99d52fSWarner Losh 1421b99d52fSWarner Losh device_printf(dev, "attached OK\n"); 1431b99d52fSWarner Losh 1441b99d52fSWarner Losh return (0); 1451b99d52fSWarner Losh } 1461b99d52fSWarner Losh 1471b99d52fSWarner Losh static int 1481b99d52fSWarner Losh mmcnull_detach(device_t dev) 1491b99d52fSWarner Losh { 1501b99d52fSWarner Losh struct mmcnull_softc *sc; 1511b99d52fSWarner Losh 1521b99d52fSWarner Losh sc = device_get_softc(dev); 1531b99d52fSWarner Losh 1541b99d52fSWarner Losh if (sc == NULL) 1551b99d52fSWarner Losh return (EINVAL); 1561b99d52fSWarner Losh 1571b99d52fSWarner Losh if (sc->sim != NULL) { 1581b99d52fSWarner Losh mtx_lock(&sc->sc_mtx); 1591b99d52fSWarner Losh xpt_bus_deregister(cam_sim_path(sc->sim)); 1601b99d52fSWarner Losh cam_sim_free(sc->sim, FALSE); 1611b99d52fSWarner Losh mtx_unlock(&sc->sc_mtx); 1621b99d52fSWarner Losh } 1631b99d52fSWarner Losh 1641b99d52fSWarner Losh if (sc->devq != NULL) 1651b99d52fSWarner Losh cam_simq_free(sc->devq); 1661b99d52fSWarner Losh 1671b99d52fSWarner Losh callout_drain(&sc->tick); 1681b99d52fSWarner Losh mtx_destroy(&sc->sc_mtx); 1691b99d52fSWarner Losh 1701b99d52fSWarner Losh device_printf(dev, "detached OK\n"); 1711b99d52fSWarner Losh return (0); 1721b99d52fSWarner Losh } 1731b99d52fSWarner Losh 1741b99d52fSWarner Losh /* 1751b99d52fSWarner Losh * The interrupt handler 1761b99d52fSWarner Losh * This implementation calls it via callout(9) 1771b99d52fSWarner Losh * with the mutex already taken 1781b99d52fSWarner Losh */ 1791b99d52fSWarner Losh static void 1801b99d52fSWarner Losh mmcnull_intr_sd(void *xsc) { 1811b99d52fSWarner Losh struct mmcnull_softc *sc; 1821b99d52fSWarner Losh union ccb *ccb; 1831b99d52fSWarner Losh struct ccb_mmcio *mmcio; 1841b99d52fSWarner Losh 1851b99d52fSWarner Losh sc = (struct mmcnull_softc *) xsc; 1861b99d52fSWarner Losh mtx_assert(&sc->sc_mtx, MA_OWNED); 1871b99d52fSWarner Losh 1881b99d52fSWarner Losh ccb = sc->cur_ccb; 1891b99d52fSWarner Losh mmcio = &ccb->mmcio; 1901b99d52fSWarner Losh device_printf(sc->dev, "mmcnull_intr: MMC command = %d\n", 1911b99d52fSWarner Losh mmcio->cmd.opcode); 1921b99d52fSWarner Losh 1931b99d52fSWarner Losh switch (mmcio->cmd.opcode) { 1941b99d52fSWarner Losh case MMC_GO_IDLE_STATE: 1951b99d52fSWarner Losh device_printf(sc->dev, "Reset device\n"); 1961b99d52fSWarner Losh break; 1971b99d52fSWarner Losh case SD_SEND_IF_COND: 1981b99d52fSWarner Losh mmcio->cmd.resp[0] = 0x1AA; // To match mmc_xpt expectations :-) 1991b99d52fSWarner Losh break; 2001b99d52fSWarner Losh case MMC_APP_CMD: 2011b99d52fSWarner Losh mmcio->cmd.resp[0] = R1_APP_CMD; 2021b99d52fSWarner Losh break; 2031b99d52fSWarner Losh case SD_SEND_RELATIVE_ADDR: 2041b99d52fSWarner Losh case MMC_SELECT_CARD: 2051b99d52fSWarner Losh mmcio->cmd.resp[0] = 0x1 << 16; 2061b99d52fSWarner Losh break; 2071b99d52fSWarner Losh case ACMD_SD_SEND_OP_COND: 2081b99d52fSWarner Losh mmcio->cmd.resp[0] = 0xc0ff8000; 2091b99d52fSWarner Losh mmcio->cmd.resp[0] |= MMC_OCR_CARD_BUSY; 2101b99d52fSWarner Losh break; 2111b99d52fSWarner Losh case MMC_ALL_SEND_CID: 2121b99d52fSWarner Losh /* Note: this is a real CID from Wandboard int mmc */ 2131b99d52fSWarner Losh mmcio->cmd.resp[0] = 0x1b534d30; 2141b99d52fSWarner Losh mmcio->cmd.resp[1] = 0x30303030; 2151b99d52fSWarner Losh mmcio->cmd.resp[2] = 0x10842806; 2161b99d52fSWarner Losh mmcio->cmd.resp[3] = 0x5700e900; 2171b99d52fSWarner Losh break; 2181b99d52fSWarner Losh case MMC_SEND_CSD: 2191b99d52fSWarner Losh /* Note: this is a real CSD from Wandboard int mmc */ 2201b99d52fSWarner Losh mmcio->cmd.resp[0] = 0x400e0032; 2211b99d52fSWarner Losh mmcio->cmd.resp[1] = 0x5b590000; 2221b99d52fSWarner Losh mmcio->cmd.resp[2] = 0x751f7f80; 2231b99d52fSWarner Losh mmcio->cmd.resp[3] = 0x0a404000; 2241b99d52fSWarner Losh break; 2251b99d52fSWarner Losh case MMC_READ_SINGLE_BLOCK: 2261b99d52fSWarner Losh case MMC_READ_MULTIPLE_BLOCK: 2271b99d52fSWarner Losh strcpy(mmcio->cmd.data->data, "WTF?!"); 2281b99d52fSWarner Losh break; 2291b99d52fSWarner Losh default: 2301b99d52fSWarner Losh device_printf(sc->dev, "mmcnull_intr_sd: unknown command\n"); 2311b99d52fSWarner Losh mmcio->cmd.error = 1; 2321b99d52fSWarner Losh } 2331b99d52fSWarner Losh ccb->ccb_h.status = CAM_REQ_CMP; 2341b99d52fSWarner Losh 2351b99d52fSWarner Losh sc->cur_ccb = NULL; 2361b99d52fSWarner Losh xpt_done(ccb); 2371b99d52fSWarner Losh } 2381b99d52fSWarner Losh 2391b99d52fSWarner Losh static void 2401b99d52fSWarner Losh mmcnull_intr_sdio_newintr(void *xsc) { 2411b99d52fSWarner Losh struct mmcnull_softc *sc; 2421b99d52fSWarner Losh struct cam_path *dpath; 2431b99d52fSWarner Losh 2441b99d52fSWarner Losh sc = (struct mmcnull_softc *) xsc; 2451b99d52fSWarner Losh mtx_assert(&sc->sc_mtx, MA_OWNED); 2461b99d52fSWarner Losh device_printf(sc->dev, "mmcnull_intr_sdio_newintr()\n"); 2471b99d52fSWarner Losh 2481b99d52fSWarner Losh /* Our path */ 2491b99d52fSWarner Losh if (xpt_create_path(&dpath, NULL, cam_sim_path(sc->sim), 0, 0) != CAM_REQ_CMP) { 2501b99d52fSWarner Losh device_printf(sc->dev, "mmcnull_intr_sdio_newintr(): cannot create path\n"); 2511b99d52fSWarner Losh return; 2521b99d52fSWarner Losh } 2531b99d52fSWarner Losh xpt_async(AC_UNIT_ATTENTION, dpath, NULL); 2541b99d52fSWarner Losh xpt_free_path(dpath); 2551b99d52fSWarner Losh } 2561b99d52fSWarner Losh 2571b99d52fSWarner Losh static void 2581b99d52fSWarner Losh mmcnull_intr_sdio(void *xsc) { 2591b99d52fSWarner Losh struct mmcnull_softc *sc; 2601b99d52fSWarner Losh union ccb *ccb; 2611b99d52fSWarner Losh struct ccb_mmcio *mmcio; 2621b99d52fSWarner Losh 2631b99d52fSWarner Losh sc = (struct mmcnull_softc *) xsc; 2641b99d52fSWarner Losh mtx_assert(&sc->sc_mtx, MA_OWNED); 2651b99d52fSWarner Losh 2661b99d52fSWarner Losh ccb = sc->cur_ccb; 2671b99d52fSWarner Losh mmcio = &ccb->mmcio; 2681b99d52fSWarner Losh device_printf(sc->dev, "mmcnull_intr: MMC command = %d\n", 2691b99d52fSWarner Losh mmcio->cmd.opcode); 2701b99d52fSWarner Losh 2711b99d52fSWarner Losh switch (mmcio->cmd.opcode) { 2721b99d52fSWarner Losh case MMC_GO_IDLE_STATE: 2731b99d52fSWarner Losh device_printf(sc->dev, "Reset device\n"); 2741b99d52fSWarner Losh break; 2751b99d52fSWarner Losh case SD_SEND_IF_COND: 2761b99d52fSWarner Losh mmcio->cmd.resp[0] = 0x1AA; // To match mmc_xpt expectations :-) 2771b99d52fSWarner Losh break; 2781b99d52fSWarner Losh case MMC_APP_CMD: 2791b99d52fSWarner Losh mmcio->cmd.resp[0] = R1_APP_CMD; 2801b99d52fSWarner Losh break; 2811b99d52fSWarner Losh case IO_SEND_OP_COND: 2821b99d52fSWarner Losh mmcio->cmd.resp[0] = 0x12345678; 2831b99d52fSWarner Losh mmcio->cmd.resp[0] |= ~ R4_IO_MEM_PRESENT; 2841b99d52fSWarner Losh break; 2851b99d52fSWarner Losh case SD_SEND_RELATIVE_ADDR: 2861b99d52fSWarner Losh case MMC_SELECT_CARD: 2871b99d52fSWarner Losh mmcio->cmd.resp[0] = 0x1 << 16; 2881b99d52fSWarner Losh break; 2891b99d52fSWarner Losh case ACMD_SD_SEND_OP_COND: 2901b99d52fSWarner Losh /* TODO: steal valid OCR from somewhere :-) */ 2911b99d52fSWarner Losh mmcio->cmd.resp[0] = 0x123; 2921b99d52fSWarner Losh mmcio->cmd.resp[0] |= MMC_OCR_CARD_BUSY; 2931b99d52fSWarner Losh break; 2941b99d52fSWarner Losh case MMC_ALL_SEND_CID: 2951b99d52fSWarner Losh mmcio->cmd.resp[0] = 0x1234; 2961b99d52fSWarner Losh mmcio->cmd.resp[1] = 0x5678; 2971b99d52fSWarner Losh mmcio->cmd.resp[2] = 0x9ABC; 2981b99d52fSWarner Losh mmcio->cmd.resp[3] = 0xDEF0; 2991b99d52fSWarner Losh break; 3001b99d52fSWarner Losh case MMC_READ_SINGLE_BLOCK: 3011b99d52fSWarner Losh case MMC_READ_MULTIPLE_BLOCK: 3021b99d52fSWarner Losh strcpy(mmcio->cmd.data->data, "WTF?!"); 3031b99d52fSWarner Losh break; 3041b99d52fSWarner Losh case SD_IO_RW_DIRECT: 3051b99d52fSWarner Losh device_printf(sc->dev, "Scheduling interrupt generation...\n"); 3061b99d52fSWarner Losh callout_reset(&sc->tick, hz / 10, mmcnull_intr_sdio_newintr, sc); 3071b99d52fSWarner Losh break; 3081b99d52fSWarner Losh default: 3091b99d52fSWarner Losh device_printf(sc->dev, "mmcnull_intr_sdio: unknown command\n"); 3101b99d52fSWarner Losh } 3111b99d52fSWarner Losh ccb->ccb_h.status = CAM_REQ_CMP; 3121b99d52fSWarner Losh 3131b99d52fSWarner Losh sc->cur_ccb = NULL; 3141b99d52fSWarner Losh xpt_done(ccb); 3151b99d52fSWarner Losh } 3161b99d52fSWarner Losh 3171b99d52fSWarner Losh /* 3181b99d52fSWarner Losh * This is a MMC IO handler 3191b99d52fSWarner Losh * It extracts MMC command from CCB and sends it 3201b99d52fSWarner Losh * to the h/w 3211b99d52fSWarner Losh */ 3221b99d52fSWarner Losh static void 3231b99d52fSWarner Losh mmcnull_handle_mmcio(struct cam_sim *sim, union ccb *ccb) 3241b99d52fSWarner Losh { 3251b99d52fSWarner Losh struct mmcnull_softc *sc; 3261b99d52fSWarner Losh struct ccb_mmcio *mmcio; 3271b99d52fSWarner Losh 3281b99d52fSWarner Losh sc = cam_sim_softc(sim); 3291b99d52fSWarner Losh mmcio = &ccb->mmcio; 3301b99d52fSWarner Losh ccb->ccb_h.status = CAM_REQ_INPROG; 3311b99d52fSWarner Losh sc->cur_ccb = ccb; 3321b99d52fSWarner Losh 3331b99d52fSWarner Losh /* Real h/w will wait for the interrupt */ 3341b99d52fSWarner Losh if (is_sdio_mode) 3351b99d52fSWarner Losh callout_reset(&sc->tick, hz / 10, mmcnull_intr_sdio, sc); 3361b99d52fSWarner Losh else 3371b99d52fSWarner Losh callout_reset(&sc->tick, hz / 10, mmcnull_intr_sd, sc); 3381b99d52fSWarner Losh } 3391b99d52fSWarner Losh 3401b99d52fSWarner Losh static void 3411b99d52fSWarner Losh mmcnull_action_sd(struct cam_sim *sim, union ccb *ccb) 3421b99d52fSWarner Losh { 3431b99d52fSWarner Losh struct mmcnull_softc *sc; 3441b99d52fSWarner Losh 3451b99d52fSWarner Losh sc = cam_sim_softc(sim); 3461b99d52fSWarner Losh if (sc == NULL) { 3471b99d52fSWarner Losh ccb->ccb_h.status = CAM_SEL_TIMEOUT; 3481b99d52fSWarner Losh xpt_done(ccb); 3491b99d52fSWarner Losh return; 3501b99d52fSWarner Losh } 3511b99d52fSWarner Losh 3521b99d52fSWarner Losh mtx_assert(&sc->sc_mtx, MA_OWNED); 3531b99d52fSWarner Losh 3541b99d52fSWarner Losh device_printf(sc->dev, "action: func_code %0x\n", ccb->ccb_h.func_code); 3551b99d52fSWarner Losh 3561b99d52fSWarner Losh switch (ccb->ccb_h.func_code) { 3571b99d52fSWarner Losh case XPT_PATH_INQ: 3581b99d52fSWarner Losh { 3591b99d52fSWarner Losh struct ccb_pathinq *cpi; 3601b99d52fSWarner Losh 3611b99d52fSWarner Losh cpi = &ccb->cpi; 3621b99d52fSWarner Losh cpi->version_num = 1; 3631b99d52fSWarner Losh cpi->hba_inquiry = PI_SDTR_ABLE | PI_TAG_ABLE | PI_WIDE_16; 3641b99d52fSWarner Losh cpi->target_sprt = 0; 3651b99d52fSWarner Losh cpi->hba_misc = PIM_NOBUSRESET | PIM_SEQSCAN; 3661b99d52fSWarner Losh cpi->hba_eng_cnt = 0; 3671b99d52fSWarner Losh cpi->max_target = 0; 3681b99d52fSWarner Losh cpi->max_lun = 0; 3691b99d52fSWarner Losh cpi->initiator_id = 1; 3701b99d52fSWarner Losh strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 3711b99d52fSWarner Losh strncpy(cpi->hba_vid, "FreeBSD Foundation", HBA_IDLEN); 3721b99d52fSWarner Losh strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 3731b99d52fSWarner Losh cpi->unit_number = cam_sim_unit(sim); 3741b99d52fSWarner Losh cpi->bus_id = cam_sim_bus(sim); 3751b99d52fSWarner Losh cpi->base_transfer_speed = 100; /* XXX WTF? */ 3761b99d52fSWarner Losh cpi->protocol = PROTO_MMCSD; 3771b99d52fSWarner Losh cpi->protocol_version = SCSI_REV_0; 3781b99d52fSWarner Losh cpi->transport = XPORT_MMCSD; 3791b99d52fSWarner Losh cpi->transport_version = 0; 3801b99d52fSWarner Losh 3811b99d52fSWarner Losh cpi->ccb_h.status = CAM_REQ_CMP; 3821b99d52fSWarner Losh break; 3831b99d52fSWarner Losh } 3841b99d52fSWarner Losh case XPT_GET_TRAN_SETTINGS: 3851b99d52fSWarner Losh { 3861b99d52fSWarner Losh struct ccb_trans_settings *cts = &ccb->cts; 3871b99d52fSWarner Losh struct ccb_trans_settings_mmc *mcts; 3881b99d52fSWarner Losh mcts = &ccb->cts.proto_specific.mmc; 3891b99d52fSWarner Losh 3901b99d52fSWarner Losh device_printf(sc->dev, "Got XPT_GET_TRAN_SETTINGS\n"); 3911b99d52fSWarner Losh 3921b99d52fSWarner Losh cts->protocol = PROTO_MMCSD; 3931b99d52fSWarner Losh cts->protocol_version = 0; 3941b99d52fSWarner Losh cts->transport = XPORT_MMCSD; 3951b99d52fSWarner Losh cts->transport_version = 0; 3961b99d52fSWarner Losh cts->xport_specific.valid = 0; 3971b99d52fSWarner Losh mcts->host_f_max = 12000000; 3981b99d52fSWarner Losh mcts->host_f_min = 200000; 3991b99d52fSWarner Losh mcts->host_ocr = 1; /* Fix this */ 4001b99d52fSWarner Losh ccb->ccb_h.status = CAM_REQ_CMP; 4011b99d52fSWarner Losh break; 4021b99d52fSWarner Losh } 4031b99d52fSWarner Losh case XPT_SET_TRAN_SETTINGS: 4041b99d52fSWarner Losh device_printf(sc->dev, "Got XPT_SET_TRAN_SETTINGS, should update IOS...\n"); 4051b99d52fSWarner Losh ccb->ccb_h.status = CAM_REQ_CMP; 4061b99d52fSWarner Losh break; 4071b99d52fSWarner Losh case XPT_RESET_BUS: 4081b99d52fSWarner Losh device_printf(sc->dev, "Got XPT_RESET_BUS, ACK it...\n"); 4091b99d52fSWarner Losh ccb->ccb_h.status = CAM_REQ_CMP; 4101b99d52fSWarner Losh break; 4111b99d52fSWarner Losh case XPT_MMC_IO: 4121b99d52fSWarner Losh /* 4131b99d52fSWarner Losh * Here is the HW-dependent part of 4141b99d52fSWarner Losh * sending the command to the underlying h/w 4151b99d52fSWarner Losh * At some point in the future an interrupt comes. 4161b99d52fSWarner Losh * Then the request will be marked as completed. 4171b99d52fSWarner Losh */ 4181b99d52fSWarner Losh device_printf(sc->dev, "Got XPT_MMC_IO\n"); 4191b99d52fSWarner Losh mmcnull_handle_mmcio(sim, ccb); 4201b99d52fSWarner Losh return; 4211b99d52fSWarner Losh break; 4221b99d52fSWarner Losh case XPT_RESET_DEV: 4231b99d52fSWarner Losh /* This is sent by `camcontrol reset`*/ 4241b99d52fSWarner Losh device_printf(sc->dev, "Got XPT_RESET_DEV\n"); 4251b99d52fSWarner Losh ccb->ccb_h.status = CAM_REQ_CMP; 4261b99d52fSWarner Losh break; 4271b99d52fSWarner Losh default: 4281b99d52fSWarner Losh device_printf(sc->dev, "Func code %d is unknown\n", ccb->ccb_h.func_code); 4291b99d52fSWarner Losh ccb->ccb_h.status = CAM_REQ_INVALID; 4301b99d52fSWarner Losh break; 4311b99d52fSWarner Losh } 4321b99d52fSWarner Losh xpt_done(ccb); 4331b99d52fSWarner Losh return; 4341b99d52fSWarner Losh } 4351b99d52fSWarner Losh 4361b99d52fSWarner Losh static void 4371b99d52fSWarner Losh mmcnull_action_sdio(struct cam_sim *sim, union ccb *ccb) { 4381b99d52fSWarner Losh mmcnull_action_sd(sim, ccb); 4391b99d52fSWarner Losh } 4401b99d52fSWarner Losh 4411b99d52fSWarner Losh static void 4421b99d52fSWarner Losh mmcnull_poll(struct cam_sim *sim) 4431b99d52fSWarner Losh { 4441b99d52fSWarner Losh return; 4451b99d52fSWarner Losh } 4461b99d52fSWarner Losh 4471b99d52fSWarner Losh 4481b99d52fSWarner Losh static device_method_t mmcnull_methods[] = { 4491b99d52fSWarner Losh /* Device interface */ 4501b99d52fSWarner Losh DEVMETHOD(device_identify, mmcnull_identify), 4511b99d52fSWarner Losh DEVMETHOD(device_probe, mmcnull_probe), 4521b99d52fSWarner Losh DEVMETHOD(device_attach, mmcnull_attach), 4531b99d52fSWarner Losh DEVMETHOD(device_detach, mmcnull_detach), 4541b99d52fSWarner Losh DEVMETHOD_END 4551b99d52fSWarner Losh }; 4561b99d52fSWarner Losh 4571b99d52fSWarner Losh static driver_t mmcnull_driver = { 4581b99d52fSWarner Losh "mmcnull", mmcnull_methods, sizeof(struct mmcnull_softc) 4591b99d52fSWarner Losh }; 4601b99d52fSWarner Losh 461*b58c5abfSJohn Baldwin DRIVER_MODULE(mmcnull, isa, mmcnull_driver, 0, 0); 462