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