Line data Source code
1 : /* $OpenBSD: sdmmc_scsi.c,v 1.42 2018/03/30 07:18:39 jmatthew 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/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 : #ifdef HIBERNATE
36 : #include <sys/hibernate.h>
37 : #include <sys/disk.h>
38 : #include <sys/disklabel.h>
39 : #include <sys/rwlock.h>
40 : #endif
41 :
42 : #define SDMMC_SCSIID_HOST 0x00
43 : #define SDMMC_SCSIID_MAX 0x0f
44 :
45 : #define SDMMC_SCSI_MAXCMDS 8
46 :
47 : struct sdmmc_scsi_target {
48 : struct sdmmc_function *card;
49 : };
50 :
51 : struct sdmmc_ccb {
52 : struct sdmmc_scsi_softc *ccb_scbus;
53 : struct scsi_xfer *ccb_xs;
54 : int ccb_flags;
55 : #define SDMMC_CCB_F_ERR 0x0001
56 : u_int32_t ccb_blockno;
57 : u_int32_t ccb_blockcnt;
58 : volatile enum {
59 : SDMMC_CCB_FREE,
60 : SDMMC_CCB_READY,
61 : SDMMC_CCB_QUEUED
62 : } ccb_state;
63 : struct sdmmc_command ccb_cmd;
64 : struct sdmmc_task ccb_task;
65 : TAILQ_ENTRY(sdmmc_ccb) ccb_link;
66 : };
67 :
68 : TAILQ_HEAD(sdmmc_ccb_list, sdmmc_ccb);
69 :
70 : struct sdmmc_scsi_softc {
71 : struct scsi_adapter sc_adapter;
72 : struct scsi_link sc_link;
73 : struct device *sc_child;
74 : struct sdmmc_scsi_target *sc_tgt;
75 : int sc_ntargets;
76 : struct sdmmc_ccb *sc_ccbs; /* allocated ccbs */
77 : int sc_nccbs;
78 : struct sdmmc_ccb_list sc_ccb_freeq; /* free ccbs */
79 : struct sdmmc_ccb_list sc_ccb_runq; /* queued ccbs */
80 : struct mutex sc_ccb_mtx;
81 : struct scsi_iopool sc_iopool;
82 : };
83 :
84 : int sdmmc_alloc_ccbs(struct sdmmc_scsi_softc *, int);
85 : void sdmmc_free_ccbs(struct sdmmc_scsi_softc *);
86 : void *sdmmc_ccb_alloc(void *);
87 : void sdmmc_ccb_free(void *, void *);
88 :
89 : void sdmmc_scsi_cmd(struct scsi_xfer *);
90 : void sdmmc_inquiry(struct scsi_xfer *);
91 : void sdmmc_start_xs(struct sdmmc_softc *, struct sdmmc_ccb *);
92 : void sdmmc_complete_xs(void *);
93 : void sdmmc_done_xs(struct sdmmc_ccb *);
94 : void sdmmc_stimeout(void *);
95 : void sdmmc_scsi_minphys(struct buf *, struct scsi_link *);
96 :
97 : #ifdef SDMMC_DEBUG
98 : #define DPRINTF(s) printf s
99 : #else
100 : #define DPRINTF(s) /**/
101 : #endif
102 :
103 : void
104 0 : sdmmc_scsi_attach(struct sdmmc_softc *sc)
105 : {
106 0 : struct sdmmc_attach_args saa;
107 : struct sdmmc_scsi_softc *scbus;
108 : struct sdmmc_function *sf;
109 :
110 0 : rw_assert_wrlock(&sc->sc_lock);
111 :
112 0 : scbus = malloc(sizeof *scbus, M_DEVBUF, M_WAITOK | M_ZERO);
113 :
114 0 : scbus->sc_tgt = mallocarray(sizeof(*scbus->sc_tgt),
115 : (SDMMC_SCSIID_MAX+1), M_DEVBUF, M_WAITOK | M_ZERO);
116 :
117 : /*
118 : * Each card that sent us a CID in the identification stage
119 : * gets a SCSI ID > 0, whether it is a memory card or not.
120 : */
121 0 : scbus->sc_ntargets = 1;
122 0 : SIMPLEQ_FOREACH(sf, &sc->sf_head, sf_list) {
123 0 : if (scbus->sc_ntargets >= SDMMC_SCSIID_MAX+1)
124 : break;
125 0 : scbus->sc_tgt[scbus->sc_ntargets].card = sf;
126 0 : scbus->sc_ntargets++;
127 : }
128 :
129 : /* Preallocate some CCBs and initialize the CCB lists. */
130 0 : if (sdmmc_alloc_ccbs(scbus, SDMMC_SCSI_MAXCMDS) != 0) {
131 0 : printf("%s: can't allocate ccbs\n", sc->sc_dev.dv_xname);
132 0 : goto free_sctgt;
133 : }
134 :
135 0 : sc->sc_scsibus = scbus;
136 :
137 0 : scbus->sc_adapter.scsi_cmd = sdmmc_scsi_cmd;
138 0 : scbus->sc_adapter.scsi_minphys = sdmmc_scsi_minphys;
139 :
140 0 : scbus->sc_link.adapter_target = SDMMC_SCSIID_HOST;
141 0 : scbus->sc_link.adapter_buswidth = scbus->sc_ntargets;
142 0 : scbus->sc_link.adapter_softc = sc;
143 0 : scbus->sc_link.luns = 1;
144 0 : scbus->sc_link.openings = 1;
145 0 : scbus->sc_link.adapter = &scbus->sc_adapter;
146 0 : scbus->sc_link.pool = &scbus->sc_iopool;
147 :
148 0 : bzero(&saa, sizeof(saa));
149 0 : saa.scsi_link = &scbus->sc_link;
150 :
151 0 : scbus->sc_child = config_found(&sc->sc_dev, &saa, scsiprint);
152 0 : if (scbus->sc_child == NULL) {
153 0 : printf("%s: can't attach scsibus\n", sc->sc_dev.dv_xname);
154 : goto free_ccbs;
155 : }
156 0 : return;
157 :
158 : free_ccbs:
159 0 : sc->sc_scsibus = NULL;
160 0 : sdmmc_free_ccbs(scbus);
161 : free_sctgt:
162 0 : free(scbus->sc_tgt, M_DEVBUF,
163 : sizeof(*scbus->sc_tgt) * (SDMMC_SCSIID_MAX+1));
164 0 : free(scbus, M_DEVBUF, sizeof *scbus);
165 0 : }
166 :
167 : void
168 0 : sdmmc_scsi_detach(struct sdmmc_softc *sc)
169 : {
170 : struct sdmmc_scsi_softc *scbus;
171 : struct sdmmc_ccb *ccb;
172 : int s;
173 :
174 0 : rw_assert_wrlock(&sc->sc_lock);
175 :
176 0 : scbus = sc->sc_scsibus;
177 0 : if (scbus == NULL)
178 0 : return;
179 :
180 : /* Complete all open scsi xfers. */
181 0 : s = splbio();
182 0 : for (ccb = TAILQ_FIRST(&scbus->sc_ccb_runq); ccb != NULL;
183 0 : ccb = TAILQ_FIRST(&scbus->sc_ccb_runq))
184 0 : sdmmc_stimeout(ccb);
185 0 : splx(s);
186 :
187 0 : if (scbus->sc_child != NULL)
188 0 : config_detach(scbus->sc_child, DETACH_FORCE);
189 :
190 0 : if (scbus->sc_tgt != NULL)
191 0 : free(scbus->sc_tgt, M_DEVBUF,
192 : sizeof(*scbus->sc_tgt) * (SDMMC_SCSIID_MAX+1));
193 :
194 0 : sdmmc_free_ccbs(scbus);
195 0 : free(scbus, M_DEVBUF, sizeof *scbus);
196 0 : sc->sc_scsibus = NULL;
197 0 : }
198 :
199 : /*
200 : * CCB management
201 : */
202 :
203 : int
204 0 : sdmmc_alloc_ccbs(struct sdmmc_scsi_softc *scbus, int nccbs)
205 : {
206 : struct sdmmc_ccb *ccb;
207 : int i;
208 :
209 0 : scbus->sc_ccbs = mallocarray(nccbs, sizeof(struct sdmmc_ccb),
210 : M_DEVBUF, M_NOWAIT);
211 0 : if (scbus->sc_ccbs == NULL)
212 0 : return 1;
213 0 : scbus->sc_nccbs = nccbs;
214 :
215 0 : TAILQ_INIT(&scbus->sc_ccb_freeq);
216 0 : TAILQ_INIT(&scbus->sc_ccb_runq);
217 0 : mtx_init(&scbus->sc_ccb_mtx, IPL_BIO);
218 0 : scsi_iopool_init(&scbus->sc_iopool, scbus, sdmmc_ccb_alloc,
219 : sdmmc_ccb_free);
220 :
221 0 : for (i = 0; i < nccbs; i++) {
222 0 : ccb = &scbus->sc_ccbs[i];
223 0 : ccb->ccb_scbus = scbus;
224 0 : ccb->ccb_state = SDMMC_CCB_FREE;
225 0 : ccb->ccb_flags = 0;
226 0 : ccb->ccb_xs = NULL;
227 :
228 0 : TAILQ_INSERT_TAIL(&scbus->sc_ccb_freeq, ccb, ccb_link);
229 : }
230 0 : return 0;
231 0 : }
232 :
233 : void
234 0 : sdmmc_free_ccbs(struct sdmmc_scsi_softc *scbus)
235 : {
236 0 : if (scbus->sc_ccbs != NULL) {
237 0 : free(scbus->sc_ccbs, M_DEVBUF,
238 0 : scbus->sc_nccbs * sizeof(struct sdmmc_ccb));
239 0 : scbus->sc_ccbs = NULL;
240 0 : }
241 0 : }
242 :
243 : void *
244 0 : sdmmc_ccb_alloc(void *xscbus)
245 : {
246 0 : struct sdmmc_scsi_softc *scbus = xscbus;
247 : struct sdmmc_ccb *ccb;
248 :
249 0 : mtx_enter(&scbus->sc_ccb_mtx);
250 0 : ccb = TAILQ_FIRST(&scbus->sc_ccb_freeq);
251 0 : if (ccb != NULL) {
252 0 : TAILQ_REMOVE(&scbus->sc_ccb_freeq, ccb, ccb_link);
253 0 : ccb->ccb_state = SDMMC_CCB_READY;
254 0 : }
255 0 : mtx_leave(&scbus->sc_ccb_mtx);
256 :
257 0 : return ccb;
258 : }
259 :
260 : void
261 0 : sdmmc_ccb_free(void *xscbus, void *xccb)
262 : {
263 0 : struct sdmmc_scsi_softc *scbus = xscbus;
264 0 : struct sdmmc_ccb *ccb = xccb;
265 : int s;
266 :
267 0 : s = splbio();
268 0 : if (ccb->ccb_state == SDMMC_CCB_QUEUED)
269 0 : TAILQ_REMOVE(&scbus->sc_ccb_runq, ccb, ccb_link);
270 0 : splx(s);
271 :
272 0 : ccb->ccb_state = SDMMC_CCB_FREE;
273 0 : ccb->ccb_flags = 0;
274 0 : ccb->ccb_xs = NULL;
275 :
276 0 : mtx_enter(&scbus->sc_ccb_mtx);
277 0 : TAILQ_INSERT_TAIL(&scbus->sc_ccb_freeq, ccb, ccb_link);
278 0 : mtx_leave(&scbus->sc_ccb_mtx);
279 0 : }
280 :
281 : /*
282 : * SCSI command emulation
283 : */
284 :
285 : /* XXX move to some sort of "scsi emulation layer". */
286 : static void
287 0 : sdmmc_scsi_decode_rw(struct scsi_xfer *xs, u_int32_t *blocknop,
288 : u_int32_t *blockcntp)
289 : {
290 : struct scsi_rw *rw;
291 : struct scsi_rw_big *rwb;
292 :
293 0 : if (xs->cmdlen == 6) {
294 0 : rw = (struct scsi_rw *)xs->cmd;
295 0 : *blocknop = _3btol(rw->addr) & (SRW_TOPADDR << 16 | 0xffff);
296 0 : *blockcntp = rw->length ? rw->length : 0x100;
297 0 : } else {
298 0 : rwb = (struct scsi_rw_big *)xs->cmd;
299 0 : *blocknop = _4btol(rwb->addr);
300 0 : *blockcntp = _2btol(rwb->length);
301 : }
302 0 : }
303 :
304 : void
305 0 : sdmmc_scsi_cmd(struct scsi_xfer *xs)
306 : {
307 0 : struct scsi_link *link = xs->sc_link;
308 0 : struct sdmmc_softc *sc = link->adapter_softc;
309 0 : struct sdmmc_scsi_softc *scbus = sc->sc_scsibus;
310 0 : struct sdmmc_scsi_target *tgt = &scbus->sc_tgt[link->target];
311 0 : struct scsi_read_cap_data rcd;
312 0 : u_int32_t blockno;
313 0 : u_int32_t blockcnt;
314 : struct sdmmc_ccb *ccb;
315 :
316 0 : if (link->target >= scbus->sc_ntargets || tgt->card == NULL ||
317 0 : link->lun != 0) {
318 : DPRINTF(("%s: sdmmc_scsi_cmd: no target %d\n",
319 : DEVNAME(sc), link->target));
320 : /* XXX should be XS_SENSE and sense filled out */
321 0 : xs->error = XS_DRIVER_STUFFUP;
322 0 : scsi_done(xs);
323 0 : return;
324 : }
325 :
326 : DPRINTF(("%s: scsi cmd target=%d opcode=%#x proc=\"%s\" (poll=%#x)\n",
327 : DEVNAME(sc), link->target, xs->cmd->opcode, curproc ?
328 : curproc->p_p->ps_comm : "", xs->flags & SCSI_POLL));
329 :
330 0 : xs->error = XS_NOERROR;
331 :
332 0 : switch (xs->cmd->opcode) {
333 : case READ_COMMAND:
334 : case READ_BIG:
335 : case WRITE_COMMAND:
336 : case WRITE_BIG:
337 : /* Deal with I/O outside the switch. */
338 : break;
339 :
340 : case INQUIRY:
341 0 : sdmmc_inquiry(xs);
342 0 : return;
343 :
344 : case TEST_UNIT_READY:
345 : case START_STOP:
346 : case SYNCHRONIZE_CACHE:
347 0 : scsi_done(xs);
348 0 : return;
349 :
350 : case READ_CAPACITY:
351 0 : bzero(&rcd, sizeof rcd);
352 0 : _lto4b(tgt->card->csd.capacity - 1, rcd.addr);
353 0 : _lto4b(tgt->card->csd.sector_size, rcd.length);
354 0 : bcopy(&rcd, xs->data, MIN(xs->datalen, sizeof rcd));
355 0 : scsi_done(xs);
356 0 : return;
357 :
358 : default:
359 : DPRINTF(("%s: unsupported scsi command %#x\n",
360 : DEVNAME(sc), xs->cmd->opcode));
361 0 : xs->error = XS_DRIVER_STUFFUP;
362 0 : scsi_done(xs);
363 0 : return;
364 : }
365 :
366 : /* A read or write operation. */
367 0 : sdmmc_scsi_decode_rw(xs, &blockno, &blockcnt);
368 :
369 0 : if (blockno >= tgt->card->csd.capacity ||
370 0 : blockno + blockcnt > tgt->card->csd.capacity) {
371 : DPRINTF(("%s: out of bounds %u-%u >= %u\n", DEVNAME(sc),
372 : blockno, blockcnt, tgt->card->csd.capacity));
373 0 : xs->error = XS_DRIVER_STUFFUP;
374 0 : scsi_done(xs);
375 0 : return;
376 : }
377 :
378 0 : ccb = xs->io;
379 :
380 0 : ccb->ccb_xs = xs;
381 0 : ccb->ccb_blockcnt = blockcnt;
382 0 : ccb->ccb_blockno = blockno;
383 :
384 0 : sdmmc_start_xs(sc, ccb);
385 0 : }
386 :
387 : void
388 0 : sdmmc_inquiry(struct scsi_xfer *xs)
389 : {
390 0 : struct scsi_link *link = xs->sc_link;
391 0 : struct sdmmc_softc *sc = link->adapter_softc;
392 0 : struct sdmmc_scsi_softc *scbus = sc->sc_scsibus;
393 0 : struct sdmmc_scsi_target *tgt = &scbus->sc_tgt[link->target];
394 0 : struct scsi_inquiry_data inq;
395 0 : struct scsi_inquiry *cdb = (struct scsi_inquiry *)xs->cmd;
396 0 : char vendor[sizeof(inq.vendor) + 1];
397 0 : char product[sizeof(inq.product) + 1];
398 0 : char revision[sizeof(inq.revision) + 1];
399 :
400 0 : if (xs->cmdlen != sizeof(*cdb)) {
401 0 : xs->error = XS_DRIVER_STUFFUP;
402 0 : goto done;
403 : }
404 :
405 0 : if (ISSET(cdb->flags, SI_EVPD)) {
406 0 : xs->error = XS_DRIVER_STUFFUP;
407 0 : goto done;
408 : }
409 :
410 0 : memset(vendor, 0, sizeof(vendor));
411 0 : memset(product, 0, sizeof(product));
412 0 : memset(revision, 0, sizeof(revision));
413 0 : switch (tgt->card->cid.mid) {
414 : case 0x02:
415 : case 0x45:
416 0 : strlcpy(vendor, "Sandisk", sizeof(vendor));
417 0 : break;
418 : case 0x11:
419 0 : strlcpy(vendor, "Toshiba", sizeof(vendor));
420 0 : break;
421 : case 0x13:
422 0 : strlcpy(vendor, "Micron", sizeof(vendor));
423 0 : break;
424 : case 0x15:
425 0 : strlcpy(vendor, "Samsung", sizeof(vendor));
426 0 : break;
427 : case 0x70:
428 0 : strlcpy(vendor, "Kingston", sizeof(vendor));
429 0 : break;
430 : default:
431 0 : strlcpy(vendor, "SD/MMC", sizeof(vendor));
432 0 : break;
433 : }
434 0 : strlcpy(product, tgt->card->cid.pnm, sizeof(product));
435 0 : snprintf(revision, sizeof(revision), "%04X", tgt->card->cid.rev);
436 :
437 0 : memset(&inq, 0, sizeof inq);
438 0 : inq.device = T_DIRECT;
439 0 : inq.dev_qual2 = SID_REMOVABLE;
440 0 : inq.version = 2;
441 0 : inq.response_format = 2;
442 0 : inq.additional_length = 32;
443 0 : memcpy(inq.vendor, vendor, sizeof(inq.vendor));
444 0 : memcpy(inq.product, product, sizeof(inq.product));
445 0 : memcpy(inq.revision, revision, sizeof(inq.revision));
446 :
447 0 : memcpy(xs->data, &inq, MIN(xs->datalen, sizeof(inq)));
448 :
449 : done:
450 0 : scsi_done(xs);
451 0 : }
452 :
453 : void
454 0 : sdmmc_start_xs(struct sdmmc_softc *sc, struct sdmmc_ccb *ccb)
455 : {
456 0 : struct sdmmc_scsi_softc *scbus = sc->sc_scsibus;
457 0 : struct scsi_xfer *xs = ccb->ccb_xs;
458 : int s;
459 :
460 0 : timeout_set(&xs->stimeout, sdmmc_stimeout, ccb);
461 0 : sdmmc_init_task(&ccb->ccb_task, sdmmc_complete_xs, ccb);
462 :
463 0 : s = splbio();
464 0 : TAILQ_INSERT_TAIL(&scbus->sc_ccb_runq, ccb, ccb_link);
465 0 : ccb->ccb_state = SDMMC_CCB_QUEUED;
466 0 : splx(s);
467 :
468 0 : if (ISSET(xs->flags, SCSI_POLL)) {
469 0 : sdmmc_complete_xs(ccb);
470 0 : return;
471 : }
472 :
473 0 : timeout_add_msec(&xs->stimeout, xs->timeout);
474 0 : sdmmc_add_task(sc, &ccb->ccb_task);
475 0 : }
476 :
477 : void
478 0 : sdmmc_complete_xs(void *arg)
479 : {
480 0 : struct sdmmc_ccb *ccb = arg;
481 0 : struct scsi_xfer *xs = ccb->ccb_xs;
482 0 : struct scsi_link *link = xs->sc_link;
483 0 : struct sdmmc_softc *sc = link->adapter_softc;
484 0 : struct sdmmc_scsi_softc *scbus = sc->sc_scsibus;
485 0 : struct sdmmc_scsi_target *tgt = &scbus->sc_tgt[link->target];
486 : int error;
487 : int s;
488 :
489 : DPRINTF(("%s: scsi cmd target=%d opcode=%#x proc=\"%s\" (poll=%#x)"
490 : " complete\n", DEVNAME(sc), link->target, xs->cmd->opcode,
491 : curproc ? curproc->p_p->ps_comm : "", xs->flags & SCSI_POLL));
492 :
493 0 : s = splbio();
494 :
495 0 : if (ISSET(xs->flags, SCSI_DATA_IN))
496 0 : error = sdmmc_mem_read_block(tgt->card, ccb->ccb_blockno,
497 : xs->data, ccb->ccb_blockcnt * DEV_BSIZE);
498 : else
499 0 : error = sdmmc_mem_write_block(tgt->card, ccb->ccb_blockno,
500 : xs->data, ccb->ccb_blockcnt * DEV_BSIZE);
501 :
502 0 : if (error != 0)
503 0 : xs->error = XS_DRIVER_STUFFUP;
504 :
505 0 : sdmmc_done_xs(ccb);
506 0 : splx(s);
507 0 : }
508 :
509 : void
510 0 : sdmmc_done_xs(struct sdmmc_ccb *ccb)
511 : {
512 0 : struct scsi_xfer *xs = ccb->ccb_xs;
513 : #ifdef SDMMC_DEBUG
514 : struct scsi_link *link = xs->sc_link;
515 : struct sdmmc_softc *sc = link->adapter_softc;
516 : #endif
517 :
518 0 : timeout_del(&xs->stimeout);
519 :
520 : DPRINTF(("%s: scsi cmd target=%d opcode=%#x proc=\"%s\" (error=%#x)"
521 : " done\n", DEVNAME(sc), link->target, xs->cmd->opcode,
522 : curproc ? curproc->p_p->ps_comm : "", xs->error));
523 :
524 0 : xs->resid = 0;
525 :
526 0 : if (ISSET(ccb->ccb_flags, SDMMC_CCB_F_ERR))
527 0 : xs->error = XS_DRIVER_STUFFUP;
528 :
529 0 : scsi_done(xs);
530 0 : }
531 :
532 : void
533 0 : sdmmc_stimeout(void *arg)
534 : {
535 0 : struct sdmmc_ccb *ccb = arg;
536 : int s;
537 :
538 0 : s = splbio();
539 0 : ccb->ccb_flags |= SDMMC_CCB_F_ERR;
540 0 : if (sdmmc_task_pending(&ccb->ccb_task)) {
541 0 : sdmmc_del_task(&ccb->ccb_task);
542 0 : sdmmc_done_xs(ccb);
543 0 : }
544 0 : splx(s);
545 0 : }
546 :
547 : void
548 0 : sdmmc_scsi_minphys(struct buf *bp, struct scsi_link *sl)
549 : {
550 0 : struct sdmmc_softc *sc = sl->adapter_softc;
551 0 : struct sdmmc_scsi_softc *scbus = sc->sc_scsibus;
552 0 : struct sdmmc_scsi_target *tgt = &scbus->sc_tgt[sl->target];
553 0 : struct sdmmc_function *sf = tgt->card;
554 :
555 : /* limit to max. transfer size supported by card/host */
556 0 : if (sc->sc_max_xfer != 0 &&
557 0 : bp->b_bcount > sf->csd.sector_size * sc->sc_max_xfer)
558 0 : bp->b_bcount = sf->csd.sector_size * sc->sc_max_xfer;
559 :
560 0 : minphys(bp);
561 0 : }
562 :
563 : #ifdef HIBERNATE
564 : int
565 0 : sdmmc_scsi_hibernate_io(dev_t dev, daddr_t blkno, vaddr_t addr, size_t size,
566 : int op, void *page)
567 : {
568 : struct {
569 : struct sdmmc_softc sdmmc_sc;
570 : struct sdmmc_function sdmmc_sf;
571 : daddr_t poffset;
572 : size_t psize;
573 : struct sdmmc_function *orig_sf;
574 : char chipset_softc[0]; /* size depends on the chipset layer */
575 0 : } *state = page;
576 : extern struct cfdriver sd_cd;
577 : struct device *disk, *scsibus, *chip, *sdmmc;
578 : struct scsibus_softc *bus_sc;
579 : struct sdmmc_scsi_softc *scsi_sc;
580 : struct scsi_link *link;
581 : struct sdmmc_function *sf;
582 : struct sdmmc_softc *sc;
583 : int error;
584 :
585 0 : switch (op) {
586 : case HIB_INIT:
587 : /* find device (sdmmc_softc, sdmmc_function) */
588 0 : disk = disk_lookup(&sd_cd, DISKUNIT(dev));
589 0 : if (disk == NULL)
590 0 : return (ENOTTY);
591 :
592 0 : scsibus = disk->dv_parent;
593 0 : sdmmc = scsibus->dv_parent;
594 0 : chip = sdmmc->dv_parent;
595 :
596 0 : bus_sc = (struct scsibus_softc *)scsibus;
597 : scsi_sc = (struct sdmmc_scsi_softc *)scsibus;
598 : sc = NULL;
599 0 : SLIST_FOREACH(link, &bus_sc->sc_link_list, bus_list) {
600 0 : if (link->device_softc == disk) {
601 0 : sc = (struct sdmmc_softc *)link->adapter_softc;
602 0 : scsi_sc = sc->sc_scsibus;
603 0 : sf = scsi_sc->sc_tgt[link->target].card;
604 0 : }
605 : }
606 0 : if (sc == NULL || sf == NULL)
607 0 : return (ENOTTY);
608 :
609 : /* if the chipset doesn't do hibernate, bail out now */
610 0 : sc = (struct sdmmc_softc *)sdmmc;
611 0 : if (sc->sct->hibernate_init == NULL)
612 0 : return (ENOTTY);
613 :
614 0 : state->sdmmc_sc = *sc;
615 0 : state->sdmmc_sf = *sf;
616 0 : state->sdmmc_sf.sc = &state->sdmmc_sc;
617 :
618 : /* pretend we own the lock */
619 0 : state->sdmmc_sc.sc_lock.rwl_owner =
620 0 : (((long)curproc) & ~RWLOCK_MASK) | RWLOCK_WRLOCK;
621 :
622 : /* build chip layer fake softc */
623 0 : error = state->sdmmc_sc.sct->hibernate_init(state->sdmmc_sc.sch,
624 0 : &state->chipset_softc);
625 0 : if (error)
626 0 : return (error);
627 0 : state->sdmmc_sc.sch = state->chipset_softc;
628 :
629 : /* make sure we're talking to the right target */
630 0 : state->orig_sf = sc->sc_card;
631 0 : error = sdmmc_select_card(&state->sdmmc_sc, &state->sdmmc_sf);
632 0 : if (error)
633 0 : return (error);
634 :
635 0 : state->poffset = blkno;
636 0 : state->psize = size;
637 0 : return (0);
638 :
639 : case HIB_W:
640 0 : if (blkno > state->psize)
641 0 : return (E2BIG);
642 0 : return (sdmmc_mem_hibernate_write(&state->sdmmc_sf,
643 0 : blkno + state->poffset, (u_char *)addr, size));
644 :
645 : case HIB_DONE:
646 : /*
647 : * bring the hardware state back into line with the real
648 : * softc by operating on the fake one
649 : */
650 0 : return (sdmmc_select_card(&state->sdmmc_sc, state->orig_sf));
651 : }
652 :
653 0 : return (EINVAL);
654 0 : }
655 :
656 : #endif
|