Page MenuHomeFreeBSD

D862.id.diff
No OneTemporary

D862.id.diff

Index: etc/mtree/BSD.include.dist
===================================================================
--- etc/mtree/BSD.include.dist
+++ etc/mtree/BSD.include.dist
@@ -90,6 +90,8 @@
..
scsi
..
+ mmc
+ ..
..
clang
3.4.1
@@ -230,7 +232,7 @@
gssapi
..
infiniband
- complib
+ complib
..
iba
..
Index: include/Makefile
===================================================================
--- include/Makefile
+++ include/Makefile
@@ -39,7 +39,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/scsi cam/mmc \
dev/acpica dev/agp dev/an dev/bktr dev/ciss dev/filemon dev/firewire \
dev/hwpmc \
dev/ic dev/iicbus ${_dev_ieee488} dev/io dev/lmc dev/mfi dev/nvme \
Index: lib/libcam/Makefile
===================================================================
--- lib/libcam/Makefile
+++ lib/libcam/Makefile
@@ -37,7 +37,7 @@
cam_cdbparse.3 buff_encode_visit.3
.PATH: ${.CURDIR}/../../sys/cam/scsi ${.CURDIR}/../../sys/cam/ata \
- ${.CURDIR}/../../sys/cam
+ ${.CURDIR}/../../sys/cam ${.CURDIR}/../../sys/cam/mmc
SDIR= ${.CURDIR}/../../sys
CFLAGS+= -I${.CURDIR} -I${SDIR}
Index: sys/Makefile
===================================================================
--- sys/Makefile
+++ sys/Makefile
@@ -56,7 +56,7 @@
# You need the devel/global and one of editor/emacs* ports for that.
TAGS ${.CURDIR}/TAGS: ${.CURDIR}/cscope.files
rm -f ${.CURDIR}/TAGS
- cd ${.CURDIR}; xargs etags -a < ${.CURDIR}/cscope.files
+ cd ${.CURDIR}; xargs exctags -ea < ${.CURDIR}/cscope.files
# You need the textproc/glimpse ports for this.
glimpse:
Index: sys/amd64/conf/GENERIC
===================================================================
--- sys/amd64/conf/GENERIC
+++ sys/amd64/conf/GENERIC
@@ -356,4 +356,5 @@
device xenpci # Xen HVM Hypervisor services driver
# VMware support
+options CAM_DEBUG_COMPILE=65535
device vmx # VMware VMXNET3 Ethernet
Index: sys/arm/conf/BEAGLEBONE
===================================================================
--- sys/arm/conf/BEAGLEBONE
+++ sys/arm/conf/BEAGLEBONE
@@ -72,12 +72,12 @@
options NFSLOCKD
# Uncomment this for NFS root
-#options NFS_ROOT # NFS usable as /, requires NFSCL
-#options BOOTP_NFSROOT
-#options BOOTP_COMPAT
-#options BOOTP
-#options BOOTP_NFSV3
-#options BOOTP_WIRED_TO=cpsw0
+options NFS_ROOT # NFS usable as /, requires NFSCL
+options BOOTP_NFSROOT
+options BOOTP_COMPAT
+options BOOTP
+options BOOTP_NFSV3
+options BOOTP_WIRED_TO=cpsw0
# MMC/SD/SDIO Card slot support
device mmc # mmc/sd bus
@@ -139,3 +139,6 @@
options FDT
options FDT_DTB_STATIC
makeoptions FDT_DTS_FILE=beaglebone.dts
+
+options CAMDEBUG
+options CAM_DEBUG_FLAGS=(CAM_DEBUG_INFO|CAM_DEBUG_PROBE|CAM_DEBUG_PERIPH|CAM_DEBUG_TRACE)
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>
@@ -52,6 +54,13 @@
#include <dev/mmc/mmcreg.h>
#include <dev/mmc/mmcbrvar.h>
+/* CAM includes */
+#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 <dev/sdhci/sdhci.h>
#include "sdhci_if.h"
@@ -75,6 +84,11 @@
uint32_t sdhci_clkdiv;
boolean_t disable_highspeed;
boolean_t force_card_present;
+
+ struct mtx sc_mtx;
+ struct cam_devq *devq;
+ struct cam_sim *sim;
+ struct cam_path *path;
};
/*
@@ -120,6 +134,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)
{
@@ -607,7 +626,39 @@
bus_generic_probe(dev);
bus_generic_attach(dev);
- sdhci_start_slot(&sc->slot);
+// sdhci_start_slot(&sc->slot);
+
+ /* CAM-specific init */
+ mtx_init(&sc->sc_mtx, "tisdhcimtx", NULL, MTX_DEF);
+
+ if ((sc->devq = cam_simq_alloc(1)) == NULL) {
+ err = ENOMEM;
+ goto fail;
+ }
+
+ sc->sim = cam_sim_alloc(ti_sdhci_cam_action, ti_sdhci_cam_poll,
+ "ti_sdhci", 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");
+ err = EINVAL;
+ goto fail;
+ }
+
+ 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);
+ err = EINVAL;
+ goto fail;
+ }
+ mtx_unlock(&sc->sc_mtx);
+ /* End CAM-specific init */
return (0);
@@ -619,6 +670,16 @@
if (sc->mem_res)
bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
+ 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);
+
return (err);
}
@@ -637,6 +698,160 @@
return (ENXIO);
}
+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));
+}
+
static device_method_t ti_sdhci_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, ti_sdhci_probe),
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 */
@@ -223,6 +224,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 ATA I/O operation */
/* Vendor Unique codes: 0x80->0x8F */
XPT_VUNIQUE = 0x80
@@ -249,6 +252,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 {
@@ -264,6 +268,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)
@@ -739,6 +744,15 @@
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 ccb_accept_tio {
struct ccb_hdr ccb_h;
cdb_t cdb_io; /* Union for CDB bytes/pointer */
@@ -940,6 +954,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;
@@ -952,6 +986,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 */
@@ -1203,6 +1238,7 @@
struct ccb_ataio ataio;
struct ccb_dev_advinfo cdai;
struct ccb_async casync;
+ struct ccb_mmcio mmcio;
};
__BEGIN_DECLS
Index: sys/cam/cam_xpt.c
===================================================================
--- sys/cam/cam_xpt.c
+++ sys/cam/cam_xpt.c
@@ -385,7 +385,7 @@
}
return (error);
}
-
+
static int
xptdoioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
{
@@ -1022,6 +1022,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) {
@@ -1075,6 +1077,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)
@@ -1315,7 +1319,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);
@@ -2494,6 +2498,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:
@@ -3898,6 +3903,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
@@ -88,6 +88,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
@@ -165,6 +166,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,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$
+ */
+
+#ifndef CAM_MMC_H
+#define CAM_MMC_H
+
+/*
+ * This structure describes an MMC/SD card
+ */
+struct mmc_params {
+ u_int8_t model[40]; /* Card model */
+} __packed;
+
+#endif
Index: sys/cam/mmc/mmc_all.h
===================================================================
--- /dev/null
+++ sys/cam/mmc/mmc_all.h
@@ -0,0 +1,70 @@
+/*-
+ * 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$
+ */
+
+/*
+ * 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,138 @@
+/*-
+ * 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_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_xpt.c
===================================================================
--- /dev/null
+++ sys/cam/mmc/mmc_xpt.c
@@ -0,0 +1,1116 @@
+/*-
+ * 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 <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_bus(struct cam_periph *periph, union ccb *ccb);
+static void mmc_scan_lun(struct cam_periph *periph,
+ struct cam_path *path, cam_flags flags,
+ union ccb *ccb);
+static void xptscandone(struct cam_periph *periph, union ccb *done_ccb);
+
+/* Supplementary methods */
+static void mmc_build_app_op_cond(union ccb *ccb, uint32_t ocr);
+
+/* 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);
+
+static struct xpt_xport mmc_xport = {
+ .alloc_device = mmc_alloc_device,
+ .action = mmc_action,
+ .async = mmc_dev_async,
+ .announce = mmc_announce_periph,
+};
+
+struct xpt_xport *
+mmc_get_xport(void)
+{
+ return (&mmc_xport);
+}
+
+static void
+xptscandone(struct cam_periph *periph, union ccb *done_ccb)
+{
+
+ xpt_free_path(done_ccb->ccb_h.path);
+ xpt_free_ccb(done_ccb);
+}
+
+/* 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)
+{
+ cam_status status;
+ struct cam_path newpath;
+
+ printf("mmc_dev_async(async_code=0x%x, path_id=%d, target_id=%x, lun_id=%" PRIu64 "\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;
+
+ /*
+ * We need our own path with wildcards expanded to
+ * handle certain types of events.
+ */
+ if ((async_code == AC_SENT_BDR)
+ || (async_code == AC_BUS_RESET)
+ || (async_code == AC_INQ_CHANGED))
+ status = xpt_compile_path(&newpath, NULL,
+ bus->path_id,
+ target->target_id,
+ device->lun_id);
+ else
+ status = CAM_REQ_CMP_ERR;
+
+ printf("mmc_async: status = 0x%x\n", status);
+
+ if (status == CAM_REQ_CMP) {
+ if (async_code == AC_INQ_CHANGED) {
+ /*
+ * We've sent a start unit command, or
+ * something similar to a device that
+ * may have caused its inquiry data to
+ * change. So we re-scan the device to
+ * refresh the inquiry data for it.
+ */
+ mmc_scan_lun(newpath.periph, &newpath,
+ CAM_EXPECT_INQ_CHANGE, NULL);
+ } else {
+ /* We need to reinitialize device after reset. */
+ mmc_scan_lun(newpath.periph, &newpath,
+ 0, NULL);
+ }
+ xpt_release_path(&newpath);
+ } else if (async_code == AC_LOST_DEVICE &&
+ (device->flags & CAM_DEV_UNCONFIGURED) == 0) {
+ device->flags |= CAM_DEV_UNCONFIGURED;
+ xpt_release_device(device);
+ } else if (async_code == AC_TRANSFER_NEG) {
+ struct ccb_trans_settings *settings;
+ struct cam_path path;
+
+ printf("AC_TRANSFER_NEG\n");
+ settings = (struct ccb_trans_settings *)async_arg;
+ xpt_compile_path(&path, NULL, bus->path_id, target->target_id,
+ device->lun_id);
+/* ata_set_transfer_settings(settings, &path, TRUE); */
+ xpt_release_path(&path);
+ }
+}
+
+typedef struct {
+ union ccb *request_ccb;
+ struct ccb_pathinq *cpi;
+ int counter;
+} mmc_scan_bus_info;
+
+static void
+mmc_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
+{
+ struct cam_path *path;
+ union ccb *work_ccb, *reset_ccb;
+ mmc_scan_bus_info *scan_info;
+ struct mtx *mtx;
+ cam_status status;
+
+ CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_INFO,
+ ("mmc_scan_bus! func_code=%x\n", request_ccb->ccb_h.func_code));
+
+ switch (request_ccb->ccb_h.func_code) {
+ case XPT_SCAN_BUS:
+ CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("XPT_SCAN_BUS\n"));
+ case XPT_SCAN_TGT:
+ CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("XPT_SCAN_TGT\n"));
+ /* Find out the characteristics of the bus */
+ work_ccb = xpt_alloc_ccb_nowait();
+ if (work_ccb == NULL) {
+ request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+ xpt_done(request_ccb);
+ return;
+ }
+ xpt_setup_ccb(&work_ccb->ccb_h, request_ccb->ccb_h.path,
+ request_ccb->ccb_h.pinfo.priority);
+ work_ccb->ccb_h.func_code = XPT_PATH_INQ;
+ xpt_action(work_ccb);
+ if (work_ccb->ccb_h.status != CAM_REQ_CMP) {
+ request_ccb->ccb_h.status = work_ccb->ccb_h.status;
+ xpt_free_ccb(work_ccb);
+ xpt_done(request_ccb);
+ return;
+ }
+
+ /* We may need to reset bus first, if we haven't done it yet. */
+ if (!(work_ccb->cpi.hba_misc & PIM_NOBUSRESET) &&
+ !timevalisset(&request_ccb->ccb_h.path->bus->last_reset)) {
+ reset_ccb = xpt_alloc_ccb_nowait();
+ if (reset_ccb == NULL) {
+ request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+ xpt_free_ccb(work_ccb);
+ xpt_done(request_ccb);
+ return;
+ }
+ xpt_setup_ccb(&reset_ccb->ccb_h, request_ccb->ccb_h.path,
+ CAM_PRIORITY_NONE);
+ reset_ccb->ccb_h.func_code = XPT_RESET_BUS;
+ xpt_action(reset_ccb);
+ if (reset_ccb->ccb_h.status != CAM_REQ_CMP) {
+ request_ccb->ccb_h.status = reset_ccb->ccb_h.status;
+ xpt_free_ccb(reset_ccb);
+ xpt_free_ccb(work_ccb);
+ xpt_done(request_ccb);
+ return;
+ }
+ xpt_free_ccb(reset_ccb);
+ }
+
+ /* Save some state for use while we probe for devices */
+ scan_info = (mmc_scan_bus_info *)
+ malloc(sizeof(mmc_scan_bus_info), M_CAMXPT, M_NOWAIT);
+ if (scan_info == NULL) {
+ request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+ xpt_free_ccb(work_ccb);
+ xpt_done(request_ccb);
+ return;
+ }
+ scan_info->request_ccb = request_ccb;
+ scan_info->cpi = &work_ccb->cpi;
+ scan_info->counter = 0;
+
+ work_ccb = xpt_alloc_ccb_nowait();
+ if (work_ccb == NULL) {
+ free(scan_info, M_CAMXPT);
+ request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+ xpt_done(request_ccb);
+ break;
+ }
+ mtx = xpt_path_mtx(scan_info->request_ccb->ccb_h.path);
+ goto scan_next;
+
+ case XPT_SCAN_LUN:
+ CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("XPT_SCAN_LUN\n"));
+ work_ccb = request_ccb;
+ /* Reuse the same CCB to query if a device was really found */
+ scan_info = (mmc_scan_bus_info *)work_ccb->ccb_h.ppriv_ptr0;
+ mtx = xpt_path_mtx(scan_info->request_ccb->ccb_h.path);
+ mtx_lock(mtx);
+ /* Free the current request path- we're done with it. */
+ xpt_free_path(work_ccb->ccb_h.path);
+ mtx_unlock(mtx);
+ xpt_free_ccb(work_ccb);
+ xpt_free_ccb((union ccb *)scan_info->cpi);
+ request_ccb = scan_info->request_ccb;
+ free(scan_info, M_CAMXPT);
+ request_ccb->ccb_h.status = CAM_REQ_CMP;
+ xpt_done(request_ccb);
+ CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("SCAN_LUN -- done with it\n"));
+ return;
+
+scan_next:
+ status = xpt_create_path(&path, NULL,
+ scan_info->request_ccb->ccb_h.path_id, 0, 0);
+ if (status != CAM_REQ_CMP) {
+ if (request_ccb->ccb_h.func_code == XPT_SCAN_LUN)
+ mtx_unlock(mtx);
+ printf("xpt_scan_bus: xpt_create_path failed"
+ " with status %#x, bus scan halted\n",
+ status);
+ xpt_free_ccb(work_ccb);
+ xpt_free_ccb((union ccb *)scan_info->cpi);
+ request_ccb = scan_info->request_ccb;
+ free(scan_info, M_CAMXPT);
+ request_ccb->ccb_h.status = status;
+ xpt_done(request_ccb);
+ break;
+ }
+ xpt_setup_ccb(&work_ccb->ccb_h, path,
+ scan_info->request_ccb->ccb_h.pinfo.priority);
+ work_ccb->ccb_h.func_code = XPT_SCAN_LUN;
+ work_ccb->ccb_h.cbfcnp = mmc_scan_bus;
+ work_ccb->ccb_h.flags |= CAM_UNLOCKED;
+ work_ccb->ccb_h.ppriv_ptr0 = scan_info;
+ work_ccb->crcn.flags = scan_info->request_ccb->crcn.flags;
+ mtx_unlock(mtx);
+ xpt_action(work_ccb);
+ if (mtx != NULL)
+ mtx_lock(mtx);
+ break;
+
+ default:
+ break;
+ }
+}
+
+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_path *new_path;
+ struct cam_periph *old_periph;
+ int lock;
+
+ CAM_DEBUG(path, CAM_DEBUG_PROBE, ("xpt_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;
+ }
+
+ if (request_ccb == NULL) {
+ request_ccb = xpt_alloc_ccb_nowait();
+ if (request_ccb == NULL) {
+ xpt_print(path, "xpt_scan_lun: can't allocate CCB, "
+ "can't continue\n");
+ return;
+ }
+ status = xpt_create_path(&new_path, NULL,
+ path->bus->path_id,
+ path->target->target_id,
+ path->device->lun_id);
+ if (status != CAM_REQ_CMP) {
+ xpt_print(path, "xpt_scan_lun: can't create path, "
+ "can't continue\n");
+ xpt_free_ccb(request_ccb);
+ return;
+ }
+ xpt_setup_ccb(&request_ccb->ccb_h, new_path, CAM_PRIORITY_XPT);
+ request_ccb->ccb_h.cbfcnp = xptscandone;
+ request_ccb->ccb_h.flags |= CAM_UNLOCKED;
+ request_ccb->ccb_h.func_code = XPT_SCAN_LUN;
+ request_ccb->crcn.flags = flags;
+ }
+
+ lock = (xpt_path_owned(path) == 0);
+ if (lock)
+ xpt_path_lock(path);
+ if ((old_periph = cam_periph_find(path, "mmcprobe")) != NULL) {
+ xpt_print(path, " Found mmcprobe device at path\n");
+ if ((old_periph->flags & CAM_PERIPH_INVALID) == 0) {
+ xpt_print(path, " Periph is OK, insert request CCB into tailq\n");
+ } else {
+ xpt_print(path, " Old periph is invalid\n");
+ 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,
+ request_ccb->ccb_h.path, NULL, 0,
+ request_ccb);
+ request_ccb->ccb_h.status = status;
+ xpt_done(request_ccb);
+ }
+ if (lock)
+ xpt_path_unlock(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:
+ CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_INFO,
+ ("mmc_action! XPT_SCAN_BUS\n"));
+ mmc_scan_bus(start_ccb->ccb_h.path->periph, start_ccb);
+ break;
+
+ case XPT_SCAN_TGT:
+ CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_INFO,
+ ("mmc_action! XPT_SCAN_TGT\n"));
+ mmc_scan_bus(start_ccb->ccb_h.path->periph, start_ccb);
+ break;
+
+ case XPT_SCAN_LUN:
+ CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_INFO,
+ ("mmc_action! XPT_SCAN_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;
+ }
+}
+
+/*
+ * XXX: What's the point in having this function per-XPT?
+ */
+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_INFO,
+ ("mmc_dev_advinfo: request %x\n", cdai->buftype));
+ switch(cdai->buftype) {
+ case CDAI_TYPE_SCSI_DEVID:
+ if (cdai->flags & CDAI_FLAG_STORE)
+ return;
+ cdai->provsiz = device->device_id_len;
+ if (device->device_id_len == 0)
+ break;
+ amt = device->device_id_len;
+ if (cdai->provsiz > cdai->bufsiz)
+ amt = cdai->bufsiz;
+ memcpy(cdai->buf, device->device_id, amt);
+ break;
+ case CDAI_TYPE_SERIAL_NUM:
+ if (cdai->flags & CDAI_FLAG_STORE)
+ return;
+ cdai->provsiz = device->serial_num_len;
+ if (device->serial_num_len == 0)
+ break;
+ amt = device->serial_num_len;
+ if (cdai->provsiz > cdai->bufsiz)
+ amt = cdai->bufsiz;
+ memcpy(cdai->buf, device->serial_num, amt);
+ break;
+ case CDAI_TYPE_PHYS_PATH:
+ if (cdai->flags & CDAI_FLAG_STORE) {
+ if (device->physpath != NULL)
+ free(device->physpath, M_CAMXPT);
+ device->physpath_len = cdai->bufsiz;
+ /* Clear existing buffer if zero length */
+ if (cdai->bufsiz == 0)
+ break;
+ device->physpath = malloc(cdai->bufsiz, M_CAMXPT, M_NOWAIT);
+ if (device->physpath == NULL) {
+ start_ccb->ccb_h.status = CAM_REQ_ABORTED;
+ return;
+ }
+ memcpy(device->physpath, cdai->buf, cdai->bufsiz);
+ } else {
+ cdai->provsiz = device->physpath_len;
+ if (device->physpath_len == 0)
+ break;
+ amt = device->physpath_len;
+ if (cdai->provsiz > cdai->bufsiz)
+ amt = cdai->bufsiz;
+ memcpy(cdai->buf, device->physpath, amt);
+ }
+ break;
+ default:
+ return;
+ }
+ start_ccb->ccb_h.status = CAM_REQ_CMP;
+
+ if (cdai->flags & CDAI_FLAG_STORE) {
+ xpt_async(AC_ADVINFO_CHANGED, start_ccb->ccb_h.path,
+ (void *)(uintptr_t)cdai->buftype);
+ }
+}
+
+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("SIM infromation should appear here!\n");
+}
+
+void
+mmc_print_ident(struct mmc_params *ident_data)
+{
+ printf("(Some information about this MMC/SD device here)\n");
+}
+
+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. */
+
+typedef enum {
+ PROBE_RESET,
+ PROBE_IDENTIFY,
+ PROBE_SEND_IF_COND,
+ PROBE_SEND_APP_OP_COND_APPCMD,
+ PROBE_SEND_APP_OP_COND_ACMD41,
+ PROBE_DONE,
+ PROBE_INVALID
+} probe_action;
+
+static char *probe_action_text[] = {
+ "PROBE_RESET",
+ "PROBE_IDENTIFY",
+ "PROBE_SEND_IF_COND",
+ "PROBE_SEND_APP_OP_COND_APPCMD",
+ "PROBE_SEND_APP_OP_COND_ACMD41",
+ "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)
+
+typedef enum {
+ PROBE_WTF = 0x01
+} probe_flags;
+
+typedef struct {
+ TAILQ_HEAD(, ccb_hdr) request_ccbs;
+ probe_action action;
+ int restart;
+ union ccb saved_ccb;
+ probe_flags flags;
+ struct cam_periph *periph;
+
+ /* MMC Bus settings */
+ uint32_t host_ocr;
+} mmcprobe_softc;
+
+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);
+ 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"));
+/*
+ * ATA XPT then sends the following CCB to the SIM:
+ cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
+ cts.type = CTS_TYPE_CURRENT_SETTINGS;
+...
+ * ... but now there is nothing to send yet, I think
+*/
+
+/*
+ * ATA XPT then calls probeschedule() here, but we dont have
+ * so much work to do to write a separate function :)
+*/
+ 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
+mmc_build_app_op_cond(union ccb *ccb, uint32_t ocr)
+{
+ struct ccb_mmcio *mmcio;
+
+ mmcio = &ccb->mmcio;
+
+ init_standard_ccb(ccb, XPT_MMC_IO);
+ mmcio->cmd.opcode = ACMD_SD_SEND_OP_COND;
+ mmcio->cmd.arg = ocr;
+ mmcio->cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
+ mmcio->cmd.data = NULL;
+}
+
+static void
+mmcprobe_start(struct cam_periph *periph, union ccb *start_ccb)
+{
+ mmcprobe_softc *softc;
+ struct cam_path *path;
+ struct ccb_mmcio *mmcio;
+ struct ccb_trans_settings_mmc *cts;
+ struct mtx *p_mtx = cam_periph_mtx(periph);
+
+ 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;
+
+ 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:
+ 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;
+ mmcio->cmd.arg = 0;
+ mmcio->cmd.flags = MMC_RSP_NONE | MMC_CMD_BC;
+ mmcio->cmd.data = NULL;
+ 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 = NULL;
+ break;
+
+ case PROBE_SEND_APP_OP_COND_APPCMD:
+ init_standard_ccb(start_ccb, XPT_MMC_IO);
+ 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 = NULL;
+ break;
+
+ case PROBE_SEND_APP_OP_COND_ACMD41:
+ init_standard_ccb(start_ccb, XPT_MMC_IO);
+ mmcio->cmd.opcode = ACMD_SD_SEND_OP_COND; /* CMD 55 */
+ /* XXX: Don't set HCS if no response to CMD8 */
+ mmcio->cmd.arg = 1 << 30; /* HCS + ocr */
+ mmcio->cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;;
+ mmcio->cmd.data = NULL;
+ break;
+
+ case PROBE_DONE:
+ CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("Start with PROBE_DONE\n"));
+ return;
+ /* NOTREACHED */
+ break;
+ default:
+ CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("probestart: invalid action state 0x%x\n", softc->action));
+ panic("ciao");
+ }
+
+ 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 found = 1;
+ 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;
+
+ if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+ /* Call generic error handler */
+ if (cam_periph_error(done_ccb,
+ 0, softc->restart ? (SF_NO_RECOVERY | SF_NO_RETRY) : 0,
+ NULL) == ERESTART) {
+ /* Drop freeze taken due to CAM_DEV_QFREEZE flag set. */
+ cam_release_devq(path, 0, 0, 0, FALSE);
+ return;
+ }
+ if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
+ /* Don't wedge the queue */
+ xpt_release_devq(path, /*count*/1, /*run_queue*/TRUE);
+ }
+
+ if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0)
+ xpt_async(AC_LOST_DEVICE, path, NULL);
+ found = 0;
+ PROBE_SET_ACTION(softc, PROBE_INVALID);
+
+ xpt_release_ccb(done_ccb);
+ /* Drop freeze taken due to CAM_DEV_QFREEZE flag set. */
+ cam_release_devq(path, 0, 0, 0, FALSE);
+ cam_periph_invalidate(periph);
+ cam_periph_release_locked(periph);
+ return;
+ }
+
+ 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;
+
+ 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]));
+ PROBE_SET_ACTION(softc, PROBE_INVALID);
+ } else {
+ PROBE_SET_ACTION(softc, PROBE_SEND_APP_OP_COND_APPCMD);
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("SD 2.0 interface conditions: OK\n"));
+ }
+ break;
+ }
+ case PROBE_SEND_APP_OP_COND_APPCMD:
+ {
+ mmcio = &done_ccb->mmcio;
+ err = mmcio->cmd.error;
+
+ if (err != MMC_ERR_NONE || !(mmcio->cmd.resp[0] & R1_APP_CMD)) {
+ 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_INVALID);
+ } else
+ PROBE_SET_ACTION(softc, PROBE_SEND_APP_OP_COND_ACMD41);
+ break;
+ }
+ case PROBE_SEND_APP_OP_COND_ACMD41:
+ {
+ 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\n", err));
+ PROBE_SET_ACTION(softc, PROBE_INVALID);
+ } else {
+ if ((mmcio->cmd.resp[0] & MMC_OCR_CARD_BUSY) ||
+ (mmcio->cmd.arg & MMC_OCR_VOLTAGE) == 0) {
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("Card OCR: %08x\n", mmcio->cmd.resp[0]));
+ PROBE_SET_ACTION(softc, PROBE_DONE);
+ } 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_APPCMD);
+ }
+ }
+ break;
+ }
+ default:
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
+ ("mmc_probedone: invalid action state 0x%x\n", softc->action));
+ panic("ciao");
+ }
+
+ xpt_release_ccb(done_ccb);
+ xpt_schedule(periph, priority);
+ /* Drop freeze taken due to CAM_DEV_QFREEZE flag set. */
+ cam_release_devq(path, 0, 0, 0, FALSE);
+}
+
+
+/* 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,445 @@
+/*-
+ * 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/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -91,6 +91,7 @@
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/scsi/scsi_da.c optional da
cam/scsi/scsi_low.c optional ct | ncv | nsp | stg
cam/scsi/scsi_pass.c optional pass
@@ -1879,6 +1880,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/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,328 @@
+/*-
+ * 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->mmc_command);
+
+ 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 * 10, 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;
+ default:
+ 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, cpu, mmcnull_driver, mmcnull_devclass, 0, 0);
Index: sys/dev/sdhci/sdhci.h
===================================================================
--- sys/dev/sdhci/sdhci.h
+++ sys/dev/sdhci/sdhci.h
@@ -247,7 +247,10 @@
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;
+
uint32_t intmask; /* Current interrupt mask */
uint32_t clock; /* Current clock freq. */
size_t offset; /* Data buffer offset */
@@ -281,4 +284,7 @@
void sdhci_generic_intr(struct sdhci_slot *slot);
uint32_t sdhci_generic_min_freq(device_t brdev, struct sdhci_slot *slot);
+/* CAM-related */
+int sdhci_update_ios_cam(struct sdhci_slot *slot);
+int sdhci_request_cam(struct sdhci_slot *slot, union ccb *ccb);
#endif /* __SDHCI_H__ */
Index: sys/dev/sdhci/sdhci.c
===================================================================
--- sys/dev/sdhci/sdhci.c
+++ sys/dev/sdhci/sdhci.c
@@ -48,13 +48,19 @@
#include <dev/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))
@@ -470,6 +476,7 @@
int err;
SDHCI_LOCK_INIT(slot);
+
slot->num = num;
slot->bus = dev;
@@ -599,6 +606,7 @@
TASK_INIT(&slot->card_task, 0, sdhci_card_task, slot);
callout_init(&slot->card_callout, 1);
callout_init_mtx(&slot->timeout_callout, &slot->mtx, 0);
+
return (0);
}
@@ -661,12 +669,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) {
@@ -767,6 +786,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;
@@ -777,8 +799,9 @@
if (cmd->data || (cmd->flags & MMC_RSP_BUSY))
mask |= SDHCI_DAT_INHIBIT;
/* We shouldn't wait for DAT for stop commands. */
- if (cmd == slot->req->stop)
+/* if (cmd == slot->req->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
@@ -836,6 +859,7 @@
WR4(slot, SDHCI_ARGUMENT, cmd->arg);
/* Set data transfer mode. */
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. */
@@ -847,6 +871,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
@@ -877,6 +903,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);
@@ -1300,6 +1330,11 @@
}
SDHCI_UNLOCK(slot);
+
+ /* Tell CAM the request is finished */
+ slot->ccb->ccb_h.status = CAM_REQ_CMP;
+
+ xpt_done(slot->ccb);
}
int
@@ -1361,6 +1396,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);
@@ -1428,4 +1464,75 @@
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>
+
+int
+sdhci_update_ios_cam(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_4)
+ slot->hostctrl |= SDHCI_CTRL_4BITBUS;
+ else
+ slot->hostctrl &= ~SDHCI_CTRL_4BITBUS;
+ if (ios->timing == bus_timing_hs)
+ 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_request_cam(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)?(u_int)mmcio->cmd.data->len:0,
+ (mmcio->cmd.data)?mmcio->cmd.data->flags:0);
+ }
+// slot->req = req;
+ slot->ccb = ccb;
+ slot->flags = 0;
+ sdhci_start_command(slot, &mmcio->cmd);
+ SDHCI_UNLOCK(slot);
+ if (dumping) {
+ while (slot->req != NULL) {
+ sdhci_generic_intr(slot);
+ DELAY(10);
+ }
+ }
+ return (0);
+}
+
MODULE_VERSION(sdhci, 1);
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>

File Metadata

Mime Type
text/plain
Expires
Sat, Apr 18, 8:21 AM (4 h, 20 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31708226
Default Alt Text
D862.id.diff (90 KB)

Event Timeline