Annotation of sys/dev/sdmmc/sdmmc_scsi.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: sdmmc_scsi.c,v 1.7 2006/11/28 23:59:45 dlg 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/kernel.h>
24: #include <sys/malloc.h>
25: #include <sys/proc.h>
26: #include <sys/systm.h>
27:
28: #include <scsi/scsi_all.h>
29: #include <scsi/scsi_disk.h>
30: #include <scsi/scsiconf.h>
31:
32: #include <dev/sdmmc/sdmmc_scsi.h>
33: #include <dev/sdmmc/sdmmcvar.h>
34:
35: #define SDMMC_SCSIID_HOST 0x00
36: #define SDMMC_SCSIID_MAX 0x0f
37:
38: #define SDMMC_SCSI_MAXCMDS 8
39:
40: struct sdmmc_scsi_target {
41: struct sdmmc_function *card;
42: };
43:
44: struct sdmmc_ccb {
45: struct sdmmc_scsi_softc *ccb_scbus;
46: struct scsi_xfer *ccb_xs;
47: int ccb_flags;
48: #define SDMMC_CCB_F_ERR 0x0001
49: void (*ccb_done)(struct sdmmc_ccb *);
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: };
74:
75: int sdmmc_alloc_ccbs(struct sdmmc_scsi_softc *, int);
76: void sdmmc_free_ccbs(struct sdmmc_scsi_softc *);
77: struct sdmmc_ccb *sdmmc_get_ccb(struct sdmmc_scsi_softc *, int);
78: void sdmmc_put_ccb(struct sdmmc_ccb *);
79:
80: int sdmmc_scsi_cmd(struct scsi_xfer *);
81: int sdmmc_start_xs(struct sdmmc_softc *, struct sdmmc_ccb *);
82: void sdmmc_complete_xs(void *);
83: void sdmmc_done_xs(struct sdmmc_ccb *);
84: void sdmmc_stimeout(void *);
85: void sdmmc_scsi_minphys(struct buf *);
86:
87: #define DEVNAME(sc) SDMMCDEVNAME(sc)
88:
89: #ifdef SDMMC_DEBUG
90: #define DPRINTF(s) printf s
91: #else
92: #define DPRINTF(s) /**/
93: #endif
94:
95: void
96: sdmmc_scsi_attach(struct sdmmc_softc *sc)
97: {
98: struct scsibus_attach_args saa;
99: struct sdmmc_scsi_softc *scbus;
100: struct sdmmc_function *sf;
101:
102: MALLOC(scbus, struct sdmmc_scsi_softc *,
103: sizeof *scbus, M_DEVBUF, M_WAITOK);
104: bzero(scbus, sizeof *scbus);
105:
106: MALLOC(scbus->sc_tgt, struct sdmmc_scsi_target *,
107: sizeof(*scbus->sc_tgt) * (SDMMC_SCSIID_MAX+1),
108: M_DEVBUF, M_WAITOK);
109: bzero(scbus->sc_tgt, sizeof(*scbus->sc_tgt) * (SDMMC_SCSIID_MAX+1));
110:
111: /*
112: * Each card that sent us a CID in the identification stage
113: * gets a SCSI ID > 0, whether it is a memory card or not.
114: */
115: scbus->sc_ntargets = 1;
116: SIMPLEQ_FOREACH(sf, &sc->sf_head, sf_list) {
117: if (scbus->sc_ntargets >= SDMMC_SCSIID_MAX+1)
118: break;
119: scbus->sc_tgt[scbus->sc_ntargets].card = sf;
120: scbus->sc_ntargets++;
121: }
122:
123: /* Preallocate some CCBs and initialize the CCB lists. */
124: if (sdmmc_alloc_ccbs(scbus, SDMMC_SCSI_MAXCMDS) != 0) {
125: printf("%s: can't allocate ccbs\n", sc->sc_dev.dv_xname);
126: goto free_sctgt;
127: }
128:
129: sc->sc_scsibus = scbus;
130:
131: scbus->sc_adapter.scsi_cmd = sdmmc_scsi_cmd;
132: scbus->sc_adapter.scsi_minphys = sdmmc_scsi_minphys;
133:
134: scbus->sc_link.adapter_target = SDMMC_SCSIID_HOST;
135: scbus->sc_link.adapter_buswidth = scbus->sc_ntargets;
136: scbus->sc_link.adapter_softc = sc;
137: scbus->sc_link.luns = 1;
138: scbus->sc_link.openings = 1;
139: scbus->sc_link.adapter = &scbus->sc_adapter;
140:
141: bzero(&saa, sizeof(saa));
142: saa.saa_sc_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: scbus = sc->sc_scsibus;
167: if (scbus == NULL)
168: return;
169:
170: /* Complete all open scsi xfers. */
171: s = splbio();
172: for (ccb = TAILQ_FIRST(&scbus->sc_ccb_runq); ccb != NULL;
173: ccb = TAILQ_FIRST(&scbus->sc_ccb_runq))
174: sdmmc_stimeout(ccb);
175: splx(s);
176:
177: if (scbus->sc_child != NULL)
178: config_detach(scbus->sc_child, DETACH_FORCE);
179:
180: if (scbus->sc_tgt != NULL)
181: FREE(scbus->sc_tgt, M_DEVBUF);
182:
183: sdmmc_free_ccbs(scbus);
184: FREE(scbus, M_DEVBUF);
185: sc->sc_scsibus = NULL;
186: }
187:
188: /*
189: * CCB management
190: */
191:
192: int
193: sdmmc_alloc_ccbs(struct sdmmc_scsi_softc *scbus, int nccbs)
194: {
195: struct sdmmc_ccb *ccb;
196: int i;
197:
198: scbus->sc_ccbs = malloc(sizeof(struct sdmmc_ccb) * nccbs,
199: M_DEVBUF, M_NOWAIT);
200: if (scbus->sc_ccbs == NULL)
201: return 1;
202:
203: TAILQ_INIT(&scbus->sc_ccb_freeq);
204: TAILQ_INIT(&scbus->sc_ccb_runq);
205:
206: for (i = 0; i < nccbs; i++) {
207: ccb = &scbus->sc_ccbs[i];
208: ccb->ccb_scbus = scbus;
209: ccb->ccb_state = SDMMC_CCB_FREE;
210: ccb->ccb_flags = 0;
211: ccb->ccb_xs = NULL;
212: ccb->ccb_done = NULL;
213:
214: TAILQ_INSERT_TAIL(&scbus->sc_ccb_freeq, ccb, ccb_link);
215: }
216: return 0;
217: }
218:
219: void
220: sdmmc_free_ccbs(struct sdmmc_scsi_softc *scbus)
221: {
222: if (scbus->sc_ccbs != NULL) {
223: free(scbus->sc_ccbs, M_DEVBUF);
224: scbus->sc_ccbs = NULL;
225: }
226: }
227:
228: struct sdmmc_ccb *
229: sdmmc_get_ccb(struct sdmmc_scsi_softc *scbus, int flags)
230: {
231: struct sdmmc_ccb *ccb;
232: int s;
233:
234: s = splbio();
235: while ((ccb = TAILQ_FIRST(&scbus->sc_ccb_freeq)) == NULL &&
236: !ISSET(flags, SCSI_NOSLEEP))
237: tsleep(&scbus->sc_ccb_freeq, PRIBIO, "getccb", 0);
238: if (ccb != NULL) {
239: TAILQ_REMOVE(&scbus->sc_ccb_freeq, ccb, ccb_link);
240: ccb->ccb_state = SDMMC_CCB_READY;
241: }
242: splx(s);
243: return ccb;
244: }
245:
246: void
247: sdmmc_put_ccb(struct sdmmc_ccb *ccb)
248: {
249: struct sdmmc_scsi_softc *scbus = ccb->ccb_scbus;
250: int s;
251:
252: s = splbio();
253: if (ccb->ccb_state == SDMMC_CCB_QUEUED)
254: TAILQ_REMOVE(&scbus->sc_ccb_runq, ccb, ccb_link);
255: ccb->ccb_state = SDMMC_CCB_FREE;
256: ccb->ccb_flags = 0;
257: ccb->ccb_xs = NULL;
258: ccb->ccb_done = NULL;
259: TAILQ_INSERT_TAIL(&scbus->sc_ccb_freeq, ccb, ccb_link);
260: if (TAILQ_NEXT(ccb, ccb_link) == NULL)
261: wakeup(&scbus->sc_ccb_freeq);
262: splx(s);
263: }
264:
265: /*
266: * SCSI command emulation
267: */
268:
269: /* XXX move to some sort of "scsi emulation layer". */
270: static void
271: sdmmc_scsi_decode_rw(struct scsi_xfer *xs, u_int32_t *blocknop,
272: u_int32_t *blockcntp)
273: {
274: struct scsi_rw *rw;
275: struct scsi_rw_big *rwb;
276:
277: if (xs->cmdlen == 6) {
278: rw = (struct scsi_rw *)xs->cmd;
279: *blocknop = _3btol(rw->addr) & (SRW_TOPADDR << 16 | 0xffff);
280: *blockcntp = rw->length ? rw->length : 0x100;
281: } else {
282: rwb = (struct scsi_rw_big *)xs->cmd;
283: *blocknop = _4btol(rwb->addr);
284: *blockcntp = _2btol(rwb->length);
285: }
286: }
287:
288: int
289: sdmmc_scsi_cmd(struct scsi_xfer *xs)
290: {
291: struct scsi_link *link = xs->sc_link;
292: struct sdmmc_softc *sc = link->adapter_softc;
293: struct sdmmc_scsi_softc *scbus = sc->sc_scsibus;
294: struct sdmmc_scsi_target *tgt = &scbus->sc_tgt[link->target];
295: struct scsi_inquiry_data inq;
296: struct scsi_read_cap_data rcd;
297: u_int32_t blockno;
298: u_int32_t blockcnt;
299: struct sdmmc_ccb *ccb;
300: int s;
301:
302: if (link->target >= scbus->sc_ntargets || tgt->card == NULL ||
303: link->lun != 0) {
304: DPRINTF(("%s: sdmmc_scsi_cmd: no target %d\n",
305: DEVNAME(sc), link->target));
306: /* XXX should be XS_SENSE and sense filled out */
307: xs->error = XS_DRIVER_STUFFUP;
308: xs->flags |= ITSDONE;
309: s = splbio();
310: scsi_done(xs);
311: splx(s);
312: return COMPLETE;
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: bzero(&inq, sizeof inq);
331: inq.device = T_DIRECT;
332: inq.version = 2;
333: inq.response_format = 2;
334: inq.additional_length = 32;
335: strlcpy(inq.vendor, "SD/MMC ", sizeof(inq.vendor));
336: snprintf(inq.product, sizeof(inq.product),
337: "Drive #%02d", link->target);
338: strlcpy(inq.revision, " ", sizeof(inq.revision));
339: bcopy(&inq, xs->data, MIN(xs->datalen, sizeof inq));
340: s = splbio();
341: scsi_done(xs);
342: splx(s);
343: return COMPLETE;
344:
345: case TEST_UNIT_READY:
346: case START_STOP:
347: case SYNCHRONIZE_CACHE:
348: return COMPLETE;
349:
350: case READ_CAPACITY:
351: bzero(&rcd, sizeof rcd);
352: _lto4b(tgt->card->csd.capacity - 1, rcd.addr);
353: _lto4b(tgt->card->csd.sector_size, rcd.length);
354: bcopy(&rcd, xs->data, MIN(xs->datalen, sizeof rcd));
355: s = splbio();
356: scsi_done(xs);
357: splx(s);
358: return COMPLETE;
359:
360: default:
361: DPRINTF(("%s: unsupported scsi command %#x\n",
362: DEVNAME(sc), xs->cmd->opcode));
363: xs->error = XS_DRIVER_STUFFUP;
364: s = splbio();
365: scsi_done(xs);
366: splx(s);
367: return COMPLETE;
368: }
369:
370: /* A read or write operation. */
371: sdmmc_scsi_decode_rw(xs, &blockno, &blockcnt);
372:
373: if (blockno >= tgt->card->csd.capacity ||
374: blockno + blockcnt > tgt->card->csd.capacity) {
375: DPRINTF(("%s: out of bounds %u-%u >= %u\n", DEVNAME(sc),
376: blockno, blockcnt, tgt->card->csd.capacity));
377: xs->error = XS_DRIVER_STUFFUP;
378: s = splbio();
379: scsi_done(xs);
380: splx(s);
381: return COMPLETE;
382: }
383:
384: ccb = sdmmc_get_ccb(sc->sc_scsibus, xs->flags);
385: if (ccb == NULL) {
386: printf("%s: out of ccbs\n", DEVNAME(sc));
387: xs->error = XS_DRIVER_STUFFUP;
388: s = splbio();
389: scsi_done(xs);
390: splx(s);
391: return COMPLETE;
392: }
393:
394: ccb->ccb_xs = xs;
395: ccb->ccb_done = sdmmc_done_xs;
396:
397: ccb->ccb_blockcnt = blockcnt;
398: ccb->ccb_blockno = blockno;
399:
400: return sdmmc_start_xs(sc, ccb);
401: }
402:
403: int
404: sdmmc_start_xs(struct sdmmc_softc *sc, struct sdmmc_ccb *ccb)
405: {
406: struct sdmmc_scsi_softc *scbus = sc->sc_scsibus;
407: struct scsi_xfer *xs = ccb->ccb_xs;
408: int s;
409:
410: timeout_set(&xs->stimeout, sdmmc_stimeout, ccb);
411: sdmmc_init_task(&ccb->ccb_task, sdmmc_complete_xs, ccb);
412:
413: s = splbio();
414: TAILQ_INSERT_TAIL(&scbus->sc_ccb_runq, ccb, ccb_link);
415: ccb->ccb_state = SDMMC_CCB_QUEUED;
416: splx(s);
417:
418: if (ISSET(xs->flags, SCSI_POLL)) {
419: sdmmc_complete_xs(ccb);
420: return COMPLETE;
421: }
422:
423: timeout_add(&xs->stimeout, (xs->timeout * hz) / 1000);
424: sdmmc_add_task(sc, &ccb->ccb_task);
425: return SUCCESSFULLY_QUEUED;
426: }
427:
428: void
429: sdmmc_complete_xs(void *arg)
430: {
431: struct sdmmc_ccb *ccb = arg;
432: struct scsi_xfer *xs = ccb->ccb_xs;
433: struct scsi_link *link = xs->sc_link;
434: struct sdmmc_softc *sc = link->adapter_softc;
435: struct sdmmc_scsi_softc *scbus = sc->sc_scsibus;
436: struct sdmmc_scsi_target *tgt = &scbus->sc_tgt[link->target];
437: int error;
438: int s;
439:
440: DPRINTF(("%s: scsi cmd target=%d opcode=%#x proc=\"%s\" (poll=%#x)"
441: " complete\n", DEVNAME(sc), link->target, xs->cmd->opcode,
442: curproc ? curproc->p_comm : "", xs->flags & SCSI_POLL));
443:
444: s = splbio();
445:
446: if (ISSET(xs->flags, SCSI_DATA_IN))
447: error = sdmmc_mem_read_block(tgt->card, ccb->ccb_blockno,
448: xs->data, ccb->ccb_blockcnt * DEV_BSIZE);
449: else
450: error = sdmmc_mem_write_block(tgt->card, ccb->ccb_blockno,
451: xs->data, ccb->ccb_blockcnt * DEV_BSIZE);
452:
453: if (error != 0)
454: xs->error = XS_DRIVER_STUFFUP;
455:
456: ccb->ccb_done(ccb);
457: splx(s);
458: }
459:
460: void
461: sdmmc_done_xs(struct sdmmc_ccb *ccb)
462: {
463: struct scsi_xfer *xs = ccb->ccb_xs;
464: #ifdef SDMMC_DEBUG
465: struct scsi_link *link = xs->sc_link;
466: struct sdmmc_softc *sc = link->adapter_softc;
467: #endif
468:
469: timeout_del(&xs->stimeout);
470:
471: DPRINTF(("%s: scsi cmd target=%d opcode=%#x proc=\"%s\" (error=%#x)"
472: " done\n", DEVNAME(sc), link->target, xs->cmd->opcode,
473: curproc ? curproc->p_comm : "", xs->error));
474:
475: xs->resid = 0;
476: xs->flags |= ITSDONE;
477:
478: if (ISSET(ccb->ccb_flags, SDMMC_CCB_F_ERR))
479: xs->error = XS_DRIVER_STUFFUP;
480:
481: sdmmc_put_ccb(ccb);
482: scsi_done(xs);
483: }
484:
485: void
486: sdmmc_stimeout(void *arg)
487: {
488: struct sdmmc_ccb *ccb = arg;
489: int s;
490:
491: s = splbio();
492: ccb->ccb_flags |= SDMMC_CCB_F_ERR;
493: if (sdmmc_task_pending(&ccb->ccb_task)) {
494: sdmmc_del_task(&ccb->ccb_task);
495: ccb->ccb_done(ccb);
496: }
497: splx(s);
498: }
499:
500: void
501: sdmmc_scsi_minphys(struct buf *bp)
502: {
503: /* XXX limit to max. transfer size supported by card/host? */
504: if (bp->b_bcount > DEV_BSIZE)
505: bp->b_bcount = DEV_BSIZE;
506: minphys(bp);
507: }
CVSweb