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