2 * Copyright (c) 2013 Ilya Bakulin. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
29 #include <sys/param.h>
30 #include <sys/module.h>
31 #include <sys/kernel.h>
32 #include <sys/malloc.h>
33 #include <sys/systm.h>
35 #include <sys/mutex.h>
37 #include <sys/endian.h>
38 #include <sys/sysctl.h>
41 #include <cam/cam_ccb.h>
42 #include <cam/cam_debug.h>
43 #include <cam/cam_sim.h>
44 #include <cam/cam_xpt_sim.h>
45 #include <cam/scsi/scsi_all.h>
47 static int is_sdio_mode = 1;
49 struct mmcnull_softc {
53 struct cam_devq *devq;
55 struct cam_path *path;
61 static void mmcnull_identify(driver_t *, device_t);
62 static int mmcnull_probe(device_t);
63 static int mmcnull_attach(device_t);
64 static int mmcnull_detach(device_t);
65 static void mmcnull_action_sd(struct cam_sim *, union ccb *);
66 static void mmcnull_action_sdio(struct cam_sim *, union ccb *);
67 static void mmcnull_intr_sd(void *xsc);
68 static void mmcnull_intr_sdio(void *xsc);
69 static void mmcnull_poll(struct cam_sim *);
72 mmcnull_identify(driver_t *driver, device_t parent)
76 if (resource_disabled("mmcnull", 0))
79 if (device_get_unit(parent) != 0)
82 /* Avoid duplicates. */
83 if (device_find_child(parent, "mmcnull", -1))
86 child = BUS_ADD_CHILD(parent, 20, "mmcnull", 0);
88 device_printf(parent, "add MMCNULL child failed\n");
95 mmcnull_probe(device_t dev)
97 device_set_desc(dev, "Emulated MMC controller");
98 return (BUS_PROBE_DEFAULT);
102 mmcnull_attach(device_t dev)
104 struct mmcnull_softc *sc;
105 sim_action_func action_func;
107 sc = device_get_softc(dev);
110 mtx_init(&sc->sc_mtx, "mmcnullmtx", NULL, MTX_DEF);
112 if ((sc->devq = cam_simq_alloc(1)) == NULL)
116 action_func = mmcnull_action_sdio;
118 action_func = mmcnull_action_sd;
119 sc->sim = cam_sim_alloc(action_func, mmcnull_poll, "mmcnull", sc,
120 device_get_unit(dev), &sc->sc_mtx, 1, 1,
123 if (sc->sim == NULL) {
124 cam_simq_free(sc->devq);
125 device_printf(dev, "cannot allocate CAM SIM\n");
129 mtx_lock(&sc->sc_mtx);
130 if (xpt_bus_register(sc->sim, dev, 0) != 0) {
132 "cannot register SCSI pass-through bus\n");
133 cam_sim_free(sc->sim, FALSE);
134 cam_simq_free(sc->devq);
135 mtx_unlock(&sc->sc_mtx);
138 mtx_unlock(&sc->sc_mtx);
140 callout_init_mtx(&sc->tick, &sc->sc_mtx, 0); /* Callout to emulate interrupts */
142 device_printf(dev, "attached OK\n");
148 mmcnull_detach(device_t dev)
150 struct mmcnull_softc *sc;
152 sc = device_get_softc(dev);
157 if (sc->sim != NULL) {
158 mtx_lock(&sc->sc_mtx);
159 xpt_bus_deregister(cam_sim_path(sc->sim));
160 cam_sim_free(sc->sim, FALSE);
161 mtx_unlock(&sc->sc_mtx);
164 if (sc->devq != NULL)
165 cam_simq_free(sc->devq);
167 callout_drain(&sc->tick);
168 mtx_destroy(&sc->sc_mtx);
170 device_printf(dev, "detached OK\n");
175 * The interrupt handler
176 * This implementation calls it via callout(9)
177 * with the mutex already taken
180 mmcnull_intr_sd(void *xsc) {
181 struct mmcnull_softc *sc;
183 struct ccb_mmcio *mmcio;
185 sc = (struct mmcnull_softc *) xsc;
186 mtx_assert(&sc->sc_mtx, MA_OWNED);
190 device_printf(sc->dev, "mmcnull_intr: MMC command = %d\n",
193 switch (mmcio->cmd.opcode) {
194 case MMC_GO_IDLE_STATE:
195 device_printf(sc->dev, "Reset device\n");
197 case SD_SEND_IF_COND:
198 mmcio->cmd.resp[0] = 0x1AA; // To match mmc_xpt expectations :-)
201 mmcio->cmd.resp[0] = R1_APP_CMD;
203 case SD_SEND_RELATIVE_ADDR:
204 case MMC_SELECT_CARD:
205 mmcio->cmd.resp[0] = 0x1 << 16;
207 case ACMD_SD_SEND_OP_COND:
208 mmcio->cmd.resp[0] = 0xc0ff8000;
209 mmcio->cmd.resp[0] |= MMC_OCR_CARD_BUSY;
211 case MMC_ALL_SEND_CID:
212 /* Note: this is a real CID from Wandboard int mmc */
213 mmcio->cmd.resp[0] = 0x1b534d30;
214 mmcio->cmd.resp[1] = 0x30303030;
215 mmcio->cmd.resp[2] = 0x10842806;
216 mmcio->cmd.resp[3] = 0x5700e900;
219 /* Note: this is a real CSD from Wandboard int mmc */
220 mmcio->cmd.resp[0] = 0x400e0032;
221 mmcio->cmd.resp[1] = 0x5b590000;
222 mmcio->cmd.resp[2] = 0x751f7f80;
223 mmcio->cmd.resp[3] = 0x0a404000;
225 case MMC_READ_SINGLE_BLOCK:
226 case MMC_READ_MULTIPLE_BLOCK:
227 strcpy(mmcio->cmd.data->data, "WTF?!");
230 device_printf(sc->dev, "mmcnull_intr_sd: unknown command\n");
231 mmcio->cmd.error = 1;
233 ccb->ccb_h.status = CAM_REQ_CMP;
240 mmcnull_intr_sdio_newintr(void *xsc) {
241 struct mmcnull_softc *sc;
242 struct cam_path *dpath;
244 sc = (struct mmcnull_softc *) xsc;
245 mtx_assert(&sc->sc_mtx, MA_OWNED);
246 device_printf(sc->dev, "mmcnull_intr_sdio_newintr()\n");
249 if (xpt_create_path(&dpath, NULL, cam_sim_path(sc->sim), 0, 0) != CAM_REQ_CMP) {
250 device_printf(sc->dev, "mmcnull_intr_sdio_newintr(): cannot create path\n");
253 xpt_async(AC_UNIT_ATTENTION, dpath, NULL);
254 xpt_free_path(dpath);
258 mmcnull_intr_sdio(void *xsc) {
259 struct mmcnull_softc *sc;
261 struct ccb_mmcio *mmcio;
263 sc = (struct mmcnull_softc *) xsc;
264 mtx_assert(&sc->sc_mtx, MA_OWNED);
268 device_printf(sc->dev, "mmcnull_intr: MMC command = %d\n",
271 switch (mmcio->cmd.opcode) {
272 case MMC_GO_IDLE_STATE:
273 device_printf(sc->dev, "Reset device\n");
275 case SD_SEND_IF_COND:
276 mmcio->cmd.resp[0] = 0x1AA; // To match mmc_xpt expectations :-)
279 mmcio->cmd.resp[0] = R1_APP_CMD;
281 case IO_SEND_OP_COND:
282 mmcio->cmd.resp[0] = 0x12345678;
283 mmcio->cmd.resp[0] |= ~ R4_IO_MEM_PRESENT;
285 case SD_SEND_RELATIVE_ADDR:
286 case MMC_SELECT_CARD:
287 mmcio->cmd.resp[0] = 0x1 << 16;
289 case ACMD_SD_SEND_OP_COND:
290 /* TODO: steal valid OCR from somewhere :-) */
291 mmcio->cmd.resp[0] = 0x123;
292 mmcio->cmd.resp[0] |= MMC_OCR_CARD_BUSY;
294 case MMC_ALL_SEND_CID:
295 mmcio->cmd.resp[0] = 0x1234;
296 mmcio->cmd.resp[1] = 0x5678;
297 mmcio->cmd.resp[2] = 0x9ABC;
298 mmcio->cmd.resp[3] = 0xDEF0;
300 case MMC_READ_SINGLE_BLOCK:
301 case MMC_READ_MULTIPLE_BLOCK:
302 strcpy(mmcio->cmd.data->data, "WTF?!");
304 case SD_IO_RW_DIRECT:
305 device_printf(sc->dev, "Scheduling interrupt generation...\n");
306 callout_reset(&sc->tick, hz / 10, mmcnull_intr_sdio_newintr, sc);
309 device_printf(sc->dev, "mmcnull_intr_sdio: unknown command\n");
311 ccb->ccb_h.status = CAM_REQ_CMP;
318 * This is a MMC IO handler
319 * It extracts MMC command from CCB and sends it
323 mmcnull_handle_mmcio(struct cam_sim *sim, union ccb *ccb)
325 struct mmcnull_softc *sc;
326 struct ccb_mmcio *mmcio;
328 sc = cam_sim_softc(sim);
330 ccb->ccb_h.status = CAM_REQ_INPROG;
333 /* Real h/w will wait for the interrupt */
335 callout_reset(&sc->tick, hz / 10, mmcnull_intr_sdio, sc);
337 callout_reset(&sc->tick, hz / 10, mmcnull_intr_sd, sc);
341 mmcnull_action_sd(struct cam_sim *sim, union ccb *ccb)
343 struct mmcnull_softc *sc;
345 sc = cam_sim_softc(sim);
347 ccb->ccb_h.status = CAM_SEL_TIMEOUT;
352 mtx_assert(&sc->sc_mtx, MA_OWNED);
354 device_printf(sc->dev, "action: func_code %0x\n", ccb->ccb_h.func_code);
356 switch (ccb->ccb_h.func_code) {
359 struct ccb_pathinq *cpi;
362 cpi->version_num = 1;
363 cpi->hba_inquiry = PI_SDTR_ABLE | PI_TAG_ABLE | PI_WIDE_16;
364 cpi->target_sprt = 0;
365 cpi->hba_misc = PIM_NOBUSRESET | PIM_SEQSCAN;
366 cpi->hba_eng_cnt = 0;
369 cpi->initiator_id = 1;
370 strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
371 strncpy(cpi->hba_vid, "FreeBSD Foundation", HBA_IDLEN);
372 strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
373 cpi->unit_number = cam_sim_unit(sim);
374 cpi->bus_id = cam_sim_bus(sim);
375 cpi->base_transfer_speed = 100; /* XXX WTF? */
376 cpi->protocol = PROTO_MMCSD;
377 cpi->protocol_version = SCSI_REV_0;
378 cpi->transport = XPORT_MMCSD;
379 cpi->transport_version = 0;
381 cpi->ccb_h.status = CAM_REQ_CMP;
384 case XPT_GET_TRAN_SETTINGS:
386 struct ccb_trans_settings *cts = &ccb->cts;
387 struct ccb_trans_settings_mmc *mcts;
388 mcts = &ccb->cts.proto_specific.mmc;
390 device_printf(sc->dev, "Got XPT_GET_TRAN_SETTINGS\n");
392 cts->protocol = PROTO_MMCSD;
393 cts->protocol_version = 0;
394 cts->transport = XPORT_MMCSD;
395 cts->transport_version = 0;
396 cts->xport_specific.valid = 0;
397 mcts->host_f_max = 12000000;
398 mcts->host_f_min = 200000;
399 mcts->host_ocr = 1; /* Fix this */
400 ccb->ccb_h.status = CAM_REQ_CMP;
403 case XPT_SET_TRAN_SETTINGS:
404 device_printf(sc->dev, "Got XPT_SET_TRAN_SETTINGS, should update IOS...\n");
405 ccb->ccb_h.status = CAM_REQ_CMP;
408 device_printf(sc->dev, "Got XPT_RESET_BUS, ACK it...\n");
409 ccb->ccb_h.status = CAM_REQ_CMP;
413 * Here is the HW-dependent part of
414 * sending the command to the underlying h/w
415 * At some point in the future an interrupt comes.
416 * Then the request will be marked as completed.
418 device_printf(sc->dev, "Got XPT_MMC_IO\n");
419 mmcnull_handle_mmcio(sim, ccb);
423 /* This is sent by `camcontrol reset`*/
424 device_printf(sc->dev, "Got XPT_RESET_DEV\n");
425 ccb->ccb_h.status = CAM_REQ_CMP;
428 device_printf(sc->dev, "Func code %d is unknown\n", ccb->ccb_h.func_code);
429 ccb->ccb_h.status = CAM_REQ_INVALID;
437 mmcnull_action_sdio(struct cam_sim *sim, union ccb *ccb) {
438 mmcnull_action_sd(sim, ccb);
442 mmcnull_poll(struct cam_sim *sim)
448 static device_method_t mmcnull_methods[] = {
449 /* Device interface */
450 DEVMETHOD(device_identify, mmcnull_identify),
451 DEVMETHOD(device_probe, mmcnull_probe),
452 DEVMETHOD(device_attach, mmcnull_attach),
453 DEVMETHOD(device_detach, mmcnull_detach),
457 static driver_t mmcnull_driver = {
458 "mmcnull", mmcnull_methods, sizeof(struct mmcnull_softc)
461 static devclass_t mmcnull_devclass;
463 DRIVER_MODULE(mmcnull, isa, mmcnull_driver, mmcnull_devclass, 0, 0);