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