1786Slclee /* 2786Slclee * CDDL HEADER START 3786Slclee * 4786Slclee * The contents of this file are subject to the terms of the 53525Sshidokht * Common Development and Distribution License (the "License"). 63525Sshidokht * You may not use this file except in compliance with the License. 7786Slclee * 8786Slclee * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9786Slclee * or http://www.opensolaris.org/os/licensing. 10786Slclee * See the License for the specific language governing permissions 11786Slclee * and limitations under the License. 12786Slclee * 13786Slclee * When distributing Covered Code, include this CDDL HEADER in each 14786Slclee * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15786Slclee * If applicable, add the following below this CDDL HEADER, with the 16786Slclee * fields enclosed by brackets "[]" replaced with your own identifying 17786Slclee * information: Portions Copyright [yyyy] [name of copyright owner] 18786Slclee * 19786Slclee * CDDL HEADER END 20786Slclee */ 21786Slclee 22786Slclee /* 236124Sshidokht * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24786Slclee * Use is subject to license terms. 25786Slclee */ 26786Slclee 27786Slclee /* 28786Slclee * This module provides support for labeling operations for target 29786Slclee * drivers. 30786Slclee */ 31786Slclee 32786Slclee #include <sys/scsi/scsi.h> 33786Slclee #include <sys/sunddi.h> 34786Slclee #include <sys/dklabel.h> 35786Slclee #include <sys/dkio.h> 36786Slclee #include <sys/vtoc.h> 37786Slclee #include <sys/dktp/fdisk.h> 38786Slclee #include <sys/vtrace.h> 39786Slclee #include <sys/efi_partition.h> 40786Slclee #include <sys/cmlb.h> 41786Slclee #include <sys/cmlb_impl.h> 427224Scth #include <sys/ddi_impldefs.h> 43786Slclee 44786Slclee /* 45786Slclee * Driver minor node structure and data table 46786Slclee */ 47786Slclee struct driver_minor_data { 48786Slclee char *name; 49786Slclee minor_t minor; 50786Slclee int type; 51786Slclee }; 52786Slclee 53786Slclee static struct driver_minor_data dk_minor_data[] = { 54786Slclee {"a", 0, S_IFBLK}, 55786Slclee {"b", 1, S_IFBLK}, 56786Slclee {"c", 2, S_IFBLK}, 57786Slclee {"d", 3, S_IFBLK}, 58786Slclee {"e", 4, S_IFBLK}, 59786Slclee {"f", 5, S_IFBLK}, 60786Slclee {"g", 6, S_IFBLK}, 61786Slclee {"h", 7, S_IFBLK}, 62786Slclee #if defined(_SUNOS_VTOC_16) 63786Slclee {"i", 8, S_IFBLK}, 64786Slclee {"j", 9, S_IFBLK}, 65786Slclee {"k", 10, S_IFBLK}, 66786Slclee {"l", 11, S_IFBLK}, 67786Slclee {"m", 12, S_IFBLK}, 68786Slclee {"n", 13, S_IFBLK}, 69786Slclee {"o", 14, S_IFBLK}, 70786Slclee {"p", 15, S_IFBLK}, 71786Slclee #endif /* defined(_SUNOS_VTOC_16) */ 72786Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 73786Slclee {"q", 16, S_IFBLK}, 74786Slclee {"r", 17, S_IFBLK}, 75786Slclee {"s", 18, S_IFBLK}, 76786Slclee {"t", 19, S_IFBLK}, 77786Slclee {"u", 20, S_IFBLK}, 78786Slclee #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 79786Slclee {"a,raw", 0, S_IFCHR}, 80786Slclee {"b,raw", 1, S_IFCHR}, 81786Slclee {"c,raw", 2, S_IFCHR}, 82786Slclee {"d,raw", 3, S_IFCHR}, 83786Slclee {"e,raw", 4, S_IFCHR}, 84786Slclee {"f,raw", 5, S_IFCHR}, 85786Slclee {"g,raw", 6, S_IFCHR}, 86786Slclee {"h,raw", 7, S_IFCHR}, 87786Slclee #if defined(_SUNOS_VTOC_16) 88786Slclee {"i,raw", 8, S_IFCHR}, 89786Slclee {"j,raw", 9, S_IFCHR}, 90786Slclee {"k,raw", 10, S_IFCHR}, 91786Slclee {"l,raw", 11, S_IFCHR}, 92786Slclee {"m,raw", 12, S_IFCHR}, 93786Slclee {"n,raw", 13, S_IFCHR}, 94786Slclee {"o,raw", 14, S_IFCHR}, 95786Slclee {"p,raw", 15, S_IFCHR}, 96786Slclee #endif /* defined(_SUNOS_VTOC_16) */ 97786Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 98786Slclee {"q,raw", 16, S_IFCHR}, 99786Slclee {"r,raw", 17, S_IFCHR}, 100786Slclee {"s,raw", 18, S_IFCHR}, 101786Slclee {"t,raw", 19, S_IFCHR}, 102786Slclee {"u,raw", 20, S_IFCHR}, 103786Slclee #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 104786Slclee {0} 105786Slclee }; 106786Slclee 107786Slclee static struct driver_minor_data dk_minor_data_efi[] = { 108786Slclee {"a", 0, S_IFBLK}, 109786Slclee {"b", 1, S_IFBLK}, 110786Slclee {"c", 2, S_IFBLK}, 111786Slclee {"d", 3, S_IFBLK}, 112786Slclee {"e", 4, S_IFBLK}, 113786Slclee {"f", 5, S_IFBLK}, 114786Slclee {"g", 6, S_IFBLK}, 115786Slclee {"wd", 7, S_IFBLK}, 116786Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 117786Slclee {"q", 16, S_IFBLK}, 118786Slclee {"r", 17, S_IFBLK}, 119786Slclee {"s", 18, S_IFBLK}, 120786Slclee {"t", 19, S_IFBLK}, 121786Slclee {"u", 20, S_IFBLK}, 122786Slclee #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 123786Slclee {"a,raw", 0, S_IFCHR}, 124786Slclee {"b,raw", 1, S_IFCHR}, 125786Slclee {"c,raw", 2, S_IFCHR}, 126786Slclee {"d,raw", 3, S_IFCHR}, 127786Slclee {"e,raw", 4, S_IFCHR}, 128786Slclee {"f,raw", 5, S_IFCHR}, 129786Slclee {"g,raw", 6, S_IFCHR}, 130786Slclee {"wd,raw", 7, S_IFCHR}, 131786Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 132786Slclee {"q,raw", 16, S_IFCHR}, 133786Slclee {"r,raw", 17, S_IFCHR}, 134786Slclee {"s,raw", 18, S_IFCHR}, 135786Slclee {"t,raw", 19, S_IFCHR}, 136786Slclee {"u,raw", 20, S_IFCHR}, 137786Slclee #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 138786Slclee {0} 139786Slclee }; 140786Slclee 1417224Scth /* 1427224Scth * Declare the dynamic properties implemented in prop_op(9E) implementation 1437224Scth * that we want to have show up in a di_init(3DEVINFO) device tree snapshot 1447224Scth * of drivers that call cmlb_attach(). 1457224Scth */ 1467224Scth static i_ddi_prop_dyn_t cmlb_prop_dyn[] = { 1477224Scth {"Nblocks", DDI_PROP_TYPE_INT64, S_IFBLK}, 1487224Scth {"Size", DDI_PROP_TYPE_INT64, S_IFCHR}, 1497224Scth {"device-nblocks", DDI_PROP_TYPE_INT64}, 1507224Scth {"device-blksize", DDI_PROP_TYPE_INT}, 1517224Scth {NULL} 1527224Scth }; 153786Slclee 1546318Sedp /* 1556318Sedp * External kernel interfaces 1566318Sedp */ 157786Slclee extern struct mod_ops mod_miscops; 158786Slclee 1596318Sedp extern int ddi_create_internal_pathname(dev_info_t *dip, char *name, 1606318Sedp int spec_type, minor_t minor_num); 1616318Sedp 162786Slclee /* 163786Slclee * Global buffer and mutex for debug logging 164786Slclee */ 165786Slclee static char cmlb_log_buffer[1024]; 166786Slclee static kmutex_t cmlb_log_mutex; 167786Slclee 168786Slclee 1693525Sshidokht struct cmlb_lun *cmlb_debug_cl = NULL; 170786Slclee uint_t cmlb_level_mask = 0x0; 171786Slclee 172786Slclee int cmlb_rot_delay = 4; /* default rotational delay */ 173786Slclee 174786Slclee static struct modlmisc modlmisc = { 175786Slclee &mod_miscops, /* Type of module */ 1767563SPrasad.Singamsetty@Sun.COM "Common Labeling module" 177786Slclee }; 178786Slclee 179786Slclee static struct modlinkage modlinkage = { 180786Slclee MODREV_1, (void *)&modlmisc, NULL 181786Slclee }; 182786Slclee 183786Slclee /* Local function prototypes */ 1843525Sshidokht static dev_t cmlb_make_device(struct cmlb_lun *cl); 1853525Sshidokht static int cmlb_validate_geometry(struct cmlb_lun *cl, int forcerevalid, 1863525Sshidokht int flags, void *tg_cookie); 1873525Sshidokht static void cmlb_resync_geom_caches(struct cmlb_lun *cl, diskaddr_t capacity, 1883525Sshidokht void *tg_cookie); 1893525Sshidokht static int cmlb_read_fdisk(struct cmlb_lun *cl, diskaddr_t capacity, 1903525Sshidokht void *tg_cookie); 191786Slclee static void cmlb_swap_efi_gpt(efi_gpt_t *e); 192786Slclee static void cmlb_swap_efi_gpe(int nparts, efi_gpe_t *p); 193786Slclee static int cmlb_validate_efi(efi_gpt_t *labp); 1943525Sshidokht static int cmlb_use_efi(struct cmlb_lun *cl, diskaddr_t capacity, int flags, 1953525Sshidokht void *tg_cookie); 1963525Sshidokht static void cmlb_build_default_label(struct cmlb_lun *cl, void *tg_cookie); 1973525Sshidokht static int cmlb_uselabel(struct cmlb_lun *cl, struct dk_label *l, int flags); 1983525Sshidokht #if defined(_SUNOS_VTOC_8) 1993525Sshidokht static void cmlb_build_user_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc); 2003525Sshidokht #endif 2013525Sshidokht static int cmlb_build_label_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc); 2023525Sshidokht static int cmlb_write_label(struct cmlb_lun *cl, void *tg_cookie); 2033525Sshidokht static int cmlb_set_vtoc(struct cmlb_lun *cl, struct dk_label *dkl, 2043525Sshidokht void *tg_cookie); 2053525Sshidokht static void cmlb_clear_efi(struct cmlb_lun *cl, void *tg_cookie); 2063525Sshidokht static void cmlb_clear_vtoc(struct cmlb_lun *cl, void *tg_cookie); 2073525Sshidokht static void cmlb_setup_default_geometry(struct cmlb_lun *cl, void *tg_cookie); 2083525Sshidokht static int cmlb_create_minor_nodes(struct cmlb_lun *cl); 2093525Sshidokht static int cmlb_check_update_blockcount(struct cmlb_lun *cl, void *tg_cookie); 2107563SPrasad.Singamsetty@Sun.COM static int cmlb_check_efi_mbr(uchar_t *buf, int *is_mbr); 211786Slclee 212786Slclee #if defined(__i386) || defined(__amd64) 2133525Sshidokht static int cmlb_update_fdisk_and_vtoc(struct cmlb_lun *cl, void *tg_cookie); 214786Slclee #endif 215786Slclee 216786Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 217786Slclee static int cmlb_has_max_chs_vals(struct ipart *fdp); 218786Slclee #endif 219786Slclee 220786Slclee #if defined(_SUNOS_VTOC_16) 2213525Sshidokht static void cmlb_convert_geometry(diskaddr_t capacity, struct dk_geom *cl_g); 222786Slclee #endif 223786Slclee 2243525Sshidokht static int cmlb_dkio_get_geometry(struct cmlb_lun *cl, caddr_t arg, int flag, 2253525Sshidokht void *tg_cookie); 2263525Sshidokht static int cmlb_dkio_set_geometry(struct cmlb_lun *cl, caddr_t arg, int flag); 2273525Sshidokht static int cmlb_dkio_get_partition(struct cmlb_lun *cl, caddr_t arg, int flag, 2283525Sshidokht void *tg_cookie); 2293525Sshidokht static int cmlb_dkio_set_partition(struct cmlb_lun *cl, caddr_t arg, int flag); 2303525Sshidokht static int cmlb_dkio_get_efi(struct cmlb_lun *cl, caddr_t arg, int flag, 2313525Sshidokht void *tg_cookie); 2323525Sshidokht static int cmlb_dkio_set_efi(struct cmlb_lun *cl, dev_t dev, caddr_t arg, 2333525Sshidokht int flag, void *tg_cookie); 2343525Sshidokht static int cmlb_dkio_get_vtoc(struct cmlb_lun *cl, caddr_t arg, int flag, 2353525Sshidokht void *tg_cookie); 2367563SPrasad.Singamsetty@Sun.COM static int cmlb_dkio_get_extvtoc(struct cmlb_lun *cl, caddr_t arg, int flag, 2377563SPrasad.Singamsetty@Sun.COM void *tg_cookie); 2383525Sshidokht static int cmlb_dkio_set_vtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, 2393525Sshidokht int flag, void *tg_cookie); 2407563SPrasad.Singamsetty@Sun.COM static int cmlb_dkio_set_extvtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, 2417563SPrasad.Singamsetty@Sun.COM int flag, void *tg_cookie); 2423525Sshidokht static int cmlb_dkio_get_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, 2433525Sshidokht void *tg_cookie); 2443525Sshidokht static int cmlb_dkio_set_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, 2453525Sshidokht void *tg_cookie); 2463525Sshidokht static int cmlb_dkio_partition(struct cmlb_lun *cl, caddr_t arg, int flag, 2473525Sshidokht void *tg_cookie); 248786Slclee 249786Slclee #if defined(__i386) || defined(__amd64) 2503525Sshidokht static int cmlb_dkio_get_virtgeom(struct cmlb_lun *cl, caddr_t arg, int flag); 2513525Sshidokht static int cmlb_dkio_get_phygeom(struct cmlb_lun *cl, caddr_t arg, int flag); 2523525Sshidokht static int cmlb_dkio_partinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg, 253786Slclee int flag); 2547563SPrasad.Singamsetty@Sun.COM static int cmlb_dkio_extpartinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg, 2557563SPrasad.Singamsetty@Sun.COM int flag); 256786Slclee #endif 257786Slclee 2583525Sshidokht static void cmlb_dbg(uint_t comp, struct cmlb_lun *cl, const char *fmt, ...); 259786Slclee static void cmlb_v_log(dev_info_t *dev, char *label, uint_t level, 260786Slclee const char *fmt, va_list ap); 261786Slclee static void cmlb_log(dev_info_t *dev, char *label, uint_t level, 262786Slclee const char *fmt, ...); 263786Slclee 264786Slclee int 265786Slclee _init(void) 266786Slclee { 267786Slclee mutex_init(&cmlb_log_mutex, NULL, MUTEX_DRIVER, NULL); 268786Slclee return (mod_install(&modlinkage)); 269786Slclee } 270786Slclee 271786Slclee int 272786Slclee _info(struct modinfo *modinfop) 273786Slclee { 274786Slclee return (mod_info(&modlinkage, modinfop)); 275786Slclee } 276786Slclee 277786Slclee int 278786Slclee _fini(void) 279786Slclee { 280786Slclee int err; 281786Slclee 282786Slclee if ((err = mod_remove(&modlinkage)) != 0) { 283786Slclee return (err); 284786Slclee } 285786Slclee 286786Slclee mutex_destroy(&cmlb_log_mutex); 287786Slclee return (err); 288786Slclee } 289786Slclee 290786Slclee /* 291786Slclee * cmlb_dbg is used for debugging to log additional info 292786Slclee * Level of output is controlled via cmlb_level_mask setting. 293786Slclee */ 294786Slclee static void 2953525Sshidokht cmlb_dbg(uint_t comp, struct cmlb_lun *cl, const char *fmt, ...) 296786Slclee { 297786Slclee va_list ap; 298786Slclee dev_info_t *dev; 299786Slclee uint_t level_mask = 0; 300786Slclee 3013525Sshidokht ASSERT(cl != NULL); 3023525Sshidokht dev = CMLB_DEVINFO(cl); 303786Slclee ASSERT(dev != NULL); 304786Slclee /* 305786Slclee * Filter messages based on the global component and level masks, 3063525Sshidokht * also print if cl matches the value of cmlb_debug_cl, or if 3073525Sshidokht * cmlb_debug_cl is set to NULL. 308786Slclee */ 309786Slclee if (comp & CMLB_TRACE) 310786Slclee level_mask |= CMLB_LOGMASK_TRACE; 311786Slclee 312786Slclee if (comp & CMLB_INFO) 313786Slclee level_mask |= CMLB_LOGMASK_INFO; 314786Slclee 315786Slclee if (comp & CMLB_ERROR) 316786Slclee level_mask |= CMLB_LOGMASK_ERROR; 317786Slclee 318786Slclee if ((cmlb_level_mask & level_mask) && 3193525Sshidokht ((cmlb_debug_cl == NULL) || (cmlb_debug_cl == cl))) { 320786Slclee va_start(ap, fmt); 3213525Sshidokht cmlb_v_log(dev, CMLB_LABEL(cl), CE_CONT, fmt, ap); 322786Slclee va_end(ap); 323786Slclee } 324786Slclee } 325786Slclee 326786Slclee /* 327786Slclee * cmlb_log is basically a duplicate of scsi_log. It is redefined here 328786Slclee * so that this module does not depend on scsi module. 329786Slclee */ 330786Slclee static void 331786Slclee cmlb_log(dev_info_t *dev, char *label, uint_t level, const char *fmt, ...) 332786Slclee { 333786Slclee va_list ap; 334786Slclee 335786Slclee va_start(ap, fmt); 336786Slclee cmlb_v_log(dev, label, level, fmt, ap); 337786Slclee va_end(ap); 338786Slclee } 339786Slclee 340786Slclee static void 341786Slclee cmlb_v_log(dev_info_t *dev, char *label, uint_t level, const char *fmt, 342786Slclee va_list ap) 343786Slclee { 344786Slclee static char name[256]; 345786Slclee int log_only = 0; 346786Slclee int boot_only = 0; 347786Slclee int console_only = 0; 348786Slclee 349786Slclee mutex_enter(&cmlb_log_mutex); 350786Slclee 351786Slclee if (dev) { 352786Slclee if (level == CE_PANIC || level == CE_WARN || 353786Slclee level == CE_NOTE) { 354786Slclee (void) sprintf(name, "%s (%s%d):\n", 355786Slclee ddi_pathname(dev, cmlb_log_buffer), 356786Slclee label, ddi_get_instance(dev)); 357786Slclee } else { 358786Slclee name[0] = '\0'; 359786Slclee } 360786Slclee } else { 361786Slclee (void) sprintf(name, "%s:", label); 362786Slclee } 363786Slclee 364786Slclee (void) vsprintf(cmlb_log_buffer, fmt, ap); 365786Slclee 366786Slclee switch (cmlb_log_buffer[0]) { 367786Slclee case '!': 368786Slclee log_only = 1; 369786Slclee break; 370786Slclee case '?': 371786Slclee boot_only = 1; 372786Slclee break; 373786Slclee case '^': 374786Slclee console_only = 1; 375786Slclee break; 376786Slclee } 377786Slclee 378786Slclee switch (level) { 379786Slclee case CE_NOTE: 380786Slclee level = CE_CONT; 381786Slclee /* FALLTHROUGH */ 382786Slclee case CE_CONT: 383786Slclee case CE_WARN: 384786Slclee case CE_PANIC: 385786Slclee if (boot_only) { 386786Slclee cmn_err(level, "?%s\t%s", name, &cmlb_log_buffer[1]); 387786Slclee } else if (console_only) { 388786Slclee cmn_err(level, "^%s\t%s", name, &cmlb_log_buffer[1]); 389786Slclee } else if (log_only) { 390786Slclee cmn_err(level, "!%s\t%s", name, &cmlb_log_buffer[1]); 391786Slclee } else { 392786Slclee cmn_err(level, "%s\t%s", name, cmlb_log_buffer); 393786Slclee } 394786Slclee break; 395786Slclee case CE_IGNORE: 396786Slclee break; 397786Slclee default: 398786Slclee cmn_err(CE_CONT, "^DEBUG: %s\t%s", name, cmlb_log_buffer); 399786Slclee break; 400786Slclee } 401786Slclee mutex_exit(&cmlb_log_mutex); 402786Slclee } 403786Slclee 404786Slclee 405786Slclee /* 406786Slclee * cmlb_alloc_handle: 407786Slclee * 408786Slclee * Allocates a handle. 409786Slclee * 410786Slclee * Arguments: 411786Slclee * cmlbhandlep pointer to handle 412786Slclee * 413786Slclee * Notes: 414786Slclee * Allocates a handle and stores the allocated handle in the area 415786Slclee * pointed to by cmlbhandlep 416786Slclee * 417786Slclee * Context: 418786Slclee * Kernel thread only (can sleep). 419786Slclee */ 420786Slclee void 421786Slclee cmlb_alloc_handle(cmlb_handle_t *cmlbhandlep) 422786Slclee { 4233525Sshidokht struct cmlb_lun *cl; 4243525Sshidokht 4253525Sshidokht cl = kmem_zalloc(sizeof (struct cmlb_lun), KM_SLEEP); 426786Slclee ASSERT(cmlbhandlep != NULL); 427786Slclee 4283525Sshidokht cl->cl_state = CMLB_INITED; 4293525Sshidokht cl->cl_def_labeltype = CMLB_LABEL_UNDEF; 4303525Sshidokht mutex_init(CMLB_MUTEX(cl), NULL, MUTEX_DRIVER, NULL); 4313525Sshidokht 4323525Sshidokht *cmlbhandlep = (cmlb_handle_t)(cl); 433786Slclee } 434786Slclee 435786Slclee /* 436786Slclee * cmlb_free_handle 437786Slclee * 438786Slclee * Frees handle. 439786Slclee * 440786Slclee * Arguments: 441786Slclee * cmlbhandlep pointer to handle 442786Slclee */ 443786Slclee void 444786Slclee cmlb_free_handle(cmlb_handle_t *cmlbhandlep) 445786Slclee { 4463525Sshidokht struct cmlb_lun *cl; 4473525Sshidokht 4483525Sshidokht cl = (struct cmlb_lun *)*cmlbhandlep; 4493525Sshidokht if (cl != NULL) { 4503525Sshidokht mutex_destroy(CMLB_MUTEX(cl)); 4513525Sshidokht kmem_free(cl, sizeof (struct cmlb_lun)); 452786Slclee } 453786Slclee 454786Slclee } 455786Slclee 456786Slclee /* 457786Slclee * cmlb_attach: 458786Slclee * 459786Slclee * Attach handle to device, create minor nodes for device. 460786Slclee * 461786Slclee * Arguments: 462786Slclee * devi pointer to device's dev_info structure. 463786Slclee * tgopsp pointer to array of functions cmlb can use to callback 464786Slclee * to target driver. 465786Slclee * 466786Slclee * device_type Peripheral device type as defined in 467786Slclee * scsi/generic/inquiry.h 468786Slclee * 469786Slclee * is_removable whether or not device is removable. 470786Slclee * 0 non-removable, 1 removable. 471786Slclee * 4723525Sshidokht * is_hotpluggable whether or not device is hotpluggable. 4733525Sshidokht * 0 non-hotpluggable, 1 hotpluggable. 4743525Sshidokht * 475786Slclee * node_type minor node type (as used by ddi_create_minor_node) 476786Slclee * 477786Slclee * alter_behavior 478786Slclee * bit flags: 479786Slclee * 480786Slclee * CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT: create 481786Slclee * an alternate slice for the default label, if 482786Slclee * device type is DTYPE_DIRECT an architectures default 483786Slclee * label type is VTOC16. 484786Slclee * Otherwise alternate slice will no be created. 485786Slclee * 486786Slclee * 487786Slclee * CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8: report a default 488786Slclee * geometry and label for DKIOCGGEOM and DKIOCGVTOC 489786Slclee * on architecture with VTOC8 label types. 490786Slclee * 4913525Sshidokht * CMLB_OFF_BY_ONE: do the workaround for legacy off-by- 4923525Sshidokht * one bug in obtaining capacity (in sd): 4933525Sshidokht * SCSI READ_CAPACITY command returns the LBA number of the 4943525Sshidokht * last logical block, but sd once treated this number as 4953525Sshidokht * disks' capacity on x86 platform. And LBAs are addressed 4963525Sshidokht * based 0. So the last block was lost on x86 platform. 4973525Sshidokht * 4983525Sshidokht * Now, we remove this workaround. In order for present sd 4993525Sshidokht * driver to work with disks which are labeled/partitioned 5003525Sshidokht * via previous sd, we add workaround as follows: 5013525Sshidokht * 5023525Sshidokht * 1) Locate backup EFI label: cmlb searches the next to 5033525Sshidokht * last 5043525Sshidokht * block for backup EFI label. If fails, it will 5053525Sshidokht * turn to the last block for backup EFI label; 5063525Sshidokht * 5073525Sshidokht * 2) Clear backup EFI label: cmlb first search the last 5083525Sshidokht * block for backup EFI label, and will search the 5093525Sshidokht * next to last block only if failed for the last 5103525Sshidokht * block. 5113525Sshidokht * 5123525Sshidokht * 3) Calculate geometry:refer to cmlb_convert_geometry() 5133525Sshidokht * If capacity increasing by 1 causes disks' capacity 5147563SPrasad.Singamsetty@Sun.COM * to cross over the limits in geometry calculation, 5153525Sshidokht * geometry info will change. This will raise an issue: 5163525Sshidokht * In case that primary VTOC label is destroyed, format 5173525Sshidokht * commandline can restore it via backup VTOC labels. 5183525Sshidokht * And format locates backup VTOC labels by use of 5193525Sshidokht * geometry. So changing geometry will 5203525Sshidokht * prevent format from finding backup VTOC labels. To 5213525Sshidokht * eliminate this side effect for compatibility, 5223525Sshidokht * sd uses (capacity -1) to calculate geometry; 5233525Sshidokht * 5243525Sshidokht * 4) 1TB disks: some important data structures use 5253525Sshidokht * 32-bit signed long/int (for example, daddr_t), 5263525Sshidokht * so that sd doesn't support a disk with capacity 5273525Sshidokht * larger than 1TB on 32-bit platform. However, 5283525Sshidokht * for exactly 1TB disk, it was treated as (1T - 512)B 5293525Sshidokht * in the past, and could have valid Solaris 5303525Sshidokht * partitions. To workaround this, if an exactly 1TB 5313525Sshidokht * disk has Solaris fdisk partition, it will be allowed 5323525Sshidokht * to work with sd. 5333525Sshidokht * 5343525Sshidokht * 535786Slclee * 5365084Sjohnlev * CMLB_FAKE_LABEL_ONE_PARTITION: create s0 and s2 covering 5375084Sjohnlev * the entire disk, if there is no valid partition info. 5385084Sjohnlev * If there is a valid Solaris partition, s0 and s2 will 5395084Sjohnlev * only cover the entire Solaris partition. 5405084Sjohnlev * 5415084Sjohnlev * 542786Slclee * cmlbhandle cmlb handle associated with device 543786Slclee * 5443525Sshidokht * tg_cookie cookie from target driver to be passed back to target 5453525Sshidokht * driver when we call back to it through tg_ops. 5463525Sshidokht * 547786Slclee * Notes: 548786Slclee * Assumes a default label based on capacity for non-removable devices. 549786Slclee * If capacity > 1TB, EFI is assumed otherwise VTOC (default VTOC 550786Slclee * for the architecture). 551786Slclee * 552786Slclee * For removable devices, default label type is assumed to be VTOC 553786Slclee * type. Create minor nodes based on a default label type. 554786Slclee * Label on the media is not validated. 555786Slclee * minor number consists of: 556786Slclee * if _SUNOS_VTOC_8 is defined 557786Slclee * lowest 3 bits is taken as partition number 558786Slclee * the rest is instance number 559786Slclee * if _SUNOS_VTOC_16 is defined 560786Slclee * lowest 6 bits is taken as partition number 561786Slclee * the rest is instance number 562786Slclee * 563786Slclee * 564786Slclee * Return values: 565786Slclee * 0 Success 566786Slclee * ENXIO creating minor nodes failed. 5673525Sshidokht * EINVAL invalid arg, unsupported tg_ops version 568786Slclee */ 569786Slclee int 570786Slclee cmlb_attach(dev_info_t *devi, cmlb_tg_ops_t *tgopsp, int device_type, 5713525Sshidokht int is_removable, int is_hotpluggable, char *node_type, 5723525Sshidokht int alter_behavior, cmlb_handle_t cmlbhandle, void *tg_cookie) 573786Slclee { 574786Slclee 5753525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 576786Slclee diskaddr_t cap; 577786Slclee int status; 578786Slclee 5793525Sshidokht if (tgopsp->tg_version < TG_DK_OPS_VERSION_1) 5803525Sshidokht return (EINVAL); 5813525Sshidokht 5823525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 5833525Sshidokht 5843525Sshidokht CMLB_DEVINFO(cl) = devi; 5853525Sshidokht cl->cmlb_tg_ops = tgopsp; 5863525Sshidokht cl->cl_device_type = device_type; 5873525Sshidokht cl->cl_is_removable = is_removable; 5883525Sshidokht cl->cl_is_hotpluggable = is_hotpluggable; 5893525Sshidokht cl->cl_node_type = node_type; 5903525Sshidokht cl->cl_sys_blocksize = DEV_BSIZE; 5913525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 5923525Sshidokht cl->cl_def_labeltype = CMLB_LABEL_VTOC; 5933525Sshidokht cl->cl_alter_behavior = alter_behavior; 5943525Sshidokht cl->cl_reserved = -1; 5957563SPrasad.Singamsetty@Sun.COM cl->cl_msglog_flag |= CMLB_ALLOW_2TB_WARN; 5967563SPrasad.Singamsetty@Sun.COM 5977563SPrasad.Singamsetty@Sun.COM if (is_removable == 0) { 5983525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 5993525Sshidokht status = DK_TG_GETCAP(cl, &cap, tg_cookie); 6003525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 6017563SPrasad.Singamsetty@Sun.COM if (status == 0 && cap > CMLB_EXTVTOC_LIMIT) { 6027563SPrasad.Singamsetty@Sun.COM /* set default EFI if > 2TB */ 6033525Sshidokht cl->cl_def_labeltype = CMLB_LABEL_EFI; 604786Slclee } 605786Slclee } 606786Slclee 607786Slclee /* create minor nodes based on default label type */ 6083525Sshidokht cl->cl_last_labeltype = CMLB_LABEL_UNDEF; 6093525Sshidokht cl->cl_cur_labeltype = CMLB_LABEL_UNDEF; 6103525Sshidokht 6113525Sshidokht if (cmlb_create_minor_nodes(cl) != 0) { 6123525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 613786Slclee return (ENXIO); 614786Slclee } 615786Slclee 6167224Scth /* Define the dynamic properties for devinfo spapshots. */ 6177224Scth i_ddi_prop_dyn_driver_set(CMLB_DEVINFO(cl), cmlb_prop_dyn); 6187224Scth 6193525Sshidokht cl->cl_state = CMLB_ATTACHED; 6203525Sshidokht 6213525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 622786Slclee return (0); 623786Slclee } 624786Slclee 625786Slclee /* 626786Slclee * cmlb_detach: 627786Slclee * 628786Slclee * Invalidate in-core labeling data and remove all minor nodes for 629786Slclee * the device associate with handle. 630786Slclee * 631786Slclee * Arguments: 632786Slclee * cmlbhandle cmlb handle associated with device. 633786Slclee * 6343525Sshidokht * tg_cookie cookie from target driver to be passed back to target 6353525Sshidokht * driver when we call back to it through tg_ops. 6363525Sshidokht * 637786Slclee */ 6383525Sshidokht /*ARGSUSED1*/ 639786Slclee void 6403525Sshidokht cmlb_detach(cmlb_handle_t cmlbhandle, void *tg_cookie) 641786Slclee { 6423525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 6433525Sshidokht 6443525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 6453525Sshidokht cl->cl_def_labeltype = CMLB_LABEL_UNDEF; 6463525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 6473525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL); 6487224Scth i_ddi_prop_dyn_driver_set(CMLB_DEVINFO(cl), NULL); 6493525Sshidokht cl->cl_state = CMLB_INITED; 6503525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 651786Slclee } 652786Slclee 653786Slclee /* 654786Slclee * cmlb_validate: 655786Slclee * 656786Slclee * Validates label. 657786Slclee * 658786Slclee * Arguments 659786Slclee * cmlbhandle cmlb handle associated with device. 660786Slclee * 6613525Sshidokht * flags operation flags. used for verbosity control 6623525Sshidokht * 6633525Sshidokht * tg_cookie cookie from target driver to be passed back to target 6643525Sshidokht * driver when we call back to it through tg_ops. 6653525Sshidokht * 6663525Sshidokht * 667786Slclee * Notes: 668786Slclee * If new label type is different from the current, adjust minor nodes 669786Slclee * accordingly. 670786Slclee * 671786Slclee * Return values: 672786Slclee * 0 success 673786Slclee * Note: having fdisk but no solaris partition is assumed 674786Slclee * success. 675786Slclee * 676786Slclee * ENOMEM memory allocation failed 677786Slclee * EIO i/o errors during read or get capacity 678786Slclee * EACCESS reservation conflicts 679786Slclee * EINVAL label was corrupt, or no default label was assumed 680786Slclee * ENXIO invalid handle 681786Slclee */ 682786Slclee int 6833525Sshidokht cmlb_validate(cmlb_handle_t cmlbhandle, int flags, void *tg_cookie) 684786Slclee { 6853525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 686786Slclee int rval; 687786Slclee int ret = 0; 688786Slclee 689786Slclee /* 6903525Sshidokht * Temp work-around checking cl for NULL since there is a bug 691786Slclee * in sd_detach calling this routine from taskq_dispatch 692786Slclee * inited function. 693786Slclee */ 6943525Sshidokht if (cl == NULL) 695786Slclee return (ENXIO); 696786Slclee 6973525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 6983525Sshidokht if (cl->cl_state < CMLB_ATTACHED) { 6993525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 700786Slclee return (ENXIO); 701786Slclee } 702786Slclee 7033525Sshidokht rval = cmlb_validate_geometry((struct cmlb_lun *)cmlbhandle, 1, 7043525Sshidokht flags, tg_cookie); 705786Slclee 706786Slclee if (rval == ENOTSUP) { 7073525Sshidokht if (cl->cl_f_geometry_is_valid == TRUE) { 7083525Sshidokht cl->cl_cur_labeltype = CMLB_LABEL_EFI; 709786Slclee ret = 0; 710786Slclee } else { 711786Slclee ret = EINVAL; 712786Slclee } 713786Slclee } else { 714786Slclee ret = rval; 715786Slclee if (ret == 0) 7163525Sshidokht cl->cl_cur_labeltype = CMLB_LABEL_VTOC; 717786Slclee } 718786Slclee 719786Slclee if (ret == 0) 7203525Sshidokht (void) cmlb_create_minor_nodes(cl); 7213525Sshidokht 7223525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 723786Slclee return (ret); 724786Slclee } 725786Slclee 726786Slclee /* 727786Slclee * cmlb_invalidate: 728786Slclee * Invalidate in core label data 729786Slclee * 730786Slclee * Arguments: 731786Slclee * cmlbhandle cmlb handle associated with device. 7323525Sshidokht * tg_cookie cookie from target driver to be passed back to target 7333525Sshidokht * driver when we call back to it through tg_ops. 734786Slclee */ 7353525Sshidokht /*ARGSUSED1*/ 736786Slclee void 7373525Sshidokht cmlb_invalidate(cmlb_handle_t cmlbhandle, void *tg_cookie) 738786Slclee { 7393525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 7403525Sshidokht 7413525Sshidokht if (cl == NULL) 742786Slclee return; 743786Slclee 7443525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 7453525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 7463525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 747786Slclee } 748786Slclee 749786Slclee /* 7503525Sshidokht * cmlb_is_valid 7513525Sshidokht * Get status on whether the incore label/geom data is valid 7523525Sshidokht * 7533525Sshidokht * Arguments: 7543525Sshidokht * cmlbhandle cmlb handle associated with device. 7553525Sshidokht * 7563525Sshidokht * Return values: 7573525Sshidokht * TRUE if incore label/geom data is valid. 7583525Sshidokht * FALSE otherwise. 7593525Sshidokht * 7603525Sshidokht */ 7613525Sshidokht 7623525Sshidokht 7633525Sshidokht int 7643525Sshidokht cmlb_is_valid(cmlb_handle_t cmlbhandle) 7653525Sshidokht { 7663525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 7673525Sshidokht 7683525Sshidokht if (cmlbhandle == NULL) 7693525Sshidokht return (FALSE); 7703525Sshidokht 7713525Sshidokht return (cl->cl_f_geometry_is_valid); 7723525Sshidokht 7733525Sshidokht } 7743525Sshidokht 7753525Sshidokht 7763525Sshidokht 7773525Sshidokht /* 778786Slclee * cmlb_close: 779786Slclee * 780786Slclee * Close the device, revert to a default label minor node for the device, 781786Slclee * if it is removable. 782786Slclee * 783786Slclee * Arguments: 784786Slclee * cmlbhandle cmlb handle associated with device. 785786Slclee * 7863525Sshidokht * tg_cookie cookie from target driver to be passed back to target 7873525Sshidokht * driver when we call back to it through tg_ops. 788786Slclee * Return values: 789786Slclee * 0 Success 790786Slclee * ENXIO Re-creating minor node failed. 791786Slclee */ 7923525Sshidokht /*ARGSUSED1*/ 793786Slclee int 7943525Sshidokht cmlb_close(cmlb_handle_t cmlbhandle, void *tg_cookie) 795786Slclee { 7963525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 7973525Sshidokht 7983525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 7993525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 800786Slclee 801786Slclee /* revert to default minor node for this device */ 8023525Sshidokht if (ISREMOVABLE(cl)) { 8033525Sshidokht cl->cl_cur_labeltype = CMLB_LABEL_UNDEF; 8043525Sshidokht (void) cmlb_create_minor_nodes(cl); 805786Slclee } 806786Slclee 8073525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 808786Slclee return (0); 809786Slclee } 810786Slclee 811786Slclee /* 812786Slclee * cmlb_get_devid_block: 813786Slclee * get the block number where device id is stored. 814786Slclee * 815786Slclee * Arguments: 816786Slclee * cmlbhandle cmlb handle associated with device. 817786Slclee * devidblockp pointer to block number. 8183525Sshidokht * tg_cookie cookie from target driver to be passed back to target 8193525Sshidokht * driver when we call back to it through tg_ops. 820786Slclee * 821786Slclee * Notes: 822786Slclee * It stores the block number of device id in the area pointed to 823786Slclee * by devidblockp. 824786Slclee * with the block number of device id. 825786Slclee * 826786Slclee * Return values: 827786Slclee * 0 success 828786Slclee * EINVAL device id does not apply to current label type. 829786Slclee */ 8303525Sshidokht /*ARGSUSED2*/ 831786Slclee int 8323525Sshidokht cmlb_get_devid_block(cmlb_handle_t cmlbhandle, diskaddr_t *devidblockp, 8333525Sshidokht void *tg_cookie) 834786Slclee { 835786Slclee daddr_t spc, blk, head, cyl; 8363525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 8373525Sshidokht 8383525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 8393525Sshidokht if (cl->cl_state < CMLB_ATTACHED) { 8403525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 8413525Sshidokht return (EINVAL); 8423525Sshidokht } 8433525Sshidokht 8443525Sshidokht if ((cl->cl_f_geometry_is_valid == FALSE) || 8453525Sshidokht (cl->cl_solaris_size < DK_LABEL_LOC)) { 8463525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 847786Slclee return (EINVAL); 848786Slclee } 849786Slclee 8503525Sshidokht if (cl->cl_cur_labeltype == CMLB_LABEL_EFI) { 8513525Sshidokht if (cl->cl_reserved != -1) { 8523525Sshidokht blk = cl->cl_map[cl->cl_reserved].dkl_cylno; 8533525Sshidokht } else { 8543525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 8553525Sshidokht return (EINVAL); 8563525Sshidokht } 8573525Sshidokht } else { 8586513Sml40262 /* if the disk is unlabeled, don't write a devid to it */ 8597563SPrasad.Singamsetty@Sun.COM if (cl->cl_label_from_media != CMLB_LABEL_VTOC) { 8606513Sml40262 mutex_exit(CMLB_MUTEX(cl)); 8616513Sml40262 return (EINVAL); 8626513Sml40262 } 8636513Sml40262 864786Slclee /* this geometry doesn't allow us to write a devid */ 8653525Sshidokht if (cl->cl_g.dkg_acyl < 2) { 8663525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 867786Slclee return (EINVAL); 868786Slclee } 869786Slclee 870786Slclee /* 871786Slclee * Subtract 2 guarantees that the next to last cylinder 872786Slclee * is used 873786Slclee */ 8743525Sshidokht cyl = cl->cl_g.dkg_ncyl + cl->cl_g.dkg_acyl - 2; 8753525Sshidokht spc = cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect; 8763525Sshidokht head = cl->cl_g.dkg_nhead - 1; 8776513Sml40262 blk = cl->cl_solaris_offset + 8786513Sml40262 (cyl * (spc - cl->cl_g.dkg_apc)) + 8793525Sshidokht (head * cl->cl_g.dkg_nsect) + 1; 880786Slclee } 8813525Sshidokht 882786Slclee *devidblockp = blk; 8833525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 884786Slclee return (0); 885786Slclee } 886786Slclee 887786Slclee /* 888786Slclee * cmlb_partinfo: 889786Slclee * Get partition info for specified partition number. 890786Slclee * 891786Slclee * Arguments: 892786Slclee * cmlbhandle cmlb handle associated with device. 893786Slclee * part partition number 894786Slclee * nblocksp pointer to number of blocks 895786Slclee * startblockp pointer to starting block 896786Slclee * partnamep pointer to name of partition 897786Slclee * tagp pointer to tag info 8983525Sshidokht * tg_cookie cookie from target driver to be passed back to target 8993525Sshidokht * driver when we call back to it through tg_ops. 900786Slclee * 901786Slclee * 902786Slclee * Notes: 903786Slclee * If in-core label is not valid, this functions tries to revalidate 904786Slclee * the label. If label is valid, it stores the total number of blocks 905786Slclee * in this partition in the area pointed to by nblocksp, starting 906786Slclee * block number in area pointed to by startblockp, pointer to partition 907786Slclee * name in area pointed to by partnamep, and tag value in area 908786Slclee * pointed by tagp. 909786Slclee * For EFI labels, tag value will be set to 0. 910786Slclee * 911786Slclee * For all nblocksp, startblockp and partnamep, tagp, a value of NULL 912786Slclee * indicates the corresponding info is not requested. 913786Slclee * 914786Slclee * 915786Slclee * Return values: 916786Slclee * 0 success 917786Slclee * EINVAL no valid label or requested partition number is invalid. 918786Slclee * 919786Slclee */ 920786Slclee int 921786Slclee cmlb_partinfo(cmlb_handle_t cmlbhandle, int part, diskaddr_t *nblocksp, 9223525Sshidokht diskaddr_t *startblockp, char **partnamep, uint16_t *tagp, void *tg_cookie) 923786Slclee { 924786Slclee 9253525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 926786Slclee int rval; 927786Slclee 9283525Sshidokht ASSERT(cl != NULL); 9293525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 9303525Sshidokht if (cl->cl_state < CMLB_ATTACHED) { 9313525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 932786Slclee return (EINVAL); 933786Slclee } 934786Slclee 935786Slclee if (part < 0 || part >= MAXPART) { 936786Slclee rval = EINVAL; 937786Slclee } else { 9383525Sshidokht if (cl->cl_f_geometry_is_valid == FALSE) 9393525Sshidokht (void) cmlb_validate_geometry((struct cmlb_lun *)cl, 0, 9403525Sshidokht 0, tg_cookie); 9413525Sshidokht 9427563SPrasad.Singamsetty@Sun.COM #if defined(_SUNOS_VTOC_16) 9437563SPrasad.Singamsetty@Sun.COM if (((cl->cl_f_geometry_is_valid == FALSE) || 9447563SPrasad.Singamsetty@Sun.COM (part < NDKMAP && cl->cl_solaris_size == 0)) && 9457563SPrasad.Singamsetty@Sun.COM (part != P0_RAW_DISK)) { 9467563SPrasad.Singamsetty@Sun.COM #else 9473525Sshidokht if ((cl->cl_f_geometry_is_valid == FALSE) || 9483525Sshidokht (part < NDKMAP && cl->cl_solaris_size == 0)) { 9497563SPrasad.Singamsetty@Sun.COM #endif 950786Slclee rval = EINVAL; 951786Slclee } else { 952786Slclee if (startblockp != NULL) 9533525Sshidokht *startblockp = (diskaddr_t)cl->cl_offset[part]; 954786Slclee 955786Slclee if (nblocksp != NULL) 956786Slclee *nblocksp = (diskaddr_t) 9573525Sshidokht cl->cl_map[part].dkl_nblk; 958786Slclee 959786Slclee if (tagp != NULL) 9603525Sshidokht if (cl->cl_cur_labeltype == CMLB_LABEL_EFI) 961786Slclee *tagp = V_UNASSIGNED; 962786Slclee else 9633525Sshidokht *tagp = cl->cl_vtoc.v_part[part].p_tag; 964786Slclee rval = 0; 965786Slclee } 966786Slclee 967786Slclee /* consistent with behavior of sd for getting minor name */ 968786Slclee if (partnamep != NULL) 969786Slclee *partnamep = dk_minor_data[part].name; 970786Slclee 971786Slclee } 972786Slclee 9733525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 974786Slclee return (rval); 975786Slclee } 976786Slclee 9776590Syl194034 /* 9786590Syl194034 * cmlb_efi_label_capacity: 9796590Syl194034 * Get capacity stored in EFI disk label. 9806590Syl194034 * 9816590Syl194034 * Arguments: 9826590Syl194034 * cmlbhandle cmlb handle associated with device. 9836590Syl194034 * capacity pointer to capacity stored in EFI disk label. 9846590Syl194034 * tg_cookie cookie from target driver to be passed back to target 9856590Syl194034 * driver when we call back to it through tg_ops. 9866590Syl194034 * 9876590Syl194034 * 9886590Syl194034 * Notes: 9896590Syl194034 * If in-core label is not valid, this functions tries to revalidate 9906590Syl194034 * the label. If label is valid and is an EFI label, it stores the capacity 9916590Syl194034 * in disk label in the area pointed to by capacity. 9926590Syl194034 * 9936590Syl194034 * 9946590Syl194034 * Return values: 9956590Syl194034 * 0 success 9966590Syl194034 * EINVAL no valid EFI label or capacity is NULL. 9976590Syl194034 * 9986590Syl194034 */ 9996590Syl194034 int 10006590Syl194034 cmlb_efi_label_capacity(cmlb_handle_t cmlbhandle, diskaddr_t *capacity, 10016590Syl194034 void *tg_cookie) 10026590Syl194034 { 10036590Syl194034 struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 10046590Syl194034 int rval; 10056590Syl194034 10066590Syl194034 ASSERT(cl != NULL); 10076590Syl194034 mutex_enter(CMLB_MUTEX(cl)); 10086590Syl194034 if (cl->cl_state < CMLB_ATTACHED) { 10096590Syl194034 mutex_exit(CMLB_MUTEX(cl)); 10106590Syl194034 return (EINVAL); 10116590Syl194034 } 10126590Syl194034 10136590Syl194034 if (cl->cl_f_geometry_is_valid == FALSE) 10146590Syl194034 (void) cmlb_validate_geometry((struct cmlb_lun *)cl, 0, 10156590Syl194034 0, tg_cookie); 10166590Syl194034 10176590Syl194034 if ((cl->cl_f_geometry_is_valid == FALSE) || (capacity == NULL) || 10186590Syl194034 (cl->cl_cur_labeltype != CMLB_LABEL_EFI)) { 10196590Syl194034 rval = EINVAL; 10206590Syl194034 } else { 10216590Syl194034 *capacity = (diskaddr_t)cl->cl_map[WD_NODE].dkl_nblk; 10226590Syl194034 rval = 0; 10236590Syl194034 } 10246590Syl194034 10256590Syl194034 mutex_exit(CMLB_MUTEX(cl)); 10266590Syl194034 return (rval); 10276590Syl194034 } 10286590Syl194034 10293525Sshidokht /* Caller should make sure Test Unit Ready succeeds before calling this. */ 10303525Sshidokht /*ARGSUSED*/ 1031786Slclee int 1032786Slclee cmlb_ioctl(cmlb_handle_t cmlbhandle, dev_t dev, int cmd, intptr_t arg, 10333525Sshidokht int flag, cred_t *cred_p, int *rval_p, void *tg_cookie) 1034786Slclee { 1035786Slclee 1036786Slclee int err; 10373525Sshidokht struct cmlb_lun *cl; 10383525Sshidokht 10393525Sshidokht cl = (struct cmlb_lun *)cmlbhandle; 10403525Sshidokht 10413525Sshidokht ASSERT(cl != NULL); 10423525Sshidokht 10433525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 10443525Sshidokht if (cl->cl_state < CMLB_ATTACHED) { 10453525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 1046786Slclee return (EIO); 1047786Slclee } 1048786Slclee 1049786Slclee switch (cmd) { 10507563SPrasad.Singamsetty@Sun.COM case DKIOCSEXTVTOC: 10513525Sshidokht case DKIOCSGEOM: 1052786Slclee case DKIOCSETEFI: 1053786Slclee case DKIOCSMBOOT: 1054786Slclee break; 10557563SPrasad.Singamsetty@Sun.COM case DKIOCSVTOC: 10567563SPrasad.Singamsetty@Sun.COM #if defined(__i386) || defined(__amd64) 10577563SPrasad.Singamsetty@Sun.COM case DKIOCPARTINFO: 10587563SPrasad.Singamsetty@Sun.COM #endif 10597563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) { 10607563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 10617563SPrasad.Singamsetty@Sun.COM return (EOVERFLOW); 10627563SPrasad.Singamsetty@Sun.COM } 10637563SPrasad.Singamsetty@Sun.COM break; 1064786Slclee default: 10657563SPrasad.Singamsetty@Sun.COM (void) cmlb_validate_geometry(cl, 1, CMLB_SILENT, 10663903Sshidokht tg_cookie); 10673525Sshidokht 10687563SPrasad.Singamsetty@Sun.COM switch (cmd) { 10697563SPrasad.Singamsetty@Sun.COM case DKIOCGVTOC: 10707563SPrasad.Singamsetty@Sun.COM case DKIOCGAPART: 10717563SPrasad.Singamsetty@Sun.COM case DKIOCSAPART: 10727563SPrasad.Singamsetty@Sun.COM 10737563SPrasad.Singamsetty@Sun.COM if (cl->cl_label_from_media == CMLB_LABEL_EFI) { 10747563SPrasad.Singamsetty@Sun.COM /* GPT label on disk */ 10757563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 10767563SPrasad.Singamsetty@Sun.COM return (ENOTSUP); 10777563SPrasad.Singamsetty@Sun.COM } else if 10787563SPrasad.Singamsetty@Sun.COM (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) { 10797563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 10807563SPrasad.Singamsetty@Sun.COM return (EOVERFLOW); 10817563SPrasad.Singamsetty@Sun.COM } 10827563SPrasad.Singamsetty@Sun.COM break; 10837563SPrasad.Singamsetty@Sun.COM 10847563SPrasad.Singamsetty@Sun.COM case DKIOCGGEOM: 10857563SPrasad.Singamsetty@Sun.COM if (cl->cl_label_from_media == CMLB_LABEL_EFI) { 10867563SPrasad.Singamsetty@Sun.COM /* GPT label on disk */ 10873525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 1088786Slclee return (ENOTSUP); 1089786Slclee } 10907563SPrasad.Singamsetty@Sun.COM break; 10917563SPrasad.Singamsetty@Sun.COM default: 10927563SPrasad.Singamsetty@Sun.COM break; 1093786Slclee } 1094786Slclee } 1095786Slclee 10963525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 1097786Slclee 1098786Slclee switch (cmd) { 1099786Slclee case DKIOCGGEOM: 11003525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGGEOM\n"); 11013525Sshidokht err = cmlb_dkio_get_geometry(cl, (caddr_t)arg, flag, tg_cookie); 1102786Slclee break; 1103786Slclee 1104786Slclee case DKIOCSGEOM: 11053525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSGEOM\n"); 11063525Sshidokht err = cmlb_dkio_set_geometry(cl, (caddr_t)arg, flag); 1107786Slclee break; 1108786Slclee 1109786Slclee case DKIOCGAPART: 11103525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGAPART\n"); 11113525Sshidokht err = cmlb_dkio_get_partition(cl, (caddr_t)arg, 11123525Sshidokht flag, tg_cookie); 1113786Slclee break; 1114786Slclee 1115786Slclee case DKIOCSAPART: 11163525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSAPART\n"); 11173525Sshidokht err = cmlb_dkio_set_partition(cl, (caddr_t)arg, flag); 1118786Slclee break; 1119786Slclee 1120786Slclee case DKIOCGVTOC: 11213525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGVTOC\n"); 11223525Sshidokht err = cmlb_dkio_get_vtoc(cl, (caddr_t)arg, flag, tg_cookie); 1123786Slclee break; 1124786Slclee 11257563SPrasad.Singamsetty@Sun.COM case DKIOCGEXTVTOC: 11267563SPrasad.Singamsetty@Sun.COM cmlb_dbg(CMLB_TRACE, cl, "DKIOCGVTOC\n"); 11277563SPrasad.Singamsetty@Sun.COM err = cmlb_dkio_get_extvtoc(cl, (caddr_t)arg, flag, tg_cookie); 11287563SPrasad.Singamsetty@Sun.COM break; 11297563SPrasad.Singamsetty@Sun.COM 1130786Slclee case DKIOCGETEFI: 11313525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGETEFI\n"); 11323525Sshidokht err = cmlb_dkio_get_efi(cl, (caddr_t)arg, flag, tg_cookie); 1133786Slclee break; 1134786Slclee 1135786Slclee case DKIOCPARTITION: 11363525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCPARTITION\n"); 11373525Sshidokht err = cmlb_dkio_partition(cl, (caddr_t)arg, flag, tg_cookie); 1138786Slclee break; 1139786Slclee 1140786Slclee case DKIOCSVTOC: 11413525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSVTOC\n"); 11423525Sshidokht err = cmlb_dkio_set_vtoc(cl, dev, (caddr_t)arg, flag, 11433525Sshidokht tg_cookie); 1144786Slclee break; 1145786Slclee 11467563SPrasad.Singamsetty@Sun.COM case DKIOCSEXTVTOC: 11477563SPrasad.Singamsetty@Sun.COM cmlb_dbg(CMLB_TRACE, cl, "DKIOCSVTOC\n"); 11487563SPrasad.Singamsetty@Sun.COM err = cmlb_dkio_set_extvtoc(cl, dev, (caddr_t)arg, flag, 11497563SPrasad.Singamsetty@Sun.COM tg_cookie); 11507563SPrasad.Singamsetty@Sun.COM break; 11517563SPrasad.Singamsetty@Sun.COM 1152786Slclee case DKIOCSETEFI: 11533525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSETEFI\n"); 11543525Sshidokht err = cmlb_dkio_set_efi(cl, dev, (caddr_t)arg, flag, tg_cookie); 1155786Slclee break; 1156786Slclee 1157786Slclee case DKIOCGMBOOT: 11583525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGMBOOT\n"); 11593525Sshidokht err = cmlb_dkio_get_mboot(cl, (caddr_t)arg, flag, tg_cookie); 1160786Slclee break; 1161786Slclee 1162786Slclee case DKIOCSMBOOT: 11633525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSMBOOT\n"); 11643525Sshidokht err = cmlb_dkio_set_mboot(cl, (caddr_t)arg, flag, tg_cookie); 1165786Slclee break; 1166786Slclee case DKIOCG_PHYGEOM: 11673525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCG_PHYGEOM\n"); 1168786Slclee #if defined(__i386) || defined(__amd64) 11693525Sshidokht err = cmlb_dkio_get_phygeom(cl, (caddr_t)arg, flag); 1170786Slclee #else 1171786Slclee err = ENOTTY; 1172786Slclee #endif 1173786Slclee break; 1174786Slclee case DKIOCG_VIRTGEOM: 11753525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCG_VIRTGEOM\n"); 1176786Slclee #if defined(__i386) || defined(__amd64) 11773525Sshidokht err = cmlb_dkio_get_virtgeom(cl, (caddr_t)arg, flag); 1178786Slclee #else 1179786Slclee err = ENOTTY; 1180786Slclee #endif 1181786Slclee break; 1182786Slclee case DKIOCPARTINFO: 11833525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCPARTINFO"); 1184786Slclee #if defined(__i386) || defined(__amd64) 11853525Sshidokht err = cmlb_dkio_partinfo(cl, dev, (caddr_t)arg, flag); 1186786Slclee #else 1187786Slclee err = ENOTTY; 1188786Slclee #endif 1189786Slclee break; 11907563SPrasad.Singamsetty@Sun.COM case DKIOCEXTPARTINFO: 11917563SPrasad.Singamsetty@Sun.COM cmlb_dbg(CMLB_TRACE, cl, "DKIOCPARTINFO"); 11927563SPrasad.Singamsetty@Sun.COM #if defined(__i386) || defined(__amd64) 11937563SPrasad.Singamsetty@Sun.COM err = cmlb_dkio_extpartinfo(cl, dev, (caddr_t)arg, flag); 11947563SPrasad.Singamsetty@Sun.COM #else 11957563SPrasad.Singamsetty@Sun.COM err = ENOTTY; 11967563SPrasad.Singamsetty@Sun.COM #endif 11977563SPrasad.Singamsetty@Sun.COM break; 1198*8333SSuhasini.Peddada@Sun.COM 1199786Slclee default: 1200786Slclee err = ENOTTY; 1201786Slclee 1202786Slclee } 12037224Scth 12047224Scth /* 12057224Scth * An ioctl that succeeds and changed ('set') size(9P) information 12067224Scth * needs to invalidate the cached devinfo snapshot to avoid having 12077224Scth * old information being returned in a snapshots. 12087224Scth * 12097224Scth * NB: When available, call ddi_change_minor_node() to clear 12107224Scth * SSIZEVALID in specfs vnodes via spec_size_invalidate(). 12117224Scth */ 12127224Scth if (err == 0) { 12137224Scth switch (cmd) { 12147224Scth case DKIOCSGEOM: 12157224Scth case DKIOCSAPART: 12167224Scth case DKIOCSVTOC: 12177563SPrasad.Singamsetty@Sun.COM case DKIOCSEXTVTOC: 12187224Scth case DKIOCSETEFI: 12197224Scth i_ddi_prop_dyn_cache_invalidate(CMLB_DEVINFO(cl), 12207224Scth i_ddi_prop_dyn_driver_get(CMLB_DEVINFO(cl))); 12217224Scth } 12227224Scth } 1223786Slclee return (err); 1224786Slclee } 1225786Slclee 1226786Slclee dev_t 12273525Sshidokht cmlb_make_device(struct cmlb_lun *cl) 1228786Slclee { 12293525Sshidokht return (makedevice(ddi_name_to_major(ddi_get_name(CMLB_DEVINFO(cl))), 12303525Sshidokht ddi_get_instance(CMLB_DEVINFO(cl)) << CMLBUNIT_SHIFT)); 1231786Slclee } 1232786Slclee 1233786Slclee /* 1234786Slclee * Function: cmlb_check_update_blockcount 1235786Slclee * 1236786Slclee * Description: If current capacity value is invalid, obtains the 1237786Slclee * current capacity from target driver. 1238786Slclee * 1239786Slclee * Return Code: 0 success 1240786Slclee * EIO failure 1241786Slclee */ 1242786Slclee static int 12433525Sshidokht cmlb_check_update_blockcount(struct cmlb_lun *cl, void *tg_cookie) 1244786Slclee { 1245786Slclee int status; 1246786Slclee diskaddr_t capacity; 12473525Sshidokht uint32_t lbasize; 12483525Sshidokht 12493525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 12503525Sshidokht 12513525Sshidokht if (cl->cl_f_geometry_is_valid == FALSE) { 12523525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 12533525Sshidokht status = DK_TG_GETCAP(cl, &capacity, tg_cookie); 12543525Sshidokht if (status != 0) { 12553525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 12563525Sshidokht return (EIO); 12573525Sshidokht } 12583525Sshidokht 12593525Sshidokht status = DK_TG_GETBLOCKSIZE(cl, &lbasize, tg_cookie); 12603525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 12613525Sshidokht if (status != 0) 12623525Sshidokht return (EIO); 12633525Sshidokht 12643525Sshidokht if ((capacity != 0) && (lbasize != 0)) { 12653525Sshidokht cl->cl_blockcount = capacity; 12663525Sshidokht cl->cl_tgt_blocksize = lbasize; 1267786Slclee return (0); 1268786Slclee } else 1269786Slclee return (EIO); 1270786Slclee } else 1271786Slclee return (0); 1272786Slclee } 1273786Slclee 12746318Sedp static int 12756318Sedp cmlb_create_minor(dev_info_t *dip, char *name, int spec_type, 12766318Sedp minor_t minor_num, char *node_type, int flag, boolean_t internal) 12776318Sedp { 12786318Sedp if (internal) 12796318Sedp return (ddi_create_internal_pathname(dip, 12806318Sedp name, spec_type, minor_num)); 12816318Sedp else 12826318Sedp return (ddi_create_minor_node(dip, 12836318Sedp name, spec_type, minor_num, node_type, flag)); 12846318Sedp } 12856318Sedp 1286786Slclee /* 1287786Slclee * Function: cmlb_create_minor_nodes 1288786Slclee * 1289786Slclee * Description: Create or adjust the minor device nodes for the instance. 1290786Slclee * Minor nodes are created based on default label type, 1291786Slclee * current label type and last label type we created 1292786Slclee * minor nodes based on. 1293786Slclee * 1294786Slclee * 12953525Sshidokht * Arguments: cl - driver soft state (unit) structure 1296786Slclee * 1297786Slclee * Return Code: 0 success 1298786Slclee * ENXIO failure. 1299786Slclee * 1300786Slclee * Context: Kernel thread context 1301786Slclee */ 1302786Slclee static int 13033525Sshidokht cmlb_create_minor_nodes(struct cmlb_lun *cl) 1304786Slclee { 1305786Slclee struct driver_minor_data *dmdp; 1306786Slclee int instance; 1307786Slclee char name[48]; 1308786Slclee cmlb_label_t newlabeltype; 13096318Sedp boolean_t internal; 1310786Slclee 13113525Sshidokht ASSERT(cl != NULL); 13123525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 1313786Slclee 13146318Sedp internal = ((cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0); 1315786Slclee 1316786Slclee /* check the most common case */ 13173525Sshidokht if (cl->cl_cur_labeltype != CMLB_LABEL_UNDEF && 13183525Sshidokht cl->cl_last_labeltype == cl->cl_cur_labeltype) { 1319786Slclee /* do nothing */ 1320786Slclee return (0); 1321786Slclee } 1322786Slclee 13233525Sshidokht if (cl->cl_def_labeltype == CMLB_LABEL_UNDEF) { 1324786Slclee /* we should never get here */ 1325786Slclee return (ENXIO); 1326786Slclee } 1327786Slclee 13283525Sshidokht if (cl->cl_last_labeltype == CMLB_LABEL_UNDEF) { 1329786Slclee /* first time during attach */ 13303525Sshidokht newlabeltype = cl->cl_def_labeltype; 13313525Sshidokht 13323525Sshidokht instance = ddi_get_instance(CMLB_DEVINFO(cl)); 1333786Slclee 1334786Slclee /* Create all the minor nodes for this target. */ 1335786Slclee dmdp = (newlabeltype == CMLB_LABEL_EFI) ? dk_minor_data_efi : 1336786Slclee dk_minor_data; 1337786Slclee while (dmdp->name != NULL) { 1338786Slclee 1339786Slclee (void) sprintf(name, "%s", dmdp->name); 1340786Slclee 13416318Sedp if (cmlb_create_minor(CMLB_DEVINFO(cl), name, 1342786Slclee dmdp->type, 1343786Slclee (instance << CMLBUNIT_SHIFT) | dmdp->minor, 13446318Sedp cl->cl_node_type, NULL, internal) == DDI_FAILURE) { 1345786Slclee /* 1346786Slclee * Clean up any nodes that may have been 1347786Slclee * created, in case this fails in the middle 1348786Slclee * of the loop. 1349786Slclee */ 13503525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL); 1351786Slclee return (ENXIO); 1352786Slclee } 1353786Slclee dmdp++; 1354786Slclee } 13553525Sshidokht cl->cl_last_labeltype = newlabeltype; 1356786Slclee return (0); 1357786Slclee } 1358786Slclee 1359786Slclee /* Not first time */ 13603525Sshidokht if (cl->cl_cur_labeltype == CMLB_LABEL_UNDEF) { 13613525Sshidokht if (cl->cl_last_labeltype != cl->cl_def_labeltype) { 1362786Slclee /* close time, revert to default. */ 13633525Sshidokht newlabeltype = cl->cl_def_labeltype; 1364786Slclee } else { 1365786Slclee /* 1366786Slclee * do nothing since the type for which we last created 1367786Slclee * nodes matches the default 1368786Slclee */ 1369786Slclee return (0); 1370786Slclee } 1371786Slclee } else { 13723525Sshidokht if (cl->cl_cur_labeltype != cl->cl_last_labeltype) { 1373786Slclee /* We are not closing, use current label type */ 13743525Sshidokht newlabeltype = cl->cl_cur_labeltype; 1375786Slclee } else { 1376786Slclee /* 1377786Slclee * do nothing since the type for which we last created 1378786Slclee * nodes matches the current label type 1379786Slclee */ 1380786Slclee return (0); 1381786Slclee } 1382786Slclee } 1383786Slclee 13843525Sshidokht instance = ddi_get_instance(CMLB_DEVINFO(cl)); 1385786Slclee 1386786Slclee /* 1387786Slclee * Currently we only fix up the s7 node when we are switching 1388786Slclee * label types from or to EFI. This is consistent with 1389786Slclee * current behavior of sd. 1390786Slclee */ 1391786Slclee if (newlabeltype == CMLB_LABEL_EFI && 13923525Sshidokht cl->cl_last_labeltype != CMLB_LABEL_EFI) { 1393786Slclee /* from vtoc to EFI */ 13943525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "h"); 13953525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw"); 13966318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd", 1397786Slclee S_IFBLK, (instance << CMLBUNIT_SHIFT) | WD_NODE, 13986318Sedp cl->cl_node_type, NULL, internal); 13996318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd,raw", 1400786Slclee S_IFCHR, (instance << CMLBUNIT_SHIFT) | WD_NODE, 14016318Sedp cl->cl_node_type, NULL, internal); 1402786Slclee } else { 1403786Slclee /* from efi to vtoc */ 14043525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd"); 14053525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd,raw"); 14066318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h", 1407786Slclee S_IFBLK, (instance << CMLBUNIT_SHIFT) | WD_NODE, 14086318Sedp cl->cl_node_type, NULL, internal); 14096318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h,raw", 1410786Slclee S_IFCHR, (instance << CMLBUNIT_SHIFT) | WD_NODE, 14116318Sedp cl->cl_node_type, NULL, internal); 1412786Slclee } 1413786Slclee 14143525Sshidokht cl->cl_last_labeltype = newlabeltype; 1415786Slclee return (0); 1416786Slclee } 1417786Slclee 1418786Slclee /* 1419786Slclee * Function: cmlb_validate_geometry 1420786Slclee * 1421786Slclee * Description: Read the label from the disk (if present). Update the unit's 1422786Slclee * geometry and vtoc information from the data in the label. 1423786Slclee * Verify that the label is valid. 1424786Slclee * 14253525Sshidokht * Arguments: 14263525Sshidokht * cl driver soft state (unit) structure 14273525Sshidokht * 14283525Sshidokht * forcerevalid force revalidation even if we are already valid. 14293525Sshidokht * flags operation flags from target driver. Used for verbosity 14303525Sshidokht * control at this time. 14313525Sshidokht * tg_cookie cookie from target driver to be passed back to target 14323525Sshidokht * driver when we call back to it through tg_ops. 1433786Slclee * 1434786Slclee * Return Code: 0 - Successful completion 14353525Sshidokht * EINVAL - Invalid value in cl->cl_tgt_blocksize or 14363525Sshidokht * cl->cl_blockcount; or label on disk is corrupted 1437786Slclee * or unreadable. 1438786Slclee * EACCES - Reservation conflict at the device. 1439786Slclee * ENOMEM - Resource allocation error 1440786Slclee * ENOTSUP - geometry not applicable 1441786Slclee * 1442786Slclee * Context: Kernel thread only (can sleep). 1443786Slclee */ 1444786Slclee static int 14453525Sshidokht cmlb_validate_geometry(struct cmlb_lun *cl, int forcerevalid, int flags, 14463525Sshidokht void *tg_cookie) 1447786Slclee { 1448786Slclee int label_error = 0; 1449786Slclee diskaddr_t capacity; 1450786Slclee int count; 14513525Sshidokht 14523525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 14533525Sshidokht 14543525Sshidokht if ((cl->cl_f_geometry_is_valid == TRUE) && (forcerevalid == 0)) { 14553525Sshidokht if (cl->cl_cur_labeltype == CMLB_LABEL_EFI) 1456786Slclee return (ENOTSUP); 1457786Slclee return (0); 1458786Slclee } 1459786Slclee 14603525Sshidokht if (cmlb_check_update_blockcount(cl, tg_cookie) != 0) 1461786Slclee return (EIO); 1462786Slclee 14633525Sshidokht capacity = cl->cl_blockcount; 1464786Slclee 1465786Slclee #if defined(_SUNOS_VTOC_16) 1466786Slclee /* 1467786Slclee * Set up the "whole disk" fdisk partition; this should always 1468786Slclee * exist, regardless of whether the disk contains an fdisk table 1469786Slclee * or vtoc. 1470786Slclee */ 14713525Sshidokht cl->cl_map[P0_RAW_DISK].dkl_cylno = 0; 14727563SPrasad.Singamsetty@Sun.COM cl->cl_offset[P0_RAW_DISK] = 0; 1473786Slclee /* 14747563SPrasad.Singamsetty@Sun.COM * note if capacity > int32_max(1TB) we are in 64bit environment 14757563SPrasad.Singamsetty@Sun.COM * so no truncation happens 1476786Slclee */ 14773525Sshidokht cl->cl_map[P0_RAW_DISK].dkl_nblk = capacity; 1478786Slclee #endif 1479786Slclee /* 1480786Slclee * Refresh the logical and physical geometry caches. 1481786Slclee * (data from MODE SENSE format/rigid disk geometry pages, 1482786Slclee * and scsi_ifgetcap("geometry"). 1483786Slclee */ 14843525Sshidokht cmlb_resync_geom_caches(cl, capacity, tg_cookie); 14853525Sshidokht 14867563SPrasad.Singamsetty@Sun.COM cl->cl_label_from_media = CMLB_LABEL_UNDEF; 14873525Sshidokht label_error = cmlb_use_efi(cl, capacity, flags, tg_cookie); 1488786Slclee if (label_error == 0) { 1489786Slclee 1490786Slclee /* found a valid EFI label */ 14913525Sshidokht cmlb_dbg(CMLB_TRACE, cl, 1492786Slclee "cmlb_validate_geometry: found EFI label\n"); 1493786Slclee /* 1494786Slclee * solaris_size and geometry_is_valid are set in 1495786Slclee * cmlb_use_efi 1496786Slclee */ 1497786Slclee return (ENOTSUP); 1498786Slclee } 1499786Slclee 1500786Slclee /* NO EFI label found */ 1501786Slclee 15027563SPrasad.Singamsetty@Sun.COM if (capacity > CMLB_EXTVTOC_LIMIT) { 1503786Slclee if (label_error == ESRCH) { 1504786Slclee /* 15057563SPrasad.Singamsetty@Sun.COM * they've configured a LUN over 2TB, but used 1506786Slclee * format.dat to restrict format's view of the 15077563SPrasad.Singamsetty@Sun.COM * capacity to be under 2TB in some earlier Solaris 15087563SPrasad.Singamsetty@Sun.COM * release. 1509786Slclee */ 15107563SPrasad.Singamsetty@Sun.COM /* i.e > 2TB with a VTOC < 2TB */ 15117563SPrasad.Singamsetty@Sun.COM if (!(flags & CMLB_SILENT) && 15127563SPrasad.Singamsetty@Sun.COM (cl->cl_msglog_flag & CMLB_ALLOW_2TB_WARN)) { 15133525Sshidokht 15143525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), 15157563SPrasad.Singamsetty@Sun.COM CE_NOTE, "!Disk (%s%d) is limited to 2 TB " 15167563SPrasad.Singamsetty@Sun.COM "due to VTOC label. To use the full " 15177563SPrasad.Singamsetty@Sun.COM "capacity of the disk, use format(1M) to " 15187563SPrasad.Singamsetty@Sun.COM "relabel the disk with EFI/GPT label.\n", 15197563SPrasad.Singamsetty@Sun.COM CMLB_LABEL(cl), 15207563SPrasad.Singamsetty@Sun.COM ddi_get_instance(CMLB_DEVINFO(cl))); 15217563SPrasad.Singamsetty@Sun.COM 15227563SPrasad.Singamsetty@Sun.COM cl->cl_msglog_flag &= ~CMLB_ALLOW_2TB_WARN; 15233525Sshidokht } 1524786Slclee } else { 15253525Sshidokht return (ENOTSUP); 1526786Slclee } 1527786Slclee } 1528786Slclee 1529786Slclee label_error = 0; 1530786Slclee 1531786Slclee /* 1532786Slclee * at this point it is either labeled with a VTOC or it is 15333525Sshidokht * under 1TB (<= 1TB actually for off-by-1) 1534786Slclee */ 1535786Slclee 1536786Slclee /* 15373525Sshidokht * Only DIRECT ACCESS devices will have Scl labels. 15383525Sshidokht * CD's supposedly have a Scl label, too 1539786Slclee */ 15403525Sshidokht if (cl->cl_device_type == DTYPE_DIRECT || ISREMOVABLE(cl)) { 1541786Slclee struct dk_label *dkl; 1542786Slclee offset_t label_addr; 1543786Slclee int rval; 1544786Slclee size_t buffer_size; 1545786Slclee 1546786Slclee /* 15473525Sshidokht * Note: This will set up cl->cl_solaris_size and 15483525Sshidokht * cl->cl_solaris_offset. 1549786Slclee */ 15503525Sshidokht rval = cmlb_read_fdisk(cl, capacity, tg_cookie); 15513525Sshidokht if ((rval != 0) && !ISCD(cl)) { 15523525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 1553786Slclee return (rval); 1554786Slclee } 1555786Slclee 15563525Sshidokht if (cl->cl_solaris_size <= DK_LABEL_LOC) { 1557786Slclee /* 1558786Slclee * Found fdisk table but no Solaris partition entry, 1559786Slclee * so don't call cmlb_uselabel() and don't create 1560786Slclee * a default label. 1561786Slclee */ 1562786Slclee label_error = 0; 15633525Sshidokht cl->cl_f_geometry_is_valid = TRUE; 1564786Slclee goto no_solaris_partition; 1565786Slclee } 1566786Slclee 15673525Sshidokht label_addr = (daddr_t)(cl->cl_solaris_offset + DK_LABEL_LOC); 15683525Sshidokht 1569786Slclee buffer_size = sizeof (struct dk_label); 1570786Slclee 15713525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "cmlb_validate_geometry: " 1572786Slclee "label_addr: 0x%x allocation size: 0x%x\n", 1573786Slclee label_addr, buffer_size); 1574786Slclee 1575786Slclee if ((dkl = kmem_zalloc(buffer_size, KM_NOSLEEP)) == NULL) 1576786Slclee return (ENOMEM); 1577786Slclee 15783525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 15793525Sshidokht rval = DK_TG_READ(cl, dkl, label_addr, buffer_size, tg_cookie); 15803525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 1581786Slclee 1582786Slclee switch (rval) { 1583786Slclee case 0: 1584786Slclee /* 1585786Slclee * cmlb_uselabel will establish that the geometry 1586786Slclee * is valid. 1587786Slclee */ 15883525Sshidokht if (cmlb_uselabel(cl, 15893525Sshidokht (struct dk_label *)(uintptr_t)dkl, flags) != 1590786Slclee CMLB_LABEL_IS_VALID) { 1591786Slclee label_error = EINVAL; 1592786Slclee } else 15937563SPrasad.Singamsetty@Sun.COM cl->cl_label_from_media = CMLB_LABEL_VTOC; 1594786Slclee break; 1595786Slclee case EACCES: 1596786Slclee label_error = EACCES; 1597786Slclee break; 1598786Slclee default: 1599786Slclee label_error = EINVAL; 1600786Slclee break; 1601786Slclee } 1602786Slclee 1603786Slclee kmem_free(dkl, buffer_size); 1604786Slclee } 1605786Slclee 1606786Slclee /* 1607786Slclee * If a valid label was not found, AND if no reservation conflict 1608786Slclee * was detected, then go ahead and create a default label (4069506). 1609786Slclee * 1610786Slclee * Note: currently, for VTOC_8 devices, the default label is created 16113525Sshidokht * for removables and hotpluggables only. For VTOC_16 devices, the 16123525Sshidokht * default label will be created for all devices. 1613786Slclee * (see cmlb_build_default_label) 1614786Slclee */ 1615786Slclee #if defined(_SUNOS_VTOC_8) 16163525Sshidokht if ((ISREMOVABLE(cl) || ISHOTPLUGGABLE(cl)) && 16173525Sshidokht (label_error != EACCES)) { 1618786Slclee #elif defined(_SUNOS_VTOC_16) 1619786Slclee if (label_error != EACCES) { 1620786Slclee #endif 16213525Sshidokht if (cl->cl_f_geometry_is_valid == FALSE) { 16223525Sshidokht cmlb_build_default_label(cl, tg_cookie); 1623786Slclee } 1624786Slclee label_error = 0; 1625786Slclee } 1626786Slclee 1627786Slclee no_solaris_partition: 1628786Slclee 1629786Slclee #if defined(_SUNOS_VTOC_16) 1630786Slclee /* 1631786Slclee * If we have valid geometry, set up the remaining fdisk partitions. 1632786Slclee * Note that dkl_cylno is not used for the fdisk map entries, so 1633786Slclee * we set it to an entirely bogus value. 1634786Slclee */ 1635*8333SSuhasini.Peddada@Sun.COM for (count = 0; count < FD_NUMPART; count++) { 16367563SPrasad.Singamsetty@Sun.COM cl->cl_map[FDISK_P1 + count].dkl_cylno = UINT16_MAX; 16373525Sshidokht cl->cl_map[FDISK_P1 + count].dkl_nblk = 16383525Sshidokht cl->cl_fmap[count].fmap_nblk; 16393525Sshidokht 16403525Sshidokht cl->cl_offset[FDISK_P1 + count] = 16413525Sshidokht cl->cl_fmap[count].fmap_start; 1642786Slclee } 1643786Slclee #endif 1644786Slclee 1645786Slclee for (count = 0; count < NDKMAP; count++) { 1646786Slclee #if defined(_SUNOS_VTOC_8) 16473525Sshidokht struct dk_map *lp = &cl->cl_map[count]; 16483525Sshidokht cl->cl_offset[count] = 16493525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno; 1650786Slclee #elif defined(_SUNOS_VTOC_16) 16513525Sshidokht struct dkl_partition *vp = &cl->cl_vtoc.v_part[count]; 16523525Sshidokht 16533525Sshidokht cl->cl_offset[count] = vp->p_start + cl->cl_solaris_offset; 1654786Slclee #else 1655786Slclee #error "No VTOC format defined." 1656786Slclee #endif 1657786Slclee } 1658786Slclee 1659786Slclee return (label_error); 1660786Slclee } 1661786Slclee 1662786Slclee #if defined(_SUNOS_VTOC_16) 1663786Slclee /* 1664786Slclee * Function: cmlb_convert_geometry 1665786Slclee * 1666786Slclee * Description: Convert physical geometry into a dk_geom structure. In 1667786Slclee * other words, make sure we don't wrap 16-bit values. 1668786Slclee * e.g. converting from geom_cache to dk_geom 1669786Slclee * 1670786Slclee * Context: Kernel thread only 1671786Slclee */ 1672786Slclee static void 16733525Sshidokht cmlb_convert_geometry(diskaddr_t capacity, struct dk_geom *cl_g) 1674786Slclee { 1675786Slclee 1676786Slclee /* Unlabeled SCSI floppy device */ 1677786Slclee if (capacity <= 0x1000) { 16783525Sshidokht cl_g->dkg_nhead = 2; 16793525Sshidokht cl_g->dkg_ncyl = 80; 16803525Sshidokht cl_g->dkg_nsect = capacity / (cl_g->dkg_nhead * cl_g->dkg_ncyl); 1681786Slclee return; 1682786Slclee } 1683786Slclee 1684786Slclee /* 16857563SPrasad.Singamsetty@Sun.COM * For all devices we calculate cylinders using the heads and sectors 16867563SPrasad.Singamsetty@Sun.COM * we assign based on capacity of the device. The algorithm is 16877563SPrasad.Singamsetty@Sun.COM * designed to be compatible with the way other operating systems 16887563SPrasad.Singamsetty@Sun.COM * lay out fdisk tables for X86 and to insure that the cylinders never 16897563SPrasad.Singamsetty@Sun.COM * exceed 65535 to prevent problems with X86 ioctls that report 16907563SPrasad.Singamsetty@Sun.COM * geometry. 16917563SPrasad.Singamsetty@Sun.COM * For some smaller disk sizes we report geometry that matches those 16927563SPrasad.Singamsetty@Sun.COM * used by X86 BIOS usage. For larger disks, we use SPT that are 16937563SPrasad.Singamsetty@Sun.COM * multiples of 63, since other OSes that are not limited to 16-bits 16947563SPrasad.Singamsetty@Sun.COM * for cylinders stop at 63 SPT we make do by using multiples of 63 SPT. 16957563SPrasad.Singamsetty@Sun.COM * 16967563SPrasad.Singamsetty@Sun.COM * The following table (in order) illustrates some end result 16977563SPrasad.Singamsetty@Sun.COM * calculations: 16987563SPrasad.Singamsetty@Sun.COM * 16997563SPrasad.Singamsetty@Sun.COM * Maximum number of blocks nhead nsect 1700786Slclee * 17017563SPrasad.Singamsetty@Sun.COM * 2097152 (1GB) 64 32 17027563SPrasad.Singamsetty@Sun.COM * 16777216 (8GB) 128 32 17037563SPrasad.Singamsetty@Sun.COM * 1052819775 (502.02GB) 255 63 17047563SPrasad.Singamsetty@Sun.COM * 2105639550 (0.98TB) 255 126 17057563SPrasad.Singamsetty@Sun.COM * 3158459325 (1.47TB) 255 189 17067563SPrasad.Singamsetty@Sun.COM * 4211279100 (1.96TB) 255 252 17077563SPrasad.Singamsetty@Sun.COM * 5264098875 (2.45TB) 255 315 17087563SPrasad.Singamsetty@Sun.COM * ... 1709786Slclee */ 17107563SPrasad.Singamsetty@Sun.COM 17117563SPrasad.Singamsetty@Sun.COM if (capacity <= 0x200000) { 17127563SPrasad.Singamsetty@Sun.COM cl_g->dkg_nhead = 64; 17137563SPrasad.Singamsetty@Sun.COM cl_g->dkg_nsect = 32; 17147563SPrasad.Singamsetty@Sun.COM } else if (capacity <= 0x01000000) { 17157563SPrasad.Singamsetty@Sun.COM cl_g->dkg_nhead = 128; 17167563SPrasad.Singamsetty@Sun.COM cl_g->dkg_nsect = 32; 17177563SPrasad.Singamsetty@Sun.COM } else { 17187563SPrasad.Singamsetty@Sun.COM cl_g->dkg_nhead = 255; 17197563SPrasad.Singamsetty@Sun.COM 17207563SPrasad.Singamsetty@Sun.COM /* make nsect be smallest multiple of 63 */ 17217563SPrasad.Singamsetty@Sun.COM cl_g->dkg_nsect = ((capacity + 17227563SPrasad.Singamsetty@Sun.COM (UINT16_MAX * 255 * 63) - 1) / 17237563SPrasad.Singamsetty@Sun.COM (UINT16_MAX * 255 * 63)) * 63; 17247563SPrasad.Singamsetty@Sun.COM 17257563SPrasad.Singamsetty@Sun.COM if (cl_g->dkg_nsect == 0) 17267563SPrasad.Singamsetty@Sun.COM cl_g->dkg_nsect = (UINT16_MAX / 63) * 63; 17277563SPrasad.Singamsetty@Sun.COM } 17287563SPrasad.Singamsetty@Sun.COM 1729786Slclee } 1730786Slclee #endif 1731786Slclee 1732786Slclee /* 1733786Slclee * Function: cmlb_resync_geom_caches 1734786Slclee * 1735786Slclee * Description: (Re)initialize both geometry caches: the virtual geometry 1736786Slclee * information is extracted from the HBA (the "geometry" 1737786Slclee * capability), and the physical geometry cache data is 1738786Slclee * generated by issuing MODE SENSE commands. 1739786Slclee * 17403525Sshidokht * Arguments: 17413525Sshidokht * cl driver soft state (unit) structure 17423525Sshidokht * capacity disk capacity in #blocks 17433525Sshidokht * tg_cookie cookie from target driver to be passed back to target 17443525Sshidokht * driver when we call back to it through tg_ops. 1745786Slclee * 1746786Slclee * Context: Kernel thread only (can sleep). 1747786Slclee */ 1748786Slclee static void 17493525Sshidokht cmlb_resync_geom_caches(struct cmlb_lun *cl, diskaddr_t capacity, 17503525Sshidokht void *tg_cookie) 1751786Slclee { 1752786Slclee struct cmlb_geom pgeom; 1753786Slclee struct cmlb_geom lgeom; 1754786Slclee struct cmlb_geom *pgeomp = &pgeom; 1755786Slclee unsigned short nhead; 1756786Slclee unsigned short nsect; 1757786Slclee int spc; 1758786Slclee int ret; 1759786Slclee 17603525Sshidokht ASSERT(cl != NULL); 17613525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 1762786Slclee 1763786Slclee /* 1764786Slclee * Ask the controller for its logical geometry. 1765786Slclee * Note: if the HBA does not support scsi_ifgetcap("geometry"), 1766786Slclee * then the lgeom cache will be invalid. 1767786Slclee */ 17683525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 1769786Slclee bzero(&lgeom, sizeof (struct cmlb_geom)); 17703525Sshidokht ret = DK_TG_GETVIRTGEOM(cl, &lgeom, tg_cookie); 17713525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 17723525Sshidokht 17733525Sshidokht bcopy(&lgeom, &cl->cl_lgeom, sizeof (cl->cl_lgeom)); 1774786Slclee 1775786Slclee /* 1776786Slclee * Initialize the pgeom cache from lgeom, so that if MODE SENSE 1777786Slclee * doesn't work, DKIOCG_PHYSGEOM can return reasonable values. 1778786Slclee */ 17793525Sshidokht if (ret != 0 || cl->cl_lgeom.g_nsect == 0 || 17803525Sshidokht cl->cl_lgeom.g_nhead == 0) { 1781786Slclee /* 1782786Slclee * Note: Perhaps this needs to be more adaptive? The rationale 1783786Slclee * is that, if there's no HBA geometry from the HBA driver, any 1784786Slclee * guess is good, since this is the physical geometry. If MODE 1785786Slclee * SENSE fails this gives a max cylinder size for non-LBA access 1786786Slclee */ 1787786Slclee nhead = 255; 1788786Slclee nsect = 63; 1789786Slclee } else { 17903525Sshidokht nhead = cl->cl_lgeom.g_nhead; 17913525Sshidokht nsect = cl->cl_lgeom.g_nsect; 1792786Slclee } 1793786Slclee 17943525Sshidokht if (ISCD(cl)) { 1795786Slclee pgeomp->g_nhead = 1; 1796786Slclee pgeomp->g_nsect = nsect * nhead; 1797786Slclee } else { 1798786Slclee pgeomp->g_nhead = nhead; 1799786Slclee pgeomp->g_nsect = nsect; 1800786Slclee } 1801786Slclee 1802786Slclee spc = pgeomp->g_nhead * pgeomp->g_nsect; 1803786Slclee pgeomp->g_capacity = capacity; 1804786Slclee pgeomp->g_ncyl = pgeomp->g_capacity / spc; 1805786Slclee pgeomp->g_acyl = 0; 1806786Slclee 1807786Slclee /* 1808786Slclee * Retrieve fresh geometry data from the hardware, stash it 1809786Slclee * here temporarily before we rebuild the incore label. 1810786Slclee * 1811786Slclee * We want to use the MODE SENSE commands to derive the 1812786Slclee * physical geometry of the device, but if either command 1813786Slclee * fails, the logical geometry is used as the fallback for 1814786Slclee * disk label geometry. 1815786Slclee */ 1816786Slclee 18173525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 18183525Sshidokht (void) DK_TG_GETPHYGEOM(cl, pgeomp, tg_cookie); 18193525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 1820786Slclee 1821786Slclee /* 1822786Slclee * Now update the real copy while holding the mutex. This 1823786Slclee * way the global copy is never in an inconsistent state. 1824786Slclee */ 18253525Sshidokht bcopy(pgeomp, &cl->cl_pgeom, sizeof (cl->cl_pgeom)); 18263525Sshidokht 18273525Sshidokht cmlb_dbg(CMLB_INFO, cl, "cmlb_resync_geom_caches: " 1828786Slclee "(cached from lgeom)\n"); 18293525Sshidokht cmlb_dbg(CMLB_INFO, cl, 1830786Slclee " ncyl: %ld; acyl: %d; nhead: %d; nsect: %d\n", 18313525Sshidokht cl->cl_pgeom.g_ncyl, cl->cl_pgeom.g_acyl, 18323525Sshidokht cl->cl_pgeom.g_nhead, cl->cl_pgeom.g_nsect); 18333525Sshidokht cmlb_dbg(CMLB_INFO, cl, " lbasize: %d; capacity: %ld; " 18343525Sshidokht "intrlv: %d; rpm: %d\n", cl->cl_pgeom.g_secsize, 18353525Sshidokht cl->cl_pgeom.g_capacity, cl->cl_pgeom.g_intrlv, 18363525Sshidokht cl->cl_pgeom.g_rpm); 1837786Slclee } 1838786Slclee 1839786Slclee 1840786Slclee /* 1841786Slclee * Function: cmlb_read_fdisk 1842786Slclee * 1843786Slclee * Description: utility routine to read the fdisk table. 1844786Slclee * 18453525Sshidokht * Arguments: 18463525Sshidokht * cl driver soft state (unit) structure 18473525Sshidokht * capacity disk capacity in #blocks 18483525Sshidokht * tg_cookie cookie from target driver to be passed back to target 18493525Sshidokht * driver when we call back to it through tg_ops. 1850786Slclee * 1851786Slclee * Return Code: 0 for success (includes not reading for no_fdisk_present case 1852786Slclee * errnos from tg_rw if failed to read the first block. 1853786Slclee * 1854786Slclee * Context: Kernel thread only (can sleep). 1855786Slclee */ 18563525Sshidokht /*ARGSUSED*/ 1857786Slclee static int 18583525Sshidokht cmlb_read_fdisk(struct cmlb_lun *cl, diskaddr_t capacity, void *tg_cookie) 1859786Slclee { 1860786Slclee #if defined(_NO_FDISK_PRESENT) 1861786Slclee 18623525Sshidokht cl->cl_solaris_offset = 0; 18633525Sshidokht cl->cl_solaris_size = capacity; 18643525Sshidokht bzero(cl->cl_fmap, sizeof (struct fmap) * FD_NUMPART); 1865786Slclee return (0); 1866786Slclee 1867786Slclee #elif defined(_FIRMWARE_NEEDS_FDISK) 1868786Slclee 1869786Slclee struct ipart *fdp; 1870786Slclee struct mboot *mbp; 1871786Slclee struct ipart fdisk[FD_NUMPART]; 1872*8333SSuhasini.Peddada@Sun.COM int i; 1873786Slclee char sigbuf[2]; 1874786Slclee caddr_t bufp; 1875786Slclee int uidx; 1876786Slclee int rval; 1877786Slclee int lba = 0; 1878786Slclee uint_t solaris_offset; /* offset to solaris part. */ 1879786Slclee daddr_t solaris_size; /* size of solaris partition */ 1880786Slclee uint32_t blocksize; 1881786Slclee 18823525Sshidokht ASSERT(cl != NULL); 18833525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 1884786Slclee 1885786Slclee /* 1886786Slclee * Start off assuming no fdisk table 1887786Slclee */ 1888786Slclee solaris_offset = 0; 1889786Slclee solaris_size = capacity; 1890786Slclee 18913525Sshidokht blocksize = cl->cl_tgt_blocksize; 1892786Slclee 1893786Slclee bufp = kmem_zalloc(blocksize, KM_SLEEP); 1894786Slclee 18953525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 18963525Sshidokht rval = DK_TG_READ(cl, bufp, 0, blocksize, tg_cookie); 18973525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 1898786Slclee 1899786Slclee if (rval != 0) { 19003525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 1901786Slclee "cmlb_read_fdisk: fdisk read err\n"); 19023525Sshidokht bzero(cl->cl_fmap, sizeof (struct fmap) * FD_NUMPART); 19033525Sshidokht goto done; 1904786Slclee } 1905786Slclee 1906786Slclee mbp = (struct mboot *)bufp; 1907786Slclee 1908786Slclee /* 1909786Slclee * The fdisk table does not begin on a 4-byte boundary within the 1910786Slclee * master boot record, so we copy it to an aligned structure to avoid 1911786Slclee * alignment exceptions on some processors. 1912786Slclee */ 1913786Slclee bcopy(&mbp->parts[0], fdisk, sizeof (fdisk)); 1914786Slclee 1915786Slclee /* 1916786Slclee * Check for lba support before verifying sig; sig might not be 1917786Slclee * there, say on a blank disk, but the max_chs mark may still 1918786Slclee * be present. 1919786Slclee * 1920786Slclee * Note: LBA support and BEFs are an x86-only concept but this 1921786Slclee * code should work OK on SPARC as well. 1922786Slclee */ 1923786Slclee 1924786Slclee /* 1925786Slclee * First, check for lba-access-ok on root node (or prom root node) 1926786Slclee * if present there, don't need to search fdisk table. 1927786Slclee */ 1928786Slclee if (ddi_getprop(DDI_DEV_T_ANY, ddi_root_node(), 0, 1929786Slclee "lba-access-ok", 0) != 0) { 1930786Slclee /* All drives do LBA; don't search fdisk table */ 1931786Slclee lba = 1; 1932786Slclee } else { 1933786Slclee /* Okay, look for mark in fdisk table */ 1934786Slclee for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) { 1935786Slclee /* accumulate "lba" value from all partitions */ 1936786Slclee lba = (lba || cmlb_has_max_chs_vals(fdp)); 1937786Slclee } 1938786Slclee } 1939786Slclee 1940786Slclee if (lba != 0) { 19413525Sshidokht dev_t dev = cmlb_make_device(cl); 19423525Sshidokht 19433525Sshidokht if (ddi_getprop(dev, CMLB_DEVINFO(cl), DDI_PROP_DONTPASS, 1944786Slclee "lba-access-ok", 0) == 0) { 1945786Slclee /* not found; create it */ 19463525Sshidokht if (ddi_prop_create(dev, CMLB_DEVINFO(cl), 0, 1947786Slclee "lba-access-ok", (caddr_t)NULL, 0) != 1948786Slclee DDI_PROP_SUCCESS) { 19493525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 1950786Slclee "cmlb_read_fdisk: Can't create lba " 1951786Slclee "property for instance %d\n", 19523525Sshidokht ddi_get_instance(CMLB_DEVINFO(cl))); 1953786Slclee } 1954786Slclee } 1955786Slclee } 1956786Slclee 1957786Slclee bcopy(&mbp->signature, sigbuf, sizeof (sigbuf)); 1958786Slclee 1959786Slclee /* 1960786Slclee * Endian-independent signature check 1961786Slclee */ 1962786Slclee if (((sigbuf[1] & 0xFF) != ((MBB_MAGIC >> 8) & 0xFF)) || 1963786Slclee (sigbuf[0] != (MBB_MAGIC & 0xFF))) { 19643525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 1965786Slclee "cmlb_read_fdisk: no fdisk\n"); 19663525Sshidokht bzero(cl->cl_fmap, sizeof (struct fmap) * FD_NUMPART); 1967786Slclee goto done; 1968786Slclee } 1969786Slclee 1970786Slclee #ifdef CMLBDEBUG 19713525Sshidokht if (cmlb_level_mask & CMLB_LOGMASK_INFO) { 1972786Slclee fdp = fdisk; 19733525Sshidokht cmlb_dbg(CMLB_INFO, cl, "cmlb_read_fdisk:\n"); 19743525Sshidokht cmlb_dbg(CMLB_INFO, cl, " relsect " 1975786Slclee "numsect sysid bootid\n"); 1976786Slclee for (i = 0; i < FD_NUMPART; i++, fdp++) { 19773525Sshidokht cmlb_dbg(CMLB_INFO, cl, 1978786Slclee " %d: %8d %8d 0x%08x 0x%08x\n", 1979786Slclee i, fdp->relsect, fdp->numsect, 1980786Slclee fdp->systid, fdp->bootid); 1981786Slclee } 1982786Slclee } 1983786Slclee #endif 1984786Slclee 1985786Slclee /* 1986786Slclee * Try to find the unix partition 1987786Slclee */ 1988786Slclee uidx = -1; 1989786Slclee solaris_offset = 0; 1990786Slclee solaris_size = 0; 1991786Slclee 1992786Slclee for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) { 19937563SPrasad.Singamsetty@Sun.COM uint32_t relsect; 19947563SPrasad.Singamsetty@Sun.COM uint32_t numsect; 1995786Slclee 1996786Slclee if (fdp->numsect == 0) { 19973525Sshidokht cl->cl_fmap[i].fmap_start = 0; 19983525Sshidokht cl->cl_fmap[i].fmap_nblk = 0; 1999786Slclee continue; 2000786Slclee } 2001786Slclee 2002786Slclee /* 2003786Slclee * Data in the fdisk table is little-endian. 2004786Slclee */ 2005786Slclee relsect = LE_32(fdp->relsect); 2006786Slclee numsect = LE_32(fdp->numsect); 2007786Slclee 20083525Sshidokht cl->cl_fmap[i].fmap_start = relsect; 20093525Sshidokht cl->cl_fmap[i].fmap_nblk = numsect; 2010786Slclee 2011786Slclee if (fdp->systid != SUNIXOS && 2012786Slclee fdp->systid != SUNIXOS2 && 2013786Slclee fdp->systid != EFI_PMBR) { 2014786Slclee continue; 2015786Slclee } 2016786Slclee 2017786Slclee /* 2018786Slclee * use the last active solaris partition id found 2019786Slclee * (there should only be 1 active partition id) 2020786Slclee * 2021786Slclee * if there are no active solaris partition id 2022786Slclee * then use the first inactive solaris partition id 2023786Slclee */ 2024786Slclee if ((uidx == -1) || (fdp->bootid == ACTIVE)) { 2025*8333SSuhasini.Peddada@Sun.COM uidx = i; 2026*8333SSuhasini.Peddada@Sun.COM solaris_offset = relsect; 2027*8333SSuhasini.Peddada@Sun.COM solaris_size = numsect; 2028786Slclee } 2029786Slclee } 2030*8333SSuhasini.Peddada@Sun.COM 20313525Sshidokht cmlb_dbg(CMLB_INFO, cl, "fdisk 0x%x 0x%lx", 20323525Sshidokht cl->cl_solaris_offset, cl->cl_solaris_size); 2033786Slclee done: 2034786Slclee 2035786Slclee /* 2036786Slclee * Clear the VTOC info, only if the Solaris partition entry 2037786Slclee * has moved, changed size, been deleted, or if the size of 2038786Slclee * the partition is too small to even fit the label sector. 2039786Slclee */ 20403525Sshidokht if ((cl->cl_solaris_offset != solaris_offset) || 20413525Sshidokht (cl->cl_solaris_size != solaris_size) || 2042786Slclee solaris_size <= DK_LABEL_LOC) { 20433525Sshidokht cmlb_dbg(CMLB_INFO, cl, "fdisk moved 0x%x 0x%lx", 20443525Sshidokht solaris_offset, solaris_size); 20453525Sshidokht bzero(&cl->cl_g, sizeof (struct dk_geom)); 20463525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc)); 20473525Sshidokht bzero(&cl->cl_map, NDKMAP * (sizeof (struct dk_map))); 20483525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 2049786Slclee } 20503525Sshidokht cl->cl_solaris_offset = solaris_offset; 20513525Sshidokht cl->cl_solaris_size = solaris_size; 2052786Slclee kmem_free(bufp, blocksize); 2053786Slclee return (rval); 2054786Slclee 2055786Slclee #else /* #elif defined(_FIRMWARE_NEEDS_FDISK) */ 2056786Slclee #error "fdisk table presence undetermined for this platform." 2057786Slclee #endif /* #if defined(_NO_FDISK_PRESENT) */ 2058786Slclee } 2059786Slclee 2060786Slclee static void 2061786Slclee cmlb_swap_efi_gpt(efi_gpt_t *e) 2062786Slclee { 2063786Slclee _NOTE(ASSUMING_PROTECTED(*e)) 2064786Slclee e->efi_gpt_Signature = LE_64(e->efi_gpt_Signature); 2065786Slclee e->efi_gpt_Revision = LE_32(e->efi_gpt_Revision); 2066786Slclee e->efi_gpt_HeaderSize = LE_32(e->efi_gpt_HeaderSize); 2067786Slclee e->efi_gpt_HeaderCRC32 = LE_32(e->efi_gpt_HeaderCRC32); 2068786Slclee e->efi_gpt_MyLBA = LE_64(e->efi_gpt_MyLBA); 2069786Slclee e->efi_gpt_AlternateLBA = LE_64(e->efi_gpt_AlternateLBA); 2070786Slclee e->efi_gpt_FirstUsableLBA = LE_64(e->efi_gpt_FirstUsableLBA); 2071786Slclee e->efi_gpt_LastUsableLBA = LE_64(e->efi_gpt_LastUsableLBA); 2072786Slclee UUID_LE_CONVERT(e->efi_gpt_DiskGUID, e->efi_gpt_DiskGUID); 2073786Slclee e->efi_gpt_PartitionEntryLBA = LE_64(e->efi_gpt_PartitionEntryLBA); 2074786Slclee e->efi_gpt_NumberOfPartitionEntries = 2075786Slclee LE_32(e->efi_gpt_NumberOfPartitionEntries); 2076786Slclee e->efi_gpt_SizeOfPartitionEntry = 2077786Slclee LE_32(e->efi_gpt_SizeOfPartitionEntry); 2078786Slclee e->efi_gpt_PartitionEntryArrayCRC32 = 2079786Slclee LE_32(e->efi_gpt_PartitionEntryArrayCRC32); 2080786Slclee } 2081786Slclee 2082786Slclee static void 2083786Slclee cmlb_swap_efi_gpe(int nparts, efi_gpe_t *p) 2084786Slclee { 2085786Slclee int i; 2086786Slclee 2087786Slclee _NOTE(ASSUMING_PROTECTED(*p)) 2088786Slclee for (i = 0; i < nparts; i++) { 2089786Slclee UUID_LE_CONVERT(p[i].efi_gpe_PartitionTypeGUID, 2090786Slclee p[i].efi_gpe_PartitionTypeGUID); 2091786Slclee p[i].efi_gpe_StartingLBA = LE_64(p[i].efi_gpe_StartingLBA); 2092786Slclee p[i].efi_gpe_EndingLBA = LE_64(p[i].efi_gpe_EndingLBA); 2093786Slclee /* PartitionAttrs */ 2094786Slclee } 2095786Slclee } 2096786Slclee 2097786Slclee static int 2098786Slclee cmlb_validate_efi(efi_gpt_t *labp) 2099786Slclee { 2100786Slclee if (labp->efi_gpt_Signature != EFI_SIGNATURE) 2101786Slclee return (EINVAL); 2102786Slclee /* at least 96 bytes in this version of the spec. */ 2103786Slclee if (sizeof (efi_gpt_t) - sizeof (labp->efi_gpt_Reserved2) > 2104786Slclee labp->efi_gpt_HeaderSize) 2105786Slclee return (EINVAL); 2106786Slclee /* this should be 128 bytes */ 2107786Slclee if (labp->efi_gpt_SizeOfPartitionEntry != sizeof (efi_gpe_t)) 2108786Slclee return (EINVAL); 2109786Slclee return (0); 2110786Slclee } 2111786Slclee 21125624Sshidokht /* 21135624Sshidokht * This function returns FALSE if there is a valid MBR signature and no 21145624Sshidokht * partition table entries of type EFI_PMBR (0xEE). Otherwise it returns TRUE. 21155624Sshidokht * 21165624Sshidokht * The EFI spec (1.10 and later) requires having a Protective MBR (PMBR) to 21175624Sshidokht * recognize the disk as GPT partitioned. However, some other OS creates an MBR 21185624Sshidokht * where a PMBR entry is not the only one. Also, if the first block has been 21195624Sshidokht * corrupted, currently best attempt to allow data access would be to try to 21205624Sshidokht * check for GPT headers. Hence in case of more than one partition entry, but 21215624Sshidokht * at least one EFI_PMBR partition type or no valid magic number, the function 21225624Sshidokht * returns TRUE to continue with looking for GPT header. 21235624Sshidokht */ 21245624Sshidokht 21255624Sshidokht static int 21267563SPrasad.Singamsetty@Sun.COM cmlb_check_efi_mbr(uchar_t *buf, int *is_mbr) 21275624Sshidokht { 21285624Sshidokht struct ipart *fdp; 21295624Sshidokht struct mboot *mbp = (struct mboot *)buf; 21305624Sshidokht struct ipart fdisk[FD_NUMPART]; 21315624Sshidokht int i; 21325624Sshidokht 21337563SPrasad.Singamsetty@Sun.COM if (is_mbr != NULL) 21347563SPrasad.Singamsetty@Sun.COM *is_mbr = TRUE; 21357563SPrasad.Singamsetty@Sun.COM 21367563SPrasad.Singamsetty@Sun.COM if (LE_16(mbp->signature) != MBB_MAGIC) { 21377563SPrasad.Singamsetty@Sun.COM if (is_mbr != NULL) 21387563SPrasad.Singamsetty@Sun.COM is_mbr = FALSE; 21395624Sshidokht return (TRUE); 21407563SPrasad.Singamsetty@Sun.COM } 21415624Sshidokht 21425624Sshidokht bcopy(&mbp->parts[0], fdisk, sizeof (fdisk)); 21435624Sshidokht 21445624Sshidokht for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) { 21455624Sshidokht if (fdp->systid == EFI_PMBR) 21465624Sshidokht return (TRUE); 21475624Sshidokht } 21485624Sshidokht 21495624Sshidokht return (FALSE); 21505624Sshidokht } 21515624Sshidokht 2152786Slclee static int 21533525Sshidokht cmlb_use_efi(struct cmlb_lun *cl, diskaddr_t capacity, int flags, 21543525Sshidokht void *tg_cookie) 2155786Slclee { 2156786Slclee int i; 2157786Slclee int rval = 0; 2158786Slclee efi_gpe_t *partitions; 2159786Slclee uchar_t *buf; 2160786Slclee uint_t lbasize; /* is really how much to read */ 21613525Sshidokht diskaddr_t cap = 0; 2162786Slclee uint_t nparts; 2163786Slclee diskaddr_t gpe_lba; 21646590Syl194034 diskaddr_t alternate_lba; 21651071Sshidokht int iofailed = 0; 21663525Sshidokht struct uuid uuid_type_reserved = EFI_RESERVED; 21677563SPrasad.Singamsetty@Sun.COM #if defined(_FIRMWARE_NEEDS_FDISK) 21687563SPrasad.Singamsetty@Sun.COM int is_mbr; 21697563SPrasad.Singamsetty@Sun.COM #endif 21703525Sshidokht 21713525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 21723525Sshidokht 21733525Sshidokht if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) { 21743525Sshidokht rval = EINVAL; 21753525Sshidokht goto done_err1; 21763525Sshidokht } 21773525Sshidokht 21783525Sshidokht 21793525Sshidokht lbasize = cl->cl_sys_blocksize; 21803525Sshidokht 21813525Sshidokht cl->cl_reserved = -1; 21823525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 2183786Slclee 2184786Slclee buf = kmem_zalloc(EFI_MIN_ARRAY_SIZE, KM_SLEEP); 21853525Sshidokht 21867563SPrasad.Singamsetty@Sun.COM rval = DK_TG_READ(cl, buf, 0, lbasize, tg_cookie); 2187786Slclee if (rval) { 21881071Sshidokht iofailed = 1; 2189786Slclee goto done_err; 2190786Slclee } 2191786Slclee if (((struct dk_label *)buf)->dkl_magic == DKL_MAGIC) { 2192786Slclee /* not ours */ 2193786Slclee rval = ESRCH; 2194786Slclee goto done_err; 2195786Slclee } 2196786Slclee 21977563SPrasad.Singamsetty@Sun.COM #if defined(_FIRMWARE_NEEDS_FDISK) 21987563SPrasad.Singamsetty@Sun.COM if (cmlb_check_efi_mbr(buf, &is_mbr) == FALSE) { 21997563SPrasad.Singamsetty@Sun.COM if (is_mbr == TRUE) 22007563SPrasad.Singamsetty@Sun.COM rval = ESRCH; 22017563SPrasad.Singamsetty@Sun.COM else 22027563SPrasad.Singamsetty@Sun.COM rval = EINVAL; 22037563SPrasad.Singamsetty@Sun.COM goto done_err; 22047563SPrasad.Singamsetty@Sun.COM } 22057563SPrasad.Singamsetty@Sun.COM #else 22067563SPrasad.Singamsetty@Sun.COM if (cmlb_check_efi_mbr(buf, NULL) == FALSE) { 22075624Sshidokht rval = EINVAL; 22085624Sshidokht goto done_err; 22095624Sshidokht } 22105624Sshidokht 22117563SPrasad.Singamsetty@Sun.COM #endif 22127563SPrasad.Singamsetty@Sun.COM 22133525Sshidokht rval = DK_TG_READ(cl, buf, 1, lbasize, tg_cookie); 2214786Slclee if (rval) { 22151071Sshidokht iofailed = 1; 2216786Slclee goto done_err; 2217786Slclee } 2218786Slclee cmlb_swap_efi_gpt((efi_gpt_t *)buf); 2219786Slclee 2220786Slclee if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) { 2221786Slclee /* 2222786Slclee * Couldn't read the primary, try the backup. Our 2223786Slclee * capacity at this point could be based on CHS, so 2224786Slclee * check what the device reports. 2225786Slclee */ 22263525Sshidokht rval = DK_TG_GETCAP(cl, &cap, tg_cookie); 2227786Slclee if (rval) { 22281071Sshidokht iofailed = 1; 2229786Slclee goto done_err; 2230786Slclee } 22313525Sshidokht 22323525Sshidokht /* 22333525Sshidokht * CMLB_OFF_BY_ONE case, we check the next to last block first 22343525Sshidokht * for backup GPT header, otherwise check the last block. 22353525Sshidokht */ 22363525Sshidokht 22373525Sshidokht if ((rval = DK_TG_READ(cl, buf, 22383525Sshidokht cap - ((cl->cl_alter_behavior & CMLB_OFF_BY_ONE) ? 2 : 1), 22393525Sshidokht lbasize, tg_cookie)) 22403525Sshidokht != 0) { 22411071Sshidokht iofailed = 1; 2242786Slclee goto done_err; 2243786Slclee } 2244786Slclee cmlb_swap_efi_gpt((efi_gpt_t *)buf); 22453525Sshidokht 22463525Sshidokht if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) { 22473525Sshidokht 22483525Sshidokht if (!(cl->cl_alter_behavior & CMLB_OFF_BY_ONE)) 22493525Sshidokht goto done_err; 22503525Sshidokht if ((rval = DK_TG_READ(cl, buf, cap - 1, lbasize, 22513525Sshidokht tg_cookie)) != 0) 22523525Sshidokht goto done_err; 22533525Sshidokht cmlb_swap_efi_gpt((efi_gpt_t *)buf); 22543525Sshidokht if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) 22553525Sshidokht goto done_err; 22563525Sshidokht } 22573525Sshidokht if (!(flags & CMLB_SILENT)) 22583525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN, 22593525Sshidokht "primary label corrupt; using backup\n"); 2260786Slclee } 2261786Slclee 2262786Slclee nparts = ((efi_gpt_t *)buf)->efi_gpt_NumberOfPartitionEntries; 2263786Slclee gpe_lba = ((efi_gpt_t *)buf)->efi_gpt_PartitionEntryLBA; 22646590Syl194034 alternate_lba = ((efi_gpt_t *)buf)->efi_gpt_AlternateLBA; 2265786Slclee 22663525Sshidokht rval = DK_TG_READ(cl, buf, gpe_lba, EFI_MIN_ARRAY_SIZE, tg_cookie); 2267786Slclee if (rval) { 22681071Sshidokht iofailed = 1; 2269786Slclee goto done_err; 2270786Slclee } 2271786Slclee partitions = (efi_gpe_t *)buf; 2272786Slclee 2273786Slclee if (nparts > MAXPART) { 2274786Slclee nparts = MAXPART; 2275786Slclee } 2276786Slclee cmlb_swap_efi_gpe(nparts, partitions); 2277786Slclee 22783525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 2279786Slclee 2280786Slclee /* Fill in partition table. */ 2281786Slclee for (i = 0; i < nparts; i++) { 2282786Slclee if (partitions->efi_gpe_StartingLBA != 0 || 2283786Slclee partitions->efi_gpe_EndingLBA != 0) { 22843525Sshidokht cl->cl_map[i].dkl_cylno = 2285786Slclee partitions->efi_gpe_StartingLBA; 22863525Sshidokht cl->cl_map[i].dkl_nblk = 2287786Slclee partitions->efi_gpe_EndingLBA - 2288786Slclee partitions->efi_gpe_StartingLBA + 1; 22893525Sshidokht cl->cl_offset[i] = 2290786Slclee partitions->efi_gpe_StartingLBA; 2291786Slclee } 22923525Sshidokht 22933525Sshidokht if (cl->cl_reserved == -1) { 22943525Sshidokht if (bcmp(&partitions->efi_gpe_PartitionTypeGUID, 22953525Sshidokht &uuid_type_reserved, sizeof (struct uuid)) == 0) { 22963525Sshidokht cl->cl_reserved = i; 22973525Sshidokht } 22983525Sshidokht } 2299786Slclee if (i == WD_NODE) { 2300786Slclee /* 2301786Slclee * minor number 7 corresponds to the whole disk 23026590Syl194034 * if the disk capacity is expanded after disk is 23036590Syl194034 * labeled, minor number 7 represents the capacity 23046590Syl194034 * indicated by the disk label. 2305786Slclee */ 23063525Sshidokht cl->cl_map[i].dkl_cylno = 0; 23076590Syl194034 if (alternate_lba == 1) { 23086590Syl194034 /* 23096590Syl194034 * We are using backup label. Since we can 23106590Syl194034 * find a valid label at the end of disk, 23116590Syl194034 * the disk capacity is not expanded. 23126590Syl194034 */ 23136590Syl194034 cl->cl_map[i].dkl_nblk = capacity; 23146590Syl194034 } else { 23156590Syl194034 cl->cl_map[i].dkl_nblk = alternate_lba + 1; 23166590Syl194034 } 23173525Sshidokht cl->cl_offset[i] = 0; 2318786Slclee } 2319786Slclee partitions++; 2320786Slclee } 23213525Sshidokht cl->cl_solaris_offset = 0; 23223525Sshidokht cl->cl_solaris_size = capacity; 23237563SPrasad.Singamsetty@Sun.COM cl->cl_label_from_media = CMLB_LABEL_EFI; 23243525Sshidokht cl->cl_f_geometry_is_valid = TRUE; 23253525Sshidokht 23263525Sshidokht /* clear the vtoc label */ 23273525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc)); 23283525Sshidokht 2329786Slclee kmem_free(buf, EFI_MIN_ARRAY_SIZE); 2330786Slclee return (0); 2331786Slclee 2332786Slclee done_err: 2333786Slclee kmem_free(buf, EFI_MIN_ARRAY_SIZE); 23343525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 23353525Sshidokht done_err1: 2336786Slclee /* 2337786Slclee * if we didn't find something that could look like a VTOC 2338786Slclee * and the disk is over 1TB, we know there isn't a valid label. 2339786Slclee * Otherwise let cmlb_uselabel decide what to do. We only 2340786Slclee * want to invalidate this if we're certain the label isn't 2341786Slclee * valid because cmlb_prop_op will now fail, which in turn 2342786Slclee * causes things like opens and stats on the partition to fail. 2343786Slclee */ 23447563SPrasad.Singamsetty@Sun.COM if ((capacity > CMLB_EXTVTOC_LIMIT) && (rval != ESRCH) && !iofailed) { 23453525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 2346786Slclee } 2347786Slclee return (rval); 2348786Slclee } 2349786Slclee 2350786Slclee 2351786Slclee /* 2352786Slclee * Function: cmlb_uselabel 2353786Slclee * 2354786Slclee * Description: Validate the disk label and update the relevant data (geometry, 2355786Slclee * partition, vtoc, and capacity data) in the cmlb_lun struct. 2356786Slclee * Marks the geometry of the unit as being valid. 2357786Slclee * 23583525Sshidokht * Arguments: cl: unit struct. 2359786Slclee * dk_label: disk label 2360786Slclee * 2361786Slclee * Return Code: CMLB_LABEL_IS_VALID: Label read from disk is OK; geometry, 2362786Slclee * partition, vtoc, and capacity data are good. 2363786Slclee * 2364786Slclee * CMLB_LABEL_IS_INVALID: Magic number or checksum error in the 2365786Slclee * label; or computed capacity does not jibe with capacity 2366786Slclee * reported from the READ CAPACITY command. 2367786Slclee * 2368786Slclee * Context: Kernel thread only (can sleep). 2369786Slclee */ 2370786Slclee static int 23713525Sshidokht cmlb_uselabel(struct cmlb_lun *cl, struct dk_label *labp, int flags) 2372786Slclee { 2373786Slclee short *sp; 2374786Slclee short sum; 2375786Slclee short count; 2376786Slclee int label_error = CMLB_LABEL_IS_VALID; 2377786Slclee int i; 2378786Slclee diskaddr_t label_capacity; 23797563SPrasad.Singamsetty@Sun.COM uint32_t part_end; 2380786Slclee diskaddr_t track_capacity; 2381786Slclee #if defined(_SUNOS_VTOC_16) 2382786Slclee struct dkl_partition *vpartp; 2383786Slclee #endif 23843525Sshidokht ASSERT(cl != NULL); 23853525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 2386786Slclee 2387786Slclee /* Validate the magic number of the label. */ 2388786Slclee if (labp->dkl_magic != DKL_MAGIC) { 2389786Slclee #if defined(__sparc) 23903525Sshidokht if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) { 23913525Sshidokht if (!(flags & CMLB_SILENT)) 23923525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), 23933525Sshidokht CE_WARN, 23943525Sshidokht "Corrupt label; wrong magic number\n"); 2395786Slclee } 2396786Slclee #endif 2397786Slclee return (CMLB_LABEL_IS_INVALID); 2398786Slclee } 2399786Slclee 2400786Slclee /* Validate the checksum of the label. */ 2401786Slclee sp = (short *)labp; 2402786Slclee sum = 0; 2403786Slclee count = sizeof (struct dk_label) / sizeof (short); 2404786Slclee while (count--) { 2405786Slclee sum ^= *sp++; 2406786Slclee } 2407786Slclee 2408786Slclee if (sum != 0) { 2409786Slclee #if defined(_SUNOS_VTOC_16) 24103525Sshidokht if (!ISCD(cl)) { 2411786Slclee #elif defined(_SUNOS_VTOC_8) 24123525Sshidokht if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) { 2413786Slclee #endif 24143525Sshidokht if (!(flags & CMLB_SILENT)) 24153525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), 24163525Sshidokht CE_WARN, 24173525Sshidokht "Corrupt label - label checksum failed\n"); 2418786Slclee } 2419786Slclee return (CMLB_LABEL_IS_INVALID); 2420786Slclee } 2421786Slclee 2422786Slclee 2423786Slclee /* 2424786Slclee * Fill in geometry structure with data from label. 2425786Slclee */ 24263525Sshidokht bzero(&cl->cl_g, sizeof (struct dk_geom)); 24273525Sshidokht cl->cl_g.dkg_ncyl = labp->dkl_ncyl; 24283525Sshidokht cl->cl_g.dkg_acyl = labp->dkl_acyl; 24293525Sshidokht cl->cl_g.dkg_bcyl = 0; 24303525Sshidokht cl->cl_g.dkg_nhead = labp->dkl_nhead; 24313525Sshidokht cl->cl_g.dkg_nsect = labp->dkl_nsect; 24323525Sshidokht cl->cl_g.dkg_intrlv = labp->dkl_intrlv; 2433786Slclee 2434786Slclee #if defined(_SUNOS_VTOC_8) 24353525Sshidokht cl->cl_g.dkg_gap1 = labp->dkl_gap1; 24363525Sshidokht cl->cl_g.dkg_gap2 = labp->dkl_gap2; 24373525Sshidokht cl->cl_g.dkg_bhead = labp->dkl_bhead; 2438786Slclee #endif 2439786Slclee #if defined(_SUNOS_VTOC_16) 24403525Sshidokht cl->cl_dkg_skew = labp->dkl_skew; 2441786Slclee #endif 2442786Slclee 2443786Slclee #if defined(__i386) || defined(__amd64) 24443525Sshidokht cl->cl_g.dkg_apc = labp->dkl_apc; 2445786Slclee #endif 2446786Slclee 2447786Slclee /* 2448786Slclee * Currently we rely on the values in the label being accurate. If 2449786Slclee * dkl_rpm or dkl_pcly are zero in the label, use a default value. 2450786Slclee * 2451786Slclee * Note: In the future a MODE SENSE may be used to retrieve this data, 2452786Slclee * although this command is optional in SCSI-2. 2453786Slclee */ 24543525Sshidokht cl->cl_g.dkg_rpm = (labp->dkl_rpm != 0) ? labp->dkl_rpm : 3600; 24553525Sshidokht cl->cl_g.dkg_pcyl = (labp->dkl_pcyl != 0) ? labp->dkl_pcyl : 24563525Sshidokht (cl->cl_g.dkg_ncyl + cl->cl_g.dkg_acyl); 2457786Slclee 2458786Slclee /* 2459786Slclee * The Read and Write reinstruct values may not be valid 2460786Slclee * for older disks. 2461786Slclee */ 24623525Sshidokht cl->cl_g.dkg_read_reinstruct = labp->dkl_read_reinstruct; 24633525Sshidokht cl->cl_g.dkg_write_reinstruct = labp->dkl_write_reinstruct; 2464786Slclee 2465786Slclee /* Fill in partition table. */ 2466786Slclee #if defined(_SUNOS_VTOC_8) 2467786Slclee for (i = 0; i < NDKMAP; i++) { 24683525Sshidokht cl->cl_map[i].dkl_cylno = labp->dkl_map[i].dkl_cylno; 24693525Sshidokht cl->cl_map[i].dkl_nblk = labp->dkl_map[i].dkl_nblk; 2470786Slclee } 2471786Slclee #endif 2472786Slclee #if defined(_SUNOS_VTOC_16) 2473786Slclee vpartp = labp->dkl_vtoc.v_part; 2474786Slclee track_capacity = labp->dkl_nhead * labp->dkl_nsect; 2475786Slclee 24763525Sshidokht /* Prevent divide by zero */ 24773525Sshidokht if (track_capacity == 0) { 24783525Sshidokht if (!(flags & CMLB_SILENT)) 24793525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN, 24803525Sshidokht "Corrupt label - zero nhead or nsect value\n"); 24813525Sshidokht 24823525Sshidokht return (CMLB_LABEL_IS_INVALID); 24833525Sshidokht } 24843525Sshidokht 2485786Slclee for (i = 0; i < NDKMAP; i++, vpartp++) { 24863525Sshidokht cl->cl_map[i].dkl_cylno = vpartp->p_start / track_capacity; 24873525Sshidokht cl->cl_map[i].dkl_nblk = vpartp->p_size; 2488786Slclee } 2489786Slclee #endif 2490786Slclee 2491786Slclee /* Fill in VTOC Structure. */ 24923525Sshidokht bcopy(&labp->dkl_vtoc, &cl->cl_vtoc, sizeof (struct dk_vtoc)); 2493786Slclee #if defined(_SUNOS_VTOC_8) 2494786Slclee /* 2495786Slclee * The 8-slice vtoc does not include the ascii label; save it into 2496786Slclee * the device's soft state structure here. 2497786Slclee */ 24983525Sshidokht bcopy(labp->dkl_asciilabel, cl->cl_asciilabel, LEN_DKL_ASCII); 2499786Slclee #endif 2500786Slclee 2501786Slclee /* Now look for a valid capacity. */ 25023525Sshidokht track_capacity = (cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect); 25033525Sshidokht label_capacity = (cl->cl_g.dkg_ncyl * track_capacity); 25043525Sshidokht 25053525Sshidokht if (cl->cl_g.dkg_acyl) { 2506786Slclee #if defined(__i386) || defined(__amd64) 2507786Slclee /* we may have > 1 alts cylinder */ 25083525Sshidokht label_capacity += (track_capacity * cl->cl_g.dkg_acyl); 2509786Slclee #else 2510786Slclee label_capacity += track_capacity; 2511786Slclee #endif 2512786Slclee } 2513786Slclee 2514786Slclee /* 25153525Sshidokht * Force check here to ensure the computed capacity is valid. 25163525Sshidokht * If capacity is zero, it indicates an invalid label and 25173525Sshidokht * we should abort updating the relevant data then. 25183525Sshidokht */ 25193525Sshidokht if (label_capacity == 0) { 25203525Sshidokht if (!(flags & CMLB_SILENT)) 25213525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN, 25223525Sshidokht "Corrupt label - no valid capacity could be " 25233525Sshidokht "retrieved\n"); 25243525Sshidokht 25253525Sshidokht return (CMLB_LABEL_IS_INVALID); 25263525Sshidokht } 25273525Sshidokht 25283525Sshidokht /* Mark the geometry as valid. */ 25293525Sshidokht cl->cl_f_geometry_is_valid = TRUE; 25303525Sshidokht 25313525Sshidokht /* 2532786Slclee * if we got invalidated when mutex exit and entered again, 2533786Slclee * if blockcount different than when we came in, need to 2534786Slclee * retry from beginning of cmlb_validate_geometry. 2535786Slclee * revisit this on next phase of utilizing this for 2536786Slclee * sd. 2537786Slclee */ 2538786Slclee 25393525Sshidokht if (label_capacity <= cl->cl_blockcount) { 2540786Slclee #if defined(_SUNOS_VTOC_8) 2541786Slclee /* 2542786Slclee * We can't let this happen on drives that are subdivided 2543786Slclee * into logical disks (i.e., that have an fdisk table). 25443525Sshidokht * The cl_blockcount field should always hold the full media 2545786Slclee * size in sectors, period. This code would overwrite 25463525Sshidokht * cl_blockcount with the size of the Solaris fdisk partition. 2547786Slclee */ 25483525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 2549786Slclee "cmlb_uselabel: Label %d blocks; Drive %d blocks\n", 25503525Sshidokht label_capacity, cl->cl_blockcount); 25513525Sshidokht cl->cl_solaris_size = label_capacity; 2552786Slclee 2553786Slclee #endif /* defined(_SUNOS_VTOC_8) */ 2554786Slclee goto done; 2555786Slclee } 2556786Slclee 25573525Sshidokht if (ISCD(cl)) { 2558786Slclee /* For CDROMs, we trust that the data in the label is OK. */ 2559786Slclee #if defined(_SUNOS_VTOC_8) 2560786Slclee for (i = 0; i < NDKMAP; i++) { 2561786Slclee part_end = labp->dkl_nhead * labp->dkl_nsect * 2562786Slclee labp->dkl_map[i].dkl_cylno + 2563786Slclee labp->dkl_map[i].dkl_nblk - 1; 2564786Slclee 2565786Slclee if ((labp->dkl_map[i].dkl_nblk) && 25663525Sshidokht (part_end > cl->cl_blockcount)) { 25673525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 2568786Slclee break; 2569786Slclee } 2570786Slclee } 2571786Slclee #endif 2572786Slclee #if defined(_SUNOS_VTOC_16) 2573786Slclee vpartp = &(labp->dkl_vtoc.v_part[0]); 2574786Slclee for (i = 0; i < NDKMAP; i++, vpartp++) { 2575786Slclee part_end = vpartp->p_start + vpartp->p_size; 2576786Slclee if ((vpartp->p_size > 0) && 25773525Sshidokht (part_end > cl->cl_blockcount)) { 25783525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 2579786Slclee break; 2580786Slclee } 2581786Slclee } 2582786Slclee #endif 2583786Slclee } else { 25843525Sshidokht /* label_capacity > cl->cl_blockcount */ 25853525Sshidokht if (!(flags & CMLB_SILENT)) { 25863525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN, 25873525Sshidokht "Corrupt label - bad geometry\n"); 25883525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_CONT, 25893525Sshidokht "Label says %llu blocks; Drive says %llu blocks\n", 25903525Sshidokht label_capacity, cl->cl_blockcount); 25913525Sshidokht } 25923525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 2593786Slclee label_error = CMLB_LABEL_IS_INVALID; 2594786Slclee } 2595786Slclee 2596786Slclee done: 2597786Slclee 25983525Sshidokht cmlb_dbg(CMLB_INFO, cl, "cmlb_uselabel: (label geometry)\n"); 25993525Sshidokht cmlb_dbg(CMLB_INFO, cl, 2600786Slclee " ncyl: %d; acyl: %d; nhead: %d; nsect: %d\n", 26013525Sshidokht cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl, 26023525Sshidokht cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect); 26033525Sshidokht 26043525Sshidokht cmlb_dbg(CMLB_INFO, cl, 2605786Slclee " label_capacity: %d; intrlv: %d; rpm: %d\n", 26063525Sshidokht cl->cl_blockcount, cl->cl_g.dkg_intrlv, cl->cl_g.dkg_rpm); 26073525Sshidokht cmlb_dbg(CMLB_INFO, cl, " wrt_reinstr: %d; rd_reinstr: %d\n", 26083525Sshidokht cl->cl_g.dkg_write_reinstruct, cl->cl_g.dkg_read_reinstruct); 26093525Sshidokht 26103525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 2611786Slclee 2612786Slclee return (label_error); 2613786Slclee } 2614786Slclee 2615786Slclee 2616786Slclee /* 2617786Slclee * Function: cmlb_build_default_label 2618786Slclee * 2619786Slclee * Description: Generate a default label for those devices that do not have 2620786Slclee * one, e.g., new media, removable cartridges, etc.. 2621786Slclee * 2622786Slclee * Context: Kernel thread only 2623786Slclee */ 26243525Sshidokht /*ARGSUSED*/ 2625786Slclee static void 26263525Sshidokht cmlb_build_default_label(struct cmlb_lun *cl, void *tg_cookie) 2627786Slclee { 2628786Slclee #if defined(_SUNOS_VTOC_16) 2629786Slclee uint_t phys_spc; 2630786Slclee uint_t disksize; 26313525Sshidokht struct dk_geom cl_g; 26323525Sshidokht diskaddr_t capacity; 2633786Slclee #endif 2634786Slclee 26353525Sshidokht ASSERT(cl != NULL); 26363525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 2637786Slclee 2638786Slclee #if defined(_SUNOS_VTOC_8) 2639786Slclee /* 2640786Slclee * Note: This is a legacy check for non-removable devices on VTOC_8 2641786Slclee * only. This may be a valid check for VTOC_16 as well. 26423525Sshidokht * Once we understand why there is this difference between SPARC and 26433525Sshidokht * x86 platform, we could remove this legacy check. 2644786Slclee */ 26453525Sshidokht if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) { 2646786Slclee return; 2647786Slclee } 2648786Slclee #endif 2649786Slclee 26503525Sshidokht bzero(&cl->cl_g, sizeof (struct dk_geom)); 26513525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc)); 26523525Sshidokht bzero(&cl->cl_map, NDKMAP * (sizeof (struct dk_map))); 2653786Slclee 2654786Slclee #if defined(_SUNOS_VTOC_8) 2655786Slclee 2656786Slclee /* 2657786Slclee * It's a REMOVABLE media, therefore no label (on sparc, anyway). 2658786Slclee * But it is still necessary to set up various geometry information, 2659786Slclee * and we are doing this here. 2660786Slclee */ 2661786Slclee 2662786Slclee /* 2663786Slclee * For the rpm, we use the minimum for the disk. For the head, cyl, 2664786Slclee * and number of sector per track, if the capacity <= 1GB, head = 64, 2665786Slclee * sect = 32. else head = 255, sect 63 Note: the capacity should be 2666786Slclee * equal to C*H*S values. This will cause some truncation of size due 2667786Slclee * to round off errors. For CD-ROMs, this truncation can have adverse 2668786Slclee * side effects, so returning ncyl and nhead as 1. The nsect will 2669786Slclee * overflow for most of CD-ROMs as nsect is of type ushort. (4190569) 2670786Slclee */ 26713525Sshidokht cl->cl_solaris_size = cl->cl_blockcount; 26723525Sshidokht if (ISCD(cl)) { 2673786Slclee tg_attribute_t tgattribute; 2674786Slclee int is_writable; 2675786Slclee /* 2676786Slclee * Preserve the old behavior for non-writable 2677786Slclee * medias. Since dkg_nsect is a ushort, it 2678786Slclee * will lose bits as cdroms have more than 2679786Slclee * 65536 sectors. So if we recalculate 2680786Slclee * capacity, it will become much shorter. 2681786Slclee * But the dkg_* information is not 2682786Slclee * used for CDROMs so it is OK. But for 2683786Slclee * Writable CDs we need this information 2684786Slclee * to be valid (for newfs say). So we 2685786Slclee * make nsect and nhead > 1 that way 2686786Slclee * nsect can still stay within ushort limit 2687786Slclee * without losing any bits. 2688786Slclee */ 2689786Slclee 2690786Slclee bzero(&tgattribute, sizeof (tg_attribute_t)); 2691786Slclee 26923525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 26933525Sshidokht is_writable = 26943525Sshidokht (DK_TG_GETATTRIBUTE(cl, &tgattribute, tg_cookie) == 0) ? 2695786Slclee tgattribute.media_is_writable : 1; 26963525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 2697786Slclee 2698786Slclee if (is_writable) { 26993525Sshidokht cl->cl_g.dkg_nhead = 64; 27003525Sshidokht cl->cl_g.dkg_nsect = 32; 27013525Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount / (64 * 32); 27027563SPrasad.Singamsetty@Sun.COM cl->cl_solaris_size = (diskaddr_t)cl->cl_g.dkg_ncyl * 27033525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect; 2704786Slclee } else { 27053525Sshidokht cl->cl_g.dkg_ncyl = 1; 27063525Sshidokht cl->cl_g.dkg_nhead = 1; 27073525Sshidokht cl->cl_g.dkg_nsect = cl->cl_blockcount; 2708786Slclee } 2709786Slclee } else { 27103525Sshidokht if (cl->cl_blockcount <= 0x1000) { 2711786Slclee /* unlabeled SCSI floppy device */ 27123525Sshidokht cl->cl_g.dkg_nhead = 2; 27133525Sshidokht cl->cl_g.dkg_ncyl = 80; 27143525Sshidokht cl->cl_g.dkg_nsect = cl->cl_blockcount / (2 * 80); 27153525Sshidokht } else if (cl->cl_blockcount <= 0x200000) { 27163525Sshidokht cl->cl_g.dkg_nhead = 64; 27173525Sshidokht cl->cl_g.dkg_nsect = 32; 27183525Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount / (64 * 32); 2719786Slclee } else { 27203525Sshidokht cl->cl_g.dkg_nhead = 255; 27216124Sshidokht 27226124Sshidokht cl->cl_g.dkg_nsect = ((cl->cl_blockcount + 27236124Sshidokht (UINT16_MAX * 255 * 63) - 1) / 27246124Sshidokht (UINT16_MAX * 255 * 63)) * 63; 27256124Sshidokht 27266124Sshidokht if (cl->cl_g.dkg_nsect == 0) 27276124Sshidokht cl->cl_g.dkg_nsect = (UINT16_MAX / 63) * 63; 27286124Sshidokht 27296124Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount / 27306124Sshidokht (255 * cl->cl_g.dkg_nsect); 2731786Slclee } 27326124Sshidokht 27333525Sshidokht cl->cl_solaris_size = 27347563SPrasad.Singamsetty@Sun.COM (diskaddr_t)cl->cl_g.dkg_ncyl * cl->cl_g.dkg_nhead * 27357563SPrasad.Singamsetty@Sun.COM cl->cl_g.dkg_nsect; 2736786Slclee 2737786Slclee } 2738786Slclee 27393525Sshidokht cl->cl_g.dkg_acyl = 0; 27403525Sshidokht cl->cl_g.dkg_bcyl = 0; 27413525Sshidokht cl->cl_g.dkg_rpm = 200; 27423525Sshidokht cl->cl_asciilabel[0] = '\0'; 27433525Sshidokht cl->cl_g.dkg_pcyl = cl->cl_g.dkg_ncyl; 27443525Sshidokht 27453525Sshidokht cl->cl_map[0].dkl_cylno = 0; 27463525Sshidokht cl->cl_map[0].dkl_nblk = cl->cl_solaris_size; 27473525Sshidokht 27483525Sshidokht cl->cl_map[2].dkl_cylno = 0; 27493525Sshidokht cl->cl_map[2].dkl_nblk = cl->cl_solaris_size; 2750786Slclee 2751786Slclee #elif defined(_SUNOS_VTOC_16) 2752786Slclee 27533525Sshidokht if (cl->cl_solaris_size == 0) { 2754786Slclee /* 2755786Slclee * Got fdisk table but no solaris entry therefore 2756786Slclee * don't create a default label 2757786Slclee */ 27583525Sshidokht cl->cl_f_geometry_is_valid = TRUE; 2759786Slclee return; 2760786Slclee } 2761786Slclee 2762786Slclee /* 2763786Slclee * For CDs we continue to use the physical geometry to calculate 2764786Slclee * number of cylinders. All other devices must convert the 2765786Slclee * physical geometry (cmlb_geom) to values that will fit 2766786Slclee * in a dk_geom structure. 2767786Slclee */ 27683525Sshidokht if (ISCD(cl)) { 27693525Sshidokht phys_spc = cl->cl_pgeom.g_nhead * cl->cl_pgeom.g_nsect; 2770786Slclee } else { 2771786Slclee /* Convert physical geometry to disk geometry */ 27723525Sshidokht bzero(&cl_g, sizeof (struct dk_geom)); 27733525Sshidokht 27743525Sshidokht /* 27753525Sshidokht * Refer to comments related to off-by-1 at the 27763525Sshidokht * header of this file. 27777224Scth * Before calculating geometry, capacity should be 27783525Sshidokht * decreased by 1. 27793525Sshidokht */ 27803525Sshidokht 27813525Sshidokht if (cl->cl_alter_behavior & CMLB_OFF_BY_ONE) 27823525Sshidokht capacity = cl->cl_blockcount - 1; 27833525Sshidokht else 27843525Sshidokht capacity = cl->cl_blockcount; 27853525Sshidokht 27863525Sshidokht 27873525Sshidokht cmlb_convert_geometry(capacity, &cl_g); 27883525Sshidokht bcopy(&cl_g, &cl->cl_g, sizeof (cl->cl_g)); 27893525Sshidokht phys_spc = cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect; 2790786Slclee } 2791786Slclee 27923525Sshidokht ASSERT(phys_spc != 0); 27933525Sshidokht cl->cl_g.dkg_pcyl = cl->cl_solaris_size / phys_spc; 27945084Sjohnlev if (cl->cl_alter_behavior & CMLB_FAKE_LABEL_ONE_PARTITION) { 27955084Sjohnlev /* disable devid */ 27965084Sjohnlev cl->cl_g.dkg_ncyl = cl->cl_g.dkg_pcyl; 27975084Sjohnlev disksize = cl->cl_solaris_size; 27985084Sjohnlev } else { 27995084Sjohnlev cl->cl_g.dkg_acyl = DK_ACYL; 28005084Sjohnlev cl->cl_g.dkg_ncyl = cl->cl_g.dkg_pcyl - DK_ACYL; 28015084Sjohnlev disksize = cl->cl_g.dkg_ncyl * phys_spc; 28025084Sjohnlev } 28033525Sshidokht 28043525Sshidokht if (ISCD(cl)) { 2805786Slclee /* 2806786Slclee * CD's don't use the "heads * sectors * cyls"-type of 2807786Slclee * geometry, but instead use the entire capacity of the media. 2808786Slclee */ 28093525Sshidokht disksize = cl->cl_solaris_size; 28103525Sshidokht cl->cl_g.dkg_nhead = 1; 28113525Sshidokht cl->cl_g.dkg_nsect = 1; 28123525Sshidokht cl->cl_g.dkg_rpm = 28133525Sshidokht (cl->cl_pgeom.g_rpm == 0) ? 200 : cl->cl_pgeom.g_rpm; 28143525Sshidokht 28153525Sshidokht cl->cl_vtoc.v_part[0].p_start = 0; 28163525Sshidokht cl->cl_vtoc.v_part[0].p_size = disksize; 28173525Sshidokht cl->cl_vtoc.v_part[0].p_tag = V_BACKUP; 28183525Sshidokht cl->cl_vtoc.v_part[0].p_flag = V_UNMNT; 28193525Sshidokht 28203525Sshidokht cl->cl_map[0].dkl_cylno = 0; 28213525Sshidokht cl->cl_map[0].dkl_nblk = disksize; 28223525Sshidokht cl->cl_offset[0] = 0; 2823786Slclee 2824786Slclee } else { 2825786Slclee /* 2826786Slclee * Hard disks and removable media cartridges 2827786Slclee */ 28283525Sshidokht cl->cl_g.dkg_rpm = 28293525Sshidokht (cl->cl_pgeom.g_rpm == 0) ? 3600: cl->cl_pgeom.g_rpm; 28303525Sshidokht cl->cl_vtoc.v_sectorsz = cl->cl_sys_blocksize; 2831786Slclee 2832786Slclee /* Add boot slice */ 28333525Sshidokht cl->cl_vtoc.v_part[8].p_start = 0; 28343525Sshidokht cl->cl_vtoc.v_part[8].p_size = phys_spc; 28353525Sshidokht cl->cl_vtoc.v_part[8].p_tag = V_BOOT; 28363525Sshidokht cl->cl_vtoc.v_part[8].p_flag = V_UNMNT; 28373525Sshidokht 28383525Sshidokht cl->cl_map[8].dkl_cylno = 0; 28393525Sshidokht cl->cl_map[8].dkl_nblk = phys_spc; 28403525Sshidokht cl->cl_offset[8] = 0; 28413525Sshidokht 28423525Sshidokht if ((cl->cl_alter_behavior & 2843786Slclee CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT) && 28443525Sshidokht cl->cl_device_type == DTYPE_DIRECT) { 28453525Sshidokht cl->cl_vtoc.v_part[9].p_start = phys_spc; 28463525Sshidokht cl->cl_vtoc.v_part[9].p_size = 2 * phys_spc; 28473525Sshidokht cl->cl_vtoc.v_part[9].p_tag = V_ALTSCTR; 28483525Sshidokht cl->cl_vtoc.v_part[9].p_flag = 0; 28493525Sshidokht 28503525Sshidokht cl->cl_map[9].dkl_cylno = 1; 28513525Sshidokht cl->cl_map[9].dkl_nblk = 2 * phys_spc; 28523525Sshidokht cl->cl_offset[9] = phys_spc; 2853786Slclee } 2854786Slclee } 2855786Slclee 28563525Sshidokht cl->cl_g.dkg_apc = 0; 2857786Slclee 2858786Slclee /* Add backup slice */ 28593525Sshidokht cl->cl_vtoc.v_part[2].p_start = 0; 28603525Sshidokht cl->cl_vtoc.v_part[2].p_size = disksize; 28613525Sshidokht cl->cl_vtoc.v_part[2].p_tag = V_BACKUP; 28623525Sshidokht cl->cl_vtoc.v_part[2].p_flag = V_UNMNT; 28633525Sshidokht 28643525Sshidokht cl->cl_map[2].dkl_cylno = 0; 28653525Sshidokht cl->cl_map[2].dkl_nblk = disksize; 28663525Sshidokht cl->cl_offset[2] = 0; 28673525Sshidokht 28685084Sjohnlev /* 28695084Sjohnlev * single slice (s0) covering the entire disk 28705084Sjohnlev */ 28715084Sjohnlev if (cl->cl_alter_behavior & CMLB_FAKE_LABEL_ONE_PARTITION) { 28725084Sjohnlev cl->cl_vtoc.v_part[0].p_start = 0; 28735084Sjohnlev cl->cl_vtoc.v_part[0].p_tag = V_UNASSIGNED; 28745084Sjohnlev cl->cl_vtoc.v_part[0].p_flag = 0; 28755084Sjohnlev cl->cl_vtoc.v_part[0].p_size = disksize; 28765084Sjohnlev cl->cl_map[0].dkl_cylno = 0; 28775084Sjohnlev cl->cl_map[0].dkl_nblk = disksize; 28785084Sjohnlev cl->cl_offset[0] = 0; 28795084Sjohnlev } 28805084Sjohnlev 28813525Sshidokht (void) sprintf(cl->cl_vtoc.v_asciilabel, "DEFAULT cyl %d alt %d" 28823525Sshidokht " hd %d sec %d", cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl, 28833525Sshidokht cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect); 2884786Slclee 2885786Slclee #else 2886786Slclee #error "No VTOC format defined." 2887786Slclee #endif 2888786Slclee 28893525Sshidokht cl->cl_g.dkg_read_reinstruct = 0; 28903525Sshidokht cl->cl_g.dkg_write_reinstruct = 0; 28913525Sshidokht 28923525Sshidokht cl->cl_g.dkg_intrlv = 1; 28933525Sshidokht 28943525Sshidokht cl->cl_vtoc.v_sanity = VTOC_SANE; 28958169SGabriel.Carrillo@Sun.COM cl->cl_vtoc.v_nparts = V_NUMPAR; 28968169SGabriel.Carrillo@Sun.COM cl->cl_vtoc.v_version = V_VERSION; 28973525Sshidokht 28983525Sshidokht cl->cl_f_geometry_is_valid = TRUE; 28997563SPrasad.Singamsetty@Sun.COM cl->cl_label_from_media = CMLB_LABEL_UNDEF; 29003525Sshidokht 29013525Sshidokht cmlb_dbg(CMLB_INFO, cl, 2902786Slclee "cmlb_build_default_label: Default label created: " 2903786Slclee "cyl: %d\tacyl: %d\tnhead: %d\tnsect: %d\tcap: %d\n", 29043525Sshidokht cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl, cl->cl_g.dkg_nhead, 29053525Sshidokht cl->cl_g.dkg_nsect, cl->cl_blockcount); 2906786Slclee } 2907786Slclee 2908786Slclee 2909786Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 2910786Slclee /* 2911786Slclee * Max CHS values, as they are encoded into bytes, for 1022/254/63 2912786Slclee */ 2913786Slclee #define LBA_MAX_SECT (63 | ((1022 & 0x300) >> 2)) 2914786Slclee #define LBA_MAX_CYL (1022 & 0xFF) 2915786Slclee #define LBA_MAX_HEAD (254) 2916786Slclee 2917786Slclee 2918786Slclee /* 2919786Slclee * Function: cmlb_has_max_chs_vals 2920786Slclee * 2921786Slclee * Description: Return TRUE if Cylinder-Head-Sector values are all at maximum. 2922786Slclee * 2923786Slclee * Arguments: fdp - ptr to CHS info 2924786Slclee * 2925786Slclee * Return Code: True or false 2926786Slclee * 2927786Slclee * Context: Any. 2928786Slclee */ 2929786Slclee static int 2930786Slclee cmlb_has_max_chs_vals(struct ipart *fdp) 2931786Slclee { 2932786Slclee return ((fdp->begcyl == LBA_MAX_CYL) && 2933786Slclee (fdp->beghead == LBA_MAX_HEAD) && 2934786Slclee (fdp->begsect == LBA_MAX_SECT) && 2935786Slclee (fdp->endcyl == LBA_MAX_CYL) && 2936786Slclee (fdp->endhead == LBA_MAX_HEAD) && 2937786Slclee (fdp->endsect == LBA_MAX_SECT)); 2938786Slclee } 2939786Slclee #endif 2940786Slclee 2941786Slclee /* 2942786Slclee * Function: cmlb_dkio_get_geometry 2943786Slclee * 2944786Slclee * Description: This routine is the driver entry point for handling user 2945786Slclee * requests to get the device geometry (DKIOCGGEOM). 2946786Slclee * 2947786Slclee * Arguments: 29483525Sshidokht * arg pointer to user provided dk_geom structure specifying 2949786Slclee * the controller's notion of the current geometry. 29503525Sshidokht * 29513525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 29523525Sshidokht * directly from the mode argument of ioctl(). 29533525Sshidokht * 29543525Sshidokht * tg_cookie cookie from target driver to be passed back to target 29553525Sshidokht * driver when we call back to it through tg_ops. 2956786Slclee * 2957786Slclee * Return Code: 0 2958786Slclee * EFAULT 2959786Slclee * ENXIO 2960786Slclee * EIO 2961786Slclee */ 2962786Slclee static int 29633525Sshidokht cmlb_dkio_get_geometry(struct cmlb_lun *cl, caddr_t arg, int flag, 29643525Sshidokht void *tg_cookie) 2965786Slclee { 2966786Slclee struct dk_geom *tmp_geom = NULL; 2967786Slclee int rval = 0; 2968786Slclee 2969786Slclee /* 2970786Slclee * cmlb_validate_geometry does not spin a disk up 29713525Sshidokht * if it was spcl down. We need to make sure it 2972786Slclee * is ready. 2973786Slclee */ 29743525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 29753525Sshidokht rval = cmlb_validate_geometry(cl, 1, 0, tg_cookie); 2976786Slclee #if defined(_SUNOS_VTOC_8) 2977786Slclee if (rval == EINVAL && 29783525Sshidokht cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8) { 2979786Slclee /* 2980786Slclee * This is to return a default label geometry even when we 2981786Slclee * do not really assume a default label for the device. 2982786Slclee * dad driver utilizes this. 2983786Slclee */ 29847563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount <= CMLB_OLDVTOC_LIMIT) { 29853525Sshidokht cmlb_setup_default_geometry(cl, tg_cookie); 2986786Slclee rval = 0; 2987786Slclee } 2988786Slclee } 2989786Slclee #endif 2990786Slclee if (rval) { 29913525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 2992786Slclee return (rval); 2993786Slclee } 2994786Slclee 2995786Slclee #if defined(__i386) || defined(__amd64) 29963525Sshidokht if (cl->cl_solaris_size == 0) { 29973525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 2998786Slclee return (EIO); 2999786Slclee } 3000786Slclee #endif 3001786Slclee 3002786Slclee /* 3003786Slclee * Make a local copy of the soft state geometry to avoid some potential 3004786Slclee * race conditions associated with holding the mutex and updating the 3005786Slclee * write_reinstruct value 3006786Slclee */ 3007786Slclee tmp_geom = kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP); 30083525Sshidokht bcopy(&cl->cl_g, tmp_geom, sizeof (struct dk_geom)); 3009786Slclee 3010786Slclee if (tmp_geom->dkg_write_reinstruct == 0) { 3011786Slclee tmp_geom->dkg_write_reinstruct = 3012786Slclee (int)((int)(tmp_geom->dkg_nsect * tmp_geom->dkg_rpm * 3013786Slclee cmlb_rot_delay) / (int)60000); 3014786Slclee } 30153525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3016786Slclee 3017786Slclee rval = ddi_copyout(tmp_geom, (void *)arg, sizeof (struct dk_geom), 3018786Slclee flag); 3019786Slclee if (rval != 0) { 3020786Slclee rval = EFAULT; 3021786Slclee } 3022786Slclee 3023786Slclee kmem_free(tmp_geom, sizeof (struct dk_geom)); 3024786Slclee return (rval); 3025786Slclee 3026786Slclee } 3027786Slclee 3028786Slclee 3029786Slclee /* 3030786Slclee * Function: cmlb_dkio_set_geometry 3031786Slclee * 3032786Slclee * Description: This routine is the driver entry point for handling user 3033786Slclee * requests to set the device geometry (DKIOCSGEOM). The actual 3034786Slclee * device geometry is not updated, just the driver "notion" of it. 3035786Slclee * 3036786Slclee * Arguments: 30373525Sshidokht * arg pointer to user provided dk_geom structure used to set 3038786Slclee * the controller's notion of the current geometry. 30393525Sshidokht * 30403525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 30413525Sshidokht * directly from the mode argument of ioctl(). 30423525Sshidokht * 30433525Sshidokht * tg_cookie cookie from target driver to be passed back to target 30443525Sshidokht * driver when we call back to it through tg_ops. 3045786Slclee * 3046786Slclee * Return Code: 0 3047786Slclee * EFAULT 3048786Slclee * ENXIO 3049786Slclee * EIO 3050786Slclee */ 3051786Slclee static int 30523525Sshidokht cmlb_dkio_set_geometry(struct cmlb_lun *cl, caddr_t arg, int flag) 3053786Slclee { 3054786Slclee struct dk_geom *tmp_geom; 3055786Slclee struct dk_map *lp; 3056786Slclee int rval = 0; 3057786Slclee int i; 3058786Slclee 3059786Slclee 3060786Slclee #if defined(__i386) || defined(__amd64) 30613525Sshidokht if (cl->cl_solaris_size == 0) { 3062786Slclee return (EIO); 3063786Slclee } 3064786Slclee #endif 3065786Slclee /* 3066786Slclee * We need to copy the user specified geometry into local 3067786Slclee * storage and then update the softstate. We don't want to hold 3068786Slclee * the mutex and copyin directly from the user to the soft state 3069786Slclee */ 3070786Slclee tmp_geom = (struct dk_geom *) 3071786Slclee kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP); 3072786Slclee rval = ddi_copyin(arg, tmp_geom, sizeof (struct dk_geom), flag); 3073786Slclee if (rval != 0) { 3074786Slclee kmem_free(tmp_geom, sizeof (struct dk_geom)); 3075786Slclee return (EFAULT); 3076786Slclee } 3077786Slclee 30783525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 30793525Sshidokht bcopy(tmp_geom, &cl->cl_g, sizeof (struct dk_geom)); 3080786Slclee for (i = 0; i < NDKMAP; i++) { 30813525Sshidokht lp = &cl->cl_map[i]; 30823525Sshidokht cl->cl_offset[i] = 30833525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno; 3084786Slclee #if defined(__i386) || defined(__amd64) 30853525Sshidokht cl->cl_offset[i] += cl->cl_solaris_offset; 3086786Slclee #endif 3087786Slclee } 30883525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 30893525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3090786Slclee kmem_free(tmp_geom, sizeof (struct dk_geom)); 3091786Slclee 3092786Slclee return (rval); 3093786Slclee } 3094786Slclee 3095786Slclee /* 3096786Slclee * Function: cmlb_dkio_get_partition 3097786Slclee * 3098786Slclee * Description: This routine is the driver entry point for handling user 3099786Slclee * requests to get the partition table (DKIOCGAPART). 3100786Slclee * 3101786Slclee * Arguments: 31023525Sshidokht * arg pointer to user provided dk_allmap structure specifying 3103786Slclee * the controller's notion of the current partition table. 31043525Sshidokht * 31053525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 31063525Sshidokht * directly from the mode argument of ioctl(). 31073525Sshidokht * 31083525Sshidokht * tg_cookie cookie from target driver to be passed back to target 31093525Sshidokht * driver when we call back to it through tg_ops. 3110786Slclee * 3111786Slclee * Return Code: 0 3112786Slclee * EFAULT 3113786Slclee * ENXIO 3114786Slclee * EIO 3115786Slclee */ 3116786Slclee static int 31173525Sshidokht cmlb_dkio_get_partition(struct cmlb_lun *cl, caddr_t arg, int flag, 31183525Sshidokht void *tg_cookie) 3119786Slclee { 3120786Slclee int rval = 0; 3121786Slclee int size; 3122786Slclee 3123786Slclee /* 3124786Slclee * Make sure the geometry is valid before getting the partition 3125786Slclee * information. 3126786Slclee */ 31273525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 31283525Sshidokht if ((rval = cmlb_validate_geometry(cl, 1, 0, tg_cookie)) != 0) { 31293525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3130786Slclee return (rval); 3131786Slclee } 31323525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3133786Slclee 3134786Slclee #if defined(__i386) || defined(__amd64) 31353525Sshidokht if (cl->cl_solaris_size == 0) { 3136786Slclee return (EIO); 3137786Slclee } 3138786Slclee #endif 3139786Slclee 3140786Slclee #ifdef _MULTI_DATAMODEL 3141786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 3142786Slclee case DDI_MODEL_ILP32: { 3143786Slclee struct dk_map32 dk_map32[NDKMAP]; 3144786Slclee int i; 3145786Slclee 3146786Slclee for (i = 0; i < NDKMAP; i++) { 31473525Sshidokht dk_map32[i].dkl_cylno = cl->cl_map[i].dkl_cylno; 31483525Sshidokht dk_map32[i].dkl_nblk = cl->cl_map[i].dkl_nblk; 3149786Slclee } 3150786Slclee size = NDKMAP * sizeof (struct dk_map32); 3151786Slclee rval = ddi_copyout(dk_map32, (void *)arg, size, flag); 3152786Slclee if (rval != 0) { 3153786Slclee rval = EFAULT; 3154786Slclee } 3155786Slclee break; 3156786Slclee } 3157786Slclee case DDI_MODEL_NONE: 3158786Slclee size = NDKMAP * sizeof (struct dk_map); 31593525Sshidokht rval = ddi_copyout(cl->cl_map, (void *)arg, size, flag); 3160786Slclee if (rval != 0) { 3161786Slclee rval = EFAULT; 3162786Slclee } 3163786Slclee break; 3164786Slclee } 3165786Slclee #else /* ! _MULTI_DATAMODEL */ 3166786Slclee size = NDKMAP * sizeof (struct dk_map); 31673525Sshidokht rval = ddi_copyout(cl->cl_map, (void *)arg, size, flag); 3168786Slclee if (rval != 0) { 3169786Slclee rval = EFAULT; 3170786Slclee } 3171786Slclee #endif /* _MULTI_DATAMODEL */ 3172786Slclee return (rval); 3173786Slclee } 3174786Slclee 3175786Slclee /* 3176786Slclee * Function: cmlb_dkio_set_partition 3177786Slclee * 3178786Slclee * Description: This routine is the driver entry point for handling user 3179786Slclee * requests to set the partition table (DKIOCSAPART). The actual 3180786Slclee * device partition is not updated. 3181786Slclee * 3182786Slclee * Arguments: 3183786Slclee * arg - pointer to user provided dk_allmap structure used to set 3184786Slclee * the controller's notion of the partition table. 3185786Slclee * flag - this argument is a pass through to ddi_copyxxx() 3186786Slclee * directly from the mode argument of ioctl(). 3187786Slclee * 3188786Slclee * Return Code: 0 3189786Slclee * EINVAL 3190786Slclee * EFAULT 3191786Slclee * ENXIO 3192786Slclee * EIO 3193786Slclee */ 3194786Slclee static int 31953525Sshidokht cmlb_dkio_set_partition(struct cmlb_lun *cl, caddr_t arg, int flag) 3196786Slclee { 3197786Slclee struct dk_map dk_map[NDKMAP]; 3198786Slclee struct dk_map *lp; 3199786Slclee int rval = 0; 3200786Slclee int size; 3201786Slclee int i; 3202786Slclee #if defined(_SUNOS_VTOC_16) 3203786Slclee struct dkl_partition *vp; 3204786Slclee #endif 3205786Slclee 3206786Slclee /* 3207786Slclee * Set the map for all logical partitions. We lock 3208786Slclee * the priority just to make sure an interrupt doesn't 3209786Slclee * come in while the map is half updated. 3210786Slclee */ 32113525Sshidokht _NOTE(DATA_READABLE_WITHOUT_LOCK(cmlb_lun::cl_solaris_size)) 32123525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 32133525Sshidokht 32147563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) { 32153525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3216786Slclee return (ENOTSUP); 3217786Slclee } 32183525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 32193525Sshidokht if (cl->cl_solaris_size == 0) { 3220786Slclee return (EIO); 3221786Slclee } 3222786Slclee 3223786Slclee #ifdef _MULTI_DATAMODEL 3224786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 3225786Slclee case DDI_MODEL_ILP32: { 3226786Slclee struct dk_map32 dk_map32[NDKMAP]; 3227786Slclee 3228786Slclee size = NDKMAP * sizeof (struct dk_map32); 3229786Slclee rval = ddi_copyin((void *)arg, dk_map32, size, flag); 3230786Slclee if (rval != 0) { 3231786Slclee return (EFAULT); 3232786Slclee } 3233786Slclee for (i = 0; i < NDKMAP; i++) { 3234786Slclee dk_map[i].dkl_cylno = dk_map32[i].dkl_cylno; 3235786Slclee dk_map[i].dkl_nblk = dk_map32[i].dkl_nblk; 3236786Slclee } 3237786Slclee break; 3238786Slclee } 3239786Slclee case DDI_MODEL_NONE: 3240786Slclee size = NDKMAP * sizeof (struct dk_map); 3241786Slclee rval = ddi_copyin((void *)arg, dk_map, size, flag); 3242786Slclee if (rval != 0) { 3243786Slclee return (EFAULT); 3244786Slclee } 3245786Slclee break; 3246786Slclee } 3247786Slclee #else /* ! _MULTI_DATAMODEL */ 3248786Slclee size = NDKMAP * sizeof (struct dk_map); 3249786Slclee rval = ddi_copyin((void *)arg, dk_map, size, flag); 3250786Slclee if (rval != 0) { 3251786Slclee return (EFAULT); 3252786Slclee } 3253786Slclee #endif /* _MULTI_DATAMODEL */ 3254786Slclee 32553525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 3256786Slclee /* Note: The size used in this bcopy is set based upon the data model */ 32573525Sshidokht bcopy(dk_map, cl->cl_map, size); 3258786Slclee #if defined(_SUNOS_VTOC_16) 32593525Sshidokht vp = (struct dkl_partition *)&(cl->cl_vtoc); 3260786Slclee #endif /* defined(_SUNOS_VTOC_16) */ 3261786Slclee for (i = 0; i < NDKMAP; i++) { 32623525Sshidokht lp = &cl->cl_map[i]; 32633525Sshidokht cl->cl_offset[i] = 32643525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno; 3265786Slclee #if defined(_SUNOS_VTOC_16) 32663525Sshidokht vp->p_start = cl->cl_offset[i]; 3267786Slclee vp->p_size = lp->dkl_nblk; 3268786Slclee vp++; 3269786Slclee #endif /* defined(_SUNOS_VTOC_16) */ 3270786Slclee #if defined(__i386) || defined(__amd64) 32713525Sshidokht cl->cl_offset[i] += cl->cl_solaris_offset; 3272786Slclee #endif 3273786Slclee } 32743525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3275786Slclee return (rval); 3276786Slclee } 3277786Slclee 3278786Slclee 3279786Slclee /* 3280786Slclee * Function: cmlb_dkio_get_vtoc 3281786Slclee * 3282786Slclee * Description: This routine is the driver entry point for handling user 3283786Slclee * requests to get the current volume table of contents 3284786Slclee * (DKIOCGVTOC). 3285786Slclee * 3286786Slclee * Arguments: 32873525Sshidokht * arg pointer to user provided vtoc structure specifying 3288786Slclee * the current vtoc. 32893525Sshidokht * 32903525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 32913525Sshidokht * directly from the mode argument of ioctl(). 32923525Sshidokht * 32933525Sshidokht * tg_cookie cookie from target driver to be passed back to target 32943525Sshidokht * driver when we call back to it through tg_ops. 3295786Slclee * 3296786Slclee * Return Code: 0 3297786Slclee * EFAULT 3298786Slclee * ENXIO 3299786Slclee * EIO 3300786Slclee */ 3301786Slclee static int 33023525Sshidokht cmlb_dkio_get_vtoc(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie) 3303786Slclee { 3304786Slclee #if defined(_SUNOS_VTOC_8) 3305786Slclee struct vtoc user_vtoc; 3306786Slclee #endif /* defined(_SUNOS_VTOC_8) */ 3307786Slclee int rval = 0; 3308786Slclee 33093525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 33107563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) { 33117563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 33127563SPrasad.Singamsetty@Sun.COM return (EOVERFLOW); 33137563SPrasad.Singamsetty@Sun.COM } 33147563SPrasad.Singamsetty@Sun.COM 33153525Sshidokht rval = cmlb_validate_geometry(cl, 1, 0, tg_cookie); 3316786Slclee 3317786Slclee #if defined(_SUNOS_VTOC_8) 3318786Slclee if (rval == EINVAL && 33193525Sshidokht (cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8)) { 3320786Slclee /* 3321786Slclee * This is to return a default label even when we do not 3322786Slclee * really assume a default label for the device. 3323786Slclee * dad driver utilizes this. 3324786Slclee */ 33257563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount <= CMLB_OLDVTOC_LIMIT) { 33263525Sshidokht cmlb_setup_default_geometry(cl, tg_cookie); 3327786Slclee rval = 0; 3328786Slclee } 3329786Slclee } 3330786Slclee #endif 3331786Slclee if (rval) { 33323525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3333786Slclee return (rval); 3334786Slclee } 3335786Slclee 3336786Slclee #if defined(_SUNOS_VTOC_8) 33373525Sshidokht cmlb_build_user_vtoc(cl, &user_vtoc); 33383525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3339786Slclee 3340786Slclee #ifdef _MULTI_DATAMODEL 3341786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 3342786Slclee case DDI_MODEL_ILP32: { 3343786Slclee struct vtoc32 user_vtoc32; 3344786Slclee 3345786Slclee vtoctovtoc32(user_vtoc, user_vtoc32); 3346786Slclee if (ddi_copyout(&user_vtoc32, (void *)arg, 3347786Slclee sizeof (struct vtoc32), flag)) { 3348786Slclee return (EFAULT); 3349786Slclee } 3350786Slclee break; 3351786Slclee } 3352786Slclee 3353786Slclee case DDI_MODEL_NONE: 3354786Slclee if (ddi_copyout(&user_vtoc, (void *)arg, 3355786Slclee sizeof (struct vtoc), flag)) { 3356786Slclee return (EFAULT); 3357786Slclee } 3358786Slclee break; 3359786Slclee } 3360786Slclee #else /* ! _MULTI_DATAMODEL */ 3361786Slclee if (ddi_copyout(&user_vtoc, (void *)arg, sizeof (struct vtoc), flag)) { 3362786Slclee return (EFAULT); 3363786Slclee } 3364786Slclee #endif /* _MULTI_DATAMODEL */ 3365786Slclee 3366786Slclee #elif defined(_SUNOS_VTOC_16) 33673525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3368786Slclee 3369786Slclee #ifdef _MULTI_DATAMODEL 3370786Slclee /* 33713525Sshidokht * The cl_vtoc structure is a "struct dk_vtoc" which is always 3372786Slclee * 32-bit to maintain compatibility with existing on-disk 3373786Slclee * structures. Thus, we need to convert the structure when copying 3374786Slclee * it out to a datamodel-dependent "struct vtoc" in a 64-bit 3375786Slclee * program. If the target is a 32-bit program, then no conversion 3376786Slclee * is necessary. 3377786Slclee */ 3378786Slclee /* LINTED: logical expression always true: op "||" */ 33793525Sshidokht ASSERT(sizeof (cl->cl_vtoc) == sizeof (struct vtoc32)); 3380786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 3381786Slclee case DDI_MODEL_ILP32: 33823525Sshidokht if (ddi_copyout(&(cl->cl_vtoc), (void *)arg, 33833525Sshidokht sizeof (cl->cl_vtoc), flag)) { 3384786Slclee return (EFAULT); 3385786Slclee } 3386786Slclee break; 3387786Slclee 3388786Slclee case DDI_MODEL_NONE: { 3389786Slclee struct vtoc user_vtoc; 3390786Slclee 33913525Sshidokht vtoc32tovtoc(cl->cl_vtoc, user_vtoc); 3392786Slclee if (ddi_copyout(&user_vtoc, (void *)arg, 3393786Slclee sizeof (struct vtoc), flag)) { 3394786Slclee return (EFAULT); 3395786Slclee } 3396786Slclee break; 3397786Slclee } 3398786Slclee } 3399786Slclee #else /* ! _MULTI_DATAMODEL */ 34003525Sshidokht if (ddi_copyout(&(cl->cl_vtoc), (void *)arg, sizeof (cl->cl_vtoc), 3401786Slclee flag)) { 3402786Slclee return (EFAULT); 3403786Slclee } 3404786Slclee #endif /* _MULTI_DATAMODEL */ 3405786Slclee #else 3406786Slclee #error "No VTOC format defined." 3407786Slclee #endif 3408786Slclee 3409786Slclee return (rval); 3410786Slclee } 3411786Slclee 34127563SPrasad.Singamsetty@Sun.COM 34137563SPrasad.Singamsetty@Sun.COM /* 34147563SPrasad.Singamsetty@Sun.COM * Function: cmlb_dkio_get_extvtoc 34157563SPrasad.Singamsetty@Sun.COM */ 34167563SPrasad.Singamsetty@Sun.COM static int 34177563SPrasad.Singamsetty@Sun.COM cmlb_dkio_get_extvtoc(struct cmlb_lun *cl, caddr_t arg, int flag, 34187563SPrasad.Singamsetty@Sun.COM void *tg_cookie) 34197563SPrasad.Singamsetty@Sun.COM { 34207563SPrasad.Singamsetty@Sun.COM struct extvtoc ext_vtoc; 34217563SPrasad.Singamsetty@Sun.COM #if defined(_SUNOS_VTOC_8) 34227563SPrasad.Singamsetty@Sun.COM struct vtoc user_vtoc; 34237563SPrasad.Singamsetty@Sun.COM #endif /* defined(_SUNOS_VTOC_8) */ 34247563SPrasad.Singamsetty@Sun.COM int rval = 0; 34257563SPrasad.Singamsetty@Sun.COM 34267563SPrasad.Singamsetty@Sun.COM bzero(&ext_vtoc, sizeof (struct extvtoc)); 34277563SPrasad.Singamsetty@Sun.COM mutex_enter(CMLB_MUTEX(cl)); 34287563SPrasad.Singamsetty@Sun.COM rval = cmlb_validate_geometry(cl, 1, 0, tg_cookie); 34297563SPrasad.Singamsetty@Sun.COM 34307563SPrasad.Singamsetty@Sun.COM #if defined(_SUNOS_VTOC_8) 34317563SPrasad.Singamsetty@Sun.COM if (rval == EINVAL && 34327563SPrasad.Singamsetty@Sun.COM (cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8)) { 34337563SPrasad.Singamsetty@Sun.COM /* 34347563SPrasad.Singamsetty@Sun.COM * This is to return a default label even when we do not 34357563SPrasad.Singamsetty@Sun.COM * really assume a default label for the device. 34367563SPrasad.Singamsetty@Sun.COM * dad driver utilizes this. 34377563SPrasad.Singamsetty@Sun.COM */ 34387563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount <= CMLB_OLDVTOC_LIMIT) { 34397563SPrasad.Singamsetty@Sun.COM cmlb_setup_default_geometry(cl, tg_cookie); 34407563SPrasad.Singamsetty@Sun.COM rval = 0; 34417563SPrasad.Singamsetty@Sun.COM } 34427563SPrasad.Singamsetty@Sun.COM } 34437563SPrasad.Singamsetty@Sun.COM #endif 34447563SPrasad.Singamsetty@Sun.COM if (rval) { 34457563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 34467563SPrasad.Singamsetty@Sun.COM return (rval); 34477563SPrasad.Singamsetty@Sun.COM } 34487563SPrasad.Singamsetty@Sun.COM 34497563SPrasad.Singamsetty@Sun.COM #if defined(_SUNOS_VTOC_8) 34507563SPrasad.Singamsetty@Sun.COM cmlb_build_user_vtoc(cl, &user_vtoc); 34517563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 34527563SPrasad.Singamsetty@Sun.COM 34537563SPrasad.Singamsetty@Sun.COM /* 34547563SPrasad.Singamsetty@Sun.COM * Checking callers data model does not make much sense here 34557563SPrasad.Singamsetty@Sun.COM * since extvtoc will always be equivalent to 64bit vtoc. 34567563SPrasad.Singamsetty@Sun.COM * What is important is whether the kernel is in 32 or 64 bit 34577563SPrasad.Singamsetty@Sun.COM */ 34587563SPrasad.Singamsetty@Sun.COM 34597563SPrasad.Singamsetty@Sun.COM #ifdef _LP64 34607563SPrasad.Singamsetty@Sun.COM if (ddi_copyout(&user_vtoc, (void *)arg, 34617563SPrasad.Singamsetty@Sun.COM sizeof (struct extvtoc), flag)) { 34627563SPrasad.Singamsetty@Sun.COM return (EFAULT); 34637563SPrasad.Singamsetty@Sun.COM } 34647563SPrasad.Singamsetty@Sun.COM #else 34657563SPrasad.Singamsetty@Sun.COM vtoc32tovtoc(user_vtoc, ext_vtoc); 34667563SPrasad.Singamsetty@Sun.COM if (ddi_copyout(&ext_vtoc, (void *)arg, 34677563SPrasad.Singamsetty@Sun.COM sizeof (struct extvtoc), flag)) { 34687563SPrasad.Singamsetty@Sun.COM return (EFAULT); 34697563SPrasad.Singamsetty@Sun.COM } 34707563SPrasad.Singamsetty@Sun.COM #endif 34717563SPrasad.Singamsetty@Sun.COM 34727563SPrasad.Singamsetty@Sun.COM #elif defined(_SUNOS_VTOC_16) 34737563SPrasad.Singamsetty@Sun.COM /* 34747563SPrasad.Singamsetty@Sun.COM * The cl_vtoc structure is a "struct dk_vtoc" which is always 34757563SPrasad.Singamsetty@Sun.COM * 32-bit to maintain compatibility with existing on-disk 34767563SPrasad.Singamsetty@Sun.COM * structures. Thus, we need to convert the structure when copying 34777563SPrasad.Singamsetty@Sun.COM * it out to extvtoc 34787563SPrasad.Singamsetty@Sun.COM */ 34797563SPrasad.Singamsetty@Sun.COM vtoc32tovtoc(cl->cl_vtoc, ext_vtoc); 34807909SXiao.L@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 34817563SPrasad.Singamsetty@Sun.COM 34827563SPrasad.Singamsetty@Sun.COM if (ddi_copyout(&ext_vtoc, (void *)arg, sizeof (struct extvtoc), flag)) 34837563SPrasad.Singamsetty@Sun.COM return (EFAULT); 34847563SPrasad.Singamsetty@Sun.COM #else 34857563SPrasad.Singamsetty@Sun.COM #error "No VTOC format defined." 34867563SPrasad.Singamsetty@Sun.COM #endif 34877563SPrasad.Singamsetty@Sun.COM 34887563SPrasad.Singamsetty@Sun.COM return (rval); 34897563SPrasad.Singamsetty@Sun.COM } 3490786Slclee static int 34913525Sshidokht cmlb_dkio_get_efi(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie) 3492786Slclee { 3493786Slclee dk_efi_t user_efi; 3494786Slclee int rval = 0; 3495786Slclee void *buffer; 34963525Sshidokht diskaddr_t tgt_lba; 3497786Slclee 3498786Slclee if (ddi_copyin(arg, &user_efi, sizeof (dk_efi_t), flag)) 3499786Slclee return (EFAULT); 3500786Slclee 3501786Slclee user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64; 3502786Slclee 35033525Sshidokht tgt_lba = user_efi.dki_lba; 35043525Sshidokht 35053525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 35063525Sshidokht if ((cmlb_check_update_blockcount(cl, tg_cookie) != 0) || 35073525Sshidokht (cl->cl_tgt_blocksize == 0)) { 35083525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 35093525Sshidokht return (EINVAL); 35103525Sshidokht } 35113525Sshidokht if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) 35123525Sshidokht tgt_lba = tgt_lba * cl->cl_tgt_blocksize / 35133525Sshidokht cl->cl_sys_blocksize; 35143525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 35153525Sshidokht 3516786Slclee buffer = kmem_alloc(user_efi.dki_length, KM_SLEEP); 35173525Sshidokht rval = DK_TG_READ(cl, buffer, tgt_lba, user_efi.dki_length, tg_cookie); 3518786Slclee if (rval == 0 && ddi_copyout(buffer, user_efi.dki_data, 3519786Slclee user_efi.dki_length, flag) != 0) 3520786Slclee rval = EFAULT; 3521786Slclee 3522786Slclee kmem_free(buffer, user_efi.dki_length); 3523786Slclee return (rval); 3524786Slclee } 3525786Slclee 35263525Sshidokht #if defined(_SUNOS_VTOC_8) 3527786Slclee /* 3528786Slclee * Function: cmlb_build_user_vtoc 3529786Slclee * 3530786Slclee * Description: This routine populates a pass by reference variable with the 3531786Slclee * current volume table of contents. 3532786Slclee * 35333525Sshidokht * Arguments: cl - driver soft state (unit) structure 3534786Slclee * user_vtoc - pointer to vtoc structure to be populated 3535786Slclee */ 3536786Slclee static void 35373525Sshidokht cmlb_build_user_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc) 3538786Slclee { 3539786Slclee struct dk_map2 *lpart; 3540786Slclee struct dk_map *lmap; 3541786Slclee struct partition *vpart; 35427563SPrasad.Singamsetty@Sun.COM uint32_t nblks; 3543786Slclee int i; 3544786Slclee 35453525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 3546786Slclee 3547786Slclee /* 3548786Slclee * Return vtoc structure fields in the provided VTOC area, addressed 3549786Slclee * by *vtoc. 3550786Slclee */ 3551786Slclee bzero(user_vtoc, sizeof (struct vtoc)); 35523525Sshidokht user_vtoc->v_bootinfo[0] = cl->cl_vtoc.v_bootinfo[0]; 35533525Sshidokht user_vtoc->v_bootinfo[1] = cl->cl_vtoc.v_bootinfo[1]; 35543525Sshidokht user_vtoc->v_bootinfo[2] = cl->cl_vtoc.v_bootinfo[2]; 3555786Slclee user_vtoc->v_sanity = VTOC_SANE; 35563525Sshidokht user_vtoc->v_version = cl->cl_vtoc.v_version; 35573525Sshidokht bcopy(cl->cl_vtoc.v_volume, user_vtoc->v_volume, LEN_DKL_VVOL); 35583525Sshidokht user_vtoc->v_sectorsz = cl->cl_sys_blocksize; 35593525Sshidokht user_vtoc->v_nparts = cl->cl_vtoc.v_nparts; 3560786Slclee 3561786Slclee for (i = 0; i < 10; i++) 35623525Sshidokht user_vtoc->v_reserved[i] = cl->cl_vtoc.v_reserved[i]; 3563786Slclee 3564786Slclee /* 3565786Slclee * Convert partitioning information. 3566786Slclee * 3567786Slclee * Note the conversion from starting cylinder number 3568786Slclee * to starting sector number. 3569786Slclee */ 35703525Sshidokht lmap = cl->cl_map; 35713525Sshidokht lpart = (struct dk_map2 *)cl->cl_vtoc.v_part; 3572786Slclee vpart = user_vtoc->v_part; 3573786Slclee 35743525Sshidokht nblks = cl->cl_g.dkg_nsect * cl->cl_g.dkg_nhead; 3575786Slclee 3576786Slclee for (i = 0; i < V_NUMPAR; i++) { 3577786Slclee vpart->p_tag = lpart->p_tag; 3578786Slclee vpart->p_flag = lpart->p_flag; 3579786Slclee vpart->p_start = lmap->dkl_cylno * nblks; 3580786Slclee vpart->p_size = lmap->dkl_nblk; 3581786Slclee lmap++; 3582786Slclee lpart++; 3583786Slclee vpart++; 3584786Slclee 3585786Slclee /* (4364927) */ 35863525Sshidokht user_vtoc->timestamp[i] = (time_t)cl->cl_vtoc.v_timestamp[i]; 3587786Slclee } 3588786Slclee 35893525Sshidokht bcopy(cl->cl_asciilabel, user_vtoc->v_asciilabel, LEN_DKL_ASCII); 3590786Slclee } 35913525Sshidokht #endif 3592786Slclee 3593786Slclee static int 35943525Sshidokht cmlb_dkio_partition(struct cmlb_lun *cl, caddr_t arg, int flag, 35953525Sshidokht void *tg_cookie) 3596786Slclee { 3597786Slclee struct partition64 p64; 3598786Slclee int rval = 0; 3599786Slclee uint_t nparts; 3600786Slclee efi_gpe_t *partitions; 3601786Slclee efi_gpt_t *buffer; 3602786Slclee diskaddr_t gpe_lba; 3603786Slclee 3604786Slclee if (ddi_copyin((const void *)arg, &p64, 3605786Slclee sizeof (struct partition64), flag)) { 3606786Slclee return (EFAULT); 3607786Slclee } 3608786Slclee 3609786Slclee buffer = kmem_alloc(EFI_MIN_ARRAY_SIZE, KM_SLEEP); 36103525Sshidokht rval = DK_TG_READ(cl, buffer, 1, DEV_BSIZE, tg_cookie); 3611786Slclee if (rval != 0) 3612786Slclee goto done_error; 3613786Slclee 3614786Slclee cmlb_swap_efi_gpt(buffer); 3615786Slclee 3616786Slclee if ((rval = cmlb_validate_efi(buffer)) != 0) 3617786Slclee goto done_error; 3618786Slclee 3619786Slclee nparts = buffer->efi_gpt_NumberOfPartitionEntries; 3620786Slclee gpe_lba = buffer->efi_gpt_PartitionEntryLBA; 3621786Slclee if (p64.p_partno > nparts) { 3622786Slclee /* couldn't find it */ 3623786Slclee rval = ESRCH; 3624786Slclee goto done_error; 3625786Slclee } 3626786Slclee /* 3627786Slclee * if we're dealing with a partition that's out of the normal 3628786Slclee * 16K block, adjust accordingly 3629786Slclee */ 3630786Slclee gpe_lba += p64.p_partno / sizeof (efi_gpe_t); 36313525Sshidokht rval = DK_TG_READ(cl, buffer, gpe_lba, EFI_MIN_ARRAY_SIZE, tg_cookie); 3632786Slclee 3633786Slclee if (rval) { 3634786Slclee goto done_error; 3635786Slclee } 3636786Slclee partitions = (efi_gpe_t *)buffer; 3637786Slclee 3638786Slclee cmlb_swap_efi_gpe(nparts, partitions); 3639786Slclee 3640786Slclee partitions += p64.p_partno; 3641786Slclee bcopy(&partitions->efi_gpe_PartitionTypeGUID, &p64.p_type, 3642786Slclee sizeof (struct uuid)); 3643786Slclee p64.p_start = partitions->efi_gpe_StartingLBA; 3644786Slclee p64.p_size = partitions->efi_gpe_EndingLBA - 36453525Sshidokht p64.p_start + 1; 3646786Slclee 3647786Slclee if (ddi_copyout(&p64, (void *)arg, sizeof (struct partition64), flag)) 3648786Slclee rval = EFAULT; 3649786Slclee 3650786Slclee done_error: 3651786Slclee kmem_free(buffer, EFI_MIN_ARRAY_SIZE); 3652786Slclee return (rval); 3653786Slclee } 3654786Slclee 3655786Slclee 3656786Slclee /* 3657786Slclee * Function: cmlb_dkio_set_vtoc 3658786Slclee * 3659786Slclee * Description: This routine is the driver entry point for handling user 3660786Slclee * requests to set the current volume table of contents 3661786Slclee * (DKIOCSVTOC). 3662786Slclee * 36633525Sshidokht * Arguments: 36643525Sshidokht * dev the device number 36653525Sshidokht * arg pointer to user provided vtoc structure used to set the 3666786Slclee * current vtoc. 36673525Sshidokht * 36683525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 36693525Sshidokht * directly from the mode argument of ioctl(). 36703525Sshidokht * 36713525Sshidokht * tg_cookie cookie from target driver to be passed back to target 36723525Sshidokht * driver when we call back to it through tg_ops. 3673786Slclee * 3674786Slclee * Return Code: 0 3675786Slclee * EFAULT 3676786Slclee * ENXIO 3677786Slclee * EINVAL 3678786Slclee * ENOTSUP 3679786Slclee */ 3680786Slclee static int 36813525Sshidokht cmlb_dkio_set_vtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag, 36823525Sshidokht void *tg_cookie) 3683786Slclee { 3684786Slclee struct vtoc user_vtoc; 3685786Slclee int rval = 0; 36866318Sedp boolean_t internal; 36876318Sedp 36886318Sedp internal = ((cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0); 3689786Slclee 3690786Slclee #ifdef _MULTI_DATAMODEL 3691786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 3692786Slclee case DDI_MODEL_ILP32: { 3693786Slclee struct vtoc32 user_vtoc32; 3694786Slclee 3695786Slclee if (ddi_copyin((const void *)arg, &user_vtoc32, 3696786Slclee sizeof (struct vtoc32), flag)) { 3697786Slclee return (EFAULT); 3698786Slclee } 3699786Slclee vtoc32tovtoc(user_vtoc32, user_vtoc); 3700786Slclee break; 3701786Slclee } 3702786Slclee 3703786Slclee case DDI_MODEL_NONE: 3704786Slclee if (ddi_copyin((const void *)arg, &user_vtoc, 3705786Slclee sizeof (struct vtoc), flag)) { 3706786Slclee return (EFAULT); 3707786Slclee } 3708786Slclee break; 3709786Slclee } 3710786Slclee #else /* ! _MULTI_DATAMODEL */ 3711786Slclee if (ddi_copyin((const void *)arg, &user_vtoc, 3712786Slclee sizeof (struct vtoc), flag)) { 3713786Slclee return (EFAULT); 3714786Slclee } 3715786Slclee #endif /* _MULTI_DATAMODEL */ 3716786Slclee 37173525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 37187563SPrasad.Singamsetty@Sun.COM 37197563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) { 37203525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 37217563SPrasad.Singamsetty@Sun.COM return (EOVERFLOW); 3722786Slclee } 37233525Sshidokht 37243525Sshidokht #if defined(__i386) || defined(__amd64) 37253525Sshidokht if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) { 37263525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 37273525Sshidokht return (EINVAL); 37283525Sshidokht } 37293525Sshidokht #endif 37303525Sshidokht 37313525Sshidokht if (cl->cl_g.dkg_ncyl == 0) { 37323525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3733786Slclee return (EINVAL); 3734786Slclee } 3735786Slclee 37363525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 37373525Sshidokht cmlb_clear_efi(cl, tg_cookie); 37383525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd"); 37393525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd,raw"); 37406318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h", 3741786Slclee S_IFBLK, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 37426318Sedp cl->cl_node_type, NULL, internal); 37436318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h,raw", 3744786Slclee S_IFCHR, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 37456318Sedp cl->cl_node_type, NULL, internal); 37463525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 37473525Sshidokht 37483525Sshidokht if ((rval = cmlb_build_label_vtoc(cl, &user_vtoc)) == 0) { 37493525Sshidokht if ((rval = cmlb_write_label(cl, tg_cookie)) == 0) { 37503525Sshidokht if (cmlb_validate_geometry(cl, 1, 0, tg_cookie) != 0) { 37513525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 3752786Slclee "cmlb_dkio_set_vtoc: " 3753786Slclee "Failed validate geometry\n"); 3754786Slclee } 37557563SPrasad.Singamsetty@Sun.COM cl->cl_msglog_flag |= CMLB_ALLOW_2TB_WARN; 3756786Slclee } 3757786Slclee } 37583525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3759786Slclee return (rval); 3760786Slclee } 3761786Slclee 37627563SPrasad.Singamsetty@Sun.COM /* 37637563SPrasad.Singamsetty@Sun.COM * Function: cmlb_dkio_set_extvtoc 37647563SPrasad.Singamsetty@Sun.COM */ 37657563SPrasad.Singamsetty@Sun.COM static int 37667563SPrasad.Singamsetty@Sun.COM cmlb_dkio_set_extvtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag, 37677563SPrasad.Singamsetty@Sun.COM void *tg_cookie) 37687563SPrasad.Singamsetty@Sun.COM { 37697563SPrasad.Singamsetty@Sun.COM int rval = 0; 37707563SPrasad.Singamsetty@Sun.COM struct vtoc user_vtoc; 37717563SPrasad.Singamsetty@Sun.COM 37727563SPrasad.Singamsetty@Sun.COM /* 37737563SPrasad.Singamsetty@Sun.COM * Checking callers data model does not make much sense here 37747563SPrasad.Singamsetty@Sun.COM * since extvtoc will always be equivalent to 64bit vtoc. 37757563SPrasad.Singamsetty@Sun.COM * What is important is whether the kernel is in 32 or 64 bit 37767563SPrasad.Singamsetty@Sun.COM */ 37777563SPrasad.Singamsetty@Sun.COM 37787563SPrasad.Singamsetty@Sun.COM #ifdef _LP64 37797563SPrasad.Singamsetty@Sun.COM if (ddi_copyin((const void *)arg, &user_vtoc, 37807563SPrasad.Singamsetty@Sun.COM sizeof (struct extvtoc), flag)) { 37817563SPrasad.Singamsetty@Sun.COM return (EFAULT); 37827563SPrasad.Singamsetty@Sun.COM } 37837563SPrasad.Singamsetty@Sun.COM #else 37847563SPrasad.Singamsetty@Sun.COM struct extvtoc user_extvtoc; 37857563SPrasad.Singamsetty@Sun.COM if (ddi_copyin((const void *)arg, &user_extvtoc, 37867563SPrasad.Singamsetty@Sun.COM sizeof (struct extvtoc), flag)) { 37877563SPrasad.Singamsetty@Sun.COM return (EFAULT); 37887563SPrasad.Singamsetty@Sun.COM } 37897563SPrasad.Singamsetty@Sun.COM 37907563SPrasad.Singamsetty@Sun.COM vtoctovtoc32(user_extvtoc, user_vtoc); 37917563SPrasad.Singamsetty@Sun.COM #endif 37927563SPrasad.Singamsetty@Sun.COM 37937563SPrasad.Singamsetty@Sun.COM mutex_enter(CMLB_MUTEX(cl)); 37947563SPrasad.Singamsetty@Sun.COM #if defined(__i386) || defined(__amd64) 37957563SPrasad.Singamsetty@Sun.COM if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) { 37967563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 37977563SPrasad.Singamsetty@Sun.COM return (EINVAL); 37987563SPrasad.Singamsetty@Sun.COM } 37997563SPrasad.Singamsetty@Sun.COM #endif 38007563SPrasad.Singamsetty@Sun.COM 38017563SPrasad.Singamsetty@Sun.COM if (cl->cl_g.dkg_ncyl == 0) { 38027563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 38037563SPrasad.Singamsetty@Sun.COM return (EINVAL); 38047563SPrasad.Singamsetty@Sun.COM } 38057563SPrasad.Singamsetty@Sun.COM 38067563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 38077563SPrasad.Singamsetty@Sun.COM cmlb_clear_efi(cl, tg_cookie); 38087563SPrasad.Singamsetty@Sun.COM ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd"); 38097563SPrasad.Singamsetty@Sun.COM ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd,raw"); 38107563SPrasad.Singamsetty@Sun.COM (void) ddi_create_minor_node(CMLB_DEVINFO(cl), "h", 38117563SPrasad.Singamsetty@Sun.COM S_IFBLK, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 38127563SPrasad.Singamsetty@Sun.COM cl->cl_node_type, NULL); 38137563SPrasad.Singamsetty@Sun.COM (void) ddi_create_minor_node(CMLB_DEVINFO(cl), "h,raw", 38147563SPrasad.Singamsetty@Sun.COM S_IFCHR, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 38157563SPrasad.Singamsetty@Sun.COM cl->cl_node_type, NULL); 38167563SPrasad.Singamsetty@Sun.COM mutex_enter(CMLB_MUTEX(cl)); 38177563SPrasad.Singamsetty@Sun.COM 38187563SPrasad.Singamsetty@Sun.COM if ((rval = cmlb_build_label_vtoc(cl, &user_vtoc)) == 0) { 38197563SPrasad.Singamsetty@Sun.COM if ((rval = cmlb_write_label(cl, tg_cookie)) == 0) { 38207563SPrasad.Singamsetty@Sun.COM if (cmlb_validate_geometry(cl, 1, 0, tg_cookie) != 0) { 38217563SPrasad.Singamsetty@Sun.COM cmlb_dbg(CMLB_ERROR, cl, 38227563SPrasad.Singamsetty@Sun.COM "cmlb_dkio_set_vtoc: " 38237563SPrasad.Singamsetty@Sun.COM "Failed validate geometry\n"); 38247563SPrasad.Singamsetty@Sun.COM } 38257563SPrasad.Singamsetty@Sun.COM } 38267563SPrasad.Singamsetty@Sun.COM } 38277563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 38287563SPrasad.Singamsetty@Sun.COM return (rval); 38297563SPrasad.Singamsetty@Sun.COM } 3830786Slclee 3831786Slclee /* 3832786Slclee * Function: cmlb_build_label_vtoc 3833786Slclee * 3834786Slclee * Description: This routine updates the driver soft state current volume table 3835786Slclee * of contents based on a user specified vtoc. 3836786Slclee * 38373525Sshidokht * Arguments: cl - driver soft state (unit) structure 3838786Slclee * user_vtoc - pointer to vtoc structure specifying vtoc to be used 3839786Slclee * to update the driver soft state. 3840786Slclee * 3841786Slclee * Return Code: 0 3842786Slclee * EINVAL 3843786Slclee */ 3844786Slclee static int 38453525Sshidokht cmlb_build_label_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc) 3846786Slclee { 3847786Slclee struct dk_map *lmap; 3848786Slclee struct partition *vpart; 38497563SPrasad.Singamsetty@Sun.COM uint_t nblks; 3850786Slclee #if defined(_SUNOS_VTOC_8) 3851786Slclee int ncyl; 3852786Slclee struct dk_map2 *lpart; 3853786Slclee #endif /* defined(_SUNOS_VTOC_8) */ 3854786Slclee int i; 3855786Slclee 38563525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 3857786Slclee 3858786Slclee /* Sanity-check the vtoc */ 3859786Slclee if (user_vtoc->v_sanity != VTOC_SANE || 38603525Sshidokht user_vtoc->v_sectorsz != cl->cl_sys_blocksize || 3861786Slclee user_vtoc->v_nparts != V_NUMPAR) { 38623525Sshidokht cmlb_dbg(CMLB_INFO, cl, 3863786Slclee "cmlb_build_label_vtoc: vtoc not valid\n"); 3864786Slclee return (EINVAL); 3865786Slclee } 3866786Slclee 38673525Sshidokht nblks = cl->cl_g.dkg_nsect * cl->cl_g.dkg_nhead; 3868786Slclee if (nblks == 0) { 38693525Sshidokht cmlb_dbg(CMLB_INFO, cl, 3870786Slclee "cmlb_build_label_vtoc: geom nblks is 0\n"); 3871786Slclee return (EINVAL); 3872786Slclee } 3873786Slclee 3874786Slclee #if defined(_SUNOS_VTOC_8) 3875786Slclee vpart = user_vtoc->v_part; 3876786Slclee for (i = 0; i < V_NUMPAR; i++) { 38777563SPrasad.Singamsetty@Sun.COM if (((unsigned)vpart->p_start % nblks) != 0) { 38783525Sshidokht cmlb_dbg(CMLB_INFO, cl, 3879786Slclee "cmlb_build_label_vtoc: p_start not multiply of" 3880786Slclee "nblks part %d p_start %d nblks %d\n", i, 3881786Slclee vpart->p_start, nblks); 3882786Slclee return (EINVAL); 3883786Slclee } 38847563SPrasad.Singamsetty@Sun.COM ncyl = (unsigned)vpart->p_start / nblks; 38857563SPrasad.Singamsetty@Sun.COM ncyl += (unsigned)vpart->p_size / nblks; 38867563SPrasad.Singamsetty@Sun.COM if (((unsigned)vpart->p_size % nblks) != 0) { 3887786Slclee ncyl++; 3888786Slclee } 38893525Sshidokht if (ncyl > (int)cl->cl_g.dkg_ncyl) { 38903525Sshidokht cmlb_dbg(CMLB_INFO, cl, 3891786Slclee "cmlb_build_label_vtoc: ncyl %d > dkg_ncyl %d" 3892786Slclee "p_size %ld p_start %ld nblks %d part number %d" 3893786Slclee "tag %d\n", 38943525Sshidokht ncyl, cl->cl_g.dkg_ncyl, vpart->p_size, 3895786Slclee vpart->p_start, nblks, 3896786Slclee i, vpart->p_tag); 3897786Slclee 3898786Slclee return (EINVAL); 3899786Slclee } 3900786Slclee vpart++; 3901786Slclee } 3902786Slclee #endif /* defined(_SUNOS_VTOC_8) */ 3903786Slclee 3904786Slclee /* Put appropriate vtoc structure fields into the disk label */ 3905786Slclee #if defined(_SUNOS_VTOC_16) 3906786Slclee /* 3907786Slclee * The vtoc is always a 32bit data structure to maintain the 3908786Slclee * on-disk format. Convert "in place" instead of doing bcopy. 3909786Slclee */ 39103525Sshidokht vtoctovtoc32((*user_vtoc), (*((struct vtoc32 *)&(cl->cl_vtoc)))); 3911786Slclee 3912786Slclee /* 3913786Slclee * in the 16-slice vtoc, starting sectors are expressed in 3914786Slclee * numbers *relative* to the start of the Solaris fdisk partition. 3915786Slclee */ 39163525Sshidokht lmap = cl->cl_map; 3917786Slclee vpart = user_vtoc->v_part; 3918786Slclee 3919786Slclee for (i = 0; i < (int)user_vtoc->v_nparts; i++, lmap++, vpart++) { 39207563SPrasad.Singamsetty@Sun.COM lmap->dkl_cylno = (unsigned)vpart->p_start / nblks; 39217563SPrasad.Singamsetty@Sun.COM lmap->dkl_nblk = (unsigned)vpart->p_size; 3922786Slclee } 3923786Slclee 3924786Slclee #elif defined(_SUNOS_VTOC_8) 3925786Slclee 39263525Sshidokht cl->cl_vtoc.v_bootinfo[0] = (uint32_t)user_vtoc->v_bootinfo[0]; 39273525Sshidokht cl->cl_vtoc.v_bootinfo[1] = (uint32_t)user_vtoc->v_bootinfo[1]; 39283525Sshidokht cl->cl_vtoc.v_bootinfo[2] = (uint32_t)user_vtoc->v_bootinfo[2]; 39293525Sshidokht 39303525Sshidokht cl->cl_vtoc.v_sanity = (uint32_t)user_vtoc->v_sanity; 39313525Sshidokht cl->cl_vtoc.v_version = (uint32_t)user_vtoc->v_version; 39323525Sshidokht 39333525Sshidokht bcopy(user_vtoc->v_volume, cl->cl_vtoc.v_volume, LEN_DKL_VVOL); 39343525Sshidokht 39353525Sshidokht cl->cl_vtoc.v_nparts = user_vtoc->v_nparts; 3936786Slclee 3937786Slclee for (i = 0; i < 10; i++) 39383525Sshidokht cl->cl_vtoc.v_reserved[i] = user_vtoc->v_reserved[i]; 3939786Slclee 3940786Slclee /* 3941786Slclee * Note the conversion from starting sector number 3942786Slclee * to starting cylinder number. 3943786Slclee * Return error if division results in a remainder. 3944786Slclee */ 39453525Sshidokht lmap = cl->cl_map; 39463525Sshidokht lpart = cl->cl_vtoc.v_part; 3947786Slclee vpart = user_vtoc->v_part; 3948786Slclee 3949786Slclee for (i = 0; i < (int)user_vtoc->v_nparts; i++) { 3950786Slclee lpart->p_tag = vpart->p_tag; 3951786Slclee lpart->p_flag = vpart->p_flag; 39527563SPrasad.Singamsetty@Sun.COM lmap->dkl_cylno = (unsigned)vpart->p_start / nblks; 39537563SPrasad.Singamsetty@Sun.COM lmap->dkl_nblk = (unsigned)vpart->p_size; 3954786Slclee 3955786Slclee lmap++; 3956786Slclee lpart++; 3957786Slclee vpart++; 3958786Slclee 3959786Slclee /* (4387723) */ 3960786Slclee #ifdef _LP64 3961786Slclee if (user_vtoc->timestamp[i] > TIME32_MAX) { 39623525Sshidokht cl->cl_vtoc.v_timestamp[i] = TIME32_MAX; 3963786Slclee } else { 39643525Sshidokht cl->cl_vtoc.v_timestamp[i] = user_vtoc->timestamp[i]; 3965786Slclee } 3966786Slclee #else 39673525Sshidokht cl->cl_vtoc.v_timestamp[i] = user_vtoc->timestamp[i]; 3968786Slclee #endif 3969786Slclee } 3970786Slclee 39713525Sshidokht bcopy(user_vtoc->v_asciilabel, cl->cl_asciilabel, LEN_DKL_ASCII); 3972786Slclee #else 3973786Slclee #error "No VTOC format defined." 3974786Slclee #endif 3975786Slclee return (0); 3976786Slclee } 3977786Slclee 3978786Slclee /* 3979786Slclee * Function: cmlb_clear_efi 3980786Slclee * 3981786Slclee * Description: This routine clears all EFI labels. 3982786Slclee * 39833525Sshidokht * Arguments: 39843525Sshidokht * cl driver soft state (unit) structure 3985786Slclee * 39863525Sshidokht * tg_cookie cookie from target driver to be passed back to target 39873525Sshidokht * driver when we call back to it through tg_ops. 3988786Slclee * Return Code: void 3989786Slclee */ 3990786Slclee static void 39913525Sshidokht cmlb_clear_efi(struct cmlb_lun *cl, void *tg_cookie) 3992786Slclee { 3993786Slclee efi_gpt_t *gpt; 3994786Slclee diskaddr_t cap; 3995786Slclee int rval; 3996786Slclee 39973525Sshidokht ASSERT(!mutex_owned(CMLB_MUTEX(cl))); 39983525Sshidokht 39993525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 40003525Sshidokht cl->cl_reserved = -1; 40013525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4002786Slclee 4003786Slclee gpt = kmem_alloc(sizeof (efi_gpt_t), KM_SLEEP); 4004786Slclee 40053525Sshidokht if (DK_TG_READ(cl, gpt, 1, DEV_BSIZE, tg_cookie) != 0) { 4006786Slclee goto done; 4007786Slclee } 4008786Slclee 4009786Slclee cmlb_swap_efi_gpt(gpt); 4010786Slclee rval = cmlb_validate_efi(gpt); 4011786Slclee if (rval == 0) { 4012786Slclee /* clear primary */ 4013786Slclee bzero(gpt, sizeof (efi_gpt_t)); 40143525Sshidokht if (rval = DK_TG_WRITE(cl, gpt, 1, EFI_LABEL_SIZE, tg_cookie)) { 40153525Sshidokht cmlb_dbg(CMLB_INFO, cl, 40163525Sshidokht "cmlb_clear_efi: clear primary label failed\n"); 4017786Slclee } 4018786Slclee } 4019786Slclee /* the backup */ 40203525Sshidokht rval = DK_TG_GETCAP(cl, &cap, tg_cookie); 4021786Slclee if (rval) { 4022786Slclee goto done; 4023786Slclee } 4024786Slclee 40253525Sshidokht if ((rval = DK_TG_READ(cl, gpt, cap - 1, EFI_LABEL_SIZE, tg_cookie)) 40263525Sshidokht != 0) { 4027786Slclee goto done; 4028786Slclee } 4029786Slclee cmlb_swap_efi_gpt(gpt); 4030786Slclee rval = cmlb_validate_efi(gpt); 4031786Slclee if (rval == 0) { 4032786Slclee /* clear backup */ 40333525Sshidokht cmlb_dbg(CMLB_TRACE, cl, 4034786Slclee "cmlb_clear_efi clear backup@%lu\n", cap - 1); 4035786Slclee bzero(gpt, sizeof (efi_gpt_t)); 40363525Sshidokht if ((rval = DK_TG_WRITE(cl, gpt, cap - 1, EFI_LABEL_SIZE, 40373525Sshidokht tg_cookie))) { 40383525Sshidokht cmlb_dbg(CMLB_INFO, cl, 40393525Sshidokht "cmlb_clear_efi: clear backup label failed\n"); 40403525Sshidokht } 40413525Sshidokht } else { 40423525Sshidokht /* 40433525Sshidokht * Refer to comments related to off-by-1 at the 40443525Sshidokht * header of this file 40453525Sshidokht */ 40463525Sshidokht if ((rval = DK_TG_READ(cl, gpt, cap - 2, 40473525Sshidokht EFI_LABEL_SIZE, tg_cookie)) != 0) { 40483525Sshidokht goto done; 40493525Sshidokht } 40503525Sshidokht cmlb_swap_efi_gpt(gpt); 40513525Sshidokht rval = cmlb_validate_efi(gpt); 40523525Sshidokht if (rval == 0) { 40533525Sshidokht /* clear legacy backup EFI label */ 40543525Sshidokht cmlb_dbg(CMLB_TRACE, cl, 40553525Sshidokht "cmlb_clear_efi clear legacy backup@%lu\n", 40563525Sshidokht cap - 2); 40573525Sshidokht bzero(gpt, sizeof (efi_gpt_t)); 40583525Sshidokht if ((rval = DK_TG_WRITE(cl, gpt, cap - 2, 40593525Sshidokht EFI_LABEL_SIZE, tg_cookie))) { 40603525Sshidokht cmlb_dbg(CMLB_INFO, cl, 40613525Sshidokht "cmlb_clear_efi: clear legacy backup label " 40623525Sshidokht "failed\n"); 40633525Sshidokht } 4064786Slclee } 4065786Slclee } 4066786Slclee 4067786Slclee done: 4068786Slclee kmem_free(gpt, sizeof (efi_gpt_t)); 4069786Slclee } 4070786Slclee 4071786Slclee /* 4072786Slclee * Function: cmlb_set_vtoc 4073786Slclee * 4074786Slclee * Description: This routine writes data to the appropriate positions 4075786Slclee * 40763525Sshidokht * Arguments: 40773525Sshidokht * cl driver soft state (unit) structure 40783525Sshidokht * 40793525Sshidokht * dkl the data to be written 40803525Sshidokht * 40813525Sshidokht * tg_cookie cookie from target driver to be passed back to target 40823525Sshidokht * driver when we call back to it through tg_ops. 4083786Slclee * 4084786Slclee * Return: void 4085786Slclee */ 4086786Slclee static int 40873525Sshidokht cmlb_set_vtoc(struct cmlb_lun *cl, struct dk_label *dkl, void *tg_cookie) 4088786Slclee { 4089786Slclee uint_t label_addr; 4090786Slclee int sec; 40917563SPrasad.Singamsetty@Sun.COM diskaddr_t blk; 4092786Slclee int head; 4093786Slclee int cyl; 4094786Slclee int rval; 4095786Slclee 4096786Slclee #if defined(__i386) || defined(__amd64) 40973525Sshidokht label_addr = cl->cl_solaris_offset + DK_LABEL_LOC; 4098786Slclee #else 4099786Slclee /* Write the primary label at block 0 of the solaris partition. */ 4100786Slclee label_addr = 0; 4101786Slclee #endif 4102786Slclee 41033525Sshidokht rval = DK_TG_WRITE(cl, dkl, label_addr, cl->cl_sys_blocksize, 41043525Sshidokht tg_cookie); 4105786Slclee 4106786Slclee if (rval != 0) { 4107786Slclee return (rval); 4108786Slclee } 4109786Slclee 4110786Slclee /* 4111786Slclee * Calculate where the backup labels go. They are always on 4112786Slclee * the last alternate cylinder, but some older drives put them 4113786Slclee * on head 2 instead of the last head. They are always on the 4114786Slclee * first 5 odd sectors of the appropriate track. 4115786Slclee * 4116786Slclee * We have no choice at this point, but to believe that the 4117786Slclee * disk label is valid. Use the geometry of the disk 4118786Slclee * as described in the label. 4119786Slclee */ 4120786Slclee cyl = dkl->dkl_ncyl + dkl->dkl_acyl - 1; 4121786Slclee head = dkl->dkl_nhead - 1; 4122786Slclee 4123786Slclee /* 4124786Slclee * Write and verify the backup labels. Make sure we don't try to 4125786Slclee * write past the last cylinder. 4126786Slclee */ 4127786Slclee for (sec = 1; ((sec < 5 * 2 + 1) && (sec < dkl->dkl_nsect)); sec += 2) { 41287563SPrasad.Singamsetty@Sun.COM blk = (diskaddr_t)( 4129786Slclee (cyl * ((dkl->dkl_nhead * dkl->dkl_nsect) - dkl->dkl_apc)) + 4130786Slclee (head * dkl->dkl_nsect) + sec); 4131786Slclee #if defined(__i386) || defined(__amd64) 41323525Sshidokht blk += cl->cl_solaris_offset; 4133786Slclee #endif 41343525Sshidokht rval = DK_TG_WRITE(cl, dkl, blk, cl->cl_sys_blocksize, 41353525Sshidokht tg_cookie); 41363525Sshidokht cmlb_dbg(CMLB_INFO, cl, 41377563SPrasad.Singamsetty@Sun.COM "cmlb_set_vtoc: wrote backup label %llx\n", blk); 4138786Slclee if (rval != 0) { 4139786Slclee goto exit; 4140786Slclee } 4141786Slclee } 4142786Slclee exit: 4143786Slclee return (rval); 4144786Slclee } 4145786Slclee 4146786Slclee /* 4147786Slclee * Function: cmlb_clear_vtoc 4148786Slclee * 4149786Slclee * Description: This routine clears out the VTOC labels. 4150786Slclee * 41513525Sshidokht * Arguments: 41523525Sshidokht * cl driver soft state (unit) structure 41533525Sshidokht * 41543525Sshidokht * tg_cookie cookie from target driver to be passed back to target 41553525Sshidokht * driver when we call back to it through tg_ops. 4156786Slclee * 4157786Slclee * Return: void 4158786Slclee */ 4159786Slclee static void 41603525Sshidokht cmlb_clear_vtoc(struct cmlb_lun *cl, void *tg_cookie) 4161786Slclee { 4162786Slclee struct dk_label *dkl; 4163786Slclee 41643525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4165786Slclee dkl = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP); 41663525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 4167786Slclee /* 4168786Slclee * cmlb_set_vtoc uses these fields in order to figure out 4169786Slclee * where to overwrite the backup labels 4170786Slclee */ 41713525Sshidokht dkl->dkl_apc = cl->cl_g.dkg_apc; 41723525Sshidokht dkl->dkl_ncyl = cl->cl_g.dkg_ncyl; 41733525Sshidokht dkl->dkl_acyl = cl->cl_g.dkg_acyl; 41743525Sshidokht dkl->dkl_nhead = cl->cl_g.dkg_nhead; 41753525Sshidokht dkl->dkl_nsect = cl->cl_g.dkg_nsect; 41763525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 41773525Sshidokht (void) cmlb_set_vtoc(cl, dkl, tg_cookie); 4178786Slclee kmem_free(dkl, sizeof (struct dk_label)); 4179786Slclee 41803525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 4181786Slclee } 4182786Slclee 4183786Slclee /* 4184786Slclee * Function: cmlb_write_label 4185786Slclee * 4186786Slclee * Description: This routine will validate and write the driver soft state vtoc 4187786Slclee * contents to the device. 4188786Slclee * 41893525Sshidokht * Arguments: 41903525Sshidokht * cl cmlb handle 41913525Sshidokht * 41923525Sshidokht * tg_cookie cookie from target driver to be passed back to target 41933525Sshidokht * driver when we call back to it through tg_ops. 41943525Sshidokht * 4195786Slclee * 4196786Slclee * Return Code: the code returned by cmlb_send_scsi_cmd() 4197786Slclee * 0 4198786Slclee * EINVAL 4199786Slclee * ENXIO 4200786Slclee * ENOMEM 4201786Slclee */ 4202786Slclee static int 42033525Sshidokht cmlb_write_label(struct cmlb_lun *cl, void *tg_cookie) 4204786Slclee { 4205786Slclee struct dk_label *dkl; 4206786Slclee short sum; 4207786Slclee short *sp; 4208786Slclee int i; 4209786Slclee int rval; 4210786Slclee 42113525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 42123525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4213786Slclee dkl = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP); 42143525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 42153525Sshidokht 42163525Sshidokht bcopy(&cl->cl_vtoc, &dkl->dkl_vtoc, sizeof (struct dk_vtoc)); 42173525Sshidokht dkl->dkl_rpm = cl->cl_g.dkg_rpm; 42183525Sshidokht dkl->dkl_pcyl = cl->cl_g.dkg_pcyl; 42193525Sshidokht dkl->dkl_apc = cl->cl_g.dkg_apc; 42203525Sshidokht dkl->dkl_intrlv = cl->cl_g.dkg_intrlv; 42213525Sshidokht dkl->dkl_ncyl = cl->cl_g.dkg_ncyl; 42223525Sshidokht dkl->dkl_acyl = cl->cl_g.dkg_acyl; 42233525Sshidokht dkl->dkl_nhead = cl->cl_g.dkg_nhead; 42243525Sshidokht dkl->dkl_nsect = cl->cl_g.dkg_nsect; 4225786Slclee 4226786Slclee #if defined(_SUNOS_VTOC_8) 42273525Sshidokht dkl->dkl_obs1 = cl->cl_g.dkg_obs1; 42283525Sshidokht dkl->dkl_obs2 = cl->cl_g.dkg_obs2; 42293525Sshidokht dkl->dkl_obs3 = cl->cl_g.dkg_obs3; 4230786Slclee for (i = 0; i < NDKMAP; i++) { 42313525Sshidokht dkl->dkl_map[i].dkl_cylno = cl->cl_map[i].dkl_cylno; 42323525Sshidokht dkl->dkl_map[i].dkl_nblk = cl->cl_map[i].dkl_nblk; 4233786Slclee } 42343525Sshidokht bcopy(cl->cl_asciilabel, dkl->dkl_asciilabel, LEN_DKL_ASCII); 4235786Slclee #elif defined(_SUNOS_VTOC_16) 42363525Sshidokht dkl->dkl_skew = cl->cl_dkg_skew; 4237786Slclee #else 4238786Slclee #error "No VTOC format defined." 4239786Slclee #endif 4240786Slclee 4241786Slclee dkl->dkl_magic = DKL_MAGIC; 42423525Sshidokht dkl->dkl_write_reinstruct = cl->cl_g.dkg_write_reinstruct; 42433525Sshidokht dkl->dkl_read_reinstruct = cl->cl_g.dkg_read_reinstruct; 4244786Slclee 4245786Slclee /* Construct checksum for the new disk label */ 4246786Slclee sum = 0; 4247786Slclee sp = (short *)dkl; 4248786Slclee i = sizeof (struct dk_label) / sizeof (short); 4249786Slclee while (i--) { 4250786Slclee sum ^= *sp++; 4251786Slclee } 4252786Slclee dkl->dkl_cksum = sum; 4253786Slclee 42543525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 42553525Sshidokht 42563525Sshidokht rval = cmlb_set_vtoc(cl, dkl, tg_cookie); 4257786Slclee exit: 4258786Slclee kmem_free(dkl, sizeof (struct dk_label)); 42593525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 4260786Slclee return (rval); 4261786Slclee } 4262786Slclee 4263786Slclee static int 42643525Sshidokht cmlb_dkio_set_efi(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag, 42653525Sshidokht void *tg_cookie) 4266786Slclee { 4267786Slclee dk_efi_t user_efi; 4268786Slclee int rval = 0; 4269786Slclee void *buffer; 42703525Sshidokht diskaddr_t tgt_lba; 42716318Sedp boolean_t internal; 4272786Slclee 4273786Slclee if (ddi_copyin(arg, &user_efi, sizeof (dk_efi_t), flag)) 4274786Slclee return (EFAULT); 4275786Slclee 42766318Sedp internal = ((cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0); 42776318Sedp 4278786Slclee user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64; 4279786Slclee 4280786Slclee buffer = kmem_alloc(user_efi.dki_length, KM_SLEEP); 4281786Slclee if (ddi_copyin(user_efi.dki_data, buffer, user_efi.dki_length, flag)) { 4282786Slclee rval = EFAULT; 4283786Slclee } else { 4284786Slclee /* 4285786Slclee * let's clear the vtoc labels and clear the softstate 4286786Slclee * vtoc. 4287786Slclee */ 42883525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 42893525Sshidokht if (cl->cl_vtoc.v_sanity == VTOC_SANE) { 42903525Sshidokht cmlb_dbg(CMLB_TRACE, cl, 42913525Sshidokht "cmlb_dkio_set_efi: CLEAR VTOC\n"); 42927563SPrasad.Singamsetty@Sun.COM if (cl->cl_label_from_media == CMLB_LABEL_VTOC) 42933525Sshidokht cmlb_clear_vtoc(cl, tg_cookie); 42943525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc)); 42953525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 42963525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "h"); 42973525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw"); 42986318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd", 4299786Slclee S_IFBLK, 4300786Slclee (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 43016318Sedp cl->cl_node_type, NULL, internal); 43026318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd,raw", 4303786Slclee S_IFCHR, 4304786Slclee (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 43056318Sedp cl->cl_node_type, NULL, internal); 4306786Slclee } else 43073525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 43083525Sshidokht 43093525Sshidokht tgt_lba = user_efi.dki_lba; 43103525Sshidokht 43113525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 43123525Sshidokht if ((cmlb_check_update_blockcount(cl, tg_cookie) != 0) || 43133525Sshidokht (cl->cl_tgt_blocksize == 0)) { 43143525Sshidokht kmem_free(buffer, user_efi.dki_length); 43153525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 43163525Sshidokht return (EINVAL); 43173525Sshidokht } 43183525Sshidokht if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) 43193525Sshidokht tgt_lba = tgt_lba * 43203525Sshidokht cl->cl_tgt_blocksize / cl->cl_sys_blocksize; 43213525Sshidokht 43223525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 43233525Sshidokht rval = DK_TG_WRITE(cl, buffer, tgt_lba, user_efi.dki_length, 43243525Sshidokht tg_cookie); 43253525Sshidokht 4326786Slclee if (rval == 0) { 43273525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 43283525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 43293525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4330786Slclee } 4331786Slclee } 4332786Slclee kmem_free(buffer, user_efi.dki_length); 4333786Slclee return (rval); 4334786Slclee } 4335786Slclee 4336786Slclee /* 4337786Slclee * Function: cmlb_dkio_get_mboot 4338786Slclee * 4339786Slclee * Description: This routine is the driver entry point for handling user 4340786Slclee * requests to get the current device mboot (DKIOCGMBOOT) 4341786Slclee * 4342786Slclee * Arguments: 43433525Sshidokht * arg pointer to user provided mboot structure specifying 4344786Slclee * the current mboot. 43453525Sshidokht * 43463525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 43473525Sshidokht * directly from the mode argument of ioctl(). 43483525Sshidokht * 43493525Sshidokht * tg_cookie cookie from target driver to be passed back to target 43503525Sshidokht * driver when we call back to it through tg_ops. 4351786Slclee * 4352786Slclee * Return Code: 0 4353786Slclee * EINVAL 4354786Slclee * EFAULT 4355786Slclee * ENXIO 4356786Slclee */ 4357786Slclee static int 43583525Sshidokht cmlb_dkio_get_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie) 4359786Slclee { 4360786Slclee struct mboot *mboot; 4361786Slclee int rval; 4362786Slclee size_t buffer_size; 4363786Slclee 4364786Slclee 4365786Slclee #if defined(_SUNOS_VTOC_8) 43663525Sshidokht if ((!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) || (arg == NULL)) { 4367786Slclee #elif defined(_SUNOS_VTOC_16) 4368786Slclee if (arg == NULL) { 4369786Slclee #endif 4370786Slclee return (EINVAL); 4371786Slclee } 4372786Slclee 4373786Slclee /* 4374786Slclee * Read the mboot block, located at absolute block 0 on the target. 4375786Slclee */ 4376786Slclee buffer_size = sizeof (struct mboot); 4377786Slclee 43783525Sshidokht cmlb_dbg(CMLB_TRACE, cl, 4379786Slclee "cmlb_dkio_get_mboot: allocation size: 0x%x\n", buffer_size); 4380786Slclee 4381786Slclee mboot = kmem_zalloc(buffer_size, KM_SLEEP); 43823525Sshidokht if ((rval = DK_TG_READ(cl, mboot, 0, buffer_size, tg_cookie)) == 0) { 4383786Slclee if (ddi_copyout(mboot, (void *)arg, 4384786Slclee sizeof (struct mboot), flag) != 0) { 4385786Slclee rval = EFAULT; 4386786Slclee } 4387786Slclee } 4388786Slclee kmem_free(mboot, buffer_size); 4389786Slclee return (rval); 4390786Slclee } 4391786Slclee 4392786Slclee 4393786Slclee /* 4394786Slclee * Function: cmlb_dkio_set_mboot 4395786Slclee * 4396786Slclee * Description: This routine is the driver entry point for handling user 4397786Slclee * requests to validate and set the device master boot 4398786Slclee * (DKIOCSMBOOT). 4399786Slclee * 4400786Slclee * Arguments: 44013525Sshidokht * arg pointer to user provided mboot structure used to set the 4402786Slclee * master boot. 44033525Sshidokht * 44043525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 44053525Sshidokht * directly from the mode argument of ioctl(). 44063525Sshidokht * 44073525Sshidokht * tg_cookie cookie from target driver to be passed back to target 44083525Sshidokht * driver when we call back to it through tg_ops. 4409786Slclee * 4410786Slclee * Return Code: 0 4411786Slclee * EINVAL 4412786Slclee * EFAULT 4413786Slclee * ENXIO 4414786Slclee */ 4415786Slclee static int 44163525Sshidokht cmlb_dkio_set_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie) 4417786Slclee { 4418786Slclee struct mboot *mboot = NULL; 4419786Slclee int rval; 4420786Slclee ushort_t magic; 4421786Slclee 4422786Slclee 44233525Sshidokht ASSERT(!mutex_owned(CMLB_MUTEX(cl))); 4424786Slclee 4425786Slclee #if defined(_SUNOS_VTOC_8) 44263525Sshidokht if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) { 4427786Slclee return (EINVAL); 4428786Slclee } 4429786Slclee #endif 4430786Slclee 4431786Slclee if (arg == NULL) { 4432786Slclee return (EINVAL); 4433786Slclee } 4434786Slclee 4435786Slclee mboot = kmem_zalloc(sizeof (struct mboot), KM_SLEEP); 4436786Slclee 4437786Slclee if (ddi_copyin((const void *)arg, mboot, 4438786Slclee sizeof (struct mboot), flag) != 0) { 4439786Slclee kmem_free(mboot, (size_t)(sizeof (struct mboot))); 4440786Slclee return (EFAULT); 4441786Slclee } 4442786Slclee 4443786Slclee /* Is this really a master boot record? */ 4444786Slclee magic = LE_16(mboot->signature); 4445786Slclee if (magic != MBB_MAGIC) { 4446786Slclee kmem_free(mboot, (size_t)(sizeof (struct mboot))); 4447786Slclee return (EINVAL); 4448786Slclee } 4449786Slclee 44503525Sshidokht rval = DK_TG_WRITE(cl, mboot, 0, cl->cl_sys_blocksize, tg_cookie); 44513525Sshidokht 44523525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 4453786Slclee #if defined(__i386) || defined(__amd64) 4454786Slclee if (rval == 0) { 4455786Slclee /* 4456786Slclee * mboot has been written successfully. 4457786Slclee * update the fdisk and vtoc tables in memory 4458786Slclee */ 44593525Sshidokht rval = cmlb_update_fdisk_and_vtoc(cl, tg_cookie); 44603525Sshidokht if ((cl->cl_f_geometry_is_valid == FALSE) || (rval != 0)) { 44613525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4462786Slclee kmem_free(mboot, (size_t)(sizeof (struct mboot))); 4463786Slclee return (rval); 4464786Slclee } 4465786Slclee } 44663525Sshidokht 44673525Sshidokht #ifdef __lock_lint 44683525Sshidokht cmlb_setup_default_geometry(cl, tg_cookie); 44693525Sshidokht #endif 44703525Sshidokht 4471786Slclee #else 4472786Slclee if (rval == 0) { 4473786Slclee /* 4474786Slclee * mboot has been written successfully. 4475786Slclee * set up the default geometry and VTOC 4476786Slclee */ 44777563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount <= CMLB_EXTVTOC_LIMIT) 44783525Sshidokht cmlb_setup_default_geometry(cl, tg_cookie); 4479786Slclee } 4480786Slclee #endif 44817563SPrasad.Singamsetty@Sun.COM cl->cl_msglog_flag |= CMLB_ALLOW_2TB_WARN; 44823525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4483786Slclee kmem_free(mboot, (size_t)(sizeof (struct mboot))); 4484786Slclee return (rval); 4485786Slclee } 4486786Slclee 4487786Slclee 4488786Slclee /* 4489786Slclee * Function: cmlb_setup_default_geometry 4490786Slclee * 4491786Slclee * Description: This local utility routine sets the default geometry as part of 4492786Slclee * setting the device mboot. 4493786Slclee * 44943525Sshidokht * Arguments: 44953525Sshidokht * cl driver soft state (unit) structure 44963525Sshidokht * 44973525Sshidokht * tg_cookie cookie from target driver to be passed back to target 44983525Sshidokht * driver when we call back to it through tg_ops. 44993525Sshidokht * 4500786Slclee * 4501786Slclee * Note: This may be redundant with cmlb_build_default_label. 4502786Slclee */ 4503786Slclee static void 45043525Sshidokht cmlb_setup_default_geometry(struct cmlb_lun *cl, void *tg_cookie) 4505786Slclee { 4506786Slclee struct cmlb_geom pgeom; 4507786Slclee struct cmlb_geom *pgeomp = &pgeom; 4508786Slclee int ret; 4509786Slclee int geom_base_cap = 1; 4510786Slclee 4511786Slclee 45123525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 4513786Slclee 4514786Slclee /* zero out the soft state geometry and partition table. */ 45153525Sshidokht bzero(&cl->cl_g, sizeof (struct dk_geom)); 45163525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc)); 45173525Sshidokht bzero(cl->cl_map, NDKMAP * (sizeof (struct dk_map))); 4518786Slclee 4519786Slclee /* 4520786Slclee * For the rpm, we use the minimum for the disk. 4521786Slclee * For the head, cyl and number of sector per track, 4522786Slclee * if the capacity <= 1GB, head = 64, sect = 32. 4523786Slclee * else head = 255, sect 63 4524786Slclee * Note: the capacity should be equal to C*H*S values. 4525786Slclee * This will cause some truncation of size due to 4526786Slclee * round off errors. For CD-ROMs, this truncation can 4527786Slclee * have adverse side effects, so returning ncyl and 4528786Slclee * nhead as 1. The nsect will overflow for most of 4529786Slclee * CD-ROMs as nsect is of type ushort. 4530786Slclee */ 45313525Sshidokht if (cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8) { 4532786Slclee /* 4533786Slclee * newfs currently can not handle 255 ntracks for SPARC 4534786Slclee * so get the geometry from target driver instead of coming up 4535786Slclee * with one based on capacity. 4536786Slclee */ 45373525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 45383525Sshidokht ret = DK_TG_GETPHYGEOM(cl, pgeomp, tg_cookie); 45393525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 4540786Slclee 4541786Slclee if (ret == 0) { 4542786Slclee geom_base_cap = 0; 4543786Slclee } else { 45443525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 4545786Slclee "cmlb_setup_default_geometry: " 4546786Slclee "tg_getphygeom failed %d\n", ret); 4547786Slclee 4548786Slclee /* do default setting, geometry based on capacity */ 4549786Slclee } 4550786Slclee } 4551786Slclee 4552786Slclee if (geom_base_cap) { 45533525Sshidokht if (ISCD(cl)) { 45543525Sshidokht cl->cl_g.dkg_ncyl = 1; 45553525Sshidokht cl->cl_g.dkg_nhead = 1; 45563525Sshidokht cl->cl_g.dkg_nsect = cl->cl_blockcount; 45573525Sshidokht } else if (cl->cl_blockcount <= 0x1000) { 4558786Slclee /* Needed for unlabeled SCSI floppies. */ 45593525Sshidokht cl->cl_g.dkg_nhead = 2; 45603525Sshidokht cl->cl_g.dkg_ncyl = 80; 45613525Sshidokht cl->cl_g.dkg_pcyl = 80; 45623525Sshidokht cl->cl_g.dkg_nsect = cl->cl_blockcount / (2 * 80); 45633525Sshidokht } else if (cl->cl_blockcount <= 0x200000) { 45643525Sshidokht cl->cl_g.dkg_nhead = 64; 45653525Sshidokht cl->cl_g.dkg_nsect = 32; 45663525Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount / (64 * 32); 4567786Slclee } else { 45683525Sshidokht cl->cl_g.dkg_nhead = 255; 45696124Sshidokht 45706124Sshidokht cl->cl_g.dkg_nsect = ((cl->cl_blockcount + 45716124Sshidokht (UINT16_MAX * 255 * 63) - 1) / 45726124Sshidokht (UINT16_MAX * 255 * 63)) * 63; 45736124Sshidokht 45746124Sshidokht if (cl->cl_g.dkg_nsect == 0) 45756124Sshidokht cl->cl_g.dkg_nsect = (UINT16_MAX / 63) * 63; 45766124Sshidokht 45776124Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount / 45786124Sshidokht (255 * cl->cl_g.dkg_nsect); 4579786Slclee } 4580786Slclee 45813525Sshidokht cl->cl_g.dkg_acyl = 0; 45823525Sshidokht cl->cl_g.dkg_bcyl = 0; 45833525Sshidokht cl->cl_g.dkg_intrlv = 1; 45843525Sshidokht cl->cl_g.dkg_rpm = 200; 45853525Sshidokht if (cl->cl_g.dkg_pcyl == 0) 45863525Sshidokht cl->cl_g.dkg_pcyl = cl->cl_g.dkg_ncyl + 45873525Sshidokht cl->cl_g.dkg_acyl; 4588786Slclee } else { 45893525Sshidokht cl->cl_g.dkg_ncyl = (short)pgeomp->g_ncyl; 45903525Sshidokht cl->cl_g.dkg_acyl = pgeomp->g_acyl; 45913525Sshidokht cl->cl_g.dkg_nhead = pgeomp->g_nhead; 45923525Sshidokht cl->cl_g.dkg_nsect = pgeomp->g_nsect; 45933525Sshidokht cl->cl_g.dkg_intrlv = pgeomp->g_intrlv; 45943525Sshidokht cl->cl_g.dkg_rpm = pgeomp->g_rpm; 45953525Sshidokht cl->cl_g.dkg_pcyl = cl->cl_g.dkg_ncyl + cl->cl_g.dkg_acyl; 4596786Slclee } 4597786Slclee 45983525Sshidokht cl->cl_g.dkg_read_reinstruct = 0; 45993525Sshidokht cl->cl_g.dkg_write_reinstruct = 0; 46003525Sshidokht cl->cl_solaris_size = cl->cl_g.dkg_ncyl * 46013525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect; 46023525Sshidokht 46033525Sshidokht cl->cl_map['a'-'a'].dkl_cylno = 0; 46043525Sshidokht cl->cl_map['a'-'a'].dkl_nblk = cl->cl_solaris_size; 46053525Sshidokht 46063525Sshidokht cl->cl_map['c'-'a'].dkl_cylno = 0; 46073525Sshidokht cl->cl_map['c'-'a'].dkl_nblk = cl->cl_solaris_size; 46083525Sshidokht 46093525Sshidokht cl->cl_vtoc.v_part[2].p_tag = V_BACKUP; 46103525Sshidokht cl->cl_vtoc.v_part[2].p_flag = V_UNMNT; 46113525Sshidokht cl->cl_vtoc.v_nparts = V_NUMPAR; 46123525Sshidokht cl->cl_vtoc.v_version = V_VERSION; 46133525Sshidokht (void) sprintf((char *)cl->cl_asciilabel, "DEFAULT cyl %d alt %d" 46143525Sshidokht " hd %d sec %d", cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl, 46153525Sshidokht cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect); 46163525Sshidokht 46173525Sshidokht cl->cl_f_geometry_is_valid = FALSE; 4618786Slclee } 4619786Slclee 4620786Slclee 4621786Slclee #if defined(__i386) || defined(__amd64) 4622786Slclee /* 4623786Slclee * Function: cmlb_update_fdisk_and_vtoc 4624786Slclee * 4625786Slclee * Description: This local utility routine updates the device fdisk and vtoc 4626786Slclee * as part of setting the device mboot. 4627786Slclee * 46283525Sshidokht * Arguments: 46293525Sshidokht * cl driver soft state (unit) structure 46303525Sshidokht * 46313525Sshidokht * tg_cookie cookie from target driver to be passed back to target 46323525Sshidokht * driver when we call back to it through tg_ops. 46333525Sshidokht * 4634786Slclee * 4635786Slclee * Return Code: 0 for success or errno-type return code. 4636786Slclee * 4637786Slclee * Note:x86: This looks like a duplicate of cmlb_validate_geometry(), but 4638786Slclee * these did exist separately in x86 sd.c. 4639786Slclee */ 4640786Slclee static int 46413525Sshidokht cmlb_update_fdisk_and_vtoc(struct cmlb_lun *cl, void *tg_cookie) 4642786Slclee { 4643786Slclee int count; 4644786Slclee int label_rc = 0; 4645786Slclee int fdisk_rval; 4646786Slclee diskaddr_t capacity; 4647786Slclee 46483525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 46493525Sshidokht 46503525Sshidokht if (cmlb_check_update_blockcount(cl, tg_cookie) != 0) 4651786Slclee return (EINVAL); 4652786Slclee 4653786Slclee #if defined(_SUNOS_VTOC_16) 4654786Slclee /* 4655786Slclee * Set up the "whole disk" fdisk partition; this should always 4656786Slclee * exist, regardless of whether the disk contains an fdisk table 4657786Slclee * or vtoc. 4658786Slclee */ 46593525Sshidokht cl->cl_map[P0_RAW_DISK].dkl_cylno = 0; 46603525Sshidokht cl->cl_map[P0_RAW_DISK].dkl_nblk = cl->cl_blockcount; 4661786Slclee #endif /* defined(_SUNOS_VTOC_16) */ 4662786Slclee 4663786Slclee /* 4664786Slclee * copy the lbasize and capacity so that if they're 46653525Sshidokht * reset while we're not holding the CMLB_MUTEX(cl), we will 46663525Sshidokht * continue to use valid values after the CMLB_MUTEX(cl) is 4667786Slclee * reacquired. 4668786Slclee */ 46693525Sshidokht capacity = cl->cl_blockcount; 4670786Slclee 4671786Slclee /* 4672786Slclee * refresh the logical and physical geometry caches. 4673786Slclee * (data from mode sense format/rigid disk geometry pages, 4674786Slclee * and scsi_ifgetcap("geometry"). 4675786Slclee */ 46763525Sshidokht cmlb_resync_geom_caches(cl, capacity, tg_cookie); 4677786Slclee 4678786Slclee /* 46793525Sshidokht * Only DIRECT ACCESS devices will have Scl labels. 46803525Sshidokht * CD's supposedly have a Scl label, too 4681786Slclee */ 46823525Sshidokht if (cl->cl_device_type == DTYPE_DIRECT || ISREMOVABLE(cl)) { 46833525Sshidokht fdisk_rval = cmlb_read_fdisk(cl, capacity, tg_cookie); 4684786Slclee if (fdisk_rval != 0) { 46853525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 4686786Slclee return (fdisk_rval); 4687786Slclee } 4688786Slclee 46893525Sshidokht if (cl->cl_solaris_size <= DK_LABEL_LOC) { 4690786Slclee /* 4691786Slclee * Found fdisk table but no Solaris partition entry, 4692786Slclee * so don't call cmlb_uselabel() and don't create 4693786Slclee * a default label. 4694786Slclee */ 4695786Slclee label_rc = 0; 46963525Sshidokht cl->cl_f_geometry_is_valid = TRUE; 4697786Slclee goto no_solaris_partition; 4698786Slclee } 4699786Slclee } else if (capacity < 0) { 47003525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 4701786Slclee return (EINVAL); 4702786Slclee } 4703786Slclee 4704786Slclee /* 4705786Slclee * For Removable media We reach here if we have found a 4706786Slclee * SOLARIS PARTITION. 47073525Sshidokht * If cl_f_geometry_is_valid is FALSE it indicates that the SOLARIS 4708786Slclee * PARTITION has changed from the previous one, hence we will setup a 4709786Slclee * default VTOC in this case. 4710786Slclee */ 47113525Sshidokht if (cl->cl_f_geometry_is_valid == FALSE) { 4712786Slclee /* if we get here it is writable */ 4713786Slclee /* we are called from SMBOOT, and after a write of fdisk */ 47143525Sshidokht cmlb_build_default_label(cl, tg_cookie); 4715786Slclee label_rc = 0; 4716786Slclee } 4717786Slclee 4718786Slclee no_solaris_partition: 4719786Slclee 4720786Slclee #if defined(_SUNOS_VTOC_16) 4721786Slclee /* 4722786Slclee * If we have valid geometry, set up the remaining fdisk partitions. 4723786Slclee * Note that dkl_cylno is not used for the fdisk map entries, so 4724786Slclee * we set it to an entirely bogus value. 4725786Slclee */ 4726*8333SSuhasini.Peddada@Sun.COM for (count = 0; count < FD_NUMPART; count++) { 47277563SPrasad.Singamsetty@Sun.COM cl->cl_map[FDISK_P1 + count].dkl_cylno = UINT32_MAX; 47283525Sshidokht cl->cl_map[FDISK_P1 + count].dkl_nblk = 47293525Sshidokht cl->cl_fmap[count].fmap_nblk; 47303525Sshidokht cl->cl_offset[FDISK_P1 + count] = 47313525Sshidokht cl->cl_fmap[count].fmap_start; 4732786Slclee } 4733786Slclee #endif 4734786Slclee 4735786Slclee for (count = 0; count < NDKMAP; count++) { 4736786Slclee #if defined(_SUNOS_VTOC_8) 47373525Sshidokht struct dk_map *lp = &cl->cl_map[count]; 47383525Sshidokht cl->cl_offset[count] = 47393525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno; 4740786Slclee #elif defined(_SUNOS_VTOC_16) 47413525Sshidokht struct dkl_partition *vp = &cl->cl_vtoc.v_part[count]; 47423525Sshidokht cl->cl_offset[count] = vp->p_start + cl->cl_solaris_offset; 4743786Slclee #else 4744786Slclee #error "No VTOC format defined." 4745786Slclee #endif 4746786Slclee } 4747786Slclee 47483525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 4749786Slclee return (label_rc); 4750786Slclee } 4751786Slclee #endif 4752786Slclee 4753786Slclee #if defined(__i386) || defined(__amd64) 4754786Slclee static int 47553525Sshidokht cmlb_dkio_get_virtgeom(struct cmlb_lun *cl, caddr_t arg, int flag) 4756786Slclee { 4757786Slclee int err = 0; 4758786Slclee 4759786Slclee /* Return the driver's notion of the media's logical geometry */ 4760786Slclee struct dk_geom disk_geom; 4761786Slclee struct dk_geom *dkgp = &disk_geom; 4762786Slclee 47633525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 4764786Slclee /* 4765786Slclee * If there is no HBA geometry available, or 4766786Slclee * if the HBA returned us something that doesn't 4767786Slclee * really fit into an Int 13/function 8 geometry 4768786Slclee * result, just fail the ioctl. See PSARC 1998/313. 4769786Slclee */ 47703525Sshidokht if (cl->cl_lgeom.g_nhead == 0 || 47713525Sshidokht cl->cl_lgeom.g_nsect == 0 || 47723525Sshidokht cl->cl_lgeom.g_ncyl > 1024) { 47733525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4774786Slclee err = EINVAL; 4775786Slclee } else { 47763525Sshidokht dkgp->dkg_ncyl = cl->cl_lgeom.g_ncyl; 47773525Sshidokht dkgp->dkg_acyl = cl->cl_lgeom.g_acyl; 4778786Slclee dkgp->dkg_pcyl = dkgp->dkg_ncyl + dkgp->dkg_acyl; 47793525Sshidokht dkgp->dkg_nhead = cl->cl_lgeom.g_nhead; 47803525Sshidokht dkgp->dkg_nsect = cl->cl_lgeom.g_nsect; 4781786Slclee 47824177Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4783786Slclee if (ddi_copyout(dkgp, (void *)arg, 4784786Slclee sizeof (struct dk_geom), flag)) { 4785786Slclee err = EFAULT; 4786786Slclee } else { 4787786Slclee err = 0; 4788786Slclee } 4789786Slclee } 4790786Slclee return (err); 4791786Slclee } 4792786Slclee #endif 4793786Slclee 4794786Slclee #if defined(__i386) || defined(__amd64) 4795786Slclee static int 47963525Sshidokht cmlb_dkio_get_phygeom(struct cmlb_lun *cl, caddr_t arg, int flag) 4797786Slclee { 4798786Slclee int err = 0; 47993525Sshidokht diskaddr_t capacity; 4800786Slclee 4801786Slclee 4802786Slclee /* Return the driver's notion of the media physical geometry */ 4803786Slclee struct dk_geom disk_geom; 4804786Slclee struct dk_geom *dkgp = &disk_geom; 4805786Slclee 48063525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 48073525Sshidokht 48083525Sshidokht if (cl->cl_g.dkg_nhead != 0 && 48093525Sshidokht cl->cl_g.dkg_nsect != 0) { 4810786Slclee /* 4811786Slclee * We succeeded in getting a geometry, but 4812786Slclee * right now it is being reported as just the 4813786Slclee * Solaris fdisk partition, just like for 4814786Slclee * DKIOCGGEOM. We need to change that to be 4815786Slclee * correct for the entire disk now. 4816786Slclee */ 48173525Sshidokht bcopy(&cl->cl_g, dkgp, sizeof (*dkgp)); 4818786Slclee dkgp->dkg_acyl = 0; 48193525Sshidokht dkgp->dkg_ncyl = cl->cl_blockcount / 4820786Slclee (dkgp->dkg_nhead * dkgp->dkg_nsect); 4821786Slclee } else { 4822786Slclee bzero(dkgp, sizeof (struct dk_geom)); 4823786Slclee /* 4824786Slclee * This disk does not have a Solaris VTOC 4825786Slclee * so we must present a physical geometry 4826786Slclee * that will remain consistent regardless 4827786Slclee * of how the disk is used. This will ensure 4828786Slclee * that the geometry does not change regardless 4829786Slclee * of the fdisk partition type (ie. EFI, FAT32, 4830786Slclee * Solaris, etc). 4831786Slclee */ 48323525Sshidokht if (ISCD(cl)) { 48333525Sshidokht dkgp->dkg_nhead = cl->cl_pgeom.g_nhead; 48343525Sshidokht dkgp->dkg_nsect = cl->cl_pgeom.g_nsect; 48353525Sshidokht dkgp->dkg_ncyl = cl->cl_pgeom.g_ncyl; 48363525Sshidokht dkgp->dkg_acyl = cl->cl_pgeom.g_acyl; 4837786Slclee } else { 48383525Sshidokht /* 48393525Sshidokht * Invalid cl_blockcount can generate invalid 48403525Sshidokht * dk_geom and may result in division by zero 48413525Sshidokht * system failure. Should make sure blockcount 48423525Sshidokht * is valid before using it here. 48433525Sshidokht */ 48443525Sshidokht if (cl->cl_blockcount == 0) { 48453525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 48463525Sshidokht err = EIO; 48473525Sshidokht return (err); 48483525Sshidokht } 48493525Sshidokht /* 48503525Sshidokht * Refer to comments related to off-by-1 at the 48513525Sshidokht * header of this file 48523525Sshidokht */ 48533525Sshidokht if (cl->cl_alter_behavior & CMLB_OFF_BY_ONE) 48543525Sshidokht capacity = cl->cl_blockcount - 1; 48553525Sshidokht else 48563525Sshidokht capacity = cl->cl_blockcount; 48573525Sshidokht 48583525Sshidokht cmlb_convert_geometry(capacity, dkgp); 4859786Slclee dkgp->dkg_acyl = 0; 48603525Sshidokht dkgp->dkg_ncyl = capacity / 4861786Slclee (dkgp->dkg_nhead * dkgp->dkg_nsect); 4862786Slclee } 4863786Slclee } 4864786Slclee dkgp->dkg_pcyl = dkgp->dkg_ncyl + dkgp->dkg_acyl; 4865786Slclee 48664177Sshidokht mutex_exit(CMLB_MUTEX(cl)); 48674177Sshidokht if (ddi_copyout(dkgp, (void *)arg, sizeof (struct dk_geom), flag)) 4868786Slclee err = EFAULT; 48694177Sshidokht 4870786Slclee return (err); 4871786Slclee } 4872786Slclee #endif 4873786Slclee 4874786Slclee #if defined(__i386) || defined(__amd64) 4875786Slclee static int 48763525Sshidokht cmlb_dkio_partinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag) 4877786Slclee { 4878786Slclee int err = 0; 4879786Slclee 4880786Slclee /* 4881786Slclee * Return parameters describing the selected disk slice. 4882786Slclee * Note: this ioctl is for the intel platform only 4883786Slclee */ 4884786Slclee int part; 4885786Slclee 4886786Slclee part = CMLBPART(dev); 4887786Slclee 48883525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 48893525Sshidokht /* don't check cl_solaris_size for pN */ 48903525Sshidokht if (part < P0_RAW_DISK && cl->cl_solaris_size == 0) { 4891786Slclee err = EIO; 48924177Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4893786Slclee } else { 4894786Slclee struct part_info p; 4895786Slclee 48963525Sshidokht p.p_start = (daddr_t)cl->cl_offset[part]; 48973525Sshidokht p.p_length = (int)cl->cl_map[part].dkl_nblk; 48984177Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4899786Slclee #ifdef _MULTI_DATAMODEL 4900786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 4901786Slclee case DDI_MODEL_ILP32: 4902786Slclee { 4903786Slclee struct part_info32 p32; 4904786Slclee 4905786Slclee p32.p_start = (daddr32_t)p.p_start; 4906786Slclee p32.p_length = p.p_length; 4907786Slclee if (ddi_copyout(&p32, (void *)arg, 4908786Slclee sizeof (p32), flag)) 4909786Slclee err = EFAULT; 4910786Slclee break; 4911786Slclee } 4912786Slclee 4913786Slclee case DDI_MODEL_NONE: 4914786Slclee { 4915786Slclee if (ddi_copyout(&p, (void *)arg, sizeof (p), 4916786Slclee flag)) 4917786Slclee err = EFAULT; 4918786Slclee break; 4919786Slclee } 4920786Slclee } 4921786Slclee #else /* ! _MULTI_DATAMODEL */ 4922786Slclee if (ddi_copyout(&p, (void *)arg, sizeof (p), flag)) 4923786Slclee err = EFAULT; 4924786Slclee #endif /* _MULTI_DATAMODEL */ 4925786Slclee } 4926786Slclee return (err); 4927786Slclee } 49287563SPrasad.Singamsetty@Sun.COM static int 49297563SPrasad.Singamsetty@Sun.COM cmlb_dkio_extpartinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag) 49307563SPrasad.Singamsetty@Sun.COM { 49317563SPrasad.Singamsetty@Sun.COM int err = 0; 49327563SPrasad.Singamsetty@Sun.COM 49337563SPrasad.Singamsetty@Sun.COM /* 49347563SPrasad.Singamsetty@Sun.COM * Return parameters describing the selected disk slice. 49357563SPrasad.Singamsetty@Sun.COM * Note: this ioctl is for the intel platform only 49367563SPrasad.Singamsetty@Sun.COM */ 49377563SPrasad.Singamsetty@Sun.COM int part; 49387563SPrasad.Singamsetty@Sun.COM 49397563SPrasad.Singamsetty@Sun.COM part = CMLBPART(dev); 49407563SPrasad.Singamsetty@Sun.COM 49417563SPrasad.Singamsetty@Sun.COM mutex_enter(CMLB_MUTEX(cl)); 49427563SPrasad.Singamsetty@Sun.COM /* don't check cl_solaris_size for pN */ 49437563SPrasad.Singamsetty@Sun.COM if (part < P0_RAW_DISK && cl->cl_solaris_size == 0) { 49447563SPrasad.Singamsetty@Sun.COM err = EIO; 49457563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 49467563SPrasad.Singamsetty@Sun.COM } else { 49477563SPrasad.Singamsetty@Sun.COM struct extpart_info p; 49487563SPrasad.Singamsetty@Sun.COM 49497563SPrasad.Singamsetty@Sun.COM p.p_start = (diskaddr_t)cl->cl_offset[part]; 49507563SPrasad.Singamsetty@Sun.COM p.p_length = (diskaddr_t)cl->cl_map[part].dkl_nblk; 49517563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 49527563SPrasad.Singamsetty@Sun.COM if (ddi_copyout(&p, (void *)arg, sizeof (p), flag)) 49537563SPrasad.Singamsetty@Sun.COM err = EFAULT; 49547563SPrasad.Singamsetty@Sun.COM } 49557563SPrasad.Singamsetty@Sun.COM return (err); 49567563SPrasad.Singamsetty@Sun.COM } 4957786Slclee #endif 49587224Scth 49597224Scth int 49607224Scth cmlb_prop_op(cmlb_handle_t cmlbhandle, 49617224Scth dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags, 49627224Scth char *name, caddr_t valuep, int *lengthp, int part, void *tg_cookie) 49637224Scth { 49647224Scth struct cmlb_lun *cl; 49657224Scth diskaddr_t capacity; 49667224Scth uint32_t lbasize; 49677224Scth enum dp { DP_NBLOCKS, DP_BLKSIZE } dp; 49687224Scth int callers_length; 49697224Scth caddr_t buffer; 49707224Scth uint64_t nblocks64; 49717224Scth uint_t dblk; 49727224Scth 49737224Scth /* Always fallback to ddi_prop_op... */ 49747224Scth cl = (struct cmlb_lun *)cmlbhandle; 49757224Scth if (cl == NULL) { 49767224Scth fallback: return (ddi_prop_op(dev, dip, prop_op, mod_flags, 49777224Scth name, valuep, lengthp)); 49787224Scth } 49797224Scth 49807224Scth /* Pick up capacity and blocksize information. */ 49817224Scth capacity = cl->cl_blockcount; 49827224Scth if (capacity == 0) 49837224Scth goto fallback; 49847224Scth lbasize = cl->cl_tgt_blocksize; 49857224Scth if (lbasize == 0) 49867224Scth lbasize = DEV_BSIZE; /* 0 -> DEV_BSIZE units */ 49877224Scth 49887224Scth /* Check for dynamic property of whole device. */ 49897224Scth if (dev == DDI_DEV_T_ANY) { 49907224Scth /* Fallback to ddi_prop_op if we don't understand. */ 49917224Scth if (strcmp(name, "device-nblocks") == 0) 49927224Scth dp = DP_NBLOCKS; 49937224Scth else if (strcmp(name, "device-blksize") == 0) 49947224Scth dp = DP_BLKSIZE; 49957224Scth else 49967224Scth goto fallback; 49977224Scth 49987224Scth /* get callers length, establish length of our dynamic prop */ 49997224Scth callers_length = *lengthp; 50007224Scth if (dp == DP_NBLOCKS) 50017224Scth *lengthp = sizeof (uint64_t); 50027224Scth else if (dp == DP_BLKSIZE) 50037224Scth *lengthp = sizeof (uint32_t); 50047224Scth 50057224Scth /* service request for the length of the property */ 50067224Scth if (prop_op == PROP_LEN) 50077224Scth return (DDI_PROP_SUCCESS); 50087224Scth 50097224Scth switch (prop_op) { 50107224Scth case PROP_LEN_AND_VAL_ALLOC: 50117224Scth if ((buffer = kmem_alloc(*lengthp, 50127224Scth (mod_flags & DDI_PROP_CANSLEEP) ? 50137224Scth KM_SLEEP : KM_NOSLEEP)) == NULL) 50147224Scth return (DDI_PROP_NO_MEMORY); 50157224Scth *(caddr_t *)valuep = buffer; /* set callers buf */ 50167224Scth break; 50177224Scth 50187224Scth case PROP_LEN_AND_VAL_BUF: 50197224Scth /* the length of the prop and the request must match */ 50207224Scth if (callers_length != *lengthp) 50217224Scth return (DDI_PROP_INVAL_ARG); 50227224Scth buffer = valuep; /* get callers buf */ 50237224Scth break; 50247224Scth 50257224Scth default: 50267224Scth return (DDI_PROP_INVAL_ARG); 50277224Scth } 50287224Scth 50297224Scth /* transfer the value into the buffer */ 50307224Scth if (dp == DP_NBLOCKS) 50317224Scth *((uint64_t *)buffer) = capacity; 50327224Scth else if (dp == DP_BLKSIZE) 50337224Scth *((uint32_t *)buffer) = lbasize; 50347224Scth 50357224Scth return (DDI_PROP_SUCCESS); 50367224Scth } 50377224Scth 50387224Scth /* 50397224Scth * Support dynamic size oriented properties of partition. Requests 50407224Scth * issued under conditions where size is valid are passed to 50417224Scth * ddi_prop_op_nblocks with the size information, otherwise the 50427224Scth * request is passed to ddi_prop_op. Size depends on valid geometry. 50437224Scth */ 50447224Scth if (!cmlb_is_valid(cmlbhandle)) 50457224Scth goto fallback; 50467224Scth 50477224Scth /* Get partition nblocks value. */ 50487224Scth (void) cmlb_partinfo(cmlbhandle, part, 50497224Scth (diskaddr_t *)&nblocks64, NULL, NULL, NULL, tg_cookie); 50507224Scth 50517224Scth /* 50527224Scth * Assume partition information is in DEV_BSIZE units, compute 50537224Scth * divisor for size(9P) property representation. 50547224Scth */ 50557224Scth dblk = lbasize / DEV_BSIZE; 50567224Scth 50577224Scth /* Now let ddi_prop_op_nblocks_blksize() handle the request. */ 50587224Scth return (ddi_prop_op_nblocks_blksize(dev, dip, prop_op, mod_flags, 50597224Scth name, valuep, lengthp, nblocks64 / dblk, lbasize)); 50607224Scth } 5061