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 /* 233525Sshidokht * Copyright 2007 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); 194786Slclee 195786Slclee #if defined(__i386) || defined(__amd64) 1963525Sshidokht static int cmlb_update_fdisk_and_vtoc(struct cmlb_lun *cl, void *tg_cookie); 197786Slclee #endif 198786Slclee 199786Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 200786Slclee static int cmlb_has_max_chs_vals(struct ipart *fdp); 201786Slclee #endif 202786Slclee 203786Slclee #if defined(_SUNOS_VTOC_16) 2043525Sshidokht static void cmlb_convert_geometry(diskaddr_t capacity, struct dk_geom *cl_g); 205786Slclee #endif 206786Slclee 2073525Sshidokht static int cmlb_dkio_get_geometry(struct cmlb_lun *cl, caddr_t arg, int flag, 2083525Sshidokht void *tg_cookie); 2093525Sshidokht static int cmlb_dkio_set_geometry(struct cmlb_lun *cl, caddr_t arg, int flag); 2103525Sshidokht static int cmlb_dkio_get_partition(struct cmlb_lun *cl, caddr_t arg, int flag, 2113525Sshidokht void *tg_cookie); 2123525Sshidokht static int cmlb_dkio_set_partition(struct cmlb_lun *cl, caddr_t arg, int flag); 2133525Sshidokht static int cmlb_dkio_get_efi(struct cmlb_lun *cl, caddr_t arg, int flag, 2143525Sshidokht void *tg_cookie); 2153525Sshidokht static int cmlb_dkio_set_efi(struct cmlb_lun *cl, dev_t dev, caddr_t arg, 2163525Sshidokht int flag, void *tg_cookie); 2173525Sshidokht static int cmlb_dkio_get_vtoc(struct cmlb_lun *cl, caddr_t arg, int flag, 2183525Sshidokht void *tg_cookie); 2193525Sshidokht static int cmlb_dkio_set_vtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, 2203525Sshidokht int flag, void *tg_cookie); 2213525Sshidokht static int cmlb_dkio_get_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, 2223525Sshidokht void *tg_cookie); 2233525Sshidokht static int cmlb_dkio_set_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, 2243525Sshidokht void *tg_cookie); 2253525Sshidokht static int cmlb_dkio_partition(struct cmlb_lun *cl, caddr_t arg, int flag, 2263525Sshidokht void *tg_cookie); 227786Slclee 228786Slclee #if defined(__i386) || defined(__amd64) 2293525Sshidokht static int cmlb_dkio_get_virtgeom(struct cmlb_lun *cl, caddr_t arg, int flag); 2303525Sshidokht static int cmlb_dkio_get_phygeom(struct cmlb_lun *cl, caddr_t arg, int flag); 2313525Sshidokht static int cmlb_dkio_partinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg, 232786Slclee int flag); 233786Slclee #endif 234786Slclee 2353525Sshidokht static void cmlb_dbg(uint_t comp, struct cmlb_lun *cl, const char *fmt, ...); 236786Slclee static void cmlb_v_log(dev_info_t *dev, char *label, uint_t level, 237786Slclee const char *fmt, va_list ap); 238786Slclee static void cmlb_log(dev_info_t *dev, char *label, uint_t level, 239786Slclee const char *fmt, ...); 240786Slclee 241786Slclee int 242786Slclee _init(void) 243786Slclee { 244786Slclee mutex_init(&cmlb_log_mutex, NULL, MUTEX_DRIVER, NULL); 245786Slclee return (mod_install(&modlinkage)); 246786Slclee } 247786Slclee 248786Slclee int 249786Slclee _info(struct modinfo *modinfop) 250786Slclee { 251786Slclee return (mod_info(&modlinkage, modinfop)); 252786Slclee } 253786Slclee 254786Slclee int 255786Slclee _fini(void) 256786Slclee { 257786Slclee int err; 258786Slclee 259786Slclee if ((err = mod_remove(&modlinkage)) != 0) { 260786Slclee return (err); 261786Slclee } 262786Slclee 263786Slclee mutex_destroy(&cmlb_log_mutex); 264786Slclee return (err); 265786Slclee } 266786Slclee 267786Slclee /* 268786Slclee * cmlb_dbg is used for debugging to log additional info 269786Slclee * Level of output is controlled via cmlb_level_mask setting. 270786Slclee */ 271786Slclee static void 2723525Sshidokht cmlb_dbg(uint_t comp, struct cmlb_lun *cl, const char *fmt, ...) 273786Slclee { 274786Slclee va_list ap; 275786Slclee dev_info_t *dev; 276786Slclee uint_t level_mask = 0; 277786Slclee 2783525Sshidokht ASSERT(cl != NULL); 2793525Sshidokht dev = CMLB_DEVINFO(cl); 280786Slclee ASSERT(dev != NULL); 281786Slclee /* 282786Slclee * Filter messages based on the global component and level masks, 2833525Sshidokht * also print if cl matches the value of cmlb_debug_cl, or if 2843525Sshidokht * cmlb_debug_cl is set to NULL. 285786Slclee */ 286786Slclee if (comp & CMLB_TRACE) 287786Slclee level_mask |= CMLB_LOGMASK_TRACE; 288786Slclee 289786Slclee if (comp & CMLB_INFO) 290786Slclee level_mask |= CMLB_LOGMASK_INFO; 291786Slclee 292786Slclee if (comp & CMLB_ERROR) 293786Slclee level_mask |= CMLB_LOGMASK_ERROR; 294786Slclee 295786Slclee if ((cmlb_level_mask & level_mask) && 2963525Sshidokht ((cmlb_debug_cl == NULL) || (cmlb_debug_cl == cl))) { 297786Slclee va_start(ap, fmt); 2983525Sshidokht cmlb_v_log(dev, CMLB_LABEL(cl), CE_CONT, fmt, ap); 299786Slclee va_end(ap); 300786Slclee } 301786Slclee } 302786Slclee 303786Slclee /* 304786Slclee * cmlb_log is basically a duplicate of scsi_log. It is redefined here 305786Slclee * so that this module does not depend on scsi module. 306786Slclee */ 307786Slclee static void 308786Slclee cmlb_log(dev_info_t *dev, char *label, uint_t level, const char *fmt, ...) 309786Slclee { 310786Slclee va_list ap; 311786Slclee 312786Slclee va_start(ap, fmt); 313786Slclee cmlb_v_log(dev, label, level, fmt, ap); 314786Slclee va_end(ap); 315786Slclee } 316786Slclee 317786Slclee static void 318786Slclee cmlb_v_log(dev_info_t *dev, char *label, uint_t level, const char *fmt, 319786Slclee va_list ap) 320786Slclee { 321786Slclee static char name[256]; 322786Slclee int log_only = 0; 323786Slclee int boot_only = 0; 324786Slclee int console_only = 0; 325786Slclee 326786Slclee mutex_enter(&cmlb_log_mutex); 327786Slclee 328786Slclee if (dev) { 329786Slclee if (level == CE_PANIC || level == CE_WARN || 330786Slclee level == CE_NOTE) { 331786Slclee (void) sprintf(name, "%s (%s%d):\n", 332786Slclee ddi_pathname(dev, cmlb_log_buffer), 333786Slclee label, ddi_get_instance(dev)); 334786Slclee } else { 335786Slclee name[0] = '\0'; 336786Slclee } 337786Slclee } else { 338786Slclee (void) sprintf(name, "%s:", label); 339786Slclee } 340786Slclee 341786Slclee (void) vsprintf(cmlb_log_buffer, fmt, ap); 342786Slclee 343786Slclee switch (cmlb_log_buffer[0]) { 344786Slclee case '!': 345786Slclee log_only = 1; 346786Slclee break; 347786Slclee case '?': 348786Slclee boot_only = 1; 349786Slclee break; 350786Slclee case '^': 351786Slclee console_only = 1; 352786Slclee break; 353786Slclee } 354786Slclee 355786Slclee switch (level) { 356786Slclee case CE_NOTE: 357786Slclee level = CE_CONT; 358786Slclee /* FALLTHROUGH */ 359786Slclee case CE_CONT: 360786Slclee case CE_WARN: 361786Slclee case CE_PANIC: 362786Slclee if (boot_only) { 363786Slclee cmn_err(level, "?%s\t%s", name, &cmlb_log_buffer[1]); 364786Slclee } else if (console_only) { 365786Slclee cmn_err(level, "^%s\t%s", name, &cmlb_log_buffer[1]); 366786Slclee } else if (log_only) { 367786Slclee cmn_err(level, "!%s\t%s", name, &cmlb_log_buffer[1]); 368786Slclee } else { 369786Slclee cmn_err(level, "%s\t%s", name, cmlb_log_buffer); 370786Slclee } 371786Slclee break; 372786Slclee case CE_IGNORE: 373786Slclee break; 374786Slclee default: 375786Slclee cmn_err(CE_CONT, "^DEBUG: %s\t%s", name, cmlb_log_buffer); 376786Slclee break; 377786Slclee } 378786Slclee mutex_exit(&cmlb_log_mutex); 379786Slclee } 380786Slclee 381786Slclee 382786Slclee /* 383786Slclee * cmlb_alloc_handle: 384786Slclee * 385786Slclee * Allocates a handle. 386786Slclee * 387786Slclee * Arguments: 388786Slclee * cmlbhandlep pointer to handle 389786Slclee * 390786Slclee * Notes: 391786Slclee * Allocates a handle and stores the allocated handle in the area 392786Slclee * pointed to by cmlbhandlep 393786Slclee * 394786Slclee * Context: 395786Slclee * Kernel thread only (can sleep). 396786Slclee */ 397786Slclee void 398786Slclee cmlb_alloc_handle(cmlb_handle_t *cmlbhandlep) 399786Slclee { 4003525Sshidokht struct cmlb_lun *cl; 4013525Sshidokht 4023525Sshidokht cl = kmem_zalloc(sizeof (struct cmlb_lun), KM_SLEEP); 403786Slclee ASSERT(cmlbhandlep != NULL); 404786Slclee 4053525Sshidokht cl->cl_state = CMLB_INITED; 4063525Sshidokht cl->cl_def_labeltype = CMLB_LABEL_UNDEF; 4073525Sshidokht mutex_init(CMLB_MUTEX(cl), NULL, MUTEX_DRIVER, NULL); 4083525Sshidokht 4093525Sshidokht *cmlbhandlep = (cmlb_handle_t)(cl); 410786Slclee } 411786Slclee 412786Slclee /* 413786Slclee * cmlb_free_handle 414786Slclee * 415786Slclee * Frees handle. 416786Slclee * 417786Slclee * Arguments: 418786Slclee * cmlbhandlep pointer to handle 419786Slclee */ 420786Slclee void 421786Slclee cmlb_free_handle(cmlb_handle_t *cmlbhandlep) 422786Slclee { 4233525Sshidokht struct cmlb_lun *cl; 4243525Sshidokht 4253525Sshidokht cl = (struct cmlb_lun *)*cmlbhandlep; 4263525Sshidokht if (cl != NULL) { 4273525Sshidokht mutex_destroy(CMLB_MUTEX(cl)); 4283525Sshidokht kmem_free(cl, sizeof (struct cmlb_lun)); 429786Slclee } 430786Slclee 431786Slclee } 432786Slclee 433786Slclee /* 434786Slclee * cmlb_attach: 435786Slclee * 436786Slclee * Attach handle to device, create minor nodes for device. 437786Slclee * 438786Slclee * Arguments: 439786Slclee * devi pointer to device's dev_info structure. 440786Slclee * tgopsp pointer to array of functions cmlb can use to callback 441786Slclee * to target driver. 442786Slclee * 443786Slclee * device_type Peripheral device type as defined in 444786Slclee * scsi/generic/inquiry.h 445786Slclee * 446786Slclee * is_removable whether or not device is removable. 447786Slclee * 0 non-removable, 1 removable. 448786Slclee * 4493525Sshidokht * is_hotpluggable whether or not device is hotpluggable. 4503525Sshidokht * 0 non-hotpluggable, 1 hotpluggable. 4513525Sshidokht * 452786Slclee * node_type minor node type (as used by ddi_create_minor_node) 453786Slclee * 454786Slclee * alter_behavior 455786Slclee * bit flags: 456786Slclee * 457786Slclee * CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT: create 458786Slclee * an alternate slice for the default label, if 459786Slclee * device type is DTYPE_DIRECT an architectures default 460786Slclee * label type is VTOC16. 461786Slclee * Otherwise alternate slice will no be created. 462786Slclee * 463786Slclee * 464786Slclee * CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8: report a default 465786Slclee * geometry and label for DKIOCGGEOM and DKIOCGVTOC 466786Slclee * on architecture with VTOC8 label types. 467786Slclee * 4683525Sshidokht * CMLB_OFF_BY_ONE: do the workaround for legacy off-by- 4693525Sshidokht * one bug in obtaining capacity (in sd): 4703525Sshidokht * SCSI READ_CAPACITY command returns the LBA number of the 4713525Sshidokht * last logical block, but sd once treated this number as 4723525Sshidokht * disks' capacity on x86 platform. And LBAs are addressed 4733525Sshidokht * based 0. So the last block was lost on x86 platform. 4743525Sshidokht * 4753525Sshidokht * Now, we remove this workaround. In order for present sd 4763525Sshidokht * driver to work with disks which are labeled/partitioned 4773525Sshidokht * via previous sd, we add workaround as follows: 4783525Sshidokht * 4793525Sshidokht * 1) Locate backup EFI label: cmlb searches the next to 4803525Sshidokht * last 4813525Sshidokht * block for backup EFI label. If fails, it will 4823525Sshidokht * turn to the last block for backup EFI label; 4833525Sshidokht * 4843525Sshidokht * 2) Clear backup EFI label: cmlb first search the last 4853525Sshidokht * block for backup EFI label, and will search the 4863525Sshidokht * next to last block only if failed for the last 4873525Sshidokht * block. 4883525Sshidokht * 4893525Sshidokht * 3) Calculate geometry:refer to cmlb_convert_geometry() 4903525Sshidokht * If capacity increasing by 1 causes disks' capacity 4913525Sshidokht * to cross over the limits in table CHS_values, 4923525Sshidokht * geometry info will change. This will raise an issue: 4933525Sshidokht * In case that primary VTOC label is destroyed, format 4943525Sshidokht * commandline can restore it via backup VTOC labels. 4953525Sshidokht * And format locates backup VTOC labels by use of 4963525Sshidokht * geometry. So changing geometry will 4973525Sshidokht * prevent format from finding backup VTOC labels. To 4983525Sshidokht * eliminate this side effect for compatibility, 4993525Sshidokht * sd uses (capacity -1) to calculate geometry; 5003525Sshidokht * 5013525Sshidokht * 4) 1TB disks: some important data structures use 5023525Sshidokht * 32-bit signed long/int (for example, daddr_t), 5033525Sshidokht * so that sd doesn't support a disk with capacity 5043525Sshidokht * larger than 1TB on 32-bit platform. However, 5053525Sshidokht * for exactly 1TB disk, it was treated as (1T - 512)B 5063525Sshidokht * in the past, and could have valid Solaris 5073525Sshidokht * partitions. To workaround this, if an exactly 1TB 5083525Sshidokht * disk has Solaris fdisk partition, it will be allowed 5093525Sshidokht * to work with sd. 5103525Sshidokht * 5113525Sshidokht * 512786Slclee * 513786Slclee * cmlbhandle cmlb handle associated with device 514786Slclee * 5153525Sshidokht * tg_cookie cookie from target driver to be passed back to target 5163525Sshidokht * driver when we call back to it through tg_ops. 5173525Sshidokht * 518786Slclee * Notes: 519786Slclee * Assumes a default label based on capacity for non-removable devices. 520786Slclee * If capacity > 1TB, EFI is assumed otherwise VTOC (default VTOC 521786Slclee * for the architecture). 522786Slclee * 523786Slclee * For removable devices, default label type is assumed to be VTOC 524786Slclee * type. Create minor nodes based on a default label type. 525786Slclee * Label on the media is not validated. 526786Slclee * minor number consists of: 527786Slclee * if _SUNOS_VTOC_8 is defined 528786Slclee * lowest 3 bits is taken as partition number 529786Slclee * the rest is instance number 530786Slclee * if _SUNOS_VTOC_16 is defined 531786Slclee * lowest 6 bits is taken as partition number 532786Slclee * the rest is instance number 533786Slclee * 534786Slclee * 535786Slclee * Return values: 536786Slclee * 0 Success 537786Slclee * ENXIO creating minor nodes failed. 5383525Sshidokht * EINVAL invalid arg, unsupported tg_ops version 539786Slclee */ 540786Slclee int 541786Slclee cmlb_attach(dev_info_t *devi, cmlb_tg_ops_t *tgopsp, int device_type, 5423525Sshidokht int is_removable, int is_hotpluggable, char *node_type, 5433525Sshidokht int alter_behavior, cmlb_handle_t cmlbhandle, void *tg_cookie) 544786Slclee { 545786Slclee 5463525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 547786Slclee diskaddr_t cap; 548786Slclee int status; 549786Slclee 5503525Sshidokht if (tgopsp->tg_version < TG_DK_OPS_VERSION_1) 5513525Sshidokht return (EINVAL); 5523525Sshidokht 5533525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 5543525Sshidokht 5553525Sshidokht CMLB_DEVINFO(cl) = devi; 5563525Sshidokht cl->cmlb_tg_ops = tgopsp; 5573525Sshidokht cl->cl_device_type = device_type; 5583525Sshidokht cl->cl_is_removable = is_removable; 5593525Sshidokht cl->cl_is_hotpluggable = is_hotpluggable; 5603525Sshidokht cl->cl_node_type = node_type; 5613525Sshidokht cl->cl_sys_blocksize = DEV_BSIZE; 5623525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 5633525Sshidokht cl->cl_def_labeltype = CMLB_LABEL_VTOC; 5643525Sshidokht cl->cl_alter_behavior = alter_behavior; 5653525Sshidokht cl->cl_reserved = -1; 566786Slclee 567786Slclee if (is_removable != 0) { 5683525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 5693525Sshidokht status = DK_TG_GETCAP(cl, &cap, tg_cookie); 5703525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 571786Slclee if (status == 0 && cap > DK_MAX_BLOCKS) { 572786Slclee /* set default EFI if > 1TB */ 5733525Sshidokht cl->cl_def_labeltype = CMLB_LABEL_EFI; 574786Slclee } 575786Slclee } 576786Slclee 577786Slclee /* create minor nodes based on default label type */ 5783525Sshidokht cl->cl_last_labeltype = CMLB_LABEL_UNDEF; 5793525Sshidokht cl->cl_cur_labeltype = CMLB_LABEL_UNDEF; 5803525Sshidokht 5813525Sshidokht if (cmlb_create_minor_nodes(cl) != 0) { 5823525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 583786Slclee return (ENXIO); 584786Slclee } 585786Slclee 5863525Sshidokht cl->cl_state = CMLB_ATTACHED; 5873525Sshidokht 5883525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 589786Slclee return (0); 590786Slclee } 591786Slclee 592786Slclee /* 593786Slclee * cmlb_detach: 594786Slclee * 595786Slclee * Invalidate in-core labeling data and remove all minor nodes for 596786Slclee * the device associate with handle. 597786Slclee * 598786Slclee * Arguments: 599786Slclee * cmlbhandle cmlb handle associated with device. 600786Slclee * 6013525Sshidokht * tg_cookie cookie from target driver to be passed back to target 6023525Sshidokht * driver when we call back to it through tg_ops. 6033525Sshidokht * 604786Slclee */ 6053525Sshidokht /*ARGSUSED1*/ 606786Slclee void 6073525Sshidokht cmlb_detach(cmlb_handle_t cmlbhandle, void *tg_cookie) 608786Slclee { 6093525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 6103525Sshidokht 6113525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 6123525Sshidokht cl->cl_def_labeltype = CMLB_LABEL_UNDEF; 6133525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 6143525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL); 6153525Sshidokht cl->cl_state = CMLB_INITED; 6163525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 617786Slclee } 618786Slclee 619786Slclee /* 620786Slclee * cmlb_validate: 621786Slclee * 622786Slclee * Validates label. 623786Slclee * 624786Slclee * Arguments 625786Slclee * cmlbhandle cmlb handle associated with device. 626786Slclee * 6273525Sshidokht * flags operation flags. used for verbosity control 6283525Sshidokht * 6293525Sshidokht * tg_cookie cookie from target driver to be passed back to target 6303525Sshidokht * driver when we call back to it through tg_ops. 6313525Sshidokht * 6323525Sshidokht * 633786Slclee * Notes: 634786Slclee * If new label type is different from the current, adjust minor nodes 635786Slclee * accordingly. 636786Slclee * 637786Slclee * Return values: 638786Slclee * 0 success 639786Slclee * Note: having fdisk but no solaris partition is assumed 640786Slclee * success. 641786Slclee * 642786Slclee * ENOMEM memory allocation failed 643786Slclee * EIO i/o errors during read or get capacity 644786Slclee * EACCESS reservation conflicts 645786Slclee * EINVAL label was corrupt, or no default label was assumed 646786Slclee * ENXIO invalid handle 647786Slclee */ 648786Slclee int 6493525Sshidokht cmlb_validate(cmlb_handle_t cmlbhandle, int flags, void *tg_cookie) 650786Slclee { 6513525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 652786Slclee int rval; 653786Slclee int ret = 0; 654786Slclee 655786Slclee /* 6563525Sshidokht * Temp work-around checking cl for NULL since there is a bug 657786Slclee * in sd_detach calling this routine from taskq_dispatch 658786Slclee * inited function. 659786Slclee */ 6603525Sshidokht if (cl == NULL) 661786Slclee return (ENXIO); 662786Slclee 6633525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 6643525Sshidokht if (cl->cl_state < CMLB_ATTACHED) { 6653525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 666786Slclee return (ENXIO); 667786Slclee } 668786Slclee 6693525Sshidokht rval = cmlb_validate_geometry((struct cmlb_lun *)cmlbhandle, 1, 6703525Sshidokht flags, tg_cookie); 671786Slclee 672786Slclee if (rval == ENOTSUP) { 6733525Sshidokht if (cl->cl_f_geometry_is_valid == TRUE) { 6743525Sshidokht cl->cl_cur_labeltype = CMLB_LABEL_EFI; 675786Slclee ret = 0; 676786Slclee } else { 677786Slclee ret = EINVAL; 678786Slclee } 679786Slclee } else { 680786Slclee ret = rval; 681786Slclee if (ret == 0) 6823525Sshidokht cl->cl_cur_labeltype = CMLB_LABEL_VTOC; 683786Slclee } 684786Slclee 685786Slclee if (ret == 0) 6863525Sshidokht (void) cmlb_create_minor_nodes(cl); 6873525Sshidokht 6883525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 689786Slclee return (ret); 690786Slclee } 691786Slclee 692786Slclee /* 693786Slclee * cmlb_invalidate: 694786Slclee * Invalidate in core label data 695786Slclee * 696786Slclee * Arguments: 697786Slclee * cmlbhandle cmlb handle associated with device. 6983525Sshidokht * tg_cookie cookie from target driver to be passed back to target 6993525Sshidokht * driver when we call back to it through tg_ops. 700786Slclee */ 7013525Sshidokht /*ARGSUSED1*/ 702786Slclee void 7033525Sshidokht cmlb_invalidate(cmlb_handle_t cmlbhandle, void *tg_cookie) 704786Slclee { 7053525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 7063525Sshidokht 7073525Sshidokht if (cl == NULL) 708786Slclee return; 709786Slclee 7103525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 7113525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 7123525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 713786Slclee } 714786Slclee 715786Slclee /* 7163525Sshidokht * cmlb_is_valid 7173525Sshidokht * Get status on whether the incore label/geom data is valid 7183525Sshidokht * 7193525Sshidokht * Arguments: 7203525Sshidokht * cmlbhandle cmlb handle associated with device. 7213525Sshidokht * 7223525Sshidokht * Return values: 7233525Sshidokht * TRUE if incore label/geom data is valid. 7243525Sshidokht * FALSE otherwise. 7253525Sshidokht * 7263525Sshidokht */ 7273525Sshidokht 7283525Sshidokht 7293525Sshidokht int 7303525Sshidokht cmlb_is_valid(cmlb_handle_t cmlbhandle) 7313525Sshidokht { 7323525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 7333525Sshidokht 7343525Sshidokht if (cmlbhandle == NULL) 7353525Sshidokht return (FALSE); 7363525Sshidokht 7373525Sshidokht return (cl->cl_f_geometry_is_valid); 7383525Sshidokht 7393525Sshidokht } 7403525Sshidokht 7413525Sshidokht 7423525Sshidokht 7433525Sshidokht /* 744786Slclee * cmlb_close: 745786Slclee * 746786Slclee * Close the device, revert to a default label minor node for the device, 747786Slclee * if it is removable. 748786Slclee * 749786Slclee * Arguments: 750786Slclee * cmlbhandle cmlb handle associated with device. 751786Slclee * 7523525Sshidokht * tg_cookie cookie from target driver to be passed back to target 7533525Sshidokht * driver when we call back to it through tg_ops. 754786Slclee * Return values: 755786Slclee * 0 Success 756786Slclee * ENXIO Re-creating minor node failed. 757786Slclee */ 7583525Sshidokht /*ARGSUSED1*/ 759786Slclee int 7603525Sshidokht cmlb_close(cmlb_handle_t cmlbhandle, void *tg_cookie) 761786Slclee { 7623525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 7633525Sshidokht 7643525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 7653525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 766786Slclee 767786Slclee /* revert to default minor node for this device */ 7683525Sshidokht if (ISREMOVABLE(cl)) { 7693525Sshidokht cl->cl_cur_labeltype = CMLB_LABEL_UNDEF; 7703525Sshidokht (void) cmlb_create_minor_nodes(cl); 771786Slclee } 772786Slclee 7733525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 774786Slclee return (0); 775786Slclee } 776786Slclee 777786Slclee /* 778786Slclee * cmlb_get_devid_block: 779786Slclee * get the block number where device id is stored. 780786Slclee * 781786Slclee * Arguments: 782786Slclee * cmlbhandle cmlb handle associated with device. 783786Slclee * devidblockp pointer to block number. 7843525Sshidokht * tg_cookie cookie from target driver to be passed back to target 7853525Sshidokht * driver when we call back to it through tg_ops. 786786Slclee * 787786Slclee * Notes: 788786Slclee * It stores the block number of device id in the area pointed to 789786Slclee * by devidblockp. 790786Slclee * with the block number of device id. 791786Slclee * 792786Slclee * Return values: 793786Slclee * 0 success 794786Slclee * EINVAL device id does not apply to current label type. 795786Slclee */ 7963525Sshidokht /*ARGSUSED2*/ 797786Slclee int 7983525Sshidokht cmlb_get_devid_block(cmlb_handle_t cmlbhandle, diskaddr_t *devidblockp, 7993525Sshidokht void *tg_cookie) 800786Slclee { 801786Slclee daddr_t spc, blk, head, cyl; 8023525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 8033525Sshidokht 8043525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 8053525Sshidokht if (cl->cl_state < CMLB_ATTACHED) { 8063525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 8073525Sshidokht return (EINVAL); 8083525Sshidokht } 8093525Sshidokht 8103525Sshidokht if ((cl->cl_f_geometry_is_valid == FALSE) || 8113525Sshidokht (cl->cl_solaris_size < DK_LABEL_LOC)) { 8123525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 813786Slclee return (EINVAL); 814786Slclee } 815786Slclee 8163525Sshidokht 8173525Sshidokht if (cl->cl_cur_labeltype == CMLB_LABEL_EFI) { 8183525Sshidokht if (cl->cl_reserved != -1) { 8193525Sshidokht blk = cl->cl_map[cl->cl_reserved].dkl_cylno; 8203525Sshidokht } else { 8213525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 8223525Sshidokht return (EINVAL); 8233525Sshidokht } 8243525Sshidokht } else { 825786Slclee /* this geometry doesn't allow us to write a devid */ 8263525Sshidokht if (cl->cl_g.dkg_acyl < 2) { 8273525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 828786Slclee return (EINVAL); 829786Slclee } 830786Slclee 831786Slclee /* 832786Slclee * Subtract 2 guarantees that the next to last cylinder 833786Slclee * is used 834786Slclee */ 8353525Sshidokht cyl = cl->cl_g.dkg_ncyl + cl->cl_g.dkg_acyl - 2; 8363525Sshidokht spc = cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect; 8373525Sshidokht head = cl->cl_g.dkg_nhead - 1; 8383525Sshidokht blk = (cyl * (spc - cl->cl_g.dkg_apc)) + 8393525Sshidokht (head * cl->cl_g.dkg_nsect) + 1; 840786Slclee } 8413525Sshidokht 842786Slclee *devidblockp = blk; 8433525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 844786Slclee return (0); 845786Slclee } 846786Slclee 847786Slclee /* 848786Slclee * cmlb_partinfo: 849786Slclee * Get partition info for specified partition number. 850786Slclee * 851786Slclee * Arguments: 852786Slclee * cmlbhandle cmlb handle associated with device. 853786Slclee * part partition number 854786Slclee * nblocksp pointer to number of blocks 855786Slclee * startblockp pointer to starting block 856786Slclee * partnamep pointer to name of partition 857786Slclee * tagp pointer to tag info 8583525Sshidokht * tg_cookie cookie from target driver to be passed back to target 8593525Sshidokht * driver when we call back to it through tg_ops. 860786Slclee * 861786Slclee * 862786Slclee * Notes: 863786Slclee * If in-core label is not valid, this functions tries to revalidate 864786Slclee * the label. If label is valid, it stores the total number of blocks 865786Slclee * in this partition in the area pointed to by nblocksp, starting 866786Slclee * block number in area pointed to by startblockp, pointer to partition 867786Slclee * name in area pointed to by partnamep, and tag value in area 868786Slclee * pointed by tagp. 869786Slclee * For EFI labels, tag value will be set to 0. 870786Slclee * 871786Slclee * For all nblocksp, startblockp and partnamep, tagp, a value of NULL 872786Slclee * indicates the corresponding info is not requested. 873786Slclee * 874786Slclee * 875786Slclee * Return values: 876786Slclee * 0 success 877786Slclee * EINVAL no valid label or requested partition number is invalid. 878786Slclee * 879786Slclee */ 880786Slclee int 881786Slclee cmlb_partinfo(cmlb_handle_t cmlbhandle, int part, diskaddr_t *nblocksp, 8823525Sshidokht diskaddr_t *startblockp, char **partnamep, uint16_t *tagp, void *tg_cookie) 883786Slclee { 884786Slclee 8853525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 886786Slclee int rval; 887786Slclee 8883525Sshidokht ASSERT(cl != NULL); 8893525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 8903525Sshidokht if (cl->cl_state < CMLB_ATTACHED) { 8913525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 892786Slclee return (EINVAL); 893786Slclee } 894786Slclee 895786Slclee if (part < 0 || part >= MAXPART) { 896786Slclee rval = EINVAL; 897786Slclee } else { 8983525Sshidokht if (cl->cl_f_geometry_is_valid == FALSE) 8993525Sshidokht (void) cmlb_validate_geometry((struct cmlb_lun *)cl, 0, 9003525Sshidokht 0, tg_cookie); 9013525Sshidokht 9023525Sshidokht if ((cl->cl_f_geometry_is_valid == FALSE) || 9033525Sshidokht (part < NDKMAP && cl->cl_solaris_size == 0)) { 904786Slclee rval = EINVAL; 905786Slclee } else { 906786Slclee if (startblockp != NULL) 9073525Sshidokht *startblockp = (diskaddr_t)cl->cl_offset[part]; 908786Slclee 909786Slclee if (nblocksp != NULL) 910786Slclee *nblocksp = (diskaddr_t) 9113525Sshidokht cl->cl_map[part].dkl_nblk; 912786Slclee 913786Slclee if (tagp != NULL) 9143525Sshidokht if (cl->cl_cur_labeltype == CMLB_LABEL_EFI) 915786Slclee *tagp = V_UNASSIGNED; 916786Slclee else 9173525Sshidokht *tagp = cl->cl_vtoc.v_part[part].p_tag; 918786Slclee rval = 0; 919786Slclee } 920786Slclee 921786Slclee /* consistent with behavior of sd for getting minor name */ 922786Slclee if (partnamep != NULL) 923786Slclee *partnamep = dk_minor_data[part].name; 924786Slclee 925786Slclee } 926786Slclee 9273525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 928786Slclee return (rval); 929786Slclee } 930786Slclee 9313525Sshidokht /* Caller should make sure Test Unit Ready succeeds before calling this. */ 9323525Sshidokht /*ARGSUSED*/ 933786Slclee int 934786Slclee cmlb_ioctl(cmlb_handle_t cmlbhandle, dev_t dev, int cmd, intptr_t arg, 9353525Sshidokht int flag, cred_t *cred_p, int *rval_p, void *tg_cookie) 936786Slclee { 937786Slclee 938786Slclee int err; 9393525Sshidokht struct cmlb_lun *cl; 9403525Sshidokht int status; 9413525Sshidokht 9423525Sshidokht cl = (struct cmlb_lun *)cmlbhandle; 9433525Sshidokht 9443525Sshidokht ASSERT(cl != NULL); 9453525Sshidokht 9463525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 9473525Sshidokht if (cl->cl_state < CMLB_ATTACHED) { 9483525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 949786Slclee return (EIO); 950786Slclee } 951786Slclee 952786Slclee switch (cmd) { 953786Slclee case DKIOCSVTOC: 9543525Sshidokht case DKIOCSGEOM: 955786Slclee case DKIOCSETEFI: 956786Slclee case DKIOCSMBOOT: 957786Slclee break; 958786Slclee default: 9593903Sshidokht status = cmlb_validate_geometry(cl, 1, CMLB_SILENT, 9603903Sshidokht tg_cookie); 9613525Sshidokht 962786Slclee /* 9633525Sshidokht * VTOC related ioctls except SVTOC/SGEOM should 9643525Sshidokht * fail if > 1TB disk and there is not already a VTOC 9653525Sshidokht * on the disk.i.e either EFI or blank 9663525Sshidokht * 9673525Sshidokht * PHYGEOM AND VIRTGEOM succeeds when disk is 9683525Sshidokht * EFI labeled but <1TB 969786Slclee */ 9703525Sshidokht 9713525Sshidokht if (status == ENOTSUP && 9723525Sshidokht cl->cl_f_geometry_is_valid == FALSE) { 973786Slclee switch (cmd) { 974786Slclee case DKIOCGAPART: 975786Slclee case DKIOCGGEOM: 976786Slclee case DKIOCGVTOC: 977786Slclee case DKIOCSAPART: 9783525Sshidokht case DKIOCG_PHYGEOM: 9793525Sshidokht case DKIOCG_VIRTGEOM: 9803525Sshidokht 9813525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 982786Slclee return (ENOTSUP); 983786Slclee } 9843525Sshidokht } else { 9853525Sshidokht if ((cl->cl_f_geometry_is_valid == TRUE) && 9863525Sshidokht (cl->cl_solaris_size > 0)) { 9873525Sshidokht if (cl->cl_vtoc.v_sanity != VTOC_SANE) { 9883525Sshidokht /* 9893525Sshidokht * it is EFI, so return ENOTSUP for 9903525Sshidokht * these 9913525Sshidokht */ 9923525Sshidokht switch (cmd) { 9933525Sshidokht case DKIOCGAPART: 9943525Sshidokht case DKIOCGGEOM: 9953525Sshidokht case DKIOCGVTOC: 9963525Sshidokht case DKIOCSVTOC: 9973525Sshidokht case DKIOCSAPART: 9983525Sshidokht 9993525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 10003525Sshidokht return (ENOTSUP); 10013525Sshidokht } 10023525Sshidokht } 1003786Slclee } 1004786Slclee } 1005786Slclee } 1006786Slclee 10073525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 1008786Slclee 1009786Slclee switch (cmd) { 1010786Slclee case DKIOCGGEOM: 10113525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGGEOM\n"); 10123525Sshidokht err = cmlb_dkio_get_geometry(cl, (caddr_t)arg, flag, tg_cookie); 1013786Slclee break; 1014786Slclee 1015786Slclee case DKIOCSGEOM: 10163525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSGEOM\n"); 10173525Sshidokht err = cmlb_dkio_set_geometry(cl, (caddr_t)arg, flag); 1018786Slclee break; 1019786Slclee 1020786Slclee case DKIOCGAPART: 10213525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGAPART\n"); 10223525Sshidokht err = cmlb_dkio_get_partition(cl, (caddr_t)arg, 10233525Sshidokht flag, tg_cookie); 1024786Slclee break; 1025786Slclee 1026786Slclee case DKIOCSAPART: 10273525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSAPART\n"); 10283525Sshidokht err = cmlb_dkio_set_partition(cl, (caddr_t)arg, flag); 1029786Slclee break; 1030786Slclee 1031786Slclee case DKIOCGVTOC: 10323525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGVTOC\n"); 10333525Sshidokht err = cmlb_dkio_get_vtoc(cl, (caddr_t)arg, flag, tg_cookie); 1034786Slclee break; 1035786Slclee 1036786Slclee case DKIOCGETEFI: 10373525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGETEFI\n"); 10383525Sshidokht err = cmlb_dkio_get_efi(cl, (caddr_t)arg, flag, tg_cookie); 1039786Slclee break; 1040786Slclee 1041786Slclee case DKIOCPARTITION: 10423525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCPARTITION\n"); 10433525Sshidokht err = cmlb_dkio_partition(cl, (caddr_t)arg, flag, tg_cookie); 1044786Slclee break; 1045786Slclee 1046786Slclee case DKIOCSVTOC: 10473525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSVTOC\n"); 10483525Sshidokht err = cmlb_dkio_set_vtoc(cl, dev, (caddr_t)arg, flag, 10493525Sshidokht tg_cookie); 1050786Slclee break; 1051786Slclee 1052786Slclee case DKIOCSETEFI: 10533525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSETEFI\n"); 10543525Sshidokht err = cmlb_dkio_set_efi(cl, dev, (caddr_t)arg, flag, tg_cookie); 1055786Slclee break; 1056786Slclee 1057786Slclee case DKIOCGMBOOT: 10583525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGMBOOT\n"); 10593525Sshidokht err = cmlb_dkio_get_mboot(cl, (caddr_t)arg, flag, tg_cookie); 1060786Slclee break; 1061786Slclee 1062786Slclee case DKIOCSMBOOT: 10633525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSMBOOT\n"); 10643525Sshidokht err = cmlb_dkio_set_mboot(cl, (caddr_t)arg, flag, tg_cookie); 1065786Slclee break; 1066786Slclee case DKIOCG_PHYGEOM: 10673525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCG_PHYGEOM\n"); 1068786Slclee #if defined(__i386) || defined(__amd64) 10693525Sshidokht err = cmlb_dkio_get_phygeom(cl, (caddr_t)arg, flag); 1070786Slclee #else 1071786Slclee err = ENOTTY; 1072786Slclee #endif 1073786Slclee break; 1074786Slclee case DKIOCG_VIRTGEOM: 10753525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCG_VIRTGEOM\n"); 1076786Slclee #if defined(__i386) || defined(__amd64) 10773525Sshidokht err = cmlb_dkio_get_virtgeom(cl, (caddr_t)arg, flag); 1078786Slclee #else 1079786Slclee err = ENOTTY; 1080786Slclee #endif 1081786Slclee break; 1082786Slclee case DKIOCPARTINFO: 10833525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCPARTINFO"); 1084786Slclee #if defined(__i386) || defined(__amd64) 10853525Sshidokht err = cmlb_dkio_partinfo(cl, dev, (caddr_t)arg, flag); 1086786Slclee #else 1087786Slclee err = ENOTTY; 1088786Slclee #endif 1089786Slclee break; 1090786Slclee 1091786Slclee default: 1092786Slclee err = ENOTTY; 1093786Slclee 1094786Slclee } 1095786Slclee return (err); 1096786Slclee } 1097786Slclee 1098786Slclee dev_t 10993525Sshidokht cmlb_make_device(struct cmlb_lun *cl) 1100786Slclee { 11013525Sshidokht return (makedevice(ddi_name_to_major(ddi_get_name(CMLB_DEVINFO(cl))), 11023525Sshidokht ddi_get_instance(CMLB_DEVINFO(cl)) << CMLBUNIT_SHIFT)); 1103786Slclee } 1104786Slclee 1105786Slclee /* 1106786Slclee * Function: cmlb_check_update_blockcount 1107786Slclee * 1108786Slclee * Description: If current capacity value is invalid, obtains the 1109786Slclee * current capacity from target driver. 1110786Slclee * 1111786Slclee * Return Code: 0 success 1112786Slclee * EIO failure 1113786Slclee */ 1114786Slclee static int 11153525Sshidokht cmlb_check_update_blockcount(struct cmlb_lun *cl, void *tg_cookie) 1116786Slclee { 1117786Slclee int status; 1118786Slclee diskaddr_t capacity; 11193525Sshidokht uint32_t lbasize; 11203525Sshidokht 11213525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 11223525Sshidokht 11233525Sshidokht if (cl->cl_f_geometry_is_valid == FALSE) { 11243525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 11253525Sshidokht status = DK_TG_GETCAP(cl, &capacity, tg_cookie); 11263525Sshidokht if (status != 0) { 11273525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 11283525Sshidokht return (EIO); 11293525Sshidokht } 11303525Sshidokht 11313525Sshidokht status = DK_TG_GETBLOCKSIZE(cl, &lbasize, tg_cookie); 11323525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 11333525Sshidokht if (status != 0) 11343525Sshidokht return (EIO); 11353525Sshidokht 11363525Sshidokht if ((capacity != 0) && (lbasize != 0)) { 11373525Sshidokht cl->cl_blockcount = capacity; 11383525Sshidokht cl->cl_tgt_blocksize = lbasize; 1139786Slclee return (0); 1140786Slclee } else 1141786Slclee return (EIO); 1142786Slclee } else 1143786Slclee return (0); 1144786Slclee } 1145786Slclee 1146786Slclee /* 1147786Slclee * Function: cmlb_create_minor_nodes 1148786Slclee * 1149786Slclee * Description: Create or adjust the minor device nodes for the instance. 1150786Slclee * Minor nodes are created based on default label type, 1151786Slclee * current label type and last label type we created 1152786Slclee * minor nodes based on. 1153786Slclee * 1154786Slclee * 11553525Sshidokht * Arguments: cl - driver soft state (unit) structure 1156786Slclee * 1157786Slclee * Return Code: 0 success 1158786Slclee * ENXIO failure. 1159786Slclee * 1160786Slclee * Context: Kernel thread context 1161786Slclee */ 1162786Slclee static int 11633525Sshidokht cmlb_create_minor_nodes(struct cmlb_lun *cl) 1164786Slclee { 1165786Slclee struct driver_minor_data *dmdp; 1166786Slclee int instance; 1167786Slclee char name[48]; 1168786Slclee cmlb_label_t newlabeltype; 1169786Slclee 11703525Sshidokht ASSERT(cl != NULL); 11713525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 1172786Slclee 1173786Slclee 1174786Slclee /* check the most common case */ 11753525Sshidokht if (cl->cl_cur_labeltype != CMLB_LABEL_UNDEF && 11763525Sshidokht cl->cl_last_labeltype == cl->cl_cur_labeltype) { 1177786Slclee /* do nothing */ 1178786Slclee return (0); 1179786Slclee } 1180786Slclee 11813525Sshidokht if (cl->cl_def_labeltype == CMLB_LABEL_UNDEF) { 1182786Slclee /* we should never get here */ 1183786Slclee return (ENXIO); 1184786Slclee } 1185786Slclee 11863525Sshidokht if (cl->cl_last_labeltype == CMLB_LABEL_UNDEF) { 1187786Slclee /* first time during attach */ 11883525Sshidokht newlabeltype = cl->cl_def_labeltype; 11893525Sshidokht 11903525Sshidokht instance = ddi_get_instance(CMLB_DEVINFO(cl)); 1191786Slclee 1192786Slclee /* Create all the minor nodes for this target. */ 1193786Slclee dmdp = (newlabeltype == CMLB_LABEL_EFI) ? dk_minor_data_efi : 1194786Slclee dk_minor_data; 1195786Slclee while (dmdp->name != NULL) { 1196786Slclee 1197786Slclee (void) sprintf(name, "%s", dmdp->name); 1198786Slclee 11993525Sshidokht if (ddi_create_minor_node(CMLB_DEVINFO(cl), name, 1200786Slclee dmdp->type, 1201786Slclee (instance << CMLBUNIT_SHIFT) | dmdp->minor, 12023525Sshidokht cl->cl_node_type, NULL) == DDI_FAILURE) { 1203786Slclee /* 1204786Slclee * Clean up any nodes that may have been 1205786Slclee * created, in case this fails in the middle 1206786Slclee * of the loop. 1207786Slclee */ 12083525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL); 1209786Slclee return (ENXIO); 1210786Slclee } 1211786Slclee dmdp++; 1212786Slclee } 12133525Sshidokht cl->cl_last_labeltype = newlabeltype; 1214786Slclee return (0); 1215786Slclee } 1216786Slclee 1217786Slclee /* Not first time */ 12183525Sshidokht if (cl->cl_cur_labeltype == CMLB_LABEL_UNDEF) { 12193525Sshidokht if (cl->cl_last_labeltype != cl->cl_def_labeltype) { 1220786Slclee /* close time, revert to default. */ 12213525Sshidokht newlabeltype = cl->cl_def_labeltype; 1222786Slclee } else { 1223786Slclee /* 1224786Slclee * do nothing since the type for which we last created 1225786Slclee * nodes matches the default 1226786Slclee */ 1227786Slclee return (0); 1228786Slclee } 1229786Slclee } else { 12303525Sshidokht if (cl->cl_cur_labeltype != cl->cl_last_labeltype) { 1231786Slclee /* We are not closing, use current label type */ 12323525Sshidokht newlabeltype = cl->cl_cur_labeltype; 1233786Slclee } else { 1234786Slclee /* 1235786Slclee * do nothing since the type for which we last created 1236786Slclee * nodes matches the current label type 1237786Slclee */ 1238786Slclee return (0); 1239786Slclee } 1240786Slclee } 1241786Slclee 12423525Sshidokht instance = ddi_get_instance(CMLB_DEVINFO(cl)); 1243786Slclee 1244786Slclee /* 1245786Slclee * Currently we only fix up the s7 node when we are switching 1246786Slclee * label types from or to EFI. This is consistent with 1247786Slclee * current behavior of sd. 1248786Slclee */ 1249786Slclee if (newlabeltype == CMLB_LABEL_EFI && 12503525Sshidokht cl->cl_last_labeltype != CMLB_LABEL_EFI) { 1251786Slclee /* from vtoc to EFI */ 12523525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "h"); 12533525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw"); 12543525Sshidokht (void) ddi_create_minor_node(CMLB_DEVINFO(cl), "wd", 1255786Slclee S_IFBLK, (instance << CMLBUNIT_SHIFT) | WD_NODE, 12563525Sshidokht cl->cl_node_type, NULL); 12573525Sshidokht (void) ddi_create_minor_node(CMLB_DEVINFO(cl), "wd,raw", 1258786Slclee S_IFCHR, (instance << CMLBUNIT_SHIFT) | WD_NODE, 12593525Sshidokht cl->cl_node_type, NULL); 1260786Slclee } else { 1261786Slclee /* from efi to vtoc */ 12623525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd"); 12633525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd,raw"); 12643525Sshidokht (void) ddi_create_minor_node(CMLB_DEVINFO(cl), "h", 1265786Slclee S_IFBLK, (instance << CMLBUNIT_SHIFT) | WD_NODE, 12663525Sshidokht cl->cl_node_type, NULL); 12673525Sshidokht (void) ddi_create_minor_node(CMLB_DEVINFO(cl), "h,raw", 1268786Slclee S_IFCHR, (instance << CMLBUNIT_SHIFT) | WD_NODE, 12693525Sshidokht cl->cl_node_type, NULL); 1270786Slclee } 1271786Slclee 12723525Sshidokht cl->cl_last_labeltype = newlabeltype; 1273786Slclee return (0); 1274786Slclee } 1275786Slclee 1276786Slclee /* 1277786Slclee * Function: cmlb_validate_geometry 1278786Slclee * 1279786Slclee * Description: Read the label from the disk (if present). Update the unit's 1280786Slclee * geometry and vtoc information from the data in the label. 1281786Slclee * Verify that the label is valid. 1282786Slclee * 12833525Sshidokht * Arguments: 12843525Sshidokht * cl driver soft state (unit) structure 12853525Sshidokht * 12863525Sshidokht * forcerevalid force revalidation even if we are already valid. 12873525Sshidokht * flags operation flags from target driver. Used for verbosity 12883525Sshidokht * control at this time. 12893525Sshidokht * tg_cookie cookie from target driver to be passed back to target 12903525Sshidokht * driver when we call back to it through tg_ops. 1291786Slclee * 1292786Slclee * Return Code: 0 - Successful completion 12933525Sshidokht * EINVAL - Invalid value in cl->cl_tgt_blocksize or 12943525Sshidokht * cl->cl_blockcount; or label on disk is corrupted 1295786Slclee * or unreadable. 1296786Slclee * EACCES - Reservation conflict at the device. 1297786Slclee * ENOMEM - Resource allocation error 1298786Slclee * ENOTSUP - geometry not applicable 1299786Slclee * 1300786Slclee * Context: Kernel thread only (can sleep). 1301786Slclee */ 1302786Slclee static int 13033525Sshidokht cmlb_validate_geometry(struct cmlb_lun *cl, int forcerevalid, int flags, 13043525Sshidokht void *tg_cookie) 1305786Slclee { 1306786Slclee int label_error = 0; 1307786Slclee diskaddr_t capacity; 1308786Slclee int count; 13093525Sshidokht #if defined(__i386) || defined(__amd64) 13103525Sshidokht int forced_under_1t = 0; 13113525Sshidokht #endif 13123525Sshidokht 13133525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 13143525Sshidokht 13153525Sshidokht if ((cl->cl_f_geometry_is_valid == TRUE) && (forcerevalid == 0)) { 13163525Sshidokht if (cl->cl_cur_labeltype == CMLB_LABEL_EFI) 1317786Slclee return (ENOTSUP); 1318786Slclee return (0); 1319786Slclee } 1320786Slclee 13213525Sshidokht if (cmlb_check_update_blockcount(cl, tg_cookie) != 0) 1322786Slclee return (EIO); 1323786Slclee 13243525Sshidokht capacity = cl->cl_blockcount; 1325786Slclee 1326786Slclee #if defined(_SUNOS_VTOC_16) 1327786Slclee /* 1328786Slclee * Set up the "whole disk" fdisk partition; this should always 1329786Slclee * exist, regardless of whether the disk contains an fdisk table 1330786Slclee * or vtoc. 1331786Slclee */ 13323525Sshidokht cl->cl_map[P0_RAW_DISK].dkl_cylno = 0; 1333786Slclee /* 1334786Slclee * note if capacity > uint32_max we should be using efi, 1335786Slclee * and not use p0, so the truncation does not matter. 1336786Slclee */ 13373525Sshidokht cl->cl_map[P0_RAW_DISK].dkl_nblk = capacity; 1338786Slclee #endif 1339786Slclee /* 1340786Slclee * Refresh the logical and physical geometry caches. 1341786Slclee * (data from MODE SENSE format/rigid disk geometry pages, 1342786Slclee * and scsi_ifgetcap("geometry"). 1343786Slclee */ 13443525Sshidokht cmlb_resync_geom_caches(cl, capacity, tg_cookie); 13453525Sshidokht 13463525Sshidokht label_error = cmlb_use_efi(cl, capacity, flags, tg_cookie); 1347786Slclee if (label_error == 0) { 1348786Slclee 1349786Slclee /* found a valid EFI label */ 13503525Sshidokht cmlb_dbg(CMLB_TRACE, cl, 1351786Slclee "cmlb_validate_geometry: found EFI label\n"); 1352786Slclee /* 1353786Slclee * solaris_size and geometry_is_valid are set in 1354786Slclee * cmlb_use_efi 1355786Slclee */ 1356786Slclee return (ENOTSUP); 1357786Slclee } 1358786Slclee 1359786Slclee /* NO EFI label found */ 1360786Slclee 1361786Slclee if (capacity > DK_MAX_BLOCKS) { 1362786Slclee if (label_error == ESRCH) { 1363786Slclee /* 1364786Slclee * they've configured a LUN over 1TB, but used 1365786Slclee * format.dat to restrict format's view of the 1366786Slclee * capacity to be under 1TB 1367786Slclee */ 1368786Slclee /* i.e > 1Tb with a VTOC < 1TB */ 13693525Sshidokht if (!(flags & CMLB_SILENT)) { 13703525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), 13713525Sshidokht CE_WARN, "is >1TB and has a VTOC label: " 13723525Sshidokht "use format(1M) to either decrease the"); 13733525Sshidokht 13743525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), 13753525Sshidokht CE_NOTE, "size to be < 1TB or relabel the " 13763525Sshidokht "disk with an EFI label"); 13773525Sshidokht #if defined(__i386) || defined(__amd64) 13783525Sshidokht forced_under_1t = 1; 13793525Sshidokht #endif 13803525Sshidokht } 1381786Slclee } else { 1382786Slclee /* unlabeled disk over 1TB */ 13833525Sshidokht #if defined(__i386) || defined(__amd64) 13843525Sshidokht 13853525Sshidokht /* 13863525Sshidokht * Refer to comments on off-by-1 at the head of the file 13873525Sshidokht * A 1TB disk was treated as (1T - 512)B in the past, 13883525Sshidokht * thus, it might have valid solaris partition. We 13893525Sshidokht * will return ENOTSUP later only if this disk has no 13903525Sshidokht * valid solaris partition. 13913525Sshidokht */ 13923525Sshidokht if (!(cl->cl_alter_behavior & CMLB_OFF_BY_ONE) || 13933525Sshidokht (cl->cl_sys_blocksize != cl->cl_tgt_blocksize) || 13943525Sshidokht (capacity - 1 > DK_MAX_BLOCKS)) 13953525Sshidokht #endif 13963525Sshidokht return (ENOTSUP); 1397786Slclee } 1398786Slclee } 1399786Slclee 1400786Slclee label_error = 0; 1401786Slclee 1402786Slclee /* 1403786Slclee * at this point it is either labeled with a VTOC or it is 14043525Sshidokht * under 1TB (<= 1TB actually for off-by-1) 1405786Slclee */ 1406786Slclee 1407786Slclee /* 14083525Sshidokht * Only DIRECT ACCESS devices will have Scl labels. 14093525Sshidokht * CD's supposedly have a Scl label, too 1410786Slclee */ 14113525Sshidokht if (cl->cl_device_type == DTYPE_DIRECT || ISREMOVABLE(cl)) { 1412786Slclee struct dk_label *dkl; 1413786Slclee offset_t label_addr; 1414786Slclee int rval; 1415786Slclee size_t buffer_size; 1416786Slclee 1417786Slclee /* 14183525Sshidokht * Note: This will set up cl->cl_solaris_size and 14193525Sshidokht * cl->cl_solaris_offset. 1420786Slclee */ 14213525Sshidokht rval = cmlb_read_fdisk(cl, capacity, tg_cookie); 14223525Sshidokht if ((rval != 0) && !ISCD(cl)) { 14233525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 1424786Slclee return (rval); 1425786Slclee } 1426786Slclee 14273525Sshidokht if (cl->cl_solaris_size <= DK_LABEL_LOC) { 14283525Sshidokht 14293525Sshidokht #if defined(__i386) || defined(__amd64) 14303525Sshidokht /* 14313525Sshidokht * Refer to comments on off-by-1 at the head of the file 14323525Sshidokht * This is for 1TB disk only. Since that there is no 14333525Sshidokht * solaris partitions, return ENOTSUP as we do for 14343525Sshidokht * >1TB disk. 14353525Sshidokht */ 14363525Sshidokht if (cl->cl_blockcount > DK_MAX_BLOCKS) 14373525Sshidokht return (ENOTSUP); 14383525Sshidokht #endif 1439786Slclee /* 1440786Slclee * Found fdisk table but no Solaris partition entry, 1441786Slclee * so don't call cmlb_uselabel() and don't create 1442786Slclee * a default label. 1443786Slclee */ 1444786Slclee label_error = 0; 14453525Sshidokht cl->cl_f_geometry_is_valid = TRUE; 1446786Slclee goto no_solaris_partition; 1447786Slclee } 1448786Slclee 14493525Sshidokht label_addr = (daddr_t)(cl->cl_solaris_offset + DK_LABEL_LOC); 14503525Sshidokht 14513525Sshidokht #if defined(__i386) || defined(__amd64) 14523525Sshidokht /* 14533525Sshidokht * Refer to comments on off-by-1 at the head of the file 14543525Sshidokht * Now, this 1TB disk has valid solaris partition. It 14553525Sshidokht * must be created by previous sd driver, we have to 14563525Sshidokht * treat it as (1T-512)B. 14573525Sshidokht */ 14583525Sshidokht if ((cl->cl_blockcount > DK_MAX_BLOCKS) && 14593525Sshidokht (forced_under_1t != 1)) { 14603525Sshidokht /* 14613525Sshidokht * Refer to cmlb_read_fdisk, when there is no 14623525Sshidokht * fdisk partition table, cl_solaris_size is 14633525Sshidokht * set to disk's capacity. In this case, we 14643525Sshidokht * need to adjust it 14653525Sshidokht */ 14663525Sshidokht if (cl->cl_solaris_size > DK_MAX_BLOCKS) 14673525Sshidokht cl->cl_solaris_size = DK_MAX_BLOCKS; 14683525Sshidokht cmlb_resync_geom_caches(cl, DK_MAX_BLOCKS, tg_cookie); 14693525Sshidokht } 14703525Sshidokht #endif 1471786Slclee 1472786Slclee buffer_size = sizeof (struct dk_label); 1473786Slclee 14743525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "cmlb_validate_geometry: " 1475786Slclee "label_addr: 0x%x allocation size: 0x%x\n", 1476786Slclee label_addr, buffer_size); 1477786Slclee 1478786Slclee if ((dkl = kmem_zalloc(buffer_size, KM_NOSLEEP)) == NULL) 1479786Slclee return (ENOMEM); 1480786Slclee 14813525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 14823525Sshidokht rval = DK_TG_READ(cl, dkl, label_addr, buffer_size, tg_cookie); 14833525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 1484786Slclee 1485786Slclee switch (rval) { 1486786Slclee case 0: 1487786Slclee /* 1488786Slclee * cmlb_uselabel will establish that the geometry 1489786Slclee * is valid. 1490786Slclee */ 14913525Sshidokht if (cmlb_uselabel(cl, 14923525Sshidokht (struct dk_label *)(uintptr_t)dkl, flags) != 1493786Slclee CMLB_LABEL_IS_VALID) { 1494786Slclee label_error = EINVAL; 1495786Slclee } else 14963525Sshidokht cl->cl_vtoc_label_is_from_media = 1; 1497786Slclee break; 1498786Slclee case EACCES: 1499786Slclee label_error = EACCES; 1500786Slclee break; 1501786Slclee default: 1502786Slclee label_error = EINVAL; 1503786Slclee break; 1504786Slclee } 1505786Slclee 1506786Slclee kmem_free(dkl, buffer_size); 1507786Slclee } 1508786Slclee 1509786Slclee /* 1510786Slclee * If a valid label was not found, AND if no reservation conflict 1511786Slclee * was detected, then go ahead and create a default label (4069506). 1512786Slclee * 1513786Slclee * Note: currently, for VTOC_8 devices, the default label is created 15143525Sshidokht * for removables and hotpluggables only. For VTOC_16 devices, the 15153525Sshidokht * default label will be created for all devices. 1516786Slclee * (see cmlb_build_default_label) 1517786Slclee */ 1518786Slclee #if defined(_SUNOS_VTOC_8) 15193525Sshidokht if ((ISREMOVABLE(cl) || ISHOTPLUGGABLE(cl)) && 15203525Sshidokht (label_error != EACCES)) { 1521786Slclee #elif defined(_SUNOS_VTOC_16) 1522786Slclee if (label_error != EACCES) { 1523786Slclee #endif 15243525Sshidokht if (cl->cl_f_geometry_is_valid == FALSE) { 15253525Sshidokht cmlb_build_default_label(cl, tg_cookie); 1526786Slclee } 1527786Slclee label_error = 0; 1528786Slclee } 1529786Slclee 1530786Slclee no_solaris_partition: 1531786Slclee 1532786Slclee #if defined(_SUNOS_VTOC_16) 1533786Slclee /* 1534786Slclee * If we have valid geometry, set up the remaining fdisk partitions. 1535786Slclee * Note that dkl_cylno is not used for the fdisk map entries, so 1536786Slclee * we set it to an entirely bogus value. 1537786Slclee */ 1538786Slclee for (count = 0; count < FD_NUMPART; count++) { 15393525Sshidokht cl->cl_map[FDISK_P1 + count].dkl_cylno = -1; 15403525Sshidokht cl->cl_map[FDISK_P1 + count].dkl_nblk = 15413525Sshidokht cl->cl_fmap[count].fmap_nblk; 15423525Sshidokht 15433525Sshidokht cl->cl_offset[FDISK_P1 + count] = 15443525Sshidokht cl->cl_fmap[count].fmap_start; 1545786Slclee } 1546786Slclee #endif 1547786Slclee 1548786Slclee for (count = 0; count < NDKMAP; count++) { 1549786Slclee #if defined(_SUNOS_VTOC_8) 15503525Sshidokht struct dk_map *lp = &cl->cl_map[count]; 15513525Sshidokht cl->cl_offset[count] = 15523525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno; 1553786Slclee #elif defined(_SUNOS_VTOC_16) 15543525Sshidokht struct dkl_partition *vp = &cl->cl_vtoc.v_part[count]; 15553525Sshidokht 15563525Sshidokht cl->cl_offset[count] = vp->p_start + cl->cl_solaris_offset; 1557786Slclee #else 1558786Slclee #error "No VTOC format defined." 1559786Slclee #endif 1560786Slclee } 1561786Slclee 1562786Slclee return (label_error); 1563786Slclee } 1564786Slclee 1565786Slclee #if defined(_SUNOS_VTOC_16) 1566786Slclee /* 1567786Slclee * Macro: MAX_BLKS 1568786Slclee * 1569786Slclee * This macro is used for table entries where we need to have the largest 1570786Slclee * possible sector value for that head & SPT (sectors per track) 1571786Slclee * combination. Other entries for some smaller disk sizes are set by 1572786Slclee * convention to match those used by X86 BIOS usage. 1573786Slclee */ 1574786Slclee #define MAX_BLKS(heads, spt) UINT16_MAX * heads * spt, heads, spt 1575786Slclee 1576786Slclee /* 1577786Slclee * Function: cmlb_convert_geometry 1578786Slclee * 1579786Slclee * Description: Convert physical geometry into a dk_geom structure. In 1580786Slclee * other words, make sure we don't wrap 16-bit values. 1581786Slclee * e.g. converting from geom_cache to dk_geom 1582786Slclee * 1583786Slclee * Context: Kernel thread only 1584786Slclee */ 1585786Slclee static void 15863525Sshidokht cmlb_convert_geometry(diskaddr_t capacity, struct dk_geom *cl_g) 1587786Slclee { 1588786Slclee int i; 1589786Slclee static const struct chs_values { 1590786Slclee uint_t max_cap; /* Max Capacity for this HS. */ 1591786Slclee uint_t nhead; /* Heads to use. */ 1592786Slclee uint_t nsect; /* SPT to use. */ 1593786Slclee } CHS_values[] = { 1594786Slclee {0x00200000, 64, 32}, /* 1GB or smaller disk. */ 1595786Slclee {0x01000000, 128, 32}, /* 8GB or smaller disk. */ 1596786Slclee {MAX_BLKS(255, 63)}, /* 502.02GB or smaller disk. */ 1597786Slclee {MAX_BLKS(255, 126)}, /* .98TB or smaller disk. */ 1598786Slclee {DK_MAX_BLOCKS, 255, 189} /* Max size is just under 1TB */ 1599786Slclee }; 1600786Slclee 1601786Slclee /* Unlabeled SCSI floppy device */ 1602786Slclee if (capacity <= 0x1000) { 16033525Sshidokht cl_g->dkg_nhead = 2; 16043525Sshidokht cl_g->dkg_ncyl = 80; 16053525Sshidokht cl_g->dkg_nsect = capacity / (cl_g->dkg_nhead * cl_g->dkg_ncyl); 1606786Slclee return; 1607786Slclee } 1608786Slclee 1609786Slclee /* 1610786Slclee * For all devices we calculate cylinders using the 1611786Slclee * heads and sectors we assign based on capacity of the 1612786Slclee * device. The table is designed to be compatible with the 1613786Slclee * way other operating systems lay out fdisk tables for X86 1614786Slclee * and to insure that the cylinders never exceed 65535 to 1615786Slclee * prevent problems with X86 ioctls that report geometry. 1616786Slclee * We use SPT that are multiples of 63, since other OSes that 1617786Slclee * are not limited to 16-bits for cylinders stop at 63 SPT 1618786Slclee * we make do by using multiples of 63 SPT. 1619786Slclee * 1620786Slclee * Note than capacities greater than or equal to 1TB will simply 1621786Slclee * get the largest geometry from the table. This should be okay 1622786Slclee * since disks this large shouldn't be using CHS values anyway. 1623786Slclee */ 1624786Slclee for (i = 0; CHS_values[i].max_cap < capacity && 1625786Slclee CHS_values[i].max_cap != DK_MAX_BLOCKS; i++) 1626786Slclee ; 1627786Slclee 16283525Sshidokht cl_g->dkg_nhead = CHS_values[i].nhead; 16293525Sshidokht cl_g->dkg_nsect = CHS_values[i].nsect; 1630786Slclee } 1631786Slclee #endif 1632786Slclee 1633786Slclee /* 1634786Slclee * Function: cmlb_resync_geom_caches 1635786Slclee * 1636786Slclee * Description: (Re)initialize both geometry caches: the virtual geometry 1637786Slclee * information is extracted from the HBA (the "geometry" 1638786Slclee * capability), and the physical geometry cache data is 1639786Slclee * generated by issuing MODE SENSE commands. 1640786Slclee * 16413525Sshidokht * Arguments: 16423525Sshidokht * cl driver soft state (unit) structure 16433525Sshidokht * capacity disk capacity in #blocks 16443525Sshidokht * tg_cookie cookie from target driver to be passed back to target 16453525Sshidokht * driver when we call back to it through tg_ops. 1646786Slclee * 1647786Slclee * Context: Kernel thread only (can sleep). 1648786Slclee */ 1649786Slclee static void 16503525Sshidokht cmlb_resync_geom_caches(struct cmlb_lun *cl, diskaddr_t capacity, 16513525Sshidokht void *tg_cookie) 1652786Slclee { 1653786Slclee struct cmlb_geom pgeom; 1654786Slclee struct cmlb_geom lgeom; 1655786Slclee struct cmlb_geom *pgeomp = &pgeom; 1656786Slclee unsigned short nhead; 1657786Slclee unsigned short nsect; 1658786Slclee int spc; 1659786Slclee int ret; 1660786Slclee 16613525Sshidokht ASSERT(cl != NULL); 16623525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 1663786Slclee 1664786Slclee /* 1665786Slclee * Ask the controller for its logical geometry. 1666786Slclee * Note: if the HBA does not support scsi_ifgetcap("geometry"), 1667786Slclee * then the lgeom cache will be invalid. 1668786Slclee */ 16693525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 1670786Slclee bzero(&lgeom, sizeof (struct cmlb_geom)); 16713525Sshidokht ret = DK_TG_GETVIRTGEOM(cl, &lgeom, tg_cookie); 16723525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 16733525Sshidokht 16743525Sshidokht bcopy(&lgeom, &cl->cl_lgeom, sizeof (cl->cl_lgeom)); 1675786Slclee 1676786Slclee /* 1677786Slclee * Initialize the pgeom cache from lgeom, so that if MODE SENSE 1678786Slclee * doesn't work, DKIOCG_PHYSGEOM can return reasonable values. 1679786Slclee */ 16803525Sshidokht if (ret != 0 || cl->cl_lgeom.g_nsect == 0 || 16813525Sshidokht cl->cl_lgeom.g_nhead == 0) { 1682786Slclee /* 1683786Slclee * Note: Perhaps this needs to be more adaptive? The rationale 1684786Slclee * is that, if there's no HBA geometry from the HBA driver, any 1685786Slclee * guess is good, since this is the physical geometry. If MODE 1686786Slclee * SENSE fails this gives a max cylinder size for non-LBA access 1687786Slclee */ 1688786Slclee nhead = 255; 1689786Slclee nsect = 63; 1690786Slclee } else { 16913525Sshidokht nhead = cl->cl_lgeom.g_nhead; 16923525Sshidokht nsect = cl->cl_lgeom.g_nsect; 1693786Slclee } 1694786Slclee 16953525Sshidokht if (ISCD(cl)) { 1696786Slclee pgeomp->g_nhead = 1; 1697786Slclee pgeomp->g_nsect = nsect * nhead; 1698786Slclee } else { 1699786Slclee pgeomp->g_nhead = nhead; 1700786Slclee pgeomp->g_nsect = nsect; 1701786Slclee } 1702786Slclee 1703786Slclee spc = pgeomp->g_nhead * pgeomp->g_nsect; 1704786Slclee pgeomp->g_capacity = capacity; 1705786Slclee pgeomp->g_ncyl = pgeomp->g_capacity / spc; 1706786Slclee pgeomp->g_acyl = 0; 1707786Slclee 1708786Slclee /* 1709786Slclee * Retrieve fresh geometry data from the hardware, stash it 1710786Slclee * here temporarily before we rebuild the incore label. 1711786Slclee * 1712786Slclee * We want to use the MODE SENSE commands to derive the 1713786Slclee * physical geometry of the device, but if either command 1714786Slclee * fails, the logical geometry is used as the fallback for 1715786Slclee * disk label geometry. 1716786Slclee */ 1717786Slclee 17183525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 17193525Sshidokht (void) DK_TG_GETPHYGEOM(cl, pgeomp, tg_cookie); 17203525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 1721786Slclee 1722786Slclee /* 1723786Slclee * Now update the real copy while holding the mutex. This 1724786Slclee * way the global copy is never in an inconsistent state. 1725786Slclee */ 17263525Sshidokht bcopy(pgeomp, &cl->cl_pgeom, sizeof (cl->cl_pgeom)); 17273525Sshidokht 17283525Sshidokht cmlb_dbg(CMLB_INFO, cl, "cmlb_resync_geom_caches: " 1729786Slclee "(cached from lgeom)\n"); 17303525Sshidokht cmlb_dbg(CMLB_INFO, cl, 1731786Slclee " ncyl: %ld; acyl: %d; nhead: %d; nsect: %d\n", 17323525Sshidokht cl->cl_pgeom.g_ncyl, cl->cl_pgeom.g_acyl, 17333525Sshidokht cl->cl_pgeom.g_nhead, cl->cl_pgeom.g_nsect); 17343525Sshidokht cmlb_dbg(CMLB_INFO, cl, " lbasize: %d; capacity: %ld; " 17353525Sshidokht "intrlv: %d; rpm: %d\n", cl->cl_pgeom.g_secsize, 17363525Sshidokht cl->cl_pgeom.g_capacity, cl->cl_pgeom.g_intrlv, 17373525Sshidokht cl->cl_pgeom.g_rpm); 1738786Slclee } 1739786Slclee 1740786Slclee 1741786Slclee /* 1742786Slclee * Function: cmlb_read_fdisk 1743786Slclee * 1744786Slclee * Description: utility routine to read the fdisk table. 1745786Slclee * 17463525Sshidokht * Arguments: 17473525Sshidokht * cl driver soft state (unit) structure 17483525Sshidokht * capacity disk capacity in #blocks 17493525Sshidokht * tg_cookie cookie from target driver to be passed back to target 17503525Sshidokht * driver when we call back to it through tg_ops. 1751786Slclee * 1752786Slclee * Return Code: 0 for success (includes not reading for no_fdisk_present case 1753786Slclee * errnos from tg_rw if failed to read the first block. 1754786Slclee * 1755786Slclee * Context: Kernel thread only (can sleep). 1756786Slclee */ 17573525Sshidokht /*ARGSUSED*/ 1758786Slclee static int 17593525Sshidokht cmlb_read_fdisk(struct cmlb_lun *cl, diskaddr_t capacity, void *tg_cookie) 1760786Slclee { 1761786Slclee #if defined(_NO_FDISK_PRESENT) 1762786Slclee 17633525Sshidokht cl->cl_solaris_offset = 0; 17643525Sshidokht cl->cl_solaris_size = capacity; 17653525Sshidokht bzero(cl->cl_fmap, sizeof (struct fmap) * FD_NUMPART); 1766786Slclee return (0); 1767786Slclee 1768786Slclee #elif defined(_FIRMWARE_NEEDS_FDISK) 1769786Slclee 1770786Slclee struct ipart *fdp; 1771786Slclee struct mboot *mbp; 1772786Slclee struct ipart fdisk[FD_NUMPART]; 1773786Slclee int i; 1774786Slclee char sigbuf[2]; 1775786Slclee caddr_t bufp; 1776786Slclee int uidx; 1777786Slclee int rval; 1778786Slclee int lba = 0; 1779786Slclee uint_t solaris_offset; /* offset to solaris part. */ 1780786Slclee daddr_t solaris_size; /* size of solaris partition */ 1781786Slclee uint32_t blocksize; 1782786Slclee 17833525Sshidokht ASSERT(cl != NULL); 17843525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 1785786Slclee 1786786Slclee /* 1787786Slclee * Start off assuming no fdisk table 1788786Slclee */ 1789786Slclee solaris_offset = 0; 1790786Slclee solaris_size = capacity; 1791786Slclee 17923525Sshidokht blocksize = cl->cl_tgt_blocksize; 1793786Slclee 1794786Slclee bufp = kmem_zalloc(blocksize, KM_SLEEP); 1795786Slclee 17963525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 17973525Sshidokht rval = DK_TG_READ(cl, bufp, 0, blocksize, tg_cookie); 17983525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 1799786Slclee 1800786Slclee if (rval != 0) { 18013525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 1802786Slclee "cmlb_read_fdisk: fdisk read err\n"); 18033525Sshidokht bzero(cl->cl_fmap, sizeof (struct fmap) * FD_NUMPART); 18043525Sshidokht goto done; 1805786Slclee } 1806786Slclee 1807786Slclee mbp = (struct mboot *)bufp; 1808786Slclee 1809786Slclee /* 1810786Slclee * The fdisk table does not begin on a 4-byte boundary within the 1811786Slclee * master boot record, so we copy it to an aligned structure to avoid 1812786Slclee * alignment exceptions on some processors. 1813786Slclee */ 1814786Slclee bcopy(&mbp->parts[0], fdisk, sizeof (fdisk)); 1815786Slclee 1816786Slclee /* 1817786Slclee * Check for lba support before verifying sig; sig might not be 1818786Slclee * there, say on a blank disk, but the max_chs mark may still 1819786Slclee * be present. 1820786Slclee * 1821786Slclee * Note: LBA support and BEFs are an x86-only concept but this 1822786Slclee * code should work OK on SPARC as well. 1823786Slclee */ 1824786Slclee 1825786Slclee /* 1826786Slclee * First, check for lba-access-ok on root node (or prom root node) 1827786Slclee * if present there, don't need to search fdisk table. 1828786Slclee */ 1829786Slclee if (ddi_getprop(DDI_DEV_T_ANY, ddi_root_node(), 0, 1830786Slclee "lba-access-ok", 0) != 0) { 1831786Slclee /* All drives do LBA; don't search fdisk table */ 1832786Slclee lba = 1; 1833786Slclee } else { 1834786Slclee /* Okay, look for mark in fdisk table */ 1835786Slclee for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) { 1836786Slclee /* accumulate "lba" value from all partitions */ 1837786Slclee lba = (lba || cmlb_has_max_chs_vals(fdp)); 1838786Slclee } 1839786Slclee } 1840786Slclee 1841786Slclee if (lba != 0) { 18423525Sshidokht dev_t dev = cmlb_make_device(cl); 18433525Sshidokht 18443525Sshidokht if (ddi_getprop(dev, CMLB_DEVINFO(cl), DDI_PROP_DONTPASS, 1845786Slclee "lba-access-ok", 0) == 0) { 1846786Slclee /* not found; create it */ 18473525Sshidokht if (ddi_prop_create(dev, CMLB_DEVINFO(cl), 0, 1848786Slclee "lba-access-ok", (caddr_t)NULL, 0) != 1849786Slclee DDI_PROP_SUCCESS) { 18503525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 1851786Slclee "cmlb_read_fdisk: Can't create lba " 1852786Slclee "property for instance %d\n", 18533525Sshidokht ddi_get_instance(CMLB_DEVINFO(cl))); 1854786Slclee } 1855786Slclee } 1856786Slclee } 1857786Slclee 1858786Slclee bcopy(&mbp->signature, sigbuf, sizeof (sigbuf)); 1859786Slclee 1860786Slclee /* 1861786Slclee * Endian-independent signature check 1862786Slclee */ 1863786Slclee if (((sigbuf[1] & 0xFF) != ((MBB_MAGIC >> 8) & 0xFF)) || 1864786Slclee (sigbuf[0] != (MBB_MAGIC & 0xFF))) { 18653525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 1866786Slclee "cmlb_read_fdisk: no fdisk\n"); 18673525Sshidokht bzero(cl->cl_fmap, sizeof (struct fmap) * FD_NUMPART); 1868786Slclee goto done; 1869786Slclee } 1870786Slclee 1871786Slclee #ifdef CMLBDEBUG 18723525Sshidokht if (cmlb_level_mask & CMLB_LOGMASK_INFO) { 1873786Slclee fdp = fdisk; 18743525Sshidokht cmlb_dbg(CMLB_INFO, cl, "cmlb_read_fdisk:\n"); 18753525Sshidokht cmlb_dbg(CMLB_INFO, cl, " relsect " 1876786Slclee "numsect sysid bootid\n"); 1877786Slclee for (i = 0; i < FD_NUMPART; i++, fdp++) { 18783525Sshidokht cmlb_dbg(CMLB_INFO, cl, 1879786Slclee " %d: %8d %8d 0x%08x 0x%08x\n", 1880786Slclee i, fdp->relsect, fdp->numsect, 1881786Slclee fdp->systid, fdp->bootid); 1882786Slclee } 1883786Slclee } 1884786Slclee #endif 1885786Slclee 1886786Slclee /* 1887786Slclee * Try to find the unix partition 1888786Slclee */ 1889786Slclee uidx = -1; 1890786Slclee solaris_offset = 0; 1891786Slclee solaris_size = 0; 1892786Slclee 1893786Slclee for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) { 1894786Slclee int relsect; 1895786Slclee int numsect; 1896786Slclee 1897786Slclee if (fdp->numsect == 0) { 18983525Sshidokht cl->cl_fmap[i].fmap_start = 0; 18993525Sshidokht cl->cl_fmap[i].fmap_nblk = 0; 1900786Slclee continue; 1901786Slclee } 1902786Slclee 1903786Slclee /* 1904786Slclee * Data in the fdisk table is little-endian. 1905786Slclee */ 1906786Slclee relsect = LE_32(fdp->relsect); 1907786Slclee numsect = LE_32(fdp->numsect); 1908786Slclee 19093525Sshidokht cl->cl_fmap[i].fmap_start = relsect; 19103525Sshidokht cl->cl_fmap[i].fmap_nblk = numsect; 1911786Slclee 1912786Slclee if (fdp->systid != SUNIXOS && 1913786Slclee fdp->systid != SUNIXOS2 && 1914786Slclee fdp->systid != EFI_PMBR) { 1915786Slclee continue; 1916786Slclee } 1917786Slclee 1918786Slclee /* 1919786Slclee * use the last active solaris partition id found 1920786Slclee * (there should only be 1 active partition id) 1921786Slclee * 1922786Slclee * if there are no active solaris partition id 1923786Slclee * then use the first inactive solaris partition id 1924786Slclee */ 1925786Slclee if ((uidx == -1) || (fdp->bootid == ACTIVE)) { 1926786Slclee uidx = i; 1927786Slclee solaris_offset = relsect; 1928786Slclee solaris_size = numsect; 1929786Slclee } 1930786Slclee } 1931786Slclee 19323525Sshidokht cmlb_dbg(CMLB_INFO, cl, "fdisk 0x%x 0x%lx", 19333525Sshidokht cl->cl_solaris_offset, cl->cl_solaris_size); 1934786Slclee done: 1935786Slclee 1936786Slclee /* 1937786Slclee * Clear the VTOC info, only if the Solaris partition entry 1938786Slclee * has moved, changed size, been deleted, or if the size of 1939786Slclee * the partition is too small to even fit the label sector. 1940786Slclee */ 19413525Sshidokht if ((cl->cl_solaris_offset != solaris_offset) || 19423525Sshidokht (cl->cl_solaris_size != solaris_size) || 1943786Slclee solaris_size <= DK_LABEL_LOC) { 19443525Sshidokht cmlb_dbg(CMLB_INFO, cl, "fdisk moved 0x%x 0x%lx", 19453525Sshidokht solaris_offset, solaris_size); 19463525Sshidokht bzero(&cl->cl_g, sizeof (struct dk_geom)); 19473525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc)); 19483525Sshidokht bzero(&cl->cl_map, NDKMAP * (sizeof (struct dk_map))); 19493525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 1950786Slclee } 19513525Sshidokht cl->cl_solaris_offset = solaris_offset; 19523525Sshidokht cl->cl_solaris_size = solaris_size; 1953786Slclee kmem_free(bufp, blocksize); 1954786Slclee return (rval); 1955786Slclee 1956786Slclee #else /* #elif defined(_FIRMWARE_NEEDS_FDISK) */ 1957786Slclee #error "fdisk table presence undetermined for this platform." 1958786Slclee #endif /* #if defined(_NO_FDISK_PRESENT) */ 1959786Slclee } 1960786Slclee 1961786Slclee static void 1962786Slclee cmlb_swap_efi_gpt(efi_gpt_t *e) 1963786Slclee { 1964786Slclee _NOTE(ASSUMING_PROTECTED(*e)) 1965786Slclee e->efi_gpt_Signature = LE_64(e->efi_gpt_Signature); 1966786Slclee e->efi_gpt_Revision = LE_32(e->efi_gpt_Revision); 1967786Slclee e->efi_gpt_HeaderSize = LE_32(e->efi_gpt_HeaderSize); 1968786Slclee e->efi_gpt_HeaderCRC32 = LE_32(e->efi_gpt_HeaderCRC32); 1969786Slclee e->efi_gpt_MyLBA = LE_64(e->efi_gpt_MyLBA); 1970786Slclee e->efi_gpt_AlternateLBA = LE_64(e->efi_gpt_AlternateLBA); 1971786Slclee e->efi_gpt_FirstUsableLBA = LE_64(e->efi_gpt_FirstUsableLBA); 1972786Slclee e->efi_gpt_LastUsableLBA = LE_64(e->efi_gpt_LastUsableLBA); 1973786Slclee UUID_LE_CONVERT(e->efi_gpt_DiskGUID, e->efi_gpt_DiskGUID); 1974786Slclee e->efi_gpt_PartitionEntryLBA = LE_64(e->efi_gpt_PartitionEntryLBA); 1975786Slclee e->efi_gpt_NumberOfPartitionEntries = 1976786Slclee LE_32(e->efi_gpt_NumberOfPartitionEntries); 1977786Slclee e->efi_gpt_SizeOfPartitionEntry = 1978786Slclee LE_32(e->efi_gpt_SizeOfPartitionEntry); 1979786Slclee e->efi_gpt_PartitionEntryArrayCRC32 = 1980786Slclee LE_32(e->efi_gpt_PartitionEntryArrayCRC32); 1981786Slclee } 1982786Slclee 1983786Slclee static void 1984786Slclee cmlb_swap_efi_gpe(int nparts, efi_gpe_t *p) 1985786Slclee { 1986786Slclee int i; 1987786Slclee 1988786Slclee _NOTE(ASSUMING_PROTECTED(*p)) 1989786Slclee for (i = 0; i < nparts; i++) { 1990786Slclee UUID_LE_CONVERT(p[i].efi_gpe_PartitionTypeGUID, 1991786Slclee p[i].efi_gpe_PartitionTypeGUID); 1992786Slclee p[i].efi_gpe_StartingLBA = LE_64(p[i].efi_gpe_StartingLBA); 1993786Slclee p[i].efi_gpe_EndingLBA = LE_64(p[i].efi_gpe_EndingLBA); 1994786Slclee /* PartitionAttrs */ 1995786Slclee } 1996786Slclee } 1997786Slclee 1998786Slclee static int 1999786Slclee cmlb_validate_efi(efi_gpt_t *labp) 2000786Slclee { 2001786Slclee if (labp->efi_gpt_Signature != EFI_SIGNATURE) 2002786Slclee return (EINVAL); 2003786Slclee /* at least 96 bytes in this version of the spec. */ 2004786Slclee if (sizeof (efi_gpt_t) - sizeof (labp->efi_gpt_Reserved2) > 2005786Slclee labp->efi_gpt_HeaderSize) 2006786Slclee return (EINVAL); 2007786Slclee /* this should be 128 bytes */ 2008786Slclee if (labp->efi_gpt_SizeOfPartitionEntry != sizeof (efi_gpe_t)) 2009786Slclee return (EINVAL); 2010786Slclee return (0); 2011786Slclee } 2012786Slclee 2013786Slclee static int 20143525Sshidokht cmlb_use_efi(struct cmlb_lun *cl, diskaddr_t capacity, int flags, 20153525Sshidokht void *tg_cookie) 2016786Slclee { 2017786Slclee int i; 2018786Slclee int rval = 0; 2019786Slclee efi_gpe_t *partitions; 2020786Slclee uchar_t *buf; 2021786Slclee uint_t lbasize; /* is really how much to read */ 20223525Sshidokht diskaddr_t cap = 0; 2023786Slclee uint_t nparts; 2024786Slclee diskaddr_t gpe_lba; 20251071Sshidokht int iofailed = 0; 20263525Sshidokht struct uuid uuid_type_reserved = EFI_RESERVED; 20273525Sshidokht 20283525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 20293525Sshidokht 20303525Sshidokht if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) { 20313525Sshidokht rval = EINVAL; 20323525Sshidokht goto done_err1; 20333525Sshidokht } 20343525Sshidokht 20353525Sshidokht 20363525Sshidokht lbasize = cl->cl_sys_blocksize; 20373525Sshidokht 20383525Sshidokht cl->cl_reserved = -1; 20393525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 2040786Slclee 2041786Slclee buf = kmem_zalloc(EFI_MIN_ARRAY_SIZE, KM_SLEEP); 20423525Sshidokht 20433525Sshidokht rval = DK_TG_READ(cl, buf, 0, lbasize, tg_cookie); 2044786Slclee if (rval) { 20451071Sshidokht iofailed = 1; 2046786Slclee goto done_err; 2047786Slclee } 2048786Slclee if (((struct dk_label *)buf)->dkl_magic == DKL_MAGIC) { 2049786Slclee /* not ours */ 2050786Slclee rval = ESRCH; 2051786Slclee goto done_err; 2052786Slclee } 2053786Slclee 20543525Sshidokht rval = DK_TG_READ(cl, buf, 1, lbasize, tg_cookie); 2055786Slclee if (rval) { 20561071Sshidokht iofailed = 1; 2057786Slclee goto done_err; 2058786Slclee } 2059786Slclee cmlb_swap_efi_gpt((efi_gpt_t *)buf); 2060786Slclee 2061786Slclee if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) { 2062786Slclee /* 2063786Slclee * Couldn't read the primary, try the backup. Our 2064786Slclee * capacity at this point could be based on CHS, so 2065786Slclee * check what the device reports. 2066786Slclee */ 20673525Sshidokht rval = DK_TG_GETCAP(cl, &cap, tg_cookie); 2068786Slclee if (rval) { 20691071Sshidokht iofailed = 1; 2070786Slclee goto done_err; 2071786Slclee } 20723525Sshidokht 20733525Sshidokht /* 20743525Sshidokht * CMLB_OFF_BY_ONE case, we check the next to last block first 20753525Sshidokht * for backup GPT header, otherwise check the last block. 20763525Sshidokht */ 20773525Sshidokht 20783525Sshidokht if ((rval = DK_TG_READ(cl, buf, 20793525Sshidokht cap - ((cl->cl_alter_behavior & CMLB_OFF_BY_ONE) ? 2 : 1), 20803525Sshidokht lbasize, tg_cookie)) 20813525Sshidokht != 0) { 20821071Sshidokht iofailed = 1; 2083786Slclee goto done_err; 2084786Slclee } 2085786Slclee cmlb_swap_efi_gpt((efi_gpt_t *)buf); 20863525Sshidokht 20873525Sshidokht if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) { 20883525Sshidokht 20893525Sshidokht if (!(cl->cl_alter_behavior & CMLB_OFF_BY_ONE)) 20903525Sshidokht goto done_err; 20913525Sshidokht if ((rval = DK_TG_READ(cl, buf, cap - 1, lbasize, 20923525Sshidokht tg_cookie)) != 0) 20933525Sshidokht goto done_err; 20943525Sshidokht cmlb_swap_efi_gpt((efi_gpt_t *)buf); 20953525Sshidokht if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) 20963525Sshidokht goto done_err; 20973525Sshidokht } 20983525Sshidokht if (!(flags & CMLB_SILENT)) 20993525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN, 21003525Sshidokht "primary label corrupt; using backup\n"); 2101786Slclee } 2102786Slclee 2103786Slclee nparts = ((efi_gpt_t *)buf)->efi_gpt_NumberOfPartitionEntries; 2104786Slclee gpe_lba = ((efi_gpt_t *)buf)->efi_gpt_PartitionEntryLBA; 2105786Slclee 21063525Sshidokht rval = DK_TG_READ(cl, buf, gpe_lba, EFI_MIN_ARRAY_SIZE, tg_cookie); 2107786Slclee if (rval) { 21081071Sshidokht iofailed = 1; 2109786Slclee goto done_err; 2110786Slclee } 2111786Slclee partitions = (efi_gpe_t *)buf; 2112786Slclee 2113786Slclee if (nparts > MAXPART) { 2114786Slclee nparts = MAXPART; 2115786Slclee } 2116786Slclee cmlb_swap_efi_gpe(nparts, partitions); 2117786Slclee 21183525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 2119786Slclee 2120786Slclee /* Fill in partition table. */ 2121786Slclee for (i = 0; i < nparts; i++) { 2122786Slclee if (partitions->efi_gpe_StartingLBA != 0 || 2123786Slclee partitions->efi_gpe_EndingLBA != 0) { 21243525Sshidokht cl->cl_map[i].dkl_cylno = 2125786Slclee partitions->efi_gpe_StartingLBA; 21263525Sshidokht cl->cl_map[i].dkl_nblk = 2127786Slclee partitions->efi_gpe_EndingLBA - 2128786Slclee partitions->efi_gpe_StartingLBA + 1; 21293525Sshidokht cl->cl_offset[i] = 2130786Slclee partitions->efi_gpe_StartingLBA; 2131786Slclee } 21323525Sshidokht 21333525Sshidokht if (cl->cl_reserved == -1) { 21343525Sshidokht if (bcmp(&partitions->efi_gpe_PartitionTypeGUID, 21353525Sshidokht &uuid_type_reserved, sizeof (struct uuid)) == 0) { 21363525Sshidokht cl->cl_reserved = i; 21373525Sshidokht } 21383525Sshidokht } 2139786Slclee if (i == WD_NODE) { 2140786Slclee /* 2141786Slclee * minor number 7 corresponds to the whole disk 2142786Slclee */ 21433525Sshidokht cl->cl_map[i].dkl_cylno = 0; 21443525Sshidokht cl->cl_map[i].dkl_nblk = capacity; 21453525Sshidokht cl->cl_offset[i] = 0; 2146786Slclee } 2147786Slclee partitions++; 2148786Slclee } 21493525Sshidokht cl->cl_solaris_offset = 0; 21503525Sshidokht cl->cl_solaris_size = capacity; 21513525Sshidokht cl->cl_f_geometry_is_valid = TRUE; 21523525Sshidokht 21533525Sshidokht /* clear the vtoc label */ 21543525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc)); 21553525Sshidokht 2156786Slclee kmem_free(buf, EFI_MIN_ARRAY_SIZE); 2157786Slclee return (0); 2158786Slclee 2159786Slclee done_err: 2160786Slclee kmem_free(buf, EFI_MIN_ARRAY_SIZE); 21613525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 21623525Sshidokht done_err1: 2163786Slclee /* 2164786Slclee * if we didn't find something that could look like a VTOC 2165786Slclee * and the disk is over 1TB, we know there isn't a valid label. 2166786Slclee * Otherwise let cmlb_uselabel decide what to do. We only 2167786Slclee * want to invalidate this if we're certain the label isn't 2168786Slclee * valid because cmlb_prop_op will now fail, which in turn 2169786Slclee * causes things like opens and stats on the partition to fail. 2170786Slclee */ 21711071Sshidokht if ((capacity > DK_MAX_BLOCKS) && (rval != ESRCH) && !iofailed) { 21723525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 2173786Slclee } 2174786Slclee return (rval); 2175786Slclee } 2176786Slclee 2177786Slclee 2178786Slclee /* 2179786Slclee * Function: cmlb_uselabel 2180786Slclee * 2181786Slclee * Description: Validate the disk label and update the relevant data (geometry, 2182786Slclee * partition, vtoc, and capacity data) in the cmlb_lun struct. 2183786Slclee * Marks the geometry of the unit as being valid. 2184786Slclee * 21853525Sshidokht * Arguments: cl: unit struct. 2186786Slclee * dk_label: disk label 2187786Slclee * 2188786Slclee * Return Code: CMLB_LABEL_IS_VALID: Label read from disk is OK; geometry, 2189786Slclee * partition, vtoc, and capacity data are good. 2190786Slclee * 2191786Slclee * CMLB_LABEL_IS_INVALID: Magic number or checksum error in the 2192786Slclee * label; or computed capacity does not jibe with capacity 2193786Slclee * reported from the READ CAPACITY command. 2194786Slclee * 2195786Slclee * Context: Kernel thread only (can sleep). 2196786Slclee */ 2197786Slclee static int 21983525Sshidokht cmlb_uselabel(struct cmlb_lun *cl, struct dk_label *labp, int flags) 2199786Slclee { 2200786Slclee short *sp; 2201786Slclee short sum; 2202786Slclee short count; 2203786Slclee int label_error = CMLB_LABEL_IS_VALID; 2204786Slclee int i; 2205786Slclee diskaddr_t label_capacity; 2206786Slclee int part_end; 2207786Slclee diskaddr_t track_capacity; 2208786Slclee #if defined(_SUNOS_VTOC_16) 2209786Slclee struct dkl_partition *vpartp; 2210786Slclee #endif 22113525Sshidokht ASSERT(cl != NULL); 22123525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 2213786Slclee 2214786Slclee /* Validate the magic number of the label. */ 2215786Slclee if (labp->dkl_magic != DKL_MAGIC) { 2216786Slclee #if defined(__sparc) 22173525Sshidokht if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) { 22183525Sshidokht if (!(flags & CMLB_SILENT)) 22193525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), 22203525Sshidokht CE_WARN, 22213525Sshidokht "Corrupt label; wrong magic number\n"); 2222786Slclee } 2223786Slclee #endif 2224786Slclee return (CMLB_LABEL_IS_INVALID); 2225786Slclee } 2226786Slclee 2227786Slclee /* Validate the checksum of the label. */ 2228786Slclee sp = (short *)labp; 2229786Slclee sum = 0; 2230786Slclee count = sizeof (struct dk_label) / sizeof (short); 2231786Slclee while (count--) { 2232786Slclee sum ^= *sp++; 2233786Slclee } 2234786Slclee 2235786Slclee if (sum != 0) { 2236786Slclee #if defined(_SUNOS_VTOC_16) 22373525Sshidokht if (!ISCD(cl)) { 2238786Slclee #elif defined(_SUNOS_VTOC_8) 22393525Sshidokht if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) { 2240786Slclee #endif 22413525Sshidokht if (!(flags & CMLB_SILENT)) 22423525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), 22433525Sshidokht CE_WARN, 22443525Sshidokht "Corrupt label - label checksum failed\n"); 2245786Slclee } 2246786Slclee return (CMLB_LABEL_IS_INVALID); 2247786Slclee } 2248786Slclee 2249786Slclee 2250786Slclee /* 2251786Slclee * Fill in geometry structure with data from label. 2252786Slclee */ 22533525Sshidokht bzero(&cl->cl_g, sizeof (struct dk_geom)); 22543525Sshidokht cl->cl_g.dkg_ncyl = labp->dkl_ncyl; 22553525Sshidokht cl->cl_g.dkg_acyl = labp->dkl_acyl; 22563525Sshidokht cl->cl_g.dkg_bcyl = 0; 22573525Sshidokht cl->cl_g.dkg_nhead = labp->dkl_nhead; 22583525Sshidokht cl->cl_g.dkg_nsect = labp->dkl_nsect; 22593525Sshidokht cl->cl_g.dkg_intrlv = labp->dkl_intrlv; 2260786Slclee 2261786Slclee #if defined(_SUNOS_VTOC_8) 22623525Sshidokht cl->cl_g.dkg_gap1 = labp->dkl_gap1; 22633525Sshidokht cl->cl_g.dkg_gap2 = labp->dkl_gap2; 22643525Sshidokht cl->cl_g.dkg_bhead = labp->dkl_bhead; 2265786Slclee #endif 2266786Slclee #if defined(_SUNOS_VTOC_16) 22673525Sshidokht cl->cl_dkg_skew = labp->dkl_skew; 2268786Slclee #endif 2269786Slclee 2270786Slclee #if defined(__i386) || defined(__amd64) 22713525Sshidokht cl->cl_g.dkg_apc = labp->dkl_apc; 2272786Slclee #endif 2273786Slclee 2274786Slclee /* 2275786Slclee * Currently we rely on the values in the label being accurate. If 2276786Slclee * dkl_rpm or dkl_pcly are zero in the label, use a default value. 2277786Slclee * 2278786Slclee * Note: In the future a MODE SENSE may be used to retrieve this data, 2279786Slclee * although this command is optional in SCSI-2. 2280786Slclee */ 22813525Sshidokht cl->cl_g.dkg_rpm = (labp->dkl_rpm != 0) ? labp->dkl_rpm : 3600; 22823525Sshidokht cl->cl_g.dkg_pcyl = (labp->dkl_pcyl != 0) ? labp->dkl_pcyl : 22833525Sshidokht (cl->cl_g.dkg_ncyl + cl->cl_g.dkg_acyl); 2284786Slclee 2285786Slclee /* 2286786Slclee * The Read and Write reinstruct values may not be valid 2287786Slclee * for older disks. 2288786Slclee */ 22893525Sshidokht cl->cl_g.dkg_read_reinstruct = labp->dkl_read_reinstruct; 22903525Sshidokht cl->cl_g.dkg_write_reinstruct = labp->dkl_write_reinstruct; 2291786Slclee 2292786Slclee /* Fill in partition table. */ 2293786Slclee #if defined(_SUNOS_VTOC_8) 2294786Slclee for (i = 0; i < NDKMAP; i++) { 22953525Sshidokht cl->cl_map[i].dkl_cylno = labp->dkl_map[i].dkl_cylno; 22963525Sshidokht cl->cl_map[i].dkl_nblk = labp->dkl_map[i].dkl_nblk; 2297786Slclee } 2298786Slclee #endif 2299786Slclee #if defined(_SUNOS_VTOC_16) 2300786Slclee vpartp = labp->dkl_vtoc.v_part; 2301786Slclee track_capacity = labp->dkl_nhead * labp->dkl_nsect; 2302786Slclee 23033525Sshidokht /* Prevent divide by zero */ 23043525Sshidokht if (track_capacity == 0) { 23053525Sshidokht if (!(flags & CMLB_SILENT)) 23063525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN, 23073525Sshidokht "Corrupt label - zero nhead or nsect value\n"); 23083525Sshidokht 23093525Sshidokht return (CMLB_LABEL_IS_INVALID); 23103525Sshidokht } 23113525Sshidokht 2312786Slclee for (i = 0; i < NDKMAP; i++, vpartp++) { 23133525Sshidokht cl->cl_map[i].dkl_cylno = vpartp->p_start / track_capacity; 23143525Sshidokht cl->cl_map[i].dkl_nblk = vpartp->p_size; 2315786Slclee } 2316786Slclee #endif 2317786Slclee 2318786Slclee /* Fill in VTOC Structure. */ 23193525Sshidokht bcopy(&labp->dkl_vtoc, &cl->cl_vtoc, sizeof (struct dk_vtoc)); 2320786Slclee #if defined(_SUNOS_VTOC_8) 2321786Slclee /* 2322786Slclee * The 8-slice vtoc does not include the ascii label; save it into 2323786Slclee * the device's soft state structure here. 2324786Slclee */ 23253525Sshidokht bcopy(labp->dkl_asciilabel, cl->cl_asciilabel, LEN_DKL_ASCII); 2326786Slclee #endif 2327786Slclee 2328786Slclee /* Now look for a valid capacity. */ 23293525Sshidokht track_capacity = (cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect); 23303525Sshidokht label_capacity = (cl->cl_g.dkg_ncyl * track_capacity); 23313525Sshidokht 23323525Sshidokht if (cl->cl_g.dkg_acyl) { 2333786Slclee #if defined(__i386) || defined(__amd64) 2334786Slclee /* we may have > 1 alts cylinder */ 23353525Sshidokht label_capacity += (track_capacity * cl->cl_g.dkg_acyl); 2336786Slclee #else 2337786Slclee label_capacity += track_capacity; 2338786Slclee #endif 2339786Slclee } 2340786Slclee 2341786Slclee /* 23423525Sshidokht * Force check here to ensure the computed capacity is valid. 23433525Sshidokht * If capacity is zero, it indicates an invalid label and 23443525Sshidokht * we should abort updating the relevant data then. 23453525Sshidokht */ 23463525Sshidokht if (label_capacity == 0) { 23473525Sshidokht if (!(flags & CMLB_SILENT)) 23483525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN, 23493525Sshidokht "Corrupt label - no valid capacity could be " 23503525Sshidokht "retrieved\n"); 23513525Sshidokht 23523525Sshidokht return (CMLB_LABEL_IS_INVALID); 23533525Sshidokht } 23543525Sshidokht 23553525Sshidokht /* Mark the geometry as valid. */ 23563525Sshidokht cl->cl_f_geometry_is_valid = TRUE; 23573525Sshidokht 23583525Sshidokht /* 2359786Slclee * if we got invalidated when mutex exit and entered again, 2360786Slclee * if blockcount different than when we came in, need to 2361786Slclee * retry from beginning of cmlb_validate_geometry. 2362786Slclee * revisit this on next phase of utilizing this for 2363786Slclee * sd. 2364786Slclee */ 2365786Slclee 23663525Sshidokht if (label_capacity <= cl->cl_blockcount) { 2367786Slclee #if defined(_SUNOS_VTOC_8) 2368786Slclee /* 2369786Slclee * We can't let this happen on drives that are subdivided 2370786Slclee * into logical disks (i.e., that have an fdisk table). 23713525Sshidokht * The cl_blockcount field should always hold the full media 2372786Slclee * size in sectors, period. This code would overwrite 23733525Sshidokht * cl_blockcount with the size of the Solaris fdisk partition. 2374786Slclee */ 23753525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 2376786Slclee "cmlb_uselabel: Label %d blocks; Drive %d blocks\n", 23773525Sshidokht label_capacity, cl->cl_blockcount); 23783525Sshidokht cl->cl_solaris_size = label_capacity; 2379786Slclee 2380786Slclee #endif /* defined(_SUNOS_VTOC_8) */ 2381786Slclee goto done; 2382786Slclee } 2383786Slclee 23843525Sshidokht if (ISCD(cl)) { 2385786Slclee /* For CDROMs, we trust that the data in the label is OK. */ 2386786Slclee #if defined(_SUNOS_VTOC_8) 2387786Slclee for (i = 0; i < NDKMAP; i++) { 2388786Slclee part_end = labp->dkl_nhead * labp->dkl_nsect * 2389786Slclee labp->dkl_map[i].dkl_cylno + 2390786Slclee labp->dkl_map[i].dkl_nblk - 1; 2391786Slclee 2392786Slclee if ((labp->dkl_map[i].dkl_nblk) && 23933525Sshidokht (part_end > cl->cl_blockcount)) { 23943525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 2395786Slclee break; 2396786Slclee } 2397786Slclee } 2398786Slclee #endif 2399786Slclee #if defined(_SUNOS_VTOC_16) 2400786Slclee vpartp = &(labp->dkl_vtoc.v_part[0]); 2401786Slclee for (i = 0; i < NDKMAP; i++, vpartp++) { 2402786Slclee part_end = vpartp->p_start + vpartp->p_size; 2403786Slclee if ((vpartp->p_size > 0) && 24043525Sshidokht (part_end > cl->cl_blockcount)) { 24053525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 2406786Slclee break; 2407786Slclee } 2408786Slclee } 2409786Slclee #endif 2410786Slclee } else { 24113525Sshidokht /* label_capacity > cl->cl_blockcount */ 24123525Sshidokht if (!(flags & CMLB_SILENT)) { 24133525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN, 24143525Sshidokht "Corrupt label - bad geometry\n"); 24153525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_CONT, 24163525Sshidokht "Label says %llu blocks; Drive says %llu blocks\n", 24173525Sshidokht label_capacity, cl->cl_blockcount); 24183525Sshidokht } 24193525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 2420786Slclee label_error = CMLB_LABEL_IS_INVALID; 2421786Slclee } 2422786Slclee 2423786Slclee done: 2424786Slclee 24253525Sshidokht cmlb_dbg(CMLB_INFO, cl, "cmlb_uselabel: (label geometry)\n"); 24263525Sshidokht cmlb_dbg(CMLB_INFO, cl, 2427786Slclee " ncyl: %d; acyl: %d; nhead: %d; nsect: %d\n", 24283525Sshidokht cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl, 24293525Sshidokht cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect); 24303525Sshidokht 24313525Sshidokht cmlb_dbg(CMLB_INFO, cl, 2432786Slclee " label_capacity: %d; intrlv: %d; rpm: %d\n", 24333525Sshidokht cl->cl_blockcount, cl->cl_g.dkg_intrlv, cl->cl_g.dkg_rpm); 24343525Sshidokht cmlb_dbg(CMLB_INFO, cl, " wrt_reinstr: %d; rd_reinstr: %d\n", 24353525Sshidokht cl->cl_g.dkg_write_reinstruct, cl->cl_g.dkg_read_reinstruct); 24363525Sshidokht 24373525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 2438786Slclee 2439786Slclee return (label_error); 2440786Slclee } 2441786Slclee 2442786Slclee 2443786Slclee /* 2444786Slclee * Function: cmlb_build_default_label 2445786Slclee * 2446786Slclee * Description: Generate a default label for those devices that do not have 2447786Slclee * one, e.g., new media, removable cartridges, etc.. 2448786Slclee * 2449786Slclee * Context: Kernel thread only 2450786Slclee */ 24513525Sshidokht /*ARGSUSED*/ 2452786Slclee static void 24533525Sshidokht cmlb_build_default_label(struct cmlb_lun *cl, void *tg_cookie) 2454786Slclee { 2455786Slclee #if defined(_SUNOS_VTOC_16) 2456786Slclee uint_t phys_spc; 2457786Slclee uint_t disksize; 24583525Sshidokht struct dk_geom cl_g; 24593525Sshidokht diskaddr_t capacity; 2460786Slclee #endif 2461786Slclee 24623525Sshidokht ASSERT(cl != NULL); 24633525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 2464786Slclee 2465786Slclee #if defined(_SUNOS_VTOC_8) 2466786Slclee /* 2467786Slclee * Note: This is a legacy check for non-removable devices on VTOC_8 2468786Slclee * only. This may be a valid check for VTOC_16 as well. 24693525Sshidokht * Once we understand why there is this difference between SPARC and 24703525Sshidokht * x86 platform, we could remove this legacy check. 2471786Slclee */ 24723525Sshidokht if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) { 2473786Slclee return; 2474786Slclee } 2475786Slclee #endif 2476786Slclee 24773525Sshidokht bzero(&cl->cl_g, sizeof (struct dk_geom)); 24783525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc)); 24793525Sshidokht bzero(&cl->cl_map, NDKMAP * (sizeof (struct dk_map))); 2480786Slclee 2481786Slclee #if defined(_SUNOS_VTOC_8) 2482786Slclee 2483786Slclee /* 2484786Slclee * It's a REMOVABLE media, therefore no label (on sparc, anyway). 2485786Slclee * But it is still necessary to set up various geometry information, 2486786Slclee * and we are doing this here. 2487786Slclee */ 2488786Slclee 2489786Slclee /* 2490786Slclee * For the rpm, we use the minimum for the disk. For the head, cyl, 2491786Slclee * and number of sector per track, if the capacity <= 1GB, head = 64, 2492786Slclee * sect = 32. else head = 255, sect 63 Note: the capacity should be 2493786Slclee * equal to C*H*S values. This will cause some truncation of size due 2494786Slclee * to round off errors. For CD-ROMs, this truncation can have adverse 2495786Slclee * side effects, so returning ncyl and nhead as 1. The nsect will 2496786Slclee * overflow for most of CD-ROMs as nsect is of type ushort. (4190569) 2497786Slclee */ 24983525Sshidokht cl->cl_solaris_size = cl->cl_blockcount; 24993525Sshidokht if (ISCD(cl)) { 2500786Slclee tg_attribute_t tgattribute; 2501786Slclee int is_writable; 2502786Slclee /* 2503786Slclee * Preserve the old behavior for non-writable 2504786Slclee * medias. Since dkg_nsect is a ushort, it 2505786Slclee * will lose bits as cdroms have more than 2506786Slclee * 65536 sectors. So if we recalculate 2507786Slclee * capacity, it will become much shorter. 2508786Slclee * But the dkg_* information is not 2509786Slclee * used for CDROMs so it is OK. But for 2510786Slclee * Writable CDs we need this information 2511786Slclee * to be valid (for newfs say). So we 2512786Slclee * make nsect and nhead > 1 that way 2513786Slclee * nsect can still stay within ushort limit 2514786Slclee * without losing any bits. 2515786Slclee */ 2516786Slclee 2517786Slclee bzero(&tgattribute, sizeof (tg_attribute_t)); 2518786Slclee 25193525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 25203525Sshidokht is_writable = 25213525Sshidokht (DK_TG_GETATTRIBUTE(cl, &tgattribute, tg_cookie) == 0) ? 2522786Slclee tgattribute.media_is_writable : 1; 25233525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 2524786Slclee 2525786Slclee if (is_writable) { 25263525Sshidokht cl->cl_g.dkg_nhead = 64; 25273525Sshidokht cl->cl_g.dkg_nsect = 32; 25283525Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount / (64 * 32); 25293525Sshidokht cl->cl_solaris_size = cl->cl_g.dkg_ncyl * 25303525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect; 2531786Slclee } else { 25323525Sshidokht cl->cl_g.dkg_ncyl = 1; 25333525Sshidokht cl->cl_g.dkg_nhead = 1; 25343525Sshidokht cl->cl_g.dkg_nsect = cl->cl_blockcount; 2535786Slclee } 2536786Slclee } else { 25373525Sshidokht if (cl->cl_blockcount <= 0x1000) { 2538786Slclee /* unlabeled SCSI floppy device */ 25393525Sshidokht cl->cl_g.dkg_nhead = 2; 25403525Sshidokht cl->cl_g.dkg_ncyl = 80; 25413525Sshidokht cl->cl_g.dkg_nsect = cl->cl_blockcount / (2 * 80); 25423525Sshidokht } else if (cl->cl_blockcount <= 0x200000) { 25433525Sshidokht cl->cl_g.dkg_nhead = 64; 25443525Sshidokht cl->cl_g.dkg_nsect = 32; 25453525Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount / (64 * 32); 2546786Slclee } else { 25473525Sshidokht cl->cl_g.dkg_nhead = 255; 25483525Sshidokht cl->cl_g.dkg_nsect = 63; 25493525Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount / (255 * 63); 2550786Slclee } 25513525Sshidokht cl->cl_solaris_size = 25523525Sshidokht cl->cl_g.dkg_ncyl * cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect; 2553786Slclee 2554786Slclee } 2555786Slclee 25563525Sshidokht cl->cl_g.dkg_acyl = 0; 25573525Sshidokht cl->cl_g.dkg_bcyl = 0; 25583525Sshidokht cl->cl_g.dkg_rpm = 200; 25593525Sshidokht cl->cl_asciilabel[0] = '\0'; 25603525Sshidokht cl->cl_g.dkg_pcyl = cl->cl_g.dkg_ncyl; 25613525Sshidokht 25623525Sshidokht cl->cl_map[0].dkl_cylno = 0; 25633525Sshidokht cl->cl_map[0].dkl_nblk = cl->cl_solaris_size; 25643525Sshidokht 25653525Sshidokht cl->cl_map[2].dkl_cylno = 0; 25663525Sshidokht cl->cl_map[2].dkl_nblk = cl->cl_solaris_size; 2567786Slclee 2568786Slclee #elif defined(_SUNOS_VTOC_16) 2569786Slclee 25703525Sshidokht if (cl->cl_solaris_size == 0) { 2571786Slclee /* 2572786Slclee * Got fdisk table but no solaris entry therefore 2573786Slclee * don't create a default label 2574786Slclee */ 25753525Sshidokht cl->cl_f_geometry_is_valid = TRUE; 2576786Slclee return; 2577786Slclee } 2578786Slclee 2579786Slclee /* 2580786Slclee * For CDs we continue to use the physical geometry to calculate 2581786Slclee * number of cylinders. All other devices must convert the 2582786Slclee * physical geometry (cmlb_geom) to values that will fit 2583786Slclee * in a dk_geom structure. 2584786Slclee */ 25853525Sshidokht if (ISCD(cl)) { 25863525Sshidokht phys_spc = cl->cl_pgeom.g_nhead * cl->cl_pgeom.g_nsect; 2587786Slclee } else { 2588786Slclee /* Convert physical geometry to disk geometry */ 25893525Sshidokht bzero(&cl_g, sizeof (struct dk_geom)); 25903525Sshidokht 25913525Sshidokht /* 25923525Sshidokht * Refer to comments related to off-by-1 at the 25933525Sshidokht * header of this file. 25943525Sshidokht * Before caculating geometry, capacity should be 25953525Sshidokht * decreased by 1. 25963525Sshidokht */ 25973525Sshidokht 25983525Sshidokht if (cl->cl_alter_behavior & CMLB_OFF_BY_ONE) 25993525Sshidokht capacity = cl->cl_blockcount - 1; 26003525Sshidokht else 26013525Sshidokht capacity = cl->cl_blockcount; 26023525Sshidokht 26033525Sshidokht 26043525Sshidokht cmlb_convert_geometry(capacity, &cl_g); 26053525Sshidokht bcopy(&cl_g, &cl->cl_g, sizeof (cl->cl_g)); 26063525Sshidokht phys_spc = cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect; 2607786Slclee } 2608786Slclee 26093525Sshidokht ASSERT(phys_spc != 0); 26103525Sshidokht cl->cl_g.dkg_pcyl = cl->cl_solaris_size / phys_spc; 26113525Sshidokht cl->cl_g.dkg_acyl = DK_ACYL; 26123525Sshidokht cl->cl_g.dkg_ncyl = cl->cl_g.dkg_pcyl - DK_ACYL; 26133525Sshidokht disksize = cl->cl_g.dkg_ncyl * phys_spc; 26143525Sshidokht 26153525Sshidokht if (ISCD(cl)) { 2616786Slclee /* 2617786Slclee * CD's don't use the "heads * sectors * cyls"-type of 2618786Slclee * geometry, but instead use the entire capacity of the media. 2619786Slclee */ 26203525Sshidokht disksize = cl->cl_solaris_size; 26213525Sshidokht cl->cl_g.dkg_nhead = 1; 26223525Sshidokht cl->cl_g.dkg_nsect = 1; 26233525Sshidokht cl->cl_g.dkg_rpm = 26243525Sshidokht (cl->cl_pgeom.g_rpm == 0) ? 200 : cl->cl_pgeom.g_rpm; 26253525Sshidokht 26263525Sshidokht cl->cl_vtoc.v_part[0].p_start = 0; 26273525Sshidokht cl->cl_vtoc.v_part[0].p_size = disksize; 26283525Sshidokht cl->cl_vtoc.v_part[0].p_tag = V_BACKUP; 26293525Sshidokht cl->cl_vtoc.v_part[0].p_flag = V_UNMNT; 26303525Sshidokht 26313525Sshidokht cl->cl_map[0].dkl_cylno = 0; 26323525Sshidokht cl->cl_map[0].dkl_nblk = disksize; 26333525Sshidokht cl->cl_offset[0] = 0; 2634786Slclee 2635786Slclee } else { 2636786Slclee /* 2637786Slclee * Hard disks and removable media cartridges 2638786Slclee */ 26393525Sshidokht cl->cl_g.dkg_rpm = 26403525Sshidokht (cl->cl_pgeom.g_rpm == 0) ? 3600: cl->cl_pgeom.g_rpm; 26413525Sshidokht cl->cl_vtoc.v_sectorsz = cl->cl_sys_blocksize; 2642786Slclee 2643786Slclee /* Add boot slice */ 26443525Sshidokht cl->cl_vtoc.v_part[8].p_start = 0; 26453525Sshidokht cl->cl_vtoc.v_part[8].p_size = phys_spc; 26463525Sshidokht cl->cl_vtoc.v_part[8].p_tag = V_BOOT; 26473525Sshidokht cl->cl_vtoc.v_part[8].p_flag = V_UNMNT; 26483525Sshidokht 26493525Sshidokht cl->cl_map[8].dkl_cylno = 0; 26503525Sshidokht cl->cl_map[8].dkl_nblk = phys_spc; 26513525Sshidokht cl->cl_offset[8] = 0; 26523525Sshidokht 26533525Sshidokht if ((cl->cl_alter_behavior & 2654786Slclee CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT) && 26553525Sshidokht cl->cl_device_type == DTYPE_DIRECT) { 26563525Sshidokht cl->cl_vtoc.v_part[9].p_start = phys_spc; 26573525Sshidokht cl->cl_vtoc.v_part[9].p_size = 2 * phys_spc; 26583525Sshidokht cl->cl_vtoc.v_part[9].p_tag = V_ALTSCTR; 26593525Sshidokht cl->cl_vtoc.v_part[9].p_flag = 0; 26603525Sshidokht 26613525Sshidokht cl->cl_map[9].dkl_cylno = 1; 26623525Sshidokht cl->cl_map[9].dkl_nblk = 2 * phys_spc; 26633525Sshidokht cl->cl_offset[9] = phys_spc; 2664786Slclee } 2665786Slclee } 2666786Slclee 26673525Sshidokht cl->cl_g.dkg_apc = 0; 26683525Sshidokht cl->cl_vtoc.v_nparts = V_NUMPAR; 26693525Sshidokht cl->cl_vtoc.v_version = V_VERSION; 2670786Slclee 2671786Slclee /* Add backup slice */ 26723525Sshidokht cl->cl_vtoc.v_part[2].p_start = 0; 26733525Sshidokht cl->cl_vtoc.v_part[2].p_size = disksize; 26743525Sshidokht cl->cl_vtoc.v_part[2].p_tag = V_BACKUP; 26753525Sshidokht cl->cl_vtoc.v_part[2].p_flag = V_UNMNT; 26763525Sshidokht 26773525Sshidokht cl->cl_map[2].dkl_cylno = 0; 26783525Sshidokht cl->cl_map[2].dkl_nblk = disksize; 26793525Sshidokht cl->cl_offset[2] = 0; 26803525Sshidokht 26813525Sshidokht (void) sprintf(cl->cl_vtoc.v_asciilabel, "DEFAULT cyl %d alt %d" 26823525Sshidokht " hd %d sec %d", cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl, 26833525Sshidokht cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect); 2684786Slclee 2685786Slclee #else 2686786Slclee #error "No VTOC format defined." 2687786Slclee #endif 2688786Slclee 26893525Sshidokht cl->cl_g.dkg_read_reinstruct = 0; 26903525Sshidokht cl->cl_g.dkg_write_reinstruct = 0; 26913525Sshidokht 26923525Sshidokht cl->cl_g.dkg_intrlv = 1; 26933525Sshidokht 26943525Sshidokht cl->cl_vtoc.v_sanity = VTOC_SANE; 26953525Sshidokht 26963525Sshidokht cl->cl_f_geometry_is_valid = TRUE; 26973525Sshidokht cl->cl_vtoc_label_is_from_media = 0; 26983525Sshidokht 26993525Sshidokht cmlb_dbg(CMLB_INFO, cl, 2700786Slclee "cmlb_build_default_label: Default label created: " 2701786Slclee "cyl: %d\tacyl: %d\tnhead: %d\tnsect: %d\tcap: %d\n", 27023525Sshidokht cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl, cl->cl_g.dkg_nhead, 27033525Sshidokht cl->cl_g.dkg_nsect, cl->cl_blockcount); 2704786Slclee } 2705786Slclee 2706786Slclee 2707786Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 2708786Slclee /* 2709786Slclee * Max CHS values, as they are encoded into bytes, for 1022/254/63 2710786Slclee */ 2711786Slclee #define LBA_MAX_SECT (63 | ((1022 & 0x300) >> 2)) 2712786Slclee #define LBA_MAX_CYL (1022 & 0xFF) 2713786Slclee #define LBA_MAX_HEAD (254) 2714786Slclee 2715786Slclee 2716786Slclee /* 2717786Slclee * Function: cmlb_has_max_chs_vals 2718786Slclee * 2719786Slclee * Description: Return TRUE if Cylinder-Head-Sector values are all at maximum. 2720786Slclee * 2721786Slclee * Arguments: fdp - ptr to CHS info 2722786Slclee * 2723786Slclee * Return Code: True or false 2724786Slclee * 2725786Slclee * Context: Any. 2726786Slclee */ 2727786Slclee static int 2728786Slclee cmlb_has_max_chs_vals(struct ipart *fdp) 2729786Slclee { 2730786Slclee return ((fdp->begcyl == LBA_MAX_CYL) && 2731786Slclee (fdp->beghead == LBA_MAX_HEAD) && 2732786Slclee (fdp->begsect == LBA_MAX_SECT) && 2733786Slclee (fdp->endcyl == LBA_MAX_CYL) && 2734786Slclee (fdp->endhead == LBA_MAX_HEAD) && 2735786Slclee (fdp->endsect == LBA_MAX_SECT)); 2736786Slclee } 2737786Slclee #endif 2738786Slclee 2739786Slclee /* 2740786Slclee * Function: cmlb_dkio_get_geometry 2741786Slclee * 2742786Slclee * Description: This routine is the driver entry point for handling user 2743786Slclee * requests to get the device geometry (DKIOCGGEOM). 2744786Slclee * 2745786Slclee * Arguments: 27463525Sshidokht * arg pointer to user provided dk_geom structure specifying 2747786Slclee * the controller's notion of the current geometry. 27483525Sshidokht * 27493525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 27503525Sshidokht * directly from the mode argument of ioctl(). 27513525Sshidokht * 27523525Sshidokht * tg_cookie cookie from target driver to be passed back to target 27533525Sshidokht * driver when we call back to it through tg_ops. 2754786Slclee * 2755786Slclee * Return Code: 0 2756786Slclee * EFAULT 2757786Slclee * ENXIO 2758786Slclee * EIO 2759786Slclee */ 2760786Slclee static int 27613525Sshidokht cmlb_dkio_get_geometry(struct cmlb_lun *cl, caddr_t arg, int flag, 27623525Sshidokht void *tg_cookie) 2763786Slclee { 2764786Slclee struct dk_geom *tmp_geom = NULL; 2765786Slclee int rval = 0; 2766786Slclee 2767786Slclee /* 2768786Slclee * cmlb_validate_geometry does not spin a disk up 27693525Sshidokht * if it was spcl down. We need to make sure it 2770786Slclee * is ready. 2771786Slclee */ 27723525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 27733525Sshidokht rval = cmlb_validate_geometry(cl, 1, 0, tg_cookie); 2774786Slclee #if defined(_SUNOS_VTOC_8) 2775786Slclee if (rval == EINVAL && 27763525Sshidokht cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8) { 2777786Slclee /* 2778786Slclee * This is to return a default label geometry even when we 2779786Slclee * do not really assume a default label for the device. 2780786Slclee * dad driver utilizes this. 2781786Slclee */ 27823525Sshidokht if (cl->cl_blockcount <= DK_MAX_BLOCKS) { 27833525Sshidokht cmlb_setup_default_geometry(cl, tg_cookie); 2784786Slclee rval = 0; 2785786Slclee } 2786786Slclee } 2787786Slclee #endif 2788786Slclee if (rval) { 27893525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 2790786Slclee return (rval); 2791786Slclee } 2792786Slclee 2793786Slclee #if defined(__i386) || defined(__amd64) 27943525Sshidokht if (cl->cl_solaris_size == 0) { 27953525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 2796786Slclee return (EIO); 2797786Slclee } 2798786Slclee #endif 2799786Slclee 2800786Slclee /* 2801786Slclee * Make a local copy of the soft state geometry to avoid some potential 2802786Slclee * race conditions associated with holding the mutex and updating the 2803786Slclee * write_reinstruct value 2804786Slclee */ 2805786Slclee tmp_geom = kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP); 28063525Sshidokht bcopy(&cl->cl_g, tmp_geom, sizeof (struct dk_geom)); 2807786Slclee 2808786Slclee if (tmp_geom->dkg_write_reinstruct == 0) { 2809786Slclee tmp_geom->dkg_write_reinstruct = 2810786Slclee (int)((int)(tmp_geom->dkg_nsect * tmp_geom->dkg_rpm * 2811786Slclee cmlb_rot_delay) / (int)60000); 2812786Slclee } 28133525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 2814786Slclee 2815786Slclee rval = ddi_copyout(tmp_geom, (void *)arg, sizeof (struct dk_geom), 2816786Slclee flag); 2817786Slclee if (rval != 0) { 2818786Slclee rval = EFAULT; 2819786Slclee } 2820786Slclee 2821786Slclee kmem_free(tmp_geom, sizeof (struct dk_geom)); 2822786Slclee return (rval); 2823786Slclee 2824786Slclee } 2825786Slclee 2826786Slclee 2827786Slclee /* 2828786Slclee * Function: cmlb_dkio_set_geometry 2829786Slclee * 2830786Slclee * Description: This routine is the driver entry point for handling user 2831786Slclee * requests to set the device geometry (DKIOCSGEOM). The actual 2832786Slclee * device geometry is not updated, just the driver "notion" of it. 2833786Slclee * 2834786Slclee * Arguments: 28353525Sshidokht * arg pointer to user provided dk_geom structure used to set 2836786Slclee * the controller's notion of the current geometry. 28373525Sshidokht * 28383525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 28393525Sshidokht * directly from the mode argument of ioctl(). 28403525Sshidokht * 28413525Sshidokht * tg_cookie cookie from target driver to be passed back to target 28423525Sshidokht * driver when we call back to it through tg_ops. 2843786Slclee * 2844786Slclee * Return Code: 0 2845786Slclee * EFAULT 2846786Slclee * ENXIO 2847786Slclee * EIO 2848786Slclee */ 2849786Slclee static int 28503525Sshidokht cmlb_dkio_set_geometry(struct cmlb_lun *cl, caddr_t arg, int flag) 2851786Slclee { 2852786Slclee struct dk_geom *tmp_geom; 2853786Slclee struct dk_map *lp; 2854786Slclee int rval = 0; 2855786Slclee int i; 2856786Slclee 2857786Slclee 2858786Slclee #if defined(__i386) || defined(__amd64) 28593525Sshidokht if (cl->cl_solaris_size == 0) { 2860786Slclee return (EIO); 2861786Slclee } 2862786Slclee #endif 2863786Slclee /* 2864786Slclee * We need to copy the user specified geometry into local 2865786Slclee * storage and then update the softstate. We don't want to hold 2866786Slclee * the mutex and copyin directly from the user to the soft state 2867786Slclee */ 2868786Slclee tmp_geom = (struct dk_geom *) 2869786Slclee kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP); 2870786Slclee rval = ddi_copyin(arg, tmp_geom, sizeof (struct dk_geom), flag); 2871786Slclee if (rval != 0) { 2872786Slclee kmem_free(tmp_geom, sizeof (struct dk_geom)); 2873786Slclee return (EFAULT); 2874786Slclee } 2875786Slclee 28763525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 28773525Sshidokht bcopy(tmp_geom, &cl->cl_g, sizeof (struct dk_geom)); 2878786Slclee for (i = 0; i < NDKMAP; i++) { 28793525Sshidokht lp = &cl->cl_map[i]; 28803525Sshidokht cl->cl_offset[i] = 28813525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno; 2882786Slclee #if defined(__i386) || defined(__amd64) 28833525Sshidokht cl->cl_offset[i] += cl->cl_solaris_offset; 2884786Slclee #endif 2885786Slclee } 28863525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 28873525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 2888786Slclee kmem_free(tmp_geom, sizeof (struct dk_geom)); 2889786Slclee 2890786Slclee return (rval); 2891786Slclee } 2892786Slclee 2893786Slclee /* 2894786Slclee * Function: cmlb_dkio_get_partition 2895786Slclee * 2896786Slclee * Description: This routine is the driver entry point for handling user 2897786Slclee * requests to get the partition table (DKIOCGAPART). 2898786Slclee * 2899786Slclee * Arguments: 29003525Sshidokht * arg pointer to user provided dk_allmap structure specifying 2901786Slclee * the controller's notion of the current partition table. 29023525Sshidokht * 29033525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 29043525Sshidokht * directly from the mode argument of ioctl(). 29053525Sshidokht * 29063525Sshidokht * tg_cookie cookie from target driver to be passed back to target 29073525Sshidokht * driver when we call back to it through tg_ops. 2908786Slclee * 2909786Slclee * Return Code: 0 2910786Slclee * EFAULT 2911786Slclee * ENXIO 2912786Slclee * EIO 2913786Slclee */ 2914786Slclee static int 29153525Sshidokht cmlb_dkio_get_partition(struct cmlb_lun *cl, caddr_t arg, int flag, 29163525Sshidokht void *tg_cookie) 2917786Slclee { 2918786Slclee int rval = 0; 2919786Slclee int size; 2920786Slclee 2921786Slclee /* 2922786Slclee * Make sure the geometry is valid before getting the partition 2923786Slclee * information. 2924786Slclee */ 29253525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 29263525Sshidokht if ((rval = cmlb_validate_geometry(cl, 1, 0, tg_cookie)) != 0) { 29273525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 2928786Slclee return (rval); 2929786Slclee } 29303525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 2931786Slclee 2932786Slclee #if defined(__i386) || defined(__amd64) 29333525Sshidokht if (cl->cl_solaris_size == 0) { 2934786Slclee return (EIO); 2935786Slclee } 2936786Slclee #endif 2937786Slclee 2938786Slclee #ifdef _MULTI_DATAMODEL 2939786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 2940786Slclee case DDI_MODEL_ILP32: { 2941786Slclee struct dk_map32 dk_map32[NDKMAP]; 2942786Slclee int i; 2943786Slclee 2944786Slclee for (i = 0; i < NDKMAP; i++) { 29453525Sshidokht dk_map32[i].dkl_cylno = cl->cl_map[i].dkl_cylno; 29463525Sshidokht dk_map32[i].dkl_nblk = cl->cl_map[i].dkl_nblk; 2947786Slclee } 2948786Slclee size = NDKMAP * sizeof (struct dk_map32); 2949786Slclee rval = ddi_copyout(dk_map32, (void *)arg, size, flag); 2950786Slclee if (rval != 0) { 2951786Slclee rval = EFAULT; 2952786Slclee } 2953786Slclee break; 2954786Slclee } 2955786Slclee case DDI_MODEL_NONE: 2956786Slclee size = NDKMAP * sizeof (struct dk_map); 29573525Sshidokht rval = ddi_copyout(cl->cl_map, (void *)arg, size, flag); 2958786Slclee if (rval != 0) { 2959786Slclee rval = EFAULT; 2960786Slclee } 2961786Slclee break; 2962786Slclee } 2963786Slclee #else /* ! _MULTI_DATAMODEL */ 2964786Slclee size = NDKMAP * sizeof (struct dk_map); 29653525Sshidokht rval = ddi_copyout(cl->cl_map, (void *)arg, size, flag); 2966786Slclee if (rval != 0) { 2967786Slclee rval = EFAULT; 2968786Slclee } 2969786Slclee #endif /* _MULTI_DATAMODEL */ 2970786Slclee return (rval); 2971786Slclee } 2972786Slclee 2973786Slclee /* 2974786Slclee * Function: cmlb_dkio_set_partition 2975786Slclee * 2976786Slclee * Description: This routine is the driver entry point for handling user 2977786Slclee * requests to set the partition table (DKIOCSAPART). The actual 2978786Slclee * device partition is not updated. 2979786Slclee * 2980786Slclee * Arguments: 2981786Slclee * arg - pointer to user provided dk_allmap structure used to set 2982786Slclee * the controller's notion of the partition table. 2983786Slclee * flag - this argument is a pass through to ddi_copyxxx() 2984786Slclee * directly from the mode argument of ioctl(). 2985786Slclee * 2986786Slclee * Return Code: 0 2987786Slclee * EINVAL 2988786Slclee * EFAULT 2989786Slclee * ENXIO 2990786Slclee * EIO 2991786Slclee */ 2992786Slclee static int 29933525Sshidokht cmlb_dkio_set_partition(struct cmlb_lun *cl, caddr_t arg, int flag) 2994786Slclee { 2995786Slclee struct dk_map dk_map[NDKMAP]; 2996786Slclee struct dk_map *lp; 2997786Slclee int rval = 0; 2998786Slclee int size; 2999786Slclee int i; 3000786Slclee #if defined(_SUNOS_VTOC_16) 3001786Slclee struct dkl_partition *vp; 3002786Slclee #endif 3003786Slclee 3004786Slclee /* 3005786Slclee * Set the map for all logical partitions. We lock 3006786Slclee * the priority just to make sure an interrupt doesn't 3007786Slclee * come in while the map is half updated. 3008786Slclee */ 30093525Sshidokht _NOTE(DATA_READABLE_WITHOUT_LOCK(cmlb_lun::cl_solaris_size)) 30103525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 30113525Sshidokht 30123525Sshidokht if (cl->cl_blockcount > DK_MAX_BLOCKS) { 30133525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3014786Slclee return (ENOTSUP); 3015786Slclee } 30163525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 30173525Sshidokht if (cl->cl_solaris_size == 0) { 3018786Slclee return (EIO); 3019786Slclee } 3020786Slclee 3021786Slclee #ifdef _MULTI_DATAMODEL 3022786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 3023786Slclee case DDI_MODEL_ILP32: { 3024786Slclee struct dk_map32 dk_map32[NDKMAP]; 3025786Slclee 3026786Slclee size = NDKMAP * sizeof (struct dk_map32); 3027786Slclee rval = ddi_copyin((void *)arg, dk_map32, size, flag); 3028786Slclee if (rval != 0) { 3029786Slclee return (EFAULT); 3030786Slclee } 3031786Slclee for (i = 0; i < NDKMAP; i++) { 3032786Slclee dk_map[i].dkl_cylno = dk_map32[i].dkl_cylno; 3033786Slclee dk_map[i].dkl_nblk = dk_map32[i].dkl_nblk; 3034786Slclee } 3035786Slclee break; 3036786Slclee } 3037786Slclee case DDI_MODEL_NONE: 3038786Slclee size = NDKMAP * sizeof (struct dk_map); 3039786Slclee rval = ddi_copyin((void *)arg, dk_map, size, flag); 3040786Slclee if (rval != 0) { 3041786Slclee return (EFAULT); 3042786Slclee } 3043786Slclee break; 3044786Slclee } 3045786Slclee #else /* ! _MULTI_DATAMODEL */ 3046786Slclee size = NDKMAP * sizeof (struct dk_map); 3047786Slclee rval = ddi_copyin((void *)arg, dk_map, size, flag); 3048786Slclee if (rval != 0) { 3049786Slclee return (EFAULT); 3050786Slclee } 3051786Slclee #endif /* _MULTI_DATAMODEL */ 3052786Slclee 30533525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 3054786Slclee /* Note: The size used in this bcopy is set based upon the data model */ 30553525Sshidokht bcopy(dk_map, cl->cl_map, size); 3056786Slclee #if defined(_SUNOS_VTOC_16) 30573525Sshidokht vp = (struct dkl_partition *)&(cl->cl_vtoc); 3058786Slclee #endif /* defined(_SUNOS_VTOC_16) */ 3059786Slclee for (i = 0; i < NDKMAP; i++) { 30603525Sshidokht lp = &cl->cl_map[i]; 30613525Sshidokht cl->cl_offset[i] = 30623525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno; 3063786Slclee #if defined(_SUNOS_VTOC_16) 30643525Sshidokht vp->p_start = cl->cl_offset[i]; 3065786Slclee vp->p_size = lp->dkl_nblk; 3066786Slclee vp++; 3067786Slclee #endif /* defined(_SUNOS_VTOC_16) */ 3068786Slclee #if defined(__i386) || defined(__amd64) 30693525Sshidokht cl->cl_offset[i] += cl->cl_solaris_offset; 3070786Slclee #endif 3071786Slclee } 30723525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3073786Slclee return (rval); 3074786Slclee } 3075786Slclee 3076786Slclee 3077786Slclee /* 3078786Slclee * Function: cmlb_dkio_get_vtoc 3079786Slclee * 3080786Slclee * Description: This routine is the driver entry point for handling user 3081786Slclee * requests to get the current volume table of contents 3082786Slclee * (DKIOCGVTOC). 3083786Slclee * 3084786Slclee * Arguments: 30853525Sshidokht * arg pointer to user provided vtoc structure specifying 3086786Slclee * the current vtoc. 30873525Sshidokht * 30883525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 30893525Sshidokht * directly from the mode argument of ioctl(). 30903525Sshidokht * 30913525Sshidokht * tg_cookie cookie from target driver to be passed back to target 30923525Sshidokht * driver when we call back to it through tg_ops. 3093786Slclee * 3094786Slclee * Return Code: 0 3095786Slclee * EFAULT 3096786Slclee * ENXIO 3097786Slclee * EIO 3098786Slclee */ 3099786Slclee static int 31003525Sshidokht cmlb_dkio_get_vtoc(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie) 3101786Slclee { 3102786Slclee #if defined(_SUNOS_VTOC_8) 3103786Slclee struct vtoc user_vtoc; 3104786Slclee #endif /* defined(_SUNOS_VTOC_8) */ 3105786Slclee int rval = 0; 3106786Slclee 31073525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 31083525Sshidokht rval = cmlb_validate_geometry(cl, 1, 0, tg_cookie); 3109786Slclee 3110786Slclee #if defined(_SUNOS_VTOC_8) 3111786Slclee if (rval == EINVAL && 31123525Sshidokht (cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8)) { 3113786Slclee /* 3114786Slclee * This is to return a default label even when we do not 3115786Slclee * really assume a default label for the device. 3116786Slclee * dad driver utilizes this. 3117786Slclee */ 31183525Sshidokht if (cl->cl_blockcount <= DK_MAX_BLOCKS) { 31193525Sshidokht cmlb_setup_default_geometry(cl, tg_cookie); 3120786Slclee rval = 0; 3121786Slclee } 3122786Slclee } 3123786Slclee #endif 3124786Slclee if (rval) { 31253525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3126786Slclee return (rval); 3127786Slclee } 3128786Slclee 3129786Slclee #if defined(_SUNOS_VTOC_8) 31303525Sshidokht cmlb_build_user_vtoc(cl, &user_vtoc); 31313525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3132786Slclee 3133786Slclee #ifdef _MULTI_DATAMODEL 3134786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 3135786Slclee case DDI_MODEL_ILP32: { 3136786Slclee struct vtoc32 user_vtoc32; 3137786Slclee 3138786Slclee vtoctovtoc32(user_vtoc, user_vtoc32); 3139786Slclee if (ddi_copyout(&user_vtoc32, (void *)arg, 3140786Slclee sizeof (struct vtoc32), flag)) { 3141786Slclee return (EFAULT); 3142786Slclee } 3143786Slclee break; 3144786Slclee } 3145786Slclee 3146786Slclee case DDI_MODEL_NONE: 3147786Slclee if (ddi_copyout(&user_vtoc, (void *)arg, 3148786Slclee sizeof (struct vtoc), flag)) { 3149786Slclee return (EFAULT); 3150786Slclee } 3151786Slclee break; 3152786Slclee } 3153786Slclee #else /* ! _MULTI_DATAMODEL */ 3154786Slclee if (ddi_copyout(&user_vtoc, (void *)arg, sizeof (struct vtoc), flag)) { 3155786Slclee return (EFAULT); 3156786Slclee } 3157786Slclee #endif /* _MULTI_DATAMODEL */ 3158786Slclee 3159786Slclee #elif defined(_SUNOS_VTOC_16) 31603525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3161786Slclee 3162786Slclee #ifdef _MULTI_DATAMODEL 3163786Slclee /* 31643525Sshidokht * The cl_vtoc structure is a "struct dk_vtoc" which is always 3165786Slclee * 32-bit to maintain compatibility with existing on-disk 3166786Slclee * structures. Thus, we need to convert the structure when copying 3167786Slclee * it out to a datamodel-dependent "struct vtoc" in a 64-bit 3168786Slclee * program. If the target is a 32-bit program, then no conversion 3169786Slclee * is necessary. 3170786Slclee */ 3171786Slclee /* LINTED: logical expression always true: op "||" */ 31723525Sshidokht ASSERT(sizeof (cl->cl_vtoc) == sizeof (struct vtoc32)); 3173786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 3174786Slclee case DDI_MODEL_ILP32: 31753525Sshidokht if (ddi_copyout(&(cl->cl_vtoc), (void *)arg, 31763525Sshidokht sizeof (cl->cl_vtoc), flag)) { 3177786Slclee return (EFAULT); 3178786Slclee } 3179786Slclee break; 3180786Slclee 3181786Slclee case DDI_MODEL_NONE: { 3182786Slclee struct vtoc user_vtoc; 3183786Slclee 31843525Sshidokht vtoc32tovtoc(cl->cl_vtoc, user_vtoc); 3185786Slclee if (ddi_copyout(&user_vtoc, (void *)arg, 3186786Slclee sizeof (struct vtoc), flag)) { 3187786Slclee return (EFAULT); 3188786Slclee } 3189786Slclee break; 3190786Slclee } 3191786Slclee } 3192786Slclee #else /* ! _MULTI_DATAMODEL */ 31933525Sshidokht if (ddi_copyout(&(cl->cl_vtoc), (void *)arg, sizeof (cl->cl_vtoc), 3194786Slclee flag)) { 3195786Slclee return (EFAULT); 3196786Slclee } 3197786Slclee #endif /* _MULTI_DATAMODEL */ 3198786Slclee #else 3199786Slclee #error "No VTOC format defined." 3200786Slclee #endif 3201786Slclee 3202786Slclee return (rval); 3203786Slclee } 3204786Slclee 3205786Slclee static int 32063525Sshidokht cmlb_dkio_get_efi(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie) 3207786Slclee { 3208786Slclee dk_efi_t user_efi; 3209786Slclee int rval = 0; 3210786Slclee void *buffer; 32113525Sshidokht diskaddr_t tgt_lba; 3212786Slclee 3213786Slclee if (ddi_copyin(arg, &user_efi, sizeof (dk_efi_t), flag)) 3214786Slclee return (EFAULT); 3215786Slclee 3216786Slclee user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64; 3217786Slclee 32183525Sshidokht tgt_lba = user_efi.dki_lba; 32193525Sshidokht 32203525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 32213525Sshidokht if ((cmlb_check_update_blockcount(cl, tg_cookie) != 0) || 32223525Sshidokht (cl->cl_tgt_blocksize == 0)) { 32233525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 32243525Sshidokht return (EINVAL); 32253525Sshidokht } 32263525Sshidokht if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) 32273525Sshidokht tgt_lba = tgt_lba * cl->cl_tgt_blocksize / 32283525Sshidokht cl->cl_sys_blocksize; 32293525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 32303525Sshidokht 3231786Slclee buffer = kmem_alloc(user_efi.dki_length, KM_SLEEP); 32323525Sshidokht rval = DK_TG_READ(cl, buffer, tgt_lba, user_efi.dki_length, tg_cookie); 3233786Slclee if (rval == 0 && ddi_copyout(buffer, user_efi.dki_data, 3234786Slclee user_efi.dki_length, flag) != 0) 3235786Slclee rval = EFAULT; 3236786Slclee 3237786Slclee kmem_free(buffer, user_efi.dki_length); 3238786Slclee return (rval); 3239786Slclee } 3240786Slclee 32413525Sshidokht #if defined(_SUNOS_VTOC_8) 3242786Slclee /* 3243786Slclee * Function: cmlb_build_user_vtoc 3244786Slclee * 3245786Slclee * Description: This routine populates a pass by reference variable with the 3246786Slclee * current volume table of contents. 3247786Slclee * 32483525Sshidokht * Arguments: cl - driver soft state (unit) structure 3249786Slclee * user_vtoc - pointer to vtoc structure to be populated 3250786Slclee */ 3251786Slclee static void 32523525Sshidokht cmlb_build_user_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc) 3253786Slclee { 3254786Slclee struct dk_map2 *lpart; 3255786Slclee struct dk_map *lmap; 3256786Slclee struct partition *vpart; 3257786Slclee int nblks; 3258786Slclee int i; 3259786Slclee 32603525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 3261786Slclee 3262786Slclee /* 3263786Slclee * Return vtoc structure fields in the provided VTOC area, addressed 3264786Slclee * by *vtoc. 3265786Slclee */ 3266786Slclee bzero(user_vtoc, sizeof (struct vtoc)); 32673525Sshidokht user_vtoc->v_bootinfo[0] = cl->cl_vtoc.v_bootinfo[0]; 32683525Sshidokht user_vtoc->v_bootinfo[1] = cl->cl_vtoc.v_bootinfo[1]; 32693525Sshidokht user_vtoc->v_bootinfo[2] = cl->cl_vtoc.v_bootinfo[2]; 3270786Slclee user_vtoc->v_sanity = VTOC_SANE; 32713525Sshidokht user_vtoc->v_version = cl->cl_vtoc.v_version; 32723525Sshidokht bcopy(cl->cl_vtoc.v_volume, user_vtoc->v_volume, LEN_DKL_VVOL); 32733525Sshidokht user_vtoc->v_sectorsz = cl->cl_sys_blocksize; 32743525Sshidokht user_vtoc->v_nparts = cl->cl_vtoc.v_nparts; 3275786Slclee 3276786Slclee for (i = 0; i < 10; i++) 32773525Sshidokht user_vtoc->v_reserved[i] = cl->cl_vtoc.v_reserved[i]; 3278786Slclee 3279786Slclee /* 3280786Slclee * Convert partitioning information. 3281786Slclee * 3282786Slclee * Note the conversion from starting cylinder number 3283786Slclee * to starting sector number. 3284786Slclee */ 32853525Sshidokht lmap = cl->cl_map; 32863525Sshidokht lpart = (struct dk_map2 *)cl->cl_vtoc.v_part; 3287786Slclee vpart = user_vtoc->v_part; 3288786Slclee 32893525Sshidokht nblks = cl->cl_g.dkg_nsect * cl->cl_g.dkg_nhead; 3290786Slclee 3291786Slclee for (i = 0; i < V_NUMPAR; i++) { 3292786Slclee vpart->p_tag = lpart->p_tag; 3293786Slclee vpart->p_flag = lpart->p_flag; 3294786Slclee vpart->p_start = lmap->dkl_cylno * nblks; 3295786Slclee vpart->p_size = lmap->dkl_nblk; 3296786Slclee lmap++; 3297786Slclee lpart++; 3298786Slclee vpart++; 3299786Slclee 3300786Slclee /* (4364927) */ 33013525Sshidokht user_vtoc->timestamp[i] = (time_t)cl->cl_vtoc.v_timestamp[i]; 3302786Slclee } 3303786Slclee 33043525Sshidokht bcopy(cl->cl_asciilabel, user_vtoc->v_asciilabel, LEN_DKL_ASCII); 3305786Slclee } 33063525Sshidokht #endif 3307786Slclee 3308786Slclee static int 33093525Sshidokht cmlb_dkio_partition(struct cmlb_lun *cl, caddr_t arg, int flag, 33103525Sshidokht void *tg_cookie) 3311786Slclee { 3312786Slclee struct partition64 p64; 3313786Slclee int rval = 0; 3314786Slclee uint_t nparts; 3315786Slclee efi_gpe_t *partitions; 3316786Slclee efi_gpt_t *buffer; 3317786Slclee diskaddr_t gpe_lba; 3318786Slclee 3319786Slclee if (ddi_copyin((const void *)arg, &p64, 3320786Slclee sizeof (struct partition64), flag)) { 3321786Slclee return (EFAULT); 3322786Slclee } 3323786Slclee 3324786Slclee buffer = kmem_alloc(EFI_MIN_ARRAY_SIZE, KM_SLEEP); 33253525Sshidokht rval = DK_TG_READ(cl, buffer, 1, DEV_BSIZE, tg_cookie); 3326786Slclee if (rval != 0) 3327786Slclee goto done_error; 3328786Slclee 3329786Slclee cmlb_swap_efi_gpt(buffer); 3330786Slclee 3331786Slclee if ((rval = cmlb_validate_efi(buffer)) != 0) 3332786Slclee goto done_error; 3333786Slclee 3334786Slclee nparts = buffer->efi_gpt_NumberOfPartitionEntries; 3335786Slclee gpe_lba = buffer->efi_gpt_PartitionEntryLBA; 3336786Slclee if (p64.p_partno > nparts) { 3337786Slclee /* couldn't find it */ 3338786Slclee rval = ESRCH; 3339786Slclee goto done_error; 3340786Slclee } 3341786Slclee /* 3342786Slclee * if we're dealing with a partition that's out of the normal 3343786Slclee * 16K block, adjust accordingly 3344786Slclee */ 3345786Slclee gpe_lba += p64.p_partno / sizeof (efi_gpe_t); 33463525Sshidokht rval = DK_TG_READ(cl, buffer, gpe_lba, EFI_MIN_ARRAY_SIZE, tg_cookie); 3347786Slclee 3348786Slclee if (rval) { 3349786Slclee goto done_error; 3350786Slclee } 3351786Slclee partitions = (efi_gpe_t *)buffer; 3352786Slclee 3353786Slclee cmlb_swap_efi_gpe(nparts, partitions); 3354786Slclee 3355786Slclee partitions += p64.p_partno; 3356786Slclee bcopy(&partitions->efi_gpe_PartitionTypeGUID, &p64.p_type, 3357786Slclee sizeof (struct uuid)); 3358786Slclee p64.p_start = partitions->efi_gpe_StartingLBA; 3359786Slclee p64.p_size = partitions->efi_gpe_EndingLBA - 33603525Sshidokht p64.p_start + 1; 3361786Slclee 3362786Slclee if (ddi_copyout(&p64, (void *)arg, sizeof (struct partition64), flag)) 3363786Slclee rval = EFAULT; 3364786Slclee 3365786Slclee done_error: 3366786Slclee kmem_free(buffer, EFI_MIN_ARRAY_SIZE); 3367786Slclee return (rval); 3368786Slclee } 3369786Slclee 3370786Slclee 3371786Slclee /* 3372786Slclee * Function: cmlb_dkio_set_vtoc 3373786Slclee * 3374786Slclee * Description: This routine is the driver entry point for handling user 3375786Slclee * requests to set the current volume table of contents 3376786Slclee * (DKIOCSVTOC). 3377786Slclee * 33783525Sshidokht * Arguments: 33793525Sshidokht * dev the device number 33803525Sshidokht * arg pointer to user provided vtoc structure used to set the 3381786Slclee * current vtoc. 33823525Sshidokht * 33833525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 33843525Sshidokht * directly from the mode argument of ioctl(). 33853525Sshidokht * 33863525Sshidokht * tg_cookie cookie from target driver to be passed back to target 33873525Sshidokht * driver when we call back to it through tg_ops. 3388786Slclee * 3389786Slclee * Return Code: 0 3390786Slclee * EFAULT 3391786Slclee * ENXIO 3392786Slclee * EINVAL 3393786Slclee * ENOTSUP 3394786Slclee */ 3395786Slclee static int 33963525Sshidokht cmlb_dkio_set_vtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag, 33973525Sshidokht void *tg_cookie) 3398786Slclee { 3399786Slclee struct vtoc user_vtoc; 3400786Slclee int rval = 0; 3401786Slclee 3402786Slclee #ifdef _MULTI_DATAMODEL 3403786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 3404786Slclee case DDI_MODEL_ILP32: { 3405786Slclee struct vtoc32 user_vtoc32; 3406786Slclee 3407786Slclee if (ddi_copyin((const void *)arg, &user_vtoc32, 3408786Slclee sizeof (struct vtoc32), flag)) { 3409786Slclee return (EFAULT); 3410786Slclee } 3411786Slclee vtoc32tovtoc(user_vtoc32, user_vtoc); 3412786Slclee break; 3413786Slclee } 3414786Slclee 3415786Slclee case DDI_MODEL_NONE: 3416786Slclee if (ddi_copyin((const void *)arg, &user_vtoc, 3417786Slclee sizeof (struct vtoc), flag)) { 3418786Slclee return (EFAULT); 3419786Slclee } 3420786Slclee break; 3421786Slclee } 3422786Slclee #else /* ! _MULTI_DATAMODEL */ 3423786Slclee if (ddi_copyin((const void *)arg, &user_vtoc, 3424786Slclee sizeof (struct vtoc), flag)) { 3425786Slclee return (EFAULT); 3426786Slclee } 3427786Slclee #endif /* _MULTI_DATAMODEL */ 3428786Slclee 34293525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 34303525Sshidokht if (cl->cl_blockcount > DK_MAX_BLOCKS) { 34313525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3432786Slclee return (ENOTSUP); 3433786Slclee } 34343525Sshidokht 34353525Sshidokht #if defined(__i386) || defined(__amd64) 34363525Sshidokht if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) { 34373525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 34383525Sshidokht return (EINVAL); 34393525Sshidokht } 34403525Sshidokht #endif 34413525Sshidokht 34423525Sshidokht if (cl->cl_g.dkg_ncyl == 0) { 34433525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3444786Slclee return (EINVAL); 3445786Slclee } 3446786Slclee 34473525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 34483525Sshidokht cmlb_clear_efi(cl, tg_cookie); 34493525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd"); 34503525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd,raw"); 34513525Sshidokht (void) ddi_create_minor_node(CMLB_DEVINFO(cl), "h", 3452786Slclee S_IFBLK, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 34533525Sshidokht cl->cl_node_type, NULL); 34543525Sshidokht (void) ddi_create_minor_node(CMLB_DEVINFO(cl), "h,raw", 3455786Slclee S_IFCHR, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 34563525Sshidokht cl->cl_node_type, NULL); 34573525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 34583525Sshidokht 34593525Sshidokht if ((rval = cmlb_build_label_vtoc(cl, &user_vtoc)) == 0) { 34603525Sshidokht if ((rval = cmlb_write_label(cl, tg_cookie)) == 0) { 34613525Sshidokht if (cmlb_validate_geometry(cl, 1, 0, tg_cookie) != 0) { 34623525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 3463786Slclee "cmlb_dkio_set_vtoc: " 3464786Slclee "Failed validate geometry\n"); 3465786Slclee } 3466786Slclee } 3467786Slclee } 34683525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3469786Slclee return (rval); 3470786Slclee } 3471786Slclee 3472786Slclee 3473786Slclee /* 3474786Slclee * Function: cmlb_build_label_vtoc 3475786Slclee * 3476786Slclee * Description: This routine updates the driver soft state current volume table 3477786Slclee * of contents based on a user specified vtoc. 3478786Slclee * 34793525Sshidokht * Arguments: cl - driver soft state (unit) structure 3480786Slclee * user_vtoc - pointer to vtoc structure specifying vtoc to be used 3481786Slclee * to update the driver soft state. 3482786Slclee * 3483786Slclee * Return Code: 0 3484786Slclee * EINVAL 3485786Slclee */ 3486786Slclee static int 34873525Sshidokht cmlb_build_label_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc) 3488786Slclee { 3489786Slclee struct dk_map *lmap; 3490786Slclee struct partition *vpart; 3491786Slclee int nblks; 3492786Slclee #if defined(_SUNOS_VTOC_8) 3493786Slclee int ncyl; 3494786Slclee struct dk_map2 *lpart; 3495786Slclee #endif /* defined(_SUNOS_VTOC_8) */ 3496786Slclee int i; 3497786Slclee 34983525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 3499786Slclee 3500786Slclee /* Sanity-check the vtoc */ 3501786Slclee if (user_vtoc->v_sanity != VTOC_SANE || 35023525Sshidokht user_vtoc->v_sectorsz != cl->cl_sys_blocksize || 3503786Slclee user_vtoc->v_nparts != V_NUMPAR) { 35043525Sshidokht cmlb_dbg(CMLB_INFO, cl, 3505786Slclee "cmlb_build_label_vtoc: vtoc not valid\n"); 3506786Slclee return (EINVAL); 3507786Slclee } 3508786Slclee 35093525Sshidokht nblks = cl->cl_g.dkg_nsect * cl->cl_g.dkg_nhead; 3510786Slclee if (nblks == 0) { 35113525Sshidokht cmlb_dbg(CMLB_INFO, cl, 3512786Slclee "cmlb_build_label_vtoc: geom nblks is 0\n"); 3513786Slclee return (EINVAL); 3514786Slclee } 3515786Slclee 3516786Slclee #if defined(_SUNOS_VTOC_8) 3517786Slclee vpart = user_vtoc->v_part; 3518786Slclee for (i = 0; i < V_NUMPAR; i++) { 3519786Slclee if ((vpart->p_start % nblks) != 0) { 35203525Sshidokht cmlb_dbg(CMLB_INFO, cl, 3521786Slclee "cmlb_build_label_vtoc: p_start not multiply of" 3522786Slclee "nblks part %d p_start %d nblks %d\n", i, 3523786Slclee vpart->p_start, nblks); 3524786Slclee return (EINVAL); 3525786Slclee } 3526786Slclee ncyl = vpart->p_start / nblks; 3527786Slclee ncyl += vpart->p_size / nblks; 3528786Slclee if ((vpart->p_size % nblks) != 0) { 3529786Slclee ncyl++; 3530786Slclee } 35313525Sshidokht if (ncyl > (int)cl->cl_g.dkg_ncyl) { 35323525Sshidokht cmlb_dbg(CMLB_INFO, cl, 3533786Slclee "cmlb_build_label_vtoc: ncyl %d > dkg_ncyl %d" 3534786Slclee "p_size %ld p_start %ld nblks %d part number %d" 3535786Slclee "tag %d\n", 35363525Sshidokht ncyl, cl->cl_g.dkg_ncyl, vpart->p_size, 3537786Slclee vpart->p_start, nblks, 3538786Slclee i, vpart->p_tag); 3539786Slclee 3540786Slclee return (EINVAL); 3541786Slclee } 3542786Slclee vpart++; 3543786Slclee } 3544786Slclee #endif /* defined(_SUNOS_VTOC_8) */ 3545786Slclee 3546786Slclee /* Put appropriate vtoc structure fields into the disk label */ 3547786Slclee #if defined(_SUNOS_VTOC_16) 3548786Slclee /* 3549786Slclee * The vtoc is always a 32bit data structure to maintain the 3550786Slclee * on-disk format. Convert "in place" instead of doing bcopy. 3551786Slclee */ 35523525Sshidokht vtoctovtoc32((*user_vtoc), (*((struct vtoc32 *)&(cl->cl_vtoc)))); 3553786Slclee 3554786Slclee /* 3555786Slclee * in the 16-slice vtoc, starting sectors are expressed in 3556786Slclee * numbers *relative* to the start of the Solaris fdisk partition. 3557786Slclee */ 35583525Sshidokht lmap = cl->cl_map; 3559786Slclee vpart = user_vtoc->v_part; 3560786Slclee 3561786Slclee for (i = 0; i < (int)user_vtoc->v_nparts; i++, lmap++, vpart++) { 3562786Slclee lmap->dkl_cylno = vpart->p_start / nblks; 3563786Slclee lmap->dkl_nblk = vpart->p_size; 3564786Slclee } 3565786Slclee 3566786Slclee #elif defined(_SUNOS_VTOC_8) 3567786Slclee 35683525Sshidokht cl->cl_vtoc.v_bootinfo[0] = (uint32_t)user_vtoc->v_bootinfo[0]; 35693525Sshidokht cl->cl_vtoc.v_bootinfo[1] = (uint32_t)user_vtoc->v_bootinfo[1]; 35703525Sshidokht cl->cl_vtoc.v_bootinfo[2] = (uint32_t)user_vtoc->v_bootinfo[2]; 35713525Sshidokht 35723525Sshidokht cl->cl_vtoc.v_sanity = (uint32_t)user_vtoc->v_sanity; 35733525Sshidokht cl->cl_vtoc.v_version = (uint32_t)user_vtoc->v_version; 35743525Sshidokht 35753525Sshidokht bcopy(user_vtoc->v_volume, cl->cl_vtoc.v_volume, LEN_DKL_VVOL); 35763525Sshidokht 35773525Sshidokht cl->cl_vtoc.v_nparts = user_vtoc->v_nparts; 3578786Slclee 3579786Slclee for (i = 0; i < 10; i++) 35803525Sshidokht cl->cl_vtoc.v_reserved[i] = user_vtoc->v_reserved[i]; 3581786Slclee 3582786Slclee /* 3583786Slclee * Note the conversion from starting sector number 3584786Slclee * to starting cylinder number. 3585786Slclee * Return error if division results in a remainder. 3586786Slclee */ 35873525Sshidokht lmap = cl->cl_map; 35883525Sshidokht lpart = cl->cl_vtoc.v_part; 3589786Slclee vpart = user_vtoc->v_part; 3590786Slclee 3591786Slclee for (i = 0; i < (int)user_vtoc->v_nparts; i++) { 3592786Slclee lpart->p_tag = vpart->p_tag; 3593786Slclee lpart->p_flag = vpart->p_flag; 3594786Slclee lmap->dkl_cylno = vpart->p_start / nblks; 3595786Slclee lmap->dkl_nblk = vpart->p_size; 3596786Slclee 3597786Slclee lmap++; 3598786Slclee lpart++; 3599786Slclee vpart++; 3600786Slclee 3601786Slclee /* (4387723) */ 3602786Slclee #ifdef _LP64 3603786Slclee if (user_vtoc->timestamp[i] > TIME32_MAX) { 36043525Sshidokht cl->cl_vtoc.v_timestamp[i] = TIME32_MAX; 3605786Slclee } else { 36063525Sshidokht cl->cl_vtoc.v_timestamp[i] = user_vtoc->timestamp[i]; 3607786Slclee } 3608786Slclee #else 36093525Sshidokht cl->cl_vtoc.v_timestamp[i] = user_vtoc->timestamp[i]; 3610786Slclee #endif 3611786Slclee } 3612786Slclee 36133525Sshidokht bcopy(user_vtoc->v_asciilabel, cl->cl_asciilabel, LEN_DKL_ASCII); 3614786Slclee #else 3615786Slclee #error "No VTOC format defined." 3616786Slclee #endif 3617786Slclee return (0); 3618786Slclee } 3619786Slclee 3620786Slclee /* 3621786Slclee * Function: cmlb_clear_efi 3622786Slclee * 3623786Slclee * Description: This routine clears all EFI labels. 3624786Slclee * 36253525Sshidokht * Arguments: 36263525Sshidokht * cl driver soft state (unit) structure 3627786Slclee * 36283525Sshidokht * tg_cookie cookie from target driver to be passed back to target 36293525Sshidokht * driver when we call back to it through tg_ops. 3630786Slclee * Return Code: void 3631786Slclee */ 3632786Slclee static void 36333525Sshidokht cmlb_clear_efi(struct cmlb_lun *cl, void *tg_cookie) 3634786Slclee { 3635786Slclee efi_gpt_t *gpt; 3636786Slclee diskaddr_t cap; 3637786Slclee int rval; 3638786Slclee 36393525Sshidokht ASSERT(!mutex_owned(CMLB_MUTEX(cl))); 36403525Sshidokht 36413525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 36423525Sshidokht cl->cl_reserved = -1; 36433525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3644786Slclee 3645786Slclee gpt = kmem_alloc(sizeof (efi_gpt_t), KM_SLEEP); 3646786Slclee 36473525Sshidokht if (DK_TG_READ(cl, gpt, 1, DEV_BSIZE, tg_cookie) != 0) { 3648786Slclee goto done; 3649786Slclee } 3650786Slclee 3651786Slclee cmlb_swap_efi_gpt(gpt); 3652786Slclee rval = cmlb_validate_efi(gpt); 3653786Slclee if (rval == 0) { 3654786Slclee /* clear primary */ 3655786Slclee bzero(gpt, sizeof (efi_gpt_t)); 36563525Sshidokht if (rval = DK_TG_WRITE(cl, gpt, 1, EFI_LABEL_SIZE, tg_cookie)) { 36573525Sshidokht cmlb_dbg(CMLB_INFO, cl, 36583525Sshidokht "cmlb_clear_efi: clear primary label failed\n"); 3659786Slclee } 3660786Slclee } 3661786Slclee /* the backup */ 36623525Sshidokht rval = DK_TG_GETCAP(cl, &cap, tg_cookie); 3663786Slclee if (rval) { 3664786Slclee goto done; 3665786Slclee } 3666786Slclee 36673525Sshidokht if ((rval = DK_TG_READ(cl, gpt, cap - 1, EFI_LABEL_SIZE, tg_cookie)) 36683525Sshidokht != 0) { 3669786Slclee goto done; 3670786Slclee } 3671786Slclee cmlb_swap_efi_gpt(gpt); 3672786Slclee rval = cmlb_validate_efi(gpt); 3673786Slclee if (rval == 0) { 3674786Slclee /* clear backup */ 36753525Sshidokht cmlb_dbg(CMLB_TRACE, cl, 3676786Slclee "cmlb_clear_efi clear backup@%lu\n", cap - 1); 3677786Slclee bzero(gpt, sizeof (efi_gpt_t)); 36783525Sshidokht if ((rval = DK_TG_WRITE(cl, gpt, cap - 1, EFI_LABEL_SIZE, 36793525Sshidokht tg_cookie))) { 36803525Sshidokht cmlb_dbg(CMLB_INFO, cl, 36813525Sshidokht "cmlb_clear_efi: clear backup label failed\n"); 36823525Sshidokht } 36833525Sshidokht } else { 36843525Sshidokht /* 36853525Sshidokht * Refer to comments related to off-by-1 at the 36863525Sshidokht * header of this file 36873525Sshidokht */ 36883525Sshidokht if ((rval = DK_TG_READ(cl, gpt, cap - 2, 36893525Sshidokht EFI_LABEL_SIZE, tg_cookie)) != 0) { 36903525Sshidokht goto done; 36913525Sshidokht } 36923525Sshidokht cmlb_swap_efi_gpt(gpt); 36933525Sshidokht rval = cmlb_validate_efi(gpt); 36943525Sshidokht if (rval == 0) { 36953525Sshidokht /* clear legacy backup EFI label */ 36963525Sshidokht cmlb_dbg(CMLB_TRACE, cl, 36973525Sshidokht "cmlb_clear_efi clear legacy backup@%lu\n", 36983525Sshidokht cap - 2); 36993525Sshidokht bzero(gpt, sizeof (efi_gpt_t)); 37003525Sshidokht if ((rval = DK_TG_WRITE(cl, gpt, cap - 2, 37013525Sshidokht EFI_LABEL_SIZE, tg_cookie))) { 37023525Sshidokht cmlb_dbg(CMLB_INFO, cl, 37033525Sshidokht "cmlb_clear_efi: clear legacy backup label " 37043525Sshidokht "failed\n"); 37053525Sshidokht } 3706786Slclee } 3707786Slclee } 3708786Slclee 3709786Slclee done: 3710786Slclee kmem_free(gpt, sizeof (efi_gpt_t)); 3711786Slclee } 3712786Slclee 3713786Slclee /* 3714786Slclee * Function: cmlb_set_vtoc 3715786Slclee * 3716786Slclee * Description: This routine writes data to the appropriate positions 3717786Slclee * 37183525Sshidokht * Arguments: 37193525Sshidokht * cl driver soft state (unit) structure 37203525Sshidokht * 37213525Sshidokht * dkl the data to be written 37223525Sshidokht * 37233525Sshidokht * tg_cookie cookie from target driver to be passed back to target 37243525Sshidokht * driver when we call back to it through tg_ops. 3725786Slclee * 3726786Slclee * Return: void 3727786Slclee */ 3728786Slclee static int 37293525Sshidokht cmlb_set_vtoc(struct cmlb_lun *cl, struct dk_label *dkl, void *tg_cookie) 3730786Slclee { 3731786Slclee uint_t label_addr; 3732786Slclee int sec; 3733786Slclee int blk; 3734786Slclee int head; 3735786Slclee int cyl; 3736786Slclee int rval; 3737786Slclee 3738786Slclee #if defined(__i386) || defined(__amd64) 37393525Sshidokht label_addr = cl->cl_solaris_offset + DK_LABEL_LOC; 3740786Slclee #else 3741786Slclee /* Write the primary label at block 0 of the solaris partition. */ 3742786Slclee label_addr = 0; 3743786Slclee #endif 3744786Slclee 37453525Sshidokht rval = DK_TG_WRITE(cl, dkl, label_addr, cl->cl_sys_blocksize, 37463525Sshidokht tg_cookie); 3747786Slclee 3748786Slclee if (rval != 0) { 3749786Slclee return (rval); 3750786Slclee } 3751786Slclee 3752786Slclee /* 3753786Slclee * Calculate where the backup labels go. They are always on 3754786Slclee * the last alternate cylinder, but some older drives put them 3755786Slclee * on head 2 instead of the last head. They are always on the 3756786Slclee * first 5 odd sectors of the appropriate track. 3757786Slclee * 3758786Slclee * We have no choice at this point, but to believe that the 3759786Slclee * disk label is valid. Use the geometry of the disk 3760786Slclee * as described in the label. 3761786Slclee */ 3762786Slclee cyl = dkl->dkl_ncyl + dkl->dkl_acyl - 1; 3763786Slclee head = dkl->dkl_nhead - 1; 3764786Slclee 3765786Slclee /* 3766786Slclee * Write and verify the backup labels. Make sure we don't try to 3767786Slclee * write past the last cylinder. 3768786Slclee */ 3769786Slclee for (sec = 1; ((sec < 5 * 2 + 1) && (sec < dkl->dkl_nsect)); sec += 2) { 3770786Slclee blk = (daddr_t)( 3771786Slclee (cyl * ((dkl->dkl_nhead * dkl->dkl_nsect) - dkl->dkl_apc)) + 3772786Slclee (head * dkl->dkl_nsect) + sec); 3773786Slclee #if defined(__i386) || defined(__amd64) 37743525Sshidokht blk += cl->cl_solaris_offset; 3775786Slclee #endif 37763525Sshidokht rval = DK_TG_WRITE(cl, dkl, blk, cl->cl_sys_blocksize, 37773525Sshidokht tg_cookie); 37783525Sshidokht cmlb_dbg(CMLB_INFO, cl, 3779786Slclee "cmlb_set_vtoc: wrote backup label %d\n", blk); 3780786Slclee if (rval != 0) { 3781786Slclee goto exit; 3782786Slclee } 3783786Slclee } 3784786Slclee exit: 3785786Slclee return (rval); 3786786Slclee } 3787786Slclee 3788786Slclee /* 3789786Slclee * Function: cmlb_clear_vtoc 3790786Slclee * 3791786Slclee * Description: This routine clears out the VTOC labels. 3792786Slclee * 37933525Sshidokht * Arguments: 37943525Sshidokht * cl driver soft state (unit) structure 37953525Sshidokht * 37963525Sshidokht * tg_cookie cookie from target driver to be passed back to target 37973525Sshidokht * driver when we call back to it through tg_ops. 3798786Slclee * 3799786Slclee * Return: void 3800786Slclee */ 3801786Slclee static void 38023525Sshidokht cmlb_clear_vtoc(struct cmlb_lun *cl, void *tg_cookie) 3803786Slclee { 3804786Slclee struct dk_label *dkl; 3805786Slclee 38063525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3807786Slclee dkl = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP); 38083525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 3809786Slclee /* 3810786Slclee * cmlb_set_vtoc uses these fields in order to figure out 3811786Slclee * where to overwrite the backup labels 3812786Slclee */ 38133525Sshidokht dkl->dkl_apc = cl->cl_g.dkg_apc; 38143525Sshidokht dkl->dkl_ncyl = cl->cl_g.dkg_ncyl; 38153525Sshidokht dkl->dkl_acyl = cl->cl_g.dkg_acyl; 38163525Sshidokht dkl->dkl_nhead = cl->cl_g.dkg_nhead; 38173525Sshidokht dkl->dkl_nsect = cl->cl_g.dkg_nsect; 38183525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 38193525Sshidokht (void) cmlb_set_vtoc(cl, dkl, tg_cookie); 3820786Slclee kmem_free(dkl, sizeof (struct dk_label)); 3821786Slclee 38223525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 3823786Slclee } 3824786Slclee 3825786Slclee /* 3826786Slclee * Function: cmlb_write_label 3827786Slclee * 3828786Slclee * Description: This routine will validate and write the driver soft state vtoc 3829786Slclee * contents to the device. 3830786Slclee * 38313525Sshidokht * Arguments: 38323525Sshidokht * cl cmlb handle 38333525Sshidokht * 38343525Sshidokht * tg_cookie cookie from target driver to be passed back to target 38353525Sshidokht * driver when we call back to it through tg_ops. 38363525Sshidokht * 3837786Slclee * 3838786Slclee * Return Code: the code returned by cmlb_send_scsi_cmd() 3839786Slclee * 0 3840786Slclee * EINVAL 3841786Slclee * ENXIO 3842786Slclee * ENOMEM 3843786Slclee */ 3844786Slclee static int 38453525Sshidokht cmlb_write_label(struct cmlb_lun *cl, void *tg_cookie) 3846786Slclee { 3847786Slclee struct dk_label *dkl; 3848786Slclee short sum; 3849786Slclee short *sp; 3850786Slclee int i; 3851786Slclee int rval; 3852786Slclee 38533525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 38543525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3855786Slclee dkl = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP); 38563525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 38573525Sshidokht 38583525Sshidokht bcopy(&cl->cl_vtoc, &dkl->dkl_vtoc, sizeof (struct dk_vtoc)); 38593525Sshidokht dkl->dkl_rpm = cl->cl_g.dkg_rpm; 38603525Sshidokht dkl->dkl_pcyl = cl->cl_g.dkg_pcyl; 38613525Sshidokht dkl->dkl_apc = cl->cl_g.dkg_apc; 38623525Sshidokht dkl->dkl_intrlv = cl->cl_g.dkg_intrlv; 38633525Sshidokht dkl->dkl_ncyl = cl->cl_g.dkg_ncyl; 38643525Sshidokht dkl->dkl_acyl = cl->cl_g.dkg_acyl; 38653525Sshidokht dkl->dkl_nhead = cl->cl_g.dkg_nhead; 38663525Sshidokht dkl->dkl_nsect = cl->cl_g.dkg_nsect; 3867786Slclee 3868786Slclee #if defined(_SUNOS_VTOC_8) 38693525Sshidokht dkl->dkl_obs1 = cl->cl_g.dkg_obs1; 38703525Sshidokht dkl->dkl_obs2 = cl->cl_g.dkg_obs2; 38713525Sshidokht dkl->dkl_obs3 = cl->cl_g.dkg_obs3; 3872786Slclee for (i = 0; i < NDKMAP; i++) { 38733525Sshidokht dkl->dkl_map[i].dkl_cylno = cl->cl_map[i].dkl_cylno; 38743525Sshidokht dkl->dkl_map[i].dkl_nblk = cl->cl_map[i].dkl_nblk; 3875786Slclee } 38763525Sshidokht bcopy(cl->cl_asciilabel, dkl->dkl_asciilabel, LEN_DKL_ASCII); 3877786Slclee #elif defined(_SUNOS_VTOC_16) 38783525Sshidokht dkl->dkl_skew = cl->cl_dkg_skew; 3879786Slclee #else 3880786Slclee #error "No VTOC format defined." 3881786Slclee #endif 3882786Slclee 3883786Slclee dkl->dkl_magic = DKL_MAGIC; 38843525Sshidokht dkl->dkl_write_reinstruct = cl->cl_g.dkg_write_reinstruct; 38853525Sshidokht dkl->dkl_read_reinstruct = cl->cl_g.dkg_read_reinstruct; 3886786Slclee 3887786Slclee /* Construct checksum for the new disk label */ 3888786Slclee sum = 0; 3889786Slclee sp = (short *)dkl; 3890786Slclee i = sizeof (struct dk_label) / sizeof (short); 3891786Slclee while (i--) { 3892786Slclee sum ^= *sp++; 3893786Slclee } 3894786Slclee dkl->dkl_cksum = sum; 3895786Slclee 38963525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 38973525Sshidokht 38983525Sshidokht rval = cmlb_set_vtoc(cl, dkl, tg_cookie); 3899786Slclee exit: 3900786Slclee kmem_free(dkl, sizeof (struct dk_label)); 39013525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 3902786Slclee return (rval); 3903786Slclee } 3904786Slclee 3905786Slclee static int 39063525Sshidokht cmlb_dkio_set_efi(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag, 39073525Sshidokht void *tg_cookie) 3908786Slclee { 3909786Slclee dk_efi_t user_efi; 3910786Slclee int rval = 0; 3911786Slclee void *buffer; 39123525Sshidokht diskaddr_t tgt_lba; 3913786Slclee 3914786Slclee if (ddi_copyin(arg, &user_efi, sizeof (dk_efi_t), flag)) 3915786Slclee return (EFAULT); 3916786Slclee 3917786Slclee user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64; 3918786Slclee 3919786Slclee buffer = kmem_alloc(user_efi.dki_length, KM_SLEEP); 3920786Slclee if (ddi_copyin(user_efi.dki_data, buffer, user_efi.dki_length, flag)) { 3921786Slclee rval = EFAULT; 3922786Slclee } else { 3923786Slclee /* 3924786Slclee * let's clear the vtoc labels and clear the softstate 3925786Slclee * vtoc. 3926786Slclee */ 39273525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 39283525Sshidokht if (cl->cl_vtoc.v_sanity == VTOC_SANE) { 39293525Sshidokht cmlb_dbg(CMLB_TRACE, cl, 39303525Sshidokht "cmlb_dkio_set_efi: CLEAR VTOC\n"); 39313525Sshidokht if (cl->cl_vtoc_label_is_from_media) 39323525Sshidokht cmlb_clear_vtoc(cl, tg_cookie); 39333525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc)); 39343525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 39353525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "h"); 39363525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw"); 39373525Sshidokht (void) ddi_create_minor_node(CMLB_DEVINFO(cl), "wd", 3938786Slclee S_IFBLK, 3939786Slclee (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 39403525Sshidokht cl->cl_node_type, NULL); 39413525Sshidokht (void) ddi_create_minor_node(CMLB_DEVINFO(cl), "wd,raw", 3942786Slclee S_IFCHR, 3943786Slclee (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 39443525Sshidokht cl->cl_node_type, NULL); 3945786Slclee } else 39463525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 39473525Sshidokht 39483525Sshidokht tgt_lba = user_efi.dki_lba; 39493525Sshidokht 39503525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 39513525Sshidokht if ((cmlb_check_update_blockcount(cl, tg_cookie) != 0) || 39523525Sshidokht (cl->cl_tgt_blocksize == 0)) { 39533525Sshidokht kmem_free(buffer, user_efi.dki_length); 39543525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 39553525Sshidokht return (EINVAL); 39563525Sshidokht } 39573525Sshidokht if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) 39583525Sshidokht tgt_lba = tgt_lba * 39593525Sshidokht cl->cl_tgt_blocksize / cl->cl_sys_blocksize; 39603525Sshidokht 39613525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 39623525Sshidokht rval = DK_TG_WRITE(cl, buffer, tgt_lba, user_efi.dki_length, 39633525Sshidokht tg_cookie); 39643525Sshidokht 3965786Slclee if (rval == 0) { 39663525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 39673525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 39683525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3969786Slclee } 3970786Slclee } 3971786Slclee kmem_free(buffer, user_efi.dki_length); 3972786Slclee return (rval); 3973786Slclee } 3974786Slclee 3975786Slclee /* 3976786Slclee * Function: cmlb_dkio_get_mboot 3977786Slclee * 3978786Slclee * Description: This routine is the driver entry point for handling user 3979786Slclee * requests to get the current device mboot (DKIOCGMBOOT) 3980786Slclee * 3981786Slclee * Arguments: 39823525Sshidokht * arg pointer to user provided mboot structure specifying 3983786Slclee * the current mboot. 39843525Sshidokht * 39853525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 39863525Sshidokht * directly from the mode argument of ioctl(). 39873525Sshidokht * 39883525Sshidokht * tg_cookie cookie from target driver to be passed back to target 39893525Sshidokht * driver when we call back to it through tg_ops. 3990786Slclee * 3991786Slclee * Return Code: 0 3992786Slclee * EINVAL 3993786Slclee * EFAULT 3994786Slclee * ENXIO 3995786Slclee */ 3996786Slclee static int 39973525Sshidokht cmlb_dkio_get_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie) 3998786Slclee { 3999786Slclee struct mboot *mboot; 4000786Slclee int rval; 4001786Slclee size_t buffer_size; 4002786Slclee 4003786Slclee 4004786Slclee #if defined(_SUNOS_VTOC_8) 40053525Sshidokht if ((!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) || (arg == NULL)) { 4006786Slclee #elif defined(_SUNOS_VTOC_16) 4007786Slclee if (arg == NULL) { 4008786Slclee #endif 4009786Slclee return (EINVAL); 4010786Slclee } 4011786Slclee 4012786Slclee /* 4013786Slclee * Read the mboot block, located at absolute block 0 on the target. 4014786Slclee */ 4015786Slclee buffer_size = sizeof (struct mboot); 4016786Slclee 40173525Sshidokht cmlb_dbg(CMLB_TRACE, cl, 4018786Slclee "cmlb_dkio_get_mboot: allocation size: 0x%x\n", buffer_size); 4019786Slclee 4020786Slclee mboot = kmem_zalloc(buffer_size, KM_SLEEP); 40213525Sshidokht if ((rval = DK_TG_READ(cl, mboot, 0, buffer_size, tg_cookie)) == 0) { 4022786Slclee if (ddi_copyout(mboot, (void *)arg, 4023786Slclee sizeof (struct mboot), flag) != 0) { 4024786Slclee rval = EFAULT; 4025786Slclee } 4026786Slclee } 4027786Slclee kmem_free(mboot, buffer_size); 4028786Slclee return (rval); 4029786Slclee } 4030786Slclee 4031786Slclee 4032786Slclee /* 4033786Slclee * Function: cmlb_dkio_set_mboot 4034786Slclee * 4035786Slclee * Description: This routine is the driver entry point for handling user 4036786Slclee * requests to validate and set the device master boot 4037786Slclee * (DKIOCSMBOOT). 4038786Slclee * 4039786Slclee * Arguments: 40403525Sshidokht * arg pointer to user provided mboot structure used to set the 4041786Slclee * master boot. 40423525Sshidokht * 40433525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 40443525Sshidokht * directly from the mode argument of ioctl(). 40453525Sshidokht * 40463525Sshidokht * tg_cookie cookie from target driver to be passed back to target 40473525Sshidokht * driver when we call back to it through tg_ops. 4048786Slclee * 4049786Slclee * Return Code: 0 4050786Slclee * EINVAL 4051786Slclee * EFAULT 4052786Slclee * ENXIO 4053786Slclee */ 4054786Slclee static int 40553525Sshidokht cmlb_dkio_set_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie) 4056786Slclee { 4057786Slclee struct mboot *mboot = NULL; 4058786Slclee int rval; 4059786Slclee ushort_t magic; 4060786Slclee 4061786Slclee 40623525Sshidokht ASSERT(!mutex_owned(CMLB_MUTEX(cl))); 4063786Slclee 4064786Slclee #if defined(_SUNOS_VTOC_8) 40653525Sshidokht if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) { 4066786Slclee return (EINVAL); 4067786Slclee } 4068786Slclee #endif 4069786Slclee 4070786Slclee if (arg == NULL) { 4071786Slclee return (EINVAL); 4072786Slclee } 4073786Slclee 4074786Slclee mboot = kmem_zalloc(sizeof (struct mboot), KM_SLEEP); 4075786Slclee 4076786Slclee if (ddi_copyin((const void *)arg, mboot, 4077786Slclee sizeof (struct mboot), flag) != 0) { 4078786Slclee kmem_free(mboot, (size_t)(sizeof (struct mboot))); 4079786Slclee return (EFAULT); 4080786Slclee } 4081786Slclee 4082786Slclee /* Is this really a master boot record? */ 4083786Slclee magic = LE_16(mboot->signature); 4084786Slclee if (magic != MBB_MAGIC) { 4085786Slclee kmem_free(mboot, (size_t)(sizeof (struct mboot))); 4086786Slclee return (EINVAL); 4087786Slclee } 4088786Slclee 40893525Sshidokht rval = DK_TG_WRITE(cl, mboot, 0, cl->cl_sys_blocksize, tg_cookie); 40903525Sshidokht 40913525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 4092786Slclee #if defined(__i386) || defined(__amd64) 4093786Slclee if (rval == 0) { 4094786Slclee /* 4095786Slclee * mboot has been written successfully. 4096786Slclee * update the fdisk and vtoc tables in memory 4097786Slclee */ 40983525Sshidokht rval = cmlb_update_fdisk_and_vtoc(cl, tg_cookie); 40993525Sshidokht if ((cl->cl_f_geometry_is_valid == FALSE) || (rval != 0)) { 41003525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4101786Slclee kmem_free(mboot, (size_t)(sizeof (struct mboot))); 4102786Slclee return (rval); 4103786Slclee } 4104786Slclee } 41053525Sshidokht 41063525Sshidokht #ifdef __lock_lint 41073525Sshidokht cmlb_setup_default_geometry(cl, tg_cookie); 41083525Sshidokht #endif 41093525Sshidokht 4110786Slclee #else 4111786Slclee if (rval == 0) { 4112786Slclee /* 4113786Slclee * mboot has been written successfully. 4114786Slclee * set up the default geometry and VTOC 4115786Slclee */ 41163525Sshidokht if (cl->cl_blockcount <= DK_MAX_BLOCKS) 41173525Sshidokht cmlb_setup_default_geometry(cl, tg_cookie); 4118786Slclee } 4119786Slclee #endif 41203525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4121786Slclee kmem_free(mboot, (size_t)(sizeof (struct mboot))); 4122786Slclee return (rval); 4123786Slclee } 4124786Slclee 4125786Slclee 4126786Slclee /* 4127786Slclee * Function: cmlb_setup_default_geometry 4128786Slclee * 4129786Slclee * Description: This local utility routine sets the default geometry as part of 4130786Slclee * setting the device mboot. 4131786Slclee * 41323525Sshidokht * Arguments: 41333525Sshidokht * cl driver soft state (unit) structure 41343525Sshidokht * 41353525Sshidokht * tg_cookie cookie from target driver to be passed back to target 41363525Sshidokht * driver when we call back to it through tg_ops. 41373525Sshidokht * 4138786Slclee * 4139786Slclee * Note: This may be redundant with cmlb_build_default_label. 4140786Slclee */ 4141786Slclee static void 41423525Sshidokht cmlb_setup_default_geometry(struct cmlb_lun *cl, void *tg_cookie) 4143786Slclee { 4144786Slclee struct cmlb_geom pgeom; 4145786Slclee struct cmlb_geom *pgeomp = &pgeom; 4146786Slclee int ret; 4147786Slclee int geom_base_cap = 1; 4148786Slclee 4149786Slclee 41503525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 4151786Slclee 4152786Slclee /* zero out the soft state geometry and partition table. */ 41533525Sshidokht bzero(&cl->cl_g, sizeof (struct dk_geom)); 41543525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc)); 41553525Sshidokht bzero(cl->cl_map, NDKMAP * (sizeof (struct dk_map))); 4156786Slclee 4157786Slclee /* 4158786Slclee * For the rpm, we use the minimum for the disk. 4159786Slclee * For the head, cyl and number of sector per track, 4160786Slclee * if the capacity <= 1GB, head = 64, sect = 32. 4161786Slclee * else head = 255, sect 63 4162786Slclee * Note: the capacity should be equal to C*H*S values. 4163786Slclee * This will cause some truncation of size due to 4164786Slclee * round off errors. For CD-ROMs, this truncation can 4165786Slclee * have adverse side effects, so returning ncyl and 4166786Slclee * nhead as 1. The nsect will overflow for most of 4167786Slclee * CD-ROMs as nsect is of type ushort. 4168786Slclee */ 41693525Sshidokht if (cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8) { 4170786Slclee /* 4171786Slclee * newfs currently can not handle 255 ntracks for SPARC 4172786Slclee * so get the geometry from target driver instead of coming up 4173786Slclee * with one based on capacity. 4174786Slclee */ 41753525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 41763525Sshidokht ret = DK_TG_GETPHYGEOM(cl, pgeomp, tg_cookie); 41773525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 4178786Slclee 4179786Slclee if (ret == 0) { 4180786Slclee geom_base_cap = 0; 4181786Slclee } else { 41823525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 4183786Slclee "cmlb_setup_default_geometry: " 4184786Slclee "tg_getphygeom failed %d\n", ret); 4185786Slclee 4186786Slclee /* do default setting, geometry based on capacity */ 4187786Slclee } 4188786Slclee } 4189786Slclee 4190786Slclee if (geom_base_cap) { 41913525Sshidokht if (ISCD(cl)) { 41923525Sshidokht cl->cl_g.dkg_ncyl = 1; 41933525Sshidokht cl->cl_g.dkg_nhead = 1; 41943525Sshidokht cl->cl_g.dkg_nsect = cl->cl_blockcount; 41953525Sshidokht } else if (cl->cl_blockcount <= 0x1000) { 4196786Slclee /* Needed for unlabeled SCSI floppies. */ 41973525Sshidokht cl->cl_g.dkg_nhead = 2; 41983525Sshidokht cl->cl_g.dkg_ncyl = 80; 41993525Sshidokht cl->cl_g.dkg_pcyl = 80; 42003525Sshidokht cl->cl_g.dkg_nsect = cl->cl_blockcount / (2 * 80); 42013525Sshidokht } else if (cl->cl_blockcount <= 0x200000) { 42023525Sshidokht cl->cl_g.dkg_nhead = 64; 42033525Sshidokht cl->cl_g.dkg_nsect = 32; 42043525Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount / (64 * 32); 4205786Slclee } else { 42063525Sshidokht cl->cl_g.dkg_nhead = 255; 42073525Sshidokht cl->cl_g.dkg_nsect = 63; 42083525Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount / (255 * 63); 4209786Slclee } 4210786Slclee 42113525Sshidokht cl->cl_g.dkg_acyl = 0; 42123525Sshidokht cl->cl_g.dkg_bcyl = 0; 42133525Sshidokht cl->cl_g.dkg_intrlv = 1; 42143525Sshidokht cl->cl_g.dkg_rpm = 200; 42153525Sshidokht if (cl->cl_g.dkg_pcyl == 0) 42163525Sshidokht cl->cl_g.dkg_pcyl = cl->cl_g.dkg_ncyl + 42173525Sshidokht cl->cl_g.dkg_acyl; 4218786Slclee } else { 42193525Sshidokht cl->cl_g.dkg_ncyl = (short)pgeomp->g_ncyl; 42203525Sshidokht cl->cl_g.dkg_acyl = pgeomp->g_acyl; 42213525Sshidokht cl->cl_g.dkg_nhead = pgeomp->g_nhead; 42223525Sshidokht cl->cl_g.dkg_nsect = pgeomp->g_nsect; 42233525Sshidokht cl->cl_g.dkg_intrlv = pgeomp->g_intrlv; 42243525Sshidokht cl->cl_g.dkg_rpm = pgeomp->g_rpm; 42253525Sshidokht cl->cl_g.dkg_pcyl = cl->cl_g.dkg_ncyl + cl->cl_g.dkg_acyl; 4226786Slclee } 4227786Slclee 42283525Sshidokht cl->cl_g.dkg_read_reinstruct = 0; 42293525Sshidokht cl->cl_g.dkg_write_reinstruct = 0; 42303525Sshidokht cl->cl_solaris_size = cl->cl_g.dkg_ncyl * 42313525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect; 42323525Sshidokht 42333525Sshidokht cl->cl_map['a'-'a'].dkl_cylno = 0; 42343525Sshidokht cl->cl_map['a'-'a'].dkl_nblk = cl->cl_solaris_size; 42353525Sshidokht 42363525Sshidokht cl->cl_map['c'-'a'].dkl_cylno = 0; 42373525Sshidokht cl->cl_map['c'-'a'].dkl_nblk = cl->cl_solaris_size; 42383525Sshidokht 42393525Sshidokht cl->cl_vtoc.v_part[2].p_tag = V_BACKUP; 42403525Sshidokht cl->cl_vtoc.v_part[2].p_flag = V_UNMNT; 42413525Sshidokht cl->cl_vtoc.v_nparts = V_NUMPAR; 42423525Sshidokht cl->cl_vtoc.v_version = V_VERSION; 42433525Sshidokht (void) sprintf((char *)cl->cl_asciilabel, "DEFAULT cyl %d alt %d" 42443525Sshidokht " hd %d sec %d", cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl, 42453525Sshidokht cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect); 42463525Sshidokht 42473525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 4248786Slclee } 4249786Slclee 4250786Slclee 4251786Slclee #if defined(__i386) || defined(__amd64) 4252786Slclee /* 4253786Slclee * Function: cmlb_update_fdisk_and_vtoc 4254786Slclee * 4255786Slclee * Description: This local utility routine updates the device fdisk and vtoc 4256786Slclee * as part of setting the device mboot. 4257786Slclee * 42583525Sshidokht * Arguments: 42593525Sshidokht * cl driver soft state (unit) structure 42603525Sshidokht * 42613525Sshidokht * tg_cookie cookie from target driver to be passed back to target 42623525Sshidokht * driver when we call back to it through tg_ops. 42633525Sshidokht * 4264786Slclee * 4265786Slclee * Return Code: 0 for success or errno-type return code. 4266786Slclee * 4267786Slclee * Note:x86: This looks like a duplicate of cmlb_validate_geometry(), but 4268786Slclee * these did exist separately in x86 sd.c. 4269786Slclee */ 4270786Slclee static int 42713525Sshidokht cmlb_update_fdisk_and_vtoc(struct cmlb_lun *cl, void *tg_cookie) 4272786Slclee { 4273786Slclee int count; 4274786Slclee int label_rc = 0; 4275786Slclee int fdisk_rval; 4276786Slclee diskaddr_t capacity; 4277786Slclee 42783525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 42793525Sshidokht 42803525Sshidokht if (cmlb_check_update_blockcount(cl, tg_cookie) != 0) 4281786Slclee return (EINVAL); 4282786Slclee 4283786Slclee #if defined(_SUNOS_VTOC_16) 4284786Slclee /* 4285786Slclee * Set up the "whole disk" fdisk partition; this should always 4286786Slclee * exist, regardless of whether the disk contains an fdisk table 4287786Slclee * or vtoc. 4288786Slclee */ 42893525Sshidokht cl->cl_map[P0_RAW_DISK].dkl_cylno = 0; 42903525Sshidokht cl->cl_map[P0_RAW_DISK].dkl_nblk = cl->cl_blockcount; 4291786Slclee #endif /* defined(_SUNOS_VTOC_16) */ 4292786Slclee 4293786Slclee /* 4294786Slclee * copy the lbasize and capacity so that if they're 42953525Sshidokht * reset while we're not holding the CMLB_MUTEX(cl), we will 42963525Sshidokht * continue to use valid values after the CMLB_MUTEX(cl) is 4297786Slclee * reacquired. 4298786Slclee */ 42993525Sshidokht capacity = cl->cl_blockcount; 4300786Slclee 4301786Slclee /* 4302786Slclee * refresh the logical and physical geometry caches. 4303786Slclee * (data from mode sense format/rigid disk geometry pages, 4304786Slclee * and scsi_ifgetcap("geometry"). 4305786Slclee */ 43063525Sshidokht cmlb_resync_geom_caches(cl, capacity, tg_cookie); 4307786Slclee 4308786Slclee /* 43093525Sshidokht * Only DIRECT ACCESS devices will have Scl labels. 43103525Sshidokht * CD's supposedly have a Scl label, too 4311786Slclee */ 43123525Sshidokht if (cl->cl_device_type == DTYPE_DIRECT || ISREMOVABLE(cl)) { 43133525Sshidokht fdisk_rval = cmlb_read_fdisk(cl, capacity, tg_cookie); 4314786Slclee if (fdisk_rval != 0) { 43153525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 4316786Slclee return (fdisk_rval); 4317786Slclee } 4318786Slclee 43193525Sshidokht if (cl->cl_solaris_size <= DK_LABEL_LOC) { 4320786Slclee /* 4321786Slclee * Found fdisk table but no Solaris partition entry, 4322786Slclee * so don't call cmlb_uselabel() and don't create 4323786Slclee * a default label. 4324786Slclee */ 4325786Slclee label_rc = 0; 43263525Sshidokht cl->cl_f_geometry_is_valid = TRUE; 4327786Slclee goto no_solaris_partition; 4328786Slclee } 4329786Slclee } else if (capacity < 0) { 43303525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 4331786Slclee return (EINVAL); 4332786Slclee } 4333786Slclee 4334786Slclee /* 4335786Slclee * For Removable media We reach here if we have found a 4336786Slclee * SOLARIS PARTITION. 43373525Sshidokht * If cl_f_geometry_is_valid is FALSE it indicates that the SOLARIS 4338786Slclee * PARTITION has changed from the previous one, hence we will setup a 4339786Slclee * default VTOC in this case. 4340786Slclee */ 43413525Sshidokht if (cl->cl_f_geometry_is_valid == FALSE) { 4342786Slclee /* if we get here it is writable */ 4343786Slclee /* we are called from SMBOOT, and after a write of fdisk */ 43443525Sshidokht cmlb_build_default_label(cl, tg_cookie); 4345786Slclee label_rc = 0; 4346786Slclee } 4347786Slclee 4348786Slclee no_solaris_partition: 4349786Slclee 4350786Slclee #if defined(_SUNOS_VTOC_16) 4351786Slclee /* 4352786Slclee * If we have valid geometry, set up the remaining fdisk partitions. 4353786Slclee * Note that dkl_cylno is not used for the fdisk map entries, so 4354786Slclee * we set it to an entirely bogus value. 4355786Slclee */ 4356786Slclee for (count = 0; count < FD_NUMPART; count++) { 43573525Sshidokht cl->cl_map[FDISK_P1 + count].dkl_cylno = -1; 43583525Sshidokht cl->cl_map[FDISK_P1 + count].dkl_nblk = 43593525Sshidokht cl->cl_fmap[count].fmap_nblk; 43603525Sshidokht cl->cl_offset[FDISK_P1 + count] = 43613525Sshidokht cl->cl_fmap[count].fmap_start; 4362786Slclee } 4363786Slclee #endif 4364786Slclee 4365786Slclee for (count = 0; count < NDKMAP; count++) { 4366786Slclee #if defined(_SUNOS_VTOC_8) 43673525Sshidokht struct dk_map *lp = &cl->cl_map[count]; 43683525Sshidokht cl->cl_offset[count] = 43693525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno; 4370786Slclee #elif defined(_SUNOS_VTOC_16) 43713525Sshidokht struct dkl_partition *vp = &cl->cl_vtoc.v_part[count]; 43723525Sshidokht cl->cl_offset[count] = vp->p_start + cl->cl_solaris_offset; 4373786Slclee #else 4374786Slclee #error "No VTOC format defined." 4375786Slclee #endif 4376786Slclee } 4377786Slclee 43783525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 4379786Slclee return (label_rc); 4380786Slclee } 4381786Slclee #endif 4382786Slclee 4383786Slclee #if defined(__i386) || defined(__amd64) 4384786Slclee static int 43853525Sshidokht cmlb_dkio_get_virtgeom(struct cmlb_lun *cl, caddr_t arg, int flag) 4386786Slclee { 4387786Slclee int err = 0; 4388786Slclee 4389786Slclee /* Return the driver's notion of the media's logical geometry */ 4390786Slclee struct dk_geom disk_geom; 4391786Slclee struct dk_geom *dkgp = &disk_geom; 4392786Slclee 43933525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 4394786Slclee /* 4395786Slclee * If there is no HBA geometry available, or 4396786Slclee * if the HBA returned us something that doesn't 4397786Slclee * really fit into an Int 13/function 8 geometry 4398786Slclee * result, just fail the ioctl. See PSARC 1998/313. 4399786Slclee */ 44003525Sshidokht if (cl->cl_lgeom.g_nhead == 0 || 44013525Sshidokht cl->cl_lgeom.g_nsect == 0 || 44023525Sshidokht cl->cl_lgeom.g_ncyl > 1024) { 44033525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4404786Slclee err = EINVAL; 4405786Slclee } else { 44063525Sshidokht dkgp->dkg_ncyl = cl->cl_lgeom.g_ncyl; 44073525Sshidokht dkgp->dkg_acyl = cl->cl_lgeom.g_acyl; 4408786Slclee dkgp->dkg_pcyl = dkgp->dkg_ncyl + dkgp->dkg_acyl; 44093525Sshidokht dkgp->dkg_nhead = cl->cl_lgeom.g_nhead; 44103525Sshidokht dkgp->dkg_nsect = cl->cl_lgeom.g_nsect; 4411786Slclee 4412*4177Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4413786Slclee if (ddi_copyout(dkgp, (void *)arg, 4414786Slclee sizeof (struct dk_geom), flag)) { 4415786Slclee err = EFAULT; 4416786Slclee } else { 4417786Slclee err = 0; 4418786Slclee } 4419786Slclee } 4420786Slclee return (err); 4421786Slclee } 4422786Slclee #endif 4423786Slclee 4424786Slclee #if defined(__i386) || defined(__amd64) 4425786Slclee static int 44263525Sshidokht cmlb_dkio_get_phygeom(struct cmlb_lun *cl, caddr_t arg, int flag) 4427786Slclee { 4428786Slclee int err = 0; 44293525Sshidokht diskaddr_t capacity; 4430786Slclee 4431786Slclee 4432786Slclee /* Return the driver's notion of the media physical geometry */ 4433786Slclee struct dk_geom disk_geom; 4434786Slclee struct dk_geom *dkgp = &disk_geom; 4435786Slclee 44363525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 44373525Sshidokht 44383525Sshidokht if (cl->cl_g.dkg_nhead != 0 && 44393525Sshidokht cl->cl_g.dkg_nsect != 0) { 4440786Slclee /* 4441786Slclee * We succeeded in getting a geometry, but 4442786Slclee * right now it is being reported as just the 4443786Slclee * Solaris fdisk partition, just like for 4444786Slclee * DKIOCGGEOM. We need to change that to be 4445786Slclee * correct for the entire disk now. 4446786Slclee */ 44473525Sshidokht bcopy(&cl->cl_g, dkgp, sizeof (*dkgp)); 4448786Slclee dkgp->dkg_acyl = 0; 44493525Sshidokht dkgp->dkg_ncyl = cl->cl_blockcount / 4450786Slclee (dkgp->dkg_nhead * dkgp->dkg_nsect); 4451786Slclee } else { 4452786Slclee bzero(dkgp, sizeof (struct dk_geom)); 4453786Slclee /* 4454786Slclee * This disk does not have a Solaris VTOC 4455786Slclee * so we must present a physical geometry 4456786Slclee * that will remain consistent regardless 4457786Slclee * of how the disk is used. This will ensure 4458786Slclee * that the geometry does not change regardless 4459786Slclee * of the fdisk partition type (ie. EFI, FAT32, 4460786Slclee * Solaris, etc). 4461786Slclee */ 44623525Sshidokht if (ISCD(cl)) { 44633525Sshidokht dkgp->dkg_nhead = cl->cl_pgeom.g_nhead; 44643525Sshidokht dkgp->dkg_nsect = cl->cl_pgeom.g_nsect; 44653525Sshidokht dkgp->dkg_ncyl = cl->cl_pgeom.g_ncyl; 44663525Sshidokht dkgp->dkg_acyl = cl->cl_pgeom.g_acyl; 4467786Slclee } else { 44683525Sshidokht /* 44693525Sshidokht * Invalid cl_blockcount can generate invalid 44703525Sshidokht * dk_geom and may result in division by zero 44713525Sshidokht * system failure. Should make sure blockcount 44723525Sshidokht * is valid before using it here. 44733525Sshidokht */ 44743525Sshidokht if (cl->cl_blockcount == 0) { 44753525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 44763525Sshidokht err = EIO; 44773525Sshidokht return (err); 44783525Sshidokht } 44793525Sshidokht /* 44803525Sshidokht * Refer to comments related to off-by-1 at the 44813525Sshidokht * header of this file 44823525Sshidokht */ 44833525Sshidokht if (cl->cl_alter_behavior & CMLB_OFF_BY_ONE) 44843525Sshidokht capacity = cl->cl_blockcount - 1; 44853525Sshidokht else 44863525Sshidokht capacity = cl->cl_blockcount; 44873525Sshidokht 44883525Sshidokht cmlb_convert_geometry(capacity, dkgp); 4489786Slclee dkgp->dkg_acyl = 0; 44903525Sshidokht dkgp->dkg_ncyl = capacity / 4491786Slclee (dkgp->dkg_nhead * dkgp->dkg_nsect); 4492786Slclee } 4493786Slclee } 4494786Slclee dkgp->dkg_pcyl = dkgp->dkg_ncyl + dkgp->dkg_acyl; 4495786Slclee 4496*4177Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4497*4177Sshidokht if (ddi_copyout(dkgp, (void *)arg, sizeof (struct dk_geom), flag)) 4498786Slclee err = EFAULT; 4499*4177Sshidokht 4500786Slclee return (err); 4501786Slclee } 4502786Slclee #endif 4503786Slclee 4504786Slclee #if defined(__i386) || defined(__amd64) 4505786Slclee static int 45063525Sshidokht cmlb_dkio_partinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag) 4507786Slclee { 4508786Slclee int err = 0; 4509786Slclee 4510786Slclee /* 4511786Slclee * Return parameters describing the selected disk slice. 4512786Slclee * Note: this ioctl is for the intel platform only 4513786Slclee */ 4514786Slclee int part; 4515786Slclee 4516786Slclee part = CMLBPART(dev); 4517786Slclee 45183525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 45193525Sshidokht /* don't check cl_solaris_size for pN */ 45203525Sshidokht if (part < P0_RAW_DISK && cl->cl_solaris_size == 0) { 4521786Slclee err = EIO; 4522*4177Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4523786Slclee } else { 4524786Slclee struct part_info p; 4525786Slclee 45263525Sshidokht p.p_start = (daddr_t)cl->cl_offset[part]; 45273525Sshidokht p.p_length = (int)cl->cl_map[part].dkl_nblk; 4528*4177Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4529786Slclee #ifdef _MULTI_DATAMODEL 4530786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 4531786Slclee case DDI_MODEL_ILP32: 4532786Slclee { 4533786Slclee struct part_info32 p32; 4534786Slclee 4535786Slclee p32.p_start = (daddr32_t)p.p_start; 4536786Slclee p32.p_length = p.p_length; 4537786Slclee if (ddi_copyout(&p32, (void *)arg, 4538786Slclee sizeof (p32), flag)) 4539786Slclee err = EFAULT; 4540786Slclee break; 4541786Slclee } 4542786Slclee 4543786Slclee case DDI_MODEL_NONE: 4544786Slclee { 4545786Slclee if (ddi_copyout(&p, (void *)arg, sizeof (p), 4546786Slclee flag)) 4547786Slclee err = EFAULT; 4548786Slclee break; 4549786Slclee } 4550786Slclee } 4551786Slclee #else /* ! _MULTI_DATAMODEL */ 4552786Slclee if (ddi_copyout(&p, (void *)arg, sizeof (p), flag)) 4553786Slclee err = EFAULT; 4554786Slclee #endif /* _MULTI_DATAMODEL */ 4555786Slclee } 4556786Slclee return (err); 4557786Slclee } 4558786Slclee #endif 4559