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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/scsi/scsi.h> 28 #include <sys/dktp/cm.h> 29 #include <sys/dktp/quetypes.h> 30 #include <sys/dktp/queue.h> 31 #include <sys/dktp/fctypes.h> 32 #include <sys/dktp/flowctrl.h> 33 #include <sys/dktp/cmdev.h> 34 #include <sys/dkio.h> 35 #include <sys/dktp/tgdk.h> 36 #include <sys/dktp/dadk.h> 37 #include <sys/dktp/bbh.h> 38 #include <sys/dktp/altsctr.h> 39 #include <sys/dktp/cmdk.h> 40 41 #include <sys/stat.h> 42 #include <sys/vtoc.h> 43 #include <sys/file.h> 44 #include <sys/dktp/dadkio.h> 45 #include <sys/aio_req.h> 46 47 #include <sys/cmlb.h> 48 49 /* 50 * Local Static Data 51 */ 52 #ifdef CMDK_DEBUG 53 #define DENT 0x0001 54 #define DIO 0x0002 55 56 static int cmdk_debug = DIO; 57 #endif 58 59 #ifndef TRUE 60 #define TRUE 1 61 #endif 62 63 #ifndef FALSE 64 #define FALSE 0 65 #endif 66 67 /* 68 * NDKMAP is the base number for accessing the fdisk partitions. 69 * c?d?p0 --> cmdk@?,?:q 70 */ 71 #define PARTITION0_INDEX (NDKMAP + 0) 72 73 #define DKTP_DATA (dkp->dk_tgobjp)->tg_data 74 #define DKTP_EXT (dkp->dk_tgobjp)->tg_ext 75 76 static void *cmdk_state; 77 78 /* 79 * the cmdk_attach_mutex protects cmdk_max_instance in multi-threaded 80 * attach situations 81 */ 82 static kmutex_t cmdk_attach_mutex; 83 static int cmdk_max_instance = 0; 84 85 /* 86 * Panic dumpsys state 87 * There is only a single flag that is not mutex locked since 88 * the system is prevented from thread switching and cmdk_dump 89 * will only be called in a single threaded operation. 90 */ 91 static int cmdk_indump; 92 93 /* 94 * Local Function Prototypes 95 */ 96 static int cmdk_create_obj(dev_info_t *dip, struct cmdk *dkp); 97 static void cmdk_destroy_obj(dev_info_t *dip, struct cmdk *dkp); 98 static void cmdkmin(struct buf *bp); 99 static int cmdkrw(dev_t dev, struct uio *uio, int flag); 100 static int cmdkarw(dev_t dev, struct aio_req *aio, int flag); 101 102 /* 103 * Bad Block Handling Functions Prototypes 104 */ 105 static void cmdk_bbh_reopen(struct cmdk *dkp); 106 static opaque_t cmdk_bbh_gethandle(opaque_t bbh_data, struct buf *bp); 107 static bbh_cookie_t cmdk_bbh_htoc(opaque_t bbh_data, opaque_t handle); 108 static void cmdk_bbh_freehandle(opaque_t bbh_data, opaque_t handle); 109 static void cmdk_bbh_close(struct cmdk *dkp); 110 static void cmdk_bbh_setalts_idx(struct cmdk *dkp); 111 static int cmdk_bbh_bsearch(struct alts_ent *buf, int cnt, daddr32_t key); 112 113 static struct bbh_objops cmdk_bbh_ops = { 114 nulldev, 115 nulldev, 116 cmdk_bbh_gethandle, 117 cmdk_bbh_htoc, 118 cmdk_bbh_freehandle, 119 0, 0 120 }; 121 122 static int cmdkopen(dev_t *dev_p, int flag, int otyp, cred_t *credp); 123 static int cmdkclose(dev_t dev, int flag, int otyp, cred_t *credp); 124 static int cmdkstrategy(struct buf *bp); 125 static int cmdkdump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk); 126 static int cmdkioctl(dev_t, int, intptr_t, int, cred_t *, int *); 127 static int cmdkread(dev_t dev, struct uio *uio, cred_t *credp); 128 static int cmdkwrite(dev_t dev, struct uio *uio, cred_t *credp); 129 static int cmdk_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, 130 int mod_flags, char *name, caddr_t valuep, int *lengthp); 131 static int cmdkaread(dev_t dev, struct aio_req *aio, cred_t *credp); 132 static int cmdkawrite(dev_t dev, struct aio_req *aio, cred_t *credp); 133 134 /* 135 * Device driver ops vector 136 */ 137 138 static struct cb_ops cmdk_cb_ops = { 139 cmdkopen, /* open */ 140 cmdkclose, /* close */ 141 cmdkstrategy, /* strategy */ 142 nodev, /* print */ 143 cmdkdump, /* dump */ 144 cmdkread, /* read */ 145 cmdkwrite, /* write */ 146 cmdkioctl, /* ioctl */ 147 nodev, /* devmap */ 148 nodev, /* mmap */ 149 nodev, /* segmap */ 150 nochpoll, /* poll */ 151 cmdk_prop_op, /* cb_prop_op */ 152 0, /* streamtab */ 153 D_64BIT | D_MP | D_NEW, /* Driver comaptibility flag */ 154 CB_REV, /* cb_rev */ 155 cmdkaread, /* async read */ 156 cmdkawrite /* async write */ 157 }; 158 159 static int cmdkinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 160 void **result); 161 static int cmdkprobe(dev_info_t *dip); 162 static int cmdkattach(dev_info_t *dip, ddi_attach_cmd_t cmd); 163 static int cmdkdetach(dev_info_t *dip, ddi_detach_cmd_t cmd); 164 165 static void cmdk_setup_pm(dev_info_t *dip, struct cmdk *dkp); 166 static int cmdkresume(dev_info_t *dip); 167 static int cmdksuspend(dev_info_t *dip); 168 static int cmdkpower(dev_info_t *dip, int component, int level); 169 170 struct dev_ops cmdk_ops = { 171 DEVO_REV, /* devo_rev, */ 172 0, /* refcnt */ 173 cmdkinfo, /* info */ 174 nulldev, /* identify */ 175 cmdkprobe, /* probe */ 176 cmdkattach, /* attach */ 177 cmdkdetach, /* detach */ 178 nodev, /* reset */ 179 &cmdk_cb_ops, /* driver operations */ 180 (struct bus_ops *)0, /* bus operations */ 181 cmdkpower, /* power */ 182 ddi_quiesce_not_needed, /* quiesce */ 183 }; 184 185 /* 186 * This is the loadable module wrapper. 187 */ 188 #include <sys/modctl.h> 189 190 extern struct mod_ops mod_driverops; 191 192 static struct modldrv modldrv = { 193 &mod_driverops, /* Type of module. This one is a driver */ 194 "Common Direct Access Disk", 195 &cmdk_ops, /* driver ops */ 196 }; 197 198 static struct modlinkage modlinkage = { 199 MODREV_1, (void *)&modldrv, NULL 200 }; 201 202 /* Function prototypes for cmlb callbacks */ 203 204 static int cmdk_lb_rdwr(dev_info_t *dip, uchar_t cmd, void *bufaddr, 205 diskaddr_t start, size_t length, void *tg_cookie); 206 207 static int cmdk_lb_getinfo(dev_info_t *dip, int cmd, void *arg, 208 void *tg_cookie); 209 210 static void cmdk_devid_setup(struct cmdk *dkp); 211 static int cmdk_devid_modser(struct cmdk *dkp); 212 static int cmdk_get_modser(struct cmdk *dkp, int ioccmd, char *buf, int len); 213 static int cmdk_devid_fabricate(struct cmdk *dkp); 214 static int cmdk_devid_read(struct cmdk *dkp); 215 216 static cmlb_tg_ops_t cmdk_lb_ops = { 217 TG_DK_OPS_VERSION_1, 218 cmdk_lb_rdwr, 219 cmdk_lb_getinfo 220 }; 221 222 static boolean_t 223 cmdk_isopen(struct cmdk *dkp, dev_t dev) 224 { 225 int part, otyp; 226 ulong_t partbit; 227 228 ASSERT(MUTEX_HELD((&dkp->dk_mutex))); 229 230 part = CMDKPART(dev); 231 partbit = 1 << part; 232 233 /* account for close */ 234 if (dkp->dk_open_lyr[part] != 0) 235 return (B_TRUE); 236 for (otyp = 0; otyp < OTYPCNT; otyp++) 237 if (dkp->dk_open_reg[otyp] & partbit) 238 return (B_TRUE); 239 return (B_FALSE); 240 } 241 242 int 243 _init(void) 244 { 245 int rval; 246 247 if (rval = ddi_soft_state_init(&cmdk_state, sizeof (struct cmdk), 7)) 248 return (rval); 249 250 mutex_init(&cmdk_attach_mutex, NULL, MUTEX_DRIVER, NULL); 251 if ((rval = mod_install(&modlinkage)) != 0) { 252 mutex_destroy(&cmdk_attach_mutex); 253 ddi_soft_state_fini(&cmdk_state); 254 } 255 return (rval); 256 } 257 258 int 259 _fini(void) 260 { 261 return (EBUSY); 262 263 /* 264 * This has been commented out until cmdk is a true 265 * unloadable module. Right now x86's are panicking on 266 * a diskless reconfig boot. 267 */ 268 269 #if 0 /* bugid 1186679 */ 270 int rval; 271 272 rval = mod_remove(&modlinkage); 273 if (rval != 0) 274 return (rval); 275 276 mutex_destroy(&cmdk_attach_mutex); 277 ddi_soft_state_fini(&cmdk_state); 278 279 return (0); 280 #endif 281 } 282 283 int 284 _info(struct modinfo *modinfop) 285 { 286 return (mod_info(&modlinkage, modinfop)); 287 } 288 289 /* 290 * Autoconfiguration Routines 291 */ 292 static int 293 cmdkprobe(dev_info_t *dip) 294 { 295 int instance; 296 int status; 297 struct cmdk *dkp; 298 299 instance = ddi_get_instance(dip); 300 301 if (ddi_get_soft_state(cmdk_state, instance)) 302 return (DDI_PROBE_PARTIAL); 303 304 if ((ddi_soft_state_zalloc(cmdk_state, instance) != DDI_SUCCESS) || 305 ((dkp = ddi_get_soft_state(cmdk_state, instance)) == NULL)) 306 return (DDI_PROBE_PARTIAL); 307 308 mutex_init(&dkp->dk_mutex, NULL, MUTEX_DRIVER, NULL); 309 rw_init(&dkp->dk_bbh_mutex, NULL, RW_DRIVER, NULL); 310 dkp->dk_dip = dip; 311 mutex_enter(&dkp->dk_mutex); 312 313 dkp->dk_dev = makedevice(ddi_driver_major(dip), 314 ddi_get_instance(dip) << CMDK_UNITSHF); 315 316 /* linkage to dadk and strategy */ 317 if (cmdk_create_obj(dip, dkp) != DDI_SUCCESS) { 318 mutex_exit(&dkp->dk_mutex); 319 mutex_destroy(&dkp->dk_mutex); 320 rw_destroy(&dkp->dk_bbh_mutex); 321 ddi_soft_state_free(cmdk_state, instance); 322 return (DDI_PROBE_PARTIAL); 323 } 324 325 status = dadk_probe(DKTP_DATA, KM_NOSLEEP); 326 if (status != DDI_PROBE_SUCCESS) { 327 cmdk_destroy_obj(dip, dkp); /* dadk/strategy linkage */ 328 mutex_exit(&dkp->dk_mutex); 329 mutex_destroy(&dkp->dk_mutex); 330 rw_destroy(&dkp->dk_bbh_mutex); 331 ddi_soft_state_free(cmdk_state, instance); 332 return (status); 333 } 334 335 mutex_exit(&dkp->dk_mutex); 336 #ifdef CMDK_DEBUG 337 if (cmdk_debug & DENT) 338 PRF("cmdkprobe: instance= %d name= `%s`\n", 339 instance, ddi_get_name_addr(dip)); 340 #endif 341 return (status); 342 } 343 344 static int 345 cmdkattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 346 { 347 int instance; 348 struct cmdk *dkp; 349 char *node_type; 350 351 switch (cmd) { 352 case DDI_ATTACH: 353 break; 354 case DDI_RESUME: 355 return (cmdkresume(dip)); 356 default: 357 return (DDI_FAILURE); 358 } 359 360 instance = ddi_get_instance(dip); 361 if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 362 return (DDI_FAILURE); 363 364 dkp->dk_pm_level = CMDK_SPINDLE_UNINIT; 365 mutex_init(&dkp->dk_mutex, NULL, MUTEX_DRIVER, NULL); 366 367 mutex_enter(&dkp->dk_mutex); 368 369 /* dadk_attach is an empty function that only returns SUCCESS */ 370 (void) dadk_attach(DKTP_DATA); 371 372 node_type = (DKTP_EXT->tg_nodetype); 373 374 /* 375 * this open allows cmlb to read the device 376 * and determine the label types 377 * so that cmlb can create minor nodes for device 378 */ 379 380 /* open the target disk */ 381 if (dadk_open(DKTP_DATA, 0) != DDI_SUCCESS) 382 goto fail2; 383 384 #ifdef _ILP32 385 { 386 struct tgdk_geom phyg; 387 (void) dadk_getphygeom(DKTP_DATA, &phyg); 388 if ((phyg.g_cap - 1) > DK_MAX_BLOCKS) { 389 (void) dadk_close(DKTP_DATA); 390 goto fail2; 391 } 392 } 393 #endif 394 395 396 /* mark as having opened target */ 397 dkp->dk_flag |= CMDK_TGDK_OPEN; 398 399 cmlb_alloc_handle((cmlb_handle_t *)&dkp->dk_cmlbhandle); 400 401 if (cmlb_attach(dip, 402 &cmdk_lb_ops, 403 DTYPE_DIRECT, /* device_type */ 404 0, /* removable */ 405 0, /* hot pluggable XXX */ 406 node_type, 407 CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT, /* alter_behaviour */ 408 dkp->dk_cmlbhandle, 409 0) != 0) 410 goto fail1; 411 412 /* Calling validate will create minor nodes according to disk label */ 413 (void) cmlb_validate(dkp->dk_cmlbhandle, 0, 0); 414 415 /* set bbh (Bad Block Handling) */ 416 cmdk_bbh_reopen(dkp); 417 418 /* setup devid string */ 419 cmdk_devid_setup(dkp); 420 421 mutex_enter(&cmdk_attach_mutex); 422 if (instance > cmdk_max_instance) 423 cmdk_max_instance = instance; 424 mutex_exit(&cmdk_attach_mutex); 425 426 mutex_exit(&dkp->dk_mutex); 427 428 /* 429 * Add a zero-length attribute to tell the world we support 430 * kernel ioctls (for layered drivers) 431 */ 432 (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 433 DDI_KERNEL_IOCTL, NULL, 0); 434 ddi_report_dev(dip); 435 436 /* 437 * Initialize power management 438 */ 439 mutex_init(&dkp->dk_pm_mutex, NULL, MUTEX_DRIVER, NULL); 440 cv_init(&dkp->dk_suspend_cv, NULL, CV_DRIVER, NULL); 441 cmdk_setup_pm(dip, dkp); 442 443 return (DDI_SUCCESS); 444 445 fail1: 446 cmlb_free_handle(&dkp->dk_cmlbhandle); 447 (void) dadk_close(DKTP_DATA); 448 fail2: 449 cmdk_destroy_obj(dip, dkp); 450 rw_destroy(&dkp->dk_bbh_mutex); 451 mutex_exit(&dkp->dk_mutex); 452 mutex_destroy(&dkp->dk_mutex); 453 ddi_soft_state_free(cmdk_state, instance); 454 return (DDI_FAILURE); 455 } 456 457 458 static int 459 cmdkdetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 460 { 461 struct cmdk *dkp; 462 int instance; 463 int max_instance; 464 465 switch (cmd) { 466 case DDI_DETACH: 467 /* return (DDI_FAILURE); */ 468 break; 469 case DDI_SUSPEND: 470 return (cmdksuspend(dip)); 471 default: 472 #ifdef CMDK_DEBUG 473 if (cmdk_debug & DIO) { 474 PRF("cmdkdetach: cmd = %d unknown\n", cmd); 475 } 476 #endif 477 return (DDI_FAILURE); 478 } 479 480 mutex_enter(&cmdk_attach_mutex); 481 max_instance = cmdk_max_instance; 482 mutex_exit(&cmdk_attach_mutex); 483 484 /* check if any instance of driver is open */ 485 for (instance = 0; instance < max_instance; instance++) { 486 dkp = ddi_get_soft_state(cmdk_state, instance); 487 if (!dkp) 488 continue; 489 if (dkp->dk_flag & CMDK_OPEN) 490 return (DDI_FAILURE); 491 } 492 493 instance = ddi_get_instance(dip); 494 if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 495 return (DDI_SUCCESS); 496 497 mutex_enter(&dkp->dk_mutex); 498 499 /* 500 * The cmdk_part_info call at the end of cmdkattach may have 501 * caused cmdk_reopen to do a TGDK_OPEN, make sure we close on 502 * detach for case when cmdkopen/cmdkclose never occurs. 503 */ 504 if (dkp->dk_flag & CMDK_TGDK_OPEN) { 505 dkp->dk_flag &= ~CMDK_TGDK_OPEN; 506 (void) dadk_close(DKTP_DATA); 507 } 508 509 cmlb_detach(dkp->dk_cmlbhandle, 0); 510 cmlb_free_handle(&dkp->dk_cmlbhandle); 511 ddi_prop_remove_all(dip); 512 513 cmdk_destroy_obj(dip, dkp); /* dadk/strategy linkage */ 514 mutex_exit(&dkp->dk_mutex); 515 mutex_destroy(&dkp->dk_mutex); 516 rw_destroy(&dkp->dk_bbh_mutex); 517 mutex_destroy(&dkp->dk_pm_mutex); 518 cv_destroy(&dkp->dk_suspend_cv); 519 ddi_soft_state_free(cmdk_state, instance); 520 521 return (DDI_SUCCESS); 522 } 523 524 static int 525 cmdkinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 526 { 527 dev_t dev = (dev_t)arg; 528 int instance; 529 struct cmdk *dkp; 530 531 #ifdef lint 532 dip = dip; /* no one ever uses this */ 533 #endif 534 #ifdef CMDK_DEBUG 535 if (cmdk_debug & DENT) 536 PRF("cmdkinfo: call\n"); 537 #endif 538 instance = CMDKUNIT(dev); 539 540 switch (infocmd) { 541 case DDI_INFO_DEVT2DEVINFO: 542 if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 543 return (DDI_FAILURE); 544 *result = (void *) dkp->dk_dip; 545 break; 546 case DDI_INFO_DEVT2INSTANCE: 547 *result = (void *)(intptr_t)instance; 548 break; 549 default: 550 return (DDI_FAILURE); 551 } 552 return (DDI_SUCCESS); 553 } 554 555 /* 556 * Initialize the power management components 557 */ 558 static void 559 cmdk_setup_pm(dev_info_t *dip, struct cmdk *dkp) 560 { 561 char *pm_comp[] = { "NAME=cmdk", "0=off", "1=on", NULL }; 562 563 /* 564 * Since the cmdk device does not the 'reg' property, 565 * cpr will not call its DDI_SUSPEND/DDI_RESUME entries. 566 * The following code is to tell cpr that this device 567 * DOES need to be suspended and resumed. 568 */ 569 (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip, 570 "pm-hardware-state", "needs-suspend-resume"); 571 572 if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip, 573 "pm-components", pm_comp, 3) == DDI_PROP_SUCCESS) { 574 if (pm_raise_power(dip, 0, CMDK_SPINDLE_ON) == DDI_SUCCESS) { 575 mutex_enter(&dkp->dk_pm_mutex); 576 dkp->dk_pm_level = CMDK_SPINDLE_ON; 577 dkp->dk_pm_is_enabled = 1; 578 mutex_exit(&dkp->dk_pm_mutex); 579 } else { 580 mutex_enter(&dkp->dk_pm_mutex); 581 dkp->dk_pm_level = CMDK_SPINDLE_OFF; 582 dkp->dk_pm_is_enabled = 0; 583 mutex_exit(&dkp->dk_pm_mutex); 584 } 585 } else { 586 mutex_enter(&dkp->dk_pm_mutex); 587 dkp->dk_pm_level = CMDK_SPINDLE_UNINIT; 588 dkp->dk_pm_is_enabled = 0; 589 mutex_exit(&dkp->dk_pm_mutex); 590 } 591 } 592 593 /* 594 * suspend routine, it will be run when get the command 595 * DDI_SUSPEND at detach(9E) from system power management 596 */ 597 static int 598 cmdksuspend(dev_info_t *dip) 599 { 600 struct cmdk *dkp; 601 int instance; 602 clock_t count = 0; 603 604 instance = ddi_get_instance(dip); 605 if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 606 return (DDI_FAILURE); 607 mutex_enter(&dkp->dk_mutex); 608 if (dkp->dk_flag & CMDK_SUSPEND) { 609 mutex_exit(&dkp->dk_mutex); 610 return (DDI_SUCCESS); 611 } 612 dkp->dk_flag |= CMDK_SUSPEND; 613 614 /* need to wait a while */ 615 while (dadk_getcmds(DKTP_DATA) != 0) { 616 delay(drv_usectohz(1000000)); 617 if (count > 60) { 618 dkp->dk_flag &= ~CMDK_SUSPEND; 619 cv_broadcast(&dkp->dk_suspend_cv); 620 mutex_exit(&dkp->dk_mutex); 621 return (DDI_FAILURE); 622 } 623 count++; 624 } 625 mutex_exit(&dkp->dk_mutex); 626 return (DDI_SUCCESS); 627 } 628 629 /* 630 * resume routine, it will be run when get the command 631 * DDI_RESUME at attach(9E) from system power management 632 */ 633 static int 634 cmdkresume(dev_info_t *dip) 635 { 636 struct cmdk *dkp; 637 int instance; 638 639 instance = ddi_get_instance(dip); 640 if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 641 return (DDI_FAILURE); 642 mutex_enter(&dkp->dk_mutex); 643 if (!(dkp->dk_flag & CMDK_SUSPEND)) { 644 mutex_exit(&dkp->dk_mutex); 645 return (DDI_FAILURE); 646 } 647 dkp->dk_pm_level = CMDK_SPINDLE_ON; 648 dkp->dk_flag &= ~CMDK_SUSPEND; 649 cv_broadcast(&dkp->dk_suspend_cv); 650 mutex_exit(&dkp->dk_mutex); 651 return (DDI_SUCCESS); 652 653 } 654 655 /* 656 * power management entry point, it was used to 657 * change power management component. 658 * Actually, the real hard drive suspend/resume 659 * was handled in ata, so this function is not 660 * doing any real work other than verifying that 661 * the disk is idle. 662 */ 663 static int 664 cmdkpower(dev_info_t *dip, int component, int level) 665 { 666 struct cmdk *dkp; 667 int instance; 668 669 instance = ddi_get_instance(dip); 670 if (!(dkp = ddi_get_soft_state(cmdk_state, instance)) || 671 component != 0 || level > CMDK_SPINDLE_ON || 672 level < CMDK_SPINDLE_OFF) { 673 return (DDI_FAILURE); 674 } 675 676 mutex_enter(&dkp->dk_pm_mutex); 677 if (dkp->dk_pm_is_enabled && dkp->dk_pm_level == level) { 678 mutex_exit(&dkp->dk_pm_mutex); 679 return (DDI_SUCCESS); 680 } 681 mutex_exit(&dkp->dk_pm_mutex); 682 683 if ((level == CMDK_SPINDLE_OFF) && 684 (dadk_getcmds(DKTP_DATA) != 0)) { 685 return (DDI_FAILURE); 686 } 687 688 mutex_enter(&dkp->dk_pm_mutex); 689 dkp->dk_pm_level = level; 690 mutex_exit(&dkp->dk_pm_mutex); 691 return (DDI_SUCCESS); 692 } 693 694 static int 695 cmdk_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags, 696 char *name, caddr_t valuep, int *lengthp) 697 { 698 struct cmdk *dkp; 699 700 #ifdef CMDK_DEBUG 701 if (cmdk_debug & DENT) 702 PRF("cmdk_prop_op: call\n"); 703 #endif 704 705 dkp = ddi_get_soft_state(cmdk_state, ddi_get_instance(dip)); 706 if (dkp == NULL) 707 return (ddi_prop_op(dev, dip, prop_op, mod_flags, 708 name, valuep, lengthp)); 709 710 return (cmlb_prop_op(dkp->dk_cmlbhandle, 711 dev, dip, prop_op, mod_flags, name, valuep, lengthp, 712 CMDKPART(dev), NULL)); 713 } 714 715 /* 716 * dump routine 717 */ 718 static int 719 cmdkdump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk) 720 { 721 int instance; 722 struct cmdk *dkp; 723 diskaddr_t p_lblksrt; 724 diskaddr_t p_lblkcnt; 725 struct buf local; 726 struct buf *bp; 727 728 #ifdef CMDK_DEBUG 729 if (cmdk_debug & DENT) 730 PRF("cmdkdump: call\n"); 731 #endif 732 instance = CMDKUNIT(dev); 733 if (!(dkp = ddi_get_soft_state(cmdk_state, instance)) || (blkno < 0)) 734 return (ENXIO); 735 736 if (cmlb_partinfo( 737 dkp->dk_cmlbhandle, 738 CMDKPART(dev), 739 &p_lblkcnt, 740 &p_lblksrt, 741 NULL, 742 NULL, 743 0)) { 744 return (ENXIO); 745 } 746 747 if ((blkno+nblk) > p_lblkcnt) 748 return (EINVAL); 749 750 cmdk_indump = 1; /* Tell disk targets we are panic dumpping */ 751 752 bp = &local; 753 bzero(bp, sizeof (*bp)); 754 bp->b_flags = B_BUSY; 755 bp->b_un.b_addr = addr; 756 bp->b_bcount = nblk << SCTRSHFT; 757 SET_BP_SEC(bp, ((ulong_t)(p_lblksrt + blkno))); 758 759 (void) dadk_dump(DKTP_DATA, bp); 760 return (bp->b_error); 761 } 762 763 /* 764 * Copy in the dadkio_rwcmd according to the user's data model. If needed, 765 * convert it for our internal use. 766 */ 767 static int 768 rwcmd_copyin(struct dadkio_rwcmd *rwcmdp, caddr_t inaddr, int flag) 769 { 770 switch (ddi_model_convert_from(flag)) { 771 case DDI_MODEL_ILP32: { 772 struct dadkio_rwcmd32 cmd32; 773 774 if (ddi_copyin(inaddr, &cmd32, 775 sizeof (struct dadkio_rwcmd32), flag)) { 776 return (EFAULT); 777 } 778 779 rwcmdp->cmd = cmd32.cmd; 780 rwcmdp->flags = cmd32.flags; 781 rwcmdp->blkaddr = (blkaddr_t)cmd32.blkaddr; 782 rwcmdp->buflen = cmd32.buflen; 783 rwcmdp->bufaddr = (caddr_t)(intptr_t)cmd32.bufaddr; 784 /* 785 * Note: we do not convert the 'status' field, 786 * as it should not contain valid data at this 787 * point. 788 */ 789 bzero(&rwcmdp->status, sizeof (rwcmdp->status)); 790 break; 791 } 792 case DDI_MODEL_NONE: { 793 if (ddi_copyin(inaddr, rwcmdp, 794 sizeof (struct dadkio_rwcmd), flag)) { 795 return (EFAULT); 796 } 797 } 798 } 799 return (0); 800 } 801 802 /* 803 * If necessary, convert the internal rwcmdp and status to the appropriate 804 * data model and copy it out to the user. 805 */ 806 static int 807 rwcmd_copyout(struct dadkio_rwcmd *rwcmdp, caddr_t outaddr, int flag) 808 { 809 switch (ddi_model_convert_from(flag)) { 810 case DDI_MODEL_ILP32: { 811 struct dadkio_rwcmd32 cmd32; 812 813 cmd32.cmd = rwcmdp->cmd; 814 cmd32.flags = rwcmdp->flags; 815 cmd32.blkaddr = rwcmdp->blkaddr; 816 cmd32.buflen = rwcmdp->buflen; 817 ASSERT64(((uintptr_t)rwcmdp->bufaddr >> 32) == 0); 818 cmd32.bufaddr = (caddr32_t)(uintptr_t)rwcmdp->bufaddr; 819 820 cmd32.status.status = rwcmdp->status.status; 821 cmd32.status.resid = rwcmdp->status.resid; 822 cmd32.status.failed_blk_is_valid = 823 rwcmdp->status.failed_blk_is_valid; 824 cmd32.status.failed_blk = rwcmdp->status.failed_blk; 825 cmd32.status.fru_code_is_valid = 826 rwcmdp->status.fru_code_is_valid; 827 cmd32.status.fru_code = rwcmdp->status.fru_code; 828 829 bcopy(rwcmdp->status.add_error_info, 830 cmd32.status.add_error_info, DADKIO_ERROR_INFO_LEN); 831 832 if (ddi_copyout(&cmd32, outaddr, 833 sizeof (struct dadkio_rwcmd32), flag)) 834 return (EFAULT); 835 break; 836 } 837 case DDI_MODEL_NONE: { 838 if (ddi_copyout(rwcmdp, outaddr, 839 sizeof (struct dadkio_rwcmd), flag)) 840 return (EFAULT); 841 } 842 } 843 return (0); 844 } 845 846 /* 847 * ioctl routine 848 */ 849 static int 850 cmdkioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp, int *rvalp) 851 { 852 int instance; 853 struct scsi_device *devp; 854 struct cmdk *dkp; 855 char data[NBPSCTR]; 856 857 instance = CMDKUNIT(dev); 858 if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 859 return (ENXIO); 860 861 mutex_enter(&dkp->dk_mutex); 862 while (dkp->dk_flag & CMDK_SUSPEND) { 863 cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex); 864 } 865 mutex_exit(&dkp->dk_mutex); 866 867 bzero(data, sizeof (data)); 868 869 switch (cmd) { 870 871 case DKIOCGMEDIAINFO: { 872 struct dk_minfo media_info; 873 struct tgdk_geom phyg; 874 875 /* dadk_getphygeom always returns success */ 876 (void) dadk_getphygeom(DKTP_DATA, &phyg); 877 878 media_info.dki_lbsize = phyg.g_secsiz; 879 media_info.dki_capacity = phyg.g_cap; 880 media_info.dki_media_type = DK_FIXED_DISK; 881 882 if (ddi_copyout(&media_info, (void *)arg, 883 sizeof (struct dk_minfo), flag)) { 884 return (EFAULT); 885 } else { 886 return (0); 887 } 888 } 889 890 case DKIOCINFO: { 891 struct dk_cinfo *info = (struct dk_cinfo *)data; 892 893 /* controller information */ 894 info->dki_ctype = (DKTP_EXT->tg_ctype); 895 info->dki_cnum = ddi_get_instance(ddi_get_parent(dkp->dk_dip)); 896 (void) strcpy(info->dki_cname, 897 ddi_get_name(ddi_get_parent(dkp->dk_dip))); 898 899 /* Unit Information */ 900 info->dki_unit = ddi_get_instance(dkp->dk_dip); 901 devp = ddi_get_driver_private(dkp->dk_dip); 902 info->dki_slave = (CMDEV_TARG(devp)<<3) | CMDEV_LUN(devp); 903 (void) strcpy(info->dki_dname, ddi_driver_name(dkp->dk_dip)); 904 info->dki_flags = DKI_FMTVOL; 905 info->dki_partition = CMDKPART(dev); 906 907 info->dki_maxtransfer = maxphys / DEV_BSIZE; 908 info->dki_addr = 1; 909 info->dki_space = 0; 910 info->dki_prio = 0; 911 info->dki_vec = 0; 912 913 if (ddi_copyout(data, (void *)arg, sizeof (*info), flag)) 914 return (EFAULT); 915 else 916 return (0); 917 } 918 919 case DKIOCSTATE: { 920 int state; 921 int rval; 922 diskaddr_t p_lblksrt; 923 diskaddr_t p_lblkcnt; 924 925 if (ddi_copyin((void *)arg, &state, sizeof (int), flag)) 926 return (EFAULT); 927 928 /* dadk_check_media blocks until state changes */ 929 if (rval = dadk_check_media(DKTP_DATA, &state)) 930 return (rval); 931 932 if (state == DKIO_INSERTED) { 933 934 if (cmlb_validate(dkp->dk_cmlbhandle, 0, 0) != 0) 935 return (ENXIO); 936 937 if (cmlb_partinfo(dkp->dk_cmlbhandle, CMDKPART(dev), 938 &p_lblkcnt, &p_lblksrt, NULL, NULL, 0)) 939 return (ENXIO); 940 941 if (p_lblkcnt <= 0) 942 return (ENXIO); 943 } 944 945 if (ddi_copyout(&state, (caddr_t)arg, sizeof (int), flag)) 946 return (EFAULT); 947 948 return (0); 949 } 950 951 /* 952 * is media removable? 953 */ 954 case DKIOCREMOVABLE: { 955 int i; 956 957 i = (DKTP_EXT->tg_rmb) ? 1 : 0; 958 959 if (ddi_copyout(&i, (caddr_t)arg, sizeof (int), flag)) 960 return (EFAULT); 961 962 return (0); 963 } 964 965 case DKIOCADDBAD: 966 /* 967 * This is not an update mechanism to add bad blocks 968 * to the bad block structures stored on disk. 969 * 970 * addbadsec(1M) will update the bad block data on disk 971 * and use this ioctl to force the driver to re-initialize 972 * the list of bad blocks in the driver. 973 */ 974 975 /* start BBH */ 976 cmdk_bbh_reopen(dkp); 977 return (0); 978 979 case DKIOCG_PHYGEOM: 980 case DKIOCG_VIRTGEOM: 981 case DKIOCGGEOM: 982 case DKIOCSGEOM: 983 case DKIOCGAPART: 984 case DKIOCSAPART: 985 case DKIOCGVTOC: 986 case DKIOCSVTOC: 987 case DKIOCPARTINFO: 988 case DKIOCGEXTVTOC: 989 case DKIOCSEXTVTOC: 990 case DKIOCEXTPARTINFO: 991 case DKIOCGMBOOT: 992 case DKIOCSMBOOT: 993 case DKIOCGETEFI: 994 case DKIOCSETEFI: 995 case DKIOCPARTITION: 996 case DKIOCSETEXTPART: 997 { 998 int rc; 999 1000 rc = cmlb_ioctl(dkp->dk_cmlbhandle, dev, cmd, arg, flag, 1001 credp, rvalp, 0); 1002 if (cmd == DKIOCSVTOC || cmd == DKIOCSEXTVTOC) 1003 cmdk_devid_setup(dkp); 1004 return (rc); 1005 } 1006 1007 case DIOCTL_RWCMD: { 1008 struct dadkio_rwcmd *rwcmdp; 1009 int status; 1010 1011 rwcmdp = kmem_alloc(sizeof (struct dadkio_rwcmd), KM_SLEEP); 1012 1013 status = rwcmd_copyin(rwcmdp, (caddr_t)arg, flag); 1014 1015 if (status == 0) { 1016 bzero(&(rwcmdp->status), sizeof (struct dadkio_status)); 1017 status = dadk_ioctl(DKTP_DATA, 1018 dev, 1019 cmd, 1020 (uintptr_t)rwcmdp, 1021 flag, 1022 credp, 1023 rvalp); 1024 } 1025 if (status == 0) 1026 status = rwcmd_copyout(rwcmdp, (caddr_t)arg, flag); 1027 1028 kmem_free(rwcmdp, sizeof (struct dadkio_rwcmd)); 1029 return (status); 1030 } 1031 1032 default: 1033 return (dadk_ioctl(DKTP_DATA, 1034 dev, 1035 cmd, 1036 arg, 1037 flag, 1038 credp, 1039 rvalp)); 1040 } 1041 } 1042 1043 /*ARGSUSED1*/ 1044 static int 1045 cmdkclose(dev_t dev, int flag, int otyp, cred_t *credp) 1046 { 1047 int part; 1048 ulong_t partbit; 1049 int instance; 1050 struct cmdk *dkp; 1051 int lastclose = 1; 1052 int i; 1053 1054 instance = CMDKUNIT(dev); 1055 if (!(dkp = ddi_get_soft_state(cmdk_state, instance)) || 1056 (otyp >= OTYPCNT)) 1057 return (ENXIO); 1058 1059 mutex_enter(&dkp->dk_mutex); 1060 1061 /* check if device has been opened */ 1062 ASSERT(cmdk_isopen(dkp, dev)); 1063 if (!(dkp->dk_flag & CMDK_OPEN)) { 1064 mutex_exit(&dkp->dk_mutex); 1065 return (ENXIO); 1066 } 1067 1068 while (dkp->dk_flag & CMDK_SUSPEND) { 1069 cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex); 1070 } 1071 1072 part = CMDKPART(dev); 1073 partbit = 1 << part; 1074 1075 /* account for close */ 1076 if (otyp == OTYP_LYR) { 1077 ASSERT(dkp->dk_open_lyr[part] > 0); 1078 if (dkp->dk_open_lyr[part]) 1079 dkp->dk_open_lyr[part]--; 1080 } else { 1081 ASSERT((dkp->dk_open_reg[otyp] & partbit) != 0); 1082 dkp->dk_open_reg[otyp] &= ~partbit; 1083 } 1084 dkp->dk_open_exl &= ~partbit; 1085 1086 for (i = 0; i < CMDK_MAXPART; i++) 1087 if (dkp->dk_open_lyr[i] != 0) { 1088 lastclose = 0; 1089 break; 1090 } 1091 1092 if (lastclose) 1093 for (i = 0; i < OTYPCNT; i++) 1094 if (dkp->dk_open_reg[i] != 0) { 1095 lastclose = 0; 1096 break; 1097 } 1098 1099 mutex_exit(&dkp->dk_mutex); 1100 1101 if (lastclose) 1102 cmlb_invalidate(dkp->dk_cmlbhandle, 0); 1103 1104 return (DDI_SUCCESS); 1105 } 1106 1107 /*ARGSUSED3*/ 1108 static int 1109 cmdkopen(dev_t *dev_p, int flag, int otyp, cred_t *credp) 1110 { 1111 dev_t dev = *dev_p; 1112 int part; 1113 ulong_t partbit; 1114 int instance; 1115 struct cmdk *dkp; 1116 diskaddr_t p_lblksrt; 1117 diskaddr_t p_lblkcnt; 1118 int i; 1119 int nodelay; 1120 1121 instance = CMDKUNIT(dev); 1122 if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 1123 return (ENXIO); 1124 1125 if (otyp >= OTYPCNT) 1126 return (EINVAL); 1127 1128 mutex_enter(&dkp->dk_mutex); 1129 while (dkp->dk_flag & CMDK_SUSPEND) { 1130 cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex); 1131 } 1132 mutex_exit(&dkp->dk_mutex); 1133 1134 part = CMDKPART(dev); 1135 partbit = 1 << part; 1136 nodelay = (flag & (FNDELAY | FNONBLOCK)); 1137 1138 mutex_enter(&dkp->dk_mutex); 1139 1140 if (cmlb_validate(dkp->dk_cmlbhandle, 0, 0) != 0) { 1141 1142 /* fail if not doing non block open */ 1143 if (!nodelay) { 1144 mutex_exit(&dkp->dk_mutex); 1145 return (ENXIO); 1146 } 1147 } else if (cmlb_partinfo(dkp->dk_cmlbhandle, part, &p_lblkcnt, 1148 &p_lblksrt, NULL, NULL, 0) == 0) { 1149 1150 if (p_lblkcnt <= 0 && (!nodelay || otyp != OTYP_CHR)) { 1151 mutex_exit(&dkp->dk_mutex); 1152 return (ENXIO); 1153 } 1154 } else { 1155 /* fail if not doing non block open */ 1156 if (!nodelay) { 1157 mutex_exit(&dkp->dk_mutex); 1158 return (ENXIO); 1159 } 1160 } 1161 1162 if ((DKTP_EXT->tg_rdonly) && (flag & FWRITE)) { 1163 mutex_exit(&dkp->dk_mutex); 1164 return (EROFS); 1165 } 1166 1167 /* check for part already opend exclusively */ 1168 if (dkp->dk_open_exl & partbit) 1169 goto excl_open_fail; 1170 1171 /* check if we can establish exclusive open */ 1172 if (flag & FEXCL) { 1173 if (dkp->dk_open_lyr[part]) 1174 goto excl_open_fail; 1175 for (i = 0; i < OTYPCNT; i++) { 1176 if (dkp->dk_open_reg[i] & partbit) 1177 goto excl_open_fail; 1178 } 1179 } 1180 1181 /* open will succeed, account for open */ 1182 dkp->dk_flag |= CMDK_OPEN; 1183 if (otyp == OTYP_LYR) 1184 dkp->dk_open_lyr[part]++; 1185 else 1186 dkp->dk_open_reg[otyp] |= partbit; 1187 if (flag & FEXCL) 1188 dkp->dk_open_exl |= partbit; 1189 1190 mutex_exit(&dkp->dk_mutex); 1191 return (DDI_SUCCESS); 1192 1193 excl_open_fail: 1194 mutex_exit(&dkp->dk_mutex); 1195 return (EBUSY); 1196 } 1197 1198 /* 1199 * read routine 1200 */ 1201 /*ARGSUSED2*/ 1202 static int 1203 cmdkread(dev_t dev, struct uio *uio, cred_t *credp) 1204 { 1205 return (cmdkrw(dev, uio, B_READ)); 1206 } 1207 1208 /* 1209 * async read routine 1210 */ 1211 /*ARGSUSED2*/ 1212 static int 1213 cmdkaread(dev_t dev, struct aio_req *aio, cred_t *credp) 1214 { 1215 return (cmdkarw(dev, aio, B_READ)); 1216 } 1217 1218 /* 1219 * write routine 1220 */ 1221 /*ARGSUSED2*/ 1222 static int 1223 cmdkwrite(dev_t dev, struct uio *uio, cred_t *credp) 1224 { 1225 return (cmdkrw(dev, uio, B_WRITE)); 1226 } 1227 1228 /* 1229 * async write routine 1230 */ 1231 /*ARGSUSED2*/ 1232 static int 1233 cmdkawrite(dev_t dev, struct aio_req *aio, cred_t *credp) 1234 { 1235 return (cmdkarw(dev, aio, B_WRITE)); 1236 } 1237 1238 static void 1239 cmdkmin(struct buf *bp) 1240 { 1241 if (bp->b_bcount > DK_MAXRECSIZE) 1242 bp->b_bcount = DK_MAXRECSIZE; 1243 } 1244 1245 static int 1246 cmdkrw(dev_t dev, struct uio *uio, int flag) 1247 { 1248 int instance; 1249 struct cmdk *dkp; 1250 1251 instance = CMDKUNIT(dev); 1252 if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 1253 return (ENXIO); 1254 1255 mutex_enter(&dkp->dk_mutex); 1256 while (dkp->dk_flag & CMDK_SUSPEND) { 1257 cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex); 1258 } 1259 mutex_exit(&dkp->dk_mutex); 1260 1261 return (physio(cmdkstrategy, (struct buf *)0, dev, flag, cmdkmin, uio)); 1262 } 1263 1264 static int 1265 cmdkarw(dev_t dev, struct aio_req *aio, int flag) 1266 { 1267 int instance; 1268 struct cmdk *dkp; 1269 1270 instance = CMDKUNIT(dev); 1271 if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 1272 return (ENXIO); 1273 1274 mutex_enter(&dkp->dk_mutex); 1275 while (dkp->dk_flag & CMDK_SUSPEND) { 1276 cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex); 1277 } 1278 mutex_exit(&dkp->dk_mutex); 1279 1280 return (aphysio(cmdkstrategy, anocancel, dev, flag, cmdkmin, aio)); 1281 } 1282 1283 /* 1284 * strategy routine 1285 */ 1286 static int 1287 cmdkstrategy(struct buf *bp) 1288 { 1289 int instance; 1290 struct cmdk *dkp; 1291 long d_cnt; 1292 diskaddr_t p_lblksrt; 1293 diskaddr_t p_lblkcnt; 1294 1295 instance = CMDKUNIT(bp->b_edev); 1296 if (cmdk_indump || !(dkp = ddi_get_soft_state(cmdk_state, instance)) || 1297 (dkblock(bp) < 0)) { 1298 bp->b_resid = bp->b_bcount; 1299 SETBPERR(bp, ENXIO); 1300 biodone(bp); 1301 return (0); 1302 } 1303 1304 mutex_enter(&dkp->dk_mutex); 1305 ASSERT(cmdk_isopen(dkp, bp->b_edev)); 1306 while (dkp->dk_flag & CMDK_SUSPEND) { 1307 cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex); 1308 } 1309 mutex_exit(&dkp->dk_mutex); 1310 1311 bp->b_flags &= ~(B_DONE|B_ERROR); 1312 bp->b_resid = 0; 1313 bp->av_back = NULL; 1314 1315 /* 1316 * only re-read the vtoc if necessary (force == FALSE) 1317 */ 1318 if (cmlb_partinfo(dkp->dk_cmlbhandle, CMDKPART(bp->b_edev), 1319 &p_lblkcnt, &p_lblksrt, NULL, NULL, 0)) { 1320 SETBPERR(bp, ENXIO); 1321 } 1322 1323 if ((bp->b_bcount & (NBPSCTR-1)) || (dkblock(bp) > p_lblkcnt)) 1324 SETBPERR(bp, ENXIO); 1325 1326 if ((bp->b_flags & B_ERROR) || (dkblock(bp) == p_lblkcnt)) { 1327 bp->b_resid = bp->b_bcount; 1328 biodone(bp); 1329 return (0); 1330 } 1331 1332 d_cnt = bp->b_bcount >> SCTRSHFT; 1333 if ((dkblock(bp) + d_cnt) > p_lblkcnt) { 1334 bp->b_resid = ((dkblock(bp) + d_cnt) - p_lblkcnt) << SCTRSHFT; 1335 bp->b_bcount -= bp->b_resid; 1336 } 1337 1338 SET_BP_SEC(bp, ((ulong_t)(p_lblksrt + dkblock(bp)))); 1339 if (dadk_strategy(DKTP_DATA, bp) != DDI_SUCCESS) { 1340 bp->b_resid += bp->b_bcount; 1341 biodone(bp); 1342 } 1343 return (0); 1344 } 1345 1346 static int 1347 cmdk_create_obj(dev_info_t *dip, struct cmdk *dkp) 1348 { 1349 struct scsi_device *devp; 1350 opaque_t queobjp = NULL; 1351 opaque_t flcobjp = NULL; 1352 char que_keyvalp[64]; 1353 int que_keylen; 1354 char flc_keyvalp[64]; 1355 int flc_keylen; 1356 1357 ASSERT(mutex_owned(&dkp->dk_mutex)); 1358 1359 /* Create linkage to queueing routines based on property */ 1360 que_keylen = sizeof (que_keyvalp); 1361 if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF, 1362 DDI_PROP_CANSLEEP, "queue", que_keyvalp, &que_keylen) != 1363 DDI_PROP_SUCCESS) { 1364 cmn_err(CE_WARN, "cmdk_create_obj: queue property undefined"); 1365 return (DDI_FAILURE); 1366 } 1367 que_keyvalp[que_keylen] = (char)0; 1368 1369 if (strcmp(que_keyvalp, "qfifo") == 0) { 1370 queobjp = (opaque_t)qfifo_create(); 1371 } else if (strcmp(que_keyvalp, "qsort") == 0) { 1372 queobjp = (opaque_t)qsort_create(); 1373 } else { 1374 return (DDI_FAILURE); 1375 } 1376 1377 /* Create linkage to dequeueing routines based on property */ 1378 flc_keylen = sizeof (flc_keyvalp); 1379 if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF, 1380 DDI_PROP_CANSLEEP, "flow_control", flc_keyvalp, &flc_keylen) != 1381 DDI_PROP_SUCCESS) { 1382 cmn_err(CE_WARN, 1383 "cmdk_create_obj: flow-control property undefined"); 1384 return (DDI_FAILURE); 1385 } 1386 1387 flc_keyvalp[flc_keylen] = (char)0; 1388 1389 if (strcmp(flc_keyvalp, "dsngl") == 0) { 1390 flcobjp = (opaque_t)dsngl_create(); 1391 } else if (strcmp(flc_keyvalp, "dmult") == 0) { 1392 flcobjp = (opaque_t)dmult_create(); 1393 } else { 1394 return (DDI_FAILURE); 1395 } 1396 1397 /* populate bbh_obj object stored in dkp */ 1398 dkp->dk_bbh_obj.bbh_data = dkp; 1399 dkp->dk_bbh_obj.bbh_ops = &cmdk_bbh_ops; 1400 1401 /* create linkage to dadk */ 1402 dkp->dk_tgobjp = (opaque_t)dadk_create(); 1403 1404 devp = ddi_get_driver_private(dip); 1405 (void) dadk_init(DKTP_DATA, devp, flcobjp, queobjp, &dkp->dk_bbh_obj, 1406 NULL); 1407 1408 return (DDI_SUCCESS); 1409 } 1410 1411 static void 1412 cmdk_destroy_obj(dev_info_t *dip, struct cmdk *dkp) 1413 { 1414 char que_keyvalp[64]; 1415 int que_keylen; 1416 char flc_keyvalp[64]; 1417 int flc_keylen; 1418 1419 ASSERT(mutex_owned(&dkp->dk_mutex)); 1420 1421 (void) dadk_free((dkp->dk_tgobjp)); 1422 dkp->dk_tgobjp = NULL; 1423 1424 que_keylen = sizeof (que_keyvalp); 1425 if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF, 1426 DDI_PROP_CANSLEEP, "queue", que_keyvalp, &que_keylen) != 1427 DDI_PROP_SUCCESS) { 1428 cmn_err(CE_WARN, "cmdk_destroy_obj: queue property undefined"); 1429 return; 1430 } 1431 que_keyvalp[que_keylen] = (char)0; 1432 1433 flc_keylen = sizeof (flc_keyvalp); 1434 if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF, 1435 DDI_PROP_CANSLEEP, "flow_control", flc_keyvalp, &flc_keylen) != 1436 DDI_PROP_SUCCESS) { 1437 cmn_err(CE_WARN, 1438 "cmdk_destroy_obj: flow-control property undefined"); 1439 return; 1440 } 1441 flc_keyvalp[flc_keylen] = (char)0; 1442 } 1443 /*ARGSUSED5*/ 1444 static int 1445 cmdk_lb_rdwr(dev_info_t *dip, uchar_t cmd, void *bufaddr, 1446 diskaddr_t start, size_t count, void *tg_cookie) 1447 { 1448 struct cmdk *dkp; 1449 opaque_t handle; 1450 int rc = 0; 1451 char *bufa; 1452 1453 dkp = ddi_get_soft_state(cmdk_state, ddi_get_instance(dip)); 1454 if (dkp == NULL) 1455 return (ENXIO); 1456 1457 if (cmd != TG_READ && cmd != TG_WRITE) 1458 return (EINVAL); 1459 1460 /* count must be multiple of 512 */ 1461 count = (count + NBPSCTR - 1) & -NBPSCTR; 1462 handle = dadk_iob_alloc(DKTP_DATA, start, count, KM_SLEEP); 1463 if (!handle) 1464 return (ENOMEM); 1465 1466 if (cmd == TG_READ) { 1467 bufa = dadk_iob_xfer(DKTP_DATA, handle, B_READ); 1468 if (!bufa) 1469 rc = EIO; 1470 else 1471 bcopy(bufa, bufaddr, count); 1472 } else { 1473 bufa = dadk_iob_htoc(DKTP_DATA, handle); 1474 bcopy(bufaddr, bufa, count); 1475 bufa = dadk_iob_xfer(DKTP_DATA, handle, B_WRITE); 1476 if (!bufa) 1477 rc = EIO; 1478 } 1479 (void) dadk_iob_free(DKTP_DATA, handle); 1480 1481 return (rc); 1482 } 1483 1484 /*ARGSUSED3*/ 1485 static int 1486 cmdk_lb_getinfo(dev_info_t *dip, int cmd, void *arg, void *tg_cookie) 1487 { 1488 1489 struct cmdk *dkp; 1490 struct tgdk_geom phyg; 1491 1492 1493 dkp = ddi_get_soft_state(cmdk_state, ddi_get_instance(dip)); 1494 if (dkp == NULL) 1495 return (ENXIO); 1496 1497 switch (cmd) { 1498 case TG_GETPHYGEOM: { 1499 cmlb_geom_t *phygeomp = (cmlb_geom_t *)arg; 1500 1501 /* dadk_getphygeom always returns success */ 1502 (void) dadk_getphygeom(DKTP_DATA, &phyg); 1503 1504 phygeomp->g_capacity = phyg.g_cap; 1505 phygeomp->g_nsect = phyg.g_sec; 1506 phygeomp->g_nhead = phyg.g_head; 1507 phygeomp->g_acyl = phyg.g_acyl; 1508 phygeomp->g_ncyl = phyg.g_cyl; 1509 phygeomp->g_secsize = phyg.g_secsiz; 1510 phygeomp->g_intrlv = 1; 1511 phygeomp->g_rpm = 3600; 1512 1513 return (0); 1514 } 1515 1516 case TG_GETVIRTGEOM: { 1517 cmlb_geom_t *virtgeomp = (cmlb_geom_t *)arg; 1518 diskaddr_t capacity; 1519 1520 (void) dadk_getgeom(DKTP_DATA, &phyg); 1521 capacity = phyg.g_cap; 1522 1523 /* 1524 * If the controller returned us something that doesn't 1525 * really fit into an Int 13/function 8 geometry 1526 * result, just fail the ioctl. See PSARC 1998/313. 1527 */ 1528 if (capacity < 0 || capacity >= 63 * 254 * 1024) 1529 return (EINVAL); 1530 1531 virtgeomp->g_capacity = capacity; 1532 virtgeomp->g_nsect = 63; 1533 virtgeomp->g_nhead = 254; 1534 virtgeomp->g_ncyl = capacity / (63 * 254); 1535 virtgeomp->g_acyl = 0; 1536 virtgeomp->g_secsize = 512; 1537 virtgeomp->g_intrlv = 1; 1538 virtgeomp->g_rpm = 3600; 1539 1540 return (0); 1541 } 1542 1543 case TG_GETCAPACITY: 1544 case TG_GETBLOCKSIZE: 1545 { 1546 1547 /* dadk_getphygeom always returns success */ 1548 (void) dadk_getphygeom(DKTP_DATA, &phyg); 1549 if (cmd == TG_GETCAPACITY) 1550 *(diskaddr_t *)arg = phyg.g_cap; 1551 else 1552 *(uint32_t *)arg = (uint32_t)phyg.g_secsiz; 1553 1554 return (0); 1555 } 1556 1557 case TG_GETATTR: { 1558 tg_attribute_t *tgattribute = (tg_attribute_t *)arg; 1559 if ((DKTP_EXT->tg_rdonly)) 1560 tgattribute->media_is_writable = FALSE; 1561 else 1562 tgattribute->media_is_writable = TRUE; 1563 1564 return (0); 1565 } 1566 1567 default: 1568 return (ENOTTY); 1569 } 1570 } 1571 1572 1573 1574 1575 1576 /* 1577 * Create and register the devid. 1578 * There are 4 different ways we can get a device id: 1579 * 1. Already have one - nothing to do 1580 * 2. Build one from the drive's model and serial numbers 1581 * 3. Read one from the disk (first sector of last track) 1582 * 4. Fabricate one and write it on the disk. 1583 * If any of these succeeds, register the deviceid 1584 */ 1585 static void 1586 cmdk_devid_setup(struct cmdk *dkp) 1587 { 1588 int rc; 1589 1590 /* Try options until one succeeds, or all have failed */ 1591 1592 /* 1. All done if already registered */ 1593 if (dkp->dk_devid != NULL) 1594 return; 1595 1596 /* 2. Build a devid from the model and serial number */ 1597 rc = cmdk_devid_modser(dkp); 1598 if (rc != DDI_SUCCESS) { 1599 /* 3. Read devid from the disk, if present */ 1600 rc = cmdk_devid_read(dkp); 1601 1602 /* 4. otherwise make one up and write it on the disk */ 1603 if (rc != DDI_SUCCESS) 1604 rc = cmdk_devid_fabricate(dkp); 1605 } 1606 1607 /* If we managed to get a devid any of the above ways, register it */ 1608 if (rc == DDI_SUCCESS) 1609 (void) ddi_devid_register(dkp->dk_dip, dkp->dk_devid); 1610 1611 } 1612 1613 /* 1614 * Build a devid from the model and serial number 1615 * Return DDI_SUCCESS or DDI_FAILURE. 1616 */ 1617 static int 1618 cmdk_devid_modser(struct cmdk *dkp) 1619 { 1620 int rc = DDI_FAILURE; 1621 char *hwid; 1622 int modlen; 1623 int serlen; 1624 1625 /* 1626 * device ID is a concatenation of model number, '=', serial number. 1627 */ 1628 hwid = kmem_alloc(CMDK_HWIDLEN, KM_SLEEP); 1629 modlen = cmdk_get_modser(dkp, DIOCTL_GETMODEL, hwid, CMDK_HWIDLEN); 1630 if (modlen == 0) { 1631 rc = DDI_FAILURE; 1632 goto err; 1633 } 1634 hwid[modlen++] = '='; 1635 serlen = cmdk_get_modser(dkp, DIOCTL_GETSERIAL, 1636 hwid + modlen, CMDK_HWIDLEN - modlen); 1637 if (serlen == 0) { 1638 rc = DDI_FAILURE; 1639 goto err; 1640 } 1641 hwid[modlen + serlen] = 0; 1642 1643 /* Initialize the device ID, trailing NULL not included */ 1644 rc = ddi_devid_init(dkp->dk_dip, DEVID_ATA_SERIAL, modlen + serlen, 1645 hwid, &dkp->dk_devid); 1646 if (rc != DDI_SUCCESS) { 1647 rc = DDI_FAILURE; 1648 goto err; 1649 } 1650 1651 rc = DDI_SUCCESS; 1652 1653 err: 1654 kmem_free(hwid, CMDK_HWIDLEN); 1655 return (rc); 1656 } 1657 1658 static int 1659 cmdk_get_modser(struct cmdk *dkp, int ioccmd, char *buf, int len) 1660 { 1661 dadk_ioc_string_t strarg; 1662 int rval; 1663 char *s; 1664 char ch; 1665 boolean_t ret; 1666 int i; 1667 int tb; 1668 1669 strarg.is_buf = buf; 1670 strarg.is_size = len; 1671 if (dadk_ioctl(DKTP_DATA, 1672 dkp->dk_dev, 1673 ioccmd, 1674 (uintptr_t)&strarg, 1675 FNATIVE | FKIOCTL, 1676 NULL, 1677 &rval) != 0) 1678 return (0); 1679 1680 /* 1681 * valid model/serial string must contain a non-zero non-space 1682 * trim trailing spaces/NULL 1683 */ 1684 ret = B_FALSE; 1685 s = buf; 1686 for (i = 0; i < strarg.is_size; i++) { 1687 ch = *s++; 1688 if (ch != ' ' && ch != '\0') 1689 tb = i + 1; 1690 if (ch != ' ' && ch != '\0' && ch != '0') 1691 ret = B_TRUE; 1692 } 1693 1694 if (ret == B_FALSE) 1695 return (0); 1696 1697 return (tb); 1698 } 1699 1700 /* 1701 * Read a devid from on the first block of the last track of 1702 * the last cylinder. Make sure what we read is a valid devid. 1703 * Return DDI_SUCCESS or DDI_FAILURE. 1704 */ 1705 static int 1706 cmdk_devid_read(struct cmdk *dkp) 1707 { 1708 diskaddr_t blk; 1709 struct dk_devid *dkdevidp; 1710 uint_t *ip; 1711 int chksum; 1712 int i, sz; 1713 tgdk_iob_handle handle = NULL; 1714 int rc = DDI_FAILURE; 1715 1716 if (cmlb_get_devid_block(dkp->dk_cmlbhandle, &blk, 0)) 1717 goto err; 1718 1719 /* read the devid */ 1720 handle = dadk_iob_alloc(DKTP_DATA, blk, NBPSCTR, KM_SLEEP); 1721 if (handle == NULL) 1722 goto err; 1723 1724 dkdevidp = (struct dk_devid *)dadk_iob_xfer(DKTP_DATA, handle, B_READ); 1725 if (dkdevidp == NULL) 1726 goto err; 1727 1728 /* Validate the revision */ 1729 if ((dkdevidp->dkd_rev_hi != DK_DEVID_REV_MSB) || 1730 (dkdevidp->dkd_rev_lo != DK_DEVID_REV_LSB)) 1731 goto err; 1732 1733 /* Calculate the checksum */ 1734 chksum = 0; 1735 ip = (uint_t *)dkdevidp; 1736 for (i = 0; i < ((NBPSCTR - sizeof (int))/sizeof (int)); i++) 1737 chksum ^= ip[i]; 1738 if (DKD_GETCHKSUM(dkdevidp) != chksum) 1739 goto err; 1740 1741 /* Validate the device id */ 1742 if (ddi_devid_valid((ddi_devid_t)dkdevidp->dkd_devid) != DDI_SUCCESS) 1743 goto err; 1744 1745 /* keep a copy of the device id */ 1746 sz = ddi_devid_sizeof((ddi_devid_t)dkdevidp->dkd_devid); 1747 dkp->dk_devid = kmem_alloc(sz, KM_SLEEP); 1748 bcopy(dkdevidp->dkd_devid, dkp->dk_devid, sz); 1749 1750 rc = DDI_SUCCESS; 1751 1752 err: 1753 if (handle != NULL) 1754 (void) dadk_iob_free(DKTP_DATA, handle); 1755 return (rc); 1756 } 1757 1758 /* 1759 * Create a devid and write it on the first block of the last track of 1760 * the last cylinder. 1761 * Return DDI_SUCCESS or DDI_FAILURE. 1762 */ 1763 static int 1764 cmdk_devid_fabricate(struct cmdk *dkp) 1765 { 1766 ddi_devid_t devid = NULL; /* devid made by ddi_devid_init */ 1767 struct dk_devid *dkdevidp; /* devid struct stored on disk */ 1768 diskaddr_t blk; 1769 tgdk_iob_handle handle = NULL; 1770 uint_t *ip, chksum; 1771 int i; 1772 int rc = DDI_FAILURE; 1773 1774 if (ddi_devid_init(dkp->dk_dip, DEVID_FAB, 0, NULL, &devid) != 1775 DDI_SUCCESS) 1776 goto err; 1777 1778 if (cmlb_get_devid_block(dkp->dk_cmlbhandle, &blk, 0)) { 1779 /* no device id block address */ 1780 goto err; 1781 } 1782 1783 handle = dadk_iob_alloc(DKTP_DATA, blk, NBPSCTR, KM_SLEEP); 1784 if (!handle) 1785 goto err; 1786 1787 /* Locate the buffer */ 1788 dkdevidp = (struct dk_devid *)dadk_iob_htoc(DKTP_DATA, handle); 1789 1790 /* Fill in the revision */ 1791 bzero(dkdevidp, NBPSCTR); 1792 dkdevidp->dkd_rev_hi = DK_DEVID_REV_MSB; 1793 dkdevidp->dkd_rev_lo = DK_DEVID_REV_LSB; 1794 1795 /* Copy in the device id */ 1796 i = ddi_devid_sizeof(devid); 1797 if (i > DK_DEVID_SIZE) 1798 goto err; 1799 bcopy(devid, dkdevidp->dkd_devid, i); 1800 1801 /* Calculate the chksum */ 1802 chksum = 0; 1803 ip = (uint_t *)dkdevidp; 1804 for (i = 0; i < ((NBPSCTR - sizeof (int))/sizeof (int)); i++) 1805 chksum ^= ip[i]; 1806 1807 /* Fill in the checksum */ 1808 DKD_FORMCHKSUM(chksum, dkdevidp); 1809 1810 /* write the devid */ 1811 (void) dadk_iob_xfer(DKTP_DATA, handle, B_WRITE); 1812 1813 dkp->dk_devid = devid; 1814 1815 rc = DDI_SUCCESS; 1816 1817 err: 1818 if (handle != NULL) 1819 (void) dadk_iob_free(DKTP_DATA, handle); 1820 1821 if (rc != DDI_SUCCESS && devid != NULL) 1822 ddi_devid_free(devid); 1823 1824 return (rc); 1825 } 1826 1827 static void 1828 cmdk_bbh_free_alts(struct cmdk *dkp) 1829 { 1830 if (dkp->dk_alts_hdl) { 1831 (void) dadk_iob_free(DKTP_DATA, dkp->dk_alts_hdl); 1832 kmem_free(dkp->dk_slc_cnt, 1833 NDKMAP * (sizeof (uint32_t) + sizeof (struct alts_ent *))); 1834 dkp->dk_alts_hdl = NULL; 1835 } 1836 } 1837 1838 static void 1839 cmdk_bbh_reopen(struct cmdk *dkp) 1840 { 1841 tgdk_iob_handle handle = NULL; 1842 diskaddr_t slcb, slcn, slce; 1843 struct alts_parttbl *ap; 1844 struct alts_ent *enttblp; 1845 uint32_t altused; 1846 uint32_t altbase; 1847 uint32_t altlast; 1848 int alts; 1849 uint16_t vtoctag; 1850 int i, j; 1851 1852 /* find slice with V_ALTSCTR tag */ 1853 for (alts = 0; alts < NDKMAP; alts++) { 1854 if (cmlb_partinfo( 1855 dkp->dk_cmlbhandle, 1856 alts, 1857 &slcn, 1858 &slcb, 1859 NULL, 1860 &vtoctag, 1861 0)) { 1862 goto empty; /* no partition table exists */ 1863 } 1864 1865 if (vtoctag == V_ALTSCTR && slcn > 1) 1866 break; 1867 } 1868 if (alts >= NDKMAP) { 1869 goto empty; /* no V_ALTSCTR slice defined */ 1870 } 1871 1872 /* read in ALTS label block */ 1873 handle = dadk_iob_alloc(DKTP_DATA, slcb, NBPSCTR, KM_SLEEP); 1874 if (!handle) { 1875 goto empty; 1876 } 1877 1878 ap = (struct alts_parttbl *)dadk_iob_xfer(DKTP_DATA, handle, B_READ); 1879 if (!ap || (ap->alts_sanity != ALTS_SANITY)) { 1880 goto empty; 1881 } 1882 1883 altused = ap->alts_ent_used; /* number of BB entries */ 1884 altbase = ap->alts_ent_base; /* blk offset from begin slice */ 1885 altlast = ap->alts_ent_end; /* blk offset to last block */ 1886 /* ((altused * sizeof (struct alts_ent) + NBPSCTR - 1) & ~NBPSCTR) */ 1887 1888 if (altused == 0 || 1889 altbase < 1 || 1890 altbase > altlast || 1891 altlast >= slcn) { 1892 goto empty; 1893 } 1894 (void) dadk_iob_free(DKTP_DATA, handle); 1895 1896 /* read in ALTS remapping table */ 1897 handle = dadk_iob_alloc(DKTP_DATA, 1898 slcb + altbase, 1899 (altlast - altbase + 1) << SCTRSHFT, KM_SLEEP); 1900 if (!handle) { 1901 goto empty; 1902 } 1903 1904 enttblp = (struct alts_ent *)dadk_iob_xfer(DKTP_DATA, handle, B_READ); 1905 if (!enttblp) { 1906 goto empty; 1907 } 1908 1909 rw_enter(&dkp->dk_bbh_mutex, RW_WRITER); 1910 1911 /* allocate space for dk_slc_cnt and dk_slc_ent tables */ 1912 if (dkp->dk_slc_cnt == NULL) { 1913 dkp->dk_slc_cnt = kmem_alloc(NDKMAP * 1914 (sizeof (long) + sizeof (struct alts_ent *)), KM_SLEEP); 1915 } 1916 dkp->dk_slc_ent = (struct alts_ent **)(dkp->dk_slc_cnt + NDKMAP); 1917 1918 /* free previous BB table (if any) */ 1919 if (dkp->dk_alts_hdl) { 1920 (void) dadk_iob_free(DKTP_DATA, dkp->dk_alts_hdl); 1921 dkp->dk_alts_hdl = NULL; 1922 dkp->dk_altused = 0; 1923 } 1924 1925 /* save linkage to new BB table */ 1926 dkp->dk_alts_hdl = handle; 1927 dkp->dk_altused = altused; 1928 1929 /* 1930 * build indexes to BB table by slice 1931 * effectively we have 1932 * struct alts_ent *enttblp[altused]; 1933 * 1934 * uint32_t dk_slc_cnt[NDKMAP]; 1935 * struct alts_ent *dk_slc_ent[NDKMAP]; 1936 */ 1937 for (i = 0; i < NDKMAP; i++) { 1938 if (cmlb_partinfo( 1939 dkp->dk_cmlbhandle, 1940 i, 1941 &slcn, 1942 &slcb, 1943 NULL, 1944 NULL, 1945 0)) { 1946 goto empty1; 1947 } 1948 1949 dkp->dk_slc_cnt[i] = 0; 1950 if (slcn == 0) 1951 continue; /* slice is not allocated */ 1952 1953 /* last block in slice */ 1954 slce = slcb + slcn - 1; 1955 1956 /* find first remap entry in after beginnning of slice */ 1957 for (j = 0; j < altused; j++) { 1958 if (enttblp[j].bad_start + enttblp[j].bad_end >= slcb) 1959 break; 1960 } 1961 dkp->dk_slc_ent[i] = enttblp + j; 1962 1963 /* count remap entrys until end of slice */ 1964 for (; j < altused && enttblp[j].bad_start <= slce; j++) { 1965 dkp->dk_slc_cnt[i] += 1; 1966 } 1967 } 1968 1969 rw_exit(&dkp->dk_bbh_mutex); 1970 return; 1971 1972 empty: 1973 rw_enter(&dkp->dk_bbh_mutex, RW_WRITER); 1974 empty1: 1975 if (handle && handle != dkp->dk_alts_hdl) 1976 (void) dadk_iob_free(DKTP_DATA, handle); 1977 1978 if (dkp->dk_alts_hdl) { 1979 (void) dadk_iob_free(DKTP_DATA, dkp->dk_alts_hdl); 1980 dkp->dk_alts_hdl = NULL; 1981 } 1982 1983 rw_exit(&dkp->dk_bbh_mutex); 1984 } 1985 1986 /*ARGSUSED*/ 1987 static bbh_cookie_t 1988 cmdk_bbh_htoc(opaque_t bbh_data, opaque_t handle) 1989 { 1990 struct bbh_handle *hp; 1991 bbh_cookie_t ckp; 1992 1993 hp = (struct bbh_handle *)handle; 1994 ckp = hp->h_cktab + hp->h_idx; 1995 hp->h_idx++; 1996 return (ckp); 1997 } 1998 1999 /*ARGSUSED*/ 2000 static void 2001 cmdk_bbh_freehandle(opaque_t bbh_data, opaque_t handle) 2002 { 2003 struct bbh_handle *hp; 2004 2005 hp = (struct bbh_handle *)handle; 2006 kmem_free(handle, (sizeof (struct bbh_handle) + 2007 (hp->h_totck * (sizeof (struct bbh_cookie))))); 2008 } 2009 2010 2011 /* 2012 * cmdk_bbh_gethandle remaps the bad sectors to alternates. 2013 * There are 7 different cases when the comparison is made 2014 * between the bad sector cluster and the disk section. 2015 * 2016 * bad sector cluster gggggggggggbbbbbbbggggggggggg 2017 * case 1: ddddd 2018 * case 2: -d----- 2019 * case 3: ddddd 2020 * case 4: dddddddddddd 2021 * case 5: ddddddd----- 2022 * case 6: ---ddddddd 2023 * case 7: ddddddd 2024 * 2025 * where: g = good sector, b = bad sector 2026 * d = sector in disk section 2027 * - = disk section may be extended to cover those disk area 2028 */ 2029 2030 static opaque_t 2031 cmdk_bbh_gethandle(opaque_t bbh_data, struct buf *bp) 2032 { 2033 struct cmdk *dkp = (struct cmdk *)bbh_data; 2034 struct bbh_handle *hp; 2035 struct bbh_cookie *ckp; 2036 struct alts_ent *altp; 2037 uint32_t alts_used; 2038 uint32_t part = CMDKPART(bp->b_edev); 2039 daddr32_t lastsec; 2040 long d_count; 2041 int i; 2042 int idx; 2043 int cnt; 2044 2045 if (part >= V_NUMPAR) 2046 return (NULL); 2047 2048 /* 2049 * This if statement is atomic and it will succeed 2050 * if there are no bad blocks (almost always) 2051 * 2052 * so this if is performed outside of the rw_enter for speed 2053 * and then repeated inside the rw_enter for safety 2054 */ 2055 if (!dkp->dk_alts_hdl) { 2056 return (NULL); 2057 } 2058 2059 rw_enter(&dkp->dk_bbh_mutex, RW_READER); 2060 2061 if (dkp->dk_alts_hdl == NULL) { 2062 rw_exit(&dkp->dk_bbh_mutex); 2063 return (NULL); 2064 } 2065 2066 alts_used = dkp->dk_slc_cnt[part]; 2067 if (alts_used == 0) { 2068 rw_exit(&dkp->dk_bbh_mutex); 2069 return (NULL); 2070 } 2071 altp = dkp->dk_slc_ent[part]; 2072 2073 /* 2074 * binary search for the largest bad sector index in the alternate 2075 * entry table which overlaps or larger than the starting d_sec 2076 */ 2077 i = cmdk_bbh_bsearch(altp, alts_used, GET_BP_SEC(bp)); 2078 /* if starting sector is > the largest bad sector, return */ 2079 if (i == -1) { 2080 rw_exit(&dkp->dk_bbh_mutex); 2081 return (NULL); 2082 } 2083 /* i is the starting index. Set altp to the starting entry addr */ 2084 altp += i; 2085 2086 d_count = bp->b_bcount >> SCTRSHFT; 2087 lastsec = GET_BP_SEC(bp) + d_count - 1; 2088 2089 /* calculate the number of bad sectors */ 2090 for (idx = i, cnt = 0; idx < alts_used; idx++, altp++, cnt++) { 2091 if (lastsec < altp->bad_start) 2092 break; 2093 } 2094 2095 if (!cnt) { 2096 rw_exit(&dkp->dk_bbh_mutex); 2097 return (NULL); 2098 } 2099 2100 /* calculate the maximum number of reserved cookies */ 2101 cnt <<= 1; 2102 cnt++; 2103 2104 /* allocate the handle */ 2105 hp = (struct bbh_handle *)kmem_zalloc((sizeof (*hp) + 2106 (cnt * sizeof (*ckp))), KM_SLEEP); 2107 2108 hp->h_idx = 0; 2109 hp->h_totck = cnt; 2110 ckp = hp->h_cktab = (struct bbh_cookie *)(hp + 1); 2111 ckp[0].ck_sector = GET_BP_SEC(bp); 2112 ckp[0].ck_seclen = d_count; 2113 2114 altp = dkp->dk_slc_ent[part]; 2115 altp += i; 2116 for (idx = 0; i < alts_used; i++, altp++) { 2117 /* CASE 1: */ 2118 if (lastsec < altp->bad_start) 2119 break; 2120 2121 /* CASE 3: */ 2122 if (ckp[idx].ck_sector > altp->bad_end) 2123 continue; 2124 2125 /* CASE 2 and 7: */ 2126 if ((ckp[idx].ck_sector >= altp->bad_start) && 2127 (lastsec <= altp->bad_end)) { 2128 ckp[idx].ck_sector = altp->good_start + 2129 ckp[idx].ck_sector - altp->bad_start; 2130 break; 2131 } 2132 2133 /* at least one bad sector in our section. break it. */ 2134 /* CASE 5: */ 2135 if ((lastsec >= altp->bad_start) && 2136 (lastsec <= altp->bad_end)) { 2137 ckp[idx+1].ck_seclen = lastsec - altp->bad_start + 1; 2138 ckp[idx].ck_seclen -= ckp[idx+1].ck_seclen; 2139 ckp[idx+1].ck_sector = altp->good_start; 2140 break; 2141 } 2142 /* CASE 6: */ 2143 if ((ckp[idx].ck_sector <= altp->bad_end) && 2144 (ckp[idx].ck_sector >= altp->bad_start)) { 2145 ckp[idx+1].ck_seclen = ckp[idx].ck_seclen; 2146 ckp[idx].ck_seclen = altp->bad_end - 2147 ckp[idx].ck_sector + 1; 2148 ckp[idx+1].ck_seclen -= ckp[idx].ck_seclen; 2149 ckp[idx].ck_sector = altp->good_start + 2150 ckp[idx].ck_sector - altp->bad_start; 2151 idx++; 2152 ckp[idx].ck_sector = altp->bad_end + 1; 2153 continue; /* check rest of section */ 2154 } 2155 2156 /* CASE 4: */ 2157 ckp[idx].ck_seclen = altp->bad_start - ckp[idx].ck_sector; 2158 ckp[idx+1].ck_sector = altp->good_start; 2159 ckp[idx+1].ck_seclen = altp->bad_end - altp->bad_start + 1; 2160 idx += 2; 2161 ckp[idx].ck_sector = altp->bad_end + 1; 2162 ckp[idx].ck_seclen = lastsec - altp->bad_end; 2163 } 2164 2165 rw_exit(&dkp->dk_bbh_mutex); 2166 return ((opaque_t)hp); 2167 } 2168 2169 static int 2170 cmdk_bbh_bsearch(struct alts_ent *buf, int cnt, daddr32_t key) 2171 { 2172 int i; 2173 int ind; 2174 int interval; 2175 int mystatus = -1; 2176 2177 if (!cnt) 2178 return (mystatus); 2179 2180 ind = 1; /* compiler complains about possible uninitialized var */ 2181 for (i = 1; i <= cnt; i <<= 1) 2182 ind = i; 2183 2184 for (interval = ind; interval; ) { 2185 if ((key >= buf[ind-1].bad_start) && 2186 (key <= buf[ind-1].bad_end)) { 2187 return (ind-1); 2188 } else { 2189 interval >>= 1; 2190 if (key < buf[ind-1].bad_start) { 2191 /* record the largest bad sector index */ 2192 mystatus = ind-1; 2193 if (!interval) 2194 break; 2195 ind = ind - interval; 2196 } else { 2197 /* 2198 * if key is larger than the last element 2199 * then break 2200 */ 2201 if ((ind == cnt) || !interval) 2202 break; 2203 if ((ind+interval) <= cnt) 2204 ind += interval; 2205 } 2206 } 2207 } 2208 return (mystatus); 2209 } 2210