xref: /titanic_50/usr/src/uts/common/io/cmlb.c (revision afd1ac7b1c9a8cdf273c865aa5e9a14620341443)
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, 0);
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 	}
1190 
1191 	/* NO EFI label found */
1192 
1193 	if (capacity > DK_MAX_BLOCKS) {
1194 		if (label_error == ESRCH) {
1195 			/*
1196 			 * they've configured a LUN over 1TB, but used
1197 			 * format.dat to restrict format's view of the
1198 			 * capacity to be under 1TB
1199 			 */
1200 			/* i.e > 1Tb with a VTOC < 1TB */
1201 
1202 			cmlb_log(CMLB_DEVINFO(un), CMLB_LABEL(un), CE_WARN,
1203 			    "is >1TB and has a VTOC label: use format(1M) to "
1204 			    "either decrease the");
1205 			cmlb_log(CMLB_DEVINFO(un), CMLB_LABEL(un), CE_CONT,
1206 			    "size to be < 1TB or relabel the disk with an EFI "
1207 			    "label");
1208 		} else {
1209 			/* unlabeled disk over 1TB */
1210 			return (ENOTSUP);
1211 		}
1212 	}
1213 
1214 	label_error = 0;
1215 
1216 	/*
1217 	 * at this point it is either labeled with a VTOC or it is
1218 	 * under 1TB
1219 	 */
1220 
1221 	/*
1222 	 * Only DIRECT ACCESS devices will have Sun labels.
1223 	 * CD's supposedly have a Sun label, too
1224 	 */
1225 	if (un->un_device_type == DTYPE_DIRECT || ISREMOVABLE(un)) {
1226 		struct	dk_label *dkl;
1227 		offset_t label_addr;
1228 		int	rval;
1229 		size_t	buffer_size;
1230 
1231 		/*
1232 		 * Note: This will set up un->un_solaris_size and
1233 		 * un->un_solaris_offset.
1234 		 */
1235 		rval = cmlb_read_fdisk(un, capacity);
1236 		if (rval != 0) {
1237 			ASSERT(mutex_owned(CMLB_MUTEX(un)));
1238 			return (rval);
1239 		}
1240 
1241 		if (un->un_solaris_size <= DK_LABEL_LOC) {
1242 			/*
1243 			 * Found fdisk table but no Solaris partition entry,
1244 			 * so don't call cmlb_uselabel() and don't create
1245 			 * a default label.
1246 			 */
1247 			label_error = 0;
1248 			un->un_f_geometry_is_valid = TRUE;
1249 			goto no_solaris_partition;
1250 		}
1251 
1252 		label_addr = (daddr_t)(un->un_solaris_offset + DK_LABEL_LOC);
1253 
1254 		buffer_size = sizeof (struct dk_label);
1255 
1256 		cmlb_dbg(CMLB_TRACE, un, "cmlb_validate_geometry: "
1257 		    "label_addr: 0x%x allocation size: 0x%x\n",
1258 		    label_addr, buffer_size);
1259 
1260 		if ((dkl = kmem_zalloc(buffer_size, KM_NOSLEEP)) == NULL)
1261 			return (ENOMEM);
1262 
1263 		mutex_exit(CMLB_MUTEX(un));
1264 		rval = DK_TG_READ(un, dkl, label_addr, buffer_size);
1265 		mutex_enter(CMLB_MUTEX(un));
1266 
1267 		switch (rval) {
1268 		case 0:
1269 			/*
1270 			 * cmlb_uselabel will establish that the geometry
1271 			 * is valid.
1272 			 */
1273 			if (cmlb_uselabel(un,
1274 			    (struct dk_label *)(uintptr_t)dkl) !=
1275 			    CMLB_LABEL_IS_VALID) {
1276 				label_error = EINVAL;
1277 			} else
1278 				un->un_vtoc_label_is_from_media = 1;
1279 			break;
1280 		case EACCES:
1281 			label_error = EACCES;
1282 			break;
1283 		default:
1284 			label_error = EINVAL;
1285 			break;
1286 		}
1287 
1288 		kmem_free(dkl, buffer_size);
1289 	}
1290 
1291 	/*
1292 	 * If a valid label was not found, AND if no reservation conflict
1293 	 * was detected, then go ahead and create a default label (4069506).
1294 	 *
1295 	 * Note: currently, for VTOC_8 devices, the default label is created
1296 	 * for removables only.  For VTOC_16 devices, the default label will
1297 	 * be created for both removables and non-removables alike.
1298 	 * (see cmlb_build_default_label)
1299 	 */
1300 #if defined(_SUNOS_VTOC_8)
1301 	if (ISREMOVABLE(un) && (label_error != EACCES)) {
1302 #elif defined(_SUNOS_VTOC_16)
1303 	if (label_error != EACCES) {
1304 #endif
1305 		if (un->un_f_geometry_is_valid == FALSE) {
1306 			cmlb_build_default_label(un);
1307 		}
1308 		label_error = 0;
1309 	}
1310 
1311 no_solaris_partition:
1312 
1313 #if defined(_SUNOS_VTOC_16)
1314 	/*
1315 	 * If we have valid geometry, set up the remaining fdisk partitions.
1316 	 * Note that dkl_cylno is not used for the fdisk map entries, so
1317 	 * we set it to an entirely bogus value.
1318 	 */
1319 	for (count = 0; count < FD_NUMPART; count++) {
1320 		un->un_map[FDISK_P1 + count].dkl_cylno = -1;
1321 		un->un_map[FDISK_P1 + count].dkl_nblk =
1322 		    un->un_fmap[count].fmap_nblk;
1323 
1324 		un->un_offset[FDISK_P1 + count] =
1325 		    un->un_fmap[count].fmap_start;
1326 	}
1327 #endif
1328 
1329 	for (count = 0; count < NDKMAP; count++) {
1330 #if defined(_SUNOS_VTOC_8)
1331 		struct dk_map *lp  = &un->un_map[count];
1332 		un->un_offset[count] =
1333 		    un->un_g.dkg_nhead * un->un_g.dkg_nsect * lp->dkl_cylno;
1334 #elif defined(_SUNOS_VTOC_16)
1335 		struct dkl_partition *vp = &un->un_vtoc.v_part[count];
1336 
1337 		un->un_offset[count] = vp->p_start + un->un_solaris_offset;
1338 #else
1339 #error "No VTOC format defined."
1340 #endif
1341 	}
1342 
1343 	return (label_error);
1344 }
1345 
1346 #if defined(_SUNOS_VTOC_16)
1347 /*
1348  * Macro: MAX_BLKS
1349  *
1350  *	This macro is used for table entries where we need to have the largest
1351  *	possible sector value for that head & SPT (sectors per track)
1352  *	combination.  Other entries for some smaller disk sizes are set by
1353  *	convention to match those used by X86 BIOS usage.
1354  */
1355 #define	MAX_BLKS(heads, spt)	UINT16_MAX * heads * spt, heads, spt
1356 
1357 /*
1358  *    Function: cmlb_convert_geometry
1359  *
1360  * Description: Convert physical geometry into a dk_geom structure. In
1361  *		other words, make sure we don't wrap 16-bit values.
1362  *		e.g. converting from geom_cache to dk_geom
1363  *
1364  *     Context: Kernel thread only
1365  */
1366 static void
1367 cmlb_convert_geometry(diskaddr_t capacity, struct dk_geom *un_g)
1368 {
1369 	int i;
1370 	static const struct chs_values {
1371 		uint_t max_cap;		/* Max Capacity for this HS. */
1372 		uint_t nhead;		/* Heads to use. */
1373 		uint_t nsect;		/* SPT to use. */
1374 	} CHS_values[] = {
1375 		{0x00200000,  64, 32},		/* 1GB or smaller disk. */
1376 		{0x01000000, 128, 32},		/* 8GB or smaller disk. */
1377 		{MAX_BLKS(255,  63)},		/* 502.02GB or smaller disk. */
1378 		{MAX_BLKS(255, 126)},		/* .98TB or smaller disk. */
1379 		{DK_MAX_BLOCKS, 255, 189}	/* Max size is just under 1TB */
1380 	};
1381 
1382 	/* Unlabeled SCSI floppy device */
1383 	if (capacity <= 0x1000) {
1384 		un_g->dkg_nhead = 2;
1385 		un_g->dkg_ncyl = 80;
1386 		un_g->dkg_nsect = capacity / (un_g->dkg_nhead * un_g->dkg_ncyl);
1387 		return;
1388 	}
1389 
1390 	/*
1391 	 * For all devices we calculate cylinders using the
1392 	 * heads and sectors we assign based on capacity of the
1393 	 * device.  The table is designed to be compatible with the
1394 	 * way other operating systems lay out fdisk tables for X86
1395 	 * and to insure that the cylinders never exceed 65535 to
1396 	 * prevent problems with X86 ioctls that report geometry.
1397 	 * We use SPT that are multiples of 63, since other OSes that
1398 	 * are not limited to 16-bits for cylinders stop at 63 SPT
1399 	 * we make do by using multiples of 63 SPT.
1400 	 *
1401 	 * Note than capacities greater than or equal to 1TB will simply
1402 	 * get the largest geometry from the table. This should be okay
1403 	 * since disks this large shouldn't be using CHS values anyway.
1404 	 */
1405 	for (i = 0; CHS_values[i].max_cap < capacity &&
1406 	    CHS_values[i].max_cap != DK_MAX_BLOCKS; i++)
1407 		;
1408 
1409 	un_g->dkg_nhead = CHS_values[i].nhead;
1410 	un_g->dkg_nsect = CHS_values[i].nsect;
1411 }
1412 #endif
1413 
1414 /*
1415  *    Function: cmlb_resync_geom_caches
1416  *
1417  * Description: (Re)initialize both geometry caches: the virtual geometry
1418  *            information is extracted from the HBA (the "geometry"
1419  *            capability), and the physical geometry cache data is
1420  *            generated by issuing MODE SENSE commands.
1421  *
1422  *   Arguments: un - driver soft state (unit) structure
1423  *		capacity - disk capacity in #blocks
1424  *
1425  *     Context: Kernel thread only (can sleep).
1426  */
1427 static void
1428 cmlb_resync_geom_caches(struct cmlb_lun *un, diskaddr_t capacity)
1429 {
1430 	struct	cmlb_geom 	pgeom;
1431 	struct	cmlb_geom	lgeom;
1432 	struct 	cmlb_geom	*pgeomp = &pgeom;
1433 	unsigned short 		nhead;
1434 	unsigned short 		nsect;
1435 	int 			spc;
1436 	int			ret;
1437 
1438 	ASSERT(un != NULL);
1439 	ASSERT(mutex_owned(CMLB_MUTEX(un)));
1440 
1441 	/*
1442 	 * Ask the controller for its logical geometry.
1443 	 * Note: if the HBA does not support scsi_ifgetcap("geometry"),
1444 	 * then the lgeom cache will be invalid.
1445 	 */
1446 	mutex_exit(CMLB_MUTEX(un));
1447 	bzero(&lgeom, sizeof (struct cmlb_geom));
1448 	ret = DK_TG_GETVIRTGEOM(un, &lgeom);
1449 	mutex_enter(CMLB_MUTEX(un));
1450 
1451 	bcopy(&lgeom, &un->un_lgeom, sizeof (un->un_lgeom));
1452 
1453 	/*
1454 	 * Initialize the pgeom cache from lgeom, so that if MODE SENSE
1455 	 * doesn't work, DKIOCG_PHYSGEOM can return reasonable values.
1456 	 */
1457 	if (ret != 0 || un->un_lgeom.g_nsect == 0 ||
1458 	    un->un_lgeom.g_nhead == 0) {
1459 		/*
1460 		 * Note: Perhaps this needs to be more adaptive? The rationale
1461 		 * is that, if there's no HBA geometry from the HBA driver, any
1462 		 * guess is good, since this is the physical geometry. If MODE
1463 		 * SENSE fails this gives a max cylinder size for non-LBA access
1464 		 */
1465 		nhead = 255;
1466 		nsect = 63;
1467 	} else {
1468 		nhead = un->un_lgeom.g_nhead;
1469 		nsect = un->un_lgeom.g_nsect;
1470 	}
1471 
1472 	if (ISCD(un)) {
1473 		pgeomp->g_nhead = 1;
1474 		pgeomp->g_nsect = nsect * nhead;
1475 	} else {
1476 		pgeomp->g_nhead = nhead;
1477 		pgeomp->g_nsect = nsect;
1478 	}
1479 
1480 	spc = pgeomp->g_nhead * pgeomp->g_nsect;
1481 	pgeomp->g_capacity = capacity;
1482 	pgeomp->g_ncyl = pgeomp->g_capacity / spc;
1483 	pgeomp->g_acyl = 0;
1484 
1485 	/*
1486 	 * Retrieve fresh geometry data from the hardware, stash it
1487 	 * here temporarily before we rebuild the incore label.
1488 	 *
1489 	 * We want to use the MODE SENSE commands to derive the
1490 	 * physical geometry of the device, but if either command
1491 	 * fails, the logical geometry is used as the fallback for
1492 	 * disk label geometry.
1493 	 */
1494 
1495 	mutex_exit(CMLB_MUTEX(un));
1496 	(void) DK_TG_GETPHYGEOM(un,  pgeomp);
1497 	mutex_enter(CMLB_MUTEX(un));
1498 
1499 	/*
1500 	 * Now update the real copy while holding the mutex. This
1501 	 * way the global copy is never in an inconsistent state.
1502 	 */
1503 	bcopy(pgeomp, &un->un_pgeom,  sizeof (un->un_pgeom));
1504 
1505 	cmlb_dbg(CMLB_INFO, un, "cmlb_resync_geom_caches: "
1506 	    "(cached from lgeom)\n");
1507 	cmlb_dbg(CMLB_INFO,  un,
1508 	    "   ncyl: %ld; acyl: %d; nhead: %d; nsect: %d\n",
1509 	    un->un_pgeom.g_ncyl, un->un_pgeom.g_acyl,
1510 	    un->un_pgeom.g_nhead, un->un_pgeom.g_nsect);
1511 	cmlb_dbg(CMLB_INFO,  un, "   lbasize: %d; capacity: %ld; "
1512 	    "intrlv: %d; rpm: %d\n", un->un_pgeom.g_secsize,
1513 	    un->un_pgeom.g_capacity, un->un_pgeom.g_intrlv,
1514 	    un->un_pgeom.g_rpm);
1515 }
1516 
1517 
1518 /*
1519  *    Function: cmlb_read_fdisk
1520  *
1521  * Description: utility routine to read the fdisk table.
1522  *
1523  *   Arguments: un - driver soft state (unit) structure
1524  *
1525  * Return Code: 0 for success (includes not reading for no_fdisk_present case
1526  *		errnos from tg_rw if failed to read the first block.
1527  *
1528  *     Context: Kernel thread only (can sleep).
1529  */
1530 /* ARGSUSED */
1531 static int
1532 cmlb_read_fdisk(struct cmlb_lun *un, diskaddr_t capacity)
1533 {
1534 #if defined(_NO_FDISK_PRESENT)
1535 
1536 	un->un_solaris_offset = 0;
1537 	un->un_solaris_size = capacity;
1538 	bzero(un->un_fmap, sizeof (struct fmap) * FD_NUMPART);
1539 	return (0);
1540 
1541 #elif defined(_FIRMWARE_NEEDS_FDISK)
1542 
1543 	struct ipart	*fdp;
1544 	struct mboot	*mbp;
1545 	struct ipart	fdisk[FD_NUMPART];
1546 	int		i;
1547 	char		sigbuf[2];
1548 	caddr_t		bufp;
1549 	int		uidx;
1550 	int 		rval;
1551 	int		lba = 0;
1552 	uint_t		solaris_offset;	/* offset to solaris part. */
1553 	daddr_t		solaris_size;	/* size of solaris partition */
1554 	uint32_t	blocksize;
1555 
1556 	ASSERT(un != NULL);
1557 	ASSERT(mutex_owned(CMLB_MUTEX(un)));
1558 
1559 	/*
1560 	 * Start off assuming no fdisk table
1561 	 */
1562 	solaris_offset = 0;
1563 	solaris_size   = capacity;
1564 
1565 	blocksize = 512;
1566 
1567 	bufp = kmem_zalloc(blocksize, KM_SLEEP);
1568 
1569 	mutex_exit(CMLB_MUTEX(un));
1570 	rval = DK_TG_READ(un,  bufp, 0, blocksize);
1571 	mutex_enter(CMLB_MUTEX(un));
1572 
1573 	if (rval != 0) {
1574 		cmlb_dbg(CMLB_ERROR,  un,
1575 		    "cmlb_read_fdisk: fdisk read err\n");
1576 		kmem_free(bufp, blocksize);
1577 		return (rval);
1578 	}
1579 
1580 	mbp = (struct mboot *)bufp;
1581 
1582 	/*
1583 	 * The fdisk table does not begin on a 4-byte boundary within the
1584 	 * master boot record, so we copy it to an aligned structure to avoid
1585 	 * alignment exceptions on some processors.
1586 	 */
1587 	bcopy(&mbp->parts[0], fdisk, sizeof (fdisk));
1588 
1589 	/*
1590 	 * Check for lba support before verifying sig; sig might not be
1591 	 * there, say on a blank disk, but the max_chs mark may still
1592 	 * be present.
1593 	 *
1594 	 * Note: LBA support and BEFs are an x86-only concept but this
1595 	 * code should work OK on SPARC as well.
1596 	 */
1597 
1598 	/*
1599 	 * First, check for lba-access-ok on root node (or prom root node)
1600 	 * if present there, don't need to search fdisk table.
1601 	 */
1602 	if (ddi_getprop(DDI_DEV_T_ANY, ddi_root_node(), 0,
1603 	    "lba-access-ok", 0) != 0) {
1604 		/* All drives do LBA; don't search fdisk table */
1605 		lba = 1;
1606 	} else {
1607 		/* Okay, look for mark in fdisk table */
1608 		for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) {
1609 			/* accumulate "lba" value from all partitions */
1610 			lba = (lba || cmlb_has_max_chs_vals(fdp));
1611 		}
1612 	}
1613 
1614 	/*
1615 	 * Next, look for 'no-bef-lba-access' prop on parent.
1616 	 * Its presence means the realmode driver doesn't support
1617 	 * LBA, so the target driver shouldn't advertise it as ok.
1618 	 * This should be a temporary condition; one day all
1619 	 * BEFs should support the LBA access functions.
1620 	 */
1621 	if ((lba != 0) && (ddi_getprop(DDI_DEV_T_ANY,
1622 	    ddi_get_parent(CMLB_DEVINFO(un)), DDI_PROP_DONTPASS,
1623 	    "no-bef-lba-access", 0) != 0)) {
1624 		/* BEF doesn't support LBA; don't advertise it as ok */
1625 		lba = 0;
1626 	}
1627 
1628 	if (lba != 0) {
1629 		dev_t dev = cmlb_make_device(un);
1630 
1631 		if (ddi_getprop(dev, CMLB_DEVINFO(un), DDI_PROP_DONTPASS,
1632 		    "lba-access-ok", 0) == 0) {
1633 			/* not found; create it */
1634 			if (ddi_prop_create(dev, CMLB_DEVINFO(un), 0,
1635 			    "lba-access-ok", (caddr_t)NULL, 0) !=
1636 			    DDI_PROP_SUCCESS) {
1637 				cmlb_dbg(CMLB_ERROR,  un,
1638 				    "cmlb_read_fdisk: Can't create lba "
1639 				    "property for instance %d\n",
1640 				    ddi_get_instance(CMLB_DEVINFO(un)));
1641 			}
1642 		}
1643 	}
1644 
1645 	bcopy(&mbp->signature, sigbuf, sizeof (sigbuf));
1646 
1647 	/*
1648 	 * Endian-independent signature check
1649 	 */
1650 	if (((sigbuf[1] & 0xFF) != ((MBB_MAGIC >> 8) & 0xFF)) ||
1651 	    (sigbuf[0] != (MBB_MAGIC & 0xFF))) {
1652 		cmlb_dbg(CMLB_ERROR,  un,
1653 		    "cmlb_read_fdisk: no fdisk\n");
1654 		bzero(un->un_fmap, sizeof (struct fmap) * FD_NUMPART);
1655 		goto done;
1656 	}
1657 
1658 #ifdef CMLBDEBUG
1659 	if (cmlb_level_mask & SD_LOGMASK_INFO) {
1660 		fdp = fdisk;
1661 		cmlb_dbg(CMLB_INFO,  un, "cmlb_read_fdisk:\n");
1662 		cmlb_dbg(CMLB_INFO,  un, "         relsect    "
1663 		    "numsect         sysid       bootid\n");
1664 		for (i = 0; i < FD_NUMPART; i++, fdp++) {
1665 			cmlb_dbg(CMLB_INFO,  un,
1666 			    "    %d:  %8d   %8d     0x%08x     0x%08x\n",
1667 			    i, fdp->relsect, fdp->numsect,
1668 			    fdp->systid, fdp->bootid);
1669 		}
1670 	}
1671 #endif
1672 
1673 	/*
1674 	 * Try to find the unix partition
1675 	 */
1676 	uidx = -1;
1677 	solaris_offset = 0;
1678 	solaris_size   = 0;
1679 
1680 	for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) {
1681 		int	relsect;
1682 		int	numsect;
1683 
1684 		if (fdp->numsect == 0) {
1685 			un->un_fmap[i].fmap_start = 0;
1686 			un->un_fmap[i].fmap_nblk  = 0;
1687 			continue;
1688 		}
1689 
1690 		/*
1691 		 * Data in the fdisk table is little-endian.
1692 		 */
1693 		relsect = LE_32(fdp->relsect);
1694 		numsect = LE_32(fdp->numsect);
1695 
1696 		un->un_fmap[i].fmap_start = relsect;
1697 		un->un_fmap[i].fmap_nblk  = numsect;
1698 
1699 		if (fdp->systid != SUNIXOS &&
1700 		    fdp->systid != SUNIXOS2 &&
1701 		    fdp->systid != EFI_PMBR) {
1702 			continue;
1703 		}
1704 
1705 		/*
1706 		 * use the last active solaris partition id found
1707 		 * (there should only be 1 active partition id)
1708 		 *
1709 		 * if there are no active solaris partition id
1710 		 * then use the first inactive solaris partition id
1711 		 */
1712 		if ((uidx == -1) || (fdp->bootid == ACTIVE)) {
1713 			uidx = i;
1714 			solaris_offset = relsect;
1715 			solaris_size   = numsect;
1716 		}
1717 	}
1718 
1719 	cmlb_dbg(CMLB_INFO,  un, "fdisk 0x%x 0x%lx",
1720 	    un->un_solaris_offset, un->un_solaris_size);
1721 done:
1722 
1723 	/*
1724 	 * Clear the VTOC info, only if the Solaris partition entry
1725 	 * has moved, changed size, been deleted, or if the size of
1726 	 * the partition is too small to even fit the label sector.
1727 	 */
1728 	if ((un->un_solaris_offset != solaris_offset) ||
1729 	    (un->un_solaris_size != solaris_size) ||
1730 	    solaris_size <= DK_LABEL_LOC) {
1731 		cmlb_dbg(CMLB_INFO,  un, "fdisk moved 0x%x 0x%lx",
1732 			solaris_offset, solaris_size);
1733 		bzero(&un->un_g, sizeof (struct dk_geom));
1734 		bzero(&un->un_vtoc, sizeof (struct dk_vtoc));
1735 		bzero(&un->un_map, NDKMAP * (sizeof (struct dk_map)));
1736 		un->un_f_geometry_is_valid = FALSE;
1737 	}
1738 	un->un_solaris_offset = solaris_offset;
1739 	un->un_solaris_size = solaris_size;
1740 	kmem_free(bufp, blocksize);
1741 	return (rval);
1742 
1743 #else	/* #elif defined(_FIRMWARE_NEEDS_FDISK) */
1744 #error "fdisk table presence undetermined for this platform."
1745 #endif	/* #if defined(_NO_FDISK_PRESENT) */
1746 }
1747 
1748 static void
1749 cmlb_swap_efi_gpt(efi_gpt_t *e)
1750 {
1751 	_NOTE(ASSUMING_PROTECTED(*e))
1752 	e->efi_gpt_Signature = LE_64(e->efi_gpt_Signature);
1753 	e->efi_gpt_Revision = LE_32(e->efi_gpt_Revision);
1754 	e->efi_gpt_HeaderSize = LE_32(e->efi_gpt_HeaderSize);
1755 	e->efi_gpt_HeaderCRC32 = LE_32(e->efi_gpt_HeaderCRC32);
1756 	e->efi_gpt_MyLBA = LE_64(e->efi_gpt_MyLBA);
1757 	e->efi_gpt_AlternateLBA = LE_64(e->efi_gpt_AlternateLBA);
1758 	e->efi_gpt_FirstUsableLBA = LE_64(e->efi_gpt_FirstUsableLBA);
1759 	e->efi_gpt_LastUsableLBA = LE_64(e->efi_gpt_LastUsableLBA);
1760 	UUID_LE_CONVERT(e->efi_gpt_DiskGUID, e->efi_gpt_DiskGUID);
1761 	e->efi_gpt_PartitionEntryLBA = LE_64(e->efi_gpt_PartitionEntryLBA);
1762 	e->efi_gpt_NumberOfPartitionEntries =
1763 	    LE_32(e->efi_gpt_NumberOfPartitionEntries);
1764 	e->efi_gpt_SizeOfPartitionEntry =
1765 	    LE_32(e->efi_gpt_SizeOfPartitionEntry);
1766 	e->efi_gpt_PartitionEntryArrayCRC32 =
1767 	    LE_32(e->efi_gpt_PartitionEntryArrayCRC32);
1768 }
1769 
1770 static void
1771 cmlb_swap_efi_gpe(int nparts, efi_gpe_t *p)
1772 {
1773 	int i;
1774 
1775 	_NOTE(ASSUMING_PROTECTED(*p))
1776 	for (i = 0; i < nparts; i++) {
1777 		UUID_LE_CONVERT(p[i].efi_gpe_PartitionTypeGUID,
1778 		    p[i].efi_gpe_PartitionTypeGUID);
1779 		p[i].efi_gpe_StartingLBA = LE_64(p[i].efi_gpe_StartingLBA);
1780 		p[i].efi_gpe_EndingLBA = LE_64(p[i].efi_gpe_EndingLBA);
1781 		/* PartitionAttrs */
1782 	}
1783 }
1784 
1785 static int
1786 cmlb_validate_efi(efi_gpt_t *labp)
1787 {
1788 	if (labp->efi_gpt_Signature != EFI_SIGNATURE)
1789 		return (EINVAL);
1790 	/* at least 96 bytes in this version of the spec. */
1791 	if (sizeof (efi_gpt_t) - sizeof (labp->efi_gpt_Reserved2) >
1792 	    labp->efi_gpt_HeaderSize)
1793 		return (EINVAL);
1794 	/* this should be 128 bytes */
1795 	if (labp->efi_gpt_SizeOfPartitionEntry != sizeof (efi_gpe_t))
1796 		return (EINVAL);
1797 	return (0);
1798 }
1799 
1800 static int
1801 cmlb_use_efi(struct cmlb_lun *un, diskaddr_t capacity)
1802 {
1803 	int		i;
1804 	int		rval = 0;
1805 	efi_gpe_t	*partitions;
1806 	uchar_t		*buf;
1807 	uint_t		lbasize;	/* is really how much to read */
1808 	diskaddr_t	cap;
1809 	uint_t		nparts;
1810 	diskaddr_t	gpe_lba;
1811 
1812 	ASSERT(mutex_owned(CMLB_MUTEX(un)));
1813 
1814 	lbasize = un->un_sys_blocksize;
1815 
1816 	buf = kmem_zalloc(EFI_MIN_ARRAY_SIZE, KM_SLEEP);
1817 	mutex_exit(CMLB_MUTEX(un));
1818 
1819 	rval = DK_TG_READ(un, buf, 0, lbasize);
1820 	if (rval) {
1821 		goto done_err;
1822 	}
1823 	if (((struct dk_label *)buf)->dkl_magic == DKL_MAGIC) {
1824 		/* not ours */
1825 		rval = ESRCH;
1826 		goto done_err;
1827 	}
1828 
1829 	rval = DK_TG_READ(un, buf, 1, lbasize);
1830 	if (rval) {
1831 		goto done_err;
1832 	}
1833 	cmlb_swap_efi_gpt((efi_gpt_t *)buf);
1834 
1835 	if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) {
1836 		/*
1837 		 * Couldn't read the primary, try the backup.  Our
1838 		 * capacity at this point could be based on CHS, so
1839 		 * check what the device reports.
1840 		 */
1841 		rval = DK_TG_GETCAP(un, &cap);
1842 
1843 		if (rval) {
1844 			goto done_err;
1845 		}
1846 		if ((rval = DK_TG_READ(un, buf, cap - 1, lbasize)) != 0) {
1847 			goto done_err;
1848 		}
1849 		cmlb_swap_efi_gpt((efi_gpt_t *)buf);
1850 		if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0)
1851 			goto done_err;
1852 		cmlb_log(CMLB_DEVINFO(un), CMLB_LABEL(un), CE_WARN,
1853 		    "primary label corrupt; using backup\n");
1854 	}
1855 
1856 	nparts = ((efi_gpt_t *)buf)->efi_gpt_NumberOfPartitionEntries;
1857 	gpe_lba = ((efi_gpt_t *)buf)->efi_gpt_PartitionEntryLBA;
1858 
1859 	rval = DK_TG_READ(un, buf, gpe_lba, EFI_MIN_ARRAY_SIZE);
1860 	if (rval) {
1861 		goto done_err;
1862 	}
1863 	partitions = (efi_gpe_t *)buf;
1864 
1865 	if (nparts > MAXPART) {
1866 		nparts = MAXPART;
1867 	}
1868 	cmlb_swap_efi_gpe(nparts, partitions);
1869 
1870 	mutex_enter(CMLB_MUTEX(un));
1871 
1872 	/* Fill in partition table. */
1873 	for (i = 0; i < nparts; i++) {
1874 		if (partitions->efi_gpe_StartingLBA != 0 ||
1875 		    partitions->efi_gpe_EndingLBA != 0) {
1876 			un->un_map[i].dkl_cylno =
1877 			    partitions->efi_gpe_StartingLBA;
1878 			un->un_map[i].dkl_nblk =
1879 			    partitions->efi_gpe_EndingLBA -
1880 			    partitions->efi_gpe_StartingLBA + 1;
1881 			un->un_offset[i] =
1882 			    partitions->efi_gpe_StartingLBA;
1883 		}
1884 		if (i == WD_NODE) {
1885 			/*
1886 			 * minor number 7 corresponds to the whole disk
1887 			 */
1888 			un->un_map[i].dkl_cylno = 0;
1889 			un->un_map[i].dkl_nblk = capacity;
1890 			un->un_offset[i] = 0;
1891 		}
1892 		partitions++;
1893 	}
1894 	un->un_solaris_offset = 0;
1895 	un->un_solaris_size = capacity;
1896 	un->un_f_geometry_is_valid = TRUE;
1897 	kmem_free(buf, EFI_MIN_ARRAY_SIZE);
1898 	return (0);
1899 
1900 done_err:
1901 	kmem_free(buf, EFI_MIN_ARRAY_SIZE);
1902 	mutex_enter(CMLB_MUTEX(un));
1903 	/*
1904 	 * if we didn't find something that could look like a VTOC
1905 	 * and the disk is over 1TB, we know there isn't a valid label.
1906 	 * Otherwise let cmlb_uselabel decide what to do.  We only
1907 	 * want to invalidate this if we're certain the label isn't
1908 	 * valid because cmlb_prop_op will now fail, which in turn
1909 	 * causes things like opens and stats on the partition to fail.
1910 	 */
1911 	if ((capacity > DK_MAX_BLOCKS) && (rval != ESRCH)) {
1912 		un->un_f_geometry_is_valid = FALSE;
1913 	}
1914 	return (rval);
1915 }
1916 
1917 
1918 /*
1919  *    Function: cmlb_uselabel
1920  *
1921  * Description: Validate the disk label and update the relevant data (geometry,
1922  *		partition, vtoc, and capacity data) in the cmlb_lun struct.
1923  *		Marks the geometry of the unit as being valid.
1924  *
1925  *   Arguments: un: unit struct.
1926  *		dk_label: disk label
1927  *
1928  * Return Code: CMLB_LABEL_IS_VALID: Label read from disk is OK; geometry,
1929  *		partition, vtoc, and capacity data are good.
1930  *
1931  *		CMLB_LABEL_IS_INVALID: Magic number or checksum error in the
1932  *		label; or computed capacity does not jibe with capacity
1933  *		reported from the READ CAPACITY command.
1934  *
1935  *     Context: Kernel thread only (can sleep).
1936  */
1937 static int
1938 cmlb_uselabel(struct cmlb_lun *un, struct dk_label *labp)
1939 {
1940 	short		*sp;
1941 	short		sum;
1942 	short		count;
1943 	int		label_error = CMLB_LABEL_IS_VALID;
1944 	int		i;
1945 	diskaddr_t	label_capacity;
1946 	int		part_end;
1947 	diskaddr_t	track_capacity;
1948 #if defined(_SUNOS_VTOC_16)
1949 	struct	dkl_partition	*vpartp;
1950 #endif
1951 	ASSERT(un != NULL);
1952 	ASSERT(mutex_owned(CMLB_MUTEX(un)));
1953 
1954 	/* Validate the magic number of the label. */
1955 	if (labp->dkl_magic != DKL_MAGIC) {
1956 #if defined(__sparc)
1957 		if (!ISREMOVABLE(un)) {
1958 			cmlb_log(CMLB_DEVINFO(un), CMLB_LABEL(un), CE_WARN,
1959 			    "Corrupt label; wrong magic number\n");
1960 		}
1961 #endif
1962 		return (CMLB_LABEL_IS_INVALID);
1963 	}
1964 
1965 	/* Validate the checksum of the label. */
1966 	sp  = (short *)labp;
1967 	sum = 0;
1968 	count = sizeof (struct dk_label) / sizeof (short);
1969 	while (count--)	 {
1970 		sum ^= *sp++;
1971 	}
1972 
1973 	if (sum != 0) {
1974 #if defined(_SUNOS_VTOC_16)
1975 		if (!ISCD(un)) {
1976 #elif defined(_SUNOS_VTOC_8)
1977 		if (!ISREMOVABLE(un)) {
1978 #endif
1979 			cmlb_log(CMLB_DEVINFO(un), CMLB_LABEL(un), CE_WARN,
1980 			    "Corrupt label - label checksum failed\n");
1981 		}
1982 		return (CMLB_LABEL_IS_INVALID);
1983 	}
1984 
1985 
1986 	/*
1987 	 * Fill in geometry structure with data from label.
1988 	 */
1989 	bzero(&un->un_g, sizeof (struct dk_geom));
1990 	un->un_g.dkg_ncyl   = labp->dkl_ncyl;
1991 	un->un_g.dkg_acyl   = labp->dkl_acyl;
1992 	un->un_g.dkg_bcyl   = 0;
1993 	un->un_g.dkg_nhead  = labp->dkl_nhead;
1994 	un->un_g.dkg_nsect  = labp->dkl_nsect;
1995 	un->un_g.dkg_intrlv = labp->dkl_intrlv;
1996 
1997 #if defined(_SUNOS_VTOC_8)
1998 	un->un_g.dkg_gap1   = labp->dkl_gap1;
1999 	un->un_g.dkg_gap2   = labp->dkl_gap2;
2000 	un->un_g.dkg_bhead  = labp->dkl_bhead;
2001 #endif
2002 #if defined(_SUNOS_VTOC_16)
2003 	un->un_dkg_skew = labp->dkl_skew;
2004 #endif
2005 
2006 #if defined(__i386) || defined(__amd64)
2007 	un->un_g.dkg_apc = labp->dkl_apc;
2008 #endif
2009 
2010 	/*
2011 	 * Currently we rely on the values in the label being accurate. If
2012 	 * dkl_rpm or dkl_pcly are zero in the label, use a default value.
2013 	 *
2014 	 * Note: In the future a MODE SENSE may be used to retrieve this data,
2015 	 * although this command is optional in SCSI-2.
2016 	 */
2017 	un->un_g.dkg_rpm  = (labp->dkl_rpm  != 0) ? labp->dkl_rpm  : 3600;
2018 	un->un_g.dkg_pcyl = (labp->dkl_pcyl != 0) ? labp->dkl_pcyl :
2019 	    (un->un_g.dkg_ncyl + un->un_g.dkg_acyl);
2020 
2021 	/*
2022 	 * The Read and Write reinstruct values may not be valid
2023 	 * for older disks.
2024 	 */
2025 	un->un_g.dkg_read_reinstruct  = labp->dkl_read_reinstruct;
2026 	un->un_g.dkg_write_reinstruct = labp->dkl_write_reinstruct;
2027 
2028 	/* Fill in partition table. */
2029 #if defined(_SUNOS_VTOC_8)
2030 	for (i = 0; i < NDKMAP; i++) {
2031 		un->un_map[i].dkl_cylno = labp->dkl_map[i].dkl_cylno;
2032 		un->un_map[i].dkl_nblk  = labp->dkl_map[i].dkl_nblk;
2033 	}
2034 #endif
2035 #if  defined(_SUNOS_VTOC_16)
2036 	vpartp		= labp->dkl_vtoc.v_part;
2037 	track_capacity	= labp->dkl_nhead * labp->dkl_nsect;
2038 
2039 	for (i = 0; i < NDKMAP; i++, vpartp++) {
2040 		un->un_map[i].dkl_cylno = vpartp->p_start / track_capacity;
2041 		un->un_map[i].dkl_nblk  = vpartp->p_size;
2042 	}
2043 #endif
2044 
2045 	/* Fill in VTOC Structure. */
2046 	bcopy(&labp->dkl_vtoc, &un->un_vtoc, sizeof (struct dk_vtoc));
2047 #if defined(_SUNOS_VTOC_8)
2048 	/*
2049 	 * The 8-slice vtoc does not include the ascii label; save it into
2050 	 * the device's soft state structure here.
2051 	 */
2052 	bcopy(labp->dkl_asciilabel, un->un_asciilabel, LEN_DKL_ASCII);
2053 #endif
2054 
2055 	/* Mark the geometry as valid. */
2056 	un->un_f_geometry_is_valid = TRUE;
2057 
2058 	/* Now look for a valid capacity. */
2059 	track_capacity	= (un->un_g.dkg_nhead * un->un_g.dkg_nsect);
2060 	label_capacity	= (un->un_g.dkg_ncyl  * track_capacity);
2061 
2062 	if (un->un_g.dkg_acyl) {
2063 #if defined(__i386) || defined(__amd64)
2064 		/* we may have > 1 alts cylinder */
2065 		label_capacity += (track_capacity * un->un_g.dkg_acyl);
2066 #else
2067 		label_capacity += track_capacity;
2068 #endif
2069 	}
2070 
2071 	/*
2072 	 * if we got invalidated when mutex exit and entered again,
2073 	 * if blockcount different than when we came in, need to
2074 	 * retry from beginning of cmlb_validate_geometry.
2075 	 * revisit this on next phase of utilizing this for
2076 	 * sd.
2077 	 */
2078 
2079 	if (label_capacity <= un->un_blockcount) {
2080 #if defined(_SUNOS_VTOC_8)
2081 		/*
2082 		 * We can't let this happen on drives that are subdivided
2083 		 * into logical disks (i.e., that have an fdisk table).
2084 		 * The un_blockcount field should always hold the full media
2085 		 * size in sectors, period.  This code would overwrite
2086 		 * un_blockcount with the size of the Solaris fdisk partition.
2087 		 */
2088 		cmlb_dbg(CMLB_ERROR,  un,
2089 		    "cmlb_uselabel: Label %d blocks; Drive %d blocks\n",
2090 		    label_capacity, un->un_blockcount);
2091 		un->un_solaris_size = label_capacity;
2092 
2093 #endif	/* defined(_SUNOS_VTOC_8) */
2094 		goto done;
2095 	}
2096 
2097 	if (ISCD(un)) {
2098 		/* For CDROMs, we trust that the data in the label is OK. */
2099 #if defined(_SUNOS_VTOC_8)
2100 		for (i = 0; i < NDKMAP; i++) {
2101 			part_end = labp->dkl_nhead * labp->dkl_nsect *
2102 			    labp->dkl_map[i].dkl_cylno +
2103 			    labp->dkl_map[i].dkl_nblk  - 1;
2104 
2105 			if ((labp->dkl_map[i].dkl_nblk) &&
2106 			    (part_end > un->un_blockcount)) {
2107 				un->un_f_geometry_is_valid = FALSE;
2108 				break;
2109 			}
2110 		}
2111 #endif
2112 #if defined(_SUNOS_VTOC_16)
2113 		vpartp = &(labp->dkl_vtoc.v_part[0]);
2114 		for (i = 0; i < NDKMAP; i++, vpartp++) {
2115 			part_end = vpartp->p_start + vpartp->p_size;
2116 			if ((vpartp->p_size > 0) &&
2117 			    (part_end > un->un_blockcount)) {
2118 				un->un_f_geometry_is_valid = FALSE;
2119 				break;
2120 			}
2121 		}
2122 #endif
2123 	} else {
2124 		/* label_capacity > un->un_blockcount */
2125 		cmlb_log(CMLB_DEVINFO(un), CMLB_LABEL(un), CE_WARN,
2126 		    "Corrupt label - bad geometry\n");
2127 		cmlb_log(CMLB_DEVINFO(un), CMLB_LABEL(un), CE_CONT,
2128 		    "Label says %llu blocks; Drive says %llu blocks\n",
2129 		    label_capacity, un->un_blockcount);
2130 		un->un_f_geometry_is_valid = FALSE;
2131 		label_error = CMLB_LABEL_IS_INVALID;
2132 	}
2133 
2134 done:
2135 
2136 	cmlb_dbg(CMLB_INFO,  un, "cmlb_uselabel: (label geometry)\n");
2137 	cmlb_dbg(CMLB_INFO,  un,
2138 	    "   ncyl: %d; acyl: %d; nhead: %d; nsect: %d\n",
2139 	    un->un_g.dkg_ncyl,  un->un_g.dkg_acyl,
2140 	    un->un_g.dkg_nhead, un->un_g.dkg_nsect);
2141 
2142 	cmlb_dbg(CMLB_INFO,  un,
2143 	    "   label_capacity: %d; intrlv: %d; rpm: %d\n",
2144 	    un->un_blockcount, un->un_g.dkg_intrlv, un->un_g.dkg_rpm);
2145 	cmlb_dbg(CMLB_INFO,  un, "   wrt_reinstr: %d; rd_reinstr: %d\n",
2146 	    un->un_g.dkg_write_reinstruct, un->un_g.dkg_read_reinstruct);
2147 
2148 	ASSERT(mutex_owned(CMLB_MUTEX(un)));
2149 
2150 	return (label_error);
2151 }
2152 
2153 
2154 /*
2155  *    Function: cmlb_build_default_label
2156  *
2157  * Description: Generate a default label for those devices that do not have
2158  *		one, e.g., new media, removable cartridges, etc..
2159  *
2160  *     Context: Kernel thread only
2161  */
2162 static void
2163 cmlb_build_default_label(struct cmlb_lun *un)
2164 {
2165 #if defined(_SUNOS_VTOC_16)
2166 	uint_t	phys_spc;
2167 	uint_t	disksize;
2168 	struct  dk_geom un_g;
2169 #endif
2170 
2171 	ASSERT(un != NULL);
2172 	ASSERT(mutex_owned(CMLB_MUTEX(un)));
2173 
2174 #if defined(_SUNOS_VTOC_8)
2175 	/*
2176 	 * Note: This is a legacy check for non-removable devices on VTOC_8
2177 	 * only. This may be a valid check for VTOC_16 as well.
2178 	 */
2179 	if (!ISREMOVABLE(un)) {
2180 		return;
2181 	}
2182 #endif
2183 
2184 	bzero(&un->un_g, sizeof (struct dk_geom));
2185 	bzero(&un->un_vtoc, sizeof (struct dk_vtoc));
2186 	bzero(&un->un_map, NDKMAP * (sizeof (struct dk_map)));
2187 
2188 #if defined(_SUNOS_VTOC_8)
2189 
2190 	/*
2191 	 * It's a REMOVABLE media, therefore no label (on sparc, anyway).
2192 	 * But it is still necessary to set up various geometry information,
2193 	 * and we are doing this here.
2194 	 */
2195 
2196 	/*
2197 	 * For the rpm, we use the minimum for the disk.  For the head, cyl,
2198 	 * and number of sector per track, if the capacity <= 1GB, head = 64,
2199 	 * sect = 32.  else head = 255, sect 63 Note: the capacity should be
2200 	 * equal to C*H*S values.  This will cause some truncation of size due
2201 	 * to round off errors. For CD-ROMs, this truncation can have adverse
2202 	 * side effects, so returning ncyl and nhead as 1. The nsect will
2203 	 * overflow for most of CD-ROMs as nsect is of type ushort. (4190569)
2204 	 */
2205 	un->un_solaris_size = un->un_blockcount;
2206 	if (ISCD(un)) {
2207 		tg_attribute_t tgattribute;
2208 		int is_writable;
2209 		/*
2210 		 * Preserve the old behavior for non-writable
2211 		 * medias. Since dkg_nsect is a ushort, it
2212 		 * will lose bits as cdroms have more than
2213 		 * 65536 sectors. So if we recalculate
2214 		 * capacity, it will become much shorter.
2215 		 * But the dkg_* information is not
2216 		 * used for CDROMs so it is OK. But for
2217 		 * Writable CDs we need this information
2218 		 * to be valid (for newfs say). So we
2219 		 * make nsect and nhead > 1 that way
2220 		 * nsect can still stay within ushort limit
2221 		 * without losing any bits.
2222 		 */
2223 
2224 		bzero(&tgattribute, sizeof (tg_attribute_t));
2225 
2226 		mutex_exit(CMLB_MUTEX(un));
2227 		is_writable = (DK_TG_GETATTRIBUTE(un, &tgattribute) == 0) ?
2228 		    tgattribute.media_is_writable : 1;
2229 		mutex_enter(CMLB_MUTEX(un));
2230 
2231 		if (is_writable) {
2232 			un->un_g.dkg_nhead = 64;
2233 			un->un_g.dkg_nsect = 32;
2234 			un->un_g.dkg_ncyl = un->un_blockcount / (64 * 32);
2235 			un->un_solaris_size = un->un_g.dkg_ncyl *
2236 			    un->un_g.dkg_nhead * un->un_g.dkg_nsect;
2237 		} else {
2238 			un->un_g.dkg_ncyl  = 1;
2239 			un->un_g.dkg_nhead = 1;
2240 			un->un_g.dkg_nsect = un->un_blockcount;
2241 		}
2242 	} else {
2243 		if (un->un_blockcount <= 0x1000) {
2244 			/* unlabeled SCSI floppy device */
2245 			un->un_g.dkg_nhead = 2;
2246 			un->un_g.dkg_ncyl = 80;
2247 			un->un_g.dkg_nsect = un->un_blockcount / (2 * 80);
2248 		} else if (un->un_blockcount <= 0x200000) {
2249 			un->un_g.dkg_nhead = 64;
2250 			un->un_g.dkg_nsect = 32;
2251 			un->un_g.dkg_ncyl  = un->un_blockcount / (64 * 32);
2252 		} else {
2253 			un->un_g.dkg_nhead = 255;
2254 			un->un_g.dkg_nsect = 63;
2255 			un->un_g.dkg_ncyl  = un->un_blockcount / (255 * 63);
2256 		}
2257 		un->un_solaris_size =
2258 		    un->un_g.dkg_ncyl * un->un_g.dkg_nhead * un->un_g.dkg_nsect;
2259 
2260 	}
2261 
2262 	un->un_g.dkg_acyl	= 0;
2263 	un->un_g.dkg_bcyl	= 0;
2264 	un->un_g.dkg_rpm	= 200;
2265 	un->un_asciilabel[0]	= '\0';
2266 	un->un_g.dkg_pcyl	= un->un_g.dkg_ncyl;
2267 
2268 	un->un_map[0].dkl_cylno = 0;
2269 	un->un_map[0].dkl_nblk  = un->un_solaris_size;
2270 
2271 	un->un_map[2].dkl_cylno = 0;
2272 	un->un_map[2].dkl_nblk  = un->un_solaris_size;
2273 
2274 #elif defined(_SUNOS_VTOC_16)
2275 
2276 	if (un->un_solaris_size == 0) {
2277 		/*
2278 		 * Got fdisk table but no solaris entry therefore
2279 		 * don't create a default label
2280 		 */
2281 		un->un_f_geometry_is_valid = TRUE;
2282 		return;
2283 	}
2284 
2285 	/*
2286 	 * For CDs we continue to use the physical geometry to calculate
2287 	 * number of cylinders. All other devices must convert the
2288 	 * physical geometry (cmlb_geom) to values that will fit
2289 	 * in a dk_geom structure.
2290 	 */
2291 	if (ISCD(un)) {
2292 		phys_spc = un->un_pgeom.g_nhead * un->un_pgeom.g_nsect;
2293 	} else {
2294 		/* Convert physical geometry to disk geometry */
2295 		bzero(&un_g, sizeof (struct dk_geom));
2296 		cmlb_convert_geometry(un->un_blockcount, &un_g);
2297 		bcopy(&un_g, &un->un_g, sizeof (un->un_g));
2298 		phys_spc = un->un_g.dkg_nhead * un->un_g.dkg_nsect;
2299 	}
2300 
2301 	un->un_g.dkg_pcyl = un->un_solaris_size / phys_spc;
2302 	un->un_g.dkg_acyl = DK_ACYL;
2303 	un->un_g.dkg_ncyl = un->un_g.dkg_pcyl - DK_ACYL;
2304 	disksize = un->un_g.dkg_ncyl * phys_spc;
2305 
2306 	if (ISCD(un)) {
2307 		/*
2308 		 * CD's don't use the "heads * sectors * cyls"-type of
2309 		 * geometry, but instead use the entire capacity of the media.
2310 		 */
2311 		disksize = un->un_solaris_size;
2312 		un->un_g.dkg_nhead = 1;
2313 		un->un_g.dkg_nsect = 1;
2314 		un->un_g.dkg_rpm =
2315 		    (un->un_pgeom.g_rpm == 0) ? 200 : un->un_pgeom.g_rpm;
2316 
2317 		un->un_vtoc.v_part[0].p_start = 0;
2318 		un->un_vtoc.v_part[0].p_size  = disksize;
2319 		un->un_vtoc.v_part[0].p_tag   = V_BACKUP;
2320 		un->un_vtoc.v_part[0].p_flag  = V_UNMNT;
2321 
2322 		un->un_map[0].dkl_cylno = 0;
2323 		un->un_map[0].dkl_nblk  = disksize;
2324 		un->un_offset[0] = 0;
2325 
2326 	} else {
2327 		/*
2328 		 * Hard disks and removable media cartridges
2329 		 */
2330 		un->un_g.dkg_rpm =
2331 		    (un->un_pgeom.g_rpm == 0) ? 3600: un->un_pgeom.g_rpm;
2332 		un->un_vtoc.v_sectorsz = un->un_sys_blocksize;
2333 
2334 		/* Add boot slice */
2335 		un->un_vtoc.v_part[8].p_start = 0;
2336 		un->un_vtoc.v_part[8].p_size  = phys_spc;
2337 		un->un_vtoc.v_part[8].p_tag   = V_BOOT;
2338 		un->un_vtoc.v_part[8].p_flag  = V_UNMNT;
2339 
2340 		un->un_map[8].dkl_cylno = 0;
2341 		un->un_map[8].dkl_nblk  = phys_spc;
2342 		un->un_offset[8] = 0;
2343 
2344 		if ((un->un_alter_behavior &
2345 		    CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT) &&
2346 		    un->un_device_type == DTYPE_DIRECT) {
2347 			un->un_vtoc.v_part[9].p_start = phys_spc;
2348 			un->un_vtoc.v_part[9].p_size  = 2 * phys_spc;
2349 			un->un_vtoc.v_part[9].p_tag   = V_ALTSCTR;
2350 			un->un_vtoc.v_part[9].p_flag  = 0;
2351 
2352 			un->un_map[9].dkl_cylno = 1;
2353 			un->un_map[9].dkl_nblk  = 2 * phys_spc;
2354 			un->un_offset[9] = phys_spc;
2355 		}
2356 	}
2357 
2358 	un->un_g.dkg_apc = 0;
2359 	un->un_vtoc.v_nparts = V_NUMPAR;
2360 	un->un_vtoc.v_version = V_VERSION;
2361 
2362 	/* Add backup slice */
2363 	un->un_vtoc.v_part[2].p_start = 0;
2364 	un->un_vtoc.v_part[2].p_size  = disksize;
2365 	un->un_vtoc.v_part[2].p_tag   = V_BACKUP;
2366 	un->un_vtoc.v_part[2].p_flag  = V_UNMNT;
2367 
2368 	un->un_map[2].dkl_cylno = 0;
2369 	un->un_map[2].dkl_nblk  = disksize;
2370 	un->un_offset[2] = 0;
2371 
2372 	(void) sprintf(un->un_vtoc.v_asciilabel, "DEFAULT cyl %d alt %d"
2373 	    " hd %d sec %d", un->un_g.dkg_ncyl, un->un_g.dkg_acyl,
2374 	    un->un_g.dkg_nhead, un->un_g.dkg_nsect);
2375 
2376 #else
2377 #error "No VTOC format defined."
2378 #endif
2379 
2380 	un->un_g.dkg_read_reinstruct  = 0;
2381 	un->un_g.dkg_write_reinstruct = 0;
2382 
2383 	un->un_g.dkg_intrlv = 1;
2384 
2385 	un->un_vtoc.v_sanity  = VTOC_SANE;
2386 
2387 	un->un_f_geometry_is_valid = TRUE;
2388 	un->un_vtoc_label_is_from_media = 0;
2389 
2390 	cmlb_dbg(CMLB_INFO,  un,
2391 	    "cmlb_build_default_label: Default label created: "
2392 	    "cyl: %d\tacyl: %d\tnhead: %d\tnsect: %d\tcap: %d\n",
2393 	    un->un_g.dkg_ncyl, un->un_g.dkg_acyl, un->un_g.dkg_nhead,
2394 	    un->un_g.dkg_nsect, un->un_blockcount);
2395 }
2396 
2397 
2398 #if defined(_FIRMWARE_NEEDS_FDISK)
2399 /*
2400  * Max CHS values, as they are encoded into bytes, for 1022/254/63
2401  */
2402 #define	LBA_MAX_SECT	(63 | ((1022 & 0x300) >> 2))
2403 #define	LBA_MAX_CYL	(1022 & 0xFF)
2404 #define	LBA_MAX_HEAD	(254)
2405 
2406 
2407 /*
2408  *    Function: cmlb_has_max_chs_vals
2409  *
2410  * Description: Return TRUE if Cylinder-Head-Sector values are all at maximum.
2411  *
2412  *   Arguments: fdp - ptr to CHS info
2413  *
2414  * Return Code: True or false
2415  *
2416  *     Context: Any.
2417  */
2418 static int
2419 cmlb_has_max_chs_vals(struct ipart *fdp)
2420 {
2421 	return ((fdp->begcyl  == LBA_MAX_CYL)	&&
2422 	    (fdp->beghead == LBA_MAX_HEAD)	&&
2423 	    (fdp->begsect == LBA_MAX_SECT)	&&
2424 	    (fdp->endcyl  == LBA_MAX_CYL)	&&
2425 	    (fdp->endhead == LBA_MAX_HEAD)	&&
2426 	    (fdp->endsect == LBA_MAX_SECT));
2427 }
2428 #endif
2429 
2430 /*
2431  *    Function: cmlb_dkio_get_geometry
2432  *
2433  * Description: This routine is the driver entry point for handling user
2434  *		requests to get the device geometry (DKIOCGGEOM).
2435  *
2436  *   Arguments:
2437  *		arg  - pointer to user provided dk_geom structure specifying
2438  *			the controller's notion of the current geometry.
2439  *		flag - this argument is a pass through to ddi_copyxxx()
2440  *		       directly from the mode argument of ioctl().
2441  *
2442  * Return Code: 0
2443  *		EFAULT
2444  *		ENXIO
2445  *		EIO
2446  */
2447 static int
2448 cmlb_dkio_get_geometry(struct cmlb_lun *un, caddr_t arg, int flag)
2449 {
2450 	struct dk_geom	*tmp_geom = NULL;
2451 	int		rval = 0;
2452 
2453 	/*
2454 	 * cmlb_validate_geometry does not spin a disk up
2455 	 * if it was spun down. We need to make sure it
2456 	 * is ready.
2457 	 */
2458 	mutex_enter(CMLB_MUTEX(un));
2459 	rval = cmlb_validate_geometry(un, 1);
2460 #if defined(_SUNOS_VTOC_8)
2461 	if (rval == EINVAL &&
2462 	    un->un_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8) {
2463 		/*
2464 		 * This is to return a default label geometry even when we
2465 		 * do not really assume a default label for the device.
2466 		 * dad driver utilizes this.
2467 		 */
2468 		if (un->un_blockcount <= DK_MAX_BLOCKS) {
2469 			cmlb_setup_default_geometry(un);
2470 			rval = 0;
2471 		}
2472 	}
2473 #endif
2474 	if (rval) {
2475 		mutex_exit(CMLB_MUTEX(un));
2476 		return (rval);
2477 	}
2478 
2479 #if defined(__i386) || defined(__amd64)
2480 	if (un->un_solaris_size == 0) {
2481 		mutex_exit(CMLB_MUTEX(un));
2482 		return (EIO);
2483 	}
2484 #endif
2485 
2486 	/*
2487 	 * Make a local copy of the soft state geometry to avoid some potential
2488 	 * race conditions associated with holding the mutex and updating the
2489 	 * write_reinstruct value
2490 	 */
2491 	tmp_geom = kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP);
2492 	bcopy(&un->un_g, tmp_geom, sizeof (struct dk_geom));
2493 
2494 	if (tmp_geom->dkg_write_reinstruct == 0) {
2495 		tmp_geom->dkg_write_reinstruct =
2496 		    (int)((int)(tmp_geom->dkg_nsect * tmp_geom->dkg_rpm *
2497 		    cmlb_rot_delay) / (int)60000);
2498 	}
2499 	mutex_exit(CMLB_MUTEX(un));
2500 
2501 	rval = ddi_copyout(tmp_geom, (void *)arg, sizeof (struct dk_geom),
2502 	    flag);
2503 	if (rval != 0) {
2504 		rval = EFAULT;
2505 	}
2506 
2507 	kmem_free(tmp_geom, sizeof (struct dk_geom));
2508 	return (rval);
2509 
2510 }
2511 
2512 
2513 /*
2514  *    Function: cmlb_dkio_set_geometry
2515  *
2516  * Description: This routine is the driver entry point for handling user
2517  *		requests to set the device geometry (DKIOCSGEOM). The actual
2518  *		device geometry is not updated, just the driver "notion" of it.
2519  *
2520  *   Arguments:
2521  *		arg  - pointer to user provided dk_geom structure used to set
2522  *			the controller's notion of the current geometry.
2523  *		flag - this argument is a pass through to ddi_copyxxx()
2524  *		       directly from the mode argument of ioctl().
2525  *
2526  * Return Code: 0
2527  *		EFAULT
2528  *		ENXIO
2529  *		EIO
2530  */
2531 static int
2532 cmlb_dkio_set_geometry(struct cmlb_lun *un, caddr_t arg, int flag)
2533 {
2534 	struct dk_geom	*tmp_geom;
2535 	struct dk_map	*lp;
2536 	int		rval = 0;
2537 	int		i;
2538 
2539 
2540 #if defined(__i386) || defined(__amd64)
2541 	if (un->un_solaris_size == 0) {
2542 		return (EIO);
2543 	}
2544 #endif
2545 	/*
2546 	 * We need to copy the user specified geometry into local
2547 	 * storage and then update the softstate. We don't want to hold
2548 	 * the mutex and copyin directly from the user to the soft state
2549 	 */
2550 	tmp_geom = (struct dk_geom *)
2551 	    kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP);
2552 	rval = ddi_copyin(arg, tmp_geom, sizeof (struct dk_geom), flag);
2553 	if (rval != 0) {
2554 		kmem_free(tmp_geom, sizeof (struct dk_geom));
2555 		return (EFAULT);
2556 	}
2557 
2558 	mutex_enter(CMLB_MUTEX(un));
2559 	bcopy(tmp_geom, &un->un_g, sizeof (struct dk_geom));
2560 	for (i = 0; i < NDKMAP; i++) {
2561 		lp  = &un->un_map[i];
2562 		un->un_offset[i] =
2563 		    un->un_g.dkg_nhead * un->un_g.dkg_nsect * lp->dkl_cylno;
2564 #if defined(__i386) || defined(__amd64)
2565 		un->un_offset[i] += un->un_solaris_offset;
2566 #endif
2567 	}
2568 	un->un_f_geometry_is_valid = FALSE;
2569 	mutex_exit(CMLB_MUTEX(un));
2570 	kmem_free(tmp_geom, sizeof (struct dk_geom));
2571 
2572 	return (rval);
2573 }
2574 
2575 /*
2576  *    Function: cmlb_dkio_get_partition
2577  *
2578  * Description: This routine is the driver entry point for handling user
2579  *		requests to get the partition table (DKIOCGAPART).
2580  *
2581  *   Arguments:
2582  *		arg  - pointer to user provided dk_allmap structure specifying
2583  *			the controller's notion of the current partition table.
2584  *		flag - this argument is a pass through to ddi_copyxxx()
2585  *		       directly from the mode argument of ioctl().
2586  *
2587  * Return Code: 0
2588  *		EFAULT
2589  *		ENXIO
2590  *		EIO
2591  */
2592 static int
2593 cmlb_dkio_get_partition(struct cmlb_lun *un, caddr_t arg, int flag)
2594 {
2595 	int		rval = 0;
2596 	int		size;
2597 
2598 	/*
2599 	 * Make sure the geometry is valid before getting the partition
2600 	 * information.
2601 	 */
2602 	mutex_enter(CMLB_MUTEX(un));
2603 	if ((rval = cmlb_validate_geometry(un, 1)) != 0) {
2604 		mutex_exit(CMLB_MUTEX(un));
2605 		return (rval);
2606 	}
2607 	mutex_exit(CMLB_MUTEX(un));
2608 
2609 #if defined(__i386) || defined(__amd64)
2610 	if (un->un_solaris_size == 0) {
2611 		return (EIO);
2612 	}
2613 #endif
2614 
2615 #ifdef _MULTI_DATAMODEL
2616 	switch (ddi_model_convert_from(flag & FMODELS)) {
2617 	case DDI_MODEL_ILP32: {
2618 		struct dk_map32 dk_map32[NDKMAP];
2619 		int		i;
2620 
2621 		for (i = 0; i < NDKMAP; i++) {
2622 			dk_map32[i].dkl_cylno = un->un_map[i].dkl_cylno;
2623 			dk_map32[i].dkl_nblk  = un->un_map[i].dkl_nblk;
2624 		}
2625 		size = NDKMAP * sizeof (struct dk_map32);
2626 		rval = ddi_copyout(dk_map32, (void *)arg, size, flag);
2627 		if (rval != 0) {
2628 			rval = EFAULT;
2629 		}
2630 		break;
2631 	}
2632 	case DDI_MODEL_NONE:
2633 		size = NDKMAP * sizeof (struct dk_map);
2634 		rval = ddi_copyout(un->un_map, (void *)arg, size, flag);
2635 		if (rval != 0) {
2636 			rval = EFAULT;
2637 		}
2638 		break;
2639 	}
2640 #else /* ! _MULTI_DATAMODEL */
2641 	size = NDKMAP * sizeof (struct dk_map);
2642 	rval = ddi_copyout(un->un_map, (void *)arg, size, flag);
2643 	if (rval != 0) {
2644 		rval = EFAULT;
2645 	}
2646 #endif /* _MULTI_DATAMODEL */
2647 	return (rval);
2648 }
2649 
2650 /*
2651  *    Function: cmlb_dkio_set_partition
2652  *
2653  * Description: This routine is the driver entry point for handling user
2654  *		requests to set the partition table (DKIOCSAPART). The actual
2655  *		device partition is not updated.
2656  *
2657  *   Arguments:
2658  *		arg  - pointer to user provided dk_allmap structure used to set
2659  *			the controller's notion of the partition table.
2660  *		flag - this argument is a pass through to ddi_copyxxx()
2661  *		       directly from the mode argument of ioctl().
2662  *
2663  * Return Code: 0
2664  *		EINVAL
2665  *		EFAULT
2666  *		ENXIO
2667  *		EIO
2668  */
2669 static int
2670 cmlb_dkio_set_partition(struct cmlb_lun *un, caddr_t arg, int flag)
2671 {
2672 	struct dk_map	dk_map[NDKMAP];
2673 	struct dk_map	*lp;
2674 	int		rval = 0;
2675 	int		size;
2676 	int		i;
2677 #if defined(_SUNOS_VTOC_16)
2678 	struct dkl_partition	*vp;
2679 #endif
2680 
2681 	/*
2682 	 * Set the map for all logical partitions.  We lock
2683 	 * the priority just to make sure an interrupt doesn't
2684 	 * come in while the map is half updated.
2685 	 */
2686 	_NOTE(DATA_READABLE_WITHOUT_LOCK(cmlb_lun::un_solaris_size))
2687 	mutex_enter(CMLB_MUTEX(un));
2688 
2689 	if (un->un_blockcount > DK_MAX_BLOCKS) {
2690 		mutex_exit(CMLB_MUTEX(un));
2691 		return (ENOTSUP);
2692 	}
2693 	mutex_exit(CMLB_MUTEX(un));
2694 	if (un->un_solaris_size == 0) {
2695 		return (EIO);
2696 	}
2697 
2698 #ifdef _MULTI_DATAMODEL
2699 	switch (ddi_model_convert_from(flag & FMODELS)) {
2700 	case DDI_MODEL_ILP32: {
2701 		struct dk_map32 dk_map32[NDKMAP];
2702 
2703 		size = NDKMAP * sizeof (struct dk_map32);
2704 		rval = ddi_copyin((void *)arg, dk_map32, size, flag);
2705 		if (rval != 0) {
2706 			return (EFAULT);
2707 		}
2708 		for (i = 0; i < NDKMAP; i++) {
2709 			dk_map[i].dkl_cylno = dk_map32[i].dkl_cylno;
2710 			dk_map[i].dkl_nblk  = dk_map32[i].dkl_nblk;
2711 		}
2712 		break;
2713 	}
2714 	case DDI_MODEL_NONE:
2715 		size = NDKMAP * sizeof (struct dk_map);
2716 		rval = ddi_copyin((void *)arg, dk_map, size, flag);
2717 		if (rval != 0) {
2718 			return (EFAULT);
2719 		}
2720 		break;
2721 	}
2722 #else /* ! _MULTI_DATAMODEL */
2723 	size = NDKMAP * sizeof (struct dk_map);
2724 	rval = ddi_copyin((void *)arg, dk_map, size, flag);
2725 	if (rval != 0) {
2726 		return (EFAULT);
2727 	}
2728 #endif /* _MULTI_DATAMODEL */
2729 
2730 	mutex_enter(CMLB_MUTEX(un));
2731 	/* Note: The size used in this bcopy is set based upon the data model */
2732 	bcopy(dk_map, un->un_map, size);
2733 #if defined(_SUNOS_VTOC_16)
2734 	vp = (struct dkl_partition *)&(un->un_vtoc);
2735 #endif	/* defined(_SUNOS_VTOC_16) */
2736 	for (i = 0; i < NDKMAP; i++) {
2737 		lp  = &un->un_map[i];
2738 		un->un_offset[i] =
2739 		    un->un_g.dkg_nhead * un->un_g.dkg_nsect * lp->dkl_cylno;
2740 #if defined(_SUNOS_VTOC_16)
2741 		vp->p_start = un->un_offset[i];
2742 		vp->p_size = lp->dkl_nblk;
2743 		vp++;
2744 #endif	/* defined(_SUNOS_VTOC_16) */
2745 #if defined(__i386) || defined(__amd64)
2746 		un->un_offset[i] += un->un_solaris_offset;
2747 #endif
2748 	}
2749 	mutex_exit(CMLB_MUTEX(un));
2750 	return (rval);
2751 }
2752 
2753 
2754 /*
2755  *    Function: cmlb_dkio_get_vtoc
2756  *
2757  * Description: This routine is the driver entry point for handling user
2758  *		requests to get the current volume table of contents
2759  *		(DKIOCGVTOC).
2760  *
2761  *   Arguments:
2762  *		arg  - pointer to user provided vtoc structure specifying
2763  *			the current vtoc.
2764  *		flag - this argument is a pass through to ddi_copyxxx()
2765  *		       directly from the mode argument of ioctl().
2766  *
2767  * Return Code: 0
2768  *		EFAULT
2769  *		ENXIO
2770  *		EIO
2771  */
2772 static int
2773 cmlb_dkio_get_vtoc(struct cmlb_lun *un, caddr_t arg, int flag)
2774 {
2775 #if defined(_SUNOS_VTOC_8)
2776 	struct vtoc	user_vtoc;
2777 #endif	/* defined(_SUNOS_VTOC_8) */
2778 	int		rval = 0;
2779 
2780 	mutex_enter(CMLB_MUTEX(un));
2781 	rval = cmlb_validate_geometry(un, 1);
2782 
2783 #if defined(_SUNOS_VTOC_8)
2784 	if (rval == EINVAL &&
2785 	    (un->un_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8)) {
2786 		/*
2787 		 * This is to return a default label even when we do not
2788 		 * really assume a default label for the device.
2789 		 * dad driver utilizes this.
2790 		 */
2791 		if (un->un_blockcount <= DK_MAX_BLOCKS) {
2792 			cmlb_setup_default_geometry(un);
2793 			rval = 0;
2794 		}
2795 	}
2796 #endif
2797 	if (rval) {
2798 		mutex_exit(CMLB_MUTEX(un));
2799 		return (rval);
2800 	}
2801 
2802 #if defined(_SUNOS_VTOC_8)
2803 	cmlb_build_user_vtoc(un, &user_vtoc);
2804 	mutex_exit(CMLB_MUTEX(un));
2805 
2806 #ifdef _MULTI_DATAMODEL
2807 	switch (ddi_model_convert_from(flag & FMODELS)) {
2808 	case DDI_MODEL_ILP32: {
2809 		struct vtoc32 user_vtoc32;
2810 
2811 		vtoctovtoc32(user_vtoc, user_vtoc32);
2812 		if (ddi_copyout(&user_vtoc32, (void *)arg,
2813 		    sizeof (struct vtoc32), flag)) {
2814 			return (EFAULT);
2815 		}
2816 		break;
2817 	}
2818 
2819 	case DDI_MODEL_NONE:
2820 		if (ddi_copyout(&user_vtoc, (void *)arg,
2821 		    sizeof (struct vtoc), flag)) {
2822 			return (EFAULT);
2823 		}
2824 		break;
2825 	}
2826 #else /* ! _MULTI_DATAMODEL */
2827 	if (ddi_copyout(&user_vtoc, (void *)arg, sizeof (struct vtoc), flag)) {
2828 		return (EFAULT);
2829 	}
2830 #endif /* _MULTI_DATAMODEL */
2831 
2832 #elif defined(_SUNOS_VTOC_16)
2833 	mutex_exit(CMLB_MUTEX(un));
2834 
2835 #ifdef _MULTI_DATAMODEL
2836 	/*
2837 	 * The un_vtoc structure is a "struct dk_vtoc"  which is always
2838 	 * 32-bit to maintain compatibility with existing on-disk
2839 	 * structures.  Thus, we need to convert the structure when copying
2840 	 * it out to a datamodel-dependent "struct vtoc" in a 64-bit
2841 	 * program.  If the target is a 32-bit program, then no conversion
2842 	 * is necessary.
2843 	 */
2844 	/* LINTED: logical expression always true: op "||" */
2845 	ASSERT(sizeof (un->un_vtoc) == sizeof (struct vtoc32));
2846 	switch (ddi_model_convert_from(flag & FMODELS)) {
2847 	case DDI_MODEL_ILP32:
2848 		if (ddi_copyout(&(un->un_vtoc), (void *)arg,
2849 		    sizeof (un->un_vtoc), flag)) {
2850 			return (EFAULT);
2851 		}
2852 		break;
2853 
2854 	case DDI_MODEL_NONE: {
2855 		struct vtoc user_vtoc;
2856 
2857 		vtoc32tovtoc(un->un_vtoc, user_vtoc);
2858 		if (ddi_copyout(&user_vtoc, (void *)arg,
2859 		    sizeof (struct vtoc), flag)) {
2860 			return (EFAULT);
2861 		}
2862 		break;
2863 	}
2864 	}
2865 #else /* ! _MULTI_DATAMODEL */
2866 	if (ddi_copyout(&(un->un_vtoc), (void *)arg, sizeof (un->un_vtoc),
2867 	    flag)) {
2868 		return (EFAULT);
2869 	}
2870 #endif /* _MULTI_DATAMODEL */
2871 #else
2872 #error "No VTOC format defined."
2873 #endif
2874 
2875 	return (rval);
2876 }
2877 
2878 static int
2879 cmlb_dkio_get_efi(struct cmlb_lun *un, caddr_t arg, int flag)
2880 {
2881 	dk_efi_t	user_efi;
2882 	int		rval = 0;
2883 	void		*buffer;
2884 
2885 	if (ddi_copyin(arg, &user_efi, sizeof (dk_efi_t), flag))
2886 		return (EFAULT);
2887 
2888 	user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64;
2889 
2890 	buffer = kmem_alloc(user_efi.dki_length, KM_SLEEP);
2891 	rval = DK_TG_READ(un, buffer, user_efi.dki_lba, user_efi.dki_length);
2892 	if (rval == 0 && ddi_copyout(buffer, user_efi.dki_data,
2893 	    user_efi.dki_length, flag) != 0)
2894 		rval = EFAULT;
2895 
2896 	kmem_free(buffer, user_efi.dki_length);
2897 	return (rval);
2898 }
2899 
2900 /*
2901  *    Function: cmlb_build_user_vtoc
2902  *
2903  * Description: This routine populates a pass by reference variable with the
2904  *		current volume table of contents.
2905  *
2906  *   Arguments: un - driver soft state (unit) structure
2907  *		user_vtoc - pointer to vtoc structure to be populated
2908  */
2909 static void
2910 cmlb_build_user_vtoc(struct cmlb_lun *un, struct vtoc *user_vtoc)
2911 {
2912 	struct dk_map2		*lpart;
2913 	struct dk_map		*lmap;
2914 	struct partition	*vpart;
2915 	int			nblks;
2916 	int			i;
2917 
2918 	ASSERT(mutex_owned(CMLB_MUTEX(un)));
2919 
2920 	/*
2921 	 * Return vtoc structure fields in the provided VTOC area, addressed
2922 	 * by *vtoc.
2923 	 */
2924 	bzero(user_vtoc, sizeof (struct vtoc));
2925 	user_vtoc->v_bootinfo[0] = un->un_vtoc.v_bootinfo[0];
2926 	user_vtoc->v_bootinfo[1] = un->un_vtoc.v_bootinfo[1];
2927 	user_vtoc->v_bootinfo[2] = un->un_vtoc.v_bootinfo[2];
2928 	user_vtoc->v_sanity	= VTOC_SANE;
2929 	user_vtoc->v_version	= un->un_vtoc.v_version;
2930 	bcopy(un->un_vtoc.v_volume, user_vtoc->v_volume, LEN_DKL_VVOL);
2931 	user_vtoc->v_sectorsz = un->un_sys_blocksize;
2932 	user_vtoc->v_nparts = un->un_vtoc.v_nparts;
2933 
2934 	for (i = 0; i < 10; i++)
2935 		user_vtoc->v_reserved[i] = un->un_vtoc.v_reserved[i];
2936 
2937 	/*
2938 	 * Convert partitioning information.
2939 	 *
2940 	 * Note the conversion from starting cylinder number
2941 	 * to starting sector number.
2942 	 */
2943 	lmap = un->un_map;
2944 	lpart = (struct dk_map2 *)un->un_vtoc.v_part;
2945 	vpart = user_vtoc->v_part;
2946 
2947 	nblks = un->un_g.dkg_nsect * un->un_g.dkg_nhead;
2948 
2949 	for (i = 0; i < V_NUMPAR; i++) {
2950 		vpart->p_tag	= lpart->p_tag;
2951 		vpart->p_flag	= lpart->p_flag;
2952 		vpart->p_start	= lmap->dkl_cylno * nblks;
2953 		vpart->p_size	= lmap->dkl_nblk;
2954 		lmap++;
2955 		lpart++;
2956 		vpart++;
2957 
2958 		/* (4364927) */
2959 		user_vtoc->timestamp[i] = (time_t)un->un_vtoc.v_timestamp[i];
2960 	}
2961 
2962 	bcopy(un->un_asciilabel, user_vtoc->v_asciilabel, LEN_DKL_ASCII);
2963 }
2964 
2965 static int
2966 cmlb_dkio_partition(struct cmlb_lun *un, caddr_t arg, int flag)
2967 {
2968 	struct partition64	p64;
2969 	int			rval = 0;
2970 	uint_t			nparts;
2971 	efi_gpe_t		*partitions;
2972 	efi_gpt_t		*buffer;
2973 	diskaddr_t		gpe_lba;
2974 
2975 	if (ddi_copyin((const void *)arg, &p64,
2976 	    sizeof (struct partition64), flag)) {
2977 		return (EFAULT);
2978 	}
2979 
2980 	buffer = kmem_alloc(EFI_MIN_ARRAY_SIZE, KM_SLEEP);
2981 	rval = DK_TG_READ(un, buffer, 1, DEV_BSIZE);
2982 	if (rval != 0)
2983 		goto done_error;
2984 
2985 	cmlb_swap_efi_gpt(buffer);
2986 
2987 	if ((rval = cmlb_validate_efi(buffer)) != 0)
2988 		goto done_error;
2989 
2990 	nparts = buffer->efi_gpt_NumberOfPartitionEntries;
2991 	gpe_lba = buffer->efi_gpt_PartitionEntryLBA;
2992 	if (p64.p_partno > nparts) {
2993 		/* couldn't find it */
2994 		rval = ESRCH;
2995 		goto done_error;
2996 	}
2997 	/*
2998 	 * if we're dealing with a partition that's out of the normal
2999 	 * 16K block, adjust accordingly
3000 	 */
3001 	gpe_lba += p64.p_partno / sizeof (efi_gpe_t);
3002 	rval = DK_TG_READ(un, buffer, gpe_lba, EFI_MIN_ARRAY_SIZE);
3003 
3004 	if (rval) {
3005 		goto done_error;
3006 	}
3007 	partitions = (efi_gpe_t *)buffer;
3008 
3009 	cmlb_swap_efi_gpe(nparts, partitions);
3010 
3011 	partitions += p64.p_partno;
3012 	bcopy(&partitions->efi_gpe_PartitionTypeGUID, &p64.p_type,
3013 	    sizeof (struct uuid));
3014 	p64.p_start = partitions->efi_gpe_StartingLBA;
3015 	p64.p_size = partitions->efi_gpe_EndingLBA -
3016 			p64.p_start + 1;
3017 
3018 	if (ddi_copyout(&p64, (void *)arg, sizeof (struct partition64), flag))
3019 		rval = EFAULT;
3020 
3021 done_error:
3022 	kmem_free(buffer, EFI_MIN_ARRAY_SIZE);
3023 	return (rval);
3024 }
3025 
3026 
3027 /*
3028  *    Function: cmlb_dkio_set_vtoc
3029  *
3030  * Description: This routine is the driver entry point for handling user
3031  *		requests to set the current volume table of contents
3032  *		(DKIOCSVTOC).
3033  *
3034  *   Arguments: dev  - the device number
3035  *		arg  - pointer to user provided vtoc structure used to set the
3036  *			current vtoc.
3037  *		flag - this argument is a pass through to ddi_copyxxx()
3038  *		       directly from the mode argument of ioctl().
3039  *
3040  * Return Code: 0
3041  *		EFAULT
3042  *		ENXIO
3043  *		EINVAL
3044  *		ENOTSUP
3045  */
3046 static int
3047 cmlb_dkio_set_vtoc(struct cmlb_lun *un, dev_t dev, caddr_t arg, int flag)
3048 {
3049 	struct vtoc	user_vtoc;
3050 	int		rval = 0;
3051 
3052 #ifdef _MULTI_DATAMODEL
3053 	switch (ddi_model_convert_from(flag & FMODELS)) {
3054 	case DDI_MODEL_ILP32: {
3055 		struct vtoc32 user_vtoc32;
3056 
3057 		if (ddi_copyin((const void *)arg, &user_vtoc32,
3058 		    sizeof (struct vtoc32), flag)) {
3059 			return (EFAULT);
3060 		}
3061 		vtoc32tovtoc(user_vtoc32, user_vtoc);
3062 		break;
3063 	}
3064 
3065 	case DDI_MODEL_NONE:
3066 		if (ddi_copyin((const void *)arg, &user_vtoc,
3067 		    sizeof (struct vtoc), flag)) {
3068 			return (EFAULT);
3069 		}
3070 		break;
3071 	}
3072 #else /* ! _MULTI_DATAMODEL */
3073 	if (ddi_copyin((const void *)arg, &user_vtoc,
3074 	    sizeof (struct vtoc), flag)) {
3075 		return (EFAULT);
3076 	}
3077 #endif /* _MULTI_DATAMODEL */
3078 
3079 	mutex_enter(CMLB_MUTEX(un));
3080 	if (un->un_blockcount > DK_MAX_BLOCKS) {
3081 		mutex_exit(CMLB_MUTEX(un));
3082 		return (ENOTSUP);
3083 	}
3084 	if (un->un_g.dkg_ncyl == 0) {
3085 		mutex_exit(CMLB_MUTEX(un));
3086 		return (EINVAL);
3087 	}
3088 
3089 	mutex_exit(CMLB_MUTEX(un));
3090 	cmlb_clear_efi(un);
3091 	ddi_remove_minor_node(CMLB_DEVINFO(un), "wd");
3092 	ddi_remove_minor_node(CMLB_DEVINFO(un), "wd,raw");
3093 	(void) ddi_create_minor_node(CMLB_DEVINFO(un), "h",
3094 	    S_IFBLK, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE,
3095 	    un->un_node_type, NULL);
3096 	(void) ddi_create_minor_node(CMLB_DEVINFO(un), "h,raw",
3097 	    S_IFCHR, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE,
3098 	    un->un_node_type, NULL);
3099 	mutex_enter(CMLB_MUTEX(un));
3100 
3101 	if ((rval = cmlb_build_label_vtoc(un, &user_vtoc)) == 0) {
3102 		if ((rval = cmlb_write_label(un)) == 0) {
3103 			if (cmlb_validate_geometry(un, 1) != 0) {
3104 				cmlb_dbg(CMLB_ERROR, un,
3105 				    "cmlb_dkio_set_vtoc: "
3106 				    "Failed validate geometry\n");
3107 			}
3108 		}
3109 	}
3110 	mutex_exit(CMLB_MUTEX(un));
3111 	return (rval);
3112 }
3113 
3114 
3115 /*
3116  *    Function: cmlb_build_label_vtoc
3117  *
3118  * Description: This routine updates the driver soft state current volume table
3119  *		of contents based on a user specified vtoc.
3120  *
3121  *   Arguments: un - driver soft state (unit) structure
3122  *		user_vtoc - pointer to vtoc structure specifying vtoc to be used
3123  *			    to update the driver soft state.
3124  *
3125  * Return Code: 0
3126  *		EINVAL
3127  */
3128 static int
3129 cmlb_build_label_vtoc(struct cmlb_lun *un, struct vtoc *user_vtoc)
3130 {
3131 	struct dk_map		*lmap;
3132 	struct partition	*vpart;
3133 	int			nblks;
3134 #if defined(_SUNOS_VTOC_8)
3135 	int			ncyl;
3136 	struct dk_map2		*lpart;
3137 #endif	/* defined(_SUNOS_VTOC_8) */
3138 	int			i;
3139 
3140 	ASSERT(mutex_owned(CMLB_MUTEX(un)));
3141 
3142 	/* Sanity-check the vtoc */
3143 	if (user_vtoc->v_sanity != VTOC_SANE ||
3144 	    user_vtoc->v_sectorsz != un->un_sys_blocksize ||
3145 	    user_vtoc->v_nparts != V_NUMPAR) {
3146 		cmlb_dbg(CMLB_INFO,  un,
3147 		    "cmlb_build_label_vtoc: vtoc not valid\n");
3148 		return (EINVAL);
3149 	}
3150 
3151 	nblks = un->un_g.dkg_nsect * un->un_g.dkg_nhead;
3152 	if (nblks == 0) {
3153 		cmlb_dbg(CMLB_INFO,  un,
3154 		    "cmlb_build_label_vtoc: geom nblks is 0\n");
3155 		return (EINVAL);
3156 	}
3157 
3158 #if defined(_SUNOS_VTOC_8)
3159 	vpart = user_vtoc->v_part;
3160 	for (i = 0; i < V_NUMPAR; i++) {
3161 		if ((vpart->p_start % nblks) != 0) {
3162 			cmlb_dbg(CMLB_INFO,  un,
3163 			    "cmlb_build_label_vtoc: p_start not multiply of"
3164 			    "nblks part %d p_start %d nblks %d\n", i,
3165 			    vpart->p_start, nblks);
3166 			return (EINVAL);
3167 		}
3168 		ncyl = vpart->p_start / nblks;
3169 		ncyl += vpart->p_size / nblks;
3170 		if ((vpart->p_size % nblks) != 0) {
3171 			ncyl++;
3172 		}
3173 		if (ncyl > (int)un->un_g.dkg_ncyl) {
3174 			cmlb_dbg(CMLB_INFO,  un,
3175 			    "cmlb_build_label_vtoc: ncyl %d  > dkg_ncyl %d"
3176 			    "p_size %ld p_start %ld nblks %d  part number %d"
3177 			    "tag %d\n",
3178 			    ncyl, un->un_g.dkg_ncyl, vpart->p_size,
3179 			    vpart->p_start, nblks,
3180 			    i, vpart->p_tag);
3181 
3182 			return (EINVAL);
3183 		}
3184 		vpart++;
3185 	}
3186 #endif	/* defined(_SUNOS_VTOC_8) */
3187 
3188 	/* Put appropriate vtoc structure fields into the disk label */
3189 #if defined(_SUNOS_VTOC_16)
3190 	/*
3191 	 * The vtoc is always a 32bit data structure to maintain the
3192 	 * on-disk format. Convert "in place" instead of doing bcopy.
3193 	 */
3194 	vtoctovtoc32((*user_vtoc), (*((struct vtoc32 *)&(un->un_vtoc))));
3195 
3196 	/*
3197 	 * in the 16-slice vtoc, starting sectors are expressed in
3198 	 * numbers *relative* to the start of the Solaris fdisk partition.
3199 	 */
3200 	lmap = un->un_map;
3201 	vpart = user_vtoc->v_part;
3202 
3203 	for (i = 0; i < (int)user_vtoc->v_nparts; i++, lmap++, vpart++) {
3204 		lmap->dkl_cylno = vpart->p_start / nblks;
3205 		lmap->dkl_nblk = vpart->p_size;
3206 	}
3207 
3208 #elif defined(_SUNOS_VTOC_8)
3209 
3210 	un->un_vtoc.v_bootinfo[0] = (uint32_t)user_vtoc->v_bootinfo[0];
3211 	un->un_vtoc.v_bootinfo[1] = (uint32_t)user_vtoc->v_bootinfo[1];
3212 	un->un_vtoc.v_bootinfo[2] = (uint32_t)user_vtoc->v_bootinfo[2];
3213 
3214 	un->un_vtoc.v_sanity = (uint32_t)user_vtoc->v_sanity;
3215 	un->un_vtoc.v_version = (uint32_t)user_vtoc->v_version;
3216 
3217 	bcopy(user_vtoc->v_volume, un->un_vtoc.v_volume, LEN_DKL_VVOL);
3218 
3219 	un->un_vtoc.v_nparts = user_vtoc->v_nparts;
3220 
3221 	for (i = 0; i < 10; i++)
3222 		un->un_vtoc.v_reserved[i] =  user_vtoc->v_reserved[i];
3223 
3224 	/*
3225 	 * Note the conversion from starting sector number
3226 	 * to starting cylinder number.
3227 	 * Return error if division results in a remainder.
3228 	 */
3229 	lmap = un->un_map;
3230 	lpart = un->un_vtoc.v_part;
3231 	vpart = user_vtoc->v_part;
3232 
3233 	for (i = 0; i < (int)user_vtoc->v_nparts; i++) {
3234 		lpart->p_tag  = vpart->p_tag;
3235 		lpart->p_flag = vpart->p_flag;
3236 		lmap->dkl_cylno = vpart->p_start / nblks;
3237 		lmap->dkl_nblk = vpart->p_size;
3238 
3239 		lmap++;
3240 		lpart++;
3241 		vpart++;
3242 
3243 		/* (4387723) */
3244 #ifdef _LP64
3245 		if (user_vtoc->timestamp[i] > TIME32_MAX) {
3246 			un->un_vtoc.v_timestamp[i] = TIME32_MAX;
3247 		} else {
3248 			un->un_vtoc.v_timestamp[i] = user_vtoc->timestamp[i];
3249 		}
3250 #else
3251 		un->un_vtoc.v_timestamp[i] = user_vtoc->timestamp[i];
3252 #endif
3253 	}
3254 
3255 	bcopy(user_vtoc->v_asciilabel, un->un_asciilabel, LEN_DKL_ASCII);
3256 #else
3257 #error "No VTOC format defined."
3258 #endif
3259 	return (0);
3260 }
3261 
3262 /*
3263  *    Function: cmlb_clear_efi
3264  *
3265  * Description: This routine clears all EFI labels.
3266  *
3267  *   Arguments: un - driver soft state (unit) structure
3268  *
3269  * Return Code: void
3270  */
3271 static void
3272 cmlb_clear_efi(struct cmlb_lun *un)
3273 {
3274 	efi_gpt_t	*gpt;
3275 	diskaddr_t	cap;
3276 	int		rval;
3277 
3278 	ASSERT(!mutex_owned(CMLB_MUTEX(un)));
3279 
3280 	gpt = kmem_alloc(sizeof (efi_gpt_t), KM_SLEEP);
3281 
3282 	if (DK_TG_READ(un, gpt, 1, DEV_BSIZE) != 0) {
3283 		goto done;
3284 	}
3285 
3286 	cmlb_swap_efi_gpt(gpt);
3287 	rval = cmlb_validate_efi(gpt);
3288 	if (rval == 0) {
3289 		/* clear primary */
3290 		bzero(gpt, sizeof (efi_gpt_t));
3291 		if (rval = DK_TG_WRITE(un, gpt, 1, EFI_LABEL_SIZE)) {
3292 			cmlb_dbg(CMLB_INFO,  un,
3293 				"cmlb_clear_efi: clear primary label failed\n");
3294 		}
3295 	}
3296 	/* the backup */
3297 	rval = DK_TG_GETCAP(un, &cap);
3298 	if (rval) {
3299 		goto done;
3300 	}
3301 
3302 	if ((rval = DK_TG_READ(un, gpt, cap - 1, EFI_LABEL_SIZE)) != 0) {
3303 		goto done;
3304 	}
3305 	cmlb_swap_efi_gpt(gpt);
3306 	rval = cmlb_validate_efi(gpt);
3307 	if (rval == 0) {
3308 		/* clear backup */
3309 		cmlb_dbg(CMLB_TRACE,  un,
3310 		    "cmlb_clear_efi clear backup@%lu\n", cap - 1);
3311 		bzero(gpt, sizeof (efi_gpt_t));
3312 		if ((rval = DK_TG_WRITE(un, gpt, cap - 1, EFI_LABEL_SIZE))) {
3313 			cmlb_dbg(CMLB_INFO,  un,
3314 				"cmlb_clear_efi: clear backup label failed\n");
3315 		}
3316 	}
3317 
3318 done:
3319 	kmem_free(gpt, sizeof (efi_gpt_t));
3320 }
3321 
3322 /*
3323  *    Function: cmlb_set_vtoc
3324  *
3325  * Description: This routine writes data to the appropriate positions
3326  *
3327  *   Arguments: un - driver soft state (unit) structure
3328  *              dkl  - the data to be written
3329  *
3330  * Return: void
3331  */
3332 static int
3333 cmlb_set_vtoc(struct cmlb_lun *un, struct dk_label *dkl)
3334 {
3335 	uint_t	label_addr;
3336 	int	sec;
3337 	int	blk;
3338 	int	head;
3339 	int	cyl;
3340 	int	rval;
3341 
3342 #if defined(__i386) || defined(__amd64)
3343 	label_addr = un->un_solaris_offset + DK_LABEL_LOC;
3344 #else
3345 	/* Write the primary label at block 0 of the solaris partition. */
3346 	label_addr = 0;
3347 #endif
3348 
3349 	rval = DK_TG_WRITE(un, dkl, label_addr, un->un_sys_blocksize);
3350 
3351 	if (rval != 0) {
3352 		return (rval);
3353 	}
3354 
3355 	/*
3356 	 * Calculate where the backup labels go.  They are always on
3357 	 * the last alternate cylinder, but some older drives put them
3358 	 * on head 2 instead of the last head.	They are always on the
3359 	 * first 5 odd sectors of the appropriate track.
3360 	 *
3361 	 * We have no choice at this point, but to believe that the
3362 	 * disk label is valid.	 Use the geometry of the disk
3363 	 * as described in the label.
3364 	 */
3365 	cyl  = dkl->dkl_ncyl  + dkl->dkl_acyl - 1;
3366 	head = dkl->dkl_nhead - 1;
3367 
3368 	/*
3369 	 * Write and verify the backup labels. Make sure we don't try to
3370 	 * write past the last cylinder.
3371 	 */
3372 	for (sec = 1; ((sec < 5 * 2 + 1) && (sec < dkl->dkl_nsect)); sec += 2) {
3373 		blk = (daddr_t)(
3374 		    (cyl * ((dkl->dkl_nhead * dkl->dkl_nsect) - dkl->dkl_apc)) +
3375 		    (head * dkl->dkl_nsect) + sec);
3376 #if defined(__i386) || defined(__amd64)
3377 		blk += un->un_solaris_offset;
3378 #endif
3379 		rval = DK_TG_WRITE(un, dkl, blk, un->un_sys_blocksize);
3380 		cmlb_dbg(CMLB_INFO,  un,
3381 		"cmlb_set_vtoc: wrote backup label %d\n", blk);
3382 		if (rval != 0) {
3383 			goto exit;
3384 		}
3385 	}
3386 exit:
3387 	return (rval);
3388 }
3389 
3390 /*
3391  *    Function: cmlb_clear_vtoc
3392  *
3393  * Description: This routine clears out the VTOC labels.
3394  *
3395  *   Arguments: un - driver soft state (unit) structure
3396  *
3397  * Return: void
3398  */
3399 static void
3400 cmlb_clear_vtoc(struct cmlb_lun *un)
3401 {
3402 	struct dk_label		*dkl;
3403 
3404 	mutex_exit(CMLB_MUTEX(un));
3405 	dkl = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP);
3406 	mutex_enter(CMLB_MUTEX(un));
3407 	/*
3408 	 * cmlb_set_vtoc uses these fields in order to figure out
3409 	 * where to overwrite the backup labels
3410 	 */
3411 	dkl->dkl_apc    = un->un_g.dkg_apc;
3412 	dkl->dkl_ncyl   = un->un_g.dkg_ncyl;
3413 	dkl->dkl_acyl   = un->un_g.dkg_acyl;
3414 	dkl->dkl_nhead  = un->un_g.dkg_nhead;
3415 	dkl->dkl_nsect  = un->un_g.dkg_nsect;
3416 	mutex_exit(CMLB_MUTEX(un));
3417 	(void) cmlb_set_vtoc(un, dkl);
3418 	kmem_free(dkl, sizeof (struct dk_label));
3419 
3420 	mutex_enter(CMLB_MUTEX(un));
3421 }
3422 
3423 /*
3424  *    Function: cmlb_write_label
3425  *
3426  * Description: This routine will validate and write the driver soft state vtoc
3427  *		contents to the device.
3428  *
3429  *   Arguments: un	cmlb handle
3430  *
3431  * Return Code: the code returned by cmlb_send_scsi_cmd()
3432  *		0
3433  *		EINVAL
3434  *		ENXIO
3435  *		ENOMEM
3436  */
3437 static int
3438 cmlb_write_label(struct cmlb_lun *un)
3439 {
3440 	struct dk_label	*dkl;
3441 	short		sum;
3442 	short		*sp;
3443 	int		i;
3444 	int		rval;
3445 
3446 	ASSERT(mutex_owned(CMLB_MUTEX(un)));
3447 	mutex_exit(CMLB_MUTEX(un));
3448 	dkl = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP);
3449 	mutex_enter(CMLB_MUTEX(un));
3450 
3451 	bcopy(&un->un_vtoc, &dkl->dkl_vtoc, sizeof (struct dk_vtoc));
3452 	dkl->dkl_rpm	= un->un_g.dkg_rpm;
3453 	dkl->dkl_pcyl	= un->un_g.dkg_pcyl;
3454 	dkl->dkl_apc	= un->un_g.dkg_apc;
3455 	dkl->dkl_intrlv = un->un_g.dkg_intrlv;
3456 	dkl->dkl_ncyl	= un->un_g.dkg_ncyl;
3457 	dkl->dkl_acyl	= un->un_g.dkg_acyl;
3458 	dkl->dkl_nhead	= un->un_g.dkg_nhead;
3459 	dkl->dkl_nsect	= un->un_g.dkg_nsect;
3460 
3461 #if defined(_SUNOS_VTOC_8)
3462 	dkl->dkl_obs1	= un->un_g.dkg_obs1;
3463 	dkl->dkl_obs2	= un->un_g.dkg_obs2;
3464 	dkl->dkl_obs3	= un->un_g.dkg_obs3;
3465 	for (i = 0; i < NDKMAP; i++) {
3466 		dkl->dkl_map[i].dkl_cylno = un->un_map[i].dkl_cylno;
3467 		dkl->dkl_map[i].dkl_nblk  = un->un_map[i].dkl_nblk;
3468 	}
3469 	bcopy(un->un_asciilabel, dkl->dkl_asciilabel, LEN_DKL_ASCII);
3470 #elif defined(_SUNOS_VTOC_16)
3471 	dkl->dkl_skew	= un->un_dkg_skew;
3472 #else
3473 #error "No VTOC format defined."
3474 #endif
3475 
3476 	dkl->dkl_magic			= DKL_MAGIC;
3477 	dkl->dkl_write_reinstruct	= un->un_g.dkg_write_reinstruct;
3478 	dkl->dkl_read_reinstruct	= un->un_g.dkg_read_reinstruct;
3479 
3480 	/* Construct checksum for the new disk label */
3481 	sum = 0;
3482 	sp = (short *)dkl;
3483 	i = sizeof (struct dk_label) / sizeof (short);
3484 	while (i--) {
3485 		sum ^= *sp++;
3486 	}
3487 	dkl->dkl_cksum = sum;
3488 
3489 	mutex_exit(CMLB_MUTEX(un));
3490 
3491 	rval = cmlb_set_vtoc(un, dkl);
3492 exit:
3493 	kmem_free(dkl, sizeof (struct dk_label));
3494 	mutex_enter(CMLB_MUTEX(un));
3495 	return (rval);
3496 }
3497 
3498 static int
3499 cmlb_dkio_set_efi(struct cmlb_lun *un, dev_t dev, caddr_t arg, int flag)
3500 {
3501 	dk_efi_t	user_efi;
3502 	int		rval = 0;
3503 	void		*buffer;
3504 
3505 	if (ddi_copyin(arg, &user_efi, sizeof (dk_efi_t), flag))
3506 		return (EFAULT);
3507 
3508 	user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64;
3509 
3510 	buffer = kmem_alloc(user_efi.dki_length, KM_SLEEP);
3511 	if (ddi_copyin(user_efi.dki_data, buffer, user_efi.dki_length, flag)) {
3512 		rval = EFAULT;
3513 	} else {
3514 		/*
3515 		 * let's clear the vtoc labels and clear the softstate
3516 		 * vtoc.
3517 		 */
3518 		mutex_enter(CMLB_MUTEX(un));
3519 		if (un->un_vtoc.v_sanity == VTOC_SANE) {
3520 			cmlb_dbg(CMLB_TRACE,  un,
3521 				"cmlb_dkio_set_efi: CLEAR VTOC\n");
3522 			if (un->un_vtoc_label_is_from_media)
3523 				cmlb_clear_vtoc(un);
3524 			bzero(&un->un_vtoc, sizeof (struct dk_vtoc));
3525 			mutex_exit(CMLB_MUTEX(un));
3526 			ddi_remove_minor_node(CMLB_DEVINFO(un), "h");
3527 			ddi_remove_minor_node(CMLB_DEVINFO(un), "h,raw");
3528 			(void) ddi_create_minor_node(CMLB_DEVINFO(un), "wd",
3529 			    S_IFBLK,
3530 			    (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE,
3531 			    un->un_node_type, NULL);
3532 			(void) ddi_create_minor_node(CMLB_DEVINFO(un), "wd,raw",
3533 			    S_IFCHR,
3534 			    (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE,
3535 			    un->un_node_type, NULL);
3536 		} else
3537 			mutex_exit(CMLB_MUTEX(un));
3538 		rval = DK_TG_WRITE(un, buffer, user_efi.dki_lba,
3539 		    user_efi.dki_length);
3540 		if (rval == 0) {
3541 			mutex_enter(CMLB_MUTEX(un));
3542 			un->un_f_geometry_is_valid = FALSE;
3543 			mutex_exit(CMLB_MUTEX(un));
3544 		}
3545 	}
3546 	kmem_free(buffer, user_efi.dki_length);
3547 	return (rval);
3548 }
3549 
3550 /*
3551  *    Function: cmlb_dkio_get_mboot
3552  *
3553  * Description: This routine is the driver entry point for handling user
3554  *		requests to get the current device mboot (DKIOCGMBOOT)
3555  *
3556  *   Arguments:
3557  *		arg  - pointer to user provided mboot structure specifying
3558  *			the current mboot.
3559  *		flag - this argument is a pass through to ddi_copyxxx()
3560  *		       directly from the mode argument of ioctl().
3561  *
3562  * Return Code: 0
3563  *		EINVAL
3564  *		EFAULT
3565  *		ENXIO
3566  */
3567 static int
3568 cmlb_dkio_get_mboot(struct cmlb_lun *un, caddr_t arg, int flag)
3569 {
3570 	struct mboot	*mboot;
3571 	int		rval;
3572 	size_t		buffer_size;
3573 
3574 
3575 #if defined(_SUNOS_VTOC_8)
3576 	if ((!ISREMOVABLE(un)) || (arg == NULL)) {
3577 #elif defined(_SUNOS_VTOC_16)
3578 	if (arg == NULL) {
3579 #endif
3580 		return (EINVAL);
3581 	}
3582 
3583 	/*
3584 	 * Read the mboot block, located at absolute block 0 on the target.
3585 	 */
3586 	buffer_size = sizeof (struct mboot);
3587 
3588 	cmlb_dbg(CMLB_TRACE,  un,
3589 	    "cmlb_dkio_get_mboot: allocation size: 0x%x\n", buffer_size);
3590 
3591 	mboot = kmem_zalloc(buffer_size, KM_SLEEP);
3592 	if ((rval = DK_TG_READ(un, mboot, 0, buffer_size)) == 0) {
3593 		if (ddi_copyout(mboot, (void *)arg,
3594 		    sizeof (struct mboot), flag) != 0) {
3595 			rval = EFAULT;
3596 		}
3597 	}
3598 	kmem_free(mboot, buffer_size);
3599 	return (rval);
3600 }
3601 
3602 
3603 /*
3604  *    Function: cmlb_dkio_set_mboot
3605  *
3606  * Description: This routine is the driver entry point for handling user
3607  *		requests to validate and set the device master boot
3608  *		(DKIOCSMBOOT).
3609  *
3610  *   Arguments:
3611  *		arg  - pointer to user provided mboot structure used to set the
3612  *			master boot.
3613  *		flag - this argument is a pass through to ddi_copyxxx()
3614  *		       directly from the mode argument of ioctl().
3615  *
3616  * Return Code: 0
3617  *		EINVAL
3618  *		EFAULT
3619  *		ENXIO
3620  */
3621 static int
3622 cmlb_dkio_set_mboot(struct cmlb_lun *un, caddr_t arg, int flag)
3623 {
3624 	struct mboot	*mboot = NULL;
3625 	int		rval;
3626 	ushort_t	magic;
3627 
3628 
3629 	ASSERT(!mutex_owned(CMLB_MUTEX(un)));
3630 
3631 #if defined(_SUNOS_VTOC_8)
3632 	if (!ISREMOVABLE(un)) {
3633 		return (EINVAL);
3634 	}
3635 #endif
3636 
3637 	if (arg == NULL) {
3638 		return (EINVAL);
3639 	}
3640 
3641 	mboot = kmem_zalloc(sizeof (struct mboot), KM_SLEEP);
3642 
3643 	if (ddi_copyin((const void *)arg, mboot,
3644 	    sizeof (struct mboot), flag) != 0) {
3645 		kmem_free(mboot, (size_t)(sizeof (struct mboot)));
3646 		return (EFAULT);
3647 	}
3648 
3649 	/* Is this really a master boot record? */
3650 	magic = LE_16(mboot->signature);
3651 	if (magic != MBB_MAGIC) {
3652 		kmem_free(mboot, (size_t)(sizeof (struct mboot)));
3653 		return (EINVAL);
3654 	}
3655 
3656 	rval = DK_TG_WRITE(un, mboot, 0, un->un_sys_blocksize);
3657 
3658 	mutex_enter(CMLB_MUTEX(un));
3659 #if defined(__i386) || defined(__amd64)
3660 	if (rval == 0) {
3661 		/*
3662 		 * mboot has been written successfully.
3663 		 * update the fdisk and vtoc tables in memory
3664 		 */
3665 		rval = cmlb_update_fdisk_and_vtoc(un);
3666 		if ((un->un_f_geometry_is_valid == FALSE) || (rval != 0)) {
3667 			mutex_exit(CMLB_MUTEX(un));
3668 			kmem_free(mboot, (size_t)(sizeof (struct mboot)));
3669 			return (rval);
3670 		}
3671 	}
3672 #else
3673 	if (rval == 0) {
3674 		/*
3675 		 * mboot has been written successfully.
3676 		 * set up the default geometry and VTOC
3677 		 */
3678 		if (un->un_blockcount <= DK_MAX_BLOCKS)
3679 			cmlb_setup_default_geometry(un);
3680 	}
3681 #endif
3682 	mutex_exit(CMLB_MUTEX(un));
3683 	kmem_free(mboot, (size_t)(sizeof (struct mboot)));
3684 	return (rval);
3685 }
3686 
3687 
3688 /*
3689  *    Function: cmlb_setup_default_geometry
3690  *
3691  * Description: This local utility routine sets the default geometry as part of
3692  *		setting the device mboot.
3693  *
3694  *   Arguments: un - driver soft state (unit) structure
3695  *
3696  * Note: This may be redundant with cmlb_build_default_label.
3697  */
3698 static void
3699 cmlb_setup_default_geometry(struct cmlb_lun *un)
3700 {
3701 	struct cmlb_geom	pgeom;
3702 	struct cmlb_geom	*pgeomp = &pgeom;
3703 	int			ret;
3704 	int			geom_base_cap = 1;
3705 
3706 
3707 	ASSERT(mutex_owned(CMLB_MUTEX(un)));
3708 
3709 	/* zero out the soft state geometry and partition table. */
3710 	bzero(&un->un_g, sizeof (struct dk_geom));
3711 	bzero(&un->un_vtoc, sizeof (struct dk_vtoc));
3712 	bzero(un->un_map, NDKMAP * (sizeof (struct dk_map)));
3713 
3714 	/*
3715 	 * For the rpm, we use the minimum for the disk.
3716 	 * For the head, cyl and number of sector per track,
3717 	 * if the capacity <= 1GB, head = 64, sect = 32.
3718 	 * else head = 255, sect 63
3719 	 * Note: the capacity should be equal to C*H*S values.
3720 	 * This will cause some truncation of size due to
3721 	 * round off errors. For CD-ROMs, this truncation can
3722 	 * have adverse side effects, so returning ncyl and
3723 	 * nhead as 1. The nsect will overflow for most of
3724 	 * CD-ROMs as nsect is of type ushort.
3725 	 */
3726 	if (un->un_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8) {
3727 		/*
3728 		 * newfs currently can not handle 255 ntracks for SPARC
3729 		 * so get the geometry from target driver instead of coming up
3730 		 * with one based on capacity.
3731 		 */
3732 		mutex_exit(CMLB_MUTEX(un));
3733 		ret = DK_TG_GETPHYGEOM(un, pgeomp);
3734 		mutex_enter(CMLB_MUTEX(un));
3735 
3736 		if (ret  == 0) {
3737 			geom_base_cap = 0;
3738 		} else {
3739 			cmlb_dbg(CMLB_ERROR,  un,
3740 			    "cmlb_setup_default_geometry: "
3741 			    "tg_getphygeom failed %d\n", ret);
3742 
3743 			/* do default setting, geometry based on capacity */
3744 		}
3745 	}
3746 
3747 	if (geom_base_cap) {
3748 		if (ISCD(un)) {
3749 			un->un_g.dkg_ncyl = 1;
3750 			un->un_g.dkg_nhead = 1;
3751 			un->un_g.dkg_nsect = un->un_blockcount;
3752 		} else if (un->un_blockcount <= 0x1000) {
3753 			/* Needed for unlabeled SCSI floppies. */
3754 			un->un_g.dkg_nhead = 2;
3755 			un->un_g.dkg_ncyl = 80;
3756 			un->un_g.dkg_pcyl = 80;
3757 			un->un_g.dkg_nsect = un->un_blockcount / (2 * 80);
3758 		} else if (un->un_blockcount <= 0x200000) {
3759 			un->un_g.dkg_nhead = 64;
3760 			un->un_g.dkg_nsect = 32;
3761 			un->un_g.dkg_ncyl = un->un_blockcount / (64 * 32);
3762 		} else {
3763 			un->un_g.dkg_nhead = 255;
3764 			un->un_g.dkg_nsect = 63;
3765 			un->un_g.dkg_ncyl = un->un_blockcount / (255 * 63);
3766 		}
3767 
3768 		un->un_g.dkg_acyl = 0;
3769 		un->un_g.dkg_bcyl = 0;
3770 		un->un_g.dkg_intrlv = 1;
3771 		un->un_g.dkg_rpm = 200;
3772 		if (un->un_g.dkg_pcyl == 0)
3773 			un->un_g.dkg_pcyl = un->un_g.dkg_ncyl +
3774 			    un->un_g.dkg_acyl;
3775 	} else {
3776 		un->un_g.dkg_ncyl = (short)pgeomp->g_ncyl;
3777 		un->un_g.dkg_acyl = pgeomp->g_acyl;
3778 		un->un_g.dkg_nhead = pgeomp->g_nhead;
3779 		un->un_g.dkg_nsect = pgeomp->g_nsect;
3780 		un->un_g.dkg_intrlv = pgeomp->g_intrlv;
3781 		un->un_g.dkg_rpm = pgeomp->g_rpm;
3782 		un->un_g.dkg_pcyl = un->un_g.dkg_ncyl + un->un_g.dkg_acyl;
3783 	}
3784 
3785 	un->un_g.dkg_read_reinstruct = 0;
3786 	un->un_g.dkg_write_reinstruct = 0;
3787 	un->un_solaris_size = un->un_g.dkg_ncyl *
3788 	    un->un_g.dkg_nhead * un->un_g.dkg_nsect;
3789 
3790 	un->un_map['a'-'a'].dkl_cylno = 0;
3791 	un->un_map['a'-'a'].dkl_nblk = un->un_solaris_size;
3792 
3793 	un->un_map['c'-'a'].dkl_cylno = 0;
3794 	un->un_map['c'-'a'].dkl_nblk = un->un_solaris_size;
3795 
3796 	un->un_vtoc.v_part[2].p_tag   = V_BACKUP;
3797 	un->un_vtoc.v_part[2].p_flag  = V_UNMNT;
3798 	un->un_vtoc.v_nparts = V_NUMPAR;
3799 	un->un_vtoc.v_version = V_VERSION;
3800 	(void) sprintf((char *)un->un_asciilabel, "DEFAULT cyl %d alt %d"
3801 	    " hd %d sec %d", un->un_g.dkg_ncyl, un->un_g.dkg_acyl,
3802 	    un->un_g.dkg_nhead, un->un_g.dkg_nsect);
3803 
3804 	un->un_f_geometry_is_valid = FALSE;
3805 }
3806 
3807 
3808 #if defined(__i386) || defined(__amd64)
3809 /*
3810  *    Function: cmlb_update_fdisk_and_vtoc
3811  *
3812  * Description: This local utility routine updates the device fdisk and vtoc
3813  *		as part of setting the device mboot.
3814  *
3815  *   Arguments: un - driver soft state (unit) structure
3816  *
3817  * Return Code: 0 for success or errno-type return code.
3818  *
3819  *    Note:x86: This looks like a duplicate of cmlb_validate_geometry(), but
3820  *		these did exist separately in x86 sd.c.
3821  */
3822 static int
3823 cmlb_update_fdisk_and_vtoc(struct cmlb_lun *un)
3824 {
3825 	int		count;
3826 	int		label_rc = 0;
3827 	int		fdisk_rval;
3828 	diskaddr_t	capacity;
3829 
3830 	ASSERT(mutex_owned(CMLB_MUTEX(un)));
3831 
3832 	if (cmlb_check_update_blockcount(un) != 0)
3833 		return (EINVAL);
3834 
3835 #if defined(_SUNOS_VTOC_16)
3836 	/*
3837 	 * Set up the "whole disk" fdisk partition; this should always
3838 	 * exist, regardless of whether the disk contains an fdisk table
3839 	 * or vtoc.
3840 	 */
3841 	un->un_map[P0_RAW_DISK].dkl_cylno = 0;
3842 	un->un_map[P0_RAW_DISK].dkl_nblk = un->un_blockcount;
3843 #endif	/* defined(_SUNOS_VTOC_16) */
3844 
3845 	/*
3846 	 * copy the lbasize and capacity so that if they're
3847 	 * reset while we're not holding the CMLB_MUTEX(un), we will
3848 	 * continue to use valid values after the CMLB_MUTEX(un) is
3849 	 * reacquired.
3850 	 */
3851 	capacity = un->un_blockcount;
3852 
3853 	/*
3854 	 * refresh the logical and physical geometry caches.
3855 	 * (data from mode sense format/rigid disk geometry pages,
3856 	 * and scsi_ifgetcap("geometry").
3857 	 */
3858 	cmlb_resync_geom_caches(un, capacity);
3859 
3860 	/*
3861 	 * Only DIRECT ACCESS devices will have Sun labels.
3862 	 * CD's supposedly have a Sun label, too
3863 	 */
3864 	if (un->un_device_type == DTYPE_DIRECT || ISREMOVABLE(un)) {
3865 		fdisk_rval = cmlb_read_fdisk(un, capacity);
3866 		if (fdisk_rval != 0) {
3867 			ASSERT(mutex_owned(CMLB_MUTEX(un)));
3868 			return (fdisk_rval);
3869 		}
3870 
3871 		if (un->un_solaris_size <= DK_LABEL_LOC) {
3872 			/*
3873 			 * Found fdisk table but no Solaris partition entry,
3874 			 * so don't call cmlb_uselabel() and don't create
3875 			 * a default label.
3876 			 */
3877 			label_rc = 0;
3878 			un->un_f_geometry_is_valid = TRUE;
3879 			goto no_solaris_partition;
3880 		}
3881 	} else if (capacity < 0) {
3882 		ASSERT(mutex_owned(CMLB_MUTEX(un)));
3883 		return (EINVAL);
3884 	}
3885 
3886 	/*
3887 	 * For Removable media We reach here if we have found a
3888 	 * SOLARIS PARTITION.
3889 	 * If un_f_geometry_is_valid is FALSE it indicates that the SOLARIS
3890 	 * PARTITION has changed from the previous one, hence we will setup a
3891 	 * default VTOC in this case.
3892 	 */
3893 	if (un->un_f_geometry_is_valid == FALSE) {
3894 		/* if we get here it is writable */
3895 		/* we are called from SMBOOT, and after a write of fdisk */
3896 		cmlb_build_default_label(un);
3897 		label_rc = 0;
3898 	}
3899 
3900 no_solaris_partition:
3901 
3902 #if defined(_SUNOS_VTOC_16)
3903 	/*
3904 	 * If we have valid geometry, set up the remaining fdisk partitions.
3905 	 * Note that dkl_cylno is not used for the fdisk map entries, so
3906 	 * we set it to an entirely bogus value.
3907 	 */
3908 	for (count = 0; count < FD_NUMPART; count++) {
3909 		un->un_map[FDISK_P1 + count].dkl_cylno = -1;
3910 		un->un_map[FDISK_P1 + count].dkl_nblk =
3911 		    un->un_fmap[count].fmap_nblk;
3912 		un->un_offset[FDISK_P1 + count] =
3913 		    un->un_fmap[count].fmap_start;
3914 	}
3915 #endif
3916 
3917 	for (count = 0; count < NDKMAP; count++) {
3918 #if defined(_SUNOS_VTOC_8)
3919 		struct dk_map *lp  = &un->un_map[count];
3920 		un->un_offset[count] =
3921 		    un->un_g.dkg_nhead * un->un_g.dkg_nsect * lp->dkl_cylno;
3922 #elif defined(_SUNOS_VTOC_16)
3923 		struct dkl_partition *vp = &un->un_vtoc.v_part[count];
3924 		un->un_offset[count] = vp->p_start + un->un_solaris_offset;
3925 #else
3926 #error "No VTOC format defined."
3927 #endif
3928 	}
3929 
3930 	ASSERT(mutex_owned(CMLB_MUTEX(un)));
3931 	return (label_rc);
3932 }
3933 #endif
3934 
3935 #if defined(__i386) || defined(__amd64)
3936 static int
3937 cmlb_dkio_get_virtgeom(struct cmlb_lun *un, caddr_t arg, int flag)
3938 {
3939 	int err = 0;
3940 
3941 	/* Return the driver's notion of the media's logical geometry */
3942 	struct dk_geom	disk_geom;
3943 	struct dk_geom	*dkgp = &disk_geom;
3944 
3945 	mutex_enter(CMLB_MUTEX(un));
3946 	/*
3947 	 * If there is no HBA geometry available, or
3948 	 * if the HBA returned us something that doesn't
3949 	 * really fit into an Int 13/function 8 geometry
3950 	 * result, just fail the ioctl.  See PSARC 1998/313.
3951 	 */
3952 	if (un->un_lgeom.g_nhead == 0 ||
3953 	    un->un_lgeom.g_nsect == 0 ||
3954 	    un->un_lgeom.g_ncyl > 1024) {
3955 		mutex_exit(CMLB_MUTEX(un));
3956 		err = EINVAL;
3957 	} else {
3958 		dkgp->dkg_ncyl	= un->un_lgeom.g_ncyl;
3959 		dkgp->dkg_acyl	= un->un_lgeom.g_acyl;
3960 		dkgp->dkg_pcyl	= dkgp->dkg_ncyl + dkgp->dkg_acyl;
3961 		dkgp->dkg_nhead	= un->un_lgeom.g_nhead;
3962 		dkgp->dkg_nsect	= un->un_lgeom.g_nsect;
3963 
3964 		if (ddi_copyout(dkgp, (void *)arg,
3965 		    sizeof (struct dk_geom), flag)) {
3966 			mutex_exit(CMLB_MUTEX(un));
3967 			err = EFAULT;
3968 		} else {
3969 			mutex_exit(CMLB_MUTEX(un));
3970 			err = 0;
3971 		}
3972 	}
3973 	return (err);
3974 }
3975 #endif
3976 
3977 #if defined(__i386) || defined(__amd64)
3978 static int
3979 cmlb_dkio_get_phygeom(struct cmlb_lun *un, caddr_t  arg, int flag)
3980 {
3981 	int err = 0;
3982 
3983 
3984 	/* Return the driver's notion of the media physical geometry */
3985 	struct dk_geom	disk_geom;
3986 	struct dk_geom	*dkgp = &disk_geom;
3987 
3988 	mutex_enter(CMLB_MUTEX(un));
3989 
3990 	if (un->un_g.dkg_nhead != 0 &&
3991 	    un->un_g.dkg_nsect != 0) {
3992 		/*
3993 		 * We succeeded in getting a geometry, but
3994 		 * right now it is being reported as just the
3995 		 * Solaris fdisk partition, just like for
3996 		 * DKIOCGGEOM. We need to change that to be
3997 		 * correct for the entire disk now.
3998 		 */
3999 		bcopy(&un->un_g, dkgp, sizeof (*dkgp));
4000 		dkgp->dkg_acyl = 0;
4001 		dkgp->dkg_ncyl = un->un_blockcount /
4002 		    (dkgp->dkg_nhead * dkgp->dkg_nsect);
4003 	} else {
4004 		bzero(dkgp, sizeof (struct dk_geom));
4005 		/*
4006 		 * This disk does not have a Solaris VTOC
4007 		 * so we must present a physical geometry
4008 		 * that will remain consistent regardless
4009 		 * of how the disk is used. This will ensure
4010 		 * that the geometry does not change regardless
4011 		 * of the fdisk partition type (ie. EFI, FAT32,
4012 		 * Solaris, etc).
4013 		 */
4014 		if (ISCD(un)) {
4015 			dkgp->dkg_nhead = un->un_pgeom.g_nhead;
4016 			dkgp->dkg_nsect = un->un_pgeom.g_nsect;
4017 			dkgp->dkg_ncyl = un->un_pgeom.g_ncyl;
4018 			dkgp->dkg_acyl = un->un_pgeom.g_acyl;
4019 		} else {
4020 			cmlb_convert_geometry(un->un_blockcount, dkgp);
4021 			dkgp->dkg_acyl = 0;
4022 			dkgp->dkg_ncyl = un->un_blockcount /
4023 			    (dkgp->dkg_nhead * dkgp->dkg_nsect);
4024 		}
4025 	}
4026 	dkgp->dkg_pcyl = dkgp->dkg_ncyl + dkgp->dkg_acyl;
4027 
4028 	if (ddi_copyout(dkgp, (void *)arg,
4029 	    sizeof (struct dk_geom), flag)) {
4030 		mutex_exit(CMLB_MUTEX(un));
4031 		err = EFAULT;
4032 	} else {
4033 		mutex_exit(CMLB_MUTEX(un));
4034 		err = 0;
4035 	}
4036 	return (err);
4037 }
4038 #endif
4039 
4040 #if defined(__i386) || defined(__amd64)
4041 static int
4042 cmlb_dkio_partinfo(struct cmlb_lun *un, dev_t dev, caddr_t  arg, int flag)
4043 {
4044 	int err = 0;
4045 
4046 	/*
4047 	 * Return parameters describing the selected disk slice.
4048 	 * Note: this ioctl is for the intel platform only
4049 	 */
4050 	int part;
4051 
4052 	part = CMLBPART(dev);
4053 
4054 	/* don't check un_solaris_size for pN */
4055 	if (part < P0_RAW_DISK && un->un_solaris_size == 0) {
4056 		err = EIO;
4057 	} else {
4058 		struct part_info p;
4059 
4060 		p.p_start = (daddr_t)un->un_offset[part];
4061 		p.p_length = (int)un->un_map[part].dkl_nblk;
4062 #ifdef _MULTI_DATAMODEL
4063 		switch (ddi_model_convert_from(flag & FMODELS)) {
4064 		case DDI_MODEL_ILP32:
4065 		{
4066 			struct part_info32 p32;
4067 
4068 			p32.p_start = (daddr32_t)p.p_start;
4069 			p32.p_length = p.p_length;
4070 			if (ddi_copyout(&p32, (void *)arg,
4071 			    sizeof (p32), flag))
4072 				err = EFAULT;
4073 			break;
4074 		}
4075 
4076 		case DDI_MODEL_NONE:
4077 		{
4078 			if (ddi_copyout(&p, (void *)arg, sizeof (p),
4079 			    flag))
4080 				err = EFAULT;
4081 			break;
4082 		}
4083 		}
4084 #else /* ! _MULTI_DATAMODEL */
4085 		if (ddi_copyout(&p, (void *)arg, sizeof (p), flag))
4086 			err = EFAULT;
4087 #endif /* _MULTI_DATAMODEL */
4088 	}
4089 	return (err);
4090 }
4091 #endif
4092