1786Slclee /* 2786Slclee * CDDL HEADER START 3786Slclee * 4786Slclee * The contents of this file are subject to the terms of the 53525Sshidokht * Common Development and Distribution License (the "License"). 63525Sshidokht * You may not use this file except in compliance with the License. 7786Slclee * 8786Slclee * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9786Slclee * or http://www.opensolaris.org/os/licensing. 10786Slclee * See the License for the specific language governing permissions 11786Slclee * and limitations under the License. 12786Slclee * 13786Slclee * When distributing Covered Code, include this CDDL HEADER in each 14786Slclee * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15786Slclee * If applicable, add the following below this CDDL HEADER, with the 16786Slclee * fields enclosed by brackets "[]" replaced with your own identifying 17786Slclee * information: Portions Copyright [yyyy] [name of copyright owner] 18786Slclee * 19786Slclee * CDDL HEADER END 20786Slclee */ 21786Slclee 22786Slclee /* 238570SSriram.Popuri@sun.com * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24786Slclee * Use is subject to license terms. 25786Slclee */ 26786Slclee 27786Slclee /* 28786Slclee * This module provides support for labeling operations for target 29786Slclee * drivers. 30786Slclee */ 31786Slclee 32786Slclee #include <sys/scsi/scsi.h> 33786Slclee #include <sys/sunddi.h> 34786Slclee #include <sys/dklabel.h> 35786Slclee #include <sys/dkio.h> 36786Slclee #include <sys/vtoc.h> 37786Slclee #include <sys/dktp/fdisk.h> 38786Slclee #include <sys/vtrace.h> 39786Slclee #include <sys/efi_partition.h> 40786Slclee #include <sys/cmlb.h> 41786Slclee #include <sys/cmlb_impl.h> 4210021SSheshadri.Vasudevan@Sun.COM #if defined(__i386) || defined(__amd64) 4310021SSheshadri.Vasudevan@Sun.COM #include <sys/fs/dv_node.h> 4410021SSheshadri.Vasudevan@Sun.COM #endif 457224Scth #include <sys/ddi_impldefs.h> 46786Slclee 47786Slclee /* 48786Slclee * Driver minor node structure and data table 49786Slclee */ 50786Slclee struct driver_minor_data { 51786Slclee char *name; 52786Slclee minor_t minor; 53786Slclee int type; 54786Slclee }; 55786Slclee 56786Slclee static struct driver_minor_data dk_minor_data[] = { 57786Slclee {"a", 0, S_IFBLK}, 58786Slclee {"b", 1, S_IFBLK}, 59786Slclee {"c", 2, S_IFBLK}, 60786Slclee {"d", 3, S_IFBLK}, 61786Slclee {"e", 4, S_IFBLK}, 62786Slclee {"f", 5, S_IFBLK}, 63786Slclee {"g", 6, S_IFBLK}, 64786Slclee {"h", 7, S_IFBLK}, 65786Slclee #if defined(_SUNOS_VTOC_16) 66786Slclee {"i", 8, S_IFBLK}, 67786Slclee {"j", 9, S_IFBLK}, 68786Slclee {"k", 10, S_IFBLK}, 69786Slclee {"l", 11, S_IFBLK}, 70786Slclee {"m", 12, S_IFBLK}, 71786Slclee {"n", 13, S_IFBLK}, 72786Slclee {"o", 14, S_IFBLK}, 73786Slclee {"p", 15, S_IFBLK}, 74786Slclee #endif /* defined(_SUNOS_VTOC_16) */ 75786Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 76786Slclee {"q", 16, S_IFBLK}, 77786Slclee {"r", 17, S_IFBLK}, 78786Slclee {"s", 18, S_IFBLK}, 79786Slclee {"t", 19, S_IFBLK}, 80786Slclee {"u", 20, S_IFBLK}, 81786Slclee #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 82786Slclee {"a,raw", 0, S_IFCHR}, 83786Slclee {"b,raw", 1, S_IFCHR}, 84786Slclee {"c,raw", 2, S_IFCHR}, 85786Slclee {"d,raw", 3, S_IFCHR}, 86786Slclee {"e,raw", 4, S_IFCHR}, 87786Slclee {"f,raw", 5, S_IFCHR}, 88786Slclee {"g,raw", 6, S_IFCHR}, 89786Slclee {"h,raw", 7, S_IFCHR}, 90786Slclee #if defined(_SUNOS_VTOC_16) 91786Slclee {"i,raw", 8, S_IFCHR}, 92786Slclee {"j,raw", 9, S_IFCHR}, 93786Slclee {"k,raw", 10, S_IFCHR}, 94786Slclee {"l,raw", 11, S_IFCHR}, 95786Slclee {"m,raw", 12, S_IFCHR}, 96786Slclee {"n,raw", 13, S_IFCHR}, 97786Slclee {"o,raw", 14, S_IFCHR}, 98786Slclee {"p,raw", 15, S_IFCHR}, 99786Slclee #endif /* defined(_SUNOS_VTOC_16) */ 100786Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 101786Slclee {"q,raw", 16, S_IFCHR}, 102786Slclee {"r,raw", 17, S_IFCHR}, 103786Slclee {"s,raw", 18, S_IFCHR}, 104786Slclee {"t,raw", 19, S_IFCHR}, 105786Slclee {"u,raw", 20, S_IFCHR}, 106786Slclee #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 107786Slclee {0} 108786Slclee }; 109786Slclee 11010021SSheshadri.Vasudevan@Sun.COM #if defined(__i386) || defined(__amd64) 11110021SSheshadri.Vasudevan@Sun.COM #if defined(_FIRMWARE_NEEDS_FDISK) 11210021SSheshadri.Vasudevan@Sun.COM static struct driver_minor_data dk_ext_minor_data[] = { 11310021SSheshadri.Vasudevan@Sun.COM {"p5", 21, S_IFBLK}, 11410021SSheshadri.Vasudevan@Sun.COM {"p6", 22, S_IFBLK}, 11510021SSheshadri.Vasudevan@Sun.COM {"p7", 23, S_IFBLK}, 11610021SSheshadri.Vasudevan@Sun.COM {"p8", 24, S_IFBLK}, 11710021SSheshadri.Vasudevan@Sun.COM {"p9", 25, S_IFBLK}, 11810021SSheshadri.Vasudevan@Sun.COM {"p10", 26, S_IFBLK}, 11910021SSheshadri.Vasudevan@Sun.COM {"p11", 27, S_IFBLK}, 12010021SSheshadri.Vasudevan@Sun.COM {"p12", 28, S_IFBLK}, 12110021SSheshadri.Vasudevan@Sun.COM {"p13", 29, S_IFBLK}, 12210021SSheshadri.Vasudevan@Sun.COM {"p14", 30, S_IFBLK}, 12310021SSheshadri.Vasudevan@Sun.COM {"p15", 31, S_IFBLK}, 12410021SSheshadri.Vasudevan@Sun.COM {"p16", 32, S_IFBLK}, 12510021SSheshadri.Vasudevan@Sun.COM {"p17", 33, S_IFBLK}, 12610021SSheshadri.Vasudevan@Sun.COM {"p18", 34, S_IFBLK}, 12710021SSheshadri.Vasudevan@Sun.COM {"p19", 35, S_IFBLK}, 12810021SSheshadri.Vasudevan@Sun.COM {"p20", 36, S_IFBLK}, 12910021SSheshadri.Vasudevan@Sun.COM {"p21", 37, S_IFBLK}, 13010021SSheshadri.Vasudevan@Sun.COM {"p22", 38, S_IFBLK}, 13110021SSheshadri.Vasudevan@Sun.COM {"p23", 39, S_IFBLK}, 13210021SSheshadri.Vasudevan@Sun.COM {"p24", 40, S_IFBLK}, 13310021SSheshadri.Vasudevan@Sun.COM {"p25", 41, S_IFBLK}, 13410021SSheshadri.Vasudevan@Sun.COM {"p26", 42, S_IFBLK}, 13510021SSheshadri.Vasudevan@Sun.COM {"p27", 43, S_IFBLK}, 13610021SSheshadri.Vasudevan@Sun.COM {"p28", 44, S_IFBLK}, 13710021SSheshadri.Vasudevan@Sun.COM {"p29", 45, S_IFBLK}, 13810021SSheshadri.Vasudevan@Sun.COM {"p30", 46, S_IFBLK}, 13910021SSheshadri.Vasudevan@Sun.COM {"p31", 47, S_IFBLK}, 14010021SSheshadri.Vasudevan@Sun.COM {"p32", 48, S_IFBLK}, 14110021SSheshadri.Vasudevan@Sun.COM {"p33", 49, S_IFBLK}, 14210021SSheshadri.Vasudevan@Sun.COM {"p34", 50, S_IFBLK}, 14310021SSheshadri.Vasudevan@Sun.COM {"p35", 51, S_IFBLK}, 14410021SSheshadri.Vasudevan@Sun.COM {"p36", 52, S_IFBLK}, 14510021SSheshadri.Vasudevan@Sun.COM {"p5,raw", 21, S_IFCHR}, 14610021SSheshadri.Vasudevan@Sun.COM {"p6,raw", 22, S_IFCHR}, 14710021SSheshadri.Vasudevan@Sun.COM {"p7,raw", 23, S_IFCHR}, 14810021SSheshadri.Vasudevan@Sun.COM {"p8,raw", 24, S_IFCHR}, 14910021SSheshadri.Vasudevan@Sun.COM {"p9,raw", 25, S_IFCHR}, 15010021SSheshadri.Vasudevan@Sun.COM {"p10,raw", 26, S_IFCHR}, 15110021SSheshadri.Vasudevan@Sun.COM {"p11,raw", 27, S_IFCHR}, 15210021SSheshadri.Vasudevan@Sun.COM {"p12,raw", 28, S_IFCHR}, 15310021SSheshadri.Vasudevan@Sun.COM {"p13,raw", 29, S_IFCHR}, 15410021SSheshadri.Vasudevan@Sun.COM {"p14,raw", 30, S_IFCHR}, 15510021SSheshadri.Vasudevan@Sun.COM {"p15,raw", 31, S_IFCHR}, 15610021SSheshadri.Vasudevan@Sun.COM {"p16,raw", 32, S_IFCHR}, 15710021SSheshadri.Vasudevan@Sun.COM {"p17,raw", 33, S_IFCHR}, 15810021SSheshadri.Vasudevan@Sun.COM {"p18,raw", 34, S_IFCHR}, 15910021SSheshadri.Vasudevan@Sun.COM {"p19,raw", 35, S_IFCHR}, 16010021SSheshadri.Vasudevan@Sun.COM {"p20,raw", 36, S_IFCHR}, 16110021SSheshadri.Vasudevan@Sun.COM {"p21,raw", 37, S_IFCHR}, 16210021SSheshadri.Vasudevan@Sun.COM {"p22,raw", 38, S_IFCHR}, 16310021SSheshadri.Vasudevan@Sun.COM {"p23,raw", 39, S_IFCHR}, 16410021SSheshadri.Vasudevan@Sun.COM {"p24,raw", 40, S_IFCHR}, 16510021SSheshadri.Vasudevan@Sun.COM {"p25,raw", 41, S_IFCHR}, 16610021SSheshadri.Vasudevan@Sun.COM {"p26,raw", 42, S_IFCHR}, 16710021SSheshadri.Vasudevan@Sun.COM {"p27,raw", 43, S_IFCHR}, 16810021SSheshadri.Vasudevan@Sun.COM {"p28,raw", 44, S_IFCHR}, 16910021SSheshadri.Vasudevan@Sun.COM {"p29,raw", 45, S_IFCHR}, 17010021SSheshadri.Vasudevan@Sun.COM {"p30,raw", 46, S_IFCHR}, 17110021SSheshadri.Vasudevan@Sun.COM {"p31,raw", 47, S_IFCHR}, 17210021SSheshadri.Vasudevan@Sun.COM {"p32,raw", 48, S_IFCHR}, 17310021SSheshadri.Vasudevan@Sun.COM {"p33,raw", 49, S_IFCHR}, 17410021SSheshadri.Vasudevan@Sun.COM {"p34,raw", 50, S_IFCHR}, 17510021SSheshadri.Vasudevan@Sun.COM {"p35,raw", 51, S_IFCHR}, 17610021SSheshadri.Vasudevan@Sun.COM {"p36,raw", 52, S_IFCHR}, 17710021SSheshadri.Vasudevan@Sun.COM {0} 17810021SSheshadri.Vasudevan@Sun.COM }; 17910021SSheshadri.Vasudevan@Sun.COM #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 18010021SSheshadri.Vasudevan@Sun.COM #endif /* if defined(__i386) || defined(__amd64) */ 18110021SSheshadri.Vasudevan@Sun.COM 182786Slclee static struct driver_minor_data dk_minor_data_efi[] = { 183786Slclee {"a", 0, S_IFBLK}, 184786Slclee {"b", 1, S_IFBLK}, 185786Slclee {"c", 2, S_IFBLK}, 186786Slclee {"d", 3, S_IFBLK}, 187786Slclee {"e", 4, S_IFBLK}, 188786Slclee {"f", 5, S_IFBLK}, 189786Slclee {"g", 6, S_IFBLK}, 190786Slclee {"wd", 7, S_IFBLK}, 1918749SShidokht.Yadegari@Sun.COM #if defined(_SUNOS_VTOC_16) 1928749SShidokht.Yadegari@Sun.COM {"i", 8, S_IFBLK}, 1938749SShidokht.Yadegari@Sun.COM {"j", 9, S_IFBLK}, 1948749SShidokht.Yadegari@Sun.COM {"k", 10, S_IFBLK}, 1958749SShidokht.Yadegari@Sun.COM {"l", 11, S_IFBLK}, 1968749SShidokht.Yadegari@Sun.COM {"m", 12, S_IFBLK}, 1978749SShidokht.Yadegari@Sun.COM {"n", 13, S_IFBLK}, 1988749SShidokht.Yadegari@Sun.COM {"o", 14, S_IFBLK}, 1998749SShidokht.Yadegari@Sun.COM {"p", 15, S_IFBLK}, 2008749SShidokht.Yadegari@Sun.COM #endif /* defined(_SUNOS_VTOC_16) */ 201786Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 202786Slclee {"q", 16, S_IFBLK}, 203786Slclee {"r", 17, S_IFBLK}, 204786Slclee {"s", 18, S_IFBLK}, 205786Slclee {"t", 19, S_IFBLK}, 206786Slclee {"u", 20, S_IFBLK}, 207786Slclee #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 208786Slclee {"a,raw", 0, S_IFCHR}, 209786Slclee {"b,raw", 1, S_IFCHR}, 210786Slclee {"c,raw", 2, S_IFCHR}, 211786Slclee {"d,raw", 3, S_IFCHR}, 212786Slclee {"e,raw", 4, S_IFCHR}, 213786Slclee {"f,raw", 5, S_IFCHR}, 214786Slclee {"g,raw", 6, S_IFCHR}, 215786Slclee {"wd,raw", 7, S_IFCHR}, 2168749SShidokht.Yadegari@Sun.COM #if defined(_SUNOS_VTOC_16) 2178749SShidokht.Yadegari@Sun.COM {"i,raw", 8, S_IFCHR}, 2188749SShidokht.Yadegari@Sun.COM {"j,raw", 9, S_IFCHR}, 2198749SShidokht.Yadegari@Sun.COM {"k,raw", 10, S_IFCHR}, 2208749SShidokht.Yadegari@Sun.COM {"l,raw", 11, S_IFCHR}, 2218749SShidokht.Yadegari@Sun.COM {"m,raw", 12, S_IFCHR}, 2228749SShidokht.Yadegari@Sun.COM {"n,raw", 13, S_IFCHR}, 2238749SShidokht.Yadegari@Sun.COM {"o,raw", 14, S_IFCHR}, 2248749SShidokht.Yadegari@Sun.COM {"p,raw", 15, S_IFCHR}, 2258749SShidokht.Yadegari@Sun.COM #endif /* defined(_SUNOS_VTOC_16) */ 226786Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 227786Slclee {"q,raw", 16, S_IFCHR}, 228786Slclee {"r,raw", 17, S_IFCHR}, 229786Slclee {"s,raw", 18, S_IFCHR}, 230786Slclee {"t,raw", 19, S_IFCHR}, 231786Slclee {"u,raw", 20, S_IFCHR}, 232786Slclee #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 233786Slclee {0} 234786Slclee }; 235786Slclee 2367224Scth /* 2377224Scth * Declare the dynamic properties implemented in prop_op(9E) implementation 2387224Scth * that we want to have show up in a di_init(3DEVINFO) device tree snapshot 2397224Scth * of drivers that call cmlb_attach(). 2407224Scth */ 2417224Scth static i_ddi_prop_dyn_t cmlb_prop_dyn[] = { 2427224Scth {"Nblocks", DDI_PROP_TYPE_INT64, S_IFBLK}, 2437224Scth {"Size", DDI_PROP_TYPE_INT64, S_IFCHR}, 2447224Scth {"device-nblocks", DDI_PROP_TYPE_INT64}, 2457224Scth {"device-blksize", DDI_PROP_TYPE_INT}, 2467224Scth {NULL} 2477224Scth }; 248786Slclee 2496318Sedp /* 2506318Sedp * External kernel interfaces 2516318Sedp */ 252786Slclee extern struct mod_ops mod_miscops; 253786Slclee 2546318Sedp extern int ddi_create_internal_pathname(dev_info_t *dip, char *name, 2556318Sedp int spec_type, minor_t minor_num); 2566318Sedp 257786Slclee /* 258786Slclee * Global buffer and mutex for debug logging 259786Slclee */ 260786Slclee static char cmlb_log_buffer[1024]; 261786Slclee static kmutex_t cmlb_log_mutex; 262786Slclee 263786Slclee 2643525Sshidokht struct cmlb_lun *cmlb_debug_cl = NULL; 265786Slclee uint_t cmlb_level_mask = 0x0; 266786Slclee 267786Slclee int cmlb_rot_delay = 4; /* default rotational delay */ 268786Slclee 269786Slclee static struct modlmisc modlmisc = { 270786Slclee &mod_miscops, /* Type of module */ 2717563SPrasad.Singamsetty@Sun.COM "Common Labeling module" 272786Slclee }; 273786Slclee 274786Slclee static struct modlinkage modlinkage = { 275786Slclee MODREV_1, (void *)&modlmisc, NULL 276786Slclee }; 277786Slclee 278786Slclee /* Local function prototypes */ 2793525Sshidokht static dev_t cmlb_make_device(struct cmlb_lun *cl); 2808863SEdward.Pilatowicz@Sun.COM static int cmlb_validate_geometry(struct cmlb_lun *cl, boolean_t forcerevalid, 2813525Sshidokht int flags, void *tg_cookie); 2823525Sshidokht static void cmlb_resync_geom_caches(struct cmlb_lun *cl, diskaddr_t capacity, 2833525Sshidokht void *tg_cookie); 2843525Sshidokht static int cmlb_read_fdisk(struct cmlb_lun *cl, diskaddr_t capacity, 2853525Sshidokht void *tg_cookie); 286786Slclee static void cmlb_swap_efi_gpt(efi_gpt_t *e); 287786Slclee static void cmlb_swap_efi_gpe(int nparts, efi_gpe_t *p); 288786Slclee static int cmlb_validate_efi(efi_gpt_t *labp); 2893525Sshidokht static int cmlb_use_efi(struct cmlb_lun *cl, diskaddr_t capacity, int flags, 2903525Sshidokht void *tg_cookie); 2913525Sshidokht static void cmlb_build_default_label(struct cmlb_lun *cl, void *tg_cookie); 2923525Sshidokht static int cmlb_uselabel(struct cmlb_lun *cl, struct dk_label *l, int flags); 2933525Sshidokht #if defined(_SUNOS_VTOC_8) 2943525Sshidokht static void cmlb_build_user_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc); 2953525Sshidokht #endif 2963525Sshidokht static int cmlb_build_label_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc); 2973525Sshidokht static int cmlb_write_label(struct cmlb_lun *cl, void *tg_cookie); 2983525Sshidokht static int cmlb_set_vtoc(struct cmlb_lun *cl, struct dk_label *dkl, 2993525Sshidokht void *tg_cookie); 3003525Sshidokht static void cmlb_clear_efi(struct cmlb_lun *cl, void *tg_cookie); 3013525Sshidokht static void cmlb_clear_vtoc(struct cmlb_lun *cl, void *tg_cookie); 3023525Sshidokht static void cmlb_setup_default_geometry(struct cmlb_lun *cl, void *tg_cookie); 3033525Sshidokht static int cmlb_create_minor_nodes(struct cmlb_lun *cl); 3043525Sshidokht static int cmlb_check_update_blockcount(struct cmlb_lun *cl, void *tg_cookie); 3058863SEdward.Pilatowicz@Sun.COM static boolean_t cmlb_check_efi_mbr(uchar_t *buf, boolean_t *is_mbr); 306786Slclee 307786Slclee #if defined(__i386) || defined(__amd64) 3083525Sshidokht static int cmlb_update_fdisk_and_vtoc(struct cmlb_lun *cl, void *tg_cookie); 309786Slclee #endif 310786Slclee 311786Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 3128863SEdward.Pilatowicz@Sun.COM static boolean_t cmlb_has_max_chs_vals(struct ipart *fdp); 313786Slclee #endif 314786Slclee 315786Slclee #if defined(_SUNOS_VTOC_16) 31610320SLarry.Liu@Sun.COM static void cmlb_convert_geometry(struct cmlb_lun *cl, diskaddr_t capacity, 31710320SLarry.Liu@Sun.COM struct dk_geom *cl_g, void *tg_cookie); 318786Slclee #endif 319786Slclee 3203525Sshidokht static int cmlb_dkio_get_geometry(struct cmlb_lun *cl, caddr_t arg, int flag, 3213525Sshidokht void *tg_cookie); 3223525Sshidokht static int cmlb_dkio_set_geometry(struct cmlb_lun *cl, caddr_t arg, int flag); 3233525Sshidokht static int cmlb_dkio_get_partition(struct cmlb_lun *cl, caddr_t arg, int flag, 3243525Sshidokht void *tg_cookie); 3253525Sshidokht static int cmlb_dkio_set_partition(struct cmlb_lun *cl, caddr_t arg, int flag); 3263525Sshidokht static int cmlb_dkio_get_efi(struct cmlb_lun *cl, caddr_t arg, int flag, 3273525Sshidokht void *tg_cookie); 3283525Sshidokht static int cmlb_dkio_set_efi(struct cmlb_lun *cl, dev_t dev, caddr_t arg, 3293525Sshidokht int flag, void *tg_cookie); 3303525Sshidokht static int cmlb_dkio_get_vtoc(struct cmlb_lun *cl, caddr_t arg, int flag, 3313525Sshidokht void *tg_cookie); 3327563SPrasad.Singamsetty@Sun.COM static int cmlb_dkio_get_extvtoc(struct cmlb_lun *cl, caddr_t arg, int flag, 3337563SPrasad.Singamsetty@Sun.COM void *tg_cookie); 3343525Sshidokht static int cmlb_dkio_set_vtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, 3353525Sshidokht int flag, void *tg_cookie); 3367563SPrasad.Singamsetty@Sun.COM static int cmlb_dkio_set_extvtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, 3377563SPrasad.Singamsetty@Sun.COM int flag, void *tg_cookie); 3383525Sshidokht static int cmlb_dkio_get_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, 3393525Sshidokht void *tg_cookie); 3403525Sshidokht static int cmlb_dkio_set_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, 3413525Sshidokht void *tg_cookie); 3423525Sshidokht static int cmlb_dkio_partition(struct cmlb_lun *cl, caddr_t arg, int flag, 3433525Sshidokht void *tg_cookie); 344786Slclee 345786Slclee #if defined(__i386) || defined(__amd64) 34610021SSheshadri.Vasudevan@Sun.COM static int cmlb_dkio_set_ext_part(struct cmlb_lun *cl, caddr_t arg, int flag, 34710021SSheshadri.Vasudevan@Sun.COM void *tg_cookie); 34810021SSheshadri.Vasudevan@Sun.COM static int cmlb_validate_ext_part(struct cmlb_lun *cl, int part, int epart, 34910021SSheshadri.Vasudevan@Sun.COM uint32_t start, uint32_t size); 35010021SSheshadri.Vasudevan@Sun.COM static int cmlb_is_linux_swap(struct cmlb_lun *cl, uint32_t part_start, 35110021SSheshadri.Vasudevan@Sun.COM void *tg_cookie); 3523525Sshidokht static int cmlb_dkio_get_virtgeom(struct cmlb_lun *cl, caddr_t arg, int flag); 35310320SLarry.Liu@Sun.COM static int cmlb_dkio_get_phygeom(struct cmlb_lun *cl, caddr_t arg, int flag, 35410320SLarry.Liu@Sun.COM void *tg_cookie); 3553525Sshidokht static int cmlb_dkio_partinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg, 356786Slclee int flag); 3577563SPrasad.Singamsetty@Sun.COM static int cmlb_dkio_extpartinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg, 3587563SPrasad.Singamsetty@Sun.COM int flag); 359786Slclee #endif 360786Slclee 3613525Sshidokht static void cmlb_dbg(uint_t comp, struct cmlb_lun *cl, const char *fmt, ...); 362786Slclee static void cmlb_v_log(dev_info_t *dev, char *label, uint_t level, 363786Slclee const char *fmt, va_list ap); 364786Slclee static void cmlb_log(dev_info_t *dev, char *label, uint_t level, 365786Slclee const char *fmt, ...); 366786Slclee 367786Slclee int 368786Slclee _init(void) 369786Slclee { 370786Slclee mutex_init(&cmlb_log_mutex, NULL, MUTEX_DRIVER, NULL); 371786Slclee return (mod_install(&modlinkage)); 372786Slclee } 373786Slclee 374786Slclee int 375786Slclee _info(struct modinfo *modinfop) 376786Slclee { 377786Slclee return (mod_info(&modlinkage, modinfop)); 378786Slclee } 379786Slclee 380786Slclee int 381786Slclee _fini(void) 382786Slclee { 383786Slclee int err; 384786Slclee 385786Slclee if ((err = mod_remove(&modlinkage)) != 0) { 386786Slclee return (err); 387786Slclee } 388786Slclee 389786Slclee mutex_destroy(&cmlb_log_mutex); 390786Slclee return (err); 391786Slclee } 392786Slclee 393786Slclee /* 394786Slclee * cmlb_dbg is used for debugging to log additional info 395786Slclee * Level of output is controlled via cmlb_level_mask setting. 396786Slclee */ 397786Slclee static void 3983525Sshidokht cmlb_dbg(uint_t comp, struct cmlb_lun *cl, const char *fmt, ...) 399786Slclee { 400786Slclee va_list ap; 401786Slclee dev_info_t *dev; 402786Slclee uint_t level_mask = 0; 403786Slclee 4043525Sshidokht ASSERT(cl != NULL); 4053525Sshidokht dev = CMLB_DEVINFO(cl); 406786Slclee ASSERT(dev != NULL); 407786Slclee /* 408786Slclee * Filter messages based on the global component and level masks, 4093525Sshidokht * also print if cl matches the value of cmlb_debug_cl, or if 4103525Sshidokht * cmlb_debug_cl is set to NULL. 411786Slclee */ 412786Slclee if (comp & CMLB_TRACE) 413786Slclee level_mask |= CMLB_LOGMASK_TRACE; 414786Slclee 415786Slclee if (comp & CMLB_INFO) 416786Slclee level_mask |= CMLB_LOGMASK_INFO; 417786Slclee 418786Slclee if (comp & CMLB_ERROR) 419786Slclee level_mask |= CMLB_LOGMASK_ERROR; 420786Slclee 421786Slclee if ((cmlb_level_mask & level_mask) && 4223525Sshidokht ((cmlb_debug_cl == NULL) || (cmlb_debug_cl == cl))) { 423786Slclee va_start(ap, fmt); 4243525Sshidokht cmlb_v_log(dev, CMLB_LABEL(cl), CE_CONT, fmt, ap); 425786Slclee va_end(ap); 426786Slclee } 427786Slclee } 428786Slclee 429786Slclee /* 430786Slclee * cmlb_log is basically a duplicate of scsi_log. It is redefined here 431786Slclee * so that this module does not depend on scsi module. 432786Slclee */ 433786Slclee static void 434786Slclee cmlb_log(dev_info_t *dev, char *label, uint_t level, const char *fmt, ...) 435786Slclee { 436786Slclee va_list ap; 437786Slclee 438786Slclee va_start(ap, fmt); 439786Slclee cmlb_v_log(dev, label, level, fmt, ap); 440786Slclee va_end(ap); 441786Slclee } 442786Slclee 443786Slclee static void 444786Slclee cmlb_v_log(dev_info_t *dev, char *label, uint_t level, const char *fmt, 445786Slclee va_list ap) 446786Slclee { 447786Slclee static char name[256]; 448786Slclee int log_only = 0; 449786Slclee int boot_only = 0; 450786Slclee int console_only = 0; 451786Slclee 452786Slclee mutex_enter(&cmlb_log_mutex); 453786Slclee 454786Slclee if (dev) { 455786Slclee if (level == CE_PANIC || level == CE_WARN || 456786Slclee level == CE_NOTE) { 457786Slclee (void) sprintf(name, "%s (%s%d):\n", 458786Slclee ddi_pathname(dev, cmlb_log_buffer), 459786Slclee label, ddi_get_instance(dev)); 460786Slclee } else { 461786Slclee name[0] = '\0'; 462786Slclee } 463786Slclee } else { 464786Slclee (void) sprintf(name, "%s:", label); 465786Slclee } 466786Slclee 467786Slclee (void) vsprintf(cmlb_log_buffer, fmt, ap); 468786Slclee 469786Slclee switch (cmlb_log_buffer[0]) { 470786Slclee case '!': 471786Slclee log_only = 1; 472786Slclee break; 473786Slclee case '?': 474786Slclee boot_only = 1; 475786Slclee break; 476786Slclee case '^': 477786Slclee console_only = 1; 478786Slclee break; 479786Slclee } 480786Slclee 481786Slclee switch (level) { 482786Slclee case CE_NOTE: 483786Slclee level = CE_CONT; 484786Slclee /* FALLTHROUGH */ 485786Slclee case CE_CONT: 486786Slclee case CE_WARN: 487786Slclee case CE_PANIC: 488786Slclee if (boot_only) { 489786Slclee cmn_err(level, "?%s\t%s", name, &cmlb_log_buffer[1]); 490786Slclee } else if (console_only) { 491786Slclee cmn_err(level, "^%s\t%s", name, &cmlb_log_buffer[1]); 492786Slclee } else if (log_only) { 493786Slclee cmn_err(level, "!%s\t%s", name, &cmlb_log_buffer[1]); 494786Slclee } else { 495786Slclee cmn_err(level, "%s\t%s", name, cmlb_log_buffer); 496786Slclee } 497786Slclee break; 498786Slclee case CE_IGNORE: 499786Slclee break; 500786Slclee default: 501786Slclee cmn_err(CE_CONT, "^DEBUG: %s\t%s", name, cmlb_log_buffer); 502786Slclee break; 503786Slclee } 504786Slclee mutex_exit(&cmlb_log_mutex); 505786Slclee } 506786Slclee 507786Slclee 508786Slclee /* 509786Slclee * cmlb_alloc_handle: 510786Slclee * 511786Slclee * Allocates a handle. 512786Slclee * 513786Slclee * Arguments: 514786Slclee * cmlbhandlep pointer to handle 515786Slclee * 516786Slclee * Notes: 517786Slclee * Allocates a handle and stores the allocated handle in the area 518786Slclee * pointed to by cmlbhandlep 519786Slclee * 520786Slclee * Context: 521786Slclee * Kernel thread only (can sleep). 522786Slclee */ 523786Slclee void 524786Slclee cmlb_alloc_handle(cmlb_handle_t *cmlbhandlep) 525786Slclee { 5263525Sshidokht struct cmlb_lun *cl; 5273525Sshidokht 5283525Sshidokht cl = kmem_zalloc(sizeof (struct cmlb_lun), KM_SLEEP); 529786Slclee ASSERT(cmlbhandlep != NULL); 530786Slclee 5313525Sshidokht cl->cl_state = CMLB_INITED; 5323525Sshidokht cl->cl_def_labeltype = CMLB_LABEL_UNDEF; 5333525Sshidokht mutex_init(CMLB_MUTEX(cl), NULL, MUTEX_DRIVER, NULL); 5343525Sshidokht 5353525Sshidokht *cmlbhandlep = (cmlb_handle_t)(cl); 536786Slclee } 537786Slclee 538786Slclee /* 539786Slclee * cmlb_free_handle 540786Slclee * 541786Slclee * Frees handle. 542786Slclee * 543786Slclee * Arguments: 544786Slclee * cmlbhandlep pointer to handle 545786Slclee */ 546786Slclee void 547786Slclee cmlb_free_handle(cmlb_handle_t *cmlbhandlep) 548786Slclee { 5493525Sshidokht struct cmlb_lun *cl; 5503525Sshidokht 5513525Sshidokht cl = (struct cmlb_lun *)*cmlbhandlep; 5523525Sshidokht if (cl != NULL) { 5533525Sshidokht mutex_destroy(CMLB_MUTEX(cl)); 5543525Sshidokht kmem_free(cl, sizeof (struct cmlb_lun)); 555786Slclee } 556786Slclee 557786Slclee } 558786Slclee 559786Slclee /* 560786Slclee * cmlb_attach: 561786Slclee * 562786Slclee * Attach handle to device, create minor nodes for device. 563786Slclee * 564786Slclee * Arguments: 565786Slclee * devi pointer to device's dev_info structure. 566786Slclee * tgopsp pointer to array of functions cmlb can use to callback 567786Slclee * to target driver. 568786Slclee * 569786Slclee * device_type Peripheral device type as defined in 570786Slclee * scsi/generic/inquiry.h 571786Slclee * 572786Slclee * is_removable whether or not device is removable. 573786Slclee * 5743525Sshidokht * is_hotpluggable whether or not device is hotpluggable. 5753525Sshidokht * 576786Slclee * node_type minor node type (as used by ddi_create_minor_node) 577786Slclee * 578786Slclee * alter_behavior 579786Slclee * bit flags: 580786Slclee * 581786Slclee * CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT: create 582786Slclee * an alternate slice for the default label, if 583786Slclee * device type is DTYPE_DIRECT an architectures default 584786Slclee * label type is VTOC16. 585786Slclee * Otherwise alternate slice will no be created. 586786Slclee * 587786Slclee * 588786Slclee * CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8: report a default 589786Slclee * geometry and label for DKIOCGGEOM and DKIOCGVTOC 590786Slclee * on architecture with VTOC8 label types. 591786Slclee * 5923525Sshidokht * CMLB_OFF_BY_ONE: do the workaround for legacy off-by- 5933525Sshidokht * one bug in obtaining capacity (in sd): 5943525Sshidokht * SCSI READ_CAPACITY command returns the LBA number of the 5953525Sshidokht * last logical block, but sd once treated this number as 5963525Sshidokht * disks' capacity on x86 platform. And LBAs are addressed 5973525Sshidokht * based 0. So the last block was lost on x86 platform. 5983525Sshidokht * 5993525Sshidokht * Now, we remove this workaround. In order for present sd 6003525Sshidokht * driver to work with disks which are labeled/partitioned 6013525Sshidokht * via previous sd, we add workaround as follows: 6023525Sshidokht * 6033525Sshidokht * 1) Locate backup EFI label: cmlb searches the next to 6043525Sshidokht * last 6053525Sshidokht * block for backup EFI label. If fails, it will 6063525Sshidokht * turn to the last block for backup EFI label; 6073525Sshidokht * 6083525Sshidokht * 2) Clear backup EFI label: cmlb first search the last 6093525Sshidokht * block for backup EFI label, and will search the 6103525Sshidokht * next to last block only if failed for the last 6113525Sshidokht * block. 6123525Sshidokht * 6133525Sshidokht * 3) Calculate geometry:refer to cmlb_convert_geometry() 6143525Sshidokht * If capacity increasing by 1 causes disks' capacity 6157563SPrasad.Singamsetty@Sun.COM * to cross over the limits in geometry calculation, 6163525Sshidokht * geometry info will change. This will raise an issue: 6173525Sshidokht * In case that primary VTOC label is destroyed, format 6183525Sshidokht * commandline can restore it via backup VTOC labels. 6193525Sshidokht * And format locates backup VTOC labels by use of 6203525Sshidokht * geometry. So changing geometry will 6213525Sshidokht * prevent format from finding backup VTOC labels. To 6223525Sshidokht * eliminate this side effect for compatibility, 6233525Sshidokht * sd uses (capacity -1) to calculate geometry; 6243525Sshidokht * 6253525Sshidokht * 4) 1TB disks: some important data structures use 6263525Sshidokht * 32-bit signed long/int (for example, daddr_t), 6273525Sshidokht * so that sd doesn't support a disk with capacity 6283525Sshidokht * larger than 1TB on 32-bit platform. However, 6293525Sshidokht * for exactly 1TB disk, it was treated as (1T - 512)B 6303525Sshidokht * in the past, and could have valid Solaris 6313525Sshidokht * partitions. To workaround this, if an exactly 1TB 6323525Sshidokht * disk has Solaris fdisk partition, it will be allowed 6333525Sshidokht * to work with sd. 6343525Sshidokht * 6353525Sshidokht * 636786Slclee * 6375084Sjohnlev * CMLB_FAKE_LABEL_ONE_PARTITION: create s0 and s2 covering 6385084Sjohnlev * the entire disk, if there is no valid partition info. 6395084Sjohnlev * If there is a valid Solaris partition, s0 and s2 will 6405084Sjohnlev * only cover the entire Solaris partition. 6415084Sjohnlev * 6425084Sjohnlev * 643786Slclee * cmlbhandle cmlb handle associated with device 644786Slclee * 6453525Sshidokht * tg_cookie cookie from target driver to be passed back to target 6463525Sshidokht * driver when we call back to it through tg_ops. 6473525Sshidokht * 648786Slclee * Notes: 649786Slclee * Assumes a default label based on capacity for non-removable devices. 650786Slclee * If capacity > 1TB, EFI is assumed otherwise VTOC (default VTOC 651786Slclee * for the architecture). 652786Slclee * 653786Slclee * For removable devices, default label type is assumed to be VTOC 654786Slclee * type. Create minor nodes based on a default label type. 655786Slclee * Label on the media is not validated. 656786Slclee * minor number consists of: 657786Slclee * if _SUNOS_VTOC_8 is defined 658786Slclee * lowest 3 bits is taken as partition number 659786Slclee * the rest is instance number 660786Slclee * if _SUNOS_VTOC_16 is defined 661786Slclee * lowest 6 bits is taken as partition number 662786Slclee * the rest is instance number 663786Slclee * 664786Slclee * 665786Slclee * Return values: 666786Slclee * 0 Success 667786Slclee * ENXIO creating minor nodes failed. 6683525Sshidokht * EINVAL invalid arg, unsupported tg_ops version 669786Slclee */ 670786Slclee int 671786Slclee cmlb_attach(dev_info_t *devi, cmlb_tg_ops_t *tgopsp, int device_type, 6728863SEdward.Pilatowicz@Sun.COM boolean_t is_removable, boolean_t is_hotpluggable, char *node_type, 6733525Sshidokht int alter_behavior, cmlb_handle_t cmlbhandle, void *tg_cookie) 674786Slclee { 675786Slclee 6763525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 677786Slclee diskaddr_t cap; 678786Slclee int status; 679786Slclee 6808863SEdward.Pilatowicz@Sun.COM ASSERT(VALID_BOOLEAN(is_removable)); 6818863SEdward.Pilatowicz@Sun.COM ASSERT(VALID_BOOLEAN(is_hotpluggable)); 6828863SEdward.Pilatowicz@Sun.COM 6833525Sshidokht if (tgopsp->tg_version < TG_DK_OPS_VERSION_1) 6843525Sshidokht return (EINVAL); 6853525Sshidokht 6863525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 6873525Sshidokht 6883525Sshidokht CMLB_DEVINFO(cl) = devi; 6893525Sshidokht cl->cmlb_tg_ops = tgopsp; 6903525Sshidokht cl->cl_device_type = device_type; 6913525Sshidokht cl->cl_is_removable = is_removable; 6923525Sshidokht cl->cl_is_hotpluggable = is_hotpluggable; 6933525Sshidokht cl->cl_node_type = node_type; 6943525Sshidokht cl->cl_sys_blocksize = DEV_BSIZE; 6958863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE; 6963525Sshidokht cl->cl_def_labeltype = CMLB_LABEL_VTOC; 6973525Sshidokht cl->cl_alter_behavior = alter_behavior; 6983525Sshidokht cl->cl_reserved = -1; 6997563SPrasad.Singamsetty@Sun.COM cl->cl_msglog_flag |= CMLB_ALLOW_2TB_WARN; 70010021SSheshadri.Vasudevan@Sun.COM #if defined(__i386) || defined(__amd64) 70110021SSheshadri.Vasudevan@Sun.COM cl->cl_logical_drive_count = 0; 70210021SSheshadri.Vasudevan@Sun.COM #endif 7037563SPrasad.Singamsetty@Sun.COM 7048863SEdward.Pilatowicz@Sun.COM if (!is_removable) { 7053525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 7063525Sshidokht status = DK_TG_GETCAP(cl, &cap, tg_cookie); 7073525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 7087563SPrasad.Singamsetty@Sun.COM if (status == 0 && cap > CMLB_EXTVTOC_LIMIT) { 7097563SPrasad.Singamsetty@Sun.COM /* set default EFI if > 2TB */ 7103525Sshidokht cl->cl_def_labeltype = CMLB_LABEL_EFI; 711786Slclee } 712786Slclee } 713786Slclee 714786Slclee /* create minor nodes based on default label type */ 7153525Sshidokht cl->cl_last_labeltype = CMLB_LABEL_UNDEF; 7163525Sshidokht cl->cl_cur_labeltype = CMLB_LABEL_UNDEF; 7173525Sshidokht 7183525Sshidokht if (cmlb_create_minor_nodes(cl) != 0) { 7193525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 720786Slclee return (ENXIO); 721786Slclee } 722786Slclee 7237224Scth /* Define the dynamic properties for devinfo spapshots. */ 7247224Scth i_ddi_prop_dyn_driver_set(CMLB_DEVINFO(cl), cmlb_prop_dyn); 7257224Scth 7263525Sshidokht cl->cl_state = CMLB_ATTACHED; 7273525Sshidokht 7283525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 729786Slclee return (0); 730786Slclee } 731786Slclee 732786Slclee /* 733786Slclee * cmlb_detach: 734786Slclee * 735786Slclee * Invalidate in-core labeling data and remove all minor nodes for 736786Slclee * the device associate with handle. 737786Slclee * 738786Slclee * Arguments: 739786Slclee * cmlbhandle cmlb handle associated with device. 740786Slclee * 7413525Sshidokht * tg_cookie cookie from target driver to be passed back to target 7423525Sshidokht * driver when we call back to it through tg_ops. 7433525Sshidokht * 744786Slclee */ 7453525Sshidokht /*ARGSUSED1*/ 746786Slclee void 7473525Sshidokht cmlb_detach(cmlb_handle_t cmlbhandle, void *tg_cookie) 748786Slclee { 7493525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 7503525Sshidokht 7513525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 7523525Sshidokht cl->cl_def_labeltype = CMLB_LABEL_UNDEF; 7538863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE; 7543525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL); 7557224Scth i_ddi_prop_dyn_driver_set(CMLB_DEVINFO(cl), NULL); 7563525Sshidokht cl->cl_state = CMLB_INITED; 7573525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 758786Slclee } 759786Slclee 760786Slclee /* 761786Slclee * cmlb_validate: 762786Slclee * 763786Slclee * Validates label. 764786Slclee * 765786Slclee * Arguments 766786Slclee * cmlbhandle cmlb handle associated with device. 767786Slclee * 7683525Sshidokht * flags operation flags. used for verbosity control 7693525Sshidokht * 7703525Sshidokht * tg_cookie cookie from target driver to be passed back to target 7713525Sshidokht * driver when we call back to it through tg_ops. 7723525Sshidokht * 7733525Sshidokht * 774786Slclee * Notes: 775786Slclee * If new label type is different from the current, adjust minor nodes 776786Slclee * accordingly. 777786Slclee * 778786Slclee * Return values: 779786Slclee * 0 success 780786Slclee * Note: having fdisk but no solaris partition is assumed 781786Slclee * success. 782786Slclee * 783786Slclee * ENOMEM memory allocation failed 784786Slclee * EIO i/o errors during read or get capacity 785786Slclee * EACCESS reservation conflicts 786786Slclee * EINVAL label was corrupt, or no default label was assumed 787786Slclee * ENXIO invalid handle 788786Slclee */ 789786Slclee int 7903525Sshidokht cmlb_validate(cmlb_handle_t cmlbhandle, int flags, void *tg_cookie) 791786Slclee { 7923525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 793786Slclee int rval; 794786Slclee int ret = 0; 795786Slclee 796786Slclee /* 7973525Sshidokht * Temp work-around checking cl for NULL since there is a bug 798786Slclee * in sd_detach calling this routine from taskq_dispatch 799786Slclee * inited function. 800786Slclee */ 8013525Sshidokht if (cl == NULL) 802786Slclee return (ENXIO); 803786Slclee 8043525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 8053525Sshidokht if (cl->cl_state < CMLB_ATTACHED) { 8063525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 807786Slclee return (ENXIO); 808786Slclee } 809786Slclee 8108863SEdward.Pilatowicz@Sun.COM rval = cmlb_validate_geometry((struct cmlb_lun *)cmlbhandle, B_TRUE, 8113525Sshidokht flags, tg_cookie); 812786Slclee 813786Slclee if (rval == ENOTSUP) { 8148863SEdward.Pilatowicz@Sun.COM if (cl->cl_f_geometry_is_valid) { 8153525Sshidokht cl->cl_cur_labeltype = CMLB_LABEL_EFI; 816786Slclee ret = 0; 817786Slclee } else { 818786Slclee ret = EINVAL; 819786Slclee } 820786Slclee } else { 821786Slclee ret = rval; 822786Slclee if (ret == 0) 8233525Sshidokht cl->cl_cur_labeltype = CMLB_LABEL_VTOC; 824786Slclee } 825786Slclee 826786Slclee if (ret == 0) 8273525Sshidokht (void) cmlb_create_minor_nodes(cl); 8283525Sshidokht 8293525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 830786Slclee return (ret); 831786Slclee } 832786Slclee 833786Slclee /* 834786Slclee * cmlb_invalidate: 835786Slclee * Invalidate in core label data 836786Slclee * 837786Slclee * Arguments: 838786Slclee * cmlbhandle cmlb handle associated with device. 8393525Sshidokht * tg_cookie cookie from target driver to be passed back to target 8403525Sshidokht * driver when we call back to it through tg_ops. 841786Slclee */ 8423525Sshidokht /*ARGSUSED1*/ 843786Slclee void 8443525Sshidokht cmlb_invalidate(cmlb_handle_t cmlbhandle, void *tg_cookie) 845786Slclee { 8463525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 8473525Sshidokht 8483525Sshidokht if (cl == NULL) 849786Slclee return; 850786Slclee 8513525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 8528863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE; 8533525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 854786Slclee } 855786Slclee 856786Slclee /* 8573525Sshidokht * cmlb_is_valid 8583525Sshidokht * Get status on whether the incore label/geom data is valid 8593525Sshidokht * 8603525Sshidokht * Arguments: 8613525Sshidokht * cmlbhandle cmlb handle associated with device. 8623525Sshidokht * 8633525Sshidokht * Return values: 8648863SEdward.Pilatowicz@Sun.COM * B_TRUE if incore label/geom data is valid. 8658863SEdward.Pilatowicz@Sun.COM * B_FALSE otherwise. 8663525Sshidokht * 8673525Sshidokht */ 8683525Sshidokht 8693525Sshidokht 8708863SEdward.Pilatowicz@Sun.COM boolean_t 8713525Sshidokht cmlb_is_valid(cmlb_handle_t cmlbhandle) 8723525Sshidokht { 8733525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 8743525Sshidokht 8753525Sshidokht if (cmlbhandle == NULL) 8768863SEdward.Pilatowicz@Sun.COM return (B_FALSE); 8773525Sshidokht 8783525Sshidokht return (cl->cl_f_geometry_is_valid); 8793525Sshidokht 8803525Sshidokht } 8813525Sshidokht 8823525Sshidokht 8833525Sshidokht 8843525Sshidokht /* 885786Slclee * cmlb_close: 886786Slclee * 887786Slclee * Close the device, revert to a default label minor node for the device, 888786Slclee * if it is removable. 889786Slclee * 890786Slclee * Arguments: 891786Slclee * cmlbhandle cmlb handle associated with device. 892786Slclee * 8933525Sshidokht * tg_cookie cookie from target driver to be passed back to target 8943525Sshidokht * driver when we call back to it through tg_ops. 895786Slclee * Return values: 896786Slclee * 0 Success 897786Slclee * ENXIO Re-creating minor node failed. 898786Slclee */ 8993525Sshidokht /*ARGSUSED1*/ 900786Slclee int 9013525Sshidokht cmlb_close(cmlb_handle_t cmlbhandle, void *tg_cookie) 902786Slclee { 9033525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 9043525Sshidokht 9053525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 9068863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE; 907786Slclee 908786Slclee /* revert to default minor node for this device */ 9093525Sshidokht if (ISREMOVABLE(cl)) { 9103525Sshidokht cl->cl_cur_labeltype = CMLB_LABEL_UNDEF; 9113525Sshidokht (void) cmlb_create_minor_nodes(cl); 912786Slclee } 913786Slclee 9143525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 915786Slclee return (0); 916786Slclee } 917786Slclee 918786Slclee /* 919786Slclee * cmlb_get_devid_block: 920786Slclee * get the block number where device id is stored. 921786Slclee * 922786Slclee * Arguments: 923786Slclee * cmlbhandle cmlb handle associated with device. 924786Slclee * devidblockp pointer to block number. 9253525Sshidokht * tg_cookie cookie from target driver to be passed back to target 9263525Sshidokht * driver when we call back to it through tg_ops. 927786Slclee * 928786Slclee * Notes: 929786Slclee * It stores the block number of device id in the area pointed to 930786Slclee * by devidblockp. 931786Slclee * with the block number of device id. 932786Slclee * 933786Slclee * Return values: 934786Slclee * 0 success 935786Slclee * EINVAL device id does not apply to current label type. 936786Slclee */ 9373525Sshidokht /*ARGSUSED2*/ 938786Slclee int 9393525Sshidokht cmlb_get_devid_block(cmlb_handle_t cmlbhandle, diskaddr_t *devidblockp, 9403525Sshidokht void *tg_cookie) 941786Slclee { 942786Slclee daddr_t spc, blk, head, cyl; 9433525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 9443525Sshidokht 9453525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 9463525Sshidokht if (cl->cl_state < CMLB_ATTACHED) { 9473525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 9483525Sshidokht return (EINVAL); 9493525Sshidokht } 9503525Sshidokht 9518863SEdward.Pilatowicz@Sun.COM if ((!cl->cl_f_geometry_is_valid) || 9523525Sshidokht (cl->cl_solaris_size < DK_LABEL_LOC)) { 9533525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 954786Slclee return (EINVAL); 955786Slclee } 956786Slclee 9573525Sshidokht if (cl->cl_cur_labeltype == CMLB_LABEL_EFI) { 9583525Sshidokht if (cl->cl_reserved != -1) { 9593525Sshidokht blk = cl->cl_map[cl->cl_reserved].dkl_cylno; 9603525Sshidokht } else { 9613525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 9623525Sshidokht return (EINVAL); 9633525Sshidokht } 9643525Sshidokht } else { 9656513Sml40262 /* if the disk is unlabeled, don't write a devid to it */ 9667563SPrasad.Singamsetty@Sun.COM if (cl->cl_label_from_media != CMLB_LABEL_VTOC) { 9676513Sml40262 mutex_exit(CMLB_MUTEX(cl)); 9686513Sml40262 return (EINVAL); 9696513Sml40262 } 9706513Sml40262 971786Slclee /* this geometry doesn't allow us to write a devid */ 9723525Sshidokht if (cl->cl_g.dkg_acyl < 2) { 9733525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 974786Slclee return (EINVAL); 975786Slclee } 976786Slclee 977786Slclee /* 978786Slclee * Subtract 2 guarantees that the next to last cylinder 979786Slclee * is used 980786Slclee */ 9813525Sshidokht cyl = cl->cl_g.dkg_ncyl + cl->cl_g.dkg_acyl - 2; 9823525Sshidokht spc = cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect; 9833525Sshidokht head = cl->cl_g.dkg_nhead - 1; 9846513Sml40262 blk = cl->cl_solaris_offset + 9856513Sml40262 (cyl * (spc - cl->cl_g.dkg_apc)) + 9863525Sshidokht (head * cl->cl_g.dkg_nsect) + 1; 987786Slclee } 9883525Sshidokht 989786Slclee *devidblockp = blk; 9903525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 991786Slclee return (0); 992786Slclee } 993786Slclee 994786Slclee /* 995786Slclee * cmlb_partinfo: 996786Slclee * Get partition info for specified partition number. 997786Slclee * 998786Slclee * Arguments: 999786Slclee * cmlbhandle cmlb handle associated with device. 1000786Slclee * part partition number 1001786Slclee * nblocksp pointer to number of blocks 1002786Slclee * startblockp pointer to starting block 1003786Slclee * partnamep pointer to name of partition 1004786Slclee * tagp pointer to tag info 10053525Sshidokht * tg_cookie cookie from target driver to be passed back to target 10063525Sshidokht * driver when we call back to it through tg_ops. 1007786Slclee * 1008786Slclee * 1009786Slclee * Notes: 1010786Slclee * If in-core label is not valid, this functions tries to revalidate 1011786Slclee * the label. If label is valid, it stores the total number of blocks 1012786Slclee * in this partition in the area pointed to by nblocksp, starting 1013786Slclee * block number in area pointed to by startblockp, pointer to partition 1014786Slclee * name in area pointed to by partnamep, and tag value in area 1015786Slclee * pointed by tagp. 1016786Slclee * For EFI labels, tag value will be set to 0. 1017786Slclee * 1018786Slclee * For all nblocksp, startblockp and partnamep, tagp, a value of NULL 1019786Slclee * indicates the corresponding info is not requested. 1020786Slclee * 1021786Slclee * 1022786Slclee * Return values: 1023786Slclee * 0 success 1024786Slclee * EINVAL no valid label or requested partition number is invalid. 1025786Slclee * 1026786Slclee */ 1027786Slclee int 1028786Slclee cmlb_partinfo(cmlb_handle_t cmlbhandle, int part, diskaddr_t *nblocksp, 10293525Sshidokht diskaddr_t *startblockp, char **partnamep, uint16_t *tagp, void *tg_cookie) 1030786Slclee { 1031786Slclee 10323525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 1033786Slclee int rval; 103410021SSheshadri.Vasudevan@Sun.COM #if defined(__i386) || defined(__amd64) 103510021SSheshadri.Vasudevan@Sun.COM int ext_part; 103610021SSheshadri.Vasudevan@Sun.COM #endif 1037786Slclee 10383525Sshidokht ASSERT(cl != NULL); 10393525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 10403525Sshidokht if (cl->cl_state < CMLB_ATTACHED) { 10413525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 1042786Slclee return (EINVAL); 1043786Slclee } 1044786Slclee 1045786Slclee if (part < 0 || part >= MAXPART) { 1046786Slclee rval = EINVAL; 1047786Slclee } else { 10488863SEdward.Pilatowicz@Sun.COM if (!cl->cl_f_geometry_is_valid) 10498863SEdward.Pilatowicz@Sun.COM (void) cmlb_validate_geometry((struct cmlb_lun *)cl, 10508863SEdward.Pilatowicz@Sun.COM B_FALSE, 0, tg_cookie); 10513525Sshidokht 10527563SPrasad.Singamsetty@Sun.COM #if defined(_SUNOS_VTOC_16) 10538863SEdward.Pilatowicz@Sun.COM if (((!cl->cl_f_geometry_is_valid) || 10547563SPrasad.Singamsetty@Sun.COM (part < NDKMAP && cl->cl_solaris_size == 0)) && 10557563SPrasad.Singamsetty@Sun.COM (part != P0_RAW_DISK)) { 10567563SPrasad.Singamsetty@Sun.COM #else 10578863SEdward.Pilatowicz@Sun.COM if ((!cl->cl_f_geometry_is_valid) || 10583525Sshidokht (part < NDKMAP && cl->cl_solaris_size == 0)) { 10597563SPrasad.Singamsetty@Sun.COM #endif 1060786Slclee rval = EINVAL; 1061786Slclee } else { 1062786Slclee if (startblockp != NULL) 10633525Sshidokht *startblockp = (diskaddr_t)cl->cl_offset[part]; 1064786Slclee 1065786Slclee if (nblocksp != NULL) 1066786Slclee *nblocksp = (diskaddr_t) 10673525Sshidokht cl->cl_map[part].dkl_nblk; 1068786Slclee 1069786Slclee if (tagp != NULL) 10703525Sshidokht if (cl->cl_cur_labeltype == CMLB_LABEL_EFI) 1071786Slclee *tagp = V_UNASSIGNED; 1072786Slclee else 10733525Sshidokht *tagp = cl->cl_vtoc.v_part[part].p_tag; 1074786Slclee rval = 0; 1075786Slclee } 1076786Slclee 1077786Slclee /* consistent with behavior of sd for getting minor name */ 107810021SSheshadri.Vasudevan@Sun.COM if (partnamep != NULL) { 107910021SSheshadri.Vasudevan@Sun.COM #if defined(__i386) || defined(__amd64) 108010021SSheshadri.Vasudevan@Sun.COM #if defined(_FIRMWARE_NEEDS_FDISK) 108110021SSheshadri.Vasudevan@Sun.COM if (part > FDISK_P4) { 108210021SSheshadri.Vasudevan@Sun.COM ext_part = part-FDISK_P4-1; 108310021SSheshadri.Vasudevan@Sun.COM *partnamep = dk_ext_minor_data[ext_part].name; 108410021SSheshadri.Vasudevan@Sun.COM } else 108510021SSheshadri.Vasudevan@Sun.COM #endif 108610021SSheshadri.Vasudevan@Sun.COM #endif 1087786Slclee *partnamep = dk_minor_data[part].name; 108810021SSheshadri.Vasudevan@Sun.COM } 1089786Slclee 1090786Slclee } 1091786Slclee 10923525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 1093786Slclee return (rval); 1094786Slclee } 1095786Slclee 10966590Syl194034 /* 10976590Syl194034 * cmlb_efi_label_capacity: 10986590Syl194034 * Get capacity stored in EFI disk label. 10996590Syl194034 * 11006590Syl194034 * Arguments: 11016590Syl194034 * cmlbhandle cmlb handle associated with device. 11026590Syl194034 * capacity pointer to capacity stored in EFI disk label. 11036590Syl194034 * tg_cookie cookie from target driver to be passed back to target 11046590Syl194034 * driver when we call back to it through tg_ops. 11056590Syl194034 * 11066590Syl194034 * 11076590Syl194034 * Notes: 11086590Syl194034 * If in-core label is not valid, this functions tries to revalidate 11096590Syl194034 * the label. If label is valid and is an EFI label, it stores the capacity 11106590Syl194034 * in disk label in the area pointed to by capacity. 11116590Syl194034 * 11126590Syl194034 * 11136590Syl194034 * Return values: 11146590Syl194034 * 0 success 11156590Syl194034 * EINVAL no valid EFI label or capacity is NULL. 11166590Syl194034 * 11176590Syl194034 */ 11186590Syl194034 int 11196590Syl194034 cmlb_efi_label_capacity(cmlb_handle_t cmlbhandle, diskaddr_t *capacity, 11206590Syl194034 void *tg_cookie) 11216590Syl194034 { 11226590Syl194034 struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle; 11236590Syl194034 int rval; 11246590Syl194034 11256590Syl194034 ASSERT(cl != NULL); 11266590Syl194034 mutex_enter(CMLB_MUTEX(cl)); 11276590Syl194034 if (cl->cl_state < CMLB_ATTACHED) { 11286590Syl194034 mutex_exit(CMLB_MUTEX(cl)); 11296590Syl194034 return (EINVAL); 11306590Syl194034 } 11316590Syl194034 11328863SEdward.Pilatowicz@Sun.COM if (!cl->cl_f_geometry_is_valid) 11338863SEdward.Pilatowicz@Sun.COM (void) cmlb_validate_geometry((struct cmlb_lun *)cl, B_FALSE, 11346590Syl194034 0, tg_cookie); 11356590Syl194034 11368863SEdward.Pilatowicz@Sun.COM if ((!cl->cl_f_geometry_is_valid) || (capacity == NULL) || 11376590Syl194034 (cl->cl_cur_labeltype != CMLB_LABEL_EFI)) { 11386590Syl194034 rval = EINVAL; 11396590Syl194034 } else { 11406590Syl194034 *capacity = (diskaddr_t)cl->cl_map[WD_NODE].dkl_nblk; 11416590Syl194034 rval = 0; 11426590Syl194034 } 11436590Syl194034 11446590Syl194034 mutex_exit(CMLB_MUTEX(cl)); 11456590Syl194034 return (rval); 11466590Syl194034 } 11476590Syl194034 11483525Sshidokht /* Caller should make sure Test Unit Ready succeeds before calling this. */ 11493525Sshidokht /*ARGSUSED*/ 1150786Slclee int 1151786Slclee cmlb_ioctl(cmlb_handle_t cmlbhandle, dev_t dev, int cmd, intptr_t arg, 11523525Sshidokht int flag, cred_t *cred_p, int *rval_p, void *tg_cookie) 1153786Slclee { 1154786Slclee 1155786Slclee int err; 11563525Sshidokht struct cmlb_lun *cl; 11573525Sshidokht 11583525Sshidokht cl = (struct cmlb_lun *)cmlbhandle; 11593525Sshidokht 11603525Sshidokht ASSERT(cl != NULL); 11613525Sshidokht 11623525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 11633525Sshidokht if (cl->cl_state < CMLB_ATTACHED) { 11643525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 1165786Slclee return (EIO); 1166786Slclee } 1167786Slclee 1168786Slclee switch (cmd) { 11697563SPrasad.Singamsetty@Sun.COM case DKIOCSEXTVTOC: 11703525Sshidokht case DKIOCSGEOM: 1171786Slclee case DKIOCSETEFI: 1172786Slclee case DKIOCSMBOOT: 117310021SSheshadri.Vasudevan@Sun.COM #if defined(__i386) || defined(__amd64) 117410021SSheshadri.Vasudevan@Sun.COM case DKIOCSETEXTPART: 117510021SSheshadri.Vasudevan@Sun.COM #endif 1176786Slclee break; 11777563SPrasad.Singamsetty@Sun.COM case DKIOCSVTOC: 11787563SPrasad.Singamsetty@Sun.COM #if defined(__i386) || defined(__amd64) 11797563SPrasad.Singamsetty@Sun.COM case DKIOCPARTINFO: 11807563SPrasad.Singamsetty@Sun.COM #endif 11817563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) { 11827563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 11837563SPrasad.Singamsetty@Sun.COM return (EOVERFLOW); 11847563SPrasad.Singamsetty@Sun.COM } 11857563SPrasad.Singamsetty@Sun.COM break; 1186786Slclee default: 11877563SPrasad.Singamsetty@Sun.COM (void) cmlb_validate_geometry(cl, 1, CMLB_SILENT, 11883903Sshidokht tg_cookie); 11893525Sshidokht 11907563SPrasad.Singamsetty@Sun.COM switch (cmd) { 11917563SPrasad.Singamsetty@Sun.COM case DKIOCGVTOC: 11927563SPrasad.Singamsetty@Sun.COM case DKIOCGAPART: 11937563SPrasad.Singamsetty@Sun.COM case DKIOCSAPART: 11947563SPrasad.Singamsetty@Sun.COM 11957563SPrasad.Singamsetty@Sun.COM if (cl->cl_label_from_media == CMLB_LABEL_EFI) { 11967563SPrasad.Singamsetty@Sun.COM /* GPT label on disk */ 11977563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 11987563SPrasad.Singamsetty@Sun.COM return (ENOTSUP); 11997563SPrasad.Singamsetty@Sun.COM } else if 12007563SPrasad.Singamsetty@Sun.COM (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) { 12017563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 12027563SPrasad.Singamsetty@Sun.COM return (EOVERFLOW); 12037563SPrasad.Singamsetty@Sun.COM } 12047563SPrasad.Singamsetty@Sun.COM break; 12057563SPrasad.Singamsetty@Sun.COM 12067563SPrasad.Singamsetty@Sun.COM case DKIOCGGEOM: 12077563SPrasad.Singamsetty@Sun.COM if (cl->cl_label_from_media == CMLB_LABEL_EFI) { 12087563SPrasad.Singamsetty@Sun.COM /* GPT label on disk */ 12093525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 1210786Slclee return (ENOTSUP); 1211786Slclee } 12127563SPrasad.Singamsetty@Sun.COM break; 12137563SPrasad.Singamsetty@Sun.COM default: 12147563SPrasad.Singamsetty@Sun.COM break; 1215786Slclee } 1216786Slclee } 1217786Slclee 12183525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 1219786Slclee 1220786Slclee switch (cmd) { 1221786Slclee case DKIOCGGEOM: 12223525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGGEOM\n"); 12233525Sshidokht err = cmlb_dkio_get_geometry(cl, (caddr_t)arg, flag, tg_cookie); 1224786Slclee break; 1225786Slclee 1226786Slclee case DKIOCSGEOM: 12273525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSGEOM\n"); 12283525Sshidokht err = cmlb_dkio_set_geometry(cl, (caddr_t)arg, flag); 1229786Slclee break; 1230786Slclee 1231786Slclee case DKIOCGAPART: 12323525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGAPART\n"); 12333525Sshidokht err = cmlb_dkio_get_partition(cl, (caddr_t)arg, 12343525Sshidokht flag, tg_cookie); 1235786Slclee break; 1236786Slclee 1237786Slclee case DKIOCSAPART: 12383525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSAPART\n"); 12393525Sshidokht err = cmlb_dkio_set_partition(cl, (caddr_t)arg, flag); 1240786Slclee break; 1241786Slclee 1242786Slclee case DKIOCGVTOC: 12433525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGVTOC\n"); 12443525Sshidokht err = cmlb_dkio_get_vtoc(cl, (caddr_t)arg, flag, tg_cookie); 1245786Slclee break; 1246786Slclee 12477563SPrasad.Singamsetty@Sun.COM case DKIOCGEXTVTOC: 12487563SPrasad.Singamsetty@Sun.COM cmlb_dbg(CMLB_TRACE, cl, "DKIOCGVTOC\n"); 12497563SPrasad.Singamsetty@Sun.COM err = cmlb_dkio_get_extvtoc(cl, (caddr_t)arg, flag, tg_cookie); 12507563SPrasad.Singamsetty@Sun.COM break; 12517563SPrasad.Singamsetty@Sun.COM 1252786Slclee case DKIOCGETEFI: 12533525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGETEFI\n"); 12543525Sshidokht err = cmlb_dkio_get_efi(cl, (caddr_t)arg, flag, tg_cookie); 1255786Slclee break; 1256786Slclee 1257786Slclee case DKIOCPARTITION: 12583525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCPARTITION\n"); 12593525Sshidokht err = cmlb_dkio_partition(cl, (caddr_t)arg, flag, tg_cookie); 1260786Slclee break; 1261786Slclee 1262786Slclee case DKIOCSVTOC: 12633525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSVTOC\n"); 12643525Sshidokht err = cmlb_dkio_set_vtoc(cl, dev, (caddr_t)arg, flag, 12653525Sshidokht tg_cookie); 1266786Slclee break; 1267786Slclee 12687563SPrasad.Singamsetty@Sun.COM case DKIOCSEXTVTOC: 12697563SPrasad.Singamsetty@Sun.COM cmlb_dbg(CMLB_TRACE, cl, "DKIOCSVTOC\n"); 12707563SPrasad.Singamsetty@Sun.COM err = cmlb_dkio_set_extvtoc(cl, dev, (caddr_t)arg, flag, 12717563SPrasad.Singamsetty@Sun.COM tg_cookie); 12727563SPrasad.Singamsetty@Sun.COM break; 12737563SPrasad.Singamsetty@Sun.COM 1274786Slclee case DKIOCSETEFI: 12753525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSETEFI\n"); 12763525Sshidokht err = cmlb_dkio_set_efi(cl, dev, (caddr_t)arg, flag, tg_cookie); 1277786Slclee break; 1278786Slclee 1279786Slclee case DKIOCGMBOOT: 12803525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGMBOOT\n"); 12813525Sshidokht err = cmlb_dkio_get_mboot(cl, (caddr_t)arg, flag, tg_cookie); 1282786Slclee break; 1283786Slclee 1284786Slclee case DKIOCSMBOOT: 12853525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSMBOOT\n"); 12863525Sshidokht err = cmlb_dkio_set_mboot(cl, (caddr_t)arg, flag, tg_cookie); 1287786Slclee break; 1288786Slclee case DKIOCG_PHYGEOM: 12893525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCG_PHYGEOM\n"); 1290786Slclee #if defined(__i386) || defined(__amd64) 129110320SLarry.Liu@Sun.COM err = cmlb_dkio_get_phygeom(cl, (caddr_t)arg, flag, tg_cookie); 1292786Slclee #else 1293786Slclee err = ENOTTY; 1294786Slclee #endif 1295786Slclee break; 1296786Slclee case DKIOCG_VIRTGEOM: 12973525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCG_VIRTGEOM\n"); 1298786Slclee #if defined(__i386) || defined(__amd64) 12993525Sshidokht err = cmlb_dkio_get_virtgeom(cl, (caddr_t)arg, flag); 1300786Slclee #else 1301786Slclee err = ENOTTY; 1302786Slclee #endif 1303786Slclee break; 1304786Slclee case DKIOCPARTINFO: 13053525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCPARTINFO"); 1306786Slclee #if defined(__i386) || defined(__amd64) 13073525Sshidokht err = cmlb_dkio_partinfo(cl, dev, (caddr_t)arg, flag); 1308786Slclee #else 1309786Slclee err = ENOTTY; 1310786Slclee #endif 1311786Slclee break; 13127563SPrasad.Singamsetty@Sun.COM case DKIOCEXTPARTINFO: 13137563SPrasad.Singamsetty@Sun.COM cmlb_dbg(CMLB_TRACE, cl, "DKIOCPARTINFO"); 13147563SPrasad.Singamsetty@Sun.COM #if defined(__i386) || defined(__amd64) 13157563SPrasad.Singamsetty@Sun.COM err = cmlb_dkio_extpartinfo(cl, dev, (caddr_t)arg, flag); 13167563SPrasad.Singamsetty@Sun.COM #else 13177563SPrasad.Singamsetty@Sun.COM err = ENOTTY; 13187563SPrasad.Singamsetty@Sun.COM #endif 13197563SPrasad.Singamsetty@Sun.COM break; 132010021SSheshadri.Vasudevan@Sun.COM #if defined(__i386) || defined(__amd64) 132110021SSheshadri.Vasudevan@Sun.COM case DKIOCSETEXTPART: 132210021SSheshadri.Vasudevan@Sun.COM cmlb_dbg(CMLB_TRACE, cl, "DKIOCSETEXTPART"); 132310021SSheshadri.Vasudevan@Sun.COM err = cmlb_dkio_set_ext_part(cl, (caddr_t)arg, flag, tg_cookie); 132410021SSheshadri.Vasudevan@Sun.COM break; 132510021SSheshadri.Vasudevan@Sun.COM #endif 1326786Slclee default: 1327786Slclee err = ENOTTY; 1328786Slclee 1329786Slclee } 13307224Scth 13317224Scth /* 13327224Scth * An ioctl that succeeds and changed ('set') size(9P) information 13337224Scth * needs to invalidate the cached devinfo snapshot to avoid having 13347224Scth * old information being returned in a snapshots. 13357224Scth * 13367224Scth * NB: When available, call ddi_change_minor_node() to clear 13377224Scth * SSIZEVALID in specfs vnodes via spec_size_invalidate(). 13387224Scth */ 13397224Scth if (err == 0) { 13407224Scth switch (cmd) { 13417224Scth case DKIOCSGEOM: 13427224Scth case DKIOCSAPART: 13437224Scth case DKIOCSVTOC: 13447563SPrasad.Singamsetty@Sun.COM case DKIOCSEXTVTOC: 13457224Scth case DKIOCSETEFI: 13467224Scth i_ddi_prop_dyn_cache_invalidate(CMLB_DEVINFO(cl), 13477224Scth i_ddi_prop_dyn_driver_get(CMLB_DEVINFO(cl))); 13487224Scth } 13497224Scth } 1350786Slclee return (err); 1351786Slclee } 1352786Slclee 1353786Slclee dev_t 13543525Sshidokht cmlb_make_device(struct cmlb_lun *cl) 1355786Slclee { 13568459SJerry.Gilliam@Sun.COM return (makedevice(ddi_driver_major(CMLB_DEVINFO(cl)), 13573525Sshidokht ddi_get_instance(CMLB_DEVINFO(cl)) << CMLBUNIT_SHIFT)); 1358786Slclee } 1359786Slclee 1360786Slclee /* 1361786Slclee * Function: cmlb_check_update_blockcount 1362786Slclee * 1363786Slclee * Description: If current capacity value is invalid, obtains the 1364786Slclee * current capacity from target driver. 1365786Slclee * 1366786Slclee * Return Code: 0 success 1367786Slclee * EIO failure 1368786Slclee */ 1369786Slclee static int 13703525Sshidokht cmlb_check_update_blockcount(struct cmlb_lun *cl, void *tg_cookie) 1371786Slclee { 1372786Slclee int status; 1373786Slclee diskaddr_t capacity; 13743525Sshidokht uint32_t lbasize; 13753525Sshidokht 13763525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 13773525Sshidokht 13788863SEdward.Pilatowicz@Sun.COM if (cl->cl_f_geometry_is_valid) 13798863SEdward.Pilatowicz@Sun.COM return (0); 13808863SEdward.Pilatowicz@Sun.COM 13818863SEdward.Pilatowicz@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 13828863SEdward.Pilatowicz@Sun.COM status = DK_TG_GETCAP(cl, &capacity, tg_cookie); 13838863SEdward.Pilatowicz@Sun.COM if (status != 0) { 13843525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 13858863SEdward.Pilatowicz@Sun.COM return (EIO); 13868863SEdward.Pilatowicz@Sun.COM } 13878863SEdward.Pilatowicz@Sun.COM 13888863SEdward.Pilatowicz@Sun.COM status = DK_TG_GETBLOCKSIZE(cl, &lbasize, tg_cookie); 13898863SEdward.Pilatowicz@Sun.COM mutex_enter(CMLB_MUTEX(cl)); 13908863SEdward.Pilatowicz@Sun.COM if (status != 0) 13918863SEdward.Pilatowicz@Sun.COM return (EIO); 13928863SEdward.Pilatowicz@Sun.COM 13938863SEdward.Pilatowicz@Sun.COM if ((capacity != 0) && (lbasize != 0)) { 13948863SEdward.Pilatowicz@Sun.COM cl->cl_blockcount = capacity; 13958863SEdward.Pilatowicz@Sun.COM cl->cl_tgt_blocksize = lbasize; 13969889SLarry.Liu@Sun.COM if (!cl->cl_is_removable) { 13979889SLarry.Liu@Sun.COM cl->cl_sys_blocksize = lbasize; 13989889SLarry.Liu@Sun.COM } 1399786Slclee return (0); 14008863SEdward.Pilatowicz@Sun.COM } else { 14018863SEdward.Pilatowicz@Sun.COM return (EIO); 14028863SEdward.Pilatowicz@Sun.COM } 1403786Slclee } 1404786Slclee 14056318Sedp static int 14066318Sedp cmlb_create_minor(dev_info_t *dip, char *name, int spec_type, 14076318Sedp minor_t minor_num, char *node_type, int flag, boolean_t internal) 14086318Sedp { 14098863SEdward.Pilatowicz@Sun.COM ASSERT(VALID_BOOLEAN(internal)); 14108863SEdward.Pilatowicz@Sun.COM 14116318Sedp if (internal) 14126318Sedp return (ddi_create_internal_pathname(dip, 14136318Sedp name, spec_type, minor_num)); 14146318Sedp else 14156318Sedp return (ddi_create_minor_node(dip, 14166318Sedp name, spec_type, minor_num, node_type, flag)); 14176318Sedp } 14186318Sedp 1419786Slclee /* 1420786Slclee * Function: cmlb_create_minor_nodes 1421786Slclee * 1422786Slclee * Description: Create or adjust the minor device nodes for the instance. 1423786Slclee * Minor nodes are created based on default label type, 1424786Slclee * current label type and last label type we created 1425786Slclee * minor nodes based on. 1426786Slclee * 1427786Slclee * 14283525Sshidokht * Arguments: cl - driver soft state (unit) structure 1429786Slclee * 1430786Slclee * Return Code: 0 success 1431786Slclee * ENXIO failure. 1432786Slclee * 1433786Slclee * Context: Kernel thread context 1434786Slclee */ 1435786Slclee static int 14363525Sshidokht cmlb_create_minor_nodes(struct cmlb_lun *cl) 1437786Slclee { 1438786Slclee struct driver_minor_data *dmdp; 1439786Slclee int instance; 1440786Slclee char name[48]; 1441786Slclee cmlb_label_t newlabeltype; 14426318Sedp boolean_t internal; 1443786Slclee 14443525Sshidokht ASSERT(cl != NULL); 14453525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 1446786Slclee 14478863SEdward.Pilatowicz@Sun.COM internal = VOID2BOOLEAN( 14488863SEdward.Pilatowicz@Sun.COM (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0); 1449786Slclee 1450786Slclee /* check the most common case */ 14513525Sshidokht if (cl->cl_cur_labeltype != CMLB_LABEL_UNDEF && 14523525Sshidokht cl->cl_last_labeltype == cl->cl_cur_labeltype) { 1453786Slclee /* do nothing */ 1454786Slclee return (0); 1455786Slclee } 1456786Slclee 14573525Sshidokht if (cl->cl_def_labeltype == CMLB_LABEL_UNDEF) { 1458786Slclee /* we should never get here */ 1459786Slclee return (ENXIO); 1460786Slclee } 1461786Slclee 14623525Sshidokht if (cl->cl_last_labeltype == CMLB_LABEL_UNDEF) { 1463786Slclee /* first time during attach */ 14643525Sshidokht newlabeltype = cl->cl_def_labeltype; 14653525Sshidokht 14663525Sshidokht instance = ddi_get_instance(CMLB_DEVINFO(cl)); 1467786Slclee 1468786Slclee /* Create all the minor nodes for this target. */ 1469786Slclee dmdp = (newlabeltype == CMLB_LABEL_EFI) ? dk_minor_data_efi : 1470786Slclee dk_minor_data; 1471786Slclee while (dmdp->name != NULL) { 1472786Slclee 1473786Slclee (void) sprintf(name, "%s", dmdp->name); 1474786Slclee 14756318Sedp if (cmlb_create_minor(CMLB_DEVINFO(cl), name, 1476786Slclee dmdp->type, 1477786Slclee (instance << CMLBUNIT_SHIFT) | dmdp->minor, 14786318Sedp cl->cl_node_type, NULL, internal) == DDI_FAILURE) { 1479786Slclee /* 1480786Slclee * Clean up any nodes that may have been 1481786Slclee * created, in case this fails in the middle 1482786Slclee * of the loop. 1483786Slclee */ 14843525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL); 1485786Slclee return (ENXIO); 1486786Slclee } 1487786Slclee dmdp++; 1488786Slclee } 14893525Sshidokht cl->cl_last_labeltype = newlabeltype; 1490786Slclee return (0); 1491786Slclee } 1492786Slclee 1493786Slclee /* Not first time */ 14943525Sshidokht if (cl->cl_cur_labeltype == CMLB_LABEL_UNDEF) { 14953525Sshidokht if (cl->cl_last_labeltype != cl->cl_def_labeltype) { 1496786Slclee /* close time, revert to default. */ 14973525Sshidokht newlabeltype = cl->cl_def_labeltype; 1498786Slclee } else { 1499786Slclee /* 1500786Slclee * do nothing since the type for which we last created 1501786Slclee * nodes matches the default 1502786Slclee */ 1503786Slclee return (0); 1504786Slclee } 1505786Slclee } else { 15063525Sshidokht if (cl->cl_cur_labeltype != cl->cl_last_labeltype) { 1507786Slclee /* We are not closing, use current label type */ 15083525Sshidokht newlabeltype = cl->cl_cur_labeltype; 1509786Slclee } else { 1510786Slclee /* 1511786Slclee * do nothing since the type for which we last created 1512786Slclee * nodes matches the current label type 1513786Slclee */ 1514786Slclee return (0); 1515786Slclee } 1516786Slclee } 1517786Slclee 15183525Sshidokht instance = ddi_get_instance(CMLB_DEVINFO(cl)); 1519786Slclee 1520786Slclee /* 1521786Slclee * Currently we only fix up the s7 node when we are switching 1522786Slclee * label types from or to EFI. This is consistent with 1523786Slclee * current behavior of sd. 1524786Slclee */ 1525786Slclee if (newlabeltype == CMLB_LABEL_EFI && 15263525Sshidokht cl->cl_last_labeltype != CMLB_LABEL_EFI) { 1527786Slclee /* from vtoc to EFI */ 15283525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "h"); 15293525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw"); 15306318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd", 1531786Slclee S_IFBLK, (instance << CMLBUNIT_SHIFT) | WD_NODE, 15326318Sedp cl->cl_node_type, NULL, internal); 15336318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd,raw", 1534786Slclee S_IFCHR, (instance << CMLBUNIT_SHIFT) | WD_NODE, 15356318Sedp cl->cl_node_type, NULL, internal); 1536786Slclee } else { 1537786Slclee /* from efi to vtoc */ 15383525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd"); 15393525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd,raw"); 15406318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h", 1541786Slclee S_IFBLK, (instance << CMLBUNIT_SHIFT) | WD_NODE, 15426318Sedp cl->cl_node_type, NULL, internal); 15436318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h,raw", 1544786Slclee S_IFCHR, (instance << CMLBUNIT_SHIFT) | WD_NODE, 15456318Sedp cl->cl_node_type, NULL, internal); 1546786Slclee } 1547786Slclee 15483525Sshidokht cl->cl_last_labeltype = newlabeltype; 1549786Slclee return (0); 1550786Slclee } 1551786Slclee 1552786Slclee /* 1553786Slclee * Function: cmlb_validate_geometry 1554786Slclee * 1555786Slclee * Description: Read the label from the disk (if present). Update the unit's 1556786Slclee * geometry and vtoc information from the data in the label. 1557786Slclee * Verify that the label is valid. 1558786Slclee * 15593525Sshidokht * Arguments: 15603525Sshidokht * cl driver soft state (unit) structure 15613525Sshidokht * 15623525Sshidokht * forcerevalid force revalidation even if we are already valid. 15633525Sshidokht * flags operation flags from target driver. Used for verbosity 15643525Sshidokht * control at this time. 15653525Sshidokht * tg_cookie cookie from target driver to be passed back to target 15663525Sshidokht * driver when we call back to it through tg_ops. 1567786Slclee * 1568786Slclee * Return Code: 0 - Successful completion 15693525Sshidokht * EINVAL - Invalid value in cl->cl_tgt_blocksize or 15703525Sshidokht * cl->cl_blockcount; or label on disk is corrupted 1571786Slclee * or unreadable. 1572786Slclee * EACCES - Reservation conflict at the device. 1573786Slclee * ENOMEM - Resource allocation error 1574786Slclee * ENOTSUP - geometry not applicable 1575786Slclee * 1576786Slclee * Context: Kernel thread only (can sleep). 1577786Slclee */ 1578786Slclee static int 15798863SEdward.Pilatowicz@Sun.COM cmlb_validate_geometry(struct cmlb_lun *cl, boolean_t forcerevalid, int flags, 15803525Sshidokht void *tg_cookie) 1581786Slclee { 1582786Slclee int label_error = 0; 1583786Slclee diskaddr_t capacity; 1584786Slclee int count; 15853525Sshidokht 15863525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 15878863SEdward.Pilatowicz@Sun.COM ASSERT(VALID_BOOLEAN(forcerevalid)); 15888863SEdward.Pilatowicz@Sun.COM 15898863SEdward.Pilatowicz@Sun.COM if ((cl->cl_f_geometry_is_valid) && (!forcerevalid)) { 15903525Sshidokht if (cl->cl_cur_labeltype == CMLB_LABEL_EFI) 1591786Slclee return (ENOTSUP); 1592786Slclee return (0); 1593786Slclee } 1594786Slclee 15953525Sshidokht if (cmlb_check_update_blockcount(cl, tg_cookie) != 0) 1596786Slclee return (EIO); 1597786Slclee 15983525Sshidokht capacity = cl->cl_blockcount; 1599786Slclee 1600786Slclee #if defined(_SUNOS_VTOC_16) 1601786Slclee /* 1602786Slclee * Set up the "whole disk" fdisk partition; this should always 1603786Slclee * exist, regardless of whether the disk contains an fdisk table 1604786Slclee * or vtoc. 1605786Slclee */ 16063525Sshidokht cl->cl_map[P0_RAW_DISK].dkl_cylno = 0; 16077563SPrasad.Singamsetty@Sun.COM cl->cl_offset[P0_RAW_DISK] = 0; 1608786Slclee /* 16097563SPrasad.Singamsetty@Sun.COM * note if capacity > int32_max(1TB) we are in 64bit environment 16107563SPrasad.Singamsetty@Sun.COM * so no truncation happens 1611786Slclee */ 16123525Sshidokht cl->cl_map[P0_RAW_DISK].dkl_nblk = capacity; 1613786Slclee #endif 1614786Slclee /* 1615786Slclee * Refresh the logical and physical geometry caches. 1616786Slclee * (data from MODE SENSE format/rigid disk geometry pages, 1617786Slclee * and scsi_ifgetcap("geometry"). 1618786Slclee */ 16193525Sshidokht cmlb_resync_geom_caches(cl, capacity, tg_cookie); 16203525Sshidokht 16217563SPrasad.Singamsetty@Sun.COM cl->cl_label_from_media = CMLB_LABEL_UNDEF; 16223525Sshidokht label_error = cmlb_use_efi(cl, capacity, flags, tg_cookie); 1623786Slclee if (label_error == 0) { 1624786Slclee 1625786Slclee /* found a valid EFI label */ 16263525Sshidokht cmlb_dbg(CMLB_TRACE, cl, 1627786Slclee "cmlb_validate_geometry: found EFI label\n"); 1628786Slclee /* 1629786Slclee * solaris_size and geometry_is_valid are set in 1630786Slclee * cmlb_use_efi 1631786Slclee */ 1632786Slclee return (ENOTSUP); 1633786Slclee } 1634786Slclee 1635786Slclee /* NO EFI label found */ 1636786Slclee 16377563SPrasad.Singamsetty@Sun.COM if (capacity > CMLB_EXTVTOC_LIMIT) { 1638786Slclee if (label_error == ESRCH) { 1639786Slclee /* 16407563SPrasad.Singamsetty@Sun.COM * they've configured a LUN over 2TB, but used 1641786Slclee * format.dat to restrict format's view of the 16427563SPrasad.Singamsetty@Sun.COM * capacity to be under 2TB in some earlier Solaris 16437563SPrasad.Singamsetty@Sun.COM * release. 1644786Slclee */ 16457563SPrasad.Singamsetty@Sun.COM /* i.e > 2TB with a VTOC < 2TB */ 16467563SPrasad.Singamsetty@Sun.COM if (!(flags & CMLB_SILENT) && 16477563SPrasad.Singamsetty@Sun.COM (cl->cl_msglog_flag & CMLB_ALLOW_2TB_WARN)) { 16483525Sshidokht 16493525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), 16507563SPrasad.Singamsetty@Sun.COM CE_NOTE, "!Disk (%s%d) is limited to 2 TB " 16517563SPrasad.Singamsetty@Sun.COM "due to VTOC label. To use the full " 16527563SPrasad.Singamsetty@Sun.COM "capacity of the disk, use format(1M) to " 16537563SPrasad.Singamsetty@Sun.COM "relabel the disk with EFI/GPT label.\n", 16547563SPrasad.Singamsetty@Sun.COM CMLB_LABEL(cl), 16557563SPrasad.Singamsetty@Sun.COM ddi_get_instance(CMLB_DEVINFO(cl))); 16567563SPrasad.Singamsetty@Sun.COM 16577563SPrasad.Singamsetty@Sun.COM cl->cl_msglog_flag &= ~CMLB_ALLOW_2TB_WARN; 16583525Sshidokht } 1659786Slclee } else { 16603525Sshidokht return (ENOTSUP); 1661786Slclee } 1662786Slclee } 1663786Slclee 1664786Slclee label_error = 0; 1665786Slclee 1666786Slclee /* 1667786Slclee * at this point it is either labeled with a VTOC or it is 16683525Sshidokht * under 1TB (<= 1TB actually for off-by-1) 1669786Slclee */ 1670786Slclee 1671786Slclee /* 16723525Sshidokht * Only DIRECT ACCESS devices will have Scl labels. 16733525Sshidokht * CD's supposedly have a Scl label, too 1674786Slclee */ 16753525Sshidokht if (cl->cl_device_type == DTYPE_DIRECT || ISREMOVABLE(cl)) { 1676786Slclee struct dk_label *dkl; 1677786Slclee offset_t label_addr; 1678786Slclee int rval; 1679786Slclee size_t buffer_size; 1680786Slclee 1681786Slclee /* 16823525Sshidokht * Note: This will set up cl->cl_solaris_size and 16833525Sshidokht * cl->cl_solaris_offset. 1684786Slclee */ 16853525Sshidokht rval = cmlb_read_fdisk(cl, capacity, tg_cookie); 16863525Sshidokht if ((rval != 0) && !ISCD(cl)) { 16873525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 1688786Slclee return (rval); 1689786Slclee } 1690786Slclee 16913525Sshidokht if (cl->cl_solaris_size <= DK_LABEL_LOC) { 1692786Slclee /* 1693786Slclee * Found fdisk table but no Solaris partition entry, 1694786Slclee * so don't call cmlb_uselabel() and don't create 1695786Slclee * a default label. 1696786Slclee */ 1697786Slclee label_error = 0; 16988863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_TRUE; 1699786Slclee goto no_solaris_partition; 1700786Slclee } 1701786Slclee 17023525Sshidokht label_addr = (daddr_t)(cl->cl_solaris_offset + DK_LABEL_LOC); 17033525Sshidokht 17049889SLarry.Liu@Sun.COM buffer_size = cl->cl_sys_blocksize; 1705786Slclee 17063525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "cmlb_validate_geometry: " 1707786Slclee "label_addr: 0x%x allocation size: 0x%x\n", 1708786Slclee label_addr, buffer_size); 1709786Slclee 1710786Slclee if ((dkl = kmem_zalloc(buffer_size, KM_NOSLEEP)) == NULL) 1711786Slclee return (ENOMEM); 1712786Slclee 17133525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 17143525Sshidokht rval = DK_TG_READ(cl, dkl, label_addr, buffer_size, tg_cookie); 17153525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 1716786Slclee 1717786Slclee switch (rval) { 1718786Slclee case 0: 1719786Slclee /* 1720786Slclee * cmlb_uselabel will establish that the geometry 1721786Slclee * is valid. 1722786Slclee */ 17233525Sshidokht if (cmlb_uselabel(cl, 17243525Sshidokht (struct dk_label *)(uintptr_t)dkl, flags) != 1725786Slclee CMLB_LABEL_IS_VALID) { 1726786Slclee label_error = EINVAL; 1727786Slclee } else 17287563SPrasad.Singamsetty@Sun.COM cl->cl_label_from_media = CMLB_LABEL_VTOC; 1729786Slclee break; 1730786Slclee case EACCES: 1731786Slclee label_error = EACCES; 1732786Slclee break; 1733786Slclee default: 1734786Slclee label_error = EINVAL; 1735786Slclee break; 1736786Slclee } 1737786Slclee 1738786Slclee kmem_free(dkl, buffer_size); 1739786Slclee } 1740786Slclee 1741786Slclee /* 1742786Slclee * If a valid label was not found, AND if no reservation conflict 1743786Slclee * was detected, then go ahead and create a default label (4069506). 1744786Slclee * 1745786Slclee * Note: currently, for VTOC_8 devices, the default label is created 17463525Sshidokht * for removables and hotpluggables only. For VTOC_16 devices, the 17473525Sshidokht * default label will be created for all devices. 1748786Slclee * (see cmlb_build_default_label) 1749786Slclee */ 1750786Slclee #if defined(_SUNOS_VTOC_8) 17513525Sshidokht if ((ISREMOVABLE(cl) || ISHOTPLUGGABLE(cl)) && 17523525Sshidokht (label_error != EACCES)) { 1753786Slclee #elif defined(_SUNOS_VTOC_16) 1754786Slclee if (label_error != EACCES) { 1755786Slclee #endif 17568863SEdward.Pilatowicz@Sun.COM if (!cl->cl_f_geometry_is_valid) { 17573525Sshidokht cmlb_build_default_label(cl, tg_cookie); 1758786Slclee } 1759786Slclee label_error = 0; 1760786Slclee } 1761786Slclee 1762786Slclee no_solaris_partition: 1763786Slclee 1764786Slclee #if defined(_SUNOS_VTOC_16) 1765786Slclee /* 1766786Slclee * If we have valid geometry, set up the remaining fdisk partitions. 1767786Slclee * Note that dkl_cylno is not used for the fdisk map entries, so 1768786Slclee * we set it to an entirely bogus value. 1769786Slclee */ 177010021SSheshadri.Vasudevan@Sun.COM for (count = 0; count < FDISK_PARTS; count++) { 17717563SPrasad.Singamsetty@Sun.COM cl->cl_map[FDISK_P1 + count].dkl_cylno = UINT16_MAX; 17723525Sshidokht cl->cl_map[FDISK_P1 + count].dkl_nblk = 17733525Sshidokht cl->cl_fmap[count].fmap_nblk; 17743525Sshidokht 17753525Sshidokht cl->cl_offset[FDISK_P1 + count] = 17763525Sshidokht cl->cl_fmap[count].fmap_start; 1777786Slclee } 1778786Slclee #endif 1779786Slclee 1780786Slclee for (count = 0; count < NDKMAP; count++) { 1781786Slclee #if defined(_SUNOS_VTOC_8) 17823525Sshidokht struct dk_map *lp = &cl->cl_map[count]; 17833525Sshidokht cl->cl_offset[count] = 17843525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno; 1785786Slclee #elif defined(_SUNOS_VTOC_16) 17863525Sshidokht struct dkl_partition *vp = &cl->cl_vtoc.v_part[count]; 17873525Sshidokht 17883525Sshidokht cl->cl_offset[count] = vp->p_start + cl->cl_solaris_offset; 1789786Slclee #else 1790786Slclee #error "No VTOC format defined." 1791786Slclee #endif 1792786Slclee } 1793786Slclee 1794786Slclee return (label_error); 1795786Slclee } 1796786Slclee 1797786Slclee #if defined(_SUNOS_VTOC_16) 1798786Slclee /* 1799786Slclee * Function: cmlb_convert_geometry 1800786Slclee * 1801786Slclee * Description: Convert physical geometry into a dk_geom structure. In 1802786Slclee * other words, make sure we don't wrap 16-bit values. 1803786Slclee * e.g. converting from geom_cache to dk_geom 1804786Slclee * 1805786Slclee * Context: Kernel thread only 1806786Slclee */ 1807786Slclee static void 180810320SLarry.Liu@Sun.COM cmlb_convert_geometry(struct cmlb_lun *cl, diskaddr_t capacity, 180910320SLarry.Liu@Sun.COM struct dk_geom *cl_g, void *tg_cookie) 1810786Slclee { 1811786Slclee 181210320SLarry.Liu@Sun.COM ASSERT(cl != NULL); 181310320SLarry.Liu@Sun.COM ASSERT(mutex_owned(CMLB_MUTEX(cl))); 181410320SLarry.Liu@Sun.COM 1815786Slclee /* Unlabeled SCSI floppy device */ 1816786Slclee if (capacity <= 0x1000) { 18173525Sshidokht cl_g->dkg_nhead = 2; 18183525Sshidokht cl_g->dkg_ncyl = 80; 18193525Sshidokht cl_g->dkg_nsect = capacity / (cl_g->dkg_nhead * cl_g->dkg_ncyl); 1820786Slclee return; 1821786Slclee } 1822786Slclee 1823786Slclee /* 18247563SPrasad.Singamsetty@Sun.COM * For all devices we calculate cylinders using the heads and sectors 18257563SPrasad.Singamsetty@Sun.COM * we assign based on capacity of the device. The algorithm is 18267563SPrasad.Singamsetty@Sun.COM * designed to be compatible with the way other operating systems 18277563SPrasad.Singamsetty@Sun.COM * lay out fdisk tables for X86 and to insure that the cylinders never 18287563SPrasad.Singamsetty@Sun.COM * exceed 65535 to prevent problems with X86 ioctls that report 18297563SPrasad.Singamsetty@Sun.COM * geometry. 18307563SPrasad.Singamsetty@Sun.COM * For some smaller disk sizes we report geometry that matches those 18317563SPrasad.Singamsetty@Sun.COM * used by X86 BIOS usage. For larger disks, we use SPT that are 18327563SPrasad.Singamsetty@Sun.COM * multiples of 63, since other OSes that are not limited to 16-bits 18337563SPrasad.Singamsetty@Sun.COM * for cylinders stop at 63 SPT we make do by using multiples of 63 SPT. 18347563SPrasad.Singamsetty@Sun.COM * 18357563SPrasad.Singamsetty@Sun.COM * The following table (in order) illustrates some end result 18367563SPrasad.Singamsetty@Sun.COM * calculations: 18377563SPrasad.Singamsetty@Sun.COM * 18387563SPrasad.Singamsetty@Sun.COM * Maximum number of blocks nhead nsect 1839786Slclee * 18407563SPrasad.Singamsetty@Sun.COM * 2097152 (1GB) 64 32 18417563SPrasad.Singamsetty@Sun.COM * 16777216 (8GB) 128 32 18427563SPrasad.Singamsetty@Sun.COM * 1052819775 (502.02GB) 255 63 18437563SPrasad.Singamsetty@Sun.COM * 2105639550 (0.98TB) 255 126 18447563SPrasad.Singamsetty@Sun.COM * 3158459325 (1.47TB) 255 189 18457563SPrasad.Singamsetty@Sun.COM * 4211279100 (1.96TB) 255 252 18467563SPrasad.Singamsetty@Sun.COM * 5264098875 (2.45TB) 255 315 18477563SPrasad.Singamsetty@Sun.COM * ... 184810320SLarry.Liu@Sun.COM * 184910320SLarry.Liu@Sun.COM * For Solid State Drive(SSD), it uses 4K page size inside and may be 185010320SLarry.Liu@Sun.COM * double with every new generation. If the I/O is not aligned with 185110320SLarry.Liu@Sun.COM * page size on SSDs, SSDs perform a lot slower. 185210320SLarry.Liu@Sun.COM * By default, Solaris partition starts from cylinder 1. It will be 185310320SLarry.Liu@Sun.COM * misaligned even with 4K if using heads(255) and SPT(63). To 185410320SLarry.Liu@Sun.COM * workaround the problem, if the device is SSD, we use heads(224) and 185510320SLarry.Liu@Sun.COM * SPT multiple of 56. Thus the default Solaris partition starts from 185610320SLarry.Liu@Sun.COM * a position that aligns with 128K on a 512 bytes sector size SSD. 1857786Slclee */ 18587563SPrasad.Singamsetty@Sun.COM 18597563SPrasad.Singamsetty@Sun.COM if (capacity <= 0x200000) { 18607563SPrasad.Singamsetty@Sun.COM cl_g->dkg_nhead = 64; 18617563SPrasad.Singamsetty@Sun.COM cl_g->dkg_nsect = 32; 18627563SPrasad.Singamsetty@Sun.COM } else if (capacity <= 0x01000000) { 18637563SPrasad.Singamsetty@Sun.COM cl_g->dkg_nhead = 128; 18647563SPrasad.Singamsetty@Sun.COM cl_g->dkg_nsect = 32; 18657563SPrasad.Singamsetty@Sun.COM } else { 186610320SLarry.Liu@Sun.COM tg_attribute_t tgattribute; 186710320SLarry.Liu@Sun.COM int is_solid_state; 186810320SLarry.Liu@Sun.COM unsigned short nhead; 186910320SLarry.Liu@Sun.COM unsigned short nsect; 187010320SLarry.Liu@Sun.COM 187110320SLarry.Liu@Sun.COM bzero(&tgattribute, sizeof (tg_attribute_t)); 187210320SLarry.Liu@Sun.COM 187310320SLarry.Liu@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 187410320SLarry.Liu@Sun.COM is_solid_state = 187510320SLarry.Liu@Sun.COM (DK_TG_GETATTRIBUTE(cl, &tgattribute, tg_cookie) == 0) ? 187610320SLarry.Liu@Sun.COM tgattribute.media_is_solid_state : FALSE; 187710320SLarry.Liu@Sun.COM mutex_enter(CMLB_MUTEX(cl)); 187810320SLarry.Liu@Sun.COM 187910320SLarry.Liu@Sun.COM if (is_solid_state) { 188010320SLarry.Liu@Sun.COM nhead = 224; 188110320SLarry.Liu@Sun.COM nsect = 56; 188210320SLarry.Liu@Sun.COM } else { 188310320SLarry.Liu@Sun.COM nhead = 255; 188410320SLarry.Liu@Sun.COM nsect = 63; 188510320SLarry.Liu@Sun.COM } 188610320SLarry.Liu@Sun.COM 188710320SLarry.Liu@Sun.COM cl_g->dkg_nhead = nhead; 188810320SLarry.Liu@Sun.COM 188910320SLarry.Liu@Sun.COM /* make nsect be smallest multiple of nhead */ 18907563SPrasad.Singamsetty@Sun.COM cl_g->dkg_nsect = ((capacity + 189110320SLarry.Liu@Sun.COM (UINT16_MAX * nhead * nsect) - 1) / 189210320SLarry.Liu@Sun.COM (UINT16_MAX * nhead * nsect)) * nsect; 18937563SPrasad.Singamsetty@Sun.COM 18947563SPrasad.Singamsetty@Sun.COM if (cl_g->dkg_nsect == 0) 189510320SLarry.Liu@Sun.COM cl_g->dkg_nsect = (UINT16_MAX / nsect) * nsect; 18967563SPrasad.Singamsetty@Sun.COM } 18977563SPrasad.Singamsetty@Sun.COM 1898786Slclee } 1899786Slclee #endif 1900786Slclee 1901786Slclee /* 1902786Slclee * Function: cmlb_resync_geom_caches 1903786Slclee * 1904786Slclee * Description: (Re)initialize both geometry caches: the virtual geometry 1905786Slclee * information is extracted from the HBA (the "geometry" 1906786Slclee * capability), and the physical geometry cache data is 1907786Slclee * generated by issuing MODE SENSE commands. 1908786Slclee * 19093525Sshidokht * Arguments: 19103525Sshidokht * cl driver soft state (unit) structure 19113525Sshidokht * capacity disk capacity in #blocks 19123525Sshidokht * tg_cookie cookie from target driver to be passed back to target 19133525Sshidokht * driver when we call back to it through tg_ops. 1914786Slclee * 1915786Slclee * Context: Kernel thread only (can sleep). 1916786Slclee */ 1917786Slclee static void 19183525Sshidokht cmlb_resync_geom_caches(struct cmlb_lun *cl, diskaddr_t capacity, 19193525Sshidokht void *tg_cookie) 1920786Slclee { 1921786Slclee struct cmlb_geom pgeom; 1922786Slclee struct cmlb_geom lgeom; 1923786Slclee struct cmlb_geom *pgeomp = &pgeom; 1924786Slclee unsigned short nhead; 1925786Slclee unsigned short nsect; 1926786Slclee int spc; 1927786Slclee int ret; 1928786Slclee 19293525Sshidokht ASSERT(cl != NULL); 19303525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 1931786Slclee 1932786Slclee /* 1933786Slclee * Ask the controller for its logical geometry. 1934786Slclee * Note: if the HBA does not support scsi_ifgetcap("geometry"), 1935786Slclee * then the lgeom cache will be invalid. 1936786Slclee */ 19373525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 1938786Slclee bzero(&lgeom, sizeof (struct cmlb_geom)); 19393525Sshidokht ret = DK_TG_GETVIRTGEOM(cl, &lgeom, tg_cookie); 19403525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 19413525Sshidokht 19423525Sshidokht bcopy(&lgeom, &cl->cl_lgeom, sizeof (cl->cl_lgeom)); 1943786Slclee 1944786Slclee /* 1945786Slclee * Initialize the pgeom cache from lgeom, so that if MODE SENSE 1946786Slclee * doesn't work, DKIOCG_PHYSGEOM can return reasonable values. 1947786Slclee */ 19483525Sshidokht if (ret != 0 || cl->cl_lgeom.g_nsect == 0 || 19493525Sshidokht cl->cl_lgeom.g_nhead == 0) { 1950786Slclee /* 1951786Slclee * Note: Perhaps this needs to be more adaptive? The rationale 1952786Slclee * is that, if there's no HBA geometry from the HBA driver, any 1953786Slclee * guess is good, since this is the physical geometry. If MODE 1954786Slclee * SENSE fails this gives a max cylinder size for non-LBA access 1955786Slclee */ 1956786Slclee nhead = 255; 1957786Slclee nsect = 63; 1958786Slclee } else { 19593525Sshidokht nhead = cl->cl_lgeom.g_nhead; 19603525Sshidokht nsect = cl->cl_lgeom.g_nsect; 1961786Slclee } 1962786Slclee 19633525Sshidokht if (ISCD(cl)) { 1964786Slclee pgeomp->g_nhead = 1; 1965786Slclee pgeomp->g_nsect = nsect * nhead; 1966786Slclee } else { 1967786Slclee pgeomp->g_nhead = nhead; 1968786Slclee pgeomp->g_nsect = nsect; 1969786Slclee } 1970786Slclee 1971786Slclee spc = pgeomp->g_nhead * pgeomp->g_nsect; 1972786Slclee pgeomp->g_capacity = capacity; 19739811SSheshadri.Vasudevan@Sun.COM if (spc == 0) 19749811SSheshadri.Vasudevan@Sun.COM pgeomp->g_ncyl = 0; 19759811SSheshadri.Vasudevan@Sun.COM else 19769811SSheshadri.Vasudevan@Sun.COM pgeomp->g_ncyl = pgeomp->g_capacity / spc; 1977786Slclee pgeomp->g_acyl = 0; 1978786Slclee 1979786Slclee /* 1980786Slclee * Retrieve fresh geometry data from the hardware, stash it 1981786Slclee * here temporarily before we rebuild the incore label. 1982786Slclee * 1983786Slclee * We want to use the MODE SENSE commands to derive the 1984786Slclee * physical geometry of the device, but if either command 1985786Slclee * fails, the logical geometry is used as the fallback for 1986786Slclee * disk label geometry. 1987786Slclee */ 1988786Slclee 19893525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 19903525Sshidokht (void) DK_TG_GETPHYGEOM(cl, pgeomp, tg_cookie); 19913525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 1992786Slclee 1993786Slclee /* 1994786Slclee * Now update the real copy while holding the mutex. This 1995786Slclee * way the global copy is never in an inconsistent state. 1996786Slclee */ 19973525Sshidokht bcopy(pgeomp, &cl->cl_pgeom, sizeof (cl->cl_pgeom)); 19983525Sshidokht 19993525Sshidokht cmlb_dbg(CMLB_INFO, cl, "cmlb_resync_geom_caches: " 2000786Slclee "(cached from lgeom)\n"); 20013525Sshidokht cmlb_dbg(CMLB_INFO, cl, 2002786Slclee " ncyl: %ld; acyl: %d; nhead: %d; nsect: %d\n", 20033525Sshidokht cl->cl_pgeom.g_ncyl, cl->cl_pgeom.g_acyl, 20043525Sshidokht cl->cl_pgeom.g_nhead, cl->cl_pgeom.g_nsect); 20053525Sshidokht cmlb_dbg(CMLB_INFO, cl, " lbasize: %d; capacity: %ld; " 20063525Sshidokht "intrlv: %d; rpm: %d\n", cl->cl_pgeom.g_secsize, 20073525Sshidokht cl->cl_pgeom.g_capacity, cl->cl_pgeom.g_intrlv, 20083525Sshidokht cl->cl_pgeom.g_rpm); 2009786Slclee } 2010786Slclee 2011786Slclee 201210021SSheshadri.Vasudevan@Sun.COM #if defined(__i386) || defined(__amd64) 201310021SSheshadri.Vasudevan@Sun.COM /* 201410021SSheshadri.Vasudevan@Sun.COM * Function: cmlb_update_ext_minor_nodes 201510021SSheshadri.Vasudevan@Sun.COM * 201610021SSheshadri.Vasudevan@Sun.COM * Description: Routine to add/remove extended partition device nodes 201710021SSheshadri.Vasudevan@Sun.COM * 201810021SSheshadri.Vasudevan@Sun.COM * Arguments: 201910021SSheshadri.Vasudevan@Sun.COM * cl driver soft state (unit) structure 202010021SSheshadri.Vasudevan@Sun.COM * num_parts Number of logical drives found on the LUN 202110021SSheshadri.Vasudevan@Sun.COM * 202210021SSheshadri.Vasudevan@Sun.COM * Should be called with the mutex held 202310021SSheshadri.Vasudevan@Sun.COM * 202410021SSheshadri.Vasudevan@Sun.COM * Return Code: 0 for success 202510021SSheshadri.Vasudevan@Sun.COM * 202610021SSheshadri.Vasudevan@Sun.COM * Context: User and Kernel thread 202710021SSheshadri.Vasudevan@Sun.COM * 202810021SSheshadri.Vasudevan@Sun.COM */ 202910021SSheshadri.Vasudevan@Sun.COM static int 203010021SSheshadri.Vasudevan@Sun.COM cmlb_update_ext_minor_nodes(struct cmlb_lun *cl, int num_parts) 203110021SSheshadri.Vasudevan@Sun.COM { 203210021SSheshadri.Vasudevan@Sun.COM int i, count; 203310021SSheshadri.Vasudevan@Sun.COM char name[48]; 203410021SSheshadri.Vasudevan@Sun.COM int instance; 203510021SSheshadri.Vasudevan@Sun.COM struct driver_minor_data *demdp, *demdpr; 203610021SSheshadri.Vasudevan@Sun.COM char *devnm; 203710021SSheshadri.Vasudevan@Sun.COM dev_info_t *pdip; 203810021SSheshadri.Vasudevan@Sun.COM boolean_t internal; 203910021SSheshadri.Vasudevan@Sun.COM 204010021SSheshadri.Vasudevan@Sun.COM ASSERT(mutex_owned(CMLB_MUTEX(cl))); 204110021SSheshadri.Vasudevan@Sun.COM ASSERT(cl->cl_update_ext_minor_nodes == 1); 204210021SSheshadri.Vasudevan@Sun.COM 204310021SSheshadri.Vasudevan@Sun.COM internal = VOID2BOOLEAN( 204410021SSheshadri.Vasudevan@Sun.COM (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0); 204510021SSheshadri.Vasudevan@Sun.COM instance = ddi_get_instance(CMLB_DEVINFO(cl)); 204610021SSheshadri.Vasudevan@Sun.COM demdp = dk_ext_minor_data; 204710021SSheshadri.Vasudevan@Sun.COM demdpr = &dk_ext_minor_data[MAX_EXT_PARTS]; 204810021SSheshadri.Vasudevan@Sun.COM 204910021SSheshadri.Vasudevan@Sun.COM 205010021SSheshadri.Vasudevan@Sun.COM if (cl->cl_logical_drive_count) { 205110021SSheshadri.Vasudevan@Sun.COM for (i = 0; i < cl->cl_logical_drive_count; i++) { 205210021SSheshadri.Vasudevan@Sun.COM (void) sprintf(name, "%s", demdp->name); 205310021SSheshadri.Vasudevan@Sun.COM ddi_remove_minor_node(CMLB_DEVINFO(cl), name); 205410021SSheshadri.Vasudevan@Sun.COM (void) sprintf(name, "%s", demdpr->name); 205510021SSheshadri.Vasudevan@Sun.COM ddi_remove_minor_node(CMLB_DEVINFO(cl), name); 205610021SSheshadri.Vasudevan@Sun.COM demdp++; 205710021SSheshadri.Vasudevan@Sun.COM demdpr++; 205810021SSheshadri.Vasudevan@Sun.COM } 205910021SSheshadri.Vasudevan@Sun.COM /* There are existing device nodes. Remove them */ 206010021SSheshadri.Vasudevan@Sun.COM devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP); 206110021SSheshadri.Vasudevan@Sun.COM (void) ddi_deviname(cl->cl_devi, devnm); 206210021SSheshadri.Vasudevan@Sun.COM pdip = ddi_get_parent(cl->cl_devi); 206310021SSheshadri.Vasudevan@Sun.COM (void) devfs_clean(pdip, devnm + 1, DV_CLEAN_FORCE); 206410021SSheshadri.Vasudevan@Sun.COM kmem_free(devnm, MAXNAMELEN + 1); 206510021SSheshadri.Vasudevan@Sun.COM } 206610021SSheshadri.Vasudevan@Sun.COM 206710021SSheshadri.Vasudevan@Sun.COM demdp = dk_ext_minor_data; 206810021SSheshadri.Vasudevan@Sun.COM demdpr = &dk_ext_minor_data[MAX_EXT_PARTS]; 206910021SSheshadri.Vasudevan@Sun.COM 207010021SSheshadri.Vasudevan@Sun.COM for (i = 0; i < num_parts; i++) { 207110021SSheshadri.Vasudevan@Sun.COM (void) sprintf(name, "%s", demdp->name); 207210021SSheshadri.Vasudevan@Sun.COM if (cmlb_create_minor(CMLB_DEVINFO(cl), name, 207310021SSheshadri.Vasudevan@Sun.COM demdp->type, 207410021SSheshadri.Vasudevan@Sun.COM (instance << CMLBUNIT_SHIFT) | demdp->minor, 207510021SSheshadri.Vasudevan@Sun.COM cl->cl_node_type, NULL, internal) == DDI_FAILURE) { 207610021SSheshadri.Vasudevan@Sun.COM /* 207710021SSheshadri.Vasudevan@Sun.COM * Clean up any nodes that may have been 207810021SSheshadri.Vasudevan@Sun.COM * created, in case this fails in the middle 207910021SSheshadri.Vasudevan@Sun.COM * of the loop. 208010021SSheshadri.Vasudevan@Sun.COM */ 208110021SSheshadri.Vasudevan@Sun.COM ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL); 208210021SSheshadri.Vasudevan@Sun.COM cl->cl_logical_drive_count = 0; 208310021SSheshadri.Vasudevan@Sun.COM return (ENXIO); 208410021SSheshadri.Vasudevan@Sun.COM } 208510021SSheshadri.Vasudevan@Sun.COM (void) sprintf(name, "%s", demdpr->name); 208610021SSheshadri.Vasudevan@Sun.COM if (ddi_create_minor_node(CMLB_DEVINFO(cl), name, 208710021SSheshadri.Vasudevan@Sun.COM demdpr->type, 208810021SSheshadri.Vasudevan@Sun.COM (instance << CMLBUNIT_SHIFT) | demdpr->minor, 208910021SSheshadri.Vasudevan@Sun.COM cl->cl_node_type, NULL) == DDI_FAILURE) { 209010021SSheshadri.Vasudevan@Sun.COM /* 209110021SSheshadri.Vasudevan@Sun.COM * Clean up any nodes that may have been 209210021SSheshadri.Vasudevan@Sun.COM * created, in case this fails in the middle 209310021SSheshadri.Vasudevan@Sun.COM * of the loop. 209410021SSheshadri.Vasudevan@Sun.COM */ 209510021SSheshadri.Vasudevan@Sun.COM ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL); 209610021SSheshadri.Vasudevan@Sun.COM cl->cl_logical_drive_count = 0; 209710021SSheshadri.Vasudevan@Sun.COM return (ENXIO); 209810021SSheshadri.Vasudevan@Sun.COM } 209910021SSheshadri.Vasudevan@Sun.COM demdp++; 210010021SSheshadri.Vasudevan@Sun.COM demdpr++; 210110021SSheshadri.Vasudevan@Sun.COM } 210210021SSheshadri.Vasudevan@Sun.COM 210310021SSheshadri.Vasudevan@Sun.COM /* Update the cl_map array for logical drives */ 210410021SSheshadri.Vasudevan@Sun.COM for (count = 0; count < MAX_EXT_PARTS; count++) { 210510021SSheshadri.Vasudevan@Sun.COM cl->cl_map[FDISK_P4 + 1 + count].dkl_cylno = UINT32_MAX; 210610021SSheshadri.Vasudevan@Sun.COM cl->cl_map[FDISK_P4 + 1 + count].dkl_nblk = 210710021SSheshadri.Vasudevan@Sun.COM cl->cl_fmap[FD_NUMPART + count].fmap_nblk; 210810021SSheshadri.Vasudevan@Sun.COM cl->cl_offset[FDISK_P4 + 1 + count] = 210910021SSheshadri.Vasudevan@Sun.COM cl->cl_fmap[FD_NUMPART + count].fmap_start; 211010021SSheshadri.Vasudevan@Sun.COM } 211110021SSheshadri.Vasudevan@Sun.COM 211210021SSheshadri.Vasudevan@Sun.COM cl->cl_logical_drive_count = i; 211310021SSheshadri.Vasudevan@Sun.COM cl->cl_update_ext_minor_nodes = 0; 211410021SSheshadri.Vasudevan@Sun.COM return (0); 211510021SSheshadri.Vasudevan@Sun.COM } 211610021SSheshadri.Vasudevan@Sun.COM /* 211710021SSheshadri.Vasudevan@Sun.COM * Function: cmlb_validate_ext_part 211810021SSheshadri.Vasudevan@Sun.COM * 211910021SSheshadri.Vasudevan@Sun.COM * Description: utility routine to validate an extended partition's 212010021SSheshadri.Vasudevan@Sun.COM * metadata as found on disk 212110021SSheshadri.Vasudevan@Sun.COM * 212210021SSheshadri.Vasudevan@Sun.COM * Arguments: 212310021SSheshadri.Vasudevan@Sun.COM * cl driver soft state (unit) structure 212410021SSheshadri.Vasudevan@Sun.COM * part partition number of the extended partition 212510021SSheshadri.Vasudevan@Sun.COM * epart partition number of the logical drive 212610021SSheshadri.Vasudevan@Sun.COM * start absolute sector number of the start of the logical 212710021SSheshadri.Vasudevan@Sun.COM * drive being validated 212810021SSheshadri.Vasudevan@Sun.COM * size size of logical drive being validated 212910021SSheshadri.Vasudevan@Sun.COM * 213010021SSheshadri.Vasudevan@Sun.COM * Return Code: 0 for success 213110021SSheshadri.Vasudevan@Sun.COM * 213210021SSheshadri.Vasudevan@Sun.COM * Context: User and Kernel thread 213310021SSheshadri.Vasudevan@Sun.COM * 213410021SSheshadri.Vasudevan@Sun.COM * Algorithm : 213510021SSheshadri.Vasudevan@Sun.COM * Error cases are : 213610021SSheshadri.Vasudevan@Sun.COM * 1. If start block is lesser than or equal to the end block 213710021SSheshadri.Vasudevan@Sun.COM * 2. If either start block or end block is beyond the bounadry 213810021SSheshadri.Vasudevan@Sun.COM * of the extended partition. 213910021SSheshadri.Vasudevan@Sun.COM * 3. start or end block overlap with existing partitions. 214010021SSheshadri.Vasudevan@Sun.COM * To check this, first make sure that the start block doesnt 214110021SSheshadri.Vasudevan@Sun.COM * overlap with existing partitions. Then, calculate the 214210021SSheshadri.Vasudevan@Sun.COM * possible end block for the given start block that doesnt 214310021SSheshadri.Vasudevan@Sun.COM * overlap with existing partitions. This can be calculated by 214410021SSheshadri.Vasudevan@Sun.COM * first setting the possible end block to the end of the 214510021SSheshadri.Vasudevan@Sun.COM * extended partition (optimistic) and then, checking if there 214610021SSheshadri.Vasudevan@Sun.COM * is any other partition that lies after the start of the 214710021SSheshadri.Vasudevan@Sun.COM * partition being validated. If so, set the possible end to 214810021SSheshadri.Vasudevan@Sun.COM * one block less than the beginning of the next nearest partition 214910021SSheshadri.Vasudevan@Sun.COM * If the actual end block is greater than the calculated end 215010021SSheshadri.Vasudevan@Sun.COM * block, we have an overlap. 215110021SSheshadri.Vasudevan@Sun.COM * 215210021SSheshadri.Vasudevan@Sun.COM */ 215310021SSheshadri.Vasudevan@Sun.COM static int 215410021SSheshadri.Vasudevan@Sun.COM cmlb_validate_ext_part(struct cmlb_lun *cl, int part, int epart, uint32_t start, 215510021SSheshadri.Vasudevan@Sun.COM uint32_t size) 215610021SSheshadri.Vasudevan@Sun.COM { 215710021SSheshadri.Vasudevan@Sun.COM int i; 215810021SSheshadri.Vasudevan@Sun.COM uint32_t end = start + size - 1; 215910021SSheshadri.Vasudevan@Sun.COM uint32_t ext_start = cl->cl_fmap[part].fmap_start; 216010021SSheshadri.Vasudevan@Sun.COM uint32_t ext_end = ext_start + cl->cl_fmap[part].fmap_nblk - 1; 216110021SSheshadri.Vasudevan@Sun.COM uint32_t ts, te; 216210021SSheshadri.Vasudevan@Sun.COM uint32_t poss_end = ext_end; 216310021SSheshadri.Vasudevan@Sun.COM 216410021SSheshadri.Vasudevan@Sun.COM if (end <= start) { 216510021SSheshadri.Vasudevan@Sun.COM return (1); 216610021SSheshadri.Vasudevan@Sun.COM } 216710021SSheshadri.Vasudevan@Sun.COM 216810021SSheshadri.Vasudevan@Sun.COM /* 216910021SSheshadri.Vasudevan@Sun.COM * Check if the logical drive boundaries are within that of the 217010021SSheshadri.Vasudevan@Sun.COM * extended partition. 217110021SSheshadri.Vasudevan@Sun.COM */ 217210021SSheshadri.Vasudevan@Sun.COM if (start <= ext_start || start > ext_end || end <= ext_start || 217310021SSheshadri.Vasudevan@Sun.COM end > ext_end) { 217410021SSheshadri.Vasudevan@Sun.COM return (1); 217510021SSheshadri.Vasudevan@Sun.COM } 217610021SSheshadri.Vasudevan@Sun.COM 217710021SSheshadri.Vasudevan@Sun.COM /* 217810021SSheshadri.Vasudevan@Sun.COM * epart will be equal to FD_NUMPART if it is the first logical drive. 217910021SSheshadri.Vasudevan@Sun.COM * There is no need to check for overlaps with other logical drives, 218010021SSheshadri.Vasudevan@Sun.COM * since it is the only logical drive that we have come across so far. 218110021SSheshadri.Vasudevan@Sun.COM */ 218210021SSheshadri.Vasudevan@Sun.COM if (epart == FD_NUMPART) { 218310021SSheshadri.Vasudevan@Sun.COM return (0); 218410021SSheshadri.Vasudevan@Sun.COM } 218510021SSheshadri.Vasudevan@Sun.COM 218610021SSheshadri.Vasudevan@Sun.COM /* Check for overlaps with existing logical drives */ 218710021SSheshadri.Vasudevan@Sun.COM i = FD_NUMPART; 218810021SSheshadri.Vasudevan@Sun.COM ts = cl->cl_fmap[FD_NUMPART].fmap_start; 218910021SSheshadri.Vasudevan@Sun.COM te = ts + cl->cl_fmap[FD_NUMPART].fmap_nblk - 1; 219010021SSheshadri.Vasudevan@Sun.COM 219110021SSheshadri.Vasudevan@Sun.COM while ((i < epart) && ts && te) { 219210021SSheshadri.Vasudevan@Sun.COM if (start >= ts && start <= te) { 219310021SSheshadri.Vasudevan@Sun.COM return (1); 219410021SSheshadri.Vasudevan@Sun.COM } 219510021SSheshadri.Vasudevan@Sun.COM 219610021SSheshadri.Vasudevan@Sun.COM if ((ts < poss_end) && (ts > start)) { 219710021SSheshadri.Vasudevan@Sun.COM poss_end = ts - 1; 219810021SSheshadri.Vasudevan@Sun.COM } 219910021SSheshadri.Vasudevan@Sun.COM 220010021SSheshadri.Vasudevan@Sun.COM i++; 220110021SSheshadri.Vasudevan@Sun.COM ts = cl->cl_fmap[i].fmap_start; 220210021SSheshadri.Vasudevan@Sun.COM te = ts + cl->cl_fmap[i].fmap_nblk - 1; 220310021SSheshadri.Vasudevan@Sun.COM } 220410021SSheshadri.Vasudevan@Sun.COM 220510021SSheshadri.Vasudevan@Sun.COM if (end > poss_end) { 220610021SSheshadri.Vasudevan@Sun.COM return (1); 220710021SSheshadri.Vasudevan@Sun.COM } 220810021SSheshadri.Vasudevan@Sun.COM 220910021SSheshadri.Vasudevan@Sun.COM return (0); 221010021SSheshadri.Vasudevan@Sun.COM } 221110021SSheshadri.Vasudevan@Sun.COM 221210021SSheshadri.Vasudevan@Sun.COM 221310021SSheshadri.Vasudevan@Sun.COM /* 221410021SSheshadri.Vasudevan@Sun.COM * Function: cmlb_is_linux_swap 221510021SSheshadri.Vasudevan@Sun.COM * 221610021SSheshadri.Vasudevan@Sun.COM * Description: utility routine to verify if a partition is a linux swap 221710021SSheshadri.Vasudevan@Sun.COM * partition or not. 221810021SSheshadri.Vasudevan@Sun.COM * 221910021SSheshadri.Vasudevan@Sun.COM * Arguments: 222010021SSheshadri.Vasudevan@Sun.COM * cl driver soft state (unit) structure 222110021SSheshadri.Vasudevan@Sun.COM * part_start absolute sector number of the start of the partition 222210021SSheshadri.Vasudevan@Sun.COM * being verified 222310021SSheshadri.Vasudevan@Sun.COM * tg_cookie cookie from target driver to be passed back to target 222410021SSheshadri.Vasudevan@Sun.COM * driver when we call back to it through tg_ops. 222510021SSheshadri.Vasudevan@Sun.COM * 222610021SSheshadri.Vasudevan@Sun.COM * Return Code: 0 for success 222710021SSheshadri.Vasudevan@Sun.COM * 222810021SSheshadri.Vasudevan@Sun.COM * Context: User and Kernel thread 222910021SSheshadri.Vasudevan@Sun.COM * 223010021SSheshadri.Vasudevan@Sun.COM * Notes: 223110021SSheshadri.Vasudevan@Sun.COM * The linux swap magic "SWAP-SPACE" or "SWAPSPACE2" is found as the 223210021SSheshadri.Vasudevan@Sun.COM * last 10 bytes of a disk block whose size is that of the linux page 223310021SSheshadri.Vasudevan@Sun.COM * size. This disk block is found at the beginning of the swap partition. 223410021SSheshadri.Vasudevan@Sun.COM */ 223510021SSheshadri.Vasudevan@Sun.COM static int 223610021SSheshadri.Vasudevan@Sun.COM cmlb_is_linux_swap(struct cmlb_lun *cl, uint32_t part_start, void *tg_cookie) 223710021SSheshadri.Vasudevan@Sun.COM { 223810021SSheshadri.Vasudevan@Sun.COM int i; 223910021SSheshadri.Vasudevan@Sun.COM int rval = -1; 224010021SSheshadri.Vasudevan@Sun.COM uint32_t seek_offset; 224110021SSheshadri.Vasudevan@Sun.COM uint32_t linux_pg_size; 224210021SSheshadri.Vasudevan@Sun.COM char *buf, *linux_swap_magic; 224310021SSheshadri.Vasudevan@Sun.COM int sec_sz = cl->cl_sys_blocksize; 224410021SSheshadri.Vasudevan@Sun.COM /* Known linux kernel page sizes */ 224510021SSheshadri.Vasudevan@Sun.COM uint32_t linux_pg_size_arr[] = {4096, }; 224610021SSheshadri.Vasudevan@Sun.COM 224710021SSheshadri.Vasudevan@Sun.COM ASSERT(cl != NULL); 224810021SSheshadri.Vasudevan@Sun.COM ASSERT(mutex_owned(CMLB_MUTEX(cl))); 224910021SSheshadri.Vasudevan@Sun.COM 225010021SSheshadri.Vasudevan@Sun.COM if ((buf = kmem_zalloc(sec_sz, KM_NOSLEEP)) == NULL) { 225110021SSheshadri.Vasudevan@Sun.COM return (ENOMEM); 225210021SSheshadri.Vasudevan@Sun.COM } 225310021SSheshadri.Vasudevan@Sun.COM 2254*10682SSheshadri.Vasudevan@Sun.COM /* 2255*10682SSheshadri.Vasudevan@Sun.COM * Check if there is a sane Solaris VTOC 2256*10682SSheshadri.Vasudevan@Sun.COM * If there is a valid vtoc, no need to lookup 2257*10682SSheshadri.Vasudevan@Sun.COM * for the linux swap signature. 2258*10682SSheshadri.Vasudevan@Sun.COM */ 2259*10682SSheshadri.Vasudevan@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 2260*10682SSheshadri.Vasudevan@Sun.COM rval = DK_TG_READ(cl, buf, part_start + DK_LABEL_LOC, 2261*10682SSheshadri.Vasudevan@Sun.COM sec_sz, tg_cookie); 2262*10682SSheshadri.Vasudevan@Sun.COM mutex_enter(CMLB_MUTEX(cl)); 2263*10682SSheshadri.Vasudevan@Sun.COM if (rval != 0) { 2264*10682SSheshadri.Vasudevan@Sun.COM cmlb_dbg(CMLB_ERROR, cl, 2265*10682SSheshadri.Vasudevan@Sun.COM "cmlb_is_linux_swap: disk vtoc read err\n"); 2266*10682SSheshadri.Vasudevan@Sun.COM rval = EIO; 2267*10682SSheshadri.Vasudevan@Sun.COM goto done; 2268*10682SSheshadri.Vasudevan@Sun.COM } 2269*10682SSheshadri.Vasudevan@Sun.COM 2270*10682SSheshadri.Vasudevan@Sun.COM if ((((struct dk_label *)buf)->dkl_magic == DKL_MAGIC) && 2271*10682SSheshadri.Vasudevan@Sun.COM (((struct dk_label *)buf)->dkl_vtoc.v_sanity == VTOC_SANE)) { 2272*10682SSheshadri.Vasudevan@Sun.COM rval = -1; 2273*10682SSheshadri.Vasudevan@Sun.COM goto done; 2274*10682SSheshadri.Vasudevan@Sun.COM } 2275*10682SSheshadri.Vasudevan@Sun.COM 2276*10682SSheshadri.Vasudevan@Sun.COM 2277*10682SSheshadri.Vasudevan@Sun.COM /* No valid vtoc, so check for linux swap signature */ 227810021SSheshadri.Vasudevan@Sun.COM linux_swap_magic = buf + sec_sz - 10; 227910021SSheshadri.Vasudevan@Sun.COM 228010021SSheshadri.Vasudevan@Sun.COM for (i = 0; i < sizeof (linux_pg_size_arr)/sizeof (uint32_t); i++) { 228110021SSheshadri.Vasudevan@Sun.COM linux_pg_size = linux_pg_size_arr[i]; 228210021SSheshadri.Vasudevan@Sun.COM seek_offset = linux_pg_size/sec_sz - 1; 228310021SSheshadri.Vasudevan@Sun.COM seek_offset += part_start; 228410021SSheshadri.Vasudevan@Sun.COM 228510021SSheshadri.Vasudevan@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 228610021SSheshadri.Vasudevan@Sun.COM rval = DK_TG_READ(cl, buf, seek_offset, sec_sz, tg_cookie); 228710021SSheshadri.Vasudevan@Sun.COM mutex_enter(CMLB_MUTEX(cl)); 228810021SSheshadri.Vasudevan@Sun.COM 228910021SSheshadri.Vasudevan@Sun.COM if (rval != 0) { 229010021SSheshadri.Vasudevan@Sun.COM cmlb_dbg(CMLB_ERROR, cl, 229110021SSheshadri.Vasudevan@Sun.COM "cmlb_is_linux_swap: disk read err\n"); 229210021SSheshadri.Vasudevan@Sun.COM rval = EIO; 229310021SSheshadri.Vasudevan@Sun.COM break; 229410021SSheshadri.Vasudevan@Sun.COM } 229510021SSheshadri.Vasudevan@Sun.COM 229610021SSheshadri.Vasudevan@Sun.COM rval = -1; 229710021SSheshadri.Vasudevan@Sun.COM 229810021SSheshadri.Vasudevan@Sun.COM if ((strncmp(linux_swap_magic, "SWAP-SPACE", 10) == 0) || 229910021SSheshadri.Vasudevan@Sun.COM (strncmp(linux_swap_magic, "SWAPSPACE2", 10) == 0)) { 230010021SSheshadri.Vasudevan@Sun.COM /* Found a linux swap */ 230110021SSheshadri.Vasudevan@Sun.COM rval = 0; 230210021SSheshadri.Vasudevan@Sun.COM break; 230310021SSheshadri.Vasudevan@Sun.COM } 230410021SSheshadri.Vasudevan@Sun.COM } 230510021SSheshadri.Vasudevan@Sun.COM 2306*10682SSheshadri.Vasudevan@Sun.COM done: 230710021SSheshadri.Vasudevan@Sun.COM kmem_free(buf, sec_sz); 230810021SSheshadri.Vasudevan@Sun.COM return (rval); 230910021SSheshadri.Vasudevan@Sun.COM } 231010021SSheshadri.Vasudevan@Sun.COM #endif 231110021SSheshadri.Vasudevan@Sun.COM 2312786Slclee /* 2313786Slclee * Function: cmlb_read_fdisk 2314786Slclee * 2315786Slclee * Description: utility routine to read the fdisk table. 2316786Slclee * 23173525Sshidokht * Arguments: 23183525Sshidokht * cl driver soft state (unit) structure 23193525Sshidokht * capacity disk capacity in #blocks 23203525Sshidokht * tg_cookie cookie from target driver to be passed back to target 23213525Sshidokht * driver when we call back to it through tg_ops. 2322786Slclee * 2323786Slclee * Return Code: 0 for success (includes not reading for no_fdisk_present case 2324786Slclee * errnos from tg_rw if failed to read the first block. 2325786Slclee * 2326786Slclee * Context: Kernel thread only (can sleep). 2327786Slclee */ 23283525Sshidokht /*ARGSUSED*/ 2329786Slclee static int 23303525Sshidokht cmlb_read_fdisk(struct cmlb_lun *cl, diskaddr_t capacity, void *tg_cookie) 2331786Slclee { 2332786Slclee #if defined(_NO_FDISK_PRESENT) 2333786Slclee 23343525Sshidokht cl->cl_solaris_offset = 0; 23353525Sshidokht cl->cl_solaris_size = capacity; 23363525Sshidokht bzero(cl->cl_fmap, sizeof (struct fmap) * FD_NUMPART); 2337786Slclee return (0); 2338786Slclee 2339786Slclee #elif defined(_FIRMWARE_NEEDS_FDISK) 2340786Slclee 2341786Slclee struct ipart *fdp; 2342786Slclee struct mboot *mbp; 2343786Slclee struct ipart fdisk[FD_NUMPART]; 234410021SSheshadri.Vasudevan@Sun.COM int i, k; 2345786Slclee char sigbuf[2]; 2346786Slclee caddr_t bufp; 2347786Slclee int uidx; 2348786Slclee int rval; 2349786Slclee int lba = 0; 2350786Slclee uint_t solaris_offset; /* offset to solaris part. */ 2351786Slclee daddr_t solaris_size; /* size of solaris partition */ 2352786Slclee uint32_t blocksize; 235310021SSheshadri.Vasudevan@Sun.COM #if defined(__i386) || defined(__amd64) 235410021SSheshadri.Vasudevan@Sun.COM struct ipart eparts[2]; 235510021SSheshadri.Vasudevan@Sun.COM struct ipart *efdp1 = &eparts[0]; 235610021SSheshadri.Vasudevan@Sun.COM struct ipart *efdp2 = &eparts[1]; 235710021SSheshadri.Vasudevan@Sun.COM int ext_part_exists = 0; 235810021SSheshadri.Vasudevan@Sun.COM int ld_count = 0; 235910021SSheshadri.Vasudevan@Sun.COM #endif 2360786Slclee 23613525Sshidokht ASSERT(cl != NULL); 23623525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 2363786Slclee 2364786Slclee /* 2365786Slclee * Start off assuming no fdisk table 2366786Slclee */ 2367786Slclee solaris_offset = 0; 2368786Slclee solaris_size = capacity; 2369786Slclee 23703525Sshidokht blocksize = cl->cl_tgt_blocksize; 2371786Slclee 2372786Slclee bufp = kmem_zalloc(blocksize, KM_SLEEP); 2373786Slclee 23743525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 23753525Sshidokht rval = DK_TG_READ(cl, bufp, 0, blocksize, tg_cookie); 23763525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 2377786Slclee 2378786Slclee if (rval != 0) { 23793525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 2380786Slclee "cmlb_read_fdisk: fdisk read err\n"); 23813525Sshidokht bzero(cl->cl_fmap, sizeof (struct fmap) * FD_NUMPART); 23823525Sshidokht goto done; 2383786Slclee } 2384786Slclee 2385786Slclee mbp = (struct mboot *)bufp; 2386786Slclee 2387786Slclee /* 2388786Slclee * The fdisk table does not begin on a 4-byte boundary within the 2389786Slclee * master boot record, so we copy it to an aligned structure to avoid 2390786Slclee * alignment exceptions on some processors. 2391786Slclee */ 2392786Slclee bcopy(&mbp->parts[0], fdisk, sizeof (fdisk)); 2393786Slclee 2394786Slclee /* 2395786Slclee * Check for lba support before verifying sig; sig might not be 2396786Slclee * there, say on a blank disk, but the max_chs mark may still 2397786Slclee * be present. 2398786Slclee * 2399786Slclee * Note: LBA support and BEFs are an x86-only concept but this 2400786Slclee * code should work OK on SPARC as well. 2401786Slclee */ 2402786Slclee 2403786Slclee /* 2404786Slclee * First, check for lba-access-ok on root node (or prom root node) 2405786Slclee * if present there, don't need to search fdisk table. 2406786Slclee */ 2407786Slclee if (ddi_getprop(DDI_DEV_T_ANY, ddi_root_node(), 0, 2408786Slclee "lba-access-ok", 0) != 0) { 2409786Slclee /* All drives do LBA; don't search fdisk table */ 2410786Slclee lba = 1; 2411786Slclee } else { 2412786Slclee /* Okay, look for mark in fdisk table */ 2413786Slclee for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) { 2414786Slclee /* accumulate "lba" value from all partitions */ 2415786Slclee lba = (lba || cmlb_has_max_chs_vals(fdp)); 2416786Slclee } 2417786Slclee } 2418786Slclee 2419786Slclee if (lba != 0) { 24203525Sshidokht dev_t dev = cmlb_make_device(cl); 24213525Sshidokht 24223525Sshidokht if (ddi_getprop(dev, CMLB_DEVINFO(cl), DDI_PROP_DONTPASS, 2423786Slclee "lba-access-ok", 0) == 0) { 2424786Slclee /* not found; create it */ 24253525Sshidokht if (ddi_prop_create(dev, CMLB_DEVINFO(cl), 0, 2426786Slclee "lba-access-ok", (caddr_t)NULL, 0) != 2427786Slclee DDI_PROP_SUCCESS) { 24283525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 2429786Slclee "cmlb_read_fdisk: Can't create lba " 2430786Slclee "property for instance %d\n", 24313525Sshidokht ddi_get_instance(CMLB_DEVINFO(cl))); 2432786Slclee } 2433786Slclee } 2434786Slclee } 2435786Slclee 2436786Slclee bcopy(&mbp->signature, sigbuf, sizeof (sigbuf)); 2437786Slclee 2438786Slclee /* 2439786Slclee * Endian-independent signature check 2440786Slclee */ 2441786Slclee if (((sigbuf[1] & 0xFF) != ((MBB_MAGIC >> 8) & 0xFF)) || 2442786Slclee (sigbuf[0] != (MBB_MAGIC & 0xFF))) { 24433525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 2444786Slclee "cmlb_read_fdisk: no fdisk\n"); 24453525Sshidokht bzero(cl->cl_fmap, sizeof (struct fmap) * FD_NUMPART); 2446786Slclee goto done; 2447786Slclee } 2448786Slclee 2449786Slclee #ifdef CMLBDEBUG 24503525Sshidokht if (cmlb_level_mask & CMLB_LOGMASK_INFO) { 2451786Slclee fdp = fdisk; 24523525Sshidokht cmlb_dbg(CMLB_INFO, cl, "cmlb_read_fdisk:\n"); 24533525Sshidokht cmlb_dbg(CMLB_INFO, cl, " relsect " 2454786Slclee "numsect sysid bootid\n"); 2455786Slclee for (i = 0; i < FD_NUMPART; i++, fdp++) { 24563525Sshidokht cmlb_dbg(CMLB_INFO, cl, 2457786Slclee " %d: %8d %8d 0x%08x 0x%08x\n", 2458786Slclee i, fdp->relsect, fdp->numsect, 2459786Slclee fdp->systid, fdp->bootid); 2460786Slclee } 2461786Slclee } 2462786Slclee #endif 2463786Slclee 2464786Slclee /* 2465786Slclee * Try to find the unix partition 2466786Slclee */ 2467786Slclee uidx = -1; 2468786Slclee solaris_offset = 0; 2469786Slclee solaris_size = 0; 2470786Slclee 2471786Slclee for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) { 24727563SPrasad.Singamsetty@Sun.COM uint32_t relsect; 24737563SPrasad.Singamsetty@Sun.COM uint32_t numsect; 247410021SSheshadri.Vasudevan@Sun.COM uchar_t systid; 247510021SSheshadri.Vasudevan@Sun.COM #if defined(__i386) || defined(__amd64) 247610021SSheshadri.Vasudevan@Sun.COM /* 247710021SSheshadri.Vasudevan@Sun.COM * Stores relative block offset from the beginning of the 247810021SSheshadri.Vasudevan@Sun.COM * Extended Partition. 247910021SSheshadri.Vasudevan@Sun.COM */ 248010021SSheshadri.Vasudevan@Sun.COM int ext_relsect = 0; 248110021SSheshadri.Vasudevan@Sun.COM #endif 2482786Slclee 2483786Slclee if (fdp->numsect == 0) { 24843525Sshidokht cl->cl_fmap[i].fmap_start = 0; 24853525Sshidokht cl->cl_fmap[i].fmap_nblk = 0; 2486786Slclee continue; 2487786Slclee } 2488786Slclee 2489786Slclee /* 2490786Slclee * Data in the fdisk table is little-endian. 2491786Slclee */ 2492786Slclee relsect = LE_32(fdp->relsect); 2493786Slclee numsect = LE_32(fdp->numsect); 2494786Slclee 24953525Sshidokht cl->cl_fmap[i].fmap_start = relsect; 24963525Sshidokht cl->cl_fmap[i].fmap_nblk = numsect; 249710021SSheshadri.Vasudevan@Sun.COM cl->cl_fmap[i].fmap_systid = LE_8(fdp->systid); 249810021SSheshadri.Vasudevan@Sun.COM 249910021SSheshadri.Vasudevan@Sun.COM #if defined(__i386) || defined(__amd64) 250010021SSheshadri.Vasudevan@Sun.COM /* Support only one extended partition per LUN */ 250110021SSheshadri.Vasudevan@Sun.COM if ((fdp->systid == EXTDOS || fdp->systid == FDISK_EXTLBA) && 250210021SSheshadri.Vasudevan@Sun.COM (ext_part_exists == 0)) { 250310021SSheshadri.Vasudevan@Sun.COM int j; 250410021SSheshadri.Vasudevan@Sun.COM uint32_t logdrive_offset; 250510021SSheshadri.Vasudevan@Sun.COM uint32_t ext_numsect; 250610021SSheshadri.Vasudevan@Sun.COM uint32_t abs_secnum; 250710021SSheshadri.Vasudevan@Sun.COM 250810021SSheshadri.Vasudevan@Sun.COM ext_part_exists = 1; 250910021SSheshadri.Vasudevan@Sun.COM 251010021SSheshadri.Vasudevan@Sun.COM for (j = FD_NUMPART; j < FDISK_PARTS; j++) { 251110021SSheshadri.Vasudevan@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 251210021SSheshadri.Vasudevan@Sun.COM rval = DK_TG_READ(cl, bufp, 251310021SSheshadri.Vasudevan@Sun.COM (relsect + ext_relsect), blocksize, 251410021SSheshadri.Vasudevan@Sun.COM tg_cookie); 251510021SSheshadri.Vasudevan@Sun.COM mutex_enter(CMLB_MUTEX(cl)); 251610021SSheshadri.Vasudevan@Sun.COM 251710021SSheshadri.Vasudevan@Sun.COM if (rval != 0) { 251810021SSheshadri.Vasudevan@Sun.COM cmlb_dbg(CMLB_ERROR, cl, 251910021SSheshadri.Vasudevan@Sun.COM "cmlb_read_fdisk: Extended " 252010021SSheshadri.Vasudevan@Sun.COM "partition read err\n"); 252110021SSheshadri.Vasudevan@Sun.COM goto done; 252210021SSheshadri.Vasudevan@Sun.COM } 252310021SSheshadri.Vasudevan@Sun.COM /* 252410021SSheshadri.Vasudevan@Sun.COM * The first ipart entry provides the offset 252510021SSheshadri.Vasudevan@Sun.COM * at which the logical drive starts off from 252610021SSheshadri.Vasudevan@Sun.COM * the beginning of the container partition 252710021SSheshadri.Vasudevan@Sun.COM * and the size of the logical drive. 252810021SSheshadri.Vasudevan@Sun.COM * The second ipart entry provides the offset 252910021SSheshadri.Vasudevan@Sun.COM * of the next container partition from the 253010021SSheshadri.Vasudevan@Sun.COM * beginning of the extended partition. 253110021SSheshadri.Vasudevan@Sun.COM */ 253210021SSheshadri.Vasudevan@Sun.COM bcopy(&bufp[FDISK_PART_TABLE_START], eparts, 253310021SSheshadri.Vasudevan@Sun.COM sizeof (eparts)); 253410021SSheshadri.Vasudevan@Sun.COM logdrive_offset = LE_32(efdp1->relsect); 253510021SSheshadri.Vasudevan@Sun.COM ext_numsect = LE_32(efdp1->numsect); 253610021SSheshadri.Vasudevan@Sun.COM systid = LE_8(efdp1->systid); 253710021SSheshadri.Vasudevan@Sun.COM if (logdrive_offset <= 0 || ext_numsect <= 0) 253810021SSheshadri.Vasudevan@Sun.COM break; 253910021SSheshadri.Vasudevan@Sun.COM abs_secnum = relsect + ext_relsect + 254010021SSheshadri.Vasudevan@Sun.COM logdrive_offset; 254110021SSheshadri.Vasudevan@Sun.COM 254210021SSheshadri.Vasudevan@Sun.COM /* Boundary condition and overlap checking */ 254310021SSheshadri.Vasudevan@Sun.COM if (cmlb_validate_ext_part(cl, i, j, abs_secnum, 254410021SSheshadri.Vasudevan@Sun.COM ext_numsect)) { 254510021SSheshadri.Vasudevan@Sun.COM break; 254610021SSheshadri.Vasudevan@Sun.COM } 254710021SSheshadri.Vasudevan@Sun.COM 254810021SSheshadri.Vasudevan@Sun.COM if ((cl->cl_fmap[j].fmap_start != abs_secnum) || 254910021SSheshadri.Vasudevan@Sun.COM (cl->cl_fmap[j].fmap_nblk != ext_numsect) || 255010021SSheshadri.Vasudevan@Sun.COM (cl->cl_fmap[j].fmap_systid != systid)) { 255110021SSheshadri.Vasudevan@Sun.COM /* 255210021SSheshadri.Vasudevan@Sun.COM * Indicates change from previous 255310021SSheshadri.Vasudevan@Sun.COM * partinfo. Need to recreate 255410021SSheshadri.Vasudevan@Sun.COM * logical device nodes. 255510021SSheshadri.Vasudevan@Sun.COM */ 255610021SSheshadri.Vasudevan@Sun.COM cl->cl_update_ext_minor_nodes = 1; 255710021SSheshadri.Vasudevan@Sun.COM } 255810021SSheshadri.Vasudevan@Sun.COM cl->cl_fmap[j].fmap_start = abs_secnum; 255910021SSheshadri.Vasudevan@Sun.COM cl->cl_fmap[j].fmap_nblk = ext_numsect; 256010021SSheshadri.Vasudevan@Sun.COM cl->cl_fmap[j].fmap_systid = systid; 256110021SSheshadri.Vasudevan@Sun.COM ld_count++; 256210021SSheshadri.Vasudevan@Sun.COM 2563*10682SSheshadri.Vasudevan@Sun.COM if ((efdp1->systid == SUNIXOS && 2564*10682SSheshadri.Vasudevan@Sun.COM (cmlb_is_linux_swap(cl, abs_secnum, 2565*10682SSheshadri.Vasudevan@Sun.COM tg_cookie) != 0)) || 2566*10682SSheshadri.Vasudevan@Sun.COM efdp1->systid == SUNIXOS2) { 2567*10682SSheshadri.Vasudevan@Sun.COM if (uidx == -1) { 256810021SSheshadri.Vasudevan@Sun.COM uidx = 0; 256910021SSheshadri.Vasudevan@Sun.COM solaris_offset = abs_secnum; 257010021SSheshadri.Vasudevan@Sun.COM solaris_size = ext_numsect; 257110021SSheshadri.Vasudevan@Sun.COM } 257210021SSheshadri.Vasudevan@Sun.COM } 257310021SSheshadri.Vasudevan@Sun.COM 257410021SSheshadri.Vasudevan@Sun.COM if ((ext_relsect = LE_32(efdp2->relsect)) == 0) 257510021SSheshadri.Vasudevan@Sun.COM break; 257610021SSheshadri.Vasudevan@Sun.COM } 257710021SSheshadri.Vasudevan@Sun.COM } 257810021SSheshadri.Vasudevan@Sun.COM 257910021SSheshadri.Vasudevan@Sun.COM #endif 2580786Slclee 2581786Slclee if (fdp->systid != SUNIXOS && 2582786Slclee fdp->systid != SUNIXOS2 && 2583786Slclee fdp->systid != EFI_PMBR) { 2584786Slclee continue; 2585786Slclee } 2586786Slclee 2587786Slclee /* 2588786Slclee * use the last active solaris partition id found 2589786Slclee * (there should only be 1 active partition id) 2590786Slclee * 2591786Slclee * if there are no active solaris partition id 2592786Slclee * then use the first inactive solaris partition id 2593786Slclee */ 2594786Slclee if ((uidx == -1) || (fdp->bootid == ACTIVE)) { 259510021SSheshadri.Vasudevan@Sun.COM #if defined(__i386) || defined(__amd64) 2596*10682SSheshadri.Vasudevan@Sun.COM if (fdp->systid != SUNIXOS || 2597*10682SSheshadri.Vasudevan@Sun.COM (fdp->systid == SUNIXOS && 2598*10682SSheshadri.Vasudevan@Sun.COM (cmlb_is_linux_swap(cl, relsect, 2599*10682SSheshadri.Vasudevan@Sun.COM tg_cookie) != 0))) { 260010021SSheshadri.Vasudevan@Sun.COM #endif 260110021SSheshadri.Vasudevan@Sun.COM uidx = i; 260210021SSheshadri.Vasudevan@Sun.COM solaris_offset = relsect; 260310021SSheshadri.Vasudevan@Sun.COM solaris_size = numsect; 260410021SSheshadri.Vasudevan@Sun.COM #if defined(__i386) || defined(__amd64) 260510021SSheshadri.Vasudevan@Sun.COM } 260610021SSheshadri.Vasudevan@Sun.COM #endif 2607786Slclee } 2608786Slclee } 260910021SSheshadri.Vasudevan@Sun.COM #if defined(__i386) || defined(__amd64) 261010021SSheshadri.Vasudevan@Sun.COM if (ld_count < cl->cl_logical_drive_count) { 261110021SSheshadri.Vasudevan@Sun.COM /* 261210021SSheshadri.Vasudevan@Sun.COM * Some/all logical drives were deleted. Clear out 261310021SSheshadri.Vasudevan@Sun.COM * the fmap entries correspoding to those deleted drives. 261410021SSheshadri.Vasudevan@Sun.COM */ 261510021SSheshadri.Vasudevan@Sun.COM for (k = ld_count + FD_NUMPART; 261610021SSheshadri.Vasudevan@Sun.COM k < cl->cl_logical_drive_count + FD_NUMPART; k++) { 261710021SSheshadri.Vasudevan@Sun.COM cl->cl_fmap[k].fmap_start = 0; 261810021SSheshadri.Vasudevan@Sun.COM cl->cl_fmap[k].fmap_nblk = 0; 261910021SSheshadri.Vasudevan@Sun.COM cl->cl_fmap[k].fmap_systid = 0; 262010021SSheshadri.Vasudevan@Sun.COM } 262110021SSheshadri.Vasudevan@Sun.COM cl->cl_update_ext_minor_nodes = 1; 262210021SSheshadri.Vasudevan@Sun.COM } 262310021SSheshadri.Vasudevan@Sun.COM if (cl->cl_update_ext_minor_nodes) { 262410021SSheshadri.Vasudevan@Sun.COM rval = cmlb_update_ext_minor_nodes(cl, ld_count); 262510021SSheshadri.Vasudevan@Sun.COM if (rval != 0) { 262610021SSheshadri.Vasudevan@Sun.COM goto done; 262710021SSheshadri.Vasudevan@Sun.COM } 262810021SSheshadri.Vasudevan@Sun.COM } 262910021SSheshadri.Vasudevan@Sun.COM #endif 26303525Sshidokht cmlb_dbg(CMLB_INFO, cl, "fdisk 0x%x 0x%lx", 26313525Sshidokht cl->cl_solaris_offset, cl->cl_solaris_size); 2632786Slclee done: 2633786Slclee 2634786Slclee /* 2635786Slclee * Clear the VTOC info, only if the Solaris partition entry 2636786Slclee * has moved, changed size, been deleted, or if the size of 2637786Slclee * the partition is too small to even fit the label sector. 2638786Slclee */ 26393525Sshidokht if ((cl->cl_solaris_offset != solaris_offset) || 26403525Sshidokht (cl->cl_solaris_size != solaris_size) || 2641786Slclee solaris_size <= DK_LABEL_LOC) { 26423525Sshidokht cmlb_dbg(CMLB_INFO, cl, "fdisk moved 0x%x 0x%lx", 26433525Sshidokht solaris_offset, solaris_size); 26443525Sshidokht bzero(&cl->cl_g, sizeof (struct dk_geom)); 26453525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc)); 26463525Sshidokht bzero(&cl->cl_map, NDKMAP * (sizeof (struct dk_map))); 26478863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE; 2648786Slclee } 26493525Sshidokht cl->cl_solaris_offset = solaris_offset; 26503525Sshidokht cl->cl_solaris_size = solaris_size; 2651786Slclee kmem_free(bufp, blocksize); 2652786Slclee return (rval); 2653786Slclee 2654786Slclee #else /* #elif defined(_FIRMWARE_NEEDS_FDISK) */ 2655786Slclee #error "fdisk table presence undetermined for this platform." 2656786Slclee #endif /* #if defined(_NO_FDISK_PRESENT) */ 2657786Slclee } 2658786Slclee 2659786Slclee static void 2660786Slclee cmlb_swap_efi_gpt(efi_gpt_t *e) 2661786Slclee { 2662786Slclee _NOTE(ASSUMING_PROTECTED(*e)) 2663786Slclee e->efi_gpt_Signature = LE_64(e->efi_gpt_Signature); 2664786Slclee e->efi_gpt_Revision = LE_32(e->efi_gpt_Revision); 2665786Slclee e->efi_gpt_HeaderSize = LE_32(e->efi_gpt_HeaderSize); 2666786Slclee e->efi_gpt_HeaderCRC32 = LE_32(e->efi_gpt_HeaderCRC32); 2667786Slclee e->efi_gpt_MyLBA = LE_64(e->efi_gpt_MyLBA); 2668786Slclee e->efi_gpt_AlternateLBA = LE_64(e->efi_gpt_AlternateLBA); 2669786Slclee e->efi_gpt_FirstUsableLBA = LE_64(e->efi_gpt_FirstUsableLBA); 2670786Slclee e->efi_gpt_LastUsableLBA = LE_64(e->efi_gpt_LastUsableLBA); 2671786Slclee UUID_LE_CONVERT(e->efi_gpt_DiskGUID, e->efi_gpt_DiskGUID); 2672786Slclee e->efi_gpt_PartitionEntryLBA = LE_64(e->efi_gpt_PartitionEntryLBA); 2673786Slclee e->efi_gpt_NumberOfPartitionEntries = 2674786Slclee LE_32(e->efi_gpt_NumberOfPartitionEntries); 2675786Slclee e->efi_gpt_SizeOfPartitionEntry = 2676786Slclee LE_32(e->efi_gpt_SizeOfPartitionEntry); 2677786Slclee e->efi_gpt_PartitionEntryArrayCRC32 = 2678786Slclee LE_32(e->efi_gpt_PartitionEntryArrayCRC32); 2679786Slclee } 2680786Slclee 2681786Slclee static void 2682786Slclee cmlb_swap_efi_gpe(int nparts, efi_gpe_t *p) 2683786Slclee { 2684786Slclee int i; 2685786Slclee 2686786Slclee _NOTE(ASSUMING_PROTECTED(*p)) 2687786Slclee for (i = 0; i < nparts; i++) { 2688786Slclee UUID_LE_CONVERT(p[i].efi_gpe_PartitionTypeGUID, 2689786Slclee p[i].efi_gpe_PartitionTypeGUID); 2690786Slclee p[i].efi_gpe_StartingLBA = LE_64(p[i].efi_gpe_StartingLBA); 2691786Slclee p[i].efi_gpe_EndingLBA = LE_64(p[i].efi_gpe_EndingLBA); 2692786Slclee /* PartitionAttrs */ 2693786Slclee } 2694786Slclee } 2695786Slclee 2696786Slclee static int 2697786Slclee cmlb_validate_efi(efi_gpt_t *labp) 2698786Slclee { 2699786Slclee if (labp->efi_gpt_Signature != EFI_SIGNATURE) 2700786Slclee return (EINVAL); 2701786Slclee /* at least 96 bytes in this version of the spec. */ 2702786Slclee if (sizeof (efi_gpt_t) - sizeof (labp->efi_gpt_Reserved2) > 2703786Slclee labp->efi_gpt_HeaderSize) 2704786Slclee return (EINVAL); 2705786Slclee /* this should be 128 bytes */ 2706786Slclee if (labp->efi_gpt_SizeOfPartitionEntry != sizeof (efi_gpe_t)) 2707786Slclee return (EINVAL); 2708786Slclee return (0); 2709786Slclee } 2710786Slclee 27115624Sshidokht /* 27128863SEdward.Pilatowicz@Sun.COM * This function returns B_FALSE if there is a valid MBR signature and no 27138863SEdward.Pilatowicz@Sun.COM * partition table entries of type EFI_PMBR (0xEE). Otherwise it returns B_TRUE. 27145624Sshidokht * 27155624Sshidokht * The EFI spec (1.10 and later) requires having a Protective MBR (PMBR) to 27165624Sshidokht * recognize the disk as GPT partitioned. However, some other OS creates an MBR 27175624Sshidokht * where a PMBR entry is not the only one. Also, if the first block has been 27185624Sshidokht * corrupted, currently best attempt to allow data access would be to try to 27195624Sshidokht * check for GPT headers. Hence in case of more than one partition entry, but 27205624Sshidokht * at least one EFI_PMBR partition type or no valid magic number, the function 27218863SEdward.Pilatowicz@Sun.COM * returns B_TRUE to continue with looking for GPT header. 27225624Sshidokht */ 27235624Sshidokht 27248863SEdward.Pilatowicz@Sun.COM static boolean_t 27258863SEdward.Pilatowicz@Sun.COM cmlb_check_efi_mbr(uchar_t *buf, boolean_t *is_mbr) 27265624Sshidokht { 27275624Sshidokht struct ipart *fdp; 27285624Sshidokht struct mboot *mbp = (struct mboot *)buf; 27295624Sshidokht struct ipart fdisk[FD_NUMPART]; 27305624Sshidokht int i; 27315624Sshidokht 27327563SPrasad.Singamsetty@Sun.COM if (is_mbr != NULL) 27338863SEdward.Pilatowicz@Sun.COM *is_mbr = B_TRUE; 27347563SPrasad.Singamsetty@Sun.COM 27357563SPrasad.Singamsetty@Sun.COM if (LE_16(mbp->signature) != MBB_MAGIC) { 27367563SPrasad.Singamsetty@Sun.COM if (is_mbr != NULL) 27378863SEdward.Pilatowicz@Sun.COM *is_mbr = B_FALSE; 27388863SEdward.Pilatowicz@Sun.COM return (B_TRUE); 27397563SPrasad.Singamsetty@Sun.COM } 27405624Sshidokht 27415624Sshidokht bcopy(&mbp->parts[0], fdisk, sizeof (fdisk)); 27425624Sshidokht 27435624Sshidokht for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) { 27445624Sshidokht if (fdp->systid == EFI_PMBR) 27458863SEdward.Pilatowicz@Sun.COM return (B_TRUE); 27465624Sshidokht } 27475624Sshidokht 27488863SEdward.Pilatowicz@Sun.COM return (B_FALSE); 27495624Sshidokht } 27505624Sshidokht 2751786Slclee static int 27523525Sshidokht cmlb_use_efi(struct cmlb_lun *cl, diskaddr_t capacity, int flags, 27533525Sshidokht void *tg_cookie) 2754786Slclee { 2755786Slclee int i; 2756786Slclee int rval = 0; 2757786Slclee efi_gpe_t *partitions; 2758786Slclee uchar_t *buf; 2759786Slclee uint_t lbasize; /* is really how much to read */ 27603525Sshidokht diskaddr_t cap = 0; 2761786Slclee uint_t nparts; 2762786Slclee diskaddr_t gpe_lba; 27636590Syl194034 diskaddr_t alternate_lba; 27641071Sshidokht int iofailed = 0; 27653525Sshidokht struct uuid uuid_type_reserved = EFI_RESERVED; 27667563SPrasad.Singamsetty@Sun.COM #if defined(_FIRMWARE_NEEDS_FDISK) 27678863SEdward.Pilatowicz@Sun.COM boolean_t is_mbr; 27687563SPrasad.Singamsetty@Sun.COM #endif 27693525Sshidokht 27703525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 27713525Sshidokht 27723525Sshidokht lbasize = cl->cl_sys_blocksize; 27733525Sshidokht 27743525Sshidokht cl->cl_reserved = -1; 27753525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 2776786Slclee 2777786Slclee buf = kmem_zalloc(EFI_MIN_ARRAY_SIZE, KM_SLEEP); 27783525Sshidokht 27797563SPrasad.Singamsetty@Sun.COM rval = DK_TG_READ(cl, buf, 0, lbasize, tg_cookie); 2780786Slclee if (rval) { 27811071Sshidokht iofailed = 1; 2782786Slclee goto done_err; 2783786Slclee } 2784786Slclee if (((struct dk_label *)buf)->dkl_magic == DKL_MAGIC) { 2785786Slclee /* not ours */ 2786786Slclee rval = ESRCH; 2787786Slclee goto done_err; 2788786Slclee } 2789786Slclee 27907563SPrasad.Singamsetty@Sun.COM #if defined(_FIRMWARE_NEEDS_FDISK) 27918863SEdward.Pilatowicz@Sun.COM if (!cmlb_check_efi_mbr(buf, &is_mbr)) { 27928863SEdward.Pilatowicz@Sun.COM if (is_mbr) 27937563SPrasad.Singamsetty@Sun.COM rval = ESRCH; 27947563SPrasad.Singamsetty@Sun.COM else 27957563SPrasad.Singamsetty@Sun.COM rval = EINVAL; 27967563SPrasad.Singamsetty@Sun.COM goto done_err; 27977563SPrasad.Singamsetty@Sun.COM } 27987563SPrasad.Singamsetty@Sun.COM #else 27998863SEdward.Pilatowicz@Sun.COM if (!cmlb_check_efi_mbr(buf, NULL)) { 28005624Sshidokht rval = EINVAL; 28015624Sshidokht goto done_err; 28025624Sshidokht } 28035624Sshidokht 28047563SPrasad.Singamsetty@Sun.COM #endif 28057563SPrasad.Singamsetty@Sun.COM 28063525Sshidokht rval = DK_TG_READ(cl, buf, 1, lbasize, tg_cookie); 2807786Slclee if (rval) { 28081071Sshidokht iofailed = 1; 2809786Slclee goto done_err; 2810786Slclee } 2811786Slclee cmlb_swap_efi_gpt((efi_gpt_t *)buf); 2812786Slclee 2813786Slclee if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) { 2814786Slclee /* 2815786Slclee * Couldn't read the primary, try the backup. Our 2816786Slclee * capacity at this point could be based on CHS, so 2817786Slclee * check what the device reports. 2818786Slclee */ 28193525Sshidokht rval = DK_TG_GETCAP(cl, &cap, tg_cookie); 2820786Slclee if (rval) { 28211071Sshidokht iofailed = 1; 2822786Slclee goto done_err; 2823786Slclee } 28243525Sshidokht 28253525Sshidokht /* 28263525Sshidokht * CMLB_OFF_BY_ONE case, we check the next to last block first 28273525Sshidokht * for backup GPT header, otherwise check the last block. 28283525Sshidokht */ 28293525Sshidokht 28303525Sshidokht if ((rval = DK_TG_READ(cl, buf, 28313525Sshidokht cap - ((cl->cl_alter_behavior & CMLB_OFF_BY_ONE) ? 2 : 1), 28323525Sshidokht lbasize, tg_cookie)) 28333525Sshidokht != 0) { 28341071Sshidokht iofailed = 1; 2835786Slclee goto done_err; 2836786Slclee } 2837786Slclee cmlb_swap_efi_gpt((efi_gpt_t *)buf); 28383525Sshidokht 28393525Sshidokht if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) { 28403525Sshidokht 28413525Sshidokht if (!(cl->cl_alter_behavior & CMLB_OFF_BY_ONE)) 28423525Sshidokht goto done_err; 28433525Sshidokht if ((rval = DK_TG_READ(cl, buf, cap - 1, lbasize, 28443525Sshidokht tg_cookie)) != 0) 28453525Sshidokht goto done_err; 28463525Sshidokht cmlb_swap_efi_gpt((efi_gpt_t *)buf); 28473525Sshidokht if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) 28483525Sshidokht goto done_err; 28493525Sshidokht } 28503525Sshidokht if (!(flags & CMLB_SILENT)) 28513525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN, 28523525Sshidokht "primary label corrupt; using backup\n"); 2853786Slclee } 2854786Slclee 2855786Slclee nparts = ((efi_gpt_t *)buf)->efi_gpt_NumberOfPartitionEntries; 2856786Slclee gpe_lba = ((efi_gpt_t *)buf)->efi_gpt_PartitionEntryLBA; 28576590Syl194034 alternate_lba = ((efi_gpt_t *)buf)->efi_gpt_AlternateLBA; 2858786Slclee 28593525Sshidokht rval = DK_TG_READ(cl, buf, gpe_lba, EFI_MIN_ARRAY_SIZE, tg_cookie); 2860786Slclee if (rval) { 28611071Sshidokht iofailed = 1; 2862786Slclee goto done_err; 2863786Slclee } 2864786Slclee partitions = (efi_gpe_t *)buf; 2865786Slclee 2866786Slclee if (nparts > MAXPART) { 2867786Slclee nparts = MAXPART; 2868786Slclee } 2869786Slclee cmlb_swap_efi_gpe(nparts, partitions); 2870786Slclee 28713525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 2872786Slclee 2873786Slclee /* Fill in partition table. */ 2874786Slclee for (i = 0; i < nparts; i++) { 2875786Slclee if (partitions->efi_gpe_StartingLBA != 0 || 2876786Slclee partitions->efi_gpe_EndingLBA != 0) { 28773525Sshidokht cl->cl_map[i].dkl_cylno = 2878786Slclee partitions->efi_gpe_StartingLBA; 28793525Sshidokht cl->cl_map[i].dkl_nblk = 2880786Slclee partitions->efi_gpe_EndingLBA - 2881786Slclee partitions->efi_gpe_StartingLBA + 1; 28823525Sshidokht cl->cl_offset[i] = 2883786Slclee partitions->efi_gpe_StartingLBA; 2884786Slclee } 28853525Sshidokht 28863525Sshidokht if (cl->cl_reserved == -1) { 28873525Sshidokht if (bcmp(&partitions->efi_gpe_PartitionTypeGUID, 28883525Sshidokht &uuid_type_reserved, sizeof (struct uuid)) == 0) { 28893525Sshidokht cl->cl_reserved = i; 28903525Sshidokht } 28913525Sshidokht } 2892786Slclee if (i == WD_NODE) { 2893786Slclee /* 2894786Slclee * minor number 7 corresponds to the whole disk 28956590Syl194034 * if the disk capacity is expanded after disk is 28966590Syl194034 * labeled, minor number 7 represents the capacity 28976590Syl194034 * indicated by the disk label. 2898786Slclee */ 28993525Sshidokht cl->cl_map[i].dkl_cylno = 0; 29006590Syl194034 if (alternate_lba == 1) { 29016590Syl194034 /* 29026590Syl194034 * We are using backup label. Since we can 29036590Syl194034 * find a valid label at the end of disk, 29046590Syl194034 * the disk capacity is not expanded. 29056590Syl194034 */ 29066590Syl194034 cl->cl_map[i].dkl_nblk = capacity; 29076590Syl194034 } else { 29086590Syl194034 cl->cl_map[i].dkl_nblk = alternate_lba + 1; 29096590Syl194034 } 29103525Sshidokht cl->cl_offset[i] = 0; 2911786Slclee } 2912786Slclee partitions++; 2913786Slclee } 29143525Sshidokht cl->cl_solaris_offset = 0; 29153525Sshidokht cl->cl_solaris_size = capacity; 29167563SPrasad.Singamsetty@Sun.COM cl->cl_label_from_media = CMLB_LABEL_EFI; 29178863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_TRUE; 29183525Sshidokht 29193525Sshidokht /* clear the vtoc label */ 29203525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc)); 29213525Sshidokht 2922786Slclee kmem_free(buf, EFI_MIN_ARRAY_SIZE); 2923786Slclee return (0); 2924786Slclee 2925786Slclee done_err: 2926786Slclee kmem_free(buf, EFI_MIN_ARRAY_SIZE); 29273525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 29283525Sshidokht done_err1: 2929786Slclee /* 2930786Slclee * if we didn't find something that could look like a VTOC 2931786Slclee * and the disk is over 1TB, we know there isn't a valid label. 2932786Slclee * Otherwise let cmlb_uselabel decide what to do. We only 2933786Slclee * want to invalidate this if we're certain the label isn't 2934786Slclee * valid because cmlb_prop_op will now fail, which in turn 2935786Slclee * causes things like opens and stats on the partition to fail. 2936786Slclee */ 29377563SPrasad.Singamsetty@Sun.COM if ((capacity > CMLB_EXTVTOC_LIMIT) && (rval != ESRCH) && !iofailed) { 29388863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE; 2939786Slclee } 2940786Slclee return (rval); 2941786Slclee } 2942786Slclee 2943786Slclee 2944786Slclee /* 2945786Slclee * Function: cmlb_uselabel 2946786Slclee * 2947786Slclee * Description: Validate the disk label and update the relevant data (geometry, 2948786Slclee * partition, vtoc, and capacity data) in the cmlb_lun struct. 2949786Slclee * Marks the geometry of the unit as being valid. 2950786Slclee * 29513525Sshidokht * Arguments: cl: unit struct. 2952786Slclee * dk_label: disk label 2953786Slclee * 2954786Slclee * Return Code: CMLB_LABEL_IS_VALID: Label read from disk is OK; geometry, 2955786Slclee * partition, vtoc, and capacity data are good. 2956786Slclee * 2957786Slclee * CMLB_LABEL_IS_INVALID: Magic number or checksum error in the 2958786Slclee * label; or computed capacity does not jibe with capacity 2959786Slclee * reported from the READ CAPACITY command. 2960786Slclee * 2961786Slclee * Context: Kernel thread only (can sleep). 2962786Slclee */ 2963786Slclee static int 29643525Sshidokht cmlb_uselabel(struct cmlb_lun *cl, struct dk_label *labp, int flags) 2965786Slclee { 2966786Slclee short *sp; 2967786Slclee short sum; 2968786Slclee short count; 2969786Slclee int label_error = CMLB_LABEL_IS_VALID; 2970786Slclee int i; 2971786Slclee diskaddr_t label_capacity; 29727563SPrasad.Singamsetty@Sun.COM uint32_t part_end; 2973786Slclee diskaddr_t track_capacity; 2974786Slclee #if defined(_SUNOS_VTOC_16) 2975786Slclee struct dkl_partition *vpartp; 2976786Slclee #endif 29773525Sshidokht ASSERT(cl != NULL); 29783525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 2979786Slclee 2980786Slclee /* Validate the magic number of the label. */ 2981786Slclee if (labp->dkl_magic != DKL_MAGIC) { 2982786Slclee #if defined(__sparc) 29833525Sshidokht if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) { 29843525Sshidokht if (!(flags & CMLB_SILENT)) 29853525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), 29863525Sshidokht CE_WARN, 29873525Sshidokht "Corrupt label; wrong magic number\n"); 2988786Slclee } 2989786Slclee #endif 2990786Slclee return (CMLB_LABEL_IS_INVALID); 2991786Slclee } 2992786Slclee 2993786Slclee /* Validate the checksum of the label. */ 2994786Slclee sp = (short *)labp; 2995786Slclee sum = 0; 2996786Slclee count = sizeof (struct dk_label) / sizeof (short); 2997786Slclee while (count--) { 2998786Slclee sum ^= *sp++; 2999786Slclee } 3000786Slclee 3001786Slclee if (sum != 0) { 3002786Slclee #if defined(_SUNOS_VTOC_16) 30033525Sshidokht if (!ISCD(cl)) { 3004786Slclee #elif defined(_SUNOS_VTOC_8) 30053525Sshidokht if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) { 3006786Slclee #endif 30073525Sshidokht if (!(flags & CMLB_SILENT)) 30083525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), 30093525Sshidokht CE_WARN, 30103525Sshidokht "Corrupt label - label checksum failed\n"); 3011786Slclee } 3012786Slclee return (CMLB_LABEL_IS_INVALID); 3013786Slclee } 3014786Slclee 3015786Slclee 3016786Slclee /* 3017786Slclee * Fill in geometry structure with data from label. 3018786Slclee */ 30193525Sshidokht bzero(&cl->cl_g, sizeof (struct dk_geom)); 30203525Sshidokht cl->cl_g.dkg_ncyl = labp->dkl_ncyl; 30213525Sshidokht cl->cl_g.dkg_acyl = labp->dkl_acyl; 30223525Sshidokht cl->cl_g.dkg_bcyl = 0; 30233525Sshidokht cl->cl_g.dkg_nhead = labp->dkl_nhead; 30243525Sshidokht cl->cl_g.dkg_nsect = labp->dkl_nsect; 30253525Sshidokht cl->cl_g.dkg_intrlv = labp->dkl_intrlv; 3026786Slclee 3027786Slclee #if defined(_SUNOS_VTOC_8) 30283525Sshidokht cl->cl_g.dkg_gap1 = labp->dkl_gap1; 30293525Sshidokht cl->cl_g.dkg_gap2 = labp->dkl_gap2; 30303525Sshidokht cl->cl_g.dkg_bhead = labp->dkl_bhead; 3031786Slclee #endif 3032786Slclee #if defined(_SUNOS_VTOC_16) 30333525Sshidokht cl->cl_dkg_skew = labp->dkl_skew; 3034786Slclee #endif 3035786Slclee 3036786Slclee #if defined(__i386) || defined(__amd64) 30373525Sshidokht cl->cl_g.dkg_apc = labp->dkl_apc; 3038786Slclee #endif 3039786Slclee 3040786Slclee /* 3041786Slclee * Currently we rely on the values in the label being accurate. If 3042786Slclee * dkl_rpm or dkl_pcly are zero in the label, use a default value. 3043786Slclee * 3044786Slclee * Note: In the future a MODE SENSE may be used to retrieve this data, 3045786Slclee * although this command is optional in SCSI-2. 3046786Slclee */ 30473525Sshidokht cl->cl_g.dkg_rpm = (labp->dkl_rpm != 0) ? labp->dkl_rpm : 3600; 30483525Sshidokht cl->cl_g.dkg_pcyl = (labp->dkl_pcyl != 0) ? labp->dkl_pcyl : 30493525Sshidokht (cl->cl_g.dkg_ncyl + cl->cl_g.dkg_acyl); 3050786Slclee 3051786Slclee /* 3052786Slclee * The Read and Write reinstruct values may not be valid 3053786Slclee * for older disks. 3054786Slclee */ 30553525Sshidokht cl->cl_g.dkg_read_reinstruct = labp->dkl_read_reinstruct; 30563525Sshidokht cl->cl_g.dkg_write_reinstruct = labp->dkl_write_reinstruct; 3057786Slclee 3058786Slclee /* Fill in partition table. */ 3059786Slclee #if defined(_SUNOS_VTOC_8) 3060786Slclee for (i = 0; i < NDKMAP; i++) { 30613525Sshidokht cl->cl_map[i].dkl_cylno = labp->dkl_map[i].dkl_cylno; 30623525Sshidokht cl->cl_map[i].dkl_nblk = labp->dkl_map[i].dkl_nblk; 3063786Slclee } 3064786Slclee #endif 3065786Slclee #if defined(_SUNOS_VTOC_16) 3066786Slclee vpartp = labp->dkl_vtoc.v_part; 3067786Slclee track_capacity = labp->dkl_nhead * labp->dkl_nsect; 3068786Slclee 30693525Sshidokht /* Prevent divide by zero */ 30703525Sshidokht if (track_capacity == 0) { 30713525Sshidokht if (!(flags & CMLB_SILENT)) 30723525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN, 30733525Sshidokht "Corrupt label - zero nhead or nsect value\n"); 30743525Sshidokht 30753525Sshidokht return (CMLB_LABEL_IS_INVALID); 30763525Sshidokht } 30773525Sshidokht 3078786Slclee for (i = 0; i < NDKMAP; i++, vpartp++) { 30793525Sshidokht cl->cl_map[i].dkl_cylno = vpartp->p_start / track_capacity; 30803525Sshidokht cl->cl_map[i].dkl_nblk = vpartp->p_size; 3081786Slclee } 3082786Slclee #endif 3083786Slclee 3084786Slclee /* Fill in VTOC Structure. */ 30853525Sshidokht bcopy(&labp->dkl_vtoc, &cl->cl_vtoc, sizeof (struct dk_vtoc)); 3086786Slclee #if defined(_SUNOS_VTOC_8) 3087786Slclee /* 3088786Slclee * The 8-slice vtoc does not include the ascii label; save it into 3089786Slclee * the device's soft state structure here. 3090786Slclee */ 30913525Sshidokht bcopy(labp->dkl_asciilabel, cl->cl_asciilabel, LEN_DKL_ASCII); 3092786Slclee #endif 3093786Slclee 3094786Slclee /* Now look for a valid capacity. */ 30953525Sshidokht track_capacity = (cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect); 30963525Sshidokht label_capacity = (cl->cl_g.dkg_ncyl * track_capacity); 30973525Sshidokht 30983525Sshidokht if (cl->cl_g.dkg_acyl) { 3099786Slclee #if defined(__i386) || defined(__amd64) 3100786Slclee /* we may have > 1 alts cylinder */ 31013525Sshidokht label_capacity += (track_capacity * cl->cl_g.dkg_acyl); 3102786Slclee #else 3103786Slclee label_capacity += track_capacity; 3104786Slclee #endif 3105786Slclee } 3106786Slclee 3107786Slclee /* 31083525Sshidokht * Force check here to ensure the computed capacity is valid. 31093525Sshidokht * If capacity is zero, it indicates an invalid label and 31103525Sshidokht * we should abort updating the relevant data then. 31113525Sshidokht */ 31123525Sshidokht if (label_capacity == 0) { 31133525Sshidokht if (!(flags & CMLB_SILENT)) 31143525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN, 31153525Sshidokht "Corrupt label - no valid capacity could be " 31163525Sshidokht "retrieved\n"); 31173525Sshidokht 31183525Sshidokht return (CMLB_LABEL_IS_INVALID); 31193525Sshidokht } 31203525Sshidokht 31213525Sshidokht /* Mark the geometry as valid. */ 31228863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_TRUE; 31233525Sshidokht 31243525Sshidokht /* 3125786Slclee * if we got invalidated when mutex exit and entered again, 3126786Slclee * if blockcount different than when we came in, need to 3127786Slclee * retry from beginning of cmlb_validate_geometry. 3128786Slclee * revisit this on next phase of utilizing this for 3129786Slclee * sd. 3130786Slclee */ 3131786Slclee 31323525Sshidokht if (label_capacity <= cl->cl_blockcount) { 3133786Slclee #if defined(_SUNOS_VTOC_8) 3134786Slclee /* 3135786Slclee * We can't let this happen on drives that are subdivided 3136786Slclee * into logical disks (i.e., that have an fdisk table). 31373525Sshidokht * The cl_blockcount field should always hold the full media 3138786Slclee * size in sectors, period. This code would overwrite 31393525Sshidokht * cl_blockcount with the size of the Solaris fdisk partition. 3140786Slclee */ 31413525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 3142786Slclee "cmlb_uselabel: Label %d blocks; Drive %d blocks\n", 31433525Sshidokht label_capacity, cl->cl_blockcount); 31443525Sshidokht cl->cl_solaris_size = label_capacity; 3145786Slclee 3146786Slclee #endif /* defined(_SUNOS_VTOC_8) */ 3147786Slclee goto done; 3148786Slclee } 3149786Slclee 31503525Sshidokht if (ISCD(cl)) { 3151786Slclee /* For CDROMs, we trust that the data in the label is OK. */ 3152786Slclee #if defined(_SUNOS_VTOC_8) 3153786Slclee for (i = 0; i < NDKMAP; i++) { 3154786Slclee part_end = labp->dkl_nhead * labp->dkl_nsect * 3155786Slclee labp->dkl_map[i].dkl_cylno + 3156786Slclee labp->dkl_map[i].dkl_nblk - 1; 3157786Slclee 3158786Slclee if ((labp->dkl_map[i].dkl_nblk) && 31593525Sshidokht (part_end > cl->cl_blockcount)) { 31608863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE; 3161786Slclee break; 3162786Slclee } 3163786Slclee } 3164786Slclee #endif 3165786Slclee #if defined(_SUNOS_VTOC_16) 3166786Slclee vpartp = &(labp->dkl_vtoc.v_part[0]); 3167786Slclee for (i = 0; i < NDKMAP; i++, vpartp++) { 3168786Slclee part_end = vpartp->p_start + vpartp->p_size; 3169786Slclee if ((vpartp->p_size > 0) && 31703525Sshidokht (part_end > cl->cl_blockcount)) { 31718863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE; 3172786Slclee break; 3173786Slclee } 3174786Slclee } 3175786Slclee #endif 3176786Slclee } else { 31773525Sshidokht /* label_capacity > cl->cl_blockcount */ 31783525Sshidokht if (!(flags & CMLB_SILENT)) { 31793525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN, 31803525Sshidokht "Corrupt label - bad geometry\n"); 31813525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_CONT, 31823525Sshidokht "Label says %llu blocks; Drive says %llu blocks\n", 31833525Sshidokht label_capacity, cl->cl_blockcount); 31843525Sshidokht } 31858863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE; 3186786Slclee label_error = CMLB_LABEL_IS_INVALID; 3187786Slclee } 3188786Slclee 3189786Slclee done: 3190786Slclee 31913525Sshidokht cmlb_dbg(CMLB_INFO, cl, "cmlb_uselabel: (label geometry)\n"); 31923525Sshidokht cmlb_dbg(CMLB_INFO, cl, 3193786Slclee " ncyl: %d; acyl: %d; nhead: %d; nsect: %d\n", 31943525Sshidokht cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl, 31953525Sshidokht cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect); 31963525Sshidokht 31973525Sshidokht cmlb_dbg(CMLB_INFO, cl, 3198786Slclee " label_capacity: %d; intrlv: %d; rpm: %d\n", 31993525Sshidokht cl->cl_blockcount, cl->cl_g.dkg_intrlv, cl->cl_g.dkg_rpm); 32003525Sshidokht cmlb_dbg(CMLB_INFO, cl, " wrt_reinstr: %d; rd_reinstr: %d\n", 32013525Sshidokht cl->cl_g.dkg_write_reinstruct, cl->cl_g.dkg_read_reinstruct); 32023525Sshidokht 32033525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 3204786Slclee 3205786Slclee return (label_error); 3206786Slclee } 3207786Slclee 3208786Slclee 3209786Slclee /* 3210786Slclee * Function: cmlb_build_default_label 3211786Slclee * 3212786Slclee * Description: Generate a default label for those devices that do not have 3213786Slclee * one, e.g., new media, removable cartridges, etc.. 3214786Slclee * 3215786Slclee * Context: Kernel thread only 3216786Slclee */ 32173525Sshidokht /*ARGSUSED*/ 3218786Slclee static void 32193525Sshidokht cmlb_build_default_label(struct cmlb_lun *cl, void *tg_cookie) 3220786Slclee { 3221786Slclee #if defined(_SUNOS_VTOC_16) 3222786Slclee uint_t phys_spc; 3223786Slclee uint_t disksize; 32243525Sshidokht struct dk_geom cl_g; 32253525Sshidokht diskaddr_t capacity; 3226786Slclee #endif 3227786Slclee 32283525Sshidokht ASSERT(cl != NULL); 32293525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 3230786Slclee 3231786Slclee #if defined(_SUNOS_VTOC_8) 3232786Slclee /* 3233786Slclee * Note: This is a legacy check for non-removable devices on VTOC_8 3234786Slclee * only. This may be a valid check for VTOC_16 as well. 32353525Sshidokht * Once we understand why there is this difference between SPARC and 32363525Sshidokht * x86 platform, we could remove this legacy check. 3237786Slclee */ 32383525Sshidokht if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) { 3239786Slclee return; 3240786Slclee } 3241786Slclee #endif 3242786Slclee 32433525Sshidokht bzero(&cl->cl_g, sizeof (struct dk_geom)); 32443525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc)); 32453525Sshidokht bzero(&cl->cl_map, NDKMAP * (sizeof (struct dk_map))); 3246786Slclee 3247786Slclee #if defined(_SUNOS_VTOC_8) 3248786Slclee 3249786Slclee /* 3250786Slclee * It's a REMOVABLE media, therefore no label (on sparc, anyway). 3251786Slclee * But it is still necessary to set up various geometry information, 3252786Slclee * and we are doing this here. 3253786Slclee */ 3254786Slclee 3255786Slclee /* 3256786Slclee * For the rpm, we use the minimum for the disk. For the head, cyl, 3257786Slclee * and number of sector per track, if the capacity <= 1GB, head = 64, 3258786Slclee * sect = 32. else head = 255, sect 63 Note: the capacity should be 3259786Slclee * equal to C*H*S values. This will cause some truncation of size due 3260786Slclee * to round off errors. For CD-ROMs, this truncation can have adverse 3261786Slclee * side effects, so returning ncyl and nhead as 1. The nsect will 3262786Slclee * overflow for most of CD-ROMs as nsect is of type ushort. (4190569) 3263786Slclee */ 32643525Sshidokht cl->cl_solaris_size = cl->cl_blockcount; 32653525Sshidokht if (ISCD(cl)) { 3266786Slclee tg_attribute_t tgattribute; 3267786Slclee int is_writable; 3268786Slclee /* 3269786Slclee * Preserve the old behavior for non-writable 3270786Slclee * medias. Since dkg_nsect is a ushort, it 3271786Slclee * will lose bits as cdroms have more than 3272786Slclee * 65536 sectors. So if we recalculate 3273786Slclee * capacity, it will become much shorter. 3274786Slclee * But the dkg_* information is not 3275786Slclee * used for CDROMs so it is OK. But for 3276786Slclee * Writable CDs we need this information 3277786Slclee * to be valid (for newfs say). So we 3278786Slclee * make nsect and nhead > 1 that way 3279786Slclee * nsect can still stay within ushort limit 3280786Slclee * without losing any bits. 3281786Slclee */ 3282786Slclee 3283786Slclee bzero(&tgattribute, sizeof (tg_attribute_t)); 3284786Slclee 32853525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 32863525Sshidokht is_writable = 32873525Sshidokht (DK_TG_GETATTRIBUTE(cl, &tgattribute, tg_cookie) == 0) ? 3288786Slclee tgattribute.media_is_writable : 1; 32893525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 3290786Slclee 3291786Slclee if (is_writable) { 32923525Sshidokht cl->cl_g.dkg_nhead = 64; 32933525Sshidokht cl->cl_g.dkg_nsect = 32; 32943525Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount / (64 * 32); 32957563SPrasad.Singamsetty@Sun.COM cl->cl_solaris_size = (diskaddr_t)cl->cl_g.dkg_ncyl * 32963525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect; 3297786Slclee } else { 32983525Sshidokht cl->cl_g.dkg_ncyl = 1; 32993525Sshidokht cl->cl_g.dkg_nhead = 1; 33003525Sshidokht cl->cl_g.dkg_nsect = cl->cl_blockcount; 3301786Slclee } 3302786Slclee } else { 33033525Sshidokht if (cl->cl_blockcount <= 0x1000) { 3304786Slclee /* unlabeled SCSI floppy device */ 33053525Sshidokht cl->cl_g.dkg_nhead = 2; 33063525Sshidokht cl->cl_g.dkg_ncyl = 80; 33073525Sshidokht cl->cl_g.dkg_nsect = cl->cl_blockcount / (2 * 80); 33083525Sshidokht } else if (cl->cl_blockcount <= 0x200000) { 33093525Sshidokht cl->cl_g.dkg_nhead = 64; 33103525Sshidokht cl->cl_g.dkg_nsect = 32; 33113525Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount / (64 * 32); 3312786Slclee } else { 33133525Sshidokht cl->cl_g.dkg_nhead = 255; 33146124Sshidokht 33156124Sshidokht cl->cl_g.dkg_nsect = ((cl->cl_blockcount + 33166124Sshidokht (UINT16_MAX * 255 * 63) - 1) / 33176124Sshidokht (UINT16_MAX * 255 * 63)) * 63; 33186124Sshidokht 33196124Sshidokht if (cl->cl_g.dkg_nsect == 0) 33206124Sshidokht cl->cl_g.dkg_nsect = (UINT16_MAX / 63) * 63; 33216124Sshidokht 33226124Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount / 33236124Sshidokht (255 * cl->cl_g.dkg_nsect); 3324786Slclee } 33256124Sshidokht 33263525Sshidokht cl->cl_solaris_size = 33277563SPrasad.Singamsetty@Sun.COM (diskaddr_t)cl->cl_g.dkg_ncyl * cl->cl_g.dkg_nhead * 33287563SPrasad.Singamsetty@Sun.COM cl->cl_g.dkg_nsect; 3329786Slclee 3330786Slclee } 3331786Slclee 33323525Sshidokht cl->cl_g.dkg_acyl = 0; 33333525Sshidokht cl->cl_g.dkg_bcyl = 0; 33343525Sshidokht cl->cl_g.dkg_rpm = 200; 33353525Sshidokht cl->cl_asciilabel[0] = '\0'; 33363525Sshidokht cl->cl_g.dkg_pcyl = cl->cl_g.dkg_ncyl; 33373525Sshidokht 33383525Sshidokht cl->cl_map[0].dkl_cylno = 0; 33393525Sshidokht cl->cl_map[0].dkl_nblk = cl->cl_solaris_size; 33403525Sshidokht 33413525Sshidokht cl->cl_map[2].dkl_cylno = 0; 33423525Sshidokht cl->cl_map[2].dkl_nblk = cl->cl_solaris_size; 3343786Slclee 3344786Slclee #elif defined(_SUNOS_VTOC_16) 3345786Slclee 33463525Sshidokht if (cl->cl_solaris_size == 0) { 3347786Slclee /* 3348786Slclee * Got fdisk table but no solaris entry therefore 3349786Slclee * don't create a default label 3350786Slclee */ 33518863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_TRUE; 3352786Slclee return; 3353786Slclee } 3354786Slclee 3355786Slclee /* 3356786Slclee * For CDs we continue to use the physical geometry to calculate 3357786Slclee * number of cylinders. All other devices must convert the 3358786Slclee * physical geometry (cmlb_geom) to values that will fit 3359786Slclee * in a dk_geom structure. 3360786Slclee */ 33613525Sshidokht if (ISCD(cl)) { 33623525Sshidokht phys_spc = cl->cl_pgeom.g_nhead * cl->cl_pgeom.g_nsect; 3363786Slclee } else { 3364786Slclee /* Convert physical geometry to disk geometry */ 33653525Sshidokht bzero(&cl_g, sizeof (struct dk_geom)); 33663525Sshidokht 33673525Sshidokht /* 33683525Sshidokht * Refer to comments related to off-by-1 at the 33693525Sshidokht * header of this file. 33707224Scth * Before calculating geometry, capacity should be 33713525Sshidokht * decreased by 1. 33723525Sshidokht */ 33733525Sshidokht 33743525Sshidokht if (cl->cl_alter_behavior & CMLB_OFF_BY_ONE) 33753525Sshidokht capacity = cl->cl_blockcount - 1; 33763525Sshidokht else 33773525Sshidokht capacity = cl->cl_blockcount; 33783525Sshidokht 33793525Sshidokht 338010320SLarry.Liu@Sun.COM cmlb_convert_geometry(cl, capacity, &cl_g, tg_cookie); 33813525Sshidokht bcopy(&cl_g, &cl->cl_g, sizeof (cl->cl_g)); 33823525Sshidokht phys_spc = cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect; 3383786Slclee } 3384786Slclee 33859811SSheshadri.Vasudevan@Sun.COM if (phys_spc == 0) 33869811SSheshadri.Vasudevan@Sun.COM return; 33873525Sshidokht cl->cl_g.dkg_pcyl = cl->cl_solaris_size / phys_spc; 33885084Sjohnlev if (cl->cl_alter_behavior & CMLB_FAKE_LABEL_ONE_PARTITION) { 33895084Sjohnlev /* disable devid */ 33905084Sjohnlev cl->cl_g.dkg_ncyl = cl->cl_g.dkg_pcyl; 33915084Sjohnlev disksize = cl->cl_solaris_size; 33925084Sjohnlev } else { 33935084Sjohnlev cl->cl_g.dkg_acyl = DK_ACYL; 33945084Sjohnlev cl->cl_g.dkg_ncyl = cl->cl_g.dkg_pcyl - DK_ACYL; 33955084Sjohnlev disksize = cl->cl_g.dkg_ncyl * phys_spc; 33965084Sjohnlev } 33973525Sshidokht 33983525Sshidokht if (ISCD(cl)) { 3399786Slclee /* 3400786Slclee * CD's don't use the "heads * sectors * cyls"-type of 3401786Slclee * geometry, but instead use the entire capacity of the media. 3402786Slclee */ 34033525Sshidokht disksize = cl->cl_solaris_size; 34043525Sshidokht cl->cl_g.dkg_nhead = 1; 34053525Sshidokht cl->cl_g.dkg_nsect = 1; 34063525Sshidokht cl->cl_g.dkg_rpm = 34073525Sshidokht (cl->cl_pgeom.g_rpm == 0) ? 200 : cl->cl_pgeom.g_rpm; 34083525Sshidokht 34093525Sshidokht cl->cl_vtoc.v_part[0].p_start = 0; 34103525Sshidokht cl->cl_vtoc.v_part[0].p_size = disksize; 34113525Sshidokht cl->cl_vtoc.v_part[0].p_tag = V_BACKUP; 34123525Sshidokht cl->cl_vtoc.v_part[0].p_flag = V_UNMNT; 34133525Sshidokht 34143525Sshidokht cl->cl_map[0].dkl_cylno = 0; 34153525Sshidokht cl->cl_map[0].dkl_nblk = disksize; 34163525Sshidokht cl->cl_offset[0] = 0; 3417786Slclee 3418786Slclee } else { 3419786Slclee /* 3420786Slclee * Hard disks and removable media cartridges 3421786Slclee */ 34223525Sshidokht cl->cl_g.dkg_rpm = 34233525Sshidokht (cl->cl_pgeom.g_rpm == 0) ? 3600: cl->cl_pgeom.g_rpm; 34243525Sshidokht cl->cl_vtoc.v_sectorsz = cl->cl_sys_blocksize; 3425786Slclee 3426786Slclee /* Add boot slice */ 34273525Sshidokht cl->cl_vtoc.v_part[8].p_start = 0; 34283525Sshidokht cl->cl_vtoc.v_part[8].p_size = phys_spc; 34293525Sshidokht cl->cl_vtoc.v_part[8].p_tag = V_BOOT; 34303525Sshidokht cl->cl_vtoc.v_part[8].p_flag = V_UNMNT; 34313525Sshidokht 34323525Sshidokht cl->cl_map[8].dkl_cylno = 0; 34333525Sshidokht cl->cl_map[8].dkl_nblk = phys_spc; 34343525Sshidokht cl->cl_offset[8] = 0; 34353525Sshidokht 34363525Sshidokht if ((cl->cl_alter_behavior & 3437786Slclee CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT) && 34383525Sshidokht cl->cl_device_type == DTYPE_DIRECT) { 34393525Sshidokht cl->cl_vtoc.v_part[9].p_start = phys_spc; 34403525Sshidokht cl->cl_vtoc.v_part[9].p_size = 2 * phys_spc; 34413525Sshidokht cl->cl_vtoc.v_part[9].p_tag = V_ALTSCTR; 34423525Sshidokht cl->cl_vtoc.v_part[9].p_flag = 0; 34433525Sshidokht 34443525Sshidokht cl->cl_map[9].dkl_cylno = 1; 34453525Sshidokht cl->cl_map[9].dkl_nblk = 2 * phys_spc; 34463525Sshidokht cl->cl_offset[9] = phys_spc; 3447786Slclee } 3448786Slclee } 3449786Slclee 34503525Sshidokht cl->cl_g.dkg_apc = 0; 3451786Slclee 3452786Slclee /* Add backup slice */ 34533525Sshidokht cl->cl_vtoc.v_part[2].p_start = 0; 34543525Sshidokht cl->cl_vtoc.v_part[2].p_size = disksize; 34553525Sshidokht cl->cl_vtoc.v_part[2].p_tag = V_BACKUP; 34563525Sshidokht cl->cl_vtoc.v_part[2].p_flag = V_UNMNT; 34573525Sshidokht 34583525Sshidokht cl->cl_map[2].dkl_cylno = 0; 34593525Sshidokht cl->cl_map[2].dkl_nblk = disksize; 34603525Sshidokht cl->cl_offset[2] = 0; 34613525Sshidokht 34625084Sjohnlev /* 34635084Sjohnlev * single slice (s0) covering the entire disk 34645084Sjohnlev */ 34655084Sjohnlev if (cl->cl_alter_behavior & CMLB_FAKE_LABEL_ONE_PARTITION) { 34665084Sjohnlev cl->cl_vtoc.v_part[0].p_start = 0; 34675084Sjohnlev cl->cl_vtoc.v_part[0].p_tag = V_UNASSIGNED; 34685084Sjohnlev cl->cl_vtoc.v_part[0].p_flag = 0; 34695084Sjohnlev cl->cl_vtoc.v_part[0].p_size = disksize; 34705084Sjohnlev cl->cl_map[0].dkl_cylno = 0; 34715084Sjohnlev cl->cl_map[0].dkl_nblk = disksize; 34725084Sjohnlev cl->cl_offset[0] = 0; 34735084Sjohnlev } 34745084Sjohnlev 34753525Sshidokht (void) sprintf(cl->cl_vtoc.v_asciilabel, "DEFAULT cyl %d alt %d" 34763525Sshidokht " hd %d sec %d", cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl, 34773525Sshidokht cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect); 3478786Slclee 3479786Slclee #else 3480786Slclee #error "No VTOC format defined." 3481786Slclee #endif 3482786Slclee 34833525Sshidokht cl->cl_g.dkg_read_reinstruct = 0; 34843525Sshidokht cl->cl_g.dkg_write_reinstruct = 0; 34853525Sshidokht 34863525Sshidokht cl->cl_g.dkg_intrlv = 1; 34873525Sshidokht 34883525Sshidokht cl->cl_vtoc.v_sanity = VTOC_SANE; 34898169SGabriel.Carrillo@Sun.COM cl->cl_vtoc.v_nparts = V_NUMPAR; 34908169SGabriel.Carrillo@Sun.COM cl->cl_vtoc.v_version = V_VERSION; 34913525Sshidokht 34928863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_TRUE; 34937563SPrasad.Singamsetty@Sun.COM cl->cl_label_from_media = CMLB_LABEL_UNDEF; 34943525Sshidokht 34953525Sshidokht cmlb_dbg(CMLB_INFO, cl, 3496786Slclee "cmlb_build_default_label: Default label created: " 3497786Slclee "cyl: %d\tacyl: %d\tnhead: %d\tnsect: %d\tcap: %d\n", 34983525Sshidokht cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl, cl->cl_g.dkg_nhead, 34993525Sshidokht cl->cl_g.dkg_nsect, cl->cl_blockcount); 3500786Slclee } 3501786Slclee 3502786Slclee 3503786Slclee #if defined(_FIRMWARE_NEEDS_FDISK) 3504786Slclee /* 3505786Slclee * Max CHS values, as they are encoded into bytes, for 1022/254/63 3506786Slclee */ 3507786Slclee #define LBA_MAX_SECT (63 | ((1022 & 0x300) >> 2)) 3508786Slclee #define LBA_MAX_CYL (1022 & 0xFF) 3509786Slclee #define LBA_MAX_HEAD (254) 3510786Slclee 3511786Slclee 3512786Slclee /* 3513786Slclee * Function: cmlb_has_max_chs_vals 3514786Slclee * 35158863SEdward.Pilatowicz@Sun.COM * Description: Return B_TRUE if Cylinder-Head-Sector values are all at maximum. 3516786Slclee * 3517786Slclee * Arguments: fdp - ptr to CHS info 3518786Slclee * 3519786Slclee * Return Code: True or false 3520786Slclee * 3521786Slclee * Context: Any. 3522786Slclee */ 35238863SEdward.Pilatowicz@Sun.COM static boolean_t 3524786Slclee cmlb_has_max_chs_vals(struct ipart *fdp) 3525786Slclee { 3526786Slclee return ((fdp->begcyl == LBA_MAX_CYL) && 3527786Slclee (fdp->beghead == LBA_MAX_HEAD) && 3528786Slclee (fdp->begsect == LBA_MAX_SECT) && 3529786Slclee (fdp->endcyl == LBA_MAX_CYL) && 3530786Slclee (fdp->endhead == LBA_MAX_HEAD) && 3531786Slclee (fdp->endsect == LBA_MAX_SECT)); 3532786Slclee } 3533786Slclee #endif 3534786Slclee 3535786Slclee /* 3536786Slclee * Function: cmlb_dkio_get_geometry 3537786Slclee * 3538786Slclee * Description: This routine is the driver entry point for handling user 3539786Slclee * requests to get the device geometry (DKIOCGGEOM). 3540786Slclee * 3541786Slclee * Arguments: 35423525Sshidokht * arg pointer to user provided dk_geom structure specifying 3543786Slclee * the controller's notion of the current geometry. 35443525Sshidokht * 35453525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 35463525Sshidokht * directly from the mode argument of ioctl(). 35473525Sshidokht * 35483525Sshidokht * tg_cookie cookie from target driver to be passed back to target 35493525Sshidokht * driver when we call back to it through tg_ops. 3550786Slclee * 3551786Slclee * Return Code: 0 3552786Slclee * EFAULT 3553786Slclee * ENXIO 3554786Slclee * EIO 3555786Slclee */ 3556786Slclee static int 35573525Sshidokht cmlb_dkio_get_geometry(struct cmlb_lun *cl, caddr_t arg, int flag, 35583525Sshidokht void *tg_cookie) 3559786Slclee { 3560786Slclee struct dk_geom *tmp_geom = NULL; 3561786Slclee int rval = 0; 3562786Slclee 3563786Slclee /* 3564786Slclee * cmlb_validate_geometry does not spin a disk up 35653525Sshidokht * if it was spcl down. We need to make sure it 3566786Slclee * is ready. 3567786Slclee */ 35683525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 35698863SEdward.Pilatowicz@Sun.COM rval = cmlb_validate_geometry(cl, B_TRUE, 0, tg_cookie); 3570786Slclee #if defined(_SUNOS_VTOC_8) 3571786Slclee if (rval == EINVAL && 35723525Sshidokht cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8) { 3573786Slclee /* 3574786Slclee * This is to return a default label geometry even when we 3575786Slclee * do not really assume a default label for the device. 3576786Slclee * dad driver utilizes this. 3577786Slclee */ 35787563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount <= CMLB_OLDVTOC_LIMIT) { 35793525Sshidokht cmlb_setup_default_geometry(cl, tg_cookie); 3580786Slclee rval = 0; 3581786Slclee } 3582786Slclee } 3583786Slclee #endif 3584786Slclee if (rval) { 35853525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3586786Slclee return (rval); 3587786Slclee } 3588786Slclee 3589786Slclee #if defined(__i386) || defined(__amd64) 35903525Sshidokht if (cl->cl_solaris_size == 0) { 35913525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3592786Slclee return (EIO); 3593786Slclee } 3594786Slclee #endif 3595786Slclee 3596786Slclee /* 3597786Slclee * Make a local copy of the soft state geometry to avoid some potential 3598786Slclee * race conditions associated with holding the mutex and updating the 3599786Slclee * write_reinstruct value 3600786Slclee */ 3601786Slclee tmp_geom = kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP); 36023525Sshidokht bcopy(&cl->cl_g, tmp_geom, sizeof (struct dk_geom)); 3603786Slclee 3604786Slclee if (tmp_geom->dkg_write_reinstruct == 0) { 3605786Slclee tmp_geom->dkg_write_reinstruct = 3606786Slclee (int)((int)(tmp_geom->dkg_nsect * tmp_geom->dkg_rpm * 3607786Slclee cmlb_rot_delay) / (int)60000); 3608786Slclee } 36093525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3610786Slclee 3611786Slclee rval = ddi_copyout(tmp_geom, (void *)arg, sizeof (struct dk_geom), 3612786Slclee flag); 3613786Slclee if (rval != 0) { 3614786Slclee rval = EFAULT; 3615786Slclee } 3616786Slclee 3617786Slclee kmem_free(tmp_geom, sizeof (struct dk_geom)); 3618786Slclee return (rval); 3619786Slclee 3620786Slclee } 3621786Slclee 3622786Slclee 3623786Slclee /* 3624786Slclee * Function: cmlb_dkio_set_geometry 3625786Slclee * 3626786Slclee * Description: This routine is the driver entry point for handling user 3627786Slclee * requests to set the device geometry (DKIOCSGEOM). The actual 3628786Slclee * device geometry is not updated, just the driver "notion" of it. 3629786Slclee * 3630786Slclee * Arguments: 36313525Sshidokht * arg pointer to user provided dk_geom structure used to set 3632786Slclee * the controller's notion of the current geometry. 36333525Sshidokht * 36343525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 36353525Sshidokht * directly from the mode argument of ioctl(). 36363525Sshidokht * 36373525Sshidokht * tg_cookie cookie from target driver to be passed back to target 36383525Sshidokht * driver when we call back to it through tg_ops. 3639786Slclee * 3640786Slclee * Return Code: 0 3641786Slclee * EFAULT 3642786Slclee * ENXIO 3643786Slclee * EIO 3644786Slclee */ 3645786Slclee static int 36463525Sshidokht cmlb_dkio_set_geometry(struct cmlb_lun *cl, caddr_t arg, int flag) 3647786Slclee { 3648786Slclee struct dk_geom *tmp_geom; 3649786Slclee struct dk_map *lp; 3650786Slclee int rval = 0; 3651786Slclee int i; 3652786Slclee 3653786Slclee 3654786Slclee #if defined(__i386) || defined(__amd64) 36553525Sshidokht if (cl->cl_solaris_size == 0) { 3656786Slclee return (EIO); 3657786Slclee } 3658786Slclee #endif 3659786Slclee /* 3660786Slclee * We need to copy the user specified geometry into local 3661786Slclee * storage and then update the softstate. We don't want to hold 3662786Slclee * the mutex and copyin directly from the user to the soft state 3663786Slclee */ 3664786Slclee tmp_geom = (struct dk_geom *) 3665786Slclee kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP); 3666786Slclee rval = ddi_copyin(arg, tmp_geom, sizeof (struct dk_geom), flag); 3667786Slclee if (rval != 0) { 3668786Slclee kmem_free(tmp_geom, sizeof (struct dk_geom)); 3669786Slclee return (EFAULT); 3670786Slclee } 3671786Slclee 36723525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 36733525Sshidokht bcopy(tmp_geom, &cl->cl_g, sizeof (struct dk_geom)); 3674786Slclee for (i = 0; i < NDKMAP; i++) { 36753525Sshidokht lp = &cl->cl_map[i]; 36763525Sshidokht cl->cl_offset[i] = 36773525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno; 3678786Slclee #if defined(__i386) || defined(__amd64) 36793525Sshidokht cl->cl_offset[i] += cl->cl_solaris_offset; 3680786Slclee #endif 3681786Slclee } 36828863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE; 36833525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3684786Slclee kmem_free(tmp_geom, sizeof (struct dk_geom)); 3685786Slclee 3686786Slclee return (rval); 3687786Slclee } 3688786Slclee 3689786Slclee /* 3690786Slclee * Function: cmlb_dkio_get_partition 3691786Slclee * 3692786Slclee * Description: This routine is the driver entry point for handling user 3693786Slclee * requests to get the partition table (DKIOCGAPART). 3694786Slclee * 3695786Slclee * Arguments: 36963525Sshidokht * arg pointer to user provided dk_allmap structure specifying 3697786Slclee * the controller's notion of the current partition table. 36983525Sshidokht * 36993525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 37003525Sshidokht * directly from the mode argument of ioctl(). 37013525Sshidokht * 37023525Sshidokht * tg_cookie cookie from target driver to be passed back to target 37033525Sshidokht * driver when we call back to it through tg_ops. 3704786Slclee * 3705786Slclee * Return Code: 0 3706786Slclee * EFAULT 3707786Slclee * ENXIO 3708786Slclee * EIO 3709786Slclee */ 3710786Slclee static int 37113525Sshidokht cmlb_dkio_get_partition(struct cmlb_lun *cl, caddr_t arg, int flag, 37123525Sshidokht void *tg_cookie) 3713786Slclee { 3714786Slclee int rval = 0; 3715786Slclee int size; 3716786Slclee 3717786Slclee /* 3718786Slclee * Make sure the geometry is valid before getting the partition 3719786Slclee * information. 3720786Slclee */ 37213525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 37228863SEdward.Pilatowicz@Sun.COM if ((rval = cmlb_validate_geometry(cl, B_TRUE, 0, tg_cookie)) != 0) { 37233525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3724786Slclee return (rval); 3725786Slclee } 37263525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3727786Slclee 3728786Slclee #if defined(__i386) || defined(__amd64) 37293525Sshidokht if (cl->cl_solaris_size == 0) { 3730786Slclee return (EIO); 3731786Slclee } 3732786Slclee #endif 3733786Slclee 3734786Slclee #ifdef _MULTI_DATAMODEL 3735786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 3736786Slclee case DDI_MODEL_ILP32: { 3737786Slclee struct dk_map32 dk_map32[NDKMAP]; 3738786Slclee int i; 3739786Slclee 3740786Slclee for (i = 0; i < NDKMAP; i++) { 37413525Sshidokht dk_map32[i].dkl_cylno = cl->cl_map[i].dkl_cylno; 37423525Sshidokht dk_map32[i].dkl_nblk = cl->cl_map[i].dkl_nblk; 3743786Slclee } 3744786Slclee size = NDKMAP * sizeof (struct dk_map32); 3745786Slclee rval = ddi_copyout(dk_map32, (void *)arg, size, flag); 3746786Slclee if (rval != 0) { 3747786Slclee rval = EFAULT; 3748786Slclee } 3749786Slclee break; 3750786Slclee } 3751786Slclee case DDI_MODEL_NONE: 3752786Slclee size = NDKMAP * sizeof (struct dk_map); 37533525Sshidokht rval = ddi_copyout(cl->cl_map, (void *)arg, size, flag); 3754786Slclee if (rval != 0) { 3755786Slclee rval = EFAULT; 3756786Slclee } 3757786Slclee break; 3758786Slclee } 3759786Slclee #else /* ! _MULTI_DATAMODEL */ 3760786Slclee size = NDKMAP * sizeof (struct dk_map); 37613525Sshidokht rval = ddi_copyout(cl->cl_map, (void *)arg, size, flag); 3762786Slclee if (rval != 0) { 3763786Slclee rval = EFAULT; 3764786Slclee } 3765786Slclee #endif /* _MULTI_DATAMODEL */ 3766786Slclee return (rval); 3767786Slclee } 3768786Slclee 3769786Slclee /* 3770786Slclee * Function: cmlb_dkio_set_partition 3771786Slclee * 3772786Slclee * Description: This routine is the driver entry point for handling user 3773786Slclee * requests to set the partition table (DKIOCSAPART). The actual 3774786Slclee * device partition is not updated. 3775786Slclee * 3776786Slclee * Arguments: 3777786Slclee * arg - pointer to user provided dk_allmap structure used to set 3778786Slclee * the controller's notion of the partition table. 3779786Slclee * flag - this argument is a pass through to ddi_copyxxx() 3780786Slclee * directly from the mode argument of ioctl(). 3781786Slclee * 3782786Slclee * Return Code: 0 3783786Slclee * EINVAL 3784786Slclee * EFAULT 3785786Slclee * ENXIO 3786786Slclee * EIO 3787786Slclee */ 3788786Slclee static int 37893525Sshidokht cmlb_dkio_set_partition(struct cmlb_lun *cl, caddr_t arg, int flag) 3790786Slclee { 3791786Slclee struct dk_map dk_map[NDKMAP]; 3792786Slclee struct dk_map *lp; 3793786Slclee int rval = 0; 3794786Slclee int size; 3795786Slclee int i; 3796786Slclee #if defined(_SUNOS_VTOC_16) 3797786Slclee struct dkl_partition *vp; 3798786Slclee #endif 3799786Slclee 3800786Slclee /* 3801786Slclee * Set the map for all logical partitions. We lock 3802786Slclee * the priority just to make sure an interrupt doesn't 3803786Slclee * come in while the map is half updated. 3804786Slclee */ 38053525Sshidokht _NOTE(DATA_READABLE_WITHOUT_LOCK(cmlb_lun::cl_solaris_size)) 38063525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 38073525Sshidokht 38087563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) { 38093525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3810786Slclee return (ENOTSUP); 3811786Slclee } 38123525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 38133525Sshidokht if (cl->cl_solaris_size == 0) { 3814786Slclee return (EIO); 3815786Slclee } 3816786Slclee 3817786Slclee #ifdef _MULTI_DATAMODEL 3818786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 3819786Slclee case DDI_MODEL_ILP32: { 3820786Slclee struct dk_map32 dk_map32[NDKMAP]; 3821786Slclee 3822786Slclee size = NDKMAP * sizeof (struct dk_map32); 3823786Slclee rval = ddi_copyin((void *)arg, dk_map32, size, flag); 3824786Slclee if (rval != 0) { 3825786Slclee return (EFAULT); 3826786Slclee } 3827786Slclee for (i = 0; i < NDKMAP; i++) { 3828786Slclee dk_map[i].dkl_cylno = dk_map32[i].dkl_cylno; 3829786Slclee dk_map[i].dkl_nblk = dk_map32[i].dkl_nblk; 3830786Slclee } 3831786Slclee break; 3832786Slclee } 3833786Slclee case DDI_MODEL_NONE: 3834786Slclee size = NDKMAP * sizeof (struct dk_map); 3835786Slclee rval = ddi_copyin((void *)arg, dk_map, size, flag); 3836786Slclee if (rval != 0) { 3837786Slclee return (EFAULT); 3838786Slclee } 3839786Slclee break; 3840786Slclee } 3841786Slclee #else /* ! _MULTI_DATAMODEL */ 3842786Slclee size = NDKMAP * sizeof (struct dk_map); 3843786Slclee rval = ddi_copyin((void *)arg, dk_map, size, flag); 3844786Slclee if (rval != 0) { 3845786Slclee return (EFAULT); 3846786Slclee } 3847786Slclee #endif /* _MULTI_DATAMODEL */ 3848786Slclee 38493525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 3850786Slclee /* Note: The size used in this bcopy is set based upon the data model */ 38513525Sshidokht bcopy(dk_map, cl->cl_map, size); 3852786Slclee #if defined(_SUNOS_VTOC_16) 38533525Sshidokht vp = (struct dkl_partition *)&(cl->cl_vtoc); 3854786Slclee #endif /* defined(_SUNOS_VTOC_16) */ 3855786Slclee for (i = 0; i < NDKMAP; i++) { 38563525Sshidokht lp = &cl->cl_map[i]; 38573525Sshidokht cl->cl_offset[i] = 38583525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno; 3859786Slclee #if defined(_SUNOS_VTOC_16) 38603525Sshidokht vp->p_start = cl->cl_offset[i]; 3861786Slclee vp->p_size = lp->dkl_nblk; 3862786Slclee vp++; 3863786Slclee #endif /* defined(_SUNOS_VTOC_16) */ 3864786Slclee #if defined(__i386) || defined(__amd64) 38653525Sshidokht cl->cl_offset[i] += cl->cl_solaris_offset; 3866786Slclee #endif 3867786Slclee } 38683525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3869786Slclee return (rval); 3870786Slclee } 3871786Slclee 3872786Slclee 3873786Slclee /* 3874786Slclee * Function: cmlb_dkio_get_vtoc 3875786Slclee * 3876786Slclee * Description: This routine is the driver entry point for handling user 3877786Slclee * requests to get the current volume table of contents 3878786Slclee * (DKIOCGVTOC). 3879786Slclee * 3880786Slclee * Arguments: 38813525Sshidokht * arg pointer to user provided vtoc structure specifying 3882786Slclee * the current vtoc. 38833525Sshidokht * 38843525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 38853525Sshidokht * directly from the mode argument of ioctl(). 38863525Sshidokht * 38873525Sshidokht * tg_cookie cookie from target driver to be passed back to target 38883525Sshidokht * driver when we call back to it through tg_ops. 3889786Slclee * 3890786Slclee * Return Code: 0 3891786Slclee * EFAULT 3892786Slclee * ENXIO 3893786Slclee * EIO 3894786Slclee */ 3895786Slclee static int 38963525Sshidokht cmlb_dkio_get_vtoc(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie) 3897786Slclee { 3898786Slclee #if defined(_SUNOS_VTOC_8) 3899786Slclee struct vtoc user_vtoc; 3900786Slclee #endif /* defined(_SUNOS_VTOC_8) */ 3901786Slclee int rval = 0; 3902786Slclee 39033525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 39047563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) { 39057563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 39067563SPrasad.Singamsetty@Sun.COM return (EOVERFLOW); 39077563SPrasad.Singamsetty@Sun.COM } 39087563SPrasad.Singamsetty@Sun.COM 39098863SEdward.Pilatowicz@Sun.COM rval = cmlb_validate_geometry(cl, B_TRUE, 0, tg_cookie); 3910786Slclee 3911786Slclee #if defined(_SUNOS_VTOC_8) 3912786Slclee if (rval == EINVAL && 39133525Sshidokht (cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8)) { 3914786Slclee /* 3915786Slclee * This is to return a default label even when we do not 3916786Slclee * really assume a default label for the device. 3917786Slclee * dad driver utilizes this. 3918786Slclee */ 39197563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount <= CMLB_OLDVTOC_LIMIT) { 39203525Sshidokht cmlb_setup_default_geometry(cl, tg_cookie); 3921786Slclee rval = 0; 3922786Slclee } 3923786Slclee } 3924786Slclee #endif 3925786Slclee if (rval) { 39263525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3927786Slclee return (rval); 3928786Slclee } 3929786Slclee 3930786Slclee #if defined(_SUNOS_VTOC_8) 39313525Sshidokht cmlb_build_user_vtoc(cl, &user_vtoc); 39323525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3933786Slclee 3934786Slclee #ifdef _MULTI_DATAMODEL 3935786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 3936786Slclee case DDI_MODEL_ILP32: { 3937786Slclee struct vtoc32 user_vtoc32; 3938786Slclee 3939786Slclee vtoctovtoc32(user_vtoc, user_vtoc32); 3940786Slclee if (ddi_copyout(&user_vtoc32, (void *)arg, 3941786Slclee sizeof (struct vtoc32), flag)) { 3942786Slclee return (EFAULT); 3943786Slclee } 3944786Slclee break; 3945786Slclee } 3946786Slclee 3947786Slclee case DDI_MODEL_NONE: 3948786Slclee if (ddi_copyout(&user_vtoc, (void *)arg, 3949786Slclee sizeof (struct vtoc), flag)) { 3950786Slclee return (EFAULT); 3951786Slclee } 3952786Slclee break; 3953786Slclee } 3954786Slclee #else /* ! _MULTI_DATAMODEL */ 3955786Slclee if (ddi_copyout(&user_vtoc, (void *)arg, sizeof (struct vtoc), flag)) { 3956786Slclee return (EFAULT); 3957786Slclee } 3958786Slclee #endif /* _MULTI_DATAMODEL */ 3959786Slclee 3960786Slclee #elif defined(_SUNOS_VTOC_16) 39613525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 3962786Slclee 3963786Slclee #ifdef _MULTI_DATAMODEL 3964786Slclee /* 39653525Sshidokht * The cl_vtoc structure is a "struct dk_vtoc" which is always 3966786Slclee * 32-bit to maintain compatibility with existing on-disk 3967786Slclee * structures. Thus, we need to convert the structure when copying 3968786Slclee * it out to a datamodel-dependent "struct vtoc" in a 64-bit 3969786Slclee * program. If the target is a 32-bit program, then no conversion 3970786Slclee * is necessary. 3971786Slclee */ 3972786Slclee /* LINTED: logical expression always true: op "||" */ 39733525Sshidokht ASSERT(sizeof (cl->cl_vtoc) == sizeof (struct vtoc32)); 3974786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 3975786Slclee case DDI_MODEL_ILP32: 39763525Sshidokht if (ddi_copyout(&(cl->cl_vtoc), (void *)arg, 39773525Sshidokht sizeof (cl->cl_vtoc), flag)) { 3978786Slclee return (EFAULT); 3979786Slclee } 3980786Slclee break; 3981786Slclee 3982786Slclee case DDI_MODEL_NONE: { 3983786Slclee struct vtoc user_vtoc; 3984786Slclee 39853525Sshidokht vtoc32tovtoc(cl->cl_vtoc, user_vtoc); 3986786Slclee if (ddi_copyout(&user_vtoc, (void *)arg, 3987786Slclee sizeof (struct vtoc), flag)) { 3988786Slclee return (EFAULT); 3989786Slclee } 3990786Slclee break; 3991786Slclee } 3992786Slclee } 3993786Slclee #else /* ! _MULTI_DATAMODEL */ 39943525Sshidokht if (ddi_copyout(&(cl->cl_vtoc), (void *)arg, sizeof (cl->cl_vtoc), 3995786Slclee flag)) { 3996786Slclee return (EFAULT); 3997786Slclee } 3998786Slclee #endif /* _MULTI_DATAMODEL */ 3999786Slclee #else 4000786Slclee #error "No VTOC format defined." 4001786Slclee #endif 4002786Slclee 4003786Slclee return (rval); 4004786Slclee } 4005786Slclee 40067563SPrasad.Singamsetty@Sun.COM 40077563SPrasad.Singamsetty@Sun.COM /* 40087563SPrasad.Singamsetty@Sun.COM * Function: cmlb_dkio_get_extvtoc 40097563SPrasad.Singamsetty@Sun.COM */ 40107563SPrasad.Singamsetty@Sun.COM static int 40117563SPrasad.Singamsetty@Sun.COM cmlb_dkio_get_extvtoc(struct cmlb_lun *cl, caddr_t arg, int flag, 40127563SPrasad.Singamsetty@Sun.COM void *tg_cookie) 40137563SPrasad.Singamsetty@Sun.COM { 40147563SPrasad.Singamsetty@Sun.COM struct extvtoc ext_vtoc; 40157563SPrasad.Singamsetty@Sun.COM #if defined(_SUNOS_VTOC_8) 40167563SPrasad.Singamsetty@Sun.COM struct vtoc user_vtoc; 40177563SPrasad.Singamsetty@Sun.COM #endif /* defined(_SUNOS_VTOC_8) */ 40187563SPrasad.Singamsetty@Sun.COM int rval = 0; 40197563SPrasad.Singamsetty@Sun.COM 40207563SPrasad.Singamsetty@Sun.COM bzero(&ext_vtoc, sizeof (struct extvtoc)); 40217563SPrasad.Singamsetty@Sun.COM mutex_enter(CMLB_MUTEX(cl)); 40228863SEdward.Pilatowicz@Sun.COM rval = cmlb_validate_geometry(cl, B_TRUE, 0, tg_cookie); 40237563SPrasad.Singamsetty@Sun.COM 40247563SPrasad.Singamsetty@Sun.COM #if defined(_SUNOS_VTOC_8) 40257563SPrasad.Singamsetty@Sun.COM if (rval == EINVAL && 40267563SPrasad.Singamsetty@Sun.COM (cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8)) { 40277563SPrasad.Singamsetty@Sun.COM /* 40287563SPrasad.Singamsetty@Sun.COM * This is to return a default label even when we do not 40297563SPrasad.Singamsetty@Sun.COM * really assume a default label for the device. 40307563SPrasad.Singamsetty@Sun.COM * dad driver utilizes this. 40317563SPrasad.Singamsetty@Sun.COM */ 40327563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount <= CMLB_OLDVTOC_LIMIT) { 40337563SPrasad.Singamsetty@Sun.COM cmlb_setup_default_geometry(cl, tg_cookie); 40347563SPrasad.Singamsetty@Sun.COM rval = 0; 40357563SPrasad.Singamsetty@Sun.COM } 40367563SPrasad.Singamsetty@Sun.COM } 40377563SPrasad.Singamsetty@Sun.COM #endif 40387563SPrasad.Singamsetty@Sun.COM if (rval) { 40397563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 40407563SPrasad.Singamsetty@Sun.COM return (rval); 40417563SPrasad.Singamsetty@Sun.COM } 40427563SPrasad.Singamsetty@Sun.COM 40437563SPrasad.Singamsetty@Sun.COM #if defined(_SUNOS_VTOC_8) 40447563SPrasad.Singamsetty@Sun.COM cmlb_build_user_vtoc(cl, &user_vtoc); 40457563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 40467563SPrasad.Singamsetty@Sun.COM 40477563SPrasad.Singamsetty@Sun.COM /* 40487563SPrasad.Singamsetty@Sun.COM * Checking callers data model does not make much sense here 40497563SPrasad.Singamsetty@Sun.COM * since extvtoc will always be equivalent to 64bit vtoc. 40507563SPrasad.Singamsetty@Sun.COM * What is important is whether the kernel is in 32 or 64 bit 40517563SPrasad.Singamsetty@Sun.COM */ 40527563SPrasad.Singamsetty@Sun.COM 40537563SPrasad.Singamsetty@Sun.COM #ifdef _LP64 40547563SPrasad.Singamsetty@Sun.COM if (ddi_copyout(&user_vtoc, (void *)arg, 40557563SPrasad.Singamsetty@Sun.COM sizeof (struct extvtoc), flag)) { 40567563SPrasad.Singamsetty@Sun.COM return (EFAULT); 40577563SPrasad.Singamsetty@Sun.COM } 40587563SPrasad.Singamsetty@Sun.COM #else 40597563SPrasad.Singamsetty@Sun.COM vtoc32tovtoc(user_vtoc, ext_vtoc); 40607563SPrasad.Singamsetty@Sun.COM if (ddi_copyout(&ext_vtoc, (void *)arg, 40617563SPrasad.Singamsetty@Sun.COM sizeof (struct extvtoc), flag)) { 40627563SPrasad.Singamsetty@Sun.COM return (EFAULT); 40637563SPrasad.Singamsetty@Sun.COM } 40647563SPrasad.Singamsetty@Sun.COM #endif 40657563SPrasad.Singamsetty@Sun.COM 40667563SPrasad.Singamsetty@Sun.COM #elif defined(_SUNOS_VTOC_16) 40677563SPrasad.Singamsetty@Sun.COM /* 40687563SPrasad.Singamsetty@Sun.COM * The cl_vtoc structure is a "struct dk_vtoc" which is always 40697563SPrasad.Singamsetty@Sun.COM * 32-bit to maintain compatibility with existing on-disk 40707563SPrasad.Singamsetty@Sun.COM * structures. Thus, we need to convert the structure when copying 40717563SPrasad.Singamsetty@Sun.COM * it out to extvtoc 40727563SPrasad.Singamsetty@Sun.COM */ 40737563SPrasad.Singamsetty@Sun.COM vtoc32tovtoc(cl->cl_vtoc, ext_vtoc); 40747909SXiao.L@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 40757563SPrasad.Singamsetty@Sun.COM 40767563SPrasad.Singamsetty@Sun.COM if (ddi_copyout(&ext_vtoc, (void *)arg, sizeof (struct extvtoc), flag)) 40777563SPrasad.Singamsetty@Sun.COM return (EFAULT); 40787563SPrasad.Singamsetty@Sun.COM #else 40797563SPrasad.Singamsetty@Sun.COM #error "No VTOC format defined." 40807563SPrasad.Singamsetty@Sun.COM #endif 40817563SPrasad.Singamsetty@Sun.COM 40827563SPrasad.Singamsetty@Sun.COM return (rval); 40837563SPrasad.Singamsetty@Sun.COM } 4084786Slclee static int 40853525Sshidokht cmlb_dkio_get_efi(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie) 4086786Slclee { 4087786Slclee dk_efi_t user_efi; 4088786Slclee int rval = 0; 4089786Slclee void *buffer; 40903525Sshidokht diskaddr_t tgt_lba; 4091786Slclee 4092786Slclee if (ddi_copyin(arg, &user_efi, sizeof (dk_efi_t), flag)) 4093786Slclee return (EFAULT); 4094786Slclee 4095786Slclee user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64; 4096786Slclee 40973525Sshidokht tgt_lba = user_efi.dki_lba; 40983525Sshidokht 40993525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 41003525Sshidokht if ((cmlb_check_update_blockcount(cl, tg_cookie) != 0) || 41013525Sshidokht (cl->cl_tgt_blocksize == 0)) { 41023525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 41033525Sshidokht return (EINVAL); 41043525Sshidokht } 41053525Sshidokht if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) 41063525Sshidokht tgt_lba = tgt_lba * cl->cl_tgt_blocksize / 41073525Sshidokht cl->cl_sys_blocksize; 41083525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 41093525Sshidokht 4110786Slclee buffer = kmem_alloc(user_efi.dki_length, KM_SLEEP); 41113525Sshidokht rval = DK_TG_READ(cl, buffer, tgt_lba, user_efi.dki_length, tg_cookie); 4112786Slclee if (rval == 0 && ddi_copyout(buffer, user_efi.dki_data, 4113786Slclee user_efi.dki_length, flag) != 0) 4114786Slclee rval = EFAULT; 4115786Slclee 4116786Slclee kmem_free(buffer, user_efi.dki_length); 4117786Slclee return (rval); 4118786Slclee } 4119786Slclee 41203525Sshidokht #if defined(_SUNOS_VTOC_8) 4121786Slclee /* 4122786Slclee * Function: cmlb_build_user_vtoc 4123786Slclee * 4124786Slclee * Description: This routine populates a pass by reference variable with the 4125786Slclee * current volume table of contents. 4126786Slclee * 41273525Sshidokht * Arguments: cl - driver soft state (unit) structure 4128786Slclee * user_vtoc - pointer to vtoc structure to be populated 4129786Slclee */ 4130786Slclee static void 41313525Sshidokht cmlb_build_user_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc) 4132786Slclee { 4133786Slclee struct dk_map2 *lpart; 4134786Slclee struct dk_map *lmap; 4135786Slclee struct partition *vpart; 41367563SPrasad.Singamsetty@Sun.COM uint32_t nblks; 4137786Slclee int i; 4138786Slclee 41393525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 4140786Slclee 4141786Slclee /* 4142786Slclee * Return vtoc structure fields in the provided VTOC area, addressed 4143786Slclee * by *vtoc. 4144786Slclee */ 4145786Slclee bzero(user_vtoc, sizeof (struct vtoc)); 41463525Sshidokht user_vtoc->v_bootinfo[0] = cl->cl_vtoc.v_bootinfo[0]; 41473525Sshidokht user_vtoc->v_bootinfo[1] = cl->cl_vtoc.v_bootinfo[1]; 41483525Sshidokht user_vtoc->v_bootinfo[2] = cl->cl_vtoc.v_bootinfo[2]; 4149786Slclee user_vtoc->v_sanity = VTOC_SANE; 41503525Sshidokht user_vtoc->v_version = cl->cl_vtoc.v_version; 41513525Sshidokht bcopy(cl->cl_vtoc.v_volume, user_vtoc->v_volume, LEN_DKL_VVOL); 41523525Sshidokht user_vtoc->v_sectorsz = cl->cl_sys_blocksize; 41533525Sshidokht user_vtoc->v_nparts = cl->cl_vtoc.v_nparts; 4154786Slclee 4155786Slclee for (i = 0; i < 10; i++) 41563525Sshidokht user_vtoc->v_reserved[i] = cl->cl_vtoc.v_reserved[i]; 4157786Slclee 4158786Slclee /* 4159786Slclee * Convert partitioning information. 4160786Slclee * 4161786Slclee * Note the conversion from starting cylinder number 4162786Slclee * to starting sector number. 4163786Slclee */ 41643525Sshidokht lmap = cl->cl_map; 41653525Sshidokht lpart = (struct dk_map2 *)cl->cl_vtoc.v_part; 4166786Slclee vpart = user_vtoc->v_part; 4167786Slclee 41683525Sshidokht nblks = cl->cl_g.dkg_nsect * cl->cl_g.dkg_nhead; 4169786Slclee 4170786Slclee for (i = 0; i < V_NUMPAR; i++) { 4171786Slclee vpart->p_tag = lpart->p_tag; 4172786Slclee vpart->p_flag = lpart->p_flag; 4173786Slclee vpart->p_start = lmap->dkl_cylno * nblks; 4174786Slclee vpart->p_size = lmap->dkl_nblk; 4175786Slclee lmap++; 4176786Slclee lpart++; 4177786Slclee vpart++; 4178786Slclee 4179786Slclee /* (4364927) */ 41803525Sshidokht user_vtoc->timestamp[i] = (time_t)cl->cl_vtoc.v_timestamp[i]; 4181786Slclee } 4182786Slclee 41833525Sshidokht bcopy(cl->cl_asciilabel, user_vtoc->v_asciilabel, LEN_DKL_ASCII); 4184786Slclee } 41853525Sshidokht #endif 4186786Slclee 4187786Slclee static int 41883525Sshidokht cmlb_dkio_partition(struct cmlb_lun *cl, caddr_t arg, int flag, 41893525Sshidokht void *tg_cookie) 4190786Slclee { 4191786Slclee struct partition64 p64; 4192786Slclee int rval = 0; 4193786Slclee uint_t nparts; 4194786Slclee efi_gpe_t *partitions; 4195786Slclee efi_gpt_t *buffer; 4196786Slclee diskaddr_t gpe_lba; 4197786Slclee 4198786Slclee if (ddi_copyin((const void *)arg, &p64, 4199786Slclee sizeof (struct partition64), flag)) { 4200786Slclee return (EFAULT); 4201786Slclee } 4202786Slclee 4203786Slclee buffer = kmem_alloc(EFI_MIN_ARRAY_SIZE, KM_SLEEP); 42049889SLarry.Liu@Sun.COM rval = DK_TG_READ(cl, buffer, 1, cl->cl_sys_blocksize, tg_cookie); 4205786Slclee if (rval != 0) 4206786Slclee goto done_error; 4207786Slclee 4208786Slclee cmlb_swap_efi_gpt(buffer); 4209786Slclee 4210786Slclee if ((rval = cmlb_validate_efi(buffer)) != 0) 4211786Slclee goto done_error; 4212786Slclee 4213786Slclee nparts = buffer->efi_gpt_NumberOfPartitionEntries; 4214786Slclee gpe_lba = buffer->efi_gpt_PartitionEntryLBA; 4215786Slclee if (p64.p_partno > nparts) { 4216786Slclee /* couldn't find it */ 4217786Slclee rval = ESRCH; 4218786Slclee goto done_error; 4219786Slclee } 4220786Slclee /* 4221786Slclee * if we're dealing with a partition that's out of the normal 4222786Slclee * 16K block, adjust accordingly 4223786Slclee */ 4224786Slclee gpe_lba += p64.p_partno / sizeof (efi_gpe_t); 42253525Sshidokht rval = DK_TG_READ(cl, buffer, gpe_lba, EFI_MIN_ARRAY_SIZE, tg_cookie); 4226786Slclee 4227786Slclee if (rval) { 4228786Slclee goto done_error; 4229786Slclee } 4230786Slclee partitions = (efi_gpe_t *)buffer; 4231786Slclee 4232786Slclee cmlb_swap_efi_gpe(nparts, partitions); 4233786Slclee 4234786Slclee partitions += p64.p_partno; 4235786Slclee bcopy(&partitions->efi_gpe_PartitionTypeGUID, &p64.p_type, 4236786Slclee sizeof (struct uuid)); 4237786Slclee p64.p_start = partitions->efi_gpe_StartingLBA; 4238786Slclee p64.p_size = partitions->efi_gpe_EndingLBA - 42393525Sshidokht p64.p_start + 1; 4240786Slclee 4241786Slclee if (ddi_copyout(&p64, (void *)arg, sizeof (struct partition64), flag)) 4242786Slclee rval = EFAULT; 4243786Slclee 4244786Slclee done_error: 4245786Slclee kmem_free(buffer, EFI_MIN_ARRAY_SIZE); 4246786Slclee return (rval); 4247786Slclee } 4248786Slclee 4249786Slclee 4250786Slclee /* 4251786Slclee * Function: cmlb_dkio_set_vtoc 4252786Slclee * 4253786Slclee * Description: This routine is the driver entry point for handling user 4254786Slclee * requests to set the current volume table of contents 4255786Slclee * (DKIOCSVTOC). 4256786Slclee * 42573525Sshidokht * Arguments: 42583525Sshidokht * dev the device number 42593525Sshidokht * arg pointer to user provided vtoc structure used to set the 4260786Slclee * current vtoc. 42613525Sshidokht * 42623525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 42633525Sshidokht * directly from the mode argument of ioctl(). 42643525Sshidokht * 42653525Sshidokht * tg_cookie cookie from target driver to be passed back to target 42663525Sshidokht * driver when we call back to it through tg_ops. 4267786Slclee * 4268786Slclee * Return Code: 0 4269786Slclee * EFAULT 4270786Slclee * ENXIO 4271786Slclee * EINVAL 4272786Slclee * ENOTSUP 4273786Slclee */ 4274786Slclee static int 42753525Sshidokht cmlb_dkio_set_vtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag, 42763525Sshidokht void *tg_cookie) 4277786Slclee { 4278786Slclee struct vtoc user_vtoc; 4279786Slclee int rval = 0; 42806318Sedp boolean_t internal; 42816318Sedp 42828863SEdward.Pilatowicz@Sun.COM internal = VOID2BOOLEAN( 42838863SEdward.Pilatowicz@Sun.COM (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0); 4284786Slclee 4285786Slclee #ifdef _MULTI_DATAMODEL 4286786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 4287786Slclee case DDI_MODEL_ILP32: { 4288786Slclee struct vtoc32 user_vtoc32; 4289786Slclee 4290786Slclee if (ddi_copyin((const void *)arg, &user_vtoc32, 4291786Slclee sizeof (struct vtoc32), flag)) { 4292786Slclee return (EFAULT); 4293786Slclee } 4294786Slclee vtoc32tovtoc(user_vtoc32, user_vtoc); 4295786Slclee break; 4296786Slclee } 4297786Slclee 4298786Slclee case DDI_MODEL_NONE: 4299786Slclee if (ddi_copyin((const void *)arg, &user_vtoc, 4300786Slclee sizeof (struct vtoc), flag)) { 4301786Slclee return (EFAULT); 4302786Slclee } 4303786Slclee break; 4304786Slclee } 4305786Slclee #else /* ! _MULTI_DATAMODEL */ 4306786Slclee if (ddi_copyin((const void *)arg, &user_vtoc, 4307786Slclee sizeof (struct vtoc), flag)) { 4308786Slclee return (EFAULT); 4309786Slclee } 4310786Slclee #endif /* _MULTI_DATAMODEL */ 4311786Slclee 43123525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 43137563SPrasad.Singamsetty@Sun.COM 43147563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) { 43153525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 43167563SPrasad.Singamsetty@Sun.COM return (EOVERFLOW); 4317786Slclee } 43183525Sshidokht 43193525Sshidokht #if defined(__i386) || defined(__amd64) 43203525Sshidokht if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) { 43213525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 43223525Sshidokht return (EINVAL); 43233525Sshidokht } 43243525Sshidokht #endif 43253525Sshidokht 43263525Sshidokht if (cl->cl_g.dkg_ncyl == 0) { 43273525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4328786Slclee return (EINVAL); 4329786Slclee } 4330786Slclee 43313525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 43323525Sshidokht cmlb_clear_efi(cl, tg_cookie); 43333525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd"); 43343525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd,raw"); 43358570SSriram.Popuri@sun.com 43368570SSriram.Popuri@sun.com /* 43378570SSriram.Popuri@sun.com * cmlb_dkio_set_vtoc creates duplicate minor nodes when 43388570SSriram.Popuri@sun.com * relabeling an SMI disk. To avoid that we remove them 43398570SSriram.Popuri@sun.com * before creating. 43408570SSriram.Popuri@sun.com * It should be OK to remove a non-existed minor node. 43418570SSriram.Popuri@sun.com */ 43428570SSriram.Popuri@sun.com ddi_remove_minor_node(CMLB_DEVINFO(cl), "h"); 43438570SSriram.Popuri@sun.com ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw"); 43448570SSriram.Popuri@sun.com 43456318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h", 4346786Slclee S_IFBLK, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 43476318Sedp cl->cl_node_type, NULL, internal); 43486318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h,raw", 4349786Slclee S_IFCHR, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 43506318Sedp cl->cl_node_type, NULL, internal); 43513525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 43523525Sshidokht 43533525Sshidokht if ((rval = cmlb_build_label_vtoc(cl, &user_vtoc)) == 0) { 43543525Sshidokht if ((rval = cmlb_write_label(cl, tg_cookie)) == 0) { 43558863SEdward.Pilatowicz@Sun.COM if (cmlb_validate_geometry(cl, 43568863SEdward.Pilatowicz@Sun.COM B_TRUE, 0, tg_cookie) != 0) { 43573525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 4358786Slclee "cmlb_dkio_set_vtoc: " 4359786Slclee "Failed validate geometry\n"); 4360786Slclee } 43617563SPrasad.Singamsetty@Sun.COM cl->cl_msglog_flag |= CMLB_ALLOW_2TB_WARN; 4362786Slclee } 4363786Slclee } 43643525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4365786Slclee return (rval); 4366786Slclee } 4367786Slclee 43687563SPrasad.Singamsetty@Sun.COM /* 43697563SPrasad.Singamsetty@Sun.COM * Function: cmlb_dkio_set_extvtoc 43707563SPrasad.Singamsetty@Sun.COM */ 43717563SPrasad.Singamsetty@Sun.COM static int 43727563SPrasad.Singamsetty@Sun.COM cmlb_dkio_set_extvtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag, 43737563SPrasad.Singamsetty@Sun.COM void *tg_cookie) 43747563SPrasad.Singamsetty@Sun.COM { 43757563SPrasad.Singamsetty@Sun.COM int rval = 0; 43767563SPrasad.Singamsetty@Sun.COM struct vtoc user_vtoc; 43778749SShidokht.Yadegari@Sun.COM boolean_t internal; 43788749SShidokht.Yadegari@Sun.COM 43797563SPrasad.Singamsetty@Sun.COM 43807563SPrasad.Singamsetty@Sun.COM /* 43817563SPrasad.Singamsetty@Sun.COM * Checking callers data model does not make much sense here 43827563SPrasad.Singamsetty@Sun.COM * since extvtoc will always be equivalent to 64bit vtoc. 43837563SPrasad.Singamsetty@Sun.COM * What is important is whether the kernel is in 32 or 64 bit 43847563SPrasad.Singamsetty@Sun.COM */ 43857563SPrasad.Singamsetty@Sun.COM 43867563SPrasad.Singamsetty@Sun.COM #ifdef _LP64 43877563SPrasad.Singamsetty@Sun.COM if (ddi_copyin((const void *)arg, &user_vtoc, 43887563SPrasad.Singamsetty@Sun.COM sizeof (struct extvtoc), flag)) { 43897563SPrasad.Singamsetty@Sun.COM return (EFAULT); 43907563SPrasad.Singamsetty@Sun.COM } 43917563SPrasad.Singamsetty@Sun.COM #else 43927563SPrasad.Singamsetty@Sun.COM struct extvtoc user_extvtoc; 43937563SPrasad.Singamsetty@Sun.COM if (ddi_copyin((const void *)arg, &user_extvtoc, 43947563SPrasad.Singamsetty@Sun.COM sizeof (struct extvtoc), flag)) { 43957563SPrasad.Singamsetty@Sun.COM return (EFAULT); 43967563SPrasad.Singamsetty@Sun.COM } 43977563SPrasad.Singamsetty@Sun.COM 43987563SPrasad.Singamsetty@Sun.COM vtoctovtoc32(user_extvtoc, user_vtoc); 43997563SPrasad.Singamsetty@Sun.COM #endif 44007563SPrasad.Singamsetty@Sun.COM 44018863SEdward.Pilatowicz@Sun.COM internal = VOID2BOOLEAN( 44028863SEdward.Pilatowicz@Sun.COM (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0); 44037563SPrasad.Singamsetty@Sun.COM mutex_enter(CMLB_MUTEX(cl)); 44047563SPrasad.Singamsetty@Sun.COM #if defined(__i386) || defined(__amd64) 44057563SPrasad.Singamsetty@Sun.COM if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) { 44067563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 44077563SPrasad.Singamsetty@Sun.COM return (EINVAL); 44087563SPrasad.Singamsetty@Sun.COM } 44097563SPrasad.Singamsetty@Sun.COM #endif 44107563SPrasad.Singamsetty@Sun.COM 44117563SPrasad.Singamsetty@Sun.COM if (cl->cl_g.dkg_ncyl == 0) { 44127563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 44137563SPrasad.Singamsetty@Sun.COM return (EINVAL); 44147563SPrasad.Singamsetty@Sun.COM } 44157563SPrasad.Singamsetty@Sun.COM 44167563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 44177563SPrasad.Singamsetty@Sun.COM cmlb_clear_efi(cl, tg_cookie); 44187563SPrasad.Singamsetty@Sun.COM ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd"); 44197563SPrasad.Singamsetty@Sun.COM ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd,raw"); 442010511SSriram.Popuri@sun.com /* 442110511SSriram.Popuri@sun.com * cmlb_dkio_set_extvtoc creates duplicate minor nodes when 442210511SSriram.Popuri@sun.com * relabeling an SMI disk. To avoid that we remove them 442310511SSriram.Popuri@sun.com * before creating. 442410511SSriram.Popuri@sun.com * It should be OK to remove a non-existed minor node. 442510511SSriram.Popuri@sun.com */ 442610511SSriram.Popuri@sun.com ddi_remove_minor_node(CMLB_DEVINFO(cl), "h"); 442710511SSriram.Popuri@sun.com ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw"); 442810511SSriram.Popuri@sun.com 44298749SShidokht.Yadegari@Sun.COM (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h", 44307563SPrasad.Singamsetty@Sun.COM S_IFBLK, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 44318749SShidokht.Yadegari@Sun.COM cl->cl_node_type, NULL, internal); 44328749SShidokht.Yadegari@Sun.COM (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h,raw", 44337563SPrasad.Singamsetty@Sun.COM S_IFCHR, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 44348749SShidokht.Yadegari@Sun.COM cl->cl_node_type, NULL, internal); 44358749SShidokht.Yadegari@Sun.COM 44367563SPrasad.Singamsetty@Sun.COM mutex_enter(CMLB_MUTEX(cl)); 44377563SPrasad.Singamsetty@Sun.COM 44387563SPrasad.Singamsetty@Sun.COM if ((rval = cmlb_build_label_vtoc(cl, &user_vtoc)) == 0) { 44397563SPrasad.Singamsetty@Sun.COM if ((rval = cmlb_write_label(cl, tg_cookie)) == 0) { 44408863SEdward.Pilatowicz@Sun.COM if (cmlb_validate_geometry(cl, 44418863SEdward.Pilatowicz@Sun.COM B_TRUE, 0, tg_cookie) != 0) { 44427563SPrasad.Singamsetty@Sun.COM cmlb_dbg(CMLB_ERROR, cl, 44437563SPrasad.Singamsetty@Sun.COM "cmlb_dkio_set_vtoc: " 44447563SPrasad.Singamsetty@Sun.COM "Failed validate geometry\n"); 44457563SPrasad.Singamsetty@Sun.COM } 44467563SPrasad.Singamsetty@Sun.COM } 44477563SPrasad.Singamsetty@Sun.COM } 44487563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 44497563SPrasad.Singamsetty@Sun.COM return (rval); 44507563SPrasad.Singamsetty@Sun.COM } 4451786Slclee 4452786Slclee /* 4453786Slclee * Function: cmlb_build_label_vtoc 4454786Slclee * 4455786Slclee * Description: This routine updates the driver soft state current volume table 4456786Slclee * of contents based on a user specified vtoc. 4457786Slclee * 44583525Sshidokht * Arguments: cl - driver soft state (unit) structure 4459786Slclee * user_vtoc - pointer to vtoc structure specifying vtoc to be used 4460786Slclee * to update the driver soft state. 4461786Slclee * 4462786Slclee * Return Code: 0 4463786Slclee * EINVAL 4464786Slclee */ 4465786Slclee static int 44663525Sshidokht cmlb_build_label_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc) 4467786Slclee { 4468786Slclee struct dk_map *lmap; 4469786Slclee struct partition *vpart; 44707563SPrasad.Singamsetty@Sun.COM uint_t nblks; 4471786Slclee #if defined(_SUNOS_VTOC_8) 4472786Slclee int ncyl; 4473786Slclee struct dk_map2 *lpart; 4474786Slclee #endif /* defined(_SUNOS_VTOC_8) */ 4475786Slclee int i; 4476786Slclee 44773525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 4478786Slclee 4479786Slclee /* Sanity-check the vtoc */ 4480786Slclee if (user_vtoc->v_sanity != VTOC_SANE || 44813525Sshidokht user_vtoc->v_sectorsz != cl->cl_sys_blocksize || 4482786Slclee user_vtoc->v_nparts != V_NUMPAR) { 44833525Sshidokht cmlb_dbg(CMLB_INFO, cl, 4484786Slclee "cmlb_build_label_vtoc: vtoc not valid\n"); 4485786Slclee return (EINVAL); 4486786Slclee } 4487786Slclee 44883525Sshidokht nblks = cl->cl_g.dkg_nsect * cl->cl_g.dkg_nhead; 4489786Slclee if (nblks == 0) { 44903525Sshidokht cmlb_dbg(CMLB_INFO, cl, 4491786Slclee "cmlb_build_label_vtoc: geom nblks is 0\n"); 4492786Slclee return (EINVAL); 4493786Slclee } 4494786Slclee 4495786Slclee #if defined(_SUNOS_VTOC_8) 4496786Slclee vpart = user_vtoc->v_part; 4497786Slclee for (i = 0; i < V_NUMPAR; i++) { 44987563SPrasad.Singamsetty@Sun.COM if (((unsigned)vpart->p_start % nblks) != 0) { 44993525Sshidokht cmlb_dbg(CMLB_INFO, cl, 4500786Slclee "cmlb_build_label_vtoc: p_start not multiply of" 4501786Slclee "nblks part %d p_start %d nblks %d\n", i, 4502786Slclee vpart->p_start, nblks); 4503786Slclee return (EINVAL); 4504786Slclee } 45057563SPrasad.Singamsetty@Sun.COM ncyl = (unsigned)vpart->p_start / nblks; 45067563SPrasad.Singamsetty@Sun.COM ncyl += (unsigned)vpart->p_size / nblks; 45077563SPrasad.Singamsetty@Sun.COM if (((unsigned)vpart->p_size % nblks) != 0) { 4508786Slclee ncyl++; 4509786Slclee } 45103525Sshidokht if (ncyl > (int)cl->cl_g.dkg_ncyl) { 45113525Sshidokht cmlb_dbg(CMLB_INFO, cl, 4512786Slclee "cmlb_build_label_vtoc: ncyl %d > dkg_ncyl %d" 4513786Slclee "p_size %ld p_start %ld nblks %d part number %d" 4514786Slclee "tag %d\n", 45153525Sshidokht ncyl, cl->cl_g.dkg_ncyl, vpart->p_size, 4516786Slclee vpart->p_start, nblks, 4517786Slclee i, vpart->p_tag); 4518786Slclee 4519786Slclee return (EINVAL); 4520786Slclee } 4521786Slclee vpart++; 4522786Slclee } 4523786Slclee #endif /* defined(_SUNOS_VTOC_8) */ 4524786Slclee 4525786Slclee /* Put appropriate vtoc structure fields into the disk label */ 4526786Slclee #if defined(_SUNOS_VTOC_16) 4527786Slclee /* 4528786Slclee * The vtoc is always a 32bit data structure to maintain the 4529786Slclee * on-disk format. Convert "in place" instead of doing bcopy. 4530786Slclee */ 45313525Sshidokht vtoctovtoc32((*user_vtoc), (*((struct vtoc32 *)&(cl->cl_vtoc)))); 4532786Slclee 4533786Slclee /* 4534786Slclee * in the 16-slice vtoc, starting sectors are expressed in 4535786Slclee * numbers *relative* to the start of the Solaris fdisk partition. 4536786Slclee */ 45373525Sshidokht lmap = cl->cl_map; 4538786Slclee vpart = user_vtoc->v_part; 4539786Slclee 4540786Slclee for (i = 0; i < (int)user_vtoc->v_nparts; i++, lmap++, vpart++) { 45417563SPrasad.Singamsetty@Sun.COM lmap->dkl_cylno = (unsigned)vpart->p_start / nblks; 45427563SPrasad.Singamsetty@Sun.COM lmap->dkl_nblk = (unsigned)vpart->p_size; 4543786Slclee } 4544786Slclee 4545786Slclee #elif defined(_SUNOS_VTOC_8) 4546786Slclee 45473525Sshidokht cl->cl_vtoc.v_bootinfo[0] = (uint32_t)user_vtoc->v_bootinfo[0]; 45483525Sshidokht cl->cl_vtoc.v_bootinfo[1] = (uint32_t)user_vtoc->v_bootinfo[1]; 45493525Sshidokht cl->cl_vtoc.v_bootinfo[2] = (uint32_t)user_vtoc->v_bootinfo[2]; 45503525Sshidokht 45513525Sshidokht cl->cl_vtoc.v_sanity = (uint32_t)user_vtoc->v_sanity; 45523525Sshidokht cl->cl_vtoc.v_version = (uint32_t)user_vtoc->v_version; 45533525Sshidokht 45543525Sshidokht bcopy(user_vtoc->v_volume, cl->cl_vtoc.v_volume, LEN_DKL_VVOL); 45553525Sshidokht 45563525Sshidokht cl->cl_vtoc.v_nparts = user_vtoc->v_nparts; 4557786Slclee 4558786Slclee for (i = 0; i < 10; i++) 45593525Sshidokht cl->cl_vtoc.v_reserved[i] = user_vtoc->v_reserved[i]; 4560786Slclee 4561786Slclee /* 4562786Slclee * Note the conversion from starting sector number 4563786Slclee * to starting cylinder number. 4564786Slclee * Return error if division results in a remainder. 4565786Slclee */ 45663525Sshidokht lmap = cl->cl_map; 45673525Sshidokht lpart = cl->cl_vtoc.v_part; 4568786Slclee vpart = user_vtoc->v_part; 4569786Slclee 4570786Slclee for (i = 0; i < (int)user_vtoc->v_nparts; i++) { 4571786Slclee lpart->p_tag = vpart->p_tag; 4572786Slclee lpart->p_flag = vpart->p_flag; 45737563SPrasad.Singamsetty@Sun.COM lmap->dkl_cylno = (unsigned)vpart->p_start / nblks; 45747563SPrasad.Singamsetty@Sun.COM lmap->dkl_nblk = (unsigned)vpart->p_size; 4575786Slclee 4576786Slclee lmap++; 4577786Slclee lpart++; 4578786Slclee vpart++; 4579786Slclee 4580786Slclee /* (4387723) */ 4581786Slclee #ifdef _LP64 4582786Slclee if (user_vtoc->timestamp[i] > TIME32_MAX) { 45833525Sshidokht cl->cl_vtoc.v_timestamp[i] = TIME32_MAX; 4584786Slclee } else { 45853525Sshidokht cl->cl_vtoc.v_timestamp[i] = user_vtoc->timestamp[i]; 4586786Slclee } 4587786Slclee #else 45883525Sshidokht cl->cl_vtoc.v_timestamp[i] = user_vtoc->timestamp[i]; 4589786Slclee #endif 4590786Slclee } 4591786Slclee 45923525Sshidokht bcopy(user_vtoc->v_asciilabel, cl->cl_asciilabel, LEN_DKL_ASCII); 4593786Slclee #else 4594786Slclee #error "No VTOC format defined." 4595786Slclee #endif 4596786Slclee return (0); 4597786Slclee } 4598786Slclee 4599786Slclee /* 4600786Slclee * Function: cmlb_clear_efi 4601786Slclee * 4602786Slclee * Description: This routine clears all EFI labels. 4603786Slclee * 46043525Sshidokht * Arguments: 46053525Sshidokht * cl driver soft state (unit) structure 4606786Slclee * 46073525Sshidokht * tg_cookie cookie from target driver to be passed back to target 46083525Sshidokht * driver when we call back to it through tg_ops. 4609786Slclee * Return Code: void 4610786Slclee */ 4611786Slclee static void 46123525Sshidokht cmlb_clear_efi(struct cmlb_lun *cl, void *tg_cookie) 4613786Slclee { 4614786Slclee efi_gpt_t *gpt; 4615786Slclee diskaddr_t cap; 4616786Slclee int rval; 4617786Slclee 46183525Sshidokht ASSERT(!mutex_owned(CMLB_MUTEX(cl))); 46193525Sshidokht 46203525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 46213525Sshidokht cl->cl_reserved = -1; 46223525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4623786Slclee 46249889SLarry.Liu@Sun.COM gpt = kmem_alloc(cl->cl_sys_blocksize, KM_SLEEP); 46259889SLarry.Liu@Sun.COM 46269889SLarry.Liu@Sun.COM if (DK_TG_READ(cl, gpt, 1, cl->cl_sys_blocksize, tg_cookie) != 0) { 4627786Slclee goto done; 4628786Slclee } 4629786Slclee 4630786Slclee cmlb_swap_efi_gpt(gpt); 4631786Slclee rval = cmlb_validate_efi(gpt); 4632786Slclee if (rval == 0) { 4633786Slclee /* clear primary */ 4634786Slclee bzero(gpt, sizeof (efi_gpt_t)); 46359889SLarry.Liu@Sun.COM if (rval = DK_TG_WRITE(cl, gpt, 1, cl->cl_sys_blocksize, 46369889SLarry.Liu@Sun.COM tg_cookie)) { 46373525Sshidokht cmlb_dbg(CMLB_INFO, cl, 46383525Sshidokht "cmlb_clear_efi: clear primary label failed\n"); 4639786Slclee } 4640786Slclee } 4641786Slclee /* the backup */ 46423525Sshidokht rval = DK_TG_GETCAP(cl, &cap, tg_cookie); 4643786Slclee if (rval) { 4644786Slclee goto done; 4645786Slclee } 4646786Slclee 46479889SLarry.Liu@Sun.COM if ((rval = DK_TG_READ(cl, gpt, cap - 1, cl->cl_sys_blocksize, 46489889SLarry.Liu@Sun.COM tg_cookie)) != 0) { 4649786Slclee goto done; 4650786Slclee } 4651786Slclee cmlb_swap_efi_gpt(gpt); 4652786Slclee rval = cmlb_validate_efi(gpt); 4653786Slclee if (rval == 0) { 4654786Slclee /* clear backup */ 46553525Sshidokht cmlb_dbg(CMLB_TRACE, cl, 4656786Slclee "cmlb_clear_efi clear backup@%lu\n", cap - 1); 4657786Slclee bzero(gpt, sizeof (efi_gpt_t)); 46589889SLarry.Liu@Sun.COM if ((rval = DK_TG_WRITE(cl, gpt, cap - 1, cl->cl_sys_blocksize, 46593525Sshidokht tg_cookie))) { 46603525Sshidokht cmlb_dbg(CMLB_INFO, cl, 46613525Sshidokht "cmlb_clear_efi: clear backup label failed\n"); 46623525Sshidokht } 46633525Sshidokht } else { 46643525Sshidokht /* 46653525Sshidokht * Refer to comments related to off-by-1 at the 46663525Sshidokht * header of this file 46673525Sshidokht */ 46683525Sshidokht if ((rval = DK_TG_READ(cl, gpt, cap - 2, 46699889SLarry.Liu@Sun.COM cl->cl_sys_blocksize, tg_cookie)) != 0) { 46703525Sshidokht goto done; 46713525Sshidokht } 46723525Sshidokht cmlb_swap_efi_gpt(gpt); 46733525Sshidokht rval = cmlb_validate_efi(gpt); 46743525Sshidokht if (rval == 0) { 46753525Sshidokht /* clear legacy backup EFI label */ 46763525Sshidokht cmlb_dbg(CMLB_TRACE, cl, 46773525Sshidokht "cmlb_clear_efi clear legacy backup@%lu\n", 46783525Sshidokht cap - 2); 46793525Sshidokht bzero(gpt, sizeof (efi_gpt_t)); 46803525Sshidokht if ((rval = DK_TG_WRITE(cl, gpt, cap - 2, 46819889SLarry.Liu@Sun.COM cl->cl_sys_blocksize, tg_cookie))) { 46823525Sshidokht cmlb_dbg(CMLB_INFO, cl, 46833525Sshidokht "cmlb_clear_efi: clear legacy backup label " 46843525Sshidokht "failed\n"); 46853525Sshidokht } 4686786Slclee } 4687786Slclee } 4688786Slclee 4689786Slclee done: 46909889SLarry.Liu@Sun.COM kmem_free(gpt, cl->cl_sys_blocksize); 4691786Slclee } 4692786Slclee 4693786Slclee /* 4694786Slclee * Function: cmlb_set_vtoc 4695786Slclee * 4696786Slclee * Description: This routine writes data to the appropriate positions 4697786Slclee * 46983525Sshidokht * Arguments: 46993525Sshidokht * cl driver soft state (unit) structure 47003525Sshidokht * 47013525Sshidokht * dkl the data to be written 47023525Sshidokht * 47033525Sshidokht * tg_cookie cookie from target driver to be passed back to target 47043525Sshidokht * driver when we call back to it through tg_ops. 4705786Slclee * 4706786Slclee * Return: void 4707786Slclee */ 4708786Slclee static int 47093525Sshidokht cmlb_set_vtoc(struct cmlb_lun *cl, struct dk_label *dkl, void *tg_cookie) 4710786Slclee { 4711786Slclee uint_t label_addr; 4712786Slclee int sec; 47137563SPrasad.Singamsetty@Sun.COM diskaddr_t blk; 4714786Slclee int head; 4715786Slclee int cyl; 4716786Slclee int rval; 4717786Slclee 4718786Slclee #if defined(__i386) || defined(__amd64) 47193525Sshidokht label_addr = cl->cl_solaris_offset + DK_LABEL_LOC; 4720786Slclee #else 4721786Slclee /* Write the primary label at block 0 of the solaris partition. */ 4722786Slclee label_addr = 0; 4723786Slclee #endif 4724786Slclee 47253525Sshidokht rval = DK_TG_WRITE(cl, dkl, label_addr, cl->cl_sys_blocksize, 47263525Sshidokht tg_cookie); 4727786Slclee 4728786Slclee if (rval != 0) { 4729786Slclee return (rval); 4730786Slclee } 4731786Slclee 4732786Slclee /* 4733786Slclee * Calculate where the backup labels go. They are always on 4734786Slclee * the last alternate cylinder, but some older drives put them 4735786Slclee * on head 2 instead of the last head. They are always on the 4736786Slclee * first 5 odd sectors of the appropriate track. 4737786Slclee * 4738786Slclee * We have no choice at this point, but to believe that the 4739786Slclee * disk label is valid. Use the geometry of the disk 4740786Slclee * as described in the label. 4741786Slclee */ 4742786Slclee cyl = dkl->dkl_ncyl + dkl->dkl_acyl - 1; 4743786Slclee head = dkl->dkl_nhead - 1; 4744786Slclee 4745786Slclee /* 4746786Slclee * Write and verify the backup labels. Make sure we don't try to 4747786Slclee * write past the last cylinder. 4748786Slclee */ 4749786Slclee for (sec = 1; ((sec < 5 * 2 + 1) && (sec < dkl->dkl_nsect)); sec += 2) { 47507563SPrasad.Singamsetty@Sun.COM blk = (diskaddr_t)( 4751786Slclee (cyl * ((dkl->dkl_nhead * dkl->dkl_nsect) - dkl->dkl_apc)) + 4752786Slclee (head * dkl->dkl_nsect) + sec); 4753786Slclee #if defined(__i386) || defined(__amd64) 47543525Sshidokht blk += cl->cl_solaris_offset; 4755786Slclee #endif 47563525Sshidokht rval = DK_TG_WRITE(cl, dkl, blk, cl->cl_sys_blocksize, 47573525Sshidokht tg_cookie); 47583525Sshidokht cmlb_dbg(CMLB_INFO, cl, 47597563SPrasad.Singamsetty@Sun.COM "cmlb_set_vtoc: wrote backup label %llx\n", blk); 4760786Slclee if (rval != 0) { 4761786Slclee goto exit; 4762786Slclee } 4763786Slclee } 4764786Slclee exit: 4765786Slclee return (rval); 4766786Slclee } 4767786Slclee 4768786Slclee /* 4769786Slclee * Function: cmlb_clear_vtoc 4770786Slclee * 4771786Slclee * Description: This routine clears out the VTOC labels. 4772786Slclee * 47733525Sshidokht * Arguments: 47743525Sshidokht * cl driver soft state (unit) structure 47753525Sshidokht * 47763525Sshidokht * tg_cookie cookie from target driver to be passed back to target 47773525Sshidokht * driver when we call back to it through tg_ops. 4778786Slclee * 4779786Slclee * Return: void 4780786Slclee */ 4781786Slclee static void 47823525Sshidokht cmlb_clear_vtoc(struct cmlb_lun *cl, void *tg_cookie) 4783786Slclee { 4784786Slclee struct dk_label *dkl; 4785786Slclee 47863525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 47879889SLarry.Liu@Sun.COM dkl = kmem_zalloc(cl->cl_sys_blocksize, KM_SLEEP); 47883525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 4789786Slclee /* 4790786Slclee * cmlb_set_vtoc uses these fields in order to figure out 4791786Slclee * where to overwrite the backup labels 4792786Slclee */ 47933525Sshidokht dkl->dkl_apc = cl->cl_g.dkg_apc; 47943525Sshidokht dkl->dkl_ncyl = cl->cl_g.dkg_ncyl; 47953525Sshidokht dkl->dkl_acyl = cl->cl_g.dkg_acyl; 47963525Sshidokht dkl->dkl_nhead = cl->cl_g.dkg_nhead; 47973525Sshidokht dkl->dkl_nsect = cl->cl_g.dkg_nsect; 47983525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 47993525Sshidokht (void) cmlb_set_vtoc(cl, dkl, tg_cookie); 48009889SLarry.Liu@Sun.COM kmem_free(dkl, cl->cl_sys_blocksize); 4801786Slclee 48023525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 4803786Slclee } 4804786Slclee 4805786Slclee /* 4806786Slclee * Function: cmlb_write_label 4807786Slclee * 4808786Slclee * Description: This routine will validate and write the driver soft state vtoc 4809786Slclee * contents to the device. 4810786Slclee * 48113525Sshidokht * Arguments: 48123525Sshidokht * cl cmlb handle 48133525Sshidokht * 48143525Sshidokht * tg_cookie cookie from target driver to be passed back to target 48153525Sshidokht * driver when we call back to it through tg_ops. 48163525Sshidokht * 4817786Slclee * 4818786Slclee * Return Code: the code returned by cmlb_send_scsi_cmd() 4819786Slclee * 0 4820786Slclee * EINVAL 4821786Slclee * ENXIO 4822786Slclee * ENOMEM 4823786Slclee */ 4824786Slclee static int 48253525Sshidokht cmlb_write_label(struct cmlb_lun *cl, void *tg_cookie) 4826786Slclee { 4827786Slclee struct dk_label *dkl; 4828786Slclee short sum; 4829786Slclee short *sp; 4830786Slclee int i; 4831786Slclee int rval; 4832786Slclee 48333525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 48343525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 48359889SLarry.Liu@Sun.COM dkl = kmem_zalloc(cl->cl_sys_blocksize, KM_SLEEP); 48363525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 48373525Sshidokht 48383525Sshidokht bcopy(&cl->cl_vtoc, &dkl->dkl_vtoc, sizeof (struct dk_vtoc)); 48393525Sshidokht dkl->dkl_rpm = cl->cl_g.dkg_rpm; 48403525Sshidokht dkl->dkl_pcyl = cl->cl_g.dkg_pcyl; 48413525Sshidokht dkl->dkl_apc = cl->cl_g.dkg_apc; 48423525Sshidokht dkl->dkl_intrlv = cl->cl_g.dkg_intrlv; 48433525Sshidokht dkl->dkl_ncyl = cl->cl_g.dkg_ncyl; 48443525Sshidokht dkl->dkl_acyl = cl->cl_g.dkg_acyl; 48453525Sshidokht dkl->dkl_nhead = cl->cl_g.dkg_nhead; 48463525Sshidokht dkl->dkl_nsect = cl->cl_g.dkg_nsect; 4847786Slclee 4848786Slclee #if defined(_SUNOS_VTOC_8) 48493525Sshidokht dkl->dkl_obs1 = cl->cl_g.dkg_obs1; 48503525Sshidokht dkl->dkl_obs2 = cl->cl_g.dkg_obs2; 48513525Sshidokht dkl->dkl_obs3 = cl->cl_g.dkg_obs3; 4852786Slclee for (i = 0; i < NDKMAP; i++) { 48533525Sshidokht dkl->dkl_map[i].dkl_cylno = cl->cl_map[i].dkl_cylno; 48543525Sshidokht dkl->dkl_map[i].dkl_nblk = cl->cl_map[i].dkl_nblk; 4855786Slclee } 48563525Sshidokht bcopy(cl->cl_asciilabel, dkl->dkl_asciilabel, LEN_DKL_ASCII); 4857786Slclee #elif defined(_SUNOS_VTOC_16) 48583525Sshidokht dkl->dkl_skew = cl->cl_dkg_skew; 4859786Slclee #else 4860786Slclee #error "No VTOC format defined." 4861786Slclee #endif 4862786Slclee 4863786Slclee dkl->dkl_magic = DKL_MAGIC; 48643525Sshidokht dkl->dkl_write_reinstruct = cl->cl_g.dkg_write_reinstruct; 48653525Sshidokht dkl->dkl_read_reinstruct = cl->cl_g.dkg_read_reinstruct; 4866786Slclee 4867786Slclee /* Construct checksum for the new disk label */ 4868786Slclee sum = 0; 4869786Slclee sp = (short *)dkl; 4870786Slclee i = sizeof (struct dk_label) / sizeof (short); 4871786Slclee while (i--) { 4872786Slclee sum ^= *sp++; 4873786Slclee } 4874786Slclee dkl->dkl_cksum = sum; 4875786Slclee 48763525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 48773525Sshidokht 48783525Sshidokht rval = cmlb_set_vtoc(cl, dkl, tg_cookie); 4879786Slclee exit: 48809889SLarry.Liu@Sun.COM kmem_free(dkl, cl->cl_sys_blocksize); 48813525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 4882786Slclee return (rval); 4883786Slclee } 4884786Slclee 4885786Slclee static int 48863525Sshidokht cmlb_dkio_set_efi(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag, 48873525Sshidokht void *tg_cookie) 4888786Slclee { 4889786Slclee dk_efi_t user_efi; 4890786Slclee int rval = 0; 4891786Slclee void *buffer; 48923525Sshidokht diskaddr_t tgt_lba; 48936318Sedp boolean_t internal; 4894786Slclee 4895786Slclee if (ddi_copyin(arg, &user_efi, sizeof (dk_efi_t), flag)) 4896786Slclee return (EFAULT); 4897786Slclee 48988863SEdward.Pilatowicz@Sun.COM internal = VOID2BOOLEAN( 48998863SEdward.Pilatowicz@Sun.COM (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0); 49006318Sedp 4901786Slclee user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64; 4902786Slclee 4903786Slclee buffer = kmem_alloc(user_efi.dki_length, KM_SLEEP); 4904786Slclee if (ddi_copyin(user_efi.dki_data, buffer, user_efi.dki_length, flag)) { 4905786Slclee rval = EFAULT; 4906786Slclee } else { 4907786Slclee /* 4908786Slclee * let's clear the vtoc labels and clear the softstate 4909786Slclee * vtoc. 4910786Slclee */ 49113525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 49123525Sshidokht if (cl->cl_vtoc.v_sanity == VTOC_SANE) { 49133525Sshidokht cmlb_dbg(CMLB_TRACE, cl, 49143525Sshidokht "cmlb_dkio_set_efi: CLEAR VTOC\n"); 49157563SPrasad.Singamsetty@Sun.COM if (cl->cl_label_from_media == CMLB_LABEL_VTOC) 49163525Sshidokht cmlb_clear_vtoc(cl, tg_cookie); 49173525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc)); 49183525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 49193525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "h"); 49203525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw"); 49216318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd", 4922786Slclee S_IFBLK, 4923786Slclee (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 49246318Sedp cl->cl_node_type, NULL, internal); 49256318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd,raw", 4926786Slclee S_IFCHR, 4927786Slclee (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, 49286318Sedp cl->cl_node_type, NULL, internal); 4929786Slclee } else 49303525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 49313525Sshidokht 49323525Sshidokht tgt_lba = user_efi.dki_lba; 49333525Sshidokht 49343525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 49353525Sshidokht if ((cmlb_check_update_blockcount(cl, tg_cookie) != 0) || 49363525Sshidokht (cl->cl_tgt_blocksize == 0)) { 49373525Sshidokht kmem_free(buffer, user_efi.dki_length); 49383525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 49393525Sshidokht return (EINVAL); 49403525Sshidokht } 49413525Sshidokht if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) 49423525Sshidokht tgt_lba = tgt_lba * 49433525Sshidokht cl->cl_tgt_blocksize / cl->cl_sys_blocksize; 49443525Sshidokht 49453525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 49463525Sshidokht rval = DK_TG_WRITE(cl, buffer, tgt_lba, user_efi.dki_length, 49473525Sshidokht tg_cookie); 49483525Sshidokht 4949786Slclee if (rval == 0) { 49503525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 49518863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE; 49523525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 4953786Slclee } 4954786Slclee } 4955786Slclee kmem_free(buffer, user_efi.dki_length); 4956786Slclee return (rval); 4957786Slclee } 4958786Slclee 4959786Slclee /* 4960786Slclee * Function: cmlb_dkio_get_mboot 4961786Slclee * 4962786Slclee * Description: This routine is the driver entry point for handling user 4963786Slclee * requests to get the current device mboot (DKIOCGMBOOT) 4964786Slclee * 4965786Slclee * Arguments: 49663525Sshidokht * arg pointer to user provided mboot structure specifying 4967786Slclee * the current mboot. 49683525Sshidokht * 49693525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 49703525Sshidokht * directly from the mode argument of ioctl(). 49713525Sshidokht * 49723525Sshidokht * tg_cookie cookie from target driver to be passed back to target 49733525Sshidokht * driver when we call back to it through tg_ops. 4974786Slclee * 4975786Slclee * Return Code: 0 4976786Slclee * EINVAL 4977786Slclee * EFAULT 4978786Slclee * ENXIO 4979786Slclee */ 4980786Slclee static int 49813525Sshidokht cmlb_dkio_get_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie) 4982786Slclee { 4983786Slclee struct mboot *mboot; 4984786Slclee int rval; 4985786Slclee size_t buffer_size; 4986786Slclee 4987786Slclee 4988786Slclee #if defined(_SUNOS_VTOC_8) 49893525Sshidokht if ((!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) || (arg == NULL)) { 4990786Slclee #elif defined(_SUNOS_VTOC_16) 4991786Slclee if (arg == NULL) { 4992786Slclee #endif 4993786Slclee return (EINVAL); 4994786Slclee } 4995786Slclee 4996786Slclee /* 4997786Slclee * Read the mboot block, located at absolute block 0 on the target. 4998786Slclee */ 49999889SLarry.Liu@Sun.COM buffer_size = cl->cl_sys_blocksize; 5000786Slclee 50013525Sshidokht cmlb_dbg(CMLB_TRACE, cl, 5002786Slclee "cmlb_dkio_get_mboot: allocation size: 0x%x\n", buffer_size); 5003786Slclee 5004786Slclee mboot = kmem_zalloc(buffer_size, KM_SLEEP); 50053525Sshidokht if ((rval = DK_TG_READ(cl, mboot, 0, buffer_size, tg_cookie)) == 0) { 5006786Slclee if (ddi_copyout(mboot, (void *)arg, 5007786Slclee sizeof (struct mboot), flag) != 0) { 5008786Slclee rval = EFAULT; 5009786Slclee } 5010786Slclee } 5011786Slclee kmem_free(mboot, buffer_size); 5012786Slclee return (rval); 5013786Slclee } 5014786Slclee 5015786Slclee 5016786Slclee /* 5017786Slclee * Function: cmlb_dkio_set_mboot 5018786Slclee * 5019786Slclee * Description: This routine is the driver entry point for handling user 5020786Slclee * requests to validate and set the device master boot 5021786Slclee * (DKIOCSMBOOT). 5022786Slclee * 5023786Slclee * Arguments: 50243525Sshidokht * arg pointer to user provided mboot structure used to set the 5025786Slclee * master boot. 50263525Sshidokht * 50273525Sshidokht * flag this argument is a pass through to ddi_copyxxx() 50283525Sshidokht * directly from the mode argument of ioctl(). 50293525Sshidokht * 50303525Sshidokht * tg_cookie cookie from target driver to be passed back to target 50313525Sshidokht * driver when we call back to it through tg_ops. 5032786Slclee * 5033786Slclee * Return Code: 0 5034786Slclee * EINVAL 5035786Slclee * EFAULT 5036786Slclee * ENXIO 5037786Slclee */ 5038786Slclee static int 50393525Sshidokht cmlb_dkio_set_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie) 5040786Slclee { 5041786Slclee struct mboot *mboot = NULL; 5042786Slclee int rval; 5043786Slclee ushort_t magic; 5044786Slclee 5045786Slclee 50463525Sshidokht ASSERT(!mutex_owned(CMLB_MUTEX(cl))); 5047786Slclee 5048786Slclee #if defined(_SUNOS_VTOC_8) 50493525Sshidokht if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) { 5050786Slclee return (EINVAL); 5051786Slclee } 5052786Slclee #endif 5053786Slclee 5054786Slclee if (arg == NULL) { 5055786Slclee return (EINVAL); 5056786Slclee } 5057786Slclee 50589889SLarry.Liu@Sun.COM mboot = kmem_zalloc(cl->cl_sys_blocksize, KM_SLEEP); 5059786Slclee 5060786Slclee if (ddi_copyin((const void *)arg, mboot, 50619889SLarry.Liu@Sun.COM cl->cl_sys_blocksize, flag) != 0) { 50629889SLarry.Liu@Sun.COM kmem_free(mboot, cl->cl_sys_blocksize); 5063786Slclee return (EFAULT); 5064786Slclee } 5065786Slclee 5066786Slclee /* Is this really a master boot record? */ 5067786Slclee magic = LE_16(mboot->signature); 5068786Slclee if (magic != MBB_MAGIC) { 50699889SLarry.Liu@Sun.COM kmem_free(mboot, cl->cl_sys_blocksize); 5070786Slclee return (EINVAL); 5071786Slclee } 5072786Slclee 50733525Sshidokht rval = DK_TG_WRITE(cl, mboot, 0, cl->cl_sys_blocksize, tg_cookie); 50743525Sshidokht 50753525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 5076786Slclee #if defined(__i386) || defined(__amd64) 5077786Slclee if (rval == 0) { 5078786Slclee /* 5079786Slclee * mboot has been written successfully. 5080786Slclee * update the fdisk and vtoc tables in memory 5081786Slclee */ 50823525Sshidokht rval = cmlb_update_fdisk_and_vtoc(cl, tg_cookie); 50838863SEdward.Pilatowicz@Sun.COM if ((!cl->cl_f_geometry_is_valid) || (rval != 0)) { 50843525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 50859889SLarry.Liu@Sun.COM kmem_free(mboot, cl->cl_sys_blocksize); 5086786Slclee return (rval); 5087786Slclee } 5088786Slclee } 50893525Sshidokht 50903525Sshidokht #ifdef __lock_lint 50913525Sshidokht cmlb_setup_default_geometry(cl, tg_cookie); 50923525Sshidokht #endif 50933525Sshidokht 5094786Slclee #else 5095786Slclee if (rval == 0) { 5096786Slclee /* 5097786Slclee * mboot has been written successfully. 5098786Slclee * set up the default geometry and VTOC 5099786Slclee */ 51007563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount <= CMLB_EXTVTOC_LIMIT) 51013525Sshidokht cmlb_setup_default_geometry(cl, tg_cookie); 5102786Slclee } 5103786Slclee #endif 51047563SPrasad.Singamsetty@Sun.COM cl->cl_msglog_flag |= CMLB_ALLOW_2TB_WARN; 51053525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 51069889SLarry.Liu@Sun.COM kmem_free(mboot, cl->cl_sys_blocksize); 5107786Slclee return (rval); 5108786Slclee } 5109786Slclee 5110786Slclee 511110021SSheshadri.Vasudevan@Sun.COM #if defined(__i386) || defined(__amd64) 511210021SSheshadri.Vasudevan@Sun.COM /*ARGSUSED*/ 511310021SSheshadri.Vasudevan@Sun.COM static int 511410021SSheshadri.Vasudevan@Sun.COM cmlb_dkio_set_ext_part(struct cmlb_lun *cl, caddr_t arg, int flag, 511510021SSheshadri.Vasudevan@Sun.COM void *tg_cookie) 511610021SSheshadri.Vasudevan@Sun.COM { 511710021SSheshadri.Vasudevan@Sun.COM int fdisk_rval; 511810021SSheshadri.Vasudevan@Sun.COM diskaddr_t capacity; 511910021SSheshadri.Vasudevan@Sun.COM 512010021SSheshadri.Vasudevan@Sun.COM ASSERT(!mutex_owned(CMLB_MUTEX(cl))); 512110021SSheshadri.Vasudevan@Sun.COM 512210021SSheshadri.Vasudevan@Sun.COM mutex_enter(CMLB_MUTEX(cl)); 512310021SSheshadri.Vasudevan@Sun.COM capacity = cl->cl_blockcount; 512410021SSheshadri.Vasudevan@Sun.COM fdisk_rval = cmlb_read_fdisk(cl, capacity, tg_cookie); 512510021SSheshadri.Vasudevan@Sun.COM if (fdisk_rval != 0) { 512610021SSheshadri.Vasudevan@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 512710021SSheshadri.Vasudevan@Sun.COM return (fdisk_rval); 512810021SSheshadri.Vasudevan@Sun.COM } 512910021SSheshadri.Vasudevan@Sun.COM 513010021SSheshadri.Vasudevan@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 513110021SSheshadri.Vasudevan@Sun.COM return (fdisk_rval); 513210021SSheshadri.Vasudevan@Sun.COM } 513310021SSheshadri.Vasudevan@Sun.COM #endif 513410021SSheshadri.Vasudevan@Sun.COM 5135786Slclee /* 5136786Slclee * Function: cmlb_setup_default_geometry 5137786Slclee * 5138786Slclee * Description: This local utility routine sets the default geometry as part of 5139786Slclee * setting the device mboot. 5140786Slclee * 51413525Sshidokht * Arguments: 51423525Sshidokht * cl driver soft state (unit) structure 51433525Sshidokht * 51443525Sshidokht * tg_cookie cookie from target driver to be passed back to target 51453525Sshidokht * driver when we call back to it through tg_ops. 51463525Sshidokht * 5147786Slclee * 5148786Slclee * Note: This may be redundant with cmlb_build_default_label. 5149786Slclee */ 5150786Slclee static void 51513525Sshidokht cmlb_setup_default_geometry(struct cmlb_lun *cl, void *tg_cookie) 5152786Slclee { 5153786Slclee struct cmlb_geom pgeom; 5154786Slclee struct cmlb_geom *pgeomp = &pgeom; 5155786Slclee int ret; 5156786Slclee int geom_base_cap = 1; 5157786Slclee 5158786Slclee 51593525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 5160786Slclee 5161786Slclee /* zero out the soft state geometry and partition table. */ 51623525Sshidokht bzero(&cl->cl_g, sizeof (struct dk_geom)); 51633525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc)); 51643525Sshidokht bzero(cl->cl_map, NDKMAP * (sizeof (struct dk_map))); 5165786Slclee 5166786Slclee /* 5167786Slclee * For the rpm, we use the minimum for the disk. 5168786Slclee * For the head, cyl and number of sector per track, 5169786Slclee * if the capacity <= 1GB, head = 64, sect = 32. 5170786Slclee * else head = 255, sect 63 5171786Slclee * Note: the capacity should be equal to C*H*S values. 5172786Slclee * This will cause some truncation of size due to 5173786Slclee * round off errors. For CD-ROMs, this truncation can 5174786Slclee * have adverse side effects, so returning ncyl and 5175786Slclee * nhead as 1. The nsect will overflow for most of 5176786Slclee * CD-ROMs as nsect is of type ushort. 5177786Slclee */ 51783525Sshidokht if (cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8) { 5179786Slclee /* 5180786Slclee * newfs currently can not handle 255 ntracks for SPARC 5181786Slclee * so get the geometry from target driver instead of coming up 5182786Slclee * with one based on capacity. 5183786Slclee */ 51843525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 51853525Sshidokht ret = DK_TG_GETPHYGEOM(cl, pgeomp, tg_cookie); 51863525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 5187786Slclee 51888863SEdward.Pilatowicz@Sun.COM if (ret == 0) { 5189786Slclee geom_base_cap = 0; 5190786Slclee } else { 51913525Sshidokht cmlb_dbg(CMLB_ERROR, cl, 5192786Slclee "cmlb_setup_default_geometry: " 5193786Slclee "tg_getphygeom failed %d\n", ret); 5194786Slclee 5195786Slclee /* do default setting, geometry based on capacity */ 5196786Slclee } 5197786Slclee } 5198786Slclee 5199786Slclee if (geom_base_cap) { 52003525Sshidokht if (ISCD(cl)) { 52013525Sshidokht cl->cl_g.dkg_ncyl = 1; 52023525Sshidokht cl->cl_g.dkg_nhead = 1; 52033525Sshidokht cl->cl_g.dkg_nsect = cl->cl_blockcount; 52043525Sshidokht } else if (cl->cl_blockcount <= 0x1000) { 5205786Slclee /* Needed for unlabeled SCSI floppies. */ 52063525Sshidokht cl->cl_g.dkg_nhead = 2; 52073525Sshidokht cl->cl_g.dkg_ncyl = 80; 52083525Sshidokht cl->cl_g.dkg_pcyl = 80; 52093525Sshidokht cl->cl_g.dkg_nsect = cl->cl_blockcount / (2 * 80); 52103525Sshidokht } else if (cl->cl_blockcount <= 0x200000) { 52113525Sshidokht cl->cl_g.dkg_nhead = 64; 52123525Sshidokht cl->cl_g.dkg_nsect = 32; 52133525Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount / (64 * 32); 5214786Slclee } else { 52153525Sshidokht cl->cl_g.dkg_nhead = 255; 52166124Sshidokht 52176124Sshidokht cl->cl_g.dkg_nsect = ((cl->cl_blockcount + 52186124Sshidokht (UINT16_MAX * 255 * 63) - 1) / 52196124Sshidokht (UINT16_MAX * 255 * 63)) * 63; 52206124Sshidokht 52216124Sshidokht if (cl->cl_g.dkg_nsect == 0) 52226124Sshidokht cl->cl_g.dkg_nsect = (UINT16_MAX / 63) * 63; 52236124Sshidokht 52246124Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount / 52256124Sshidokht (255 * cl->cl_g.dkg_nsect); 5226786Slclee } 5227786Slclee 52283525Sshidokht cl->cl_g.dkg_acyl = 0; 52293525Sshidokht cl->cl_g.dkg_bcyl = 0; 52303525Sshidokht cl->cl_g.dkg_intrlv = 1; 52313525Sshidokht cl->cl_g.dkg_rpm = 200; 52323525Sshidokht if (cl->cl_g.dkg_pcyl == 0) 52333525Sshidokht cl->cl_g.dkg_pcyl = cl->cl_g.dkg_ncyl + 52343525Sshidokht cl->cl_g.dkg_acyl; 5235786Slclee } else { 52363525Sshidokht cl->cl_g.dkg_ncyl = (short)pgeomp->g_ncyl; 52373525Sshidokht cl->cl_g.dkg_acyl = pgeomp->g_acyl; 52383525Sshidokht cl->cl_g.dkg_nhead = pgeomp->g_nhead; 52393525Sshidokht cl->cl_g.dkg_nsect = pgeomp->g_nsect; 52403525Sshidokht cl->cl_g.dkg_intrlv = pgeomp->g_intrlv; 52413525Sshidokht cl->cl_g.dkg_rpm = pgeomp->g_rpm; 52423525Sshidokht cl->cl_g.dkg_pcyl = cl->cl_g.dkg_ncyl + cl->cl_g.dkg_acyl; 5243786Slclee } 5244786Slclee 52453525Sshidokht cl->cl_g.dkg_read_reinstruct = 0; 52463525Sshidokht cl->cl_g.dkg_write_reinstruct = 0; 52473525Sshidokht cl->cl_solaris_size = cl->cl_g.dkg_ncyl * 52483525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect; 52493525Sshidokht 52503525Sshidokht cl->cl_map['a'-'a'].dkl_cylno = 0; 52513525Sshidokht cl->cl_map['a'-'a'].dkl_nblk = cl->cl_solaris_size; 52523525Sshidokht 52533525Sshidokht cl->cl_map['c'-'a'].dkl_cylno = 0; 52543525Sshidokht cl->cl_map['c'-'a'].dkl_nblk = cl->cl_solaris_size; 52553525Sshidokht 52563525Sshidokht cl->cl_vtoc.v_part[2].p_tag = V_BACKUP; 52573525Sshidokht cl->cl_vtoc.v_part[2].p_flag = V_UNMNT; 52583525Sshidokht cl->cl_vtoc.v_nparts = V_NUMPAR; 52593525Sshidokht cl->cl_vtoc.v_version = V_VERSION; 52603525Sshidokht (void) sprintf((char *)cl->cl_asciilabel, "DEFAULT cyl %d alt %d" 52613525Sshidokht " hd %d sec %d", cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl, 52623525Sshidokht cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect); 52633525Sshidokht 52648863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE; 5265786Slclee } 5266786Slclee 5267786Slclee 5268786Slclee #if defined(__i386) || defined(__amd64) 5269786Slclee /* 5270786Slclee * Function: cmlb_update_fdisk_and_vtoc 5271786Slclee * 5272786Slclee * Description: This local utility routine updates the device fdisk and vtoc 5273786Slclee * as part of setting the device mboot. 5274786Slclee * 52753525Sshidokht * Arguments: 52763525Sshidokht * cl driver soft state (unit) structure 52773525Sshidokht * 52783525Sshidokht * tg_cookie cookie from target driver to be passed back to target 52793525Sshidokht * driver when we call back to it through tg_ops. 52803525Sshidokht * 5281786Slclee * 5282786Slclee * Return Code: 0 for success or errno-type return code. 5283786Slclee * 5284786Slclee * Note:x86: This looks like a duplicate of cmlb_validate_geometry(), but 5285786Slclee * these did exist separately in x86 sd.c. 5286786Slclee */ 5287786Slclee static int 52883525Sshidokht cmlb_update_fdisk_and_vtoc(struct cmlb_lun *cl, void *tg_cookie) 5289786Slclee { 5290786Slclee int count; 5291786Slclee int label_rc = 0; 5292786Slclee int fdisk_rval; 5293786Slclee diskaddr_t capacity; 5294786Slclee 52953525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 52963525Sshidokht 52973525Sshidokht if (cmlb_check_update_blockcount(cl, tg_cookie) != 0) 5298786Slclee return (EINVAL); 5299786Slclee 5300786Slclee #if defined(_SUNOS_VTOC_16) 5301786Slclee /* 5302786Slclee * Set up the "whole disk" fdisk partition; this should always 5303786Slclee * exist, regardless of whether the disk contains an fdisk table 5304786Slclee * or vtoc. 5305786Slclee */ 53063525Sshidokht cl->cl_map[P0_RAW_DISK].dkl_cylno = 0; 53073525Sshidokht cl->cl_map[P0_RAW_DISK].dkl_nblk = cl->cl_blockcount; 5308786Slclee #endif /* defined(_SUNOS_VTOC_16) */ 5309786Slclee 5310786Slclee /* 5311786Slclee * copy the lbasize and capacity so that if they're 53123525Sshidokht * reset while we're not holding the CMLB_MUTEX(cl), we will 53133525Sshidokht * continue to use valid values after the CMLB_MUTEX(cl) is 5314786Slclee * reacquired. 5315786Slclee */ 53163525Sshidokht capacity = cl->cl_blockcount; 5317786Slclee 5318786Slclee /* 5319786Slclee * refresh the logical and physical geometry caches. 5320786Slclee * (data from mode sense format/rigid disk geometry pages, 5321786Slclee * and scsi_ifgetcap("geometry"). 5322786Slclee */ 53233525Sshidokht cmlb_resync_geom_caches(cl, capacity, tg_cookie); 5324786Slclee 5325786Slclee /* 53263525Sshidokht * Only DIRECT ACCESS devices will have Scl labels. 53273525Sshidokht * CD's supposedly have a Scl label, too 5328786Slclee */ 53293525Sshidokht if (cl->cl_device_type == DTYPE_DIRECT || ISREMOVABLE(cl)) { 53303525Sshidokht fdisk_rval = cmlb_read_fdisk(cl, capacity, tg_cookie); 5331786Slclee if (fdisk_rval != 0) { 53323525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 5333786Slclee return (fdisk_rval); 5334786Slclee } 5335786Slclee 53363525Sshidokht if (cl->cl_solaris_size <= DK_LABEL_LOC) { 5337786Slclee /* 5338786Slclee * Found fdisk table but no Solaris partition entry, 5339786Slclee * so don't call cmlb_uselabel() and don't create 5340786Slclee * a default label. 5341786Slclee */ 5342786Slclee label_rc = 0; 53438863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_TRUE; 5344786Slclee goto no_solaris_partition; 5345786Slclee } 5346786Slclee } else if (capacity < 0) { 53473525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 5348786Slclee return (EINVAL); 5349786Slclee } 5350786Slclee 5351786Slclee /* 5352786Slclee * For Removable media We reach here if we have found a 5353786Slclee * SOLARIS PARTITION. 53548863SEdward.Pilatowicz@Sun.COM * If cl_f_geometry_is_valid is B_FALSE it indicates that the SOLARIS 5355786Slclee * PARTITION has changed from the previous one, hence we will setup a 5356786Slclee * default VTOC in this case. 5357786Slclee */ 53588863SEdward.Pilatowicz@Sun.COM if (!cl->cl_f_geometry_is_valid) { 5359786Slclee /* if we get here it is writable */ 5360786Slclee /* we are called from SMBOOT, and after a write of fdisk */ 53613525Sshidokht cmlb_build_default_label(cl, tg_cookie); 5362786Slclee label_rc = 0; 5363786Slclee } 5364786Slclee 5365786Slclee no_solaris_partition: 5366786Slclee 5367786Slclee #if defined(_SUNOS_VTOC_16) 5368786Slclee /* 5369786Slclee * If we have valid geometry, set up the remaining fdisk partitions. 5370786Slclee * Note that dkl_cylno is not used for the fdisk map entries, so 5371786Slclee * we set it to an entirely bogus value. 5372786Slclee */ 537310021SSheshadri.Vasudevan@Sun.COM for (count = 0; count < FDISK_PARTS; count++) { 53747563SPrasad.Singamsetty@Sun.COM cl->cl_map[FDISK_P1 + count].dkl_cylno = UINT32_MAX; 53753525Sshidokht cl->cl_map[FDISK_P1 + count].dkl_nblk = 53763525Sshidokht cl->cl_fmap[count].fmap_nblk; 53773525Sshidokht cl->cl_offset[FDISK_P1 + count] = 53783525Sshidokht cl->cl_fmap[count].fmap_start; 5379786Slclee } 5380786Slclee #endif 5381786Slclee 5382786Slclee for (count = 0; count < NDKMAP; count++) { 5383786Slclee #if defined(_SUNOS_VTOC_8) 53843525Sshidokht struct dk_map *lp = &cl->cl_map[count]; 53853525Sshidokht cl->cl_offset[count] = 53863525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno; 5387786Slclee #elif defined(_SUNOS_VTOC_16) 53883525Sshidokht struct dkl_partition *vp = &cl->cl_vtoc.v_part[count]; 53893525Sshidokht cl->cl_offset[count] = vp->p_start + cl->cl_solaris_offset; 5390786Slclee #else 5391786Slclee #error "No VTOC format defined." 5392786Slclee #endif 5393786Slclee } 5394786Slclee 53953525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl))); 5396786Slclee return (label_rc); 5397786Slclee } 5398786Slclee #endif 5399786Slclee 5400786Slclee #if defined(__i386) || defined(__amd64) 5401786Slclee static int 54023525Sshidokht cmlb_dkio_get_virtgeom(struct cmlb_lun *cl, caddr_t arg, int flag) 5403786Slclee { 5404786Slclee int err = 0; 5405786Slclee 5406786Slclee /* Return the driver's notion of the media's logical geometry */ 5407786Slclee struct dk_geom disk_geom; 5408786Slclee struct dk_geom *dkgp = &disk_geom; 5409786Slclee 54103525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 5411786Slclee /* 5412786Slclee * If there is no HBA geometry available, or 5413786Slclee * if the HBA returned us something that doesn't 5414786Slclee * really fit into an Int 13/function 8 geometry 5415786Slclee * result, just fail the ioctl. See PSARC 1998/313. 5416786Slclee */ 54173525Sshidokht if (cl->cl_lgeom.g_nhead == 0 || 54183525Sshidokht cl->cl_lgeom.g_nsect == 0 || 54193525Sshidokht cl->cl_lgeom.g_ncyl > 1024) { 54203525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 5421786Slclee err = EINVAL; 5422786Slclee } else { 54233525Sshidokht dkgp->dkg_ncyl = cl->cl_lgeom.g_ncyl; 54243525Sshidokht dkgp->dkg_acyl = cl->cl_lgeom.g_acyl; 5425786Slclee dkgp->dkg_pcyl = dkgp->dkg_ncyl + dkgp->dkg_acyl; 54263525Sshidokht dkgp->dkg_nhead = cl->cl_lgeom.g_nhead; 54273525Sshidokht dkgp->dkg_nsect = cl->cl_lgeom.g_nsect; 5428786Slclee 54294177Sshidokht mutex_exit(CMLB_MUTEX(cl)); 5430786Slclee if (ddi_copyout(dkgp, (void *)arg, 5431786Slclee sizeof (struct dk_geom), flag)) { 5432786Slclee err = EFAULT; 5433786Slclee } else { 5434786Slclee err = 0; 5435786Slclee } 5436786Slclee } 5437786Slclee return (err); 5438786Slclee } 5439786Slclee #endif 5440786Slclee 5441786Slclee #if defined(__i386) || defined(__amd64) 5442786Slclee static int 544310320SLarry.Liu@Sun.COM cmlb_dkio_get_phygeom(struct cmlb_lun *cl, caddr_t arg, int flag, 544410320SLarry.Liu@Sun.COM void *tg_cookie) 5445786Slclee { 5446786Slclee int err = 0; 54473525Sshidokht diskaddr_t capacity; 5448786Slclee 5449786Slclee 5450786Slclee /* Return the driver's notion of the media physical geometry */ 5451786Slclee struct dk_geom disk_geom; 5452786Slclee struct dk_geom *dkgp = &disk_geom; 5453786Slclee 54543525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 54553525Sshidokht 54563525Sshidokht if (cl->cl_g.dkg_nhead != 0 && 54573525Sshidokht cl->cl_g.dkg_nsect != 0) { 5458786Slclee /* 5459786Slclee * We succeeded in getting a geometry, but 5460786Slclee * right now it is being reported as just the 5461786Slclee * Solaris fdisk partition, just like for 5462786Slclee * DKIOCGGEOM. We need to change that to be 5463786Slclee * correct for the entire disk now. 5464786Slclee */ 54653525Sshidokht bcopy(&cl->cl_g, dkgp, sizeof (*dkgp)); 5466786Slclee dkgp->dkg_acyl = 0; 54673525Sshidokht dkgp->dkg_ncyl = cl->cl_blockcount / 5468786Slclee (dkgp->dkg_nhead * dkgp->dkg_nsect); 5469786Slclee } else { 5470786Slclee bzero(dkgp, sizeof (struct dk_geom)); 5471786Slclee /* 5472786Slclee * This disk does not have a Solaris VTOC 5473786Slclee * so we must present a physical geometry 5474786Slclee * that will remain consistent regardless 5475786Slclee * of how the disk is used. This will ensure 5476786Slclee * that the geometry does not change regardless 5477786Slclee * of the fdisk partition type (ie. EFI, FAT32, 5478786Slclee * Solaris, etc). 5479786Slclee */ 54803525Sshidokht if (ISCD(cl)) { 54813525Sshidokht dkgp->dkg_nhead = cl->cl_pgeom.g_nhead; 54823525Sshidokht dkgp->dkg_nsect = cl->cl_pgeom.g_nsect; 54833525Sshidokht dkgp->dkg_ncyl = cl->cl_pgeom.g_ncyl; 54843525Sshidokht dkgp->dkg_acyl = cl->cl_pgeom.g_acyl; 5485786Slclee } else { 54863525Sshidokht /* 54873525Sshidokht * Invalid cl_blockcount can generate invalid 54883525Sshidokht * dk_geom and may result in division by zero 54893525Sshidokht * system failure. Should make sure blockcount 54903525Sshidokht * is valid before using it here. 54913525Sshidokht */ 54923525Sshidokht if (cl->cl_blockcount == 0) { 54933525Sshidokht mutex_exit(CMLB_MUTEX(cl)); 54943525Sshidokht err = EIO; 54953525Sshidokht return (err); 54963525Sshidokht } 54973525Sshidokht /* 54983525Sshidokht * Refer to comments related to off-by-1 at the 54993525Sshidokht * header of this file 55003525Sshidokht */ 55013525Sshidokht if (cl->cl_alter_behavior & CMLB_OFF_BY_ONE) 55023525Sshidokht capacity = cl->cl_blockcount - 1; 55033525Sshidokht else 55043525Sshidokht capacity = cl->cl_blockcount; 55053525Sshidokht 550610320SLarry.Liu@Sun.COM cmlb_convert_geometry(cl, capacity, dkgp, tg_cookie); 5507786Slclee dkgp->dkg_acyl = 0; 55083525Sshidokht dkgp->dkg_ncyl = capacity / 5509786Slclee (dkgp->dkg_nhead * dkgp->dkg_nsect); 5510786Slclee } 5511786Slclee } 5512786Slclee dkgp->dkg_pcyl = dkgp->dkg_ncyl + dkgp->dkg_acyl; 5513786Slclee 55144177Sshidokht mutex_exit(CMLB_MUTEX(cl)); 55154177Sshidokht if (ddi_copyout(dkgp, (void *)arg, sizeof (struct dk_geom), flag)) 5516786Slclee err = EFAULT; 55174177Sshidokht 5518786Slclee return (err); 5519786Slclee } 5520786Slclee #endif 5521786Slclee 5522786Slclee #if defined(__i386) || defined(__amd64) 5523786Slclee static int 55243525Sshidokht cmlb_dkio_partinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag) 5525786Slclee { 5526786Slclee int err = 0; 5527786Slclee 5528786Slclee /* 5529786Slclee * Return parameters describing the selected disk slice. 5530786Slclee * Note: this ioctl is for the intel platform only 5531786Slclee */ 5532786Slclee int part; 5533786Slclee 5534786Slclee part = CMLBPART(dev); 5535786Slclee 55363525Sshidokht mutex_enter(CMLB_MUTEX(cl)); 55373525Sshidokht /* don't check cl_solaris_size for pN */ 55383525Sshidokht if (part < P0_RAW_DISK && cl->cl_solaris_size == 0) { 5539786Slclee err = EIO; 55404177Sshidokht mutex_exit(CMLB_MUTEX(cl)); 5541786Slclee } else { 5542786Slclee struct part_info p; 5543786Slclee 55443525Sshidokht p.p_start = (daddr_t)cl->cl_offset[part]; 55453525Sshidokht p.p_length = (int)cl->cl_map[part].dkl_nblk; 55464177Sshidokht mutex_exit(CMLB_MUTEX(cl)); 5547786Slclee #ifdef _MULTI_DATAMODEL 5548786Slclee switch (ddi_model_convert_from(flag & FMODELS)) { 5549786Slclee case DDI_MODEL_ILP32: 5550786Slclee { 5551786Slclee struct part_info32 p32; 5552786Slclee 5553786Slclee p32.p_start = (daddr32_t)p.p_start; 5554786Slclee p32.p_length = p.p_length; 5555786Slclee if (ddi_copyout(&p32, (void *)arg, 5556786Slclee sizeof (p32), flag)) 5557786Slclee err = EFAULT; 5558786Slclee break; 5559786Slclee } 5560786Slclee 5561786Slclee case DDI_MODEL_NONE: 5562786Slclee { 5563786Slclee if (ddi_copyout(&p, (void *)arg, sizeof (p), 5564786Slclee flag)) 5565786Slclee err = EFAULT; 5566786Slclee break; 5567786Slclee } 5568786Slclee } 5569786Slclee #else /* ! _MULTI_DATAMODEL */ 5570786Slclee if (ddi_copyout(&p, (void *)arg, sizeof (p), flag)) 5571786Slclee err = EFAULT; 5572786Slclee #endif /* _MULTI_DATAMODEL */ 5573786Slclee } 5574786Slclee return (err); 5575786Slclee } 55767563SPrasad.Singamsetty@Sun.COM static int 55777563SPrasad.Singamsetty@Sun.COM cmlb_dkio_extpartinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag) 55787563SPrasad.Singamsetty@Sun.COM { 55797563SPrasad.Singamsetty@Sun.COM int err = 0; 55807563SPrasad.Singamsetty@Sun.COM 55817563SPrasad.Singamsetty@Sun.COM /* 55827563SPrasad.Singamsetty@Sun.COM * Return parameters describing the selected disk slice. 55837563SPrasad.Singamsetty@Sun.COM * Note: this ioctl is for the intel platform only 55847563SPrasad.Singamsetty@Sun.COM */ 55857563SPrasad.Singamsetty@Sun.COM int part; 55867563SPrasad.Singamsetty@Sun.COM 55877563SPrasad.Singamsetty@Sun.COM part = CMLBPART(dev); 55887563SPrasad.Singamsetty@Sun.COM 55897563SPrasad.Singamsetty@Sun.COM mutex_enter(CMLB_MUTEX(cl)); 55907563SPrasad.Singamsetty@Sun.COM /* don't check cl_solaris_size for pN */ 55917563SPrasad.Singamsetty@Sun.COM if (part < P0_RAW_DISK && cl->cl_solaris_size == 0) { 55927563SPrasad.Singamsetty@Sun.COM err = EIO; 55937563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 55947563SPrasad.Singamsetty@Sun.COM } else { 55957563SPrasad.Singamsetty@Sun.COM struct extpart_info p; 55967563SPrasad.Singamsetty@Sun.COM 55977563SPrasad.Singamsetty@Sun.COM p.p_start = (diskaddr_t)cl->cl_offset[part]; 55987563SPrasad.Singamsetty@Sun.COM p.p_length = (diskaddr_t)cl->cl_map[part].dkl_nblk; 55997563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl)); 56007563SPrasad.Singamsetty@Sun.COM if (ddi_copyout(&p, (void *)arg, sizeof (p), flag)) 56017563SPrasad.Singamsetty@Sun.COM err = EFAULT; 56027563SPrasad.Singamsetty@Sun.COM } 56037563SPrasad.Singamsetty@Sun.COM return (err); 56047563SPrasad.Singamsetty@Sun.COM } 5605786Slclee #endif 56067224Scth 56077224Scth int 56087224Scth cmlb_prop_op(cmlb_handle_t cmlbhandle, 56097224Scth dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags, 56107224Scth char *name, caddr_t valuep, int *lengthp, int part, void *tg_cookie) 56117224Scth { 56127224Scth struct cmlb_lun *cl; 56137224Scth diskaddr_t capacity; 56147224Scth uint32_t lbasize; 56157224Scth enum dp { DP_NBLOCKS, DP_BLKSIZE } dp; 56167224Scth int callers_length; 56177224Scth caddr_t buffer; 56187224Scth uint64_t nblocks64; 56197224Scth uint_t dblk; 56207224Scth 56217224Scth /* Always fallback to ddi_prop_op... */ 56227224Scth cl = (struct cmlb_lun *)cmlbhandle; 56237224Scth if (cl == NULL) { 56247224Scth fallback: return (ddi_prop_op(dev, dip, prop_op, mod_flags, 56257224Scth name, valuep, lengthp)); 56267224Scth } 56277224Scth 56287224Scth /* Pick up capacity and blocksize information. */ 56297224Scth capacity = cl->cl_blockcount; 56307224Scth if (capacity == 0) 56317224Scth goto fallback; 56327224Scth lbasize = cl->cl_tgt_blocksize; 56337224Scth if (lbasize == 0) 56347224Scth lbasize = DEV_BSIZE; /* 0 -> DEV_BSIZE units */ 56357224Scth 56367224Scth /* Check for dynamic property of whole device. */ 56377224Scth if (dev == DDI_DEV_T_ANY) { 56387224Scth /* Fallback to ddi_prop_op if we don't understand. */ 56397224Scth if (strcmp(name, "device-nblocks") == 0) 56407224Scth dp = DP_NBLOCKS; 56417224Scth else if (strcmp(name, "device-blksize") == 0) 56427224Scth dp = DP_BLKSIZE; 56437224Scth else 56447224Scth goto fallback; 56457224Scth 56467224Scth /* get callers length, establish length of our dynamic prop */ 56477224Scth callers_length = *lengthp; 56487224Scth if (dp == DP_NBLOCKS) 56497224Scth *lengthp = sizeof (uint64_t); 56507224Scth else if (dp == DP_BLKSIZE) 56517224Scth *lengthp = sizeof (uint32_t); 56527224Scth 56537224Scth /* service request for the length of the property */ 56547224Scth if (prop_op == PROP_LEN) 56557224Scth return (DDI_PROP_SUCCESS); 56567224Scth 56577224Scth switch (prop_op) { 56587224Scth case PROP_LEN_AND_VAL_ALLOC: 56597224Scth if ((buffer = kmem_alloc(*lengthp, 56607224Scth (mod_flags & DDI_PROP_CANSLEEP) ? 56617224Scth KM_SLEEP : KM_NOSLEEP)) == NULL) 56627224Scth return (DDI_PROP_NO_MEMORY); 56637224Scth *(caddr_t *)valuep = buffer; /* set callers buf */ 56647224Scth break; 56657224Scth 56667224Scth case PROP_LEN_AND_VAL_BUF: 56677224Scth /* the length of the prop and the request must match */ 56687224Scth if (callers_length != *lengthp) 56697224Scth return (DDI_PROP_INVAL_ARG); 56707224Scth buffer = valuep; /* get callers buf */ 56717224Scth break; 56727224Scth 56737224Scth default: 56747224Scth return (DDI_PROP_INVAL_ARG); 56757224Scth } 56767224Scth 56777224Scth /* transfer the value into the buffer */ 56787224Scth if (dp == DP_NBLOCKS) 56797224Scth *((uint64_t *)buffer) = capacity; 56807224Scth else if (dp == DP_BLKSIZE) 56817224Scth *((uint32_t *)buffer) = lbasize; 56827224Scth 56837224Scth return (DDI_PROP_SUCCESS); 56847224Scth } 56857224Scth 56867224Scth /* 56877224Scth * Support dynamic size oriented properties of partition. Requests 56887224Scth * issued under conditions where size is valid are passed to 56897224Scth * ddi_prop_op_nblocks with the size information, otherwise the 56907224Scth * request is passed to ddi_prop_op. Size depends on valid geometry. 56917224Scth */ 56927224Scth if (!cmlb_is_valid(cmlbhandle)) 56937224Scth goto fallback; 56947224Scth 56957224Scth /* Get partition nblocks value. */ 56967224Scth (void) cmlb_partinfo(cmlbhandle, part, 56977224Scth (diskaddr_t *)&nblocks64, NULL, NULL, NULL, tg_cookie); 56987224Scth 56997224Scth /* 57009889SLarry.Liu@Sun.COM * Assume partition information is in sys_blocksize units, compute 57017224Scth * divisor for size(9P) property representation. 57027224Scth */ 57039889SLarry.Liu@Sun.COM dblk = lbasize / cl->cl_sys_blocksize; 57047224Scth 57057224Scth /* Now let ddi_prop_op_nblocks_blksize() handle the request. */ 57067224Scth return (ddi_prop_op_nblocks_blksize(dev, dip, prop_op, mod_flags, 57077224Scth name, valuep, lengthp, nblocks64 / dblk, lbasize)); 57087224Scth } 5709