From 44682688f038edbf34591b25ce36412a7f2d6d07 Mon Sep 17 00:00:00 2001 From: Andriy Gapon Date: Wed, 12 Jan 2022 09:01:29 +0200 Subject: [PATCH] mmc_da: implement d_dump method, sddadump sddadump has been derived from sddastart. mmc_sim interface has grown a new method, cam_poll, to support polled operation. mmc_sim code has been changed to provide a sim_poll hook only if the controller implements the new method. The hooks is implemented in terms of the new mmc_sim_cam_poll method. Additionally, in-progress CCB-s now have CAM_REQ_INPROG status to satisfy xpt_pollwait(). mmc_sim_cam_poll method has been implemented in dwmmc host controller. Reviewed by: manu, mav, imp MFC after: 2 weeks Relnotes: perhaps Differential Revision: https://reviews.freebsd.org/D33843 --- sys/cam/mmc/mmc_da.c | 73 ++++++++++++++++++++++++++++++++++++++++ sys/cam/mmc/mmc_sim.c | 20 ++++++----- sys/cam/mmc/mmc_sim_if.m | 4 +++ sys/dev/mmc/host/dwmmc.c | 15 +++++++++ 4 files changed, 103 insertions(+), 9 deletions(-) diff --git a/sys/cam/mmc/mmc_da.c b/sys/cam/mmc/mmc_da.c index 0dfa43f4679..8740421e416 100644 --- a/sys/cam/mmc/mmc_da.c +++ b/sys/cam/mmc/mmc_da.c @@ -164,6 +164,7 @@ static const char *mmc_errmsg[] = #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 @@ sdda_add_part(struct cam_periph *periph, u_int type, const char *name, 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 @@ sddaerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) { 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 */ diff --git a/sys/cam/mmc/mmc_sim.c b/sys/cam/mmc/mmc_sim.c index 792551a9351..40330958574 100644 --- a/sys/cam/mmc/mmc_sim.c +++ b/sys/cam/mmc/mmc_sim.c @@ -46,8 +46,10 @@ __FBSDID("$FreeBSD$"); static void mmc_cam_default_poll(struct cam_sim *sim) { + struct mmc_sim *mmc_sim; - return; + mmc_sim = cam_sim_softc(sim); + MMC_SIM_CAM_POLL(mmc_sim->dev); } static void @@ -97,12 +99,6 @@ mmc_cam_sim_default_action(struct cam_sim *sim, union ccb *ccb) mmc_sim = cam_sim_softc(sim); - if (mmc_sim == NULL) { - ccb->ccb_h.status = CAM_SEL_TIMEOUT; - xpt_done(ccb); - return; - } - mtx_assert(&mmc_sim->mtx, MA_OWNED); if (mmc_sim->ccb != NULL) { @@ -172,7 +168,6 @@ mmc_cam_sim_default_action(struct cam_sim *sim, union ccb *ccb) break; case XPT_MMC_IO: { - ccb->ccb_h.status = CAM_REQ_INVALID; rv = MMC_SIM_CAM_REQUEST(mmc_sim->dev, ccb); if (rv != 0) ccb->ccb_h.status = CAM_SIM_QUEUED; @@ -191,6 +186,8 @@ mmc_cam_sim_default_action(struct cam_sim *sim, union ccb *ccb) 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 +197,13 @@ mmc_cam_sim_alloc(device_t dev, const char *name, struct mmc_sim *mmc_sim) 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); diff --git a/sys/cam/mmc/mmc_sim_if.m b/sys/cam/mmc/mmc_sim_if.m index f1b88fc05ef..f7d3f4df5eb 100644 --- a/sys/cam/mmc/mmc_sim_if.m +++ b/sys/cam/mmc/mmc_sim_if.m @@ -52,3 +52,7 @@ METHOD int cam_request { device_t dev; union ccb *ccb; }; + +METHOD void cam_poll { + device_t dev; +}; diff --git a/sys/dev/mmc/host/dwmmc.c b/sys/dev/mmc/host/dwmmc.c index 2080a973564..70bd204069b 100644 --- a/sys/dev/mmc/host/dwmmc.c +++ b/sys/dev/mmc/host/dwmmc.c @@ -38,12 +38,14 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -459,6 +461,9 @@ dwmmc_handle_card_present(struct dwmmc_softc *sc, bool is_present) { bool was_present; + if (dumping || SCHEDULER_STOPPED()) + return; + was_present = sc->child != NULL; if (!was_present && is_present) { @@ -1543,6 +1548,15 @@ dwmmc_cam_request(device_t dev, union ccb *ccb) 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 @@ static device_method_t dwmmc_methods[] = { 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 -- 2.45.0