xref: /openbsd-src/sys/dev/sdmmc/sdmmc_scsi.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: sdmmc_scsi.c,v 1.30 2011/07/17 22:46:48 matthew Exp $	*/
2 
3 /*
4  * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /* A SCSI adapter emulation to access SD/MMC memory cards */
20 
21 #include <sys/param.h>
22 #include <sys/buf.h>
23 #include <sys/device.h>
24 #include <sys/kernel.h>
25 #include <sys/malloc.h>
26 #include <sys/proc.h>
27 #include <sys/systm.h>
28 
29 #include <scsi/scsi_all.h>
30 #include <scsi/scsi_disk.h>
31 #include <scsi/scsiconf.h>
32 
33 #include <dev/sdmmc/sdmmc_scsi.h>
34 #include <dev/sdmmc/sdmmcvar.h>
35 
36 #define SDMMC_SCSIID_HOST	0x00
37 #define SDMMC_SCSIID_MAX	0x0f
38 
39 #define SDMMC_SCSI_MAXCMDS	8
40 
41 struct sdmmc_scsi_target {
42 	struct sdmmc_function *card;
43 };
44 
45 struct sdmmc_ccb {
46 	struct sdmmc_scsi_softc *ccb_scbus;
47 	struct scsi_xfer *ccb_xs;
48 	int ccb_flags;
49 #define SDMMC_CCB_F_ERR		0x0001
50 	u_int32_t ccb_blockno;
51 	u_int32_t ccb_blockcnt;
52 	volatile enum {
53 		SDMMC_CCB_FREE,
54 		SDMMC_CCB_READY,
55 		SDMMC_CCB_QUEUED
56 	} ccb_state;
57 	struct sdmmc_command ccb_cmd;
58 	struct sdmmc_task ccb_task;
59 	TAILQ_ENTRY(sdmmc_ccb) ccb_link;
60 };
61 
62 TAILQ_HEAD(sdmmc_ccb_list, sdmmc_ccb);
63 
64 struct sdmmc_scsi_softc {
65 	struct scsi_adapter sc_adapter;
66 	struct scsi_link sc_link;
67 	struct device *sc_child;
68 	struct sdmmc_scsi_target *sc_tgt;
69 	int sc_ntargets;
70 	struct sdmmc_ccb *sc_ccbs;		/* allocated ccbs */
71 	struct sdmmc_ccb_list sc_ccb_freeq;	/* free ccbs */
72 	struct sdmmc_ccb_list sc_ccb_runq;	/* queued ccbs */
73 	struct mutex sc_ccb_mtx;
74 	struct scsi_iopool sc_iopool;
75 };
76 
77 int	sdmmc_alloc_ccbs(struct sdmmc_scsi_softc *, int);
78 void	sdmmc_free_ccbs(struct sdmmc_scsi_softc *);
79 void	*sdmmc_ccb_alloc(void *);
80 void	sdmmc_ccb_free(void *, void *);
81 
82 void	sdmmc_scsi_cmd(struct scsi_xfer *);
83 void	sdmmc_inquiry(struct scsi_xfer *);
84 void	sdmmc_start_xs(struct sdmmc_softc *, struct sdmmc_ccb *);
85 void	sdmmc_complete_xs(void *);
86 void	sdmmc_done_xs(struct sdmmc_ccb *);
87 void	sdmmc_stimeout(void *);
88 void	sdmmc_scsi_minphys(struct buf *, struct scsi_link *);
89 
90 #ifdef SDMMC_DEBUG
91 #define DPRINTF(s)	printf s
92 #else
93 #define DPRINTF(s)	/**/
94 #endif
95 
96 void
97 sdmmc_scsi_attach(struct sdmmc_softc *sc)
98 {
99 	struct sdmmc_attach_args saa;
100 	struct sdmmc_scsi_softc *scbus;
101 	struct sdmmc_function *sf;
102 
103 	rw_assert_wrlock(&sc->sc_lock);
104 
105 	scbus = malloc(sizeof *scbus, M_DEVBUF, M_WAITOK | M_ZERO);
106 
107 	scbus->sc_tgt = malloc(sizeof(*scbus->sc_tgt) *
108 	    (SDMMC_SCSIID_MAX+1), M_DEVBUF, M_WAITOK | M_ZERO);
109 
110 	/*
111 	 * Each card that sent us a CID in the identification stage
112 	 * gets a SCSI ID > 0, whether it is a memory card or not.
113 	 */
114 	scbus->sc_ntargets = 1;
115 	SIMPLEQ_FOREACH(sf, &sc->sf_head, sf_list) {
116 		if (scbus->sc_ntargets >= SDMMC_SCSIID_MAX+1)
117 			break;
118 		scbus->sc_tgt[scbus->sc_ntargets].card = sf;
119 		scbus->sc_ntargets++;
120 	}
121 
122 	/* Preallocate some CCBs and initialize the CCB lists. */
123 	if (sdmmc_alloc_ccbs(scbus, SDMMC_SCSI_MAXCMDS) != 0) {
124 		printf("%s: can't allocate ccbs\n", sc->sc_dev.dv_xname);
125 		goto free_sctgt;
126 	}
127 
128 	sc->sc_scsibus = scbus;
129 
130 	scbus->sc_adapter.scsi_cmd = sdmmc_scsi_cmd;
131 	scbus->sc_adapter.scsi_minphys = sdmmc_scsi_minphys;
132 
133 	scbus->sc_link.adapter_target = SDMMC_SCSIID_HOST;
134 	scbus->sc_link.adapter_buswidth = scbus->sc_ntargets;
135 	scbus->sc_link.adapter_softc = sc;
136 	scbus->sc_link.luns = 1;
137 	scbus->sc_link.openings = 1;
138 	scbus->sc_link.adapter = &scbus->sc_adapter;
139 	scbus->sc_link.pool = &scbus->sc_iopool;
140 
141 	bzero(&saa, sizeof(saa));
142 	saa.scsi_link = &scbus->sc_link;
143 
144 	scbus->sc_child = config_found(&sc->sc_dev, &saa, scsiprint);
145 	if (scbus->sc_child == NULL) {
146 		printf("%s: can't attach scsibus\n", sc->sc_dev.dv_xname);
147 		goto free_ccbs;
148 	}
149 	return;
150 
151  free_ccbs:
152 	sc->sc_scsibus = NULL;
153 	sdmmc_free_ccbs(scbus);
154  free_sctgt:
155 	free(scbus->sc_tgt, M_DEVBUF);
156 	free(scbus, M_DEVBUF);
157 }
158 
159 void
160 sdmmc_scsi_detach(struct sdmmc_softc *sc)
161 {
162 	struct sdmmc_scsi_softc *scbus;
163 	struct sdmmc_ccb *ccb;
164 	int s;
165 
166 	rw_assert_wrlock(&sc->sc_lock);
167 
168 	scbus = sc->sc_scsibus;
169 	if (scbus == NULL)
170 		return;
171 
172 	/* Complete all open scsi xfers. */
173 	s = splbio();
174 	for (ccb = TAILQ_FIRST(&scbus->sc_ccb_runq); ccb != NULL;
175 	     ccb = TAILQ_FIRST(&scbus->sc_ccb_runq))
176 		sdmmc_stimeout(ccb);
177 	splx(s);
178 
179 	if (scbus->sc_child != NULL)
180 		config_detach(scbus->sc_child, DETACH_FORCE);
181 
182 	if (scbus->sc_tgt != NULL)
183 		free(scbus->sc_tgt, M_DEVBUF);
184 
185 	sdmmc_free_ccbs(scbus);
186 	free(scbus, M_DEVBUF);
187 	sc->sc_scsibus = NULL;
188 }
189 
190 /*
191  * CCB management
192  */
193 
194 int
195 sdmmc_alloc_ccbs(struct sdmmc_scsi_softc *scbus, int nccbs)
196 {
197 	struct sdmmc_ccb *ccb;
198 	int i;
199 
200 	scbus->sc_ccbs = malloc(sizeof(struct sdmmc_ccb) * nccbs,
201 	    M_DEVBUF, M_NOWAIT);
202 	if (scbus->sc_ccbs == NULL)
203 		return 1;
204 
205 	TAILQ_INIT(&scbus->sc_ccb_freeq);
206 	TAILQ_INIT(&scbus->sc_ccb_runq);
207 	mtx_init(&scbus->sc_ccb_mtx, IPL_BIO);
208 	scsi_iopool_init(&scbus->sc_iopool, scbus, sdmmc_ccb_alloc,
209 	    sdmmc_ccb_free);
210 
211 	for (i = 0; i < nccbs; i++) {
212 		ccb = &scbus->sc_ccbs[i];
213 		ccb->ccb_scbus = scbus;
214 		ccb->ccb_state = SDMMC_CCB_FREE;
215 		ccb->ccb_flags = 0;
216 		ccb->ccb_xs = NULL;
217 
218 		TAILQ_INSERT_TAIL(&scbus->sc_ccb_freeq, ccb, ccb_link);
219 	}
220 	return 0;
221 }
222 
223 void
224 sdmmc_free_ccbs(struct sdmmc_scsi_softc *scbus)
225 {
226 	if (scbus->sc_ccbs != NULL) {
227 		free(scbus->sc_ccbs, M_DEVBUF);
228 		scbus->sc_ccbs = NULL;
229 	}
230 }
231 
232 void *
233 sdmmc_ccb_alloc(void *xscbus)
234 {
235 	struct sdmmc_scsi_softc *scbus = xscbus;
236 	struct sdmmc_ccb *ccb;
237 
238 	mtx_enter(&scbus->sc_ccb_mtx);
239 	ccb = TAILQ_FIRST(&scbus->sc_ccb_freeq);
240 	if (ccb != NULL) {
241 		TAILQ_REMOVE(&scbus->sc_ccb_freeq, ccb, ccb_link);
242 		ccb->ccb_state = SDMMC_CCB_READY;
243 	}
244 	mtx_leave(&scbus->sc_ccb_mtx);
245 
246 	return ccb;
247 }
248 
249 void
250 sdmmc_ccb_free(void *xscbus, void *xccb)
251 {
252 	struct sdmmc_scsi_softc *scbus = xscbus;
253 	struct sdmmc_ccb *ccb = xccb;
254 	int s;
255 
256 	s = splbio();
257 	if (ccb->ccb_state == SDMMC_CCB_QUEUED)
258 		TAILQ_REMOVE(&scbus->sc_ccb_runq, ccb, ccb_link);
259 	splx(s);
260 
261 	ccb->ccb_state = SDMMC_CCB_FREE;
262 	ccb->ccb_flags = 0;
263 	ccb->ccb_xs = NULL;
264 
265 	mtx_enter(&scbus->sc_ccb_mtx);
266 	TAILQ_INSERT_TAIL(&scbus->sc_ccb_freeq, ccb, ccb_link);
267 	mtx_leave(&scbus->sc_ccb_mtx);
268 }
269 
270 /*
271  * SCSI command emulation
272  */
273 
274 /* XXX move to some sort of "scsi emulation layer". */
275 static void
276 sdmmc_scsi_decode_rw(struct scsi_xfer *xs, u_int32_t *blocknop,
277     u_int32_t *blockcntp)
278 {
279 	struct scsi_rw *rw;
280 	struct scsi_rw_big *rwb;
281 
282 	if (xs->cmdlen == 6) {
283 		rw = (struct scsi_rw *)xs->cmd;
284 		*blocknop = _3btol(rw->addr) & (SRW_TOPADDR << 16 | 0xffff);
285 		*blockcntp = rw->length ? rw->length : 0x100;
286 	} else {
287 		rwb = (struct scsi_rw_big *)xs->cmd;
288 		*blocknop = _4btol(rwb->addr);
289 		*blockcntp = _2btol(rwb->length);
290 	}
291 }
292 
293 void
294 sdmmc_scsi_cmd(struct scsi_xfer *xs)
295 {
296 	struct scsi_link *link = xs->sc_link;
297 	struct sdmmc_softc *sc = link->adapter_softc;
298 	struct sdmmc_scsi_softc *scbus = sc->sc_scsibus;
299 	struct sdmmc_scsi_target *tgt = &scbus->sc_tgt[link->target];
300 	struct scsi_read_cap_data rcd;
301 	u_int32_t blockno;
302 	u_int32_t blockcnt;
303 	struct sdmmc_ccb *ccb;
304 
305 	if (link->target >= scbus->sc_ntargets || tgt->card == NULL ||
306 	    link->lun != 0) {
307 		DPRINTF(("%s: sdmmc_scsi_cmd: no target %d\n",
308 		    DEVNAME(sc), link->target));
309 		/* XXX should be XS_SENSE and sense filled out */
310 		xs->error = XS_DRIVER_STUFFUP;
311 		scsi_done(xs);
312 		return;
313 	}
314 
315 	DPRINTF(("%s: scsi cmd target=%d opcode=%#x proc=\"%s\" (poll=%#x)\n",
316 	    DEVNAME(sc), link->target, xs->cmd->opcode, curproc ?
317 	    curproc->p_comm : "", xs->flags & SCSI_POLL));
318 
319 	xs->error = XS_NOERROR;
320 
321 	switch (xs->cmd->opcode) {
322 	case READ_COMMAND:
323 	case READ_BIG:
324 	case WRITE_COMMAND:
325 	case WRITE_BIG:
326 		/* Deal with I/O outside the switch. */
327 		break;
328 
329 	case INQUIRY:
330 		sdmmc_inquiry(xs);
331 		return;
332 
333 	case TEST_UNIT_READY:
334 	case START_STOP:
335 	case SYNCHRONIZE_CACHE:
336 		scsi_done(xs);
337 		return;
338 
339 	case READ_CAPACITY:
340 		bzero(&rcd, sizeof rcd);
341 		_lto4b(tgt->card->csd.capacity - 1, rcd.addr);
342 		_lto4b(tgt->card->csd.sector_size, rcd.length);
343 		bcopy(&rcd, xs->data, MIN(xs->datalen, sizeof rcd));
344 		scsi_done(xs);
345 		return;
346 
347 	default:
348 		DPRINTF(("%s: unsupported scsi command %#x\n",
349 		    DEVNAME(sc), xs->cmd->opcode));
350 		xs->error = XS_DRIVER_STUFFUP;
351 		scsi_done(xs);
352 		return;
353 	}
354 
355 	/* A read or write operation. */
356 	sdmmc_scsi_decode_rw(xs, &blockno, &blockcnt);
357 
358 	if (blockno >= tgt->card->csd.capacity ||
359 	    blockno + blockcnt > tgt->card->csd.capacity) {
360 		DPRINTF(("%s: out of bounds %u-%u >= %u\n", DEVNAME(sc),
361 		    blockno, blockcnt, tgt->card->csd.capacity));
362 		xs->error = XS_DRIVER_STUFFUP;
363 		scsi_done(xs);
364 		return;
365 	}
366 
367 	ccb = xs->io;
368 
369 	ccb->ccb_xs = xs;
370 	ccb->ccb_blockcnt = blockcnt;
371 	ccb->ccb_blockno = blockno;
372 
373 	sdmmc_start_xs(sc, ccb);
374 }
375 
376 void
377 sdmmc_inquiry(struct scsi_xfer *xs)
378 {
379 	struct scsi_link *link = xs->sc_link;
380 	struct scsi_inquiry_data inq;
381 	struct scsi_inquiry *cdb = (struct scsi_inquiry *)xs->cmd;
382 
383         if (xs->cmdlen != sizeof(*cdb)) {
384 		xs->error = XS_DRIVER_STUFFUP;
385 		goto done;
386 	}
387 
388 	if (ISSET(cdb->flags, SI_EVPD)) {
389 		xs->error = XS_DRIVER_STUFFUP;
390 		goto done;
391 	}
392 
393 	bzero(&inq, sizeof inq);
394 	inq.device = T_DIRECT;
395 	inq.version = 2;
396 	inq.response_format = 2;
397 	inq.additional_length = 32;
398 	strlcpy(inq.vendor, "SD/MMC ", sizeof(inq.vendor));
399 	snprintf(inq.product, sizeof(inq.product),
400 	    "Drive #%02d", link->target);
401 	strlcpy(inq.revision, "   ", sizeof(inq.revision));
402 
403 	bcopy(&inq, xs->data, MIN(xs->datalen, sizeof(inq)));
404 
405 done:
406 	scsi_done(xs);
407 }
408 
409 void
410 sdmmc_start_xs(struct sdmmc_softc *sc, struct sdmmc_ccb *ccb)
411 {
412 	struct sdmmc_scsi_softc *scbus = sc->sc_scsibus;
413 	struct scsi_xfer *xs = ccb->ccb_xs;
414 	int s;
415 
416 	timeout_set(&xs->stimeout, sdmmc_stimeout, ccb);
417 	sdmmc_init_task(&ccb->ccb_task, sdmmc_complete_xs, ccb);
418 
419 	s = splbio();
420 	TAILQ_INSERT_TAIL(&scbus->sc_ccb_runq, ccb, ccb_link);
421 	ccb->ccb_state = SDMMC_CCB_QUEUED;
422 	splx(s);
423 
424 	if (ISSET(xs->flags, SCSI_POLL)) {
425 		sdmmc_complete_xs(ccb);
426 		return;
427 	}
428 
429 	timeout_add_msec(&xs->stimeout, xs->timeout);
430 	sdmmc_add_task(sc, &ccb->ccb_task);
431 }
432 
433 void
434 sdmmc_complete_xs(void *arg)
435 {
436 	struct sdmmc_ccb *ccb = arg;
437 	struct scsi_xfer *xs = ccb->ccb_xs;
438 	struct scsi_link *link = xs->sc_link;
439 	struct sdmmc_softc *sc = link->adapter_softc;
440 	struct sdmmc_scsi_softc *scbus = sc->sc_scsibus;
441 	struct sdmmc_scsi_target *tgt = &scbus->sc_tgt[link->target];
442 	int error;
443 	int s;
444 
445 	DPRINTF(("%s: scsi cmd target=%d opcode=%#x proc=\"%s\" (poll=%#x)"
446 	    " complete\n", DEVNAME(sc), link->target, xs->cmd->opcode,
447 	    curproc ? curproc->p_comm : "", xs->flags & SCSI_POLL));
448 
449 	s = splbio();
450 
451 	if (ISSET(xs->flags, SCSI_DATA_IN))
452 		error = sdmmc_mem_read_block(tgt->card, ccb->ccb_blockno,
453 		    xs->data, ccb->ccb_blockcnt * DEV_BSIZE);
454 	else
455 		error = sdmmc_mem_write_block(tgt->card, ccb->ccb_blockno,
456 		    xs->data, ccb->ccb_blockcnt * DEV_BSIZE);
457 
458 	if (error != 0)
459 		xs->error = XS_DRIVER_STUFFUP;
460 
461 	sdmmc_done_xs(ccb);
462 	splx(s);
463 }
464 
465 void
466 sdmmc_done_xs(struct sdmmc_ccb *ccb)
467 {
468 	struct scsi_xfer *xs = ccb->ccb_xs;
469 #ifdef SDMMC_DEBUG
470 	struct scsi_link *link = xs->sc_link;
471 	struct sdmmc_softc *sc = link->adapter_softc;
472 #endif
473 
474 	timeout_del(&xs->stimeout);
475 
476 	DPRINTF(("%s: scsi cmd target=%d opcode=%#x proc=\"%s\" (error=%#x)"
477 	    " done\n", DEVNAME(sc), link->target, xs->cmd->opcode,
478 	    curproc ? curproc->p_comm : "", xs->error));
479 
480 	xs->resid = 0;
481 
482 	if (ISSET(ccb->ccb_flags, SDMMC_CCB_F_ERR))
483 		xs->error = XS_DRIVER_STUFFUP;
484 
485 	scsi_done(xs);
486 }
487 
488 void
489 sdmmc_stimeout(void *arg)
490 {
491 	struct sdmmc_ccb *ccb = arg;
492 	int s;
493 
494 	s = splbio();
495 	ccb->ccb_flags |= SDMMC_CCB_F_ERR;
496 	if (sdmmc_task_pending(&ccb->ccb_task)) {
497 		sdmmc_del_task(&ccb->ccb_task);
498 		sdmmc_done_xs(ccb);
499 	}
500 	splx(s);
501 }
502 
503 void
504 sdmmc_scsi_minphys(struct buf *bp, struct scsi_link *sl)
505 {
506 	struct sdmmc_softc *sc = sl->adapter_softc;
507 	struct sdmmc_scsi_softc *scbus = sc->sc_scsibus;
508 	struct sdmmc_scsi_target *tgt = &scbus->sc_tgt[sl->target];
509 	struct sdmmc_function *sf = tgt->card;
510 
511 	/* limit to max. transfer size supported by card/host */
512 	if (sc->sc_max_xfer != 0 &&
513 	    bp->b_bcount > sf->csd.sector_size * sc->sc_max_xfer)
514 		bp->b_bcount = sf->csd.sector_size * sc->sc_max_xfer;
515 
516 	minphys(bp);
517 }
518