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