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 /*
2311536SSharath.Srinivasan@Sun.COM * Copyright 2010 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 /*
25011748SShidokht.Yadegari@Sun.COM * This implies an upper limit of 8192 GPT partitions
25111748SShidokht.Yadegari@Sun.COM * in one transfer for GUID Partition Entry Array.
25211748SShidokht.Yadegari@Sun.COM */
25311748SShidokht.Yadegari@Sun.COM len_t cmlb_tg_max_efi_xfer = 1024 * 1024;
25411748SShidokht.Yadegari@Sun.COM
25511748SShidokht.Yadegari@Sun.COM /*
2566318Sedp * External kernel interfaces
2576318Sedp */
258786Slclee extern struct mod_ops mod_miscops;
259786Slclee
2606318Sedp extern int ddi_create_internal_pathname(dev_info_t *dip, char *name,
2616318Sedp int spec_type, minor_t minor_num);
2626318Sedp
263786Slclee /*
264786Slclee * Global buffer and mutex for debug logging
265786Slclee */
266786Slclee static char cmlb_log_buffer[1024];
267786Slclee static kmutex_t cmlb_log_mutex;
268786Slclee
269786Slclee
2703525Sshidokht struct cmlb_lun *cmlb_debug_cl = NULL;
271786Slclee uint_t cmlb_level_mask = 0x0;
272786Slclee
273786Slclee int cmlb_rot_delay = 4; /* default rotational delay */
274786Slclee
275786Slclee static struct modlmisc modlmisc = {
276786Slclee &mod_miscops, /* Type of module */
2777563SPrasad.Singamsetty@Sun.COM "Common Labeling module"
278786Slclee };
279786Slclee
280786Slclee static struct modlinkage modlinkage = {
281786Slclee MODREV_1, (void *)&modlmisc, NULL
282786Slclee };
283786Slclee
284786Slclee /* Local function prototypes */
2853525Sshidokht static dev_t cmlb_make_device(struct cmlb_lun *cl);
2868863SEdward.Pilatowicz@Sun.COM static int cmlb_validate_geometry(struct cmlb_lun *cl, boolean_t forcerevalid,
2873525Sshidokht int flags, void *tg_cookie);
2883525Sshidokht static void cmlb_resync_geom_caches(struct cmlb_lun *cl, diskaddr_t capacity,
2893525Sshidokht void *tg_cookie);
2903525Sshidokht static int cmlb_read_fdisk(struct cmlb_lun *cl, diskaddr_t capacity,
2913525Sshidokht void *tg_cookie);
292786Slclee static void cmlb_swap_efi_gpt(efi_gpt_t *e);
293786Slclee static void cmlb_swap_efi_gpe(int nparts, efi_gpe_t *p);
294786Slclee static int cmlb_validate_efi(efi_gpt_t *labp);
2953525Sshidokht static int cmlb_use_efi(struct cmlb_lun *cl, diskaddr_t capacity, int flags,
2963525Sshidokht void *tg_cookie);
2973525Sshidokht static void cmlb_build_default_label(struct cmlb_lun *cl, void *tg_cookie);
2983525Sshidokht static int cmlb_uselabel(struct cmlb_lun *cl, struct dk_label *l, int flags);
2993525Sshidokht #if defined(_SUNOS_VTOC_8)
3003525Sshidokht static void cmlb_build_user_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc);
3013525Sshidokht #endif
3023525Sshidokht static int cmlb_build_label_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc);
3033525Sshidokht static int cmlb_write_label(struct cmlb_lun *cl, void *tg_cookie);
3043525Sshidokht static int cmlb_set_vtoc(struct cmlb_lun *cl, struct dk_label *dkl,
3053525Sshidokht void *tg_cookie);
3063525Sshidokht static void cmlb_clear_efi(struct cmlb_lun *cl, void *tg_cookie);
3073525Sshidokht static void cmlb_clear_vtoc(struct cmlb_lun *cl, void *tg_cookie);
3083525Sshidokht static void cmlb_setup_default_geometry(struct cmlb_lun *cl, void *tg_cookie);
3093525Sshidokht static int cmlb_create_minor_nodes(struct cmlb_lun *cl);
3103525Sshidokht static int cmlb_check_update_blockcount(struct cmlb_lun *cl, void *tg_cookie);
3118863SEdward.Pilatowicz@Sun.COM static boolean_t cmlb_check_efi_mbr(uchar_t *buf, boolean_t *is_mbr);
312786Slclee
313786Slclee #if defined(__i386) || defined(__amd64)
3143525Sshidokht static int cmlb_update_fdisk_and_vtoc(struct cmlb_lun *cl, void *tg_cookie);
315786Slclee #endif
316786Slclee
317786Slclee #if defined(_FIRMWARE_NEEDS_FDISK)
3188863SEdward.Pilatowicz@Sun.COM static boolean_t cmlb_has_max_chs_vals(struct ipart *fdp);
319786Slclee #endif
320786Slclee
321786Slclee #if defined(_SUNOS_VTOC_16)
32210320SLarry.Liu@Sun.COM static void cmlb_convert_geometry(struct cmlb_lun *cl, diskaddr_t capacity,
32310320SLarry.Liu@Sun.COM struct dk_geom *cl_g, void *tg_cookie);
324786Slclee #endif
325786Slclee
3263525Sshidokht static int cmlb_dkio_get_geometry(struct cmlb_lun *cl, caddr_t arg, int flag,
3273525Sshidokht void *tg_cookie);
3283525Sshidokht static int cmlb_dkio_set_geometry(struct cmlb_lun *cl, caddr_t arg, int flag);
3293525Sshidokht static int cmlb_dkio_get_partition(struct cmlb_lun *cl, caddr_t arg, int flag,
3303525Sshidokht void *tg_cookie);
3313525Sshidokht static int cmlb_dkio_set_partition(struct cmlb_lun *cl, caddr_t arg, int flag);
3323525Sshidokht static int cmlb_dkio_get_efi(struct cmlb_lun *cl, caddr_t arg, int flag,
3333525Sshidokht void *tg_cookie);
3343525Sshidokht static int cmlb_dkio_set_efi(struct cmlb_lun *cl, dev_t dev, caddr_t arg,
3353525Sshidokht int flag, void *tg_cookie);
3363525Sshidokht static int cmlb_dkio_get_vtoc(struct cmlb_lun *cl, caddr_t arg, int flag,
3373525Sshidokht void *tg_cookie);
3387563SPrasad.Singamsetty@Sun.COM static int cmlb_dkio_get_extvtoc(struct cmlb_lun *cl, caddr_t arg, int flag,
3397563SPrasad.Singamsetty@Sun.COM void *tg_cookie);
3403525Sshidokht static int cmlb_dkio_set_vtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg,
3413525Sshidokht int flag, void *tg_cookie);
3427563SPrasad.Singamsetty@Sun.COM static int cmlb_dkio_set_extvtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg,
3437563SPrasad.Singamsetty@Sun.COM int flag, void *tg_cookie);
3443525Sshidokht static int cmlb_dkio_get_mboot(struct cmlb_lun *cl, caddr_t arg, int flag,
3453525Sshidokht void *tg_cookie);
3463525Sshidokht static int cmlb_dkio_set_mboot(struct cmlb_lun *cl, caddr_t arg, int flag,
3473525Sshidokht void *tg_cookie);
3483525Sshidokht static int cmlb_dkio_partition(struct cmlb_lun *cl, caddr_t arg, int flag,
3493525Sshidokht void *tg_cookie);
350786Slclee
351786Slclee #if defined(__i386) || defined(__amd64)
35210021SSheshadri.Vasudevan@Sun.COM static int cmlb_dkio_set_ext_part(struct cmlb_lun *cl, caddr_t arg, int flag,
35310021SSheshadri.Vasudevan@Sun.COM void *tg_cookie);
35410021SSheshadri.Vasudevan@Sun.COM static int cmlb_validate_ext_part(struct cmlb_lun *cl, int part, int epart,
35510021SSheshadri.Vasudevan@Sun.COM uint32_t start, uint32_t size);
35610021SSheshadri.Vasudevan@Sun.COM static int cmlb_is_linux_swap(struct cmlb_lun *cl, uint32_t part_start,
35710021SSheshadri.Vasudevan@Sun.COM void *tg_cookie);
3583525Sshidokht static int cmlb_dkio_get_virtgeom(struct cmlb_lun *cl, caddr_t arg, int flag);
35910320SLarry.Liu@Sun.COM static int cmlb_dkio_get_phygeom(struct cmlb_lun *cl, caddr_t arg, int flag,
36010320SLarry.Liu@Sun.COM void *tg_cookie);
3613525Sshidokht static int cmlb_dkio_partinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg,
362786Slclee int flag);
3637563SPrasad.Singamsetty@Sun.COM static int cmlb_dkio_extpartinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg,
3647563SPrasad.Singamsetty@Sun.COM int flag);
365786Slclee #endif
366786Slclee
3673525Sshidokht static void cmlb_dbg(uint_t comp, struct cmlb_lun *cl, const char *fmt, ...);
36811748SShidokht.Yadegari@Sun.COM static void cmlb_v_log(dev_info_t *dev, const char *label, uint_t level,
369786Slclee const char *fmt, va_list ap);
37011748SShidokht.Yadegari@Sun.COM static void cmlb_log(dev_info_t *dev, const char *label, uint_t level,
371786Slclee const char *fmt, ...);
372786Slclee
373786Slclee int
_init(void)374786Slclee _init(void)
375786Slclee {
376786Slclee mutex_init(&cmlb_log_mutex, NULL, MUTEX_DRIVER, NULL);
377786Slclee return (mod_install(&modlinkage));
378786Slclee }
379786Slclee
380786Slclee int
_info(struct modinfo * modinfop)381786Slclee _info(struct modinfo *modinfop)
382786Slclee {
383786Slclee return (mod_info(&modlinkage, modinfop));
384786Slclee }
385786Slclee
386786Slclee int
_fini(void)387786Slclee _fini(void)
388786Slclee {
389786Slclee int err;
390786Slclee
391786Slclee if ((err = mod_remove(&modlinkage)) != 0) {
392786Slclee return (err);
393786Slclee }
394786Slclee
395786Slclee mutex_destroy(&cmlb_log_mutex);
396786Slclee return (err);
397786Slclee }
398786Slclee
399786Slclee /*
400786Slclee * cmlb_dbg is used for debugging to log additional info
401786Slclee * Level of output is controlled via cmlb_level_mask setting.
402786Slclee */
403786Slclee static void
cmlb_dbg(uint_t comp,struct cmlb_lun * cl,const char * fmt,...)4043525Sshidokht cmlb_dbg(uint_t comp, struct cmlb_lun *cl, const char *fmt, ...)
405786Slclee {
406786Slclee va_list ap;
407786Slclee dev_info_t *dev;
408786Slclee uint_t level_mask = 0;
409786Slclee
4103525Sshidokht ASSERT(cl != NULL);
4113525Sshidokht dev = CMLB_DEVINFO(cl);
412786Slclee ASSERT(dev != NULL);
413786Slclee /*
414786Slclee * Filter messages based on the global component and level masks,
4153525Sshidokht * also print if cl matches the value of cmlb_debug_cl, or if
4163525Sshidokht * cmlb_debug_cl is set to NULL.
417786Slclee */
418786Slclee if (comp & CMLB_TRACE)
419786Slclee level_mask |= CMLB_LOGMASK_TRACE;
420786Slclee
421786Slclee if (comp & CMLB_INFO)
422786Slclee level_mask |= CMLB_LOGMASK_INFO;
423786Slclee
424786Slclee if (comp & CMLB_ERROR)
425786Slclee level_mask |= CMLB_LOGMASK_ERROR;
426786Slclee
427786Slclee if ((cmlb_level_mask & level_mask) &&
4283525Sshidokht ((cmlb_debug_cl == NULL) || (cmlb_debug_cl == cl))) {
429786Slclee va_start(ap, fmt);
4303525Sshidokht cmlb_v_log(dev, CMLB_LABEL(cl), CE_CONT, fmt, ap);
431786Slclee va_end(ap);
432786Slclee }
433786Slclee }
434786Slclee
435786Slclee /*
436786Slclee * cmlb_log is basically a duplicate of scsi_log. It is redefined here
437786Slclee * so that this module does not depend on scsi module.
438786Slclee */
439786Slclee static void
cmlb_log(dev_info_t * dev,const char * label,uint_t level,const char * fmt,...)44011748SShidokht.Yadegari@Sun.COM cmlb_log(dev_info_t *dev, const char *label, uint_t level, const char *fmt, ...)
441786Slclee {
442786Slclee va_list ap;
443786Slclee
444786Slclee va_start(ap, fmt);
445786Slclee cmlb_v_log(dev, label, level, fmt, ap);
446786Slclee va_end(ap);
447786Slclee }
448786Slclee
449786Slclee static void
cmlb_v_log(dev_info_t * dev,const char * label,uint_t level,const char * fmt,va_list ap)45011748SShidokht.Yadegari@Sun.COM cmlb_v_log(dev_info_t *dev, const char *label, uint_t level, const char *fmt,
451786Slclee va_list ap)
452786Slclee {
453786Slclee static char name[256];
454786Slclee int log_only = 0;
455786Slclee int boot_only = 0;
456786Slclee int console_only = 0;
457786Slclee
458786Slclee mutex_enter(&cmlb_log_mutex);
459786Slclee
460786Slclee if (dev) {
461786Slclee if (level == CE_PANIC || level == CE_WARN ||
462786Slclee level == CE_NOTE) {
463786Slclee (void) sprintf(name, "%s (%s%d):\n",
464786Slclee ddi_pathname(dev, cmlb_log_buffer),
465786Slclee label, ddi_get_instance(dev));
466786Slclee } else {
467786Slclee name[0] = '\0';
468786Slclee }
469786Slclee } else {
470786Slclee (void) sprintf(name, "%s:", label);
471786Slclee }
472786Slclee
473786Slclee (void) vsprintf(cmlb_log_buffer, fmt, ap);
474786Slclee
475786Slclee switch (cmlb_log_buffer[0]) {
476786Slclee case '!':
477786Slclee log_only = 1;
478786Slclee break;
479786Slclee case '?':
480786Slclee boot_only = 1;
481786Slclee break;
482786Slclee case '^':
483786Slclee console_only = 1;
484786Slclee break;
485786Slclee }
486786Slclee
487786Slclee switch (level) {
488786Slclee case CE_NOTE:
489786Slclee level = CE_CONT;
490786Slclee /* FALLTHROUGH */
491786Slclee case CE_CONT:
492786Slclee case CE_WARN:
493786Slclee case CE_PANIC:
494786Slclee if (boot_only) {
495786Slclee cmn_err(level, "?%s\t%s", name, &cmlb_log_buffer[1]);
496786Slclee } else if (console_only) {
497786Slclee cmn_err(level, "^%s\t%s", name, &cmlb_log_buffer[1]);
498786Slclee } else if (log_only) {
499786Slclee cmn_err(level, "!%s\t%s", name, &cmlb_log_buffer[1]);
500786Slclee } else {
501786Slclee cmn_err(level, "%s\t%s", name, cmlb_log_buffer);
502786Slclee }
503786Slclee break;
504786Slclee case CE_IGNORE:
505786Slclee break;
506786Slclee default:
507786Slclee cmn_err(CE_CONT, "^DEBUG: %s\t%s", name, cmlb_log_buffer);
508786Slclee break;
509786Slclee }
510786Slclee mutex_exit(&cmlb_log_mutex);
511786Slclee }
512786Slclee
513786Slclee
514786Slclee /*
515786Slclee * cmlb_alloc_handle:
516786Slclee *
517786Slclee * Allocates a handle.
518786Slclee *
519786Slclee * Arguments:
520786Slclee * cmlbhandlep pointer to handle
521786Slclee *
522786Slclee * Notes:
523786Slclee * Allocates a handle and stores the allocated handle in the area
524786Slclee * pointed to by cmlbhandlep
525786Slclee *
526786Slclee * Context:
527786Slclee * Kernel thread only (can sleep).
528786Slclee */
529786Slclee void
cmlb_alloc_handle(cmlb_handle_t * cmlbhandlep)530786Slclee cmlb_alloc_handle(cmlb_handle_t *cmlbhandlep)
531786Slclee {
5323525Sshidokht struct cmlb_lun *cl;
5333525Sshidokht
5343525Sshidokht cl = kmem_zalloc(sizeof (struct cmlb_lun), KM_SLEEP);
535786Slclee ASSERT(cmlbhandlep != NULL);
536786Slclee
5373525Sshidokht cl->cl_state = CMLB_INITED;
5383525Sshidokht cl->cl_def_labeltype = CMLB_LABEL_UNDEF;
5393525Sshidokht mutex_init(CMLB_MUTEX(cl), NULL, MUTEX_DRIVER, NULL);
5403525Sshidokht
5413525Sshidokht *cmlbhandlep = (cmlb_handle_t)(cl);
542786Slclee }
543786Slclee
544786Slclee /*
545786Slclee * cmlb_free_handle
546786Slclee *
547786Slclee * Frees handle.
548786Slclee *
549786Slclee * Arguments:
550786Slclee * cmlbhandlep pointer to handle
551786Slclee */
552786Slclee void
cmlb_free_handle(cmlb_handle_t * cmlbhandlep)553786Slclee cmlb_free_handle(cmlb_handle_t *cmlbhandlep)
554786Slclee {
5553525Sshidokht struct cmlb_lun *cl;
5563525Sshidokht
5573525Sshidokht cl = (struct cmlb_lun *)*cmlbhandlep;
5583525Sshidokht if (cl != NULL) {
5593525Sshidokht mutex_destroy(CMLB_MUTEX(cl));
5603525Sshidokht kmem_free(cl, sizeof (struct cmlb_lun));
561786Slclee }
562786Slclee
563786Slclee }
564786Slclee
565786Slclee /*
566786Slclee * cmlb_attach:
567786Slclee *
568786Slclee * Attach handle to device, create minor nodes for device.
569786Slclee *
570786Slclee * Arguments:
571786Slclee * devi pointer to device's dev_info structure.
572786Slclee * tgopsp pointer to array of functions cmlb can use to callback
573786Slclee * to target driver.
574786Slclee *
575786Slclee * device_type Peripheral device type as defined in
576786Slclee * scsi/generic/inquiry.h
577786Slclee *
578786Slclee * is_removable whether or not device is removable.
579786Slclee *
5803525Sshidokht * is_hotpluggable whether or not device is hotpluggable.
5813525Sshidokht *
582786Slclee * node_type minor node type (as used by ddi_create_minor_node)
583786Slclee *
584786Slclee * alter_behavior
585786Slclee * bit flags:
586786Slclee *
587786Slclee * CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT: create
588786Slclee * an alternate slice for the default label, if
589786Slclee * device type is DTYPE_DIRECT an architectures default
590786Slclee * label type is VTOC16.
591786Slclee * Otherwise alternate slice will no be created.
592786Slclee *
593786Slclee *
594786Slclee * CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8: report a default
595786Slclee * geometry and label for DKIOCGGEOM and DKIOCGVTOC
596786Slclee * on architecture with VTOC8 label types.
597786Slclee *
5983525Sshidokht * CMLB_OFF_BY_ONE: do the workaround for legacy off-by-
5993525Sshidokht * one bug in obtaining capacity (in sd):
6003525Sshidokht * SCSI READ_CAPACITY command returns the LBA number of the
6013525Sshidokht * last logical block, but sd once treated this number as
6023525Sshidokht * disks' capacity on x86 platform. And LBAs are addressed
6033525Sshidokht * based 0. So the last block was lost on x86 platform.
6043525Sshidokht *
6053525Sshidokht * Now, we remove this workaround. In order for present sd
6063525Sshidokht * driver to work with disks which are labeled/partitioned
6073525Sshidokht * via previous sd, we add workaround as follows:
6083525Sshidokht *
6093525Sshidokht * 1) Locate backup EFI label: cmlb searches the next to
6103525Sshidokht * last
6113525Sshidokht * block for backup EFI label. If fails, it will
6123525Sshidokht * turn to the last block for backup EFI label;
6133525Sshidokht *
6143525Sshidokht * 2) Clear backup EFI label: cmlb first search the last
6153525Sshidokht * block for backup EFI label, and will search the
6163525Sshidokht * next to last block only if failed for the last
6173525Sshidokht * block.
6183525Sshidokht *
6193525Sshidokht * 3) Calculate geometry:refer to cmlb_convert_geometry()
6203525Sshidokht * If capacity increasing by 1 causes disks' capacity
6217563SPrasad.Singamsetty@Sun.COM * to cross over the limits in geometry calculation,
6223525Sshidokht * geometry info will change. This will raise an issue:
6233525Sshidokht * In case that primary VTOC label is destroyed, format
6243525Sshidokht * commandline can restore it via backup VTOC labels.
6253525Sshidokht * And format locates backup VTOC labels by use of
6263525Sshidokht * geometry. So changing geometry will
6273525Sshidokht * prevent format from finding backup VTOC labels. To
6283525Sshidokht * eliminate this side effect for compatibility,
6293525Sshidokht * sd uses (capacity -1) to calculate geometry;
6303525Sshidokht *
6313525Sshidokht * 4) 1TB disks: some important data structures use
6323525Sshidokht * 32-bit signed long/int (for example, daddr_t),
6333525Sshidokht * so that sd doesn't support a disk with capacity
6343525Sshidokht * larger than 1TB on 32-bit platform. However,
6353525Sshidokht * for exactly 1TB disk, it was treated as (1T - 512)B
6363525Sshidokht * in the past, and could have valid Solaris
6373525Sshidokht * partitions. To workaround this, if an exactly 1TB
6383525Sshidokht * disk has Solaris fdisk partition, it will be allowed
6393525Sshidokht * to work with sd.
6403525Sshidokht *
6413525Sshidokht *
642786Slclee *
6435084Sjohnlev * CMLB_FAKE_LABEL_ONE_PARTITION: create s0 and s2 covering
6445084Sjohnlev * the entire disk, if there is no valid partition info.
6455084Sjohnlev * If there is a valid Solaris partition, s0 and s2 will
6465084Sjohnlev * only cover the entire Solaris partition.
6475084Sjohnlev *
6485084Sjohnlev *
649786Slclee * cmlbhandle cmlb handle associated with device
650786Slclee *
6513525Sshidokht * tg_cookie cookie from target driver to be passed back to target
6523525Sshidokht * driver when we call back to it through tg_ops.
6533525Sshidokht *
654786Slclee * Notes:
655786Slclee * Assumes a default label based on capacity for non-removable devices.
656786Slclee * If capacity > 1TB, EFI is assumed otherwise VTOC (default VTOC
657786Slclee * for the architecture).
658786Slclee *
659786Slclee * For removable devices, default label type is assumed to be VTOC
660786Slclee * type. Create minor nodes based on a default label type.
661786Slclee * Label on the media is not validated.
662786Slclee * minor number consists of:
663786Slclee * if _SUNOS_VTOC_8 is defined
664786Slclee * lowest 3 bits is taken as partition number
665786Slclee * the rest is instance number
666786Slclee * if _SUNOS_VTOC_16 is defined
667786Slclee * lowest 6 bits is taken as partition number
668786Slclee * the rest is instance number
669786Slclee *
670786Slclee *
671786Slclee * Return values:
672786Slclee * 0 Success
673786Slclee * ENXIO creating minor nodes failed.
6743525Sshidokht * EINVAL invalid arg, unsupported tg_ops version
675786Slclee */
676786Slclee int
cmlb_attach(dev_info_t * devi,cmlb_tg_ops_t * tgopsp,int device_type,boolean_t is_removable,boolean_t is_hotpluggable,char * node_type,int alter_behavior,cmlb_handle_t cmlbhandle,void * tg_cookie)677786Slclee cmlb_attach(dev_info_t *devi, cmlb_tg_ops_t *tgopsp, int device_type,
6788863SEdward.Pilatowicz@Sun.COM boolean_t is_removable, boolean_t is_hotpluggable, char *node_type,
6793525Sshidokht int alter_behavior, cmlb_handle_t cmlbhandle, void *tg_cookie)
680786Slclee {
681786Slclee
6823525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle;
683786Slclee diskaddr_t cap;
684786Slclee int status;
685786Slclee
6868863SEdward.Pilatowicz@Sun.COM ASSERT(VALID_BOOLEAN(is_removable));
6878863SEdward.Pilatowicz@Sun.COM ASSERT(VALID_BOOLEAN(is_hotpluggable));
6888863SEdward.Pilatowicz@Sun.COM
6893525Sshidokht if (tgopsp->tg_version < TG_DK_OPS_VERSION_1)
6903525Sshidokht return (EINVAL);
6913525Sshidokht
6923525Sshidokht mutex_enter(CMLB_MUTEX(cl));
6933525Sshidokht
6943525Sshidokht CMLB_DEVINFO(cl) = devi;
6953525Sshidokht cl->cmlb_tg_ops = tgopsp;
6963525Sshidokht cl->cl_device_type = device_type;
6973525Sshidokht cl->cl_is_removable = is_removable;
6983525Sshidokht cl->cl_is_hotpluggable = is_hotpluggable;
6993525Sshidokht cl->cl_node_type = node_type;
7003525Sshidokht cl->cl_sys_blocksize = DEV_BSIZE;
7018863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE;
7023525Sshidokht cl->cl_def_labeltype = CMLB_LABEL_VTOC;
7033525Sshidokht cl->cl_alter_behavior = alter_behavior;
7043525Sshidokht cl->cl_reserved = -1;
7057563SPrasad.Singamsetty@Sun.COM cl->cl_msglog_flag |= CMLB_ALLOW_2TB_WARN;
70610021SSheshadri.Vasudevan@Sun.COM #if defined(__i386) || defined(__amd64)
70710021SSheshadri.Vasudevan@Sun.COM cl->cl_logical_drive_count = 0;
70810021SSheshadri.Vasudevan@Sun.COM #endif
7097563SPrasad.Singamsetty@Sun.COM
7108863SEdward.Pilatowicz@Sun.COM if (!is_removable) {
7113525Sshidokht mutex_exit(CMLB_MUTEX(cl));
7123525Sshidokht status = DK_TG_GETCAP(cl, &cap, tg_cookie);
7133525Sshidokht mutex_enter(CMLB_MUTEX(cl));
7147563SPrasad.Singamsetty@Sun.COM if (status == 0 && cap > CMLB_EXTVTOC_LIMIT) {
7157563SPrasad.Singamsetty@Sun.COM /* set default EFI if > 2TB */
7163525Sshidokht cl->cl_def_labeltype = CMLB_LABEL_EFI;
717786Slclee }
718786Slclee }
719786Slclee
720786Slclee /* create minor nodes based on default label type */
7213525Sshidokht cl->cl_last_labeltype = CMLB_LABEL_UNDEF;
7223525Sshidokht cl->cl_cur_labeltype = CMLB_LABEL_UNDEF;
7233525Sshidokht
7243525Sshidokht if (cmlb_create_minor_nodes(cl) != 0) {
7253525Sshidokht mutex_exit(CMLB_MUTEX(cl));
726786Slclee return (ENXIO);
727786Slclee }
728786Slclee
7297224Scth /* Define the dynamic properties for devinfo spapshots. */
7307224Scth i_ddi_prop_dyn_driver_set(CMLB_DEVINFO(cl), cmlb_prop_dyn);
7317224Scth
7323525Sshidokht cl->cl_state = CMLB_ATTACHED;
7333525Sshidokht
7343525Sshidokht mutex_exit(CMLB_MUTEX(cl));
735786Slclee return (0);
736786Slclee }
737786Slclee
738786Slclee /*
739786Slclee * cmlb_detach:
740786Slclee *
741786Slclee * Invalidate in-core labeling data and remove all minor nodes for
742786Slclee * the device associate with handle.
743786Slclee *
744786Slclee * Arguments:
745786Slclee * cmlbhandle cmlb handle associated with device.
746786Slclee *
7473525Sshidokht * tg_cookie cookie from target driver to be passed back to target
7483525Sshidokht * driver when we call back to it through tg_ops.
7493525Sshidokht *
750786Slclee */
7513525Sshidokht /*ARGSUSED1*/
752786Slclee void
cmlb_detach(cmlb_handle_t cmlbhandle,void * tg_cookie)7533525Sshidokht cmlb_detach(cmlb_handle_t cmlbhandle, void *tg_cookie)
754786Slclee {
7553525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle;
7563525Sshidokht
7573525Sshidokht mutex_enter(CMLB_MUTEX(cl));
7583525Sshidokht cl->cl_def_labeltype = CMLB_LABEL_UNDEF;
7598863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE;
7603525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL);
7617224Scth i_ddi_prop_dyn_driver_set(CMLB_DEVINFO(cl), NULL);
7623525Sshidokht cl->cl_state = CMLB_INITED;
7633525Sshidokht mutex_exit(CMLB_MUTEX(cl));
764786Slclee }
765786Slclee
766786Slclee /*
767786Slclee * cmlb_validate:
768786Slclee *
769786Slclee * Validates label.
770786Slclee *
771786Slclee * Arguments
772786Slclee * cmlbhandle cmlb handle associated with device.
773786Slclee *
7743525Sshidokht * flags operation flags. used for verbosity control
7753525Sshidokht *
7763525Sshidokht * tg_cookie cookie from target driver to be passed back to target
7773525Sshidokht * driver when we call back to it through tg_ops.
7783525Sshidokht *
7793525Sshidokht *
780786Slclee * Notes:
781786Slclee * If new label type is different from the current, adjust minor nodes
782786Slclee * accordingly.
783786Slclee *
784786Slclee * Return values:
785786Slclee * 0 success
786786Slclee * Note: having fdisk but no solaris partition is assumed
787786Slclee * success.
788786Slclee *
789786Slclee * ENOMEM memory allocation failed
790786Slclee * EIO i/o errors during read or get capacity
791786Slclee * EACCESS reservation conflicts
792786Slclee * EINVAL label was corrupt, or no default label was assumed
793786Slclee * ENXIO invalid handle
794786Slclee */
795786Slclee int
cmlb_validate(cmlb_handle_t cmlbhandle,int flags,void * tg_cookie)7963525Sshidokht cmlb_validate(cmlb_handle_t cmlbhandle, int flags, void *tg_cookie)
797786Slclee {
7983525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle;
799786Slclee int rval;
800786Slclee int ret = 0;
801786Slclee
802786Slclee /*
8033525Sshidokht * Temp work-around checking cl for NULL since there is a bug
804786Slclee * in sd_detach calling this routine from taskq_dispatch
805786Slclee * inited function.
806786Slclee */
8073525Sshidokht if (cl == NULL)
808786Slclee return (ENXIO);
809786Slclee
8103525Sshidokht mutex_enter(CMLB_MUTEX(cl));
8113525Sshidokht if (cl->cl_state < CMLB_ATTACHED) {
8123525Sshidokht mutex_exit(CMLB_MUTEX(cl));
813786Slclee return (ENXIO);
814786Slclee }
815786Slclee
8168863SEdward.Pilatowicz@Sun.COM rval = cmlb_validate_geometry((struct cmlb_lun *)cmlbhandle, B_TRUE,
8173525Sshidokht flags, tg_cookie);
818786Slclee
819786Slclee if (rval == ENOTSUP) {
8208863SEdward.Pilatowicz@Sun.COM if (cl->cl_f_geometry_is_valid) {
8213525Sshidokht cl->cl_cur_labeltype = CMLB_LABEL_EFI;
822786Slclee ret = 0;
823786Slclee } else {
824786Slclee ret = EINVAL;
825786Slclee }
826786Slclee } else {
827786Slclee ret = rval;
828786Slclee if (ret == 0)
8293525Sshidokht cl->cl_cur_labeltype = CMLB_LABEL_VTOC;
830786Slclee }
831786Slclee
832786Slclee if (ret == 0)
8333525Sshidokht (void) cmlb_create_minor_nodes(cl);
8343525Sshidokht
8353525Sshidokht mutex_exit(CMLB_MUTEX(cl));
836786Slclee return (ret);
837786Slclee }
838786Slclee
839786Slclee /*
840786Slclee * cmlb_invalidate:
841786Slclee * Invalidate in core label data
842786Slclee *
843786Slclee * Arguments:
844786Slclee * cmlbhandle cmlb handle associated with device.
8453525Sshidokht * tg_cookie cookie from target driver to be passed back to target
8463525Sshidokht * driver when we call back to it through tg_ops.
847786Slclee */
8483525Sshidokht /*ARGSUSED1*/
849786Slclee void
cmlb_invalidate(cmlb_handle_t cmlbhandle,void * tg_cookie)8503525Sshidokht cmlb_invalidate(cmlb_handle_t cmlbhandle, void *tg_cookie)
851786Slclee {
8523525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle;
8533525Sshidokht
8543525Sshidokht if (cl == NULL)
855786Slclee return;
856786Slclee
8573525Sshidokht mutex_enter(CMLB_MUTEX(cl));
8588863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE;
8593525Sshidokht mutex_exit(CMLB_MUTEX(cl));
860786Slclee }
861786Slclee
862786Slclee /*
8633525Sshidokht * cmlb_is_valid
8643525Sshidokht * Get status on whether the incore label/geom data is valid
8653525Sshidokht *
8663525Sshidokht * Arguments:
8673525Sshidokht * cmlbhandle cmlb handle associated with device.
8683525Sshidokht *
8693525Sshidokht * Return values:
8708863SEdward.Pilatowicz@Sun.COM * B_TRUE if incore label/geom data is valid.
8718863SEdward.Pilatowicz@Sun.COM * B_FALSE otherwise.
8723525Sshidokht *
8733525Sshidokht */
8743525Sshidokht
8753525Sshidokht
8768863SEdward.Pilatowicz@Sun.COM boolean_t
cmlb_is_valid(cmlb_handle_t cmlbhandle)8773525Sshidokht cmlb_is_valid(cmlb_handle_t cmlbhandle)
8783525Sshidokht {
8793525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle;
8803525Sshidokht
8813525Sshidokht if (cmlbhandle == NULL)
8828863SEdward.Pilatowicz@Sun.COM return (B_FALSE);
8833525Sshidokht
8843525Sshidokht return (cl->cl_f_geometry_is_valid);
8853525Sshidokht
8863525Sshidokht }
8873525Sshidokht
8883525Sshidokht
8893525Sshidokht
8903525Sshidokht /*
891786Slclee * cmlb_close:
892786Slclee *
893786Slclee * Close the device, revert to a default label minor node for the device,
894786Slclee * if it is removable.
895786Slclee *
896786Slclee * Arguments:
897786Slclee * cmlbhandle cmlb handle associated with device.
898786Slclee *
8993525Sshidokht * tg_cookie cookie from target driver to be passed back to target
9003525Sshidokht * driver when we call back to it through tg_ops.
901786Slclee * Return values:
902786Slclee * 0 Success
903786Slclee * ENXIO Re-creating minor node failed.
904786Slclee */
9053525Sshidokht /*ARGSUSED1*/
906786Slclee int
cmlb_close(cmlb_handle_t cmlbhandle,void * tg_cookie)9073525Sshidokht cmlb_close(cmlb_handle_t cmlbhandle, void *tg_cookie)
908786Slclee {
9093525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle;
9103525Sshidokht
9113525Sshidokht mutex_enter(CMLB_MUTEX(cl));
9128863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE;
913786Slclee
914786Slclee /* revert to default minor node for this device */
9153525Sshidokht if (ISREMOVABLE(cl)) {
9163525Sshidokht cl->cl_cur_labeltype = CMLB_LABEL_UNDEF;
9173525Sshidokht (void) cmlb_create_minor_nodes(cl);
918786Slclee }
919786Slclee
9203525Sshidokht mutex_exit(CMLB_MUTEX(cl));
921786Slclee return (0);
922786Slclee }
923786Slclee
924786Slclee /*
925786Slclee * cmlb_get_devid_block:
926786Slclee * get the block number where device id is stored.
927786Slclee *
928786Slclee * Arguments:
929786Slclee * cmlbhandle cmlb handle associated with device.
930786Slclee * devidblockp pointer to block number.
9313525Sshidokht * tg_cookie cookie from target driver to be passed back to target
9323525Sshidokht * driver when we call back to it through tg_ops.
933786Slclee *
934786Slclee * Notes:
935786Slclee * It stores the block number of device id in the area pointed to
936786Slclee * by devidblockp.
937786Slclee * with the block number of device id.
938786Slclee *
939786Slclee * Return values:
940786Slclee * 0 success
941786Slclee * EINVAL device id does not apply to current label type.
942786Slclee */
9433525Sshidokht /*ARGSUSED2*/
944786Slclee int
cmlb_get_devid_block(cmlb_handle_t cmlbhandle,diskaddr_t * devidblockp,void * tg_cookie)9453525Sshidokht cmlb_get_devid_block(cmlb_handle_t cmlbhandle, diskaddr_t *devidblockp,
9463525Sshidokht void *tg_cookie)
947786Slclee {
948786Slclee daddr_t spc, blk, head, cyl;
9493525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle;
9503525Sshidokht
9513525Sshidokht mutex_enter(CMLB_MUTEX(cl));
9523525Sshidokht if (cl->cl_state < CMLB_ATTACHED) {
9533525Sshidokht mutex_exit(CMLB_MUTEX(cl));
9543525Sshidokht return (EINVAL);
9553525Sshidokht }
9563525Sshidokht
9578863SEdward.Pilatowicz@Sun.COM if ((!cl->cl_f_geometry_is_valid) ||
9583525Sshidokht (cl->cl_solaris_size < DK_LABEL_LOC)) {
9593525Sshidokht mutex_exit(CMLB_MUTEX(cl));
960786Slclee return (EINVAL);
961786Slclee }
962786Slclee
9633525Sshidokht if (cl->cl_cur_labeltype == CMLB_LABEL_EFI) {
9643525Sshidokht if (cl->cl_reserved != -1) {
9653525Sshidokht blk = cl->cl_map[cl->cl_reserved].dkl_cylno;
9663525Sshidokht } else {
9673525Sshidokht mutex_exit(CMLB_MUTEX(cl));
9683525Sshidokht return (EINVAL);
9693525Sshidokht }
9703525Sshidokht } else {
9716513Sml40262 /* if the disk is unlabeled, don't write a devid to it */
9727563SPrasad.Singamsetty@Sun.COM if (cl->cl_label_from_media != CMLB_LABEL_VTOC) {
9736513Sml40262 mutex_exit(CMLB_MUTEX(cl));
9746513Sml40262 return (EINVAL);
9756513Sml40262 }
9766513Sml40262
977786Slclee /* this geometry doesn't allow us to write a devid */
9783525Sshidokht if (cl->cl_g.dkg_acyl < 2) {
9793525Sshidokht mutex_exit(CMLB_MUTEX(cl));
980786Slclee return (EINVAL);
981786Slclee }
982786Slclee
983786Slclee /*
984786Slclee * Subtract 2 guarantees that the next to last cylinder
985786Slclee * is used
986786Slclee */
9873525Sshidokht cyl = cl->cl_g.dkg_ncyl + cl->cl_g.dkg_acyl - 2;
9883525Sshidokht spc = cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect;
9893525Sshidokht head = cl->cl_g.dkg_nhead - 1;
9906513Sml40262 blk = cl->cl_solaris_offset +
9916513Sml40262 (cyl * (spc - cl->cl_g.dkg_apc)) +
9923525Sshidokht (head * cl->cl_g.dkg_nsect) + 1;
993786Slclee }
9943525Sshidokht
995786Slclee *devidblockp = blk;
9963525Sshidokht mutex_exit(CMLB_MUTEX(cl));
997786Slclee return (0);
998786Slclee }
999786Slclee
1000786Slclee /*
1001786Slclee * cmlb_partinfo:
1002786Slclee * Get partition info for specified partition number.
1003786Slclee *
1004786Slclee * Arguments:
1005786Slclee * cmlbhandle cmlb handle associated with device.
1006786Slclee * part partition number
1007786Slclee * nblocksp pointer to number of blocks
1008786Slclee * startblockp pointer to starting block
1009786Slclee * partnamep pointer to name of partition
1010786Slclee * tagp pointer to tag info
10113525Sshidokht * tg_cookie cookie from target driver to be passed back to target
10123525Sshidokht * driver when we call back to it through tg_ops.
1013786Slclee *
1014786Slclee *
1015786Slclee * Notes:
1016786Slclee * If in-core label is not valid, this functions tries to revalidate
1017786Slclee * the label. If label is valid, it stores the total number of blocks
1018786Slclee * in this partition in the area pointed to by nblocksp, starting
1019786Slclee * block number in area pointed to by startblockp, pointer to partition
1020786Slclee * name in area pointed to by partnamep, and tag value in area
1021786Slclee * pointed by tagp.
1022786Slclee * For EFI labels, tag value will be set to 0.
1023786Slclee *
1024786Slclee * For all nblocksp, startblockp and partnamep, tagp, a value of NULL
1025786Slclee * indicates the corresponding info is not requested.
1026786Slclee *
1027786Slclee *
1028786Slclee * Return values:
1029786Slclee * 0 success
1030786Slclee * EINVAL no valid label or requested partition number is invalid.
1031786Slclee *
1032786Slclee */
1033786Slclee int
cmlb_partinfo(cmlb_handle_t cmlbhandle,int part,diskaddr_t * nblocksp,diskaddr_t * startblockp,char ** partnamep,uint16_t * tagp,void * tg_cookie)1034786Slclee cmlb_partinfo(cmlb_handle_t cmlbhandle, int part, diskaddr_t *nblocksp,
10353525Sshidokht diskaddr_t *startblockp, char **partnamep, uint16_t *tagp, void *tg_cookie)
1036786Slclee {
1037786Slclee
10383525Sshidokht struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle;
1039786Slclee int rval;
104010021SSheshadri.Vasudevan@Sun.COM #if defined(__i386) || defined(__amd64)
104110021SSheshadri.Vasudevan@Sun.COM int ext_part;
104210021SSheshadri.Vasudevan@Sun.COM #endif
1043786Slclee
10443525Sshidokht ASSERT(cl != NULL);
10453525Sshidokht mutex_enter(CMLB_MUTEX(cl));
10463525Sshidokht if (cl->cl_state < CMLB_ATTACHED) {
10473525Sshidokht mutex_exit(CMLB_MUTEX(cl));
1048786Slclee return (EINVAL);
1049786Slclee }
1050786Slclee
1051786Slclee if (part < 0 || part >= MAXPART) {
1052786Slclee rval = EINVAL;
1053786Slclee } else {
10548863SEdward.Pilatowicz@Sun.COM if (!cl->cl_f_geometry_is_valid)
10558863SEdward.Pilatowicz@Sun.COM (void) cmlb_validate_geometry((struct cmlb_lun *)cl,
10568863SEdward.Pilatowicz@Sun.COM B_FALSE, 0, tg_cookie);
10573525Sshidokht
10587563SPrasad.Singamsetty@Sun.COM #if defined(_SUNOS_VTOC_16)
10598863SEdward.Pilatowicz@Sun.COM if (((!cl->cl_f_geometry_is_valid) ||
10607563SPrasad.Singamsetty@Sun.COM (part < NDKMAP && cl->cl_solaris_size == 0)) &&
10617563SPrasad.Singamsetty@Sun.COM (part != P0_RAW_DISK)) {
10627563SPrasad.Singamsetty@Sun.COM #else
10638863SEdward.Pilatowicz@Sun.COM if ((!cl->cl_f_geometry_is_valid) ||
10643525Sshidokht (part < NDKMAP && cl->cl_solaris_size == 0)) {
10657563SPrasad.Singamsetty@Sun.COM #endif
1066786Slclee rval = EINVAL;
1067786Slclee } else {
1068786Slclee if (startblockp != NULL)
10693525Sshidokht *startblockp = (diskaddr_t)cl->cl_offset[part];
1070786Slclee
1071786Slclee if (nblocksp != NULL)
1072786Slclee *nblocksp = (diskaddr_t)
10733525Sshidokht cl->cl_map[part].dkl_nblk;
1074786Slclee
1075786Slclee if (tagp != NULL)
107611748SShidokht.Yadegari@Sun.COM *tagp =
107711748SShidokht.Yadegari@Sun.COM ((cl->cl_cur_labeltype == CMLB_LABEL_EFI) ||
107811748SShidokht.Yadegari@Sun.COM (part >= NDKMAP)) ? V_UNASSIGNED :
107911748SShidokht.Yadegari@Sun.COM cl->cl_vtoc.v_part[part].p_tag;
1080786Slclee rval = 0;
1081786Slclee }
1082786Slclee
1083786Slclee /* consistent with behavior of sd for getting minor name */
108410021SSheshadri.Vasudevan@Sun.COM if (partnamep != NULL) {
108510021SSheshadri.Vasudevan@Sun.COM #if defined(__i386) || defined(__amd64)
108610021SSheshadri.Vasudevan@Sun.COM #if defined(_FIRMWARE_NEEDS_FDISK)
108710021SSheshadri.Vasudevan@Sun.COM if (part > FDISK_P4) {
108810021SSheshadri.Vasudevan@Sun.COM ext_part = part-FDISK_P4-1;
108910021SSheshadri.Vasudevan@Sun.COM *partnamep = dk_ext_minor_data[ext_part].name;
109010021SSheshadri.Vasudevan@Sun.COM } else
109110021SSheshadri.Vasudevan@Sun.COM #endif
109210021SSheshadri.Vasudevan@Sun.COM #endif
1093786Slclee *partnamep = dk_minor_data[part].name;
109410021SSheshadri.Vasudevan@Sun.COM }
1095786Slclee
1096786Slclee }
1097786Slclee
10983525Sshidokht mutex_exit(CMLB_MUTEX(cl));
1099786Slclee return (rval);
1100786Slclee }
1101786Slclee
11026590Syl194034 /*
11036590Syl194034 * cmlb_efi_label_capacity:
11046590Syl194034 * Get capacity stored in EFI disk label.
11056590Syl194034 *
11066590Syl194034 * Arguments:
11076590Syl194034 * cmlbhandle cmlb handle associated with device.
11086590Syl194034 * capacity pointer to capacity stored in EFI disk label.
11096590Syl194034 * tg_cookie cookie from target driver to be passed back to target
11106590Syl194034 * driver when we call back to it through tg_ops.
11116590Syl194034 *
11126590Syl194034 *
11136590Syl194034 * Notes:
11146590Syl194034 * If in-core label is not valid, this functions tries to revalidate
11156590Syl194034 * the label. If label is valid and is an EFI label, it stores the capacity
11166590Syl194034 * in disk label in the area pointed to by capacity.
11176590Syl194034 *
11186590Syl194034 *
11196590Syl194034 * Return values:
11206590Syl194034 * 0 success
11216590Syl194034 * EINVAL no valid EFI label or capacity is NULL.
11226590Syl194034 *
11236590Syl194034 */
11246590Syl194034 int
11256590Syl194034 cmlb_efi_label_capacity(cmlb_handle_t cmlbhandle, diskaddr_t *capacity,
11266590Syl194034 void *tg_cookie)
11276590Syl194034 {
11286590Syl194034 struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle;
11296590Syl194034 int rval;
11306590Syl194034
11316590Syl194034 ASSERT(cl != NULL);
11326590Syl194034 mutex_enter(CMLB_MUTEX(cl));
11336590Syl194034 if (cl->cl_state < CMLB_ATTACHED) {
11346590Syl194034 mutex_exit(CMLB_MUTEX(cl));
11356590Syl194034 return (EINVAL);
11366590Syl194034 }
11376590Syl194034
11388863SEdward.Pilatowicz@Sun.COM if (!cl->cl_f_geometry_is_valid)
11398863SEdward.Pilatowicz@Sun.COM (void) cmlb_validate_geometry((struct cmlb_lun *)cl, B_FALSE,
11406590Syl194034 0, tg_cookie);
11416590Syl194034
11428863SEdward.Pilatowicz@Sun.COM if ((!cl->cl_f_geometry_is_valid) || (capacity == NULL) ||
11436590Syl194034 (cl->cl_cur_labeltype != CMLB_LABEL_EFI)) {
11446590Syl194034 rval = EINVAL;
11456590Syl194034 } else {
11466590Syl194034 *capacity = (diskaddr_t)cl->cl_map[WD_NODE].dkl_nblk;
11476590Syl194034 rval = 0;
11486590Syl194034 }
11496590Syl194034
11506590Syl194034 mutex_exit(CMLB_MUTEX(cl));
11516590Syl194034 return (rval);
11526590Syl194034 }
11536590Syl194034
11543525Sshidokht /* Caller should make sure Test Unit Ready succeeds before calling this. */
11553525Sshidokht /*ARGSUSED*/
1156786Slclee int
1157786Slclee cmlb_ioctl(cmlb_handle_t cmlbhandle, dev_t dev, int cmd, intptr_t arg,
11583525Sshidokht int flag, cred_t *cred_p, int *rval_p, void *tg_cookie)
1159786Slclee {
1160786Slclee
1161786Slclee int err;
11623525Sshidokht struct cmlb_lun *cl;
11633525Sshidokht
11643525Sshidokht cl = (struct cmlb_lun *)cmlbhandle;
11653525Sshidokht
11663525Sshidokht ASSERT(cl != NULL);
11673525Sshidokht
11683525Sshidokht mutex_enter(CMLB_MUTEX(cl));
11693525Sshidokht if (cl->cl_state < CMLB_ATTACHED) {
11703525Sshidokht mutex_exit(CMLB_MUTEX(cl));
1171786Slclee return (EIO);
1172786Slclee }
1173786Slclee
1174786Slclee switch (cmd) {
11757563SPrasad.Singamsetty@Sun.COM case DKIOCSEXTVTOC:
11763525Sshidokht case DKIOCSGEOM:
1177786Slclee case DKIOCSETEFI:
1178786Slclee case DKIOCSMBOOT:
117910021SSheshadri.Vasudevan@Sun.COM #if defined(__i386) || defined(__amd64)
118010021SSheshadri.Vasudevan@Sun.COM case DKIOCSETEXTPART:
118110021SSheshadri.Vasudevan@Sun.COM #endif
1182786Slclee break;
11837563SPrasad.Singamsetty@Sun.COM case DKIOCSVTOC:
11847563SPrasad.Singamsetty@Sun.COM #if defined(__i386) || defined(__amd64)
11857563SPrasad.Singamsetty@Sun.COM case DKIOCPARTINFO:
11867563SPrasad.Singamsetty@Sun.COM #endif
11877563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) {
11887563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl));
11897563SPrasad.Singamsetty@Sun.COM return (EOVERFLOW);
11907563SPrasad.Singamsetty@Sun.COM }
11917563SPrasad.Singamsetty@Sun.COM break;
1192786Slclee default:
11937563SPrasad.Singamsetty@Sun.COM (void) cmlb_validate_geometry(cl, 1, CMLB_SILENT,
11943903Sshidokht tg_cookie);
11953525Sshidokht
11967563SPrasad.Singamsetty@Sun.COM switch (cmd) {
11977563SPrasad.Singamsetty@Sun.COM case DKIOCGVTOC:
11987563SPrasad.Singamsetty@Sun.COM case DKIOCGAPART:
11997563SPrasad.Singamsetty@Sun.COM case DKIOCSAPART:
12007563SPrasad.Singamsetty@Sun.COM
12017563SPrasad.Singamsetty@Sun.COM if (cl->cl_label_from_media == CMLB_LABEL_EFI) {
12027563SPrasad.Singamsetty@Sun.COM /* GPT label on disk */
12037563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl));
12047563SPrasad.Singamsetty@Sun.COM return (ENOTSUP);
12057563SPrasad.Singamsetty@Sun.COM } else if
12067563SPrasad.Singamsetty@Sun.COM (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) {
12077563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl));
12087563SPrasad.Singamsetty@Sun.COM return (EOVERFLOW);
12097563SPrasad.Singamsetty@Sun.COM }
12107563SPrasad.Singamsetty@Sun.COM break;
12117563SPrasad.Singamsetty@Sun.COM
12127563SPrasad.Singamsetty@Sun.COM case DKIOCGGEOM:
12137563SPrasad.Singamsetty@Sun.COM if (cl->cl_label_from_media == CMLB_LABEL_EFI) {
12147563SPrasad.Singamsetty@Sun.COM /* GPT label on disk */
12153525Sshidokht mutex_exit(CMLB_MUTEX(cl));
1216786Slclee return (ENOTSUP);
1217786Slclee }
12187563SPrasad.Singamsetty@Sun.COM break;
12197563SPrasad.Singamsetty@Sun.COM default:
12207563SPrasad.Singamsetty@Sun.COM break;
1221786Slclee }
1222786Slclee }
1223786Slclee
12243525Sshidokht mutex_exit(CMLB_MUTEX(cl));
1225786Slclee
1226786Slclee switch (cmd) {
1227786Slclee case DKIOCGGEOM:
12283525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGGEOM\n");
12293525Sshidokht err = cmlb_dkio_get_geometry(cl, (caddr_t)arg, flag, tg_cookie);
1230786Slclee break;
1231786Slclee
1232786Slclee case DKIOCSGEOM:
12333525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSGEOM\n");
12343525Sshidokht err = cmlb_dkio_set_geometry(cl, (caddr_t)arg, flag);
1235786Slclee break;
1236786Slclee
1237786Slclee case DKIOCGAPART:
12383525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGAPART\n");
12393525Sshidokht err = cmlb_dkio_get_partition(cl, (caddr_t)arg,
12403525Sshidokht flag, tg_cookie);
1241786Slclee break;
1242786Slclee
1243786Slclee case DKIOCSAPART:
12443525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSAPART\n");
12453525Sshidokht err = cmlb_dkio_set_partition(cl, (caddr_t)arg, flag);
1246786Slclee break;
1247786Slclee
1248786Slclee case DKIOCGVTOC:
12493525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGVTOC\n");
12503525Sshidokht err = cmlb_dkio_get_vtoc(cl, (caddr_t)arg, flag, tg_cookie);
1251786Slclee break;
1252786Slclee
12537563SPrasad.Singamsetty@Sun.COM case DKIOCGEXTVTOC:
12547563SPrasad.Singamsetty@Sun.COM cmlb_dbg(CMLB_TRACE, cl, "DKIOCGVTOC\n");
12557563SPrasad.Singamsetty@Sun.COM err = cmlb_dkio_get_extvtoc(cl, (caddr_t)arg, flag, tg_cookie);
12567563SPrasad.Singamsetty@Sun.COM break;
12577563SPrasad.Singamsetty@Sun.COM
1258786Slclee case DKIOCGETEFI:
12593525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGETEFI\n");
12603525Sshidokht err = cmlb_dkio_get_efi(cl, (caddr_t)arg, flag, tg_cookie);
1261786Slclee break;
1262786Slclee
1263786Slclee case DKIOCPARTITION:
12643525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCPARTITION\n");
12653525Sshidokht err = cmlb_dkio_partition(cl, (caddr_t)arg, flag, tg_cookie);
1266786Slclee break;
1267786Slclee
1268786Slclee case DKIOCSVTOC:
12693525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSVTOC\n");
12703525Sshidokht err = cmlb_dkio_set_vtoc(cl, dev, (caddr_t)arg, flag,
12713525Sshidokht tg_cookie);
1272786Slclee break;
1273786Slclee
12747563SPrasad.Singamsetty@Sun.COM case DKIOCSEXTVTOC:
12757563SPrasad.Singamsetty@Sun.COM cmlb_dbg(CMLB_TRACE, cl, "DKIOCSVTOC\n");
12767563SPrasad.Singamsetty@Sun.COM err = cmlb_dkio_set_extvtoc(cl, dev, (caddr_t)arg, flag,
12777563SPrasad.Singamsetty@Sun.COM tg_cookie);
12787563SPrasad.Singamsetty@Sun.COM break;
12797563SPrasad.Singamsetty@Sun.COM
1280786Slclee case DKIOCSETEFI:
12813525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSETEFI\n");
12823525Sshidokht err = cmlb_dkio_set_efi(cl, dev, (caddr_t)arg, flag, tg_cookie);
1283786Slclee break;
1284786Slclee
1285786Slclee case DKIOCGMBOOT:
12863525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCGMBOOT\n");
12873525Sshidokht err = cmlb_dkio_get_mboot(cl, (caddr_t)arg, flag, tg_cookie);
1288786Slclee break;
1289786Slclee
1290786Slclee case DKIOCSMBOOT:
12913525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCSMBOOT\n");
12923525Sshidokht err = cmlb_dkio_set_mboot(cl, (caddr_t)arg, flag, tg_cookie);
1293786Slclee break;
1294786Slclee case DKIOCG_PHYGEOM:
12953525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCG_PHYGEOM\n");
1296786Slclee #if defined(__i386) || defined(__amd64)
129710320SLarry.Liu@Sun.COM err = cmlb_dkio_get_phygeom(cl, (caddr_t)arg, flag, tg_cookie);
1298786Slclee #else
1299786Slclee err = ENOTTY;
1300786Slclee #endif
1301786Slclee break;
1302786Slclee case DKIOCG_VIRTGEOM:
13033525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCG_VIRTGEOM\n");
1304786Slclee #if defined(__i386) || defined(__amd64)
13053525Sshidokht err = cmlb_dkio_get_virtgeom(cl, (caddr_t)arg, flag);
1306786Slclee #else
1307786Slclee err = ENOTTY;
1308786Slclee #endif
1309786Slclee break;
1310786Slclee case DKIOCPARTINFO:
13113525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "DKIOCPARTINFO");
1312786Slclee #if defined(__i386) || defined(__amd64)
13133525Sshidokht err = cmlb_dkio_partinfo(cl, dev, (caddr_t)arg, flag);
1314786Slclee #else
1315786Slclee err = ENOTTY;
1316786Slclee #endif
1317786Slclee break;
13187563SPrasad.Singamsetty@Sun.COM case DKIOCEXTPARTINFO:
13197563SPrasad.Singamsetty@Sun.COM cmlb_dbg(CMLB_TRACE, cl, "DKIOCPARTINFO");
13207563SPrasad.Singamsetty@Sun.COM #if defined(__i386) || defined(__amd64)
13217563SPrasad.Singamsetty@Sun.COM err = cmlb_dkio_extpartinfo(cl, dev, (caddr_t)arg, flag);
13227563SPrasad.Singamsetty@Sun.COM #else
13237563SPrasad.Singamsetty@Sun.COM err = ENOTTY;
13247563SPrasad.Singamsetty@Sun.COM #endif
13257563SPrasad.Singamsetty@Sun.COM break;
132610021SSheshadri.Vasudevan@Sun.COM #if defined(__i386) || defined(__amd64)
132710021SSheshadri.Vasudevan@Sun.COM case DKIOCSETEXTPART:
132810021SSheshadri.Vasudevan@Sun.COM cmlb_dbg(CMLB_TRACE, cl, "DKIOCSETEXTPART");
132910021SSheshadri.Vasudevan@Sun.COM err = cmlb_dkio_set_ext_part(cl, (caddr_t)arg, flag, tg_cookie);
133010021SSheshadri.Vasudevan@Sun.COM break;
133110021SSheshadri.Vasudevan@Sun.COM #endif
1332786Slclee default:
1333786Slclee err = ENOTTY;
1334786Slclee
1335786Slclee }
13367224Scth
13377224Scth /*
13387224Scth * An ioctl that succeeds and changed ('set') size(9P) information
13397224Scth * needs to invalidate the cached devinfo snapshot to avoid having
13407224Scth * old information being returned in a snapshots.
13417224Scth *
13427224Scth * NB: When available, call ddi_change_minor_node() to clear
13437224Scth * SSIZEVALID in specfs vnodes via spec_size_invalidate().
13447224Scth */
13457224Scth if (err == 0) {
13467224Scth switch (cmd) {
13477224Scth case DKIOCSGEOM:
13487224Scth case DKIOCSAPART:
13497224Scth case DKIOCSVTOC:
13507563SPrasad.Singamsetty@Sun.COM case DKIOCSEXTVTOC:
13517224Scth case DKIOCSETEFI:
13527224Scth i_ddi_prop_dyn_cache_invalidate(CMLB_DEVINFO(cl),
13537224Scth i_ddi_prop_dyn_driver_get(CMLB_DEVINFO(cl)));
13547224Scth }
13557224Scth }
1356786Slclee return (err);
1357786Slclee }
1358786Slclee
1359786Slclee dev_t
13603525Sshidokht cmlb_make_device(struct cmlb_lun *cl)
1361786Slclee {
13628459SJerry.Gilliam@Sun.COM return (makedevice(ddi_driver_major(CMLB_DEVINFO(cl)),
13633525Sshidokht ddi_get_instance(CMLB_DEVINFO(cl)) << CMLBUNIT_SHIFT));
1364786Slclee }
1365786Slclee
1366786Slclee /*
1367786Slclee * Function: cmlb_check_update_blockcount
1368786Slclee *
1369786Slclee * Description: If current capacity value is invalid, obtains the
1370786Slclee * current capacity from target driver.
1371786Slclee *
1372786Slclee * Return Code: 0 success
1373786Slclee * EIO failure
1374786Slclee */
1375786Slclee static int
13763525Sshidokht cmlb_check_update_blockcount(struct cmlb_lun *cl, void *tg_cookie)
1377786Slclee {
1378786Slclee int status;
1379786Slclee diskaddr_t capacity;
13803525Sshidokht uint32_t lbasize;
13813525Sshidokht
13823525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl)));
13833525Sshidokht
13848863SEdward.Pilatowicz@Sun.COM if (cl->cl_f_geometry_is_valid)
13858863SEdward.Pilatowicz@Sun.COM return (0);
13868863SEdward.Pilatowicz@Sun.COM
13878863SEdward.Pilatowicz@Sun.COM mutex_exit(CMLB_MUTEX(cl));
13888863SEdward.Pilatowicz@Sun.COM status = DK_TG_GETCAP(cl, &capacity, tg_cookie);
13898863SEdward.Pilatowicz@Sun.COM if (status != 0) {
13903525Sshidokht mutex_enter(CMLB_MUTEX(cl));
13918863SEdward.Pilatowicz@Sun.COM return (EIO);
13928863SEdward.Pilatowicz@Sun.COM }
13938863SEdward.Pilatowicz@Sun.COM
13948863SEdward.Pilatowicz@Sun.COM status = DK_TG_GETBLOCKSIZE(cl, &lbasize, tg_cookie);
13958863SEdward.Pilatowicz@Sun.COM mutex_enter(CMLB_MUTEX(cl));
13968863SEdward.Pilatowicz@Sun.COM if (status != 0)
13978863SEdward.Pilatowicz@Sun.COM return (EIO);
13988863SEdward.Pilatowicz@Sun.COM
13998863SEdward.Pilatowicz@Sun.COM if ((capacity != 0) && (lbasize != 0)) {
14008863SEdward.Pilatowicz@Sun.COM cl->cl_blockcount = capacity;
14018863SEdward.Pilatowicz@Sun.COM cl->cl_tgt_blocksize = lbasize;
14029889SLarry.Liu@Sun.COM if (!cl->cl_is_removable) {
14039889SLarry.Liu@Sun.COM cl->cl_sys_blocksize = lbasize;
14049889SLarry.Liu@Sun.COM }
1405786Slclee return (0);
14068863SEdward.Pilatowicz@Sun.COM } else {
14078863SEdward.Pilatowicz@Sun.COM return (EIO);
14088863SEdward.Pilatowicz@Sun.COM }
1409786Slclee }
1410786Slclee
14116318Sedp static int
14126318Sedp cmlb_create_minor(dev_info_t *dip, char *name, int spec_type,
14136318Sedp minor_t minor_num, char *node_type, int flag, boolean_t internal)
14146318Sedp {
14158863SEdward.Pilatowicz@Sun.COM ASSERT(VALID_BOOLEAN(internal));
14168863SEdward.Pilatowicz@Sun.COM
14176318Sedp if (internal)
14186318Sedp return (ddi_create_internal_pathname(dip,
14196318Sedp name, spec_type, minor_num));
14206318Sedp else
14216318Sedp return (ddi_create_minor_node(dip,
14226318Sedp name, spec_type, minor_num, node_type, flag));
14236318Sedp }
14246318Sedp
1425786Slclee /*
1426786Slclee * Function: cmlb_create_minor_nodes
1427786Slclee *
1428786Slclee * Description: Create or adjust the minor device nodes for the instance.
1429786Slclee * Minor nodes are created based on default label type,
1430786Slclee * current label type and last label type we created
1431786Slclee * minor nodes based on.
1432786Slclee *
1433786Slclee *
14343525Sshidokht * Arguments: cl - driver soft state (unit) structure
1435786Slclee *
1436786Slclee * Return Code: 0 success
1437786Slclee * ENXIO failure.
1438786Slclee *
1439786Slclee * Context: Kernel thread context
1440786Slclee */
1441786Slclee static int
14423525Sshidokht cmlb_create_minor_nodes(struct cmlb_lun *cl)
1443786Slclee {
1444786Slclee struct driver_minor_data *dmdp;
1445786Slclee int instance;
1446786Slclee char name[48];
1447786Slclee cmlb_label_t newlabeltype;
14486318Sedp boolean_t internal;
1449786Slclee
14503525Sshidokht ASSERT(cl != NULL);
14513525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl)));
1452786Slclee
14538863SEdward.Pilatowicz@Sun.COM internal = VOID2BOOLEAN(
14548863SEdward.Pilatowicz@Sun.COM (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0);
1455786Slclee
1456786Slclee /* check the most common case */
14573525Sshidokht if (cl->cl_cur_labeltype != CMLB_LABEL_UNDEF &&
14583525Sshidokht cl->cl_last_labeltype == cl->cl_cur_labeltype) {
1459786Slclee /* do nothing */
1460786Slclee return (0);
1461786Slclee }
1462786Slclee
14633525Sshidokht if (cl->cl_def_labeltype == CMLB_LABEL_UNDEF) {
1464786Slclee /* we should never get here */
1465786Slclee return (ENXIO);
1466786Slclee }
1467786Slclee
14683525Sshidokht if (cl->cl_last_labeltype == CMLB_LABEL_UNDEF) {
1469786Slclee /* first time during attach */
14703525Sshidokht newlabeltype = cl->cl_def_labeltype;
14713525Sshidokht
14723525Sshidokht instance = ddi_get_instance(CMLB_DEVINFO(cl));
1473786Slclee
1474786Slclee /* Create all the minor nodes for this target. */
1475786Slclee dmdp = (newlabeltype == CMLB_LABEL_EFI) ? dk_minor_data_efi :
1476786Slclee dk_minor_data;
1477786Slclee while (dmdp->name != NULL) {
1478786Slclee
1479786Slclee (void) sprintf(name, "%s", dmdp->name);
1480786Slclee
14816318Sedp if (cmlb_create_minor(CMLB_DEVINFO(cl), name,
1482786Slclee dmdp->type,
1483786Slclee (instance << CMLBUNIT_SHIFT) | dmdp->minor,
14846318Sedp cl->cl_node_type, NULL, internal) == DDI_FAILURE) {
1485786Slclee /*
1486786Slclee * Clean up any nodes that may have been
1487786Slclee * created, in case this fails in the middle
1488786Slclee * of the loop.
1489786Slclee */
14903525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL);
1491786Slclee return (ENXIO);
1492786Slclee }
1493786Slclee dmdp++;
1494786Slclee }
14953525Sshidokht cl->cl_last_labeltype = newlabeltype;
1496786Slclee return (0);
1497786Slclee }
1498786Slclee
1499786Slclee /* Not first time */
15003525Sshidokht if (cl->cl_cur_labeltype == CMLB_LABEL_UNDEF) {
15013525Sshidokht if (cl->cl_last_labeltype != cl->cl_def_labeltype) {
1502786Slclee /* close time, revert to default. */
15033525Sshidokht newlabeltype = cl->cl_def_labeltype;
1504786Slclee } else {
1505786Slclee /*
1506786Slclee * do nothing since the type for which we last created
1507786Slclee * nodes matches the default
1508786Slclee */
1509786Slclee return (0);
1510786Slclee }
1511786Slclee } else {
15123525Sshidokht if (cl->cl_cur_labeltype != cl->cl_last_labeltype) {
1513786Slclee /* We are not closing, use current label type */
15143525Sshidokht newlabeltype = cl->cl_cur_labeltype;
1515786Slclee } else {
1516786Slclee /*
1517786Slclee * do nothing since the type for which we last created
1518786Slclee * nodes matches the current label type
1519786Slclee */
1520786Slclee return (0);
1521786Slclee }
1522786Slclee }
1523786Slclee
15243525Sshidokht instance = ddi_get_instance(CMLB_DEVINFO(cl));
1525786Slclee
1526786Slclee /*
1527786Slclee * Currently we only fix up the s7 node when we are switching
1528786Slclee * label types from or to EFI. This is consistent with
1529786Slclee * current behavior of sd.
1530786Slclee */
1531786Slclee if (newlabeltype == CMLB_LABEL_EFI &&
15323525Sshidokht cl->cl_last_labeltype != CMLB_LABEL_EFI) {
1533786Slclee /* from vtoc to EFI */
15343525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "h");
15353525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw");
15366318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd",
1537786Slclee S_IFBLK, (instance << CMLBUNIT_SHIFT) | WD_NODE,
15386318Sedp cl->cl_node_type, NULL, internal);
15396318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd,raw",
1540786Slclee S_IFCHR, (instance << CMLBUNIT_SHIFT) | WD_NODE,
15416318Sedp cl->cl_node_type, NULL, internal);
1542786Slclee } else {
1543786Slclee /* from efi to vtoc */
15443525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd");
15453525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd,raw");
15466318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h",
1547786Slclee S_IFBLK, (instance << CMLBUNIT_SHIFT) | WD_NODE,
15486318Sedp cl->cl_node_type, NULL, internal);
15496318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h,raw",
1550786Slclee S_IFCHR, (instance << CMLBUNIT_SHIFT) | WD_NODE,
15516318Sedp cl->cl_node_type, NULL, internal);
1552786Slclee }
1553786Slclee
15543525Sshidokht cl->cl_last_labeltype = newlabeltype;
1555786Slclee return (0);
1556786Slclee }
1557786Slclee
1558786Slclee /*
1559786Slclee * Function: cmlb_validate_geometry
1560786Slclee *
1561786Slclee * Description: Read the label from the disk (if present). Update the unit's
1562786Slclee * geometry and vtoc information from the data in the label.
1563786Slclee * Verify that the label is valid.
1564786Slclee *
15653525Sshidokht * Arguments:
15663525Sshidokht * cl driver soft state (unit) structure
15673525Sshidokht *
15683525Sshidokht * forcerevalid force revalidation even if we are already valid.
15693525Sshidokht * flags operation flags from target driver. Used for verbosity
15703525Sshidokht * control at this time.
15713525Sshidokht * tg_cookie cookie from target driver to be passed back to target
15723525Sshidokht * driver when we call back to it through tg_ops.
1573786Slclee *
1574786Slclee * Return Code: 0 - Successful completion
15753525Sshidokht * EINVAL - Invalid value in cl->cl_tgt_blocksize or
15763525Sshidokht * cl->cl_blockcount; or label on disk is corrupted
1577786Slclee * or unreadable.
1578786Slclee * EACCES - Reservation conflict at the device.
1579786Slclee * ENOMEM - Resource allocation error
1580786Slclee * ENOTSUP - geometry not applicable
1581786Slclee *
1582786Slclee * Context: Kernel thread only (can sleep).
1583786Slclee */
1584786Slclee static int
15858863SEdward.Pilatowicz@Sun.COM cmlb_validate_geometry(struct cmlb_lun *cl, boolean_t forcerevalid, int flags,
15863525Sshidokht void *tg_cookie)
1587786Slclee {
1588786Slclee int label_error = 0;
1589786Slclee diskaddr_t capacity;
1590786Slclee int count;
15913525Sshidokht
15923525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl)));
15938863SEdward.Pilatowicz@Sun.COM ASSERT(VALID_BOOLEAN(forcerevalid));
15948863SEdward.Pilatowicz@Sun.COM
15958863SEdward.Pilatowicz@Sun.COM if ((cl->cl_f_geometry_is_valid) && (!forcerevalid)) {
15963525Sshidokht if (cl->cl_cur_labeltype == CMLB_LABEL_EFI)
1597786Slclee return (ENOTSUP);
1598786Slclee return (0);
1599786Slclee }
1600786Slclee
16013525Sshidokht if (cmlb_check_update_blockcount(cl, tg_cookie) != 0)
1602786Slclee return (EIO);
1603786Slclee
16043525Sshidokht capacity = cl->cl_blockcount;
1605786Slclee
1606786Slclee #if defined(_SUNOS_VTOC_16)
1607786Slclee /*
1608786Slclee * Set up the "whole disk" fdisk partition; this should always
1609786Slclee * exist, regardless of whether the disk contains an fdisk table
1610786Slclee * or vtoc.
1611786Slclee */
16123525Sshidokht cl->cl_map[P0_RAW_DISK].dkl_cylno = 0;
16137563SPrasad.Singamsetty@Sun.COM cl->cl_offset[P0_RAW_DISK] = 0;
1614786Slclee /*
16157563SPrasad.Singamsetty@Sun.COM * note if capacity > int32_max(1TB) we are in 64bit environment
16167563SPrasad.Singamsetty@Sun.COM * so no truncation happens
1617786Slclee */
16183525Sshidokht cl->cl_map[P0_RAW_DISK].dkl_nblk = capacity;
1619786Slclee #endif
1620786Slclee /*
1621786Slclee * Refresh the logical and physical geometry caches.
1622786Slclee * (data from MODE SENSE format/rigid disk geometry pages,
1623786Slclee * and scsi_ifgetcap("geometry").
1624786Slclee */
16253525Sshidokht cmlb_resync_geom_caches(cl, capacity, tg_cookie);
16263525Sshidokht
16277563SPrasad.Singamsetty@Sun.COM cl->cl_label_from_media = CMLB_LABEL_UNDEF;
16283525Sshidokht label_error = cmlb_use_efi(cl, capacity, flags, tg_cookie);
1629786Slclee if (label_error == 0) {
1630786Slclee
1631786Slclee /* found a valid EFI label */
16323525Sshidokht cmlb_dbg(CMLB_TRACE, cl,
1633786Slclee "cmlb_validate_geometry: found EFI label\n");
1634786Slclee /*
1635786Slclee * solaris_size and geometry_is_valid are set in
1636786Slclee * cmlb_use_efi
1637786Slclee */
1638786Slclee return (ENOTSUP);
1639786Slclee }
1640786Slclee
1641786Slclee /* NO EFI label found */
1642786Slclee
16437563SPrasad.Singamsetty@Sun.COM if (capacity > CMLB_EXTVTOC_LIMIT) {
1644786Slclee if (label_error == ESRCH) {
1645786Slclee /*
16467563SPrasad.Singamsetty@Sun.COM * they've configured a LUN over 2TB, but used
1647786Slclee * format.dat to restrict format's view of the
16487563SPrasad.Singamsetty@Sun.COM * capacity to be under 2TB in some earlier Solaris
16497563SPrasad.Singamsetty@Sun.COM * release.
1650786Slclee */
16517563SPrasad.Singamsetty@Sun.COM /* i.e > 2TB with a VTOC < 2TB */
16527563SPrasad.Singamsetty@Sun.COM if (!(flags & CMLB_SILENT) &&
16537563SPrasad.Singamsetty@Sun.COM (cl->cl_msglog_flag & CMLB_ALLOW_2TB_WARN)) {
16543525Sshidokht
16553525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl),
16567563SPrasad.Singamsetty@Sun.COM CE_NOTE, "!Disk (%s%d) is limited to 2 TB "
16577563SPrasad.Singamsetty@Sun.COM "due to VTOC label. To use the full "
16587563SPrasad.Singamsetty@Sun.COM "capacity of the disk, use format(1M) to "
16597563SPrasad.Singamsetty@Sun.COM "relabel the disk with EFI/GPT label.\n",
16607563SPrasad.Singamsetty@Sun.COM CMLB_LABEL(cl),
16617563SPrasad.Singamsetty@Sun.COM ddi_get_instance(CMLB_DEVINFO(cl)));
16627563SPrasad.Singamsetty@Sun.COM
16637563SPrasad.Singamsetty@Sun.COM cl->cl_msglog_flag &= ~CMLB_ALLOW_2TB_WARN;
16643525Sshidokht }
1665786Slclee } else {
16663525Sshidokht return (ENOTSUP);
1667786Slclee }
1668786Slclee }
1669786Slclee
1670786Slclee label_error = 0;
1671786Slclee
1672786Slclee /*
1673786Slclee * at this point it is either labeled with a VTOC or it is
16743525Sshidokht * under 1TB (<= 1TB actually for off-by-1)
1675786Slclee */
1676786Slclee
1677786Slclee /*
16783525Sshidokht * Only DIRECT ACCESS devices will have Scl labels.
16793525Sshidokht * CD's supposedly have a Scl label, too
1680786Slclee */
16813525Sshidokht if (cl->cl_device_type == DTYPE_DIRECT || ISREMOVABLE(cl)) {
1682786Slclee struct dk_label *dkl;
1683786Slclee offset_t label_addr;
1684786Slclee int rval;
1685786Slclee size_t buffer_size;
1686786Slclee
1687786Slclee /*
16883525Sshidokht * Note: This will set up cl->cl_solaris_size and
16893525Sshidokht * cl->cl_solaris_offset.
1690786Slclee */
16913525Sshidokht rval = cmlb_read_fdisk(cl, capacity, tg_cookie);
16923525Sshidokht if ((rval != 0) && !ISCD(cl)) {
16933525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl)));
1694786Slclee return (rval);
1695786Slclee }
1696786Slclee
16973525Sshidokht if (cl->cl_solaris_size <= DK_LABEL_LOC) {
1698786Slclee /*
1699786Slclee * Found fdisk table but no Solaris partition entry,
1700786Slclee * so don't call cmlb_uselabel() and don't create
1701786Slclee * a default label.
1702786Slclee */
1703786Slclee label_error = 0;
17048863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_TRUE;
1705786Slclee goto no_solaris_partition;
1706786Slclee }
1707786Slclee
17083525Sshidokht label_addr = (daddr_t)(cl->cl_solaris_offset + DK_LABEL_LOC);
17093525Sshidokht
17109889SLarry.Liu@Sun.COM buffer_size = cl->cl_sys_blocksize;
1711786Slclee
17123525Sshidokht cmlb_dbg(CMLB_TRACE, cl, "cmlb_validate_geometry: "
1713786Slclee "label_addr: 0x%x allocation size: 0x%x\n",
1714786Slclee label_addr, buffer_size);
1715786Slclee
1716786Slclee if ((dkl = kmem_zalloc(buffer_size, KM_NOSLEEP)) == NULL)
1717786Slclee return (ENOMEM);
1718786Slclee
17193525Sshidokht mutex_exit(CMLB_MUTEX(cl));
17203525Sshidokht rval = DK_TG_READ(cl, dkl, label_addr, buffer_size, tg_cookie);
17213525Sshidokht mutex_enter(CMLB_MUTEX(cl));
1722786Slclee
1723786Slclee switch (rval) {
1724786Slclee case 0:
1725786Slclee /*
1726786Slclee * cmlb_uselabel will establish that the geometry
1727786Slclee * is valid.
1728786Slclee */
17293525Sshidokht if (cmlb_uselabel(cl,
17303525Sshidokht (struct dk_label *)(uintptr_t)dkl, flags) !=
1731786Slclee CMLB_LABEL_IS_VALID) {
1732786Slclee label_error = EINVAL;
1733786Slclee } else
17347563SPrasad.Singamsetty@Sun.COM cl->cl_label_from_media = CMLB_LABEL_VTOC;
1735786Slclee break;
1736786Slclee case EACCES:
1737786Slclee label_error = EACCES;
1738786Slclee break;
1739786Slclee default:
1740786Slclee label_error = EINVAL;
1741786Slclee break;
1742786Slclee }
1743786Slclee
1744786Slclee kmem_free(dkl, buffer_size);
1745786Slclee }
1746786Slclee
1747786Slclee /*
1748786Slclee * If a valid label was not found, AND if no reservation conflict
1749786Slclee * was detected, then go ahead and create a default label (4069506).
1750786Slclee *
1751786Slclee * Note: currently, for VTOC_8 devices, the default label is created
17523525Sshidokht * for removables and hotpluggables only. For VTOC_16 devices, the
17533525Sshidokht * default label will be created for all devices.
1754786Slclee * (see cmlb_build_default_label)
1755786Slclee */
1756786Slclee #if defined(_SUNOS_VTOC_8)
17573525Sshidokht if ((ISREMOVABLE(cl) || ISHOTPLUGGABLE(cl)) &&
17583525Sshidokht (label_error != EACCES)) {
1759786Slclee #elif defined(_SUNOS_VTOC_16)
1760786Slclee if (label_error != EACCES) {
1761786Slclee #endif
17628863SEdward.Pilatowicz@Sun.COM if (!cl->cl_f_geometry_is_valid) {
17633525Sshidokht cmlb_build_default_label(cl, tg_cookie);
1764786Slclee }
1765786Slclee label_error = 0;
1766786Slclee }
1767786Slclee
1768786Slclee no_solaris_partition:
1769786Slclee
1770786Slclee #if defined(_SUNOS_VTOC_16)
1771786Slclee /*
1772786Slclee * If we have valid geometry, set up the remaining fdisk partitions.
1773786Slclee * Note that dkl_cylno is not used for the fdisk map entries, so
1774786Slclee * we set it to an entirely bogus value.
1775786Slclee */
177610021SSheshadri.Vasudevan@Sun.COM for (count = 0; count < FDISK_PARTS; count++) {
17777563SPrasad.Singamsetty@Sun.COM cl->cl_map[FDISK_P1 + count].dkl_cylno = UINT16_MAX;
17783525Sshidokht cl->cl_map[FDISK_P1 + count].dkl_nblk =
17793525Sshidokht cl->cl_fmap[count].fmap_nblk;
17803525Sshidokht
17813525Sshidokht cl->cl_offset[FDISK_P1 + count] =
17823525Sshidokht cl->cl_fmap[count].fmap_start;
1783786Slclee }
1784786Slclee #endif
1785786Slclee
1786786Slclee for (count = 0; count < NDKMAP; count++) {
1787786Slclee #if defined(_SUNOS_VTOC_8)
17883525Sshidokht struct dk_map *lp = &cl->cl_map[count];
17893525Sshidokht cl->cl_offset[count] =
17903525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno;
1791786Slclee #elif defined(_SUNOS_VTOC_16)
17923525Sshidokht struct dkl_partition *vp = &cl->cl_vtoc.v_part[count];
17933525Sshidokht
17943525Sshidokht cl->cl_offset[count] = vp->p_start + cl->cl_solaris_offset;
1795786Slclee #else
1796786Slclee #error "No VTOC format defined."
1797786Slclee #endif
1798786Slclee }
1799786Slclee
1800786Slclee return (label_error);
1801786Slclee }
1802786Slclee
1803786Slclee #if defined(_SUNOS_VTOC_16)
1804786Slclee /*
1805786Slclee * Function: cmlb_convert_geometry
1806786Slclee *
1807786Slclee * Description: Convert physical geometry into a dk_geom structure. In
1808786Slclee * other words, make sure we don't wrap 16-bit values.
1809786Slclee * e.g. converting from geom_cache to dk_geom
1810786Slclee *
1811786Slclee * Context: Kernel thread only
1812786Slclee */
1813786Slclee static void
181410320SLarry.Liu@Sun.COM cmlb_convert_geometry(struct cmlb_lun *cl, diskaddr_t capacity,
181510320SLarry.Liu@Sun.COM struct dk_geom *cl_g, void *tg_cookie)
1816786Slclee {
1817786Slclee
181810320SLarry.Liu@Sun.COM ASSERT(cl != NULL);
181910320SLarry.Liu@Sun.COM ASSERT(mutex_owned(CMLB_MUTEX(cl)));
182010320SLarry.Liu@Sun.COM
1821786Slclee /* Unlabeled SCSI floppy device */
182211748SShidokht.Yadegari@Sun.COM if (capacity < 160) {
182311748SShidokht.Yadegari@Sun.COM /* Less than 80K */
182411748SShidokht.Yadegari@Sun.COM cl_g->dkg_nhead = 1;
182511748SShidokht.Yadegari@Sun.COM cl_g->dkg_ncyl = capacity;
182611748SShidokht.Yadegari@Sun.COM cl_g->dkg_nsect = 1;
182711748SShidokht.Yadegari@Sun.COM return;
182811748SShidokht.Yadegari@Sun.COM } else if (capacity <= 0x1000) {
18293525Sshidokht cl_g->dkg_nhead = 2;
18303525Sshidokht cl_g->dkg_ncyl = 80;
18313525Sshidokht cl_g->dkg_nsect = capacity / (cl_g->dkg_nhead * cl_g->dkg_ncyl);
1832786Slclee return;
1833786Slclee }
1834786Slclee
1835786Slclee /*
18367563SPrasad.Singamsetty@Sun.COM * For all devices we calculate cylinders using the heads and sectors
18377563SPrasad.Singamsetty@Sun.COM * we assign based on capacity of the device. The algorithm is
18387563SPrasad.Singamsetty@Sun.COM * designed to be compatible with the way other operating systems
18397563SPrasad.Singamsetty@Sun.COM * lay out fdisk tables for X86 and to insure that the cylinders never
18407563SPrasad.Singamsetty@Sun.COM * exceed 65535 to prevent problems with X86 ioctls that report
18417563SPrasad.Singamsetty@Sun.COM * geometry.
18427563SPrasad.Singamsetty@Sun.COM * For some smaller disk sizes we report geometry that matches those
18437563SPrasad.Singamsetty@Sun.COM * used by X86 BIOS usage. For larger disks, we use SPT that are
18447563SPrasad.Singamsetty@Sun.COM * multiples of 63, since other OSes that are not limited to 16-bits
18457563SPrasad.Singamsetty@Sun.COM * for cylinders stop at 63 SPT we make do by using multiples of 63 SPT.
18467563SPrasad.Singamsetty@Sun.COM *
18477563SPrasad.Singamsetty@Sun.COM * The following table (in order) illustrates some end result
18487563SPrasad.Singamsetty@Sun.COM * calculations:
18497563SPrasad.Singamsetty@Sun.COM *
18507563SPrasad.Singamsetty@Sun.COM * Maximum number of blocks nhead nsect
1851786Slclee *
18527563SPrasad.Singamsetty@Sun.COM * 2097152 (1GB) 64 32
18537563SPrasad.Singamsetty@Sun.COM * 16777216 (8GB) 128 32
18547563SPrasad.Singamsetty@Sun.COM * 1052819775 (502.02GB) 255 63
18557563SPrasad.Singamsetty@Sun.COM * 2105639550 (0.98TB) 255 126
18567563SPrasad.Singamsetty@Sun.COM * 3158459325 (1.47TB) 255 189
18577563SPrasad.Singamsetty@Sun.COM * 4211279100 (1.96TB) 255 252
18587563SPrasad.Singamsetty@Sun.COM * 5264098875 (2.45TB) 255 315
18597563SPrasad.Singamsetty@Sun.COM * ...
186010320SLarry.Liu@Sun.COM *
186110320SLarry.Liu@Sun.COM * For Solid State Drive(SSD), it uses 4K page size inside and may be
186210320SLarry.Liu@Sun.COM * double with every new generation. If the I/O is not aligned with
186310320SLarry.Liu@Sun.COM * page size on SSDs, SSDs perform a lot slower.
186410320SLarry.Liu@Sun.COM * By default, Solaris partition starts from cylinder 1. It will be
186510320SLarry.Liu@Sun.COM * misaligned even with 4K if using heads(255) and SPT(63). To
186610320SLarry.Liu@Sun.COM * workaround the problem, if the device is SSD, we use heads(224) and
186710320SLarry.Liu@Sun.COM * SPT multiple of 56. Thus the default Solaris partition starts from
186810320SLarry.Liu@Sun.COM * a position that aligns with 128K on a 512 bytes sector size SSD.
1869786Slclee */
18707563SPrasad.Singamsetty@Sun.COM
18717563SPrasad.Singamsetty@Sun.COM if (capacity <= 0x200000) {
18727563SPrasad.Singamsetty@Sun.COM cl_g->dkg_nhead = 64;
18737563SPrasad.Singamsetty@Sun.COM cl_g->dkg_nsect = 32;
18747563SPrasad.Singamsetty@Sun.COM } else if (capacity <= 0x01000000) {
18757563SPrasad.Singamsetty@Sun.COM cl_g->dkg_nhead = 128;
18767563SPrasad.Singamsetty@Sun.COM cl_g->dkg_nsect = 32;
18777563SPrasad.Singamsetty@Sun.COM } else {
187810320SLarry.Liu@Sun.COM tg_attribute_t tgattribute;
187910320SLarry.Liu@Sun.COM int is_solid_state;
188010320SLarry.Liu@Sun.COM unsigned short nhead;
188110320SLarry.Liu@Sun.COM unsigned short nsect;
188210320SLarry.Liu@Sun.COM
188310320SLarry.Liu@Sun.COM bzero(&tgattribute, sizeof (tg_attribute_t));
188410320SLarry.Liu@Sun.COM
188510320SLarry.Liu@Sun.COM mutex_exit(CMLB_MUTEX(cl));
188610320SLarry.Liu@Sun.COM is_solid_state =
188710320SLarry.Liu@Sun.COM (DK_TG_GETATTRIBUTE(cl, &tgattribute, tg_cookie) == 0) ?
188810320SLarry.Liu@Sun.COM tgattribute.media_is_solid_state : FALSE;
188910320SLarry.Liu@Sun.COM mutex_enter(CMLB_MUTEX(cl));
189010320SLarry.Liu@Sun.COM
189110320SLarry.Liu@Sun.COM if (is_solid_state) {
189210320SLarry.Liu@Sun.COM nhead = 224;
189310320SLarry.Liu@Sun.COM nsect = 56;
189410320SLarry.Liu@Sun.COM } else {
189510320SLarry.Liu@Sun.COM nhead = 255;
189610320SLarry.Liu@Sun.COM nsect = 63;
189710320SLarry.Liu@Sun.COM }
189810320SLarry.Liu@Sun.COM
189910320SLarry.Liu@Sun.COM cl_g->dkg_nhead = nhead;
190010320SLarry.Liu@Sun.COM
190111368SCathy.Cai@Sun.COM /* make dkg_nsect be smallest multiple of nsect */
19027563SPrasad.Singamsetty@Sun.COM cl_g->dkg_nsect = ((capacity +
190310320SLarry.Liu@Sun.COM (UINT16_MAX * nhead * nsect) - 1) /
190410320SLarry.Liu@Sun.COM (UINT16_MAX * nhead * nsect)) * nsect;
19057563SPrasad.Singamsetty@Sun.COM
19067563SPrasad.Singamsetty@Sun.COM if (cl_g->dkg_nsect == 0)
190710320SLarry.Liu@Sun.COM cl_g->dkg_nsect = (UINT16_MAX / nsect) * nsect;
19087563SPrasad.Singamsetty@Sun.COM }
19097563SPrasad.Singamsetty@Sun.COM
1910786Slclee }
1911786Slclee #endif
1912786Slclee
1913786Slclee /*
1914786Slclee * Function: cmlb_resync_geom_caches
1915786Slclee *
1916786Slclee * Description: (Re)initialize both geometry caches: the virtual geometry
1917786Slclee * information is extracted from the HBA (the "geometry"
1918786Slclee * capability), and the physical geometry cache data is
1919786Slclee * generated by issuing MODE SENSE commands.
1920786Slclee *
19213525Sshidokht * Arguments:
19223525Sshidokht * cl driver soft state (unit) structure
19233525Sshidokht * capacity disk capacity in #blocks
19243525Sshidokht * tg_cookie cookie from target driver to be passed back to target
19253525Sshidokht * driver when we call back to it through tg_ops.
1926786Slclee *
1927786Slclee * Context: Kernel thread only (can sleep).
1928786Slclee */
1929786Slclee static void
19303525Sshidokht cmlb_resync_geom_caches(struct cmlb_lun *cl, diskaddr_t capacity,
19313525Sshidokht void *tg_cookie)
1932786Slclee {
1933786Slclee struct cmlb_geom pgeom;
1934786Slclee struct cmlb_geom lgeom;
1935786Slclee struct cmlb_geom *pgeomp = &pgeom;
1936786Slclee unsigned short nhead;
1937786Slclee unsigned short nsect;
1938786Slclee int spc;
1939786Slclee int ret;
1940786Slclee
19413525Sshidokht ASSERT(cl != NULL);
19423525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl)));
1943786Slclee
1944786Slclee /*
1945786Slclee * Ask the controller for its logical geometry.
1946786Slclee * Note: if the HBA does not support scsi_ifgetcap("geometry"),
1947786Slclee * then the lgeom cache will be invalid.
1948786Slclee */
19493525Sshidokht mutex_exit(CMLB_MUTEX(cl));
1950786Slclee bzero(&lgeom, sizeof (struct cmlb_geom));
19513525Sshidokht ret = DK_TG_GETVIRTGEOM(cl, &lgeom, tg_cookie);
19523525Sshidokht mutex_enter(CMLB_MUTEX(cl));
19533525Sshidokht
19543525Sshidokht bcopy(&lgeom, &cl->cl_lgeom, sizeof (cl->cl_lgeom));
1955786Slclee
1956786Slclee /*
1957786Slclee * Initialize the pgeom cache from lgeom, so that if MODE SENSE
1958786Slclee * doesn't work, DKIOCG_PHYSGEOM can return reasonable values.
1959786Slclee */
19603525Sshidokht if (ret != 0 || cl->cl_lgeom.g_nsect == 0 ||
19613525Sshidokht cl->cl_lgeom.g_nhead == 0) {
1962786Slclee /*
1963786Slclee * Note: Perhaps this needs to be more adaptive? The rationale
1964786Slclee * is that, if there's no HBA geometry from the HBA driver, any
1965786Slclee * guess is good, since this is the physical geometry. If MODE
1966786Slclee * SENSE fails this gives a max cylinder size for non-LBA access
1967786Slclee */
1968786Slclee nhead = 255;
1969786Slclee nsect = 63;
1970786Slclee } else {
19713525Sshidokht nhead = cl->cl_lgeom.g_nhead;
19723525Sshidokht nsect = cl->cl_lgeom.g_nsect;
1973786Slclee }
1974786Slclee
19753525Sshidokht if (ISCD(cl)) {
1976786Slclee pgeomp->g_nhead = 1;
1977786Slclee pgeomp->g_nsect = nsect * nhead;
1978786Slclee } else {
1979786Slclee pgeomp->g_nhead = nhead;
1980786Slclee pgeomp->g_nsect = nsect;
1981786Slclee }
1982786Slclee
1983786Slclee spc = pgeomp->g_nhead * pgeomp->g_nsect;
1984786Slclee pgeomp->g_capacity = capacity;
19859811SSheshadri.Vasudevan@Sun.COM if (spc == 0)
19869811SSheshadri.Vasudevan@Sun.COM pgeomp->g_ncyl = 0;
19879811SSheshadri.Vasudevan@Sun.COM else
19889811SSheshadri.Vasudevan@Sun.COM pgeomp->g_ncyl = pgeomp->g_capacity / spc;
1989786Slclee pgeomp->g_acyl = 0;
1990786Slclee
1991786Slclee /*
1992786Slclee * Retrieve fresh geometry data from the hardware, stash it
1993786Slclee * here temporarily before we rebuild the incore label.
1994786Slclee *
1995786Slclee * We want to use the MODE SENSE commands to derive the
1996786Slclee * physical geometry of the device, but if either command
1997786Slclee * fails, the logical geometry is used as the fallback for
1998786Slclee * disk label geometry.
1999786Slclee */
2000786Slclee
20013525Sshidokht mutex_exit(CMLB_MUTEX(cl));
20023525Sshidokht (void) DK_TG_GETPHYGEOM(cl, pgeomp, tg_cookie);
20033525Sshidokht mutex_enter(CMLB_MUTEX(cl));
2004786Slclee
2005786Slclee /*
2006786Slclee * Now update the real copy while holding the mutex. This
2007786Slclee * way the global copy is never in an inconsistent state.
2008786Slclee */
20093525Sshidokht bcopy(pgeomp, &cl->cl_pgeom, sizeof (cl->cl_pgeom));
20103525Sshidokht
20113525Sshidokht cmlb_dbg(CMLB_INFO, cl, "cmlb_resync_geom_caches: "
2012786Slclee "(cached from lgeom)\n");
20133525Sshidokht cmlb_dbg(CMLB_INFO, cl,
2014786Slclee " ncyl: %ld; acyl: %d; nhead: %d; nsect: %d\n",
20153525Sshidokht cl->cl_pgeom.g_ncyl, cl->cl_pgeom.g_acyl,
20163525Sshidokht cl->cl_pgeom.g_nhead, cl->cl_pgeom.g_nsect);
20173525Sshidokht cmlb_dbg(CMLB_INFO, cl, " lbasize: %d; capacity: %ld; "
20183525Sshidokht "intrlv: %d; rpm: %d\n", cl->cl_pgeom.g_secsize,
20193525Sshidokht cl->cl_pgeom.g_capacity, cl->cl_pgeom.g_intrlv,
20203525Sshidokht cl->cl_pgeom.g_rpm);
2021786Slclee }
2022786Slclee
2023786Slclee
202410021SSheshadri.Vasudevan@Sun.COM #if defined(__i386) || defined(__amd64)
202510021SSheshadri.Vasudevan@Sun.COM /*
202610021SSheshadri.Vasudevan@Sun.COM * Function: cmlb_update_ext_minor_nodes
202710021SSheshadri.Vasudevan@Sun.COM *
202810021SSheshadri.Vasudevan@Sun.COM * Description: Routine to add/remove extended partition device nodes
202910021SSheshadri.Vasudevan@Sun.COM *
203010021SSheshadri.Vasudevan@Sun.COM * Arguments:
203110021SSheshadri.Vasudevan@Sun.COM * cl driver soft state (unit) structure
203210021SSheshadri.Vasudevan@Sun.COM * num_parts Number of logical drives found on the LUN
203310021SSheshadri.Vasudevan@Sun.COM *
203410021SSheshadri.Vasudevan@Sun.COM * Should be called with the mutex held
203510021SSheshadri.Vasudevan@Sun.COM *
203610021SSheshadri.Vasudevan@Sun.COM * Return Code: 0 for success
203710021SSheshadri.Vasudevan@Sun.COM *
203810021SSheshadri.Vasudevan@Sun.COM * Context: User and Kernel thread
203910021SSheshadri.Vasudevan@Sun.COM *
204010021SSheshadri.Vasudevan@Sun.COM */
204110021SSheshadri.Vasudevan@Sun.COM static int
204210021SSheshadri.Vasudevan@Sun.COM cmlb_update_ext_minor_nodes(struct cmlb_lun *cl, int num_parts)
204310021SSheshadri.Vasudevan@Sun.COM {
204410021SSheshadri.Vasudevan@Sun.COM int i, count;
204510021SSheshadri.Vasudevan@Sun.COM char name[48];
204610021SSheshadri.Vasudevan@Sun.COM int instance;
204710021SSheshadri.Vasudevan@Sun.COM struct driver_minor_data *demdp, *demdpr;
204810021SSheshadri.Vasudevan@Sun.COM char *devnm;
204910021SSheshadri.Vasudevan@Sun.COM dev_info_t *pdip;
205010021SSheshadri.Vasudevan@Sun.COM boolean_t internal;
205110021SSheshadri.Vasudevan@Sun.COM
205210021SSheshadri.Vasudevan@Sun.COM ASSERT(mutex_owned(CMLB_MUTEX(cl)));
205310021SSheshadri.Vasudevan@Sun.COM ASSERT(cl->cl_update_ext_minor_nodes == 1);
205410021SSheshadri.Vasudevan@Sun.COM
205510021SSheshadri.Vasudevan@Sun.COM internal = VOID2BOOLEAN(
205610021SSheshadri.Vasudevan@Sun.COM (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0);
205710021SSheshadri.Vasudevan@Sun.COM instance = ddi_get_instance(CMLB_DEVINFO(cl));
205810021SSheshadri.Vasudevan@Sun.COM demdp = dk_ext_minor_data;
205910021SSheshadri.Vasudevan@Sun.COM demdpr = &dk_ext_minor_data[MAX_EXT_PARTS];
206010021SSheshadri.Vasudevan@Sun.COM
206110021SSheshadri.Vasudevan@Sun.COM
206210021SSheshadri.Vasudevan@Sun.COM if (cl->cl_logical_drive_count) {
206310021SSheshadri.Vasudevan@Sun.COM for (i = 0; i < cl->cl_logical_drive_count; i++) {
206410021SSheshadri.Vasudevan@Sun.COM (void) sprintf(name, "%s", demdp->name);
206510021SSheshadri.Vasudevan@Sun.COM ddi_remove_minor_node(CMLB_DEVINFO(cl), name);
206610021SSheshadri.Vasudevan@Sun.COM (void) sprintf(name, "%s", demdpr->name);
206710021SSheshadri.Vasudevan@Sun.COM ddi_remove_minor_node(CMLB_DEVINFO(cl), name);
206810021SSheshadri.Vasudevan@Sun.COM demdp++;
206910021SSheshadri.Vasudevan@Sun.COM demdpr++;
207010021SSheshadri.Vasudevan@Sun.COM }
207110021SSheshadri.Vasudevan@Sun.COM /* There are existing device nodes. Remove them */
207210021SSheshadri.Vasudevan@Sun.COM devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
207310021SSheshadri.Vasudevan@Sun.COM (void) ddi_deviname(cl->cl_devi, devnm);
207410021SSheshadri.Vasudevan@Sun.COM pdip = ddi_get_parent(cl->cl_devi);
207510021SSheshadri.Vasudevan@Sun.COM (void) devfs_clean(pdip, devnm + 1, DV_CLEAN_FORCE);
207610021SSheshadri.Vasudevan@Sun.COM kmem_free(devnm, MAXNAMELEN + 1);
207710021SSheshadri.Vasudevan@Sun.COM }
207810021SSheshadri.Vasudevan@Sun.COM
207910021SSheshadri.Vasudevan@Sun.COM demdp = dk_ext_minor_data;
208010021SSheshadri.Vasudevan@Sun.COM demdpr = &dk_ext_minor_data[MAX_EXT_PARTS];
208110021SSheshadri.Vasudevan@Sun.COM
208210021SSheshadri.Vasudevan@Sun.COM for (i = 0; i < num_parts; i++) {
208310021SSheshadri.Vasudevan@Sun.COM (void) sprintf(name, "%s", demdp->name);
208410021SSheshadri.Vasudevan@Sun.COM if (cmlb_create_minor(CMLB_DEVINFO(cl), name,
208510021SSheshadri.Vasudevan@Sun.COM demdp->type,
208610021SSheshadri.Vasudevan@Sun.COM (instance << CMLBUNIT_SHIFT) | demdp->minor,
208710021SSheshadri.Vasudevan@Sun.COM cl->cl_node_type, NULL, internal) == DDI_FAILURE) {
208810021SSheshadri.Vasudevan@Sun.COM /*
208910021SSheshadri.Vasudevan@Sun.COM * Clean up any nodes that may have been
209010021SSheshadri.Vasudevan@Sun.COM * created, in case this fails in the middle
209110021SSheshadri.Vasudevan@Sun.COM * of the loop.
209210021SSheshadri.Vasudevan@Sun.COM */
209310021SSheshadri.Vasudevan@Sun.COM ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL);
209410021SSheshadri.Vasudevan@Sun.COM cl->cl_logical_drive_count = 0;
209510021SSheshadri.Vasudevan@Sun.COM return (ENXIO);
209610021SSheshadri.Vasudevan@Sun.COM }
209710021SSheshadri.Vasudevan@Sun.COM (void) sprintf(name, "%s", demdpr->name);
209810021SSheshadri.Vasudevan@Sun.COM if (ddi_create_minor_node(CMLB_DEVINFO(cl), name,
209910021SSheshadri.Vasudevan@Sun.COM demdpr->type,
210010021SSheshadri.Vasudevan@Sun.COM (instance << CMLBUNIT_SHIFT) | demdpr->minor,
210110021SSheshadri.Vasudevan@Sun.COM cl->cl_node_type, NULL) == DDI_FAILURE) {
210210021SSheshadri.Vasudevan@Sun.COM /*
210310021SSheshadri.Vasudevan@Sun.COM * Clean up any nodes that may have been
210410021SSheshadri.Vasudevan@Sun.COM * created, in case this fails in the middle
210510021SSheshadri.Vasudevan@Sun.COM * of the loop.
210610021SSheshadri.Vasudevan@Sun.COM */
210710021SSheshadri.Vasudevan@Sun.COM ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL);
210810021SSheshadri.Vasudevan@Sun.COM cl->cl_logical_drive_count = 0;
210910021SSheshadri.Vasudevan@Sun.COM return (ENXIO);
211010021SSheshadri.Vasudevan@Sun.COM }
211110021SSheshadri.Vasudevan@Sun.COM demdp++;
211210021SSheshadri.Vasudevan@Sun.COM demdpr++;
211310021SSheshadri.Vasudevan@Sun.COM }
211410021SSheshadri.Vasudevan@Sun.COM
211510021SSheshadri.Vasudevan@Sun.COM /* Update the cl_map array for logical drives */
211610021SSheshadri.Vasudevan@Sun.COM for (count = 0; count < MAX_EXT_PARTS; count++) {
211710021SSheshadri.Vasudevan@Sun.COM cl->cl_map[FDISK_P4 + 1 + count].dkl_cylno = UINT32_MAX;
211810021SSheshadri.Vasudevan@Sun.COM cl->cl_map[FDISK_P4 + 1 + count].dkl_nblk =
211910021SSheshadri.Vasudevan@Sun.COM cl->cl_fmap[FD_NUMPART + count].fmap_nblk;
212010021SSheshadri.Vasudevan@Sun.COM cl->cl_offset[FDISK_P4 + 1 + count] =
212110021SSheshadri.Vasudevan@Sun.COM cl->cl_fmap[FD_NUMPART + count].fmap_start;
212210021SSheshadri.Vasudevan@Sun.COM }
212310021SSheshadri.Vasudevan@Sun.COM
212410021SSheshadri.Vasudevan@Sun.COM cl->cl_logical_drive_count = i;
212510021SSheshadri.Vasudevan@Sun.COM cl->cl_update_ext_minor_nodes = 0;
212610021SSheshadri.Vasudevan@Sun.COM return (0);
212710021SSheshadri.Vasudevan@Sun.COM }
212810021SSheshadri.Vasudevan@Sun.COM /*
212910021SSheshadri.Vasudevan@Sun.COM * Function: cmlb_validate_ext_part
213010021SSheshadri.Vasudevan@Sun.COM *
213110021SSheshadri.Vasudevan@Sun.COM * Description: utility routine to validate an extended partition's
213210021SSheshadri.Vasudevan@Sun.COM * metadata as found on disk
213310021SSheshadri.Vasudevan@Sun.COM *
213410021SSheshadri.Vasudevan@Sun.COM * Arguments:
213510021SSheshadri.Vasudevan@Sun.COM * cl driver soft state (unit) structure
213610021SSheshadri.Vasudevan@Sun.COM * part partition number of the extended partition
213710021SSheshadri.Vasudevan@Sun.COM * epart partition number of the logical drive
213810021SSheshadri.Vasudevan@Sun.COM * start absolute sector number of the start of the logical
213910021SSheshadri.Vasudevan@Sun.COM * drive being validated
214010021SSheshadri.Vasudevan@Sun.COM * size size of logical drive being validated
214110021SSheshadri.Vasudevan@Sun.COM *
214210021SSheshadri.Vasudevan@Sun.COM * Return Code: 0 for success
214310021SSheshadri.Vasudevan@Sun.COM *
214410021SSheshadri.Vasudevan@Sun.COM * Context: User and Kernel thread
214510021SSheshadri.Vasudevan@Sun.COM *
214610021SSheshadri.Vasudevan@Sun.COM * Algorithm :
214710021SSheshadri.Vasudevan@Sun.COM * Error cases are :
214810021SSheshadri.Vasudevan@Sun.COM * 1. If start block is lesser than or equal to the end block
214910021SSheshadri.Vasudevan@Sun.COM * 2. If either start block or end block is beyond the bounadry
215010021SSheshadri.Vasudevan@Sun.COM * of the extended partition.
215110021SSheshadri.Vasudevan@Sun.COM * 3. start or end block overlap with existing partitions.
215210021SSheshadri.Vasudevan@Sun.COM * To check this, first make sure that the start block doesnt
215310021SSheshadri.Vasudevan@Sun.COM * overlap with existing partitions. Then, calculate the
215410021SSheshadri.Vasudevan@Sun.COM * possible end block for the given start block that doesnt
215510021SSheshadri.Vasudevan@Sun.COM * overlap with existing partitions. This can be calculated by
215610021SSheshadri.Vasudevan@Sun.COM * first setting the possible end block to the end of the
215710021SSheshadri.Vasudevan@Sun.COM * extended partition (optimistic) and then, checking if there
215810021SSheshadri.Vasudevan@Sun.COM * is any other partition that lies after the start of the
215910021SSheshadri.Vasudevan@Sun.COM * partition being validated. If so, set the possible end to
216010021SSheshadri.Vasudevan@Sun.COM * one block less than the beginning of the next nearest partition
216110021SSheshadri.Vasudevan@Sun.COM * If the actual end block is greater than the calculated end
216210021SSheshadri.Vasudevan@Sun.COM * block, we have an overlap.
216310021SSheshadri.Vasudevan@Sun.COM *
216410021SSheshadri.Vasudevan@Sun.COM */
216510021SSheshadri.Vasudevan@Sun.COM static int
216610021SSheshadri.Vasudevan@Sun.COM cmlb_validate_ext_part(struct cmlb_lun *cl, int part, int epart, uint32_t start,
216710021SSheshadri.Vasudevan@Sun.COM uint32_t size)
216810021SSheshadri.Vasudevan@Sun.COM {
216910021SSheshadri.Vasudevan@Sun.COM int i;
217010021SSheshadri.Vasudevan@Sun.COM uint32_t end = start + size - 1;
217110021SSheshadri.Vasudevan@Sun.COM uint32_t ext_start = cl->cl_fmap[part].fmap_start;
217210021SSheshadri.Vasudevan@Sun.COM uint32_t ext_end = ext_start + cl->cl_fmap[part].fmap_nblk - 1;
217310021SSheshadri.Vasudevan@Sun.COM uint32_t ts, te;
217410021SSheshadri.Vasudevan@Sun.COM uint32_t poss_end = ext_end;
217510021SSheshadri.Vasudevan@Sun.COM
217610021SSheshadri.Vasudevan@Sun.COM if (end <= start) {
217710021SSheshadri.Vasudevan@Sun.COM return (1);
217810021SSheshadri.Vasudevan@Sun.COM }
217910021SSheshadri.Vasudevan@Sun.COM
218010021SSheshadri.Vasudevan@Sun.COM /*
218110021SSheshadri.Vasudevan@Sun.COM * Check if the logical drive boundaries are within that of the
218210021SSheshadri.Vasudevan@Sun.COM * extended partition.
218310021SSheshadri.Vasudevan@Sun.COM */
218410021SSheshadri.Vasudevan@Sun.COM if (start <= ext_start || start > ext_end || end <= ext_start ||
218510021SSheshadri.Vasudevan@Sun.COM end > ext_end) {
218610021SSheshadri.Vasudevan@Sun.COM return (1);
218710021SSheshadri.Vasudevan@Sun.COM }
218810021SSheshadri.Vasudevan@Sun.COM
218910021SSheshadri.Vasudevan@Sun.COM /*
219010021SSheshadri.Vasudevan@Sun.COM * epart will be equal to FD_NUMPART if it is the first logical drive.
219110021SSheshadri.Vasudevan@Sun.COM * There is no need to check for overlaps with other logical drives,
219210021SSheshadri.Vasudevan@Sun.COM * since it is the only logical drive that we have come across so far.
219310021SSheshadri.Vasudevan@Sun.COM */
219410021SSheshadri.Vasudevan@Sun.COM if (epart == FD_NUMPART) {
219510021SSheshadri.Vasudevan@Sun.COM return (0);
219610021SSheshadri.Vasudevan@Sun.COM }
219710021SSheshadri.Vasudevan@Sun.COM
219810021SSheshadri.Vasudevan@Sun.COM /* Check for overlaps with existing logical drives */
219910021SSheshadri.Vasudevan@Sun.COM i = FD_NUMPART;
220010021SSheshadri.Vasudevan@Sun.COM ts = cl->cl_fmap[FD_NUMPART].fmap_start;
220110021SSheshadri.Vasudevan@Sun.COM te = ts + cl->cl_fmap[FD_NUMPART].fmap_nblk - 1;
220210021SSheshadri.Vasudevan@Sun.COM
220310021SSheshadri.Vasudevan@Sun.COM while ((i < epart) && ts && te) {
220410021SSheshadri.Vasudevan@Sun.COM if (start >= ts && start <= te) {
220510021SSheshadri.Vasudevan@Sun.COM return (1);
220610021SSheshadri.Vasudevan@Sun.COM }
220710021SSheshadri.Vasudevan@Sun.COM
220810021SSheshadri.Vasudevan@Sun.COM if ((ts < poss_end) && (ts > start)) {
220910021SSheshadri.Vasudevan@Sun.COM poss_end = ts - 1;
221010021SSheshadri.Vasudevan@Sun.COM }
221110021SSheshadri.Vasudevan@Sun.COM
221210021SSheshadri.Vasudevan@Sun.COM i++;
221310021SSheshadri.Vasudevan@Sun.COM ts = cl->cl_fmap[i].fmap_start;
221410021SSheshadri.Vasudevan@Sun.COM te = ts + cl->cl_fmap[i].fmap_nblk - 1;
221510021SSheshadri.Vasudevan@Sun.COM }
221610021SSheshadri.Vasudevan@Sun.COM
221710021SSheshadri.Vasudevan@Sun.COM if (end > poss_end) {
221810021SSheshadri.Vasudevan@Sun.COM return (1);
221910021SSheshadri.Vasudevan@Sun.COM }
222010021SSheshadri.Vasudevan@Sun.COM
222110021SSheshadri.Vasudevan@Sun.COM return (0);
222210021SSheshadri.Vasudevan@Sun.COM }
222310021SSheshadri.Vasudevan@Sun.COM
222410021SSheshadri.Vasudevan@Sun.COM
222510021SSheshadri.Vasudevan@Sun.COM /*
222610021SSheshadri.Vasudevan@Sun.COM * Function: cmlb_is_linux_swap
222710021SSheshadri.Vasudevan@Sun.COM *
222810021SSheshadri.Vasudevan@Sun.COM * Description: utility routine to verify if a partition is a linux swap
222910021SSheshadri.Vasudevan@Sun.COM * partition or not.
223010021SSheshadri.Vasudevan@Sun.COM *
223110021SSheshadri.Vasudevan@Sun.COM * Arguments:
223210021SSheshadri.Vasudevan@Sun.COM * cl driver soft state (unit) structure
223310021SSheshadri.Vasudevan@Sun.COM * part_start absolute sector number of the start of the partition
223410021SSheshadri.Vasudevan@Sun.COM * being verified
223510021SSheshadri.Vasudevan@Sun.COM * tg_cookie cookie from target driver to be passed back to target
223610021SSheshadri.Vasudevan@Sun.COM * driver when we call back to it through tg_ops.
223710021SSheshadri.Vasudevan@Sun.COM *
223810021SSheshadri.Vasudevan@Sun.COM * Return Code: 0 for success
223910021SSheshadri.Vasudevan@Sun.COM *
224010021SSheshadri.Vasudevan@Sun.COM * Context: User and Kernel thread
224110021SSheshadri.Vasudevan@Sun.COM *
224210021SSheshadri.Vasudevan@Sun.COM * Notes:
224310021SSheshadri.Vasudevan@Sun.COM * The linux swap magic "SWAP-SPACE" or "SWAPSPACE2" is found as the
224410021SSheshadri.Vasudevan@Sun.COM * last 10 bytes of a disk block whose size is that of the linux page
224510021SSheshadri.Vasudevan@Sun.COM * size. This disk block is found at the beginning of the swap partition.
224610021SSheshadri.Vasudevan@Sun.COM */
224710021SSheshadri.Vasudevan@Sun.COM static int
224810021SSheshadri.Vasudevan@Sun.COM cmlb_is_linux_swap(struct cmlb_lun *cl, uint32_t part_start, void *tg_cookie)
224910021SSheshadri.Vasudevan@Sun.COM {
225010021SSheshadri.Vasudevan@Sun.COM int i;
225110021SSheshadri.Vasudevan@Sun.COM int rval = -1;
225210021SSheshadri.Vasudevan@Sun.COM uint32_t seek_offset;
225310021SSheshadri.Vasudevan@Sun.COM uint32_t linux_pg_size;
225410021SSheshadri.Vasudevan@Sun.COM char *buf, *linux_swap_magic;
225510021SSheshadri.Vasudevan@Sun.COM int sec_sz = cl->cl_sys_blocksize;
225610021SSheshadri.Vasudevan@Sun.COM /* Known linux kernel page sizes */
225710021SSheshadri.Vasudevan@Sun.COM uint32_t linux_pg_size_arr[] = {4096, };
225810021SSheshadri.Vasudevan@Sun.COM
225910021SSheshadri.Vasudevan@Sun.COM ASSERT(cl != NULL);
226010021SSheshadri.Vasudevan@Sun.COM ASSERT(mutex_owned(CMLB_MUTEX(cl)));
226110021SSheshadri.Vasudevan@Sun.COM
226210021SSheshadri.Vasudevan@Sun.COM if ((buf = kmem_zalloc(sec_sz, KM_NOSLEEP)) == NULL) {
226310021SSheshadri.Vasudevan@Sun.COM return (ENOMEM);
226410021SSheshadri.Vasudevan@Sun.COM }
226510021SSheshadri.Vasudevan@Sun.COM
226610682SSheshadri.Vasudevan@Sun.COM /*
226710682SSheshadri.Vasudevan@Sun.COM * Check if there is a sane Solaris VTOC
226810682SSheshadri.Vasudevan@Sun.COM * If there is a valid vtoc, no need to lookup
226910682SSheshadri.Vasudevan@Sun.COM * for the linux swap signature.
227010682SSheshadri.Vasudevan@Sun.COM */
227110682SSheshadri.Vasudevan@Sun.COM mutex_exit(CMLB_MUTEX(cl));
227210682SSheshadri.Vasudevan@Sun.COM rval = DK_TG_READ(cl, buf, part_start + DK_LABEL_LOC,
227310682SSheshadri.Vasudevan@Sun.COM sec_sz, tg_cookie);
227410682SSheshadri.Vasudevan@Sun.COM mutex_enter(CMLB_MUTEX(cl));
227510682SSheshadri.Vasudevan@Sun.COM if (rval != 0) {
227610682SSheshadri.Vasudevan@Sun.COM cmlb_dbg(CMLB_ERROR, cl,
227710682SSheshadri.Vasudevan@Sun.COM "cmlb_is_linux_swap: disk vtoc read err\n");
227810682SSheshadri.Vasudevan@Sun.COM rval = EIO;
227910682SSheshadri.Vasudevan@Sun.COM goto done;
228010682SSheshadri.Vasudevan@Sun.COM }
228110682SSheshadri.Vasudevan@Sun.COM
228210682SSheshadri.Vasudevan@Sun.COM if ((((struct dk_label *)buf)->dkl_magic == DKL_MAGIC) &&
228310682SSheshadri.Vasudevan@Sun.COM (((struct dk_label *)buf)->dkl_vtoc.v_sanity == VTOC_SANE)) {
228410682SSheshadri.Vasudevan@Sun.COM rval = -1;
228510682SSheshadri.Vasudevan@Sun.COM goto done;
228610682SSheshadri.Vasudevan@Sun.COM }
228710682SSheshadri.Vasudevan@Sun.COM
228810682SSheshadri.Vasudevan@Sun.COM
228910682SSheshadri.Vasudevan@Sun.COM /* No valid vtoc, so check for linux swap signature */
229010021SSheshadri.Vasudevan@Sun.COM linux_swap_magic = buf + sec_sz - 10;
229110021SSheshadri.Vasudevan@Sun.COM
229210021SSheshadri.Vasudevan@Sun.COM for (i = 0; i < sizeof (linux_pg_size_arr)/sizeof (uint32_t); i++) {
229310021SSheshadri.Vasudevan@Sun.COM linux_pg_size = linux_pg_size_arr[i];
229410021SSheshadri.Vasudevan@Sun.COM seek_offset = linux_pg_size/sec_sz - 1;
229510021SSheshadri.Vasudevan@Sun.COM seek_offset += part_start;
229610021SSheshadri.Vasudevan@Sun.COM
229710021SSheshadri.Vasudevan@Sun.COM mutex_exit(CMLB_MUTEX(cl));
229810021SSheshadri.Vasudevan@Sun.COM rval = DK_TG_READ(cl, buf, seek_offset, sec_sz, tg_cookie);
229910021SSheshadri.Vasudevan@Sun.COM mutex_enter(CMLB_MUTEX(cl));
230010021SSheshadri.Vasudevan@Sun.COM
230110021SSheshadri.Vasudevan@Sun.COM if (rval != 0) {
230210021SSheshadri.Vasudevan@Sun.COM cmlb_dbg(CMLB_ERROR, cl,
230310021SSheshadri.Vasudevan@Sun.COM "cmlb_is_linux_swap: disk read err\n");
230410021SSheshadri.Vasudevan@Sun.COM rval = EIO;
230510021SSheshadri.Vasudevan@Sun.COM break;
230610021SSheshadri.Vasudevan@Sun.COM }
230710021SSheshadri.Vasudevan@Sun.COM
230810021SSheshadri.Vasudevan@Sun.COM rval = -1;
230910021SSheshadri.Vasudevan@Sun.COM
231010021SSheshadri.Vasudevan@Sun.COM if ((strncmp(linux_swap_magic, "SWAP-SPACE", 10) == 0) ||
231110021SSheshadri.Vasudevan@Sun.COM (strncmp(linux_swap_magic, "SWAPSPACE2", 10) == 0)) {
231210021SSheshadri.Vasudevan@Sun.COM /* Found a linux swap */
231310021SSheshadri.Vasudevan@Sun.COM rval = 0;
231410021SSheshadri.Vasudevan@Sun.COM break;
231510021SSheshadri.Vasudevan@Sun.COM }
231610021SSheshadri.Vasudevan@Sun.COM }
231710021SSheshadri.Vasudevan@Sun.COM
231810682SSheshadri.Vasudevan@Sun.COM done:
231910021SSheshadri.Vasudevan@Sun.COM kmem_free(buf, sec_sz);
232010021SSheshadri.Vasudevan@Sun.COM return (rval);
232110021SSheshadri.Vasudevan@Sun.COM }
232210021SSheshadri.Vasudevan@Sun.COM #endif
232310021SSheshadri.Vasudevan@Sun.COM
2324786Slclee /*
2325786Slclee * Function: cmlb_read_fdisk
2326786Slclee *
2327786Slclee * Description: utility routine to read the fdisk table.
2328786Slclee *
23293525Sshidokht * Arguments:
23303525Sshidokht * cl driver soft state (unit) structure
23313525Sshidokht * capacity disk capacity in #blocks
23323525Sshidokht * tg_cookie cookie from target driver to be passed back to target
23333525Sshidokht * driver when we call back to it through tg_ops.
2334786Slclee *
2335786Slclee * Return Code: 0 for success (includes not reading for no_fdisk_present case
2336786Slclee * errnos from tg_rw if failed to read the first block.
2337786Slclee *
2338786Slclee * Context: Kernel thread only (can sleep).
2339786Slclee */
23403525Sshidokht /*ARGSUSED*/
2341786Slclee static int
23423525Sshidokht cmlb_read_fdisk(struct cmlb_lun *cl, diskaddr_t capacity, void *tg_cookie)
2343786Slclee {
2344786Slclee #if defined(_NO_FDISK_PRESENT)
2345786Slclee
23463525Sshidokht cl->cl_solaris_offset = 0;
23473525Sshidokht cl->cl_solaris_size = capacity;
23483525Sshidokht bzero(cl->cl_fmap, sizeof (struct fmap) * FD_NUMPART);
2349786Slclee return (0);
2350786Slclee
2351786Slclee #elif defined(_FIRMWARE_NEEDS_FDISK)
2352786Slclee
2353786Slclee struct ipart *fdp;
2354786Slclee struct mboot *mbp;
2355786Slclee struct ipart fdisk[FD_NUMPART];
235610021SSheshadri.Vasudevan@Sun.COM int i, k;
2357786Slclee char sigbuf[2];
2358786Slclee caddr_t bufp;
2359786Slclee int uidx;
2360786Slclee int rval;
2361786Slclee int lba = 0;
2362786Slclee uint_t solaris_offset; /* offset to solaris part. */
2363786Slclee daddr_t solaris_size; /* size of solaris partition */
2364786Slclee uint32_t blocksize;
236510021SSheshadri.Vasudevan@Sun.COM #if defined(__i386) || defined(__amd64)
236610021SSheshadri.Vasudevan@Sun.COM struct ipart eparts[2];
236710021SSheshadri.Vasudevan@Sun.COM struct ipart *efdp1 = &eparts[0];
236810021SSheshadri.Vasudevan@Sun.COM struct ipart *efdp2 = &eparts[1];
236910021SSheshadri.Vasudevan@Sun.COM int ext_part_exists = 0;
237010021SSheshadri.Vasudevan@Sun.COM int ld_count = 0;
237110021SSheshadri.Vasudevan@Sun.COM #endif
2372786Slclee
23733525Sshidokht ASSERT(cl != NULL);
23743525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl)));
2375786Slclee
2376786Slclee /*
2377786Slclee * Start off assuming no fdisk table
2378786Slclee */
2379786Slclee solaris_offset = 0;
2380786Slclee solaris_size = capacity;
2381786Slclee
23823525Sshidokht blocksize = cl->cl_tgt_blocksize;
2383786Slclee
2384786Slclee bufp = kmem_zalloc(blocksize, KM_SLEEP);
2385786Slclee
23863525Sshidokht mutex_exit(CMLB_MUTEX(cl));
23873525Sshidokht rval = DK_TG_READ(cl, bufp, 0, blocksize, tg_cookie);
23883525Sshidokht mutex_enter(CMLB_MUTEX(cl));
2389786Slclee
2390786Slclee if (rval != 0) {
23913525Sshidokht cmlb_dbg(CMLB_ERROR, cl,
2392786Slclee "cmlb_read_fdisk: fdisk read err\n");
23933525Sshidokht bzero(cl->cl_fmap, sizeof (struct fmap) * FD_NUMPART);
23943525Sshidokht goto done;
2395786Slclee }
2396786Slclee
2397786Slclee mbp = (struct mboot *)bufp;
2398786Slclee
2399786Slclee /*
2400786Slclee * The fdisk table does not begin on a 4-byte boundary within the
2401786Slclee * master boot record, so we copy it to an aligned structure to avoid
2402786Slclee * alignment exceptions on some processors.
2403786Slclee */
2404786Slclee bcopy(&mbp->parts[0], fdisk, sizeof (fdisk));
2405786Slclee
2406786Slclee /*
2407786Slclee * Check for lba support before verifying sig; sig might not be
2408786Slclee * there, say on a blank disk, but the max_chs mark may still
2409786Slclee * be present.
2410786Slclee *
2411786Slclee * Note: LBA support and BEFs are an x86-only concept but this
2412786Slclee * code should work OK on SPARC as well.
2413786Slclee */
2414786Slclee
2415786Slclee /*
2416786Slclee * First, check for lba-access-ok on root node (or prom root node)
2417786Slclee * if present there, don't need to search fdisk table.
2418786Slclee */
2419786Slclee if (ddi_getprop(DDI_DEV_T_ANY, ddi_root_node(), 0,
2420786Slclee "lba-access-ok", 0) != 0) {
2421786Slclee /* All drives do LBA; don't search fdisk table */
2422786Slclee lba = 1;
2423786Slclee } else {
2424786Slclee /* Okay, look for mark in fdisk table */
2425786Slclee for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) {
2426786Slclee /* accumulate "lba" value from all partitions */
2427786Slclee lba = (lba || cmlb_has_max_chs_vals(fdp));
2428786Slclee }
2429786Slclee }
2430786Slclee
2431786Slclee if (lba != 0) {
24323525Sshidokht dev_t dev = cmlb_make_device(cl);
24333525Sshidokht
24343525Sshidokht if (ddi_getprop(dev, CMLB_DEVINFO(cl), DDI_PROP_DONTPASS,
2435786Slclee "lba-access-ok", 0) == 0) {
2436786Slclee /* not found; create it */
24373525Sshidokht if (ddi_prop_create(dev, CMLB_DEVINFO(cl), 0,
2438786Slclee "lba-access-ok", (caddr_t)NULL, 0) !=
2439786Slclee DDI_PROP_SUCCESS) {
24403525Sshidokht cmlb_dbg(CMLB_ERROR, cl,
2441786Slclee "cmlb_read_fdisk: Can't create lba "
2442786Slclee "property for instance %d\n",
24433525Sshidokht ddi_get_instance(CMLB_DEVINFO(cl)));
2444786Slclee }
2445786Slclee }
2446786Slclee }
2447786Slclee
2448786Slclee bcopy(&mbp->signature, sigbuf, sizeof (sigbuf));
2449786Slclee
2450786Slclee /*
2451786Slclee * Endian-independent signature check
2452786Slclee */
2453786Slclee if (((sigbuf[1] & 0xFF) != ((MBB_MAGIC >> 8) & 0xFF)) ||
2454786Slclee (sigbuf[0] != (MBB_MAGIC & 0xFF))) {
24553525Sshidokht cmlb_dbg(CMLB_ERROR, cl,
2456786Slclee "cmlb_read_fdisk: no fdisk\n");
24573525Sshidokht bzero(cl->cl_fmap, sizeof (struct fmap) * FD_NUMPART);
2458786Slclee goto done;
2459786Slclee }
2460786Slclee
2461786Slclee #ifdef CMLBDEBUG
24623525Sshidokht if (cmlb_level_mask & CMLB_LOGMASK_INFO) {
2463786Slclee fdp = fdisk;
24643525Sshidokht cmlb_dbg(CMLB_INFO, cl, "cmlb_read_fdisk:\n");
24653525Sshidokht cmlb_dbg(CMLB_INFO, cl, " relsect "
2466786Slclee "numsect sysid bootid\n");
2467786Slclee for (i = 0; i < FD_NUMPART; i++, fdp++) {
24683525Sshidokht cmlb_dbg(CMLB_INFO, cl,
2469786Slclee " %d: %8d %8d 0x%08x 0x%08x\n",
2470786Slclee i, fdp->relsect, fdp->numsect,
2471786Slclee fdp->systid, fdp->bootid);
2472786Slclee }
2473786Slclee }
2474786Slclee #endif
2475786Slclee
2476786Slclee /*
2477786Slclee * Try to find the unix partition
2478786Slclee */
2479786Slclee uidx = -1;
2480786Slclee solaris_offset = 0;
2481786Slclee solaris_size = 0;
2482786Slclee
2483786Slclee for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) {
24847563SPrasad.Singamsetty@Sun.COM uint32_t relsect;
24857563SPrasad.Singamsetty@Sun.COM uint32_t numsect;
248610021SSheshadri.Vasudevan@Sun.COM uchar_t systid;
248710021SSheshadri.Vasudevan@Sun.COM #if defined(__i386) || defined(__amd64)
248810021SSheshadri.Vasudevan@Sun.COM /*
248910021SSheshadri.Vasudevan@Sun.COM * Stores relative block offset from the beginning of the
249010021SSheshadri.Vasudevan@Sun.COM * Extended Partition.
249110021SSheshadri.Vasudevan@Sun.COM */
249210021SSheshadri.Vasudevan@Sun.COM int ext_relsect = 0;
249310021SSheshadri.Vasudevan@Sun.COM #endif
2494786Slclee
2495786Slclee if (fdp->numsect == 0) {
24963525Sshidokht cl->cl_fmap[i].fmap_start = 0;
24973525Sshidokht cl->cl_fmap[i].fmap_nblk = 0;
2498786Slclee continue;
2499786Slclee }
2500786Slclee
2501786Slclee /*
2502786Slclee * Data in the fdisk table is little-endian.
2503786Slclee */
2504786Slclee relsect = LE_32(fdp->relsect);
2505786Slclee numsect = LE_32(fdp->numsect);
2506786Slclee
25073525Sshidokht cl->cl_fmap[i].fmap_start = relsect;
25083525Sshidokht cl->cl_fmap[i].fmap_nblk = numsect;
250910021SSheshadri.Vasudevan@Sun.COM cl->cl_fmap[i].fmap_systid = LE_8(fdp->systid);
251010021SSheshadri.Vasudevan@Sun.COM
251110021SSheshadri.Vasudevan@Sun.COM #if defined(__i386) || defined(__amd64)
251210021SSheshadri.Vasudevan@Sun.COM /* Support only one extended partition per LUN */
251310021SSheshadri.Vasudevan@Sun.COM if ((fdp->systid == EXTDOS || fdp->systid == FDISK_EXTLBA) &&
251410021SSheshadri.Vasudevan@Sun.COM (ext_part_exists == 0)) {
251510021SSheshadri.Vasudevan@Sun.COM int j;
251610021SSheshadri.Vasudevan@Sun.COM uint32_t logdrive_offset;
251710021SSheshadri.Vasudevan@Sun.COM uint32_t ext_numsect;
251810021SSheshadri.Vasudevan@Sun.COM uint32_t abs_secnum;
251910021SSheshadri.Vasudevan@Sun.COM
252010021SSheshadri.Vasudevan@Sun.COM ext_part_exists = 1;
252110021SSheshadri.Vasudevan@Sun.COM
252210021SSheshadri.Vasudevan@Sun.COM for (j = FD_NUMPART; j < FDISK_PARTS; j++) {
252310021SSheshadri.Vasudevan@Sun.COM mutex_exit(CMLB_MUTEX(cl));
252410021SSheshadri.Vasudevan@Sun.COM rval = DK_TG_READ(cl, bufp,
252510021SSheshadri.Vasudevan@Sun.COM (relsect + ext_relsect), blocksize,
252610021SSheshadri.Vasudevan@Sun.COM tg_cookie);
252710021SSheshadri.Vasudevan@Sun.COM mutex_enter(CMLB_MUTEX(cl));
252810021SSheshadri.Vasudevan@Sun.COM
252910021SSheshadri.Vasudevan@Sun.COM if (rval != 0) {
253010021SSheshadri.Vasudevan@Sun.COM cmlb_dbg(CMLB_ERROR, cl,
253110021SSheshadri.Vasudevan@Sun.COM "cmlb_read_fdisk: Extended "
253210021SSheshadri.Vasudevan@Sun.COM "partition read err\n");
253310021SSheshadri.Vasudevan@Sun.COM goto done;
253410021SSheshadri.Vasudevan@Sun.COM }
253510021SSheshadri.Vasudevan@Sun.COM /*
253610021SSheshadri.Vasudevan@Sun.COM * The first ipart entry provides the offset
253710021SSheshadri.Vasudevan@Sun.COM * at which the logical drive starts off from
253810021SSheshadri.Vasudevan@Sun.COM * the beginning of the container partition
253910021SSheshadri.Vasudevan@Sun.COM * and the size of the logical drive.
254010021SSheshadri.Vasudevan@Sun.COM * The second ipart entry provides the offset
254110021SSheshadri.Vasudevan@Sun.COM * of the next container partition from the
254210021SSheshadri.Vasudevan@Sun.COM * beginning of the extended partition.
254310021SSheshadri.Vasudevan@Sun.COM */
254410021SSheshadri.Vasudevan@Sun.COM bcopy(&bufp[FDISK_PART_TABLE_START], eparts,
254510021SSheshadri.Vasudevan@Sun.COM sizeof (eparts));
254610021SSheshadri.Vasudevan@Sun.COM logdrive_offset = LE_32(efdp1->relsect);
254710021SSheshadri.Vasudevan@Sun.COM ext_numsect = LE_32(efdp1->numsect);
254810021SSheshadri.Vasudevan@Sun.COM systid = LE_8(efdp1->systid);
254910021SSheshadri.Vasudevan@Sun.COM if (logdrive_offset <= 0 || ext_numsect <= 0)
255010021SSheshadri.Vasudevan@Sun.COM break;
255110021SSheshadri.Vasudevan@Sun.COM abs_secnum = relsect + ext_relsect +
255210021SSheshadri.Vasudevan@Sun.COM logdrive_offset;
255310021SSheshadri.Vasudevan@Sun.COM
255410021SSheshadri.Vasudevan@Sun.COM /* Boundary condition and overlap checking */
255510021SSheshadri.Vasudevan@Sun.COM if (cmlb_validate_ext_part(cl, i, j, abs_secnum,
255610021SSheshadri.Vasudevan@Sun.COM ext_numsect)) {
255710021SSheshadri.Vasudevan@Sun.COM break;
255810021SSheshadri.Vasudevan@Sun.COM }
255910021SSheshadri.Vasudevan@Sun.COM
256010021SSheshadri.Vasudevan@Sun.COM if ((cl->cl_fmap[j].fmap_start != abs_secnum) ||
256110021SSheshadri.Vasudevan@Sun.COM (cl->cl_fmap[j].fmap_nblk != ext_numsect) ||
256210021SSheshadri.Vasudevan@Sun.COM (cl->cl_fmap[j].fmap_systid != systid)) {
256310021SSheshadri.Vasudevan@Sun.COM /*
256410021SSheshadri.Vasudevan@Sun.COM * Indicates change from previous
256510021SSheshadri.Vasudevan@Sun.COM * partinfo. Need to recreate
256610021SSheshadri.Vasudevan@Sun.COM * logical device nodes.
256710021SSheshadri.Vasudevan@Sun.COM */
256810021SSheshadri.Vasudevan@Sun.COM cl->cl_update_ext_minor_nodes = 1;
256910021SSheshadri.Vasudevan@Sun.COM }
257010021SSheshadri.Vasudevan@Sun.COM cl->cl_fmap[j].fmap_start = abs_secnum;
257110021SSheshadri.Vasudevan@Sun.COM cl->cl_fmap[j].fmap_nblk = ext_numsect;
257210021SSheshadri.Vasudevan@Sun.COM cl->cl_fmap[j].fmap_systid = systid;
257310021SSheshadri.Vasudevan@Sun.COM ld_count++;
257410021SSheshadri.Vasudevan@Sun.COM
257510682SSheshadri.Vasudevan@Sun.COM if ((efdp1->systid == SUNIXOS &&
257610682SSheshadri.Vasudevan@Sun.COM (cmlb_is_linux_swap(cl, abs_secnum,
257710682SSheshadri.Vasudevan@Sun.COM tg_cookie) != 0)) ||
257810682SSheshadri.Vasudevan@Sun.COM efdp1->systid == SUNIXOS2) {
257910682SSheshadri.Vasudevan@Sun.COM if (uidx == -1) {
258010021SSheshadri.Vasudevan@Sun.COM uidx = 0;
258110021SSheshadri.Vasudevan@Sun.COM solaris_offset = abs_secnum;
258210021SSheshadri.Vasudevan@Sun.COM solaris_size = ext_numsect;
258310021SSheshadri.Vasudevan@Sun.COM }
258410021SSheshadri.Vasudevan@Sun.COM }
258510021SSheshadri.Vasudevan@Sun.COM
258610021SSheshadri.Vasudevan@Sun.COM if ((ext_relsect = LE_32(efdp2->relsect)) == 0)
258710021SSheshadri.Vasudevan@Sun.COM break;
258810021SSheshadri.Vasudevan@Sun.COM }
258910021SSheshadri.Vasudevan@Sun.COM }
259010021SSheshadri.Vasudevan@Sun.COM
259110021SSheshadri.Vasudevan@Sun.COM #endif
2592786Slclee
2593786Slclee if (fdp->systid != SUNIXOS &&
2594786Slclee fdp->systid != SUNIXOS2 &&
2595786Slclee fdp->systid != EFI_PMBR) {
2596786Slclee continue;
2597786Slclee }
2598786Slclee
2599786Slclee /*
2600786Slclee * use the last active solaris partition id found
2601786Slclee * (there should only be 1 active partition id)
2602786Slclee *
2603786Slclee * if there are no active solaris partition id
2604786Slclee * then use the first inactive solaris partition id
2605786Slclee */
2606786Slclee if ((uidx == -1) || (fdp->bootid == ACTIVE)) {
260710021SSheshadri.Vasudevan@Sun.COM #if defined(__i386) || defined(__amd64)
260810682SSheshadri.Vasudevan@Sun.COM if (fdp->systid != SUNIXOS ||
260910682SSheshadri.Vasudevan@Sun.COM (fdp->systid == SUNIXOS &&
261010682SSheshadri.Vasudevan@Sun.COM (cmlb_is_linux_swap(cl, relsect,
261110682SSheshadri.Vasudevan@Sun.COM tg_cookie) != 0))) {
261210021SSheshadri.Vasudevan@Sun.COM #endif
261310021SSheshadri.Vasudevan@Sun.COM uidx = i;
261410021SSheshadri.Vasudevan@Sun.COM solaris_offset = relsect;
261510021SSheshadri.Vasudevan@Sun.COM solaris_size = numsect;
261610021SSheshadri.Vasudevan@Sun.COM #if defined(__i386) || defined(__amd64)
261710021SSheshadri.Vasudevan@Sun.COM }
261810021SSheshadri.Vasudevan@Sun.COM #endif
2619786Slclee }
2620786Slclee }
262110021SSheshadri.Vasudevan@Sun.COM #if defined(__i386) || defined(__amd64)
262210021SSheshadri.Vasudevan@Sun.COM if (ld_count < cl->cl_logical_drive_count) {
262310021SSheshadri.Vasudevan@Sun.COM /*
262410021SSheshadri.Vasudevan@Sun.COM * Some/all logical drives were deleted. Clear out
262510021SSheshadri.Vasudevan@Sun.COM * the fmap entries correspoding to those deleted drives.
262610021SSheshadri.Vasudevan@Sun.COM */
262710021SSheshadri.Vasudevan@Sun.COM for (k = ld_count + FD_NUMPART;
262810021SSheshadri.Vasudevan@Sun.COM k < cl->cl_logical_drive_count + FD_NUMPART; k++) {
262910021SSheshadri.Vasudevan@Sun.COM cl->cl_fmap[k].fmap_start = 0;
263010021SSheshadri.Vasudevan@Sun.COM cl->cl_fmap[k].fmap_nblk = 0;
263110021SSheshadri.Vasudevan@Sun.COM cl->cl_fmap[k].fmap_systid = 0;
263210021SSheshadri.Vasudevan@Sun.COM }
263310021SSheshadri.Vasudevan@Sun.COM cl->cl_update_ext_minor_nodes = 1;
263410021SSheshadri.Vasudevan@Sun.COM }
263510021SSheshadri.Vasudevan@Sun.COM if (cl->cl_update_ext_minor_nodes) {
263610021SSheshadri.Vasudevan@Sun.COM rval = cmlb_update_ext_minor_nodes(cl, ld_count);
263710021SSheshadri.Vasudevan@Sun.COM if (rval != 0) {
263810021SSheshadri.Vasudevan@Sun.COM goto done;
263910021SSheshadri.Vasudevan@Sun.COM }
264010021SSheshadri.Vasudevan@Sun.COM }
264110021SSheshadri.Vasudevan@Sun.COM #endif
26423525Sshidokht cmlb_dbg(CMLB_INFO, cl, "fdisk 0x%x 0x%lx",
26433525Sshidokht cl->cl_solaris_offset, cl->cl_solaris_size);
2644786Slclee done:
2645786Slclee
2646786Slclee /*
2647786Slclee * Clear the VTOC info, only if the Solaris partition entry
2648786Slclee * has moved, changed size, been deleted, or if the size of
2649786Slclee * the partition is too small to even fit the label sector.
2650786Slclee */
26513525Sshidokht if ((cl->cl_solaris_offset != solaris_offset) ||
26523525Sshidokht (cl->cl_solaris_size != solaris_size) ||
2653786Slclee solaris_size <= DK_LABEL_LOC) {
26543525Sshidokht cmlb_dbg(CMLB_INFO, cl, "fdisk moved 0x%x 0x%lx",
26553525Sshidokht solaris_offset, solaris_size);
26563525Sshidokht bzero(&cl->cl_g, sizeof (struct dk_geom));
26573525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc));
26583525Sshidokht bzero(&cl->cl_map, NDKMAP * (sizeof (struct dk_map)));
26598863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE;
2660786Slclee }
26613525Sshidokht cl->cl_solaris_offset = solaris_offset;
26623525Sshidokht cl->cl_solaris_size = solaris_size;
2663786Slclee kmem_free(bufp, blocksize);
2664786Slclee return (rval);
2665786Slclee
2666786Slclee #else /* #elif defined(_FIRMWARE_NEEDS_FDISK) */
2667786Slclee #error "fdisk table presence undetermined for this platform."
2668786Slclee #endif /* #if defined(_NO_FDISK_PRESENT) */
2669786Slclee }
2670786Slclee
2671786Slclee static void
2672786Slclee cmlb_swap_efi_gpt(efi_gpt_t *e)
2673786Slclee {
2674786Slclee _NOTE(ASSUMING_PROTECTED(*e))
2675786Slclee e->efi_gpt_Signature = LE_64(e->efi_gpt_Signature);
2676786Slclee e->efi_gpt_Revision = LE_32(e->efi_gpt_Revision);
2677786Slclee e->efi_gpt_HeaderSize = LE_32(e->efi_gpt_HeaderSize);
2678786Slclee e->efi_gpt_HeaderCRC32 = LE_32(e->efi_gpt_HeaderCRC32);
2679786Slclee e->efi_gpt_MyLBA = LE_64(e->efi_gpt_MyLBA);
2680786Slclee e->efi_gpt_AlternateLBA = LE_64(e->efi_gpt_AlternateLBA);
2681786Slclee e->efi_gpt_FirstUsableLBA = LE_64(e->efi_gpt_FirstUsableLBA);
2682786Slclee e->efi_gpt_LastUsableLBA = LE_64(e->efi_gpt_LastUsableLBA);
2683786Slclee UUID_LE_CONVERT(e->efi_gpt_DiskGUID, e->efi_gpt_DiskGUID);
2684786Slclee e->efi_gpt_PartitionEntryLBA = LE_64(e->efi_gpt_PartitionEntryLBA);
2685786Slclee e->efi_gpt_NumberOfPartitionEntries =
2686786Slclee LE_32(e->efi_gpt_NumberOfPartitionEntries);
2687786Slclee e->efi_gpt_SizeOfPartitionEntry =
2688786Slclee LE_32(e->efi_gpt_SizeOfPartitionEntry);
2689786Slclee e->efi_gpt_PartitionEntryArrayCRC32 =
2690786Slclee LE_32(e->efi_gpt_PartitionEntryArrayCRC32);
2691786Slclee }
2692786Slclee
2693786Slclee static void
2694786Slclee cmlb_swap_efi_gpe(int nparts, efi_gpe_t *p)
2695786Slclee {
2696786Slclee int i;
2697786Slclee
2698786Slclee _NOTE(ASSUMING_PROTECTED(*p))
2699786Slclee for (i = 0; i < nparts; i++) {
2700786Slclee UUID_LE_CONVERT(p[i].efi_gpe_PartitionTypeGUID,
2701786Slclee p[i].efi_gpe_PartitionTypeGUID);
2702786Slclee p[i].efi_gpe_StartingLBA = LE_64(p[i].efi_gpe_StartingLBA);
2703786Slclee p[i].efi_gpe_EndingLBA = LE_64(p[i].efi_gpe_EndingLBA);
2704786Slclee /* PartitionAttrs */
2705786Slclee }
2706786Slclee }
2707786Slclee
2708786Slclee static int
2709786Slclee cmlb_validate_efi(efi_gpt_t *labp)
2710786Slclee {
2711786Slclee if (labp->efi_gpt_Signature != EFI_SIGNATURE)
2712786Slclee return (EINVAL);
2713786Slclee /* at least 96 bytes in this version of the spec. */
2714786Slclee if (sizeof (efi_gpt_t) - sizeof (labp->efi_gpt_Reserved2) >
2715786Slclee labp->efi_gpt_HeaderSize)
2716786Slclee return (EINVAL);
2717786Slclee /* this should be 128 bytes */
2718786Slclee if (labp->efi_gpt_SizeOfPartitionEntry != sizeof (efi_gpe_t))
2719786Slclee return (EINVAL);
2720786Slclee return (0);
2721786Slclee }
2722786Slclee
27235624Sshidokht /*
27248863SEdward.Pilatowicz@Sun.COM * This function returns B_FALSE if there is a valid MBR signature and no
27258863SEdward.Pilatowicz@Sun.COM * partition table entries of type EFI_PMBR (0xEE). Otherwise it returns B_TRUE.
27265624Sshidokht *
27275624Sshidokht * The EFI spec (1.10 and later) requires having a Protective MBR (PMBR) to
27285624Sshidokht * recognize the disk as GPT partitioned. However, some other OS creates an MBR
27295624Sshidokht * where a PMBR entry is not the only one. Also, if the first block has been
27305624Sshidokht * corrupted, currently best attempt to allow data access would be to try to
27315624Sshidokht * check for GPT headers. Hence in case of more than one partition entry, but
27325624Sshidokht * at least one EFI_PMBR partition type or no valid magic number, the function
27338863SEdward.Pilatowicz@Sun.COM * returns B_TRUE to continue with looking for GPT header.
27345624Sshidokht */
27355624Sshidokht
27368863SEdward.Pilatowicz@Sun.COM static boolean_t
27378863SEdward.Pilatowicz@Sun.COM cmlb_check_efi_mbr(uchar_t *buf, boolean_t *is_mbr)
27385624Sshidokht {
27395624Sshidokht struct ipart *fdp;
27405624Sshidokht struct mboot *mbp = (struct mboot *)buf;
27415624Sshidokht struct ipart fdisk[FD_NUMPART];
27425624Sshidokht int i;
27435624Sshidokht
27447563SPrasad.Singamsetty@Sun.COM if (is_mbr != NULL)
27458863SEdward.Pilatowicz@Sun.COM *is_mbr = B_TRUE;
27467563SPrasad.Singamsetty@Sun.COM
27477563SPrasad.Singamsetty@Sun.COM if (LE_16(mbp->signature) != MBB_MAGIC) {
27487563SPrasad.Singamsetty@Sun.COM if (is_mbr != NULL)
27498863SEdward.Pilatowicz@Sun.COM *is_mbr = B_FALSE;
27508863SEdward.Pilatowicz@Sun.COM return (B_TRUE);
27517563SPrasad.Singamsetty@Sun.COM }
27525624Sshidokht
27535624Sshidokht bcopy(&mbp->parts[0], fdisk, sizeof (fdisk));
27545624Sshidokht
27555624Sshidokht for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) {
27565624Sshidokht if (fdp->systid == EFI_PMBR)
27578863SEdward.Pilatowicz@Sun.COM return (B_TRUE);
27585624Sshidokht }
27595624Sshidokht
27608863SEdward.Pilatowicz@Sun.COM return (B_FALSE);
27615624Sshidokht }
27625624Sshidokht
2763786Slclee static int
27643525Sshidokht cmlb_use_efi(struct cmlb_lun *cl, diskaddr_t capacity, int flags,
27653525Sshidokht void *tg_cookie)
2766786Slclee {
2767786Slclee int i;
2768786Slclee int rval = 0;
2769786Slclee efi_gpe_t *partitions;
2770786Slclee uchar_t *buf;
2771786Slclee uint_t lbasize; /* is really how much to read */
27723525Sshidokht diskaddr_t cap = 0;
2773786Slclee uint_t nparts;
2774786Slclee diskaddr_t gpe_lba;
27756590Syl194034 diskaddr_t alternate_lba;
27761071Sshidokht int iofailed = 0;
27773525Sshidokht struct uuid uuid_type_reserved = EFI_RESERVED;
27787563SPrasad.Singamsetty@Sun.COM #if defined(_FIRMWARE_NEEDS_FDISK)
27798863SEdward.Pilatowicz@Sun.COM boolean_t is_mbr;
27807563SPrasad.Singamsetty@Sun.COM #endif
27813525Sshidokht
27823525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl)));
27833525Sshidokht
27843525Sshidokht lbasize = cl->cl_sys_blocksize;
27853525Sshidokht
27863525Sshidokht cl->cl_reserved = -1;
27873525Sshidokht mutex_exit(CMLB_MUTEX(cl));
2788786Slclee
2789786Slclee buf = kmem_zalloc(EFI_MIN_ARRAY_SIZE, KM_SLEEP);
27903525Sshidokht
27917563SPrasad.Singamsetty@Sun.COM rval = DK_TG_READ(cl, buf, 0, lbasize, tg_cookie);
2792786Slclee if (rval) {
27931071Sshidokht iofailed = 1;
2794786Slclee goto done_err;
2795786Slclee }
2796786Slclee if (((struct dk_label *)buf)->dkl_magic == DKL_MAGIC) {
2797786Slclee /* not ours */
2798786Slclee rval = ESRCH;
2799786Slclee goto done_err;
2800786Slclee }
2801786Slclee
28027563SPrasad.Singamsetty@Sun.COM #if defined(_FIRMWARE_NEEDS_FDISK)
28038863SEdward.Pilatowicz@Sun.COM if (!cmlb_check_efi_mbr(buf, &is_mbr)) {
28048863SEdward.Pilatowicz@Sun.COM if (is_mbr)
28057563SPrasad.Singamsetty@Sun.COM rval = ESRCH;
28067563SPrasad.Singamsetty@Sun.COM else
28077563SPrasad.Singamsetty@Sun.COM rval = EINVAL;
28087563SPrasad.Singamsetty@Sun.COM goto done_err;
28097563SPrasad.Singamsetty@Sun.COM }
28107563SPrasad.Singamsetty@Sun.COM #else
28118863SEdward.Pilatowicz@Sun.COM if (!cmlb_check_efi_mbr(buf, NULL)) {
28125624Sshidokht rval = EINVAL;
28135624Sshidokht goto done_err;
28145624Sshidokht }
28155624Sshidokht
28167563SPrasad.Singamsetty@Sun.COM #endif
28177563SPrasad.Singamsetty@Sun.COM
28183525Sshidokht rval = DK_TG_READ(cl, buf, 1, lbasize, tg_cookie);
2819786Slclee if (rval) {
28201071Sshidokht iofailed = 1;
2821786Slclee goto done_err;
2822786Slclee }
2823786Slclee cmlb_swap_efi_gpt((efi_gpt_t *)buf);
2824786Slclee
2825786Slclee if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) {
2826786Slclee /*
2827786Slclee * Couldn't read the primary, try the backup. Our
2828786Slclee * capacity at this point could be based on CHS, so
2829786Slclee * check what the device reports.
2830786Slclee */
28313525Sshidokht rval = DK_TG_GETCAP(cl, &cap, tg_cookie);
2832786Slclee if (rval) {
28331071Sshidokht iofailed = 1;
2834786Slclee goto done_err;
2835786Slclee }
28363525Sshidokht
28373525Sshidokht /*
28383525Sshidokht * CMLB_OFF_BY_ONE case, we check the next to last block first
28393525Sshidokht * for backup GPT header, otherwise check the last block.
28403525Sshidokht */
28413525Sshidokht
28423525Sshidokht if ((rval = DK_TG_READ(cl, buf,
28433525Sshidokht cap - ((cl->cl_alter_behavior & CMLB_OFF_BY_ONE) ? 2 : 1),
28443525Sshidokht lbasize, tg_cookie))
28453525Sshidokht != 0) {
28461071Sshidokht iofailed = 1;
2847786Slclee goto done_err;
2848786Slclee }
2849786Slclee cmlb_swap_efi_gpt((efi_gpt_t *)buf);
28503525Sshidokht
28513525Sshidokht if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) {
28523525Sshidokht
28533525Sshidokht if (!(cl->cl_alter_behavior & CMLB_OFF_BY_ONE))
28543525Sshidokht goto done_err;
28553525Sshidokht if ((rval = DK_TG_READ(cl, buf, cap - 1, lbasize,
28563525Sshidokht tg_cookie)) != 0)
28573525Sshidokht goto done_err;
28583525Sshidokht cmlb_swap_efi_gpt((efi_gpt_t *)buf);
28593525Sshidokht if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0)
28603525Sshidokht goto done_err;
28613525Sshidokht }
28623525Sshidokht if (!(flags & CMLB_SILENT))
28633525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN,
28643525Sshidokht "primary label corrupt; using backup\n");
2865786Slclee }
2866786Slclee
2867786Slclee nparts = ((efi_gpt_t *)buf)->efi_gpt_NumberOfPartitionEntries;
2868786Slclee gpe_lba = ((efi_gpt_t *)buf)->efi_gpt_PartitionEntryLBA;
28696590Syl194034 alternate_lba = ((efi_gpt_t *)buf)->efi_gpt_AlternateLBA;
2870786Slclee
28713525Sshidokht rval = DK_TG_READ(cl, buf, gpe_lba, EFI_MIN_ARRAY_SIZE, tg_cookie);
2872786Slclee if (rval) {
28731071Sshidokht iofailed = 1;
2874786Slclee goto done_err;
2875786Slclee }
2876786Slclee partitions = (efi_gpe_t *)buf;
2877786Slclee
2878786Slclee if (nparts > MAXPART) {
2879786Slclee nparts = MAXPART;
2880786Slclee }
2881786Slclee cmlb_swap_efi_gpe(nparts, partitions);
2882786Slclee
28833525Sshidokht mutex_enter(CMLB_MUTEX(cl));
2884786Slclee
2885786Slclee /* Fill in partition table. */
2886786Slclee for (i = 0; i < nparts; i++) {
2887786Slclee if (partitions->efi_gpe_StartingLBA != 0 ||
2888786Slclee partitions->efi_gpe_EndingLBA != 0) {
28893525Sshidokht cl->cl_map[i].dkl_cylno =
2890786Slclee partitions->efi_gpe_StartingLBA;
28913525Sshidokht cl->cl_map[i].dkl_nblk =
2892786Slclee partitions->efi_gpe_EndingLBA -
2893786Slclee partitions->efi_gpe_StartingLBA + 1;
28943525Sshidokht cl->cl_offset[i] =
2895786Slclee partitions->efi_gpe_StartingLBA;
2896786Slclee }
28973525Sshidokht
28983525Sshidokht if (cl->cl_reserved == -1) {
28993525Sshidokht if (bcmp(&partitions->efi_gpe_PartitionTypeGUID,
29003525Sshidokht &uuid_type_reserved, sizeof (struct uuid)) == 0) {
29013525Sshidokht cl->cl_reserved = i;
29023525Sshidokht }
29033525Sshidokht }
2904786Slclee if (i == WD_NODE) {
2905786Slclee /*
2906786Slclee * minor number 7 corresponds to the whole disk
29076590Syl194034 * if the disk capacity is expanded after disk is
29086590Syl194034 * labeled, minor number 7 represents the capacity
29096590Syl194034 * indicated by the disk label.
2910786Slclee */
29113525Sshidokht cl->cl_map[i].dkl_cylno = 0;
29126590Syl194034 if (alternate_lba == 1) {
29136590Syl194034 /*
29146590Syl194034 * We are using backup label. Since we can
29156590Syl194034 * find a valid label at the end of disk,
29166590Syl194034 * the disk capacity is not expanded.
29176590Syl194034 */
29186590Syl194034 cl->cl_map[i].dkl_nblk = capacity;
29196590Syl194034 } else {
29206590Syl194034 cl->cl_map[i].dkl_nblk = alternate_lba + 1;
29216590Syl194034 }
29223525Sshidokht cl->cl_offset[i] = 0;
2923786Slclee }
2924786Slclee partitions++;
2925786Slclee }
29263525Sshidokht cl->cl_solaris_offset = 0;
29273525Sshidokht cl->cl_solaris_size = capacity;
29287563SPrasad.Singamsetty@Sun.COM cl->cl_label_from_media = CMLB_LABEL_EFI;
29298863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_TRUE;
29303525Sshidokht
29313525Sshidokht /* clear the vtoc label */
29323525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc));
29333525Sshidokht
2934786Slclee kmem_free(buf, EFI_MIN_ARRAY_SIZE);
2935786Slclee return (0);
2936786Slclee
2937786Slclee done_err:
2938786Slclee kmem_free(buf, EFI_MIN_ARRAY_SIZE);
29393525Sshidokht mutex_enter(CMLB_MUTEX(cl));
29403525Sshidokht done_err1:
2941786Slclee /*
2942786Slclee * if we didn't find something that could look like a VTOC
2943786Slclee * and the disk is over 1TB, we know there isn't a valid label.
2944786Slclee * Otherwise let cmlb_uselabel decide what to do. We only
2945786Slclee * want to invalidate this if we're certain the label isn't
2946786Slclee * valid because cmlb_prop_op will now fail, which in turn
2947786Slclee * causes things like opens and stats on the partition to fail.
2948786Slclee */
29497563SPrasad.Singamsetty@Sun.COM if ((capacity > CMLB_EXTVTOC_LIMIT) && (rval != ESRCH) && !iofailed) {
29508863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE;
2951786Slclee }
2952786Slclee return (rval);
2953786Slclee }
2954786Slclee
2955786Slclee
2956786Slclee /*
2957786Slclee * Function: cmlb_uselabel
2958786Slclee *
2959786Slclee * Description: Validate the disk label and update the relevant data (geometry,
2960786Slclee * partition, vtoc, and capacity data) in the cmlb_lun struct.
2961786Slclee * Marks the geometry of the unit as being valid.
2962786Slclee *
29633525Sshidokht * Arguments: cl: unit struct.
2964786Slclee * dk_label: disk label
2965786Slclee *
2966786Slclee * Return Code: CMLB_LABEL_IS_VALID: Label read from disk is OK; geometry,
2967786Slclee * partition, vtoc, and capacity data are good.
2968786Slclee *
2969786Slclee * CMLB_LABEL_IS_INVALID: Magic number or checksum error in the
2970786Slclee * label; or computed capacity does not jibe with capacity
2971786Slclee * reported from the READ CAPACITY command.
2972786Slclee *
2973786Slclee * Context: Kernel thread only (can sleep).
2974786Slclee */
2975786Slclee static int
29763525Sshidokht cmlb_uselabel(struct cmlb_lun *cl, struct dk_label *labp, int flags)
2977786Slclee {
2978786Slclee short *sp;
2979786Slclee short sum;
2980786Slclee short count;
2981786Slclee int label_error = CMLB_LABEL_IS_VALID;
2982786Slclee int i;
2983786Slclee diskaddr_t label_capacity;
29847563SPrasad.Singamsetty@Sun.COM uint32_t part_end;
2985786Slclee diskaddr_t track_capacity;
2986786Slclee #if defined(_SUNOS_VTOC_16)
2987786Slclee struct dkl_partition *vpartp;
2988786Slclee #endif
29893525Sshidokht ASSERT(cl != NULL);
29903525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl)));
2991786Slclee
2992786Slclee /* Validate the magic number of the label. */
2993786Slclee if (labp->dkl_magic != DKL_MAGIC) {
2994786Slclee #if defined(__sparc)
29953525Sshidokht if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) {
29963525Sshidokht if (!(flags & CMLB_SILENT))
29973525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl),
29983525Sshidokht CE_WARN,
29993525Sshidokht "Corrupt label; wrong magic number\n");
3000786Slclee }
3001786Slclee #endif
3002786Slclee return (CMLB_LABEL_IS_INVALID);
3003786Slclee }
3004786Slclee
3005786Slclee /* Validate the checksum of the label. */
3006786Slclee sp = (short *)labp;
3007786Slclee sum = 0;
3008786Slclee count = sizeof (struct dk_label) / sizeof (short);
3009786Slclee while (count--) {
3010786Slclee sum ^= *sp++;
3011786Slclee }
3012786Slclee
3013786Slclee if (sum != 0) {
3014786Slclee #if defined(_SUNOS_VTOC_16)
30153525Sshidokht if (!ISCD(cl)) {
3016786Slclee #elif defined(_SUNOS_VTOC_8)
30173525Sshidokht if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) {
3018786Slclee #endif
30193525Sshidokht if (!(flags & CMLB_SILENT))
30203525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl),
30213525Sshidokht CE_WARN,
30223525Sshidokht "Corrupt label - label checksum failed\n");
3023786Slclee }
3024786Slclee return (CMLB_LABEL_IS_INVALID);
3025786Slclee }
3026786Slclee
3027786Slclee
3028786Slclee /*
3029786Slclee * Fill in geometry structure with data from label.
3030786Slclee */
30313525Sshidokht bzero(&cl->cl_g, sizeof (struct dk_geom));
30323525Sshidokht cl->cl_g.dkg_ncyl = labp->dkl_ncyl;
30333525Sshidokht cl->cl_g.dkg_acyl = labp->dkl_acyl;
30343525Sshidokht cl->cl_g.dkg_bcyl = 0;
30353525Sshidokht cl->cl_g.dkg_nhead = labp->dkl_nhead;
30363525Sshidokht cl->cl_g.dkg_nsect = labp->dkl_nsect;
30373525Sshidokht cl->cl_g.dkg_intrlv = labp->dkl_intrlv;
3038786Slclee
3039786Slclee #if defined(_SUNOS_VTOC_8)
30403525Sshidokht cl->cl_g.dkg_gap1 = labp->dkl_gap1;
30413525Sshidokht cl->cl_g.dkg_gap2 = labp->dkl_gap2;
30423525Sshidokht cl->cl_g.dkg_bhead = labp->dkl_bhead;
3043786Slclee #endif
3044786Slclee #if defined(_SUNOS_VTOC_16)
30453525Sshidokht cl->cl_dkg_skew = labp->dkl_skew;
3046786Slclee #endif
3047786Slclee
3048786Slclee #if defined(__i386) || defined(__amd64)
30493525Sshidokht cl->cl_g.dkg_apc = labp->dkl_apc;
3050786Slclee #endif
3051786Slclee
3052786Slclee /*
3053786Slclee * Currently we rely on the values in the label being accurate. If
3054786Slclee * dkl_rpm or dkl_pcly are zero in the label, use a default value.
3055786Slclee *
3056786Slclee * Note: In the future a MODE SENSE may be used to retrieve this data,
3057786Slclee * although this command is optional in SCSI-2.
3058786Slclee */
30593525Sshidokht cl->cl_g.dkg_rpm = (labp->dkl_rpm != 0) ? labp->dkl_rpm : 3600;
30603525Sshidokht cl->cl_g.dkg_pcyl = (labp->dkl_pcyl != 0) ? labp->dkl_pcyl :
30613525Sshidokht (cl->cl_g.dkg_ncyl + cl->cl_g.dkg_acyl);
3062786Slclee
3063786Slclee /*
3064786Slclee * The Read and Write reinstruct values may not be valid
3065786Slclee * for older disks.
3066786Slclee */
30673525Sshidokht cl->cl_g.dkg_read_reinstruct = labp->dkl_read_reinstruct;
30683525Sshidokht cl->cl_g.dkg_write_reinstruct = labp->dkl_write_reinstruct;
3069786Slclee
3070786Slclee /* Fill in partition table. */
3071786Slclee #if defined(_SUNOS_VTOC_8)
3072786Slclee for (i = 0; i < NDKMAP; i++) {
30733525Sshidokht cl->cl_map[i].dkl_cylno = labp->dkl_map[i].dkl_cylno;
30743525Sshidokht cl->cl_map[i].dkl_nblk = labp->dkl_map[i].dkl_nblk;
3075786Slclee }
3076786Slclee #endif
3077786Slclee #if defined(_SUNOS_VTOC_16)
3078786Slclee vpartp = labp->dkl_vtoc.v_part;
3079786Slclee track_capacity = labp->dkl_nhead * labp->dkl_nsect;
3080786Slclee
30813525Sshidokht /* Prevent divide by zero */
30823525Sshidokht if (track_capacity == 0) {
30833525Sshidokht if (!(flags & CMLB_SILENT))
30843525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN,
30853525Sshidokht "Corrupt label - zero nhead or nsect value\n");
30863525Sshidokht
30873525Sshidokht return (CMLB_LABEL_IS_INVALID);
30883525Sshidokht }
30893525Sshidokht
3090786Slclee for (i = 0; i < NDKMAP; i++, vpartp++) {
30913525Sshidokht cl->cl_map[i].dkl_cylno = vpartp->p_start / track_capacity;
30923525Sshidokht cl->cl_map[i].dkl_nblk = vpartp->p_size;
3093786Slclee }
3094786Slclee #endif
3095786Slclee
3096786Slclee /* Fill in VTOC Structure. */
30973525Sshidokht bcopy(&labp->dkl_vtoc, &cl->cl_vtoc, sizeof (struct dk_vtoc));
3098786Slclee #if defined(_SUNOS_VTOC_8)
3099786Slclee /*
3100786Slclee * The 8-slice vtoc does not include the ascii label; save it into
3101786Slclee * the device's soft state structure here.
3102786Slclee */
31033525Sshidokht bcopy(labp->dkl_asciilabel, cl->cl_asciilabel, LEN_DKL_ASCII);
3104786Slclee #endif
3105786Slclee
3106786Slclee /* Now look for a valid capacity. */
31073525Sshidokht track_capacity = (cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect);
31083525Sshidokht label_capacity = (cl->cl_g.dkg_ncyl * track_capacity);
31093525Sshidokht
31103525Sshidokht if (cl->cl_g.dkg_acyl) {
3111786Slclee #if defined(__i386) || defined(__amd64)
3112786Slclee /* we may have > 1 alts cylinder */
31133525Sshidokht label_capacity += (track_capacity * cl->cl_g.dkg_acyl);
3114786Slclee #else
3115786Slclee label_capacity += track_capacity;
3116786Slclee #endif
3117786Slclee }
3118786Slclee
3119786Slclee /*
31203525Sshidokht * Force check here to ensure the computed capacity is valid.
31213525Sshidokht * If capacity is zero, it indicates an invalid label and
31223525Sshidokht * we should abort updating the relevant data then.
31233525Sshidokht */
31243525Sshidokht if (label_capacity == 0) {
31253525Sshidokht if (!(flags & CMLB_SILENT))
31263525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN,
31273525Sshidokht "Corrupt label - no valid capacity could be "
31283525Sshidokht "retrieved\n");
31293525Sshidokht
31303525Sshidokht return (CMLB_LABEL_IS_INVALID);
31313525Sshidokht }
31323525Sshidokht
31333525Sshidokht /* Mark the geometry as valid. */
31348863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_TRUE;
31353525Sshidokht
31363525Sshidokht /*
3137786Slclee * if we got invalidated when mutex exit and entered again,
3138786Slclee * if blockcount different than when we came in, need to
3139786Slclee * retry from beginning of cmlb_validate_geometry.
3140786Slclee * revisit this on next phase of utilizing this for
3141786Slclee * sd.
3142786Slclee */
3143786Slclee
31443525Sshidokht if (label_capacity <= cl->cl_blockcount) {
3145786Slclee #if defined(_SUNOS_VTOC_8)
3146786Slclee /*
3147786Slclee * We can't let this happen on drives that are subdivided
3148786Slclee * into logical disks (i.e., that have an fdisk table).
31493525Sshidokht * The cl_blockcount field should always hold the full media
3150786Slclee * size in sectors, period. This code would overwrite
31513525Sshidokht * cl_blockcount with the size of the Solaris fdisk partition.
3152786Slclee */
31533525Sshidokht cmlb_dbg(CMLB_ERROR, cl,
3154786Slclee "cmlb_uselabel: Label %d blocks; Drive %d blocks\n",
31553525Sshidokht label_capacity, cl->cl_blockcount);
31563525Sshidokht cl->cl_solaris_size = label_capacity;
3157786Slclee
3158786Slclee #endif /* defined(_SUNOS_VTOC_8) */
3159786Slclee goto done;
3160786Slclee }
3161786Slclee
31623525Sshidokht if (ISCD(cl)) {
3163786Slclee /* For CDROMs, we trust that the data in the label is OK. */
3164786Slclee #if defined(_SUNOS_VTOC_8)
3165786Slclee for (i = 0; i < NDKMAP; i++) {
3166786Slclee part_end = labp->dkl_nhead * labp->dkl_nsect *
3167786Slclee labp->dkl_map[i].dkl_cylno +
3168786Slclee labp->dkl_map[i].dkl_nblk - 1;
3169786Slclee
3170786Slclee if ((labp->dkl_map[i].dkl_nblk) &&
31713525Sshidokht (part_end > cl->cl_blockcount)) {
31728863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE;
3173786Slclee break;
3174786Slclee }
3175786Slclee }
3176786Slclee #endif
3177786Slclee #if defined(_SUNOS_VTOC_16)
3178786Slclee vpartp = &(labp->dkl_vtoc.v_part[0]);
3179786Slclee for (i = 0; i < NDKMAP; i++, vpartp++) {
3180786Slclee part_end = vpartp->p_start + vpartp->p_size;
3181786Slclee if ((vpartp->p_size > 0) &&
31823525Sshidokht (part_end > cl->cl_blockcount)) {
31838863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE;
3184786Slclee break;
3185786Slclee }
3186786Slclee }
3187786Slclee #endif
3188786Slclee } else {
31893525Sshidokht /* label_capacity > cl->cl_blockcount */
31903525Sshidokht if (!(flags & CMLB_SILENT)) {
31913525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN,
31923525Sshidokht "Corrupt label - bad geometry\n");
31933525Sshidokht cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_CONT,
31943525Sshidokht "Label says %llu blocks; Drive says %llu blocks\n",
31953525Sshidokht label_capacity, cl->cl_blockcount);
31963525Sshidokht }
31978863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE;
3198786Slclee label_error = CMLB_LABEL_IS_INVALID;
3199786Slclee }
3200786Slclee
3201786Slclee done:
3202786Slclee
32033525Sshidokht cmlb_dbg(CMLB_INFO, cl, "cmlb_uselabel: (label geometry)\n");
32043525Sshidokht cmlb_dbg(CMLB_INFO, cl,
3205786Slclee " ncyl: %d; acyl: %d; nhead: %d; nsect: %d\n",
32063525Sshidokht cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl,
32073525Sshidokht cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect);
32083525Sshidokht
32093525Sshidokht cmlb_dbg(CMLB_INFO, cl,
3210786Slclee " label_capacity: %d; intrlv: %d; rpm: %d\n",
32113525Sshidokht cl->cl_blockcount, cl->cl_g.dkg_intrlv, cl->cl_g.dkg_rpm);
32123525Sshidokht cmlb_dbg(CMLB_INFO, cl, " wrt_reinstr: %d; rd_reinstr: %d\n",
32133525Sshidokht cl->cl_g.dkg_write_reinstruct, cl->cl_g.dkg_read_reinstruct);
32143525Sshidokht
32153525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl)));
3216786Slclee
3217786Slclee return (label_error);
3218786Slclee }
3219786Slclee
3220786Slclee
3221786Slclee /*
3222786Slclee * Function: cmlb_build_default_label
3223786Slclee *
3224786Slclee * Description: Generate a default label for those devices that do not have
3225786Slclee * one, e.g., new media, removable cartridges, etc..
3226786Slclee *
3227786Slclee * Context: Kernel thread only
3228786Slclee */
32293525Sshidokht /*ARGSUSED*/
3230786Slclee static void
32313525Sshidokht cmlb_build_default_label(struct cmlb_lun *cl, void *tg_cookie)
3232786Slclee {
3233786Slclee #if defined(_SUNOS_VTOC_16)
3234786Slclee uint_t phys_spc;
3235786Slclee uint_t disksize;
32363525Sshidokht struct dk_geom cl_g;
32373525Sshidokht diskaddr_t capacity;
3238786Slclee #endif
3239786Slclee
32403525Sshidokht ASSERT(cl != NULL);
32413525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl)));
3242786Slclee
3243786Slclee #if defined(_SUNOS_VTOC_8)
3244786Slclee /*
3245786Slclee * Note: This is a legacy check for non-removable devices on VTOC_8
3246786Slclee * only. This may be a valid check for VTOC_16 as well.
32473525Sshidokht * Once we understand why there is this difference between SPARC and
32483525Sshidokht * x86 platform, we could remove this legacy check.
3249786Slclee */
32503525Sshidokht if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) {
3251786Slclee return;
3252786Slclee }
3253786Slclee #endif
3254786Slclee
32553525Sshidokht bzero(&cl->cl_g, sizeof (struct dk_geom));
32563525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc));
32573525Sshidokht bzero(&cl->cl_map, NDKMAP * (sizeof (struct dk_map)));
3258786Slclee
3259786Slclee #if defined(_SUNOS_VTOC_8)
3260786Slclee
3261786Slclee /*
3262786Slclee * It's a REMOVABLE media, therefore no label (on sparc, anyway).
3263786Slclee * But it is still necessary to set up various geometry information,
3264786Slclee * and we are doing this here.
3265786Slclee */
3266786Slclee
3267786Slclee /*
3268786Slclee * For the rpm, we use the minimum for the disk. For the head, cyl,
3269786Slclee * and number of sector per track, if the capacity <= 1GB, head = 64,
3270786Slclee * sect = 32. else head = 255, sect 63 Note: the capacity should be
3271786Slclee * equal to C*H*S values. This will cause some truncation of size due
3272786Slclee * to round off errors. For CD-ROMs, this truncation can have adverse
3273786Slclee * side effects, so returning ncyl and nhead as 1. The nsect will
3274786Slclee * overflow for most of CD-ROMs as nsect is of type ushort. (4190569)
3275786Slclee */
32763525Sshidokht cl->cl_solaris_size = cl->cl_blockcount;
32773525Sshidokht if (ISCD(cl)) {
3278786Slclee tg_attribute_t tgattribute;
3279786Slclee int is_writable;
3280786Slclee /*
3281786Slclee * Preserve the old behavior for non-writable
3282786Slclee * medias. Since dkg_nsect is a ushort, it
3283786Slclee * will lose bits as cdroms have more than
3284786Slclee * 65536 sectors. So if we recalculate
3285786Slclee * capacity, it will become much shorter.
3286786Slclee * But the dkg_* information is not
3287786Slclee * used for CDROMs so it is OK. But for
3288786Slclee * Writable CDs we need this information
3289786Slclee * to be valid (for newfs say). So we
3290786Slclee * make nsect and nhead > 1 that way
3291786Slclee * nsect can still stay within ushort limit
3292786Slclee * without losing any bits.
3293786Slclee */
3294786Slclee
3295786Slclee bzero(&tgattribute, sizeof (tg_attribute_t));
3296786Slclee
32973525Sshidokht mutex_exit(CMLB_MUTEX(cl));
32983525Sshidokht is_writable =
32993525Sshidokht (DK_TG_GETATTRIBUTE(cl, &tgattribute, tg_cookie) == 0) ?
3300786Slclee tgattribute.media_is_writable : 1;
33013525Sshidokht mutex_enter(CMLB_MUTEX(cl));
3302786Slclee
3303786Slclee if (is_writable) {
33043525Sshidokht cl->cl_g.dkg_nhead = 64;
33053525Sshidokht cl->cl_g.dkg_nsect = 32;
33063525Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount / (64 * 32);
33077563SPrasad.Singamsetty@Sun.COM cl->cl_solaris_size = (diskaddr_t)cl->cl_g.dkg_ncyl *
33083525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect;
3309786Slclee } else {
33103525Sshidokht cl->cl_g.dkg_ncyl = 1;
33113525Sshidokht cl->cl_g.dkg_nhead = 1;
33123525Sshidokht cl->cl_g.dkg_nsect = cl->cl_blockcount;
3313786Slclee }
3314786Slclee } else {
331511748SShidokht.Yadegari@Sun.COM if (cl->cl_blockcount < 160) {
331611748SShidokht.Yadegari@Sun.COM /* Less than 80K */
331711748SShidokht.Yadegari@Sun.COM cl->cl_g.dkg_nhead = 1;
331811748SShidokht.Yadegari@Sun.COM cl->cl_g.dkg_ncyl = cl->cl_blockcount;
331911748SShidokht.Yadegari@Sun.COM cl->cl_g.dkg_nsect = 1;
332011748SShidokht.Yadegari@Sun.COM } else if (cl->cl_blockcount <= 0x1000) {
3321786Slclee /* unlabeled SCSI floppy device */
33223525Sshidokht cl->cl_g.dkg_nhead = 2;
33233525Sshidokht cl->cl_g.dkg_ncyl = 80;
33243525Sshidokht cl->cl_g.dkg_nsect = cl->cl_blockcount / (2 * 80);
33253525Sshidokht } else if (cl->cl_blockcount <= 0x200000) {
33263525Sshidokht cl->cl_g.dkg_nhead = 64;
33273525Sshidokht cl->cl_g.dkg_nsect = 32;
33283525Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount / (64 * 32);
3329786Slclee } else {
33303525Sshidokht cl->cl_g.dkg_nhead = 255;
33316124Sshidokht
33326124Sshidokht cl->cl_g.dkg_nsect = ((cl->cl_blockcount +
33336124Sshidokht (UINT16_MAX * 255 * 63) - 1) /
33346124Sshidokht (UINT16_MAX * 255 * 63)) * 63;
33356124Sshidokht
33366124Sshidokht if (cl->cl_g.dkg_nsect == 0)
33376124Sshidokht cl->cl_g.dkg_nsect = (UINT16_MAX / 63) * 63;
33386124Sshidokht
33396124Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount /
33406124Sshidokht (255 * cl->cl_g.dkg_nsect);
3341786Slclee }
33426124Sshidokht
33433525Sshidokht cl->cl_solaris_size =
33447563SPrasad.Singamsetty@Sun.COM (diskaddr_t)cl->cl_g.dkg_ncyl * cl->cl_g.dkg_nhead *
33457563SPrasad.Singamsetty@Sun.COM cl->cl_g.dkg_nsect;
3346786Slclee
3347786Slclee }
3348786Slclee
33493525Sshidokht cl->cl_g.dkg_acyl = 0;
33503525Sshidokht cl->cl_g.dkg_bcyl = 0;
33513525Sshidokht cl->cl_g.dkg_rpm = 200;
33523525Sshidokht cl->cl_asciilabel[0] = '\0';
33533525Sshidokht cl->cl_g.dkg_pcyl = cl->cl_g.dkg_ncyl;
33543525Sshidokht
33553525Sshidokht cl->cl_map[0].dkl_cylno = 0;
33563525Sshidokht cl->cl_map[0].dkl_nblk = cl->cl_solaris_size;
33573525Sshidokht
33583525Sshidokht cl->cl_map[2].dkl_cylno = 0;
33593525Sshidokht cl->cl_map[2].dkl_nblk = cl->cl_solaris_size;
3360786Slclee
3361786Slclee #elif defined(_SUNOS_VTOC_16)
3362786Slclee
33633525Sshidokht if (cl->cl_solaris_size == 0) {
3364786Slclee /*
3365786Slclee * Got fdisk table but no solaris entry therefore
3366786Slclee * don't create a default label
3367786Slclee */
33688863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_TRUE;
3369786Slclee return;
3370786Slclee }
3371786Slclee
3372786Slclee /*
3373786Slclee * For CDs we continue to use the physical geometry to calculate
3374786Slclee * number of cylinders. All other devices must convert the
3375786Slclee * physical geometry (cmlb_geom) to values that will fit
3376786Slclee * in a dk_geom structure.
3377786Slclee */
33783525Sshidokht if (ISCD(cl)) {
33793525Sshidokht phys_spc = cl->cl_pgeom.g_nhead * cl->cl_pgeom.g_nsect;
3380786Slclee } else {
3381786Slclee /* Convert physical geometry to disk geometry */
33823525Sshidokht bzero(&cl_g, sizeof (struct dk_geom));
33833525Sshidokht
33843525Sshidokht /*
33853525Sshidokht * Refer to comments related to off-by-1 at the
33863525Sshidokht * header of this file.
33877224Scth * Before calculating geometry, capacity should be
33883525Sshidokht * decreased by 1.
33893525Sshidokht */
33903525Sshidokht
33913525Sshidokht if (cl->cl_alter_behavior & CMLB_OFF_BY_ONE)
33923525Sshidokht capacity = cl->cl_blockcount - 1;
33933525Sshidokht else
33943525Sshidokht capacity = cl->cl_blockcount;
33953525Sshidokht
33963525Sshidokht
339710320SLarry.Liu@Sun.COM cmlb_convert_geometry(cl, capacity, &cl_g, tg_cookie);
33983525Sshidokht bcopy(&cl_g, &cl->cl_g, sizeof (cl->cl_g));
33993525Sshidokht phys_spc = cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect;
3400786Slclee }
3401786Slclee
34029811SSheshadri.Vasudevan@Sun.COM if (phys_spc == 0)
34039811SSheshadri.Vasudevan@Sun.COM return;
34043525Sshidokht cl->cl_g.dkg_pcyl = cl->cl_solaris_size / phys_spc;
34055084Sjohnlev if (cl->cl_alter_behavior & CMLB_FAKE_LABEL_ONE_PARTITION) {
34065084Sjohnlev /* disable devid */
34075084Sjohnlev cl->cl_g.dkg_ncyl = cl->cl_g.dkg_pcyl;
34085084Sjohnlev disksize = cl->cl_solaris_size;
34095084Sjohnlev } else {
34105084Sjohnlev cl->cl_g.dkg_acyl = DK_ACYL;
34115084Sjohnlev cl->cl_g.dkg_ncyl = cl->cl_g.dkg_pcyl - DK_ACYL;
34125084Sjohnlev disksize = cl->cl_g.dkg_ncyl * phys_spc;
34135084Sjohnlev }
34143525Sshidokht
34153525Sshidokht if (ISCD(cl)) {
3416786Slclee /*
3417786Slclee * CD's don't use the "heads * sectors * cyls"-type of
3418786Slclee * geometry, but instead use the entire capacity of the media.
3419786Slclee */
34203525Sshidokht disksize = cl->cl_solaris_size;
34213525Sshidokht cl->cl_g.dkg_nhead = 1;
34223525Sshidokht cl->cl_g.dkg_nsect = 1;
34233525Sshidokht cl->cl_g.dkg_rpm =
34243525Sshidokht (cl->cl_pgeom.g_rpm == 0) ? 200 : cl->cl_pgeom.g_rpm;
34253525Sshidokht
34263525Sshidokht cl->cl_vtoc.v_part[0].p_start = 0;
34273525Sshidokht cl->cl_vtoc.v_part[0].p_size = disksize;
34283525Sshidokht cl->cl_vtoc.v_part[0].p_tag = V_BACKUP;
34293525Sshidokht cl->cl_vtoc.v_part[0].p_flag = V_UNMNT;
34303525Sshidokht
34313525Sshidokht cl->cl_map[0].dkl_cylno = 0;
34323525Sshidokht cl->cl_map[0].dkl_nblk = disksize;
34333525Sshidokht cl->cl_offset[0] = 0;
3434786Slclee
3435786Slclee } else {
3436786Slclee /*
3437786Slclee * Hard disks and removable media cartridges
3438786Slclee */
34393525Sshidokht cl->cl_g.dkg_rpm =
34403525Sshidokht (cl->cl_pgeom.g_rpm == 0) ? 3600: cl->cl_pgeom.g_rpm;
34413525Sshidokht cl->cl_vtoc.v_sectorsz = cl->cl_sys_blocksize;
3442786Slclee
3443786Slclee /* Add boot slice */
34443525Sshidokht cl->cl_vtoc.v_part[8].p_start = 0;
34453525Sshidokht cl->cl_vtoc.v_part[8].p_size = phys_spc;
34463525Sshidokht cl->cl_vtoc.v_part[8].p_tag = V_BOOT;
34473525Sshidokht cl->cl_vtoc.v_part[8].p_flag = V_UNMNT;
34483525Sshidokht
34493525Sshidokht cl->cl_map[8].dkl_cylno = 0;
34503525Sshidokht cl->cl_map[8].dkl_nblk = phys_spc;
34513525Sshidokht cl->cl_offset[8] = 0;
34523525Sshidokht
34533525Sshidokht if ((cl->cl_alter_behavior &
3454786Slclee CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT) &&
34553525Sshidokht cl->cl_device_type == DTYPE_DIRECT) {
34563525Sshidokht cl->cl_vtoc.v_part[9].p_start = phys_spc;
34573525Sshidokht cl->cl_vtoc.v_part[9].p_size = 2 * phys_spc;
34583525Sshidokht cl->cl_vtoc.v_part[9].p_tag = V_ALTSCTR;
34593525Sshidokht cl->cl_vtoc.v_part[9].p_flag = 0;
34603525Sshidokht
34613525Sshidokht cl->cl_map[9].dkl_cylno = 1;
34623525Sshidokht cl->cl_map[9].dkl_nblk = 2 * phys_spc;
34633525Sshidokht cl->cl_offset[9] = phys_spc;
3464786Slclee }
3465786Slclee }
3466786Slclee
34673525Sshidokht cl->cl_g.dkg_apc = 0;
3468786Slclee
3469786Slclee /* Add backup slice */
34703525Sshidokht cl->cl_vtoc.v_part[2].p_start = 0;
34713525Sshidokht cl->cl_vtoc.v_part[2].p_size = disksize;
34723525Sshidokht cl->cl_vtoc.v_part[2].p_tag = V_BACKUP;
34733525Sshidokht cl->cl_vtoc.v_part[2].p_flag = V_UNMNT;
34743525Sshidokht
34753525Sshidokht cl->cl_map[2].dkl_cylno = 0;
34763525Sshidokht cl->cl_map[2].dkl_nblk = disksize;
34773525Sshidokht cl->cl_offset[2] = 0;
34783525Sshidokht
34795084Sjohnlev /*
34805084Sjohnlev * single slice (s0) covering the entire disk
34815084Sjohnlev */
34825084Sjohnlev if (cl->cl_alter_behavior & CMLB_FAKE_LABEL_ONE_PARTITION) {
34835084Sjohnlev cl->cl_vtoc.v_part[0].p_start = 0;
34845084Sjohnlev cl->cl_vtoc.v_part[0].p_tag = V_UNASSIGNED;
34855084Sjohnlev cl->cl_vtoc.v_part[0].p_flag = 0;
34865084Sjohnlev cl->cl_vtoc.v_part[0].p_size = disksize;
34875084Sjohnlev cl->cl_map[0].dkl_cylno = 0;
34885084Sjohnlev cl->cl_map[0].dkl_nblk = disksize;
34895084Sjohnlev cl->cl_offset[0] = 0;
34905084Sjohnlev }
34915084Sjohnlev
34923525Sshidokht (void) sprintf(cl->cl_vtoc.v_asciilabel, "DEFAULT cyl %d alt %d"
34933525Sshidokht " hd %d sec %d", cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl,
34943525Sshidokht cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect);
3495786Slclee
3496786Slclee #else
3497786Slclee #error "No VTOC format defined."
3498786Slclee #endif
3499786Slclee
35003525Sshidokht cl->cl_g.dkg_read_reinstruct = 0;
35013525Sshidokht cl->cl_g.dkg_write_reinstruct = 0;
35023525Sshidokht
35033525Sshidokht cl->cl_g.dkg_intrlv = 1;
35043525Sshidokht
35053525Sshidokht cl->cl_vtoc.v_sanity = VTOC_SANE;
35068169SGabriel.Carrillo@Sun.COM cl->cl_vtoc.v_nparts = V_NUMPAR;
35078169SGabriel.Carrillo@Sun.COM cl->cl_vtoc.v_version = V_VERSION;
35083525Sshidokht
35098863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_TRUE;
35107563SPrasad.Singamsetty@Sun.COM cl->cl_label_from_media = CMLB_LABEL_UNDEF;
35113525Sshidokht
35123525Sshidokht cmlb_dbg(CMLB_INFO, cl,
3513786Slclee "cmlb_build_default_label: Default label created: "
3514786Slclee "cyl: %d\tacyl: %d\tnhead: %d\tnsect: %d\tcap: %d\n",
35153525Sshidokht cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl, cl->cl_g.dkg_nhead,
35163525Sshidokht cl->cl_g.dkg_nsect, cl->cl_blockcount);
3517786Slclee }
3518786Slclee
3519786Slclee
3520786Slclee #if defined(_FIRMWARE_NEEDS_FDISK)
3521786Slclee /*
3522786Slclee * Max CHS values, as they are encoded into bytes, for 1022/254/63
3523786Slclee */
3524786Slclee #define LBA_MAX_SECT (63 | ((1022 & 0x300) >> 2))
3525786Slclee #define LBA_MAX_CYL (1022 & 0xFF)
3526786Slclee #define LBA_MAX_HEAD (254)
3527786Slclee
3528786Slclee
3529786Slclee /*
3530786Slclee * Function: cmlb_has_max_chs_vals
3531786Slclee *
35328863SEdward.Pilatowicz@Sun.COM * Description: Return B_TRUE if Cylinder-Head-Sector values are all at maximum.
3533786Slclee *
3534786Slclee * Arguments: fdp - ptr to CHS info
3535786Slclee *
3536786Slclee * Return Code: True or false
3537786Slclee *
3538786Slclee * Context: Any.
3539786Slclee */
35408863SEdward.Pilatowicz@Sun.COM static boolean_t
3541786Slclee cmlb_has_max_chs_vals(struct ipart *fdp)
3542786Slclee {
3543786Slclee return ((fdp->begcyl == LBA_MAX_CYL) &&
3544786Slclee (fdp->beghead == LBA_MAX_HEAD) &&
3545786Slclee (fdp->begsect == LBA_MAX_SECT) &&
3546786Slclee (fdp->endcyl == LBA_MAX_CYL) &&
3547786Slclee (fdp->endhead == LBA_MAX_HEAD) &&
3548786Slclee (fdp->endsect == LBA_MAX_SECT));
3549786Slclee }
3550786Slclee #endif
3551786Slclee
3552786Slclee /*
3553786Slclee * Function: cmlb_dkio_get_geometry
3554786Slclee *
3555786Slclee * Description: This routine is the driver entry point for handling user
3556786Slclee * requests to get the device geometry (DKIOCGGEOM).
3557786Slclee *
3558786Slclee * Arguments:
35593525Sshidokht * arg pointer to user provided dk_geom structure specifying
3560786Slclee * the controller's notion of the current geometry.
35613525Sshidokht *
35623525Sshidokht * flag this argument is a pass through to ddi_copyxxx()
35633525Sshidokht * directly from the mode argument of ioctl().
35643525Sshidokht *
35653525Sshidokht * tg_cookie cookie from target driver to be passed back to target
35663525Sshidokht * driver when we call back to it through tg_ops.
3567786Slclee *
3568786Slclee * Return Code: 0
3569786Slclee * EFAULT
3570786Slclee * ENXIO
3571786Slclee * EIO
3572786Slclee */
3573786Slclee static int
35743525Sshidokht cmlb_dkio_get_geometry(struct cmlb_lun *cl, caddr_t arg, int flag,
35753525Sshidokht void *tg_cookie)
3576786Slclee {
3577786Slclee struct dk_geom *tmp_geom = NULL;
3578786Slclee int rval = 0;
3579786Slclee
3580786Slclee /*
3581786Slclee * cmlb_validate_geometry does not spin a disk up
35823525Sshidokht * if it was spcl down. We need to make sure it
3583786Slclee * is ready.
3584786Slclee */
35853525Sshidokht mutex_enter(CMLB_MUTEX(cl));
35868863SEdward.Pilatowicz@Sun.COM rval = cmlb_validate_geometry(cl, B_TRUE, 0, tg_cookie);
3587786Slclee #if defined(_SUNOS_VTOC_8)
3588786Slclee if (rval == EINVAL &&
35893525Sshidokht cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8) {
3590786Slclee /*
3591786Slclee * This is to return a default label geometry even when we
3592786Slclee * do not really assume a default label for the device.
3593786Slclee * dad driver utilizes this.
3594786Slclee */
35957563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount <= CMLB_OLDVTOC_LIMIT) {
35963525Sshidokht cmlb_setup_default_geometry(cl, tg_cookie);
3597786Slclee rval = 0;
3598786Slclee }
3599786Slclee }
3600786Slclee #endif
3601786Slclee if (rval) {
36023525Sshidokht mutex_exit(CMLB_MUTEX(cl));
3603786Slclee return (rval);
3604786Slclee }
3605786Slclee
3606786Slclee #if defined(__i386) || defined(__amd64)
36073525Sshidokht if (cl->cl_solaris_size == 0) {
36083525Sshidokht mutex_exit(CMLB_MUTEX(cl));
3609786Slclee return (EIO);
3610786Slclee }
3611786Slclee #endif
3612786Slclee
3613786Slclee /*
3614786Slclee * Make a local copy of the soft state geometry to avoid some potential
3615786Slclee * race conditions associated with holding the mutex and updating the
3616786Slclee * write_reinstruct value
3617786Slclee */
3618786Slclee tmp_geom = kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP);
36193525Sshidokht bcopy(&cl->cl_g, tmp_geom, sizeof (struct dk_geom));
3620786Slclee
3621786Slclee if (tmp_geom->dkg_write_reinstruct == 0) {
3622786Slclee tmp_geom->dkg_write_reinstruct =
3623786Slclee (int)((int)(tmp_geom->dkg_nsect * tmp_geom->dkg_rpm *
3624786Slclee cmlb_rot_delay) / (int)60000);
3625786Slclee }
36263525Sshidokht mutex_exit(CMLB_MUTEX(cl));
3627786Slclee
3628786Slclee rval = ddi_copyout(tmp_geom, (void *)arg, sizeof (struct dk_geom),
3629786Slclee flag);
3630786Slclee if (rval != 0) {
3631786Slclee rval = EFAULT;
3632786Slclee }
3633786Slclee
3634786Slclee kmem_free(tmp_geom, sizeof (struct dk_geom));
3635786Slclee return (rval);
3636786Slclee
3637786Slclee }
3638786Slclee
3639786Slclee
3640786Slclee /*
3641786Slclee * Function: cmlb_dkio_set_geometry
3642786Slclee *
3643786Slclee * Description: This routine is the driver entry point for handling user
3644786Slclee * requests to set the device geometry (DKIOCSGEOM). The actual
3645786Slclee * device geometry is not updated, just the driver "notion" of it.
3646786Slclee *
3647786Slclee * Arguments:
36483525Sshidokht * arg pointer to user provided dk_geom structure used to set
3649786Slclee * the controller's notion of the current geometry.
36503525Sshidokht *
36513525Sshidokht * flag this argument is a pass through to ddi_copyxxx()
36523525Sshidokht * directly from the mode argument of ioctl().
36533525Sshidokht *
36543525Sshidokht * tg_cookie cookie from target driver to be passed back to target
36553525Sshidokht * driver when we call back to it through tg_ops.
3656786Slclee *
3657786Slclee * Return Code: 0
3658786Slclee * EFAULT
3659786Slclee * ENXIO
3660786Slclee * EIO
3661786Slclee */
3662786Slclee static int
36633525Sshidokht cmlb_dkio_set_geometry(struct cmlb_lun *cl, caddr_t arg, int flag)
3664786Slclee {
3665786Slclee struct dk_geom *tmp_geom;
3666786Slclee struct dk_map *lp;
3667786Slclee int rval = 0;
3668786Slclee int i;
3669786Slclee
3670786Slclee
3671786Slclee #if defined(__i386) || defined(__amd64)
36723525Sshidokht if (cl->cl_solaris_size == 0) {
3673786Slclee return (EIO);
3674786Slclee }
3675786Slclee #endif
3676786Slclee /*
3677786Slclee * We need to copy the user specified geometry into local
3678786Slclee * storage and then update the softstate. We don't want to hold
3679786Slclee * the mutex and copyin directly from the user to the soft state
3680786Slclee */
3681786Slclee tmp_geom = (struct dk_geom *)
3682786Slclee kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP);
3683786Slclee rval = ddi_copyin(arg, tmp_geom, sizeof (struct dk_geom), flag);
3684786Slclee if (rval != 0) {
3685786Slclee kmem_free(tmp_geom, sizeof (struct dk_geom));
3686786Slclee return (EFAULT);
3687786Slclee }
3688786Slclee
36893525Sshidokht mutex_enter(CMLB_MUTEX(cl));
36903525Sshidokht bcopy(tmp_geom, &cl->cl_g, sizeof (struct dk_geom));
3691786Slclee for (i = 0; i < NDKMAP; i++) {
36923525Sshidokht lp = &cl->cl_map[i];
36933525Sshidokht cl->cl_offset[i] =
36943525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno;
3695786Slclee #if defined(__i386) || defined(__amd64)
36963525Sshidokht cl->cl_offset[i] += cl->cl_solaris_offset;
3697786Slclee #endif
3698786Slclee }
36998863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE;
37003525Sshidokht mutex_exit(CMLB_MUTEX(cl));
3701786Slclee kmem_free(tmp_geom, sizeof (struct dk_geom));
3702786Slclee
3703786Slclee return (rval);
3704786Slclee }
3705786Slclee
3706786Slclee /*
3707786Slclee * Function: cmlb_dkio_get_partition
3708786Slclee *
3709786Slclee * Description: This routine is the driver entry point for handling user
3710786Slclee * requests to get the partition table (DKIOCGAPART).
3711786Slclee *
3712786Slclee * Arguments:
37133525Sshidokht * arg pointer to user provided dk_allmap structure specifying
3714786Slclee * the controller's notion of the current partition table.
37153525Sshidokht *
37163525Sshidokht * flag this argument is a pass through to ddi_copyxxx()
37173525Sshidokht * directly from the mode argument of ioctl().
37183525Sshidokht *
37193525Sshidokht * tg_cookie cookie from target driver to be passed back to target
37203525Sshidokht * driver when we call back to it through tg_ops.
3721786Slclee *
3722786Slclee * Return Code: 0
3723786Slclee * EFAULT
3724786Slclee * ENXIO
3725786Slclee * EIO
3726786Slclee */
3727786Slclee static int
37283525Sshidokht cmlb_dkio_get_partition(struct cmlb_lun *cl, caddr_t arg, int flag,
37293525Sshidokht void *tg_cookie)
3730786Slclee {
3731786Slclee int rval = 0;
3732786Slclee int size;
3733786Slclee
3734786Slclee /*
3735786Slclee * Make sure the geometry is valid before getting the partition
3736786Slclee * information.
3737786Slclee */
37383525Sshidokht mutex_enter(CMLB_MUTEX(cl));
37398863SEdward.Pilatowicz@Sun.COM if ((rval = cmlb_validate_geometry(cl, B_TRUE, 0, tg_cookie)) != 0) {
37403525Sshidokht mutex_exit(CMLB_MUTEX(cl));
3741786Slclee return (rval);
3742786Slclee }
37433525Sshidokht mutex_exit(CMLB_MUTEX(cl));
3744786Slclee
3745786Slclee #if defined(__i386) || defined(__amd64)
37463525Sshidokht if (cl->cl_solaris_size == 0) {
3747786Slclee return (EIO);
3748786Slclee }
3749786Slclee #endif
3750786Slclee
3751786Slclee #ifdef _MULTI_DATAMODEL
3752786Slclee switch (ddi_model_convert_from(flag & FMODELS)) {
3753786Slclee case DDI_MODEL_ILP32: {
3754786Slclee struct dk_map32 dk_map32[NDKMAP];
3755786Slclee int i;
3756786Slclee
3757786Slclee for (i = 0; i < NDKMAP; i++) {
37583525Sshidokht dk_map32[i].dkl_cylno = cl->cl_map[i].dkl_cylno;
37593525Sshidokht dk_map32[i].dkl_nblk = cl->cl_map[i].dkl_nblk;
3760786Slclee }
3761786Slclee size = NDKMAP * sizeof (struct dk_map32);
3762786Slclee rval = ddi_copyout(dk_map32, (void *)arg, size, flag);
3763786Slclee if (rval != 0) {
3764786Slclee rval = EFAULT;
3765786Slclee }
3766786Slclee break;
3767786Slclee }
3768786Slclee case DDI_MODEL_NONE:
3769786Slclee size = NDKMAP * sizeof (struct dk_map);
37703525Sshidokht rval = ddi_copyout(cl->cl_map, (void *)arg, size, flag);
3771786Slclee if (rval != 0) {
3772786Slclee rval = EFAULT;
3773786Slclee }
3774786Slclee break;
3775786Slclee }
3776786Slclee #else /* ! _MULTI_DATAMODEL */
3777786Slclee size = NDKMAP * sizeof (struct dk_map);
37783525Sshidokht rval = ddi_copyout(cl->cl_map, (void *)arg, size, flag);
3779786Slclee if (rval != 0) {
3780786Slclee rval = EFAULT;
3781786Slclee }
3782786Slclee #endif /* _MULTI_DATAMODEL */
3783786Slclee return (rval);
3784786Slclee }
3785786Slclee
3786786Slclee /*
3787786Slclee * Function: cmlb_dkio_set_partition
3788786Slclee *
3789786Slclee * Description: This routine is the driver entry point for handling user
3790786Slclee * requests to set the partition table (DKIOCSAPART). The actual
3791786Slclee * device partition is not updated.
3792786Slclee *
3793786Slclee * Arguments:
3794786Slclee * arg - pointer to user provided dk_allmap structure used to set
3795786Slclee * the controller's notion of the partition table.
3796786Slclee * flag - this argument is a pass through to ddi_copyxxx()
3797786Slclee * directly from the mode argument of ioctl().
3798786Slclee *
3799786Slclee * Return Code: 0
3800786Slclee * EINVAL
3801786Slclee * EFAULT
3802786Slclee * ENXIO
3803786Slclee * EIO
3804786Slclee */
3805786Slclee static int
38063525Sshidokht cmlb_dkio_set_partition(struct cmlb_lun *cl, caddr_t arg, int flag)
3807786Slclee {
3808786Slclee struct dk_map dk_map[NDKMAP];
3809786Slclee struct dk_map *lp;
3810786Slclee int rval = 0;
3811786Slclee int size;
3812786Slclee int i;
3813786Slclee #if defined(_SUNOS_VTOC_16)
3814786Slclee struct dkl_partition *vp;
3815786Slclee #endif
3816786Slclee
3817786Slclee /*
3818786Slclee * Set the map for all logical partitions. We lock
3819786Slclee * the priority just to make sure an interrupt doesn't
3820786Slclee * come in while the map is half updated.
3821786Slclee */
38223525Sshidokht _NOTE(DATA_READABLE_WITHOUT_LOCK(cmlb_lun::cl_solaris_size))
38233525Sshidokht mutex_enter(CMLB_MUTEX(cl));
38243525Sshidokht
38257563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) {
38263525Sshidokht mutex_exit(CMLB_MUTEX(cl));
3827786Slclee return (ENOTSUP);
3828786Slclee }
38293525Sshidokht mutex_exit(CMLB_MUTEX(cl));
38303525Sshidokht if (cl->cl_solaris_size == 0) {
3831786Slclee return (EIO);
3832786Slclee }
3833786Slclee
3834786Slclee #ifdef _MULTI_DATAMODEL
3835786Slclee switch (ddi_model_convert_from(flag & FMODELS)) {
3836786Slclee case DDI_MODEL_ILP32: {
3837786Slclee struct dk_map32 dk_map32[NDKMAP];
3838786Slclee
3839786Slclee size = NDKMAP * sizeof (struct dk_map32);
3840786Slclee rval = ddi_copyin((void *)arg, dk_map32, size, flag);
3841786Slclee if (rval != 0) {
3842786Slclee return (EFAULT);
3843786Slclee }
3844786Slclee for (i = 0; i < NDKMAP; i++) {
3845786Slclee dk_map[i].dkl_cylno = dk_map32[i].dkl_cylno;
3846786Slclee dk_map[i].dkl_nblk = dk_map32[i].dkl_nblk;
3847786Slclee }
3848786Slclee break;
3849786Slclee }
3850786Slclee case DDI_MODEL_NONE:
3851786Slclee size = NDKMAP * sizeof (struct dk_map);
3852786Slclee rval = ddi_copyin((void *)arg, dk_map, size, flag);
3853786Slclee if (rval != 0) {
3854786Slclee return (EFAULT);
3855786Slclee }
3856786Slclee break;
3857786Slclee }
3858786Slclee #else /* ! _MULTI_DATAMODEL */
3859786Slclee size = NDKMAP * sizeof (struct dk_map);
3860786Slclee rval = ddi_copyin((void *)arg, dk_map, size, flag);
3861786Slclee if (rval != 0) {
3862786Slclee return (EFAULT);
3863786Slclee }
3864786Slclee #endif /* _MULTI_DATAMODEL */
3865786Slclee
38663525Sshidokht mutex_enter(CMLB_MUTEX(cl));
3867786Slclee /* Note: The size used in this bcopy is set based upon the data model */
38683525Sshidokht bcopy(dk_map, cl->cl_map, size);
3869786Slclee #if defined(_SUNOS_VTOC_16)
38703525Sshidokht vp = (struct dkl_partition *)&(cl->cl_vtoc);
3871786Slclee #endif /* defined(_SUNOS_VTOC_16) */
3872786Slclee for (i = 0; i < NDKMAP; i++) {
38733525Sshidokht lp = &cl->cl_map[i];
38743525Sshidokht cl->cl_offset[i] =
38753525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno;
3876786Slclee #if defined(_SUNOS_VTOC_16)
38773525Sshidokht vp->p_start = cl->cl_offset[i];
3878786Slclee vp->p_size = lp->dkl_nblk;
3879786Slclee vp++;
3880786Slclee #endif /* defined(_SUNOS_VTOC_16) */
3881786Slclee #if defined(__i386) || defined(__amd64)
38823525Sshidokht cl->cl_offset[i] += cl->cl_solaris_offset;
3883786Slclee #endif
3884786Slclee }
38853525Sshidokht mutex_exit(CMLB_MUTEX(cl));
3886786Slclee return (rval);
3887786Slclee }
3888786Slclee
3889786Slclee
3890786Slclee /*
3891786Slclee * Function: cmlb_dkio_get_vtoc
3892786Slclee *
3893786Slclee * Description: This routine is the driver entry point for handling user
3894786Slclee * requests to get the current volume table of contents
3895786Slclee * (DKIOCGVTOC).
3896786Slclee *
3897786Slclee * Arguments:
38983525Sshidokht * arg pointer to user provided vtoc structure specifying
3899786Slclee * the current vtoc.
39003525Sshidokht *
39013525Sshidokht * flag this argument is a pass through to ddi_copyxxx()
39023525Sshidokht * directly from the mode argument of ioctl().
39033525Sshidokht *
39043525Sshidokht * tg_cookie cookie from target driver to be passed back to target
39053525Sshidokht * driver when we call back to it through tg_ops.
3906786Slclee *
3907786Slclee * Return Code: 0
3908786Slclee * EFAULT
3909786Slclee * ENXIO
3910786Slclee * EIO
3911786Slclee */
3912786Slclee static int
39133525Sshidokht cmlb_dkio_get_vtoc(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie)
3914786Slclee {
3915786Slclee #if defined(_SUNOS_VTOC_8)
3916786Slclee struct vtoc user_vtoc;
3917786Slclee #endif /* defined(_SUNOS_VTOC_8) */
3918786Slclee int rval = 0;
3919786Slclee
39203525Sshidokht mutex_enter(CMLB_MUTEX(cl));
39217563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) {
39227563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl));
39237563SPrasad.Singamsetty@Sun.COM return (EOVERFLOW);
39247563SPrasad.Singamsetty@Sun.COM }
39257563SPrasad.Singamsetty@Sun.COM
39268863SEdward.Pilatowicz@Sun.COM rval = cmlb_validate_geometry(cl, B_TRUE, 0, tg_cookie);
3927786Slclee
3928786Slclee #if defined(_SUNOS_VTOC_8)
3929786Slclee if (rval == EINVAL &&
39303525Sshidokht (cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8)) {
3931786Slclee /*
3932786Slclee * This is to return a default label even when we do not
3933786Slclee * really assume a default label for the device.
3934786Slclee * dad driver utilizes this.
3935786Slclee */
39367563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount <= CMLB_OLDVTOC_LIMIT) {
39373525Sshidokht cmlb_setup_default_geometry(cl, tg_cookie);
3938786Slclee rval = 0;
3939786Slclee }
3940786Slclee }
3941786Slclee #endif
3942786Slclee if (rval) {
39433525Sshidokht mutex_exit(CMLB_MUTEX(cl));
3944786Slclee return (rval);
3945786Slclee }
3946786Slclee
3947786Slclee #if defined(_SUNOS_VTOC_8)
39483525Sshidokht cmlb_build_user_vtoc(cl, &user_vtoc);
39493525Sshidokht mutex_exit(CMLB_MUTEX(cl));
3950786Slclee
3951786Slclee #ifdef _MULTI_DATAMODEL
3952786Slclee switch (ddi_model_convert_from(flag & FMODELS)) {
3953786Slclee case DDI_MODEL_ILP32: {
3954786Slclee struct vtoc32 user_vtoc32;
3955786Slclee
3956786Slclee vtoctovtoc32(user_vtoc, user_vtoc32);
3957786Slclee if (ddi_copyout(&user_vtoc32, (void *)arg,
3958786Slclee sizeof (struct vtoc32), flag)) {
3959786Slclee return (EFAULT);
3960786Slclee }
3961786Slclee break;
3962786Slclee }
3963786Slclee
3964786Slclee case DDI_MODEL_NONE:
3965786Slclee if (ddi_copyout(&user_vtoc, (void *)arg,
3966786Slclee sizeof (struct vtoc), flag)) {
3967786Slclee return (EFAULT);
3968786Slclee }
3969786Slclee break;
3970786Slclee }
3971786Slclee #else /* ! _MULTI_DATAMODEL */
3972786Slclee if (ddi_copyout(&user_vtoc, (void *)arg, sizeof (struct vtoc), flag)) {
3973786Slclee return (EFAULT);
3974786Slclee }
3975786Slclee #endif /* _MULTI_DATAMODEL */
3976786Slclee
3977786Slclee #elif defined(_SUNOS_VTOC_16)
39783525Sshidokht mutex_exit(CMLB_MUTEX(cl));
3979786Slclee
3980786Slclee #ifdef _MULTI_DATAMODEL
3981786Slclee /*
39823525Sshidokht * The cl_vtoc structure is a "struct dk_vtoc" which is always
3983786Slclee * 32-bit to maintain compatibility with existing on-disk
3984786Slclee * structures. Thus, we need to convert the structure when copying
3985786Slclee * it out to a datamodel-dependent "struct vtoc" in a 64-bit
3986786Slclee * program. If the target is a 32-bit program, then no conversion
3987786Slclee * is necessary.
3988786Slclee */
3989786Slclee /* LINTED: logical expression always true: op "||" */
39903525Sshidokht ASSERT(sizeof (cl->cl_vtoc) == sizeof (struct vtoc32));
3991786Slclee switch (ddi_model_convert_from(flag & FMODELS)) {
3992786Slclee case DDI_MODEL_ILP32:
39933525Sshidokht if (ddi_copyout(&(cl->cl_vtoc), (void *)arg,
39943525Sshidokht sizeof (cl->cl_vtoc), flag)) {
3995786Slclee return (EFAULT);
3996786Slclee }
3997786Slclee break;
3998786Slclee
3999786Slclee case DDI_MODEL_NONE: {
4000786Slclee struct vtoc user_vtoc;
4001786Slclee
40023525Sshidokht vtoc32tovtoc(cl->cl_vtoc, user_vtoc);
4003786Slclee if (ddi_copyout(&user_vtoc, (void *)arg,
4004786Slclee sizeof (struct vtoc), flag)) {
4005786Slclee return (EFAULT);
4006786Slclee }
4007786Slclee break;
4008786Slclee }
4009786Slclee }
4010786Slclee #else /* ! _MULTI_DATAMODEL */
40113525Sshidokht if (ddi_copyout(&(cl->cl_vtoc), (void *)arg, sizeof (cl->cl_vtoc),
4012786Slclee flag)) {
4013786Slclee return (EFAULT);
4014786Slclee }
4015786Slclee #endif /* _MULTI_DATAMODEL */
4016786Slclee #else
4017786Slclee #error "No VTOC format defined."
4018786Slclee #endif
4019786Slclee
4020786Slclee return (rval);
4021786Slclee }
4022786Slclee
40237563SPrasad.Singamsetty@Sun.COM
40247563SPrasad.Singamsetty@Sun.COM /*
40257563SPrasad.Singamsetty@Sun.COM * Function: cmlb_dkio_get_extvtoc
40267563SPrasad.Singamsetty@Sun.COM */
40277563SPrasad.Singamsetty@Sun.COM static int
40287563SPrasad.Singamsetty@Sun.COM cmlb_dkio_get_extvtoc(struct cmlb_lun *cl, caddr_t arg, int flag,
40297563SPrasad.Singamsetty@Sun.COM void *tg_cookie)
40307563SPrasad.Singamsetty@Sun.COM {
40317563SPrasad.Singamsetty@Sun.COM struct extvtoc ext_vtoc;
40327563SPrasad.Singamsetty@Sun.COM #if defined(_SUNOS_VTOC_8)
40337563SPrasad.Singamsetty@Sun.COM struct vtoc user_vtoc;
40347563SPrasad.Singamsetty@Sun.COM #endif /* defined(_SUNOS_VTOC_8) */
40357563SPrasad.Singamsetty@Sun.COM int rval = 0;
40367563SPrasad.Singamsetty@Sun.COM
40377563SPrasad.Singamsetty@Sun.COM bzero(&ext_vtoc, sizeof (struct extvtoc));
40387563SPrasad.Singamsetty@Sun.COM mutex_enter(CMLB_MUTEX(cl));
40398863SEdward.Pilatowicz@Sun.COM rval = cmlb_validate_geometry(cl, B_TRUE, 0, tg_cookie);
40407563SPrasad.Singamsetty@Sun.COM
40417563SPrasad.Singamsetty@Sun.COM #if defined(_SUNOS_VTOC_8)
40427563SPrasad.Singamsetty@Sun.COM if (rval == EINVAL &&
40437563SPrasad.Singamsetty@Sun.COM (cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8)) {
40447563SPrasad.Singamsetty@Sun.COM /*
40457563SPrasad.Singamsetty@Sun.COM * This is to return a default label even when we do not
40467563SPrasad.Singamsetty@Sun.COM * really assume a default label for the device.
40477563SPrasad.Singamsetty@Sun.COM * dad driver utilizes this.
40487563SPrasad.Singamsetty@Sun.COM */
40497563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount <= CMLB_OLDVTOC_LIMIT) {
40507563SPrasad.Singamsetty@Sun.COM cmlb_setup_default_geometry(cl, tg_cookie);
40517563SPrasad.Singamsetty@Sun.COM rval = 0;
40527563SPrasad.Singamsetty@Sun.COM }
40537563SPrasad.Singamsetty@Sun.COM }
40547563SPrasad.Singamsetty@Sun.COM #endif
40557563SPrasad.Singamsetty@Sun.COM if (rval) {
40567563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl));
40577563SPrasad.Singamsetty@Sun.COM return (rval);
40587563SPrasad.Singamsetty@Sun.COM }
40597563SPrasad.Singamsetty@Sun.COM
40607563SPrasad.Singamsetty@Sun.COM #if defined(_SUNOS_VTOC_8)
40617563SPrasad.Singamsetty@Sun.COM cmlb_build_user_vtoc(cl, &user_vtoc);
40627563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl));
40637563SPrasad.Singamsetty@Sun.COM
40647563SPrasad.Singamsetty@Sun.COM /*
40657563SPrasad.Singamsetty@Sun.COM * Checking callers data model does not make much sense here
40667563SPrasad.Singamsetty@Sun.COM * since extvtoc will always be equivalent to 64bit vtoc.
40677563SPrasad.Singamsetty@Sun.COM * What is important is whether the kernel is in 32 or 64 bit
40687563SPrasad.Singamsetty@Sun.COM */
40697563SPrasad.Singamsetty@Sun.COM
40707563SPrasad.Singamsetty@Sun.COM #ifdef _LP64
40717563SPrasad.Singamsetty@Sun.COM if (ddi_copyout(&user_vtoc, (void *)arg,
40727563SPrasad.Singamsetty@Sun.COM sizeof (struct extvtoc), flag)) {
40737563SPrasad.Singamsetty@Sun.COM return (EFAULT);
40747563SPrasad.Singamsetty@Sun.COM }
40757563SPrasad.Singamsetty@Sun.COM #else
40767563SPrasad.Singamsetty@Sun.COM vtoc32tovtoc(user_vtoc, ext_vtoc);
40777563SPrasad.Singamsetty@Sun.COM if (ddi_copyout(&ext_vtoc, (void *)arg,
40787563SPrasad.Singamsetty@Sun.COM sizeof (struct extvtoc), flag)) {
40797563SPrasad.Singamsetty@Sun.COM return (EFAULT);
40807563SPrasad.Singamsetty@Sun.COM }
40817563SPrasad.Singamsetty@Sun.COM #endif
40827563SPrasad.Singamsetty@Sun.COM
40837563SPrasad.Singamsetty@Sun.COM #elif defined(_SUNOS_VTOC_16)
40847563SPrasad.Singamsetty@Sun.COM /*
40857563SPrasad.Singamsetty@Sun.COM * The cl_vtoc structure is a "struct dk_vtoc" which is always
40867563SPrasad.Singamsetty@Sun.COM * 32-bit to maintain compatibility with existing on-disk
40877563SPrasad.Singamsetty@Sun.COM * structures. Thus, we need to convert the structure when copying
40887563SPrasad.Singamsetty@Sun.COM * it out to extvtoc
40897563SPrasad.Singamsetty@Sun.COM */
40907563SPrasad.Singamsetty@Sun.COM vtoc32tovtoc(cl->cl_vtoc, ext_vtoc);
40917909SXiao.L@Sun.COM mutex_exit(CMLB_MUTEX(cl));
40927563SPrasad.Singamsetty@Sun.COM
40937563SPrasad.Singamsetty@Sun.COM if (ddi_copyout(&ext_vtoc, (void *)arg, sizeof (struct extvtoc), flag))
40947563SPrasad.Singamsetty@Sun.COM return (EFAULT);
40957563SPrasad.Singamsetty@Sun.COM #else
40967563SPrasad.Singamsetty@Sun.COM #error "No VTOC format defined."
40977563SPrasad.Singamsetty@Sun.COM #endif
40987563SPrasad.Singamsetty@Sun.COM
40997563SPrasad.Singamsetty@Sun.COM return (rval);
41007563SPrasad.Singamsetty@Sun.COM }
410111748SShidokht.Yadegari@Sun.COM
410211748SShidokht.Yadegari@Sun.COM /*
410311748SShidokht.Yadegari@Sun.COM * This routine implements the DKIOCGETEFI ioctl. This ioctl is currently
410411748SShidokht.Yadegari@Sun.COM * used to read the GPT Partition Table Header (primary/backup), the GUID
410511748SShidokht.Yadegari@Sun.COM * partition Entry Array (primary/backup), and the MBR.
410611748SShidokht.Yadegari@Sun.COM */
4107786Slclee static int
41083525Sshidokht cmlb_dkio_get_efi(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie)
4109786Slclee {
4110786Slclee dk_efi_t user_efi;
4111786Slclee int rval = 0;
4112786Slclee void *buffer;
41133525Sshidokht diskaddr_t tgt_lba;
4114786Slclee
4115786Slclee if (ddi_copyin(arg, &user_efi, sizeof (dk_efi_t), flag))
4116786Slclee return (EFAULT);
4117786Slclee
4118786Slclee user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64;
4119786Slclee
4120*11896SShidokht.Yadegari@Sun.COM if (user_efi.dki_length == 0 ||
4121*11896SShidokht.Yadegari@Sun.COM user_efi.dki_length > cmlb_tg_max_efi_xfer)
412211748SShidokht.Yadegari@Sun.COM return (EINVAL);
412311748SShidokht.Yadegari@Sun.COM
41243525Sshidokht tgt_lba = user_efi.dki_lba;
41253525Sshidokht
41263525Sshidokht mutex_enter(CMLB_MUTEX(cl));
41273525Sshidokht if ((cmlb_check_update_blockcount(cl, tg_cookie) != 0) ||
4128*11896SShidokht.Yadegari@Sun.COM (cl->cl_tgt_blocksize == 0) ||
4129*11896SShidokht.Yadegari@Sun.COM (user_efi.dki_length % cl->cl_sys_blocksize)) {
41303525Sshidokht mutex_exit(CMLB_MUTEX(cl));
41313525Sshidokht return (EINVAL);
41323525Sshidokht }
41333525Sshidokht if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize)
41343525Sshidokht tgt_lba = tgt_lba * cl->cl_tgt_blocksize /
41353525Sshidokht cl->cl_sys_blocksize;
41363525Sshidokht mutex_exit(CMLB_MUTEX(cl));
41373525Sshidokht
4138786Slclee buffer = kmem_alloc(user_efi.dki_length, KM_SLEEP);
41393525Sshidokht rval = DK_TG_READ(cl, buffer, tgt_lba, user_efi.dki_length, tg_cookie);
4140786Slclee if (rval == 0 && ddi_copyout(buffer, user_efi.dki_data,
4141786Slclee user_efi.dki_length, flag) != 0)
4142786Slclee rval = EFAULT;
4143786Slclee
4144786Slclee kmem_free(buffer, user_efi.dki_length);
4145786Slclee return (rval);
4146786Slclee }
4147786Slclee
41483525Sshidokht #if defined(_SUNOS_VTOC_8)
4149786Slclee /*
4150786Slclee * Function: cmlb_build_user_vtoc
4151786Slclee *
4152786Slclee * Description: This routine populates a pass by reference variable with the
4153786Slclee * current volume table of contents.
4154786Slclee *
41553525Sshidokht * Arguments: cl - driver soft state (unit) structure
4156786Slclee * user_vtoc - pointer to vtoc structure to be populated
4157786Slclee */
4158786Slclee static void
41593525Sshidokht cmlb_build_user_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc)
4160786Slclee {
4161786Slclee struct dk_map2 *lpart;
4162786Slclee struct dk_map *lmap;
4163786Slclee struct partition *vpart;
41647563SPrasad.Singamsetty@Sun.COM uint32_t nblks;
4165786Slclee int i;
4166786Slclee
41673525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl)));
4168786Slclee
4169786Slclee /*
4170786Slclee * Return vtoc structure fields in the provided VTOC area, addressed
4171786Slclee * by *vtoc.
4172786Slclee */
4173786Slclee bzero(user_vtoc, sizeof (struct vtoc));
41743525Sshidokht user_vtoc->v_bootinfo[0] = cl->cl_vtoc.v_bootinfo[0];
41753525Sshidokht user_vtoc->v_bootinfo[1] = cl->cl_vtoc.v_bootinfo[1];
41763525Sshidokht user_vtoc->v_bootinfo[2] = cl->cl_vtoc.v_bootinfo[2];
4177786Slclee user_vtoc->v_sanity = VTOC_SANE;
41783525Sshidokht user_vtoc->v_version = cl->cl_vtoc.v_version;
41793525Sshidokht bcopy(cl->cl_vtoc.v_volume, user_vtoc->v_volume, LEN_DKL_VVOL);
41803525Sshidokht user_vtoc->v_sectorsz = cl->cl_sys_blocksize;
41813525Sshidokht user_vtoc->v_nparts = cl->cl_vtoc.v_nparts;
4182786Slclee
4183786Slclee for (i = 0; i < 10; i++)
41843525Sshidokht user_vtoc->v_reserved[i] = cl->cl_vtoc.v_reserved[i];
4185786Slclee
4186786Slclee /*
4187786Slclee * Convert partitioning information.
4188786Slclee *
4189786Slclee * Note the conversion from starting cylinder number
4190786Slclee * to starting sector number.
4191786Slclee */
41923525Sshidokht lmap = cl->cl_map;
41933525Sshidokht lpart = (struct dk_map2 *)cl->cl_vtoc.v_part;
4194786Slclee vpart = user_vtoc->v_part;
4195786Slclee
41963525Sshidokht nblks = cl->cl_g.dkg_nsect * cl->cl_g.dkg_nhead;
4197786Slclee
4198786Slclee for (i = 0; i < V_NUMPAR; i++) {
4199786Slclee vpart->p_tag = lpart->p_tag;
4200786Slclee vpart->p_flag = lpart->p_flag;
4201786Slclee vpart->p_start = lmap->dkl_cylno * nblks;
4202786Slclee vpart->p_size = lmap->dkl_nblk;
4203786Slclee lmap++;
4204786Slclee lpart++;
4205786Slclee vpart++;
4206786Slclee
4207786Slclee /* (4364927) */
42083525Sshidokht user_vtoc->timestamp[i] = (time_t)cl->cl_vtoc.v_timestamp[i];
4209786Slclee }
4210786Slclee
42113525Sshidokht bcopy(cl->cl_asciilabel, user_vtoc->v_asciilabel, LEN_DKL_ASCII);
4212786Slclee }
42133525Sshidokht #endif
4214786Slclee
4215786Slclee static int
42163525Sshidokht cmlb_dkio_partition(struct cmlb_lun *cl, caddr_t arg, int flag,
42173525Sshidokht void *tg_cookie)
4218786Slclee {
4219786Slclee struct partition64 p64;
4220786Slclee int rval = 0;
4221786Slclee uint_t nparts;
4222786Slclee efi_gpe_t *partitions;
4223786Slclee efi_gpt_t *buffer;
4224786Slclee diskaddr_t gpe_lba;
422511536SSharath.Srinivasan@Sun.COM int n_gpe_per_blk = 0;
4226786Slclee
4227786Slclee if (ddi_copyin((const void *)arg, &p64,
4228786Slclee sizeof (struct partition64), flag)) {
4229786Slclee return (EFAULT);
4230786Slclee }
4231786Slclee
423211536SSharath.Srinivasan@Sun.COM buffer = kmem_alloc(cl->cl_sys_blocksize, KM_SLEEP);
42339889SLarry.Liu@Sun.COM rval = DK_TG_READ(cl, buffer, 1, cl->cl_sys_blocksize, tg_cookie);
4234786Slclee if (rval != 0)
4235786Slclee goto done_error;
4236786Slclee
4237786Slclee cmlb_swap_efi_gpt(buffer);
4238786Slclee
4239786Slclee if ((rval = cmlb_validate_efi(buffer)) != 0)
4240786Slclee goto done_error;
4241786Slclee
4242786Slclee nparts = buffer->efi_gpt_NumberOfPartitionEntries;
4243786Slclee gpe_lba = buffer->efi_gpt_PartitionEntryLBA;
424411536SSharath.Srinivasan@Sun.COM if (p64.p_partno >= nparts) {
4245786Slclee /* couldn't find it */
4246786Slclee rval = ESRCH;
4247786Slclee goto done_error;
4248786Slclee }
4249786Slclee /*
425011536SSharath.Srinivasan@Sun.COM * Read the block that contains the requested GPE.
4251786Slclee */
425211536SSharath.Srinivasan@Sun.COM n_gpe_per_blk = cl->cl_sys_blocksize / sizeof (efi_gpe_t);
425311536SSharath.Srinivasan@Sun.COM gpe_lba += p64.p_partno / n_gpe_per_blk;
425411536SSharath.Srinivasan@Sun.COM rval = DK_TG_READ(cl, buffer, gpe_lba, cl->cl_sys_blocksize, tg_cookie);
4255786Slclee
4256786Slclee if (rval) {
4257786Slclee goto done_error;
4258786Slclee }
4259786Slclee partitions = (efi_gpe_t *)buffer;
426011536SSharath.Srinivasan@Sun.COM partitions += p64.p_partno % n_gpe_per_blk;
426111647SSharath.Srinivasan@Sun.COM
426211647SSharath.Srinivasan@Sun.COM /* Byte swap only the requested GPE */
426311647SSharath.Srinivasan@Sun.COM cmlb_swap_efi_gpe(1, partitions);
426411647SSharath.Srinivasan@Sun.COM
4265786Slclee bcopy(&partitions->efi_gpe_PartitionTypeGUID, &p64.p_type,
4266786Slclee sizeof (struct uuid));
4267786Slclee p64.p_start = partitions->efi_gpe_StartingLBA;
4268786Slclee p64.p_size = partitions->efi_gpe_EndingLBA -
42693525Sshidokht p64.p_start + 1;
4270786Slclee
4271786Slclee if (ddi_copyout(&p64, (void *)arg, sizeof (struct partition64), flag))
4272786Slclee rval = EFAULT;
4273786Slclee
4274786Slclee done_error:
427511536SSharath.Srinivasan@Sun.COM kmem_free(buffer, cl->cl_sys_blocksize);
4276786Slclee return (rval);
4277786Slclee }
4278786Slclee
4279786Slclee
4280786Slclee /*
4281786Slclee * Function: cmlb_dkio_set_vtoc
4282786Slclee *
4283786Slclee * Description: This routine is the driver entry point for handling user
4284786Slclee * requests to set the current volume table of contents
4285786Slclee * (DKIOCSVTOC).
4286786Slclee *
42873525Sshidokht * Arguments:
42883525Sshidokht * dev the device number
42893525Sshidokht * arg pointer to user provided vtoc structure used to set the
4290786Slclee * current vtoc.
42913525Sshidokht *
42923525Sshidokht * flag this argument is a pass through to ddi_copyxxx()
42933525Sshidokht * directly from the mode argument of ioctl().
42943525Sshidokht *
42953525Sshidokht * tg_cookie cookie from target driver to be passed back to target
42963525Sshidokht * driver when we call back to it through tg_ops.
4297786Slclee *
4298786Slclee * Return Code: 0
4299786Slclee * EFAULT
4300786Slclee * ENXIO
4301786Slclee * EINVAL
4302786Slclee * ENOTSUP
4303786Slclee */
4304786Slclee static int
43053525Sshidokht cmlb_dkio_set_vtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag,
43063525Sshidokht void *tg_cookie)
4307786Slclee {
4308786Slclee struct vtoc user_vtoc;
4309786Slclee int rval = 0;
43106318Sedp boolean_t internal;
43116318Sedp
43128863SEdward.Pilatowicz@Sun.COM internal = VOID2BOOLEAN(
43138863SEdward.Pilatowicz@Sun.COM (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0);
4314786Slclee
4315786Slclee #ifdef _MULTI_DATAMODEL
4316786Slclee switch (ddi_model_convert_from(flag & FMODELS)) {
4317786Slclee case DDI_MODEL_ILP32: {
4318786Slclee struct vtoc32 user_vtoc32;
4319786Slclee
4320786Slclee if (ddi_copyin((const void *)arg, &user_vtoc32,
4321786Slclee sizeof (struct vtoc32), flag)) {
4322786Slclee return (EFAULT);
4323786Slclee }
4324786Slclee vtoc32tovtoc(user_vtoc32, user_vtoc);
4325786Slclee break;
4326786Slclee }
4327786Slclee
4328786Slclee case DDI_MODEL_NONE:
4329786Slclee if (ddi_copyin((const void *)arg, &user_vtoc,
4330786Slclee sizeof (struct vtoc), flag)) {
4331786Slclee return (EFAULT);
4332786Slclee }
4333786Slclee break;
4334786Slclee }
4335786Slclee #else /* ! _MULTI_DATAMODEL */
4336786Slclee if (ddi_copyin((const void *)arg, &user_vtoc,
4337786Slclee sizeof (struct vtoc), flag)) {
4338786Slclee return (EFAULT);
4339786Slclee }
4340786Slclee #endif /* _MULTI_DATAMODEL */
4341786Slclee
43423525Sshidokht mutex_enter(CMLB_MUTEX(cl));
43437563SPrasad.Singamsetty@Sun.COM
43447563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) {
43453525Sshidokht mutex_exit(CMLB_MUTEX(cl));
43467563SPrasad.Singamsetty@Sun.COM return (EOVERFLOW);
4347786Slclee }
43483525Sshidokht
43493525Sshidokht #if defined(__i386) || defined(__amd64)
43503525Sshidokht if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) {
43513525Sshidokht mutex_exit(CMLB_MUTEX(cl));
43523525Sshidokht return (EINVAL);
43533525Sshidokht }
43543525Sshidokht #endif
43553525Sshidokht
43563525Sshidokht if (cl->cl_g.dkg_ncyl == 0) {
43573525Sshidokht mutex_exit(CMLB_MUTEX(cl));
4358786Slclee return (EINVAL);
4359786Slclee }
4360786Slclee
43613525Sshidokht mutex_exit(CMLB_MUTEX(cl));
43623525Sshidokht cmlb_clear_efi(cl, tg_cookie);
43633525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd");
43643525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd,raw");
43658570SSriram.Popuri@sun.com
43668570SSriram.Popuri@sun.com /*
43678570SSriram.Popuri@sun.com * cmlb_dkio_set_vtoc creates duplicate minor nodes when
43688570SSriram.Popuri@sun.com * relabeling an SMI disk. To avoid that we remove them
43698570SSriram.Popuri@sun.com * before creating.
43708570SSriram.Popuri@sun.com * It should be OK to remove a non-existed minor node.
43718570SSriram.Popuri@sun.com */
43728570SSriram.Popuri@sun.com ddi_remove_minor_node(CMLB_DEVINFO(cl), "h");
43738570SSriram.Popuri@sun.com ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw");
43748570SSriram.Popuri@sun.com
43756318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h",
4376786Slclee S_IFBLK, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE,
43776318Sedp cl->cl_node_type, NULL, internal);
43786318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h,raw",
4379786Slclee S_IFCHR, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE,
43806318Sedp cl->cl_node_type, NULL, internal);
43813525Sshidokht mutex_enter(CMLB_MUTEX(cl));
43823525Sshidokht
43833525Sshidokht if ((rval = cmlb_build_label_vtoc(cl, &user_vtoc)) == 0) {
43843525Sshidokht if ((rval = cmlb_write_label(cl, tg_cookie)) == 0) {
43858863SEdward.Pilatowicz@Sun.COM if (cmlb_validate_geometry(cl,
43868863SEdward.Pilatowicz@Sun.COM B_TRUE, 0, tg_cookie) != 0) {
43873525Sshidokht cmlb_dbg(CMLB_ERROR, cl,
4388786Slclee "cmlb_dkio_set_vtoc: "
4389786Slclee "Failed validate geometry\n");
4390786Slclee }
43917563SPrasad.Singamsetty@Sun.COM cl->cl_msglog_flag |= CMLB_ALLOW_2TB_WARN;
4392786Slclee }
4393786Slclee }
43943525Sshidokht mutex_exit(CMLB_MUTEX(cl));
4395786Slclee return (rval);
4396786Slclee }
4397786Slclee
43987563SPrasad.Singamsetty@Sun.COM /*
43997563SPrasad.Singamsetty@Sun.COM * Function: cmlb_dkio_set_extvtoc
44007563SPrasad.Singamsetty@Sun.COM */
44017563SPrasad.Singamsetty@Sun.COM static int
44027563SPrasad.Singamsetty@Sun.COM cmlb_dkio_set_extvtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag,
44037563SPrasad.Singamsetty@Sun.COM void *tg_cookie)
44047563SPrasad.Singamsetty@Sun.COM {
44057563SPrasad.Singamsetty@Sun.COM int rval = 0;
44067563SPrasad.Singamsetty@Sun.COM struct vtoc user_vtoc;
44078749SShidokht.Yadegari@Sun.COM boolean_t internal;
44088749SShidokht.Yadegari@Sun.COM
44097563SPrasad.Singamsetty@Sun.COM
44107563SPrasad.Singamsetty@Sun.COM /*
44117563SPrasad.Singamsetty@Sun.COM * Checking callers data model does not make much sense here
44127563SPrasad.Singamsetty@Sun.COM * since extvtoc will always be equivalent to 64bit vtoc.
44137563SPrasad.Singamsetty@Sun.COM * What is important is whether the kernel is in 32 or 64 bit
44147563SPrasad.Singamsetty@Sun.COM */
44157563SPrasad.Singamsetty@Sun.COM
44167563SPrasad.Singamsetty@Sun.COM #ifdef _LP64
44177563SPrasad.Singamsetty@Sun.COM if (ddi_copyin((const void *)arg, &user_vtoc,
44187563SPrasad.Singamsetty@Sun.COM sizeof (struct extvtoc), flag)) {
44197563SPrasad.Singamsetty@Sun.COM return (EFAULT);
44207563SPrasad.Singamsetty@Sun.COM }
44217563SPrasad.Singamsetty@Sun.COM #else
44227563SPrasad.Singamsetty@Sun.COM struct extvtoc user_extvtoc;
44237563SPrasad.Singamsetty@Sun.COM if (ddi_copyin((const void *)arg, &user_extvtoc,
44247563SPrasad.Singamsetty@Sun.COM sizeof (struct extvtoc), flag)) {
44257563SPrasad.Singamsetty@Sun.COM return (EFAULT);
44267563SPrasad.Singamsetty@Sun.COM }
44277563SPrasad.Singamsetty@Sun.COM
44287563SPrasad.Singamsetty@Sun.COM vtoctovtoc32(user_extvtoc, user_vtoc);
44297563SPrasad.Singamsetty@Sun.COM #endif
44307563SPrasad.Singamsetty@Sun.COM
44318863SEdward.Pilatowicz@Sun.COM internal = VOID2BOOLEAN(
44328863SEdward.Pilatowicz@Sun.COM (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0);
44337563SPrasad.Singamsetty@Sun.COM mutex_enter(CMLB_MUTEX(cl));
44347563SPrasad.Singamsetty@Sun.COM #if defined(__i386) || defined(__amd64)
44357563SPrasad.Singamsetty@Sun.COM if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) {
44367563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl));
44377563SPrasad.Singamsetty@Sun.COM return (EINVAL);
44387563SPrasad.Singamsetty@Sun.COM }
44397563SPrasad.Singamsetty@Sun.COM #endif
44407563SPrasad.Singamsetty@Sun.COM
44417563SPrasad.Singamsetty@Sun.COM if (cl->cl_g.dkg_ncyl == 0) {
44427563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl));
44437563SPrasad.Singamsetty@Sun.COM return (EINVAL);
44447563SPrasad.Singamsetty@Sun.COM }
44457563SPrasad.Singamsetty@Sun.COM
44467563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl));
44477563SPrasad.Singamsetty@Sun.COM cmlb_clear_efi(cl, tg_cookie);
44487563SPrasad.Singamsetty@Sun.COM ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd");
44497563SPrasad.Singamsetty@Sun.COM ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd,raw");
445010511SSriram.Popuri@sun.com /*
445110511SSriram.Popuri@sun.com * cmlb_dkio_set_extvtoc creates duplicate minor nodes when
445210511SSriram.Popuri@sun.com * relabeling an SMI disk. To avoid that we remove them
445310511SSriram.Popuri@sun.com * before creating.
445410511SSriram.Popuri@sun.com * It should be OK to remove a non-existed minor node.
445510511SSriram.Popuri@sun.com */
445610511SSriram.Popuri@sun.com ddi_remove_minor_node(CMLB_DEVINFO(cl), "h");
445710511SSriram.Popuri@sun.com ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw");
445810511SSriram.Popuri@sun.com
44598749SShidokht.Yadegari@Sun.COM (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h",
44607563SPrasad.Singamsetty@Sun.COM S_IFBLK, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE,
44618749SShidokht.Yadegari@Sun.COM cl->cl_node_type, NULL, internal);
44628749SShidokht.Yadegari@Sun.COM (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h,raw",
44637563SPrasad.Singamsetty@Sun.COM S_IFCHR, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE,
44648749SShidokht.Yadegari@Sun.COM cl->cl_node_type, NULL, internal);
44658749SShidokht.Yadegari@Sun.COM
44667563SPrasad.Singamsetty@Sun.COM mutex_enter(CMLB_MUTEX(cl));
44677563SPrasad.Singamsetty@Sun.COM
44687563SPrasad.Singamsetty@Sun.COM if ((rval = cmlb_build_label_vtoc(cl, &user_vtoc)) == 0) {
44697563SPrasad.Singamsetty@Sun.COM if ((rval = cmlb_write_label(cl, tg_cookie)) == 0) {
44708863SEdward.Pilatowicz@Sun.COM if (cmlb_validate_geometry(cl,
44718863SEdward.Pilatowicz@Sun.COM B_TRUE, 0, tg_cookie) != 0) {
44727563SPrasad.Singamsetty@Sun.COM cmlb_dbg(CMLB_ERROR, cl,
44737563SPrasad.Singamsetty@Sun.COM "cmlb_dkio_set_vtoc: "
44747563SPrasad.Singamsetty@Sun.COM "Failed validate geometry\n");
44757563SPrasad.Singamsetty@Sun.COM }
44767563SPrasad.Singamsetty@Sun.COM }
44777563SPrasad.Singamsetty@Sun.COM }
44787563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl));
44797563SPrasad.Singamsetty@Sun.COM return (rval);
44807563SPrasad.Singamsetty@Sun.COM }
4481786Slclee
4482786Slclee /*
4483786Slclee * Function: cmlb_build_label_vtoc
4484786Slclee *
4485786Slclee * Description: This routine updates the driver soft state current volume table
4486786Slclee * of contents based on a user specified vtoc.
4487786Slclee *
44883525Sshidokht * Arguments: cl - driver soft state (unit) structure
4489786Slclee * user_vtoc - pointer to vtoc structure specifying vtoc to be used
4490786Slclee * to update the driver soft state.
4491786Slclee *
4492786Slclee * Return Code: 0
4493786Slclee * EINVAL
4494786Slclee */
4495786Slclee static int
44963525Sshidokht cmlb_build_label_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc)
4497786Slclee {
4498786Slclee struct dk_map *lmap;
4499786Slclee struct partition *vpart;
45007563SPrasad.Singamsetty@Sun.COM uint_t nblks;
4501786Slclee #if defined(_SUNOS_VTOC_8)
4502786Slclee int ncyl;
4503786Slclee struct dk_map2 *lpart;
4504786Slclee #endif /* defined(_SUNOS_VTOC_8) */
4505786Slclee int i;
4506786Slclee
45073525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl)));
4508786Slclee
4509786Slclee /* Sanity-check the vtoc */
4510786Slclee if (user_vtoc->v_sanity != VTOC_SANE ||
45113525Sshidokht user_vtoc->v_sectorsz != cl->cl_sys_blocksize ||
4512786Slclee user_vtoc->v_nparts != V_NUMPAR) {
45133525Sshidokht cmlb_dbg(CMLB_INFO, cl,
4514786Slclee "cmlb_build_label_vtoc: vtoc not valid\n");
4515786Slclee return (EINVAL);
4516786Slclee }
4517786Slclee
45183525Sshidokht nblks = cl->cl_g.dkg_nsect * cl->cl_g.dkg_nhead;
4519786Slclee if (nblks == 0) {
45203525Sshidokht cmlb_dbg(CMLB_INFO, cl,
4521786Slclee "cmlb_build_label_vtoc: geom nblks is 0\n");
4522786Slclee return (EINVAL);
4523786Slclee }
4524786Slclee
4525786Slclee #if defined(_SUNOS_VTOC_8)
4526786Slclee vpart = user_vtoc->v_part;
4527786Slclee for (i = 0; i < V_NUMPAR; i++) {
45287563SPrasad.Singamsetty@Sun.COM if (((unsigned)vpart->p_start % nblks) != 0) {
45293525Sshidokht cmlb_dbg(CMLB_INFO, cl,
4530786Slclee "cmlb_build_label_vtoc: p_start not multiply of"
4531786Slclee "nblks part %d p_start %d nblks %d\n", i,
4532786Slclee vpart->p_start, nblks);
4533786Slclee return (EINVAL);
4534786Slclee }
45357563SPrasad.Singamsetty@Sun.COM ncyl = (unsigned)vpart->p_start / nblks;
45367563SPrasad.Singamsetty@Sun.COM ncyl += (unsigned)vpart->p_size / nblks;
45377563SPrasad.Singamsetty@Sun.COM if (((unsigned)vpart->p_size % nblks) != 0) {
4538786Slclee ncyl++;
4539786Slclee }
45403525Sshidokht if (ncyl > (int)cl->cl_g.dkg_ncyl) {
45413525Sshidokht cmlb_dbg(CMLB_INFO, cl,
4542786Slclee "cmlb_build_label_vtoc: ncyl %d > dkg_ncyl %d"
4543786Slclee "p_size %ld p_start %ld nblks %d part number %d"
4544786Slclee "tag %d\n",
45453525Sshidokht ncyl, cl->cl_g.dkg_ncyl, vpart->p_size,
4546786Slclee vpart->p_start, nblks,
4547786Slclee i, vpart->p_tag);
4548786Slclee
4549786Slclee return (EINVAL);
4550786Slclee }
4551786Slclee vpart++;
4552786Slclee }
4553786Slclee #endif /* defined(_SUNOS_VTOC_8) */
4554786Slclee
4555786Slclee /* Put appropriate vtoc structure fields into the disk label */
4556786Slclee #if defined(_SUNOS_VTOC_16)
4557786Slclee /*
4558786Slclee * The vtoc is always a 32bit data structure to maintain the
4559786Slclee * on-disk format. Convert "in place" instead of doing bcopy.
4560786Slclee */
45613525Sshidokht vtoctovtoc32((*user_vtoc), (*((struct vtoc32 *)&(cl->cl_vtoc))));
4562786Slclee
4563786Slclee /*
4564786Slclee * in the 16-slice vtoc, starting sectors are expressed in
4565786Slclee * numbers *relative* to the start of the Solaris fdisk partition.
4566786Slclee */
45673525Sshidokht lmap = cl->cl_map;
4568786Slclee vpart = user_vtoc->v_part;
4569786Slclee
4570786Slclee for (i = 0; i < (int)user_vtoc->v_nparts; i++, lmap++, vpart++) {
45717563SPrasad.Singamsetty@Sun.COM lmap->dkl_cylno = (unsigned)vpart->p_start / nblks;
45727563SPrasad.Singamsetty@Sun.COM lmap->dkl_nblk = (unsigned)vpart->p_size;
4573786Slclee }
4574786Slclee
4575786Slclee #elif defined(_SUNOS_VTOC_8)
4576786Slclee
45773525Sshidokht cl->cl_vtoc.v_bootinfo[0] = (uint32_t)user_vtoc->v_bootinfo[0];
45783525Sshidokht cl->cl_vtoc.v_bootinfo[1] = (uint32_t)user_vtoc->v_bootinfo[1];
45793525Sshidokht cl->cl_vtoc.v_bootinfo[2] = (uint32_t)user_vtoc->v_bootinfo[2];
45803525Sshidokht
45813525Sshidokht cl->cl_vtoc.v_sanity = (uint32_t)user_vtoc->v_sanity;
45823525Sshidokht cl->cl_vtoc.v_version = (uint32_t)user_vtoc->v_version;
45833525Sshidokht
45843525Sshidokht bcopy(user_vtoc->v_volume, cl->cl_vtoc.v_volume, LEN_DKL_VVOL);
45853525Sshidokht
45863525Sshidokht cl->cl_vtoc.v_nparts = user_vtoc->v_nparts;
4587786Slclee
4588786Slclee for (i = 0; i < 10; i++)
45893525Sshidokht cl->cl_vtoc.v_reserved[i] = user_vtoc->v_reserved[i];
4590786Slclee
4591786Slclee /*
4592786Slclee * Note the conversion from starting sector number
4593786Slclee * to starting cylinder number.
4594786Slclee * Return error if division results in a remainder.
4595786Slclee */
45963525Sshidokht lmap = cl->cl_map;
45973525Sshidokht lpart = cl->cl_vtoc.v_part;
4598786Slclee vpart = user_vtoc->v_part;
4599786Slclee
4600786Slclee for (i = 0; i < (int)user_vtoc->v_nparts; i++) {
4601786Slclee lpart->p_tag = vpart->p_tag;
4602786Slclee lpart->p_flag = vpart->p_flag;
46037563SPrasad.Singamsetty@Sun.COM lmap->dkl_cylno = (unsigned)vpart->p_start / nblks;
46047563SPrasad.Singamsetty@Sun.COM lmap->dkl_nblk = (unsigned)vpart->p_size;
4605786Slclee
4606786Slclee lmap++;
4607786Slclee lpart++;
4608786Slclee vpart++;
4609786Slclee
4610786Slclee /* (4387723) */
4611786Slclee #ifdef _LP64
4612786Slclee if (user_vtoc->timestamp[i] > TIME32_MAX) {
46133525Sshidokht cl->cl_vtoc.v_timestamp[i] = TIME32_MAX;
4614786Slclee } else {
46153525Sshidokht cl->cl_vtoc.v_timestamp[i] = user_vtoc->timestamp[i];
4616786Slclee }
4617786Slclee #else
46183525Sshidokht cl->cl_vtoc.v_timestamp[i] = user_vtoc->timestamp[i];
4619786Slclee #endif
4620786Slclee }
4621786Slclee
46223525Sshidokht bcopy(user_vtoc->v_asciilabel, cl->cl_asciilabel, LEN_DKL_ASCII);
4623786Slclee #else
4624786Slclee #error "No VTOC format defined."
4625786Slclee #endif
4626786Slclee return (0);
4627786Slclee }
4628786Slclee
4629786Slclee /*
4630786Slclee * Function: cmlb_clear_efi
4631786Slclee *
4632786Slclee * Description: This routine clears all EFI labels.
4633786Slclee *
46343525Sshidokht * Arguments:
46353525Sshidokht * cl driver soft state (unit) structure
4636786Slclee *
46373525Sshidokht * tg_cookie cookie from target driver to be passed back to target
46383525Sshidokht * driver when we call back to it through tg_ops.
4639786Slclee * Return Code: void
4640786Slclee */
4641786Slclee static void
46423525Sshidokht cmlb_clear_efi(struct cmlb_lun *cl, void *tg_cookie)
4643786Slclee {
4644786Slclee efi_gpt_t *gpt;
4645786Slclee diskaddr_t cap;
4646786Slclee int rval;
4647786Slclee
46483525Sshidokht ASSERT(!mutex_owned(CMLB_MUTEX(cl)));
46493525Sshidokht
46503525Sshidokht mutex_enter(CMLB_MUTEX(cl));
46513525Sshidokht cl->cl_reserved = -1;
46523525Sshidokht mutex_exit(CMLB_MUTEX(cl));
4653786Slclee
46549889SLarry.Liu@Sun.COM gpt = kmem_alloc(cl->cl_sys_blocksize, KM_SLEEP);
46559889SLarry.Liu@Sun.COM
46569889SLarry.Liu@Sun.COM if (DK_TG_READ(cl, gpt, 1, cl->cl_sys_blocksize, tg_cookie) != 0) {
4657786Slclee goto done;
4658786Slclee }
4659786Slclee
4660786Slclee cmlb_swap_efi_gpt(gpt);
4661786Slclee rval = cmlb_validate_efi(gpt);
4662786Slclee if (rval == 0) {
4663786Slclee /* clear primary */
4664786Slclee bzero(gpt, sizeof (efi_gpt_t));
46659889SLarry.Liu@Sun.COM if (rval = DK_TG_WRITE(cl, gpt, 1, cl->cl_sys_blocksize,
46669889SLarry.Liu@Sun.COM tg_cookie)) {
46673525Sshidokht cmlb_dbg(CMLB_INFO, cl,
46683525Sshidokht "cmlb_clear_efi: clear primary label failed\n");
4669786Slclee }
4670786Slclee }
4671786Slclee /* the backup */
46723525Sshidokht rval = DK_TG_GETCAP(cl, &cap, tg_cookie);
4673786Slclee if (rval) {
4674786Slclee goto done;
4675786Slclee }
4676786Slclee
46779889SLarry.Liu@Sun.COM if ((rval = DK_TG_READ(cl, gpt, cap - 1, cl->cl_sys_blocksize,
46789889SLarry.Liu@Sun.COM tg_cookie)) != 0) {
4679786Slclee goto done;
4680786Slclee }
4681786Slclee cmlb_swap_efi_gpt(gpt);
4682786Slclee rval = cmlb_validate_efi(gpt);
4683786Slclee if (rval == 0) {
4684786Slclee /* clear backup */
46853525Sshidokht cmlb_dbg(CMLB_TRACE, cl,
4686786Slclee "cmlb_clear_efi clear backup@%lu\n", cap - 1);
4687786Slclee bzero(gpt, sizeof (efi_gpt_t));
46889889SLarry.Liu@Sun.COM if ((rval = DK_TG_WRITE(cl, gpt, cap - 1, cl->cl_sys_blocksize,
46893525Sshidokht tg_cookie))) {
46903525Sshidokht cmlb_dbg(CMLB_INFO, cl,
46913525Sshidokht "cmlb_clear_efi: clear backup label failed\n");
46923525Sshidokht }
46933525Sshidokht } else {
46943525Sshidokht /*
46953525Sshidokht * Refer to comments related to off-by-1 at the
46963525Sshidokht * header of this file
46973525Sshidokht */
46983525Sshidokht if ((rval = DK_TG_READ(cl, gpt, cap - 2,
46999889SLarry.Liu@Sun.COM cl->cl_sys_blocksize, tg_cookie)) != 0) {
47003525Sshidokht goto done;
47013525Sshidokht }
47023525Sshidokht cmlb_swap_efi_gpt(gpt);
47033525Sshidokht rval = cmlb_validate_efi(gpt);
47043525Sshidokht if (rval == 0) {
47053525Sshidokht /* clear legacy backup EFI label */
47063525Sshidokht cmlb_dbg(CMLB_TRACE, cl,
47073525Sshidokht "cmlb_clear_efi clear legacy backup@%lu\n",
47083525Sshidokht cap - 2);
47093525Sshidokht bzero(gpt, sizeof (efi_gpt_t));
47103525Sshidokht if ((rval = DK_TG_WRITE(cl, gpt, cap - 2,
47119889SLarry.Liu@Sun.COM cl->cl_sys_blocksize, tg_cookie))) {
47123525Sshidokht cmlb_dbg(CMLB_INFO, cl,
47133525Sshidokht "cmlb_clear_efi: clear legacy backup label "
47143525Sshidokht "failed\n");
47153525Sshidokht }
4716786Slclee }
4717786Slclee }
4718786Slclee
4719786Slclee done:
47209889SLarry.Liu@Sun.COM kmem_free(gpt, cl->cl_sys_blocksize);
4721786Slclee }
4722786Slclee
4723786Slclee /*
4724786Slclee * Function: cmlb_set_vtoc
4725786Slclee *
4726786Slclee * Description: This routine writes data to the appropriate positions
4727786Slclee *
47283525Sshidokht * Arguments:
47293525Sshidokht * cl driver soft state (unit) structure
47303525Sshidokht *
47313525Sshidokht * dkl the data to be written
47323525Sshidokht *
47333525Sshidokht * tg_cookie cookie from target driver to be passed back to target
47343525Sshidokht * driver when we call back to it through tg_ops.
4735786Slclee *
4736786Slclee * Return: void
4737786Slclee */
4738786Slclee static int
47393525Sshidokht cmlb_set_vtoc(struct cmlb_lun *cl, struct dk_label *dkl, void *tg_cookie)
4740786Slclee {
4741786Slclee uint_t label_addr;
4742786Slclee int sec;
47437563SPrasad.Singamsetty@Sun.COM diskaddr_t blk;
4744786Slclee int head;
4745786Slclee int cyl;
4746786Slclee int rval;
4747786Slclee
4748786Slclee #if defined(__i386) || defined(__amd64)
47493525Sshidokht label_addr = cl->cl_solaris_offset + DK_LABEL_LOC;
4750786Slclee #else
4751786Slclee /* Write the primary label at block 0 of the solaris partition. */
4752786Slclee label_addr = 0;
4753786Slclee #endif
4754786Slclee
47553525Sshidokht rval = DK_TG_WRITE(cl, dkl, label_addr, cl->cl_sys_blocksize,
47563525Sshidokht tg_cookie);
4757786Slclee
4758786Slclee if (rval != 0) {
4759786Slclee return (rval);
4760786Slclee }
4761786Slclee
4762786Slclee /*
4763786Slclee * Calculate where the backup labels go. They are always on
4764786Slclee * the last alternate cylinder, but some older drives put them
4765786Slclee * on head 2 instead of the last head. They are always on the
4766786Slclee * first 5 odd sectors of the appropriate track.
4767786Slclee *
4768786Slclee * We have no choice at this point, but to believe that the
4769786Slclee * disk label is valid. Use the geometry of the disk
4770786Slclee * as described in the label.
4771786Slclee */
4772786Slclee cyl = dkl->dkl_ncyl + dkl->dkl_acyl - 1;
4773786Slclee head = dkl->dkl_nhead - 1;
4774786Slclee
4775786Slclee /*
4776786Slclee * Write and verify the backup labels. Make sure we don't try to
4777786Slclee * write past the last cylinder.
4778786Slclee */
4779786Slclee for (sec = 1; ((sec < 5 * 2 + 1) && (sec < dkl->dkl_nsect)); sec += 2) {
47807563SPrasad.Singamsetty@Sun.COM blk = (diskaddr_t)(
4781786Slclee (cyl * ((dkl->dkl_nhead * dkl->dkl_nsect) - dkl->dkl_apc)) +
4782786Slclee (head * dkl->dkl_nsect) + sec);
4783786Slclee #if defined(__i386) || defined(__amd64)
47843525Sshidokht blk += cl->cl_solaris_offset;
4785786Slclee #endif
47863525Sshidokht rval = DK_TG_WRITE(cl, dkl, blk, cl->cl_sys_blocksize,
47873525Sshidokht tg_cookie);
47883525Sshidokht cmlb_dbg(CMLB_INFO, cl,
47897563SPrasad.Singamsetty@Sun.COM "cmlb_set_vtoc: wrote backup label %llx\n", blk);
4790786Slclee if (rval != 0) {
4791786Slclee goto exit;
4792786Slclee }
4793786Slclee }
4794786Slclee exit:
4795786Slclee return (rval);
4796786Slclee }
4797786Slclee
4798786Slclee /*
4799786Slclee * Function: cmlb_clear_vtoc
4800786Slclee *
4801786Slclee * Description: This routine clears out the VTOC labels.
4802786Slclee *
48033525Sshidokht * Arguments:
48043525Sshidokht * cl driver soft state (unit) structure
48053525Sshidokht *
48063525Sshidokht * tg_cookie cookie from target driver to be passed back to target
48073525Sshidokht * driver when we call back to it through tg_ops.
4808786Slclee *
4809786Slclee * Return: void
4810786Slclee */
4811786Slclee static void
48123525Sshidokht cmlb_clear_vtoc(struct cmlb_lun *cl, void *tg_cookie)
4813786Slclee {
4814786Slclee struct dk_label *dkl;
4815786Slclee
48163525Sshidokht mutex_exit(CMLB_MUTEX(cl));
48179889SLarry.Liu@Sun.COM dkl = kmem_zalloc(cl->cl_sys_blocksize, KM_SLEEP);
48183525Sshidokht mutex_enter(CMLB_MUTEX(cl));
4819786Slclee /*
4820786Slclee * cmlb_set_vtoc uses these fields in order to figure out
4821786Slclee * where to overwrite the backup labels
4822786Slclee */
48233525Sshidokht dkl->dkl_apc = cl->cl_g.dkg_apc;
48243525Sshidokht dkl->dkl_ncyl = cl->cl_g.dkg_ncyl;
48253525Sshidokht dkl->dkl_acyl = cl->cl_g.dkg_acyl;
48263525Sshidokht dkl->dkl_nhead = cl->cl_g.dkg_nhead;
48273525Sshidokht dkl->dkl_nsect = cl->cl_g.dkg_nsect;
48283525Sshidokht mutex_exit(CMLB_MUTEX(cl));
48293525Sshidokht (void) cmlb_set_vtoc(cl, dkl, tg_cookie);
48309889SLarry.Liu@Sun.COM kmem_free(dkl, cl->cl_sys_blocksize);
4831786Slclee
48323525Sshidokht mutex_enter(CMLB_MUTEX(cl));
4833786Slclee }
4834786Slclee
4835786Slclee /*
4836786Slclee * Function: cmlb_write_label
4837786Slclee *
4838786Slclee * Description: This routine will validate and write the driver soft state vtoc
4839786Slclee * contents to the device.
4840786Slclee *
48413525Sshidokht * Arguments:
48423525Sshidokht * cl cmlb handle
48433525Sshidokht *
48443525Sshidokht * tg_cookie cookie from target driver to be passed back to target
48453525Sshidokht * driver when we call back to it through tg_ops.
48463525Sshidokht *
4847786Slclee *
4848786Slclee * Return Code: the code returned by cmlb_send_scsi_cmd()
4849786Slclee * 0
4850786Slclee * EINVAL
4851786Slclee * ENXIO
4852786Slclee * ENOMEM
4853786Slclee */
4854786Slclee static int
48553525Sshidokht cmlb_write_label(struct cmlb_lun *cl, void *tg_cookie)
4856786Slclee {
4857786Slclee struct dk_label *dkl;
4858786Slclee short sum;
4859786Slclee short *sp;
4860786Slclee int i;
4861786Slclee int rval;
4862786Slclee
48633525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl)));
48643525Sshidokht mutex_exit(CMLB_MUTEX(cl));
48659889SLarry.Liu@Sun.COM dkl = kmem_zalloc(cl->cl_sys_blocksize, KM_SLEEP);
48663525Sshidokht mutex_enter(CMLB_MUTEX(cl));
48673525Sshidokht
48683525Sshidokht bcopy(&cl->cl_vtoc, &dkl->dkl_vtoc, sizeof (struct dk_vtoc));
48693525Sshidokht dkl->dkl_rpm = cl->cl_g.dkg_rpm;
48703525Sshidokht dkl->dkl_pcyl = cl->cl_g.dkg_pcyl;
48713525Sshidokht dkl->dkl_apc = cl->cl_g.dkg_apc;
48723525Sshidokht dkl->dkl_intrlv = cl->cl_g.dkg_intrlv;
48733525Sshidokht dkl->dkl_ncyl = cl->cl_g.dkg_ncyl;
48743525Sshidokht dkl->dkl_acyl = cl->cl_g.dkg_acyl;
48753525Sshidokht dkl->dkl_nhead = cl->cl_g.dkg_nhead;
48763525Sshidokht dkl->dkl_nsect = cl->cl_g.dkg_nsect;
4877786Slclee
4878786Slclee #if defined(_SUNOS_VTOC_8)
48793525Sshidokht dkl->dkl_obs1 = cl->cl_g.dkg_obs1;
48803525Sshidokht dkl->dkl_obs2 = cl->cl_g.dkg_obs2;
48813525Sshidokht dkl->dkl_obs3 = cl->cl_g.dkg_obs3;
4882786Slclee for (i = 0; i < NDKMAP; i++) {
48833525Sshidokht dkl->dkl_map[i].dkl_cylno = cl->cl_map[i].dkl_cylno;
48843525Sshidokht dkl->dkl_map[i].dkl_nblk = cl->cl_map[i].dkl_nblk;
4885786Slclee }
48863525Sshidokht bcopy(cl->cl_asciilabel, dkl->dkl_asciilabel, LEN_DKL_ASCII);
4887786Slclee #elif defined(_SUNOS_VTOC_16)
48883525Sshidokht dkl->dkl_skew = cl->cl_dkg_skew;
4889786Slclee #else
4890786Slclee #error "No VTOC format defined."
4891786Slclee #endif
4892786Slclee
4893786Slclee dkl->dkl_magic = DKL_MAGIC;
48943525Sshidokht dkl->dkl_write_reinstruct = cl->cl_g.dkg_write_reinstruct;
48953525Sshidokht dkl->dkl_read_reinstruct = cl->cl_g.dkg_read_reinstruct;
4896786Slclee
4897786Slclee /* Construct checksum for the new disk label */
4898786Slclee sum = 0;
4899786Slclee sp = (short *)dkl;
4900786Slclee i = sizeof (struct dk_label) / sizeof (short);
4901786Slclee while (i--) {
4902786Slclee sum ^= *sp++;
4903786Slclee }
4904786Slclee dkl->dkl_cksum = sum;
4905786Slclee
49063525Sshidokht mutex_exit(CMLB_MUTEX(cl));
49073525Sshidokht
49083525Sshidokht rval = cmlb_set_vtoc(cl, dkl, tg_cookie);
4909786Slclee exit:
49109889SLarry.Liu@Sun.COM kmem_free(dkl, cl->cl_sys_blocksize);
49113525Sshidokht mutex_enter(CMLB_MUTEX(cl));
4912786Slclee return (rval);
4913786Slclee }
4914786Slclee
491511748SShidokht.Yadegari@Sun.COM /*
491611748SShidokht.Yadegari@Sun.COM * This routine implements the DKIOCSETEFI ioctl. This ioctl is currently
491711748SShidokht.Yadegari@Sun.COM * used to write (or clear) the GPT Partition Table header (primary/backup)
491811748SShidokht.Yadegari@Sun.COM * and GUID partition Entry Array (primary/backup). It is also used to write
491911748SShidokht.Yadegari@Sun.COM * the Protective MBR.
492011748SShidokht.Yadegari@Sun.COM */
4921786Slclee static int
49223525Sshidokht cmlb_dkio_set_efi(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag,
49233525Sshidokht void *tg_cookie)
4924786Slclee {
4925786Slclee dk_efi_t user_efi;
4926786Slclee int rval = 0;
4927786Slclee void *buffer;
49283525Sshidokht diskaddr_t tgt_lba;
49296318Sedp boolean_t internal;
4930786Slclee
4931786Slclee if (ddi_copyin(arg, &user_efi, sizeof (dk_efi_t), flag))
4932786Slclee return (EFAULT);
4933786Slclee
49348863SEdward.Pilatowicz@Sun.COM internal = VOID2BOOLEAN(
49358863SEdward.Pilatowicz@Sun.COM (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0);
49366318Sedp
4937786Slclee user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64;
4938786Slclee
4939*11896SShidokht.Yadegari@Sun.COM if (user_efi.dki_length == 0 ||
4940*11896SShidokht.Yadegari@Sun.COM user_efi.dki_length > cmlb_tg_max_efi_xfer)
494111748SShidokht.Yadegari@Sun.COM return (EINVAL);
494211748SShidokht.Yadegari@Sun.COM
4943*11896SShidokht.Yadegari@Sun.COM tgt_lba = user_efi.dki_lba;
4944*11896SShidokht.Yadegari@Sun.COM
4945*11896SShidokht.Yadegari@Sun.COM mutex_enter(CMLB_MUTEX(cl));
4946*11896SShidokht.Yadegari@Sun.COM if ((cmlb_check_update_blockcount(cl, tg_cookie) != 0) ||
4947*11896SShidokht.Yadegari@Sun.COM (cl->cl_tgt_blocksize == 0) ||
4948*11896SShidokht.Yadegari@Sun.COM (user_efi.dki_length % cl->cl_sys_blocksize)) {
4949*11896SShidokht.Yadegari@Sun.COM mutex_exit(CMLB_MUTEX(cl));
4950*11896SShidokht.Yadegari@Sun.COM return (EINVAL);
4951*11896SShidokht.Yadegari@Sun.COM }
4952*11896SShidokht.Yadegari@Sun.COM if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize)
4953*11896SShidokht.Yadegari@Sun.COM tgt_lba = tgt_lba *
4954*11896SShidokht.Yadegari@Sun.COM cl->cl_tgt_blocksize / cl->cl_sys_blocksize;
4955*11896SShidokht.Yadegari@Sun.COM mutex_exit(CMLB_MUTEX(cl));
4956*11896SShidokht.Yadegari@Sun.COM
4957786Slclee buffer = kmem_alloc(user_efi.dki_length, KM_SLEEP);
4958786Slclee if (ddi_copyin(user_efi.dki_data, buffer, user_efi.dki_length, flag)) {
4959786Slclee rval = EFAULT;
4960786Slclee } else {
4961786Slclee /*
4962786Slclee * let's clear the vtoc labels and clear the softstate
4963786Slclee * vtoc.
4964786Slclee */
49653525Sshidokht mutex_enter(CMLB_MUTEX(cl));
49663525Sshidokht if (cl->cl_vtoc.v_sanity == VTOC_SANE) {
49673525Sshidokht cmlb_dbg(CMLB_TRACE, cl,
49683525Sshidokht "cmlb_dkio_set_efi: CLEAR VTOC\n");
49697563SPrasad.Singamsetty@Sun.COM if (cl->cl_label_from_media == CMLB_LABEL_VTOC)
49703525Sshidokht cmlb_clear_vtoc(cl, tg_cookie);
49713525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc));
49723525Sshidokht mutex_exit(CMLB_MUTEX(cl));
49733525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "h");
49743525Sshidokht ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw");
49756318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd",
4976786Slclee S_IFBLK,
4977786Slclee (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE,
49786318Sedp cl->cl_node_type, NULL, internal);
49796318Sedp (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd,raw",
4980786Slclee S_IFCHR,
4981786Slclee (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE,
49826318Sedp cl->cl_node_type, NULL, internal);
4983786Slclee } else
49843525Sshidokht mutex_exit(CMLB_MUTEX(cl));
49853525Sshidokht
49863525Sshidokht rval = DK_TG_WRITE(cl, buffer, tgt_lba, user_efi.dki_length,
49873525Sshidokht tg_cookie);
49883525Sshidokht
4989786Slclee if (rval == 0) {
49903525Sshidokht mutex_enter(CMLB_MUTEX(cl));
49918863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE;
49923525Sshidokht mutex_exit(CMLB_MUTEX(cl));
4993786Slclee }
4994786Slclee }
4995786Slclee kmem_free(buffer, user_efi.dki_length);
4996786Slclee return (rval);
4997786Slclee }
4998786Slclee
4999786Slclee /*
5000786Slclee * Function: cmlb_dkio_get_mboot
5001786Slclee *
5002786Slclee * Description: This routine is the driver entry point for handling user
5003786Slclee * requests to get the current device mboot (DKIOCGMBOOT)
5004786Slclee *
5005786Slclee * Arguments:
50063525Sshidokht * arg pointer to user provided mboot structure specifying
5007786Slclee * the current mboot.
50083525Sshidokht *
50093525Sshidokht * flag this argument is a pass through to ddi_copyxxx()
50103525Sshidokht * directly from the mode argument of ioctl().
50113525Sshidokht *
50123525Sshidokht * tg_cookie cookie from target driver to be passed back to target
50133525Sshidokht * driver when we call back to it through tg_ops.
5014786Slclee *
5015786Slclee * Return Code: 0
5016786Slclee * EINVAL
5017786Slclee * EFAULT
5018786Slclee * ENXIO
5019786Slclee */
5020786Slclee static int
50213525Sshidokht cmlb_dkio_get_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie)
5022786Slclee {
5023786Slclee struct mboot *mboot;
5024786Slclee int rval;
5025786Slclee size_t buffer_size;
5026786Slclee
5027786Slclee
5028786Slclee #if defined(_SUNOS_VTOC_8)
50293525Sshidokht if ((!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) || (arg == NULL)) {
5030786Slclee #elif defined(_SUNOS_VTOC_16)
5031786Slclee if (arg == NULL) {
5032786Slclee #endif
5033786Slclee return (EINVAL);
5034786Slclee }
5035786Slclee
5036786Slclee /*
5037786Slclee * Read the mboot block, located at absolute block 0 on the target.
5038786Slclee */
50399889SLarry.Liu@Sun.COM buffer_size = cl->cl_sys_blocksize;
5040786Slclee
50413525Sshidokht cmlb_dbg(CMLB_TRACE, cl,
5042786Slclee "cmlb_dkio_get_mboot: allocation size: 0x%x\n", buffer_size);
5043786Slclee
5044786Slclee mboot = kmem_zalloc(buffer_size, KM_SLEEP);
50453525Sshidokht if ((rval = DK_TG_READ(cl, mboot, 0, buffer_size, tg_cookie)) == 0) {
5046786Slclee if (ddi_copyout(mboot, (void *)arg,
5047786Slclee sizeof (struct mboot), flag) != 0) {
5048786Slclee rval = EFAULT;
5049786Slclee }
5050786Slclee }
5051786Slclee kmem_free(mboot, buffer_size);
5052786Slclee return (rval);
5053786Slclee }
5054786Slclee
5055786Slclee
5056786Slclee /*
5057786Slclee * Function: cmlb_dkio_set_mboot
5058786Slclee *
5059786Slclee * Description: This routine is the driver entry point for handling user
5060786Slclee * requests to validate and set the device master boot
5061786Slclee * (DKIOCSMBOOT).
5062786Slclee *
5063786Slclee * Arguments:
50643525Sshidokht * arg pointer to user provided mboot structure used to set the
5065786Slclee * master boot.
50663525Sshidokht *
50673525Sshidokht * flag this argument is a pass through to ddi_copyxxx()
50683525Sshidokht * directly from the mode argument of ioctl().
50693525Sshidokht *
50703525Sshidokht * tg_cookie cookie from target driver to be passed back to target
50713525Sshidokht * driver when we call back to it through tg_ops.
5072786Slclee *
5073786Slclee * Return Code: 0
5074786Slclee * EINVAL
5075786Slclee * EFAULT
5076786Slclee * ENXIO
5077786Slclee */
5078786Slclee static int
50793525Sshidokht cmlb_dkio_set_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie)
5080786Slclee {
5081786Slclee struct mboot *mboot = NULL;
5082786Slclee int rval;
5083786Slclee ushort_t magic;
5084786Slclee
5085786Slclee
50863525Sshidokht ASSERT(!mutex_owned(CMLB_MUTEX(cl)));
5087786Slclee
5088786Slclee #if defined(_SUNOS_VTOC_8)
50893525Sshidokht if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) {
5090786Slclee return (EINVAL);
5091786Slclee }
5092786Slclee #endif
5093786Slclee
5094786Slclee if (arg == NULL) {
5095786Slclee return (EINVAL);
5096786Slclee }
5097786Slclee
50989889SLarry.Liu@Sun.COM mboot = kmem_zalloc(cl->cl_sys_blocksize, KM_SLEEP);
5099786Slclee
5100786Slclee if (ddi_copyin((const void *)arg, mboot,
51019889SLarry.Liu@Sun.COM cl->cl_sys_blocksize, flag) != 0) {
51029889SLarry.Liu@Sun.COM kmem_free(mboot, cl->cl_sys_blocksize);
5103786Slclee return (EFAULT);
5104786Slclee }
5105786Slclee
5106786Slclee /* Is this really a master boot record? */
5107786Slclee magic = LE_16(mboot->signature);
5108786Slclee if (magic != MBB_MAGIC) {
51099889SLarry.Liu@Sun.COM kmem_free(mboot, cl->cl_sys_blocksize);
5110786Slclee return (EINVAL);
5111786Slclee }
5112786Slclee
51133525Sshidokht rval = DK_TG_WRITE(cl, mboot, 0, cl->cl_sys_blocksize, tg_cookie);
51143525Sshidokht
51153525Sshidokht mutex_enter(CMLB_MUTEX(cl));
5116786Slclee #if defined(__i386) || defined(__amd64)
5117786Slclee if (rval == 0) {
5118786Slclee /*
5119786Slclee * mboot has been written successfully.
5120786Slclee * update the fdisk and vtoc tables in memory
5121786Slclee */
51223525Sshidokht rval = cmlb_update_fdisk_and_vtoc(cl, tg_cookie);
51238863SEdward.Pilatowicz@Sun.COM if ((!cl->cl_f_geometry_is_valid) || (rval != 0)) {
51243525Sshidokht mutex_exit(CMLB_MUTEX(cl));
51259889SLarry.Liu@Sun.COM kmem_free(mboot, cl->cl_sys_blocksize);
5126786Slclee return (rval);
5127786Slclee }
5128786Slclee }
51293525Sshidokht
51303525Sshidokht #ifdef __lock_lint
51313525Sshidokht cmlb_setup_default_geometry(cl, tg_cookie);
51323525Sshidokht #endif
51333525Sshidokht
5134786Slclee #else
5135786Slclee if (rval == 0) {
5136786Slclee /*
5137786Slclee * mboot has been written successfully.
5138786Slclee * set up the default geometry and VTOC
5139786Slclee */
51407563SPrasad.Singamsetty@Sun.COM if (cl->cl_blockcount <= CMLB_EXTVTOC_LIMIT)
51413525Sshidokht cmlb_setup_default_geometry(cl, tg_cookie);
5142786Slclee }
5143786Slclee #endif
51447563SPrasad.Singamsetty@Sun.COM cl->cl_msglog_flag |= CMLB_ALLOW_2TB_WARN;
51453525Sshidokht mutex_exit(CMLB_MUTEX(cl));
51469889SLarry.Liu@Sun.COM kmem_free(mboot, cl->cl_sys_blocksize);
5147786Slclee return (rval);
5148786Slclee }
5149786Slclee
5150786Slclee
515110021SSheshadri.Vasudevan@Sun.COM #if defined(__i386) || defined(__amd64)
515210021SSheshadri.Vasudevan@Sun.COM /*ARGSUSED*/
515310021SSheshadri.Vasudevan@Sun.COM static int
515410021SSheshadri.Vasudevan@Sun.COM cmlb_dkio_set_ext_part(struct cmlb_lun *cl, caddr_t arg, int flag,
515510021SSheshadri.Vasudevan@Sun.COM void *tg_cookie)
515610021SSheshadri.Vasudevan@Sun.COM {
515710021SSheshadri.Vasudevan@Sun.COM int fdisk_rval;
515810021SSheshadri.Vasudevan@Sun.COM diskaddr_t capacity;
515910021SSheshadri.Vasudevan@Sun.COM
516010021SSheshadri.Vasudevan@Sun.COM ASSERT(!mutex_owned(CMLB_MUTEX(cl)));
516110021SSheshadri.Vasudevan@Sun.COM
516210021SSheshadri.Vasudevan@Sun.COM mutex_enter(CMLB_MUTEX(cl));
516310021SSheshadri.Vasudevan@Sun.COM capacity = cl->cl_blockcount;
516410021SSheshadri.Vasudevan@Sun.COM fdisk_rval = cmlb_read_fdisk(cl, capacity, tg_cookie);
516510021SSheshadri.Vasudevan@Sun.COM if (fdisk_rval != 0) {
516610021SSheshadri.Vasudevan@Sun.COM mutex_exit(CMLB_MUTEX(cl));
516710021SSheshadri.Vasudevan@Sun.COM return (fdisk_rval);
516810021SSheshadri.Vasudevan@Sun.COM }
516910021SSheshadri.Vasudevan@Sun.COM
517010021SSheshadri.Vasudevan@Sun.COM mutex_exit(CMLB_MUTEX(cl));
517110021SSheshadri.Vasudevan@Sun.COM return (fdisk_rval);
517210021SSheshadri.Vasudevan@Sun.COM }
517310021SSheshadri.Vasudevan@Sun.COM #endif
517410021SSheshadri.Vasudevan@Sun.COM
5175786Slclee /*
5176786Slclee * Function: cmlb_setup_default_geometry
5177786Slclee *
5178786Slclee * Description: This local utility routine sets the default geometry as part of
5179786Slclee * setting the device mboot.
5180786Slclee *
51813525Sshidokht * Arguments:
51823525Sshidokht * cl driver soft state (unit) structure
51833525Sshidokht *
51843525Sshidokht * tg_cookie cookie from target driver to be passed back to target
51853525Sshidokht * driver when we call back to it through tg_ops.
51863525Sshidokht *
5187786Slclee *
5188786Slclee * Note: This may be redundant with cmlb_build_default_label.
5189786Slclee */
5190786Slclee static void
51913525Sshidokht cmlb_setup_default_geometry(struct cmlb_lun *cl, void *tg_cookie)
5192786Slclee {
5193786Slclee struct cmlb_geom pgeom;
5194786Slclee struct cmlb_geom *pgeomp = &pgeom;
5195786Slclee int ret;
5196786Slclee int geom_base_cap = 1;
5197786Slclee
5198786Slclee
51993525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl)));
5200786Slclee
5201786Slclee /* zero out the soft state geometry and partition table. */
52023525Sshidokht bzero(&cl->cl_g, sizeof (struct dk_geom));
52033525Sshidokht bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc));
52043525Sshidokht bzero(cl->cl_map, NDKMAP * (sizeof (struct dk_map)));
5205786Slclee
5206786Slclee /*
5207786Slclee * For the rpm, we use the minimum for the disk.
5208786Slclee * For the head, cyl and number of sector per track,
5209786Slclee * if the capacity <= 1GB, head = 64, sect = 32.
5210786Slclee * else head = 255, sect 63
5211786Slclee * Note: the capacity should be equal to C*H*S values.
5212786Slclee * This will cause some truncation of size due to
5213786Slclee * round off errors. For CD-ROMs, this truncation can
5214786Slclee * have adverse side effects, so returning ncyl and
5215786Slclee * nhead as 1. The nsect will overflow for most of
5216786Slclee * CD-ROMs as nsect is of type ushort.
5217786Slclee */
52183525Sshidokht if (cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8) {
5219786Slclee /*
5220786Slclee * newfs currently can not handle 255 ntracks for SPARC
5221786Slclee * so get the geometry from target driver instead of coming up
5222786Slclee * with one based on capacity.
5223786Slclee */
52243525Sshidokht mutex_exit(CMLB_MUTEX(cl));
52253525Sshidokht ret = DK_TG_GETPHYGEOM(cl, pgeomp, tg_cookie);
52263525Sshidokht mutex_enter(CMLB_MUTEX(cl));
5227786Slclee
52288863SEdward.Pilatowicz@Sun.COM if (ret == 0) {
5229786Slclee geom_base_cap = 0;
5230786Slclee } else {
52313525Sshidokht cmlb_dbg(CMLB_ERROR, cl,
5232786Slclee "cmlb_setup_default_geometry: "
5233786Slclee "tg_getphygeom failed %d\n", ret);
5234786Slclee
5235786Slclee /* do default setting, geometry based on capacity */
5236786Slclee }
5237786Slclee }
5238786Slclee
5239786Slclee if (geom_base_cap) {
52403525Sshidokht if (ISCD(cl)) {
52413525Sshidokht cl->cl_g.dkg_ncyl = 1;
52423525Sshidokht cl->cl_g.dkg_nhead = 1;
52433525Sshidokht cl->cl_g.dkg_nsect = cl->cl_blockcount;
524411748SShidokht.Yadegari@Sun.COM } else if (cl->cl_blockcount < 160) {
524511748SShidokht.Yadegari@Sun.COM /* Less than 80K */
524611748SShidokht.Yadegari@Sun.COM cl->cl_g.dkg_nhead = 1;
524711748SShidokht.Yadegari@Sun.COM cl->cl_g.dkg_ncyl = cl->cl_blockcount;
524811748SShidokht.Yadegari@Sun.COM cl->cl_g.dkg_nsect = 1;
52493525Sshidokht } else if (cl->cl_blockcount <= 0x1000) {
5250786Slclee /* Needed for unlabeled SCSI floppies. */
52513525Sshidokht cl->cl_g.dkg_nhead = 2;
52523525Sshidokht cl->cl_g.dkg_ncyl = 80;
52533525Sshidokht cl->cl_g.dkg_pcyl = 80;
52543525Sshidokht cl->cl_g.dkg_nsect = cl->cl_blockcount / (2 * 80);
52553525Sshidokht } else if (cl->cl_blockcount <= 0x200000) {
52563525Sshidokht cl->cl_g.dkg_nhead = 64;
52573525Sshidokht cl->cl_g.dkg_nsect = 32;
52583525Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount / (64 * 32);
5259786Slclee } else {
52603525Sshidokht cl->cl_g.dkg_nhead = 255;
52616124Sshidokht
52626124Sshidokht cl->cl_g.dkg_nsect = ((cl->cl_blockcount +
52636124Sshidokht (UINT16_MAX * 255 * 63) - 1) /
52646124Sshidokht (UINT16_MAX * 255 * 63)) * 63;
52656124Sshidokht
52666124Sshidokht if (cl->cl_g.dkg_nsect == 0)
52676124Sshidokht cl->cl_g.dkg_nsect = (UINT16_MAX / 63) * 63;
52686124Sshidokht
52696124Sshidokht cl->cl_g.dkg_ncyl = cl->cl_blockcount /
52706124Sshidokht (255 * cl->cl_g.dkg_nsect);
5271786Slclee }
5272786Slclee
52733525Sshidokht cl->cl_g.dkg_acyl = 0;
52743525Sshidokht cl->cl_g.dkg_bcyl = 0;
52753525Sshidokht cl->cl_g.dkg_intrlv = 1;
52763525Sshidokht cl->cl_g.dkg_rpm = 200;
52773525Sshidokht if (cl->cl_g.dkg_pcyl == 0)
52783525Sshidokht cl->cl_g.dkg_pcyl = cl->cl_g.dkg_ncyl +
52793525Sshidokht cl->cl_g.dkg_acyl;
5280786Slclee } else {
52813525Sshidokht cl->cl_g.dkg_ncyl = (short)pgeomp->g_ncyl;
52823525Sshidokht cl->cl_g.dkg_acyl = pgeomp->g_acyl;
52833525Sshidokht cl->cl_g.dkg_nhead = pgeomp->g_nhead;
52843525Sshidokht cl->cl_g.dkg_nsect = pgeomp->g_nsect;
52853525Sshidokht cl->cl_g.dkg_intrlv = pgeomp->g_intrlv;
52863525Sshidokht cl->cl_g.dkg_rpm = pgeomp->g_rpm;
52873525Sshidokht cl->cl_g.dkg_pcyl = cl->cl_g.dkg_ncyl + cl->cl_g.dkg_acyl;
5288786Slclee }
5289786Slclee
52903525Sshidokht cl->cl_g.dkg_read_reinstruct = 0;
52913525Sshidokht cl->cl_g.dkg_write_reinstruct = 0;
52923525Sshidokht cl->cl_solaris_size = cl->cl_g.dkg_ncyl *
52933525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect;
52943525Sshidokht
52953525Sshidokht cl->cl_map['a'-'a'].dkl_cylno = 0;
52963525Sshidokht cl->cl_map['a'-'a'].dkl_nblk = cl->cl_solaris_size;
52973525Sshidokht
52983525Sshidokht cl->cl_map['c'-'a'].dkl_cylno = 0;
52993525Sshidokht cl->cl_map['c'-'a'].dkl_nblk = cl->cl_solaris_size;
53003525Sshidokht
53013525Sshidokht cl->cl_vtoc.v_part[2].p_tag = V_BACKUP;
53023525Sshidokht cl->cl_vtoc.v_part[2].p_flag = V_UNMNT;
53033525Sshidokht cl->cl_vtoc.v_nparts = V_NUMPAR;
53043525Sshidokht cl->cl_vtoc.v_version = V_VERSION;
53053525Sshidokht (void) sprintf((char *)cl->cl_asciilabel, "DEFAULT cyl %d alt %d"
53063525Sshidokht " hd %d sec %d", cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl,
53073525Sshidokht cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect);
53083525Sshidokht
53098863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_FALSE;
5310786Slclee }
5311786Slclee
5312786Slclee
5313786Slclee #if defined(__i386) || defined(__amd64)
5314786Slclee /*
5315786Slclee * Function: cmlb_update_fdisk_and_vtoc
5316786Slclee *
5317786Slclee * Description: This local utility routine updates the device fdisk and vtoc
5318786Slclee * as part of setting the device mboot.
5319786Slclee *
53203525Sshidokht * Arguments:
53213525Sshidokht * cl driver soft state (unit) structure
53223525Sshidokht *
53233525Sshidokht * tg_cookie cookie from target driver to be passed back to target
53243525Sshidokht * driver when we call back to it through tg_ops.
53253525Sshidokht *
5326786Slclee *
5327786Slclee * Return Code: 0 for success or errno-type return code.
5328786Slclee *
5329786Slclee * Note:x86: This looks like a duplicate of cmlb_validate_geometry(), but
5330786Slclee * these did exist separately in x86 sd.c.
5331786Slclee */
5332786Slclee static int
53333525Sshidokht cmlb_update_fdisk_and_vtoc(struct cmlb_lun *cl, void *tg_cookie)
5334786Slclee {
5335786Slclee int count;
5336786Slclee int label_rc = 0;
5337786Slclee int fdisk_rval;
5338786Slclee diskaddr_t capacity;
5339786Slclee
53403525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl)));
53413525Sshidokht
53423525Sshidokht if (cmlb_check_update_blockcount(cl, tg_cookie) != 0)
5343786Slclee return (EINVAL);
5344786Slclee
5345786Slclee #if defined(_SUNOS_VTOC_16)
5346786Slclee /*
5347786Slclee * Set up the "whole disk" fdisk partition; this should always
5348786Slclee * exist, regardless of whether the disk contains an fdisk table
5349786Slclee * or vtoc.
5350786Slclee */
53513525Sshidokht cl->cl_map[P0_RAW_DISK].dkl_cylno = 0;
53523525Sshidokht cl->cl_map[P0_RAW_DISK].dkl_nblk = cl->cl_blockcount;
5353786Slclee #endif /* defined(_SUNOS_VTOC_16) */
5354786Slclee
5355786Slclee /*
5356786Slclee * copy the lbasize and capacity so that if they're
53573525Sshidokht * reset while we're not holding the CMLB_MUTEX(cl), we will
53583525Sshidokht * continue to use valid values after the CMLB_MUTEX(cl) is
5359786Slclee * reacquired.
5360786Slclee */
53613525Sshidokht capacity = cl->cl_blockcount;
5362786Slclee
5363786Slclee /*
5364786Slclee * refresh the logical and physical geometry caches.
5365786Slclee * (data from mode sense format/rigid disk geometry pages,
5366786Slclee * and scsi_ifgetcap("geometry").
5367786Slclee */
53683525Sshidokht cmlb_resync_geom_caches(cl, capacity, tg_cookie);
5369786Slclee
5370786Slclee /*
53713525Sshidokht * Only DIRECT ACCESS devices will have Scl labels.
53723525Sshidokht * CD's supposedly have a Scl label, too
5373786Slclee */
53743525Sshidokht if (cl->cl_device_type == DTYPE_DIRECT || ISREMOVABLE(cl)) {
53753525Sshidokht fdisk_rval = cmlb_read_fdisk(cl, capacity, tg_cookie);
5376786Slclee if (fdisk_rval != 0) {
53773525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl)));
5378786Slclee return (fdisk_rval);
5379786Slclee }
5380786Slclee
53813525Sshidokht if (cl->cl_solaris_size <= DK_LABEL_LOC) {
5382786Slclee /*
5383786Slclee * Found fdisk table but no Solaris partition entry,
5384786Slclee * so don't call cmlb_uselabel() and don't create
5385786Slclee * a default label.
5386786Slclee */
5387786Slclee label_rc = 0;
53888863SEdward.Pilatowicz@Sun.COM cl->cl_f_geometry_is_valid = B_TRUE;
5389786Slclee goto no_solaris_partition;
5390786Slclee }
5391786Slclee } else if (capacity < 0) {
53923525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl)));
5393786Slclee return (EINVAL);
5394786Slclee }
5395786Slclee
5396786Slclee /*
5397786Slclee * For Removable media We reach here if we have found a
5398786Slclee * SOLARIS PARTITION.
53998863SEdward.Pilatowicz@Sun.COM * If cl_f_geometry_is_valid is B_FALSE it indicates that the SOLARIS
5400786Slclee * PARTITION has changed from the previous one, hence we will setup a
5401786Slclee * default VTOC in this case.
5402786Slclee */
54038863SEdward.Pilatowicz@Sun.COM if (!cl->cl_f_geometry_is_valid) {
5404786Slclee /* if we get here it is writable */
5405786Slclee /* we are called from SMBOOT, and after a write of fdisk */
54063525Sshidokht cmlb_build_default_label(cl, tg_cookie);
5407786Slclee label_rc = 0;
5408786Slclee }
5409786Slclee
5410786Slclee no_solaris_partition:
5411786Slclee
5412786Slclee #if defined(_SUNOS_VTOC_16)
5413786Slclee /*
5414786Slclee * If we have valid geometry, set up the remaining fdisk partitions.
5415786Slclee * Note that dkl_cylno is not used for the fdisk map entries, so
5416786Slclee * we set it to an entirely bogus value.
5417786Slclee */
541810021SSheshadri.Vasudevan@Sun.COM for (count = 0; count < FDISK_PARTS; count++) {
54197563SPrasad.Singamsetty@Sun.COM cl->cl_map[FDISK_P1 + count].dkl_cylno = UINT32_MAX;
54203525Sshidokht cl->cl_map[FDISK_P1 + count].dkl_nblk =
54213525Sshidokht cl->cl_fmap[count].fmap_nblk;
54223525Sshidokht cl->cl_offset[FDISK_P1 + count] =
54233525Sshidokht cl->cl_fmap[count].fmap_start;
5424786Slclee }
5425786Slclee #endif
5426786Slclee
5427786Slclee for (count = 0; count < NDKMAP; count++) {
5428786Slclee #if defined(_SUNOS_VTOC_8)
54293525Sshidokht struct dk_map *lp = &cl->cl_map[count];
54303525Sshidokht cl->cl_offset[count] =
54313525Sshidokht cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno;
5432786Slclee #elif defined(_SUNOS_VTOC_16)
54333525Sshidokht struct dkl_partition *vp = &cl->cl_vtoc.v_part[count];
54343525Sshidokht cl->cl_offset[count] = vp->p_start + cl->cl_solaris_offset;
5435786Slclee #else
5436786Slclee #error "No VTOC format defined."
5437786Slclee #endif
5438786Slclee }
5439786Slclee
54403525Sshidokht ASSERT(mutex_owned(CMLB_MUTEX(cl)));
5441786Slclee return (label_rc);
5442786Slclee }
5443786Slclee #endif
5444786Slclee
5445786Slclee #if defined(__i386) || defined(__amd64)
5446786Slclee static int
54473525Sshidokht cmlb_dkio_get_virtgeom(struct cmlb_lun *cl, caddr_t arg, int flag)
5448786Slclee {
5449786Slclee int err = 0;
5450786Slclee
5451786Slclee /* Return the driver's notion of the media's logical geometry */
5452786Slclee struct dk_geom disk_geom;
5453786Slclee struct dk_geom *dkgp = &disk_geom;
5454786Slclee
54553525Sshidokht mutex_enter(CMLB_MUTEX(cl));
5456786Slclee /*
5457786Slclee * If there is no HBA geometry available, or
5458786Slclee * if the HBA returned us something that doesn't
5459786Slclee * really fit into an Int 13/function 8 geometry
5460786Slclee * result, just fail the ioctl. See PSARC 1998/313.
5461786Slclee */
54623525Sshidokht if (cl->cl_lgeom.g_nhead == 0 ||
54633525Sshidokht cl->cl_lgeom.g_nsect == 0 ||
54643525Sshidokht cl->cl_lgeom.g_ncyl > 1024) {
54653525Sshidokht mutex_exit(CMLB_MUTEX(cl));
5466786Slclee err = EINVAL;
5467786Slclee } else {
54683525Sshidokht dkgp->dkg_ncyl = cl->cl_lgeom.g_ncyl;
54693525Sshidokht dkgp->dkg_acyl = cl->cl_lgeom.g_acyl;
5470786Slclee dkgp->dkg_pcyl = dkgp->dkg_ncyl + dkgp->dkg_acyl;
54713525Sshidokht dkgp->dkg_nhead = cl->cl_lgeom.g_nhead;
54723525Sshidokht dkgp->dkg_nsect = cl->cl_lgeom.g_nsect;
5473786Slclee
54744177Sshidokht mutex_exit(CMLB_MUTEX(cl));
5475786Slclee if (ddi_copyout(dkgp, (void *)arg,
5476786Slclee sizeof (struct dk_geom), flag)) {
5477786Slclee err = EFAULT;
5478786Slclee } else {
5479786Slclee err = 0;
5480786Slclee }
5481786Slclee }
5482786Slclee return (err);
5483786Slclee }
5484786Slclee #endif
5485786Slclee
5486786Slclee #if defined(__i386) || defined(__amd64)
5487786Slclee static int
548810320SLarry.Liu@Sun.COM cmlb_dkio_get_phygeom(struct cmlb_lun *cl, caddr_t arg, int flag,
548910320SLarry.Liu@Sun.COM void *tg_cookie)
5490786Slclee {
5491786Slclee int err = 0;
54923525Sshidokht diskaddr_t capacity;
5493786Slclee
5494786Slclee
5495786Slclee /* Return the driver's notion of the media physical geometry */
5496786Slclee struct dk_geom disk_geom;
5497786Slclee struct dk_geom *dkgp = &disk_geom;
5498786Slclee
54993525Sshidokht mutex_enter(CMLB_MUTEX(cl));
55003525Sshidokht
55013525Sshidokht if (cl->cl_g.dkg_nhead != 0 &&
55023525Sshidokht cl->cl_g.dkg_nsect != 0) {
5503786Slclee /*
5504786Slclee * We succeeded in getting a geometry, but
5505786Slclee * right now it is being reported as just the
5506786Slclee * Solaris fdisk partition, just like for
5507786Slclee * DKIOCGGEOM. We need to change that to be
5508786Slclee * correct for the entire disk now.
5509786Slclee */
55103525Sshidokht bcopy(&cl->cl_g, dkgp, sizeof (*dkgp));
5511786Slclee dkgp->dkg_acyl = 0;
55123525Sshidokht dkgp->dkg_ncyl = cl->cl_blockcount /
5513786Slclee (dkgp->dkg_nhead * dkgp->dkg_nsect);
5514786Slclee } else {
5515786Slclee bzero(dkgp, sizeof (struct dk_geom));
5516786Slclee /*
5517786Slclee * This disk does not have a Solaris VTOC
5518786Slclee * so we must present a physical geometry
5519786Slclee * that will remain consistent regardless
5520786Slclee * of how the disk is used. This will ensure
5521786Slclee * that the geometry does not change regardless
5522786Slclee * of the fdisk partition type (ie. EFI, FAT32,
5523786Slclee * Solaris, etc).
5524786Slclee */
55253525Sshidokht if (ISCD(cl)) {
55263525Sshidokht dkgp->dkg_nhead = cl->cl_pgeom.g_nhead;
55273525Sshidokht dkgp->dkg_nsect = cl->cl_pgeom.g_nsect;
55283525Sshidokht dkgp->dkg_ncyl = cl->cl_pgeom.g_ncyl;
55293525Sshidokht dkgp->dkg_acyl = cl->cl_pgeom.g_acyl;
5530786Slclee } else {
55313525Sshidokht /*
55323525Sshidokht * Invalid cl_blockcount can generate invalid
55333525Sshidokht * dk_geom and may result in division by zero
55343525Sshidokht * system failure. Should make sure blockcount
55353525Sshidokht * is valid before using it here.
55363525Sshidokht */
55373525Sshidokht if (cl->cl_blockcount == 0) {
55383525Sshidokht mutex_exit(CMLB_MUTEX(cl));
55393525Sshidokht err = EIO;
55403525Sshidokht return (err);
55413525Sshidokht }
55423525Sshidokht /*
55433525Sshidokht * Refer to comments related to off-by-1 at the
55443525Sshidokht * header of this file
55453525Sshidokht */
55463525Sshidokht if (cl->cl_alter_behavior & CMLB_OFF_BY_ONE)
55473525Sshidokht capacity = cl->cl_blockcount - 1;
55483525Sshidokht else
55493525Sshidokht capacity = cl->cl_blockcount;
55503525Sshidokht
555110320SLarry.Liu@Sun.COM cmlb_convert_geometry(cl, capacity, dkgp, tg_cookie);
5552786Slclee dkgp->dkg_acyl = 0;
55533525Sshidokht dkgp->dkg_ncyl = capacity /
5554786Slclee (dkgp->dkg_nhead * dkgp->dkg_nsect);
5555786Slclee }
5556786Slclee }
5557786Slclee dkgp->dkg_pcyl = dkgp->dkg_ncyl + dkgp->dkg_acyl;
5558786Slclee
55594177Sshidokht mutex_exit(CMLB_MUTEX(cl));
55604177Sshidokht if (ddi_copyout(dkgp, (void *)arg, sizeof (struct dk_geom), flag))
5561786Slclee err = EFAULT;
55624177Sshidokht
5563786Slclee return (err);
5564786Slclee }
5565786Slclee #endif
5566786Slclee
5567786Slclee #if defined(__i386) || defined(__amd64)
5568786Slclee static int
55693525Sshidokht cmlb_dkio_partinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag)
5570786Slclee {
5571786Slclee int err = 0;
5572786Slclee
5573786Slclee /*
5574786Slclee * Return parameters describing the selected disk slice.
5575786Slclee * Note: this ioctl is for the intel platform only
5576786Slclee */
5577786Slclee int part;
5578786Slclee
5579786Slclee part = CMLBPART(dev);
5580786Slclee
55813525Sshidokht mutex_enter(CMLB_MUTEX(cl));
55823525Sshidokht /* don't check cl_solaris_size for pN */
55833525Sshidokht if (part < P0_RAW_DISK && cl->cl_solaris_size == 0) {
5584786Slclee err = EIO;
55854177Sshidokht mutex_exit(CMLB_MUTEX(cl));
5586786Slclee } else {
5587786Slclee struct part_info p;
5588786Slclee
55893525Sshidokht p.p_start = (daddr_t)cl->cl_offset[part];
55903525Sshidokht p.p_length = (int)cl->cl_map[part].dkl_nblk;
55914177Sshidokht mutex_exit(CMLB_MUTEX(cl));
5592786Slclee #ifdef _MULTI_DATAMODEL
5593786Slclee switch (ddi_model_convert_from(flag & FMODELS)) {
5594786Slclee case DDI_MODEL_ILP32:
5595786Slclee {
5596786Slclee struct part_info32 p32;
5597786Slclee
5598786Slclee p32.p_start = (daddr32_t)p.p_start;
5599786Slclee p32.p_length = p.p_length;
5600786Slclee if (ddi_copyout(&p32, (void *)arg,
5601786Slclee sizeof (p32), flag))
5602786Slclee err = EFAULT;
5603786Slclee break;
5604786Slclee }
5605786Slclee
5606786Slclee case DDI_MODEL_NONE:
5607786Slclee {
5608786Slclee if (ddi_copyout(&p, (void *)arg, sizeof (p),
5609786Slclee flag))
5610786Slclee err = EFAULT;
5611786Slclee break;
5612786Slclee }
5613786Slclee }
5614786Slclee #else /* ! _MULTI_DATAMODEL */
5615786Slclee if (ddi_copyout(&p, (void *)arg, sizeof (p), flag))
5616786Slclee err = EFAULT;
5617786Slclee #endif /* _MULTI_DATAMODEL */
5618786Slclee }
5619786Slclee return (err);
5620786Slclee }
56217563SPrasad.Singamsetty@Sun.COM static int
56227563SPrasad.Singamsetty@Sun.COM cmlb_dkio_extpartinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag)
56237563SPrasad.Singamsetty@Sun.COM {
56247563SPrasad.Singamsetty@Sun.COM int err = 0;
56257563SPrasad.Singamsetty@Sun.COM
56267563SPrasad.Singamsetty@Sun.COM /*
56277563SPrasad.Singamsetty@Sun.COM * Return parameters describing the selected disk slice.
56287563SPrasad.Singamsetty@Sun.COM * Note: this ioctl is for the intel platform only
56297563SPrasad.Singamsetty@Sun.COM */
56307563SPrasad.Singamsetty@Sun.COM int part;
56317563SPrasad.Singamsetty@Sun.COM
56327563SPrasad.Singamsetty@Sun.COM part = CMLBPART(dev);
56337563SPrasad.Singamsetty@Sun.COM
56347563SPrasad.Singamsetty@Sun.COM mutex_enter(CMLB_MUTEX(cl));
56357563SPrasad.Singamsetty@Sun.COM /* don't check cl_solaris_size for pN */
56367563SPrasad.Singamsetty@Sun.COM if (part < P0_RAW_DISK && cl->cl_solaris_size == 0) {
56377563SPrasad.Singamsetty@Sun.COM err = EIO;
56387563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl));
56397563SPrasad.Singamsetty@Sun.COM } else {
56407563SPrasad.Singamsetty@Sun.COM struct extpart_info p;
56417563SPrasad.Singamsetty@Sun.COM
56427563SPrasad.Singamsetty@Sun.COM p.p_start = (diskaddr_t)cl->cl_offset[part];
56437563SPrasad.Singamsetty@Sun.COM p.p_length = (diskaddr_t)cl->cl_map[part].dkl_nblk;
56447563SPrasad.Singamsetty@Sun.COM mutex_exit(CMLB_MUTEX(cl));
56457563SPrasad.Singamsetty@Sun.COM if (ddi_copyout(&p, (void *)arg, sizeof (p), flag))
56467563SPrasad.Singamsetty@Sun.COM err = EFAULT;
56477563SPrasad.Singamsetty@Sun.COM }
56487563SPrasad.Singamsetty@Sun.COM return (err);
56497563SPrasad.Singamsetty@Sun.COM }
5650786Slclee #endif
56517224Scth
56527224Scth int
56537224Scth cmlb_prop_op(cmlb_handle_t cmlbhandle,
56547224Scth dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
56557224Scth char *name, caddr_t valuep, int *lengthp, int part, void *tg_cookie)
56567224Scth {
56577224Scth struct cmlb_lun *cl;
56587224Scth diskaddr_t capacity;
56597224Scth uint32_t lbasize;
56607224Scth enum dp { DP_NBLOCKS, DP_BLKSIZE } dp;
56617224Scth int callers_length;
56627224Scth caddr_t buffer;
56637224Scth uint64_t nblocks64;
56647224Scth uint_t dblk;
56657224Scth
56667224Scth /* Always fallback to ddi_prop_op... */
56677224Scth cl = (struct cmlb_lun *)cmlbhandle;
56687224Scth if (cl == NULL) {
56697224Scth fallback: return (ddi_prop_op(dev, dip, prop_op, mod_flags,
56707224Scth name, valuep, lengthp));
56717224Scth }
56727224Scth
56737224Scth /* Pick up capacity and blocksize information. */
56747224Scth capacity = cl->cl_blockcount;
56757224Scth if (capacity == 0)
56767224Scth goto fallback;
56777224Scth lbasize = cl->cl_tgt_blocksize;
56787224Scth if (lbasize == 0)
56797224Scth lbasize = DEV_BSIZE; /* 0 -> DEV_BSIZE units */
56807224Scth
56817224Scth /* Check for dynamic property of whole device. */
56827224Scth if (dev == DDI_DEV_T_ANY) {
56837224Scth /* Fallback to ddi_prop_op if we don't understand. */
56847224Scth if (strcmp(name, "device-nblocks") == 0)
56857224Scth dp = DP_NBLOCKS;
56867224Scth else if (strcmp(name, "device-blksize") == 0)
56877224Scth dp = DP_BLKSIZE;
56887224Scth else
56897224Scth goto fallback;
56907224Scth
56917224Scth /* get callers length, establish length of our dynamic prop */
56927224Scth callers_length = *lengthp;
56937224Scth if (dp == DP_NBLOCKS)
56947224Scth *lengthp = sizeof (uint64_t);
56957224Scth else if (dp == DP_BLKSIZE)
56967224Scth *lengthp = sizeof (uint32_t);
56977224Scth
56987224Scth /* service request for the length of the property */
56997224Scth if (prop_op == PROP_LEN)
57007224Scth return (DDI_PROP_SUCCESS);
57017224Scth
57027224Scth switch (prop_op) {
57037224Scth case PROP_LEN_AND_VAL_ALLOC:
57047224Scth if ((buffer = kmem_alloc(*lengthp,
57057224Scth (mod_flags & DDI_PROP_CANSLEEP) ?
57067224Scth KM_SLEEP : KM_NOSLEEP)) == NULL)
57077224Scth return (DDI_PROP_NO_MEMORY);
57087224Scth *(caddr_t *)valuep = buffer; /* set callers buf */
57097224Scth break;
57107224Scth
57117224Scth case PROP_LEN_AND_VAL_BUF:
57127224Scth /* the length of the prop and the request must match */
57137224Scth if (callers_length != *lengthp)
57147224Scth return (DDI_PROP_INVAL_ARG);
57157224Scth buffer = valuep; /* get callers buf */
57167224Scth break;
57177224Scth
57187224Scth default:
57197224Scth return (DDI_PROP_INVAL_ARG);
57207224Scth }
57217224Scth
57227224Scth /* transfer the value into the buffer */
57237224Scth if (dp == DP_NBLOCKS)
57247224Scth *((uint64_t *)buffer) = capacity;
57257224Scth else if (dp == DP_BLKSIZE)
57267224Scth *((uint32_t *)buffer) = lbasize;
57277224Scth
57287224Scth return (DDI_PROP_SUCCESS);
57297224Scth }
57307224Scth
57317224Scth /*
57327224Scth * Support dynamic size oriented properties of partition. Requests
57337224Scth * issued under conditions where size is valid are passed to
57347224Scth * ddi_prop_op_nblocks with the size information, otherwise the
57357224Scth * request is passed to ddi_prop_op. Size depends on valid geometry.
57367224Scth */
57377224Scth if (!cmlb_is_valid(cmlbhandle))
57387224Scth goto fallback;
57397224Scth
57407224Scth /* Get partition nblocks value. */
57417224Scth (void) cmlb_partinfo(cmlbhandle, part,
57427224Scth (diskaddr_t *)&nblocks64, NULL, NULL, NULL, tg_cookie);
57437224Scth
57447224Scth /*
57459889SLarry.Liu@Sun.COM * Assume partition information is in sys_blocksize units, compute
57467224Scth * divisor for size(9P) property representation.
57477224Scth */
57489889SLarry.Liu@Sun.COM dblk = lbasize / cl->cl_sys_blocksize;
57497224Scth
57507224Scth /* Now let ddi_prop_op_nblocks_blksize() handle the request. */
57517224Scth return (ddi_prop_op_nblocks_blksize(dev, dip, prop_op, mod_flags,
57527224Scth name, valuep, lengthp, nblocks64 / dblk, lbasize));
57537224Scth }
5754