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, 0); 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 } 1190 1191 /* NO EFI label found */ 1192 1193 if (capacity > DK_MAX_BLOCKS) { 1194 if (label_error == ESRCH) { 1195 /* 1196 * they've configured a LUN over 1TB, but used 1197 * format.dat to restrict format's view of the 1198 * capacity to be under 1TB 1199 */ 1200 /* i.e > 1Tb with a VTOC < 1TB */ 1201 1202 cmlb_log(CMLB_DEVINFO(un), CMLB_LABEL(un), CE_WARN, 1203 "is >1TB and has a VTOC label: use format(1M) to " 1204 "either decrease the"); 1205 cmlb_log(CMLB_DEVINFO(un), CMLB_LABEL(un), CE_CONT, 1206 "size to be < 1TB or relabel the disk with an EFI " 1207 "label"); 1208 } else { 1209 /* unlabeled disk over 1TB */ 1210 return (ENOTSUP); 1211 } 1212 } 1213 1214 label_error = 0; 1215 1216 /* 1217 * at this point it is either labeled with a VTOC or it is 1218 * under 1TB 1219 */ 1220 1221 /* 1222 * Only DIRECT ACCESS devices will have Sun labels. 1223 * CD's supposedly have a Sun label, too 1224 */ 1225 if (un->un_device_type == DTYPE_DIRECT || ISREMOVABLE(un)) { 1226 struct dk_label *dkl; 1227 offset_t label_addr; 1228 int rval; 1229 size_t buffer_size; 1230 1231 /* 1232 * Note: This will set up un->un_solaris_size and 1233 * un->un_solaris_offset. 1234 */ 1235 rval = cmlb_read_fdisk(un, capacity); 1236 if (rval != 0) { 1237 ASSERT(mutex_owned(CMLB_MUTEX(un))); 1238 return (rval); 1239 } 1240 1241 if (un->un_solaris_size <= DK_LABEL_LOC) { 1242 /* 1243 * Found fdisk table but no Solaris partition entry, 1244 * so don't call cmlb_uselabel() and don't create 1245 * a default label. 1246 */ 1247 label_error = 0; 1248 un->un_f_geometry_is_valid = TRUE; 1249 goto no_solaris_partition; 1250 } 1251 1252 label_addr = (daddr_t)(un->un_solaris_offset + DK_LABEL_LOC); 1253 1254 buffer_size = sizeof (struct dk_label); 1255 1256 cmlb_dbg(CMLB_TRACE, un, "cmlb_validate_geometry: " 1257 "label_addr: 0x%x allocation size: 0x%x\n", 1258 label_addr, buffer_size); 1259 1260 if ((dkl = kmem_zalloc(buffer_size, KM_NOSLEEP)) == NULL) 1261 return (ENOMEM); 1262 1263 mutex_exit(CMLB_MUTEX(un)); 1264 rval = DK_TG_READ(un, dkl, label_addr, buffer_size); 1265 mutex_enter(CMLB_MUTEX(un)); 1266 1267 switch (rval) { 1268 case 0: 1269 /* 1270 * cmlb_uselabel will establish that the geometry 1271 * is valid. 1272 */ 1273 if (cmlb_uselabel(un, 1274 (struct dk_label *)(uintptr_t)dkl) != 1275 CMLB_LABEL_IS_VALID) { 1276 label_error = EINVAL; 1277 } else 1278 un->un_vtoc_label_is_from_media = 1; 1279 break; 1280 case EACCES: 1281 label_error = EACCES; 1282 break; 1283 default: 1284 label_error = EINVAL; 1285 break; 1286 } 1287 1288 kmem_free(dkl, buffer_size); 1289 } 1290 1291 /* 1292 * If a valid label was not found, AND if no reservation conflict 1293 * was detected, then go ahead and create a default label (4069506). 1294 * 1295 * Note: currently, for VTOC_8 devices, the default label is created 1296 * for removables only. For VTOC_16 devices, the default label will 1297 * be created for both removables and non-removables alike. 1298 * (see cmlb_build_default_label) 1299 */ 1300 #if defined(_SUNOS_VTOC_8) 1301 if (ISREMOVABLE(un) && (label_error != EACCES)) { 1302 #elif defined(_SUNOS_VTOC_16) 1303 if (label_error != EACCES) { 1304 #endif 1305 if (un->un_f_geometry_is_valid == FALSE) { 1306 cmlb_build_default_label(un); 1307 } 1308 label_error = 0; 1309 } 1310 1311 no_solaris_partition: 1312 1313 #if defined(_SUNOS_VTOC_16) 1314 /* 1315 * If we have valid geometry, set up the remaining fdisk partitions. 1316 * Note that dkl_cylno is not used for the fdisk map entries, so 1317 * we set it to an entirely bogus value. 1318 */ 1319 for (count = 0; count < FD_NUMPART; count++) { 1320 un->un_map[FDISK_P1 + count].dkl_cylno = -1; 1321 un->un_map[FDISK_P1 + count].dkl_nblk = 1322 un->un_fmap[count].fmap_nblk; 1323 1324 un->un_offset[FDISK_P1 + count] = 1325 un->un_fmap[count].fmap_start; 1326 } 1327 #endif 1328 1329 for (count = 0; count < NDKMAP; count++) { 1330 #if defined(_SUNOS_VTOC_8) 1331 struct dk_map *lp = &un->un_map[count]; 1332 un->un_offset[count] = 1333 un->un_g.dkg_nhead * un->un_g.dkg_nsect * lp->dkl_cylno; 1334 #elif defined(_SUNOS_VTOC_16) 1335 struct dkl_partition *vp = &un->un_vtoc.v_part[count]; 1336 1337 un->un_offset[count] = vp->p_start + un->un_solaris_offset; 1338 #else 1339 #error "No VTOC format defined." 1340 #endif 1341 } 1342 1343 return (label_error); 1344 } 1345 1346 #if defined(_SUNOS_VTOC_16) 1347 /* 1348 * Macro: MAX_BLKS 1349 * 1350 * This macro is used for table entries where we need to have the largest 1351 * possible sector value for that head & SPT (sectors per track) 1352 * combination. Other entries for some smaller disk sizes are set by 1353 * convention to match those used by X86 BIOS usage. 1354 */ 1355 #define MAX_BLKS(heads, spt) UINT16_MAX * heads * spt, heads, spt 1356 1357 /* 1358 * Function: cmlb_convert_geometry 1359 * 1360 * Description: Convert physical geometry into a dk_geom structure. In 1361 * other words, make sure we don't wrap 16-bit values. 1362 * e.g. converting from geom_cache to dk_geom 1363 * 1364 * Context: Kernel thread only 1365 */ 1366 static void 1367 cmlb_convert_geometry(diskaddr_t capacity, struct dk_geom *un_g) 1368 { 1369 int i; 1370 static const struct chs_values { 1371 uint_t max_cap; /* Max Capacity for this HS. */ 1372 uint_t nhead; /* Heads to use. */ 1373 uint_t nsect; /* SPT to use. */ 1374 } CHS_values[] = { 1375 {0x00200000, 64, 32}, /* 1GB or smaller disk. */ 1376 {0x01000000, 128, 32}, /* 8GB or smaller disk. */ 1377 {MAX_BLKS(255, 63)}, /* 502.02GB or smaller disk. */ 1378 {MAX_BLKS(255, 126)}, /* .98TB or smaller disk. */ 1379 {DK_MAX_BLOCKS, 255, 189} /* Max size is just under 1TB */ 1380 }; 1381 1382 /* Unlabeled SCSI floppy device */ 1383 if (capacity <= 0x1000) { 1384 un_g->dkg_nhead = 2; 1385 un_g->dkg_ncyl = 80; 1386 un_g->dkg_nsect = capacity / (un_g->dkg_nhead * un_g->dkg_ncyl); 1387 return; 1388 } 1389 1390 /* 1391 * For all devices we calculate cylinders using the 1392 * heads and sectors we assign based on capacity of the 1393 * device. The table is designed to be compatible with the 1394 * way other operating systems lay out fdisk tables for X86 1395 * and to insure that the cylinders never exceed 65535 to 1396 * prevent problems with X86 ioctls that report geometry. 1397 * We use SPT that are multiples of 63, since other OSes that 1398 * are not limited to 16-bits for cylinders stop at 63 SPT 1399 * we make do by using multiples of 63 SPT. 1400 * 1401 * Note than capacities greater than or equal to 1TB will simply 1402 * get the largest geometry from the table. This should be okay 1403 * since disks this large shouldn't be using CHS values anyway. 1404 */ 1405 for (i = 0; CHS_values[i].max_cap < capacity && 1406 CHS_values[i].max_cap != DK_MAX_BLOCKS; i++) 1407 ; 1408 1409 un_g->dkg_nhead = CHS_values[i].nhead; 1410 un_g->dkg_nsect = CHS_values[i].nsect; 1411 } 1412 #endif 1413 1414 /* 1415 * Function: cmlb_resync_geom_caches 1416 * 1417 * Description: (Re)initialize both geometry caches: the virtual geometry 1418 * information is extracted from the HBA (the "geometry" 1419 * capability), and the physical geometry cache data is 1420 * generated by issuing MODE SENSE commands. 1421 * 1422 * Arguments: un - driver soft state (unit) structure 1423 * capacity - disk capacity in #blocks 1424 * 1425 * Context: Kernel thread only (can sleep). 1426 */ 1427 static void 1428 cmlb_resync_geom_caches(struct cmlb_lun *un, diskaddr_t capacity) 1429 { 1430 struct cmlb_geom pgeom; 1431 struct cmlb_geom lgeom; 1432 struct cmlb_geom *pgeomp = &pgeom; 1433 unsigned short nhead; 1434 unsigned short nsect; 1435 int spc; 1436 int ret; 1437 1438 ASSERT(un != NULL); 1439 ASSERT(mutex_owned(CMLB_MUTEX(un))); 1440 1441 /* 1442 * Ask the controller for its logical geometry. 1443 * Note: if the HBA does not support scsi_ifgetcap("geometry"), 1444 * then the lgeom cache will be invalid. 1445 */ 1446 mutex_exit(CMLB_MUTEX(un)); 1447 bzero(&lgeom, sizeof (struct cmlb_geom)); 1448 ret = DK_TG_GETVIRTGEOM(un, &lgeom); 1449 mutex_enter(CMLB_MUTEX(un)); 1450 1451 bcopy(&lgeom, &un->un_lgeom, sizeof (un->un_lgeom)); 1452 1453 /* 1454 * Initialize the pgeom cache from lgeom, so that if MODE SENSE 1455 * doesn't work, DKIOCG_PHYSGEOM can return reasonable values. 1456 */ 1457 if (ret != 0 || un->un_lgeom.g_nsect == 0 || 1458 un->un_lgeom.g_nhead == 0) { 1459 /* 1460 * Note: Perhaps this needs to be more adaptive? The rationale 1461 * is that, if there's no HBA geometry from the HBA driver, any 1462 * guess is good, since this is the physical geometry. If MODE 1463 * SENSE fails this gives a max cylinder size for non-LBA access 1464 */ 1465 nhead = 255; 1466 nsect = 63; 1467 } else { 1468 nhead = un->un_lgeom.g_nhead; 1469 nsect = un->un_lgeom.g_nsect; 1470 } 1471 1472 if (ISCD(un)) { 1473 pgeomp->g_nhead = 1; 1474 pgeomp->g_nsect = nsect * nhead; 1475 } else { 1476 pgeomp->g_nhead = nhead; 1477 pgeomp->g_nsect = nsect; 1478 } 1479 1480 spc = pgeomp->g_nhead * pgeomp->g_nsect; 1481 pgeomp->g_capacity = capacity; 1482 pgeomp->g_ncyl = pgeomp->g_capacity / spc; 1483 pgeomp->g_acyl = 0; 1484 1485 /* 1486 * Retrieve fresh geometry data from the hardware, stash it 1487 * here temporarily before we rebuild the incore label. 1488 * 1489 * We want to use the MODE SENSE commands to derive the 1490 * physical geometry of the device, but if either command 1491 * fails, the logical geometry is used as the fallback for 1492 * disk label geometry. 1493 */ 1494 1495 mutex_exit(CMLB_MUTEX(un)); 1496 (void) DK_TG_GETPHYGEOM(un, pgeomp); 1497 mutex_enter(CMLB_MUTEX(un)); 1498 1499 /* 1500 * Now update the real copy while holding the mutex. This 1501 * way the global copy is never in an inconsistent state. 1502 */ 1503 bcopy(pgeomp, &un->un_pgeom, sizeof (un->un_pgeom)); 1504 1505 cmlb_dbg(CMLB_INFO, un, "cmlb_resync_geom_caches: " 1506 "(cached from lgeom)\n"); 1507 cmlb_dbg(CMLB_INFO, un, 1508 " ncyl: %ld; acyl: %d; nhead: %d; nsect: %d\n", 1509 un->un_pgeom.g_ncyl, un->un_pgeom.g_acyl, 1510 un->un_pgeom.g_nhead, un->un_pgeom.g_nsect); 1511 cmlb_dbg(CMLB_INFO, un, " lbasize: %d; capacity: %ld; " 1512 "intrlv: %d; rpm: %d\n", un->un_pgeom.g_secsize, 1513 un->un_pgeom.g_capacity, un->un_pgeom.g_intrlv, 1514 un->un_pgeom.g_rpm); 1515 } 1516 1517 1518 /* 1519 * Function: cmlb_read_fdisk 1520 * 1521 * Description: utility routine to read the fdisk table. 1522 * 1523 * Arguments: un - driver soft state (unit) structure 1524 * 1525 * Return Code: 0 for success (includes not reading for no_fdisk_present case 1526 * errnos from tg_rw if failed to read the first block. 1527 * 1528 * Context: Kernel thread only (can sleep). 1529 */ 1530 /* ARGSUSED */ 1531 static int 1532 cmlb_read_fdisk(struct cmlb_lun *un, diskaddr_t capacity) 1533 { 1534 #if defined(_NO_FDISK_PRESENT) 1535 1536 un->un_solaris_offset = 0; 1537 un->un_solaris_size = capacity; 1538 bzero(un->un_fmap, sizeof (struct fmap) * FD_NUMPART); 1539 return (0); 1540 1541 #elif defined(_FIRMWARE_NEEDS_FDISK) 1542 1543 struct ipart *fdp; 1544 struct mboot *mbp; 1545 struct ipart fdisk[FD_NUMPART]; 1546 int i; 1547 char sigbuf[2]; 1548 caddr_t bufp; 1549 int uidx; 1550 int rval; 1551 int lba = 0; 1552 uint_t solaris_offset; /* offset to solaris part. */ 1553 daddr_t solaris_size; /* size of solaris partition */ 1554 uint32_t blocksize; 1555 1556 ASSERT(un != NULL); 1557 ASSERT(mutex_owned(CMLB_MUTEX(un))); 1558 1559 /* 1560 * Start off assuming no fdisk table 1561 */ 1562 solaris_offset = 0; 1563 solaris_size = capacity; 1564 1565 blocksize = 512; 1566 1567 bufp = kmem_zalloc(blocksize, KM_SLEEP); 1568 1569 mutex_exit(CMLB_MUTEX(un)); 1570 rval = DK_TG_READ(un, bufp, 0, blocksize); 1571 mutex_enter(CMLB_MUTEX(un)); 1572 1573 if (rval != 0) { 1574 cmlb_dbg(CMLB_ERROR, un, 1575 "cmlb_read_fdisk: fdisk read err\n"); 1576 kmem_free(bufp, blocksize); 1577 return (rval); 1578 } 1579 1580 mbp = (struct mboot *)bufp; 1581 1582 /* 1583 * The fdisk table does not begin on a 4-byte boundary within the 1584 * master boot record, so we copy it to an aligned structure to avoid 1585 * alignment exceptions on some processors. 1586 */ 1587 bcopy(&mbp->parts[0], fdisk, sizeof (fdisk)); 1588 1589 /* 1590 * Check for lba support before verifying sig; sig might not be 1591 * there, say on a blank disk, but the max_chs mark may still 1592 * be present. 1593 * 1594 * Note: LBA support and BEFs are an x86-only concept but this 1595 * code should work OK on SPARC as well. 1596 */ 1597 1598 /* 1599 * First, check for lba-access-ok on root node (or prom root node) 1600 * if present there, don't need to search fdisk table. 1601 */ 1602 if (ddi_getprop(DDI_DEV_T_ANY, ddi_root_node(), 0, 1603 "lba-access-ok", 0) != 0) { 1604 /* All drives do LBA; don't search fdisk table */ 1605 lba = 1; 1606 } else { 1607 /* Okay, look for mark in fdisk table */ 1608 for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) { 1609 /* accumulate "lba" value from all partitions */ 1610 lba = (lba || cmlb_has_max_chs_vals(fdp)); 1611 } 1612 } 1613 1614 /* 1615 * Next, look for 'no-bef-lba-access' prop on parent. 1616 * Its presence means the realmode driver doesn't support 1617 * LBA, so the target driver shouldn't advertise it as ok. 1618 * This should be a temporary condition; one day all 1619 * BEFs should support the LBA access functions. 1620 */ 1621 if ((lba != 0) && (ddi_getprop(DDI_DEV_T_ANY, 1622 ddi_get_parent(CMLB_DEVINFO(un)), DDI_PROP_DONTPASS, 1623 "no-bef-lba-access", 0) != 0)) { 1624 /* BEF doesn't support LBA; don't advertise it as ok */ 1625 lba = 0; 1626 } 1627 1628 if (lba != 0) { 1629 dev_t dev = cmlb_make_device(un); 1630 1631 if (ddi_getprop(dev, CMLB_DEVINFO(un), DDI_PROP_DONTPASS, 1632 "lba-access-ok", 0) == 0) { 1633 /* not found; create it */ 1634 if (ddi_prop_create(dev, CMLB_DEVINFO(un), 0, 1635 "lba-access-ok", (caddr_t)NULL, 0) != 1636 DDI_PROP_SUCCESS) { 1637 cmlb_dbg(CMLB_ERROR, un, 1638 "cmlb_read_fdisk: Can't create lba " 1639 "property for instance %d\n", 1640 ddi_get_instance(CMLB_DEVINFO(un))); 1641 } 1642 } 1643 } 1644 1645 bcopy(&mbp->signature, sigbuf, sizeof (sigbuf)); 1646 1647 /* 1648 * Endian-independent signature check 1649 */ 1650 if (((sigbuf[1] & 0xFF) != ((MBB_MAGIC >> 8) & 0xFF)) || 1651 (sigbuf[0] != (MBB_MAGIC & 0xFF))) { 1652 cmlb_dbg(CMLB_ERROR, un, 1653 "cmlb_read_fdisk: no fdisk\n"); 1654 bzero(un->un_fmap, sizeof (struct fmap) * FD_NUMPART); 1655 goto done; 1656 } 1657 1658 #ifdef CMLBDEBUG 1659 if (cmlb_level_mask & SD_LOGMASK_INFO) { 1660 fdp = fdisk; 1661 cmlb_dbg(CMLB_INFO, un, "cmlb_read_fdisk:\n"); 1662 cmlb_dbg(CMLB_INFO, un, " relsect " 1663 "numsect sysid bootid\n"); 1664 for (i = 0; i < FD_NUMPART; i++, fdp++) { 1665 cmlb_dbg(CMLB_INFO, un, 1666 " %d: %8d %8d 0x%08x 0x%08x\n", 1667 i, fdp->relsect, fdp->numsect, 1668 fdp->systid, fdp->bootid); 1669 } 1670 } 1671 #endif 1672 1673 /* 1674 * Try to find the unix partition 1675 */ 1676 uidx = -1; 1677 solaris_offset = 0; 1678 solaris_size = 0; 1679 1680 for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) { 1681 int relsect; 1682 int numsect; 1683 1684 if (fdp->numsect == 0) { 1685 un->un_fmap[i].fmap_start = 0; 1686 un->un_fmap[i].fmap_nblk = 0; 1687 continue; 1688 } 1689 1690 /* 1691 * Data in the fdisk table is little-endian. 1692 */ 1693 relsect = LE_32(fdp->relsect); 1694 numsect = LE_32(fdp->numsect); 1695 1696 un->un_fmap[i].fmap_start = relsect; 1697 un->un_fmap[i].fmap_nblk = numsect; 1698 1699 if (fdp->systid != SUNIXOS && 1700 fdp->systid != SUNIXOS2 && 1701 fdp->systid != EFI_PMBR) { 1702 continue; 1703 } 1704 1705 /* 1706 * use the last active solaris partition id found 1707 * (there should only be 1 active partition id) 1708 * 1709 * if there are no active solaris partition id 1710 * then use the first inactive solaris partition id 1711 */ 1712 if ((uidx == -1) || (fdp->bootid == ACTIVE)) { 1713 uidx = i; 1714 solaris_offset = relsect; 1715 solaris_size = numsect; 1716 } 1717 } 1718 1719 cmlb_dbg(CMLB_INFO, un, "fdisk 0x%x 0x%lx", 1720 un->un_solaris_offset, un->un_solaris_size); 1721 done: 1722 1723 /* 1724 * Clear the VTOC info, only if the Solaris partition entry 1725 * has moved, changed size, been deleted, or if the size of 1726 * the partition is too small to even fit the label sector. 1727 */ 1728 if ((un->un_solaris_offset != solaris_offset) || 1729 (un->un_solaris_size != solaris_size) || 1730 solaris_size <= DK_LABEL_LOC) { 1731 cmlb_dbg(CMLB_INFO, un, "fdisk moved 0x%x 0x%lx", 1732 solaris_offset, solaris_size); 1733 bzero(&un->un_g, sizeof (struct dk_geom)); 1734 bzero(&un->un_vtoc, sizeof (struct dk_vtoc)); 1735 bzero(&un->un_map, NDKMAP * (sizeof (struct dk_map))); 1736 un->un_f_geometry_is_valid = FALSE; 1737 } 1738 un->un_solaris_offset = solaris_offset; 1739 un->un_solaris_size = solaris_size; 1740 kmem_free(bufp, blocksize); 1741 return (rval); 1742 1743 #else /* #elif defined(_FIRMWARE_NEEDS_FDISK) */ 1744 #error "fdisk table presence undetermined for this platform." 1745 #endif /* #if defined(_NO_FDISK_PRESENT) */ 1746 } 1747 1748 static void 1749 cmlb_swap_efi_gpt(efi_gpt_t *e) 1750 { 1751 _NOTE(ASSUMING_PROTECTED(*e)) 1752 e->efi_gpt_Signature = LE_64(e->efi_gpt_Signature); 1753 e->efi_gpt_Revision = LE_32(e->efi_gpt_Revision); 1754 e->efi_gpt_HeaderSize = LE_32(e->efi_gpt_HeaderSize); 1755 e->efi_gpt_HeaderCRC32 = LE_32(e->efi_gpt_HeaderCRC32); 1756 e->efi_gpt_MyLBA = LE_64(e->efi_gpt_MyLBA); 1757 e->efi_gpt_AlternateLBA = LE_64(e->efi_gpt_AlternateLBA); 1758 e->efi_gpt_FirstUsableLBA = LE_64(e->efi_gpt_FirstUsableLBA); 1759 e->efi_gpt_LastUsableLBA = LE_64(e->efi_gpt_LastUsableLBA); 1760 UUID_LE_CONVERT(e->efi_gpt_DiskGUID, e->efi_gpt_DiskGUID); 1761 e->efi_gpt_PartitionEntryLBA = LE_64(e->efi_gpt_PartitionEntryLBA); 1762 e->efi_gpt_NumberOfPartitionEntries = 1763 LE_32(e->efi_gpt_NumberOfPartitionEntries); 1764 e->efi_gpt_SizeOfPartitionEntry = 1765 LE_32(e->efi_gpt_SizeOfPartitionEntry); 1766 e->efi_gpt_PartitionEntryArrayCRC32 = 1767 LE_32(e->efi_gpt_PartitionEntryArrayCRC32); 1768 } 1769 1770 static void 1771 cmlb_swap_efi_gpe(int nparts, efi_gpe_t *p) 1772 { 1773 int i; 1774 1775 _NOTE(ASSUMING_PROTECTED(*p)) 1776 for (i = 0; i < nparts; i++) { 1777 UUID_LE_CONVERT(p[i].efi_gpe_PartitionTypeGUID, 1778 p[i].efi_gpe_PartitionTypeGUID); 1779 p[i].efi_gpe_StartingLBA = LE_64(p[i].efi_gpe_StartingLBA); 1780 p[i].efi_gpe_EndingLBA = LE_64(p[i].efi_gpe_EndingLBA); 1781 /* PartitionAttrs */ 1782 } 1783 } 1784 1785 static int 1786 cmlb_validate_efi(efi_gpt_t *labp) 1787 { 1788 if (labp->efi_gpt_Signature != EFI_SIGNATURE) 1789 return (EINVAL); 1790 /* at least 96 bytes in this version of the spec. */ 1791 if (sizeof (efi_gpt_t) - sizeof (labp->efi_gpt_Reserved2) > 1792 labp->efi_gpt_HeaderSize) 1793 return (EINVAL); 1794 /* this should be 128 bytes */ 1795 if (labp->efi_gpt_SizeOfPartitionEntry != sizeof (efi_gpe_t)) 1796 return (EINVAL); 1797 return (0); 1798 } 1799 1800 static int 1801 cmlb_use_efi(struct cmlb_lun *un, diskaddr_t capacity) 1802 { 1803 int i; 1804 int rval = 0; 1805 efi_gpe_t *partitions; 1806 uchar_t *buf; 1807 uint_t lbasize; /* is really how much to read */ 1808 diskaddr_t cap; 1809 uint_t nparts; 1810 diskaddr_t gpe_lba; 1811 1812 ASSERT(mutex_owned(CMLB_MUTEX(un))); 1813 1814 lbasize = un->un_sys_blocksize; 1815 1816 buf = kmem_zalloc(EFI_MIN_ARRAY_SIZE, KM_SLEEP); 1817 mutex_exit(CMLB_MUTEX(un)); 1818 1819 rval = DK_TG_READ(un, buf, 0, lbasize); 1820 if (rval) { 1821 goto done_err; 1822 } 1823 if (((struct dk_label *)buf)->dkl_magic == DKL_MAGIC) { 1824 /* not ours */ 1825 rval = ESRCH; 1826 goto done_err; 1827 } 1828 1829 rval = DK_TG_READ(un, buf, 1, lbasize); 1830 if (rval) { 1831 goto done_err; 1832 } 1833 cmlb_swap_efi_gpt((efi_gpt_t *)buf); 1834 1835 if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) { 1836 /* 1837 * Couldn't read the primary, try the backup. Our 1838 * capacity at this point could be based on CHS, so 1839 * check what the device reports. 1840 */ 1841 rval = DK_TG_GETCAP(un, &cap); 1842 1843 if (rval) { 1844 goto done_err; 1845 } 1846 if ((rval = DK_TG_READ(un, buf, cap - 1, lbasize)) != 0) { 1847 goto done_err; 1848 } 1849 cmlb_swap_efi_gpt((efi_gpt_t *)buf); 1850 if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) 1851 goto done_err; 1852 cmlb_log(CMLB_DEVINFO(un), CMLB_LABEL(un), CE_WARN, 1853 "primary label corrupt; using backup\n"); 1854 } 1855 1856 nparts = ((efi_gpt_t *)buf)->efi_gpt_NumberOfPartitionEntries; 1857 gpe_lba = ((efi_gpt_t *)buf)->efi_gpt_PartitionEntryLBA; 1858 1859 rval = DK_TG_READ(un, buf, gpe_lba, EFI_MIN_ARRAY_SIZE); 1860 if (rval) { 1861 goto done_err; 1862 } 1863 partitions = (efi_gpe_t *)buf; 1864 1865 if (nparts > MAXPART) { 1866 nparts = MAXPART; 1867 } 1868 cmlb_swap_efi_gpe(nparts, partitions); 1869 1870 mutex_enter(CMLB_MUTEX(un)); 1871 1872 /* Fill in partition table. */ 1873 for (i = 0; i < nparts; i++) { 1874 if (partitions->efi_gpe_StartingLBA != 0 || 1875 partitions->efi_gpe_EndingLBA != 0) { 1876 un->un_map[i].dkl_cylno = 1877 partitions->efi_gpe_StartingLBA; 1878 un->un_map[i].dkl_nblk = 1879 partitions->efi_gpe_EndingLBA - 1880 partitions->efi_gpe_StartingLBA + 1; 1881 un->un_offset[i] = 1882 partitions->efi_gpe_StartingLBA; 1883 } 1884 if (i == WD_NODE) { 1885 /* 1886 * minor number 7 corresponds to the whole disk 1887 */ 1888 un->un_map[i].dkl_cylno = 0; 1889 un->un_map[i].dkl_nblk = capacity; 1890 un->un_offset[i] = 0; 1891 } 1892 partitions++; 1893 } 1894 un->un_solaris_offset = 0; 1895 un->un_solaris_size = capacity; 1896 un->un_f_geometry_is_valid = TRUE; 1897 kmem_free(buf, EFI_MIN_ARRAY_SIZE); 1898 return (0); 1899 1900 done_err: 1901 kmem_free(buf, EFI_MIN_ARRAY_SIZE); 1902 mutex_enter(CMLB_MUTEX(un)); 1903 /* 1904 * if we didn't find something that could look like a VTOC 1905 * and the disk is over 1TB, we know there isn't a valid label. 1906 * Otherwise let cmlb_uselabel decide what to do. We only 1907 * want to invalidate this if we're certain the label isn't 1908 * valid because cmlb_prop_op will now fail, which in turn 1909 * causes things like opens and stats on the partition to fail. 1910 */ 1911 if ((capacity > DK_MAX_BLOCKS) && (rval != ESRCH)) { 1912 un->un_f_geometry_is_valid = FALSE; 1913 } 1914 return (rval); 1915 } 1916 1917 1918 /* 1919 * Function: cmlb_uselabel 1920 * 1921 * Description: Validate the disk label and update the relevant data (geometry, 1922 * partition, vtoc, and capacity data) in the cmlb_lun struct. 1923 * Marks the geometry of the unit as being valid. 1924 * 1925 * Arguments: un: unit struct. 1926 * dk_label: disk label 1927 * 1928 * Return Code: CMLB_LABEL_IS_VALID: Label read from disk is OK; geometry, 1929 * partition, vtoc, and capacity data are good. 1930 * 1931 * CMLB_LABEL_IS_INVALID: Magic number or checksum error in the 1932 * label; or computed capacity does not jibe with capacity 1933 * reported from the READ CAPACITY command. 1934 * 1935 * Context: Kernel thread only (can sleep). 1936 */ 1937 static int 1938 cmlb_uselabel(struct cmlb_lun *un, struct dk_label *labp) 1939 { 1940 short *sp; 1941 short sum; 1942 short count; 1943 int label_error = CMLB_LABEL_IS_VALID; 1944 int i; 1945 diskaddr_t label_capacity; 1946 int part_end; 1947 diskaddr_t track_capacity; 1948 #if defined(_SUNOS_VTOC_16) 1949 struct dkl_partition *vpartp; 1950 #endif 1951 ASSERT(un != NULL); 1952 ASSERT(mutex_owned(CMLB_MUTEX(un))); 1953 1954 /* Validate the magic number of the label. */ 1955 if (labp->dkl_magic != DKL_MAGIC) { 1956 #if defined(__sparc) 1957 if (!ISREMOVABLE(un)) { 1958 cmlb_log(CMLB_DEVINFO(un), CMLB_LABEL(un), CE_WARN, 1959 "Corrupt label; wrong magic number\n"); 1960 } 1961 #endif 1962 return (CMLB_LABEL_IS_INVALID); 1963 } 1964 1965 /* Validate the checksum of the label. */ 1966 sp = (short *)labp; 1967 sum = 0; 1968 count = sizeof (struct dk_label) / sizeof (short); 1969 while (count--) { 1970 sum ^= *sp++; 1971 } 1972 1973 if (sum != 0) { 1974 #if defined(_SUNOS_VTOC_16) 1975 if (!ISCD(un)) { 1976 #elif defined(_SUNOS_VTOC_8) 1977 if (!ISREMOVABLE(un)) { 1978 #endif 1979 cmlb_log(CMLB_DEVINFO(un), CMLB_LABEL(un), CE_WARN, 1980 "Corrupt label - label checksum failed\n"); 1981 } 1982 return (CMLB_LABEL_IS_INVALID); 1983 } 1984 1985 1986 /* 1987 * Fill in geometry structure with data from label. 1988 */ 1989 bzero(&un->un_g, sizeof (struct dk_geom)); 1990 un->un_g.dkg_ncyl = labp->dkl_ncyl; 1991 un->un_g.dkg_acyl = labp->dkl_acyl; 1992 un->un_g.dkg_bcyl = 0; 1993 un->un_g.dkg_nhead = labp->dkl_nhead; 1994 un->un_g.dkg_nsect = labp->dkl_nsect; 1995 un->un_g.dkg_intrlv = labp->dkl_intrlv; 1996 1997 #if defined(_SUNOS_VTOC_8) 1998 un->un_g.dkg_gap1 = labp->dkl_gap1; 1999 un->un_g.dkg_gap2 = labp->dkl_gap2; 2000 un->un_g.dkg_bhead = labp->dkl_bhead; 2001 #endif 2002 #if defined(_SUNOS_VTOC_16) 2003 un->un_dkg_skew = labp->dkl_skew; 2004 #endif 2005 2006 #if defined(__i386) || defined(__amd64) 2007 un->un_g.dkg_apc = labp->dkl_apc; 2008 #endif 2009 2010 /* 2011 * Currently we rely on the values in the label being accurate. If 2012 * dkl_rpm or dkl_pcly are zero in the label, use a default value. 2013 * 2014 * Note: In the future a MODE SENSE may be used to retrieve this data, 2015 * although this command is optional in SCSI-2. 2016 */ 2017 un->un_g.dkg_rpm = (labp->dkl_rpm != 0) ? labp->dkl_rpm : 3600; 2018 un->un_g.dkg_pcyl = (labp->dkl_pcyl != 0) ? labp->dkl_pcyl : 2019 (un->un_g.dkg_ncyl + un->un_g.dkg_acyl); 2020 2021 /* 2022 * The Read and Write reinstruct values may not be valid 2023 * for older disks. 2024 */ 2025 un->un_g.dkg_read_reinstruct = labp->dkl_read_reinstruct; 2026 un->un_g.dkg_write_reinstruct = labp->dkl_write_reinstruct; 2027 2028 /* Fill in partition table. */ 2029 #if defined(_SUNOS_VTOC_8) 2030 for (i = 0; i < NDKMAP; i++) { 2031 un->un_map[i].dkl_cylno = labp->dkl_map[i].dkl_cylno; 2032 un->un_map[i].dkl_nblk = labp->dkl_map[i].dkl_nblk; 2033 } 2034 #endif 2035 #if defined(_SUNOS_VTOC_16) 2036 vpartp = labp->dkl_vtoc.v_part; 2037 track_capacity = labp->dkl_nhead * labp->dkl_nsect; 2038 2039 for (i = 0; i < NDKMAP; i++, vpartp++) { 2040 un->un_map[i].dkl_cylno = vpartp->p_start / track_capacity; 2041 un->un_map[i].dkl_nblk = vpartp->p_size; 2042 } 2043 #endif 2044 2045 /* Fill in VTOC Structure. */ 2046 bcopy(&labp->dkl_vtoc, &un->un_vtoc, sizeof (struct dk_vtoc)); 2047 #if defined(_SUNOS_VTOC_8) 2048 /* 2049 * The 8-slice vtoc does not include the ascii label; save it into 2050 * the device's soft state structure here. 2051 */ 2052 bcopy(labp->dkl_asciilabel, un->un_asciilabel, LEN_DKL_ASCII); 2053 #endif 2054 2055 /* Mark the geometry as valid. */ 2056 un->un_f_geometry_is_valid = TRUE; 2057 2058 /* Now look for a valid capacity. */ 2059 track_capacity = (un->un_g.dkg_nhead * un->un_g.dkg_nsect); 2060 label_capacity = (un->un_g.dkg_ncyl * track_capacity); 2061 2062 if (un->un_g.dkg_acyl) { 2063 #if defined(__i386) || defined(__amd64) 2064 /* we may have > 1 alts cylinder */ 2065 label_capacity += (track_capacity * un->un_g.dkg_acyl); 2066 #else 2067 label_capacity += track_capacity; 2068 #endif 2069 } 2070 2071 /* 2072 * if we got invalidated when mutex exit and entered again, 2073 * if blockcount different than when we came in, need to 2074 * retry from beginning of cmlb_validate_geometry. 2075 * revisit this on next phase of utilizing this for 2076 * sd. 2077 */ 2078 2079 if (label_capacity <= un->un_blockcount) { 2080 #if defined(_SUNOS_VTOC_8) 2081 /* 2082 * We can't let this happen on drives that are subdivided 2083 * into logical disks (i.e., that have an fdisk table). 2084 * The un_blockcount field should always hold the full media 2085 * size in sectors, period. This code would overwrite 2086 * un_blockcount with the size of the Solaris fdisk partition. 2087 */ 2088 cmlb_dbg(CMLB_ERROR, un, 2089 "cmlb_uselabel: Label %d blocks; Drive %d blocks\n", 2090 label_capacity, un->un_blockcount); 2091 un->un_solaris_size = label_capacity; 2092 2093 #endif /* defined(_SUNOS_VTOC_8) */ 2094 goto done; 2095 } 2096 2097 if (ISCD(un)) { 2098 /* For CDROMs, we trust that the data in the label is OK. */ 2099 #if defined(_SUNOS_VTOC_8) 2100 for (i = 0; i < NDKMAP; i++) { 2101 part_end = labp->dkl_nhead * labp->dkl_nsect * 2102 labp->dkl_map[i].dkl_cylno + 2103 labp->dkl_map[i].dkl_nblk - 1; 2104 2105 if ((labp->dkl_map[i].dkl_nblk) && 2106 (part_end > un->un_blockcount)) { 2107 un->un_f_geometry_is_valid = FALSE; 2108 break; 2109 } 2110 } 2111 #endif 2112 #if defined(_SUNOS_VTOC_16) 2113 vpartp = &(labp->dkl_vtoc.v_part[0]); 2114 for (i = 0; i < NDKMAP; i++, vpartp++) { 2115 part_end = vpartp->p_start + vpartp->p_size; 2116 if ((vpartp->p_size > 0) && 2117 (part_end > un->un_blockcount)) { 2118 un->un_f_geometry_is_valid = FALSE; 2119 break; 2120 } 2121 } 2122 #endif 2123 } else { 2124 /* label_capacity > un->un_blockcount */ 2125 cmlb_log(CMLB_DEVINFO(un), CMLB_LABEL(un), CE_WARN, 2126 "Corrupt label - bad geometry\n"); 2127 cmlb_log(CMLB_DEVINFO(un), CMLB_LABEL(un), CE_CONT, 2128 "Label says %llu blocks; Drive says %llu blocks\n", 2129 label_capacity, un->un_blockcount); 2130 un->un_f_geometry_is_valid = FALSE; 2131 label_error = CMLB_LABEL_IS_INVALID; 2132 } 2133 2134 done: 2135 2136 cmlb_dbg(CMLB_INFO, un, "cmlb_uselabel: (label geometry)\n"); 2137 cmlb_dbg(CMLB_INFO, un, 2138 " ncyl: %d; acyl: %d; nhead: %d; nsect: %d\n", 2139 un->un_g.dkg_ncyl, un->un_g.dkg_acyl, 2140 un->un_g.dkg_nhead, un->un_g.dkg_nsect); 2141 2142 cmlb_dbg(CMLB_INFO, un, 2143 " label_capacity: %d; intrlv: %d; rpm: %d\n", 2144 un->un_blockcount, un->un_g.dkg_intrlv, un->un_g.dkg_rpm); 2145 cmlb_dbg(CMLB_INFO, un, " wrt_reinstr: %d; rd_reinstr: %d\n", 2146 un->un_g.dkg_write_reinstruct, un->un_g.dkg_read_reinstruct); 2147 2148 ASSERT(mutex_owned(CMLB_MUTEX(un))); 2149 2150 return (label_error); 2151 } 2152 2153 2154 /* 2155 * Function: cmlb_build_default_label 2156 * 2157 * Description: Generate a default label for those devices that do not have 2158 * one, e.g., new media, removable cartridges, etc.. 2159 * 2160 * Context: Kernel thread only 2161 */ 2162 static void 2163 cmlb_build_default_label(struct cmlb_lun *un) 2164 { 2165 #if defined(_SUNOS_VTOC_16) 2166 uint_t phys_spc; 2167 uint_t disksize; 2168 struct dk_geom un_g; 2169 #endif 2170 2171 ASSERT(un != NULL); 2172 ASSERT(mutex_owned(CMLB_MUTEX(un))); 2173 2174 #if defined(_SUNOS_VTOC_8) 2175 /* 2176 * Note: This is a legacy check for non-removable devices on VTOC_8 2177 * only. This may be a valid check for VTOC_16 as well. 2178 */ 2179 if (!ISREMOVABLE(un)) { 2180 return; 2181 } 2182 #endif 2183 2184 bzero(&un->un_g, sizeof (struct dk_geom)); 2185 bzero(&un->un_vtoc, sizeof (struct dk_vtoc)); 2186 bzero(&un->un_map, NDKMAP * (sizeof (struct dk_map))); 2187 2188 #if defined(_SUNOS_VTOC_8) 2189 2190 /* 2191 * It's a REMOVABLE media, therefore no label (on sparc, anyway). 2192 * But it is still necessary to set up various geometry information, 2193 * and we are doing this here. 2194 */ 2195 2196 /* 2197 * For the rpm, we use the minimum for the disk. For the head, cyl, 2198 * and number of sector per track, if the capacity <= 1GB, head = 64, 2199 * sect = 32. else head = 255, sect 63 Note: the capacity should be 2200 * equal to C*H*S values. This will cause some truncation of size due 2201 * to round off errors. For CD-ROMs, this truncation can have adverse 2202 * side effects, so returning ncyl and nhead as 1. The nsect will 2203 * overflow for most of CD-ROMs as nsect is of type ushort. (4190569) 2204 */ 2205 un->un_solaris_size = un->un_blockcount; 2206 if (ISCD(un)) { 2207 tg_attribute_t tgattribute; 2208 int is_writable; 2209 /* 2210 * Preserve the old behavior for non-writable 2211 * medias. Since dkg_nsect is a ushort, it 2212 * will lose bits as cdroms have more than 2213 * 65536 sectors. So if we recalculate 2214 * capacity, it will become much shorter. 2215 * But the dkg_* information is not 2216 * used for CDROMs so it is OK. But for 2217 * Writable CDs we need this information 2218 * to be valid (for newfs say). So we 2219 * make nsect and nhead > 1 that way 2220 * nsect can still stay within ushort limit 2221 * without losing any bits. 2222 */ 2223 2224 bzero(&tgattribute, sizeof (tg_attribute_t)); 2225 2226 mutex_exit(CMLB_MUTEX(un)); 2227 is_writable = (DK_TG_GETATTRIBUTE(un, &tgattribute) == 0) ? 2228 tgattribute.media_is_writable : 1; 2229 mutex_enter(CMLB_MUTEX(un)); 2230 2231 if (is_writable) { 2232 un->un_g.dkg_nhead = 64; 2233 un->un_g.dkg_nsect = 32; 2234 un->un_g.dkg_ncyl = un->un_blockcount / (64 * 32); 2235 un->un_solaris_size = un->un_g.dkg_ncyl * 2236 un->un_g.dkg_nhead * un->un_g.dkg_nsect; 2237 } else { 2238 un->un_g.dkg_ncyl = 1; 2239 un->un_g.dkg_nhead = 1; 2240 un->un_g.dkg_nsect = un->un_blockcount; 2241 } 2242 } else { 2243 if (un->un_blockcount <= 0x1000) { 2244 /* unlabeled SCSI floppy device */ 2245 un->un_g.dkg_nhead = 2; 2246 un->un_g.dkg_ncyl = 80; 2247 un->un_g.dkg_nsect = un->un_blockcount / (2 * 80); 2248 } else if (un->un_blockcount <= 0x200000) { 2249 un->un_g.dkg_nhead = 64; 2250 un->un_g.dkg_nsect = 32; 2251 un->un_g.dkg_ncyl = un->un_blockcount / (64 * 32); 2252 } else { 2253 un->un_g.dkg_nhead = 255; 2254 un->un_g.dkg_nsect = 63; 2255 un->un_g.dkg_ncyl = un->un_blockcount / (255 * 63); 2256 } 2257 un->un_solaris_size = 2258 un->un_g.dkg_ncyl * un->un_g.dkg_nhead * un->un_g.dkg_nsect; 2259 2260 } 2261 2262 un->un_g.dkg_acyl = 0; 2263 un->un_g.dkg_bcyl = 0; 2264 un->un_g.dkg_rpm = 200; 2265 un->un_asciilabel[0] = '\0'; 2266 un->un_g.dkg_pcyl = un->un_g.dkg_ncyl; 2267 2268 un->un_map[0].dkl_cylno = 0; 2269 un->un_map[0].dkl_nblk = un->un_solaris_size; 2270 2271 un->un_map[2].dkl_cylno = 0; 2272 un->un_map[2].dkl_nblk = un->un_solaris_size; 2273 2274 #elif defined(_SUNOS_VTOC_16) 2275 2276 if (un->un_solaris_size == 0) { 2277 /* 2278 * Got fdisk table but no solaris entry therefore 2279 * don't create a default label 2280 */ 2281 un->un_f_geometry_is_valid = TRUE; 2282 return; 2283 } 2284 2285 /* 2286 * For CDs we continue to use the physical geometry to calculate 2287 * number of cylinders. All other devices must convert the 2288 * physical geometry (cmlb_geom) to values that will fit 2289 * in a dk_geom structure. 2290 */ 2291 if (ISCD(un)) { 2292 phys_spc = un->un_pgeom.g_nhead * un->un_pgeom.g_nsect; 2293 } else { 2294 /* Convert physical geometry to disk geometry */ 2295 bzero(&un_g, sizeof (struct dk_geom)); 2296 cmlb_convert_geometry(un->un_blockcount, &un_g); 2297 bcopy(&un_g, &un->un_g, sizeof (un->un_g)); 2298 phys_spc = un->un_g.dkg_nhead * un->un_g.dkg_nsect; 2299 } 2300 2301 un->un_g.dkg_pcyl = un->un_solaris_size / phys_spc; 2302 un->un_g.dkg_acyl = DK_ACYL; 2303 un->un_g.dkg_ncyl = un->un_g.dkg_pcyl - DK_ACYL; 2304 disksize = un->un_g.dkg_ncyl * phys_spc; 2305 2306 if (ISCD(un)) { 2307 /* 2308 * CD's don't use the "heads * sectors * cyls"-type of 2309 * geometry, but instead use the entire capacity of the media. 2310 */ 2311 disksize = un->un_solaris_size; 2312 un->un_g.dkg_nhead = 1; 2313 un->un_g.dkg_nsect = 1; 2314 un->un_g.dkg_rpm = 2315 (un->un_pgeom.g_rpm == 0) ? 200 : un->un_pgeom.g_rpm; 2316 2317 un->un_vtoc.v_part[0].p_start = 0; 2318 un->un_vtoc.v_part[0].p_size = disksize; 2319 un->un_vtoc.v_part[0].p_tag = V_BACKUP; 2320 un->un_vtoc.v_part[0].p_flag = V_UNMNT; 2321 2322 un->un_map[0].dkl_cylno = 0; 2323 un->un_map[0].dkl_nblk = disksize; 2324 un->un_offset[0] = 0; 2325 2326 } else { 2327 /* 2328 * Hard disks and removable media cartridges 2329 */ 2330 un->un_g.dkg_rpm = 2331 (un->un_pgeom.g_rpm == 0) ? 3600: un->un_pgeom.g_rpm; 2332 un->un_vtoc.v_sectorsz = un->un_sys_blocksize; 2333 2334 /* Add boot slice */ 2335 un->un_vtoc.v_part[8].p_start = 0; 2336 un->un_vtoc.v_part[8].p_size = phys_spc; 2337 un->un_vtoc.v_part[8].p_tag = V_BOOT; 2338 un->un_vtoc.v_part[8].p_flag = V_UNMNT; 2339 2340 un->un_map[8].dkl_cylno = 0; 2341 un->un_map[8].dkl_nblk = phys_spc; 2342 un->un_offset[8] = 0; 2343 2344 if ((un->un_alter_behavior & 2345 CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT) && 2346 un->un_device_type == DTYPE_DIRECT) { 2347 un->un_vtoc.v_part[9].p_start = phys_spc; 2348 un->un_vtoc.v_part[9].p_size = 2 * phys_spc; 2349 un->un_vtoc.v_part[9].p_tag = V_ALTSCTR; 2350 un->un_vtoc.v_part[9].p_flag = 0; 2351 2352 un->un_map[9].dkl_cylno = 1; 2353 un->un_map[9].dkl_nblk = 2 * phys_spc; 2354 un->un_offset[9] = phys_spc; 2355 } 2356 } 2357 2358 un->un_g.dkg_apc = 0; 2359 un->un_vtoc.v_nparts = V_NUMPAR; 2360 un->un_vtoc.v_version = V_VERSION; 2361 2362 /* Add backup slice */ 2363 un->un_vtoc.v_part[2].p_start = 0; 2364 un->un_vtoc.v_part[2].p_size = disksize; 2365 un->un_vtoc.v_part[2].p_tag = V_BACKUP; 2366 un->un_vtoc.v_part[2].p_flag = V_UNMNT; 2367 2368 un->un_map[2].dkl_cylno = 0; 2369 un->un_map[2].dkl_nblk = disksize; 2370 un->un_offset[2] = 0; 2371 2372 (void) sprintf(un->un_vtoc.v_asciilabel, "DEFAULT cyl %d alt %d" 2373 " hd %d sec %d", un->un_g.dkg_ncyl, un->un_g.dkg_acyl, 2374 un->un_g.dkg_nhead, un->un_g.dkg_nsect); 2375 2376 #else 2377 #error "No VTOC format defined." 2378 #endif 2379 2380 un->un_g.dkg_read_reinstruct = 0; 2381 un->un_g.dkg_write_reinstruct = 0; 2382 2383 un->un_g.dkg_intrlv = 1; 2384 2385 un->un_vtoc.v_sanity = VTOC_SANE; 2386 2387 un->un_f_geometry_is_valid = TRUE; 2388 un->un_vtoc_label_is_from_media = 0; 2389 2390 cmlb_dbg(CMLB_INFO, un, 2391 "cmlb_build_default_label: Default label created: " 2392 "cyl: %d\tacyl: %d\tnhead: %d\tnsect: %d\tcap: %d\n", 2393 un->un_g.dkg_ncyl, un->un_g.dkg_acyl, un->un_g.dkg_nhead, 2394 un->un_g.dkg_nsect, un->un_blockcount); 2395 } 2396 2397 2398 #if defined(_FIRMWARE_NEEDS_FDISK) 2399 /* 2400 * Max CHS values, as they are encoded into bytes, for 1022/254/63 2401 */ 2402 #define LBA_MAX_SECT (63 | ((1022 & 0x300) >> 2)) 2403 #define LBA_MAX_CYL (1022 & 0xFF) 2404 #define LBA_MAX_HEAD (254) 2405 2406 2407 /* 2408 * Function: cmlb_has_max_chs_vals 2409 * 2410 * Description: Return TRUE if Cylinder-Head-Sector values are all at maximum. 2411 * 2412 * Arguments: fdp - ptr to CHS info 2413 * 2414 * Return Code: True or false 2415 * 2416 * Context: Any. 2417 */ 2418 static int 2419 cmlb_has_max_chs_vals(struct ipart *fdp) 2420 { 2421 return ((fdp->begcyl == LBA_MAX_CYL) && 2422 (fdp->beghead == LBA_MAX_HEAD) && 2423 (fdp->begsect == LBA_MAX_SECT) && 2424 (fdp->endcyl == LBA_MAX_CYL) && 2425 (fdp->endhead == LBA_MAX_HEAD) && 2426 (fdp->endsect == LBA_MAX_SECT)); 2427 } 2428 #endif 2429 2430 /* 2431 * Function: cmlb_dkio_get_geometry 2432 * 2433 * Description: This routine is the driver entry point for handling user 2434 * requests to get the device geometry (DKIOCGGEOM). 2435 * 2436 * Arguments: 2437 * arg - pointer to user provided dk_geom structure specifying 2438 * the controller's notion of the current geometry. 2439 * flag - this argument is a pass through to ddi_copyxxx() 2440 * directly from the mode argument of ioctl(). 2441 * 2442 * Return Code: 0 2443 * EFAULT 2444 * ENXIO 2445 * EIO 2446 */ 2447 static int 2448 cmlb_dkio_get_geometry(struct cmlb_lun *un, caddr_t arg, int flag) 2449 { 2450 struct dk_geom *tmp_geom = NULL; 2451 int rval = 0; 2452 2453 /* 2454 * cmlb_validate_geometry does not spin a disk up 2455 * if it was spun down. We need to make sure it 2456 * is ready. 2457 */ 2458 mutex_enter(CMLB_MUTEX(un)); 2459 rval = cmlb_validate_geometry(un, 1); 2460 #if defined(_SUNOS_VTOC_8) 2461 if (rval == EINVAL && 2462 un->un_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8) { 2463 /* 2464 * This is to return a default label geometry even when we 2465 * do not really assume a default label for the device. 2466 * dad driver utilizes this. 2467 */ 2468 if (un->un_blockcount <= DK_MAX_BLOCKS) { 2469 cmlb_setup_default_geometry(un); 2470 rval = 0; 2471 } 2472 } 2473 #endif 2474 if (rval) { 2475 mutex_exit(CMLB_MUTEX(un)); 2476 return (rval); 2477 } 2478 2479 #if defined(__i386) || defined(__amd64) 2480 if (un->un_solaris_size == 0) { 2481 mutex_exit(CMLB_MUTEX(un)); 2482 return (EIO); 2483 } 2484 #endif 2485 2486 /* 2487 * Make a local copy of the soft state geometry to avoid some potential 2488 * race conditions associated with holding the mutex and updating the 2489 * write_reinstruct value 2490 */ 2491 tmp_geom = kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP); 2492 bcopy(&un->un_g, tmp_geom, sizeof (struct dk_geom)); 2493 2494 if (tmp_geom->dkg_write_reinstruct == 0) { 2495 tmp_geom->dkg_write_reinstruct = 2496 (int)((int)(tmp_geom->dkg_nsect * tmp_geom->dkg_rpm * 2497 cmlb_rot_delay) / (int)60000); 2498 } 2499 mutex_exit(CMLB_MUTEX(un)); 2500 2501 rval = ddi_copyout(tmp_geom, (void *)arg, sizeof (struct dk_geom), 2502 flag); 2503 if (rval != 0) { 2504 rval = EFAULT; 2505 } 2506 2507 kmem_free(tmp_geom, sizeof (struct dk_geom)); 2508 return (rval); 2509 2510 } 2511 2512 2513 /* 2514 * Function: cmlb_dkio_set_geometry 2515 * 2516 * Description: This routine is the driver entry point for handling user 2517 * requests to set the device geometry (DKIOCSGEOM). The actual 2518 * device geometry is not updated, just the driver "notion" of it. 2519 * 2520 * Arguments: 2521 * arg - pointer to user provided dk_geom structure used to set 2522 * the controller's notion of the current geometry. 2523 * flag - this argument is a pass through to ddi_copyxxx() 2524 * directly from the mode argument of ioctl(). 2525 * 2526 * Return Code: 0 2527 * EFAULT 2528 * ENXIO 2529 * EIO 2530 */ 2531 static int 2532 cmlb_dkio_set_geometry(struct cmlb_lun *un, caddr_t arg, int flag) 2533 { 2534 struct dk_geom *tmp_geom; 2535 struct dk_map *lp; 2536 int rval = 0; 2537 int i; 2538 2539 2540 #if defined(__i386) || defined(__amd64) 2541 if (un->un_solaris_size == 0) { 2542 return (EIO); 2543 } 2544 #endif 2545 /* 2546 * We need to copy the user specified geometry into local 2547 * storage and then update the softstate. We don't want to hold 2548 * the mutex and copyin directly from the user to the soft state 2549 */ 2550 tmp_geom = (struct dk_geom *) 2551 kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP); 2552 rval = ddi_copyin(arg, tmp_geom, sizeof (struct dk_geom), flag); 2553 if (rval != 0) { 2554 kmem_free(tmp_geom, sizeof (struct dk_geom)); 2555 return (EFAULT); 2556 } 2557 2558 mutex_enter(CMLB_MUTEX(un)); 2559 bcopy(tmp_geom, &un->un_g, sizeof (struct dk_geom)); 2560 for (i = 0; i < NDKMAP; i++) { 2561 lp = &un->un_map[i]; 2562 un->un_offset[i] = 2563 un->un_g.dkg_nhead * un->un_g.dkg_nsect * lp->dkl_cylno; 2564 #if defined(__i386) || defined(__amd64) 2565 un->un_offset[i] += un->un_solaris_offset; 2566 #endif 2567 } 2568 un->un_f_geometry_is_valid = FALSE; 2569 mutex_exit(CMLB_MUTEX(un)); 2570 kmem_free(tmp_geom, sizeof (struct dk_geom)); 2571 2572 return (rval); 2573 } 2574 2575 /* 2576 * Function: cmlb_dkio_get_partition 2577 * 2578 * Description: This routine is the driver entry point for handling user 2579 * requests to get the partition table (DKIOCGAPART). 2580 * 2581 * Arguments: 2582 * arg - pointer to user provided dk_allmap structure specifying 2583 * the controller's notion of the current partition table. 2584 * flag - this argument is a pass through to ddi_copyxxx() 2585 * directly from the mode argument of ioctl(). 2586 * 2587 * Return Code: 0 2588 * EFAULT 2589 * ENXIO 2590 * EIO 2591 */ 2592 static int 2593 cmlb_dkio_get_partition(struct cmlb_lun *un, caddr_t arg, int flag) 2594 { 2595 int rval = 0; 2596 int size; 2597 2598 /* 2599 * Make sure the geometry is valid before getting the partition 2600 * information. 2601 */ 2602 mutex_enter(CMLB_MUTEX(un)); 2603 if ((rval = cmlb_validate_geometry(un, 1)) != 0) { 2604 mutex_exit(CMLB_MUTEX(un)); 2605 return (rval); 2606 } 2607 mutex_exit(CMLB_MUTEX(un)); 2608 2609 #if defined(__i386) || defined(__amd64) 2610 if (un->un_solaris_size == 0) { 2611 return (EIO); 2612 } 2613 #endif 2614 2615 #ifdef _MULTI_DATAMODEL 2616 switch (ddi_model_convert_from(flag & FMODELS)) { 2617 case DDI_MODEL_ILP32: { 2618 struct dk_map32 dk_map32[NDKMAP]; 2619 int i; 2620 2621 for (i = 0; i < NDKMAP; i++) { 2622 dk_map32[i].dkl_cylno = un->un_map[i].dkl_cylno; 2623 dk_map32[i].dkl_nblk = un->un_map[i].dkl_nblk; 2624 } 2625 size = NDKMAP * sizeof (struct dk_map32); 2626 rval = ddi_copyout(dk_map32, (void *)arg, size, flag); 2627 if (rval != 0) { 2628 rval = EFAULT; 2629 } 2630 break; 2631 } 2632 case DDI_MODEL_NONE: 2633 size = NDKMAP * sizeof (struct dk_map); 2634 rval = ddi_copyout(un->un_map, (void *)arg, size, flag); 2635 if (rval != 0) { 2636 rval = EFAULT; 2637 } 2638 break; 2639 } 2640 #else /* ! _MULTI_DATAMODEL */ 2641 size = NDKMAP * sizeof (struct dk_map); 2642 rval = ddi_copyout(un->un_map, (void *)arg, size, flag); 2643 if (rval != 0) { 2644 rval = EFAULT; 2645 } 2646 #endif /* _MULTI_DATAMODEL */ 2647 return (rval); 2648 } 2649 2650 /* 2651 * Function: cmlb_dkio_set_partition 2652 * 2653 * Description: This routine is the driver entry point for handling user 2654 * requests to set the partition table (DKIOCSAPART). The actual 2655 * device partition is not updated. 2656 * 2657 * Arguments: 2658 * arg - pointer to user provided dk_allmap structure used to set 2659 * the controller's notion of the partition table. 2660 * flag - this argument is a pass through to ddi_copyxxx() 2661 * directly from the mode argument of ioctl(). 2662 * 2663 * Return Code: 0 2664 * EINVAL 2665 * EFAULT 2666 * ENXIO 2667 * EIO 2668 */ 2669 static int 2670 cmlb_dkio_set_partition(struct cmlb_lun *un, caddr_t arg, int flag) 2671 { 2672 struct dk_map dk_map[NDKMAP]; 2673 struct dk_map *lp; 2674 int rval = 0; 2675 int size; 2676 int i; 2677 #if defined(_SUNOS_VTOC_16) 2678 struct dkl_partition *vp; 2679 #endif 2680 2681 /* 2682 * Set the map for all logical partitions. We lock 2683 * the priority just to make sure an interrupt doesn't 2684 * come in while the map is half updated. 2685 */ 2686 _NOTE(DATA_READABLE_WITHOUT_LOCK(cmlb_lun::un_solaris_size)) 2687 mutex_enter(CMLB_MUTEX(un)); 2688 2689 if (un->un_blockcount > DK_MAX_BLOCKS) { 2690 mutex_exit(CMLB_MUTEX(un)); 2691 return (ENOTSUP); 2692 } 2693 mutex_exit(CMLB_MUTEX(un)); 2694 if (un->un_solaris_size == 0) { 2695 return (EIO); 2696 } 2697 2698 #ifdef _MULTI_DATAMODEL 2699 switch (ddi_model_convert_from(flag & FMODELS)) { 2700 case DDI_MODEL_ILP32: { 2701 struct dk_map32 dk_map32[NDKMAP]; 2702 2703 size = NDKMAP * sizeof (struct dk_map32); 2704 rval = ddi_copyin((void *)arg, dk_map32, size, flag); 2705 if (rval != 0) { 2706 return (EFAULT); 2707 } 2708 for (i = 0; i < NDKMAP; i++) { 2709 dk_map[i].dkl_cylno = dk_map32[i].dkl_cylno; 2710 dk_map[i].dkl_nblk = dk_map32[i].dkl_nblk; 2711 } 2712 break; 2713 } 2714 case DDI_MODEL_NONE: 2715 size = NDKMAP * sizeof (struct dk_map); 2716 rval = ddi_copyin((void *)arg, dk_map, size, flag); 2717 if (rval != 0) { 2718 return (EFAULT); 2719 } 2720 break; 2721 } 2722 #else /* ! _MULTI_DATAMODEL */ 2723 size = NDKMAP * sizeof (struct dk_map); 2724 rval = ddi_copyin((void *)arg, dk_map, size, flag); 2725 if (rval != 0) { 2726 return (EFAULT); 2727 } 2728 #endif /* _MULTI_DATAMODEL */ 2729 2730 mutex_enter(CMLB_MUTEX(un)); 2731 /* Note: The size used in this bcopy is set based upon the data model */ 2732 bcopy(dk_map, un->un_map, size); 2733 #if defined(_SUNOS_VTOC_16) 2734 vp = (struct dkl_partition *)&(un->un_vtoc); 2735 #endif /* defined(_SUNOS_VTOC_16) */ 2736 for (i = 0; i < NDKMAP; i++) { 2737 lp = &un->un_map[i]; 2738 un->un_offset[i] = 2739 un->un_g.dkg_nhead * un->un_g.dkg_nsect * lp->dkl_cylno; 2740 #if defined(_SUNOS_VTOC_16) 2741 vp->p_start = un->un_offset[i]; 2742 vp->p_size = lp->dkl_nblk; 2743 vp++; 2744 #endif /* defined(_SUNOS_VTOC_16) */ 2745 #if defined(__i386) || defined(__amd64) 2746 un->un_offset[i] += un->un_solaris_offset; 2747 #endif 2748 } 2749 mutex_exit(CMLB_MUTEX(un)); 2750 return (rval); 2751 } 2752 2753 2754 /* 2755 * Function: cmlb_dkio_get_vtoc 2756 * 2757 * Description: This routine is the driver entry point for handling user 2758 * requests to get the current volume table of contents 2759 * (DKIOCGVTOC). 2760 * 2761 * Arguments: 2762 * arg - pointer to user provided vtoc structure specifying 2763 * the current vtoc. 2764 * flag - this argument is a pass through to ddi_copyxxx() 2765 * directly from the mode argument of ioctl(). 2766 * 2767 * Return Code: 0 2768 * EFAULT 2769 * ENXIO 2770 * EIO 2771 */ 2772 static int 2773 cmlb_dkio_get_vtoc(struct cmlb_lun *un, caddr_t arg, int flag) 2774 { 2775 #if defined(_SUNOS_VTOC_8) 2776 struct vtoc user_vtoc; 2777 #endif /* defined(_SUNOS_VTOC_8) */ 2778 int rval = 0; 2779 2780 mutex_enter(CMLB_MUTEX(un)); 2781 rval = cmlb_validate_geometry(un, 1); 2782 2783 #if defined(_SUNOS_VTOC_8) 2784 if (rval == EINVAL && 2785 (un->un_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8)) { 2786 /* 2787 * This is to return a default label even when we do not 2788 * really assume a default label for the device. 2789 * dad driver utilizes this. 2790 */ 2791 if (un->un_blockcount <= DK_MAX_BLOCKS) { 2792 cmlb_setup_default_geometry(un); 2793 rval = 0; 2794 } 2795 } 2796 #endif 2797 if (rval) { 2798 mutex_exit(CMLB_MUTEX(un)); 2799 return (rval); 2800 } 2801 2802 #if defined(_SUNOS_VTOC_8) 2803 cmlb_build_user_vtoc(un, &user_vtoc); 2804 mutex_exit(CMLB_MUTEX(un)); 2805 2806 #ifdef _MULTI_DATAMODEL 2807 switch (ddi_model_convert_from(flag & FMODELS)) { 2808 case DDI_MODEL_ILP32: { 2809 struct vtoc32 user_vtoc32; 2810 2811 vtoctovtoc32(user_vtoc, user_vtoc32); 2812 if (ddi_copyout(&user_vtoc32, (void *)arg, 2813 sizeof (struct vtoc32), flag)) { 2814 return (EFAULT); 2815 } 2816 break; 2817 } 2818 2819 case DDI_MODEL_NONE: 2820 if (ddi_copyout(&user_vtoc, (void *)arg, 2821 sizeof (struct vtoc), flag)) { 2822 return (EFAULT); 2823 } 2824 break; 2825 } 2826 #else /* ! _MULTI_DATAMODEL */ 2827 if (ddi_copyout(&user_vtoc, (void *)arg, sizeof (struct vtoc), flag)) { 2828 return (EFAULT); 2829 } 2830 #endif /* _MULTI_DATAMODEL */ 2831 2832 #elif defined(_SUNOS_VTOC_16) 2833 mutex_exit(CMLB_MUTEX(un)); 2834 2835 #ifdef _MULTI_DATAMODEL 2836 /* 2837 * The un_vtoc structure is a "struct dk_vtoc" which is always 2838 * 32-bit to maintain compatibility with existing on-disk 2839 * structures. Thus, we need to convert the structure when copying 2840 * it out to a datamodel-dependent "struct vtoc" in a 64-bit 2841 * program. If the target is a 32-bit program, then no conversion 2842 * is necessary. 2843 */ 2844 /* LINTED: logical expression always true: op "||" */ 2845 ASSERT(sizeof (un->un_vtoc) == sizeof (struct vtoc32)); 2846 switch (ddi_model_convert_from(flag & FMODELS)) { 2847 case DDI_MODEL_ILP32: 2848 if (ddi_copyout(&(un->un_vtoc), (void *)arg, 2849 sizeof (un->un_vtoc), flag)) { 2850 return (EFAULT); 2851 } 2852 break; 2853 2854 case DDI_MODEL_NONE: { 2855 struct vtoc user_vtoc; 2856 2857 vtoc32tovtoc(un->un_vtoc, user_vtoc); 2858 if (ddi_copyout(&user_vtoc, (void *)arg, 2859 sizeof (struct vtoc), flag)) { 2860 return (EFAULT); 2861 } 2862 break; 2863 } 2864 } 2865 #else /* ! _MULTI_DATAMODEL */ 2866 if (ddi_copyout(&(un->un_vtoc), (void *)arg, sizeof (un->un_vtoc), 2867 flag)) { 2868 return (EFAULT); 2869 } 2870 #endif /* _MULTI_DATAMODEL */ 2871 #else 2872 #error "No VTOC format defined." 2873 #endif 2874 2875 return (rval); 2876 } 2877 2878 static int 2879 cmlb_dkio_get_efi(struct cmlb_lun *un, caddr_t arg, int flag) 2880 { 2881 dk_efi_t user_efi; 2882 int rval = 0; 2883 void *buffer; 2884 2885 if (ddi_copyin(arg, &user_efi, sizeof (dk_efi_t), flag)) 2886 return (EFAULT); 2887 2888 user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64; 2889 2890 buffer = kmem_alloc(user_efi.dki_length, KM_SLEEP); 2891 rval = DK_TG_READ(un, buffer, user_efi.dki_lba, user_efi.dki_length); 2892 if (rval == 0 && ddi_copyout(buffer, user_efi.dki_data, 2893 user_efi.dki_length, flag) != 0) 2894 rval = EFAULT; 2895 2896 kmem_free(buffer, user_efi.dki_length); 2897 return (rval); 2898 } 2899 2900 /* 2901 * Function: cmlb_build_user_vtoc 2902 * 2903 * Description: This routine populates a pass by reference variable with the 2904 * current volume table of contents. 2905 * 2906 * Arguments: un - driver soft state (unit) structure 2907 * user_vtoc - pointer to vtoc structure to be populated 2908 */ 2909 static void 2910 cmlb_build_user_vtoc(struct cmlb_lun *un, struct vtoc *user_vtoc) 2911 { 2912 struct dk_map2 *lpart; 2913 struct dk_map *lmap; 2914 struct partition *vpart; 2915 int nblks; 2916 int i; 2917 2918 ASSERT(mutex_owned(CMLB_MUTEX(un))); 2919 2920 /* 2921 * Return vtoc structure fields in the provided VTOC area, addressed 2922 * by *vtoc. 2923 */ 2924 bzero(user_vtoc, sizeof (struct vtoc)); 2925 user_vtoc->v_bootinfo[0] = un->un_vtoc.v_bootinfo[0]; 2926 user_vtoc->v_bootinfo[1] = un->un_vtoc.v_bootinfo[1]; 2927 user_vtoc->v_bootinfo[2] = un->un_vtoc.v_bootinfo[2]; 2928 user_vtoc->v_sanity = VTOC_SANE; 2929 user_vtoc->v_version = un->un_vtoc.v_version; 2930 bcopy(un->un_vtoc.v_volume, user_vtoc->v_volume, LEN_DKL_VVOL); 2931 user_vtoc->v_sectorsz = un->un_sys_blocksize; 2932 user_vtoc->v_nparts = un->un_vtoc.v_nparts; 2933 2934 for (i = 0; i < 10; i++) 2935 user_vtoc->v_reserved[i] = un->un_vtoc.v_reserved[i]; 2936 2937 /* 2938 * Convert partitioning information. 2939 * 2940 * Note the conversion from starting cylinder number 2941 * to starting sector number. 2942 */ 2943 lmap = un->un_map; 2944 lpart = (struct dk_map2 *)un->un_vtoc.v_part; 2945 vpart = user_vtoc->v_part; 2946 2947 nblks = un->un_g.dkg_nsect * un->un_g.dkg_nhead; 2948 2949 for (i = 0; i < V_NUMPAR; i++) { 2950 vpart->p_tag = lpart->p_tag; 2951 vpart->p_flag = lpart->p_flag; 2952 vpart->p_start = lmap->dkl_cylno * nblks; 2953 vpart->p_size = lmap->dkl_nblk; 2954 lmap++; 2955 lpart++; 2956 vpart++; 2957 2958 /* (4364927) */ 2959 user_vtoc->timestamp[i] = (time_t)un->un_vtoc.v_timestamp[i]; 2960 } 2961 2962 bcopy(un->un_asciilabel, user_vtoc->v_asciilabel, LEN_DKL_ASCII); 2963 } 2964 2965 static int 2966 cmlb_dkio_partition(struct cmlb_lun *un, caddr_t arg, int flag) 2967 { 2968 struct partition64 p64; 2969 int rval = 0; 2970 uint_t nparts; 2971 efi_gpe_t *partitions; 2972 efi_gpt_t *buffer; 2973 diskaddr_t gpe_lba; 2974 2975 if (ddi_copyin((const void *)arg, &p64, 2976 sizeof (struct partition64), flag)) { 2977 return (EFAULT); 2978 } 2979 2980 buffer = kmem_alloc(EFI_MIN_ARRAY_SIZE, KM_SLEEP); 2981 rval = DK_TG_READ(un, buffer, 1, DEV_BSIZE); 2982 if (rval != 0) 2983 goto done_error; 2984 2985 cmlb_swap_efi_gpt(buffer); 2986 2987 if ((rval = cmlb_validate_efi(buffer)) != 0) 2988 goto done_error; 2989 2990 nparts = buffer->efi_gpt_NumberOfPartitionEntries; 2991 gpe_lba = buffer->efi_gpt_PartitionEntryLBA; 2992 if (p64.p_partno > nparts) { 2993 /* couldn't find it */ 2994 rval = ESRCH; 2995 goto done_error; 2996 } 2997 /* 2998 * if we're dealing with a partition that's out of the normal 2999 * 16K block, adjust accordingly 3000 */ 3001 gpe_lba += p64.p_partno / sizeof (efi_gpe_t); 3002 rval = DK_TG_READ(un, buffer, gpe_lba, EFI_MIN_ARRAY_SIZE); 3003 3004 if (rval) { 3005 goto done_error; 3006 } 3007 partitions = (efi_gpe_t *)buffer; 3008 3009 cmlb_swap_efi_gpe(nparts, partitions); 3010 3011 partitions += p64.p_partno; 3012 bcopy(&partitions->efi_gpe_PartitionTypeGUID, &p64.p_type, 3013 sizeof (struct uuid)); 3014 p64.p_start = partitions->efi_gpe_StartingLBA; 3015 p64.p_size = partitions->efi_gpe_EndingLBA - 3016 p64.p_start + 1; 3017 3018 if (ddi_copyout(&p64, (void *)arg, sizeof (struct partition64), flag)) 3019 rval = EFAULT; 3020 3021 done_error: 3022 kmem_free(buffer, EFI_MIN_ARRAY_SIZE); 3023 return (rval); 3024 } 3025 3026 3027 /* 3028 * Function: cmlb_dkio_set_vtoc 3029 * 3030 * Description: This routine is the driver entry point for handling user 3031 * requests to set the current volume table of contents 3032 * (DKIOCSVTOC). 3033 * 3034 * Arguments: dev - the device number 3035 * arg - pointer to user provided vtoc structure used to set the 3036 * current vtoc. 3037 * flag - this argument is a pass through to ddi_copyxxx() 3038 * directly from the mode argument of ioctl(). 3039 * 3040 * Return Code: 0 3041 * EFAULT 3042 * ENXIO 3043 * EINVAL 3044 * ENOTSUP 3045 */ 3046 static int 3047 cmlb_dkio_set_vtoc(struct cmlb_lun *un, dev_t dev, caddr_t arg, int flag) 3048 { 3049 struct vtoc user_vtoc; 3050 int rval = 0; 3051 3052 #ifdef _MULTI_DATAMODEL 3053 switch (ddi_model_convert_from(flag & FMODELS)) { 3054 case DDI_MODEL_ILP32: { 3055 struct vtoc32 user_vtoc32; 3056 3057 if (ddi_copyin((const void *)arg, &user_vtoc32, 3058 sizeof (struct vtoc32), flag)) { 3059 return (EFAULT); 3060 } 3061 vtoc32tovtoc(user_vtoc32, user_vtoc); 3062 break; 3063 } 3064 3065 case DDI_MODEL_NONE: 3066 if (ddi_copyin((const void *)arg, &user_vtoc, 3067 sizeof (struct vtoc), flag)) { 3068 return (EFAULT); 3069 } 3070 break; 3071 } 3072 #else /* ! _MULTI_DATAMODEL */ 3073 if (ddi_copyin((const void *)arg, &user_vtoc, 3074 sizeof (struct vtoc), flag)) { 3075 return (EFAULT); 3076 } 3077 #endif /* _MULTI_DATAMODEL */ 3078 3079 mutex_enter(CMLB_MUTEX(un)); 3080 if (un->un_blockcount > DK_MAX_BLOCKS) { 3081 mutex_exit(CMLB_MUTEX(un)); 3082 return (ENOTSUP); 3083 } 3084 if (un->un_g.dkg_ncyl == 0) { 3085 mutex_exit(CMLB_MUTEX(un)); 3086 return (EINVAL); 3087 } 3088 3089 mutex_exit(CMLB_MUTEX(un)); 3090 cmlb_clear_efi(un); 3091 ddi_remove_minor_node(CMLB_DEVINFO(un), "wd"); 3092 ddi_remove_minor_node(CMLB_DEVINFO(un), "wd,raw"); 3093 (void) ddi_create_minor_node(CMLB_DEVINFO(un), "h", 3094 S_IFBLK, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 3095 un->un_node_type, NULL); 3096 (void) ddi_create_minor_node(CMLB_DEVINFO(un), "h,raw", 3097 S_IFCHR, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 3098 un->un_node_type, NULL); 3099 mutex_enter(CMLB_MUTEX(un)); 3100 3101 if ((rval = cmlb_build_label_vtoc(un, &user_vtoc)) == 0) { 3102 if ((rval = cmlb_write_label(un)) == 0) { 3103 if (cmlb_validate_geometry(un, 1) != 0) { 3104 cmlb_dbg(CMLB_ERROR, un, 3105 "cmlb_dkio_set_vtoc: " 3106 "Failed validate geometry\n"); 3107 } 3108 } 3109 } 3110 mutex_exit(CMLB_MUTEX(un)); 3111 return (rval); 3112 } 3113 3114 3115 /* 3116 * Function: cmlb_build_label_vtoc 3117 * 3118 * Description: This routine updates the driver soft state current volume table 3119 * of contents based on a user specified vtoc. 3120 * 3121 * Arguments: un - driver soft state (unit) structure 3122 * user_vtoc - pointer to vtoc structure specifying vtoc to be used 3123 * to update the driver soft state. 3124 * 3125 * Return Code: 0 3126 * EINVAL 3127 */ 3128 static int 3129 cmlb_build_label_vtoc(struct cmlb_lun *un, struct vtoc *user_vtoc) 3130 { 3131 struct dk_map *lmap; 3132 struct partition *vpart; 3133 int nblks; 3134 #if defined(_SUNOS_VTOC_8) 3135 int ncyl; 3136 struct dk_map2 *lpart; 3137 #endif /* defined(_SUNOS_VTOC_8) */ 3138 int i; 3139 3140 ASSERT(mutex_owned(CMLB_MUTEX(un))); 3141 3142 /* Sanity-check the vtoc */ 3143 if (user_vtoc->v_sanity != VTOC_SANE || 3144 user_vtoc->v_sectorsz != un->un_sys_blocksize || 3145 user_vtoc->v_nparts != V_NUMPAR) { 3146 cmlb_dbg(CMLB_INFO, un, 3147 "cmlb_build_label_vtoc: vtoc not valid\n"); 3148 return (EINVAL); 3149 } 3150 3151 nblks = un->un_g.dkg_nsect * un->un_g.dkg_nhead; 3152 if (nblks == 0) { 3153 cmlb_dbg(CMLB_INFO, un, 3154 "cmlb_build_label_vtoc: geom nblks is 0\n"); 3155 return (EINVAL); 3156 } 3157 3158 #if defined(_SUNOS_VTOC_8) 3159 vpart = user_vtoc->v_part; 3160 for (i = 0; i < V_NUMPAR; i++) { 3161 if ((vpart->p_start % nblks) != 0) { 3162 cmlb_dbg(CMLB_INFO, un, 3163 "cmlb_build_label_vtoc: p_start not multiply of" 3164 "nblks part %d p_start %d nblks %d\n", i, 3165 vpart->p_start, nblks); 3166 return (EINVAL); 3167 } 3168 ncyl = vpart->p_start / nblks; 3169 ncyl += vpart->p_size / nblks; 3170 if ((vpart->p_size % nblks) != 0) { 3171 ncyl++; 3172 } 3173 if (ncyl > (int)un->un_g.dkg_ncyl) { 3174 cmlb_dbg(CMLB_INFO, un, 3175 "cmlb_build_label_vtoc: ncyl %d > dkg_ncyl %d" 3176 "p_size %ld p_start %ld nblks %d part number %d" 3177 "tag %d\n", 3178 ncyl, un->un_g.dkg_ncyl, vpart->p_size, 3179 vpart->p_start, nblks, 3180 i, vpart->p_tag); 3181 3182 return (EINVAL); 3183 } 3184 vpart++; 3185 } 3186 #endif /* defined(_SUNOS_VTOC_8) */ 3187 3188 /* Put appropriate vtoc structure fields into the disk label */ 3189 #if defined(_SUNOS_VTOC_16) 3190 /* 3191 * The vtoc is always a 32bit data structure to maintain the 3192 * on-disk format. Convert "in place" instead of doing bcopy. 3193 */ 3194 vtoctovtoc32((*user_vtoc), (*((struct vtoc32 *)&(un->un_vtoc)))); 3195 3196 /* 3197 * in the 16-slice vtoc, starting sectors are expressed in 3198 * numbers *relative* to the start of the Solaris fdisk partition. 3199 */ 3200 lmap = un->un_map; 3201 vpart = user_vtoc->v_part; 3202 3203 for (i = 0; i < (int)user_vtoc->v_nparts; i++, lmap++, vpart++) { 3204 lmap->dkl_cylno = vpart->p_start / nblks; 3205 lmap->dkl_nblk = vpart->p_size; 3206 } 3207 3208 #elif defined(_SUNOS_VTOC_8) 3209 3210 un->un_vtoc.v_bootinfo[0] = (uint32_t)user_vtoc->v_bootinfo[0]; 3211 un->un_vtoc.v_bootinfo[1] = (uint32_t)user_vtoc->v_bootinfo[1]; 3212 un->un_vtoc.v_bootinfo[2] = (uint32_t)user_vtoc->v_bootinfo[2]; 3213 3214 un->un_vtoc.v_sanity = (uint32_t)user_vtoc->v_sanity; 3215 un->un_vtoc.v_version = (uint32_t)user_vtoc->v_version; 3216 3217 bcopy(user_vtoc->v_volume, un->un_vtoc.v_volume, LEN_DKL_VVOL); 3218 3219 un->un_vtoc.v_nparts = user_vtoc->v_nparts; 3220 3221 for (i = 0; i < 10; i++) 3222 un->un_vtoc.v_reserved[i] = user_vtoc->v_reserved[i]; 3223 3224 /* 3225 * Note the conversion from starting sector number 3226 * to starting cylinder number. 3227 * Return error if division results in a remainder. 3228 */ 3229 lmap = un->un_map; 3230 lpart = un->un_vtoc.v_part; 3231 vpart = user_vtoc->v_part; 3232 3233 for (i = 0; i < (int)user_vtoc->v_nparts; i++) { 3234 lpart->p_tag = vpart->p_tag; 3235 lpart->p_flag = vpart->p_flag; 3236 lmap->dkl_cylno = vpart->p_start / nblks; 3237 lmap->dkl_nblk = vpart->p_size; 3238 3239 lmap++; 3240 lpart++; 3241 vpart++; 3242 3243 /* (4387723) */ 3244 #ifdef _LP64 3245 if (user_vtoc->timestamp[i] > TIME32_MAX) { 3246 un->un_vtoc.v_timestamp[i] = TIME32_MAX; 3247 } else { 3248 un->un_vtoc.v_timestamp[i] = user_vtoc->timestamp[i]; 3249 } 3250 #else 3251 un->un_vtoc.v_timestamp[i] = user_vtoc->timestamp[i]; 3252 #endif 3253 } 3254 3255 bcopy(user_vtoc->v_asciilabel, un->un_asciilabel, LEN_DKL_ASCII); 3256 #else 3257 #error "No VTOC format defined." 3258 #endif 3259 return (0); 3260 } 3261 3262 /* 3263 * Function: cmlb_clear_efi 3264 * 3265 * Description: This routine clears all EFI labels. 3266 * 3267 * Arguments: un - driver soft state (unit) structure 3268 * 3269 * Return Code: void 3270 */ 3271 static void 3272 cmlb_clear_efi(struct cmlb_lun *un) 3273 { 3274 efi_gpt_t *gpt; 3275 diskaddr_t cap; 3276 int rval; 3277 3278 ASSERT(!mutex_owned(CMLB_MUTEX(un))); 3279 3280 gpt = kmem_alloc(sizeof (efi_gpt_t), KM_SLEEP); 3281 3282 if (DK_TG_READ(un, gpt, 1, DEV_BSIZE) != 0) { 3283 goto done; 3284 } 3285 3286 cmlb_swap_efi_gpt(gpt); 3287 rval = cmlb_validate_efi(gpt); 3288 if (rval == 0) { 3289 /* clear primary */ 3290 bzero(gpt, sizeof (efi_gpt_t)); 3291 if (rval = DK_TG_WRITE(un, gpt, 1, EFI_LABEL_SIZE)) { 3292 cmlb_dbg(CMLB_INFO, un, 3293 "cmlb_clear_efi: clear primary label failed\n"); 3294 } 3295 } 3296 /* the backup */ 3297 rval = DK_TG_GETCAP(un, &cap); 3298 if (rval) { 3299 goto done; 3300 } 3301 3302 if ((rval = DK_TG_READ(un, gpt, cap - 1, EFI_LABEL_SIZE)) != 0) { 3303 goto done; 3304 } 3305 cmlb_swap_efi_gpt(gpt); 3306 rval = cmlb_validate_efi(gpt); 3307 if (rval == 0) { 3308 /* clear backup */ 3309 cmlb_dbg(CMLB_TRACE, un, 3310 "cmlb_clear_efi clear backup@%lu\n", cap - 1); 3311 bzero(gpt, sizeof (efi_gpt_t)); 3312 if ((rval = DK_TG_WRITE(un, gpt, cap - 1, EFI_LABEL_SIZE))) { 3313 cmlb_dbg(CMLB_INFO, un, 3314 "cmlb_clear_efi: clear backup label failed\n"); 3315 } 3316 } 3317 3318 done: 3319 kmem_free(gpt, sizeof (efi_gpt_t)); 3320 } 3321 3322 /* 3323 * Function: cmlb_set_vtoc 3324 * 3325 * Description: This routine writes data to the appropriate positions 3326 * 3327 * Arguments: un - driver soft state (unit) structure 3328 * dkl - the data to be written 3329 * 3330 * Return: void 3331 */ 3332 static int 3333 cmlb_set_vtoc(struct cmlb_lun *un, struct dk_label *dkl) 3334 { 3335 uint_t label_addr; 3336 int sec; 3337 int blk; 3338 int head; 3339 int cyl; 3340 int rval; 3341 3342 #if defined(__i386) || defined(__amd64) 3343 label_addr = un->un_solaris_offset + DK_LABEL_LOC; 3344 #else 3345 /* Write the primary label at block 0 of the solaris partition. */ 3346 label_addr = 0; 3347 #endif 3348 3349 rval = DK_TG_WRITE(un, dkl, label_addr, un->un_sys_blocksize); 3350 3351 if (rval != 0) { 3352 return (rval); 3353 } 3354 3355 /* 3356 * Calculate where the backup labels go. They are always on 3357 * the last alternate cylinder, but some older drives put them 3358 * on head 2 instead of the last head. They are always on the 3359 * first 5 odd sectors of the appropriate track. 3360 * 3361 * We have no choice at this point, but to believe that the 3362 * disk label is valid. Use the geometry of the disk 3363 * as described in the label. 3364 */ 3365 cyl = dkl->dkl_ncyl + dkl->dkl_acyl - 1; 3366 head = dkl->dkl_nhead - 1; 3367 3368 /* 3369 * Write and verify the backup labels. Make sure we don't try to 3370 * write past the last cylinder. 3371 */ 3372 for (sec = 1; ((sec < 5 * 2 + 1) && (sec < dkl->dkl_nsect)); sec += 2) { 3373 blk = (daddr_t)( 3374 (cyl * ((dkl->dkl_nhead * dkl->dkl_nsect) - dkl->dkl_apc)) + 3375 (head * dkl->dkl_nsect) + sec); 3376 #if defined(__i386) || defined(__amd64) 3377 blk += un->un_solaris_offset; 3378 #endif 3379 rval = DK_TG_WRITE(un, dkl, blk, un->un_sys_blocksize); 3380 cmlb_dbg(CMLB_INFO, un, 3381 "cmlb_set_vtoc: wrote backup label %d\n", blk); 3382 if (rval != 0) { 3383 goto exit; 3384 } 3385 } 3386 exit: 3387 return (rval); 3388 } 3389 3390 /* 3391 * Function: cmlb_clear_vtoc 3392 * 3393 * Description: This routine clears out the VTOC labels. 3394 * 3395 * Arguments: un - driver soft state (unit) structure 3396 * 3397 * Return: void 3398 */ 3399 static void 3400 cmlb_clear_vtoc(struct cmlb_lun *un) 3401 { 3402 struct dk_label *dkl; 3403 3404 mutex_exit(CMLB_MUTEX(un)); 3405 dkl = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP); 3406 mutex_enter(CMLB_MUTEX(un)); 3407 /* 3408 * cmlb_set_vtoc uses these fields in order to figure out 3409 * where to overwrite the backup labels 3410 */ 3411 dkl->dkl_apc = un->un_g.dkg_apc; 3412 dkl->dkl_ncyl = un->un_g.dkg_ncyl; 3413 dkl->dkl_acyl = un->un_g.dkg_acyl; 3414 dkl->dkl_nhead = un->un_g.dkg_nhead; 3415 dkl->dkl_nsect = un->un_g.dkg_nsect; 3416 mutex_exit(CMLB_MUTEX(un)); 3417 (void) cmlb_set_vtoc(un, dkl); 3418 kmem_free(dkl, sizeof (struct dk_label)); 3419 3420 mutex_enter(CMLB_MUTEX(un)); 3421 } 3422 3423 /* 3424 * Function: cmlb_write_label 3425 * 3426 * Description: This routine will validate and write the driver soft state vtoc 3427 * contents to the device. 3428 * 3429 * Arguments: un cmlb handle 3430 * 3431 * Return Code: the code returned by cmlb_send_scsi_cmd() 3432 * 0 3433 * EINVAL 3434 * ENXIO 3435 * ENOMEM 3436 */ 3437 static int 3438 cmlb_write_label(struct cmlb_lun *un) 3439 { 3440 struct dk_label *dkl; 3441 short sum; 3442 short *sp; 3443 int i; 3444 int rval; 3445 3446 ASSERT(mutex_owned(CMLB_MUTEX(un))); 3447 mutex_exit(CMLB_MUTEX(un)); 3448 dkl = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP); 3449 mutex_enter(CMLB_MUTEX(un)); 3450 3451 bcopy(&un->un_vtoc, &dkl->dkl_vtoc, sizeof (struct dk_vtoc)); 3452 dkl->dkl_rpm = un->un_g.dkg_rpm; 3453 dkl->dkl_pcyl = un->un_g.dkg_pcyl; 3454 dkl->dkl_apc = un->un_g.dkg_apc; 3455 dkl->dkl_intrlv = un->un_g.dkg_intrlv; 3456 dkl->dkl_ncyl = un->un_g.dkg_ncyl; 3457 dkl->dkl_acyl = un->un_g.dkg_acyl; 3458 dkl->dkl_nhead = un->un_g.dkg_nhead; 3459 dkl->dkl_nsect = un->un_g.dkg_nsect; 3460 3461 #if defined(_SUNOS_VTOC_8) 3462 dkl->dkl_obs1 = un->un_g.dkg_obs1; 3463 dkl->dkl_obs2 = un->un_g.dkg_obs2; 3464 dkl->dkl_obs3 = un->un_g.dkg_obs3; 3465 for (i = 0; i < NDKMAP; i++) { 3466 dkl->dkl_map[i].dkl_cylno = un->un_map[i].dkl_cylno; 3467 dkl->dkl_map[i].dkl_nblk = un->un_map[i].dkl_nblk; 3468 } 3469 bcopy(un->un_asciilabel, dkl->dkl_asciilabel, LEN_DKL_ASCII); 3470 #elif defined(_SUNOS_VTOC_16) 3471 dkl->dkl_skew = un->un_dkg_skew; 3472 #else 3473 #error "No VTOC format defined." 3474 #endif 3475 3476 dkl->dkl_magic = DKL_MAGIC; 3477 dkl->dkl_write_reinstruct = un->un_g.dkg_write_reinstruct; 3478 dkl->dkl_read_reinstruct = un->un_g.dkg_read_reinstruct; 3479 3480 /* Construct checksum for the new disk label */ 3481 sum = 0; 3482 sp = (short *)dkl; 3483 i = sizeof (struct dk_label) / sizeof (short); 3484 while (i--) { 3485 sum ^= *sp++; 3486 } 3487 dkl->dkl_cksum = sum; 3488 3489 mutex_exit(CMLB_MUTEX(un)); 3490 3491 rval = cmlb_set_vtoc(un, dkl); 3492 exit: 3493 kmem_free(dkl, sizeof (struct dk_label)); 3494 mutex_enter(CMLB_MUTEX(un)); 3495 return (rval); 3496 } 3497 3498 static int 3499 cmlb_dkio_set_efi(struct cmlb_lun *un, dev_t dev, caddr_t arg, int flag) 3500 { 3501 dk_efi_t user_efi; 3502 int rval = 0; 3503 void *buffer; 3504 3505 if (ddi_copyin(arg, &user_efi, sizeof (dk_efi_t), flag)) 3506 return (EFAULT); 3507 3508 user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64; 3509 3510 buffer = kmem_alloc(user_efi.dki_length, KM_SLEEP); 3511 if (ddi_copyin(user_efi.dki_data, buffer, user_efi.dki_length, flag)) { 3512 rval = EFAULT; 3513 } else { 3514 /* 3515 * let's clear the vtoc labels and clear the softstate 3516 * vtoc. 3517 */ 3518 mutex_enter(CMLB_MUTEX(un)); 3519 if (un->un_vtoc.v_sanity == VTOC_SANE) { 3520 cmlb_dbg(CMLB_TRACE, un, 3521 "cmlb_dkio_set_efi: CLEAR VTOC\n"); 3522 if (un->un_vtoc_label_is_from_media) 3523 cmlb_clear_vtoc(un); 3524 bzero(&un->un_vtoc, sizeof (struct dk_vtoc)); 3525 mutex_exit(CMLB_MUTEX(un)); 3526 ddi_remove_minor_node(CMLB_DEVINFO(un), "h"); 3527 ddi_remove_minor_node(CMLB_DEVINFO(un), "h,raw"); 3528 (void) ddi_create_minor_node(CMLB_DEVINFO(un), "wd", 3529 S_IFBLK, 3530 (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 3531 un->un_node_type, NULL); 3532 (void) ddi_create_minor_node(CMLB_DEVINFO(un), "wd,raw", 3533 S_IFCHR, 3534 (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 3535 un->un_node_type, NULL); 3536 } else 3537 mutex_exit(CMLB_MUTEX(un)); 3538 rval = DK_TG_WRITE(un, buffer, user_efi.dki_lba, 3539 user_efi.dki_length); 3540 if (rval == 0) { 3541 mutex_enter(CMLB_MUTEX(un)); 3542 un->un_f_geometry_is_valid = FALSE; 3543 mutex_exit(CMLB_MUTEX(un)); 3544 } 3545 } 3546 kmem_free(buffer, user_efi.dki_length); 3547 return (rval); 3548 } 3549 3550 /* 3551 * Function: cmlb_dkio_get_mboot 3552 * 3553 * Description: This routine is the driver entry point for handling user 3554 * requests to get the current device mboot (DKIOCGMBOOT) 3555 * 3556 * Arguments: 3557 * arg - pointer to user provided mboot structure specifying 3558 * the current mboot. 3559 * flag - this argument is a pass through to ddi_copyxxx() 3560 * directly from the mode argument of ioctl(). 3561 * 3562 * Return Code: 0 3563 * EINVAL 3564 * EFAULT 3565 * ENXIO 3566 */ 3567 static int 3568 cmlb_dkio_get_mboot(struct cmlb_lun *un, caddr_t arg, int flag) 3569 { 3570 struct mboot *mboot; 3571 int rval; 3572 size_t buffer_size; 3573 3574 3575 #if defined(_SUNOS_VTOC_8) 3576 if ((!ISREMOVABLE(un)) || (arg == NULL)) { 3577 #elif defined(_SUNOS_VTOC_16) 3578 if (arg == NULL) { 3579 #endif 3580 return (EINVAL); 3581 } 3582 3583 /* 3584 * Read the mboot block, located at absolute block 0 on the target. 3585 */ 3586 buffer_size = sizeof (struct mboot); 3587 3588 cmlb_dbg(CMLB_TRACE, un, 3589 "cmlb_dkio_get_mboot: allocation size: 0x%x\n", buffer_size); 3590 3591 mboot = kmem_zalloc(buffer_size, KM_SLEEP); 3592 if ((rval = DK_TG_READ(un, mboot, 0, buffer_size)) == 0) { 3593 if (ddi_copyout(mboot, (void *)arg, 3594 sizeof (struct mboot), flag) != 0) { 3595 rval = EFAULT; 3596 } 3597 } 3598 kmem_free(mboot, buffer_size); 3599 return (rval); 3600 } 3601 3602 3603 /* 3604 * Function: cmlb_dkio_set_mboot 3605 * 3606 * Description: This routine is the driver entry point for handling user 3607 * requests to validate and set the device master boot 3608 * (DKIOCSMBOOT). 3609 * 3610 * Arguments: 3611 * arg - pointer to user provided mboot structure used to set the 3612 * master boot. 3613 * flag - this argument is a pass through to ddi_copyxxx() 3614 * directly from the mode argument of ioctl(). 3615 * 3616 * Return Code: 0 3617 * EINVAL 3618 * EFAULT 3619 * ENXIO 3620 */ 3621 static int 3622 cmlb_dkio_set_mboot(struct cmlb_lun *un, caddr_t arg, int flag) 3623 { 3624 struct mboot *mboot = NULL; 3625 int rval; 3626 ushort_t magic; 3627 3628 3629 ASSERT(!mutex_owned(CMLB_MUTEX(un))); 3630 3631 #if defined(_SUNOS_VTOC_8) 3632 if (!ISREMOVABLE(un)) { 3633 return (EINVAL); 3634 } 3635 #endif 3636 3637 if (arg == NULL) { 3638 return (EINVAL); 3639 } 3640 3641 mboot = kmem_zalloc(sizeof (struct mboot), KM_SLEEP); 3642 3643 if (ddi_copyin((const void *)arg, mboot, 3644 sizeof (struct mboot), flag) != 0) { 3645 kmem_free(mboot, (size_t)(sizeof (struct mboot))); 3646 return (EFAULT); 3647 } 3648 3649 /* Is this really a master boot record? */ 3650 magic = LE_16(mboot->signature); 3651 if (magic != MBB_MAGIC) { 3652 kmem_free(mboot, (size_t)(sizeof (struct mboot))); 3653 return (EINVAL); 3654 } 3655 3656 rval = DK_TG_WRITE(un, mboot, 0, un->un_sys_blocksize); 3657 3658 mutex_enter(CMLB_MUTEX(un)); 3659 #if defined(__i386) || defined(__amd64) 3660 if (rval == 0) { 3661 /* 3662 * mboot has been written successfully. 3663 * update the fdisk and vtoc tables in memory 3664 */ 3665 rval = cmlb_update_fdisk_and_vtoc(un); 3666 if ((un->un_f_geometry_is_valid == FALSE) || (rval != 0)) { 3667 mutex_exit(CMLB_MUTEX(un)); 3668 kmem_free(mboot, (size_t)(sizeof (struct mboot))); 3669 return (rval); 3670 } 3671 } 3672 #else 3673 if (rval == 0) { 3674 /* 3675 * mboot has been written successfully. 3676 * set up the default geometry and VTOC 3677 */ 3678 if (un->un_blockcount <= DK_MAX_BLOCKS) 3679 cmlb_setup_default_geometry(un); 3680 } 3681 #endif 3682 mutex_exit(CMLB_MUTEX(un)); 3683 kmem_free(mboot, (size_t)(sizeof (struct mboot))); 3684 return (rval); 3685 } 3686 3687 3688 /* 3689 * Function: cmlb_setup_default_geometry 3690 * 3691 * Description: This local utility routine sets the default geometry as part of 3692 * setting the device mboot. 3693 * 3694 * Arguments: un - driver soft state (unit) structure 3695 * 3696 * Note: This may be redundant with cmlb_build_default_label. 3697 */ 3698 static void 3699 cmlb_setup_default_geometry(struct cmlb_lun *un) 3700 { 3701 struct cmlb_geom pgeom; 3702 struct cmlb_geom *pgeomp = &pgeom; 3703 int ret; 3704 int geom_base_cap = 1; 3705 3706 3707 ASSERT(mutex_owned(CMLB_MUTEX(un))); 3708 3709 /* zero out the soft state geometry and partition table. */ 3710 bzero(&un->un_g, sizeof (struct dk_geom)); 3711 bzero(&un->un_vtoc, sizeof (struct dk_vtoc)); 3712 bzero(un->un_map, NDKMAP * (sizeof (struct dk_map))); 3713 3714 /* 3715 * For the rpm, we use the minimum for the disk. 3716 * For the head, cyl and number of sector per track, 3717 * if the capacity <= 1GB, head = 64, sect = 32. 3718 * else head = 255, sect 63 3719 * Note: the capacity should be equal to C*H*S values. 3720 * This will cause some truncation of size due to 3721 * round off errors. For CD-ROMs, this truncation can 3722 * have adverse side effects, so returning ncyl and 3723 * nhead as 1. The nsect will overflow for most of 3724 * CD-ROMs as nsect is of type ushort. 3725 */ 3726 if (un->un_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8) { 3727 /* 3728 * newfs currently can not handle 255 ntracks for SPARC 3729 * so get the geometry from target driver instead of coming up 3730 * with one based on capacity. 3731 */ 3732 mutex_exit(CMLB_MUTEX(un)); 3733 ret = DK_TG_GETPHYGEOM(un, pgeomp); 3734 mutex_enter(CMLB_MUTEX(un)); 3735 3736 if (ret == 0) { 3737 geom_base_cap = 0; 3738 } else { 3739 cmlb_dbg(CMLB_ERROR, un, 3740 "cmlb_setup_default_geometry: " 3741 "tg_getphygeom failed %d\n", ret); 3742 3743 /* do default setting, geometry based on capacity */ 3744 } 3745 } 3746 3747 if (geom_base_cap) { 3748 if (ISCD(un)) { 3749 un->un_g.dkg_ncyl = 1; 3750 un->un_g.dkg_nhead = 1; 3751 un->un_g.dkg_nsect = un->un_blockcount; 3752 } else if (un->un_blockcount <= 0x1000) { 3753 /* Needed for unlabeled SCSI floppies. */ 3754 un->un_g.dkg_nhead = 2; 3755 un->un_g.dkg_ncyl = 80; 3756 un->un_g.dkg_pcyl = 80; 3757 un->un_g.dkg_nsect = un->un_blockcount / (2 * 80); 3758 } else if (un->un_blockcount <= 0x200000) { 3759 un->un_g.dkg_nhead = 64; 3760 un->un_g.dkg_nsect = 32; 3761 un->un_g.dkg_ncyl = un->un_blockcount / (64 * 32); 3762 } else { 3763 un->un_g.dkg_nhead = 255; 3764 un->un_g.dkg_nsect = 63; 3765 un->un_g.dkg_ncyl = un->un_blockcount / (255 * 63); 3766 } 3767 3768 un->un_g.dkg_acyl = 0; 3769 un->un_g.dkg_bcyl = 0; 3770 un->un_g.dkg_intrlv = 1; 3771 un->un_g.dkg_rpm = 200; 3772 if (un->un_g.dkg_pcyl == 0) 3773 un->un_g.dkg_pcyl = un->un_g.dkg_ncyl + 3774 un->un_g.dkg_acyl; 3775 } else { 3776 un->un_g.dkg_ncyl = (short)pgeomp->g_ncyl; 3777 un->un_g.dkg_acyl = pgeomp->g_acyl; 3778 un->un_g.dkg_nhead = pgeomp->g_nhead; 3779 un->un_g.dkg_nsect = pgeomp->g_nsect; 3780 un->un_g.dkg_intrlv = pgeomp->g_intrlv; 3781 un->un_g.dkg_rpm = pgeomp->g_rpm; 3782 un->un_g.dkg_pcyl = un->un_g.dkg_ncyl + un->un_g.dkg_acyl; 3783 } 3784 3785 un->un_g.dkg_read_reinstruct = 0; 3786 un->un_g.dkg_write_reinstruct = 0; 3787 un->un_solaris_size = un->un_g.dkg_ncyl * 3788 un->un_g.dkg_nhead * un->un_g.dkg_nsect; 3789 3790 un->un_map['a'-'a'].dkl_cylno = 0; 3791 un->un_map['a'-'a'].dkl_nblk = un->un_solaris_size; 3792 3793 un->un_map['c'-'a'].dkl_cylno = 0; 3794 un->un_map['c'-'a'].dkl_nblk = un->un_solaris_size; 3795 3796 un->un_vtoc.v_part[2].p_tag = V_BACKUP; 3797 un->un_vtoc.v_part[2].p_flag = V_UNMNT; 3798 un->un_vtoc.v_nparts = V_NUMPAR; 3799 un->un_vtoc.v_version = V_VERSION; 3800 (void) sprintf((char *)un->un_asciilabel, "DEFAULT cyl %d alt %d" 3801 " hd %d sec %d", un->un_g.dkg_ncyl, un->un_g.dkg_acyl, 3802 un->un_g.dkg_nhead, un->un_g.dkg_nsect); 3803 3804 un->un_f_geometry_is_valid = FALSE; 3805 } 3806 3807 3808 #if defined(__i386) || defined(__amd64) 3809 /* 3810 * Function: cmlb_update_fdisk_and_vtoc 3811 * 3812 * Description: This local utility routine updates the device fdisk and vtoc 3813 * as part of setting the device mboot. 3814 * 3815 * Arguments: un - driver soft state (unit) structure 3816 * 3817 * Return Code: 0 for success or errno-type return code. 3818 * 3819 * Note:x86: This looks like a duplicate of cmlb_validate_geometry(), but 3820 * these did exist separately in x86 sd.c. 3821 */ 3822 static int 3823 cmlb_update_fdisk_and_vtoc(struct cmlb_lun *un) 3824 { 3825 int count; 3826 int label_rc = 0; 3827 int fdisk_rval; 3828 diskaddr_t capacity; 3829 3830 ASSERT(mutex_owned(CMLB_MUTEX(un))); 3831 3832 if (cmlb_check_update_blockcount(un) != 0) 3833 return (EINVAL); 3834 3835 #if defined(_SUNOS_VTOC_16) 3836 /* 3837 * Set up the "whole disk" fdisk partition; this should always 3838 * exist, regardless of whether the disk contains an fdisk table 3839 * or vtoc. 3840 */ 3841 un->un_map[P0_RAW_DISK].dkl_cylno = 0; 3842 un->un_map[P0_RAW_DISK].dkl_nblk = un->un_blockcount; 3843 #endif /* defined(_SUNOS_VTOC_16) */ 3844 3845 /* 3846 * copy the lbasize and capacity so that if they're 3847 * reset while we're not holding the CMLB_MUTEX(un), we will 3848 * continue to use valid values after the CMLB_MUTEX(un) is 3849 * reacquired. 3850 */ 3851 capacity = un->un_blockcount; 3852 3853 /* 3854 * refresh the logical and physical geometry caches. 3855 * (data from mode sense format/rigid disk geometry pages, 3856 * and scsi_ifgetcap("geometry"). 3857 */ 3858 cmlb_resync_geom_caches(un, capacity); 3859 3860 /* 3861 * Only DIRECT ACCESS devices will have Sun labels. 3862 * CD's supposedly have a Sun label, too 3863 */ 3864 if (un->un_device_type == DTYPE_DIRECT || ISREMOVABLE(un)) { 3865 fdisk_rval = cmlb_read_fdisk(un, capacity); 3866 if (fdisk_rval != 0) { 3867 ASSERT(mutex_owned(CMLB_MUTEX(un))); 3868 return (fdisk_rval); 3869 } 3870 3871 if (un->un_solaris_size <= DK_LABEL_LOC) { 3872 /* 3873 * Found fdisk table but no Solaris partition entry, 3874 * so don't call cmlb_uselabel() and don't create 3875 * a default label. 3876 */ 3877 label_rc = 0; 3878 un->un_f_geometry_is_valid = TRUE; 3879 goto no_solaris_partition; 3880 } 3881 } else if (capacity < 0) { 3882 ASSERT(mutex_owned(CMLB_MUTEX(un))); 3883 return (EINVAL); 3884 } 3885 3886 /* 3887 * For Removable media We reach here if we have found a 3888 * SOLARIS PARTITION. 3889 * If un_f_geometry_is_valid is FALSE it indicates that the SOLARIS 3890 * PARTITION has changed from the previous one, hence we will setup a 3891 * default VTOC in this case. 3892 */ 3893 if (un->un_f_geometry_is_valid == FALSE) { 3894 /* if we get here it is writable */ 3895 /* we are called from SMBOOT, and after a write of fdisk */ 3896 cmlb_build_default_label(un); 3897 label_rc = 0; 3898 } 3899 3900 no_solaris_partition: 3901 3902 #if defined(_SUNOS_VTOC_16) 3903 /* 3904 * If we have valid geometry, set up the remaining fdisk partitions. 3905 * Note that dkl_cylno is not used for the fdisk map entries, so 3906 * we set it to an entirely bogus value. 3907 */ 3908 for (count = 0; count < FD_NUMPART; count++) { 3909 un->un_map[FDISK_P1 + count].dkl_cylno = -1; 3910 un->un_map[FDISK_P1 + count].dkl_nblk = 3911 un->un_fmap[count].fmap_nblk; 3912 un->un_offset[FDISK_P1 + count] = 3913 un->un_fmap[count].fmap_start; 3914 } 3915 #endif 3916 3917 for (count = 0; count < NDKMAP; count++) { 3918 #if defined(_SUNOS_VTOC_8) 3919 struct dk_map *lp = &un->un_map[count]; 3920 un->un_offset[count] = 3921 un->un_g.dkg_nhead * un->un_g.dkg_nsect * lp->dkl_cylno; 3922 #elif defined(_SUNOS_VTOC_16) 3923 struct dkl_partition *vp = &un->un_vtoc.v_part[count]; 3924 un->un_offset[count] = vp->p_start + un->un_solaris_offset; 3925 #else 3926 #error "No VTOC format defined." 3927 #endif 3928 } 3929 3930 ASSERT(mutex_owned(CMLB_MUTEX(un))); 3931 return (label_rc); 3932 } 3933 #endif 3934 3935 #if defined(__i386) || defined(__amd64) 3936 static int 3937 cmlb_dkio_get_virtgeom(struct cmlb_lun *un, caddr_t arg, int flag) 3938 { 3939 int err = 0; 3940 3941 /* Return the driver's notion of the media's logical geometry */ 3942 struct dk_geom disk_geom; 3943 struct dk_geom *dkgp = &disk_geom; 3944 3945 mutex_enter(CMLB_MUTEX(un)); 3946 /* 3947 * If there is no HBA geometry available, or 3948 * if the HBA returned us something that doesn't 3949 * really fit into an Int 13/function 8 geometry 3950 * result, just fail the ioctl. See PSARC 1998/313. 3951 */ 3952 if (un->un_lgeom.g_nhead == 0 || 3953 un->un_lgeom.g_nsect == 0 || 3954 un->un_lgeom.g_ncyl > 1024) { 3955 mutex_exit(CMLB_MUTEX(un)); 3956 err = EINVAL; 3957 } else { 3958 dkgp->dkg_ncyl = un->un_lgeom.g_ncyl; 3959 dkgp->dkg_acyl = un->un_lgeom.g_acyl; 3960 dkgp->dkg_pcyl = dkgp->dkg_ncyl + dkgp->dkg_acyl; 3961 dkgp->dkg_nhead = un->un_lgeom.g_nhead; 3962 dkgp->dkg_nsect = un->un_lgeom.g_nsect; 3963 3964 if (ddi_copyout(dkgp, (void *)arg, 3965 sizeof (struct dk_geom), flag)) { 3966 mutex_exit(CMLB_MUTEX(un)); 3967 err = EFAULT; 3968 } else { 3969 mutex_exit(CMLB_MUTEX(un)); 3970 err = 0; 3971 } 3972 } 3973 return (err); 3974 } 3975 #endif 3976 3977 #if defined(__i386) || defined(__amd64) 3978 static int 3979 cmlb_dkio_get_phygeom(struct cmlb_lun *un, caddr_t arg, int flag) 3980 { 3981 int err = 0; 3982 3983 3984 /* Return the driver's notion of the media physical geometry */ 3985 struct dk_geom disk_geom; 3986 struct dk_geom *dkgp = &disk_geom; 3987 3988 mutex_enter(CMLB_MUTEX(un)); 3989 3990 if (un->un_g.dkg_nhead != 0 && 3991 un->un_g.dkg_nsect != 0) { 3992 /* 3993 * We succeeded in getting a geometry, but 3994 * right now it is being reported as just the 3995 * Solaris fdisk partition, just like for 3996 * DKIOCGGEOM. We need to change that to be 3997 * correct for the entire disk now. 3998 */ 3999 bcopy(&un->un_g, dkgp, sizeof (*dkgp)); 4000 dkgp->dkg_acyl = 0; 4001 dkgp->dkg_ncyl = un->un_blockcount / 4002 (dkgp->dkg_nhead * dkgp->dkg_nsect); 4003 } else { 4004 bzero(dkgp, sizeof (struct dk_geom)); 4005 /* 4006 * This disk does not have a Solaris VTOC 4007 * so we must present a physical geometry 4008 * that will remain consistent regardless 4009 * of how the disk is used. This will ensure 4010 * that the geometry does not change regardless 4011 * of the fdisk partition type (ie. EFI, FAT32, 4012 * Solaris, etc). 4013 */ 4014 if (ISCD(un)) { 4015 dkgp->dkg_nhead = un->un_pgeom.g_nhead; 4016 dkgp->dkg_nsect = un->un_pgeom.g_nsect; 4017 dkgp->dkg_ncyl = un->un_pgeom.g_ncyl; 4018 dkgp->dkg_acyl = un->un_pgeom.g_acyl; 4019 } else { 4020 cmlb_convert_geometry(un->un_blockcount, dkgp); 4021 dkgp->dkg_acyl = 0; 4022 dkgp->dkg_ncyl = un->un_blockcount / 4023 (dkgp->dkg_nhead * dkgp->dkg_nsect); 4024 } 4025 } 4026 dkgp->dkg_pcyl = dkgp->dkg_ncyl + dkgp->dkg_acyl; 4027 4028 if (ddi_copyout(dkgp, (void *)arg, 4029 sizeof (struct dk_geom), flag)) { 4030 mutex_exit(CMLB_MUTEX(un)); 4031 err = EFAULT; 4032 } else { 4033 mutex_exit(CMLB_MUTEX(un)); 4034 err = 0; 4035 } 4036 return (err); 4037 } 4038 #endif 4039 4040 #if defined(__i386) || defined(__amd64) 4041 static int 4042 cmlb_dkio_partinfo(struct cmlb_lun *un, dev_t dev, caddr_t arg, int flag) 4043 { 4044 int err = 0; 4045 4046 /* 4047 * Return parameters describing the selected disk slice. 4048 * Note: this ioctl is for the intel platform only 4049 */ 4050 int part; 4051 4052 part = CMLBPART(dev); 4053 4054 /* don't check un_solaris_size for pN */ 4055 if (part < P0_RAW_DISK && un->un_solaris_size == 0) { 4056 err = EIO; 4057 } else { 4058 struct part_info p; 4059 4060 p.p_start = (daddr_t)un->un_offset[part]; 4061 p.p_length = (int)un->un_map[part].dkl_nblk; 4062 #ifdef _MULTI_DATAMODEL 4063 switch (ddi_model_convert_from(flag & FMODELS)) { 4064 case DDI_MODEL_ILP32: 4065 { 4066 struct part_info32 p32; 4067 4068 p32.p_start = (daddr32_t)p.p_start; 4069 p32.p_length = p.p_length; 4070 if (ddi_copyout(&p32, (void *)arg, 4071 sizeof (p32), flag)) 4072 err = EFAULT; 4073 break; 4074 } 4075 4076 case DDI_MODEL_NONE: 4077 { 4078 if (ddi_copyout(&p, (void *)arg, sizeof (p), 4079 flag)) 4080 err = EFAULT; 4081 break; 4082 } 4083 } 4084 #else /* ! _MULTI_DATAMODEL */ 4085 if (ddi_copyout(&p, (void *)arg, sizeof (p), flag)) 4086 err = EFAULT; 4087 #endif /* _MULTI_DATAMODEL */ 4088 } 4089 return (err); 4090 } 4091 #endif 4092