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