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 2008 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(_FIRMWARE_NEEDS_FDISK) 117 {"q", 16, S_IFBLK}, 118 {"r", 17, S_IFBLK}, 119 {"s", 18, S_IFBLK}, 120 {"t", 19, S_IFBLK}, 121 {"u", 20, S_IFBLK}, 122 #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 123 {"a,raw", 0, S_IFCHR}, 124 {"b,raw", 1, S_IFCHR}, 125 {"c,raw", 2, S_IFCHR}, 126 {"d,raw", 3, S_IFCHR}, 127 {"e,raw", 4, S_IFCHR}, 128 {"f,raw", 5, S_IFCHR}, 129 {"g,raw", 6, S_IFCHR}, 130 {"wd,raw", 7, S_IFCHR}, 131 #if defined(_FIRMWARE_NEEDS_FDISK) 132 {"q,raw", 16, S_IFCHR}, 133 {"r,raw", 17, S_IFCHR}, 134 {"s,raw", 18, S_IFCHR}, 135 {"t,raw", 19, S_IFCHR}, 136 {"u,raw", 20, S_IFCHR}, 137 #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 138 {0} 139 }; 140 141 /* 142 * Declare the dynamic properties implemented in prop_op(9E) implementation 143 * that we want to have show up in a di_init(3DEVINFO) device tree snapshot 144 * of drivers that call cmlb_attach(). 145 */ 146 static i_ddi_prop_dyn_t cmlb_prop_dyn[] = { 147 {"Nblocks", DDI_PROP_TYPE_INT64, S_IFBLK}, 148 {"Size", DDI_PROP_TYPE_INT64, S_IFCHR}, 149 {"device-nblocks", DDI_PROP_TYPE_INT64}, 150 {"device-blksize", DDI_PROP_TYPE_INT}, 151 {NULL} 152 }; 153 154 /* 155 * External kernel interfaces 156 */ 157 extern struct mod_ops mod_miscops; 158 159 extern int ddi_create_internal_pathname(dev_info_t *dip, char *name, 160 int spec_type, minor_t minor_num); 161 162 /* 163 * Global buffer and mutex for debug logging 164 */ 165 static char cmlb_log_buffer[1024]; 166 static kmutex_t cmlb_log_mutex; 167 168 169 struct cmlb_lun *cmlb_debug_cl = NULL; 170 uint_t cmlb_level_mask = 0x0; 171 172 int cmlb_rot_delay = 4; /* default rotational delay */ 173 174 static struct modlmisc modlmisc = { 175 &mod_miscops, /* Type of module */ 176 "Common Labeling module" 177 }; 178 179 static struct modlinkage modlinkage = { 180 MODREV_1, (void *)&modlmisc, NULL 181 }; 182 183 /* Local function prototypes */ 184 static dev_t cmlb_make_device(struct cmlb_lun *cl); 185 static int cmlb_validate_geometry(struct cmlb_lun *cl, int forcerevalid, 186 int flags, void *tg_cookie); 187 static void cmlb_resync_geom_caches(struct cmlb_lun *cl, diskaddr_t capacity, 188 void *tg_cookie); 189 static int cmlb_read_fdisk(struct cmlb_lun *cl, diskaddr_t capacity, 190 void *tg_cookie); 191 static void cmlb_swap_efi_gpt(efi_gpt_t *e); 192 static void cmlb_swap_efi_gpe(int nparts, efi_gpe_t *p); 193 static int cmlb_validate_efi(efi_gpt_t *labp); 194 static int cmlb_use_efi(struct cmlb_lun *cl, diskaddr_t capacity, int flags, 195 void *tg_cookie); 196 static void cmlb_build_default_label(struct cmlb_lun *cl, void *tg_cookie); 197 static int cmlb_uselabel(struct cmlb_lun *cl, struct dk_label *l, int flags); 198 #if defined(_SUNOS_VTOC_8) 199 static void cmlb_build_user_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc); 200 #endif 201 static int cmlb_build_label_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc); 202 static int cmlb_write_label(struct cmlb_lun *cl, void *tg_cookie); 203 static int cmlb_set_vtoc(struct cmlb_lun *cl, struct dk_label *dkl, 204 void *tg_cookie); 205 static void cmlb_clear_efi(struct cmlb_lun *cl, void *tg_cookie); 206 static void cmlb_clear_vtoc(struct cmlb_lun *cl, void *tg_cookie); 207 static void cmlb_setup_default_geometry(struct cmlb_lun *cl, void *tg_cookie); 208 static int cmlb_create_minor_nodes(struct cmlb_lun *cl); 209 static int cmlb_check_update_blockcount(struct cmlb_lun *cl, void *tg_cookie); 210 static int cmlb_check_efi_mbr(uchar_t *buf, int *is_mbr); 211 212 #if defined(__i386) || defined(__amd64) 213 static int cmlb_update_fdisk_and_vtoc(struct cmlb_lun *cl, void *tg_cookie); 214 #endif 215 216 #if defined(_FIRMWARE_NEEDS_FDISK) 217 static int cmlb_has_max_chs_vals(struct ipart *fdp); 218 #endif 219 220 #if defined(_SUNOS_VTOC_16) 221 static void cmlb_convert_geometry(diskaddr_t capacity, struct dk_geom *cl_g); 222 #endif 223 224 static int cmlb_dkio_get_geometry(struct cmlb_lun *cl, caddr_t arg, int flag, 225 void *tg_cookie); 226 static int cmlb_dkio_set_geometry(struct cmlb_lun *cl, caddr_t arg, int flag); 227 static int cmlb_dkio_get_partition(struct cmlb_lun *cl, caddr_t arg, int flag, 228 void *tg_cookie); 229 static int cmlb_dkio_set_partition(struct cmlb_lun *cl, caddr_t arg, int flag); 230 static int cmlb_dkio_get_efi(struct cmlb_lun *cl, caddr_t arg, int flag, 231 void *tg_cookie); 232 static int cmlb_dkio_set_efi(struct cmlb_lun *cl, dev_t dev, caddr_t arg, 233 int flag, void *tg_cookie); 234 static int cmlb_dkio_get_vtoc(struct cmlb_lun *cl, caddr_t arg, int flag, 235 void *tg_cookie); 236 static int cmlb_dkio_get_extvtoc(struct cmlb_lun *cl, caddr_t arg, int flag, 237 void *tg_cookie); 238 static int cmlb_dkio_set_vtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, 239 int flag, void *tg_cookie); 240 static int cmlb_dkio_set_extvtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, 241 int flag, void *tg_cookie); 242 static int cmlb_dkio_get_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, 243 void *tg_cookie); 244 static int cmlb_dkio_set_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, 245 void *tg_cookie); 246 static int cmlb_dkio_partition(struct cmlb_lun *cl, caddr_t arg, int flag, 247 void *tg_cookie); 248 249 #if defined(__i386) || defined(__amd64) 250 static int cmlb_dkio_get_virtgeom(struct cmlb_lun *cl, caddr_t arg, int flag); 251 static int cmlb_dkio_get_phygeom(struct cmlb_lun *cl, caddr_t arg, int flag); 252 static int cmlb_dkio_partinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg, 253 int flag); 254 static int cmlb_dkio_extpartinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg, 255 int flag); 256 #endif 257 258 static void cmlb_dbg(uint_t comp, struct cmlb_lun *cl, const char *fmt, ...); 259 static void cmlb_v_log(dev_info_t *dev, char *label, uint_t level, 260 const char *fmt, va_list ap); 261 static void cmlb_log(dev_info_t *dev, char *label, uint_t level, 262 const char *fmt, ...); 263 264 int 265 _init(void) 266 { 267 mutex_init(&cmlb_log_mutex, NULL, MUTEX_DRIVER, NULL); 268 return (mod_install(&modlinkage)); 269 } 270 271 int 272 _info(struct modinfo *modinfop) 273 { 274 return (mod_info(&modlinkage, modinfop)); 275 } 276 277 int 278 _fini(void) 279 { 280 int err; 281 282 if ((err = mod_remove(&modlinkage)) != 0) { 283 return (err); 284 } 285 286 mutex_destroy(&cmlb_log_mutex); 287 return (err); 288 } 289 290 /* 291 * cmlb_dbg is used for debugging to log additional info 292 * Level of output is controlled via cmlb_level_mask setting. 293 */ 294 static void 295 cmlb_dbg(uint_t comp, struct cmlb_lun *cl, const char *fmt, ...) 296 { 297 va_list ap; 298 dev_info_t *dev; 299 uint_t level_mask = 0; 300 301 ASSERT(cl != NULL); 302 dev = CMLB_DEVINFO(cl); 303 ASSERT(dev != NULL); 304 /* 305 * Filter messages based on the global component and level masks, 306 * also print if cl matches the value of cmlb_debug_cl, or if 307 * cmlb_debug_cl is set to NULL. 308 */ 309 if (comp & CMLB_TRACE) 310 level_mask |= CMLB_LOGMASK_TRACE; 311 312 if (comp & CMLB_INFO) 313 level_mask |= CMLB_LOGMASK_INFO; 314 315 if (comp & CMLB_ERROR) 316 level_mask |= CMLB_LOGMASK_ERROR; 317 318 if ((cmlb_level_mask & level_mask) && 319 ((cmlb_debug_cl == NULL) || (cmlb_debug_cl == cl))) { 320 va_start(ap, fmt); 321 cmlb_v_log(dev, CMLB_LABEL(cl), CE_CONT, fmt, ap); 322 va_end(ap); 323 } 324 } 325 326 /* 327 * cmlb_log is basically a duplicate of scsi_log. It is redefined here 328 * so that this module does not depend on scsi module. 329 */ 330 static void 331 cmlb_log(dev_info_t *dev, char *label, uint_t level, const char *fmt, ...) 332 { 333 va_list ap; 334 335 va_start(ap, fmt); 336 cmlb_v_log(dev, label, level, fmt, ap); 337 va_end(ap); 338 } 339 340 static void 341 cmlb_v_log(dev_info_t *dev, char *label, uint_t level, const char *fmt, 342 va_list ap) 343 { 344 static char name[256]; 345 int log_only = 0; 346 int boot_only = 0; 347 int console_only = 0; 348 349 mutex_enter(&cmlb_log_mutex); 350 351 if (dev) { 352 if (level == CE_PANIC || level == CE_WARN || 353 level == CE_NOTE) { 354 (void) sprintf(name, "%s (%s%d):\n", 355 ddi_pathname(dev, cmlb_log_buffer), 356 label, ddi_get_instance(dev)); 357 } else { 358 name[0] = '\0'; 359 } 360 } else { 361 (void) sprintf(name, "%s:", label); 362 } 363 364 (void) vsprintf(cmlb_log_buffer, fmt, ap); 365 366 switch (cmlb_log_buffer[0]) { 367 case '!': 368 log_only = 1; 369 break; 370 case '?': 371 boot_only = 1; 372 break; 373 case '^': 374 console_only = 1; 375 break; 376 } 377 378 switch (level) { 379 case CE_NOTE: 380 level = CE_CONT; 381 /* FALLTHROUGH */ 382 case CE_CONT: 383 case CE_WARN: 384 case CE_PANIC: 385 if (boot_only) { 386 cmn_err(level, "?%s\t%s", name, &cmlb_log_buffer[1]); 387 } else if (console_only) { 388 cmn_err(level, "^%s\t%s", name, &cmlb_log_buffer[1]); 389 } else if (log_only) { 390 cmn_err(level, "!%s\t%s", name, &cmlb_log_buffer[1]); 391 } else { 392 cmn_err(level, "%s\t%s", name, cmlb_log_buffer); 393 } 394 break; 395 case CE_IGNORE: 396 break; 397 default: 398 cmn_err(CE_CONT, "^DEBUG: %s\t%s", name, cmlb_log_buffer); 399 break; 400 } 401 mutex_exit(&cmlb_log_mutex); 402 } 403 404 405 /* 406 * cmlb_alloc_handle: 407 * 408 * Allocates a handle. 409 * 410 * Arguments: 411 * cmlbhandlep pointer to handle 412 * 413 * Notes: 414 * Allocates a handle and stores the allocated handle in the area 415 * pointed to by cmlbhandlep 416 * 417 * Context: 418 * Kernel thread only (can sleep). 419 */ 420 void 421 cmlb_alloc_handle(cmlb_handle_t *cmlbhandlep) 422 { 423 struct cmlb_lun *cl; 424 425 cl = kmem_zalloc(sizeof (struct cmlb_lun), KM_SLEEP); 426 ASSERT(cmlbhandlep != NULL); 427 428 cl->cl_state = CMLB_INITED; 429 cl->cl_def_labeltype = CMLB_LABEL_UNDEF; 430 mutex_init(CMLB_MUTEX(cl), NULL, MUTEX_DRIVER, NULL); 431 432 *cmlbhandlep = (cmlb_handle_t)(cl); 433 } 434 435 /* 436 * cmlb_free_handle 437 * 438 * Frees handle. 439 * 440 * Arguments: 441 * cmlbhandlep pointer to handle 442 */ 443 void 444 cmlb_free_handle(cmlb_handle_t *cmlbhandlep) 445 { 446 struct cmlb_lun *cl; 447 448 cl = (struct cmlb_lun *)*cmlbhandlep; 449 if (cl != NULL) { 450 mutex_destroy(CMLB_MUTEX(cl)); 451 kmem_free(cl, sizeof (struct cmlb_lun)); 452 } 453 454 } 455 456 /* 457 * cmlb_attach: 458 * 459 * Attach handle to device, create minor nodes for device. 460 * 461 * Arguments: 462 * devi pointer to device's dev_info structure. 463 * tgopsp pointer to array of functions cmlb can use to callback 464 * to target driver. 465 * 466 * device_type Peripheral device type as defined in 467 * scsi/generic/inquiry.h 468 * 469 * is_removable whether or not device is removable. 470 * 0 non-removable, 1 removable. 471 * 472 * is_hotpluggable whether or not device is hotpluggable. 473 * 0 non-hotpluggable, 1 hotpluggable. 474 * 475 * node_type minor node type (as used by ddi_create_minor_node) 476 * 477 * alter_behavior 478 * bit flags: 479 * 480 * CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT: create 481 * an alternate slice for the default label, if 482 * device type is DTYPE_DIRECT an architectures default 483 * label type is VTOC16. 484 * Otherwise alternate slice will no be created. 485 * 486 * 487 * CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8: report a default 488 * geometry and label for DKIOCGGEOM and DKIOCGVTOC 489 * on architecture with VTOC8 label types. 490 * 491 * CMLB_OFF_BY_ONE: do the workaround for legacy off-by- 492 * one bug in obtaining capacity (in sd): 493 * SCSI READ_CAPACITY command returns the LBA number of the 494 * last logical block, but sd once treated this number as 495 * disks' capacity on x86 platform. And LBAs are addressed 496 * based 0. So the last block was lost on x86 platform. 497 * 498 * Now, we remove this workaround. In order for present sd 499 * driver to work with disks which are labeled/partitioned 500 * via previous sd, we add workaround as follows: 501 * 502 * 1) Locate backup EFI label: cmlb searches the next to 503 * last 504 * block for backup EFI label. If fails, it will 505 * turn to the last block for backup EFI label; 506 * 507 * 2) Clear backup EFI label: cmlb first search the last 508 * block for backup EFI label, and will search the 509 * next to last block only if failed for the last 510 * block. 511 * 512 * 3) Calculate geometry:refer to cmlb_convert_geometry() 513 * If capacity increasing by 1 causes disks' capacity 514 * to cross over the limits in geometry calculation, 515 * geometry info will change. This will raise an issue: 516 * In case that primary VTOC label is destroyed, format 517 * commandline can restore it via backup VTOC labels. 518 * And format locates backup VTOC labels by use of 519 * geometry. So changing geometry will 520 * prevent format from finding backup VTOC labels. To 521 * eliminate this side effect for compatibility, 522 * sd uses (capacity -1) to calculate geometry; 523 * 524 * 4) 1TB disks: some important data structures use 525 * 32-bit signed long/int (for example, daddr_t), 526 * so that sd doesn't support a disk with capacity 527 * larger than 1TB on 32-bit platform. However, 528 * for exactly 1TB disk, it was treated as (1T - 512)B 529 * in the past, and could have valid Solaris 530 * partitions. To workaround this, if an exactly 1TB 531 * disk has Solaris fdisk partition, it will be allowed 532 * to work with sd. 533 * 534 * 535 * 536 * CMLB_FAKE_LABEL_ONE_PARTITION: create s0 and s2 covering 537 * the entire disk, if there is no valid partition info. 538 * If there is a valid Solaris partition, s0 and s2 will 539 * only cover the entire Solaris partition. 540 * 541 * 542 * cmlbhandle cmlb handle associated with device 543 * 544 * tg_cookie cookie from target driver to be passed back to target 545 * driver when we call back to it through tg_ops. 546 * 547 * Notes: 548 * Assumes a default label based on capacity for non-removable devices. 549 * If capacity > 1TB, EFI is assumed otherwise VTOC (default VTOC 550 * for the architecture). 551 * 552 * For removable devices, default label type is assumed to be VTOC 553 * type. Create minor nodes based on a default label type. 554 * Label on the media is not validated. 555 * minor number consists of: 556 * if _SUNOS_VTOC_8 is defined 557 * lowest 3 bits is taken as partition number 558 * the rest is instance number 559 * if _SUNOS_VTOC_16 is defined 560 * lowest 6 bits is taken as partition number 561 * the rest is instance number 562 * 563 * 564 * Return values: 565 * 0 Success 566 * ENXIO creating minor nodes failed. 567 * EINVAL invalid arg, unsupported tg_ops version 568 */ 569 int 570 cmlb_attach(dev_info_t *devi, cmlb_tg_ops_t *tgopsp, int device_type, 571 int is_removable, int is_hotpluggable, char *node_type, 572 int alter_behavior, cmlb_handle_t cmlbhandle, void *tg_cookie) 573 { 574 575 struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 576 diskaddr_t cap; 577 int status; 578 579 if (tgopsp->tg_version < TG_DK_OPS_VERSION_1) 580 return (EINVAL); 581 582 mutex_enter(CMLB_MUTEX(cl)); 583 584 CMLB_DEVINFO(cl) = devi; 585 cl->cmlb_tg_ops = tgopsp; 586 cl->cl_device_type = device_type; 587 cl->cl_is_removable = is_removable; 588 cl->cl_is_hotpluggable = is_hotpluggable; 589 cl->cl_node_type = node_type; 590 cl->cl_sys_blocksize = DEV_BSIZE; 591 cl->cl_f_geometry_is_valid = FALSE; 592 cl->cl_def_labeltype = CMLB_LABEL_VTOC; 593 cl->cl_alter_behavior = alter_behavior; 594 cl->cl_reserved = -1; 595 cl->cl_msglog_flag |= CMLB_ALLOW_2TB_WARN; 596 597 if (is_removable == 0) { 598 mutex_exit(CMLB_MUTEX(cl)); 599 status = DK_TG_GETCAP(cl, &cap, tg_cookie); 600 mutex_enter(CMLB_MUTEX(cl)); 601 if (status == 0 && cap > CMLB_EXTVTOC_LIMIT) { 602 /* set default EFI if > 2TB */ 603 cl->cl_def_labeltype = CMLB_LABEL_EFI; 604 } 605 } 606 607 /* create minor nodes based on default label type */ 608 cl->cl_last_labeltype = CMLB_LABEL_UNDEF; 609 cl->cl_cur_labeltype = CMLB_LABEL_UNDEF; 610 611 if (cmlb_create_minor_nodes(cl) != 0) { 612 mutex_exit(CMLB_MUTEX(cl)); 613 return (ENXIO); 614 } 615 616 /* Define the dynamic properties for devinfo spapshots. */ 617 i_ddi_prop_dyn_driver_set(CMLB_DEVINFO(cl), cmlb_prop_dyn); 618 619 cl->cl_state = CMLB_ATTACHED; 620 621 mutex_exit(CMLB_MUTEX(cl)); 622 return (0); 623 } 624 625 /* 626 * cmlb_detach: 627 * 628 * Invalidate in-core labeling data and remove all minor nodes for 629 * the device associate with handle. 630 * 631 * Arguments: 632 * cmlbhandle cmlb handle associated with device. 633 * 634 * tg_cookie cookie from target driver to be passed back to target 635 * driver when we call back to it through tg_ops. 636 * 637 */ 638 /*ARGSUSED1*/ 639 void 640 cmlb_detach(cmlb_handle_t cmlbhandle, void *tg_cookie) 641 { 642 struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 643 644 mutex_enter(CMLB_MUTEX(cl)); 645 cl->cl_def_labeltype = CMLB_LABEL_UNDEF; 646 cl->cl_f_geometry_is_valid = FALSE; 647 ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL); 648 i_ddi_prop_dyn_driver_set(CMLB_DEVINFO(cl), NULL); 649 cl->cl_state = CMLB_INITED; 650 mutex_exit(CMLB_MUTEX(cl)); 651 } 652 653 /* 654 * cmlb_validate: 655 * 656 * Validates label. 657 * 658 * Arguments 659 * cmlbhandle cmlb handle associated with device. 660 * 661 * flags operation flags. used for verbosity control 662 * 663 * tg_cookie cookie from target driver to be passed back to target 664 * driver when we call back to it through tg_ops. 665 * 666 * 667 * Notes: 668 * If new label type is different from the current, adjust minor nodes 669 * accordingly. 670 * 671 * Return values: 672 * 0 success 673 * Note: having fdisk but no solaris partition is assumed 674 * success. 675 * 676 * ENOMEM memory allocation failed 677 * EIO i/o errors during read or get capacity 678 * EACCESS reservation conflicts 679 * EINVAL label was corrupt, or no default label was assumed 680 * ENXIO invalid handle 681 */ 682 int 683 cmlb_validate(cmlb_handle_t cmlbhandle, int flags, void *tg_cookie) 684 { 685 struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 686 int rval; 687 int ret = 0; 688 689 /* 690 * Temp work-around checking cl for NULL since there is a bug 691 * in sd_detach calling this routine from taskq_dispatch 692 * inited function. 693 */ 694 if (cl == NULL) 695 return (ENXIO); 696 697 mutex_enter(CMLB_MUTEX(cl)); 698 if (cl->cl_state < CMLB_ATTACHED) { 699 mutex_exit(CMLB_MUTEX(cl)); 700 return (ENXIO); 701 } 702 703 rval = cmlb_validate_geometry((struct cmlb_lun *)cmlbhandle, 1, 704 flags, tg_cookie); 705 706 if (rval == ENOTSUP) { 707 if (cl->cl_f_geometry_is_valid == TRUE) { 708 cl->cl_cur_labeltype = CMLB_LABEL_EFI; 709 ret = 0; 710 } else { 711 ret = EINVAL; 712 } 713 } else { 714 ret = rval; 715 if (ret == 0) 716 cl->cl_cur_labeltype = CMLB_LABEL_VTOC; 717 } 718 719 if (ret == 0) 720 (void) cmlb_create_minor_nodes(cl); 721 722 mutex_exit(CMLB_MUTEX(cl)); 723 return (ret); 724 } 725 726 /* 727 * cmlb_invalidate: 728 * Invalidate in core label data 729 * 730 * Arguments: 731 * cmlbhandle cmlb handle associated with device. 732 * tg_cookie cookie from target driver to be passed back to target 733 * driver when we call back to it through tg_ops. 734 */ 735 /*ARGSUSED1*/ 736 void 737 cmlb_invalidate(cmlb_handle_t cmlbhandle, void *tg_cookie) 738 { 739 struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 740 741 if (cl == NULL) 742 return; 743 744 mutex_enter(CMLB_MUTEX(cl)); 745 cl->cl_f_geometry_is_valid = FALSE; 746 mutex_exit(CMLB_MUTEX(cl)); 747 } 748 749 /* 750 * cmlb_is_valid 751 * Get status on whether the incore label/geom data is valid 752 * 753 * Arguments: 754 * cmlbhandle cmlb handle associated with device. 755 * 756 * Return values: 757 * TRUE if incore label/geom data is valid. 758 * FALSE otherwise. 759 * 760 */ 761 762 763 int 764 cmlb_is_valid(cmlb_handle_t cmlbhandle) 765 { 766 struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 767 768 if (cmlbhandle == NULL) 769 return (FALSE); 770 771 return (cl->cl_f_geometry_is_valid); 772 773 } 774 775 776 777 /* 778 * cmlb_close: 779 * 780 * Close the device, revert to a default label minor node for the device, 781 * if it is removable. 782 * 783 * Arguments: 784 * cmlbhandle cmlb handle associated with device. 785 * 786 * tg_cookie cookie from target driver to be passed back to target 787 * driver when we call back to it through tg_ops. 788 * Return values: 789 * 0 Success 790 * ENXIO Re-creating minor node failed. 791 */ 792 /*ARGSUSED1*/ 793 int 794 cmlb_close(cmlb_handle_t cmlbhandle, void *tg_cookie) 795 { 796 struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 797 798 mutex_enter(CMLB_MUTEX(cl)); 799 cl->cl_f_geometry_is_valid = FALSE; 800 801 /* revert to default minor node for this device */ 802 if (ISREMOVABLE(cl)) { 803 cl->cl_cur_labeltype = CMLB_LABEL_UNDEF; 804 (void) cmlb_create_minor_nodes(cl); 805 } 806 807 mutex_exit(CMLB_MUTEX(cl)); 808 return (0); 809 } 810 811 /* 812 * cmlb_get_devid_block: 813 * get the block number where device id is stored. 814 * 815 * Arguments: 816 * cmlbhandle cmlb handle associated with device. 817 * devidblockp pointer to block number. 818 * tg_cookie cookie from target driver to be passed back to target 819 * driver when we call back to it through tg_ops. 820 * 821 * Notes: 822 * It stores the block number of device id in the area pointed to 823 * by devidblockp. 824 * with the block number of device id. 825 * 826 * Return values: 827 * 0 success 828 * EINVAL device id does not apply to current label type. 829 */ 830 /*ARGSUSED2*/ 831 int 832 cmlb_get_devid_block(cmlb_handle_t cmlbhandle, diskaddr_t *devidblockp, 833 void *tg_cookie) 834 { 835 daddr_t spc, blk, head, cyl; 836 struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 837 838 mutex_enter(CMLB_MUTEX(cl)); 839 if (cl->cl_state < CMLB_ATTACHED) { 840 mutex_exit(CMLB_MUTEX(cl)); 841 return (EINVAL); 842 } 843 844 if ((cl->cl_f_geometry_is_valid == FALSE) || 845 (cl->cl_solaris_size < DK_LABEL_LOC)) { 846 mutex_exit(CMLB_MUTEX(cl)); 847 return (EINVAL); 848 } 849 850 if (cl->cl_cur_labeltype == CMLB_LABEL_EFI) { 851 if (cl->cl_reserved != -1) { 852 blk = cl->cl_map[cl->cl_reserved].dkl_cylno; 853 } else { 854 mutex_exit(CMLB_MUTEX(cl)); 855 return (EINVAL); 856 } 857 } else { 858 /* if the disk is unlabeled, don't write a devid to it */ 859 if (cl->cl_label_from_media != CMLB_LABEL_VTOC) { 860 mutex_exit(CMLB_MUTEX(cl)); 861 return (EINVAL); 862 } 863 864 /* this geometry doesn't allow us to write a devid */ 865 if (cl->cl_g.dkg_acyl < 2) { 866 mutex_exit(CMLB_MUTEX(cl)); 867 return (EINVAL); 868 } 869 870 /* 871 * Subtract 2 guarantees that the next to last cylinder 872 * is used 873 */ 874 cyl = cl->cl_g.dkg_ncyl + cl->cl_g.dkg_acyl - 2; 875 spc = cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect; 876 head = cl->cl_g.dkg_nhead - 1; 877 blk = cl->cl_solaris_offset + 878 (cyl * (spc - cl->cl_g.dkg_apc)) + 879 (head * cl->cl_g.dkg_nsect) + 1; 880 } 881 882 *devidblockp = blk; 883 mutex_exit(CMLB_MUTEX(cl)); 884 return (0); 885 } 886 887 /* 888 * cmlb_partinfo: 889 * Get partition info for specified partition number. 890 * 891 * Arguments: 892 * cmlbhandle cmlb handle associated with device. 893 * part partition number 894 * nblocksp pointer to number of blocks 895 * startblockp pointer to starting block 896 * partnamep pointer to name of partition 897 * tagp pointer to tag info 898 * tg_cookie cookie from target driver to be passed back to target 899 * driver when we call back to it through tg_ops. 900 * 901 * 902 * Notes: 903 * If in-core label is not valid, this functions tries to revalidate 904 * the label. If label is valid, it stores the total number of blocks 905 * in this partition in the area pointed to by nblocksp, starting 906 * block number in area pointed to by startblockp, pointer to partition 907 * name in area pointed to by partnamep, and tag value in area 908 * pointed by tagp. 909 * For EFI labels, tag value will be set to 0. 910 * 911 * For all nblocksp, startblockp and partnamep, tagp, a value of NULL 912 * indicates the corresponding info is not requested. 913 * 914 * 915 * Return values: 916 * 0 success 917 * EINVAL no valid label or requested partition number is invalid. 918 * 919 */ 920 int 921 cmlb_partinfo(cmlb_handle_t cmlbhandle, int part, diskaddr_t *nblocksp, 922 diskaddr_t *startblockp, char **partnamep, uint16_t *tagp, void *tg_cookie) 923 { 924 925 struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 926 int rval; 927 928 ASSERT(cl != NULL); 929 mutex_enter(CMLB_MUTEX(cl)); 930 if (cl->cl_state < CMLB_ATTACHED) { 931 mutex_exit(CMLB_MUTEX(cl)); 932 return (EINVAL); 933 } 934 935 if (part < 0 || part >= MAXPART) { 936 rval = EINVAL; 937 } else { 938 if (cl->cl_f_geometry_is_valid == FALSE) 939 (void) cmlb_validate_geometry((struct cmlb_lun *)cl, 0, 940 0, tg_cookie); 941 942 #if defined(_SUNOS_VTOC_16) 943 if (((cl->cl_f_geometry_is_valid == FALSE) || 944 (part < NDKMAP && cl->cl_solaris_size == 0)) && 945 (part != P0_RAW_DISK)) { 946 #else 947 if ((cl->cl_f_geometry_is_valid == FALSE) || 948 (part < NDKMAP && cl->cl_solaris_size == 0)) { 949 #endif 950 rval = EINVAL; 951 } else { 952 if (startblockp != NULL) 953 *startblockp = (diskaddr_t)cl->cl_offset[part]; 954 955 if (nblocksp != NULL) 956 *nblocksp = (diskaddr_t) 957 cl->cl_map[part].dkl_nblk; 958 959 if (tagp != NULL) 960 if (cl->cl_cur_labeltype == CMLB_LABEL_EFI) 961 *tagp = V_UNASSIGNED; 962 else 963 *tagp = cl->cl_vtoc.v_part[part].p_tag; 964 rval = 0; 965 } 966 967 /* consistent with behavior of sd for getting minor name */ 968 if (partnamep != NULL) 969 *partnamep = dk_minor_data[part].name; 970 971 } 972 973 mutex_exit(CMLB_MUTEX(cl)); 974 return (rval); 975 } 976 977 /* 978 * cmlb_efi_label_capacity: 979 * Get capacity stored in EFI disk label. 980 * 981 * Arguments: 982 * cmlbhandle cmlb handle associated with device. 983 * capacity pointer to capacity stored in EFI disk label. 984 * tg_cookie cookie from target driver to be passed back to target 985 * driver when we call back to it through tg_ops. 986 * 987 * 988 * Notes: 989 * If in-core label is not valid, this functions tries to revalidate 990 * the label. If label is valid and is an EFI label, it stores the capacity 991 * in disk label in the area pointed to by capacity. 992 * 993 * 994 * Return values: 995 * 0 success 996 * EINVAL no valid EFI label or capacity is NULL. 997 * 998 */ 999 int 1000 cmlb_efi_label_capacity(cmlb_handle_t cmlbhandle, diskaddr_t *capacity, 1001 void *tg_cookie) 1002 { 1003 struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 1004 int rval; 1005 1006 ASSERT(cl != NULL); 1007 mutex_enter(CMLB_MUTEX(cl)); 1008 if (cl->cl_state < CMLB_ATTACHED) { 1009 mutex_exit(CMLB_MUTEX(cl)); 1010 return (EINVAL); 1011 } 1012 1013 if (cl->cl_f_geometry_is_valid == FALSE) 1014 (void) cmlb_validate_geometry((struct cmlb_lun *)cl, 0, 1015 0, tg_cookie); 1016 1017 if ((cl->cl_f_geometry_is_valid == FALSE) || (capacity == NULL) || 1018 (cl->cl_cur_labeltype != CMLB_LABEL_EFI)) { 1019 rval = EINVAL; 1020 } else { 1021 *capacity = (diskaddr_t)cl->cl_map[WD_NODE].dkl_nblk; 1022 rval = 0; 1023 } 1024 1025 mutex_exit(CMLB_MUTEX(cl)); 1026 return (rval); 1027 } 1028 1029 /* Caller should make sure Test Unit Ready succeeds before calling this. */ 1030 /*ARGSUSED*/ 1031 int 1032 cmlb_ioctl(cmlb_handle_t cmlbhandle, dev_t dev, int cmd, intptr_t arg, 1033 int flag, cred_t *cred_p, int *rval_p, void *tg_cookie) 1034 { 1035 1036 int err; 1037 struct cmlb_lun *cl; 1038 1039 cl = (struct cmlb_lun *)cmlbhandle; 1040 1041 ASSERT(cl != NULL); 1042 1043 mutex_enter(CMLB_MUTEX(cl)); 1044 if (cl->cl_state < CMLB_ATTACHED) { 1045 mutex_exit(CMLB_MUTEX(cl)); 1046 return (EIO); 1047 } 1048 1049 switch (cmd) { 1050 case DKIOCSEXTVTOC: 1051 case DKIOCSGEOM: 1052 case DKIOCSETEFI: 1053 case DKIOCSMBOOT: 1054 break; 1055 case DKIOCSVTOC: 1056 #if defined(__i386) || defined(__amd64) 1057 case DKIOCPARTINFO: 1058 #endif 1059 if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) { 1060 mutex_exit(CMLB_MUTEX(cl)); 1061 return (EOVERFLOW); 1062 } 1063 break; 1064 default: 1065 (void) cmlb_validate_geometry(cl, 1, CMLB_SILENT, 1066 tg_cookie); 1067 1068 switch (cmd) { 1069 case DKIOCGVTOC: 1070 case DKIOCGAPART: 1071 case DKIOCSAPART: 1072 1073 if (cl->cl_label_from_media == CMLB_LABEL_EFI) { 1074 /* GPT label on disk */ 1075 mutex_exit(CMLB_MUTEX(cl)); 1076 return (ENOTSUP); 1077 } else if 1078 (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) { 1079 mutex_exit(CMLB_MUTEX(cl)); 1080 return (EOVERFLOW); 1081 } 1082 break; 1083 1084 case DKIOCGGEOM: 1085 if (cl->cl_label_from_media == CMLB_LABEL_EFI) { 1086 /* GPT label on disk */ 1087 mutex_exit(CMLB_MUTEX(cl)); 1088 return (ENOTSUP); 1089 } 1090 break; 1091 default: 1092 break; 1093 } 1094 } 1095 1096 mutex_exit(CMLB_MUTEX(cl)); 1097 1098 switch (cmd) { 1099 case DKIOCGGEOM: 1100 cmlb_dbg(CMLB_TRACE, cl, "DKIOCGGEOM\n"); 1101 err = cmlb_dkio_get_geometry(cl, (caddr_t)arg, flag, tg_cookie); 1102 break; 1103 1104 case DKIOCSGEOM: 1105 cmlb_dbg(CMLB_TRACE, cl, "DKIOCSGEOM\n"); 1106 err = cmlb_dkio_set_geometry(cl, (caddr_t)arg, flag); 1107 break; 1108 1109 case DKIOCGAPART: 1110 cmlb_dbg(CMLB_TRACE, cl, "DKIOCGAPART\n"); 1111 err = cmlb_dkio_get_partition(cl, (caddr_t)arg, 1112 flag, tg_cookie); 1113 break; 1114 1115 case DKIOCSAPART: 1116 cmlb_dbg(CMLB_TRACE, cl, "DKIOCSAPART\n"); 1117 err = cmlb_dkio_set_partition(cl, (caddr_t)arg, flag); 1118 break; 1119 1120 case DKIOCGVTOC: 1121 cmlb_dbg(CMLB_TRACE, cl, "DKIOCGVTOC\n"); 1122 err = cmlb_dkio_get_vtoc(cl, (caddr_t)arg, flag, tg_cookie); 1123 break; 1124 1125 case DKIOCGEXTVTOC: 1126 cmlb_dbg(CMLB_TRACE, cl, "DKIOCGVTOC\n"); 1127 err = cmlb_dkio_get_extvtoc(cl, (caddr_t)arg, flag, tg_cookie); 1128 break; 1129 1130 case DKIOCGETEFI: 1131 cmlb_dbg(CMLB_TRACE, cl, "DKIOCGETEFI\n"); 1132 err = cmlb_dkio_get_efi(cl, (caddr_t)ar