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