Page MenuHomeFreeBSD

D4761.id.diff
No OneTemporary

D4761.id.diff

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

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)

Event Timeline