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 if (!cl->cl_is_removable) { 1291 cl->cl_sys_blocksize = lbasize; 1292 } 1293 return (0); 1294 } else { 1295 return (EIO); 1296 } 1297 } 1298 1299 static int 1300 cmlb_create_minor(dev_info_t *dip, char *name, int spec_type, 1301 minor_t minor_num, char *node_type, int flag, boolean_t internal) 1302 { 1303 ASSERT(VALID_BOOLEAN(internal)); 1304 1305 if (internal) 1306 return (ddi_create_internal_pathname(dip, 1307 name, spec_type, minor_num)); 1308 else 1309 return (ddi_create_minor_node(dip, 1310 name, spec_type, minor_num, node_type, flag)); 1311 } 1312 1313 /* 1314 * Function: cmlb_create_minor_nodes 1315 * 1316 * Description: Create or adjust the minor device nodes for the instance. 1317 * Minor nodes are created based on default label type, 1318 * current label type and last label type we created 1319 * minor nodes based on. 1320 * 1321 * 1322 * Arguments: cl - driver soft state (unit) structure 1323 * 1324 * Return Code: 0 success 1325 * ENXIO failure. 1326 * 1327 * Context: Kernel thread context 1328 */ 1329 static int 1330 cmlb_create_minor_nodes(struct cmlb_lun *cl) 1331 { 1332 struct driver_minor_data *dmdp; 1333 int instance; 1334 char name[48]; 1335 cmlb_label_t newlabeltype; 1336 boolean_t internal; 1337 1338 ASSERT(cl != NULL); 1339 ASSERT(mutex_owned(CMLB_MUTEX(cl))); 1340 1341 internal = VOID2BOOLEAN( 1342 (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0); 1343 1344 /* check the most common case */ 1345 if (cl->cl_cur_labeltype != CMLB_LABEL_UNDEF && 1346 cl->cl_last_labeltype == cl->cl_cur_labeltype) { 1347 /* do nothing */ 1348 return (0); 1349 } 1350 1351 if (cl->cl_def_labeltype == CMLB_LABEL_UNDEF) { 1352 /* we should never get here */ 1353 return (ENXIO); 1354 } 1355 1356 if (cl->cl_last_labeltype == CMLB_LABEL_UNDEF) { 1357 /* first time during attach */ 1358 newlabeltype = cl->cl_def_labeltype; 1359 1360 instance = ddi_get_instance(CMLB_DEVINFO(cl)); 1361 1362 /* Create all the minor nodes for this target. */ 1363 dmdp = (newlabeltype == CMLB_LABEL_EFI) ? dk_minor_data_efi : 1364 dk_minor_data; 1365 while (dmdp->name != NULL) { 1366 1367 (void) sprintf(name, "%s", dmdp->name); 1368 1369 if (cmlb_create_minor(CMLB_DEVINFO(cl), name, 1370 dmdp->type, 1371 (instance << CMLBUNIT_SHIFT) | dmdp->minor, 1372 cl->cl_node_type, NULL, internal) == DDI_FAILURE) { 1373 /* 1374 * Clean up any nodes that may have been 1375 * created, in case this fails in the middle 1376 * of the loop. 1377 */ 1378 ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL); 1379 return (ENXIO); 1380 } 1381 dmdp++; 1382 } 1383 cl->cl_last_labeltype = newlabeltype; 1384 return (0); 1385 } 1386 1387 /* Not first time */ 1388 if (cl->cl_cur_labeltype == CMLB_LABEL_UNDEF) { 1389 if (cl->cl_last_labeltype != cl->cl_def_labeltype) { 1390 /* close time, revert to default. */ 1391 newlabeltype = cl->cl_def_labeltype; 1392 } else { 1393 /* 1394 * do nothing since the type for which we last created 1395 * nodes matches the default 1396 */ 1397 return (0); 1398 } 1399 } else { 1400 if (cl->cl_cur_labeltype != cl->cl_last_labeltype) { 1401 /* We are not closing, use current label type */ 1402 newlabeltype = cl->cl_cur_labeltype; 1403 } else { 1404 /* 1405 * do nothing since the type for which we last created 1406 * nodes matches the current label type 1407 */ 1408 return (0); 1409 } 1410 } 1411 1412 instance = ddi_get_instance(CMLB_DEVINFO(cl)); 1413 1414 /* 1415 * Currently we only fix up the s7 node when we are switching 1416 * label types from or to EFI. This is consistent with 1417 * current behavior of sd. 1418 */ 1419 if (newlabeltype == CMLB_LABEL_EFI && 1420 cl->cl_last_labeltype != CMLB_LABEL_EFI) { 1421 /* from vtoc to EFI */ 1422 ddi_remove_minor_node(CMLB_DEVINFO(cl), "h"); 1423 ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw"); 1424 (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd", 1425 S_IFBLK, (instance << CMLBUNIT_SHIFT) | WD_NODE, 1426 cl->cl_node_type, NULL, internal); 1427 (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd,raw", 1428 S_IFCHR, (instance << CMLBUNIT_SHIFT) | WD_NODE, 1429 cl->cl_node_type, NULL, internal); 1430 } else { 1431 /* from efi to vtoc */ 1432 ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd"); 1433 ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd,raw"); 1434 (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h", 1435 S_IFBLK, (instance << CMLBUNIT_SHIFT) | WD_NODE, 1436 cl->cl_node_type, NULL, internal); 1437 (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h,raw", 1438 S_IFCHR, (instance << CMLBUNIT_SHIFT) | WD_NODE, 1439 cl->cl_node_type, NULL, internal); 1440 } 1441 1442 cl->cl_last_labeltype = newlabeltype; 1443 return (0); 1444 } 1445 1446 /* 1447 * Function: cmlb_validate_geometry 1448 * 1449 * Description: Read the label from the disk (if present). Update the unit's 1450 * geometry and vtoc information from the data in the label. 1451 * Verify that the label is valid. 1452 * 1453 * Arguments: 1454 * cl driver soft state (unit) structure 1455 * 1456 * forcerevalid force revalidation even if we are already valid. 1457 * flags operation flags from target driver. Used for verbosity 1458 * control at this time. 1459 * tg_cookie cookie from target driver to be passed back to target 1460 * driver when we call back to it through tg_ops. 1461 * 1462 * Return Code: 0 - Successful completion 1463 * EINVAL - Invalid value in cl->cl_tgt_blocksize or 1464 * cl->cl_blockcount; or label on disk is corrupted 1465 * or unreadable. 1466 * EACCES - Reservation conflict at the device. 1467 * ENOMEM - Resource allocation error 1468 * ENOTSUP - geometry not applicable 1469 * 1470 * Context: Kernel thread only (can sleep). 1471 */ 1472 static int 1473 cmlb_validate_geometry(struct cmlb_lun *cl, boolean_t forcerevalid, int flags, 1474 void *tg_cookie) 1475 { 1476 int label_error = 0; 1477 diskaddr_t capacity; 1478 int count; 1479 1480 ASSERT(mutex_owned(CMLB_MUTEX(cl))); 1481 ASSERT(VALID_BOOLEAN(forcerevalid)); 1482 1483 if ((cl->cl_f_geometry_is_valid) && (!forcerevalid)) { 1484 if (cl->cl_cur_labeltype == CMLB_LABEL_EFI) 1485 return (ENOTSUP); 1486 return (0); 1487 } 1488 1489 if (cmlb_check_update_blockcount(cl, tg_cookie) != 0) 1490 return (EIO); 1491 1492 capacity = cl->cl_blockcount; 1493 1494 #if defined(_SUNOS_VTOC_16) 1495 /* 1496 * Set up the "whole disk" fdisk partition; this should always 1497 * exist, regardless of whether the disk contains an fdisk table 1498 * or vtoc. 1499 */ 1500 cl->cl_map[P0_RAW_DISK].dkl_cylno = 0; 1501 cl->cl_offset[P0_RAW_DISK] = 0; 1502 /* 1503 * note if capacity > int32_max(1TB) we are in 64bit environment 1504 * so no truncation happens 1505 */ 1506 cl->cl_map[P0_RAW_DISK].dkl_nblk = capacity; 1507 #endif 1508 /* 1509 * Refresh the logical and physical geometry caches. 1510 * (data from MODE SENSE format/rigid disk geometry pages, 1511 * and scsi_ifgetcap("geometry"). 1512 */ 1513 cmlb_resync_geom_caches(cl, capacity, tg_cookie); 1514 1515 cl->cl_label_from_media = CMLB_LABEL_UNDEF; 1516 label_error = cmlb_use_efi(cl, capacity, flags, tg_cookie); 1517 if (label_error == 0) { 1518 1519 /* found a valid EFI label */ 1520 cmlb_dbg(CMLB_TRACE, cl, 1521 "cmlb_validate_geometry: found EFI label\n"); 1522 /* 1523 * solaris_size and geometry_is_valid are set in 1524 * cmlb_use_efi 1525 */ 1526 return (ENOTSUP); 1527 } 1528 1529 /* NO EFI label found */ 1530 1531 if (capacity > CMLB_EXTVTOC_LIMIT) { 1532 if (label_error == ESRCH) { 1533 /* 1534 * they've configured a LUN over 2TB, but used 1535 * format.dat to restrict format's view of the 1536 * capacity to be under 2TB in some earlier Solaris 1537 * release. 1538 */ 1539 /* i.e > 2TB with a VTOC < 2TB */ 1540 if (!(flags & CMLB_SILENT) && 1541 (cl->cl_msglog_flag & CMLB_ALLOW_2TB_WARN)) { 1542 1543 cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), 1544 CE_NOTE, "!Disk (%s%d) is limited to 2 TB " 1545 "due to VTOC label. To use the full " 1546 "capacity of the disk, use format(1M) to " 1547 "relabel the disk with EFI/GPT label.\n", 1548 CMLB_LABEL(cl), 1549 ddi_get_instance(CMLB_DEVINFO(cl))); 1550 1551 cl->cl_msglog_flag &= ~CMLB_ALLOW_2TB_WARN; 1552 } 1553 } else { 1554 return (ENOTSUP); 1555 } 1556 } 1557 1558 label_error = 0; 1559 1560 /* 1561 * at this point it is either labeled with a VTOC or it is 1562 * under 1TB (<= 1TB actually for off-by-1) 1563 */ 1564 1565 /* 1566 * Only DIRECT ACCESS devices will have Scl labels. 1567 * CD's supposedly have a Scl label, too 1568 */ 1569 if (cl->cl_device_type == DTYPE_DIRECT || ISREMOVABLE(cl)) { 1570 struct dk_label *dkl; 1571 offset_t label_addr; 1572 int rval; 1573 size_t buffer_size; 1574 1575 /* 1576 * Note: This will set up cl->cl_solaris_size and 1577 * cl->cl_solaris_offset. 1578 */ 1579 rval = cmlb_read_fdisk(cl, capacity, tg_cookie); 1580 if ((rval != 0) && !ISCD(cl)) { 1581 ASSERT(mutex_owned(CMLB_MUTEX(cl))); 1582 return (rval); 1583 } 1584 1585 if (cl->cl_solaris_size <= DK_LABEL_LOC) { 1586 /* 1587 * Found fdisk table but no Solaris partition entry, 1588 * so don't call cmlb_uselabel() and don't create 1589 * a default label. 1590 */ 1591 label_error = 0; 1592 cl->cl_f_geometry_is_valid = B_TRUE; 1593 goto no_solaris_partition; 1594 } 1595 1596 label_addr = (daddr_t)(cl->cl_solaris_offset + DK_LABEL_LOC); 1597 1598 buffer_size = cl->cl_sys_blocksize; 1599 1600 cmlb_dbg(CMLB_TRACE, cl, "cmlb_validate_geometry: " 1601 "label_addr: 0x%x allocation size: 0x%x\n", 1602 label_addr, buffer_size); 1603 1604 if ((dkl = kmem_zalloc(buffer_size, KM_NOSLEEP)) == NULL) 1605 return (ENOMEM); 1606 1607 mutex_exit(CMLB_MUTEX(cl)); 1608 rval = DK_TG_READ(cl, dkl, label_addr, buffer_size, tg_cookie); 1609 mutex_enter(CMLB_MUTEX(cl)); 1610 1611 switch (rval) { 1612 case 0: 1613 /* 1614 * cmlb_uselabel will establish that the geometry 1615 * is valid. 1616 */ 1617 if (cmlb_uselabel(cl, 1618 (struct dk_label *)(uintptr_t)dkl, flags) != 1619 CMLB_LABEL_IS_VALID) { 1620 label_error = EINVAL; 1621 } else 1622 cl->cl_label_from_media = CMLB_LABEL_VTOC; 1623 break; 1624 case EACCES: 1625 label_error = EACCES; 1626 break; 1627 default: 1628 label_error = EINVAL; 1629 break; 1630 } 1631 1632 kmem_free(dkl, buffer_size); 1633 } 1634 1635 /* 1636 * If a valid label was not found, AND if no reservation conflict 1637 * was detected, then go ahead and create a default label (4069506). 1638 * 1639 * Note: currently, for VTOC_8 devices, the default label is created 1640 * for removables and hotpluggables only. For VTOC_16 devices, the 1641 * default label will be created for all devices. 1642 * (see cmlb_build_default_label) 1643 */ 1644 #if defined(_SUNOS_VTOC_8) 1645 if ((ISREMOVABLE(cl) || ISHOTPLUGGABLE(cl)) && 1646 (label_error != EACCES)) { 1647 #elif defined(_SUNOS_VTOC_16) 1648 if (label_error != EACCES) { 1649 #endif 1650 if (!cl->cl_f_geometry_is_valid) { 1651 cmlb_build_default_label(cl, tg_cookie); 1652 } 1653 label_error = 0; 1654 } 1655 1656 no_solaris_partition: 1657 1658 #if defined(_SUNOS_VTOC_16) 1659 /* 1660 * If we have valid geometry, set up the remaining fdisk partitions. 1661 * Note that dkl_cylno is not used for the fdisk map entries, so 1662 * we set it to an entirely bogus value. 1663 */ 1664 for (count = 0; count < FD_NUMPART; count++) { 1665 cl->cl_map[FDISK_P1 + count].dkl_cylno = UINT16_MAX; 1666 cl->cl_map[FDISK_P1 + count].dkl_nblk = 1667 cl->cl_fmap[count].fmap_nblk; 1668 1669 cl->cl_offset[FDISK_P1 + count] = 1670 cl->cl_fmap[count].fmap_start; 1671 } 1672 #endif 1673 1674 for (count = 0; count < NDKMAP; count++) { 1675 #if defined(_SUNOS_VTOC_8) 1676 struct dk_map *lp = &cl->cl_map[count]; 1677 cl->cl_offset[count] = 1678 cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno; 1679 #elif defined(_SUNOS_VTOC_16) 1680 struct dkl_partition *vp = &cl->cl_vtoc.v_part[count]; 1681 1682 cl->cl_offset[count] = vp->p_start + cl->cl_solaris_offset; 1683 #else 1684 #error "No VTOC format defined." 1685 #endif 1686 } 1687 1688 return (label_error); 1689 } 1690 1691 #if defined(_SUNOS_VTOC_16) 1692 /* 1693 * Function: cmlb_convert_geometry 1694 * 1695 * Description: Convert physical geometry into a dk_geom structure. In 1696 * other words, make sure we don't wrap 16-bit values. 1697 * e.g. converting from geom_cache to dk_geom 1698 * 1699 * Context: Kernel thread only 1700 */ 1701 static void 1702 cmlb_convert_geometry(diskaddr_t capacity, struct dk_geom *cl_g) 1703 { 1704 1705 /* Unlabeled SCSI floppy device */ 1706 if (capacity <= 0x1000) { 1707 cl_g->dkg_nhead = 2; 1708 cl_g->dkg_ncyl = 80; 1709 cl_g->dkg_nsect = capacity / (cl_g->dkg_nhead * cl_g->dkg_ncyl); 1710 return; 1711 } 1712 1713 /* 1714 * For all devices we calculate cylinders using the heads and sectors 1715 * we assign based on capacity of the device. The algorithm is 1716 * designed to be compatible with the way other operating systems 1717 * lay out fdisk tables for X86 and to insure that the cylinders never 1718 * exceed 65535 to prevent problems with X86 ioctls that report 1719 * geometry. 1720 * For some smaller disk sizes we report geometry that matches those 1721 * used by X86 BIOS usage. For larger disks, we use SPT that are 1722 * multiples of 63, since other OSes that are not limited to 16-bits 1723 * for cylinders stop at 63 SPT we make do by using multiples of 63 SPT. 1724 * 1725 * The following table (in order) illustrates some end result 1726 * calculations: 1727 * 1728 * Maximum number of blocks nhead nsect 1729 * 1730 * 2097152 (1GB) 64 32 1731 * 16777216 (8GB) 128 32 1732 * 1052819775 (502.02GB) 255 63 1733 * 2105639550 (0.98TB) 255 126 1734 * 3158459325 (1.47TB) 255 189 1735 * 4211279100 (1.96TB) 255 252 1736 * 5264098875 (2.45TB) 255 315 1737 * ... 1738 */ 1739 1740 if (capacity <= 0x200000) { 1741 cl_g->dkg_nhead = 64; 1742 cl_g->dkg_nsect = 32; 1743 } else if (capacity <= 0x01000000) { 1744 cl_g->dkg_nhead = 128; 1745 cl_g->dkg_nsect = 32; 1746 } else { 1747 cl_g->dkg_nhead = 255; 1748 1749 /* make nsect be smallest multiple of 63 */ 1750 cl_g->dkg_nsect = ((capacity + 1751 (UINT16_MAX * 255 * 63) - 1) / 1752 (UINT16_MAX * 255 * 63)) * 63; 1753 1754 if (cl_g->dkg_nsect == 0) 1755 cl_g->dkg_nsect = (UINT16_MAX / 63) * 63; 1756 } 1757 1758 } 1759 #endif 1760 1761 /* 1762 * Function: cmlb_resync_geom_caches 1763 * 1764 * Description: (Re)initialize both geometry caches: the virtual geometry 1765 * information is extracted from the HBA (the "geometry" 1766 * capability), and the physical geometry cache data is 1767 * generated by issuing MODE SENSE commands. 1768 * 1769 * Arguments: 1770 * cl driver soft state (unit) structure 1771 * capacity disk capacity in #blocks 1772 * tg_cookie cookie from target driver to be passed back to target 1773 * driver when we call back to it through tg_ops. 1774 * 1775 * Context: Kernel thread only (can sleep). 1776 */ 1777 static void 1778 cmlb_resync_geom_caches(struct cmlb_lun *cl, diskaddr_t capacity, 1779 void *tg_cookie) 1780 { 1781 struct cmlb_geom pgeom; 1782 struct cmlb_geom lgeom; 1783 struct cmlb_geom *pgeomp = &pgeom; 1784 unsigned short nhead; 1785 unsigned short nsect; 1786 int spc; 1787 int ret; 1788 1789 ASSERT(cl != NULL); 1790 ASSERT(mutex_owned(CMLB_MUTEX(cl))); 1791 1792 /* 1793 * Ask the controller for its logical geometry. 1794 * Note: if the HBA does not support scsi_ifgetcap("geometry"), 1795 * then the lgeom cache will be invalid. 1796 */ 1797 mutex_exit(CMLB_MUTEX(cl)); 1798 bzero(&lgeom, sizeof (struct cmlb_geom)); 1799 ret = DK_TG_GETVIRTGEOM(cl, &lgeom, tg_cookie); 1800 mutex_enter(CMLB_MUTEX(cl)); 1801 1802 bcopy(&lgeom, &cl->cl_lgeom, sizeof (cl->cl_lgeom)); 1803 1804 /* 1805 * Initialize the pgeom cache from lgeom, so that if MODE SENSE 1806 * doesn't work, DKIOCG_PHYSGEOM can return reasonable values. 1807 */ 1808 if (ret != 0 || cl->cl_lgeom.g_nsect == 0 || 1809 cl->cl_lgeom.g_nhead == 0) { 1810 /* 1811 * Note: Perhaps this needs to be more adaptive? The rationale 1812 * is that, if there's no HBA geometry from the HBA driver, any 1813 * guess is good, since this is the physical geometry. If MODE 1814 * SENSE fails this gives a max cylinder size for non-LBA access 1815 */ 1816 nhead = 255; 1817 nsect = 63; 1818 } else { 1819 nhead = cl->cl_lgeom.g_nhead; 1820 nsect = cl->cl_lgeom.g_nsect; 1821 } 1822 1823 if (ISCD(cl)) { 1824 pgeomp->g_nhead = 1; 1825 pgeomp->g_nsect = nsect * nhead; 1826 } else { 1827 pgeomp->g_nhead = nhead; 1828 pgeomp->g_nsect = nsect; 1829 } 1830 1831 spc = pgeomp->g_nhead * pgeomp->g_nsect; 1832 pgeomp->g_capacity = capacity; 1833 if (spc == 0) 1834 pgeomp->g_ncyl = 0; 1835 else 1836 pgeomp->g_ncyl = pgeomp->g_capacity / spc; 1837 pgeomp->g_acyl = 0; 1838 1839 /* 1840 * Retrieve fresh geometry data from the hardware, stash it 1841 * here temporarily before we rebuild the incore label. 1842 * 1843 * We want to use the MODE SENSE commands to derive the 1844 * physical geometry of the device, but if either command 1845 * fails, the logical geometry is used as the fallback for 1846 * disk label geometry. 1847 */ 1848 1849 mutex_exit(CMLB_MUTEX(cl)); 1850 (void) DK_TG_GETPHYGEOM(cl, pgeomp, tg_cookie); 1851 mutex_enter(CMLB_MUTEX(cl)); 1852 1853 /* 1854 * Now update the real copy while holding the mutex. This 1855 * way the global copy is never in an inconsistent state. 1856 */ 1857 bcopy(pgeomp, &cl->cl_pgeom, sizeof (cl->cl_pgeom)); 1858 1859 cmlb_dbg(CMLB_INFO, cl, "cmlb_resync_geom_caches: " 1860 "(cached from lgeom)\n"); 1861 cmlb_dbg(CMLB_INFO, cl, 1862 " ncyl: %ld; acyl: %d; nhead: %d; nsect: %d\n", 1863 cl->cl_pgeom.g_ncyl, cl->cl_pgeom.g_acyl, 1864 cl->cl_pgeom.g_nhead, cl->cl_pgeom.g_nsect); 1865 cmlb_dbg(CMLB_INFO, cl, " lbasize: %d; capacity: %ld; " 1866 "intrlv: %d; rpm: %d\n", cl->cl_pgeom.g_secsize, 1867 cl->cl_pgeom.g_capacity, cl->cl_pgeom.g_intrlv, 1868 cl->cl_pgeom.g_rpm); 1869 } 1870 1871 1872 /* 1873 * Function: cmlb_read_fdisk 1874 * 1875 * Description: utility routine to read the fdisk table. 1876 * 1877 * Arguments: 1878 * cl driver soft state (unit) structure 1879 * capacity disk capacity in #blocks 1880 * tg_cookie cookie from target driver to be passed back to target 1881 * driver when we call back to it through tg_ops. 1882 * 1883 * Return Code: 0 for success (includes not reading for no_fdisk_present case 1884 * errnos from tg_rw if failed to read the first block. 1885 * 1886 * Context: Kernel thread only (can sleep). 1887 */ 1888 /*ARGSUSED*/ 1889 static int 1890 cmlb_read_fdisk(struct cmlb_lun *cl, diskaddr_t capacity, void *tg_cookie) 1891 { 1892 #if defined(_NO_FDISK_PRESENT) 1893 1894 cl->cl_solaris_offset = 0; 1895 cl->cl_solaris_size = capacity; 1896 bzero(cl->cl_fmap, sizeof (struct fmap) * FD_NUMPART); 1897 return (0); 1898 1899 #elif defined(_FIRMWARE_NEEDS_FDISK) 1900 1901 struct ipart *fdp; 1902 struct mboot *mbp; 1903 struct ipart fdisk[FD_NUMPART]; 1904 int i; 1905 char sigbuf[2]; 1906 caddr_t bufp; 1907 int uidx; 1908 int rval; 1909 int lba = 0; 1910 uint_t solaris_offset; /* offset to solaris part. */ 1911 daddr_t solaris_size; /* size of solaris partition */ 1912 uint32_t blocksize; 1913 1914 ASSERT(cl != NULL); 1915 ASSERT(mutex_owned(CMLB_MUTEX(cl))); 1916 1917 /* 1918 * Start off assuming no fdisk table 1919 */ 1920 solaris_offset = 0; 1921 solaris_size = capacity; 1922 1923 blocksize = cl->cl_tgt_blocksize; 1924 1925 bufp = kmem_zalloc(blocksize, KM_SLEEP); 1926 1927 mutex_exit(CMLB_MUTEX(cl)); 1928 rval = DK_TG_READ(cl, bufp, 0, blocksize, tg_cookie); 1929 mutex_enter(CMLB_MUTEX(cl)); 1930 1931 if (rval != 0) { 1932 cmlb_dbg(CMLB_ERROR, cl, 1933 "cmlb_read_fdisk: fdisk read err\n"); 1934 bzero(cl->cl_fmap, sizeof (struct fmap) * FD_NUMPART); 1935 goto done; 1936 } 1937 1938 mbp = (struct mboot *)bufp; 1939 1940 /* 1941 * The fdisk table does not begin on a 4-byte boundary within the 1942 * master boot record, so we copy it to an aligned structure to avoid 1943 * alignment exceptions on some processors. 1944 */ 1945 bcopy(&mbp->parts[0], fdisk, sizeof (fdisk)); 1946 1947 /* 1948 * Check for lba support before verifying sig; sig might not be 1949 * there, say on a blank disk, but the max_chs mark may still 1950 * be present. 1951 * 1952 * Note: LBA support and BEFs are an x86-only concept but this 1953 * code should work OK on SPARC as well. 1954 */ 1955 1956 /* 1957 * First, check for lba-access-ok on root node (or prom root node) 1958 * if present there, don't need to search fdisk table. 1959 */ 1960 if (ddi_getprop(DDI_DEV_T_ANY, ddi_root_node(), 0, 1961 "lba-access-ok", 0) != 0) { 1962 /* All drives do LBA; don't search fdisk table */ 1963 lba = 1; 1964 } else { 1965 /* Okay, look for mark in fdisk table */ 1966 for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) { 1967 /* accumulate "lba" value from all partitions */ 1968 lba = (lba || cmlb_has_max_chs_vals(fdp)); 1969 } 1970 } 1971 1972 if (lba != 0) { 1973 dev_t dev = cmlb_make_device(cl); 1974 1975 if (ddi_getprop(dev, CMLB_DEVINFO(cl), DDI_PROP_DONTPASS, 1976 "lba-access-ok", 0) == 0) { 1977 /* not found; create it */ 1978 if (ddi_prop_create(dev, CMLB_DEVINFO(cl), 0, 1979 "lba-access-ok", (caddr_t)NULL, 0) != 1980 DDI_PROP_SUCCESS) { 1981 cmlb_dbg(CMLB_ERROR, cl, 1982 "cmlb_read_fdisk: Can't create lba " 1983 "property for instance %d\n", 1984 ddi_get_instance(CMLB_DEVINFO(cl))); 1985 } 1986 } 1987 } 1988 1989 bcopy(&mbp->signature, sigbuf, sizeof (sigbuf)); 1990 1991 /* 1992 * Endian-independent signature check 1993 */ 1994 if (((sigbuf[1] & 0xFF) != ((MBB_MAGIC >> 8) & 0xFF)) || 1995 (sigbuf[0] != (MBB_MAGIC & 0xFF))) { 1996 cmlb_dbg(CMLB_ERROR, cl, 1997 "cmlb_read_fdisk: no fdisk\n"); 1998 bzero(cl->cl_fmap, sizeof (struct fmap) * FD_NUMPART); 1999 goto done; 2000 } 2001 2002 #ifdef CMLBDEBUG 2003 if (cmlb_level_mask & CMLB_LOGMASK_INFO) { 2004 fdp = fdisk; 2005 cmlb_dbg(CMLB_INFO, cl, "cmlb_read_fdisk:\n"); 2006 cmlb_dbg(CMLB_INFO, cl, " relsect " 2007 "numsect sysid bootid\n"); 2008 for (i = 0; i < FD_NUMPART; i++, fdp++) { 2009 cmlb_dbg(CMLB_INFO, cl, 2010 " %d: %8d %8d 0x%08x 0x%08x\n", 2011 i, fdp->relsect, fdp->numsect, 2012 fdp->systid, fdp->bootid); 2013 } 2014 } 2015 #endif 2016 2017 /* 2018 * Try to find the unix partition 2019 */ 2020 uidx = -1; 2021 solaris_offset = 0; 2022 solaris_size = 0; 2023 2024 for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) { 2025 uint32_t relsect; 2026 uint32_t numsect; 2027 2028 if (fdp->numsect == 0) { 2029 cl->cl_fmap[i].fmap_start = 0; 2030 cl->cl_fmap[i].fmap_nblk = 0; 2031 continue; 2032 } 2033 2034 /* 2035 * Data in the fdisk table is little-endian. 2036 */ 2037 relsect = LE_32(fdp->relsect); 2038 numsect = LE_32(fdp->numsect); 2039 2040 cl->cl_fmap[i].fmap_start = relsect; 2041 cl->cl_fmap[i].fmap_nblk = numsect; 2042 2043 if (fdp->systid != SUNIXOS && 2044 fdp->systid != SUNIXOS2 && 2045 fdp->systid != EFI_PMBR) { 2046 continue; 2047 } 2048 2049 /* 2050 * use the last active solaris partition id found 2051 * (there should only be 1 active partition id) 2052 * 2053 * if there are no active solaris partition id 2054 * then use the first inactive solaris partition id 2055 */ 2056 if ((uidx == -1) || (fdp->bootid == ACTIVE)) { 2057 uidx = i; 2058 solaris_offset = relsect; 2059 solaris_size = numsect; 2060 } 2061 } 2062 2063 cmlb_dbg(CMLB_INFO, cl, "fdisk 0x%x 0x%lx", 2064 cl->cl_solaris_offset, cl->cl_solaris_size); 2065 done: 2066 2067 /* 2068 * Clear the VTOC info, only if the Solaris partition entry 2069 * has moved, changed size, been deleted, or if the size of 2070 * the partition is too small to even fit the label sector. 2071 */ 2072 if ((cl->cl_solaris_offset != solaris_offset) || 2073 (cl->cl_solaris_size != solaris_size) || 2074 solaris_size <= DK_LABEL_LOC) { 2075 cmlb_dbg(CMLB_INFO, cl, "fdisk moved 0x%x 0x%lx", 2076 solaris_offset, solaris_size); 2077 bzero(&cl->cl_g, sizeof (struct dk_geom)); 2078 bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc)); 2079 bzero(&cl->cl_map, NDKMAP * (sizeof (struct dk_map))); 2080 cl->cl_f_geometry_is_valid = B_FALSE; 2081 } 2082 cl->cl_solaris_offset = solaris_offset; 2083 cl->cl_solaris_size = solaris_size; 2084 kmem_free(bufp, blocksize); 2085 return (rval); 2086 2087 #else /* #elif defined(_FIRMWARE_NEEDS_FDISK) */ 2088 #error "fdisk table presence undetermined for this platform." 2089 #endif /* #if defined(_NO_FDISK_PRESENT) */ 2090 } 2091 2092 static void 2093 cmlb_swap_efi_gpt(efi_gpt_t *e) 2094 { 2095 _NOTE(ASSUMING_PROTECTED(*e)) 2096 e->efi_gpt_Signature = LE_64(e->efi_gpt_Signature); 2097 e->efi_gpt_Revision = LE_32(e->efi_gpt_Revision); 2098 e->efi_gpt_HeaderSize = LE_32(e->efi_gpt_HeaderSize); 2099 e->efi_gpt_HeaderCRC32 = LE_32(e->efi_gpt_HeaderCRC32); 2100 e->efi_gpt_MyLBA = LE_64(e->efi_gpt_MyLBA); 2101 e->efi_gpt_AlternateLBA = LE_64(e->efi_gpt_AlternateLBA); 2102 e->efi_gpt_FirstUsableLBA = LE_64(e->efi_gpt_FirstUsableLBA); 2103 e->efi_gpt_LastUsableLBA = LE_64(e->efi_gpt_LastUsableLBA); 2104 UUID_LE_CONVERT(e->efi_gpt_DiskGUID, e->efi_gpt_DiskGUID); 2105 e->efi_gpt_PartitionEntryLBA = LE_64(e->efi_gpt_PartitionEntryLBA); 2106 e->efi_gpt_NumberOfPartitionEntries = 2107 LE_32(e->efi_gpt_NumberOfPartitionEntries); 2108 e->efi_gpt_SizeOfPartitionEntry = 2109 LE_32(e->efi_gpt_SizeOfPartitionEntry); 2110 e->efi_gpt_PartitionEntryArrayCRC32 = 2111 LE_32(e->efi_gpt_PartitionEntryArrayCRC32); 2112 } 2113 2114 static void 2115 cmlb_swap_efi_gpe(int nparts, efi_gpe_t *p) 2116 { 2117 int i; 2118 2119 _NOTE(ASSUMING_PROTECTED(*p)) 2120 for (i = 0; i < nparts; i++) { 2121 UUID_LE_CONVERT(p[i].efi_gpe_PartitionTypeGUID, 2122 p[i].efi_gpe_PartitionTypeGUID); 2123 p[i].efi_gpe_StartingLBA = LE_64(p[i].efi_gpe_StartingLBA); 2124 p[i].efi_gpe_EndingLBA = LE_64(p[i].efi_gpe_EndingLBA); 2125 /* PartitionAttrs */ 2126 } 2127 } 2128 2129 static int 2130 cmlb_validate_efi(efi_gpt_t *labp) 2131 { 2132 if (labp->efi_gpt_Signature != EFI_SIGNATURE) 2133 return (EINVAL); 2134 /* at least 96 bytes in this version of the spec. */ 2135 if (sizeof (efi_gpt_t) - sizeof (labp->efi_gpt_Reserved2) > 2136 labp->efi_gpt_HeaderSize) 2137 return (EINVAL); 2138 /* this should be 128 bytes */ 2139 if (labp->efi_gpt_SizeOfPartitionEntry != sizeof (efi_gpe_t)) 2140 return (EINVAL); 2141 return (0); 2142 } 2143 2144 /* 2145 * This function returns B_FALSE if there is a valid MBR signature and no 2146 * partition table entries of type EFI_PMBR (0xEE). Otherwise it returns B_TRUE. 2147 * 2148 * The EFI spec (1.10 and later) requires having a Protective MBR (PMBR) to 2149 * recognize the disk as GPT partitioned. However, some other OS creates an MBR 2150 * where a PMBR entry is not the only one. Also, if the first block has been 2151 * corrupted, currently best attempt to allow data access would be to try to 2152 * check for GPT headers. Hence in case of more than one partition entry, but 2153 * at least one EFI_PMBR partition type or no valid magic number, the function 2154 * returns B_TRUE to continue with looking for GPT header. 2155 */ 2156 2157 static boolean_t 2158 cmlb_check_efi_mbr(uchar_t *buf, boolean_t *is_mbr) 2159 { 2160 struct ipart *fdp; 2161 struct mboot *mbp = (struct mboot *)buf; 2162 struct ipart fdisk[FD_NUMPART]; 2163 int i; 2164 2165 if (is_mbr != NULL) 2166 *is_mbr = B_TRUE; 2167 2168 if (LE_16(mbp->signature) != MBB_MAGIC) { 2169 if (is_mbr != NULL) 2170 *is_mbr = B_FALSE; 2171 return (B_TRUE); 2172 } 2173 2174 bcopy(&mbp->parts[0], fdisk, sizeof (fdisk)); 2175 2176 for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) { 2177 if (fdp->systid == EFI_PMBR) 2178 return (B_TRUE); 2179 } 2180 2181 return (B_FALSE); 2182 } 2183 2184 static int 2185 cmlb_use_efi(struct cmlb_lun *cl, diskaddr_t capacity, int flags, 2186 void *tg_cookie) 2187 { 2188 int i; 2189 int rval = 0; 2190 efi_gpe_t *partitions; 2191 uchar_t *buf; 2192 uint_t lbasize; /* is really how much to read */ 2193 diskaddr_t cap = 0; 2194 uint_t nparts; 2195 diskaddr_t gpe_lba; 2196 diskaddr_t alternate_lba; 2197 int iofailed = 0; 2198 struct uuid uuid_type_reserved = EFI_RESERVED; 2199 #if defined(_FIRMWARE_NEEDS_FDISK) 2200 boolean_t is_mbr; 2201 #endif 2202 2203 ASSERT(mutex_owned(CMLB_MUTEX(cl))); 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 if (phys_spc == 0) 2819 return; 2820 cl->cl_g.dkg_pcyl = cl->cl_solaris_size / phys_spc; 2821 if (cl->cl_alter_behavior & CMLB_FAKE_LABEL_ONE_PARTITION) { 2822 /* disable devid */ 2823 cl->cl_g.dkg_ncyl = cl->cl_g.dkg_pcyl; 2824 disksize = cl->cl_solaris_size; 2825 } else { 2826 cl->cl_g.dkg_acyl = DK_ACYL; 2827 cl->cl_g.dkg_ncyl = cl->cl_g.dkg_pcyl - DK_ACYL; 2828 disksize = cl->cl_g.dkg_ncyl * phys_spc; 2829 } 2830 2831 if (ISCD(cl)) { 2832 /* 2833 * CD's don't use the "heads * sectors * cyls"-type of 2834 * geometry, but instead use the entire capacity of the media. 2835 */ 2836 disksize = cl->cl_solaris_size; 2837 cl->cl_g.dkg_nhead = 1; 2838 cl->cl_g.dkg_nsect = 1; 2839 cl->cl_g.dkg_rpm = 2840 (cl->cl_pgeom.g_rpm == 0) ? 200 : cl->cl_pgeom.g_rpm; 2841 2842 cl->cl_vtoc.v_part[0].p_start = 0; 2843 cl->cl_vtoc.v_part[0].p_size = disksize; 2844 cl->cl_vtoc.v_part[0].p_tag = V_BACKUP; 2845 cl->cl_vtoc.v_part[0].p_flag = V_UNMNT; 2846 2847 cl->cl_map[0].dkl_cylno = 0; 2848 cl->cl_map[0].dkl_nblk = disksize; 2849 cl->cl_offset[0] = 0; 2850 2851 } else { 2852 /* 2853 * Hard disks and removable media cartridges 2854 */ 2855 cl->cl_g.dkg_rpm = 2856 (cl->cl_pgeom.g_rpm == 0) ? 3600: cl->cl_pgeom.g_rpm; 2857 cl->cl_vtoc.v_sectorsz = cl->cl_sys_blocksize; 2858 2859 /* Add boot slice */ 2860 cl->cl_vtoc.v_part[8].p_start = 0; 2861 cl->cl_vtoc.v_part[8].p_size = phys_spc; 2862 cl->cl_vtoc.v_part[8].p_tag = V_BOOT; 2863 cl->cl_vtoc.v_part[8].p_flag = V_UNMNT; 2864 2865 cl->cl_map[8].dkl_cylno = 0; 2866 cl->cl_map[8].dkl_nblk = phys_spc; 2867 cl->cl_offset[8] = 0; 2868 2869 if ((cl->cl_alter_behavior & 2870 CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT) && 2871 cl->cl_device_type == DTYPE_DIRECT) { 2872 cl->cl_vtoc.v_part[9].p_start = phys_spc; 2873 cl->cl_vtoc.v_part[9].p_size = 2 * phys_spc; 2874 cl->cl_vtoc.v_part[9].p_tag = V_ALTSCTR; 2875 cl->cl_vtoc.v_part[9].p_flag = 0; 2876 2877 cl->cl_map[9].dkl_cylno = 1; 2878 cl->cl_map[9].dkl_nblk = 2 * phys_spc; 2879 cl->cl_offset[9] = phys_spc; 2880 } 2881 } 2882 2883 cl->cl_g.dkg_apc = 0; 2884 2885 /* Add backup slice */ 2886 cl->cl_vtoc.v_part[2].p_start = 0; 2887 cl->cl_vtoc.v_part[2].p_size = disksize; 2888 cl->cl_vtoc.v_part[2].p_tag = V_BACKUP; 2889 cl->cl_vtoc.v_part[2].p_flag = V_UNMNT; 2890 2891 cl->cl_map[2].dkl_cylno = 0; 2892 cl->cl_map[2].dkl_nblk = disksize; 2893 cl->cl_offset[2] = 0; 2894 2895 /* 2896 * single slice (s0) covering the entire disk 2897 */ 2898 if (cl->cl_alter_behavior & CMLB_FAKE_LABEL_ONE_PARTITION) { 2899 cl->cl_vtoc.v_part[0].p_start = 0; 2900 cl->cl_vtoc.v_part[0].p_tag = V_UNASSIGNED; 2901 cl->cl_vtoc.v_part[0].p_flag = 0; 2902 cl->cl_vtoc.v_part[0].p_size = disksize; 2903 cl->cl_map[0].dkl_cylno = 0; 2904 cl->cl_map[0].dkl_nblk = disksize; 2905 cl->cl_offset[0] = 0; 2906 } 2907 2908 (void) sprintf(cl->cl_vtoc.v_asciilabel, "DEFAULT cyl %d alt %d" 2909 " hd %d sec %d", cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl, 2910 cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect); 2911 2912 #else 2913 #error "No VTOC format defined." 2914 #endif 2915 2916 cl->cl_g.dkg_read_reinstruct = 0; 2917 cl->cl_g.dkg_write_reinstruct = 0; 2918 2919 cl->cl_g.dkg_intrlv = 1; 2920 2921 cl->cl_vtoc.v_sanity = VTOC_SANE; 2922 cl->cl_vtoc.v_nparts = V_NUMPAR; 2923 cl->cl_vtoc.v_version = V_VERSION; 2924 2925 cl->cl_f_geometry_is_valid = B_TRUE; 2926 cl->cl_label_from_media = CMLB_LABEL_UNDEF; 2927 2928 cmlb_dbg(CMLB_INFO, cl, 2929 "cmlb_build_default_label: Default label created: " 2930 "cyl: %d\tacyl: %d\tnhead: %d\tnsect: %d\tcap: %d\n", 2931 cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl, cl->cl_g.dkg_nhead, 2932 cl->cl_g.dkg_nsect, cl->cl_blockcount); 2933 } 2934 2935 2936 #if defined(_FIRMWARE_NEEDS_FDISK) 2937 /* 2938 * Max CHS values, as they are encoded into bytes, for 1022/254/63 2939 */ 2940 #define LBA_MAX_SECT (63 | ((1022 & 0x300) >> 2)) 2941 #define LBA_MAX_CYL (1022 & 0xFF) 2942 #define LBA_MAX_HEAD (254) 2943 2944 2945 /* 2946 * Function: cmlb_has_max_chs_vals 2947 * 2948 * Description: Return B_TRUE if Cylinder-Head-Sector values are all at maximum. 2949 * 2950 * Arguments: fdp - ptr to CHS info 2951 * 2952 * Return Code: True or false 2953 * 2954 * Context: Any. 2955 */ 2956 static boolean_t 2957 cmlb_has_max_chs_vals(struct ipart *fdp) 2958 { 2959 return ((fdp->begcyl == LBA_MAX_CYL) && 2960 (fdp->beghead == LBA_MAX_HEAD) && 2961 (fdp->begsect == LBA_MAX_SECT) && 2962 (fdp->endcyl == LBA_MAX_CYL) && 2963 (fdp->endhead == LBA_MAX_HEAD) && 2964 (fdp->endsect == LBA_MAX_SECT)); 2965 } 2966 #endif 2967 2968 /* 2969 * Function: cmlb_dkio_get_geometry 2970 * 2971 * Description: This routine is the driver entry point for handling user 2972 * requests to get the device geometry (DKIOCGGEOM). 2973 * 2974 * Arguments: 2975 * arg pointer to user provided dk_geom structure specifying 2976 * the controller's notion of the current geometry. 2977 * 2978 * flag this argument is a pass through to ddi_copyxxx() 2979 * directly from the mode argument of ioctl(). 2980 * 2981 * tg_cookie cookie from target driver to be passed back to target 2982 * driver when we call back to it through tg_ops. 2983 * 2984 * Return Code: 0 2985 * EFAULT 2986 * ENXIO 2987 * EIO 2988 */ 2989 static int 2990 cmlb_dkio_get_geometry(struct cmlb_lun *cl, caddr_t arg, int flag, 2991 void *tg_cookie) 2992 { 2993 struct dk_geom *tmp_geom = NULL; 2994 int rval = 0; 2995 2996 /* 2997 * cmlb_validate_geometry does not spin a disk up 2998 * if it was spcl down. We need to make sure it 2999 * is ready. 3000 */ 3001 mutex_enter(CMLB_MUTEX(cl)); 3002 rval = cmlb_validate_geometry(cl, B_TRUE, 0, tg_cookie); 3003 #if defined(_SUNOS_VTOC_8) 3004 if (rval == EINVAL && 3005 cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8) { 3006 /* 3007 * This is to return a default label geometry even when we 3008 * do not really assume a default label for the device. 3009 * dad driver utilizes this. 3010 */ 3011 if (cl->cl_blockcount <= CMLB_OLDVTOC_LIMIT) { 3012 cmlb_setup_default_geometry(cl, tg_cookie); 3013 rval = 0; 3014 } 3015 } 3016 #endif 3017 if (rval) { 3018 mutex_exit(CMLB_MUTEX(cl)); 3019 return (rval); 3020 } 3021 3022 #if defined(__i386) || defined(__amd64) 3023 if (cl->cl_solaris_size == 0) { 3024 mutex_exit(CMLB_MUTEX(cl)); 3025 return (EIO); 3026 } 3027 #endif 3028 3029 /* 3030 * Make a local copy of the soft state geometry to avoid some potential 3031 * race conditions associated with holding the mutex and updating the 3032 * write_reinstruct value 3033 */ 3034 tmp_geom = kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP); 3035 bcopy(&cl->cl_g, tmp_geom, sizeof (struct dk_geom)); 3036 3037 if (tmp_geom->dkg_write_reinstruct == 0) { 3038 tmp_geom->dkg_write_reinstruct = 3039 (int)((int)(tmp_geom->dkg_nsect * tmp_geom->dkg_rpm * 3040 cmlb_rot_delay) / (int)60000); 3041 } 3042 mutex_exit(CMLB_MUTEX(cl)); 3043 3044 rval = ddi_copyout(tmp_geom, (void *)arg, sizeof (struct dk_geom), 3045 flag); 3046 if (rval != 0) { 3047 rval = EFAULT; 3048 } 3049 3050 kmem_free(tmp_geom, sizeof (struct dk_geom)); 3051 return (rval); 3052 3053 } 3054 3055 3056 /* 3057 * Function: cmlb_dkio_set_geometry 3058 * 3059 * Description: This routine is the driver entry point for handling user 3060 * requests to set the device geometry (DKIOCSGEOM). The actual 3061 * device geometry is not updated, just the driver "notion" of it. 3062 * 3063 * Arguments: 3064 * arg pointer to user provided dk_geom structure used to set 3065 * the controller's notion of the current geometry. 3066 * 3067 * flag this argument is a pass through to ddi_copyxxx() 3068 * directly from the mode argument of ioctl(). 3069 * 3070 * tg_cookie cookie from target driver to be passed back to target 3071 * driver when we call back to it through tg_ops. 3072 * 3073 * Return Code: 0 3074 * EFAULT 3075 * ENXIO 3076 * EIO 3077 */ 3078 static int 3079 cmlb_dkio_set_geometry(struct cmlb_lun *cl, caddr_t arg, int flag) 3080 { 3081 struct dk_geom *tmp_geom; 3082 struct dk_map *lp; 3083 int rval = 0; 3084 int i; 3085 3086 3087 #if defined(__i386) || defined(__amd64) 3088 if (cl->cl_solaris_size == 0) { 3089 return (EIO); 3090 } 3091 #endif 3092 /* 3093 * We need to copy the user specified geometry into local 3094 * storage and then update the softstate. We don't want to hold 3095 * the mutex and copyin directly from the user to the soft state 3096 */ 3097 tmp_geom = (struct dk_geom *) 3098 kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP); 3099 rval = ddi_copyin(arg, tmp_geom, sizeof (struct dk_geom), flag); 3100 if (rval != 0) { 3101 kmem_free(tmp_geom, sizeof (struct dk_geom)); 3102 return (EFAULT); 3103 } 3104 3105 mutex_enter(CMLB_MUTEX(cl)); 3106 bcopy(tmp_geom, &cl->cl_g, sizeof (struct dk_geom)); 3107 for (i = 0; i < NDKMAP; i++) { 3108 lp = &cl->cl_map[i]; 3109 cl->cl_offset[i] = 3110 cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno; 3111 #if defined(__i386) || defined(__amd64) 3112 cl->cl_offset[i] += cl->cl_solaris_offset; 3113 #endif 3114 } 3115 cl->cl_f_geometry_is_valid = B_FALSE; 3116 mutex_exit(CMLB_MUTEX(cl)); 3117 kmem_free(tmp_geom, sizeof (struct dk_geom)); 3118 3119 return (rval); 3120 } 3121 3122 /* 3123 * Function: cmlb_dkio_get_partition 3124 * 3125 * Description: This routine is the driver entry point for handling user 3126 * requests to get the partition table (DKIOCGAPART). 3127 * 3128 * Arguments: 3129 * arg pointer to user provided dk_allmap structure specifying 3130 * the controller's notion of the current partition table. 3131 * 3132 * flag this argument is a pass through to ddi_copyxxx() 3133 * directly from the mode argument of ioctl(). 3134 * 3135 * tg_cookie cookie from target driver to be passed back to target 3136 * driver when we call back to it through tg_ops. 3137 * 3138 * Return Code: 0 3139 * EFAULT 3140 * ENXIO 3141 * EIO 3142 */ 3143 static int 3144 cmlb_dkio_get_partition(struct cmlb_lun *cl, caddr_t arg, int flag, 3145 void *tg_cookie) 3146 { 3147 int rval = 0; 3148 int size; 3149 3150 /* 3151 * Make sure the geometry is valid before getting the partition 3152 * information. 3153 */ 3154 mutex_enter(CMLB_MUTEX(cl)); 3155 if ((rval = cmlb_validate_geometry(cl, B_TRUE, 0, tg_cookie)) != 0) { 3156 mutex_exit(CMLB_MUTEX(cl)); 3157 return (rval); 3158 } 3159 mutex_exit(CMLB_MUTEX(cl)); 3160 3161 #if defined(__i386) || defined(__amd64) 3162 if (cl->cl_solaris_size == 0) { 3163 return (EIO); 3164 } 3165 #endif 3166 3167 #ifdef _MULTI_DATAMODEL 3168 switch (ddi_model_convert_from(flag & FMODELS)) { 3169 case DDI_MODEL_ILP32: { 3170 struct dk_map32 dk_map32[NDKMAP]; 3171 int i; 3172 3173 for (i = 0; i < NDKMAP; i++) { 3174 dk_map32[i].dkl_cylno = cl->cl_map[i].dkl_cylno; 3175 dk_map32[i].dkl_nblk = cl->cl_map[i].dkl_nblk; 3176 } 3177 size = NDKMAP * sizeof (struct dk_map32); 3178 rval = ddi_copyout(dk_map32, (void *)arg, size, flag); 3179 if (rval != 0) { 3180 rval = EFAULT; 3181 } 3182 break; 3183 } 3184 case DDI_MODEL_NONE: 3185 size = NDKMAP * sizeof (struct dk_map); 3186 rval = ddi_copyout(cl->cl_map, (void *)arg, size, flag); 3187 if (rval != 0) { 3188 rval = EFAULT; 3189 } 3190 break; 3191 } 3192 #else /* ! _MULTI_DATAMODEL */ 3193 size = NDKMAP * sizeof (struct dk_map); 3194 rval = ddi_copyout(cl->cl_map, (void *)arg, size, flag); 3195 if (rval != 0) { 3196 rval = EFAULT; 3197 } 3198 #endif /* _MULTI_DATAMODEL */ 3199 return (rval); 3200 } 3201 3202 /* 3203 * Function: cmlb_dkio_set_partition 3204 * 3205 * Description: This routine is the driver entry point for handling user 3206 * requests to set the partition table (DKIOCSAPART). The actual 3207 * device partition is not updated. 3208 * 3209 * Arguments: 3210 * arg - pointer to user provided dk_allmap structure used to set 3211 * the controller's notion of the partition table. 3212 * flag - this argument is a pass through to ddi_copyxxx() 3213 * directly from the mode argument of ioctl(). 3214 * 3215 * Return Code: 0 3216 * EINVAL 3217 * EFAULT 3218 * ENXIO 3219 * EIO 3220 */ 3221 static int 3222 cmlb_dkio_set_partition(struct cmlb_lun *cl, caddr_t arg, int flag) 3223 { 3224 struct dk_map dk_map[NDKMAP]; 3225 struct dk_map *lp; 3226 int rval = 0; 3227 int size; 3228 int i; 3229 #if defined(_SUNOS_VTOC_16) 3230 struct dkl_partition *vp; 3231 #endif 3232 3233 /* 3234 * Set the map for all logical partitions. We lock 3235 * the priority just to make sure an interrupt doesn't 3236 * come in while the map is half updated. 3237 */ 3238 _NOTE(DATA_READABLE_WITHOUT_LOCK(cmlb_lun::cl_solaris_size)) 3239 mutex_enter(CMLB_MUTEX(cl)); 3240 3241 if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) { 3242 mutex_exit(CMLB_MUTEX(cl)); 3243 return (ENOTSUP); 3244 } 3245 mutex_exit(CMLB_MUTEX(cl)); 3246 if (cl->cl_solaris_size == 0) { 3247 return (EIO); 3248 } 3249 3250 #ifdef _MULTI_DATAMODEL 3251 switch (ddi_model_convert_from(flag & FMODELS)) { 3252 case DDI_MODEL_ILP32: { 3253 struct dk_map32 dk_map32[NDKMAP]; 3254 3255 size = NDKMAP * sizeof (struct dk_map32); 3256 rval = ddi_copyin((void *)arg, dk_map32, size, flag); 3257 if (rval != 0) { 3258 return (EFAULT); 3259 } 3260 for (i = 0; i < NDKMAP; i++) { 3261 dk_map[i].dkl_cylno = dk_map32[i].dkl_cylno; 3262 dk_map[i].dkl_nblk = dk_map32[i].dkl_nblk; 3263 } 3264 break; 3265 } 3266 case DDI_MODEL_NONE: 3267 size = NDKMAP * sizeof (struct dk_map); 3268 rval = ddi_copyin((void *)arg, dk_map, size, flag); 3269 if (rval != 0) { 3270 return (EFAULT); 3271 } 3272 break; 3273 } 3274 #else /* ! _MULTI_DATAMODEL */ 3275 size = NDKMAP * sizeof (struct dk_map); 3276 rval = ddi_copyin((void *)arg, dk_map, size, flag); 3277 if (rval != 0) { 3278 return (EFAULT); 3279 } 3280 #endif /* _MULTI_DATAMODEL */ 3281 3282 mutex_enter(CMLB_MUTEX(cl)); 3283 /* Note: The size used in this bcopy is set based upon the data model */ 3284 bcopy(dk_map, cl->cl_map, size); 3285 #if defined(_SUNOS_VTOC_16) 3286 vp = (struct dkl_partition *)&(cl->cl_vtoc); 3287 #endif /* defined(_SUNOS_VTOC_16) */ 3288 for (i = 0; i < NDKMAP; i++) { 3289 lp = &cl->cl_map[i]; 3290 cl->cl_offset[i] = 3291 cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno; 3292 #if defined(_SUNOS_VTOC_16) 3293 vp->p_start = cl->cl_offset[i]; 3294 vp->p_size = lp->dkl_nblk; 3295 vp++; 3296 #endif /* defined(_SUNOS_VTOC_16) */ 3297 #if defined(__i386) || defined(__amd64) 3298 cl->cl_offset[i] += cl->cl_solaris_offset; 3299 #endif 3300 } 3301 mutex_exit(CMLB_MUTEX(cl)); 3302 return (rval); 3303 } 3304 3305 3306 /* 3307 * Function: cmlb_dkio_get_vtoc 3308 * 3309 * Description: This routine is the driver entry point for handling user 3310 * requests to get the current volume table of contents 3311 * (DKIOCGVTOC). 3312 * 3313 * Arguments: 3314 * arg pointer to user provided vtoc structure specifying 3315 * the current vtoc. 3316 * 3317 * flag this argument is a pass through to ddi_copyxxx() 3318 * directly from the mode argument of ioctl(). 3319 * 3320 * tg_cookie cookie from target driver to be passed back to target 3321 * driver when we call back to it through tg_ops. 3322 * 3323 * Return Code: 0 3324 * EFAULT 3325 * ENXIO 3326 * EIO 3327 */ 3328 static int 3329 cmlb_dkio_get_vtoc(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie) 3330 { 3331 #if defined(_SUNOS_VTOC_8) 3332 struct vtoc user_vtoc; 3333 #endif /* defined(_SUNOS_VTOC_8) */ 3334 int rval = 0; 3335 3336 mutex_enter(CMLB_MUTEX(cl)); 3337 if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) { 3338 mutex_exit(CMLB_MUTEX(cl)); 3339 return (EOVERFLOW); 3340 } 3341 3342 rval = cmlb_validate_geometry(cl, B_TRUE, 0, tg_cookie); 3343 3344 #if defined(_SUNOS_VTOC_8) 3345 if (rval == EINVAL && 3346 (cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8)) { 3347 /* 3348 * This is to return a default label even when we do not 3349 * really assume a default label for the device. 3350 * dad driver utilizes this. 3351 */ 3352 if (cl->cl_blockcount <= CMLB_OLDVTOC_LIMIT) { 3353 cmlb_setup_default_geometry(cl, tg_cookie); 3354 rval = 0; 3355 } 3356 } 3357 #endif 3358 if (rval) { 3359 mutex_exit(CMLB_MUTEX(cl)); 3360 return (rval); 3361 } 3362 3363 #if defined(_SUNOS_VTOC_8) 3364 cmlb_build_user_vtoc(cl, &user_vtoc); 3365 mutex_exit(CMLB_MUTEX(cl)); 3366 3367 #ifdef _MULTI_DATAMODEL 3368 switch (ddi_model_convert_from(flag & FMODELS)) { 3369 case DDI_MODEL_ILP32: { 3370 struct vtoc32 user_vtoc32; 3371 3372 vtoctovtoc32(user_vtoc, user_vtoc32); 3373 if (ddi_copyout(&user_vtoc32, (void *)arg, 3374 sizeof (struct vtoc32), flag)) { 3375 return (EFAULT); 3376 } 3377 break; 3378 } 3379 3380 case DDI_MODEL_NONE: 3381 if (ddi_copyout(&user_vtoc, (void *)arg, 3382 sizeof (struct vtoc), flag)) { 3383 return (EFAULT); 3384 } 3385 break; 3386 } 3387 #else /* ! _MULTI_DATAMODEL */ 3388 if (ddi_copyout(&user_vtoc, (void *)arg, sizeof (struct vtoc), flag)) { 3389 return (EFAULT); 3390 } 3391 #endif /* _MULTI_DATAMODEL */ 3392 3393 #elif defined(_SUNOS_VTOC_16) 3394 mutex_exit(CMLB_MUTEX(cl)); 3395 3396 #ifdef _MULTI_DATAMODEL 3397 /* 3398 * The cl_vtoc structure is a "struct dk_vtoc" which is always 3399 * 32-bit to maintain compatibility with existing on-disk 3400 * structures. Thus, we need to convert the structure when copying 3401 * it out to a datamodel-dependent "struct vtoc" in a 64-bit 3402 * program. If the target is a 32-bit program, then no conversion 3403 * is necessary. 3404 */ 3405 /* LINTED: logical expression always true: op "||" */ 3406 ASSERT(sizeof (cl->cl_vtoc) == sizeof (struct vtoc32)); 3407 switch (ddi_model_convert_from(flag & FMODELS)) { 3408 case DDI_MODEL_ILP32: 3409 if (ddi_copyout(&(cl->cl_vtoc), (void *)arg, 3410 sizeof (cl->cl_vtoc), flag)) { 3411 return (EFAULT); 3412 } 3413 break; 3414 3415 case DDI_MODEL_NONE: { 3416 struct vtoc user_vtoc; 3417 3418 vtoc32tovtoc(cl->cl_vtoc, user_vtoc); 3419 if (ddi_copyout(&user_vtoc, (void *)arg, 3420 sizeof (struct vtoc), flag)) { 3421 return (EFAULT); 3422 } 3423 break; 3424 } 3425 } 3426 #else /* ! _MULTI_DATAMODEL */ 3427 if (ddi_copyout(&(cl->cl_vtoc), (void *)arg, sizeof (cl->cl_vtoc), 3428 flag)) { 3429 return (EFAULT); 3430 } 3431 #endif /* _MULTI_DATAMODEL */ 3432 #else 3433 #error "No VTOC format defined." 3434 #endif 3435 3436 return (rval); 3437 } 3438 3439 3440 /* 3441 * Function: cmlb_dkio_get_extvtoc 3442 */ 3443 static int 3444 cmlb_dkio_get_extvtoc(struct cmlb_lun *cl, caddr_t arg, int flag, 3445 void *tg_cookie) 3446 { 3447 struct extvtoc ext_vtoc; 3448 #if defined(_SUNOS_VTOC_8) 3449 struct vtoc user_vtoc; 3450 #endif /* defined(_SUNOS_VTOC_8) */ 3451 int rval = 0; 3452 3453 bzero(&ext_vtoc, sizeof (struct extvtoc)); 3454 mutex_enter(CMLB_MUTEX(cl)); 3455 rval = cmlb_validate_geometry(cl, B_TRUE, 0, tg_cookie); 3456 3457 #if defined(_SUNOS_VTOC_8) 3458 if (rval == EINVAL && 3459 (cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8)) { 3460 /* 3461 * This is to return a default label even when we do not 3462 * really assume a default label for the device. 3463 * dad driver utilizes this. 3464 */ 3465 if (cl->cl_blockcount <= CMLB_OLDVTOC_LIMIT) { 3466 cmlb_setup_default_geometry(cl, tg_cookie); 3467 rval = 0; 3468 } 3469 } 3470 #endif 3471 if (rval) { 3472 mutex_exit(CMLB_MUTEX(cl)); 3473 return (rval); 3474 } 3475 3476 #if defined(_SUNOS_VTOC_8) 3477 cmlb_build_user_vtoc(cl, &user_vtoc); 3478 mutex_exit(CMLB_MUTEX(cl)); 3479 3480 /* 3481 * Checking callers data model does not make much sense here 3482 * since extvtoc will always be equivalent to 64bit vtoc. 3483 * What is important is whether the kernel is in 32 or 64 bit 3484 */ 3485 3486 #ifdef _LP64 3487 if (ddi_copyout(&user_vtoc, (void *)arg, 3488 sizeof (struct extvtoc), flag)) { 3489 return (EFAULT); 3490 } 3491 #else 3492 vtoc32tovtoc(user_vtoc, ext_vtoc); 3493 if (ddi_copyout(&ext_vtoc, (void *)arg, 3494 sizeof (struct extvtoc), flag)) { 3495 return (EFAULT); 3496 } 3497 #endif 3498 3499 #elif defined(_SUNOS_VTOC_16) 3500 /* 3501 * The cl_vtoc structure is a "struct dk_vtoc" which is always 3502 * 32-bit to maintain compatibility with existing on-disk 3503 * structures. Thus, we need to convert the structure when copying 3504 * it out to extvtoc 3505 */ 3506 vtoc32tovtoc(cl->cl_vtoc, ext_vtoc); 3507 mutex_exit(CMLB_MUTEX(cl)); 3508 3509 if (ddi_copyout(&ext_vtoc, (void *)arg, sizeof (struct extvtoc), flag)) 3510 return (EFAULT); 3511 #else 3512 #error "No VTOC format defined." 3513 #endif 3514 3515 return (rval); 3516 } 3517 static int 3518 cmlb_dkio_get_efi(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie) 3519 { 3520 dk_efi_t user_efi; 3521 int rval = 0; 3522 void *buffer; 3523 diskaddr_t tgt_lba; 3524 3525 if (ddi_copyin(arg, &user_efi, sizeof (dk_efi_t), flag)) 3526 return (EFAULT); 3527 3528 user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64; 3529 3530 tgt_lba = user_efi.dki_lba; 3531 3532 mutex_enter(CMLB_MUTEX(cl)); 3533 if ((cmlb_check_update_blockcount(cl, tg_cookie) != 0) || 3534 (cl->cl_tgt_blocksize == 0)) { 3535 mutex_exit(CMLB_MUTEX(cl)); 3536 return (EINVAL); 3537 } 3538 if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) 3539 tgt_lba = tgt_lba * cl->cl_tgt_blocksize / 3540 cl->cl_sys_blocksize; 3541 mutex_exit(CMLB_MUTEX(cl)); 3542 3543 buffer = kmem_alloc(user_efi.dki_length, KM_SLEEP); 3544 rval = DK_TG_READ(cl, buffer, tgt_lba, user_efi.dki_length, tg_cookie); 3545 if (rval == 0 && ddi_copyout(buffer, user_efi.dki_data, 3546 user_efi.dki_length, flag) != 0) 3547 rval = EFAULT; 3548 3549 kmem_free(buffer, user_efi.dki_length); 3550 return (rval); 3551 } 3552 3553 #if defined(_SUNOS_VTOC_8) 3554 /* 3555 * Function: cmlb_build_user_vtoc 3556 * 3557 * Description: This routine populates a pass by reference variable with the 3558 * current volume table of contents. 3559 * 3560 * Arguments: cl - driver soft state (unit) structure 3561 * user_vtoc - pointer to vtoc structure to be populated 3562 */ 3563 static void 3564 cmlb_build_user_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc) 3565 { 3566 struct dk_map2 *lpart; 3567 struct dk_map *lmap; 3568 struct partition *vpart; 3569 uint32_t nblks; 3570 int i; 3571 3572 ASSERT(mutex_owned(CMLB_MUTEX(cl))); 3573 3574 /* 3575 * Return vtoc structure fields in the provided VTOC area, addressed 3576 * by *vtoc. 3577 */ 3578 bzero(user_vtoc, sizeof (struct vtoc)); 3579 user_vtoc->v_bootinfo[0] = cl->cl_vtoc.v_bootinfo[0]; 3580 user_vtoc->v_bootinfo[1] = cl->cl_vtoc.v_bootinfo[1]; 3581 user_vtoc->v_bootinfo[2] = cl->cl_vtoc.v_bootinfo[2]; 3582 user_vtoc->v_sanity = VTOC_SANE; 3583 user_vtoc->v_version = cl->cl_vtoc.v_version; 3584 bcopy(cl->cl_vtoc.v_volume, user_vtoc->v_volume, LEN_DKL_VVOL); 3585 user_vtoc->v_sectorsz = cl->cl_sys_blocksize; 3586 user_vtoc->v_nparts = cl->cl_vtoc.v_nparts; 3587 3588 for (i = 0; i < 10; i++) 3589 user_vtoc->v_reserved[i] = cl->cl_vtoc.v_reserved[i]; 3590 3591 /* 3592 * Convert partitioning information. 3593 * 3594 * Note the conversion from starting cylinder number 3595 * to starting sector number. 3596 */ 3597 lmap = cl->cl_map; 3598 lpart = (struct dk_map2 *)cl->cl_vtoc.v_part; 3599 vpart = user_vtoc->v_part; 3600 3601 nblks = cl->cl_g.dkg_nsect * cl->cl_g.dkg_nhead; 3602 3603 for (i = 0; i < V_NUMPAR; i++) { 3604 vpart->p_tag = lpart->p_tag; 3605 vpart->p_flag = lpart->p_flag; 3606 vpart->p_start = lmap->dkl_cylno * nblks; 3607 vpart->p_size = lmap->dkl_nblk; 3608 lmap++; 3609 lpart++; 3610 vpart++; 3611 3612 /* (4364927) */ 3613 user_vtoc->timestamp[i] = (time_t)cl->cl_vtoc.v_timestamp[i]; 3614 } 3615 3616 bcopy(cl->cl_asciilabel, user_vtoc->v_asciilabel, LEN_DKL_ASCII); 3617 } 3618 #endif 3619 3620 static int 3621 cmlb_dkio_partition(struct cmlb_lun *cl, caddr_t arg, int flag, 3622 void *tg_cookie) 3623 { 3624 struct partition64 p64; 3625 int rval = 0; 3626 uint_t nparts; 3627 efi_gpe_t *partitions; 3628 efi_gpt_t *buffer; 3629 diskaddr_t gpe_lba; 3630 3631 if (ddi_copyin((const void *)arg, &p64, 3632 sizeof (struct partition64), flag)) { 3633 return (EFAULT); 3634 } 3635 3636 buffer = kmem_alloc(EFI_MIN_ARRAY_SIZE, KM_SLEEP); 3637 rval = DK_TG_READ(cl, buffer, 1, cl->cl_sys_blocksize, tg_cookie); 3638 if (rval != 0) 3639 goto done_error; 3640 3641 cmlb_swap_efi_gpt(buffer); 3642 3643 if ((rval = cmlb_validate_efi(buffer)) != 0) 3644 goto done_error; 3645 3646 nparts = buffer->efi_gpt_NumberOfPartitionEntries; 3647 gpe_lba = buffer->efi_gpt_PartitionEntryLBA; 3648 if (p64.p_partno > nparts) { 3649 /* couldn't find it */ 3650 rval = ESRCH; 3651 goto done_error; 3652 } 3653 /* 3654 * if we're dealing with a partition that's out of the normal 3655 * 16K block, adjust accordingly 3656 */ 3657 gpe_lba += p64.p_partno / sizeof (efi_gpe_t); 3658 rval = DK_TG_READ(cl, buffer, gpe_lba, EFI_MIN_ARRAY_SIZE, tg_cookie); 3659 3660 if (rval) { 3661 goto done_error; 3662 } 3663 partitions = (efi_gpe_t *)buffer; 3664 3665 cmlb_swap_efi_gpe(nparts, partitions); 3666 3667 partitions += p64.p_partno; 3668 bcopy(&partitions->efi_gpe_PartitionTypeGUID, &p64.p_type, 3669 sizeof (struct uuid)); 3670 p64.p_start = partitions->efi_gpe_StartingLBA; 3671 p64.p_size = partitions->efi_gpe_EndingLBA - 3672 p64.p_start + 1; 3673 3674 if (ddi_copyout(&p64, (void *)arg, sizeof (struct partition64), flag)) 3675 rval = EFAULT; 3676 3677 done_error: 3678 kmem_free(buffer, EFI_MIN_ARRAY_SIZE); 3679 return (rval); 3680 } 3681 3682 3683 /* 3684 * Function: cmlb_dkio_set_vtoc 3685 * 3686 * Description: This routine is the driver entry point for handling user 3687 * requests to set the current volume table of contents 3688 * (DKIOCSVTOC). 3689 * 3690 * Arguments: 3691 * dev the device number 3692 * arg pointer to user provided vtoc structure used to set the 3693 * current vtoc. 3694 * 3695 * flag this argument is a pass through to ddi_copyxxx() 3696 * directly from the mode argument of ioctl(). 3697 * 3698 * tg_cookie cookie from target driver to be passed back to target 3699 * driver when we call back to it through tg_ops. 3700 * 3701 * Return Code: 0 3702 * EFAULT 3703 * ENXIO 3704 * EINVAL 3705 * ENOTSUP 3706 */ 3707 static int 3708 cmlb_dkio_set_vtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag, 3709 void *tg_cookie) 3710 { 3711 struct vtoc user_vtoc; 3712 int rval = 0; 3713 boolean_t internal; 3714 3715 internal = VOID2BOOLEAN( 3716 (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0); 3717 3718 #ifdef _MULTI_DATAMODEL 3719 switch (ddi_model_convert_from(flag & FMODELS)) { 3720 case DDI_MODEL_ILP32: { 3721 struct vtoc32 user_vtoc32; 3722 3723 if (ddi_copyin((const void *)arg, &user_vtoc32, 3724 sizeof (struct vtoc32), flag)) { 3725 return (EFAULT); 3726 } 3727 vtoc32tovtoc(user_vtoc32, user_vtoc); 3728 break; 3729 } 3730 3731 case DDI_MODEL_NONE: 3732 if (ddi_copyin((const void *)arg, &user_vtoc, 3733 sizeof (struct vtoc), flag)) { 3734 return (EFAULT); 3735 } 3736 break; 3737 } 3738 #else /* ! _MULTI_DATAMODEL */ 3739 if (ddi_copyin((const void *)arg, &user_vtoc, 3740 sizeof (struct vtoc), flag)) { 3741 return (EFAULT); 3742 } 3743 #endif /* _MULTI_DATAMODEL */ 3744 3745 mutex_enter(CMLB_MUTEX(cl)); 3746 3747 if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) { 3748 mutex_exit(CMLB_MUTEX(cl)); 3749 return (EOVERFLOW); 3750 } 3751 3752 #if defined(__i386) || defined(__amd64) 3753 if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) { 3754 mutex_exit(CMLB_MUTEX(cl)); 3755 return (EINVAL); 3756 } 3757 #endif 3758 3759 if (cl->cl_g.dkg_ncyl == 0) { 3760 mutex_exit(CMLB_MUTEX(cl)); 3761 return (EINVAL); 3762 } 3763 3764 mutex_exit(CMLB_MUTEX(cl)); 3765 cmlb_clear_efi(cl, tg_cookie); 3766 ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd"); 3767 ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd,raw"); 3768 3769 /* 3770 * cmlb_dkio_set_vtoc creates duplicate minor nodes when 3771 * relabeling an SMI disk. To avoid that we remove them 3772 * before creating. 3773 * It should be OK to remove a non-existed minor node. 3774 */ 3775 ddi_remove_minor_node(CMLB_DEVINFO(cl), "h"); 3776 ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw"); 3777 3778 (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h", 3779 S_IFBLK, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 3780 cl->cl_node_type, NULL, internal); 3781 (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h,raw", 3782 S_IFCHR, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 3783 cl->cl_node_type, NULL, internal); 3784 mutex_enter(CMLB_MUTEX(cl)); 3785 3786 if ((rval = cmlb_build_label_vtoc(cl, &user_vtoc)) == 0) { 3787 if ((rval = cmlb_write_label(cl, tg_cookie)) == 0) { 3788 if (cmlb_validate_geometry(cl, 3789 B_TRUE, 0, tg_cookie) != 0) { 3790 cmlb_dbg(CMLB_ERROR, cl, 3791 "cmlb_dkio_set_vtoc: " 3792 "Failed validate geometry\n"); 3793 } 3794 cl->cl_msglog_flag |= CMLB_ALLOW_2TB_WARN; 3795 } 3796 } 3797 mutex_exit(CMLB_MUTEX(cl)); 3798 return (rval); 3799 } 3800 3801 /* 3802 * Function: cmlb_dkio_set_extvtoc 3803 */ 3804 static int 3805 cmlb_dkio_set_extvtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag, 3806 void *tg_cookie) 3807 { 3808 int rval = 0; 3809 struct vtoc user_vtoc; 3810 boolean_t internal; 3811 3812 3813 /* 3814 * Checking callers data model does not make much sense here 3815 * since extvtoc will always be equivalent to 64bit vtoc. 3816 * What is important is whether the kernel is in 32 or 64 bit 3817 */ 3818 3819 #ifdef _LP64 3820 if (ddi_copyin((const void *)arg, &user_vtoc, 3821 sizeof (struct extvtoc), flag)) { 3822 return (EFAULT); 3823 } 3824 #else 3825 struct extvtoc user_extvtoc; 3826 if (ddi_copyin((const void *)arg, &user_extvtoc, 3827 sizeof (struct extvtoc), flag)) { 3828 return (EFAULT); 3829 } 3830 3831 vtoctovtoc32(user_extvtoc, user_vtoc); 3832 #endif 3833 3834 internal = VOID2BOOLEAN( 3835 (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0); 3836 mutex_enter(CMLB_MUTEX(cl)); 3837 #if defined(__i386) || defined(__amd64) 3838 if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) { 3839 mutex_exit(CMLB_MUTEX(cl)); 3840 return (EINVAL); 3841 } 3842 #endif 3843 3844 if (cl->cl_g.dkg_ncyl == 0) { 3845 mutex_exit(CMLB_MUTEX(cl)); 3846 return (EINVAL); 3847 } 3848 3849 mutex_exit(CMLB_MUTEX(cl)); 3850 cmlb_clear_efi(cl, tg_cookie); 3851 ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd"); 3852 ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd,raw"); 3853 (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h", 3854 S_IFBLK, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 3855 cl->cl_node_type, NULL, internal); 3856 (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h,raw", 3857 S_IFCHR, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 3858 cl->cl_node_type, NULL, internal); 3859 3860 mutex_enter(CMLB_MUTEX(cl)); 3861 3862 if ((rval = cmlb_build_label_vtoc(cl, &user_vtoc)) == 0) { 3863 if ((rval = cmlb_write_label(cl, tg_cookie)) == 0) { 3864 if (cmlb_validate_geometry(cl, 3865 B_TRUE, 0, tg_cookie) != 0) { 3866 cmlb_dbg(CMLB_ERROR, cl, 3867 "cmlb_dkio_set_vtoc: " 3868 "Failed validate geometry\n"); 3869 } 3870 } 3871 } 3872 mutex_exit(CMLB_MUTEX(cl)); 3873 return (rval); 3874 } 3875 3876 /* 3877 * Function: cmlb_build_label_vtoc 3878 * 3879 * Description: This routine updates the driver soft state current volume table 3880 * of contents based on a user specified vtoc. 3881 * 3882 * Arguments: cl - driver soft state (unit) structure 3883 * user_vtoc - pointer to vtoc structure specifying vtoc to be used 3884 * to update the driver soft state. 3885 * 3886 * Return Code: 0 3887 * EINVAL 3888 */ 3889 static int 3890 cmlb_build_label_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc) 3891 { 3892 struct dk_map *lmap; 3893 struct partition *vpart; 3894 uint_t nblks; 3895 #if defined(_SUNOS_VTOC_8) 3896 int ncyl; 3897 struct dk_map2 *lpart; 3898 #endif /* defined(_SUNOS_VTOC_8) */ 3899 int i; 3900 3901 ASSERT(mutex_owned(CMLB_MUTEX(cl))); 3902 3903 /* Sanity-check the vtoc */ 3904 if (user_vtoc->v_sanity != VTOC_SANE || 3905 user_vtoc->v_sectorsz != cl->cl_sys_blocksize || 3906 user_vtoc->v_nparts != V_NUMPAR) { 3907 cmlb_dbg(CMLB_INFO, cl, 3908 "cmlb_build_label_vtoc: vtoc not valid\n"); 3909 return (EINVAL); 3910 } 3911 3912 nblks = cl->cl_g.dkg_nsect * cl->cl_g.dkg_nhead; 3913 if (nblks == 0) { 3914 cmlb_dbg(CMLB_INFO, cl, 3915 "cmlb_build_label_vtoc: geom nblks is 0\n"); 3916 return (EINVAL); 3917 } 3918 3919 #if defined(_SUNOS_VTOC_8) 3920 vpart = user_vtoc->v_part; 3921 for (i = 0; i < V_NUMPAR; i++) { 3922 if (((unsigned)vpart->p_start % nblks) != 0) { 3923 cmlb_dbg(CMLB_INFO, cl, 3924 "cmlb_build_label_vtoc: p_start not multiply of" 3925 "nblks part %d p_start %d nblks %d\n", i, 3926 vpart->p_start, nblks); 3927 return (EINVAL); 3928 } 3929 ncyl = (unsigned)vpart->p_start / nblks; 3930 ncyl += (unsigned)vpart->p_size / nblks; 3931 if (((unsigned)vpart->p_size % nblks) != 0) { 3932 ncyl++; 3933 } 3934 if (ncyl > (int)cl->cl_g.dkg_ncyl) { 3935 cmlb_dbg(CMLB_INFO, cl, 3936 "cmlb_build_label_vtoc: ncyl %d > dkg_ncyl %d" 3937 "p_size %ld p_start %ld nblks %d part number %d" 3938 "tag %d\n", 3939 ncyl, cl->cl_g.dkg_ncyl, vpart->p_size, 3940 vpart->p_start, nblks, 3941 i, vpart->p_tag); 3942 3943 return (EINVAL); 3944 } 3945 vpart++; 3946 } 3947 #endif /* defined(_SUNOS_VTOC_8) */ 3948 3949 /* Put appropriate vtoc structure fields into the disk label */ 3950 #if defined(_SUNOS_VTOC_16) 3951 /* 3952 * The vtoc is always a 32bit data structure to maintain the 3953 * on-disk format. Convert "in place" instead of doing bcopy. 3954 */ 3955 vtoctovtoc32((*user_vtoc), (*((struct vtoc32 *)&(cl->cl_vtoc)))); 3956 3957 /* 3958 * in the 16-slice vtoc, starting sectors are expressed in 3959 * numbers *relative* to the start of the Solaris fdisk partition. 3960 */ 3961 lmap = cl->cl_map; 3962 vpart = user_vtoc->v_part; 3963 3964 for (i = 0; i < (int)user_vtoc->v_nparts; i++, lmap++, vpart++) { 3965 lmap->dkl_cylno = (unsigned)vpart->p_start / nblks; 3966 lmap->dkl_nblk = (unsigned)vpart->p_size; 3967 } 3968 3969 #elif defined(_SUNOS_VTOC_8) 3970 3971 cl->cl_vtoc.v_bootinfo[0] = (uint32_t)user_vtoc->v_bootinfo[0]; 3972 cl->cl_vtoc.v_bootinfo[1] = (uint32_t)user_vtoc->v_bootinfo[1]; 3973 cl->cl_vtoc.v_bootinfo[2] = (uint32_t)user_vtoc->v_bootinfo[2]; 3974 3975 cl->cl_vtoc.v_sanity = (uint32_t)user_vtoc->v_sanity; 3976 cl->cl_vtoc.v_version = (uint32_t)user_vtoc->v_version; 3977 3978 bcopy(user_vtoc->v_volume, cl->cl_vtoc.v_volume, LEN_DKL_VVOL); 3979 3980 cl->cl_vtoc.v_nparts = user_vtoc->v_nparts; 3981 3982 for (i = 0; i < 10; i++) 3983 cl->cl_vtoc.v_reserved[i] = user_vtoc->v_reserved[i]; 3984 3985 /* 3986 * Note the conversion from starting sector number 3987 * to starting cylinder number. 3988 * Return error if division results in a remainder. 3989 */ 3990 lmap = cl->cl_map; 3991 lpart = cl->cl_vtoc.v_part; 3992 vpart = user_vtoc->v_part; 3993 3994 for (i = 0; i < (int)user_vtoc->v_nparts; i++) { 3995 lpart->p_tag = vpart->p_tag; 3996 lpart->p_flag = vpart->p_flag; 3997 lmap->dkl_cylno = (unsigned)vpart->p_start / nblks; 3998 lmap->dkl_nblk = (unsigned)vpart->p_size; 3999 4000 lmap++; 4001 lpart++; 4002 vpart++; 4003 4004 /* (4387723) */ 4005 #ifdef _LP64 4006 if (user_vtoc->timestamp[i] > TIME32_MAX) { 4007 cl->cl_vtoc.v_timestamp[i] = TIME32_MAX; 4008 } else { 4009 cl->cl_vtoc.v_timestamp[i] = user_vtoc->timestamp[i]; 4010 } 4011 #else 4012 cl->cl_vtoc.v_timestamp[i] = user_vtoc->timestamp[i]; 4013 #endif 4014 } 4015 4016 bcopy(user_vtoc->v_asciilabel, cl->cl_asciilabel, LEN_DKL_ASCII); 4017 #else 4018 #error "No VTOC format defined." 4019 #endif 4020 return (0); 4021 } 4022 4023 /* 4024 * Function: cmlb_clear_efi 4025 * 4026 * Description: This routine clears all EFI labels. 4027 * 4028 * Arguments: 4029 * cl driver soft state (unit) structure 4030 * 4031 * tg_cookie cookie from target driver to be passed back to target 4032 * driver when we call back to it through tg_ops. 4033 * Return Code: void 4034 */ 4035 static void 4036 cmlb_clear_efi(struct cmlb_lun *cl, void *tg_cookie) 4037 { 4038 efi_gpt_t *gpt; 4039 diskaddr_t cap; 4040 int rval; 4041 4042 ASSERT(!mutex_owned(CMLB_MUTEX(cl))); 4043 4044 mutex_enter(CMLB_MUTEX(cl)); 4045 cl->cl_reserved = -1; 4046 mutex_exit(CMLB_MUTEX(cl)); 4047 4048 gpt = kmem_alloc(cl->cl_sys_blocksize, KM_SLEEP); 4049 4050 if (DK_TG_READ(cl, gpt, 1, cl->cl_sys_blocksize, tg_cookie) != 0) { 4051 goto done; 4052 } 4053 4054 cmlb_swap_efi_gpt(gpt); 4055 rval = cmlb_validate_efi(gpt); 4056 if (rval == 0) { 4057 /* clear primary */ 4058 bzero(gpt, sizeof (efi_gpt_t)); 4059 if (rval = DK_TG_WRITE(cl, gpt, 1, cl->cl_sys_blocksize, 4060 tg_cookie)) { 4061 cmlb_dbg(CMLB_INFO, cl, 4062 "cmlb_clear_efi: clear primary label failed\n"); 4063 } 4064 } 4065 /* the backup */ 4066 rval = DK_TG_GETCAP(cl, &cap, tg_cookie); 4067 if (rval) { 4068 goto done; 4069 } 4070 4071 if ((rval = DK_TG_READ(cl, gpt, cap - 1, cl->cl_sys_blocksize, 4072 tg_cookie)) != 0) { 4073 goto done; 4074 } 4075 cmlb_swap_efi_gpt(gpt); 4076 rval = cmlb_validate_efi(gpt); 4077 if (rval == 0) { 4078 /* clear backup */ 4079 cmlb_dbg(CMLB_TRACE, cl, 4080 "cmlb_clear_efi clear backup@%lu\n", cap - 1); 4081 bzero(gpt, sizeof (efi_gpt_t)); 4082 if ((rval = DK_TG_WRITE(cl, gpt, cap - 1, cl->cl_sys_blocksize, 4083 tg_cookie))) { 4084 cmlb_dbg(CMLB_INFO, cl, 4085 "cmlb_clear_efi: clear backup label failed\n"); 4086 } 4087 } else { 4088 /* 4089 * Refer to comments related to off-by-1 at the 4090 * header of this file 4091 */ 4092 if ((rval = DK_TG_READ(cl, gpt, cap - 2, 4093 cl->cl_sys_blocksize, tg_cookie)) != 0) { 4094 goto done; 4095 } 4096 cmlb_swap_efi_gpt(gpt); 4097 rval = cmlb_validate_efi(gpt); 4098 if (rval == 0) { 4099 /* clear legacy backup EFI label */ 4100 cmlb_dbg(CMLB_TRACE, cl, 4101 "cmlb_clear_efi clear legacy backup@%lu\n", 4102 cap - 2); 4103 bzero(gpt, sizeof (efi_gpt_t)); 4104 if ((rval = DK_TG_WRITE(cl, gpt, cap - 2, 4105 cl->cl_sys_blocksize, tg_cookie))) { 4106 cmlb_dbg(CMLB_INFO, cl, 4107 "cmlb_clear_efi: clear legacy backup label " 4108 "failed\n"); 4109 } 4110 } 4111 } 4112 4113 done: 4114 kmem_free(gpt, cl->cl_sys_blocksize); 4115 } 4116 4117 /* 4118 * Function: cmlb_set_vtoc 4119 * 4120 * Description: This routine writes data to the appropriate positions 4121 * 4122 * Arguments: 4123 * cl driver soft state (unit) structure 4124 * 4125 * dkl the data to be written 4126 * 4127 * tg_cookie cookie from target driver to be passed back to target 4128 * driver when we call back to it through tg_ops. 4129 * 4130 * Return: void 4131 */ 4132 static int 4133 cmlb_set_vtoc(struct cmlb_lun *cl, struct dk_label *dkl, void *tg_cookie) 4134 { 4135 uint_t label_addr; 4136 int sec; 4137 diskaddr_t blk; 4138 int head; 4139 int cyl; 4140 int rval; 4141 4142 #if defined(__i386) || defined(__amd64) 4143 label_addr = cl->cl_solaris_offset + DK_LABEL_LOC; 4144 #else 4145 /* Write the primary label at block 0 of the solaris partition. */ 4146 label_addr = 0; 4147 #endif 4148 4149 rval = DK_TG_WRITE(cl, dkl, label_addr, cl->cl_sys_blocksize, 4150 tg_cookie); 4151 4152 if (rval != 0) { 4153 return (rval); 4154 } 4155 4156 /* 4157 * Calculate where the backup labels go. They are always on 4158 * the last alternate cylinder, but some older drives put them 4159 * on head 2 instead of the last head. They are always on the 4160 * first 5 odd sectors of the appropriate track. 4161 * 4162 * We have no choice at this point, but to believe that the 4163 * disk label is valid. Use the geometry of the disk 4164 * as described in the label. 4165 */ 4166 cyl = dkl->dkl_ncyl + dkl->dkl_acyl - 1; 4167 head = dkl->dkl_nhead - 1; 4168 4169 /* 4170 * Write and verify the backup labels. Make sure we don't try to 4171 * write past the last cylinder. 4172 */ 4173 for (sec = 1; ((sec < 5 * 2 + 1) && (sec < dkl->dkl_nsect)); sec += 2) { 4174 blk = (diskaddr_t)( 4175 (cyl * ((dkl->dkl_nhead * dkl->dkl_nsect) - dkl->dkl_apc)) + 4176 (head * dkl->dkl_nsect) + sec); 4177 #if defined(__i386) || defined(__amd64) 4178 blk += cl->cl_solaris_offset; 4179 #endif 4180 rval = DK_TG_WRITE(cl, dkl, blk, cl->cl_sys_blocksize, 4181 tg_cookie); 4182 cmlb_dbg(CMLB_INFO, cl, 4183 "cmlb_set_vtoc: wrote backup label %llx\n", blk); 4184 if (rval != 0) { 4185 goto exit; 4186 } 4187 } 4188 exit: 4189 return (rval); 4190 } 4191 4192 /* 4193 * Function: cmlb_clear_vtoc 4194 * 4195 * Description: This routine clears out the VTOC labels. 4196 * 4197 * Arguments: 4198 * cl driver soft state (unit) structure 4199 * 4200 * tg_cookie cookie from target driver to be passed back to target 4201 * driver when we call back to it through tg_ops. 4202 * 4203 * Return: void 4204 */ 4205 static void 4206 cmlb_clear_vtoc(struct cmlb_lun *cl, void *tg_cookie) 4207 { 4208 struct dk_label *dkl; 4209 4210 mutex_exit(CMLB_MUTEX(cl)); 4211 dkl = kmem_zalloc(cl->cl_sys_blocksize, KM_SLEEP); 4212 mutex_enter(CMLB_MUTEX(cl)); 4213 /* 4214 * cmlb_set_vtoc uses these fields in order to figure out 4215 * where to overwrite the backup labels 4216 */ 4217 dkl->dkl_apc = cl->cl_g.dkg_apc; 4218 dkl->dkl_ncyl = cl->cl_g.dkg_ncyl; 4219 dkl->dkl_acyl = cl->cl_g.dkg_acyl; 4220 dkl->dkl_nhead = cl->cl_g.dkg_nhead; 4221 dkl->dkl_nsect = cl->cl_g.dkg_nsect; 4222 mutex_exit(CMLB_MUTEX(cl)); 4223 (void) cmlb_set_vtoc(cl, dkl, tg_cookie); 4224 kmem_free(dkl, cl->cl_sys_blocksize); 4225 4226 mutex_enter(CMLB_MUTEX(cl)); 4227 } 4228 4229 /* 4230 * Function: cmlb_write_label 4231 * 4232 * Description: This routine will validate and write the driver soft state vtoc 4233 * contents to the device. 4234 * 4235 * Arguments: 4236 * cl cmlb handle 4237 * 4238 * tg_cookie cookie from target driver to be passed back to target 4239 * driver when we call back to it through tg_ops. 4240 * 4241 * 4242 * Return Code: the code returned by cmlb_send_scsi_cmd() 4243 * 0 4244 * EINVAL 4245 * ENXIO 4246 * ENOMEM 4247 */ 4248 static int 4249 cmlb_write_label(struct cmlb_lun *cl, void *tg_cookie) 4250 { 4251 struct dk_label *dkl; 4252 short sum; 4253 short *sp; 4254 int i; 4255 int rval; 4256 4257 ASSERT(mutex_owned(CMLB_MUTEX(cl))); 4258 mutex_exit(CMLB_MUTEX(cl)); 4259 dkl = kmem_zalloc(cl->cl_sys_blocksize, KM_SLEEP); 4260 mutex_enter(CMLB_MUTEX(cl)); 4261 4262 bcopy(&cl->cl_vtoc, &dkl->dkl_vtoc, sizeof (struct dk_vtoc)); 4263 dkl->dkl_rpm = cl->cl_g.dkg_rpm; 4264 dkl->dkl_pcyl = cl->cl_g.dkg_pcyl; 4265 dkl->dkl_apc = cl->cl_g.dkg_apc; 4266 dkl->dkl_intrlv = cl->cl_g.dkg_intrlv; 4267 dkl->dkl_ncyl = cl->cl_g.dkg_ncyl; 4268 dkl->dkl_acyl = cl->cl_g.dkg_acyl; 4269 dkl->dkl_nhead = cl->cl_g.dkg_nhead; 4270 dkl->dkl_nsect = cl->cl_g.dkg_nsect; 4271 4272 #if defined(_SUNOS_VTOC_8) 4273 dkl->dkl_obs1 = cl->cl_g.dkg_obs1; 4274 dkl->dkl_obs2 = cl->cl_g.dkg_obs2; 4275 dkl->dkl_obs3 = cl->cl_g.dkg_obs3; 4276 for (i = 0; i < NDKMAP; i++) { 4277 dkl->dkl_map[i].dkl_cylno = cl->cl_map[i].dkl_cylno; 4278 dkl->dkl_map[i].dkl_nblk = cl->cl_map[i].dkl_nblk; 4279 } 4280 bcopy(cl->cl_asciilabel, dkl->dkl_asciilabel, LEN_DKL_ASCII); 4281 #elif defined(_SUNOS_VTOC_16) 4282 dkl->dkl_skew = cl->cl_dkg_skew; 4283 #else 4284 #error "No VTOC format defined." 4285 #endif 4286 4287 dkl->dkl_magic = DKL_MAGIC; 4288 dkl->dkl_write_reinstruct = cl->cl_g.dkg_write_reinstruct; 4289 dkl->dkl_read_reinstruct = cl->cl_g.dkg_read_reinstruct; 4290 4291 /* Construct checksum for the new disk label */ 4292 sum = 0; 4293 sp = (short *)dkl; 4294 i = sizeof (struct dk_label) / sizeof (short); 4295 while (i--) { 4296 sum ^= *sp++; 4297 } 4298 dkl->dkl_cksum = sum; 4299 4300 mutex_exit(CMLB_MUTEX(cl)); 4301 4302 rval = cmlb_set_vtoc(cl, dkl, tg_cookie); 4303 exit: 4304 kmem_free(dkl, cl->cl_sys_blocksize); 4305 mutex_enter(CMLB_MUTEX(cl)); 4306 return (rval); 4307 } 4308 4309 static int 4310 cmlb_dkio_set_efi(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag, 4311 void *tg_cookie) 4312 { 4313 dk_efi_t user_efi; 4314 int rval = 0; 4315 void *buffer; 4316 diskaddr_t tgt_lba; 4317 boolean_t internal; 4318 4319 if (ddi_copyin(arg, &user_efi, sizeof (dk_efi_t), flag)) 4320 return (EFAULT); 4321 4322 internal = VOID2BOOLEAN( 4323 (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0); 4324 4325 user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64; 4326 4327 buffer = kmem_alloc(user_efi.dki_length, KM_SLEEP); 4328 if (ddi_copyin(user_efi.dki_data, buffer, user_efi.dki_length, flag)) { 4329 rval = EFAULT; 4330 } else { 4331 /* 4332 * let's clear the vtoc labels and clear the softstate 4333 * vtoc. 4334 */ 4335 mutex_enter(CMLB_MUTEX(cl)); 4336 if (cl->cl_vtoc.v_sanity == VTOC_SANE) { 4337 cmlb_dbg(CMLB_TRACE, cl, 4338 "cmlb_dkio_set_efi: CLEAR VTOC\n"); 4339 if (cl->cl_label_from_media == CMLB_LABEL_VTOC) 4340 cmlb_clear_vtoc(cl, tg_cookie); 4341 bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc)); 4342 mutex_exit(CMLB_MUTEX(cl)); 4343 ddi_remove_minor_node(CMLB_DEVINFO(cl), "h"); 4344 ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw"); 4345 (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd", 4346 S_IFBLK, 4347 (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 4348 cl->cl_node_type, NULL, internal); 4349 (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd,raw", 4350 S_IFCHR, 4351 (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 4352 cl->cl_node_type, NULL, internal); 4353 } else 4354 mutex_exit(CMLB_MUTEX(cl)); 4355 4356 tgt_lba = user_efi.dki_lba; 4357 4358 mutex_enter(CMLB_MUTEX(cl)); 4359 if ((cmlb_check_update_blockcount(cl, tg_cookie) != 0) || 4360 (cl->cl_tgt_blocksize == 0)) { 4361 kmem_free(buffer, user_efi.dki_length); 4362 mutex_exit(CMLB_MUTEX(cl)); 4363 return (EINVAL); 4364 } 4365 if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) 4366 tgt_lba = tgt_lba * 4367 cl->cl_tgt_blocksize / cl->cl_sys_blocksize; 4368 4369 mutex_exit(CMLB_MUTEX(cl)); 4370 rval = DK_TG_WRITE(cl, buffer, tgt_lba, user_efi.dki_length, 4371 tg_cookie); 4372 4373 if (rval == 0) { 4374 mutex_enter(CMLB_MUTEX(cl)); 4375 cl->cl_f_geometry_is_valid = B_FALSE; 4376 mutex_exit(CMLB_MUTEX(cl)); 4377 } 4378 } 4379 kmem_free(buffer, user_efi.dki_length); 4380 return (rval); 4381 } 4382 4383 /* 4384 * Function: cmlb_dkio_get_mboot 4385 * 4386 * Description: This routine is the driver entry point for handling user 4387 * requests to get the current device mboot (DKIOCGMBOOT) 4388 * 4389 * Arguments: 4390 * arg pointer to user provided mboot structure specifying 4391 * the current mboot. 4392 * 4393 * flag this argument is a pass through to ddi_copyxxx() 4394 * directly from the mode argument of ioctl(). 4395 * 4396 * tg_cookie cookie from target driver to be passed back to target 4397 * driver when we call back to it through tg_ops. 4398 * 4399 * Return Code: 0 4400 * EINVAL 4401 * EFAULT 4402 * ENXIO 4403 */ 4404 static int 4405 cmlb_dkio_get_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie) 4406 { 4407 struct mboot *mboot; 4408 int rval; 4409 size_t buffer_size; 4410 4411 4412 #if defined(_SUNOS_VTOC_8) 4413 if ((!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) || (arg == NULL)) { 4414 #elif defined(_SUNOS_VTOC_16) 4415 if (arg == NULL) { 4416 #endif 4417 return (EINVAL); 4418 } 4419 4420 /* 4421 * Read the mboot block, located at absolute block 0 on the target. 4422 */ 4423 buffer_size = cl->cl_sys_blocksize; 4424 4425 cmlb_dbg(CMLB_TRACE, cl, 4426 "cmlb_dkio_get_mboot: allocation size: 0x%x\n", buffer_size); 4427 4428 mboot = kmem_zalloc(buffer_size, KM_SLEEP); 4429 if ((rval = DK_TG_READ(cl, mboot, 0, buffer_size, tg_cookie)) == 0) { 4430 if (ddi_copyout(mboot, (void *)arg, 4431 sizeof (struct mboot), flag) != 0) { 4432 rval = EFAULT; 4433 } 4434 } 4435 kmem_free(mboot, buffer_size); 4436 return (rval); 4437 } 4438 4439 4440 /* 4441 * Function: cmlb_dkio_set_mboot 4442 * 4443 * Description: This routine is the driver entry point for handling user 4444 * requests to validate and set the device master boot 4445 * (DKIOCSMBOOT). 4446 * 4447 * Arguments: 4448 * arg pointer to user provided mboot structure used to set the 4449 * master boot. 4450 * 4451 * flag this argument is a pass through to ddi_copyxxx() 4452 * directly from the mode argument of ioctl(). 4453 * 4454 * tg_cookie cookie from target driver to be passed back to target 4455 * driver when we call back to it through tg_ops. 4456 * 4457 * Return Code: 0 4458 * EINVAL 4459 * EFAULT 4460 * ENXIO 4461 */ 4462 static int 4463 cmlb_dkio_set_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie) 4464 { 4465 struct mboot *mboot = NULL; 4466 int rval; 4467 ushort_t magic; 4468 4469 4470 ASSERT(!mutex_owned(CMLB_MUTEX(cl))); 4471 4472 #if defined(_SUNOS_VTOC_8) 4473 if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) { 4474 return (EINVAL); 4475 } 4476 #endif 4477 4478 if (arg == NULL) { 4479 return (EINVAL); 4480 } 4481 4482 mboot = kmem_zalloc(cl->cl_sys_blocksize, KM_SLEEP); 4483 4484 if (ddi_copyin((const void *)arg, mboot, 4485 cl->cl_sys_blocksize, flag) != 0) { 4486 kmem_free(mboot, cl->cl_sys_blocksize); 4487 return (EFAULT); 4488 } 4489 4490 /* Is this really a master boot record? */ 4491 magic = LE_16(mboot->signature); 4492 if (magic != MBB_MAGIC) { 4493 kmem_free(mboot, cl->cl_sys_blocksize); 4494 return (EINVAL); 4495 } 4496 4497 rval = DK_TG_WRITE(cl, mboot, 0, cl->cl_sys_blocksize, tg_cookie); 4498 4499 mutex_enter(CMLB_MUTEX(cl)); 4500 #if defined(__i386) || defined(__amd64) 4501 if (rval == 0) { 4502 /* 4503 * mboot has been written successfully. 4504 * update the fdisk and vtoc tables in memory 4505 */ 4506 rval = cmlb_update_fdisk_and_vtoc(cl, tg_cookie); 4507 if ((!cl->cl_f_geometry_is_valid) || (rval != 0)) { 4508 mutex_exit(CMLB_MUTEX(cl)); 4509 kmem_free(mboot, cl->cl_sys_blocksize); 4510 return (rval); 4511 } 4512 } 4513 4514 #ifdef __lock_lint 4515 cmlb_setup_default_geometry(cl, tg_cookie); 4516 #endif 4517 4518 #else 4519 if (rval == 0) { 4520 /* 4521 * mboot has been written successfully. 4522 * set up the default geometry and VTOC 4523 */ 4524 if (cl->cl_blockcount <= CMLB_EXTVTOC_LIMIT) 4525 cmlb_setup_default_geometry(cl, tg_cookie); 4526 } 4527 #endif 4528 cl->cl_msglog_flag |= CMLB_ALLOW_2TB_WARN; 4529 mutex_exit(CMLB_MUTEX(cl)); 4530 kmem_free(mboot, cl->cl_sys_blocksize); 4531 return (rval); 4532 } 4533 4534 4535 /* 4536 * Function: cmlb_setup_default_geometry 4537 * 4538 * Description: This local utility routine sets the default geometry as part of 4539 * setting the device mboot. 4540 * 4541 * Arguments: 4542 * cl driver soft state (unit) structure 4543 * 4544 * tg_cookie cookie from target driver to be passed back to target 4545 * driver when we call back to it through tg_ops. 4546 * 4547 * 4548 * Note: This may be redundant with cmlb_build_default_label. 4549 */ 4550 static void 4551 cmlb_setup_default_geometry(struct cmlb_lun *cl, void *tg_cookie) 4552 { 4553 struct cmlb_geom pgeom; 4554 struct cmlb_geom *pgeomp = &pgeom; 4555 int ret; 4556 int geom_base_cap = 1; 4557 4558 4559 ASSERT(mutex_owned(CMLB_MUTEX(cl))); 4560 4561 /* zero out the soft state geometry and partition table. */ 4562 bzero(&cl->cl_g, sizeof (struct dk_geom)); 4563 bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc)); 4564 bzero(cl->cl_map, NDKMAP * (sizeof (struct dk_map))); 4565 4566 /* 4567 * For the rpm, we use the minimum for the disk. 4568 * For the head, cyl and number of sector per track, 4569 * if the capacity <= 1GB, head = 64, sect = 32. 4570 * else head = 255, sect 63 4571 * Note: the capacity should be equal to C*H*S values. 4572 * This will cause some truncation of size due to 4573 * round off errors. For CD-ROMs, this truncation can 4574 * have adverse side effects, so returning ncyl and 4575 * nhead as 1. The nsect will overflow for most of 4576 * CD-ROMs as nsect is of type ushort. 4577 */ 4578 if (cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8) { 4579 /* 4580 * newfs currently can not handle 255 ntracks for SPARC 4581 * so get the geometry from target driver instead of coming up 4582 * with one based on capacity. 4583 */ 4584 mutex_exit(CMLB_MUTEX(cl)); 4585 ret = DK_TG_GETPHYGEOM(cl, pgeomp, tg_cookie); 4586 mutex_enter(CMLB_MUTEX(cl)); 4587 4588 if (ret == 0) { 4589 geom_base_cap = 0; 4590 } else { 4591 cmlb_dbg(CMLB_ERROR, cl, 4592 "cmlb_setup_default_geometry: " 4593 "tg_getphygeom failed %d\n", ret); 4594 4595 /* do default setting, geometry based on capacity */ 4596 } 4597 } 4598 4599 if (geom_base_cap) { 4600 if (ISCD(cl)) { 4601 cl->cl_g.dkg_ncyl = 1; 4602 cl->cl_g.dkg_nhead = 1; 4603 cl->cl_g.dkg_nsect = cl->cl_blockcount; 4604 } else if (cl->cl_blockcount <= 0x1000) { 4605 /* Needed for unlabeled SCSI floppies. */ 4606 cl->cl_g.dkg_nhead = 2; 4607 cl->cl_g.dkg_ncyl = 80; 4608 cl->cl_g.dkg_pcyl = 80; 4609 cl->cl_g.dkg_nsect = cl->cl_blockcount / (2 * 80); 4610 } else if (cl->cl_blockcount <= 0x200000) { 4611 cl->cl_g.dkg_nhead = 64; 4612 cl->cl_g.dkg_nsect = 32; 4613 cl->cl_g.dkg_ncyl = cl->cl_blockcount / (64 * 32); 4614 } else { 4615 cl->cl_g.dkg_nhead = 255; 4616 4617 cl->cl_g.dkg_nsect = ((cl->cl_blockcount + 4618 (UINT16_MAX * 255 * 63) - 1) / 4619 (UINT16_MAX * 255 * 63)) * 63; 4620 4621 if (cl->cl_g.dkg_nsect == 0) 4622 cl->cl_g.dkg_nsect = (UINT16_MAX / 63) * 63; 4623 4624 cl->cl_g.dkg_ncyl = cl->cl_blockcount / 4625 (255 * cl->cl_g.dkg_nsect); 4626 } 4627 4628 cl->cl_g.dkg_acyl = 0; 4629 cl->cl_g.dkg_bcyl = 0; 4630 cl->cl_g.dkg_intrlv = 1; 4631 cl->cl_g.dkg_rpm = 200; 4632 if (cl->cl_g.dkg_pcyl == 0) 4633 cl->cl_g.dkg_pcyl = cl->cl_g.dkg_ncyl + 4634 cl->cl_g.dkg_acyl; 4635 } else { 4636 cl->cl_g.dkg_ncyl = (short)pgeomp->g_ncyl; 4637 cl->cl_g.dkg_acyl = pgeomp->g_acyl; 4638 cl->cl_g.dkg_nhead = pgeomp->g_nhead; 4639 cl->cl_g.dkg_nsect = pgeomp->g_nsect; 4640 cl->cl_g.dkg_intrlv = pgeomp->g_intrlv; 4641 cl->cl_g.dkg_rpm = pgeomp->g_rpm; 4642 cl->cl_g.dkg_pcyl = cl->cl_g.dkg_ncyl + cl->cl_g.dkg_acyl; 4643 } 4644 4645 cl->cl_g.dkg_read_reinstruct = 0; 4646 cl->cl_g.dkg_write_reinstruct = 0; 4647 cl->cl_solaris_size = cl->cl_g.dkg_ncyl * 4648 cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect; 4649 4650 cl->cl_map['a'-'a'].dkl_cylno = 0; 4651 cl->cl_map['a'-'a'].dkl_nblk = cl->cl_solaris_size; 4652 4653 cl->cl_map['c'-'a'].dkl_cylno = 0; 4654 cl->cl_map['c'-'a'].dkl_nblk = cl->cl_solaris_size; 4655 4656 cl->cl_vtoc.v_part[2].p_tag = V_BACKUP; 4657 cl->cl_vtoc.v_part[2].p_flag = V_UNMNT; 4658 cl->cl_vtoc.v_nparts = V_NUMPAR; 4659 cl->cl_vtoc.v_version = V_VERSION; 4660 (void) sprintf((char *)cl->cl_asciilabel, "DEFAULT cyl %d alt %d" 4661 " hd %d sec %d", cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl, 4662 cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect); 4663 4664 cl->cl_f_geometry_is_valid = B_FALSE; 4665 } 4666 4667 4668 #if defined(__i386) || defined(__amd64) 4669 /* 4670 * Function: cmlb_update_fdisk_and_vtoc 4671 * 4672 * Description: This local utility routine updates the device fdisk and vtoc 4673 * as part of setting the device mboot. 4674 * 4675 * Arguments: 4676 * cl driver soft state (unit) structure 4677 * 4678 * tg_cookie cookie from target driver to be passed back to target 4679 * driver when we call back to it through tg_ops. 4680 * 4681 * 4682 * Return Code: 0 for success or errno-type return code. 4683 * 4684 * Note:x86: This looks like a duplicate of cmlb_validate_geometry(), but 4685 * these did exist separately in x86 sd.c. 4686 */ 4687 static int 4688 cmlb_update_fdisk_and_vtoc(struct cmlb_lun *cl, void *tg_cookie) 4689 { 4690 int count; 4691 int label_rc = 0; 4692 int fdisk_rval; 4693 diskaddr_t capacity; 4694 4695 ASSERT(mutex_owned(CMLB_MUTEX(cl))); 4696 4697 if (cmlb_check_update_blockcount(cl, tg_cookie) != 0) 4698 return (EINVAL); 4699 4700 #if defined(_SUNOS_VTOC_16) 4701 /* 4702 * Set up the "whole disk" fdisk partition; this should always 4703 * exist, regardless of whether the disk contains an fdisk table 4704 * or vtoc. 4705 */ 4706 cl->cl_map[P0_RAW_DISK].dkl_cylno = 0; 4707 cl->cl_map[P0_RAW_DISK].dkl_nblk = cl->cl_blockcount; 4708 #endif /* defined(_SUNOS_VTOC_16) */ 4709 4710 /* 4711 * copy the lbasize and capacity so that if they're 4712 * reset while we're not holding the CMLB_MUTEX(cl), we will 4713 * continue to use valid values after the CMLB_MUTEX(cl) is 4714 * reacquired. 4715 */ 4716 capacity = cl->cl_blockcount; 4717 4718 /* 4719 * refresh the logical and physical geometry caches. 4720 * (data from mode sense format/rigid disk geometry pages, 4721 * and scsi_ifgetcap("geometry"). 4722 */ 4723 cmlb_resync_geom_caches(cl, capacity, tg_cookie); 4724 4725 /* 4726 * Only DIRECT ACCESS devices will have Scl labels. 4727 * CD's supposedly have a Scl label, too 4728 */ 4729 if (cl->cl_device_type == DTYPE_DIRECT || ISREMOVABLE(cl)) { 4730 fdisk_rval = cmlb_read_fdisk(cl, capacity, tg_cookie); 4731 if (fdisk_rval != 0) { 4732 ASSERT(mutex_owned(CMLB_MUTEX(cl))); 4733 return (fdisk_rval); 4734 } 4735 4736 if (cl->cl_solaris_size <= DK_LABEL_LOC) { 4737 /* 4738 * Found fdisk table but no Solaris partition entry, 4739 * so don't call cmlb_uselabel() and don't create 4740 * a default label. 4741 */ 4742 label_rc = 0; 4743 cl->cl_f_geometry_is_valid = B_TRUE; 4744 goto no_solaris_partition; 4745 } 4746 } else if (capacity < 0) { 4747 ASSERT(mutex_owned(CMLB_MUTEX(cl))); 4748 return (EINVAL); 4749 } 4750 4751 /* 4752 * For Removable media We reach here if we have found a 4753 * SOLARIS PARTITION. 4754 * If cl_f_geometry_is_valid is B_FALSE it indicates that the SOLARIS 4755 * PARTITION has changed from the previous one, hence we will setup a 4756 * default VTOC in this case. 4757 */ 4758 if (!cl->cl_f_geometry_is_valid) { 4759 /* if we get here it is writable */ 4760 /* we are called from SMBOOT, and after a write of fdisk */ 4761 cmlb_build_default_label(cl, tg_cookie); 4762 label_rc = 0; 4763 } 4764 4765 no_solaris_partition: 4766 4767 #if defined(_SUNOS_VTOC_16) 4768 /* 4769 * If we have valid geometry, set up the remaining fdisk partitions. 4770 * Note that dkl_cylno is not used for the fdisk map entries, so 4771 * we set it to an entirely bogus value. 4772 */ 4773 for (count = 0; count < FD_NUMPART; count++) { 4774 cl->cl_map[FDISK_P1 + count].dkl_cylno = UINT32_MAX; 4775 cl->cl_map[FDISK_P1 + count].dkl_nblk = 4776 cl->cl_fmap[count].fmap_nblk; 4777 cl->cl_offset[FDISK_P1 + count] = 4778 cl->cl_fmap[count].fmap_start; 4779 } 4780 #endif 4781 4782 for (count = 0; count < NDKMAP; count++) { 4783 #if defined(_SUNOS_VTOC_8) 4784 struct dk_map *lp = &cl->cl_map[count]; 4785 cl->cl_offset[count] = 4786 cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno; 4787 #elif defined(_SUNOS_VTOC_16) 4788 struct dkl_partition *vp = &cl->cl_vtoc.v_part[count]; 4789 cl->cl_offset[count] = vp->p_start + cl->cl_solaris_offset; 4790 #else 4791 #error "No VTOC format defined." 4792 #endif 4793 } 4794 4795 ASSERT(mutex_owned(CMLB_MUTEX(cl))); 4796 return (label_rc); 4797 } 4798 #endif 4799 4800 #if defined(__i386) || defined(__amd64) 4801 static int 4802 cmlb_dkio_get_virtgeom(struct cmlb_lun *cl, caddr_t arg, int flag) 4803 { 4804 int err = 0; 4805 4806 /* Return the driver's notion of the media's logical geometry */ 4807 struct dk_geom disk_geom; 4808 struct dk_geom *dkgp = &disk_geom; 4809 4810 mutex_enter(CMLB_MUTEX(cl)); 4811 /* 4812 * If there is no HBA geometry available, or 4813 * if the HBA returned us something that doesn't 4814 * really fit into an Int 13/function 8 geometry 4815 * result, just fail the ioctl. See PSARC 1998/313. 4816 */ 4817 if (cl->cl_lgeom.g_nhead == 0 || 4818 cl->cl_lgeom.g_nsect == 0 || 4819 cl->cl_lgeom.g_ncyl > 1024) { 4820 mutex_exit(CMLB_MUTEX(cl)); 4821 err = EINVAL; 4822 } else { 4823 dkgp->dkg_ncyl = cl->cl_lgeom.g_ncyl; 4824 dkgp->dkg_acyl = cl->cl_lgeom.g_acyl; 4825 dkgp->dkg_pcyl = dkgp->dkg_ncyl + dkgp->dkg_acyl; 4826 dkgp->dkg_nhead = cl->cl_lgeom.g_nhead; 4827 dkgp->dkg_nsect = cl->cl_lgeom.g_nsect; 4828 4829 mutex_exit(CMLB_MUTEX(cl)); 4830 if (ddi_copyout(dkgp, (void *)arg, 4831 sizeof (struct dk_geom), flag)) { 4832 err = EFAULT; 4833 } else { 4834 err = 0; 4835 } 4836 } 4837 return (err); 4838 } 4839 #endif 4840 4841 #if defined(__i386) || defined(__amd64) 4842 static int 4843 cmlb_dkio_get_phygeom(struct cmlb_lun *cl, caddr_t arg, int flag) 4844 { 4845 int err = 0; 4846 diskaddr_t capacity; 4847 4848 4849 /* Return the driver's notion of the media physical geometry */ 4850 struct dk_geom disk_geom; 4851 struct dk_geom *dkgp = &disk_geom; 4852 4853 mutex_enter(CMLB_MUTEX(cl)); 4854 4855 if (cl->cl_g.dkg_nhead != 0 && 4856 cl->cl_g.dkg_nsect != 0) { 4857 /* 4858 * We succeeded in getting a geometry, but 4859 * right now it is being reported as just the 4860 * Solaris fdisk partition, just like for 4861 * DKIOCGGEOM. We need to change that to be 4862 * correct for the entire disk now. 4863 */ 4864 bcopy(&cl->cl_g, dkgp, sizeof (*dkgp)); 4865 dkgp->dkg_acyl = 0; 4866 dkgp->dkg_ncyl = cl->cl_blockcount / 4867 (dkgp->dkg_nhead * dkgp->dkg_nsect); 4868 } else { 4869 bzero(dkgp, sizeof (struct dk_geom)); 4870 /* 4871 * This disk does not have a Solaris VTOC 4872 * so we must present a physical geometry 4873 * that will remain consistent regardless 4874 * of how the disk is used. This will ensure 4875 * that the geometry does not change regardless 4876 * of the fdisk partition type (ie. EFI, FAT32, 4877 * Solaris, etc). 4878 */ 4879 if (ISCD(cl)) { 4880 dkgp->dkg_nhead = cl->cl_pgeom.g_nhead; 4881 dkgp->dkg_nsect = cl->cl_pgeom.g_nsect; 4882 dkgp->dkg_ncyl = cl->cl_pgeom.g_ncyl; 4883 dkgp->dkg_acyl = cl->cl_pgeom.g_acyl; 4884 } else { 4885 /* 4886 * Invalid cl_blockcount can generate invalid 4887 * dk_geom and may result in division by zero 4888 * system failure. Should make sure blockcount 4889 * is valid before using it here. 4890 */ 4891 if (cl->cl_blockcount == 0) { 4892 mutex_exit(CMLB_MUTEX(cl)); 4893 err = EIO; 4894 return (err); 4895 } 4896 /* 4897 * Refer to comments related to off-by-1 at the 4898 * header of this file 4899 */ 4900 if (cl->cl_alter_behavior & CMLB_OFF_BY_ONE) 4901 capacity = cl->cl_blockcount - 1; 4902 else 4903 capacity = cl->cl_blockcount; 4904 4905 cmlb_convert_geometry(capacity, dkgp); 4906 dkgp->dkg_acyl = 0; 4907 dkgp->dkg_ncyl = capacity / 4908 (dkgp->dkg_nhead * dkgp->dkg_nsect); 4909 } 4910 } 4911 dkgp->dkg_pcyl = dkgp->dkg_ncyl + dkgp->dkg_acyl; 4912 4913 mutex_exit(CMLB_MUTEX(cl)); 4914 if (ddi_copyout(dkgp, (void *)arg, sizeof (struct dk_geom), flag)) 4915 err = EFAULT; 4916 4917 return (err); 4918 } 4919 #endif 4920 4921 #if defined(__i386) || defined(__amd64) 4922 static int 4923 cmlb_dkio_partinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag) 4924 { 4925 int err = 0; 4926 4927 /* 4928 * Return parameters describing the selected disk slice. 4929 * Note: this ioctl is for the intel platform only 4930 */ 4931 int part; 4932 4933 part = CMLBPART(dev); 4934 4935 mutex_enter(CMLB_MUTEX(cl)); 4936 /* don't check cl_solaris_size for pN */ 4937 if (part < P0_RAW_DISK && cl->cl_solaris_size == 0) { 4938 err = EIO; 4939 mutex_exit(CMLB_MUTEX(cl)); 4940 } else { 4941 struct part_info p; 4942 4943 p.p_start = (daddr_t)cl->cl_offset[part]; 4944 p.p_length = (int)cl->cl_map[part].dkl_nblk; 4945 mutex_exit(CMLB_MUTEX(cl)); 4946 #ifdef _MULTI_DATAMODEL 4947 switch (ddi_model_convert_from(flag & FMODELS)) { 4948 case DDI_MODEL_ILP32: 4949 { 4950 struct part_info32 p32; 4951 4952 p32.p_start = (daddr32_t)p.p_start; 4953 p32.p_length = p.p_length; 4954 if (ddi_copyout(&p32, (void *)arg, 4955 sizeof (p32), flag)) 4956 err = EFAULT; 4957 break; 4958 } 4959 4960 case DDI_MODEL_NONE: 4961 { 4962 if (ddi_copyout(&p, (void *)arg, sizeof (p), 4963 flag)) 4964 err = EFAULT; 4965 break; 4966 } 4967 } 4968 #else /* ! _MULTI_DATAMODEL */ 4969 if (ddi_copyout(&p, (void *)arg, sizeof (p), flag)) 4970 err = EFAULT; 4971 #endif /* _MULTI_DATAMODEL */ 4972 } 4973 return (err); 4974 } 4975 static int 4976 cmlb_dkio_extpartinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag) 4977 { 4978 int err = 0; 4979 4980 /* 4981 * Return parameters describing the selected disk slice. 4982 * Note: this ioctl is for the intel platform only 4983 */ 4984 int part; 4985 4986 part = CMLBPART(dev); 4987 4988 mutex_enter(CMLB_MUTEX(cl)); 4989 /* don't check cl_solaris_size for pN */ 4990 if (part < P0_RAW_DISK && cl->cl_solaris_size == 0) { 4991 err = EIO; 4992 mutex_exit(CMLB_MUTEX(cl)); 4993 } else { 4994 struct extpart_info p; 4995 4996 p.p_start = (diskaddr_t)cl->cl_offset[part]; 4997 p.p_length = (diskaddr_t)cl->cl_map[part].dkl_nblk; 4998 mutex_exit(CMLB_MUTEX(cl)); 4999 if (ddi_copyout(&p, (void *)arg, sizeof (p), flag)) 5000 err = EFAULT; 5001 } 5002 return (err); 5003 } 5004 #endif 5005 5006 int 5007 cmlb_prop_op(cmlb_handle_t cmlbhandle, 5008 dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags, 5009 char *name, caddr_t valuep, int *lengthp, int part, void *tg_cookie) 5010 { 5011 struct cmlb_lun *cl; 5012 diskaddr_t capacity; 5013 uint32_t lbasize; 5014 enum dp { DP_NBLOCKS, DP_BLKSIZE } dp; 5015 int callers_length; 5016 caddr_t buffer; 5017 uint64_t nblocks64; 5018 uint_t dblk; 5019 5020 /* Always fallback to ddi_prop_op... */ 5021 cl = (struct cmlb_lun *)cmlbhandle; 5022 if (cl == NULL) { 5023 fallback: return (ddi_prop_op(dev, dip, prop_op, mod_flags, 5024 name, valuep, lengthp)); 5025 } 5026 5027 /* Pick up capacity and blocksize information. */ 5028 capacity = cl->cl_blockcount; 5029 if (capacity == 0) 5030 goto fallback; 5031 lbasize = cl->cl_tgt_blocksize; 5032 if (lbasize == 0) 5033 lbasize = DEV_BSIZE; /* 0 -> DEV_BSIZE units */ 5034 5035 /* Check for dynamic property of whole device. */ 5036 if (dev == DDI_DEV_T_ANY) { 5037 /* Fallback to ddi_prop_op if we don't understand. */ 5038 if (strcmp(name, "device-nblocks") == 0) 5039 dp = DP_NBLOCKS; 5040 else if (strcmp(name, "device-blksize") == 0) 5041 dp = DP_BLKSIZE; 5042 else 5043 goto fallback; 5044 5045 /* get callers length, establish length of our dynamic prop */ 5046 callers_length = *lengthp; 5047 if (dp == DP_NBLOCKS) 5048 *lengthp = sizeof (uint64_t); 5049 else if (dp == DP_BLKSIZE) 5050 *lengthp = sizeof (uint32_t); 5051 5052 /* service request for the length of the property */ 5053 if (prop_op == PROP_LEN) 5054 return (DDI_PROP_SUCCESS); 5055 5056 switch (prop_op) { 5057 case PROP_LEN_AND_VAL_ALLOC: 5058 if ((buffer = kmem_alloc(*lengthp, 5059 (mod_flags & DDI_PROP_CANSLEEP) ? 5060 KM_SLEEP : KM_NOSLEEP)) == NULL) 5061 return (DDI_PROP_NO_MEMORY); 5062 *(caddr_t *)valuep = buffer; /* set callers buf */ 5063 break; 5064 5065 case PROP_LEN_AND_VAL_BUF: 5066 /* the length of the prop and the request must match */ 5067 if (callers_length != *lengthp) 5068 return (DDI_PROP_INVAL_ARG); 5069 buffer = valuep; /* get callers buf */ 5070 break; 5071 5072 default: 5073 return (DDI_PROP_INVAL_ARG); 5074 } 5075 5076 /* transfer the value into the buffer */ 5077 if (dp == DP_NBLOCKS) 5078 *((uint64_t *)buffer) = capacity; 5079 else if (dp == DP_BLKSIZE) 5080 *((uint32_t *)buffer) = lbasize; 5081 5082 return (DDI_PROP_SUCCESS); 5083 } 5084 5085 /* 5086 * Support dynamic size oriented properties of partition. Requests 5087 * issued under conditions where size is valid are passed to 5088 * ddi_prop_op_nblocks with the size information, otherwise the 5089 * request is passed to ddi_prop_op. Size depends on valid geometry. 5090 */ 5091 if (!cmlb_is_valid(cmlbhandle)) 5092 goto fallback; 5093 5094 /* Get partition nblocks value. */ 5095 (void) cmlb_partinfo(cmlbhandle, part, 5096 (diskaddr_t *)&nblocks64, NULL, NULL, NULL, tg_cookie); 5097 5098 /* 5099 * Assume partition information is in sys_blocksize units, compute 5100 * divisor for size(9P) property representation. 5101 */ 5102 dblk = lbasize / cl->cl_sys_blocksize; 5103 5104 /* Now let ddi_prop_op_nblocks_blksize() handle the request. */ 5105 return (ddi_prop_op_nblocks_blksize(dev, dip, prop_op, mod_flags, 5106 name, valuep, lengthp, nblocks64 / dblk, lbasize)); 5107 } 5108