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/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 } 184 if ((slot->s_caps & SLOT_CAP_NOPIO) == 0) { 185 size_t maplen; 186 b2s_request_mapin(reqp, &cmdp->sc_kvaddr, &maplen); 187 cmdp->sc_ndmac = 0; 188 } 189 190 if (nblks == 0) { 191 /* 192 * This is not strictly a failure, but no work to do. 193 * We have to do it late here because we don't want to 194 * by pass the above media readiness checks. 195 */ 196 rv = B2S_EOK; 197 goto failed; 198 } 199 if (nblks > 0xffff) { 200 rv = B2S_EINVAL; 201 goto failed; 202 } 203 204 rblen = slot->s_blksz; 205 206 if ((blkno + nblks) > slot->s_nblks) { 207 rv = B2S_EBLKADDR; 208 goto failed; 209 } 210 211 cmdp->sc_rtype = R1; 212 cmdp->sc_blksz = rblen; 213 cmdp->sc_nblks = (uint16_t)nblks; 214 cmdp->sc_index = index; 215 cmdp->sc_flags = flags; 216 217 sda_cmd_submit(slot, cmdp, sda_mem_b2s_done); 218 return (B_TRUE); 219 220 failed: 221 sda_cmd_free(cmdp); 222 b2s_request_done(reqp, rv, 0); 223 return (B_TRUE); 224 } 225 226 boolean_t 227 sda_mem_b2s_format(sda_slot_t *slot, b2s_request_t *reqp) 228 { 229 sda_cmd_t *cmdp; 230 int rv; 231 232 233 rv = sda_mem_cmd(slot, CMD_ERASE_START, 0, R1, NULL); 234 if (rv != 0) { 235 b2s_request_done(reqp, sda_mem_b2s_errno(rv), 0); 236 return (B_TRUE); 237 } 238 rv = sda_mem_cmd(slot, CMD_ERASE_END, slot->s_nblks - 1, R1, NULL); 239 if (rv != 0) { 240 b2s_request_done(reqp, sda_mem_b2s_errno(rv), 0); 241 return (B_TRUE); 242 } 243 244 cmdp = sda_cmd_alloc(slot, CMD_ERASE, 0, R1b, reqp, KM_NOSLEEP); 245 if (cmdp == NULL) { 246 b2s_request_done(reqp, B2S_ENOMEM, 0); 247 return (B_TRUE); 248 } 249 cmdp->sc_flags = SDA_CMDF_DAT | SDA_CMDF_MEM; 250 251 sda_cmd_submit(slot, cmdp, sda_mem_b2s_done); 252 return (B_TRUE); 253 } 254 255 b2s_err_t 256 sda_mem_b2s_errno(sda_err_t errno) 257 { 258 /* the hot path */ 259 if (errno == SDA_EOK) { 260 return (B2S_EOK); 261 } 262 263 switch (errno) { 264 case SDA_ENOMEM: 265 return (B2S_ENOMEM); 266 case SDA_ETIME: 267 return (B2S_ETIMEDOUT); 268 case SDA_EWPROTECT: 269 return (B2S_EWPROTECT); 270 case SDA_ESUSPENDED: 271 case SDA_ENODEV: 272 return (B2S_ENOMEDIA); 273 case SDA_EFAULT: 274 case SDA_ECRC7: 275 case SDA_EPROTO: 276 return (B2S_EHARDWARE); 277 case SDA_ERESET: 278 return (B2S_ERESET); 279 case SDA_EIO: 280 case SDA_ERESID: 281 default: 282 return (B2S_EIO); 283 } 284 } 285 286 void 287 sda_mem_b2s_done(sda_cmd_t *cmdp) 288 { 289 b2s_request_t *reqp = sda_cmd_data(cmdp); 290 int errno = sda_cmd_errno(cmdp); 291 292 b2s_request_done(reqp, sda_mem_b2s_errno(errno), cmdp->sc_resid); 293 sda_cmd_free(cmdp); 294 } 295 296 boolean_t 297 sda_mem_b2s_request(void *arg, b2s_request_t *reqp) 298 { 299 sda_slot_t *slot = arg; 300 int rv; 301 302 switch (reqp->br_cmd) { 303 case B2S_CMD_WRITE: 304 if ((slot->s_flags & SLOTF_WRITABLE) == 0) { 305 rv = B2S_EWPROTECT; 306 } else { 307 return (sda_mem_b2s_rw(slot, reqp)); 308 } 309 break; 310 311 case B2S_CMD_READ: 312 return (sda_mem_b2s_rw(slot, reqp)); 313 314 case B2S_CMD_INQUIRY: 315 reqp->br_inquiry.inq_vendor = "OSOL"; 316 reqp->br_inquiry.inq_product = 317 slot->s_flags & SLOTF_MMC ? "MultiMediaCard" : 318 slot->s_flags & SLOTF_SDHC ? "SDHC Memory Card" : 319 "SD Memory Card"; 320 reqp->br_inquiry.inq_revision = ""; 321 reqp->br_inquiry.inq_serial = ""; 322 rv = B2S_EOK; 323 break; 324 325 case B2S_CMD_GETMEDIA: 326 if (!slot->s_ready) { 327 rv = B2S_ENODEV; 328 } else { 329 reqp->br_media.media_blksz = slot->s_blksz; 330 reqp->br_media.media_nblks = slot->s_nblks; 331 /* detect read-only cards */ 332 if (slot->s_flags & SLOTF_WRITABLE) { 333 reqp->br_media.media_flags = 0; 334 } else { 335 reqp->br_media.media_flags = 336 B2S_MEDIA_FLAG_READ_ONLY; 337 } 338 rv = B2S_EOK; 339 } 340 break; 341 342 case B2S_CMD_FORMAT: 343 return (sda_mem_b2s_format(slot, reqp)); 344 345 case B2S_CMD_ABORT: 346 sda_slot_mem_reset(slot, SDA_EABORT); 347 rv = B2S_EOK; 348 break; 349 350 case B2S_CMD_RESET: 351 sda_slot_mem_reset(slot, SDA_ERESET); 352 rv = B2S_EOK; 353 break; 354 355 case B2S_CMD_START: 356 case B2S_CMD_STOP: 357 case B2S_CMD_SYNC: 358 rv = B2S_EOK; 359 break; 360 361 case B2S_CMD_LOCK: 362 case B2S_CMD_UNLOCK: 363 default: 364 rv = B2S_ENOTSUP; 365 break; 366 } 367 368 b2s_request_done(reqp, rv, 0); 369 return (B_TRUE); 370 } 371 372 int 373 sda_mem_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 374 { 375 sda_slot_t *slot; 376 b2s_nexus_t *nexus; 377 b2s_nexus_info_t nexinfo; 378 b2s_leaf_info_t leafinfo; 379 380 switch (cmd) { 381 case DDI_ATTACH: 382 if ((slot = ddi_get_parent_data(dip)) == NULL) { 383 return (DDI_FAILURE); 384 } 385 386 if (sda_mem_parse_cid_csd(slot, dip) != DDI_SUCCESS) { 387 return (DDI_FAILURE); 388 } 389 390 nexinfo.nexus_version = B2S_VERSION_0; 391 nexinfo.nexus_private = slot; 392 nexinfo.nexus_dip = dip; 393 nexinfo.nexus_dma_attr = slot->s_hostp->h_dma; 394 nexinfo.nexus_request = sda_mem_b2s_request; 395 396 nexus = b2s_alloc_nexus(&nexinfo); 397 if (nexus == NULL) { 398 return (DDI_FAILURE); 399 } 400 401 leafinfo.leaf_target = 0; 402 leafinfo.leaf_lun = 0; 403 leafinfo.leaf_flags = 404 B2S_LEAF_REMOVABLE | B2S_LEAF_HOTPLUGGABLE; 405 leafinfo.leaf_unique_id = slot->s_uuid; 406 407 slot->s_leaf = b2s_attach_leaf(nexus, &leafinfo); 408 if (slot->s_leaf == NULL) { 409 b2s_free_nexus(nexus); 410 return (DDI_FAILURE); 411 } 412 413 slot->s_nexus = nexus; 414 if (b2s_attach_nexus(nexus) != DDI_SUCCESS) { 415 slot->s_nexus = NULL; 416 b2s_free_nexus(nexus); 417 return (DDI_FAILURE); 418 } 419 slot->s_nexus = nexus; 420 421 return (DDI_SUCCESS); 422 423 424 case DDI_RESUME: 425 return (DDI_SUCCESS); 426 427 default: 428 return (DDI_FAILURE); 429 } 430 } 431 432 int 433 sda_mem_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 434 { 435 sda_slot_t *slot; 436 b2s_nexus_t *nexus; 437 438 switch (cmd) { 439 case DDI_DETACH: 440 if ((slot = ddi_get_parent_data(dip)) == NULL) { 441 return (DDI_FAILURE); 442 } 443 if ((nexus = slot->s_nexus) == NULL) { 444 /* nothing to do */ 445 return (DDI_SUCCESS); 446 } 447 if (b2s_detach_nexus(nexus) != DDI_SUCCESS) { 448 return (DDI_FAILURE); 449 } 450 slot->s_nexus = NULL; 451 b2s_free_nexus(nexus); 452 return (DDI_SUCCESS); 453 454 case DDI_SUSPEND: 455 return (DDI_SUCCESS); 456 457 default: 458 return (DDI_FAILURE); 459 } 460 } 461 462 int 463 sda_mem_quiesce(dev_info_t *dip) 464 { 465 /* no work to do */ 466 return (DDI_SUCCESS); 467 } 468 469 uint32_t 470 sda_mem_getbits(uint32_t *resp, int hibit, int len) 471 { 472 uint32_t val = 0; 473 uint32_t bit; 474 475 for (bit = hibit; len--; bit--) { 476 val <<= 1; 477 val |= ((resp[bit / 32]) >> (bit % 32)) & 1; 478 } 479 return (val); 480 } 481 482 void 483 sda_mem_getstring(uint32_t *resp, char *s, int hibit, int len) 484 { 485 while (len--) { 486 *s++ = sda_mem_getbits(resp, hibit, 8); 487 hibit -= 8; 488 } 489 *s = 0; 490 } 491 492 uint32_t 493 sda_mem_maxclk(sda_slot_t *slot) 494 { 495 static const uint32_t mult[16] = { 496 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 497 }; 498 499 static const uint32_t units[8] = { 500 10000, 100000, 1000000, 10000000, 0, 0, 0, 0, 501 }; 502 uint8_t ts; 503 504 ts = sda_mem_getbits(slot->s_rcsd, 103, 8); 505 506 return ((units[ts & 0x7]) * (mult[(ts >> 3) & 0xf])); 507 } 508 509 int 510 sda_mem_parse_cid_csd(sda_slot_t *slot, dev_info_t *dip) 511 { 512 uint32_t *rcid; 513 uint32_t *rcsd; 514 int csdver; 515 uint16_t rblen; 516 uint16_t bshift; 517 uint32_t cmult; 518 uint32_t csize; 519 char date[16]; 520 char *dtype; 521 522 rcid = slot->s_rcid; 523 rcsd = slot->s_rcsd; 524 525 csdver = sda_mem_getbits(rcsd, 127, 2); 526 527 if (slot->s_flags & SLOTF_SDMEM) { 528 switch (csdver) { 529 case 0: 530 csize = sda_mem_getbits(rcsd, 73, 12); 531 /* see comment above */ 532 rblen = (1 << sda_mem_getbits(rcsd, 83, 4)); 533 cmult = (4 << sda_mem_getbits(rcsd, 49, 3)); 534 bshift = 9; 535 break; 536 case 1: 537 rblen = 512; 538 csize = sda_mem_getbits(rcsd, 69, 22); 539 cmult = 1024; 540 bshift = 0; 541 break; 542 default: 543 sda_slot_err(slot, "Unknown SD CSD version (%d)", 544 csdver); 545 return (DDI_FAILURE); 546 } 547 548 dtype = slot->s_flags & SLOTF_SDHC ? "sdhc" : "sdcard"; 549 slot->s_mfg = sda_mem_getbits(rcid, 127, 8); 550 sda_mem_getstring(rcid, slot->s_oem, 119, 2); 551 sda_mem_getstring(rcid, slot->s_prod, 103, 5); 552 slot->s_majver = sda_mem_getbits(rcid, 63, 4); 553 slot->s_minver = sda_mem_getbits(rcid, 59, 4); 554 slot->s_serial = sda_mem_getbits(rcid, 55, 32); 555 slot->s_year = sda_mem_getbits(rcid, 19, 8) + 2000; 556 slot->s_month = sda_mem_getbits(rcid, 11, 4); 557 558 } else if (slot->s_flags & SLOTF_MMC) { 559 if ((csdver < 1) || (csdver > 2)) { 560 sda_slot_err(slot, "Unknown MMC CSD version (%d)", 561 csdver); 562 return (DDI_FAILURE); 563 } 564 565 dtype = "mmc"; 566 567 switch (sda_mem_getbits(rcsd, 125, 4)) { 568 case 0: /* MMC 1.0 - 1.2 */ 569 case 1: /* MMC 1.4 */ 570 slot->s_mfg = sda_mem_getbits(rcid, 127, 24); 571 slot->s_oem[0] = 0; 572 sda_mem_getstring(rcid, slot->s_prod, 103, 7); 573 slot->s_majver = sda_mem_getbits(rcid, 47, 4); 574 slot->s_minver = sda_mem_getbits(rcid, 43, 4); 575 slot->s_serial = sda_mem_getbits(rcid, 39, 24); 576 break; 577 578 case 2: /* MMC 2.0 - 2.2 */ 579 case 3: /* MMC 3.1 - 3.3 */ 580 case 4: /* MMC 4.x */ 581 slot->s_mfg = sda_mem_getbits(rcid, 127, 8); 582 sda_mem_getstring(rcid, slot->s_oem, 119, 2); 583 sda_mem_getstring(rcid, slot->s_prod, 103, 6); 584 slot->s_majver = sda_mem_getbits(rcid, 55, 4); 585 slot->s_minver = sda_mem_getbits(rcid, 51, 4); 586 slot->s_serial = sda_mem_getbits(rcid, 47, 32); 587 break; 588 589 default: 590 /* this error isn't fatal to us */ 591 sda_slot_err(slot, "Unknown MMCA version (%d)", 592 sda_mem_getbits(rcsd, 125, 4)); 593 break; 594 } 595 596 slot->s_year = sda_mem_getbits(rcid, 11, 4) + 1997; 597 slot->s_month = sda_mem_getbits(rcid, 15, 4); 598 599 csize = sda_mem_getbits(rcsd, 73, 12); 600 rblen = (1 << sda_mem_getbits(rcsd, 83, 4)); 601 cmult = (4 << sda_mem_getbits(rcsd, 49, 3)); 602 bshift = 9; 603 604 } else { 605 606 sda_slot_err(slot, "Card type unknown"); 607 return (DDI_FAILURE); 608 } 609 610 /* 611 * These fields are common to all known MMC/SDcard memory cards. 612 * 613 * The spec requires that block size 512 be supported. 614 * The media may have a different native size, but 512 615 * byte blocks will always work. This is true for SDcard, 616 * and apparently for MMC as well. 617 */ 618 rblen = max(rblen, 512); /* paranoia */ 619 slot->s_nblks = (csize + 1) * cmult * (rblen / 512); 620 slot->s_bshift = bshift; 621 slot->s_blksz = 512; 622 623 slot->s_r2w = (1 << sda_mem_getbits(rcsd, 28, 3)); 624 slot->s_ccc = sda_mem_getbits(rcsd, 95, 12); 625 slot->s_perm_wp = sda_mem_getbits(rcsd, 13, 1); 626 slot->s_temp_wp = sda_mem_getbits(rcsd, 12, 1); 627 slot->s_dsr = sda_mem_getbits(rcsd, 76, 1); 628 629 if (((slot->s_ccc & (1 << 4)) == 0) || 630 (slot->s_perm_wp != 0) || (slot->s_temp_wp != 0)) { 631 slot->s_flags &= ~SLOTF_WRITABLE; 632 } 633 (void) snprintf(date, sizeof (date), "%02d-%04d", 634 slot->s_month, slot->s_year); 635 636 #define prop_set_int(name, val) \ 637 (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, name, val) 638 #define prop_set_str(name, val) \ 639 (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip, name, val) 640 #define prop_set_bool(name, val) \ 641 if (val) (void) ddi_prop_create(DDI_DEV_T_NONE, dip, 0, name, NULL, 0) 642 643 prop_set_str("device-type", dtype); 644 prop_set_int("mfg-id", slot->s_mfg); 645 prop_set_str("product-id", slot->s_prod); 646 prop_set_str("oem-id", slot->s_oem); 647 prop_set_str("mfg-date", date); 648 649 prop_set_int("block-size", slot->s_blksz); 650 prop_set_int("num-blocks", slot->s_nblks); 651 prop_set_int("max-freq", slot->s_maxclk); 652 prop_set_bool("dsr-implemented", slot->s_dsr); 653 prop_set_int("ccc", slot->s_ccc); 654 prop_set_bool("perm-wp", slot->s_perm_wp); 655 prop_set_bool("temp-wp", slot->s_temp_wp); 656 657 #undef prop_set_int 658 #undef prop_set_str 659 #undef prop_set_bool 660 661 return (DDI_SUCCESS); 662 } 663