1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Memory target support for SDcard. 28 */ 29 30 #include <sys/types.h> 31 #include <sys/types.h> 32 #include <sys/note.h> 33 #include <sys/conf.h> 34 #include <sys/scsi/adapters/blk2scsa.h> 35 #include <sys/ddi.h> 36 #include <sys/sunddi.h> 37 #include <sys/sdcard/sda.h> 38 #include <sys/sdcard/sda_impl.h> 39 40 static int sda_mem_attach(dev_info_t *, ddi_attach_cmd_t); 41 static int sda_mem_detach(dev_info_t *, ddi_detach_cmd_t); 42 static int sda_mem_quiesce(dev_info_t *); 43 static b2s_err_t sda_mem_b2s_errno(sda_err_t); 44 static boolean_t sda_mem_b2s_request(void *, b2s_request_t *); 45 static boolean_t sda_mem_b2s_rw(sda_slot_t *, b2s_request_t *); 46 static void sda_mem_b2s_done(sda_cmd_t *); 47 static void sda_mem_getstring(uint32_t *, char *, int, int); 48 static int sda_mem_parse_cid_csd(sda_slot_t *, dev_info_t *); 49 static int sda_mem_cmd(sda_slot_t *, uint8_t, uint32_t, uint8_t, uint32_t *); 50 51 52 /* 53 * To minimize complexity and reduce layering, we implement almost the 54 * entire memory card driver (sdcard) here. The memory card still 55 * needs to be a separate driver though, due to the requirement to 56 * have both SCSI HBA bus ops and SD bus ops. 57 */ 58 59 /* 60 * SCSA layer supplies a cb_ops, but we don't want it, because we 61 * don't want to expose a SCSI attachment point. (Our parent handles 62 * the attachment point, the SCSI one would be confusing.) We have to 63 * supply a stubbed out one, to prevent SCSA from trying to create minor 64 * nodes on our behalf. 65 * 66 * Perhaps at some future point we might want to expose a separate set 67 * of ioctls for these nodes, but for now we rely on our parent to do 68 * all that work. 69 */ 70 static struct cb_ops sda_mem_ops = { 71 nodev, /* cb_open */ 72 nodev, /* cb_close */ 73 nodev, /* cb_strategy */ 74 nodev, /* cb_print */ 75 nodev, /* cb_dump */ 76 nodev, /* cb_read */ 77 nodev, /* cb_write */ 78 nodev, /* cb_ioctl */ 79 nodev, /* cb_devmap */ 80 nodev, /* cb_mmap */ 81 nodev, /* cb_segmap */ 82 nochpoll, /* cb_chpoll */ 83 ddi_prop_op, /* cb_prop_op */ 84 NULL, /* cb_stream */ 85 D_MP /* cb_flag */ 86 }; 87 88 /* 89 * Here are the public functions. 90 */ 91 void 92 sda_mem_init(struct modlinkage *modlp) 93 { 94 struct dev_ops *devo; 95 96 devo = ((struct modldrv *)(modlp->ml_linkage[0]))->drv_dev_ops; 97 devo->devo_attach = sda_mem_attach; 98 devo->devo_detach = sda_mem_detach; 99 devo->devo_quiesce = sda_mem_quiesce; 100 101 devo->devo_cb_ops = &sda_mem_ops; 102 103 /* it turns out that this can't ever really fail */ 104 (void) b2s_mod_init(modlp); 105 } 106 107 void 108 sda_mem_fini(struct modlinkage *modlp) 109 { 110 b2s_mod_fini(modlp); 111 } 112 113 /* 114 * Everything beyond this is private. 115 */ 116 117 int 118 sda_mem_cmd(sda_slot_t *slot, uint8_t cmd, uint32_t arg, uint8_t rtype, 119 uint32_t *resp) 120 { 121 sda_cmd_t *cmdp; 122 int errno; 123 124 cmdp = sda_cmd_alloc(slot, cmd, arg, rtype, NULL, KM_SLEEP); 125 if (cmdp == NULL) { 126 return (ENOMEM); 127 } 128 errno = sda_cmd_exec(slot, cmdp, resp); 129 sda_cmd_free(cmdp); 130 131 return (errno); 132 } 133 134 boolean_t 135 sda_mem_b2s_rw(sda_slot_t *slot, b2s_request_t *reqp) 136 { 137 sda_cmd_t *cmdp; 138 uint64_t nblks; 139 uint64_t blkno; 140 uint16_t rblen; 141 int rv; 142 uint8_t index; 143 uint16_t flags; 144 145 blkno = reqp->br_lba; 146 nblks = reqp->br_nblks; 147 148 switch (reqp->br_cmd) { 149 case B2S_CMD_READ: 150 if (nblks > 1) { 151 index = CMD_READ_MULTI; 152 flags = SDA_CMDF_DAT | SDA_CMDF_MEM | SDA_CMDF_READ | 153 SDA_CMDF_AUTO_CMD12; 154 } else { 155 index = CMD_READ_SINGLE; 156 flags = SDA_CMDF_DAT | SDA_CMDF_MEM | SDA_CMDF_READ; 157 } 158 break; 159 case B2S_CMD_WRITE: 160 if (nblks > 1) { 161 index = CMD_WRITE_MULTI; 162 flags = SDA_CMDF_DAT | SDA_CMDF_MEM | SDA_CMDF_WRITE | 163 SDA_CMDF_AUTO_CMD12; 164 } else { 165 index = CMD_WRITE_SINGLE; 166 flags = SDA_CMDF_DAT | SDA_CMDF_MEM | SDA_CMDF_WRITE; 167 } 168 break; 169 default: 170 ASSERT(0); 171 break; 172 } 173 174 cmdp = sda_cmd_alloc(slot, index, blkno << slot->s_bshift, 175 R1, reqp, KM_NOSLEEP); 176 if (cmdp == NULL) { 177 b2s_request_done(reqp, B2S_ENOMEM, 0); 178 return (B_TRUE); 179 } 180 181 if (slot->s_hostp->h_dma != NULL) { 182 b2s_request_dma(reqp, &cmdp->sc_ndmac, &cmdp->sc_dmacs); 183 cmdp->sc_kvaddr = 0; 184 } 185 if ((slot->s_caps & SLOT_CAP_NOPIO) == 0) { 186 size_t maplen; 187 b2s_request_mapin(reqp, &cmdp->sc_kvaddr, &maplen); 188 cmdp->sc_ndmac = 0; 189 } 190 191 if (nblks == 0) { 192 /* 193 * This is not strictly a failure, but no work to do. 194 * We have to do it late here because we don't want to 195 * by pass the above media readiness checks. 196 */ 197 rv = B2S_EOK; 198 goto failed; 199 } 200 if (nblks > 0xffff) { 201 rv = B2S_EINVAL; 202 goto failed; 203 } 204 205 rblen = slot->s_blksz; 206 207 if ((blkno + nblks) > slot->s_nblks) { 208 rv = B2S_EBLKADDR; 209 goto failed; 210 } 211 212 cmdp->sc_rtype = R1; 213 cmdp->sc_blksz = rblen; 214 cmdp->sc_nblks = (uint16_t)nblks; 215 cmdp->sc_index = index; 216 cmdp->sc_flags = flags; 217 218 sda_cmd_submit(slot, cmdp, sda_mem_b2s_done); 219 return (B_TRUE); 220 221 failed: 222 sda_cmd_free(cmdp); 223 b2s_request_done(reqp, rv, 0); 224 return (B_TRUE); 225 } 226 227 boolean_t 228 sda_mem_b2s_format(sda_slot_t *slot, b2s_request_t *reqp) 229 { 230 sda_cmd_t *cmdp; 231 int rv; 232 233 234 rv = sda_mem_cmd(slot, CMD_ERASE_START, 0, R1, NULL); 235 if (rv != 0) { 236 b2s_request_done(reqp, sda_mem_b2s_errno(rv), 0); 237 return (B_TRUE); 238 } 239 rv = sda_mem_cmd(slot, CMD_ERASE_END, slot->s_nblks - 1, R1, NULL); 240 if (rv != 0) { 241 b2s_request_done(reqp, sda_mem_b2s_errno(rv), 0); 242 return (B_TRUE); 243 } 244 245 cmdp = sda_cmd_alloc(slot, CMD_ERASE, 0, R1b, reqp, KM_NOSLEEP); 246 if (cmdp == NULL) { 247 b2s_request_done(reqp, B2S_ENOMEM, 0); 248 return (B_TRUE); 249 } 250 cmdp->sc_flags = SDA_CMDF_DAT | SDA_CMDF_MEM; 251 252 sda_cmd_submit(slot, cmdp, sda_mem_b2s_done); 253 return (B_TRUE); 254 } 255 256 b2s_err_t 257 sda_mem_b2s_errno(sda_err_t errno) 258 { 259 /* the hot path */ 260 if (errno == SDA_EOK) { 261 return (B2S_EOK); 262 } 263 264 switch (errno) { 265 case SDA_ENOMEM: 266 return (B2S_ENOMEM); 267 case SDA_ETIME: 268 return (B2S_ETIMEDOUT); 269 case SDA_EWPROTECT: 270 return (B2S_EWPROTECT); 271 case SDA_ESUSPENDED: 272 case SDA_ENODEV: 273 return (B2S_ENOMEDIA); 274 case SDA_EFAULT: 275 case SDA_ECRC7: 276 case SDA_EPROTO: 277 return (B2S_EHARDWARE); 278 case SDA_ERESET: 279 return (B2S_ERESET); 280 case SDA_EIO: 281 case SDA_ERESID: 282 default: 283 return (B2S_EIO); 284 } 285 } 286 287 void 288 sda_mem_b2s_done(sda_cmd_t *cmdp) 289 { 290 b2s_request_t *reqp = sda_cmd_data(cmdp); 291 int errno = sda_cmd_errno(cmdp); 292 293 b2s_request_done(reqp, sda_mem_b2s_errno(errno), cmdp->sc_resid); 294 sda_cmd_free(cmdp); 295 } 296 297 boolean_t 298 sda_mem_b2s_request(void *arg, b2s_request_t *reqp) 299 { 300 sda_slot_t *slot = arg; 301 int rv; 302 303 switch (reqp->br_cmd) { 304 case B2S_CMD_WRITE: 305 if ((slot->s_flags & SLOTF_WRITABLE) == 0) { 306 rv = B2S_EWPROTECT; 307 } else { 308 return (sda_mem_b2s_rw(slot, reqp)); 309 } 310 break; 311 312 case B2S_CMD_READ: 313 return (sda_mem_b2s_rw(slot, reqp)); 314 315 case B2S_CMD_INQUIRY: 316 reqp->br_inquiry.inq_vendor = "OSOL"; 317 reqp->br_inquiry.inq_product = 318 slot->s_flags & SLOTF_MMC ? "MultiMediaCard" : 319 slot->s_flags & SLOTF_SDHC ? "SDHC Memory Card" : 320 "SD Memory Card"; 321 reqp->br_inquiry.inq_revision = ""; 322 reqp->br_inquiry.inq_serial = ""; 323 rv = B2S_EOK; 324 break; 325 326 case B2S_CMD_GETMEDIA: 327 if (!slot->s_ready) { 328 rv = B2S_ENODEV; 329 } else { 330 reqp->br_media.media_blksz = slot->s_blksz; 331 reqp->br_media.media_nblks = slot->s_nblks; 332 /* detect read-only cards */ 333 if (slot->s_flags & SLOTF_WRITABLE) { 334 reqp->br_media.media_flags = 0; 335 } else { 336 reqp->br_media.media_flags = 337 B2S_MEDIA_FLAG_READ_ONLY; 338 } 339 rv = B2S_EOK; 340 } 341 break; 342 343 case B2S_CMD_FORMAT: 344 return (sda_mem_b2s_format(slot, reqp)); 345 346 case B2S_CMD_ABORT: 347 sda_slot_mem_reset(slot, SDA_EABORT); 348 rv = B2S_EOK; 349 break; 350 351 case B2S_CMD_RESET: 352 sda_slot_mem_reset(slot, SDA_ERESET); 353 rv = B2S_EOK; 354 break; 355 356 case B2S_CMD_START: 357 case B2S_CMD_STOP: 358 case B2S_CMD_SYNC: 359 rv = B2S_EOK; 360 break; 361 362 case B2S_CMD_LOCK: 363 case B2S_CMD_UNLOCK: 364 default: 365 rv = B2S_ENOTSUP; 366 break; 367 } 368 369 b2s_request_done(reqp, rv, 0); 370 return (B_TRUE); 371 } 372 373 int 374 sda_mem_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 375 { 376 sda_slot_t *slot; 377 b2s_nexus_t *nexus; 378 b2s_nexus_info_t nexinfo; 379 b2s_leaf_info_t leafinfo; 380 381 switch (cmd) { 382 case DDI_ATTACH: 383 if ((slot = ddi_get_parent_data(dip)) == NULL) { 384 return (DDI_FAILURE); 385 } 386 387 if (sda_mem_parse_cid_csd(slot, dip) != DDI_SUCCESS) { 388 return (DDI_FAILURE); 389 } 390 391 nexinfo.nexus_version = B2S_VERSION_0; 392 nexinfo.nexus_private = slot; 393 nexinfo.nexus_dip = dip; 394 nexinfo.nexus_dma_attr = slot->s_hostp->h_dma; 395 nexinfo.nexus_request = sda_mem_b2s_request; 396 397 nexus = b2s_alloc_nexus(&nexinfo); 398 if (nexus == NULL) { 399 return (DDI_FAILURE); 400 } 401 402 leafinfo.leaf_target = 0; 403 leafinfo.leaf_lun = 0; 404 leafinfo.leaf_flags = 405 B2S_LEAF_REMOVABLE | B2S_LEAF_HOTPLUGGABLE; 406 leafinfo.leaf_unique_id = slot->s_uuid; 407 408 slot->s_leaf = b2s_attach_leaf(nexus, &leafinfo); 409 if (slot->s_leaf == NULL) { 410 b2s_free_nexus(nexus); 411 return (DDI_FAILURE); 412 } 413 414 slot->s_nexus = nexus; 415 if (b2s_attach_nexus(nexus) != DDI_SUCCESS) { 416 slot->s_nexus = NULL; 417 b2s_free_nexus(nexus); 418 return (DDI_FAILURE); 419 } 420 slot->s_nexus = nexus; 421 422 return (DDI_SUCCESS); 423 424 425 case DDI_RESUME: 426 return (DDI_SUCCESS); 427 428 default: 429 return (DDI_FAILURE); 430 } 431 } 432 433 int 434 sda_mem_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 435 { 436 sda_slot_t *slot; 437 b2s_nexus_t *nexus; 438 439 switch (cmd) { 440 case DDI_DETACH: 441 if ((slot = ddi_get_parent_data(dip)) == NULL) { 442 return (DDI_FAILURE); 443 } 444 if ((nexus = slot->s_nexus) == NULL) { 445 /* nothing to do */ 446 return (DDI_SUCCESS); 447 } 448 if (b2s_detach_nexus(nexus) != DDI_SUCCESS) { 449 return (DDI_FAILURE); 450 } 451 slot->s_nexus = NULL; 452 b2s_free_nexus(nexus); 453 return (DDI_SUCCESS); 454 455 case DDI_SUSPEND: 456 return (DDI_SUCCESS); 457 458 default: 459 return (DDI_FAILURE); 460 } 461 } 462 463 int 464 sda_mem_quiesce(dev_info_t *dip) 465 { 466 _NOTE(ARGUNUSED(dip)); 467 /* no work to do */ 468 return (DDI_SUCCESS); 469 } 470 471 uint32_t 472 sda_mem_getbits(uint32_t *resp, int hibit, int len) 473 { 474 uint32_t val = 0; 475 uint32_t bit; 476 477 for (bit = hibit; len--; bit--) { 478 val <<= 1; 479 val |= ((resp[bit / 32]) >> (bit % 32)) & 1; 480 } 481 return (val); 482 } 483 484 void 485 sda_mem_getstring(uint32_t *resp, char *s, int hibit, int len) 486 { 487 while (len--) { 488 *s++ = sda_mem_getbits(resp, hibit, 8); 489 hibit -= 8; 490 } 491 *s = 0; 492 } 493 494 uint32_t 495 sda_mem_maxclk(sda_slot_t *slot) 496 { 497 static const uint32_t mult[16] = { 498 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 499 }; 500 501 static const uint32_t units[8] = { 502 10000, 100000, 1000000, 10000000, 0, 0, 0, 0, 503 }; 504 uint8_t ts; 505 506 ts = sda_mem_getbits(slot->s_rcsd, 103, 8); 507 508 return ((units[ts & 0x7]) * (mult[(ts >> 3) & 0xf])); 509 } 510 511 int 512 sda_mem_parse_cid_csd(sda_slot_t *slot, dev_info_t *dip) 513 { 514 uint32_t *rcid; 515 uint32_t *rcsd; 516 int csdver; 517 uint16_t rblen; 518 uint16_t bshift; 519 uint32_t cmult; 520 uint32_t csize; 521 char date[16]; 522 char *dtype; 523 524 rcid = slot->s_rcid; 525 rcsd = slot->s_rcsd; 526 527 csdver = sda_mem_getbits(rcsd, 127, 2); 528 529 if (slot->s_flags & SLOTF_SDMEM) { 530 switch (csdver) { 531 case 0: 532 csize = sda_mem_getbits(rcsd, 73, 12); 533 /* see comment above */ 534 rblen = (1 << sda_mem_getbits(rcsd, 83, 4)); 535 cmult = (4 << sda_mem_getbits(rcsd, 49, 3)); 536 bshift = 9; 537 break; 538 case 1: 539 rblen = 512; 540 csize = sda_mem_getbits(rcsd, 69, 22); 541 cmult = 1024; 542 bshift = 0; 543 break; 544 default: 545 sda_slot_err(slot, "Unknown SD CSD version (%d)", 546 csdver); 547 return (DDI_FAILURE); 548 } 549 550 dtype = slot->s_flags & SLOTF_SDHC ? "sdhc" : "sdcard"; 551 slot->s_mfg = sda_mem_getbits(rcid, 127, 8); 552 sda_mem_getstring(rcid, slot->s_oem, 119, 2); 553 sda_mem_getstring(rcid, slot->s_prod, 103, 5); 554 slot->s_majver = sda_mem_getbits(rcid, 63, 4); 555 slot->s_minver = sda_mem_getbits(rcid, 59, 4); 556 slot->s_serial = sda_mem_getbits(rcid, 55, 32); 557 slot->s_year = sda_mem_getbits(rcid, 19, 8) + 2000; 558 slot->s_month = sda_mem_getbits(rcid, 11, 4); 559 560 } else if (slot->s_flags & SLOTF_MMC) { 561 if ((csdver < 1) || (csdver > 2)) { 562 sda_slot_err(slot, "Unknown MMC CSD version (%d)", 563 csdver); 564 return (DDI_FAILURE); 565 } 566 567 dtype = "mmc"; 568 569 switch (sda_mem_getbits(rcsd, 125, 4)) { 570 case 0: /* MMC 1.0 - 1.2 */ 571 case 1: /* MMC 1.4 */ 572 slot->s_mfg = sda_mem_getbits(rcid, 127, 24); 573 slot->s_oem[0] = 0; 574 sda_mem_getstring(rcid, slot->s_prod, 103, 7); 575 slot->s_majver = sda_mem_getbits(rcid, 47, 4); 576 slot->s_minver = sda_mem_getbits(rcid, 43, 4); 577 slot->s_serial = sda_mem_getbits(rcid, 39, 24); 578 break; 579 580 case 2: /* MMC 2.0 - 2.2 */ 581 case 3: /* MMC 3.1 - 3.3 */ 582 case 4: /* MMC 4.x */ 583 slot->s_mfg = sda_mem_getbits(rcid, 127, 8); 584 sda_mem_getstring(rcid, slot->s_oem, 119, 2); 585 sda_mem_getstring(rcid, slot->s_prod, 103, 6); 586 slot->s_majver = sda_mem_getbits(rcid, 55, 4); 587 slot->s_minver = sda_mem_getbits(rcid, 51, 4); 588 slot->s_serial = sda_mem_getbits(rcid, 47, 32); 589 break; 590 591 default: 592 /* this error isn't fatal to us */ 593 sda_slot_err(slot, "Unknown MMCA version (%d)", 594 sda_mem_getbits(rcsd, 125, 4)); 595 break; 596 } 597 598 slot->s_year = sda_mem_getbits(rcid, 11, 4) + 1997; 599 slot->s_month = sda_mem_getbits(rcid, 15, 4); 600 601 csize = sda_mem_getbits(rcsd, 73, 12); 602 rblen = (1 << sda_mem_getbits(rcsd, 83, 4)); 603 cmult = (4 << sda_mem_getbits(rcsd, 49, 3)); 604 bshift = 9; 605 606 } else { 607 608 sda_slot_err(slot, "Card type unknown"); 609 return (DDI_FAILURE); 610 } 611 612 /* 613 * These fields are common to all known MMC/SDcard memory cards. 614 * 615 * The spec requires that block size 512 be supported. 616 * The media may have a different native size, but 512 617 * byte blocks will always work. This is true for SDcard, 618 * and apparently for MMC as well. 619 */ 620 rblen = max(rblen, 512); /* paranoia */ 621 slot->s_nblks = (csize + 1) * cmult * (rblen / 512); 622 slot->s_bshift = bshift; 623 slot->s_blksz = 512; 624 625 slot->s_r2w = (1 << sda_mem_getbits(rcsd, 28, 3)); 626 slot->s_ccc = sda_mem_getbits(rcsd, 95, 12); 627 slot->s_perm_wp = sda_mem_getbits(rcsd, 13, 1); 628 slot->s_temp_wp = sda_mem_getbits(rcsd, 12, 1); 629 slot->s_dsr = sda_mem_getbits(rcsd, 76, 1); 630 631 if (((slot->s_ccc & (1 << 4)) == 0) || 632 (slot->s_perm_wp != 0) || (slot->s_temp_wp != 0)) { 633 slot->s_flags &= ~SLOTF_WRITABLE; 634 } 635 (void) snprintf(date, sizeof (date), "%02d-%04d", 636 slot->s_month, slot->s_year); 637 638 #define prop_set_int(name, val) \ 639 (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, name, val) 640 #define prop_set_str(name, val) \ 641 (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip, name, val) 642 #define prop_set_bool(name, val) \ 643 if (val) (void) ddi_prop_create(DDI_DEV_T_NONE, dip, 0, name, NULL, 0) 644 645 prop_set_str("device-type", dtype); 646 prop_set_int("mfg-id", slot->s_mfg); 647 prop_set_str("product-id", slot->s_prod); 648 prop_set_str("oem-id", slot->s_oem); 649 prop_set_str("mfg-date", date); 650 651 prop_set_int("block-size", slot->s_blksz); 652 prop_set_int("num-blocks", slot->s_nblks); 653 prop_set_int("max-freq", slot->s_maxclk); 654 prop_set_bool("dsr-implemented", slot->s_dsr); 655 prop_set_int("ccc", slot->s_ccc); 656 prop_set_bool("perm-wp", slot->s_perm_wp); 657 prop_set_bool("temp-wp", slot->s_temp_wp); 658 659 #undef prop_set_int 660 #undef prop_set_str 661 #undef prop_set_bool 662 663 return (DDI_SUCCESS); 664 } 665