Index: sys/cam/mmc/mmc_da.c =================================================================== --- sys/cam/mmc/mmc_da.c +++ sys/cam/mmc/mmc_da.c @@ -164,6 +164,7 @@ #define ccb_bp ppriv_ptr1 static disk_strategy_t sddastrategy; +static dumper_t sddadump; static periph_init_t sddainit; static void sddaasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg); @@ -1570,6 +1571,8 @@ part->disk->d_open = sddaopen; part->disk->d_close = sddaclose; part->disk->d_strategy = sddastrategy; + if (cam_sim_pollable(periph->sim)) + part->disk->d_dump = sddadump; part->disk->d_getattr = sddagetattr; part->disk->d_gone = sddadiskgonecb; part->disk->d_name = part->name; @@ -2005,4 +2008,74 @@ { return(cam_periph_error(ccb, cam_flags, sense_flags)); } + +static int +sddadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, + size_t length) +{ + struct ccb_mmcio mmcio; + struct disk *dp; + struct sdda_part *part; + struct sdda_softc *softc; + struct cam_periph *periph; + struct mmc_params *mmcp; + uint16_t count; + uint16_t opcode; + int error; + + dp = arg; + part = dp->d_drv1; + softc = part->sc; + periph = softc->periph; + mmcp = &periph->path->device->mmc_ident_data; + + if (softc->state != SDDA_STATE_NORMAL) + return (ENXIO); + + count = length / 512; + if (count == 0) + return (0); + + if (softc->part[softc->part_curr] != part) + return (EIO); /* TODO implement polled partition switch */ + + memset(&mmcio, 0, sizeof(mmcio)); + xpt_setup_ccb(&mmcio.ccb_h, periph->path, CAM_PRIORITY_NORMAL); /* XXX needed? */ + + mmcio.ccb_h.func_code = XPT_MMC_IO; + mmcio.ccb_h.flags = CAM_DIR_OUT; + mmcio.ccb_h.retry_count = 0; + mmcio.ccb_h.timeout = 15 * 1000; + + if (count > 1) + opcode = MMC_WRITE_MULTIPLE_BLOCK; + else + opcode = MMC_WRITE_BLOCK; + mmcio.cmd.opcode = opcode; + mmcio.cmd.arg = offset / 512; + if (!(mmcp->card_features & CARD_FEATURE_SDHC)) + mmcio.cmd.arg <<= 9; + + mmcio.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + mmcio.cmd.data = softc->mmcdata; + memset(mmcio.cmd.data, 0, sizeof(struct mmc_data)); + mmcio.cmd.data->data = virtual; + mmcio.cmd.data->len = 512 * count; + mmcio.cmd.data->flags = MMC_DATA_WRITE; + + /* Direct h/w to issue CMD12 upon completion */ + if (count > 1) { + mmcio.cmd.data->flags |= MMC_DATA_MULTI; + mmcio.stop.opcode = MMC_STOP_TRANSMISSION; + mmcio.stop.flags = MMC_RSP_R1B | MMC_CMD_AC; + mmcio.stop.arg = 0; + } + + error = cam_periph_runccb((union ccb *)&mmcio, cam_periph_error, + 0, SF_NO_RECOVERY | SF_NO_RETRY, NULL); + if (error != 0) + printf("Aborting dump due to I/O error.\n"); + return (error); +} + #endif /* _KERNEL */ Index: sys/cam/mmc/mmc_sim.c =================================================================== --- sys/cam/mmc/mmc_sim.c +++ sys/cam/mmc/mmc_sim.c @@ -46,8 +46,12 @@ static void mmc_cam_default_poll(struct cam_sim *sim) { + struct mmc_sim *mmc_sim; - return; + mmc_sim = cam_sim_softc(sim); + if (mmc_sim == NULL) + return; + MMC_SIM_CAM_POLL(mmc_sim->dev); } static void @@ -172,7 +176,7 @@ break; case XPT_MMC_IO: { - ccb->ccb_h.status = CAM_REQ_INVALID; + ccb->ccb_h.status = CAM_REQ_INPROG; rv = MMC_SIM_CAM_REQUEST(mmc_sim->dev, ccb); if (rv != 0) ccb->ccb_h.status = CAM_SIM_QUEUED; @@ -191,6 +195,8 @@ int mmc_cam_sim_alloc(device_t dev, const char *name, struct mmc_sim *mmc_sim) { + kobjop_desc_t kobj_desc; + kobj_method_t *kobj_method; mmc_sim->dev = dev; @@ -200,8 +206,13 @@ snprintf(mmc_sim->name, sizeof(mmc_sim->name), "%s_sim", name); mtx_init(&mmc_sim->mtx, mmc_sim->name, NULL, MTX_DEF); + + /* Provide sim_poll hook only if the device has the poll method. */ + kobj_desc = &mmc_sim_cam_poll_desc; + kobj_method = kobj_lookup_method(((kobj_t)dev)->ops->cls, NULL, + kobj_desc); mmc_sim->sim = cam_sim_alloc(mmc_cam_sim_default_action, - mmc_cam_default_poll, + kobj_method == &kobj_desc->deflt ? NULL : mmc_cam_default_poll, mmc_sim->name, mmc_sim, device_get_unit(dev), &mmc_sim->mtx, 1, 1, mmc_sim->devq); Index: sys/cam/mmc/mmc_sim_if.m =================================================================== --- sys/cam/mmc/mmc_sim_if.m +++ sys/cam/mmc/mmc_sim_if.m @@ -52,3 +52,7 @@ device_t dev; union ccb *ccb; }; + +METHOD void cam_poll { + device_t dev; +}; Index: sys/dev/mmc/host/dwmmc.c =================================================================== --- sys/dev/mmc/host/dwmmc.c +++ sys/dev/mmc/host/dwmmc.c @@ -38,12 +38,14 @@ #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -459,6 +461,9 @@ { bool was_present; + if (dumping || SCHEDULER_STOPPED()) + return; + was_present = sc->child != NULL; if (!was_present && is_present) { @@ -1543,6 +1548,15 @@ return (0); } + +static void +dwmmc_cam_poll(device_t dev) +{ + struct dwmmc_softc *sc; + + sc = device_get_softc(dev); + dwmmc_intr(sc); +} #endif /* MMCCAM */ static device_method_t dwmmc_methods[] = { @@ -1564,6 +1578,7 @@ DEVMETHOD(mmc_sim_get_tran_settings, dwmmc_get_tran_settings), DEVMETHOD(mmc_sim_set_tran_settings, dwmmc_set_tran_settings), DEVMETHOD(mmc_sim_cam_request, dwmmc_cam_request), + DEVMETHOD(mmc_sim_cam_poll, dwmmc_cam_poll), DEVMETHOD(bus_add_child, bus_generic_add_child), #endif