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