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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 /* 31 * This module provides support for labeling operations for target 32 * drivers. 33 */ 34 35 #include <sys/scsi/scsi.h> 36 #include <sys/sunddi.h> 37 #include <sys/dklabel.h> 38 #include <sys/dkio.h> 39 #include <sys/vtoc.h> 40 #include <sys/dktp/fdisk.h> 41 #include <sys/vtrace.h> 42 #include <sys/efi_partition.h> 43 #include <sys/cmlb.h> 44 #include <sys/cmlb_impl.h> 45 46 47 /* 48 * Driver minor node structure and data table 49 */ 50 struct driver_minor_data { 51 char *name; 52 minor_t minor; 53 int type; 54 }; 55 56 static struct driver_minor_data dk_minor_data[] = { 57 {"a", 0, S_IFBLK}, 58 {"b", 1, S_IFBLK}, 59 {"c", 2, S_IFBLK}, 60 {"d", 3, S_IFBLK}, 61 {"e", 4, S_IFBLK}, 62 {"f", 5, S_IFBLK}, 63 {"g", 6, S_IFBLK}, 64 {"h", 7, S_IFBLK}, 65 #if defined(_SUNOS_VTOC_16) 66 {"i", 8, S_IFBLK}, 67 {"j", 9, S_IFBLK}, 68 {"k", 10, S_IFBLK}, 69 {"l", 11, S_IFBLK}, 70 {"m", 12, S_IFBLK}, 71 {"n", 13, S_IFBLK}, 72 {"o", 14, S_IFBLK}, 73 {"p", 15, S_IFBLK}, 74 #endif /* defined(_SUNOS_VTOC_16) */ 75 #if defined(_FIRMWARE_NEEDS_FDISK) 76 {"q", 16, S_IFBLK}, 77 {"r", 17, S_IFBLK}, 78 {"s", 18, S_IFBLK}, 79 {"t", 19, S_IFBLK}, 80 {"u", 20, S_IFBLK}, 81 #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 82 {"a,raw", 0, S_IFCHR}, 83 {"b,raw", 1, S_IFCHR}, 84 {"c,raw", 2, S_IFCHR}, 85 {"d,raw", 3, S_IFCHR}, 86 {"e,raw", 4, S_IFCHR}, 87 {"f,raw", 5, S_IFCHR}, 88 {"g,raw", 6, S_IFCHR}, 89 {"h,raw", 7, S_IFCHR}, 90 #if defined(_SUNOS_VTOC_16) 91 {"i,raw", 8, S_IFCHR}, 92 {"j,raw", 9, S_IFCHR}, 93 {"k,raw", 10, S_IFCHR}, 94 {"l,raw", 11, S_IFCHR}, 95 {"m,raw", 12, S_IFCHR}, 96 {"n,raw", 13, S_IFCHR}, 97 {"o,raw", 14, S_IFCHR}, 98 {"p,raw", 15, S_IFCHR}, 99 #endif /* defined(_SUNOS_VTOC_16) */ 100 #if defined(_FIRMWARE_NEEDS_FDISK) 101 {"q,raw", 16, S_IFCHR}, 102 {"r,raw", 17, S_IFCHR}, 103 {"s,raw", 18, S_IFCHR}, 104 {"t,raw", 19, S_IFCHR}, 105 {"u,raw", 20, S_IFCHR}, 106 #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 107 {0} 108 }; 109 110 static struct driver_minor_data dk_minor_data_efi[] = { 111 {"a", 0, S_IFBLK}, 112 {"b", 1, S_IFBLK}, 113 {"c", 2, S_IFBLK}, 114 {"d", 3, S_IFBLK}, 115 {"e", 4, S_IFBLK}, 116 {"f", 5, S_IFBLK}, 117 {"g", 6, S_IFBLK}, 118 {"wd", 7, S_IFBLK}, 119 #if defined(_FIRMWARE_NEEDS_FDISK) 120 {"q", 16, S_IFBLK}, 121 {"r", 17, S_IFBLK}, 122 {"s", 18, S_IFBLK}, 123 {"t", 19, S_IFBLK}, 124 {"u", 20, S_IFBLK}, 125 #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 126 {"a,raw", 0, S_IFCHR}, 127 {"b,raw", 1, S_IFCHR}, 128 {"c,raw", 2, S_IFCHR}, 129 {"d,raw", 3, S_IFCHR}, 130 {"e,raw", 4, S_IFCHR}, 131 {"f,raw", 5, S_IFCHR}, 132 {"g,raw", 6, S_IFCHR}, 133 {"wd,raw", 7, S_IFCHR}, 134 #if defined(_FIRMWARE_NEEDS_FDISK) 135 {"q,raw", 16, S_IFCHR}, 136 {"r,raw", 17, S_IFCHR}, 137 {"s,raw", 18, S_IFCHR}, 138 {"t,raw", 19, S_IFCHR}, 139 {"u,raw", 20, S_IFCHR}, 140 #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 141 {0} 142 }; 143 144 145 146 extern struct mod_ops mod_miscops; 147 148 /* 149 * Global buffer and mutex for debug logging 150 */ 151 static char cmlb_log_buffer[1024]; 152 static kmutex_t cmlb_log_mutex; 153 154 155 struct cmlb_lun *cmlb_debug_un = NULL; 156 uint_t cmlb_level_mask = 0x0; 157 158 int cmlb_rot_delay = 4; /* default rotational delay */ 159 160 static struct modlmisc modlmisc = { 161 &mod_miscops, /* Type of module */ 162 "Common Labeling module %I%" 163 }; 164 165 static struct modlinkage modlinkage = { 166 MODREV_1, (void *)&modlmisc, NULL 167 }; 168 169 /* Local function prototypes */ 170 static dev_t cmlb_make_device(struct cmlb_lun *un); 171 static int cmlb_validate_geometry(struct cmlb_lun *un, int forcerevalid); 172 static void cmlb_resync_geom_caches(struct cmlb_lun *un, diskaddr_t capacity); 173 static int cmlb_read_fdisk(struct cmlb_lun *un, diskaddr_t capacity); 174 static void cmlb_swap_efi_gpt(efi_gpt_t *e); 175 static void cmlb_swap_efi_gpe(int nparts, efi_gpe_t *p); 176 static int cmlb_validate_efi(efi_gpt_t *labp); 177 static int cmlb_use_efi(struct cmlb_lun *un, diskaddr_t capacity); 178 static void cmlb_build_default_label(struct cmlb_lun *un); 179 static int cmlb_uselabel(struct cmlb_lun *un, struct dk_label *l); 180 static void cmlb_build_user_vtoc(struct cmlb_lun *un, struct vtoc *user_vtoc); 181 static int cmlb_build_label_vtoc(struct cmlb_lun *un, struct vtoc *user_vtoc); 182 static int cmlb_write_label(struct cmlb_lun *un); 183 static int cmlb_set_vtoc(struct cmlb_lun *un, struct dk_label *dkl); 184 static void cmlb_clear_efi(struct cmlb_lun *un); 185 static void cmlb_clear_vtoc(struct cmlb_lun *un); 186 static void cmlb_setup_default_geometry(struct cmlb_lun *un); 187 static int cmlb_create_minor_nodes(struct cmlb_lun *un); 188 static int cmlb_check_update_blockcount(struct cmlb_lun *un); 189 190 #if defined(__i386) || defined(__amd64) 191 static int cmlb_update_fdisk_and_vtoc(struct cmlb_lun *un); 192 #endif 193 194 #if defined(_FIRMWARE_NEEDS_FDISK) 195 static int cmlb_has_max_chs_vals(struct ipart *fdp); 196 #endif 197 198 #if defined(_SUNOS_VTOC_16) 199 static void cmlb_convert_geometry(diskaddr_t capacity, struct dk_geom *un_g); 200 #endif 201 202 static int cmlb_dkio_get_geometry(struct cmlb_lun *un, caddr_t arg, int flag); 203 static int cmlb_dkio_set_geometry(struct cmlb_lun *un, caddr_t arg, int flag); 204 static int cmlb_dkio_get_partition(struct cmlb_lun *un, caddr_t arg, int flag); 205 static int cmlb_dkio_set_partition(struct cmlb_lun *un, caddr_t arg, int flag); 206 static int cmlb_dkio_get_efi(struct cmlb_lun *un, caddr_t arg, int flag); 207 static int cmlb_dkio_set_efi(struct cmlb_lun *un, dev_t dev, caddr_t arg, 208 int flag); 209 static int cmlb_dkio_get_vtoc(struct cmlb_lun *un, caddr_t arg, int flag); 210 static int cmlb_dkio_set_vtoc(struct cmlb_lun *un, dev_t dev, caddr_t arg, 211 int flag); 212 static int cmlb_dkio_get_mboot(struct cmlb_lun *un, caddr_t arg, int flag); 213 static int cmlb_dkio_set_mboot(struct cmlb_lun *un, caddr_t arg, int flag); 214 static int cmlb_dkio_partition(struct cmlb_lun *un, caddr_t arg, int flag); 215 216 #if defined(__i386) || defined(__amd64) 217 static int cmlb_dkio_get_virtgeom(struct cmlb_lun *un, caddr_t arg, int flag); 218 static int cmlb_dkio_get_phygeom(struct cmlb_lun *un, caddr_t arg, int flag); 219 static int cmlb_dkio_partinfo(struct cmlb_lun *un, dev_t dev, caddr_t arg, 220 int flag); 221 #endif 222 223 static void cmlb_dbg(uint_t comp, struct cmlb_lun *un, const char *fmt, ...); 224 static void cmlb_v_log(dev_info_t *dev, char *label, uint_t level, 225 const char *fmt, va_list ap); 226 static void cmlb_log(dev_info_t *dev, char *label, uint_t level, 227 const char *fmt, ...); 228 229 int 230 _init(void) 231 { 232 mutex_init(&cmlb_log_mutex, NULL, MUTEX_DRIVER, NULL); 233 return (mod_install(&modlinkage)); 234 } 235 236 int 237 _info(struct modinfo *modinfop) 238 { 239 return (mod_info(&modlinkage, modinfop)); 240 } 241 242 int 243 _fini(void) 244 { 245 int err; 246 247 if ((err = mod_remove(&modlinkage)) != 0) { 248 return (err); 249 } 250 251 mutex_destroy(&cmlb_log_mutex); 252 return (err); 253 } 254 255 /* 256 * cmlb_dbg is used for debugging to log additional info 257 * Level of output is controlled via cmlb_level_mask setting. 258 */ 259 static void 260 cmlb_dbg(uint_t comp, struct cmlb_lun *un, const char *fmt, ...) 261 { 262 va_list ap; 263 dev_info_t *dev; 264 uint_t level_mask = 0; 265 266 ASSERT(un != NULL); 267 dev = CMLB_DEVINFO(un); 268 ASSERT(dev != NULL); 269 /* 270 * Filter messages based on the global component and level masks, 271 * also print if un matches the value of cmlb_debug_un, or if 272 * cmlb_debug_un is set to NULL. 273 */ 274 if (comp & CMLB_TRACE) 275 level_mask |= CMLB_LOGMASK_TRACE; 276 277 if (comp & CMLB_INFO) 278 level_mask |= CMLB_LOGMASK_INFO; 279 280 if (comp & CMLB_ERROR) 281 level_mask |= CMLB_LOGMASK_ERROR; 282 283 if ((cmlb_level_mask & level_mask) && 284 ((cmlb_debug_un == NULL) || (cmlb_debug_un == un))) { 285 va_start(ap, fmt); 286 cmlb_v_log(dev, CMLB_LABEL(un), CE_CONT, fmt, ap); 287 va_end(ap); 288 } 289 } 290 291 /* 292 * cmlb_log is basically a duplicate of scsi_log. It is redefined here 293 * so that this module does not depend on scsi module. 294 */ 295 static void 296 cmlb_log(dev_info_t *dev, char *label, uint_t level, const char *fmt, ...) 297 { 298 va_list ap; 299 300 va_start(ap, fmt); 301 cmlb_v_log(dev, label, level, fmt, ap); 302 va_end(ap); 303 } 304 305 static void 306 cmlb_v_log(dev_info_t *dev, char *label, uint_t level, const char *fmt, 307 va_list ap) 308 { 309 static char name[256]; 310 int log_only = 0; 311 int boot_only = 0; 312 int console_only = 0; 313 314 mutex_enter(&cmlb_log_mutex); 315 316 if (dev) { 317 if (level == CE_PANIC || level == CE_WARN || 318 level == CE_NOTE) { 319 (void) sprintf(name, "%s (%s%d):\n", 320 ddi_pathname(dev, cmlb_log_buffer), 321 label, ddi_get_instance(dev)); 322 } else { 323 name[0] = '\0'; 324 } 325 } else { 326 (void) sprintf(name, "%s:", label); 327 } 328 329 (void) vsprintf(cmlb_log_buffer, fmt, ap); 330 331 switch (cmlb_log_buffer[0]) { 332 case '!': 333 log_only = 1; 334 break; 335 case '?': 336 boot_only = 1; 337 break; 338 case '^': 339 console_only = 1; 340 break; 341 } 342 343 switch (level) { 344 case CE_NOTE: 345 level = CE_CONT; 346 /* FALLTHROUGH */ 347 case CE_CONT: 348 case CE_WARN: 349 case CE_PANIC: 350 if (boot_only) { 351 cmn_err(level, "?%s\t%s", name, &cmlb_log_buffer[1]); 352 } else if (console_only) { 353 cmn_err(level, "^%s\t%s", name, &cmlb_log_buffer[1]); 354 } else if (log_only) { 355 cmn_err(level, "!%s\t%s", name, &cmlb_log_buffer[1]); 356 } else { 357 cmn_err(level, "%s\t%s", name, cmlb_log_buffer); 358 } 359 break; 360 case CE_IGNORE: 361 break; 362 default: 363 cmn_err(CE_CONT, "^DEBUG: %s\t%s", name, cmlb_log_buffer); 364 break; 365 } 366 mutex_exit(&cmlb_log_mutex); 367 } 368 369 370 /* 371 * cmlb_alloc_handle: 372 * 373 * Allocates a handle. 374 * 375 * Arguments: 376 * cmlbhandlep pointer to handle 377 * 378 * Notes: 379 * Allocates a handle and stores the allocated handle in the area 380 * pointed to by cmlbhandlep 381 * 382 * Context: 383 * Kernel thread only (can sleep). 384 */ 385 void 386 cmlb_alloc_handle(cmlb_handle_t *cmlbhandlep) 387 { 388 struct cmlb_lun *un; 389 390 un = kmem_zalloc(sizeof (struct cmlb_lun), KM_SLEEP); 391 ASSERT(cmlbhandlep != NULL); 392 393 un->un_state = CMLB_INITED; 394 un->un_def_labeltype = CMLB_LABEL_UNDEF; 395 mutex_init(CMLB_MUTEX(un), NULL, MUTEX_DRIVER, NULL); 396 397 *cmlbhandlep = (cmlb_handle_t)(un); 398 } 399 400 /* 401 * cmlb_free_handle 402 * 403 * Frees handle. 404 * 405 * Arguments: 406 * cmlbhandlep pointer to handle 407 */ 408 void 409 cmlb_free_handle(cmlb_handle_t *cmlbhandlep) 410 { 411 struct cmlb_lun *un; 412 413 un = (struct cmlb_lun *)*cmlbhandlep; 414 if (un != NULL) { 415 mutex_destroy(CMLB_MUTEX(un)); 416 kmem_free(un, sizeof (struct cmlb_lun)); 417 } 418 419 } 420 421 /* 422 * cmlb_attach: 423 * 424 * Attach handle to device, create minor nodes for device. 425 * 426 * Arguments: 427 * devi pointer to device's dev_info structure. 428 * tgopsp pointer to array of functions cmlb can use to callback 429 * to target driver. 430 * 431 * device_type Peripheral device type as defined in 432 * scsi/generic/inquiry.h 433 * 434 * is_removable whether or not device is removable. 435 * 0 non-removable, 1 removable. 436 * 437 * node_type minor node type (as used by ddi_create_minor_node) 438 * 439 * alter_behavior 440 * bit flags: 441 * 442 * CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT: create 443 * an alternate slice for the default label, if 444 * device type is DTYPE_DIRECT an architectures default 445 * label type is VTOC16. 446 * Otherwise alternate slice will no be created. 447 * 448 * 449 * CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8: report a default 450 * geometry and label for DKIOCGGEOM and DKIOCGVTOC 451 * on architecture with VTOC8 label types. 452 * 453 * 454 * cmlbhandle cmlb handle associated with device 455 * 456 * Notes: 457 * Assumes a default label based on capacity for non-removable devices. 458 * If capacity > 1TB, EFI is assumed otherwise VTOC (default VTOC 459 * for the architecture). 460 * 461 * For removable devices, default label type is assumed to be VTOC 462 * type. Create minor nodes based on a default label type. 463 * Label on the media is not validated. 464 * minor number consists of: 465 * if _SUNOS_VTOC_8 is defined 466 * lowest 3 bits is taken as partition number 467 * the rest is instance number 468 * if _SUNOS_VTOC_16 is defined 469 * lowest 6 bits is taken as partition number 470 * the rest is instance number 471 * 472 * 473 * Return values: 474 * 0 Success 475 * ENXIO creating minor nodes failed. 476 */ 477 int 478 cmlb_attach(dev_info_t *devi, cmlb_tg_ops_t *tgopsp, int device_type, 479 int is_removable, char *node_type, int alter_behavior, 480 cmlb_handle_t cmlbhandle) 481 { 482 483 struct cmlb_lun *un = (struct cmlb_lun *)cmlbhandle; 484 diskaddr_t cap; 485 int status; 486 487 mutex_enter(CMLB_MUTEX(un)); 488 489 CMLB_DEVINFO(un) = devi; 490 un->cmlb_tg_ops = tgopsp; 491 un->un_device_type = device_type; 492 un->un_is_removable = is_removable; 493 un->un_node_type = node_type; 494 un->un_sys_blocksize = DEV_BSIZE; 495 un->un_f_geometry_is_valid = FALSE; 496 un->un_def_labeltype = CMLB_LABEL_VTOC; 497 un->un_alter_behavior = alter_behavior; 498 499 if (is_removable != 0) { 500 mutex_exit(CMLB_MUTEX(un)); 501 status = DK_TG_GETCAP(un, &cap); 502 mutex_enter(CMLB_MUTEX(un)); 503 if (status == 0 && cap > DK_MAX_BLOCKS) { 504 /* set default EFI if > 1TB */ 505 un->un_def_labeltype = CMLB_LABEL_EFI; 506 } 507 } 508 509 /* create minor nodes based on default label type */ 510 un->un_last_labeltype = CMLB_LABEL_UNDEF; 511 un->un_cur_labeltype = CMLB_LABEL_UNDEF; 512 513 if (cmlb_create_minor_nodes(un) != 0) { 514 mutex_exit(CMLB_MUTEX(un)); 515 return (ENXIO); 516 } 517 518 un->un_state = CMLB_ATTACHED; 519 520 mutex_exit(CMLB_MUTEX(un)); 521 return (0); 522 } 523 524 /* 525 * cmlb_detach: 526 * 527 * Invalidate in-core labeling data and remove all minor nodes for 528 * the device associate with handle. 529 * 530 * Arguments: 531 * cmlbhandle cmlb handle associated with device. 532 * 533 */ 534 void 535 cmlb_detach(cmlb_handle_t cmlbhandle) 536 { 537 struct cmlb_lun *un = (struct cmlb_lun *)cmlbhandle; 538 539 mutex_enter(CMLB_MUTEX(un)); 540 un->un_def_labeltype = CMLB_LABEL_UNDEF; 541 un->un_f_geometry_is_valid = FALSE; 542 ddi_remove_minor_node(CMLB_DEVINFO(un), NULL); 543 un->un_state = CMLB_INITED; 544 mutex_exit(CMLB_MUTEX(un)); 545 } 546 547 /* 548 * cmlb_validate: 549 * 550 * Validates label. 551 * 552 * Arguments 553 * cmlbhandle cmlb handle associated with device. 554 * 555 * Notes: 556 * If new label type is different from the current, adjust minor nodes 557 * accordingly. 558 * 559 * Return values: 560 * 0 success 561 * Note: having fdisk but no solaris partition is assumed 562 * success. 563 * 564 * ENOMEM memory allocation failed 565 * EIO i/o errors during read or get capacity 566 * EACCESS reservation conflicts 567 * EINVAL label was corrupt, or no default label was assumed 568 * ENXIO invalid handle 569 */ 570 int 571 cmlb_validate(cmlb_handle_t cmlbhandle) 572 { 573 struct cmlb_lun *un = (struct cmlb_lun *)cmlbhandle; 574 int rval; 575 int ret = 0; 576 577 /* 578 * Temp work-around checking un for NULL since there is a bug 579 * in sd_detach calling this routine from taskq_dispatch 580 * inited function. 581 */ 582 if (un == NULL) 583 return (ENXIO); 584 585 ASSERT(un != NULL); 586 587 mutex_enter(CMLB_MUTEX(un)); 588 if (un->un_state < CMLB_ATTACHED) { 589 mutex_exit(CMLB_MUTEX(un)); 590 return (ENXIO); 591 } 592 593 rval = cmlb_validate_geometry((struct cmlb_lun *)cmlbhandle, 1); 594 595 if (rval == ENOTSUP) { 596 if (un->un_f_geometry_is_valid == TRUE) { 597 un->un_cur_labeltype = CMLB_LABEL_EFI; 598 ret = 0; 599 } else { 600 ret = EINVAL; 601 } 602 } else { 603 ret = rval; 604 if (ret == 0) 605 un->un_cur_labeltype = CMLB_LABEL_VTOC; 606 } 607 608 if (ret == 0) 609 (void) cmlb_create_minor_nodes(un); 610 611 mutex_exit(CMLB_MUTEX(un)); 612 return (ret); 613 } 614 615 /* 616 * cmlb_invalidate: 617 * Invalidate in core label data 618 * 619 * Arguments: 620 * cmlbhandle cmlb handle associated with device. 621 */ 622 void 623 cmlb_invalidate(cmlb_handle_t cmlbhandle) 624 { 625 struct cmlb_lun *un = (struct cmlb_lun *)cmlbhandle; 626 627 if (un == NULL) 628 return; 629 630 mutex_enter(CMLB_MUTEX(un)); 631 un->un_f_geometry_is_valid = FALSE; 632 mutex_exit(CMLB_MUTEX(un)); 633 } 634 635 /* 636 * cmlb_close: 637 * 638 * Close the device, revert to a default label minor node for the device, 639 * if it is removable. 640 * 641 * Arguments: 642 * cmlbhandle cmlb handle associated with device. 643 * 644 * Return values: 645 * 0 Success 646 * ENXIO Re-creating minor node failed. 647 */ 648 int 649 cmlb_close(cmlb_handle_t cmlbhandle) 650 { 651 struct cmlb_lun *un = (struct cmlb_lun *)cmlbhandle; 652 653 mutex_enter(CMLB_MUTEX(un)); 654 un->un_f_geometry_is_valid = FALSE; 655 656 /* revert to default minor node for this device */ 657 if (ISREMOVABLE(un)) { 658 un->un_cur_labeltype = CMLB_LABEL_UNDEF; 659 (void) cmlb_create_minor_nodes(un); 660 } 661 662 mutex_exit(CMLB_MUTEX(un)); 663 return (0); 664 } 665 666 /* 667 * cmlb_get_devid_block: 668 * get the block number where device id is stored. 669 * 670 * Arguments: 671 * cmlbhandle cmlb handle associated with device. 672 * devidblockp pointer to block number. 673 * 674 * Notes: 675 * It stores the block number of device id in the area pointed to 676 * by devidblockp. 677 * with the block number of device id. 678 * 679 * Return values: 680 * 0 success 681 * EINVAL device id does not apply to current label type. 682 */ 683 int 684 cmlb_get_devid_block(cmlb_handle_t cmlbhandle, diskaddr_t *devidblockp) 685 { 686 daddr_t spc, blk, head, cyl; 687 struct cmlb_lun *un = (struct cmlb_lun *)cmlbhandle; 688 689 mutex_enter(CMLB_MUTEX(un)); 690 if (un->un_state < CMLB_ATTACHED) { 691 mutex_exit(CMLB_MUTEX(un)); 692 return (EINVAL); 693 } 694 695 if (un->un_blockcount <= DK_MAX_BLOCKS) { 696 /* this geometry doesn't allow us to write a devid */ 697 if (un->un_g.dkg_acyl < 2) { 698 mutex_exit(CMLB_MUTEX(un)); 699 return (EINVAL); 700 } 701 702 /* 703 * Subtract 2 guarantees that the next to last cylinder 704 * is used 705 */ 706 cyl = un->un_g.dkg_ncyl + un->un_g.dkg_acyl - 2; 707 spc = un->un_g.dkg_nhead * un->un_g.dkg_nsect; 708 head = un->un_g.dkg_nhead - 1; 709 blk = (cyl * (spc - un->un_g.dkg_apc)) + 710 (head * un->un_g.dkg_nsect) + 1; 711 } else { 712 mutex_exit(CMLB_MUTEX(un)); 713 return (EINVAL); 714 } 715 *devidblockp = blk; 716 mutex_exit(CMLB_MUTEX(un)); 717 return (0); 718 } 719 720 /* 721 * cmlb_partinfo: 722 * Get partition info for specified partition number. 723 * 724 * Arguments: 725 * cmlbhandle cmlb handle associated with device. 726 * part partition number 727 * nblocksp pointer to number of blocks 728 * startblockp pointer to starting block 729 * partnamep pointer to name of partition 730 * tagp pointer to tag info 731 * 732 * 733 * Notes: 734 * If in-core label is not valid, this functions tries to revalidate 735 * the label. If label is valid, it stores the total number of blocks 736 * in this partition in the area pointed to by nblocksp, starting 737 * block number in area pointed to by startblockp, pointer to partition 738 * name in area pointed to by partnamep, and tag value in area 739 * pointed by tagp. 740 * For EFI labels, tag value will be set to 0. 741 * 742 * For all nblocksp, startblockp and partnamep, tagp, a value of NULL 743 * indicates the corresponding info is not requested. 744 * 745 * 746 * Return values: 747 * 0 success 748 * EINVAL no valid label or requested partition number is invalid. 749 * 750 */ 751 int 752 cmlb_partinfo(cmlb_handle_t cmlbhandle, int part, diskaddr_t *nblocksp, 753 diskaddr_t *startblockp, char **partnamep, uint16_t *tagp) 754 { 755 756 struct cmlb_lun *un = (struct cmlb_lun *)cmlbhandle; 757 int rval; 758 759 ASSERT(un != NULL); 760 mutex_enter(CMLB_MUTEX(un)); 761 if (un->un_state < CMLB_ATTACHED) { 762 mutex_exit(CMLB_MUTEX(un)); 763 return (EINVAL); 764 } 765 766 if (part < 0 || part >= MAXPART) { 767 rval = EINVAL; 768 } else { 769 (void) cmlb_validate_geometry((struct cmlb_lun *)un, 0); 770 if ((un->un_f_geometry_is_valid == FALSE) || 771 (part < NDKMAP && un->un_solaris_size == 0)) { 772 rval = EINVAL; 773 } else { 774 if (startblockp != NULL) 775 *startblockp = (diskaddr_t)un->un_offset[part]; 776 777 if (nblocksp != NULL) 778 *nblocksp = (diskaddr_t) 779 un->un_map[part].dkl_nblk; 780 781 if (tagp != NULL) 782 if (un->un_cur_labeltype == CMLB_LABEL_EFI) 783 *tagp = V_UNASSIGNED; 784 else 785 *tagp = un->un_vtoc.v_part[part].p_tag; 786 rval = 0; 787 } 788 789 /* consistent with behavior of sd for getting minor name */ 790 if (partnamep != NULL) 791 *partnamep = dk_minor_data[part].name; 792 793 } 794 795 mutex_exit(CMLB_MUTEX(un)); 796 return (rval); 797 } 798 799 /* ARGSUSED */ 800 int 801 cmlb_ioctl(cmlb_handle_t cmlbhandle, dev_t dev, int cmd, intptr_t arg, 802 int flag, cred_t *cred_p, int *rval_p) 803 { 804 805 int err; 806 struct cmlb_lun *un; 807 808 un = (struct cmlb_lun *)cmlbhandle; 809 810 ASSERT(un != NULL); 811 812 mutex_enter(CMLB_MUTEX(un)); 813 if (un->un_state < CMLB_ATTACHED) { 814 mutex_exit(CMLB_MUTEX(un)); 815 return (EIO); 816 } 817 818 819 if ((cmlb_check_update_blockcount(un) == 0) && 820 (un->un_blockcount > DK_MAX_BLOCKS)) { 821 switch (cmd) { 822 case DKIOCGAPART: 823 case DKIOCGGEOM: 824 case DKIOCSGEOM: 825 case DKIOCGVTOC: 826 case DKIOCSVTOC: 827 case DKIOCSAPART: 828 case DKIOCG_PHYGEOM: 829 case DKIOCG_VIRTGEOM: 830 mutex_exit(CMLB_MUTEX(un)); 831 return (ENOTSUP); 832 } 833 } 834 835 switch (cmd) { 836 case DKIOCSVTOC: 837 case DKIOCSETEFI: 838 case DKIOCSMBOOT: 839 break; 840 default: 841 (void) cmlb_validate_geometry(un, 0); 842 if ((un->un_f_geometry_is_valid == TRUE) && 843 (un->un_solaris_size > 0)) { 844 /* 845 * the "geometry_is_valid" flag could be true if we 846 * have an fdisk table but no Solaris partition 847 */ 848 if (un->un_vtoc.v_sanity != VTOC_SANE) { 849 /* it is EFI, so return ENOTSUP for these */ 850 switch (cmd) { 851 case DKIOCGAPART: 852 case DKIOCGGEOM: 853 case DKIOCGVTOC: 854 case DKIOCSVTOC: 855 case DKIOCSAPART: 856 mutex_exit(CMLB_MUTEX(un)); 857 return (ENOTSUP); 858 } 859 } 860 } 861 } 862 863 mutex_exit(CMLB_MUTEX(un)); 864 865 switch (cmd) { 866 case DKIOCGGEOM: 867 cmlb_dbg(CMLB_TRACE, un, "DKIOCGGEOM\n"); 868 err = cmlb_dkio_get_geometry(un, (caddr_t)arg, flag); 869 break; 870 871 case DKIOCSGEOM: 872 cmlb_dbg(CMLB_TRACE, un, "DKIOCSGEOM\n"); 873 err = cmlb_dkio_set_geometry(un, (caddr_t)arg, flag); 874 break; 875 876 case DKIOCGAPART: 877 cmlb_dbg(CMLB_TRACE, un, "DKIOCGAPART\n"); 878 err = cmlb_dkio_get_partition(un, (caddr_t)arg, flag); 879 break; 880 881 case DKIOCSAPART: 882 cmlb_dbg(CMLB_TRACE, un, "DKIOCSAPART\n"); 883 err = cmlb_dkio_set_partition(un, (caddr_t)arg, flag); 884 break; 885 886 case DKIOCGVTOC: 887 cmlb_dbg(CMLB_TRACE, un, "DKIOCGVTOC\n"); 888 err = cmlb_dkio_get_vtoc(un, (caddr_t)arg, flag); 889 break; 890 891 case DKIOCGETEFI: 892 cmlb_dbg(CMLB_TRACE, un, "DKIOCGETEFI\n"); 893 err = cmlb_dkio_get_efi(un, (caddr_t)arg, flag); 894 break; 895 896 case DKIOCPARTITION: 897 cmlb_dbg(CMLB_TRACE, un, "DKIOCPARTITION\n"); 898 err = cmlb_dkio_partition(un, (caddr_t)arg, flag); 899 break; 900 901 case DKIOCSVTOC: 902 cmlb_dbg(CMLB_TRACE, un, "DKIOCSVTOC\n"); 903 err = cmlb_dkio_set_vtoc(un, dev, (caddr_t)arg, flag); 904 break; 905 906 case DKIOCSETEFI: 907 cmlb_dbg(CMLB_TRACE, un, "DKIOCSETEFI\n"); 908 err = cmlb_dkio_set_efi(un, dev, (caddr_t)arg, flag); 909 break; 910 911 case DKIOCGMBOOT: 912 cmlb_dbg(CMLB_TRACE, un, "DKIOCGMBOOT\n"); 913 err = cmlb_dkio_get_mboot(un, (caddr_t)arg, flag); 914 break; 915 916 case DKIOCSMBOOT: 917 cmlb_dbg(CMLB_TRACE, un, "DKIOCSMBOOT\n"); 918 err = cmlb_dkio_set_mboot(un, (caddr_t)arg, flag); 919 break; 920 case DKIOCG_PHYGEOM: 921 cmlb_dbg(CMLB_TRACE, un, "DKIOCG_PHYGEOM\n"); 922 #if defined(__i386) || defined(__amd64) 923 err = cmlb_dkio_get_phygeom(un, (caddr_t)arg, flag); 924 #else 925 err = ENOTTY; 926 #endif 927 break; 928 case DKIOCG_VIRTGEOM: 929 cmlb_dbg(CMLB_TRACE, un, "DKIOCG_VIRTGEOM\n"); 930 #if defined(__i386) || defined(__amd64) 931 err = cmlb_dkio_get_virtgeom(un, (caddr_t)arg, flag); 932 #else 933 err = ENOTTY; 934 #endif 935 break; 936 case DKIOCPARTINFO: 937 cmlb_dbg(CMLB_TRACE, un, "DKIOCPARTINFO"); 938 #if defined(__i386) || defined(__amd64) 939 err = cmlb_dkio_partinfo(un, dev, (caddr_t)arg, flag); 940 #else 941 err = ENOTTY; 942 #endif 943 break; 944 945 default: 946 err = ENOTTY; 947 948 } 949 return (err); 950 } 951 952 dev_t 953 cmlb_make_device(struct cmlb_lun *un) 954 { 955 return (makedevice(ddi_name_to_major(ddi_get_name(CMLB_DEVINFO(un))), 956 ddi_get_instance(CMLB_DEVINFO(un)) << CMLBUNIT_SHIFT)); 957 } 958 959 /* 960 * Function: cmlb_check_update_blockcount 961 * 962 * Description: If current capacity value is invalid, obtains the 963 * current capacity from target driver. 964 * 965 * Return Code: 0 success 966 * EIO failure 967 */ 968 static int 969 cmlb_check_update_blockcount(struct cmlb_lun *un) 970 { 971 int status; 972 diskaddr_t capacity; 973 974 ASSERT(mutex_owned(CMLB_MUTEX(un))); 975 976 if (un->un_f_geometry_is_valid == FALSE) { 977 mutex_exit(CMLB_MUTEX(un)); 978 status = DK_TG_GETCAP(un, &capacity); 979 mutex_enter(CMLB_MUTEX(un)); 980 if (status == 0 && capacity != 0) { 981 un->un_blockcount = capacity; 982 return (0); 983 } else 984 return (EIO); 985 } else 986 return (0); 987 } 988 989 /* 990 * Function: cmlb_create_minor_nodes 991 * 992 * Description: Create or adjust the minor device nodes for the instance. 993 * Minor nodes are created based on default label type, 994 * current label type and last label type we created 995 * minor nodes based on. 996 * 997 * 998 * Arguments: un - driver soft state (unit) structure 999 * 1000 * Return Code: 0 success 1001 * ENXIO failure. 1002 * 1003 * Context: Kernel thread context 1004 */ 1005 static int 1006 cmlb_create_minor_nodes(struct cmlb_lun *un) 1007 { 1008 struct driver_minor_data *dmdp; 1009 int instance; 1010 char name[48]; 1011 cmlb_label_t newlabeltype; 1012 1013 ASSERT(un != NULL); 1014 ASSERT(mutex_owned(CMLB_MUTEX(un))); 1015 1016 1017 /* check the most common case */ 1018 if (un->un_cur_labeltype != CMLB_LABEL_UNDEF && 1019 un->un_last_labeltype == un->un_cur_labeltype) { 1020 /* do nothing */ 1021 return (0); 1022 } 1023 1024 if (un->un_def_labeltype == CMLB_LABEL_UNDEF) { 1025 /* we should never get here */ 1026 return (ENXIO); 1027 } 1028 1029 if (un->un_last_labeltype == CMLB_LABEL_UNDEF) { 1030 /* first time during attach */ 1031 newlabeltype = un->un_def_labeltype; 1032 1033 instance = ddi_get_instance(CMLB_DEVINFO(un)); 1034 1035 /* Create all the minor nodes for this target. */ 1036 dmdp = (newlabeltype == CMLB_LABEL_EFI) ? dk_minor_data_efi : 1037 dk_minor_data; 1038 while (dmdp->name != NULL) { 1039 1040 (void) sprintf(name, "%s", dmdp->name); 1041 1042 if (ddi_create_minor_node(CMLB_DEVINFO(un), name, 1043 dmdp->type, 1044 (instance << CMLBUNIT_SHIFT) | dmdp->minor, 1045 un->un_node_type, NULL) == DDI_FAILURE) { 1046 /* 1047 * Clean up any nodes that may have been 1048 * created, in case this fails in the middle 1049 * of the loop. 1050 */ 1051 ddi_remove_minor_node(CMLB_DEVINFO(un), NULL); 1052 return (ENXIO); 1053 } 1054 dmdp++; 1055 } 1056 un->un_last_labeltype = newlabeltype; 1057 return (0); 1058 } 1059 1060 /* Not first time */ 1061 if (un->un_cur_labeltype == CMLB_LABEL_UNDEF) { 1062 if (un->un_last_labeltype != un->un_def_labeltype) { 1063 /* close time, revert to default. */ 1064 newlabeltype = un->un_def_labeltype; 1065 } else { 1066 /* 1067 * do nothing since the type for which we last created 1068 * nodes matches the default 1069 */ 1070 return (0); 1071 } 1072 } else { 1073 if (un->un_cur_labeltype != un->un_last_labeltype) { 1074 /* We are not closing, use current label type */ 1075 newlabeltype = un->un_cur_labeltype; 1076 } else { 1077 /* 1078 * do nothing since the type for which we last created 1079 * nodes matches the current label type 1080 */ 1081 return (0); 1082 } 1083 } 1084 1085 instance = ddi_get_instance(CMLB_DEVINFO(un)); 1086 1087 /* 1088 * Currently we only fix up the s7 node when we are switching 1089 * label types from or to EFI. This is consistent with 1090 * current behavior of sd. 1091 */ 1092 if (newlabeltype == CMLB_LABEL_EFI && 1093 un->un_last_labeltype != CMLB_LABEL_EFI) { 1094 /* from vtoc to EFI */ 1095 ddi_remove_minor_node(CMLB_DEVINFO(un), "h"); 1096 ddi_remove_minor_node(CMLB_DEVINFO(un), "h,raw"); 1097 (void) ddi_create_minor_node(CMLB_DEVINFO(un), "wd", 1098 S_IFBLK, (instance << CMLBUNIT_SHIFT) | WD_NODE, 1099 un->un_node_type, NULL); 1100 (void) ddi_create_minor_node(CMLB_DEVINFO(un), "wd,raw", 1101 S_IFCHR, (instance << CMLBUNIT_SHIFT) | WD_NODE, 1102 un->un_node_type, NULL); 1103 } else { 1104 /* from efi to vtoc */ 1105 ddi_remove_minor_node(CMLB_DEVINFO(un), "wd"); 1106 ddi_remove_minor_node(CMLB_DEVINFO(un), "wd,raw"); 1107 (void) ddi_create_minor_node(CMLB_DEVINFO(un), "h", 1108 S_IFBLK, (instance << CMLBUNIT_SHIFT) | WD_NODE, 1109 un->un_node_type, NULL); 1110 (void) ddi_create_minor_node(CMLB_DEVINFO(un), "h,raw", 1111 S_IFCHR, (instance << CMLBUNIT_SHIFT) | WD_NODE, 1112 un->un_node_type, NULL); 1113 } 1114 1115 un->un_last_labeltype = newlabeltype; 1116 return (0); 1117 } 1118 1119 /* 1120 * Function: cmlb_validate_geometry 1121 * 1122 * Description: Read the label from the disk (if present). Update the unit's 1123 * geometry and vtoc information from the data in the label. 1124 * Verify that the label is valid. 1125 * 1126 * Arguments: un - driver soft state (unit) structure 1127 * 1128 * Return Code: 0 - Successful completion 1129 * EINVAL - Invalid value in un->un_tgt_blocksize or 1130 * un->un_blockcount; or label on disk is corrupted 1131 * or unreadable. 1132 * EACCES - Reservation conflict at the device. 1133 * ENOMEM - Resource allocation error 1134 * ENOTSUP - geometry not applicable 1135 * 1136 * Context: Kernel thread only (can sleep). 1137 */ 1138 static int 1139 cmlb_validate_geometry(struct cmlb_lun *un, int forcerevalid) 1140 { 1141 int label_error = 0; 1142 diskaddr_t capacity; 1143 int count; 1144 1145 ASSERT(mutex_owned(CMLB_MUTEX(un))); 1146 1147 if ((un->un_f_geometry_is_valid == TRUE) && (forcerevalid == 0)) { 1148 if (un->un_cur_labeltype == CMLB_LABEL_EFI) 1149 return (ENOTSUP); 1150 return (0); 1151 } 1152 1153 if (cmlb_check_update_blockcount(un) != 0) 1154 return (EIO); 1155 1156 capacity = un->un_blockcount; 1157 1158 #if defined(_SUNOS_VTOC_16) 1159 /* 1160 * Set up the "whole disk" fdisk partition; this should always 1161 * exist, regardless of whether the disk contains an fdisk table 1162 * or vtoc. 1163 */ 1164 un->un_map[P0_RAW_DISK].dkl_cylno = 0; 1165 /* 1166 * note if capacity > uint32_max we should be using efi, 1167 * and not use p0, so the truncation does not matter. 1168 */ 1169 un->un_map[P0_RAW_DISK].dkl_nblk = capacity; 1170 #endif 1171 /* 1172 * Refresh the logical and physical geometry caches. 1173 * (data from MODE SENSE format/rigid disk geometry pages, 1174 * and scsi_ifgetcap("geometry"). 1175 */ 1176 cmlb_resync_geom_caches(un, capacity); 1177 1178 label_error = cmlb_use_efi(un, capacity); 1179 if (label_error == 0) { 1180 1181 /* found a valid EFI label */ 1182 cmlb_dbg(CMLB_TRACE, un, 1183 "cmlb_validate_geometry: found EFI label\n"); 1184 /* 1185 * solaris_size and geometry_is_valid are set in 1186 * cmlb_use_efi 1187 */ 1188 return (ENOTSUP); 1189 } else { 1190 if ((label_error != ESRCH) && (label_error != EINVAL)) { 1191 cmlb_dbg(CMLB_ERROR, un, "cmlb_use_efi failed %d\n", 1192 label_error); 1193 return (label_error); 1194 } 1195 } 1196 1197 /* NO EFI label found */ 1198 1199 if (capacity > DK_MAX_BLOCKS) { 1200 if (label_error == ESRCH) { 1201 /* 1202 * they've configured a LUN over 1TB, but used 1203 * format.dat to restrict format's view of the 1204 * capacity to be under 1TB 1205 */ 1206 /* i.e > 1Tb with a VTOC < 1TB */ 1207 1208 cmlb_log(CMLB_DEVINFO(un), CMLB_LABEL(un), CE_WARN, 1209 "is >1TB and has a VTOC label: use format(1M) to " 1210 "either decrease the"); 1211 cmlb_log(CMLB_DEVINFO(un), CMLB_LABEL(un), CE_CONT, 1212 "size to be < 1TB or relabel the disk with an EFI " 1213 "label"); 1214 } else { 1215 /* unlabeled disk over 1TB */ 1216 return (ENOTSUP); 1217 } 1218 } 1219 1220 label_error = 0; 1221 1222 /* 1223 * at this point it is either labeled with a VTOC or it is 1224 * under 1TB 1225 */ 1226 1227 /* 1228 * Only DIRECT ACCESS devices will have Sun labels. 1229 * CD's supposedly have a Sun label, too 1230 */ 1231 if (un->un_device_type == DTYPE_DIRECT || ISREMOVABLE(un)) { 1232 struct dk_label *dkl; 1233 offset_t label_addr; 1234 int rval; 1235 size_t buffer_size; 1236 1237 /* 1238 * Note: This will set up un->un_solaris_size and 1239 * un->un_solaris_offset. 1240 */ 1241 rval = cmlb_read_fdisk(un, capacity); 1242 if (rval != 0) { 1243 ASSERT(mutex_owned(CMLB_MUTEX(un))); 1244 return (rval); 1245 } 1246 1247 if (un->un_solaris_size <= DK_LABEL_LOC) { 1248 /* 1249 * Found fdisk table but no Solaris partition entry, 1250 * so don't call cmlb_uselabel() and don't create 1251 * a default label. 1252 */ 1253 label_error = 0; 1254 un->un_f_geometry_is_valid = TRUE; 1255 goto no_solaris_partition; 1256 } 1257 1258 label_addr = (daddr_t)(un->un_solaris_offset + DK_LABEL_LOC); 1259 1260 buffer_size = sizeof (struct dk_label); 1261 1262 cmlb_dbg(CMLB_TRACE, un, "cmlb_validate_geometry: " 1263 "label_addr: 0x%x allocation size: 0x%x\n", 1264 label_addr, buffer_size); 1265 1266 if ((dkl = kmem_zalloc(buffer_size, KM_NOSLEEP)) == NULL) 1267 return (ENOMEM); 1268 1269 mutex_exit(CMLB_MUTEX(un)); 1270 rval = DK_TG_READ(un, dkl, label_addr, buffer_size); 1271 mutex_enter(CMLB_MUTEX(un)); 1272 1273 switch (rval) { 1274 case 0: 1275 /* 1276 * cmlb_uselabel will establish that the geometry 1277 * is valid. 1278 */ 1279 if (cmlb_uselabel(un, 1280 (struct dk_label *)(uintptr_t)dkl) != 1281 CMLB_LABEL_IS_VALID) { 1282 label_error = EINVAL; 1283 } else 1284 un->un_vtoc_label_is_from_media = 1; 1285 break; 1286 case EACCES: 1287 label_error = EACCES; 1288 break; 1289 default: 1290 label_error = EINVAL; 1291 break; 1292 } 1293 1294 kmem_free(dkl, buffer_size); 1295 } 1296 1297 /* 1298 * If a valid label was not found, AND if no reservation conflict 1299 * was detected, then go ahead and create a default label (4069506). 1300 * 1301 * Note: currently, for VTOC_8 devices, the default label is created 1302 * for removables only. For VTOC_16 devices, the default label will 1303 * be created for both removables and non-removables alike. 1304 * (see cmlb_build_default_label) 1305 */ 1306 #if defined(_SUNOS_VTOC_8) 1307 if (ISREMOVABLE(un) && (label_error != EACCES)) { 1308 #elif defined(_SUNOS_VTOC_16) 1309 if (label_error != EACCES) { 1310 #endif 1311 if (un->un_f_geometry_is_valid == FALSE) { 1312 cmlb_build_default_label(un); 1313 } 1314 label_error = 0; 1315 } 1316 1317 no_solaris_partition: 1318 1319 #if defined(_SUNOS_VTOC_16) 1320 /* 1321 * If we have valid geometry, set up the remaining fdisk partitions. 1322 * Note that dkl_cylno is not used for the fdisk map entries, so 1323 * we set it to an entirely bogus value. 1324 */ 1325 for (count = 0; count < FD_NUMPART; count++) { 1326 un->un_map[FDISK_P1 + count].dkl_cylno = -1; 1327 un->un_map[FDISK_P1 + count].dkl_nblk = 1328 un->un_fmap[count].fmap_nblk; 1329 1330 un->un_offset[FDISK_P1 + count] = 1331 un->un_fmap[count].fmap_start; 1332 } 1333 #endif 1334 1335 for (count = 0; count < NDKMAP; count++) { 1336 #if defined(_SUNOS_VTOC_8) 1337 struct dk_map *lp = &un->un_map[count]; 1338 un->un_offset[count] = 1339 un->un_g.dkg_nhead * un->un_g.dkg_nsect * lp->dkl_cylno; 1340 #elif defined(_SUNOS_VTOC_16) 1341 struct dkl_partition *vp = &un->un_vtoc.v_part[count]; 1342 1343 un->un_offset[count] = vp->p_start + un->un_solaris_offset; 1344 #else 1345 #error "No VTOC format defined." 1346 #endif 1347 } 1348 1349 return (label_error); 1350 } 1351 1352 #if defined(_SUNOS_VTOC_16) 1353 /* 1354 * Macro: MAX_BLKS 1355 * 1356 * This macro is used for table entries where we need to have the largest 1357 * possible sector value for that head & SPT (sectors per track) 1358 * combination. Other entries for some smaller disk sizes are set by 1359 * convention to match those used by X86 BIOS usage. 1360 */ 1361 #define MAX_BLKS(heads, spt) UINT16_MAX * heads * spt, heads, spt 1362 1363 /* 1364 * Function: cmlb_convert_geometry 1365 * 1366 * Description: Convert physical geometry into a dk_geom structure. In 1367 * other words, make sure we don't wrap 16-bit values. 1368 * e.g. converting from geom_cache to dk_geom 1369 * 1370 * Context: Kernel thread only 1371 */ 1372 static void 1373 cmlb_convert_geometry(diskaddr_t capacity, struct dk_geom *un_g) 1374 { 1375 int i; 1376 static const struct chs_values { 1377 uint_t max_cap; /* Max Capacity for this HS. */ 1378 uint_t nhead; /* Heads to use. */ 1379 uint_t nsect; /* SPT to use. */ 1380 } CHS_values[] = { 1381 {0x00200000, 64, 32}, /* 1GB or smaller disk. */ 1382 {0x01000000, 128, 32}, /* 8GB or smaller disk. */ 1383 {MAX_BLKS(255, 63)}, /* 502.02GB or smaller disk. */ 1384 {MAX_BLKS(255, 126)}, /* .98TB or smaller disk. */ 1385 {DK_MAX_BLOCKS, 255, 189} /* Max size is just under 1TB */ 1386 }; 1387 1388 /* Unlabeled SCSI floppy device */ 1389 if (capacity <= 0x1000) { 1390 un_g->dkg_nhead = 2; 1391 un_g->dkg_ncyl = 80; 1392 un_g->dkg_nsect = capacity / (un_g->dkg_nhead * un_g->dkg_ncyl); 1393 return; 1394 } 1395 1396 /* 1397 * For all devices we calculate cylinders using the 1398 * heads and sectors we assign based on capacity of the 1399 * device. The table is designed to be compatible with the 1400 * way other operating systems lay out fdisk tables for X86 1401 * and to insure that the cylinders never exceed 65535 to 1402 * prevent problems with X86 ioctls that report geometry. 1403 * We use SPT that are multiples of 63, since other OSes that 1404 * are not limited to 16-bits for cylinders stop at 63 SPT 1405 * we make do by using multiples of 63 SPT. 1406 * 1407 * Note than capacities greater than or equal to 1TB will simply 1408 * get the largest geometry from the table. This should be okay 1409 * since disks this large shouldn't be using CHS values anyway. 1410 */ 1411 for (i = 0; CHS_values[i].max_cap < capacity && 1412 CHS_values[i].max_cap != DK_MAX_BLOCKS; i++) 1413 ; 1414 1415 un_g->dkg_nhead = CHS_values[i].nhead; 1416 un_g->dkg_nsect = CHS_values[i].nsect; 1417 } 1418 #endif 1419 1420 /* 1421 * Function: cmlb_resync_geom_caches 1422 * 1423 * Description: (Re)initialize both geometry caches: the virtual geometry 1424 * information is extracted from the HBA (the "geometry" 1425 * capability), and the physical geometry cache data is 1426 * generated by issuing MODE SENSE commands. 1427 * 1428 * Arguments: un - driver soft state (unit) structure 1429 * capacity - disk capacity in #blocks 1430 * 1431 * Context: Kernel thread only (can sleep). 1432 */ 1433 static void 1434 cmlb_resync_geom_caches(struct cmlb_lun *un, diskaddr_t capacity) 1435 { 1436 struct cmlb_geom pgeom; 1437 struct cmlb_geom lgeom; 1438 struct cmlb_geom *pgeomp = &pgeom; 1439 unsigned short nhead; 1440 unsigned short nsect; 1441 int spc; 1442 int ret; 1443 1444 ASSERT(un != NULL); 1445 ASSERT(mutex_owned(CMLB_MUTEX(un))); 1446 1447 /* 1448 * Ask the controller for its logical geometry. 1449 * Note: if the HBA does not support scsi_ifgetcap("geometry"), 1450 * then the lgeom cache will be invalid. 1451 */ 1452 mutex_exit(CMLB_MUTEX(un)); 1453 bzero(&lgeom, sizeof (struct cmlb_geom)); 1454 ret = DK_TG_GETVIRTGEOM(un, &lgeom); 1455 mutex_enter(CMLB_MUTEX(un)); 1456 1457 bcopy(&lgeom, &un->un_lgeom, sizeof (un->un_lgeom)); 1458 1459 /* 1460 * Initialize the pgeom cache from lgeom, so that if MODE SENSE 1461 * doesn't work, DKIOCG_PHYSGEOM can return reasonable values. 1462 */ 1463 if (ret != 0 || un->un_lgeom.g_nsect == 0 || 1464 un->un_lgeom.g_nhead == 0) { 1465 /* 1466 * Note: Perhaps this needs to be more adaptive? The rationale 1467 * is that, if there's no HBA geometry from the HBA driver, any 1468 * guess is good, since this is the physical geometry. If MODE 1469 * SENSE fails this gives a max cylinder size for non-LBA access 1470 */ 1471 nhead = 255; 1472 nsect = 63; 1473 } else { 1474 nhead = un->un_lgeom.g_nhead; 1475 nsect = un->un_lgeom.g_nsect; 1476 } 1477 1478 if (ISCD(un)) { 1479 pgeomp->g_nhead = 1; 1480 pgeomp->g_nsect = nsect * nhead; 1481 } else { 1482 pgeomp->g_nhead = nhead; 1483 pgeomp->g_nsect = nsect; 1484 } 1485 1486 spc = pgeomp->g_nhead * pgeomp->g_nsect; 1487 pgeomp->g_capacity = capacity; 1488 pgeomp->g_ncyl = pgeomp->g_capacity / spc; 1489 pgeomp->g_acyl = 0; 1490 1491 /* 1492 * Retrieve fresh geometry data from the hardware, stash it 1493 * here temporarily before we rebuild the incore label. 1494 * 1495 * We want to use the MODE SENSE commands to derive the 1496 * physical geometry of the device, but if either command 1497 * fails, the logical geometry is used as the fallback for 1498 * disk label geometry. 1499 */ 1500 1501 mutex_exit(CMLB_MUTEX(un)); 1502 (void) DK_TG_GETPHYGEOM(un, pgeomp); 1503 mutex_enter(CMLB_MUTEX(un)); 1504 1505 /* 1506 * Now update the real copy while holding the mutex. This 1507 * way the global copy is never in an inconsistent state. 1508 */ 1509 bcopy(pgeomp, &un->un_pgeom, sizeof (un->un_pgeom)); 1510 1511 cmlb_dbg(CMLB_INFO, un, "cmlb_resync_geom_caches: " 1512 "(cached from lgeom)\n"); 1513 cmlb_dbg(CMLB_INFO, un, 1514 " ncyl: %ld; acyl: %d; nhead: %d; nsect: %d\n", 1515 un->un_pgeom.g_ncyl, un->un_pgeom.g_acyl, 1516 un->un_pgeom.g_nhead, un->un_pgeom.g_nsect); 1517 cmlb_dbg(CMLB_INFO, un, " lbasize: %d; capacity: %ld; " 1518 "intrlv: %d; rpm: %d\n", un->un_pgeom.g_secsize, 1519 un->un_pgeom.g_capacity, un->un_pgeom.g_intrlv, 1520 un->un_pgeom.g_rpm); 1521 } 1522 1523 1524 /* 1525 * Function: cmlb_read_fdisk 1526 * 1527 * Description: utility routine to read the fdisk table. 1528 * 1529 * Arguments: un - driver soft state (unit) structure 1530 * 1531 * Return Code: 0 for success (includes not reading for no_fdisk_present case 1532 * errnos from tg_rw if failed to read the first block. 1533 * 1534 * Context: Kernel thread only (can sleep). 1535 */ 1536 /* ARGSUSED */ 1537 static int 1538 cmlb_read_fdisk(struct cmlb_lun *un, diskaddr_t capacity) 1539 { 1540 #if defined(_NO_FDISK_PRESENT) 1541 1542 un->un_solaris_offset = 0; 1543 un->un_solaris_size = capacity; 1544 bzero(un->un_fmap, sizeof (struct fmap) * FD_NUMPART); 1545 return (0); 1546 1547 #elif defined(_FIRMWARE_NEEDS_FDISK) 1548 1549 struct ipart *fdp; 1550 struct mboot *mbp; 1551 struct ipart fdisk[FD_NUMPART]; 1552 int i; 1553 char sigbuf[2]; 1554 caddr_t bufp; 1555 int uidx; 1556 int rval; 1557 int lba = 0; 1558 uint_t solaris_offset; /* offset to solaris part. */ 1559 daddr_t solaris_size; /* size of solaris partition */ 1560 uint32_t blocksize; 1561 1562 ASSERT(un != NULL); 1563 ASSERT(mutex_owned(CMLB_MUTEX(un))); 1564 1565 /* 1566 * Start off assuming no fdisk table 1567 */ 1568 solaris_offset = 0; 1569 solaris_size = capacity; 1570 1571 blocksize = 512; 1572 1573 bufp = kmem_zalloc(blocksize, KM_SLEEP); 1574 1575 mutex_exit(CMLB_MUTEX(un)); 1576 rval = DK_TG_READ(un, bufp, 0, blocksize); 1577 mutex_enter(CMLB_MUTEX(un)); 1578 1579 if (rval != 0) { 1580 cmlb_dbg(CMLB_ERROR, un, 1581 "cmlb_read_fdisk: fdisk read err\n"); 1582 kmem_free(bufp, blocksize); 1583 return (rval); 1584 } 1585 1586 mbp = (struct mboot *)bufp; 1587 1588 /* 1589 * The fdisk table does not begin on a 4-byte boundary within the 1590 * master boot record, so we copy it to an aligned structure to avoid 1591 * alignment exceptions on some processors. 1592 */ 1593 bcopy(&mbp->parts[0], fdisk, sizeof (fdisk)); 1594 1595 /* 1596 * Check for lba support before verifying sig; sig might not be 1597 * there, say on a blank disk, but the max_chs mark may still 1598 * be present. 1599 * 1600 * Note: LBA support and BEFs are an x86-only concept but this 1601 * code should work OK on SPARC as well. 1602 */ 1603 1604 /* 1605 * First, check for lba-access-ok on root node (or prom root node) 1606 * if present there, don't need to search fdisk table. 1607 */ 1608 if (ddi_getprop(DDI_DEV_T_ANY, ddi_root_node(), 0, 1609 "lba-access-ok", 0) != 0) { 1610 /* All drives do LBA; don't search fdisk table */ 1611 lba = 1; 1612 } else { 1613 /* Okay, look for mark in fdisk table */ 1614 for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) { 1615 /* accumulate "lba" value from all partitions */ 1616 lba = (lba || cmlb_has_max_chs_vals(fdp)); 1617 } 1618 } 1619 1620 /* 1621 * Next, look for 'no-bef-lba-access' prop on parent. 1622 * Its presence means the realmode driver doesn't support 1623 * LBA, so the target driver shouldn't advertise it as ok. 1624 * This should be a temporary condition; one day all 1625 * BEFs should support the LBA access functions. 1626 */ 1627 if ((lba != 0) && (ddi_getprop(DDI_DEV_T_ANY, 1628 ddi_get_parent(CMLB_DEVINFO(un)), DDI_PROP_DONTPASS, 1629 "no-bef-lba-access", 0) != 0)) { 1630 /* BEF doesn't support LBA; don't advertise it as ok */ 1631 lba = 0; 1632 } 1633 1634 if (lba != 0) { 1635 dev_t dev = cmlb_make_device(un); 1636 1637 if (ddi_getprop(dev, CMLB_DEVINFO(un), DDI_PROP_DONTPASS, 1638 "lba-access-ok", 0) == 0) { 1639 /* not found; create it */ 1640 if (ddi_prop_create(dev, CMLB_DEVINFO(un), 0, 1641 "lba-access-ok", (caddr_t)NULL, 0) != 1642 DDI_PROP_SUCCESS) { 1643 cmlb_dbg(CMLB_ERROR, un, 1644 "cmlb_read_fdisk: Can't create lba " 1645 "property for instance %d\n", 1646 ddi_get_instance(CMLB_DEVINFO(un))); 1647 } 1648 } 1649 } 1650 1651 bcopy(&mbp->signature, sigbuf, sizeof (sigbuf)); 1652 1653 /* 1654 * Endian-independent signature check 1655 */ 1656 if (((sigbuf[1] & 0xFF) != ((MBB_MAGIC >> 8) & 0xFF)) || 1657 (sigbuf[0] != (MBB_MAGIC & 0xFF))) { 1658 cmlb_dbg(CMLB_ERROR, un, 1659 "cmlb_read_fdisk: no fdisk\n"); 1660 bzero(un->un_fmap, sizeof (struct fmap) * FD_NUMPART); 1661 goto done; 1662 } 1663 1664 #ifdef CMLBDEBUG 1665 if (cmlb_level_mask & SD_LOGMASK_INFO) { 1666 fdp = fdisk; 1667 cmlb_dbg(CMLB_INFO, un, "cmlb_read_fdisk:\n"); 1668 cmlb_dbg(CMLB_INFO, un, " relsect " 1669 "numsect sysid bootid\n"); 1670 for (i = 0; i < FD_NUMPART; i++, fdp++) { 1671 cmlb_dbg(CMLB_INFO, un, 1672 " %d: %8d %8d 0x%08x 0x%08x\n", 1673 i, fdp->relsect, fdp->numsect, 1674 fdp->systid, fdp->bootid); 1675 } 1676 } 1677 #endif 1678 1679 /* 1680 * Try to find the unix partition 1681 */ 1682 uidx = -1; 1683 solaris_offset = 0; 1684 solaris_size = 0; 1685 1686 for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) { 1687 int relsect; 1688 int numsect; 1689 1690 if (fdp->numsect == 0) { 1691 un->un_fmap[i].fmap_start = 0; 1692 un->un_fmap[i].fmap_nblk = 0; 1693 continue; 1694 } 1695 1696 /* 1697 * Data in the fdisk table is little-endian. 1698 */ 1699 relsect = LE_32(fdp->relsect); 1700 numsect = LE_32(fdp->numsect); 1701 1702 un->un_fmap[i].fmap_start = relsect; 1703 un->un_fmap[i].fmap_nblk = numsect; 1704 1705 if (fdp->systid != SUNIXOS && 1706 fdp->systid != SUNIXOS2 && 1707 fdp->systid != EFI_PMBR) { 1708 continue; 1709 } 1710 1711 /* 1712 * use the last active solaris partition id found 1713 * (there should only be 1 active partition id) 1714 * 1715 * if there are no active solaris partition id 1716 * then use the first inactive solaris partition id 1717 */ 1718 if ((uidx == -1) || (fdp->bootid == ACTIVE)) { 1719 uidx = i; 1720 solaris_offset = relsect; 1721 solaris_size = numsect; 1722 } 1723 } 1724 1725 cmlb_dbg(CMLB_INFO, un, "fdisk 0x%x 0x%lx", 1726 un->un_solaris_offset, un->un_solaris_size); 1727 done: 1728 1729 /* 1730 * Clear the VTOC info, only if the Solaris partition entry 1731 * has moved, changed size, been deleted, or if the size of 1732 * the partition is too small to even fit the label sector. 1733 */ 1734 if ((un->un_solaris_offset != solaris_offset) || 1735 (un->un_solaris_size != solaris_size) || 1736 solaris_size <= DK_LABEL_LOC) { 1737 cmlb_dbg(CMLB_INFO, un, "fdisk moved 0x%x 0x%lx", 1738 solaris_offset, solaris_size); 1739 bzero(&un->un_g, sizeof (struct dk_geom)); 1740 bzero(&un->un_vtoc, sizeof (struct dk_vtoc)); 1741 bzero(&un->un_map, NDKMAP * (sizeof (struct dk_map))); 1742 un->un_f_geometry_is_valid = FALSE; 1743 } 1744 un->un_solaris_offset = solaris_offset; 1745 un->un_solaris_size = solaris_size; 1746 kmem_free(bufp, blocksize); 1747 return (rval); 1748 1749 #else /* #elif defined(_FIRMWARE_NEEDS_FDISK) */ 1750 #error "fdisk table presence undetermined for this platform." 1751 #endif /* #if defined(_NO_FDISK_PRESENT) */ 1752 } 1753 1754 static void 1755 cmlb_swap_efi_gpt(efi_gpt_t *e) 1756 { 1757 _NOTE(ASSUMING_PROTECTED(*e)) 1758 e->efi_gpt_Signature = LE_64(e->efi_gpt_Signature); 1759 e->efi_gpt_Revision = LE_32(e->efi_gpt_Revision); 1760 e->efi_gpt_HeaderSize = LE_32(e->efi_gpt_HeaderSize); 1761 e->efi_gpt_HeaderCRC32 = LE_32(e->efi_gpt_HeaderCRC32); 1762 e->efi_gpt_MyLBA = LE_64(e->efi_gpt_MyLBA); 1763 e->efi_gpt_AlternateLBA = LE_64(e->efi_gpt_AlternateLBA); 1764 e->efi_gpt_FirstUsableLBA = LE_64(e->efi_gpt_FirstUsableLBA); 1765 e->efi_gpt_LastUsableLBA = LE_64(e->efi_gpt_LastUsableLBA); 1766 UUID_LE_CONVERT(e->efi_gpt_DiskGUID, e->efi_gpt_DiskGUID); 1767 e->efi_gpt_PartitionEntryLBA = LE_64(e->efi_gpt_PartitionEntryLBA); 1768 e->efi_gpt_NumberOfPartitionEntries = 1769 LE_32(e->efi_gpt_NumberOfPartitionEntries); 1770 e->efi_gpt_SizeOfPartitionEntry = 1771 LE_32(e->efi_gpt_SizeOfPartitionEntry); 1772 e->efi_gpt_PartitionEntryArrayCRC32 = 1773 LE_32(e->efi_gpt_PartitionEntryArrayCRC32); 1774 } 1775 1776 static void 1777 cmlb_swap_efi_gpe(int nparts, efi_gpe_t *p) 1778 { 1779 int i; 1780 1781 _NOTE(ASSUMING_PROTECTED(*p)) 1782 for (i = 0; i < nparts; i++) { 1783 UUID_LE_CONVERT(p[i].efi_gpe_PartitionTypeGUID, 1784 p[i].efi_gpe_PartitionTypeGUID); 1785 p[i].efi_gpe_StartingLBA = LE_64(p[i].efi_gpe_StartingLBA); 1786 p[i].efi_gpe_EndingLBA = LE_64(p[i].efi_gpe_EndingLBA); 1787 /* PartitionAttrs */ 1788 } 1789 } 1790 1791 static int 1792 cmlb_validate_efi(efi_gpt_t *labp) 1793 { 1794 if (labp->efi_gpt_Signature != EFI_SIGNATURE) 1795 return (EINVAL); 1796 /* at least 96 bytes in this version of the spec. */ 1797 if (sizeof (efi_gpt_t) - sizeof (labp->efi_gpt_Reserved2) > 1798 labp->efi_gpt_HeaderSize) 1799 return (EINVAL); 1800 /* this should be 128 bytes */ 1801 if (labp->efi_gpt_SizeOfPartitionEntry != sizeof (efi_gpe_t)) 1802 return (EINVAL); 1803 return (0); 1804 } 1805 1806 static int 1807 cmlb_use_efi(struct cmlb_lun *un, diskaddr_t capacity) 1808 { 1809 int i; 1810 int rval = 0; 1811 efi_gpe_t *partitions; 1812 uchar_t *buf; 1813 uint_t lbasize; /* is really how much to read */ 1814 diskaddr_t cap; 1815 uint_t nparts; 1816 diskaddr_t gpe_lba; 1817 int iofailed = 0; 1818 1819 ASSERT(mutex_owned(CMLB_MUTEX(un))); 1820 1821 lbasize = un->un_sys_blocksize; 1822 1823 buf = kmem_zalloc(EFI_MIN_ARRAY_SIZE, KM_SLEEP); 1824 mutex_exit(CMLB_MUTEX(un)); 1825 1826 rval = DK_TG_READ(un, buf, 0, lbasize); 1827 if (rval) { 1828 iofailed = 1; 1829 goto done_err; 1830 } 1831 if (((struct dk_label *)buf)->dkl_magic == DKL_MAGIC) { 1832 /* not ours */ 1833 rval = ESRCH; 1834 goto done_err; 1835 } 1836 1837 rval = DK_TG_READ(un, buf, 1, lbasize); 1838 if (rval) { 1839 iofailed = 1; 1840 goto done_err; 1841 } 1842 cmlb_swap_efi_gpt((efi_gpt_t *)buf); 1843 1844 if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) { 1845 /* 1846 * Couldn't read the primary, try the backup. Our 1847 * capacity at this point could be based on CHS, so 1848 * check what the device reports. 1849 */ 1850 rval = DK_TG_GETCAP(un, &cap); 1851 1852 if (rval) { 1853 iofailed = 1; 1854 goto done_err; 1855 } 1856 if ((rval = DK_TG_READ(un, buf, cap - 1, lbasize)) != 0) { 1857 iofailed = 1; 1858 goto done_err; 1859 } 1860 cmlb_swap_efi_gpt((efi_gpt_t *)buf); 1861 if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) 1862 goto done_err; 1863 cmlb_log(CMLB_DEVINFO(un), CMLB_LABEL(un), CE_WARN, 1864 "primary label corrupt; using backup\n"); 1865 } 1866 1867 nparts = ((efi_gpt_t *)buf)->efi_gpt_NumberOfPartitionEntries; 1868 gpe_lba = ((efi_gpt_t *)buf)->efi_gpt_PartitionEntryLBA; 1869 1870 rval = DK_TG_READ(un, buf, gpe_lba, EFI_MIN_ARRAY_SIZE); 1871 if (rval) { 1872 iofailed = 1; 1873 goto done_err; 1874 } 1875 partitions = (efi_gpe_t *)buf; 1876 1877 if (nparts > MAXPART) { 1878 nparts = MAXPART; 1879 } 1880 cmlb_swap_efi_gpe(nparts, partitions); 1881 1882 mutex_enter(CMLB_MUTEX(un)); 1883 1884 /* Fill in partition table. */ 1885 for (i = 0; i < nparts; i++) { 1886 if (partitions->efi_gpe_StartingLBA != 0 || 1887 partitions->efi_gpe_EndingLBA != 0) { 1888 un->un_map[i].dkl_cylno = 1889 partitions->efi_gpe_StartingLBA; 1890 un->un_map[i].dkl_nblk = 1891 partitions->efi_gpe_EndingLBA - 1892 partitions->efi_gpe_StartingLBA + 1; 1893 un->un_offset[i] = 1894 partitions->efi_gpe_StartingLBA; 1895 } 1896 if (i == WD_NODE) { 1897 /* 1898 * minor number 7 corresponds to the whole disk 1899 */ 1900 un->un_map[i].dkl_cylno = 0; 1901 un->un_map[i].dkl_nblk = capacity; 1902 un->un_offset[i] = 0; 1903 } 1904 partitions++; 1905 } 1906 un->un_solaris_offset = 0; 1907 un->un_solaris_size = capacity; 1908 un->un_f_geometry_is_valid = TRUE; 1909 kmem_free(buf, EFI_MIN_ARRAY_SIZE); 1910 return (0); 1911 1912 done_err: 1913 kmem_free(buf, EFI_MIN_ARRAY_SIZE); 1914 mutex_enter(CMLB_MUTEX(un)); 1915 /* 1916 * if we didn't find something that could look like a VTOC 1917 * and the disk is over 1TB, we know there isn't a valid label. 1918 * Otherwise let cmlb_uselabel decide what to do. We only 1919 * want to invalidate this if we're certain the label isn't 1920 * valid because cmlb_prop_op will now fail, which in turn 1921 * causes things like opens and stats on the partition to fail. 1922 */ 1923 if ((capacity > DK_MAX_BLOCKS) && (rval != ESRCH) && !iofailed) { 1924 un->un_f_geometry_is_valid = FALSE; 1925 } 1926 return (rval); 1927 } 1928 1929 1930 /* 1931 * Function: cmlb_uselabel 1932 * 1933 * Description: Validate the disk label and update the relevant data (geometry, 1934 * partition, vtoc, and capacity data) in the cmlb_lun struct. 1935 * Marks the geometry of the unit as being valid. 1936 * 1937 * Arguments: un: unit struct. 1938 * dk_label: disk label 1939 * 1940 * Return Code: CMLB_LABEL_IS_VALID: Label read from disk is OK; geometry, 1941 * partition, vtoc, and capacity data are good. 1942 * 1943 * CMLB_LABEL_IS_INVALID: Magic number or checksum error in the 1944 * label; or computed capacity does not jibe with capacity 1945 * reported from the READ CAPACITY command. 1946 * 1947 * Context: Kernel thread only (can sleep). 1948 */ 1949 static int 1950 cmlb_uselabel(struct cmlb_lun *un, struct dk_label *labp) 1951 { 1952 short *sp; 1953 short sum; 1954 short count; 1955 int label_error = CMLB_LABEL_IS_VALID; 1956 int i; 1957 diskaddr_t label_capacity; 1958 int part_end; 1959 diskaddr_t track_capacity; 1960 #if defined(_SUNOS_VTOC_16) 1961 struct dkl_partition *vpartp; 1962 #endif 1963 ASSERT(un != NULL); 1964 ASSERT(mutex_owned(CMLB_MUTEX(un))); 1965 1966 /* Validate the magic number of the label. */ 1967 if (labp->dkl_magic != DKL_MAGIC) { 1968 #if defined(__sparc) 1969 if (!ISREMOVABLE(un)) { 1970 cmlb_log(CMLB_DEVINFO(un), CMLB_LABEL(un), CE_WARN, 1971 "Corrupt label; wrong magic number\n"); 1972 } 1973 #endif 1974 return (CMLB_LABEL_IS_INVALID); 1975 } 1976 1977 /* Validate the checksum of the label. */ 1978 sp = (short *)labp; 1979 sum = 0; 1980 count = sizeof (struct dk_label) / sizeof (short); 1981 while (count--) { 1982 sum ^= *sp++; 1983 } 1984 1985 if (sum != 0) { 1986 #if defined(_SUNOS_VTOC_16) 1987 if (!ISCD(un)) { 1988 #elif defined(_SUNOS_VTOC_8) 1989 if (!ISREMOVABLE(un)) { 1990 #endif 1991 cmlb_log(CMLB_DEVINFO(un), CMLB_LABEL(un), CE_WARN, 1992 "Corrupt label - label checksum failed\n"); 1993 } 1994 return (CMLB_LABEL_IS_INVALID); 1995 } 1996 1997 1998 /* 1999 * Fill in geometry structure with data from label. 2000 */ 2001 bzero(&un->un_g, sizeof (struct dk_geom)); 2002 un->un_g.dkg_ncyl = labp->dkl_ncyl; 2003 un->un_g.dkg_acyl = labp->dkl_acyl; 2004 un->un_g.dkg_bcyl = 0; 2005 un->un_g.dkg_nhead = labp->dkl_nhead; 2006 un->un_g.dkg_nsect = labp->dkl_nsect; 2007 un->un_g.dkg_intrlv = labp->dkl_intrlv; 2008 2009 #if defined(_SUNOS_VTOC_8) 2010 un->un_g.dkg_gap1 = labp->dkl_gap1; 2011 un->un_g.dkg_gap2 = labp->dkl_gap2; 2012 un->un_g.dkg_bhead = labp->dkl_bhead; 2013 #endif 2014 #if defined(_SUNOS_VTOC_16) 2015 un->un_dkg_skew = labp->dkl_skew; 2016 #endif 2017 2018 #if defined(__i386) || defined(__amd64) 2019 un->un_g.dkg_apc = labp->dkl_apc; 2020 #endif 2021 2022 /* 2023 * Currently we rely on the values in the label being accurate. If 2024 * dkl_rpm or dkl_pcly are zero in the label, use a default value. 2025 * 2026 * Note: In the future a MODE SENSE may be used to retrieve this data, 2027 * although this command is optional in SCSI-2. 2028 */ 2029 un->un_g.dkg_rpm = (labp->dkl_rpm != 0) ? labp->dkl_rpm : 3600; 2030 un->un_g.dkg_pcyl = (labp->dkl_pcyl != 0) ? labp->dkl_pcyl : 2031 (un->un_g.dkg_ncyl + un->un_g.dkg_acyl); 2032 2033 /* 2034 * The Read and Write reinstruct values may not be valid 2035 * for older disks. 2036 */ 2037 un->un_g.dkg_read_reinstruct = labp->dkl_read_reinstruct; 2038 un->un_g.dkg_write_reinstruct = labp->dkl_write_reinstruct; 2039 2040 /* Fill in partition table. */ 2041 #if defined(_SUNOS_VTOC_8) 2042 for (i = 0; i < NDKMAP; i++) { 2043 un->un_map[i].dkl_cylno = labp->dkl_map[i].dkl_cylno; 2044 un->un_map[i].dkl_nblk = labp->dkl_map[i].dkl_nblk; 2045 } 2046 #endif 2047 #if defined(_SUNOS_VTOC_16) 2048 vpartp = labp->dkl_vtoc.v_part; 2049 track_capacity = labp->dkl_nhead * labp->dkl_nsect; 2050 2051 for (i = 0; i < NDKMAP; i++, vpartp++) { 2052 un->un_map[i].dkl_cylno = vpartp->p_start / track_capacity; 2053 un->un_map[i].dkl_nblk = vpartp->p_size; 2054 } 2055 #endif 2056 2057 /* Fill in VTOC Structure. */ 2058 bcopy(&labp->dkl_vtoc, &un->un_vtoc, sizeof (struct dk_vtoc)); 2059 #if defined(_SUNOS_VTOC_8) 2060 /* 2061 * The 8-slice vtoc does not include the ascii label; save it into 2062 * the device's soft state structure here. 2063 */ 2064 bcopy(labp->dkl_asciilabel, un->un_asciilabel, LEN_DKL_ASCII); 2065 #endif 2066 2067 /* Mark the geometry as valid. */ 2068 un->un_f_geometry_is_valid = TRUE; 2069 2070 /* Now look for a valid capacity. */ 2071 track_capacity = (un->un_g.dkg_nhead * un->un_g.dkg_nsect); 2072 label_capacity = (un->un_g.dkg_ncyl * track_capacity); 2073 2074 if (un->un_g.dkg_acyl) { 2075 #if defined(__i386) || defined(__amd64) 2076 /* we may have > 1 alts cylinder */ 2077 label_capacity += (track_capacity * un->un_g.dkg_acyl); 2078 #else 2079 label_capacity += track_capacity; 2080 #endif 2081 } 2082 2083 /* 2084 * if we got invalidated when mutex exit and entered again, 2085 * if blockcount different than when we came in, need to 2086 * retry from beginning of cmlb_validate_geometry. 2087 * revisit this on next phase of utilizing this for 2088 * sd. 2089 */ 2090 2091 if (label_capacity <= un->un_blockcount) { 2092 #if defined(_SUNOS_VTOC_8) 2093 /* 2094 * We can't let this happen on drives that are subdivided 2095 * into logical disks (i.e., that have an fdisk table). 2096 * The un_blockcount field should always hold the full media 2097 * size in sectors, period. This code would overwrite 2098 * un_blockcount with the size of the Solaris fdisk partition. 2099 */ 2100 cmlb_dbg(CMLB_ERROR, un, 2101 "cmlb_uselabel: Label %d blocks; Drive %d blocks\n", 2102 label_capacity, un->un_blockcount); 2103 un->un_solaris_size = label_capacity; 2104 2105 #endif /* defined(_SUNOS_VTOC_8) */ 2106 goto done; 2107 } 2108 2109 if (ISCD(un)) { 2110 /* For CDROMs, we trust that the data in the label is OK. */ 2111 #if defined(_SUNOS_VTOC_8) 2112 for (i = 0; i < NDKMAP; i++) { 2113 part_end = labp->dkl_nhead * labp->dkl_nsect * 2114 labp->dkl_map[i].dkl_cylno + 2115 labp->dkl_map[i].dkl_nblk - 1; 2116 2117 if ((labp->dkl_map[i].dkl_nblk) && 2118 (part_end > un->un_blockcount)) { 2119 un->un_f_geometry_is_valid = FALSE; 2120 break; 2121 } 2122 } 2123 #endif 2124 #if defined(_SUNOS_VTOC_16) 2125 vpartp = &(labp->dkl_vtoc.v_part[0]); 2126 for (i = 0; i < NDKMAP; i++, vpartp++) { 2127 part_end = vpartp->p_start + vpartp->p_size; 2128 if ((vpartp->p_size > 0) && 2129 (part_end > un->un_blockcount)) { 2130 un->un_f_geometry_is_valid = FALSE; 2131 break; 2132 } 2133 } 2134 #endif 2135 } else { 2136 /* label_capacity > un->un_blockcount */ 2137 cmlb_log(CMLB_DEVINFO(un), CMLB_LABEL(un), CE_WARN, 2138 "Corrupt label - bad geometry\n"); 2139 cmlb_log(CMLB_DEVINFO(un), CMLB_LABEL(un), CE_CONT, 2140 "Label says %llu blocks; Drive says %llu blocks\n", 2141 label_capacity, un->un_blockcount); 2142 un->un_f_geometry_is_valid = FALSE; 2143 label_error = CMLB_LABEL_IS_INVALID; 2144 } 2145 2146 done: 2147 2148 cmlb_dbg(CMLB_INFO, un, "cmlb_uselabel: (label geometry)\n"); 2149 cmlb_dbg(CMLB_INFO, un, 2150 " ncyl: %d; acyl: %d; nhead: %d; nsect: %d\n", 2151 un->un_g.dkg_ncyl, un->un_g.dkg_acyl, 2152 un->un_g.dkg_nhead, un->un_g.dkg_nsect); 2153 2154 cmlb_dbg(CMLB_INFO, un, 2155 " label_capacity: %d; intrlv: %d; rpm: %d\n", 2156 un->un_blockcount, un->un_g.dkg_intrlv, un->un_g.dkg_rpm); 2157 cmlb_dbg(CMLB_INFO, un, " wrt_reinstr: %d; rd_reinstr: %d\n", 2158 un->un_g.dkg_write_reinstruct, un->un_g.dkg_read_reinstruct); 2159 2160 ASSERT(mutex_owned(CMLB_MUTEX(un))); 2161 2162 return (label_error); 2163 } 2164 2165 2166 /* 2167 * Function: cmlb_build_default_label 2168 * 2169 * Description: Generate a default label for those devices that do not have 2170 * one, e.g., new media, removable cartridges, etc.. 2171 * 2172 * Context: Kernel thread only 2173 */ 2174 static void 2175 cmlb_build_default_label(struct cmlb_lun *un) 2176 { 2177 #if defined(_SUNOS_VTOC_16) 2178 uint_t phys_spc; 2179 uint_t disksize; 2180 struct dk_geom un_g; 2181 #endif 2182 2183 ASSERT(un != NULL); 2184 ASSERT(mutex_owned(CMLB_MUTEX(un))); 2185 2186 #if defined(_SUNOS_VTOC_8) 2187 /* 2188 * Note: This is a legacy check for non-removable devices on VTOC_8 2189 * only. This may be a valid check for VTOC_16 as well. 2190 */ 2191 if (!ISREMOVABLE(un)) { 2192 return; 2193 } 2194 #endif 2195 2196 bzero(&un->un_g, sizeof (struct dk_geom)); 2197 bzero(&un->un_vtoc, sizeof (struct dk_vtoc)); 2198 bzero(&un->un_map, NDKMAP * (sizeof (struct dk_map))); 2199 2200 #if defined(_SUNOS_VTOC_8) 2201 2202 /* 2203 * It's a REMOVABLE media, therefore no label (on sparc, anyway). 2204 * But it is still necessary to set up various geometry information, 2205 * and we are doing this here. 2206 */ 2207 2208 /* 2209 * For the rpm, we use the minimum for the disk. For the head, cyl, 2210 * and number of sector per track, if the capacity <= 1GB, head = 64, 2211 * sect = 32. else head = 255, sect 63 Note: the capacity should be 2212 * equal to C*H*S values. This will cause some truncation of size due 2213 * to round off errors. For CD-ROMs, this truncation can have adverse 2214 * side effects, so returning ncyl and nhead as 1. The nsect will 2215 * overflow for most of CD-ROMs as nsect is of type ushort. (4190569) 2216 */ 2217 un->un_solaris_size = un->un_blockcount; 2218 if (ISCD(un)) { 2219 tg_attribute_t tgattribute; 2220 int is_writable; 2221 /* 2222 * Preserve the old behavior for non-writable 2223 * medias. Since dkg_nsect is a ushort, it 2224 * will lose bits as cdroms have more than 2225 * 65536 sectors. So if we recalculate 2226 * capacity, it will become much shorter. 2227 * But the dkg_* information is not 2228 * used for CDROMs so it is OK. But for 2229 * Writable CDs we need this information 2230 * to be valid (for newfs say). So we 2231 * make nsect and nhead > 1 that way 2232 * nsect can still stay within ushort limit 2233 * without losing any bits. 2234 */ 2235 2236 bzero(&tgattribute, sizeof (tg_attribute_t)); 2237 2238 mutex_exit(CMLB_MUTEX(un)); 2239 is_writable = (DK_TG_GETATTRIBUTE(un, &tgattribute) == 0) ? 2240 tgattribute.media_is_writable : 1; 2241 mutex_enter(CMLB_MUTEX(un)); 2242 2243 if (is_writable) { 2244 un->un_g.dkg_nhead = 64; 2245 un->un_g.dkg_nsect = 32; 2246 un->un_g.dkg_ncyl = un->un_blockcount / (64 * 32); 2247 un->un_solaris_size = un->un_g.dkg_ncyl * 2248 un->un_g.dkg_nhead * un->un_g.dkg_nsect; 2249 } else { 2250 un->un_g.dkg_ncyl = 1; 2251 un->un_g.dkg_nhead = 1; 2252 un->un_g.dkg_nsect = un->un_blockcount; 2253 } 2254 } else { 2255 if (un->un_blockcount <= 0x1000) { 2256 /* unlabeled SCSI floppy device */ 2257 un->un_g.dkg_nhead = 2; 2258 un->un_g.dkg_ncyl = 80; 2259 un->un_g.dkg_nsect = un->un_blockcount / (2 * 80); 2260 } else if (un->un_blockcount <= 0x200000) { 2261 un->un_g.dkg_nhead = 64; 2262 un->un_g.dkg_nsect = 32; 2263 un->un_g.dkg_ncyl = un->un_blockcount / (64 * 32); 2264 } else { 2265 un->un_g.dkg_nhead = 255; 2266 un->un_g.dkg_nsect = 63; 2267 un->un_g.dkg_ncyl = un->un_blockcount / (255 * 63); 2268 } 2269 un->un_solaris_size = 2270 un->un_g.dkg_ncyl * un->un_g.dkg_nhead * un->un_g.dkg_nsect; 2271 2272 } 2273 2274 un->un_g.dkg_acyl = 0; 2275 un->un_g.dkg_bcyl = 0; 2276 un->un_g.dkg_rpm = 200; 2277 un->un_asciilabel[0] = '\0'; 2278 un->un_g.dkg_pcyl = un->un_g.dkg_ncyl; 2279 2280 un->un_map[0].dkl_cylno = 0; 2281 un->un_map[0].dkl_nblk = un->un_solaris_size; 2282 2283 un->un_map[2].dkl_cylno = 0; 2284 un->un_map[2].dkl_nblk = un->un_solaris_size; 2285 2286 #elif defined(_SUNOS_VTOC_16) 2287 2288 if (un->un_solaris_size == 0) { 2289 /* 2290 * Got fdisk table but no solaris entry therefore 2291 * don't create a default label 2292 */ 2293 un->un_f_geometry_is_valid = TRUE; 2294 return; 2295 } 2296 2297 /* 2298 * For CDs we continue to use the physical geometry to calculate 2299 * number of cylinders. All other devices must convert the 2300 * physical geometry (cmlb_geom) to values that will fit 2301 * in a dk_geom structure. 2302 */ 2303 if (ISCD(un)) { 2304 phys_spc = un->un_pgeom.g_nhead * un->un_pgeom.g_nsect; 2305 } else { 2306 /* Convert physical geometry to disk geometry */ 2307 bzero(&un_g, sizeof (struct dk_geom)); 2308 cmlb_convert_geometry(un->un_blockcount, &un_g); 2309 bcopy(&un_g, &un->un_g, sizeof (un->un_g)); 2310 phys_spc = un->un_g.dkg_nhead * un->un_g.dkg_nsect; 2311 } 2312 2313 un->un_g.dkg_pcyl = un->un_solaris_size / phys_spc; 2314 un->un_g.dkg_acyl = DK_ACYL; 2315 un->un_g.dkg_ncyl = un->un_g.dkg_pcyl - DK_ACYL; 2316 disksize = un->un_g.dkg_ncyl * phys_spc; 2317 2318 if (ISCD(un)) { 2319 /* 2320 * CD's don't use the "heads * sectors * cyls"-type of 2321 * geometry, but instead use the entire capacity of the media. 2322 */ 2323 disksize = un->un_solaris_size; 2324 un->un_g.dkg_nhead = 1; 2325 un->un_g.dkg_nsect = 1; 2326 un->un_g.dkg_rpm = 2327 (un->un_pgeom.g_rpm == 0) ? 200 : un->un_pgeom.g_rpm; 2328 2329 un->un_vtoc.v_part[0].p_start = 0; 2330 un->un_vtoc.v_part[0].p_size = disksize; 2331 un->un_vtoc.v_part[0].p_tag = V_BACKUP; 2332 un->un_vtoc.v_part[0].p_flag = V_UNMNT; 2333 2334 un->un_map[0].dkl_cylno = 0; 2335 un->un_map[0].dkl_nblk = disksize; 2336 un->un_offset[0] = 0; 2337 2338 } else { 2339 /* 2340 * Hard disks and removable media cartridges 2341 */ 2342 un->un_g.dkg_rpm = 2343 (un->un_pgeom.g_rpm == 0) ? 3600: un->un_pgeom.g_rpm; 2344 un->un_vtoc.v_sectorsz = un->un_sys_blocksize; 2345 2346 /* Add boot slice */ 2347 un->un_vtoc.v_part[8].p_start = 0; 2348 un->un_vtoc.v_part[8].p_size = phys_spc; 2349 un->un_vtoc.v_part[8].p_tag = V_BOOT; 2350 un->un_vtoc.v_part[8].p_flag = V_UNMNT; 2351 2352 un->un_map[8].dkl_cylno = 0; 2353 un->un_map[8].dkl_nblk = phys_spc; 2354 un->un_offset[8] = 0; 2355 2356 if ((un->un_alter_behavior & 2357 CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT) && 2358 un->un_device_type == DTYPE_DIRECT) { 2359 un->un_vtoc.v_part[9].p_start = phys_spc; 2360 un->un_vtoc.v_part[9].p_size = 2 * phys_spc; 2361 un->un_vtoc.v_part[9].p_tag = V_ALTSCTR; 2362 un->un_vtoc.v_part[9].p_flag = 0; 2363 2364 un->un_map[9].dkl_cylno = 1; 2365 un->un_map[9].dkl_nblk = 2 * phys_spc; 2366 un->un_offset[9] = phys_spc; 2367 } 2368 } 2369 2370 un->un_g.dkg_apc = 0; 2371 un->un_vtoc.v_nparts = V_NUMPAR; 2372 un->un_vtoc.v_version = V_VERSION; 2373 2374 /* Add backup slice */ 2375 un->un_vtoc.v_part[2].p_start = 0; 2376 un->un_vtoc.v_part[2].p_size = disksize; 2377 un->un_vtoc.v_part[2].p_tag = V_BACKUP; 2378 un->un_vtoc.v_part[2].p_flag = V_UNMNT; 2379 2380 un->un_map[2].dkl_cylno = 0; 2381 un->un_map[2].dkl_nblk = disksize; 2382 un->un_offset[2] = 0; 2383 2384 (void) sprintf(un->un_vtoc.v_asciilabel, "DEFAULT cyl %d alt %d" 2385 " hd %d sec %d", un->un_g.dkg_ncyl, un->un_g.dkg_acyl, 2386 un->un_g.dkg_nhead, un->un_g.dkg_nsect); 2387 2388 #else 2389 #error "No VTOC format defined." 2390 #endif 2391 2392 un->un_g.dkg_read_reinstruct = 0; 2393 un->un_g.dkg_write_reinstruct = 0; 2394 2395 un->un_g.dkg_intrlv = 1; 2396 2397 un->un_vtoc.v_sanity = VTOC_SANE; 2398 2399 un->un_f_geometry_is_valid = TRUE; 2400 un->un_vtoc_label_is_from_media = 0; 2401 2402 cmlb_dbg(CMLB_INFO, un, 2403 "cmlb_build_default_label: Default label created: " 2404 "cyl: %d\tacyl: %d\tnhead: %d\tnsect: %d\tcap: %d\n", 2405 un->un_g.dkg_ncyl, un->un_g.dkg_acyl, un->un_g.dkg_nhead, 2406 un->un_g.dkg_nsect, un->un_blockcount); 2407 } 2408 2409 2410 #if defined(_FIRMWARE_NEEDS_FDISK) 2411 /* 2412 * Max CHS values, as they are encoded into bytes, for 1022/254/63 2413 */ 2414 #define LBA_MAX_SECT (63 | ((1022 & 0x300) >> 2)) 2415 #define LBA_MAX_CYL (1022 & 0xFF) 2416 #define LBA_MAX_HEAD (254) 2417 2418 2419 /* 2420 * Function: cmlb_has_max_chs_vals 2421 * 2422 * Description: Return TRUE if Cylinder-Head-Sector values are all at maximum. 2423 * 2424 * Arguments: fdp - ptr to CHS info 2425 * 2426 * Return Code: True or false 2427 * 2428 * Context: Any. 2429 */ 2430 static int 2431 cmlb_has_max_chs_vals(struct ipart *fdp) 2432 { 2433 return ((fdp->begcyl == LBA_MAX_CYL) && 2434 (fdp->beghead == LBA_MAX_HEAD) && 2435 (fdp->begsect == LBA_MAX_SECT) && 2436 (fdp->endcyl == LBA_MAX_CYL) && 2437 (fdp->endhead == LBA_MAX_HEAD) && 2438 (fdp->endsect == LBA_MAX_SECT)); 2439 } 2440 #endif 2441 2442 /* 2443 * Function: cmlb_dkio_get_geometry 2444 * 2445 * Description: This routine is the driver entry point for handling user 2446 * requests to get the device geometry (DKIOCGGEOM). 2447 * 2448 * Arguments: 2449 * arg - pointer to user provided dk_geom structure specifying 2450 * the controller's notion of the current geometry. 2451 * flag - this argument is a pass through to ddi_copyxxx() 2452 * directly from the mode argument of ioctl(). 2453 * 2454 * Return Code: 0 2455 * EFAULT 2456 * ENXIO 2457 * EIO 2458 */ 2459 static int 2460 cmlb_dkio_get_geometry(struct cmlb_lun *un, caddr_t arg, int flag) 2461 { 2462 struct dk_geom *tmp_geom = NULL; 2463 int rval = 0; 2464 2465 /* 2466 * cmlb_validate_geometry does not spin a disk up 2467 * if it was spun down. We need to make sure it 2468 * is ready. 2469 */ 2470 mutex_enter(CMLB_MUTEX(un)); 2471 rval = cmlb_validate_geometry(un, 1); 2472 #if defined(_SUNOS_VTOC_8) 2473 if (rval == EINVAL && 2474 un->un_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8) { 2475 /* 2476 * This is to return a default label geometry even when we 2477 * do not really assume a default label for the device. 2478 * dad driver utilizes this. 2479 */ 2480 if (un->un_blockcount <= DK_MAX_BLOCKS) { 2481 cmlb_setup_default_geometry(un); 2482 rval = 0; 2483 } 2484 } 2485 #endif 2486 if (rval) { 2487 mutex_exit(CMLB_MUTEX(un)); 2488 return (rval); 2489 } 2490 2491 #if defined(__i386) || defined(__amd64) 2492 if (un->un_solaris_size == 0) { 2493 mutex_exit(CMLB_MUTEX(un)); 2494 return (EIO); 2495 } 2496 #endif 2497 2498 /* 2499 * Make a local copy of the soft state geometry to avoid some potential 2500 * race conditions associated with holding the mutex and updating the 2501 * write_reinstruct value 2502 */ 2503 tmp_geom = kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP); 2504 bcopy(&un->un_g, tmp_geom, sizeof (struct dk_geom)); 2505 2506 if (tmp_geom->dkg_write_reinstruct == 0) { 2507 tmp_geom->dkg_write_reinstruct = 2508 (int)((int)(tmp_geom->dkg_nsect * tmp_geom->dkg_rpm * 2509 cmlb_rot_delay) / (int)60000); 2510 } 2511 mutex_exit(CMLB_MUTEX(un)); 2512 2513 rval = ddi_copyout(tmp_geom, (void *)arg, sizeof (struct dk_geom), 2514 flag); 2515 if (rval != 0) { 2516 rval = EFAULT; 2517 } 2518 2519 kmem_free(tmp_geom, sizeof (struct dk_geom)); 2520 return (rval); 2521 2522 } 2523 2524 2525 /* 2526 * Function: cmlb_dkio_set_geometry 2527 * 2528 * Description: This routine is the driver entry point for handling user 2529 * requests to set the device geometry (DKIOCSGEOM). The actual 2530 * device geometry is not updated, just the driver "notion" of it. 2531 * 2532 * Arguments: 2533 * arg - pointer to user provided dk_geom structure used to set 2534 * the controller's notion of the current geometry. 2535 * flag - this argument is a pass through to ddi_copyxxx() 2536 * directly from the mode argument of ioctl(). 2537 * 2538 * Return Code: 0 2539 * EFAULT 2540 * ENXIO 2541 * EIO 2542 */ 2543 static int 2544 cmlb_dkio_set_geometry(struct cmlb_lun *un, caddr_t arg, int flag) 2545 { 2546 struct dk_geom *tmp_geom; 2547 struct dk_map *lp; 2548 int rval = 0; 2549 int i; 2550 2551 2552 #if defined(__i386) || defined(__amd64) 2553 if (un->un_solaris_size == 0) { 2554 return (EIO); 2555 } 2556 #endif 2557 /* 2558 * We need to copy the user specified geometry into local 2559 * storage and then update the softstate. We don't want to hold 2560 * the mutex and copyin directly from the user to the soft state 2561 */ 2562 tmp_geom = (struct dk_geom *) 2563 kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP); 2564 rval = ddi_copyin(arg, tmp_geom, sizeof (struct dk_geom), flag); 2565 if (rval != 0) { 2566 kmem_free(tmp_geom, sizeof (struct dk_geom)); 2567 return (EFAULT); 2568 } 2569 2570 mutex_enter(CMLB_MUTEX(un)); 2571 bcopy(tmp_geom, &un->un_g, sizeof (struct dk_geom)); 2572 for (i = 0; i < NDKMAP; i++) { 2573 lp = &un->un_map[i]; 2574 un->un_offset[i] = 2575 un->un_g.dkg_nhead * un->un_g.dkg_nsect * lp->dkl_cylno; 2576 #if defined(__i386) || defined(__amd64) 2577 un->un_offset[i] += un->un_solaris_offset; 2578 #endif 2579 } 2580 un->un_f_geometry_is_valid = FALSE; 2581 mutex_exit(CMLB_MUTEX(un)); 2582 kmem_free(tmp_geom, sizeof (struct dk_geom)); 2583 2584 return (rval); 2585 } 2586 2587 /* 2588 * Function: cmlb_dkio_get_partition 2589 * 2590 * Description: This routine is the driver entry point for handling user 2591 * requests to get the partition table (DKIOCGAPART). 2592 * 2593 * Arguments: 2594 * arg - pointer to user provided dk_allmap structure specifying 2595 * the controller's notion of the current partition table. 2596 * flag - this argument is a pass through to ddi_copyxxx() 2597 * directly from the mode argument of ioctl(). 2598 * 2599 * Return Code: 0 2600 * EFAULT 2601 * ENXIO 2602 * EIO 2603 */ 2604 static int 2605 cmlb_dkio_get_partition(struct cmlb_lun *un, caddr_t arg, int flag) 2606 { 2607 int rval = 0; 2608 int size; 2609 2610 /* 2611 * Make sure the geometry is valid before getting the partition 2612 * information. 2613 */ 2614 mutex_enter(CMLB_MUTEX(un)); 2615 if ((rval = cmlb_validate_geometry(un, 1)) != 0) { 2616 mutex_exit(CMLB_MUTEX(un)); 2617 return (rval); 2618 } 2619 mutex_exit(CMLB_MUTEX(un)); 2620 2621 #if defined(__i386) || defined(__amd64) 2622 if (un->un_solaris_size == 0) { 2623 return (EIO); 2624 } 2625 #endif 2626 2627 #ifdef _MULTI_DATAMODEL 2628 switch (ddi_model_convert_from(flag & FMODELS)) { 2629 case DDI_MODEL_ILP32: { 2630 struct dk_map32 dk_map32[NDKMAP]; 2631 int i; 2632 2633 for (i = 0; i < NDKMAP; i++) { 2634 dk_map32[i].dkl_cylno = un->un_map[i].dkl_cylno; 2635 dk_map32[i].dkl_nblk = un->un_map[i].dkl_nblk; 2636 } 2637 size = NDKMAP * sizeof (struct dk_map32); 2638 rval = ddi_copyout(dk_map32, (void *)arg, size, flag); 2639 if (rval != 0) { 2640 rval = EFAULT; 2641 } 2642 break; 2643 } 2644 case DDI_MODEL_NONE: 2645 size = NDKMAP * sizeof (struct dk_map); 2646 rval = ddi_copyout(un->un_map, (void *)arg, size, flag); 2647 if (rval != 0) { 2648 rval = EFAULT; 2649 } 2650 break; 2651 } 2652 #else /* ! _MULTI_DATAMODEL */ 2653 size = NDKMAP * sizeof (struct dk_map); 2654 rval = ddi_copyout(un->un_map, (void *)arg, size, flag); 2655 if (rval != 0) { 2656 rval = EFAULT; 2657 } 2658 #endif /* _MULTI_DATAMODEL */ 2659 return (rval); 2660 } 2661 2662 /* 2663 * Function: cmlb_dkio_set_partition 2664 * 2665 * Description: This routine is the driver entry point for handling user 2666 * requests to set the partition table (DKIOCSAPART). The actual 2667 * device partition is not updated. 2668 * 2669 * Arguments: 2670 * arg - pointer to user provided dk_allmap structure used to set 2671 * the controller's notion of the partition table. 2672 * flag - this argument is a pass through to ddi_copyxxx() 2673 * directly from the mode argument of ioctl(). 2674 * 2675 * Return Code: 0 2676 * EINVAL 2677 * EFAULT 2678 * ENXIO 2679 * EIO 2680 */ 2681 static int 2682 cmlb_dkio_set_partition(struct cmlb_lun *un, caddr_t arg, int flag) 2683 { 2684 struct dk_map dk_map[NDKMAP]; 2685 struct dk_map *lp; 2686 int rval = 0; 2687 int size; 2688 int i; 2689 #if defined(_SUNOS_VTOC_16) 2690 struct dkl_partition *vp; 2691 #endif 2692 2693 /* 2694 * Set the map for all logical partitions. We lock 2695 * the priority just to make sure an interrupt doesn't 2696 * come in while the map is half updated. 2697 */ 2698 _NOTE(DATA_READABLE_WITHOUT_LOCK(cmlb_lun::un_solaris_size)) 2699 mutex_enter(CMLB_MUTEX(un)); 2700 2701 if (un->un_blockcount > DK_MAX_BLOCKS) { 2702 mutex_exit(CMLB_MUTEX(un)); 2703 return (ENOTSUP); 2704 } 2705 mutex_exit(CMLB_MUTEX(un)); 2706 if (un->un_solaris_size == 0) { 2707 return (EIO); 2708 } 2709 2710 #ifdef _MULTI_DATAMODEL 2711 switch (ddi_model_convert_from(flag & FMODELS)) { 2712 case DDI_MODEL_ILP32: { 2713 struct dk_map32 dk_map32[NDKMAP]; 2714 2715 size = NDKMAP * sizeof (struct dk_map32); 2716 rval = ddi_copyin((void *)arg, dk_map32, size, flag); 2717 if (rval != 0) { 2718 return (EFAULT); 2719 } 2720 for (i = 0; i < NDKMAP; i++) { 2721 dk_map[i].dkl_cylno = dk_map32[i].dkl_cylno; 2722 dk_map[i].dkl_nblk = dk_map32[i].dkl_nblk; 2723 } 2724 break; 2725 } 2726 case DDI_MODEL_NONE: 2727 size = NDKMAP * sizeof (struct dk_map); 2728 rval = ddi_copyin((void *)arg, dk_map, size, flag); 2729 if (rval != 0) { 2730 return (EFAULT); 2731 } 2732 break; 2733 } 2734 #else /* ! _MULTI_DATAMODEL */ 2735 size = NDKMAP * sizeof (struct dk_map); 2736 rval = ddi_copyin((void *)arg, dk_map, size, flag); 2737 if (rval != 0) { 2738 return (EFAULT); 2739 } 2740 #endif /* _MULTI_DATAMODEL */ 2741 2742 mutex_enter(CMLB_MUTEX(un)); 2743 /* Note: The size used in this bcopy is set based upon the data model */ 2744 bcopy(dk_map, un->un_map, size); 2745 #if defined(_SUNOS_VTOC_16) 2746 vp = (struct dkl_partition *)&(un->un_vtoc); 2747 #endif /* defined(_SUNOS_VTOC_16) */ 2748 for (i = 0; i < NDKMAP; i++) { 2749 lp = &un->un_map[i]; 2750 un->un_offset[i] = 2751 un->un_g.dkg_nhead * un->un_g.dkg_nsect * lp->dkl_cylno; 2752 #if defined(_SUNOS_VTOC_16) 2753 vp->p_start = un->un_offset[i]; 2754 vp->p_size = lp->dkl_nblk; 2755 vp++; 2756 #endif /* defined(_SUNOS_VTOC_16) */ 2757 #if defined(__i386) || defined(__amd64) 2758 un->un_offset[i] += un->un_solaris_offset; 2759 #endif 2760 } 2761 mutex_exit(CMLB_MUTEX(un)); 2762 return (rval); 2763 } 2764 2765 2766 /* 2767 * Function: cmlb_dkio_get_vtoc 2768 * 2769 * Description: This routine is the driver entry point for handling user 2770 * requests to get the current volume table of contents 2771 * (DKIOCGVTOC). 2772 * 2773 * Arguments: 2774 * arg - pointer to user provided vtoc structure specifying 2775 * the current vtoc. 2776 * flag - this argument is a pass through to ddi_copyxxx() 2777 * directly from the mode argument of ioctl(). 2778 * 2779 * Return Code: 0 2780 * EFAULT 2781 * ENXIO 2782 * EIO 2783 */ 2784 static int 2785 cmlb_dkio_get_vtoc(struct cmlb_lun *un, caddr_t arg, int flag) 2786 { 2787 #if defined(_SUNOS_VTOC_8) 2788 struct vtoc user_vtoc; 2789 #endif /* defined(_SUNOS_VTOC_8) */ 2790 int rval = 0; 2791 2792 mutex_enter(CMLB_MUTEX(un)); 2793 rval = cmlb_validate_geometry(un, 1); 2794 2795 #if defined(_SUNOS_VTOC_8) 2796 if (rval == EINVAL && 2797 (un->un_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8)) { 2798 /* 2799 * This is to return a default label even when we do not 2800 * really assume a default label for the device. 2801 * dad driver utilizes this. 2802 */ 2803 if (un->un_blockcount <= DK_MAX_BLOCKS) { 2804 cmlb_setup_default_geometry(un); 2805 rval = 0; 2806 } 2807 } 2808 #endif 2809 if (rval) { 2810 mutex_exit(CMLB_MUTEX(un)); 2811 return (rval); 2812 } 2813 2814 #if defined(_SUNOS_VTOC_8) 2815 cmlb_build_user_vtoc(un, &user_vtoc); 2816 mutex_exit(CMLB_MUTEX(un)); 2817 2818 #ifdef _MULTI_DATAMODEL 2819 switch (ddi_model_convert_from(flag & FMODELS)) { 2820 case DDI_MODEL_ILP32: { 2821 struct vtoc32 user_vtoc32; 2822 2823 vtoctovtoc32(user_vtoc, user_vtoc32); 2824 if (ddi_copyout(&user_vtoc32, (void *)arg, 2825 sizeof (struct vtoc32), flag)) { 2826 return (EFAULT); 2827 } 2828 break; 2829 } 2830 2831 case DDI_MODEL_NONE: 2832 if (ddi_copyout(&user_vtoc, (void *)arg, 2833 sizeof (struct vtoc), flag)) { 2834 return (EFAULT); 2835 } 2836 break; 2837 } 2838 #else /* ! _MULTI_DATAMODEL */ 2839 if (ddi_copyout(&user_vtoc, (void *)arg, sizeof (struct vtoc), flag)) { 2840 return (EFAULT); 2841 } 2842 #endif /* _MULTI_DATAMODEL */ 2843 2844 #elif defined(_SUNOS_VTOC_16) 2845 mutex_exit(CMLB_MUTEX(un)); 2846 2847 #ifdef _MULTI_DATAMODEL 2848 /* 2849 * The un_vtoc structure is a "struct dk_vtoc" which is always 2850 * 32-bit to maintain compatibility with existing on-disk 2851 * structures. Thus, we need to convert the structure when copying 2852 * it out to a datamodel-dependent "struct vtoc" in a 64-bit 2853 * program. If the target is a 32-bit program, then no conversion 2854 * is necessary. 2855 */ 2856 /* LINTED: logical expression always true: op "||" */ 2857 ASSERT(sizeof (un->un_vtoc) == sizeof (struct vtoc32)); 2858 switch (ddi_model_convert_from(flag & FMODELS)) { 2859 case DDI_MODEL_ILP32: 2860 if (ddi_copyout(&(un->un_vtoc), (void *)arg, 2861 sizeof (un->un_vtoc), flag)) { 2862 return (EFAULT); 2863 } 2864 break; 2865 2866 case DDI_MODEL_NONE: { 2867 struct vtoc user_vtoc; 2868 2869 vtoc32tovtoc(un->un_vtoc, user_vtoc); 2870 if (ddi_copyout(&user_vtoc, (void *)arg, 2871 sizeof (struct vtoc), flag)) { 2872 return (EFAULT); 2873 } 2874 break; 2875 } 2876 } 2877 #else /* ! _MULTI_DATAMODEL */ 2878 if (ddi_copyout(&(un->un_vtoc), (void *)arg, sizeof (un->un_vtoc), 2879 flag)) { 2880 return (EFAULT); 2881 } 2882 #endif /* _MULTI_DATAMODEL */ 2883 #else 2884 #error "No VTOC format defined." 2885 #endif 2886 2887 return (rval); 2888 } 2889 2890 static int 2891 cmlb_dkio_get_efi(struct cmlb_lun *un, caddr_t arg, int flag) 2892 { 2893 dk_efi_t user_efi; 2894 int rval = 0; 2895 void *buffer; 2896 2897 if (ddi_copyin(arg, &user_efi, sizeof (dk_efi_t), flag)) 2898 return (EFAULT); 2899 2900 user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64; 2901 2902 buffer = kmem_alloc(user_efi.dki_length, KM_SLEEP); 2903 rval = DK_TG_READ(un, buffer, user_efi.dki_lba, user_efi.dki_length); 2904 if (rval == 0 && ddi_copyout(buffer, user_efi.dki_data, 2905 user_efi.dki_length, flag) != 0) 2906 rval = EFAULT; 2907 2908 kmem_free(buffer, user_efi.dki_length); 2909 return (rval); 2910 } 2911 2912 /* 2913 * Function: cmlb_build_user_vtoc 2914 * 2915 * Description: This routine populates a pass by reference variable with the 2916 * current volume table of contents. 2917 * 2918 * Arguments: un - driver soft state (unit) structure 2919 * user_vtoc - pointer to vtoc structure to be populated 2920 */ 2921 static void 2922 cmlb_build_user_vtoc(struct cmlb_lun *un, struct vtoc *user_vtoc) 2923 { 2924 struct dk_map2 *lpart; 2925 struct dk_map *lmap; 2926 struct partition *vpart; 2927 int nblks; 2928 int i; 2929 2930 ASSERT(mutex_owned(CMLB_MUTEX(un))); 2931 2932 /* 2933 * Return vtoc structure fields in the provided VTOC area, addressed 2934 * by *vtoc. 2935 */ 2936 bzero(user_vtoc, sizeof (struct vtoc)); 2937 user_vtoc->v_bootinfo[0] = un->un_vtoc.v_bootinfo[0]; 2938 user_vtoc->v_bootinfo[1] = un->un_vtoc.v_bootinfo[1]; 2939 user_vtoc->v_bootinfo[2] = un->un_vtoc.v_bootinfo[2]; 2940 user_vtoc->v_sanity = VTOC_SANE; 2941 user_vtoc->v_version = un->un_vtoc.v_version; 2942 bcopy(un->un_vtoc.v_volume, user_vtoc->v_volume, LEN_DKL_VVOL); 2943 user_vtoc->v_sectorsz = un->un_sys_blocksize; 2944 user_vtoc->v_nparts = un->un_vtoc.v_nparts; 2945 2946 for (i = 0; i < 10; i++) 2947 user_vtoc->v_reserved[i] = un->un_vtoc.v_reserved[i]; 2948 2949 /* 2950 * Convert partitioning information. 2951 * 2952 * Note the conversion from starting cylinder number 2953 * to starting sector number. 2954 */ 2955 lmap = un->un_map; 2956 lpart = (struct dk_map2 *)un->un_vtoc.v_part; 2957 vpart = user_vtoc->v_part; 2958 2959 nblks = un->un_g.dkg_nsect * un->un_g.dkg_nhead; 2960 2961 for (i = 0; i < V_NUMPAR; i++) { 2962 vpart->p_tag = lpart->p_tag; 2963 vpart->p_flag = lpart->p_flag; 2964 vpart->p_start = lmap->dkl_cylno * nblks; 2965 vpart->p_size = lmap->dkl_nblk; 2966 lmap++; 2967 lpart++; 2968 vpart++; 2969 2970 /* (4364927) */ 2971 user_vtoc->timestamp[i] = (time_t)un->un_vtoc.v_timestamp[i]; 2972 } 2973 2974 bcopy(un->un_asciilabel, user_vtoc->v_asciilabel, LEN_DKL_ASCII); 2975 } 2976 2977 static int 2978 cmlb_dkio_partition(struct cmlb_lun *un, caddr_t arg, int flag) 2979 { 2980 struct partition64 p64; 2981 int rval = 0; 2982 uint_t nparts; 2983 efi_gpe_t *partitions; 2984 efi_gpt_t *buffer; 2985 diskaddr_t gpe_lba; 2986 2987 if (ddi_copyin((const void *)arg, &p64, 2988 sizeof (struct partition64), flag)) { 2989 return (EFAULT); 2990 } 2991 2992 buffer = kmem_alloc(EFI_MIN_ARRAY_SIZE, KM_SLEEP); 2993 rval = DK_TG_READ(un, buffer, 1, DEV_BSIZE); 2994 if (rval != 0) 2995 goto done_error; 2996 2997 cmlb_swap_efi_gpt(buffer); 2998 2999 if ((rval = cmlb_validate_efi(buffer)) != 0) 3000 goto done_error; 3001 3002 nparts = buffer->efi_gpt_NumberOfPartitionEntries; 3003 gpe_lba = buffer->efi_gpt_PartitionEntryLBA; 3004 if (p64.p_partno > nparts) { 3005 /* couldn't find it */ 3006 rval = ESRCH; 3007 goto done_error; 3008 } 3009 /* 3010 * if we're dealing with a partition that's out of the normal 3011 * 16K block, adjust accordingly 3012 */ 3013 gpe_lba += p64.p_partno / sizeof (efi_gpe_t); 3014 rval = DK_TG_READ(un, buffer, gpe_lba, EFI_MIN_ARRAY_SIZE); 3015 3016 if (rval) { 3017 goto done_error; 3018 } 3019 partitions = (efi_gpe_t *)buffer; 3020 3021 cmlb_swap_efi_gpe(nparts, partitions); 3022 3023 partitions += p64.p_partno; 3024 bcopy(&partitions->efi_gpe_PartitionTypeGUID, &p64.p_type, 3025 sizeof (struct uuid)); 3026 p64.p_start = partitions->efi_gpe_StartingLBA; 3027 p64.p_size = partitions->efi_gpe_EndingLBA - 3028 p64.p_start + 1; 3029 3030 if (ddi_copyout(&p64, (void *)arg, sizeof (struct partition64), flag)) 3031 rval = EFAULT; 3032 3033 done_error: 3034 kmem_free(buffer, EFI_MIN_ARRAY_SIZE); 3035 return (rval); 3036 } 3037 3038 3039 /* 3040 * Function: cmlb_dkio_set_vtoc 3041 * 3042 * Description: This routine is the driver entry point for handling user 3043 * requests to set the current volume table of contents 3044 * (DKIOCSVTOC). 3045 * 3046 * Arguments: dev - the device number 3047 * arg - pointer to user provided vtoc structure used to set the 3048 * current vtoc. 3049 * flag - this argument is a pass through to ddi_copyxxx() 3050 * directly from the mode argument of ioctl(). 3051 * 3052 * Return Code: 0 3053 * EFAULT 3054 * ENXIO 3055 * EINVAL 3056 * ENOTSUP 3057 */ 3058 static int 3059 cmlb_dkio_set_vtoc(struct cmlb_lun *un, dev_t dev, caddr_t arg, int flag) 3060 { 3061 struct vtoc user_vtoc; 3062 int rval = 0; 3063 3064 #ifdef _MULTI_DATAMODEL 3065 switch (ddi_model_convert_from(flag & FMODELS)) { 3066 case DDI_MODEL_ILP32: { 3067 struct vtoc32 user_vtoc32; 3068 3069 if (ddi_copyin((const void *)arg, &user_vtoc32, 3070 sizeof (struct vtoc32), flag)) { 3071 return (EFAULT); 3072 } 3073 vtoc32tovtoc(user_vtoc32, user_vtoc); 3074 break; 3075 } 3076 3077 case DDI_MODEL_NONE: 3078 if (ddi_copyin((const void *)arg, &user_vtoc, 3079 sizeof (struct vtoc), flag)) { 3080 return (EFAULT); 3081 } 3082 break; 3083 } 3084 #else /* ! _MULTI_DATAMODEL */ 3085 if (ddi_copyin((const void *)arg, &user_vtoc, 3086 sizeof (struct vtoc), flag)) { 3087 return (EFAULT); 3088 } 3089 #endif /* _MULTI_DATAMODEL */ 3090 3091 mutex_enter(CMLB_MUTEX(un)); 3092 if (un->un_blockcount > DK_MAX_BLOCKS) { 3093 mutex_exit(CMLB_MUTEX(un)); 3094 return (ENOTSUP); 3095 } 3096 if (un->un_g.dkg_ncyl == 0) { 3097 mutex_exit(CMLB_MUTEX(un)); 3098 return (EINVAL); 3099 } 3100 3101 mutex_exit(CMLB_MUTEX(un)); 3102 cmlb_clear_efi(un); 3103 ddi_remove_minor_node(CMLB_DEVINFO(un), "wd"); 3104 ddi_remove_minor_node(CMLB_DEVINFO(un), "wd,raw"); 3105 (void) ddi_create_minor_node(CMLB_DEVINFO(un), "h", 3106 S_IFBLK, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 3107 un->un_node_type, NULL); 3108 (void) ddi_create_minor_node(CMLB_DEVINFO(un), "h,raw", 3109 S_IFCHR, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 3110 un->un_node_type, NULL); 3111 mutex_enter(CMLB_MUTEX(un)); 3112 3113 if ((rval = cmlb_build_label_vtoc(un, &user_vtoc)) == 0) { 3114 if ((rval = cmlb_write_label(un)) == 0) { 3115 if (cmlb_validate_geometry(un, 1) != 0) { 3116 cmlb_dbg(CMLB_ERROR, un, 3117 "cmlb_dkio_set_vtoc: " 3118 "Failed validate geometry\n"); 3119 } 3120 } 3121 } 3122 mutex_exit(CMLB_MUTEX(un)); 3123 return (rval); 3124 } 3125 3126 3127 /* 3128 * Function: cmlb_build_label_vtoc 3129 * 3130 * Description: This routine updates the driver soft state current volume table 3131 * of contents based on a user specified vtoc. 3132 * 3133 * Arguments: un - driver soft state (unit) structure 3134 * user_vtoc - pointer to vtoc structure specifying vtoc to be used 3135 * to update the driver soft state. 3136 * 3137 * Return Code: 0 3138 * EINVAL 3139 */ 3140 static int 3141 cmlb_build_label_vtoc(struct cmlb_lun *un, struct vtoc *user_vtoc) 3142 { 3143 struct dk_map *lmap; 3144 struct partition *vpart; 3145 int nblks; 3146 #if defined(_SUNOS_VTOC_8) 3147 int ncyl; 3148 struct dk_map2 *lpart; 3149 #endif /* defined(_SUNOS_VTOC_8) */ 3150 int i; 3151 3152 ASSERT(mutex_owned(CMLB_MUTEX(un))); 3153 3154 /* Sanity-check the vtoc */ 3155 if (user_vtoc->v_sanity != VTOC_SANE || 3156 user_vtoc->v_sectorsz != un->un_sys_blocksize || 3157 user_vtoc->v_nparts != V_NUMPAR) { 3158 cmlb_dbg(CMLB_INFO, un, 3159 "cmlb_build_label_vtoc: vtoc not valid\n"); 3160 return (EINVAL); 3161 } 3162 3163 nblks = un->un_g.dkg_nsect * un->un_g.dkg_nhead; 3164 if (nblks == 0) { 3165 cmlb_dbg(CMLB_INFO, un, 3166 "cmlb_build_label_vtoc: geom nblks is 0\n"); 3167 return (EINVAL); 3168 } 3169 3170 #if defined(_SUNOS_VTOC_8) 3171 vpart = user_vtoc->v_part; 3172 for (i = 0; i < V_NUMPAR; i++) { 3173 if ((vpart->p_start % nblks) != 0) { 3174 cmlb_dbg(CMLB_INFO, un, 3175 "cmlb_build_label_vtoc: p_start not multiply of" 3176 "nblks part %d p_start %d nblks %d\n", i, 3177 vpart->p_start, nblks); 3178 return (EINVAL); 3179 } 3180 ncyl = vpart->p_start / nblks; 3181 ncyl += vpart->p_size / nblks; 3182 if ((vpart->p_size % nblks) != 0) { 3183 ncyl++; 3184 } 3185 if (ncyl > (int)un->un_g.dkg_ncyl) { 3186 cmlb_dbg(CMLB_INFO, un, 3187 "cmlb_build_label_vtoc: ncyl %d > dkg_ncyl %d" 3188 "p_size %ld p_start %ld nblks %d part number %d" 3189 "tag %d\n", 3190 ncyl, un->un_g.dkg_ncyl, vpart->p_size, 3191 vpart->p_start, nblks, 3192 i, vpart->p_tag); 3193 3194 return (EINVAL); 3195 } 3196 vpart++; 3197 } 3198 #endif /* defined(_SUNOS_VTOC_8) */ 3199 3200 /* Put appropriate vtoc structure fields into the disk label */ 3201 #if defined(_SUNOS_VTOC_16) 3202 /* 3203 * The vtoc is always a 32bit data structure to maintain the 3204 * on-disk format. Convert "in place" instead of doing bcopy. 3205 */ 3206 vtoctovtoc32((*user_vtoc), (*((struct vtoc32 *)&(un->un_vtoc)))); 3207 3208 /* 3209 * in the 16-slice vtoc, starting sectors are expressed in 3210 * numbers *relative* to the start of the Solaris fdisk partition. 3211 */ 3212 lmap = un->un_map; 3213 vpart = user_vtoc->v_part; 3214 3215 for (i = 0; i < (int)user_vtoc->v_nparts; i++, lmap++, vpart++) { 3216 lmap->dkl_cylno = vpart->p_start / nblks; 3217 lmap->dkl_nblk = vpart->p_size; 3218 } 3219 3220 #elif defined(_SUNOS_VTOC_8) 3221 3222 un->un_vtoc.v_bootinfo[0] = (uint32_t)user_vtoc->v_bootinfo[0]; 3223 un->un_vtoc.v_bootinfo[1] = (uint32_t)user_vtoc->v_bootinfo[1]; 3224 un->un_vtoc.v_bootinfo[2] = (uint32_t)user_vtoc->v_bootinfo[2]; 3225 3226 un->un_vtoc.v_sanity = (uint32_t)user_vtoc->v_sanity; 3227 un->un_vtoc.v_version = (uint32_t)user_vtoc->v_version; 3228 3229 bcopy(user_vtoc->v_volume, un->un_vtoc.v_volume, LEN_DKL_VVOL); 3230 3231 un->un_vtoc.v_nparts = user_vtoc->v_nparts; 3232 3233 for (i = 0; i < 10; i++) 3234 un->un_vtoc.v_reserved[i] = user_vtoc->v_reserved[i]; 3235 3236 /* 3237 * Note the conversion from starting sector number 3238 * to starting cylinder number. 3239 * Return error if division results in a remainder. 3240 */ 3241 lmap = un->un_map; 3242 lpart = un->un_vtoc.v_part; 3243 vpart = user_vtoc->v_part; 3244 3245 for (i = 0; i < (int)user_vtoc->v_nparts; i++) { 3246 lpart->p_tag = vpart->p_tag; 3247 lpart->p_flag = vpart->p_flag; 3248 lmap->dkl_cylno = vpart->p_start / nblks; 3249 lmap->dkl_nblk = vpart->p_size; 3250 3251 lmap++; 3252 lpart++; 3253 vpart++; 3254 3255 /* (4387723) */ 3256 #ifdef _LP64 3257 if (user_vtoc->timestamp[i] > TIME32_MAX) { 3258 un->un_vtoc.v_timestamp[i] = TIME32_MAX; 3259 } else { 3260 un->un_vtoc.v_timestamp[i] = user_vtoc->timestamp[i]; 3261 } 3262 #else 3263 un->un_vtoc.v_timestamp[i] = user_vtoc->timestamp[i]; 3264 #endif 3265 } 3266 3267 bcopy(user_vtoc->v_asciilabel, un->un_asciilabel, LEN_DKL_ASCII); 3268 #else 3269 #error "No VTOC format defined." 3270 #endif 3271 return (0); 3272 } 3273 3274 /* 3275 * Function: cmlb_clear_efi 3276 * 3277 * Description: This routine clears all EFI labels. 3278 * 3279 * Arguments: un - driver soft state (unit) structure 3280 * 3281 * Return Code: void 3282 */ 3283 static void 3284 cmlb_clear_efi(struct cmlb_lun *un) 3285 { 3286 efi_gpt_t *gpt; 3287 diskaddr_t cap; 3288 int rval; 3289 3290 ASSERT(!mutex_owned(CMLB_MUTEX(un))); 3291 3292 gpt = kmem_alloc(sizeof (efi_gpt_t), KM_SLEEP); 3293 3294 if (DK_TG_READ(un, gpt, 1, DEV_BSIZE) != 0) { 3295 goto done; 3296 } 3297 3298 cmlb_swap_efi_gpt(gpt); 3299 rval = cmlb_validate_efi(gpt); 3300 if (rval == 0) { 3301 /* clear primary */ 3302 bzero(gpt, sizeof (efi_gpt_t)); 3303 if (rval = DK_TG_WRITE(un, gpt, 1, EFI_LABEL_SIZE)) { 3304 cmlb_dbg(CMLB_INFO, un, 3305 "cmlb_clear_efi: clear primary label failed\n"); 3306 } 3307 } 3308 /* the backup */ 3309 rval = DK_TG_GETCAP(un, &cap); 3310 if (rval) { 3311 goto done; 3312 } 3313 3314 if ((rval = DK_TG_READ(un, gpt, cap - 1, EFI_LABEL_SIZE)) != 0) { 3315 goto done; 3316 } 3317 cmlb_swap_efi_gpt(gpt); 3318 rval = cmlb_validate_efi(gpt); 3319 if (rval == 0) { 3320 /* clear backup */ 3321 cmlb_dbg(CMLB_TRACE, un, 3322 "cmlb_clear_efi clear backup@%lu\n", cap - 1); 3323 bzero(gpt, sizeof (efi_gpt_t)); 3324 if ((rval = DK_TG_WRITE(un, gpt, cap - 1, EFI_LABEL_SIZE))) { 3325 cmlb_dbg(CMLB_INFO, un, 3326 "cmlb_clear_efi: clear backup label failed\n"); 3327 } 3328 } 3329 3330 done: 3331 kmem_free(gpt, sizeof (efi_gpt_t)); 3332 } 3333 3334 /* 3335 * Function: cmlb_set_vtoc 3336 * 3337 * Description: This routine writes data to the appropriate positions 3338 * 3339 * Arguments: un - driver soft state (unit) structure 3340 * dkl - the data to be written 3341 * 3342 * Return: void 3343 */ 3344 static int 3345 cmlb_set_vtoc(struct cmlb_lun *un, struct dk_label *dkl) 3346 { 3347 uint_t label_addr; 3348 int sec; 3349 int blk; 3350 int head; 3351 int cyl; 3352 int rval; 3353 3354 #if defined(__i386) || defined(__amd64) 3355 label_addr = un->un_solaris_offset + DK_LABEL_LOC; 3356 #else 3357 /* Write the primary label at block 0 of the solaris partition. */ 3358 label_addr = 0; 3359 #endif 3360 3361 rval = DK_TG_WRITE(un, dkl, label_addr, un->un_sys_blocksize); 3362 3363 if (rval != 0) { 3364 return (rval); 3365 } 3366 3367 /* 3368 * Calculate where the backup labels go. They are always on 3369 * the last alternate cylinder, but some older drives put them 3370 * on head 2 instead of the last head. They are always on the 3371 * first 5 odd sectors of the appropriate track. 3372 * 3373 * We have no choice at this point, but to believe that the 3374 * disk label is valid. Use the geometry of the disk 3375 * as described in the label. 3376 */ 3377 cyl = dkl->dkl_ncyl + dkl->dkl_acyl - 1; 3378 head = dkl->dkl_nhead - 1; 3379 3380 /* 3381 * Write and verify the backup labels. Make sure we don't try to 3382 * write past the last cylinder. 3383 */ 3384 for (sec = 1; ((sec < 5 * 2 + 1) && (sec < dkl->dkl_nsect)); sec += 2) { 3385 blk = (daddr_t)( 3386 (cyl * ((dkl->dkl_nhead * dkl->dkl_nsect) - dkl->dkl_apc)) + 3387 (head * dkl->dkl_nsect) + sec); 3388 #if defined(__i386) || defined(__amd64) 3389 blk += un->un_solaris_offset; 3390 #endif 3391 rval = DK_TG_WRITE(un, dkl, blk, un->un_sys_blocksize); 3392 cmlb_dbg(CMLB_INFO, un, 3393 "cmlb_set_vtoc: wrote backup label %d\n", blk); 3394 if (rval != 0) { 3395 goto exit; 3396 } 3397 } 3398 exit: 3399 return (rval); 3400 } 3401 3402 /* 3403 * Function: cmlb_clear_vtoc 3404 * 3405 * Description: This routine clears out the VTOC labels. 3406 * 3407 * Arguments: un - driver soft state (unit) structure 3408 * 3409 * Return: void 3410 */ 3411 static void 3412 cmlb_clear_vtoc(struct cmlb_lun *un) 3413 { 3414 struct dk_label *dkl; 3415 3416 mutex_exit(CMLB_MUTEX(un)); 3417 dkl = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP); 3418 mutex_enter(CMLB_MUTEX(un)); 3419 /* 3420 * cmlb_set_vtoc uses these fields in order to figure out 3421 * where to overwrite the backup labels 3422 */ 3423 dkl->dkl_apc = un->un_g.dkg_apc; 3424 dkl->dkl_ncyl = un->un_g.dkg_ncyl; 3425 dkl->dkl_acyl = un->un_g.dkg_acyl; 3426 dkl->dkl_nhead = un->un_g.dkg_nhead; 3427 dkl->dkl_nsect = un->un_g.dkg_nsect; 3428 mutex_exit(CMLB_MUTEX(un)); 3429 (void) cmlb_set_vtoc(un, dkl); 3430 kmem_free(dkl, sizeof (struct dk_label)); 3431 3432 mutex_enter(CMLB_MUTEX(un)); 3433 } 3434 3435 /* 3436 * Function: cmlb_write_label 3437 * 3438 * Description: This routine will validate and write the driver soft state vtoc 3439 * contents to the device. 3440 * 3441 * Arguments: un cmlb handle 3442 * 3443 * Return Code: the code returned by cmlb_send_scsi_cmd() 3444 * 0 3445 * EINVAL 3446 * ENXIO 3447 * ENOMEM 3448 */ 3449 static int 3450 cmlb_write_label(struct cmlb_lun *un) 3451 { 3452 struct dk_label *dkl; 3453 short sum; 3454 short *sp; 3455 int i; 3456 int rval; 3457 3458 ASSERT(mutex_owned(CMLB_MUTEX(un))); 3459 mutex_exit(CMLB_MUTEX(un)); 3460 dkl = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP); 3461 mutex_enter(CMLB_MUTEX(un)); 3462 3463 bcopy(&un->un_vtoc, &dkl->dkl_vtoc, sizeof (struct dk_vtoc)); 3464 dkl->dkl_rpm = un->un_g.dkg_rpm; 3465 dkl->dkl_pcyl = un->un_g.dkg_pcyl; 3466 dkl->dkl_apc = un->un_g.dkg_apc; 3467 dkl->dkl_intrlv = un->un_g.dkg_intrlv; 3468 dkl->dkl_ncyl = un->un_g.dkg_ncyl; 3469 dkl->dkl_acyl = un->un_g.dkg_acyl; 3470 dkl->dkl_nhead = un->un_g.dkg_nhead; 3471 dkl->dkl_nsect = un->un_g.dkg_nsect; 3472 3473 #if defined(_SUNOS_VTOC_8) 3474 dkl->dkl_obs1 = un->un_g.dkg_obs1; 3475 dkl->dkl_obs2 = un->un_g.dkg_obs2; 3476 dkl->dkl_obs3 = un->un_g.dkg_obs3; 3477 for (i = 0; i < NDKMAP; i++) { 3478 dkl->dkl_map[i].dkl_cylno = un->un_map[i].dkl_cylno; 3479 dkl->dkl_map[i].dkl_nblk = un->un_map[i].dkl_nblk; 3480 } 3481 bcopy(un->un_asciilabel, dkl->dkl_asciilabel, LEN_DKL_ASCII); 3482 #elif defined(_SUNOS_VTOC_16) 3483 dkl->dkl_skew = un->un_dkg_skew; 3484 #else 3485 #error "No VTOC format defined." 3486 #endif 3487 3488 dkl->dkl_magic = DKL_MAGIC; 3489 dkl->dkl_write_reinstruct = un->un_g.dkg_write_reinstruct; 3490 dkl->dkl_read_reinstruct = un->un_g.dkg_read_reinstruct; 3491 3492 /* Construct checksum for the new disk label */ 3493 sum = 0; 3494 sp = (short *)dkl; 3495 i = sizeof (struct dk_label) / sizeof (short); 3496 while (i--) { 3497 sum ^= *sp++; 3498 } 3499 dkl->dkl_cksum = sum; 3500 3501 mutex_exit(CMLB_MUTEX(un)); 3502 3503 rval = cmlb_set_vtoc(un, dkl); 3504 exit: 3505 kmem_free(dkl, sizeof (struct dk_label)); 3506 mutex_enter(CMLB_MUTEX(un)); 3507 return (rval); 3508 } 3509 3510 static int 3511 cmlb_dkio_set_efi(struct cmlb_lun *un, dev_t dev, caddr_t arg, int flag) 3512 { 3513 dk_efi_t user_efi; 3514 int rval = 0; 3515 void *buffer; 3516 3517 if (ddi_copyin(arg, &user_efi, sizeof (dk_efi_t), flag)) 3518 return (EFAULT); 3519 3520 user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64; 3521 3522 buffer = kmem_alloc(user_efi.dki_length, KM_SLEEP); 3523 if (ddi_copyin(user_efi.dki_data, buffer, user_efi.dki_length, flag)) { 3524 rval = EFAULT; 3525 } else { 3526 /* 3527 * let's clear the vtoc labels and clear the softstate 3528 * vtoc. 3529 */ 3530 mutex_enter(CMLB_MUTEX(un)); 3531 if (un->un_vtoc.v_sanity == VTOC_SANE) { 3532 cmlb_dbg(CMLB_TRACE, un, 3533 "cmlb_dkio_set_efi: CLEAR VTOC\n"); 3534 if (un->un_vtoc_label_is_from_media) 3535 cmlb_clear_vtoc(un); 3536 bzero(&un->un_vtoc, sizeof (struct dk_vtoc)); 3537 mutex_exit(CMLB_MUTEX(un)); 3538 ddi_remove_minor_node(CMLB_DEVINFO(un), "h"); 3539 ddi_remove_minor_node(CMLB_DEVINFO(un), "h,raw"); 3540 (void) ddi_create_minor_node(CMLB_DEVINFO(un), "wd", 3541 S_IFBLK, 3542 (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 3543 un->un_node_type, NULL); 3544 (void) ddi_create_minor_node(CMLB_DEVINFO(un), "wd,raw", 3545 S_IFCHR, 3546 (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 3547 un->un_node_type, NULL); 3548 } else 3549 mutex_exit(CMLB_MUTEX(un)); 3550 rval = DK_TG_WRITE(un, buffer, user_efi.dki_lba, 3551 user_efi.dki_length); 3552 if (rval == 0) { 3553 mutex_enter(CMLB_MUTEX(un)); 3554 un->un_f_geometry_is_valid = FALSE; 3555 mutex_exit(CMLB_MUTEX(un)); 3556 } 3557 } 3558 kmem_free(buffer, user_efi.dki_length); 3559 return (rval); 3560 } 3561 3562 /* 3563 * Function: cmlb_dkio_get_mboot 3564 * 3565 * Description: This routine is the driver entry point for handling user 3566 * requests to get the current device mboot (DKIOCGMBOOT) 3567 * 3568 * Arguments: 3569 * arg - pointer to user provided mboot structure specifying 3570 * the current mboot. 3571 * flag - this argument is a pass through to ddi_copyxxx() 3572 * directly from the mode argument of ioctl(). 3573 * 3574 * Return Code: 0 3575 * EINVAL 3576 * EFAULT 3577 * ENXIO 3578 */ 3579 static int 3580 cmlb_dkio_get_mboot(struct cmlb_lun *un, caddr_t arg, int flag) 3581 { 3582 struct mboot *mboot; 3583 int rval; 3584 size_t buffer_size; 3585 3586 3587 #if defined(_SUNOS_VTOC_8) 3588 if ((!ISREMOVABLE(un)) || (arg == NULL)) { 3589 #elif defined(_SUNOS_VTOC_16) 3590 if (arg == NULL) { 3591 #endif 3592 return (EINVAL); 3593 } 3594 3595 /* 3596 * Read the mboot block, located at absolute block 0 on the target. 3597 */ 3598 buffer_size = sizeof (struct mboot); 3599 3600 cmlb_dbg(CMLB_TRACE, un, 3601 "cmlb_dkio_get_mboot: allocation size: 0x%x\n", buffer_size); 3602 3603 mboot = kmem_zalloc(buffer_size, KM_SLEEP); 3604 if ((rval = DK_TG_READ(un, mboot, 0, buffer_size)) == 0) { 3605 if (ddi_copyout(mboot, (void *)arg, 3606 sizeof (struct mboot), flag) != 0) { 3607 rval = EFAULT; 3608 } 3609 } 3610 kmem_free(mboot, buffer_size); 3611 return (rval); 3612 } 3613 3614 3615 /* 3616 * Function: cmlb_dkio_set_mboot 3617 * 3618 * Description: This routine is the driver entry point for handling user 3619 * requests to validate and set the device master boot 3620 * (DKIOCSMBOOT). 3621 * 3622 * Arguments: 3623 * arg - pointer to user provided mboot structure used to set the 3624 * master boot. 3625 * flag - this argument is a pass through to ddi_copyxxx() 3626 * directly from the mode argument of ioctl(). 3627 * 3628 * Return Code: 0 3629 * EINVAL 3630 * EFAULT 3631 * ENXIO 3632 */ 3633 static int 3634 cmlb_dkio_set_mboot(struct cmlb_lun *un, caddr_t arg, int flag) 3635 { 3636 struct mboot *mboot = NULL; 3637 int rval; 3638 ushort_t magic; 3639 3640 3641 ASSERT(!mutex_owned(CMLB_MUTEX(un))); 3642 3643 #if defined(_SUNOS_VTOC_8) 3644 if (!ISREMOVABLE(un)) { 3645 return (EINVAL); 3646 } 3647 #endif 3648 3649 if (arg == NULL) { 3650 return (EINVAL); 3651 } 3652 3653 mboot = kmem_zalloc(sizeof (struct mboot), KM_SLEEP); 3654 3655 if (ddi_copyin((const void *)arg, mboot, 3656 sizeof (struct mboot), flag) != 0) { 3657 kmem_free(mboot, (size_t)(sizeof (struct mboot))); 3658 return (EFAULT); 3659 } 3660 3661 /* Is this really a master boot record? */ 3662 magic = LE_16(mboot->signature); 3663 if (magic != MBB_MAGIC) { 3664 kmem_free(mboot, (size_t)(sizeof (struct mboot))); 3665 return (EINVAL); 3666 } 3667 3668 rval = DK_TG_WRITE(un, mboot, 0, un->un_sys_blocksize); 3669 3670 mutex_enter(CMLB_MUTEX(un)); 3671 #if defined(__i386) || defined(__amd64) 3672 if (rval == 0) { 3673 /* 3674 * mboot has been written successfully. 3675 * update the fdisk and vtoc tables in memory 3676 */ 3677 rval = cmlb_update_fdisk_and_vtoc(un); 3678 if ((un->un_f_geometry_is_valid == FALSE) || (rval != 0)) { 3679 mutex_exit(CMLB_MUTEX(un)); 3680 kmem_free(mboot, (size_t)(sizeof (struct mboot))); 3681 return (rval); 3682 } 3683 } 3684 #else 3685 if (rval == 0) { 3686 /* 3687 * mboot has been written successfully. 3688 * set up the default geometry and VTOC 3689 */ 3690 if (un->un_blockcount <= DK_MAX_BLOCKS) 3691 cmlb_setup_default_geometry(un); 3692 } 3693 #endif 3694 mutex_exit(CMLB_MUTEX(un)); 3695 kmem_free(mboot, (size_t)(sizeof (struct mboot))); 3696 return (rval); 3697 } 3698 3699 3700 /* 3701 * Function: cmlb_setup_default_geometry 3702 * 3703 * Description: This local utility routine sets the default geometry as part of 3704 * setting the device mboot. 3705 * 3706 * Arguments: un - driver soft state (unit) structure 3707 * 3708 * Note: This may be redundant with cmlb_build_default_label. 3709 */ 3710 static void 3711 cmlb_setup_default_geometry(struct cmlb_lun *un) 3712 { 3713 struct cmlb_geom pgeom; 3714 struct cmlb_geom *pgeomp = &pgeom; 3715 int ret; 3716 int geom_base_cap = 1; 3717 3718 3719 ASSERT(mutex_owned(CMLB_MUTEX(un))); 3720 3721 /* zero out the soft state geometry and partition table. */ 3722 bzero(&un->un_g, sizeof (struct dk_geom)); 3723 bzero(&un->un_vtoc, sizeof (struct dk_vtoc)); 3724 bzero(un->un_map, NDKMAP * (sizeof (struct dk_map))); 3725 3726 /* 3727 * For the rpm, we use the minimum for the disk. 3728 * For the head, cyl and number of sector per track, 3729 * if the capacity <= 1GB, head = 64, sect = 32. 3730 * else head = 255, sect 63 3731 * Note: the capacity should be equal to C*H*S values. 3732 * This will cause some truncation of size due to 3733 * round off errors. For CD-ROMs, this truncation can 3734 * have adverse side effects, so returning ncyl and 3735 * nhead as 1. The nsect will overflow for most of 3736 * CD-ROMs as nsect is of type ushort. 3737 */ 3738 if (un->un_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8) { 3739 /* 3740 * newfs currently can not handle 255 ntracks for SPARC 3741 * so get the geometry from target driver instead of coming up 3742 * with one based on capacity. 3743 */ 3744 mutex_exit(CMLB_MUTEX(un)); 3745 ret = DK_TG_GETPHYGEOM(un, pgeomp); 3746 mutex_enter(CMLB_MUTEX(un)); 3747 3748 if (ret == 0) { 3749 geom_base_cap = 0; 3750 } else { 3751 cmlb_dbg(CMLB_ERROR, un, 3752 "cmlb_setup_default_geometry: " 3753 "tg_getphygeom failed %d\n", ret); 3754 3755 /* do default setting, geometry based on capacity */ 3756 } 3757 } 3758 3759 if (geom_base_cap) { 3760 if (ISCD(un)) { 3761 un->un_g.dkg_ncyl = 1; 3762 un->un_g.dkg_nhead = 1; 3763 un->un_g.dkg_nsect = un->un_blockcount; 3764 } else if (un->un_blockcount <= 0x1000) { 3765 /* Needed for unlabeled SCSI floppies. */ 3766 un->un_g.dkg_nhead = 2; 3767 un->un_g.dkg_ncyl = 80; 3768 un->un_g.dkg_pcyl = 80; 3769 un->un_g.dkg_nsect = un->un_blockcount / (2 * 80); 3770 } else if (un->un_blockcount <= 0x200000) { 3771 un->un_g.dkg_nhead = 64; 3772 un->un_g.dkg_nsect = 32; 3773 un->un_g.dkg_ncyl = un->un_blockcount / (64 * 32); 3774 } else { 3775 un->un_g.dkg_nhead = 255; 3776 un->un_g.dkg_nsect = 63; 3777 un->un_g.dkg_ncyl = un->un_blockcount / (255 * 63); 3778 } 3779 3780 un->un_g.dkg_acyl = 0; 3781 un->un_g.dkg_bcyl = 0; 3782 un->un_g.dkg_intrlv = 1; 3783 un->un_g.dkg_rpm = 200; 3784 if (un->un_g.dkg_pcyl == 0) 3785 un->un_g.dkg_pcyl = un->un_g.dkg_ncyl + 3786 un->un_g.dkg_acyl; 3787 } else { 3788 un->un_g.dkg_ncyl = (short)pgeomp->g_ncyl; 3789 un->un_g.dkg_acyl = pgeomp->g_acyl; 3790 un->un_g.dkg_nhead = pgeomp->g_nhead; 3791 un->un_g.dkg_nsect = pgeomp->g_nsect; 3792 un->un_g.dkg_intrlv = pgeomp->g_intrlv; 3793 un->un_g.dkg_rpm = pgeomp->g_rpm; 3794 un->un_g.dkg_pcyl = un->un_g.dkg_ncyl + un->un_g.dkg_acyl; 3795 } 3796 3797 un->un_g.dkg_read_reinstruct = 0; 3798 un->un_g.dkg_write_reinstruct = 0; 3799 un->un_solaris_size = un->un_g.dkg_ncyl * 3800 un->un_g.dkg_nhead * un->un_g.dkg_nsect; 3801 3802 un->un_map['a'-'a'].dkl_cylno = 0; 3803 un->un_map['a'-'a'].dkl_nblk = un->un_solaris_size; 3804 3805 un->un_map['c'-'a'].dkl_cylno = 0; 3806 un->un_map['c'-'a'].dkl_nblk = un->un_solaris_size; 3807 3808 un->un_vtoc.v_part[2].p_tag = V_BACKUP; 3809 un->un_vtoc.v_part[2].p_flag = V_UNMNT; 3810 un->un_vtoc.v_nparts = V_NUMPAR; 3811 un->un_vtoc.v_version = V_VERSION; 3812 (void) sprintf((char *)un->un_asciilabel, "DEFAULT cyl %d alt %d" 3813 " hd %d sec %d", un->un_g.dkg_ncyl, un->un_g.dkg_acyl, 3814 un->un_g.dkg_nhead, un->un_g.dkg_nsect); 3815 3816 un->un_f_geometry_is_valid = FALSE; 3817 } 3818 3819 3820 #if defined(__i386) || defined(__amd64) 3821 /* 3822 * Function: cmlb_update_fdisk_and_vtoc 3823 * 3824 * Description: This local utility routine updates the device fdisk and vtoc 3825 * as part of setting the device mboot. 3826 * 3827 * Arguments: un - driver soft state (unit) structure 3828 * 3829 * Return Code: 0 for success or errno-type return code. 3830 * 3831 * Note:x86: This looks like a duplicate of cmlb_validate_geometry(), but 3832 * these did exist separately in x86 sd.c. 3833 */ 3834 static int 3835 cmlb_update_fdisk_and_vtoc(struct cmlb_lun *un) 3836 { 3837 int count; 3838 int label_rc = 0; 3839 int fdisk_rval; 3840 diskaddr_t capacity; 3841 3842 ASSERT(mutex_owned(CMLB_MUTEX(un))); 3843 3844 if (cmlb_check_update_blockcount(un) != 0) 3845 return (EINVAL); 3846 3847 #if defined(_SUNOS_VTOC_16) 3848 /* 3849 * Set up the "whole disk" fdisk partition; this should always 3850 * exist, regardless of whether the disk contains an fdisk table 3851 * or vtoc. 3852 */ 3853 un->un_map[P0_RAW_DISK].dkl_cylno = 0; 3854 un->un_map[P0_RAW_DISK].dkl_nblk = un->un_blockcount; 3855 #endif /* defined(_SUNOS_VTOC_16) */ 3856 3857 /* 3858 * copy the lbasize and capacity so that if they're 3859 * reset while we're not holding the CMLB_MUTEX(un), we will 3860 * continue to use valid values after the CMLB_MUTEX(un) is 3861 * reacquired. 3862 */ 3863 capacity = un->un_blockcount; 3864 3865 /* 3866 * refresh the logical and physical geometry caches. 3867 * (data from mode sense format/rigid disk geometry pages, 3868 * and scsi_ifgetcap("geometry"). 3869 */ 3870 cmlb_resync_geom_caches(un, capacity); 3871 3872 /* 3873 * Only DIRECT ACCESS devices will have Sun labels. 3874 * CD's supposedly have a Sun label, too 3875 */ 3876 if (un->un_device_type == DTYPE_DIRECT || ISREMOVABLE(un)) { 3877 fdisk_rval = cmlb_read_fdisk(un, capacity); 3878 if (fdisk_rval != 0) { 3879 ASSERT(mutex_owned(CMLB_MUTEX(un))); 3880 return (fdisk_rval); 3881 } 3882 3883 if (un->un_solaris_size <= DK_LABEL_LOC) { 3884 /* 3885 * Found fdisk table but no Solaris partition entry, 3886 * so don't call cmlb_uselabel() and don't create 3887 * a default label. 3888 */ 3889 label_rc = 0; 3890 un->un_f_geometry_is_valid = TRUE; 3891 goto no_solaris_partition; 3892 } 3893 } else if (capacity < 0) { 3894 ASSERT(mutex_owned(CMLB_MUTEX(un))); 3895 return (EINVAL); 3896 } 3897 3898 /* 3899 * For Removable media We reach here if we have found a 3900 * SOLARIS PARTITION. 3901 * If un_f_geometry_is_valid is FALSE it indicates that the SOLARIS 3902 * PARTITION has changed from the previous one, hence we will setup a 3903 * default VTOC in this case. 3904 */ 3905 if (un->un_f_geometry_is_valid == FALSE) { 3906 /* if we get here it is writable */ 3907 /* we are called from SMBOOT, and after a write of fdisk */ 3908 cmlb_build_default_label(un); 3909 label_rc = 0; 3910 } 3911 3912 no_solaris_partition: 3913 3914 #if defined(_SUNOS_VTOC_16) 3915 /* 3916 * If we have valid geometry, set up the remaining fdisk partitions. 3917 * Note that dkl_cylno is not used for the fdisk map entries, so 3918 * we set it to an entirely bogus value. 3919 */ 3920 for (count = 0; count < FD_NUMPART; count++) { 3921 un->un_map[FDISK_P1 + count].dkl_cylno = -1; 3922 un->un_map[FDISK_P1 + count].dkl_nblk = 3923 un->un_fmap[count].fmap_nblk; 3924 un->un_offset[FDISK_P1 + count] = 3925 un->un_fmap[count].fmap_start; 3926 } 3927 #endif 3928 3929 for (count = 0; count < NDKMAP; count++) { 3930 #if defined(_SUNOS_VTOC_8) 3931 struct dk_map *lp = &un->un_map[count]; 3932 un->un_offset[count] = 3933 un->un_g.dkg_nhead * un->un_g.dkg_nsect * lp->dkl_cylno; 3934 #elif defined(_SUNOS_VTOC_16) 3935 struct dkl_partition *vp = &un->un_vtoc.v_part[count]; 3936 un->un_offset[count] = vp->p_start + un->un_solaris_offset; 3937 #else 3938 #error "No VTOC format defined." 3939 #endif 3940 } 3941 3942 ASSERT(mutex_owned(CMLB_MUTEX(un))); 3943 return (label_rc); 3944 } 3945 #endif 3946 3947 #if defined(__i386) || defined(__amd64) 3948 static int 3949 cmlb_dkio_get_virtgeom(struct cmlb_lun *un, caddr_t arg, int flag) 3950 { 3951 int err = 0; 3952 3953 /* Return the driver's notion of the media's logical geometry */ 3954 struct dk_geom disk_geom; 3955 struct dk_geom *dkgp = &disk_geom; 3956 3957 mutex_enter(CMLB_MUTEX(un)); 3958 /* 3959 * If there is no HBA geometry available, or 3960 * if the HBA returned us something that doesn't 3961 * really fit into an Int 13/function 8 geometry 3962 * result, just fail the ioctl. See PSARC 1998/313. 3963 */ 3964 if (un->un_lgeom.g_nhead == 0 || 3965 un->un_lgeom.g_nsect == 0 || 3966 un->un_lgeom.g_ncyl > 1024) { 3967 mutex_exit(CMLB_MUTEX(un)); 3968 err = EINVAL; 3969 } else { 3970 dkgp->dkg_ncyl = un->un_lgeom.g_ncyl; 3971 dkgp->dkg_acyl = un->un_lgeom.g_acyl; 3972 dkgp->dkg_pcyl = dkgp->dkg_ncyl + dkgp->dkg_acyl; 3973 dkgp->dkg_nhead = un->un_lgeom.g_nhead; 3974 dkgp->dkg_nsect = un->un_lgeom.g_nsect; 3975 3976 if (ddi_copyout(dkgp, (void *)arg, 3977 sizeof (struct dk_geom), flag)) { 3978 mutex_exit(CMLB_MUTEX(un)); 3979 err = EFAULT; 3980 } else { 3981 mutex_exit(CMLB_MUTEX(un)); 3982 err = 0; 3983 } 3984 } 3985 return (err); 3986 } 3987 #endif 3988 3989 #if defined(__i386) || defined(__amd64) 3990 static int 3991 cmlb_dkio_get_phygeom(struct cmlb_lun *un, caddr_t arg, int flag) 3992 { 3993 int err = 0; 3994 3995 3996 /* Return the driver's notion of the media physical geometry */ 3997 struct dk_geom disk_geom; 3998 struct dk_geom *dkgp = &disk_geom; 3999 4000 mutex_enter(CMLB_MUTEX(un)); 4001 4002 if (un->un_g.dkg_nhead != 0 && 4003 un->un_g.dkg_nsect != 0) { 4004 /* 4005 * We succeeded in getting a geometry, but 4006 * right now it is being reported as just the 4007 * Solaris fdisk partition, just like for 4008 * DKIOCGGEOM. We need to change that to be 4009 * correct for the entire disk now. 4010 */ 4011 bcopy(&un->un_g, dkgp, sizeof (*dkgp)); 4012 dkgp->dkg_acyl = 0; 4013 dkgp->dkg_ncyl = un->un_blockcount / 4014 (dkgp->dkg_nhead * dkgp->dkg_nsect); 4015 } else { 4016 bzero(dkgp, sizeof (struct dk_geom)); 4017 /* 4018 * This disk does not have a Solaris VTOC 4019 * so we must present a physical geometry 4020 * that will remain consistent regardless 4021 * of how the disk is used. This will ensure 4022 * that the geometry does not change regardless 4023 * of the fdisk partition type (ie. EFI, FAT32, 4024 * Solaris, etc). 4025 */ 4026 if (ISCD(un)) { 4027 dkgp->dkg_nhead = un->un_pgeom.g_nhead; 4028 dkgp->dkg_nsect = un->un_pgeom.g_nsect; 4029 dkgp->dkg_ncyl = un->un_pgeom.g_ncyl; 4030 dkgp->dkg_acyl = un->un_pgeom.g_acyl; 4031 } else { 4032 cmlb_convert_geometry(un->un_blockcount, dkgp); 4033 dkgp->dkg_acyl = 0; 4034 dkgp->dkg_ncyl = un->un_blockcount / 4035 (dkgp->dkg_nhead * dkgp->dkg_nsect); 4036 } 4037 } 4038 dkgp->dkg_pcyl = dkgp->dkg_ncyl + dkgp->dkg_acyl; 4039 4040 if (ddi_copyout(dkgp, (void *)arg, 4041 sizeof (struct dk_geom), flag)) { 4042 mutex_exit(CMLB_MUTEX(un)); 4043 err = EFAULT; 4044 } else { 4045 mutex_exit(CMLB_MUTEX(un)); 4046 err = 0; 4047 } 4048 return (err); 4049 } 4050 #endif 4051 4052 #if defined(__i386) || defined(__amd64) 4053 static int 4054 cmlb_dkio_partinfo(struct cmlb_lun *un, dev_t dev, caddr_t arg, int flag) 4055 { 4056 int err = 0; 4057 4058 /* 4059 * Return parameters describing the selected disk slice. 4060 * Note: this ioctl is for the intel platform only 4061 */ 4062 int part; 4063 4064 part = CMLBPART(dev); 4065 4066 /* don't check un_solaris_size for pN */ 4067 if (part < P0_RAW_DISK && un->un_solaris_size == 0) { 4068 err = EIO; 4069 } else { 4070 struct part_info p; 4071 4072 p.p_start = (daddr_t)un->un_offset[part]; 4073 p.p_length = (int)un->un_map[part].dkl_nblk; 4074 #ifdef _MULTI_DATAMODEL 4075 switch (ddi_model_convert_from(flag & FMODELS)) { 4076 case DDI_MODEL_ILP32: 4077 { 4078 struct part_info32 p32; 4079 4080 p32.p_start = (daddr32_t)p.p_start; 4081 p32.p_length = p.p_length; 4082 if (ddi_copyout(&p32, (void *)arg, 4083 sizeof (p32), flag)) 4084 err = EFAULT; 4085 break; 4086 } 4087 4088 case DDI_MODEL_NONE: 4089 { 4090 if (ddi_copyout(&p, (void *)arg, sizeof (p), 4091 flag)) 4092 err = EFAULT; 4093 break; 4094 } 4095 } 4096 #else /* ! _MULTI_DATAMODEL */ 4097 if (ddi_copyout(&p, (void *)arg, sizeof (p), flag)) 4098 err = EFAULT; 4099 #endif /* _MULTI_DATAMODEL */ 4100 } 4101 return (err); 4102 } 4103 #endif 4104