aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndriy Gapon <avg@FreeBSD.org>2022-01-12 07:01:29 +0000
committerAndriy Gapon <avg@FreeBSD.org>2022-01-26 07:27:21 +0000
commit79c3478e76c3bcea0879e799d81a8ac1d2b553e6 (patch)
tree6ff87791cab289aa314c98f1f362260ae20b93ea
parent82dbca47a5588efeadac7d52be690801de5f3ae8 (diff)
downloadsrc-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.c73
-rw-r--r--sys/cam/mmc/mmc_sim.c20
-rw-r--r--sys/cam/mmc/mmc_sim_if.m4
-rw-r--r--sys/dev/mmc/host/dwmmc.c15
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