git: 44682688f038 - main - mmc_da: implement d_dump method, sddadump

From: Andriy Gapon <avg_at_FreeBSD.org>
Date: Wed, 12 Jan 2022 07:03:23 UTC
The branch main has been updated by avg:

URL: https://cgit.FreeBSD.org/src/commit/?id=44682688f038edbf34591b25ce36412a7f2d6d07

commit 44682688f038edbf34591b25ce36412a7f2d6d07
Author:     Andriy Gapon <avg@FreeBSD.org>
AuthorDate: 2022-01-12 07:01:29 +0000
Commit:     Andriy Gapon <avg@FreeBSD.org>
CommitDate: 2022-01-12 07:02:47 +0000

    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 0dfa43f4679b..8740421e416b 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 792551a93511..40330958574b 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 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 2080a973564f..70bd204069bd 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) {
@@ -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