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