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 47struct sdmmc_scsi_target { 48 struct sdmmc_function *card; 49}; 50 51struct 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 68TAILQ_HEAD(sdmmc_ccb_list, sdmmc_ccb); 69 70struct 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 82int sdmmc_alloc_ccbs(struct sdmmc_scsi_softc *, int); 83void sdmmc_free_ccbs(struct sdmmc_scsi_softc *); 84void *sdmmc_ccb_alloc(void *); 85void sdmmc_ccb_free(void *, void *); 86 87void sdmmc_scsi_cmd(struct scsi_xfer *); 88void sdmmc_inquiry(struct scsi_xfer *); 89void sdmmc_start_xs(struct sdmmc_softc *, struct sdmmc_ccb *); 90void sdmmc_complete_xs(void *); 91void sdmmc_done_xs(struct sdmmc_ccb *); 92void sdmmc_stimeout(void *); 93void sdmmc_minphys(struct buf *, struct scsi_link *); 94 95const 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 105void 106sdmmc_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 166void 167sdmmc_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 202int 203sdmmc_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 232void 233sdmmc_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 242void * 243sdmmc_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 259void 260sdmmc_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". */ 285static void 286sdmmc_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 303void 304sdmmc_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 386void 387sdmmc_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 456done: 457 scsi_done(xs); 458} 459 460void 461sdmmc_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 484void 485sdmmc_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 516void 517sdmmc_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 539void 540sdmmc_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 554void 555sdmmc_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 571int 572sdmmc_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