xref: /illumos-gate/usr/src/uts/common/io/cmlb.c (revision 86ef0a63)
13ccda647Slclee /*
23ccda647Slclee  * CDDL HEADER START
33ccda647Slclee  *
43ccda647Slclee  * The contents of this file are subject to the terms of the
5e8fb11a1Sshidokht  * Common Development and Distribution License (the "License").
6e8fb11a1Sshidokht  * You may not use this file except in compliance with the License.
73ccda647Slclee  *
83ccda647Slclee  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93ccda647Slclee  * or http://www.opensolaris.org/os/licensing.
103ccda647Slclee  * See the License for the specific language governing permissions
113ccda647Slclee  * and limitations under the License.
123ccda647Slclee  *
133ccda647Slclee  * When distributing Covered Code, include this CDDL HEADER in each
143ccda647Slclee  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153ccda647Slclee  * If applicable, add the following below this CDDL HEADER, with the
163ccda647Slclee  * fields enclosed by brackets "[]" replaced with your own identifying
173ccda647Slclee  * information: Portions Copyright [yyyy] [name of copyright owner]
183ccda647Slclee  *
193ccda647Slclee  * CDDL HEADER END
203ccda647Slclee  */
223ccda647Slclee /*
2359d8f100SGarrett D'Amore  * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
247e74b1cbSSharath M Srinivasan  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
253ccda647Slclee  * Use is subject to license terms.
26406fc510SToomas Soome  * Copyright 2016 Toomas Soome <tsoome@me.com>
27fd797736SJohn Levon  * Copyright (c) 2019, Joyent, Inc.
283ccda647Slclee  */
303ccda647Slclee /*
313ccda647Slclee  * This module provides support for labeling operations for target
323ccda647Slclee  * drivers.
333ccda647Slclee  */
353ccda647Slclee #include <sys/scsi/scsi.h>
363ccda647Slclee #include <sys/sunddi.h>
373ccda647Slclee #include <sys/dklabel.h>
383ccda647Slclee #include <sys/dkio.h>
393ccda647Slclee #include <sys/vtoc.h>
403ccda647Slclee #include <sys/dktp/fdisk.h>
413ccda647Slclee #include <sys/vtrace.h>
423ccda647Slclee #include <sys/efi_partition.h>
433ccda647Slclee #include <sys/cmlb.h>
443ccda647Slclee #include <sys/cmlb_impl.h>
45*86ef0a63SRichard Lowe #if defined(__x86)
46aa1b14e7SSheshadri Vasudevan #include <sys/fs/dv_node.h>
47aa1b14e7SSheshadri Vasudevan #endif
48b9ccdc5aScth #include <sys/ddi_impldefs.h>
503ccda647Slclee /*
513ccda647Slclee  * Driver minor node structure and data table
523ccda647Slclee  */
533ccda647Slclee struct driver_minor_data {
543ccda647Slclee 	char	*name;
553ccda647Slclee 	minor_t	minor;
563ccda647Slclee 	int	type;
573ccda647Slclee };
593ccda647Slclee static struct driver_minor_data dk_minor_data[] = {
603ccda647Slclee 	{"a", 0, S_IFBLK},
613ccda647Slclee 	{"b", 1, S_IFBLK},
623ccda647Slclee 	{"c", 2, S_IFBLK},
633ccda647Slclee 	{"d", 3, S_IFBLK},
643ccda647Slclee 	{"e", 4, S_IFBLK},
653ccda647Slclee 	{"f", 5, S_IFBLK},
663ccda647Slclee 	{"g", 6, S_IFBLK},
673ccda647Slclee 	{"h", 7, S_IFBLK},
683ccda647Slclee #if defined(_SUNOS_VTOC_16)
693ccda647Slclee 	{"i", 8, S_IFBLK},
703ccda647Slclee 	{"j", 9, S_IFBLK},
713ccda647Slclee 	{"k", 10, S_IFBLK},
723ccda647Slclee 	{"l", 11, S_IFBLK},
733ccda647Slclee 	{"m", 12, S_IFBLK},
743ccda647Slclee 	{"n", 13, S_IFBLK},
753ccda647Slclee 	{"o", 14, S_IFBLK},
763ccda647Slclee 	{"p", 15, S_IFBLK},
773ccda647Slclee #endif			/* defined(_SUNOS_VTOC_16) */
783ccda647Slclee #if defined(_FIRMWARE_NEEDS_FDISK)
793ccda647Slclee 	{"q", 16, S_IFBLK},
803ccda647Slclee 	{"r", 17, S_IFBLK},
813ccda647Slclee 	{"s", 18, S_IFBLK},
823ccda647Slclee 	{"t", 19, S_IFBLK},
833ccda647Slclee 	{"u", 20, S_IFBLK},
843ccda647Slclee #endif			/* defined(_FIRMWARE_NEEDS_FDISK) */
853ccda647Slclee 	{"a,raw", 0, S_IFCHR},
863ccda647Slclee 	{"b,raw", 1, S_IFCHR},
873ccda647Slclee 	{"c,raw", 2, S_IFCHR},
883ccda647Slclee 	{"d,raw", 3, S_IFCHR},
893ccda647Slclee 	{"e,raw", 4, S_IFCHR},
903ccda647Slclee 	{"f,raw", 5, S_IFCHR},
913ccda647Slclee 	{"g,raw", 6, S_IFCHR},
923ccda647Slclee 	{"h,raw", 7, S_IFCHR},
933ccda647Slclee #if defined(_SUNOS_VTOC_16)
943ccda647Slclee 	{"i,raw", 8, S_IFCHR},
953ccda647Slclee 	{"j,raw", 9, S_IFCHR},
963ccda647Slclee 	{"k,raw", 10, S_IFCHR},
973ccda647Slclee 	{"l,raw", 11, S_IFCHR},
983ccda647Slclee 	{"m,raw", 12, S_IFCHR},
993ccda647Slclee 	{"n,raw", 13, S_IFCHR},
1003ccda647Slclee 	{"o,raw", 14, S_IFCHR},
1013ccda647Slclee 	{"p,raw", 15, S_IFCHR},
1023ccda647Slclee #endif			/* defined(_SUNOS_VTOC_16) */
1033ccda647Slclee #if defined(_FIRMWARE_NEEDS_FDISK)
1043ccda647Slclee 	{"q,raw", 16, S_IFCHR},
1053ccda647Slclee 	{"r,raw", 17, S_IFCHR},
1063ccda647Slclee 	{"s,raw", 18, S_IFCHR},
1073ccda647Slclee 	{"t,raw", 19, S_IFCHR},
1083ccda647Slclee 	{"u,raw", 20, S_IFCHR},
1093ccda647Slclee #endif			/* defined(_FIRMWARE_NEEDS_FDISK) */
1103ccda647Slclee 	{0}
1113ccda647Slclee };
113*86ef0a63SRichard Lowe #if defined(__x86)
114aa1b14e7SSheshadri Vasudevan #if defined(_FIRMWARE_NEEDS_FDISK)
115aa1b14e7SSheshadri Vasudevan static struct driver_minor_data dk_ext_minor_data[] = {
116aa1b14e7SSheshadri Vasudevan 	{"p5", 21, S_IFBLK},
117aa1b14e7SSheshadri Vasudevan 	{"p6", 22, S_IFBLK},
118aa1b14e7SSheshadri Vasudevan 	{"p7", 23, S_IFBLK},
119aa1b14e7SSheshadri Vasudevan 	{"p8", 24, S_IFBLK},
120aa1b14e7SSheshadri Vasudevan 	{"p9", 25, S_IFBLK},
121aa1b14e7SSheshadri Vasudevan 	{"p10", 26, S_IFBLK},
122aa1b14e7SSheshadri Vasudevan 	{"p11", 27, S_IFBLK},
123aa1b14e7SSheshadri Vasudevan 	{"p12", 28, S_IFBLK},
124aa1b14e7SSheshadri Vasudevan 	{"p13", 29, S_IFBLK},
125aa1b14e7SSheshadri Vasudevan 	{"p14", 30, S_IFBLK},
126aa1b14e7SSheshadri Vasudevan 	{"p15", 31, S_IFBLK},
127aa1b14e7SSheshadri Vasudevan 	{"p16", 32, S_IFBLK},
128aa1b14e7SSheshadri Vasudevan 	{"p17", 33, S_IFBLK},
129aa1b14e7SSheshadri Vasudevan 	{"p18", 34, S_IFBLK},
130aa1b14e7SSheshadri Vasudevan 	{"p19", 35, S_IFBLK},
131aa1b14e7SSheshadri Vasudevan 	{"p20", 36, S_IFBLK},
132aa1b14e7SSheshadri Vasudevan 	{"p21", 37, S_IFBLK},
133aa1b14e7SSheshadri Vasudevan 	{"p22", 38, S_IFBLK},
134aa1b14e7SSheshadri Vasudevan 	{"p23", 39, S_IFBLK},
135aa1b14e7SSheshadri Vasudevan 	{"p24", 40, S_IFBLK},
136aa1b14e7SSheshadri Vasudevan 	{"p25", 41, S_IFBLK},
137aa1b14e7SSheshadri Vasudevan 	{"p26", 42, S_IFBLK},
138aa1b14e7SSheshadri Vasudevan 	{"p27", 43, S_IFBLK},
139aa1b14e7SSheshadri Vasudevan 	{"p28", 44, S_IFBLK},
140aa1b14e7SSheshadri Vasudevan 	{"p29", 45, S_IFBLK},
141aa1b14e7SSheshadri Vasudevan 	{"p30", 46, S_IFBLK},
142aa1b14e7SSheshadri Vasudevan 	{"p31", 47, S_IFBLK},
143aa1b14e7SSheshadri Vasudevan 	{"p32", 48, S_IFBLK},
144aa1b14e7SSheshadri Vasudevan 	{"p33", 49, S_IFBLK},
145aa1b14e7SSheshadri Vasudevan 	{"p34", 50, S_IFBLK},
146aa1b14e7SSheshadri Vasudevan 	{"p35", 51, S_IFBLK},
147aa1b14e7SSheshadri Vasudevan 	{"p36", 52, S_IFBLK},
148aa1b14e7SSheshadri Vasudevan 	{"p5,raw", 21, S_IFCHR},
149aa1b14e7SSheshadri Vasudevan 	{"p6,raw", 22, S_IFCHR},
150aa1b14e7SSheshadri Vasudevan 	{"p7,raw", 23, S_IFCHR},
151aa1b14e7SSheshadri Vasudevan 	{"p8,raw", 24, S_IFCHR},
152aa1b14e7SSheshadri Vasudevan 	{"p9,raw", 25, S_IFCHR},
153aa1b14e7SSheshadri Vasudevan 	{"p10,raw", 26, S_IFCHR},
154aa1b14e7SSheshadri Vasudevan 	{"p11,raw", 27, S_IFCHR},
155aa1b14e7SSheshadri Vasudevan 	{"p12,raw", 28, S_IFCHR},
156aa1b14e7SSheshadri Vasudevan 	{"p13,raw", 29, S_IFCHR},
157aa1b14e7SSheshadri Vasudevan 	{"p14,raw", 30, S_IFCHR},
158aa1b14e7SSheshadri Vasudevan 	{"p15,raw", 31, S_IFCHR},
159aa1b14e7SSheshadri Vasudevan 	{"p16,raw", 32, S_IFCHR},
160aa1b14e7SSheshadri Vasudevan 	{"p17,raw", 33, S_IFCHR},
161aa1b14e7SSheshadri Vasudevan 	{"p18,raw", 34, S_IFCHR},
162aa1b14e7SSheshadri Vasudevan 	{"p19,raw", 35, S_IFCHR},
163aa1b14e7SSheshadri Vasudevan 	{"p20,raw", 36, S_IFCHR},
164aa1b14e7SSheshadri Vasudevan 	{"p21,raw", 37, S_IFCHR},
165aa1b14e7SSheshadri Vasudevan 	{"p22,raw", 38, S_IFCHR},
166aa1b14e7SSheshadri Vasudevan 	{"p23,raw", 39, S_IFCHR},
167aa1b14e7SSheshadri Vasudevan 	{"p24,raw", 40, S_IFCHR},
168aa1b14e7SSheshadri Vasudevan 	{"p25,raw", 41, S_IFCHR},
169aa1b14e7SSheshadri Vasudevan 	{"p26,raw", 42, S_IFCHR},
170aa1b14e7SSheshadri Vasudevan 	{"p27,raw", 43, S_IFCHR},
171aa1b14e7SSheshadri Vasudevan 	{"p28,raw", 44, S_IFCHR},
172aa1b14e7SSheshadri Vasudevan 	{"p29,raw", 45, S_IFCHR},
173aa1b14e7SSheshadri Vasudevan 	{"p30,raw", 46, S_IFCHR},
174aa1b14e7SSheshadri Vasudevan 	{"p31,raw", 47, S_IFCHR},
175aa1b14e7SSheshadri Vasudevan 	{"p32,raw", 48, S_IFCHR},
176aa1b14e7SSheshadri Vasudevan 	{"p33,raw", 49, S_IFCHR},
177aa1b14e7SSheshadri Vasudevan 	{"p34,raw", 50, S_IFCHR},
178aa1b14e7SSheshadri Vasudevan 	{"p35,raw", 51, S_IFCHR},
179aa1b14e7SSheshadri Vasudevan 	{"p36,raw", 52, S_IFCHR},
180aa1b14e7SSheshadri Vasudevan 	{0}
181aa1b14e7SSheshadri Vasudevan };
182aa1b14e7SSheshadri Vasudevan #endif			/* defined(_FIRMWARE_NEEDS_FDISK) */
183*86ef0a63SRichard Lowe #endif			/* if defined(__x86) */
184aa1b14e7SSheshadri Vasudevan 
1853ccda647Slclee static struct driver_minor_data dk_minor_data_efi[] = {
1863ccda647Slclee 	{"a", 0, S_IFBLK},
1873ccda647Slclee 	{"b", 1, S_IFBLK},
1883ccda647Slclee 	{"c", 2, S_IFBLK},
1893ccda647Slclee 	{"d", 3, S_IFBLK},
1903ccda647Slclee 	{"e", 4, S_IFBLK},
1913ccda647Slclee 	{"f", 5, S_IFBLK},
1923ccda647Slclee 	{"g", 6, S_IFBLK},
1933ccda647Slclee 	{"wd", 7, S_IFBLK},
1947e70b434SShidokht Yadegari #if defined(_SUNOS_VTOC_16)
1957e70b434SShidokht Yadegari 	{"i", 8, S_IFBLK},
1967e70b434SShidokht Yadegari 	{"j", 9, S_IFBLK},
1977e70b434SShidokht Yadegari 	{"k", 10, S_IFBLK},
1987e70b434SShidokht Yadegari 	{"l", 11, S_IFBLK},
1997e70b434SShidokht Yadegari 	{"m", 12, S_IFBLK},
2007e70b434SShidokht Yadegari 	{"n", 13, S_IFBLK},
2017e70b434SShidokht Yadegari 	{"o", 14, S_IFBLK},
2027e70b434SShidokht Yadegari 	{"p", 15, S_IFBLK},
2037e70b434SShidokht Yadegari #endif			/* defined(_SUNOS_VTOC_16) */
2043ccda647Slclee #if defined(_FIRMWARE_NEEDS_FDISK)
2053ccda647Slclee 	{"q", 16, S_IFBLK},
2063ccda647Slclee 	{"r", 17, S_IFBLK},
2073ccda647Slclee 	{"s", 18, S_IFBLK},
2083ccda647Slclee 	{"t", 19, S_IFBLK},
2093ccda647Slclee 	{"u", 20, S_IFBLK},
2103ccda647Slclee #endif			/* defined(_FIRMWARE_NEEDS_FDISK) */
2113ccda647Slclee 	{"a,raw", 0, S_IFCHR},
2123ccda647Slclee 	{"b,raw", 1, S_IFCHR},
2133ccda647Slclee 	{"c,raw", 2, S_IFCHR},
2143ccda647Slclee 	{"d,raw", 3, S_IFCHR},
2153ccda647Slclee 	{"e,raw", 4, S_IFCHR},
2163ccda647Slclee 	{"f,raw", 5, S_IFCHR},
2173ccda647Slclee 	{"g,raw", 6, S_IFCHR},
2183ccda647Slclee 	{"wd,raw", 7, S_IFCHR},
2197e70b434SShidokht Yadegari #if defined(_SUNOS_VTOC_16)
2207e70b434SShidokht Yadegari 	{"i,raw", 8, S_IFCHR},
2217e70b434SShidokht Yadegari 	{"j,raw", 9, S_IFCHR},
2227e70b434SShidokht Yadegari 	{"k,raw", 10, S_IFCHR},
2237e70b434SShidokht Yadegari 	{"l,raw", 11, S_IFCHR},
2247e70b434SShidokht Yadegari 	{"m,raw", 12, S_IFCHR},
2257e70b434SShidokht Yadegari 	{"n,raw", 13, S_IFCHR},
2267e70b434SShidokht Yadegari 	{"o,raw", 14, S_IFCHR},
2277e70b434SShidokht Yadegari 	{"p,raw", 15, S_IFCHR},
2287e70b434SShidokht Yadegari #endif			/* defined(_SUNOS_VTOC_16) */
2293ccda647Slclee #if defined(_FIRMWARE_NEEDS_FDISK)
2303ccda647Slclee 	{"q,raw", 16, S_IFCHR},
2313ccda647Slclee 	{"r,raw", 17, S_IFCHR},
2323ccda647Slclee 	{"s,raw", 18, S_IFCHR},
2333ccda647Slclee 	{"t,raw", 19, S_IFCHR},
2343ccda647Slclee 	{"u,raw", 20, S_IFCHR},
2353ccda647Slclee #endif			/* defined(_FIRMWARE_NEEDS_FDISK) */
2363ccda647Slclee 	{0}
2373ccda647Slclee };
239b9ccdc5aScth /*
240b9ccdc5aScth  * Declare the dynamic properties implemented in prop_op(9E) implementation
241b9ccdc5aScth  * that we want to have show up in a di_init(3DEVINFO) device tree snapshot
242b9ccdc5aScth  * of drivers that call cmlb_attach().
243b9ccdc5aScth  */
244b9ccdc5aScth static i_ddi_prop_dyn_t cmlb_prop_dyn[] = {
245b9ccdc5aScth 	{"Nblocks",		DDI_PROP_TYPE_INT64,	S_IFBLK},
246b9ccdc5aScth 	{"Size",		DDI_PROP_TYPE_INT64,	S_IFCHR},
247b9ccdc5aScth 	{"device-nblocks",	DDI_PROP_TYPE_INT64},
248b9ccdc5aScth 	{"device-blksize",	DDI_PROP_TYPE_INT},
24959d8f100SGarrett D'Amore 	{"device-solid-state",	DDI_PROP_TYPE_INT},
250acb450ddSYuri Pankov 	{"device-rotational",	DDI_PROP_TYPE_INT},
251b9ccdc5aScth 	{NULL}
252b9ccdc5aScth };
254c31fac72SShidokht Yadegari /*
255c31fac72SShidokht Yadegari  * This implies an upper limit of 8192 GPT partitions
256c31fac72SShidokht Yadegari  * in one transfer for GUID Partition Entry Array.
257c31fac72SShidokht Yadegari  */
258c31fac72SShidokht Yadegari len_t cmlb_tg_max_efi_xfer = 1024 * 1024;
259c31fac72SShidokht Yadegari 
26006bbe1e0Sedp /*
26106bbe1e0Sedp  * External kernel interfaces
26206bbe1e0Sedp  */
2633ccda647Slclee extern struct mod_ops mod_miscops;
26506bbe1e0Sedp extern int ddi_create_internal_pathname(dev_info_t *dip, char *name,
26606bbe1e0Sedp     int spec_type, minor_t minor_num);
2683ccda647Slclee /*
2693ccda647Slclee  * Global buffer and mutex for debug logging
2703ccda647Slclee  */
2713ccda647Slclee static char	cmlb_log_buffer[1024];
2723ccda647Slclee static kmutex_t	cmlb_log_mutex;
275e8fb11a1Sshidokht struct cmlb_lun *cmlb_debug_cl = NULL;
2763ccda647Slclee uint_t cmlb_level_mask = 0x0;
2783ccda647Slclee int cmlb_rot_delay = 4;	/* default rotational delay */
2803ccda647Slclee static struct modlmisc modlmisc = {
2813ccda647Slclee 	&mod_miscops,   /* Type of module */
282342440ecSPrasad Singamsetty 	"Common Labeling module"
2833ccda647Slclee };
2853ccda647Slclee static struct modlinkage modlinkage = {
2863ccda647Slclee 	MODREV_1, (void *)&modlmisc, NULL
2873ccda647Slclee };
2893ccda647Slclee /* Local function prototypes */
290e8fb11a1Sshidokht static dev_t cmlb_make_device(struct cmlb_lun *cl);
2917f0b8309SEdward Pilatowicz static int cmlb_validate_geometry(struct cmlb_lun *cl, boolean_t forcerevalid,
292e8fb11a1Sshidokht     int flags, void *tg_cookie);
293e8fb11a1Sshidokht static void cmlb_resync_geom_caches(struct cmlb_lun *cl, diskaddr_t capacity,
294e8fb11a1Sshidokht     void *tg_cookie);
295e8fb11a1Sshidokht static int cmlb_read_fdisk(struct cmlb_lun *cl, diskaddr_t capacity,
296e8fb11a1Sshidokht     void *tg_cookie);
2973ccda647Slclee static void cmlb_swap_efi_gpt(efi_gpt_t *e);
2983ccda647Slclee static void cmlb_swap_efi_gpe(int nparts, efi_gpe_t *p);
2993ccda647Slclee static int cmlb_validate_efi(efi_gpt_t *labp);
300e8fb11a1Sshidokht static int cmlb_use_efi(struct cmlb_lun *cl, diskaddr_t capacity, int flags,
301e8fb11a1Sshidokht     void *tg_cookie);
302e8fb11a1Sshidokht static void cmlb_build_default_label(struct cmlb_lun *cl, void *tg_cookie);
303e8fb11a1Sshidokht static int  cmlb_uselabel(struct cmlb_lun *cl,  struct dk_label *l, int flags);
304e8fb11a1Sshidokht #if defined(_SUNOS_VTOC_8)
305e8fb11a1Sshidokht static void cmlb_build_user_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc);
306e8fb11a1Sshidokht #endif
307e8fb11a1Sshidokht static int cmlb_build_label_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc);
308e8fb11a1Sshidokht static int cmlb_write_label(struct cmlb_lun *cl, void *tg_cookie);
309e8fb11a1Sshidokht static int cmlb_set_vtoc(struct cmlb_lun *cl, struct dk_label *dkl,
310e8fb11a1Sshidokht     void *tg_cookie);
311e8fb11a1Sshidokht static void cmlb_clear_efi(struct cmlb_lun *cl, void *tg_cookie);
312e8fb11a1Sshidokht static void cmlb_clear_vtoc(struct cmlb_lun *cl, void *tg_cookie);
313e8fb11a1Sshidokht static void cmlb_setup_default_geometry(struct cmlb_lun *cl, void *tg_cookie);
314e8fb11a1Sshidokht static int cmlb_create_minor_nodes(struct cmlb_lun *cl);
315e8fb11a1Sshidokht static int cmlb_check_update_blockcount(struct cmlb_lun *cl, void *tg_cookie);
3167f0b8309SEdward Pilatowicz static boolean_t cmlb_check_efi_mbr(uchar_t *buf, boolean_t *is_mbr);
318*86ef0a63SRichard Lowe #if defined(__x86)
319e8fb11a1Sshidokht static int cmlb_update_fdisk_and_vtoc(struct cmlb_lun *cl, void *tg_cookie);
3203ccda647Slclee #endif
3223ccda647Slclee #if defined(_FIRMWARE_NEEDS_FDISK)
3237f0b8309SEdward Pilatowicz static boolean_t  cmlb_has_max_chs_vals(struct ipart *fdp);
3243ccda647Slclee #endif
3263ccda647Slclee #if defined(_SUNOS_VTOC_16)
327b081f1c4Syu, larry liu - Sun Microsystems - Beijing China static void cmlb_convert_geometry(struct cmlb_lun *cl, diskaddr_t capacity,
328b081f1c4Syu, larry liu - Sun Microsystems - Beijing China     struct dk_geom *cl_g, void *tg_cookie);
3293ccda647Slclee #endif
331e8fb11a1Sshidokht static int cmlb_dkio_get_geometry(struct cmlb_lun *cl, caddr_t arg, int flag,
332e8fb11a1Sshidokht     void *tg_cookie);
333e8fb11a1Sshidokht static int cmlb_dkio_set_geometry(struct cmlb_lun *cl, caddr_t arg, int flag);
334e8fb11a1Sshidokht static int cmlb_dkio_get_partition(struct cmlb_lun *cl, caddr_t arg, int flag,
335e8fb11a1Sshidokht     void *tg_cookie);
336e8fb11a1Sshidokht static int cmlb_dkio_set_partition(struct cmlb_lun *cl, caddr_t arg, int flag);
337e8fb11a1Sshidokht static int cmlb_dkio_get_efi(struct cmlb_lun *cl, caddr_t arg, int flag,
338e8fb11a1Sshidokht     void *tg_cookie);
339e8fb11a1Sshidokht static int cmlb_dkio_set_efi(struct cmlb_lun *cl, dev_t dev, caddr_t arg,
340e8fb11a1Sshidokht     int flag, void *tg_cookie);
341e8fb11a1Sshidokht static int cmlb_dkio_get_vtoc(struct cmlb_lun *cl, caddr_t arg, int flag,
342e8fb11a1Sshidokht     void *tg_cookie);
343342440ecSPrasad Singamsetty static int cmlb_dkio_get_extvtoc(struct cmlb_lun *cl, caddr_t arg, int flag,
344342440ecSPrasad Singamsetty     void *tg_cookie);
345e8fb11a1Sshidokht static int cmlb_dkio_set_vtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg,
346e8fb11a1Sshidokht     int flag, void *tg_cookie);
347342440ecSPrasad Singamsetty static int cmlb_dkio_set_extvtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg,
348342440ecSPrasad Singamsetty     int flag, void *tg_cookie);
349e8fb11a1Sshidokht static int cmlb_dkio_get_mboot(struct cmlb_lun *cl, caddr_t arg, int flag,
350e8fb11a1Sshidokht     void *tg_cookie);
351e8fb11a1Sshidokht static int cmlb_dkio_set_mboot(struct cmlb_lun *cl, caddr_t arg, int flag,
352e8fb11a1Sshidokht     void *tg_cookie);
353e8fb11a1Sshidokht static int cmlb_dkio_partition(struct cmlb_lun *cl, caddr_t arg, int flag,
354e8fb11a1Sshidokht     void *tg_cookie);
356*86ef0a63SRichard Lowe #if defined(__x86)
357aa1b14e7SSheshadri Vasudevan static int cmlb_dkio_set_ext_part(struct cmlb_lun *cl, caddr_t arg, int flag,
358aa1b14e7SSheshadri Vasudevan     void *tg_cookie);
359aa1b14e7SSheshadri Vasudevan static int cmlb_validate_ext_part(struct cmlb_lun *cl, int part, int epart,
360aa1b14e7SSheshadri Vasudevan     uint32_t start, uint32_t size);
361aa1b14e7SSheshadri Vasudevan static int cmlb_is_linux_swap(struct cmlb_lun *cl, uint32_t part_start,
362aa1b14e7SSheshadri Vasudevan     void *tg_cookie);
363e8fb11a1Sshidokht static int cmlb_dkio_get_virtgeom(struct cmlb_lun *cl, caddr_t arg, int flag);
364b081f1c4Syu, larry liu - Sun Microsystems - Beijing China static int cmlb_dkio_get_phygeom(struct cmlb_lun *cl, caddr_t  arg, int flag,
365b081f1c4Syu, larry liu - Sun Microsystems - Beijing China     void *tg_cookie);
366e8fb11a1Sshidokht static int cmlb_dkio_partinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg,
3673ccda647Slclee     int flag);
368342440ecSPrasad Singamsetty static int cmlb_dkio_extpartinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg,
369342440ecSPrasad Singamsetty     int flag);
3703ccda647Slclee #endif
372e8fb11a1Sshidokht static void cmlb_dbg(uint_t comp, struct cmlb_lun *cl, const char *fmt, ...);
373c31fac72SShidokht Yadegari static void cmlb_v_log(dev_info_t *dev, const char *label, uint_t level,
3743ccda647Slclee     const char *fmt, va_list ap);
375c31fac72SShidokht Yadegari static void cmlb_log(dev_info_t *dev, const char *label, uint_t level,
3763ccda647Slclee     const char *fmt, ...);
3783ccda647Slclee int
_init(void)3793ccda647Slclee _init(void)
3803ccda647Slclee {
3813ccda647Slclee 	mutex_init(&cmlb_log_mutex, NULL, MUTEX_DRIVER, NULL);
3823ccda647Slclee 	return (mod_install(&modlinkage));
3833ccda647Slclee }
3853ccda647Slclee int
_info(struct modinfo * modinfop)3863ccda647Slclee _info(struct modinfo *modinfop)
3873ccda647Slclee {
3883ccda647Slclee 	return (mod_info(&modlinkage, modinfop));
3893ccda647Slclee }
3913ccda647Slclee int
_fini(void)3923ccda647Slclee _fini(void)
3933ccda647Slclee {
3943ccda647Slclee 	int err;
3963ccda647Slclee 	if ((err = mod_remove(&modlinkage)) != 0) {
3973ccda647Slclee 		return (err);
3983ccda647Slclee 	}
4003ccda647Slclee 	mutex_destroy(&cmlb_log_mutex);
4013ccda647Slclee 	return (err);
4023ccda647Slclee }
4043ccda647Slclee /*
4053ccda647Slclee  * cmlb_dbg is used for debugging to log additional info
4063ccda647Slclee  * Level of output is controlled via cmlb_level_mask setting.
4073ccda647Slclee  */
4083ccda647Slclee static void
cmlb_dbg(uint_t comp,struct cmlb_lun * cl,const char * fmt,...)409e8fb11a1Sshidokht cmlb_dbg(uint_t comp, struct cmlb_lun *cl, const char *fmt, ...)
4103ccda647Slclee {
4113ccda647Slclee 	va_list		ap;
4123ccda647Slclee 	dev_info_t	*dev;
4133ccda647Slclee 	uint_t		level_mask = 0;
415e8fb11a1Sshidokht 	ASSERT(cl != NULL);
416e8fb11a1Sshidokht 	dev = CMLB_DEVINFO(cl);
4173ccda647Slclee 	ASSERT(dev != NULL);
4183ccda647Slclee 	/*
4193ccda647Slclee 	 * Filter messages based on the global component and level masks,
420e8fb11a1Sshidokht 	 * also print if cl matches the value of cmlb_debug_cl, or if
421e8fb11a1Sshidokht 	 * cmlb_debug_cl is set to NULL.
4223ccda647Slclee 	 */
4233ccda647Slclee 	if (comp & CMLB_TRACE)
4243ccda647Slclee 		level_mask |= CMLB_LOGMASK_TRACE;
4263ccda647Slclee 	if (comp & CMLB_INFO)
4273ccda647Slclee 		level_mask |= CMLB_LOGMASK_INFO;
4293ccda647Slclee 	if (comp & CMLB_ERROR)
4303ccda647Slclee 		level_mask |= CMLB_LOGMASK_ERROR;
4323ccda647Slclee 	if ((cmlb_level_mask & level_mask) &&
433e8fb11a1Sshidokht 	    ((cmlb_debug_cl == NULL) || (cmlb_debug_cl == cl))) {
4343ccda647Slclee 		va_start(ap, fmt);
435e8fb11a1Sshidokht 		cmlb_v_log(dev, CMLB_LABEL(cl), CE_CONT, fmt, ap);
4363ccda647Slclee 		va_end(ap);
4373ccda647Slclee 	}
4383ccda647Slclee }
4403ccda647Slclee /*
4413ccda647Slclee  * cmlb_log is basically a duplicate of scsi_log. It is redefined here
4423ccda647Slclee  * so that this module does not depend on scsi module.
4433ccda647Slclee  */
4443ccda647Slclee static void
cmlb_log(dev_info_t * dev,const char * label,uint_t level,const char * fmt,...)445c31fac72SShidokht Yadegari cmlb_log(dev_info_t *dev, const char *label, uint_t level, const char *fmt, ...)
4463ccda647Slclee {
4473ccda647Slclee 	va_list		ap;
4493ccda647Slclee 	va_start(ap, fmt);
4503ccda647Slclee 	cmlb_v_log(dev, label, level, fmt, ap);
4513ccda647Slclee 	va_end(ap);
4523ccda647Slclee }
4543ccda647Slclee static void
cmlb_v_log(dev_info_t * dev,const char * label,uint_t level,const char * fmt,va_list ap)455c31fac72SShidokht Yadegari cmlb_v_log(dev_info_t *dev, const char *label, uint_t level, const char *fmt,
4563ccda647Slclee     va_list ap)
4573ccda647Slclee {
458531d0b66SToomas Soome 	static char	name[256];
459531d0b66SToomas Soome 	int		log_only = 0;
460531d0b66SToomas Soome 	int		boot_only = 0;
461531d0b66SToomas Soome 	int		console_only = 0;
4633ccda647Slclee 	mutex_enter(&cmlb_log_mutex);
4653ccda647Slclee 	if (dev) {
4663ccda647Slclee 		if (level == CE_PANIC || level == CE_WARN ||
4673ccda647Slclee 		    level == CE_NOTE) {
4683ccda647Slclee 			(void) sprintf(name, "%s (%s%d):\n",
4693ccda647Slclee 			    ddi_pathname(dev, cmlb_log_buffer),
4703ccda647Slclee 			    label, ddi_get_instance(dev));
4713ccda647Slclee 		} else {
4723ccda647Slclee 			name[0] = '\0';
4733ccda647Slclee 		}
4743ccda647Slclee 	} else {
4753ccda647Slclee 		(void) sprintf(name, "%s:", label);
4763ccda647Slclee 	}
4783ccda647Slclee 	(void) vsprintf(cmlb_log_buffer, fmt, ap);
4803ccda647Slclee 	switch (cmlb_log_buffer[0]) {
4813ccda647Slclee 	case '!':
4823ccda647Slclee 		log_only = 1;
4833ccda647Slclee 		break;
4843ccda647Slclee 	case '?':
4853ccda647Slclee 		boot_only = 1;
4863ccda647Slclee 		break;
4873ccda647Slclee 	case '^':
4883ccda647Slclee 		console_only = 1;
4893ccda647Slclee 		break;
4903ccda647Slclee 	}
4923ccda647Slclee 	switch (level) {
4933ccda647Slclee 	case CE_NOTE:
4943ccda647Slclee 		level = CE_CONT;
4953ccda647Slclee 		/* FALLTHROUGH */
4963ccda647Slclee 	case CE_CONT:
4973ccda647Slclee 	case CE_WARN:
4983ccda647Slclee 	case CE_PANIC:
4993ccda647Slclee 		if (boot_only) {
5003ccda647Slclee 			cmn_err(level, "?%s\t%s", name, &cmlb_log_buffer[1]);
5013ccda647Slclee 		} else if (console_only) {
5023ccda647Slclee 			cmn_err(level, "^%s\t%s", name, &cmlb_log_buffer[1]);
5033ccda647Slclee 		} else if (log_only) {
5043ccda647Slclee 			cmn_err(level, "!%s\t%s", name, &cmlb_log_buffer[1]);
5053ccda647Slclee 		} else {
5063ccda647Slclee 			cmn_err(level, "%s\t%s", name, cmlb_log_buffer);
5073ccda647Slclee 		}
5083ccda647Slclee 		break;
5093ccda647Slclee 	case CE_IGNORE:
5103ccda647Slclee 		break;
5113ccda647Slclee 	default:
5123ccda647Slclee 		cmn_err(CE_CONT, "^DEBUG: %s\t%s", name, cmlb_log_buffer);
5133ccda647Slclee 		break;
5143ccda647Slclee 	}
5153ccda647Slclee 	mutex_exit(&cmlb_log_mutex);
5163ccda647Slclee }
5193ccda647Slclee /*
5203ccda647Slclee  * cmlb_alloc_handle:
5213ccda647Slclee  *
5223ccda647Slclee  *	Allocates a handle.
5233ccda647Slclee  *
5243ccda647Slclee  * Arguments:
5253ccda647Slclee  *	cmlbhandlep	pointer to handle
5263ccda647Slclee  *
5273ccda647Slclee  * Notes:
5283ccda647Slclee  *	Allocates a handle and stores the allocated handle in the area
5293ccda647Slclee  *	pointed to by cmlbhandlep
5303ccda647Slclee  *
5313ccda647Slclee  * Context:
5323ccda647Slclee  *	Kernel thread only (can sleep).
5333ccda647Slclee  */
5343ccda647Slclee void
cmlb_alloc_handle(cmlb_handle_t * cmlbhandlep)5353ccda647Slclee cmlb_alloc_handle(cmlb_handle_t *cmlbhandlep)
5363ccda647Slclee {
537531d0b66SToomas Soome 	struct cmlb_lun	*cl;
539e8fb11a1Sshidokht 	cl = kmem_zalloc(sizeof (struct cmlb_lun), KM_SLEEP);
5403ccda647Slclee 	ASSERT(cmlbhandlep != NULL);
542e8fb11a1Sshidokht 	cl->cl_state = CMLB_INITED;
543e8fb11a1Sshidokht 	cl->cl_def_labeltype = CMLB_LABEL_UNDEF;
544e8fb11a1Sshidokht 	mutex_init(CMLB_MUTEX(cl), NULL, MUTEX_DRIVER, NULL);
546e8fb11a1Sshidokht 	*cmlbhandlep = (cmlb_handle_t)(cl);
5473ccda647Slclee }
5493ccda647Slclee /*
5503ccda647Slclee  * cmlb_free_handle
5513ccda647Slclee  *
5523ccda647Slclee  *	Frees handle.
5533ccda647Slclee  *
5543ccda647Slclee  * Arguments:
5553ccda647Slclee  *	cmlbhandlep	pointer to handle
5563ccda647Slclee  */
5573ccda647Slclee void
cmlb_free_handle(cmlb_handle_t * cmlbhandlep)5583ccda647Slclee cmlb_free_handle(cmlb_handle_t *cmlbhandlep)
5593ccda647Slclee {
560531d0b66SToomas Soome 	struct cmlb_lun	*cl;
562e8fb11a1Sshidokht 	cl = (struct cmlb_lun *)*cmlbhandlep;
563e8fb11a1Sshidokht 	if (cl != NULL) {
564e8fb11a1Sshidokht 		mutex_destroy(CMLB_MUTEX(cl));
565e8fb11a1Sshidokht 		kmem_free(cl, sizeof (struct cmlb_lun));
5663ccda647Slclee 	}
5683ccda647Slclee }
5703ccda647Slclee /*
5713ccda647Slclee  * cmlb_attach:
5723ccda647Slclee  *
5733ccda647Slclee  *	Attach handle to device, create minor nodes for device.
5743ccda647Slclee  *
5753ccda647Slclee  * Arguments:
576531d0b66SToomas Soome  *	devi		pointer to device's dev_info structure.
577531d0b66SToomas Soome  *	tgopsp		pointer to array of functions cmlb can use to callback
5783ccda647Slclee  *			to target driver.
5793ccda647Slclee  *
5803ccda647Slclee  *	device_type	Peripheral device type as defined in
5813ccda647Slclee  *			scsi/generic/inquiry.h
5823ccda647Slclee  *
5833ccda647Slclee  *	is_removable	whether or not device is removable.
5843ccda647Slclee  *
585e8fb11a1Sshidokht  *	is_hotpluggable	whether or not device is hotpluggable.
586e8fb11a1Sshidokht  *
5873ccda647Slclee  *	node_type	minor node type (as used by ddi_create_minor_node)
5883ccda647Slclee  *
5893ccda647Slclee  *	alter_behavior
5903ccda647Slclee  *			bit flags:
5913ccda647Slclee  *
5923ccda647Slclee  *			CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT: create
5933ccda647Slclee  *			an alternate slice for the default label, if
5943ccda647Slclee  *			device type is DTYPE_DIRECT an architectures default
5953ccda647Slclee  *			label type is VTOC16.
5963ccda647Slclee  *			Otherwise alternate slice will no be created.
5973ccda647Slclee  *
5983ccda647Slclee  *
5993ccda647Slclee  *			CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8: report a default
6003ccda647Slclee  *			geometry and label for DKIOCGGEOM and DKIOCGVTOC
6013ccda647Slclee  *			on architecture with VTOC8 label types.
6023ccda647Slclee  *
603531d0b66SToomas Soome  *			CMLB_OFF_BY_ONE: do the workaround for legacy off-by-
604e8fb11a1Sshidokht  *                      one bug in obtaining capacity (in sd):
605e8fb11a1Sshidokht  *			SCSI READ_CAPACITY command returns the LBA number of the
606e8fb11a1Sshidokht  *			last logical block, but sd once treated this number as
607e8fb11a1Sshidokht  *			disks' capacity on x86 platform. And LBAs are addressed
608e8fb11a1Sshidokht  *			based 0. So the last block was lost on x86 platform.
609e8fb11a1Sshidokht  *
610e8fb11a1Sshidokht  *			Now, we remove this workaround. In order for present sd
611e8fb11a1Sshidokht  *			driver to work with disks which are labeled/partitioned
612e8fb11a1Sshidokht  *			via previous sd, we add workaround as follows:
613e8fb11a1Sshidokht  *
614e8fb11a1Sshidokht  *			1) Locate backup EFI label: cmlb searches the next to
615e8fb11a1Sshidokht  *			   last
616e8fb11a1Sshidokht  *			   block for backup EFI label. If fails, it will
617e8fb11a1Sshidokht  *			   turn to the last block for backup EFI label;
618e8fb11a1Sshidokht  *
619e8fb11a1Sshidokht  *			2) Clear backup EFI label: cmlb first search the last
620e8fb11a1Sshidokht  *			   block for backup EFI label, and will search the
621e8fb11a1Sshidokht  *			   next to last block only if failed for the last
622e8fb11a1Sshidokht  *			   block.
623e8fb11a1Sshidokht  *
624e8fb11a1Sshidokht  *			3) Calculate geometry:refer to cmlb_convert_geometry()
625e8fb11a1Sshidokht  *			   If capacity increasing by 1 causes disks' capacity
626342440ecSPrasad Singamsetty  *			   to cross over the limits in geometry calculation,
627e8fb11a1Sshidokht  *			   geometry info will change. This will raise an issue:
628e8fb11a1Sshidokht  *			   In case that primary VTOC label is destroyed, format
629e8fb11a1Sshidokht  *			   commandline can restore it via backup VTOC labels.
630e8fb11a1Sshidokht  *			   And format locates backup VTOC labels by use of
631e8fb11a1Sshidokht  *			   geometry. So changing geometry will
632e8fb11a1Sshidokht  *			   prevent format from finding backup VTOC labels. To
633e8fb11a1Sshidokht  *			   eliminate this side effect for compatibility,
634e8fb11a1Sshidokht  *			   sd uses (capacity -1) to calculate geometry;
635e8fb11a1Sshidokht  *
636e8fb11a1Sshidokht  *			4) 1TB disks: some important data structures use
637e8fb11a1Sshidokht  *			   32-bit signed long/int (for example, daddr_t),
638e8fb11a1Sshidokht  *			   so that sd doesn't support a disk with capacity
639e8fb11a1Sshidokht  *			   larger than 1TB on 32-bit platform. However,
640e8fb11a1Sshidokht  *			   for exactly 1TB disk, it was treated as (1T - 512)B
641e8fb11a1Sshidokht  *			   in the past, and could have valid Solaris
642e8fb11a1Sshidokht  *			   partitions. To workaround this, if an exactly 1TB
643e8fb11a1Sshidokht  *			   disk has Solaris fdisk partition, it will be allowed
644e8fb11a1Sshidokht  *			   to work with sd.
645e8fb11a1Sshidokht  *
646e8fb11a1Sshidokht  *
6473ccda647Slclee  *
648843e1988Sjohnlev  *			CMLB_FAKE_LABEL_ONE_PARTITION: create s0 and s2 covering
649843e1988Sjohnlev  *			the entire disk, if there is no valid partition info.
650843e1988Sjohnlev  *			If there is a valid Solaris partition, s0 and s2 will
651843e1988Sjohnlev  *			only cover the entire Solaris partition.
652843e1988Sjohnlev  *
653406fc510SToomas Soome  *			CMLB_CREATE_P0_MINOR_NODE: create p0 node covering
654406fc510SToomas Soome  *			the entire disk. Used by lofi to ensure presence of
655406fc510SToomas Soome  *			whole disk device node in case of LOFI_MAP_FILE ioctl.
656843e1988Sjohnlev  *
6573ccda647Slclee  *	cmlbhandle	cmlb handle associated with device
6583ccda647Slclee  *
659e8fb11a1Sshidokht  *	tg_cookie	cookie from target driver to be passed back to target
660e8fb11a1Sshidokht  *			driver when we call back to it through tg_ops.
661e8fb11a1Sshidokht  *
6623ccda647Slclee  * Notes:
6633ccda647Slclee  *	Assumes a default label based on capacity for non-removable devices.
6643ccda647Slclee  *	If capacity > 1TB, EFI is assumed otherwise VTOC (default VTOC
6653ccda647Slclee  *	for the architecture).
6663ccda647Slclee  *
6673ccda647Slclee  *	For removable devices, default label type is assumed to be VTOC
6683ccda647Slclee  *	type. Create minor nodes based on a default label type.
6693ccda647Slclee  *	Label on the media is not validated.
6703ccda647Slclee  *	minor number consists of:
6713ccda647Slclee  *		if _SUNOS_VTOC_8 is defined
6723ccda647Slclee  *			lowest 3 bits is taken as partition number
6733ccda647Slclee  *			the rest is instance number
6743ccda647Slclee  *		if _SUNOS_VTOC_16 is defined
6753ccda647Slclee  *			lowest 6 bits is taken as partition number
6763ccda647Slclee  *			the rest is instance number
6773ccda647Slclee  *
6783ccda647Slclee  *
6793ccda647Slclee  * Return values:
680531d0b66SToomas Soome  *	0	Success
681531d0b66SToomas Soome  *	ENXIO	creating minor nodes failed.
682e8fb11a1Sshidokht  *	EINVAL  invalid arg, unsupported tg_ops version
6833ccda647Slclee  */
6843ccda647Slclee 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)6853ccda647Slclee cmlb_attach(dev_info_t *devi, cmlb_tg_ops_t *tgopsp, int device_type,
6867f0b8309SEdward Pilatowicz     boolean_t is_removable, boolean_t is_hotpluggable, char *node_type,
687e8fb11a1Sshidokht     int alter_behavior, cmlb_handle_t cmlbhandle, void *tg_cookie)
6883ccda647Slclee {
690e8fb11a1Sshidokht 	struct cmlb_lun	*cl = (struct cmlb_lun *)cmlbhandle;
6913ccda647Slclee 	diskaddr_t	cap;
6923ccda647Slclee 	int		status;
6947f0b8309SEdward Pilatowicz 	ASSERT(VALID_BOOLEAN(is_removable));
6957f0b8309SEdward Pilatowicz 	ASSERT(VALID_BOOLEAN(is_hotpluggable));
6967f0b8309SEdward Pilatowicz 
697e8fb11a1Sshidokht 	if (tgopsp->tg_version < TG_DK_OPS_VERSION_1)
698e8fb11a1Sshidokht 		return (EINVAL);
700e8fb11a1Sshidokht 	mutex_enter(CMLB_MUTEX(cl));
702e8fb11a1Sshidokht 	CMLB_DEVINFO(cl) = devi;
703e8fb11a1Sshidokht 	cl->cmlb_tg_ops = tgopsp;
704e8fb11a1Sshidokht 	cl->cl_device_type = device_type;
705e8fb11a1Sshidokht 	cl->cl_is_removable = is_removable;
706e8fb11a1Sshidokht 	cl->