1 /*-
2 * Copyright (c) 2013 Ilya Bakulin. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
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.
12 *
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.
23 *
24 */
25
26 #include <sys/cdefs.h>
27 #include <sys/param.h>
28 #include <sys/module.h>
29 #include <sys/kernel.h>
30 #include <sys/malloc.h>
31 #include <sys/systm.h>
32 #include <sys/lock.h>
33 #include <sys/mutex.h>
34 #include <sys/bus.h>
35 #include <sys/endian.h>
36 #include <sys/sysctl.h>
37
38 #include <cam/cam.h>
39 #include <cam/cam_ccb.h>
40 #include <cam/cam_debug.h>
41 #include <cam/cam_sim.h>
42 #include <cam/cam_xpt_sim.h>
43 #include <cam/scsi/scsi_all.h>
44
45 static int is_sdio_mode = 1;
46
47 struct mmcnull_softc {
48 device_t dev;
49 struct mtx sc_mtx;
50
51 struct cam_devq *devq;
52 struct cam_sim *sim;
53 struct cam_path *path;
54
55 struct callout tick;
56 union ccb *cur_ccb;
57 };
58
59 static void mmcnull_identify(driver_t *, device_t);
60 static int mmcnull_probe(device_t);
61 static int mmcnull_attach(device_t);
62 static int mmcnull_detach(device_t);
63 static void mmcnull_action_sd(struct cam_sim *, union ccb *);
64 static void mmcnull_action_sdio(struct cam_sim *, union ccb *);
65 static void mmcnull_intr_sd(void *xsc);
66 static void mmcnull_intr_sdio(void *xsc);
67 static void mmcnull_poll(struct cam_sim *);
68
69 static void
mmcnull_identify(driver_t * driver,device_t parent)70 mmcnull_identify(driver_t *driver, device_t parent)
71 {
72 device_t child;
73
74 if (resource_disabled("mmcnull", 0))
75 return;
76
77 if (device_get_unit(parent) != 0)
78 return;
79
80 /* Avoid duplicates. */
81 if (device_find_child(parent, "mmcnull", -1))
82 return;
83
84 child = BUS_ADD_CHILD(parent, 20, "mmcnull", 0);
85 if (child == NULL) {
86 device_printf(parent, "add MMCNULL child failed\n");
87 return;
88 }
89 }
90
91
92 static int
mmcnull_probe(device_t dev)93 mmcnull_probe(device_t dev)
94 {
95 device_set_desc(dev, "Emulated MMC controller");
96 return (BUS_PROBE_DEFAULT);
97 }
98
99 static int
mmcnull_attach(device_t dev)100 mmcnull_attach(device_t dev)
101 {
102 struct mmcnull_softc *sc;
103 sim_action_func action_func;
104
105 sc = device_get_softc(dev);
106 sc->dev = dev;
107
108 mtx_init(&sc->sc_mtx, "mmcnullmtx", NULL, MTX_DEF);
109
110 if ((sc->devq = cam_simq_alloc(1)) == NULL)
111 return (ENOMEM);
112
113 if (is_sdio_mode)
114 action_func = mmcnull_action_sdio;
115 else
116 action_func = mmcnull_action_sd;
117 sc->sim = cam_sim_alloc(action_func, mmcnull_poll, "mmcnull", sc,
118 device_get_unit(dev), &sc->sc_mtx, 1, 1,
119 sc->devq);
120
121 if (sc->sim == NULL) {
122 cam_simq_free(sc->devq);
123 device_printf(dev, "cannot allocate CAM SIM\n");
124 return (EINVAL);
125 }
126
127 mtx_lock(&sc->sc_mtx);
128 if (xpt_bus_register(sc->sim, dev, 0) != 0) {
129 device_printf(dev,
130 "cannot register SCSI pass-through bus\n");
131 cam_sim_free(sc->sim, FALSE);
132 cam_simq_free(sc->devq);
133 mtx_unlock(&sc->sc_mtx);
134 return (EINVAL);
135 }
136 mtx_unlock(&sc->sc_mtx);
137
138 callout_init_mtx(&sc->tick, &sc->sc_mtx, 0); /* Callout to emulate interrupts */
139
140 device_printf(dev, "attached OK\n");
141
142 return (0);
143 }
144
145 static int
mmcnull_detach(device_t dev)146 mmcnull_detach(device_t dev)
147 {
148 struct mmcnull_softc *sc;
149
150 sc = device_get_softc(dev);
151
152 if (sc == NULL)
153 return (EINVAL);
154
155 if (sc->sim != NULL) {
156 mtx_lock(&sc->sc_mtx);
157 xpt_bus_deregister(cam_sim_path(sc->sim));
158 cam_sim_free(sc->sim, FALSE);
159 mtx_unlock(&sc->sc_mtx);
160 }
161
162 if (sc->devq != NULL)
163 cam_simq_free(sc->devq);
164
165 callout_drain(&sc->tick);
166 mtx_destroy(&sc->sc_mtx);
167
168 device_printf(dev, "detached OK\n");
169 return (0);
170 }
171
172 /*
173 * The interrupt handler
174 * This implementation calls it via callout(9)
175 * with the mutex already taken
176 */
177 static void
mmcnull_intr_sd(void * xsc)178 mmcnull_intr_sd(void *xsc) {
179 struct mmcnull_softc *sc;
180 union ccb *ccb;
181 struct ccb_mmcio *mmcio;
182
183 sc = (struct mmcnull_softc *) xsc;
184 mtx_assert(&sc->sc_mtx, MA_OWNED);
185
186 ccb = sc->cur_ccb;
187 mmcio = &ccb->mmcio;
188 device_printf(sc->dev, "mmcnull_intr: MMC command = %d\n",
189 mmcio->cmd.opcode);
190
191 switch (mmcio->cmd.opcode) {
192 case MMC_GO_IDLE_STATE:
193 device_printf(sc->dev, "Reset device\n");
194 break;
195 case SD_SEND_IF_COND:
196 mmcio->cmd.resp[0] = 0x1AA; // To match mmc_xpt expectations :-)
197 break;
198 case MMC_APP_CMD:
199 mmcio->cmd.resp[0] = R1_APP_CMD;
200 break;
201 case SD_SEND_RELATIVE_ADDR:
202 case MMC_SELECT_CARD:
203 mmcio->cmd.resp[0] = 0x1 << 16;
204 break;
205 case ACMD_SD_SEND_OP_COND:
206 mmcio->cmd.resp[0] = 0xc0ff8000;
207 mmcio->cmd.resp[0] |= MMC_OCR_CARD_BUSY;
208 break;
209 case MMC_ALL_SEND_CID:
210 /* Note: this is a real CID from Wandboard int mmc */
211 mmcio->cmd.resp[0] = 0x1b534d30;
212 mmcio->cmd.resp[1] = 0x30303030;
213 mmcio->cmd.resp[2] = 0x10842806;
214 mmcio->cmd.resp[3] = 0x5700e900;
215 break;
216 case MMC_SEND_CSD:
217 /* Note: this is a real CSD from Wandboard int mmc */
218 mmcio->cmd.resp[0] = 0x400e0032;
219 mmcio->cmd.resp[1] = 0x5b590000;
220 mmcio->cmd.resp[2] = 0x751f7f80;
221 mmcio->cmd.resp[3] = 0x0a404000;
222 break;
223 case MMC_READ_SINGLE_BLOCK:
224 case MMC_READ_MULTIPLE_BLOCK:
225 strcpy(mmcio->cmd.data->data, "WTF?!");
226 break;
227 default:
228 device_printf(sc->dev, "mmcnull_intr_sd: unknown command\n");
229 mmcio->cmd.error = 1;
230 }
231 ccb->ccb_h.status = CAM_REQ_CMP;
232
233 sc->cur_ccb = NULL;
234 xpt_done(ccb);
235 }
236
237 static void
mmcnull_intr_sdio_newintr(void * xsc)238 mmcnull_intr_sdio_newintr(void *xsc) {
239 struct mmcnull_softc *sc;
240 struct cam_path *dpath;
241
242 sc = (struct mmcnull_softc *) xsc;
243 mtx_assert(&sc->sc_mtx, MA_OWNED);
244 device_printf(sc->dev, "mmcnull_intr_sdio_newintr()\n");
245
246 /* Our path */
247 if (xpt_create_path(&dpath, NULL, cam_sim_path(sc->sim), 0, 0) != CAM_REQ_CMP) {
248 device_printf(sc->dev, "mmcnull_intr_sdio_newintr(): cannot create path\n");
249 return;
250 }
251 xpt_async(AC_UNIT_ATTENTION, dpath, NULL);
252 xpt_free_path(dpath);
253 }
254
255 static void
mmcnull_intr_sdio(void * xsc)256 mmcnull_intr_sdio(void *xsc) {
257 struct mmcnull_softc *sc;
258 union ccb *ccb;
259 struct ccb_mmcio *mmcio;
260
261 sc = (struct mmcnull_softc *) xsc;
262 mtx_assert(&sc->sc_mtx, MA_OWNED);
263
264 ccb = sc->cur_ccb;
265 mmcio = &ccb->mmcio;
266 device_printf(sc->dev, "mmcnull_intr: MMC command = %d\n",
267 mmcio->cmd.opcode);
268
269 switch (mmcio->cmd.opcode) {
270 case MMC_GO_IDLE_STATE:
271 device_printf(sc->dev, "Reset device\n");
272 break;
273 case SD_SEND_IF_COND:
274 mmcio->cmd.resp[0] = 0x1AA; // To match mmc_xpt expectations :-)
275 break;
276 case MMC_APP_CMD:
277 mmcio->cmd.resp[0] = R1_APP_CMD;
278 break;
279 case IO_SEND_OP_COND:
280 mmcio->cmd.resp[0] = 0x12345678;
281 mmcio->cmd.resp[0] |= ~ R4_IO_MEM_PRESENT;
282 break;
283 case SD_SEND_RELATIVE_ADDR:
284 case MMC_SELECT_CARD:
285 mmcio->cmd.resp[0] = 0x1 << 16;
286 break;
287 case ACMD_SD_SEND_OP_COND:
288 /* TODO: steal valid OCR from somewhere :-) */
289 mmcio->cmd.resp[0] = 0x123;
290 mmcio->cmd.resp[0] |= MMC_OCR_CARD_BUSY;
291 break;
292 case MMC_ALL_SEND_CID:
293 mmcio->cmd.resp[0] = 0x1234;
294 mmcio->cmd.resp[1] = 0x5678;
295 mmcio->cmd.resp[2] = 0x9ABC;
296 mmcio->cmd.resp[3] = 0xDEF0;
297 break;
298 case MMC_READ_SINGLE_BLOCK:
299 case MMC_READ_MULTIPLE_BLOCK:
300 strcpy(mmcio->cmd.data->data, "WTF?!");
301 break;
302 case SD_IO_RW_DIRECT:
303 device_printf(sc->dev, "Scheduling interrupt generation...\n");
304 callout_reset(&sc->tick, hz / 10, mmcnull_intr_sdio_newintr, sc);
305 break;
306 default:
307 device_printf(sc->dev, "mmcnull_intr_sdio: unknown command\n");
308 }
309 ccb->ccb_h.status = CAM_REQ_CMP;
310
311 sc->cur_ccb = NULL;
312 xpt_done(ccb);
313 }
314
315 /*
316 * This is a MMC IO handler
317 * It extracts MMC command from CCB and sends it
318 * to the h/w
319 */
320 static void
mmcnull_handle_mmcio(struct cam_sim * sim,union ccb * ccb)321 mmcnull_handle_mmcio(struct cam_sim *sim, union ccb *ccb)
322 {
323 struct mmcnull_softc *sc;
324 struct ccb_mmcio *mmcio;
325
326 sc = cam_sim_softc(sim);
327 mmcio = &ccb->mmcio;
328 ccb->ccb_h.status = CAM_REQ_INPROG;
329 sc->cur_ccb = ccb;
330
331 /* Real h/w will wait for the interrupt */
332 if (is_sdio_mode)
333 callout_reset(&sc->tick, hz / 10, mmcnull_intr_sdio, sc);
334 else
335 callout_reset(&sc->tick, hz / 10, mmcnull_intr_sd, sc);
336 }
337
338 static void
mmcnull_action_sd(struct cam_sim * sim,union ccb * ccb)339 mmcnull_action_sd(struct cam_sim *sim, union ccb *ccb)
340 {
341 struct mmcnull_softc *sc;
342
343 sc = cam_sim_softc(sim);
344 if (sc == NULL) {
345 ccb->ccb_h.status = CAM_SEL_TIMEOUT;
346 xpt_done(ccb);
347 return;
348 }
349
350 mtx_assert(&sc->sc_mtx, MA_OWNED);
351
352 device_printf(sc->dev, "action: func_code %0x\n", ccb->ccb_h.func_code);
353
354 switch (ccb->ccb_h.func_code) {
355 case XPT_PATH_INQ:
356 {
357 struct ccb_pathinq *cpi;
358
359 cpi = &ccb->cpi;
360 cpi->version_num = 1;
361 cpi->hba_inquiry = PI_SDTR_ABLE | PI_TAG_ABLE | PI_WIDE_16;
362 cpi->target_sprt = 0;
363 cpi->hba_misc = PIM_NOBUSRESET | PIM_SEQSCAN;
364 cpi->hba_eng_cnt = 0;
365 cpi->max_target = 0;
366 cpi->max_lun = 0;
367 cpi->initiator_id = 1;
368 strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
369 strncpy(cpi->hba_vid, "FreeBSD Foundation", HBA_IDLEN);
370 strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
371 cpi->unit_number = cam_sim_unit(sim);
372 cpi->bus_id = cam_sim_bus(sim);
373 cpi->base_transfer_speed = 100; /* XXX WTF? */
374 cpi->protocol = PROTO_MMCSD;
375 cpi->protocol_version = SCSI_REV_0;
376 cpi->transport = XPORT_MMCSD;
377 cpi->transport_version = 0;
378
379 cpi->ccb_h.status = CAM_REQ_CMP;
380 break;
381 }
382 case XPT_GET_TRAN_SETTINGS:
383 {
384 struct ccb_trans_settings *cts = &ccb->cts;
385 struct ccb_trans_settings_mmc *mcts;
386 mcts = &ccb->cts.proto_specific.mmc;
387
388 device_printf(sc->dev, "Got XPT_GET_TRAN_SETTINGS\n");
389
390 cts->protocol = PROTO_MMCSD;
391 cts->protocol_version = 0;
392 cts->transport = XPORT_MMCSD;
393 cts->transport_version = 0;
394 cts->xport_specific.valid = 0;
395 mcts->host_f_max = 12000000;
396 mcts->host_f_min = 200000;
397 mcts->host_ocr = 1; /* Fix this */
398 ccb->ccb_h.status = CAM_REQ_CMP;
399 break;
400 }
401 case XPT_SET_TRAN_SETTINGS:
402 device_printf(sc->dev, "Got XPT_SET_TRAN_SETTINGS, should update IOS...\n");
403 ccb->ccb_h.status = CAM_REQ_CMP;
404 break;
405 case XPT_RESET_BUS:
406 device_printf(sc->dev, "Got XPT_RESET_BUS, ACK it...\n");
407 ccb->ccb_h.status = CAM_REQ_CMP;
408 break;
409 case XPT_MMC_IO:
410 /*
411 * Here is the HW-dependent part of
412 * sending the command to the underlying h/w
413 * At some point in the future an interrupt comes.
414 * Then the request will be marked as completed.
415 */
416 device_printf(sc->dev, "Got XPT_MMC_IO\n");
417 mmcnull_handle_mmcio(sim, ccb);
418 return;
419 break;
420 case XPT_RESET_DEV:
421 /* This is sent by `camcontrol reset`*/
422 device_printf(sc->dev, "Got XPT_RESET_DEV\n");
423 ccb->ccb_h.status = CAM_REQ_CMP;
424 break;
425 default:
426 device_printf(sc->dev, "Func code %d is unknown\n", ccb->ccb_h.func_code);
427 ccb->ccb_h.status = CAM_REQ_INVALID;
428 break;
429 }
430 xpt_done(ccb);
431 return;
432 }
433
434 static void
mmcnull_action_sdio(struct cam_sim * sim,union ccb * ccb)435 mmcnull_action_sdio(struct cam_sim *sim, union ccb *ccb) {
436 mmcnull_action_sd(sim, ccb);
437 }
438
439 static void
mmcnull_poll(struct cam_sim * sim)440 mmcnull_poll(struct cam_sim *sim)
441 {
442 return;
443 }
444
445
446 static device_method_t mmcnull_methods[] = {
447 /* Device interface */
448 DEVMETHOD(device_identify, mmcnull_identify),
449 DEVMETHOD(device_probe, mmcnull_probe),
450 DEVMETHOD(device_attach, mmcnull_attach),
451 DEVMETHOD(device_detach, mmcnull_detach),
452 DEVMETHOD_END
453 };
454
455 static driver_t mmcnull_driver = {
456 "mmcnull", mmcnull_methods, sizeof(struct mmcnull_softc)
457 };
458
459 DRIVER_MODULE(mmcnull, isa, mmcnull_driver, 0, 0);
460