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