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 /* 238570SSriram.Popuri@sun.com * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24786Slclee * Use is subject to license terms. 25786Slclee */ 26786Slclee 27786Slclee /* 28786Slclee * This module provides support for labeling operations for target 29786Slclee * drivers. 30786Slclee */ 31786Slclee 32786Slclee #include <sys/scsi/scsi.h> 33786Slclee #include <sys/sunddi.h> 34786Slclee #include <sys/dklabel.h> 35786Slclee #include <sys/dkio.h> 36786Slclee #include <sys/vtoc.h> 37786Slclee #include <sys/dktp/fdisk.h> 38786Slclee #include <sys/vtrace.h> 39786Slclee #include <sys/efi_partition.h> 40786Slclee #include <sys/cmlb.h> 41786Slclee #include <sys/cmlb_impl.h> 427224Scth #include <sys/ddi_impldefs.h> 43786Slclee 44786Slclee /* 45786Slclee * Driver minor node structure and data table 46786Slclee */ 47786Slclee struct driver_minor_data { 48786Slclee char *name; 49786Slclee minor_t minor; 50786Slclee int type; 51786Slclee }; 52786Slclee 53786Slclee static struct driver_minor_data dk_minor_data[] = { 54786Slclee {"a", 0, S_IFBLK}, 55786Slclee {"b", 1, S_IFBLK}, 56786Slclee {"c", 2, S_IFBLK}, 57786Slclee {"d", 3, S_IFBLK}, 58786Slclee {"e", 4, S_IFBLK}, 59786Slclee {"f", 5, S_IFBLK}, 60786Slclee {"g", 6, S_IFBLK}, 61786Slclee {"h", 7, S_IFBLK}, 62786Slclee #if defined(_SUNOS_VTOC_16) 63786Slclee {"i", 8, S_IFBLK}, 64786Slclee {"j", 9, S_IFBLK}, 65786Slclee {"k", 10, S_IFBLK}, 66786Slclee {"l", 11, S_IFBLK}, 67786Slclee {"m", 12, S_IFBLK}, 68786Slclee {"n", 13, S_IFBLK}, 69786Slclee {"o", 14, S_IFBLK}, 70786Slclee {"p", 15, S_IFBLK}, 71786Slclee #endif /* defined(_SUNOS_VTOC_16) */ 72786Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 73786Slclee {"q", 16, S_IFBLK}, 74786Slclee {"r", 17, S_IFBLK}, 75786Slclee {"s", 18, S_IFBLK}, 76786Slclee {"t", 19, S_IFBLK}, 77786Slclee {"u", 20, S_IFBLK}, 78786Slclee #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 79786Slclee {"a,raw", 0, S_IFCHR}, 80786Slclee {"b,raw", 1, S_IFCHR}, 81786Slclee {"c,raw", 2, S_IFCHR}, 82786Slclee {"d,raw", 3, S_IFCHR}, 83786Slclee {"e,raw", 4, S_IFCHR}, 84786Slclee {"f,raw", 5, S_IFCHR}, 85786Slclee {"g,raw", 6, S_IFCHR}, 86786Slclee {"h,raw", 7, S_IFCHR}, 87786Slclee #if defined(_SUNOS_VTOC_16) 88786Slclee {"i,raw", 8, S_IFCHR}, 89786Slclee {"j,raw", 9, S_IFCHR}, 90786Slclee {"k,raw", 10, S_IFCHR}, 91786Slclee {"l,raw", 11, S_IFCHR}, 92786Slclee {"m,raw", 12, S_IFCHR}, 93786Slclee {"n,raw", 13, S_IFCHR}, 94786Slclee {"o,raw", 14, S_IFCHR}, 95786Slclee {"p,raw", 15, S_IFCHR}, 96786Slclee #endif /* defined(_SUNOS_VTOC_16) */ 97786Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 98786Slclee {"q,raw", 16, S_IFCHR}, 99786Slclee {"r,raw", 17, S_IFCHR}, 100786Slclee {"s,raw", 18, S_IFCHR}, 101786Slclee {"t,raw", 19, S_IFCHR}, 102786Slclee {"u,raw", 20, S_IFCHR}, 103786Slclee #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 104786Slclee {0} 105786Slclee }; 106786Slclee 107786Slclee static struct driver_minor_data dk_minor_data_efi[] = { 108786Slclee {"a", 0, S_IFBLK}, 109786Slclee {"b", 1, S_IFBLK}, 110786Slclee {"c", 2, S_IFBLK}, 111786Slclee {"d", 3, S_IFBLK}, 112786Slclee {"e", 4, S_IFBLK}, 113786Slclee {"f", 5, S_IFBLK}, 114786Slclee {"g", 6, S_IFBLK}, 115786Slclee {"wd", 7, S_IFBLK}, 1168749SShidokht.Yadegari@Sun.COM #if defined(_SUNOS_VTOC_16) 1178749SShidokht.Yadegari@Sun.COM {"i", 8, S_IFBLK}, 1188749SShidokht.Yadegari@Sun.COM {"j", 9, S_IFBLK}, 1198749SShidokht.Yadegari@Sun.COM {"k", 10, S_IFBLK}, 1208749SShidokht.Yadegari@Sun.COM {"l", 11, S_IFBLK}, 1218749SShidokht.Yadegari@Sun.COM {"m", 12, S_IFBLK}, 1228749SShidokht.Yadegari@Sun.COM {"n", 13, S_IFBLK}, 1238749SShidokht.Yadegari@Sun.COM {"o", 14, S_IFBLK}, 1248749SShidokht.Yadegari@Sun.COM {"p", 15, S_IFBLK}, 1258749SShidokht.Yadegari@Sun.COM #endif /* defined(_SUNOS_VTOC_16) */ 126786Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 127786Slclee {"q", 16, S_IFBLK}, 128786Slclee {"r", 17, S_IFBLK}, 129786Slclee {"s", 18, S_IFBLK}, 130786Slclee {"t", 19, S_IFBLK}, 131786Slclee {"u", 20, S_IFBLK}, 132786Slclee #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 133786Slclee {"a,raw", 0, S_IFCHR}, 134786Slclee {"b,raw", 1, S_IFCHR}, 135786Slclee {"c,raw", 2, S_IFCHR}, 136786Slclee {"d,raw", 3, S_IFCHR}, 137786Slclee {"e,raw", 4, S_IFCHR}, 138786Slclee {"f,raw", 5, S_IFCHR}, 139786Slclee {"g,raw", 6, S_IFCHR}, 140786Slclee {"wd,raw", 7, S_IFCHR}, 1418749SShidokht.Yadegari@Sun.COM #if defined(_SUNOS_VTOC_16) 1428749SShidokht.Yadegari@Sun.COM {"i,raw", 8, S_IFCHR}, 1438749SShidokht.Yadegari@Sun.COM {"j,raw", 9, S_IFCHR}, 1448749SShidokht.Yadegari@Sun.COM {"k,raw", 10, S_IFCHR}, 1458749SShidokht.Yadegari@Sun.COM {"l,raw", 11, S_IFCHR}, 1468749SShidokht.Yadegari@Sun.COM {"m,raw", 12, S_IFCHR}, 1478749SShidokht.Yadegari@Sun.COM {"n,raw", 13, S_IFCHR}, 1488749SShidokht.Yadegari@Sun.COM {"o,raw", 14, S_IFCHR}, 1498749SShidokht.Yadegari@Sun.COM {"p,raw", 15, S_IFCHR}, 1508749SShidokht.Yadegari@Sun.COM #endif /* defined(_SUNOS_VTOC_16) */ 151786Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 152786Slclee {"q,raw", 16, S_IFCHR}, 153786Slclee {"r,raw", 17, S_IFCHR}, 154786Slclee {"s,raw", 18, S_IFCHR}, 155786Slclee {"t,raw", 19, S_IFCHR}, 156786Slclee {"u,raw", 20, S_IFCHR}, 157786Slclee #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 158786Slclee {0} 159786Slclee }; 160786Slclee 1617224Scth /* 1627224Scth * Declare the dynamic properties implemented in prop_op(9E) implementation 1637224Scth * that we want to have show up in a di_init(3DEVINFO) device tree snapshot 1647224Scth * of drivers that call cmlb_attach(). 1657224Scth */ 1667224Scth static i_ddi_prop_dyn_t cmlb_prop_dyn[] = { 1677224Scth {"Nblocks", DDI_PROP_TYPE_INT64, S_IFBLK}, 1687224Scth {"Size", DDI_PROP_TYPE_INT64, S_IFCHR}, 1697224Scth {"device-nblocks", DDI_PROP_TYPE_INT64}, 1707224Scth {"device-blksize", DDI_PROP_TYPE_INT}, 1717224Scth {NULL} 1727224Scth }; 173786Slclee 1746318Sedp /* 1756318Sedp * External kernel interfaces 1766318Sedp */ 177786Slclee extern struct mod_ops mod_miscops; 178786Slclee 1796318Sedp extern int ddi_create_internal_pathname(dev_info_t *dip, char *name, 1806318Sedp int spec_type, minor_t minor_num); 1816318Sedp 182786Slclee /* 183786Slclee * Global buffer and mutex for debug logging 184786Slclee */ 185786Slclee static char cmlb_log_buffer[1024]; 186786Slclee static kmutex_t cmlb_log_mutex; 187786Slclee 188786Slclee 1893525Sshidokht struct cmlb_lun *cmlb_debug_cl = NULL; 190786Slclee uint_t cmlb_level_mask = 0x0; 191786Slclee 192786Slclee int cmlb_rot_delay = 4; /* default rotational delay */ 193786Slclee 194786Slclee static struct modlmisc modlmisc = { 195786Slclee &mod_miscops, /* Type of module */ 1967563SPrasad.Singamsetty@Sun.COM "Common Labeling module" 197786Slclee }; 198786Slclee 199786Slclee static struct modlinkage modlinkage = { 200786Slclee MODREV_1, (void *)&modlmisc, NULL 201786Slclee }; 202786Slclee 203786Slclee /* Local function prototypes */ 2043525Sshidokht static dev_t cmlb_make_device(struct cmlb_lun *cl); 2058863SEdward.Pilatowicz@Sun.COM static int cmlb_validate_geometry(struct cmlb_lun *cl, boolean_t forcerevalid, 2063525Sshidokht int flags, void *tg_cookie); 2073525Sshidokht static void cmlb_resync_geom_caches(struct cmlb_lun *cl, diskaddr_t capacity, 2083525Sshidokht void *tg_cookie); 2093525Sshidokht static int cmlb_read_fdisk(struct cmlb_lun *cl, diskaddr_t capacity, 2103525Sshidokht void *tg_cookie); 211786Slclee static void cmlb_swap_efi_gpt(efi_gpt_t *e); 212786Slclee static void cmlb_swap_efi_gpe(int nparts, efi_gpe_t *p); 213786Slclee static int cmlb_validate_efi(efi_gpt_t *labp); 2143525Sshidokht static int cmlb_use_efi(struct cmlb_lun *cl, diskaddr_t capacity, int flags, 2153525Sshidokht void *tg_cookie); 2163525Sshidokht static void cmlb_build_default_label(struct cmlb_lun *cl, void *tg_cookie); 2173525Sshidokht static int cmlb_uselabel(struct cmlb_lun *cl, struct dk_label *l, int flags); 2183525Sshidokht #if defined(_SUNOS_VTOC_8) 2193525Sshidokht static void cmlb_build_user_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc); 2203525Sshidokht #endif 2213525Sshidokht static int cmlb_build_label_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc); 2223525Sshidokht static int cmlb_write_label(struct cmlb_lun *cl, void *tg_cookie); 2233525Sshidokht static int cmlb_set_vtoc(struct cmlb_lun *cl, struct dk_label *dkl, 2243525Sshidokht void *tg_cookie); 2253525Sshidokht static void cmlb_clear_efi(struct cmlb_lun *cl, void *tg_cookie); 2263525Sshidokht static void cmlb_clear_vtoc(struct cmlb_lun *cl, void *tg_cookie); 2273525Sshidokht static void cmlb_setup_default_geometry(struct cmlb_lun *cl, void *tg_cookie); 2283525Sshidokht static int cmlb_create_minor_nodes(struct cmlb_lun *cl); 2293525Sshidokht static int cmlb_check_update_blockcount(struct cmlb_lun *cl, void *tg_cookie); 2308863SEdward.Pilatowicz@Sun.COM static boolean_t cmlb_check_efi_mbr(uchar_t *buf, boolean_t *is_mbr); 231786Slclee 232786Slclee #if defined(__i386) || defined(__amd64) 2333525Sshidokht static int cmlb_update_fdisk_and_vtoc(struct cmlb_lun *cl, void *tg_cookie); 234786Slclee #endif 235786Slclee 236786Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 2378863SEdward.Pilatowicz@Sun.COM static boolean_t cmlb_has_max_chs_vals(struct ipart *fdp); 238786Slclee #endif 239786Slclee 240786Slclee #if defined(_SUNOS_VTOC_16) 2413525Sshidokht static void cmlb_convert_geometry(diskaddr_t capacity, struct dk_geom *cl_g); 242786Slclee #endif 243786Slclee 2443525Sshidokht static int cmlb_dkio_get_geometry(struct cmlb_lun *cl, caddr_t arg, int flag, 2453525Sshidokht void *tg_cookie); 2463525Sshidokht static int cmlb_dkio_set_geometry(struct cmlb_lun *cl, caddr_t arg, int flag); 2473525Sshidokht static int cmlb_dkio_get_partition(struct cmlb_lun *cl, caddr_t arg, int flag, 2483525Sshidokht void *tg_cookie); 2493525Sshidokht static int cmlb_dkio_set_partition(struct cmlb_lun *cl, caddr_t arg, int flag); 2503525Sshidokht static int cmlb_dkio_get_efi(struct cmlb_lun *cl, caddr_t arg, int flag, 2513525Sshidokht void *tg_cookie); 2523525Sshidokht static int cmlb_dkio_set_efi(struct cmlb_lun *cl, dev_t dev, caddr_t arg, 2533525Sshidokht int flag, void *tg_cookie); 2543525Sshidokht static int cmlb_dkio_get_vtoc(struct cmlb_lun *cl, caddr_t arg, int flag, 2553525Sshidokht void *tg_cookie); 2567563SPrasad.Singamsetty@Sun.COM static int cmlb_dkio_get_extvtoc(struct cmlb_lun *cl, caddr_t arg, int flag, 2577563SPrasad.Singamsetty@Sun.COM void *tg_cookie); 2583525Sshidokht static int cmlb_dkio_set_vtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, 2593525Sshidokht int flag, void *tg_cookie); 2607563SPrasad.Singamsetty@Sun.COM static int cmlb_dkio_set_extvtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, 2617563SPrasad.Singamsetty@Sun.COM int flag, void *tg_cookie); 2623525Sshidokht static int cmlb_dkio_get_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, 2633525Sshidokht void *tg_cookie); 2643525Sshidokht static int cmlb_dkio_set_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, 2653525Sshidokht void *tg_cookie); 2663525Sshidokht static int cmlb_dkio_partition(struct cmlb_lun *cl, caddr_t arg, int flag, 2673525Sshidokht void *tg_cookie); 268786Slclee 269786Slclee #if defined(__i386) || defined(__amd64) 2703525Sshidokht static int cmlb_dkio_get_virtgeom(struct cmlb_lun *cl, caddr_t arg, int flag); 2713525Sshidokht static int cmlb_dkio_get_phygeom(struct cmlb_lun *cl, caddr_t arg, int flag); 2723525Sshidokht static int cmlb_dkio_partinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg, 273786Slclee int flag); 2747563SPrasad.Singamsetty@Sun.COM static int cmlb_dkio_extpartinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg, 2757563SPrasad.Singamsetty@Sun.COM int flag); 276786Slclee #endif 277786Slclee 2783525Sshidokht static void cmlb_dbg(uint_t comp, struct cmlb_lun *cl, const char *fmt, ...); 279786Slclee static void cmlb_v_log(dev_info_t *dev, char *label, uint_t level, 280786Slclee const char *fmt, va_list ap); 281786Slclee static void cmlb_log(dev_info_t *dev, char *label, uint_t level, 282786Slclee const char *fmt, ...); 283786Slclee 284786Slclee int 285786Slclee _init(void) 286786Slclee { 287786Slclee mutex_init(&cmlb_log_mutex, NULL, MUTEX_DRIVER, NULL); 288786Slclee return (mod_install(&modlinkage)); 289786Slclee } 290786Slclee 291786Slclee int 292786Slclee _info(struct modinfo *modinfop) 293786Slclee { 294786Slclee return (mod_info(&modlinkage, modinfop)); 295786Slclee } 296786Slclee 297786Slclee int 298786Slclee _fini(void) 299786Slclee { 300786Slclee int err; 301786Slclee 302786Slclee if ((err = mod_remove(&modlinkage)) != 0) { 303786Slclee return (err); 304786Slclee } 305786Slclee 306786Slclee mutex_destroy(&cmlb_log_mutex); 307786Slclee return (err); 308786Slclee } 309786Slclee 310786Slclee /* 311786Slclee * cmlb_dbg is used for debugging to log additional info 312786Slclee * Level of output is controlled via cmlb_level_mask setting. 313786Slclee */ 314786Slclee static void 3153525Sshidokht cmlb_dbg(uint_t comp, struct cmlb_lun *cl, const char *fmt, ...) 316786Slclee { 317786Slclee va_list ap; 318786Slclee dev_info_t *dev; 319786Slclee uint_t level_mask = 0; 320786Slclee 3213525Sshidokht ASSERT(cl != NULL); 3223525Sshidokht dev = CMLB_DEVINFO(cl); 323786Slclee ASSERT(dev != NULL); 324786Slclee /* 325786Slclee * Filter messages based on the global component and level masks, 3263525Sshidokht * also print if cl matches the value of cmlb_debug_cl, or if 3273525Sshidokht * cmlb_debug_cl is set to NULL. 328786Slclee */ 329786Slclee if (comp & CMLB_TRACE) 330786Slclee level_mask |= CMLB_LOGMASK_TRACE; 331786Slclee 332786Slclee if (comp & CMLB_INFO) 333786Slclee level_mask |= CMLB_LOGMASK_INFO; 334786Slclee 335786Slclee if (comp & CMLB_ERROR) 336786Slclee level_mask |= CMLB_LOGMASK_ERROR; 337786Slclee 338786Slclee if ((cmlb_level_mask & level_mask) && 3393525Sshidokht ((cmlb_debug_cl == NULL) || (cmlb_debug_cl == cl))) { 340786Slclee va_start(ap, fmt); 3413525Sshidokht cmlb_v_log(dev, CMLB_LABEL(cl), CE_CONT, fmt, ap); 342786Slclee va_end(ap); 343786Slclee } 344786Slclee } 345786Slclee 346786Slclee /* 347786Slclee * cmlb_log is basically a duplicate of scsi_log. It is redefined here 348786Slclee * so that this module does not depend on scsi module. 349786Slclee */ 350786Slclee static void 351786Slclee cmlb_log(dev_info_t *dev, char *label, uint_t level, const char *fmt, ...) 352786Slclee { 353786Slclee va_list ap; 354786Slclee 355786Slclee va_start(ap, fmt); 356786Slclee cmlb_v_log(dev, label, level, fmt, ap); 357786Slclee va_end(ap); 358786Slclee } 359786Slclee 360786Slclee static void 361786Slclee cmlb_v_log(dev_info_t *dev, char *label, uint_t level, const char *fmt, 362786Slclee va_list ap) 363786Slclee { 364786Slclee static char name[256]; 365786Slclee int log_only = 0; 366786Slclee int boot_only = 0; 367786Slclee int console_only = 0; 368786Slclee 369786Slclee mutex_enter(&cmlb_log_mutex); 370786Slclee 371786Slclee if (dev) { 372786Slclee if (level == CE_PANIC || level == CE_WARN || 373786Slclee level == CE_NOTE) { 374786Slclee (void) sprintf(name, "%s (%s%d):\n", 375786Slclee ddi_pathname(dev, cmlb_log_buffer), 376786Slclee label, ddi_get_instance(dev)); 377786Slclee } else { 378786Slclee name[0] = '\0'; 379786Slclee } 380786Slclee } else { 381786Slclee (void) sprintf(name, "%s:", label); 382786Slclee } 383786Slclee 384786Slclee (void) vsprintf(cmlb_log_buffer, fmt, ap); 385786Slclee 386786Slclee switch (cmlb_log_buffer[0]) { 387786Slclee case '!': 388786Slclee log_only = 1; 389786Slclee break; 390786Slclee case '?': 391786Slclee boot_only = 1; 392786Slclee break; 393786Slclee case '^': 394786Slclee console_only = 1; 395786Slclee break; 396786Slclee } 397786Slclee 398786Slclee switch (level) { 399786Slclee case CE_NOTE: 400786Slclee level = CE_CONT; 401786Slclee /* FALLTHROUGH */ 402786Slclee case CE_CONT: 403786Slclee case CE_WARN: 404786Slclee case CE_PANIC: 405786Slclee if (boot_only) { 406786Slclee cmn_err(level, "?%s\t%s", name, &cmlb_log_buffer[1]); 407786Slclee } else if (console_only) { 408786Slclee cmn_err(level, "^%s\t%s", name, &cmlb_log_buffer[1]); 409786Slclee } else if (log_only) { 410786Slclee cmn_err(level, "!%s\t%s", name, &cmlb_log_buffer[1]); 411786Slclee } else { 412786Slclee cmn_err(level, "%s\t%s", name, cmlb_log_buffer); 413786Slclee } 414786Slclee break; 415786Slclee case CE_IGNORE: 416786Slclee break; 417786Slclee default: 418786Slclee cmn_err(CE_CONT, "^DEBUG: %s\t%s", name, cmlb_log_buffer); 419786Slclee break; 420786Slclee } 421786Slclee mutex_exit(&cmlb_log_mutex); 422786Slclee } 423786Slclee 424786Slclee 425786Slclee /* 426786Slclee * cmlb_alloc_handle: 427786Slclee * 428786Slclee * Allocates a handle. 429786Slclee * 430786Slclee * Arguments: 431786Slclee * cmlbhandlep pointer to handle 432786Slclee * 433786Slclee * Notes: 434786Slclee * Allocates a handle and stores the allocated handle in the area 435786Slclee * pointed to by cmlbhandlep 436786Slclee * 437786Slclee * Context: 438786Slclee * Kernel thread only (can sleep). 439786Slclee */ 440786Slclee void 441786Slclee cmlb_alloc_handle(cmlb_handle_t *cmlbhandlep) 442786Slclee { 4433525Sshidokht struct cmlb_lun *cl; 4443525Sshidokht 4453525Sshidokht cl = kmem_zalloc(sizeof (struct cmlb_lun), KM_SLEEP); 446786Slclee ASSERT(cmlbhandlep != NULL); 447786Slclee 4483525Sshidokht cl->cl_state = CMLB_INITED; 4493525Sshidokht cl->cl_def_labeltype = CMLB_LABEL_UNDEF; 4503525Sshidokht mutex_init(CMLB_MUTEX(cl), NULL, MUTEX_DRIVER, NULL); 4513525Sshidokht 4523525Sshidokht *cmlbhandlep = (cmlb_handle_t)(cl); 453786Slclee } 454786Slclee 455786Slclee /* 456786Slclee * cmlb_free_handle 457786Slclee * 458786Slclee * Frees handle. 459786Slclee * 460786Slclee * Arguments: 461786Slclee * cmlbhandlep pointer to handle 462786Slclee */ 463786Slclee void 464786Slclee cmlb_free_handle(cmlb_handle_t *cmlbhandlep) 465786Slclee { 4663525Sshidokht struct cmlb_lun *cl; 4673525Sshidokht 4683525Sshidokht cl = (struct cmlb_lun *)*cmlbhandlep; 4693525Sshidokht if (cl != NULL) { 4703525Sshidokht mutex_destroy(CMLB_MUTEX(cl)); 4713525Sshidokht kmem_free(cl, sizeof (struct cmlb_lun)); 472786Slclee } 473786Slclee 474786Slclee } 475786Slclee 476786Slclee /* 477786Slclee * cmlb_attach: 478786Slclee * 479786Slclee * Attach handle to device, create minor nodes for device. 480786Slclee * 481786Slclee * Arguments: 482786Slclee * devi pointer to device's dev_info structure. 483786Slclee * tgopsp pointer to array of functions cmlb can use to callback 484786Slclee * to target driver. 485786Slclee * 486786Slclee * device_type Peripheral device type as defined in 487786Slclee * scsi/generic/inquiry.h 488786Slclee * 489786Slclee * is_removable whether or not device is removable. 490786Slclee * 4913525Sshidokht * is_hotpluggable whether or not device is hotpluggable. 4923525Sshidokht * 493786Slclee * node_type minor node type (as used by ddi_create_minor_node) 494786Slclee * 495786Slclee * alter_behavior 496786Slclee * bit flags: 497786Slclee * 498786Slclee * CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT: create 499786Slclee * an alternate slice for the default label, if 500786Slclee * device type is DTYPE_DIRECT an architectures default 501786Slclee * label type is VTOC16. 502786Slclee * Otherwise alternate slice will no be created. 503786Slclee * 504786Slclee * 505786Slclee * CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8: report a default 506786Slclee * geometry and label for DKIOCGGEOM and DKIOCGVTOC 507786Slclee * on architecture with VTOC8 label types. 508786Slclee * 5093525Sshidokht * CMLB_OFF_BY_ONE: do the workaround for legacy off-by- 5103525Sshidokht * one bug in obtaining capacity (in sd): 5113525Sshidokht * SCSI READ_CAPACITY command returns the LBA number of the 5123525Sshidokht * last logical block, but sd once treated this number as 5133525Sshidokht * disks' capacity on x86 platform. And LBAs are addressed 5143525Sshidokht * based 0. So the last block was lost on x86 platform. 5153525Sshidokht * 5163525Sshidokht * Now, we remove this workaround. In order for present sd 5173525Sshidokht * driver to work with disks which are labeled/partitioned 5183525Sshidokht * via previous sd, we add workaround as follows: 5193525Sshidokht * 5203525Sshidokht * 1) Locate backup EFI label: cmlb searches the next to 5213525Sshidokht * last 5223525Sshidokht * block for backup EFI label. If fails, it will 5233525Sshidokht * turn to the last block for backup EFI label; 5243525Sshidokht * 5253525Sshidokht * 2) Clear backup EFI label: cmlb first search the last 5263525Sshidokht * block for backup EFI label, and will search the 5273525Sshidokht * next to last block only if failed for the last 5283525Sshidokht * block. 5293525Sshidokht * 5303525Sshidokht * 3) Calculate geometry:refer to cmlb_convert_geometry() 5313525Sshidokht * If capacity increasing by 1 causes disks' capacity 5327563SPrasad.Singamsetty@Sun.COM * to cross over the limits in geometry calculation, 5333525Sshidokht * geometry info will change. This will raise an issue: 5343525Sshidokht * In case that primary VTOC label is destroyed, format 5353525Sshidokht * commandline can restore it via backup VTOC labels. 5363525Sshidokht * And format locates backup VTOC labels by use of 5373525Sshidokht * geometry. So changing geometry will 5383525Sshidokht * prevent format from finding backup VTOC labels. To 5393525Sshidokht * eliminate this side effect for compatibility, 5403525Sshidokht * sd uses (capacity -1) to calculate geometry; 5413525Sshidokht * 5423525Sshidokht * 4) 1TB disks: some important data structures use 5433525Sshidokht * 32-bit signed long/int (for example, daddr_t), 5443525Sshidokht * so that sd doesn't support a disk with capacity 5453525Sshidokht * larger than 1TB on 32-bit platform. However, 5463525Sshidokht * for exactly 1TB disk, it was treated as (1T - 512)B 5473525Sshidokht * in the past, and could have valid Solaris 5483525Sshidokht * partitions. To workaround this, if an exactly 1TB 5493525Sshidokht * disk has Solaris fdisk partition, it will be allowed 5503525Sshidokht * to work with sd. 5513525Sshidokht * 5523525Sshidokht * 553786Slclee * 5545084Sjohnlev * CMLB_FAKE_LABEL_ONE_PARTITION: create s0 and s2 covering 5555084Sjohnlev * the entire disk, if there is no valid partition info. 5565084Sjohnlev * If there is a valid Solaris partition, s0 and s2 will 5575084Sjohnlev * only cover the entire Solaris partition. 5585084Sjohnlev * 5595084Sjohnlev * 560786Slclee * cmlbhandle cmlb handle associated with device 561786Slclee * 5623525Sshidokht * tg_cookie cookie from target driver to be passed back to target 5633525Sshidokht * driver when we call back to it through tg_ops. 5643525Sshidokht * 565786Slclee * Notes: 566786Slclee * Assumes a default label based on capacity for non-removable devices. 567786Slclee * If capacity > 1TB, EFI is assumed otherwise VTOC (default VTOC 568786Slclee * for the architecture). 569786Slclee * 570786Slclee * For removable devices, default label type is assumed to be VTOC 571786Slclee * type. Create minor nodes based on a default label type. 572786Slclee * Label on the media is not validated. 573786Slclee * minor number consists of: 574786Slclee * if _SUNOS_VTOC_8 is defined 575786Slclee * lowest 3 bits is taken as partition number 576786Slclee * the rest is instance number 577786Slclee * if _SUNOS_VTOC_16 is defined 578786Slclee * lowest 6 bits is taken as partition number 579786Slclee * the rest is instance number 580786Slclee * 581786Slclee * 582786Slclee * Return values: 583786Slclee * 0 Success 584786Slclee * ENXIO creating minor nodes failed. 5853525Sshidokht * EINVAL invalid arg, unsupported tg_ops version 586786Slclee */ 587786Slclee int 588786Slclee cmlb_attach(dev_info_t *devi, cmlb_tg_ops_t *tgopsp, int device_type, 5898863SEdward.Pilatowicz@Sun.COM boolean_t is_removable, boolean_t is_hotpluggable, char *node_type, 5903525Sshidokht int alter_behavior, cmlb_handle_t cmlbhandle, void *tg_cookie) 591786Slclee { 592786Slclee 5933525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 594786Slclee diskaddr_t cap; 595786Slclee int status; 596786Slclee 5978863SEdward.Pilatowicz@Sun.COM ASSERT(VALID_BOOLEAN(is_removable)); 5988863SEdward.Pilatowicz@Sun.COM ASSERT(VALID_BOOLEAN(is_hotpluggable)); 5998863SEdward.Pilatowicz@Sun.COM 6003525Sshidokht if (tgopsp->tg_version < TG_DK_OPS_VERSION_1) 6013525Sshidokht return (EINVAL); 6023525Sshidokht 6033525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 6043525Sshidokht 6053525Sshidokht CMLB_DEVINFO(cl) = devi; 6063525Sshidokht cl->cmlb_tg_ops = tgopsp; 6073525Sshidokht cl->cl_device_type = device_type; 6083525Sshidokht cl->cl_is_removable = is_removable; 6093525Sshidokht cl->cl_is_hotpluggable = is_hotpluggable; 6103525Sshidokht cl->cl_node_type = node_type; 6113525Sshidokht cl->cl_sys_blocksize = DEV_BSIZE; 6128863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE; 6133525Sshidokht cl->cl_def_labeltype = CMLB_LABEL_VTOC; 6143525Sshidokht cl->cl_alter_behavior = alter_behavior; 6153525Sshidokht cl->cl_reserved = -1; 6167563SPrasad.Singamsetty@Sun.COM cl->cl_msglog_flag |= CMLB_ALLOW_2TB_WARN; 6177563SPrasad.Singamsetty@Sun.COM 6188863SEdward.Pilatowicz@Sun.COM if (!is_removable) { 6193525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 6203525Sshidokht status = DK_TG_GETCAP(cl, &cap, tg_cookie); 6213525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 6227563SPrasad.Singamsetty@Sun.COM if (status == 0 && cap > CMLB_EXTVTOC_LIMIT) { 6237563SPrasad.Singamsetty@Sun.COM /* set default EFI if > 2TB */ 6243525Sshidokht cl->cl_def_labeltype = CMLB_LABEL_EFI; 625786Slclee } 626786Slclee } 627786Slclee 628786Slclee /* create minor nodes based on default label type */ 6293525Sshidokht cl->cl_last_labeltype = CMLB_LABEL_UNDEF; 6303525Sshidokht cl->cl_cur_labeltype = CMLB_LABEL_UNDEF; 6313525Sshidokht 6323525Sshidokht if (cmlb_create_minor_nodes(cl) != 0) { 6333525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 634786Slclee return (ENXIO); 635786Slclee } 636786Slclee 6377224Scth /* Define the dynamic properties for devinfo spapshots. */ 6387224Scth i_ddi_prop_dyn_driver_set(CMLB_DEVINFO(cl), cmlb_prop_dyn); 6397224Scth 6403525Sshidokht cl->cl_state = CMLB_ATTACHED; 6413525Sshidokht 6423525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 643786Slclee return (0); 644786Slclee } 645786Slclee 646786Slclee /* 647786Slclee * cmlb_detach: 648786Slclee * 649786Slclee * Invalidate in-core labeling data and remove all minor nodes for 650786Slclee * the device associate with handle. 651786Slclee * 652786Slclee * Arguments: 653786Slclee * cmlbhandle cmlb handle associated with device. 654786Slclee * 6553525Sshidokht * tg_cookie cookie from target driver to be passed back to target 6563525Sshidokht * driver when we call back to it through tg_ops. 6573525Sshidokht * 658786Slclee */ 6593525Sshidokht /*ARGSUSED1*/ 660786Slclee void 6613525Sshidokht cmlb_detach(cmlb_handle_t cmlbhandle, void *tg_cookie) 662786Slclee { 6633525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 6643525Sshidokht 6653525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 6663525Sshidokht cl->cl_def_labeltype = CMLB_LABEL_UNDEF; 6678863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE; 6683525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL); 6697224Scth i_ddi_prop_dyn_driver_set(CMLB_DEVINFO(cl), NULL); 6703525Sshidokht cl->cl_state = CMLB_INITED; 6713525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 672786Slclee } 673786Slclee 674786Slclee /* 675786Slclee * cmlb_validate: 676786Slclee * 677786Slclee * Validates label. 678786Slclee * 679786Slclee * Arguments 680786Slclee * cmlbhandle cmlb handle associated with device. 681786Slclee * 6823525Sshidokht * flags operation flags. used for verbosity control 6833525Sshidokht * 6843525Sshidokht * tg_cookie cookie from target driver to be passed back to target 6853525Sshidokht * driver when we call back to it through tg_ops. 6863525Sshidokht * 6873525Sshidokht * 688786Slclee * Notes: 689786Slclee * If new label type is different from the current, adjust minor nodes 690786Slclee * accordingly. 691786Slclee * 692786Slclee * Return values: 693786Slclee * 0 success 694786Slclee * Note: having fdisk but no solaris partition is assumed 695786Slclee * success. 696786Slclee * 697786Slclee * ENOMEM memory allocation failed 698786Slclee * EIO i/o errors during read or get capacity 699786Slclee * EACCESS reservation conflicts 700786Slclee * EINVAL label was corrupt, or no default label was assumed 701786Slclee * ENXIO invalid handle 702786Slclee */ 703786Slclee int 7043525Sshidokht cmlb_validate(cmlb_handle_t cmlbhandle, int flags, void *tg_cookie) 705786Slclee { 7063525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 707786Slclee int rval; 708786Slclee int ret = 0; 709786Slclee 710786Slclee /* 7113525Sshidokht * Temp work-around checking cl for NULL since there is a bug 712786Slclee * in sd_detach calling this routine from taskq_dispatch 713786Slclee * inited function. 714786Slclee */ 7153525Sshidokht if (cl == NULL) 716786Slclee return (ENXIO); 717786Slclee 7183525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 7193525Sshidokht if (cl->cl_state < CMLB_ATTACHED) { 7203525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 721786Slclee return (ENXIO); 722786Slclee } 723786Slclee 7248863SEdward.Pilatowicz@Sun.COM rval = cmlb_validate_geometry((struct cmlb_lun *)cmlbhandle, B_TRUE, 7253525Sshidokht flags, tg_cookie); 726786Slclee 727786Slclee if (rval == ENOTSUP) { 7288863SEdward.Pilatowicz@Sun.COM if (cl->cl_f_geometry_is_valid) { 7293525Sshidokht cl->cl_cur_labeltype = CMLB_LABEL_EFI; 730786Slclee ret = 0; 731786Slclee } else { 732786Slclee ret = EINVAL; 733786Slclee } 734786Slclee } else { 735786Slclee ret = rval; 736786Slclee if (ret == 0) 7373525Sshidokht cl->cl_cur_labeltype = CMLB_LABEL_VTOC; 738786Slclee } 739786Slclee 740786Slclee if (ret == 0) 7413525Sshidokht (void) cmlb_create_minor_nodes(cl); 7423525Sshidokht 7433525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 744786Slclee return (ret); 745786Slclee } 746786Slclee 747786Slclee /* 748786Slclee * cmlb_invalidate: 749786Slclee * Invalidate in core label data 750786Slclee * 751786Slclee * Arguments: 752786Slclee * cmlbhandle cmlb handle associated with device. 7533525Sshidokht * tg_cookie cookie from target driver to be passed back to target 7543525Sshidokht * driver when we call back to it through tg_ops. 755786Slclee */ 7563525Sshidokht /*ARGSUSED1*/ 757786Slclee void 7583525Sshidokht cmlb_invalidate(cmlb_handle_t cmlbhandle, void *tg_cookie) 759786Slclee { 7603525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 7613525Sshidokht 7623525Sshidokht if (cl == NULL) 763786Slclee return; 764786Slclee 7653525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 7668863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE; 7673525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 768786Slclee } 769786Slclee 770786Slclee /* 7713525Sshidokht * cmlb_is_valid 7723525Sshidokht * Get status on whether the incore label/geom data is valid 7733525Sshidokht * 7743525Sshidokht * Arguments: 7753525Sshidokht * cmlbhandle cmlb handle associated with device. 7763525Sshidokht * 7773525Sshidokht * Return values: 7788863SEdward.Pilatowicz@Sun.COM * B_TRUE if incore label/geom data is valid. 7798863SEdward.Pilatowicz@Sun.COM * B_FALSE otherwise. 7803525Sshidokht * 7813525Sshidokht */ 7823525Sshidokht 7833525Sshidokht 7848863SEdward.Pilatowicz@Sun.COM boolean_t 7853525Sshidokht cmlb_is_valid(cmlb_handle_t cmlbhandle) 7863525Sshidokht { 7873525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 7883525Sshidokht 7893525Sshidokht if (cmlbhandle == NULL) 7908863SEdward.Pilatowicz@Sun.COM return (B_FALSE); 7913525Sshidokht 7923525Sshidokht return (cl->cl_f_geometry_is_valid); 7933525Sshidokht 7943525Sshidokht } 7953525Sshidokht 7963525Sshidokht 7973525Sshidokht 7983525Sshidokht /* 799786Slclee * cmlb_close: 800786Slclee * 801786Slclee * Close the device, revert to a default label minor node for the device, 802786Slclee * if it is removable. 803786Slclee * 804786Slclee * Arguments: 805786Slclee * cmlbhandle cmlb handle associated with device. 806786Slclee * 8073525Sshidokht * tg_cookie cookie from target driver to be passed back to target 8083525Sshidokht * driver when we call back to it through tg_ops. 809786Slclee * Return values: 810786Slclee * 0 Success 811786Slclee * ENXIO Re-creating minor node failed. 812786Slclee */ 8133525Sshidokht /*ARGSUSED1*/ 814786Slclee int 8153525Sshidokht cmlb_close(cmlb_handle_t cmlbhandle, void *tg_cookie) 816786Slclee { 8173525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 8183525Sshidokht 8193525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 8208863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE; 821786Slclee 822786Slclee /* revert to default minor node for this device */ 8233525Sshidokht if (ISREMOVABLE(cl)) { 8243525Sshidokht cl->cl_cur_labeltype = CMLB_LABEL_UNDEF; 8253525Sshidokht (void) cmlb_create_minor_nodes(cl); 826786Slclee } 827786Slclee 8283525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 829786Slclee return (0); 830786Slclee } 831786Slclee 832786Slclee /* 833786Slclee * cmlb_get_devid_block: 834786Slclee * get the block number where device id is stored. 835786Slclee * 836786Slclee * Arguments: 837786Slclee * cmlbhandle cmlb handle associated with device. 838786Slclee * devidblockp pointer to block number. 8393525Sshidokht * tg_cookie cookie from target driver to be passed back to target 8403525Sshidokht * driver when we call back to it through tg_ops. 841786Slclee * 842786Slclee * Notes: 843786Slclee * It stores the block number of device id in the area pointed to 844786Slclee * by devidblockp. 845786Slclee * with the block number of device id. 846786Slclee * 847786Slclee * Return values: 848786Slclee * 0 success 849786Slclee * EINVAL device id does not apply to current label type. 850786Slclee */ 8513525Sshidokht /*ARGSUSED2*/ 852786Slclee int 8533525Sshidokht cmlb_get_devid_block(cmlb_handle_t cmlbhandle, diskaddr_t *devidblockp, 8543525Sshidokht void *tg_cookie) 855786Slclee { 856786Slclee daddr_t spc, blk, head, cyl; 8573525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 8583525Sshidokht 8593525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 8603525Sshidokht if (cl->cl_state < CMLB_ATTACHED) { 8613525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 8623525Sshidokht return (EINVAL); 8633525Sshidokht } 8643525Sshidokht 8658863SEdward.Pilatowicz@Sun.COM if ((!cl->cl_f_geometry_is_valid) || 8663525Sshidokht (cl->cl_solaris_size < DK_LABEL_LOC)) { 8673525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 868786Slclee return (EINVAL); 869786Slclee } 870786Slclee 8713525Sshidokht if (cl->cl_cur_labeltype == CMLB_LABEL_EFI) { 8723525Sshidokht if (cl->cl_reserved != -1) { 8733525Sshidokht blk = cl->cl_map[cl->cl_reserved].dkl_cylno; 8743525Sshidokht } else { 8753525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 8763525Sshidokht return (EINVAL); 8773525Sshidokht } 8783525Sshidokht } else { 8796513Sml40262 /* if the disk is unlabeled, don't write a devid to it */ 8807563SPrasad.Singamsetty@Sun.COM if (cl->cl_label_from_media != CMLB_LABEL_VTOC) { 8816513Sml40262 mutex_exit(CMLB_MUTEX(cl)); 8826513Sml40262 return (EINVAL); 8836513Sml40262 } 8846513Sml40262 885786Slclee /* this geometry doesn't allow us to write a devid */ 8863525Sshidokht if (cl->cl_g.dkg_acyl < 2) { 8873525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 888786Slclee return (EINVAL); 889786Slclee } 890786Slclee 891786Slclee /* 892786Slclee * Subtract 2 guarantees that the next to last cylinder 893786Slclee * is used 894786Slclee */ 8953525Sshidokht cyl = cl->cl_g.dkg_ncyl + cl->cl_g.dkg_acyl - 2; 8963525Sshidokht spc = cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect; 8973525Sshidokht head = cl->cl_g.dkg_nhead - 1; 8986513Sml40262 blk = cl->cl_solaris_offset + 8996513Sml40262 (cyl * (spc - cl->cl_g.dkg_apc)) + 9003525Sshidokht (head * cl->cl_g.dkg_nsect) + 1; 901786Slclee } 9023525Sshidokht 903786Slclee *devidblockp = blk; 9043525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 905786Slclee return (0); 906786Slclee } 907786Slclee 908786Slclee /* 909786Slclee * cmlb_partinfo: 910786Slclee * Get partition info for specified partition number. 911786Slclee * 912786Slclee * Arguments: 913786Slclee * cmlbhandle cmlb handle associated with device. 914786Slclee * part partition number 915786Slclee * nblocksp pointer to number of blocks 916786Slclee * startblockp pointer to starting block 917786Slclee * partnamep pointer to name of partition 918786Slclee * tagp pointer to tag info 9193525Sshidokht * tg_cookie cookie from target driver to be passed back to target 9203525Sshidokht * driver when we call back to it through tg_ops. 921786Slclee * 922786Slclee * 923786Slclee * Notes: 924786Slclee * If in-core label is not valid, this functions tries to revalidate 925786Slclee * the label. If label is valid, it stores the total number of blocks 926786Slclee * in this partition in the area pointed to by nblocksp, starting 927786Slclee * block number in area pointed to by startblockp, pointer to partition 928786Slclee * name in area pointed to by partnamep, and tag value in area 929786Slclee * pointed by tagp. 930786Slclee * For EFI labels, tag value will be set to 0. 931786Slclee * 932786Slclee * For all nblocksp, startblockp and partnamep, tagp, a value of NULL 933786Slclee * indicates the corresponding info is not requested. 934786Slclee * 935786Slclee * 936786Slclee * Return values: 937786Slclee * 0 success 938786Slclee * EINVAL no valid label or requested partition number is invalid. 939786Slclee * 940786Slclee */ 941786Slclee int 942786Slclee cmlb_partinfo(cmlb_handle_t cmlbhandle, int part, diskaddr_t *nblocksp, 9433525Sshidokht diskaddr_t *startblockp, char **partnamep, uint16_t *tagp, void *tg_cookie) 944786Slclee { 945786Slclee 9463525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 947786Slclee int rval; 948786Slclee 9493525Sshidokht ASSERT(cl != NULL); 9503525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 9513525Sshidokht if (cl->cl_state < CMLB_ATTACHED) { 9523525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 953786Slclee return (EINVAL); 954786Slclee } 955786Slclee 956786Slclee if (part < 0 || part >= MAXPART) { 957786Slclee rval = EINVAL; 958786Slclee } else { 9598863SEdward.Pilatowicz@Sun.COM if (!cl->cl_f_geometry_is_valid) 9608863SEdward.Pilatowicz@Sun.COM (void) cmlb_validate_geometry((struct cmlb_lun *)cl, 9618863SEdward.Pilatowicz@Sun.COM B_FALSE, 0, tg_cookie); 9623525Sshidokht 9637563SPrasad.Singamsetty@Sun.COM #if defined(_SUNOS_VTOC_16) 9648863SEdward.Pilatowicz@Sun.COM if (((!cl->cl_f_geometry_is_valid) || 9657563SPrasad.Singamsetty@Sun.COM (part < NDKMAP && cl->cl_solaris_size == 0)) && 9667563SPrasad.Singamsetty@Sun.COM (part != P0_RAW_DISK)) { 9677563SPrasad.Singamsetty@Sun.COM #else 9688863SEdward.Pilatowicz@Sun.COM if ((!cl->cl_f_geometry_is_valid) || 9693525Sshidokht (part < NDKMAP && cl->cl_solaris_size == 0)) { 9707563SPrasad.Singamsetty@Sun.COM #endif 971786Slclee rval = EINVAL; 972786Slclee } else { 973786Slclee if (startblockp != NULL) 9743525Sshidokht *startblockp = (diskaddr_t)cl->cl_offset[part]; 975786Slclee 976786Slclee if (nblocksp != NULL) 977786Slclee *nblocksp = (diskaddr_t) 9783525Sshidokht cl->cl_map[part].dkl_nblk; 979786Slclee 980786Slclee if (tagp != NULL) 9813525Sshidokht if (cl->cl_cur_labeltype == CMLB_LABEL_EFI) 982786Slclee *tagp = V_UNASSIGNED; 983786Slclee else 9843525Sshidokht *tagp = cl->cl_vtoc.v_part[part].p_tag; 985786Slclee rval = 0; 986786Slclee } 987786Slclee 988786Slclee /* consistent with behavior of sd for getting minor name */ 989786Slclee if (partnamep != NULL) 990786Slclee *partnamep = dk_minor_data[part].name; 991786Slclee 992786Slclee } 993786Slclee 9943525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 995786Slclee return (rval); 996786Slclee } 997786Slclee 9986590Syl194034 /* 9996590Syl194034 * cmlb_efi_label_capacity: 10006590Syl194034 * Get capacity stored in EFI disk label. 10016590Syl194034 * 10026590Syl194034 * Arguments: 10036590Syl194034 * cmlbhandle cmlb handle associated with device. 10046590Syl194034 * capacity pointer to capacity stored in EFI disk label. 10056590Syl194034 * tg_cookie cookie from target driver to be passed back to target 10066590Syl194034 * driver when we call back to it through tg_ops. 10076590Syl194034 * 10086590Syl194034 * 10096590Syl194034 * Notes: 10106590Syl194034 * If in-core label is not valid, this functions tries to revalidate 10116590Syl194034 * the label. If label is valid and is an EFI label, it stores the capacity 10126590Syl194034 * in disk label in the area pointed to by capacity. 10136590Syl194034 * 10146590Syl194034 * 10156590Syl194034 * Return values: 10166590Syl194034 * 0 success 10176590Syl194034 * EINVAL no valid EFI label or capacity is NULL. 10186590Syl194034 * 10196590Syl194034 */ 10206590Syl194034 int 10216590Syl194034 cmlb_efi_label_capacity(cmlb_handle_t cmlbhandle, diskaddr_t *capacity, 10226590Syl194034 void *tg_cookie) 10236590Syl194034 { 10246590Syl194034 struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 10256590Syl194034 int rval; 10266590Syl194034 10276590Syl194034 ASSERT(cl != NULL); 10286590Syl194034 mutex_enter(CMLB_MUTEX(cl)); 10296590Syl194034 if (cl->cl_state < CMLB_ATTACHED) { 10306590Syl194034 mutex_exit(CMLB_MUTEX(cl)); 10316590Syl194034 return (EINVAL); 10326590Syl194034 } 10336590Syl194034 10348863SEdward.Pilatowicz@Sun.COM if (!cl->cl_f_geometry_is_valid) 10358863SEdward.Pilatowicz@Sun.COM (void) cmlb_validate_geometry((struct cmlb_lun *)cl, B_FALSE, 10366590Syl194034 0, tg_cookie); 10376590Syl194034 10388863SEdward.Pilatowicz@Sun.COM if ((!cl->cl_f_geometry_is_valid) || (capacity == NULL) || 10396590Syl194034 (cl->cl_cur_labeltype != CMLB_LABEL_EFI)) { 10406590Syl194034 rval = EINVAL; 10416590Syl194034 } else { 10426590Syl194034 *capacity = (diskaddr_t)cl->cl_map[WD_NODE].dkl_nblk; 10436590Syl194034 rval = 0; 10446590Syl194034 } 10456590Syl194034 10466590Syl194034 mutex_exit(CMLB_MUTEX(cl)); 10476590Syl194034 return (rval); 10486590Syl194034 } 10496590Syl194034 10503525Sshidokht /* Caller should make sure Test Unit Ready succeeds before calling this. */ 10513525Sshidokht /*ARGSUSED*/ 1052786Slclee int 1053786Slclee cmlb_ioctl(cmlb_handle_t cmlbhandle, dev_t dev, int cmd, intptr_t arg, 10543525Sshidokht int flag, cred_t *cred_p, int *rval_p, void *tg_cookie) 1055786Slclee { 1056786Slclee 1057786Slclee int err; 10583525Sshidokht struct cmlb_lun *cl; 10593525Sshidokht 10603525Sshidokht cl = (struct cmlb_lun *)cmlbhandle; 10613525Sshidokht 10623525Sshidokht ASSERT(cl != NULL); 10633525Sshidokht 10643525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 10653525Sshidokht if (cl->cl_state < CMLB_ATTACHED) { 10663525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 1067786Slclee return (EIO); 1068786Slclee } 1069786Slclee 1070786Slclee switch (cmd) { 10717563SPrasad.Singamsetty@Sun.COM case DKIOCSEXTVTOC: 10723525Sshidokht case DKIOCSGEOM: 1073786Slclee case DKIOCSETEFI: 1074786Slclee case DKIOCSMBOOT: 1075786Slclee break; 10767563SPrasad.Singamsetty@Sun.COM case DKIOCSVTOC: 10777563SPrasad.Singamsetty@Sun.COM #if defined(__i386) || defined(__amd64) 10787563SPrasad.Singamsetty@Sun.COM case DKIOCPARTINFO: 10797563SPrasad.Singamsetty@Sun.COM #endif 10807563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) { 10817563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 10827563SPrasad.Singamsetty@Sun.COM return (EOVERFLOW); 10837563SPrasad.Singamsetty@Sun.COM } 10847563SPrasad.Singamsetty@Sun.COM break; 1085786Slclee default: 10867563SPrasad.Singamsetty@Sun.COM (void) cmlb_validate_geometry(cl, 1, CMLB_SILENT, 10873903Sshidokht tg_cookie); 10883525Sshidokht 10897563SPrasad.Singamsetty@Sun.COM switch (cmd) { 10907563SPrasad.Singamsetty@Sun.COM case DKIOCGVTOC: 10917563SPrasad.Singamsetty@Sun.COM case DKIOCGAPART: 10927563SPrasad.Singamsetty@Sun.COM case DKIOCSAPART: 10937563SPrasad.Singamsetty@Sun.COM 10947563SPrasad.Singamsetty@Sun.COM if (cl->cl_label_from_media == CMLB_LABEL_EFI) { 10957563SPrasad.Singamsetty@Sun.COM /* GPT label on disk */ 10967563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 10977563SPrasad.Singamsetty@Sun.COM return (ENOTSUP); 10987563SPrasad.Singamsetty@Sun.COM } else if 10997563SPrasad.Singamsetty@Sun.COM (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) { 11007563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 11017563SPrasad.Singamsetty@Sun.COM return (EOVERFLOW); 11027563SPrasad.Singamsetty@Sun.COM } 11037563SPrasad.Singamsetty@Sun.COM break; 11047563SPrasad.Singamsetty@Sun.COM 11057563SPrasad.Singamsetty@Sun.COM case DKIOCGGEOM: 11067563SPrasad.Singamsetty@Sun.COM if (cl->cl_label_from_media == CMLB_LABEL_EFI) { 11077563SPrasad.Singamsetty@Sun.COM /* GPT label on disk */ 11083525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 1109786Slclee return (ENOTSUP); 1110786Slclee } 11117563SPrasad.Singamsetty@Sun.COM break; 11127563SPrasad.Singamsetty@Sun.COM default: 11137563SPrasad.Singamsetty@Sun.COM break; 1114786Slclee } 1115786Slclee } 1116786Slclee 11173525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 1118786Slclee 1119786Slclee switch (cmd) { 1120786Slclee case DKIOCGGEOM: 11213525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGGEOM\n"); 11223525Sshidokht err = cmlb_dkio_get_geometry(cl, (caddr_t)arg, flag, tg_cookie); 1123786Slclee break; 1124786Slclee 1125786Slclee case DKIOCSGEOM: 11263525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSGEOM\n"); 11273525Sshidokht err = cmlb_dkio_set_geometry(cl, (caddr_t)arg, flag); 1128786Slclee break; 1129786Slclee 1130786Slclee case DKIOCGAPART: 11313525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGAPART\n"); 11323525Sshidokht err = cmlb_dkio_get_partition(cl, (caddr_t)arg, 11333525Sshidokht flag, tg_cookie); 1134786Slclee break; 1135786Slclee 1136786Slclee case DKIOCSAPART: 11373525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSAPART\n"); 11383525Sshidokht err = cmlb_dkio_set_partition(cl, (caddr_t)arg, flag); 1139786Slclee break; 1140786Slclee 1141786Slclee case DKIOCGVTOC: 11423525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGVTOC\n"); 11433525Sshidokht err = cmlb_dkio_get_vtoc(cl, (caddr_t)arg, flag, tg_cookie); 1144786Slclee break; 1145786Slclee 11467563SPrasad.Singamsetty@Sun.COM case DKIOCGEXTVTOC: 11477563SPrasad.Singamsetty@Sun.COM cmlb_dbg(CMLB_TRACE, cl, "DKIOCGVTOC\n"); 11487563SPrasad.Singamsetty@Sun.COM err = cmlb_dkio_get_extvtoc(cl, (caddr_t)arg, flag, tg_cookie); 11497563SPrasad.Singamsetty@Sun.COM break; 11507563SPrasad.Singamsetty@Sun.COM 1151786Slclee case DKIOCGETEFI: 11523525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGETEFI\n"); 11533525Sshidokht err = cmlb_dkio_get_efi(cl, (caddr_t)arg, flag, tg_cookie); 1154786Slclee break; 1155786Slclee 1156786Slclee case DKIOCPARTITION: 11573525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCPARTITION\n"); 11583525Sshidokht err = cmlb_dkio_partition(cl, (caddr_t)arg, flag, tg_cookie); 1159786Slclee break; 1160786Slclee 1161786Slclee case DKIOCSVTOC: 11623525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSVTOC\n"); 11633525Sshidokht err = cmlb_dkio_set_vtoc(cl, dev, (caddr_t)arg, flag, 11643525Sshidokht tg_cookie); 1165786Slclee break; 1166786Slclee 11677563SPrasad.Singamsetty@Sun.COM case DKIOCSEXTVTOC: 11687563SPrasad.Singamsetty@Sun.COM cmlb_dbg(CMLB_TRACE, cl, "DKIOCSVTOC\n"); 11697563SPrasad.Singamsetty@Sun.COM err = cmlb_dkio_set_extvtoc(cl, dev, (caddr_t)arg, flag, 11707563SPrasad.Singamsetty@Sun.COM tg_cookie); 11717563SPrasad.Singamsetty@Sun.COM break; 11727563SPrasad.Singamsetty@Sun.COM 1173786Slclee case DKIOCSETEFI: 11743525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSETEFI\n"); 11753525Sshidokht err = cmlb_dkio_set_efi(cl, dev, (caddr_t)arg, flag, tg_cookie); 1176786Slclee break; 1177786Slclee 1178786Slclee case DKIOCGMBOOT: 11793525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGMBOOT\n"); 11803525Sshidokht err = cmlb_dkio_get_mboot(cl, (caddr_t)arg, flag, tg_cookie); 1181786Slclee break; 1182786Slclee 1183786Slclee case DKIOCSMBOOT: 11843525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSMBOOT\n"); 11853525Sshidokht err = cmlb_dkio_set_mboot(cl, (caddr_t)arg, flag, tg_cookie); 1186786Slclee break; 1187786Slclee case DKIOCG_PHYGEOM: 11883525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCG_PHYGEOM\n"); 1189786Slclee #if defined(__i386) || defined(__amd64) 11903525Sshidokht err = cmlb_dkio_get_phygeom(cl, (caddr_t)arg, flag); 1191786Slclee #else 1192786Slclee err = ENOTTY; 1193786Slclee #endif 1194786Slclee break; 1195786Slclee case DKIOCG_VIRTGEOM: 11963525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCG_VIRTGEOM\n"); 1197786Slclee #if defined(__i386) || defined(__amd64) 11983525Sshidokht err = cmlb_dkio_get_virtgeom(cl, (caddr_t)arg, flag); 1199786Slclee #else 1200786Slclee err = ENOTTY; 1201786Slclee #endif 1202786Slclee break; 1203786Slclee case DKIOCPARTINFO: 12043525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCPARTINFO"); 1205786Slclee #if defined(__i386) || defined(__amd64) 12063525Sshidokht err = cmlb_dkio_partinfo(cl, dev, (caddr_t)arg, flag); 1207786Slclee #else 1208786Slclee err = ENOTTY; 1209786Slclee #endif 1210786Slclee break; 12117563SPrasad.Singamsetty@Sun.COM case DKIOCEXTPARTINFO: 12127563SPrasad.Singamsetty@Sun.COM cmlb_dbg(CMLB_TRACE, cl, "DKIOCPARTINFO"); 12137563SPrasad.Singamsetty@Sun.COM #if defined(__i386) || defined(__amd64) 12147563SPrasad.Singamsetty@Sun.COM err = cmlb_dkio_extpartinfo(cl, dev, (caddr_t)arg, flag); 12157563SPrasad.Singamsetty@Sun.COM #else 12167563SPrasad.Singamsetty@Sun.COM err = ENOTTY; 12177563SPrasad.Singamsetty@Sun.COM #endif 12187563SPrasad.Singamsetty@Sun.COM break; 12198333SSuhasini.Peddada@Sun.COM 1220786Slclee default: 1221786Slclee err = ENOTTY; 1222786Slclee 1223786Slclee } 12247224Scth 12257224Scth /* 12267224Scth * An ioctl that succeeds and changed ('set') size(9P) information 12277224Scth * needs to invalidate the cached devinfo snapshot to avoid having 12287224Scth * old information being returned in a snapshots. 12297224Scth * 12307224Scth * NB: When available, call ddi_change_minor_node() to clear 12317224Scth * SSIZEVALID in specfs vnodes via spec_size_invalidate(). 12327224Scth */ 12337224Scth if (err == 0) { 12347224Scth switch (cmd) { 12357224Scth case DKIOCSGEOM: 12367224Scth case DKIOCSAPART: 12377224Scth case DKIOCSVTOC: 12387563SPrasad.Singamsetty@Sun.COM case DKIOCSEXTVTOC: 12397224Scth case DKIOCSETEFI: 12407224Scth i_ddi_prop_dyn_cache_invalidate(CMLB_DEVINFO(cl), 12417224Scth i_ddi_prop_dyn_driver_get(CMLB_DEVINFO(cl))); 12427224Scth } 12437224Scth } 1244786Slclee return (err); 1245786Slclee } 1246786Slclee 1247786Slclee dev_t 12483525Sshidokht cmlb_make_device(struct cmlb_lun *cl) 1249786Slclee { 12508459SJerry.Gilliam@Sun.COM return (makedevice(ddi_driver_major(CMLB_DEVINFO(cl)), 12513525Sshidokht ddi_get_instance(CMLB_DEVINFO(cl)) << CMLBUNIT_SHIFT)); 1252786Slclee } 1253786Slclee 1254786Slclee /* 1255786Slclee * Function: cmlb_check_update_blockcount 1256786Slclee * 1257786Slclee * Description: If current capacity value is invalid, obtains the 1258786Slclee * current capacity from target driver. 1259786Slclee * 1260786Slclee * Return Code: 0 success 1261786Slclee * EIO failure 1262786Slclee */ 1263786Slclee static int 12643525Sshidokht cmlb_check_update_blockcount(struct cmlb_lun *cl, void *tg_cookie) 1265786Slclee { 1266786Slclee int status; 1267786Slclee diskaddr_t capacity; 12683525Sshidokht uint32_t lbasize; 12693525Sshidokht 12703525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 12713525Sshidokht 12728863SEdward.Pilatowicz@Sun.COM if (cl->cl_f_geometry_is_valid) 12738863SEdward.Pilatowicz@Sun.COM return (0); 12748863SEdward.Pilatowicz@Sun.COM 12758863SEdward.Pilatowicz@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 12768863SEdward.Pilatowicz@Sun.COM status = DK_TG_GETCAP(cl, &capacity, tg_cookie); 12778863SEdward.Pilatowicz@Sun.COM if (status != 0) { 12783525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 12798863SEdward.Pilatowicz@Sun.COM return (EIO); 12808863SEdward.Pilatowicz@Sun.COM } 12818863SEdward.Pilatowicz@Sun.COM 12828863SEdward.Pilatowicz@Sun.COM status = DK_TG_GETBLOCKSIZE(cl, &lbasize, tg_cookie); 12838863SEdward.Pilatowicz@Sun.COM mutex_enter(CMLB_MUTEX(cl)); 12848863SEdward.Pilatowicz@Sun.COM if (status != 0) 12858863SEdward.Pilatowicz@Sun.COM return (EIO); 12868863SEdward.Pilatowicz@Sun.COM 12878863SEdward.Pilatowicz@Sun.COM if ((capacity != 0) && (lbasize != 0)) { 12888863SEdward.Pilatowicz@Sun.COM cl->cl_blockcount = capacity; 12898863SEdward.Pilatowicz@Sun.COM cl->cl_tgt_blocksize = lbasize; 1290*9889SLarry.Liu@Sun.COM if (!cl->cl_is_removable) { 1291*9889SLarry.Liu@Sun.COM cl->cl_sys_blocksize = lbasize; 1292*9889SLarry.Liu@Sun.COM } 1293786Slclee return (0); 12948863SEdward.Pilatowicz@Sun.COM } else { 12958863SEdward.Pilatowicz@Sun.COM return (EIO); 12968863SEdward.Pilatowicz@Sun.COM } 1297786Slclee } 1298786Slclee 12996318Sedp static int 13006318Sedp cmlb_create_minor(dev_info_t *dip, char *name, int spec_type, 13016318Sedp minor_t minor_num, char *node_type, int flag, boolean_t internal) 13026318Sedp { 13038863SEdward.Pilatowicz@Sun.COM ASSERT(VALID_BOOLEAN(internal)); 13048863SEdward.Pilatowicz@Sun.COM 13056318Sedp if (internal) 13066318Sedp return (ddi_create_internal_pathname(dip, 13076318Sedp name, spec_type, minor_num)); 13086318Sedp else 13096318Sedp return (ddi_create_minor_node(dip, 13106318Sedp name, spec_type, minor_num, node_type, flag)); 13116318Sedp } 13126318Sedp 1313786Slclee /* 1314786Slclee * Function: cmlb_create_minor_nodes 1315786Slclee * 1316786Slclee * Description: Create or adjust the minor device nodes for the instance. 1317786Slclee * Minor nodes are created based on default label type, 1318786Slclee * current label type and last label type we created 1319786Slclee * minor nodes based on. 1320786Slclee * 1321786Slclee * 13223525Sshidokht * Arguments: cl - driver soft state (unit) structure 1323786Slclee * 1324786Slclee * Return Code: 0 success 1325786Slclee * ENXIO failure. 1326786Slclee * 1327786Slclee * Context: Kernel thread context 1328786Slclee */ 1329786Slclee static int 13303525Sshidokht cmlb_create_minor_nodes(struct cmlb_lun *cl) 1331786Slclee { 1332786Slclee struct driver_minor_data *dmdp; 1333786Slclee int instance; 1334786Slclee char name[48]; 1335786Slclee cmlb_label_t newlabeltype; 13366318Sedp boolean_t internal; 1337786Slclee 13383525Sshidokht ASSERT(cl != NULL); 13393525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 1340786Slclee 13418863SEdward.Pilatowicz@Sun.COM internal = VOID2BOOLEAN( 13428863SEdward.Pilatowicz@Sun.COM (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0); 1343786Slclee 1344786Slclee /* check the most common case */ 13453525Sshidokht if (cl->cl_cur_labeltype != CMLB_LABEL_UNDEF && 13463525Sshidokht cl->cl_last_labeltype == cl->cl_cur_labeltype) { 1347786Slclee /* do nothing */ 1348786Slclee return (0); 1349786Slclee } 1350786Slclee 13513525Sshidokht if (cl->cl_def_labeltype == CMLB_LABEL_UNDEF) { 1352786Slclee /* we should never get here */ 1353786Slclee return (ENXIO); 1354786Slclee } 1355786Slclee 13563525Sshidokht if (cl->cl_last_labeltype == CMLB_LABEL_UNDEF) { 1357786Slclee /* first time during attach */ 13583525Sshidokht newlabeltype = cl->cl_def_labeltype; 13593525Sshidokht 13603525Sshidokht instance = ddi_get_instance(CMLB_DEVINFO(cl)); 1361786Slclee 1362786Slclee /* Create all the minor nodes for this target. */ 1363786Slclee dmdp = (newlabeltype == CMLB_LABEL_EFI) ? dk_minor_data_efi : 1364786Slclee dk_minor_data; 1365786Slclee while (dmdp->name != NULL) { 1366786Slclee 1367786Slclee (void) sprintf(name, "%s", dmdp->name); 1368786Slclee 13696318Sedp if (cmlb_create_minor(CMLB_DEVINFO(cl), name, 1370786Slclee dmdp->type, 1371786Slclee (instance << CMLBUNIT_SHIFT) | dmdp->minor, 13726318Sedp cl->cl_node_type, NULL, internal) == DDI_FAILURE) { 1373786Slclee /* 1374786Slclee * Clean up any nodes that may have been 1375786Slclee * created, in case this fails in the middle 1376786Slclee * of the loop. 1377786Slclee */ 13783525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL); 1379786Slclee return (ENXIO); 1380786Slclee } 1381786Slclee dmdp++; 1382786Slclee } 13833525Sshidokht cl->cl_last_labeltype = newlabeltype; 1384786Slclee return (0); 1385786Slclee } 1386786Slclee 1387786Slclee /* Not first time */ 13883525Sshidokht if (cl->cl_cur_labeltype == CMLB_LABEL_UNDEF) { 13893525Sshidokht if (cl->cl_last_labeltype != cl->cl_def_labeltype) { 1390786Slclee /* close time, revert to default. */ 13913525Sshidokht newlabeltype = cl->cl_def_labeltype; 1392786Slclee } else { 1393786Slclee /* 1394786Slclee * do nothing since the type for which we last created 1395786Slclee * nodes matches the default 1396786Slclee */ 1397786Slclee return (0); 1398786Slclee } 1399786Slclee } else { 14003525Sshidokht if (cl->cl_cur_labeltype != cl->cl_last_labeltype) { 1401786Slclee /* We are not closing, use current label type */ 14023525Sshidokht newlabeltype = cl->cl_cur_labeltype; 1403786Slclee } else { 1404786Slclee /* 1405786Slclee * do nothing since the type for which we last created 1406786Slclee * nodes matches the current label type 1407786Slclee */ 1408786Slclee return (0); 1409786Slclee } 1410786Slclee } 1411786Slclee 14123525Sshidokht instance = ddi_get_instance(CMLB_DEVINFO(cl)); 1413786Slclee 1414786Slclee /* 1415786Slclee * Currently we only fix up the s7 node when we are switching 1416786Slclee * label types from or to EFI. This is consistent with 1417786Slclee * current behavior of sd. 1418786Slclee */ 1419786Slclee if (newlabeltype == CMLB_LABEL_EFI && 14203525Sshidokht cl->cl_last_labeltype != CMLB_LABEL_EFI) { 1421786Slclee /* from vtoc to EFI */ 14223525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "h"); 14233525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw"); 14246318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd", 1425786Slclee S_IFBLK, (instance << CMLBUNIT_SHIFT) | WD_NODE, 14266318Sedp cl->cl_node_type, NULL, internal); 14276318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd,raw", 1428786Slclee S_IFCHR, (instance << CMLBUNIT_SHIFT) | WD_NODE, 14296318Sedp cl->cl_node_type, NULL, internal); 1430786Slclee } else { 1431786Slclee /* from efi to vtoc */ 14323525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd"); 14333525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd,raw"); 14346318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h", 1435786Slclee S_IFBLK, (instance << CMLBUNIT_SHIFT) | WD_NODE, 14366318Sedp cl->cl_node_type, NULL, internal); 14376318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h,raw", 1438786Slclee S_IFCHR, (instance << CMLBUNIT_SHIFT) | WD_NODE, 14396318Sedp cl->cl_node_type, NULL, internal); 1440786Slclee } 1441786Slclee 14423525Sshidokht cl->cl_last_labeltype = newlabeltype; 1443786Slclee return (0); 1444786Slclee } 1445786Slclee 1446786Slclee /* 1447786Slclee * Function: cmlb_validate_geometry 1448786Slclee * 1449786Slclee * Description: Read the label from the disk (if present). Update the unit's 1450786Slclee * geometry and vtoc information from the data in the label. 1451786Slclee * Verify that the label is valid. 1452786Slclee * 14533525Sshidokht * Arguments: 14543525Sshidokht * cl driver soft state (unit) structure 14553525Sshidokht * 14563525Sshidokht * forcerevalid force revalidation even if we are already valid. 14573525Sshidokht * flags operation flags from target driver. Used for verbosity 14583525Sshidokht * control at this time. 14593525Sshidokht * tg_cookie cookie from target driver to be passed back to target 14603525Sshidokht * driver when we call back to it through tg_ops. 1461786Slclee * 1462786Slclee * Return Code: 0 - Successful completion 14633525Sshidokht * EINVAL - Invalid value in cl->cl_tgt_blocksize or 14643525Sshidokht * cl->cl_blockcount; or label on disk is corrupted 1465786Slclee * or unreadable. 1466786Slclee * EACCES - Reservation conflict at the device. 1467786Slclee * ENOMEM - Resource allocation error 1468786Slclee * ENOTSUP - geometry not applicable 1469786Slclee * 1470786Slclee * Context: Kernel thread only (can sleep). 1471786Slclee */ 1472786Slclee static int 14738863SEdward.Pilatowicz@Sun.COM cmlb_validate_geometry(struct cmlb_lun *cl, boolean_t forcerevalid, int flags, 14743525Sshidokht void *tg_cookie) 1475786Slclee { 1476786Slclee int label_error = 0; 1477786Slclee diskaddr_t capacity; 1478786Slclee int count; 14793525Sshidokht 14803525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 14818863SEdward.Pilatowicz@Sun.COM ASSERT(VALID_BOOLEAN(forcerevalid)); 14828863SEdward.Pilatowicz@Sun.COM 14838863SEdward.Pilatowicz@Sun.COM if ((cl->cl_f_geometry_is_valid) && (!forcerevalid)) { 14843525Sshidokht if (cl->cl_cur_labeltype == CMLB_LABEL_EFI) 1485786Slclee return (ENOTSUP); 1486786Slclee return (0); 1487786Slclee } 1488786Slclee 14893525Sshidokht if (cmlb_check_update_blockcount(cl, tg_cookie) != 0) 1490786Slclee return (EIO); 1491786Slclee 14923525Sshidokht capacity = cl->cl_blockcount; 1493786Slclee 1494786Slclee #if defined(_SUNOS_VTOC_16) 1495786Slclee /* 1496786Slclee * Set up the "whole disk" fdisk partition; this should always 1497786Slclee * exist, regardless of whether the disk contains an fdisk table 1498786Slclee * or vtoc. 1499786Slclee */ 15003525Sshidokht cl->cl_map[P0_RAW_DISK].dkl_cylno = 0; 15017563SPrasad.Singamsetty@Sun.COM cl->cl_offset[P0_RAW_DISK] = 0; 1502786Slclee /* 15037563SPrasad.Singamsetty@Sun.COM * note if capacity > int32_max(1TB) we are in 64bit environment 15047563SPrasad.Singamsetty@Sun.COM * so no truncation happens 1505786Slclee */ 15063525Sshidokht cl->cl_map[P0_RAW_DISK].dkl_nblk = capacity; 1507786Slclee #endif 1508786Slclee /* 1509786Slclee * Refresh the logical and physical geometry caches. 1510786Slclee * (data from MODE SENSE format/rigid disk geometry pages, 1511786Slclee * and scsi_ifgetcap("geometry"). 1512786Slclee */ 15133525Sshidokht cmlb_resync_geom_caches(cl, capacity, tg_cookie); 15143525Sshidokht 15157563SPrasad.Singamsetty@Sun.COM cl->cl_label_from_media = CMLB_LABEL_UNDEF; 15163525Sshidokht label_error = cmlb_use_efi(cl, capacity, flags, tg_cookie); 1517786Slclee if (label_error == 0) { 1518786Slclee 1519786Slclee /* found a valid EFI label */ 15203525Sshidokht cmlb_dbg(CMLB_TRACE, cl, 1521786Slclee "cmlb_validate_geometry: found EFI label\n"); 1522786Slclee /* 1523786Slclee * solaris_size and geometry_is_valid are set in 1524786Slclee * cmlb_use_efi 1525786Slclee */ 1526786Slclee return (ENOTSUP); 1527786Slclee } 1528786Slclee 1529786Slclee /* NO EFI label found */ 1530786Slclee 15317563SPrasad.Singamsetty@Sun.COM if (capacity > CMLB_EXTVTOC_LIMIT) { 1532786Slclee if (label_error == ESRCH) { 1533786Slclee /* 15347563SPrasad.Singamsetty@Sun.COM * they've configured a LUN over 2TB, but used 1535786Slclee * format.dat to restrict format's view of the 15367563SPrasad.Singamsetty@Sun.COM * capacity to be under 2TB in some earlier Solaris 15377563SPrasad.Singamsetty@Sun.COM * release. 1538786Slclee */ 15397563SPrasad.Singamsetty@Sun.COM /* i.e > 2TB with a VTOC < 2TB */ 15407563SPrasad.Singamsetty@Sun.COM if (!(flags & CMLB_SILENT) && 15417563SPrasad.Singamsetty@Sun.COM (cl->cl_msglog_flag & CMLB_ALLOW_2TB_WARN)) { 15423525Sshidokht 15433525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), 15447563SPrasad.Singamsetty@Sun.COM CE_NOTE, "!Disk (%s%d) is limited to 2 TB " 15457563SPrasad.Singamsetty@Sun.COM "due to VTOC label. To use the full " 15467563SPrasad.Singamsetty@Sun.COM "capacity of the disk, use format(1M) to " 15477563SPrasad.Singamsetty@Sun.COM "relabel the disk with EFI/GPT label.\n", 15487563SPrasad.Singamsetty@Sun.COM CMLB_LABEL(cl), 15497563SPrasad.Singamsetty@Sun.COM ddi_get_instance(CMLB_DEVINFO(cl))); 15507563SPrasad.Singamsetty@Sun.COM 15517563SPrasad.Singamsetty@Sun.COM cl->cl_msglog_flag &= ~CMLB_ALLOW_2TB_WARN; 15523525Sshidokht } 1553786Slclee } else { 15543525Sshidokht return (ENOTSUP); 1555786Slclee } 1556786Slclee } 1557786Slclee 1558786Slclee label_error = 0; 1559786Slclee 1560786Slclee /* 1561786Slclee * at this point it is either labeled with a VTOC or it is 15623525Sshidokht * under 1TB (<= 1TB actually for off-by-1) 1563786Slclee */ 1564786Slclee 1565786Slclee /* 15663525Sshidokht * Only DIRECT ACCESS devices will have Scl labels. 15673525Sshidokht * CD's supposedly have a Scl label, too 1568786Slclee */ 15693525Sshidokht if (cl->cl_device_type == DTYPE_DIRECT || ISREMOVABLE(cl)) { 1570786Slclee struct dk_label *dkl; 1571786Slclee offset_t label_addr; 1572786Slclee int rval; 1573786Slclee size_t buffer_size; 1574786Slclee 1575786Slclee /* 15763525Sshidokht * Note: This will set up cl->cl_solaris_size and 15773525Sshidokht * cl->cl_solaris_offset. 1578786Slclee */ 15793525Sshidokht rval = cmlb_read_fdisk(cl, capacity, tg_cookie); 15803525Sshidokht if ((rval != 0) && !ISCD(cl)) { 15813525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 1582786Slclee return (rval); 1583786Slclee } 1584786Slclee 15853525Sshidokht if (cl->cl_solaris_size <= DK_LABEL_LOC) { 1586786Slclee /* 1587786Slclee * Found fdisk table but no Solaris partition entry, 1588786Slclee * so don't call cmlb_uselabel() and don't create 1589786Slclee * a default label. 1590786Slclee */ 1591786Slclee label_error = 0; 15928863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_TRUE; 1593786Slclee goto no_solaris_partition; 1594786Slclee } 1595786Slclee 15963525Sshidokht label_addr = (daddr_t)(cl->cl_solaris_offset + DK_LABEL_LOC); 15973525Sshidokht 1598*9889SLarry.Liu@Sun.COM buffer_size = cl->cl_sys_blocksize; 1599786Slclee 16003525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "cmlb_validate_geometry: " 1601786Slclee "label_addr: 0x%x allocation size: 0x%x\n", 1602786Slclee label_addr, buffer_size); 1603786Slclee 1604786Slclee if ((dkl = kmem_zalloc(buffer_size, KM_NOSLEEP)) == NULL) 1605786Slclee return (ENOMEM); 1606786Slclee 16073525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 16083525Sshidokht rval = DK_TG_READ(cl, dkl, label_addr, buffer_size, tg_cookie); 16093525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 1610786Slclee 1611786Slclee switch (rval) { 1612786Slclee case 0: 1613786Slclee /* 1614786Slclee * cmlb_uselabel will establish that the geometry 1615786Slclee * is valid. 1616786Slclee */ 16173525Sshidokht if (cmlb_uselabel(cl, 16183525Sshidokht (struct dk_label *)(uintptr_t)dkl, flags) != 1619786Slclee CMLB_LABEL_IS_VALID) { 1620786Slclee label_error = EINVAL; 1621786Slclee } else 16227563SPrasad.Singamsetty@Sun.COM cl->cl_label_from_media = CMLB_LABEL_VTOC; 1623786Slclee break; 1624786Slclee case EACCES: 1625786Slclee label_error = EACCES; 1626786Slclee break; 1627786Slclee default: 1628786Slclee label_error = EINVAL; 1629786Slclee break; 1630786Slclee } 1631786Slclee 1632786Slclee kmem_free(dkl, buffer_size); 1633786Slclee } 1634786Slclee 1635786Slclee /* 1636786Slclee * If a valid label was not found, AND if no reservation conflict 1637786Slclee * was detected, then go ahead and create a default label (4069506). 1638786Slclee * 1639786Slclee * Note: currently, for VTOC_8 devices, the default label is created 16403525Sshidokht * for removables and hotpluggables only. For VTOC_16 devices, the 16413525Sshidokht * default label will be created for all devices. 1642786Slclee * (see cmlb_build_default_label) 1643786Slclee */ 1644786Slclee #if defined(_SUNOS_VTOC_8) 16453525Sshidokht if ((ISREMOVABLE(cl) || ISHOTPLUGGABLE(cl)) && 16463525Sshidokht (label_error != EACCES)) { 1647786Slclee #elif defined(_SUNOS_VTOC_16) 1648786Slclee if (label_error != EACCES) { 1649786Slclee #endif 16508863SEdward.Pilatowicz@Sun.COM if (!cl->cl_f_geometry_is_valid) { 16513525Sshidokht cmlb_build_default_label(cl, tg_cookie); 1652786Slclee } 1653786Slclee label_error = 0; 1654786Slclee } 1655786Slclee 1656786Slclee no_solaris_partition: 1657786Slclee 1658786Slclee #if defined(_SUNOS_VTOC_16) 1659786Slclee /* 1660786Slclee * If we have valid geometry, set up the remaining fdisk partitions. 1661786Slclee * Note that dkl_cylno is not used for the fdisk map entries, so 1662786Slclee * we set it to an entirely bogus value. 1663786Slclee */ 16648333SSuhasini.Peddada@Sun.COM for (count = 0; count < FD_NUMPART; count++) { 16657563SPrasad.Singamsetty@Sun.COM cl->cl_map[FDISK_P1 + count].dkl_cylno = UINT16_MAX; 16663525Sshidokht cl->cl_map[FDISK_P1 + count].dkl_nblk = 16673525Sshidokht cl->cl_fmap[count].fmap_nblk; 16683525Sshidokht 16693525Sshidokht cl->cl_offset[FDISK_P1 + count] = 16703525Sshidokht cl->cl_fmap[count].fmap_start; 1671786Slclee } 1672786Slclee #endif 1673786Slclee 1674786Slclee for (count = 0; count < NDKMAP; count++) { 1675786Slclee #if defined(_SUNOS_VTOC_8) 16763525Sshidokht struct dk_map *lp = &cl->cl_map[count]; 16773525Sshidokht cl->cl_offset[count] = 16783525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno; 1679786Slclee #elif defined(_SUNOS_VTOC_16) 16803525Sshidokht struct dkl_partition *vp = &cl->cl_vtoc.v_part[count]; 16813525Sshidokht 16823525Sshidokht cl->cl_offset[count] = vp->p_start + cl->cl_solaris_offset; 1683786Slclee #else 1684786Slclee #error "No VTOC format defined." 1685786Slclee #endif 1686786Slclee } 1687786Slclee 1688786Slclee return (label_error); 1689786Slclee } 1690786Slclee 1691786Slclee #if defined(_SUNOS_VTOC_16) 1692786Slclee /* 1693786Slclee * Function: cmlb_convert_geometry 1694786Slclee * 1695786Slclee * Description: Convert physical geometry into a dk_geom structure. In 1696786Slclee * other words, make sure we don't wrap 16-bit values. 1697786Slclee * e.g. converting from geom_cache to dk_geom 1698786Slclee * 1699786Slclee * Context: Kernel thread only 1700786Slclee */ 1701786Slclee static void 17023525Sshidokht cmlb_convert_geometry(diskaddr_t capacity, struct dk_geom *cl_g) 1703786Slclee { 1704786Slclee 1705786Slclee /* Unlabeled SCSI floppy device */ 1706786Slclee if (capacity <= 0x1000) { 17073525Sshidokht cl_g->dkg_nhead = 2; 17083525Sshidokht cl_g->dkg_ncyl = 80; 17093525Sshidokht cl_g->dkg_nsect = capacity / (cl_g->dkg_nhead * cl_g->dkg_ncyl); 1710786Slclee return; 1711786Slclee } 1712786Slclee 1713786Slclee /* 17147563SPrasad.Singamsetty@Sun.COM * For all devices we calculate cylinders using the heads and sectors 17157563SPrasad.Singamsetty@Sun.COM * we assign based on capacity of the device. The algorithm is 17167563SPrasad.Singamsetty@Sun.COM * designed to be compatible with the way other operating systems 17177563SPrasad.Singamsetty@Sun.COM * lay out fdisk tables for X86 and to insure that the cylinders never 17187563SPrasad.Singamsetty@Sun.COM * exceed 65535 to prevent problems with X86 ioctls that report 17197563SPrasad.Singamsetty@Sun.COM * geometry. 17207563SPrasad.Singamsetty@Sun.COM * For some smaller disk sizes we report geometry that matches those 17217563SPrasad.Singamsetty@Sun.COM * used by X86 BIOS usage. For larger disks, we use SPT that are 17227563SPrasad.Singamsetty@Sun.COM * multiples of 63, since other OSes that are not limited to 16-bits 17237563SPrasad.Singamsetty@Sun.COM * for cylinders stop at 63 SPT we make do by using multiples of 63 SPT. 17247563SPrasad.Singamsetty@Sun.COM * 17257563SPrasad.Singamsetty@Sun.COM * The following table (in order) illustrates some end result 17267563SPrasad.Singamsetty@Sun.COM * calculations: 17277563SPrasad.Singamsetty@Sun.COM * 17287563SPrasad.Singamsetty@Sun.COM * Maximum number of blocks nhead nsect 1729786Slclee * 17307563SPrasad.Singamsetty@Sun.COM * 2097152 (1GB) 64 32 17317563SPrasad.Singamsetty@Sun.COM * 16777216 (8GB) 128 32 17327563SPrasad.Singamsetty@Sun.COM * 1052819775 (502.02GB) 255 63 17337563SPrasad.Singamsetty@Sun.COM * 2105639550 (0.98TB) 255 126 17347563SPrasad.Singamsetty@Sun.COM * 3158459325 (1.47TB) 255 189 17357563SPrasad.Singamsetty@Sun.COM * 4211279100 (1.96TB) 255 252 17367563SPrasad.Singamsetty@Sun.COM * 5264098875 (2.45TB) 255 315 17377563SPrasad.Singamsetty@Sun.COM * ... 1738786Slclee */ 17397563SPrasad.Singamsetty@Sun.COM 17407563SPrasad.Singamsetty@Sun.COM if (capacity <= 0x200000) { 17417563SPrasad.Singamsetty@Sun.COM cl_g->dkg_nhead = 64; 17427563SPrasad.Singamsetty@Sun.COM cl_g->dkg_nsect = 32; 17437563SPrasad.Singamsetty@Sun.COM } else if (capacity <= 0x01000000) { 17447563SPrasad.Singamsetty@Sun.COM cl_g->dkg_nhead = 128; 17457563SPrasad.Singamsetty@Sun.COM cl_g->dkg_nsect = 32; 17467563SPrasad.Singamsetty@Sun.COM } else { 17477563SPrasad.Singamsetty@Sun.COM cl_g->dkg_nhead = 255; 17487563SPrasad.Singamsetty@Sun.COM 17497563SPrasad.Singamsetty@Sun.COM /* make nsect be smallest multiple of 63 */ 17507563SPrasad.Singamsetty@Sun.COM cl_g->dkg_nsect = ((capacity + 17517563SPrasad.Singamsetty@Sun.COM (UINT16_MAX * 255 * 63) - 1) / 17527563SPrasad.Singamsetty@Sun.COM (UINT16_MAX * 255 * 63)) * 63; 17537563SPrasad.Singamsetty@Sun.COM 17547563SPrasad.Singamsetty@Sun.COM if (cl_g->dkg_nsect == 0) 17557563SPrasad.Singamsetty@Sun.COM cl_g->dkg_nsect = (UINT16_MAX / 63) * 63; 17567563SPrasad.Singamsetty@Sun.COM } 17577563SPrasad.Singamsetty@Sun.COM 1758786Slclee } 1759786Slclee #endif 1760786Slclee 1761786Slclee /* 1762786Slclee * Function: cmlb_resync_geom_caches 1763786Slclee * 1764786Slclee * Description: (Re)initialize both geometry caches: the virtual geometry 1765786Slclee * information is extracted from the HBA (the "geometry" 1766786Slclee * capability), and the physical geometry cache data is 1767786Slclee * generated by issuing MODE SENSE commands. 1768786Slclee * 17693525Sshidokht * Arguments: 17703525Sshidokht * cl driver soft state (unit) structure 17713525Sshidokht * capacity disk capacity in #blocks 17723525Sshidokht * tg_cookie cookie from target driver to be passed back to target 17733525Sshidokht * driver when we call back to it through tg_ops. 1774786Slclee * 1775786Slclee * Context: Kernel thread only (can sleep). 1776786Slclee */ 1777786Slclee static void 17783525Sshidokht cmlb_resync_geom_caches(struct cmlb_lun *cl, diskaddr_t capacity, 17793525Sshidokht void *tg_cookie) 1780786Slclee { 1781786Slclee struct cmlb_geom pgeom; 1782786Slclee struct cmlb_geom lgeom; 1783786Slclee struct cmlb_geom *pgeomp = &pgeom; 1784786Slclee unsigned short nhead; 1785786Slclee unsigned short nsect; 1786786Slclee int spc; 1787786Slclee int ret; 1788786Slclee 17893525Sshidokht ASSERT(cl != NULL); 17903525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 1791786Slclee 1792786Slclee /* 1793786Slclee * Ask the controller for its logical geometry. 1794786Slclee * Note: if the HBA does not support scsi_ifgetcap("geometry"), 1795786Slclee * then the lgeom cache will be invalid. 1796786Slclee */ 17973525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 1798786Slclee bzero(&lgeom, sizeof (struct cmlb_geom)); 17993525Sshidokht ret = DK_TG_GETVIRTGEOM(cl, &lgeom, tg_cookie); 18003525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 18013525Sshidokht 18023525Sshidokht bcopy(&lgeom, &cl->cl_lgeom, sizeof (cl->cl_lgeom)); 1803786Slclee 1804786Slclee /* 1805786Slclee * Initialize the pgeom cache from lgeom, so that if MODE SENSE 1806786Slclee * doesn't work, DKIOCG_PHYSGEOM can return reasonable values. 1807786Slclee */ 18083525Sshidokht if (ret != 0 || cl->cl_lgeom.g_nsect == 0 || 18093525Sshidokht cl->cl_lgeom.g_nhead == 0) { 1810786Slclee /* 1811786Slclee * Note: Perhaps this needs to be more adaptive? The rationale 1812786Slclee * is that, if there's no HBA geometry from the HBA driver, any 1813786Slclee * guess is good, since this is the physical geometry. If MODE 1814786Slclee * SENSE fails this gives a max cylinder size for non-LBA access 1815786Slclee */ 1816786Slclee nhead = 255; 1817786Slclee nsect = 63; 1818786Slclee } else { 18193525Sshidokht nhead = cl->cl_lgeom.g_nhead; 18203525Sshidokht nsect = cl->cl_lgeom.g_nsect; 1821786Slclee } 1822786Slclee 18233525Sshidokht if (ISCD(cl)) { 1824786Slclee pgeomp->g_nhead = 1; 1825786Slclee pgeomp->g_nsect = nsect * nhead; 1826786Slclee } else { 1827786Slclee pgeomp->g_nhead = nhead; 1828786Slclee pgeomp->g_nsect = nsect; 1829786Slclee } 1830786Slclee 1831786Slclee spc = pgeomp->g_nhead * pgeomp->g_nsect; 1832786Slclee pgeomp->g_capacity = capacity; 18339811SSheshadri.Vasudevan@Sun.COM if (spc == 0) 18349811SSheshadri.Vasudevan@Sun.COM pgeomp->g_ncyl = 0; 18359811SSheshadri.Vasudevan@Sun.COM else 18369811SSheshadri.Vasudevan@Sun.COM pgeomp->g_ncyl = pgeomp->g_capacity / spc; 1837786Slclee pgeomp->g_acyl = 0; 1838786Slclee 1839786Slclee /* 1840786Slclee * Retrieve fresh geometry data from the hardware, stash it 1841786Slclee * here temporarily before we rebuild the incore label. 1842786Slclee * 1843786Slclee * We want to use the MODE SENSE commands to derive the 1844786Slclee * physical geometry of the device, but if either command 1845786Slclee * fails, the logical geometry is used as the fallback for 1846786Slclee * disk label geometry. 1847786Slclee */ 1848786Slclee 18493525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 18503525Sshidokht (void) DK_TG_GETPHYGEOM(cl, pgeomp, tg_cookie); 18513525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 1852786Slclee 1853786Slclee /* 1854786Slclee * Now update the real copy while holding the mutex. This 1855786Slclee * way the global copy is never in an inconsistent state. 1856786Slclee */ 18573525Sshidokht bcopy(pgeomp, &cl->cl_pgeom, sizeof (cl->cl_pgeom)); 18583525Sshidokht 18593525Sshidokht cmlb_dbg(CMLB_INFO, cl, "cmlb_resync_geom_caches: " 1860786Slclee "(cached from lgeom)\n"); 18613525Sshidokht cmlb_dbg(CMLB_INFO, cl, 1862786Slclee " ncyl: %ld; acyl: %d; nhead: %d; nsect: %d\n", 18633525Sshidokht cl->cl_pgeom.g_ncyl, cl->cl_pgeom.g_acyl, 18643525Sshidokht cl->cl_pgeom.g_nhead, cl->cl_pgeom.g_nsect); 18653525Sshidokht cmlb_dbg(CMLB_INFO, cl, " lbasize: %d; capacity: %ld; " 18663525Sshidokht "intrlv: %d; rpm: %d\n", cl->cl_pgeom.g_secsize, 18673525Sshidokht cl->cl_pgeom.g_capacity, cl->cl_pgeom.g_intrlv, 18683525Sshidokht cl->cl_pgeom.g_rpm); 1869786Slclee } 1870786Slclee 1871786Slclee 1872786Slclee /* 1873786Slclee * Function: cmlb_read_fdisk 1874786Slclee * 1875786Slclee * Description: utility routine to read the fdisk table. 1876786Slclee * 18773525Sshidokht * Arguments: 18783525Sshidokht * cl driver soft state (unit) structure 18793525Sshidokht * capacity disk capacity in #blocks 18803525Sshidokht * tg_cookie cookie from target driver to be passed back to target 18813525Sshidokht * driver when we call back to it through tg_ops. 1882786Slclee * 1883786Slclee * Return Code: 0 for success (includes not reading for no_fdisk_present case 1884786Slclee * errnos from tg_rw if failed to read the first block. 1885786Slclee * 1886786Slclee * Context: Kernel thread only (can sleep). 1887786Slclee */ 18883525Sshidokht /*ARGSUSED*/ 1889786Slclee static int 18903525Sshidokht cmlb_read_fdisk(struct cmlb_lun *cl, diskaddr_t capacity, void *tg_cookie) 1891786Slclee { 1892786Slclee #if defined(_NO_FDISK_PRESENT) 1893786Slclee 18943525Sshidokht cl->cl_solaris_offset = 0; 18953525Sshidokht cl->cl_solaris_size = capacity; 18963525Sshidokht bzero(cl->cl_fmap, sizeof (struct fmap) * FD_NUMPART); 1897786Slclee return (0); 1898786Slclee 1899786Slclee #elif defined(_FIRMWARE_NEEDS_FDISK) 1900786Slclee 1901786Slclee struct ipart *fdp; 1902786Slclee struct mboot *mbp; 1903786Slclee struct ipart fdisk[FD_NUMPART]; 19048333SSuhasini.Peddada@Sun.COM int i; 1905786Slclee char sigbuf[2]; 1906786Slclee caddr_t bufp; 1907786Slclee int uidx; 1908786Slclee int rval; 1909786Slclee int lba = 0; 1910786Slclee uint_t solaris_offset; /* offset to solaris part. */ 1911786Slclee daddr_t solaris_size; /* size of solaris partition */ 1912786Slclee uint32_t blocksize; 1913786Slclee 19143525Sshidokht ASSERT(cl != NULL); 19153525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 1916786Slclee 1917786Slclee /* 1918786Slclee * Start off assuming no fdisk table 1919786Slclee */ 1920786Slclee solaris_offset = 0; 1921786Slclee solaris_size = capacity; 1922786Slclee 19233525Sshidokht blocksize = cl->cl_tgt_blocksize; 1924786Slclee 1925786Slclee bufp = kmem_zalloc(blocksize, KM_SLEEP); 1926786Slclee 19273525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 19283525Sshidokht rval = DK_TG_READ(cl, bufp, 0, blocksize, tg_cookie); 19293525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 1930786Slclee 1931786Slclee if (rval != 0) { 19323525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 1933786Slclee "cmlb_read_fdisk: fdisk read err\n"); 19343525Sshidokht bzero(cl->cl_fmap, sizeof (struct fmap) * FD_NUMPART); 19353525Sshidokht goto done; 1936786Slclee } 1937786Slclee 1938786Slclee mbp = (struct mboot *)bufp; 1939786Slclee 1940786Slclee /* 1941786Slclee * The fdisk table does not begin on a 4-byte boundary within the 1942786Slclee * master boot record, so we copy it to an aligned structure to avoid 1943786Slclee * alignment exceptions on some processors. 1944786Slclee */ 1945786Slclee bcopy(&mbp->parts[0], fdisk, sizeof (fdisk)); 1946786Slclee 1947786Slclee /* 1948786Slclee * Check for lba support before verifying sig; sig might not be 1949786Slclee * there, say on a blank disk, but the max_chs mark may still 1950786Slclee * be present. 1951786Slclee * 1952786Slclee * Note: LBA support and BEFs are an x86-only concept but this 1953786Slclee * code should work OK on SPARC as well. 1954786Slclee */ 1955786Slclee 1956786Slclee /* 1957786Slclee * First, check for lba-access-ok on root node (or prom root node) 1958786Slclee * if present there, don't need to search fdisk table. 1959786Slclee */ 1960786Slclee if (ddi_getprop(DDI_DEV_T_ANY, ddi_root_node(), 0, 1961786Slclee "lba-access-ok", 0) != 0) { 1962786Slclee /* All drives do LBA; don't search fdisk table */ 1963786Slclee lba = 1; 1964786Slclee } else { 1965786Slclee /* Okay, look for mark in fdisk table */ 1966786Slclee for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) { 1967786Slclee /* accumulate "lba" value from all partitions */ 1968786Slclee lba = (lba || cmlb_has_max_chs_vals(fdp)); 1969786Slclee } 1970786Slclee } 1971786Slclee 1972786Slclee if (lba != 0) { 19733525Sshidokht dev_t dev = cmlb_make_device(cl); 19743525Sshidokht 19753525Sshidokht if (ddi_getprop(dev, CMLB_DEVINFO(cl), DDI_PROP_DONTPASS, 1976786Slclee "lba-access-ok", 0) == 0) { 1977786Slclee /* not found; create it */ 19783525Sshidokht if (ddi_prop_create(dev, CMLB_DEVINFO(cl), 0, 1979786Slclee "lba-access-ok", (caddr_t)NULL, 0) != 1980786Slclee DDI_PROP_SUCCESS) { 19813525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 1982786Slclee "cmlb_read_fdisk: Can't create lba " 1983786Slclee "property for instance %d\n", 19843525Sshidokht ddi_get_instance(CMLB_DEVINFO(cl))); 1985786Slclee } 1986786Slclee } 1987786Slclee } 1988786Slclee 1989786Slclee bcopy(&mbp->signature, sigbuf, sizeof (sigbuf)); 1990786Slclee 1991786Slclee /* 1992786Slclee * Endian-independent signature check 1993786Slclee */ 1994786Slclee if (((sigbuf[1] & 0xFF) != ((MBB_MAGIC >> 8) & 0xFF)) || 1995786Slclee (sigbuf[0] != (MBB_MAGIC & 0xFF))) { 19963525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 1997786Slclee "cmlb_read_fdisk: no fdisk\n"); 19983525Sshidokht bzero(cl->cl_fmap, sizeof (struct fmap) * FD_NUMPART); 1999786Slclee goto done; 2000786Slclee } 2001786Slclee 2002786Slclee #ifdef CMLBDEBUG 20033525Sshidokht if (cmlb_level_mask & CMLB_LOGMASK_INFO) { 2004786Slclee fdp = fdisk; 20053525Sshidokht cmlb_dbg(CMLB_INFO, cl, "cmlb_read_fdisk:\n"); 20063525Sshidokht cmlb_dbg(CMLB_INFO, cl, " relsect " 2007786Slclee "numsect sysid bootid\n"); 2008786Slclee for (i = 0; i < FD_NUMPART; i++, fdp++) { 20093525Sshidokht cmlb_dbg(CMLB_INFO, cl, 2010786Slclee " %d: %8d %8d 0x%08x 0x%08x\n", 2011786Slclee i, fdp->relsect, fdp->numsect, 2012786Slclee fdp->systid, fdp->bootid); 2013786Slclee } 2014786Slclee } 2015786Slclee #endif 2016786Slclee 2017786Slclee /* 2018786Slclee * Try to find the unix partition 2019786Slclee */ 2020786Slclee uidx = -1; 2021786Slclee solaris_offset = 0; 2022786Slclee solaris_size = 0; 2023786Slclee 2024786Slclee for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) { 20257563SPrasad.Singamsetty@Sun.COM uint32_t relsect; 20267563SPrasad.Singamsetty@Sun.COM uint32_t numsect; 2027786Slclee 2028786Slclee if (fdp->numsect == 0) { 20293525Sshidokht cl->cl_fmap[i].fmap_start = 0; 20303525Sshidokht cl->cl_fmap[i].fmap_nblk = 0; 2031786Slclee continue; 2032786Slclee } 2033786Slclee 2034786Slclee /* 2035786Slclee * Data in the fdisk table is little-endian. 2036786Slclee */ 2037786Slclee relsect = LE_32(fdp->relsect); 2038786Slclee numsect = LE_32(fdp->numsect); 2039786Slclee 20403525Sshidokht cl->cl_fmap[i].fmap_start = relsect; 20413525Sshidokht cl->cl_fmap[i].fmap_nblk = numsect; 2042786Slclee 2043786Slclee if (fdp->systid != SUNIXOS && 2044786Slclee fdp->systid != SUNIXOS2 && 2045786Slclee fdp->systid != EFI_PMBR) { 2046786Slclee continue; 2047786Slclee } 2048786Slclee 2049786Slclee /* 2050786Slclee * use the last active solaris partition id found 2051786Slclee * (there should only be 1 active partition id) 2052786Slclee * 2053786Slclee * if there are no active solaris partition id 2054786Slclee * then use the first inactive solaris partition id 2055786Slclee */ 2056786Slclee if ((uidx == -1) || (fdp->bootid == ACTIVE)) { 20578333SSuhasini.Peddada@Sun.COM uidx = i; 20588333SSuhasini.Peddada@Sun.COM solaris_offset = relsect; 20598333SSuhasini.Peddada@Sun.COM solaris_size = numsect; 2060786Slclee } 2061786Slclee } 20628333SSuhasini.Peddada@Sun.COM 20633525Sshidokht cmlb_dbg(CMLB_INFO, cl, "fdisk 0x%x 0x%lx", 20643525Sshidokht cl->cl_solaris_offset, cl->cl_solaris_size); 2065786Slclee done: 2066786Slclee 2067786Slclee /* 2068786Slclee * Clear the VTOC info, only if the Solaris partition entry 2069786Slclee * has moved, changed size, been deleted, or if the size of 2070786Slclee * the partition is too small to even fit the label sector. 2071786Slclee */ 20723525Sshidokht if ((cl->cl_solaris_offset != solaris_offset) || 20733525Sshidokht (cl->cl_solaris_size != solaris_size) || 2074786Slclee solaris_size <= DK_LABEL_LOC) { 20753525Sshidokht cmlb_dbg(CMLB_INFO, cl, "fdisk moved 0x%x 0x%lx", 20763525Sshidokht solaris_offset, solaris_size); 20773525Sshidokht bzero(&cl->cl_g, sizeof (struct dk_geom)); 20783525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc)); 20793525Sshidokht bzero(&cl->cl_map, NDKMAP * (sizeof (struct dk_map))); 20808863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE; 2081786Slclee } 20823525Sshidokht cl->cl_solaris_offset = solaris_offset; 20833525Sshidokht cl->cl_solaris_size = solaris_size; 2084786Slclee kmem_free(bufp, blocksize); 2085786Slclee return (rval); 2086786Slclee 2087786Slclee #else /* #elif defined(_FIRMWARE_NEEDS_FDISK) */ 2088786Slclee #error "fdisk table presence undetermined for this platform." 2089786Slclee #endif /* #if defined(_NO_FDISK_PRESENT) */ 2090786Slclee } 2091786Slclee 2092786Slclee static void 2093786Slclee cmlb_swap_efi_gpt(efi_gpt_t *e) 2094786Slclee { 2095786Slclee _NOTE(ASSUMING_PROTECTED(*e)) 2096786Slclee e->efi_gpt_Signature = LE_64(e->efi_gpt_Signature); 2097786Slclee e->efi_gpt_Revision = LE_32(e->efi_gpt_Revision); 2098786Slclee e->efi_gpt_HeaderSize = LE_32(e->efi_gpt_HeaderSize); 2099786Slclee e->efi_gpt_HeaderCRC32 = LE_32(e->efi_gpt_HeaderCRC32); 2100786Slclee e->efi_gpt_MyLBA = LE_64(e->efi_gpt_MyLBA); 2101786Slclee e->efi_gpt_AlternateLBA = LE_64(e->efi_gpt_AlternateLBA); 2102786Slclee e->efi_gpt_FirstUsableLBA = LE_64(e->efi_gpt_FirstUsableLBA); 2103786Slclee e->efi_gpt_LastUsableLBA = LE_64(e->efi_gpt_LastUsableLBA); 2104786Slclee UUID_LE_CONVERT(e->efi_gpt_DiskGUID, e->efi_gpt_DiskGUID); 2105786Slclee e->efi_gpt_PartitionEntryLBA = LE_64(e->efi_gpt_PartitionEntryLBA); 2106786Slclee e->efi_gpt_NumberOfPartitionEntries = 2107786Slclee LE_32(e->efi_gpt_NumberOfPartitionEntries); 2108786Slclee e->efi_gpt_SizeOfPartitionEntry = 2109786Slclee LE_32(e->efi_gpt_SizeOfPartitionEntry); 2110786Slclee e->efi_gpt_PartitionEntryArrayCRC32 = 2111786Slclee LE_32(e->efi_gpt_PartitionEntryArrayCRC32); 2112786Slclee } 2113786Slclee 2114786Slclee static void 2115786Slclee cmlb_swap_efi_gpe(int nparts, efi_gpe_t *p) 2116786Slclee { 2117786Slclee int i; 2118786Slclee 2119786Slclee _NOTE(ASSUMING_PROTECTED(*p)) 2120786Slclee for (i = 0; i < nparts; i++) { 2121786Slclee UUID_LE_CONVERT(p[i].efi_gpe_PartitionTypeGUID, 2122786Slclee p[i].efi_gpe_PartitionTypeGUID); 2123786Slclee p[i].efi_gpe_StartingLBA = LE_64(p[i].efi_gpe_StartingLBA); 2124786Slclee p[i].efi_gpe_EndingLBA = LE_64(p[i].efi_gpe_EndingLBA); 2125786Slclee /* PartitionAttrs */ 2126786Slclee } 2127786Slclee } 2128786Slclee 2129786Slclee static int 2130786Slclee cmlb_validate_efi(efi_gpt_t *labp) 2131786Slclee { 2132786Slclee if (labp->efi_gpt_Signature != EFI_SIGNATURE) 2133786Slclee return (EINVAL); 2134786Slclee /* at least 96 bytes in this version of the spec. */ 2135786Slclee if (sizeof (efi_gpt_t) - sizeof (labp->efi_gpt_Reserved2) > 2136786Slclee labp->efi_gpt_HeaderSize) 2137786Slclee return (EINVAL); 2138786Slclee /* this should be 128 bytes */ 2139786Slclee if (labp->efi_gpt_SizeOfPartitionEntry != sizeof (efi_gpe_t)) 2140786Slclee return (EINVAL); 2141786Slclee return (0); 2142786Slclee } 2143786Slclee 21445624Sshidokht /* 21458863SEdward.Pilatowicz@Sun.COM * This function returns B_FALSE if there is a valid MBR signature and no 21468863SEdward.Pilatowicz@Sun.COM * partition table entries of type EFI_PMBR (0xEE). Otherwise it returns B_TRUE. 21475624Sshidokht * 21485624Sshidokht * The EFI spec (1.10 and later) requires having a Protective MBR (PMBR) to 21495624Sshidokht * recognize the disk as GPT partitioned. However, some other OS creates an MBR 21505624Sshidokht * where a PMBR entry is not the only one. Also, if the first block has been 21515624Sshidokht * corrupted, currently best attempt to allow data access would be to try to 21525624Sshidokht * check for GPT headers. Hence in case of more than one partition entry, but 21535624Sshidokht * at least one EFI_PMBR partition type or no valid magic number, the function 21548863SEdward.Pilatowicz@Sun.COM * returns B_TRUE to continue with looking for GPT header. 21555624Sshidokht */ 21565624Sshidokht 21578863SEdward.Pilatowicz@Sun.COM static boolean_t 21588863SEdward.Pilatowicz@Sun.COM cmlb_check_efi_mbr(uchar_t *buf, boolean_t *is_mbr) 21595624Sshidokht { 21605624Sshidokht struct ipart *fdp; 21615624Sshidokht struct mboot *mbp = (struct mboot *)buf; 21625624Sshidokht struct ipart fdisk[FD_NUMPART]; 21635624Sshidokht int i; 21645624Sshidokht 21657563SPrasad.Singamsetty@Sun.COM if (is_mbr != NULL) 21668863SEdward.Pilatowicz@Sun.COM *is_mbr = B_TRUE; 21677563SPrasad.Singamsetty@Sun.COM 21687563SPrasad.Singamsetty@Sun.COM if (LE_16(mbp->signature) != MBB_MAGIC) { 21697563SPrasad.Singamsetty@Sun.COM if (is_mbr != NULL) 21708863SEdward.Pilatowicz@Sun.COM *is_mbr = B_FALSE; 21718863SEdward.Pilatowicz@Sun.COM return (B_TRUE); 21727563SPrasad.Singamsetty@Sun.COM } 21735624Sshidokht 21745624Sshidokht bcopy(&mbp->parts[0], fdisk, sizeof (fdisk)); 21755624Sshidokht 21765624Sshidokht for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) { 21775624Sshidokht if (fdp->systid == EFI_PMBR) 21788863SEdward.Pilatowicz@Sun.COM return (B_TRUE); 21795624Sshidokht } 21805624Sshidokht 21818863SEdward.Pilatowicz@Sun.COM return (B_FALSE); 21825624Sshidokht } 21835624Sshidokht 2184786Slclee static int 21853525Sshidokht cmlb_use_efi(struct cmlb_lun *cl, diskaddr_t capacity, int flags, 21863525Sshidokht void *tg_cookie) 2187786Slclee { 2188786Slclee int i; 2189786Slclee int rval = 0; 2190786Slclee efi_gpe_t *partitions; 2191786Slclee uchar_t *buf; 2192786Slclee uint_t lbasize; /* is really how much to read */ 21933525Sshidokht diskaddr_t cap = 0; 2194786Slclee uint_t nparts; 2195786Slclee diskaddr_t gpe_lba; 21966590Syl194034 diskaddr_t alternate_lba; 21971071Sshidokht int iofailed = 0; 21983525Sshidokht struct uuid uuid_type_reserved = EFI_RESERVED; 21997563SPrasad.Singamsetty@Sun.COM #if defined(_FIRMWARE_NEEDS_FDISK) 22008863SEdward.Pilatowicz@Sun.COM boolean_t is_mbr; 22017563SPrasad.Singamsetty@Sun.COM #endif 22023525Sshidokht 22033525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 22043525Sshidokht 22053525Sshidokht lbasize = cl->cl_sys_blocksize; 22063525Sshidokht 22073525Sshidokht cl->cl_reserved = -1; 22083525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 2209786Slclee 2210786Slclee buf = kmem_zalloc(EFI_MIN_ARRAY_SIZE, KM_SLEEP); 22113525Sshidokht 22127563SPrasad.Singamsetty@Sun.COM rval = DK_TG_READ(cl, buf, 0, lbasize, tg_cookie); 2213786Slclee if (rval) { 22141071Sshidokht iofailed = 1; 2215786Slclee goto done_err; 2216786Slclee } 2217786Slclee if (((struct dk_label *)buf)->dkl_magic == DKL_MAGIC) { 2218786Slclee /* not ours */ 2219786Slclee rval = ESRCH; 2220786Slclee goto done_err; 2221786Slclee } 2222786Slclee 22237563SPrasad.Singamsetty@Sun.COM #if defined(_FIRMWARE_NEEDS_FDISK) 22248863SEdward.Pilatowicz@Sun.COM if (!cmlb_check_efi_mbr(buf, &is_mbr)) { 22258863SEdward.Pilatowicz@Sun.COM if (is_mbr) 22267563SPrasad.Singamsetty@Sun.COM rval = ESRCH; 22277563SPrasad.Singamsetty@Sun.COM else 22287563SPrasad.Singamsetty@Sun.COM rval = EINVAL; 22297563SPrasad.Singamsetty@Sun.COM goto done_err; 22307563SPrasad.Singamsetty@Sun.COM } 22317563SPrasad.Singamsetty@Sun.COM #else 22328863SEdward.Pilatowicz@Sun.COM if (!cmlb_check_efi_mbr(buf, NULL)) { 22335624Sshidokht rval = EINVAL; 22345624Sshidokht goto done_err; 22355624Sshidokht } 22365624Sshidokht 22377563SPrasad.Singamsetty@Sun.COM #endif 22387563SPrasad.Singamsetty@Sun.COM 22393525Sshidokht rval = DK_TG_READ(cl, buf, 1, lbasize, tg_cookie); 2240786Slclee if (rval) { 22411071Sshidokht iofailed = 1; 2242786Slclee goto done_err; 2243786Slclee } 2244786Slclee cmlb_swap_efi_gpt((efi_gpt_t *)buf); 2245786Slclee 2246786Slclee if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) { 2247786Slclee /* 2248786Slclee * Couldn't read the primary, try the backup. Our 2249786Slclee * capacity at this point could be based on CHS, so 2250786Slclee * check what the device reports. 2251786Slclee */ 22523525Sshidokht rval = DK_TG_GETCAP(cl, &cap, tg_cookie); 2253786Slclee if (rval) { 22541071Sshidokht iofailed = 1; 2255786Slclee goto done_err; 2256786Slclee } 22573525Sshidokht 22583525Sshidokht /* 22593525Sshidokht * CMLB_OFF_BY_ONE case, we check the next to last block first 22603525Sshidokht * for backup GPT header, otherwise check the last block. 22613525Sshidokht */ 22623525Sshidokht 22633525Sshidokht if ((rval = DK_TG_READ(cl, buf, 22643525Sshidokht cap - ((cl->cl_alter_behavior & CMLB_OFF_BY_ONE) ? 2 : 1), 22653525Sshidokht lbasize, tg_cookie)) 22663525Sshidokht != 0) { 22671071Sshidokht iofailed = 1; 2268786Slclee goto done_err; 2269786Slclee } 2270786Slclee cmlb_swap_efi_gpt((efi_gpt_t *)buf); 22713525Sshidokht 22723525Sshidokht if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) { 22733525Sshidokht 22743525Sshidokht if (!(cl->cl_alter_behavior & CMLB_OFF_BY_ONE)) 22753525Sshidokht goto done_err; 22763525Sshidokht if ((rval = DK_TG_READ(cl, buf, cap - 1, lbasize, 22773525Sshidokht tg_cookie)) != 0) 22783525Sshidokht goto done_err; 22793525Sshidokht cmlb_swap_efi_gpt((efi_gpt_t *)buf); 22803525Sshidokht if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) 22813525Sshidokht goto done_err; 22823525Sshidokht } 22833525Sshidokht if (!(flags & CMLB_SILENT)) 22843525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN, 22853525Sshidokht "primary label corrupt; using backup\n"); 2286786Slclee } 2287786Slclee 2288786Slclee nparts = ((efi_gpt_t *)buf)->efi_gpt_NumberOfPartitionEntries; 2289786Slclee gpe_lba = ((efi_gpt_t *)buf)->efi_gpt_PartitionEntryLBA; 22906590Syl194034 alternate_lba = ((efi_gpt_t *)buf)->efi_gpt_AlternateLBA; 2291786Slclee 22923525Sshidokht rval = DK_TG_READ(cl, buf, gpe_lba, EFI_MIN_ARRAY_SIZE, tg_cookie); 2293786Slclee if (rval) { 22941071Sshidokht iofailed = 1; 2295786Slclee goto done_err; 2296786Slclee } 2297786Slclee partitions = (efi_gpe_t *)buf; 2298786Slclee 2299786Slclee if (nparts > MAXPART) { 2300786Slclee nparts = MAXPART; 2301786Slclee } 2302786Slclee cmlb_swap_efi_gpe(nparts, partitions); 2303786Slclee 23043525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 2305786Slclee 2306786Slclee /* Fill in partition table. */ 2307786Slclee for (i = 0; i < nparts; i++) { 2308786Slclee if (partitions->efi_gpe_StartingLBA != 0 || 2309786Slclee partitions->efi_gpe_EndingLBA != 0) { 23103525Sshidokht cl->cl_map[i].dkl_cylno = 2311786Slclee partitions->efi_gpe_StartingLBA; 23123525Sshidokht cl->cl_map[i].dkl_nblk = 2313786Slclee partitions->efi_gpe_EndingLBA - 2314786Slclee partitions->efi_gpe_StartingLBA + 1; 23153525Sshidokht cl->cl_offset[i] = 2316786Slclee partitions->efi_gpe_StartingLBA; 2317786Slclee } 23183525Sshidokht 23193525Sshidokht if (cl->cl_reserved == -1) { 23203525Sshidokht if (bcmp(&partitions->efi_gpe_PartitionTypeGUID, 23213525Sshidokht &uuid_type_reserved, sizeof (struct uuid)) == 0) { 23223525Sshidokht cl->cl_reserved = i; 23233525Sshidokht } 23243525Sshidokht } 2325786Slclee if (i == WD_NODE) { 2326786Slclee /* 2327786Slclee * minor number 7 corresponds to the whole disk 23286590Syl194034 * if the disk capacity is expanded after disk is 23296590Syl194034 * labeled, minor number 7 represents the capacity 23306590Syl194034 * indicated by the disk label. 2331786Slclee */ 23323525Sshidokht cl->cl_map[i].dkl_cylno = 0; 23336590Syl194034 if (alternate_lba == 1) { 23346590Syl194034 /* 23356590Syl194034 * We are using backup label. Since we can 23366590Syl194034 * find a valid label at the end of disk, 23376590Syl194034 * the disk capacity is not expanded. 23386590Syl194034 */ 23396590Syl194034 cl->cl_map[i].dkl_nblk = capacity; 23406590Syl194034 } else { 23416590Syl194034 cl->cl_map[i].dkl_nblk = alternate_lba + 1; 23426590Syl194034 } 23433525Sshidokht cl->cl_offset[i] = 0; 2344786Slclee } 2345786Slclee partitions++; 2346786Slclee } 23473525Sshidokht cl->cl_solaris_offset = 0; 23483525Sshidokht cl->cl_solaris_size = capacity; 23497563SPrasad.Singamsetty@Sun.COM cl->cl_label_from_media = CMLB_LABEL_EFI; 23508863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_TRUE; 23513525Sshidokht 23523525Sshidokht /* clear the vtoc label */ 23533525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc)); 23543525Sshidokht 2355786Slclee kmem_free(buf, EFI_MIN_ARRAY_SIZE); 2356786Slclee return (0); 2357786Slclee 2358786Slclee done_err: 2359786Slclee kmem_free(buf, EFI_MIN_ARRAY_SIZE); 23603525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 23613525Sshidokht done_err1: 2362786Slclee /* 2363786Slclee * if we didn't find something that could look like a VTOC 2364786Slclee * and the disk is over 1TB, we know there isn't a valid label. 2365786Slclee * Otherwise let cmlb_uselabel decide what to do. We only 2366786Slclee * want to invalidate this if we're certain the label isn't 2367786Slclee * valid because cmlb_prop_op will now fail, which in turn 2368786Slclee * causes things like opens and stats on the partition to fail. 2369786Slclee */ 23707563SPrasad.Singamsetty@Sun.COM if ((capacity > CMLB_EXTVTOC_LIMIT) && (rval != ESRCH) && !iofailed) { 23718863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE; 2372786Slclee } 2373786Slclee return (rval); 2374786Slclee } 2375786Slclee 2376786Slclee 2377786Slclee /* 2378786Slclee * Function: cmlb_uselabel 2379786Slclee * 2380786Slclee * Description: Validate the disk label and update the relevant data (geometry, 2381786Slclee * partition, vtoc, and capacity data) in the cmlb_lun struct. 2382786Slclee * Marks the geometry of the unit as being valid. 2383786Slclee * 23843525Sshidokht * Arguments: cl: unit struct. 2385786Slclee * dk_label: disk label 2386786Slclee * 2387786Slclee * Return Code: CMLB_LABEL_IS_VALID: Label read from disk is OK; geometry, 2388786Slclee * partition, vtoc, and capacity data are good. 2389786Slclee * 2390786Slclee * CMLB_LABEL_IS_INVALID: Magic number or checksum error in the 2391786Slclee * label; or computed capacity does not jibe with capacity 2392786Slclee * reported from the READ CAPACITY command. 2393786Slclee * 2394786Slclee * Context: Kernel thread only (can sleep). 2395786Slclee */ 2396786Slclee static int 23973525Sshidokht cmlb_uselabel(struct cmlb_lun *cl, struct dk_label *labp, int flags) 2398786Slclee { 2399786Slclee short *sp; 2400786Slclee short sum; 2401786Slclee short count; 2402786Slclee int label_error = CMLB_LABEL_IS_VALID; 2403786Slclee int i; 2404786Slclee diskaddr_t label_capacity; 24057563SPrasad.Singamsetty@Sun.COM uint32_t part_end; 2406786Slclee diskaddr_t track_capacity; 2407786Slclee #if defined(_SUNOS_VTOC_16) 2408786Slclee struct dkl_partition *vpartp; 2409786Slclee #endif 24103525Sshidokht ASSERT(cl != NULL); 24113525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 2412786Slclee 2413786Slclee /* Validate the magic number of the label. */ 2414786Slclee if (labp->dkl_magic != DKL_MAGIC) { 2415786Slclee #if defined(__sparc) 24163525Sshidokht if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) { 24173525Sshidokht if (!(flags & CMLB_SILENT)) 24183525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), 24193525Sshidokht CE_WARN, 24203525Sshidokht "Corrupt label; wrong magic number\n"); 2421786Slclee } 2422786Slclee #endif 2423786Slclee return (CMLB_LABEL_IS_INVALID); 2424786Slclee } 2425786Slclee 2426786Slclee /* Validate the checksum of the label. */ 2427786Slclee sp = (short *)labp; 2428786Slclee sum = 0; 2429786Slclee count = sizeof (struct dk_label) / sizeof (short); 2430786Slclee while (count--) { 2431786Slclee sum ^= *sp++; 2432786Slclee } 2433786Slclee 2434786Slclee if (sum != 0) { 2435786Slclee #if defined(_SUNOS_VTOC_16) 24363525Sshidokht if (!ISCD(cl)) { 2437786Slclee #elif defined(_SUNOS_VTOC_8) 24383525Sshidokht if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) { 2439786Slclee #endif 24403525Sshidokht if (!(flags & CMLB_SILENT)) 24413525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), 24423525Sshidokht CE_WARN, 24433525Sshidokht "Corrupt label - label checksum failed\n"); 2444786Slclee } 2445786Slclee return (CMLB_LABEL_IS_INVALID); 2446786Slclee } 2447786Slclee 2448786Slclee 2449786Slclee /* 2450786Slclee * Fill in geometry structure with data from label. 2451786Slclee */ 24523525Sshidokht bzero(&cl->cl_g, sizeof (struct dk_geom)); 24533525Sshidokht cl->cl_g.dkg_ncyl = labp->dkl_ncyl; 24543525Sshidokht cl->cl_g.dkg_acyl = labp->dkl_acyl; 24553525Sshidokht cl->cl_g.dkg_bcyl = 0; 24563525Sshidokht cl->cl_g.dkg_nhead = labp->dkl_nhead; 24573525Sshidokht cl->cl_g.dkg_nsect = labp->dkl_nsect; 24583525Sshidokht cl->cl_g.dkg_intrlv = labp->dkl_intrlv; 2459786Slclee 2460786Slclee #if defined(_SUNOS_VTOC_8) 24613525Sshidokht cl->cl_g.dkg_gap1 = labp->dkl_gap1; 24623525Sshidokht cl->cl_g.dkg_gap2 = labp->dkl_gap2; 24633525Sshidokht cl->cl_g.dkg_bhead = labp->dkl_bhead; 2464786Slclee #endif 2465786Slclee #if defined(_SUNOS_VTOC_16) 24663525Sshidokht cl->cl_dkg_skew = labp->dkl_skew; 2467786Slclee #endif 2468786Slclee 2469786Slclee #if defined(__i386) || defined(__amd64) 24703525Sshidokht cl->cl_g.dkg_apc = labp->dkl_apc; 2471786Slclee #endif 2472786Slclee 2473786Slclee /* 2474786Slclee * Currently we rely on the values in the label being accurate. If 2475786Slclee * dkl_rpm or dkl_pcly are zero in the label, use a default value. 2476786Slclee * 2477786Slclee * Note: In the future a MODE SENSE may be used to retrieve this data, 2478786Slclee * although this command is optional in SCSI-2. 2479786Slclee */ 24803525Sshidokht cl->cl_g.dkg_rpm = (labp->dkl_rpm != 0) ? labp->dkl_rpm : 3600; 24813525Sshidokht cl->cl_g.dkg_pcyl = (labp->dkl_pcyl != 0) ? labp->dkl_pcyl : 24823525Sshidokht (cl->cl_g.dkg_ncyl + cl->cl_g.dkg_acyl); 2483786Slclee 2484786Slclee /* 2485786Slclee * The Read and Write reinstruct values may not be valid 2486786Slclee * for older disks. 2487786Slclee */ 24883525Sshidokht cl->cl_g.dkg_read_reinstruct = labp->dkl_read_reinstruct; 24893525Sshidokht cl->cl_g.dkg_write_reinstruct = labp->dkl_write_reinstruct; 2490786Slclee 2491786Slclee /* Fill in partition table. */ 2492786Slclee #if defined(_SUNOS_VTOC_8) 2493786Slclee for (i = 0; i < NDKMAP; i++) { 24943525Sshidokht cl->cl_map[i].dkl_cylno = labp->dkl_map[i].dkl_cylno; 24953525Sshidokht cl->cl_map[i].dkl_nblk = labp->dkl_map[i].dkl_nblk; 2496786Slclee } 2497786Slclee #endif 2498786Slclee #if defined(_SUNOS_VTOC_16) 2499786Slclee vpartp = labp->dkl_vtoc.v_part; 2500786Slclee track_capacity = labp->dkl_nhead * labp->dkl_nsect; 2501786Slclee 25023525Sshidokht /* Prevent divide by zero */ 25033525Sshidokht if (track_capacity == 0) { 25043525Sshidokht if (!(flags & CMLB_SILENT)) 25053525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN, 25063525Sshidokht "Corrupt label - zero nhead or nsect value\n"); 25073525Sshidokht 25083525Sshidokht return (CMLB_LABEL_IS_INVALID); 25093525Sshidokht } 25103525Sshidokht 2511786Slclee for (i = 0; i < NDKMAP; i++, vpartp++) { 25123525Sshidokht cl->cl_map[i].dkl_cylno = vpartp->p_start / track_capacity; 25133525Sshidokht cl->cl_map[i].dkl_nblk = vpartp->p_size; 2514786Slclee } 2515786Slclee #endif 2516786Slclee 2517786Slclee /* Fill in VTOC Structure. */ 25183525Sshidokht bcopy(&labp->dkl_vtoc, &cl->cl_vtoc, sizeof (struct dk_vtoc)); 2519786Slclee #if defined(_SUNOS_VTOC_8) 2520786Slclee /* 2521786Slclee * The 8-slice vtoc does not include the ascii label; save it into 2522786Slclee * the device's soft state structure here. 2523786Slclee */ 25243525Sshidokht bcopy(labp->dkl_asciilabel, cl->cl_asciilabel, LEN_DKL_ASCII); 2525786Slclee #endif 2526786Slclee 2527786Slclee /* Now look for a valid capacity. */ 25283525Sshidokht track_capacity = (cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect); 25293525Sshidokht label_capacity = (cl->cl_g.dkg_ncyl * track_capacity); 25303525Sshidokht 25313525Sshidokht if (cl->cl_g.dkg_acyl) { 2532786Slclee #if defined(__i386) || defined(__amd64) 2533786Slclee /* we may have > 1 alts cylinder */ 25343525Sshidokht label_capacity += (track_capacity * cl->cl_g.dkg_acyl); 2535786Slclee #else 2536786Slclee label_capacity += track_capacity; 2537786Slclee #endif 2538786Slclee } 2539786Slclee 2540786Slclee /* 25413525Sshidokht * Force check here to ensure the computed capacity is valid. 25423525Sshidokht * If capacity is zero, it indicates an invalid label and 25433525Sshidokht * we should abort updating the relevant data then. 25443525Sshidokht */ 25453525Sshidokht if (label_capacity == 0) { 25463525Sshidokht if (!(flags & CMLB_SILENT)) 25473525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN, 25483525Sshidokht "Corrupt label - no valid capacity could be " 25493525Sshidokht "retrieved\n"); 25503525Sshidokht 25513525Sshidokht return (CMLB_LABEL_IS_INVALID); 25523525Sshidokht } 25533525Sshidokht 25543525Sshidokht /* Mark the geometry as valid. */ 25558863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_TRUE; 25563525Sshidokht 25573525Sshidokht /* 2558786Slclee * if we got invalidated when mutex exit and entered again, 2559786Slclee * if blockcount different than when we came in, need to 2560786Slclee * retry from beginning of cmlb_validate_geometry. 2561786Slclee * revisit this on next phase of utilizing this for 2562786Slclee * sd. 2563786Slclee */ 2564786Slclee 25653525Sshidokht if (label_capacity <= cl->cl_blockcount) { 2566786Slclee #if defined(_SUNOS_VTOC_8) 2567786Slclee /* 2568786Slclee * We can't let this happen on drives that are subdivided 2569786Slclee * into logical disks (i.e., that have an fdisk table). 25703525Sshidokht * The cl_blockcount field should always hold the full media 2571786Slclee * size in sectors, period. This code would overwrite 25723525Sshidokht * cl_blockcount with the size of the Solaris fdisk partition. 2573786Slclee */ 25743525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 2575786Slclee "cmlb_uselabel: Label %d blocks; Drive %d blocks\n", 25763525Sshidokht label_capacity, cl->cl_blockcount); 25773525Sshidokht cl->cl_solaris_size = label_capacity; 2578786Slclee 2579786Slclee #endif /* defined(_SUNOS_VTOC_8) */ 2580786Slclee goto done; 2581786Slclee } 2582786Slclee 25833525Sshidokht if (ISCD(cl)) { 2584786Slclee /* For CDROMs, we trust that the data in the label is OK. */ 2585786Slclee #if defined(_SUNOS_VTOC_8) 2586786Slclee for (i = 0; i < NDKMAP; i++) { 2587786Slclee part_end = labp->dkl_nhead * labp->dkl_nsect * 2588786Slclee labp->dkl_map[i].dkl_cylno + 2589786Slclee labp->dkl_map[i].dkl_nblk - 1; 2590786Slclee 2591786Slclee if ((labp->dkl_map[i].dkl_nblk) && 25923525Sshidokht (part_end > cl->cl_blockcount)) { 25938863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE; 2594786Slclee break; 2595786Slclee } 2596786Slclee } 2597786Slclee #endif 2598786Slclee #if defined(_SUNOS_VTOC_16) 2599786Slclee vpartp = &(labp->dkl_vtoc.v_part[0]); 2600786Slclee for (i = 0; i < NDKMAP; i++, vpartp++) { 2601786Slclee part_end = vpartp->p_start + vpartp->p_size; 2602786Slclee if ((vpartp->p_size > 0) && 26033525Sshidokht (part_end > cl->cl_blockcount)) { 26048863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE; 2605786Slclee break; 2606786Slclee } 2607786Slclee } 2608786Slclee #endif 2609786Slclee } else { 26103525Sshidokht /* label_capacity > cl->cl_blockcount */ 26113525Sshidokht if (!(flags & CMLB_SILENT)) { 26123525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN, 26133525Sshidokht "Corrupt label - bad geometry\n"); 26143525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_CONT, 26153525Sshidokht "Label says %llu blocks; Drive says %llu blocks\n", 26163525Sshidokht label_capacity, cl->cl_blockcount); 26173525Sshidokht } 26188863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE; 2619786Slclee label_error = CMLB_LABEL_IS_INVALID; 2620786Slclee } 2621786Slclee 2622786Slclee done: 2623786Slclee 26243525Sshidokht cmlb_dbg(CMLB_INFO, cl, "cmlb_uselabel: (label geometry)\n"); 26253525Sshidokht cmlb_dbg(CMLB_INFO, cl, 2626786Slclee " ncyl: %d; acyl: %d; nhead: %d; nsect: %d\n", 26273525Sshidokht cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl, 26283525Sshidokht cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect); 26293525Sshidokht 26303525Sshidokht cmlb_dbg(CMLB_INFO, cl, 2631786Slclee " label_capacity: %d; intrlv: %d; rpm: %d\n", 26323525Sshidokht cl->cl_blockcount, cl->cl_g.dkg_intrlv, cl->cl_g.dkg_rpm); 26333525Sshidokht cmlb_dbg(CMLB_INFO, cl, " wrt_reinstr: %d; rd_reinstr: %d\n", 26343525Sshidokht cl->cl_g.dkg_write_reinstruct, cl->cl_g.dkg_read_reinstruct); 26353525Sshidokht 26363525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 2637786Slclee 2638786Slclee return (label_error); 2639786Slclee } 2640786Slclee 2641786Slclee 2642786Slclee /* 2643786Slclee * Function: cmlb_build_default_label 2644786Slclee * 2645786Slclee * Description: Generate a default label for those devices that do not have 2646786Slclee * one, e.g., new media, removable cartridges, etc.. 2647786Slclee * 2648786Slclee * Context: Kernel thread only 2649786Slclee */ 26503525Sshidokht /*ARGSUSED*/ 2651786Slclee static void 26523525Sshidokht cmlb_build_default_label(struct cmlb_lun *cl, void *tg_cookie) 2653786Slclee { 2654786Slclee #if defined(_SUNOS_VTOC_16) 2655786Slclee uint_t phys_spc; 2656786Slclee uint_t disksize; 26573525Sshidokht struct dk_geom cl_g; 26583525Sshidokht diskaddr_t capacity; 2659786Slclee #endif 2660786Slclee 26613525Sshidokht ASSERT(cl != NULL); 26623525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 2663786Slclee 2664786Slclee #if defined(_SUNOS_VTOC_8) 2665786Slclee /* 2666786Slclee * Note: This is a legacy check for non-removable devices on VTOC_8 2667786Slclee * only. This may be a valid check for VTOC_16 as well. 26683525Sshidokht * Once we understand why there is this difference between SPARC and 26693525Sshidokht * x86 platform, we could remove this legacy check. 2670786Slclee */ 26713525Sshidokht if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) { 2672786Slclee return; 2673786Slclee } 2674786Slclee #endif 2675786Slclee 26763525Sshidokht bzero(&cl->cl_g, sizeof (struct dk_geom)); 26773525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc)); 26783525Sshidokht bzero(&cl->cl_map, NDKMAP * (sizeof (struct dk_map))); 2679786Slclee 2680786Slclee #if defined(_SUNOS_VTOC_8) 2681786Slclee 2682786Slclee /* 2683786Slclee * It's a REMOVABLE media, therefore no label (on sparc, anyway). 2684786Slclee * But it is still necessary to set up various geometry information, 2685786Slclee * and we are doing this here. 2686786Slclee */ 2687786Slclee 2688786Slclee /* 2689786Slclee * For the rpm, we use the minimum for the disk. For the head, cyl, 2690786Slclee * and number of sector per track, if the capacity <= 1GB, head = 64, 2691786Slclee * sect = 32. else head = 255, sect 63 Note: the capacity should be 2692786Slclee * equal to C*H*S values. This will cause some truncation of size due 2693786Slclee * to round off errors. For CD-ROMs, this truncation can have adverse 2694786Slclee * side effects, so returning ncyl and nhead as 1. The nsect will 2695786Slclee * overflow for most of CD-ROMs as nsect is of type ushort. (4190569) 2696786Slclee */ 26973525Sshidokht cl->cl_solaris_size = cl->cl_blockcount; 26983525Sshidokht if (ISCD(cl)) { 2699786Slclee tg_attribute_t tgattribute; 2700786Slclee int is_writable; 2701786Slclee /* 2702786Slclee * Preserve the old behavior for non-writable 2703786Slclee * medias. Since dkg_nsect is a ushort, it 2704786Slclee * will lose bits as cdroms have more than 2705786Slclee * 65536 sectors. So if we recalculate 2706786Slclee * capacity, it will become much shorter. 2707786Slclee * But the dkg_* information is not 2708786Slclee * used for CDROMs so it is OK. But for 2709786Slclee * Writable CDs we need this information 2710786Slclee * to be valid (for newfs say). So we 2711786Slclee * make nsect and nhead > 1 that way 2712786Slclee * nsect can still stay within ushort limit 2713786Slclee * without losing any bits. 2714786Slclee */ 2715786Slclee 2716786Slclee bzero(&tgattribute, sizeof (tg_attribute_t)); 2717786Slclee 27183525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 27193525Sshidokht is_writable = 27203525Sshidokht (DK_TG_GETATTRIBUTE(cl, &tgattribute, tg_cookie) == 0) ? 2721786Slclee tgattribute.media_is_writable : 1; 27223525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 2723786Slclee 2724786Slclee if (is_writable) { 27253525Sshidokht cl->cl_g.dkg_nhead = 64; 27263525Sshidokht cl->cl_g.dkg_nsect = 32; 27273525Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount / (64 * 32); 27287563SPrasad.Singamsetty@Sun.COM cl->cl_solaris_size = (diskaddr_t)cl->cl_g.dkg_ncyl * 27293525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect; 2730786Slclee } else { 27313525Sshidokht cl->cl_g.dkg_ncyl = 1; 27323525Sshidokht cl->cl_g.dkg_nhead = 1; 27333525Sshidokht cl->cl_g.dkg_nsect = cl->cl_blockcount; 2734786Slclee } 2735786Slclee } else { 27363525Sshidokht if (cl->cl_blockcount <= 0x1000) { 2737786Slclee /* unlabeled SCSI floppy device */ 27383525Sshidokht cl->cl_g.dkg_nhead = 2; 27393525Sshidokht cl->cl_g.dkg_ncyl = 80; 27403525Sshidokht cl->cl_g.dkg_nsect = cl->cl_blockcount / (2 * 80); 27413525Sshidokht } else if (cl->cl_blockcount <= 0x200000) { 27423525Sshidokht cl->cl_g.dkg_nhead = 64; 27433525Sshidokht cl->cl_g.dkg_nsect = 32; 27443525Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount / (64 * 32); 2745786Slclee } else { 27463525Sshidokht cl->cl_g.dkg_nhead = 255; 27476124Sshidokht 27486124Sshidokht cl->cl_g.dkg_nsect = ((cl->cl_blockcount + 27496124Sshidokht (UINT16_MAX * 255 * 63) - 1) / 27506124Sshidokht (UINT16_MAX * 255 * 63)) * 63; 27516124Sshidokht 27526124Sshidokht if (cl->cl_g.dkg_nsect == 0) 27536124Sshidokht cl->cl_g.dkg_nsect = (UINT16_MAX / 63) * 63; 27546124Sshidokht 27556124Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount / 27566124Sshidokht (255 * cl->cl_g.dkg_nsect); 2757786Slclee } 27586124Sshidokht 27593525Sshidokht cl->cl_solaris_size = 27607563SPrasad.Singamsetty@Sun.COM (diskaddr_t)cl->cl_g.dkg_ncyl * cl->cl_g.dkg_nhead * 27617563SPrasad.Singamsetty@Sun.COM cl->cl_g.dkg_nsect; 2762786Slclee 2763786Slclee } 2764786Slclee 27653525Sshidokht cl->cl_g.dkg_acyl = 0; 27663525Sshidokht cl->cl_g.dkg_bcyl = 0; 27673525Sshidokht cl->cl_g.dkg_rpm = 200; 27683525Sshidokht cl->cl_asciilabel[0] = '\0'; 27693525Sshidokht cl->cl_g.dkg_pcyl = cl->cl_g.dkg_ncyl; 27703525Sshidokht 27713525Sshidokht cl->cl_map[0].dkl_cylno = 0; 27723525Sshidokht cl->cl_map[0].dkl_nblk = cl->cl_solaris_size; 27733525Sshidokht 27743525Sshidokht cl->cl_map[2].dkl_cylno = 0; 27753525Sshidokht cl->cl_map[2].dkl_nblk = cl->cl_solaris_size; 2776786Slclee 2777786Slclee #elif defined(_SUNOS_VTOC_16) 2778786Slclee 27793525Sshidokht if (cl->cl_solaris_size == 0) { 2780786Slclee /* 2781786Slclee * Got fdisk table but no solaris entry therefore 2782786Slclee * don't create a default label 2783786Slclee */ 27848863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_TRUE; 2785786Slclee return; 2786786Slclee } 2787786Slclee 2788786Slclee /* 2789786Slclee * For CDs we continue to use the physical geometry to calculate 2790786Slclee * number of cylinders. All other devices must convert the 2791786Slclee * physical geometry (cmlb_geom) to values that will fit 2792786Slclee * in a dk_geom structure. 2793786Slclee */ 27943525Sshidokht if (ISCD(cl)) { 27953525Sshidokht phys_spc = cl->cl_pgeom.g_nhead * cl->cl_pgeom.g_nsect; 2796786Slclee } else { 2797786Slclee /* Convert physical geometry to disk geometry */ 27983525Sshidokht bzero(&cl_g, sizeof (struct dk_geom)); 27993525Sshidokht 28003525Sshidokht /* 28013525Sshidokht * Refer to comments related to off-by-1 at the 28023525Sshidokht * header of this file. 28037224Scth * Before calculating geometry, capacity should be 28043525Sshidokht * decreased by 1. 28053525Sshidokht */ 28063525Sshidokht 28073525Sshidokht if (cl->cl_alter_behavior & CMLB_OFF_BY_ONE) 28083525Sshidokht capacity = cl->cl_blockcount - 1; 28093525Sshidokht else 28103525Sshidokht capacity = cl->cl_blockcount; 28113525Sshidokht 28123525Sshidokht 28133525Sshidokht cmlb_convert_geometry(capacity, &cl_g); 28143525Sshidokht bcopy(&cl_g, &cl->cl_g, sizeof (cl->cl_g)); 28153525Sshidokht phys_spc = cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect; 2816786Slclee } 2817786Slclee 28189811SSheshadri.Vasudevan@Sun.COM if (phys_spc == 0) 28199811SSheshadri.Vasudevan@Sun.COM return; 28203525Sshidokht cl->cl_g.dkg_pcyl = cl->cl_solaris_size / phys_spc; 28215084Sjohnlev if (cl->cl_alter_behavior & CMLB_FAKE_LABEL_ONE_PARTITION) { 28225084Sjohnlev /* disable devid */ 28235084Sjohnlev cl->cl_g.dkg_ncyl = cl->cl_g.dkg_pcyl; 28245084Sjohnlev disksize = cl->cl_solaris_size; 28255084Sjohnlev } else { 28265084Sjohnlev cl->cl_g.dkg_acyl = DK_ACYL; 28275084Sjohnlev cl->cl_g.dkg_ncyl = cl->cl_g.dkg_pcyl - DK_ACYL; 28285084Sjohnlev disksize = cl->cl_g.dkg_ncyl * phys_spc; 28295084Sjohnlev } 28303525Sshidokht 28313525Sshidokht if (ISCD(cl)) { 2832786Slclee /* 2833786Slclee * CD's don't use the "heads * sectors * cyls"-type of 2834786Slclee * geometry, but instead use the entire capacity of the media. 2835786Slclee */ 28363525Sshidokht disksize = cl->cl_solaris_size; 28373525Sshidokht cl->cl_g.dkg_nhead = 1; 28383525Sshidokht cl->cl_g.dkg_nsect = 1; 28393525Sshidokht cl->cl_g.dkg_rpm = 28403525Sshidokht (cl->cl_pgeom.g_rpm == 0) ? 200 : cl->cl_pgeom.g_rpm; 28413525Sshidokht 28423525Sshidokht cl->cl_vtoc.v_part[0].p_start = 0; 28433525Sshidokht cl->cl_vtoc.v_part[0].p_size = disksize; 28443525Sshidokht cl->cl_vtoc.v_part[0].p_tag = V_BACKUP; 28453525Sshidokht cl->cl_vtoc.v_part[0].p_flag = V_UNMNT; 28463525Sshidokht 28473525Sshidokht cl->cl_map[0].dkl_cylno = 0; 28483525Sshidokht cl->cl_map[0].dkl_nblk = disksize; 28493525Sshidokht cl->cl_offset[0] = 0; 2850786Slclee 2851786Slclee } else { 2852786Slclee /* 2853786Slclee * Hard disks and removable media cartridges 2854786Slclee */ 28553525Sshidokht cl->cl_g.dkg_rpm = 28563525Sshidokht (cl->cl_pgeom.g_rpm == 0) ? 3600: cl->cl_pgeom.g_rpm; 28573525Sshidokht cl->cl_vtoc.v_sectorsz = cl->cl_sys_blocksize; 2858786Slclee 2859786Slclee /* Add boot slice */ 28603525Sshidokht cl->cl_vtoc.v_part[8].p_start = 0; 28613525Sshidokht cl->cl_vtoc.v_part[8].p_size = phys_spc; 28623525Sshidokht cl->cl_vtoc.v_part[8].p_tag = V_BOOT; 28633525Sshidokht cl->cl_vtoc.v_part[8].p_flag = V_UNMNT; 28643525Sshidokht 28653525Sshidokht cl->cl_map[8].dkl_cylno = 0; 28663525Sshidokht cl->cl_map[8].dkl_nblk = phys_spc; 28673525Sshidokht cl->cl_offset[8] = 0; 28683525Sshidokht 28693525Sshidokht if ((cl->cl_alter_behavior & 2870786Slclee CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT) && 28713525Sshidokht cl->cl_device_type == DTYPE_DIRECT) { 28723525Sshidokht cl->cl_vtoc.v_part[9].p_start = phys_spc; 28733525Sshidokht cl->cl_vtoc.v_part[9].p_size = 2 * phys_spc; 28743525Sshidokht cl->cl_vtoc.v_part[9].p_tag = V_ALTSCTR; 28753525Sshidokht cl->cl_vtoc.v_part[9].p_flag = 0; 28763525Sshidokht 28773525Sshidokht cl->cl_map[9].dkl_cylno = 1; 28783525Sshidokht cl->cl_map[9].dkl_nblk = 2 * phys_spc; 28793525Sshidokht cl->cl_offset[9] = phys_spc; 2880786Slclee } 2881786Slclee } 2882786Slclee 28833525Sshidokht cl->cl_g.dkg_apc = 0; 2884786Slclee 2885786Slclee /* Add backup slice */ 28863525Sshidokht cl->cl_vtoc.v_part[2].p_start = 0; 28873525Sshidokht cl->cl_vtoc.v_part[2].p_size = disksize; 28883525Sshidokht cl->cl_vtoc.v_part[2].p_tag = V_BACKUP; 28893525Sshidokht cl->cl_vtoc.v_part[2].p_flag = V_UNMNT; 28903525Sshidokht 28913525Sshidokht cl->cl_map[2].dkl_cylno = 0; 28923525Sshidokht cl->cl_map[2].dkl_nblk = disksize; 28933525Sshidokht cl->cl_offset[2] = 0; 28943525Sshidokht 28955084Sjohnlev /* 28965084Sjohnlev * single slice (s0) covering the entire disk 28975084Sjohnlev */ 28985084Sjohnlev if (cl->cl_alter_behavior & CMLB_FAKE_LABEL_ONE_PARTITION) { 28995084Sjohnlev cl->cl_vtoc.v_part[0].p_start = 0; 29005084Sjohnlev cl->cl_vtoc.v_part[0].p_tag = V_UNASSIGNED; 29015084Sjohnlev cl->cl_vtoc.v_part[0].p_flag = 0; 29025084Sjohnlev cl->cl_vtoc.v_part[0].p_size = disksize; 29035084Sjohnlev cl->cl_map[0].dkl_cylno = 0; 29045084Sjohnlev cl->cl_map[0].dkl_nblk = disksize; 29055084Sjohnlev cl->cl_offset[0] = 0; 29065084Sjohnlev } 29075084Sjohnlev 29083525Sshidokht (void) sprintf(cl->cl_vtoc.v_asciilabel, "DEFAULT cyl %d alt %d" 29093525Sshidokht " hd %d sec %d", cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl, 29103525Sshidokht cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect); 2911786Slclee 2912786Slclee #else 2913786Slclee #error "No VTOC format defined." 2914786Slclee #endif 2915786Slclee 29163525Sshidokht cl->cl_g.dkg_read_reinstruct = 0; 29173525Sshidokht cl->cl_g.dkg_write_reinstruct = 0; 29183525Sshidokht 29193525Sshidokht cl->cl_g.dkg_intrlv = 1; 29203525Sshidokht 29213525Sshidokht cl->cl_vtoc.v_sanity = VTOC_SANE; 29228169SGabriel.Carrillo@Sun.COM cl->cl_vtoc.v_nparts = V_NUMPAR; 29238169SGabriel.Carrillo@Sun.COM cl->cl_vtoc.v_version = V_VERSION; 29243525Sshidokht 29258863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_TRUE; 29267563SPrasad.Singamsetty@Sun.COM cl->cl_label_from_media = CMLB_LABEL_UNDEF; 29273525Sshidokht 29283525Sshidokht cmlb_dbg(CMLB_INFO, cl, 2929786Slclee "cmlb_build_default_label: Default label created: " 2930786Slclee "cyl: %d\tacyl: %d\tnhead: %d\tnsect: %d\tcap: %d\n", 29313525Sshidokht cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl, cl->cl_g.dkg_nhead, 29323525Sshidokht cl->cl_g.dkg_nsect, cl->cl_blockcount); 2933786Slclee } 2934786Slclee 2935786Slclee 2936786Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 2937786Slclee /* 2938786Slclee * Max CHS values, as they are encoded into bytes, for 1022/254/63 2939786Slclee */ 2940786Slclee #define LBA_MAX_SECT (63 | ((1022 & 0x300) >> 2)) 2941786Slclee #define LBA_MAX_CYL (1022 & 0xFF) 2942786Slclee #define LBA_MAX_HEAD (254) 2943786Slclee 2944786Slclee 2945786Slclee /* 2946786Slclee * Function: cmlb_has_max_chs_vals 2947786Slclee * 29488863SEdward.Pilatowicz@Sun.COM * Description: Return B_TRUE if Cylinder-Head-Sector values are all at maximum. 2949786Slclee * 2950786Slclee * Arguments: fdp - ptr to CHS info 2951786Slclee * 2952786Slclee * Return Code: True or false 2953786Slclee * 2954786Slclee * Context: Any. 2955786Slclee */ 29568863SEdward.Pilatowicz@Sun.COM static boolean_t 2957786Slclee cmlb_has_max_chs_vals(struct ipart *fdp) 2958786Slclee { 2959786Slclee return ((fdp->begcyl == LBA_MAX_CYL) && 2960786Slclee (fdp->beghead == LBA_MAX_HEAD) && 2961786Slclee (fdp->begsect == LBA_MAX_SECT) && 2962786Slclee (fdp->endcyl == LBA_MAX_CYL) && 2963786Slclee (fdp->endhead == LBA_MAX_HEAD) && 2964786Slclee (fdp->endsect == LBA_MAX_SECT)); 2965786Slclee } 2966786Slclee #endif 2967786Slclee 2968786Slclee /* 2969786Slclee * Function: cmlb_dkio_get_geometry 2970786Slclee * 2971786Slclee * Description: This routine is the driver entry point for handling user 2972786Slclee * requests to get the device geometry (DKIOCGGEOM). 2973786Slclee * 2974786Slclee * Arguments: 29753525Sshidokht * arg pointer to user provided dk_geom structure specifying 2976786Slclee * the controller's notion of the current geometry. 29773525Sshidokht * 29783525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 29793525Sshidokht * directly from the mode argument of ioctl(). 29803525Sshidokht * 29813525Sshidokht * tg_cookie cookie from target driver to be passed back to target 29823525Sshidokht * driver when we call back to it through tg_ops. 2983786Slclee * 2984786Slclee * Return Code: 0 2985786Slclee * EFAULT 2986786Slclee * ENXIO 2987786Slclee * EIO 2988786Slclee */ 2989786Slclee static int 29903525Sshidokht cmlb_dkio_get_geometry(struct cmlb_lun *cl, caddr_t arg, int flag, 29913525Sshidokht void *tg_cookie) 2992786Slclee { 2993786Slclee struct dk_geom *tmp_geom = NULL; 2994786Slclee int rval = 0; 2995786Slclee 2996786Slclee /* 2997786Slclee * cmlb_validate_geometry does not spin a disk up 29983525Sshidokht * if it was spcl down. We need to make sure it 2999786Slclee * is ready. 3000786Slclee */ 30013525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 30028863SEdward.Pilatowicz@Sun.COM rval = cmlb_validate_geometry(cl, B_TRUE, 0, tg_cookie); 3003786Slclee #if defined(_SUNOS_VTOC_8) 3004786Slclee if (rval == EINVAL && 30053525Sshidokht cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8) { 3006786Slclee /* 3007786Slclee * This is to return a default label geometry even when we 3008786Slclee * do not really assume a default label for the device. 3009786Slclee * dad driver utilizes this. 3010786Slclee */ 30117563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount <= CMLB_OLDVTOC_LIMIT) { 30123525Sshidokht cmlb_setup_default_geometry(cl, tg_cookie); 3013786Slclee rval = 0; 3014786Slclee } 3015786Slclee } 3016786Slclee #endif 3017786Slclee if (rval) { 30183525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3019786Slclee return (rval); 3020786Slclee } 3021786Slclee 3022786Slclee #if defined(__i386) || defined(__amd64) 30233525Sshidokht if (cl->cl_solaris_size == 0) { 30243525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3025786Slclee return (EIO); 3026786Slclee } 3027786Slclee #endif 3028786Slclee 3029786Slclee /* 3030786Slclee * Make a local copy of the soft state geometry to avoid some potential 3031786Slclee * race conditions associated with holding the mutex and updating the 3032786Slclee * write_reinstruct value 3033786Slclee */ 3034786Slclee tmp_geom = kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP); 30353525Sshidokht bcopy(&cl->cl_g, tmp_geom, sizeof (struct dk_geom)); 3036786Slclee 3037786Slclee if (tmp_geom->dkg_write_reinstruct == 0) { 3038786Slclee tmp_geom->dkg_write_reinstruct = 3039786Slclee (int)((int)(tmp_geom->dkg_nsect * tmp_geom->dkg_rpm * 3040786Slclee cmlb_rot_delay) / (int)60000); 3041786Slclee } 30423525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3043786Slclee 3044786Slclee rval = ddi_copyout(tmp_geom, (void *)arg, sizeof (struct dk_geom), 3045786Slclee flag); 3046786Slclee if (rval != 0) { 3047786Slclee rval = EFAULT; 3048786Slclee } 3049786Slclee 3050786Slclee kmem_free(tmp_geom, sizeof (struct dk_geom)); 3051786Slclee return (rval); 3052786Slclee 3053786Slclee } 3054786Slclee 3055786Slclee 3056786Slclee /* 3057786Slclee * Function: cmlb_dkio_set_geometry 3058786Slclee * 3059786Slclee * Description: This routine is the driver entry point for handling user 3060786Slclee * requests to set the device geometry (DKIOCSGEOM). The actual 3061786Slclee * device geometry is not updated, just the driver "notion" of it. 3062786Slclee * 3063786Slclee * Arguments: 30643525Sshidokht * arg pointer to user provided dk_geom structure used to set 3065786Slclee * the controller's notion of the current geometry. 30663525Sshidokht * 30673525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 30683525Sshidokht * directly from the mode argument of ioctl(). 30693525Sshidokht * 30703525Sshidokht * tg_cookie cookie from target driver to be passed back to target 30713525Sshidokht * driver when we call back to it through tg_ops. 3072786Slclee * 3073786Slclee * Return Code: 0 3074786Slclee * EFAULT 3075786Slclee * ENXIO 3076786Slclee * EIO 3077786Slclee */ 3078786Slclee static int 30793525Sshidokht cmlb_dkio_set_geometry(struct cmlb_lun *cl, caddr_t arg, int flag) 3080786Slclee { 3081786Slclee struct dk_geom *tmp_geom; 3082786Slclee struct dk_map *lp; 3083786Slclee int rval = 0; 3084786Slclee int i; 3085786Slclee 3086786Slclee 3087786Slclee #if defined(__i386) || defined(__amd64) 30883525Sshidokht if (cl->cl_solaris_size == 0) { 3089786Slclee return (EIO); 3090786Slclee } 3091786Slclee #endif 3092786Slclee /* 3093786Slclee * We need to copy the user specified geometry into local 3094786Slclee * storage and then update the softstate. We don't want to hold 3095786Slclee * the mutex and copyin directly from the user to the soft state 3096786Slclee */ 3097786Slclee tmp_geom = (struct dk_geom *) 3098786Slclee kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP); 3099786Slclee rval = ddi_copyin(arg, tmp_geom, sizeof (struct dk_geom), flag); 3100786Slclee if (rval != 0) { 3101786Slclee kmem_free(tmp_geom, sizeof (struct dk_geom)); 3102786Slclee return (EFAULT); 3103786Slclee } 3104786Slclee 31053525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 31063525Sshidokht bcopy(tmp_geom, &cl->cl_g, sizeof (struct dk_geom)); 3107786Slclee for (i = 0; i < NDKMAP; i++) { 31083525Sshidokht lp = &cl->cl_map[i]; 31093525Sshidokht cl->cl_offset[i] = 31103525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno; 3111786Slclee #if defined(__i386) || defined(__amd64) 31123525Sshidokht cl->cl_offset[i] += cl->cl_solaris_offset; 3113786Slclee #endif 3114786Slclee } 31158863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE; 31163525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3117786Slclee kmem_free(tmp_geom, sizeof (struct dk_geom)); 3118786Slclee 3119786Slclee return (rval); 3120786Slclee } 3121786Slclee 3122786Slclee /* 3123786Slclee * Function: cmlb_dkio_get_partition 3124786Slclee * 3125786Slclee * Description: This routine is the driver entry point for handling user 3126786Slclee * requests to get the partition table (DKIOCGAPART). 3127786Slclee * 3128786Slclee * Arguments: 31293525Sshidokht * arg pointer to user provided dk_allmap structure specifying 3130786Slclee * the controller's notion of the current partition table. 31313525Sshidokht * 31323525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 31333525Sshidokht * directly from the mode argument of ioctl(). 31343525Sshidokht * 31353525Sshidokht * tg_cookie cookie from target driver to be passed back to target 31363525Sshidokht * driver when we call back to it through tg_ops. 3137786Slclee * 3138786Slclee * Return Code: 0 3139786Slclee * EFAULT 3140786Slclee * ENXIO 3141786Slclee * EIO 3142786Slclee */ 3143786Slclee static int 31443525Sshidokht cmlb_dkio_get_partition(struct cmlb_lun *cl, caddr_t arg, int flag, 31453525Sshidokht void *tg_cookie) 3146786Slclee { 3147786Slclee int rval = 0; 3148786Slclee int size; 3149786Slclee 3150786Slclee /* 3151786Slclee * Make sure the geometry is valid before getting the partition 3152786Slclee * information. 3153786Slclee */ 31543525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 31558863SEdward.Pilatowicz@Sun.COM if ((rval = cmlb_validate_geometry(cl, B_TRUE, 0, tg_cookie)) != 0) { 31563525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3157786Slclee return (rval); 3158786Slclee } 31593525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3160786Slclee 3161786Slclee #if defined(__i386) || defined(__amd64) 31623525Sshidokht if (cl->cl_solaris_size == 0) { 3163786Slclee return (EIO); 3164786Slclee } 3165786Slclee #endif 3166786Slclee 3167786Slclee #ifdef _MULTI_DATAMODEL 3168786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 3169786Slclee case DDI_MODEL_ILP32: { 3170786Slclee struct dk_map32 dk_map32[NDKMAP]; 3171786Slclee int i; 3172786Slclee 3173786Slclee for (i = 0; i < NDKMAP; i++) { 31743525Sshidokht dk_map32[i].dkl_cylno = cl->cl_map[i].dkl_cylno; 31753525Sshidokht dk_map32[i].dkl_nblk = cl->cl_map[i].dkl_nblk; 3176786Slclee } 3177786Slclee size = NDKMAP * sizeof (struct dk_map32); 3178786Slclee rval = ddi_copyout(dk_map32, (void *)arg, size, flag); 3179786Slclee if (rval != 0) { 3180786Slclee rval = EFAULT; 3181786Slclee } 3182786Slclee break; 3183786Slclee } 3184786Slclee case DDI_MODEL_NONE: 3185786Slclee size = NDKMAP * sizeof (struct dk_map); 31863525Sshidokht rval = ddi_copyout(cl->cl_map, (void *)arg, size, flag); 3187786Slclee if (rval != 0) { 3188786Slclee rval = EFAULT; 3189786Slclee } 3190786Slclee break; 3191786Slclee } 3192786Slclee #else /* ! _MULTI_DATAMODEL */ 3193786Slclee size = NDKMAP * sizeof (struct dk_map); 31943525Sshidokht rval = ddi_copyout(cl->cl_map, (void *)arg, size, flag); 3195786Slclee if (rval != 0) { 3196786Slclee rval = EFAULT; 3197786Slclee } 3198786Slclee #endif /* _MULTI_DATAMODEL */ 3199786Slclee return (rval); 3200786Slclee } 3201786Slclee 3202786Slclee /* 3203786Slclee * Function: cmlb_dkio_set_partition 3204786Slclee * 3205786Slclee * Description: This routine is the driver entry point for handling user 3206786Slclee * requests to set the partition table (DKIOCSAPART). The actual 3207786Slclee * device partition is not updated. 3208786Slclee * 3209786Slclee * Arguments: 3210786Slclee * arg - pointer to user provided dk_allmap structure used to set 3211786Slclee * the controller's notion of the partition table. 3212786Slclee * flag - this argument is a pass through to ddi_copyxxx() 3213786Slclee * directly from the mode argument of ioctl(). 3214786Slclee * 3215786Slclee * Return Code: 0 3216786Slclee * EINVAL 3217786Slclee * EFAULT 3218786Slclee * ENXIO 3219786Slclee * EIO 3220786Slclee */ 3221786Slclee static int 32223525Sshidokht cmlb_dkio_set_partition(struct cmlb_lun *cl, caddr_t arg, int flag) 3223786Slclee { 3224786Slclee struct dk_map dk_map[NDKMAP]; 3225786Slclee struct dk_map *lp; 3226786Slclee int rval = 0; 3227786Slclee int size; 3228786Slclee int i; 3229786Slclee #if defined(_SUNOS_VTOC_16) 3230786Slclee struct dkl_partition *vp; 3231786Slclee #endif 3232786Slclee 3233786Slclee /* 3234786Slclee * Set the map for all logical partitions. We lock 3235786Slclee * the priority just to make sure an interrupt doesn't 3236786Slclee * come in while the map is half updated. 3237786Slclee */ 32383525Sshidokht _NOTE(DATA_READABLE_WITHOUT_LOCK(cmlb_lun::cl_solaris_size)) 32393525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 32403525Sshidokht 32417563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) { 32423525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3243786Slclee return (ENOTSUP); 3244786Slclee } 32453525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 32463525Sshidokht if (cl->cl_solaris_size == 0) { 3247786Slclee return (EIO); 3248786Slclee } 3249786Slclee 3250786Slclee #ifdef _MULTI_DATAMODEL 3251786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 3252786Slclee case DDI_MODEL_ILP32: { 3253786Slclee struct dk_map32 dk_map32[NDKMAP]; 3254786Slclee 3255786Slclee size = NDKMAP * sizeof (struct dk_map32); 3256786Slclee rval = ddi_copyin((void *)arg, dk_map32, size, flag); 3257786Slclee if (rval != 0) { 3258786Slclee return (EFAULT); 3259786Slclee } 3260786Slclee for (i = 0; i < NDKMAP; i++) { 3261786Slclee dk_map[i].dkl_cylno = dk_map32[i].dkl_cylno; 3262786Slclee dk_map[i].dkl_nblk = dk_map32[i].dkl_nblk; 3263786Slclee } 3264786Slclee break; 3265786Slclee } 3266786Slclee case DDI_MODEL_NONE: 3267786Slclee size = NDKMAP * sizeof (struct dk_map); 3268786Slclee rval = ddi_copyin((void *)arg, dk_map, size, flag); 3269786Slclee if (rval != 0) { 3270786Slclee return (EFAULT); 3271786Slclee } 3272786Slclee break; 3273786Slclee } 3274786Slclee #else /* ! _MULTI_DATAMODEL */ 3275786Slclee size = NDKMAP * sizeof (struct dk_map); 3276786Slclee rval = ddi_copyin((void *)arg, dk_map, size, flag); 3277786Slclee if (rval != 0) { 3278786Slclee return (EFAULT); 3279786Slclee } 3280786Slclee #endif /* _MULTI_DATAMODEL */ 3281786Slclee 32823525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 3283786Slclee /* Note: The size used in this bcopy is set based upon the data model */ 32843525Sshidokht bcopy(dk_map, cl->cl_map, size); 3285786Slclee #if defined(_SUNOS_VTOC_16) 32863525Sshidokht vp = (struct dkl_partition *)&(cl->cl_vtoc); 3287786Slclee #endif /* defined(_SUNOS_VTOC_16) */ 3288786Slclee for (i = 0; i < NDKMAP; i++) { 32893525Sshidokht lp = &cl->cl_map[i]; 32903525Sshidokht cl->cl_offset[i] = 32913525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno; 3292786Slclee #if defined(_SUNOS_VTOC_16) 32933525Sshidokht vp->p_start = cl->cl_offset[i]; 3294786Slclee vp->p_size = lp->dkl_nblk; 3295786Slclee vp++; 3296786Slclee #endif /* defined(_SUNOS_VTOC_16) */ 3297786Slclee #if defined(__i386) || defined(__amd64) 32983525Sshidokht cl->cl_offset[i] += cl->cl_solaris_offset; 3299786Slclee #endif 3300786Slclee } 33013525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3302786Slclee return (rval); 3303786Slclee } 3304786Slclee 3305786Slclee 3306786Slclee /* 3307786Slclee * Function: cmlb_dkio_get_vtoc 3308786Slclee * 3309786Slclee * Description: This routine is the driver entry point for handling user 3310786Slclee * requests to get the current volume table of contents 3311786Slclee * (DKIOCGVTOC). 3312786Slclee * 3313786Slclee * Arguments: 33143525Sshidokht * arg pointer to user provided vtoc structure specifying 3315786Slclee * the current vtoc. 33163525Sshidokht * 33173525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 33183525Sshidokht * directly from the mode argument of ioctl(). 33193525Sshidokht * 33203525Sshidokht * tg_cookie cookie from target driver to be passed back to target 33213525Sshidokht * driver when we call back to it through tg_ops. 3322786Slclee * 3323786Slclee * Return Code: 0 3324786Slclee * EFAULT 3325786Slclee * ENXIO 3326786Slclee * EIO 3327786Slclee */ 3328786Slclee static int 33293525Sshidokht cmlb_dkio_get_vtoc(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie) 3330786Slclee { 3331786Slclee #if defined(_SUNOS_VTOC_8) 3332786Slclee struct vtoc user_vtoc; 3333786Slclee #endif /* defined(_SUNOS_VTOC_8) */ 3334786Slclee int rval = 0; 3335786Slclee 33363525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 33377563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) { 33387563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 33397563SPrasad.Singamsetty@Sun.COM return (EOVERFLOW); 33407563SPrasad.Singamsetty@Sun.COM } 33417563SPrasad.Singamsetty@Sun.COM 33428863SEdward.Pilatowicz@Sun.COM rval = cmlb_validate_geometry(cl, B_TRUE, 0, tg_cookie); 3343786Slclee 3344786Slclee #if defined(_SUNOS_VTOC_8) 3345786Slclee if (rval == EINVAL && 33463525Sshidokht (cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8)) { 3347786Slclee /* 3348786Slclee * This is to return a default label even when we do not 3349786Slclee * really assume a default label for the device. 3350786Slclee * dad driver utilizes this. 3351786Slclee */ 33527563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount <= CMLB_OLDVTOC_LIMIT) { 33533525Sshidokht cmlb_setup_default_geometry(cl, tg_cookie); 3354786Slclee rval = 0; 3355786Slclee } 3356786Slclee } 3357786Slclee #endif 3358786Slclee if (rval) { 33593525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3360786Slclee return (rval); 3361786Slclee } 3362786Slclee 3363786Slclee #if defined(_SUNOS_VTOC_8) 33643525Sshidokht cmlb_build_user_vtoc(cl, &user_vtoc); 33653525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3366786Slclee 3367786Slclee #ifdef _MULTI_DATAMODEL 3368786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 3369786Slclee case DDI_MODEL_ILP32: { 3370786Slclee struct vtoc32 user_vtoc32; 3371786Slclee 3372786Slclee vtoctovtoc32(user_vtoc, user_vtoc32); 3373786Slclee if (ddi_copyout(&user_vtoc32, (void *)arg, 3374786Slclee sizeof (struct vtoc32), flag)) { 3375786Slclee return (EFAULT); 3376786Slclee } 3377786Slclee break; 3378786Slclee } 3379786Slclee 3380786Slclee case DDI_MODEL_NONE: 3381786Slclee if (ddi_copyout(&user_vtoc, (void *)arg, 3382786Slclee sizeof (struct vtoc), flag)) { 3383786Slclee return (EFAULT); 3384786Slclee } 3385786Slclee break; 3386786Slclee } 3387786Slclee #else /* ! _MULTI_DATAMODEL */ 3388786Slclee if (ddi_copyout(&user_vtoc, (void *)arg, sizeof (struct vtoc), flag)) { 3389786Slclee return (EFAULT); 3390786Slclee } 3391786Slclee #endif /* _MULTI_DATAMODEL */ 3392786Slclee 3393786Slclee #elif defined(_SUNOS_VTOC_16) 33943525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3395786Slclee 3396786Slclee #ifdef _MULTI_DATAMODEL 3397786Slclee /* 33983525Sshidokht * The cl_vtoc structure is a "struct dk_vtoc" which is always 3399786Slclee * 32-bit to maintain compatibility with existing on-disk 3400786Slclee * structures. Thus, we need to convert the structure when copying 3401786Slclee * it out to a datamodel-dependent "struct vtoc" in a 64-bit 3402786Slclee * program. If the target is a 32-bit program, then no conversion 3403786Slclee * is necessary. 3404786Slclee */ 3405786Slclee /* LINTED: logical expression always true: op "||" */ 34063525Sshidokht ASSERT(sizeof (cl->cl_vtoc) == sizeof (struct vtoc32)); 3407786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 3408786Slclee case DDI_MODEL_ILP32: 34093525Sshidokht if (ddi_copyout(&(cl->cl_vtoc), (void *)arg, 34103525Sshidokht sizeof (cl->cl_vtoc), flag)) { 3411786Slclee return (EFAULT); 3412786Slclee } 3413786Slclee break; 3414786Slclee 3415786Slclee case DDI_MODEL_NONE: { 3416786Slclee struct vtoc user_vtoc; 3417786Slclee 34183525Sshidokht vtoc32tovtoc(cl->cl_vtoc, user_vtoc); 3419786Slclee if (ddi_copyout(&user_vtoc, (void *)arg, 3420786Slclee sizeof (struct vtoc), flag)) { 3421786Slclee return (EFAULT); 3422786Slclee } 3423786Slclee break; 3424786Slclee } 3425786Slclee } 3426786Slclee #else /* ! _MULTI_DATAMODEL */ 34273525Sshidokht if (ddi_copyout(&(cl->cl_vtoc), (void *)arg, sizeof (cl->cl_vtoc), 3428786Slclee flag)) { 3429786Slclee return (EFAULT); 3430786Slclee } 3431786Slclee #endif /* _MULTI_DATAMODEL */ 3432786Slclee #else 3433786Slclee #error "No VTOC format defined." 3434786Slclee #endif 3435786Slclee 3436786Slclee return (rval); 3437786Slclee } 3438786Slclee 34397563SPrasad.Singamsetty@Sun.COM 34407563SPrasad.Singamsetty@Sun.COM /* 34417563SPrasad.Singamsetty@Sun.COM * Function: cmlb_dkio_get_extvtoc 34427563SPrasad.Singamsetty@Sun.COM */ 34437563SPrasad.Singamsetty@Sun.COM static int 34447563SPrasad.Singamsetty@Sun.COM cmlb_dkio_get_extvtoc(struct cmlb_lun *cl, caddr_t arg, int flag, 34457563SPrasad.Singamsetty@Sun.COM void *tg_cookie) 34467563SPrasad.Singamsetty@Sun.COM { 34477563SPrasad.Singamsetty@Sun.COM struct extvtoc ext_vtoc; 34487563SPrasad.Singamsetty@Sun.COM #if defined(_SUNOS_VTOC_8) 34497563SPrasad.Singamsetty@Sun.COM struct vtoc user_vtoc; 34507563SPrasad.Singamsetty@Sun.COM #endif /* defined(_SUNOS_VTOC_8) */ 34517563SPrasad.Singamsetty@Sun.COM int rval = 0; 34527563SPrasad.Singamsetty@Sun.COM 34537563SPrasad.Singamsetty@Sun.COM bzero(&ext_vtoc, sizeof (struct extvtoc)); 34547563SPrasad.Singamsetty@Sun.COM mutex_enter(CMLB_MUTEX(cl)); 34558863SEdward.Pilatowicz@Sun.COM rval = cmlb_validate_geometry(cl, B_TRUE, 0, tg_cookie); 34567563SPrasad.Singamsetty@Sun.COM 34577563SPrasad.Singamsetty@Sun.COM #if defined(_SUNOS_VTOC_8) 34587563SPrasad.Singamsetty@Sun.COM if (rval == EINVAL && 34597563SPrasad.Singamsetty@Sun.COM (cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8)) { 34607563SPrasad.Singamsetty@Sun.COM /* 34617563SPrasad.Singamsetty@Sun.COM * This is to return a default label even when we do not 34627563SPrasad.Singamsetty@Sun.COM * really assume a default label for the device. 34637563SPrasad.Singamsetty@Sun.COM * dad driver utilizes this. 34647563SPrasad.Singamsetty@Sun.COM */ 34657563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount <= CMLB_OLDVTOC_LIMIT) { 34667563SPrasad.Singamsetty@Sun.COM cmlb_setup_default_geometry(cl, tg_cookie); 34677563SPrasad.Singamsetty@Sun.COM rval = 0; 34687563SPrasad.Singamsetty@Sun.COM } 34697563SPrasad.Singamsetty@Sun.COM } 34707563SPrasad.Singamsetty@Sun.COM #endif 34717563SPrasad.Singamsetty@Sun.COM if (rval) { 34727563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 34737563SPrasad.Singamsetty@Sun.COM return (rval); 34747563SPrasad.Singamsetty@Sun.COM } 34757563SPrasad.Singamsetty@Sun.COM 34767563SPrasad.Singamsetty@Sun.COM #if defined(_SUNOS_VTOC_8) 34777563SPrasad.Singamsetty@Sun.COM cmlb_build_user_vtoc(cl, &user_vtoc); 34787563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 34797563SPrasad.Singamsetty@Sun.COM 34807563SPrasad.Singamsetty@Sun.COM /* 34817563SPrasad.Singamsetty@Sun.COM * Checking callers data model does not make much sense here 34827563SPrasad.Singamsetty@Sun.COM * since extvtoc will always be equivalent to 64bit vtoc. 34837563SPrasad.Singamsetty@Sun.COM * What is important is whether the kernel is in 32 or 64 bit 34847563SPrasad.Singamsetty@Sun.COM */ 34857563SPrasad.Singamsetty@Sun.COM 34867563SPrasad.Singamsetty@Sun.COM #ifdef _LP64 34877563SPrasad.Singamsetty@Sun.COM if (ddi_copyout(&user_vtoc, (void *)arg, 34887563SPrasad.Singamsetty@Sun.COM sizeof (struct extvtoc), flag)) { 34897563SPrasad.Singamsetty@Sun.COM return (EFAULT); 34907563SPrasad.Singamsetty@Sun.COM } 34917563SPrasad.Singamsetty@Sun.COM #else 34927563SPrasad.Singamsetty@Sun.COM vtoc32tovtoc(user_vtoc, ext_vtoc); 34937563SPrasad.Singamsetty@Sun.COM if (ddi_copyout(&ext_vtoc, (void *)arg, 34947563SPrasad.Singamsetty@Sun.COM sizeof (struct extvtoc), flag)) { 34957563SPrasad.Singamsetty@Sun.COM return (EFAULT); 34967563SPrasad.Singamsetty@Sun.COM } 34977563SPrasad.Singamsetty@Sun.COM #endif 34987563SPrasad.Singamsetty@Sun.COM 34997563SPrasad.Singamsetty@Sun.COM #elif defined(_SUNOS_VTOC_16) 35007563SPrasad.Singamsetty@Sun.COM /* 35017563SPrasad.Singamsetty@Sun.COM * The cl_vtoc structure is a "struct dk_vtoc" which is always 35027563SPrasad.Singamsetty@Sun.COM * 32-bit to maintain compatibility with existing on-disk 35037563SPrasad.Singamsetty@Sun.COM * structures. Thus, we need to convert the structure when copying 35047563SPrasad.Singamsetty@Sun.COM * it out to extvtoc 35057563SPrasad.Singamsetty@Sun.COM */ 35067563SPrasad.Singamsetty@Sun.COM vtoc32tovtoc(cl->cl_vtoc, ext_vtoc); 35077909SXiao.L@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 35087563SPrasad.Singamsetty@Sun.COM 35097563SPrasad.Singamsetty@Sun.COM if (ddi_copyout(&ext_vtoc, (void *)arg, sizeof (struct extvtoc), flag)) 35107563SPrasad.Singamsetty@Sun.COM return (EFAULT); 35117563SPrasad.Singamsetty@Sun.COM #else 35127563SPrasad.Singamsetty@Sun.COM #error "No VTOC format defined." 35137563SPrasad.Singamsetty@Sun.COM #endif 35147563SPrasad.Singamsetty@Sun.COM 35157563SPrasad.Singamsetty@Sun.COM return (rval); 35167563SPrasad.Singamsetty@Sun.COM } 3517786Slclee static int 35183525Sshidokht cmlb_dkio_get_efi(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie) 3519786Slclee { 3520786Slclee dk_efi_t user_efi; 3521786Slclee int rval = 0; 3522786Slclee void *buffer; 35233525Sshidokht diskaddr_t tgt_lba; 3524786Slclee 3525786Slclee if (ddi_copyin(arg, &user_efi, sizeof (dk_efi_t), flag)) 3526786Slclee return (EFAULT); 3527786Slclee 3528786Slclee user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64; 3529786Slclee 35303525Sshidokht tgt_lba = user_efi.dki_lba; 35313525Sshidokht 35323525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 35333525Sshidokht if ((cmlb_check_update_blockcount(cl, tg_cookie) != 0) || 35343525Sshidokht (cl->cl_tgt_blocksize == 0)) { 35353525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 35363525Sshidokht return (EINVAL); 35373525Sshidokht } 35383525Sshidokht if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) 35393525Sshidokht tgt_lba = tgt_lba * cl->cl_tgt_blocksize / 35403525Sshidokht cl->cl_sys_blocksize; 35413525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 35423525Sshidokht 3543786Slclee buffer = kmem_alloc(user_efi.dki_length, KM_SLEEP); 35443525Sshidokht rval = DK_TG_READ(cl, buffer, tgt_lba, user_efi.dki_length, tg_cookie); 3545786Slclee if (rval == 0 && ddi_copyout(buffer, user_efi.dki_data, 3546786Slclee user_efi.dki_length, flag) != 0) 3547786Slclee rval = EFAULT; 3548786Slclee 3549786Slclee kmem_free(buffer, user_efi.dki_length); 3550786Slclee return (rval); 3551786Slclee } 3552786Slclee 35533525Sshidokht #if defined(_SUNOS_VTOC_8) 3554786Slclee /* 3555786Slclee * Function: cmlb_build_user_vtoc 3556786Slclee * 3557786Slclee * Description: This routine populates a pass by reference variable with the 3558786Slclee * current volume table of contents. 3559786Slclee * 35603525Sshidokht * Arguments: cl - driver soft state (unit) structure 3561786Slclee * user_vtoc - pointer to vtoc structure to be populated 3562786Slclee */ 3563786Slclee static void 35643525Sshidokht cmlb_build_user_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc) 3565786Slclee { 3566786Slclee struct dk_map2 *lpart; 3567786Slclee struct dk_map *lmap; 3568786Slclee struct partition *vpart; 35697563SPrasad.Singamsetty@Sun.COM uint32_t nblks; 3570786Slclee int i; 3571786Slclee 35723525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 3573786Slclee 3574786Slclee /* 3575786Slclee * Return vtoc structure fields in the provided VTOC area, addressed 3576786Slclee * by *vtoc. 3577786Slclee */ 3578786Slclee bzero(user_vtoc, sizeof (struct vtoc)); 35793525Sshidokht user_vtoc->v_bootinfo[0] = cl->cl_vtoc.v_bootinfo[0]; 35803525Sshidokht user_vtoc->v_bootinfo[1] = cl->cl_vtoc.v_bootinfo[1]; 35813525Sshidokht user_vtoc->v_bootinfo[2] = cl->cl_vtoc.v_bootinfo[2]; 3582786Slclee user_vtoc->v_sanity = VTOC_SANE; 35833525Sshidokht user_vtoc->v_version = cl->cl_vtoc.v_version; 35843525Sshidokht bcopy(cl->cl_vtoc.v_volume, user_vtoc->v_volume, LEN_DKL_VVOL); 35853525Sshidokht user_vtoc->v_sectorsz = cl->cl_sys_blocksize; 35863525Sshidokht user_vtoc->v_nparts = cl->cl_vtoc.v_nparts; 3587786Slclee 3588786Slclee for (i = 0; i < 10; i++) 35893525Sshidokht user_vtoc->v_reserved[i] = cl->cl_vtoc.v_reserved[i]; 3590786Slclee 3591786Slclee /* 3592786Slclee * Convert partitioning information. 3593786Slclee * 3594786Slclee * Note the conversion from starting cylinder number 3595786Slclee * to starting sector number. 3596786Slclee */ 35973525Sshidokht lmap = cl->cl_map; 35983525Sshidokht lpart = (struct dk_map2 *)cl->cl_vtoc.v_part; 3599786Slclee vpart = user_vtoc->v_part; 3600786Slclee 36013525Sshidokht nblks = cl->cl_g.dkg_nsect * cl->cl_g.dkg_nhead; 3602786Slclee 3603786Slclee for (i = 0; i < V_NUMPAR; i++) { 3604786Slclee vpart->p_tag = lpart->p_tag; 3605786Slclee vpart->p_flag = lpart->p_flag; 3606786Slclee vpart->p_start = lmap->dkl_cylno * nblks; 3607786Slclee vpart->p_size = lmap->dkl_nblk; 3608786Slclee lmap++; 3609786Slclee lpart++; 3610786Slclee vpart++; 3611786Slclee 3612786Slclee /* (4364927) */ 36133525Sshidokht user_vtoc->timestamp[i] = (time_t)cl->cl_vtoc.v_timestamp[i]; 3614786Slclee } 3615786Slclee 36163525Sshidokht bcopy(cl->cl_asciilabel, user_vtoc->v_asciilabel, LEN_DKL_ASCII); 3617786Slclee } 36183525Sshidokht #endif 3619786Slclee 3620786Slclee static int 36213525Sshidokht cmlb_dkio_partition(struct cmlb_lun *cl, caddr_t arg, int flag, 36223525Sshidokht void *tg_cookie) 3623786Slclee { 3624786Slclee struct partition64 p64; 3625786Slclee int rval = 0; 3626786Slclee uint_t nparts; 3627786Slclee efi_gpe_t *partitions; 3628786Slclee efi_gpt_t *buffer; 3629786Slclee diskaddr_t gpe_lba; 3630786Slclee 3631786Slclee if (ddi_copyin((const void *)arg, &p64, 3632786Slclee sizeof (struct partition64), flag)) { 3633786Slclee return (EFAULT); 3634786Slclee } 3635786Slclee 3636786Slclee buffer = kmem_alloc(EFI_MIN_ARRAY_SIZE, KM_SLEEP); 3637*9889SLarry.Liu@Sun.COM rval = DK_TG_READ(cl, buffer, 1, cl->cl_sys_blocksize, tg_cookie); 3638786Slclee if (rval != 0) 3639786Slclee goto done_error; 3640786Slclee 3641786Slclee cmlb_swap_efi_gpt(buffer); 3642786Slclee 3643786Slclee if ((rval = cmlb_validate_efi(buffer)) != 0) 3644786Slclee goto done_error; 3645786Slclee 3646786Slclee nparts = buffer->efi_gpt_NumberOfPartitionEntries; 3647786Slclee gpe_lba = buffer->efi_gpt_PartitionEntryLBA; 3648786Slclee if (p64.p_partno > nparts) { 3649786Slclee /* couldn't find it */ 3650786Slclee rval = ESRCH; 3651786Slclee goto done_error; 3652786Slclee } 3653786Slclee /* 3654786Slclee * if we're dealing with a partition that's out of the normal 3655786Slclee * 16K block, adjust accordingly 3656786Slclee */ 3657786Slclee gpe_lba += p64.p_partno / sizeof (efi_gpe_t); 36583525Sshidokht rval = DK_TG_READ(cl, buffer, gpe_lba, EFI_MIN_ARRAY_SIZE, tg_cookie); 3659786Slclee 3660786Slclee if (rval) { 3661786Slclee goto done_error; 3662786Slclee } 3663786Slclee partitions = (efi_gpe_t *)buffer; 3664786Slclee 3665786Slclee cmlb_swap_efi_gpe(nparts, partitions); 3666786Slclee 3667786Slclee partitions += p64.p_partno; 3668786Slclee bcopy(&partitions->efi_gpe_PartitionTypeGUID, &p64.p_type, 3669786Slclee sizeof (struct uuid)); 3670786Slclee p64.p_start = partitions->efi_gpe_StartingLBA; 3671786Slclee p64.p_size = partitions->efi_gpe_EndingLBA - 36723525Sshidokht p64.p_start + 1; 3673786Slclee 3674786Slclee if (ddi_copyout(&p64, (void *)arg, sizeof (struct partition64), flag)) 3675786Slclee rval = EFAULT; 3676786Slclee 3677786Slclee done_error: 3678786Slclee kmem_free(buffer, EFI_MIN_ARRAY_SIZE); 3679786Slclee return (rval); 3680786Slclee } 3681786Slclee 3682786Slclee 3683786Slclee /* 3684786Slclee * Function: cmlb_dkio_set_vtoc 3685786Slclee * 3686786Slclee * Description: This routine is the driver entry point for handling user 3687786Slclee * requests to set the current volume table of contents 3688786Slclee * (DKIOCSVTOC). 3689786Slclee * 36903525Sshidokht * Arguments: 36913525Sshidokht * dev the device number 36923525Sshidokht * arg pointer to user provided vtoc structure used to set the 3693786Slclee * current vtoc. 36943525Sshidokht * 36953525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 36963525Sshidokht * directly from the mode argument of ioctl(). 36973525Sshidokht * 36983525Sshidokht * tg_cookie cookie from target driver to be passed back to target 36993525Sshidokht * driver when we call back to it through tg_ops. 3700786Slclee * 3701786Slclee * Return Code: 0 3702786Slclee * EFAULT 3703786Slclee * ENXIO 3704786Slclee * EINVAL 3705786Slclee * ENOTSUP 3706786Slclee */ 3707786Slclee static int 37083525Sshidokht cmlb_dkio_set_vtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag, 37093525Sshidokht void *tg_cookie) 3710786Slclee { 3711786Slclee struct vtoc user_vtoc; 3712786Slclee int rval = 0; 37136318Sedp boolean_t internal; 37146318Sedp 37158863SEdward.Pilatowicz@Sun.COM internal = VOID2BOOLEAN( 37168863SEdward.Pilatowicz@Sun.COM (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0); 3717786Slclee 3718786Slclee #ifdef _MULTI_DATAMODEL 3719786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 3720786Slclee case DDI_MODEL_ILP32: { 3721786Slclee struct vtoc32 user_vtoc32; 3722786Slclee 3723786Slclee if (ddi_copyin((const void *)arg, &user_vtoc32, 3724786Slclee sizeof (struct vtoc32), flag)) { 3725786Slclee return (EFAULT); 3726786Slclee } 3727786Slclee vtoc32tovtoc(user_vtoc32, user_vtoc); 3728786Slclee break; 3729786Slclee } 3730786Slclee 3731786Slclee case DDI_MODEL_NONE: 3732786Slclee if (ddi_copyin((const void *)arg, &user_vtoc, 3733786Slclee sizeof (struct vtoc), flag)) { 3734786Slclee return (EFAULT); 3735786Slclee } 3736786Slclee break; 3737786Slclee } 3738786Slclee #else /* ! _MULTI_DATAMODEL */ 3739786Slclee if (ddi_copyin((const void *)arg, &user_vtoc, 3740786Slclee sizeof (struct vtoc), flag)) { 3741786Slclee return (EFAULT); 3742786Slclee } 3743786Slclee #endif /* _MULTI_DATAMODEL */ 3744786Slclee 37453525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 37467563SPrasad.Singamsetty@Sun.COM 37477563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) { 37483525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 37497563SPrasad.Singamsetty@Sun.COM return (EOVERFLOW); 3750786Slclee } 37513525Sshidokht 37523525Sshidokht #if defined(__i386) || defined(__amd64) 37533525Sshidokht if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) { 37543525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 37553525Sshidokht return (EINVAL); 37563525Sshidokht } 37573525Sshidokht #endif 37583525Sshidokht 37593525Sshidokht if (cl->cl_g.dkg_ncyl == 0) { 37603525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3761786Slclee return (EINVAL); 3762786Slclee } 3763786Slclee 37643525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 37653525Sshidokht cmlb_clear_efi(cl, tg_cookie); 37663525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd"); 37673525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd,raw"); 37688570SSriram.Popuri@sun.com 37698570SSriram.Popuri@sun.com /* 37708570SSriram.Popuri@sun.com * cmlb_dkio_set_vtoc creates duplicate minor nodes when 37718570SSriram.Popuri@sun.com * relabeling an SMI disk. To avoid that we remove them 37728570SSriram.Popuri@sun.com * before creating. 37738570SSriram.Popuri@sun.com * It should be OK to remove a non-existed minor node. 37748570SSriram.Popuri@sun.com */ 37758570SSriram.Popuri@sun.com ddi_remove_minor_node(CMLB_DEVINFO(cl), "h"); 37768570SSriram.Popuri@sun.com ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw"); 37778570SSriram.Popuri@sun.com 37786318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h", 3779786Slclee S_IFBLK, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 37806318Sedp cl->cl_node_type, NULL, internal); 37816318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h,raw", 3782786Slclee S_IFCHR, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 37836318Sedp cl->cl_node_type, NULL, internal); 37843525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 37853525Sshidokht 37863525Sshidokht if ((rval = cmlb_build_label_vtoc(cl, &user_vtoc)) == 0) { 37873525Sshidokht if ((rval = cmlb_write_label(cl, tg_cookie)) == 0) { 37888863SEdward.Pilatowicz@Sun.COM if (cmlb_validate_geometry(cl, 37898863SEdward.Pilatowicz@Sun.COM B_TRUE, 0, tg_cookie) != 0) { 37903525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 3791786Slclee "cmlb_dkio_set_vtoc: " 3792786Slclee "Failed validate geometry\n"); 3793786Slclee } 37947563SPrasad.Singamsetty@Sun.COM cl->cl_msglog_flag |= CMLB_ALLOW_2TB_WARN; 3795786Slclee } 3796786Slclee } 37973525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3798786Slclee return (rval); 3799786Slclee } 3800786Slclee 38017563SPrasad.Singamsetty@Sun.COM /* 38027563SPrasad.Singamsetty@Sun.COM * Function: cmlb_dkio_set_extvtoc 38037563SPrasad.Singamsetty@Sun.COM */ 38047563SPrasad.Singamsetty@Sun.COM static int 38057563SPrasad.Singamsetty@Sun.COM cmlb_dkio_set_extvtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag, 38067563SPrasad.Singamsetty@Sun.COM void *tg_cookie) 38077563SPrasad.Singamsetty@Sun.COM { 38087563SPrasad.Singamsetty@Sun.COM int rval = 0; 38097563SPrasad.Singamsetty@Sun.COM struct vtoc user_vtoc; 38108749SShidokht.Yadegari@Sun.COM boolean_t internal; 38118749SShidokht.Yadegari@Sun.COM 38127563SPrasad.Singamsetty@Sun.COM 38137563SPrasad.Singamsetty@Sun.COM /* 38147563SPrasad.Singamsetty@Sun.COM * Checking callers data model does not make much sense here 38157563SPrasad.Singamsetty@Sun.COM * since extvtoc will always be equivalent to 64bit vtoc. 38167563SPrasad.Singamsetty@Sun.COM * What is important is whether the kernel is in 32 or 64 bit 38177563SPrasad.Singamsetty@Sun.COM */ 38187563SPrasad.Singamsetty@Sun.COM 38197563SPrasad.Singamsetty@Sun.COM #ifdef _LP64 38207563SPrasad.Singamsetty@Sun.COM if (ddi_copyin((const void *)arg, &user_vtoc, 38217563SPrasad.Singamsetty@Sun.COM sizeof (struct extvtoc), flag)) { 38227563SPrasad.Singamsetty@Sun.COM return (EFAULT); 38237563SPrasad.Singamsetty@Sun.COM } 38247563SPrasad.Singamsetty@Sun.COM #else 38257563SPrasad.Singamsetty@Sun.COM struct extvtoc user_extvtoc; 38267563SPrasad.Singamsetty@Sun.COM if (ddi_copyin((const void *)arg, &user_extvtoc, 38277563SPrasad.Singamsetty@Sun.COM sizeof (struct extvtoc), flag)) { 38287563SPrasad.Singamsetty@Sun.COM return (EFAULT); 38297563SPrasad.Singamsetty@Sun.COM } 38307563SPrasad.Singamsetty@Sun.COM 38317563SPrasad.Singamsetty@Sun.COM vtoctovtoc32(user_extvtoc, user_vtoc); 38327563SPrasad.Singamsetty@Sun.COM #endif 38337563SPrasad.Singamsetty@Sun.COM 38348863SEdward.Pilatowicz@Sun.COM internal = VOID2BOOLEAN( 38358863SEdward.Pilatowicz@Sun.COM (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0); 38367563SPrasad.Singamsetty@Sun.COM mutex_enter(CMLB_MUTEX(cl)); 38377563SPrasad.Singamsetty@Sun.COM #if defined(__i386) || defined(__amd64) 38387563SPrasad.Singamsetty@Sun.COM if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) { 38397563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 38407563SPrasad.Singamsetty@Sun.COM return (EINVAL); 38417563SPrasad.Singamsetty@Sun.COM } 38427563SPrasad.Singamsetty@Sun.COM #endif 38437563SPrasad.Singamsetty@Sun.COM 38447563SPrasad.Singamsetty@Sun.COM if (cl->cl_g.dkg_ncyl == 0) { 38457563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 38467563SPrasad.Singamsetty@Sun.COM return (EINVAL); 38477563SPrasad.Singamsetty@Sun.COM } 38487563SPrasad.Singamsetty@Sun.COM 38497563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 38507563SPrasad.Singamsetty@Sun.COM cmlb_clear_efi(cl, tg_cookie); 38517563SPrasad.Singamsetty@Sun.COM ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd"); 38527563SPrasad.Singamsetty@Sun.COM ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd,raw"); 38538749SShidokht.Yadegari@Sun.COM (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h", 38547563SPrasad.Singamsetty@Sun.COM S_IFBLK, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 38558749SShidokht.Yadegari@Sun.COM cl->cl_node_type, NULL, internal); 38568749SShidokht.Yadegari@Sun.COM (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h,raw", 38577563SPrasad.Singamsetty@Sun.COM S_IFCHR, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 38588749SShidokht.Yadegari@Sun.COM cl->cl_node_type, NULL, internal); 38598749SShidokht.Yadegari@Sun.COM 38607563SPrasad.Singamsetty@Sun.COM mutex_enter(CMLB_MUTEX(cl)); 38617563SPrasad.Singamsetty@Sun.COM 38627563SPrasad.Singamsetty@Sun.COM if ((rval = cmlb_build_label_vtoc(cl, &user_vtoc)) == 0) { 38637563SPrasad.Singamsetty@Sun.COM if ((rval = cmlb_write_label(cl, tg_cookie)) == 0) { 38648863SEdward.Pilatowicz@Sun.COM if (cmlb_validate_geometry(cl, 38658863SEdward.Pilatowicz@Sun.COM B_TRUE, 0, tg_cookie) != 0) { 38667563SPrasad.Singamsetty@Sun.COM cmlb_dbg(CMLB_ERROR, cl, 38677563SPrasad.Singamsetty@Sun.COM "cmlb_dkio_set_vtoc: " 38687563SPrasad.Singamsetty@Sun.COM "Failed validate geometry\n"); 38697563SPrasad.Singamsetty@Sun.COM } 38707563SPrasad.Singamsetty@Sun.COM } 38717563SPrasad.Singamsetty@Sun.COM } 38727563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 38737563SPrasad.Singamsetty@Sun.COM return (rval); 38747563SPrasad.Singamsetty@Sun.COM } 3875786Slclee 3876786Slclee /* 3877786Slclee * Function: cmlb_build_label_vtoc 3878786Slclee * 3879786Slclee * Description: This routine updates the driver soft state current volume table 3880786Slclee * of contents based on a user specified vtoc. 3881786Slclee * 38823525Sshidokht * Arguments: cl - driver soft state (unit) structure 3883786Slclee * user_vtoc - pointer to vtoc structure specifying vtoc to be used 3884786Slclee * to update the driver soft state. 3885786Slclee * 3886786Slclee * Return Code: 0 3887786Slclee * EINVAL 3888786Slclee */ 3889786Slclee static int 38903525Sshidokht cmlb_build_label_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc) 3891786Slclee { 3892786Slclee struct dk_map *lmap; 3893786Slclee struct partition *vpart; 38947563SPrasad.Singamsetty@Sun.COM uint_t nblks; 3895786Slclee #if defined(_SUNOS_VTOC_8) 3896786Slclee int ncyl; 3897786Slclee struct dk_map2 *lpart; 3898786Slclee #endif /* defined(_SUNOS_VTOC_8) */ 3899786Slclee int i; 3900786Slclee 39013525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 3902786Slclee 3903786Slclee /* Sanity-check the vtoc */ 3904786Slclee if (user_vtoc->v_sanity != VTOC_SANE || 39053525Sshidokht user_vtoc->v_sectorsz != cl->cl_sys_blocksize || 3906786Slclee user_vtoc->v_nparts != V_NUMPAR) { 39073525Sshidokht cmlb_dbg(CMLB_INFO, cl, 3908786Slclee "cmlb_build_label_vtoc: vtoc not valid\n"); 3909786Slclee return (EINVAL); 3910786Slclee } 3911786Slclee 39123525Sshidokht nblks = cl->cl_g.dkg_nsect * cl->cl_g.dkg_nhead; 3913786Slclee if (nblks == 0) { 39143525Sshidokht cmlb_dbg(CMLB_INFO, cl, 3915786Slclee "cmlb_build_label_vtoc: geom nblks is 0\n"); 3916786Slclee return (EINVAL); 3917786Slclee } 3918786Slclee 3919786Slclee #if defined(_SUNOS_VTOC_8) 3920786Slclee vpart = user_vtoc->v_part; 3921786Slclee for (i = 0; i < V_NUMPAR; i++) { 39227563SPrasad.Singamsetty@Sun.COM if (((unsigned)vpart->p_start % nblks) != 0) { 39233525Sshidokht cmlb_dbg(CMLB_INFO, cl, 3924786Slclee "cmlb_build_label_vtoc: p_start not multiply of" 3925786Slclee "nblks part %d p_start %d nblks %d\n", i, 3926786Slclee vpart->p_start, nblks); 3927786Slclee return (EINVAL); 3928786Slclee } 39297563SPrasad.Singamsetty@Sun.COM ncyl = (unsigned)vpart->p_start / nblks; 39307563SPrasad.Singamsetty@Sun.COM ncyl += (unsigned)vpart->p_size / nblks; 39317563SPrasad.Singamsetty@Sun.COM if (((unsigned)vpart->p_size % nblks) != 0) { 3932786Slclee ncyl++; 3933786Slclee } 39343525Sshidokht if (ncyl > (int)cl->cl_g.dkg_ncyl) { 39353525Sshidokht cmlb_dbg(CMLB_INFO, cl, 3936786Slclee "cmlb_build_label_vtoc: ncyl %d > dkg_ncyl %d" 3937786Slclee "p_size %ld p_start %ld nblks %d part number %d" 3938786Slclee "tag %d\n", 39393525Sshidokht ncyl, cl->cl_g.dkg_ncyl, vpart->p_size, 3940786Slclee vpart->p_start, nblks, 3941786Slclee i, vpart->p_tag); 3942786Slclee 3943786Slclee return (EINVAL); 3944786Slclee } 3945786Slclee vpart++; 3946786Slclee } 3947786Slclee #endif /* defined(_SUNOS_VTOC_8) */ 3948786Slclee 3949786Slclee /* Put appropriate vtoc structure fields into the disk label */ 3950786Slclee #if defined(_SUNOS_VTOC_16) 3951786Slclee /* 3952786Slclee * The vtoc is always a 32bit data structure to maintain the 3953786Slclee * on-disk format. Convert "in place" instead of doing bcopy. 3954786Slclee */ 39553525Sshidokht vtoctovtoc32((*user_vtoc), (*((struct vtoc32 *)&(cl->cl_vtoc)))); 3956786Slclee 3957786Slclee /* 3958786Slclee * in the 16-slice vtoc, starting sectors are expressed in 3959786Slclee * numbers *relative* to the start of the Solaris fdisk partition. 3960786Slclee */ 39613525Sshidokht lmap = cl->cl_map; 3962786Slclee vpart = user_vtoc->v_part; 3963786Slclee 3964786Slclee for (i = 0; i < (int)user_vtoc->v_nparts; i++, lmap++, vpart++) { 39657563SPrasad.Singamsetty@Sun.COM lmap->dkl_cylno = (unsigned)vpart->p_start / nblks; 39667563SPrasad.Singamsetty@Sun.COM lmap->dkl_nblk = (unsigned)vpart->p_size; 3967786Slclee } 3968786Slclee 3969786Slclee #elif defined(_SUNOS_VTOC_8) 3970786Slclee 39713525Sshidokht cl->cl_vtoc.v_bootinfo[0] = (uint32_t)user_vtoc->v_bootinfo[0]; 39723525Sshidokht cl->cl_vtoc.v_bootinfo[1] = (uint32_t)user_vtoc->v_bootinfo[1]; 39733525Sshidokht cl->cl_vtoc.v_bootinfo[2] = (uint32_t)user_vtoc->v_bootinfo[2]; 39743525Sshidokht 39753525Sshidokht cl->cl_vtoc.v_sanity = (uint32_t)user_vtoc->v_sanity; 39763525Sshidokht cl->cl_vtoc.v_version = (uint32_t)user_vtoc->v_version; 39773525Sshidokht 39783525Sshidokht bcopy(user_vtoc->v_volume, cl->cl_vtoc.v_volume, LEN_DKL_VVOL); 39793525Sshidokht 39803525Sshidokht cl->cl_vtoc.v_nparts = user_vtoc->v_nparts; 3981786Slclee 3982786Slclee for (i = 0; i < 10; i++) 39833525Sshidokht cl->cl_vtoc.v_reserved[i] = user_vtoc->v_reserved[i]; 3984786Slclee 3985786Slclee /* 3986786Slclee * Note the conversion from starting sector number 3987786Slclee * to starting cylinder number. 3988786Slclee * Return error if division results in a remainder. 3989786Slclee */ 39903525Sshidokht lmap = cl->cl_map; 39913525Sshidokht lpart = cl->cl_vtoc.v_part; 3992786Slclee vpart = user_vtoc->v_part; 3993786Slclee 3994786Slclee for (i = 0; i < (int)user_vtoc->v_nparts; i++) { 3995786Slclee lpart->p_tag = vpart->p_tag; 3996786Slclee lpart->p_flag = vpart->p_flag; 39977563SPrasad.Singamsetty@Sun.COM lmap->dkl_cylno = (unsigned)vpart->p_start / nblks; 39987563SPrasad.Singamsetty@Sun.COM lmap->dkl_nblk = (unsigned)vpart->p_size; 3999786Slclee 4000786Slclee lmap++; 4001786Slclee lpart++; 4002786Slclee vpart++; 4003786Slclee 4004786Slclee /* (4387723) */ 4005786Slclee #ifdef _LP64 4006786Slclee if (user_vtoc->timestamp[i] > TIME32_MAX) { 40073525Sshidokht cl->cl_vtoc.v_timestamp[i] = TIME32_MAX; 4008786Slclee } else { 40093525Sshidokht cl->cl_vtoc.v_timestamp[i] = user_vtoc->timestamp[i]; 4010786Slclee } 4011786Slclee #else 40123525Sshidokht cl->cl_vtoc.v_timestamp[i] = user_vtoc->timestamp[i]; 4013786Slclee #endif 4014786Slclee } 4015786Slclee 40163525Sshidokht bcopy(user_vtoc->v_asciilabel, cl->cl_asciilabel, LEN_DKL_ASCII); 4017786Slclee #else 4018786Slclee #error "No VTOC format defined." 4019786Slclee #endif 4020786Slclee return (0); 4021786Slclee } 4022786Slclee 4023786Slclee /* 4024786Slclee * Function: cmlb_clear_efi 4025786Slclee * 4026786Slclee * Description: This routine clears all EFI labels. 4027786Slclee * 40283525Sshidokht * Arguments: 40293525Sshidokht * cl driver soft state (unit) structure 4030786Slclee * 40313525Sshidokht * tg_cookie cookie from target driver to be passed back to target 40323525Sshidokht * driver when we call back to it through tg_ops. 4033786Slclee * Return Code: void 4034786Slclee */ 4035786Slclee static void 40363525Sshidokht cmlb_clear_efi(struct cmlb_lun *cl, void *tg_cookie) 4037786Slclee { 4038786Slclee efi_gpt_t *gpt; 4039786Slclee diskaddr_t cap; 4040786Slclee int rval; 4041786Slclee 40423525Sshidokht ASSERT(!mutex_owned(CMLB_MUTEX(cl))); 40433525Sshidokht 40443525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 40453525Sshidokht cl->cl_reserved = -1; 40463525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4047786Slclee 4048*9889SLarry.Liu@Sun.COM gpt = kmem_alloc(cl->cl_sys_blocksize, KM_SLEEP); 4049*9889SLarry.Liu@Sun.COM 4050*9889SLarry.Liu@Sun.COM if (DK_TG_READ(cl, gpt, 1, cl->cl_sys_blocksize, tg_cookie) != 0) { 4051786Slclee goto done; 4052786Slclee } 4053786Slclee 4054786Slclee cmlb_swap_efi_gpt(gpt); 4055786Slclee rval = cmlb_validate_efi(gpt); 4056786Slclee if (rval == 0) { 4057786Slclee /* clear primary */ 4058786Slclee bzero(gpt, sizeof (efi_gpt_t)); 4059*9889SLarry.Liu@Sun.COM if (rval = DK_TG_WRITE(cl, gpt, 1, cl->cl_sys_blocksize, 4060*9889SLarry.Liu@Sun.COM tg_cookie)) { 40613525Sshidokht cmlb_dbg(CMLB_INFO, cl, 40623525Sshidokht "cmlb_clear_efi: clear primary label failed\n"); 4063786Slclee } 4064786Slclee } 4065786Slclee /* the backup */ 40663525Sshidokht rval = DK_TG_GETCAP(cl, &cap, tg_cookie); 4067786Slclee if (rval) { 4068786Slclee goto done; 4069786Slclee } 4070786Slclee 4071*9889SLarry.Liu@Sun.COM if ((rval = DK_TG_READ(cl, gpt, cap - 1, cl->cl_sys_blocksize, 4072*9889SLarry.Liu@Sun.COM tg_cookie)) != 0) { 4073786Slclee goto done; 4074786Slclee } 4075786Slclee cmlb_swap_efi_gpt(gpt); 4076786Slclee rval = cmlb_validate_efi(gpt); 4077786Slclee if (rval == 0) { 4078786Slclee /* clear backup */ 40793525Sshidokht cmlb_dbg(CMLB_TRACE, cl, 4080786Slclee "cmlb_clear_efi clear backup@%lu\n", cap - 1); 4081786Slclee bzero(gpt, sizeof (efi_gpt_t)); 4082*9889SLarry.Liu@Sun.COM if ((rval = DK_TG_WRITE(cl, gpt, cap - 1, cl->cl_sys_blocksize, 40833525Sshidokht tg_cookie))) { 40843525Sshidokht cmlb_dbg(CMLB_INFO, cl, 40853525Sshidokht "cmlb_clear_efi: clear backup label failed\n"); 40863525Sshidokht } 40873525Sshidokht } else { 40883525Sshidokht /* 40893525Sshidokht * Refer to comments related to off-by-1 at the 40903525Sshidokht * header of this file 40913525Sshidokht */ 40923525Sshidokht if ((rval = DK_TG_READ(cl, gpt, cap - 2, 4093*9889SLarry.Liu@Sun.COM cl->cl_sys_blocksize, tg_cookie)) != 0) { 40943525Sshidokht goto done; 40953525Sshidokht } 40963525Sshidokht cmlb_swap_efi_gpt(gpt); 40973525Sshidokht rval = cmlb_validate_efi(gpt); 40983525Sshidokht if (rval == 0) { 40993525Sshidokht /* clear legacy backup EFI label */ 41003525Sshidokht cmlb_dbg(CMLB_TRACE, cl, 41013525Sshidokht "cmlb_clear_efi clear legacy backup@%lu\n", 41023525Sshidokht cap - 2); 41033525Sshidokht bzero(gpt, sizeof (efi_gpt_t)); 41043525Sshidokht if ((rval = DK_TG_WRITE(cl, gpt, cap - 2, 4105*9889SLarry.Liu@Sun.COM cl->cl_sys_blocksize, tg_cookie))) { 41063525Sshidokht cmlb_dbg(CMLB_INFO, cl, 41073525Sshidokht "cmlb_clear_efi: clear legacy backup label " 41083525Sshidokht "failed\n"); 41093525Sshidokht } 4110786Slclee } 4111786Slclee } 4112786Slclee 4113786Slclee done: 4114*9889SLarry.Liu@Sun.COM kmem_free(gpt, cl->cl_sys_blocksize); 4115786Slclee } 4116786Slclee 4117786Slclee /* 4118786Slclee * Function: cmlb_set_vtoc 4119786Slclee * 4120786Slclee * Description: This routine writes data to the appropriate positions 4121786Slclee * 41223525Sshidokht * Arguments: 41233525Sshidokht * cl driver soft state (unit) structure 41243525Sshidokht * 41253525Sshidokht * dkl the data to be written 41263525Sshidokht * 41273525Sshidokht * tg_cookie cookie from target driver to be passed back to target 41283525Sshidokht * driver when we call back to it through tg_ops. 4129786Slclee * 4130786Slclee * Return: void 4131786Slclee */ 4132786Slclee static int 41333525Sshidokht cmlb_set_vtoc(struct cmlb_lun *cl, struct dk_label *dkl, void *tg_cookie) 4134786Slclee { 4135786Slclee uint_t label_addr; 4136786Slclee int sec; 41377563SPrasad.Singamsetty@Sun.COM diskaddr_t blk; 4138786Slclee int head; 4139786Slclee int cyl; 4140786Slclee int rval; 4141786Slclee 4142786Slclee #if defined(__i386) || defined(__amd64) 41433525Sshidokht label_addr = cl->cl_solaris_offset + DK_LABEL_LOC; 4144786Slclee #else 4145786Slclee /* Write the primary label at block 0 of the solaris partition. */ 4146786Slclee label_addr = 0; 4147786Slclee #endif 4148786Slclee 41493525Sshidokht rval = DK_TG_WRITE(cl, dkl, label_addr, cl->cl_sys_blocksize, 41503525Sshidokht tg_cookie); 4151786Slclee 4152786Slclee if (rval != 0) { 4153786Slclee return (rval); 4154786Slclee } 4155786Slclee 4156786Slclee /* 4157786Slclee * Calculate where the backup labels go. They are always on 4158786Slclee * the last alternate cylinder, but some older drives put them 4159786Slclee * on head 2 instead of the last head. They are always on the 4160786Slclee * first 5 odd sectors of the appropriate track. 4161786Slclee * 4162786Slclee * We have no choice at this point, but to believe that the 4163786Slclee * disk label is valid. Use the geometry of the disk 4164786Slclee * as described in the label. 4165786Slclee */ 4166786Slclee cyl = dkl->dkl_ncyl + dkl->dkl_acyl - 1; 4167786Slclee head = dkl->dkl_nhead - 1; 4168786Slclee 4169786Slclee /* 4170786Slclee * Write and verify the backup labels. Make sure we don't try to 4171786Slclee * write past the last cylinder. 4172786Slclee */ 4173786Slclee for (sec = 1; ((sec < 5 * 2 + 1) && (sec < dkl->dkl_nsect)); sec += 2) { 41747563SPrasad.Singamsetty@Sun.COM blk = (diskaddr_t)( 4175786Slclee (cyl * ((dkl->dkl_nhead * dkl->dkl_nsect) - dkl->dkl_apc)) + 4176786Slclee (head * dkl->dkl_nsect) + sec); 4177786Slclee #if defined(__i386) || defined(__amd64) 41783525Sshidokht blk += cl->cl_solaris_offset; 4179786Slclee #endif 41803525Sshidokht rval = DK_TG_WRITE(cl, dkl, blk, cl->cl_sys_blocksize, 41813525Sshidokht tg_cookie); 41823525Sshidokht cmlb_dbg(CMLB_INFO, cl, 41837563SPrasad.Singamsetty@Sun.COM "cmlb_set_vtoc: wrote backup label %llx\n", blk); 4184786Slclee if (rval != 0) { 4185786Slclee goto exit; 4186786Slclee } 4187786Slclee } 4188786Slclee exit: 4189786Slclee return (rval); 4190786Slclee } 4191786Slclee 4192786Slclee /* 4193786Slclee * Function: cmlb_clear_vtoc 4194786Slclee * 4195786Slclee * Description: This routine clears out the VTOC labels. 4196786Slclee * 41973525Sshidokht * Arguments: 41983525Sshidokht * cl driver soft state (unit) structure 41993525Sshidokht * 42003525Sshidokht * tg_cookie cookie from target driver to be passed back to target 42013525Sshidokht * driver when we call back to it through tg_ops. 4202786Slclee * 4203786Slclee * Return: void 4204786Slclee */ 4205786Slclee static void 42063525Sshidokht cmlb_clear_vtoc(struct cmlb_lun *cl, void *tg_cookie) 4207786Slclee { 4208786Slclee struct dk_label *dkl; 4209786Slclee 42103525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4211*9889SLarry.Liu@Sun.COM dkl = kmem_zalloc(cl->cl_sys_blocksize, KM_SLEEP); 42123525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 4213786Slclee /* 4214786Slclee * cmlb_set_vtoc uses these fields in order to figure out 4215786Slclee * where to overwrite the backup labels 4216786Slclee */ 42173525Sshidokht dkl->dkl_apc = cl->cl_g.dkg_apc; 42183525Sshidokht dkl->dkl_ncyl = cl->cl_g.dkg_ncyl; 42193525Sshidokht dkl->dkl_acyl = cl->cl_g.dkg_acyl; 42203525Sshidokht dkl->dkl_nhead = cl->cl_g.dkg_nhead; 42213525Sshidokht dkl->dkl_nsect = cl->cl_g.dkg_nsect; 42223525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 42233525Sshidokht (void) cmlb_set_vtoc(cl, dkl, tg_cookie); 4224*9889SLarry.Liu@Sun.COM kmem_free(dkl, cl->cl_sys_blocksize); 4225786Slclee 42263525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 4227786Slclee } 4228786Slclee 4229786Slclee /* 4230786Slclee * Function: cmlb_write_label 4231786Slclee * 4232786Slclee * Description: This routine will validate and write the driver soft state vtoc 4233786Slclee * contents to the device. 4234786Slclee * 42353525Sshidokht * Arguments: 42363525Sshidokht * cl cmlb handle 42373525Sshidokht * 42383525Sshidokht * tg_cookie cookie from target driver to be passed back to target 42393525Sshidokht * driver when we call back to it through tg_ops. 42403525Sshidokht * 4241786Slclee * 4242786Slclee * Return Code: the code returned by cmlb_send_scsi_cmd() 4243786Slclee * 0 4244786Slclee * EINVAL 4245786Slclee * ENXIO 4246786Slclee * ENOMEM 4247786Slclee */ 4248786Slclee static int 42493525Sshidokht cmlb_write_label(struct cmlb_lun *cl, void *tg_cookie) 4250786Slclee { 4251786Slclee struct dk_label *dkl; 4252786Slclee short sum; 4253786Slclee short *sp; 4254786Slclee int i; 4255786Slclee int rval; 4256786Slclee 42573525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 42583525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4259*9889SLarry.Liu@Sun.COM dkl = kmem_zalloc(cl->cl_sys_blocksize, KM_SLEEP); 42603525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 42613525Sshidokht 42623525Sshidokht bcopy(&cl->cl_vtoc, &dkl->dkl_vtoc, sizeof (struct dk_vtoc)); 42633525Sshidokht dkl->dkl_rpm = cl->cl_g.dkg_rpm; 42643525Sshidokht dkl->dkl_pcyl = cl->cl_g.dkg_pcyl; 42653525Sshidokht dkl->dkl_apc = cl->cl_g.dkg_apc; 42663525Sshidokht dkl->dkl_intrlv = cl->cl_g.dkg_intrlv; 42673525Sshidokht dkl->dkl_ncyl = cl->cl_g.dkg_ncyl; 42683525Sshidokht dkl->dkl_acyl = cl->cl_g.dkg_acyl; 42693525Sshidokht dkl->dkl_nhead = cl->cl_g.dkg_nhead; 42703525Sshidokht dkl->dkl_nsect = cl->cl_g.dkg_nsect; 4271786Slclee 4272786Slclee #if defined(_SUNOS_VTOC_8) 42733525Sshidokht dkl->dkl_obs1 = cl->cl_g.dkg_obs1; 42743525Sshidokht dkl->dkl_obs2 = cl->cl_g.dkg_obs2; 42753525Sshidokht dkl->dkl_obs3 = cl->cl_g.dkg_obs3; 4276786Slclee for (i = 0; i < NDKMAP; i++) { 42773525Sshidokht dkl->dkl_map[i].dkl_cylno = cl->cl_map[i].dkl_cylno; 42783525Sshidokht dkl->dkl_map[i].dkl_nblk = cl->cl_map[i].dkl_nblk; 4279786Slclee } 42803525Sshidokht bcopy(cl->cl_asciilabel, dkl->dkl_asciilabel, LEN_DKL_ASCII); 4281786Slclee #elif defined(_SUNOS_VTOC_16) 42823525Sshidokht dkl->dkl_skew = cl->cl_dkg_skew; 4283786Slclee #else 4284786Slclee #error "No VTOC format defined." 4285786Slclee #endif 4286786Slclee 4287786Slclee dkl->dkl_magic = DKL_MAGIC; 42883525Sshidokht dkl->dkl_write_reinstruct = cl->cl_g.dkg_write_reinstruct; 42893525Sshidokht dkl->dkl_read_reinstruct = cl->cl_g.dkg_read_reinstruct; 4290786Slclee 4291786Slclee /* Construct checksum for the new disk label */ 4292786Slclee sum = 0; 4293786Slclee sp = (short *)dkl; 4294786Slclee i = sizeof (struct dk_label) / sizeof (short); 4295786Slclee while (i--) { 4296786Slclee sum ^= *sp++; 4297786Slclee } 4298786Slclee dkl->dkl_cksum = sum; 4299786Slclee 43003525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 43013525Sshidokht 43023525Sshidokht rval = cmlb_set_vtoc(cl, dkl, tg_cookie); 4303786Slclee exit: 4304*9889SLarry.Liu@Sun.COM kmem_free(dkl, cl->cl_sys_blocksize); 43053525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 4306786Slclee return (rval); 4307786Slclee } 4308786Slclee 4309786Slclee static int 43103525Sshidokht cmlb_dkio_set_efi(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag, 43113525Sshidokht void *tg_cookie) 4312786Slclee { 4313786Slclee dk_efi_t user_efi; 4314786Slclee int rval = 0; 4315786Slclee void *buffer; 43163525Sshidokht diskaddr_t tgt_lba; 43176318Sedp boolean_t internal; 4318786Slclee 4319786Slclee if (ddi_copyin(arg, &user_efi, sizeof (dk_efi_t), flag)) 4320786Slclee return (EFAULT); 4321786Slclee 43228863SEdward.Pilatowicz@Sun.COM internal = VOID2BOOLEAN( 43238863SEdward.Pilatowicz@Sun.COM (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0); 43246318Sedp 4325786Slclee user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64; 4326786Slclee 4327786Slclee buffer = kmem_alloc(user_efi.dki_length, KM_SLEEP); 4328786Slclee if (ddi_copyin(user_efi.dki_data, buffer, user_efi.dki_length, flag)) { 4329786Slclee rval = EFAULT; 4330786Slclee } else { 4331786Slclee /* 4332786Slclee * let's clear the vtoc labels and clear the softstate 4333786Slclee * vtoc. 4334786Slclee */ 43353525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 43363525Sshidokht if (cl->cl_vtoc.v_sanity == VTOC_SANE) { 43373525Sshidokht cmlb_dbg(CMLB_TRACE, cl, 43383525Sshidokht "cmlb_dkio_set_efi: CLEAR VTOC\n"); 43397563SPrasad.Singamsetty@Sun.COM if (cl->cl_label_from_media == CMLB_LABEL_VTOC) 43403525Sshidokht cmlb_clear_vtoc(cl, tg_cookie); 43413525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc)); 43423525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 43433525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "h"); 43443525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw"); 43456318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd", 4346786Slclee S_IFBLK, 4347786Slclee (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 43486318Sedp cl->cl_node_type, NULL, internal); 43496318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd,raw", 4350786Slclee S_IFCHR, 4351786Slclee (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 43526318Sedp cl->cl_node_type, NULL, internal); 4353786Slclee } else 43543525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 43553525Sshidokht 43563525Sshidokht tgt_lba = user_efi.dki_lba; 43573525Sshidokht 43583525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 43593525Sshidokht if ((cmlb_check_update_blockcount(cl, tg_cookie) != 0) || 43603525Sshidokht (cl->cl_tgt_blocksize == 0)) { 43613525Sshidokht kmem_free(buffer, user_efi.dki_length); 43623525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 43633525Sshidokht return (EINVAL); 43643525Sshidokht } 43653525Sshidokht if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) 43663525Sshidokht tgt_lba = tgt_lba * 43673525Sshidokht cl->cl_tgt_blocksize / cl->cl_sys_blocksize; 43683525Sshidokht 43693525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 43703525Sshidokht rval = DK_TG_WRITE(cl, buffer, tgt_lba, user_efi.dki_length, 43713525Sshidokht tg_cookie); 43723525Sshidokht 4373786Slclee if (rval == 0) { 43743525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 43758863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE; 43763525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4377786Slclee } 4378786Slclee } 4379786Slclee kmem_free(buffer, user_efi.dki_length); 4380786Slclee return (rval); 4381786Slclee } 4382786Slclee 4383786Slclee /* 4384786Slclee * Function: cmlb_dkio_get_mboot 4385786Slclee * 4386786Slclee * Description: This routine is the driver entry point for handling user 4387786Slclee * requests to get the current device mboot (DKIOCGMBOOT) 4388786Slclee * 4389786Slclee * Arguments: 43903525Sshidokht * arg pointer to user provided mboot structure specifying 4391786Slclee * the current mboot. 43923525Sshidokht * 43933525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 43943525Sshidokht * directly from the mode argument of ioctl(). 43953525Sshidokht * 43963525Sshidokht * tg_cookie cookie from target driver to be passed back to target 43973525Sshidokht * driver when we call back to it through tg_ops. 4398786Slclee * 4399786Slclee * Return Code: 0 4400786Slclee * EINVAL 4401786Slclee * EFAULT 4402786Slclee * ENXIO 4403786Slclee */ 4404786Slclee static int 44053525Sshidokht cmlb_dkio_get_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie) 4406786Slclee { 4407786Slclee struct mboot *mboot; 4408786Slclee int rval; 4409786Slclee size_t buffer_size; 4410786Slclee 4411786Slclee 4412786Slclee #if defined(_SUNOS_VTOC_8) 44133525Sshidokht if ((!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) || (arg == NULL)) { 4414786Slclee #elif defined(_SUNOS_VTOC_16) 4415786Slclee if (arg == NULL) { 4416786Slclee #endif 4417786Slclee return (EINVAL); 4418786Slclee } 4419786Slclee 4420786Slclee /* 4421786Slclee * Read the mboot block, located at absolute block 0 on the target. 4422786Slclee */ 4423*9889SLarry.Liu@Sun.COM buffer_size = cl->cl_sys_blocksize; 4424786Slclee 44253525Sshidokht cmlb_dbg(CMLB_TRACE, cl, 4426786Slclee "cmlb_dkio_get_mboot: allocation size: 0x%x\n", buffer_size); 4427786Slclee 4428786Slclee mboot = kmem_zalloc(buffer_size, KM_SLEEP); 44293525Sshidokht if ((rval = DK_TG_READ(cl, mboot, 0, buffer_size, tg_cookie)) == 0) { 4430786Slclee if (ddi_copyout(mboot, (void *)arg, 4431786Slclee sizeof (struct mboot), flag) != 0) { 4432786Slclee rval = EFAULT; 4433786Slclee } 4434786Slclee } 4435786Slclee kmem_free(mboot, buffer_size); 4436786Slclee return (rval); 4437786Slclee } 4438786Slclee 4439786Slclee 4440786Slclee /* 4441786Slclee * Function: cmlb_dkio_set_mboot 4442786Slclee * 4443786Slclee * Description: This routine is the driver entry point for handling user 4444786Slclee * requests to validate and set the device master boot 4445786Slclee * (DKIOCSMBOOT). 4446786Slclee * 4447786Slclee * Arguments: 44483525Sshidokht * arg pointer to user provided mboot structure used to set the 4449786Slclee * master boot. 44503525Sshidokht * 44513525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 44523525Sshidokht * directly from the mode argument of ioctl(). 44533525Sshidokht * 44543525Sshidokht * tg_cookie cookie from target driver to be passed back to target 44553525Sshidokht * driver when we call back to it through tg_ops. 4456786Slclee * 4457786Slclee * Return Code: 0 4458786Slclee * EINVAL 4459786Slclee * EFAULT 4460786Slclee * ENXIO 4461786Slclee */ 4462786Slclee static int 44633525Sshidokht cmlb_dkio_set_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie) 4464786Slclee { 4465786Slclee struct mboot *mboot = NULL; 4466786Slclee int rval; 4467786Slclee ushort_t magic; 4468786Slclee 4469786Slclee 44703525Sshidokht ASSERT(!mutex_owned(CMLB_MUTEX(cl))); 4471786Slclee 4472786Slclee #if defined(_SUNOS_VTOC_8) 44733525Sshidokht if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) { 4474786Slclee return (EINVAL); 4475786Slclee } 4476786Slclee #endif 4477786Slclee 4478786Slclee if (arg == NULL) { 4479786Slclee return (EINVAL); 4480786Slclee } 4481786Slclee 4482*9889SLarry.Liu@Sun.COM mboot = kmem_zalloc(cl->cl_sys_blocksize, KM_SLEEP); 4483786Slclee 4484786Slclee if (ddi_copyin((const void *)arg, mboot, 4485*9889SLarry.Liu@Sun.COM cl->cl_sys_blocksize, flag) != 0) { 4486*9889SLarry.Liu@Sun.COM kmem_free(mboot, cl->cl_sys_blocksize); 4487786Slclee return (EFAULT); 4488786Slclee } 4489786Slclee 4490786Slclee /* Is this really a master boot record? */ 4491786Slclee magic = LE_16(mboot->signature); 4492786Slclee if (magic != MBB_MAGIC) { 4493*9889SLarry.Liu@Sun.COM kmem_free(mboot, cl->cl_sys_blocksize); 4494786Slclee return (EINVAL); 4495786Slclee } 4496786Slclee 44973525Sshidokht rval = DK_TG_WRITE(cl, mboot, 0, cl->cl_sys_blocksize, tg_cookie); 44983525Sshidokht 44993525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 4500786Slclee #if defined(__i386) || defined(__amd64) 4501786Slclee if (rval == 0) { 4502786Slclee /* 4503786Slclee * mboot has been written successfully. 4504786Slclee * update the fdisk and vtoc tables in memory 4505786Slclee */ 45063525Sshidokht rval = cmlb_update_fdisk_and_vtoc(cl, tg_cookie); 45078863SEdward.Pilatowicz@Sun.COM if ((!cl->cl_f_geometry_is_valid) || (rval != 0)) { 45083525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4509*9889SLarry.Liu@Sun.COM kmem_free(mboot, cl->cl_sys_blocksize); 4510786Slclee return (rval); 4511786Slclee } 4512786Slclee } 45133525Sshidokht 45143525Sshidokht #ifdef __lock_lint 45153525Sshidokht cmlb_setup_default_geometry(cl, tg_cookie); 45163525Sshidokht #endif 45173525Sshidokht 4518786Slclee #else 4519786Slclee if (rval == 0) { 4520786Slclee /* 4521786Slclee * mboot has been written successfully. 4522786Slclee * set up the default geometry and VTOC 4523786Slclee */ 45247563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount <= CMLB_EXTVTOC_LIMIT) 45253525Sshidokht cmlb_setup_default_geometry(cl, tg_cookie); 4526786Slclee } 4527786Slclee #endif 45287563SPrasad.Singamsetty@Sun.COM cl->cl_msglog_flag |= CMLB_ALLOW_2TB_WARN; 45293525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4530*9889SLarry.Liu@Sun.COM kmem_free(mboot, cl->cl_sys_blocksize); 4531786Slclee return (rval); 4532786Slclee } 4533786Slclee 4534786Slclee 4535786Slclee /* 4536786Slclee * Function: cmlb_setup_default_geometry 4537786Slclee * 4538786Slclee * Description: This local utility routine sets the default geometry as part of 4539786Slclee * setting the device mboot. 4540786Slclee * 45413525Sshidokht * Arguments: 45423525Sshidokht * cl driver soft state (unit) structure 45433525Sshidokht * 45443525Sshidokht * tg_cookie cookie from target driver to be passed back to target 45453525Sshidokht * driver when we call back to it through tg_ops. 45463525Sshidokht * 4547786Slclee * 4548786Slclee * Note: This may be redundant with cmlb_build_default_label. 4549786Slclee */ 4550786Slclee static void 45513525Sshidokht cmlb_setup_default_geometry(struct cmlb_lun *cl, void *tg_cookie) 4552786Slclee { 4553786Slclee struct cmlb_geom pgeom; 4554786Slclee struct cmlb_geom *pgeomp = &pgeom; 4555786Slclee int ret; 4556786Slclee int geom_base_cap = 1; 4557786Slclee 4558786Slclee 45593525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 4560786Slclee 4561786Slclee /* zero out the soft state geometry and partition table. */ 45623525Sshidokht bzero(&cl->cl_g, sizeof (struct dk_geom)); 45633525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc)); 45643525Sshidokht bzero(cl->cl_map, NDKMAP * (sizeof (struct dk_map))); 4565786Slclee 4566786Slclee /* 4567786Slclee * For the rpm, we use the minimum for the disk. 4568786Slclee * For the head, cyl and number of sector per track, 4569786Slclee * if the capacity <= 1GB, head = 64, sect = 32. 4570786Slclee * else head = 255, sect 63 4571786Slclee * Note: the capacity should be equal to C*H*S values. 4572786Slclee * This will cause some truncation of size due to 4573786Slclee * round off errors. For CD-ROMs, this truncation can 4574786Slclee * have adverse side effects, so returning ncyl and 4575786Slclee * nhead as 1. The nsect will overflow for most of 4576786Slclee * CD-ROMs as nsect is of type ushort. 4577786Slclee */ 45783525Sshidokht if (cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8) { 4579786Slclee /* 4580786Slclee * newfs currently can not handle 255 ntracks for SPARC 4581786Slclee * so get the geometry from target driver instead of coming up 4582786Slclee * with one based on capacity. 4583786Slclee */ 45843525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 45853525Sshidokht ret = DK_TG_GETPHYGEOM(cl, pgeomp, tg_cookie); 45863525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 4587786Slclee 45888863SEdward.Pilatowicz@Sun.COM if (ret == 0) { 4589786Slclee geom_base_cap = 0; 4590786Slclee } else { 45913525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 4592786Slclee "cmlb_setup_default_geometry: " 4593786Slclee "tg_getphygeom failed %d\n", ret); 4594786Slclee 4595786Slclee /* do default setting, geometry based on capacity */ 4596786Slclee } 4597786Slclee } 4598786Slclee 4599786Slclee if (geom_base_cap) { 46003525Sshidokht if (ISCD(cl)) { 46013525Sshidokht cl->cl_g.dkg_ncyl = 1; 46023525Sshidokht cl->cl_g.dkg_nhead = 1; 46033525Sshidokht cl->cl_g.dkg_nsect = cl->cl_blockcount; 46043525Sshidokht } else if (cl->cl_blockcount <= 0x1000) { 4605786Slclee /* Needed for unlabeled SCSI floppies. */ 46063525Sshidokht cl->cl_g.dkg_nhead = 2; 46073525Sshidokht cl->cl_g.dkg_ncyl = 80; 46083525Sshidokht cl->cl_g.dkg_pcyl = 80; 46093525Sshidokht cl->cl_g.dkg_nsect = cl->cl_blockcount / (2 * 80); 46103525Sshidokht } else if (cl->cl_blockcount <= 0x200000) { 46113525Sshidokht cl->cl_g.dkg_nhead = 64; 46123525Sshidokht cl->cl_g.dkg_nsect = 32; 46133525Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount / (64 * 32); 4614786Slclee } else { 46153525Sshidokht cl->cl_g.dkg_nhead = 255; 46166124Sshidokht 46176124Sshidokht cl->cl_g.dkg_nsect = ((cl->cl_blockcount + 46186124Sshidokht (UINT16_MAX * 255 * 63) - 1) / 46196124Sshidokht (UINT16_MAX * 255 * 63)) * 63; 46206124Sshidokht 46216124Sshidokht if (cl->cl_g.dkg_nsect == 0) 46226124Sshidokht cl->cl_g.dkg_nsect = (UINT16_MAX / 63) * 63; 46236124Sshidokht 46246124Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount / 46256124Sshidokht (255 * cl->cl_g.dkg_nsect); 4626786Slclee } 4627786Slclee 46283525Sshidokht cl->cl_g.dkg_acyl = 0; 46293525Sshidokht cl->cl_g.dkg_bcyl = 0; 46303525Sshidokht cl->cl_g.dkg_intrlv = 1; 46313525Sshidokht cl->cl_g.dkg_rpm = 200; 46323525Sshidokht if (cl->cl_g.dkg_pcyl == 0) 46333525Sshidokht cl->cl_g.dkg_pcyl = cl->cl_g.dkg_ncyl + 46343525Sshidokht cl->cl_g.dkg_acyl; 4635786Slclee } else { 46363525Sshidokht cl->cl_g.dkg_ncyl = (short)pgeomp->g_ncyl; 46373525Sshidokht cl->cl_g.dkg_acyl = pgeomp->g_acyl; 46383525Sshidokht cl->cl_g.dkg_nhead = pgeomp->g_nhead; 46393525Sshidokht cl->cl_g.dkg_nsect = pgeomp->g_nsect; 46403525Sshidokht cl->cl_g.dkg_intrlv = pgeomp->g_intrlv; 46413525Sshidokht cl->cl_g.dkg_rpm = pgeomp->g_rpm; 46423525Sshidokht cl->cl_g.dkg_pcyl = cl->cl_g.dkg_ncyl + cl->cl_g.dkg_acyl; 4643786Slclee } 4644786Slclee 46453525Sshidokht cl->cl_g.dkg_read_reinstruct = 0; 46463525Sshidokht cl->cl_g.dkg_write_reinstruct = 0; 46473525Sshidokht cl->cl_solaris_size = cl->cl_g.dkg_ncyl * 46483525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect; 46493525Sshidokht 46503525Sshidokht cl->cl_map['a'-'a'].dkl_cylno = 0; 46513525Sshidokht cl->cl_map['a'-'a'].dkl_nblk = cl->cl_solaris_size; 46523525Sshidokht 46533525Sshidokht cl->cl_map['c'-'a'].dkl_cylno = 0; 46543525Sshidokht cl->cl_map['c'-'a'].dkl_nblk = cl->cl_solaris_size; 46553525Sshidokht 46563525Sshidokht cl->cl_vtoc.v_part[2].p_tag = V_BACKUP; 46573525Sshidokht cl->cl_vtoc.v_part[2].p_flag = V_UNMNT; 46583525Sshidokht cl->cl_vtoc.v_nparts = V_NUMPAR; 46593525Sshidokht cl->cl_vtoc.v_version = V_VERSION; 46603525Sshidokht (void) sprintf((char *)cl->cl_asciilabel, "DEFAULT cyl %d alt %d" 46613525Sshidokht " hd %d sec %d", cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl, 46623525Sshidokht cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect); 46633525Sshidokht 46648863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE; 4665786Slclee } 4666786Slclee 4667786Slclee 4668786Slclee #if defined(__i386) || defined(__amd64) 4669786Slclee /* 4670786Slclee * Function: cmlb_update_fdisk_and_vtoc 4671786Slclee * 4672786Slclee * Description: This local utility routine updates the device fdisk and vtoc 4673786Slclee * as part of setting the device mboot. 4674786Slclee * 46753525Sshidokht * Arguments: 46763525Sshidokht * cl driver soft state (unit) structure 46773525Sshidokht * 46783525Sshidokht * tg_cookie cookie from target driver to be passed back to target 46793525Sshidokht * driver when we call back to it through tg_ops. 46803525Sshidokht * 4681786Slclee * 4682786Slclee * Return Code: 0 for success or errno-type return code. 4683786Slclee * 4684786Slclee * Note:x86: This looks like a duplicate of cmlb_validate_geometry(), but 4685786Slclee * these did exist separately in x86 sd.c. 4686786Slclee */ 4687786Slclee static int 46883525Sshidokht cmlb_update_fdisk_and_vtoc(struct cmlb_lun *cl, void *tg_cookie) 4689786Slclee { 4690786Slclee int count; 4691786Slclee int label_rc = 0; 4692786Slclee int fdisk_rval; 4693786Slclee diskaddr_t capacity; 4694786Slclee 46953525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 46963525Sshidokht 46973525Sshidokht if (cmlb_check_update_blockcount(cl, tg_cookie) != 0) 4698786Slclee return (EINVAL); 4699786Slclee 4700786Slclee #if defined(_SUNOS_VTOC_16) 4701786Slclee /* 4702786Slclee * Set up the "whole disk" fdisk partition; this should always 4703786Slclee * exist, regardless of whether the disk contains an fdisk table 4704786Slclee * or vtoc. 4705786Slclee */ 47063525Sshidokht cl->cl_map[P0_RAW_DISK].dkl_cylno = 0; 47073525Sshidokht cl->cl_map[P0_RAW_DISK].dkl_nblk = cl->cl_blockcount; 4708786Slclee #endif /* defined(_SUNOS_VTOC_16) */ 4709786Slclee 4710786Slclee /* 4711786Slclee * copy the lbasize and capacity so that if they're 47123525Sshidokht * reset while we're not holding the CMLB_MUTEX(cl), we will 47133525Sshidokht * continue to use valid values after the CMLB_MUTEX(cl) is 4714786Slclee * reacquired. 4715786Slclee */ 47163525Sshidokht capacity = cl->cl_blockcount; 4717786Slclee 4718786Slclee /* 4719786Slclee * refresh the logical and physical geometry caches. 4720786Slclee * (data from mode sense format/rigid disk geometry pages, 4721786Slclee * and scsi_ifgetcap("geometry"). 4722786Slclee */ 47233525Sshidokht cmlb_resync_geom_caches(cl, capacity, tg_cookie); 4724786Slclee 4725786Slclee /* 47263525Sshidokht * Only DIRECT ACCESS devices will have Scl labels. 47273525Sshidokht * CD's supposedly have a Scl label, too 4728786Slclee */ 47293525Sshidokht if (cl->cl_device_type == DTYPE_DIRECT || ISREMOVABLE(cl)) { 47303525Sshidokht fdisk_rval = cmlb_read_fdisk(cl, capacity, tg_cookie); 4731786Slclee if (fdisk_rval != 0) { 47323525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 4733786Slclee return (fdisk_rval); 4734786Slclee } 4735786Slclee 47363525Sshidokht if (cl->cl_solaris_size <= DK_LABEL_LOC) { 4737786Slclee /* 4738786Slclee * Found fdisk table but no Solaris partition entry, 4739786Slclee * so don't call cmlb_uselabel() and don't create 4740786Slclee * a default label. 4741786Slclee */ 4742786Slclee label_rc = 0; 47438863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_TRUE; 4744786Slclee goto no_solaris_partition; 4745786Slclee } 4746786Slclee } else if (capacity < 0) { 47473525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 4748786Slclee return (EINVAL); 4749786Slclee } 4750786Slclee 4751786Slclee /* 4752786Slclee * For Removable media We reach here if we have found a 4753786Slclee * SOLARIS PARTITION. 47548863SEdward.Pilatowicz@Sun.COM * If cl_f_geometry_is_valid is B_FALSE it indicates that the SOLARIS 4755786Slclee * PARTITION has changed from the previous one, hence we will setup a 4756786Slclee * default VTOC in this case. 4757786Slclee */ 47588863SEdward.Pilatowicz@Sun.COM if (!cl->cl_f_geometry_is_valid) { 4759786Slclee /* if we get here it is writable */ 4760786Slclee /* we are called from SMBOOT, and after a write of fdisk */ 47613525Sshidokht cmlb_build_default_label(cl, tg_cookie); 4762786Slclee label_rc = 0; 4763786Slclee } 4764786Slclee 4765786Slclee no_solaris_partition: 4766786Slclee 4767786Slclee #if defined(_SUNOS_VTOC_16) 4768786Slclee /* 4769786Slclee * If we have valid geometry, set up the remaining fdisk partitions. 4770786Slclee * Note that dkl_cylno is not used for the fdisk map entries, so 4771786Slclee * we set it to an entirely bogus value. 4772786Slclee */ 47738333SSuhasini.Peddada@Sun.COM for (count = 0; count < FD_NUMPART; count++) { 47747563SPrasad.Singamsetty@Sun.COM cl->cl_map[FDISK_P1 + count].dkl_cylno = UINT32_MAX; 47753525Sshidokht cl->cl_map[FDISK_P1 + count].dkl_nblk = 47763525Sshidokht cl->cl_fmap[count].fmap_nblk; 47773525Sshidokht cl->cl_offset[FDISK_P1 + count] = 47783525Sshidokht cl->cl_fmap[count].fmap_start; 4779786Slclee } 4780786Slclee #endif 4781786Slclee 4782786Slclee for (count = 0; count < NDKMAP; count++) { 4783786Slclee #if defined(_SUNOS_VTOC_8) 47843525Sshidokht struct dk_map *lp = &cl->cl_map[count]; 47853525Sshidokht cl->cl_offset[count] = 47863525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno; 4787786Slclee #elif defined(_SUNOS_VTOC_16) 47883525Sshidokht struct dkl_partition *vp = &cl->cl_vtoc.v_part[count]; 47893525Sshidokht cl->cl_offset[count] = vp->p_start + cl->cl_solaris_offset; 4790786Slclee #else 4791786Slclee #error "No VTOC format defined." 4792786Slclee #endif 4793786Slclee } 4794786Slclee 47953525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 4796786Slclee return (label_rc); 4797786Slclee } 4798786Slclee #endif 4799786Slclee 4800786Slclee #if defined(__i386) || defined(__amd64) 4801786Slclee static int 48023525Sshidokht cmlb_dkio_get_virtgeom(struct cmlb_lun *cl, caddr_t arg, int flag) 4803786Slclee { 4804786Slclee int err = 0; 4805786Slclee 4806786Slclee /* Return the driver's notion of the media's logical geometry */ 4807786Slclee struct dk_geom disk_geom; 4808786Slclee struct dk_geom *dkgp = &disk_geom; 4809786Slclee 48103525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 4811786Slclee /* 4812786Slclee * If there is no HBA geometry available, or 4813786Slclee * if the HBA returned us something that doesn't 4814786Slclee * really fit into an Int 13/function 8 geometry 4815786Slclee * result, just fail the ioctl. See PSARC 1998/313. 4816786Slclee */ 48173525Sshidokht if (cl->cl_lgeom.g_nhead == 0 || 48183525Sshidokht cl->cl_lgeom.g_nsect == 0 || 48193525Sshidokht cl->cl_lgeom.g_ncyl > 1024) { 48203525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4821786Slclee err = EINVAL; 4822786Slclee } else { 48233525Sshidokht dkgp->dkg_ncyl = cl->cl_lgeom.g_ncyl; 48243525Sshidokht dkgp->dkg_acyl = cl->cl_lgeom.g_acyl; 4825786Slclee dkgp->dkg_pcyl = dkgp->dkg_ncyl + dkgp->dkg_acyl; 48263525Sshidokht dkgp->dkg_nhead = cl->cl_lgeom.g_nhead; 48273525Sshidokht dkgp->dkg_nsect = cl->cl_lgeom.g_nsect; 4828786Slclee 48294177Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4830786Slclee if (ddi_copyout(dkgp, (void *)arg, 4831786Slclee sizeof (struct dk_geom), flag)) { 4832786Slclee err = EFAULT; 4833786Slclee } else { 4834786Slclee err = 0; 4835786Slclee } 4836786Slclee } 4837786Slclee return (err); 4838786Slclee } 4839786Slclee #endif 4840786Slclee 4841786Slclee #if defined(__i386) || defined(__amd64) 4842786Slclee static int 48433525Sshidokht cmlb_dkio_get_phygeom(struct cmlb_lun *cl, caddr_t arg, int flag) 4844786Slclee { 4845786Slclee int err = 0; 48463525Sshidokht diskaddr_t capacity; 4847786Slclee 4848786Slclee 4849786Slclee /* Return the driver's notion of the media physical geometry */ 4850786Slclee struct dk_geom disk_geom; 4851786Slclee struct dk_geom *dkgp = &disk_geom; 4852786Slclee 48533525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 48543525Sshidokht 48553525Sshidokht if (cl->cl_g.dkg_nhead != 0 && 48563525Sshidokht cl->cl_g.dkg_nsect != 0) { 4857786Slclee /* 4858786Slclee * We succeeded in getting a geometry, but 4859786Slclee * right now it is being reported as just the 4860786Slclee * Solaris fdisk partition, just like for 4861786Slclee * DKIOCGGEOM. We need to change that to be 4862786Slclee * correct for the entire disk now. 4863786Slclee */ 48643525Sshidokht bcopy(&cl->cl_g, dkgp, sizeof (*dkgp)); 4865786Slclee dkgp->dkg_acyl = 0; 48663525Sshidokht dkgp->dkg_ncyl = cl->cl_blockcount / 4867786Slclee (dkgp->dkg_nhead * dkgp->dkg_nsect); 4868786Slclee } else { 4869786Slclee bzero(dkgp, sizeof (struct dk_geom)); 4870786Slclee /* 4871786Slclee * This disk does not have a Solaris VTOC 4872786Slclee * so we must present a physical geometry 4873786Slclee * that will remain consistent regardless 4874786Slclee * of how the disk is used. This will ensure 4875786Slclee * that the geometry does not change regardless 4876786Slclee * of the fdisk partition type (ie. EFI, FAT32, 4877786Slclee * Solaris, etc). 4878786Slclee */ 48793525Sshidokht if (ISCD(cl)) { 48803525Sshidokht dkgp->dkg_nhead = cl->cl_pgeom.g_nhead; 48813525Sshidokht dkgp->dkg_nsect = cl->cl_pgeom.g_nsect; 48823525Sshidokht dkgp->dkg_ncyl = cl->cl_pgeom.g_ncyl; 48833525Sshidokht dkgp->dkg_acyl = cl->cl_pgeom.g_acyl; 4884786Slclee } else { 48853525Sshidokht /* 48863525Sshidokht * Invalid cl_blockcount can generate invalid 48873525Sshidokht * dk_geom and may result in division by zero 48883525Sshidokht * system failure. Should make sure blockcount 48893525Sshidokht * is valid before using it here. 48903525Sshidokht */ 48913525Sshidokht if (cl->cl_blockcount == 0) { 48923525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 48933525Sshidokht err = EIO; 48943525Sshidokht return (err); 48953525Sshidokht } 48963525Sshidokht /* 48973525Sshidokht * Refer to comments related to off-by-1 at the 48983525Sshidokht * header of this file 48993525Sshidokht */ 49003525Sshidokht if (cl->cl_alter_behavior & CMLB_OFF_BY_ONE) 49013525Sshidokht capacity = cl->cl_blockcount - 1; 49023525Sshidokht else 49033525Sshidokht capacity = cl->cl_blockcount; 49043525Sshidokht 49053525Sshidokht cmlb_convert_geometry(capacity, dkgp); 4906786Slclee dkgp->dkg_acyl = 0; 49073525Sshidokht dkgp->dkg_ncyl = capacity / 4908786Slclee (dkgp->dkg_nhead * dkgp->dkg_nsect); 4909786Slclee } 4910786Slclee } 4911786Slclee dkgp->dkg_pcyl = dkgp->dkg_ncyl + dkgp->dkg_acyl; 4912786Slclee 49134177Sshidokht mutex_exit(CMLB_MUTEX(cl)); 49144177Sshidokht if (ddi_copyout(dkgp, (void *)arg, sizeof (struct dk_geom), flag)) 4915786Slclee err = EFAULT; 49164177Sshidokht 4917786Slclee return (err); 4918786Slclee } 4919786Slclee #endif 4920786Slclee 4921786Slclee #if defined(__i386) || defined(__amd64) 4922786Slclee static int 49233525Sshidokht cmlb_dkio_partinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag) 4924786Slclee { 4925786Slclee int err = 0; 4926786Slclee 4927786Slclee /* 4928786Slclee * Return parameters describing the selected disk slice. 4929786Slclee * Note: this ioctl is for the intel platform only 4930786Slclee */ 4931786Slclee int part; 4932786Slclee 4933786Slclee part = CMLBPART(dev); 4934786Slclee 49353525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 49363525Sshidokht /* don't check cl_solaris_size for pN */ 49373525Sshidokht if (part < P0_RAW_DISK && cl->cl_solaris_size == 0) { 4938786Slclee err = EIO; 49394177Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4940786Slclee } else { 4941786Slclee struct part_info p; 4942786Slclee 49433525Sshidokht p.p_start = (daddr_t)cl->cl_offset[part]; 49443525Sshidokht p.p_length = (int)cl->cl_map[part].dkl_nblk; 49454177Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4946786Slclee #ifdef _MULTI_DATAMODEL 4947786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 4948786Slclee case DDI_MODEL_ILP32: 4949786Slclee { 4950786Slclee struct part_info32 p32; 4951786Slclee 4952786Slclee p32.p_start = (daddr32_t)p.p_start; 4953786Slclee p32.p_length = p.p_length; 4954786Slclee if (ddi_copyout(&p32, (void *)arg, 4955786Slclee sizeof (p32), flag)) 4956786Slclee err = EFAULT; 4957786Slclee break; 4958786Slclee } 4959786Slclee 4960786Slclee case DDI_MODEL_NONE: 4961786Slclee { 4962786Slclee if (ddi_copyout(&p, (void *)arg, sizeof (p), 4963786Slclee flag)) 4964786Slclee err = EFAULT; 4965786Slclee break; 4966786Slclee } 4967786Slclee } 4968786Slclee #else /* ! _MULTI_DATAMODEL */ 4969786Slclee if (ddi_copyout(&p, (void *)arg, sizeof (p), flag)) 4970786Slclee err = EFAULT; 4971786Slclee #endif /* _MULTI_DATAMODEL */ 4972786Slclee } 4973786Slclee return (err); 4974786Slclee } 49757563SPrasad.Singamsetty@Sun.COM static int 49767563SPrasad.Singamsetty@Sun.COM cmlb_dkio_extpartinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag) 49777563SPrasad.Singamsetty@Sun.COM { 49787563SPrasad.Singamsetty@Sun.COM int err = 0; 49797563SPrasad.Singamsetty@Sun.COM 49807563SPrasad.Singamsetty@Sun.COM /* 49817563SPrasad.Singamsetty@Sun.COM * Return parameters describing the selected disk slice. 49827563SPrasad.Singamsetty@Sun.COM * Note: this ioctl is for the intel platform only 49837563SPrasad.Singamsetty@Sun.COM */ 49847563SPrasad.Singamsetty@Sun.COM int part; 49857563SPrasad.Singamsetty@Sun.COM 49867563SPrasad.Singamsetty@Sun.COM part = CMLBPART(dev); 49877563SPrasad.Singamsetty@Sun.COM 49887563SPrasad.Singamsetty@Sun.COM mutex_enter(CMLB_MUTEX(cl)); 49897563SPrasad.Singamsetty@Sun.COM /* don't check cl_solaris_size for pN */ 49907563SPrasad.Singamsetty@Sun.COM if (part < P0_RAW_DISK && cl->cl_solaris_size == 0) { 49917563SPrasad.Singamsetty@Sun.COM err = EIO; 49927563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 49937563SPrasad.Singamsetty@Sun.COM } else { 49947563SPrasad.Singamsetty@Sun.COM struct extpart_info p; 49957563SPrasad.Singamsetty@Sun.COM 49967563SPrasad.Singamsetty@Sun.COM p.p_start = (diskaddr_t)cl->cl_offset[part]; 49977563SPrasad.Singamsetty@Sun.COM p.p_length = (diskaddr_t)cl->cl_map[part].dkl_nblk; 49987563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 49997563SPrasad.Singamsetty@Sun.COM if (ddi_copyout(&p, (void *)arg, sizeof (p), flag)) 50007563SPrasad.Singamsetty@Sun.COM err = EFAULT; 50017563SPrasad.Singamsetty@Sun.COM } 50027563SPrasad.Singamsetty@Sun.COM return (err); 50037563SPrasad.Singamsetty@Sun.COM } 5004786Slclee #endif 50057224Scth 50067224Scth int 50077224Scth cmlb_prop_op(cmlb_handle_t cmlbhandle, 50087224Scth dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags, 50097224Scth char *name, caddr_t valuep, int *lengthp, int part, void *tg_cookie) 50107224Scth { 50117224Scth struct cmlb_lun *cl; 50127224Scth diskaddr_t capacity; 50137224Scth uint32_t lbasize; 50147224Scth enum dp { DP_NBLOCKS, DP_BLKSIZE } dp; 50157224Scth int callers_length; 50167224Scth caddr_t buffer; 50177224Scth uint64_t nblocks64; 50187224Scth uint_t dblk; 50197224Scth 50207224Scth /* Always fallback to ddi_prop_op... */ 50217224Scth cl = (struct cmlb_lun *)cmlbhandle; 50227224Scth if (cl == NULL) { 50237224Scth fallback: return (ddi_prop_op(dev, dip, prop_op, mod_flags, 50247224Scth name, valuep, lengthp)); 50257224Scth } 50267224Scth 50277224Scth /* Pick up capacity and blocksize information. */ 50287224Scth capacity = cl->cl_blockcount; 50297224Scth if (capacity == 0) 50307224Scth goto fallback; 50317224Scth lbasize = cl->cl_tgt_blocksize; 50327224Scth if (lbasize == 0) 50337224Scth lbasize = DEV_BSIZE; /* 0 -> DEV_BSIZE units */ 50347224Scth 50357224Scth /* Check for dynamic property of whole device. */ 50367224Scth if (dev == DDI_DEV_T_ANY) { 50377224Scth /* Fallback to ddi_prop_op if we don't understand. */ 50387224Scth if (strcmp(name, "device-nblocks") == 0) 50397224Scth dp = DP_NBLOCKS; 50407224Scth else if (strcmp(name, "device-blksize") == 0) 50417224Scth dp = DP_BLKSIZE; 50427224Scth else 50437224Scth goto fallback; 50447224Scth 50457224Scth /* get callers length, establish length of our dynamic prop */ 50467224Scth callers_length = *lengthp; 50477224Scth if (dp == DP_NBLOCKS) 50487224Scth *lengthp = sizeof (uint64_t); 50497224Scth else if (dp == DP_BLKSIZE) 50507224Scth *lengthp = sizeof (uint32_t); 50517224Scth 50527224Scth /* service request for the length of the property */ 50537224Scth if (prop_op == PROP_LEN) 50547224Scth return (DDI_PROP_SUCCESS); 50557224Scth 50567224Scth switch (prop_op) { 50577224Scth case PROP_LEN_AND_VAL_ALLOC: 50587224Scth if ((buffer = kmem_alloc(*lengthp, 50597224Scth (mod_flags & DDI_PROP_CANSLEEP) ? 50607224Scth KM_SLEEP : KM_NOSLEEP)) == NULL) 50617224Scth return (DDI_PROP_NO_MEMORY); 50627224Scth *(caddr_t *)valuep = buffer; /* set callers buf */ 50637224Scth break; 50647224Scth 50657224Scth case PROP_LEN_AND_VAL_BUF: 50667224Scth /* the length of the prop and the request must match */ 50677224Scth if (callers_length != *lengthp) 50687224Scth return (DDI_PROP_INVAL_ARG); 50697224Scth buffer = valuep; /* get callers buf */ 50707224Scth break; 50717224Scth 50727224Scth default: 50737224Scth return (DDI_PROP_INVAL_ARG); 50747224Scth } 50757224Scth 50767224Scth /* transfer the value into the buffer */ 50777224Scth if (dp == DP_NBLOCKS) 50787224Scth *((uint64_t *)buffer) = capacity; 50797224Scth else if (dp == DP_BLKSIZE) 50807224Scth *((uint32_t *)buffer) = lbasize; 50817224Scth 50827224Scth return (DDI_PROP_SUCCESS); 50837224Scth } 50847224Scth 50857224Scth /* 50867224Scth * Support dynamic size oriented properties of partition. Requests 50877224Scth * issued under conditions where size is valid are passed to 50887224Scth * ddi_prop_op_nblocks with the size information, otherwise the 50897224Scth * request is passed to ddi_prop_op. Size depends on valid geometry. 50907224Scth */ 50917224Scth if (!cmlb_is_valid(cmlbhandle)) 50927224Scth goto fallback; 50937224Scth 50947224Scth /* Get partition nblocks value. */ 50957224Scth (void) cmlb_partinfo(cmlbhandle, part, 50967224Scth (diskaddr_t *)&nblocks64, NULL, NULL, NULL, tg_cookie); 50977224Scth 50987224Scth /* 5099*9889SLarry.Liu@Sun.COM * Assume partition information is in sys_blocksize units, compute 51007224Scth * divisor for size(9P) property representation. 51017224Scth */ 5102*9889SLarry.Liu@Sun.COM dblk = lbasize / cl->cl_sys_blocksize; 51037224Scth 51047224Scth /* Now let ddi_prop_op_nblocks_blksize() handle the request. */ 51057224Scth return (ddi_prop_op_nblocks_blksize(dev, dip, prop_op, mod_flags, 51067224Scth name, valuep, lengthp, nblocks64 / dblk, lbasize)); 51077224Scth } 5108