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 2009 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/note.h> 32 #include <sys/conf.h> 33 #include <sys/scsi/adapters/blk2scsa.h> 34 #include <sys/ddi.h> 35 #include <sys/sunddi.h> 36 #include <sys/sdcard/sda.h> 37 #include <sys/sdcard/sda_impl.h> 38 39 static int sda_mem_attach(dev_info_t *, ddi_attach_cmd_t); 40 static int sda_mem_detach(dev_info_t *, ddi_detach_cmd_t); 41 static int sda_mem_quiesce(dev_info_t *); 42 static b2s_err_t sda_mem_b2s_errno(sda_err_t); 43 static boolean_t sda_mem_b2s_request(void *, b2s_request_t *); 44 static boolean_t sda_mem_b2s_rw(sda_slot_t *, b2s_request_t *); 45 static void sda_mem_b2s_done(sda_cmd_t *); 46 static void sda_mem_getstring(uint32_t *, char *, int, int); 47 static int sda_mem_parse_cid_csd(sda_slot_t *, dev_info_t *); 48 static int sda_mem_cmd(sda_slot_t *, uint8_t, uint32_t, uint8_t, uint32_t *); 49 50 51 /* 52 * To minimize complexity and reduce layering, we implement almost the 53 * entire memory card driver (sdcard) here. The memory card still 54 * needs to be a separate driver though, due to the requirement to 55 * have both SCSI HBA bus ops and SD bus ops. 56 */ 57 58 /* 59 * SCSA layer supplies a cb_ops, but we don't want it, because we 60 * don't want to expose a SCSI attachment point. (Our parent handles 61 * the attachment point, the SCSI one would be confusing.) We have to 62 * supply a stubbed out one, to prevent SCSA from trying to create minor 63 * nodes on our behalf. 64 * 65 * Perhaps at some future point we might want to expose a separate set 66 * of ioctls for these nodes, but for now we rely on our parent to do 67 * all that work. 68 */ 69 static struct cb_ops sda_mem_ops = { 70 nodev, /* cb_open */ 71 nodev, /* cb_close */ 72 nodev, /* cb_strategy */ 73 nodev, /* cb_print */ 74 nodev, /* cb_dump */ 75 nodev, /* cb_read */ 76 nodev, /* cb_write */ 77 nodev, /* cb_ioctl */ 78 nodev, /* cb_devmap */ 79 nodev, /* cb_mmap */ 80 nodev, /* cb_segmap */ 81 nochpoll, /* cb_chpoll */ 82 ddi_prop_op, /* cb_prop_op */ 83 NULL, /* cb_stream */ 84 D_MP /* cb_flag */ 85 }; 86 87 /* 88 * Here are the public functions. 89 */ 90 void 91 sda_mem_init(struct modlinkage *modlp) 92 { 93 struct dev_ops *devo; 94 95 devo = ((struct modldrv *)(modlp->ml_linkage[0]))->drv_dev_ops; 96 devo->devo_attach = sda_mem_attach; 97 devo->devo_detach = sda_mem_detach; 98 devo->devo_quiesce = sda_mem_quiesce; 99 100 devo->devo_cb_ops = &sda_mem_ops; 101 102 /* it turns out that this can't ever really fail */ 103 (void) b2s_mod_init(modlp); 104 } 105 106 void 107 sda_mem_fini(struct modlinkage *modlp) 108 { 109 b2s_mod_fini(modlp); 110 } 111 112 /* 113 * Everything beyond this is private. 114 */ 115 116 int 117 sda_mem_cmd(sda_slot_t *slot, uint8_t cmd, uint32_t arg, uint8_t rtype, 118 uint32_t *resp) 119 { 120 sda_cmd_t *cmdp; 121 int errno; 122 123 cmdp = sda_cmd_alloc(slot, cmd, arg, rtype, NULL, KM_SLEEP); 124 if (cmdp == NULL) { 125 return (ENOMEM); 126 } 127 errno = sda_cmd_exec(slot, cmdp, resp); 128 sda_cmd_free(cmdp); 129 130 return (errno); 131 } 132 133 boolean_t 134 sda_mem_b2s_rw(sda_slot_t *slot, b2s_request_t *reqp) 135 { 136 sda_cmd_t *cmdp; 137 uint64_t nblks; 138 uint64_t blkno; 139 uint16_t rblen; 140 int rv; 141 uint8_t index; 142 uint16_t flags; 143 144 blkno = reqp->br_lba; 145 nblks = reqp->br_nblks; 146 147 switch (reqp->br_cmd) { 148 case B2S_CMD_READ: 149 if (nblks > 1) { 150 index = CMD_READ_MULTI; 151 flags = SDA_CMDF_DAT | SDA_CMDF_MEM | SDA_CMDF_READ | 152 SDA_CMDF_AUTO_CMD12; 153 } else { 154 index = CMD_READ_SINGLE; 155 flags = SDA_CMDF_DAT | SDA_CMDF_MEM | SDA_CMDF_READ; 156 } 157 break; 158 case B2S_CMD_WRITE: 159 if (nblks > 1) { 160 index = CMD_WRITE_MULTI; 161 flags = SDA_CMDF_DAT | SDA_CMDF_MEM | SDA_CMDF_WRITE | 162 SDA_CMDF_AUTO_CMD12; 163 } else { 164 index = CMD_WRITE_SINGLE; 165 flags = SDA_CMDF_DAT | SDA_CMDF_MEM | SDA_CMDF_WRITE; 166 } 167 break; 168 default: 169 ASSERT(0); 170 break; 171 } 172 173 cmdp = sda_cmd_alloc(slot, index, blkno << slot->s_bshift, 174 R1, reqp, KM_NOSLEEP); 175 if (cmdp == NULL) { 176 b2s_request_done(reqp, B2S_ENOMEM, 0); 177 return (B_TRUE); 178 } 179 180 if (slot->s_hostp->h_dma != NULL) { 181 b2s_request_dma(reqp, &cmdp->sc_ndmac, &cmdp->sc_dmacs); 182 cmdp->sc_kvaddr = 0; 183 } else { 184 cmdp->sc_ndmac = 0; 185 } 186 if ((slot->s_caps & SLOT_CAP_NOPIO) == 0) { 187 size_t maplen; 188 b2s_request_mapin(reqp, &cmdp->sc_kvaddr, &maplen); 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 leafinfo.leaf_eui = 0; 408 409 slot->s_leaf = b2s_attach_leaf(nexus, &leafinfo); 410 if (slot->s_leaf == NULL) { 411 b2s_free_nexus(nexus); 412 return (DDI_FAILURE); 413 } 414 415 slot->s_nexus = nexus; 416 if (b2s_attach_nexus(nexus) != DDI_SUCCESS) { 417 slot->s_nexus = NULL; 418 b2s_free_nexus(nexus); 419 return (DDI_FAILURE); 420 } 421 slot->s_nexus = nexus; 422 423 return (DDI_SUCCESS); 424 425 426 case DDI_RESUME: 427 return (DDI_SUCCESS); 428 429 default: 430 return (DDI_FAILURE); 431 } 432 } 433 434 int 435 sda_mem_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 436 { 437 sda_slot_t *slot; 438 b2s_nexus_t *nexus; 439 440 switch (cmd) { 441 case DDI_DETACH: 442 if ((slot = ddi_get_parent_data(dip)) == NULL) { 443 return (DDI_FAILURE); 444 } 445 if ((nexus = slot->s_nexus) == NULL) { 446 /* nothing to do */ 447 return (DDI_SUCCESS); 448 } 449 if (b2s_detach_nexus(nexus) != DDI_SUCCESS) { 450 return (DDI_FAILURE); 451 } 452 slot->s_nexus = NULL; 453 b2s_free_nexus(nexus); 454 return (DDI_SUCCESS); 455 456 case DDI_SUSPEND: 457 return (DDI_SUCCESS); 458 459 default: 460 return (DDI_FAILURE); 461 } 462 } 463 464 int 465 sda_mem_quiesce(dev_info_t *dip) 466 { 467 _NOTE(ARGUNUSED(dip)); 468 /* no work to do */ 469 return (DDI_SUCCESS); 470 } 471 472 uint32_t 473 sda_mem_getbits(uint32_t *resp, int hibit, int len) 474 { 475 uint32_t val = 0; 476 uint32_t bit; 477 478 for (bit = hibit; len--; bit--) { 479 val <<= 1; 480 val |= ((resp[bit / 32]) >> (bit % 32)) & 1; 481 } 482 return (val); 483 } 484 485 void 486 sda_mem_getstring(uint32_t *resp, char *s, int hibit, int len) 487 { 488 while (len--) { 489 *s++ = sda_mem_getbits(resp, hibit, 8); 490 hibit -= 8; 491 } 492 *s = 0; 493 } 494 495 uint32_t 496 sda_mem_maxclk(sda_slot_t *slot) 497 { 498 static const uint32_t mult[16] = { 499 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 500 }; 501 502 static const uint32_t units[8] = { 503 10000, 100000, 1000000, 10000000, 0, 0, 0, 0, 504 }; 505 uint8_t ts; 506 507 ts = sda_mem_getbits(slot->s_rcsd, 103, 8); 508 509 return ((units[ts & 0x7]) * (mult[(ts >> 3) & 0xf])); 510 } 511 512 int 513 sda_mem_parse_cid_csd(sda_slot_t *slot, dev_info_t *dip) 514 { 515 uint32_t *rcid; 516 uint32_t *rcsd; 517 int csdver; 518 uint16_t rblen; 519 uint16_t bshift; 520 uint32_t cmult; 521 uint32_t csize; 522 char date[16]; 523 char *dtype; 524 525 rcid = slot->s_rcid; 526 rcsd = slot->s_rcsd; 527 528 csdver = sda_mem_getbits(rcsd, 127, 2); 529 530 if (slot->s_flags & SLOTF_SDMEM) { 531 switch (csdver) { 532 case 0: 533 csize = sda_mem_getbits(rcsd, 73, 12); 534 /* see comment above */ 535 rblen = (1 << sda_mem_getbits(rcsd, 83, 4)); 536 cmult = (4 << sda_mem_getbits(rcsd, 49, 3)); 537 bshift = 9; 538 break; 539 case 1: 540 rblen = 512; 541 csize = sda_mem_getbits(rcsd, 69, 22); 542 cmult = 1024; 543 bshift = 0; 544 break; 545 default: 546 sda_slot_err(slot, "Unknown SD CSD version (%d)", 547 csdver); 548 return (DDI_FAILURE); 549 } 550 551 dtype = slot->s_flags & SLOTF_SDHC ? "sdhc" : "sdcard"; 552 slot->s_mfg = sda_mem_getbits(rcid, 127, 8); 553 sda_mem_getstring(rcid, slot->s_oem, 119, 2); 554 sda_mem_getstring(rcid, slot->s_prod, 103, 5); 555 slot->s_majver = sda_mem_getbits(rcid, 63, 4); 556 slot->s_minver = sda_mem_getbits(rcid, 59, 4); 557 slot->s_serial = sda_mem_getbits(rcid, 55, 32); 558 slot->s_year = sda_mem_getbits(rcid, 19, 8) + 2000; 559 slot->s_month = sda_mem_getbits(rcid, 11, 4); 560 561 } else if (slot->s_flags & SLOTF_MMC) { 562 if ((csdver < 1) || (csdver > 2)) { 563 sda_slot_err(slot, "Unknown MMC CSD version (%d)", 564 csdver); 565 return (DDI_FAILURE); 566 } 567 568 dtype = "mmc"; 569 570 switch (sda_mem_getbits(rcsd, 125, 4)) { 571 case 0: /* MMC 1.0 - 1.2 */ 572 case 1: /* MMC 1.4 */ 573 slot->s_mfg = sda_mem_getbits(rcid, 127, 24); 574 slot->s_oem[0] = 0; 575 sda_mem_getstring(rcid, slot->s_prod, 103, 7); 576 slot->s_majver = sda_mem_getbits(rcid, 47, 4); 577 slot->s_minver = sda_mem_getbits(rcid, 43, 4); 578 slot->s_serial = sda_mem_getbits(rcid, 39, 24); 579 break; 580 581 case 2: /* MMC 2.0 - 2.2 */ 582 case 3: /* MMC 3.1 - 3.3 */ 583 case 4: /* MMC 4.x */ 584 slot->s_mfg = sda_mem_getbits(rcid, 127, 8); 585 sda_mem_getstring(rcid, slot->s_oem, 119, 2); 586 sda_mem_getstring(rcid, slot->s_prod, 103, 6); 587 slot->s_majver = sda_mem_getbits(rcid, 55, 4); 588 slot->s_minver = sda_mem_getbits(rcid, 51, 4); 589 slot->s_serial = sda_mem_getbits(rcid, 47, 32); 590 break; 591 592 default: 593 /* this error isn't fatal to us */ 594 sda_slot_err(slot, "Unknown MMCA version (%d)", 595 sda_mem_getbits(rcsd, 125, 4)); 596 break; 597 } 598 599 slot->s_year = sda_mem_getbits(rcid, 11, 4) + 1997; 600 slot->s_month = sda_mem_getbits(rcid, 15, 4); 601 602 csize = sda_mem_getbits(rcsd, 73, 12); 603 rblen = (1 << sda_mem_getbits(rcsd, 83, 4)); 604 cmult = (4 << sda_mem_getbits(rcsd, 49, 3)); 605 bshift = 9; 606 607 } else { 608 609 sda_slot_err(slot, "Card type unknown"); 610 return (DDI_FAILURE); 611 } 612 613 /* 614 * These fields are common to all known MMC/SDcard memory cards. 615 * 616 * The spec requires that block size 512 be supported. 617 * The media may have a different native size, but 512 618 * byte blocks will always work. This is true for SDcard, 619 * and apparently for MMC as well. 620 */ 621 rblen = max(rblen, 512); /* paranoia */ 622 slot->s_nblks = (csize + 1) * cmult * (rblen / 512); 623 slot->s_bshift = bshift; 624 slot->s_blksz = 512; 625 626 slot->s_r2w = (1 << sda_mem_getbits(rcsd, 28, 3)); 627 slot->s_ccc = sda_mem_getbits(rcsd, 95, 12); 628 slot->s_perm_wp = sda_mem_getbits(rcsd, 13, 1); 629 slot->s_temp_wp = sda_mem_getbits(rcsd, 12, 1); 630 slot->s_dsr = sda_mem_getbits(rcsd, 76, 1); 631 632 if (((slot->s_ccc & (1 << 4)) == 0) || 633 (slot->s_perm_wp != 0) || (slot->s_temp_wp != 0)) { 634 slot->s_flags &= ~SLOTF_WRITABLE; 635 } 636 (void) snprintf(date, sizeof (date), "%02d-%04d", 637 slot->s_month, slot->s_year); 638 639 #define prop_set_int(name, val) \ 640 (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, name, val) 641 #define prop_set_str(name, val) \ 642 (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip, name, val) 643 #define prop_set_bool(name, val) \ 644 if (val) (void) ddi_prop_create(DDI_DEV_T_NONE, dip, 0, name, NULL, 0) 645 646 prop_set_str("device-type", dtype); 647 prop_set_int("mfg-id", slot->s_mfg); 648 prop_set_str("product-id", slot->s_prod); 649 prop_set_str("oem-id", slot->s_oem); 650 prop_set_str("mfg-date", date); 651 652 prop_set_int("block-size", slot->s_blksz); 653 prop_set_int("num-blocks", slot->s_nblks); 654 prop_set_int("max-freq", slot->s_maxclk); 655 prop_set_bool("dsr-implemented", slot->s_dsr); 656 prop_set_int("ccc", slot->s_ccc); 657 prop_set_bool("perm-wp", slot->s_perm_wp); 658 prop_set_bool("temp-wp", slot->s_temp_wp); 659 660 #undef prop_set_int 661 #undef prop_set_str 662 #undef prop_set_bool 663 664 return (DDI_SUCCESS); 665 } 666