Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F141964004
D4761.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
198 KB
Referenced Files
None
Subscribers
None
D4761.id.diff
View Options
Index: etc/mtree/BSD.include.dist
===================================================================
--- etc/mtree/BSD.include.dist
+++ etc/mtree/BSD.include.dist
@@ -90,6 +90,8 @@
cam
ata
..
+ mmc
+ ..
scsi
..
..
Index: include/Makefile
===================================================================
--- include/Makefile
+++ include/Makefile
@@ -40,7 +40,7 @@
LDIRS= bsm cam geom net net80211 netgraph netinet netinet6 \
netipsec netnatm netsmb nfs nfsclient nfsserver sys vm
-LSUBDIRS= cam/ata cam/scsi \
+LSUBDIRS= cam/ata cam/mmc cam/scsi \
dev/acpica dev/agp dev/an dev/bktr dev/ciss dev/filemon dev/firewire \
dev/hwpmc \
dev/ic dev/iicbus dev/io dev/lmc dev/mfi dev/nvme \
Index: lib/libcam/Makefile
===================================================================
--- lib/libcam/Makefile
+++ lib/libcam/Makefile
@@ -35,8 +35,8 @@
cam_cdbparse.3 csio_encode_visit.3 \
cam_cdbparse.3 buff_encode_visit.3
-.PATH: ${.CURDIR}/../../sys/cam/scsi ${.CURDIR}/../../sys/cam/ata \
- ${.CURDIR}/../../sys/cam
+.PATH: ${.CURDIR}/../../sys/cam ${.CURDIR}/../../sys/cam/ata \
+ ${.CURDIR}/../../sys/cam/mmc ${.CURDIR}/../../sys/cam/scsi
SDIR= ${.CURDIR}/../../sys
CFLAGS+= -I${.CURDIR} -I${SDIR}
Index: sbin/camcontrol/camcontrol.c
===================================================================
--- sbin/camcontrol/camcontrol.c
+++ sbin/camcontrol/camcontrol.c
@@ -100,7 +100,8 @@
CAM_CMD_APM = 0x00000021,
CAM_CMD_AAM = 0x00000022,
CAM_CMD_ATTRIB = 0x00000023,
- CAM_CMD_OPCODES = 0x00000024
+ CAM_CMD_OPCODES = 0x00000024,
+ CAM_CMD_MMCSD_CMD = 0x00000025
} cam_cmdmask;
typedef enum {
@@ -195,6 +196,7 @@
{"reset", CAM_CMD_RESET, CAM_ARG_NONE, NULL},
#ifndef MINIMALISTIC
{"cmd", CAM_CMD_SCSI_CMD, CAM_ARG_NONE, scsicmd_opts},
+ {"mmcsdcmd", CAM_CMD_MMCSD_CMD, CAM_ARG_NONE, "c:a:f:Wb:l:41S:"},
{"command", CAM_CMD_SCSI_CMD, CAM_ARG_NONE, scsicmd_opts},
{"smpcmd", CAM_CMD_SMP_CMD, CAM_ARG_NONE, "r:R:"},
{"smprg", CAM_CMD_SMP_RG, CAM_ARG_NONE, smprg_opts},
@@ -282,6 +284,8 @@
char *combinedopt, int retry_count, int timeout);
static int smpcmd(struct cam_device *device, int argc, char **argv,
char *combinedopt, int retry_count, int timeout);
+static int mmcsdcmd(struct cam_device *device, int argc, char **argv,
+ char *combinedopt, int retry_count, int timeout);
static int smpreportgeneral(struct cam_device *device, int argc, char **argv,
char *combinedopt, int retry_count, int timeout);
static int smpphycontrol(struct cam_device *device, int argc, char **argv,
@@ -568,6 +572,13 @@
sizeof(revision));
sprintf(tmpstr, "<%s %s>", product,
revision);
+ } else if (dev_result->protocol == PROTO_MMCSD) {
+ if (strlen(dev_result->mmc_ident_data.model) > 0) {
+ sprintf(tmpstr, "<%s>", dev_result->mmc_ident_data.model);
+ } else {
+ sprintf(tmpstr, "<%s card>",
+ dev_result->mmc_ident_data.card_features & CARD_FEATURE_SDIO ? "SDIO" : "unknown");
+ }
} else if (dev_result->protocol == PROTO_SEMB) {
struct sep_identify_data *sid;
@@ -7035,6 +7046,247 @@
}
static int
+mmcsdcmd(struct cam_device *device, int argc, char **argv, char *combinedopt,
+ int retry_count, int timeout)
+{
+ int c, error = 0;
+ union ccb *ccb;
+ int32_t mmc_opcode = 0, mmc_arg = 0;
+ int32_t mmc_flags = -1;
+ int retval;
+ int is_write = 0;
+ int is_bw_4 = 0, is_bw_1 = 0;
+ int is_highspeed = 0, is_stdspeed = 0;
+ int flags = 0;
+ uint8_t mmc_data_byte;
+
+ /* For IO_RW_EXTENDED command */
+ uint8_t *mmc_data = NULL;
+ struct mmc_data mmc_d;
+ int mmc_data_len = 0;
+
+ /*
+ * Note that at the moment we don't support sending SMP CCBs to
+ * devices that aren't probed by CAM.
+ */
+ ccb = cam_getccb(device);
+ if (ccb == NULL) {
+ warnx("%s: error allocating CCB", __func__);
+ return (1);
+ }
+
+ bzero(&(&ccb->ccb_h)[1],
+ sizeof(union ccb) - sizeof(struct ccb_hdr));
+
+ while ((c = getopt(argc, argv, combinedopt)) != -1) {
+ switch (c) {
+ case '4':
+ is_bw_4 = 1;
+ break;
+ case '1':
+ is_bw_1 = 1;
+ break;
+ case 'S':
+ if (!strcmp(optarg, "high"))
+ is_highspeed = 1;
+ else
+ is_stdspeed = 1;
+ break;
+ case 'c':
+ mmc_opcode = strtol(optarg, NULL, 0);
+ if (mmc_opcode < 0) {
+ warnx("invalid MMC opcode %d",
+ mmc_opcode);
+ error = 1;
+ goto mmccmd_bailout;
+ }
+ break;
+ case 'a':
+ mmc_arg = strtol(optarg, NULL, 0);
+ if (mmc_arg < 0) {
+ warnx("invalid MMC arg %d",
+ mmc_arg);
+ error = 1;
+ goto mmccmd_bailout;
+ }
+ break;
+ case 'f':
+ mmc_flags = strtol(optarg, NULL, 0);
+ if (mmc_flags < 0) {
+ warnx("invalid MMC flags %d",
+ mmc_flags);
+ error = 1;
+ goto mmccmd_bailout;
+ }
+ break;
+ case 'l':
+ mmc_data_len = strtol(optarg, NULL, 0);
+ if (mmc_data_len <= 0) {
+ warnx("invalid MMC data len %d",
+ mmc_data_len);
+ error = 1;
+ goto mmccmd_bailout;
+ }
+ break;
+ case 'W':
+ is_write = 1;
+ break;
+ case 'b':
+ mmc_data_byte = strtol(optarg, NULL, 0);
+ break;
+ default:
+ break;
+ }
+ }
+ flags |= CAM_DEV_QFRZDIS; /* masks are broken?! */
+
+ /* If flags are left default, supply the right flags */
+ if (mmc_flags < 0)
+ switch (mmc_opcode) {
+ case MMC_GO_IDLE_STATE:
+ mmc_flags = MMC_RSP_NONE | MMC_CMD_BC;
+ break;
+ case IO_SEND_OP_COND:
+ mmc_flags = MMC_RSP_R4;
+ break;
+ case SD_SEND_RELATIVE_ADDR:
+ mmc_flags = MMC_RSP_R6 | MMC_CMD_BCR;
+ break;
+ case MMC_SELECT_CARD:
+ mmc_flags = MMC_RSP_R1B | MMC_CMD_AC;
+ mmc_arg = mmc_arg << 16;
+ break;
+ case SD_IO_RW_DIRECT:
+ mmc_flags = MMC_RSP_R5 | MMC_CMD_AC;
+ mmc_arg = SD_IO_RW_ADR(mmc_arg);
+ if (is_write)
+ mmc_arg |= SD_IO_RW_WR | SD_IO_RW_RAW | SD_IO_RW_DAT(mmc_data_byte);
+ break;
+ case SD_IO_RW_EXTENDED:
+ mmc_flags = MMC_RSP_R5 | MMC_CMD_ADTC;
+ mmc_arg = SD_IO_RW_ADR(mmc_arg);
+ int len_arg = mmc_data_len;
+ if (mmc_data_len == 512)
+ len_arg = 0;
+
+ // Byte mode
+ mmc_arg |= SD_IOE_RW_LEN(len_arg) | SD_IO_RW_INCR;
+ // Block mode
+// mmc_arg |= SD_IOE_RW_BLK | SD_IOE_RW_LEN(len_arg) | SD_IO_RW_INCR;
+ break;
+ default:
+ mmc_flags = MMC_RSP_R1;
+ break;
+ }
+
+ // Switch bus width instead of sending IO command
+ if (is_bw_4 || is_bw_1) {
+ struct ccb_trans_settings_mmc *cts;
+ ccb->ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
+ ccb->ccb_h.flags = 0;
+ cts = &ccb->cts.proto_specific.mmc;
+ cts->ios.bus_width = is_bw_4 == 1 ? bus_width_4 : bus_width_1;
+ cts->ios_valid = MMC_BW;
+ if (((retval = cam_send_ccb(device, ccb)) < 0)
+ || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
+ warn("Error sending command");
+ } else {
+ printf("Parameters set OK\n");
+ }
+ cam_freeccb(ccb);
+ return (retval);
+ }
+
+ // Switch bus speed instead of sending IO command
+ if (is_stdspeed || is_highspeed) {
+ struct ccb_trans_settings_mmc *cts;
+ ccb->ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
+ ccb->ccb_h.flags = 0;
+ cts = &ccb->cts.proto_specific.mmc;
+ cts->ios.timing = is_highspeed == 1 ? bus_timing_hs : bus_timing_normal;
+ cts->ios_valid = MMC_BT;
+ if (((retval = cam_send_ccb(device, ccb)) < 0)
+ || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
+ warn("Error sending command");
+ } else {
+ printf("Parameters set OK\n");
+ }
+ cam_freeccb(ccb);
+ return (retval);
+ }
+
+ printf("CMD %d arg %d flags %02x\n", mmc_opcode, mmc_arg, mmc_flags);
+
+ if (mmc_data_len > 0) {
+ flags |= CAM_DIR_IN;
+ mmc_data = malloc(mmc_data_len);
+ memset(mmc_data, 0, mmc_data_len);
+ mmc_d.len = mmc_data_len;
+ mmc_d.data = mmc_data;
+ mmc_d.flags = MMC_DATA_READ;
+ }
+
+ cam_fill_mmcio(&ccb->mmcio,
+ /*retries*/ retry_count,
+ /*cbfcnp*/ NULL,
+ /*flags*/ flags,
+ /*mmc_opcode*/ mmc_opcode,
+ /*mmc_arg*/ mmc_arg,
+ /*mmc_flags*/ mmc_flags,
+ /*mmc_data*/ mmc_data_len > 0 ? &mmc_d : NULL,
+ /*timeout*/ timeout ? timeout : 5000);
+
+ if (((retval = cam_send_ccb(device, ccb)) < 0)
+ || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
+ const char warnstr[] = "error sending command";
+
+ if (retval < 0)
+ warn(warnstr);
+ else
+ warnx(warnstr);
+
+ if (arglist & CAM_ARG_VERBOSE) {
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
+ }
+ }
+
+ if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)) {
+ printf("MMCIO: error %d, %08x %08x %08x %08x\n",
+ ccb->mmcio.cmd.error, ccb->mmcio.cmd.resp[0],
+ ccb->mmcio.cmd.resp[1],
+ ccb->mmcio.cmd.resp[2],
+ ccb->mmcio.cmd.resp[3]);
+
+ switch (mmc_opcode) {
+ case SD_IO_RW_DIRECT:
+ printf("IO_RW_DIRECT: resp byte %02x, cur state %d\n",
+ SD_R5_DATA(ccb->mmcio.cmd.resp),
+ (ccb->mmcio.cmd.resp[0] >> 12) & 0x3
+ );
+ break;
+ case SD_IO_RW_EXTENDED:
+ printf("IO_RW_EXTENDED: read %d bytes w/o error:\n", mmc_data_len);
+ hexdump(mmc_data, mmc_data_len, NULL, 0);
+ break;
+ case SD_SEND_RELATIVE_ADDR:
+ printf("SEND_RELATIVE_ADDR: published RCA %02x\n", ccb->mmcio.cmd.resp[0] >> 16);
+ break;
+ default:
+ printf("No command-specific decoder for CMD %d\n", mmc_opcode);
+ }
+ }
+mmccmd_bailout:
+ if (ccb != NULL)
+ cam_freeccb(ccb);
+
+ if (mmc_data_len > 0 && mmc_data != NULL)
+ free(mmc_data);
+
+ return (error);
+}
+
+static int
smpreportgeneral(struct cam_device *device, int argc, char **argv,
char *combinedopt, int retry_count, int timeout)
{
@@ -9217,6 +9469,10 @@
error = scsicmd(cam_dev, argc, argv, combinedopt,
retry_count, timeout);
break;
+ case CAM_CMD_MMCSD_CMD:
+ error = mmcsdcmd(cam_dev, argc, argv, combinedopt,
+ retry_count, timeout);
+ break;
case CAM_CMD_SMP_CMD:
error = smpcmd(cam_dev, argc, argv, combinedopt,
retry_count, timeout);
Index: sys/arm/freescale/imx/imx_sdhci.c
===================================================================
--- sys/arm/freescale/imx/imx_sdhci.c
+++ sys/arm/freescale/imx/imx_sdhci.c
@@ -59,7 +59,7 @@
#include <dev/ofw/ofw_bus_subr.h>
#include <dev/mmc/bridge.h>
-#include <dev/mmc/mmcreg.h>
+#include <cam/mmc/mmcreg.h>
#include <dev/mmc/mmcbrvar.h>
#include <dev/sdhci/sdhci.h>
@@ -758,7 +758,7 @@
bus_generic_probe(dev);
bus_generic_attach(dev);
- sdhci_start_slot(&sc->slot);
+ sdhci_cam_start_slot(&sc->slot);
return (0);
@@ -834,4 +834,4 @@
DRIVER_MODULE(sdhci_imx, simplebus, imx_sdhci_driver, imx_sdhci_devclass, 0, 0);
MODULE_DEPEND(sdhci_imx, sdhci, 1, 1, 1);
-DRIVER_MODULE(mmc, sdhci_imx, mmc_driver, mmc_devclass, NULL, NULL);
+//DRIVER_MODULE(mmc, sdhci_imx, mmc_driver, mmc_devclass, NULL, NULL);
Index: sys/arm/ti/ti_sdhci.c
===================================================================
--- sys/arm/ti/ti_sdhci.c
+++ sys/arm/ti/ti_sdhci.c
@@ -39,6 +39,8 @@
#include <sys/rman.h>
#include <sys/sysctl.h>
#include <sys/taskqueue.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
#include <machine/bus.h>
#include <machine/resource.h>
@@ -49,7 +51,7 @@
#include <dev/ofw/ofw_bus_subr.h>
#include <dev/mmc/bridge.h>
-#include <dev/mmc/mmcreg.h>
+#include <cam/mmc/mmcreg.h>
#include <dev/mmc/mmcbrvar.h>
#include <dev/sdhci/sdhci.h>
@@ -122,6 +124,11 @@
#define MMCHS_SD_CAPA_VS30 (1 << 25)
#define MMCHS_SD_CAPA_VS33 (1 << 24)
+/* Forward declarations, CAM-relataed */
+// static void ti_sdhci_cam_poll(struct cam_sim *);
+// static void ti_sdhci_cam_action(struct cam_sim *, union ccb *);
+// static int ti_sdhci_cam_settran_settings(struct ti_sdhci_softc *sc, union ccb *);
+
static inline uint32_t
ti_mmchs_read_4(struct ti_sdhci_softc *sc, bus_size_t off)
{
@@ -650,7 +657,7 @@
bus_generic_probe(dev);
bus_generic_attach(dev);
- sdhci_start_slot(&sc->slot);
+ sdhci_cam_start_slot(&sc->slot);
return (0);
@@ -680,6 +687,162 @@
return (ENXIO);
}
+#if 0
+static void
+ti_sdhci_handle_mmcio(struct cam_sim *sim, union ccb *ccb)
+{
+ struct ti_sdhci_softc *sc;
+
+ sc = cam_sim_softc(sim);
+
+ sdhci_request_cam(&sc->slot, ccb);
+}
+
+static void
+ti_sdhci_cam_action(struct cam_sim *sim, union ccb *ccb)
+{
+ struct ti_sdhci_softc *sc;
+
+ sc = cam_sim_softc(sim);
+ if (sc == NULL) {
+ ccb->ccb_h.status = CAM_SEL_TIMEOUT;
+ xpt_done(ccb);
+ return;
+ }
+
+ mtx_assert(&sc->sc_mtx, MA_OWNED);
+
+ device_printf(sc->dev, "action: func_code %0x\n", ccb->ccb_h.func_code);
+
+ switch (ccb->ccb_h.func_code) {
+ case XPT_PATH_INQ:
+ {
+ struct ccb_pathinq *cpi;
+
+ cpi = &ccb->cpi;
+ cpi->version_num = 1;
+ cpi->hba_inquiry = PI_SDTR_ABLE | PI_TAG_ABLE | PI_WIDE_16;
+ cpi->target_sprt = 0;
+ cpi->hba_misc = PIM_NOBUSRESET | PIM_SEQSCAN;
+ cpi->hba_eng_cnt = 0;
+ cpi->max_target = 0;
+ cpi->max_lun = 0;
+ cpi->initiator_id = 1;
+ strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
+ strncpy(cpi->hba_vid, "Deglitch Networks", HBA_IDLEN);
+ strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
+ cpi->unit_number = cam_sim_unit(sim);
+ cpi->bus_id = cam_sim_bus(sim);
+ cpi->base_transfer_speed = 100; /* XXX WTF? */
+ cpi->protocol = PROTO_MMCSD;
+ cpi->protocol_version = SCSI_REV_0;
+ cpi->transport = XPORT_MMCSD;
+ cpi->transport_version = 0;
+
+ cpi->ccb_h.status = CAM_REQ_CMP;
+ break;
+ }
+ case XPT_GET_TRAN_SETTINGS:
+ {
+ struct ccb_trans_settings *cts = &ccb->cts;
+
+ device_printf(sc->dev, "Got XPT_GET_TRAN_SETTINGS\n");
+
+ cts->protocol = PROTO_MMCSD;
+ cts->protocol_version = 0;
+ cts->transport = XPORT_MMCSD;
+ cts->transport_version = 0;
+ cts->xport_specific.valid = 0;
+ cts->proto_specific.mmc.host_ocr = sc->slot.host.host_ocr;
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+ }
+ case XPT_SET_TRAN_SETTINGS:
+ device_printf(sc->dev, "Got XPT_SET_TRAN_SETTINGS, should update IOS...\n");
+ ti_sdhci_cam_settran_settings(sc, ccb);
+
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+ case XPT_RESET_BUS:
+ device_printf(sc->dev, "Got XPT_RESET_BUS, ACK it...\n");
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+ case XPT_MMC_IO:
+ /*
+ * Here is the HW-dependent part of
+ * sending the command to the underlying h/w
+ * At some point in the future an interrupt comes.
+ * Then the request will be marked as completed.
+ */
+ device_printf(sc->dev, "Got XPT_MMC_IO\n");
+ ccb->ccb_h.status = CAM_REQ_INPROG;
+
+ ti_sdhci_handle_mmcio(sim, ccb);
+ return;
+ /* NOTREACHED */
+ break;
+ default:
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ break;
+ }
+ xpt_done(ccb);
+ return;
+}
+
+static void
+ti_sdhci_cam_poll(struct cam_sim *sim)
+{
+ return;
+}
+
+static int
+ti_sdhci_cam_settran_settings(struct ti_sdhci_softc *sc, union ccb *ccb)
+{
+ struct sdhci_slot *slot;
+ struct mmc_ios *ios;
+ struct mmc_ios *new_ios;
+ uint32_t val32;
+ struct ccb_trans_settings_mmc *cts;
+
+ slot = &sc->slot;
+ ios = &slot->host.ios;
+
+ cts = &ccb->cts.proto_specific.mmc;
+ new_ios = &cts->ios;
+
+ /* Update only requested fields */
+ if (cts->ios_valid & MMC_CLK)
+ ios->clock = new_ios->clock;
+ if (cts->ios_valid & MMC_VDD) {
+ ios->vdd = new_ios->vdd;
+ device_printf(sc->dev, "VDD => %d\n", ios->vdd);
+ }
+ if (cts->ios_valid & MMC_CS)
+ ios->chip_select = new_ios->chip_select;
+ if (cts->ios_valid & MMC_BW)
+ ios->bus_width = new_ios->bus_width;
+ if (cts->ios_valid & MMC_PM)
+ ios->power_mode = new_ios->power_mode;
+ if (cts->ios_valid & MMC_BT)
+ ios->timing = new_ios->timing;
+ if (cts->ios_valid & MMC_BM)
+ ios->bus_mode = new_ios->bus_mode;
+ /*
+ * There is an 8-bit-bus bit in the MMCHS control register which, when
+ * set, overrides the 1 vs 4 bit setting in the standard SDHCI
+ * registers. Set that bit first according to whether an 8-bit bus is
+ * requested, then let the standard driver handle everything else.
+ */
+ val32 = ti_mmchs_read_4(sc, MMCHS_CON);
+ if (ios->bus_width == bus_width_8)
+ ti_mmchs_write_4(sc, MMCHS_CON, val32 | MMCHS_CON_DW8);
+ else
+ ti_mmchs_write_4(sc, MMCHS_CON, val32 & ~MMCHS_CON_DW8);
+
+ return (sdhci_update_ios_cam(slot));
+}
+#endif
+
static device_method_t ti_sdhci_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, ti_sdhci_probe),
@@ -721,4 +884,4 @@
DRIVER_MODULE(sdhci_ti, simplebus, ti_sdhci_driver, ti_sdhci_devclass, 0, 0);
MODULE_DEPEND(sdhci_ti, sdhci, 1, 1, 1);
-DRIVER_MODULE(mmc, sdhci_ti, mmc_driver, mmc_devclass, NULL, NULL);
+//DRIVER_MODULE(mmc, sdhci_ti, mmc_driver, mmc_devclass, NULL, NULL);
Index: sys/cam/cam_ccb.h
===================================================================
--- sys/cam/cam_ccb.h
+++ sys/cam/cam_ccb.h
@@ -41,6 +41,7 @@
#include <cam/cam_debug.h>
#include <cam/scsi/scsi_all.h>
#include <cam/ata/ata_all.h>
+#include <cam/mmc/mmc_all.h>
/* General allocation length definitions for CCB structures */
#define IOCDBLEN CAM_MAX_CDBLEN /* Space for CDB bytes/pointer */
@@ -229,6 +230,8 @@
/* Notify Host Target driver of event */
XPT_NOTIFY_ACKNOWLEDGE = 0x37 | XPT_FC_QUEUED | XPT_FC_USER_CCB,
/* Acknowledgement of event */
+ XPT_MMC_IO = 0x38 | XPT_FC_DEV_QUEUED,
+ /* Execute the requested MMC I/O operation */
/* Vendor Unique codes: 0x80->0x8F */
XPT_VUNIQUE = 0x80
@@ -255,6 +258,7 @@
PROTO_ATAPI, /* AT Attachment Packetized Interface */
PROTO_SATAPM, /* SATA Port Multiplier */
PROTO_SEMB, /* SATA Enclosure Management Bridge */
+ PROTO_MMCSD, /* MMC, SD, SDIO */
} cam_proto;
typedef enum {
@@ -270,6 +274,7 @@
XPORT_SATA, /* Serial AT Attachment */
XPORT_ISCSI, /* iSCSI */
XPORT_SRP, /* SCSI RDMA Protocol */
+ XPORT_MMCSD, /* MMC, SD, SDIO card */
} cam_xport;
#define XPORT_IS_ATA(t) ((t) == XPORT_ATA || (t) == XPORT_SATA)
@@ -482,6 +487,7 @@
cam_proto protocol;
struct scsi_inquiry_data inq_data;
struct ata_params ident_data;
+ struct mmc_params mmc_ident_data;
dev_result_flags flags;
};
@@ -745,6 +751,16 @@
u_int init_id; /* initiator id of who selected */
};
+/*
+ * MMC I/O Request CCB used for the XPT_MMC_IO function code.
+ */
+struct ccb_mmcio {
+ struct ccb_hdr ccb_h;
+ union ccb *next_ccb; /* Ptr for next CCB for action */
+ struct mmc_command cmd;
+ struct mmc_command stop;
+};
+
struct ccb_accept_tio {
struct ccb_hdr ccb_h;
cdb_t cdb_io; /* Union for CDB bytes/pointer */
@@ -946,6 +962,26 @@
#define CTS_SATA_CAPS_D_APST 0x00020000
};
+/*
+ * Basically, what earlier was done with updating IOS
+ * now can be done using SET_TRAN_SETTINGS
+ */
+#include <cam/mmc/mmc_bus.h>
+struct ccb_trans_settings_mmc {
+ struct mmc_ios ios;
+#define MMC_CLK (1 << 1)
+#define MMC_VDD (1 << 2)
+#define MMC_CS (1 << 3)
+#define MMC_BW (1 << 4)
+#define MMC_PM (1 << 5)
+#define MMC_BT (1 << 6)
+#define MMC_BM (1 << 7)
+ uint32_t ios_valid;
+
+/* The folowing is used only for GET_TRAN_SETTINGS */
+ uint32_t host_ocr;
+};
+
/* Get/Set transfer rate/width/disconnection/tag queueing settings */
struct ccb_trans_settings {
struct ccb_hdr ccb_h;
@@ -958,6 +994,7 @@
u_int valid; /* Which fields to honor */
struct ccb_trans_settings_ata ata;
struct ccb_trans_settings_scsi scsi;
+ struct ccb_trans_settings_mmc mmc;
} proto_specific;
union {
u_int valid; /* Which fields to honor */
@@ -1211,6 +1248,7 @@
struct ccb_ataio ataio;
struct ccb_dev_advinfo cdai;
struct ccb_async casync;
+ struct ccb_mmcio mmcio;
};
__BEGIN_DECLS
@@ -1244,6 +1282,13 @@
uint32_t timeout);
static __inline void
+cam_fill_mmcio(struct ccb_mmcio *mmcio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *), uint32_t flags,
+ uint32_t mmc_opcode, uint32_t mmc_arg, uint32_t mmc_flags,
+ struct mmc_data *mmc_d,
+ uint32_t timeout);
+
+static __inline void
cam_fill_csio(struct ccb_scsiio *csio, u_int32_t retries,
void (*cbfcnp)(struct cam_periph *, union ccb *),
u_int32_t flags, u_int8_t tag_action,
@@ -1329,6 +1374,34 @@
}
static __inline void
+cam_fill_mmcio(struct ccb_mmcio *mmcio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *), uint32_t flags,
+ uint32_t mmc_opcode, uint32_t mmc_arg, uint32_t mmc_flags,
+ struct mmc_data *mmc_d,
+ uint32_t timeout)
+{
+ mmcio->ccb_h.func_code = XPT_MMC_IO;
+ mmcio->ccb_h.flags = flags;
+ mmcio->ccb_h.retry_count = retries;
+ mmcio->ccb_h.cbfcnp = cbfcnp;
+ mmcio->ccb_h.timeout = timeout;
+ mmcio->cmd.opcode = mmc_opcode;
+ mmcio->cmd.arg = mmc_arg;
+ mmcio->cmd.flags = mmc_flags;
+ if (mmc_d != NULL) {
+ mmcio->cmd.data.len = mmc_d->len;
+ mmcio->cmd.data.data = mmc_d->data;
+ mmcio->cmd.data.flags = mmc_d->flags;
+ }
+ else
+ mmcio->cmd.data.len = 0;
+ mmcio->cmd.resp[0] = 0;
+ mmcio->cmd.resp[1] = 0;
+ mmcio->cmd.resp[2] = 0;
+ mmcio->cmd.resp[3] = 0;
+}
+
+static __inline void
cam_set_ccbstatus(union ccb *ccb, cam_status status)
{
ccb->ccb_h.status &= ~CAM_STATUS_MASK;
Index: sys/cam/cam_periph.c
===================================================================
--- sys/cam/cam_periph.c
+++ sys/cam/cam_periph.c
@@ -777,6 +777,20 @@
dirs[0] = ccb->ccb_h.flags & CAM_DIR_MASK;
numbufs = 1;
break;
+ case XPT_MMC_IO:
+ printf("cam_periph_mapmem: MMCIO flags %02x\n", ccb->ccb_h.flags);
+ if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE)
+ return(0);
+ if (ccb->mmcio.cmd.data.len == 0) {
+ printf("cam_periph_mapmem: almost failed!...\n");
+ return(0);
+ }
+ printf("cam_periph_mapmem: Setting up memory map...\n");
+ data_ptrs[0] = (unsigned char **)&ccb->mmcio.cmd.data.data;
+ lengths[0] = ccb->mmcio.cmd.data.len;
+ dirs[0] = ccb->ccb_h.flags & CAM_DIR_MASK;
+ numbufs = 1;
+ break;
case XPT_SMP_IO:
data_ptrs[0] = &ccb->smpio.smp_request;
lengths[0] = ccb->smpio.smp_request_len;
Index: sys/cam/cam_xpt.c
===================================================================
--- sys/cam/cam_xpt.c
+++ sys/cam/cam_xpt.c
@@ -391,7 +391,7 @@
}
return (error);
}
-
+
static int
xptdoioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
{
@@ -1028,6 +1028,8 @@
else if (path->device->protocol == PROTO_SEMB)
semb_print_ident(
(struct sep_identify_data *)&path->device->ident_data);
+ else if (path->device->protocol == PROTO_MMCSD)
+ mmc_print_ident(&path->device->mmc_ident_data);
else
printf("Unknown protocol device\n");
if (path->device->serial_num_len > 0) {
@@ -1081,6 +1083,8 @@
else if (path->device->protocol == PROTO_SEMB)
semb_print_ident_short(
(struct sep_identify_data *)&path->device->ident_data);
+ else if (path->device->protocol == PROTO_MMCSD)
+ mmc_print_ident(&path->device->mmc_ident_data);
else
printf("Unknown protocol device");
if (path->device->serial_num_len > 0)
@@ -1328,7 +1332,7 @@
cur_pattern = &patterns[i].pattern.device_pattern;
- /* Error out if mutually exclusive options are specified. */
+ /* Error out if mutually exclusive options are specified. */
if ((cur_pattern->flags & (DEV_MATCH_INQUIRY|DEV_MATCH_DEVID))
== (DEV_MATCH_INQUIRY|DEV_MATCH_DEVID))
return(DM_RET_ERROR);
@@ -1730,6 +1734,9 @@
bcopy(&device->ident_data,
&cdm->matches[j].result.device_result.ident_data,
sizeof(struct ata_params));
+ bcopy(&device->mmc_ident_data,
+ &cdm->matches[j].result.device_result.mmc_ident_data,
+ sizeof(struct mmc_params));
/* Let the user know whether this device is unconfigured */
if (device->flags & CAM_DEV_UNCONFIGURED)
@@ -2509,6 +2516,7 @@
if (start_ccb->ccb_h.func_code == XPT_ATA_IO)
start_ccb->ataio.resid = 0;
/* FALLTHROUGH */
+ case XPT_MMC_IO:
case XPT_RESET_DEV:
case XPT_ENG_EXEC:
case XPT_SMP_IO:
@@ -3885,6 +3893,9 @@
case XPORT_SATA:
new_bus->xport = ata_get_xport();
break;
+ case XPORT_MMCSD:
+ new_bus->xport = mmc_get_xport();
+ break;
default:
new_bus->xport = &xport_default;
break;
Index: sys/cam/cam_xpt_internal.h
===================================================================
--- sys/cam/cam_xpt_internal.h
+++ sys/cam/cam_xpt_internal.h
@@ -90,6 +90,7 @@
uint32_t rcap_len;
uint8_t *rcap_buf;
struct ata_params ident_data;
+ struct mmc_params mmc_ident_data;
u_int8_t inq_flags; /*
* Current settings for inquiry flags.
* This allows us to override settings
@@ -167,6 +168,7 @@
struct xpt_xport * scsi_get_xport(void);
struct xpt_xport * ata_get_xport(void);
+struct xpt_xport * mmc_get_xport(void);
struct cam_ed * xpt_alloc_device(struct cam_eb *bus,
struct cam_et *target,
Index: sys/cam/mmc/mmc.h
===================================================================
--- /dev/null
+++ sys/cam/mmc/mmc.h
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 2014-2016 Ilya Bakulin. All rights reserved.
+ * Lots of code taken from sys/dev/mmc implementation,
+ * thanks to Warner Losh <imp@FreeBSD.org>, Alexander Motin <mav@FreeBSD.org> and other authors.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Portions of this software may have been developed with reference to
+ * the SD Simplified Specification. The following disclaimer may apply:
+ *
+ * The following conditions apply to the release of the simplified
+ * specification ("Simplified Specification") by the SD Card Association and
+ * the SD Group. The Simplified Specification is a subset of the complete SD
+ * Specification which is owned by the SD Card Association and the SD
+ * Group. This Simplified Specification is provided on a non-confidential
+ * basis subject to the disclaimers below. Any implementation of the
+ * Simplified Specification may require a license from the SD Card
+ * Association, SD Group, SD-3C LLC or other third parties.
+ *
+ * Disclaimers:
+ *
+ * The information contained in the Simplified Specification is presented only
+ * as a standard specification for SD Cards and SD Host/Ancillary products and
+ * is provided "AS-IS" without any representations or warranties of any
+ * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD
+ * Card Association for any damages, any infringements of patents or other
+ * right of the SD Group, SD-3C LLC, the SD Card Association or any third
+ * parties, which may result from its use. No license is granted by
+ * implication, estoppel or otherwise under any patent or other rights of the
+ * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing
+ * herein shall be construed as an obligation by the SD Group, the SD-3C LLC
+ * or the SD Card Association to disclose or distribute any technical
+ * information, know-how or other confidential information to any third party.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef CAM_MMC_H
+#define CAM_MMC_H
+
+#include <cam/mmc/mmcreg.h>
+/*
+ * This structure describes an MMC/SD card
+ */
+struct mmc_params {
+ u_int8_t model[40]; /* Card model */
+
+ /* Card OCR */
+ uint32_t card_ocr;
+
+ /* OCR of the IO portion of the card */
+ uint32_t io_ocr;
+
+ /* Card CID -- raw and parsed */
+ uint32_t card_cid[4];
+ struct mmc_cid cid;
+
+ /* Card CSD -- raw */
+ uint32_t card_csd[4];
+
+ /* Card RCA */
+ uint16_t card_rca;
+
+ /* What kind of card is it */
+ uint32_t card_features;
+#define CARD_FEATURE_MEMORY 0x1
+#define CARD_FEATURE_SDHC 0x1 << 1
+#define CARD_FEATURE_SDIO 0x1 << 2
+#define CARD_FEATURE_SD20 0x1 << 3
+#define CARD_FEATURE_MMC 0x1 << 4
+
+ uint8_t sdio_func_count;
+} __packed;
+
+#endif
Index: sys/cam/mmc/mmc_all.h
===================================================================
--- /dev/null
+++ sys/cam/mmc/mmc_all.h
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 2014-2016 Ilya Bakulin. All rights reserved.
+ * Lots of code taken from sys/dev/mmc implementation,
+ * thanks to Warner Losh <imp@FreeBSD.org>, Alexander Motin <mav@FreeBSD.org> and other authors.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Portions of this software may have been developed with reference to
+ * the SD Simplified Specification. The following disclaimer may apply:
+ *
+ * The following conditions apply to the release of the simplified
+ * specification ("Simplified Specification") by the SD Card Association and
+ * the SD Group. The Simplified Specification is a subset of the complete SD
+ * Specification which is owned by the SD Card Association and the SD
+ * Group. This Simplified Specification is provided on a non-confidential
+ * basis subject to the disclaimers below. Any implementation of the
+ * Simplified Specification may require a license from the SD Card
+ * Association, SD Group, SD-3C LLC or other third parties.
+ *
+ * Disclaimers:
+ *
+ * The information contained in the Simplified Specification is presented only
+ * as a standard specification for SD Cards and SD Host/Ancillary products and
+ * is provided "AS-IS" without any representations or warranties of any
+ * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD
+ * Card Association for any damages, any infringements of patents or other
+ * right of the SD Group, SD-3C LLC, the SD Card Association or any third
+ * parties, which may result from its use. No license is granted by
+ * implication, estoppel or otherwise under any patent or other rights of the
+ * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing
+ * herein shall be construed as an obligation by the SD Group, the SD-3C LLC
+ * or the SD Card Association to disclose or distribute any technical
+ * information, know-how or other confidential information to any third party.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * MMC function that should be visible to the CAM subsystem
+ * and are somehow useful should be declared here
+ *
+ * Like in other *_all.h, it's also a nice place to include
+ * some other transport-specific headers.
+ */
+
+#ifndef CAM_MMC_ALL_H
+#define CAM_MMC_ALL_H
+
+#include <cam/mmc/mmc.h>
+#include <cam/mmc/mmcreg.h>
+
+void mmc_print_ident(struct mmc_params *ident_data);
+
+#endif
Index: sys/cam/mmc/mmc_bus.h
===================================================================
--- /dev/null
+++ sys/cam/mmc/mmc_bus.h
@@ -0,0 +1,141 @@
+/*-
+ * Copyright (c) 2015-2016 Ilya Bakulin <kibab@FreeBSD.org>
+ * All rights reserved.
+ * Lots of code taken from sys/dev/mmc implementation,
+ * thanks to Warner Losh <imp@FreeBSD.org>, Alexander Motin <mav@FreeBSD.org> and other authors.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Portions of this software may have been developed with reference to
+ * the SD Simplified Specification. The following disclaimer may apply:
+ *
+ * The following conditions apply to the release of the simplified
+ * specification ("Simplified Specification") by the SD Card Association and
+ * the SD Group. The Simplified Specification is a subset of the complete SD
+ * Specification which is owned by the SD Card Association and the SD
+ * Group. This Simplified Specification is provided on a non-confidential
+ * basis subject to the disclaimers below. Any implementation of the
+ * Simplified Specification may require a license from the SD Card
+ * Association, SD Group, SD-3C LLC or other third parties.
+ *
+ * Disclaimers:
+ *
+ * The information contained in the Simplified Specification is presented only
+ * as a standard specification for SD Cards and SD Host/Ancillary products and
+ * is provided "AS-IS" without any representations or warranties of any
+ * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD
+ * Card Association for any damages, any infringements of patents or other
+ * right of the SD Group, SD-3C LLC, the SD Card Association or any third
+ * parties, which may result from its use. No license is granted by
+ * implication, estoppel or otherwise under any patent or other rights of the
+ * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing
+ * herein shall be construed as an obligation by the SD Group, the SD-3C LLC
+ * or the SD Card Association to disclose or distribute any technical
+ * information, know-how or other confidential information to any third party.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef DEV_MMC_BRIDGE_H
+#define DEV_MMC_BRIDGE_H
+
+/*
+ * This file defines interfaces for the mmc bridge. The names chosen
+ * are similar to or the same as the names used in Linux to allow for
+ * easy porting of what Linux calls mmc host drivers. I use the
+ * FreeBSD terminology of bridge and bus for consistancy with other
+ * drivers in the system. This file corresponds roughly to the Linux
+ * linux/mmc/host.h file.
+ *
+ * A mmc bridge is a chipset that can have one or more mmc and/or sd
+ * cards attached to it. mmc cards are attached on a bus topology,
+ * while sd and sdio cards are attached using a star topology (meaning
+ * in practice each sd card has its own, independent slot). Each
+ * mmcbr is assumed to be derived from the mmcbr. This is done to
+ * allow for easier addition of bridges (as each bridge does not need
+ * to be added to the mmcbus file).
+ *
+ * Attached to the mmc bridge is an mmcbus. The mmcbus is described
+ * in dev/mmc/bus.h.
+ */
+
+
+/*
+ * mmc_ios is a structure that is used to store the state of the mmc/sd
+ * bus configuration. This include the bus' clock speed, its voltage,
+ * the bus mode for command output, the SPI chip select, some power
+ * states and the bus width.
+ */
+enum mmc_vdd {
+ vdd_150 = 0, vdd_155, vdd_160, vdd_165, vdd_170, vdd_180,
+ vdd_190, vdd_200, vdd_210, vdd_220, vdd_230, vdd_240, vdd_250,
+ vdd_260, vdd_270, vdd_280, vdd_290, vdd_300, vdd_310, vdd_320,
+ vdd_330, vdd_340, vdd_350, vdd_360
+};
+
+enum mmc_power_mode {
+ power_off = 0, power_up, power_on
+};
+
+enum mmc_bus_mode {
+ opendrain = 1, pushpull
+};
+
+enum mmc_chip_select {
+ cs_dontcare = 0, cs_high, cs_low
+};
+
+enum mmc_bus_width {
+ bus_width_1 = 0, bus_width_4 = 2, bus_width_8 = 3
+};
+
+enum mmc_bus_timing {
+ bus_timing_normal = 0, bus_timing_hs
+};
+
+struct mmc_ios {
+ uint32_t clock; /* Speed of the clock in Hz to move data */
+ enum mmc_vdd vdd; /* Voltage to apply to the power pins/ */
+ enum mmc_bus_mode bus_mode;
+ enum mmc_chip_select chip_select;
+ enum mmc_bus_width bus_width;
+ enum mmc_power_mode power_mode;
+ enum mmc_bus_timing timing;
+};
+
+enum mmc_card_mode {
+ mode_mmc, mode_sd
+};
+
+struct mmc_host {
+ int f_min;
+ int f_max;
+ uint32_t host_ocr;
+ uint32_t ocr;
+ uint32_t caps;
+#define MMC_CAP_4_BIT_DATA (1 << 0) /* Can do 4-bit data transfers */
+#define MMC_CAP_8_BIT_DATA (1 << 1) /* Can do 8-bit data transfers */
+#define MMC_CAP_HSPEED (1 << 2) /* Can do High Speed transfers */
+ enum mmc_card_mode mode;
+ struct mmc_ios ios; /* Current state of the host */
+};
+
+#endif /* DEV_MMC_BRIDGE_H */
Index: sys/cam/mmc/mmc_da.c
===================================================================
--- /dev/null
+++ sys/cam/mmc/mmc_da.c
@@ -0,0 +1,1140 @@
+/*-
+ * Copyright (c) 2015-2016 Ilya Bakulin <kibab@FreeBSD.org>
+ * All rights reserved.
+ * Lots of code taken from sys/dev/mmc implementation,
+ * thanks to Warner Losh <imp@FreeBSD.org>, Alexander Motin <mav@FreeBSD.org> and other authors.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+//#include "opt_sdda.h"
+
+#include <sys/param.h>
+
+#ifdef _KERNEL
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bio.h>
+#include <sys/taskqueue.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/conf.h>
+#include <sys/devicestat.h>
+#include <sys/eventhandler.h>
+#include <sys/malloc.h>
+#include <sys/cons.h>
+#include <sys/proc.h>
+#include <sys/reboot.h>
+#include <geom/geom_disk.h>
+#include <machine/_inttypes.h> /* for PRIu64 */
+#endif /* _KERNEL */
+
+#ifndef _KERNEL
+#include <stdio.h>
+#include <string.h>
+#endif /* _KERNEL */
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_queue.h>
+#include <cam/cam_periph.h>
+#include <cam/cam_sim.h>
+#include <cam/cam_xpt.h>
+#include <cam/cam_xpt_sim.h>
+#include <cam/cam_xpt_periph.h>
+#include <cam/cam_xpt_internal.h>
+#include <cam/cam_debug.h>
+
+
+#include <cam/mmc/mmc_all.h>
+
+#include <machine/md_var.h> /* geometry translation */
+
+#ifdef _KERNEL
+
+typedef enum {
+ SDDA_FLAG_OPEN = 0x0002,
+ SDDA_FLAG_DIRTY = 0x0004
+} sdda_flags;
+
+typedef enum {
+ SDDA_STATE_INIT,
+ SDDA_STATE_INVALID,
+ SDDA_STATE_NORMAL
+} sdda_state;
+
+struct sdda_softc {
+ struct bio_queue_head bio_queue;
+ int outstanding_cmds; /* Number of active commands */
+ int refcount; /* Active xpt_action() calls */
+ sdda_state state;
+ sdda_flags flags;
+// sdda_quirks quirks;
+ struct disk *disk;
+ uint32_t raw_csd[4];
+ struct mmc_csd csd;
+ struct mmc_cid cid;
+ /* Calculated from CSD */
+ uint64_t sector_count;
+ uint64_t mediasize;
+
+ /* Calculated from CID */
+ char card_id_string[64];/* Formatted CID info (serial, MFG, etc) */
+ char card_sn_string[16];/* Formatted serial # for disk->d_ident */
+};
+
+#define ccb_bp ppriv_ptr1
+
+static disk_strategy_t sddastrategy;
+static periph_init_t sddainit;
+static void sddaasync(void *callback_arg, u_int32_t code,
+ struct cam_path *path, void *arg);
+static periph_ctor_t sddaregister;
+static periph_dtor_t sddacleanup;
+static periph_start_t sddastart;
+static periph_oninv_t sddaoninvalidate;
+static void sddadone(struct cam_periph *periph,
+ union ccb *done_ccb);
+static int sddaerror(union ccb *ccb, u_int32_t cam_flags,
+ u_int32_t sense_flags);
+
+static cam_status sdda_hook_into_geom(struct cam_periph *periph);
+static void sdda_start_init(struct cam_periph *periph, union ccb *start_ccb);
+static void sdda_done_init(struct cam_periph *periph, union ccb *done_ccb);
+
+static struct periph_driver sddadriver =
+{
+ sddainit, "sdda",
+ TAILQ_HEAD_INITIALIZER(sddadriver.units), /* generation */ 0
+};
+
+PERIPHDRIVER_DECLARE(sdda, sddadriver);
+
+static MALLOC_DEFINE(M_SDDA, "sd_da", "sd_da buffers");
+
+static const int exp[8] = {
+ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
+};
+
+static const int mant[16] = {
+ 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80
+};
+
+static const int cur_min[8] = {
+ 500, 1000, 5000, 10000, 25000, 35000, 60000, 100000
+};
+
+static const int cur_max[8] = {
+ 1000, 5000, 10000, 25000, 35000, 45000, 800000, 200000
+};
+
+static uint32_t
+mmc_get_bits(uint32_t *bits, int bit_len, int start, int size)
+{
+ const int i = (bit_len / 32) - (start / 32) - 1;
+ const int shift = start & 31;
+ uint32_t retval = bits[i] >> shift;
+ if (size + shift > 32)
+ retval |= bits[i - 1] << (32 - shift);
+ return (retval & ((1llu << size) - 1));
+}
+
+
+static void
+mmc_decode_csd_sd(uint32_t *raw_csd, struct mmc_csd *csd)
+{
+ int v;
+ int m;
+ int e;
+
+ memset(csd, 0, sizeof(*csd));
+ csd->csd_structure = v = mmc_get_bits(raw_csd, 128, 126, 2);
+ if (v == 0) {
+ m = mmc_get_bits(raw_csd, 128, 115, 4);
+ e = mmc_get_bits(raw_csd, 128, 112, 3);
+ csd->tacc = (exp[e] * mant[m] + 9) / 10;
+ csd->nsac = mmc_get_bits(raw_csd, 128, 104, 8) * 100;
+ m = mmc_get_bits(raw_csd, 128, 99, 4);
+ e = mmc_get_bits(raw_csd, 128, 96, 3);
+ csd->tran_speed = exp[e] * 10000 * mant[m];
+ csd->ccc = mmc_get_bits(raw_csd, 128, 84, 12);
+ csd->read_bl_len = 1 << mmc_get_bits(raw_csd, 128, 80, 4);
+ csd->read_bl_partial = mmc_get_bits(raw_csd, 128, 79, 1);
+ csd->write_blk_misalign = mmc_get_bits(raw_csd, 128, 78, 1);
+ csd->read_blk_misalign = mmc_get_bits(raw_csd, 128, 77, 1);
+ csd->dsr_imp = mmc_get_bits(raw_csd, 128, 76, 1);
+ csd->vdd_r_curr_min = cur_min[mmc_get_bits(raw_csd, 128, 59, 3)];
+ csd->vdd_r_curr_max = cur_max[mmc_get_bits(raw_csd, 128, 56, 3)];
+ csd->vdd_w_curr_min = cur_min[mmc_get_bits(raw_csd, 128, 53, 3)];
+ csd->vdd_w_curr_max = cur_max[mmc_get_bits(raw_csd, 128, 50, 3)];
+ m = mmc_get_bits(raw_csd, 128, 62, 12);
+ e = mmc_get_bits(raw_csd, 128, 47, 3);
+ csd->capacity = ((1 + m) << (e + 2)) * csd->read_bl_len;
+ csd->erase_blk_en = mmc_get_bits(raw_csd, 128, 46, 1);
+ csd->erase_sector = mmc_get_bits(raw_csd, 128, 39, 7) + 1;
+ csd->wp_grp_size = mmc_get_bits(raw_csd, 128, 32, 7);
+ csd->wp_grp_enable = mmc_get_bits(raw_csd, 128, 31, 1);
+ csd->r2w_factor = 1 << mmc_get_bits(raw_csd, 128, 26, 3);
+ csd->write_bl_len = 1 << mmc_get_bits(raw_csd, 128, 22, 4);
+ csd->write_bl_partial = mmc_get_bits(raw_csd, 128, 21, 1);
+ } else if (v == 1) {
+ m = mmc_get_bits(raw_csd, 128, 115, 4);
+ e = mmc_get_bits(raw_csd, 128, 112, 3);
+ csd->tacc = (exp[e] * mant[m] + 9) / 10;
+ csd->nsac = mmc_get_bits(raw_csd, 128, 104, 8) * 100;
+ m = mmc_get_bits(raw_csd, 128, 99, 4);
+ e = mmc_get_bits(raw_csd, 128, 96, 3);
+ csd->tran_speed = exp[e] * 10000 * mant[m];
+ csd->ccc = mmc_get_bits(raw_csd, 128, 84, 12);
+ csd->read_bl_len = 1 << mmc_get_bits(raw_csd, 128, 80, 4);
+ csd->read_bl_partial = mmc_get_bits(raw_csd, 128, 79, 1);
+ csd->write_blk_misalign = mmc_get_bits(raw_csd, 128, 78, 1);
+ csd->read_blk_misalign = mmc_get_bits(raw_csd, 128, 77, 1);
+ csd->dsr_imp = mmc_get_bits(raw_csd, 128, 76, 1);
+ csd->capacity = ((uint64_t)mmc_get_bits(raw_csd, 128, 48, 22) + 1) *
+ 512 * 1024;
+ csd->erase_blk_en = mmc_get_bits(raw_csd, 128, 46, 1);
+ csd->erase_sector = mmc_get_bits(raw_csd, 128, 39, 7) + 1;
+ csd->wp_grp_size = mmc_get_bits(raw_csd, 128, 32, 7);
+ csd->wp_grp_enable = mmc_get_bits(raw_csd, 128, 31, 1);
+ csd->r2w_factor = 1 << mmc_get_bits(raw_csd, 128, 26, 3);
+ csd->write_bl_len = 1 << mmc_get_bits(raw_csd, 128, 22, 4);
+ csd->write_bl_partial = mmc_get_bits(raw_csd, 128, 21, 1);
+ } else
+ panic("unknown SD CSD version");
+}
+
+static void
+mmc_decode_csd_mmc(uint32_t *raw_csd, struct mmc_csd *csd)
+{
+ int m;
+ int e;
+
+ memset(csd, 0, sizeof(*csd));
+ csd->csd_structure = mmc_get_bits(raw_csd, 128, 126, 2);
+ csd->spec_vers = mmc_get_bits(raw_csd, 128, 122, 4);
+ m = mmc_get_bits(raw_csd, 128, 115, 4);
+ e = mmc_get_bits(raw_csd, 128, 112, 3);
+ csd->tacc = exp[e] * mant[m] + 9 / 10;
+ csd->nsac = mmc_get_bits(raw_csd, 128, 104, 8) * 100;
+ m = mmc_get_bits(raw_csd, 128, 99, 4);
+ e = mmc_get_bits(raw_csd, 128, 96, 3);
+ csd->tran_speed = exp[e] * 10000 * mant[m];
+ csd->ccc = mmc_get_bits(raw_csd, 128, 84, 12);
+ csd->read_bl_len = 1 << mmc_get_bits(raw_csd, 128, 80, 4);
+ csd->read_bl_partial = mmc_get_bits(raw_csd, 128, 79, 1);
+ csd->write_blk_misalign = mmc_get_bits(raw_csd, 128, 78, 1);
+ csd->read_blk_misalign = mmc_get_bits(raw_csd, 128, 77, 1);
+ csd->dsr_imp = mmc_get_bits(raw_csd, 128, 76, 1);
+ csd->vdd_r_curr_min = cur_min[mmc_get_bits(raw_csd, 128, 59, 3)];
+ csd->vdd_r_curr_max = cur_max[mmc_get_bits(raw_csd, 128, 56, 3)];
+ csd->vdd_w_curr_min = cur_min[mmc_get_bits(raw_csd, 128, 53, 3)];
+ csd->vdd_w_curr_max = cur_max[mmc_get_bits(raw_csd, 128, 50, 3)];
+ m = mmc_get_bits(raw_csd, 128, 62, 12);
+ e = mmc_get_bits(raw_csd, 128, 47, 3);
+ csd->capacity = ((1 + m) << (e + 2)) * csd->read_bl_len;
+ csd->erase_blk_en = 0;
+ csd->erase_sector = (mmc_get_bits(raw_csd, 128, 42, 5) + 1) *
+ (mmc_get_bits(raw_csd, 128, 37, 5) + 1);
+ csd->wp_grp_size = mmc_get_bits(raw_csd, 128, 32, 5);
+ csd->wp_grp_enable = mmc_get_bits(raw_csd, 128, 31, 1);
+ csd->r2w_factor = 1 << mmc_get_bits(raw_csd, 128, 26, 3);
+ csd->write_bl_len = 1 << mmc_get_bits(raw_csd, 128, 22, 4);
+ csd->write_bl_partial = mmc_get_bits(raw_csd, 128, 21, 1);
+}
+
+static void
+mmc_decode_cid_sd(uint32_t *raw_cid, struct mmc_cid *cid)
+{
+ int i;
+
+ /* There's no version info, so we take it on faith */
+ memset(cid, 0, sizeof(*cid));
+ cid->mid = mmc_get_bits(raw_cid, 128, 120, 8);
+ cid->oid = mmc_get_bits(raw_cid, 128, 104, 16);
+ for (i = 0; i < 5; i++)
+ cid->pnm[i] = mmc_get_bits(raw_cid, 128, 96 - i * 8, 8);
+ cid->pnm[5] = 0;
+ cid->prv = mmc_get_bits(raw_cid, 128, 56, 8);
+ cid->psn = mmc_get_bits(raw_cid, 128, 24, 32);
+ cid->mdt_year = mmc_get_bits(raw_cid, 128, 12, 8) + 2000;
+ cid->mdt_month = mmc_get_bits(raw_cid, 128, 8, 4);
+}
+
+static void
+mmc_decode_cid_mmc(uint32_t *raw_cid, struct mmc_cid *cid)
+{
+ int i;
+
+ /* There's no version info, so we take it on faith */
+ memset(cid, 0, sizeof(*cid));
+ cid->mid = mmc_get_bits(raw_cid, 128, 120, 8);
+ cid->oid = mmc_get_bits(raw_cid, 128, 104, 8);
+ for (i = 0; i < 6; i++)
+ cid->pnm[i] = mmc_get_bits(raw_cid, 128, 96 - i * 8, 8);
+ cid->pnm[6] = 0;
+ cid->prv = mmc_get_bits(raw_cid, 128, 48, 8);
+ cid->psn = mmc_get_bits(raw_cid, 128, 16, 32);
+ cid->mdt_month = mmc_get_bits(raw_cid, 128, 12, 4);
+ cid->mdt_year = mmc_get_bits(raw_cid, 128, 8, 4) + 1997;
+}
+
+static void
+mmc_format_card_id_string(struct sdda_softc *sc, struct mmc_params *mmcp)
+{
+ char oidstr[8];
+ uint8_t c1;
+ uint8_t c2;
+
+ /*
+ * Format a card ID string for use by the mmcsd driver, it's what
+ * appears between the <> in the following:
+ * mmcsd0: 968MB <SD SD01G 8.0 SN 2686905 Mfg 08/2008 by 3 TN> at mmc0
+ * 22.5MHz/4bit/128-block
+ *
+ * Also format just the card serial number, which the mmcsd driver will
+ * use as the disk->d_ident string.
+ *
+ * The card_id_string in mmc_ivars is currently allocated as 64 bytes,
+ * and our max formatted length is currently 55 bytes if every field
+ * contains the largest value.
+ *
+ * Sometimes the oid is two printable ascii chars; when it's not,
+ * format it as 0xnnnn instead.
+ */
+ c1 = (sc->cid.oid >> 8) & 0x0ff;
+ c2 = sc->cid.oid & 0x0ff;
+ if (c1 > 0x1f && c1 < 0x7f && c2 > 0x1f && c2 < 0x7f)
+ snprintf(oidstr, sizeof(oidstr), "%c%c", c1, c2);
+ else
+ snprintf(oidstr, sizeof(oidstr), "0x%04x", sc->cid.oid);
+ snprintf(sc->card_sn_string, sizeof(sc->card_sn_string),
+ "%08X", sc->cid.psn);
+ snprintf(sc->card_id_string, sizeof(sc->card_id_string),
+ "%s%s %s %d.%d SN %08X MFG %02d/%04d by %d %s",
+ mmcp->card_features & CARD_FEATURE_MMC ? "MMC" : "SD",
+ mmcp->card_features & CARD_FEATURE_SDHC ? "HC" : "",
+ sc->cid.pnm, sc->cid.prv >> 4, sc->cid.prv & 0x0f,
+ sc->cid.psn, sc->cid.mdt_month, sc->cid.mdt_year,
+ sc->cid.mid, oidstr);
+}
+
+static int
+sddaopen(struct disk *dp)
+{
+ struct cam_periph *periph;
+ struct sdda_softc *softc;
+ int error;
+
+ periph = (struct cam_periph *)dp->d_drv1;
+ if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
+ return(ENXIO);
+ }
+
+ cam_periph_lock(periph);
+ if ((error = cam_periph_hold(periph, PRIBIO|PCATCH)) != 0) {
+ cam_periph_unlock(periph);
+ cam_periph_release(periph);
+ return (error);
+ }
+
+ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH,
+ ("sddaopen\n"));
+
+ softc = (struct sdda_softc *)periph->softc;
+ softc->flags |= SDDA_FLAG_OPEN;
+
+ cam_periph_unhold(periph);
+ cam_periph_unlock(periph);
+ return (0);
+}
+
+static int
+sddaclose(struct disk *dp)
+{
+ struct cam_periph *periph;
+ struct sdda_softc *softc;
+// union ccb *ccb;
+// int error;
+
+ periph = (struct cam_periph *)dp->d_drv1;
+ softc = (struct sdda_softc *)periph->softc;
+ softc->flags &= ~SDDA_FLAG_OPEN;
+
+ cam_periph_lock(periph);
+
+ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH,
+ ("sddaclose\n"));
+
+ while (softc->refcount != 0)
+ cam_periph_sleep(periph, &softc->refcount, PRIBIO, "sddaclose", 1);
+ cam_periph_unlock(periph);
+ cam_periph_release(periph);
+ return (0);
+}
+
+static void
+sddaschedule(struct cam_periph *periph)
+{
+ struct sdda_softc *softc = (struct sdda_softc *)periph->softc;
+
+ /* Check if we have more work to do. */
+ if (bioq_first(&softc->bio_queue)) {
+ xpt_schedule(periph, CAM_PRIORITY_NORMAL);
+ }
+}
+
+/*
+ * Actually translate the requested transfer into one the physical driver
+ * can understand. The transfer is described by a buf and will include
+ * only one physical transfer.
+ */
+static void
+sddastrategy(struct bio *bp)
+{
+ struct cam_periph *periph;
+ struct sdda_softc *softc;
+
+ periph = (struct cam_periph *)bp->bio_disk->d_drv1;
+ softc = (struct sdda_softc *)periph->softc;
+
+ cam_periph_lock(periph);
+
+ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sddastrategy(%p)\n", bp));
+
+ /*
+ * If the device has been made invalid, error out
+ */
+ if ((periph->flags & CAM_PERIPH_INVALID) != 0) {
+ cam_periph_unlock(periph);
+ biofinish(bp, NULL, ENXIO);
+ return;
+ }
+
+ /*
+ * Place it in the queue of disk activities for this disk
+ */
+ bioq_disksort(&softc->bio_queue, bp);
+
+ /*
+ * Schedule ourselves for performing the work.
+ */
+ sddaschedule(periph);
+ cam_periph_unlock(periph);
+
+ return;
+}
+
+static void
+sddainit(void)
+{
+ cam_status status;
+
+ /*
+ * Install a global async callback. This callback will
+ * receive async callbacks like "new device found".
+ */
+ status = xpt_register_async(AC_FOUND_DEVICE, sddaasync, NULL, NULL);
+
+ if (status != CAM_REQ_CMP) {
+ printf("sdda: Failed to attach master async callback "
+ "due to status 0x%x!\n", status);
+ }
+}
+
+/*
+ * Callback from GEOM, called when it has finished cleaning up its
+ * resources.
+ */
+static void
+sddadiskgonecb(struct disk *dp)
+{
+ struct cam_periph *periph;
+
+ periph = (struct cam_periph *)dp->d_drv1;
+ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sddadiskgonecb\n"));
+
+ cam_periph_release(periph);
+}
+
+static void
+sddaoninvalidate(struct cam_periph *periph)
+{
+ struct sdda_softc *softc;
+
+ softc = (struct sdda_softc *)periph->softc;
+
+ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sddaoninvalidate\n"));
+
+ /*
+ * De-register any async callbacks.
+ */
+ xpt_register_async(0, sddaasync, periph, periph->path);
+
+ /*
+ * Return all queued I/O with ENXIO.
+ * XXX Handle any transactions queued to the card
+ * with XPT_ABORT_CCB.
+ */
+ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("bioq_flush start\n"));
+ bioq_flush(&softc->bio_queue, NULL, ENXIO);
+ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("bioq_flush end\n"));
+
+ disk_gone(softc->disk);
+}
+
+static void
+sddacleanup(struct cam_periph *periph)
+{
+ struct sdda_softc *softc;
+
+ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sddacleanup\n"));
+ softc = (struct sdda_softc *)periph->softc;
+
+ cam_periph_unlock(periph);
+
+ disk_destroy(softc->disk);
+ free(softc, M_DEVBUF);
+ cam_periph_lock(periph);
+}
+
+static void
+sddaasync(void *callback_arg, u_int32_t code,
+ struct cam_path *path, void *arg)
+{
+ struct ccb_getdev cgd;
+ struct cam_periph *periph;
+ struct sdda_softc *softc;
+
+ periph = (struct cam_periph *)callback_arg;
+ CAM_DEBUG(path, CAM_DEBUG_TRACE, ("sddaasync(code=%d)\n", code));
+ switch (code) {
+ case AC_FOUND_DEVICE:
+ {
+ CAM_DEBUG(path, CAM_DEBUG_TRACE, ("=> AC_FOUND_DEVICE\n"));
+ struct ccb_getdev *cgd;
+ cam_status status;
+
+ cgd = (struct ccb_getdev *)arg;
+ if (cgd == NULL)
+ break;
+
+ if (cgd->protocol != PROTO_MMCSD)
+ break;
+
+ if (!(path->device->mmc_ident_data.card_features & CARD_FEATURE_MEMORY)) {
+ CAM_DEBUG(path, CAM_DEBUG_TRACE, ("No memory on the card!\n"));
+ break;
+ }
+
+ /*
+ * Allocate a peripheral instance for
+ * this device and start the probe
+ * process.
+ */
+ status = cam_periph_alloc(sddaregister, sddaoninvalidate,
+ sddacleanup, sddastart,
+ "sdda", CAM_PERIPH_BIO,
+ path, sddaasync,
+ AC_FOUND_DEVICE, cgd);
+
+ if (status != CAM_REQ_CMP
+ && status != CAM_REQ_INPROG)
+ printf("sddaasync: Unable to attach to new device "
+ "due to status 0x%x\n", status);
+ break;
+ }
+ case AC_GETDEV_CHANGED:
+ {
+ CAM_DEBUG(path, CAM_DEBUG_TRACE, ("=> AC_GETDEV_CHANGED\n"));
+ softc = (struct sdda_softc *)periph->softc;
+ xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
+ cgd.ccb_h.func_code = XPT_GDEV_TYPE;
+ xpt_action((union ccb *)&cgd);
+
+ /*
+ if ((cgd.ident_data.capabilities1 & ATA_SUPPORT_DMA) &&
+ (cgd.inq_flags & SID_DMA))
+ softc->flags |= SDDA_FLAG_CAN_DMA;
+ else
+ softc->flags &= ~SDDA_FLAG_CAN_DMA;
+ if (cgd.ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) {
+ softc->flags |= SDDA_FLAG_CAN_48BIT;
+ if (cgd.inq_flags & SID_DMA48)
+ softc->flags |= SDDA_FLAG_CAN_DMA48;
+ else
+ softc->flags &= ~SDDA_FLAG_CAN_DMA48;
+ } else
+ softc->flags &= ~(SDDA_FLAG_CAN_48BIT |
+ SDDA_FLAG_CAN_DMA48);
+ if ((cgd.ident_data.satacapabilities & ATA_SUPPORT_NCQ) &&
+ (cgd.inq_flags & SID_DMA) && (cgd.inq_flags & SID_CmdQue))
+ softc->flags |= SDDA_FLAG_CAN_NCQ;
+ else
+ softc->flags &= ~SDDA_FLAG_CAN_NCQ;
+ if ((cgd.ident_data.support_dsm & ATA_SUPPORT_DSM_TRIM) &&
+ (cgd.inq_flags & SID_DMA))
+ softc->flags |= SDDA_FLAG_CAN_TRIM;
+ else
+ softc->flags &= ~SDDA_FLAG_CAN_TRIM;
+ */
+ cam_periph_async(periph, code, path, arg);
+ break;
+ }
+ case AC_ADVINFO_CHANGED:
+ {
+ uintptr_t buftype;
+ CAM_DEBUG(path, CAM_DEBUG_TRACE, ("=> AC_ADVINFO_CHANGED\n"));
+ buftype = (uintptr_t)arg;
+ if (buftype == CDAI_TYPE_PHYS_PATH) {
+ struct sdda_softc *softc;
+
+ softc = periph->softc;
+ disk_attr_changed(softc->disk, "GEOM::physpath",
+ M_NOWAIT);
+ }
+ break;
+ }
+ case AC_SENT_BDR:
+ case AC_BUS_RESET:
+ {
+ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("AC_BUS_RESET"));
+/* softc = (struct sdda_softc *)periph->softc;
+ cam_periph_async(periph, code, path, arg);
+ if (softc->state != SDDA_STATE_NORMAL)
+ break;
+ xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
+ cgd.ccb_h.func_code = XPT_GDEV_TYPE;
+ xpt_action((union ccb *)&cgd);
+ if (SDDA_RA >= 0 &&
+ cgd.ident_data.support.command1 & ATA_SUPPORT_LOOKAHEAD)
+ softc->state = SDDA_STATE_RAHEAD;
+ else if (SDDA_WC >= 0 &&
+ cgd.ident_data.support.command1 & ATA_SUPPORT_WRITECACHE)
+ softc->state = SDDA_STATE_WCACHE;
+ else
+ break;
+ if (cam_periph_acquire(periph) != CAM_REQ_CMP)
+ softc->state = SDDA_STATE_NORMAL;
+ else
+ xpt_schedule(periph, CAM_PRIORITY_DEV);
+*/
+ }
+ default:
+ CAM_DEBUG(path, CAM_DEBUG_TRACE, ("=> default?!\n"));
+ cam_periph_async(periph, code, path, arg);
+ break;
+ }
+}
+
+
+static int
+sddagetattr(struct bio *bp)
+{
+ int ret;
+ struct cam_periph *periph;
+
+ periph = (struct cam_periph *)bp->bio_disk->d_drv1;
+ cam_periph_lock(periph);
+ ret = xpt_getattr(bp->bio_data, bp->bio_length, bp->bio_attribute,
+ periph->path);
+ cam_periph_unlock(periph);
+ if (ret == 0)
+ bp->bio_completed = bp->bio_length;
+ return ret;
+}
+
+static cam_status
+sddaregister(struct cam_periph *periph, void *arg)
+{
+ struct sdda_softc *softc;
+// struct ccb_pathinq cpi;
+ struct ccb_getdev *cgd;
+// char announce_buf[80], buf1[32];
+// caddr_t match;
+ union ccb *request_ccb; /* CCB representing the probe request */
+
+ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sddaregister\n"));
+ cgd = (struct ccb_getdev *)arg;
+ if (cgd == NULL) {
+ printf("sddaregister: no getdev CCB, can't register device\n");
+ return(CAM_REQ_CMP_ERR);
+ }
+
+ softc = (struct sdda_softc *)malloc(sizeof(*softc), M_DEVBUF,
+ M_NOWAIT|M_ZERO);
+
+ if (softc == NULL) {
+ printf("sddaregister: Unable to probe new device. "
+ "Unable to allocate softc\n");
+ return(CAM_REQ_CMP_ERR);
+ }
+
+ bioq_init(&softc->bio_queue);
+ softc->state = SDDA_STATE_INIT;
+
+/*
+ if ((cgd->ident_data.capabilities1 & ATA_SUPPORT_DMA) &&
+ (cgd->inq_flags & SID_DMA))
+ softc->flags |= SDDA_FLAG_CAN_DMA;
+ if (cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) {
+ softc->flags |= SDDA_FLAG_CAN_48BIT;
+ if (cgd->inq_flags & SID_DMA48)
+ softc->flags |= SDDA_FLAG_CAN_DMA48;
+ }
+ if (cgd->ident_data.support.command2 & ATA_SUPPORT_FLUSHCACHE)
+ softc->flags |= SDDA_FLAG_CAN_FLUSHCACHE;
+ if (cgd->ident_data.support.command1 & ATA_SUPPORT_POWERMGT)
+ softc->flags |= SDDA_FLAG_CAN_POWERMGT;
+ if ((cgd->ident_data.satacapabilities & ATA_SUPPORT_NCQ) &&
+ (cgd->inq_flags & SID_DMA) && (cgd->inq_flags & SID_CmdQue))
+ softc->flags |= SDDA_FLAG_CAN_NCQ;
+ if (cgd->ident_data.support.command2 & ATA_SUPPORT_CFA)
+ softc->flags |= SDDA_FLAG_CAN_CFA;
+*/
+ periph->softc = softc;
+
+ request_ccb = (union ccb*) arg;
+ if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
+ xpt_print(periph->path, "%s: lost periph during "
+ "registration!\n", __func__);
+ cam_periph_lock(periph);
+ return (CAM_REQ_CMP_ERR);
+ }
+ sdda_start_init(periph, request_ccb);
+ xpt_schedule(periph, CAM_PRIORITY_XPT);
+ return (CAM_REQ_CMP);
+
+ /* NOTREACHED */
+}
+
+static cam_status
+sdda_hook_into_geom(struct cam_periph *periph)
+{
+ struct sdda_softc *softc;
+ struct ccb_pathinq cpi;
+ struct ccb_getdev cgd;
+ u_int maxio;
+
+ softc = (struct sdda_softc*) periph->softc;
+
+ bzero(&cpi, sizeof(cpi));
+ xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NONE);
+ cpi.ccb_h.func_code = XPT_PATH_INQ;
+ xpt_action((union ccb *)&cpi);
+
+ bzero(&cgd, sizeof(cgd));
+ xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NONE);
+ cpi.ccb_h.func_code = XPT_GDEV_TYPE;
+ xpt_action((union ccb *)&cgd);
+
+ /*
+ * Register this media as a disk
+ */
+ (void)cam_periph_hold(periph, PRIBIO);
+ cam_periph_unlock(periph);
+
+ softc->disk = disk_alloc();
+ softc->disk->d_rotation_rate = 0;
+ softc->disk->d_devstat = devstat_new_entry(periph->periph_name,
+ periph->unit_number, 512,
+ DEVSTAT_ALL_SUPPORTED,
+ DEVSTAT_TYPE_DIRECT |
+ XPORT_DEVSTAT_TYPE(cpi.transport),
+ DEVSTAT_PRIORITY_DISK);
+ softc->disk->d_open = sddaopen;
+ softc->disk->d_close = sddaclose;
+ softc->disk->d_strategy = sddastrategy;
+ softc->disk->d_getattr = sddagetattr;
+// softc->disk->d_dump = sddadump;
+ softc->disk->d_gone = sddadiskgonecb;
+ softc->disk->d_name = "sdda";
+ softc->disk->d_drv1 = periph;
+ maxio = cpi.maxio; /* Honor max I/O size of SIM */
+ if (maxio == 0)
+ maxio = DFLTPHYS; /* traditional default */
+ else if (maxio > MAXPHYS)
+ maxio = MAXPHYS; /* for safety */
+ softc->disk->d_maxsize = maxio;
+ softc->disk->d_unit = periph->unit_number;
+ softc->disk->d_flags = DISKFLAG_CANDELETE;
+ strlcpy(softc->disk->d_descr, softc->card_id_string,
+ MIN(sizeof(softc->disk->d_descr), sizeof(softc->card_id_string)));
+ strlcpy(softc->disk->d_ident, softc->card_sn_string,
+ MIN(sizeof(softc->disk->d_ident), sizeof(softc->card_sn_string)));
+ softc->disk->d_hba_vendor = cpi.hba_vendor;
+ softc->disk->d_hba_device = cpi.hba_device;
+ softc->disk->d_hba_subvendor = cpi.hba_subvendor;
+ softc->disk->d_hba_subdevice = cpi.hba_subdevice;
+
+ softc->disk->d_sectorsize = 512;
+ softc->disk->d_mediasize = softc->mediasize;
+ softc->disk->d_stripesize = 0;
+ softc->disk->d_fwsectors = 0;
+ softc->disk->d_fwheads = 0;
+
+ /*
+ * Acquire a reference to the periph before we register with GEOM.
+ * We'll release this reference once GEOM calls us back (via
+ * sddadiskgonecb()) telling us that our provider has been freed.
+ */
+ if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
+ xpt_print(periph->path, "%s: lost periph during "
+ "registration!\n", __func__);
+ cam_periph_lock(periph);
+ return (CAM_REQ_CMP_ERR);
+ }
+ disk_create(softc->disk, DISK_VERSION);
+ cam_periph_lock(periph);
+ cam_periph_unhold(periph);
+
+ xpt_announce_periph(periph, softc->card_id_string);
+
+ if (cam_periph_acquire(periph) == CAM_REQ_CMP)
+ printf("Acquired periph Ok\n");
+ /*
+ * Add async callbacks for bus reset and
+ * bus device reset calls. I don't bother
+ * checking if this fails as, in most cases,
+ * the system will function just fine without
+ * them and the only alternative would be to
+ * not attach the device on failure.
+ */
+ xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE |
+ AC_GETDEV_CHANGED | AC_ADVINFO_CHANGED,
+ sddaasync, periph, periph->path);
+
+// if (cam_periph_acquire(periph) != CAM_REQ_CMP)
+// printf("wtf?!");
+// else
+// xpt_schedule(periph, CAM_PRIORITY_DEV);
+ return(CAM_REQ_CMP);
+}
+
+static void
+sdda_start_init(struct cam_periph *periph, union ccb *start_ccb) {
+ struct sdda_softc *softc = (struct sdda_softc *)periph->softc;
+ //struct ccb_mmcio *mmcio = &start_ccb->mmcio;
+ struct mmc_params *mmcp = &periph->path->device->mmc_ident_data;
+ struct cam_ed *device = periph->path->device;
+
+ if (mmcp->card_features & CARD_FEATURE_MMC) {
+ mmc_decode_csd_mmc(mmcp->card_csd, &softc->csd);
+ mmc_decode_cid_mmc(mmcp->card_cid, &softc->cid);
+ } else {
+ mmc_decode_csd_sd(mmcp->card_csd, &softc->csd);
+ mmc_decode_cid_sd(mmcp->card_cid, &softc->cid);
+ }
+ mmc_format_card_id_string(softc, mmcp);
+
+
+ CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PERIPH,
+ ("Capacity: %"PRIu64", sectors: %"PRIu64"\n",
+ softc->csd.capacity,
+ softc->csd.capacity / 512));
+ softc->state = SDDA_STATE_NORMAL;
+
+ softc->sector_count = softc->csd.capacity / 512;
+ softc->mediasize = softc->csd.capacity;
+
+ /* Update info for CAM */
+ device->serial_num_len = strlen(softc->card_sn_string);
+ device->serial_num =
+ (u_int8_t *)malloc((device->serial_num_len + 1),
+ M_CAMXPT, M_NOWAIT);
+ strlcpy(device->serial_num, softc->card_sn_string, device->serial_num_len);
+
+ device->device_id_len = strlen(softc->card_id_string);
+ device->device_id =
+ (u_int8_t *)malloc((device->device_id_len + 1),
+ M_CAMXPT, M_NOWAIT);
+ strlcpy(device->device_id, softc->card_id_string, device->device_id_len);
+
+ strlcpy(mmcp->model, softc->card_id_string, sizeof(mmcp->model));
+ sdda_hook_into_geom(periph);
+ return;
+
+/* switch (softc->state) {
+ case SDDA_STATE_INIT:
+ {
+ start_ccb->ccb_h.func_code = XPT_MMC_IO;
+ start_ccb->ccb_h.flags = CAM_DIR_IN;
+ start_ccb->ccb_h.retry_count = 0;
+ start_ccb->ccb_h.timeout = 15 * 1000;
+ start_ccb->ccb_h.cbfcnp = sdda_done_init;
+
+ mmcio->cmd.opcode = MMC_SEND_CSD;
+ mmcio->cmd.arg = mmcp->card_rca << 16;
+ mmcio->cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
+ mmcio->cmd.data = NULL;
+ break;
+ }
+ case SDDA_STATE_INVALID:
+ return;
+ default:
+ panic("Wrong state in sdda_start_init");
+ }
+
+ start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
+ xpt_action(start_ccb);
+*/
+}
+
+/*static void
+sdda_done_init(struct cam_periph *periph, union ccb *done_ccb) {
+ struct sdda_softc *softc = (struct sdda_softc *)periph->softc;
+ struct ccb_mmcio *mmcio = &done_ccb->mmcio;
+// struct mmc_params *mmcp = &periph->path->device->mmc_ident_data;
+ struct cam_path *path = done_ccb->ccb_h.path;
+ int err = mmcio->cmd.error;
+ int priority = done_ccb->ccb_h.pinfo.priority;
+
+ switch (softc->state) {
+ case SDDA_STATE_INIT:
+ {
+ if (err != MMC_ERR_NONE) {
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PERIPH,
+ ("Failed to get CSD\n"));
+ break;
+ }
+ memcpy(softc->raw_csd, mmcio->cmd.resp, 4 * sizeof(uint32_t));
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PERIPH,
+ ("CSD: %08x %08x %08x %08x\n",
+ softc->raw_csd[0],
+ softc->raw_csd[1],
+ softc->raw_csd[2],
+ softc->raw_csd[3]));
+ mmc_decode_csd_sd(softc->raw_csd, &softc->csd);
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PERIPH,
+ ("Capacity: %llu, sectors: %llu\n",
+ softc->csd.capacity,
+ softc->csd.capacity / 512));
+ softc->state = SDDA_STATE_INVALID;
+ break;
+ }
+ default:
+ panic("Wrong state in sdda_done_init");
+ }
+
+ xpt_release_ccb(done_ccb);
+ xpt_schedule(periph, priority);
+ cam_release_devq(path, 0, 0, 0, FALSE);
+}
+*/
+/* Called with periph lock held! */
+static void
+sddastart(struct cam_periph *periph, union ccb *start_ccb)
+{
+ struct sdda_softc *softc = (struct sdda_softc *)periph->softc;
+ struct mmc_params *mmcp = &periph->path->device->mmc_ident_data;
+
+ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sddastart\n"));
+
+ if (softc->state != SDDA_STATE_NORMAL) {
+ sdda_start_init(periph, start_ccb);
+ return;
+ }
+ struct bio *bp;
+
+ /* Run regular command. */
+ bp = bioq_first(&softc->bio_queue);
+ if (bp == NULL) {
+ xpt_release_ccb(start_ccb);
+ return;
+ }
+ bioq_remove(&softc->bio_queue, bp);
+
+ switch (bp->bio_cmd) {
+ case BIO_WRITE:
+ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("BIO_WRITE\n"));
+ softc->flags |= SDDA_FLAG_DIRTY;
+ /* FALLTHROUGH */
+ case BIO_READ:
+ {
+ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("BIO_READ\n"));
+ uint64_t blockno = bp->bio_pblkno;
+ uint16_t count = bp->bio_bcount / 512;
+ uint16_t opcode;
+
+ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("Block %"PRIu64" cnt %u\n", blockno, count));
+
+ /* Construct new MMC command */
+ if (bp->bio_cmd == BIO_READ) {
+ if (count > 1)
+ opcode = MMC_READ_MULTIPLE_BLOCK;
+ else
+ opcode = MMC_READ_SINGLE_BLOCK;
+ } else {
+ if (count > 1)
+ opcode = MMC_WRITE_MULTIPLE_BLOCK;
+ else
+ opcode = MMC_WRITE_BLOCK;
+ }
+
+ start_ccb->ccb_h.func_code = XPT_MMC_IO;
+ start_ccb->ccb_h.flags = (bp->bio_cmd == BIO_READ ? CAM_DIR_IN : CAM_DIR_OUT);
+ start_ccb->ccb_h.retry_count = 0;
+ start_ccb->ccb_h.timeout = 15 * 1000;
+ start_ccb->ccb_h.cbfcnp = sddadone;
+ struct ccb_mmcio *mmcio;
+
+ mmcio = &start_ccb->mmcio;
+ mmcio->cmd.opcode = opcode;
+ mmcio->cmd.arg = blockno;
+ if (!(mmcp->card_features & CARD_FEATURE_SDHC))
+ mmcio->cmd.arg <<= 9;
+
+ mmcio->cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+ mmcio->cmd.data.data = bp->bio_data;
+ mmcio->cmd.data.len = 512 * count;
+ mmcio->cmd.data.flags = (bp->bio_cmd == BIO_READ ? MMC_DATA_READ : MMC_DATA_WRITE);
+ /* Direct h/w to issue CMD12 upon completion */
+ if (count > 1) {
+ mmcio->stop.opcode = MMC_STOP_TRANSMISSION;
+ mmcio->stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
+ mmcio->stop.arg = 0;
+ }
+
+ break;
+ }
+ case BIO_FLUSH:
+ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("BIO_FLUSH\n"));
+ sddaschedule(periph);
+ break;
+ case BIO_DELETE:
+ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("BIO_DELETE\n"));
+ sddaschedule(periph);
+ break;
+ }
+
+ start_ccb->ccb_h.ccb_bp = bp;
+ softc->outstanding_cmds++;
+ softc->refcount++;
+ cam_periph_unlock(periph);
+ xpt_action(start_ccb);
+ cam_periph_lock(periph);
+ softc->refcount--;
+
+ /* May have more work to do, so ensure we stay scheduled */
+ sddaschedule(periph);
+}
+
+static void
+sddadone(struct cam_periph *periph, union ccb *done_ccb)
+{
+ struct sdda_softc *softc;
+ struct ccb_mmcio *mmcio;
+// struct ccb_getdev *cgd;
+ struct cam_path *path;
+// int state;
+
+ softc = (struct sdda_softc *)periph->softc;
+ mmcio = &done_ccb->mmcio;
+ path = done_ccb->ccb_h.path;
+
+ CAM_DEBUG(path, CAM_DEBUG_TRACE, ("sddadone\n"));
+
+ struct bio *bp;
+ int error = 0;
+
+// cam_periph_lock(periph);
+ if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+ CAM_DEBUG(path, CAM_DEBUG_TRACE, ("Error!!!\n"));
+ if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
+ cam_release_devq(path,
+ /*relsim_flags*/0,
+ /*reduction*/0,
+ /*timeout*/0,
+ /*getcount_only*/0);
+ error = 5; /* EIO */
+ } else {
+ if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
+ panic("REQ_CMP with QFRZN");
+ error = 0;
+ }
+
+
+ bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
+ bp->bio_error = error;
+ if (error != 0) {
+ bp->bio_resid = bp->bio_bcount;
+ bp->bio_flags |= BIO_ERROR;
+ } else {
+ /* XXX: How many bytes remaining? */
+ bp->bio_resid = 0;
+ if (bp->bio_resid > 0)
+ bp->bio_flags |= BIO_ERROR;
+ }
+
+ uint32_t card_status = mmcio->cmd.resp[0];
+ CAM_DEBUG(path, CAM_DEBUG_TRACE,
+ ("Card status: %08x\n", R1_STATUS(card_status)));
+ CAM_DEBUG(path, CAM_DEBUG_TRACE,
+ ("Current state: %d\n", R1_CURRENT_STATE(card_status)));
+
+ softc->outstanding_cmds--;
+ xpt_release_ccb(done_ccb);
+// cam_periph_unlock(periph);
+ biodone(bp);
+}
+
+static int
+sddaerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
+{
+ return(cam_periph_error(ccb, cam_flags, sense_flags, NULL));
+}
+
+/*
+ * Step through all SDDA peripheral drivers, and if the device is still open,
+ * sync the disk cache to physical media.
+ */
+static void
+sddaflush(void)
+{
+ struct cam_periph *periph;
+// struct sdda_softc *softc;
+// union ccb *ccb;
+// int error;
+
+ CAM_PERIPH_FOREACH(periph, &sddadriver) {
+ cam_periph_lock(periph);
+ xpt_print(periph->path, "flush\n");
+ cam_periph_unlock(periph);
+ }
+}
+
+static void
+sddaspindown(uint8_t cmd, int flags)
+{
+ struct cam_periph *periph;
+
+ CAM_PERIPH_FOREACH(periph, &sddadriver) {
+ cam_periph_lock(periph);
+ xpt_print(periph->path, "spin-down\n");
+ cam_periph_unlock(periph);
+ }
+}
+
+#endif /* _KERNEL */
Index: sys/cam/mmc/mmc_sdio.h
===================================================================
--- /dev/null
+++ sys/cam/mmc/mmc_sdio.h
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 2014 Ilya Bakulin. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Portions of this software may have been developed with reference to
+ * the SD Simplified Specification. The following disclaimer may apply:
+ *
+ * The following conditions apply to the release of the simplified
+ * specification ("Simplified Specification") by the SD Card Association and
+ * the SD Group. The Simplified Specification is a subset of the complete SD
+ * Specification which is owned by the SD Card Association and the SD
+ * Group. This Simplified Specification is provided on a non-confidential
+ * basis subject to the disclaimers below. Any implementation of the
+ * Simplified Specification may require a license from the SD Card
+ * Association, SD Group, SD-3C LLC or other third parties.
+ *
+ * Disclaimers:
+ *
+ * The information contained in the Simplified Specification is presented only
+ * as a standard specification for SD Cards and SD Host/Ancillary products and
+ * is provided "AS-IS" without any representations or warranties of any
+ * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD
+ * Card Association for any damages, any infringements of patents or other
+ * right of the SD Group, SD-3C LLC, the SD Card Association or any third
+ * parties, which may result from its use. No license is granted by
+ * implication, estoppel or otherwise under any patent or other rights of the
+ * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing
+ * herein shall be construed as an obligation by the SD Group, the SD-3C LLC
+ * or the SD Card Association to disclose or distribute any technical
+ * information, know-how or other confidential information to any third party.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Various SDIO-related stuff
+ */
+
+#ifndef CAM_MMC_SDIO_H
+#define CAM_MMC_SDIO_H
+
+void sdio_print_stupid_message(struct cam_periph *periph);
+void sdio_fill_mmcio_rw_direct(union ccb *ccb, uint8_t f, uint8_t wr, uint32_t adr, uint8_t *data);
+uint8_t sdio_parse_mmcio_rw_direct(union ccb *ccb, uint8_t *data);
+#endif
Index: sys/cam/mmc/mmc_sdio.c
===================================================================
--- /dev/null
+++ sys/cam/mmc/mmc_sdio.c
@@ -0,0 +1,126 @@
+/*-
+ * Copyright (c) 2015 Ilya Bakulin <ilya@bakulin.de>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/time.h>
+#include <sys/conf.h>
+#include <sys/fcntl.h>
+#include <sys/interrupt.h>
+#include <sys/sbuf.h>
+
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sysctl.h>
+#include <sys/condvar.h>
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_queue.h>
+#include <cam/cam_periph.h>
+#include <cam/cam_sim.h>
+#include <cam/cam_xpt.h>
+#include <cam/cam_xpt_sim.h>
+#include <cam/cam_xpt_periph.h>
+#include <cam/cam_xpt_internal.h>
+#include <cam/cam_debug.h>
+
+#include <cam/mmc/mmc.h>
+#include <cam/mmc/mmc_bus.h>
+#include <cam/mmc/mmc_sdio.h>
+
+#include <machine/stdarg.h> /* for xpt_print below */
+#include <machine/_inttypes.h> /* for PRIu64 */
+#include "opt_cam.h"
+
+
+void
+sdio_print_stupid_message(struct cam_periph *periph) {
+
+ CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
+ ("%s\n", __func__));
+}
+
+/*
+ * f - function to read from / write to
+ * wr - is write
+ * adr - address to r/w
+ * data - actual data to write
+ */
+void sdio_fill_mmcio_rw_direct(union ccb *ccb, uint8_t f, uint8_t wr, uint32_t adr, uint8_t *data) {
+ struct ccb_mmcio *mmcio;
+
+ CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
+ ("sdio_fill_mmcio(f=%d, wr=%d, adr=%02x, data=%02x)\n", f, wr, adr, (data == NULL ? 0 : *data)));
+ mmcio = &ccb->mmcio;
+
+ mmcio->cmd.opcode = SD_IO_RW_DIRECT;
+ mmcio->cmd.arg = SD_IO_RW_FUNC(f) | SD_IO_RW_ADR(adr);
+ if (wr)
+ mmcio->cmd.arg |= SD_IO_RW_WR | SD_IO_RW_RAW | SD_IO_RW_DAT(*data);
+ mmcio->cmd.flags = MMC_RSP_R5 | MMC_CMD_AC;
+ mmcio->cmd.data.len = 0;
+}
+
+uint8_t sdio_parse_mmcio_rw_direct(union ccb *ccb, uint8_t *data) {
+ struct ccb_mmcio *mmcio;
+
+ CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
+ ("sdio_parse_mmcio(datap=%p)\n", data));
+ mmcio = &ccb->mmcio;
+
+ if (mmcio->cmd.error)
+ return (mmcio->cmd.error);
+ if (mmcio->cmd.resp[0] & R5_COM_CRC_ERROR)
+ return (MMC_ERR_BADCRC);
+ if (mmcio->cmd.resp[0] & (R5_ILLEGAL_COMMAND | R5_FUNCTION_NUMBER))
+ return (MMC_ERR_INVALID);
+ if (mmcio->cmd.resp[0] & R5_OUT_OF_RANGE)
+ return (MMC_ERR_FAILED);
+
+ /* Just for information... */
+ if (R5_IO_CURRENT_STATE(mmcio->cmd.resp[0]) != 1)
+ printf("!!! SDIO state %d\n", R5_IO_CURRENT_STATE(mmcio->cmd.resp[0]));
+
+ if (mmcio->cmd.resp[0] & R5_ERROR)
+ printf("An error was detected!\n");
+
+ if (mmcio->cmd.resp[0] & R5_COM_CRC_ERROR)
+ printf("A CRC error was detected!\n");
+
+ if (data != NULL)
+ *data = (uint8_t) (mmcio->cmd.resp[0] & 0xff);
+ return (MMC_ERR_NONE);
+
+}
Index: sys/cam/mmc/mmc_xpt.c
===================================================================
--- /dev/null
+++ sys/cam/mmc/mmc_xpt.c
@@ -0,0 +1,1240 @@
+/*-
+ * Copyright (c) 2013,2014 Ilya Bakulin <ilya@bakulin.de>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/time.h>
+#include <sys/conf.h>
+#include <sys/fcntl.h>
+#include <sys/interrupt.h>
+#include <sys/sbuf.h>
+
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sysctl.h>
+#include <sys/condvar.h>
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_queue.h>
+#include <cam/cam_periph.h>
+#include <cam/cam_sim.h>
+#include <cam/cam_xpt.h>
+#include <cam/cam_xpt_sim.h>
+#include <cam/cam_xpt_periph.h>
+#include <cam/cam_xpt_internal.h>
+#include <cam/cam_debug.h>
+
+#include <cam/mmc/mmc.h>
+#include <cam/mmc/mmc_bus.h>
+#include <cam/mmc/mmc_sdio.h>
+
+#include <machine/stdarg.h> /* for xpt_print below */
+#include <machine/_inttypes.h> /* for PRIu64 */
+#include "opt_cam.h"
+
+struct xpt_xport *mmc_get_xport(void);
+static struct cam_ed * mmc_alloc_device(struct cam_eb *bus,
+ struct cam_et *target,
+ lun_id_t lun_id);
+static void mmc_dev_async(u_int32_t async_code,
+ struct cam_eb *bus,
+ struct cam_et *target,
+ struct cam_ed *device,
+ void *async_arg);
+static void mmc_action(union ccb *start_ccb);
+static void mmc_dev_advinfo(union ccb *start_ccb);
+static void mmc_announce_periph(struct cam_periph *periph);
+static void mmc_scan_lun(struct cam_periph *periph,
+ struct cam_path *path, cam_flags flags,
+ union ccb *ccb);
+
+/* mmcprobe methods */
+static cam_status mmcprobe_register(struct cam_periph *periph,
+ void *arg);
+static void mmcprobe_start(struct cam_periph *periph, union ccb *start_ccb);
+static void mmcprobe_cleanup(struct cam_periph *periph);
+static void mmcprobe_done(struct cam_periph *periph, union ccb *done_ccb);
+
+static const char * get_action_desc(int action);
+
+typedef enum {
+ PROBE_RESET,
+ PROBE_IDENTIFY,
+ PROBE_SDIO_RESET,
+ PROBE_SEND_IF_COND,
+ PROBE_SDIO_INIT,
+ PROBE_MMC_INIT,
+ PROBE_SEND_APP_OP_COND,
+ PROBE_GET_CID,
+ PROBE_GET_CSD,
+ PROBE_SEND_RELATIVE_ADDR,
+ PROBE_SELECT_CARD,
+ PROBE_SET_BUS_WIDTH,
+ PROBE_SET_BUS_WIDTH_HOST,
+ PROBE_DONE,
+ PROBE_INVALID
+} probe_action;
+
+static char *probe_action_text[] = {
+ "PROBE_RESET",
+ "PROBE_IDENTIFY",
+ "PROBE_SDIO_RESET",
+ "PROBE_SEND_IF_COND",
+ "PROBE_SDIO_INIT",
+ "PROBE_MMC_INIT",
+ "PROBE_SEND_APP_OP_COND",
+ "PROBE_GET_CID",
+ "PROBE_GET_CSD",
+ "PROBE_SEND_RELATIVE_ADDR",
+ "PROBE_SELECT_CARD",
+ "PROBE_SET_BUS_WIDTH",
+ "PROBE_SET_BUS_WIDTH_HOST",
+ "PROBE_DONE",
+ "PROBE_INVALID"
+};
+
+#define PROBE_SET_ACTION(softc, newaction) \
+do { \
+ char **text; \
+ text = probe_action_text; \
+ CAM_DEBUG((softc)->periph->path, CAM_DEBUG_PROBE, \
+ ("Probe %s to %s\n", text[(softc)->action], \
+ text[(newaction)])); \
+ (softc)->action = (newaction); \
+} while(0)
+
+static struct xpt_xport mmc_xport = {
+ .alloc_device = mmc_alloc_device,
+ .action = mmc_action,
+ .async = mmc_dev_async,
+ .announce = mmc_announce_periph,
+};
+
+typedef struct {
+ probe_action action;
+ int restart;
+ union ccb saved_ccb;
+ uint32_t flags;
+#define PROBE_FLAG_ACMD_SENT 0x1 /* CMD55 is sent, card expects ACMD */
+ struct cam_periph *periph;
+} mmcprobe_softc;
+
+struct xpt_xport *
+mmc_get_xport(void)
+{
+ return (&mmc_xport);
+}
+
+/* XPort functions -- an interface to CAM at periph side */
+
+static struct cam_ed *
+mmc_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id)
+{
+ struct cam_ed *device;
+
+ printf("mmc_alloc_device()\n");
+ device = xpt_alloc_device(bus, target, lun_id);
+ if (device == NULL)
+ return (NULL);
+
+ device->quirk = NULL;
+ device->mintags = 0;
+ device->maxtags = 0;
+ bzero(&device->inq_data, sizeof(device->inq_data));
+ device->inq_flags = 0;
+ device->queue_flags = 0;
+ device->serial_num = NULL;
+ device->serial_num_len = 0;
+ return (device);
+}
+
+static void
+mmc_dev_async(u_int32_t async_code, struct cam_eb *bus, struct cam_et *target,
+ struct cam_ed *device, void *async_arg)
+{
+
+ printf("mmc_dev_async(async_code=0x%x, path_id=%d, target_id=%x, lun_id=%" SCNx64 "\n",
+ async_code,
+ bus->path_id,
+ target->target_id,
+ device->lun_id);
+ /*
+ * We only need to handle events for real devices.
+ */
+ if (target->target_id == CAM_TARGET_WILDCARD
+ || device->lun_id == CAM_LUN_WILDCARD)
+ return;
+
+ if (async_code == AC_LOST_DEVICE) {
+ if ((device->flags & CAM_DEV_UNCONFIGURED) == 0) {
+ printf("AC_LOST_DEVICE -> set to unconfigured\n");
+ device->flags |= CAM_DEV_UNCONFIGURED;
+ xpt_release_device(device);
+ } else {
+ printf("AC_LOST_DEVICE on unconfigured device\n");
+ }
+ } else if (async_code == AC_FOUND_DEVICE) {
+ printf("Got AC_FOUND_DEVICE -- whatever...\n");
+ } else if (async_code == AC_PATH_DEREGISTERED ) {
+ printf("Got AC_PATH_DEREGISTERED -- whatever...\n");
+ } else
+ panic("Unknown async code\n");
+}
+
+/* Taken from nvme_scan_lun, thanks to bsdimp@ */
+static void
+mmc_scan_lun(struct cam_periph *periph, struct cam_path *path,
+ cam_flags flags, union ccb *request_ccb)
+{
+ struct ccb_pathinq cpi;
+ cam_status status;
+ struct cam_periph *old_periph;
+
+ CAM_DEBUG(path, CAM_DEBUG_TRACE, ("mmc_scan_lun\n"));
+
+ xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE);
+ cpi.ccb_h.func_code = XPT_PATH_INQ;
+ xpt_action((union ccb *)&cpi);
+
+ if (cpi.ccb_h.status != CAM_REQ_CMP) {
+ if (request_ccb != NULL) {
+ request_ccb->ccb_h.status = cpi.ccb_h.status;
+ xpt_done(request_ccb);
+ }
+ return;
+ }
+
+ /*
+ * Unlike in other drivers like ata(4), here we're called with the wildcard
+ * path. So we need to create a new path to start a scanner on it.
+ */
+ struct cam_path *newpath;
+ status = xpt_create_path(&newpath, NULL,
+ request_ccb->ccb_h.path_id,
+ /* target */ 0 ,
+ /* lun */ 0);
+ if (status != CAM_REQ_CMP) {
+ printf("xpt_create_path failed"
+ " with status %#x\n",
+ status);
+ request_ccb->ccb_h.status = status;
+ xpt_done(request_ccb);
+ return;
+ }
+
+ CAM_DEBUG(newpath, CAM_DEBUG_INFO,
+ ("Locking new path\n"));
+ xpt_path_unlock(path);
+ xpt_path_lock(newpath);
+
+ if ((old_periph = cam_periph_find(path, "mmcprobe")) != NULL) {
+ if ((old_periph->flags & CAM_PERIPH_INVALID) == 0) {
+// mmcprobe_softc *softc;
+// softc = (mmcprobe_softc *)old_periph->softc;
+// Not sure if we need request ccb queue for mmc
+// TAILQ_INSERT_TAIL(&softc->request_ccbs,
+// &request_ccb->ccb_h, periph_links.tqe);
+// softc->restart = 1;
+ CAM_DEBUG(newpath, CAM_DEBUG_INFO,
+ ("Got scan request, but mmcprobe already exists\n"));
+ request_ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+ xpt_done(request_ccb);
+ } else {
+ request_ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+ xpt_done(request_ccb);
+ }
+ } else {
+ xpt_print(path, " Set up the mmcprobe device...\n");
+
+ status = cam_periph_alloc(mmcprobe_register, NULL,
+ mmcprobe_cleanup,
+ mmcprobe_start,
+ "mmcprobe",
+ CAM_PERIPH_BIO,
+ newpath, NULL, 0,
+ request_ccb);
+ if (status != CAM_REQ_CMP) {
+ xpt_print(path, "xpt_scan_lun: cam_alloc_periph "
+ "returned an error, can't continue probe\n");
+ }
+ request_ccb->ccb_h.status = status;
+ xpt_done(request_ccb);
+ }
+
+ CAM_DEBUG(newpath, CAM_DEBUG_INFO,
+ ("Unlocking new path\n"));
+ xpt_path_unlock(newpath);
+ xpt_path_lock(path);
+}
+
+static void
+mmc_action(union ccb *start_ccb)
+{
+ CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_INFO,
+ ("mmc_action! func_code=%x, action %s\n", start_ccb->ccb_h.func_code,
+ get_action_desc(start_ccb->ccb_h.func_code)));
+ switch (start_ccb->ccb_h.func_code) {
+
+ case XPT_SCAN_BUS:
+ /* FALLTHROUGH */
+ case XPT_SCAN_TGT:
+ /* FALLTHROUGH */
+ case XPT_SCAN_LUN:
+ CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_INFO,
+ ("XPT_SCAN_{BUS,TGT,LUN}\n"));
+ mmc_scan_lun(start_ccb->ccb_h.path->periph,
+ start_ccb->ccb_h.path, start_ccb->crcn.flags,
+ start_ccb);
+ break;
+
+ case XPT_DEV_ADVINFO:
+ {
+ mmc_dev_advinfo(start_ccb);
+ break;
+ }
+
+ default:
+ xpt_action_default(start_ccb);
+ break;
+ }
+}
+
+static void
+mmc_dev_advinfo(union ccb *start_ccb)
+{
+ struct cam_ed *device;
+ struct ccb_dev_advinfo *cdai;
+ off_t amt;
+
+ start_ccb->ccb_h.status = CAM_REQ_INVALID;
+ device = start_ccb->ccb_h.path->device;
+ cdai = &start_ccb->cdai;
+ CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE,
+ ("%s: request %x\n", __func__, cdai->buftype));
+
+ /* We don't support writing any data */
+ if (cdai->flags & CDAI_FLAG_STORE)
+ panic("Attempt to store data?!");
+
+ switch(cdai->buftype) {
+ case CDAI_TYPE_SCSI_DEVID:
+ cdai->provsiz = device->device_id_len;
+ if (device->device_id_len == 0)
+ break;
+ amt = MIN(cdai->provsiz, cdai->bufsiz);
+ memcpy(cdai->buf, device->device_id, amt);
+ break;
+ case CDAI_TYPE_SERIAL_NUM:
+ cdai->provsiz = device->serial_num_len;
+ if (device->serial_num_len == 0)
+ break;
+ amt = MIN(cdai->provsiz, cdai->bufsiz);
+ memcpy(cdai->buf, device->serial_num, amt);
+ break;
+ case CDAI_TYPE_PHYS_PATH: /* pass(4) wants this */
+ cdai->provsiz = 0;
+ break;
+ default:
+ panic("Unknown buftype");
+ return;
+ }
+ start_ccb->ccb_h.status = CAM_REQ_CMP;
+}
+
+static void
+mmc_announce_periph(struct cam_periph *periph)
+{
+ struct ccb_pathinq cpi;
+ struct ccb_trans_settings cts;
+ struct cam_path *path = periph->path;
+
+ cam_periph_assert(periph, MA_OWNED);
+
+ CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
+ ("mmc_announce_periph: called\n"));
+
+ xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+ cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
+ cts.type = CTS_TYPE_CURRENT_SETTINGS;
+ xpt_action((union ccb*)&cts);
+ if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
+ return;
+ xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL);
+ cpi.ccb_h.func_code = XPT_PATH_INQ;
+ xpt_action((union ccb *)&cpi);
+ printf("XPT info: CLK %04X, ...\n", cts.proto_specific.mmc.ios.clock);
+}
+
+/* This func is called per attached device :-( */
+void
+mmc_print_ident(struct mmc_params *ident_data)
+{
+ printf("Relative addr: %08x\n", ident_data->card_rca);
+ printf("Card features: <");
+ if (ident_data->card_features & CARD_FEATURE_MMC)
+ printf("MMC ");
+ if (ident_data->card_features & CARD_FEATURE_MEMORY)
+ printf("Memory ");
+ if (ident_data->card_features & CARD_FEATURE_SDHC)
+ printf("High-Capacity ");
+ if (ident_data->card_features & CARD_FEATURE_SD20)
+ printf("SD2.0-Conditions ");
+ if (ident_data->card_features & CARD_FEATURE_SDIO)
+ printf("SDIO ");
+ printf(">\n");
+
+ if (ident_data->card_features & CARD_FEATURE_MEMORY)
+ printf("Card memory OCR: %08x\n", ident_data->card_ocr);
+
+ if (ident_data->card_features & CARD_FEATURE_SDIO) {
+ printf("Card IO OCR: %08x\n", ident_data->io_ocr);
+ printf("Number of funcitions: %u\n", ident_data->sdio_func_count);
+ }
+}
+
+static periph_init_t probe_periph_init;
+
+static struct periph_driver probe_driver =
+{
+ probe_periph_init, "mmcprobe",
+ TAILQ_HEAD_INITIALIZER(probe_driver.units), /* generation */ 0,
+ CAM_PERIPH_DRV_EARLY
+};
+
+PERIPHDRIVER_DECLARE(mmcprobe, probe_driver);
+
+#define CARD_ID_FREQUENCY 400000 /* Spec requires 400kHz max during ID phase. */
+
+static void
+probe_periph_init()
+{
+}
+
+static cam_status
+mmcprobe_register(struct cam_periph *periph, void *arg)
+{
+ union ccb *request_ccb; /* CCB representing the probe request */
+ cam_status status;
+ mmcprobe_softc *softc;
+
+ CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("mmcprobe_register\n"));
+
+ request_ccb = (union ccb *)arg;
+ if (request_ccb == NULL) {
+ printf("mmcprobe_register: no probe CCB, "
+ "can't register device\n");
+ return(CAM_REQ_CMP_ERR);
+ }
+
+ softc = (mmcprobe_softc *)malloc(sizeof(*softc), M_CAMXPT, M_NOWAIT);
+
+ if (softc == NULL) {
+ printf("proberegister: Unable to probe new device. "
+ "Unable to allocate softc\n");
+ return(CAM_REQ_CMP_ERR);
+ }
+
+ softc->flags = 0;
+ periph->softc = softc;
+ softc->periph = periph;
+ softc->action = PROBE_INVALID;
+ softc->restart = 0;
+ status = cam_periph_acquire(periph);
+
+ memset(&periph->path->device->mmc_ident_data, 0, sizeof(struct mmc_params));
+ if (status != CAM_REQ_CMP) {
+ printf("proberegister: cam_periph_acquire failed (status=%d)\n",
+ status);
+ return (status);
+ }
+ CAM_DEBUG(periph->path, CAM_DEBUG_PROBE, ("Probe started\n"));
+
+ if (periph->path->device->flags & CAM_DEV_UNCONFIGURED)
+ PROBE_SET_ACTION(softc, PROBE_RESET);
+ else
+ PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
+
+ /* This will kick the ball */
+ xpt_schedule(periph, CAM_PRIORITY_XPT);
+
+ return(CAM_REQ_CMP);
+}
+
+static int
+mmc_highest_voltage(uint32_t ocr)
+{
+ int i;
+
+ for (i = MMC_OCR_MAX_VOLTAGE_SHIFT;
+ i >= MMC_OCR_MIN_VOLTAGE_SHIFT; i--)
+ if (ocr & (1 << i))
+ return (i);
+ return (-1);
+}
+
+static inline void
+init_standard_ccb(union ccb *ccb, uint32_t cmd)
+{
+ ccb->ccb_h.func_code = cmd;
+ ccb->ccb_h.flags = CAM_DIR_OUT;
+ ccb->ccb_h.retry_count = 0;
+ ccb->ccb_h.timeout = 15 * 1000;
+ ccb->ccb_h.cbfcnp = mmcprobe_done;
+}
+
+static void
+mmcprobe_start(struct cam_periph *periph, union ccb *start_ccb)
+{
+ mmcprobe_softc *softc;
+ struct cam_path *path;
+ struct ccb_mmcio *mmcio;
+ struct mtx *p_mtx = cam_periph_mtx(periph);
+ struct ccb_trans_settings_mmc *cts;
+
+ CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("mmcprobe_start\n"));
+ softc = (mmcprobe_softc *)periph->softc;
+ path = start_ccb->ccb_h.path;
+ mmcio = &start_ccb->mmcio;
+ cts = &start_ccb->cts.proto_specific.mmc;
+ struct mmc_params *mmcp = &path->device->mmc_ident_data;
+
+ memset(&mmcio->cmd, 0, sizeof(struct mmc_command));
+
+ if (softc->restart) {
+ softc->restart = 0;
+ if (path->device->flags & CAM_DEV_UNCONFIGURED)
+ softc->action = PROBE_RESET;
+ else
+ softc->action = PROBE_IDENTIFY;
+
+ }
+
+ /* Here is the place where the identify fun begins */
+ switch (softc->action) {
+ case PROBE_RESET:
+ /* FALLTHROUGH */
+ case PROBE_IDENTIFY:
+ init_standard_ccb(start_ccb, XPT_PATH_INQ);
+ xpt_action(start_ccb);
+
+ CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("Start with PROBE_RESET\n"));
+ init_standard_ccb(start_ccb, XPT_SET_TRAN_SETTINGS);
+ cts->ios.power_mode = power_off;
+ cts->ios_valid = MMC_PM;
+ xpt_action(start_ccb);
+ mtx_sleep(periph, p_mtx, 0, "mmcios", 100);
+
+ /* mmc_power_up */
+ /* Get the host OCR */
+ init_standard_ccb(start_ccb, XPT_GET_TRAN_SETTINGS);
+ xpt_action(start_ccb);
+
+ uint32_t hv = mmc_highest_voltage(cts->host_ocr);
+ init_standard_ccb(start_ccb, XPT_SET_TRAN_SETTINGS);
+ cts->ios.vdd = hv;
+ cts->ios.bus_mode = opendrain;
+ cts->ios.chip_select = cs_dontcare;
+ cts->ios.power_mode = power_up;
+ cts->ios.bus_width = bus_width_1;
+ cts->ios.clock = 0;
+ cts->ios_valid = MMC_VDD | MMC_PM | MMC_BM |
+ MMC_CS | MMC_BW | MMC_CLK;
+ xpt_action(start_ccb);
+ mtx_sleep(periph, p_mtx, 0, "mmcios", 100);
+
+ init_standard_ccb(start_ccb, XPT_SET_TRAN_SETTINGS);
+ cts->ios.power_mode = power_on;
+ cts->ios.clock = CARD_ID_FREQUENCY;
+ cts->ios.timing = bus_timing_normal;
+ cts->ios_valid = MMC_PM | MMC_CLK | MMC_BT;
+ xpt_action(start_ccb);
+ mtx_sleep(periph, p_mtx, 0, "mmcios", 100);
+ /* End for mmc_power_on */
+
+ /* Begin mmc_idle_cards() */
+ init_standard_ccb(start_ccb, XPT_SET_TRAN_SETTINGS);
+ cts->ios.chip_select = cs_high;
+ cts->ios_valid = MMC_CS;
+ xpt_action(start_ccb);
+ mtx_sleep(periph, p_mtx, 0, "mmcios", 1);
+
+ init_standard_ccb(start_ccb, XPT_MMC_IO);
+ mmcio->cmd.opcode = MMC_GO_IDLE_STATE; /* CMD 0 */
+ mmcio->cmd.arg = 0;
+ mmcio->cmd.flags = MMC_RSP_NONE | MMC_CMD_BC;
+ mmcio->cmd.data.len = 0;
+ mmcio->stop.opcode = 0;
+
+ /* XXX Reset I/O portion as well */
+ break;
+ case PROBE_SDIO_RESET:
+ CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("Start with PROBE_SDIO_RESET\n"));
+ uint32_t mmc_arg = SD_IO_RW_ADR(SD_IO_CCCR_CTL)
+ | SD_IO_RW_DAT(CCCR_CTL_RES) | SD_IO_RW_WR | SD_IO_RW_RAW;
+ cam_fill_mmcio(&start_ccb->mmcio,
+ /*retries*/ 0,
+ /*cbfcnp*/ mmcprobe_done,
+ /*flags*/ CAM_DIR_NONE,
+ /*mmc_opcode*/ SD_IO_RW_DIRECT,
+ /*mmc_arg*/ mmc_arg,
+ /*mmc_flags*/ MMC_RSP_R5 | MMC_CMD_AC,
+ /*mmc_data*/ NULL,
+ /*timeout*/ 1000);
+ break;
+ case PROBE_SEND_IF_COND:
+ CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("Start with PROBE_SEND_IF_COND\n"));
+ init_standard_ccb(start_ccb, XPT_MMC_IO);
+ mmcio->cmd.opcode = SD_SEND_IF_COND; /* CMD 8 */
+ mmcio->cmd.arg = (1 << 8) + 0xAA;
+ mmcio->cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR;
+ mmcio->cmd.data.len = 0;
+ mmcio->stop.opcode = 0;
+ break;
+
+ case PROBE_SDIO_INIT:
+ CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("Start with PROBE_SDIO_INIT\n"));
+ init_standard_ccb(start_ccb, XPT_MMC_IO);
+ mmcio->cmd.opcode = IO_SEND_OP_COND; /* CMD 5 */
+ mmcio->cmd.arg = mmcp->io_ocr;
+ mmcio->cmd.flags = MMC_RSP_R4;
+ mmcio->cmd.data.len = 0; mmcio->cmd.data.data = NULL;
+ mmcio->stop.opcode = 0;
+ break;
+
+ case PROBE_MMC_INIT:
+ CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("Start with PROBE_MMC_INIT\n"));
+ init_standard_ccb(start_ccb, XPT_MMC_IO);
+ mmcio->cmd.opcode = MMC_SEND_OP_COND; /* CMD 1 */
+ mmcio->cmd.arg = MMC_OCR_HCS | mmcp->card_ocr; /* HCS + ocr */;
+ mmcio->cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
+ mmcio->cmd.data.len = 0; mmcio->cmd.data.data = NULL;
+ mmcio->stop.opcode = 0;
+ break;
+
+ case PROBE_SEND_APP_OP_COND:
+ init_standard_ccb(start_ccb, XPT_MMC_IO);
+ if (softc->flags & PROBE_FLAG_ACMD_SENT) {
+ mmcio->cmd.opcode = ACMD_SD_SEND_OP_COND; /* CMD 41 */
+ /*
+ * We set HCS bit because we do support SDHC cards.
+ * XXX: Don't set HCS if no response to CMD8.
+ */
+ mmcio->cmd.arg = MMC_OCR_HCS | mmcp->card_ocr; /* HCS + ocr */
+ mmcio->cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
+ } else {
+ mmcio->cmd.opcode = MMC_APP_CMD; /* CMD 55 */
+ mmcio->cmd.arg = 0; /* rca << 16 */
+ mmcio->cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ }
+ mmcio->cmd.data.len = 0; mmcio->cmd.data.data = NULL;
+ mmcio->stop.opcode = 0;
+ break;
+
+ case PROBE_GET_CID: /* XXX move to mmc_da */
+ init_standard_ccb(start_ccb, XPT_MMC_IO);
+ mmcio->cmd.opcode = MMC_ALL_SEND_CID;
+ mmcio->cmd.arg = 0;
+ mmcio->cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
+ mmcio->cmd.data.len = 0; mmcio->cmd.data.data = NULL;
+ mmcio->stop.opcode = 0;
+ break;
+
+ case PROBE_SEND_RELATIVE_ADDR:
+ init_standard_ccb(start_ccb, XPT_MMC_IO);
+ mmcio->cmd.opcode = SD_SEND_RELATIVE_ADDR;
+ mmcio->cmd.arg = 0;
+ mmcio->cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
+ mmcio->cmd.data.len = 0; mmcio->cmd.data.data = NULL;
+ mmcio->stop.opcode = 0;
+ break;
+ case PROBE_SELECT_CARD:
+ init_standard_ccb(start_ccb, XPT_MMC_IO);
+ mmcio->cmd.opcode = MMC_SELECT_CARD;
+ mmcio->cmd.arg = (uint32_t)path->device->mmc_ident_data.card_rca << 16;
+ mmcio->cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
+ mmcio->cmd.data.len = 0; mmcio->cmd.data.data = NULL;
+ mmcio->stop.opcode = 0;
+ break;
+ case PROBE_GET_CSD: /* XXX move to mmc_da */
+ init_standard_ccb(start_ccb, XPT_MMC_IO);
+ mmcio->cmd.opcode = MMC_SEND_CSD;
+ mmcio->cmd.arg = (uint32_t)path->device->mmc_ident_data.card_rca << 16;
+ mmcio->cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
+ mmcio->cmd.data.len = 0; mmcio->cmd.data.data = NULL;
+ mmcio->stop.opcode = 0;
+ break;
+ case PROBE_SET_BUS_WIDTH:
+ /* This only works for SD cards, for MMC see mmc.c:725 */
+ /* TODO: need to reset CD bit, does it work at all w/o that??? */
+ init_standard_ccb(start_ccb, XPT_MMC_IO);
+ if (!(softc->flags & PROBE_FLAG_ACMD_SENT)) {
+ mmcio->cmd.opcode = MMC_APP_CMD; /* CMD 55 */
+ mmcio->cmd.arg = (uint32_t)path->device->mmc_ident_data.card_rca << 16;
+ mmcio->cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ mmcio->cmd.data.len = 0; mmcio->cmd.data.data = NULL;
+ break;
+ }
+ mmcio->cmd.opcode = ACMD_SET_BUS_WIDTH; /* ACMD 6 */
+ mmcio->cmd.arg = 0x1 << 1; /* 4-bit mode */
+ mmcio->cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ mmcio->cmd.data.len = 0; mmcio->cmd.data.data = NULL;
+ mmcio->stop.opcode = 0;
+ break;
+ case PROBE_SET_BUS_WIDTH_HOST:
+ init_standard_ccb(start_ccb, XPT_SET_TRAN_SETTINGS);
+ cts->ios.bus_width = bus_width_4;
+ cts->ios_valid = MMC_BW;
+ xpt_action(start_ccb);
+ PROBE_SET_ACTION(softc, PROBE_DONE);
+ /* ... and proceed to PROBE_DONE */
+ case PROBE_DONE:
+ CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("Start with PROBE_DONE\n"));
+ init_standard_ccb(start_ccb, XPT_SET_TRAN_SETTINGS);
+ cts->ios.bus_mode = pushpull;
+ cts->ios_valid = MMC_BM;
+ xpt_action(start_ccb);
+ return;
+ /* NOTREACHED */
+ break;
+ case PROBE_INVALID:
+ break;
+ default:
+ CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("probestart: invalid action state 0x%x\n", softc->action));
+ panic("default: case in mmc_probe_start()");
+ }
+
+ start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
+ xpt_action(start_ccb);
+}
+
+static void mmcprobe_cleanup(struct cam_periph *periph)
+{
+ free(periph->softc, M_CAMXPT);
+}
+
+static void
+mmcprobe_done(struct cam_periph *periph, union ccb *done_ccb)
+{
+ mmcprobe_softc *softc;
+ struct cam_path *path;
+
+ int err;
+ struct ccb_mmcio *mmcio;
+ u_int32_t priority;
+
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("mmcprobe_done\n"));
+ softc = (mmcprobe_softc *)periph->softc;
+ path = done_ccb->ccb_h.path;
+ priority = done_ccb->ccb_h.pinfo.priority;
+
+ switch (softc->action) {
+ case PROBE_RESET:
+ /* FALLTHROUGH */
+ case PROBE_IDENTIFY:
+ {
+ printf("Starting completion of PROBE_RESET\n");
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("done with PROBE_RESET\n"));
+ path->device->protocol = PROTO_MMCSD;
+ PROBE_SET_ACTION(softc, PROBE_SEND_IF_COND);
+ break;
+ }
+ case PROBE_SEND_IF_COND:
+ {
+ mmcio = &done_ccb->mmcio;
+ err = mmcio->cmd.error;
+ struct mmc_params *mmcp = &path->device->mmc_ident_data;
+
+ if (err != MMC_ERR_NONE || mmcio->cmd.resp[0] != 0x1AA) {
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("IF_COND: error %d, pattern %08x\n",
+ err, mmcio->cmd.resp[0]));
+ } else {
+ mmcp->card_features |= CARD_FEATURE_SD20;
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("SD 2.0 interface conditions: OK\n"));
+
+ }
+ PROBE_SET_ACTION(softc, PROBE_SDIO_RESET);
+ break;
+ }
+ case PROBE_SDIO_RESET:
+ {
+ mmcio = &done_ccb->mmcio;
+ err = mmcio->cmd.error;
+
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("SDIO_RESET: error %d, CCCR CTL register: %08x\n",
+ err, mmcio->cmd.resp[0]));
+ PROBE_SET_ACTION(softc, PROBE_SDIO_INIT);
+ break;
+ }
+ case PROBE_SDIO_INIT:
+ {
+ mmcio = &done_ccb->mmcio;
+ err = mmcio->cmd.error;
+ struct mmc_params *mmcp = &path->device->mmc_ident_data;
+
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("SDIO_INIT: error %d, %08x %08x %08x %08x\n",
+ err, mmcio->cmd.resp[0],
+ mmcio->cmd.resp[1],
+ mmcio->cmd.resp[2],
+ mmcio->cmd.resp[3]));
+
+ /*
+ * Error here means that this card is not SDIO,
+ * so proceed with memory init as if nothing has happened
+ */
+ if (err != MMC_ERR_NONE) {
+ PROBE_SET_ACTION(softc, PROBE_SEND_APP_OP_COND);
+ break;
+ }
+ mmcp->card_features |= CARD_FEATURE_SDIO;
+ uint32_t ioifcond = mmcio->cmd.resp[0];
+ uint32_t io_ocr = ioifcond & R4_IO_OCR_MASK;
+
+ mmcp->sdio_func_count = R4_IO_NUM_FUNCTIONS(ioifcond);
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("SDIO card: %d functions\n", mmcp->sdio_func_count));
+ if (io_ocr == 0) {
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("SDIO OCR invalid?!\n"));
+ break; /* Retry */
+ }
+
+ if (io_ocr != 0 && mmcp->io_ocr == 0) {
+ mmcp->io_ocr = io_ocr;
+ break; /* Retry, this time with non-0 OCR */
+ }
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("SDIO OCR: %08x\n", mmcp->io_ocr));
+
+ if (ioifcond & R4_IO_MEM_PRESENT) {
+ /* Combo card -- proceed to memory initialization */
+ PROBE_SET_ACTION(softc, PROBE_SEND_APP_OP_COND);
+ } else {
+ /* No memory portion -- get RCA and select card */
+ PROBE_SET_ACTION(softc, PROBE_SEND_RELATIVE_ADDR);
+ }
+ break;
+ }
+ case PROBE_MMC_INIT:
+ {
+ mmcio = &done_ccb->mmcio;
+ err = mmcio->cmd.error;
+ struct mmc_params *mmcp = &path->device->mmc_ident_data;
+
+ if (err != MMC_ERR_NONE) {
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("MMC_INIT: error %d, resp %08x\n",
+ err, mmcio->cmd.resp[0]));
+ PROBE_SET_ACTION(softc, PROBE_INVALID);
+ break;
+ }
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("MMC card, OCR %08x\n", mmcio->cmd.resp[0]));
+
+ if (mmcp->card_ocr == 0) {
+ /* We haven't sent the OCR to the card yet -- do it */
+ mmcp->card_ocr = mmcio->cmd.resp[0];
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("-> sending OCR to card\n"));
+ break;
+ }
+
+ if (!(mmcio->cmd.resp[0] & MMC_OCR_CARD_BUSY)) {
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("Card is still powering up\n"));
+ break;
+ }
+
+ mmcp->card_features |= CARD_FEATURE_MMC | CARD_FEATURE_MEMORY;
+ PROBE_SET_ACTION(softc, PROBE_GET_CID);
+ break;
+ }
+ case PROBE_SEND_APP_OP_COND:
+ {
+ mmcio = &done_ccb->mmcio;
+ err = mmcio->cmd.error;
+
+ if (err != MMC_ERR_NONE) {
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("APP_OP_COND: error %d, resp %08x\n",
+ err, mmcio->cmd.resp[0]));
+ PROBE_SET_ACTION(softc, PROBE_MMC_INIT);
+ break;
+ }
+
+ if (!(softc->flags & PROBE_FLAG_ACMD_SENT)) {
+ /* Don't change the state */
+ softc->flags |= PROBE_FLAG_ACMD_SENT;
+ break;
+ }
+
+ softc->flags &= ~PROBE_FLAG_ACMD_SENT;
+ if ((mmcio->cmd.resp[0] & MMC_OCR_CARD_BUSY) ||
+ (mmcio->cmd.arg & MMC_OCR_VOLTAGE) == 0) {
+ struct mmc_params *mmcp = &path->device->mmc_ident_data;
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("Card OCR: %08x\n", mmcio->cmd.resp[0]));
+ if (mmcp->card_ocr == 0) {
+ mmcp->card_ocr = mmcio->cmd.resp[0];
+ /* Now when we know OCR that we want -- send it to card */
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("-> sending OCR to card\n"));
+ } else {
+ /* We already know the OCR and despite of that we
+ * are processing the answer to ACMD41 -> move on
+ */
+ PROBE_SET_ACTION(softc, PROBE_GET_CID);
+ }
+ /* Getting an answer to ACMD41 means the card has memory */
+ mmcp->card_features |= CARD_FEATURE_MEMORY;
+
+ /* Standard capacity vs High Capacity memory card */
+ if (mmcio->cmd.resp[0] & MMC_OCR_CCS) {
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("Card is SDHC\n"));
+ mmcp->card_features |= CARD_FEATURE_SDHC;
+ }
+
+ } else {
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("Card not ready: %08x\n", mmcio->cmd.resp[0]));
+ /* Send CMD55+ACMD41 once again */
+ PROBE_SET_ACTION(softc, PROBE_SEND_APP_OP_COND);
+ }
+
+ break;
+ }
+ case PROBE_GET_CID: /* XXX move to mmc_da */
+ {
+ mmcio = &done_ccb->mmcio;
+ err = mmcio->cmd.error;
+
+ if (err != MMC_ERR_NONE) {
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("PROBE_GET_CID: error %d\n", err));
+ PROBE_SET_ACTION(softc, PROBE_INVALID);
+ break;
+ }
+
+ struct mmc_params *mmcp = &path->device->mmc_ident_data;
+ memcpy(mmcp->card_cid, mmcio->cmd.resp, 4 * sizeof(uint32_t));
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("CID %08x%08x%08x%08x\n",
+ mmcp->card_cid[0],
+ mmcp->card_cid[1],
+ mmcp->card_cid[2],
+ mmcp->card_cid[3]));
+ PROBE_SET_ACTION(softc, PROBE_SEND_RELATIVE_ADDR);
+ break;
+ }
+ case PROBE_SEND_RELATIVE_ADDR: {
+ mmcio = &done_ccb->mmcio;
+ err = mmcio->cmd.error;
+ struct mmc_params *mmcp = &path->device->mmc_ident_data;
+ uint16_t rca = mmcio->cmd.resp[0] >> 16;
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("Card published RCA: %u\n", rca));
+ path->device->mmc_ident_data.card_rca = rca;
+ if (err != MMC_ERR_NONE) {
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("PROBE_SEND_RELATIVE_ADDR: error %d\n", err));
+ PROBE_SET_ACTION(softc, PROBE_INVALID);
+ break;
+ }
+
+ /* If memory is present, get CSD, otherwise select card */
+ if (mmcp->card_features & CARD_FEATURE_MEMORY)
+ PROBE_SET_ACTION(softc, PROBE_GET_CSD);
+ else
+ PROBE_SET_ACTION(softc, PROBE_SELECT_CARD);
+ break;
+ }
+ case PROBE_GET_CSD: {
+ mmcio = &done_ccb->mmcio;
+ err = mmcio->cmd.error;
+
+ if (err != MMC_ERR_NONE) {
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("PROBE_GET_CSD: error %d\n", err));
+ PROBE_SET_ACTION(softc, PROBE_INVALID);
+ break;
+ }
+
+ struct mmc_params *mmcp = &path->device->mmc_ident_data;
+ memcpy(mmcp->card_csd, mmcio->cmd.resp, 4 * sizeof(uint32_t));
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("CSD %08x%08x%08x%08x\n",
+ mmcp->card_csd[0],
+ mmcp->card_csd[1],
+ mmcp->card_csd[2],
+ mmcp->card_csd[3]));
+ PROBE_SET_ACTION(softc, PROBE_SELECT_CARD);
+ break;
+ }
+ case PROBE_SELECT_CARD: {
+ mmcio = &done_ccb->mmcio;
+ err = mmcio->cmd.error;
+ if (err != MMC_ERR_NONE) {
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("PROBE_SEND_RELATIVE_ADDR: error %d\n", err));
+ PROBE_SET_ACTION(softc, PROBE_INVALID);
+ break;
+ }
+ /* Notify the system that the device is found! */
+ if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
+ path->device->flags &= ~CAM_DEV_UNCONFIGURED;
+ xpt_acquire_device(path->device);
+ done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
+ xpt_action(done_ccb);
+ xpt_async(AC_FOUND_DEVICE, path, done_ccb);
+ }
+
+ struct mmc_params *mmcp = &path->device->mmc_ident_data;
+
+ for (int i = 0; i < mmcp->sdio_func_count; i++) {
+ struct cam_path *newpath;
+ cam_status status;
+ status = xpt_create_path(&newpath, NULL,
+ done_ccb->ccb_h.path_id, 0, i + 1);
+ if (status != CAM_REQ_CMP)
+ printf("xpt_create_path failed"
+ " with status %#x\n",
+ status);
+ xpt_async(AC_FOUND_DEVICE, newpath, done_ccb);
+ }
+
+ PROBE_SET_ACTION(softc, PROBE_SET_BUS_WIDTH);
+ break;
+ }
+ case PROBE_SET_BUS_WIDTH: {
+ mmcio = &done_ccb->mmcio;
+ err = mmcio->cmd.error;
+
+ if (err != MMC_ERR_NONE) {
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("APP_BUS_WIDTH: error %d, resp %08x\n",
+ err, mmcio->cmd.resp[0]));
+ PROBE_SET_ACTION(softc, PROBE_DONE);
+ break;
+ }
+
+ if (!(softc->flags & PROBE_FLAG_ACMD_SENT)) {
+ /* Don't change the state */
+ softc->flags |= PROBE_FLAG_ACMD_SENT;
+ break;
+ }
+
+ softc->flags &= ~PROBE_FLAG_ACMD_SENT;
+
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("Bus width set to 4 bit: resp %08x\n", mmcio->cmd.resp[0]));
+ PROBE_SET_ACTION(softc, PROBE_SET_BUS_WIDTH_HOST);
+ break;
+ }
+ default:
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("mmc_probedone: invalid action state 0x%x\n", softc->action));
+ panic("default: case in mmc_probe_done()");
+ }
+
+ if (softc->action == PROBE_INVALID &&
+ (path->device->flags & CAM_DEV_UNCONFIGURED) == 0) {
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("mmc_probedone: Should send AC_LOST_DEVICE but won't for now\n"));
+ //xpt_async(AC_LOST_DEVICE, path, NULL);
+ }
+
+ xpt_release_ccb(done_ccb);
+ if (softc->action != PROBE_INVALID)
+ xpt_schedule(periph, priority);
+ /* Drop freeze taken due to CAM_DEV_QFREEZE flag set. */
+ int frozen = cam_release_devq(path, 0, 0, 0, FALSE);
+ printf("mmc_probedone: remaining freezecnt %d\n", frozen);
+
+ if (softc->action == PROBE_DONE || softc->action == PROBE_INVALID) {
+ cam_periph_invalidate(periph);
+ cam_periph_release_locked(periph);
+ }
+}
+
+
+/* Helper stuff */
+static const char *
+get_action_desc(int action)
+{
+ switch (action) {
+ case XPT_FC_QUEUED:
+ return "XPT_FC_QUEUED";
+ ;break;
+ case XPT_FC_USER_CCB:
+ return "XPT_FC_USER_CCB";
+ ;break;
+ case XPT_FC_XPT_ONLY:
+ return "XPT_FC_XPT_ONLY";
+ ;break;
+ case XPT_FC_DEV_QUEUED:
+ return "XPT_FC_DEV_QUEUED";
+ ;break;
+ case XPT_NOOP:
+ return "XPT_NOOP";
+ ;break;
+ case XPT_SCSI_IO:
+ return "XPT_SCSI_IO";
+ ;break;
+ case XPT_GDEV_TYPE:
+ return "XPT_GDEV_TYPE";
+ ;break;
+ case XPT_GDEVLIST:
+ return "XPT_GDEVLIST";
+ ;break;
+ case XPT_PATH_INQ:
+ return "XPT_PATH_INQ";
+ ;break;
+ case XPT_REL_SIMQ:
+ return "XPT_REL_SIMQ";
+ ;break;
+ case XPT_SASYNC_CB:
+ return "XPT_SASYNC_CB";
+ ;break;
+ case XPT_SDEV_TYPE:
+ return "XPT_SDEV_TYPE";
+ ;break;
+ case XPT_SCAN_BUS:
+ return "XPT_SCAN_BUS";
+ ;break;
+ case XPT_DEV_MATCH:
+ return "XPT_DEV_MATCH";
+ ;break;
+ case XPT_DEBUG:
+ return "XPT_DEBUG";
+ ;break;
+ case XPT_PATH_STATS:
+ return "XPT_PATH_STATS";
+ ;break;
+ case XPT_GDEV_STATS:
+ return "XPT_GDEV_STATS";
+ ;break;
+ case XPT_DEV_ADVINFO:
+ return "XPT_DEV_ADVINFO";
+ ;break;
+ case XPT_ASYNC:
+ return "XPT_ASYNC";
+ ;break;
+ case XPT_ABORT:
+ return "XPT_ABORT";
+ ;break;
+ case XPT_RESET_BUS:
+ return "XPT_RESET_BUS";
+ ;break;
+ case XPT_RESET_DEV:
+ return "XPT_RESET_DEV";
+ ;break;
+ case XPT_TERM_IO:
+ return "XPT_TERM_IO";
+ ;break;
+ case XPT_SCAN_LUN:
+ return "XPT_SCAN_LUN";
+ ;break;
+ case XPT_GET_TRAN_SETTINGS:
+ return "XPT_GET_TRAN_SETTINGS";
+ ;break;
+ case XPT_SET_TRAN_SETTINGS:
+ return "XPT_SET_TRAN_SETTINGS";
+ ;break;
+ case XPT_CALC_GEOMETRY:
+ return "XPT_CALC_GEOMETRY";
+ ;break;
+ case XPT_ATA_IO:
+ return "XPT_ATA_IO";
+ ;break;
+ case XPT_GET_SIM_KNOB:
+ return "XPT_GET_SIM_KNOB";
+ ;break;
+ case XPT_SET_SIM_KNOB:
+ return "XPT_SET_SIM_KNOB";
+ ;break;
+ case XPT_SMP_IO:
+ return "XPT_SMP_IO";
+ ;break;
+ case XPT_SCAN_TGT:
+ return "XPT_SCAN_TGT";
+ ;break;
+ case XPT_ENG_INQ:
+ return "XPT_ENG_INQ";
+ ;break;
+ case XPT_ENG_EXEC:
+ return "XPT_ENG_EXEC";
+ ;break;
+ case XPT_EN_LUN:
+ return "XPT_EN_LUN";
+ ;break;
+ case XPT_TARGET_IO:
+ return "XPT_TARGET_IO";
+ ;break;
+ case XPT_ACCEPT_TARGET_IO:
+ return "XPT_ACCEPT_TARGET_IO";
+ ;break;
+ case XPT_CONT_TARGET_IO:
+ return "XPT_CONT_TARGET_IO";
+ ;break;
+ case XPT_IMMED_NOTIFY:
+ return "XPT_IMMED_NOTIFY";
+ ;break;
+ case XPT_NOTIFY_ACK:
+ return "XPT_NOTIFY_ACK";
+ ;break;
+ case XPT_IMMEDIATE_NOTIFY:
+ return "XPT_IMMEDIATE_NOTIFY";
+ ;break;
+ case XPT_NOTIFY_ACKNOWLEDGE:
+ return "XPT_NOTIFY_ACKNOWLEDGE";
+ ;break;
+ case XPT_MMC_IO:
+ return "XPT_MMC_IO";
+ ;break;
+ case XPT_VUNIQUE:
+ return "XPT_VUNIQUE";
+ ;break;
+ default:
+ return "<Unknown>";
+ }
+}
Index: sys/cam/mmc/mmcreg.h
===================================================================
--- /dev/null
+++ sys/cam/mmc/mmcreg.h
@@ -0,0 +1,546 @@
+/*-
+ * Copyright (c) 2015-2016 Ilya Bakulin <kibab@FreeBSD.org>
+ * All rights reserved.
+ * Lots of code taken from sys/dev/mmc implementation,
+ * thanks to Warner Losh <imp@FreeBSD.org>, Alexander Motin <mav@FreeBSD.org> and other authors.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Portions of this software may have been developed with reference to
+ * the SD Simplified Specification. The following disclaimer may apply:
+ *
+ * The following conditions apply to the release of the simplified
+ * specification ("Simplified Specification") by the SD Card Association and
+ * the SD Group. The Simplified Specification is a subset of the complete SD
+ * Specification which is owned by the SD Card Association and the SD
+ * Group. This Simplified Specification is provided on a non-confidential
+ * basis subject to the disclaimers below. Any implementation of the
+ * Simplified Specification may require a license from the SD Card
+ * Association, SD Group, SD-3C LLC or other third parties.
+ *
+ * Disclaimers:
+ *
+ * The information contained in the Simplified Specification is presented only
+ * as a standard specification for SD Cards and SD Host/Ancillary products and
+ * is provided "AS-IS" without any representations or warranties of any
+ * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD
+ * Card Association for any damages, any infringements of patents or other
+ * right of the SD Group, SD-3C LLC, the SD Card Association or any third
+ * parties, which may result from its use. No license is granted by
+ * implication, estoppel or otherwise under any patent or other rights of the
+ * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing
+ * herein shall be construed as an obligation by the SD Group, the SD-3C LLC
+ * or the SD Card Association to disclose or distribute any technical
+ * information, know-how or other confidential information to any third party.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef DEV_MMC_MMCREG_H
+#define DEV_MMC_MMCREG_H
+
+/*
+ * This file contains the register definitions for the mmc and sd busses.
+ * They are taken from publicly available sources.
+ */
+
+struct mmc_data {
+ size_t len; /* size of the data */
+ void *data; /* data buffer */
+ uint32_t flags;
+#define MMC_DATA_WRITE (1UL << 0)
+#define MMC_DATA_READ (1UL << 1)
+#define MMC_DATA_STREAM (1UL << 2)
+#define MMC_DATA_MULTI (1UL << 3)
+};
+
+struct mmc_command {
+ uint32_t opcode;
+ uint32_t arg;
+ uint32_t resp[4];
+ uint32_t flags; /* Expected responses */
+#define MMC_RSP_PRESENT (1ul << 0) /* Response */
+#define MMC_RSP_136 (1ul << 1) /* 136 bit response */
+#define MMC_RSP_CRC (1ul << 2) /* Expect valid crc */
+#define MMC_RSP_BUSY (1ul << 3) /* Card may send busy */
+#define MMC_RSP_OPCODE (1ul << 4) /* Response include opcode */
+#define MMC_RSP_MASK 0x1ful
+#define MMC_CMD_AC (0ul << 5) /* Addressed Command, no data */
+#define MMC_CMD_ADTC (1ul << 5) /* Addressed Data transfer cmd */
+#define MMC_CMD_BC (2ul << 5) /* Broadcast command, no response */
+#define MMC_CMD_BCR (3ul << 5) /* Broadcast command with response */
+#define MMC_CMD_MASK (3ul << 5)
+
+/* Possible response types defined in the standard: */
+#define MMC_RSP_NONE (0)
+#define MMC_RSP_R1 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
+#define MMC_RSP_R1B (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE | MMC_RSP_BUSY)
+#define MMC_RSP_R2 (MMC_RSP_PRESENT | MMC_RSP_136 | MMC_RSP_CRC)
+#define MMC_RSP_R3 (MMC_RSP_PRESENT)
+#define MMC_RSP_R4 (MMC_RSP_PRESENT)
+#define MMC_RSP_R5 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
+#define MMC_RSP_R6 (MMC_RSP_PRESENT | MMC_RSP_CRC)
+#define MMC_RSP_R7 (MMC_RSP_PRESENT | MMC_RSP_CRC)
+#define MMC_RSP(x) ((x) & MMC_RSP_MASK)
+ uint32_t retries;
+ uint32_t error;
+#define MMC_ERR_NONE 0
+#define MMC_ERR_TIMEOUT 1
+#define MMC_ERR_BADCRC 2
+#define MMC_ERR_FIFO 3
+#define MMC_ERR_FAILED 4
+#define MMC_ERR_INVALID 5
+#define MMC_ERR_NO_MEMORY 6
+#define MMC_ERR_MAX 6
+ struct mmc_data data; /* Data segment with cmd */
+};
+
+/*
+ * R1 responses
+ *
+ * Types (per SD 2.0 standard)
+ * e : error bit
+ * s : status bit
+ * r : detected and set for the actual command response
+ * x : Detected and set during command execution. The host can get
+ * the status by issuing a command with R1 response.
+ *
+ * Clear Condition (per SD 2.0 standard)
+ * a : according to the card current state.
+ * b : always related to the previous command. reception of a valid
+ * command will clear it (with a delay of one command).
+ * c : clear by read
+ */
+#define R1_OUT_OF_RANGE (1u << 31) /* erx, c */
+#define R1_ADDRESS_ERROR (1u << 30) /* erx, c */
+#define R1_BLOCK_LEN_ERROR (1u << 29) /* erx, c */
+#define R1_ERASE_SEQ_ERROR (1u << 28) /* er, c */
+#define R1_ERASE_PARAM (1u << 27) /* erx, c */
+#define R1_WP_VIOLATION (1u << 26) /* erx, c */
+#define R1_CARD_IS_LOCKED (1u << 25) /* sx, a */
+#define R1_LOCK_UNLOCK_FAILED (1u << 24) /* erx, c */
+#define R1_COM_CRC_ERROR (1u << 23) /* er, b */
+#define R1_ILLEGAL_COMMAND (1u << 22) /* er, b */
+#define R1_CARD_ECC_FAILED (1u << 21) /* erx, c */
+#define R1_CC_ERROR (1u << 20) /* erx, c */
+#define R1_ERROR (1u << 19) /* erx, c */
+#define R1_CSD_OVERWRITE (1u << 16) /* erx, c */
+#define R1_WP_ERASE_SKIP (1u << 15) /* erx, c */
+#define R1_CARD_ECC_DISABLED (1u << 14) /* sx, a */
+#define R1_ERASE_RESET (1u << 13) /* sr, c */
+#define R1_CURRENT_STATE_MASK (0xfu << 9) /* sx, b */
+#define R1_READY_FOR_DATA (1u << 8) /* sx, a */
+#define R1_APP_CMD (1u << 5) /* sr, c */
+#define R1_AKE_SEQ_ERROR (1u << 3) /* er, c */
+#define R1_STATUS(x) ((x) & 0xFFFFE000)
+#define R1_CURRENT_STATE(x) (((x) & R1_CURRENT_STATE_MASK) >> 9)
+#define R1_STATE_IDLE 0
+#define R1_STATE_READY 1
+#define R1_STATE_IDENT 2
+#define R1_STATE_STBY 3
+#define R1_STATE_TRAN 4
+#define R1_STATE_DATA 5
+#define R1_STATE_RCV 6
+#define R1_STATE_PRG 7
+#define R1_STATE_DIS 8
+
+/* R4 response (SDIO) */
+#define R4_IO_NUM_FUNCTIONS(ocr) (((ocr) >> 28) & 0x3)
+#define R4_IO_MEM_PRESENT (0x1<<27)
+#define R4_IO_OCR_MASK 0x00fffff0
+
+/*
+ * R5 responses
+ *
+ * Types (per SD 2.0 standard)
+ *e : error bit
+ *s : status bit
+ *r : detected and set for the actual command response
+ *x : Detected and set during command execution. The host can get
+ * the status by issuing a command with R1 response.
+ *
+ * Clear Condition (per SD 2.0 standard)
+ *a : according to the card current state.
+ *b : always related to the previous command. reception of a valid
+ * command will clear it (with a delay of one command).
+ *c : clear by read
+ */
+#define R5_COM_CRC_ERROR (1u << 15)/* er, b */
+#define R5_ILLEGAL_COMMAND (1u << 14)/* er, b */
+#define R5_IO_CURRENT_STATE_MASK (3u << 12)/* s, b */
+#define R5_IO_CURRENT_STATE(x) (((x) & R5_IO_CURRENT_STATE_MASK) >> 12)
+#define R5_ERROR (1u << 11)/* erx, c */
+#define R5_FUNCTION_NUMBER (1u << 9)/* er, c */
+#define R5_OUT_OF_RANGE (1u << 8)/* er, c */
+
+struct mmc_request {
+ struct mmc_command *cmd;
+ struct mmc_command *stop;
+ void (*done)(struct mmc_request *); /* Completion function */
+ void *done_data; /* requestor set data */
+ uint32_t flags;
+#define MMC_REQ_DONE 1
+};
+
+/* Command definitions */
+
+/* Class 0 and 1: Basic commands & read stream commands */
+#define MMC_GO_IDLE_STATE 0
+#define MMC_SEND_OP_COND 1
+#define MMC_ALL_SEND_CID 2
+#define MMC_SET_RELATIVE_ADDR 3
+#define SD_SEND_RELATIVE_ADDR 3
+#define MMC_SET_DSR 4
+#define IO_SEND_OP_COND 5
+#define MMC_SWITCH_FUNC 6
+#define MMC_SWITCH_FUNC_CMDS 0
+#define MMC_SWITCH_FUNC_SET 1
+#define MMC_SWITCH_FUNC_CLR 2
+#define MMC_SWITCH_FUNC_WR 3
+#define MMC_SELECT_CARD 7
+#define MMC_DESELECT_CARD 7
+#define MMC_SEND_EXT_CSD 8
+#define SD_SEND_IF_COND 8
+#define MMC_SEND_CSD 9
+#define MMC_SEND_CID 10
+#define MMC_READ_DAT_UNTIL_STOP 11
+#define MMC_STOP_TRANSMISSION 12
+#define MMC_SEND_STATUS 13
+#define MMC_BUSTEST_R 14
+#define MMC_GO_INACTIVE_STATE 15
+#define MMC_BUSTEST_W 19
+
+/* Class 2: Block oriented read commands */
+#define MMC_SET_BLOCKLEN 16
+#define MMC_READ_SINGLE_BLOCK 17
+#define MMC_READ_MULTIPLE_BLOCK 18
+ /* reserved: 19 */
+
+/* Class 3: Stream write commands */
+#define MMC_WRITE_DAT_UNTIL_STOP 20
+ /* reserved: 21 */
+ /* reserved: 22 */
+
+/* Class 4: Block oriented write commands */
+#define MMC_SET_BLOCK_COUNT 23
+#define MMC_WRITE_BLOCK 24
+#define MMC_WRITE_MULTIPLE_BLOCK 25
+#define MMC_PROGARM_CID 26
+#define MMC_PROGRAM_CSD 27
+
+/* Class 6: Block oriented write protection commands */
+#define MMC_SET_WRITE_PROT 28
+#define MMC_CLR_WRITE_PROT 29
+#define MMC_SEND_WRITE_PROT 30
+ /* reserved: 31 */
+
+/* Class 5: Erase commands */
+#define SD_ERASE_WR_BLK_START 32
+#define SD_ERASE_WR_BLK_END 33
+ /* 34 -- reserved old command */
+#define MMC_ERASE_GROUP_START 35
+#define MMC_ERASE_GROUP_END 36
+ /* 37 -- reserved old command */
+#define MMC_ERASE 38
+
+/* Class 9: I/O mode commands */
+#define MMC_FAST_IO 39
+#define MMC_GO_IRQ_STATE 40
+ /* reserved: 41 */
+
+/* Class 7: Lock card */
+#define MMC_LOCK_UNLOCK 42
+ /* reserved: 43 */
+ /* reserved: 44 */
+ /* reserved: 45 */
+ /* reserved: 46 */
+ /* reserved: 47 */
+ /* reserved: 48 */
+ /* reserved: 49 */
+ /* reserved: 50 */
+ /* reserved: 51 */
+ /* reserved: 54 */
+
+/* Class 8: Application specific commands */
+#define MMC_APP_CMD 55
+#define MMC_GEN_CMD 56
+ /* reserved: 57 */
+ /* reserved: 58 */
+ /* reserved: 59 */
+ /* reserved for mfg: 60 */
+ /* reserved for mfg: 61 */
+ /* reserved for mfg: 62 */
+ /* reserved for mfg: 63 */
+
+/* Class 9: I/O cards (sd) */
+#define SD_IO_RW_DIRECT 52
+/* CMD52 arguments */
+#define SD_ARG_CMD52_READ (0<<31)
+#define SD_ARG_CMD52_WRITE (1<<31)
+#define SD_ARG_CMD52_FUNC_SHIFT 28
+#define SD_ARG_CMD52_FUNC_MASK 0x7
+#define SD_ARG_CMD52_EXCHANGE (1<<27)
+#define SD_ARG_CMD52_REG_SHIFT 9
+#define SD_ARG_CMD52_REG_MASK 0x1ffff
+#define SD_ARG_CMD52_DATA_SHIFT 0
+#define SD_ARG_CMD52_DATA_MASK 0xff
+#define SD_R5_DATA(resp) ((resp)[0] & 0xff)
+
+#define SD_IO_RW_EXTENDED 53
+/* CMD53 arguments */
+#define SD_ARG_CMD53_READ (0<<31)
+#define SD_ARG_CMD53_WRITE (1<<31)
+#define SD_ARG_CMD53_FUNC_SHIFT 28
+#define SD_ARG_CMD53_FUNC_MASK 0x7
+#define SD_ARG_CMD53_BLOCK_MODE (1<<27)
+#define SD_ARG_CMD53_INCREMENT (1<<26)
+#define SD_ARG_CMD53_REG_SHIFT 9
+#define SD_ARG_CMD53_REG_MASK 0x1ffff
+#define SD_ARG_CMD53_LENGTH_SHIFT 0
+#define SD_ARG_CMD53_LENGTH_MASK 0x1ff
+#define SD_ARG_CMD53_LENGTH_MAX 64 /* XXX should be 511? */
+
+/* Class 10: Switch function commands */
+#define SD_SWITCH_FUNC 6
+ /* reserved: 34 */
+ /* reserved: 35 */
+ /* reserved: 36 */
+ /* reserved: 37 */
+ /* reserved: 50 */
+ /* reserved: 57 */
+
+
+/* Application specific commands for SD */
+#define ACMD_SET_BUS_WIDTH 6
+#define ACMD_SD_STATUS 13
+#define ACMD_SEND_NUM_WR_BLOCKS 22
+#define ACMD_SET_WR_BLK_ERASE_COUNT 23
+#define ACMD_SD_SEND_OP_COND 41
+#define ACMD_SET_CLR_CARD_DETECT 42
+#define ACMD_SEND_SCR 51
+
+/*
+ * EXT_CSD fields
+ */
+#define EXT_CSD_ERASE_GRP_DEF 175 /* R/W */
+#define EXT_CSD_BUS_WIDTH 183 /* R/W */
+#define EXT_CSD_HS_TIMING 185 /* R/W */
+#define EXT_CSD_CARD_TYPE 196 /* RO */
+#define EXT_CSD_REV 192 /* RO */
+#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */
+#define EXT_CSD_ERASE_TO_MULT 223 /* RO */
+#define EXT_CSD_ERASE_GRP_SIZE 224 /* RO */
+
+/*
+ * EXT_CSD field definitions
+ */
+#define EXT_CSD_CMD_SET_NORMAL 1
+#define EXT_CSD_CMD_SET_SECURE 2
+#define EXT_CSD_CMD_SET_CPSECURE 4
+
+#define EXT_CSD_CARD_TYPE_26 1
+#define EXT_CSD_CARD_TYPE_52 2
+
+#define EXT_CSD_BUS_WIDTH_1 0
+#define EXT_CSD_BUS_WIDTH_4 1
+#define EXT_CSD_BUS_WIDTH_8 2
+
+#define MMC_TYPE_26_MAX_HS 26000000
+#define MMC_TYPE_52_MAX_HS 52000000
+
+/*
+ * SD bus widths
+ */
+#define SD_BUS_WIDTH_1 0
+#define SD_BUS_WIDTH_4 2
+
+/*
+ * SD Switch
+ */
+#define SD_SWITCH_MODE_CHECK 0
+#define SD_SWITCH_MODE_SET 1
+#define SD_SWITCH_GROUP1 0
+#define SD_SWITCH_NORMAL_MODE 0
+#define SD_SWITCH_HS_MODE 1
+#define SD_SWITCH_NOCHANGE 0xF
+
+#define SD_CLR_CARD_DETECT 0
+#define SD_SET_CARD_DETECT 1
+
+#define SD_MAX_HS 50000000
+
+/*
+ * SDIO Direct & Extended I/O
+ */
+#define SD_IO_RW_WR (1u << 31)
+#define SD_IO_RW_FUNC(x) (((x) & 0x7) << 28)
+#define SD_IO_RW_RAW (1u << 27)
+#define SD_IO_RW_INCR (1u << 26)
+#define SD_IO_RW_ADR(x) (((x) & 0x1FFFF) << 9)
+#define SD_IO_RW_DAT(x) (((x) & 0xFF) << 0)
+#define SD_IO_RW_LEN(x) (((x) & 0xFF) << 0)
+
+#define SD_IOE_RW_LEN(x) (((x) & 0x1FF) << 0)
+#define SD_IOE_RW_BLK (1u << 27)
+
+/* Card Common Control Registers (CCCR) */
+#define SD_IO_CCCR_START 0x00000
+#define SD_IO_CCCR_SIZE 0x100
+#define SD_IO_CCCR_FN_ENABLE 0x02
+#define SD_IO_CCCR_FN_READY 0x03
+#define SD_IO_CCCR_INT_ENABLE 0x04
+#define SD_IO_CCCR_INT_PENDING 0x05
+#define SD_IO_CCCR_CTL 0x06
+#define CCCR_CTL_RES (1<<3)
+#define SD_IO_CCCR_BUS_WIDTH 0x07
+#define CCCR_BUS_WIDTH_4 (1<<1)
+#define CCCR_BUS_WIDTH_1 (1<<0)
+#define SD_IO_CCCR_CARDCAP 0x08
+#define SD_IO_CCCR_CISPTR 0x09 /* XXX 9-10, 10-11, or 9-12 */
+
+/* Function Basic Registers (FBR) */
+#define SD_IO_FBR_START 0x00100
+#define SD_IO_FBR_SIZE 0x00700
+
+/* Card Information Structure (CIS) */
+#define SD_IO_CIS_START 0x01000
+#define SD_IO_CIS_SIZE 0x17000
+
+/* CIS tuple codes (based on PC Card 16) */
+#define SD_IO_CISTPL_VERS_1 0x15
+#define SD_IO_CISTPL_MANFID 0x20
+#define SD_IO_CISTPL_FUNCID 0x21
+#define SD_IO_CISTPL_FUNCE 0x22
+#define SD_IO_CISTPL_END 0xff
+
+/* CISTPL_FUNCID codes */
+/* OpenBSD incorrectly defines 0x0c as FUNCTION_WLAN */
+/* #define SDMMC_FUNCTION_WLAN 0x0c */
+
+/* OCR bits */
+
+/*
+ * in SD 2.0 spec, bits 8-14 are now marked reserved
+ * Low voltage in SD2.0 spec is bit 7, TBD voltage
+ * Low voltage in MC 3.31 spec is bit 7, 1.65-1.95V
+ * Specs prior to MMC 3.31 defined bits 0-7 as voltages down to 1.5V.
+ * 3.31 redefined them to be reserved and also said that cards had to
+ * support the 2.7-3.6V and fixed the OCR to be 0xfff8000 for high voltage
+ * cards. MMC 4.0 says that a dual voltage card responds with 0xfff8080.
+ * Looks like the fine-grained control of the voltage tolerance ranges
+ * was abandoned.
+ *
+ * The MMC_OCR_CCS appears to be valid for only SD cards.
+ */
+#define MMC_OCR_VOLTAGE 0x3fffffffU /* Vdd Voltage mask */
+#define MMC_OCR_LOW_VOLTAGE (1u << 7) /* Low Voltage Range -- tbd */
+#define MMC_OCR_200_210 (1U << 8) /* Vdd voltage 2.00 ~ 2.10 */
+#define MMC_OCR_MIN_VOLTAGE_SHIFT 8
+#define MMC_OCR_210_220 (1U << 9) /* Vdd voltage 2.10 ~ 2.20 */
+#define MMC_OCR_220_230 (1U << 10) /* Vdd voltage 2.20 ~ 2.30 */
+#define MMC_OCR_230_240 (1U << 11) /* Vdd voltage 2.30 ~ 2.40 */
+#define MMC_OCR_240_250 (1U << 12) /* Vdd voltage 2.40 ~ 2.50 */
+#define MMC_OCR_250_260 (1U << 13) /* Vdd voltage 2.50 ~ 2.60 */
+#define MMC_OCR_260_270 (1U << 14) /* Vdd voltage 2.60 ~ 2.70 */
+#define MMC_OCR_270_280 (1U << 15) /* Vdd voltage 2.70 ~ 2.80 */
+#define MMC_OCR_280_290 (1U << 16) /* Vdd voltage 2.80 ~ 2.90 */
+#define MMC_OCR_290_300 (1U << 17) /* Vdd voltage 2.90 ~ 3.00 */
+#define MMC_OCR_300_310 (1U << 18) /* Vdd voltage 3.00 ~ 3.10 */
+#define MMC_OCR_310_320 (1U << 19) /* Vdd voltage 3.10 ~ 3.20 */
+#define MMC_OCR_320_330 (1U << 20) /* Vdd voltage 3.20 ~ 3.30 */
+#define MMC_OCR_330_340 (1U << 21) /* Vdd voltage 3.30 ~ 3.40 */
+#define MMC_OCR_340_350 (1U << 22) /* Vdd voltage 3.40 ~ 3.50 */
+#define MMC_OCR_350_360 (1U << 23) /* Vdd voltage 3.50 ~ 3.60 */
+#define MMC_OCR_MAX_VOLTAGE_SHIFT 23
+#define MMC_OCR_HCS (1u << 30) /* "Host supports SDHC" */
+#define MMC_OCR_CCS (1u << 30) /* Card Capacity status (SD vs SDHC) */
+#define MMC_OCR_CARD_BUSY (1U << 31) /* Card Power up status */
+
+/* CSD -- decoded structure */
+struct mmc_cid {
+ uint32_t mid;
+ char pnm[8];
+ uint32_t psn;
+ uint16_t oid;
+ uint16_t mdt_year;
+ uint8_t mdt_month;
+ uint8_t prv;
+ uint8_t fwrev;
+};
+
+struct mmc_csd
+{
+ uint8_t csd_structure;
+ uint8_t spec_vers;
+ uint16_t ccc;
+ uint16_t tacc;
+ uint32_t nsac;
+ uint32_t r2w_factor;
+ uint32_t tran_speed;
+ uint32_t read_bl_len;
+ uint32_t write_bl_len;
+ uint32_t vdd_r_curr_min;
+ uint32_t vdd_r_curr_max;
+ uint32_t vdd_w_curr_min;
+ uint32_t vdd_w_curr_max;
+ uint32_t wp_grp_size;
+ uint32_t erase_sector;
+ uint64_t capacity;
+ unsigned int read_bl_partial:1,
+ read_blk_misalign:1,
+ write_bl_partial:1,
+ write_blk_misalign:1,
+ dsr_imp:1,
+ erase_blk_en:1,
+ wp_grp_enable:1;
+};
+
+struct mmc_scr
+{
+ unsigned char sda_vsn;
+ unsigned char bus_widths;
+#define SD_SCR_BUS_WIDTH_1 (1<<0)
+#define SD_SCR_BUS_WIDTH_4 (1<<2)
+};
+
+struct mmc_sd_status
+{
+ uint8_t bus_width;
+ uint8_t secured_mode;
+ uint16_t card_type;
+ uint16_t prot_area;
+ uint8_t speed_class;
+ uint8_t perf_move;
+ uint8_t au_size;
+ uint16_t erase_size;
+ uint8_t erase_timeout;
+ uint8_t erase_offset;
+};
+
+/*
+ * Older versions of the MMC standard had a variable sector size. However,
+ * I've been able to find no old MMC or SD cards that have a non 512
+ * byte sector size anywhere, so we assume that such cards are very rare
+ * and only note their existance in passing here...
+ */
+#define MMC_SECTOR_SIZE 512
+
+#endif /* DEV_MMCREG_H */
Index: sys/cam/scsi/scsi_pass.c
===================================================================
--- sys/cam/scsi/scsi_pass.c
+++ sys/cam/scsi/scsi_pass.c
@@ -2170,7 +2170,7 @@
*/
fc = ccb->ccb_h.func_code;
if ((fc == XPT_SCSI_IO) || (fc == XPT_ATA_IO) || (fc == XPT_SMP_IO)
- || (fc == XPT_DEV_MATCH) || (fc == XPT_DEV_ADVINFO)) {
+ || (fc == XPT_DEV_MATCH) || (fc == XPT_DEV_ADVINFO) || (fc == XPT_MMC_IO)) {
bzero(&mapinfo, sizeof(mapinfo));
/*
Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -92,6 +92,9 @@
cam/ctl/ctl_error.c optional ctl
cam/ctl/ctl_util.c optional ctl
cam/ctl/scsi_ctl.c optional ctl
+cam/mmc/mmc_xpt.c optional scbus
+cam/mmc/mmc_da.c optional scbus
+cam/mmc/mmc_sdio.c optional scbus
cam/scsi/scsi_da.c optional da
cam/scsi/scsi_low.c optional ct | ncv | nsp | stg
cam/scsi/scsi_pass.c optional pass
@@ -1551,10 +1554,10 @@
compile-with "${NORMAL_FW}" \
no-obj no-implicit-rule \
clean "ipw_monitor.fw"
-dev/iscsi/icl.c optional iscsi | ctl
-dev/iscsi/icl_conn_if.m optional iscsi | ctl
+dev/iscsi/icl.c optional iscsi | ctl
+dev/iscsi/icl_conn_if.m optional iscsi | ctl
dev/iscsi/icl_proxy.c optional iscsi | ctl
-dev/iscsi/icl_soft.c optional iscsi | ctl
+dev/iscsi/icl_soft.c optional iscsi | ctl
dev/iscsi/iscsi.c optional iscsi scbus
dev/iscsi_initiator/iscsi.c optional iscsi_initiator scbus
dev/iscsi_initiator/iscsi_subr.c optional iscsi_initiator scbus
@@ -1961,6 +1964,7 @@
dev/mmc/mmcbr_if.m standard
dev/mmc/mmcbus_if.m standard
dev/mmc/mmcsd.c optional mmcsd
+dev/mmcnull/mmcnull.c optional mmcnull
dev/mn/if_mn.c optional mn pci
dev/mpr/mpr.c optional mpr
dev/mpr/mpr_config.c optional mpr
Index: sys/dev/mmc/mmcbr_if.m
===================================================================
--- sys/dev/mmc/mmcbr_if.m
+++ sys/dev/mmc/mmcbr_if.m
@@ -55,7 +55,7 @@
#include <sys/types.h>
#include <dev/mmc/bridge.h>
-#include <dev/mmc/mmcreg.h>
+#include <cam/mmc/mmcreg.h>
#
# This is the interface that a mmc bridge chip gives to the mmc bus
Index: sys/dev/mmc/mmcbrvar.h
===================================================================
--- sys/dev/mmc/mmcbrvar.h
+++ sys/dev/mmc/mmcbrvar.h
@@ -56,7 +56,7 @@
#define DEV_MMC_MMCBRVAR_H
#include <dev/mmc/bridge.h>
-#include <dev/mmc/mmcreg.h>
+#include <cam/mmc/mmcreg.h>
#include "mmcbr_if.h"
enum mmcbr_device_ivars {
Index: sys/dev/mmc/mmcbus_if.m
===================================================================
--- sys/dev/mmc/mmcbus_if.m
+++ sys/dev/mmc/mmcbus_if.m
@@ -53,7 +53,7 @@
# $FreeBSD$
#
-#include <dev/mmc/mmcreg.h>
+#include <cam/mmc/mmcreg.h>
#include <dev/mmc/bridge.h>
#
Index: sys/dev/mmc/mmcreg.h
===================================================================
--- sys/dev/mmc/mmcreg.h
+++ /dev/null
@@ -1,445 +0,0 @@
-/*-
- * Copyright (c) 2006 M. Warner Losh. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Portions of this software may have been developed with reference to
- * the SD Simplified Specification. The following disclaimer may apply:
- *
- * The following conditions apply to the release of the simplified
- * specification ("Simplified Specification") by the SD Card Association and
- * the SD Group. The Simplified Specification is a subset of the complete SD
- * Specification which is owned by the SD Card Association and the SD
- * Group. This Simplified Specification is provided on a non-confidential
- * basis subject to the disclaimers below. Any implementation of the
- * Simplified Specification may require a license from the SD Card
- * Association, SD Group, SD-3C LLC or other third parties.
- *
- * Disclaimers:
- *
- * The information contained in the Simplified Specification is presented only
- * as a standard specification for SD Cards and SD Host/Ancillary products and
- * is provided "AS-IS" without any representations or warranties of any
- * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD
- * Card Association for any damages, any infringements of patents or other
- * right of the SD Group, SD-3C LLC, the SD Card Association or any third
- * parties, which may result from its use. No license is granted by
- * implication, estoppel or otherwise under any patent or other rights of the
- * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing
- * herein shall be construed as an obligation by the SD Group, the SD-3C LLC
- * or the SD Card Association to disclose or distribute any technical
- * information, know-how or other confidential information to any third party.
- *
- * $FreeBSD$
- */
-
-#ifndef DEV_MMC_MMCREG_H
-#define DEV_MMC_MMCREG_H
-
-/*
- * This file contains the register definitions for the mmc and sd busses.
- * They are taken from publicly available sources.
- */
-
-struct mmc_data;
-struct mmc_request;
-
-struct mmc_command {
- uint32_t opcode;
- uint32_t arg;
- uint32_t resp[4];
- uint32_t flags; /* Expected responses */
-#define MMC_RSP_PRESENT (1ul << 0) /* Response */
-#define MMC_RSP_136 (1ul << 1) /* 136 bit response */
-#define MMC_RSP_CRC (1ul << 2) /* Expect valid crc */
-#define MMC_RSP_BUSY (1ul << 3) /* Card may send busy */
-#define MMC_RSP_OPCODE (1ul << 4) /* Response include opcode */
-#define MMC_RSP_MASK 0x1ful
-#define MMC_CMD_AC (0ul << 5) /* Addressed Command, no data */
-#define MMC_CMD_ADTC (1ul << 5) /* Addressed Data transfer cmd */
-#define MMC_CMD_BC (2ul << 5) /* Broadcast command, no response */
-#define MMC_CMD_BCR (3ul << 5) /* Broadcast command with response */
-#define MMC_CMD_MASK (3ul << 5)
-
-/* Possible response types defined in the standard: */
-#define MMC_RSP_NONE (0)
-#define MMC_RSP_R1 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
-#define MMC_RSP_R1B (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE | MMC_RSP_BUSY)
-#define MMC_RSP_R2 (MMC_RSP_PRESENT | MMC_RSP_136 | MMC_RSP_CRC)
-#define MMC_RSP_R3 (MMC_RSP_PRESENT)
-#define MMC_RSP_R6 (MMC_RSP_PRESENT | MMC_RSP_CRC)
-#define MMC_RSP_R7 (MMC_RSP_PRESENT | MMC_RSP_CRC)
-#define MMC_RSP(x) ((x) & MMC_RSP_MASK)
- uint32_t retries;
- uint32_t error;
-#define MMC_ERR_NONE 0
-#define MMC_ERR_TIMEOUT 1
-#define MMC_ERR_BADCRC 2
-#define MMC_ERR_FIFO 3
-#define MMC_ERR_FAILED 4
-#define MMC_ERR_INVALID 5
-#define MMC_ERR_NO_MEMORY 6
-#define MMC_ERR_MAX 6
- struct mmc_data *data; /* Data segment with cmd */
- struct mmc_request *mrq; /* backpointer to request */
-};
-
-/*
- * R1 responses
- *
- * Types (per SD 2.0 standard)
- * e : error bit
- * s : status bit
- * r : detected and set for the actual command response
- * x : Detected and set during command execution. The host can get
- * the status by issuing a command with R1 response.
- *
- * Clear Condition (per SD 2.0 standard)
- * a : according to the card current state.
- * b : always related to the previous command. reception of a valid
- * command will clear it (with a delay of one command).
- * c : clear by read
- */
-#define R1_OUT_OF_RANGE (1u << 31) /* erx, c */
-#define R1_ADDRESS_ERROR (1u << 30) /* erx, c */
-#define R1_BLOCK_LEN_ERROR (1u << 29) /* erx, c */
-#define R1_ERASE_SEQ_ERROR (1u << 28) /* er, c */
-#define R1_ERASE_PARAM (1u << 27) /* erx, c */
-#define R1_WP_VIOLATION (1u << 26) /* erx, c */
-#define R1_CARD_IS_LOCKED (1u << 25) /* sx, a */
-#define R1_LOCK_UNLOCK_FAILED (1u << 24) /* erx, c */
-#define R1_COM_CRC_ERROR (1u << 23) /* er, b */
-#define R1_ILLEGAL_COMMAND (1u << 22) /* er, b */
-#define R1_CARD_ECC_FAILED (1u << 21) /* erx, c */
-#define R1_CC_ERROR (1u << 20) /* erx, c */
-#define R1_ERROR (1u << 19) /* erx, c */
-#define R1_CSD_OVERWRITE (1u << 16) /* erx, c */
-#define R1_WP_ERASE_SKIP (1u << 15) /* erx, c */
-#define R1_CARD_ECC_DISABLED (1u << 14) /* sx, a */
-#define R1_ERASE_RESET (1u << 13) /* sr, c */
-#define R1_CURRENT_STATE_MASK (0xfu << 9) /* sx, b */
-#define R1_READY_FOR_DATA (1u << 8) /* sx, a */
-#define R1_APP_CMD (1u << 5) /* sr, c */
-#define R1_AKE_SEQ_ERROR (1u << 3) /* er, c */
-#define R1_STATUS(x) ((x) & 0xFFFFE000)
-#define R1_CURRENT_STATE(x) (((x) & R1_CURRENT_STATE_MASK) >> 9)
-#define R1_STATE_IDLE 0
-#define R1_STATE_READY 1
-#define R1_STATE_IDENT 2
-#define R1_STATE_STBY 3
-#define R1_STATE_TRAN 4
-#define R1_STATE_DATA 5
-#define R1_STATE_RCV 6
-#define R1_STATE_PRG 7
-#define R1_STATE_DIS 8
-
-struct mmc_data {
- size_t len; /* size of the data */
- size_t xfer_len;
- void *data; /* data buffer */
- uint32_t flags;
-#define MMC_DATA_WRITE (1UL << 0)
-#define MMC_DATA_READ (1UL << 1)
-#define MMC_DATA_STREAM (1UL << 2)
-#define MMC_DATA_MULTI (1UL << 3)
- struct mmc_request *mrq;
-};
-
-struct mmc_request {
- struct mmc_command *cmd;
- struct mmc_command *stop;
- void (*done)(struct mmc_request *); /* Completion function */
- void *done_data; /* requestor set data */
- uint32_t flags;
-#define MMC_REQ_DONE 1
-};
-
-/* Command definitions */
-
-/* Class 0 and 1: Basic commands & read stream commands */
-#define MMC_GO_IDLE_STATE 0
-#define MMC_SEND_OP_COND 1
-#define MMC_ALL_SEND_CID 2
-#define MMC_SET_RELATIVE_ADDR 3
-#define SD_SEND_RELATIVE_ADDR 3
-#define MMC_SET_DSR 4
- /* reserved: 5 */
-#define MMC_SWITCH_FUNC 6
-#define MMC_SWITCH_FUNC_CMDS 0
-#define MMC_SWITCH_FUNC_SET 1
-#define MMC_SWITCH_FUNC_CLR 2
-#define MMC_SWITCH_FUNC_WR 3
-#define MMC_SELECT_CARD 7
-#define MMC_DESELECT_CARD 7
-#define MMC_SEND_EXT_CSD 8
-#define SD_SEND_IF_COND 8
-#define MMC_SEND_CSD 9
-#define MMC_SEND_CID 10
-#define MMC_READ_DAT_UNTIL_STOP 11
-#define MMC_STOP_TRANSMISSION 12
-#define MMC_SEND_STATUS 13
-#define MMC_BUSTEST_R 14
-#define MMC_GO_INACTIVE_STATE 15
-#define MMC_BUSTEST_W 19
-
-/* Class 2: Block oriented read commands */
-#define MMC_SET_BLOCKLEN 16
-#define MMC_READ_SINGLE_BLOCK 17
-#define MMC_READ_MULTIPLE_BLOCK 18
- /* reserved: 19 */
-
-/* Class 3: Stream write commands */
-#define MMC_WRITE_DAT_UNTIL_STOP 20
- /* reserved: 21 */
- /* reserved: 22 */
-
-/* Class 4: Block oriented write commands */
-#define MMC_SET_BLOCK_COUNT 23
-#define MMC_WRITE_BLOCK 24
-#define MMC_WRITE_MULTIPLE_BLOCK 25
-#define MMC_PROGARM_CID 26
-#define MMC_PROGRAM_CSD 27
-
-/* Class 6: Block oriented write protection commands */
-#define MMC_SET_WRITE_PROT 28
-#define MMC_CLR_WRITE_PROT 29
-#define MMC_SEND_WRITE_PROT 30
- /* reserved: 31 */
-
-/* Class 5: Erase commands */
-#define SD_ERASE_WR_BLK_START 32
-#define SD_ERASE_WR_BLK_END 33
- /* 34 -- reserved old command */
-#define MMC_ERASE_GROUP_START 35
-#define MMC_ERASE_GROUP_END 36
- /* 37 -- reserved old command */
-#define MMC_ERASE 38
-
-/* Class 9: I/O mode commands */
-#define MMC_FAST_IO 39
-#define MMC_GO_IRQ_STATE 40
- /* reserved: 41 */
-
-/* Class 7: Lock card */
-#define MMC_LOCK_UNLOCK 42
- /* reserved: 43 */
- /* reserved: 44 */
- /* reserved: 45 */
- /* reserved: 46 */
- /* reserved: 47 */
- /* reserved: 48 */
- /* reserved: 49 */
- /* reserved: 50 */
- /* reserved: 51 */
- /* reserved: 54 */
-
-/* Class 8: Application specific commands */
-#define MMC_APP_CMD 55
-#define MMC_GEN_CMD 56
- /* reserved: 57 */
- /* reserved: 58 */
- /* reserved: 59 */
- /* reserved for mfg: 60 */
- /* reserved for mfg: 61 */
- /* reserved for mfg: 62 */
- /* reserved for mfg: 63 */
-
-/* Class 9: I/O cards (sd) */
-#define SD_IO_RW_DIRECT 52
-#define SD_IO_RW_EXTENDED 53
-
-/* Class 10: Switch function commands */
-#define SD_SWITCH_FUNC 6
- /* reserved: 34 */
- /* reserved: 35 */
- /* reserved: 36 */
- /* reserved: 37 */
- /* reserved: 50 */
- /* reserved: 57 */
-
-
-/* Application specific commands for SD */
-#define ACMD_SET_BUS_WIDTH 6
-#define ACMD_SD_STATUS 13
-#define ACMD_SEND_NUM_WR_BLOCKS 22
-#define ACMD_SET_WR_BLK_ERASE_COUNT 23
-#define ACMD_SD_SEND_OP_COND 41
-#define ACMD_SET_CLR_CARD_DETECT 42
-#define ACMD_SEND_SCR 51
-
-/*
- * EXT_CSD fields
- */
-#define EXT_CSD_ERASE_GRP_DEF 175 /* R/W */
-#define EXT_CSD_BUS_WIDTH 183 /* R/W */
-#define EXT_CSD_HS_TIMING 185 /* R/W */
-#define EXT_CSD_CARD_TYPE 196 /* RO */
-#define EXT_CSD_REV 192 /* RO */
-#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */
-#define EXT_CSD_ERASE_TO_MULT 223 /* RO */
-#define EXT_CSD_ERASE_GRP_SIZE 224 /* RO */
-
-/*
- * EXT_CSD field definitions
- */
-#define EXT_CSD_CMD_SET_NORMAL 1
-#define EXT_CSD_CMD_SET_SECURE 2
-#define EXT_CSD_CMD_SET_CPSECURE 4
-
-#define EXT_CSD_CARD_TYPE_26 1
-#define EXT_CSD_CARD_TYPE_52 2
-
-#define EXT_CSD_BUS_WIDTH_1 0
-#define EXT_CSD_BUS_WIDTH_4 1
-#define EXT_CSD_BUS_WIDTH_8 2
-
-#define MMC_TYPE_26_MAX_HS 26000000
-#define MMC_TYPE_52_MAX_HS 52000000
-
-/*
- * SD bus widths
- */
-#define SD_BUS_WIDTH_1 0
-#define SD_BUS_WIDTH_4 2
-
-/*
- * SD Switch
- */
-#define SD_SWITCH_MODE_CHECK 0
-#define SD_SWITCH_MODE_SET 1
-#define SD_SWITCH_GROUP1 0
-#define SD_SWITCH_NORMAL_MODE 0
-#define SD_SWITCH_HS_MODE 1
-#define SD_SWITCH_NOCHANGE 0xF
-
-#define SD_CLR_CARD_DETECT 0
-#define SD_SET_CARD_DETECT 1
-
-#define SD_MAX_HS 50000000
-
-/* OCR bits */
-
-/*
- * in SD 2.0 spec, bits 8-14 are now marked reserved
- * Low voltage in SD2.0 spec is bit 7, TBD voltage
- * Low voltage in MC 3.31 spec is bit 7, 1.65-1.95V
- * Specs prior to MMC 3.31 defined bits 0-7 as voltages down to 1.5V.
- * 3.31 redefined them to be reserved and also said that cards had to
- * support the 2.7-3.6V and fixed the OCR to be 0xfff8000 for high voltage
- * cards. MMC 4.0 says that a dual voltage card responds with 0xfff8080.
- * Looks like the fine-grained control of the voltage tolerance ranges
- * was abandoned.
- *
- * The MMC_OCR_CCS appears to be valid for only SD cards.
- */
-#define MMC_OCR_VOLTAGE 0x3fffffffU /* Vdd Voltage mask */
-#define MMC_OCR_LOW_VOLTAGE (1u << 7) /* Low Voltage Range -- tbd */
-#define MMC_OCR_200_210 (1U << 8) /* Vdd voltage 2.00 ~ 2.10 */
-#define MMC_OCR_MIN_VOLTAGE_SHIFT 8
-#define MMC_OCR_210_220 (1U << 9) /* Vdd voltage 2.10 ~ 2.20 */
-#define MMC_OCR_220_230 (1U << 10) /* Vdd voltage 2.20 ~ 2.30 */
-#define MMC_OCR_230_240 (1U << 11) /* Vdd voltage 2.30 ~ 2.40 */
-#define MMC_OCR_240_250 (1U << 12) /* Vdd voltage 2.40 ~ 2.50 */
-#define MMC_OCR_250_260 (1U << 13) /* Vdd voltage 2.50 ~ 2.60 */
-#define MMC_OCR_260_270 (1U << 14) /* Vdd voltage 2.60 ~ 2.70 */
-#define MMC_OCR_270_280 (1U << 15) /* Vdd voltage 2.70 ~ 2.80 */
-#define MMC_OCR_280_290 (1U << 16) /* Vdd voltage 2.80 ~ 2.90 */
-#define MMC_OCR_290_300 (1U << 17) /* Vdd voltage 2.90 ~ 3.00 */
-#define MMC_OCR_300_310 (1U << 18) /* Vdd voltage 3.00 ~ 3.10 */
-#define MMC_OCR_310_320 (1U << 19) /* Vdd voltage 3.10 ~ 3.20 */
-#define MMC_OCR_320_330 (1U << 20) /* Vdd voltage 3.20 ~ 3.30 */
-#define MMC_OCR_330_340 (1U << 21) /* Vdd voltage 3.30 ~ 3.40 */
-#define MMC_OCR_340_350 (1U << 22) /* Vdd voltage 3.40 ~ 3.50 */
-#define MMC_OCR_350_360 (1U << 23) /* Vdd voltage 3.50 ~ 3.60 */
-#define MMC_OCR_MAX_VOLTAGE_SHIFT 23
-#define MMC_OCR_CCS (1u << 30) /* Card Capacity status (SD vs SDHC) */
-#define MMC_OCR_CARD_BUSY (1U << 31) /* Card Power up status */
-
-/* CSD -- decoded structure */
-struct mmc_cid {
- uint32_t mid;
- char pnm[8];
- uint32_t psn;
- uint16_t oid;
- uint16_t mdt_year;
- uint8_t mdt_month;
- uint8_t prv;
- uint8_t fwrev;
-};
-
-struct mmc_csd
-{
- uint8_t csd_structure;
- uint8_t spec_vers;
- uint16_t ccc;
- uint16_t tacc;
- uint32_t nsac;
- uint32_t r2w_factor;
- uint32_t tran_speed;
- uint32_t read_bl_len;
- uint32_t write_bl_len;
- uint32_t vdd_r_curr_min;
- uint32_t vdd_r_curr_max;
- uint32_t vdd_w_curr_min;
- uint32_t vdd_w_curr_max;
- uint32_t wp_grp_size;
- uint32_t erase_sector;
- uint64_t capacity;
- unsigned int read_bl_partial:1,
- read_blk_misalign:1,
- write_bl_partial:1,
- write_blk_misalign:1,
- dsr_imp:1,
- erase_blk_en:1,
- wp_grp_enable:1;
-};
-
-struct mmc_scr
-{
- unsigned char sda_vsn;
- unsigned char bus_widths;
-#define SD_SCR_BUS_WIDTH_1 (1<<0)
-#define SD_SCR_BUS_WIDTH_4 (1<<2)
-};
-
-struct mmc_sd_status
-{
- uint8_t bus_width;
- uint8_t secured_mode;
- uint16_t card_type;
- uint16_t prot_area;
- uint8_t speed_class;
- uint8_t perf_move;
- uint8_t au_size;
- uint16_t erase_size;
- uint8_t erase_timeout;
- uint8_t erase_offset;
-};
-
-/*
- * Older versions of the MMC standard had a variable sector size. However,
- * I've been able to find no old MMC or SD cards that have a non 512
- * byte sector size anywhere, so we assume that such cards are very rare
- * and only note their existance in passing here...
- */
-#define MMC_SECTOR_SIZE 512
-
-#endif /* DEV_MMCREG_H */
Index: sys/dev/mmcnull/Makefile
===================================================================
--- /dev/null
+++ sys/dev/mmcnull/Makefile
@@ -0,0 +1,4 @@
+KMOD= mmcnull
+SRCS= mmcnull.c
+
+.include <bsd.kmod.mk>
Index: sys/dev/mmcnull/mmcnull.c
===================================================================
--- /dev/null
+++ sys/dev/mmcnull/mmcnull.c
@@ -0,0 +1,370 @@
+/*-
+ * Copyright (c) 2013 Ilya Bakulin. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/sysctl.h>
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_debug.h>
+#include <cam/cam_sim.h>
+#include <cam/cam_xpt_sim.h>
+#include <cam/scsi/scsi_all.h>
+
+struct mmcnull_softc {
+ device_t dev;
+ struct mtx sc_mtx;
+
+ struct cam_devq *devq;
+ struct cam_sim *sim;
+ struct cam_path *path;
+
+ struct callout tick;
+ union ccb *cur_ccb;
+};
+
+static void mmcnull_identify(driver_t *, device_t);
+static int mmcnull_probe(device_t);
+static int mmcnull_attach(device_t);
+static int mmcnull_detach(device_t);
+static void mmcnull_action(struct cam_sim *, union ccb *);
+static void mmcnull_poll(struct cam_sim *);
+
+static void
+mmcnull_callout(void *arg)
+{
+ struct mmcnull_softc *sc;
+
+ sc = (struct mmcnull_softc *)arg;
+
+ callout_reset(&sc->tick, 1, mmcnull_callout, sc);
+}
+
+static void
+mmcnull_identify(driver_t *driver, device_t parent)
+{
+ device_t child;
+
+ if (resource_disabled("mmcnull", 0))
+ return;
+
+ if (device_get_unit(parent) != 0)
+ return;
+
+ /* Avoid duplicates. */
+ if (device_find_child(parent, "mmcnull", -1))
+ return;
+
+ child = BUS_ADD_CHILD(parent, 20, "mmcnull", 0);
+ if (child == NULL) {
+ device_printf(parent, "add MMCNULL child failed\n");
+ return;
+ }
+}
+
+
+static int
+mmcnull_probe(device_t dev)
+{
+ device_set_desc(dev, "Emulated MMC controller");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+mmcnull_attach(device_t dev)
+{
+ struct mmcnull_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+
+ mtx_init(&sc->sc_mtx, "mmcnullmtx", NULL, MTX_DEF);
+
+ if ((sc->devq = cam_simq_alloc(1)) == NULL)
+ return (ENOMEM);
+
+ sc->sim = cam_sim_alloc(mmcnull_action, mmcnull_poll, "mmcnull", sc,
+ device_get_unit(dev), &sc->sc_mtx, 1, 1,
+ sc->devq);
+
+ if (sc->sim == NULL) {
+ cam_simq_free(sc->devq);
+ device_printf(dev, "cannot allocate CAM SIM\n");
+ return (EINVAL);
+ }
+
+ mtx_lock(&sc->sc_mtx);
+ if (xpt_bus_register(sc->sim, dev, 0) != 0) {
+ device_printf(dev,
+ "cannot register SCSI pass-through bus\n");
+ cam_sim_free(sc->sim, FALSE);
+ cam_simq_free(sc->devq);
+ mtx_unlock(&sc->sc_mtx);
+ return (EINVAL);
+ }
+ mtx_unlock(&sc->sc_mtx);
+
+ callout_init_mtx(&sc->tick, &sc->sc_mtx, 0); /* Callout to emulate interrupts */
+
+ device_printf(dev, "attached OK\n");
+
+ return (0);
+}
+
+static int
+mmcnull_detach(device_t dev)
+{
+ struct mmcnull_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ if (sc == NULL)
+ return (EINVAL);
+
+ if (sc->sim != NULL) {
+ mtx_lock(&sc->sc_mtx);
+ xpt_bus_deregister(cam_sim_path(sc->sim));
+ cam_sim_free(sc->sim, FALSE);
+ mtx_unlock(&sc->sc_mtx);
+ }
+
+ if (sc->devq != NULL)
+ cam_simq_free(sc->devq);
+
+ callout_drain(&sc->tick);
+ mtx_destroy(&sc->sc_mtx);
+
+ device_printf(dev, "detached OK\n");
+ return (0);
+}
+
+/*
+ * The interrupt handler
+ * This implementation calls it via callout(9)
+ * with the mutex already taken
+ */
+static void
+mmcnull_intr(void *xsc)
+{
+ struct mmcnull_softc *sc;
+ union ccb *ccb;
+ struct ccb_mmcio *mmcio;
+
+ sc = (struct mmcnull_softc *) xsc;
+ mtx_assert(&sc->sc_mtx, MA_OWNED);
+
+ ccb = sc->cur_ccb;
+ mmcio = &ccb->mmcio;
+ device_printf(sc->dev, "mmcnull_intr: MMC command = %d\n",
+ mmcio->cmd.opcode);
+
+ switch (mmcio->cmd.opcode) {
+ case MMC_GO_IDLE_STATE:
+ device_printf(sc->dev, "Reset device\n");
+ break;
+ case SD_SEND_IF_COND:
+ mmcio->cmd.resp[0] = 0x1AA; // To match mmc_xpt expectations :-)
+ break;
+ case MMC_APP_CMD:
+ mmcio->cmd.resp[0] = R1_APP_CMD;
+ break;
+ case IO_SEND_OP_COND:
+ mmcio->cmd.resp[0] = 0x12345678;
+ mmcio->cmd.resp[0] |= ~ R4_IO_MEM_PRESENT;
+ break;
+ case SD_SEND_RELATIVE_ADDR:
+ case MMC_SELECT_CARD:
+ mmcio->cmd.resp[0] = 0x1 << 16;
+ break;
+ case ACMD_SD_SEND_OP_COND:
+ /* TODO: steal valid OCR from somewhere :-) */
+ mmcio->cmd.resp[0] = 0x123;
+ mmcio->cmd.resp[0] |= MMC_OCR_CARD_BUSY;
+ break;
+ case MMC_ALL_SEND_CID:
+ mmcio->cmd.resp[0] = 0x1234;
+ mmcio->cmd.resp[1] = 0x5678;
+ mmcio->cmd.resp[2] = 0x9ABC;
+ mmcio->cmd.resp[3] = 0xDEF0;
+ break;
+ case MMC_READ_SINGLE_BLOCK:
+ case MMC_READ_MULTIPLE_BLOCK:
+ strcpy(mmcio->cmd.data->data, "WTF?!");
+ break;
+ default:
+ device_printf(sc->dev, "mmcnull_intr: unknown command\n");
+ }
+ ccb->ccb_h.status = CAM_REQ_CMP;
+
+ sc->cur_ccb = NULL;
+ xpt_done(ccb);
+}
+
+/*
+ * This is a MMC IO handler
+ * It extracts MMC command from CCB and sends it
+ * to the h/w
+ */
+static void
+mmcnull_handle_mmcio(struct cam_sim *sim, union ccb *ccb)
+{
+ struct mmcnull_softc *sc;
+ struct ccb_mmcio *mmcio;
+
+ sc = cam_sim_softc(sim);
+ mmcio = &ccb->mmcio;
+ ccb->ccb_h.status = CAM_REQ_INPROG;
+ sc->cur_ccb = ccb;
+
+ /* Real h/w will wait for the interrupt */
+ callout_reset(&sc->tick, hz * 1, mmcnull_intr, sc);
+}
+
+static void
+mmcnull_action(struct cam_sim *sim, union ccb *ccb)
+{
+ struct mmcnull_softc *sc;
+
+ sc = cam_sim_softc(sim);
+ if (sc == NULL) {
+ ccb->ccb_h.status = CAM_SEL_TIMEOUT;
+ xpt_done(ccb);
+ return;
+ }
+
+ mtx_assert(&sc->sc_mtx, MA_OWNED);
+
+ device_printf(sc->dev, "action: func_code %0x\n", ccb->ccb_h.func_code);
+
+ switch (ccb->ccb_h.func_code) {
+ case XPT_PATH_INQ:
+ {
+ struct ccb_pathinq *cpi;
+
+ cpi = &ccb->cpi;
+ cpi->version_num = 1;
+ cpi->hba_inquiry = PI_SDTR_ABLE | PI_TAG_ABLE | PI_WIDE_16;
+ cpi->target_sprt = 0;
+ cpi->hba_misc = PIM_NOBUSRESET | PIM_SEQSCAN;
+ cpi->hba_eng_cnt = 0;
+ cpi->max_target = 0;
+ cpi->max_lun = 0;
+ cpi->initiator_id = 1;
+ strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
+ strncpy(cpi->hba_vid, "Deglitch Networks", HBA_IDLEN);
+ strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
+ cpi->unit_number = cam_sim_unit(sim);
+ cpi->bus_id = cam_sim_bus(sim);
+ cpi->base_transfer_speed = 100; /* XXX WTF? */
+ cpi->protocol = PROTO_MMCSD;
+ cpi->protocol_version = SCSI_REV_0;
+ cpi->transport = XPORT_MMCSD;
+ cpi->transport_version = 0;
+
+ cpi->ccb_h.status = CAM_REQ_CMP;
+ break;
+ }
+ case XPT_GET_TRAN_SETTINGS:
+ {
+ struct ccb_trans_settings *cts = &ccb->cts;
+
+ device_printf(sc->dev, "Got XPT_GET_TRAN_SETTINGS\n");
+
+ cts->protocol = PROTO_MMCSD;
+ cts->protocol_version = 0;
+ cts->transport = XPORT_MMCSD;
+ cts->transport_version = 0;
+ cts->xport_specific.valid = 0;
+
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+ }
+ case XPT_SET_TRAN_SETTINGS:
+ device_printf(sc->dev, "Got XPT_SET_TRAN_SETTINGS, should update IOS...\n");
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+ case XPT_RESET_BUS:
+ device_printf(sc->dev, "Got XPT_RESET_BUS, ACK it...\n");
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+ case XPT_MMC_IO:
+ /*
+ * Here is the HW-dependent part of
+ * sending the command to the underlying h/w
+ * At some point in the future an interrupt comes.
+ * Then the request will be marked as completed.
+ */
+ device_printf(sc->dev, "Got XPT_MMC_IO\n");
+ mmcnull_handle_mmcio(sim, ccb);
+ return;
+ break;
+ case XPT_RESET_DEV:
+ /* This is sent by `camcontrol reset`*/
+ device_printf(sc->dev, "Got XPT_RESET_DEV\n");
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+ default:
+ device_printf(sc->dev, "Func code %d is unknown\n", ccb->ccb_h.func_code);
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ break;
+ }
+ xpt_done(ccb);
+ return;
+}
+
+static void
+mmcnull_poll(struct cam_sim *sim)
+{
+ return;
+}
+
+
+static device_method_t mmcnull_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_identify, mmcnull_identify),
+ DEVMETHOD(device_probe, mmcnull_probe),
+ DEVMETHOD(device_attach, mmcnull_attach),
+ DEVMETHOD(device_detach, mmcnull_detach),
+ DEVMETHOD_END
+};
+
+static driver_t mmcnull_driver = {
+ "mmcnull", mmcnull_methods, sizeof(struct mmcnull_softc)
+};
+
+static devclass_t mmcnull_devclass;
+
+DRIVER_MODULE(mmcnull, isa, mmcnull_driver, mmcnull_devclass, 0, 0);
Index: sys/dev/sdhci/sdhci.h
===================================================================
--- sys/dev/sdhci/sdhci.h
+++ sys/dev/sdhci/sdhci.h
@@ -286,7 +286,14 @@
struct mmc_host host; /* Host parameters */
struct mmc_request *req; /* Current request */
struct mmc_command *curcmd; /* Current command of current request */
-
+
+ /* CAM stuff */
+ union ccb *ccb;
+ struct cam_devq *devq;
+ struct cam_sim *sim;
+ struct cam_path *path;
+ struct mtx sim_mtx;
+
uint32_t intmask; /* Current interrupt mask */
uint32_t clock; /* Current clock freq. */
size_t offset; /* Data buffer offset */
@@ -320,4 +327,6 @@
void sdhci_generic_intr(struct sdhci_slot *slot);
uint32_t sdhci_generic_min_freq(device_t brdev, struct sdhci_slot *slot);
+/* CAM-related */
+void sdhci_cam_start_slot(struct sdhci_slot *slot);
#endif /* __SDHCI_H__ */
Index: sys/dev/sdhci/sdhci.c
===================================================================
--- sys/dev/sdhci/sdhci.c
+++ sys/dev/sdhci/sdhci.c
@@ -45,16 +45,22 @@
#include <machine/stdarg.h>
#include <dev/mmc/bridge.h>
-#include <dev/mmc/mmcreg.h>
+#include <cam/mmc/mmcreg.h>
#include <dev/mmc/mmcbrvar.h>
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_debug.h>
+#include <cam/cam_sim.h>
+#include <cam/cam_xpt_sim.h>
+
#include "mmcbr_if.h"
#include "sdhci.h"
#include "sdhci_if.h"
SYSCTL_NODE(_hw, OID_AUTO, sdhci, CTLFLAG_RD, 0, "sdhci driver");
-static int sdhci_debug;
+static int sdhci_debug = 10;
SYSCTL_INT(_hw_sdhci, OID_AUTO, debug, CTLFLAG_RWTUN, &sdhci_debug, 0, "Debug level");
#define RD1(slot, off) SDHCI_READ_1((slot)->bus, (slot), (off))
@@ -75,6 +81,13 @@
static void sdhci_card_task(void *, int);
+/* CAM-related */
+static int sdhci_cam_update_ios(struct sdhci_slot *slot);
+static int sdhci_cam_request(struct sdhci_slot *slot, union ccb *ccb);
+static void sdhci_cam_action(struct cam_sim *sim, union ccb *ccb);
+static void sdhci_cam_poll(struct cam_sim *sim);
+static int sdhci_cam_settran_settings(struct sdhci_slot *slot, union ccb *ccb);
+
/* helper routines */
#define SDHCI_LOCK(_slot) mtx_lock(&(_slot)->mtx)
#define SDHCI_UNLOCK(_slot) mtx_unlock(&(_slot)->mtx)
@@ -377,10 +390,10 @@
char *buffer;
size_t left;
- buffer = slot->curcmd->data->data;
+ buffer = slot->curcmd->data.data;
buffer += slot->offset;
/* Transfer one block at a time. */
- left = min(512, slot->curcmd->data->len - slot->offset);
+ left = min(512, slot->curcmd->data.len - slot->offset);
slot->offset += left;
/* If we are too fast, broken controllers return zeroes. */
@@ -420,10 +433,10 @@
char *buffer;
size_t left;
- buffer = slot->curcmd->data->data;
+ buffer = slot->curcmd->data.data;
buffer += slot->offset;
/* Transfer one block at a time. */
- left = min(512, slot->curcmd->data->len - slot->offset);
+ left = min(512, slot->curcmd->data.len - slot->offset);
slot->offset += left;
/* Handle unaligned and aligned buffer cases. */
@@ -458,18 +471,18 @@
{
/* Read as many blocks as possible. */
- if (slot->curcmd->data->flags & MMC_DATA_READ) {
+ if (slot->curcmd->data.flags & MMC_DATA_READ) {
while (RD4(slot, SDHCI_PRESENT_STATE) &
SDHCI_DATA_AVAILABLE) {
sdhci_read_block_pio(slot);
- if (slot->offset >= slot->curcmd->data->len)
+ if (slot->offset >= slot->curcmd->data.len)
break;
}
} else {
while (RD4(slot, SDHCI_PRESENT_STATE) &
SDHCI_SPACE_AVAILABLE) {
sdhci_write_block_pio(slot);
- if (slot->offset >= slot->curcmd->data->len)
+ if (slot->offset >= slot->curcmd->data.len)
break;
}
}
@@ -517,6 +530,7 @@
int err;
SDHCI_LOCK_INIT(slot);
+
slot->num = num;
slot->bus = dev;
@@ -718,12 +732,23 @@
return (slot->max_clk / SDHCI_200_MAX_DIVIDER);
}
+/*
+ * When called from the old stack:
+ sdhci_ti0: This is a bridge device
+ mmc0: This is a request device
+ sdhci_ti0-slot0: <--- The locking slot is this
+ *
+ */
int
sdhci_generic_update_ios(device_t brdev, device_t reqdev)
{
struct sdhci_slot *slot = device_get_ivars(reqdev);
struct mmc_ios *ios = &slot->host.ios;
+ device_printf(brdev, "This is a bridge device\n");
+ device_printf(reqdev, "This is a request device\n");
+
+ slot_printf(slot, " <--- The locking slot is this\n");
SDHCI_LOCK(slot);
/* Do full reset on bus power down to clear from any state. */
if (ios->power_mode == power_off) {
@@ -762,14 +787,22 @@
static void
sdhci_req_done(struct sdhci_slot *slot)
{
- struct mmc_request *req;
+ union ccb *ccb;
- if (slot->req != NULL && slot->curcmd != NULL) {
+ slot_printf(slot, "sdhci_req_done()\n");
+ if (slot->ccb != NULL && slot->curcmd != NULL) {
callout_stop(&slot->timeout_callout);
- req = slot->req;
- slot->req = NULL;
+ ccb = slot->ccb;
+ slot->ccb = NULL;
slot->curcmd = NULL;
- req->done(req);
+
+ /* Tell CAM the request is finished */
+ struct ccb_mmcio *mmcio;
+ mmcio = &ccb->mmcio;
+
+ ccb->ccb_h.status =
+ (mmcio->cmd.error == 0 ? CAM_REQ_CMP : CAM_REQ_CMP_ERR);
+ xpt_done(ccb);
}
}
@@ -788,22 +821,24 @@
slot_printf(slot, " Spurious timeout - no active command\n");
}
}
-
+
static void
sdhci_set_transfer_mode(struct sdhci_slot *slot,
struct mmc_data *data)
{
uint16_t mode;
+ struct ccb_mmcio *mmcio;
if (data == NULL)
return;
+ mmcio = &slot->ccb->mmcio;
mode = SDHCI_TRNS_BLK_CNT_EN;
if (data->len > 512)
mode |= SDHCI_TRNS_MULTI;
if (data->flags & MMC_DATA_READ)
mode |= SDHCI_TRNS_READ;
- if (slot->req->stop)
+ if (mmcio->stop.opcode == MMC_STOP_TRANSMISSION)
mode |= SDHCI_TRNS_ACMD12;
if (slot->flags & SDHCI_USE_DMA)
mode |= SDHCI_TRNS_DMA;
@@ -837,6 +872,9 @@
if ((state & SDHCI_CARD_PRESENT) == 0 ||
slot->power == 0 ||
slot->clock == 0) {
+ slot_printf(slot,
+ "Cannot issue a command (card=%d power=%d clock=%d)",
+ state, slot->power, slot->clock);
cmd->error = MMC_ERR_FAILED;
sdhci_req_done(slot);
return;
@@ -844,11 +882,13 @@
/* Always wait for free CMD bus. */
mask = SDHCI_CMD_INHIBIT;
/* Wait for free DAT if we have data or busy signal. */
- if (cmd->data || (cmd->flags & MMC_RSP_BUSY))
+ if (cmd->data.len > 0 || (cmd->flags & MMC_RSP_BUSY))
mask |= SDHCI_DAT_INHIBIT;
/* We shouldn't wait for DAT for stop commands. */
- if (cmd == slot->req->stop)
+ struct ccb_mmcio *mmcio = &slot->ccb->mmcio;
+ if (cmd == &mmcio->stop)
mask &= ~SDHCI_DAT_INHIBIT;
+
/*
* Wait for bus no more then 250 ms. Typically there will be no wait
* here at all, but when writing a crash dump we may be bypassing the
@@ -887,13 +927,13 @@
flags |= SDHCI_CMD_CRC;
if (cmd->flags & MMC_RSP_OPCODE)
flags |= SDHCI_CMD_INDEX;
- if (cmd->data)
+ if (cmd->data.len > 0)
flags |= SDHCI_CMD_DATA;
if (cmd->opcode == MMC_STOP_TRANSMISSION)
flags |= SDHCI_CMD_TYPE_ABORT;
/* Prepare data. */
sdhci_start_data(slot, cmd->data);
- /*
+ /*
* Interrupt aggregation: To reduce total number of interrupts
* group response interrupt with data interrupt when possible.
* If there going to be data interrupt, mask response one.
@@ -905,7 +945,8 @@
/* Set command argument. */
WR4(slot, SDHCI_ARGUMENT, cmd->arg);
/* Set data transfer mode. */
- sdhci_set_transfer_mode(slot, cmd->data);
+ sdhci_set_transfer_mode(slot, &cmd->data);
+ slot_printf(slot, "Starting command!\n");
/* Start command. */
WR2(slot, SDHCI_COMMAND_FLAGS, (cmd->opcode << 8) | (flags & 0xff));
/* Start timeout callout. */
@@ -918,6 +959,8 @@
{
int i;
+ slot_printf(slot, "%s: called, err %d flags %d\n",
+ __func__, slot->curcmd->error, slot->curcmd->flags);
slot->cmd_done = 1;
/* Interrupt aggregation: Restore command interrupt.
* Main restore point for the case when command interrupt
@@ -948,6 +991,10 @@
} else
slot->curcmd->resp[0] = RD4(slot, SDHCI_RESPONSE);
}
+ printf("Resp: %02x %02x %02x %02x\n",
+ slot->curcmd->resp[0], slot->curcmd->resp[1],
+ slot->curcmd->resp[2], slot->curcmd->resp[3]);
+
/* If data ready - finish. */
if (slot->data_done)
sdhci_start(slot);
@@ -959,7 +1006,7 @@
uint32_t target_timeout, current_timeout;
uint8_t div;
- if (data == NULL && (slot->curcmd->flags & MMC_RSP_BUSY) == 0) {
+ if (data->len == 0 && (slot->curcmd->flags & MMC_RSP_BUSY) == 0) {
slot->data_done = 1;
return;
}
@@ -1028,12 +1075,19 @@
SDHCI_MAKE_BLKSZ(DMA_BOUNDARY, (data->len < 512)?data->len:512));
/* Set block count. */
WR2(slot, SDHCI_BLOCK_COUNT, (data->len + 511) / 512);
+
+ slot_printf(slot, "Block size: %02x, count %d\n",
+ SDHCI_MAKE_BLKSZ(DMA_BOUNDARY, (data->len < 512)?data->len:512),
+ (data->len + 511) / 512);
}
void
sdhci_finish_data(struct sdhci_slot *slot)
{
- struct mmc_data *data = slot->curcmd->data;
+ struct mmc_data *data = &slot->curcmd->data;
+
+ slot_printf(slot, "%s: called, err %d flags %d\n",
+ __func__, slot->curcmd->error, slot->curcmd->flags);
/* Interrupt aggregation: Restore command interrupt.
* Auxiliary restore point for the case when data interrupt
@@ -1070,27 +1124,30 @@
static void
sdhci_start(struct sdhci_slot *slot)
{
- struct mmc_request *req;
+ union ccb *ccb;
- req = slot->req;
- if (req == NULL)
+ ccb = slot->ccb;
+ if (ccb == NULL)
return;
+ struct ccb_mmcio *mmcio;
+ mmcio = &ccb->mmcio;
+
if (!(slot->flags & CMD_STARTED)) {
slot->flags |= CMD_STARTED;
- sdhci_start_command(slot, req->cmd);
+ sdhci_start_command(slot, &mmcio->cmd);
return;
}
-/* We don't need this until using Auto-CMD12 feature
- if (!(slot->flags & STOP_STARTED) && req->stop) {
+
+ if (!(slot->flags & STOP_STARTED) && mmcio->stop.opcode != 0) {
slot->flags |= STOP_STARTED;
- sdhci_start_command(slot, req->stop);
+ sdhci_start_command(slot, &mmcio->stop);
return;
}
-*/
+
if (sdhci_debug > 1)
- slot_printf(slot, "result: %d\n", req->cmd->error);
- if (!req->cmd->error &&
+ slot_printf(slot, "result: %d\n", mmcio->cmd.error);
+ if (mmcio->cmd.error == 0 &&
(slot->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST)) {
sdhci_reset(slot, SDHCI_RESET_CMD);
sdhci_reset(slot, SDHCI_RESET_DATA);
@@ -1111,9 +1168,9 @@
}
if (sdhci_debug > 1) {
slot_printf(slot, "CMD%u arg %#x flags %#x dlen %u dflags %#x\n",
- req->cmd->opcode, req->cmd->arg, req->cmd->flags,
- (req->cmd->data)?(u_int)req->cmd->data->len:0,
- (req->cmd->data)?req->cmd->data->flags:0);
+ req->cmd->opcode, req->cmd->arg, req->cmd->flags,
+ req->cmd->data.len,
+ req->cmd->data.flags);
}
slot->req = req;
slot->flags = 0;
@@ -1200,7 +1257,7 @@
sdhci_dumpregs(slot);
return;
}
- if (slot->curcmd->data == NULL &&
+ if (slot->curcmd->data.len == 0 &&
(slot->curcmd->flags & MMC_RSP_BUSY) == 0) {
slot_printf(slot, "Got data interrupt 0x%08x, but "
"there is no active data operation.\n",
@@ -1212,7 +1269,7 @@
slot->curcmd->error = MMC_ERR_TIMEOUT;
else if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT))
slot->curcmd->error = MMC_ERR_BADCRC;
- if (slot->curcmd->data == NULL &&
+ if (slot->curcmd->data.len == 0 &&
(intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL |
SDHCI_INT_DMA_END))) {
slot_printf(slot, "Got data interrupt 0x%08x, but "
@@ -1236,7 +1293,7 @@
}
/* Handle DMA border. */
if (intmask & SDHCI_INT_DMA_END) {
- struct mmc_data *data = slot->curcmd->data;
+ struct mmc_data *data = &slot->curcmd->data;
size_t left;
/* Unload DMA buffer... */
@@ -1375,7 +1432,7 @@
intmask);
sdhci_dumpregs(slot);
}
-
+
SDHCI_UNLOCK(slot);
}
@@ -1438,6 +1495,7 @@
{
struct sdhci_slot *slot = device_get_ivars(child);
+ slot_printf(slot, "sdhci_generic_write_ivar, var=%d\n", which);
switch (which) {
default:
return (EINVAL);
@@ -1505,4 +1563,269 @@
return (0);
}
+/* CAM-related functions */
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_debug.h>
+#include <cam/cam_sim.h>
+#include <cam/cam_xpt_sim.h>
+
+void
+sdhci_cam_start_slot(struct sdhci_slot *slot)
+{
+// sdhci_card_task(slot, 0);
+ if ((slot->devq = cam_simq_alloc(1)) == NULL) {
+ goto fail;
+ }
+
+ mtx_init(&slot->sim_mtx, "sdhcisim", NULL, MTX_DEF);
+ slot->sim = cam_sim_alloc(sdhci_cam_action, sdhci_cam_poll,
+ "sdhci_slot", slot, device_get_unit(slot->bus),
+ &slot->sim_mtx, 1, 1, slot->devq);
+
+ if (slot->sim == NULL) {
+ cam_simq_free(slot->devq);
+ slot_printf(slot, "cannot allocate CAM SIM\n");
+ goto fail;
+ }
+
+ mtx_lock(&slot->sim_mtx);
+ if (xpt_bus_register(slot->sim, slot->bus, 0) != 0) {
+ slot_printf(slot,
+ "cannot register SCSI pass-through bus\n");
+ cam_sim_free(slot->sim, FALSE);
+ cam_simq_free(slot->devq);
+ mtx_unlock(&slot->sim_mtx);
+ goto fail;
+ }
+
+ mtx_unlock(&slot->sim_mtx);
+ /* End CAM-specific init */
+ return;
+
+fail:
+ if (slot->sim != NULL) {
+ mtx_lock(&slot->sim_mtx);
+ xpt_bus_deregister(cam_sim_path(slot->sim));
+ cam_sim_free(slot->sim, FALSE);
+ mtx_unlock(&slot->sim_mtx);
+ }
+
+ if (slot->devq != NULL)
+ cam_simq_free(slot->devq);
+}
+
+static void
+sdhci_cam_handle_mmcio(struct cam_sim *sim, union ccb *ccb)
+{
+ struct sdhci_slot *slot;
+
+ slot = cam_sim_softc(sim);
+
+ sdhci_cam_request(slot, ccb);
+}
+
+void
+sdhci_cam_action(struct cam_sim *sim, union ccb *ccb)
+{
+ struct sdhci_slot *slot;
+
+ slot = cam_sim_softc(sim);
+ if (slot == NULL) {
+ ccb->ccb_h.status = CAM_SEL_TIMEOUT;
+ xpt_done(ccb);
+ return;
+ }
+
+ mtx_assert(&slot->sim_mtx, MA_OWNED);
+
+ slot_printf(slot, "action: func_code %0x\n", ccb->ccb_h.func_code);
+
+ switch (ccb->ccb_h.func_code) {
+ case XPT_PATH_INQ:
+ {
+ struct ccb_pathinq *cpi;
+
+ cpi = &ccb->cpi;
+ cpi->version_num = 1;
+ cpi->hba_inquiry = 0;
+ cpi->target_sprt = 0;
+ cpi->hba_misc = PIM_NOBUSRESET | PIM_SEQSCAN;
+ cpi->hba_eng_cnt = 0;
+ cpi->max_target = 0;
+ cpi->max_lun = 0;
+ cpi->initiator_id = 1;
+ strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
+ strncpy(cpi->hba_vid, "Deglitch Networks", HBA_IDLEN);
+ strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
+ cpi->unit_number = cam_sim_unit(sim);
+ cpi->bus_id = cam_sim_bus(sim);
+ cpi->base_transfer_speed = 100; /* XXX WTF? */
+ cpi->protocol = PROTO_MMCSD;
+ cpi->protocol_version = SCSI_REV_0;
+ cpi->transport = XPORT_MMCSD;
+ cpi->transport_version = 0;
+
+ cpi->ccb_h.status = CAM_REQ_CMP;
+ break;
+ }
+ case XPT_GET_TRAN_SETTINGS:
+ {
+ struct ccb_trans_settings *cts = &ccb->cts;
+
+ slot_printf(slot, "Got XPT_GET_TRAN_SETTINGS\n");
+
+ cts->protocol = PROTO_MMCSD;
+ cts->protocol_version = 0;
+ cts->transport = XPORT_MMCSD;
+ cts->transport_version = 0;
+ cts->xport_specific.valid = 0;
+ cts->proto_specific.mmc.host_ocr = slot->host.host_ocr;
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+ }
+ case XPT_SET_TRAN_SETTINGS:
+ slot_printf(slot, "Got XPT_SET_TRAN_SETTINGS, should update IOS...\n");
+ sdhci_cam_settran_settings(slot, ccb); /* ah wtf with ti_sdhci ?!*/
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+ case XPT_RESET_BUS:
+ slot_printf(slot, "Got XPT_RESET_BUS, ACK it...\n");
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+ case XPT_MMC_IO:
+ /*
+ * Here is the HW-dependent part of
+ * sending the command to the underlying h/w
+ * At some point in the future an interrupt comes.
+ * Then the request will be marked as completed.
+ */
+ slot_printf(slot, "Got XPT_MMC_IO\n");
+ ccb->ccb_h.status = CAM_REQ_INPROG;
+
+ sdhci_cam_handle_mmcio(sim, ccb);
+ return;
+ /* NOTREACHED */
+ break;
+ default:
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ break;
+ }
+ xpt_done(ccb);
+ return;
+}
+
+void
+sdhci_cam_poll(struct cam_sim *sim)
+{
+ return;
+}
+
+int
+sdhci_cam_settran_settings(struct sdhci_slot *slot, union ccb *ccb)
+{
+ struct mmc_ios *ios;
+ struct mmc_ios *new_ios;
+ struct ccb_trans_settings_mmc *cts;
+
+ ios = &slot->host.ios;
+
+ cts = &ccb->cts.proto_specific.mmc;
+ new_ios = &cts->ios;
+
+ /* Update only requested fields */
+ if (cts->ios_valid & MMC_CLK)
+ ios->clock = new_ios->clock;
+ if (cts->ios_valid & MMC_VDD) {
+ ios->vdd = new_ios->vdd;
+ slot_printf(slot, "VDD => %d\n", ios->vdd);
+ }
+ if (cts->ios_valid & MMC_CS)
+ ios->chip_select = new_ios->chip_select;
+ if (cts->ios_valid & MMC_BW)
+ ios->bus_width = new_ios->bus_width;
+ if (cts->ios_valid & MMC_PM)
+ ios->power_mode = new_ios->power_mode;
+ if (cts->ios_valid & MMC_BT)
+ ios->timing = new_ios->timing;
+ if (cts->ios_valid & MMC_BM)
+ ios->bus_mode = new_ios->bus_mode;
+
+ /* XXX Provide a way to call a chip-specific IOS update, required for TI */
+ return (sdhci_cam_update_ios(slot));
+}
+
+int
+sdhci_cam_update_ios(struct sdhci_slot *slot)
+{
+ struct mmc_ios *ios = &slot->host.ios;
+
+ slot_printf(slot, " <--- The locking slot is this\n");
+ SDHCI_LOCK(slot);
+ /* Do full reset on bus power down to clear from any state. */
+ if (ios->power_mode == power_off) {
+ WR4(slot, SDHCI_SIGNAL_ENABLE, 0);
+ sdhci_init(slot);
+ }
+ /* Configure the bus. */
+ sdhci_set_clock(slot, ios->clock);
+ sdhci_set_power(slot, (ios->power_mode == power_off) ? 0 : ios->vdd);
+ if (ios->bus_width == bus_width_8) {
+ slot->hostctrl |= SDHCI_CTRL_8BITBUS;
+ slot->hostctrl &= ~SDHCI_CTRL_4BITBUS;
+ } else if (ios->bus_width == bus_width_4) {
+ slot->hostctrl &= ~SDHCI_CTRL_8BITBUS;
+ slot->hostctrl |= SDHCI_CTRL_4BITBUS;
+ } else if (ios->bus_width == bus_width_1) {
+ slot->hostctrl &= ~SDHCI_CTRL_8BITBUS;
+ slot->hostctrl &= ~SDHCI_CTRL_4BITBUS;
+ } else {
+ panic("Invalid bus width: %d", ios->bus_width);
+ }
+ if (ios->timing == bus_timing_hs &&
+ !(slot->quirks & SDHCI_QUIRK_DONT_SET_HISPD_BIT))
+ slot->hostctrl |= SDHCI_CTRL_HISPD;
+ else
+ slot->hostctrl &= ~SDHCI_CTRL_HISPD;
+ WR1(slot, SDHCI_HOST_CONTROL, slot->hostctrl);
+ /* Some controllers like reset after bus changes. */
+ if(slot->quirks & SDHCI_QUIRK_RESET_ON_IOS)
+ sdhci_reset(slot, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+
+ SDHCI_UNLOCK(slot);
+ return (0);
+}
+
+int
+sdhci_cam_request(struct sdhci_slot *slot, union ccb *ccb)
+{
+ struct ccb_mmcio *mmcio;
+
+ mmcio = &ccb->mmcio;
+
+ SDHCI_LOCK(slot);
+/* if (slot->req != NULL) {
+ SDHCI_UNLOCK(slot);
+ return (EBUSY);
+ }
+*/
+ if (sdhci_debug > 1) {
+ slot_printf(slot, "CMD%u arg %#x flags %#x dlen %u dflags %#x\n",
+ mmcio->cmd.opcode, mmcio->cmd.arg, mmcio->cmd.flags,
+ mmcio->cmd.data.len,
+ mmcio->cmd.data.flags);
+ }
+ slot->ccb = ccb;
+ slot->flags = 0;
+ sdhci_start(slot);
+ SDHCI_UNLOCK(slot);
+ if (dumping) {
+ while (slot->ccb != NULL) {
+ sdhci_generic_intr(slot);
+ DELAY(10);
+ }
+ }
+ return (0);
+}
+
MODULE_VERSION(sdhci, 1);
Index: sys/dev/sdhci/sdhci_if.m
===================================================================
--- sys/dev/sdhci/sdhci_if.m
+++ sys/dev/sdhci/sdhci_if.m
@@ -68,7 +68,7 @@
#include <machine/bus.h>
#include <dev/mmc/bridge.h>
-#include <dev/mmc/mmcreg.h>
+#include <cam/mmc/mmcreg.h>
#include <dev/sdhci/sdhci.h>
CODE {
Index: sys/dev/sdhci/sdhci_pci.c
===================================================================
--- sys/dev/sdhci/sdhci_pci.c
+++ sys/dev/sdhci/sdhci_pci.c
@@ -355,7 +355,7 @@
for (i = 0; i < sc->num_slots; i++) {
struct sdhci_slot *slot = &sc->slots[i];
- sdhci_start_slot(slot);
+ sdhci_cam_start_slot(slot);
}
return (0);
Index: sys/modules/mmcnull/Makefile
===================================================================
--- /dev/null
+++ sys/modules/mmcnull/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../dev/mmcnull
+
+KMOD= mmcnull
+SRCS= mmcnull.c device_if.h bus_if.h
+
+.include <bsd.kmod.mk>
Index: usr.bin/Makefile
===================================================================
--- usr.bin/Makefile
+++ usr.bin/Makefile
@@ -134,6 +134,7 @@
rusers \
rwall \
script \
+ sdiotool \
sed \
send-pr \
seq \
Index: usr.bin/sdiotool/Makefile
===================================================================
--- /dev/null
+++ usr.bin/sdiotool/Makefile
@@ -0,0 +1,7 @@
+PROG= sdiotool
+SRCS= sdiotool.c
+
+LIBADD= cam util
+NO_MAN= 1
+
+.include <bsd.prog.mk>
Index: usr.bin/sdiotool/sdiotool.c
===================================================================
--- /dev/null
+++ usr.bin/sdiotool/sdiotool.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2016 Ilya Bakulin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/ioctl.h>
+#include <sys/stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/endian.h>
+#include <sys/sbuf.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <err.h>
+#include <libutil.h>
+
+#include <cam/cam.h>
+#include <cam/cam_debug.h>
+#include <cam/cam_ccb.h>
+#include <cam/mmc/mmc_all.h>
+#include <camlib.h>
+
+static int sdio_rw_direct(struct cam_device *dev,
+ uint8_t func_number,
+ uint32_t addr,
+ uint8_t is_write,
+ uint8_t *data);
+
+/* Use CMD52 to read or write a single byte */
+int
+sdio_rw_direct(struct cam_device *dev,
+ uint8_t func_number,
+ uint32_t addr,
+ uint8_t is_write,
+ uint8_t *data) {
+ union ccb *ccb;
+ uint32_t flags;
+ uint32_t arg;
+
+ ccb = cam_getccb(dev);
+ if (ccb == NULL) {
+ warnx("%s: error allocating CCB", __func__);
+ return (1);
+ }
+ bzero(&(&ccb->ccb_h)[1],
+ sizeof(union ccb) - sizeof(struct ccb_hdr));
+
+ flags = MMC_RSP_R5 | MMC_CMD_AC;
+ arg = SD_IO_RW_FUNC(func_number) | SD_IO_RW_ADR(addr);
+ if (is_write)
+ arg |= SD_IO_RW_WR | SD_IO_RW_RAW | SD_IO_RW_DAT(*data);
+
+ cam_fill_mmcio(&ccb->mmcio,
+ /*retries*/ 0,
+ /*cbfcnp*/ NULL,
+ /*flags*/ flags,
+ /*mmc_opcode*/ SD_IO_RW_DIRECT,
+ /*mmc_arg*/ arg,
+ /*mmc_flags*/ flags,
+ /*mmc_data*/ 0,
+ /*timeout*/ 5000);
+
+ if (((retval = cam_send_ccb(device, ccb)) < 0)
+ || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
+ const char warnstr[] = "error sending command";
+
+ if (retval < 0)
+ warn(warnstr);
+ else
+ warnx(warnstr);
+ }
+
+ cam_freeccb(ccb);
+ return 0;
+}
+
+int
+main(__unused int argc, __unused char **argv) {
+ char device[] = "pass";
+ int unit = 0;
+ struct cam_device *cam_dev = NULL;
+ if ((cam_dev = cam_open_spec_device(device, unit, O_RDWR, NULL)) == NULL)
+ errx(1, "Cannot open device");
+
+ cam_close_spec_device(cam_dev);
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Jan 15, 6:20 AM (12 h, 26 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27644866
Default Alt Text
D4761.id.diff (198 KB)
Attached To
Mode
D4761: MMC stack on top of CAM framework
Attached
Detach File
Event Timeline
Log In to Comment