diff options
author | Andriy Gapon <avg@FreeBSD.org> | 2022-01-12 07:01:29 +0000 |
---|---|---|
committer | Andriy Gapon <avg@FreeBSD.org> | 2022-01-26 07:27:21 +0000 |
commit | 79c3478e76c3bcea0879e799d81a8ac1d2b553e6 (patch) | |
tree | 6ff87791cab289aa314c98f1f362260ae20b93ea | |
parent | 82dbca47a5588efeadac7d52be690801de5f3ae8 (diff) | |
download | src-79c3478e76c3.tar.gz src-79c3478e76c3.zip |
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.
Relnotes: perhaps
(cherry picked from commit 44682688f038edbf34591b25ce36412a7f2d6d07)
-rw-r--r-- | sys/cam/mmc/mmc_da.c | 73 | ||||
-rw-r--r-- | sys/cam/mmc/mmc_sim.c | 20 | ||||
-rw-r--r-- | sys/cam/mmc/mmc_sim_if.m | 4 | ||||
-rw-r--r-- | 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 0aeea57eee26..272721f5ef34 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); @@ -1563,6 +1564,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; @@ -1998,4 +2001,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 461cb7625a1f..4e845be68e8b 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_dev(mmc_cam_sim_default_action, - mmc_cam_default_poll, + kobj_method == &kobj_desc->deflt ? NULL : mmc_cam_default_poll, mmc_sim->name, mmc_sim, 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 f1b88fc05ef5..f7d3f4df5ebb 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 f12a03e1c7aa..f0cd8c1b4378 100644 --- a/sys/dev/mmc/host/dwmmc.c +++ b/sys/dev/mmc/host/dwmmc.c @@ -38,12 +38,14 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/conf.h> #include <sys/bus.h> #include <sys/kernel.h> #include <sys/lock.h> #include <sys/module.h> #include <sys/malloc.h> #include <sys/mutex.h> +#include <sys/proc.h> #include <sys/rman.h> #include <sys/queue.h> #include <sys/taskqueue.h> @@ -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) { @@ -1535,6 +1540,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[] = { @@ -1556,6 +1570,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 |