1*3ccda647Slclee /* 2*3ccda647Slclee * CDDL HEADER START 3*3ccda647Slclee * 4*3ccda647Slclee * The contents of this file are subject to the terms of the 5*3ccda647Slclee * Common Development and Distribution License, Version 1.0 only 6*3ccda647Slclee * (the "License"). You may not use this file except in compliance 7*3ccda647Slclee * with the License. 8*3ccda647Slclee * 9*3ccda647Slclee * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*3ccda647Slclee * or http://www.opensolaris.org/os/licensing. 11*3ccda647Slclee * See the License for the specific language governing permissions 12*3ccda647Slclee * and limitations under the License. 13*3ccda647Slclee * 14*3ccda647Slclee * When distributing Covered Code, include this CDDL HEADER in each 15*3ccda647Slclee * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*3ccda647Slclee * If applicable, add the following below this CDDL HEADER, with the 17*3ccda647Slclee * fields enclosed by brackets "[]" replaced with your own identifying 18*3ccda647Slclee * information: Portions Copyright [yyyy] [name of copyright owner] 19*3ccda647Slclee * 20*3ccda647Slclee * CDDL HEADER END 21*3ccda647Slclee */ 22*3ccda647Slclee 23*3ccda647Slclee /* 24*3ccda647Slclee * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 25*3ccda647Slclee * Use is subject to license terms. 26*3ccda647Slclee */ 27*3ccda647Slclee 28*3ccda647Slclee #pragma ident "%Z%%M% %I% %E% SMI" 29*3ccda647Slclee 30*3ccda647Slclee /* 31*3ccda647Slclee * This module provides support for labeling operations for target 32*3ccda647Slclee * drivers. 33*3ccda647Slclee */ 34*3ccda647Slclee 35*3ccda647Slclee #include <sys/scsi/scsi.h> 36*3ccda647Slclee #include <sys/sunddi.h> 37*3ccda647Slclee #include <sys/dklabel.h> 38*3ccda647Slclee #include <sys/dkio.h> 39*3ccda647Slclee #include <sys/vtoc.h> 40*3ccda647Slclee #include <sys/dktp/fdisk.h> 41*3ccda647Slclee #include <sys/vtrace.h> 42*3ccda647Slclee #include <sys/efi_partition.h> 43*3ccda647Slclee #include <sys/cmlb.h> 44*3ccda647Slclee #include <sys/cmlb_impl.h> 45*3ccda647Slclee 46*3ccda647Slclee 47*3ccda647Slclee /* 48*3ccda647Slclee * Driver minor node structure and data table 49*3ccda647Slclee */ 50*3ccda647Slclee struct driver_minor_data { 51*3ccda647Slclee char *name; 52*3ccda647Slclee minor_t minor; 53*3ccda647Slclee int type; 54*3ccda647Slclee }; 55*3ccda647Slclee 56*3ccda647Slclee static struct driver_minor_data dk_minor_data[] = { 57*3ccda647Slclee {"a", 0, S_IFBLK}, 58*3ccda647Slclee {"b", 1, S_IFBLK}, 59*3ccda647Slclee {"c", 2, S_IFBLK}, 60*3ccda647Slclee {"d", 3, S_IFBLK}, 61*3ccda647Slclee {"e", 4, S_IFBLK}, 62*3ccda647Slclee {"f", 5, S_IFBLK}, 63*3ccda647Slclee {"g", 6, S_IFBLK}, 64*3ccda647Slclee {"h", 7, S_IFBLK}, 65*3ccda647Slclee #if defined(_SUNOS_VTOC_16) 66*3ccda647Slclee {"i", 8, S_IFBLK}, 67*3ccda647Slclee {"j", 9, S_IFBLK}, 68*3ccda647Slclee {"k", 10, S_IFBLK}, 69*3ccda647Slclee {"l", 11, S_IFBLK}, 70*3ccda647Slclee {"m", 12, S_IFBLK}, 71*3ccda647Slclee {"n", 13, S_IFBLK}, 72*3ccda647Slclee {"o", 14, S_IFBLK}, 73*3ccda647Slclee {"p", 15, S_IFBLK}, 74*3ccda647Slclee #endif /* defined(_SUNOS_VTOC_16) */ 75*3ccda647Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 76*3ccda647Slclee {"q", 16, S_IFBLK}, 77*3ccda647Slclee {"r", 17, S_IFBLK}, 78*3ccda647Slclee {"s", 18, S_IFBLK}, 79*3ccda647Slclee {"t", 19, S_IFBLK}, 80*3ccda647Slclee {"u", 20, S_IFBLK}, 81*3ccda647Slclee #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 82*3ccda647Slclee {"a,raw", 0, S_IFCHR}, 83*3ccda647Slclee {"b,raw", 1, S_IFCHR}, 84*3ccda647Slclee {"c,raw", 2, S_IFCHR}, 85*3ccda647Slclee {"d,raw", 3, S_IFCHR}, 86*3ccda647Slclee {"e,raw", 4, S_IFCHR}, 87*3ccda647Slclee {"f,raw", 5, S_IFCHR}, 88*3ccda647Slclee {"g,raw", 6, S_IFCHR}, 89*3ccda647Slclee {"h,raw", 7, S_IFCHR}, 90*3ccda647Slclee #if defined(_SUNOS_VTOC_16) 91*3ccda647Slclee {"i,raw", 8, S_IFCHR}, 92*3ccda647Slclee {"j,raw", 9, S_IFCHR}, 93*3ccda647Slclee {"k,raw", 10, S_IFCHR}, 94*3ccda647Slclee {"l,raw", 11, S_IFCHR}, 95*3ccda647Slclee {"m,raw", 12, S_IFCHR}, 96*3ccda647Slclee {"n,raw", 13, S_IFCHR}, 97*3ccda647Slclee {"o,raw", 14, S_IFCHR}, 98*3ccda647Slclee {"p,raw", 15, S_IFCHR}, 99*3ccda647Slclee #endif /* defined(_SUNOS_VTOC_16) */ 100*3ccda647Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 101*3ccda647Slclee {"q,raw", 16, S_IFCHR}, 102*3ccda647Slclee {"r,raw", 17, S_IFCHR}, 103*3ccda647Slclee {"s,raw", 18, S_IFCHR}, 104*3ccda647Slclee {"t,raw", 19, S_IFCHR}, 105*3ccda647Slclee {"u,raw", 20, S_IFCHR}, 106*3ccda647Slclee #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 107*3ccda647Slclee {0} 108*3ccda647Slclee }; 109*3ccda647Slclee 110*3ccda647Slclee static struct driver_minor_data dk_minor_data_efi[] = { 111*3ccda647Slclee {"a", 0, S_IFBLK}, 112*3ccda647Slclee {"b", 1, S_IFBLK}, 113*3ccda647Slclee {"c", 2, S_IFBLK}, 114*3ccda647Slclee {"d", 3, S_IFBLK}, 115*3ccda647Slclee {"e", 4, S_IFBLK}, 116*3ccda647Slclee {"f", 5, S_IFBLK}, 117*3ccda647Slclee {"g", 6, S_IFBLK}, 118*3ccda647Slclee {"wd", 7, S_IFBLK}, 119*3ccda647Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 120*3ccda647Slclee {"q", 16, S_IFBLK}, 121*3ccda647Slclee {"r", 17, S_IFBLK}, 122*3ccda647Slclee {"s", 18, S_IFBLK}, 123*3ccda647Slclee {"t", 19, S_IFBLK}, 124*3ccda647Slclee {"u", 20, S_IFBLK}, 125*3ccda647Slclee #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 126*3ccda647Slclee {"a,raw", 0, S_IFCHR}, 127*3ccda647Slclee {"b,raw", 1, S_IFCHR}, 128*3ccda647Slclee {"c,raw", 2, S_IFCHR}, 129*3ccda647Slclee {"d,raw", 3, S_IFCHR}, 130*3ccda647Slclee {"e,raw", 4, S_IFCHR}, 131*3ccda647Slclee {"f,raw", 5, S_IFCHR}, 132*3ccda647Slclee {"g,raw", 6, S_IFCHR}, 133*3ccda647Slclee {"wd,raw", 7, S_IFCHR}, 134*3ccda647Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 135*3ccda647Slclee {"q,raw", 16, S_IFCHR}, 136*3ccda647Slclee {"r,raw", 17, S_IFCHR}, 137*3ccda647Slclee {"s,raw", 18, S_IFCHR}, 138*3ccda647Slclee {"t,raw", 19, S_IFCHR}, 139*3ccda647Slclee {"u,raw", 20, S_IFCHR}, 140*3ccda647Slclee #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 141*3ccda647Slclee {0} 142*3ccda647Slclee }; 143*3ccda647Slclee 144*3ccda647Slclee 145*3ccda647Slclee 146*3ccda647Slclee extern struct mod_ops mod_miscops; 147*3ccda647Slclee 148*3ccda647Slclee /* 149*3ccda647Slclee * Global buffer and mutex for debug logging 150*3ccda647Slclee */ 151*3ccda647Slclee static char cmlb_log_buffer[1024]; 152*3ccda647Slclee static kmutex_t cmlb_log_mutex; 153*3ccda647Slclee 154*3ccda647Slclee 155*3ccda647Slclee struct cmlb_lun *cmlb_debug_un = NULL; 156*3ccda647Slclee uint_t cmlb_level_mask = 0x0; 157*3ccda647Slclee 158*3ccda647Slclee int cmlb_rot_delay = 4; /* default rotational delay */ 159*3ccda647Slclee 160*3ccda647Slclee static struct modlmisc modlmisc = { 161*3ccda647Slclee &mod_miscops, /* Type of module */ 162*3ccda647Slclee "Common Labeling module %I%" 163*3ccda647Slclee }; 164*3ccda647Slclee 165*3ccda647Slclee static struct modlinkage modlinkage = { 166*3ccda647Slclee MODREV_1, (void *)&modlmisc, NULL 167*3ccda647Slclee }; 168*3ccda647Slclee 169*3ccda647Slclee /* Local function prototypes */ 170*3ccda647Slclee static dev_t cmlb_make_device(struct cmlb_lun *un); 171*3ccda647Slclee static int cmlb_validate_geometry(struct cmlb_lun *un, int forcerevalid); 172*3ccda647Slclee static void cmlb_resync_geom_caches(struct cmlb_lun *un, diskaddr_t capacity); 173*3ccda647Slclee static int cmlb_read_fdisk(struct cmlb_lun *un, diskaddr_t capacity); 174*3ccda647Slclee static void cmlb_swap_efi_gpt(efi_gpt_t *e); 175*3ccda647Slclee static void cmlb_swap_efi_gpe(int nparts, efi_gpe_t *p); 176*3ccda647Slclee static int cmlb_validate_efi(efi_gpt_t *labp); 177*3ccda647Slclee static int cmlb_use_efi(struct cmlb_lun *un, diskaddr_t capacity); 178*3ccda647Slclee static void cmlb_build_default_label(struct cmlb_lun *un); 179*3ccda647Slclee static int cmlb_uselabel(struct cmlb_lun *un, struct dk_label *l); 180*3ccda647Slclee static void cmlb_build_user_vtoc(struct cmlb_lun *un, struct vtoc *user_vtoc); 181*3ccda647Slclee static int cmlb_build_label_vtoc(struct cmlb_lun *un, struct vtoc *user_vtoc); 182*3ccda647Slclee static int cmlb_write_label(struct cmlb_lun *un); 183*3ccda647Slclee static int cmlb_set_vtoc(struct cmlb_lun *un, struct dk_label *dkl); 184*3ccda647Slclee static void cmlb_clear_efi(struct cmlb_lun *un); 185*3ccda647Slclee static void cmlb_clear_vtoc(struct cmlb_lun *un); 186*3ccda647Slclee static void cmlb_setup_default_geometry(struct cmlb_lun *un); 187*3ccda647Slclee static int cmlb_create_minor_nodes(struct cmlb_lun *un); 188*3ccda647Slclee static int cmlb_check_update_blockcount(struct cmlb_lun *un); 189*3ccda647Slclee 190*3ccda647Slclee #if defined(__i386) || defined(__amd64) 191*3ccda647Slclee static int cmlb_update_fdisk_and_vtoc(struct cmlb_lun *un); 192*3ccda647Slclee #endif 193*3ccda647Slclee 194*3ccda647Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 195*3ccda647Slclee static int cmlb_has_max_chs_vals(struct ipart *fdp); 196*3ccda647Slclee #endif 197*3ccda647Slclee 198*3ccda647Slclee #if defined(_SUNOS_VTOC_16) 199*3ccda647Slclee static void cmlb_convert_geometry(diskaddr_t capacity, struct dk_geom *un_g); 200*3ccda647Slclee #endif 201*3ccda647Slclee 202*3ccda647Slclee static int cmlb_dkio_get_geometry(struct cmlb_lun *un, caddr_t arg, int flag); 203*3ccda647Slclee static int cmlb_dkio_set_geometry(struct cmlb_lun *un, caddr_t arg, int flag); 204*3ccda647Slclee static int cmlb_dkio_get_partition(struct cmlb_lun *un, caddr_t arg, int flag); 205*3ccda647Slclee static int cmlb_dkio_set_partition(struct cmlb_lun *un, caddr_t arg, int flag); 206*3ccda647Slclee static int cmlb_dkio_get_efi(struct cmlb_lun *un, caddr_t arg, int flag); 207*3ccda647Slclee static int cmlb_dkio_set_efi(struct cmlb_lun *un, dev_t dev, caddr_t arg, 208*3ccda647Slclee int flag); 209*3ccda647Slclee static int cmlb_dkio_get_vtoc(struct cmlb_lun *un, caddr_t arg, int flag); 210*3ccda647Slclee static int cmlb_dkio_set_vtoc(struct cmlb_lun *un, dev_t dev, caddr_t arg, 211*3ccda647Slclee int flag); 212*3ccda647Slclee static int cmlb_dkio_get_mboot(struct cmlb_lun *un, caddr_t arg, int flag); 213*3ccda647Slclee static int cmlb_dkio_set_mboot(struct cmlb_lun *un, caddr_t arg, int flag); 214*3ccda647Slclee static int cmlb_dkio_partition(struct cmlb_lun *un, caddr_t arg, int flag); 215*3ccda647Slclee 216*3ccda647Slclee #if defined(__i386) || defined(__amd64) 217*3ccda647Slclee static int cmlb_dkio_get_virtgeom(struct cmlb_lun *un, caddr_t arg, int flag); 218*3ccda647Slclee static int cmlb_dkio_get_phygeom(struct cmlb_lun *un, caddr_t arg, int flag); 219*3ccda647Slclee static int cmlb_dkio_partinfo(struct cmlb_lun *un, dev_t dev, caddr_t arg, 220*3ccda647Slclee int flag); 221*3ccda647Slclee #endif 222*3ccda647Slclee 223*3ccda647Slclee static void cmlb_dbg(uint_t comp, struct cmlb_lun *un, const char *fmt, ...); 224*3ccda647Slclee static void cmlb_v_log(dev_info_t *dev, char *label, uint_t level, 225*3ccda647Slclee const char *fmt, va_list ap); 226*3ccda647Slclee static void cmlb_log(dev_info_t *dev, char *label, uint_t level, 227*3ccda647Slclee const char *fmt, ...); 228*3ccda647Slclee 229*3ccda647Slclee int 230*3ccda647Slclee _init(void) 231*3ccda647Slclee { 232*3ccda647Slclee mutex_init(&cmlb_log_mutex, NULL, MUTEX_DRIVER, NULL); 233*3ccda647Slclee return (mod_install(&modlinkage)); 234*3ccda647Slclee } 235*3ccda647Slclee 236*3ccda647Slclee int 237*3ccda647Slclee _info(struct modinfo *modinfop) 238*3ccda647Slclee { 239*3ccda647Slclee return (mod_info(&modlinkage, modinfop)); 240*3ccda647Slclee } 241*3ccda647Slclee 242*3ccda647Slclee int 243*3ccda647Slclee _fini(void) 244*3ccda647Slclee { 245*3ccda647Slclee int err; 246*3ccda647Slclee 247*3ccda647Slclee if ((err = mod_remove(&modlinkage)) != 0) { 248*3ccda647Slclee return (err); 249*3ccda647Slclee } 250*3ccda647Slclee 251*3ccda647Slclee mutex_destroy(&cmlb_log_mutex); 252*3ccda647Slclee return (err); 253*3ccda647Slclee } 254*3ccda647Slclee 255*3ccda647Slclee /* 256*3ccda647Slclee * cmlb_dbg is used for debugging to log additional info 257*3ccda647Slclee * Level of output is controlled via cmlb_level_mask setting. 258*3ccda647Slclee */ 259*3ccda647Slclee static void 260*3ccda647Slclee cmlb_dbg(uint_t comp, struct cmlb_lun *un, const char *fmt, ...) 261*3ccda647Slclee { 262*3ccda647Slclee va_list ap; 263*3ccda647Slclee dev_info_t *dev; 264*3ccda647Slclee uint_t level_mask = 0; 265*3ccda647Slclee 266*3ccda647Slclee ASSERT(un != NULL); 267*3ccda647Slclee dev = CMLB_DEVINFO(un); 268*3ccda647Slclee ASSERT(dev != NULL); 269*3ccda647Slclee /* 270*3ccda647Slclee * Filter messages based on the global component and level masks, 271*3ccda647Slclee * also print if un matches the value of cmlb_debug_un, or if 272*3ccda647Slclee * cmlb_debug_un is set to NULL. 273*3ccda647Slclee */ 274*3ccda647Slclee if (comp & CMLB_TRACE) 275*3ccda647Slclee level_mask |= CMLB_LOGMASK_TRACE; 276*3ccda647Slclee 277*3ccda647Slclee if (comp & CMLB_INFO) 278*3ccda647Slclee level_mask |= CMLB_LOGMASK_INFO; 279*3ccda647Slclee 280*3ccda647Slclee if (comp & CMLB_ERROR) 281*3ccda647Slclee level_mask |= CMLB_LOGMASK_ERROR; 282*3ccda647Slclee 283*3ccda647Slclee if ((cmlb_level_mask & level_mask) && 284*3ccda647Slclee ((cmlb_debug_un == NULL) || (cmlb_debug_un == un))) { 285*3ccda647Slclee va_start(ap, fmt); 286*3ccda647Slclee cmlb_v_log(dev, CMLB_LABEL(un), CE_CONT, fmt, ap); 287*3ccda647Slclee va_end(ap); 288*3ccda647Slclee } 289*3ccda647Slclee } 290*3ccda647Slclee 291*3ccda647Slclee /* 292*3ccda647Slclee * cmlb_log is basically a duplicate of scsi_log. It is redefined here 293*3ccda647Slclee * so that this module does not depend on scsi module. 294*3ccda647Slclee */ 295*3ccda647Slclee static void 296*3ccda647Slclee cmlb_log(dev_info_t *dev, char *label, uint_t level, const char *fmt, ...) 297*3ccda647Slclee { 298*3ccda647Slclee va_list ap; 299*3ccda647Slclee 300*3ccda647Slclee va_start(ap, fmt); 301*3ccda647Slclee cmlb_v_log(dev, label, level, fmt, ap); 302*3ccda647Slclee va_end(ap); 303*3ccda647Slclee } 304*3ccda647Slclee 305*3ccda647Slclee static void 306*3ccda647Slclee cmlb_v_log(dev_info_t *dev, char *label, uint_t level, const char *fmt, 307*3ccda647Slclee va_list ap) 308*3ccda647Slclee { 309*3ccda647Slclee static char name[256]; 310*3ccda647Slclee int log_only = 0; 311*3ccda647Slclee int boot_only = 0; 312*3ccda647Slclee int console_only = 0; 313*3ccda647Slclee 314*3ccda647Slclee mutex_enter(&cmlb_log_mutex); 315*3ccda647Slclee 316*3ccda647Slclee if (dev) { 317*3ccda647Slclee if (level == CE_PANIC || level == CE_WARN || 318*3ccda647Slclee level == CE_NOTE) { 319*3ccda647Slclee (void) sprintf(name, "%s (%s%d):\n", 320*3ccda647Slclee ddi_pathname(dev, cmlb_log_buffer), 321*3ccda647Slclee label, ddi_get_instance(dev)); 322*3ccda647Slclee } else { 323*3ccda647Slclee name[0] = '\0'; 324*3ccda647Slclee } 325*3ccda647Slclee } else { 326*3ccda647Slclee (void) sprintf(name, "%s:", label); 327*3ccda647Slclee } 328*3ccda647Slclee 329*3ccda647Slclee (void) vsprintf(cmlb_log_buffer, fmt, ap); 330*3ccda647Slclee 331*3ccda647Slclee switch (cmlb_log_buffer[0]) { 332*3ccda647Slclee case '!': 333*3ccda647Slclee log_only = 1; 334*3ccda647Slclee break; 335*3ccda647Slclee case '?': 336*3ccda647Slclee boot_only = 1; 337*3ccda647Slclee break; 338*3ccda647Slclee case '^': 339*3ccda647Slclee console_only = 1; 340*3ccda647Slclee break; 341*3ccda647Slclee } 342*3ccda647Slclee 343*3ccda647Slclee switch (level) { 344*3ccda647Slclee case CE_NOTE: 345*3ccda647Slclee level = CE_CONT; 346*3ccda647Slclee /* FALLTHROUGH */ 347*3ccda647Slclee case CE_CONT: 348*3ccda647Slclee case CE_WARN: 349*3ccda647Slclee case CE_PANIC: 350*3ccda647Slclee if (boot_only) { 351*3ccda647Slclee cmn_err(level, "?%s\t%s", name, &cmlb_log_buffer[1]); 352*3ccda647Slclee } else if (console_only) { 353*3ccda647Slclee cmn_err(level, "^%s\t%s", name, &cmlb_log_buffer[1]); 354*3ccda647Slclee } else if (log_only) { 355*3ccda647Slclee cmn_err(level, "!%s\t%s", name, &cmlb_log_buffer[1]); 356*3ccda647Slclee } else { 357*3ccda647Slclee cmn_err(level, "%s\t%s", name, cmlb_log_buffer); 358*3ccda647Slclee } 359*3ccda647Slclee break; 360*3ccda647Slclee case CE_IGNORE: 361*3ccda647Slclee break; 362*3ccda647Slclee default: 363*3ccda647Slclee cmn_err(CE_CONT, "^DEBUG: %s\t%s", name, cmlb_log_buffer); 364*3ccda647Slclee break; 365*3ccda647Slclee } 366*3ccda647Slclee mutex_exit(&cmlb_log_mutex); 367*3ccda647Slclee } 368*3ccda647Slclee 369*3ccda647Slclee 370*3ccda647Slclee /* 371*3ccda647Slclee * cmlb_alloc_handle: 372*3ccda647Slclee * 373*3ccda647Slclee * Allocates a handle. 374*3ccda647Slclee * 375*3ccda647Slclee * Arguments: 376*3ccda647Slclee * cmlbhandlep pointer to handle 377*3ccda647Slclee * 378*3ccda647Slclee * Notes: 379*3ccda647Slclee * Allocates a handle and stores the allocated handle in the area 380*3ccda647Slclee * pointed to by cmlbhandlep 381*3ccda647Slclee * 382*3ccda647Slclee * Context: 383*3ccda647Slclee * Kernel thread only (can sleep). 384*3ccda647Slclee */ 385*3ccda647Slclee void 386*3ccda647Slclee cmlb_alloc_handle(cmlb_handle_t *cmlbhandlep) 387*3ccda647Slclee { 388*3ccda647Slclee struct cmlb_lun *un; 389*3ccda647Slclee 390*3ccda647Slclee un = kmem_zalloc(sizeof (struct cmlb_lun), KM_SLEEP); 391*3ccda647Slclee ASSERT(cmlbhandlep != NULL); 392*3ccda647Slclee 393*3ccda647Slclee un->un_state = CMLB_INITED; 394*3ccda647Slclee un->un_def_labeltype = CMLB_LABEL_UNDEF; 395*3ccda647Slclee mutex_init(CMLB_MUTEX(un), NULL, MUTEX_DRIVER, NULL); 396*3ccda647Slclee 397*3ccda647Slclee *cmlbhandlep = (cmlb_handle_t)(un); 398*3ccda647Slclee } 399*3ccda647Slclee 400*3ccda647Slclee /* 401*3ccda647Slclee * cmlb_free_handle 402*3ccda647Slclee * 403*3ccda647Slclee * Frees handle. 404*3ccda647Slclee * 405*3ccda647Slclee * Arguments: 406*3ccda647Slclee * cmlbhandlep pointer to handle 407*3ccda647Slclee */ 408*3ccda647Slclee void 409*3ccda647Slclee cmlb_free_handle(cmlb_handle_t *cmlbhandlep) 410*3ccda647Slclee { 411*3ccda647Slclee struct cmlb_lun *un; 412*3ccda647Slclee 413*3ccda647Slclee un = (struct cmlb_lun *)*cmlbhandlep; 414*3ccda647Slclee if (un != NULL) { 415*3ccda647Slclee mutex_destroy(CMLB_MUTEX(un)); 416*3ccda647Slclee kmem_free(un, sizeof (struct cmlb_lun)); 417*3ccda647Slclee } 418*3ccda647Slclee 419*3ccda647Slclee } 420*3ccda647Slclee 421*3ccda647Slclee /* 422*3ccda647Slclee * cmlb_attach: 423*3ccda647Slclee * 424*3ccda647Slclee * Attach handle to device, create minor nodes for device. 425*3ccda647Slclee * 426*3ccda647Slclee * Arguments: 427*3ccda647Slclee * devi pointer to device's dev_info structure. 428*3ccda647Slclee * tgopsp pointer to array of functions cmlb can use to callback 429*3ccda647Slclee * to target driver. 430*3ccda647Slclee * 431*3ccda647Slclee * device_type Peripheral device type as defined in 432*3ccda647Slclee * scsi/generic/inquiry.h 433*3ccda647Slclee * 434*3ccda647Slclee * is_removable whether or not device is removable. 435*3ccda647Slclee * 0 non-removable, 1 removable. 436*3ccda647Slclee * 437*3ccda647Slclee * node_type minor node type (as used by ddi_create_minor_node) 438*3ccda647Slclee * 439*3ccda647Slclee * alter_behavior 440*3ccda647Slclee * bit flags: 441*3ccda647Slclee * 442*3ccda647Slclee * CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT: create 443*3ccda647Slclee * an alternate slice for the default label, if 444*3ccda647Slclee * device type is DTYPE_DIRECT an architectures default 445*3ccda647Slclee * label type is VTOC16. 446*3ccda647Slclee * Otherwise alternate slice will no be created. 447*3ccda647Slclee * 448*3ccda647Slclee * 449*3ccda647Slclee * CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8: report a default 450*3ccda647Slclee * geometry and label for DKIOCGGEOM and DKIOCGVTOC 451*3ccda647Slclee * on architecture with VTOC8 label types. 452*3ccda647Slclee * 453*3ccda647Slclee * 454*3ccda647Slclee * cmlbhandle cmlb handle associated with device 455*3ccda647Slclee * 456*3ccda647Slclee * Notes: 457*3ccda647Slclee * Assumes a default label based on capacity for non-removable devices. 458*3ccda647Slclee * If capacity > 1TB, EFI is assumed otherwise VTOC (default VTOC 459*3ccda647Slclee * for the architecture). 460*3ccda647Slclee * 461*3ccda647Slclee * For removable devices, default label type is assumed to be VTOC 462*3ccda647Slclee * type. Create minor nodes based on a default label type. 463*3ccda647Slclee * Label on the media is not validated. 464*3ccda647Slclee * minor number consists of: 465*3ccda647Slclee * if _SUNOS_VTOC_8 is defined 466*3ccda647Slclee * lowest 3 bits is taken as partition number 467*3ccda647Slclee * the rest is instance number 468*3ccda647Slclee * if _SUNOS_VTOC_16 is defined 469*3ccda647Slclee * lowest 6 bits is taken as partition number 470*3ccda647Slclee * the rest is instance number 471*3ccda647Slclee * 472*3ccda647Slclee * 473*3ccda647Slclee * Return values: 474*3ccda647Slclee * 0 Success 475*3ccda647Slclee * ENXIO creating minor nodes failed. 476*3ccda647Slclee */ 477*3ccda647Slclee int 478*3ccda647Slclee cmlb_attach(dev_info_t *devi, cmlb_tg_ops_t *tgopsp, int device_type, 479*3ccda647Slclee int is_removable, char *node_type, int alter_behavior, 480*3ccda647Slclee cmlb_handle_t cmlbhandle) 481*3ccda647Slclee { 482*3ccda647Slclee 483*3ccda647Slclee struct cmlb_lun *un = (struct cmlb_lun *)cmlbhandle; 484*3ccda647Slclee diskaddr_t cap; 485*3ccda647Slclee int status; 486*3ccda647Slclee 487*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 488*3ccda647Slclee 489*3ccda647Slclee CMLB_DEVINFO(un) = devi; 490*3ccda647Slclee un->cmlb_tg_ops = tgopsp; 491*3ccda647Slclee un->un_device_type = device_type; 492*3ccda647Slclee un->un_is_removable = is_removable; 493*3ccda647Slclee un->un_node_type = node_type; 494*3ccda647Slclee un->un_sys_blocksize = DEV_BSIZE; 495*3ccda647Slclee un->un_f_geometry_is_valid = FALSE; 496*3ccda647Slclee un->un_def_labeltype = CMLB_LABEL_VTOC; 497*3ccda647Slclee un->un_alter_behavior = alter_behavior; 498*3ccda647Slclee 499*3ccda647Slclee if (is_removable != 0) { 500*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 501*3ccda647Slclee status = DK_TG_GETCAP(un, &cap); 502*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 503*3ccda647Slclee if (status == 0 && cap > DK_MAX_BLOCKS) { 504*3ccda647Slclee /* set default EFI if > 1TB */ 505*3ccda647Slclee un->un_def_labeltype = CMLB_LABEL_EFI; 506*3ccda647Slclee } 507*3ccda647Slclee } 508*3ccda647Slclee 509*3ccda647Slclee /* create minor nodes based on default label type */ 510*3ccda647Slclee un->un_last_labeltype = CMLB_LABEL_UNDEF; 511*3ccda647Slclee un->un_cur_labeltype = CMLB_LABEL_UNDEF; 512*3ccda647Slclee 513*3ccda647Slclee if (cmlb_create_minor_nodes(un) != 0) { 514*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 515*3ccda647Slclee return (ENXIO); 516*3ccda647Slclee } 517*3ccda647Slclee 518*3ccda647Slclee un->un_state = CMLB_ATTACHED; 519*3ccda647Slclee 520*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 521*3ccda647Slclee return (0); 522*3ccda647Slclee } 523*3ccda647Slclee 524*3ccda647Slclee /* 525*3ccda647Slclee * cmlb_detach: 526*3ccda647Slclee * 527*3ccda647Slclee * Invalidate in-core labeling data and remove all minor nodes for 528*3ccda647Slclee * the device associate with handle. 529*3ccda647Slclee * 530*3ccda647Slclee * Arguments: 531*3ccda647Slclee * cmlbhandle cmlb handle associated with device. 532*3ccda647Slclee * 533*3ccda647Slclee */ 534*3ccda647Slclee void 535*3ccda647Slclee cmlb_detach(cmlb_handle_t cmlbhandle) 536*3ccda647Slclee { 537*3ccda647Slclee struct cmlb_lun *un = (struct cmlb_lun *)cmlbhandle; 538*3ccda647Slclee 539*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 540*3ccda647Slclee un->un_def_labeltype = CMLB_LABEL_UNDEF; 541*3ccda647Slclee un->un_f_geometry_is_valid = FALSE; 542*3ccda647Slclee ddi_remove_minor_node(CMLB_DEVINFO(un), NULL); 543*3ccda647Slclee un->un_state = CMLB_INITED; 544*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 545*3ccda647Slclee } 546*3ccda647Slclee 547*3ccda647Slclee /* 548*3ccda647Slclee * cmlb_validate: 549*3ccda647Slclee * 550*3ccda647Slclee * Validates label. 551*3ccda647Slclee * 552*3ccda647Slclee * Arguments 553*3ccda647Slclee * cmlbhandle cmlb handle associated with device. 554*3ccda647Slclee * 555*3ccda647Slclee * Notes: 556*3ccda647Slclee * If new label type is different from the current, adjust minor nodes 557*3ccda647Slclee * accordingly. 558*3ccda647Slclee * 559*3ccda647Slclee * Return values: 560*3ccda647Slclee * 0 success 561*3ccda647Slclee * Note: having fdisk but no solaris partition is assumed 562*3ccda647Slclee * success. 563*3ccda647Slclee * 564*3ccda647Slclee * ENOMEM memory allocation failed 565*3ccda647Slclee * EIO i/o errors during read or get capacity 566*3ccda647Slclee * EACCESS reservation conflicts 567*3ccda647Slclee * EINVAL label was corrupt, or no default label was assumed 568*3ccda647Slclee * ENXIO invalid handle 569*3ccda647Slclee */ 570*3ccda647Slclee int 571*3ccda647Slclee cmlb_validate(cmlb_handle_t cmlbhandle) 572*3ccda647Slclee { 573*3ccda647Slclee struct cmlb_lun *un = (struct cmlb_lun *)cmlbhandle; 574*3ccda647Slclee int rval; 575*3ccda647Slclee int ret = 0; 576*3ccda647Slclee 577*3ccda647Slclee /* 578*3ccda647Slclee * Temp work-around checking un for NULL since there is a bug 579*3ccda647Slclee * in sd_detach calling this routine from taskq_dispatch 580*3ccda647Slclee * inited function. 581*3ccda647Slclee */ 582*3ccda647Slclee if (un == NULL) 583*3ccda647Slclee return (ENXIO); 584*3ccda647Slclee 585*3ccda647Slclee ASSERT(un != NULL); 586*3ccda647Slclee 587*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 588*3ccda647Slclee if (un->un_state < CMLB_ATTACHED) { 589*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 590*3ccda647Slclee return (ENXIO); 591*3ccda647Slclee } 592*3ccda647Slclee 593*3ccda647Slclee rval = cmlb_validate_geometry((struct cmlb_lun *)cmlbhandle, 0); 594*3ccda647Slclee 595*3ccda647Slclee if (rval == ENOTSUP) { 596*3ccda647Slclee if (un->un_f_geometry_is_valid == TRUE) { 597*3ccda647Slclee un->un_cur_labeltype = CMLB_LABEL_EFI; 598*3ccda647Slclee ret = 0; 599*3ccda647Slclee } else { 600*3ccda647Slclee ret = EINVAL; 601*3ccda647Slclee } 602*3ccda647Slclee } else { 603*3ccda647Slclee ret = rval; 604*3ccda647Slclee if (ret == 0) 605*3ccda647Slclee un->un_cur_labeltype = CMLB_LABEL_VTOC; 606*3ccda647Slclee } 607*3ccda647Slclee 608*3ccda647Slclee if (ret == 0) 609*3ccda647Slclee (void) cmlb_create_minor_nodes(un); 610*3ccda647Slclee 611*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 612*3ccda647Slclee return (ret); 613*3ccda647Slclee } 614*3ccda647Slclee 615*3ccda647Slclee /* 616*3ccda647Slclee * cmlb_invalidate: 617*3ccda647Slclee * Invalidate in core label data 618*3ccda647Slclee * 619*3ccda647Slclee * Arguments: 620*3ccda647Slclee * cmlbhandle cmlb handle associated with device. 621*3ccda647Slclee */ 622*3ccda647Slclee void 623*3ccda647Slclee cmlb_invalidate(cmlb_handle_t cmlbhandle) 624*3ccda647Slclee { 625*3ccda647Slclee struct cmlb_lun *un = (struct cmlb_lun *)cmlbhandle; 626*3ccda647Slclee 627*3ccda647Slclee if (un == NULL) 628*3ccda647Slclee return; 629*3ccda647Slclee 630*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 631*3ccda647Slclee un->un_f_geometry_is_valid = FALSE; 632*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 633*3ccda647Slclee } 634*3ccda647Slclee 635*3ccda647Slclee /* 636*3ccda647Slclee * cmlb_close: 637*3ccda647Slclee * 638*3ccda647Slclee * Close the device, revert to a default label minor node for the device, 639*3ccda647Slclee * if it is removable. 640*3ccda647Slclee * 641*3ccda647Slclee * Arguments: 642*3ccda647Slclee * cmlbhandle cmlb handle associated with device. 643*3ccda647Slclee * 644*3ccda647Slclee * Return values: 645*3ccda647Slclee * 0 Success 646*3ccda647Slclee * ENXIO Re-creating minor node failed. 647*3ccda647Slclee */ 648*3ccda647Slclee int 649*3ccda647Slclee cmlb_close(cmlb_handle_t cmlbhandle) 650*3ccda647Slclee { 651*3ccda647Slclee struct cmlb_lun *un = (struct cmlb_lun *)cmlbhandle; 652*3ccda647Slclee 653*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 654*3ccda647Slclee un->un_f_geometry_is_valid = FALSE; 655*3ccda647Slclee 656*3ccda647Slclee /* revert to default minor node for this device */ 657*3ccda647Slclee if (ISREMOVABLE(un)) { 658*3ccda647Slclee un->un_cur_labeltype = CMLB_LABEL_UNDEF; 659*3ccda647Slclee (void) cmlb_create_minor_nodes(un); 660*3ccda647Slclee } 661*3ccda647Slclee 662*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 663*3ccda647Slclee return (0); 664*3ccda647Slclee } 665*3ccda647Slclee 666*3ccda647Slclee /* 667*3ccda647Slclee * cmlb_get_devid_block: 668*3ccda647Slclee * get the block number where device id is stored. 669*3ccda647Slclee * 670*3ccda647Slclee * Arguments: 671*3ccda647Slclee * cmlbhandle cmlb handle associated with device. 672*3ccda647Slclee * devidblockp pointer to block number. 673*3ccda647Slclee * 674*3ccda647Slclee * Notes: 675*3ccda647Slclee * It stores the block number of device id in the area pointed to 676*3ccda647Slclee * by devidblockp. 677*3ccda647Slclee * with the block number of device id. 678*3ccda647Slclee * 679*3ccda647Slclee * Return values: 680*3ccda647Slclee * 0 success 681*3ccda647Slclee * EINVAL device id does not apply to current label type. 682*3ccda647Slclee */ 683*3ccda647Slclee int 684*3ccda647Slclee cmlb_get_devid_block(cmlb_handle_t cmlbhandle, diskaddr_t *devidblockp) 685*3ccda647Slclee { 686*3ccda647Slclee daddr_t spc, blk, head, cyl; 687*3ccda647Slclee struct cmlb_lun *un = (struct cmlb_lun *)cmlbhandle; 688*3ccda647Slclee 689*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 690*3ccda647Slclee if (un->un_state < CMLB_ATTACHED) { 691*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 692*3ccda647Slclee return (EINVAL); 693*3ccda647Slclee } 694*3ccda647Slclee 695*3ccda647Slclee if (un->un_blockcount <= DK_MAX_BLOCKS) { 696*3ccda647Slclee /* this geometry doesn't allow us to write a devid */ 697*3ccda647Slclee if (un->un_g.dkg_acyl < 2) { 698*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 699*3ccda647Slclee return (EINVAL); 700*3ccda647Slclee } 701*3ccda647Slclee 702*3ccda647Slclee /* 703*3ccda647Slclee * Subtract 2 guarantees that the next to last cylinder 704*3ccda647Slclee * is used 705*3ccda647Slclee */ 706*3ccda647Slclee cyl = un->un_g.dkg_ncyl + un->un_g.dkg_acyl - 2; 707*3ccda647Slclee spc = un->un_g.dkg_nhead * un->un_g.dkg_nsect; 708*3ccda647Slclee head = un->un_g.dkg_nhead - 1; 709*3ccda647Slclee blk = (cyl * (spc - un->un_g.dkg_apc)) + 710*3ccda647Slclee (head * un->un_g.dkg_nsect) + 1; 711*3ccda647Slclee } else { 712*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 713*3ccda647Slclee return (EINVAL); 714*3ccda647Slclee } 715*3ccda647Slclee *devidblockp = blk; 716*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 717*3ccda647Slclee return (0); 718*3ccda647Slclee } 719*3ccda647Slclee 720*3ccda647Slclee /* 721*3ccda647Slclee * cmlb_partinfo: 722*3ccda647Slclee * Get partition info for specified partition number. 723*3ccda647Slclee * 724*3ccda647Slclee * Arguments: 725*3ccda647Slclee * cmlbhandle cmlb handle associated with device. 726*3ccda647Slclee * part partition number 727*3ccda647Slclee * nblocksp pointer to number of blocks 728*3ccda647Slclee * startblockp pointer to starting block 729*3ccda647Slclee * partnamep pointer to name of partition 730*3ccda647Slclee * tagp pointer to tag info 731*3ccda647Slclee * 732*3ccda647Slclee * 733*3ccda647Slclee * Notes: 734*3ccda647Slclee * If in-core label is not valid, this functions tries to revalidate 735*3ccda647Slclee * the label. If label is valid, it stores the total number of blocks 736*3ccda647Slclee * in this partition in the area pointed to by nblocksp, starting 737*3ccda647Slclee * block number in area pointed to by startblockp, pointer to partition 738*3ccda647Slclee * name in area pointed to by partnamep, and tag value in area 739*3ccda647Slclee * pointed by tagp. 740*3ccda647Slclee * For EFI labels, tag value will be set to 0. 741*3ccda647Slclee * 742*3ccda647Slclee * For all nblocksp, startblockp and partnamep, tagp, a value of NULL 743*3ccda647Slclee * indicates the corresponding info is not requested. 744*3ccda647Slclee * 745*3ccda647Slclee * 746*3ccda647Slclee * Return values: 747*3ccda647Slclee * 0 success 748*3ccda647Slclee * EINVAL no valid label or requested partition number is invalid. 749*3ccda647Slclee * 750*3ccda647Slclee */ 751*3ccda647Slclee int 752*3ccda647Slclee cmlb_partinfo(cmlb_handle_t cmlbhandle, int part, diskaddr_t *nblocksp, 753*3ccda647Slclee diskaddr_t *startblockp, char **partnamep, uint16_t *tagp) 754*3ccda647Slclee { 755*3ccda647Slclee 756*3ccda647Slclee struct cmlb_lun *un = (struct cmlb_lun *)cmlbhandle; 757*3ccda647Slclee int rval; 758*3ccda647Slclee 759*3ccda647Slclee ASSERT(un != NULL); 760*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 761*3ccda647Slclee if (un->un_state < CMLB_ATTACHED) { 762*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 763*3ccda647Slclee return (EINVAL); 764*3ccda647Slclee } 765*3ccda647Slclee 766*3ccda647Slclee if (part < 0 || part >= MAXPART) { 767*3ccda647Slclee rval = EINVAL; 768*3ccda647Slclee } else { 769*3ccda647Slclee (void) cmlb_validate_geometry((struct cmlb_lun *)un, 0); 770*3ccda647Slclee if ((un->un_f_geometry_is_valid == FALSE) || 771*3ccda647Slclee (part < NDKMAP && un->un_solaris_size == 0)) { 772*3ccda647Slclee rval = EINVAL; 773*3ccda647Slclee } else { 774*3ccda647Slclee if (startblockp != NULL) 775*3ccda647Slclee *startblockp = (diskaddr_t)un->un_offset[part]; 776*3ccda647Slclee 777*3ccda647Slclee if (nblocksp != NULL) 778*3ccda647Slclee *nblocksp = (diskaddr_t) 779*3ccda647Slclee un->un_map[part].dkl_nblk; 780*3ccda647Slclee 781*3ccda647Slclee if (tagp != NULL) 782*3ccda647Slclee if (un->un_cur_labeltype == CMLB_LABEL_EFI) 783*3ccda647Slclee *tagp = V_UNASSIGNED; 784*3ccda647Slclee else 785*3ccda647Slclee *tagp = un->un_vtoc.v_part[part].p_tag; 786*3ccda647Slclee rval = 0; 787*3ccda647Slclee } 788*3ccda647Slclee 789*3ccda647Slclee /* consistent with behavior of sd for getting minor name */ 790*3ccda647Slclee if (partnamep != NULL) 791*3ccda647Slclee *partnamep = dk_minor_data[part].name; 792*3ccda647Slclee 793*3ccda647Slclee } 794*3ccda647Slclee 795*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 796*3ccda647Slclee return (rval); 797*3ccda647Slclee } 798*3ccda647Slclee 799*3ccda647Slclee /* ARGSUSED */ 800*3ccda647Slclee int 801*3ccda647Slclee cmlb_ioctl(cmlb_handle_t cmlbhandle, dev_t dev, int cmd, intptr_t arg, 802*3ccda647Slclee int flag, cred_t *cred_p, int *rval_p) 803*3ccda647Slclee { 804*3ccda647Slclee 805*3ccda647Slclee int err; 806*3ccda647Slclee struct cmlb_lun *un; 807*3ccda647Slclee 808*3ccda647Slclee un = (struct cmlb_lun *)cmlbhandle; 809*3ccda647Slclee 810*3ccda647Slclee ASSERT(un != NULL); 811*3ccda647Slclee 812*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 813*3ccda647Slclee if (un->un_state < CMLB_ATTACHED) { 814*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 815*3ccda647Slclee return (EIO); 816*3ccda647Slclee } 817*3ccda647Slclee 818*3ccda647Slclee 819*3ccda647Slclee if ((cmlb_check_update_blockcount(un) == 0) && 820*3ccda647Slclee (un->un_blockcount > DK_MAX_BLOCKS)) { 821*3ccda647Slclee switch (cmd) { 822*3ccda647Slclee case DKIOCGAPART: 823*3ccda647Slclee case DKIOCGGEOM: 824*3ccda647Slclee case DKIOCSGEOM: 825*3ccda647Slclee case DKIOCGVTOC: 826*3ccda647Slclee case DKIOCSVTOC: 827*3ccda647Slclee case DKIOCSAPART: 828*3ccda647Slclee case DKIOCG_PHYGEOM: 829*3ccda647Slclee case DKIOCG_VIRTGEOM: 830*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 831*3ccda647Slclee return (ENOTSUP); 832*3ccda647Slclee } 833*3ccda647Slclee } 834*3ccda647Slclee 835*3ccda647Slclee switch (cmd) { 836*3ccda647Slclee case DKIOCSVTOC: 837*3ccda647Slclee case DKIOCSETEFI: 838*3ccda647Slclee case DKIOCSMBOOT: 839*3ccda647Slclee break; 840*3ccda647Slclee default: 841*3ccda647Slclee (void) cmlb_validate_geometry(un, 0); 842*3ccda647Slclee if ((un->un_f_geometry_is_valid == TRUE) && 843*3ccda647Slclee (un->un_solaris_size > 0)) { 844*3ccda647Slclee /* 845*3ccda647Slclee * the "geometry_is_valid" flag could be true if we 846*3ccda647Slclee * have an fdisk table but no Solaris partition 847*3ccda647Slclee */ 848*3ccda647Slclee if (un->un_vtoc.v_sanity != VTOC_SANE) { 849*3ccda647Slclee /* it is EFI, so return ENOTSUP for these */ 850*3ccda647Slclee switch (cmd) { 851*3ccda647Slclee case DKIOCGAPART: 852*3ccda647Slclee case DKIOCGGEOM: 853*3ccda647Slclee case DKIOCGVTOC: 854*3ccda647Slclee case DKIOCSVTOC: 855*3ccda647Slclee case DKIOCSAPART: 856*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 857*3ccda647Slclee return (ENOTSUP); 858*3ccda647Slclee } 859*3ccda647Slclee } 860*3ccda647Slclee } 861*3ccda647Slclee } 862*3ccda647Slclee 863*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 864*3ccda647Slclee 865*3ccda647Slclee switch (cmd) { 866*3ccda647Slclee case DKIOCGGEOM: 867*3ccda647Slclee cmlb_dbg(CMLB_TRACE, un, "DKIOCGGEOM\n"); 868*3ccda647Slclee err = cmlb_dkio_get_geometry(un, (caddr_t)arg, flag); 869*3ccda647Slclee break; 870*3ccda647Slclee 871*3ccda647Slclee case DKIOCSGEOM: 872*3ccda647Slclee cmlb_dbg(CMLB_TRACE, un, "DKIOCSGEOM\n"); 873*3ccda647Slclee err = cmlb_dkio_set_geometry(un, (caddr_t)arg, flag); 874*3ccda647Slclee break; 875*3ccda647Slclee 876*3ccda647Slclee case DKIOCGAPART: 877*3ccda647Slclee cmlb_dbg(CMLB_TRACE, un, "DKIOCGAPART\n"); 878*3ccda647Slclee err = cmlb_dkio_get_partition(un, (caddr_t)arg, flag); 879*3ccda647Slclee break; 880*3ccda647Slclee 881*3ccda647Slclee case DKIOCSAPART: 882*3ccda647Slclee cmlb_dbg(CMLB_TRACE, un, "DKIOCSAPART\n"); 883*3ccda647Slclee err = cmlb_dkio_set_partition(un, (caddr_t)arg, flag); 884*3ccda647Slclee break; 885*3ccda647Slclee 886*3ccda647Slclee case DKIOCGVTOC: 887*3ccda647Slclee cmlb_dbg(CMLB_TRACE, un, "DKIOCGVTOC\n"); 888*3ccda647Slclee err = cmlb_dkio_get_vtoc(un, (caddr_t)arg, flag); 889*3ccda647Slclee break; 890*3ccda647Slclee 891*3ccda647Slclee case DKIOCGETEFI: 892*3ccda647Slclee cmlb_dbg(CMLB_TRACE, un, "DKIOCGETEFI\n"); 893*3ccda647Slclee err = cmlb_dkio_get_efi(un, (caddr_t)arg, flag); 894*3ccda647Slclee break; 895*3ccda647Slclee 896*3ccda647Slclee case DKIOCPARTITION: 897*3ccda647Slclee cmlb_dbg(CMLB_TRACE, un, "DKIOCPARTITION\n"); 898*3ccda647Slclee err = cmlb_dkio_partition(un, (caddr_t)arg, flag); 899*3ccda647Slclee break; 900*3ccda647Slclee 901*3ccda647Slclee case DKIOCSVTOC: 902*3ccda647Slclee cmlb_dbg(CMLB_TRACE, un, "DKIOCSVTOC\n"); 903*3ccda647Slclee err = cmlb_dkio_set_vtoc(un, dev, (caddr_t)arg, flag); 904*3ccda647Slclee break; 905*3ccda647Slclee 906*3ccda647Slclee case DKIOCSETEFI: 907*3ccda647Slclee cmlb_dbg(CMLB_TRACE, un, "DKIOCSETEFI\n"); 908*3ccda647Slclee err = cmlb_dkio_set_efi(un, dev, (caddr_t)arg, flag); 909*3ccda647Slclee break; 910*3ccda647Slclee 911*3ccda647Slclee case DKIOCGMBOOT: 912*3ccda647Slclee cmlb_dbg(CMLB_TRACE, un, "DKIOCGMBOOT\n"); 913*3ccda647Slclee err = cmlb_dkio_get_mboot(un, (caddr_t)arg, flag); 914*3ccda647Slclee break; 915*3ccda647Slclee 916*3ccda647Slclee case DKIOCSMBOOT: 917*3ccda647Slclee cmlb_dbg(CMLB_TRACE, un, "DKIOCSMBOOT\n"); 918*3ccda647Slclee err = cmlb_dkio_set_mboot(un, (caddr_t)arg, flag); 919*3ccda647Slclee break; 920*3ccda647Slclee case DKIOCG_PHYGEOM: 921*3ccda647Slclee cmlb_dbg(CMLB_TRACE, un, "DKIOCG_PHYGEOM\n"); 922*3ccda647Slclee #if defined(__i386) || defined(__amd64) 923*3ccda647Slclee err = cmlb_dkio_get_phygeom(un, (caddr_t)arg, flag); 924*3ccda647Slclee #else 925*3ccda647Slclee err = ENOTTY; 926*3ccda647Slclee #endif 927*3ccda647Slclee break; 928*3ccda647Slclee case DKIOCG_VIRTGEOM: 929*3ccda647Slclee cmlb_dbg(CMLB_TRACE, un, "DKIOCG_VIRTGEOM\n"); 930*3ccda647Slclee #if defined(__i386) || defined(__amd64) 931*3ccda647Slclee err = cmlb_dkio_get_virtgeom(un, (caddr_t)arg, flag); 932*3ccda647Slclee #else 933*3ccda647Slclee err = ENOTTY; 934*3ccda647Slclee #endif 935*3ccda647Slclee break; 936*3ccda647Slclee case DKIOCPARTINFO: 937*3ccda647Slclee cmlb_dbg(CMLB_TRACE, un, "DKIOCPARTINFO"); 938*3ccda647Slclee #if defined(__i386) || defined(__amd64) 939*3ccda647Slclee err = cmlb_dkio_partinfo(un, dev, (caddr_t)arg, flag); 940*3ccda647Slclee #else 941*3ccda647Slclee err = ENOTTY; 942*3ccda647Slclee #endif 943*3ccda647Slclee break; 944*3ccda647Slclee 945*3ccda647Slclee default: 946*3ccda647Slclee err = ENOTTY; 947*3ccda647Slclee 948*3ccda647Slclee } 949*3ccda647Slclee return (err); 950*3ccda647Slclee } 951*3ccda647Slclee 952*3ccda647Slclee dev_t 953*3ccda647Slclee cmlb_make_device(struct cmlb_lun *un) 954*3ccda647Slclee { 955*3ccda647Slclee return (makedevice(ddi_name_to_major(ddi_get_name(CMLB_DEVINFO(un))), 956*3ccda647Slclee ddi_get_instance(CMLB_DEVINFO(un)) << CMLBUNIT_SHIFT)); 957*3ccda647Slclee } 958*3ccda647Slclee 959*3ccda647Slclee /* 960*3ccda647Slclee * Function: cmlb_check_update_blockcount 961*3ccda647Slclee * 962*3ccda647Slclee * Description: If current capacity value is invalid, obtains the 963*3ccda647Slclee * current capacity from target driver. 964*3ccda647Slclee * 965*3ccda647Slclee * Return Code: 0 success 966*3ccda647Slclee * EIO failure 967*3ccda647Slclee */ 968*3ccda647Slclee static int 969*3ccda647Slclee cmlb_check_update_blockcount(struct cmlb_lun *un) 970*3ccda647Slclee { 971*3ccda647Slclee int status; 972*3ccda647Slclee diskaddr_t capacity; 973*3ccda647Slclee 974*3ccda647Slclee ASSERT(mutex_owned(CMLB_MUTEX(un))); 975*3ccda647Slclee 976*3ccda647Slclee if (un->un_f_geometry_is_valid == FALSE) { 977*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 978*3ccda647Slclee status = DK_TG_GETCAP(un, &capacity); 979*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 980*3ccda647Slclee if (status == 0 && capacity != 0) { 981*3ccda647Slclee un->un_blockcount = capacity; 982*3ccda647Slclee return (0); 983*3ccda647Slclee } else 984*3ccda647Slclee return (EIO); 985*3ccda647Slclee } else 986*3ccda647Slclee return (0); 987*3ccda647Slclee } 988*3ccda647Slclee 989*3ccda647Slclee /* 990*3ccda647Slclee * Function: cmlb_create_minor_nodes 991*3ccda647Slclee * 992*3ccda647Slclee * Description: Create or adjust the minor device nodes for the instance. 993*3ccda647Slclee * Minor nodes are created based on default label type, 994*3ccda647Slclee * current label type and last label type we created 995*3ccda647Slclee * minor nodes based on. 996*3ccda647Slclee * 997*3ccda647Slclee * 998*3ccda647Slclee * Arguments: un - driver soft state (unit) structure 999*3ccda647Slclee * 1000*3ccda647Slclee * Return Code: 0 success 1001*3ccda647Slclee * ENXIO failure. 1002*3ccda647Slclee * 1003*3ccda647Slclee * Context: Kernel thread context 1004*3ccda647Slclee */ 1005*3ccda647Slclee static int 1006*3ccda647Slclee cmlb_create_minor_nodes(struct cmlb_lun *un) 1007*3ccda647Slclee { 1008*3ccda647Slclee struct driver_minor_data *dmdp; 1009*3ccda647Slclee int instance; 1010*3ccda647Slclee char name[48]; 1011*3ccda647Slclee cmlb_label_t newlabeltype; 1012*3ccda647Slclee 1013*3ccda647Slclee ASSERT(un != NULL); 1014*3ccda647Slclee ASSERT(mutex_owned(CMLB_MUTEX(un))); 1015*3ccda647Slclee 1016*3ccda647Slclee 1017*3ccda647Slclee /* check the most common case */ 1018*3ccda647Slclee if (un->un_cur_labeltype != CMLB_LABEL_UNDEF && 1019*3ccda647Slclee un->un_last_labeltype == un->un_cur_labeltype) { 1020*3ccda647Slclee /* do nothing */ 1021*3ccda647Slclee return (0); 1022*3ccda647Slclee } 1023*3ccda647Slclee 1024*3ccda647Slclee if (un->un_def_labeltype == CMLB_LABEL_UNDEF) { 1025*3ccda647Slclee /* we should never get here */ 1026*3ccda647Slclee return (ENXIO); 1027*3ccda647Slclee } 1028*3ccda647Slclee 1029*3ccda647Slclee if (un->un_last_labeltype == CMLB_LABEL_UNDEF) { 1030*3ccda647Slclee /* first time during attach */ 1031*3ccda647Slclee newlabeltype = un->un_def_labeltype; 1032*3ccda647Slclee 1033*3ccda647Slclee instance = ddi_get_instance(CMLB_DEVINFO(un)); 1034*3ccda647Slclee 1035*3ccda647Slclee /* Create all the minor nodes for this target. */ 1036*3ccda647Slclee dmdp = (newlabeltype == CMLB_LABEL_EFI) ? dk_minor_data_efi : 1037*3ccda647Slclee dk_minor_data; 1038*3ccda647Slclee while (dmdp->name != NULL) { 1039*3ccda647Slclee 1040*3ccda647Slclee (void) sprintf(name, "%s", dmdp->name); 1041*3ccda647Slclee 1042*3ccda647Slclee if (ddi_create_minor_node(CMLB_DEVINFO(un), name, 1043*3ccda647Slclee dmdp->type, 1044*3ccda647Slclee (instance << CMLBUNIT_SHIFT) | dmdp->minor, 1045*3ccda647Slclee un->un_node_type, NULL) == DDI_FAILURE) { 1046*3ccda647Slclee /* 1047*3ccda647Slclee * Clean up any nodes that may have been 1048*3ccda647Slclee * created, in case this fails in the middle 1049*3ccda647Slclee * of the loop. 1050*3ccda647Slclee */ 1051*3ccda647Slclee ddi_remove_minor_node(CMLB_DEVINFO(un), NULL); 1052*3ccda647Slclee return (ENXIO); 1053*3ccda647Slclee } 1054*3ccda647Slclee dmdp++; 1055*3ccda647Slclee } 1056*3ccda647Slclee un->un_last_labeltype = newlabeltype; 1057*3ccda647Slclee return (0); 1058*3ccda647Slclee } 1059*3ccda647Slclee 1060*3ccda647Slclee /* Not first time */ 1061*3ccda647Slclee if (un->un_cur_labeltype == CMLB_LABEL_UNDEF) { 1062*3ccda647Slclee if (un->un_last_labeltype != un->un_def_labeltype) { 1063*3ccda647Slclee /* close time, revert to default. */ 1064*3ccda647Slclee newlabeltype = un->un_def_labeltype; 1065*3ccda647Slclee } else { 1066*3ccda647Slclee /* 1067*3ccda647Slclee * do nothing since the type for which we last created 1068*3ccda647Slclee * nodes matches the default 1069*3ccda647Slclee */ 1070*3ccda647Slclee return (0); 1071*3ccda647Slclee } 1072*3ccda647Slclee } else { 1073*3ccda647Slclee if (un->un_cur_labeltype != un->un_last_labeltype) { 1074*3ccda647Slclee /* We are not closing, use current label type */ 1075*3ccda647Slclee newlabeltype = un->un_cur_labeltype; 1076*3ccda647Slclee } else { 1077*3ccda647Slclee /* 1078*3ccda647Slclee * do nothing since the type for which we last created 1079*3ccda647Slclee * nodes matches the current label type 1080*3ccda647Slclee */ 1081*3ccda647Slclee return (0); 1082*3ccda647Slclee } 1083*3ccda647Slclee } 1084*3ccda647Slclee 1085*3ccda647Slclee instance = ddi_get_instance(CMLB_DEVINFO(un)); 1086*3ccda647Slclee 1087*3ccda647Slclee /* 1088*3ccda647Slclee * Currently we only fix up the s7 node when we are switching 1089*3ccda647Slclee * label types from or to EFI. This is consistent with 1090*3ccda647Slclee * current behavior of sd. 1091*3ccda647Slclee */ 1092*3ccda647Slclee if (newlabeltype == CMLB_LABEL_EFI && 1093*3ccda647Slclee un->un_last_labeltype != CMLB_LABEL_EFI) { 1094*3ccda647Slclee /* from vtoc to EFI */ 1095*3ccda647Slclee ddi_remove_minor_node(CMLB_DEVINFO(un), "h"); 1096*3ccda647Slclee ddi_remove_minor_node(CMLB_DEVINFO(un), "h,raw"); 1097*3ccda647Slclee (void) ddi_create_minor_node(CMLB_DEVINFO(un), "wd", 1098*3ccda647Slclee S_IFBLK, (instance << CMLBUNIT_SHIFT) | WD_NODE, 1099*3ccda647Slclee un->un_node_type, NULL); 1100*3ccda647Slclee (void) ddi_create_minor_node(CMLB_DEVINFO(un), "wd,raw", 1101*3ccda647Slclee S_IFCHR, (instance << CMLBUNIT_SHIFT) | WD_NODE, 1102*3ccda647Slclee un->un_node_type, NULL); 1103*3ccda647Slclee } else { 1104*3ccda647Slclee /* from efi to vtoc */ 1105*3ccda647Slclee ddi_remove_minor_node(CMLB_DEVINFO(un), "wd"); 1106*3ccda647Slclee ddi_remove_minor_node(CMLB_DEVINFO(un), "wd,raw"); 1107*3ccda647Slclee (void) ddi_create_minor_node(CMLB_DEVINFO(un), "h", 1108*3ccda647Slclee S_IFBLK, (instance << CMLBUNIT_SHIFT) | WD_NODE, 1109*3ccda647Slclee un->un_node_type, NULL); 1110*3ccda647Slclee (void) ddi_create_minor_node(CMLB_DEVINFO(un), "h,raw", 1111*3ccda647Slclee S_IFCHR, (instance << CMLBUNIT_SHIFT) | WD_NODE, 1112*3ccda647Slclee un->un_node_type, NULL); 1113*3ccda647Slclee } 1114*3ccda647Slclee 1115*3ccda647Slclee un->un_last_labeltype = newlabeltype; 1116*3ccda647Slclee return (0); 1117*3ccda647Slclee } 1118*3ccda647Slclee 1119*3ccda647Slclee /* 1120*3ccda647Slclee * Function: cmlb_validate_geometry 1121*3ccda647Slclee * 1122*3ccda647Slclee * Description: Read the label from the disk (if present). Update the unit's 1123*3ccda647Slclee * geometry and vtoc information from the data in the label. 1124*3ccda647Slclee * Verify that the label is valid. 1125*3ccda647Slclee * 1126*3ccda647Slclee * Arguments: un - driver soft state (unit) structure 1127*3ccda647Slclee * 1128*3ccda647Slclee * Return Code: 0 - Successful completion 1129*3ccda647Slclee * EINVAL - Invalid value in un->un_tgt_blocksize or 1130*3ccda647Slclee * un->un_blockcount; or label on disk is corrupted 1131*3ccda647Slclee * or unreadable. 1132*3ccda647Slclee * EACCES - Reservation conflict at the device. 1133*3ccda647Slclee * ENOMEM - Resource allocation error 1134*3ccda647Slclee * ENOTSUP - geometry not applicable 1135*3ccda647Slclee * 1136*3ccda647Slclee * Context: Kernel thread only (can sleep). 1137*3ccda647Slclee */ 1138*3ccda647Slclee static int 1139*3ccda647Slclee cmlb_validate_geometry(struct cmlb_lun *un, int forcerevalid) 1140*3ccda647Slclee { 1141*3ccda647Slclee int label_error = 0; 1142*3ccda647Slclee diskaddr_t capacity; 1143*3ccda647Slclee int count; 1144*3ccda647Slclee 1145*3ccda647Slclee ASSERT(mutex_owned(CMLB_MUTEX(un))); 1146*3ccda647Slclee 1147*3ccda647Slclee if ((un->un_f_geometry_is_valid == TRUE) && (forcerevalid == 0)) { 1148*3ccda647Slclee if (un->un_cur_labeltype == CMLB_LABEL_EFI) 1149*3ccda647Slclee return (ENOTSUP); 1150*3ccda647Slclee return (0); 1151*3ccda647Slclee } 1152*3ccda647Slclee 1153*3ccda647Slclee if (cmlb_check_update_blockcount(un) != 0) 1154*3ccda647Slclee return (EIO); 1155*3ccda647Slclee 1156*3ccda647Slclee capacity = un->un_blockcount; 1157*3ccda647Slclee 1158*3ccda647Slclee #if defined(_SUNOS_VTOC_16) 1159*3ccda647Slclee /* 1160*3ccda647Slclee * Set up the "whole disk" fdisk partition; this should always 1161*3ccda647Slclee * exist, regardless of whether the disk contains an fdisk table 1162*3ccda647Slclee * or vtoc. 1163*3ccda647Slclee */ 1164*3ccda647Slclee un->un_map[P0_RAW_DISK].dkl_cylno = 0; 1165*3ccda647Slclee /* 1166*3ccda647Slclee * note if capacity > uint32_max we should be using efi, 1167*3ccda647Slclee * and not use p0, so the truncation does not matter. 1168*3ccda647Slclee */ 1169*3ccda647Slclee un->un_map[P0_RAW_DISK].dkl_nblk = capacity; 1170*3ccda647Slclee #endif 1171*3ccda647Slclee /* 1172*3ccda647Slclee * Refresh the logical and physical geometry caches. 1173*3ccda647Slclee * (data from MODE SENSE format/rigid disk geometry pages, 1174*3ccda647Slclee * and scsi_ifgetcap("geometry"). 1175*3ccda647Slclee */ 1176*3ccda647Slclee cmlb_resync_geom_caches(un, capacity); 1177*3ccda647Slclee 1178*3ccda647Slclee label_error = cmlb_use_efi(un, capacity); 1179*3ccda647Slclee if (label_error == 0) { 1180*3ccda647Slclee 1181*3ccda647Slclee /* found a valid EFI label */ 1182*3ccda647Slclee cmlb_dbg(CMLB_TRACE, un, 1183*3ccda647Slclee "cmlb_validate_geometry: found EFI label\n"); 1184*3ccda647Slclee /* 1185*3ccda647Slclee * solaris_size and geometry_is_valid are set in 1186*3ccda647Slclee * cmlb_use_efi 1187*3ccda647Slclee */ 1188*3ccda647Slclee return (ENOTSUP); 1189*3ccda647Slclee } 1190*3ccda647Slclee 1191*3ccda647Slclee /* NO EFI label found */ 1192*3ccda647Slclee 1193*3ccda647Slclee if (capacity > DK_MAX_BLOCKS) { 1194*3ccda647Slclee if (label_error == ESRCH) { 1195*3ccda647Slclee /* 1196*3ccda647Slclee * they've configured a LUN over 1TB, but used 1197*3ccda647Slclee * format.dat to restrict format's view of the 1198*3ccda647Slclee * capacity to be under 1TB 1199*3ccda647Slclee */ 1200*3ccda647Slclee /* i.e > 1Tb with a VTOC < 1TB */ 1201*3ccda647Slclee 1202*3ccda647Slclee cmlb_log(CMLB_DEVINFO(un), CMLB_LABEL(un), CE_WARN, 1203*3ccda647Slclee "is >1TB and has a VTOC label: use format(1M) to " 1204*3ccda647Slclee "either decrease the"); 1205*3ccda647Slclee cmlb_log(CMLB_DEVINFO(un), CMLB_LABEL(un), CE_CONT, 1206*3ccda647Slclee "size to be < 1TB or relabel the disk with an EFI " 1207*3ccda647Slclee "label"); 1208*3ccda647Slclee } else { 1209*3ccda647Slclee /* unlabeled disk over 1TB */ 1210*3ccda647Slclee return (ENOTSUP); 1211*3ccda647Slclee } 1212*3ccda647Slclee } 1213*3ccda647Slclee 1214*3ccda647Slclee label_error = 0; 1215*3ccda647Slclee 1216*3ccda647Slclee /* 1217*3ccda647Slclee * at this point it is either labeled with a VTOC or it is 1218*3ccda647Slclee * under 1TB 1219*3ccda647Slclee */ 1220*3ccda647Slclee 1221*3ccda647Slclee /* 1222*3ccda647Slclee * Only DIRECT ACCESS devices will have Sun labels. 1223*3ccda647Slclee * CD's supposedly have a Sun label, too 1224*3ccda647Slclee */ 1225*3ccda647Slclee if (un->un_device_type == DTYPE_DIRECT || ISREMOVABLE(un)) { 1226*3ccda647Slclee struct dk_label *dkl; 1227*3ccda647Slclee offset_t label_addr; 1228*3ccda647Slclee int rval; 1229*3ccda647Slclee size_t buffer_size; 1230*3ccda647Slclee 1231*3ccda647Slclee /* 1232*3ccda647Slclee * Note: This will set up un->un_solaris_size and 1233*3ccda647Slclee * un->un_solaris_offset. 1234*3ccda647Slclee */ 1235*3ccda647Slclee rval = cmlb_read_fdisk(un, capacity); 1236*3ccda647Slclee if (rval != 0) { 1237*3ccda647Slclee ASSERT(mutex_owned(CMLB_MUTEX(un))); 1238*3ccda647Slclee return (rval); 1239*3ccda647Slclee } 1240*3ccda647Slclee 1241*3ccda647Slclee if (un->un_solaris_size <= DK_LABEL_LOC) { 1242*3ccda647Slclee /* 1243*3ccda647Slclee * Found fdisk table but no Solaris partition entry, 1244*3ccda647Slclee * so don't call cmlb_uselabel() and don't create 1245*3ccda647Slclee * a default label. 1246*3ccda647Slclee */ 1247*3ccda647Slclee label_error = 0; 1248*3ccda647Slclee un->un_f_geometry_is_valid = TRUE; 1249*3ccda647Slclee goto no_solaris_partition; 1250*3ccda647Slclee } 1251*3ccda647Slclee 1252*3ccda647Slclee label_addr = (daddr_t)(un->un_solaris_offset + DK_LABEL_LOC); 1253*3ccda647Slclee 1254*3ccda647Slclee buffer_size = sizeof (struct dk_label); 1255*3ccda647Slclee 1256*3ccda647Slclee cmlb_dbg(CMLB_TRACE, un, "cmlb_validate_geometry: " 1257*3ccda647Slclee "label_addr: 0x%x allocation size: 0x%x\n", 1258*3ccda647Slclee label_addr, buffer_size); 1259*3ccda647Slclee 1260*3ccda647Slclee if ((dkl = kmem_zalloc(buffer_size, KM_NOSLEEP)) == NULL) 1261*3ccda647Slclee return (ENOMEM); 1262*3ccda647Slclee 1263*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 1264*3ccda647Slclee rval = DK_TG_READ(un, dkl, label_addr, buffer_size); 1265*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 1266*3ccda647Slclee 1267*3ccda647Slclee switch (rval) { 1268*3ccda647Slclee case 0: 1269*3ccda647Slclee /* 1270*3ccda647Slclee * cmlb_uselabel will establish that the geometry 1271*3ccda647Slclee * is valid. 1272*3ccda647Slclee */ 1273*3ccda647Slclee if (cmlb_uselabel(un, 1274*3ccda647Slclee (struct dk_label *)(uintptr_t)dkl) != 1275*3ccda647Slclee CMLB_LABEL_IS_VALID) { 1276*3ccda647Slclee label_error = EINVAL; 1277*3ccda647Slclee } else 1278*3ccda647Slclee un->un_vtoc_label_is_from_media = 1; 1279*3ccda647Slclee break; 1280*3ccda647Slclee case EACCES: 1281*3ccda647Slclee label_error = EACCES; 1282*3ccda647Slclee break; 1283*3ccda647Slclee default: 1284*3ccda647Slclee label_error = EINVAL; 1285*3ccda647Slclee break; 1286*3ccda647Slclee } 1287*3ccda647Slclee 1288*3ccda647Slclee kmem_free(dkl, buffer_size); 1289*3ccda647Slclee } 1290*3ccda647Slclee 1291*3ccda647Slclee /* 1292*3ccda647Slclee * If a valid label was not found, AND if no reservation conflict 1293*3ccda647Slclee * was detected, then go ahead and create a default label (4069506). 1294*3ccda647Slclee * 1295*3ccda647Slclee * Note: currently, for VTOC_8 devices, the default label is created 1296*3ccda647Slclee * for removables only. For VTOC_16 devices, the default label will 1297*3ccda647Slclee * be created for both removables and non-removables alike. 1298*3ccda647Slclee * (see cmlb_build_default_label) 1299*3ccda647Slclee */ 1300*3ccda647Slclee #if defined(_SUNOS_VTOC_8) 1301*3ccda647Slclee if (ISREMOVABLE(un) && (label_error != EACCES)) { 1302*3ccda647Slclee #elif defined(_SUNOS_VTOC_16) 1303*3ccda647Slclee if (label_error != EACCES) { 1304*3ccda647Slclee #endif 1305*3ccda647Slclee if (un->un_f_geometry_is_valid == FALSE) { 1306*3ccda647Slclee cmlb_build_default_label(un); 1307*3ccda647Slclee } 1308*3ccda647Slclee label_error = 0; 1309*3ccda647Slclee } 1310*3ccda647Slclee 1311*3ccda647Slclee no_solaris_partition: 1312*3ccda647Slclee 1313*3ccda647Slclee #if defined(_SUNOS_VTOC_16) 1314*3ccda647Slclee /* 1315*3ccda647Slclee * If we have valid geometry, set up the remaining fdisk partitions. 1316*3ccda647Slclee * Note that dkl_cylno is not used for the fdisk map entries, so 1317*3ccda647Slclee * we set it to an entirely bogus value. 1318*3ccda647Slclee */ 1319*3ccda647Slclee for (count = 0; count < FD_NUMPART; count++) { 1320*3ccda647Slclee un->un_map[FDISK_P1 + count].dkl_cylno = -1; 1321*3ccda647Slclee un->un_map[FDISK_P1 + count].dkl_nblk = 1322*3ccda647Slclee un->un_fmap[count].fmap_nblk; 1323*3ccda647Slclee 1324*3ccda647Slclee un->un_offset[FDISK_P1 + count] = 1325*3ccda647Slclee un->un_fmap[count].fmap_start; 1326*3ccda647Slclee } 1327*3ccda647Slclee #endif 1328*3ccda647Slclee 1329*3ccda647Slclee for (count = 0; count < NDKMAP; count++) { 1330*3ccda647Slclee #if defined(_SUNOS_VTOC_8) 1331*3ccda647Slclee struct dk_map *lp = &un->un_map[count]; 1332*3ccda647Slclee un->un_offset[count] = 1333*3ccda647Slclee un->un_g.dkg_nhead * un->un_g.dkg_nsect * lp->dkl_cylno; 1334*3ccda647Slclee #elif defined(_SUNOS_VTOC_16) 1335*3ccda647Slclee struct dkl_partition *vp = &un->un_vtoc.v_part[count]; 1336*3ccda647Slclee 1337*3ccda647Slclee un->un_offset[count] = vp->p_start + un->un_solaris_offset; 1338*3ccda647Slclee #else 1339*3ccda647Slclee #error "No VTOC format defined." 1340*3ccda647Slclee #endif 1341*3ccda647Slclee } 1342*3ccda647Slclee 1343*3ccda647Slclee return (label_error); 1344*3ccda647Slclee } 1345*3ccda647Slclee 1346*3ccda647Slclee #if defined(_SUNOS_VTOC_16) 1347*3ccda647Slclee /* 1348*3ccda647Slclee * Macro: MAX_BLKS 1349*3ccda647Slclee * 1350*3ccda647Slclee * This macro is used for table entries where we need to have the largest 1351*3ccda647Slclee * possible sector value for that head & SPT (sectors per track) 1352*3ccda647Slclee * combination. Other entries for some smaller disk sizes are set by 1353*3ccda647Slclee * convention to match those used by X86 BIOS usage. 1354*3ccda647Slclee */ 1355*3ccda647Slclee #define MAX_BLKS(heads, spt) UINT16_MAX * heads * spt, heads, spt 1356*3ccda647Slclee 1357*3ccda647Slclee /* 1358*3ccda647Slclee * Function: cmlb_convert_geometry 1359*3ccda647Slclee * 1360*3ccda647Slclee * Description: Convert physical geometry into a dk_geom structure. In 1361*3ccda647Slclee * other words, make sure we don't wrap 16-bit values. 1362*3ccda647Slclee * e.g. converting from geom_cache to dk_geom 1363*3ccda647Slclee * 1364*3ccda647Slclee * Context: Kernel thread only 1365*3ccda647Slclee */ 1366*3ccda647Slclee static void 1367*3ccda647Slclee cmlb_convert_geometry(diskaddr_t capacity, struct dk_geom *un_g) 1368*3ccda647Slclee { 1369*3ccda647Slclee int i; 1370*3ccda647Slclee static const struct chs_values { 1371*3ccda647Slclee uint_t max_cap; /* Max Capacity for this HS. */ 1372*3ccda647Slclee uint_t nhead; /* Heads to use. */ 1373*3ccda647Slclee uint_t nsect; /* SPT to use. */ 1374*3ccda647Slclee } CHS_values[] = { 1375*3ccda647Slclee {0x00200000, 64, 32}, /* 1GB or smaller disk. */ 1376*3ccda647Slclee {0x01000000, 128, 32}, /* 8GB or smaller disk. */ 1377*3ccda647Slclee {MAX_BLKS(255, 63)}, /* 502.02GB or smaller disk. */ 1378*3ccda647Slclee {MAX_BLKS(255, 126)}, /* .98TB or smaller disk. */ 1379*3ccda647Slclee {DK_MAX_BLOCKS, 255, 189} /* Max size is just under 1TB */ 1380*3ccda647Slclee }; 1381*3ccda647Slclee 1382*3ccda647Slclee /* Unlabeled SCSI floppy device */ 1383*3ccda647Slclee if (capacity <= 0x1000) { 1384*3ccda647Slclee un_g->dkg_nhead = 2; 1385*3ccda647Slclee un_g->dkg_ncyl = 80; 1386*3ccda647Slclee un_g->dkg_nsect = capacity / (un_g->dkg_nhead * un_g->dkg_ncyl); 1387*3ccda647Slclee return; 1388*3ccda647Slclee } 1389*3ccda647Slclee 1390*3ccda647Slclee /* 1391*3ccda647Slclee * For all devices we calculate cylinders using the 1392*3ccda647Slclee * heads and sectors we assign based on capacity of the 1393*3ccda647Slclee * device. The table is designed to be compatible with the 1394*3ccda647Slclee * way other operating systems lay out fdisk tables for X86 1395*3ccda647Slclee * and to insure that the cylinders never exceed 65535 to 1396*3ccda647Slclee * prevent problems with X86 ioctls that report geometry. 1397*3ccda647Slclee * We use SPT that are multiples of 63, since other OSes that 1398*3ccda647Slclee * are not limited to 16-bits for cylinders stop at 63 SPT 1399*3ccda647Slclee * we make do by using multiples of 63 SPT. 1400*3ccda647Slclee * 1401*3ccda647Slclee * Note than capacities greater than or equal to 1TB will simply 1402*3ccda647Slclee * get the largest geometry from the table. This should be okay 1403*3ccda647Slclee * since disks this large shouldn't be using CHS values anyway. 1404*3ccda647Slclee */ 1405*3ccda647Slclee for (i = 0; CHS_values[i].max_cap < capacity && 1406*3ccda647Slclee CHS_values[i].max_cap != DK_MAX_BLOCKS; i++) 1407*3ccda647Slclee ; 1408*3ccda647Slclee 1409*3ccda647Slclee un_g->dkg_nhead = CHS_values[i].nhead; 1410*3ccda647Slclee un_g->dkg_nsect = CHS_values[i].nsect; 1411*3ccda647Slclee } 1412*3ccda647Slclee #endif 1413*3ccda647Slclee 1414*3ccda647Slclee /* 1415*3ccda647Slclee * Function: cmlb_resync_geom_caches 1416*3ccda647Slclee * 1417*3ccda647Slclee * Description: (Re)initialize both geometry caches: the virtual geometry 1418*3ccda647Slclee * information is extracted from the HBA (the "geometry" 1419*3ccda647Slclee * capability), and the physical geometry cache data is 1420*3ccda647Slclee * generated by issuing MODE SENSE commands. 1421*3ccda647Slclee * 1422*3ccda647Slclee * Arguments: un - driver soft state (unit) structure 1423*3ccda647Slclee * capacity - disk capacity in #blocks 1424*3ccda647Slclee * 1425*3ccda647Slclee * Context: Kernel thread only (can sleep). 1426*3ccda647Slclee */ 1427*3ccda647Slclee static void 1428*3ccda647Slclee cmlb_resync_geom_caches(struct cmlb_lun *un, diskaddr_t capacity) 1429*3ccda647Slclee { 1430*3ccda647Slclee struct cmlb_geom pgeom; 1431*3ccda647Slclee struct cmlb_geom lgeom; 1432*3ccda647Slclee struct cmlb_geom *pgeomp = &pgeom; 1433*3ccda647Slclee unsigned short nhead; 1434*3ccda647Slclee unsigned short nsect; 1435*3ccda647Slclee int spc; 1436*3ccda647Slclee int ret; 1437*3ccda647Slclee 1438*3ccda647Slclee ASSERT(un != NULL); 1439*3ccda647Slclee ASSERT(mutex_owned(CMLB_MUTEX(un))); 1440*3ccda647Slclee 1441*3ccda647Slclee /* 1442*3ccda647Slclee * Ask the controller for its logical geometry. 1443*3ccda647Slclee * Note: if the HBA does not support scsi_ifgetcap("geometry"), 1444*3ccda647Slclee * then the lgeom cache will be invalid. 1445*3ccda647Slclee */ 1446*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 1447*3ccda647Slclee bzero(&lgeom, sizeof (struct cmlb_geom)); 1448*3ccda647Slclee ret = DK_TG_GETVIRTGEOM(un, &lgeom); 1449*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 1450*3ccda647Slclee 1451*3ccda647Slclee bcopy(&lgeom, &un->un_lgeom, sizeof (un->un_lgeom)); 1452*3ccda647Slclee 1453*3ccda647Slclee /* 1454*3ccda647Slclee * Initialize the pgeom cache from lgeom, so that if MODE SENSE 1455*3ccda647Slclee * doesn't work, DKIOCG_PHYSGEOM can return reasonable values. 1456*3ccda647Slclee */ 1457*3ccda647Slclee if (ret != 0 || un->un_lgeom.g_nsect == 0 || 1458*3ccda647Slclee un->un_lgeom.g_nhead == 0) { 1459*3ccda647Slclee /* 1460*3ccda647Slclee * Note: Perhaps this needs to be more adaptive? The rationale 1461*3ccda647Slclee * is that, if there's no HBA geometry from the HBA driver, any 1462*3ccda647Slclee * guess is good, since this is the physical geometry. If MODE 1463*3ccda647Slclee * SENSE fails this gives a max cylinder size for non-LBA access 1464*3ccda647Slclee */ 1465*3ccda647Slclee nhead = 255; 1466*3ccda647Slclee nsect = 63; 1467*3ccda647Slclee } else { 1468*3ccda647Slclee nhead = un->un_lgeom.g_nhead; 1469*3ccda647Slclee nsect = un->un_lgeom.g_nsect; 1470*3ccda647Slclee } 1471*3ccda647Slclee 1472*3ccda647Slclee if (ISCD(un)) { 1473*3ccda647Slclee pgeomp->g_nhead = 1; 1474*3ccda647Slclee pgeomp->g_nsect = nsect * nhead; 1475*3ccda647Slclee } else { 1476*3ccda647Slclee pgeomp->g_nhead = nhead; 1477*3ccda647Slclee pgeomp->g_nsect = nsect; 1478*3ccda647Slclee } 1479*3ccda647Slclee 1480*3ccda647Slclee spc = pgeomp->g_nhead * pgeomp->g_nsect; 1481*3ccda647Slclee pgeomp->g_capacity = capacity; 1482*3ccda647Slclee pgeomp->g_ncyl = pgeomp->g_capacity / spc; 1483*3ccda647Slclee pgeomp->g_acyl = 0; 1484*3ccda647Slclee 1485*3ccda647Slclee /* 1486*3ccda647Slclee * Retrieve fresh geometry data from the hardware, stash it 1487*3ccda647Slclee * here temporarily before we rebuild the incore label. 1488*3ccda647Slclee * 1489*3ccda647Slclee * We want to use the MODE SENSE commands to derive the 1490*3ccda647Slclee * physical geometry of the device, but if either command 1491*3ccda647Slclee * fails, the logical geometry is used as the fallback for 1492*3ccda647Slclee * disk label geometry. 1493*3ccda647Slclee */ 1494*3ccda647Slclee 1495*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 1496*3ccda647Slclee (void) DK_TG_GETPHYGEOM(un, pgeomp); 1497*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 1498*3ccda647Slclee 1499*3ccda647Slclee /* 1500*3ccda647Slclee * Now update the real copy while holding the mutex. This 1501*3ccda647Slclee * way the global copy is never in an inconsistent state. 1502*3ccda647Slclee */ 1503*3ccda647Slclee bcopy(pgeomp, &un->un_pgeom, sizeof (un->un_pgeom)); 1504*3ccda647Slclee 1505*3ccda647Slclee cmlb_dbg(CMLB_INFO, un, "cmlb_resync_geom_caches: " 1506*3ccda647Slclee "(cached from lgeom)\n"); 1507*3ccda647Slclee cmlb_dbg(CMLB_INFO, un, 1508*3ccda647Slclee " ncyl: %ld; acyl: %d; nhead: %d; nsect: %d\n", 1509*3ccda647Slclee un->un_pgeom.g_ncyl, un->un_pgeom.g_acyl, 1510*3ccda647Slclee un->un_pgeom.g_nhead, un->un_pgeom.g_nsect); 1511*3ccda647Slclee cmlb_dbg(CMLB_INFO, un, " lbasize: %d; capacity: %ld; " 1512*3ccda647Slclee "intrlv: %d; rpm: %d\n", un->un_pgeom.g_secsize, 1513*3ccda647Slclee un->un_pgeom.g_capacity, un->un_pgeom.g_intrlv, 1514*3ccda647Slclee un->un_pgeom.g_rpm); 1515*3ccda647Slclee } 1516*3ccda647Slclee 1517*3ccda647Slclee 1518*3ccda647Slclee /* 1519*3ccda647Slclee * Function: cmlb_read_fdisk 1520*3ccda647Slclee * 1521*3ccda647Slclee * Description: utility routine to read the fdisk table. 1522*3ccda647Slclee * 1523*3ccda647Slclee * Arguments: un - driver soft state (unit) structure 1524*3ccda647Slclee * 1525*3ccda647Slclee * Return Code: 0 for success (includes not reading for no_fdisk_present case 1526*3ccda647Slclee * errnos from tg_rw if failed to read the first block. 1527*3ccda647Slclee * 1528*3ccda647Slclee * Context: Kernel thread only (can sleep). 1529*3ccda647Slclee */ 1530*3ccda647Slclee /* ARGSUSED */ 1531*3ccda647Slclee static int 1532*3ccda647Slclee cmlb_read_fdisk(struct cmlb_lun *un, diskaddr_t capacity) 1533*3ccda647Slclee { 1534*3ccda647Slclee #if defined(_NO_FDISK_PRESENT) 1535*3ccda647Slclee 1536*3ccda647Slclee un->un_solaris_offset = 0; 1537*3ccda647Slclee un->un_solaris_size = capacity; 1538*3ccda647Slclee bzero(un->un_fmap, sizeof (struct fmap) * FD_NUMPART); 1539*3ccda647Slclee return (0); 1540*3ccda647Slclee 1541*3ccda647Slclee #elif defined(_FIRMWARE_NEEDS_FDISK) 1542*3ccda647Slclee 1543*3ccda647Slclee struct ipart *fdp; 1544*3ccda647Slclee struct mboot *mbp; 1545*3ccda647Slclee struct ipart fdisk[FD_NUMPART]; 1546*3ccda647Slclee int i; 1547*3ccda647Slclee char sigbuf[2]; 1548*3ccda647Slclee caddr_t bufp; 1549*3ccda647Slclee int uidx; 1550*3ccda647Slclee int rval; 1551*3ccda647Slclee int lba = 0; 1552*3ccda647Slclee uint_t solaris_offset; /* offset to solaris part. */ 1553*3ccda647Slclee daddr_t solaris_size; /* size of solaris partition */ 1554*3ccda647Slclee uint32_t blocksize; 1555*3ccda647Slclee 1556*3ccda647Slclee ASSERT(un != NULL); 1557*3ccda647Slclee ASSERT(mutex_owned(CMLB_MUTEX(un))); 1558*3ccda647Slclee 1559*3ccda647Slclee /* 1560*3ccda647Slclee * Start off assuming no fdisk table 1561*3ccda647Slclee */ 1562*3ccda647Slclee solaris_offset = 0; 1563*3ccda647Slclee solaris_size = capacity; 1564*3ccda647Slclee 1565*3ccda647Slclee blocksize = 512; 1566*3ccda647Slclee 1567*3ccda647Slclee bufp = kmem_zalloc(blocksize, KM_SLEEP); 1568*3ccda647Slclee 1569*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 1570*3ccda647Slclee rval = DK_TG_READ(un, bufp, 0, blocksize); 1571*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 1572*3ccda647Slclee 1573*3ccda647Slclee if (rval != 0) { 1574*3ccda647Slclee cmlb_dbg(CMLB_ERROR, un, 1575*3ccda647Slclee "cmlb_read_fdisk: fdisk read err\n"); 1576*3ccda647Slclee kmem_free(bufp, blocksize); 1577*3ccda647Slclee return (rval); 1578*3ccda647Slclee } 1579*3ccda647Slclee 1580*3ccda647Slclee mbp = (struct mboot *)bufp; 1581*3ccda647Slclee 1582*3ccda647Slclee /* 1583*3ccda647Slclee * The fdisk table does not begin on a 4-byte boundary within the 1584*3ccda647Slclee * master boot record, so we copy it to an aligned structure to avoid 1585*3ccda647Slclee * alignment exceptions on some processors. 1586*3ccda647Slclee */ 1587*3ccda647Slclee bcopy(&mbp->parts[0], fdisk, sizeof (fdisk)); 1588*3ccda647Slclee 1589*3ccda647Slclee /* 1590*3ccda647Slclee * Check for lba support before verifying sig; sig might not be 1591*3ccda647Slclee * there, say on a blank disk, but the max_chs mark may still 1592*3ccda647Slclee * be present. 1593*3ccda647Slclee * 1594*3ccda647Slclee * Note: LBA support and BEFs are an x86-only concept but this 1595*3ccda647Slclee * code should work OK on SPARC as well. 1596*3ccda647Slclee */ 1597*3ccda647Slclee 1598*3ccda647Slclee /* 1599*3ccda647Slclee * First, check for lba-access-ok on root node (or prom root node) 1600*3ccda647Slclee * if present there, don't need to search fdisk table. 1601*3ccda647Slclee */ 1602*3ccda647Slclee if (ddi_getprop(DDI_DEV_T_ANY, ddi_root_node(), 0, 1603*3ccda647Slclee "lba-access-ok", 0) != 0) { 1604*3ccda647Slclee /* All drives do LBA; don't search fdisk table */ 1605*3ccda647Slclee lba = 1; 1606*3ccda647Slclee } else { 1607*3ccda647Slclee /* Okay, look for mark in fdisk table */ 1608*3ccda647Slclee for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) { 1609*3ccda647Slclee /* accumulate "lba" value from all partitions */ 1610*3ccda647Slclee lba = (lba || cmlb_has_max_chs_vals(fdp)); 1611*3ccda647Slclee } 1612*3ccda647Slclee } 1613*3ccda647Slclee 1614*3ccda647Slclee /* 1615*3ccda647Slclee * Next, look for 'no-bef-lba-access' prop on parent. 1616*3ccda647Slclee * Its presence means the realmode driver doesn't support 1617*3ccda647Slclee * LBA, so the target driver shouldn't advertise it as ok. 1618*3ccda647Slclee * This should be a temporary condition; one day all 1619*3ccda647Slclee * BEFs should support the LBA access functions. 1620*3ccda647Slclee */ 1621*3ccda647Slclee if ((lba != 0) && (ddi_getprop(DDI_DEV_T_ANY, 1622*3ccda647Slclee ddi_get_parent(CMLB_DEVINFO(un)), DDI_PROP_DONTPASS, 1623*3ccda647Slclee "no-bef-lba-access", 0) != 0)) { 1624*3ccda647Slclee /* BEF doesn't support LBA; don't advertise it as ok */ 1625*3ccda647Slclee lba = 0; 1626*3ccda647Slclee } 1627*3ccda647Slclee 1628*3ccda647Slclee if (lba != 0) { 1629*3ccda647Slclee dev_t dev = cmlb_make_device(un); 1630*3ccda647Slclee 1631*3ccda647Slclee if (ddi_getprop(dev, CMLB_DEVINFO(un), DDI_PROP_DONTPASS, 1632*3ccda647Slclee "lba-access-ok", 0) == 0) { 1633*3ccda647Slclee /* not found; create it */ 1634*3ccda647Slclee if (ddi_prop_create(dev, CMLB_DEVINFO(un), 0, 1635*3ccda647Slclee "lba-access-ok", (caddr_t)NULL, 0) != 1636*3ccda647Slclee DDI_PROP_SUCCESS) { 1637*3ccda647Slclee cmlb_dbg(CMLB_ERROR, un, 1638*3ccda647Slclee "cmlb_read_fdisk: Can't create lba " 1639*3ccda647Slclee "property for instance %d\n", 1640*3ccda647Slclee ddi_get_instance(CMLB_DEVINFO(un))); 1641*3ccda647Slclee } 1642*3ccda647Slclee } 1643*3ccda647Slclee } 1644*3ccda647Slclee 1645*3ccda647Slclee bcopy(&mbp->signature, sigbuf, sizeof (sigbuf)); 1646*3ccda647Slclee 1647*3ccda647Slclee /* 1648*3ccda647Slclee * Endian-independent signature check 1649*3ccda647Slclee */ 1650*3ccda647Slclee if (((sigbuf[1] & 0xFF) != ((MBB_MAGIC >> 8) & 0xFF)) || 1651*3ccda647Slclee (sigbuf[0] != (MBB_MAGIC & 0xFF))) { 1652*3ccda647Slclee cmlb_dbg(CMLB_ERROR, un, 1653*3ccda647Slclee "cmlb_read_fdisk: no fdisk\n"); 1654*3ccda647Slclee bzero(un->un_fmap, sizeof (struct fmap) * FD_NUMPART); 1655*3ccda647Slclee goto done; 1656*3ccda647Slclee } 1657*3ccda647Slclee 1658*3ccda647Slclee #ifdef CMLBDEBUG 1659*3ccda647Slclee if (cmlb_level_mask & SD_LOGMASK_INFO) { 1660*3ccda647Slclee fdp = fdisk; 1661*3ccda647Slclee cmlb_dbg(CMLB_INFO, un, "cmlb_read_fdisk:\n"); 1662*3ccda647Slclee cmlb_dbg(CMLB_INFO, un, " relsect " 1663*3ccda647Slclee "numsect sysid bootid\n"); 1664*3ccda647Slclee for (i = 0; i < FD_NUMPART; i++, fdp++) { 1665*3ccda647Slclee cmlb_dbg(CMLB_INFO, un, 1666*3ccda647Slclee " %d: %8d %8d 0x%08x 0x%08x\n", 1667*3ccda647Slclee i, fdp->relsect, fdp->numsect, 1668*3ccda647Slclee fdp->systid, fdp->bootid); 1669*3ccda647Slclee } 1670*3ccda647Slclee } 1671*3ccda647Slclee #endif 1672*3ccda647Slclee 1673*3ccda647Slclee /* 1674*3ccda647Slclee * Try to find the unix partition 1675*3ccda647Slclee */ 1676*3ccda647Slclee uidx = -1; 1677*3ccda647Slclee solaris_offset = 0; 1678*3ccda647Slclee solaris_size = 0; 1679*3ccda647Slclee 1680*3ccda647Slclee for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) { 1681*3ccda647Slclee int relsect; 1682*3ccda647Slclee int numsect; 1683*3ccda647Slclee 1684*3ccda647Slclee if (fdp->numsect == 0) { 1685*3ccda647Slclee un->un_fmap[i].fmap_start = 0; 1686*3ccda647Slclee un->un_fmap[i].fmap_nblk = 0; 1687*3ccda647Slclee continue; 1688*3ccda647Slclee } 1689*3ccda647Slclee 1690*3ccda647Slclee /* 1691*3ccda647Slclee * Data in the fdisk table is little-endian. 1692*3ccda647Slclee */ 1693*3ccda647Slclee relsect = LE_32(fdp->relsect); 1694*3ccda647Slclee numsect = LE_32(fdp->numsect); 1695*3ccda647Slclee 1696*3ccda647Slclee un->un_fmap[i].fmap_start = relsect; 1697*3ccda647Slclee un->un_fmap[i].fmap_nblk = numsect; 1698*3ccda647Slclee 1699*3ccda647Slclee if (fdp->systid != SUNIXOS && 1700*3ccda647Slclee fdp->systid != SUNIXOS2 && 1701*3ccda647Slclee fdp->systid != EFI_PMBR) { 1702*3ccda647Slclee continue; 1703*3ccda647Slclee } 1704*3ccda647Slclee 1705*3ccda647Slclee /* 1706*3ccda647Slclee * use the last active solaris partition id found 1707*3ccda647Slclee * (there should only be 1 active partition id) 1708*3ccda647Slclee * 1709*3ccda647Slclee * if there are no active solaris partition id 1710*3ccda647Slclee * then use the first inactive solaris partition id 1711*3ccda647Slclee */ 1712*3ccda647Slclee if ((uidx == -1) || (fdp->bootid == ACTIVE)) { 1713*3ccda647Slclee uidx = i; 1714*3ccda647Slclee solaris_offset = relsect; 1715*3ccda647Slclee solaris_size = numsect; 1716*3ccda647Slclee } 1717*3ccda647Slclee } 1718*3ccda647Slclee 1719*3ccda647Slclee cmlb_dbg(CMLB_INFO, un, "fdisk 0x%x 0x%lx", 1720*3ccda647Slclee un->un_solaris_offset, un->un_solaris_size); 1721*3ccda647Slclee done: 1722*3ccda647Slclee 1723*3ccda647Slclee /* 1724*3ccda647Slclee * Clear the VTOC info, only if the Solaris partition entry 1725*3ccda647Slclee * has moved, changed size, been deleted, or if the size of 1726*3ccda647Slclee * the partition is too small to even fit the label sector. 1727*3ccda647Slclee */ 1728*3ccda647Slclee if ((un->un_solaris_offset != solaris_offset) || 1729*3ccda647Slclee (un->un_solaris_size != solaris_size) || 1730*3ccda647Slclee solaris_size <= DK_LABEL_LOC) { 1731*3ccda647Slclee cmlb_dbg(CMLB_INFO, un, "fdisk moved 0x%x 0x%lx", 1732*3ccda647Slclee solaris_offset, solaris_size); 1733*3ccda647Slclee bzero(&un->un_g, sizeof (struct dk_geom)); 1734*3ccda647Slclee bzero(&un->un_vtoc, sizeof (struct dk_vtoc)); 1735*3ccda647Slclee bzero(&un->un_map, NDKMAP * (sizeof (struct dk_map))); 1736*3ccda647Slclee un->un_f_geometry_is_valid = FALSE; 1737*3ccda647Slclee } 1738*3ccda647Slclee un->un_solaris_offset = solaris_offset; 1739*3ccda647Slclee un->un_solaris_size = solaris_size; 1740*3ccda647Slclee kmem_free(bufp, blocksize); 1741*3ccda647Slclee return (rval); 1742*3ccda647Slclee 1743*3ccda647Slclee #else /* #elif defined(_FIRMWARE_NEEDS_FDISK) */ 1744*3ccda647Slclee #error "fdisk table presence undetermined for this platform." 1745*3ccda647Slclee #endif /* #if defined(_NO_FDISK_PRESENT) */ 1746*3ccda647Slclee } 1747*3ccda647Slclee 1748*3ccda647Slclee static void 1749*3ccda647Slclee cmlb_swap_efi_gpt(efi_gpt_t *e) 1750*3ccda647Slclee { 1751*3ccda647Slclee _NOTE(ASSUMING_PROTECTED(*e)) 1752*3ccda647Slclee e->efi_gpt_Signature = LE_64(e->efi_gpt_Signature); 1753*3ccda647Slclee e->efi_gpt_Revision = LE_32(e->efi_gpt_Revision); 1754*3ccda647Slclee e->efi_gpt_HeaderSize = LE_32(e->efi_gpt_HeaderSize); 1755*3ccda647Slclee e->efi_gpt_HeaderCRC32 = LE_32(e->efi_gpt_HeaderCRC32); 1756*3ccda647Slclee e->efi_gpt_MyLBA = LE_64(e->efi_gpt_MyLBA); 1757*3ccda647Slclee e->efi_gpt_AlternateLBA = LE_64(e->efi_gpt_AlternateLBA); 1758*3ccda647Slclee e->efi_gpt_FirstUsableLBA = LE_64(e->efi_gpt_FirstUsableLBA); 1759*3ccda647Slclee e->efi_gpt_LastUsableLBA = LE_64(e->efi_gpt_LastUsableLBA); 1760*3ccda647Slclee UUID_LE_CONVERT(e->efi_gpt_DiskGUID, e->efi_gpt_DiskGUID); 1761*3ccda647Slclee e->efi_gpt_PartitionEntryLBA = LE_64(e->efi_gpt_PartitionEntryLBA); 1762*3ccda647Slclee e->efi_gpt_NumberOfPartitionEntries = 1763*3ccda647Slclee LE_32(e->efi_gpt_NumberOfPartitionEntries); 1764*3ccda647Slclee e->efi_gpt_SizeOfPartitionEntry = 1765*3ccda647Slclee LE_32(e->efi_gpt_SizeOfPartitionEntry); 1766*3ccda647Slclee e->efi_gpt_PartitionEntryArrayCRC32 = 1767*3ccda647Slclee LE_32(e->efi_gpt_PartitionEntryArrayCRC32); 1768*3ccda647Slclee } 1769*3ccda647Slclee 1770*3ccda647Slclee static void 1771*3ccda647Slclee cmlb_swap_efi_gpe(int nparts, efi_gpe_t *p) 1772*3ccda647Slclee { 1773*3ccda647Slclee int i; 1774*3ccda647Slclee 1775*3ccda647Slclee _NOTE(ASSUMING_PROTECTED(*p)) 1776*3ccda647Slclee for (i = 0; i < nparts; i++) { 1777*3ccda647Slclee UUID_LE_CONVERT(p[i].efi_gpe_PartitionTypeGUID, 1778*3ccda647Slclee p[i].efi_gpe_PartitionTypeGUID); 1779*3ccda647Slclee p[i].efi_gpe_StartingLBA = LE_64(p[i].efi_gpe_StartingLBA); 1780*3ccda647Slclee p[i].efi_gpe_EndingLBA = LE_64(p[i].efi_gpe_EndingLBA); 1781*3ccda647Slclee /* PartitionAttrs */ 1782*3ccda647Slclee } 1783*3ccda647Slclee } 1784*3ccda647Slclee 1785*3ccda647Slclee static int 1786*3ccda647Slclee cmlb_validate_efi(efi_gpt_t *labp) 1787*3ccda647Slclee { 1788*3ccda647Slclee if (labp->efi_gpt_Signature != EFI_SIGNATURE) 1789*3ccda647Slclee return (EINVAL); 1790*3ccda647Slclee /* at least 96 bytes in this version of the spec. */ 1791*3ccda647Slclee if (sizeof (efi_gpt_t) - sizeof (labp->efi_gpt_Reserved2) > 1792*3ccda647Slclee labp->efi_gpt_HeaderSize) 1793*3ccda647Slclee return (EINVAL); 1794*3ccda647Slclee /* this should be 128 bytes */ 1795*3ccda647Slclee if (labp->efi_gpt_SizeOfPartitionEntry != sizeof (efi_gpe_t)) 1796*3ccda647Slclee return (EINVAL); 1797*3ccda647Slclee return (0); 1798*3ccda647Slclee } 1799*3ccda647Slclee 1800*3ccda647Slclee static int 1801*3ccda647Slclee cmlb_use_efi(struct cmlb_lun *un, diskaddr_t capacity) 1802*3ccda647Slclee { 1803*3ccda647Slclee int i; 1804*3ccda647Slclee int rval = 0; 1805*3ccda647Slclee efi_gpe_t *partitions; 1806*3ccda647Slclee uchar_t *buf; 1807*3ccda647Slclee uint_t lbasize; /* is really how much to read */ 1808*3ccda647Slclee diskaddr_t cap; 1809*3ccda647Slclee uint_t nparts; 1810*3ccda647Slclee diskaddr_t gpe_lba; 1811*3ccda647Slclee 1812*3ccda647Slclee ASSERT(mutex_owned(CMLB_MUTEX(un))); 1813*3ccda647Slclee 1814*3ccda647Slclee lbasize = un->un_sys_blocksize; 1815*3ccda647Slclee 1816*3ccda647Slclee buf = kmem_zalloc(EFI_MIN_ARRAY_SIZE, KM_SLEEP); 1817*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 1818*3ccda647Slclee 1819*3ccda647Slclee rval = DK_TG_READ(un, buf, 0, lbasize); 1820*3ccda647Slclee if (rval) { 1821*3ccda647Slclee goto done_err; 1822*3ccda647Slclee } 1823*3ccda647Slclee if (((struct dk_label *)buf)->dkl_magic == DKL_MAGIC) { 1824*3ccda647Slclee /* not ours */ 1825*3ccda647Slclee rval = ESRCH; 1826*3ccda647Slclee goto done_err; 1827*3ccda647Slclee } 1828*3ccda647Slclee 1829*3ccda647Slclee rval = DK_TG_READ(un, buf, 1, lbasize); 1830*3ccda647Slclee if (rval) { 1831*3ccda647Slclee goto done_err; 1832*3ccda647Slclee } 1833*3ccda647Slclee cmlb_swap_efi_gpt((efi_gpt_t *)buf); 1834*3ccda647Slclee 1835*3ccda647Slclee if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) { 1836*3ccda647Slclee /* 1837*3ccda647Slclee * Couldn't read the primary, try the backup. Our 1838*3ccda647Slclee * capacity at this point could be based on CHS, so 1839*3ccda647Slclee * check what the device reports. 1840*3ccda647Slclee */ 1841*3ccda647Slclee rval = DK_TG_GETCAP(un, &cap); 1842*3ccda647Slclee 1843*3ccda647Slclee if (rval) { 1844*3ccda647Slclee goto done_err; 1845*3ccda647Slclee } 1846*3ccda647Slclee if ((rval = DK_TG_READ(un, buf, cap - 1, lbasize)) != 0) { 1847*3ccda647Slclee goto done_err; 1848*3ccda647Slclee } 1849*3ccda647Slclee cmlb_swap_efi_gpt((efi_gpt_t *)buf); 1850*3ccda647Slclee if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) 1851*3ccda647Slclee goto done_err; 1852*3ccda647Slclee cmlb_log(CMLB_DEVINFO(un), CMLB_LABEL(un), CE_WARN, 1853*3ccda647Slclee "primary label corrupt; using backup\n"); 1854*3ccda647Slclee } 1855*3ccda647Slclee 1856*3ccda647Slclee nparts = ((efi_gpt_t *)buf)->efi_gpt_NumberOfPartitionEntries; 1857*3ccda647Slclee gpe_lba = ((efi_gpt_t *)buf)->efi_gpt_PartitionEntryLBA; 1858*3ccda647Slclee 1859*3ccda647Slclee rval = DK_TG_READ(un, buf, gpe_lba, EFI_MIN_ARRAY_SIZE); 1860*3ccda647Slclee if (rval) { 1861*3ccda647Slclee goto done_err; 1862*3ccda647Slclee } 1863*3ccda647Slclee partitions = (efi_gpe_t *)buf; 1864*3ccda647Slclee 1865*3ccda647Slclee if (nparts > MAXPART) { 1866*3ccda647Slclee nparts = MAXPART; 1867*3ccda647Slclee } 1868*3ccda647Slclee cmlb_swap_efi_gpe(nparts, partitions); 1869*3ccda647Slclee 1870*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 1871*3ccda647Slclee 1872*3ccda647Slclee /* Fill in partition table. */ 1873*3ccda647Slclee for (i = 0; i < nparts; i++) { 1874*3ccda647Slclee if (partitions->efi_gpe_StartingLBA != 0 || 1875*3ccda647Slclee partitions->efi_gpe_EndingLBA != 0) { 1876*3ccda647Slclee un->un_map[i].dkl_cylno = 1877*3ccda647Slclee partitions->efi_gpe_StartingLBA; 1878*3ccda647Slclee un->un_map[i].dkl_nblk = 1879*3ccda647Slclee partitions->efi_gpe_EndingLBA - 1880*3ccda647Slclee partitions->efi_gpe_StartingLBA + 1; 1881*3ccda647Slclee un->un_offset[i] = 1882*3ccda647Slclee partitions->efi_gpe_StartingLBA; 1883*3ccda647Slclee } 1884*3ccda647Slclee if (i == WD_NODE) { 1885*3ccda647Slclee /* 1886*3ccda647Slclee * minor number 7 corresponds to the whole disk 1887*3ccda647Slclee */ 1888*3ccda647Slclee un->un_map[i].dkl_cylno = 0; 1889*3ccda647Slclee un->un_map[i].dkl_nblk = capacity; 1890*3ccda647Slclee un->un_offset[i] = 0; 1891*3ccda647Slclee } 1892*3ccda647Slclee partitions++; 1893*3ccda647Slclee } 1894*3ccda647Slclee un->un_solaris_offset = 0; 1895*3ccda647Slclee un->un_solaris_size = capacity; 1896*3ccda647Slclee un->un_f_geometry_is_valid = TRUE; 1897*3ccda647Slclee kmem_free(buf, EFI_MIN_ARRAY_SIZE); 1898*3ccda647Slclee return (0); 1899*3ccda647Slclee 1900*3ccda647Slclee done_err: 1901*3ccda647Slclee kmem_free(buf, EFI_MIN_ARRAY_SIZE); 1902*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 1903*3ccda647Slclee /* 1904*3ccda647Slclee * if we didn't find something that could look like a VTOC 1905*3ccda647Slclee * and the disk is over 1TB, we know there isn't a valid label. 1906*3ccda647Slclee * Otherwise let cmlb_uselabel decide what to do. We only 1907*3ccda647Slclee * want to invalidate this if we're certain the label isn't 1908*3ccda647Slclee * valid because cmlb_prop_op will now fail, which in turn 1909*3ccda647Slclee * causes things like opens and stats on the partition to fail. 1910*3ccda647Slclee */ 1911*3ccda647Slclee if ((capacity > DK_MAX_BLOCKS) && (rval != ESRCH)) { 1912*3ccda647Slclee un->un_f_geometry_is_valid = FALSE; 1913*3ccda647Slclee } 1914*3ccda647Slclee return (rval); 1915*3ccda647Slclee } 1916*3ccda647Slclee 1917*3ccda647Slclee 1918*3ccda647Slclee /* 1919*3ccda647Slclee * Function: cmlb_uselabel 1920*3ccda647Slclee * 1921*3ccda647Slclee * Description: Validate the disk label and update the relevant data (geometry, 1922*3ccda647Slclee * partition, vtoc, and capacity data) in the cmlb_lun struct. 1923*3ccda647Slclee * Marks the geometry of the unit as being valid. 1924*3ccda647Slclee * 1925*3ccda647Slclee * Arguments: un: unit struct. 1926*3ccda647Slclee * dk_label: disk label 1927*3ccda647Slclee * 1928*3ccda647Slclee * Return Code: CMLB_LABEL_IS_VALID: Label read from disk is OK; geometry, 1929*3ccda647Slclee * partition, vtoc, and capacity data are good. 1930*3ccda647Slclee * 1931*3ccda647Slclee * CMLB_LABEL_IS_INVALID: Magic number or checksum error in the 1932*3ccda647Slclee * label; or computed capacity does not jibe with capacity 1933*3ccda647Slclee * reported from the READ CAPACITY command. 1934*3ccda647Slclee * 1935*3ccda647Slclee * Context: Kernel thread only (can sleep). 1936*3ccda647Slclee */ 1937*3ccda647Slclee static int 1938*3ccda647Slclee cmlb_uselabel(struct cmlb_lun *un, struct dk_label *labp) 1939*3ccda647Slclee { 1940*3ccda647Slclee short *sp; 1941*3ccda647Slclee short sum; 1942*3ccda647Slclee short count; 1943*3ccda647Slclee int label_error = CMLB_LABEL_IS_VALID; 1944*3ccda647Slclee int i; 1945*3ccda647Slclee diskaddr_t label_capacity; 1946*3ccda647Slclee int part_end; 1947*3ccda647Slclee diskaddr_t track_capacity; 1948*3ccda647Slclee #if defined(_SUNOS_VTOC_16) 1949*3ccda647Slclee struct dkl_partition *vpartp; 1950*3ccda647Slclee #endif 1951*3ccda647Slclee ASSERT(un != NULL); 1952*3ccda647Slclee ASSERT(mutex_owned(CMLB_MUTEX(un))); 1953*3ccda647Slclee 1954*3ccda647Slclee /* Validate the magic number of the label. */ 1955*3ccda647Slclee if (labp->dkl_magic != DKL_MAGIC) { 1956*3ccda647Slclee #if defined(__sparc) 1957*3ccda647Slclee if (!ISREMOVABLE(un)) { 1958*3ccda647Slclee cmlb_log(CMLB_DEVINFO(un), CMLB_LABEL(un), CE_WARN, 1959*3ccda647Slclee "Corrupt label; wrong magic number\n"); 1960*3ccda647Slclee } 1961*3ccda647Slclee #endif 1962*3ccda647Slclee return (CMLB_LABEL_IS_INVALID); 1963*3ccda647Slclee } 1964*3ccda647Slclee 1965*3ccda647Slclee /* Validate the checksum of the label. */ 1966*3ccda647Slclee sp = (short *)labp; 1967*3ccda647Slclee sum = 0; 1968*3ccda647Slclee count = sizeof (struct dk_label) / sizeof (short); 1969*3ccda647Slclee while (count--) { 1970*3ccda647Slclee sum ^= *sp++; 1971*3ccda647Slclee } 1972*3ccda647Slclee 1973*3ccda647Slclee if (sum != 0) { 1974*3ccda647Slclee #if defined(_SUNOS_VTOC_16) 1975*3ccda647Slclee if (!ISCD(un)) { 1976*3ccda647Slclee #elif defined(_SUNOS_VTOC_8) 1977*3ccda647Slclee if (!ISREMOVABLE(un)) { 1978*3ccda647Slclee #endif 1979*3ccda647Slclee cmlb_log(CMLB_DEVINFO(un), CMLB_LABEL(un), CE_WARN, 1980*3ccda647Slclee "Corrupt label - label checksum failed\n"); 1981*3ccda647Slclee } 1982*3ccda647Slclee return (CMLB_LABEL_IS_INVALID); 1983*3ccda647Slclee } 1984*3ccda647Slclee 1985*3ccda647Slclee 1986*3ccda647Slclee /* 1987*3ccda647Slclee * Fill in geometry structure with data from label. 1988*3ccda647Slclee */ 1989*3ccda647Slclee bzero(&un->un_g, sizeof (struct dk_geom)); 1990*3ccda647Slclee un->un_g.dkg_ncyl = labp->dkl_ncyl; 1991*3ccda647Slclee un->un_g.dkg_acyl = labp->dkl_acyl; 1992*3ccda647Slclee un->un_g.dkg_bcyl = 0; 1993*3ccda647Slclee un->un_g.dkg_nhead = labp->dkl_nhead; 1994*3ccda647Slclee un->un_g.dkg_nsect = labp->dkl_nsect; 1995*3ccda647Slclee un->un_g.dkg_intrlv = labp->dkl_intrlv; 1996*3ccda647Slclee 1997*3ccda647Slclee #if defined(_SUNOS_VTOC_8) 1998*3ccda647Slclee un->un_g.dkg_gap1 = labp->dkl_gap1; 1999*3ccda647Slclee un->un_g.dkg_gap2 = labp->dkl_gap2; 2000*3ccda647Slclee un->un_g.dkg_bhead = labp->dkl_bhead; 2001*3ccda647Slclee #endif 2002*3ccda647Slclee #if defined(_SUNOS_VTOC_16) 2003*3ccda647Slclee un->un_dkg_skew = labp->dkl_skew; 2004*3ccda647Slclee #endif 2005*3ccda647Slclee 2006*3ccda647Slclee #if defined(__i386) || defined(__amd64) 2007*3ccda647Slclee un->un_g.dkg_apc = labp->dkl_apc; 2008*3ccda647Slclee #endif 2009*3ccda647Slclee 2010*3ccda647Slclee /* 2011*3ccda647Slclee * Currently we rely on the values in the label being accurate. If 2012*3ccda647Slclee * dkl_rpm or dkl_pcly are zero in the label, use a default value. 2013*3ccda647Slclee * 2014*3ccda647Slclee * Note: In the future a MODE SENSE may be used to retrieve this data, 2015*3ccda647Slclee * although this command is optional in SCSI-2. 2016*3ccda647Slclee */ 2017*3ccda647Slclee un->un_g.dkg_rpm = (labp->dkl_rpm != 0) ? labp->dkl_rpm : 3600; 2018*3ccda647Slclee un->un_g.dkg_pcyl = (labp->dkl_pcyl != 0) ? labp->dkl_pcyl : 2019*3ccda647Slclee (un->un_g.dkg_ncyl + un->un_g.dkg_acyl); 2020*3ccda647Slclee 2021*3ccda647Slclee /* 2022*3ccda647Slclee * The Read and Write reinstruct values may not be valid 2023*3ccda647Slclee * for older disks. 2024*3ccda647Slclee */ 2025*3ccda647Slclee un->un_g.dkg_read_reinstruct = labp->dkl_read_reinstruct; 2026*3ccda647Slclee un->un_g.dkg_write_reinstruct = labp->dkl_write_reinstruct; 2027*3ccda647Slclee 2028*3ccda647Slclee /* Fill in partition table. */ 2029*3ccda647Slclee #if defined(_SUNOS_VTOC_8) 2030*3ccda647Slclee for (i = 0; i < NDKMAP; i++) { 2031*3ccda647Slclee un->un_map[i].dkl_cylno = labp->dkl_map[i].dkl_cylno; 2032*3ccda647Slclee un->un_map[i].dkl_nblk = labp->dkl_map[i].dkl_nblk; 2033*3ccda647Slclee } 2034*3ccda647Slclee #endif 2035*3ccda647Slclee #if defined(_SUNOS_VTOC_16) 2036*3ccda647Slclee vpartp = labp->dkl_vtoc.v_part; 2037*3ccda647Slclee track_capacity = labp->dkl_nhead * labp->dkl_nsect; 2038*3ccda647Slclee 2039*3ccda647Slclee for (i = 0; i < NDKMAP; i++, vpartp++) { 2040*3ccda647Slclee un->un_map[i].dkl_cylno = vpartp->p_start / track_capacity; 2041*3ccda647Slclee un->un_map[i].dkl_nblk = vpartp->p_size; 2042*3ccda647Slclee } 2043*3ccda647Slclee #endif 2044*3ccda647Slclee 2045*3ccda647Slclee /* Fill in VTOC Structure. */ 2046*3ccda647Slclee bcopy(&labp->dkl_vtoc, &un->un_vtoc, sizeof (struct dk_vtoc)); 2047*3ccda647Slclee #if defined(_SUNOS_VTOC_8) 2048*3ccda647Slclee /* 2049*3ccda647Slclee * The 8-slice vtoc does not include the ascii label; save it into 2050*3ccda647Slclee * the device's soft state structure here. 2051*3ccda647Slclee */ 2052*3ccda647Slclee bcopy(labp->dkl_asciilabel, un->un_asciilabel, LEN_DKL_ASCII); 2053*3ccda647Slclee #endif 2054*3ccda647Slclee 2055*3ccda647Slclee /* Mark the geometry as valid. */ 2056*3ccda647Slclee un->un_f_geometry_is_valid = TRUE; 2057*3ccda647Slclee 2058*3ccda647Slclee /* Now look for a valid capacity. */ 2059*3ccda647Slclee track_capacity = (un->un_g.dkg_nhead * un->un_g.dkg_nsect); 2060*3ccda647Slclee label_capacity = (un->un_g.dkg_ncyl * track_capacity); 2061*3ccda647Slclee 2062*3ccda647Slclee if (un->un_g.dkg_acyl) { 2063*3ccda647Slclee #if defined(__i386) || defined(__amd64) 2064*3ccda647Slclee /* we may have > 1 alts cylinder */ 2065*3ccda647Slclee label_capacity += (track_capacity * un->un_g.dkg_acyl); 2066*3ccda647Slclee #else 2067*3ccda647Slclee label_capacity += track_capacity; 2068*3ccda647Slclee #endif 2069*3ccda647Slclee } 2070*3ccda647Slclee 2071*3ccda647Slclee /* 2072*3ccda647Slclee * if we got invalidated when mutex exit and entered again, 2073*3ccda647Slclee * if blockcount different than when we came in, need to 2074*3ccda647Slclee * retry from beginning of cmlb_validate_geometry. 2075*3ccda647Slclee * revisit this on next phase of utilizing this for 2076*3ccda647Slclee * sd. 2077*3ccda647Slclee */ 2078*3ccda647Slclee 2079*3ccda647Slclee if (label_capacity <= un->un_blockcount) { 2080*3ccda647Slclee #if defined(_SUNOS_VTOC_8) 2081*3ccda647Slclee /* 2082*3ccda647Slclee * We can't let this happen on drives that are subdivided 2083*3ccda647Slclee * into logical disks (i.e., that have an fdisk table). 2084*3ccda647Slclee * The un_blockcount field should always hold the full media 2085*3ccda647Slclee * size in sectors, period. This code would overwrite 2086*3ccda647Slclee * un_blockcount with the size of the Solaris fdisk partition. 2087*3ccda647Slclee */ 2088*3ccda647Slclee cmlb_dbg(CMLB_ERROR, un, 2089*3ccda647Slclee "cmlb_uselabel: Label %d blocks; Drive %d blocks\n", 2090*3ccda647Slclee label_capacity, un->un_blockcount); 2091*3ccda647Slclee un->un_solaris_size = label_capacity; 2092*3ccda647Slclee 2093*3ccda647Slclee #endif /* defined(_SUNOS_VTOC_8) */ 2094*3ccda647Slclee goto done; 2095*3ccda647Slclee } 2096*3ccda647Slclee 2097*3ccda647Slclee if (ISCD(un)) { 2098*3ccda647Slclee /* For CDROMs, we trust that the data in the label is OK. */ 2099*3ccda647Slclee #if defined(_SUNOS_VTOC_8) 2100*3ccda647Slclee for (i = 0; i < NDKMAP; i++) { 2101*3ccda647Slclee part_end = labp->dkl_nhead * labp->dkl_nsect * 2102*3ccda647Slclee labp->dkl_map[i].dkl_cylno + 2103*3ccda647Slclee labp->dkl_map[i].dkl_nblk - 1; 2104*3ccda647Slclee 2105*3ccda647Slclee if ((labp->dkl_map[i].dkl_nblk) && 2106*3ccda647Slclee (part_end > un->un_blockcount)) { 2107*3ccda647Slclee un->un_f_geometry_is_valid = FALSE; 2108*3ccda647Slclee break; 2109*3ccda647Slclee } 2110*3ccda647Slclee } 2111*3ccda647Slclee #endif 2112*3ccda647Slclee #if defined(_SUNOS_VTOC_16) 2113*3ccda647Slclee vpartp = &(labp->dkl_vtoc.v_part[0]); 2114*3ccda647Slclee for (i = 0; i < NDKMAP; i++, vpartp++) { 2115*3ccda647Slclee part_end = vpartp->p_start + vpartp->p_size; 2116*3ccda647Slclee if ((vpartp->p_size > 0) && 2117*3ccda647Slclee (part_end > un->un_blockcount)) { 2118*3ccda647Slclee un->un_f_geometry_is_valid = FALSE; 2119*3ccda647Slclee break; 2120*3ccda647Slclee } 2121*3ccda647Slclee } 2122*3ccda647Slclee #endif 2123*3ccda647Slclee } else { 2124*3ccda647Slclee /* label_capacity > un->un_blockcount */ 2125*3ccda647Slclee cmlb_log(CMLB_DEVINFO(un), CMLB_LABEL(un), CE_WARN, 2126*3ccda647Slclee "Corrupt label - bad geometry\n"); 2127*3ccda647Slclee cmlb_log(CMLB_DEVINFO(un), CMLB_LABEL(un), CE_CONT, 2128*3ccda647Slclee "Label says %llu blocks; Drive says %llu blocks\n", 2129*3ccda647Slclee label_capacity, un->un_blockcount); 2130*3ccda647Slclee un->un_f_geometry_is_valid = FALSE; 2131*3ccda647Slclee label_error = CMLB_LABEL_IS_INVALID; 2132*3ccda647Slclee } 2133*3ccda647Slclee 2134*3ccda647Slclee done: 2135*3ccda647Slclee 2136*3ccda647Slclee cmlb_dbg(CMLB_INFO, un, "cmlb_uselabel: (label geometry)\n"); 2137*3ccda647Slclee cmlb_dbg(CMLB_INFO, un, 2138*3ccda647Slclee " ncyl: %d; acyl: %d; nhead: %d; nsect: %d\n", 2139*3ccda647Slclee un->un_g.dkg_ncyl, un->un_g.dkg_acyl, 2140*3ccda647Slclee un->un_g.dkg_nhead, un->un_g.dkg_nsect); 2141*3ccda647Slclee 2142*3ccda647Slclee cmlb_dbg(CMLB_INFO, un, 2143*3ccda647Slclee " label_capacity: %d; intrlv: %d; rpm: %d\n", 2144*3ccda647Slclee un->un_blockcount, un->un_g.dkg_intrlv, un->un_g.dkg_rpm); 2145*3ccda647Slclee cmlb_dbg(CMLB_INFO, un, " wrt_reinstr: %d; rd_reinstr: %d\n", 2146*3ccda647Slclee un->un_g.dkg_write_reinstruct, un->un_g.dkg_read_reinstruct); 2147*3ccda647Slclee 2148*3ccda647Slclee ASSERT(mutex_owned(CMLB_MUTEX(un))); 2149*3ccda647Slclee 2150*3ccda647Slclee return (label_error); 2151*3ccda647Slclee } 2152*3ccda647Slclee 2153*3ccda647Slclee 2154*3ccda647Slclee /* 2155*3ccda647Slclee * Function: cmlb_build_default_label 2156*3ccda647Slclee * 2157*3ccda647Slclee * Description: Generate a default label for those devices that do not have 2158*3ccda647Slclee * one, e.g., new media, removable cartridges, etc.. 2159*3ccda647Slclee * 2160*3ccda647Slclee * Context: Kernel thread only 2161*3ccda647Slclee */ 2162*3ccda647Slclee static void 2163*3ccda647Slclee cmlb_build_default_label(struct cmlb_lun *un) 2164*3ccda647Slclee { 2165*3ccda647Slclee #if defined(_SUNOS_VTOC_16) 2166*3ccda647Slclee uint_t phys_spc; 2167*3ccda647Slclee uint_t disksize; 2168*3ccda647Slclee struct dk_geom un_g; 2169*3ccda647Slclee #endif 2170*3ccda647Slclee 2171*3ccda647Slclee ASSERT(un != NULL); 2172*3ccda647Slclee ASSERT(mutex_owned(CMLB_MUTEX(un))); 2173*3ccda647Slclee 2174*3ccda647Slclee #if defined(_SUNOS_VTOC_8) 2175*3ccda647Slclee /* 2176*3ccda647Slclee * Note: This is a legacy check for non-removable devices on VTOC_8 2177*3ccda647Slclee * only. This may be a valid check for VTOC_16 as well. 2178*3ccda647Slclee */ 2179*3ccda647Slclee if (!ISREMOVABLE(un)) { 2180*3ccda647Slclee return; 2181*3ccda647Slclee } 2182*3ccda647Slclee #endif 2183*3ccda647Slclee 2184*3ccda647Slclee bzero(&un->un_g, sizeof (struct dk_geom)); 2185*3ccda647Slclee bzero(&un->un_vtoc, sizeof (struct dk_vtoc)); 2186*3ccda647Slclee bzero(&un->un_map, NDKMAP * (sizeof (struct dk_map))); 2187*3ccda647Slclee 2188*3ccda647Slclee #if defined(_SUNOS_VTOC_8) 2189*3ccda647Slclee 2190*3ccda647Slclee /* 2191*3ccda647Slclee * It's a REMOVABLE media, therefore no label (on sparc, anyway). 2192*3ccda647Slclee * But it is still necessary to set up various geometry information, 2193*3ccda647Slclee * and we are doing this here. 2194*3ccda647Slclee */ 2195*3ccda647Slclee 2196*3ccda647Slclee /* 2197*3ccda647Slclee * For the rpm, we use the minimum for the disk. For the head, cyl, 2198*3ccda647Slclee * and number of sector per track, if the capacity <= 1GB, head = 64, 2199*3ccda647Slclee * sect = 32. else head = 255, sect 63 Note: the capacity should be 2200*3ccda647Slclee * equal to C*H*S values. This will cause some truncation of size due 2201*3ccda647Slclee * to round off errors. For CD-ROMs, this truncation can have adverse 2202*3ccda647Slclee * side effects, so returning ncyl and nhead as 1. The nsect will 2203*3ccda647Slclee * overflow for most of CD-ROMs as nsect is of type ushort. (4190569) 2204*3ccda647Slclee */ 2205*3ccda647Slclee un->un_solaris_size = un->un_blockcount; 2206*3ccda647Slclee if (ISCD(un)) { 2207*3ccda647Slclee tg_attribute_t tgattribute; 2208*3ccda647Slclee int is_writable; 2209*3ccda647Slclee /* 2210*3ccda647Slclee * Preserve the old behavior for non-writable 2211*3ccda647Slclee * medias. Since dkg_nsect is a ushort, it 2212*3ccda647Slclee * will lose bits as cdroms have more than 2213*3ccda647Slclee * 65536 sectors. So if we recalculate 2214*3ccda647Slclee * capacity, it will become much shorter. 2215*3ccda647Slclee * But the dkg_* information is not 2216*3ccda647Slclee * used for CDROMs so it is OK. But for 2217*3ccda647Slclee * Writable CDs we need this information 2218*3ccda647Slclee * to be valid (for newfs say). So we 2219*3ccda647Slclee * make nsect and nhead > 1 that way 2220*3ccda647Slclee * nsect can still stay within ushort limit 2221*3ccda647Slclee * without losing any bits. 2222*3ccda647Slclee */ 2223*3ccda647Slclee 2224*3ccda647Slclee bzero(&tgattribute, sizeof (tg_attribute_t)); 2225*3ccda647Slclee 2226*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 2227*3ccda647Slclee is_writable = (DK_TG_GETATTRIBUTE(un, &tgattribute) == 0) ? 2228*3ccda647Slclee tgattribute.media_is_writable : 1; 2229*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 2230*3ccda647Slclee 2231*3ccda647Slclee if (is_writable) { 2232*3ccda647Slclee un->un_g.dkg_nhead = 64; 2233*3ccda647Slclee un->un_g.dkg_nsect = 32; 2234*3ccda647Slclee un->un_g.dkg_ncyl = un->un_blockcount / (64 * 32); 2235*3ccda647Slclee un->un_solaris_size = un->un_g.dkg_ncyl * 2236*3ccda647Slclee un->un_g.dkg_nhead * un->un_g.dkg_nsect; 2237*3ccda647Slclee } else { 2238*3ccda647Slclee un->un_g.dkg_ncyl = 1; 2239*3ccda647Slclee un->un_g.dkg_nhead = 1; 2240*3ccda647Slclee un->un_g.dkg_nsect = un->un_blockcount; 2241*3ccda647Slclee } 2242*3ccda647Slclee } else { 2243*3ccda647Slclee if (un->un_blockcount <= 0x1000) { 2244*3ccda647Slclee /* unlabeled SCSI floppy device */ 2245*3ccda647Slclee un->un_g.dkg_nhead = 2; 2246*3ccda647Slclee un->un_g.dkg_ncyl = 80; 2247*3ccda647Slclee un->un_g.dkg_nsect = un->un_blockcount / (2 * 80); 2248*3ccda647Slclee } else if (un->un_blockcount <= 0x200000) { 2249*3ccda647Slclee un->un_g.dkg_nhead = 64; 2250*3ccda647Slclee un->un_g.dkg_nsect = 32; 2251*3ccda647Slclee un->un_g.dkg_ncyl = un->un_blockcount / (64 * 32); 2252*3ccda647Slclee } else { 2253*3ccda647Slclee un->un_g.dkg_nhead = 255; 2254*3ccda647Slclee un->un_g.dkg_nsect = 63; 2255*3ccda647Slclee un->un_g.dkg_ncyl = un->un_blockcount / (255 * 63); 2256*3ccda647Slclee } 2257*3ccda647Slclee un->un_solaris_size = 2258*3ccda647Slclee un->un_g.dkg_ncyl * un->un_g.dkg_nhead * un->un_g.dkg_nsect; 2259*3ccda647Slclee 2260*3ccda647Slclee } 2261*3ccda647Slclee 2262*3ccda647Slclee un->un_g.dkg_acyl = 0; 2263*3ccda647Slclee un->un_g.dkg_bcyl = 0; 2264*3ccda647Slclee un->un_g.dkg_rpm = 200; 2265*3ccda647Slclee un->un_asciilabel[0] = '\0'; 2266*3ccda647Slclee un->un_g.dkg_pcyl = un->un_g.dkg_ncyl; 2267*3ccda647Slclee 2268*3ccda647Slclee un->un_map[0].dkl_cylno = 0; 2269*3ccda647Slclee un->un_map[0].dkl_nblk = un->un_solaris_size; 2270*3ccda647Slclee 2271*3ccda647Slclee un->un_map[2].dkl_cylno = 0; 2272*3ccda647Slclee un->un_map[2].dkl_nblk = un->un_solaris_size; 2273*3ccda647Slclee 2274*3ccda647Slclee #elif defined(_SUNOS_VTOC_16) 2275*3ccda647Slclee 2276*3ccda647Slclee if (un->un_solaris_size == 0) { 2277*3ccda647Slclee /* 2278*3ccda647Slclee * Got fdisk table but no solaris entry therefore 2279*3ccda647Slclee * don't create a default label 2280*3ccda647Slclee */ 2281*3ccda647Slclee un->un_f_geometry_is_valid = TRUE; 2282*3ccda647Slclee return; 2283*3ccda647Slclee } 2284*3ccda647Slclee 2285*3ccda647Slclee /* 2286*3ccda647Slclee * For CDs we continue to use the physical geometry to calculate 2287*3ccda647Slclee * number of cylinders. All other devices must convert the 2288*3ccda647Slclee * physical geometry (cmlb_geom) to values that will fit 2289*3ccda647Slclee * in a dk_geom structure. 2290*3ccda647Slclee */ 2291*3ccda647Slclee if (ISCD(un)) { 2292*3ccda647Slclee phys_spc = un->un_pgeom.g_nhead * un->un_pgeom.g_nsect; 2293*3ccda647Slclee } else { 2294*3ccda647Slclee /* Convert physical geometry to disk geometry */ 2295*3ccda647Slclee bzero(&un_g, sizeof (struct dk_geom)); 2296*3ccda647Slclee cmlb_convert_geometry(un->un_blockcount, &un_g); 2297*3ccda647Slclee bcopy(&un_g, &un->un_g, sizeof (un->un_g)); 2298*3ccda647Slclee phys_spc = un->un_g.dkg_nhead * un->un_g.dkg_nsect; 2299*3ccda647Slclee } 2300*3ccda647Slclee 2301*3ccda647Slclee un->un_g.dkg_pcyl = un->un_solaris_size / phys_spc; 2302*3ccda647Slclee un->un_g.dkg_acyl = DK_ACYL; 2303*3ccda647Slclee un->un_g.dkg_ncyl = un->un_g.dkg_pcyl - DK_ACYL; 2304*3ccda647Slclee disksize = un->un_g.dkg_ncyl * phys_spc; 2305*3ccda647Slclee 2306*3ccda647Slclee if (ISCD(un)) { 2307*3ccda647Slclee /* 2308*3ccda647Slclee * CD's don't use the "heads * sectors * cyls"-type of 2309*3ccda647Slclee * geometry, but instead use the entire capacity of the media. 2310*3ccda647Slclee */ 2311*3ccda647Slclee disksize = un->un_solaris_size; 2312*3ccda647Slclee un->un_g.dkg_nhead = 1; 2313*3ccda647Slclee un->un_g.dkg_nsect = 1; 2314*3ccda647Slclee un->un_g.dkg_rpm = 2315*3ccda647Slclee (un->un_pgeom.g_rpm == 0) ? 200 : un->un_pgeom.g_rpm; 2316*3ccda647Slclee 2317*3ccda647Slclee un->un_vtoc.v_part[0].p_start = 0; 2318*3ccda647Slclee un->un_vtoc.v_part[0].p_size = disksize; 2319*3ccda647Slclee un->un_vtoc.v_part[0].p_tag = V_BACKUP; 2320*3ccda647Slclee un->un_vtoc.v_part[0].p_flag = V_UNMNT; 2321*3ccda647Slclee 2322*3ccda647Slclee un->un_map[0].dkl_cylno = 0; 2323*3ccda647Slclee un->un_map[0].dkl_nblk = disksize; 2324*3ccda647Slclee un->un_offset[0] = 0; 2325*3ccda647Slclee 2326*3ccda647Slclee } else { 2327*3ccda647Slclee /* 2328*3ccda647Slclee * Hard disks and removable media cartridges 2329*3ccda647Slclee */ 2330*3ccda647Slclee un->un_g.dkg_rpm = 2331*3ccda647Slclee (un->un_pgeom.g_rpm == 0) ? 3600: un->un_pgeom.g_rpm; 2332*3ccda647Slclee un->un_vtoc.v_sectorsz = un->un_sys_blocksize; 2333*3ccda647Slclee 2334*3ccda647Slclee /* Add boot slice */ 2335*3ccda647Slclee un->un_vtoc.v_part[8].p_start = 0; 2336*3ccda647Slclee un->un_vtoc.v_part[8].p_size = phys_spc; 2337*3ccda647Slclee un->un_vtoc.v_part[8].p_tag = V_BOOT; 2338*3ccda647Slclee un->un_vtoc.v_part[8].p_flag = V_UNMNT; 2339*3ccda647Slclee 2340*3ccda647Slclee un->un_map[8].dkl_cylno = 0; 2341*3ccda647Slclee un->un_map[8].dkl_nblk = phys_spc; 2342*3ccda647Slclee un->un_offset[8] = 0; 2343*3ccda647Slclee 2344*3ccda647Slclee if ((un->un_alter_behavior & 2345*3ccda647Slclee CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT) && 2346*3ccda647Slclee un->un_device_type == DTYPE_DIRECT) { 2347*3ccda647Slclee un->un_vtoc.v_part[9].p_start = phys_spc; 2348*3ccda647Slclee un->un_vtoc.v_part[9].p_size = 2 * phys_spc; 2349*3ccda647Slclee un->un_vtoc.v_part[9].p_tag = V_ALTSCTR; 2350*3ccda647Slclee un->un_vtoc.v_part[9].p_flag = 0; 2351*3ccda647Slclee 2352*3ccda647Slclee un->un_map[9].dkl_cylno = 1; 2353*3ccda647Slclee un->un_map[9].dkl_nblk = 2 * phys_spc; 2354*3ccda647Slclee un->un_offset[9] = phys_spc; 2355*3ccda647Slclee } 2356*3ccda647Slclee } 2357*3ccda647Slclee 2358*3ccda647Slclee un->un_g.dkg_apc = 0; 2359*3ccda647Slclee un->un_vtoc.v_nparts = V_NUMPAR; 2360*3ccda647Slclee un->un_vtoc.v_version = V_VERSION; 2361*3ccda647Slclee 2362*3ccda647Slclee /* Add backup slice */ 2363*3ccda647Slclee un->un_vtoc.v_part[2].p_start = 0; 2364*3ccda647Slclee un->un_vtoc.v_part[2].p_size = disksize; 2365*3ccda647Slclee un->un_vtoc.v_part[2].p_tag = V_BACKUP; 2366*3ccda647Slclee un->un_vtoc.v_part[2].p_flag = V_UNMNT; 2367*3ccda647Slclee 2368*3ccda647Slclee un->un_map[2].dkl_cylno = 0; 2369*3ccda647Slclee un->un_map[2].dkl_nblk = disksize; 2370*3ccda647Slclee un->un_offset[2] = 0; 2371*3ccda647Slclee 2372*3ccda647Slclee (void) sprintf(un->un_vtoc.v_asciilabel, "DEFAULT cyl %d alt %d" 2373*3ccda647Slclee " hd %d sec %d", un->un_g.dkg_ncyl, un->un_g.dkg_acyl, 2374*3ccda647Slclee un->un_g.dkg_nhead, un->un_g.dkg_nsect); 2375*3ccda647Slclee 2376*3ccda647Slclee #else 2377*3ccda647Slclee #error "No VTOC format defined." 2378*3ccda647Slclee #endif 2379*3ccda647Slclee 2380*3ccda647Slclee un->un_g.dkg_read_reinstruct = 0; 2381*3ccda647Slclee un->un_g.dkg_write_reinstruct = 0; 2382*3ccda647Slclee 2383*3ccda647Slclee un->un_g.dkg_intrlv = 1; 2384*3ccda647Slclee 2385*3ccda647Slclee un->un_vtoc.v_sanity = VTOC_SANE; 2386*3ccda647Slclee 2387*3ccda647Slclee un->un_f_geometry_is_valid = TRUE; 2388*3ccda647Slclee un->un_vtoc_label_is_from_media = 0; 2389*3ccda647Slclee 2390*3ccda647Slclee cmlb_dbg(CMLB_INFO, un, 2391*3ccda647Slclee "cmlb_build_default_label: Default label created: " 2392*3ccda647Slclee "cyl: %d\tacyl: %d\tnhead: %d\tnsect: %d\tcap: %d\n", 2393*3ccda647Slclee un->un_g.dkg_ncyl, un->un_g.dkg_acyl, un->un_g.dkg_nhead, 2394*3ccda647Slclee un->un_g.dkg_nsect, un->un_blockcount); 2395*3ccda647Slclee } 2396*3ccda647Slclee 2397*3ccda647Slclee 2398*3ccda647Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 2399*3ccda647Slclee /* 2400*3ccda647Slclee * Max CHS values, as they are encoded into bytes, for 1022/254/63 2401*3ccda647Slclee */ 2402*3ccda647Slclee #define LBA_MAX_SECT (63 | ((1022 & 0x300) >> 2)) 2403*3ccda647Slclee #define LBA_MAX_CYL (1022 & 0xFF) 2404*3ccda647Slclee #define LBA_MAX_HEAD (254) 2405*3ccda647Slclee 2406*3ccda647Slclee 2407*3ccda647Slclee /* 2408*3ccda647Slclee * Function: cmlb_has_max_chs_vals 2409*3ccda647Slclee * 2410*3ccda647Slclee * Description: Return TRUE if Cylinder-Head-Sector values are all at maximum. 2411*3ccda647Slclee * 2412*3ccda647Slclee * Arguments: fdp - ptr to CHS info 2413*3ccda647Slclee * 2414*3ccda647Slclee * Return Code: True or false 2415*3ccda647Slclee * 2416*3ccda647Slclee * Context: Any. 2417*3ccda647Slclee */ 2418*3ccda647Slclee static int 2419*3ccda647Slclee cmlb_has_max_chs_vals(struct ipart *fdp) 2420*3ccda647Slclee { 2421*3ccda647Slclee return ((fdp->begcyl == LBA_MAX_CYL) && 2422*3ccda647Slclee (fdp->beghead == LBA_MAX_HEAD) && 2423*3ccda647Slclee (fdp->begsect == LBA_MAX_SECT) && 2424*3ccda647Slclee (fdp->endcyl == LBA_MAX_CYL) && 2425*3ccda647Slclee (fdp->endhead == LBA_MAX_HEAD) && 2426*3ccda647Slclee (fdp->endsect == LBA_MAX_SECT)); 2427*3ccda647Slclee } 2428*3ccda647Slclee #endif 2429*3ccda647Slclee 2430*3ccda647Slclee /* 2431*3ccda647Slclee * Function: cmlb_dkio_get_geometry 2432*3ccda647Slclee * 2433*3ccda647Slclee * Description: This routine is the driver entry point for handling user 2434*3ccda647Slclee * requests to get the device geometry (DKIOCGGEOM). 2435*3ccda647Slclee * 2436*3ccda647Slclee * Arguments: 2437*3ccda647Slclee * arg - pointer to user provided dk_geom structure specifying 2438*3ccda647Slclee * the controller's notion of the current geometry. 2439*3ccda647Slclee * flag - this argument is a pass through to ddi_copyxxx() 2440*3ccda647Slclee * directly from the mode argument of ioctl(). 2441*3ccda647Slclee * 2442*3ccda647Slclee * Return Code: 0 2443*3ccda647Slclee * EFAULT 2444*3ccda647Slclee * ENXIO 2445*3ccda647Slclee * EIO 2446*3ccda647Slclee */ 2447*3ccda647Slclee static int 2448*3ccda647Slclee cmlb_dkio_get_geometry(struct cmlb_lun *un, caddr_t arg, int flag) 2449*3ccda647Slclee { 2450*3ccda647Slclee struct dk_geom *tmp_geom = NULL; 2451*3ccda647Slclee int rval = 0; 2452*3ccda647Slclee 2453*3ccda647Slclee /* 2454*3ccda647Slclee * cmlb_validate_geometry does not spin a disk up 2455*3ccda647Slclee * if it was spun down. We need to make sure it 2456*3ccda647Slclee * is ready. 2457*3ccda647Slclee */ 2458*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 2459*3ccda647Slclee rval = cmlb_validate_geometry(un, 1); 2460*3ccda647Slclee #if defined(_SUNOS_VTOC_8) 2461*3ccda647Slclee if (rval == EINVAL && 2462*3ccda647Slclee un->un_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8) { 2463*3ccda647Slclee /* 2464*3ccda647Slclee * This is to return a default label geometry even when we 2465*3ccda647Slclee * do not really assume a default label for the device. 2466*3ccda647Slclee * dad driver utilizes this. 2467*3ccda647Slclee */ 2468*3ccda647Slclee if (un->un_blockcount <= DK_MAX_BLOCKS) { 2469*3ccda647Slclee cmlb_setup_default_geometry(un); 2470*3ccda647Slclee rval = 0; 2471*3ccda647Slclee } 2472*3ccda647Slclee } 2473*3ccda647Slclee #endif 2474*3ccda647Slclee if (rval) { 2475*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 2476*3ccda647Slclee return (rval); 2477*3ccda647Slclee } 2478*3ccda647Slclee 2479*3ccda647Slclee #if defined(__i386) || defined(__amd64) 2480*3ccda647Slclee if (un->un_solaris_size == 0) { 2481*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 2482*3ccda647Slclee return (EIO); 2483*3ccda647Slclee } 2484*3ccda647Slclee #endif 2485*3ccda647Slclee 2486*3ccda647Slclee /* 2487*3ccda647Slclee * Make a local copy of the soft state geometry to avoid some potential 2488*3ccda647Slclee * race conditions associated with holding the mutex and updating the 2489*3ccda647Slclee * write_reinstruct value 2490*3ccda647Slclee */ 2491*3ccda647Slclee tmp_geom = kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP); 2492*3ccda647Slclee bcopy(&un->un_g, tmp_geom, sizeof (struct dk_geom)); 2493*3ccda647Slclee 2494*3ccda647Slclee if (tmp_geom->dkg_write_reinstruct == 0) { 2495*3ccda647Slclee tmp_geom->dkg_write_reinstruct = 2496*3ccda647Slclee (int)((int)(tmp_geom->dkg_nsect * tmp_geom->dkg_rpm * 2497*3ccda647Slclee cmlb_rot_delay) / (int)60000); 2498*3ccda647Slclee } 2499*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 2500*3ccda647Slclee 2501*3ccda647Slclee rval = ddi_copyout(tmp_geom, (void *)arg, sizeof (struct dk_geom), 2502*3ccda647Slclee flag); 2503*3ccda647Slclee if (rval != 0) { 2504*3ccda647Slclee rval = EFAULT; 2505*3ccda647Slclee } 2506*3ccda647Slclee 2507*3ccda647Slclee kmem_free(tmp_geom, sizeof (struct dk_geom)); 2508*3ccda647Slclee return (rval); 2509*3ccda647Slclee 2510*3ccda647Slclee } 2511*3ccda647Slclee 2512*3ccda647Slclee 2513*3ccda647Slclee /* 2514*3ccda647Slclee * Function: cmlb_dkio_set_geometry 2515*3ccda647Slclee * 2516*3ccda647Slclee * Description: This routine is the driver entry point for handling user 2517*3ccda647Slclee * requests to set the device geometry (DKIOCSGEOM). The actual 2518*3ccda647Slclee * device geometry is not updated, just the driver "notion" of it. 2519*3ccda647Slclee * 2520*3ccda647Slclee * Arguments: 2521*3ccda647Slclee * arg - pointer to user provided dk_geom structure used to set 2522*3ccda647Slclee * the controller's notion of the current geometry. 2523*3ccda647Slclee * flag - this argument is a pass through to ddi_copyxxx() 2524*3ccda647Slclee * directly from the mode argument of ioctl(). 2525*3ccda647Slclee * 2526*3ccda647Slclee * Return Code: 0 2527*3ccda647Slclee * EFAULT 2528*3ccda647Slclee * ENXIO 2529*3ccda647Slclee * EIO 2530*3ccda647Slclee */ 2531*3ccda647Slclee static int 2532*3ccda647Slclee cmlb_dkio_set_geometry(struct cmlb_lun *un, caddr_t arg, int flag) 2533*3ccda647Slclee { 2534*3ccda647Slclee struct dk_geom *tmp_geom; 2535*3ccda647Slclee struct dk_map *lp; 2536*3ccda647Slclee int rval = 0; 2537*3ccda647Slclee int i; 2538*3ccda647Slclee 2539*3ccda647Slclee 2540*3ccda647Slclee #if defined(__i386) || defined(__amd64) 2541*3ccda647Slclee if (un->un_solaris_size == 0) { 2542*3ccda647Slclee return (EIO); 2543*3ccda647Slclee } 2544*3ccda647Slclee #endif 2545*3ccda647Slclee /* 2546*3ccda647Slclee * We need to copy the user specified geometry into local 2547*3ccda647Slclee * storage and then update the softstate. We don't want to hold 2548*3ccda647Slclee * the mutex and copyin directly from the user to the soft state 2549*3ccda647Slclee */ 2550*3ccda647Slclee tmp_geom = (struct dk_geom *) 2551*3ccda647Slclee kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP); 2552*3ccda647Slclee rval = ddi_copyin(arg, tmp_geom, sizeof (struct dk_geom), flag); 2553*3ccda647Slclee if (rval != 0) { 2554*3ccda647Slclee kmem_free(tmp_geom, sizeof (struct dk_geom)); 2555*3ccda647Slclee return (EFAULT); 2556*3ccda647Slclee } 2557*3ccda647Slclee 2558*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 2559*3ccda647Slclee bcopy(tmp_geom, &un->un_g, sizeof (struct dk_geom)); 2560*3ccda647Slclee for (i = 0; i < NDKMAP; i++) { 2561*3ccda647Slclee lp = &un->un_map[i]; 2562*3ccda647Slclee un->un_offset[i] = 2563*3ccda647Slclee un->un_g.dkg_nhead * un->un_g.dkg_nsect * lp->dkl_cylno; 2564*3ccda647Slclee #if defined(__i386) || defined(__amd64) 2565*3ccda647Slclee un->un_offset[i] += un->un_solaris_offset; 2566*3ccda647Slclee #endif 2567*3ccda647Slclee } 2568*3ccda647Slclee un->un_f_geometry_is_valid = FALSE; 2569*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 2570*3ccda647Slclee kmem_free(tmp_geom, sizeof (struct dk_geom)); 2571*3ccda647Slclee 2572*3ccda647Slclee return (rval); 2573*3ccda647Slclee } 2574*3ccda647Slclee 2575*3ccda647Slclee /* 2576*3ccda647Slclee * Function: cmlb_dkio_get_partition 2577*3ccda647Slclee * 2578*3ccda647Slclee * Description: This routine is the driver entry point for handling user 2579*3ccda647Slclee * requests to get the partition table (DKIOCGAPART). 2580*3ccda647Slclee * 2581*3ccda647Slclee * Arguments: 2582*3ccda647Slclee * arg - pointer to user provided dk_allmap structure specifying 2583*3ccda647Slclee * the controller's notion of the current partition table. 2584*3ccda647Slclee * flag - this argument is a pass through to ddi_copyxxx() 2585*3ccda647Slclee * directly from the mode argument of ioctl(). 2586*3ccda647Slclee * 2587*3ccda647Slclee * Return Code: 0 2588*3ccda647Slclee * EFAULT 2589*3ccda647Slclee * ENXIO 2590*3ccda647Slclee * EIO 2591*3ccda647Slclee */ 2592*3ccda647Slclee static int 2593*3ccda647Slclee cmlb_dkio_get_partition(struct cmlb_lun *un, caddr_t arg, int flag) 2594*3ccda647Slclee { 2595*3ccda647Slclee int rval = 0; 2596*3ccda647Slclee int size; 2597*3ccda647Slclee 2598*3ccda647Slclee /* 2599*3ccda647Slclee * Make sure the geometry is valid before getting the partition 2600*3ccda647Slclee * information. 2601*3ccda647Slclee */ 2602*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 2603*3ccda647Slclee if ((rval = cmlb_validate_geometry(un, 1)) != 0) { 2604*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 2605*3ccda647Slclee return (rval); 2606*3ccda647Slclee } 2607*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 2608*3ccda647Slclee 2609*3ccda647Slclee #if defined(__i386) || defined(__amd64) 2610*3ccda647Slclee if (un->un_solaris_size == 0) { 2611*3ccda647Slclee return (EIO); 2612*3ccda647Slclee } 2613*3ccda647Slclee #endif 2614*3ccda647Slclee 2615*3ccda647Slclee #ifdef _MULTI_DATAMODEL 2616*3ccda647Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 2617*3ccda647Slclee case DDI_MODEL_ILP32: { 2618*3ccda647Slclee struct dk_map32 dk_map32[NDKMAP]; 2619*3ccda647Slclee int i; 2620*3ccda647Slclee 2621*3ccda647Slclee for (i = 0; i < NDKMAP; i++) { 2622*3ccda647Slclee dk_map32[i].dkl_cylno = un->un_map[i].dkl_cylno; 2623*3ccda647Slclee dk_map32[i].dkl_nblk = un->un_map[i].dkl_nblk; 2624*3ccda647Slclee } 2625*3ccda647Slclee size = NDKMAP * sizeof (struct dk_map32); 2626*3ccda647Slclee rval = ddi_copyout(dk_map32, (void *)arg, size, flag); 2627*3ccda647Slclee if (rval != 0) { 2628*3ccda647Slclee rval = EFAULT; 2629*3ccda647Slclee } 2630*3ccda647Slclee break; 2631*3ccda647Slclee } 2632*3ccda647Slclee case DDI_MODEL_NONE: 2633*3ccda647Slclee size = NDKMAP * sizeof (struct dk_map); 2634*3ccda647Slclee rval = ddi_copyout(un->un_map, (void *)arg, size, flag); 2635*3ccda647Slclee if (rval != 0) { 2636*3ccda647Slclee rval = EFAULT; 2637*3ccda647Slclee } 2638*3ccda647Slclee break; 2639*3ccda647Slclee } 2640*3ccda647Slclee #else /* ! _MULTI_DATAMODEL */ 2641*3ccda647Slclee size = NDKMAP * sizeof (struct dk_map); 2642*3ccda647Slclee rval = ddi_copyout(un->un_map, (void *)arg, size, flag); 2643*3ccda647Slclee if (rval != 0) { 2644*3ccda647Slclee rval = EFAULT; 2645*3ccda647Slclee } 2646*3ccda647Slclee #endif /* _MULTI_DATAMODEL */ 2647*3ccda647Slclee return (rval); 2648*3ccda647Slclee } 2649*3ccda647Slclee 2650*3ccda647Slclee /* 2651*3ccda647Slclee * Function: cmlb_dkio_set_partition 2652*3ccda647Slclee * 2653*3ccda647Slclee * Description: This routine is the driver entry point for handling user 2654*3ccda647Slclee * requests to set the partition table (DKIOCSAPART). The actual 2655*3ccda647Slclee * device partition is not updated. 2656*3ccda647Slclee * 2657*3ccda647Slclee * Arguments: 2658*3ccda647Slclee * arg - pointer to user provided dk_allmap structure used to set 2659*3ccda647Slclee * the controller's notion of the partition table. 2660*3ccda647Slclee * flag - this argument is a pass through to ddi_copyxxx() 2661*3ccda647Slclee * directly from the mode argument of ioctl(). 2662*3ccda647Slclee * 2663*3ccda647Slclee * Return Code: 0 2664*3ccda647Slclee * EINVAL 2665*3ccda647Slclee * EFAULT 2666*3ccda647Slclee * ENXIO 2667*3ccda647Slclee * EIO 2668*3ccda647Slclee */ 2669*3ccda647Slclee static int 2670*3ccda647Slclee cmlb_dkio_set_partition(struct cmlb_lun *un, caddr_t arg, int flag) 2671*3ccda647Slclee { 2672*3ccda647Slclee struct dk_map dk_map[NDKMAP]; 2673*3ccda647Slclee struct dk_map *lp; 2674*3ccda647Slclee int rval = 0; 2675*3ccda647Slclee int size; 2676*3ccda647Slclee int i; 2677*3ccda647Slclee #if defined(_SUNOS_VTOC_16) 2678*3ccda647Slclee struct dkl_partition *vp; 2679*3ccda647Slclee #endif 2680*3ccda647Slclee 2681*3ccda647Slclee /* 2682*3ccda647Slclee * Set the map for all logical partitions. We lock 2683*3ccda647Slclee * the priority just to make sure an interrupt doesn't 2684*3ccda647Slclee * come in while the map is half updated. 2685*3ccda647Slclee */ 2686*3ccda647Slclee _NOTE(DATA_READABLE_WITHOUT_LOCK(cmlb_lun::un_solaris_size)) 2687*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 2688*3ccda647Slclee 2689*3ccda647Slclee if (un->un_blockcount > DK_MAX_BLOCKS) { 2690*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 2691*3ccda647Slclee return (ENOTSUP); 2692*3ccda647Slclee } 2693*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 2694*3ccda647Slclee if (un->un_solaris_size == 0) { 2695*3ccda647Slclee return (EIO); 2696*3ccda647Slclee } 2697*3ccda647Slclee 2698*3ccda647Slclee #ifdef _MULTI_DATAMODEL 2699*3ccda647Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 2700*3ccda647Slclee case DDI_MODEL_ILP32: { 2701*3ccda647Slclee struct dk_map32 dk_map32[NDKMAP]; 2702*3ccda647Slclee 2703*3ccda647Slclee size = NDKMAP * sizeof (struct dk_map32); 2704*3ccda647Slclee rval = ddi_copyin((void *)arg, dk_map32, size, flag); 2705*3ccda647Slclee if (rval != 0) { 2706*3ccda647Slclee return (EFAULT); 2707*3ccda647Slclee } 2708*3ccda647Slclee for (i = 0; i < NDKMAP; i++) { 2709*3ccda647Slclee dk_map[i].dkl_cylno = dk_map32[i].dkl_cylno; 2710*3ccda647Slclee dk_map[i].dkl_nblk = dk_map32[i].dkl_nblk; 2711*3ccda647Slclee } 2712*3ccda647Slclee break; 2713*3ccda647Slclee } 2714*3ccda647Slclee case DDI_MODEL_NONE: 2715*3ccda647Slclee size = NDKMAP * sizeof (struct dk_map); 2716*3ccda647Slclee rval = ddi_copyin((void *)arg, dk_map, size, flag); 2717*3ccda647Slclee if (rval != 0) { 2718*3ccda647Slclee return (EFAULT); 2719*3ccda647Slclee } 2720*3ccda647Slclee break; 2721*3ccda647Slclee } 2722*3ccda647Slclee #else /* ! _MULTI_DATAMODEL */ 2723*3ccda647Slclee size = NDKMAP * sizeof (struct dk_map); 2724*3ccda647Slclee rval = ddi_copyin((void *)arg, dk_map, size, flag); 2725*3ccda647Slclee if (rval != 0) { 2726*3ccda647Slclee return (EFAULT); 2727*3ccda647Slclee } 2728*3ccda647Slclee #endif /* _MULTI_DATAMODEL */ 2729*3ccda647Slclee 2730*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 2731*3ccda647Slclee /* Note: The size used in this bcopy is set based upon the data model */ 2732*3ccda647Slclee bcopy(dk_map, un->un_map, size); 2733*3ccda647Slclee #if defined(_SUNOS_VTOC_16) 2734*3ccda647Slclee vp = (struct dkl_partition *)&(un->un_vtoc); 2735*3ccda647Slclee #endif /* defined(_SUNOS_VTOC_16) */ 2736*3ccda647Slclee for (i = 0; i < NDKMAP; i++) { 2737*3ccda647Slclee lp = &un->un_map[i]; 2738*3ccda647Slclee un->un_offset[i] = 2739*3ccda647Slclee un->un_g.dkg_nhead * un->un_g.dkg_nsect * lp->dkl_cylno; 2740*3ccda647Slclee #if defined(_SUNOS_VTOC_16) 2741*3ccda647Slclee vp->p_start = un->un_offset[i]; 2742*3ccda647Slclee vp->p_size = lp->dkl_nblk; 2743*3ccda647Slclee vp++; 2744*3ccda647Slclee #endif /* defined(_SUNOS_VTOC_16) */ 2745*3ccda647Slclee #if defined(__i386) || defined(__amd64) 2746*3ccda647Slclee un->un_offset[i] += un->un_solaris_offset; 2747*3ccda647Slclee #endif 2748*3ccda647Slclee } 2749*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 2750*3ccda647Slclee return (rval); 2751*3ccda647Slclee } 2752*3ccda647Slclee 2753*3ccda647Slclee 2754*3ccda647Slclee /* 2755*3ccda647Slclee * Function: cmlb_dkio_get_vtoc 2756*3ccda647Slclee * 2757*3ccda647Slclee * Description: This routine is the driver entry point for handling user 2758*3ccda647Slclee * requests to get the current volume table of contents 2759*3ccda647Slclee * (DKIOCGVTOC). 2760*3ccda647Slclee * 2761*3ccda647Slclee * Arguments: 2762*3ccda647Slclee * arg - pointer to user provided vtoc structure specifying 2763*3ccda647Slclee * the current vtoc. 2764*3ccda647Slclee * flag - this argument is a pass through to ddi_copyxxx() 2765*3ccda647Slclee * directly from the mode argument of ioctl(). 2766*3ccda647Slclee * 2767*3ccda647Slclee * Return Code: 0 2768*3ccda647Slclee * EFAULT 2769*3ccda647Slclee * ENXIO 2770*3ccda647Slclee * EIO 2771*3ccda647Slclee */ 2772*3ccda647Slclee static int 2773*3ccda647Slclee cmlb_dkio_get_vtoc(struct cmlb_lun *un, caddr_t arg, int flag) 2774*3ccda647Slclee { 2775*3ccda647Slclee #if defined(_SUNOS_VTOC_8) 2776*3ccda647Slclee struct vtoc user_vtoc; 2777*3ccda647Slclee #endif /* defined(_SUNOS_VTOC_8) */ 2778*3ccda647Slclee int rval = 0; 2779*3ccda647Slclee 2780*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 2781*3ccda647Slclee rval = cmlb_validate_geometry(un, 1); 2782*3ccda647Slclee 2783*3ccda647Slclee #if defined(_SUNOS_VTOC_8) 2784*3ccda647Slclee if (rval == EINVAL && 2785*3ccda647Slclee (un->un_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8)) { 2786*3ccda647Slclee /* 2787*3ccda647Slclee * This is to return a default label even when we do not 2788*3ccda647Slclee * really assume a default label for the device. 2789*3ccda647Slclee * dad driver utilizes this. 2790*3ccda647Slclee */ 2791*3ccda647Slclee if (un->un_blockcount <= DK_MAX_BLOCKS) { 2792*3ccda647Slclee cmlb_setup_default_geometry(un); 2793*3ccda647Slclee rval = 0; 2794*3ccda647Slclee } 2795*3ccda647Slclee } 2796*3ccda647Slclee #endif 2797*3ccda647Slclee if (rval) { 2798*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 2799*3ccda647Slclee return (rval); 2800*3ccda647Slclee } 2801*3ccda647Slclee 2802*3ccda647Slclee #if defined(_SUNOS_VTOC_8) 2803*3ccda647Slclee cmlb_build_user_vtoc(un, &user_vtoc); 2804*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 2805*3ccda647Slclee 2806*3ccda647Slclee #ifdef _MULTI_DATAMODEL 2807*3ccda647Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 2808*3ccda647Slclee case DDI_MODEL_ILP32: { 2809*3ccda647Slclee struct vtoc32 user_vtoc32; 2810*3ccda647Slclee 2811*3ccda647Slclee vtoctovtoc32(user_vtoc, user_vtoc32); 2812*3ccda647Slclee if (ddi_copyout(&user_vtoc32, (void *)arg, 2813*3ccda647Slclee sizeof (struct vtoc32), flag)) { 2814*3ccda647Slclee return (EFAULT); 2815*3ccda647Slclee } 2816*3ccda647Slclee break; 2817*3ccda647Slclee } 2818*3ccda647Slclee 2819*3ccda647Slclee case DDI_MODEL_NONE: 2820*3ccda647Slclee if (ddi_copyout(&user_vtoc, (void *)arg, 2821*3ccda647Slclee sizeof (struct vtoc), flag)) { 2822*3ccda647Slclee return (EFAULT); 2823*3ccda647Slclee } 2824*3ccda647Slclee break; 2825*3ccda647Slclee } 2826*3ccda647Slclee #else /* ! _MULTI_DATAMODEL */ 2827*3ccda647Slclee if (ddi_copyout(&user_vtoc, (void *)arg, sizeof (struct vtoc), flag)) { 2828*3ccda647Slclee return (EFAULT); 2829*3ccda647Slclee } 2830*3ccda647Slclee #endif /* _MULTI_DATAMODEL */ 2831*3ccda647Slclee 2832*3ccda647Slclee #elif defined(_SUNOS_VTOC_16) 2833*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 2834*3ccda647Slclee 2835*3ccda647Slclee #ifdef _MULTI_DATAMODEL 2836*3ccda647Slclee /* 2837*3ccda647Slclee * The un_vtoc structure is a "struct dk_vtoc" which is always 2838*3ccda647Slclee * 32-bit to maintain compatibility with existing on-disk 2839*3ccda647Slclee * structures. Thus, we need to convert the structure when copying 2840*3ccda647Slclee * it out to a datamodel-dependent "struct vtoc" in a 64-bit 2841*3ccda647Slclee * program. If the target is a 32-bit program, then no conversion 2842*3ccda647Slclee * is necessary. 2843*3ccda647Slclee */ 2844*3ccda647Slclee /* LINTED: logical expression always true: op "||" */ 2845*3ccda647Slclee ASSERT(sizeof (un->un_vtoc) == sizeof (struct vtoc32)); 2846*3ccda647Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 2847*3ccda647Slclee case DDI_MODEL_ILP32: 2848*3ccda647Slclee if (ddi_copyout(&(un->un_vtoc), (void *)arg, 2849*3ccda647Slclee sizeof (un->un_vtoc), flag)) { 2850*3ccda647Slclee return (EFAULT); 2851*3ccda647Slclee } 2852*3ccda647Slclee break; 2853*3ccda647Slclee 2854*3ccda647Slclee case DDI_MODEL_NONE: { 2855*3ccda647Slclee struct vtoc user_vtoc; 2856*3ccda647Slclee 2857*3ccda647Slclee vtoc32tovtoc(un->un_vtoc, user_vtoc); 2858*3ccda647Slclee if (ddi_copyout(&user_vtoc, (void *)arg, 2859*3ccda647Slclee sizeof (struct vtoc), flag)) { 2860*3ccda647Slclee return (EFAULT); 2861*3ccda647Slclee } 2862*3ccda647Slclee break; 2863*3ccda647Slclee } 2864*3ccda647Slclee } 2865*3ccda647Slclee #else /* ! _MULTI_DATAMODEL */ 2866*3ccda647Slclee if (ddi_copyout(&(un->un_vtoc), (void *)arg, sizeof (un->un_vtoc), 2867*3ccda647Slclee flag)) { 2868*3ccda647Slclee return (EFAULT); 2869*3ccda647Slclee } 2870*3ccda647Slclee #endif /* _MULTI_DATAMODEL */ 2871*3ccda647Slclee #else 2872*3ccda647Slclee #error "No VTOC format defined." 2873*3ccda647Slclee #endif 2874*3ccda647Slclee 2875*3ccda647Slclee return (rval); 2876*3ccda647Slclee } 2877*3ccda647Slclee 2878*3ccda647Slclee static int 2879*3ccda647Slclee cmlb_dkio_get_efi(struct cmlb_lun *un, caddr_t arg, int flag) 2880*3ccda647Slclee { 2881*3ccda647Slclee dk_efi_t user_efi; 2882*3ccda647Slclee int rval = 0; 2883*3ccda647Slclee void *buffer; 2884*3ccda647Slclee 2885*3ccda647Slclee if (ddi_copyin(arg, &user_efi, sizeof (dk_efi_t), flag)) 2886*3ccda647Slclee return (EFAULT); 2887*3ccda647Slclee 2888*3ccda647Slclee user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64; 2889*3ccda647Slclee 2890*3ccda647Slclee buffer = kmem_alloc(user_efi.dki_length, KM_SLEEP); 2891*3ccda647Slclee rval = DK_TG_READ(un, buffer, user_efi.dki_lba, user_efi.dki_length); 2892*3ccda647Slclee if (rval == 0 && ddi_copyout(buffer, user_efi.dki_data, 2893*3ccda647Slclee user_efi.dki_length, flag) != 0) 2894*3ccda647Slclee rval = EFAULT; 2895*3ccda647Slclee 2896*3ccda647Slclee kmem_free(buffer, user_efi.dki_length); 2897*3ccda647Slclee return (rval); 2898*3ccda647Slclee } 2899*3ccda647Slclee 2900*3ccda647Slclee /* 2901*3ccda647Slclee * Function: cmlb_build_user_vtoc 2902*3ccda647Slclee * 2903*3ccda647Slclee * Description: This routine populates a pass by reference variable with the 2904*3ccda647Slclee * current volume table of contents. 2905*3ccda647Slclee * 2906*3ccda647Slclee * Arguments: un - driver soft state (unit) structure 2907*3ccda647Slclee * user_vtoc - pointer to vtoc structure to be populated 2908*3ccda647Slclee */ 2909*3ccda647Slclee static void 2910*3ccda647Slclee cmlb_build_user_vtoc(struct cmlb_lun *un, struct vtoc *user_vtoc) 2911*3ccda647Slclee { 2912*3ccda647Slclee struct dk_map2 *lpart; 2913*3ccda647Slclee struct dk_map *lmap; 2914*3ccda647Slclee struct partition *vpart; 2915*3ccda647Slclee int nblks; 2916*3ccda647Slclee int i; 2917*3ccda647Slclee 2918*3ccda647Slclee ASSERT(mutex_owned(CMLB_MUTEX(un))); 2919*3ccda647Slclee 2920*3ccda647Slclee /* 2921*3ccda647Slclee * Return vtoc structure fields in the provided VTOC area, addressed 2922*3ccda647Slclee * by *vtoc. 2923*3ccda647Slclee */ 2924*3ccda647Slclee bzero(user_vtoc, sizeof (struct vtoc)); 2925*3ccda647Slclee user_vtoc->v_bootinfo[0] = un->un_vtoc.v_bootinfo[0]; 2926*3ccda647Slclee user_vtoc->v_bootinfo[1] = un->un_vtoc.v_bootinfo[1]; 2927*3ccda647Slclee user_vtoc->v_bootinfo[2] = un->un_vtoc.v_bootinfo[2]; 2928*3ccda647Slclee user_vtoc->v_sanity = VTOC_SANE; 2929*3ccda647Slclee user_vtoc->v_version = un->un_vtoc.v_version; 2930*3ccda647Slclee bcopy(un->un_vtoc.v_volume, user_vtoc->v_volume, LEN_DKL_VVOL); 2931*3ccda647Slclee user_vtoc->v_sectorsz = un->un_sys_blocksize; 2932*3ccda647Slclee user_vtoc->v_nparts = un->un_vtoc.v_nparts; 2933*3ccda647Slclee 2934*3ccda647Slclee for (i = 0; i < 10; i++) 2935*3ccda647Slclee user_vtoc->v_reserved[i] = un->un_vtoc.v_reserved[i]; 2936*3ccda647Slclee 2937*3ccda647Slclee /* 2938*3ccda647Slclee * Convert partitioning information. 2939*3ccda647Slclee * 2940*3ccda647Slclee * Note the conversion from starting cylinder number 2941*3ccda647Slclee * to starting sector number. 2942*3ccda647Slclee */ 2943*3ccda647Slclee lmap = un->un_map; 2944*3ccda647Slclee lpart = (struct dk_map2 *)un->un_vtoc.v_part; 2945*3ccda647Slclee vpart = user_vtoc->v_part; 2946*3ccda647Slclee 2947*3ccda647Slclee nblks = un->un_g.dkg_nsect * un->un_g.dkg_nhead; 2948*3ccda647Slclee 2949*3ccda647Slclee for (i = 0; i < V_NUMPAR; i++) { 2950*3ccda647Slclee vpart->p_tag = lpart->p_tag; 2951*3ccda647Slclee vpart->p_flag = lpart->p_flag; 2952*3ccda647Slclee vpart->p_start = lmap->dkl_cylno * nblks; 2953*3ccda647Slclee vpart->p_size = lmap->dkl_nblk; 2954*3ccda647Slclee lmap++; 2955*3ccda647Slclee lpart++; 2956*3ccda647Slclee vpart++; 2957*3ccda647Slclee 2958*3ccda647Slclee /* (4364927) */ 2959*3ccda647Slclee user_vtoc->timestamp[i] = (time_t)un->un_vtoc.v_timestamp[i]; 2960*3ccda647Slclee } 2961*3ccda647Slclee 2962*3ccda647Slclee bcopy(un->un_asciilabel, user_vtoc->v_asciilabel, LEN_DKL_ASCII); 2963*3ccda647Slclee } 2964*3ccda647Slclee 2965*3ccda647Slclee static int 2966*3ccda647Slclee cmlb_dkio_partition(struct cmlb_lun *un, caddr_t arg, int flag) 2967*3ccda647Slclee { 2968*3ccda647Slclee struct partition64 p64; 2969*3ccda647Slclee int rval = 0; 2970*3ccda647Slclee uint_t nparts; 2971*3ccda647Slclee efi_gpe_t *partitions; 2972*3ccda647Slclee efi_gpt_t *buffer; 2973*3ccda647Slclee diskaddr_t gpe_lba; 2974*3ccda647Slclee 2975*3ccda647Slclee if (ddi_copyin((const void *)arg, &p64, 2976*3ccda647Slclee sizeof (struct partition64), flag)) { 2977*3ccda647Slclee return (EFAULT); 2978*3ccda647Slclee } 2979*3ccda647Slclee 2980*3ccda647Slclee buffer = kmem_alloc(EFI_MIN_ARRAY_SIZE, KM_SLEEP); 2981*3ccda647Slclee rval = DK_TG_READ(un, buffer, 1, DEV_BSIZE); 2982*3ccda647Slclee if (rval != 0) 2983*3ccda647Slclee goto done_error; 2984*3ccda647Slclee 2985*3ccda647Slclee cmlb_swap_efi_gpt(buffer); 2986*3ccda647Slclee 2987*3ccda647Slclee if ((rval = cmlb_validate_efi(buffer)) != 0) 2988*3ccda647Slclee goto done_error; 2989*3ccda647Slclee 2990*3ccda647Slclee nparts = buffer->efi_gpt_NumberOfPartitionEntries; 2991*3ccda647Slclee gpe_lba = buffer->efi_gpt_PartitionEntryLBA; 2992*3ccda647Slclee if (p64.p_partno > nparts) { 2993*3ccda647Slclee /* couldn't find it */ 2994*3ccda647Slclee rval = ESRCH; 2995*3ccda647Slclee goto done_error; 2996*3ccda647Slclee } 2997*3ccda647Slclee /* 2998*3ccda647Slclee * if we're dealing with a partition that's out of the normal 2999*3ccda647Slclee * 16K block, adjust accordingly 3000*3ccda647Slclee */ 3001*3ccda647Slclee gpe_lba += p64.p_partno / sizeof (efi_gpe_t); 3002*3ccda647Slclee rval = DK_TG_READ(un, buffer, gpe_lba, EFI_MIN_ARRAY_SIZE); 3003*3ccda647Slclee 3004*3ccda647Slclee if (rval) { 3005*3ccda647Slclee goto done_error; 3006*3ccda647Slclee } 3007*3ccda647Slclee partitions = (efi_gpe_t *)buffer; 3008*3ccda647Slclee 3009*3ccda647Slclee cmlb_swap_efi_gpe(nparts, partitions); 3010*3ccda647Slclee 3011*3ccda647Slclee partitions += p64.p_partno; 3012*3ccda647Slclee bcopy(&partitions->efi_gpe_PartitionTypeGUID, &p64.p_type, 3013*3ccda647Slclee sizeof (struct uuid)); 3014*3ccda647Slclee p64.p_start = partitions->efi_gpe_StartingLBA; 3015*3ccda647Slclee p64.p_size = partitions->efi_gpe_EndingLBA - 3016*3ccda647Slclee p64.p_start + 1; 3017*3ccda647Slclee 3018*3ccda647Slclee if (ddi_copyout(&p64, (void *)arg, sizeof (struct partition64), flag)) 3019*3ccda647Slclee rval = EFAULT; 3020*3ccda647Slclee 3021*3ccda647Slclee done_error: 3022*3ccda647Slclee kmem_free(buffer, EFI_MIN_ARRAY_SIZE); 3023*3ccda647Slclee return (rval); 3024*3ccda647Slclee } 3025*3ccda647Slclee 3026*3ccda647Slclee 3027*3ccda647Slclee /* 3028*3ccda647Slclee * Function: cmlb_dkio_set_vtoc 3029*3ccda647Slclee * 3030*3ccda647Slclee * Description: This routine is the driver entry point for handling user 3031*3ccda647Slclee * requests to set the current volume table of contents 3032*3ccda647Slclee * (DKIOCSVTOC). 3033*3ccda647Slclee * 3034*3ccda647Slclee * Arguments: dev - the device number 3035*3ccda647Slclee * arg - pointer to user provided vtoc structure used to set the 3036*3ccda647Slclee * current vtoc. 3037*3ccda647Slclee * flag - this argument is a pass through to ddi_copyxxx() 3038*3ccda647Slclee * directly from the mode argument of ioctl(). 3039*3ccda647Slclee * 3040*3ccda647Slclee * Return Code: 0 3041*3ccda647Slclee * EFAULT 3042*3ccda647Slclee * ENXIO 3043*3ccda647Slclee * EINVAL 3044*3ccda647Slclee * ENOTSUP 3045*3ccda647Slclee */ 3046*3ccda647Slclee static int 3047*3ccda647Slclee cmlb_dkio_set_vtoc(struct cmlb_lun *un, dev_t dev, caddr_t arg, int flag) 3048*3ccda647Slclee { 3049*3ccda647Slclee struct vtoc user_vtoc; 3050*3ccda647Slclee int rval = 0; 3051*3ccda647Slclee 3052*3ccda647Slclee #ifdef _MULTI_DATAMODEL 3053*3ccda647Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 3054*3ccda647Slclee case DDI_MODEL_ILP32: { 3055*3ccda647Slclee struct vtoc32 user_vtoc32; 3056*3ccda647Slclee 3057*3ccda647Slclee if (ddi_copyin((const void *)arg, &user_vtoc32, 3058*3ccda647Slclee sizeof (struct vtoc32), flag)) { 3059*3ccda647Slclee return (EFAULT); 3060*3ccda647Slclee } 3061*3ccda647Slclee vtoc32tovtoc(user_vtoc32, user_vtoc); 3062*3ccda647Slclee break; 3063*3ccda647Slclee } 3064*3ccda647Slclee 3065*3ccda647Slclee case DDI_MODEL_NONE: 3066*3ccda647Slclee if (ddi_copyin((const void *)arg, &user_vtoc, 3067*3ccda647Slclee sizeof (struct vtoc), flag)) { 3068*3ccda647Slclee return (EFAULT); 3069*3ccda647Slclee } 3070*3ccda647Slclee break; 3071*3ccda647Slclee } 3072*3ccda647Slclee #else /* ! _MULTI_DATAMODEL */ 3073*3ccda647Slclee if (ddi_copyin((const void *)arg, &user_vtoc, 3074*3ccda647Slclee sizeof (struct vtoc), flag)) { 3075*3ccda647Slclee return (EFAULT); 3076*3ccda647Slclee } 3077*3ccda647Slclee #endif /* _MULTI_DATAMODEL */ 3078*3ccda647Slclee 3079*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 3080*3ccda647Slclee if (un->un_blockcount > DK_MAX_BLOCKS) { 3081*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 3082*3ccda647Slclee return (ENOTSUP); 3083*3ccda647Slclee } 3084*3ccda647Slclee if (un->un_g.dkg_ncyl == 0) { 3085*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 3086*3ccda647Slclee return (EINVAL); 3087*3ccda647Slclee } 3088*3ccda647Slclee 3089*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 3090*3ccda647Slclee cmlb_clear_efi(un); 3091*3ccda647Slclee ddi_remove_minor_node(CMLB_DEVINFO(un), "wd"); 3092*3ccda647Slclee ddi_remove_minor_node(CMLB_DEVINFO(un), "wd,raw"); 3093*3ccda647Slclee (void) ddi_create_minor_node(CMLB_DEVINFO(un), "h", 3094*3ccda647Slclee S_IFBLK, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 3095*3ccda647Slclee un->un_node_type, NULL); 3096*3ccda647Slclee (void) ddi_create_minor_node(CMLB_DEVINFO(un), "h,raw", 3097*3ccda647Slclee S_IFCHR, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 3098*3ccda647Slclee un->un_node_type, NULL); 3099*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 3100*3ccda647Slclee 3101*3ccda647Slclee if ((rval = cmlb_build_label_vtoc(un, &user_vtoc)) == 0) { 3102*3ccda647Slclee if ((rval = cmlb_write_label(un)) == 0) { 3103*3ccda647Slclee if (cmlb_validate_geometry(un, 1) != 0) { 3104*3ccda647Slclee cmlb_dbg(CMLB_ERROR, un, 3105*3ccda647Slclee "cmlb_dkio_set_vtoc: " 3106*3ccda647Slclee "Failed validate geometry\n"); 3107*3ccda647Slclee } 3108*3ccda647Slclee } 3109*3ccda647Slclee } 3110*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 3111*3ccda647Slclee return (rval); 3112*3ccda647Slclee } 3113*3ccda647Slclee 3114*3ccda647Slclee 3115*3ccda647Slclee /* 3116*3ccda647Slclee * Function: cmlb_build_label_vtoc 3117*3ccda647Slclee * 3118*3ccda647Slclee * Description: This routine updates the driver soft state current volume table 3119*3ccda647Slclee * of contents based on a user specified vtoc. 3120*3ccda647Slclee * 3121*3ccda647Slclee * Arguments: un - driver soft state (unit) structure 3122*3ccda647Slclee * user_vtoc - pointer to vtoc structure specifying vtoc to be used 3123*3ccda647Slclee * to update the driver soft state. 3124*3ccda647Slclee * 3125*3ccda647Slclee * Return Code: 0 3126*3ccda647Slclee * EINVAL 3127*3ccda647Slclee */ 3128*3ccda647Slclee static int 3129*3ccda647Slclee cmlb_build_label_vtoc(struct cmlb_lun *un, struct vtoc *user_vtoc) 3130*3ccda647Slclee { 3131*3ccda647Slclee struct dk_map *lmap; 3132*3ccda647Slclee struct partition *vpart; 3133*3ccda647Slclee int nblks; 3134*3ccda647Slclee #if defined(_SUNOS_VTOC_8) 3135*3ccda647Slclee int ncyl; 3136*3ccda647Slclee struct dk_map2 *lpart; 3137*3ccda647Slclee #endif /* defined(_SUNOS_VTOC_8) */ 3138*3ccda647Slclee int i; 3139*3ccda647Slclee 3140*3ccda647Slclee ASSERT(mutex_owned(CMLB_MUTEX(un))); 3141*3ccda647Slclee 3142*3ccda647Slclee /* Sanity-check the vtoc */ 3143*3ccda647Slclee if (user_vtoc->v_sanity != VTOC_SANE || 3144*3ccda647Slclee user_vtoc->v_sectorsz != un->un_sys_blocksize || 3145*3ccda647Slclee user_vtoc->v_nparts != V_NUMPAR) { 3146*3ccda647Slclee cmlb_dbg(CMLB_INFO, un, 3147*3ccda647Slclee "cmlb_build_label_vtoc: vtoc not valid\n"); 3148*3ccda647Slclee return (EINVAL); 3149*3ccda647Slclee } 3150*3ccda647Slclee 3151*3ccda647Slclee nblks = un->un_g.dkg_nsect * un->un_g.dkg_nhead; 3152*3ccda647Slclee if (nblks == 0) { 3153*3ccda647Slclee cmlb_dbg(CMLB_INFO, un, 3154*3ccda647Slclee "cmlb_build_label_vtoc: geom nblks is 0\n"); 3155*3ccda647Slclee return (EINVAL); 3156*3ccda647Slclee } 3157*3ccda647Slclee 3158*3ccda647Slclee #if defined(_SUNOS_VTOC_8) 3159*3ccda647Slclee vpart = user_vtoc->v_part; 3160*3ccda647Slclee for (i = 0; i < V_NUMPAR; i++) { 3161*3ccda647Slclee if ((vpart->p_start % nblks) != 0) { 3162*3ccda647Slclee cmlb_dbg(CMLB_INFO, un, 3163*3ccda647Slclee "cmlb_build_label_vtoc: p_start not multiply of" 3164*3ccda647Slclee "nblks part %d p_start %d nblks %d\n", i, 3165*3ccda647Slclee vpart->p_start, nblks); 3166*3ccda647Slclee return (EINVAL); 3167*3ccda647Slclee } 3168*3ccda647Slclee ncyl = vpart->p_start / nblks; 3169*3ccda647Slclee ncyl += vpart->p_size / nblks; 3170*3ccda647Slclee if ((vpart->p_size % nblks) != 0) { 3171*3ccda647Slclee ncyl++; 3172*3ccda647Slclee } 3173*3ccda647Slclee if (ncyl > (int)un->un_g.dkg_ncyl) { 3174*3ccda647Slclee cmlb_dbg(CMLB_INFO, un, 3175*3ccda647Slclee "cmlb_build_label_vtoc: ncyl %d > dkg_ncyl %d" 3176*3ccda647Slclee "p_size %ld p_start %ld nblks %d part number %d" 3177*3ccda647Slclee "tag %d\n", 3178*3ccda647Slclee ncyl, un->un_g.dkg_ncyl, vpart->p_size, 3179*3ccda647Slclee vpart->p_start, nblks, 3180*3ccda647Slclee i, vpart->p_tag); 3181*3ccda647Slclee 3182*3ccda647Slclee return (EINVAL); 3183*3ccda647Slclee } 3184*3ccda647Slclee vpart++; 3185*3ccda647Slclee } 3186*3ccda647Slclee #endif /* defined(_SUNOS_VTOC_8) */ 3187*3ccda647Slclee 3188*3ccda647Slclee /* Put appropriate vtoc structure fields into the disk label */ 3189*3ccda647Slclee #if defined(_SUNOS_VTOC_16) 3190*3ccda647Slclee /* 3191*3ccda647Slclee * The vtoc is always a 32bit data structure to maintain the 3192*3ccda647Slclee * on-disk format. Convert "in place" instead of doing bcopy. 3193*3ccda647Slclee */ 3194*3ccda647Slclee vtoctovtoc32((*user_vtoc), (*((struct vtoc32 *)&(un->un_vtoc)))); 3195*3ccda647Slclee 3196*3ccda647Slclee /* 3197*3ccda647Slclee * in the 16-slice vtoc, starting sectors are expressed in 3198*3ccda647Slclee * numbers *relative* to the start of the Solaris fdisk partition. 3199*3ccda647Slclee */ 3200*3ccda647Slclee lmap = un->un_map; 3201*3ccda647Slclee vpart = user_vtoc->v_part; 3202*3ccda647Slclee 3203*3ccda647Slclee for (i = 0; i < (int)user_vtoc->v_nparts; i++, lmap++, vpart++) { 3204*3ccda647Slclee lmap->dkl_cylno = vpart->p_start / nblks; 3205*3ccda647Slclee lmap->dkl_nblk = vpart->p_size; 3206*3ccda647Slclee } 3207*3ccda647Slclee 3208*3ccda647Slclee #elif defined(_SUNOS_VTOC_8) 3209*3ccda647Slclee 3210*3ccda647Slclee un->un_vtoc.v_bootinfo[0] = (uint32_t)user_vtoc->v_bootinfo[0]; 3211*3ccda647Slclee un->un_vtoc.v_bootinfo[1] = (uint32_t)user_vtoc->v_bootinfo[1]; 3212*3ccda647Slclee un->un_vtoc.v_bootinfo[2] = (uint32_t)user_vtoc->v_bootinfo[2]; 3213*3ccda647Slclee 3214*3ccda647Slclee un->un_vtoc.v_sanity = (uint32_t)user_vtoc->v_sanity; 3215*3ccda647Slclee un->un_vtoc.v_version = (uint32_t)user_vtoc->v_version; 3216*3ccda647Slclee 3217*3ccda647Slclee bcopy(user_vtoc->v_volume, un->un_vtoc.v_volume, LEN_DKL_VVOL); 3218*3ccda647Slclee 3219*3ccda647Slclee un->un_vtoc.v_nparts = user_vtoc->v_nparts; 3220*3ccda647Slclee 3221*3ccda647Slclee for (i = 0; i < 10; i++) 3222*3ccda647Slclee un->un_vtoc.v_reserved[i] = user_vtoc->v_reserved[i]; 3223*3ccda647Slclee 3224*3ccda647Slclee /* 3225*3ccda647Slclee * Note the conversion from starting sector number 3226*3ccda647Slclee * to starting cylinder number. 3227*3ccda647Slclee * Return error if division results in a remainder. 3228*3ccda647Slclee */ 3229*3ccda647Slclee lmap = un->un_map; 3230*3ccda647Slclee lpart = un->un_vtoc.v_part; 3231*3ccda647Slclee vpart = user_vtoc->v_part; 3232*3ccda647Slclee 3233*3ccda647Slclee for (i = 0; i < (int)user_vtoc->v_nparts; i++) { 3234*3ccda647Slclee lpart->p_tag = vpart->p_tag; 3235*3ccda647Slclee lpart->p_flag = vpart->p_flag; 3236*3ccda647Slclee lmap->dkl_cylno = vpart->p_start / nblks; 3237*3ccda647Slclee lmap->dkl_nblk = vpart->p_size; 3238*3ccda647Slclee 3239*3ccda647Slclee lmap++; 3240*3ccda647Slclee lpart++; 3241*3ccda647Slclee vpart++; 3242*3ccda647Slclee 3243*3ccda647Slclee /* (4387723) */ 3244*3ccda647Slclee #ifdef _LP64 3245*3ccda647Slclee if (user_vtoc->timestamp[i] > TIME32_MAX) { 3246*3ccda647Slclee un->un_vtoc.v_timestamp[i] = TIME32_MAX; 3247*3ccda647Slclee } else { 3248*3ccda647Slclee un->un_vtoc.v_timestamp[i] = user_vtoc->timestamp[i]; 3249*3ccda647Slclee } 3250*3ccda647Slclee #else 3251*3ccda647Slclee un->un_vtoc.v_timestamp[i] = user_vtoc->timestamp[i]; 3252*3ccda647Slclee #endif 3253*3ccda647Slclee } 3254*3ccda647Slclee 3255*3ccda647Slclee bcopy(user_vtoc->v_asciilabel, un->un_asciilabel, LEN_DKL_ASCII); 3256*3ccda647Slclee #else 3257*3ccda647Slclee #error "No VTOC format defined." 3258*3ccda647Slclee #endif 3259*3ccda647Slclee return (0); 3260*3ccda647Slclee } 3261*3ccda647Slclee 3262*3ccda647Slclee /* 3263*3ccda647Slclee * Function: cmlb_clear_efi 3264*3ccda647Slclee * 3265*3ccda647Slclee * Description: This routine clears all EFI labels. 3266*3ccda647Slclee * 3267*3ccda647Slclee * Arguments: un - driver soft state (unit) structure 3268*3ccda647Slclee * 3269*3ccda647Slclee * Return Code: void 3270*3ccda647Slclee */ 3271*3ccda647Slclee static void 3272*3ccda647Slclee cmlb_clear_efi(struct cmlb_lun *un) 3273*3ccda647Slclee { 3274*3ccda647Slclee efi_gpt_t *gpt; 3275*3ccda647Slclee diskaddr_t cap; 3276*3ccda647Slclee int rval; 3277*3ccda647Slclee 3278*3ccda647Slclee ASSERT(!mutex_owned(CMLB_MUTEX(un))); 3279*3ccda647Slclee 3280*3ccda647Slclee gpt = kmem_alloc(sizeof (efi_gpt_t), KM_SLEEP); 3281*3ccda647Slclee 3282*3ccda647Slclee if (DK_TG_READ(un, gpt, 1, DEV_BSIZE) != 0) { 3283*3ccda647Slclee goto done; 3284*3ccda647Slclee } 3285*3ccda647Slclee 3286*3ccda647Slclee cmlb_swap_efi_gpt(gpt); 3287*3ccda647Slclee rval = cmlb_validate_efi(gpt); 3288*3ccda647Slclee if (rval == 0) { 3289*3ccda647Slclee /* clear primary */ 3290*3ccda647Slclee bzero(gpt, sizeof (efi_gpt_t)); 3291*3ccda647Slclee if (rval = DK_TG_WRITE(un, gpt, 1, EFI_LABEL_SIZE)) { 3292*3ccda647Slclee cmlb_dbg(CMLB_INFO, un, 3293*3ccda647Slclee "cmlb_clear_efi: clear primary label failed\n"); 3294*3ccda647Slclee } 3295*3ccda647Slclee } 3296*3ccda647Slclee /* the backup */ 3297*3ccda647Slclee rval = DK_TG_GETCAP(un, &cap); 3298*3ccda647Slclee if (rval) { 3299*3ccda647Slclee goto done; 3300*3ccda647Slclee } 3301*3ccda647Slclee 3302*3ccda647Slclee if ((rval = DK_TG_READ(un, gpt, cap - 1, EFI_LABEL_SIZE)) != 0) { 3303*3ccda647Slclee goto done; 3304*3ccda647Slclee } 3305*3ccda647Slclee cmlb_swap_efi_gpt(gpt); 3306*3ccda647Slclee rval = cmlb_validate_efi(gpt); 3307*3ccda647Slclee if (rval == 0) { 3308*3ccda647Slclee /* clear backup */ 3309*3ccda647Slclee cmlb_dbg(CMLB_TRACE, un, 3310*3ccda647Slclee "cmlb_clear_efi clear backup@%lu\n", cap - 1); 3311*3ccda647Slclee bzero(gpt, sizeof (efi_gpt_t)); 3312*3ccda647Slclee if ((rval = DK_TG_WRITE(un, gpt, cap - 1, EFI_LABEL_SIZE))) { 3313*3ccda647Slclee cmlb_dbg(CMLB_INFO, un, 3314*3ccda647Slclee "cmlb_clear_efi: clear backup label failed\n"); 3315*3ccda647Slclee } 3316*3ccda647Slclee } 3317*3ccda647Slclee 3318*3ccda647Slclee done: 3319*3ccda647Slclee kmem_free(gpt, sizeof (efi_gpt_t)); 3320*3ccda647Slclee } 3321*3ccda647Slclee 3322*3ccda647Slclee /* 3323*3ccda647Slclee * Function: cmlb_set_vtoc 3324*3ccda647Slclee * 3325*3ccda647Slclee * Description: This routine writes data to the appropriate positions 3326*3ccda647Slclee * 3327*3ccda647Slclee * Arguments: un - driver soft state (unit) structure 3328*3ccda647Slclee * dkl - the data to be written 3329*3ccda647Slclee * 3330*3ccda647Slclee * Return: void 3331*3ccda647Slclee */ 3332*3ccda647Slclee static int 3333*3ccda647Slclee cmlb_set_vtoc(struct cmlb_lun *un, struct dk_label *dkl) 3334*3ccda647Slclee { 3335*3ccda647Slclee uint_t label_addr; 3336*3ccda647Slclee int sec; 3337*3ccda647Slclee int blk; 3338*3ccda647Slclee int head; 3339*3ccda647Slclee int cyl; 3340*3ccda647Slclee int rval; 3341*3ccda647Slclee 3342*3ccda647Slclee #if defined(__i386) || defined(__amd64) 3343*3ccda647Slclee label_addr = un->un_solaris_offset + DK_LABEL_LOC; 3344*3ccda647Slclee #else 3345*3ccda647Slclee /* Write the primary label at block 0 of the solaris partition. */ 3346*3ccda647Slclee label_addr = 0; 3347*3ccda647Slclee #endif 3348*3ccda647Slclee 3349*3ccda647Slclee rval = DK_TG_WRITE(un, dkl, label_addr, un->un_sys_blocksize); 3350*3ccda647Slclee 3351*3ccda647Slclee if (rval != 0) { 3352*3ccda647Slclee return (rval); 3353*3ccda647Slclee } 3354*3ccda647Slclee 3355*3ccda647Slclee /* 3356*3ccda647Slclee * Calculate where the backup labels go. They are always on 3357*3ccda647Slclee * the last alternate cylinder, but some older drives put them 3358*3ccda647Slclee * on head 2 instead of the last head. They are always on the 3359*3ccda647Slclee * first 5 odd sectors of the appropriate track. 3360*3ccda647Slclee * 3361*3ccda647Slclee * We have no choice at this point, but to believe that the 3362*3ccda647Slclee * disk label is valid. Use the geometry of the disk 3363*3ccda647Slclee * as described in the label. 3364*3ccda647Slclee */ 3365*3ccda647Slclee cyl = dkl->dkl_ncyl + dkl->dkl_acyl - 1; 3366*3ccda647Slclee head = dkl->dkl_nhead - 1; 3367*3ccda647Slclee 3368*3ccda647Slclee /* 3369*3ccda647Slclee * Write and verify the backup labels. Make sure we don't try to 3370*3ccda647Slclee * write past the last cylinder. 3371*3ccda647Slclee */ 3372*3ccda647Slclee for (sec = 1; ((sec < 5 * 2 + 1) && (sec < dkl->dkl_nsect)); sec += 2) { 3373*3ccda647Slclee blk = (daddr_t)( 3374*3ccda647Slclee (cyl * ((dkl->dkl_nhead * dkl->dkl_nsect) - dkl->dkl_apc)) + 3375*3ccda647Slclee (head * dkl->dkl_nsect) + sec); 3376*3ccda647Slclee #if defined(__i386) || defined(__amd64) 3377*3ccda647Slclee blk += un->un_solaris_offset; 3378*3ccda647Slclee #endif 3379*3ccda647Slclee rval = DK_TG_WRITE(un, dkl, blk, un->un_sys_blocksize); 3380*3ccda647Slclee cmlb_dbg(CMLB_INFO, un, 3381*3ccda647Slclee "cmlb_set_vtoc: wrote backup label %d\n", blk); 3382*3ccda647Slclee if (rval != 0) { 3383*3ccda647Slclee goto exit; 3384*3ccda647Slclee } 3385*3ccda647Slclee } 3386*3ccda647Slclee exit: 3387*3ccda647Slclee return (rval); 3388*3ccda647Slclee } 3389*3ccda647Slclee 3390*3ccda647Slclee /* 3391*3ccda647Slclee * Function: cmlb_clear_vtoc 3392*3ccda647Slclee * 3393*3ccda647Slclee * Description: This routine clears out the VTOC labels. 3394*3ccda647Slclee * 3395*3ccda647Slclee * Arguments: un - driver soft state (unit) structure 3396*3ccda647Slclee * 3397*3ccda647Slclee * Return: void 3398*3ccda647Slclee */ 3399*3ccda647Slclee static void 3400*3ccda647Slclee cmlb_clear_vtoc(struct cmlb_lun *un) 3401*3ccda647Slclee { 3402*3ccda647Slclee struct dk_label *dkl; 3403*3ccda647Slclee 3404*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 3405*3ccda647Slclee dkl = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP); 3406*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 3407*3ccda647Slclee /* 3408*3ccda647Slclee * cmlb_set_vtoc uses these fields in order to figure out 3409*3ccda647Slclee * where to overwrite the backup labels 3410*3ccda647Slclee */ 3411*3ccda647Slclee dkl->dkl_apc = un->un_g.dkg_apc; 3412*3ccda647Slclee dkl->dkl_ncyl = un->un_g.dkg_ncyl; 3413*3ccda647Slclee dkl->dkl_acyl = un->un_g.dkg_acyl; 3414*3ccda647Slclee dkl->dkl_nhead = un->un_g.dkg_nhead; 3415*3ccda647Slclee dkl->dkl_nsect = un->un_g.dkg_nsect; 3416*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 3417*3ccda647Slclee (void) cmlb_set_vtoc(un, dkl); 3418*3ccda647Slclee kmem_free(dkl, sizeof (struct dk_label)); 3419*3ccda647Slclee 3420*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 3421*3ccda647Slclee } 3422*3ccda647Slclee 3423*3ccda647Slclee /* 3424*3ccda647Slclee * Function: cmlb_write_label 3425*3ccda647Slclee * 3426*3ccda647Slclee * Description: This routine will validate and write the driver soft state vtoc 3427*3ccda647Slclee * contents to the device. 3428*3ccda647Slclee * 3429*3ccda647Slclee * Arguments: un cmlb handle 3430*3ccda647Slclee * 3431*3ccda647Slclee * Return Code: the code returned by cmlb_send_scsi_cmd() 3432*3ccda647Slclee * 0 3433*3ccda647Slclee * EINVAL 3434*3ccda647Slclee * ENXIO 3435*3ccda647Slclee * ENOMEM 3436*3ccda647Slclee */ 3437*3ccda647Slclee static int 3438*3ccda647Slclee cmlb_write_label(struct cmlb_lun *un) 3439*3ccda647Slclee { 3440*3ccda647Slclee struct dk_label *dkl; 3441*3ccda647Slclee short sum; 3442*3ccda647Slclee short *sp; 3443*3ccda647Slclee int i; 3444*3ccda647Slclee int rval; 3445*3ccda647Slclee 3446*3ccda647Slclee ASSERT(mutex_owned(CMLB_MUTEX(un))); 3447*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 3448*3ccda647Slclee dkl = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP); 3449*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 3450*3ccda647Slclee 3451*3ccda647Slclee bcopy(&un->un_vtoc, &dkl->dkl_vtoc, sizeof (struct dk_vtoc)); 3452*3ccda647Slclee dkl->dkl_rpm = un->un_g.dkg_rpm; 3453*3ccda647Slclee dkl->dkl_pcyl = un->un_g.dkg_pcyl; 3454*3ccda647Slclee dkl->dkl_apc = un->un_g.dkg_apc; 3455*3ccda647Slclee dkl->dkl_intrlv = un->un_g.dkg_intrlv; 3456*3ccda647Slclee dkl->dkl_ncyl = un->un_g.dkg_ncyl; 3457*3ccda647Slclee dkl->dkl_acyl = un->un_g.dkg_acyl; 3458*3ccda647Slclee dkl->dkl_nhead = un->un_g.dkg_nhead; 3459*3ccda647Slclee dkl->dkl_nsect = un->un_g.dkg_nsect; 3460*3ccda647Slclee 3461*3ccda647Slclee #if defined(_SUNOS_VTOC_8) 3462*3ccda647Slclee dkl->dkl_obs1 = un->un_g.dkg_obs1; 3463*3ccda647Slclee dkl->dkl_obs2 = un->un_g.dkg_obs2; 3464*3ccda647Slclee dkl->dkl_obs3 = un->un_g.dkg_obs3; 3465*3ccda647Slclee for (i = 0; i < NDKMAP; i++) { 3466*3ccda647Slclee dkl->dkl_map[i].dkl_cylno = un->un_map[i].dkl_cylno; 3467*3ccda647Slclee dkl->dkl_map[i].dkl_nblk = un->un_map[i].dkl_nblk; 3468*3ccda647Slclee } 3469*3ccda647Slclee bcopy(un->un_asciilabel, dkl->dkl_asciilabel, LEN_DKL_ASCII); 3470*3ccda647Slclee #elif defined(_SUNOS_VTOC_16) 3471*3ccda647Slclee dkl->dkl_skew = un->un_dkg_skew; 3472*3ccda647Slclee #else 3473*3ccda647Slclee #error "No VTOC format defined." 3474*3ccda647Slclee #endif 3475*3ccda647Slclee 3476*3ccda647Slclee dkl->dkl_magic = DKL_MAGIC; 3477*3ccda647Slclee dkl->dkl_write_reinstruct = un->un_g.dkg_write_reinstruct; 3478*3ccda647Slclee dkl->dkl_read_reinstruct = un->un_g.dkg_read_reinstruct; 3479*3ccda647Slclee 3480*3ccda647Slclee /* Construct checksum for the new disk label */ 3481*3ccda647Slclee sum = 0; 3482*3ccda647Slclee sp = (short *)dkl; 3483*3ccda647Slclee i = sizeof (struct dk_label) / sizeof (short); 3484*3ccda647Slclee while (i--) { 3485*3ccda647Slclee sum ^= *sp++; 3486*3ccda647Slclee } 3487*3ccda647Slclee dkl->dkl_cksum = sum; 3488*3ccda647Slclee 3489*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 3490*3ccda647Slclee 3491*3ccda647Slclee rval = cmlb_set_vtoc(un, dkl); 3492*3ccda647Slclee exit: 3493*3ccda647Slclee kmem_free(dkl, sizeof (struct dk_label)); 3494*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 3495*3ccda647Slclee return (rval); 3496*3ccda647Slclee } 3497*3ccda647Slclee 3498*3ccda647Slclee static int 3499*3ccda647Slclee cmlb_dkio_set_efi(struct cmlb_lun *un, dev_t dev, caddr_t arg, int flag) 3500*3ccda647Slclee { 3501*3ccda647Slclee dk_efi_t user_efi; 3502*3ccda647Slclee int rval = 0; 3503*3ccda647Slclee void *buffer; 3504*3ccda647Slclee 3505*3ccda647Slclee if (ddi_copyin(arg, &user_efi, sizeof (dk_efi_t), flag)) 3506*3ccda647Slclee return (EFAULT); 3507*3ccda647Slclee 3508*3ccda647Slclee user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64; 3509*3ccda647Slclee 3510*3ccda647Slclee buffer = kmem_alloc(user_efi.dki_length, KM_SLEEP); 3511*3ccda647Slclee if (ddi_copyin(user_efi.dki_data, buffer, user_efi.dki_length, flag)) { 3512*3ccda647Slclee rval = EFAULT; 3513*3ccda647Slclee } else { 3514*3ccda647Slclee /* 3515*3ccda647Slclee * let's clear the vtoc labels and clear the softstate 3516*3ccda647Slclee * vtoc. 3517*3ccda647Slclee */ 3518*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 3519*3ccda647Slclee if (un->un_vtoc.v_sanity == VTOC_SANE) { 3520*3ccda647Slclee cmlb_dbg(CMLB_TRACE, un, 3521*3ccda647Slclee "cmlb_dkio_set_efi: CLEAR VTOC\n"); 3522*3ccda647Slclee if (un->un_vtoc_label_is_from_media) 3523*3ccda647Slclee cmlb_clear_vtoc(un); 3524*3ccda647Slclee bzero(&un->un_vtoc, sizeof (struct dk_vtoc)); 3525*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 3526*3ccda647Slclee ddi_remove_minor_node(CMLB_DEVINFO(un), "h"); 3527*3ccda647Slclee ddi_remove_minor_node(CMLB_DEVINFO(un), "h,raw"); 3528*3ccda647Slclee (void) ddi_create_minor_node(CMLB_DEVINFO(un), "wd", 3529*3ccda647Slclee S_IFBLK, 3530*3ccda647Slclee (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 3531*3ccda647Slclee un->un_node_type, NULL); 3532*3ccda647Slclee (void) ddi_create_minor_node(CMLB_DEVINFO(un), "wd,raw", 3533*3ccda647Slclee S_IFCHR, 3534*3ccda647Slclee (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 3535*3ccda647Slclee un->un_node_type, NULL); 3536*3ccda647Slclee } else 3537*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 3538*3ccda647Slclee rval = DK_TG_WRITE(un, buffer, user_efi.dki_lba, 3539*3ccda647Slclee user_efi.dki_length); 3540*3ccda647Slclee if (rval == 0) { 3541*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 3542*3ccda647Slclee un->un_f_geometry_is_valid = FALSE; 3543*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 3544*3ccda647Slclee } 3545*3ccda647Slclee } 3546*3ccda647Slclee kmem_free(buffer, user_efi.dki_length); 3547*3ccda647Slclee return (rval); 3548*3ccda647Slclee } 3549*3ccda647Slclee 3550*3ccda647Slclee /* 3551*3ccda647Slclee * Function: cmlb_dkio_get_mboot 3552*3ccda647Slclee * 3553*3ccda647Slclee * Description: This routine is the driver entry point for handling user 3554*3ccda647Slclee * requests to get the current device mboot (DKIOCGMBOOT) 3555*3ccda647Slclee * 3556*3ccda647Slclee * Arguments: 3557*3ccda647Slclee * arg - pointer to user provided mboot structure specifying 3558*3ccda647Slclee * the current mboot. 3559*3ccda647Slclee * flag - this argument is a pass through to ddi_copyxxx() 3560*3ccda647Slclee * directly from the mode argument of ioctl(). 3561*3ccda647Slclee * 3562*3ccda647Slclee * Return Code: 0 3563*3ccda647Slclee * EINVAL 3564*3ccda647Slclee * EFAULT 3565*3ccda647Slclee * ENXIO 3566*3ccda647Slclee */ 3567*3ccda647Slclee static int 3568*3ccda647Slclee cmlb_dkio_get_mboot(struct cmlb_lun *un, caddr_t arg, int flag) 3569*3ccda647Slclee { 3570*3ccda647Slclee struct mboot *mboot; 3571*3ccda647Slclee int rval; 3572*3ccda647Slclee size_t buffer_size; 3573*3ccda647Slclee 3574*3ccda647Slclee 3575*3ccda647Slclee #if defined(_SUNOS_VTOC_8) 3576*3ccda647Slclee if ((!ISREMOVABLE(un)) || (arg == NULL)) { 3577*3ccda647Slclee #elif defined(_SUNOS_VTOC_16) 3578*3ccda647Slclee if (arg == NULL) { 3579*3ccda647Slclee #endif 3580*3ccda647Slclee return (EINVAL); 3581*3ccda647Slclee } 3582*3ccda647Slclee 3583*3ccda647Slclee /* 3584*3ccda647Slclee * Read the mboot block, located at absolute block 0 on the target. 3585*3ccda647Slclee */ 3586*3ccda647Slclee buffer_size = sizeof (struct mboot); 3587*3ccda647Slclee 3588*3ccda647Slclee cmlb_dbg(CMLB_TRACE, un, 3589*3ccda647Slclee "cmlb_dkio_get_mboot: allocation size: 0x%x\n", buffer_size); 3590*3ccda647Slclee 3591*3ccda647Slclee mboot = kmem_zalloc(buffer_size, KM_SLEEP); 3592*3ccda647Slclee if ((rval = DK_TG_READ(un, mboot, 0, buffer_size)) == 0) { 3593*3ccda647Slclee if (ddi_copyout(mboot, (void *)arg, 3594*3ccda647Slclee sizeof (struct mboot), flag) != 0) { 3595*3ccda647Slclee rval = EFAULT; 3596*3ccda647Slclee } 3597*3ccda647Slclee } 3598*3ccda647Slclee kmem_free(mboot, buffer_size); 3599*3ccda647Slclee return (rval); 3600*3ccda647Slclee } 3601*3ccda647Slclee 3602*3ccda647Slclee 3603*3ccda647Slclee /* 3604*3ccda647Slclee * Function: cmlb_dkio_set_mboot 3605*3ccda647Slclee * 3606*3ccda647Slclee * Description: This routine is the driver entry point for handling user 3607*3ccda647Slclee * requests to validate and set the device master boot 3608*3ccda647Slclee * (DKIOCSMBOOT). 3609*3ccda647Slclee * 3610*3ccda647Slclee * Arguments: 3611*3ccda647Slclee * arg - pointer to user provided mboot structure used to set the 3612*3ccda647Slclee * master boot. 3613*3ccda647Slclee * flag - this argument is a pass through to ddi_copyxxx() 3614*3ccda647Slclee * directly from the mode argument of ioctl(). 3615*3ccda647Slclee * 3616*3ccda647Slclee * Return Code: 0 3617*3ccda647Slclee * EINVAL 3618*3ccda647Slclee * EFAULT 3619*3ccda647Slclee * ENXIO 3620*3ccda647Slclee */ 3621*3ccda647Slclee static int 3622*3ccda647Slclee cmlb_dkio_set_mboot(struct cmlb_lun *un, caddr_t arg, int flag) 3623*3ccda647Slclee { 3624*3ccda647Slclee struct mboot *mboot = NULL; 3625*3ccda647Slclee int rval; 3626*3ccda647Slclee ushort_t magic; 3627*3ccda647Slclee 3628*3ccda647Slclee 3629*3ccda647Slclee ASSERT(!mutex_owned(CMLB_MUTEX(un))); 3630*3ccda647Slclee 3631*3ccda647Slclee #if defined(_SUNOS_VTOC_8) 3632*3ccda647Slclee if (!ISREMOVABLE(un)) { 3633*3ccda647Slclee return (EINVAL); 3634*3ccda647Slclee } 3635*3ccda647Slclee #endif 3636*3ccda647Slclee 3637*3ccda647Slclee if (arg == NULL) { 3638*3ccda647Slclee return (EINVAL); 3639*3ccda647Slclee } 3640*3ccda647Slclee 3641*3ccda647Slclee mboot = kmem_zalloc(sizeof (struct mboot), KM_SLEEP); 3642*3ccda647Slclee 3643*3ccda647Slclee if (ddi_copyin((const void *)arg, mboot, 3644*3ccda647Slclee sizeof (struct mboot), flag) != 0) { 3645*3ccda647Slclee kmem_free(mboot, (size_t)(sizeof (struct mboot))); 3646*3ccda647Slclee return (EFAULT); 3647*3ccda647Slclee } 3648*3ccda647Slclee 3649*3ccda647Slclee /* Is this really a master boot record? */ 3650*3ccda647Slclee magic = LE_16(mboot->signature); 3651*3ccda647Slclee if (magic != MBB_MAGIC) { 3652*3ccda647Slclee kmem_free(mboot, (size_t)(sizeof (struct mboot))); 3653*3ccda647Slclee return (EINVAL); 3654*3ccda647Slclee } 3655*3ccda647Slclee 3656*3ccda647Slclee rval = DK_TG_WRITE(un, mboot, 0, un->un_sys_blocksize); 3657*3ccda647Slclee 3658*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 3659*3ccda647Slclee #if defined(__i386) || defined(__amd64) 3660*3ccda647Slclee if (rval == 0) { 3661*3ccda647Slclee /* 3662*3ccda647Slclee * mboot has been written successfully. 3663*3ccda647Slclee * update the fdisk and vtoc tables in memory 3664*3ccda647Slclee */ 3665*3ccda647Slclee rval = cmlb_update_fdisk_and_vtoc(un); 3666*3ccda647Slclee if ((un->un_f_geometry_is_valid == FALSE) || (rval != 0)) { 3667*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 3668*3ccda647Slclee kmem_free(mboot, (size_t)(sizeof (struct mboot))); 3669*3ccda647Slclee return (rval); 3670*3ccda647Slclee } 3671*3ccda647Slclee } 3672*3ccda647Slclee #else 3673*3ccda647Slclee if (rval == 0) { 3674*3ccda647Slclee /* 3675*3ccda647Slclee * mboot has been written successfully. 3676*3ccda647Slclee * set up the default geometry and VTOC 3677*3ccda647Slclee */ 3678*3ccda647Slclee if (un->un_blockcount <= DK_MAX_BLOCKS) 3679*3ccda647Slclee cmlb_setup_default_geometry(un); 3680*3ccda647Slclee } 3681*3ccda647Slclee #endif 3682*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 3683*3ccda647Slclee kmem_free(mboot, (size_t)(sizeof (struct mboot))); 3684*3ccda647Slclee return (rval); 3685*3ccda647Slclee } 3686*3ccda647Slclee 3687*3ccda647Slclee 3688*3ccda647Slclee /* 3689*3ccda647Slclee * Function: cmlb_setup_default_geometry 3690*3ccda647Slclee * 3691*3ccda647Slclee * Description: This local utility routine sets the default geometry as part of 3692*3ccda647Slclee * setting the device mboot. 3693*3ccda647Slclee * 3694*3ccda647Slclee * Arguments: un - driver soft state (unit) structure 3695*3ccda647Slclee * 3696*3ccda647Slclee * Note: This may be redundant with cmlb_build_default_label. 3697*3ccda647Slclee */ 3698*3ccda647Slclee static void 3699*3ccda647Slclee cmlb_setup_default_geometry(struct cmlb_lun *un) 3700*3ccda647Slclee { 3701*3ccda647Slclee struct cmlb_geom pgeom; 3702*3ccda647Slclee struct cmlb_geom *pgeomp = &pgeom; 3703*3ccda647Slclee int ret; 3704*3ccda647Slclee int geom_base_cap = 1; 3705*3ccda647Slclee 3706*3ccda647Slclee 3707*3ccda647Slclee ASSERT(mutex_owned(CMLB_MUTEX(un))); 3708*3ccda647Slclee 3709*3ccda647Slclee /* zero out the soft state geometry and partition table. */ 3710*3ccda647Slclee bzero(&un->un_g, sizeof (struct dk_geom)); 3711*3ccda647Slclee bzero(&un->un_vtoc, sizeof (struct dk_vtoc)); 3712*3ccda647Slclee bzero(un->un_map, NDKMAP * (sizeof (struct dk_map))); 3713*3ccda647Slclee 3714*3ccda647Slclee /* 3715*3ccda647Slclee * For the rpm, we use the minimum for the disk. 3716*3ccda647Slclee * For the head, cyl and number of sector per track, 3717*3ccda647Slclee * if the capacity <= 1GB, head = 64, sect = 32. 3718*3ccda647Slclee * else head = 255, sect 63 3719*3ccda647Slclee * Note: the capacity should be equal to C*H*S values. 3720*3ccda647Slclee * This will cause some truncation of size due to 3721*3ccda647Slclee * round off errors. For CD-ROMs, this truncation can 3722*3ccda647Slclee * have adverse side effects, so returning ncyl and 3723*3ccda647Slclee * nhead as 1. The nsect will overflow for most of 3724*3ccda647Slclee * CD-ROMs as nsect is of type ushort. 3725*3ccda647Slclee */ 3726*3ccda647Slclee if (un->un_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8) { 3727*3ccda647Slclee /* 3728*3ccda647Slclee * newfs currently can not handle 255 ntracks for SPARC 3729*3ccda647Slclee * so get the geometry from target driver instead of coming up 3730*3ccda647Slclee * with one based on capacity. 3731*3ccda647Slclee */ 3732*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 3733*3ccda647Slclee ret = DK_TG_GETPHYGEOM(un, pgeomp); 3734*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 3735*3ccda647Slclee 3736*3ccda647Slclee if (ret == 0) { 3737*3ccda647Slclee geom_base_cap = 0; 3738*3ccda647Slclee } else { 3739*3ccda647Slclee cmlb_dbg(CMLB_ERROR, un, 3740*3ccda647Slclee "cmlb_setup_default_geometry: " 3741*3ccda647Slclee "tg_getphygeom failed %d\n", ret); 3742*3ccda647Slclee 3743*3ccda647Slclee /* do default setting, geometry based on capacity */ 3744*3ccda647Slclee } 3745*3ccda647Slclee } 3746*3ccda647Slclee 3747*3ccda647Slclee if (geom_base_cap) { 3748*3ccda647Slclee if (ISCD(un)) { 3749*3ccda647Slclee un->un_g.dkg_ncyl = 1; 3750*3ccda647Slclee un->un_g.dkg_nhead = 1; 3751*3ccda647Slclee un->un_g.dkg_nsect = un->un_blockcount; 3752*3ccda647Slclee } else if (un->un_blockcount <= 0x1000) { 3753*3ccda647Slclee /* Needed for unlabeled SCSI floppies. */ 3754*3ccda647Slclee un->un_g.dkg_nhead = 2; 3755*3ccda647Slclee un->un_g.dkg_ncyl = 80; 3756*3ccda647Slclee un->un_g.dkg_pcyl = 80; 3757*3ccda647Slclee un->un_g.dkg_nsect = un->un_blockcount / (2 * 80); 3758*3ccda647Slclee } else if (un->un_blockcount <= 0x200000) { 3759*3ccda647Slclee un->un_g.dkg_nhead = 64; 3760*3ccda647Slclee un->un_g.dkg_nsect = 32; 3761*3ccda647Slclee un->un_g.dkg_ncyl = un->un_blockcount / (64 * 32); 3762*3ccda647Slclee } else { 3763*3ccda647Slclee un->un_g.dkg_nhead = 255; 3764*3ccda647Slclee un->un_g.dkg_nsect = 63; 3765*3ccda647Slclee un->un_g.dkg_ncyl = un->un_blockcount / (255 * 63); 3766*3ccda647Slclee } 3767*3ccda647Slclee 3768*3ccda647Slclee un->un_g.dkg_acyl = 0; 3769*3ccda647Slclee un->un_g.dkg_bcyl = 0; 3770*3ccda647Slclee un->un_g.dkg_intrlv = 1; 3771*3ccda647Slclee un->un_g.dkg_rpm = 200; 3772*3ccda647Slclee if (un->un_g.dkg_pcyl == 0) 3773*3ccda647Slclee un->un_g.dkg_pcyl = un->un_g.dkg_ncyl + 3774*3ccda647Slclee un->un_g.dkg_acyl; 3775*3ccda647Slclee } else { 3776*3ccda647Slclee un->un_g.dkg_ncyl = (short)pgeomp->g_ncyl; 3777*3ccda647Slclee un->un_g.dkg_acyl = pgeomp->g_acyl; 3778*3ccda647Slclee un->un_g.dkg_nhead = pgeomp->g_nhead; 3779*3ccda647Slclee un->un_g.dkg_nsect = pgeomp->g_nsect; 3780*3ccda647Slclee un->un_g.dkg_intrlv = pgeomp->g_intrlv; 3781*3ccda647Slclee un->un_g.dkg_rpm = pgeomp->g_rpm; 3782*3ccda647Slclee un->un_g.dkg_pcyl = un->un_g.dkg_ncyl + un->un_g.dkg_acyl; 3783*3ccda647Slclee } 3784*3ccda647Slclee 3785*3ccda647Slclee un->un_g.dkg_read_reinstruct = 0; 3786*3ccda647Slclee un->un_g.dkg_write_reinstruct = 0; 3787*3ccda647Slclee un->un_solaris_size = un->un_g.dkg_ncyl * 3788*3ccda647Slclee un->un_g.dkg_nhead * un->un_g.dkg_nsect; 3789*3ccda647Slclee 3790*3ccda647Slclee un->un_map['a'-'a'].dkl_cylno = 0; 3791*3ccda647Slclee un->un_map['a'-'a'].dkl_nblk = un->un_solaris_size; 3792*3ccda647Slclee 3793*3ccda647Slclee un->un_map['c'-'a'].dkl_cylno = 0; 3794*3ccda647Slclee un->un_map['c'-'a'].dkl_nblk = un->un_solaris_size; 3795*3ccda647Slclee 3796*3ccda647Slclee un->un_vtoc.v_part[2].p_tag = V_BACKUP; 3797*3ccda647Slclee un->un_vtoc.v_part[2].p_flag = V_UNMNT; 3798*3ccda647Slclee un->un_vtoc.v_nparts = V_NUMPAR; 3799*3ccda647Slclee un->un_vtoc.v_version = V_VERSION; 3800*3ccda647Slclee (void) sprintf((char *)un->un_asciilabel, "DEFAULT cyl %d alt %d" 3801*3ccda647Slclee " hd %d sec %d", un->un_g.dkg_ncyl, un->un_g.dkg_acyl, 3802*3ccda647Slclee un->un_g.dkg_nhead, un->un_g.dkg_nsect); 3803*3ccda647Slclee 3804*3ccda647Slclee un->un_f_geometry_is_valid = FALSE; 3805*3ccda647Slclee } 3806*3ccda647Slclee 3807*3ccda647Slclee 3808*3ccda647Slclee #if defined(__i386) || defined(__amd64) 3809*3ccda647Slclee /* 3810*3ccda647Slclee * Function: cmlb_update_fdisk_and_vtoc 3811*3ccda647Slclee * 3812*3ccda647Slclee * Description: This local utility routine updates the device fdisk and vtoc 3813*3ccda647Slclee * as part of setting the device mboot. 3814*3ccda647Slclee * 3815*3ccda647Slclee * Arguments: un - driver soft state (unit) structure 3816*3ccda647Slclee * 3817*3ccda647Slclee * Return Code: 0 for success or errno-type return code. 3818*3ccda647Slclee * 3819*3ccda647Slclee * Note:x86: This looks like a duplicate of cmlb_validate_geometry(), but 3820*3ccda647Slclee * these did exist separately in x86 sd.c. 3821*3ccda647Slclee */ 3822*3ccda647Slclee static int 3823*3ccda647Slclee cmlb_update_fdisk_and_vtoc(struct cmlb_lun *un) 3824*3ccda647Slclee { 3825*3ccda647Slclee int count; 3826*3ccda647Slclee int label_rc = 0; 3827*3ccda647Slclee int fdisk_rval; 3828*3ccda647Slclee diskaddr_t capacity; 3829*3ccda647Slclee 3830*3ccda647Slclee ASSERT(mutex_owned(CMLB_MUTEX(un))); 3831*3ccda647Slclee 3832*3ccda647Slclee if (cmlb_check_update_blockcount(un) != 0) 3833*3ccda647Slclee return (EINVAL); 3834*3ccda647Slclee 3835*3ccda647Slclee #if defined(_SUNOS_VTOC_16) 3836*3ccda647Slclee /* 3837*3ccda647Slclee * Set up the "whole disk" fdisk partition; this should always 3838*3ccda647Slclee * exist, regardless of whether the disk contains an fdisk table 3839*3ccda647Slclee * or vtoc. 3840*3ccda647Slclee */ 3841*3ccda647Slclee un->un_map[P0_RAW_DISK].dkl_cylno = 0; 3842*3ccda647Slclee un->un_map[P0_RAW_DISK].dkl_nblk = un->un_blockcount; 3843*3ccda647Slclee #endif /* defined(_SUNOS_VTOC_16) */ 3844*3ccda647Slclee 3845*3ccda647Slclee /* 3846*3ccda647Slclee * copy the lbasize and capacity so that if they're 3847*3ccda647Slclee * reset while we're not holding the CMLB_MUTEX(un), we will 3848*3ccda647Slclee * continue to use valid values after the CMLB_MUTEX(un) is 3849*3ccda647Slclee * reacquired. 3850*3ccda647Slclee */ 3851*3ccda647Slclee capacity = un->un_blockcount; 3852*3ccda647Slclee 3853*3ccda647Slclee /* 3854*3ccda647Slclee * refresh the logical and physical geometry caches. 3855*3ccda647Slclee * (data from mode sense format/rigid disk geometry pages, 3856*3ccda647Slclee * and scsi_ifgetcap("geometry"). 3857*3ccda647Slclee */ 3858*3ccda647Slclee cmlb_resync_geom_caches(un, capacity); 3859*3ccda647Slclee 3860*3ccda647Slclee /* 3861*3ccda647Slclee * Only DIRECT ACCESS devices will have Sun labels. 3862*3ccda647Slclee * CD's supposedly have a Sun label, too 3863*3ccda647Slclee */ 3864*3ccda647Slclee if (un->un_device_type == DTYPE_DIRECT || ISREMOVABLE(un)) { 3865*3ccda647Slclee fdisk_rval = cmlb_read_fdisk(un, capacity); 3866*3ccda647Slclee if (fdisk_rval != 0) { 3867*3ccda647Slclee ASSERT(mutex_owned(CMLB_MUTEX(un))); 3868*3ccda647Slclee return (fdisk_rval); 3869*3ccda647Slclee } 3870*3ccda647Slclee 3871*3ccda647Slclee if (un->un_solaris_size <= DK_LABEL_LOC) { 3872*3ccda647Slclee /* 3873*3ccda647Slclee * Found fdisk table but no Solaris partition entry, 3874*3ccda647Slclee * so don't call cmlb_uselabel() and don't create 3875*3ccda647Slclee * a default label. 3876*3ccda647Slclee */ 3877*3ccda647Slclee label_rc = 0; 3878*3ccda647Slclee un->un_f_geometry_is_valid = TRUE; 3879*3ccda647Slclee goto no_solaris_partition; 3880*3ccda647Slclee } 3881*3ccda647Slclee } else if (capacity < 0) { 3882*3ccda647Slclee ASSERT(mutex_owned(CMLB_MUTEX(un))); 3883*3ccda647Slclee return (EINVAL); 3884*3ccda647Slclee } 3885*3ccda647Slclee 3886*3ccda647Slclee /* 3887*3ccda647Slclee * For Removable media We reach here if we have found a 3888*3ccda647Slclee * SOLARIS PARTITION. 3889*3ccda647Slclee * If un_f_geometry_is_valid is FALSE it indicates that the SOLARIS 3890*3ccda647Slclee * PARTITION has changed from the previous one, hence we will setup a 3891*3ccda647Slclee * default VTOC in this case. 3892*3ccda647Slclee */ 3893*3ccda647Slclee if (un->un_f_geometry_is_valid == FALSE) { 3894*3ccda647Slclee /* if we get here it is writable */ 3895*3ccda647Slclee /* we are called from SMBOOT, and after a write of fdisk */ 3896*3ccda647Slclee cmlb_build_default_label(un); 3897*3ccda647Slclee label_rc = 0; 3898*3ccda647Slclee } 3899*3ccda647Slclee 3900*3ccda647Slclee no_solaris_partition: 3901*3ccda647Slclee 3902*3ccda647Slclee #if defined(_SUNOS_VTOC_16) 3903*3ccda647Slclee /* 3904*3ccda647Slclee * If we have valid geometry, set up the remaining fdisk partitions. 3905*3ccda647Slclee * Note that dkl_cylno is not used for the fdisk map entries, so 3906*3ccda647Slclee * we set it to an entirely bogus value. 3907*3ccda647Slclee */ 3908*3ccda647Slclee for (count = 0; count < FD_NUMPART; count++) { 3909*3ccda647Slclee un->un_map[FDISK_P1 + count].dkl_cylno = -1; 3910*3ccda647Slclee un->un_map[FDISK_P1 + count].dkl_nblk = 3911*3ccda647Slclee un->un_fmap[count].fmap_nblk; 3912*3ccda647Slclee un->un_offset[FDISK_P1 + count] = 3913*3ccda647Slclee un->un_fmap[count].fmap_start; 3914*3ccda647Slclee } 3915*3ccda647Slclee #endif 3916*3ccda647Slclee 3917*3ccda647Slclee for (count = 0; count < NDKMAP; count++) { 3918*3ccda647Slclee #if defined(_SUNOS_VTOC_8) 3919*3ccda647Slclee struct dk_map *lp = &un->un_map[count]; 3920*3ccda647Slclee un->un_offset[count] = 3921*3ccda647Slclee un->un_g.dkg_nhead * un->un_g.dkg_nsect * lp->dkl_cylno; 3922*3ccda647Slclee #elif defined(_SUNOS_VTOC_16) 3923*3ccda647Slclee struct dkl_partition *vp = &un->un_vtoc.v_part[count]; 3924*3ccda647Slclee un->un_offset[count] = vp->p_start + un->un_solaris_offset; 3925*3ccda647Slclee #else 3926*3ccda647Slclee #error "No VTOC format defined." 3927*3ccda647Slclee #endif 3928*3ccda647Slclee } 3929*3ccda647Slclee 3930*3ccda647Slclee ASSERT(mutex_owned(CMLB_MUTEX(un))); 3931*3ccda647Slclee return (label_rc); 3932*3ccda647Slclee } 3933*3ccda647Slclee #endif 3934*3ccda647Slclee 3935*3ccda647Slclee #if defined(__i386) || defined(__amd64) 3936*3ccda647Slclee static int 3937*3ccda647Slclee cmlb_dkio_get_virtgeom(struct cmlb_lun *un, caddr_t arg, int flag) 3938*3ccda647Slclee { 3939*3ccda647Slclee int err = 0; 3940*3ccda647Slclee 3941*3ccda647Slclee /* Return the driver's notion of the media's logical geometry */ 3942*3ccda647Slclee struct dk_geom disk_geom; 3943*3ccda647Slclee struct dk_geom *dkgp = &disk_geom; 3944*3ccda647Slclee 3945*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 3946*3ccda647Slclee /* 3947*3ccda647Slclee * If there is no HBA geometry available, or 3948*3ccda647Slclee * if the HBA returned us something that doesn't 3949*3ccda647Slclee * really fit into an Int 13/function 8 geometry 3950*3ccda647Slclee * result, just fail the ioctl. See PSARC 1998/313. 3951*3ccda647Slclee */ 3952*3ccda647Slclee if (un->un_lgeom.g_nhead == 0 || 3953*3ccda647Slclee un->un_lgeom.g_nsect == 0 || 3954*3ccda647Slclee un->un_lgeom.g_ncyl > 1024) { 3955*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 3956*3ccda647Slclee err = EINVAL; 3957*3ccda647Slclee } else { 3958*3ccda647Slclee dkgp->dkg_ncyl = un->un_lgeom.g_ncyl; 3959*3ccda647Slclee dkgp->dkg_acyl = un->un_lgeom.g_acyl; 3960*3ccda647Slclee dkgp->dkg_pcyl = dkgp->dkg_ncyl + dkgp->dkg_acyl; 3961*3ccda647Slclee dkgp->dkg_nhead = un->un_lgeom.g_nhead; 3962*3ccda647Slclee dkgp->dkg_nsect = un->un_lgeom.g_nsect; 3963*3ccda647Slclee 3964*3ccda647Slclee if (ddi_copyout(dkgp, (void *)arg, 3965*3ccda647Slclee sizeof (struct dk_geom), flag)) { 3966*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 3967*3ccda647Slclee err = EFAULT; 3968*3ccda647Slclee } else { 3969*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 3970*3ccda647Slclee err = 0; 3971*3ccda647Slclee } 3972*3ccda647Slclee } 3973*3ccda647Slclee return (err); 3974*3ccda647Slclee } 3975*3ccda647Slclee #endif 3976*3ccda647Slclee 3977*3ccda647Slclee #if defined(__i386) || defined(__amd64) 3978*3ccda647Slclee static int 3979*3ccda647Slclee cmlb_dkio_get_phygeom(struct cmlb_lun *un, caddr_t arg, int flag) 3980*3ccda647Slclee { 3981*3ccda647Slclee int err = 0; 3982*3ccda647Slclee 3983*3ccda647Slclee 3984*3ccda647Slclee /* Return the driver's notion of the media physical geometry */ 3985*3ccda647Slclee struct dk_geom disk_geom; 3986*3ccda647Slclee struct dk_geom *dkgp = &disk_geom; 3987*3ccda647Slclee 3988*3ccda647Slclee mutex_enter(CMLB_MUTEX(un)); 3989*3ccda647Slclee 3990*3ccda647Slclee if (un->un_g.dkg_nhead != 0 && 3991*3ccda647Slclee un->un_g.dkg_nsect != 0) { 3992*3ccda647Slclee /* 3993*3ccda647Slclee * We succeeded in getting a geometry, but 3994*3ccda647Slclee * right now it is being reported as just the 3995*3ccda647Slclee * Solaris fdisk partition, just like for 3996*3ccda647Slclee * DKIOCGGEOM. We need to change that to be 3997*3ccda647Slclee * correct for the entire disk now. 3998*3ccda647Slclee */ 3999*3ccda647Slclee bcopy(&un->un_g, dkgp, sizeof (*dkgp)); 4000*3ccda647Slclee dkgp->dkg_acyl = 0; 4001*3ccda647Slclee dkgp->dkg_ncyl = un->un_blockcount / 4002*3ccda647Slclee (dkgp->dkg_nhead * dkgp->dkg_nsect); 4003*3ccda647Slclee } else { 4004*3ccda647Slclee bzero(dkgp, sizeof (struct dk_geom)); 4005*3ccda647Slclee /* 4006*3ccda647Slclee * This disk does not have a Solaris VTOC 4007*3ccda647Slclee * so we must present a physical geometry 4008*3ccda647Slclee * that will remain consistent regardless 4009*3ccda647Slclee * of how the disk is used. This will ensure 4010*3ccda647Slclee * that the geometry does not change regardless 4011*3ccda647Slclee * of the fdisk partition type (ie. EFI, FAT32, 4012*3ccda647Slclee * Solaris, etc). 4013*3ccda647Slclee */ 4014*3ccda647Slclee if (ISCD(un)) { 4015*3ccda647Slclee dkgp->dkg_nhead = un->un_pgeom.g_nhead; 4016*3ccda647Slclee dkgp->dkg_nsect = un->un_pgeom.g_nsect; 4017*3ccda647Slclee dkgp->dkg_ncyl = un->un_pgeom.g_ncyl; 4018*3ccda647Slclee dkgp->dkg_acyl = un->un_pgeom.g_acyl; 4019*3ccda647Slclee } else { 4020*3ccda647Slclee cmlb_convert_geometry(un->un_blockcount, dkgp); 4021*3ccda647Slclee dkgp->dkg_acyl = 0; 4022*3ccda647Slclee dkgp->dkg_ncyl = un->un_blockcount / 4023*3ccda647Slclee (dkgp->dkg_nhead * dkgp->dkg_nsect); 4024*3ccda647Slclee } 4025*3ccda647Slclee } 4026*3ccda647Slclee dkgp->dkg_pcyl = dkgp->dkg_ncyl + dkgp->dkg_acyl; 4027*3ccda647Slclee 4028*3ccda647Slclee if (ddi_copyout(dkgp, (void *)arg, 4029*3ccda647Slclee sizeof (struct dk_geom), flag)) { 4030*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 4031*3ccda647Slclee err = EFAULT; 4032*3ccda647Slclee } else { 4033*3ccda647Slclee mutex_exit(CMLB_MUTEX(un)); 4034*3ccda647Slclee err = 0; 4035*3ccda647Slclee } 4036*3ccda647Slclee return (err); 4037*3ccda647Slclee } 4038*3ccda647Slclee #endif 4039*3ccda647Slclee 4040*3ccda647Slclee #if defined(__i386) || defined(__amd64) 4041*3ccda647Slclee static int 4042*3ccda647Slclee cmlb_dkio_partinfo(struct cmlb_lun *un, dev_t dev, caddr_t arg, int flag) 4043*3ccda647Slclee { 4044*3ccda647Slclee int err = 0; 4045*3ccda647Slclee 4046*3ccda647Slclee /* 4047*3ccda647Slclee * Return parameters describing the selected disk slice. 4048*3ccda647Slclee * Note: this ioctl is for the intel platform only 4049*3ccda647Slclee */ 4050*3ccda647Slclee int part; 4051*3ccda647Slclee 4052*3ccda647Slclee part = CMLBPART(dev); 4053*3ccda647Slclee 4054*3ccda647Slclee /* don't check un_solaris_size for pN */ 4055*3ccda647Slclee if (part < P0_RAW_DISK && un->un_solaris_size == 0) { 4056*3ccda647Slclee err = EIO; 4057*3ccda647Slclee } else { 4058*3ccda647Slclee struct part_info p; 4059*3ccda647Slclee 4060*3ccda647Slclee p.p_start = (daddr_t)un->un_offset[part]; 4061*3ccda647Slclee p.p_length = (int)un->un_map[part].dkl_nblk; 4062*3ccda647Slclee #ifdef _MULTI_DATAMODEL 4063*3ccda647Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 4064*3ccda647Slclee case DDI_MODEL_ILP32: 4065*3ccda647Slclee { 4066*3ccda647Slclee struct part_info32 p32; 4067*3ccda647Slclee 4068*3ccda647Slclee p32.p_start = (daddr32_t)p.p_start; 4069*3ccda647Slclee p32.p_length = p.p_length; 4070*3ccda647Slclee if (ddi_copyout(&p32, (void *)arg, 4071*3ccda647Slclee sizeof (p32), flag)) 4072*3ccda647Slclee err = EFAULT; 4073*3ccda647Slclee break; 4074*3ccda647Slclee } 4075*3ccda647Slclee 4076*3ccda647Slclee case DDI_MODEL_NONE: 4077*3ccda647Slclee { 4078*3ccda647Slclee if (ddi_copyout(&p, (void *)arg, sizeof (p), 4079*3ccda647Slclee flag)) 4080*3ccda647Slclee err = EFAULT; 4081*3ccda647Slclee break; 4082*3ccda647Slclee } 4083*3ccda647Slclee } 4084*3ccda647Slclee #else /* ! _MULTI_DATAMODEL */ 4085*3ccda647Slclee if (ddi_copyout(&p, (void *)arg, sizeof (p), flag)) 4086*3ccda647Slclee err = EFAULT; 4087*3ccda647Slclee #endif /* _MULTI_DATAMODEL */ 4088*3ccda647Slclee } 4089*3ccda647Slclee return (err); 4090*3ccda647Slclee } 4091*3ccda647Slclee #endif 4092