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