xref: /freebsd/sys/dev/mmcnull/mmcnull.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
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