4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
24 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
26 * Copyright 2016 Toomas Soome <tsoome@me.com>
30 * This module provides support for labeling operations for target
34 #include <sys/scsi/scsi.h>
35 #include <sys/sunddi.h>
36 #include <sys/dklabel.h>
39 #include <sys/dktp/fdisk.h>
40 #include <sys/vtrace.h>
41 #include <sys/efi_partition.h>
43 #include <sys/cmlb_impl.h>
44 #if defined(__i386) || defined(__amd64)
45 #include <sys/fs/dv_node.h>
47 #include <sys/ddi_impldefs.h>
50 * Driver minor node structure and data table
52 struct driver_minor_data
{
58 static struct driver_minor_data dk_minor_data
[] = {
67 #if defined(_SUNOS_VTOC_16)
76 #endif /* defined(_SUNOS_VTOC_16) */
77 #if defined(_FIRMWARE_NEEDS_FDISK)
83 #endif /* defined(_FIRMWARE_NEEDS_FDISK) */
84 {"a,raw", 0, S_IFCHR
},
85 {"b,raw", 1, S_IFCHR
},
86 {"c,raw", 2, S_IFCHR
},
87 {"d,raw", 3, S_IFCHR
},
88 {"e,raw", 4, S_IFCHR
},
89 {"f,raw", 5, S_IFCHR
},
90 {"g,raw", 6, S_IFCHR
},
91 {"h,raw", 7, S_IFCHR
},
92 #if defined(_SUNOS_VTOC_16)
93 {"i,raw", 8, S_IFCHR
},
94 {"j,raw", 9, S_IFCHR
},
95 {"k,raw", 10, S_IFCHR
},
96 {"l,raw", 11, S_IFCHR
},
97 {"m,raw", 12, S_IFCHR
},
98 {"n,raw", 13, S_IFCHR
},
99 {"o,raw", 14, S_IFCHR
},
100 {"p,raw", 15, S_IFCHR
},
101 #endif /* defined(_SUNOS_VTOC_16) */
102 #if defined(_FIRMWARE_NEEDS_FDISK)
103 {"q,raw", 16, S_IFCHR
},
104 {"r,raw", 17, S_IFCHR
},
105 {"s,raw", 18, S_IFCHR
},
106 {"t,raw", 19, S_IFCHR
},
107 {"u,raw", 20, S_IFCHR
},
108 #endif /* defined(_FIRMWARE_NEEDS_FDISK) */
112 #if defined(__i386) || defined(__amd64)
113 #if defined(_FIRMWARE_NEEDS_FDISK)
114 static struct driver_minor_data dk_ext_minor_data
[] = {
120 {"p10", 26, S_IFBLK
},
121 {"p11", 27, S_IFBLK
},
122 {"p12", 28, S_IFBLK
},
123 {"p13", 29, S_IFBLK
},
124 {"p14", 30, S_IFBLK
},
125 {"p15", 31, S_IFBLK
},
126 {"p16", 32, S_IFBLK
},
127 {"p17", 33, S_IFBLK
},
128 {"p18", 34, S_IFBLK
},
129 {"p19", 35, S_IFBLK
},
130 {"p20", 36, S_IFBLK
},
131 {"p21", 37, S_IFBLK
},
132 {"p22", 38, S_IFBLK
},
133 {"p23", 39, S_IFBLK
},
134 {"p24", 40, S_IFBLK
},
135 {"p25", 41, S_IFBLK
},
136 {"p26", 42, S_IFBLK
},
137 {"p27", 43, S_IFBLK
},
138 {"p28", 44, S_IFBLK
},
139 {"p29", 45, S_IFBLK
},
140 {"p30", 46, S_IFBLK
},
141 {"p31", 47, S_IFBLK
},
142 {"p32", 48, S_IFBLK
},
143 {"p33", 49, S_IFBLK
},
144 {"p34", 50, S_IFBLK
},
145 {"p35", 51, S_IFBLK
},
146 {"p36", 52, S_IFBLK
},
147 {"p5,raw", 21, S_IFCHR
},
148 {"p6,raw", 22, S_IFCHR
},
149 {"p7,raw", 23, S_IFCHR
},
150 {"p8,raw", 24, S_IFCHR
},
151 {"p9,raw", 25, S_IFCHR
},
152 {"p10,raw", 26, S_IFCHR
},
153 {"p11,raw", 27, S_IFCHR
},
154 {"p12,raw", 28, S_IFCHR
},
155 {"p13,raw", 29, S_IFCHR
},
156 {"p14,raw", 30, S_IFCHR
},
157 {"p15,raw", 31, S_IFCHR
},
158 {"p16,raw", 32, S_IFCHR
},
159 {"p17,raw", 33, S_IFCHR
},
160 {"p18,raw", 34, S_IFCHR
},
161 {"p19,raw", 35, S_IFCHR
},
162 {"p20,raw", 36, S_IFCHR
},
163 {"p21,raw", 37, S_IFCHR
},
164 {"p22,raw", 38, S_IFCHR
},
165 {"p23,raw", 39, S_IFCHR
},
166 {"p24,raw", 40, S_IFCHR
},
167 {"p25,raw", 41, S_IFCHR
},
168 {"p26,raw", 42, S_IFCHR
},
169 {"p27,raw", 43, S_IFCHR
},
170 {"p28,raw", 44, S_IFCHR
},
171 {"p29,raw", 45, S_IFCHR
},
172 {"p30,raw", 46, S_IFCHR
},
173 {"p31,raw", 47, S_IFCHR
},
174 {"p32,raw", 48, S_IFCHR
},
175 {"p33,raw", 49, S_IFCHR
},
176 {"p34,raw", 50, S_IFCHR
},
177 {"p35,raw", 51, S_IFCHR
},
178 {"p36,raw", 52, S_IFCHR
},
181 #endif /* defined(_FIRMWARE_NEEDS_FDISK) */
182 #endif /* if defined(__i386) || defined(__amd64) */
184 static struct driver_minor_data dk_minor_data_efi
[] = {
193 #if defined(_SUNOS_VTOC_16)
202 #endif /* defined(_SUNOS_VTOC_16) */
203 #if defined(_FIRMWARE_NEEDS_FDISK)
209 #endif /* defined(_FIRMWARE_NEEDS_FDISK) */
210 {"a,raw", 0, S_IFCHR
},
211 {"b,raw", 1, S_IFCHR
},
212 {"c,raw", 2, S_IFCHR
},
213 {"d,raw", 3, S_IFCHR
},
214 {"e,raw", 4, S_IFCHR
},
215 {"f,raw", 5, S_IFCHR
},
216 {"g,raw", 6, S_IFCHR
},
217 {"wd,raw", 7, S_IFCHR
},
218 #if defined(_SUNOS_VTOC_16)
219 {"i,raw", 8, S_IFCHR
},
220 {"j,raw", 9, S_IFCHR
},
221 {"k,raw", 10, S_IFCHR
},
222 {"l,raw", 11, S_IFCHR
},
223 {"m,raw", 12, S_IFCHR
},
224 {"n,raw", 13, S_IFCHR
},
225 {"o,raw", 14, S_IFCHR
},
226 {"p,raw", 15, S_IFCHR
},
227 #endif /* defined(_SUNOS_VTOC_16) */
228 #if defined(_FIRMWARE_NEEDS_FDISK)
229 {"q,raw", 16, S_IFCHR
},
230 {"r,raw", 17, S_IFCHR
},
231 {"s,raw", 18, S_IFCHR
},
232 {"t,raw", 19, S_IFCHR
},
233 {"u,raw", 20, S_IFCHR
},
234 #endif /* defined(_FIRMWARE_NEEDS_FDISK) */
239 * Declare the dynamic properties implemented in prop_op(9E) implementation
240 * that we want to have show up in a di_init(3DEVINFO) device tree snapshot
241 * of drivers that call cmlb_attach().
243 static i_ddi_prop_dyn_t cmlb_prop_dyn
[] = {
244 {"Nblocks", DDI_PROP_TYPE_INT64
, S_IFBLK
},
245 {"Size", DDI_PROP_TYPE_INT64
, S_IFCHR
},
246 {"device-nblocks", DDI_PROP_TYPE_INT64
},
247 {"device-blksize", DDI_PROP_TYPE_INT
},
248 {"device-solid-state", DDI_PROP_TYPE_INT
},
249 {"device-rotational", DDI_PROP_TYPE_INT
},
254 * This implies an upper limit of 8192 GPT partitions
255 * in one transfer for GUID Partition Entry Array.
257 len_t cmlb_tg_max_efi_xfer
= 1024 * 1024;
260 * External kernel interfaces
262 extern struct mod_ops mod_miscops
;
264 extern int ddi_create_internal_pathname(dev_info_t
*dip
, char *name
,
265 int spec_type
, minor_t minor_num
);
268 * Global buffer and mutex for debug logging
270 static char cmlb_log_buffer
[1024];
271 static kmutex_t cmlb_log_mutex
;
274 struct cmlb_lun
*cmlb_debug_cl
= NULL
;
275 uint_t cmlb_level_mask
= 0x0;
277 int cmlb_rot_delay
= 4; /* default rotational delay */
279 static struct modlmisc modlmisc
= {
280 &mod_miscops
, /* Type of module */
281 "Common Labeling module"
284 static struct modlinkage modlinkage
= {
285 MODREV_1
, (void *)&modlmisc
, NULL
288 /* Local function prototypes */
289 static dev_t
cmlb_make_device(struct cmlb_lun
*cl
);
290 static int cmlb_validate_geometry(struct cmlb_lun
*cl
, boolean_t forcerevalid
,
291 int flags
, void *tg_cookie
);
292 static void cmlb_resync_geom_caches(struct cmlb_lun
*cl
, diskaddr_t capacity
,
294 static int cmlb_read_fdisk(struct cmlb_lun
*cl
, diskaddr_t capacity
,
296 static void cmlb_swap_efi_gpt(efi_gpt_t
*e
);
297 static void cmlb_swap_efi_gpe(int nparts
, efi_gpe_t
*p
);
298 static int cmlb_validate_efi(efi_gpt_t
*labp
);
299 static int cmlb_use_efi(struct cmlb_lun
*cl
, diskaddr_t capacity
, int flags
,
301 static void cmlb_build_default_label(struct cmlb_lun
*cl
, void *tg_cookie
);
302 static int cmlb_uselabel(struct cmlb_lun
*cl
, struct dk_label
*l
, int flags
);
303 #if defined(_SUNOS_VTOC_8)
304 static void cmlb_build_user_vtoc(struct cmlb_lun
*cl
, struct vtoc
*user_vtoc
);
306 static int cmlb_build_label_vtoc(struct cmlb_lun
*cl
, struct vtoc
*user_vtoc
);
307 static int cmlb_write_label(struct cmlb_lun
*cl
, void *tg_cookie
);
308 static int cmlb_set_vtoc(struct cmlb_lun
*cl
, struct dk_label
*dkl
,
310 static void cmlb_clear_efi(struct cmlb_lun
*cl
, void *tg_cookie
);
311 static void cmlb_clear_vtoc(struct cmlb_lun
*cl
, void *tg_cookie
);
312 static void cmlb_setup_default_geometry(struct cmlb_lun
*cl
, void *tg_cookie
);
313 static int cmlb_create_minor_nodes(struct cmlb_lun
*cl
);
314 static int cmlb_check_update_blockcount(struct cmlb_lun
*cl
, void *tg_cookie
);
315 static boolean_t
cmlb_check_efi_mbr(uchar_t
*buf
, boolean_t
*is_mbr
);
317 #if defined(__i386) || defined(__amd64)
318 static int cmlb_update_fdisk_and_vtoc(struct cmlb_lun
*cl
, void *tg_cookie
);
321 #if defined(_FIRMWARE_NEEDS_FDISK)
322 static boolean_t
cmlb_has_max_chs_vals(struct ipart
*fdp
);
325 #if defined(_SUNOS_VTOC_16)
326 static void cmlb_convert_geometry(struct cmlb_lun
*cl
, diskaddr_t capacity
,
327 struct dk_geom
*cl_g
, void *tg_cookie
);
330 static int cmlb_dkio_get_geometry(struct cmlb_lun
*cl
, caddr_t arg
, int flag
,
332 static int cmlb_dkio_set_geometry(struct cmlb_lun
*cl
, caddr_t arg
, int flag
);
333 static int cmlb_dkio_get_partition(struct cmlb_lun
*cl
, caddr_t arg
, int flag
,
335 static int cmlb_dkio_set_partition(struct cmlb_lun
*cl
, caddr_t arg
, int flag
);
336 static int cmlb_dkio_get_efi(struct cmlb_lun
*cl
, caddr_t arg
, int flag
,
338 static int cmlb_dkio_set_efi(struct cmlb_lun
*cl
, dev_t dev
, caddr_t arg
,
339 int flag
, void *tg_cookie
);
340 static int cmlb_dkio_get_vtoc(struct cmlb_lun
*cl
, caddr_t arg
, int flag
,
342 static int cmlb_dkio_get_extvtoc(struct cmlb_lun
*cl
, caddr_t arg
, int flag
,
344 static int cmlb_dkio_set_vtoc(struct cmlb_lun
*cl
, dev_t dev
, caddr_t arg
,
345 int flag
, void *tg_cookie
);
346 static int cmlb_dkio_set_extvtoc(struct cmlb_lun
*cl
, dev_t dev
, caddr_t arg
,
347 int flag
, void *tg_cookie
);
348 static int cmlb_dkio_get_mboot(struct cmlb_lun
*cl
, caddr_t arg
, int flag
,
350 static int cmlb_dkio_set_mboot(struct cmlb_lun
*cl
, caddr_t arg
, int flag
,
352 static int cmlb_dkio_partition(struct cmlb_lun
*cl
, caddr_t arg
, int flag
,
355 #if defined(__i386) || defined(__amd64)
356 static int cmlb_dkio_set_ext_part(struct cmlb_lun
*cl
, caddr_t arg
, int flag
,
358 static int cmlb_validate_ext_part(struct cmlb_lun
*cl
, int part
, int epart
,
359 uint32_t start
, uint32_t size
);
360 static int cmlb_is_linux_swap(struct cmlb_lun
*cl
, uint32_t part_start
,
362 static int cmlb_dkio_get_virtgeom(struct cmlb_lun
*cl
, caddr_t arg
, int flag
);
363 static int cmlb_dkio_get_phygeom(struct cmlb_lun
*cl
, caddr_t arg
, int flag
,
365 static int cmlb_dkio_partinfo(struct cmlb_lun
*cl
, dev_t dev
, caddr_t arg
,
367 static int cmlb_dkio_extpartinfo(struct cmlb_lun
*cl
, dev_t dev
, caddr_t arg
,
371 static void cmlb_dbg(uint_t comp
, struct cmlb_lun
*cl
, const char *fmt
, ...);
372 static void cmlb_v_log(dev_info_t
*dev
, const char *label
, uint_t level
,
373 const char *fmt
, va_list ap
);
374 static void cmlb_log(dev_info_t
*dev
, const char *label
, uint_t level
,
375 const char *fmt
, ...);
380 mutex_init(&cmlb_log_mutex
, NULL
, MUTEX_DRIVER
, NULL
);
381 return (mod_install(&modlinkage
));
385 _info(struct modinfo
*modinfop
)
387 return (mod_info(&modlinkage
, modinfop
));
395 if ((err
= mod_remove(&modlinkage
)) != 0) {
399 mutex_destroy(&cmlb_log_mutex
);
404 * cmlb_dbg is used for debugging to log additional info
405 * Level of output is controlled via cmlb_level_mask setting.
408 cmlb_dbg(uint_t comp
, struct cmlb_lun
*cl
, const char *fmt
, ...)
412 uint_t level_mask
= 0;
415 dev
= CMLB_DEVINFO(cl
);
418 * Filter messages based on the global component and level masks,
419 * also print if cl matches the value of cmlb_debug_cl, or if
420 * cmlb_debug_cl is set to NULL.
422 if (comp
& CMLB_TRACE
)
423 level_mask
|= CMLB_LOGMASK_TRACE
;
425 if (comp
& CMLB_INFO
)
426 level_mask
|= CMLB_LOGMASK_INFO
;
428 if (comp
& CMLB_ERROR
)
429 level_mask
|= CMLB_LOGMASK_ERROR
;
431 if ((cmlb_level_mask
& level_mask
) &&
432 ((cmlb_debug_cl
== NULL
) || (cmlb_debug_cl
== cl
))) {
434 cmlb_v_log(dev
, CMLB_LABEL(cl
), CE_CONT
, fmt
, ap
);
440 * cmlb_log is basically a duplicate of scsi_log. It is redefined here
441 * so that this module does not depend on scsi module.
444 cmlb_log(dev_info_t
*dev
, const char *label
, uint_t level
, const char *fmt
, ...)
449 cmlb_v_log(dev
, label
, level
, fmt
, ap
);
454 cmlb_v_log(dev_info_t
*dev
, const char *label
, uint_t level
, const char *fmt
,
457 static char name
[256];
460 int console_only
= 0;
462 mutex_enter(&cmlb_log_mutex
);
465 if (level
== CE_PANIC
|| level
== CE_WARN
||
467 (void) sprintf(name
, "%s (%s%d):\n",
468 ddi_pathname(dev
, cmlb_log_buffer
),
469 label
, ddi_get_instance(dev
));
474 (void) sprintf(name
, "%s:", label
);
477 (void) vsprintf(cmlb_log_buffer
, fmt
, ap
);
479 switch (cmlb_log_buffer
[0]) {
499 cmn_err(level
, "?%s\t%s", name
, &cmlb_log_buffer
[1]);
500 } else if (console_only
) {
501 cmn_err(level
, "^%s\t%s", name
, &cmlb_log_buffer
[1]);
502 } else if (log_only
) {
503 cmn_err(level
, "!%s\t%s", name
, &cmlb_log_buffer
[1]);
505 cmn_err(level
, "%s\t%s", name
, cmlb_log_buffer
);
511 cmn_err(CE_CONT
, "^DEBUG: %s\t%s", name
, cmlb_log_buffer
);
514 mutex_exit(&cmlb_log_mutex
);
521 * Allocates a handle.
524 * cmlbhandlep pointer to handle
527 * Allocates a handle and stores the allocated handle in the area
528 * pointed to by cmlbhandlep
531 * Kernel thread only (can sleep).
534 cmlb_alloc_handle(cmlb_handle_t
*cmlbhandlep
)
538 cl
= kmem_zalloc(sizeof (struct cmlb_lun
), KM_SLEEP
);
539 ASSERT(cmlbhandlep
!= NULL
);
541 cl
->cl_state
= CMLB_INITED
;
542 cl
->cl_def_labeltype
= CMLB_LABEL_UNDEF
;
543 mutex_init(CMLB_MUTEX(cl
), NULL
, MUTEX_DRIVER
, NULL
);
545 *cmlbhandlep
= (cmlb_handle_t
)(cl
);
554 * cmlbhandlep pointer to handle
557 cmlb_free_handle(cmlb_handle_t
*cmlbhandlep
)
561 cl
= (struct cmlb_lun
*)*cmlbhandlep
;
563 mutex_destroy(CMLB_MUTEX(cl
));
564 kmem_free(cl
, sizeof (struct cmlb_lun
));
572 * Attach handle to device, create minor nodes for device.
575 * devi pointer to device's dev_info structure.
576 * tgopsp pointer to array of functions cmlb can use to callback
579 * device_type Peripheral device type as defined in
580 * scsi/generic/inquiry.h
582 * is_removable whether or not device is removable.
584 * is_hotpluggable whether or not device is hotpluggable.
586 * node_type minor node type (as used by ddi_create_minor_node)
591 * CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT: create
592 * an alternate slice for the default label, if
593 * device type is DTYPE_DIRECT an architectures default
594 * label type is VTOC16.
595 * Otherwise alternate slice will no be created.
598 * CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8: report a default
599 * geometry and label for DKIOCGGEOM and DKIOCGVTOC
600 * on architecture with VTOC8 label types.
602 * CMLB_OFF_BY_ONE: do the workaround for legacy off-by-
603 * one bug in obtaining capacity (in sd):
604 * SCSI READ_CAPACITY command returns the LBA number of the
605 * last logical block, but sd once treated this number as
606 * disks' capacity on x86 platform. And LBAs are addressed
607 * based 0. So the last block was lost on x86 platform.
609 * Now, we remove this workaround. In order for present sd
610 * driver to work with disks which are labeled/partitioned
611 * via previous sd, we add workaround as follows:
613 * 1) Locate backup EFI label: cmlb searches the next to
615 * block for backup EFI label. If fails, it will
616 * turn to the last block for backup EFI label;
618 * 2) Clear backup EFI label: cmlb first search the last
619 * block for backup EFI label, and will search the
620 * next to last block only if failed for the last
623 * 3) Calculate geometry:refer to cmlb_convert_geometry()
624 * If capacity increasing by 1 causes disks' capacity
625 * to cross over the limits in geometry calculation,
626 * geometry info will change. This will raise an issue:
627 * In case that primary VTOC label is destroyed, format
628 * commandline can restore it via backup VTOC labels.
629 * And format locates backup VTOC labels by use of
630 * geometry. So changing geometry will
631 * prevent format from finding backup VTOC labels. To
632 * eliminate this side effect for compatibility,
633 * sd uses (capacity -1) to calculate geometry;
635 * 4) 1TB disks: some important data structures use
636 * 32-bit signed long/int (for example, daddr_t),
637 * so that sd doesn't support a disk with capacity
638 * larger than 1TB on 32-bit platform. However,
639 * for exactly 1TB disk, it was treated as (1T - 512)B
640 * in the past, and could have valid Solaris
641 * partitions. To workaround this, if an exactly 1TB
642 * disk has Solaris fdisk partition, it will be allowed
647 * CMLB_FAKE_LABEL_ONE_PARTITION: create s0 and s2 covering
648 * the entire disk, if there is no valid partition info.
649 * If there is a valid Solaris partition, s0 and s2 will
650 * only cover the entire Solaris partition.
652 * CMLB_CREATE_P0_MINOR_NODE: create p0 node covering
653 * the entire disk. Used by lofi to ensure presence of
654 * whole disk device node in case of LOFI_MAP_FILE ioctl.
656 * cmlbhandle cmlb handle associated with device
658 * tg_cookie cookie from target driver to be passed back to target
659 * driver when we call back to it through tg_ops.
662 * Assumes a default label based on capacity for non-removable devices.
663 * If capacity > 1TB, EFI is assumed otherwise VTOC (default VTOC
664 * for the architecture).
666 * For removable devices, default label type is assumed to be VTOC
667 * type. Create minor nodes based on a default label type.
668 * Label on the media is not validated.
669 * minor number consists of:
670 * if _SUNOS_VTOC_8 is defined
671 * lowest 3 bits is taken as partition number
672 * the rest is instance number
673 * if _SUNOS_VTOC_16 is defined
674 * lowest 6 bits is taken as partition number
675 * the rest is instance number
680 * ENXIO creating minor nodes failed.
681 * EINVAL invalid arg, unsupported tg_ops version
684 cmlb_attach(dev_info_t
*devi
, cmlb_tg_ops_t
*tgopsp
, int device_type
,
685 boolean_t is_removable
, boolean_t is_hotpluggable
, char *node_type
,
686 int alter_behavior
, cmlb_handle_t cmlbhandle
, void *tg_cookie
)
689 struct cmlb_lun
*cl
= (struct cmlb_lun
*)cmlbhandle
;
693 if (tgopsp
->tg_version
< TG_DK_OPS_VERSION_1
)
696 mutex_enter(CMLB_MUTEX(cl
));
698 CMLB_DEVINFO(cl
) = devi
;
699 cl
->cmlb_tg_ops
= tgopsp
;
700 cl
->cl_device_type
= device_type
;
701 cl
->cl_is_removable
= is_removable
;
702 cl
->cl_is_hotpluggable
= is_hotpluggable
;
703 cl
->cl_node_type
= node_type
;
704 cl
->cl_sys_blocksize
= DEV_BSIZE
;
705 cl
->cl_f_geometry_is_valid
= B_FALSE
;
706 cl
->cl_def_labeltype
= CMLB_LABEL_VTOC
;
707 cl
->cl_alter_behavior
= alter_behavior
;
708 cl
->cl_reserved
= -1;
709 cl
->cl_msglog_flag
|= CMLB_ALLOW_2TB_WARN
;
710 #if defined(__i386) || defined(__amd64)
711 cl
->cl_logical_drive_count
= 0;
715 mutex_exit(CMLB_MUTEX(cl
));
716 status
= DK_TG_GETCAP(cl
, &cap
, tg_cookie
);
717 mutex_enter(CMLB_MUTEX(cl
));
718 if (status
== 0 && cap
> CMLB_EXTVTOC_LIMIT
) {
719 /* set default EFI if > 2TB */
720 cl
->cl_def_labeltype
= CMLB_LABEL_EFI
;
724 /* create minor nodes based on default label type */
725 cl
->cl_last_labeltype
= CMLB_LABEL_UNDEF
;
726 cl
->cl_cur_labeltype
= CMLB_LABEL_UNDEF
;
728 if (cmlb_create_minor_nodes(cl
) != 0) {
729 mutex_exit(CMLB_MUTEX(cl
));
733 /* Define the dynamic properties for devinfo spapshots. */
734 i_ddi_prop_dyn_driver_set(CMLB_DEVINFO(cl
), cmlb_prop_dyn
);
736 cl
->cl_state
= CMLB_ATTACHED
;
738 mutex_exit(CMLB_MUTEX(cl
));
745 * Invalidate in-core labeling data and remove all minor nodes for
746 * the device associate with handle.
749 * cmlbhandle cmlb handle associated with device.
751 * tg_cookie cookie from target driver to be passed back to target
752 * driver when we call back to it through tg_ops.
757 cmlb_detach(cmlb_handle_t cmlbhandle
, void *tg_cookie
)
759 struct cmlb_lun
*cl
= (struct cmlb_lun
*)cmlbhandle
;
761 mutex_enter(CMLB_MUTEX(cl
));
762 cl
->cl_def_labeltype
= CMLB_LABEL_UNDEF
;
763 cl
->cl_f_geometry_is_valid
= B_FALSE
;
764 ddi_remove_minor_node(CMLB_DEVINFO(cl
), NULL
);
765 i_ddi_prop_dyn_driver_set(CMLB_DEVINFO(cl
), NULL
);
766 cl
->cl_state
= CMLB_INITED
;
767 mutex_exit(CMLB_MUTEX(cl
));
776 * cmlbhandle cmlb handle associated with device.
778 * flags operation flags. used for verbosity control
780 * tg_cookie cookie from target driver to be passed back to target
781 * driver when we call back to it through tg_ops.
785 * If new label type is different from the current, adjust minor nodes
790 * Note: having fdisk but no solaris partition is assumed
793 * ENOMEM memory allocation failed
794 * EIO i/o errors during read or get capacity
795 * EACCESS reservation conflicts
796 * EINVAL label was corrupt, or no default label was assumed
797 * ENXIO invalid handle
800 cmlb_validate(cmlb_handle_t cmlbhandle
, int flags
, void *tg_cookie
)
802 struct cmlb_lun
*cl
= (struct cmlb_lun
*)cmlbhandle
;
807 * Temp work-around checking cl for NULL since there is a bug
808 * in sd_detach calling this routine from taskq_dispatch
814 mutex_enter(CMLB_MUTEX(cl
));
815 if (cl
->cl_state
< CMLB_ATTACHED
) {
816 mutex_exit(CMLB_MUTEX(cl
));
820 rval
= cmlb_validate_geometry((struct cmlb_lun
*)cmlbhandle
, B_TRUE
,
823 if (rval
== ENOTSUP
) {
824 if (cl
->cl_f_geometry_is_valid
) {
825 cl
->cl_cur_labeltype
= CMLB_LABEL_EFI
;
833 cl
->cl_cur_labeltype
= CMLB_LABEL_VTOC
;
837 (void) cmlb_create_minor_nodes(cl
);
839 mutex_exit(CMLB_MUTEX(cl
));
845 * Invalidate in core label data
848 * cmlbhandle cmlb handle associated with device.
849 * tg_cookie cookie from target driver to be passed back to target
850 * driver when we call back to it through tg_ops.
854 cmlb_invalidate(cmlb_handle_t cmlbhandle
, void *tg_cookie
)
856 struct cmlb_lun
*cl
= (struct cmlb_lun
*)cmlbhandle
;
861 mutex_enter(CMLB_MUTEX(cl
));
862 cl
->cl_f_geometry_is_valid
= B_FALSE
;
863 mutex_exit(CMLB_MUTEX(cl
));
868 * Get status on whether the incore label/geom data is valid
871 * cmlbhandle cmlb handle associated with device.
874 * B_TRUE if incore label/geom data is valid.
881 cmlb_is_valid(cmlb_handle_t cmlbhandle
)
883 struct cmlb_lun
*cl
= (struct cmlb_lun
*)cmlbhandle
;
885 if (cmlbhandle
== NULL
)
888 return (cl
->cl_f_geometry_is_valid
);
897 * Close the device, revert to a default label minor node for the device,
898 * if it is removable.
901 * cmlbhandle cmlb handle associated with device.
903 * tg_cookie cookie from target driver to be passed back to target
904 * driver when we call back to it through tg_ops.
907 * ENXIO Re-creating minor node failed.
911 cmlb_close(cmlb_handle_t cmlbhandle
, void *tg_cookie
)
913 struct cmlb_lun
*cl
= (struct cmlb_lun
*)cmlbhandle
;
915 mutex_enter(CMLB_MUTEX(cl
));
916 cl
->cl_f_geometry_is_valid
= B_FALSE
;
918 /* revert to default minor node for this device */
919 if (ISREMOVABLE(cl
)) {
920 cl
->cl_cur_labeltype
= CMLB_LABEL_UNDEF
;
921 (void) cmlb_create_minor_nodes(cl
);
924 mutex_exit(CMLB_MUTEX(cl
));
929 * cmlb_get_devid_block:
930 * get the block number where device id is stored.
933 * cmlbhandle cmlb handle associated with device.
934 * devidblockp pointer to block number.
935 * tg_cookie cookie from target driver to be passed back to target
936 * driver when we call back to it through tg_ops.
939 * It stores the block number of device id in the area pointed to
941 * with the block number of device id.
945 * EINVAL device id does not apply to current label type.
949 cmlb_get_devid_block(cmlb_handle_t cmlbhandle
, diskaddr_t
*devidblockp
,
952 daddr_t spc
, blk
, head
, cyl
;
953 struct cmlb_lun
*cl
= (struct cmlb_lun
*)cmlbhandle
;
955 mutex_enter(CMLB_MUTEX(cl
));
956 if (cl
->cl_state
< CMLB_ATTACHED
) {
957 mutex_exit(CMLB_MUTEX(cl
));
961 if ((!cl
->cl_f_geometry_is_valid
) ||
962 (cl
->cl_solaris_size
< DK_LABEL_LOC
)) {
963 mutex_exit(CMLB_MUTEX(cl
));
967 if (cl
->cl_cur_labeltype
== CMLB_LABEL_EFI
) {
968 if (cl
->cl_reserved
!= -1) {
969 blk
= cl
->cl_map
[cl
->cl_reserved
].dkl_cylno
;
971 mutex_exit(CMLB_MUTEX(cl
));
975 /* if the disk is unlabeled, don't write a devid to it */
976 if (cl
->cl_label_from_media
!= CMLB_LABEL_VTOC
) {
977 mutex_exit(CMLB_MUTEX(cl
));
981 /* this geometry doesn't allow us to write a devid */
982 if (cl
->cl_g
.dkg_acyl
< 2) {
983 mutex_exit(CMLB_MUTEX(cl
));
988 * Subtract 2 guarantees that the next to last cylinder
991 cyl
= cl
->cl_g
.dkg_ncyl
+ cl
->cl_g
.dkg_acyl
- 2;
992 spc
= cl
->cl_g
.dkg_nhead
* cl
->cl_g
.dkg_nsect
;
993 head
= cl
->cl_g
.dkg_nhead
- 1;
994 blk
= cl
->cl_solaris_offset
+
995 (cyl
* (spc
- cl
->cl_g
.dkg_apc
)) +
996 (head
* cl
->cl_g
.dkg_nsect
) + 1;
1000 mutex_exit(CMLB_MUTEX(cl
));
1006 * Get partition info for specified partition number.
1009 * cmlbhandle cmlb handle associated with device.
1010 * part partition number
1011 * nblocksp pointer to number of blocks
1012 * startblockp pointer to starting block
1013 * partnamep pointer to name of partition
1014 * tagp pointer to tag info
1015 * tg_cookie cookie from target driver to be passed back to target
1016 * driver when we call back to it through tg_ops.
1020 * If in-core label is not valid, this functions tries to revalidate
1021 * the label. If label is valid, it stores the total number of blocks
1022 * in this partition in the area pointed to by nblocksp, starting
1023 * block number in area pointed to by startblockp, pointer to partition
1024 * name in area pointed to by partnamep, and tag value in area
1026 * For EFI labels, tag value will be set to 0.
1028 * For all nblocksp, startblockp and partnamep, tagp, a value of NULL
1029 * indicates the corresponding info is not requested.
1034 * EINVAL no valid label or requested partition number is invalid.
1038 cmlb_partinfo(cmlb_handle_t cmlbhandle
, int part
, diskaddr_t
*nblocksp
,
1039 diskaddr_t
*startblockp
, char **partnamep
, uint16_t *tagp
, void *tg_cookie
)
1042 struct cmlb_lun
*cl
= (struct cmlb_lun
*)cmlbhandle
;
1044 #if defined(__i386) || defined(__amd64)
1049 mutex_enter(CMLB_MUTEX(cl
));
1050 if (cl
->cl_state
< CMLB_ATTACHED
) {
1051 mutex_exit(CMLB_MUTEX(cl
));
1055 if (part
< 0 || part
>= MAXPART
) {
1058 if (!cl
->cl_f_geometry_is_valid
)
1059 (void) cmlb_validate_geometry((struct cmlb_lun
*)cl
,
1060 B_FALSE
, 0, tg_cookie
);
1062 if (((!cl
->cl_f_geometry_is_valid
) ||
1063 (part
< NDKMAP
&& cl
->cl_solaris_size
== 0)) &&
1064 (part
!= P0_RAW_DISK
)) {
1067 if (startblockp
!= NULL
)
1068 *startblockp
= (diskaddr_t
)cl
->cl_offset
[part
];
1070 if (nblocksp
!= NULL
)
1071 *nblocksp
= (diskaddr_t
)
1072 cl
->cl_map
[part
].dkl_nblk
;
1076 ((cl
->cl_cur_labeltype
== CMLB_LABEL_EFI
) ||
1077 (part
>= NDKMAP
)) ? V_UNASSIGNED
:
1078 cl
->cl_vtoc
.v_part
[part
].p_tag
;
1082 /* consistent with behavior of sd for getting minor name */
1083 if (partnamep
!= NULL
) {
1084 #if defined(__i386) || defined(__amd64)
1085 #if defined(_FIRMWARE_NEEDS_FDISK)
1086 if (part
> FDISK_P4
) {
1087 ext_part
= part
-FDISK_P4
-1;
1088 *partnamep
= dk_ext_minor_data
[ext_part
].name
;
1092 *partnamep
= dk_minor_data
[part
].name
;
1097 mutex_exit(CMLB_MUTEX(cl
));
1102 * cmlb_efi_label_capacity:
1103 * Get capacity stored in EFI disk label.
1106 * cmlbhandle cmlb handle associated with device.
1107 * capacity pointer to capacity stored in EFI disk label.
1108 * tg_cookie cookie from target driver to be passed back to target
1109 * driver when we call back to it through tg_ops.
1113 * If in-core label is not valid, this functions tries to revalidate
1114 * the label. If label is valid and is an EFI label, it stores the capacity
1115 * in disk label in the area pointed to by capacity.
1120 * EINVAL no valid EFI label or capacity is NULL.
1124 cmlb_efi_label_capacity(cmlb_handle_t cmlbhandle
, diskaddr_t
*capacity
,
1127 struct cmlb_lun
*cl
= (struct cmlb_lun
*)cmlbhandle
;
1131 mutex_enter(CMLB_MUTEX(cl
));
1132 if (cl
->cl_state
< CMLB_ATTACHED
) {
1133 mutex_exit(CMLB_MUTEX(cl
));
1137 if (!cl
->cl_f_geometry_is_valid
)
1138 (void) cmlb_validate_geometry((struct cmlb_lun
*)cl
, B_FALSE
,
1141 if ((!cl
->cl_f_geometry_is_valid
) || (capacity
== NULL
) ||
1142 (cl
->cl_cur_labeltype
!= CMLB_LABEL_EFI
)) {
1145 *capacity
= (diskaddr_t
)cl
->cl_map
[WD_NODE
].dkl_nblk
;
1149 mutex_exit(CMLB_MUTEX(cl
));
1153 /* Caller should make sure Test Unit Ready succeeds before calling this. */
1156 cmlb_ioctl(cmlb_handle_t cmlbhandle
, dev_t dev
, int cmd
, intptr_t arg
,
1157 int flag
, cred_t
*cred_p
, int *rval_p
, void *tg_cookie
)
1161 struct cmlb_lun
*cl
;
1163 cl
= (struct cmlb_lun
*)cmlbhandle
;
1167 mutex_enter(CMLB_MUTEX(cl
));
1168 if (cl
->cl_state
< CMLB_ATTACHED
) {
1169 mutex_exit(CMLB_MUTEX(cl
));
1178 #if defined(__i386) || defined(__amd64)
1179 case DKIOCSETEXTPART
:
1183 #if defined(__i386) || defined(__amd64)
1186 if (cl
->cl_blockcount
> CMLB_OLDVTOC_LIMIT
) {
1187 mutex_exit(CMLB_MUTEX(cl
));
1192 (void) cmlb_validate_geometry(cl
, 1, CMLB_SILENT
,
1200 if (cl
->cl_label_from_media
== CMLB_LABEL_EFI
) {
1201 /* GPT label on disk */
1202 mutex_exit(CMLB_MUTEX(cl
));
1205 (cl
->cl_blockcount
> CMLB_OLDVTOC_LIMIT
) {
1206 mutex_exit(CMLB_MUTEX(cl
));
1212 if (cl
->cl_label_from_media
== CMLB_LABEL_EFI
) {
1213 /* GPT label on disk */
1214 mutex_exit(CMLB_MUTEX(cl
));
1223 mutex_exit(CMLB_MUTEX(cl
));
1227 cmlb_dbg(CMLB_TRACE
, cl
, "DKIOCGGEOM\n");
1228 err
= cmlb_dkio_get_geometry(cl
, (caddr_t
)arg
, flag
, tg_cookie
);
1232 cmlb_dbg(CMLB_TRACE
, cl
, "DKIOCSGEOM\n");
1233 err
= cmlb_dkio_set_geometry(cl
, (caddr_t
)arg
, flag
);
1237 cmlb_dbg(CMLB_TRACE
, cl
, "DKIOCGAPART\n");
1238 err
= cmlb_dkio_get_partition(cl
, (caddr_t
)arg
,
1243 cmlb_dbg(CMLB_TRACE
, cl
, "DKIOCSAPART\n");
1244 err
= cmlb_dkio_set_partition(cl
, (caddr_t
)arg
, flag
);
1248 cmlb_dbg(CMLB_TRACE
, cl
, "DKIOCGVTOC\n");
1249 err
= cmlb_dkio_get_vtoc(cl
, (caddr_t
)arg
, flag
, tg_cookie
);
1253 cmlb_dbg(CMLB_TRACE
, cl
, "DKIOCGVTOC\n");
1254 err
= cmlb_dkio_get_extvtoc(cl
, (caddr_t
)arg
, flag
, tg_cookie
);
1258 cmlb_dbg(CMLB_TRACE
, cl
, "DKIOCGETEFI\n");
1259 err
= cmlb_dkio_get_efi(cl
, (caddr_t
)arg
, flag
, tg_cookie
);
1262 case DKIOCPARTITION
:
1263 cmlb_dbg(CMLB_TRACE
, cl
, "DKIOCPARTITION\n");
1264 err
= cmlb_dkio_partition(cl
, (caddr_t
)arg
, flag
, tg_cookie
);
1268 cmlb_dbg(CMLB_TRACE
, cl
, "DKIOCSVTOC\n");
1269 err
= cmlb_dkio_set_vtoc(cl
, dev
, (caddr_t
)arg
, flag
,
1274 cmlb_dbg(CMLB_TRACE
, cl
, "DKIOCSVTOC\n");
1275 err
= cmlb_dkio_set_extvtoc(cl
, dev
, (caddr_t
)arg
, flag
,
1280 cmlb_dbg(CMLB_TRACE
, cl
, "DKIOCSETEFI\n");
1281 err
= cmlb_dkio_set_efi(cl
, dev
, (caddr_t
)arg
, flag
, tg_cookie
);
1285 cmlb_dbg(CMLB_TRACE
, cl
, "DKIOCGMBOOT\n");
1286 err
= cmlb_dkio_get_mboot(cl
, (caddr_t
)arg
, flag
, tg_cookie
);
1290 cmlb_dbg(CMLB_TRACE
, cl
, "DKIOCSMBOOT\n");
1291 err
= cmlb_dkio_set_mboot(cl
, (caddr_t
)arg
, flag
, tg_cookie
);
1293 case DKIOCG_PHYGEOM
:
1294 cmlb_dbg(CMLB_TRACE
, cl
, "DKIOCG_PHYGEOM\n");
1295 #if defined(__i386) || defined(__amd64)
1296 err
= cmlb_dkio_get_phygeom(cl
, (caddr_t
)arg
, flag
, tg_cookie
);
1301 case DKIOCG_VIRTGEOM
:
1302 cmlb_dbg(CMLB_TRACE
, cl
, "DKIOCG_VIRTGEOM\n");
1303 #if defined(__i386) || defined(__amd64)
1304 err
= cmlb_dkio_get_virtgeom(cl
, (caddr_t
)arg
, flag
);
1310 cmlb_dbg(CMLB_TRACE
, cl
, "DKIOCPARTINFO");
1311 #if defined(__i386) || defined(__amd64)
1312 err
= cmlb_dkio_partinfo(cl
, dev
, (caddr_t
)arg
, flag
);
1317 case DKIOCEXTPARTINFO
:
1318 cmlb_dbg(CMLB_TRACE
, cl
, "DKIOCPARTINFO");
1319 #if defined(__i386) || defined(__amd64)
1320 err
= cmlb_dkio_extpartinfo(cl
, dev
, (caddr_t
)arg
, flag
);
1325 #if defined(__i386) || defined(__amd64)
1326 case DKIOCSETEXTPART
:
1327 cmlb_dbg(CMLB_TRACE
, cl
, "DKIOCSETEXTPART");
1328 err
= cmlb_dkio_set_ext_part(cl
, (caddr_t
)arg
, flag
, tg_cookie
);
1337 * An ioctl that succeeds and changed ('set') size(9P) information
1338 * needs to invalidate the cached devinfo snapshot to avoid having
1339 * old information being returned in a snapshots.
1341 * NB: When available, call ddi_change_minor_node() to clear
1342 * SSIZEVALID in specfs vnodes via spec_size_invalidate().
1351 i_ddi_prop_dyn_cache_invalidate(CMLB_DEVINFO(cl
),
1352 i_ddi_prop_dyn_driver_get(CMLB_DEVINFO(cl
)));
1359 cmlb_make_device(struct cmlb_lun
*cl
)
1361 if (cl
->cl_alter_behavior
& CMLB_CREATE_P0_MINOR_NODE
) {
1362 return (makedevice(ddi_driver_major(CMLB_DEVINFO(cl
)),
1364 CMLB_DEVINFO(cl
)) << CMLBUNIT_FORCE_P0_SHIFT
));
1366 return (makedevice(ddi_driver_major(CMLB_DEVINFO(cl
)),
1367 ddi_get_instance(CMLB_DEVINFO(cl
)) << CMLBUNIT_SHIFT
));
1372 * Function: cmlb_check_update_blockcount
1374 * Description: If current capacity value is invalid, obtains the
1375 * current capacity from target driver.
1377 * Return Code: 0 success
1381 cmlb_check_update_blockcount(struct cmlb_lun
*cl
, void *tg_cookie
)
1384 diskaddr_t capacity
;
1387 ASSERT(mutex_owned(CMLB_MUTEX(cl
)));
1389 if (cl
->cl_f_geometry_is_valid
)
1392 mutex_exit(CMLB_MUTEX(cl
));
1393 status
= DK_TG_GETCAP(cl
, &capacity
, tg_cookie
);
1395 mutex_enter(CMLB_MUTEX(cl
));
1399 status
= DK_TG_GETBLOCKSIZE(cl
, &lbasize
, tg_cookie
);
1400 mutex_enter(CMLB_MUTEX(cl
));
1404 if ((capacity
!= 0) && (lbasize
!= 0)) {
1405 cl
->cl_blockcount
= capacity
;
1406 cl
->cl_tgt_blocksize
= lbasize
;
1407 if (!cl
->cl_is_removable
) {
1408 cl
->cl_sys_blocksize
= lbasize
;
1417 cmlb_create_minor(dev_info_t
*dip
, char *name
, int spec_type
,
1418 minor_t minor_num
, char *node_type
, int flag
, boolean_t internal
)
1421 return (ddi_create_internal_pathname(dip
,
1422 name
, spec_type
, minor_num
));
1424 return (ddi_create_minor_node(dip
,
1425 name
, spec_type
, minor_num
, node_type
, flag
));
1429 * Function: cmlb_create_minor_nodes
1431 * Description: Create or adjust the minor device nodes for the instance.
1432 * Minor nodes are created based on default label type,
1433 * current label type and last label type we created
1434 * minor nodes based on.
1437 * Arguments: cl - driver soft state (unit) structure
1439 * Return Code: 0 success
1442 * Context: Kernel thread context
1445 cmlb_create_minor_nodes(struct cmlb_lun
*cl
)
1447 struct driver_minor_data
*dmdp
;
1448 int instance
, shift
;
1450 cmlb_label_t newlabeltype
;
1454 ASSERT(mutex_owned(CMLB_MUTEX(cl
)));
1456 internal
= (cl
->cl_alter_behavior
& CMLB_INTERNAL_MINOR_NODES
) != 0;
1458 if (cl
->cl_alter_behavior
& CMLB_CREATE_P0_MINOR_NODE
)
1459 shift
= CMLBUNIT_FORCE_P0_SHIFT
;
1461 shift
= CMLBUNIT_SHIFT
;
1463 /* check the most common case */
1464 if (cl
->cl_cur_labeltype
!= CMLB_LABEL_UNDEF
&&
1465 cl
->cl_last_labeltype
== cl
->cl_cur_labeltype
) {
1470 if (cl
->cl_def_labeltype
== CMLB_LABEL_UNDEF
) {
1471 /* we should never get here */
1475 if (cl
->cl_last_labeltype
== CMLB_LABEL_UNDEF
) {
1476 /* first time during attach */
1477 newlabeltype
= cl
->cl_def_labeltype
;
1479 instance
= ddi_get_instance(CMLB_DEVINFO(cl
));
1481 /* Create all the minor nodes for this target. */
1482 dmdp
= (newlabeltype
== CMLB_LABEL_EFI
) ? dk_minor_data_efi
:
1484 while (dmdp
->name
!= NULL
) {
1486 (void) sprintf(name
, "%s", dmdp
->name
);
1488 if (cmlb_create_minor(CMLB_DEVINFO(cl
), name
,
1490 (instance
<< shift
) | dmdp
->minor
,
1491 cl
->cl_node_type
, 0, internal
) == DDI_FAILURE
) {
1493 * Clean up any nodes that may have been
1494 * created, in case this fails in the middle
1497 ddi_remove_minor_node(CMLB_DEVINFO(cl
), NULL
);
1502 cl
->cl_last_labeltype
= newlabeltype
;
1503 #if defined(_SUNOS_VTOC_8)
1505 * "emulate" p0 device for sparc, used by lofi
1507 if (cl
->cl_alter_behavior
& CMLB_CREATE_P0_MINOR_NODE
) {
1508 if (cmlb_create_minor(CMLB_DEVINFO(cl
), "q", S_IFBLK
,
1509 (instance
<< CMLBUNIT_FORCE_P0_SHIFT
) | P0_RAW_DISK
,
1510 cl
->cl_node_type
, NULL
, internal
) == DDI_FAILURE
) {
1511 ddi_remove_minor_node(CMLB_DEVINFO(cl
), NULL
);
1515 if (cmlb_create_minor(CMLB_DEVINFO(cl
), "q,raw",
1517 (instance
<< CMLBUNIT_FORCE_P0_SHIFT
) | P0_RAW_DISK
,
1518 cl
->cl_node_type
, NULL
, internal
) == DDI_FAILURE
) {
1519 ddi_remove_minor_node(CMLB_DEVINFO(cl
), NULL
);
1523 #endif /* defined(_SUNOS_VTOC_8) */
1527 /* Not first time */
1528 if (cl
->cl_cur_labeltype
== CMLB_LABEL_UNDEF
) {
1529 if (cl
->cl_last_labeltype
!= cl
->cl_def_labeltype
) {
1530 /* close time, revert to default. */
1531 newlabeltype
= cl
->cl_def_labeltype
;
1534 * do nothing since the type for which we last created
1535 * nodes matches the default
1540 if (cl
->cl_cur_labeltype
!= cl
->cl_last_labeltype
) {
1541 /* We are not closing, use current label type */
1542 newlabeltype
= cl
->cl_cur_labeltype
;
1545 * do nothing since the type for which we last created
1546 * nodes matches the current label type
1552 instance
= ddi_get_instance(CMLB_DEVINFO(cl
));
1555 * Currently we only fix up the s7 node when we are switching
1556 * label types from or to EFI. This is consistent with
1557 * current behavior of sd.
1559 if (newlabeltype
== CMLB_LABEL_EFI
&&
1560 cl
->cl_last_labeltype
!= CMLB_LABEL_EFI
) {
1561 /* from vtoc to EFI */
1562 ddi_remove_minor_node(CMLB_DEVINFO(cl
), "h");
1563 ddi_remove_minor_node(CMLB_DEVINFO(cl
), "h,raw");
1564 (void) cmlb_create_minor(CMLB_DEVINFO(cl
), "wd",
1565 S_IFBLK
, (instance
<< shift
) | WD_NODE
,
1566 cl
->cl_node_type
, 0, internal
);
1567 (void) cmlb_create_minor(CMLB_DEVINFO(cl
), "wd,raw",
1568 S_IFCHR
, (instance
<< shift
) | WD_NODE
,
1569 cl
->cl_node_type
, 0, internal
);
1571 /* from efi to vtoc */
1572 ddi_remove_minor_node(CMLB_DEVINFO(cl
), "wd");
1573 ddi_remove_minor_node(CMLB_DEVINFO(cl
), "wd,raw");
1574 (void) cmlb_create_minor(CMLB_DEVINFO(cl
), "h",
1575 S_IFBLK
, (instance
<< shift
) | WD_NODE
,
1576 cl
->cl_node_type
, 0, internal
);
1577 (void) cmlb_create_minor(CMLB_DEVINFO(cl
), "h,raw",
1578 S_IFCHR
, (instance
<< shift
) | WD_NODE
,
1579 cl
->cl_node_type
, 0, internal
);
1582 cl
->cl_last_labeltype
= newlabeltype
;
1587 * Function: cmlb_validate_geometry
1589 * Description: Read the label from the disk (if present). Update the unit's
1590 * geometry and vtoc information from the data in the label.
1591 * Verify that the label is valid.
1594 * cl driver soft state (unit) structure
1596 * forcerevalid force revalidation even if we are already valid.
1597 * flags operation flags from target driver. Used for verbosity
1598 * control at this time.
1599 * tg_cookie cookie from target driver to be passed back to target
1600 * driver when we call back to it through tg_ops.
1602 * Return Code: 0 - Successful completion
1603 * EINVAL - Invalid value in cl->cl_tgt_blocksize or
1604 * cl->cl_blockcount; or label on disk is corrupted
1606 * EACCES - Reservation conflict at the device.
1607 * ENOMEM - Resource allocation error
1608 * ENOTSUP - geometry not applicable
1610 * Context: Kernel thread only (can sleep).
1613 cmlb_validate_geometry(struct cmlb_lun
*cl
, boolean_t forcerevalid
, int flags
,
1616 int label_error
= 0;
1617 diskaddr_t capacity
;
1620 ASSERT(mutex_owned(CMLB_MUTEX(cl
)));
1622 if ((cl
->cl_f_geometry_is_valid
) && (!forcerevalid
)) {
1623 if (cl
->cl_cur_labeltype
== CMLB_LABEL_EFI
)
1628 if (cmlb_check_update_blockcount(cl
, tg_cookie
) != 0)
1631 capacity
= cl
->cl_blockcount
;
1634 * Set up the "whole disk" fdisk partition; this should always
1635 * exist, regardless of whether the disk contains an fdisk table
1638 cl
->cl_map
[P0_RAW_DISK
].dkl_cylno
= 0;
1639 cl
->cl_offset
[P0_RAW_DISK
] = 0;
1641 * note if capacity > int32_max(1TB) we are in 64bit environment
1642 * so no truncation happens
1644 cl
->cl_map
[P0_RAW_DISK
].dkl_nblk
= capacity
;
1647 * Refresh the logical and physical geometry caches.
1648 * (data from MODE SENSE format/rigid disk geometry pages,
1649 * and scsi_ifgetcap("geometry").
1651 cmlb_resync_geom_caches(cl
, capacity
, tg_cookie
);
1653 cl
->cl_label_from_media
= CMLB_LABEL_UNDEF
;
1654 label_error
= cmlb_use_efi(cl
, capacity
, flags
, tg_cookie
);
1655 if (label_error
== 0) {
1657 /* found a valid EFI label */
1658 cmlb_dbg(CMLB_TRACE
, cl
,
1659 "cmlb_validate_geometry: found EFI label\n");
1661 * solaris_size and geometry_is_valid are set in
1667 /* NO EFI label found */
1669 if (capacity
> CMLB_EXTVTOC_LIMIT
) {
1670 if (label_error
== ESRCH
) {
1672 * they've configured a LUN over 2TB, but used
1673 * format.dat to restrict format's view of the
1674 * capacity to be under 2TB in some earlier Solaris
1677 /* i.e > 2TB with a VTOC < 2TB */
1678 if (!(flags
& CMLB_SILENT
) &&
1679 (cl
->cl_msglog_flag
& CMLB_ALLOW_2TB_WARN
)) {
1681 cmlb_log(CMLB_DEVINFO(cl
), CMLB_LABEL(cl
),
1682 CE_NOTE
, "!Disk (%s%d) is limited to 2 TB "
1683 "due to VTOC label. To use the full "
1684 "capacity of the disk, use format(8) to "
1685 "relabel the disk with EFI/GPT label.\n",
1687 ddi_get_instance(CMLB_DEVINFO(cl
)));
1689 cl
->cl_msglog_flag
&= ~CMLB_ALLOW_2TB_WARN
;
1699 * at this point it is either labeled with a VTOC or it is
1700 * under 1TB (<= 1TB actually for off-by-1)
1704 * Only DIRECT ACCESS devices will have Scl labels.
1705 * CD's supposedly have a Scl label, too
1707 if (cl
->cl_device_type
== DTYPE_DIRECT
|| ISREMOVABLE(cl
)) {
1708 struct dk_label
*dkl
;
1709 offset_t label_addr
;
1714 * Note: This will set up cl->cl_solaris_size and
1715 * cl->cl_solaris_offset.
1717 rval
= cmlb_read_fdisk(cl
, capacity
, tg_cookie
);
1718 if ((rval
!= 0) && !ISCD(cl
)) {
1719 ASSERT(mutex_owned(CMLB_MUTEX(cl
)));
1723 if (cl
->cl_solaris_size
<= DK_LABEL_LOC
) {
1725 * Found fdisk table but no Solaris partition entry,
1726 * so don't call cmlb_uselabel() and don't create
1730 cl
->cl_f_geometry_is_valid
= B_TRUE
;
1731 goto no_solaris_partition
;
1734 label_addr
= (daddr_t
)(cl
->cl_solaris_offset
+ DK_LABEL_LOC
);
1736 buffer_size
= cl
->cl_sys_blocksize
;
1738 cmlb_dbg(CMLB_TRACE
, cl
, "cmlb_validate_geometry: "
1739 "label_addr: 0x%x allocation size: 0x%x\n",
1740 label_addr
, buffer_size
);
1742 if ((dkl
= kmem_zalloc(buffer_size
, KM_NOSLEEP
)) == NULL
)
1745 mutex_exit(CMLB_MUTEX(cl
));
1746 rval
= DK_TG_READ(cl
, dkl
, label_addr
, buffer_size
, tg_cookie
);
1747 mutex_enter(CMLB_MUTEX(cl
));
1752 * cmlb_uselabel will establish that the geometry
1755 if (cmlb_uselabel(cl
,
1756 (struct dk_label
*)(uintptr_t)dkl
, flags
) !=
1757 CMLB_LABEL_IS_VALID
) {
1758 label_error
= EINVAL
;
1760 cl
->cl_label_from_media
= CMLB_LABEL_VTOC
;
1763 label_error
= EACCES
;
1766 label_error
= EINVAL
;
1770 kmem_free(dkl
, buffer_size
);
1774 * If a valid label was not found, AND if no reservation conflict
1775 * was detected, then go ahead and create a default label (4069506).
1777 * Note: currently, for VTOC_8 devices, the default label is created
1778 * for removables and hotpluggables only. For VTOC_16 devices, the
1779 * default label will be created for all devices.
1780 * (see cmlb_build_default_label)
1782 #if defined(_SUNOS_VTOC_8)
1783 if ((ISREMOVABLE(cl
) || ISHOTPLUGGABLE(cl
)) &&
1784 (label_error
!= EACCES
)) {
1785 #elif defined(_SUNOS_VTOC_16)
1786 if (label_error
!= EACCES
) {
1788 if (!cl
->cl_f_geometry_is_valid
) {
1789 cmlb_build_default_label(cl
, tg_cookie
);
1794 no_solaris_partition
:
1796 #if defined(_SUNOS_VTOC_16)
1798 * If we have valid geometry, set up the remaining fdisk partitions.
1799 * Note that dkl_cylno is not used for the fdisk map entries, so
1800 * we set it to an entirely bogus value.
1802 for (count
= 0; count
< FDISK_PARTS
; count
++) {
1803 cl
->cl_map
[FDISK_P1
+ count
].dkl_cylno
= UINT16_MAX
;
1804 cl
->cl_map
[FDISK_P1
+ count
].dkl_nblk
=
1805 cl
->cl_fmap
[count
].fmap_nblk
;
1807 cl
->cl_offset
[FDISK_P1
+ count
] =
1808 cl
->cl_fmap
[count
].fmap_start
;
1812 for (count
= 0; count
< NDKMAP
; count
++) {
1813 #if defined(_SUNOS_VTOC_8)
1814 struct dk_map
*lp
= &cl
->cl_map
[count
];
1815 cl
->cl_offset
[count
] =
1816 cl
->cl_g
.dkg_nhead
* cl
->cl_g
.dkg_nsect
* lp
->dkl_cylno
;
1817 #elif defined(_SUNOS_VTOC_16)
1818 struct dkl_partition
*vp
= &cl
->cl_vtoc
.v_part
[count
];
1820 cl
->cl_offset
[count
] = vp
->p_start
+ cl
->cl_solaris_offset
;
1822 #error "No VTOC format defined."
1826 return (label_error
);
1829 #if defined(_SUNOS_VTOC_16)
1831 * Function: cmlb_convert_geometry
1833 * Description: Convert physical geometry into a dk_geom structure. In
1834 * other words, make sure we don't wrap 16-bit values.
1835 * e.g. converting from geom_cache to dk_geom
1837 * Context: Kernel thread only
1840 cmlb_convert_geometry(struct cmlb_lun
*cl
, diskaddr_t capacity
,
1841 struct dk_geom
*cl_g
, void *tg_cookie
)
1845 ASSERT(mutex_owned(CMLB_MUTEX(cl
)));
1847 /* Unlabeled SCSI floppy device */
1848 if (capacity
< 160) {
1850 cl_g
->dkg_nhead
= 1;
1851 cl_g
->dkg_ncyl
= capacity
;
1852 cl_g
->dkg_nsect
= 1;
1854 } else if (capacity
<= 0x1000) {
1855 cl_g
->dkg_nhead
= 2;
1856 cl_g
->dkg_ncyl
= 80;
1857 cl_g
->dkg_nsect
= capacity
/ (cl_g
->dkg_nhead
* cl_g
->dkg_ncyl
);
1862 * For all devices we calculate cylinders using the heads and sectors
1863 * we assign based on capacity of the device. The algorithm is
1864 * designed to be compatible with the way other operating systems
1865 * lay out fdisk tables for X86 and to insure that the cylinders never
1866 * exceed 65535 to prevent problems with X86 ioctls that report
1868 * For some smaller disk sizes we report geometry that matches those
1869 * used by X86 BIOS usage. For larger disks, we use SPT that are
1870 * multiples of 63, since other OSes that are not limited to 16-bits
1871 * for cylinders stop at 63 SPT we make do by using multiples of 63 SPT.
1873 * The following table (in order) illustrates some end result
1876 * Maximum number of blocks nhead nsect
1878 * 2097152 (1GB) 64 32
1879 * 16777216 (8GB) 128 32
1880 * 1052819775 (502.02GB) 255 63
1881 * 2105639550 (0.98TB) 255 126
1882 * 3158459325 (1.47TB) 255 189
1883 * 4211279100 (1.96TB) 255 252
1884 * 5264098875 (2.45TB) 255 315
1887 * For Solid State Drive(SSD), it uses 4K page size inside and may be
1888 * double with every new generation. If the I/O is not aligned with
1889 * page size on SSDs, SSDs perform a lot slower.
1890 * By default, Solaris partition starts from cylinder 1. It will be
1891 * misaligned even with 4K if using heads(255) and SPT(63). To
1892 * workaround the problem, if the device is SSD, we use heads(224) and
1893 * SPT multiple of 56. Thus the default Solaris partition starts from
1894 * a position that aligns with 128K on a 512 bytes sector size SSD.
1897 if (capacity
<= 0x200000) {
1898 cl_g
->dkg_nhead
= 64;
1899 cl_g
->dkg_nsect
= 32;
1900 } else if (capacity
<= 0x01000000) {
1901 cl_g
->dkg_nhead
= 128;
1902 cl_g
->dkg_nsect
= 32;
1904 tg_attribute_t tgattribute
;
1906 unsigned short nhead
;
1907 unsigned short nsect
;
1909 bzero(&tgattribute
, sizeof (tg_attribute_t
));
1911 mutex_exit(CMLB_MUTEX(cl
));
1913 (DK_TG_GETATTRIBUTE(cl
, &tgattribute
, tg_cookie
) == 0) ?
1914 tgattribute
.media_is_solid_state
: FALSE
;
1915 mutex_enter(CMLB_MUTEX(cl
));
1917 if (is_solid_state
) {
1925 cl_g
->dkg_nhead
= nhead
;
1927 /* make dkg_nsect be smallest multiple of nsect */
1928 cl_g
->dkg_nsect
= ((capacity
+
1929 (UINT16_MAX
* nhead
* nsect
) - 1) /
1930 (UINT16_MAX
* nhead
* nsect
)) * nsect
;
1932 if (cl_g
->dkg_nsect
== 0)
1933 cl_g
->dkg_nsect
= (UINT16_MAX
/ nsect
) * nsect
;
1940 * Function: cmlb_resync_geom_caches
1942 * Description: (Re)initialize both geometry caches: the virtual geometry
1943 * information is extracted from the HBA (the "geometry"
1944 * capability), and the physical geometry cache data is
1945 * generated by issuing MODE SENSE commands.
1948 * cl driver soft state (unit) structure
1949 * capacity disk capacity in #blocks
1950 * tg_cookie cookie from target driver to be passed back to target
1951 * driver when we call back to it through tg_ops.
1953 * Context: Kernel thread only (can sleep).
1956 cmlb_resync_geom_caches(struct cmlb_lun
*cl
, diskaddr_t capacity
,
1959 struct cmlb_geom pgeom
;
1960 struct cmlb_geom lgeom
;
1961 struct cmlb_geom
*pgeomp
= &pgeom
;
1962 unsigned short nhead
;
1963 unsigned short nsect
;
1968 ASSERT(mutex_owned(CMLB_MUTEX(cl
)));
1971 * Ask the controller for its logical geometry.
1972 * Note: if the HBA does not support scsi_ifgetcap("geometry"),
1973 * then the lgeom cache will be invalid.
1975 mutex_exit(CMLB_MUTEX(cl
));
1976 bzero(&lgeom
, sizeof (struct cmlb_geom
));
1977 ret
= DK_TG_GETVIRTGEOM(cl
, &lgeom
, tg_cookie
);
1978 mutex_enter(CMLB_MUTEX(cl
));
1980 bcopy(&lgeom
, &cl
->cl_lgeom
, sizeof (cl
->cl_lgeom
));
1983 * Initialize the pgeom cache from lgeom, so that if MODE SENSE
1984 * doesn't work, DKIOCG_PHYSGEOM can return reasonable values.
1986 if (ret
!= 0 || cl
->cl_lgeom
.g_nsect
== 0 ||
1987 cl
->cl_lgeom
.g_nhead
== 0) {
1989 * Note: Perhaps this needs to be more adaptive? The rationale
1990 * is that, if there's no HBA geometry from the HBA driver, any
1991 * guess is good, since this is the physical geometry. If MODE
1992 * SENSE fails this gives a max cylinder size for non-LBA access
1997 nhead
= cl
->cl_lgeom
.g_nhead
;
1998 nsect
= cl
->cl_lgeom
.g_nsect
;
2002 pgeomp
->g_nhead
= 1;
2003 pgeomp
->g_nsect
= nsect
* nhead
;
2005 pgeomp
->g_nhead
= nhead
;
2006 pgeomp
->g_nsect
= nsect
;
2009 spc
= pgeomp
->g_nhead
* pgeomp
->g_nsect
;
2010 pgeomp
->g_capacity
= capacity
;
2014 pgeomp
->g_ncyl
= pgeomp
->g_capacity
/ spc
;
2018 * Retrieve fresh geometry data from the hardware, stash it
2019 * here temporarily before we rebuild the incore label.
2021 * We want to use the MODE SENSE commands to derive the
2022 * physical geometry of the device, but if either command
2023 * fails, the logical geometry is used as the fallback for
2024 * disk label geometry.
2027 mutex_exit(CMLB_MUTEX(cl
));
2028 (void) DK_TG_GETPHYGEOM(cl
, pgeomp
, tg_cookie
);
2029 mutex_enter(CMLB_MUTEX(cl
));
2032 * Now update the real copy while holding the mutex. This
2033 * way the global copy is never in an inconsistent state.
2035 bcopy(pgeomp
, &cl
->cl_pgeom
, sizeof (cl
->cl_pgeom
));
2037 cmlb_dbg(CMLB_INFO
, cl
, "cmlb_resync_geom_caches: "
2038 "(cached from lgeom)\n");
2039 cmlb_dbg(CMLB_INFO
, cl
,
2040 " ncyl: %ld; acyl: %d; nhead: %d; nsect: %d\n",
2041 cl
->cl_pgeom
.g_ncyl
, cl
->cl_pgeom
.g_acyl
,
2042 cl
->cl_pgeom
.g_nhead
, cl
->cl_pgeom
.g_nsect
);
2043 cmlb_dbg(CMLB_INFO
, cl
, " lbasize: %d; capacity: %ld; "
2044 "intrlv: %d; rpm: %d\n", cl
->cl_pgeom
.g_secsize
,
2045 cl
->cl_pgeom
.g_capacity
, cl
->cl_pgeom
.g_intrlv
,
2046 cl
->cl_pgeom
.g_rpm
);
2050 #if defined(__i386) || defined(__amd64)
2052 * Function: cmlb_update_ext_minor_nodes
2054 * Description: Routine to add/remove extended partition device nodes
2057 * cl driver soft state (unit) structure
2058 * num_parts Number of logical drives found on the LUN
2060 * Should be called with the mutex held
2062 * Return Code: 0 for success
2064 * Context: User and Kernel thread
2068 cmlb_update_ext_minor_nodes(struct cmlb_lun
*cl
, int num_parts
)
2070 int i
, count
, shift
;
2073 struct driver_minor_data
*demdp
, *demdpr
;
2078 ASSERT(mutex_owned(CMLB_MUTEX(cl
)));
2079 ASSERT(cl
->cl_update_ext_minor_nodes
== 1);
2081 internal
= (cl
->cl_alter_behavior
& CMLB_INTERNAL_MINOR_NODES
) != 0;
2082 instance
= ddi_get_instance(CMLB_DEVINFO(cl
));
2083 demdp
= dk_ext_minor_data
;
2084 demdpr
= &dk_ext_minor_data
[MAX_EXT_PARTS
];
2086 if (cl
->cl_alter_behavior
& CMLB_CREATE_P0_MINOR_NODE
)
2087 shift
= CMLBUNIT_FORCE_P0_SHIFT
;
2089 shift
= CMLBUNIT_SHIFT
;
2091 if (cl
->cl_logical_drive_count
) {
2092 for (i
= 0; i
< cl
->cl_logical_drive_count
; i
++) {
2093 (void) sprintf(name
, "%s", demdp
->name
);
2094 ddi_remove_minor_node(CMLB_DEVINFO(cl
), name
);
2095 (void) sprintf(name
, "%s", demdpr
->name
);
2096 ddi_remove_minor_node(CMLB_DEVINFO(cl
), name
);
2100 /* There are existing device nodes. Remove them */
2101 devnm
= kmem_alloc(MAXNAMELEN
+ 1, KM_SLEEP
);
2102 (void) ddi_deviname(cl
->cl_devi
, devnm
);
2103 pdip
= ddi_get_parent(cl
->cl_devi
);
2104 (void) devfs_clean(pdip
, devnm
+ 1, DV_CLEAN_FORCE
);
2105 kmem_free(devnm
, MAXNAMELEN
+ 1);
2108 demdp
= dk_ext_minor_data
;
2109 demdpr
= &dk_ext_minor_data
[MAX_EXT_PARTS
];
2111 for (i
= 0; i
< num_parts
; i
++) {
2112 (void) sprintf(name
, "%s", demdp
->name
);
2113 if (cmlb_create_minor(CMLB_DEVINFO(cl
), name
,
2115 (instance
<< shift
) | demdp
->minor
,
2116 cl
->cl_node_type
, 0, internal
) == DDI_FAILURE
) {
2118 * Clean up any nodes that may have been
2119 * created, in case this fails in the middle
2122 ddi_remove_minor_node(CMLB_DEVINFO(cl
), NULL
);
2123 cl
->cl_logical_drive_count
= 0;
2126 (void) sprintf(name
, "%s", demdpr
->name
);
2127 if (ddi_create_minor_node(CMLB_DEVINFO(cl
), name
,
2129 (instance
<< shift
) | demdpr
->minor
,
2130 cl
->cl_node_type
, 0) == DDI_FAILURE
) {
2132 * Clean up any nodes that may have been
2133 * created, in case this fails in the middle
2136 ddi_remove_minor_node(CMLB_DEVINFO(cl
), NULL
);
2137 cl
->cl_logical_drive_count
= 0;
2144 /* Update the cl_map array for logical drives */
2145 for (count
= 0; count
< MAX_EXT_PARTS
; count
++) {
2146 cl
->cl_map
[FDISK_P4
+ 1 + count
].dkl_cylno
= UINT32_MAX
;
2147 cl
->cl_map
[FDISK_P4
+ 1 + count
].dkl_nblk
=
2148 cl
->cl_fmap
[FD_NUMPART
+ count
].fmap_nblk
;
2149 cl
->cl_offset
[FDISK_P4
+ 1 + count
] =
2150 cl
->cl_fmap
[FD_NUMPART
+ count
].fmap_start
;
2153 cl
->cl_logical_drive_count
= i
;
2154 cl
->cl_update_ext_minor_nodes
= 0;
2158 * Function: cmlb_validate_ext_part
2160 * Description: utility routine to validate an extended partition's
2161 * metadata as found on disk
2164 * cl driver soft state (unit) structure
2165 * part partition number of the extended partition
2166 * epart partition number of the logical drive
2167 * start absolute sector number of the start of the logical
2168 * drive being validated
2169 * size size of logical drive being validated
2171 * Return Code: 0 for success
2173 * Context: User and Kernel thread
2177 * 1. If start block is lesser than or equal to the end block
2178 * 2. If either start block or end block is beyond the bounadry
2179 * of the extended partition.
2180 * 3. start or end block overlap with existing partitions.
2181 * To check this, first make sure that the start block doesnt
2182 * overlap with existing partitions. Then, calculate the
2183 * possible end block for the given start block that doesnt
2184 * overlap with existing partitions. This can be calculated by
2185 * first setting the possible end block to the end of the
2186 * extended partition (optimistic) and then, checking if there
2187 * is any other partition that lies after the start of the
2188 * partition being validated. If so, set the possible end to
2189 * one block less than the beginning of the next nearest partition
2190 * If the actual end block is greater than the calculated end
2191 * block, we have an overlap.
2195 cmlb_validate_ext_part(struct cmlb_lun
*cl
, int part
, int epart
, uint32_t start
,
2199 uint32_t end
= start
+ size
- 1;
2200 uint32_t ext_start
= cl
->cl_fmap
[part
].fmap_start
;
2201 uint32_t ext_end
= ext_start
+ cl
->cl_fmap
[part
].fmap_nblk
- 1;
2203 uint32_t poss_end
= ext_end
;
2210 * Check if the logical drive boundaries are within that of the
2211 * extended partition.
2213 if (start
<= ext_start
|| start
> ext_end
|| end
<= ext_start
||
2219 * epart will be equal to FD_NUMPART if it is the first logical drive.
2220 * There is no need to check for overlaps with other logical drives,
2221 * since it is the only logical drive that we have come across so far.
2223 if (epart
== FD_NUMPART
) {
2227 /* Check for overlaps with existing logical drives */
2229 ts
= cl
->cl_fmap
[FD_NUMPART
].fmap_start
;
2230 te
= ts
+ cl
->cl_fmap
[FD_NUMPART
].fmap_nblk
- 1;
2232 while ((i
< epart
) && ts
&& te
) {
2233 if (start
>= ts
&& start
<= te
) {
2237 if ((ts
< poss_end
) && (ts
> start
)) {
2242 ts
= cl
->cl_fmap
[i
].fmap_start
;
2243 te
= ts
+ cl
->cl_fmap
[i
].fmap_nblk
- 1;
2246 if (end
> poss_end
) {
2255 * Function: cmlb_is_linux_swap
2257 * Description: utility routine to verify if a partition is a linux swap
2261 * cl driver soft state (unit) structure
2262 * part_start absolute sector number of the start of the partition
2264 * tg_cookie cookie from target driver to be passed back to target
2265 * driver when we call back to it through tg_ops.
2267 * Return Code: 0 for success
2269 * Context: User and Kernel thread
2272 * The linux swap magic "SWAP-SPACE" or "SWAPSPACE2" is found as the
2273 * last 10 bytes of a disk block whose size is that of the linux page
2274 * size. This disk block is found at the beginning of the swap partition.
2277 cmlb_is_linux_swap(struct cmlb_lun
*cl
, uint32_t part_start
, void *tg_cookie
)
2281 uint32_t seek_offset
;
2282 uint32_t linux_pg_size
;
2283 char *buf
, *linux_swap_magic
;
2284 int sec_sz
= cl
->cl_sys_blocksize
;
2285 /* Known linux kernel page sizes */
2286 uint32_t linux_pg_size_arr
[] = {4096, };
2289 ASSERT(mutex_owned(CMLB_MUTEX(cl
)));
2291 if ((buf
= kmem_zalloc(sec_sz
, KM_NOSLEEP
)) == NULL
) {
2296 * Check if there is a sane Solaris VTOC
2297 * If there is a valid vtoc, no need to lookup
2298 * for the linux swap signature.
2300 mutex_exit(CMLB_MUTEX(cl
));
2301 rval
= DK_TG_READ(cl
, buf
, part_start
+ DK_LABEL_LOC
,
2303 mutex_enter(CMLB_MUTEX(cl
));
2305 cmlb_dbg(CMLB_ERROR
, cl
,
2306 "cmlb_is_linux_swap: disk vtoc read err\n");
2311 if ((((struct dk_label
*)buf
)->dkl_magic
== DKL_MAGIC
) &&
2312 (((struct dk_label
*)buf
)->dkl_vtoc
.v_sanity
== VTOC_SANE
)) {
2318 /* No valid vtoc, so check for linux swap signature */
2319 linux_swap_magic
= buf
+ sec_sz
- 10;
2321 for (i
= 0; i
< sizeof (linux_pg_size_arr
)/sizeof (uint32_t); i
++) {
2322 linux_pg_size
= linux_pg_size_arr
[i
];
2323 seek_offset
= linux_pg_size
/sec_sz
- 1;
2324 seek_offset
+= part_start
;
2326 mutex_exit(CMLB_MUTEX(cl
));
2327 rval
= DK_TG_READ(cl
, buf
, seek_offset
, sec_sz
, tg_cookie
);
2328 mutex_enter(CMLB_MUTEX(cl
));
2331 cmlb_dbg(CMLB_ERROR
, cl
,
2332 "cmlb_is_linux_swap: disk read err\n");
2339 if ((strncmp(linux_swap_magic
, "SWAP-SPACE", 10) == 0) ||
2340 (strncmp(linux_swap_magic
, "SWAPSPACE2", 10) == 0)) {
2341 /* Found a linux swap */
2348 kmem_free(buf
, sec_sz
);
2354 * Function: cmlb_read_fdisk
2356 * Description: utility routine to read the fdisk table.
2359 * cl driver soft state (unit) structure
2360 * capacity disk capacity in #blocks
2361 * tg_cookie cookie from target driver to be passed back to target
2362 * driver when we call back to it through tg_ops.
2364 * Return Code: 0 for success (includes not reading for no_fdisk_present case
2365 * errnos from tg_rw if failed to read the first block.
2367 * Context: Kernel thread only (can sleep).
2371 cmlb_read_fdisk(struct cmlb_lun
*cl
, diskaddr_t capacity
, void *tg_cookie
)
2373 #if defined(_NO_FDISK_PRESENT)
2375 cl
->cl_solaris_offset
= 0;
2376 cl
->cl_solaris_size
= capacity
;
2377 bzero(cl
->cl_fmap
, sizeof (struct fmap
) * FD_NUMPART
);
2380 #elif defined(_FIRMWARE_NEEDS_FDISK)
2384 struct ipart fdisk
[FD_NUMPART
];
2391 uint_t solaris_offset
; /* offset to solaris part. */
2392 daddr_t solaris_size
; /* size of solaris partition */
2394 #if defined(__i386) || defined(__amd64)
2395 struct ipart eparts
[2];
2396 struct ipart
*efdp1
= &eparts
[0];
2397 struct ipart
*efdp2
= &eparts
[1];
2398 int ext_part_exists
= 0;
2403 ASSERT(mutex_owned(CMLB_MUTEX(cl
)));
2406 * Start off assuming no fdisk table
2409 solaris_size
= capacity
;
2411 blocksize
= cl
->cl_tgt_blocksize
;
2413 bufp
= kmem_zalloc(blocksize
, KM_SLEEP
);
2415 mutex_exit(CMLB_MUTEX(cl
));
2416 rval
= DK_TG_READ(cl
, bufp
, 0, blocksize
, tg_cookie
);
2417 mutex_enter(CMLB_MUTEX(cl
));
2420 cmlb_dbg(CMLB_ERROR
, cl
,
2421 "cmlb_read_fdisk: fdisk read err\n");
2422 bzero(cl
->cl_fmap
, sizeof (struct fmap
) * FD_NUMPART
);
2426 mbp
= (struct mboot
*)bufp
;
2429 * The fdisk table does not begin on a 4-byte boundary within the
2430 * master boot record, so we copy it to an aligned structure to avoid
2431 * alignment exceptions on some processors.
2433 bcopy(&mbp
->parts
[0], fdisk
, sizeof (fdisk
));
2436 * Check for lba support before verifying sig; sig might not be
2437 * there, say on a blank disk, but the max_chs mark may still
2440 * Note: LBA support and BEFs are an x86-only concept but this
2441 * code should work OK on SPARC as well.
2445 * First, check for lba-access-ok on root node (or prom root node)
2446 * if present there, don't need to search fdisk table.
2448 if (ddi_getprop(DDI_DEV_T_ANY
, ddi_root_node(), 0,
2449 "lba-access-ok", 0) != 0) {
2450 /* All drives do LBA; don't search fdisk table */
2453 /* Okay, look for mark in fdisk table */
2454 for (fdp
= fdisk
, i
= 0; i
< FD_NUMPART
; i
++, fdp
++) {
2455 /* accumulate "lba" value from all partitions */
2456 lba
= (lba
|| cmlb_has_max_chs_vals(fdp
));
2461 dev_t dev
= cmlb_make_device(cl
);
2463 if (ddi_getprop(dev
, CMLB_DEVINFO(cl
), DDI_PROP_DONTPASS
,
2464 "lba-access-ok", 0) == 0) {
2465 /* not found; create it */
2466 if (ddi_prop_create(dev
, CMLB_DEVINFO(cl
), 0,
2467 "lba-access-ok", NULL
, 0) !=
2469 cmlb_dbg(CMLB_ERROR
, cl
,
2470 "cmlb_read_fdisk: Can't create lba "
2471 "property for instance %d\n",
2472 ddi_get_instance(CMLB_DEVINFO(cl
)));
2477 bcopy(&mbp
->signature
, sigbuf
, sizeof (sigbuf
));
2480 * Endian-independent signature check
2482 if (((sigbuf
[1] & 0xFF) != ((MBB_MAGIC
>> 8) & 0xFF)) ||
2483 (sigbuf
[0] != (MBB_MAGIC
& 0xFF))) {
2484 cmlb_dbg(CMLB_ERROR
, cl
,
2485 "cmlb_read_fdisk: no fdisk\n");
2486 bzero(cl
->cl_fmap
, sizeof (struct fmap
) * FD_NUMPART
);
2491 if (cmlb_level_mask
& CMLB_LOGMASK_INFO
) {
2493 cmlb_dbg(CMLB_INFO
, cl
, "cmlb_read_fdisk:\n");
2494 cmlb_dbg(CMLB_INFO
, cl
, " relsect "
2495 "numsect sysid bootid\n");
2496 for (i
= 0; i
< FD_NUMPART
; i
++, fdp
++) {
2497 cmlb_dbg(CMLB_INFO
, cl
,
2498 " %d: %8d %8d 0x%08x 0x%08x\n",
2499 i
, fdp
->relsect
, fdp
->numsect
,
2500 fdp
->systid
, fdp
->bootid
);
2506 * Try to find the unix partition
2512 for (fdp
= fdisk
, i
= 0; i
< FD_NUMPART
; i
++, fdp
++) {
2516 #if defined(__i386) || defined(__amd64)
2518 * Stores relative block offset from the beginning of the
2519 * Extended Partition.
2521 int ext_relsect
= 0;
2524 if (fdp
->numsect
== 0) {
2525 cl
->cl_fmap
[i
].fmap_start
= 0;
2526 cl
->cl_fmap
[i
].fmap_nblk
= 0;
2531 * Data in the fdisk table is little-endian.
2533 relsect
= LE_32(fdp
->relsect
);
2534 numsect
= LE_32(fdp
->numsect
);
2536 cl
->cl_fmap
[i
].fmap_start
= relsect
;
2537 cl
->cl_fmap
[i
].fmap_nblk
= numsect
;
2538 cl
->cl_fmap
[i
].fmap_systid
= LE_8(fdp
->systid
);
2540 #if defined(__i386) || defined(__amd64)
2541 /* Support only one extended partition per LUN */
2542 if ((fdp
->systid
== EXTDOS
|| fdp
->systid
== FDISK_EXTLBA
) &&
2543 (ext_part_exists
== 0)) {
2545 uint32_t logdrive_offset
;
2546 uint32_t ext_numsect
;
2547 uint32_t abs_secnum
;
2549 ext_part_exists
= 1;
2551 for (j
= FD_NUMPART
; j
< FDISK_PARTS
; j
++) {
2552 mutex_exit(CMLB_MUTEX(cl
));
2553 rval
= DK_TG_READ(cl
, bufp
,
2554 (relsect
+ ext_relsect
), blocksize
,
2556 mutex_enter(CMLB_MUTEX(cl
));
2559 cmlb_dbg(CMLB_ERROR
, cl
,
2560 "cmlb_read_fdisk: Extended "
2561 "partition read err\n");
2565 * The first ipart entry provides the offset
2566 * at which the logical drive starts off from
2567 * the beginning of the container partition
2568 * and the size of the logical drive.
2569 * The second ipart entry provides the offset
2570 * of the next container partition from the
2571 * beginning of the extended partition.
2573 bcopy(&bufp
[FDISK_PART_TABLE_START
], eparts
,
2575 logdrive_offset
= LE_32(efdp1
->relsect
);
2576 ext_numsect
= LE_32(efdp1
->numsect
);
2577 systid
= LE_8(efdp1
->systid
);
2578 if (logdrive_offset
<= 0 || ext_numsect
<= 0)
2580 abs_secnum
= relsect
+ ext_relsect
+
2583 /* Boundary condition and overlap checking */
2584 if (cmlb_validate_ext_part(cl
, i
, j
, abs_secnum
,
2589 if ((cl
->cl_fmap
[j
].fmap_start
!= abs_secnum
) ||
2590 (cl
->cl_fmap
[j
].fmap_nblk
!= ext_numsect
) ||
2591 (cl
->cl_fmap
[j
].fmap_systid
!= systid
)) {
2593 * Indicates change from previous
2594 * partinfo. Need to recreate
2595 * logical device nodes.
2597 cl
->cl_update_ext_minor_nodes
= 1;
2599 cl
->cl_fmap
[j
].fmap_start
= abs_secnum
;
2600 cl
->cl_fmap
[j
].fmap_nblk
= ext_numsect
;
2601 cl
->cl_fmap
[j
].fmap_systid
= systid
;
2604 if ((efdp1
->systid
== SUNIXOS
&&
2605 (cmlb_is_linux_swap(cl
, abs_secnum
,
2606 tg_cookie
) != 0)) ||
2607 efdp1
->systid
== SUNIXOS2
) {
2610 solaris_offset
= abs_secnum
;
2611 solaris_size
= ext_numsect
;
2615 if ((ext_relsect
= LE_32(efdp2
->relsect
)) == 0)
2622 if (fdp
->systid
!= SUNIXOS
&&
2623 fdp
->systid
!= SUNIXOS2
&&
2624 fdp
->systid
!= EFI_PMBR
) {
2629 * use the last active solaris partition id found
2630 * (there should only be 1 active partition id)
2632 * if there are no active solaris partition id
2633 * then use the first inactive solaris partition id
2635 if ((uidx
== -1) || (fdp
->bootid
== ACTIVE
)) {
2636 #if defined(__i386) || defined(__amd64)
2637 if (fdp
->systid
!= SUNIXOS
||
2638 (fdp
->systid
== SUNIXOS
&&
2639 (cmlb_is_linux_swap(cl
, relsect
,
2640 tg_cookie
) != 0))) {
2643 solaris_offset
= relsect
;
2644 solaris_size
= numsect
;
2645 #if defined(__i386) || defined(__amd64)
2650 #if defined(__i386) || defined(__amd64)
2651 if (ld_count
< cl
->cl_logical_drive_count
) {
2653 * Some/all logical drives were deleted. Clear out
2654 * the fmap entries correspoding to those deleted drives.
2656 for (k
= ld_count
+ FD_NUMPART
;
2657 k
< cl
->cl_logical_drive_count
+ FD_NUMPART
; k
++) {
2658 cl
->cl_fmap
[k
].fmap_start
= 0;
2659 cl
->cl_fmap
[k
].fmap_nblk
= 0;
2660 cl
->cl_fmap
[k
].fmap_systid
= 0;
2662 cl
->cl_update_ext_minor_nodes
= 1;
2664 if (cl
->cl_update_ext_minor_nodes
) {
2665 rval
= cmlb_update_ext_minor_nodes(cl
, ld_count
);
2671 cmlb_dbg(CMLB_INFO
, cl
, "fdisk 0x%x 0x%lx",
2672 cl
->cl_solaris_offset
, cl
->cl_solaris_size
);
2676 * Clear the VTOC info, only if the Solaris partition entry
2677 * has moved, changed size, been deleted, or if the size of
2678 * the partition is too small to even fit the label sector.
2680 if ((cl
->cl_solaris_offset
!= solaris_offset
) ||
2681 (cl
->cl_solaris_size
!= solaris_size
) ||
2682 solaris_size
<= DK_LABEL_LOC
) {
2683 cmlb_dbg(CMLB_INFO
, cl
, "fdisk moved 0x%x 0x%lx",
2684 solaris_offset
, solaris_size
);
2685 bzero(&cl
->cl_g
, sizeof (struct dk_geom
));
2686 bzero(&cl
->cl_vtoc
, sizeof (struct dk_vtoc
));
2687 bzero(&cl
->cl_map
, NDKMAP
* (sizeof (struct dk_map
)));
2688 cl
->cl_f_geometry_is_valid
= B_FALSE
;
2690 cl
->cl_solaris_offset
= solaris_offset
;
2691 cl
->cl_solaris_size
= solaris_size
;
2692 kmem_free(bufp
, blocksize
);
2695 #else /* #elif defined(_FIRMWARE_NEEDS_FDISK) */
2696 #error "fdisk table presence undetermined for this platform."
2697 #endif /* #if defined(_NO_FDISK_PRESENT) */
2701 cmlb_swap_efi_gpt(efi_gpt_t
*e
)
2703 _NOTE(ASSUMING_PROTECTED(*e
))
2704 e
->efi_gpt_Signature
= LE_64(e
->efi_gpt_Signature
);
2705 e
->efi_gpt_Revision
= LE_32(e
->efi_gpt_Revision
);
2706 e
->efi_gpt_HeaderSize
= LE_32(e
->efi_gpt_HeaderSize
);
2707 e
->efi_gpt_HeaderCRC32
= LE_32(e
->efi_gpt_HeaderCRC32
);
2708 e
->efi_gpt_MyLBA
= LE_64(e
->efi_gpt_MyLBA
);
2709 e
->efi_gpt_AlternateLBA
= LE_64(e
->efi_gpt_AlternateLBA
);
2710 e
->efi_gpt_FirstUsableLBA
= LE_64(e
->efi_gpt_FirstUsableLBA
);
2711 e
->efi_gpt_LastUsableLBA
= LE_64(e
->efi_gpt_LastUsableLBA
);
2712 UUID_LE_CONVERT(e
->efi_gpt_DiskGUID
, e
->efi_gpt_DiskGUID
);
2713 e
->efi_gpt_PartitionEntryLBA
= LE_64(e
->efi_gpt_PartitionEntryLBA
);
2714 e
->efi_gpt_NumberOfPartitionEntries
=
2715 LE_32(e
->efi_gpt_NumberOfPartitionEntries
);
2716 e
->efi_gpt_SizeOfPartitionEntry
=
2717 LE_32(e
->efi_gpt_SizeOfPartitionEntry
);
2718 e
->efi_gpt_PartitionEntryArrayCRC32
=
2719 LE_32(e
->efi_gpt_PartitionEntryArrayCRC32
);
2723 cmlb_swap_efi_gpe(int nparts
, efi_gpe_t
*p
)
2727 _NOTE(ASSUMING_PROTECTED(*p
))
2728 for (i
= 0; i
< nparts
; i
++) {
2729 UUID_LE_CONVERT(p
[i
].efi_gpe_PartitionTypeGUID
,
2730 p
[i
].efi_gpe_PartitionTypeGUID
);
2731 p
[i
].efi_gpe_StartingLBA
= LE_64(p
[i
].efi_gpe_StartingLBA
);
2732 p
[i
].efi_gpe_EndingLBA
= LE_64(p
[i
].efi_gpe_EndingLBA
);
2733 /* PartitionAttrs */
2738 cmlb_validate_efi(efi_gpt_t
*labp
)
2740 if (labp
->efi_gpt_Signature
!= EFI_SIGNATURE
)
2742 /* at least 96 bytes in this version of the spec. */
2743 if (sizeof (efi_gpt_t
) - sizeof (labp
->efi_gpt_Reserved2
) >
2744 labp
->efi_gpt_HeaderSize
)
2746 /* this should be 128 bytes */
2747 if (labp
->efi_gpt_SizeOfPartitionEntry
!= sizeof (efi_gpe_t
))
2753 * This function returns B_FALSE if there is a valid MBR signature and no
2754 * partition table entries of type EFI_PMBR (0xEE). Otherwise it returns B_TRUE.
2756 * The EFI spec (1.10 and later) requires having a Protective MBR (PMBR) to
2757 * recognize the disk as GPT partitioned. However, some other OS creates an MBR
2758 * where a PMBR entry is not the only one. Also, if the first block has been
2759 * corrupted, currently best attempt to allow data access would be to try to
2760 * check for GPT headers. Hence in case of more than one partition entry, but
2761 * at least one EFI_PMBR partition type or no valid magic number, the function
2762 * returns B_TRUE to continue with looking for GPT header.
2766 cmlb_check_efi_mbr(uchar_t
*buf
, boolean_t
*is_mbr
)
2769 struct mboot
*mbp
= (struct mboot
*)buf
;
2770 struct ipart fdisk
[FD_NUMPART
];
2776 if (LE_16(mbp
->signature
) != MBB_MAGIC
) {
2782 bcopy(&mbp
->parts
[0], fdisk
, sizeof (fdisk
));
2784 for (fdp
= fdisk
, i
= 0; i
< FD_NUMPART
; i
++, fdp
++) {
2785 if (fdp
->systid
== EFI_PMBR
)
2793 cmlb_use_efi(struct cmlb_lun
*cl
, diskaddr_t capacity
, int flags
,
2798 efi_gpe_t
*partitions
;
2800 uint_t lbasize
; /* is really how much to read */
2804 diskaddr_t alternate_lba
;
2806 struct uuid uuid_type_reserved
= EFI_RESERVED
;
2807 #if defined(_FIRMWARE_NEEDS_FDISK)
2811 ASSERT(mutex_owned(CMLB_MUTEX(cl
)));
2813 lbasize
= cl
->cl_sys_blocksize
;
2815 cl
->cl_reserved
= -1;
2816 mutex_exit(CMLB_MUTEX(cl
));
2818 buf
= kmem_zalloc(EFI_MIN_ARRAY_SIZE
, KM_SLEEP
);
2820 rval
= DK_TG_READ(cl
, buf
, 0, lbasize
, tg_cookie
);
2825 if (((struct dk_label
*)buf
)->dkl_magic
== DKL_MAGIC
) {
2831 #if defined(_FIRMWARE_NEEDS_FDISK)
2832 if (!cmlb_check_efi_mbr(buf
, &is_mbr
)) {
2840 if (!cmlb_check_efi_mbr(buf
, NULL
)) {
2847 rval
= DK_TG_READ(cl
, buf
, 1, lbasize
, tg_cookie
);
2852 cmlb_swap_efi_gpt((efi_gpt_t
*)buf
);
2854 if ((rval
= cmlb_validate_efi((efi_gpt_t
*)buf
)) != 0) {
2856 * Couldn't read the primary, try the backup. Our
2857 * capacity at this point could be based on CHS, so
2858 * check what the device reports.
2860 rval
= DK_TG_GETCAP(cl
, &cap
, tg_cookie
);
2867 * CMLB_OFF_BY_ONE case, we check the next to last block first
2868 * for backup GPT header, otherwise check the last block.
2871 if ((rval
= DK_TG_READ(cl
, buf
,
2872 cap
- ((cl
->cl_alter_behavior
& CMLB_OFF_BY_ONE
) ? 2 : 1),
2873 lbasize
, tg_cookie
))
2878 cmlb_swap_efi_gpt((efi_gpt_t
*)buf
);
2880 if ((rval
= cmlb_validate_efi((efi_gpt_t
*)buf
)) != 0) {
2882 if (!(cl
->cl_alter_behavior
& CMLB_OFF_BY_ONE
))
2884 if ((rval
= DK_TG_READ(cl
, buf
, cap
- 1, lbasize
,
2887 cmlb_swap_efi_gpt((efi_gpt_t
*)buf
);
2888 if ((rval
= cmlb_validate_efi((efi_gpt_t
*)buf
)) != 0)
2891 if (!(flags
& CMLB_SILENT
))
2892 cmlb_log(CMLB_DEVINFO(cl
), CMLB_LABEL(cl
), CE_WARN
,
2893 "primary label corrupt; using backup\n");
2896 nparts
= ((efi_gpt_t
*)buf
)->efi_gpt_NumberOfPartitionEntries
;
2897 gpe_lba
= ((efi_gpt_t
*)buf
)->efi_gpt_PartitionEntryLBA
;
2898 alternate_lba
= ((efi_gpt_t
*)buf
)->efi_gpt_AlternateLBA
;
2900 rval
= DK_TG_READ(cl
, buf
, gpe_lba
, EFI_MIN_ARRAY_SIZE
, tg_cookie
);
2905 partitions
= (efi_gpe_t
*)buf
;
2907 if (nparts
> MAXPART
) {
2910 cmlb_swap_efi_gpe(nparts
, partitions
);
2912 mutex_enter(CMLB_MUTEX(cl
));
2914 /* Fill in partition table. */
2915 for (i
= 0; i
< nparts
; i
++) {
2916 if (partitions
->efi_gpe_StartingLBA
!= 0 ||
2917 partitions
->efi_gpe_EndingLBA
!= 0) {
2918 cl
->cl_map
[i
].dkl_cylno
=
2919 partitions
->efi_gpe_StartingLBA
;
2920 cl
->cl_map
[i
].dkl_nblk
=
2921 partitions
->efi_gpe_EndingLBA
-
2922 partitions
->efi_gpe_StartingLBA
+ 1;
2924 partitions
->efi_gpe_StartingLBA
;
2927 if (cl
->cl_reserved
== -1) {
2928 if (bcmp(&partitions
->efi_gpe_PartitionTypeGUID
,
2929 &uuid_type_reserved
, sizeof (struct uuid
)) == 0) {
2930 cl
->cl_reserved
= i
;
2935 * minor number 7 corresponds to the whole disk
2936 * if the disk capacity is expanded after disk is
2937 * labeled, minor number 7 represents the capacity
2938 * indicated by the disk label.
2940 cl
->cl_map
[i
].dkl_cylno
= 0;
2941 if (alternate_lba
== 1) {
2943 * We are using backup label. Since we can
2944 * find a valid label at the end of disk,
2945 * the disk capacity is not expanded.
2947 cl
->cl_map
[i
].dkl_nblk
= capacity
;
2949 cl
->cl_map
[i
].dkl_nblk
= alternate_lba
+ 1;
2951 cl
->cl_offset
[i
] = 0;
2955 cl
->cl_solaris_offset
= 0;
2956 cl
->cl_solaris_size
= capacity
;
2957 cl
->cl_label_from_media
= CMLB_LABEL_EFI
;
2958 cl
->cl_f_geometry_is_valid
= B_TRUE
;
2960 /* clear the vtoc label */
2961 bzero(&cl
->cl_vtoc
, sizeof (struct dk_vtoc
));
2963 kmem_free(buf
, EFI_MIN_ARRAY_SIZE
);
2967 kmem_free(buf
, EFI_MIN_ARRAY_SIZE
);
2968 mutex_enter(CMLB_MUTEX(cl
));
2971 * if we didn't find something that could look like a VTOC
2972 * and the disk is over 1TB, we know there isn't a valid label.
2973 * Otherwise let cmlb_uselabel decide what to do. We only
2974 * want to invalidate this if we're certain the label isn't
2975 * valid because cmlb_prop_op will now fail, which in turn
2976 * causes things like opens and stats on the partition to fail.
2978 if ((capacity
> CMLB_EXTVTOC_LIMIT
) && (rval
!= ESRCH
) && !iofailed
) {
2979 cl
->cl_f_geometry_is_valid
= B_FALSE
;
2986 * Function: cmlb_uselabel
2988 * Description: Validate the disk label and update the relevant data (geometry,
2989 * partition, vtoc, and capacity data) in the cmlb_lun struct.
2990 * Marks the geometry of the unit as being valid.
2992 * Arguments: cl: unit struct.
2993 * dk_label: disk label
2995 * Return Code: CMLB_LABEL_IS_VALID: Label read from disk is OK; geometry,
2996 * partition, vtoc, and capacity data are good.
2998 * CMLB_LABEL_IS_INVALID: Magic number or checksum error in the
2999 * label; or computed capacity does not jibe with capacity
3000 * reported from the READ CAPACITY command.
3002 * Context: Kernel thread only (can sleep).
3005 cmlb_uselabel(struct cmlb_lun
*cl
, struct dk_label
*labp
, int flags
)
3010 int label_error
= CMLB_LABEL_IS_VALID
;
3012 diskaddr_t label_capacity
;
3014 diskaddr_t track_capacity
;
3015 #if defined(_SUNOS_VTOC_16)
3016 struct dkl_partition
*vpartp
;
3019 ASSERT(mutex_owned(CMLB_MUTEX(cl
)));
3021 /* Validate the magic number of the label. */
3022 if (labp
->dkl_magic
!= DKL_MAGIC
) {
3023 return (CMLB_LABEL_IS_INVALID
);
3026 /* Validate the checksum of the label. */
3029 count
= sizeof (struct dk_label
) / sizeof (short);
3035 #if defined(_SUNOS_VTOC_16)
3037 #elif defined(_SUNOS_VTOC_8)
3038 if (!ISREMOVABLE(cl
) && !ISHOTPLUGGABLE(cl
)) {
3040 if (!(flags
& CMLB_SILENT
))
3041 cmlb_log(CMLB_DEVINFO(cl
), CMLB_LABEL(cl
),
3043 "Corrupt label - label checksum failed\n");
3045 return (CMLB_LABEL_IS_INVALID
);
3050 * Fill in geometry structure with data from label.
3052 bzero(&cl
->cl_g
, sizeof (struct dk_geom
));
3053 cl
->cl_g
.dkg_ncyl
= labp
->dkl_ncyl
;
3054 cl
->cl_g
.dkg_acyl
= labp
->dkl_acyl
;
3055 cl
->cl_g
.dkg_bcyl
= 0;
3056 cl
->cl_g
.dkg_nhead
= labp
->dkl_nhead
;
3057 cl
->cl_g
.dkg_nsect
= labp
->dkl_nsect
;
3058 cl
->cl_g
.dkg_intrlv
= labp
->dkl_intrlv
;
3060 #if defined(_SUNOS_VTOC_8)
3061 cl
->cl_g
.dkg_gap1
= labp
->dkl_gap1
;
3062 cl
->cl_g
.dkg_gap2
= labp
->dkl_gap2
;
3063 cl
->cl_g
.dkg_bhead
= labp
->dkl_bhead
;
3065 #if defined(_SUNOS_VTOC_16)
3066 cl
->cl_dkg_skew
= labp
->dkl_skew
;
3069 #if defined(__i386) || defined(__amd64)
3070 cl
->cl_g
.dkg_apc
= labp
->dkl_apc
;
3074 * Currently we rely on the values in the label being accurate. If
3075 * dkl_rpm or dkl_pcly are zero in the label, use a default value.
3077 * Note: In the future a MODE SENSE may be used to retrieve this data,
3078 * although this command is optional in SCSI-2.
3080 cl
->cl_g
.dkg_rpm
= (labp
->dkl_rpm
!= 0) ? labp
->dkl_rpm
: 3600;
3081 cl
->cl_g
.dkg_pcyl
= (labp
->dkl_pcyl
!= 0) ? labp
->dkl_pcyl
:
3082 (cl
->cl_g
.dkg_ncyl
+ cl
->cl_g
.dkg_acyl
);
3085 * The Read and Write reinstruct values may not be valid
3088 cl
->cl_g
.dkg_read_reinstruct
= labp
->dkl_read_reinstruct
;
3089 cl
->cl_g
.dkg_write_reinstruct
= labp
->dkl_write_reinstruct
;
3091 /* Fill in partition table. */
3092 #if defined(_SUNOS_VTOC_8)
3093 for (i
= 0; i
< NDKMAP
; i
++) {
3094 cl
->cl_map
[i
].dkl_cylno
= labp
->dkl_map
[i
].dkl_cylno
;
3095 cl
->cl_map
[i
].dkl_nblk
= labp
->dkl_map
[i
].dkl_nblk
;
3098 #if defined(_SUNOS_VTOC_16)
3099 vpartp
= labp
->dkl_vtoc
.v_part
;
3100 track_capacity
= labp
->dkl_nhead
* labp
->dkl_nsect
;
3102 /* Prevent divide by zero */
3103 if (track_capacity
== 0) {
3104 if (!(flags
& CMLB_SILENT
))
3105 cmlb_log(CMLB_DEVINFO(cl
), CMLB_LABEL(cl
), CE_WARN
,
3106 "Corrupt label - zero nhead or nsect value\n");
3108 return (CMLB_LABEL_IS_INVALID
);
3111 for (i
= 0; i
< NDKMAP
; i
++, vpartp
++) {
3112 cl
->cl_map
[i
].dkl_cylno
= vpartp
->p_start
/ track_capacity
;
3113 cl
->cl_map
[i
].dkl_nblk
= vpartp
->p_size
;
3117 /* Fill in VTOC Structure. */
3118 bcopy(&labp
->dkl_vtoc
, &cl
->cl_vtoc
, sizeof (struct dk_vtoc
));
3119 #if defined(_SUNOS_VTOC_8)
3121 * The 8-slice vtoc does not include the ascii label; save it into
3122 * the device's soft state structure here.
3124 bcopy(labp
->dkl_asciilabel
, cl
->cl_asciilabel
, LEN_DKL_ASCII
);
3127 /* Now look for a valid capacity. */
3128 track_capacity
= (cl
->cl_g
.dkg_nhead
* cl
->cl_g
.dkg_nsect
);
3129 label_capacity
= (cl
->cl_g
.dkg_ncyl
* track_capacity
);
3131 if (cl
->cl_g
.dkg_acyl
) {
3132 #if defined(__i386) || defined(__amd64)
3133 /* we may have > 1 alts cylinder */
3134 label_capacity
+= (track_capacity
* cl
->cl_g
.dkg_acyl
);
3136 label_capacity
+= track_capacity
;
3141 * Force check here to ensure the computed capacity is valid.
3142 * If capacity is zero, it indicates an invalid label and
3143 * we should abort updating the relevant data then.
3145 if (label_capacity
== 0) {
3146 if (!(flags
& CMLB_SILENT
))
3147 cmlb_log(CMLB_DEVINFO(cl
), CMLB_LABEL(cl
), CE_WARN
,
3148 "Corrupt label - no valid capacity could be "
3151 return (CMLB_LABEL_IS_INVALID
);
3154 /* Mark the geometry as valid. */
3155 cl
->cl_f_geometry_is_valid
= B_TRUE
;
3158 * if we got invalidated when mutex exit and entered again,
3159 * if blockcount different than when we came in, need to
3160 * retry from beginning of cmlb_validate_geometry.
3161 * revisit this on next phase of utilizing this for
3165 if (label_capacity
<= cl
->cl_blockcount
) {
3166 #if defined(_SUNOS_VTOC_8)
3168 * We can't let this happen on drives that are subdivided
3169 * into logical disks (i.e., that have an fdisk table).
3170 * The cl_blockcount field should always hold the full media
3171 * size in sectors, period. This code would overwrite
3172 * cl_blockcount with the size of the Solaris fdisk partition.
3174 cmlb_dbg(CMLB_ERROR
, cl
,
3175 "cmlb_uselabel: Label %d blocks; Drive %d blocks\n",
3176 label_capacity
, cl
->cl_blockcount
);
3177 cl
->cl_solaris_size
= label_capacity
;
3179 #endif /* defined(_SUNOS_VTOC_8) */
3184 /* For CDROMs, we trust that the data in the label is OK. */
3185 #if defined(_SUNOS_VTOC_8)
3186 for (i
= 0; i
< NDKMAP
; i
++) {
3187 part_end
= labp
->dkl_nhead
* labp
->dkl_nsect
*
3188 labp
->dkl_map
[i
].dkl_cylno
+
3189 labp
->dkl_map
[i
].dkl_nblk
- 1;
3191 if ((labp
->dkl_map
[i
].dkl_nblk
) &&
3192 (part_end
> cl
->cl_blockcount
)) {
3193 cl
->cl_f_geometry_is_valid
= B_FALSE
;
3198 #if defined(_SUNOS_VTOC_16)
3199 vpartp
= &(labp
->dkl_vtoc
.v_part
[0]);
3200 for (i
= 0; i
< NDKMAP
; i
++, vpartp
++) {
3201 part_end
= vpartp
->p_start
+ vpartp
->p_size
;
3202 if ((vpartp
->p_size
> 0) &&
3203 (part_end
> cl
->cl_blockcount
)) {
3204 cl
->cl_f_geometry_is_valid
= B_FALSE
;
3210 /* label_capacity > cl->cl_blockcount */
3211 if (!(flags
& CMLB_SILENT
)) {
3212 cmlb_log(CMLB_DEVINFO(cl
), CMLB_LABEL(cl
), CE_WARN
,
3213 "Corrupt label - bad geometry\n");
3214 cmlb_log(CMLB_DEVINFO(cl
), CMLB_LABEL(cl
), CE_CONT
,
3215 "Label says %llu blocks; Drive says %llu blocks\n",
3216 label_capacity
, cl
->cl_blockcount
);
3218 cl
->cl_f_geometry_is_valid
= B_FALSE
;
3219 label_error
= CMLB_LABEL_IS_INVALID
;
3224 cmlb_dbg(CMLB_INFO
, cl
, "cmlb_uselabel: (label geometry)\n");
3225 cmlb_dbg(CMLB_INFO
, cl
,
3226 " ncyl: %d; acyl: %d; nhead: %d; nsect: %d\n",
3227 cl
->cl_g
.dkg_ncyl
, cl
->cl_g
.dkg_acyl
,
3228 cl
->cl_g
.dkg_nhead
, cl
->cl_g
.dkg_nsect
);
3230 cmlb_dbg(CMLB_INFO
, cl
,
3231 " label_capacity: %d; intrlv: %d; rpm: %d\n",
3232 cl
->cl_blockcount
, cl
->cl_g
.dkg_intrlv
, cl
->cl_g
.dkg_rpm
);
3233 cmlb_dbg(CMLB_INFO
, cl
, " wrt_reinstr: %d; rd_reinstr: %d\n",
3234 cl
->cl_g
.dkg_write_reinstruct
, cl
->cl_g
.dkg_read_reinstruct
);
3236 ASSERT(mutex_owned(CMLB_MUTEX(cl
)));
3238 return (label_error
);
3243 * Function: cmlb_build_default_label
3245 * Description: Generate a default label for those devices that do not have
3246 * one, e.g., new media, removable cartridges, etc..
3248 * Context: Kernel thread only
3252 cmlb_build_default_label(struct cmlb_lun
*cl
, void *tg_cookie
)
3254 #if defined(_SUNOS_VTOC_16)
3257 struct dk_geom cl_g
;
3258 diskaddr_t capacity
;
3262 ASSERT(mutex_owned(CMLB_MUTEX(cl
)));
3264 #if defined(_SUNOS_VTOC_8)
3266 * Note: This is a legacy check for non-removable devices on VTOC_8
3267 * only. This may be a valid check for VTOC_16 as well.
3268 * Once we understand why there is this difference between SPARC and
3269 * x86 platform, we could remove this legacy check.
3271 if (!ISREMOVABLE(cl
) && !ISHOTPLUGGABLE(cl
)) {
3276 bzero(&cl
->cl_g
, sizeof (struct dk_geom
));
3277 bzero(&cl
->cl_vtoc
, sizeof (struct dk_vtoc
));
3278 bzero(&cl
->cl_map
, NDKMAP
* (sizeof (struct dk_map
)));
3280 #if defined(_SUNOS_VTOC_8)
3283 * It's a REMOVABLE media, therefore no label (on sparc, anyway).
3284 * But it is still necessary to set up various geometry information,
3285 * and we are doing this here.
3289 * For the rpm, we use the minimum for the disk. For the head, cyl,
3290 * and number of sector per track, if the capacity <= 1GB, head = 64,
3291 * sect = 32. else head = 255, sect 63 Note: the capacity should be
3292 * equal to C*H*S values. This will cause some truncation of size due
3293 * to round off errors. For CD-ROMs, this truncation can have adverse
3294 * side effects, so returning ncyl and nhead as 1. The nsect will
3295 * overflow for most of CD-ROMs as nsect is of type ushort. (4190569)
3297 cl
->cl_solaris_size
= cl
->cl_blockcount
;
3299 tg_attribute_t tgattribute
;
3302 * Preserve the old behavior for non-writable
3303 * medias. Since dkg_nsect is a ushort, it
3304 * will lose bits as cdroms have more than
3305 * 65536 sectors. So if we recalculate
3306 * capacity, it will become much shorter.
3307 * But the dkg_* information is not
3308 * used for CDROMs so it is OK. But for
3309 * Writable CDs we need this information
3310 * to be valid (for newfs say). So we
3311 * make nsect and nhead > 1 that way
3312 * nsect can still stay within ushort limit
3313 * without losing any bits.
3316 bzero(&tgattribute
, sizeof (tg_attribute_t
));
3318 mutex_exit(CMLB_MUTEX(cl
));
3320 (DK_TG_GETATTRIBUTE(cl
, &tgattribute
, tg_cookie
) == 0) ?
3321 tgattribute
.media_is_writable
: 1;
3322 mutex_enter(CMLB_MUTEX(cl
));
3325 cl
->cl_g
.dkg_nhead
= 64;
3326 cl
->cl_g
.dkg_nsect
= 32;
3327 cl
->cl_g
.dkg_ncyl
= cl
->cl_blockcount
/ (64 * 32);
3328 cl
->cl_solaris_size
= (diskaddr_t
)cl
->cl_g
.dkg_ncyl
*
3329 cl
->cl_g
.dkg_nhead
* cl
->cl_g
.dkg_nsect
;
3331 cl
->cl_g
.dkg_ncyl
= 1;
3332 cl
->cl_g
.dkg_nhead
= 1;
3333 cl
->cl_g
.dkg_nsect
= cl
->cl_blockcount
;
3336 if (cl
->cl_blockcount
< 160) {
3338 cl
->cl_g
.dkg_nhead
= 1;
3339 cl
->cl_g
.dkg_ncyl
= cl
->cl_blockcount
;
3340 cl
->cl_g
.dkg_nsect
= 1;
3341 } else if (cl
->cl_blockcount
<= 0x1000) {
3342 /* unlabeled SCSI floppy device */
3343 cl
->cl_g
.dkg_nhead
= 2;
3344 cl
->cl_g
.dkg_ncyl
= 80;
3345 cl
->cl_g
.dkg_nsect
= cl
->cl_blockcount
/ (2 * 80);
3346 } else if (cl
->cl_blockcount
<= 0x200000) {
3347 cl
->cl_g
.dkg_nhead
= 64;
3348 cl
->cl_g
.dkg_nsect
= 32;
3349 cl
->cl_g
.dkg_ncyl
= cl
->cl_blockcount
/ (64 * 32);
3351 cl
->cl_g
.dkg_nhead
= 255;
3353 cl
->cl_g
.dkg_nsect
= ((cl
->cl_blockcount
+
3354 (UINT16_MAX
* 255 * 63) - 1) /
3355 (UINT16_MAX
* 255 * 63)) * 63;
3357 if (cl
->cl_g
.dkg_nsect
== 0)
3358 cl
->cl_g
.dkg_nsect
= (UINT16_MAX
/ 63) * 63;
3360 cl
->cl_g
.dkg_ncyl
= cl
->cl_blockcount
/
3361 (255 * cl
->cl_g
.dkg_nsect
);
3364 cl
->cl_solaris_size
=
3365 (diskaddr_t
)cl
->cl_g
.dkg_ncyl
* cl
->cl_g
.dkg_nhead
*
3370 cl
->cl_g
.dkg_acyl
= 0;
3371 cl
->cl_g
.dkg_bcyl
= 0;
3372 cl
->cl_g
.dkg_rpm
= 200;
3373 cl
->cl_asciilabel
[0] = '\0';
3374 cl
->cl_g
.dkg_pcyl
= cl
->cl_g
.dkg_ncyl
;
3376 cl
->cl_map
[0].dkl_cylno
= 0;
3377 cl
->cl_map
[0].dkl_nblk
= cl
->cl_solaris_size
;
3379 cl
->cl_map
[2].dkl_cylno
= 0;
3380 cl
->cl_map
[2].dkl_nblk
= cl
->cl_solaris_size
;
3382 #elif defined(_SUNOS_VTOC_16)
3384 if (cl
->cl_solaris_size
== 0) {
3386 * Got fdisk table but no solaris entry therefore
3387 * don't create a default label
3389 cl
->cl_f_geometry_is_valid
= B_TRUE
;
3394 * For CDs we continue to use the physical geometry to calculate
3395 * number of cylinders. All other devices must convert the
3396 * physical geometry (cmlb_geom) to values that will fit
3397 * in a dk_geom structure.
3400 phys_spc
= cl
->cl_pgeom
.g_nhead
* cl
->cl_pgeom
.g_nsect
;
3402 /* Convert physical geometry to disk geometry */
3403 bzero(&cl_g
, sizeof (struct dk_geom
));
3406 * Refer to comments related to off-by-1 at the
3407 * header of this file.
3408 * Before calculating geometry, capacity should be
3412 if (cl
->cl_alter_behavior
& CMLB_OFF_BY_ONE
)
3413 capacity
= cl
->cl_blockcount
- 1;
3415 capacity
= cl
->cl_blockcount
;
3418 cmlb_convert_geometry(cl
, capacity
, &cl_g
, tg_cookie
);
3419 bcopy(&cl_g
, &cl
->cl_g
, sizeof (cl
->cl_g
));
3420 phys_spc
= cl
->cl_g
.dkg_nhead
* cl
->cl_g
.dkg_nsect
;
3425 cl
->cl_g
.dkg_pcyl
= cl
->cl_solaris_size
/ phys_spc
;
3426 if (cl
->cl_alter_behavior
& CMLB_FAKE_LABEL_ONE_PARTITION
) {
3428 cl
->cl_g
.dkg_ncyl
= cl
->cl_g
.dkg_pcyl
;
3429 disksize
= cl
->cl_solaris_size
;
3431 cl
->cl_g
.dkg_acyl
= DK_ACYL
;
3432 cl
->cl_g
.dkg_ncyl
= cl
->cl_g
.dkg_pcyl
- DK_ACYL
;
3433 disksize
= cl
->cl_g
.dkg_ncyl
* phys_spc
;
3438 * CD's don't use the "heads * sectors * cyls"-type of
3439 * geometry, but instead use the entire capacity of the media.
3441 disksize
= cl
->cl_solaris_size
;
3442 cl
->cl_g
.dkg_nhead
= 1;
3443 cl
->cl_g
.dkg_nsect
= 1;
3445 (cl
->cl_pgeom
.g_rpm
== 0) ? 200 : cl
->cl_pgeom
.g_rpm
;
3447 cl
->cl_vtoc
.v_part
[0].p_start
= 0;
3448 cl
->cl_vtoc
.v_part
[0].p_size
= disksize
;
3449 cl
->cl_vtoc
.v_part
[0].p_tag
= V_BACKUP
;
3450 cl
->cl_vtoc
.v_part
[0].p_flag
= V_UNMNT
;
3452 cl
->cl_map
[0].dkl_cylno
= 0;
3453 cl
->cl_map
[0].dkl_nblk
= disksize
;
3454 cl
->cl_offset
[0] = 0;
3458 * Hard disks and removable media cartridges
3461 (cl
->cl_pgeom
.g_rpm
== 0) ? 3600: cl
->cl_pgeom
.g_rpm
;
3462 cl
->cl_vtoc
.v_sectorsz
= cl
->cl_sys_blocksize
;
3464 /* Add boot slice */
3465 cl
->cl_vtoc
.v_part
[8].p_start
= 0;
3466 cl
->cl_vtoc
.v_part
[8].p_size
= phys_spc
;
3467 cl
->cl_vtoc
.v_part
[8].p_tag
= V_BOOT
;
3468 cl
->cl_vtoc
.v_part
[8].p_flag
= V_UNMNT
;
3470 cl
->cl_map
[8].dkl_cylno
= 0;
3471 cl
->cl_map
[8].dkl_nblk
= phys_spc
;
3472 cl
->cl_offset
[8] = 0;
3474 if ((cl
->cl_alter_behavior
&
3475 CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT
) &&
3476 cl
->cl_device_type
== DTYPE_DIRECT
) {
3477 cl
->cl_vtoc
.v_part
[9].p_start
= phys_spc
;
3478 cl
->cl_vtoc
.v_part
[9].p_size
= 2 * phys_spc
;
3479 cl
->cl_vtoc
.v_part
[9].p_tag
= V_ALTSCTR
;
3480 cl
->cl_vtoc
.v_part
[9].p_flag
= 0;
3482 cl
->cl_map
[9].dkl_cylno
= 1;
3483 cl
->cl_map
[9].dkl_nblk
= 2 * phys_spc
;
3484 cl
->cl_offset
[9] = phys_spc
;
3488 cl
->cl_g
.dkg_apc
= 0;
3490 /* Add backup slice */
3491 cl
->cl_vtoc
.v_part
[2].p_start
= 0;
3492 cl
->cl_vtoc
.v_part
[2].p_size
= disksize
;
3493 cl
->cl_vtoc
.v_part
[2].p_tag
= V_BACKUP
;
3494 cl
->cl_vtoc
.v_part
[2].p_flag
= V_UNMNT
;
3496 cl
->cl_map
[2].dkl_cylno
= 0;
3497 cl
->cl_map
[2].dkl_nblk
= disksize
;
3498 cl
->cl_offset
[2] = 0;
3501 * single slice (s0) covering the entire disk
3503 if (cl
->cl_alter_behavior
& CMLB_FAKE_LABEL_ONE_PARTITION
) {
3504 cl
->cl_vtoc
.v_part
[0].p_start
= 0;
3505 cl
->cl_vtoc
.v_part
[0].p_tag
= V_UNASSIGNED
;
3506 cl
->cl_vtoc
.v_part
[0].p_flag
= 0;
3507 cl
->cl_vtoc
.v_part
[0].p_size
= disksize
;
3508 cl
->cl_map
[0].dkl_cylno
= 0;
3509 cl
->cl_map
[0].dkl_nblk
= disksize
;
3510 cl
->cl_offset
[0] = 0;
3513 (void) sprintf(cl
->cl_vtoc
.v_asciilabel
, "DEFAULT cyl %d alt %d"
3514 " hd %d sec %d", cl
->cl_g
.dkg_ncyl
, cl
->cl_g
.dkg_acyl
,
3515 cl
->cl_g
.dkg_nhead
, cl
->cl_g
.dkg_nsect
);
3518 #error "No VTOC format defined."
3521 cl
->cl_g
.dkg_read_reinstruct
= 0;
3522 cl
->cl_g
.dkg_write_reinstruct
= 0;
3524 cl
->cl_g
.dkg_intrlv
= 1;
3526 cl
->cl_vtoc
.v_sanity
= VTOC_SANE
;
3527 cl
->cl_vtoc
.v_nparts
= V_NUMPAR
;
3528 cl
->cl_vtoc
.v_version
= V_VERSION
;
3530 cl
->cl_f_geometry_is_valid
= B_TRUE
;
3531 cl
->cl_label_from_media
= CMLB_LABEL_UNDEF
;
3533 cmlb_dbg(CMLB_INFO
, cl
,
3534 "cmlb_build_default_label: Default label created: "
3535 "cyl: %d\tacyl: %d\tnhead: %d\tnsect: %d\tcap: %d\n",
3536 cl
->cl_g
.dkg_ncyl
, cl
->cl_g
.dkg_acyl
, cl
->cl_g
.dkg_nhead
,
3537 cl
->cl_g
.dkg_nsect
, cl
->cl_blockcount
);
3541 #if defined(_FIRMWARE_NEEDS_FDISK)
3543 * Max CHS values, as they are encoded into bytes, for 1022/254/63
3545 #define LBA_MAX_SECT (63 | ((1022 & 0x300) >> 2))
3546 #define LBA_MAX_CYL (1022 & 0xFF)
3547 #define LBA_MAX_HEAD (254)
3551 * Function: cmlb_has_max_chs_vals
3553 * Description: Return B_TRUE if Cylinder-Head-Sector values are all at maximum.
3555 * Arguments: fdp - ptr to CHS info
3557 * Return Code: True or false
3562 cmlb_has_max_chs_vals(struct ipart
*fdp
)
3564 return ((fdp
->begcyl
== LBA_MAX_CYL
) &&
3565 (fdp
->beghead
== LBA_MAX_HEAD
) &&
3566 (fdp
->begsect
== LBA_MAX_SECT
) &&
3567 (fdp
->endcyl
== LBA_MAX_CYL
) &&
3568 (fdp
->endhead
== LBA_MAX_HEAD
) &&
3569 (fdp
->endsect
== LBA_MAX_SECT
));
3574 * Function: cmlb_dkio_get_geometry
3576 * Description: This routine is the driver entry point for handling user
3577 * requests to get the device geometry (DKIOCGGEOM).
3580 * arg pointer to user provided dk_geom structure specifying
3581 * the controller's notion of the current geometry.
3583 * flag this argument is a pass through to ddi_copyxxx()
3584 * directly from the mode argument of ioctl().
3586 * tg_cookie cookie from target driver to be passed back to target
3587 * driver when we call back to it through tg_ops.
3595 cmlb_dkio_get_geometry(struct cmlb_lun
*cl
, caddr_t arg
, int flag
,
3598 struct dk_geom
*tmp_geom
= NULL
;
3602 * cmlb_validate_geometry does not spin a disk up
3603 * if it was spcl down. We need to make sure it
3606 mutex_enter(CMLB_MUTEX(cl
));
3607 rval
= cmlb_validate_geometry(cl
, B_TRUE
, 0, tg_cookie
);
3608 #if defined(_SUNOS_VTOC_8)
3609 if (rval
== EINVAL
&&
3610 cl
->cl_alter_behavior
& CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8
) {
3612 * This is to return a default label geometry even when we
3613 * do not really assume a default label for the device.
3614 * dad driver utilizes this.
3616 if (cl
->cl_blockcount
<= CMLB_OLDVTOC_LIMIT
) {
3617 cmlb_setup_default_geometry(cl
, tg_cookie
);
3623 mutex_exit(CMLB_MUTEX(cl
));
3627 #if defined(__i386) || defined(__amd64)
3628 if (cl
->cl_solaris_size
== 0) {
3629 mutex_exit(CMLB_MUTEX(cl
));
3635 * Make a local copy of the soft state geometry to avoid some potential
3636 * race conditions associated with holding the mutex and updating the
3637 * write_reinstruct value
3639 tmp_geom
= kmem_zalloc(sizeof (struct dk_geom
), KM_SLEEP
);
3640 bcopy(&cl
->cl_g
, tmp_geom
, sizeof (struct dk_geom
));
3642 if (tmp_geom
->dkg_write_reinstruct
== 0) {
3643 tmp_geom
->dkg_write_reinstruct
=
3644 (int)((int)(tmp_geom
->dkg_nsect
* tmp_geom
->dkg_rpm
*
3645 cmlb_rot_delay
) / (int)60000);
3647 mutex_exit(CMLB_MUTEX(cl
));
3649 rval
= ddi_copyout(tmp_geom
, (void *)arg
, sizeof (struct dk_geom
),
3655 kmem_free(tmp_geom
, sizeof (struct dk_geom
));
3662 * Function: cmlb_dkio_set_geometry
3664 * Description: This routine is the driver entry point for handling user
3665 * requests to set the device geometry (DKIOCSGEOM). The actual
3666 * device geometry is not updated, just the driver "notion" of it.
3669 * arg pointer to user provided dk_geom structure used to set
3670 * the controller's notion of the current geometry.
3672 * flag this argument is a pass through to ddi_copyxxx()
3673 * directly from the mode argument of ioctl().
3675 * tg_cookie cookie from target driver to be passed back to target
3676 * driver when we call back to it through tg_ops.
3684 cmlb_dkio_set_geometry(struct cmlb_lun
*cl
, caddr_t arg
, int flag
)
3686 struct dk_geom
*tmp_geom
;
3692 #if defined(__i386) || defined(__amd64)
3693 if (cl
->cl_solaris_size
== 0) {
3698 * We need to copy the user specified geometry into local
3699 * storage and then update the softstate. We don't want to hold
3700 * the mutex and copyin directly from the user to the soft state
3702 tmp_geom
= (struct dk_geom
*)
3703 kmem_zalloc(sizeof (struct dk_geom
), KM_SLEEP
);
3704 rval
= ddi_copyin(arg
, tmp_geom
, sizeof (struct dk_geom
), flag
);
3706 kmem_free(tmp_geom
, sizeof (struct dk_geom
));
3710 mutex_enter(CMLB_MUTEX(cl
));
3711 bcopy(tmp_geom
, &cl
->cl_g
, sizeof (struct dk_geom
));
3712 for (i
= 0; i
< NDKMAP
; i
++) {
3713 lp
= &cl
->cl_map
[i
];
3715 cl
->cl_g
.dkg_nhead
* cl
->cl_g
.dkg_nsect
* lp
->dkl_cylno
;
3716 #if defined(__i386) || defined(__amd64)
3717 cl
->cl_offset
[i
] += cl
->cl_solaris_offset
;
3720 cl
->cl_f_geometry_is_valid
= B_FALSE
;
3721 mutex_exit(CMLB_MUTEX(cl
));
3722 kmem_free(tmp_geom
, sizeof (struct dk_geom
));
3728 * Function: cmlb_dkio_get_partition
3730 * Description: This routine is the driver entry point for handling user
3731 * requests to get the partition table (DKIOCGAPART).
3734 * arg pointer to user provided dk_allmap structure specifying
3735 * the controller's notion of the current partition table.
3737 * flag this argument is a pass through to ddi_copyxxx()
3738 * directly from the mode argument of ioctl().
3740 * tg_cookie cookie from target driver to be passed back to target
3741 * driver when we call back to it through tg_ops.
3749 cmlb_dkio_get_partition(struct cmlb_lun
*cl
, caddr_t arg
, int flag
,
3756 * Make sure the geometry is valid before getting the partition
3759 mutex_enter(CMLB_MUTEX(cl
));
3760 if ((rval
= cmlb_validate_geometry(cl
, B_TRUE
, 0, tg_cookie
)) != 0) {
3761 mutex_exit(CMLB_MUTEX(cl
));
3764 mutex_exit(CMLB_MUTEX(cl
));
3766 #if defined(__i386) || defined(__amd64)
3767 if (cl
->cl_solaris_size
== 0) {
3772 #ifdef _MULTI_DATAMODEL
3773 switch (ddi_model_convert_from(flag
& FMODELS
)) {
3774 case DDI_MODEL_ILP32
: {
3775 struct dk_map32 dk_map32
[NDKMAP
];
3778 for (i
= 0; i
< NDKMAP
; i
++) {
3779 dk_map32
[i
].dkl_cylno
= cl
->cl_map
[i
].dkl_cylno
;
3780 dk_map32
[i
].dkl_nblk
= cl
->cl_map
[i
].dkl_nblk
;
3782 size
= NDKMAP
* sizeof (struct dk_map32
);
3783 rval
= ddi_copyout(dk_map32
, (void *)arg
, size
, flag
);
3789 case DDI_MODEL_NONE
:
3790 size
= NDKMAP
* sizeof (struct dk_map
);
3791 rval
= ddi_copyout(cl
->cl_map
, (void *)arg
, size
, flag
);
3797 #else /* ! _MULTI_DATAMODEL */
3798 size
= NDKMAP
* sizeof (struct dk_map
);
3799 rval
= ddi_copyout(cl
->cl_map
, (void *)arg
, size
, flag
);
3803 #endif /* _MULTI_DATAMODEL */
3808 * Function: cmlb_dkio_set_partition
3810 * Description: This routine is the driver entry point for handling user
3811 * requests to set the partition table (DKIOCSAPART). The actual
3812 * device partition is not updated.
3815 * arg - pointer to user provided dk_allmap structure used to set
3816 * the controller's notion of the partition table.
3817 * flag - this argument is a pass through to ddi_copyxxx()
3818 * directly from the mode argument of ioctl().
3827 cmlb_dkio_set_partition(struct cmlb_lun
*cl
, caddr_t arg
, int flag
)
3829 struct dk_map dk_map
[NDKMAP
];
3834 #if defined(_SUNOS_VTOC_16)
3835 struct dkl_partition
*vp
;
3839 * Set the map for all logical partitions. We lock
3840 * the priority just to make sure an interrupt doesn't
3841 * come in while the map is half updated.
3843 _NOTE(DATA_READABLE_WITHOUT_LOCK(cmlb_lun::cl_solaris_size
))
3844 mutex_enter(CMLB_MUTEX(cl
));
3846 if (cl
->cl_blockcount
> CMLB_OLDVTOC_LIMIT
) {
3847 mutex_exit(CMLB_MUTEX(cl
));
3850 mutex_exit(CMLB_MUTEX(cl
));
3851 if (cl
->cl_solaris_size
== 0) {
3855 #ifdef _MULTI_DATAMODEL
3856 switch (ddi_model_convert_from(flag
& FMODELS
)) {
3857 case DDI_MODEL_ILP32
: {
3858 struct dk_map32 dk_map32
[NDKMAP
];
3860 size
= NDKMAP
* sizeof (struct dk_map32
);
3861 rval
= ddi_copyin((void *)arg
, dk_map32
, size
, flag
);
3865 for (i
= 0; i
< NDKMAP
; i
++) {
3866 dk_map
[i
].dkl_cylno
= dk_map32
[i
].dkl_cylno
;
3867 dk_map
[i
].dkl_nblk
= dk_map32
[i
].dkl_nblk
;
3871 case DDI_MODEL_NONE
:
3872 size
= NDKMAP
* sizeof (struct dk_map
);
3873 rval
= ddi_copyin((void *)arg
, dk_map
, size
, flag
);
3879 #else /* ! _MULTI_DATAMODEL */
3880 size
= NDKMAP
* sizeof (struct dk_map
);
3881 rval
= ddi_copyin((void *)arg
, dk_map
, size
, flag
);
3885 #endif /* _MULTI_DATAMODEL */
3887 mutex_enter(CMLB_MUTEX(cl
));
3888 /* Note: The size used in this bcopy is set based upon the data model */
3889 bcopy(dk_map
, cl
->cl_map
, size
);
3890 #if defined(_SUNOS_VTOC_16)
3891 vp
= (struct dkl_partition
*)&(cl
->cl_vtoc
);
3892 #endif /* defined(_SUNOS_VTOC_16) */
3893 for (i
= 0; i
< NDKMAP
; i
++) {
3894 lp
= &cl
->cl_map
[i
];
3896 cl
->cl_g
.dkg_nhead
* cl
->cl_g
.dkg_nsect
* lp
->dkl_cylno
;
3897 #if defined(_SUNOS_VTOC_16)
3898 vp
->p_start
= cl
->cl_offset
[i
];
3899 vp
->p_size
= lp
->dkl_nblk
;
3901 #endif /* defined(_SUNOS_VTOC_16) */
3902 #if defined(__i386) || defined(__amd64)
3903 cl
->cl_offset
[i
] += cl
->cl_solaris_offset
;
3906 mutex_exit(CMLB_MUTEX(cl
));
3912 * Function: cmlb_dkio_get_vtoc
3914 * Description: This routine is the driver entry point for handling user
3915 * requests to get the current volume table of contents
3919 * arg pointer to user provided vtoc structure specifying
3922 * flag this argument is a pass through to ddi_copyxxx()
3923 * directly from the mode argument of ioctl().
3925 * tg_cookie cookie from target driver to be passed back to target
3926 * driver when we call back to it through tg_ops.
3934 cmlb_dkio_get_vtoc(struct cmlb_lun
*cl
, caddr_t arg
, int flag
, void *tg_cookie
)
3936 #if defined(_SUNOS_VTOC_8)
3937 struct vtoc user_vtoc
;
3938 #endif /* defined(_SUNOS_VTOC_8) */
3941 mutex_enter(CMLB_MUTEX(cl
));
3942 if (cl
->cl_blockcount
> CMLB_OLDVTOC_LIMIT
) {
3943 mutex_exit(CMLB_MUTEX(cl
));
3947 rval
= cmlb_validate_geometry(cl
, B_TRUE
, 0, tg_cookie
);
3949 #if defined(_SUNOS_VTOC_8)
3950 if (rval
== EINVAL
&&
3951 (cl
->cl_alter_behavior
& CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8
)) {
3953 * This is to return a default label even when we do not
3954 * really assume a default label for the device.
3955 * dad driver utilizes this.
3957 if (cl
->cl_blockcount
<= CMLB_OLDVTOC_LIMIT
) {
3958 cmlb_setup_default_geometry(cl
, tg_cookie
);
3964 mutex_exit(CMLB_MUTEX(cl
));
3968 #if defined(_SUNOS_VTOC_8)
3969 cmlb_build_user_vtoc(cl
, &user_vtoc
);
3970 mutex_exit(CMLB_MUTEX(cl
));
3972 #ifdef _MULTI_DATAMODEL
3973 switch (ddi_model_convert_from(flag
& FMODELS
)) {
3974 case DDI_MODEL_ILP32
: {
3975 struct vtoc32 user_vtoc32
;
3977 vtoctovtoc32(user_vtoc
, user_vtoc32
);
3978 if (ddi_copyout(&user_vtoc32
, (void *)arg
,
3979 sizeof (struct vtoc32
), flag
)) {
3985 case DDI_MODEL_NONE
:
3986 if (ddi_copyout(&user_vtoc
, (void *)arg
,
3987 sizeof (struct vtoc
), flag
)) {
3992 #else /* ! _MULTI_DATAMODEL */
3993 if (ddi_copyout(&user_vtoc
, (void *)arg
, sizeof (struct vtoc
), flag
)) {
3996 #endif /* _MULTI_DATAMODEL */
3998 #elif defined(_SUNOS_VTOC_16)
3999 mutex_exit(CMLB_MUTEX(cl
));
4001 #ifdef _MULTI_DATAMODEL
4003 * The cl_vtoc structure is a "struct dk_vtoc" which is always
4004 * 32-bit to maintain compatibility with existing on-disk
4005 * structures. Thus, we need to convert the structure when copying
4006 * it out to a datamodel-dependent "struct vtoc" in a 64-bit
4007 * program. If the target is a 32-bit program, then no conversion
4010 /* LINTED: logical expression always true: op "||" */
4011 ASSERT(sizeof (cl
->cl_vtoc
) == sizeof (struct vtoc32
));
4012 switch (ddi_model_convert_from(flag
& FMODELS
)) {
4013 case DDI_MODEL_ILP32
:
4014 if (ddi_copyout(&(cl
->cl_vtoc
), (void *)arg
,
4015 sizeof (cl
->cl_vtoc
), flag
)) {
4020 case DDI_MODEL_NONE
: {
4021 struct vtoc user_vtoc
;
4023 vtoc32tovtoc(cl
->cl_vtoc
, user_vtoc
);
4024 if (ddi_copyout(&user_vtoc
, (void *)arg
,
4025 sizeof (struct vtoc
), flag
)) {
4031 #else /* ! _MULTI_DATAMODEL */
4032 if (ddi_copyout(&(cl
->cl_vtoc
), (void *)arg
, sizeof (cl
->cl_vtoc
),
4036 #endif /* _MULTI_DATAMODEL */
4038 #error "No VTOC format defined."
4046 * Function: cmlb_dkio_get_extvtoc
4049 cmlb_dkio_get_extvtoc(struct cmlb_lun
*cl
, caddr_t arg
, int flag
,
4052 struct extvtoc ext_vtoc
;
4053 #if defined(_SUNOS_VTOC_8)
4054 struct vtoc user_vtoc
;
4055 #endif /* defined(_SUNOS_VTOC_8) */
4058 bzero(&ext_vtoc
, sizeof (struct extvtoc
));
4059 mutex_enter(CMLB_MUTEX(cl
));
4060 rval
= cmlb_validate_geometry(cl
, B_TRUE
, 0, tg_cookie
);
4062 #if defined(_SUNOS_VTOC_8)
4063 if (rval
== EINVAL
&&
4064 (cl
->cl_alter_behavior
& CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8
)) {
4066 * This is to return a default label even when we do not
4067 * really assume a default label for the device.
4068 * dad driver utilizes this.
4070 if (cl
->cl_blockcount
<= CMLB_OLDVTOC_LIMIT
) {
4071 cmlb_setup_default_geometry(cl
, tg_cookie
);
4077 mutex_exit(CMLB_MUTEX(cl
));
4081 #if defined(_SUNOS_VTOC_8)
4082 cmlb_build_user_vtoc(cl
, &user_vtoc
);
4083 mutex_exit(CMLB_MUTEX(cl
));
4086 * Checking callers data model does not make much sense here
4087 * since extvtoc will always be equivalent to 64bit vtoc.
4088 * What is important is whether the kernel is in 32 or 64 bit
4092 if (ddi_copyout(&user_vtoc
, (void *)arg
,
4093 sizeof (struct extvtoc
), flag
)) {
4097 vtoc32tovtoc(user_vtoc
, ext_vtoc
);
4098 if (ddi_copyout(&ext_vtoc
, (void *)arg
,
4099 sizeof (struct extvtoc
), flag
)) {
4104 #elif defined(_SUNOS_VTOC_16)
4106 * The cl_vtoc structure is a "struct dk_vtoc" which is always
4107 * 32-bit to maintain compatibility with existing on-disk
4108 * structures. Thus, we need to convert the structure when copying
4111 vtoc32tovtoc(cl
->cl_vtoc
, ext_vtoc
);
4112 mutex_exit(CMLB_MUTEX(cl
));
4114 if (ddi_copyout(&ext_vtoc
, (void *)arg
, sizeof (struct extvtoc
), flag
))
4117 #error "No VTOC format defined."
4124 * This routine implements the DKIOCGETEFI ioctl. This ioctl is currently
4125 * used to read the GPT Partition Table Header (primary/backup), the GUID
4126 * partition Entry Array (primary/backup), and the MBR.
4129 cmlb_dkio_get_efi(struct cmlb_lun
*cl
, caddr_t arg
, int flag
, void *tg_cookie
)
4136 if (ddi_copyin(arg
, &user_efi
, sizeof (dk_efi_t
), flag
))
4139 user_efi
.dki_data
= (void *)(uintptr_t)user_efi
.dki_data_64
;
4141 if (user_efi
.dki_length
== 0 ||
4142 user_efi
.dki_length
> cmlb_tg_max_efi_xfer
)
4145 tgt_lba
= user_efi
.dki_lba
;
4147 mutex_enter(CMLB_MUTEX(cl
));
4148 if ((cmlb_check_update_blockcount(cl
, tg_cookie
) != 0) ||
4149 (cl
->cl_tgt_blocksize
== 0) ||
4150 (user_efi
.dki_length
% cl
->cl_sys_blocksize
)) {
4151 mutex_exit(CMLB_MUTEX(cl
));
4154 if (cl
->cl_tgt_blocksize
!= cl
->cl_sys_blocksize
)
4155 tgt_lba
= tgt_lba
* cl
->cl_tgt_blocksize
/
4156 cl
->cl_sys_blocksize
;
4157 mutex_exit(CMLB_MUTEX(cl
));
4159 buffer
= kmem_alloc(user_efi
.dki_length
, KM_SLEEP
);
4160 rval
= DK_TG_READ(cl
, buffer
, tgt_lba
, user_efi
.dki_length
, tg_cookie
);
4161 if (rval
== 0 && ddi_copyout(buffer
, user_efi
.dki_data
,
4162 user_efi
.dki_length
, flag
) != 0)
4165 kmem_free(buffer
, user_efi
.dki_length
);
4169 #if defined(_SUNOS_VTOC_8)
4171 * Function: cmlb_build_user_vtoc
4173 * Description: This routine populates a pass by reference variable with the
4174 * current volume table of contents.
4176 * Arguments: cl - driver soft state (unit) structure
4177 * user_vtoc - pointer to vtoc structure to be populated
4180 cmlb_build_user_vtoc(struct cmlb_lun
*cl
, struct vtoc
*user_vtoc
)
4182 struct dk_map2
*lpart
;
4183 struct dk_map
*lmap
;
4184 struct partition
*vpart
;
4188 ASSERT(mutex_owned(CMLB_MUTEX(cl
)));
4191 * Return vtoc structure fields in the provided VTOC area, addressed
4194 bzero(user_vtoc
, sizeof (struct vtoc
));
4195 user_vtoc
->v_bootinfo
[0] = cl
->cl_vtoc
.v_bootinfo
[0];
4196 user_vtoc
->v_bootinfo
[1] = cl
->cl_vtoc
.v_bootinfo
[1];
4197 user_vtoc
->v_bootinfo
[2] = cl
->cl_vtoc
.v_bootinfo
[2];
4198 user_vtoc
->v_sanity
= VTOC_SANE
;
4199 user_vtoc
->v_version
= cl
->cl_vtoc
.v_version
;
4200 bcopy(cl
->cl_vtoc
.v_volume
, user_vtoc
->v_volume
, LEN_DKL_VVOL
);
4201 user_vtoc
->v_sectorsz
= cl
->cl_sys_blocksize
;
4202 user_vtoc
->v_nparts
= cl
->cl_vtoc
.v_nparts
;
4204 for (i
= 0; i
< 10; i
++)
4205 user_vtoc
->v_reserved
[i
] = cl
->cl_vtoc
.v_reserved
[i
];
4208 * Convert partitioning information.
4210 * Note the conversion from starting cylinder number
4211 * to starting sector number.
4214 lpart
= (struct dk_map2
*)cl
->cl_vtoc
.v_part
;
4215 vpart
= user_vtoc
->v_part
;
4217 nblks
= cl
->cl_g
.dkg_nsect
* cl
->cl_g
.dkg_nhead
;
4219 for (i
= 0; i
< V_NUMPAR
; i
++) {
4220 vpart
->p_tag
= lpart
->p_tag
;
4221 vpart
->p_flag
= lpart
->p_flag
;
4222 vpart
->p_start
= lmap
->dkl_cylno
* nblks
;
4223 vpart
->p_size
= lmap
->dkl_nblk
;
4229 user_vtoc
->timestamp
[i
] = (time_t)cl
->cl_vtoc
.v_timestamp
[i
];
4232 bcopy(cl
->cl_asciilabel
, user_vtoc
->v_asciilabel
, LEN_DKL_ASCII
);
4237 cmlb_dkio_partition(struct cmlb_lun
*cl
, caddr_t arg
, int flag
,
4240 struct partition64 p64
;
4243 efi_gpe_t
*partitions
;
4246 int n_gpe_per_blk
= 0;
4248 if (ddi_copyin((const void *)arg
, &p64
,
4249 sizeof (struct partition64
), flag
)) {
4253 buffer
= kmem_alloc(cl
->cl_sys_blocksize
, KM_SLEEP
);
4254 rval
= DK_TG_READ(cl
, buffer
, 1, cl
->cl_sys_blocksize
, tg_cookie
);
4258 cmlb_swap_efi_gpt(buffer
);
4260 if ((rval
= cmlb_validate_efi(buffer
)) != 0)
4263 nparts
= buffer
->efi_gpt_NumberOfPartitionEntries
;
4264 gpe_lba
= buffer
->efi_gpt_PartitionEntryLBA
;
4265 if (p64
.p_partno
>= nparts
) {
4266 /* couldn't find it */
4271 * Read the block that contains the requested GPE.
4273 n_gpe_per_blk
= cl
->cl_sys_blocksize
/ sizeof (efi_gpe_t
);
4274 gpe_lba
+= p64
.p_partno
/ n_gpe_per_blk
;
4275 rval
= DK_TG_READ(cl
, buffer
, gpe_lba
, cl
->cl_sys_blocksize
, tg_cookie
);
4280 partitions
= (efi_gpe_t
*)buffer
;
4281 partitions
+= p64
.p_partno
% n_gpe_per_blk
;
4283 /* Byte swap only the requested GPE */
4284 cmlb_swap_efi_gpe(1, partitions
);
4286 bcopy(&partitions
->efi_gpe_PartitionTypeGUID
, &p64
.p_type
,
4287 sizeof (struct uuid
));
4288 p64
.p_start
= partitions
->efi_gpe_StartingLBA
;
4289 p64
.p_size
= partitions
->efi_gpe_EndingLBA
-
4292 if (ddi_copyout(&p64
, (void *)arg
, sizeof (struct partition64
), flag
))
4296 kmem_free(buffer
, cl
->cl_sys_blocksize
);
4302 * Function: cmlb_dkio_set_vtoc
4304 * Description: This routine is the driver entry point for handling user
4305 * requests to set the current volume table of contents
4309 * dev the device number
4310 * arg pointer to user provided vtoc structure used to set the
4313 * flag this argument is a pass through to ddi_copyxxx()
4314 * directly from the mode argument of ioctl().
4316 * tg_cookie cookie from target driver to be passed back to target
4317 * driver when we call back to it through tg_ops.
4326 cmlb_dkio_set_vtoc(struct cmlb_lun
*cl
, dev_t dev
, caddr_t arg
, int flag
,
4329 struct vtoc user_vtoc
;
4330 int shift
, rval
= 0;
4333 internal
= (cl
->cl_alter_behavior
& CMLB_INTERNAL_MINOR_NODES
) != 0;
4335 if (cl
->cl_alter_behavior
& CMLB_CREATE_P0_MINOR_NODE
)
4336 shift
= CMLBUNIT_FORCE_P0_SHIFT
;
4338 shift
= CMLBUNIT_SHIFT
;
4340 #ifdef _MULTI_DATAMODEL
4341 switch (ddi_model_convert_from(flag
& FMODELS
)) {
4342 case DDI_MODEL_ILP32
: {
4343 struct vtoc32 user_vtoc32
;
4345 if (ddi_copyin((const void *)arg
, &user_vtoc32
,
4346 sizeof (struct vtoc32
), flag
)) {
4349 vtoc32tovtoc(user_vtoc32
, user_vtoc
);
4353 case DDI_MODEL_NONE
:
4354 if (ddi_copyin((const void *)arg
, &user_vtoc
,
4355 sizeof (struct vtoc
), flag
)) {
4360 #else /* ! _MULTI_DATAMODEL */
4361 if (ddi_copyin((const void *)arg
, &user_vtoc
,
4362 sizeof (struct vtoc
), flag
)) {
4365 #endif /* _MULTI_DATAMODEL */
4367 mutex_enter(CMLB_MUTEX(cl
));
4369 if (cl
->cl_blockcount
> CMLB_OLDVTOC_LIMIT
) {
4370 mutex_exit(CMLB_MUTEX(cl
));
4374 #if defined(__i386) || defined(__amd64)
4375 if (cl
->cl_tgt_blocksize
!= cl
->cl_sys_blocksize
) {
4376 mutex_exit(CMLB_MUTEX(cl
));
4381 if (cl
->cl_g
.dkg_ncyl
== 0) {
4382 mutex_exit(CMLB_MUTEX(cl
));
4386 mutex_exit(CMLB_MUTEX(cl
));
4387 cmlb_clear_efi(cl
, tg_cookie
);
4388 ddi_remove_minor_node(CMLB_DEVINFO(cl
), "wd");
4389 ddi_remove_minor_node(CMLB_DEVINFO(cl
), "wd,raw");
4392 * cmlb_dkio_set_vtoc creates duplicate minor nodes when
4393 * relabeling an SMI disk. To avoid that we remove them
4395 * It should be OK to remove a non-existed minor node.
4397 ddi_remove_minor_node(CMLB_DEVINFO(cl
), "h");
4398 ddi_remove_minor_node(CMLB_DEVINFO(cl
), "h,raw");
4400 (void) cmlb_create_minor(CMLB_DEVINFO(cl
), "h",
4401 S_IFBLK
, (CMLBUNIT(dev
, shift
) << shift
) | WD_NODE
,
4402 cl
->cl_node_type
, 0, internal
);
4403 (void) cmlb_create_minor(CMLB_DEVINFO(cl
), "h,raw",
4404 S_IFCHR
, (CMLBUNIT(dev
, shift
) << shift
) | WD_NODE
,
4405 cl
->cl_node_type
, 0, internal
);
4406 mutex_enter(CMLB_MUTEX(cl
));
4408 if ((rval
= cmlb_build_label_vtoc(cl
, &user_vtoc
)) == 0) {
4409 if ((rval
= cmlb_write_label(cl
, tg_cookie
)) == 0) {
4410 if (cmlb_validate_geometry(cl
,
4411 B_TRUE
, 0, tg_cookie
) != 0) {
4412 cmlb_dbg(CMLB_ERROR
, cl
,
4413 "cmlb_dkio_set_vtoc: "
4414 "Failed validate geometry\n");
4416 cl
->cl_msglog_flag
|= CMLB_ALLOW_2TB_WARN
;
4419 mutex_exit(CMLB_MUTEX(cl
));
4424 * Function: cmlb_dkio_set_extvtoc
4427 cmlb_dkio_set_extvtoc(struct cmlb_lun
*cl
, dev_t dev
, caddr_t arg
, int flag
,
4430 int shift
, rval
= 0;
4431 struct vtoc user_vtoc
;
4434 if (cl
->cl_alter_behavior
& CMLB_CREATE_P0_MINOR_NODE
)
4435 shift
= CMLBUNIT_FORCE_P0_SHIFT
;
4437 shift
= CMLBUNIT_SHIFT
;
4440 * Checking callers data model does not make much sense here
4441 * since extvtoc will always be equivalent to 64bit vtoc.
4442 * What is important is whether the kernel is in 32 or 64 bit
4446 if (ddi_copyin((const void *)arg
, &user_vtoc
,
4447 sizeof (struct extvtoc
), flag
)) {
4451 struct extvtoc user_extvtoc
;
4452 if (ddi_copyin((const void *)arg
, &user_extvtoc
,
4453 sizeof (struct extvtoc
), flag
)) {
4457 vtoctovtoc32(user_extvtoc
, user_vtoc
);
4460 internal
= (cl
->cl_alter_behavior
& CMLB_INTERNAL_MINOR_NODES
) != 0;
4461 mutex_enter(CMLB_MUTEX(cl
));
4462 #if defined(__i386) || defined(__amd64)
4463 if (cl
->cl_tgt_blocksize
!= cl
->cl_sys_blocksize
) {
4464 mutex_exit(CMLB_MUTEX(cl
));
4469 if (cl
->cl_g
.dkg_ncyl
== 0) {
4470 mutex_exit(CMLB_MUTEX(cl
));
4474 mutex_exit(CMLB_MUTEX(cl
));
4475 cmlb_clear_efi(cl
, tg_cookie
);
4476 ddi_remove_minor_node(CMLB_DEVINFO(cl
), "wd");
4477 ddi_remove_minor_node(CMLB_DEVINFO(cl
), "wd,raw");
4479 * cmlb_dkio_set_extvtoc creates duplicate minor nodes when
4480 * relabeling an SMI disk. To avoid that we remove them
4482 * It should be OK to remove a non-existed minor node.
4484 ddi_remove_minor_node(CMLB_DEVINFO(cl
), "h");
4485 ddi_remove_minor_node(CMLB_DEVINFO(cl
), "h,raw");
4487 (void) cmlb_create_minor(CMLB_DEVINFO(cl
), "h",
4488 S_IFBLK
, (CMLBUNIT(dev
, shift
) << shift
) | WD_NODE
,
4489 cl
->cl_node_type
, 0, internal
);
4490 (void) cmlb_create_minor(CMLB_DEVINFO(cl
), "h,raw",
4491 S_IFCHR
, (CMLBUNIT(dev
, shift
) << shift
) | WD_NODE
,
4492 cl
->cl_node_type
, 0, internal
);
4494 mutex_enter(CMLB_MUTEX(cl
));
4496 if ((rval
= cmlb_build_label_vtoc(cl
, &user_vtoc
)) == 0) {
4497 if ((rval
= cmlb_write_label(cl
, tg_cookie
)) == 0) {
4498 if (cmlb_validate_geometry(cl
,
4499 B_TRUE
, 0, tg_cookie
) != 0) {
4500 cmlb_dbg(CMLB_ERROR
, cl
,
4501 "cmlb_dkio_set_vtoc: "
4502 "Failed validate geometry\n");
4506 mutex_exit(CMLB_MUTEX(cl
));
4511 * Function: cmlb_build_label_vtoc
4513 * Description: This routine updates the driver soft state current volume table
4514 * of contents based on a user specified vtoc.
4516 * Arguments: cl - driver soft state (unit) structure
4517 * user_vtoc - pointer to vtoc structure specifying vtoc to be used
4518 * to update the driver soft state.
4524 cmlb_build_label_vtoc(struct cmlb_lun
*cl
, struct vtoc
*user_vtoc
)
4526 struct dk_map
*lmap
;
4527 struct partition
*vpart
;
4529 #if defined(_SUNOS_VTOC_8)
4531 struct dk_map2
*lpart
;
4532 #endif /* defined(_SUNOS_VTOC_8) */
4535 ASSERT(mutex_owned(CMLB_MUTEX(cl
)));
4537 /* Sanity-check the vtoc */
4538 if (user_vtoc
->v_sanity
!= VTOC_SANE
||
4539 user_vtoc
->v_sectorsz
!= cl
->cl_sys_blocksize
||
4540 user_vtoc
->v_nparts
!= V_NUMPAR
) {
4541 cmlb_dbg(CMLB_INFO
, cl
,
4542 "cmlb_build_label_vtoc: vtoc not valid\n");
4546 nblks
= cl
->cl_g
.dkg_nsect
* cl
->cl_g
.dkg_nhead
;
4548 cmlb_dbg(CMLB_INFO
, cl
,
4549 "cmlb_build_label_vtoc: geom nblks is 0\n");
4553 #if defined(_SUNOS_VTOC_8)
4554 vpart
= user_vtoc
->v_part
;
4555 for (i
= 0; i
< V_NUMPAR
; i
++) {
4556 if (((unsigned)vpart
->p_start
% nblks
) != 0) {
4557 cmlb_dbg(CMLB_INFO
, cl
,
4558 "cmlb_build_label_vtoc: p_start not multiply of"
4559 "nblks part %d p_start %d nblks %d\n", i
,
4560 vpart
->p_start
, nblks
);
4563 ncyl
= (unsigned)vpart
->p_start
/ nblks
;
4564 ncyl
+= (unsigned)vpart
->p_size
/ nblks
;
4565 if (((unsigned)vpart
->p_size
% nblks
) != 0) {
4568 if (ncyl
> (int)cl
->cl_g
.dkg_ncyl
) {
4569 cmlb_dbg(CMLB_INFO
, cl
,
4570 "cmlb_build_label_vtoc: ncyl %d > dkg_ncyl %d"
4571 "p_size %ld p_start %ld nblks %d part number %d"
4573 ncyl
, cl
->cl_g
.dkg_ncyl
, vpart
->p_size
,
4574 vpart
->p_start
, nblks
,
4581 #endif /* defined(_SUNOS_VTOC_8) */
4583 /* Put appropriate vtoc structure fields into the disk label */
4584 #if defined(_SUNOS_VTOC_16)
4586 * The vtoc is always a 32bit data structure to maintain the
4587 * on-disk format. Convert "in place" instead of doing bcopy.
4589 vtoctovtoc32((*user_vtoc
), (*((struct vtoc32
*)&(cl
->cl_vtoc
))));
4592 * in the 16-slice vtoc, starting sectors are expressed in
4593 * numbers *relative* to the start of the Solaris fdisk partition.
4596 vpart
= user_vtoc
->v_part
;
4598 for (i
= 0; i
< (int)user_vtoc
->v_nparts
; i
++, lmap
++, vpart
++) {
4599 lmap
->dkl_cylno
= (unsigned)vpart
->p_start
/ nblks
;
4600 lmap
->dkl_nblk
= (unsigned)vpart
->p_size
;
4603 #elif defined(_SUNOS_VTOC_8)
4605 cl
->cl_vtoc
.v_bootinfo
[0] = (uint32_t)user_vtoc
->v_bootinfo
[0];
4606 cl
->cl_vtoc
.v_bootinfo
[1] = (uint32_t)user_vtoc
->v_bootinfo
[1];
4607 cl
->cl_vtoc
.v_bootinfo
[2] = (uint32_t)user_vtoc
->v_bootinfo
[2];
4609 cl
->cl_vtoc
.v_sanity
= (uint32_t)user_vtoc
->v_sanity
;
4610 cl
->cl_vtoc
.v_version
= (uint32_t)user_vtoc
->v_version
;
4612 bcopy(user_vtoc
->v_volume
, cl
->cl_vtoc
.v_volume
, LEN_DKL_VVOL
);
4614 cl
->cl_vtoc
.v_nparts
= user_vtoc
->v_nparts
;
4616 for (i
= 0; i
< 10; i
++)
4617 cl
->cl_vtoc
.v_reserved
[i
] = user_vtoc
->v_reserved
[i
];
4620 * Note the conversion from starting sector number
4621 * to starting cylinder number.
4622 * Return error if division results in a remainder.
4625 lpart
= cl
->cl_vtoc
.v_part
;
4626 vpart
= user_vtoc
->v_part
;
4628 for (i
= 0; i
< (int)user_vtoc
->v_nparts
; i
++) {
4629 lpart
->p_tag
= vpart
->p_tag
;
4630 lpart
->p_flag
= vpart
->p_flag
;
4631 lmap
->dkl_cylno
= (unsigned)vpart
->p_start
/ nblks
;
4632 lmap
->dkl_nblk
= (unsigned)vpart
->p_size
;
4640 if (user_vtoc
->timestamp
[i
] > TIME32_MAX
) {
4641 cl
->cl_vtoc
.v_timestamp
[i
] = TIME32_MAX
;
4643 cl
->cl_vtoc
.v_timestamp
[i
] = user_vtoc
->timestamp
[i
];
4646 cl
->cl_vtoc
.v_timestamp
[i
] = user_vtoc
->timestamp
[i
];
4650 bcopy(user_vtoc
->v_asciilabel
, cl
->cl_asciilabel
, LEN_DKL_ASCII
);
4652 #error "No VTOC format defined."
4658 * Function: cmlb_clear_efi
4660 * Description: This routine clears all EFI labels.
4663 * cl driver soft state (unit) structure
4665 * tg_cookie cookie from target driver to be passed back to target
4666 * driver when we call back to it through tg_ops.
4670 cmlb_clear_efi(struct cmlb_lun
*cl
, void *tg_cookie
)
4676 ASSERT(!mutex_owned(CMLB_MUTEX(cl
)));
4678 mutex_enter(CMLB_MUTEX(cl
));
4679 cl
->cl_reserved
= -1;
4680 mutex_exit(CMLB_MUTEX(cl
));
4682 gpt
= kmem_alloc(cl
->cl_sys_blocksize
, KM_SLEEP
);
4684 if (DK_TG_READ(cl
, gpt
, 1, cl
->cl_sys_blocksize
, tg_cookie
) != 0) {
4688 cmlb_swap_efi_gpt(gpt
);
4689 rval
= cmlb_validate_efi(gpt
);
4692 bzero(gpt
, sizeof (efi_gpt_t
));
4693 if (rval
= DK_TG_WRITE(cl
, gpt
, 1, cl
->cl_sys_blocksize
,
4695 cmlb_dbg(CMLB_INFO
, cl
,
4696 "cmlb_clear_efi: clear primary label failed\n");
4700 rval
= DK_TG_GETCAP(cl
, &cap
, tg_cookie
);
4705 if ((rval
= DK_TG_READ(cl
, gpt
, cap
- 1, cl
->cl_sys_blocksize
,
4709 cmlb_swap_efi_gpt(gpt
);
4710 rval
= cmlb_validate_efi(gpt
);
4713 cmlb_dbg(CMLB_TRACE
, cl
,
4714 "cmlb_clear_efi clear backup@%lu\n", cap
- 1);
4715 bzero(gpt
, sizeof (efi_gpt_t
));
4716 if ((rval
= DK_TG_WRITE(cl
, gpt
, cap
- 1, cl
->cl_sys_blocksize
,
4718 cmlb_dbg(CMLB_INFO
, cl
,
4719 "cmlb_clear_efi: clear backup label failed\n");
4723 * Refer to comments related to off-by-1 at the
4724 * header of this file
4726 if ((rval
= DK_TG_READ(cl
, gpt
, cap
- 2,
4727 cl
->cl_sys_blocksize
, tg_cookie
)) != 0) {
4730 cmlb_swap_efi_gpt(gpt
);
4731 rval
= cmlb_validate_efi(gpt
);
4733 /* clear legacy backup EFI label */
4734 cmlb_dbg(CMLB_TRACE
, cl
,
4735 "cmlb_clear_efi clear legacy backup@%lu\n",
4737 bzero(gpt
, sizeof (efi_gpt_t
));
4738 if ((rval
= DK_TG_WRITE(cl
, gpt
, cap
- 2,
4739 cl
->cl_sys_blocksize
, tg_cookie
))) {
4740 cmlb_dbg(CMLB_INFO
, cl
,
4741 "cmlb_clear_efi: clear legacy backup label "
4748 kmem_free(gpt
, cl
->cl_sys_blocksize
);
4752 * Function: cmlb_set_vtoc
4754 * Description: This routine writes data to the appropriate positions
4757 * cl driver soft state (unit) structure
4759 * dkl the data to be written
4761 * tg_cookie cookie from target driver to be passed back to target
4762 * driver when we call back to it through tg_ops.
4767 cmlb_set_vtoc(struct cmlb_lun
*cl
, struct dk_label
*dkl
, void *tg_cookie
)
4776 #if defined(__i386) || defined(__amd64)
4777 label_addr
= cl
->cl_solaris_offset
+ DK_LABEL_LOC
;
4779 /* Write the primary label at block 0 of the solaris partition. */
4783 rval
= DK_TG_WRITE(cl
, dkl
, label_addr
, cl
->cl_sys_blocksize
,
4791 * Calculate where the backup labels go. They are always on
4792 * the last alternate cylinder, but some older drives put them
4793 * on head 2 instead of the last head. They are always on the
4794 * first 5 odd sectors of the appropriate track.
4796 * We have no choice at this point, but to believe that the
4797 * disk label is valid. Use the geometry of the disk
4798 * as described in the label.
4800 cyl
= dkl
->dkl_ncyl
+ dkl
->dkl_acyl
- 1;
4801 head
= dkl
->dkl_nhead
- 1;
4804 * Write and verify the backup labels. Make sure we don't try to
4805 * write past the last cylinder.
4807 for (sec
= 1; ((sec
< 5 * 2 + 1) && (sec
< dkl
->dkl_nsect
)); sec
+= 2) {
4809 (cyl
* ((dkl
->dkl_nhead
* dkl
->dkl_nsect
) - dkl
->dkl_apc
)) +
4810 (head
* dkl
->dkl_nsect
) + sec
);
4811 #if defined(__i386) || defined(__amd64)
4812 blk
+= cl
->cl_solaris_offset
;
4814 rval
= DK_TG_WRITE(cl
, dkl
, blk
, cl
->cl_sys_blocksize
,
4816 cmlb_dbg(CMLB_INFO
, cl
,
4817 "cmlb_set_vtoc: wrote backup label %llx\n", blk
);
4827 * Function: cmlb_clear_vtoc
4829 * Description: This routine clears out the VTOC labels.
4832 * cl driver soft state (unit) structure
4834 * tg_cookie cookie from target driver to be passed back to target
4835 * driver when we call back to it through tg_ops.
4840 cmlb_clear_vtoc(struct cmlb_lun
*cl
, void *tg_cookie
)
4842 struct dk_label
*dkl
;
4844 mutex_exit(CMLB_MUTEX(cl
));
4845 dkl
= kmem_zalloc(cl
->cl_sys_blocksize
, KM_SLEEP
);
4846 mutex_enter(CMLB_MUTEX(cl
));
4848 * cmlb_set_vtoc uses these fields in order to figure out
4849 * where to overwrite the backup labels
4851 dkl
->dkl_apc
= cl
->cl_g
.dkg_apc
;
4852 dkl
->dkl_ncyl
= cl
->cl_g
.dkg_ncyl
;
4853 dkl
->dkl_acyl
= cl
->cl_g
.dkg_acyl
;
4854 dkl
->dkl_nhead
= cl
->cl_g
.dkg_nhead
;
4855 dkl
->dkl_nsect
= cl
->cl_g
.dkg_nsect
;
4856 mutex_exit(CMLB_MUTEX(cl
));
4857 (void) cmlb_set_vtoc(cl
, dkl
, tg_cookie
);
4858 kmem_free(dkl
, cl
->cl_sys_blocksize
);
4860 mutex_enter(CMLB_MUTEX(cl
));
4864 * Function: cmlb_write_label
4866 * Description: This routine will validate and write the driver soft state vtoc
4867 * contents to the device.
4872 * tg_cookie cookie from target driver to be passed back to target
4873 * driver when we call back to it through tg_ops.
4876 * Return Code: the code returned by cmlb_send_scsi_cmd()
4883 cmlb_write_label(struct cmlb_lun
*cl
, void *tg_cookie
)
4885 struct dk_label
*dkl
;
4891 ASSERT(mutex_owned(CMLB_MUTEX(cl
)));
4892 mutex_exit(CMLB_MUTEX(cl
));
4893 dkl
= kmem_zalloc(cl
->cl_sys_blocksize
, KM_SLEEP
);
4894 mutex_enter(CMLB_MUTEX(cl
));
4896 bcopy(&cl
->cl_vtoc
, &dkl
->dkl_vtoc
, sizeof (struct dk_vtoc
));
4897 dkl
->dkl_rpm
= cl
->cl_g
.dkg_rpm
;
4898 dkl
->dkl_pcyl
= cl
->cl_g
.dkg_pcyl
;
4899 dkl
->dkl_apc
= cl
->cl_g
.dkg_apc
;
4900 dkl
->dkl_intrlv
= cl
->cl_g
.dkg_intrlv
;
4901 dkl
->dkl_ncyl
= cl
->cl_g
.dkg_ncyl
;
4902 dkl
->dkl_acyl
= cl
->cl_g
.dkg_acyl
;
4903 dkl
->dkl_nhead
= cl
->cl_g
.dkg_nhead
;
4904 dkl
->dkl_nsect
= cl
->cl_g
.dkg_nsect
;
4906 #if defined(_SUNOS_VTOC_8)
4907 dkl
->dkl_obs1
= cl
->cl_g
.dkg_obs1
;
4908 dkl
->dkl_obs2
= cl
->cl_g
.dkg_obs2
;
4909 dkl
->dkl_obs3
= cl
->cl_g
.dkg_obs3
;
4910 for (i
= 0; i
< NDKMAP
; i
++) {
4911 dkl
->dkl_map
[i
].dkl_cylno
= cl
->cl_map
[i
].dkl_cylno
;
4912 dkl
->dkl_map
[i
].dkl_nblk
= cl
->cl_map
[i
].dkl_nblk
;
4914 bcopy(cl
->cl_asciilabel
, dkl
->dkl_asciilabel
, LEN_DKL_ASCII
);
4915 #elif defined(_SUNOS_VTOC_16)
4916 dkl
->dkl_skew
= cl
->cl_dkg_skew
;
4918 #error "No VTOC format defined."
4921 dkl
->dkl_magic
= DKL_MAGIC
;
4922 dkl
->dkl_write_reinstruct
= cl
->cl_g
.dkg_write_reinstruct
;
4923 dkl
->dkl_read_reinstruct
= cl
->cl_g
.dkg_read_reinstruct
;
4925 /* Construct checksum for the new disk label */
4928 i
= sizeof (struct dk_label
) / sizeof (short);
4932 dkl
->dkl_cksum
= sum
;
4934 mutex_exit(CMLB_MUTEX(cl
));
4936 rval
= cmlb_set_vtoc(cl
, dkl
, tg_cookie
);
4938 kmem_free(dkl
, cl
->cl_sys_blocksize
);
4939 mutex_enter(CMLB_MUTEX(cl
));
4944 * This routine implements the DKIOCSETEFI ioctl. This ioctl is currently
4945 * used to write (or clear) the GPT Partition Table header (primary/backup)
4946 * and GUID partition Entry Array (primary/backup). It is also used to write
4947 * the Protective MBR.
4950 cmlb_dkio_set_efi(struct cmlb_lun
*cl
, dev_t dev
, caddr_t arg
, int flag
,
4954 int shift
, rval
= 0;
4959 if (ddi_copyin(arg
, &user_efi
, sizeof (dk_efi_t
), flag
))
4962 internal
= (cl
->cl_alter_behavior
& CMLB_INTERNAL_MINOR_NODES
) != 0;
4964 if (cl
->cl_alter_behavior
& CMLB_CREATE_P0_MINOR_NODE
)
4965 shift
= CMLBUNIT_FORCE_P0_SHIFT
;
4967 shift
= CMLBUNIT_SHIFT
;
4969 user_efi
.dki_data
= (void *)(uintptr_t)user_efi
.dki_data_64
;
4971 if (user_efi
.dki_length
== 0 ||
4972 user_efi
.dki_length
> cmlb_tg_max_efi_xfer
)
4975 tgt_lba
= user_efi
.dki_lba
;
4977 mutex_enter(CMLB_MUTEX(cl
));
4978 if ((cmlb_check_update_blockcount(cl
, tg_cookie
) != 0) ||
4979 (cl
->cl_tgt_blocksize
== 0) ||
4980 (user_efi
.dki_length
% cl
->cl_sys_blocksize
)) {
4981 mutex_exit(CMLB_MUTEX(cl
));
4984 if (cl
->cl_tgt_blocksize
!= cl
->cl_sys_blocksize
)
4986 cl
->cl_tgt_blocksize
/ cl
->cl_sys_blocksize
;
4987 mutex_exit(CMLB_MUTEX(cl
));
4989 buffer
= kmem_alloc(user_efi
.dki_length
, KM_SLEEP
);
4990 if (ddi_copyin(user_efi
.dki_data
, buffer
, user_efi
.dki_length
, flag
)) {
4994 * let's clear the vtoc labels and clear the softstate
4997 mutex_enter(CMLB_MUTEX(cl
));
4998 if (cl
->cl_vtoc
.v_sanity
== VTOC_SANE
) {
4999 cmlb_dbg(CMLB_TRACE
, cl
,
5000 "cmlb_dkio_set_efi: CLEAR VTOC\n");
5001 if (cl
->cl_label_from_media
== CMLB_LABEL_VTOC
)
5002 cmlb_clear_vtoc(cl
, tg_cookie
);
5003 bzero(&cl
->cl_vtoc
, sizeof (struct dk_vtoc
));
5004 mutex_exit(CMLB_MUTEX(cl
));
5005 ddi_remove_minor_node(CMLB_DEVINFO(cl
), "h");
5006 ddi_remove_minor_node(CMLB_DEVINFO(cl
), "h,raw");
5007 (void) cmlb_create_minor(CMLB_DEVINFO(cl
), "wd",
5009 (CMLBUNIT(dev
, shift
) << shift
) | WD_NODE
,
5010 cl
->cl_node_type
, 0, internal
);
5011 (void) cmlb_create_minor(CMLB_DEVINFO(cl
), "wd,raw",
5013 (CMLBUNIT(dev
, shift
) << shift
) | WD_NODE
,
5014 cl
->cl_node_type
, 0, internal
);
5016 mutex_exit(CMLB_MUTEX(cl
));
5018 rval
= DK_TG_WRITE(cl
, buffer
, tgt_lba
, user_efi
.dki_length
,
5022 mutex_enter(CMLB_MUTEX(cl
));
5023 cl
->cl_f_geometry_is_valid
= B_FALSE
;
5024 mutex_exit(CMLB_MUTEX(cl
));
5027 kmem_free(buffer
, user_efi
.dki_length
);
5032 * Function: cmlb_dkio_get_mboot
5034 * Description: This routine is the driver entry point for handling user
5035 * requests to get the current device mboot (DKIOCGMBOOT)
5038 * arg pointer to user provided mboot structure specifying
5039 * the current mboot.
5041 * flag this argument is a pass through to ddi_copyxxx()
5042 * directly from the mode argument of ioctl().
5044 * tg_cookie cookie from target driver to be passed back to target
5045 * driver when we call back to it through tg_ops.
5053 cmlb_dkio_get_mboot(struct cmlb_lun
*cl
, caddr_t arg
, int flag
, void *tg_cookie
)
5055 struct mboot
*mboot
;
5060 #if defined(_SUNOS_VTOC_8)
5061 if ((!ISREMOVABLE(cl
) && !ISHOTPLUGGABLE(cl
)) || (arg
== NULL
)) {
5062 #elif defined(_SUNOS_VTOC_16)
5069 * Read the mboot block, located at absolute block 0 on the target.
5071 buffer_size
= cl
->cl_sys_blocksize
;
5073 cmlb_dbg(CMLB_TRACE
, cl
,
5074 "cmlb_dkio_get_mboot: allocation size: 0x%x\n", buffer_size
);
5076 mboot
= kmem_zalloc(buffer_size
, KM_SLEEP
);
5077 if ((rval
= DK_TG_READ(cl
, mboot
, 0, buffer_size
, tg_cookie
)) == 0) {
5078 if (ddi_copyout(mboot
, (void *)arg
,
5079 sizeof (struct mboot
), flag
) != 0) {
5083 kmem_free(mboot
, buffer_size
);
5089 * Function: cmlb_dkio_set_mboot
5091 * Description: This routine is the driver entry point for handling user
5092 * requests to validate and set the device master boot
5096 * arg pointer to user provided mboot structure used to set the
5099 * flag this argument is a pass through to ddi_copyxxx()
5100 * directly from the mode argument of ioctl().
5102 * tg_cookie cookie from target driver to be passed back to target
5103 * driver when we call back to it through tg_ops.
5111 cmlb_dkio_set_mboot(struct cmlb_lun
*cl
, caddr_t arg
, int flag
, void *tg_cookie
)
5113 struct mboot
*mboot
= NULL
;
5118 ASSERT(!mutex_owned(CMLB_MUTEX(cl
)));
5120 #if defined(_SUNOS_VTOC_8)
5121 if (!ISREMOVABLE(cl
) && !ISHOTPLUGGABLE(cl
)) {
5130 mboot
= kmem_zalloc(cl
->cl_sys_blocksize
, KM_SLEEP
);
5132 if (ddi_copyin((const void *)arg
, mboot
,
5133 cl
->cl_sys_blocksize
, flag
) != 0) {
5134 kmem_free(mboot
, cl
->cl_sys_blocksize
);
5138 /* Is this really a master boot record? */
5139 magic
= LE_16(mboot
->signature
);
5140 if (magic
!= MBB_MAGIC
) {
5141 kmem_free(mboot
, cl
->cl_sys_blocksize
);
5145 rval
= DK_TG_WRITE(cl
, mboot
, 0, cl
->cl_sys_blocksize
, tg_cookie
);
5147 mutex_enter(CMLB_MUTEX(cl
));
5148 #if defined(__i386) || defined(__amd64)
5151 * mboot has been written successfully.
5152 * update the fdisk and vtoc tables in memory
5154 rval
= cmlb_update_fdisk_and_vtoc(cl
, tg_cookie
);
5155 if ((!cl
->cl_f_geometry_is_valid
) || (rval
!= 0)) {
5156 mutex_exit(CMLB_MUTEX(cl
));
5157 kmem_free(mboot
, cl
->cl_sys_blocksize
);
5163 cmlb_setup_default_geometry(cl
, tg_cookie
);
5169 * mboot has been written successfully.
5170 * set up the default geometry and VTOC
5172 if (cl
->cl_blockcount
<= CMLB_EXTVTOC_LIMIT
)
5173 cmlb_setup_default_geometry(cl
, tg_cookie
);
5176 cl
->cl_msglog_flag
|= CMLB_ALLOW_2TB_WARN
;
5177 mutex_exit(CMLB_MUTEX(cl
));
5178 kmem_free(mboot
, cl
->cl_sys_blocksize
);
5183 #if defined(__i386) || defined(__amd64)
5186 cmlb_dkio_set_ext_part(struct cmlb_lun
*cl
, caddr_t arg
, int flag
,
5190 diskaddr_t capacity
;
5192 ASSERT(!mutex_owned(CMLB_MUTEX(cl
)));
5194 mutex_enter(CMLB_MUTEX(cl
));
5195 capacity
= cl
->cl_blockcount
;
5196 fdisk_rval
= cmlb_read_fdisk(cl
, capacity
, tg_cookie
);
5197 if (fdisk_rval
!= 0) {
5198 mutex_exit(CMLB_MUTEX(cl
));
5199 return (fdisk_rval
);
5202 mutex_exit(CMLB_MUTEX(cl
));
5203 return (fdisk_rval
);
5208 * Function: cmlb_setup_default_geometry
5210 * Description: This local utility routine sets the default geometry as part of
5211 * setting the device mboot.
5214 * cl driver soft state (unit) structure
5216 * tg_cookie cookie from target driver to be passed back to target
5217 * driver when we call back to it through tg_ops.
5220 * Note: This may be redundant with cmlb_build_default_label.
5223 cmlb_setup_default_geometry(struct cmlb_lun
*cl
, void *tg_cookie
)
5225 struct cmlb_geom pgeom
;
5226 struct cmlb_geom
*pgeomp
= &pgeom
;
5228 int geom_base_cap
= 1;
5231 ASSERT(mutex_owned(CMLB_MUTEX(cl
)));
5233 /* zero out the soft state geometry and partition table. */
5234 bzero(&cl
->cl_g
, sizeof (struct dk_geom
));
5235 bzero(&cl
->cl_vtoc
, sizeof (struct dk_vtoc
));
5236 bzero(cl
->cl_map
, NDKMAP
* (sizeof (struct dk_map
)));
5239 * For the rpm, we use the minimum for the disk.
5240 * For the head, cyl and number of sector per track,
5241 * if the capacity <= 1GB, head = 64, sect = 32.
5242 * else head = 255, sect 63
5243 * Note: the capacity should be equal to C*H*S values.
5244 * This will cause some truncation of size due to
5245 * round off errors. For CD-ROMs, this truncation can
5246 * have adverse side effects, so returning ncyl and
5247 * nhead as 1. The nsect will overflow for most of
5248 * CD-ROMs as nsect is of type ushort.
5250 if (cl
->cl_alter_behavior
& CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8
) {
5252 * newfs currently can not handle 255 ntracks for SPARC
5253 * so get the geometry from target driver instead of coming up
5254 * with one based on capacity.
5256 mutex_exit(CMLB_MUTEX(cl
));
5257 ret
= DK_TG_GETPHYGEOM(cl
, pgeomp
, tg_cookie
);
5258 mutex_enter(CMLB_MUTEX(cl
));
5263 cmlb_dbg(CMLB_ERROR
, cl
,
5264 "cmlb_setup_default_geometry: "
5265 "tg_getphygeom failed %d\n", ret
);
5267 /* do default setting, geometry based on capacity */
5271 if (geom_base_cap
) {
5273 cl
->cl_g
.dkg_ncyl
= 1;
5274 cl
->cl_g
.dkg_nhead
= 1;
5275 cl
->cl_g
.dkg_nsect
= cl
->cl_blockcount
;
5276 } else if (cl
->cl_blockcount
< 160) {
5278 cl
->cl_g
.dkg_nhead
= 1;
5279 cl
->cl_g
.dkg_ncyl
= cl
->cl_blockcount
;
5280 cl
->cl_g
.dkg_nsect
= 1;
5281 } else if (cl
->cl_blockcount
<= 0x1000) {
5282 /* Needed for unlabeled SCSI floppies. */
5283 cl
->cl_g
.dkg_nhead
= 2;
5284 cl
->cl_g
.dkg_ncyl
= 80;
5285 cl
->cl_g
.dkg_pcyl
= 80;
5286 cl
->cl_g
.dkg_nsect
= cl
->cl_blockcount
/ (2 * 80);
5287 } else if (cl
->cl_blockcount
<= 0x200000) {
5288 cl
->cl_g
.dkg_nhead
= 64;
5289 cl
->cl_g
.dkg_nsect
= 32;
5290 cl
->cl_g
.dkg_ncyl
= cl
->cl_blockcount
/ (64 * 32);
5292 cl
->cl_g
.dkg_nhead
= 255;
5294 cl
->cl_g
.dkg_nsect
= ((cl
->cl_blockcount
+
5295 (UINT16_MAX
* 255 * 63) - 1) /
5296 (UINT16_MAX
* 255 * 63)) * 63;
5298 if (cl
->cl_g
.dkg_nsect
== 0)
5299 cl
->cl_g
.dkg_nsect
= (UINT16_MAX
/ 63) * 63;
5301 cl
->cl_g
.dkg_ncyl
= cl
->cl_blockcount
/
5302 (255 * cl
->cl_g
.dkg_nsect
);
5305 cl
->cl_g
.dkg_acyl
= 0;
5306 cl
->cl_g
.dkg_bcyl
= 0;
5307 cl
->cl_g
.dkg_intrlv
= 1;
5308 cl
->cl_g
.dkg_rpm
= 200;
5309 if (cl
->cl_g
.dkg_pcyl
== 0)
5310 cl
->cl_g
.dkg_pcyl
= cl
->cl_g
.dkg_ncyl
+
5313 cl
->cl_g
.dkg_ncyl
= (short)pgeomp
->g_ncyl
;
5314 cl
->cl_g
.dkg_acyl
= pgeomp
->g_acyl
;
5315 cl
->cl_g
.dkg_nhead
= pgeomp
->g_nhead
;
5316 cl
->cl_g
.dkg_nsect
= pgeomp
->g_nsect
;
5317 cl
->cl_g
.dkg_intrlv
= pgeomp
->g_intrlv
;
5318 cl
->cl_g
.dkg_rpm
= pgeomp
->g_rpm
;
5319 cl
->cl_g
.dkg_pcyl
= cl
->cl_g
.dkg_ncyl
+ cl
->cl_g
.dkg_acyl
;
5322 cl
->cl_g
.dkg_read_reinstruct
= 0;
5323 cl
->cl_g
.dkg_write_reinstruct
= 0;
5324 cl
->cl_solaris_size
= cl
->cl_g
.dkg_ncyl
*
5325 cl
->cl_g
.dkg_nhead
* cl
->cl_g
.dkg_nsect
;
5327 cl
->cl_map
['a'-'a'].dkl_cylno
= 0;
5328 cl
->cl_map
['a'-'a'].dkl_nblk
= cl
->cl_solaris_size
;
5330 cl
->cl_map
['c'-'a'].dkl_cylno
= 0;
5331 cl
->cl_map
['c'-'a'].dkl_nblk
= cl
->cl_solaris_size
;
5333 cl
->cl_vtoc
.v_part
[2].p_tag
= V_BACKUP
;
5334 cl
->cl_vtoc
.v_part
[2].p_flag
= V_UNMNT
;
5335 cl
->cl_vtoc
.v_nparts
= V_NUMPAR
;
5336 cl
->cl_vtoc
.v_version
= V_VERSION
;
5337 (void) sprintf((char *)cl
->cl_asciilabel
, "DEFAULT cyl %d alt %d"
5338 " hd %d sec %d", cl
->cl_g
.dkg_ncyl
, cl
->cl_g
.dkg_acyl
,
5339 cl
->cl_g
.dkg_nhead
, cl
->cl_g
.dkg_nsect
);
5341 cl
->cl_f_geometry_is_valid
= B_FALSE
;
5345 #if defined(__i386) || defined(__amd64)
5347 * Function: cmlb_update_fdisk_and_vtoc
5349 * Description: This local utility routine updates the device fdisk and vtoc
5350 * as part of setting the device mboot.
5353 * cl driver soft state (unit) structure
5355 * tg_cookie cookie from target driver to be passed back to target
5356 * driver when we call back to it through tg_ops.
5359 * Return Code: 0 for success or errno-type return code.
5361 * Note:x86: This looks like a duplicate of cmlb_validate_geometry(), but
5362 * these did exist separately in x86 sd.c.
5365 cmlb_update_fdisk_and_vtoc(struct cmlb_lun
*cl
, void *tg_cookie
)
5370 diskaddr_t capacity
;
5372 ASSERT(mutex_owned(CMLB_MUTEX(cl
)));
5374 if (cmlb_check_update_blockcount(cl
, tg_cookie
) != 0)
5378 * Set up the "whole disk" fdisk partition; this should always
5379 * exist, regardless of whether the disk contains an fdisk table
5382 cl
->cl_map
[P0_RAW_DISK
].dkl_cylno
= 0;
5383 cl
->cl_map
[P0_RAW_DISK
].dkl_nblk
= cl
->cl_blockcount
;
5386 * copy the lbasize and capacity so that if they're
5387 * reset while we're not holding the CMLB_MUTEX(cl), we will
5388 * continue to use valid values after the CMLB_MUTEX(cl) is
5391 capacity
= cl
->cl_blockcount
;
5394 * refresh the logical and physical geometry caches.
5395 * (data from mode sense format/rigid disk geometry pages,
5396 * and scsi_ifgetcap("geometry").
5398 cmlb_resync_geom_caches(cl
, capacity
, tg_cookie
);
5401 * Only DIRECT ACCESS devices will have Scl labels.
5402 * CD's supposedly have a Scl label, too
5404 if (cl
->cl_device_type
== DTYPE_DIRECT
|| ISREMOVABLE(cl
)) {
5405 fdisk_rval
= cmlb_read_fdisk(cl
, capacity
, tg_cookie
);
5406 if (fdisk_rval
!= 0) {
5407 ASSERT(mutex_owned(CMLB_MUTEX(cl
)));
5408 return (fdisk_rval
);
5411 if (cl
->cl_solaris_size
<= DK_LABEL_LOC
) {
5413 * Found fdisk table but no Solaris partition entry,
5414 * so don't call cmlb_uselabel() and don't create
5418 cl
->cl_f_geometry_is_valid
= B_TRUE
;
5419 goto no_solaris_partition
;
5421 } else if (capacity
< 0) {
5422 ASSERT(mutex_owned(CMLB_MUTEX(cl
)));
5427 * For Removable media We reach here if we have found a
5428 * SOLARIS PARTITION.
5429 * If cl_f_geometry_is_valid is B_FALSE it indicates that the SOLARIS
5430 * PARTITION has changed from the previous one, hence we will setup a
5431 * default VTOC in this case.
5433 if (!cl
->cl_f_geometry_is_valid
) {
5434 /* if we get here it is writable */
5435 /* we are called from SMBOOT, and after a write of fdisk */
5436 cmlb_build_default_label(cl
, tg_cookie
);
5440 no_solaris_partition
:
5442 #if defined(_SUNOS_VTOC_16)
5444 * If we have valid geometry, set up the remaining fdisk partitions.
5445 * Note that dkl_cylno is not used for the fdisk map entries, so
5446 * we set it to an entirely bogus value.
5448 for (count
= 0; count
< FDISK_PARTS
; count
++) {
5449 cl
->cl_map
[FDISK_P1
+ count
].dkl_cylno
= UINT32_MAX
;
5450 cl
->cl_map
[FDISK_P1
+ count
].dkl_nblk
=
5451 cl
->cl_fmap
[count
].fmap_nblk
;
5452 cl
->cl_offset
[FDISK_P1
+ count
] =
5453 cl
->cl_fmap
[count
].fmap_start
;
5457 for (count
= 0; count
< NDKMAP
; count
++) {
5458 #if defined(_SUNOS_VTOC_8)
5459 struct dk_map
*lp
= &cl
->cl_map
[count
];
5460 cl
->cl_offset
[count
] =
5461 cl
->cl_g
.dkg_nhead
* cl
->cl_g
.dkg_nsect
* lp
->dkl_cylno
;
5462 #elif defined(_SUNOS_VTOC_16)
5463 struct dkl_partition
*vp
= &cl
->cl_vtoc
.v_part
[count
];
5464 cl
->cl_offset
[count
] = vp
->p_start
+ cl
->cl_solaris_offset
;
5466 #error "No VTOC format defined."
5470 ASSERT(mutex_owned(CMLB_MUTEX(cl
)));
5475 #if defined(__i386) || defined(__amd64)
5477 cmlb_dkio_get_virtgeom(struct cmlb_lun
*cl
, caddr_t arg
, int flag
)
5481 /* Return the driver's notion of the media's logical geometry */
5482 struct dk_geom disk_geom
;
5483 struct dk_geom
*dkgp
= &disk_geom
;
5485 mutex_enter(CMLB_MUTEX(cl
));
5487 * If there is no HBA geometry available, or
5488 * if the HBA returned us something that doesn't
5489 * really fit into an Int 13/function 8 geometry
5490 * result, just fail the ioctl. See PSARC 1998/313.
5492 if (cl
->cl_lgeom
.g_nhead
== 0 ||
5493 cl
->cl_lgeom
.g_nsect
== 0 ||
5494 cl
->cl_lgeom
.g_ncyl
> 1024) {
5495 mutex_exit(CMLB_MUTEX(cl
));
5498 dkgp
->dkg_ncyl
= cl
->cl_lgeom
.g_ncyl
;
5499 dkgp
->dkg_acyl
= cl
->cl_lgeom
.g_acyl
;
5500 dkgp
->dkg_pcyl
= dkgp
->dkg_ncyl
+ dkgp
->dkg_acyl
;
5501 dkgp
->dkg_nhead
= cl
->cl_lgeom
.g_nhead
;
5502 dkgp
->dkg_nsect
= cl
->cl_lgeom
.g_nsect
;
5504 mutex_exit(CMLB_MUTEX(cl
));
5505 if (ddi_copyout(dkgp
, (void *)arg
,
5506 sizeof (struct dk_geom
), flag
)) {
5516 #if defined(__i386) || defined(__amd64)
5518 cmlb_dkio_get_phygeom(struct cmlb_lun
*cl
, caddr_t arg
, int flag
,
5522 diskaddr_t capacity
;
5525 /* Return the driver's notion of the media physical geometry */
5526 struct dk_geom disk_geom
;
5527 struct dk_geom
*dkgp
= &disk_geom
;
5529 mutex_enter(CMLB_MUTEX(cl
));
5531 if (cl
->cl_g
.dkg_nhead
!= 0 &&
5532 cl
->cl_g
.dkg_nsect
!= 0) {
5534 * We succeeded in getting a geometry, but
5535 * right now it is being reported as just the
5536 * Solaris fdisk partition, just like for
5537 * DKIOCGGEOM. We need to change that to be
5538 * correct for the entire disk now.
5540 bcopy(&cl
->cl_g
, dkgp
, sizeof (*dkgp
));
5542 dkgp
->dkg_ncyl
= cl
->cl_blockcount
/
5543 (dkgp
->dkg_nhead
* dkgp
->dkg_nsect
);
5545 bzero(dkgp
, sizeof (struct dk_geom
));
5547 * This disk does not have a Solaris VTOC
5548 * so we must present a physical geometry
5549 * that will remain consistent regardless
5550 * of how the disk is used. This will ensure
5551 * that the geometry does not change regardless
5552 * of the fdisk partition type (ie. EFI, FAT32,
5556 dkgp
->dkg_nhead
= cl
->cl_pgeom
.g_nhead
;
5557 dkgp
->dkg_nsect
= cl
->cl_pgeom
.g_nsect
;
5558 dkgp
->dkg_ncyl
= cl
->cl_pgeom
.g_ncyl
;
5559 dkgp
->dkg_acyl
= cl
->cl_pgeom
.g_acyl
;
5562 * Invalid cl_blockcount can generate invalid
5563 * dk_geom and may result in division by zero
5564 * system failure. Should make sure blockcount
5565 * is valid before using it here.
5567 if (cl
->cl_blockcount
== 0) {
5568 mutex_exit(CMLB_MUTEX(cl
));
5573 * Refer to comments related to off-by-1 at the
5574 * header of this file
5576 if (cl
->cl_alter_behavior
& CMLB_OFF_BY_ONE
)
5577 capacity
= cl
->cl_blockcount
- 1;
5579 capacity
= cl
->cl_blockcount
;
5581 cmlb_convert_geometry(cl
, capacity
, dkgp
, tg_cookie
);
5583 dkgp
->dkg_ncyl
= capacity
/
5584 (dkgp
->dkg_nhead
* dkgp
->dkg_nsect
);
5587 dkgp
->dkg_pcyl
= dkgp
->dkg_ncyl
+ dkgp
->dkg_acyl
;
5589 mutex_exit(CMLB_MUTEX(cl
));
5590 if (ddi_copyout(dkgp
, (void *)arg
, sizeof (struct dk_geom
), flag
))
5597 #if defined(__i386) || defined(__amd64)
5599 cmlb_dkio_partinfo(struct cmlb_lun
*cl
, dev_t dev
, caddr_t arg
, int flag
)
5604 * Return parameters describing the selected disk slice.
5605 * Note: this ioctl is for the intel platform only
5609 if (cl
->cl_alter_behavior
& CMLB_CREATE_P0_MINOR_NODE
)
5610 part
= getminor(dev
) & ((1 << CMLBUNIT_FORCE_P0_SHIFT
) - 1);
5612 part
= CMLBPART(dev
);
5614 mutex_enter(CMLB_MUTEX(cl
));
5615 /* don't check cl_solaris_size for pN */
5616 if (part
< P0_RAW_DISK
&& cl
->cl_solaris_size
== 0) {
5618 mutex_exit(CMLB_MUTEX(cl
));
5622 p
.p_start
= (daddr_t
)cl
->cl_offset
[part
];
5623 p
.p_length
= (int)cl
->cl_map
[part
].dkl_nblk
;
5624 mutex_exit(CMLB_MUTEX(cl
));
5625 #ifdef _MULTI_DATAMODEL
5626 switch (ddi_model_convert_from(flag
& FMODELS
)) {
5627 case DDI_MODEL_ILP32
:
5629 struct part_info32 p32
;
5631 p32
.p_start
= (daddr32_t
)p
.p_start
;
5632 p32
.p_length
= p
.p_length
;
5633 if (ddi_copyout(&p32
, (void *)arg
,
5634 sizeof (p32
), flag
))
5639 case DDI_MODEL_NONE
:
5641 if (ddi_copyout(&p
, (void *)arg
, sizeof (p
),
5647 #else /* ! _MULTI_DATAMODEL */
5648 if (ddi_copyout(&p
, (void *)arg
, sizeof (p
), flag
))
5650 #endif /* _MULTI_DATAMODEL */
5655 cmlb_dkio_extpartinfo(struct cmlb_lun
*cl
, dev_t dev
, caddr_t arg
, int flag
)
5660 * Return parameters describing the selected disk slice.
5661 * Note: this ioctl is for the intel platform only
5665 if (cl
->cl_alter_behavior
& CMLB_CREATE_P0_MINOR_NODE
)
5666 part
= getminor(dev
) & ((1 << CMLBUNIT_FORCE_P0_SHIFT
) - 1);
5668 part
= CMLBPART(dev
);
5670 mutex_enter(CMLB_MUTEX(cl
));
5671 /* don't check cl_solaris_size for pN */
5672 if (part
< P0_RAW_DISK
&& cl
->cl_solaris_size
== 0) {
5674 mutex_exit(CMLB_MUTEX(cl
));
5676 struct extpart_info p
;
5678 p
.p_start
= (diskaddr_t
)cl
->cl_offset
[part
];
5679 p
.p_length
= (diskaddr_t
)cl
->cl_map
[part
].dkl_nblk
;
5680 mutex_exit(CMLB_MUTEX(cl
));
5681 if (ddi_copyout(&p
, (void *)arg
, sizeof (p
), flag
))
5689 cmlb_prop_op(cmlb_handle_t cmlbhandle
,
5690 dev_t dev
, dev_info_t
*dip
, ddi_prop_op_t prop_op
, int mod_flags
,
5691 char *name
, caddr_t valuep
, int *lengthp
, int part
, void *tg_cookie
)
5693 struct cmlb_lun
*cl
;
5694 diskaddr_t capacity
;
5696 enum dp
{ DP_NBLOCKS
, DP_BLKSIZE
, DP_SSD
, DP_ROT
} dp
;
5701 tg_attribute_t tgattr
;
5703 /* Always fallback to ddi_prop_op... */
5704 cl
= (struct cmlb_lun
*)cmlbhandle
;
5706 fallback
: return (ddi_prop_op(dev
, dip
, prop_op
, mod_flags
,
5707 name
, valuep
, lengthp
));
5710 /* Pick up capacity and blocksize information. */
5711 capacity
= cl
->cl_blockcount
;
5714 lbasize
= cl
->cl_tgt_blocksize
;
5716 lbasize
= DEV_BSIZE
; /* 0 -> DEV_BSIZE units */
5718 /* Check for dynamic property of whole device. */
5719 if (dev
== DDI_DEV_T_ANY
) {
5720 /* Fallback to ddi_prop_op if we don't understand. */
5721 if (strcmp(name
, "device-nblocks") == 0)
5723 else if (strcmp(name
, "device-blksize") == 0)
5725 else if (strcmp(name
, "device-solid-state") == 0)
5727 else if (strcmp(name
, "device-rotational") == 0)
5732 /* get callers length, establish length of our dynamic prop */
5733 callers_length
= *lengthp
;
5734 if (dp
== DP_NBLOCKS
)
5735 *lengthp
= sizeof (uint64_t);
5736 else if ((dp
== DP_BLKSIZE
) || (dp
== DP_SSD
))
5737 *lengthp
= sizeof (uint32_t);
5739 /* service request for the length of the property */
5740 if (prop_op
== PROP_LEN
)
5741 return (DDI_PROP_SUCCESS
);
5744 case PROP_LEN_AND_VAL_ALLOC
:
5745 if ((buffer
= kmem_alloc(*lengthp
,
5746 (mod_flags
& DDI_PROP_CANSLEEP
) ?
5747 KM_SLEEP
: KM_NOSLEEP
)) == NULL
)
5748 return (DDI_PROP_NO_MEMORY
);
5749 *(caddr_t
*)valuep
= buffer
; /* set callers buf */
5752 case PROP_LEN_AND_VAL_BUF
:
5753 /* the length of the prop and the request must match */
5754 if (callers_length
!= *lengthp
)
5755 return (DDI_PROP_INVAL_ARG
);
5756 buffer
= valuep
; /* get callers buf */
5760 return (DDI_PROP_INVAL_ARG
);
5763 /* transfer the value into the buffer */
5766 *((uint64_t *)buffer
) = capacity
;
5769 *((uint32_t *)buffer
) = lbasize
;
5772 if (DK_TG_GETATTRIBUTE(cl
, &tgattr
, tg_cookie
) != 0)
5773 tgattr
.media_is_solid_state
= B_FALSE
;
5774 *((uint32_t *)buffer
) =
5775 tgattr
.media_is_solid_state
? 1 : 0;
5778 if (DK_TG_GETATTRIBUTE(cl
, &tgattr
, tg_cookie
) != 0)
5779 tgattr
.media_is_rotational
= B_TRUE
;
5780 *((uint32_t *)buffer
) =
5781 tgattr
.media_is_rotational
? 1 : 0;
5784 return (DDI_PROP_SUCCESS
);
5788 * Support dynamic size oriented properties of partition. Requests
5789 * issued under conditions where size is valid are passed to
5790 * ddi_prop_op_nblocks with the size information, otherwise the
5791 * request is passed to ddi_prop_op. Size depends on valid geometry.
5793 if (!cmlb_is_valid(cmlbhandle
))
5796 /* Get partition nblocks value. */
5797 (void) cmlb_partinfo(cmlbhandle
, part
,
5798 (diskaddr_t
*)&nblocks64
, NULL
, NULL
, NULL
, tg_cookie
);
5801 * Assume partition information is in sys_blocksize units, compute
5802 * divisor for size(9P) property representation.
5804 dblk
= lbasize
/ cl
->cl_sys_blocksize
;
5806 /* Now let ddi_prop_op_nblocks_blksize() handle the request. */
5807 return (ddi_prop_op_nblocks_blksize(dev
, dip
, prop_op
, mod_flags
,
5808 name
, valuep
, lengthp
, nblocks64
/ dblk
, lbasize
));