1786Slclee /* 2786Slclee * CDDL HEADER START 3786Slclee * 4786Slclee * The contents of this file are subject to the terms of the 53525Sshidokht * Common Development and Distribution License (the "License"). 63525Sshidokht * You may not use this file except in compliance with the License. 7786Slclee * 8786Slclee * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9786Slclee * or http://www.opensolaris.org/os/licensing. 10786Slclee * See the License for the specific language governing permissions 11786Slclee * and limitations under the License. 12786Slclee * 13786Slclee * When distributing Covered Code, include this CDDL HEADER in each 14786Slclee * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15786Slclee * If applicable, add the following below this CDDL HEADER, with the 16786Slclee * fields enclosed by brackets "[]" replaced with your own identifying 17786Slclee * information: Portions Copyright [yyyy] [name of copyright owner] 18786Slclee * 19786Slclee * CDDL HEADER END 20786Slclee */ 21786Slclee 22786Slclee /* 23*6124Sshidokht * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24786Slclee * Use is subject to license terms. 25786Slclee */ 26786Slclee 27786Slclee #pragma ident "%Z%%M% %I% %E% SMI" 28786Slclee 29786Slclee /* 30786Slclee * This module provides support for labeling operations for target 31786Slclee * drivers. 32786Slclee */ 33786Slclee 34786Slclee #include <sys/scsi/scsi.h> 35786Slclee #include <sys/sunddi.h> 36786Slclee #include <sys/dklabel.h> 37786Slclee #include <sys/dkio.h> 38786Slclee #include <sys/vtoc.h> 39786Slclee #include <sys/dktp/fdisk.h> 40786Slclee #include <sys/vtrace.h> 41786Slclee #include <sys/efi_partition.h> 42786Slclee #include <sys/cmlb.h> 43786Slclee #include <sys/cmlb_impl.h> 44786Slclee 45786Slclee /* 46786Slclee * Driver minor node structure and data table 47786Slclee */ 48786Slclee struct driver_minor_data { 49786Slclee char *name; 50786Slclee minor_t minor; 51786Slclee int type; 52786Slclee }; 53786Slclee 54786Slclee static struct driver_minor_data dk_minor_data[] = { 55786Slclee {"a", 0, S_IFBLK}, 56786Slclee {"b", 1, S_IFBLK}, 57786Slclee {"c", 2, S_IFBLK}, 58786Slclee {"d", 3, S_IFBLK}, 59786Slclee {"e", 4, S_IFBLK}, 60786Slclee {"f", 5, S_IFBLK}, 61786Slclee {"g", 6, S_IFBLK}, 62786Slclee {"h", 7, S_IFBLK}, 63786Slclee #if defined(_SUNOS_VTOC_16) 64786Slclee {"i", 8, S_IFBLK}, 65786Slclee {"j", 9, S_IFBLK}, 66786Slclee {"k", 10, S_IFBLK}, 67786Slclee {"l", 11, S_IFBLK}, 68786Slclee {"m", 12, S_IFBLK}, 69786Slclee {"n", 13, S_IFBLK}, 70786Slclee {"o", 14, S_IFBLK}, 71786Slclee {"p", 15, S_IFBLK}, 72786Slclee #endif /* defined(_SUNOS_VTOC_16) */ 73786Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 74786Slclee {"q", 16, S_IFBLK}, 75786Slclee {"r", 17, S_IFBLK}, 76786Slclee {"s", 18, S_IFBLK}, 77786Slclee {"t", 19, S_IFBLK}, 78786Slclee {"u", 20, S_IFBLK}, 79786Slclee #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 80786Slclee {"a,raw", 0, S_IFCHR}, 81786Slclee {"b,raw", 1, S_IFCHR}, 82786Slclee {"c,raw", 2, S_IFCHR}, 83786Slclee {"d,raw", 3, S_IFCHR}, 84786Slclee {"e,raw", 4, S_IFCHR}, 85786Slclee {"f,raw", 5, S_IFCHR}, 86786Slclee {"g,raw", 6, S_IFCHR}, 87786Slclee {"h,raw", 7, S_IFCHR}, 88786Slclee #if defined(_SUNOS_VTOC_16) 89786Slclee {"i,raw", 8, S_IFCHR}, 90786Slclee {"j,raw", 9, S_IFCHR}, 91786Slclee {"k,raw", 10, S_IFCHR}, 92786Slclee {"l,raw", 11, S_IFCHR}, 93786Slclee {"m,raw", 12, S_IFCHR}, 94786Slclee {"n,raw", 13, S_IFCHR}, 95786Slclee {"o,raw", 14, S_IFCHR}, 96786Slclee {"p,raw", 15, S_IFCHR}, 97786Slclee #endif /* defined(_SUNOS_VTOC_16) */ 98786Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 99786Slclee {"q,raw", 16, S_IFCHR}, 100786Slclee {"r,raw", 17, S_IFCHR}, 101786Slclee {"s,raw", 18, S_IFCHR}, 102786Slclee {"t,raw", 19, S_IFCHR}, 103786Slclee {"u,raw", 20, S_IFCHR}, 104786Slclee #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 105786Slclee {0} 106786Slclee }; 107786Slclee 108786Slclee static struct driver_minor_data dk_minor_data_efi[] = { 109786Slclee {"a", 0, S_IFBLK}, 110786Slclee {"b", 1, S_IFBLK}, 111786Slclee {"c", 2, S_IFBLK}, 112786Slclee {"d", 3, S_IFBLK}, 113786Slclee {"e", 4, S_IFBLK}, 114786Slclee {"f", 5, S_IFBLK}, 115786Slclee {"g", 6, S_IFBLK}, 116786Slclee {"wd", 7, S_IFBLK}, 117786Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 118786Slclee {"q", 16, S_IFBLK}, 119786Slclee {"r", 17, S_IFBLK}, 120786Slclee {"s", 18, S_IFBLK}, 121786Slclee {"t", 19, S_IFBLK}, 122786Slclee {"u", 20, S_IFBLK}, 123786Slclee #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 124786Slclee {"a,raw", 0, S_IFCHR}, 125786Slclee {"b,raw", 1, S_IFCHR}, 126786Slclee {"c,raw", 2, S_IFCHR}, 127786Slclee {"d,raw", 3, S_IFCHR}, 128786Slclee {"e,raw", 4, S_IFCHR}, 129786Slclee {"f,raw", 5, S_IFCHR}, 130786Slclee {"g,raw", 6, S_IFCHR}, 131786Slclee {"wd,raw", 7, S_IFCHR}, 132786Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 133786Slclee {"q,raw", 16, S_IFCHR}, 134786Slclee {"r,raw", 17, S_IFCHR}, 135786Slclee {"s,raw", 18, S_IFCHR}, 136786Slclee {"t,raw", 19, S_IFCHR}, 137786Slclee {"u,raw", 20, S_IFCHR}, 138786Slclee #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 139786Slclee {0} 140786Slclee }; 141786Slclee 142786Slclee 143786Slclee 144786Slclee extern struct mod_ops mod_miscops; 145786Slclee 146786Slclee /* 147786Slclee * Global buffer and mutex for debug logging 148786Slclee */ 149786Slclee static char cmlb_log_buffer[1024]; 150786Slclee static kmutex_t cmlb_log_mutex; 151786Slclee 152786Slclee 1533525Sshidokht struct cmlb_lun *cmlb_debug_cl = NULL; 154786Slclee uint_t cmlb_level_mask = 0x0; 155786Slclee 156786Slclee int cmlb_rot_delay = 4; /* default rotational delay */ 157786Slclee 158786Slclee static struct modlmisc modlmisc = { 159786Slclee &mod_miscops, /* Type of module */ 160786Slclee "Common Labeling module %I%" 161786Slclee }; 162786Slclee 163786Slclee static struct modlinkage modlinkage = { 164786Slclee MODREV_1, (void *)&modlmisc, NULL 165786Slclee }; 166786Slclee 167786Slclee /* Local function prototypes */ 1683525Sshidokht static dev_t cmlb_make_device(struct cmlb_lun *cl); 1693525Sshidokht static int cmlb_validate_geometry(struct cmlb_lun *cl, int forcerevalid, 1703525Sshidokht int flags, void *tg_cookie); 1713525Sshidokht static void cmlb_resync_geom_caches(struct cmlb_lun *cl, diskaddr_t capacity, 1723525Sshidokht void *tg_cookie); 1733525Sshidokht static int cmlb_read_fdisk(struct cmlb_lun *cl, diskaddr_t capacity, 1743525Sshidokht void *tg_cookie); 175786Slclee static void cmlb_swap_efi_gpt(efi_gpt_t *e); 176786Slclee static void cmlb_swap_efi_gpe(int nparts, efi_gpe_t *p); 177786Slclee static int cmlb_validate_efi(efi_gpt_t *labp); 1783525Sshidokht static int cmlb_use_efi(struct cmlb_lun *cl, diskaddr_t capacity, int flags, 1793525Sshidokht void *tg_cookie); 1803525Sshidokht static void cmlb_build_default_label(struct cmlb_lun *cl, void *tg_cookie); 1813525Sshidokht static int cmlb_uselabel(struct cmlb_lun *cl, struct dk_label *l, int flags); 1823525Sshidokht #if defined(_SUNOS_VTOC_8) 1833525Sshidokht static void cmlb_build_user_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc); 1843525Sshidokht #endif 1853525Sshidokht static int cmlb_build_label_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc); 1863525Sshidokht static int cmlb_write_label(struct cmlb_lun *cl, void *tg_cookie); 1873525Sshidokht static int cmlb_set_vtoc(struct cmlb_lun *cl, struct dk_label *dkl, 1883525Sshidokht void *tg_cookie); 1893525Sshidokht static void cmlb_clear_efi(struct cmlb_lun *cl, void *tg_cookie); 1903525Sshidokht static void cmlb_clear_vtoc(struct cmlb_lun *cl, void *tg_cookie); 1913525Sshidokht static void cmlb_setup_default_geometry(struct cmlb_lun *cl, void *tg_cookie); 1923525Sshidokht static int cmlb_create_minor_nodes(struct cmlb_lun *cl); 1933525Sshidokht static int cmlb_check_update_blockcount(struct cmlb_lun *cl, void *tg_cookie); 1945624Sshidokht static int cmlb_check_efi_mbr(uchar_t *buf); 195786Slclee 196786Slclee #if defined(__i386) || defined(__amd64) 1973525Sshidokht static int cmlb_update_fdisk_and_vtoc(struct cmlb_lun *cl, void *tg_cookie); 198786Slclee #endif 199786Slclee 200786Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 201786Slclee static int cmlb_has_max_chs_vals(struct ipart *fdp); 202786Slclee #endif 203786Slclee 204786Slclee #if defined(_SUNOS_VTOC_16) 2053525Sshidokht static void cmlb_convert_geometry(diskaddr_t capacity, struct dk_geom *cl_g); 206786Slclee #endif 207786Slclee 2083525Sshidokht static int cmlb_dkio_get_geometry(struct cmlb_lun *cl, caddr_t arg, int flag, 2093525Sshidokht void *tg_cookie); 2103525Sshidokht static int cmlb_dkio_set_geometry(struct cmlb_lun *cl, caddr_t arg, int flag); 2113525Sshidokht static int cmlb_dkio_get_partition(struct cmlb_lun *cl, caddr_t arg, int flag, 2123525Sshidokht void *tg_cookie); 2133525Sshidokht static int cmlb_dkio_set_partition(struct cmlb_lun *cl, caddr_t arg, int flag); 2143525Sshidokht static int cmlb_dkio_get_efi(struct cmlb_lun *cl, caddr_t arg, int flag, 2153525Sshidokht void *tg_cookie); 2163525Sshidokht static int cmlb_dkio_set_efi(struct cmlb_lun *cl, dev_t dev, caddr_t arg, 2173525Sshidokht int flag, void *tg_cookie); 2183525Sshidokht static int cmlb_dkio_get_vtoc(struct cmlb_lun *cl, caddr_t arg, int flag, 2193525Sshidokht void *tg_cookie); 2203525Sshidokht static int cmlb_dkio_set_vtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, 2213525Sshidokht int flag, void *tg_cookie); 2223525Sshidokht static int cmlb_dkio_get_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, 2233525Sshidokht void *tg_cookie); 2243525Sshidokht static int cmlb_dkio_set_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, 2253525Sshidokht void *tg_cookie); 2263525Sshidokht static int cmlb_dkio_partition(struct cmlb_lun *cl, caddr_t arg, int flag, 2273525Sshidokht void *tg_cookie); 228786Slclee 229786Slclee #if defined(__i386) || defined(__amd64) 2303525Sshidokht static int cmlb_dkio_get_virtgeom(struct cmlb_lun *cl, caddr_t arg, int flag); 2313525Sshidokht static int cmlb_dkio_get_phygeom(struct cmlb_lun *cl, caddr_t arg, int flag); 2323525Sshidokht static int cmlb_dkio_partinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg, 233786Slclee int flag); 234786Slclee #endif 235786Slclee 2363525Sshidokht static void cmlb_dbg(uint_t comp, struct cmlb_lun *cl, const char *fmt, ...); 237786Slclee static void cmlb_v_log(dev_info_t *dev, char *label, uint_t level, 238786Slclee const char *fmt, va_list ap); 239786Slclee static void cmlb_log(dev_info_t *dev, char *label, uint_t level, 240786Slclee const char *fmt, ...); 241786Slclee 242786Slclee int 243786Slclee _init(void) 244786Slclee { 245786Slclee mutex_init(&cmlb_log_mutex, NULL, MUTEX_DRIVER, NULL); 246786Slclee return (mod_install(&modlinkage)); 247786Slclee } 248786Slclee 249786Slclee int 250786Slclee _info(struct modinfo *modinfop) 251786Slclee { 252786Slclee return (mod_info(&modlinkage, modinfop)); 253786Slclee } 254786Slclee 255786Slclee int 256786Slclee _fini(void) 257786Slclee { 258786Slclee int err; 259786Slclee 260786Slclee if ((err = mod_remove(&modlinkage)) != 0) { 261786Slclee return (err); 262786Slclee } 263786Slclee 264786Slclee mutex_destroy(&cmlb_log_mutex); 265786Slclee return (err); 266786Slclee } 267786Slclee 268786Slclee /* 269786Slclee * cmlb_dbg is used for debugging to log additional info 270786Slclee * Level of output is controlled via cmlb_level_mask setting. 271786Slclee */ 272786Slclee static void 2733525Sshidokht cmlb_dbg(uint_t comp, struct cmlb_lun *cl, const char *fmt, ...) 274786Slclee { 275786Slclee va_list ap; 276786Slclee dev_info_t *dev; 277786Slclee uint_t level_mask = 0; 278786Slclee 2793525Sshidokht ASSERT(cl != NULL); 2803525Sshidokht dev = CMLB_DEVINFO(cl); 281786Slclee ASSERT(dev != NULL); 282786Slclee /* 283786Slclee * Filter messages based on the global component and level masks, 2843525Sshidokht * also print if cl matches the value of cmlb_debug_cl, or if 2853525Sshidokht * cmlb_debug_cl is set to NULL. 286786Slclee */ 287786Slclee if (comp & CMLB_TRACE) 288786Slclee level_mask |= CMLB_LOGMASK_TRACE; 289786Slclee 290786Slclee if (comp & CMLB_INFO) 291786Slclee level_mask |= CMLB_LOGMASK_INFO; 292786Slclee 293786Slclee if (comp & CMLB_ERROR) 294786Slclee level_mask |= CMLB_LOGMASK_ERROR; 295786Slclee 296786Slclee if ((cmlb_level_mask & level_mask) && 2973525Sshidokht ((cmlb_debug_cl == NULL) || (cmlb_debug_cl == cl))) { 298786Slclee va_start(ap, fmt); 2993525Sshidokht cmlb_v_log(dev, CMLB_LABEL(cl), CE_CONT, fmt, ap); 300786Slclee va_end(ap); 301786Slclee } 302786Slclee } 303786Slclee 304786Slclee /* 305786Slclee * cmlb_log is basically a duplicate of scsi_log. It is redefined here 306786Slclee * so that this module does not depend on scsi module. 307786Slclee */ 308786Slclee static void 309786Slclee cmlb_log(dev_info_t *dev, char *label, uint_t level, const char *fmt, ...) 310786Slclee { 311786Slclee va_list ap; 312786Slclee 313786Slclee va_start(ap, fmt); 314786Slclee cmlb_v_log(dev, label, level, fmt, ap); 315786Slclee va_end(ap); 316786Slclee } 317786Slclee 318786Slclee static void 319786Slclee cmlb_v_log(dev_info_t *dev, char *label, uint_t level, const char *fmt, 320786Slclee va_list ap) 321786Slclee { 322786Slclee static char name[256]; 323786Slclee int log_only = 0; 324786Slclee int boot_only = 0; 325786Slclee int console_only = 0; 326786Slclee 327786Slclee mutex_enter(&cmlb_log_mutex); 328786Slclee 329786Slclee if (dev) { 330786Slclee if (level == CE_PANIC || level == CE_WARN || 331786Slclee level == CE_NOTE) { 332786Slclee (void) sprintf(name, "%s (%s%d):\n", 333786Slclee ddi_pathname(dev, cmlb_log_buffer), 334786Slclee label, ddi_get_instance(dev)); 335786Slclee } else { 336786Slclee name[0] = '\0'; 337786Slclee } 338786Slclee } else { 339786Slclee (void) sprintf(name, "%s:", label); 340786Slclee } 341786Slclee 342786Slclee (void) vsprintf(cmlb_log_buffer, fmt, ap); 343786Slclee 344786Slclee switch (cmlb_log_buffer[0]) { 345786Slclee case '!': 346786Slclee log_only = 1; 347786Slclee break; 348786Slclee case '?': 349786Slclee boot_only = 1; 350786Slclee break; 351786Slclee case '^': 352786Slclee console_only = 1; 353786Slclee break; 354786Slclee } 355786Slclee 356786Slclee switch (level) { 357786Slclee case CE_NOTE: 358786Slclee level = CE_CONT; 359786Slclee /* FALLTHROUGH */ 360786Slclee case CE_CONT: 361786Slclee case CE_WARN: 362786Slclee case CE_PANIC: 363786Slclee if (boot_only) { 364786Slclee cmn_err(level, "?%s\t%s", name, &cmlb_log_buffer[1]); 365786Slclee } else if (console_only) { 366786Slclee cmn_err(level, "^%s\t%s", name, &cmlb_log_buffer[1]); 367786Slclee } else if (log_only) { 368786Slclee cmn_err(level, "!%s\t%s", name, &cmlb_log_buffer[1]); 369786Slclee } else { 370786Slclee cmn_err(level, "%s\t%s", name, cmlb_log_buffer); 371786Slclee } 372786Slclee break; 373786Slclee case CE_IGNORE: 374786Slclee break; 375786Slclee default: 376786Slclee cmn_err(CE_CONT, "^DEBUG: %s\t%s", name, cmlb_log_buffer); 377786Slclee break; 378786Slclee } 379786Slclee mutex_exit(&cmlb_log_mutex); 380786Slclee } 381786Slclee 382786Slclee 383786Slclee /* 384786Slclee * cmlb_alloc_handle: 385786Slclee * 386786Slclee * Allocates a handle. 387786Slclee * 388786Slclee * Arguments: 389786Slclee * cmlbhandlep pointer to handle 390786Slclee * 391786Slclee * Notes: 392786Slclee * Allocates a handle and stores the allocated handle in the area 393786Slclee * pointed to by cmlbhandlep 394786Slclee * 395786Slclee * Context: 396786Slclee * Kernel thread only (can sleep). 397786Slclee */ 398786Slclee void 399786Slclee cmlb_alloc_handle(cmlb_handle_t *cmlbhandlep) 400786Slclee { 4013525Sshidokht struct cmlb_lun *cl; 4023525Sshidokht 4033525Sshidokht cl = kmem_zalloc(sizeof (struct cmlb_lun), KM_SLEEP); 404786Slclee ASSERT(cmlbhandlep != NULL); 405786Slclee 4063525Sshidokht cl->cl_state = CMLB_INITED; 4073525Sshidokht cl->cl_def_labeltype = CMLB_LABEL_UNDEF; 4083525Sshidokht mutex_init(CMLB_MUTEX(cl), NULL, MUTEX_DRIVER, NULL); 4093525Sshidokht 4103525Sshidokht *cmlbhandlep = (cmlb_handle_t)(cl); 411786Slclee } 412786Slclee 413786Slclee /* 414786Slclee * cmlb_free_handle 415786Slclee * 416786Slclee * Frees handle. 417786Slclee * 418786Slclee * Arguments: 419786Slclee * cmlbhandlep pointer to handle 420786Slclee */ 421786Slclee void 422786Slclee cmlb_free_handle(cmlb_handle_t *cmlbhandlep) 423786Slclee { 4243525Sshidokht struct cmlb_lun *cl; 4253525Sshidokht 4263525Sshidokht cl = (struct cmlb_lun *)*cmlbhandlep; 4273525Sshidokht if (cl != NULL) { 4283525Sshidokht mutex_destroy(CMLB_MUTEX(cl)); 4293525Sshidokht kmem_free(cl, sizeof (struct cmlb_lun)); 430786Slclee } 431786Slclee 432786Slclee } 433786Slclee 434786Slclee /* 435786Slclee * cmlb_attach: 436786Slclee * 437786Slclee * Attach handle to device, create minor nodes for device. 438786Slclee * 439786Slclee * Arguments: 440786Slclee * devi pointer to device's dev_info structure. 441786Slclee * tgopsp pointer to array of functions cmlb can use to callback 442786Slclee * to target driver. 443786Slclee * 444786Slclee * device_type Peripheral device type as defined in 445786Slclee * scsi/generic/inquiry.h 446786Slclee * 447786Slclee * is_removable whether or not device is removable. 448786Slclee * 0 non-removable, 1 removable. 449786Slclee * 4503525Sshidokht * is_hotpluggable whether or not device is hotpluggable. 4513525Sshidokht * 0 non-hotpluggable, 1 hotpluggable. 4523525Sshidokht * 453786Slclee * node_type minor node type (as used by ddi_create_minor_node) 454786Slclee * 455786Slclee * alter_behavior 456786Slclee * bit flags: 457786Slclee * 458786Slclee * CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT: create 459786Slclee * an alternate slice for the default label, if 460786Slclee * device type is DTYPE_DIRECT an architectures default 461786Slclee * label type is VTOC16. 462786Slclee * Otherwise alternate slice will no be created. 463786Slclee * 464786Slclee * 465786Slclee * CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8: report a default 466786Slclee * geometry and label for DKIOCGGEOM and DKIOCGVTOC 467786Slclee * on architecture with VTOC8 label types. 468786Slclee * 4693525Sshidokht * CMLB_OFF_BY_ONE: do the workaround for legacy off-by- 4703525Sshidokht * one bug in obtaining capacity (in sd): 4713525Sshidokht * SCSI READ_CAPACITY command returns the LBA number of the 4723525Sshidokht * last logical block, but sd once treated this number as 4733525Sshidokht * disks' capacity on x86 platform. And LBAs are addressed 4743525Sshidokht * based 0. So the last block was lost on x86 platform. 4753525Sshidokht * 4763525Sshidokht * Now, we remove this workaround. In order for present sd 4773525Sshidokht * driver to work with disks which are labeled/partitioned 4783525Sshidokht * via previous sd, we add workaround as follows: 4793525Sshidokht * 4803525Sshidokht * 1) Locate backup EFI label: cmlb searches the next to 4813525Sshidokht * last 4823525Sshidokht * block for backup EFI label. If fails, it will 4833525Sshidokht * turn to the last block for backup EFI label; 4843525Sshidokht * 4853525Sshidokht * 2) Clear backup EFI label: cmlb first search the last 4863525Sshidokht * block for backup EFI label, and will search the 4873525Sshidokht * next to last block only if failed for the last 4883525Sshidokht * block. 4893525Sshidokht * 4903525Sshidokht * 3) Calculate geometry:refer to cmlb_convert_geometry() 4913525Sshidokht * If capacity increasing by 1 causes disks' capacity 4923525Sshidokht * to cross over the limits in table CHS_values, 4933525Sshidokht * geometry info will change. This will raise an issue: 4943525Sshidokht * In case that primary VTOC label is destroyed, format 4953525Sshidokht * commandline can restore it via backup VTOC labels. 4963525Sshidokht * And format locates backup VTOC labels by use of 4973525Sshidokht * geometry. So changing geometry will 4983525Sshidokht * prevent format from finding backup VTOC labels. To 4993525Sshidokht * eliminate this side effect for compatibility, 5003525Sshidokht * sd uses (capacity -1) to calculate geometry; 5013525Sshidokht * 5023525Sshidokht * 4) 1TB disks: some important data structures use 5033525Sshidokht * 32-bit signed long/int (for example, daddr_t), 5043525Sshidokht * so that sd doesn't support a disk with capacity 5053525Sshidokht * larger than 1TB on 32-bit platform. However, 5063525Sshidokht * for exactly 1TB disk, it was treated as (1T - 512)B 5073525Sshidokht * in the past, and could have valid Solaris 5083525Sshidokht * partitions. To workaround this, if an exactly 1TB 5093525Sshidokht * disk has Solaris fdisk partition, it will be allowed 5103525Sshidokht * to work with sd. 5113525Sshidokht * 5123525Sshidokht * 513786Slclee * 5145084Sjohnlev * CMLB_FAKE_LABEL_ONE_PARTITION: create s0 and s2 covering 5155084Sjohnlev * the entire disk, if there is no valid partition info. 5165084Sjohnlev * If there is a valid Solaris partition, s0 and s2 will 5175084Sjohnlev * only cover the entire Solaris partition. 5185084Sjohnlev * 5195084Sjohnlev * 520786Slclee * cmlbhandle cmlb handle associated with device 521786Slclee * 5223525Sshidokht * tg_cookie cookie from target driver to be passed back to target 5233525Sshidokht * driver when we call back to it through tg_ops. 5243525Sshidokht * 525786Slclee * Notes: 526786Slclee * Assumes a default label based on capacity for non-removable devices. 527786Slclee * If capacity > 1TB, EFI is assumed otherwise VTOC (default VTOC 528786Slclee * for the architecture). 529786Slclee * 530786Slclee * For removable devices, default label type is assumed to be VTOC 531786Slclee * type. Create minor nodes based on a default label type. 532786Slclee * Label on the media is not validated. 533786Slclee * minor number consists of: 534786Slclee * if _SUNOS_VTOC_8 is defined 535786Slclee * lowest 3 bits is taken as partition number 536786Slclee * the rest is instance number 537786Slclee * if _SUNOS_VTOC_16 is defined 538786Slclee * lowest 6 bits is taken as partition number 539786Slclee * the rest is instance number 540786Slclee * 541786Slclee * 542786Slclee * Return values: 543786Slclee * 0 Success 544786Slclee * ENXIO creating minor nodes failed. 5453525Sshidokht * EINVAL invalid arg, unsupported tg_ops version 546786Slclee */ 547786Slclee int 548786Slclee cmlb_attach(dev_info_t *devi, cmlb_tg_ops_t *tgopsp, int device_type, 5493525Sshidokht int is_removable, int is_hotpluggable, char *node_type, 5503525Sshidokht int alter_behavior, cmlb_handle_t cmlbhandle, void *tg_cookie) 551786Slclee { 552786Slclee 5533525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 554786Slclee diskaddr_t cap; 555786Slclee int status; 556786Slclee 5573525Sshidokht if (tgopsp->tg_version < TG_DK_OPS_VERSION_1) 5583525Sshidokht return (EINVAL); 5593525Sshidokht 5603525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 5613525Sshidokht 5623525Sshidokht CMLB_DEVINFO(cl) = devi; 5633525Sshidokht cl->cmlb_tg_ops = tgopsp; 5643525Sshidokht cl->cl_device_type = device_type; 5653525Sshidokht cl->cl_is_removable = is_removable; 5663525Sshidokht cl->cl_is_hotpluggable = is_hotpluggable; 5673525Sshidokht cl->cl_node_type = node_type; 5683525Sshidokht cl->cl_sys_blocksize = DEV_BSIZE; 5693525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 5703525Sshidokht cl->cl_def_labeltype = CMLB_LABEL_VTOC; 5713525Sshidokht cl->cl_alter_behavior = alter_behavior; 5723525Sshidokht cl->cl_reserved = -1; 573786Slclee 574786Slclee if (is_removable != 0) { 5753525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 5763525Sshidokht status = DK_TG_GETCAP(cl, &cap, tg_cookie); 5773525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 578786Slclee if (status == 0 && cap > DK_MAX_BLOCKS) { 579786Slclee /* set default EFI if > 1TB */ 5803525Sshidokht cl->cl_def_labeltype = CMLB_LABEL_EFI; 581786Slclee } 582786Slclee } 583786Slclee 584786Slclee /* create minor nodes based on default label type */ 5853525Sshidokht cl->cl_last_labeltype = CMLB_LABEL_UNDEF; 5863525Sshidokht cl->cl_cur_labeltype = CMLB_LABEL_UNDEF; 5873525Sshidokht 5883525Sshidokht if (cmlb_create_minor_nodes(cl) != 0) { 5893525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 590786Slclee return (ENXIO); 591786Slclee } 592786Slclee 5933525Sshidokht cl->cl_state = CMLB_ATTACHED; 5943525Sshidokht 5953525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 596786Slclee return (0); 597786Slclee } 598786Slclee 599786Slclee /* 600786Slclee * cmlb_detach: 601786Slclee * 602786Slclee * Invalidate in-core labeling data and remove all minor nodes for 603786Slclee * the device associate with handle. 604786Slclee * 605786Slclee * Arguments: 606786Slclee * cmlbhandle cmlb handle associated with device. 607786Slclee * 6083525Sshidokht * tg_cookie cookie from target driver to be passed back to target 6093525Sshidokht * driver when we call back to it through tg_ops. 6103525Sshidokht * 611786Slclee */ 6123525Sshidokht /*ARGSUSED1*/ 613786Slclee void 6143525Sshidokht cmlb_detach(cmlb_handle_t cmlbhandle, void *tg_cookie) 615786Slclee { 6163525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 6173525Sshidokht 6183525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 6193525Sshidokht cl->cl_def_labeltype = CMLB_LABEL_UNDEF; 6203525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 6213525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL); 6223525Sshidokht cl->cl_state = CMLB_INITED; 6233525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 624786Slclee } 625786Slclee 626786Slclee /* 627786Slclee * cmlb_validate: 628786Slclee * 629786Slclee * Validates label. 630786Slclee * 631786Slclee * Arguments 632786Slclee * cmlbhandle cmlb handle associated with device. 633786Slclee * 6343525Sshidokht * flags operation flags. used for verbosity control 6353525Sshidokht * 6363525Sshidokht * tg_cookie cookie from target driver to be passed back to target 6373525Sshidokht * driver when we call back to it through tg_ops. 6383525Sshidokht * 6393525Sshidokht * 640786Slclee * Notes: 641786Slclee * If new label type is different from the current, adjust minor nodes 642786Slclee * accordingly. 643786Slclee * 644786Slclee * Return values: 645786Slclee * 0 success 646786Slclee * Note: having fdisk but no solaris partition is assumed 647786Slclee * success. 648786Slclee * 649786Slclee * ENOMEM memory allocation failed 650786Slclee * EIO i/o errors during read or get capacity 651786Slclee * EACCESS reservation conflicts 652786Slclee * EINVAL label was corrupt, or no default label was assumed 653786Slclee * ENXIO invalid handle 654786Slclee */ 655786Slclee int 6563525Sshidokht cmlb_validate(cmlb_handle_t cmlbhandle, int flags, void *tg_cookie) 657786Slclee { 6583525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 659786Slclee int rval; 660786Slclee int ret = 0; 661786Slclee 662786Slclee /* 6633525Sshidokht * Temp work-around checking cl for NULL since there is a bug 664786Slclee * in sd_detach calling this routine from taskq_dispatch 665786Slclee * inited function. 666786Slclee */ 6673525Sshidokht if (cl == NULL) 668786Slclee return (ENXIO); 669786Slclee 6703525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 6713525Sshidokht if (cl->cl_state < CMLB_ATTACHED) { 6723525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 673786Slclee return (ENXIO); 674786Slclee } 675786Slclee 6763525Sshidokht rval = cmlb_validate_geometry((struct cmlb_lun *)cmlbhandle, 1, 6773525Sshidokht flags, tg_cookie); 678786Slclee 679786Slclee if (rval == ENOTSUP) { 6803525Sshidokht if (cl->cl_f_geometry_is_valid == TRUE) { 6813525Sshidokht cl->cl_cur_labeltype = CMLB_LABEL_EFI; 682786Slclee ret = 0; 683786Slclee } else { 684786Slclee ret = EINVAL; 685786Slclee } 686786Slclee } else { 687786Slclee ret = rval; 688786Slclee if (ret == 0) 6893525Sshidokht cl->cl_cur_labeltype = CMLB_LABEL_VTOC; 690786Slclee } 691786Slclee 692786Slclee if (ret == 0) 6933525Sshidokht (void) cmlb_create_minor_nodes(cl); 6943525Sshidokht 6953525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 696786Slclee return (ret); 697786Slclee } 698786Slclee 699786Slclee /* 700786Slclee * cmlb_invalidate: 701786Slclee * Invalidate in core label data 702786Slclee * 703786Slclee * Arguments: 704786Slclee * cmlbhandle cmlb handle associated with device. 7053525Sshidokht * tg_cookie cookie from target driver to be passed back to target 7063525Sshidokht * driver when we call back to it through tg_ops. 707786Slclee */ 7083525Sshidokht /*ARGSUSED1*/ 709786Slclee void 7103525Sshidokht cmlb_invalidate(cmlb_handle_t cmlbhandle, void *tg_cookie) 711786Slclee { 7123525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 7133525Sshidokht 7143525Sshidokht if (cl == NULL) 715786Slclee return; 716786Slclee 7173525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 7183525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 7193525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 720786Slclee } 721786Slclee 722786Slclee /* 7233525Sshidokht * cmlb_is_valid 7243525Sshidokht * Get status on whether the incore label/geom data is valid 7253525Sshidokht * 7263525Sshidokht * Arguments: 7273525Sshidokht * cmlbhandle cmlb handle associated with device. 7283525Sshidokht * 7293525Sshidokht * Return values: 7303525Sshidokht * TRUE if incore label/geom data is valid. 7313525Sshidokht * FALSE otherwise. 7323525Sshidokht * 7333525Sshidokht */ 7343525Sshidokht 7353525Sshidokht 7363525Sshidokht int 7373525Sshidokht cmlb_is_valid(cmlb_handle_t cmlbhandle) 7383525Sshidokht { 7393525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 7403525Sshidokht 7413525Sshidokht if (cmlbhandle == NULL) 7423525Sshidokht return (FALSE); 7433525Sshidokht 7443525Sshidokht return (cl->cl_f_geometry_is_valid); 7453525Sshidokht 7463525Sshidokht } 7473525Sshidokht 7483525Sshidokht 7493525Sshidokht 7503525Sshidokht /* 751786Slclee * cmlb_close: 752786Slclee * 753786Slclee * Close the device, revert to a default label minor node for the device, 754786Slclee * if it is removable. 755786Slclee * 756786Slclee * Arguments: 757786Slclee * cmlbhandle cmlb handle associated with device. 758786Slclee * 7593525Sshidokht * tg_cookie cookie from target driver to be passed back to target 7603525Sshidokht * driver when we call back to it through tg_ops. 761786Slclee * Return values: 762786Slclee * 0 Success 763786Slclee * ENXIO Re-creating minor node failed. 764786Slclee */ 7653525Sshidokht /*ARGSUSED1*/ 766786Slclee int 7673525Sshidokht cmlb_close(cmlb_handle_t cmlbhandle, void *tg_cookie) 768786Slclee { 7693525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 7703525Sshidokht 7713525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 7723525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 773786Slclee 774786Slclee /* revert to default minor node for this device */ 7753525Sshidokht if (ISREMOVABLE(cl)) { 7763525Sshidokht cl->cl_cur_labeltype = CMLB_LABEL_UNDEF; 7773525Sshidokht (void) cmlb_create_minor_nodes(cl); 778786Slclee } 779786Slclee 7803525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 781786Slclee return (0); 782786Slclee } 783786Slclee 784786Slclee /* 785786Slclee * cmlb_get_devid_block: 786786Slclee * get the block number where device id is stored. 787786Slclee * 788786Slclee * Arguments: 789786Slclee * cmlbhandle cmlb handle associated with device. 790786Slclee * devidblockp pointer to block number. 7913525Sshidokht * tg_cookie cookie from target driver to be passed back to target 7923525Sshidokht * driver when we call back to it through tg_ops. 793786Slclee * 794786Slclee * Notes: 795786Slclee * It stores the block number of device id in the area pointed to 796786Slclee * by devidblockp. 797786Slclee * with the block number of device id. 798786Slclee * 799786Slclee * Return values: 800786Slclee * 0 success 801786Slclee * EINVAL device id does not apply to current label type. 802786Slclee */ 8033525Sshidokht /*ARGSUSED2*/ 804786Slclee int 8053525Sshidokht cmlb_get_devid_block(cmlb_handle_t cmlbhandle, diskaddr_t *devidblockp, 8063525Sshidokht void *tg_cookie) 807786Slclee { 808786Slclee daddr_t spc, blk, head, cyl; 8093525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 8103525Sshidokht 8113525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 8123525Sshidokht if (cl->cl_state < CMLB_ATTACHED) { 8133525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 8143525Sshidokht return (EINVAL); 8153525Sshidokht } 8163525Sshidokht 8173525Sshidokht if ((cl->cl_f_geometry_is_valid == FALSE) || 8183525Sshidokht (cl->cl_solaris_size < DK_LABEL_LOC)) { 8193525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 820786Slclee return (EINVAL); 821786Slclee } 822786Slclee 8233525Sshidokht 8243525Sshidokht if (cl->cl_cur_labeltype == CMLB_LABEL_EFI) { 8253525Sshidokht if (cl->cl_reserved != -1) { 8263525Sshidokht blk = cl->cl_map[cl->cl_reserved].dkl_cylno; 8273525Sshidokht } else { 8283525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 8293525Sshidokht return (EINVAL); 8303525Sshidokht } 8313525Sshidokht } else { 832786Slclee /* this geometry doesn't allow us to write a devid */ 8333525Sshidokht if (cl->cl_g.dkg_acyl < 2) { 8343525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 835786Slclee return (EINVAL); 836786Slclee } 837786Slclee 838786Slclee /* 839786Slclee * Subtract 2 guarantees that the next to last cylinder 840786Slclee * is used 841786Slclee */ 8423525Sshidokht cyl = cl->cl_g.dkg_ncyl + cl->cl_g.dkg_acyl - 2; 8433525Sshidokht spc = cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect; 8443525Sshidokht head = cl->cl_g.dkg_nhead - 1; 8453525Sshidokht blk = (cyl * (spc - cl->cl_g.dkg_apc)) + 8463525Sshidokht (head * cl->cl_g.dkg_nsect) + 1; 847786Slclee } 8483525Sshidokht 849786Slclee *devidblockp = blk; 8503525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 851786Slclee return (0); 852786Slclee } 853786Slclee 854786Slclee /* 855786Slclee * cmlb_partinfo: 856786Slclee * Get partition info for specified partition number. 857786Slclee * 858786Slclee * Arguments: 859786Slclee * cmlbhandle cmlb handle associated with device. 860786Slclee * part partition number 861786Slclee * nblocksp pointer to number of blocks 862786Slclee * startblockp pointer to starting block 863786Slclee * partnamep pointer to name of partition 864786Slclee * tagp pointer to tag info 8653525Sshidokht * tg_cookie cookie from target driver to be passed back to target 8663525Sshidokht * driver when we call back to it through tg_ops. 867786Slclee * 868786Slclee * 869786Slclee * Notes: 870786Slclee * If in-core label is not valid, this functions tries to revalidate 871786Slclee * the label. If label is valid, it stores the total number of blocks 872786Slclee * in this partition in the area pointed to by nblocksp, starting 873786Slclee * block number in area pointed to by startblockp, pointer to partition 874786Slclee * name in area pointed to by partnamep, and tag value in area 875786Slclee * pointed by tagp. 876786Slclee * For EFI labels, tag value will be set to 0. 877786Slclee * 878786Slclee * For all nblocksp, startblockp and partnamep, tagp, a value of NULL 879786Slclee * indicates the corresponding info is not requested. 880786Slclee * 881786Slclee * 882786Slclee * Return values: 883786Slclee * 0 success 884786Slclee * EINVAL no valid label or requested partition number is invalid. 885786Slclee * 886786Slclee */ 887786Slclee int 888786Slclee cmlb_partinfo(cmlb_handle_t cmlbhandle, int part, diskaddr_t *nblocksp, 8893525Sshidokht diskaddr_t *startblockp, char **partnamep, uint16_t *tagp, void *tg_cookie) 890786Slclee { 891786Slclee 8923525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 893786Slclee int rval; 894786Slclee 8953525Sshidokht ASSERT(cl != NULL); 8963525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 8973525Sshidokht if (cl->cl_state < CMLB_ATTACHED) { 8983525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 899786Slclee return (EINVAL); 900786Slclee } 901786Slclee 902786Slclee if (part < 0 || part >= MAXPART) { 903786Slclee rval = EINVAL; 904786Slclee } else { 9053525Sshidokht if (cl->cl_f_geometry_is_valid == FALSE) 9063525Sshidokht (void) cmlb_validate_geometry((struct cmlb_lun *)cl, 0, 9073525Sshidokht 0, tg_cookie); 9083525Sshidokht 9093525Sshidokht if ((cl->cl_f_geometry_is_valid == FALSE) || 9103525Sshidokht (part < NDKMAP && cl->cl_solaris_size == 0)) { 911786Slclee rval = EINVAL; 912786Slclee } else { 913786Slclee if (startblockp != NULL) 9143525Sshidokht *startblockp = (diskaddr_t)cl->cl_offset[part]; 915786Slclee 916786Slclee if (nblocksp != NULL) 917786Slclee *nblocksp = (diskaddr_t) 9183525Sshidokht cl->cl_map[part].dkl_nblk; 919786Slclee 920786Slclee if (tagp != NULL) 9213525Sshidokht if (cl->cl_cur_labeltype == CMLB_LABEL_EFI) 922786Slclee *tagp = V_UNASSIGNED; 923786Slclee else 9243525Sshidokht *tagp = cl->cl_vtoc.v_part[part].p_tag; 925786Slclee rval = 0; 926786Slclee } 927786Slclee 928786Slclee /* consistent with behavior of sd for getting minor name */ 929786Slclee if (partnamep != NULL) 930786Slclee *partnamep = dk_minor_data[part].name; 931786Slclee 932786Slclee } 933786Slclee 9343525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 935786Slclee return (rval); 936786Slclee } 937786Slclee 9383525Sshidokht /* Caller should make sure Test Unit Ready succeeds before calling this. */ 9393525Sshidokht /*ARGSUSED*/ 940786Slclee int 941786Slclee cmlb_ioctl(cmlb_handle_t cmlbhandle, dev_t dev, int cmd, intptr_t arg, 9423525Sshidokht int flag, cred_t *cred_p, int *rval_p, void *tg_cookie) 943786Slclee { 944786Slclee 945786Slclee int err; 9463525Sshidokht struct cmlb_lun *cl; 9473525Sshidokht int status; 9483525Sshidokht 9493525Sshidokht cl = (struct cmlb_lun *)cmlbhandle; 9503525Sshidokht 9513525Sshidokht ASSERT(cl != NULL); 9523525Sshidokht 9533525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 9543525Sshidokht if (cl->cl_state < CMLB_ATTACHED) { 9553525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 956786Slclee return (EIO); 957786Slclee } 958786Slclee 959786Slclee switch (cmd) { 960786Slclee case DKIOCSVTOC: 9613525Sshidokht case DKIOCSGEOM: 962786Slclee case DKIOCSETEFI: 963786Slclee case DKIOCSMBOOT: 964786Slclee break; 965786Slclee default: 9663903Sshidokht status = cmlb_validate_geometry(cl, 1, CMLB_SILENT, 9673903Sshidokht tg_cookie); 9683525Sshidokht 969786Slclee /* 9703525Sshidokht * VTOC related ioctls except SVTOC/SGEOM should 9713525Sshidokht * fail if > 1TB disk and there is not already a VTOC 9723525Sshidokht * on the disk.i.e either EFI or blank 9733525Sshidokht * 9743525Sshidokht * PHYGEOM AND VIRTGEOM succeeds when disk is 9753525Sshidokht * EFI labeled but <1TB 976786Slclee */ 9773525Sshidokht 9783525Sshidokht if (status == ENOTSUP && 9793525Sshidokht cl->cl_f_geometry_is_valid == FALSE) { 980786Slclee switch (cmd) { 981786Slclee case DKIOCGAPART: 982786Slclee case DKIOCGGEOM: 983786Slclee case DKIOCGVTOC: 984786Slclee case DKIOCSAPART: 9853525Sshidokht case DKIOCG_PHYGEOM: 9863525Sshidokht case DKIOCG_VIRTGEOM: 9873525Sshidokht 9883525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 989786Slclee return (ENOTSUP); 990786Slclee } 9913525Sshidokht } else { 9923525Sshidokht if ((cl->cl_f_geometry_is_valid == TRUE) && 9933525Sshidokht (cl->cl_solaris_size > 0)) { 9943525Sshidokht if (cl->cl_vtoc.v_sanity != VTOC_SANE) { 9953525Sshidokht /* 9963525Sshidokht * it is EFI, so return ENOTSUP for 9973525Sshidokht * these 9983525Sshidokht */ 9993525Sshidokht switch (cmd) { 10003525Sshidokht case DKIOCGAPART: 10013525Sshidokht case DKIOCGGEOM: 10023525Sshidokht case DKIOCGVTOC: 10033525Sshidokht case DKIOCSVTOC: 10043525Sshidokht case DKIOCSAPART: 10053525Sshidokht 10063525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 10073525Sshidokht return (ENOTSUP); 10083525Sshidokht } 10093525Sshidokht } 1010786Slclee } 1011786Slclee } 1012786Slclee } 1013786Slclee 10143525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 1015786Slclee 1016786Slclee switch (cmd) { 1017786Slclee case DKIOCGGEOM: 10183525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGGEOM\n"); 10193525Sshidokht err = cmlb_dkio_get_geometry(cl, (caddr_t)arg, flag, tg_cookie); 1020786Slclee break; 1021786Slclee 1022786Slclee case DKIOCSGEOM: 10233525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSGEOM\n"); 10243525Sshidokht err = cmlb_dkio_set_geometry(cl, (caddr_t)arg, flag); 1025786Slclee break; 1026786Slclee 1027786Slclee case DKIOCGAPART: 10283525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGAPART\n"); 10293525Sshidokht err = cmlb_dkio_get_partition(cl, (caddr_t)arg, 10303525Sshidokht flag, tg_cookie); 1031786Slclee break; 1032786Slclee 1033786Slclee case DKIOCSAPART: 10343525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSAPART\n"); 10353525Sshidokht err = cmlb_dkio_set_partition(cl, (caddr_t)arg, flag); 1036786Slclee break; 1037786Slclee 1038786Slclee case DKIOCGVTOC: 10393525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGVTOC\n"); 10403525Sshidokht err = cmlb_dkio_get_vtoc(cl, (caddr_t)arg, flag, tg_cookie); 1041786Slclee break; 1042786Slclee 1043786Slclee case DKIOCGETEFI: 10443525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGETEFI\n"); 10453525Sshidokht err = cmlb_dkio_get_efi(cl, (caddr_t)arg, flag, tg_cookie); 1046786Slclee break; 1047786Slclee 1048786Slclee case DKIOCPARTITION: 10493525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCPARTITION\n"); 10503525Sshidokht err = cmlb_dkio_partition(cl, (caddr_t)arg, flag, tg_cookie); 1051786Slclee break; 1052786Slclee 1053786Slclee case DKIOCSVTOC: 10543525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSVTOC\n"); 10553525Sshidokht err = cmlb_dkio_set_vtoc(cl, dev, (caddr_t)arg, flag, 10563525Sshidokht tg_cookie); 1057786Slclee break; 1058786Slclee 1059786Slclee case DKIOCSETEFI: 10603525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSETEFI\n"); 10613525Sshidokht err = cmlb_dkio_set_efi(cl, dev, (caddr_t)arg, flag, tg_cookie); 1062786Slclee break; 1063786Slclee 1064786Slclee case DKIOCGMBOOT: 10653525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGMBOOT\n"); 10663525Sshidokht err = cmlb_dkio_get_mboot(cl, (caddr_t)arg, flag, tg_cookie); 1067786Slclee break; 1068786Slclee 1069786Slclee case DKIOCSMBOOT: 10703525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSMBOOT\n"); 10713525Sshidokht err = cmlb_dkio_set_mboot(cl, (caddr_t)arg, flag, tg_cookie); 1072786Slclee break; 1073786Slclee case DKIOCG_PHYGEOM: 10743525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCG_PHYGEOM\n"); 1075786Slclee #if defined(__i386) || defined(__amd64) 10763525Sshidokht err = cmlb_dkio_get_phygeom(cl, (caddr_t)arg, flag); 1077786Slclee #else 1078786Slclee err = ENOTTY; 1079786Slclee #endif 1080786Slclee break; 1081786Slclee case DKIOCG_VIRTGEOM: 10823525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCG_VIRTGEOM\n"); 1083786Slclee #if defined(__i386) || defined(__amd64) 10843525Sshidokht err = cmlb_dkio_get_virtgeom(cl, (caddr_t)arg, flag); 1085786Slclee #else 1086786Slclee err = ENOTTY; 1087786Slclee #endif 1088786Slclee break; 1089786Slclee case DKIOCPARTINFO: 10903525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCPARTINFO"); 1091786Slclee #if defined(__i386) || defined(__amd64) 10923525Sshidokht err = cmlb_dkio_partinfo(cl, dev, (caddr_t)arg, flag); 1093786Slclee #else 1094786Slclee err = ENOTTY; 1095786Slclee #endif 1096786Slclee break; 1097786Slclee 1098786Slclee default: 1099786Slclee err = ENOTTY; 1100786Slclee 1101786Slclee } 1102786Slclee return (err); 1103786Slclee } 1104786Slclee 1105786Slclee dev_t 11063525Sshidokht cmlb_make_device(struct cmlb_lun *cl) 1107786Slclee { 11083525Sshidokht return (makedevice(ddi_name_to_major(ddi_get_name(CMLB_DEVINFO(cl))), 11093525Sshidokht ddi_get_instance(CMLB_DEVINFO(cl)) << CMLBUNIT_SHIFT)); 1110786Slclee } 1111786Slclee 1112786Slclee /* 1113786Slclee * Function: cmlb_check_update_blockcount 1114786Slclee * 1115786Slclee * Description: If current capacity value is invalid, obtains the 1116786Slclee * current capacity from target driver. 1117786Slclee * 1118786Slclee * Return Code: 0 success 1119786Slclee * EIO failure 1120786Slclee */ 1121786Slclee static int 11223525Sshidokht cmlb_check_update_blockcount(struct cmlb_lun *cl, void *tg_cookie) 1123786Slclee { 1124786Slclee int status; 1125786Slclee diskaddr_t capacity; 11263525Sshidokht uint32_t lbasize; 11273525Sshidokht 11283525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 11293525Sshidokht 11303525Sshidokht if (cl->cl_f_geometry_is_valid == FALSE) { 11313525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 11323525Sshidokht status = DK_TG_GETCAP(cl, &capacity, tg_cookie); 11333525Sshidokht if (status != 0) { 11343525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 11353525Sshidokht return (EIO); 11363525Sshidokht } 11373525Sshidokht 11383525Sshidokht status = DK_TG_GETBLOCKSIZE(cl, &lbasize, tg_cookie); 11393525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 11403525Sshidokht if (status != 0) 11413525Sshidokht return (EIO); 11423525Sshidokht 11433525Sshidokht if ((capacity != 0) && (lbasize != 0)) { 11443525Sshidokht cl->cl_blockcount = capacity; 11453525Sshidokht cl->cl_tgt_blocksize = lbasize; 1146786Slclee return (0); 1147786Slclee } else 1148786Slclee return (EIO); 1149786Slclee } else 1150786Slclee return (0); 1151786Slclee } 1152786Slclee 1153786Slclee /* 1154786Slclee * Function: cmlb_create_minor_nodes 1155786Slclee * 1156786Slclee * Description: Create or adjust the minor device nodes for the instance. 1157786Slclee * Minor nodes are created based on default label type, 1158786Slclee * current label type and last label type we created 1159786Slclee * minor nodes based on. 1160786Slclee * 1161786Slclee * 11623525Sshidokht * Arguments: cl - driver soft state (unit) structure 1163786Slclee * 1164786Slclee * Return Code: 0 success 1165786Slclee * ENXIO failure. 1166786Slclee * 1167786Slclee * Context: Kernel thread context 1168786Slclee */ 1169786Slclee static int 11703525Sshidokht cmlb_create_minor_nodes(struct cmlb_lun *cl) 1171786Slclee { 1172786Slclee struct driver_minor_data *dmdp; 1173786Slclee int instance; 1174786Slclee char name[48]; 1175786Slclee cmlb_label_t newlabeltype; 1176786Slclee 11773525Sshidokht ASSERT(cl != NULL); 11783525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 1179786Slclee 1180786Slclee 1181786Slclee /* check the most common case */ 11823525Sshidokht if (cl->cl_cur_labeltype != CMLB_LABEL_UNDEF && 11833525Sshidokht cl->cl_last_labeltype == cl->cl_cur_labeltype) { 1184786Slclee /* do nothing */ 1185786Slclee return (0); 1186786Slclee } 1187786Slclee 11883525Sshidokht if (cl->cl_def_labeltype == CMLB_LABEL_UNDEF) { 1189786Slclee /* we should never get here */ 1190786Slclee return (ENXIO); 1191786Slclee } 1192786Slclee 11933525Sshidokht if (cl->cl_last_labeltype == CMLB_LABEL_UNDEF) { 1194786Slclee /* first time during attach */ 11953525Sshidokht newlabeltype = cl->cl_def_labeltype; 11963525Sshidokht 11973525Sshidokht instance = ddi_get_instance(CMLB_DEVINFO(cl)); 1198786Slclee 1199786Slclee /* Create all the minor nodes for this target. */ 1200786Slclee dmdp = (newlabeltype == CMLB_LABEL_EFI) ? dk_minor_data_efi : 1201786Slclee dk_minor_data; 1202786Slclee while (dmdp->name != NULL) { 1203786Slclee 1204786Slclee (void) sprintf(name, "%s", dmdp->name); 1205786Slclee 12063525Sshidokht if (ddi_create_minor_node(CMLB_DEVINFO(cl), name, 1207786Slclee dmdp->type, 1208786Slclee (instance << CMLBUNIT_SHIFT) | dmdp->minor, 12093525Sshidokht cl->cl_node_type, NULL) == DDI_FAILURE) { 1210786Slclee /* 1211786Slclee * Clean up any nodes that may have been 1212786Slclee * created, in case this fails in the middle 1213786Slclee * of the loop. 1214786Slclee */ 12153525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL); 1216786Slclee return (ENXIO); 1217786Slclee } 1218786Slclee dmdp++; 1219786Slclee } 12203525Sshidokht cl->cl_last_labeltype = newlabeltype; 1221786Slclee return (0); 1222786Slclee } 1223786Slclee 1224786Slclee /* Not first time */ 12253525Sshidokht if (cl->cl_cur_labeltype == CMLB_LABEL_UNDEF) { 12263525Sshidokht if (cl->cl_last_labeltype != cl->cl_def_labeltype) { 1227786Slclee /* close time, revert to default. */ 12283525Sshidokht newlabeltype = cl->cl_def_labeltype; 1229786Slclee } else { 1230786Slclee /* 1231786Slclee * do nothing since the type for which we last created 1232786Slclee * nodes matches the default 1233786Slclee */ 1234786Slclee return (0); 1235786Slclee } 1236786Slclee } else { 12373525Sshidokht if (cl->cl_cur_labeltype != cl->cl_last_labeltype) { 1238786Slclee /* We are not closing, use current label type */ 12393525Sshidokht newlabeltype = cl->cl_cur_labeltype; 1240786Slclee } else { 1241786Slclee /* 1242786Slclee * do nothing since the type for which we last created 1243786Slclee * nodes matches the current label type 1244786Slclee */ 1245786Slclee return (0); 1246786Slclee } 1247786Slclee } 1248786Slclee 12493525Sshidokht instance = ddi_get_instance(CMLB_DEVINFO(cl)); 1250786Slclee 1251786Slclee /* 1252786Slclee * Currently we only fix up the s7 node when we are switching 1253786Slclee * label types from or to EFI. This is consistent with 1254786Slclee * current behavior of sd. 1255786Slclee */ 1256786Slclee if (newlabeltype == CMLB_LABEL_EFI && 12573525Sshidokht cl->cl_last_labeltype != CMLB_LABEL_EFI) { 1258786Slclee /* from vtoc to EFI */ 12593525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "h"); 12603525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw"); 12613525Sshidokht (void) ddi_create_minor_node(CMLB_DEVINFO(cl), "wd", 1262786Slclee S_IFBLK, (instance << CMLBUNIT_SHIFT) | WD_NODE, 12633525Sshidokht cl->cl_node_type, NULL); 12643525Sshidokht (void) ddi_create_minor_node(CMLB_DEVINFO(cl), "wd,raw", 1265786Slclee S_IFCHR, (instance << CMLBUNIT_SHIFT) | WD_NODE, 12663525Sshidokht cl->cl_node_type, NULL); 1267786Slclee } else { 1268786Slclee /* from efi to vtoc */ 12693525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd"); 12703525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd,raw"); 12713525Sshidokht (void) ddi_create_minor_node(CMLB_DEVINFO(cl), "h", 1272786Slclee S_IFBLK, (instance << CMLBUNIT_SHIFT) | WD_NODE, 12733525Sshidokht cl->cl_node_type, NULL); 12743525Sshidokht (void) ddi_create_minor_node(CMLB_DEVINFO(cl), "h,raw", 1275786Slclee S_IFCHR, (instance << CMLBUNIT_SHIFT) | WD_NODE, 12763525Sshidokht cl->cl_node_type, NULL); 1277786Slclee } 1278786Slclee 12793525Sshidokht cl->cl_last_labeltype = newlabeltype; 1280786Slclee return (0); 1281786Slclee } 1282786Slclee 1283786Slclee /* 1284786Slclee * Function: cmlb_validate_geometry 1285786Slclee * 1286786Slclee * Description: Read the label from the disk (if present). Update the unit's 1287786Slclee * geometry and vtoc information from the data in the label. 1288786Slclee * Verify that the label is valid. 1289786Slclee * 12903525Sshidokht * Arguments: 12913525Sshidokht * cl driver soft state (unit) structure 12923525Sshidokht * 12933525Sshidokht * forcerevalid force revalidation even if we are already valid. 12943525Sshidokht * flags operation flags from target driver. Used for verbosity 12953525Sshidokht * control at this time. 12963525Sshidokht * tg_cookie cookie from target driver to be passed back to target 12973525Sshidokht * driver when we call back to it through tg_ops. 1298786Slclee * 1299786Slclee * Return Code: 0 - Successful completion 13003525Sshidokht * EINVAL - Invalid value in cl->cl_tgt_blocksize or 13013525Sshidokht * cl->cl_blockcount; or label on disk is corrupted 1302786Slclee * or unreadable. 1303786Slclee * EACCES - Reservation conflict at the device. 1304786Slclee * ENOMEM - Resource allocation error 1305786Slclee * ENOTSUP - geometry not applicable 1306786Slclee * 1307786Slclee * Context: Kernel thread only (can sleep). 1308786Slclee */ 1309786Slclee static int 13103525Sshidokht cmlb_validate_geometry(struct cmlb_lun *cl, int forcerevalid, int flags, 13113525Sshidokht void *tg_cookie) 1312786Slclee { 1313786Slclee int label_error = 0; 1314786Slclee diskaddr_t capacity; 1315786Slclee int count; 13163525Sshidokht #if defined(__i386) || defined(__amd64) 13173525Sshidokht int forced_under_1t = 0; 13183525Sshidokht #endif 13193525Sshidokht 13203525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 13213525Sshidokht 13223525Sshidokht if ((cl->cl_f_geometry_is_valid == TRUE) && (forcerevalid == 0)) { 13233525Sshidokht if (cl->cl_cur_labeltype == CMLB_LABEL_EFI) 1324786Slclee return (ENOTSUP); 1325786Slclee return (0); 1326786Slclee } 1327786Slclee 13283525Sshidokht if (cmlb_check_update_blockcount(cl, tg_cookie) != 0) 1329786Slclee return (EIO); 1330786Slclee 13313525Sshidokht capacity = cl->cl_blockcount; 1332786Slclee 1333786Slclee #if defined(_SUNOS_VTOC_16) 1334786Slclee /* 1335786Slclee * Set up the "whole disk" fdisk partition; this should always 1336786Slclee * exist, regardless of whether the disk contains an fdisk table 1337786Slclee * or vtoc. 1338786Slclee */ 13393525Sshidokht cl->cl_map[P0_RAW_DISK].dkl_cylno = 0; 1340786Slclee /* 1341786Slclee * note if capacity > uint32_max we should be using efi, 1342786Slclee * and not use p0, so the truncation does not matter. 1343786Slclee */ 13443525Sshidokht cl->cl_map[P0_RAW_DISK].dkl_nblk = capacity; 1345786Slclee #endif 1346786Slclee /* 1347786Slclee * Refresh the logical and physical geometry caches. 1348786Slclee * (data from MODE SENSE format/rigid disk geometry pages, 1349786Slclee * and scsi_ifgetcap("geometry"). 1350786Slclee */ 13513525Sshidokht cmlb_resync_geom_caches(cl, capacity, tg_cookie); 13523525Sshidokht 13533525Sshidokht label_error = cmlb_use_efi(cl, capacity, flags, tg_cookie); 1354786Slclee if (label_error == 0) { 1355786Slclee 1356786Slclee /* found a valid EFI label */ 13573525Sshidokht cmlb_dbg(CMLB_TRACE, cl, 1358786Slclee "cmlb_validate_geometry: found EFI label\n"); 1359786Slclee /* 1360786Slclee * solaris_size and geometry_is_valid are set in 1361786Slclee * cmlb_use_efi 1362786Slclee */ 1363786Slclee return (ENOTSUP); 1364786Slclee } 1365786Slclee 1366786Slclee /* NO EFI label found */ 1367786Slclee 1368786Slclee if (capacity > DK_MAX_BLOCKS) { 1369786Slclee if (label_error == ESRCH) { 1370786Slclee /* 1371786Slclee * they've configured a LUN over 1TB, but used 1372786Slclee * format.dat to restrict format's view of the 1373786Slclee * capacity to be under 1TB 1374786Slclee */ 1375786Slclee /* i.e > 1Tb with a VTOC < 1TB */ 13763525Sshidokht if (!(flags & CMLB_SILENT)) { 13773525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), 13783525Sshidokht CE_WARN, "is >1TB and has a VTOC label: " 13793525Sshidokht "use format(1M) to either decrease the"); 13803525Sshidokht 13813525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), 13823525Sshidokht CE_NOTE, "size to be < 1TB or relabel the " 13833525Sshidokht "disk with an EFI label"); 13843525Sshidokht #if defined(__i386) || defined(__amd64) 13853525Sshidokht forced_under_1t = 1; 13863525Sshidokht #endif 13873525Sshidokht } 1388786Slclee } else { 1389786Slclee /* unlabeled disk over 1TB */ 13903525Sshidokht #if defined(__i386) || defined(__amd64) 13913525Sshidokht 13923525Sshidokht /* 13933525Sshidokht * Refer to comments on off-by-1 at the head of the file 13943525Sshidokht * A 1TB disk was treated as (1T - 512)B in the past, 13953525Sshidokht * thus, it might have valid solaris partition. We 13963525Sshidokht * will return ENOTSUP later only if this disk has no 13973525Sshidokht * valid solaris partition. 13983525Sshidokht */ 13993525Sshidokht if (!(cl->cl_alter_behavior & CMLB_OFF_BY_ONE) || 14003525Sshidokht (cl->cl_sys_blocksize != cl->cl_tgt_blocksize) || 14013525Sshidokht (capacity - 1 > DK_MAX_BLOCKS)) 14023525Sshidokht #endif 14033525Sshidokht return (ENOTSUP); 1404786Slclee } 1405786Slclee } 1406786Slclee 1407786Slclee label_error = 0; 1408786Slclee 1409786Slclee /* 1410786Slclee * at this point it is either labeled with a VTOC or it is 14113525Sshidokht * under 1TB (<= 1TB actually for off-by-1) 1412786Slclee */ 1413786Slclee 1414786Slclee /* 14153525Sshidokht * Only DIRECT ACCESS devices will have Scl labels. 14163525Sshidokht * CD's supposedly have a Scl label, too 1417786Slclee */ 14183525Sshidokht if (cl->cl_device_type == DTYPE_DIRECT || ISREMOVABLE(cl)) { 1419786Slclee struct dk_label *dkl; 1420786Slclee offset_t label_addr; 1421786Slclee int rval; 1422786Slclee size_t buffer_size; 1423786Slclee 1424786Slclee /* 14253525Sshidokht * Note: This will set up cl->cl_solaris_size and 14263525Sshidokht * cl->cl_solaris_offset. 1427786Slclee */ 14283525Sshidokht rval = cmlb_read_fdisk(cl, capacity, tg_cookie); 14293525Sshidokht if ((rval != 0) && !ISCD(cl)) { 14303525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 1431786Slclee return (rval); 1432786Slclee } 1433786Slclee 14343525Sshidokht if (cl->cl_solaris_size <= DK_LABEL_LOC) { 14353525Sshidokht 14363525Sshidokht #if defined(__i386) || defined(__amd64) 14373525Sshidokht /* 14383525Sshidokht * Refer to comments on off-by-1 at the head of the file 14393525Sshidokht * This is for 1TB disk only. Since that there is no 14403525Sshidokht * solaris partitions, return ENOTSUP as we do for 14413525Sshidokht * >1TB disk. 14423525Sshidokht */ 14433525Sshidokht if (cl->cl_blockcount > DK_MAX_BLOCKS) 14443525Sshidokht return (ENOTSUP); 14453525Sshidokht #endif 1446786Slclee /* 1447786Slclee * Found fdisk table but no Solaris partition entry, 1448786Slclee * so don't call cmlb_uselabel() and don't create 1449786Slclee * a default label. 1450786Slclee */ 1451786Slclee label_error = 0; 14523525Sshidokht cl->cl_f_geometry_is_valid = TRUE; 1453786Slclee goto no_solaris_partition; 1454786Slclee } 1455786Slclee 14563525Sshidokht label_addr = (daddr_t)(cl->cl_solaris_offset + DK_LABEL_LOC); 14573525Sshidokht 14583525Sshidokht #if defined(__i386) || defined(__amd64) 14593525Sshidokht /* 14603525Sshidokht * Refer to comments on off-by-1 at the head of the file 14613525Sshidokht * Now, this 1TB disk has valid solaris partition. It 14623525Sshidokht * must be created by previous sd driver, we have to 14633525Sshidokht * treat it as (1T-512)B. 14643525Sshidokht */ 14653525Sshidokht if ((cl->cl_blockcount > DK_MAX_BLOCKS) && 14663525Sshidokht (forced_under_1t != 1)) { 14673525Sshidokht /* 14683525Sshidokht * Refer to cmlb_read_fdisk, when there is no 14693525Sshidokht * fdisk partition table, cl_solaris_size is 14703525Sshidokht * set to disk's capacity. In this case, we 14713525Sshidokht * need to adjust it 14723525Sshidokht */ 14733525Sshidokht if (cl->cl_solaris_size > DK_MAX_BLOCKS) 14743525Sshidokht cl->cl_solaris_size = DK_MAX_BLOCKS; 14753525Sshidokht cmlb_resync_geom_caches(cl, DK_MAX_BLOCKS, tg_cookie); 14763525Sshidokht } 14773525Sshidokht #endif 1478786Slclee 1479786Slclee buffer_size = sizeof (struct dk_label); 1480786Slclee 14813525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "cmlb_validate_geometry: " 1482786Slclee "label_addr: 0x%x allocation size: 0x%x\n", 1483786Slclee label_addr, buffer_size); 1484786Slclee 1485786Slclee if ((dkl = kmem_zalloc(buffer_size, KM_NOSLEEP)) == NULL) 1486786Slclee return (ENOMEM); 1487786Slclee 14883525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 14893525Sshidokht rval = DK_TG_READ(cl, dkl, label_addr, buffer_size, tg_cookie); 14903525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 1491786Slclee 1492786Slclee switch (rval) { 1493786Slclee case 0: 1494786Slclee /* 1495786Slclee * cmlb_uselabel will establish that the geometry 1496786Slclee * is valid. 1497786Slclee */ 14983525Sshidokht if (cmlb_uselabel(cl, 14993525Sshidokht (struct dk_label *)(uintptr_t)dkl, flags) != 1500786Slclee CMLB_LABEL_IS_VALID) { 1501786Slclee label_error = EINVAL; 1502786Slclee } else 15033525Sshidokht cl->cl_vtoc_label_is_from_media = 1; 1504786Slclee break; 1505786Slclee case EACCES: 1506786Slclee label_error = EACCES; 1507786Slclee break; 1508786Slclee default: 1509786Slclee label_error = EINVAL; 1510786Slclee break; 1511786Slclee } 1512786Slclee 1513786Slclee kmem_free(dkl, buffer_size); 1514786Slclee } 1515786Slclee 1516786Slclee /* 1517786Slclee * If a valid label was not found, AND if no reservation conflict 1518786Slclee * was detected, then go ahead and create a default label (4069506). 1519786Slclee * 1520786Slclee * Note: currently, for VTOC_8 devices, the default label is created 15213525Sshidokht * for removables and hotpluggables only. For VTOC_16 devices, the 15223525Sshidokht * default label will be created for all devices. 1523786Slclee * (see cmlb_build_default_label) 1524786Slclee */ 1525786Slclee #if defined(_SUNOS_VTOC_8) 15263525Sshidokht if ((ISREMOVABLE(cl) || ISHOTPLUGGABLE(cl)) && 15273525Sshidokht (label_error != EACCES)) { 1528786Slclee #elif defined(_SUNOS_VTOC_16) 1529786Slclee if (label_error != EACCES) { 1530786Slclee #endif 15313525Sshidokht if (cl->cl_f_geometry_is_valid == FALSE) { 15323525Sshidokht cmlb_build_default_label(cl, tg_cookie); 1533786Slclee } 1534786Slclee label_error = 0; 1535786Slclee } 1536786Slclee 1537786Slclee no_solaris_partition: 1538786Slclee 1539786Slclee #if defined(_SUNOS_VTOC_16) 1540786Slclee /* 1541786Slclee * If we have valid geometry, set up the remaining fdisk partitions. 1542786Slclee * Note that dkl_cylno is not used for the fdisk map entries, so 1543786Slclee * we set it to an entirely bogus value. 1544786Slclee */ 1545786Slclee for (count = 0; count < FD_NUMPART; count++) { 15463525Sshidokht cl->cl_map[FDISK_P1 + count].dkl_cylno = -1; 15473525Sshidokht cl->cl_map[FDISK_P1 + count].dkl_nblk = 15483525Sshidokht cl->cl_fmap[count].fmap_nblk; 15493525Sshidokht 15503525Sshidokht cl->cl_offset[FDISK_P1 + count] = 15513525Sshidokht cl->cl_fmap[count].fmap_start; 1552786Slclee } 1553786Slclee #endif 1554786Slclee 1555786Slclee for (count = 0; count < NDKMAP; count++) { 1556786Slclee #if defined(_SUNOS_VTOC_8) 15573525Sshidokht struct dk_map *lp = &cl->cl_map[count]; 15583525Sshidokht cl->cl_offset[count] = 15593525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno; 1560786Slclee #elif defined(_SUNOS_VTOC_16) 15613525Sshidokht struct dkl_partition *vp = &cl->cl_vtoc.v_part[count]; 15623525Sshidokht 15633525Sshidokht cl->cl_offset[count] = vp->p_start + cl->cl_solaris_offset; 1564786Slclee #else 1565786Slclee #error "No VTOC format defined." 1566786Slclee #endif 1567786Slclee } 1568786Slclee 1569786Slclee return (label_error); 1570786Slclee } 1571786Slclee 1572786Slclee #if defined(_SUNOS_VTOC_16) 1573786Slclee /* 1574786Slclee * Macro: MAX_BLKS 1575786Slclee * 1576786Slclee * This macro is used for table entries where we need to have the largest 1577786Slclee * possible sector value for that head & SPT (sectors per track) 1578786Slclee * combination. Other entries for some smaller disk sizes are set by 1579786Slclee * convention to match those used by X86 BIOS usage. 1580786Slclee */ 1581786Slclee #define MAX_BLKS(heads, spt) UINT16_MAX * heads * spt, heads, spt 1582786Slclee 1583786Slclee /* 1584786Slclee * Function: cmlb_convert_geometry 1585786Slclee * 1586786Slclee * Description: Convert physical geometry into a dk_geom structure. In 1587786Slclee * other words, make sure we don't wrap 16-bit values. 1588786Slclee * e.g. converting from geom_cache to dk_geom 1589786Slclee * 1590786Slclee * Context: Kernel thread only 1591786Slclee */ 1592786Slclee static void 15933525Sshidokht cmlb_convert_geometry(diskaddr_t capacity, struct dk_geom *cl_g) 1594786Slclee { 1595786Slclee int i; 1596786Slclee static const struct chs_values { 1597786Slclee uint_t max_cap; /* Max Capacity for this HS. */ 1598786Slclee uint_t nhead; /* Heads to use. */ 1599786Slclee uint_t nsect; /* SPT to use. */ 1600786Slclee } CHS_values[] = { 1601786Slclee {0x00200000, 64, 32}, /* 1GB or smaller disk. */ 1602786Slclee {0x01000000, 128, 32}, /* 8GB or smaller disk. */ 1603786Slclee {MAX_BLKS(255, 63)}, /* 502.02GB or smaller disk. */ 1604786Slclee {MAX_BLKS(255, 126)}, /* .98TB or smaller disk. */ 1605786Slclee {DK_MAX_BLOCKS, 255, 189} /* Max size is just under 1TB */ 1606786Slclee }; 1607786Slclee 1608786Slclee /* Unlabeled SCSI floppy device */ 1609786Slclee if (capacity <= 0x1000) { 16103525Sshidokht cl_g->dkg_nhead = 2; 16113525Sshidokht cl_g->dkg_ncyl = 80; 16123525Sshidokht cl_g->dkg_nsect = capacity / (cl_g->dkg_nhead * cl_g->dkg_ncyl); 1613786Slclee return; 1614786Slclee } 1615786Slclee 1616786Slclee /* 1617786Slclee * For all devices we calculate cylinders using the 1618786Slclee * heads and sectors we assign based on capacity of the 1619786Slclee * device. The table is designed to be compatible with the 1620786Slclee * way other operating systems lay out fdisk tables for X86 1621786Slclee * and to insure that the cylinders never exceed 65535 to 1622786Slclee * prevent problems with X86 ioctls that report geometry. 1623786Slclee * We use SPT that are multiples of 63, since other OSes that 1624786Slclee * are not limited to 16-bits for cylinders stop at 63 SPT 1625786Slclee * we make do by using multiples of 63 SPT. 1626786Slclee * 1627786Slclee * Note than capacities greater than or equal to 1TB will simply 1628786Slclee * get the largest geometry from the table. This should be okay 1629786Slclee * since disks this large shouldn't be using CHS values anyway. 1630786Slclee */ 1631786Slclee for (i = 0; CHS_values[i].max_cap < capacity && 1632786Slclee CHS_values[i].max_cap != DK_MAX_BLOCKS; i++) 1633786Slclee ; 1634786Slclee 16353525Sshidokht cl_g->dkg_nhead = CHS_values[i].nhead; 16363525Sshidokht cl_g->dkg_nsect = CHS_values[i].nsect; 1637786Slclee } 1638786Slclee #endif 1639786Slclee 1640786Slclee /* 1641786Slclee * Function: cmlb_resync_geom_caches 1642786Slclee * 1643786Slclee * Description: (Re)initialize both geometry caches: the virtual geometry 1644786Slclee * information is extracted from the HBA (the "geometry" 1645786Slclee * capability), and the physical geometry cache data is 1646786Slclee * generated by issuing MODE SENSE commands. 1647786Slclee * 16483525Sshidokht * Arguments: 16493525Sshidokht * cl driver soft state (unit) structure 16503525Sshidokht * capacity disk capacity in #blocks 16513525Sshidokht * tg_cookie cookie from target driver to be passed back to target 16523525Sshidokht * driver when we call back to it through tg_ops. 1653786Slclee * 1654786Slclee * Context: Kernel thread only (can sleep). 1655786Slclee */ 1656786Slclee static void 16573525Sshidokht cmlb_resync_geom_caches(struct cmlb_lun *cl, diskaddr_t capacity, 16583525Sshidokht void *tg_cookie) 1659786Slclee { 1660786Slclee struct cmlb_geom pgeom; 1661786Slclee struct cmlb_geom lgeom; 1662786Slclee struct cmlb_geom *pgeomp = &pgeom; 1663786Slclee unsigned short nhead; 1664786Slclee unsigned short nsect; 1665786Slclee int spc; 1666786Slclee int ret; 1667786Slclee 16683525Sshidokht ASSERT(cl != NULL); 16693525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 1670786Slclee 1671786Slclee /* 1672786Slclee * Ask the controller for its logical geometry. 1673786Slclee * Note: if the HBA does not support scsi_ifgetcap("geometry"), 1674786Slclee * then the lgeom cache will be invalid. 1675786Slclee */ 16763525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 1677786Slclee bzero(&lgeom, sizeof (struct cmlb_geom)); 16783525Sshidokht ret = DK_TG_GETVIRTGEOM(cl, &lgeom, tg_cookie); 16793525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 16803525Sshidokht 16813525Sshidokht bcopy(&lgeom, &cl->cl_lgeom, sizeof (cl->cl_lgeom)); 1682786Slclee 1683786Slclee /* 1684786Slclee * Initialize the pgeom cache from lgeom, so that if MODE SENSE 1685786Slclee * doesn't work, DKIOCG_PHYSGEOM can return reasonable values. 1686786Slclee */ 16873525Sshidokht if (ret != 0 || cl->cl_lgeom.g_nsect == 0 || 16883525Sshidokht cl->cl_lgeom.g_nhead == 0) { 1689786Slclee /* 1690786Slclee * Note: Perhaps this needs to be more adaptive? The rationale 1691786Slclee * is that, if there's no HBA geometry from the HBA driver, any 1692786Slclee * guess is good, since this is the physical geometry. If MODE 1693786Slclee * SENSE fails this gives a max cylinder size for non-LBA access 1694786Slclee */ 1695786Slclee nhead = 255; 1696786Slclee nsect = 63; 1697786Slclee } else { 16983525Sshidokht nhead = cl->cl_lgeom.g_nhead; 16993525Sshidokht nsect = cl->cl_lgeom.g_nsect; 1700786Slclee } 1701786Slclee 17023525Sshidokht if (ISCD(cl)) { 1703786Slclee pgeomp->g_nhead = 1; 1704786Slclee pgeomp->g_nsect = nsect * nhead; 1705786Slclee } else { 1706786Slclee pgeomp->g_nhead = nhead; 1707786Slclee pgeomp->g_nsect = nsect; 1708786Slclee } 1709786Slclee 1710786Slclee spc = pgeomp->g_nhead * pgeomp->g_nsect; 1711786Slclee pgeomp->g_capacity = capacity; 1712786Slclee pgeomp->g_ncyl = pgeomp->g_capacity / spc; 1713786Slclee pgeomp->g_acyl = 0; 1714786Slclee 1715786Slclee /* 1716786Slclee * Retrieve fresh geometry data from the hardware, stash it 1717786Slclee * here temporarily before we rebuild the incore label. 1718786Slclee * 1719786Slclee * We want to use the MODE SENSE commands to derive the 1720786Slclee * physical geometry of the device, but if either command 1721786Slclee * fails, the logical geometry is used as the fallback for 1722786Slclee * disk label geometry. 1723786Slclee */ 1724786Slclee 17253525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 17263525Sshidokht (void) DK_TG_GETPHYGEOM(cl, pgeomp, tg_cookie); 17273525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 1728786Slclee 1729786Slclee /* 1730786Slclee * Now update the real copy while holding the mutex. This 1731786Slclee * way the global copy is never in an inconsistent state. 1732786Slclee */ 17333525Sshidokht bcopy(pgeomp, &cl->cl_pgeom, sizeof (cl->cl_pgeom)); 17343525Sshidokht 17353525Sshidokht cmlb_dbg(CMLB_INFO, cl, "cmlb_resync_geom_caches: " 1736786Slclee "(cached from lgeom)\n"); 17373525Sshidokht cmlb_dbg(CMLB_INFO, cl, 1738786Slclee " ncyl: %ld; acyl: %d; nhead: %d; nsect: %d\n", 17393525Sshidokht cl->cl_pgeom.g_ncyl, cl->cl_pgeom.g_acyl, 17403525Sshidokht cl->cl_pgeom.g_nhead, cl->cl_pgeom.g_nsect); 17413525Sshidokht cmlb_dbg(CMLB_INFO, cl, " lbasize: %d; capacity: %ld; " 17423525Sshidokht "intrlv: %d; rpm: %d\n", cl->cl_pgeom.g_secsize, 17433525Sshidokht cl->cl_pgeom.g_capacity, cl->cl_pgeom.g_intrlv, 17443525Sshidokht cl->cl_pgeom.g_rpm); 1745786Slclee } 1746786Slclee 1747786Slclee 1748786Slclee /* 1749786Slclee * Function: cmlb_read_fdisk 1750786Slclee * 1751786Slclee * Description: utility routine to read the fdisk table. 1752786Slclee * 17533525Sshidokht * Arguments: 17543525Sshidokht * cl driver soft state (unit) structure 17553525Sshidokht * capacity disk capacity in #blocks 17563525Sshidokht * tg_cookie cookie from target driver to be passed back to target 17573525Sshidokht * driver when we call back to it through tg_ops. 1758786Slclee * 1759786Slclee * Return Code: 0 for success (includes not reading for no_fdisk_present case 1760786Slclee * errnos from tg_rw if failed to read the first block. 1761786Slclee * 1762786Slclee * Context: Kernel thread only (can sleep). 1763786Slclee */ 17643525Sshidokht /*ARGSUSED*/ 1765786Slclee static int 17663525Sshidokht cmlb_read_fdisk(struct cmlb_lun *cl, diskaddr_t capacity, void *tg_cookie) 1767786Slclee { 1768786Slclee #if defined(_NO_FDISK_PRESENT) 1769786Slclee 17703525Sshidokht cl->cl_solaris_offset = 0; 17713525Sshidokht cl->cl_solaris_size = capacity; 17723525Sshidokht bzero(cl->cl_fmap, sizeof (struct fmap) * FD_NUMPART); 1773786Slclee return (0); 1774786Slclee 1775786Slclee #elif defined(_FIRMWARE_NEEDS_FDISK) 1776786Slclee 1777786Slclee struct ipart *fdp; 1778786Slclee struct mboot *mbp; 1779786Slclee struct ipart fdisk[FD_NUMPART]; 1780786Slclee int i; 1781786Slclee char sigbuf[2]; 1782786Slclee caddr_t bufp; 1783786Slclee int uidx; 1784786Slclee int rval; 1785786Slclee int lba = 0; 1786786Slclee uint_t solaris_offset; /* offset to solaris part. */ 1787786Slclee daddr_t solaris_size; /* size of solaris partition */ 1788786Slclee uint32_t blocksize; 1789786Slclee 17903525Sshidokht ASSERT(cl != NULL); 17913525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 1792786Slclee 1793786Slclee /* 1794786Slclee * Start off assuming no fdisk table 1795786Slclee */ 1796786Slclee solaris_offset = 0; 1797786Slclee solaris_size = capacity; 1798786Slclee 17993525Sshidokht blocksize = cl->cl_tgt_blocksize; 1800786Slclee 1801786Slclee bufp = kmem_zalloc(blocksize, KM_SLEEP); 1802786Slclee 18033525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 18043525Sshidokht rval = DK_TG_READ(cl, bufp, 0, blocksize, tg_cookie); 18053525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 1806786Slclee 1807786Slclee if (rval != 0) { 18083525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 1809786Slclee "cmlb_read_fdisk: fdisk read err\n"); 18103525Sshidokht bzero(cl->cl_fmap, sizeof (struct fmap) * FD_NUMPART); 18113525Sshidokht goto done; 1812786Slclee } 1813786Slclee 1814786Slclee mbp = (struct mboot *)bufp; 1815786Slclee 1816786Slclee /* 1817786Slclee * The fdisk table does not begin on a 4-byte boundary within the 1818786Slclee * master boot record, so we copy it to an aligned structure to avoid 1819786Slclee * alignment exceptions on some processors. 1820786Slclee */ 1821786Slclee bcopy(&mbp->parts[0], fdisk, sizeof (fdisk)); 1822786Slclee 1823786Slclee /* 1824786Slclee * Check for lba support before verifying sig; sig might not be 1825786Slclee * there, say on a blank disk, but the max_chs mark may still 1826786Slclee * be present. 1827786Slclee * 1828786Slclee * Note: LBA support and BEFs are an x86-only concept but this 1829786Slclee * code should work OK on SPARC as well. 1830786Slclee */ 1831786Slclee 1832786Slclee /* 1833786Slclee * First, check for lba-access-ok on root node (or prom root node) 1834786Slclee * if present there, don't need to search fdisk table. 1835786Slclee */ 1836786Slclee if (ddi_getprop(DDI_DEV_T_ANY, ddi_root_node(), 0, 1837786Slclee "lba-access-ok", 0) != 0) { 1838786Slclee /* All drives do LBA; don't search fdisk table */ 1839786Slclee lba = 1; 1840786Slclee } else { 1841786Slclee /* Okay, look for mark in fdisk table */ 1842786Slclee for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) { 1843786Slclee /* accumulate "lba" value from all partitions */ 1844786Slclee lba = (lba || cmlb_has_max_chs_vals(fdp)); 1845786Slclee } 1846786Slclee } 1847786Slclee 1848786Slclee if (lba != 0) { 18493525Sshidokht dev_t dev = cmlb_make_device(cl); 18503525Sshidokht 18513525Sshidokht if (ddi_getprop(dev, CMLB_DEVINFO(cl), DDI_PROP_DONTPASS, 1852786Slclee "lba-access-ok", 0) == 0) { 1853786Slclee /* not found; create it */ 18543525Sshidokht if (ddi_prop_create(dev, CMLB_DEVINFO(cl), 0, 1855786Slclee "lba-access-ok", (caddr_t)NULL, 0) != 1856786Slclee DDI_PROP_SUCCESS) { 18573525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 1858786Slclee "cmlb_read_fdisk: Can't create lba " 1859786Slclee "property for instance %d\n", 18603525Sshidokht ddi_get_instance(CMLB_DEVINFO(cl))); 1861786Slclee } 1862786Slclee } 1863786Slclee } 1864786Slclee 1865786Slclee bcopy(&mbp->signature, sigbuf, sizeof (sigbuf)); 1866786Slclee 1867786Slclee /* 1868786Slclee * Endian-independent signature check 1869786Slclee */ 1870786Slclee if (((sigbuf[1] & 0xFF) != ((MBB_MAGIC >> 8) & 0xFF)) || 1871786Slclee (sigbuf[0] != (MBB_MAGIC & 0xFF))) { 18723525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 1873786Slclee "cmlb_read_fdisk: no fdisk\n"); 18743525Sshidokht bzero(cl->cl_fmap, sizeof (struct fmap) * FD_NUMPART); 1875786Slclee goto done; 1876786Slclee } 1877786Slclee 1878786Slclee #ifdef CMLBDEBUG 18793525Sshidokht if (cmlb_level_mask & CMLB_LOGMASK_INFO) { 1880786Slclee fdp = fdisk; 18813525Sshidokht cmlb_dbg(CMLB_INFO, cl, "cmlb_read_fdisk:\n"); 18823525Sshidokht cmlb_dbg(CMLB_INFO, cl, " relsect " 1883786Slclee "numsect sysid bootid\n"); 1884786Slclee for (i = 0; i < FD_NUMPART; i++, fdp++) { 18853525Sshidokht cmlb_dbg(CMLB_INFO, cl, 1886786Slclee " %d: %8d %8d 0x%08x 0x%08x\n", 1887786Slclee i, fdp->relsect, fdp->numsect, 1888786Slclee fdp->systid, fdp->bootid); 1889786Slclee } 1890786Slclee } 1891786Slclee #endif 1892786Slclee 1893786Slclee /* 1894786Slclee * Try to find the unix partition 1895786Slclee */ 1896786Slclee uidx = -1; 1897786Slclee solaris_offset = 0; 1898786Slclee solaris_size = 0; 1899786Slclee 1900786Slclee for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) { 1901786Slclee int relsect; 1902786Slclee int numsect; 1903786Slclee 1904786Slclee if (fdp->numsect == 0) { 19053525Sshidokht cl->cl_fmap[i].fmap_start = 0; 19063525Sshidokht cl->cl_fmap[i].fmap_nblk = 0; 1907786Slclee continue; 1908786Slclee } 1909786Slclee 1910786Slclee /* 1911786Slclee * Data in the fdisk table is little-endian. 1912786Slclee */ 1913786Slclee relsect = LE_32(fdp->relsect); 1914786Slclee numsect = LE_32(fdp->numsect); 1915786Slclee 19163525Sshidokht cl->cl_fmap[i].fmap_start = relsect; 19173525Sshidokht cl->cl_fmap[i].fmap_nblk = numsect; 1918786Slclee 1919786Slclee if (fdp->systid != SUNIXOS && 1920786Slclee fdp->systid != SUNIXOS2 && 1921786Slclee fdp->systid != EFI_PMBR) { 1922786Slclee continue; 1923786Slclee } 1924786Slclee 1925786Slclee /* 1926786Slclee * use the last active solaris partition id found 1927786Slclee * (there should only be 1 active partition id) 1928786Slclee * 1929786Slclee * if there are no active solaris partition id 1930786Slclee * then use the first inactive solaris partition id 1931786Slclee */ 1932786Slclee if ((uidx == -1) || (fdp->bootid == ACTIVE)) { 1933786Slclee uidx = i; 1934786Slclee solaris_offset = relsect; 1935786Slclee solaris_size = numsect; 1936786Slclee } 1937786Slclee } 1938786Slclee 19393525Sshidokht cmlb_dbg(CMLB_INFO, cl, "fdisk 0x%x 0x%lx", 19403525Sshidokht cl->cl_solaris_offset, cl->cl_solaris_size); 1941786Slclee done: 1942786Slclee 1943786Slclee /* 1944786Slclee * Clear the VTOC info, only if the Solaris partition entry 1945786Slclee * has moved, changed size, been deleted, or if the size of 1946786Slclee * the partition is too small to even fit the label sector. 1947786Slclee */ 19483525Sshidokht if ((cl->cl_solaris_offset != solaris_offset) || 19493525Sshidokht (cl->cl_solaris_size != solaris_size) || 1950786Slclee solaris_size <= DK_LABEL_LOC) { 19513525Sshidokht cmlb_dbg(CMLB_INFO, cl, "fdisk moved 0x%x 0x%lx", 19523525Sshidokht solaris_offset, solaris_size); 19533525Sshidokht bzero(&cl->cl_g, sizeof (struct dk_geom)); 19543525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc)); 19553525Sshidokht bzero(&cl->cl_map, NDKMAP * (sizeof (struct dk_map))); 19563525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 1957786Slclee } 19583525Sshidokht cl->cl_solaris_offset = solaris_offset; 19593525Sshidokht cl->cl_solaris_size = solaris_size; 1960786Slclee kmem_free(bufp, blocksize); 1961786Slclee return (rval); 1962786Slclee 1963786Slclee #else /* #elif defined(_FIRMWARE_NEEDS_FDISK) */ 1964786Slclee #error "fdisk table presence undetermined for this platform." 1965786Slclee #endif /* #if defined(_NO_FDISK_PRESENT) */ 1966786Slclee } 1967786Slclee 1968786Slclee static void 1969786Slclee cmlb_swap_efi_gpt(efi_gpt_t *e) 1970786Slclee { 1971786Slclee _NOTE(ASSUMING_PROTECTED(*e)) 1972786Slclee e->efi_gpt_Signature = LE_64(e->efi_gpt_Signature); 1973786Slclee e->efi_gpt_Revision = LE_32(e->efi_gpt_Revision); 1974786Slclee e->efi_gpt_HeaderSize = LE_32(e->efi_gpt_HeaderSize); 1975786Slclee e->efi_gpt_HeaderCRC32 = LE_32(e->efi_gpt_HeaderCRC32); 1976786Slclee e->efi_gpt_MyLBA = LE_64(e->efi_gpt_MyLBA); 1977786Slclee e->efi_gpt_AlternateLBA = LE_64(e->efi_gpt_AlternateLBA); 1978786Slclee e->efi_gpt_FirstUsableLBA = LE_64(e->efi_gpt_FirstUsableLBA); 1979786Slclee e->efi_gpt_LastUsableLBA = LE_64(e->efi_gpt_LastUsableLBA); 1980786Slclee UUID_LE_CONVERT(e->efi_gpt_DiskGUID, e->efi_gpt_DiskGUID); 1981786Slclee e->efi_gpt_PartitionEntryLBA = LE_64(e->efi_gpt_PartitionEntryLBA); 1982786Slclee e->efi_gpt_NumberOfPartitionEntries = 1983786Slclee LE_32(e->efi_gpt_NumberOfPartitionEntries); 1984786Slclee e->efi_gpt_SizeOfPartitionEntry = 1985786Slclee LE_32(e->efi_gpt_SizeOfPartitionEntry); 1986786Slclee e->efi_gpt_PartitionEntryArrayCRC32 = 1987786Slclee LE_32(e->efi_gpt_PartitionEntryArrayCRC32); 1988786Slclee } 1989786Slclee 1990786Slclee static void 1991786Slclee cmlb_swap_efi_gpe(int nparts, efi_gpe_t *p) 1992786Slclee { 1993786Slclee int i; 1994786Slclee 1995786Slclee _NOTE(ASSUMING_PROTECTED(*p)) 1996786Slclee for (i = 0; i < nparts; i++) { 1997786Slclee UUID_LE_CONVERT(p[i].efi_gpe_PartitionTypeGUID, 1998786Slclee p[i].efi_gpe_PartitionTypeGUID); 1999786Slclee p[i].efi_gpe_StartingLBA = LE_64(p[i].efi_gpe_StartingLBA); 2000786Slclee p[i].efi_gpe_EndingLBA = LE_64(p[i].efi_gpe_EndingLBA); 2001786Slclee /* PartitionAttrs */ 2002786Slclee } 2003786Slclee } 2004786Slclee 2005786Slclee static int 2006786Slclee cmlb_validate_efi(efi_gpt_t *labp) 2007786Slclee { 2008786Slclee if (labp->efi_gpt_Signature != EFI_SIGNATURE) 2009786Slclee return (EINVAL); 2010786Slclee /* at least 96 bytes in this version of the spec. */ 2011786Slclee if (sizeof (efi_gpt_t) - sizeof (labp->efi_gpt_Reserved2) > 2012786Slclee labp->efi_gpt_HeaderSize) 2013786Slclee return (EINVAL); 2014786Slclee /* this should be 128 bytes */ 2015786Slclee if (labp->efi_gpt_SizeOfPartitionEntry != sizeof (efi_gpe_t)) 2016786Slclee return (EINVAL); 2017786Slclee return (0); 2018786Slclee } 2019786Slclee 20205624Sshidokht /* 20215624Sshidokht * This function returns FALSE if there is a valid MBR signature and no 20225624Sshidokht * partition table entries of type EFI_PMBR (0xEE). Otherwise it returns TRUE. 20235624Sshidokht * 20245624Sshidokht * The EFI spec (1.10 and later) requires having a Protective MBR (PMBR) to 20255624Sshidokht * recognize the disk as GPT partitioned. However, some other OS creates an MBR 20265624Sshidokht * where a PMBR entry is not the only one. Also, if the first block has been 20275624Sshidokht * corrupted, currently best attempt to allow data access would be to try to 20285624Sshidokht * check for GPT headers. Hence in case of more than one partition entry, but 20295624Sshidokht * at least one EFI_PMBR partition type or no valid magic number, the function 20305624Sshidokht * returns TRUE to continue with looking for GPT header. 20315624Sshidokht */ 20325624Sshidokht 20335624Sshidokht static int 20345624Sshidokht cmlb_check_efi_mbr(uchar_t *buf) 20355624Sshidokht { 20365624Sshidokht struct ipart *fdp; 20375624Sshidokht struct mboot *mbp = (struct mboot *)buf; 20385624Sshidokht struct ipart fdisk[FD_NUMPART]; 20395624Sshidokht int i; 20405624Sshidokht 20415624Sshidokht if (LE_16(mbp->signature) != MBB_MAGIC) 20425624Sshidokht return (TRUE); 20435624Sshidokht 20445624Sshidokht bcopy(&mbp->parts[0], fdisk, sizeof (fdisk)); 20455624Sshidokht 20465624Sshidokht for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) { 20475624Sshidokht if (fdp->systid == EFI_PMBR) 20485624Sshidokht return (TRUE); 20495624Sshidokht } 20505624Sshidokht 20515624Sshidokht return (FALSE); 20525624Sshidokht } 20535624Sshidokht 2054786Slclee static int 20553525Sshidokht cmlb_use_efi(struct cmlb_lun *cl, diskaddr_t capacity, int flags, 20563525Sshidokht void *tg_cookie) 2057786Slclee { 2058786Slclee int i; 2059786Slclee int rval = 0; 2060786Slclee efi_gpe_t *partitions; 2061786Slclee uchar_t *buf; 2062786Slclee uint_t lbasize; /* is really how much to read */ 20633525Sshidokht diskaddr_t cap = 0; 2064786Slclee uint_t nparts; 2065786Slclee diskaddr_t gpe_lba; 20661071Sshidokht int iofailed = 0; 20673525Sshidokht struct uuid uuid_type_reserved = EFI_RESERVED; 20683525Sshidokht 20693525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 20703525Sshidokht 20713525Sshidokht if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) { 20723525Sshidokht rval = EINVAL; 20733525Sshidokht goto done_err1; 20743525Sshidokht } 20753525Sshidokht 20763525Sshidokht 20773525Sshidokht lbasize = cl->cl_sys_blocksize; 20783525Sshidokht 20793525Sshidokht cl->cl_reserved = -1; 20803525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 2081786Slclee 2082786Slclee buf = kmem_zalloc(EFI_MIN_ARRAY_SIZE, KM_SLEEP); 20833525Sshidokht 20843525Sshidokht rval = DK_TG_READ(cl, buf, 0, lbasize, tg_cookie); 2085786Slclee if (rval) { 20861071Sshidokht iofailed = 1; 2087786Slclee goto done_err; 2088786Slclee } 2089786Slclee if (((struct dk_label *)buf)->dkl_magic == DKL_MAGIC) { 2090786Slclee /* not ours */ 2091786Slclee rval = ESRCH; 2092786Slclee goto done_err; 2093786Slclee } 2094786Slclee 20955624Sshidokht if (cmlb_check_efi_mbr(buf) == FALSE) { 20965624Sshidokht rval = EINVAL; 20975624Sshidokht goto done_err; 20985624Sshidokht } 20995624Sshidokht 21003525Sshidokht rval = DK_TG_READ(cl, buf, 1, lbasize, tg_cookie); 2101786Slclee if (rval) { 21021071Sshidokht iofailed = 1; 2103786Slclee goto done_err; 2104786Slclee } 2105786Slclee cmlb_swap_efi_gpt((efi_gpt_t *)buf); 2106786Slclee 2107786Slclee if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) { 2108786Slclee /* 2109786Slclee * Couldn't read the primary, try the backup. Our 2110786Slclee * capacity at this point could be based on CHS, so 2111786Slclee * check what the device reports. 2112786Slclee */ 21133525Sshidokht rval = DK_TG_GETCAP(cl, &cap, tg_cookie); 2114786Slclee if (rval) { 21151071Sshidokht iofailed = 1; 2116786Slclee goto done_err; 2117786Slclee } 21183525Sshidokht 21193525Sshidokht /* 21203525Sshidokht * CMLB_OFF_BY_ONE case, we check the next to last block first 21213525Sshidokht * for backup GPT header, otherwise check the last block. 21223525Sshidokht */ 21233525Sshidokht 21243525Sshidokht if ((rval = DK_TG_READ(cl, buf, 21253525Sshidokht cap - ((cl->cl_alter_behavior & CMLB_OFF_BY_ONE) ? 2 : 1), 21263525Sshidokht lbasize, tg_cookie)) 21273525Sshidokht != 0) { 21281071Sshidokht iofailed = 1; 2129786Slclee goto done_err; 2130786Slclee } 2131786Slclee cmlb_swap_efi_gpt((efi_gpt_t *)buf); 21323525Sshidokht 21333525Sshidokht if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) { 21343525Sshidokht 21353525Sshidokht if (!(cl->cl_alter_behavior & CMLB_OFF_BY_ONE)) 21363525Sshidokht goto done_err; 21373525Sshidokht if ((rval = DK_TG_READ(cl, buf, cap - 1, lbasize, 21383525Sshidokht tg_cookie)) != 0) 21393525Sshidokht goto done_err; 21403525Sshidokht cmlb_swap_efi_gpt((efi_gpt_t *)buf); 21413525Sshidokht if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) 21423525Sshidokht goto done_err; 21433525Sshidokht } 21443525Sshidokht if (!(flags & CMLB_SILENT)) 21453525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN, 21463525Sshidokht "primary label corrupt; using backup\n"); 2147786Slclee } 2148786Slclee 2149786Slclee nparts = ((efi_gpt_t *)buf)->efi_gpt_NumberOfPartitionEntries; 2150786Slclee gpe_lba = ((efi_gpt_t *)buf)->efi_gpt_PartitionEntryLBA; 2151786Slclee 21523525Sshidokht rval = DK_TG_READ(cl, buf, gpe_lba, EFI_MIN_ARRAY_SIZE, tg_cookie); 2153786Slclee if (rval) { 21541071Sshidokht iofailed = 1; 2155786Slclee goto done_err; 2156786Slclee } 2157786Slclee partitions = (efi_gpe_t *)buf; 2158786Slclee 2159786Slclee if (nparts > MAXPART) { 2160786Slclee nparts = MAXPART; 2161786Slclee } 2162786Slclee cmlb_swap_efi_gpe(nparts, partitions); 2163786Slclee 21643525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 2165786Slclee 2166786Slclee /* Fill in partition table. */ 2167786Slclee for (i = 0; i < nparts; i++) { 2168786Slclee if (partitions->efi_gpe_StartingLBA != 0 || 2169786Slclee partitions->efi_gpe_EndingLBA != 0) { 21703525Sshidokht cl->cl_map[i].dkl_cylno = 2171786Slclee partitions->efi_gpe_StartingLBA; 21723525Sshidokht cl->cl_map[i].dkl_nblk = 2173786Slclee partitions->efi_gpe_EndingLBA - 2174786Slclee partitions->efi_gpe_StartingLBA + 1; 21753525Sshidokht cl->cl_offset[i] = 2176786Slclee partitions->efi_gpe_StartingLBA; 2177786Slclee } 21783525Sshidokht 21793525Sshidokht if (cl->cl_reserved == -1) { 21803525Sshidokht if (bcmp(&partitions->efi_gpe_PartitionTypeGUID, 21813525Sshidokht &uuid_type_reserved, sizeof (struct uuid)) == 0) { 21823525Sshidokht cl->cl_reserved = i; 21833525Sshidokht } 21843525Sshidokht } 2185786Slclee if (i == WD_NODE) { 2186786Slclee /* 2187786Slclee * minor number 7 corresponds to the whole disk 2188786Slclee */ 21893525Sshidokht cl->cl_map[i].dkl_cylno = 0; 21903525Sshidokht cl->cl_map[i].dkl_nblk = capacity; 21913525Sshidokht cl->cl_offset[i] = 0; 2192786Slclee } 2193786Slclee partitions++; 2194786Slclee } 21953525Sshidokht cl->cl_solaris_offset = 0; 21963525Sshidokht cl->cl_solaris_size = capacity; 21973525Sshidokht cl->cl_f_geometry_is_valid = TRUE; 21983525Sshidokht 21993525Sshidokht /* clear the vtoc label */ 22003525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc)); 22013525Sshidokht 2202786Slclee kmem_free(buf, EFI_MIN_ARRAY_SIZE); 2203786Slclee return (0); 2204786Slclee 2205786Slclee done_err: 2206786Slclee kmem_free(buf, EFI_MIN_ARRAY_SIZE); 22073525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 22083525Sshidokht done_err1: 2209786Slclee /* 2210786Slclee * if we didn't find something that could look like a VTOC 2211786Slclee * and the disk is over 1TB, we know there isn't a valid label. 2212786Slclee * Otherwise let cmlb_uselabel decide what to do. We only 2213786Slclee * want to invalidate this if we're certain the label isn't 2214786Slclee * valid because cmlb_prop_op will now fail, which in turn 2215786Slclee * causes things like opens and stats on the partition to fail. 2216786Slclee */ 22171071Sshidokht if ((capacity > DK_MAX_BLOCKS) && (rval != ESRCH) && !iofailed) { 22183525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 2219786Slclee } 2220786Slclee return (rval); 2221786Slclee } 2222786Slclee 2223786Slclee 2224786Slclee /* 2225786Slclee * Function: cmlb_uselabel 2226786Slclee * 2227786Slclee * Description: Validate the disk label and update the relevant data (geometry, 2228786Slclee * partition, vtoc, and capacity data) in the cmlb_lun struct. 2229786Slclee * Marks the geometry of the unit as being valid. 2230786Slclee * 22313525Sshidokht * Arguments: cl: unit struct. 2232786Slclee * dk_label: disk label 2233786Slclee * 2234786Slclee * Return Code: CMLB_LABEL_IS_VALID: Label read from disk is OK; geometry, 2235786Slclee * partition, vtoc, and capacity data are good. 2236786Slclee * 2237786Slclee * CMLB_LABEL_IS_INVALID: Magic number or checksum error in the 2238786Slclee * label; or computed capacity does not jibe with capacity 2239786Slclee * reported from the READ CAPACITY command. 2240786Slclee * 2241786Slclee * Context: Kernel thread only (can sleep). 2242786Slclee */ 2243786Slclee static int 22443525Sshidokht cmlb_uselabel(struct cmlb_lun *cl, struct dk_label *labp, int flags) 2245786Slclee { 2246786Slclee short *sp; 2247786Slclee short sum; 2248786Slclee short count; 2249786Slclee int label_error = CMLB_LABEL_IS_VALID; 2250786Slclee int i; 2251786Slclee diskaddr_t label_capacity; 2252786Slclee int part_end; 2253786Slclee diskaddr_t track_capacity; 2254786Slclee #if defined(_SUNOS_VTOC_16) 2255786Slclee struct dkl_partition *vpartp; 2256786Slclee #endif 22573525Sshidokht ASSERT(cl != NULL); 22583525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 2259786Slclee 2260786Slclee /* Validate the magic number of the label. */ 2261786Slclee if (labp->dkl_magic != DKL_MAGIC) { 2262786Slclee #if defined(__sparc) 22633525Sshidokht if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) { 22643525Sshidokht if (!(flags & CMLB_SILENT)) 22653525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), 22663525Sshidokht CE_WARN, 22673525Sshidokht "Corrupt label; wrong magic number\n"); 2268786Slclee } 2269786Slclee #endif 2270786Slclee return (CMLB_LABEL_IS_INVALID); 2271786Slclee } 2272786Slclee 2273786Slclee /* Validate the checksum of the label. */ 2274786Slclee sp = (short *)labp; 2275786Slclee sum = 0; 2276786Slclee count = sizeof (struct dk_label) / sizeof (short); 2277786Slclee while (count--) { 2278786Slclee sum ^= *sp++; 2279786Slclee } 2280786Slclee 2281786Slclee if (sum != 0) { 2282786Slclee #if defined(_SUNOS_VTOC_16) 22833525Sshidokht if (!ISCD(cl)) { 2284786Slclee #elif defined(_SUNOS_VTOC_8) 22853525Sshidokht if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) { 2286786Slclee #endif 22873525Sshidokht if (!(flags & CMLB_SILENT)) 22883525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), 22893525Sshidokht CE_WARN, 22903525Sshidokht "Corrupt label - label checksum failed\n"); 2291786Slclee } 2292786Slclee return (CMLB_LABEL_IS_INVALID); 2293786Slclee } 2294786Slclee 2295786Slclee 2296786Slclee /* 2297786Slclee * Fill in geometry structure with data from label. 2298786Slclee */ 22993525Sshidokht bzero(&cl->cl_g, sizeof (struct dk_geom)); 23003525Sshidokht cl->cl_g.dkg_ncyl = labp->dkl_ncyl; 23013525Sshidokht cl->cl_g.dkg_acyl = labp->dkl_acyl; 23023525Sshidokht cl->cl_g.dkg_bcyl = 0; 23033525Sshidokht cl->cl_g.dkg_nhead = labp->dkl_nhead; 23043525Sshidokht cl->cl_g.dkg_nsect = labp->dkl_nsect; 23053525Sshidokht cl->cl_g.dkg_intrlv = labp->dkl_intrlv; 2306786Slclee 2307786Slclee #if defined(_SUNOS_VTOC_8) 23083525Sshidokht cl->cl_g.dkg_gap1 = labp->dkl_gap1; 23093525Sshidokht cl->cl_g.dkg_gap2 = labp->dkl_gap2; 23103525Sshidokht cl->cl_g.dkg_bhead = labp->dkl_bhead; 2311786Slclee #endif 2312786Slclee #if defined(_SUNOS_VTOC_16) 23133525Sshidokht cl->cl_dkg_skew = labp->dkl_skew; 2314786Slclee #endif 2315786Slclee 2316786Slclee #if defined(__i386) || defined(__amd64) 23173525Sshidokht cl->cl_g.dkg_apc = labp->dkl_apc; 2318786Slclee #endif 2319786Slclee 2320786Slclee /* 2321786Slclee * Currently we rely on the values in the label being accurate. If 2322786Slclee * dkl_rpm or dkl_pcly are zero in the label, use a default value. 2323786Slclee * 2324786Slclee * Note: In the future a MODE SENSE may be used to retrieve this data, 2325786Slclee * although this command is optional in SCSI-2. 2326786Slclee */ 23273525Sshidokht cl->cl_g.dkg_rpm = (labp->dkl_rpm != 0) ? labp->dkl_rpm : 3600; 23283525Sshidokht cl->cl_g.dkg_pcyl = (labp->dkl_pcyl != 0) ? labp->dkl_pcyl : 23293525Sshidokht (cl->cl_g.dkg_ncyl + cl->cl_g.dkg_acyl); 2330786Slclee 2331786Slclee /* 2332786Slclee * The Read and Write reinstruct values may not be valid 2333786Slclee * for older disks. 2334786Slclee */ 23353525Sshidokht cl->cl_g.dkg_read_reinstruct = labp->dkl_read_reinstruct; 23363525Sshidokht cl->cl_g.dkg_write_reinstruct = labp->dkl_write_reinstruct; 2337786Slclee 2338786Slclee /* Fill in partition table. */ 2339786Slclee #if defined(_SUNOS_VTOC_8) 2340786Slclee for (i = 0; i < NDKMAP; i++) { 23413525Sshidokht cl->cl_map[i].dkl_cylno = labp->dkl_map[i].dkl_cylno; 23423525Sshidokht cl->cl_map[i].dkl_nblk = labp->dkl_map[i].dkl_nblk; 2343786Slclee } 2344786Slclee #endif 2345786Slclee #if defined(_SUNOS_VTOC_16) 2346786Slclee vpartp = labp->dkl_vtoc.v_part; 2347786Slclee track_capacity = labp->dkl_nhead * labp->dkl_nsect; 2348786Slclee 23493525Sshidokht /* Prevent divide by zero */ 23503525Sshidokht if (track_capacity == 0) { 23513525Sshidokht if (!(flags & CMLB_SILENT)) 23523525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN, 23533525Sshidokht "Corrupt label - zero nhead or nsect value\n"); 23543525Sshidokht 23553525Sshidokht return (CMLB_LABEL_IS_INVALID); 23563525Sshidokht } 23573525Sshidokht 2358786Slclee for (i = 0; i < NDKMAP; i++, vpartp++) { 23593525Sshidokht cl->cl_map[i].dkl_cylno = vpartp->p_start / track_capacity; 23603525Sshidokht cl->cl_map[i].dkl_nblk = vpartp->p_size; 2361786Slclee } 2362786Slclee #endif 2363786Slclee 2364786Slclee /* Fill in VTOC Structure. */ 23653525Sshidokht bcopy(&labp->dkl_vtoc, &cl->cl_vtoc, sizeof (struct dk_vtoc)); 2366786Slclee #if defined(_SUNOS_VTOC_8) 2367786Slclee /* 2368786Slclee * The 8-slice vtoc does not include the ascii label; save it into 2369786Slclee * the device's soft state structure here. 2370786Slclee */ 23713525Sshidokht bcopy(labp->dkl_asciilabel, cl->cl_asciilabel, LEN_DKL_ASCII); 2372786Slclee #endif 2373786Slclee 2374786Slclee /* Now look for a valid capacity. */ 23753525Sshidokht track_capacity = (cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect); 23763525Sshidokht label_capacity = (cl->cl_g.dkg_ncyl * track_capacity); 23773525Sshidokht 23783525Sshidokht if (cl->cl_g.dkg_acyl) { 2379786Slclee #if defined(__i386) || defined(__amd64) 2380786Slclee /* we may have > 1 alts cylinder */ 23813525Sshidokht label_capacity += (track_capacity * cl->cl_g.dkg_acyl); 2382786Slclee #else 2383786Slclee label_capacity += track_capacity; 2384786Slclee #endif 2385786Slclee } 2386786Slclee 2387786Slclee /* 23883525Sshidokht * Force check here to ensure the computed capacity is valid. 23893525Sshidokht * If capacity is zero, it indicates an invalid label and 23903525Sshidokht * we should abort updating the relevant data then. 23913525Sshidokht */ 23923525Sshidokht if (label_capacity == 0) { 23933525Sshidokht if (!(flags & CMLB_SILENT)) 23943525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN, 23953525Sshidokht "Corrupt label - no valid capacity could be " 23963525Sshidokht "retrieved\n"); 23973525Sshidokht 23983525Sshidokht return (CMLB_LABEL_IS_INVALID); 23993525Sshidokht } 24003525Sshidokht 24013525Sshidokht /* Mark the geometry as valid. */ 24023525Sshidokht cl->cl_f_geometry_is_valid = TRUE; 24033525Sshidokht 24043525Sshidokht /* 2405786Slclee * if we got invalidated when mutex exit and entered again, 2406786Slclee * if blockcount different than when we came in, need to 2407786Slclee * retry from beginning of cmlb_validate_geometry. 2408786Slclee * revisit this on next phase of utilizing this for 2409786Slclee * sd. 2410786Slclee */ 2411786Slclee 24123525Sshidokht if (label_capacity <= cl->cl_blockcount) { 2413786Slclee #if defined(_SUNOS_VTOC_8) 2414786Slclee /* 2415786Slclee * We can't let this happen on drives that are subdivided 2416786Slclee * into logical disks (i.e., that have an fdisk table). 24173525Sshidokht * The cl_blockcount field should always hold the full media 2418786Slclee * size in sectors, period. This code would overwrite 24193525Sshidokht * cl_blockcount with the size of the Solaris fdisk partition. 2420786Slclee */ 24213525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 2422786Slclee "cmlb_uselabel: Label %d blocks; Drive %d blocks\n", 24233525Sshidokht label_capacity, cl->cl_blockcount); 24243525Sshidokht cl->cl_solaris_size = label_capacity; 2425786Slclee 2426786Slclee #endif /* defined(_SUNOS_VTOC_8) */ 2427786Slclee goto done; 2428786Slclee } 2429786Slclee 24303525Sshidokht if (ISCD(cl)) { 2431786Slclee /* For CDROMs, we trust that the data in the label is OK. */ 2432786Slclee #if defined(_SUNOS_VTOC_8) 2433786Slclee for (i = 0; i < NDKMAP; i++) { 2434786Slclee part_end = labp->dkl_nhead * labp->dkl_nsect * 2435786Slclee labp->dkl_map[i].dkl_cylno + 2436786Slclee labp->dkl_map[i].dkl_nblk - 1; 2437786Slclee 2438786Slclee if ((labp->dkl_map[i].dkl_nblk) && 24393525Sshidokht (part_end > cl->cl_blockcount)) { 24403525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 2441786Slclee break; 2442786Slclee } 2443786Slclee } 2444786Slclee #endif 2445786Slclee #if defined(_SUNOS_VTOC_16) 2446786Slclee vpartp = &(labp->dkl_vtoc.v_part[0]); 2447786Slclee for (i = 0; i < NDKMAP; i++, vpartp++) { 2448786Slclee part_end = vpartp->p_start + vpartp->p_size; 2449786Slclee if ((vpartp->p_size > 0) && 24503525Sshidokht (part_end > cl->cl_blockcount)) { 24513525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 2452786Slclee break; 2453786Slclee } 2454786Slclee } 2455786Slclee #endif 2456786Slclee } else { 24573525Sshidokht /* label_capacity > cl->cl_blockcount */ 24583525Sshidokht if (!(flags & CMLB_SILENT)) { 24593525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN, 24603525Sshidokht "Corrupt label - bad geometry\n"); 24613525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_CONT, 24623525Sshidokht "Label says %llu blocks; Drive says %llu blocks\n", 24633525Sshidokht label_capacity, cl->cl_blockcount); 24643525Sshidokht } 24653525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 2466786Slclee label_error = CMLB_LABEL_IS_INVALID; 2467786Slclee } 2468786Slclee 2469786Slclee done: 2470786Slclee 24713525Sshidokht cmlb_dbg(CMLB_INFO, cl, "cmlb_uselabel: (label geometry)\n"); 24723525Sshidokht cmlb_dbg(CMLB_INFO, cl, 2473786Slclee " ncyl: %d; acyl: %d; nhead: %d; nsect: %d\n", 24743525Sshidokht cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl, 24753525Sshidokht cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect); 24763525Sshidokht 24773525Sshidokht cmlb_dbg(CMLB_INFO, cl, 2478786Slclee " label_capacity: %d; intrlv: %d; rpm: %d\n", 24793525Sshidokht cl->cl_blockcount, cl->cl_g.dkg_intrlv, cl->cl_g.dkg_rpm); 24803525Sshidokht cmlb_dbg(CMLB_INFO, cl, " wrt_reinstr: %d; rd_reinstr: %d\n", 24813525Sshidokht cl->cl_g.dkg_write_reinstruct, cl->cl_g.dkg_read_reinstruct); 24823525Sshidokht 24833525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 2484786Slclee 2485786Slclee return (label_error); 2486786Slclee } 2487786Slclee 2488786Slclee 2489786Slclee /* 2490786Slclee * Function: cmlb_build_default_label 2491786Slclee * 2492786Slclee * Description: Generate a default label for those devices that do not have 2493786Slclee * one, e.g., new media, removable cartridges, etc.. 2494786Slclee * 2495786Slclee * Context: Kernel thread only 2496786Slclee */ 24973525Sshidokht /*ARGSUSED*/ 2498786Slclee static void 24993525Sshidokht cmlb_build_default_label(struct cmlb_lun *cl, void *tg_cookie) 2500786Slclee { 2501786Slclee #if defined(_SUNOS_VTOC_16) 2502786Slclee uint_t phys_spc; 2503786Slclee uint_t disksize; 25043525Sshidokht struct dk_geom cl_g; 25053525Sshidokht diskaddr_t capacity; 2506786Slclee #endif 2507786Slclee 25083525Sshidokht ASSERT(cl != NULL); 25093525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 2510786Slclee 2511786Slclee #if defined(_SUNOS_VTOC_8) 2512786Slclee /* 2513786Slclee * Note: This is a legacy check for non-removable devices on VTOC_8 2514786Slclee * only. This may be a valid check for VTOC_16 as well. 25153525Sshidokht * Once we understand why there is this difference between SPARC and 25163525Sshidokht * x86 platform, we could remove this legacy check. 2517786Slclee */ 25183525Sshidokht if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) { 2519786Slclee return; 2520786Slclee } 2521786Slclee #endif 2522786Slclee 25233525Sshidokht bzero(&cl->cl_g, sizeof (struct dk_geom)); 25243525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc)); 25253525Sshidokht bzero(&cl->cl_map, NDKMAP * (sizeof (struct dk_map))); 2526786Slclee 2527786Slclee #if defined(_SUNOS_VTOC_8) 2528786Slclee 2529786Slclee /* 2530786Slclee * It's a REMOVABLE media, therefore no label (on sparc, anyway). 2531786Slclee * But it is still necessary to set up various geometry information, 2532786Slclee * and we are doing this here. 2533786Slclee */ 2534786Slclee 2535786Slclee /* 2536786Slclee * For the rpm, we use the minimum for the disk. For the head, cyl, 2537786Slclee * and number of sector per track, if the capacity <= 1GB, head = 64, 2538786Slclee * sect = 32. else head = 255, sect 63 Note: the capacity should be 2539786Slclee * equal to C*H*S values. This will cause some truncation of size due 2540786Slclee * to round off errors. For CD-ROMs, this truncation can have adverse 2541786Slclee * side effects, so returning ncyl and nhead as 1. The nsect will 2542786Slclee * overflow for most of CD-ROMs as nsect is of type ushort. (4190569) 2543786Slclee */ 25443525Sshidokht cl->cl_solaris_size = cl->cl_blockcount; 25453525Sshidokht if (ISCD(cl)) { 2546786Slclee tg_attribute_t tgattribute; 2547786Slclee int is_writable; 2548786Slclee /* 2549786Slclee * Preserve the old behavior for non-writable 2550786Slclee * medias. Since dkg_nsect is a ushort, it 2551786Slclee * will lose bits as cdroms have more than 2552786Slclee * 65536 sectors. So if we recalculate 2553786Slclee * capacity, it will become much shorter. 2554786Slclee * But the dkg_* information is not 2555786Slclee * used for CDROMs so it is OK. But for 2556786Slclee * Writable CDs we need this information 2557786Slclee * to be valid (for newfs say). So we 2558786Slclee * make nsect and nhead > 1 that way 2559786Slclee * nsect can still stay within ushort limit 2560786Slclee * without losing any bits. 2561786Slclee */ 2562786Slclee 2563786Slclee bzero(&tgattribute, sizeof (tg_attribute_t)); 2564786Slclee 25653525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 25663525Sshidokht is_writable = 25673525Sshidokht (DK_TG_GETATTRIBUTE(cl, &tgattribute, tg_cookie) == 0) ? 2568786Slclee tgattribute.media_is_writable : 1; 25693525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 2570786Slclee 2571786Slclee if (is_writable) { 25723525Sshidokht cl->cl_g.dkg_nhead = 64; 25733525Sshidokht cl->cl_g.dkg_nsect = 32; 25743525Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount / (64 * 32); 25753525Sshidokht cl->cl_solaris_size = cl->cl_g.dkg_ncyl * 25763525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect; 2577786Slclee } else { 25783525Sshidokht cl->cl_g.dkg_ncyl = 1; 25793525Sshidokht cl->cl_g.dkg_nhead = 1; 25803525Sshidokht cl->cl_g.dkg_nsect = cl->cl_blockcount; 2581786Slclee } 2582786Slclee } else { 25833525Sshidokht if (cl->cl_blockcount <= 0x1000) { 2584786Slclee /* unlabeled SCSI floppy device */ 25853525Sshidokht cl->cl_g.dkg_nhead = 2; 25863525Sshidokht cl->cl_g.dkg_ncyl = 80; 25873525Sshidokht cl->cl_g.dkg_nsect = cl->cl_blockcount / (2 * 80); 25883525Sshidokht } else if (cl->cl_blockcount <= 0x200000) { 25893525Sshidokht cl->cl_g.dkg_nhead = 64; 25903525Sshidokht cl->cl_g.dkg_nsect = 32; 25913525Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount / (64 * 32); 2592786Slclee } else { 25933525Sshidokht cl->cl_g.dkg_nhead = 255; 2594*6124Sshidokht 2595*6124Sshidokht cl->cl_g.dkg_nsect = ((cl->cl_blockcount + 2596*6124Sshidokht (UINT16_MAX * 255 * 63) - 1) / 2597*6124Sshidokht (UINT16_MAX * 255 * 63)) * 63; 2598*6124Sshidokht 2599*6124Sshidokht if (cl->cl_g.dkg_nsect == 0) 2600*6124Sshidokht cl->cl_g.dkg_nsect = (UINT16_MAX / 63) * 63; 2601*6124Sshidokht 2602*6124Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount / 2603*6124Sshidokht (255 * cl->cl_g.dkg_nsect); 2604786Slclee } 2605*6124Sshidokht 26063525Sshidokht cl->cl_solaris_size = 26073525Sshidokht cl->cl_g.dkg_ncyl * cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect; 2608786Slclee 2609786Slclee } 2610786Slclee 26113525Sshidokht cl->cl_g.dkg_acyl = 0; 26123525Sshidokht cl->cl_g.dkg_bcyl = 0; 26133525Sshidokht cl->cl_g.dkg_rpm = 200; 26143525Sshidokht cl->cl_asciilabel[0] = '\0'; 26153525Sshidokht cl->cl_g.dkg_pcyl = cl->cl_g.dkg_ncyl; 26163525Sshidokht 26173525Sshidokht cl->cl_map[0].dkl_cylno = 0; 26183525Sshidokht cl->cl_map[0].dkl_nblk = cl->cl_solaris_size; 26193525Sshidokht 26203525Sshidokht cl->cl_map[2].dkl_cylno = 0; 26213525Sshidokht cl->cl_map[2].dkl_nblk = cl->cl_solaris_size; 2622786Slclee 2623786Slclee #elif defined(_SUNOS_VTOC_16) 2624786Slclee 26253525Sshidokht if (cl->cl_solaris_size == 0) { 2626786Slclee /* 2627786Slclee * Got fdisk table but no solaris entry therefore 2628786Slclee * don't create a default label 2629786Slclee */ 26303525Sshidokht cl->cl_f_geometry_is_valid = TRUE; 2631786Slclee return; 2632786Slclee } 2633786Slclee 2634786Slclee /* 2635786Slclee * For CDs we continue to use the physical geometry to calculate 2636786Slclee * number of cylinders. All other devices must convert the 2637786Slclee * physical geometry (cmlb_geom) to values that will fit 2638786Slclee * in a dk_geom structure. 2639786Slclee */ 26403525Sshidokht if (ISCD(cl)) { 26413525Sshidokht phys_spc = cl->cl_pgeom.g_nhead * cl->cl_pgeom.g_nsect; 2642786Slclee } else { 2643786Slclee /* Convert physical geometry to disk geometry */ 26443525Sshidokht bzero(&cl_g, sizeof (struct dk_geom)); 26453525Sshidokht 26463525Sshidokht /* 26473525Sshidokht * Refer to comments related to off-by-1 at the 26483525Sshidokht * header of this file. 26493525Sshidokht * Before caculating geometry, capacity should be 26503525Sshidokht * decreased by 1. 26513525Sshidokht */ 26523525Sshidokht 26533525Sshidokht if (cl->cl_alter_behavior & CMLB_OFF_BY_ONE) 26543525Sshidokht capacity = cl->cl_blockcount - 1; 26553525Sshidokht else 26563525Sshidokht capacity = cl->cl_blockcount; 26573525Sshidokht 26583525Sshidokht 26593525Sshidokht cmlb_convert_geometry(capacity, &cl_g); 26603525Sshidokht bcopy(&cl_g, &cl->cl_g, sizeof (cl->cl_g)); 26613525Sshidokht phys_spc = cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect; 2662786Slclee } 2663786Slclee 26643525Sshidokht ASSERT(phys_spc != 0); 26653525Sshidokht cl->cl_g.dkg_pcyl = cl->cl_solaris_size / phys_spc; 26665084Sjohnlev if (cl->cl_alter_behavior & CMLB_FAKE_LABEL_ONE_PARTITION) { 26675084Sjohnlev /* disable devid */ 26685084Sjohnlev cl->cl_g.dkg_ncyl = cl->cl_g.dkg_pcyl; 26695084Sjohnlev disksize = cl->cl_solaris_size; 26705084Sjohnlev } else { 26715084Sjohnlev cl->cl_g.dkg_acyl = DK_ACYL; 26725084Sjohnlev cl->cl_g.dkg_ncyl = cl->cl_g.dkg_pcyl - DK_ACYL; 26735084Sjohnlev disksize = cl->cl_g.dkg_ncyl * phys_spc; 26745084Sjohnlev } 26753525Sshidokht 26763525Sshidokht if (ISCD(cl)) { 2677786Slclee /* 2678786Slclee * CD's don't use the "heads * sectors * cyls"-type of 2679786Slclee * geometry, but instead use the entire capacity of the media. 2680786Slclee */ 26813525Sshidokht disksize = cl->cl_solaris_size; 26823525Sshidokht cl->cl_g.dkg_nhead = 1; 26833525Sshidokht cl->cl_g.dkg_nsect = 1; 26843525Sshidokht cl->cl_g.dkg_rpm = 26853525Sshidokht (cl->cl_pgeom.g_rpm == 0) ? 200 : cl->cl_pgeom.g_rpm; 26863525Sshidokht 26873525Sshidokht cl->cl_vtoc.v_part[0].p_start = 0; 26883525Sshidokht cl->cl_vtoc.v_part[0].p_size = disksize; 26893525Sshidokht cl->cl_vtoc.v_part[0].p_tag = V_BACKUP; 26903525Sshidokht cl->cl_vtoc.v_part[0].p_flag = V_UNMNT; 26913525Sshidokht 26923525Sshidokht cl->cl_map[0].dkl_cylno = 0; 26933525Sshidokht cl->cl_map[0].dkl_nblk = disksize; 26943525Sshidokht cl->cl_offset[0] = 0; 2695786Slclee 2696786Slclee } else { 2697786Slclee /* 2698786Slclee * Hard disks and removable media cartridges 2699786Slclee */ 27003525Sshidokht cl->cl_g.dkg_rpm = 27013525Sshidokht (cl->cl_pgeom.g_rpm == 0) ? 3600: cl->cl_pgeom.g_rpm; 27023525Sshidokht cl->cl_vtoc.v_sectorsz = cl->cl_sys_blocksize; 2703786Slclee 2704786Slclee /* Add boot slice */ 27053525Sshidokht cl->cl_vtoc.v_part[8].p_start = 0; 27063525Sshidokht cl->cl_vtoc.v_part[8].p_size = phys_spc; 27073525Sshidokht cl->cl_vtoc.v_part[8].p_tag = V_BOOT; 27083525Sshidokht cl->cl_vtoc.v_part[8].p_flag = V_UNMNT; 27093525Sshidokht 27103525Sshidokht cl->cl_map[8].dkl_cylno = 0; 27113525Sshidokht cl->cl_map[8].dkl_nblk = phys_spc; 27123525Sshidokht cl->cl_offset[8] = 0; 27133525Sshidokht 27143525Sshidokht if ((cl->cl_alter_behavior & 2715786Slclee CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT) && 27163525Sshidokht cl->cl_device_type == DTYPE_DIRECT) { 27173525Sshidokht cl->cl_vtoc.v_part[9].p_start = phys_spc; 27183525Sshidokht cl->cl_vtoc.v_part[9].p_size = 2 * phys_spc; 27193525Sshidokht cl->cl_vtoc.v_part[9].p_tag = V_ALTSCTR; 27203525Sshidokht cl->cl_vtoc.v_part[9].p_flag = 0; 27213525Sshidokht 27223525Sshidokht cl->cl_map[9].dkl_cylno = 1; 27233525Sshidokht cl->cl_map[9].dkl_nblk = 2 * phys_spc; 27243525Sshidokht cl->cl_offset[9] = phys_spc; 2725786Slclee } 2726786Slclee } 2727786Slclee 27283525Sshidokht cl->cl_g.dkg_apc = 0; 27293525Sshidokht cl->cl_vtoc.v_nparts = V_NUMPAR; 27303525Sshidokht cl->cl_vtoc.v_version = V_VERSION; 2731786Slclee 2732786Slclee /* Add backup slice */ 27333525Sshidokht cl->cl_vtoc.v_part[2].p_start = 0; 27343525Sshidokht cl->cl_vtoc.v_part[2].p_size = disksize; 27353525Sshidokht cl->cl_vtoc.v_part[2].p_tag = V_BACKUP; 27363525Sshidokht cl->cl_vtoc.v_part[2].p_flag = V_UNMNT; 27373525Sshidokht 27383525Sshidokht cl->cl_map[2].dkl_cylno = 0; 27393525Sshidokht cl->cl_map[2].dkl_nblk = disksize; 27403525Sshidokht cl->cl_offset[2] = 0; 27413525Sshidokht 27425084Sjohnlev /* 27435084Sjohnlev * single slice (s0) covering the entire disk 27445084Sjohnlev */ 27455084Sjohnlev if (cl->cl_alter_behavior & CMLB_FAKE_LABEL_ONE_PARTITION) { 27465084Sjohnlev cl->cl_vtoc.v_part[0].p_start = 0; 27475084Sjohnlev cl->cl_vtoc.v_part[0].p_tag = V_UNASSIGNED; 27485084Sjohnlev cl->cl_vtoc.v_part[0].p_flag = 0; 27495084Sjohnlev cl->cl_vtoc.v_part[0].p_size = disksize; 27505084Sjohnlev cl->cl_map[0].dkl_cylno = 0; 27515084Sjohnlev cl->cl_map[0].dkl_nblk = disksize; 27525084Sjohnlev cl->cl_offset[0] = 0; 27535084Sjohnlev } 27545084Sjohnlev 27553525Sshidokht (void) sprintf(cl->cl_vtoc.v_asciilabel, "DEFAULT cyl %d alt %d" 27563525Sshidokht " hd %d sec %d", cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl, 27573525Sshidokht cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect); 2758786Slclee 2759786Slclee #else 2760786Slclee #error "No VTOC format defined." 2761786Slclee #endif 2762786Slclee 27633525Sshidokht cl->cl_g.dkg_read_reinstruct = 0; 27643525Sshidokht cl->cl_g.dkg_write_reinstruct = 0; 27653525Sshidokht 27663525Sshidokht cl->cl_g.dkg_intrlv = 1; 27673525Sshidokht 27683525Sshidokht cl->cl_vtoc.v_sanity = VTOC_SANE; 27693525Sshidokht 27703525Sshidokht cl->cl_f_geometry_is_valid = TRUE; 27713525Sshidokht cl->cl_vtoc_label_is_from_media = 0; 27723525Sshidokht 27733525Sshidokht cmlb_dbg(CMLB_INFO, cl, 2774786Slclee "cmlb_build_default_label: Default label created: " 2775786Slclee "cyl: %d\tacyl: %d\tnhead: %d\tnsect: %d\tcap: %d\n", 27763525Sshidokht cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl, cl->cl_g.dkg_nhead, 27773525Sshidokht cl->cl_g.dkg_nsect, cl->cl_blockcount); 2778786Slclee } 2779786Slclee 2780786Slclee 2781786Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 2782786Slclee /* 2783786Slclee * Max CHS values, as they are encoded into bytes, for 1022/254/63 2784786Slclee */ 2785786Slclee #define LBA_MAX_SECT (63 | ((1022 & 0x300) >> 2)) 2786786Slclee #define LBA_MAX_CYL (1022 & 0xFF) 2787786Slclee #define LBA_MAX_HEAD (254) 2788786Slclee 2789786Slclee 2790786Slclee /* 2791786Slclee * Function: cmlb_has_max_chs_vals 2792786Slclee * 2793786Slclee * Description: Return TRUE if Cylinder-Head-Sector values are all at maximum. 2794786Slclee * 2795786Slclee * Arguments: fdp - ptr to CHS info 2796786Slclee * 2797786Slclee * Return Code: True or false 2798786Slclee * 2799786Slclee * Context: Any. 2800786Slclee */ 2801786Slclee static int 2802786Slclee cmlb_has_max_chs_vals(struct ipart *fdp) 2803786Slclee { 2804786Slclee return ((fdp->begcyl == LBA_MAX_CYL) && 2805786Slclee (fdp->beghead == LBA_MAX_HEAD) && 2806786Slclee (fdp->begsect == LBA_MAX_SECT) && 2807786Slclee (fdp->endcyl == LBA_MAX_CYL) && 2808786Slclee (fdp->endhead == LBA_MAX_HEAD) && 2809786Slclee (fdp->endsect == LBA_MAX_SECT)); 2810786Slclee } 2811786Slclee #endif 2812786Slclee 2813786Slclee /* 2814786Slclee * Function: cmlb_dkio_get_geometry 2815786Slclee * 2816786Slclee * Description: This routine is the driver entry point for handling user 2817786Slclee * requests to get the device geometry (DKIOCGGEOM). 2818786Slclee * 2819786Slclee * Arguments: 28203525Sshidokht * arg pointer to user provided dk_geom structure specifying 2821786Slclee * the controller's notion of the current geometry. 28223525Sshidokht * 28233525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 28243525Sshidokht * directly from the mode argument of ioctl(). 28253525Sshidokht * 28263525Sshidokht * tg_cookie cookie from target driver to be passed back to target 28273525Sshidokht * driver when we call back to it through tg_ops. 2828786Slclee * 2829786Slclee * Return Code: 0 2830786Slclee * EFAULT 2831786Slclee * ENXIO 2832786Slclee * EIO 2833786Slclee */ 2834786Slclee static int 28353525Sshidokht cmlb_dkio_get_geometry(struct cmlb_lun *cl, caddr_t arg, int flag, 28363525Sshidokht void *tg_cookie) 2837786Slclee { 2838786Slclee struct dk_geom *tmp_geom = NULL; 2839786Slclee int rval = 0; 2840786Slclee 2841786Slclee /* 2842786Slclee * cmlb_validate_geometry does not spin a disk up 28433525Sshidokht * if it was spcl down. We need to make sure it 2844786Slclee * is ready. 2845786Slclee */ 28463525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 28473525Sshidokht rval = cmlb_validate_geometry(cl, 1, 0, tg_cookie); 2848786Slclee #if defined(_SUNOS_VTOC_8) 2849786Slclee if (rval == EINVAL && 28503525Sshidokht cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8) { 2851786Slclee /* 2852786Slclee * This is to return a default label geometry even when we 2853786Slclee * do not really assume a default label for the device. 2854786Slclee * dad driver utilizes this. 2855786Slclee */ 28563525Sshidokht if (cl->cl_blockcount <= DK_MAX_BLOCKS) { 28573525Sshidokht cmlb_setup_default_geometry(cl, tg_cookie); 2858786Slclee rval = 0; 2859786Slclee } 2860786Slclee } 2861786Slclee #endif 2862786Slclee if (rval) { 28633525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 2864786Slclee return (rval); 2865786Slclee } 2866786Slclee 2867786Slclee #if defined(__i386) || defined(__amd64) 28683525Sshidokht if (cl->cl_solaris_size == 0) { 28693525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 2870786Slclee return (EIO); 2871786Slclee } 2872786Slclee #endif 2873786Slclee 2874786Slclee /* 2875786Slclee * Make a local copy of the soft state geometry to avoid some potential 2876786Slclee * race conditions associated with holding the mutex and updating the 2877786Slclee * write_reinstruct value 2878786Slclee */ 2879786Slclee tmp_geom = kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP); 28803525Sshidokht bcopy(&cl->cl_g, tmp_geom, sizeof (struct dk_geom)); 2881786Slclee 2882786Slclee if (tmp_geom->dkg_write_reinstruct == 0) { 2883786Slclee tmp_geom->dkg_write_reinstruct = 2884786Slclee (int)((int)(tmp_geom->dkg_nsect * tmp_geom->dkg_rpm * 2885786Slclee cmlb_rot_delay) / (int)60000); 2886786Slclee } 28873525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 2888786Slclee 2889786Slclee rval = ddi_copyout(tmp_geom, (void *)arg, sizeof (struct dk_geom), 2890786Slclee flag); 2891786Slclee if (rval != 0) { 2892786Slclee rval = EFAULT; 2893786Slclee } 2894786Slclee 2895786Slclee kmem_free(tmp_geom, sizeof (struct dk_geom)); 2896786Slclee return (rval); 2897786Slclee 2898786Slclee } 2899786Slclee 2900786Slclee 2901786Slclee /* 2902786Slclee * Function: cmlb_dkio_set_geometry 2903786Slclee * 2904786Slclee * Description: This routine is the driver entry point for handling user 2905786Slclee * requests to set the device geometry (DKIOCSGEOM). The actual 2906786Slclee * device geometry is not updated, just the driver "notion" of it. 2907786Slclee * 2908786Slclee * Arguments: 29093525Sshidokht * arg pointer to user provided dk_geom structure used to set 2910786Slclee * the controller's notion of the current geometry. 29113525Sshidokht * 29123525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 29133525Sshidokht * directly from the mode argument of ioctl(). 29143525Sshidokht * 29153525Sshidokht * tg_cookie cookie from target driver to be passed back to target 29163525Sshidokht * driver when we call back to it through tg_ops. 2917786Slclee * 2918786Slclee * Return Code: 0 2919786Slclee * EFAULT 2920786Slclee * ENXIO 2921786Slclee * EIO 2922786Slclee */ 2923786Slclee static int 29243525Sshidokht cmlb_dkio_set_geometry(struct cmlb_lun *cl, caddr_t arg, int flag) 2925786Slclee { 2926786Slclee struct dk_geom *tmp_geom; 2927786Slclee struct dk_map *lp; 2928786Slclee int rval = 0; 2929786Slclee int i; 2930786Slclee 2931786Slclee 2932786Slclee #if defined(__i386) || defined(__amd64) 29333525Sshidokht if (cl->cl_solaris_size == 0) { 2934786Slclee return (EIO); 2935786Slclee } 2936786Slclee #endif 2937786Slclee /* 2938786Slclee * We need to copy the user specified geometry into local 2939786Slclee * storage and then update the softstate. We don't want to hold 2940786Slclee * the mutex and copyin directly from the user to the soft state 2941786Slclee */ 2942786Slclee tmp_geom = (struct dk_geom *) 2943786Slclee kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP); 2944786Slclee rval = ddi_copyin(arg, tmp_geom, sizeof (struct dk_geom), flag); 2945786Slclee if (rval != 0) { 2946786Slclee kmem_free(tmp_geom, sizeof (struct dk_geom)); 2947786Slclee return (EFAULT); 2948786Slclee } 2949786Slclee 29503525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 29513525Sshidokht bcopy(tmp_geom, &cl->cl_g, sizeof (struct dk_geom)); 2952786Slclee for (i = 0; i < NDKMAP; i++) { 29533525Sshidokht lp = &cl->cl_map[i]; 29543525Sshidokht cl->cl_offset[i] = 29553525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno; 2956786Slclee #if defined(__i386) || defined(__amd64) 29573525Sshidokht cl->cl_offset[i] += cl->cl_solaris_offset; 2958786Slclee #endif 2959786Slclee } 29603525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 29613525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 2962786Slclee kmem_free(tmp_geom, sizeof (struct dk_geom)); 2963786Slclee 2964786Slclee return (rval); 2965786Slclee } 2966786Slclee 2967786Slclee /* 2968786Slclee * Function: cmlb_dkio_get_partition 2969786Slclee * 2970786Slclee * Description: This routine is the driver entry point for handling user 2971786Slclee * requests to get the partition table (DKIOCGAPART). 2972786Slclee * 2973786Slclee * Arguments: 29743525Sshidokht * arg pointer to user provided dk_allmap structure specifying 2975786Slclee * the controller's notion of the current partition table. 29763525Sshidokht * 29773525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 29783525Sshidokht * directly from the mode argument of ioctl(). 29793525Sshidokht * 29803525Sshidokht * tg_cookie cookie from target driver to be passed back to target 29813525Sshidokht * driver when we call back to it through tg_ops. 2982786Slclee * 2983786Slclee * Return Code: 0 2984786Slclee * EFAULT 2985786Slclee * ENXIO 2986786Slclee * EIO 2987786Slclee */ 2988786Slclee static int 29893525Sshidokht cmlb_dkio_get_partition(struct cmlb_lun *cl, caddr_t arg, int flag, 29903525Sshidokht void *tg_cookie) 2991786Slclee { 2992786Slclee int rval = 0; 2993786Slclee int size; 2994786Slclee 2995786Slclee /* 2996786Slclee * Make sure the geometry is valid before getting the partition 2997786Slclee * information. 2998786Slclee */ 29993525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 30003525Sshidokht if ((rval = cmlb_validate_geometry(cl, 1, 0, tg_cookie)) != 0) { 30013525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3002786Slclee return (rval); 3003786Slclee } 30043525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3005786Slclee 3006786Slclee #if defined(__i386) || defined(__amd64) 30073525Sshidokht if (cl->cl_solaris_size == 0) { 3008786Slclee return (EIO); 3009786Slclee } 3010786Slclee #endif 3011786Slclee 3012786Slclee #ifdef _MULTI_DATAMODEL 3013786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 3014786Slclee case DDI_MODEL_ILP32: { 3015786Slclee struct dk_map32 dk_map32[NDKMAP]; 3016786Slclee int i; 3017786Slclee 3018786Slclee for (i = 0; i < NDKMAP; i++) { 30193525Sshidokht dk_map32[i].dkl_cylno = cl->cl_map[i].dkl_cylno; 30203525Sshidokht dk_map32[i].dkl_nblk = cl->cl_map[i].dkl_nblk; 3021786Slclee } 3022786Slclee size = NDKMAP * sizeof (struct dk_map32); 3023786Slclee rval = ddi_copyout(dk_map32, (void *)arg, size, flag); 3024786Slclee if (rval != 0) { 3025786Slclee rval = EFAULT; 3026786Slclee } 3027786Slclee break; 3028786Slclee } 3029786Slclee case DDI_MODEL_NONE: 3030786Slclee size = NDKMAP * sizeof (struct dk_map); 30313525Sshidokht rval = ddi_copyout(cl->cl_map, (void *)arg, size, flag); 3032786Slclee if (rval != 0) { 3033786Slclee rval = EFAULT; 3034786Slclee } 3035786Slclee break; 3036786Slclee } 3037786Slclee #else /* ! _MULTI_DATAMODEL */ 3038786Slclee size = NDKMAP * sizeof (struct dk_map); 30393525Sshidokht rval = ddi_copyout(cl->cl_map, (void *)arg, size, flag); 3040786Slclee if (rval != 0) { 3041786Slclee rval = EFAULT; 3042786Slclee } 3043786Slclee #endif /* _MULTI_DATAMODEL */ 3044786Slclee return (rval); 3045786Slclee } 3046786Slclee 3047786Slclee /* 3048786Slclee * Function: cmlb_dkio_set_partition 3049786Slclee * 3050786Slclee * Description: This routine is the driver entry point for handling user 3051786Slclee * requests to set the partition table (DKIOCSAPART). The actual 3052786Slclee * device partition is not updated. 3053786Slclee * 3054786Slclee * Arguments: 3055786Slclee * arg - pointer to user provided dk_allmap structure used to set 3056786Slclee * the controller's notion of the partition table. 3057786Slclee * flag - this argument is a pass through to ddi_copyxxx() 3058786Slclee * directly from the mode argument of ioctl(). 3059786Slclee * 3060786Slclee * Return Code: 0 3061786Slclee * EINVAL 3062786Slclee * EFAULT 3063786Slclee * ENXIO 3064786Slclee * EIO 3065786Slclee */ 3066786Slclee static int 30673525Sshidokht cmlb_dkio_set_partition(struct cmlb_lun *cl, caddr_t arg, int flag) 3068786Slclee { 3069786Slclee struct dk_map dk_map[NDKMAP]; 3070786Slclee struct dk_map *lp; 3071786Slclee int rval = 0; 3072786Slclee int size; 3073786Slclee int i; 3074786Slclee #if defined(_SUNOS_VTOC_16) 3075786Slclee struct dkl_partition *vp; 3076786Slclee #endif 3077786Slclee 3078786Slclee /* 3079786Slclee * Set the map for all logical partitions. We lock 3080786Slclee * the priority just to make sure an interrupt doesn't 3081786Slclee * come in while the map is half updated. 3082786Slclee */ 30833525Sshidokht _NOTE(DATA_READABLE_WITHOUT_LOCK(cmlb_lun::cl_solaris_size)) 30843525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 30853525Sshidokht 30863525Sshidokht if (cl->cl_blockcount > DK_MAX_BLOCKS) { 30873525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3088786Slclee return (ENOTSUP); 3089786Slclee } 30903525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 30913525Sshidokht if (cl->cl_solaris_size == 0) { 3092786Slclee return (EIO); 3093786Slclee } 3094786Slclee 3095786Slclee #ifdef _MULTI_DATAMODEL 3096786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 3097786Slclee case DDI_MODEL_ILP32: { 3098786Slclee struct dk_map32 dk_map32[NDKMAP]; 3099786Slclee 3100786Slclee size = NDKMAP * sizeof (struct dk_map32); 3101786Slclee rval = ddi_copyin((void *)arg, dk_map32, size, flag); 3102786Slclee if (rval != 0) { 3103786Slclee return (EFAULT); 3104786Slclee } 3105786Slclee for (i = 0; i < NDKMAP; i++) { 3106786Slclee dk_map[i].dkl_cylno = dk_map32[i].dkl_cylno; 3107786Slclee dk_map[i].dkl_nblk = dk_map32[i].dkl_nblk; 3108786Slclee } 3109786Slclee break; 3110786Slclee } 3111786Slclee case DDI_MODEL_NONE: 3112786Slclee size = NDKMAP * sizeof (struct dk_map); 3113786Slclee rval = ddi_copyin((void *)arg, dk_map, size, flag); 3114786Slclee if (rval != 0) { 3115786Slclee return (EFAULT); 3116786Slclee } 3117786Slclee break; 3118786Slclee } 3119786Slclee #else /* ! _MULTI_DATAMODEL */ 3120786Slclee size = NDKMAP * sizeof (struct dk_map); 3121786Slclee rval = ddi_copyin((void *)arg, dk_map, size, flag); 3122786Slclee if (rval != 0) { 3123786Slclee return (EFAULT); 3124786Slclee } 3125786Slclee #endif /* _MULTI_DATAMODEL */ 3126786Slclee 31273525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 3128786Slclee /* Note: The size used in this bcopy is set based upon the data model */ 31293525Sshidokht bcopy(dk_map, cl->cl_map, size); 3130786Slclee #if defined(_SUNOS_VTOC_16) 31313525Sshidokht vp = (struct dkl_partition *)&(cl->cl_vtoc); 3132786Slclee #endif /* defined(_SUNOS_VTOC_16) */ 3133786Slclee for (i = 0; i < NDKMAP; i++) { 31343525Sshidokht lp = &cl->cl_map[i]; 31353525Sshidokht cl->cl_offset[i] = 31363525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno; 3137786Slclee #if defined(_SUNOS_VTOC_16) 31383525Sshidokht vp->p_start = cl->cl_offset[i]; 3139786Slclee vp->p_size = lp->dkl_nblk; 3140786Slclee vp++; 3141786Slclee #endif /* defined(_SUNOS_VTOC_16) */ 3142786Slclee #if defined(__i386) || defined(__amd64) 31433525Sshidokht cl->cl_offset[i] += cl->cl_solaris_offset; 3144786Slclee #endif 3145786Slclee } 31463525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3147786Slclee return (rval); 3148786Slclee } 3149786Slclee 3150786Slclee 3151786Slclee /* 3152786Slclee * Function: cmlb_dkio_get_vtoc 3153786Slclee * 3154786Slclee * Description: This routine is the driver entry point for handling user 3155786Slclee * requests to get the current volume table of contents 3156786Slclee * (DKIOCGVTOC). 3157786Slclee * 3158786Slclee * Arguments: 31593525Sshidokht * arg pointer to user provided vtoc structure specifying 3160786Slclee * the current vtoc. 31613525Sshidokht * 31623525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 31633525Sshidokht * directly from the mode argument of ioctl(). 31643525Sshidokht * 31653525Sshidokht * tg_cookie cookie from target driver to be passed back to target 31663525Sshidokht * driver when we call back to it through tg_ops. 3167786Slclee * 3168786Slclee * Return Code: 0 3169786Slclee * EFAULT 3170786Slclee * ENXIO 3171786Slclee * EIO 3172786Slclee */ 3173786Slclee static int 31743525Sshidokht cmlb_dkio_get_vtoc(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie) 3175786Slclee { 3176786Slclee #if defined(_SUNOS_VTOC_8) 3177786Slclee struct vtoc user_vtoc; 3178786Slclee #endif /* defined(_SUNOS_VTOC_8) */ 3179786Slclee int rval = 0; 3180786Slclee 31813525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 31823525Sshidokht rval = cmlb_validate_geometry(cl, 1, 0, tg_cookie); 3183786Slclee 3184786Slclee #if defined(_SUNOS_VTOC_8) 3185786Slclee if (rval == EINVAL && 31863525Sshidokht (cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8)) { 3187786Slclee /* 3188786Slclee * This is to return a default label even when we do not 3189786Slclee * really assume a default label for the device. 3190786Slclee * dad driver utilizes this. 3191786Slclee */ 31923525Sshidokht if (cl->cl_blockcount <= DK_MAX_BLOCKS) { 31933525Sshidokht cmlb_setup_default_geometry(cl, tg_cookie); 3194786Slclee rval = 0; 3195786Slclee } 3196786Slclee } 3197786Slclee #endif 3198786Slclee if (rval) { 31993525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3200786Slclee return (rval); 3201786Slclee } 3202786Slclee 3203786Slclee #if defined(_SUNOS_VTOC_8) 32043525Sshidokht cmlb_build_user_vtoc(cl, &user_vtoc); 32053525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3206786Slclee 3207786Slclee #ifdef _MULTI_DATAMODEL 3208786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 3209786Slclee case DDI_MODEL_ILP32: { 3210786Slclee struct vtoc32 user_vtoc32; 3211786Slclee 3212786Slclee vtoctovtoc32(user_vtoc, user_vtoc32); 3213786Slclee if (ddi_copyout(&user_vtoc32, (void *)arg, 3214786Slclee sizeof (struct vtoc32), flag)) { 3215786Slclee return (EFAULT); 3216786Slclee } 3217786Slclee break; 3218786Slclee } 3219786Slclee 3220786Slclee case DDI_MODEL_NONE: 3221786Slclee if (ddi_copyout(&user_vtoc, (void *)arg, 3222786Slclee sizeof (struct vtoc), flag)) { 3223786Slclee return (EFAULT); 3224786Slclee } 3225786Slclee break; 3226786Slclee } 3227786Slclee #else /* ! _MULTI_DATAMODEL */ 3228786Slclee if (ddi_copyout(&user_vtoc, (void *)arg, sizeof (struct vtoc), flag)) { 3229786Slclee return (EFAULT); 3230786Slclee } 3231786Slclee #endif /* _MULTI_DATAMODEL */ 3232786Slclee 3233786Slclee #elif defined(_SUNOS_VTOC_16) 32343525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3235786Slclee 3236786Slclee #ifdef _MULTI_DATAMODEL 3237786Slclee /* 32383525Sshidokht * The cl_vtoc structure is a "struct dk_vtoc" which is always 3239786Slclee * 32-bit to maintain compatibility with existing on-disk 3240786Slclee * structures. Thus, we need to convert the structure when copying 3241786Slclee * it out to a datamodel-dependent "struct vtoc" in a 64-bit 3242786Slclee * program. If the target is a 32-bit program, then no conversion 3243786Slclee * is necessary. 3244786Slclee */ 3245786Slclee /* LINTED: logical expression always true: op "||" */ 32463525Sshidokht ASSERT(sizeof (cl->cl_vtoc) == sizeof (struct vtoc32)); 3247786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 3248786Slclee case DDI_MODEL_ILP32: 32493525Sshidokht if (ddi_copyout(&(cl->cl_vtoc), (void *)arg, 32503525Sshidokht sizeof (cl->cl_vtoc), flag)) { 3251786Slclee return (EFAULT); 3252786Slclee } 3253786Slclee break; 3254786Slclee 3255786Slclee case DDI_MODEL_NONE: { 3256786Slclee struct vtoc user_vtoc; 3257786Slclee 32583525Sshidokht vtoc32tovtoc(cl->cl_vtoc, user_vtoc); 3259786Slclee if (ddi_copyout(&user_vtoc, (void *)arg, 3260786Slclee sizeof (struct vtoc), flag)) { 3261786Slclee return (EFAULT); 3262786Slclee } 3263786Slclee break; 3264786Slclee } 3265786Slclee } 3266786Slclee #else /* ! _MULTI_DATAMODEL */ 32673525Sshidokht if (ddi_copyout(&(cl->cl_vtoc), (void *)arg, sizeof (cl->cl_vtoc), 3268786Slclee flag)) { 3269786Slclee return (EFAULT); 3270786Slclee } 3271786Slclee #endif /* _MULTI_DATAMODEL */ 3272786Slclee #else 3273786Slclee #error "No VTOC format defined." 3274786Slclee #endif 3275786Slclee 3276786Slclee return (rval); 3277786Slclee } 3278786Slclee 3279786Slclee static int 32803525Sshidokht cmlb_dkio_get_efi(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie) 3281786Slclee { 3282786Slclee dk_efi_t user_efi; 3283786Slclee int rval = 0; 3284786Slclee void *buffer; 32853525Sshidokht diskaddr_t tgt_lba; 3286786Slclee 3287786Slclee if (ddi_copyin(arg, &user_efi, sizeof (dk_efi_t), flag)) 3288786Slclee return (EFAULT); 3289786Slclee 3290786Slclee user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64; 3291786Slclee 32923525Sshidokht tgt_lba = user_efi.dki_lba; 32933525Sshidokht 32943525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 32953525Sshidokht if ((cmlb_check_update_blockcount(cl, tg_cookie) != 0) || 32963525Sshidokht (cl->cl_tgt_blocksize == 0)) { 32973525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 32983525Sshidokht return (EINVAL); 32993525Sshidokht } 33003525Sshidokht if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) 33013525Sshidokht tgt_lba = tgt_lba * cl->cl_tgt_blocksize / 33023525Sshidokht cl->cl_sys_blocksize; 33033525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 33043525Sshidokht 3305786Slclee buffer = kmem_alloc(user_efi.dki_length, KM_SLEEP); 33063525Sshidokht rval = DK_TG_READ(cl, buffer, tgt_lba, user_efi.dki_length, tg_cookie); 3307786Slclee if (rval == 0 && ddi_copyout(buffer, user_efi.dki_data, 3308786Slclee user_efi.dki_length, flag) != 0) 3309786Slclee rval = EFAULT; 3310786Slclee 3311786Slclee kmem_free(buffer, user_efi.dki_length); 3312786Slclee return (rval); 3313786Slclee } 3314786Slclee 33153525Sshidokht #if defined(_SUNOS_VTOC_8) 3316786Slclee /* 3317786Slclee * Function: cmlb_build_user_vtoc 3318786Slclee * 3319786Slclee * Description: This routine populates a pass by reference variable with the 3320786Slclee * current volume table of contents. 3321786Slclee * 33223525Sshidokht * Arguments: cl - driver soft state (unit) structure 3323786Slclee * user_vtoc - pointer to vtoc structure to be populated 3324786Slclee */ 3325786Slclee static void 33263525Sshidokht cmlb_build_user_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc) 3327786Slclee { 3328786Slclee struct dk_map2 *lpart; 3329786Slclee struct dk_map *lmap; 3330786Slclee struct partition *vpart; 3331786Slclee int nblks; 3332786Slclee int i; 3333786Slclee 33343525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 3335786Slclee 3336786Slclee /* 3337786Slclee * Return vtoc structure fields in the provided VTOC area, addressed 3338786Slclee * by *vtoc. 3339786Slclee */ 3340786Slclee bzero(user_vtoc, sizeof (struct vtoc)); 33413525Sshidokht user_vtoc->v_bootinfo[0] = cl->cl_vtoc.v_bootinfo[0]; 33423525Sshidokht user_vtoc->v_bootinfo[1] = cl->cl_vtoc.v_bootinfo[1]; 33433525Sshidokht user_vtoc->v_bootinfo[2] = cl->cl_vtoc.v_bootinfo[2]; 3344786Slclee user_vtoc->v_sanity = VTOC_SANE; 33453525Sshidokht user_vtoc->v_version = cl->cl_vtoc.v_version; 33463525Sshidokht bcopy(cl->cl_vtoc.v_volume, user_vtoc->v_volume, LEN_DKL_VVOL); 33473525Sshidokht user_vtoc->v_sectorsz = cl->cl_sys_blocksize; 33483525Sshidokht user_vtoc->v_nparts = cl->cl_vtoc.v_nparts; 3349786Slclee 3350786Slclee for (i = 0; i < 10; i++) 33513525Sshidokht user_vtoc->v_reserved[i] = cl->cl_vtoc.v_reserved[i]; 3352786Slclee 3353786Slclee /* 3354786Slclee * Convert partitioning information. 3355786Slclee * 3356786Slclee * Note the conversion from starting cylinder number 3357786Slclee * to starting sector number. 3358786Slclee */ 33593525Sshidokht lmap = cl->cl_map; 33603525Sshidokht lpart = (struct dk_map2 *)cl->cl_vtoc.v_part; 3361786Slclee vpart = user_vtoc->v_part; 3362786Slclee 33633525Sshidokht nblks = cl->cl_g.dkg_nsect * cl->cl_g.dkg_nhead; 3364786Slclee 3365786Slclee for (i = 0; i < V_NUMPAR; i++) { 3366786Slclee vpart->p_tag = lpart->p_tag; 3367786Slclee vpart->p_flag = lpart->p_flag; 3368786Slclee vpart->p_start = lmap->dkl_cylno * nblks; 3369786Slclee vpart->p_size = lmap->dkl_nblk; 3370786Slclee lmap++; 3371786Slclee lpart++; 3372786Slclee vpart++; 3373786Slclee 3374786Slclee /* (4364927) */ 33753525Sshidokht user_vtoc->timestamp[i] = (time_t)cl->cl_vtoc.v_timestamp[i]; 3376786Slclee } 3377786Slclee 33783525Sshidokht bcopy(cl->cl_asciilabel, user_vtoc->v_asciilabel, LEN_DKL_ASCII); 3379786Slclee } 33803525Sshidokht #endif 3381786Slclee 3382786Slclee static int 33833525Sshidokht cmlb_dkio_partition(struct cmlb_lun *cl, caddr_t arg, int flag, 33843525Sshidokht void *tg_cookie) 3385786Slclee { 3386786Slclee struct partition64 p64; 3387786Slclee int rval = 0; 3388786Slclee uint_t nparts; 3389786Slclee efi_gpe_t *partitions; 3390786Slclee efi_gpt_t *buffer; 3391786Slclee diskaddr_t gpe_lba; 3392786Slclee 3393786Slclee if (ddi_copyin((const void *)arg, &p64, 3394786Slclee sizeof (struct partition64), flag)) { 3395786Slclee return (EFAULT); 3396786Slclee } 3397786Slclee 3398786Slclee buffer = kmem_alloc(EFI_MIN_ARRAY_SIZE, KM_SLEEP); 33993525Sshidokht rval = DK_TG_READ(cl, buffer, 1, DEV_BSIZE, tg_cookie); 3400786Slclee if (rval != 0) 3401786Slclee goto done_error; 3402786Slclee 3403786Slclee cmlb_swap_efi_gpt(buffer); 3404786Slclee 3405786Slclee if ((rval = cmlb_validate_efi(buffer)) != 0) 3406786Slclee goto done_error; 3407786Slclee 3408786Slclee nparts = buffer->efi_gpt_NumberOfPartitionEntries; 3409786Slclee gpe_lba = buffer->efi_gpt_PartitionEntryLBA; 3410786Slclee if (p64.p_partno > nparts) { 3411786Slclee /* couldn't find it */ 3412786Slclee rval = ESRCH; 3413786Slclee goto done_error; 3414786Slclee } 3415786Slclee /* 3416786Slclee * if we're dealing with a partition that's out of the normal 3417786Slclee * 16K block, adjust accordingly 3418786Slclee */ 3419786Slclee gpe_lba += p64.p_partno / sizeof (efi_gpe_t); 34203525Sshidokht rval = DK_TG_READ(cl, buffer, gpe_lba, EFI_MIN_ARRAY_SIZE, tg_cookie); 3421786Slclee 3422786Slclee if (rval) { 3423786Slclee goto done_error; 3424786Slclee } 3425786Slclee partitions = (efi_gpe_t *)buffer; 3426786Slclee 3427786Slclee cmlb_swap_efi_gpe(nparts, partitions); 3428786Slclee 3429786Slclee partitions += p64.p_partno; 3430786Slclee bcopy(&partitions->efi_gpe_PartitionTypeGUID, &p64.p_type, 3431786Slclee sizeof (struct uuid)); 3432786Slclee p64.p_start = partitions->efi_gpe_StartingLBA; 3433786Slclee p64.p_size = partitions->efi_gpe_EndingLBA - 34343525Sshidokht p64.p_start + 1; 3435786Slclee 3436786Slclee if (ddi_copyout(&p64, (void *)arg, sizeof (struct partition64), flag)) 3437786Slclee rval = EFAULT; 3438786Slclee 3439786Slclee done_error: 3440786Slclee kmem_free(buffer, EFI_MIN_ARRAY_SIZE); 3441786Slclee return (rval); 3442786Slclee } 3443786Slclee 3444786Slclee 3445786Slclee /* 3446786Slclee * Function: cmlb_dkio_set_vtoc 3447786Slclee * 3448786Slclee * Description: This routine is the driver entry point for handling user 3449786Slclee * requests to set the current volume table of contents 3450786Slclee * (DKIOCSVTOC). 3451786Slclee * 34523525Sshidokht * Arguments: 34533525Sshidokht * dev the device number 34543525Sshidokht * arg pointer to user provided vtoc structure used to set the 3455786Slclee * current vtoc. 34563525Sshidokht * 34573525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 34583525Sshidokht * directly from the mode argument of ioctl(). 34593525Sshidokht * 34603525Sshidokht * tg_cookie cookie from target driver to be passed back to target 34613525Sshidokht * driver when we call back to it through tg_ops. 3462786Slclee * 3463786Slclee * Return Code: 0 3464786Slclee * EFAULT 3465786Slclee * ENXIO 3466786Slclee * EINVAL 3467786Slclee * ENOTSUP 3468786Slclee */ 3469786Slclee static int 34703525Sshidokht cmlb_dkio_set_vtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag, 34713525Sshidokht void *tg_cookie) 3472786Slclee { 3473786Slclee struct vtoc user_vtoc; 3474786Slclee int rval = 0; 3475786Slclee 3476786Slclee #ifdef _MULTI_DATAMODEL 3477786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 3478786Slclee case DDI_MODEL_ILP32: { 3479786Slclee struct vtoc32 user_vtoc32; 3480786Slclee 3481786Slclee if (ddi_copyin((const void *)arg, &user_vtoc32, 3482786Slclee sizeof (struct vtoc32), flag)) { 3483786Slclee return (EFAULT); 3484786Slclee } 3485786Slclee vtoc32tovtoc(user_vtoc32, user_vtoc); 3486786Slclee break; 3487786Slclee } 3488786Slclee 3489786Slclee case DDI_MODEL_NONE: 3490786Slclee if (ddi_copyin((const void *)arg, &user_vtoc, 3491786Slclee sizeof (struct vtoc), flag)) { 3492786Slclee return (EFAULT); 3493786Slclee } 3494786Slclee break; 3495786Slclee } 3496786Slclee #else /* ! _MULTI_DATAMODEL */ 3497786Slclee if (ddi_copyin((const void *)arg, &user_vtoc, 3498786Slclee sizeof (struct vtoc), flag)) { 3499786Slclee return (EFAULT); 3500786Slclee } 3501786Slclee #endif /* _MULTI_DATAMODEL */ 3502786Slclee 35033525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 35043525Sshidokht if (cl->cl_blockcount > DK_MAX_BLOCKS) { 35053525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3506786Slclee return (ENOTSUP); 3507786Slclee } 35083525Sshidokht 35093525Sshidokht #if defined(__i386) || defined(__amd64) 35103525Sshidokht if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) { 35113525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 35123525Sshidokht return (EINVAL); 35133525Sshidokht } 35143525Sshidokht #endif 35153525Sshidokht 35163525Sshidokht if (cl->cl_g.dkg_ncyl == 0) { 35173525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3518786Slclee return (EINVAL); 3519786Slclee } 3520786Slclee 35213525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 35223525Sshidokht cmlb_clear_efi(cl, tg_cookie); 35233525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd"); 35243525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd,raw"); 35253525Sshidokht (void) ddi_create_minor_node(CMLB_DEVINFO(cl), "h", 3526786Slclee S_IFBLK, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 35273525Sshidokht cl->cl_node_type, NULL); 35283525Sshidokht (void) ddi_create_minor_node(CMLB_DEVINFO(cl), "h,raw", 3529786Slclee S_IFCHR, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 35303525Sshidokht cl->cl_node_type, NULL); 35313525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 35323525Sshidokht 35333525Sshidokht if ((rval = cmlb_build_label_vtoc(cl, &user_vtoc)) == 0) { 35343525Sshidokht if ((rval = cmlb_write_label(cl, tg_cookie)) == 0) { 35353525Sshidokht if (cmlb_validate_geometry(cl, 1, 0, tg_cookie) != 0) { 35363525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 3537786Slclee "cmlb_dkio_set_vtoc: " 3538786Slclee "Failed validate geometry\n"); 3539786Slclee } 3540786Slclee } 3541786Slclee } 35423525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3543786Slclee return (rval); 3544786Slclee } 3545786Slclee 3546786Slclee 3547786Slclee /* 3548786Slclee * Function: cmlb_build_label_vtoc 3549786Slclee * 3550786Slclee * Description: This routine updates the driver soft state current volume table 3551786Slclee * of contents based on a user specified vtoc. 3552786Slclee * 35533525Sshidokht * Arguments: cl - driver soft state (unit) structure 3554786Slclee * user_vtoc - pointer to vtoc structure specifying vtoc to be used 3555786Slclee * to update the driver soft state. 3556786Slclee * 3557786Slclee * Return Code: 0 3558786Slclee * EINVAL 3559786Slclee */ 3560786Slclee static int 35613525Sshidokht cmlb_build_label_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc) 3562786Slclee { 3563786Slclee struct dk_map *lmap; 3564786Slclee struct partition *vpart; 3565786Slclee int nblks; 3566786Slclee #if defined(_SUNOS_VTOC_8) 3567786Slclee int ncyl; 3568786Slclee struct dk_map2 *lpart; 3569786Slclee #endif /* defined(_SUNOS_VTOC_8) */ 3570786Slclee int i; 3571786Slclee 35723525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 3573786Slclee 3574786Slclee /* Sanity-check the vtoc */ 3575786Slclee if (user_vtoc->v_sanity != VTOC_SANE || 35763525Sshidokht user_vtoc->v_sectorsz != cl->cl_sys_blocksize || 3577786Slclee user_vtoc->v_nparts != V_NUMPAR) { 35783525Sshidokht cmlb_dbg(CMLB_INFO, cl, 3579786Slclee "cmlb_build_label_vtoc: vtoc not valid\n"); 3580786Slclee return (EINVAL); 3581786Slclee } 3582786Slclee 35833525Sshidokht nblks = cl->cl_g.dkg_nsect * cl->cl_g.dkg_nhead; 3584786Slclee if (nblks == 0) { 35853525Sshidokht cmlb_dbg(CMLB_INFO, cl, 3586786Slclee "cmlb_build_label_vtoc: geom nblks is 0\n"); 3587786Slclee return (EINVAL); 3588786Slclee } 3589786Slclee 3590786Slclee #if defined(_SUNOS_VTOC_8) 3591786Slclee vpart = user_vtoc->v_part; 3592786Slclee for (i = 0; i < V_NUMPAR; i++) { 3593786Slclee if ((vpart->p_start % nblks) != 0) { 35943525Sshidokht cmlb_dbg(CMLB_INFO, cl, 3595786Slclee "cmlb_build_label_vtoc: p_start not multiply of" 3596786Slclee "nblks part %d p_start %d nblks %d\n", i, 3597786Slclee vpart->p_start, nblks); 3598786Slclee return (EINVAL); 3599786Slclee } 3600786Slclee ncyl = vpart->p_start / nblks; 3601786Slclee ncyl += vpart->p_size / nblks; 3602786Slclee if ((vpart->p_size % nblks) != 0) { 3603786Slclee ncyl++; 3604786Slclee } 36053525Sshidokht if (ncyl > (int)cl->cl_g.dkg_ncyl) { 36063525Sshidokht cmlb_dbg(CMLB_INFO, cl, 3607786Slclee "cmlb_build_label_vtoc: ncyl %d > dkg_ncyl %d" 3608786Slclee "p_size %ld p_start %ld nblks %d part number %d" 3609786Slclee "tag %d\n", 36103525Sshidokht ncyl, cl->cl_g.dkg_ncyl, vpart->p_size, 3611786Slclee vpart->p_start, nblks, 3612786Slclee i, vpart->p_tag); 3613786Slclee 3614786Slclee return (EINVAL); 3615786Slclee } 3616786Slclee vpart++; 3617786Slclee } 3618786Slclee #endif /* defined(_SUNOS_VTOC_8) */ 3619786Slclee 3620786Slclee /* Put appropriate vtoc structure fields into the disk label */ 3621786Slclee #if defined(_SUNOS_VTOC_16) 3622786Slclee /* 3623786Slclee * The vtoc is always a 32bit data structure to maintain the 3624786Slclee * on-disk format. Convert "in place" instead of doing bcopy. 3625786Slclee */ 36263525Sshidokht vtoctovtoc32((*user_vtoc), (*((struct vtoc32 *)&(cl->cl_vtoc)))); 3627786Slclee 3628786Slclee /* 3629786Slclee * in the 16-slice vtoc, starting sectors are expressed in 3630786Slclee * numbers *relative* to the start of the Solaris fdisk partition. 3631786Slclee */ 36323525Sshidokht lmap = cl->cl_map; 3633786Slclee vpart = user_vtoc->v_part; 3634786Slclee 3635786Slclee for (i = 0; i < (int)user_vtoc->v_nparts; i++, lmap++, vpart++) { 3636786Slclee lmap->dkl_cylno = vpart->p_start / nblks; 3637786Slclee lmap->dkl_nblk = vpart->p_size; 3638786Slclee } 3639786Slclee 3640786Slclee #elif defined(_SUNOS_VTOC_8) 3641786Slclee 36423525Sshidokht cl->cl_vtoc.v_bootinfo[0] = (uint32_t)user_vtoc->v_bootinfo[0]; 36433525Sshidokht cl->cl_vtoc.v_bootinfo[1] = (uint32_t)user_vtoc->v_bootinfo[1]; 36443525Sshidokht cl->cl_vtoc.v_bootinfo[2] = (uint32_t)user_vtoc->v_bootinfo[2]; 36453525Sshidokht 36463525Sshidokht cl->cl_vtoc.v_sanity = (uint32_t)user_vtoc->v_sanity; 36473525Sshidokht cl->cl_vtoc.v_version = (uint32_t)user_vtoc->v_version; 36483525Sshidokht 36493525Sshidokht bcopy(user_vtoc->v_volume, cl->cl_vtoc.v_volume, LEN_DKL_VVOL); 36503525Sshidokht 36513525Sshidokht cl->cl_vtoc.v_nparts = user_vtoc->v_nparts; 3652786Slclee 3653786Slclee for (i = 0; i < 10; i++) 36543525Sshidokht cl->cl_vtoc.v_reserved[i] = user_vtoc->v_reserved[i]; 3655786Slclee 3656786Slclee /* 3657786Slclee * Note the conversion from starting sector number 3658786Slclee * to starting cylinder number. 3659786Slclee * Return error if division results in a remainder. 3660786Slclee */ 36613525Sshidokht lmap = cl->cl_map; 36623525Sshidokht lpart = cl->cl_vtoc.v_part; 3663786Slclee vpart = user_vtoc->v_part; 3664786Slclee 3665786Slclee for (i = 0; i < (int)user_vtoc->v_nparts; i++) { 3666786Slclee lpart->p_tag = vpart->p_tag; 3667786Slclee lpart->p_flag = vpart->p_flag; 3668786Slclee lmap->dkl_cylno = vpart->p_start / nblks; 3669786Slclee lmap->dkl_nblk = vpart->p_size; 3670786Slclee 3671786Slclee lmap++; 3672786Slclee lpart++; 3673786Slclee vpart++; 3674786Slclee 3675786Slclee /* (4387723) */ 3676786Slclee #ifdef _LP64 3677786Slclee if (user_vtoc->timestamp[i] > TIME32_MAX) { 36783525Sshidokht cl->cl_vtoc.v_timestamp[i] = TIME32_MAX; 3679786Slclee } else { 36803525Sshidokht cl->cl_vtoc.v_timestamp[i] = user_vtoc->timestamp[i]; 3681786Slclee } 3682786Slclee #else 36833525Sshidokht cl->cl_vtoc.v_timestamp[i] = user_vtoc->timestamp[i]; 3684786Slclee #endif 3685786Slclee } 3686786Slclee 36873525Sshidokht bcopy(user_vtoc->v_asciilabel, cl->cl_asciilabel, LEN_DKL_ASCII); 3688786Slclee #else 3689786Slclee #error "No VTOC format defined." 3690786Slclee #endif 3691786Slclee return (0); 3692786Slclee } 3693786Slclee 3694786Slclee /* 3695786Slclee * Function: cmlb_clear_efi 3696786Slclee * 3697786Slclee * Description: This routine clears all EFI labels. 3698786Slclee * 36993525Sshidokht * Arguments: 37003525Sshidokht * cl driver soft state (unit) structure 3701786Slclee * 37023525Sshidokht * tg_cookie cookie from target driver to be passed back to target 37033525Sshidokht * driver when we call back to it through tg_ops. 3704786Slclee * Return Code: void 3705786Slclee */ 3706786Slclee static void 37073525Sshidokht cmlb_clear_efi(struct cmlb_lun *cl, void *tg_cookie) 3708786Slclee { 3709786Slclee efi_gpt_t *gpt; 3710786Slclee diskaddr_t cap; 3711786Slclee int rval; 3712786Slclee 37133525Sshidokht ASSERT(!mutex_owned(CMLB_MUTEX(cl))); 37143525Sshidokht 37153525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 37163525Sshidokht cl->cl_reserved = -1; 37173525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3718786Slclee 3719786Slclee gpt = kmem_alloc(sizeof (efi_gpt_t), KM_SLEEP); 3720786Slclee 37213525Sshidokht if (DK_TG_READ(cl, gpt, 1, DEV_BSIZE, tg_cookie) != 0) { 3722786Slclee goto done; 3723786Slclee } 3724786Slclee 3725786Slclee cmlb_swap_efi_gpt(gpt); 3726786Slclee rval = cmlb_validate_efi(gpt); 3727786Slclee if (rval == 0) { 3728786Slclee /* clear primary */ 3729786Slclee bzero(gpt, sizeof (efi_gpt_t)); 37303525Sshidokht if (rval = DK_TG_WRITE(cl, gpt, 1, EFI_LABEL_SIZE, tg_cookie)) { 37313525Sshidokht cmlb_dbg(CMLB_INFO, cl, 37323525Sshidokht "cmlb_clear_efi: clear primary label failed\n"); 3733786Slclee } 3734786Slclee } 3735786Slclee /* the backup */ 37363525Sshidokht rval = DK_TG_GETCAP(cl, &cap, tg_cookie); 3737786Slclee if (rval) { 3738786Slclee goto done; 3739786Slclee } 3740786Slclee 37413525Sshidokht if ((rval = DK_TG_READ(cl, gpt, cap - 1, EFI_LABEL_SIZE, tg_cookie)) 37423525Sshidokht != 0) { 3743786Slclee goto done; 3744786Slclee } 3745786Slclee cmlb_swap_efi_gpt(gpt); 3746786Slclee rval = cmlb_validate_efi(gpt); 3747786Slclee if (rval == 0) { 3748786Slclee /* clear backup */ 37493525Sshidokht cmlb_dbg(CMLB_TRACE, cl, 3750786Slclee "cmlb_clear_efi clear backup@%lu\n", cap - 1); 3751786Slclee bzero(gpt, sizeof (efi_gpt_t)); 37523525Sshidokht if ((rval = DK_TG_WRITE(cl, gpt, cap - 1, EFI_LABEL_SIZE, 37533525Sshidokht tg_cookie))) { 37543525Sshidokht cmlb_dbg(CMLB_INFO, cl, 37553525Sshidokht "cmlb_clear_efi: clear backup label failed\n"); 37563525Sshidokht } 37573525Sshidokht } else { 37583525Sshidokht /* 37593525Sshidokht * Refer to comments related to off-by-1 at the 37603525Sshidokht * header of this file 37613525Sshidokht */ 37623525Sshidokht if ((rval = DK_TG_READ(cl, gpt, cap - 2, 37633525Sshidokht EFI_LABEL_SIZE, tg_cookie)) != 0) { 37643525Sshidokht goto done; 37653525Sshidokht } 37663525Sshidokht cmlb_swap_efi_gpt(gpt); 37673525Sshidokht rval = cmlb_validate_efi(gpt); 37683525Sshidokht if (rval == 0) { 37693525Sshidokht /* clear legacy backup EFI label */ 37703525Sshidokht cmlb_dbg(CMLB_TRACE, cl, 37713525Sshidokht "cmlb_clear_efi clear legacy backup@%lu\n", 37723525Sshidokht cap - 2); 37733525Sshidokht bzero(gpt, sizeof (efi_gpt_t)); 37743525Sshidokht if ((rval = DK_TG_WRITE(cl, gpt, cap - 2, 37753525Sshidokht EFI_LABEL_SIZE, tg_cookie))) { 37763525Sshidokht cmlb_dbg(CMLB_INFO, cl, 37773525Sshidokht "cmlb_clear_efi: clear legacy backup label " 37783525Sshidokht "failed\n"); 37793525Sshidokht } 3780786Slclee } 3781786Slclee } 3782786Slclee 3783786Slclee done: 3784786Slclee kmem_free(gpt, sizeof (efi_gpt_t)); 3785786Slclee } 3786786Slclee 3787786Slclee /* 3788786Slclee * Function: cmlb_set_vtoc 3789786Slclee * 3790786Slclee * Description: This routine writes data to the appropriate positions 3791786Slclee * 37923525Sshidokht * Arguments: 37933525Sshidokht * cl driver soft state (unit) structure 37943525Sshidokht * 37953525Sshidokht * dkl the data to be written 37963525Sshidokht * 37973525Sshidokht * tg_cookie cookie from target driver to be passed back to target 37983525Sshidokht * driver when we call back to it through tg_ops. 3799786Slclee * 3800786Slclee * Return: void 3801786Slclee */ 3802786Slclee static int 38033525Sshidokht cmlb_set_vtoc(struct cmlb_lun *cl, struct dk_label *dkl, void *tg_cookie) 3804786Slclee { 3805786Slclee uint_t label_addr; 3806786Slclee int sec; 3807786Slclee int blk; 3808786Slclee int head; 3809786Slclee int cyl; 3810786Slclee int rval; 3811786Slclee 3812786Slclee #if defined(__i386) || defined(__amd64) 38133525Sshidokht label_addr = cl->cl_solaris_offset + DK_LABEL_LOC; 3814786Slclee #else 3815786Slclee /* Write the primary label at block 0 of the solaris partition. */ 3816786Slclee label_addr = 0; 3817786Slclee #endif 3818786Slclee 38193525Sshidokht rval = DK_TG_WRITE(cl, dkl, label_addr, cl->cl_sys_blocksize, 38203525Sshidokht tg_cookie); 3821786Slclee 3822786Slclee if (rval != 0) { 3823786Slclee return (rval); 3824786Slclee } 3825786Slclee 3826786Slclee /* 3827786Slclee * Calculate where the backup labels go. They are always on 3828786Slclee * the last alternate cylinder, but some older drives put them 3829786Slclee * on head 2 instead of the last head. They are always on the 3830786Slclee * first 5 odd sectors of the appropriate track. 3831786Slclee * 3832786Slclee * We have no choice at this point, but to believe that the 3833786Slclee * disk label is valid. Use the geometry of the disk 3834786Slclee * as described in the label. 3835786Slclee */ 3836786Slclee cyl = dkl->dkl_ncyl + dkl->dkl_acyl - 1; 3837786Slclee head = dkl->dkl_nhead - 1; 3838786Slclee 3839786Slclee /* 3840786Slclee * Write and verify the backup labels. Make sure we don't try to 3841786Slclee * write past the last cylinder. 3842786Slclee */ 3843786Slclee for (sec = 1; ((sec < 5 * 2 + 1) && (sec < dkl->dkl_nsect)); sec += 2) { 3844786Slclee blk = (daddr_t)( 3845786Slclee (cyl * ((dkl->dkl_nhead * dkl->dkl_nsect) - dkl->dkl_apc)) + 3846786Slclee (head * dkl->dkl_nsect) + sec); 3847786Slclee #if defined(__i386) || defined(__amd64) 38483525Sshidokht blk += cl->cl_solaris_offset; 3849786Slclee #endif 38503525Sshidokht rval = DK_TG_WRITE(cl, dkl, blk, cl->cl_sys_blocksize, 38513525Sshidokht tg_cookie); 38523525Sshidokht cmlb_dbg(CMLB_INFO, cl, 3853786Slclee "cmlb_set_vtoc: wrote backup label %d\n", blk); 3854786Slclee if (rval != 0) { 3855786Slclee goto exit; 3856786Slclee } 3857786Slclee } 3858786Slclee exit: 3859786Slclee return (rval); 3860786Slclee } 3861786Slclee 3862786Slclee /* 3863786Slclee * Function: cmlb_clear_vtoc 3864786Slclee * 3865786Slclee * Description: This routine clears out the VTOC labels. 3866786Slclee * 38673525Sshidokht * Arguments: 38683525Sshidokht * cl driver soft state (unit) structure 38693525Sshidokht * 38703525Sshidokht * tg_cookie cookie from target driver to be passed back to target 38713525Sshidokht * driver when we call back to it through tg_ops. 3872786Slclee * 3873786Slclee * Return: void 3874786Slclee */ 3875786Slclee static void 38763525Sshidokht cmlb_clear_vtoc(struct cmlb_lun *cl, void *tg_cookie) 3877786Slclee { 3878786Slclee struct dk_label *dkl; 3879786Slclee 38803525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3881786Slclee dkl = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP); 38823525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 3883786Slclee /* 3884786Slclee * cmlb_set_vtoc uses these fields in order to figure out 3885786Slclee * where to overwrite the backup labels 3886786Slclee */ 38873525Sshidokht dkl->dkl_apc = cl->cl_g.dkg_apc; 38883525Sshidokht dkl->dkl_ncyl = cl->cl_g.dkg_ncyl; 38893525Sshidokht dkl->dkl_acyl = cl->cl_g.dkg_acyl; 38903525Sshidokht dkl->dkl_nhead = cl->cl_g.dkg_nhead; 38913525Sshidokht dkl->dkl_nsect = cl->cl_g.dkg_nsect; 38923525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 38933525Sshidokht (void) cmlb_set_vtoc(cl, dkl, tg_cookie); 3894786Slclee kmem_free(dkl, sizeof (struct dk_label)); 3895786Slclee 38963525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 3897786Slclee } 3898786Slclee 3899786Slclee /* 3900786Slclee * Function: cmlb_write_label 3901786Slclee * 3902786Slclee * Description: This routine will validate and write the driver soft state vtoc 3903786Slclee * contents to the device. 3904786Slclee * 39053525Sshidokht * Arguments: 39063525Sshidokht * cl cmlb handle 39073525Sshidokht * 39083525Sshidokht * tg_cookie cookie from target driver to be passed back to target 39093525Sshidokht * driver when we call back to it through tg_ops. 39103525Sshidokht * 3911786Slclee * 3912786Slclee * Return Code: the code returned by cmlb_send_scsi_cmd() 3913786Slclee * 0 3914786Slclee * EINVAL 3915786Slclee * ENXIO 3916786Slclee * ENOMEM 3917786Slclee */ 3918786Slclee static int 39193525Sshidokht cmlb_write_label(struct cmlb_lun *cl, void *tg_cookie) 3920786Slclee { 3921786Slclee struct dk_label *dkl; 3922786Slclee short sum; 3923786Slclee short *sp; 3924786Slclee int i; 3925786Slclee int rval; 3926786Slclee 39273525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 39283525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3929786Slclee dkl = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP); 39303525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 39313525Sshidokht 39323525Sshidokht bcopy(&cl->cl_vtoc, &dkl->dkl_vtoc, sizeof (struct dk_vtoc)); 39333525Sshidokht dkl->dkl_rpm = cl->cl_g.dkg_rpm; 39343525Sshidokht dkl->dkl_pcyl = cl->cl_g.dkg_pcyl; 39353525Sshidokht dkl->dkl_apc = cl->cl_g.dkg_apc; 39363525Sshidokht dkl->dkl_intrlv = cl->cl_g.dkg_intrlv; 39373525Sshidokht dkl->dkl_ncyl = cl->cl_g.dkg_ncyl; 39383525Sshidokht dkl->dkl_acyl = cl->cl_g.dkg_acyl; 39393525Sshidokht dkl->dkl_nhead = cl->cl_g.dkg_nhead; 39403525Sshidokht dkl->dkl_nsect = cl->cl_g.dkg_nsect; 3941786Slclee 3942786Slclee #if defined(_SUNOS_VTOC_8) 39433525Sshidokht dkl->dkl_obs1 = cl->cl_g.dkg_obs1; 39443525Sshidokht dkl->dkl_obs2 = cl->cl_g.dkg_obs2; 39453525Sshidokht dkl->dkl_obs3 = cl->cl_g.dkg_obs3; 3946786Slclee for (i = 0; i < NDKMAP; i++) { 39473525Sshidokht dkl->dkl_map[i].dkl_cylno = cl->cl_map[i].dkl_cylno; 39483525Sshidokht dkl->dkl_map[i].dkl_nblk = cl->cl_map[i].dkl_nblk; 3949786Slclee } 39503525Sshidokht bcopy(cl->cl_asciilabel, dkl->dkl_asciilabel, LEN_DKL_ASCII); 3951786Slclee #elif defined(_SUNOS_VTOC_16) 39523525Sshidokht dkl->dkl_skew = cl->cl_dkg_skew; 3953786Slclee #else 3954786Slclee #error "No VTOC format defined." 3955786Slclee #endif 3956786Slclee 3957786Slclee dkl->dkl_magic = DKL_MAGIC; 39583525Sshidokht dkl->dkl_write_reinstruct = cl->cl_g.dkg_write_reinstruct; 39593525Sshidokht dkl->dkl_read_reinstruct = cl->cl_g.dkg_read_reinstruct; 3960786Slclee 3961786Slclee /* Construct checksum for the new disk label */ 3962786Slclee sum = 0; 3963786Slclee sp = (short *)dkl; 3964786Slclee i = sizeof (struct dk_label) / sizeof (short); 3965786Slclee while (i--) { 3966786Slclee sum ^= *sp++; 3967786Slclee } 3968786Slclee dkl->dkl_cksum = sum; 3969786Slclee 39703525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 39713525Sshidokht 39723525Sshidokht rval = cmlb_set_vtoc(cl, dkl, tg_cookie); 3973786Slclee exit: 3974786Slclee kmem_free(dkl, sizeof (struct dk_label)); 39753525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 3976786Slclee return (rval); 3977786Slclee } 3978786Slclee 3979786Slclee static int 39803525Sshidokht cmlb_dkio_set_efi(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag, 39813525Sshidokht void *tg_cookie) 3982786Slclee { 3983786Slclee dk_efi_t user_efi; 3984786Slclee int rval = 0; 3985786Slclee void *buffer; 39863525Sshidokht diskaddr_t tgt_lba; 3987786Slclee 3988786Slclee if (ddi_copyin(arg, &user_efi, sizeof (dk_efi_t), flag)) 3989786Slclee return (EFAULT); 3990786Slclee 3991786Slclee user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64; 3992786Slclee 3993786Slclee buffer = kmem_alloc(user_efi.dki_length, KM_SLEEP); 3994786Slclee if (ddi_copyin(user_efi.dki_data, buffer, user_efi.dki_length, flag)) { 3995786Slclee rval = EFAULT; 3996786Slclee } else { 3997786Slclee /* 3998786Slclee * let's clear the vtoc labels and clear the softstate 3999786Slclee * vtoc. 4000786Slclee */ 40013525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 40023525Sshidokht if (cl->cl_vtoc.v_sanity == VTOC_SANE) { 40033525Sshidokht cmlb_dbg(CMLB_TRACE, cl, 40043525Sshidokht "cmlb_dkio_set_efi: CLEAR VTOC\n"); 40053525Sshidokht if (cl->cl_vtoc_label_is_from_media) 40063525Sshidokht cmlb_clear_vtoc(cl, tg_cookie); 40073525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc)); 40083525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 40093525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "h"); 40103525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw"); 40113525Sshidokht (void) ddi_create_minor_node(CMLB_DEVINFO(cl), "wd", 4012786Slclee S_IFBLK, 4013786Slclee (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 40143525Sshidokht cl->cl_node_type, NULL); 40153525Sshidokht (void) ddi_create_minor_node(CMLB_DEVINFO(cl), "wd,raw", 4016786Slclee S_IFCHR, 4017786Slclee (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 40183525Sshidokht cl->cl_node_type, NULL); 4019786Slclee } else 40203525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 40213525Sshidokht 40223525Sshidokht tgt_lba = user_efi.dki_lba; 40233525Sshidokht 40243525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 40253525Sshidokht if ((cmlb_check_update_blockcount(cl, tg_cookie) != 0) || 40263525Sshidokht (cl->cl_tgt_blocksize == 0)) { 40273525Sshidokht kmem_free(buffer, user_efi.dki_length); 40283525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 40293525Sshidokht return (EINVAL); 40303525Sshidokht } 40313525Sshidokht if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) 40323525Sshidokht tgt_lba = tgt_lba * 40333525Sshidokht cl->cl_tgt_blocksize / cl->cl_sys_blocksize; 40343525Sshidokht 40353525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 40363525Sshidokht rval = DK_TG_WRITE(cl, buffer, tgt_lba, user_efi.dki_length, 40373525Sshidokht tg_cookie); 40383525Sshidokht 4039786Slclee if (rval == 0) { 40403525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 40413525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 40423525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4043786Slclee } 4044786Slclee } 4045786Slclee kmem_free(buffer, user_efi.dki_length); 4046786Slclee return (rval); 4047786Slclee } 4048786Slclee 4049786Slclee /* 4050786Slclee * Function: cmlb_dkio_get_mboot 4051786Slclee * 4052786Slclee * Description: This routine is the driver entry point for handling user 4053786Slclee * requests to get the current device mboot (DKIOCGMBOOT) 4054786Slclee * 4055786Slclee * Arguments: 40563525Sshidokht * arg pointer to user provided mboot structure specifying 4057786Slclee * the current mboot. 40583525Sshidokht * 40593525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 40603525Sshidokht * directly from the mode argument of ioctl(). 40613525Sshidokht * 40623525Sshidokht * tg_cookie cookie from target driver to be passed back to target 40633525Sshidokht * driver when we call back to it through tg_ops. 4064786Slclee * 4065786Slclee * Return Code: 0 4066786Slclee * EINVAL 4067786Slclee * EFAULT 4068786Slclee * ENXIO 4069786Slclee */ 4070786Slclee static int 40713525Sshidokht cmlb_dkio_get_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie) 4072786Slclee { 4073786Slclee struct mboot *mboot; 4074786Slclee int rval; 4075786Slclee size_t buffer_size; 4076786Slclee 4077786Slclee 4078786Slclee #if defined(_SUNOS_VTOC_8) 40793525Sshidokht if ((!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) || (arg == NULL)) { 4080786Slclee #elif defined(_SUNOS_VTOC_16) 4081786Slclee if (arg == NULL) { 4082786Slclee #endif 4083786Slclee return (EINVAL); 4084786Slclee } 4085786Slclee 4086786Slclee /* 4087786Slclee * Read the mboot block, located at absolute block 0 on the target. 4088786Slclee */ 4089786Slclee buffer_size = sizeof (struct mboot); 4090786Slclee 40913525Sshidokht cmlb_dbg(CMLB_TRACE, cl, 4092786Slclee "cmlb_dkio_get_mboot: allocation size: 0x%x\n", buffer_size); 4093786Slclee 4094786Slclee mboot = kmem_zalloc(buffer_size, KM_SLEEP); 40953525Sshidokht if ((rval = DK_TG_READ(cl, mboot, 0, buffer_size, tg_cookie)) == 0) { 4096786Slclee if (ddi_copyout(mboot, (void *)arg, 4097786Slclee sizeof (struct mboot), flag) != 0) { 4098786Slclee rval = EFAULT; 4099786Slclee } 4100786Slclee } 4101786Slclee kmem_free(mboot, buffer_size); 4102786Slclee return (rval); 4103786Slclee } 4104786Slclee 4105786Slclee 4106786Slclee /* 4107786Slclee * Function: cmlb_dkio_set_mboot 4108786Slclee * 4109786Slclee * Description: This routine is the driver entry point for handling user 4110786Slclee * requests to validate and set the device master boot 4111786Slclee * (DKIOCSMBOOT). 4112786Slclee * 4113786Slclee * Arguments: 41143525Sshidokht * arg pointer to user provided mboot structure used to set the 4115786Slclee * master boot. 41163525Sshidokht * 41173525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 41183525Sshidokht * directly from the mode argument of ioctl(). 41193525Sshidokht * 41203525Sshidokht * tg_cookie cookie from target driver to be passed back to target 41213525Sshidokht * driver when we call back to it through tg_ops. 4122786Slclee * 4123786Slclee * Return Code: 0 4124786Slclee * EINVAL 4125786Slclee * EFAULT 4126786Slclee * ENXIO 4127786Slclee */ 4128786Slclee static int 41293525Sshidokht cmlb_dkio_set_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie) 4130786Slclee { 4131786Slclee struct mboot *mboot = NULL; 4132786Slclee int rval; 4133786Slclee ushort_t magic; 4134786Slclee 4135786Slclee 41363525Sshidokht ASSERT(!mutex_owned(CMLB_MUTEX(cl))); 4137786Slclee 4138786Slclee #if defined(_SUNOS_VTOC_8) 41393525Sshidokht if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) { 4140786Slclee return (EINVAL); 4141786Slclee } 4142786Slclee #endif 4143786Slclee 4144786Slclee if (arg == NULL) { 4145786Slclee return (EINVAL); 4146786Slclee } 4147786Slclee 4148786Slclee mboot = kmem_zalloc(sizeof (struct mboot), KM_SLEEP); 4149786Slclee 4150786Slclee if (ddi_copyin((const void *)arg, mboot, 4151786Slclee sizeof (struct mboot), flag) != 0) { 4152786Slclee kmem_free(mboot, (size_t)(sizeof (struct mboot))); 4153786Slclee return (EFAULT); 4154786Slclee } 4155786Slclee 4156786Slclee /* Is this really a master boot record? */ 4157786Slclee magic = LE_16(mboot->signature); 4158786Slclee if (magic != MBB_MAGIC) { 4159786Slclee kmem_free(mboot, (size_t)(sizeof (struct mboot))); 4160786Slclee return (EINVAL); 4161786Slclee } 4162786Slclee 41633525Sshidokht rval = DK_TG_WRITE(cl, mboot, 0, cl->cl_sys_blocksize, tg_cookie); 41643525Sshidokht 41653525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 4166786Slclee #if defined(__i386) || defined(__amd64) 4167786Slclee if (rval == 0) { 4168786Slclee /* 4169786Slclee * mboot has been written successfully. 4170786Slclee * update the fdisk and vtoc tables in memory 4171786Slclee */ 41723525Sshidokht rval = cmlb_update_fdisk_and_vtoc(cl, tg_cookie); 41733525Sshidokht if ((cl->cl_f_geometry_is_valid == FALSE) || (rval != 0)) { 41743525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4175786Slclee kmem_free(mboot, (size_t)(sizeof (struct mboot))); 4176786Slclee return (rval); 4177786Slclee } 4178786Slclee } 41793525Sshidokht 41803525Sshidokht #ifdef __lock_lint 41813525Sshidokht cmlb_setup_default_geometry(cl, tg_cookie); 41823525Sshidokht #endif 41833525Sshidokht 4184786Slclee #else 4185786Slclee if (rval == 0) { 4186786Slclee /* 4187786Slclee * mboot has been written successfully. 4188786Slclee * set up the default geometry and VTOC 4189786Slclee */ 41903525Sshidokht if (cl->cl_blockcount <= DK_MAX_BLOCKS) 41913525Sshidokht cmlb_setup_default_geometry(cl, tg_cookie); 4192786Slclee } 4193786Slclee #endif 41943525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4195786Slclee kmem_free(mboot, (size_t)(sizeof (struct mboot))); 4196786Slclee return (rval); 4197786Slclee } 4198786Slclee 4199786Slclee 4200786Slclee /* 4201786Slclee * Function: cmlb_setup_default_geometry 4202786Slclee * 4203786Slclee * Description: This local utility routine sets the default geometry as part of 4204786Slclee * setting the device mboot. 4205786Slclee * 42063525Sshidokht * Arguments: 42073525Sshidokht * cl driver soft state (unit) structure 42083525Sshidokht * 42093525Sshidokht * tg_cookie cookie from target driver to be passed back to target 42103525Sshidokht * driver when we call back to it through tg_ops. 42113525Sshidokht * 4212786Slclee * 4213786Slclee * Note: This may be redundant with cmlb_build_default_label. 4214786Slclee */ 4215786Slclee static void 42163525Sshidokht cmlb_setup_default_geometry(struct cmlb_lun *cl, void *tg_cookie) 4217786Slclee { 4218786Slclee struct cmlb_geom pgeom; 4219786Slclee struct cmlb_geom *pgeomp = &pgeom; 4220786Slclee int ret; 4221786Slclee int geom_base_cap = 1; 4222786Slclee 4223786Slclee 42243525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 4225786Slclee 4226786Slclee /* zero out the soft state geometry and partition table. */ 42273525Sshidokht bzero(&cl->cl_g, sizeof (struct dk_geom)); 42283525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc)); 42293525Sshidokht bzero(cl->cl_map, NDKMAP * (sizeof (struct dk_map))); 4230786Slclee 4231786Slclee /* 4232786Slclee * For the rpm, we use the minimum for the disk. 4233786Slclee * For the head, cyl and number of sector per track, 4234786Slclee * if the capacity <= 1GB, head = 64, sect = 32. 4235786Slclee * else head = 255, sect 63 4236786Slclee * Note: the capacity should be equal to C*H*S values. 4237786Slclee * This will cause some truncation of size due to 4238786Slclee * round off errors. For CD-ROMs, this truncation can 4239786Slclee * have adverse side effects, so returning ncyl and 4240786Slclee * nhead as 1. The nsect will overflow for most of 4241786Slclee * CD-ROMs as nsect is of type ushort. 4242786Slclee */ 42433525Sshidokht if (cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8) { 4244786Slclee /* 4245786Slclee * newfs currently can not handle 255 ntracks for SPARC 4246786Slclee * so get the geometry from target driver instead of coming up 4247786Slclee * with one based on capacity. 4248786Slclee */ 42493525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 42503525Sshidokht ret = DK_TG_GETPHYGEOM(cl, pgeomp, tg_cookie); 42513525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 4252786Slclee 4253786Slclee if (ret == 0) { 4254786Slclee geom_base_cap = 0; 4255786Slclee } else { 42563525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 4257786Slclee "cmlb_setup_default_geometry: " 4258786Slclee "tg_getphygeom failed %d\n", ret); 4259786Slclee 4260786Slclee /* do default setting, geometry based on capacity */ 4261786Slclee } 4262786Slclee } 4263786Slclee 4264786Slclee if (geom_base_cap) { 42653525Sshidokht if (ISCD(cl)) { 42663525Sshidokht cl->cl_g.dkg_ncyl = 1; 42673525Sshidokht cl->cl_g.dkg_nhead = 1; 42683525Sshidokht cl->cl_g.dkg_nsect = cl->cl_blockcount; 42693525Sshidokht } else if (cl->cl_blockcount <= 0x1000) { 4270786Slclee /* Needed for unlabeled SCSI floppies. */ 42713525Sshidokht cl->cl_g.dkg_nhead = 2; 42723525Sshidokht cl->cl_g.dkg_ncyl = 80; 42733525Sshidokht cl->cl_g.dkg_pcyl = 80; 42743525Sshidokht cl->cl_g.dkg_nsect = cl->cl_blockcount / (2 * 80); 42753525Sshidokht } else if (cl->cl_blockcount <= 0x200000) { 42763525Sshidokht cl->cl_g.dkg_nhead = 64; 42773525Sshidokht cl->cl_g.dkg_nsect = 32; 42783525Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount / (64 * 32); 4279786Slclee } else { 42803525Sshidokht cl->cl_g.dkg_nhead = 255; 4281*6124Sshidokht 4282*6124Sshidokht cl->cl_g.dkg_nsect = ((cl->cl_blockcount + 4283*6124Sshidokht (UINT16_MAX * 255 * 63) - 1) / 4284*6124Sshidokht (UINT16_MAX * 255 * 63)) * 63; 4285*6124Sshidokht 4286*6124Sshidokht if (cl->cl_g.dkg_nsect == 0) 4287*6124Sshidokht cl->cl_g.dkg_nsect = (UINT16_MAX / 63) * 63; 4288*6124Sshidokht 4289*6124Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount / 4290*6124Sshidokht (255 * cl->cl_g.dkg_nsect); 4291786Slclee } 4292786Slclee 42933525Sshidokht cl->cl_g.dkg_acyl = 0; 42943525Sshidokht cl->cl_g.dkg_bcyl = 0; 42953525Sshidokht cl->cl_g.dkg_intrlv = 1; 42963525Sshidokht cl->cl_g.dkg_rpm = 200; 42973525Sshidokht if (cl->cl_g.dkg_pcyl == 0) 42983525Sshidokht cl->cl_g.dkg_pcyl = cl->cl_g.dkg_ncyl + 42993525Sshidokht cl->cl_g.dkg_acyl; 4300786Slclee } else { 43013525Sshidokht cl->cl_g.dkg_ncyl = (short)pgeomp->g_ncyl; 43023525Sshidokht cl->cl_g.dkg_acyl = pgeomp->g_acyl; 43033525Sshidokht cl->cl_g.dkg_nhead = pgeomp->g_nhead; 43043525Sshidokht cl->cl_g.dkg_nsect = pgeomp->g_nsect; 43053525Sshidokht cl->cl_g.dkg_intrlv = pgeomp->g_intrlv; 43063525Sshidokht cl->cl_g.dkg_rpm = pgeomp->g_rpm; 43073525Sshidokht cl->cl_g.dkg_pcyl = cl->cl_g.dkg_ncyl + cl->cl_g.dkg_acyl; 4308786Slclee } 4309786Slclee 43103525Sshidokht cl->cl_g.dkg_read_reinstruct = 0; 43113525Sshidokht cl->cl_g.dkg_write_reinstruct = 0; 43123525Sshidokht cl->cl_solaris_size = cl->cl_g.dkg_ncyl * 43133525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect; 43143525Sshidokht 43153525Sshidokht cl->cl_map['a'-'a'].dkl_cylno = 0; 43163525Sshidokht cl->cl_map['a'-'a'].dkl_nblk = cl->cl_solaris_size; 43173525Sshidokht 43183525Sshidokht cl->cl_map['c'-'a'].dkl_cylno = 0; 43193525Sshidokht cl->cl_map['c'-'a'].dkl_nblk = cl->cl_solaris_size; 43203525Sshidokht 43213525Sshidokht cl->cl_vtoc.v_part[2].p_tag = V_BACKUP; 43223525Sshidokht cl->cl_vtoc.v_part[2].p_flag = V_UNMNT; 43233525Sshidokht cl->cl_vtoc.v_nparts = V_NUMPAR; 43243525Sshidokht cl->cl_vtoc.v_version = V_VERSION; 43253525Sshidokht (void) sprintf((char *)cl->cl_asciilabel, "DEFAULT cyl %d alt %d" 43263525Sshidokht " hd %d sec %d", cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl, 43273525Sshidokht cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect); 43283525Sshidokht 43293525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 4330786Slclee } 4331786Slclee 4332786Slclee 4333786Slclee #if defined(__i386) || defined(__amd64) 4334786Slclee /* 4335786Slclee * Function: cmlb_update_fdisk_and_vtoc 4336786Slclee * 4337786Slclee * Description: This local utility routine updates the device fdisk and vtoc 4338786Slclee * as part of setting the device mboot. 4339786Slclee * 43403525Sshidokht * Arguments: 43413525Sshidokht * cl driver soft state (unit) structure 43423525Sshidokht * 43433525Sshidokht * tg_cookie cookie from target driver to be passed back to target 43443525Sshidokht * driver when we call back to it through tg_ops. 43453525Sshidokht * 4346786Slclee * 4347786Slclee * Return Code: 0 for success or errno-type return code. 4348786Slclee * 4349786Slclee * Note:x86: This looks like a duplicate of cmlb_validate_geometry(), but 4350786Slclee * these did exist separately in x86 sd.c. 4351786Slclee */ 4352786Slclee static int 43533525Sshidokht cmlb_update_fdisk_and_vtoc(struct cmlb_lun *cl, void *tg_cookie) 4354786Slclee { 4355786Slclee int count; 4356786Slclee int label_rc = 0; 4357786Slclee int fdisk_rval; 4358786Slclee diskaddr_t capacity; 4359786Slclee 43603525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 43613525Sshidokht 43623525Sshidokht if (cmlb_check_update_blockcount(cl, tg_cookie) != 0) 4363786Slclee return (EINVAL); 4364786Slclee 4365786Slclee #if defined(_SUNOS_VTOC_16) 4366786Slclee /* 4367786Slclee * Set up the "whole disk" fdisk partition; this should always 4368786Slclee * exist, regardless of whether the disk contains an fdisk table 4369786Slclee * or vtoc. 4370786Slclee */ 43713525Sshidokht cl->cl_map[P0_RAW_DISK].dkl_cylno = 0; 43723525Sshidokht cl->cl_map[P0_RAW_DISK].dkl_nblk = cl->cl_blockcount; 4373786Slclee #endif /* defined(_SUNOS_VTOC_16) */ 4374786Slclee 4375786Slclee /* 4376786Slclee * copy the lbasize and capacity so that if they're 43773525Sshidokht * reset while we're not holding the CMLB_MUTEX(cl), we will 43783525Sshidokht * continue to use valid values after the CMLB_MUTEX(cl) is 4379786Slclee * reacquired. 4380786Slclee */ 43813525Sshidokht capacity = cl->cl_blockcount; 4382786Slclee 4383786Slclee /* 4384786Slclee * refresh the logical and physical geometry caches. 4385786Slclee * (data from mode sense format/rigid disk geometry pages, 4386786Slclee * and scsi_ifgetcap("geometry"). 4387786Slclee */ 43883525Sshidokht cmlb_resync_geom_caches(cl, capacity, tg_cookie); 4389786Slclee 4390786Slclee /* 43913525Sshidokht * Only DIRECT ACCESS devices will have Scl labels. 43923525Sshidokht * CD's supposedly have a Scl label, too 4393786Slclee */ 43943525Sshidokht if (cl->cl_device_type == DTYPE_DIRECT || ISREMOVABLE(cl)) { 43953525Sshidokht fdisk_rval = cmlb_read_fdisk(cl, capacity, tg_cookie); 4396786Slclee if (fdisk_rval != 0) { 43973525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 4398786Slclee return (fdisk_rval); 4399786Slclee } 4400786Slclee 44013525Sshidokht if (cl->cl_solaris_size <= DK_LABEL_LOC) { 4402786Slclee /* 4403786Slclee * Found fdisk table but no Solaris partition entry, 4404786Slclee * so don't call cmlb_uselabel() and don't create 4405786Slclee * a default label. 4406786Slclee */ 4407786Slclee label_rc = 0; 44083525Sshidokht cl->cl_f_geometry_is_valid = TRUE; 4409786Slclee goto no_solaris_partition; 4410786Slclee } 4411786Slclee } else if (capacity < 0) { 44123525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 4413786Slclee return (EINVAL); 4414786Slclee } 4415786Slclee 4416786Slclee /* 4417786Slclee * For Removable media We reach here if we have found a 4418786Slclee * SOLARIS PARTITION. 44193525Sshidokht * If cl_f_geometry_is_valid is FALSE it indicates that the SOLARIS 4420786Slclee * PARTITION has changed from the previous one, hence we will setup a 4421786Slclee * default VTOC in this case. 4422786Slclee */ 44233525Sshidokht if (cl->cl_f_geometry_is_valid == FALSE) { 4424786Slclee /* if we get here it is writable */ 4425786Slclee /* we are called from SMBOOT, and after a write of fdisk */ 44263525Sshidokht cmlb_build_default_label(cl, tg_cookie); 4427786Slclee label_rc = 0; 4428786Slclee } 4429786Slclee 4430786Slclee no_solaris_partition: 4431786Slclee 4432786Slclee #if defined(_SUNOS_VTOC_16) 4433786Slclee /* 4434786Slclee * If we have valid geometry, set up the remaining fdisk partitions. 4435786Slclee * Note that dkl_cylno is not used for the fdisk map entries, so 4436786Slclee * we set it to an entirely bogus value. 4437786Slclee */ 4438786Slclee for (count = 0; count < FD_NUMPART; count++) { 44393525Sshidokht cl->cl_map[FDISK_P1 + count].dkl_cylno = -1; 44403525Sshidokht cl->cl_map[FDISK_P1 + count].dkl_nblk = 44413525Sshidokht cl->cl_fmap[count].fmap_nblk; 44423525Sshidokht cl->cl_offset[FDISK_P1 + count] = 44433525Sshidokht cl->cl_fmap[count].fmap_start; 4444786Slclee } 4445786Slclee #endif 4446786Slclee 4447786Slclee for (count = 0; count < NDKMAP; count++) { 4448786Slclee #if defined(_SUNOS_VTOC_8) 44493525Sshidokht struct dk_map *lp = &cl->cl_map[count]; 44503525Sshidokht cl->cl_offset[count] = 44513525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno; 4452786Slclee #elif defined(_SUNOS_VTOC_16) 44533525Sshidokht struct dkl_partition *vp = &cl->cl_vtoc.v_part[count]; 44543525Sshidokht cl->cl_offset[count] = vp->p_start + cl->cl_solaris_offset; 4455786Slclee #else 4456786Slclee #error "No VTOC format defined." 4457786Slclee #endif 4458786Slclee } 4459786Slclee 44603525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 4461786Slclee return (label_rc); 4462786Slclee } 4463786Slclee #endif 4464786Slclee 4465786Slclee #if defined(__i386) || defined(__amd64) 4466786Slclee static int 44673525Sshidokht cmlb_dkio_get_virtgeom(struct cmlb_lun *cl, caddr_t arg, int flag) 4468786Slclee { 4469786Slclee int err = 0; 4470786Slclee 4471786Slclee /* Return the driver's notion of the media's logical geometry */ 4472786Slclee struct dk_geom disk_geom; 4473786Slclee struct dk_geom *dkgp = &disk_geom; 4474786Slclee 44753525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 4476786Slclee /* 4477786Slclee * If there is no HBA geometry available, or 4478786Slclee * if the HBA returned us something that doesn't 4479786Slclee * really fit into an Int 13/function 8 geometry 4480786Slclee * result, just fail the ioctl. See PSARC 1998/313. 4481786Slclee */ 44823525Sshidokht if (cl->cl_lgeom.g_nhead == 0 || 44833525Sshidokht cl->cl_lgeom.g_nsect == 0 || 44843525Sshidokht cl->cl_lgeom.g_ncyl > 1024) { 44853525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4486786Slclee err = EINVAL; 4487786Slclee } else { 44883525Sshidokht dkgp->dkg_ncyl = cl->cl_lgeom.g_ncyl; 44893525Sshidokht dkgp->dkg_acyl = cl->cl_lgeom.g_acyl; 4490786Slclee dkgp->dkg_pcyl = dkgp->dkg_ncyl + dkgp->dkg_acyl; 44913525Sshidokht dkgp->dkg_nhead = cl->cl_lgeom.g_nhead; 44923525Sshidokht dkgp->dkg_nsect = cl->cl_lgeom.g_nsect; 4493786Slclee 44944177Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4495786Slclee if (ddi_copyout(dkgp, (void *)arg, 4496786Slclee sizeof (struct dk_geom), flag)) { 4497786Slclee err = EFAULT; 4498786Slclee } else { 4499786Slclee err = 0; 4500786Slclee } 4501786Slclee } 4502786Slclee return (err); 4503786Slclee } 4504786Slclee #endif 4505786Slclee 4506786Slclee #if defined(__i386) || defined(__amd64) 4507786Slclee static int 45083525Sshidokht cmlb_dkio_get_phygeom(struct cmlb_lun *cl, caddr_t arg, int flag) 4509786Slclee { 4510786Slclee int err = 0; 45113525Sshidokht diskaddr_t capacity; 4512786Slclee 4513786Slclee 4514786Slclee /* Return the driver's notion of the media physical geometry */ 4515786Slclee struct dk_geom disk_geom; 4516786Slclee struct dk_geom *dkgp = &disk_geom; 4517786Slclee 45183525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 45193525Sshidokht 45203525Sshidokht if (cl->cl_g.dkg_nhead != 0 && 45213525Sshidokht cl->cl_g.dkg_nsect != 0) { 4522786Slclee /* 4523786Slclee * We succeeded in getting a geometry, but 4524786Slclee * right now it is being reported as just the 4525786Slclee * Solaris fdisk partition, just like for 4526786Slclee * DKIOCGGEOM. We need to change that to be 4527786Slclee * correct for the entire disk now. 4528786Slclee */ 45293525Sshidokht bcopy(&cl->cl_g, dkgp, sizeof (*dkgp)); 4530786Slclee dkgp->dkg_acyl = 0; 45313525Sshidokht dkgp->dkg_ncyl = cl->cl_blockcount / 4532786Slclee (dkgp->dkg_nhead * dkgp->dkg_nsect); 4533786Slclee } else { 4534786Slclee bzero(dkgp, sizeof (struct dk_geom)); 4535786Slclee /* 4536786Slclee * This disk does not have a Solaris VTOC 4537786Slclee * so we must present a physical geometry 4538786Slclee * that will remain consistent regardless 4539786Slclee * of how the disk is used. This will ensure 4540786Slclee * that the geometry does not change regardless 4541786Slclee * of the fdisk partition type (ie. EFI, FAT32, 4542786Slclee * Solaris, etc). 4543786Slclee */ 45443525Sshidokht if (ISCD(cl)) { 45453525Sshidokht dkgp->dkg_nhead = cl->cl_pgeom.g_nhead; 45463525Sshidokht dkgp->dkg_nsect = cl->cl_pgeom.g_nsect; 45473525Sshidokht dkgp->dkg_ncyl = cl->cl_pgeom.g_ncyl; 45483525Sshidokht dkgp->dkg_acyl = cl->cl_pgeom.g_acyl; 4549786Slclee } else { 45503525Sshidokht /* 45513525Sshidokht * Invalid cl_blockcount can generate invalid 45523525Sshidokht * dk_geom and may result in division by zero 45533525Sshidokht * system failure. Should make sure blockcount 45543525Sshidokht * is valid before using it here. 45553525Sshidokht */ 45563525Sshidokht if (cl->cl_blockcount == 0) { 45573525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 45583525Sshidokht err = EIO; 45593525Sshidokht return (err); 45603525Sshidokht } 45613525Sshidokht /* 45623525Sshidokht * Refer to comments related to off-by-1 at the 45633525Sshidokht * header of this file 45643525Sshidokht */ 45653525Sshidokht if (cl->cl_alter_behavior & CMLB_OFF_BY_ONE) 45663525Sshidokht capacity = cl->cl_blockcount - 1; 45673525Sshidokht else 45683525Sshidokht capacity = cl->cl_blockcount; 45693525Sshidokht 45703525Sshidokht cmlb_convert_geometry(capacity, dkgp); 4571786Slclee dkgp->dkg_acyl = 0; 45723525Sshidokht dkgp->dkg_ncyl = capacity / 4573786Slclee (dkgp->dkg_nhead * dkgp->dkg_nsect); 4574786Slclee } 4575786Slclee } 4576786Slclee dkgp->dkg_pcyl = dkgp->dkg_ncyl + dkgp->dkg_acyl; 4577786Slclee 45784177Sshidokht mutex_exit(CMLB_MUTEX(cl)); 45794177Sshidokht if (ddi_copyout(dkgp, (void *)arg, sizeof (struct dk_geom), flag)) 4580786Slclee err = EFAULT; 45814177Sshidokht 4582786Slclee return (err); 4583786Slclee } 4584786Slclee #endif 4585786Slclee 4586786Slclee #if defined(__i386) || defined(__amd64) 4587786Slclee static int 45883525Sshidokht cmlb_dkio_partinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag) 4589786Slclee { 4590786Slclee int err = 0; 4591786Slclee 4592786Slclee /* 4593786Slclee * Return parameters describing the selected disk slice. 4594786Slclee * Note: this ioctl is for the intel platform only 4595786Slclee */ 4596786Slclee int part; 4597786Slclee 4598786Slclee part = CMLBPART(dev); 4599786Slclee 46003525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 46013525Sshidokht /* don't check cl_solaris_size for pN */ 46023525Sshidokht if (part < P0_RAW_DISK && cl->cl_solaris_size == 0) { 4603786Slclee err = EIO; 46044177Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4605786Slclee } else { 4606786Slclee struct part_info p; 4607786Slclee 46083525Sshidokht p.p_start = (daddr_t)cl->cl_offset[part]; 46093525Sshidokht p.p_length = (int)cl->cl_map[part].dkl_nblk; 46104177Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4611786Slclee #ifdef _MULTI_DATAMODEL 4612786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 4613786Slclee case DDI_MODEL_ILP32: 4614786Slclee { 4615786Slclee struct part_info32 p32; 4616786Slclee 4617786Slclee p32.p_start = (daddr32_t)p.p_start; 4618786Slclee p32.p_length = p.p_length; 4619786Slclee if (ddi_copyout(&p32, (void *)arg, 4620786Slclee sizeof (p32), flag)) 4621786Slclee err = EFAULT; 4622786Slclee break; 4623786Slclee } 4624786Slclee 4625786Slclee case DDI_MODEL_NONE: 4626786Slclee { 4627786Slclee if (ddi_copyout(&p, (void *)arg, sizeof (p), 4628786Slclee flag)) 4629786Slclee err = EFAULT; 4630786Slclee break; 4631786Slclee } 4632786Slclee } 4633786Slclee #else /* ! _MULTI_DATAMODEL */ 4634786Slclee if (ddi_copyout(&p, (void *)arg, sizeof (p), flag)) 4635786Slclee err = EFAULT; 4636786Slclee #endif /* _MULTI_DATAMODEL */ 4637786Slclee } 4638786Slclee return (err); 4639786Slclee } 4640786Slclee #endif 4641