1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
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 */
27
28 /*
29 * This module provides support for labeling operations for target
30 * drivers.
31 */
32
33 #include <sys/scsi/scsi.h>
34 #include <sys/sunddi.h>
35 #include <sys/dklabel.h>
36 #include <sys/dkio.h>
37 #include <sys/vtoc.h>
38 #include <sys/dktp/fdisk.h>
39 #include <sys/vtrace.h>
40 #include <sys/efi_partition.h>
41 #include <sys/cmlb.h>
42 #include <sys/cmlb_impl.h>
43 #if defined(__i386) || defined(__amd64)
44 #include <sys/fs/dv_node.h>
45 #endif
46 #include <sys/ddi_impldefs.h>
47
48 /*
49 * Driver minor node structure and data table
50 */
51 struct driver_minor_data {
52 char *name;
53 minor_t minor;
54 int type;
55 };
56
57 static struct driver_minor_data dk_minor_data[] = {
58 {"a", 0, S_IFBLK},
59 {"b", 1, S_IFBLK},
60 {"c", 2, S_IFBLK},
61 {"d", 3, S_IFBLK},
62 {"e", 4, S_IFBLK},
63 {"f", 5, S_IFBLK},
64 {"g", 6, S_IFBLK},
65 {"h", 7, S_IFBLK},
66 #if defined(_SUNOS_VTOC_16)
67 {"i", 8, S_IFBLK},
68 {"j", 9, S_IFBLK},
69 {"k", 10, S_IFBLK},
70 {"l", 11, S_IFBLK},
71 {"m", 12, S_IFBLK},
72 {"n", 13, S_IFBLK},
73 {"o", 14, S_IFBLK},
74 {"p", 15, S_IFBLK},
75 #endif /* defined(_SUNOS_VTOC_16) */
76 #if defined(_FIRMWARE_NEEDS_FDISK)
77 {"q", 16, S_IFBLK},
78 {"r", 17, S_IFBLK},
79 {"s", 18, S_IFBLK},
80 {"t", 19, S_IFBLK},
81 {"u", 20, S_IFBLK},
82 #endif /* defined(_FIRMWARE_NEEDS_FDISK) */
83 {"a,raw", 0, S_IFCHR},
84 {"b,raw", 1, S_IFCHR},
85 {"c,raw", 2, S_IFCHR},
86 {"d,raw", 3, S_IFCHR},
87 {"e,raw", 4, S_IFCHR},
88 {"f,raw", 5, S_IFCHR},
89 {"g,raw", 6, S_IFCHR},
90 {"h,raw", 7, S_IFCHR},
91 #if defined(_SUNOS_VTOC_16)
92 {"i,raw", 8, S_IFCHR},
93 {"j,raw", 9, S_IFCHR},
94 {"k,raw", 10, S_IFCHR},
95 {"l,raw", 11, S_IFCHR},
96 {"m,raw", 12, S_IFCHR},
97 {"n,raw", 13, S_IFCHR},
98 {"o,raw", 14, S_IFCHR},
99 {"p,raw", 15, S_IFCHR},
100 #endif /* defined(_SUNOS_VTOC_16) */
101 #if defined(_FIRMWARE_NEEDS_FDISK)
102 {"q,raw", 16, S_IFCHR},
103 {"r,raw", 17, S_IFCHR},
104 {"s,raw", 18, S_IFCHR},
105 {"t,raw", 19, S_IFCHR},
106 {"u,raw", 20, S_IFCHR},
107 #endif /* defined(_FIRMWARE_NEEDS_FDISK) */
108 {0}
109 };
110
111 #if defined(__i386) || defined(__amd64)
112 #if defined(_FIRMWARE_NEEDS_FDISK)
113 static struct driver_minor_data dk_ext_minor_data[] = {
114 {"p5", 21, S_IFBLK},
115 {"p6", 22, S_IFBLK},
116 {"p7", 23, S_IFBLK},
117 {"p8", 24, S_IFBLK},
118 {"p9", 25, S_IFBLK},
119 {"p10", 26, S_IFBLK},
120 {"p11", 27, S_IFBLK},
121 {"p12", 28, S_IFBLK},
122 {"p13", 29, S_IFBLK},
123 {"p14", 30, S_IFBLK},
124 {"p15", 31, S_IFBLK},
125 {"p16", 32, S_IFBLK},
126 {"p17", 33, S_IFBLK},
127 {"p18", 34, S_IFBLK},
128 {"p19", 35, S_IFBLK},
129 {"p20", 36, S_IFBLK},
130 {"p21", 37, S_IFBLK},
131 {"p22", 38, S_IFBLK},
132 {"p23", 39, S_IFBLK},
133 {"p24", 40, S_IFBLK},
134 {"p25", 41, S_IFBLK},
135 {"p26", 42, S_IFBLK},
136 {"p27", 43, S_IFBLK},
137 {"p28", 44, S_IFBLK},
138 {"p29", 45, S_IFBLK},
139 {"p30", 46, S_IFBLK},
140 {"p31", 47, S_IFBLK},
141 {"p32", 48, S_IFBLK},
142 {"p33", 49, S_IFBLK},
143 {"p34", 50, S_IFBLK},
144 {"p35", 51, S_IFBLK},
145 {"p36", 52, S_IFBLK},
146 {"p5,raw", 21, S_IFCHR},
147 {"p6,raw", 22, S_IFCHR},
148 {"p7,raw", 23, S_IFCHR},
149 {"p8,raw", 24, S_IFCHR},
150 {"p9,raw", 25, S_IFCHR},
151 {"p10,raw", 26, S_IFCHR},
152 {"p11,raw", 27, S_IFCHR},
153 {"p12,raw", 28, S_IFCHR},
154 {"p13,raw", 29, S_IFCHR},
155 {"p14,raw", 30, S_IFCHR},
156 {"p15,raw", 31, S_IFCHR},
157 {"p16,raw", 32, S_IFCHR},
158 {"p17,raw", 33, S_IFCHR},
159 {"p18,raw", 34, S_IFCHR},
160 {"p19,raw", 35, S_IFCHR},
161 {"p20,raw", 36, S_IFCHR},
162 {"p21,raw", 37, S_IFCHR},
163 {"p22,raw", 38, S_IFCHR},
164 {"p23,raw", 39, S_IFCHR},
165 {"p24,raw", 40, S_IFCHR},
166 {"p25,raw", 41, S_IFCHR},
167 {"p26,raw", 42, S_IFCHR},
168 {"p27,raw", 43, S_IFCHR},
169 {"p28,raw", 44, S_IFCHR},
170 {"p29,raw", 45, S_IFCHR},
171 {"p30,raw", 46, S_IFCHR},
172 {"p31,raw", 47, S_IFCHR},
173 {"p32,raw", 48, S_IFCHR},
174 {"p33,raw", 49, S_IFCHR},
175 {"p34,raw", 50, S_IFCHR},
176 {"p35,raw", 51, S_IFCHR},
177 {"p36,raw", 52, S_IFCHR},
178 {0}
179 };
180 #endif /* defined(_FIRMWARE_NEEDS_FDISK) */
181 #endif /* if defined(__i386) || defined(__amd64) */
182
183 static struct driver_minor_data dk_minor_data_efi[] = {
184 {"a", 0, S_IFBLK},
185 {"b", 1, S_IFBLK},
186 {"c", 2, S_IFBLK},
187 {"d", 3, S_IFBLK},
188 {"e", 4, S_IFBLK},
189 {"f", 5, S_IFBLK},
190 {"g", 6, S_IFBLK},
191 {"wd", 7, S_IFBLK},
192 #if defined(_SUNOS_VTOC_16)
193 {"i", 8, S_IFBLK},
194 {"j", 9, S_IFBLK},
195 {"k", 10, S_IFBLK},
196 {"l", 11, S_IFBLK},
197 {"m", 12, S_IFBLK},
198 {"n", 13, S_IFBLK},
199 {"o", 14, S_IFBLK},
200 {"p", 15, S_IFBLK},
201 #endif /* defined(_SUNOS_VTOC_16) */
202 #if defined(_FIRMWARE_NEEDS_FDISK)
203 {"q", 16, S_IFBLK},
204 {"r", 17, S_IFBLK},
205 {"s", 18, S_IFBLK},
206 {"t", 19, S_IFBLK},
207 {"u", 20, S_IFBLK},
208 #endif /* defined(_FIRMWARE_NEEDS_FDISK) */
209 {"a,raw", 0, S_IFCHR},
210 {"b,raw", 1, S_IFCHR},
211 {"c,raw", 2, S_IFCHR},
212 {"d,raw", 3, S_IFCHR},
213 {"e,raw", 4, S_IFCHR},
214 {"f,raw", 5, S_IFCHR},
215 {"g,raw", 6, S_IFCHR},
216 {"wd,raw", 7, S_IFCHR},
217 #if defined(_SUNOS_VTOC_16)
218 {"i,raw", 8, S_IFCHR},
219 {"j,raw", 9, S_IFCHR},
220 {"k,raw", 10, S_IFCHR},
221 {"l,raw", 11, S_IFCHR},
222 {"m,raw", 12, S_IFCHR},
223 {"n,raw", 13, S_IFCHR},
224 {"o,raw", 14, S_IFCHR},
225 {"p,raw", 15, S_IFCHR},
226 #endif /* defined(_SUNOS_VTOC_16) */
227 #if defined(_FIRMWARE_NEEDS_FDISK)
228 {"q,raw", 16, S_IFCHR},
229 {"r,raw", 17, S_IFCHR},
230 {"s,raw", 18, S_IFCHR},
231 {"t,raw", 19, S_IFCHR},
232 {"u,raw", 20, S_IFCHR},
233 #endif /* defined(_FIRMWARE_NEEDS_FDISK) */
234 {0}
235 };
236
237 /*
238 * Declare the dynamic properties implemented in prop_op(9E) implementation
239 * that we want to have show up in a di_init(3DEVINFO) device tree snapshot
240 * of drivers that call cmlb_attach().
241 */
242 static i_ddi_prop_dyn_t cmlb_prop_dyn[] = {
243 {"Nblocks", DDI_PROP_TYPE_INT64, S_IFBLK},
244 {"Size", DDI_PROP_TYPE_INT64, S_IFCHR},
245 {"device-nblocks", DDI_PROP_TYPE_INT64},
246 {"device-blksize", DDI_PROP_TYPE_INT},
247 {"device-solid-state", DDI_PROP_TYPE_INT},
248 {"device-rotational", DDI_PROP_TYPE_INT},
249 {NULL}
250 };
251
252 /*
253 * This implies an upper limit of 8192 GPT partitions
254 * in one transfer for GUID Partition Entry Array.
255 */
256 len_t cmlb_tg_max_efi_xfer = 1024 * 1024;
257
258 /*
259 * External kernel interfaces
260 */
261 extern struct mod_ops mod_miscops;
262
263 extern int ddi_create_internal_pathname(dev_info_t *dip, char *name,
264 int spec_type, minor_t minor_num);
265
266 /*
267 * Global buffer and mutex for debug logging
268 */
269 static char cmlb_log_buffer[1024];
270 static kmutex_t cmlb_log_mutex;
271
272
273 struct cmlb_lun *cmlb_debug_cl = NULL;
274 uint_t cmlb_level_mask = 0x0;
275
276 int cmlb_rot_delay = 4; /* default rotational delay */
277
278 static struct modlmisc modlmisc = {
279 &mod_miscops, /* Type of module */
280 "Common Labeling module"
281 };
282
283 static struct modlinkage modlinkage = {
284 MODREV_1, (void *)&modlmisc, NULL
285 };
286
287 /* Local function prototypes */
288 static dev_t cmlb_make_device(struct cmlb_lun *cl);
289 static int cmlb_validate_geometry(struct cmlb_lun *cl, boolean_t forcerevalid,
290 int flags, void *tg_cookie);
291 static void cmlb_resync_geom_caches(struct cmlb_lun *cl, diskaddr_t capacity,
292 void *tg_cookie);
293 static int cmlb_read_fdisk(struct cmlb_lun *cl, diskaddr_t capacity,
294 void *tg_cookie);
295 static void cmlb_swap_efi_gpt(efi_gpt_t *e);
296 static void cmlb_swap_efi_gpe(int nparts, efi_gpe_t *p);
297 static int cmlb_validate_efi(efi_gpt_t *labp);
298 static int cmlb_use_efi(struct cmlb_lun *cl, diskaddr_t capacity, int flags,
299 void *tg_cookie);
300 static void cmlb_build_default_label(struct cmlb_lun *cl, void *tg_cookie);
301 static int cmlb_uselabel(struct cmlb_lun *cl, struct dk_label *l, int flags);
302 #if defined(_SUNOS_VTOC_8)
303 static void cmlb_build_user_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc);
304 #endif
305 static int cmlb_build_label_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc);
306 static int cmlb_write_label(struct cmlb_lun *cl, void *tg_cookie);
307 static int cmlb_set_vtoc(struct cmlb_lun *cl, struct dk_label *dkl,
308 void *tg_cookie);
309 static void cmlb_clear_efi(struct cmlb_lun *cl, void *tg_cookie);
310 static void cmlb_clear_vtoc(struct cmlb_lun *cl, void *tg_cookie);
311 static void cmlb_setup_default_geometry(struct cmlb_lun *cl, void *tg_cookie);
312 static int cmlb_create_minor_nodes(struct cmlb_lun *cl);
313 static int cmlb_check_update_blockcount(struct cmlb_lun *cl, void *tg_cookie);
314 static boolean_t cmlb_check_efi_mbr(uchar_t *buf, boolean_t *is_mbr);
315
316 #if defined(__i386) || defined(__amd64)
317 static int cmlb_update_fdisk_and_vtoc(struct cmlb_lun *cl, void *tg_cookie);
318 #endif
319
320 #if defined(_FIRMWARE_NEEDS_FDISK)
321 static boolean_t cmlb_has_max_chs_vals(struct ipart *fdp);
322 #endif
323
324 #if defined(_SUNOS_VTOC_16)
325 static void cmlb_convert_geometry(struct cmlb_lun *cl, diskaddr_t capacity,
326 struct dk_geom *cl_g, void *tg_cookie);
327 #endif
328
329 static int cmlb_dkio_get_geometry(struct cmlb_lun *cl, caddr_t arg, int flag,
330 void *tg_cookie);
331 static int cmlb_dkio_set_geometry(struct cmlb_lun *cl, caddr_t arg, int flag);
332 static int cmlb_dkio_get_partition(struct cmlb_lun *cl, caddr_t arg, int flag,
333 void *tg_cookie);
334 static int cmlb_dkio_set_partition(struct cmlb_lun *cl, caddr_t arg, int flag);
335 static int cmlb_dkio_get_efi(struct cmlb_lun *cl, caddr_t arg, int flag,
336 void *tg_cookie);
337 static int cmlb_dkio_set_efi(struct cmlb_lun *cl, dev_t dev, caddr_t arg,
338 int flag, void *tg_cookie);
339 static int cmlb_dkio_get_vtoc(struct cmlb_lun *cl, caddr_t arg, int flag,
340 void *tg_cookie);
341 static int cmlb_dkio_get_extvtoc(struct cmlb_lun *cl, caddr_t arg, int flag,
342 void *tg_cookie);
343 static int cmlb_dkio_set_vtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg,
344 int flag, void *tg_cookie);
345 static int cmlb_dkio_set_extvtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg,
346 int flag, void *tg_cookie);
347 static int cmlb_dkio_get_mboot(struct cmlb_lun *cl, caddr_t arg, int flag,
348 void *tg_cookie);
349 static int cmlb_dkio_set_mboot(struct cmlb_lun *cl, caddr_t arg, int flag,
350 void *tg_cookie);
351 static int cmlb_dkio_partition(struct cmlb_lun *cl, caddr_t arg, int flag,
352 void *tg_cookie);
353
354 #if defined(__i386) || defined(__amd64)
355 static int cmlb_dkio_set_ext_part(struct cmlb_lun *cl, caddr_t arg, int flag,
356 void *tg_cookie);
357 static int cmlb_validate_ext_part(struct cmlb_lun *cl, int part, int epart,
358 uint32_t start, uint32_t size);
359 static int cmlb_is_linux_swap(struct cmlb_lun *cl, uint32_t part_start,
360 void *tg_cookie);
361 static int cmlb_dkio_get_virtgeom(struct cmlb_lun *cl, caddr_t arg, int flag);
362 static int cmlb_dkio_get_phygeom(struct cmlb_lun *cl, caddr_t arg, int flag,
363 void *tg_cookie);
364 static int cmlb_dkio_partinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg,
365 int flag);
366 static int cmlb_dkio_extpartinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg,
367 int flag);
368 #endif
369
370 static void cmlb_dbg(uint_t comp, struct cmlb_lun *cl, const char *fmt, ...);
371 static void cmlb_v_log(dev_info_t *dev, const char *label, uint_t level,
372 const char *fmt, va_list ap);
373 static void cmlb_log(dev_info_t *dev, const char *label, uint_t level,
374 const char *fmt, ...);
375
376 int
_init(void)377 _init(void)
378 {
379 mutex_init(&cmlb_log_mutex, NULL, MUTEX_DRIVER, NULL);
380 return (mod_install(&modlinkage));
381 }
382
383 int
_info(struct modinfo * modinfop)384 _info(struct modinfo *modinfop)
385 {
386 return (mod_info(&modlinkage, modinfop));
387 }
388
389 int
_fini(void)390 _fini(void)
391 {
392 int err;
393
394 if ((err = mod_remove(&modlinkage)) != 0) {
395 return (err);
396 }
397
398 mutex_destroy(&cmlb_log_mutex);
399 return (err);
400 }
401
402 /*
403 * cmlb_dbg is used for debugging to log additional info
404 * Level of output is controlled via cmlb_level_mask setting.
405 */
406 static void
cmlb_dbg(uint_t comp,struct cmlb_lun * cl,const char * fmt,...)407 cmlb_dbg(uint_t comp, struct cmlb_lun *cl, const char *fmt, ...)
408 {
409 va_list ap;
410 dev_info_t *dev;
411 uint_t level_mask = 0;
412
413 ASSERT(cl != NULL);
414 dev = CMLB_DEVINFO(cl);
415 ASSERT(dev != NULL);
416 /*
417 * Filter messages based on the global component and level masks,
418 * also print if cl matches the value of cmlb_debug_cl, or if
419 * cmlb_debug_cl is set to NULL.
420 */
421 if (comp & CMLB_TRACE)
422 level_mask |= CMLB_LOGMASK_TRACE;
423
424 if (comp & CMLB_INFO)
425 level_mask |= CMLB_LOGMASK_INFO;
426
427 if (comp & CMLB_ERROR)
428 level_mask |= CMLB_LOGMASK_ERROR;
429
430 if ((cmlb_level_mask & level_mask) &&
431 ((cmlb_debug_cl == NULL) || (cmlb_debug_cl == cl))) {
432 va_start(ap, fmt);
433 cmlb_v_log(dev, CMLB_LABEL(cl), CE_CONT, fmt, ap);
434 va_end(ap);
435 }
436 }
437
438 /*
439 * cmlb_log is basically a duplicate of scsi_log. It is redefined here
440 * so that this module does not depend on scsi module.
441 */
442 static void
cmlb_log(dev_info_t * dev,const char * label,uint_t level,const char * fmt,...)443 cmlb_log(dev_info_t *dev, const char *label, uint_t level, const char *fmt, ...)
444 {
445 va_list ap;
446
447 va_start(ap, fmt);
448 cmlb_v_log(dev, label, level, fmt, ap);
449 va_end(ap);
450 }
451
452 static void
cmlb_v_log(dev_info_t * dev,const char * label,uint_t level,const char * fmt,va_list ap)453 cmlb_v_log(dev_info_t *dev, const char *label, uint_t level, const char *fmt,
454 va_list ap)
455 {
456 static char name[256];
457 int log_only = 0;
458 int boot_only = 0;
459 int console_only = 0;
460
461 mutex_enter(&cmlb_log_mutex);
462
463 if (dev) {
464 if (level == CE_PANIC || level == CE_WARN ||
465 level == CE_NOTE) {
466 (void) sprintf(name, "%s (%s%d):\n",
467 ddi_pathname(dev, cmlb_log_buffer),
468 label, ddi_get_instance(dev));
469 } else {
470 name[0] = '\0';
471 }
472 } else {
473 (void) sprintf(name, "%s:", label);
474 }
475
476 (void) vsprintf(cmlb_log_buffer, fmt, ap);
477
478 switch (cmlb_log_buffer[0]) {
479 case '!':
480 log_only = 1;
481 break;
482 case '?':
483 boot_only = 1;
484 break;
485 case '^':
486 console_only = 1;
487 break;
488 }
489
490 switch (level) {
491 case CE_NOTE:
492 level = CE_CONT;
493 /* FALLTHROUGH */
494 case CE_CONT:
495 case CE_WARN:
496 case CE_PANIC:
497 if (boot_only) {
498 cmn_err(level, "?%s\t%s", name, &cmlb_log_buffer[1]);
499 } else if (console_only) {
500 cmn_err(level, "^%s\t%s", name, &cmlb_log_buffer[1]);
501 } else if (log_only) {
502 cmn_err(level, "!%s\t%s", name, &cmlb_log_buffer[1]);
503 } else {
504 cmn_err(level, "%s\t%s", name, cmlb_log_buffer);
505 }
506 break;
507 case CE_IGNORE:
508 break;
509 default:
510 cmn_err(CE_CONT, "^DEBUG: %s\t%s", name, cmlb_log_buffer);
511 break;
512 }
513 mutex_exit(&cmlb_log_mutex);
514 }
515
516
517 /*
518 * cmlb_alloc_handle:
519 *
520 * Allocates a handle.
521 *
522 * Arguments:
523 * cmlbhandlep pointer to handle
524 *
525 * Notes:
526 * Allocates a handle and stores the allocated handle in the area
527 * pointed to by cmlbhandlep
528 *
529 * Context:
530 * Kernel thread only (can sleep).
531 */
532 void
cmlb_alloc_handle(cmlb_handle_t * cmlbhandlep)533 cmlb_alloc_handle(cmlb_handle_t *cmlbhandlep)
534 {
535 struct cmlb_lun *cl;
536
537 cl = kmem_zalloc(sizeof (struct cmlb_lun), KM_SLEEP);
538 ASSERT(cmlbhandlep != NULL);
539
540 cl->cl_state = CMLB_INITED;
541 cl->cl_def_labeltype = CMLB_LABEL_UNDEF;
542 mutex_init(CMLB_MUTEX(cl), NULL, MUTEX_DRIVER, NULL);
543
544 *cmlbhandlep = (cmlb_handle_t)(cl);
545 }
546
547 /*
548 * cmlb_free_handle
549 *
550 * Frees handle.
551 *
552 * Arguments:
553 * cmlbhandlep pointer to handle
554 */
555 void
cmlb_free_handle(cmlb_handle_t * cmlbhandlep)556 cmlb_free_handle(cmlb_handle_t *cmlbhandlep)
557 {
558 struct cmlb_lun *cl;
559
560 cl = (struct cmlb_lun *)*cmlbhandlep;
561 if (cl != NULL) {
562 mutex_destroy(CMLB_MUTEX(cl));
563 kmem_free(cl, sizeof (struct cmlb_lun));
564 }
565
566 }
567
568 /*
569 * cmlb_attach:
570 *
571 * Attach handle to device, create minor nodes for device.
572 *
573 * Arguments:
574 * devi pointer to device's dev_info structure.
575 * tgopsp pointer to array of functions cmlb can use to callback
576 * to target driver.
577 *
578 * device_type Peripheral device type as defined in
579 * scsi/generic/inquiry.h
580 *
581 * is_removable whether or not device is removable.
582 *
583 * is_hotpluggable whether or not device is hotpluggable.
584 *
585 * node_type minor node type (as used by ddi_create_minor_node)
586 *
587 * alter_behavior
588 * bit flags:
589 *
590 * CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT: create
591 * an alternate slice for the default label, if
592 * device type is DTYPE_DIRECT an architectures default
593 * label type is VTOC16.
594 * Otherwise alternate slice will no be created.
595 *
596 *
597 * CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8: report a default
598 * geometry and label for DKIOCGGEOM and DKIOCGVTOC
599 * on architecture with VTOC8 label types.
600 *
601 * CMLB_OFF_BY_ONE: do the workaround for legacy off-by-
602 * one bug in obtaining capacity (in sd):
603 * SCSI READ_CAPACITY command returns the LBA number of the
604 * last logical block, but sd once treated this number as
605 * disks' capacity on x86 platform. And LBAs are addressed
606 * based 0. So the last block was lost on x86 platform.
607 *
608 * Now, we remove this workaround. In order for present sd
609 * driver to work with disks which are labeled/partitioned
610 * via previous sd, we add workaround as follows:
611 *
612 * 1) Locate backup EFI label: cmlb searches the next to
613 * last
614 * block for backup EFI label. If fails, it will
615 * turn to the last block for backup EFI label;
616 *
617 * 2) Clear backup EFI label: cmlb first search the last
618 * block for backup EFI label, and will search the
619 * next to last block only if failed for the last
620 * block.
621 *
622 * 3) Calculate geometry:refer to cmlb_convert_geometry()
623 * If capacity increasing by 1 causes disks' capacity
624 * to cross over the limits in geometry calculation,
625 * geometry info will change. This will raise an issue:
626 * In case that primary VTOC label is destroyed, format
627 * commandline can restore it via backup VTOC labels.
628 * And format locates backup VTOC labels by use of
629 * geometry. So changing geometry will
630 * prevent format from finding backup VTOC labels. To
631 * eliminate this side effect for compatibility,
632 * sd uses (capacity -1) to calculate geometry;
633 *
634 * 4) 1TB disks: some important data structures use
635 * 32-bit signed long/int (for example, daddr_t),
636 * so that sd doesn't support a disk with capacity
637 * larger than 1TB on 32-bit platform. However,
638 * for exactly 1TB disk, it was treated as (1T - 512)B
639 * in the past, and could have valid Solaris
640 * partitions. To workaround this, if an exactly 1TB
641 * disk has Solaris fdisk partition, it will be allowed
642 * to work with sd.
643 *
644 *
645 *
646 * CMLB_FAKE_LABEL_ONE_PARTITION: create s0 and s2 covering
647 * the entire disk, if there is no valid partition info.
648 * If there is a valid Solaris partition, s0 and s2 will
649 * only cover the entire Solaris partition.
650 *
651 *
652 * cmlbhandle cmlb handle associated with device
653 *
654 * tg_cookie cookie from target driver to be passed back to target
655 * driver when we call back to it through tg_ops.
656 *
657 * Notes:
658 * Assumes a default label based on capacity for non-removable devices.
659 * If capacity > 1TB, EFI is assumed otherwise VTOC (default VTOC
660 * for the architecture).
661 *
662 * For removable devices, default label type is assumed to be VTOC
663 * type. Create minor nodes based on a default label type.
664 * Label on the media is not validated.
665 * minor number consists of:
666 * if _SUNOS_VTOC_8 is defined
667 * lowest 3 bits is taken as partition number
668 * the rest is instance number
669 * if _SUNOS_VTOC_16 is defined
670 * lowest 6 bits is taken as partition number
671 * the rest is instance number
672 *
673 *
674 * Return values:
675 * 0 Success
676 * ENXIO creating minor nodes failed.
677 * EINVAL invalid arg, unsupported tg_ops version
678 */
679 int
cmlb_attach(dev_info_t * devi,cmlb_tg_ops_t * tgopsp,int device_type,boolean_t is_removable,boolean_t is_hotpluggable,char * node_type,int alter_behavior,cmlb_handle_t cmlbhandle,void * tg_cookie)680 cmlb_attach(dev_info_t *devi, cmlb_tg_ops_t *tgopsp, int device_type,
681 boolean_t is_removable, boolean_t is_hotpluggable, char *node_type,
682 int alter_behavior, cmlb_handle_t cmlbhandle, void *tg_cookie)
683 {
684
685 struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle;
686 diskaddr_t cap;
687 int status;
688
689 ASSERT(VALID_BOOLEAN(is_removable));
690 ASSERT(VALID_BOOLEAN(is_hotpluggable));
691
692 if (tgopsp->tg_version < TG_DK_OPS_VERSION_1)
693 return (EINVAL);
694
695 mutex_enter(CMLB_MUTEX(cl));
696
697 CMLB_DEVINFO(cl) = devi;
698 cl->cmlb_tg_ops = tgopsp;
699 cl->cl_device_type = device_type;
700 cl->cl_is_removable = is_removable;
701 cl->cl_is_hotpluggable = is_hotpluggable;
702 cl->cl_node_type = node_type;
703 cl->cl_sys_blocksize = DEV_BSIZE;
704 cl->cl_f_geometry_is_valid = B_FALSE;
705 cl->cl_def_labeltype = CMLB_LABEL_VTOC;
706 cl->cl_alter_behavior = alter_behavior;
707 cl->cl_reserved = -1;
708 cl->cl_msglog_flag |= CMLB_ALLOW_2TB_WARN;
709 #if defined(__i386) || defined(__amd64)
710 cl->cl_logical_drive_count = 0;
711 #endif
712
713 if (!is_removable) {
714 mutex_exit(CMLB_MUTEX(cl));
715 status = DK_TG_GETCAP(cl, &cap, tg_cookie);
716 mutex_enter(CMLB_MUTEX(cl));
717 if (status == 0 && cap > CMLB_EXTVTOC_LIMIT) {
718 /* set default EFI if > 2TB */
719 cl->cl_def_labeltype = CMLB_LABEL_EFI;
720 }
721 }
722
723 /* create minor nodes based on default label type */
724 cl->cl_last_labeltype = CMLB_LABEL_UNDEF;
725 cl->cl_cur_labeltype = CMLB_LABEL_UNDEF;
726
727 if (cmlb_create_minor_nodes(cl) != 0) {
728 mutex_exit(CMLB_MUTEX(cl));
729 return (ENXIO);
730 }
731
732 /* Define the dynamic properties for devinfo spapshots. */
733 i_ddi_prop_dyn_driver_set(CMLB_DEVINFO(cl), cmlb_prop_dyn);
734
735 cl->cl_state = CMLB_ATTACHED;
736
737 mutex_exit(CMLB_MUTEX(cl));
738 return (0);
739 }
740
741 /*
742 * cmlb_detach:
743 *
744 * Invalidate in-core labeling data and remove all minor nodes for
745 * the device associate with handle.
746 *
747 * Arguments:
748 * cmlbhandle cmlb handle associated with device.
749 *
750 * tg_cookie cookie from target driver to be passed back to target
751 * driver when we call back to it through tg_ops.
752 *
753 */
754 /*ARGSUSED1*/
755 void
cmlb_detach(cmlb_handle_t cmlbhandle,void * tg_cookie)756 cmlb_detach(cmlb_handle_t cmlbhandle, void *tg_cookie)
757 {
758 struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle;
759
760 mutex_enter(CMLB_MUTEX(cl));
761 cl->cl_def_labeltype = CMLB_LABEL_UNDEF;
762 cl->cl_f_geometry_is_valid = B_FALSE;
763 ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL);
764 i_ddi_prop_dyn_driver_set(CMLB_DEVINFO(cl), NULL);
765 cl->cl_state = CMLB_INITED;
766 mutex_exit(CMLB_MUTEX(cl));
767 }
768
769 /*
770 * cmlb_validate:
771 *
772 * Validates label.
773 *
774 * Arguments
775 * cmlbhandle cmlb handle associated with device.
776 *
777 * flags operation flags. used for verbosity control
778 *
779 * tg_cookie cookie from target driver to be passed back to target
780 * driver when we call back to it through tg_ops.
781 *
782 *
783 * Notes:
784 * If new label type is different from the current, adjust minor nodes
785 * accordingly.
786 *
787 * Return values:
788 * 0 success
789 * Note: having fdisk but no solaris partition is assumed
790 * success.
791 *
792 * ENOMEM memory allocation failed
793 * EIO i/o errors during read or get capacity
794 * EACCESS reservation conflicts
795 * EINVAL label was corrupt, or no default label was assumed
796 * ENXIO invalid handle
797 */
798 int
cmlb_validate(cmlb_handle_t cmlbhandle,int flags,void * tg_cookie)799 cmlb_validate(cmlb_handle_t cmlbhandle, int flags, void *tg_cookie)
800 {
801 struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle;
802 int rval;
803 int ret = 0;
804
805 /*
806 * Temp work-around checking cl for NULL since there is a bug
807 * in sd_detach calling this routine from taskq_dispatch
808 * inited function.
809 */
810 if (cl == NULL)
811 return (ENXIO);
812
813 mutex_enter(CMLB_MUTEX(cl));
814 if (cl->cl_state < CMLB_ATTACHED) {
815 mutex_exit(CMLB_MUTEX(cl));
816 return (ENXIO);
817 }
818
819 rval = cmlb_validate_geometry((struct cmlb_lun *)cmlbhandle, B_TRUE,
820 flags, tg_cookie);
821
822 if (rval == ENOTSUP) {
823 if (cl->cl_f_geometry_is_valid) {
824 cl->cl_cur_labeltype = CMLB_LABEL_EFI;
825 ret = 0;
826 } else {
827 ret = EINVAL;
828 }
829 } else {
830 ret = rval;
831 if (ret == 0)
832 cl->cl_cur_labeltype = CMLB_LABEL_VTOC;
833 }
834
835 if (ret == 0)
836 (void) cmlb_create_minor_nodes(cl);
837
838 mutex_exit(CMLB_MUTEX(cl));
839 return (ret);
840 }
841
842 /*
843 * cmlb_invalidate:
844 * Invalidate in core label data
845 *
846 * Arguments:
847 * cmlbhandle cmlb handle associated with device.
848 * tg_cookie cookie from target driver to be passed back to target
849 * driver when we call back to it through tg_ops.
850 */
851 /*ARGSUSED1*/
852 void
cmlb_invalidate(cmlb_handle_t cmlbhandle,void * tg_cookie)853 cmlb_invalidate(cmlb_handle_t cmlbhandle, void *tg_cookie)
854 {
855 struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle;
856
857 if (cl == NULL)
858 return;
859
860 mutex_enter(CMLB_MUTEX(cl));
861 cl->cl_f_geometry_is_valid = B_FALSE;
862 mutex_exit(CMLB_MUTEX(cl));
863 }
864
865 /*
866 * cmlb_is_valid
867 * Get status on whether the incore label/geom data is valid
868 *
869 * Arguments:
870 * cmlbhandle cmlb handle associated with device.
871 *
872 * Return values:
873 * B_TRUE if incore label/geom data is valid.
874 * B_FALSE otherwise.
875 *
876 */
877
878
879 boolean_t
cmlb_is_valid(cmlb_handle_t cmlbhandle)880 cmlb_is_valid(cmlb_handle_t cmlbhandle)
881 {
882 struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle;
883
884 if (cmlbhandle == NULL)
885 return (B_FALSE);
886
887 return (cl->cl_f_geometry_is_valid);
888
889 }
890
891
892
893 /*
894 * cmlb_close:
895 *
896 * Close the device, revert to a default label minor node for the device,
897 * if it is removable.
898 *
899 * Arguments:
900 * cmlbhandle cmlb handle associated with device.
901 *
902 * tg_cookie cookie from target driver to be passed back to target
903 * driver when we call back to it through tg_ops.
904 * Return values:
905 * 0 Success
906 * ENXIO Re-creating minor node failed.
907 */
908 /*ARGSUSED1*/
909 int
cmlb_close(cmlb_handle_t cmlbhandle,void * tg_cookie)910 cmlb_close(cmlb_handle_t cmlbhandle, void *tg_cookie)
911 {
912 struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle;
913
914 mutex_enter(CMLB_MUTEX(cl));
915 cl->cl_f_geometry_is_valid = B_FALSE;
916
917 /* revert to default minor node for this device */
918 if (ISREMOVABLE(cl)) {
919 cl->cl_cur_labeltype = CMLB_LABEL_UNDEF;
920 (void) cmlb_create_minor_nodes(cl);
921 }
922
923 mutex_exit(CMLB_MUTEX(cl));
924 return (0);
925 }
926
927 /*
928 * cmlb_get_devid_block:
929 * get the block number where device id is stored.
930 *
931 * Arguments:
932 * cmlbhandle cmlb handle associated with device.
933 * devidblockp pointer to block number.
934 * tg_cookie cookie from target driver to be passed back to target
935 * driver when we call back to it through tg_ops.
936 *
937 * Notes:
938 * It stores the block number of device id in the area pointed to
939 * by devidblockp.
940 * with the block number of device id.
941 *
942 * Return values:
943 * 0 success
944 * EINVAL device id does not apply to current label type.
945 */
946 /*ARGSUSED2*/
947 int
cmlb_get_devid_block(cmlb_handle_t cmlbhandle,diskaddr_t * devidblockp,void * tg_cookie)948 cmlb_get_devid_block(cmlb_handle_t cmlbhandle, diskaddr_t *devidblockp,
949 void *tg_cookie)
950 {
951 daddr_t spc, blk, head, cyl;
952 struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle;
953
954 mutex_enter(CMLB_MUTEX(cl));
955 if (cl->cl_state < CMLB_ATTACHED) {
956 mutex_exit(CMLB_MUTEX(cl));
957 return (EINVAL);
958 }
959
960 if ((!cl->cl_f_geometry_is_valid) ||
961 (cl->cl_solaris_size < DK_LABEL_LOC)) {
962 mutex_exit(CMLB_MUTEX(cl));
963 return (EINVAL);
964 }
965
966 if (cl->cl_cur_labeltype == CMLB_LABEL_EFI) {
967 if (cl->cl_reserved != -1) {
968 blk = cl->cl_map[cl->cl_reserved].dkl_cylno;
969 } else {
970 mutex_exit(CMLB_MUTEX(cl));
971 return (EINVAL);
972 }
973 } else {
974 /* if the disk is unlabeled, don't write a devid to it */
975 if (cl->cl_label_from_media != CMLB_LABEL_VTOC) {
976 mutex_exit(CMLB_MUTEX(cl));
977 return (EINVAL);
978 }
979
980 /* this geometry doesn't allow us to write a devid */
981 if (cl->cl_g.dkg_acyl < 2) {
982 mutex_exit(CMLB_MUTEX(cl));
983 return (EINVAL);
984 }
985
986 /*
987 * Subtract 2 guarantees that the next to last cylinder
988 * is used
989 */
990 cyl = cl->cl_g.dkg_ncyl + cl->cl_g.dkg_acyl - 2;
991 spc = cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect;
992 head = cl->cl_g.dkg_nhead - 1;
993 blk = cl->cl_solaris_offset +
994 (cyl * (spc - cl->cl_g.dkg_apc)) +
995 (head * cl->cl_g.dkg_nsect) + 1;
996 }
997
998 *devidblockp = blk;
999 mutex_exit(CMLB_MUTEX(cl));
1000 return (0);
1001 }
1002
1003 /*
1004 * cmlb_partinfo:
1005 * Get partition info for specified partition number.
1006 *
1007 * Arguments:
1008 * cmlbhandle cmlb handle associated with device.
1009 * part partition number
1010 * nblocksp pointer to number of blocks
1011 * startblockp pointer to starting block
1012 * partnamep pointer to name of partition
1013 * tagp pointer to tag info
1014 * tg_cookie cookie from target driver to be passed back to target
1015 * driver when we call back to it through tg_ops.
1016 *
1017 *
1018 * Notes:
1019 * If in-core label is not valid, this functions tries to revalidate
1020 * the label. If label is valid, it stores the total number of blocks
1021 * in this partition in the area pointed to by nblocksp, starting
1022 * block number in area pointed to by startblockp, pointer to partition
1023 * name in area pointed to by partnamep, and tag value in area
1024 * pointed by tagp.
1025 * For EFI labels, tag value will be set to 0.
1026 *
1027 * For all nblocksp, startblockp and partnamep, tagp, a value of NULL
1028 * indicates the corresponding info is not requested.
1029 *
1030 *
1031 * Return values:
1032 * 0 success
1033 * EINVAL no valid label or requested partition number is invalid.
1034 *
1035 */
1036 int
cmlb_partinfo(cmlb_handle_t cmlbhandle,int part,diskaddr_t * nblocksp,diskaddr_t * startblockp,char ** partnamep,uint16_t * tagp,void * tg_cookie)1037 cmlb_partinfo(cmlb_handle_t cmlbhandle, int part, diskaddr_t *nblocksp,
1038 diskaddr_t *startblockp, char **partnamep, uint16_t *tagp, void *tg_cookie)
1039 {
1040
1041 struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle;
1042 int rval;
1043 #if defined(__i386) || defined(__amd64)
1044 int ext_part;
1045 #endif
1046
1047 ASSERT(cl != NULL);
1048 mutex_enter(CMLB_MUTEX(cl));
1049 if (cl->cl_state < CMLB_ATTACHED) {
1050 mutex_exit(CMLB_MUTEX(cl));
1051 return (EINVAL);
1052 }
1053
1054 if (part < 0 || part >= MAXPART) {
1055 rval = EINVAL;
1056 } else {
1057 if (!cl->cl_f_geometry_is_valid)
1058 (void) cmlb_validate_geometry((struct cmlb_lun *)cl,
1059 B_FALSE, 0, tg_cookie);
1060
1061 #if defined(_SUNOS_VTOC_16)
1062 if (((!cl->cl_f_geometry_is_valid) ||
1063 (part < NDKMAP && cl->cl_solaris_size == 0)) &&
1064 (part != P0_RAW_DISK)) {
1065 #else
1066 if ((!cl->cl_f_geometry_is_valid) ||
1067 (part < NDKMAP && cl->cl_solaris_size == 0)) {
1068 #endif
1069 rval = EINVAL;
1070 } else {
1071 if (startblockp != NULL)
1072 *startblockp = (diskaddr_t)cl->cl_offset[part];
1073
1074 if (nblocksp != NULL)
1075 *nblocksp = (diskaddr_t)
1076 cl->cl_map[part].dkl_nblk;
1077
1078 if (tagp != NULL)
1079 *tagp =
1080 ((cl->cl_cur_labeltype == CMLB_LABEL_EFI) ||
1081 (part >= NDKMAP)) ? V_UNASSIGNED :
1082 cl->cl_vtoc.v_part[part].p_tag;
1083 rval = 0;
1084 }
1085
1086 /* consistent with behavior of sd for getting minor name */
1087 if (partnamep != NULL) {
1088 #if defined(__i386) || defined(__amd64)
1089 #if defined(_FIRMWARE_NEEDS_FDISK)
1090 if (part > FDISK_P4) {
1091 ext_part = part-FDISK_P4-1;
1092 *partnamep = dk_ext_minor_data[ext_part].name;
1093 } else
1094 #endif
1095 #endif
1096 *partnamep = dk_minor_data[part].name;
1097 }
1098
1099 }
1100
1101 mutex_exit(CMLB_MUTEX(cl));
1102 return (rval);
1103 }
1104
1105 /*
1106 * cmlb_efi_label_capacity:
1107 * Get capacity stored in EFI disk label.
1108 *
1109 * Arguments:
1110 * cmlbhandle cmlb handle associated with device.
1111 * capacity pointer to capacity stored in EFI disk label.
1112 * tg_cookie cookie from target driver to be passed back to target
1113 * driver when we call back to it through tg_ops.
1114 *
1115 *
1116 * Notes:
1117 * If in-core label is not valid, this functions tries to revalidate
1118 * the label. If label is valid and is an EFI label, it stores the capacity
1119 * in disk label in the area pointed to by capacity.
1120 *
1121 *
1122 * Return values:
1123 * 0 success
1124 * EINVAL no valid EFI label or capacity is NULL.
1125 *
1126 */
1127 int
1128 cmlb_efi_label_capacity(cmlb_handle_t cmlbhandle, diskaddr_t *capacity,
1129 void *tg_cookie)
1130 {
1131 struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle;
1132 int rval;
1133
1134 ASSERT(cl != NULL);
1135 mutex_enter(CMLB_MUTEX(cl));
1136 if (cl->cl_state < CMLB_ATTACHED) {
1137 mutex_exit(CMLB_MUTEX(cl));
1138 return (EINVAL);
1139 }
1140
1141 if (!cl->cl_f_geometry_is_valid)
1142 (void) cmlb_validate_geometry((struct cmlb_lun *)cl, B_FALSE,
1143 0, tg_cookie);
1144
1145 if ((!cl->cl_f_geometry_is_valid) || (capacity == NULL) ||
1146 (cl->cl_cur_labeltype != CMLB_LABEL_EFI)) {
1147 rval = EINVAL;
1148 } else {
1149 *capacity = (diskaddr_t)cl->cl_map[WD_NODE].dkl_nblk;
1150 rval = 0;
1151 }
1152
1153 mutex_exit(CMLB_MUTEX(cl));
1154 return (rval);
1155 }
1156
1157 /* Caller should make sure Test Unit Ready succeeds before calling this. */
1158 /*ARGSUSED*/
1159 int
1160 cmlb_ioctl(cmlb_handle_t cmlbhandle, dev_t dev, int cmd, intptr_t arg,
1161 int flag, cred_t *cred_p, int *rval_p, void *tg_cookie)
1162 {
1163
1164 int err;
1165 struct cmlb_lun *cl;
1166
1167 cl = (struct cmlb_lun *)cmlbhandle;
1168
1169 ASSERT(cl != NULL);
1170
1171 mutex_enter(CMLB_MUTEX(cl));
1172 if (cl->cl_state < CMLB_ATTACHED) {
1173 mutex_exit(CMLB_MUTEX(cl));
1174 return (EIO);
1175 }
1176
1177 switch (cmd) {
1178 case DKIOCSEXTVTOC:
1179 case DKIOCSGEOM:
1180 case DKIOCSETEFI:
1181 case DKIOCSMBOOT:
1182 #if defined(__i386) || defined(__amd64)
1183 case DKIOCSETEXTPART:
1184 #endif
1185 break;
1186 case DKIOCSVTOC:
1187 #if defined(__i386) || defined(__amd64)
1188 case DKIOCPARTINFO:
1189 #endif
1190 if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) {
1191 mutex_exit(CMLB_MUTEX(cl));
1192 return (EOVERFLOW);
1193 }
1194 break;
1195 default:
1196 (void) cmlb_validate_geometry(cl, 1, CMLB_SILENT,
1197 tg_cookie);
1198
1199 switch (cmd) {
1200 case DKIOCGVTOC:
1201 case DKIOCGAPART:
1202 case DKIOCSAPART:
1203
1204 if (cl->cl_label_from_media == CMLB_LABEL_EFI) {
1205 /* GPT label on disk */
1206 mutex_exit(CMLB_MUTEX(cl));
1207 return (ENOTSUP);
1208 } else if
1209 (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) {
1210 mutex_exit(CMLB_MUTEX(cl));
1211 return (EOVERFLOW);
1212 }
1213 break;
1214
1215 case DKIOCGGEOM:
1216 if (cl->cl_label_from_media == CMLB_LABEL_EFI) {
1217 /* GPT label on disk */
1218 mutex_exit(CMLB_MUTEX(cl));
1219 return (ENOTSUP);
1220 }
1221 break;
1222 default:
1223 break;
1224 }
1225 }
1226
1227 mutex_exit(CMLB_MUTEX(cl));
1228
1229 switch (cmd) {
1230 case DKIOCGGEOM:
1231 cmlb_dbg(CMLB_TRACE, cl, "DKIOCGGEOM\n");
1232 err = cmlb_dkio_get_geometry(cl, (caddr_t)arg, flag, tg_cookie);
1233 break;
1234
1235 case DKIOCSGEOM:
1236 cmlb_dbg(CMLB_TRACE, cl, "DKIOCSGEOM\n");
1237 err = cmlb_dkio_set_geometry(cl, (caddr_t)arg, flag);
1238 break;
1239
1240 case DKIOCGAPART:
1241 cmlb_dbg(CMLB_TRACE, cl, "DKIOCGAPART\n");
1242 err = cmlb_dkio_get_partition(cl, (caddr_t)arg,
1243 flag, tg_cookie);
1244 break;
1245
1246 case DKIOCSAPART:
1247 cmlb_dbg(CMLB_TRACE, cl, "DKIOCSAPART\n");
1248 err = cmlb_dkio_set_partition(cl, (caddr_t)arg, flag);
1249 break;
1250
1251 case DKIOCGVTOC:
1252 cmlb_dbg(CMLB_TRACE, cl, "DKIOCGVTOC\n");
1253 err = cmlb_dkio_get_vtoc(cl, (caddr_t)arg, flag, tg_cookie);
1254 break;
1255
1256 case DKIOCGEXTVTOC:
1257 cmlb_dbg(CMLB_TRACE, cl, "DKIOCGVTOC\n");
1258 err = cmlb_dkio_get_extvtoc(cl, (caddr_t)arg, flag, tg_cookie);
1259 break;
1260
1261 case DKIOCGETEFI:
1262 cmlb_dbg(CMLB_TRACE, cl, "DKIOCGETEFI\n");
1263 err = cmlb_dkio_get_efi(cl, (caddr_t)arg, flag, tg_cookie);
1264 break;
1265
1266 case DKIOCPARTITION:
1267 cmlb_dbg(CMLB_TRACE, cl, "DKIOCPARTITION\n");
1268 err = cmlb_dkio_partition(cl, (caddr_t)arg, flag, tg_cookie);
1269 break;
1270
1271 case DKIOCSVTOC:
1272 cmlb_dbg(CMLB_TRACE, cl, "DKIOCSVTOC\n");
1273 err = cmlb_dkio_set_vtoc(cl, dev, (caddr_t)arg, flag,
1274 tg_cookie);
1275 break;
1276
1277 case DKIOCSEXTVTOC:
1278 cmlb_dbg(CMLB_TRACE, cl, "DKIOCSVTOC\n");
1279 err = cmlb_dkio_set_extvtoc(cl, dev, (caddr_t)arg, flag,
1280 tg_cookie);
1281 break;
1282
1283 case DKIOCSETEFI:
1284 cmlb_dbg(CMLB_TRACE, cl, "DKIOCSETEFI\n");
1285 err = cmlb_dkio_set_efi(cl, dev, (caddr_t)arg, flag, tg_cookie);
1286 break;
1287
1288 case DKIOCGMBOOT:
1289 cmlb_dbg(CMLB_TRACE, cl, "DKIOCGMBOOT\n");
1290 err = cmlb_dkio_get_mboot(cl, (caddr_t)arg, flag, tg_cookie);
1291 break;
1292
1293 case DKIOCSMBOOT:
1294 cmlb_dbg(CMLB_TRACE, cl, "DKIOCSMBOOT\n");
1295 err = cmlb_dkio_set_mboot(cl, (caddr_t)arg, flag, tg_cookie);
1296 break;
1297 case DKIOCG_PHYGEOM:
1298 cmlb_dbg(CMLB_TRACE, cl, "DKIOCG_PHYGEOM\n");
1299 #if defined(__i386) || defined(__amd64)
1300 err = cmlb_dkio_get_phygeom(cl, (caddr_t)arg, flag, tg_cookie);
1301 #else
1302 err = ENOTTY;
1303 #endif
1304 break;
1305 case DKIOCG_VIRTGEOM:
1306 cmlb_dbg(CMLB_TRACE, cl, "DKIOCG_VIRTGEOM\n");
1307 #if defined(__i386) || defined(__amd64)
1308 err = cmlb_dkio_get_virtgeom(cl, (caddr_t)arg, flag);
1309 #else
1310 err = ENOTTY;
1311 #endif
1312 break;
1313 case DKIOCPARTINFO:
1314 cmlb_dbg(CMLB_TRACE, cl, "DKIOCPARTINFO");
1315 #if defined(__i386) || defined(__amd64)
1316 err = cmlb_dkio_partinfo(cl, dev, (caddr_t)arg, flag);
1317 #else
1318 err = ENOTTY;
1319 #endif
1320 break;
1321 case DKIOCEXTPARTINFO:
1322 cmlb_dbg(CMLB_TRACE, cl, "DKIOCPARTINFO");
1323 #if defined(__i386) || defined(__amd64)
1324 err = cmlb_dkio_extpartinfo(cl, dev, (caddr_t)arg, flag);
1325 #else
1326 err = ENOTTY;
1327 #endif
1328 break;
1329 #if defined(__i386) || defined(__amd64)
1330 case DKIOCSETEXTPART:
1331 cmlb_dbg(CMLB_TRACE, cl, "DKIOCSETEXTPART");
1332 err = cmlb_dkio_set_ext_part(cl, (caddr_t)arg, flag, tg_cookie);
1333 break;
1334 #endif
1335 default:
1336 err = ENOTTY;
1337
1338 }
1339
1340 /*
1341 * An ioctl that succeeds and changed ('set') size(9P) information
1342 * needs to invalidate the cached devinfo snapshot to avoid having
1343 * old information being returned in a snapshots.
1344 *
1345 * NB: When available, call ddi_change_minor_node() to clear
1346 * SSIZEVALID in specfs vnodes via spec_size_invalidate().
1347 */
1348 if (err == 0) {
1349 switch (cmd) {
1350 case DKIOCSGEOM:
1351 case DKIOCSAPART:
1352 case DKIOCSVTOC:
1353 case DKIOCSEXTVTOC:
1354 case DKIOCSETEFI:
1355 i_ddi_prop_dyn_cache_invalidate(CMLB_DEVINFO(cl),
1356 i_ddi_prop_dyn_driver_get(CMLB_DEVINFO(cl)));
1357 }
1358 }
1359 return (err);
1360 }
1361
1362 dev_t
1363 cmlb_make_device(struct cmlb_lun *cl)
1364 {
1365 return (makedevice(ddi_driver_major(CMLB_DEVINFO(cl)),
1366 ddi_get_instance(CMLB_DEVINFO(cl)) << CMLBUNIT_SHIFT));
1367 }
1368
1369 /*
1370 * Function: cmlb_check_update_blockcount
1371 *
1372 * Description: If current capacity value is invalid, obtains the
1373 * current capacity from target driver.
1374 *
1375 * Return Code: 0 success
1376 * EIO failure
1377 */
1378 static int
1379 cmlb_check_update_blockcount(struct cmlb_lun *cl, void *tg_cookie)
1380 {
1381 int status;
1382 diskaddr_t capacity;
1383 uint32_t lbasize;
1384
1385 ASSERT(mutex_owned(CMLB_MUTEX(cl)));
1386
1387 if (cl->cl_f_geometry_is_valid)
1388 return (0);
1389
1390 mutex_exit(CMLB_MUTEX(cl));
1391 status = DK_TG_GETCAP(cl, &capacity, tg_cookie);
1392 if (status != 0) {
1393 mutex_enter(CMLB_MUTEX(cl));
1394 return (EIO);
1395 }
1396
1397 status = DK_TG_GETBLOCKSIZE(cl, &lbasize, tg_cookie);
1398 mutex_enter(CMLB_MUTEX(cl));
1399 if (status != 0)
1400 return (EIO);
1401
1402 if ((capacity != 0) && (lbasize != 0)) {
1403 cl->cl_blockcount = capacity;
1404 cl->cl_tgt_blocksize = lbasize;
1405 if (!cl->cl_is_removable) {
1406 cl->cl_sys_blocksize = lbasize;
1407 }
1408 return (0);
1409 } else {
1410 return (EIO);
1411 }
1412 }
1413
1414 static int
1415 cmlb_create_minor(dev_info_t *dip, char *name, int spec_type,
1416 minor_t minor_num, char *node_type, int flag, boolean_t internal)
1417 {
1418 ASSERT(VALID_BOOLEAN(internal));
1419
1420 if (internal)
1421 return (ddi_create_internal_pathname(dip,
1422 name, spec_type, minor_num));
1423 else
1424 return (ddi_create_minor_node(dip,
1425 name, spec_type, minor_num, node_type, flag));
1426 }
1427
1428 /*
1429 * Function: cmlb_create_minor_nodes
1430 *
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.
1435 *
1436 *
1437 * Arguments: cl - driver soft state (unit) structure
1438 *
1439 * Return Code: 0 success
1440 * ENXIO failure.
1441 *
1442 * Context: Kernel thread context
1443 */
1444 static int
1445 cmlb_create_minor_nodes(struct cmlb_lun *cl)
1446 {
1447 struct driver_minor_data *dmdp;
1448 int instance;
1449 char name[48];
1450 cmlb_label_t newlabeltype;
1451 boolean_t internal;
1452
1453 ASSERT(cl != NULL);
1454 ASSERT(mutex_owned(CMLB_MUTEX(cl)));
1455
1456 internal = VOID2BOOLEAN(
1457 (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0);
1458
1459 /* check the most common case */
1460 if (cl->cl_cur_labeltype != CMLB_LABEL_UNDEF &&
1461 cl->cl_last_labeltype == cl->cl_cur_labeltype) {
1462 /* do nothing */
1463 return (0);
1464 }
1465
1466 if (cl->cl_def_labeltype == CMLB_LABEL_UNDEF) {
1467 /* we should never get here */
1468 return (ENXIO);
1469 }
1470
1471 if (cl->cl_last_labeltype == CMLB_LABEL_UNDEF) {
1472 /* first time during attach */
1473 newlabeltype = cl->cl_def_labeltype;
1474
1475 instance = ddi_get_instance(CMLB_DEVINFO(cl));
1476
1477 /* Create all the minor nodes for this target. */
1478 dmdp = (newlabeltype == CMLB_LABEL_EFI) ? dk_minor_data_efi :
1479 dk_minor_data;
1480 while (dmdp->name != NULL) {
1481
1482 (void) sprintf(name, "%s", dmdp->name);
1483
1484 if (cmlb_create_minor(CMLB_DEVINFO(cl), name,
1485 dmdp->type,
1486 (instance << CMLBUNIT_SHIFT) | dmdp->minor,
1487 cl->cl_node_type, NULL, internal) == DDI_FAILURE) {
1488 /*
1489 * Clean up any nodes that may have been
1490 * created, in case this fails in the middle
1491 * of the loop.
1492 */
1493 ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL);
1494 return (ENXIO);
1495 }
1496 dmdp++;
1497 }
1498 cl->cl_last_labeltype = newlabeltype;
1499 return (0);
1500 }
1501
1502 /* Not first time */
1503 if (cl->cl_cur_labeltype == CMLB_LABEL_UNDEF) {
1504 if (cl->cl_last_labeltype != cl->cl_def_labeltype) {
1505 /* close time, revert to default. */
1506 newlabeltype = cl->cl_def_labeltype;
1507 } else {
1508 /*
1509 * do nothing since the type for which we last created
1510 * nodes matches the default
1511 */
1512 return (0);
1513 }
1514 } else {
1515 if (cl->cl_cur_labeltype != cl->cl_last_labeltype) {
1516 /* We are not closing, use current label type */
1517 newlabeltype = cl->cl_cur_labeltype;
1518 } else {
1519 /*
1520 * do nothing since the type for which we last created
1521 * nodes matches the current label type
1522 */
1523 return (0);
1524 }
1525 }
1526
1527 instance = ddi_get_instance(CMLB_DEVINFO(cl));
1528
1529 /*
1530 * Currently we only fix up the s7 node when we are switching
1531 * label types from or to EFI. This is consistent with
1532 * current behavior of sd.
1533 */
1534 if (newlabeltype == CMLB_LABEL_EFI &&
1535 cl->cl_last_labeltype != CMLB_LABEL_EFI) {
1536 /* from vtoc to EFI */
1537 ddi_remove_minor_node(CMLB_DEVINFO(cl), "h");
1538 ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw");
1539 (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd",
1540 S_IFBLK, (instance << CMLBUNIT_SHIFT) | WD_NODE,
1541 cl->cl_node_type, NULL, internal);
1542 (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd,raw",
1543 S_IFCHR, (instance << CMLBUNIT_SHIFT) | WD_NODE,
1544 cl->cl_node_type, NULL, internal);
1545 } else {
1546 /* from efi to vtoc */
1547 ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd");
1548 ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd,raw");
1549 (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h",
1550 S_IFBLK, (instance << CMLBUNIT_SHIFT) | WD_NODE,
1551 cl->cl_node_type, NULL, internal);
1552 (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h,raw",
1553 S_IFCHR, (instance << CMLBUNIT_SHIFT) | WD_NODE,
1554 cl->cl_node_type, NULL, internal);
1555 }
1556
1557 cl->cl_last_labeltype = newlabeltype;
1558 return (0);
1559 }
1560
1561 /*
1562 * Function: cmlb_validate_geometry
1563 *
1564 * Description: Read the label from the disk (if present). Update the unit's
1565 * geometry and vtoc information from the data in the label.
1566 * Verify that the label is valid.
1567 *
1568 * Arguments:
1569 * cl driver soft state (unit) structure
1570 *
1571 * forcerevalid force revalidation even if we are already valid.
1572 * flags operation flags from target driver. Used for verbosity
1573 * control at this time.
1574 * tg_cookie cookie from target driver to be passed back to target
1575 * driver when we call back to it through tg_ops.
1576 *
1577 * Return Code: 0 - Successful completion
1578 * EINVAL - Invalid value in cl->cl_tgt_blocksize or
1579 * cl->cl_blockcount; or label on disk is corrupted
1580 * or unreadable.
1581 * EACCES - Reservation conflict at the device.
1582 * ENOMEM - Resource allocation error
1583 * ENOTSUP - geometry not applicable
1584 *
1585 * Context: Kernel thread only (can sleep).
1586 */
1587 static int
1588 cmlb_validate_geometry(struct cmlb_lun *cl, boolean_t forcerevalid, int flags,
1589 void *tg_cookie)
1590 {
1591 int label_error = 0;
1592 diskaddr_t capacity;
1593 int count;
1594
1595 ASSERT(mutex_owned(CMLB_MUTEX(cl)));
1596 ASSERT(VALID_BOOLEAN(forcerevalid));
1597
1598 if ((cl->cl_f_geometry_is_valid) && (!forcerevalid)) {
1599 if (cl->cl_cur_labeltype == CMLB_LABEL_EFI)
1600 return (ENOTSUP);
1601 return (0);
1602 }
1603
1604 if (cmlb_check_update_blockcount(cl, tg_cookie) != 0)
1605 return (EIO);
1606
1607 capacity = cl->cl_blockcount;
1608
1609 #if defined(_SUNOS_VTOC_16)
1610 /*
1611 * Set up the "whole disk" fdisk partition; this should always
1612 * exist, regardless of whether the disk contains an fdisk table
1613 * or vtoc.
1614 */
1615 cl->cl_map[P0_RAW_DISK].dkl_cylno = 0;
1616 cl->cl_offset[P0_RAW_DISK] = 0;
1617 /*
1618 * note if capacity > int32_max(1TB) we are in 64bit environment
1619 * so no truncation happens
1620 */
1621 cl->cl_map[P0_RAW_DISK].dkl_nblk = capacity;
1622 #endif
1623 /*
1624 * Refresh the logical and physical geometry caches.
1625 * (data from MODE SENSE format/rigid disk geometry pages,
1626 * and scsi_ifgetcap("geometry").
1627 */
1628 cmlb_resync_geom_caches(cl, capacity, tg_cookie);
1629
1630 cl->cl_label_from_media = CMLB_LABEL_UNDEF;
1631 label_error = cmlb_use_efi(cl, capacity, flags, tg_cookie);
1632 if (label_error == 0) {
1633
1634 /* found a valid EFI label */
1635 cmlb_dbg(CMLB_TRACE, cl,
1636 "cmlb_validate_geometry: found EFI label\n");
1637 /*
1638 * solaris_size and geometry_is_valid are set in
1639 * cmlb_use_efi
1640 */
1641 return (ENOTSUP);
1642 }
1643
1644 /* NO EFI label found */
1645
1646 if (capacity > CMLB_EXTVTOC_LIMIT) {
1647 if (label_error == ESRCH) {
1648 /*
1649 * they've configured a LUN over 2TB, but used
1650 * format.dat to restrict format's view of the
1651 * capacity to be under 2TB in some earlier Solaris
1652 * release.
1653 */
1654 /* i.e > 2TB with a VTOC < 2TB */
1655 if (!(flags & CMLB_SILENT) &&
1656 (cl->cl_msglog_flag & CMLB_ALLOW_2TB_WARN)) {
1657
1658 cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl),
1659 CE_NOTE, "!Disk (%s%d) is limited to 2 TB "
1660 "due to VTOC label. To use the full "
1661 "capacity of the disk, use format(1M) to "
1662 "relabel the disk with EFI/GPT label.\n",
1663 CMLB_LABEL(cl),
1664 ddi_get_instance(CMLB_DEVINFO(cl)));
1665
1666 cl->cl_msglog_flag &= ~CMLB_ALLOW_2TB_WARN;
1667 }
1668 } else {
1669 return (ENOTSUP);
1670 }
1671 }
1672
1673 label_error = 0;
1674
1675 /*
1676 * at this point it is either labeled with a VTOC or it is
1677 * under 1TB (<= 1TB actually for off-by-1)
1678 */
1679
1680 /*
1681 * Only DIRECT ACCESS devices will have Scl labels.
1682 * CD's supposedly have a Scl label, too
1683 */
1684 if (cl->cl_device_type == DTYPE_DIRECT || ISREMOVABLE(cl)) {
1685 struct dk_label *dkl;
1686 offset_t label_addr;
1687 int rval;
1688 size_t buffer_size;
1689
1690 /*
1691 * Note: This will set up cl->cl_solaris_size and
1692 * cl->cl_solaris_offset.
1693 */
1694 rval = cmlb_read_fdisk(cl, capacity, tg_cookie);
1695 if ((rval != 0) && !ISCD(cl)) {
1696 ASSERT(mutex_owned(CMLB_MUTEX(cl)));
1697 return (rval);
1698 }
1699
1700 if (cl->cl_solaris_size <= DK_LABEL_LOC) {
1701 /*
1702 * Found fdisk table but no Solaris partition entry,
1703 * so don't call cmlb_uselabel() and don't create
1704 * a default label.
1705 */
1706 label_error = 0;
1707 cl->cl_f_geometry_is_valid = B_TRUE;
1708 goto no_solaris_partition;
1709 }
1710
1711 label_addr = (daddr_t)(cl->cl_solaris_offset + DK_LABEL_LOC);
1712
1713 buffer_size = cl->cl_sys_blocksize;
1714
1715 cmlb_dbg(CMLB_TRACE, cl, "cmlb_validate_geometry: "
1716 "label_addr: 0x%x allocation size: 0x%x\n",
1717 label_addr, buffer_size);
1718
1719 if ((dkl = kmem_zalloc(buffer_size, KM_NOSLEEP)) == NULL)
1720 return (ENOMEM);
1721
1722 mutex_exit(CMLB_MUTEX(cl));
1723 rval = DK_TG_READ(cl, dkl, label_addr, buffer_size, tg_cookie);
1724 mutex_enter(CMLB_MUTEX(cl));
1725
1726 switch (rval) {
1727 case 0:
1728 /*
1729 * cmlb_uselabel will establish that the geometry
1730 * is valid.
1731 */
1732 if (cmlb_uselabel(cl,
1733 (struct dk_label *)(uintptr_t)dkl, flags) !=
1734 CMLB_LABEL_IS_VALID) {
1735 label_error = EINVAL;
1736 } else
1737 cl->cl_label_from_media = CMLB_LABEL_VTOC;
1738 break;
1739 case EACCES:
1740 label_error = EACCES;
1741 break;
1742 default:
1743 label_error = EINVAL;
1744 break;
1745 }
1746
1747 kmem_free(dkl, buffer_size);
1748 }
1749
1750 /*
1751 * If a valid label was not found, AND if no reservation conflict
1752 * was detected, then go ahead and create a default label (4069506).
1753 *
1754 * Note: currently, for VTOC_8 devices, the default label is created
1755 * for removables and hotpluggables only. For VTOC_16 devices, the
1756 * default label will be created for all devices.
1757 * (see cmlb_build_default_label)
1758 */
1759 #if defined(_SUNOS_VTOC_8)
1760 if ((ISREMOVABLE(cl) || ISHOTPLUGGABLE(cl)) &&
1761 (label_error != EACCES)) {
1762 #elif defined(_SUNOS_VTOC_16)
1763 if (label_error != EACCES) {
1764 #endif
1765 if (!cl->cl_f_geometry_is_valid) {
1766 cmlb_build_default_label(cl, tg_cookie);
1767 }
1768 label_error = 0;
1769 }
1770
1771 no_solaris_partition:
1772
1773 #if defined(_SUNOS_VTOC_16)
1774 /*
1775 * If we have valid geometry, set up the remaining fdisk partitions.
1776 * Note that dkl_cylno is not used for the fdisk map entries, so
1777 * we set it to an entirely bogus value.
1778 */
1779 for (count = 0; count < FDISK_PARTS; count++) {
1780 cl->cl_map[FDISK_P1 + count].dkl_cylno = UINT16_MAX;
1781 cl->cl_map[FDISK_P1 + count].dkl_nblk =
1782 cl->cl_fmap[count].fmap_nblk;
1783
1784 cl->cl_offset[FDISK_P1 + count] =
1785 cl->cl_fmap[count].fmap_start;
1786 }
1787 #endif
1788
1789 for (count = 0; count < NDKMAP; count++) {
1790 #if defined(_SUNOS_VTOC_8)
1791 struct dk_map *lp = &cl->cl_map[count];
1792 cl->cl_offset[count] =
1793 cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno;
1794 #elif defined(_SUNOS_VTOC_16)
1795 struct dkl_partition *vp = &cl->cl_vtoc.v_part[count];
1796
1797 cl->cl_offset[count] = vp->p_start + cl->cl_solaris_offset;
1798 #else
1799 #error "No VTOC format defined."
1800 #endif
1801 }
1802
1803 return (label_error);
1804 }
1805
1806 #if defined(_SUNOS_VTOC_16)
1807 /*
1808 * Function: cmlb_convert_geometry
1809 *
1810 * Description: Convert physical geometry into a dk_geom structure. In
1811 * other words, make sure we don't wrap 16-bit values.
1812 * e.g. converting from geom_cache to dk_geom
1813 *
1814 * Context: Kernel thread only
1815 */
1816 static void
1817 cmlb_convert_geometry(struct cmlb_lun *cl, diskaddr_t capacity,
1818 struct dk_geom *cl_g, void *tg_cookie)
1819 {
1820
1821 ASSERT(cl != NULL);
1822 ASSERT(mutex_owned(CMLB_MUTEX(cl)));
1823
1824 /* Unlabeled SCSI floppy device */
1825 if (capacity < 160) {
1826 /* Less than 80K */
1827 cl_g->dkg_nhead = 1;
1828 cl_g->dkg_ncyl = capacity;
1829 cl_g->dkg_nsect = 1;
1830 return;
1831 } else if (capacity <= 0x1000) {
1832 cl_g->dkg_nhead = 2;
1833 cl_g->dkg_ncyl = 80;
1834 cl_g->dkg_nsect = capacity / (cl_g->dkg_nhead * cl_g->dkg_ncyl);
1835 return;
1836 }
1837
1838 /*
1839 * For all devices we calculate cylinders using the heads and sectors
1840 * we assign based on capacity of the device. The algorithm is
1841 * designed to be compatible with the way other operating systems
1842 * lay out fdisk tables for X86 and to insure that the cylinders never
1843 * exceed 65535 to prevent problems with X86 ioctls that report
1844 * geometry.
1845 * For some smaller disk sizes we report geometry that matches those
1846 * used by X86 BIOS usage. For larger disks, we use SPT that are
1847 * multiples of 63, since other OSes that are not limited to 16-bits
1848 * for cylinders stop at 63 SPT we make do by using multiples of 63 SPT.
1849 *
1850 * The following table (in order) illustrates some end result
1851 * calculations:
1852 *
1853 * Maximum number of blocks nhead nsect
1854 *
1855 * 2097152 (1GB) 64 32
1856 * 16777216 (8GB) 128 32
1857 * 1052819775 (502.02GB) 255 63
1858 * 2105639550 (0.98TB) 255 126
1859 * 3158459325 (1.47TB) 255 189
1860 * 4211279100 (1.96TB) 255 252
1861 * 5264098875 (2.45TB) 255 315
1862 * ...
1863 *
1864 * For Solid State Drive(SSD), it uses 4K page size inside and may be
1865 * double with every new generation. If the I/O is not aligned with
1866 * page size on SSDs, SSDs perform a lot slower.
1867 * By default, Solaris partition starts from cylinder 1. It will be
1868 * misaligned even with 4K if using heads(255) and SPT(63). To
1869 * workaround the problem, if the device is SSD, we use heads(224) and
1870 * SPT multiple of 56. Thus the default Solaris partition starts from
1871 * a position that aligns with 128K on a 512 bytes sector size SSD.
1872 */
1873
1874 if (capacity <= 0x200000) {
1875 cl_g->dkg_nhead = 64;
1876 cl_g->dkg_nsect = 32;
1877 } else if (capacity <= 0x01000000) {
1878 cl_g->dkg_nhead = 128;
1879 cl_g->dkg_nsect = 32;
1880 } else {
1881 tg_attribute_t tgattribute;
1882 int is_solid_state;
1883 unsigned short nhead;
1884 unsigned short nsect;
1885
1886 bzero(&tgattribute, sizeof (tg_attribute_t));
1887
1888 mutex_exit(CMLB_MUTEX(cl));
1889 is_solid_state =
1890 (DK_TG_GETATTRIBUTE(cl, &tgattribute, tg_cookie) == 0) ?
1891 tgattribute.media_is_solid_state : FALSE;
1892 mutex_enter(CMLB_MUTEX(cl));
1893
1894 if (is_solid_state) {
1895 nhead = 224;
1896 nsect = 56;
1897 } else {
1898 nhead = 255;
1899 nsect = 63;
1900 }
1901
1902 cl_g->dkg_nhead = nhead;
1903
1904 /* make dkg_nsect be smallest multiple of nsect */
1905 cl_g->dkg_nsect = ((capacity +
1906 (UINT16_MAX * nhead * nsect) - 1) /
1907 (UINT16_MAX * nhead * nsect)) * nsect;
1908
1909 if (cl_g->dkg_nsect == 0)
1910 cl_g->dkg_nsect = (UINT16_MAX / nsect) * nsect;
1911 }
1912
1913 }
1914 #endif
1915
1916 /*
1917 * Function: cmlb_resync_geom_caches
1918 *
1919 * Description: (Re)initialize both geometry caches: the virtual geometry
1920 * information is extracted from the HBA (the "geometry"
1921 * capability), and the physical geometry cache data is
1922 * generated by issuing MODE SENSE commands.
1923 *
1924 * Arguments:
1925 * cl driver soft state (unit) structure
1926 * capacity disk capacity in #blocks
1927 * tg_cookie cookie from target driver to be passed back to target
1928 * driver when we call back to it through tg_ops.
1929 *
1930 * Context: Kernel thread only (can sleep).
1931 */
1932 static void
1933 cmlb_resync_geom_caches(struct cmlb_lun *cl, diskaddr_t capacity,
1934 void *tg_cookie)
1935 {
1936 struct cmlb_geom pgeom;
1937 struct cmlb_geom lgeom;
1938 struct cmlb_geom *pgeomp = &pgeom;
1939 unsigned short nhead;
1940 unsigned short nsect;
1941 int spc;
1942 int ret;
1943
1944 ASSERT(cl != NULL);
1945 ASSERT(mutex_owned(CMLB_MUTEX(cl)));
1946
1947 /*
1948 * Ask the controller for its logical geometry.
1949 * Note: if the HBA does not support scsi_ifgetcap("geometry"),
1950 * then the lgeom cache will be invalid.
1951 */
1952 mutex_exit(CMLB_MUTEX(cl));
1953 bzero(&lgeom, sizeof (struct cmlb_geom));
1954 ret = DK_TG_GETVIRTGEOM(cl, &lgeom, tg_cookie);
1955 mutex_enter(CMLB_MUTEX(cl));
1956
1957 bcopy(&lgeom, &cl->cl_lgeom, sizeof (cl->cl_lgeom));
1958
1959 /*
1960 * Initialize the pgeom cache from lgeom, so that if MODE SENSE
1961 * doesn't work, DKIOCG_PHYSGEOM can return reasonable values.
1962 */
1963 if (ret != 0 || cl->cl_lgeom.g_nsect == 0 ||
1964 cl->cl_lgeom.g_nhead == 0) {
1965 /*
1966 * Note: Perhaps this needs to be more adaptive? The rationale
1967 * is that, if there's no HBA geometry from the HBA driver, any
1968 * guess is good, since this is the physical geometry. If MODE
1969 * SENSE fails this gives a max cylinder size for non-LBA access
1970 */
1971 nhead = 255;
1972 nsect = 63;
1973 } else {
1974 nhead = cl->cl_lgeom.g_nhead;
1975 nsect = cl->cl_lgeom.g_nsect;
1976 }
1977
1978 if (ISCD(cl)) {
1979 pgeomp->g_nhead = 1;
1980 pgeomp->g_nsect = nsect * nhead;
1981 } else {
1982 pgeomp->g_nhead = nhead;
1983 pgeomp->g_nsect = nsect;
1984 }
1985
1986 spc = pgeomp->g_nhead * pgeomp->g_nsect;
1987 pgeomp->g_capacity = capacity;
1988 if (spc == 0)
1989 pgeomp->g_ncyl = 0;
1990 else
1991 pgeomp->g_ncyl = pgeomp->g_capacity / spc;
1992 pgeomp->g_acyl = 0;
1993
1994 /*
1995 * Retrieve fresh geometry data from the hardware, stash it
1996 * here temporarily before we rebuild the incore label.
1997 *
1998 * We want to use the MODE SENSE commands to derive the
1999 * physical geometry of the device, but if either command
2000 * fails, the logical geometry is used as the fallback for
2001 * disk label geometry.
2002 */
2003
2004 mutex_exit(CMLB_MUTEX(cl));
2005 (void) DK_TG_GETPHYGEOM(cl, pgeomp, tg_cookie);
2006 mutex_enter(CMLB_MUTEX(cl));
2007
2008 /*
2009 * Now update the real copy while holding the mutex. This
2010 * way the global copy is never in an inconsistent state.
2011 */
2012 bcopy(pgeomp, &cl->cl_pgeom, sizeof (cl->cl_pgeom));
2013
2014 cmlb_dbg(CMLB_INFO, cl, "cmlb_resync_geom_caches: "
2015 "(cached from lgeom)\n");
2016 cmlb_dbg(CMLB_INFO, cl,
2017 " ncyl: %ld; acyl: %d; nhead: %d; nsect: %d\n",
2018 cl->cl_pgeom.g_ncyl, cl->cl_pgeom.g_acyl,
2019 cl->cl_pgeom.g_nhead, cl->cl_pgeom.g_nsect);
2020 cmlb_dbg(CMLB_INFO, cl, " lbasize: %d; capacity: %ld; "
2021 "intrlv: %d; rpm: %d\n", cl->cl_pgeom.g_secsize,
2022 cl->cl_pgeom.g_capacity, cl->cl_pgeom.g_intrlv,
2023 cl->cl_pgeom.g_rpm);
2024 }
2025
2026
2027 #if defined(__i386) || defined(__amd64)
2028 /*
2029 * Function: cmlb_update_ext_minor_nodes
2030 *
2031 * Description: Routine to add/remove extended partition device nodes
2032 *
2033 * Arguments:
2034 * cl driver soft state (unit) structure
2035 * num_parts Number of logical drives found on the LUN
2036 *
2037 * Should be called with the mutex held
2038 *
2039 * Return Code: 0 for success
2040 *
2041 * Context: User and Kernel thread
2042 *
2043 */
2044 static int
2045 cmlb_update_ext_minor_nodes(struct cmlb_lun *cl, int num_parts)
2046 {
2047 int i, count;
2048 char name[48];
2049 int instance;
2050 struct driver_minor_data *demdp, *demdpr;
2051 char *devnm;
2052 dev_info_t *pdip;
2053 boolean_t internal;
2054
2055 ASSERT(mutex_owned(CMLB_MUTEX(cl)));
2056 ASSERT(cl->cl_update_ext_minor_nodes == 1);
2057
2058 internal = VOID2BOOLEAN(
2059 (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0);
2060 instance = ddi_get_instance(CMLB_DEVINFO(cl));
2061 demdp = dk_ext_minor_data;
2062 demdpr = &dk_ext_minor_data[MAX_EXT_PARTS];
2063
2064
2065 if (cl->cl_logical_drive_count) {
2066 for (i = 0; i < cl->cl_logical_drive_count; i++) {
2067 (void) sprintf(name, "%s", demdp->name);
2068 ddi_remove_minor_node(CMLB_DEVINFO(cl), name);
2069 (void) sprintf(name, "%s", demdpr->name);
2070 ddi_remove_minor_node(CMLB_DEVINFO(cl), name);
2071 demdp++;
2072 demdpr++;
2073 }
2074 /* There are existing device nodes. Remove them */
2075 devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
2076 (void) ddi_deviname(cl->cl_devi, devnm);
2077 pdip = ddi_get_parent(cl->cl_devi);
2078 (void) devfs_clean(pdip, devnm + 1, DV_CLEAN_FORCE);
2079 kmem_free(devnm, MAXNAMELEN + 1);
2080 }
2081
2082 demdp = dk_ext_minor_data;
2083 demdpr = &dk_ext_minor_data[MAX_EXT_PARTS];
2084
2085 for (i = 0; i < num_parts; i++) {
2086 (void) sprintf(name, "%s", demdp->name);
2087 if (cmlb_create_minor(CMLB_DEVINFO(cl), name,
2088 demdp->type,
2089 (instance << CMLBUNIT_SHIFT) | demdp->minor,
2090 cl->cl_node_type, NULL, internal) == DDI_FAILURE) {
2091 /*
2092 * Clean up any nodes that may have been
2093 * created, in case this fails in the middle
2094 * of the loop.
2095 */
2096 ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL);
2097 cl->cl_logical_drive_count = 0;
2098 return (ENXIO);
2099 }
2100 (void) sprintf(name, "%s", demdpr->name);
2101 if (ddi_create_minor_node(CMLB_DEVINFO(cl), name,
2102 demdpr->type,
2103 (instance << CMLBUNIT_SHIFT) | demdpr->minor,
2104 cl->cl_node_type, NULL) == DDI_FAILURE) {
2105 /*
2106 * Clean up any nodes that may have been
2107 * created, in case this fails in the middle
2108 * of the loop.
2109 */
2110 ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL);
2111 cl->cl_logical_drive_count = 0;
2112 return (ENXIO);
2113 }
2114 demdp++;
2115 demdpr++;
2116 }
2117
2118 /* Update the cl_map array for logical drives */
2119 for (count = 0; count < MAX_EXT_PARTS; count++) {
2120 cl->cl_map[FDISK_P4 + 1 + count].dkl_cylno = UINT32_MAX;
2121 cl->cl_map[FDISK_P4 + 1 + count].dkl_nblk =
2122 cl->cl_fmap[FD_NUMPART + count].fmap_nblk;
2123 cl->cl_offset[FDISK_P4 + 1 + count] =
2124 cl->cl_fmap[FD_NUMPART + count].fmap_start;
2125 }
2126
2127 cl->cl_logical_drive_count = i;
2128 cl->cl_update_ext_minor_nodes = 0;
2129 return (0);
2130 }
2131 /*
2132 * Function: cmlb_validate_ext_part
2133 *
2134 * Description: utility routine to validate an extended partition's
2135 * metadata as found on disk
2136 *
2137 * Arguments:
2138 * cl driver soft state (unit) structure
2139 * part partition number of the extended partition
2140 * epart partition number of the logical drive
2141 * start absolute sector number of the start of the logical
2142 * drive being validated
2143 * size size of logical drive being validated
2144 *
2145 * Return Code: 0 for success
2146 *
2147 * Context: User and Kernel thread
2148 *
2149 * Algorithm :
2150 * Error cases are :
2151 * 1. If start block is lesser than or equal to the end block
2152 * 2. If either start block or end block is beyond the bounadry
2153 * of the extended partition.
2154 * 3. start or end block overlap with existing partitions.
2155 * To check this, first make sure that the start block doesnt
2156 * overlap with existing partitions. Then, calculate the
2157 * possible end block for the given start block that doesnt
2158 * overlap with existing partitions. This can be calculated by
2159 * first setting the possible end block to the end of the
2160 * extended partition (optimistic) and then, checking if there
2161 * is any other partition that lies after the start of the
2162 * partition being validated. If so, set the possible end to
2163 * one block less than the beginning of the next nearest partition
2164 * If the actual end block is greater than the calculated end
2165 * block, we have an overlap.
2166 *
2167 */
2168 static int
2169 cmlb_validate_ext_part(struct cmlb_lun *cl, int part, int epart, uint32_t start,
2170 uint32_t size)
2171 {
2172 int i;
2173 uint32_t end = start + size - 1;
2174 uint32_t ext_start = cl->cl_fmap[part].fmap_start;
2175 uint32_t ext_end = ext_start + cl->cl_fmap[part].fmap_nblk - 1;
2176 uint32_t ts, te;
2177 uint32_t poss_end = ext_end;
2178
2179 if (end <= start) {
2180 return (1);
2181 }
2182
2183 /*
2184 * Check if the logical drive boundaries are within that of the
2185 * extended partition.
2186 */
2187 if (start <= ext_start || start > ext_end || end <= ext_start ||
2188 end > ext_end) {
2189 return (1);
2190 }
2191
2192 /*
2193 * epart will be equal to FD_NUMPART if it is the first logical drive.
2194 * There is no need to check for overlaps with other logical drives,
2195 * since it is the only logical drive that we have come across so far.
2196 */
2197 if (epart == FD_NUMPART) {
2198 return (0);
2199 }
2200
2201 /* Check for overlaps with existing logical drives */
2202 i = FD_NUMPART;
2203 ts = cl->cl_fmap[FD_NUMPART].fmap_start;
2204 te = ts + cl->cl_fmap[FD_NUMPART].fmap_nblk - 1;
2205
2206 while ((i < epart) && ts && te) {
2207 if (start >= ts && start <= te) {
2208 return (1);
2209 }
2210
2211 if ((ts < poss_end) && (ts > start)) {
2212 poss_end = ts - 1;
2213 }
2214
2215 i++;
2216 ts = cl->cl_fmap[i].fmap_start;
2217 te = ts + cl->cl_fmap[i].fmap_nblk - 1;
2218 }
2219
2220 if (end > poss_end) {
2221 return (1);
2222 }
2223
2224 return (0);
2225 }
2226
2227
2228 /*
2229 * Function: cmlb_is_linux_swap
2230 *
2231 * Description: utility routine to verify if a partition is a linux swap
2232 * partition or not.
2233 *
2234 * Arguments:
2235 * cl driver soft state (unit) structure
2236 * part_start absolute sector number of the start of the partition
2237 * being verified
2238 * tg_cookie cookie from target driver to be passed back to target
2239 * driver when we call back to it through tg_ops.
2240 *
2241 * Return Code: 0 for success
2242 *
2243 * Context: User and Kernel thread
2244 *
2245 * Notes:
2246 * The linux swap magic "SWAP-SPACE" or "SWAPSPACE2" is found as the
2247 * last 10 bytes of a disk block whose size is that of the linux page
2248 * size. This disk block is found at the beginning of the swap partition.
2249 */
2250 static int
2251 cmlb_is_linux_swap(struct cmlb_lun *cl, uint32_t part_start, void *tg_cookie)
2252 {
2253 int i;
2254 int rval = -1;
2255 uint32_t seek_offset;
2256 uint32_t linux_pg_size;
2257 char *buf, *linux_swap_magic;
2258 int sec_sz = cl->cl_sys_blocksize;
2259 /* Known linux kernel page sizes */
2260 uint32_t linux_pg_size_arr[] = {4096, };
2261
2262 ASSERT(cl != NULL);
2263 ASSERT(mutex_owned(CMLB_MUTEX(cl)));
2264
2265 if ((buf = kmem_zalloc(sec_sz, KM_NOSLEEP)) == NULL) {
2266 return (ENOMEM);
2267 }
2268
2269 /*
2270 * Check if there is a sane Solaris VTOC
2271 * If there is a valid vtoc, no need to lookup
2272 * for the linux swap signature.
2273 */
2274 mutex_exit(CMLB_MUTEX(cl));
2275 rval = DK_TG_READ(cl, buf, part_start + DK_LABEL_LOC,
2276 sec_sz, tg_cookie);
2277 mutex_enter(CMLB_MUTEX(cl));
2278 if (rval != 0) {
2279 cmlb_dbg(CMLB_ERROR, cl,
2280 "cmlb_is_linux_swap: disk vtoc read err\n");
2281 rval = EIO;
2282 goto done;
2283 }
2284
2285 if ((((struct dk_label *)buf)->dkl_magic == DKL_MAGIC) &&
2286 (((struct dk_label *)buf)->dkl_vtoc.v_sanity == VTOC_SANE)) {
2287 rval = -1;
2288 goto done;
2289 }
2290
2291
2292 /* No valid vtoc, so check for linux swap signature */
2293 linux_swap_magic = buf + sec_sz - 10;
2294
2295 for (i = 0; i < sizeof (linux_pg_size_arr)/sizeof (uint32_t); i++) {
2296 linux_pg_size = linux_pg_size_arr[i];
2297 seek_offset = linux_pg_size/sec_sz - 1;
2298 seek_offset += part_start;
2299
2300 mutex_exit(CMLB_MUTEX(cl));
2301 rval = DK_TG_READ(cl, buf, seek_offset, sec_sz, tg_cookie);
2302 mutex_enter(CMLB_MUTEX(cl));
2303
2304 if (rval != 0) {
2305 cmlb_dbg(CMLB_ERROR, cl,
2306 "cmlb_is_linux_swap: disk read err\n");
2307 rval = EIO;
2308 break;
2309 }
2310
2311 rval = -1;
2312
2313 if ((strncmp(linux_swap_magic, "SWAP-SPACE", 10) == 0) ||
2314 (strncmp(linux_swap_magic, "SWAPSPACE2", 10) == 0)) {
2315 /* Found a linux swap */
2316 rval = 0;
2317 break;
2318 }
2319 }
2320
2321 done:
2322 kmem_free(buf, sec_sz);
2323 return (rval);
2324 }
2325 #endif
2326
2327 /*
2328 * Function: cmlb_read_fdisk
2329 *
2330 * Description: utility routine to read the fdisk table.
2331 *
2332 * Arguments:
2333 * cl driver soft state (unit) structure
2334 * capacity disk capacity in #blocks
2335 * tg_cookie cookie from target driver to be passed back to target
2336 * driver when we call back to it through tg_ops.
2337 *
2338 * Return Code: 0 for success (includes not reading for no_fdisk_present case
2339 * errnos from tg_rw if failed to read the first block.
2340 *
2341 * Context: Kernel thread only (can sleep).
2342 */
2343 /*ARGSUSED*/
2344 static int
2345 cmlb_read_fdisk(struct cmlb_lun *cl, diskaddr_t capacity, void *tg_cookie)
2346 {
2347 #if defined(_NO_FDISK_PRESENT)
2348
2349 cl->cl_solaris_offset = 0;
2350 cl->cl_solaris_size = capacity;
2351 bzero(cl->cl_fmap, sizeof (struct fmap) * FD_NUMPART);
2352 return (0);
2353
2354 #elif defined(_FIRMWARE_NEEDS_FDISK)
2355
2356 struct ipart *fdp;
2357 struct mboot *mbp;
2358 struct ipart fdisk[FD_NUMPART];
2359 int i, k;
2360 char sigbuf[2];
2361 caddr_t bufp;
2362 int uidx;
2363 int rval;
2364 int lba = 0;
2365 uint_t solaris_offset; /* offset to solaris part. */
2366 daddr_t solaris_size; /* size of solaris partition */
2367 uint32_t blocksize;
2368 #if defined(__i386) || defined(__amd64)
2369 struct ipart eparts[2];
2370 struct ipart *efdp1 = &eparts[0];
2371 struct ipart *efdp2 = &eparts[1];
2372 int ext_part_exists = 0;
2373 int ld_count = 0;
2374 #endif
2375
2376 ASSERT(cl != NULL);
2377 ASSERT(mutex_owned(CMLB_MUTEX(cl)));
2378
2379 /*
2380 * Start off assuming no fdisk table
2381 */
2382 solaris_offset = 0;
2383 solaris_size = capacity;
2384
2385 blocksize = cl->cl_tgt_blocksize;
2386
2387 bufp = kmem_zalloc(blocksize, KM_SLEEP);
2388
2389 mutex_exit(CMLB_MUTEX(cl));
2390 rval = DK_TG_READ(cl, bufp, 0, blocksize, tg_cookie);
2391 mutex_enter(CMLB_MUTEX(cl));
2392
2393 if (rval != 0) {
2394 cmlb_dbg(CMLB_ERROR, cl,
2395 "cmlb_read_fdisk: fdisk read err\n");
2396 bzero(cl->cl_fmap, sizeof (struct fmap) * FD_NUMPART);
2397 goto done;
2398 }
2399
2400 mbp = (struct mboot *)bufp;
2401
2402 /*
2403 * The fdisk table does not begin on a 4-byte boundary within the
2404 * master boot record, so we copy it to an aligned structure to avoid
2405 * alignment exceptions on some processors.
2406 */
2407 bcopy(&mbp->parts[0], fdisk, sizeof (fdisk));
2408
2409 /*
2410 * Check for lba support before verifying sig; sig might not be
2411 * there, say on a blank disk, but the max_chs mark may still
2412 * be present.
2413 *
2414 * Note: LBA support and BEFs are an x86-only concept but this
2415 * code should work OK on SPARC as well.
2416 */
2417
2418 /*
2419 * First, check for lba-access-ok on root node (or prom root node)
2420 * if present there, don't need to search fdisk table.
2421 */
2422 if (ddi_getprop(DDI_DEV_T_ANY, ddi_root_node(), 0,
2423 "lba-access-ok", 0) != 0) {
2424 /* All drives do LBA; don't search fdisk table */
2425 lba = 1;
2426 } else {
2427 /* Okay, look for mark in fdisk table */
2428 for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) {
2429 /* accumulate "lba" value from all partitions */
2430 lba = (lba || cmlb_has_max_chs_vals(fdp));
2431 }
2432 }
2433
2434 if (lba != 0) {
2435 dev_t dev = cmlb_make_device(cl);
2436
2437 if (ddi_getprop(dev, CMLB_DEVINFO(cl), DDI_PROP_DONTPASS,
2438 "lba-access-ok", 0) == 0) {
2439 /* not found; create it */
2440 if (ddi_prop_create(dev, CMLB_DEVINFO(cl), 0,
2441 "lba-access-ok", (caddr_t)NULL, 0) !=
2442 DDI_PROP_SUCCESS) {
2443 cmlb_dbg(CMLB_ERROR, cl,
2444 "cmlb_read_fdisk: Can't create lba "
2445 "property for instance %d\n",
2446 ddi_get_instance(CMLB_DEVINFO(cl)));
2447 }
2448 }
2449 }
2450
2451 bcopy(&mbp->signature, sigbuf, sizeof (sigbuf));
2452
2453 /*
2454 * Endian-independent signature check
2455 */
2456 if (((sigbuf[1] & 0xFF) != ((MBB_MAGIC >> 8) & 0xFF)) ||
2457 (sigbuf[0] != (MBB_MAGIC & 0xFF))) {
2458 cmlb_dbg(CMLB_ERROR, cl,
2459 "cmlb_read_fdisk: no fdisk\n");
2460 bzero(cl->cl_fmap, sizeof (struct fmap) * FD_NUMPART);
2461 goto done;
2462 }
2463
2464 #ifdef CMLBDEBUG
2465 if (cmlb_level_mask & CMLB_LOGMASK_INFO) {
2466 fdp = fdisk;
2467 cmlb_dbg(CMLB_INFO, cl, "cmlb_read_fdisk:\n");
2468 cmlb_dbg(CMLB_INFO, cl, " relsect "
2469 "numsect sysid bootid\n");
2470 for (i = 0; i < FD_NUMPART; i++, fdp++) {
2471 cmlb_dbg(CMLB_INFO, cl,
2472 " %d: %8d %8d 0x%08x 0x%08x\n",
2473 i, fdp->relsect, fdp->numsect,
2474 fdp->systid, fdp->bootid);
2475 }
2476 }
2477 #endif
2478
2479 /*
2480 * Try to find the unix partition
2481 */
2482 uidx = -1;
2483 solaris_offset = 0;
2484 solaris_size = 0;
2485
2486 for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) {
2487 uint32_t relsect;
2488 uint32_t numsect;
2489 uchar_t systid;
2490 #if defined(__i386) || defined(__amd64)
2491 /*
2492 * Stores relative block offset from the beginning of the
2493 * Extended Partition.
2494 */
2495 int ext_relsect = 0;
2496 #endif
2497
2498 if (fdp->numsect == 0) {
2499 cl->cl_fmap[i].fmap_start = 0;
2500 cl->cl_fmap[i].fmap_nblk = 0;
2501 continue;
2502 }
2503
2504 /*
2505 * Data in the fdisk table is little-endian.
2506 */
2507 relsect = LE_32(fdp->relsect);
2508 numsect = LE_32(fdp->numsect);
2509
2510 cl->cl_fmap[i].fmap_start = relsect;
2511 cl->cl_fmap[i].fmap_nblk = numsect;
2512 cl->cl_fmap[i].fmap_systid = LE_8(fdp->systid);
2513
2514 #if defined(__i386) || defined(__amd64)
2515 /* Support only one extended partition per LUN */
2516 if ((fdp->systid == EXTDOS || fdp->systid == FDISK_EXTLBA) &&
2517 (ext_part_exists == 0)) {
2518 int j;
2519 uint32_t logdrive_offset;
2520 uint32_t ext_numsect;
2521 uint32_t abs_secnum;
2522
2523 ext_part_exists = 1;
2524
2525 for (j = FD_NUMPART; j < FDISK_PARTS; j++) {
2526 mutex_exit(CMLB_MUTEX(cl));
2527 rval = DK_TG_READ(cl, bufp,
2528 (relsect + ext_relsect), blocksize,
2529 tg_cookie);
2530 mutex_enter(CMLB_MUTEX(cl));
2531
2532 if (rval != 0) {
2533 cmlb_dbg(CMLB_ERROR, cl,
2534 "cmlb_read_fdisk: Extended "
2535 "partition read err\n");
2536 goto done;
2537 }
2538 /*
2539 * The first ipart entry provides the offset
2540 * at which the logical drive starts off from
2541 * the beginning of the container partition
2542 * and the size of the logical drive.
2543 * The second ipart entry provides the offset
2544 * of the next container partition from the
2545 * beginning of the extended partition.
2546 */
2547 bcopy(&bufp[FDISK_PART_TABLE_START], eparts,
2548 sizeof (eparts));
2549 logdrive_offset = LE_32(efdp1->relsect);
2550 ext_numsect = LE_32(efdp1->numsect);
2551 systid = LE_8(efdp1->systid);
2552 if (logdrive_offset <= 0 || ext_numsect <= 0)
2553 break;
2554 abs_secnum = relsect + ext_relsect +
2555 logdrive_offset;
2556
2557 /* Boundary condition and overlap checking */
2558 if (cmlb_validate_ext_part(cl, i, j, abs_secnum,
2559 ext_numsect)) {
2560 break;
2561 }
2562
2563 if ((cl->cl_fmap[j].fmap_start != abs_secnum) ||
2564 (cl->cl_fmap[j].fmap_nblk != ext_numsect) ||
2565 (cl->cl_fmap[j].fmap_systid != systid)) {
2566 /*
2567 * Indicates change from previous
2568 * partinfo. Need to recreate
2569 * logical device nodes.
2570 */
2571 cl->cl_update_ext_minor_nodes = 1;
2572 }
2573 cl->cl_fmap[j].fmap_start = abs_secnum;
2574 cl->cl_fmap[j].fmap_nblk = ext_numsect;
2575 cl->cl_fmap[j].fmap_systid = systid;
2576 ld_count++;
2577
2578 if ((efdp1->systid == SUNIXOS &&
2579 (cmlb_is_linux_swap(cl, abs_secnum,
2580 tg_cookie) != 0)) ||
2581 efdp1->systid == SUNIXOS2) {
2582 if (uidx == -1) {
2583 uidx = 0;
2584 solaris_offset = abs_secnum;
2585 solaris_size = ext_numsect;
2586 }
2587 }
2588
2589 if ((ext_relsect = LE_32(efdp2->relsect)) == 0)
2590 break;
2591 }
2592 }
2593
2594 #endif
2595
2596 if (fdp->systid != SUNIXOS &&
2597 fdp->systid != SUNIXOS2 &&
2598 fdp->systid != EFI_PMBR) {
2599 continue;
2600 }
2601
2602 /*
2603 * use the last active solaris partition id found
2604 * (there should only be 1 active partition id)
2605 *
2606 * if there are no active solaris partition id
2607 * then use the first inactive solaris partition id
2608 */
2609 if ((uidx == -1) || (fdp->bootid == ACTIVE)) {
2610 #if defined(__i386) || defined(__amd64)
2611 if (fdp->systid != SUNIXOS ||
2612 (fdp->systid == SUNIXOS &&
2613 (cmlb_is_linux_swap(cl, relsect,
2614 tg_cookie) != 0))) {
2615 #endif
2616 uidx = i;
2617 solaris_offset = relsect;
2618 solaris_size = numsect;
2619 #if defined(__i386) || defined(__amd64)
2620 }
2621 #endif
2622 }
2623 }
2624 #if defined(__i386) || defined(__amd64)
2625 if (ld_count < cl->cl_logical_drive_count) {
2626 /*
2627 * Some/all logical drives were deleted. Clear out
2628 * the fmap entries correspoding to those deleted drives.
2629 */
2630 for (k = ld_count + FD_NUMPART;
2631 k < cl->cl_logical_drive_count + FD_NUMPART; k++) {
2632 cl->cl_fmap[k].fmap_start = 0;
2633 cl->cl_fmap[k].fmap_nblk = 0;
2634 cl->cl_fmap[k].fmap_systid = 0;
2635 }
2636 cl->cl_update_ext_minor_nodes = 1;
2637 }
2638 if (cl->cl_update_ext_minor_nodes) {
2639 rval = cmlb_update_ext_minor_nodes(cl, ld_count);
2640 if (rval != 0) {
2641 goto done;
2642 }
2643 }
2644 #endif
2645 cmlb_dbg(CMLB_INFO, cl, "fdisk 0x%x 0x%lx",
2646 cl->cl_solaris_offset, cl->cl_solaris_size);
2647 done:
2648
2649 /*
2650 * Clear the VTOC info, only if the Solaris partition entry
2651 * has moved, changed size, been deleted, or if the size of
2652 * the partition is too small to even fit the label sector.
2653 */
2654 if ((cl->cl_solaris_offset != solaris_offset) ||
2655 (cl->cl_solaris_size != solaris_size) ||
2656 solaris_size <= DK_LABEL_LOC) {
2657 cmlb_dbg(CMLB_INFO, cl, "fdisk moved 0x%x 0x%lx",
2658 solaris_offset, solaris_size);
2659 bzero(&cl->cl_g, sizeof (struct dk_geom));
2660 bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc));
2661 bzero(&cl->cl_map, NDKMAP * (sizeof (struct dk_map)));
2662 cl->cl_f_geometry_is_valid = B_FALSE;
2663 }
2664 cl->cl_solaris_offset = solaris_offset;
2665 cl->cl_solaris_size = solaris_size;
2666 kmem_free(bufp, blocksize);
2667 return (rval);
2668
2669 #else /* #elif defined(_FIRMWARE_NEEDS_FDISK) */
2670 #error "fdisk table presence undetermined for this platform."
2671 #endif /* #if defined(_NO_FDISK_PRESENT) */
2672 }
2673
2674 static void
2675 cmlb_swap_efi_gpt(efi_gpt_t *e)
2676 {
2677 _NOTE(ASSUMING_PROTECTED(*e))
2678 e->efi_gpt_Signature = LE_64(e->efi_gpt_Signature);
2679 e->efi_gpt_Revision = LE_32(e->efi_gpt_Revision);
2680 e->efi_gpt_HeaderSize = LE_32(e->efi_gpt_HeaderSize);
2681 e->efi_gpt_HeaderCRC32 = LE_32(e->efi_gpt_HeaderCRC32);
2682 e->efi_gpt_MyLBA = LE_64(e->efi_gpt_MyLBA);
2683 e->efi_gpt_AlternateLBA = LE_64(e->efi_gpt_AlternateLBA);
2684 e->efi_gpt_FirstUsableLBA = LE_64(e->efi_gpt_FirstUsableLBA);
2685 e->efi_gpt_LastUsableLBA = LE_64(e->efi_gpt_LastUsableLBA);
2686 UUID_LE_CONVERT(e->efi_gpt_DiskGUID, e->efi_gpt_DiskGUID);
2687 e->efi_gpt_PartitionEntryLBA = LE_64(e->efi_gpt_PartitionEntryLBA);
2688 e->efi_gpt_NumberOfPartitionEntries =
2689 LE_32(e->efi_gpt_NumberOfPartitionEntries);
2690 e->efi_gpt_SizeOfPartitionEntry =
2691 LE_32(e->efi_gpt_SizeOfPartitionEntry);
2692 e->efi_gpt_PartitionEntryArrayCRC32 =
2693 LE_32(e->efi_gpt_PartitionEntryArrayCRC32);
2694 }
2695
2696 static void
2697 cmlb_swap_efi_gpe(int nparts, efi_gpe_t *p)
2698 {
2699 int i;
2700
2701 _NOTE(ASSUMING_PROTECTED(*p))
2702 for (i = 0; i < nparts; i++) {
2703 UUID_LE_CONVERT(p[i].efi_gpe_PartitionTypeGUID,
2704 p[i].efi_gpe_PartitionTypeGUID);
2705 p[i].efi_gpe_StartingLBA = LE_64(p[i].efi_gpe_StartingLBA);
2706 p[i].efi_gpe_EndingLBA = LE_64(p[i].efi_gpe_EndingLBA);
2707 /* PartitionAttrs */
2708 }
2709 }
2710
2711 static int
2712 cmlb_validate_efi(efi_gpt_t *labp)
2713 {
2714 if (labp->efi_gpt_Signature != EFI_SIGNATURE)
2715 return (EINVAL);
2716 /* at least 96 bytes in this version of the spec. */
2717 if (sizeof (efi_gpt_t) - sizeof (labp->efi_gpt_Reserved2) >
2718 labp->efi_gpt_HeaderSize)
2719 return (EINVAL);
2720 /* this should be 128 bytes */
2721 if (labp->efi_gpt_SizeOfPartitionEntry != sizeof (efi_gpe_t))
2722 return (EINVAL);
2723 return (0);
2724 }
2725
2726 /*
2727 * This function returns B_FALSE if there is a valid MBR signature and no
2728 * partition table entries of type EFI_PMBR (0xEE). Otherwise it returns B_TRUE.
2729 *
2730 * The EFI spec (1.10 and later) requires having a Protective MBR (PMBR) to
2731 * recognize the disk as GPT partitioned. However, some other OS creates an MBR
2732 * where a PMBR entry is not the only one. Also, if the first block has been
2733 * corrupted, currently best attempt to allow data access would be to try to
2734 * check for GPT headers. Hence in case of more than one partition entry, but
2735 * at least one EFI_PMBR partition type or no valid magic number, the function
2736 * returns B_TRUE to continue with looking for GPT header.
2737 */
2738
2739 static boolean_t
2740 cmlb_check_efi_mbr(uchar_t *buf, boolean_t *is_mbr)
2741 {
2742 struct ipart *fdp;
2743 struct mboot *mbp = (struct mboot *)buf;
2744 struct ipart fdisk[FD_NUMPART];
2745 int i;
2746
2747 if (is_mbr != NULL)
2748 *is_mbr = B_TRUE;
2749
2750 if (LE_16(mbp->signature) != MBB_MAGIC) {
2751 if (is_mbr != NULL)
2752 *is_mbr = B_FALSE;
2753 return (B_TRUE);
2754 }
2755
2756 bcopy(&mbp->parts[0], fdisk, sizeof (fdisk));
2757
2758 for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) {
2759 if (fdp->systid == EFI_PMBR)
2760 return (B_TRUE);
2761 }
2762
2763 return (B_FALSE);
2764 }
2765
2766 static int
2767 cmlb_use_efi(struct cmlb_lun *cl, diskaddr_t capacity, int flags,
2768 void *tg_cookie)
2769 {
2770 int i;
2771 int rval = 0;
2772 efi_gpe_t *partitions;
2773 uchar_t *buf;
2774 uint_t lbasize; /* is really how much to read */
2775 diskaddr_t cap = 0;
2776 uint_t nparts;
2777 diskaddr_t gpe_lba;
2778 diskaddr_t alternate_lba;
2779 int iofailed = 0;
2780 struct uuid uuid_type_reserved = EFI_RESERVED;
2781 #if defined(_FIRMWARE_NEEDS_FDISK)
2782 boolean_t is_mbr;
2783 #endif
2784
2785 ASSERT(mutex_owned(CMLB_MUTEX(cl)));
2786
2787 lbasize = cl->cl_sys_blocksize;
2788
2789 cl->cl_reserved = -1;
2790 mutex_exit(CMLB_MUTEX(cl));
2791
2792 buf = kmem_zalloc(EFI_MIN_ARRAY_SIZE, KM_SLEEP);
2793
2794 rval = DK_TG_READ(cl, buf, 0, lbasize, tg_cookie);
2795 if (rval) {
2796 iofailed = 1;
2797 goto done_err;
2798 }
2799 if (((struct dk_label *)buf)->dkl_magic == DKL_MAGIC) {
2800 /* not ours */
2801 rval = ESRCH;
2802 goto done_err;
2803 }
2804
2805 #if defined(_FIRMWARE_NEEDS_FDISK)
2806 if (!cmlb_check_efi_mbr(buf, &is_mbr)) {
2807 if (is_mbr)
2808 rval = ESRCH;
2809 else
2810 rval = EINVAL;
2811 goto done_err;
2812 }
2813 #else
2814 if (!cmlb_check_efi_mbr(buf, NULL)) {
2815 rval = EINVAL;
2816 goto done_err;
2817 }
2818
2819 #endif
2820
2821 rval = DK_TG_READ(cl, buf, 1, lbasize, tg_cookie);
2822 if (rval) {
2823 iofailed = 1;
2824 goto done_err;
2825 }
2826 cmlb_swap_efi_gpt((efi_gpt_t *)buf);
2827
2828 if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) {
2829 /*
2830 * Couldn't read the primary, try the backup. Our
2831 * capacity at this point could be based on CHS, so
2832 * check what the device reports.
2833 */
2834 rval = DK_TG_GETCAP(cl, &cap, tg_cookie);
2835 if (rval) {
2836 iofailed = 1;
2837 goto done_err;
2838 }
2839
2840 /*
2841 * CMLB_OFF_BY_ONE case, we check the next to last block first
2842 * for backup GPT header, otherwise check the last block.
2843 */
2844
2845 if ((rval = DK_TG_READ(cl, buf,
2846 cap - ((cl->cl_alter_behavior & CMLB_OFF_BY_ONE) ? 2 : 1),
2847 lbasize, tg_cookie))
2848 != 0) {
2849 iofailed = 1;
2850 goto done_err;
2851 }
2852 cmlb_swap_efi_gpt((efi_gpt_t *)buf);
2853
2854 if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) {
2855
2856 if (!(cl->cl_alter_behavior & CMLB_OFF_BY_ONE))
2857 goto done_err;
2858 if ((rval = DK_TG_READ(cl, buf, cap - 1, lbasize,
2859 tg_cookie)) != 0)
2860 goto done_err;
2861 cmlb_swap_efi_gpt((efi_gpt_t *)buf);
2862 if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0)
2863 goto done_err;
2864 }
2865 if (!(flags & CMLB_SILENT))
2866 cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN,
2867 "primary label corrupt; using backup\n");
2868 }
2869
2870 nparts = ((efi_gpt_t *)buf)->efi_gpt_NumberOfPartitionEntries;
2871 gpe_lba = ((efi_gpt_t *)buf)->efi_gpt_PartitionEntryLBA;
2872 alternate_lba = ((efi_gpt_t *)buf)->efi_gpt_AlternateLBA;
2873
2874 rval = DK_TG_READ(cl, buf, gpe_lba, EFI_MIN_ARRAY_SIZE, tg_cookie);
2875 if (rval) {
2876 iofailed = 1;
2877 goto done_err;
2878 }
2879 partitions = (efi_gpe_t *)buf;
2880
2881 if (nparts > MAXPART) {
2882 nparts = MAXPART;
2883 }
2884 cmlb_swap_efi_gpe(nparts, partitions);
2885
2886 mutex_enter(CMLB_MUTEX(cl));
2887
2888 /* Fill in partition table. */
2889 for (i = 0; i < nparts; i++) {
2890 if (partitions->efi_gpe_StartingLBA != 0 ||
2891 partitions->efi_gpe_EndingLBA != 0) {
2892 cl->cl_map[i].dkl_cylno =
2893 partitions->efi_gpe_StartingLBA;
2894 cl->cl_map[i].dkl_nblk =
2895 partitions->efi_gpe_EndingLBA -
2896 partitions->efi_gpe_StartingLBA + 1;
2897 cl->cl_offset[i] =
2898 partitions->efi_gpe_StartingLBA;
2899 }
2900
2901 if (cl->cl_reserved == -1) {
2902 if (bcmp(&partitions->efi_gpe_PartitionTypeGUID,
2903 &uuid_type_reserved, sizeof (struct uuid)) == 0) {
2904 cl->cl_reserved = i;
2905 }
2906 }
2907 if (i == WD_NODE) {
2908 /*
2909 * minor number 7 corresponds to the whole disk
2910 * if the disk capacity is expanded after disk is
2911 * labeled, minor number 7 represents the capacity
2912 * indicated by the disk label.
2913 */
2914 cl->cl_map[i].dkl_cylno = 0;
2915 if (alternate_lba == 1) {
2916 /*
2917 * We are using backup label. Since we can
2918 * find a valid label at the end of disk,
2919 * the disk capacity is not expanded.
2920 */
2921 cl->cl_map[i].dkl_nblk = capacity;
2922 } else {
2923 cl->cl_map[i].dkl_nblk = alternate_lba + 1;
2924 }
2925 cl->cl_offset[i] = 0;
2926 }
2927 partitions++;
2928 }
2929 cl->cl_solaris_offset = 0;
2930 cl->cl_solaris_size = capacity;
2931 cl->cl_label_from_media = CMLB_LABEL_EFI;
2932 cl->cl_f_geometry_is_valid = B_TRUE;
2933
2934 /* clear the vtoc label */
2935 bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc));
2936
2937 kmem_free(buf, EFI_MIN_ARRAY_SIZE);
2938 return (0);
2939
2940 done_err:
2941 kmem_free(buf, EFI_MIN_ARRAY_SIZE);
2942 mutex_enter(CMLB_MUTEX(cl));
2943 done_err1:
2944 /*
2945 * if we didn't find something that could look like a VTOC
2946 * and the disk is over 1TB, we know there isn't a valid label.
2947 * Otherwise let cmlb_uselabel decide what to do. We only
2948 * want to invalidate this if we're certain the label isn't
2949 * valid because cmlb_prop_op will now fail, which in turn
2950 * causes things like opens and stats on the partition to fail.
2951 */
2952 if ((capacity > CMLB_EXTVTOC_LIMIT) && (rval != ESRCH) && !iofailed) {
2953 cl->cl_f_geometry_is_valid = B_FALSE;
2954 }
2955 return (rval);
2956 }
2957
2958
2959 /*
2960 * Function: cmlb_uselabel
2961 *
2962 * Description: Validate the disk label and update the relevant data (geometry,
2963 * partition, vtoc, and capacity data) in the cmlb_lun struct.
2964 * Marks the geometry of the unit as being valid.
2965 *
2966 * Arguments: cl: unit struct.
2967 * dk_label: disk label
2968 *
2969 * Return Code: CMLB_LABEL_IS_VALID: Label read from disk is OK; geometry,
2970 * partition, vtoc, and capacity data are good.
2971 *
2972 * CMLB_LABEL_IS_INVALID: Magic number or checksum error in the
2973 * label; or computed capacity does not jibe with capacity
2974 * reported from the READ CAPACITY command.
2975 *
2976 * Context: Kernel thread only (can sleep).
2977 */
2978 static int
2979 cmlb_uselabel(struct cmlb_lun *cl, struct dk_label *labp, int flags)
2980 {
2981 short *sp;
2982 short sum;
2983 short count;
2984 int label_error = CMLB_LABEL_IS_VALID;
2985 int i;
2986 diskaddr_t label_capacity;
2987 uint32_t part_end;
2988 diskaddr_t track_capacity;
2989 #if defined(_SUNOS_VTOC_16)
2990 struct dkl_partition *vpartp;
2991 #endif
2992 ASSERT(cl != NULL);
2993 ASSERT(mutex_owned(CMLB_MUTEX(cl)));
2994
2995 /* Validate the magic number of the label. */
2996 if (labp->dkl_magic != DKL_MAGIC) {
2997 #if defined(__sparc)
2998 if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) {
2999 if (!(flags & CMLB_SILENT))
3000 cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl),
3001 CE_WARN,
3002 "Corrupt label; wrong magic number\n");
3003 }
3004 #endif
3005 return (CMLB_LABEL_IS_INVALID);
3006 }
3007
3008 /* Validate the checksum of the label. */
3009 sp = (short *)labp;
3010 sum = 0;
3011 count = sizeof (struct dk_label) / sizeof (short);
3012 while (count--) {
3013 sum ^= *sp++;
3014 }
3015
3016 if (sum != 0) {
3017 #if defined(_SUNOS_VTOC_16)
3018 if (!ISCD(cl)) {
3019 #elif defined(_SUNOS_VTOC_8)
3020 if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) {
3021 #endif
3022 if (!(flags & CMLB_SILENT))
3023 cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl),
3024 CE_WARN,
3025 "Corrupt label - label checksum failed\n");
3026 }
3027 return (CMLB_LABEL_IS_INVALID);
3028 }
3029
3030
3031 /*
3032 * Fill in geometry structure with data from label.
3033 */
3034 bzero(&cl->cl_g, sizeof (struct dk_geom));
3035 cl->cl_g.dkg_ncyl = labp->dkl_ncyl;
3036 cl->cl_g.dkg_acyl = labp->dkl_acyl;
3037 cl->cl_g.dkg_bcyl = 0;
3038 cl->cl_g.dkg_nhead = labp->dkl_nhead;
3039 cl->cl_g.dkg_nsect = labp->dkl_nsect;
3040 cl->cl_g.dkg_intrlv = labp->dkl_intrlv;
3041
3042 #if defined(_SUNOS_VTOC_8)
3043 cl->cl_g.dkg_gap1 = labp->dkl_gap1;
3044 cl->cl_g.dkg_gap2 = labp->dkl_gap2;
3045 cl->cl_g.dkg_bhead = labp->dkl_bhead;
3046 #endif
3047 #if defined(_SUNOS_VTOC_16)
3048 cl->cl_dkg_skew = labp->dkl_skew;
3049 #endif
3050
3051 #if defined(__i386) || defined(__amd64)
3052 cl->cl_g.dkg_apc = labp->dkl_apc;
3053 #endif
3054
3055 /*
3056 * Currently we rely on the values in the label being accurate. If
3057 * dkl_rpm or dkl_pcly are zero in the label, use a default value.
3058 *
3059 * Note: In the future a MODE SENSE may be used to retrieve this data,
3060 * although this command is optional in SCSI-2.
3061 */
3062 cl->cl_g.dkg_rpm = (labp->dkl_rpm != 0) ? labp->dkl_rpm : 3600;
3063 cl->cl_g.dkg_pcyl = (labp->dkl_pcyl != 0) ? labp->dkl_pcyl :
3064 (cl->cl_g.dkg_ncyl + cl->cl_g.dkg_acyl);
3065
3066 /*
3067 * The Read and Write reinstruct values may not be valid
3068 * for older disks.
3069 */
3070 cl->cl_g.dkg_read_reinstruct = labp->dkl_read_reinstruct;
3071 cl->cl_g.dkg_write_reinstruct = labp->dkl_write_reinstruct;
3072
3073 /* Fill in partition table. */
3074 #if defined(_SUNOS_VTOC_8)
3075 for (i = 0; i < NDKMAP; i++) {
3076 cl->cl_map[i].dkl_cylno = labp->dkl_map[i].dkl_cylno;
3077 cl->cl_map[i].dkl_nblk = labp->dkl_map[i].dkl_nblk;
3078 }
3079 #endif
3080 #if defined(_SUNOS_VTOC_16)
3081 vpartp = labp->dkl_vtoc.v_part;
3082 track_capacity = labp->dkl_nhead * labp->dkl_nsect;
3083
3084 /* Prevent divide by zero */
3085 if (track_capacity == 0) {
3086 if (!(flags & CMLB_SILENT))
3087 cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN,
3088 "Corrupt label - zero nhead or nsect value\n");
3089
3090 return (CMLB_LABEL_IS_INVALID);
3091 }
3092
3093 for (i = 0; i < NDKMAP; i++, vpartp++) {
3094 cl->cl_map[i].dkl_cylno = vpartp->p_start / track_capacity;
3095 cl->cl_map[i].dkl_nblk = vpartp->p_size;
3096 }
3097 #endif
3098
3099 /* Fill in VTOC Structure. */
3100 bcopy(&labp->dkl_vtoc, &cl->cl_vtoc, sizeof (struct dk_vtoc));
3101 #if defined(_SUNOS_VTOC_8)
3102 /*
3103 * The 8-slice vtoc does not include the ascii label; save it into
3104 * the device's soft state structure here.
3105 */
3106 bcopy(labp->dkl_asciilabel, cl->cl_asciilabel, LEN_DKL_ASCII);
3107 #endif
3108
3109 /* Now look for a valid capacity. */
3110 track_capacity = (cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect);
3111 label_capacity = (cl->cl_g.dkg_ncyl * track_capacity);
3112
3113 if (cl->cl_g.dkg_acyl) {
3114 #if defined(__i386) || defined(__amd64)
3115 /* we may have > 1 alts cylinder */
3116 label_capacity += (track_capacity * cl->cl_g.dkg_acyl);
3117 #else
3118 label_capacity += track_capacity;
3119 #endif
3120 }
3121
3122 /*
3123 * Force check here to ensure the computed capacity is valid.
3124 * If capacity is zero, it indicates an invalid label and
3125 * we should abort updating the relevant data then.
3126 */
3127 if (label_capacity == 0) {
3128 if (!(flags & CMLB_SILENT))
3129 cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN,
3130 "Corrupt label - no valid capacity could be "
3131 "retrieved\n");
3132
3133 return (CMLB_LABEL_IS_INVALID);
3134 }
3135
3136 /* Mark the geometry as valid. */
3137 cl->cl_f_geometry_is_valid = B_TRUE;
3138
3139 /*
3140 * if we got invalidated when mutex exit and entered again,
3141 * if blockcount different than when we came in, need to
3142 * retry from beginning of cmlb_validate_geometry.
3143 * revisit this on next phase of utilizing this for
3144 * sd.
3145 */
3146
3147 if (label_capacity <= cl->cl_blockcount) {
3148 #if defined(_SUNOS_VTOC_8)
3149 /*
3150 * We can't let this happen on drives that are subdivided
3151 * into logical disks (i.e., that have an fdisk table).
3152 * The cl_blockcount field should always hold the full media
3153 * size in sectors, period. This code would overwrite
3154 * cl_blockcount with the size of the Solaris fdisk partition.
3155 */
3156 cmlb_dbg(CMLB_ERROR, cl,
3157 "cmlb_uselabel: Label %d blocks; Drive %d blocks\n",
3158 label_capacity, cl->cl_blockcount);
3159 cl->cl_solaris_size = label_capacity;
3160
3161 #endif /* defined(_SUNOS_VTOC_8) */
3162 goto done;
3163 }
3164
3165 if (ISCD(cl)) {
3166 /* For CDROMs, we trust that the data in the label is OK. */
3167 #if defined(_SUNOS_VTOC_8)
3168 for (i = 0; i < NDKMAP; i++) {
3169 part_end = labp->dkl_nhead * labp->dkl_nsect *
3170 labp->dkl_map[i].dkl_cylno +
3171 labp->dkl_map[i].dkl_nblk - 1;
3172
3173 if ((labp->dkl_map[i].dkl_nblk) &&
3174 (part_end > cl->cl_blockcount)) {
3175 cl->cl_f_geometry_is_valid = B_FALSE;
3176 break;
3177 }
3178 }
3179 #endif
3180 #if defined(_SUNOS_VTOC_16)
3181 vpartp = &(labp->dkl_vtoc.v_part[0]);
3182 for (i = 0; i < NDKMAP; i++, vpartp++) {
3183 part_end = vpartp->p_start + vpartp->p_size;
3184 if ((vpartp->p_size > 0) &&
3185 (part_end > cl->cl_blockcount)) {
3186 cl->cl_f_geometry_is_valid = B_FALSE;
3187 break;
3188 }
3189 }
3190 #endif
3191 } else {
3192 /* label_capacity > cl->cl_blockcount */
3193 if (!(flags & CMLB_SILENT)) {
3194 cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN,
3195 "Corrupt label - bad geometry\n");
3196 cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_CONT,
3197 "Label says %llu blocks; Drive says %llu blocks\n",
3198 label_capacity, cl->cl_blockcount);
3199 }
3200 cl->cl_f_geometry_is_valid = B_FALSE;
3201 label_error = CMLB_LABEL_IS_INVALID;
3202 }
3203
3204 done:
3205
3206 cmlb_dbg(CMLB_INFO, cl, "cmlb_uselabel: (label geometry)\n");
3207 cmlb_dbg(CMLB_INFO, cl,
3208 " ncyl: %d; acyl: %d; nhead: %d; nsect: %d\n",
3209 cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl,
3210 cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect);
3211
3212 cmlb_dbg(CMLB_INFO, cl,
3213 " label_capacity: %d; intrlv: %d; rpm: %d\n",
3214 cl->cl_blockcount, cl->cl_g.dkg_intrlv, cl->cl_g.dkg_rpm);
3215 cmlb_dbg(CMLB_INFO, cl, " wrt_reinstr: %d; rd_reinstr: %d\n",
3216 cl->cl_g.dkg_write_reinstruct, cl->cl_g.dkg_read_reinstruct);
3217
3218 ASSERT(mutex_owned(CMLB_MUTEX(cl)));
3219
3220 return (label_error);
3221 }
3222
3223
3224 /*
3225 * Function: cmlb_build_default_label
3226 *
3227 * Description: Generate a default label for those devices that do not have
3228 * one, e.g., new media, removable cartridges, etc..
3229 *
3230 * Context: Kernel thread only
3231 */
3232 /*ARGSUSED*/
3233 static void
3234 cmlb_build_default_label(struct cmlb_lun *cl, void *tg_cookie)
3235 {
3236 #if defined(_SUNOS_VTOC_16)
3237 uint_t phys_spc;
3238 uint_t disksize;
3239 struct dk_geom cl_g;
3240 diskaddr_t capacity;
3241 #endif
3242
3243 ASSERT(cl != NULL);
3244 ASSERT(mutex_owned(CMLB_MUTEX(cl)));
3245
3246 #if defined(_SUNOS_VTOC_8)
3247 /*
3248 * Note: This is a legacy check for non-removable devices on VTOC_8
3249 * only. This may be a valid check for VTOC_16 as well.
3250 * Once we understand why there is this difference between SPARC and
3251 * x86 platform, we could remove this legacy check.
3252 */
3253 if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) {
3254 return;
3255 }
3256 #endif
3257
3258 bzero(&cl->cl_g, sizeof (struct dk_geom));
3259 bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc));
3260 bzero(&cl->cl_map, NDKMAP * (sizeof (struct dk_map)));
3261
3262 #if defined(_SUNOS_VTOC_8)
3263
3264 /*
3265 * It's a REMOVABLE media, therefore no label (on sparc, anyway).
3266 * But it is still necessary to set up various geometry information,
3267 * and we are doing this here.
3268 */
3269
3270 /*
3271 * For the rpm, we use the minimum for the disk. For the head, cyl,
3272 * and number of sector per track, if the capacity <= 1GB, head = 64,
3273 * sect = 32. else head = 255, sect 63 Note: the capacity should be
3274 * equal to C*H*S values. This will cause some truncation of size due
3275 * to round off errors. For CD-ROMs, this truncation can have adverse
3276 * side effects, so returning ncyl and nhead as 1. The nsect will
3277 * overflow for most of CD-ROMs as nsect is of type ushort. (4190569)
3278 */
3279 cl->cl_solaris_size = cl->cl_blockcount;
3280 if (ISCD(cl)) {
3281 tg_attribute_t tgattribute;
3282 int is_writable;
3283 /*
3284 * Preserve the old behavior for non-writable
3285 * medias. Since dkg_nsect is a ushort, it
3286 * will lose bits as cdroms have more than
3287 * 65536 sectors. So if we recalculate
3288 * capacity, it will become much shorter.
3289 * But the dkg_* information is not
3290 * used for CDROMs so it is OK. But for
3291 * Writable CDs we need this information
3292 * to be valid (for newfs say). So we
3293 * make nsect and nhead > 1 that way
3294 * nsect can still stay within ushort limit
3295 * without losing any bits.
3296 */
3297
3298 bzero(&tgattribute, sizeof (tg_attribute_t));
3299
3300 mutex_exit(CMLB_MUTEX(cl));
3301 is_writable =
3302 (DK_TG_GETATTRIBUTE(cl, &tgattribute, tg_cookie) == 0) ?
3303 tgattribute.media_is_writable : 1;
3304 mutex_enter(CMLB_MUTEX(cl));
3305
3306 if (is_writable) {
3307 cl->cl_g.dkg_nhead = 64;
3308 cl->cl_g.dkg_nsect = 32;
3309 cl->cl_g.dkg_ncyl = cl->cl_blockcount / (64 * 32);
3310 cl->cl_solaris_size = (diskaddr_t)cl->cl_g.dkg_ncyl *
3311 cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect;
3312 } else {
3313 cl->cl_g.dkg_ncyl = 1;
3314 cl->cl_g.dkg_nhead = 1;
3315 cl->cl_g.dkg_nsect = cl->cl_blockcount;
3316 }
3317 } else {
3318 if (cl->cl_blockcount < 160) {
3319 /* Less than 80K */
3320 cl->cl_g.dkg_nhead = 1;
3321 cl->cl_g.dkg_ncyl = cl->cl_blockcount;
3322 cl->cl_g.dkg_nsect = 1;
3323 } else if (cl->cl_blockcount <= 0x1000) {
3324 /* unlabeled SCSI floppy device */
3325 cl->cl_g.dkg_nhead = 2;
3326 cl->cl_g.dkg_ncyl = 80;
3327 cl->cl_g.dkg_nsect = cl->cl_blockcount / (2 * 80);
3328 } else if (cl->cl_blockcount <= 0x200000) {
3329 cl->cl_g.dkg_nhead = 64;
3330 cl->cl_g.dkg_nsect = 32;
3331 cl->cl_g.dkg_ncyl = cl->cl_blockcount / (64 * 32);
3332 } else {
3333 cl->cl_g.dkg_nhead = 255;
3334
3335 cl->cl_g.dkg_nsect = ((cl->cl_blockcount +
3336 (UINT16_MAX * 255 * 63) - 1) /
3337 (UINT16_MAX * 255 * 63)) * 63;
3338
3339 if (cl->cl_g.dkg_nsect == 0)
3340 cl->cl_g.dkg_nsect = (UINT16_MAX / 63) * 63;
3341
3342 cl->cl_g.dkg_ncyl = cl->cl_blockcount /
3343 (255 * cl->cl_g.dkg_nsect);
3344 }
3345
3346 cl->cl_solaris_size =
3347 (diskaddr_t)cl->cl_g.dkg_ncyl * cl->cl_g.dkg_nhead *
3348 cl->cl_g.dkg_nsect;
3349
3350 }
3351
3352 cl->cl_g.dkg_acyl = 0;
3353 cl->cl_g.dkg_bcyl = 0;
3354 cl->cl_g.dkg_rpm = 200;
3355 cl->cl_asciilabel[0] = '\0';
3356 cl->cl_g.dkg_pcyl = cl->cl_g.dkg_ncyl;
3357
3358 cl->cl_map[0].dkl_cylno = 0;
3359 cl->cl_map[0].dkl_nblk = cl->cl_solaris_size;
3360
3361 cl->cl_map[2].dkl_cylno = 0;
3362 cl->cl_map[2].dkl_nblk = cl->cl_solaris_size;
3363
3364 #elif defined(_SUNOS_VTOC_16)
3365
3366 if (cl->cl_solaris_size == 0) {
3367 /*
3368 * Got fdisk table but no solaris entry therefore
3369 * don't create a default label
3370 */
3371 cl->cl_f_geometry_is_valid = B_TRUE;
3372 return;
3373 }
3374
3375 /*
3376 * For CDs we continue to use the physical geometry to calculate
3377 * number of cylinders. All other devices must convert the
3378 * physical geometry (cmlb_geom) to values that will fit
3379 * in a dk_geom structure.
3380 */
3381 if (ISCD(cl)) {
3382 phys_spc = cl->cl_pgeom.g_nhead * cl->cl_pgeom.g_nsect;
3383 } else {
3384 /* Convert physical geometry to disk geometry */
3385 bzero(&cl_g, sizeof (struct dk_geom));
3386
3387 /*
3388 * Refer to comments related to off-by-1 at the
3389 * header of this file.
3390 * Before calculating geometry, capacity should be
3391 * decreased by 1.
3392 */
3393
3394 if (cl->cl_alter_behavior & CMLB_OFF_BY_ONE)
3395 capacity = cl->cl_blockcount - 1;
3396 else
3397 capacity = cl->cl_blockcount;
3398
3399
3400 cmlb_convert_geometry(cl, capacity, &cl_g, tg_cookie);
3401 bcopy(&cl_g, &cl->cl_g, sizeof (cl->cl_g));
3402 phys_spc = cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect;
3403 }
3404
3405 if (phys_spc == 0)
3406 return;
3407 cl->cl_g.dkg_pcyl = cl->cl_solaris_size / phys_spc;
3408 if (cl->cl_alter_behavior & CMLB_FAKE_LABEL_ONE_PARTITION) {
3409 /* disable devid */
3410 cl->cl_g.dkg_ncyl = cl->cl_g.dkg_pcyl;
3411 disksize = cl->cl_solaris_size;
3412 } else {
3413 cl->cl_g.dkg_acyl = DK_ACYL;
3414 cl->cl_g.dkg_ncyl = cl->cl_g.dkg_pcyl - DK_ACYL;
3415 disksize = cl->cl_g.dkg_ncyl * phys_spc;
3416 }
3417
3418 if (ISCD(cl)) {
3419 /*
3420 * CD's don't use the "heads * sectors * cyls"-type of
3421 * geometry, but instead use the entire capacity of the media.
3422 */
3423 disksize = cl->cl_solaris_size;
3424 cl->cl_g.dkg_nhead = 1;
3425 cl->cl_g.dkg_nsect = 1;
3426 cl->cl_g.dkg_rpm =
3427 (cl->cl_pgeom.g_rpm == 0) ? 200 : cl->cl_pgeom.g_rpm;
3428
3429 cl->cl_vtoc.v_part[0].p_start = 0;
3430 cl->cl_vtoc.v_part[0].p_size = disksize;
3431 cl->cl_vtoc.v_part[0].p_tag = V_BACKUP;
3432 cl->cl_vtoc.v_part[0].p_flag = V_UNMNT;
3433
3434 cl->cl_map[0].dkl_cylno = 0;
3435 cl->cl_map[0].dkl_nblk = disksize;
3436 cl->cl_offset[0] = 0;
3437
3438 } else {
3439 /*
3440 * Hard disks and removable media cartridges
3441 */
3442 cl->cl_g.dkg_rpm =
3443 (cl->cl_pgeom.g_rpm == 0) ? 3600: cl->cl_pgeom.g_rpm;
3444 cl->cl_vtoc.v_sectorsz = cl->cl_sys_blocksize;
3445
3446 /* Add boot slice */
3447 cl->cl_vtoc.v_part[8].p_start = 0;
3448 cl->cl_vtoc.v_part[8].p_size = phys_spc;
3449 cl->cl_vtoc.v_part[8].p_tag = V_BOOT;
3450 cl->cl_vtoc.v_part[8].p_flag = V_UNMNT;
3451
3452 cl->cl_map[8].dkl_cylno = 0;
3453 cl->cl_map[8].dkl_nblk = phys_spc;
3454 cl->cl_offset[8] = 0;
3455
3456 if ((cl->cl_alter_behavior &
3457 CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT) &&
3458 cl->cl_device_type == DTYPE_DIRECT) {
3459 cl->cl_vtoc.v_part[9].p_start = phys_spc;
3460 cl->cl_vtoc.v_part[9].p_size = 2 * phys_spc;
3461 cl->cl_vtoc.v_part[9].p_tag = V_ALTSCTR;
3462 cl->cl_vtoc.v_part[9].p_flag = 0;
3463
3464 cl->cl_map[9].dkl_cylno = 1;
3465 cl->cl_map[9].dkl_nblk = 2 * phys_spc;
3466 cl->cl_offset[9] = phys_spc;
3467 }
3468 }
3469
3470 cl->cl_g.dkg_apc = 0;
3471
3472 /* Add backup slice */
3473 cl->cl_vtoc.v_part[2].p_start = 0;
3474 cl->cl_vtoc.v_part[2].p_size = disksize;
3475 cl->cl_vtoc.v_part[2].p_tag = V_BACKUP;
3476 cl->cl_vtoc.v_part[2].p_flag = V_UNMNT;
3477
3478 cl->cl_map[2].dkl_cylno = 0;
3479 cl->cl_map[2].dkl_nblk = disksize;
3480 cl->cl_offset[2] = 0;
3481
3482 /*
3483 * single slice (s0) covering the entire disk
3484 */
3485 if (cl->cl_alter_behavior & CMLB_FAKE_LABEL_ONE_PARTITION) {
3486 cl->cl_vtoc.v_part[0].p_start = 0;
3487 cl->cl_vtoc.v_part[0].p_tag = V_UNASSIGNED;
3488 cl->cl_vtoc.v_part[0].p_flag = 0;
3489 cl->cl_vtoc.v_part[0].p_size = disksize;
3490 cl->cl_map[0].dkl_cylno = 0;
3491 cl->cl_map[0].dkl_nblk = disksize;
3492 cl->cl_offset[0] = 0;
3493 }
3494
3495 (void) sprintf(cl->cl_vtoc.v_asciilabel, "DEFAULT cyl %d alt %d"
3496 " hd %d sec %d", cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl,
3497 cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect);
3498
3499 #else
3500 #error "No VTOC format defined."
3501 #endif
3502
3503 cl->cl_g.dkg_read_reinstruct = 0;
3504 cl->cl_g.dkg_write_reinstruct = 0;
3505
3506 cl->cl_g.dkg_intrlv = 1;
3507
3508 cl->cl_vtoc.v_sanity = VTOC_SANE;
3509 cl->cl_vtoc.v_nparts = V_NUMPAR;
3510 cl->cl_vtoc.v_version = V_VERSION;
3511
3512 cl->cl_f_geometry_is_valid = B_TRUE;
3513 cl->cl_label_from_media = CMLB_LABEL_UNDEF;
3514
3515 cmlb_dbg(CMLB_INFO, cl,
3516 "cmlb_build_default_label: Default label created: "
3517 "cyl: %d\tacyl: %d\tnhead: %d\tnsect: %d\tcap: %d\n",
3518 cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl, cl->cl_g.dkg_nhead,
3519 cl->cl_g.dkg_nsect, cl->cl_blockcount);
3520 }
3521
3522
3523 #if defined(_FIRMWARE_NEEDS_FDISK)
3524 /*
3525 * Max CHS values, as they are encoded into bytes, for 1022/254/63
3526 */
3527 #define LBA_MAX_SECT (63 | ((1022 & 0x300) >> 2))
3528 #define LBA_MAX_CYL (1022 & 0xFF)
3529 #define LBA_MAX_HEAD (254)
3530
3531
3532 /*
3533 * Function: cmlb_has_max_chs_vals
3534 *
3535 * Description: Return B_TRUE if Cylinder-Head-Sector values are all at maximum.
3536 *
3537 * Arguments: fdp - ptr to CHS info
3538 *
3539 * Return Code: True or false
3540 *
3541 * Context: Any.
3542 */
3543 static boolean_t
3544 cmlb_has_max_chs_vals(struct ipart *fdp)
3545 {
3546 return ((fdp->begcyl == LBA_MAX_CYL) &&
3547 (fdp->beghead == LBA_MAX_HEAD) &&
3548 (fdp->begsect == LBA_MAX_SECT) &&
3549 (fdp->endcyl == LBA_MAX_CYL) &&
3550 (fdp->endhead == LBA_MAX_HEAD) &&
3551 (fdp->endsect == LBA_MAX_SECT));
3552 }
3553 #endif
3554
3555 /*
3556 * Function: cmlb_dkio_get_geometry
3557 *
3558 * Description: This routine is the driver entry point for handling user
3559 * requests to get the device geometry (DKIOCGGEOM).
3560 *
3561 * Arguments:
3562 * arg pointer to user provided dk_geom structure specifying
3563 * the controller's notion of the current geometry.
3564 *
3565 * flag this argument is a pass through to ddi_copyxxx()
3566 * directly from the mode argument of ioctl().
3567 *
3568 * tg_cookie cookie from target driver to be passed back to target
3569 * driver when we call back to it through tg_ops.
3570 *
3571 * Return Code: 0
3572 * EFAULT
3573 * ENXIO
3574 * EIO
3575 */
3576 static int
3577 cmlb_dkio_get_geometry(struct cmlb_lun *cl, caddr_t arg, int flag,
3578 void *tg_cookie)
3579 {
3580 struct dk_geom *tmp_geom = NULL;
3581 int rval = 0;
3582
3583 /*
3584 * cmlb_validate_geometry does not spin a disk up
3585 * if it was spcl down. We need to make sure it
3586 * is ready.
3587 */
3588 mutex_enter(CMLB_MUTEX(cl));
3589 rval = cmlb_validate_geometry(cl, B_TRUE, 0, tg_cookie);
3590 #if defined(_SUNOS_VTOC_8)
3591 if (rval == EINVAL &&
3592 cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8) {
3593 /*
3594 * This is to return a default label geometry even when we
3595 * do not really assume a default label for the device.
3596 * dad driver utilizes this.
3597 */
3598 if (cl->cl_blockcount <= CMLB_OLDVTOC_LIMIT) {
3599 cmlb_setup_default_geometry(cl, tg_cookie);
3600 rval = 0;
3601 }
3602 }
3603 #endif
3604 if (rval) {
3605 mutex_exit(CMLB_MUTEX(cl));
3606 return (rval);
3607 }
3608
3609 #if defined(__i386) || defined(__amd64)
3610 if (cl->cl_solaris_size == 0) {
3611 mutex_exit(CMLB_MUTEX(cl));
3612 return (EIO);
3613 }
3614 #endif
3615
3616 /*
3617 * Make a local copy of the soft state geometry to avoid some potential
3618 * race conditions associated with holding the mutex and updating the
3619 * write_reinstruct value
3620 */
3621 tmp_geom = kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP);
3622 bcopy(&cl->cl_g, tmp_geom, sizeof (struct dk_geom));
3623
3624 if (tmp_geom->dkg_write_reinstruct == 0) {
3625 tmp_geom->dkg_write_reinstruct =
3626 (int)((int)(tmp_geom->dkg_nsect * tmp_geom->dkg_rpm *
3627 cmlb_rot_delay) / (int)60000);
3628 }
3629 mutex_exit(CMLB_MUTEX(cl));
3630
3631 rval = ddi_copyout(tmp_geom, (void *)arg, sizeof (struct dk_geom),
3632 flag);
3633 if (rval != 0) {
3634 rval = EFAULT;
3635 }
3636
3637 kmem_free(tmp_geom, sizeof (struct dk_geom));
3638 return (rval);
3639
3640 }
3641
3642
3643 /*
3644 * Function: cmlb_dkio_set_geometry
3645 *
3646 * Description: This routine is the driver entry point for handling user
3647 * requests to set the device geometry (DKIOCSGEOM). The actual
3648 * device geometry is not updated, just the driver "notion" of it.
3649 *
3650 * Arguments:
3651 * arg pointer to user provided dk_geom structure used to set
3652 * the controller's notion of the current geometry.
3653 *
3654 * flag this argument is a pass through to ddi_copyxxx()
3655 * directly from the mode argument of ioctl().
3656 *
3657 * tg_cookie cookie from target driver to be passed back to target
3658 * driver when we call back to it through tg_ops.
3659 *
3660 * Return Code: 0
3661 * EFAULT
3662 * ENXIO
3663 * EIO
3664 */
3665 static int
3666 cmlb_dkio_set_geometry(struct cmlb_lun *cl, caddr_t arg, int flag)
3667 {
3668 struct dk_geom *tmp_geom;
3669 struct dk_map *lp;
3670 int rval = 0;
3671 int i;
3672
3673
3674 #if defined(__i386) || defined(__amd64)
3675 if (cl->cl_solaris_size == 0) {
3676 return (EIO);
3677 }
3678 #endif
3679 /*
3680 * We need to copy the user specified geometry into local
3681 * storage and then update the softstate. We don't want to hold
3682 * the mutex and copyin directly from the user to the soft state
3683 */
3684 tmp_geom = (struct dk_geom *)
3685 kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP);
3686 rval = ddi_copyin(arg, tmp_geom, sizeof (struct dk_geom), flag);
3687 if (rval != 0) {
3688 kmem_free(tmp_geom, sizeof (struct dk_geom));
3689 return (EFAULT);
3690 }
3691
3692 mutex_enter(CMLB_MUTEX(cl));
3693 bcopy(tmp_geom, &cl->cl_g, sizeof (struct dk_geom));
3694 for (i = 0; i < NDKMAP; i++) {
3695 lp = &cl->cl_map[i];
3696 cl->cl_offset[i] =
3697 cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno;
3698 #if defined(__i386) || defined(__amd64)
3699 cl->cl_offset[i] += cl->cl_solaris_offset;
3700 #endif
3701 }
3702 cl->cl_f_geometry_is_valid = B_FALSE;
3703 mutex_exit(CMLB_MUTEX(cl));
3704 kmem_free(tmp_geom, sizeof (struct dk_geom));
3705
3706 return (rval);
3707 }
3708
3709 /*
3710 * Function: cmlb_dkio_get_partition
3711 *
3712 * Description: This routine is the driver entry point for handling user
3713 * requests to get the partition table (DKIOCGAPART).
3714 *
3715 * Arguments:
3716 * arg pointer to user provided dk_allmap structure specifying
3717 * the controller's notion of the current partition table.
3718 *
3719 * flag this argument is a pass through to ddi_copyxxx()
3720 * directly from the mode argument of ioctl().
3721 *
3722 * tg_cookie cookie from target driver to be passed back to target
3723 * driver when we call back to it through tg_ops.
3724 *
3725 * Return Code: 0
3726 * EFAULT
3727 * ENXIO
3728 * EIO
3729 */
3730 static int
3731 cmlb_dkio_get_partition(struct cmlb_lun *cl, caddr_t arg, int flag,
3732 void *tg_cookie)
3733 {
3734 int rval = 0;
3735 int size;
3736
3737 /*
3738 * Make sure the geometry is valid before getting the partition
3739 * information.
3740 */
3741 mutex_enter(CMLB_MUTEX(cl));
3742 if ((rval = cmlb_validate_geometry(cl, B_TRUE, 0, tg_cookie)) != 0) {
3743 mutex_exit(CMLB_MUTEX(cl));
3744 return (rval);
3745 }
3746 mutex_exit(CMLB_MUTEX(cl));
3747
3748 #if defined(__i386) || defined(__amd64)
3749 if (cl->cl_solaris_size == 0) {
3750 return (EIO);
3751 }
3752 #endif
3753
3754 #ifdef _MULTI_DATAMODEL
3755 switch (ddi_model_convert_from(flag & FMODELS)) {
3756 case DDI_MODEL_ILP32: {
3757 struct dk_map32 dk_map32[NDKMAP];
3758 int i;
3759
3760 for (i = 0; i < NDKMAP; i++) {
3761 dk_map32[i].dkl_cylno = cl->cl_map[i].dkl_cylno;
3762 dk_map32[i].dkl_nblk = cl->cl_map[i].dkl_nblk;
3763 }
3764 size = NDKMAP * sizeof (struct dk_map32);
3765 rval = ddi_copyout(dk_map32, (void *)arg, size, flag);
3766 if (rval != 0) {
3767 rval = EFAULT;
3768 }
3769 break;
3770 }
3771 case DDI_MODEL_NONE:
3772 size = NDKMAP * sizeof (struct dk_map);
3773 rval = ddi_copyout(cl->cl_map, (void *)arg, size, flag);
3774 if (rval != 0) {
3775 rval = EFAULT;
3776 }
3777 break;
3778 }
3779 #else /* ! _MULTI_DATAMODEL */
3780 size = NDKMAP * sizeof (struct dk_map);
3781 rval = ddi_copyout(cl->cl_map, (void *)arg, size, flag);
3782 if (rval != 0) {
3783 rval = EFAULT;
3784 }
3785 #endif /* _MULTI_DATAMODEL */
3786 return (rval);
3787 }
3788
3789 /*
3790 * Function: cmlb_dkio_set_partition
3791 *
3792 * Description: This routine is the driver entry point for handling user
3793 * requests to set the partition table (DKIOCSAPART). The actual
3794 * device partition is not updated.
3795 *
3796 * Arguments:
3797 * arg - pointer to user provided dk_allmap structure used to set
3798 * the controller's notion of the partition table.
3799 * flag - this argument is a pass through to ddi_copyxxx()
3800 * directly from the mode argument of ioctl().
3801 *
3802 * Return Code: 0
3803 * EINVAL
3804 * EFAULT
3805 * ENXIO
3806 * EIO
3807 */
3808 static int
3809 cmlb_dkio_set_partition(struct cmlb_lun *cl, caddr_t arg, int flag)
3810 {
3811 struct dk_map dk_map[NDKMAP];
3812 struct dk_map *lp;
3813 int rval = 0;
3814 int size;
3815 int i;
3816 #if defined(_SUNOS_VTOC_16)
3817 struct dkl_partition *vp;
3818 #endif
3819
3820 /*
3821 * Set the map for all logical partitions. We lock
3822 * the priority just to make sure an interrupt doesn't
3823 * come in while the map is half updated.
3824 */
3825 _NOTE(DATA_READABLE_WITHOUT_LOCK(cmlb_lun::cl_solaris_size))
3826 mutex_enter(CMLB_MUTEX(cl));
3827
3828 if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) {
3829 mutex_exit(CMLB_MUTEX(cl));
3830 return (ENOTSUP);
3831 }
3832 mutex_exit(CMLB_MUTEX(cl));
3833 if (cl->cl_solaris_size == 0) {
3834 return (EIO);
3835 }
3836
3837 #ifdef _MULTI_DATAMODEL
3838 switch (ddi_model_convert_from(flag & FMODELS)) {
3839 case DDI_MODEL_ILP32: {
3840 struct dk_map32 dk_map32[NDKMAP];
3841
3842 size = NDKMAP * sizeof (struct dk_map32);
3843 rval = ddi_copyin((void *)arg, dk_map32, size, flag);
3844 if (rval != 0) {
3845 return (EFAULT);
3846 }
3847 for (i = 0; i < NDKMAP; i++) {
3848 dk_map[i].dkl_cylno = dk_map32[i].dkl_cylno;
3849 dk_map[i].dkl_nblk = dk_map32[i].dkl_nblk;
3850 }
3851 break;
3852 }
3853 case DDI_MODEL_NONE:
3854 size = NDKMAP * sizeof (struct dk_map);
3855 rval = ddi_copyin((void *)arg, dk_map, size, flag);
3856 if (rval != 0) {
3857 return (EFAULT);
3858 }
3859 break;
3860 }
3861 #else /* ! _MULTI_DATAMODEL */
3862 size = NDKMAP * sizeof (struct dk_map);
3863 rval = ddi_copyin((void *)arg, dk_map, size, flag);
3864 if (rval != 0) {
3865 return (EFAULT);
3866 }
3867 #endif /* _MULTI_DATAMODEL */
3868
3869 mutex_enter(CMLB_MUTEX(cl));
3870 /* Note: The size used in this bcopy is set based upon the data model */
3871 bcopy(dk_map, cl->cl_map, size);
3872 #if defined(_SUNOS_VTOC_16)
3873 vp = (struct dkl_partition *)&(cl->cl_vtoc);
3874 #endif /* defined(_SUNOS_VTOC_16) */
3875 for (i = 0; i < NDKMAP; i++) {
3876 lp = &cl->cl_map[i];
3877 cl->cl_offset[i] =
3878 cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno;
3879 #if defined(_SUNOS_VTOC_16)
3880 vp->p_start = cl->cl_offset[i];
3881 vp->p_size = lp->dkl_nblk;
3882 vp++;
3883 #endif /* defined(_SUNOS_VTOC_16) */
3884 #if defined(__i386) || defined(__amd64)
3885 cl->cl_offset[i] += cl->cl_solaris_offset;
3886 #endif
3887 }
3888 mutex_exit(CMLB_MUTEX(cl));
3889 return (rval);
3890 }
3891
3892
3893 /*
3894 * Function: cmlb_dkio_get_vtoc
3895 *
3896 * Description: This routine is the driver entry point for handling user
3897 * requests to get the current volume table of contents
3898 * (DKIOCGVTOC).
3899 *
3900 * Arguments:
3901 * arg pointer to user provided vtoc structure specifying
3902 * the current vtoc.
3903 *
3904 * flag this argument is a pass through to ddi_copyxxx()
3905 * directly from the mode argument of ioctl().
3906 *
3907 * tg_cookie cookie from target driver to be passed back to target
3908 * driver when we call back to it through tg_ops.
3909 *
3910 * Return Code: 0
3911 * EFAULT
3912 * ENXIO
3913 * EIO
3914 */
3915 static int
3916 cmlb_dkio_get_vtoc(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie)
3917 {
3918 #if defined(_SUNOS_VTOC_8)
3919 struct vtoc user_vtoc;
3920 #endif /* defined(_SUNOS_VTOC_8) */
3921 int rval = 0;
3922
3923 mutex_enter(CMLB_MUTEX(cl));
3924 if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) {
3925 mutex_exit(CMLB_MUTEX(cl));
3926 return (EOVERFLOW);
3927 }
3928
3929 rval = cmlb_validate_geometry(cl, B_TRUE, 0, tg_cookie);
3930
3931 #if defined(_SUNOS_VTOC_8)
3932 if (rval == EINVAL &&
3933 (cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8)) {
3934 /*
3935 * This is to return a default label even when we do not
3936 * really assume a default label for the device.
3937 * dad driver utilizes this.
3938 */
3939 if (cl->cl_blockcount <= CMLB_OLDVTOC_LIMIT) {
3940 cmlb_setup_default_geometry(cl, tg_cookie);
3941 rval = 0;
3942 }
3943 }
3944 #endif
3945 if (rval) {
3946 mutex_exit(CMLB_MUTEX(cl));
3947 return (rval);
3948 }
3949
3950 #if defined(_SUNOS_VTOC_8)
3951 cmlb_build_user_vtoc(cl, &user_vtoc);
3952 mutex_exit(CMLB_MUTEX(cl));
3953
3954 #ifdef _MULTI_DATAMODEL
3955 switch (ddi_model_convert_from(flag & FMODELS)) {
3956 case DDI_MODEL_ILP32: {
3957 struct vtoc32 user_vtoc32;
3958
3959 vtoctovtoc32(user_vtoc, user_vtoc32);
3960 if (ddi_copyout(&user_vtoc32, (void *)arg,
3961 sizeof (struct vtoc32), flag)) {
3962 return (EFAULT);
3963 }
3964 break;
3965 }
3966
3967 case DDI_MODEL_NONE:
3968 if (ddi_copyout(&user_vtoc, (void *)arg,
3969 sizeof (struct vtoc), flag)) {
3970 return (EFAULT);
3971 }
3972 break;
3973 }
3974 #else /* ! _MULTI_DATAMODEL */
3975 if (ddi_copyout(&user_vtoc, (void *)arg, sizeof (struct vtoc), flag)) {
3976 return (EFAULT);
3977 }
3978 #endif /* _MULTI_DATAMODEL */
3979
3980 #elif defined(_SUNOS_VTOC_16)
3981 mutex_exit(CMLB_MUTEX(cl));
3982
3983 #ifdef _MULTI_DATAMODEL
3984 /*
3985 * The cl_vtoc structure is a "struct dk_vtoc" which is always
3986 * 32-bit to maintain compatibility with existing on-disk
3987 * structures. Thus, we need to convert the structure when copying
3988 * it out to a datamodel-dependent "struct vtoc" in a 64-bit
3989 * program. If the target is a 32-bit program, then no conversion
3990 * is necessary.
3991 */
3992 /* LINTED: logical expression always true: op "||" */
3993 ASSERT(sizeof (cl->cl_vtoc) == sizeof (struct vtoc32));
3994 switch (ddi_model_convert_from(flag & FMODELS)) {
3995 case DDI_MODEL_ILP32:
3996 if (ddi_copyout(&(cl->cl_vtoc), (void *)arg,
3997 sizeof (cl->cl_vtoc), flag)) {
3998 return (EFAULT);
3999 }
4000 break;
4001
4002 case DDI_MODEL_NONE: {
4003 struct vtoc user_vtoc;
4004
4005 vtoc32tovtoc(cl->cl_vtoc, user_vtoc);
4006 if (ddi_copyout(&user_vtoc, (void *)arg,
4007 sizeof (struct vtoc), flag)) {
4008 return (EFAULT);
4009 }
4010 break;
4011 }
4012 }
4013 #else /* ! _MULTI_DATAMODEL */
4014 if (ddi_copyout(&(cl->cl_vtoc), (void *)arg, sizeof (cl->cl_vtoc),
4015 flag)) {
4016 return (EFAULT);
4017 }
4018 #endif /* _MULTI_DATAMODEL */
4019 #else
4020 #error "No VTOC format defined."
4021 #endif
4022
4023 return (rval);
4024 }
4025
4026
4027 /*
4028 * Function: cmlb_dkio_get_extvtoc
4029 */
4030 static int
4031 cmlb_dkio_get_extvtoc(struct cmlb_lun *cl, caddr_t arg, int flag,
4032 void *tg_cookie)
4033 {
4034 struct extvtoc ext_vtoc;
4035 #if defined(_SUNOS_VTOC_8)
4036 struct vtoc user_vtoc;
4037 #endif /* defined(_SUNOS_VTOC_8) */
4038 int rval = 0;
4039
4040 bzero(&ext_vtoc, sizeof (struct extvtoc));
4041 mutex_enter(CMLB_MUTEX(cl));
4042 rval = cmlb_validate_geometry(cl, B_TRUE, 0, tg_cookie);
4043
4044 #if defined(_SUNOS_VTOC_8)
4045 if (rval == EINVAL &&
4046 (cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8)) {
4047 /*
4048 * This is to return a default label even when we do not
4049 * really assume a default label for the device.
4050 * dad driver utilizes this.
4051 */
4052 if (cl->cl_blockcount <= CMLB_OLDVTOC_LIMIT) {
4053 cmlb_setup_default_geometry(cl, tg_cookie);
4054 rval = 0;
4055 }
4056 }
4057 #endif
4058 if (rval) {
4059 mutex_exit(CMLB_MUTEX(cl));
4060 return (rval);
4061 }
4062
4063 #if defined(_SUNOS_VTOC_8)
4064 cmlb_build_user_vtoc(cl, &user_vtoc);
4065 mutex_exit(CMLB_MUTEX(cl));
4066
4067 /*
4068 * Checking callers data model does not make much sense here
4069 * since extvtoc will always be equivalent to 64bit vtoc.
4070 * What is important is whether the kernel is in 32 or 64 bit
4071 */
4072
4073 #ifdef _LP64
4074 if (ddi_copyout(&user_vtoc, (void *)arg,
4075 sizeof (struct extvtoc), flag)) {
4076 return (EFAULT);
4077 }
4078 #else
4079 vtoc32tovtoc(user_vtoc, ext_vtoc);
4080 if (ddi_copyout(&ext_vtoc, (void *)arg,
4081 sizeof (struct extvtoc), flag)) {
4082 return (EFAULT);
4083 }
4084 #endif
4085
4086 #elif defined(_SUNOS_VTOC_16)
4087 /*
4088 * The cl_vtoc structure is a "struct dk_vtoc" which is always
4089 * 32-bit to maintain compatibility with existing on-disk
4090 * structures. Thus, we need to convert the structure when copying
4091 * it out to extvtoc
4092 */
4093 vtoc32tovtoc(cl->cl_vtoc, ext_vtoc);
4094 mutex_exit(CMLB_MUTEX(cl));
4095
4096 if (ddi_copyout(&ext_vtoc, (void *)arg, sizeof (struct extvtoc), flag))
4097 return (EFAULT);
4098 #else
4099 #error "No VTOC format defined."
4100 #endif
4101
4102 return (rval);
4103 }
4104
4105 /*
4106 * This routine implements the DKIOCGETEFI ioctl. This ioctl is currently
4107 * used to read the GPT Partition Table Header (primary/backup), the GUID
4108 * partition Entry Array (primary/backup), and the MBR.
4109 */
4110 static int
4111 cmlb_dkio_get_efi(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie)
4112 {
4113 dk_efi_t user_efi;
4114 int rval = 0;
4115 void *buffer;
4116 diskaddr_t tgt_lba;
4117
4118 if (ddi_copyin(arg, &user_efi, sizeof (dk_efi_t), flag))
4119 return (EFAULT);
4120
4121 user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64;
4122
4123 if (user_efi.dki_length == 0 ||
4124 user_efi.dki_length > cmlb_tg_max_efi_xfer)
4125 return (EINVAL);
4126
4127 tgt_lba = user_efi.dki_lba;
4128
4129 mutex_enter(CMLB_MUTEX(cl));
4130 if ((cmlb_check_update_blockcount(cl, tg_cookie) != 0) ||
4131 (cl->cl_tgt_blocksize == 0) ||
4132 (user_efi.dki_length % cl->cl_sys_blocksize)) {
4133 mutex_exit(CMLB_MUTEX(cl));
4134 return (EINVAL);
4135 }
4136 if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize)
4137 tgt_lba = tgt_lba * cl->cl_tgt_blocksize /
4138 cl->cl_sys_blocksize;
4139 mutex_exit(CMLB_MUTEX(cl));
4140
4141 buffer = kmem_alloc(user_efi.dki_length, KM_SLEEP);
4142 rval = DK_TG_READ(cl, buffer, tgt_lba, user_efi.dki_length, tg_cookie);
4143 if (rval == 0 && ddi_copyout(buffer, user_efi.dki_data,
4144 user_efi.dki_length, flag) != 0)
4145 rval = EFAULT;
4146
4147 kmem_free(buffer, user_efi.dki_length);
4148 return (rval);
4149 }
4150
4151 #if defined(_SUNOS_VTOC_8)
4152 /*
4153 * Function: cmlb_build_user_vtoc
4154 *
4155 * Description: This routine populates a pass by reference variable with the
4156 * current volume table of contents.
4157 *
4158 * Arguments: cl - driver soft state (unit) structure
4159 * user_vtoc - pointer to vtoc structure to be populated
4160 */
4161 static void
4162 cmlb_build_user_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc)
4163 {
4164 struct dk_map2 *lpart;
4165 struct dk_map *lmap;
4166 struct partition *vpart;
4167 uint32_t nblks;
4168 int i;
4169
4170 ASSERT(mutex_owned(CMLB_MUTEX(cl)));
4171
4172 /*
4173 * Return vtoc structure fields in the provided VTOC area, addressed
4174 * by *vtoc.
4175 */
4176 bzero(user_vtoc, sizeof (struct vtoc));
4177 user_vtoc->v_bootinfo[0] = cl->cl_vtoc.v_bootinfo[0];
4178 user_vtoc->v_bootinfo[1] = cl->cl_vtoc.v_bootinfo[1];
4179 user_vtoc->v_bootinfo[2] = cl->cl_vtoc.v_bootinfo[2];
4180 user_vtoc->v_sanity = VTOC_SANE;
4181 user_vtoc->v_version = cl->cl_vtoc.v_version;
4182 bcopy(cl->cl_vtoc.v_volume, user_vtoc->v_volume, LEN_DKL_VVOL);
4183 user_vtoc->v_sectorsz = cl->cl_sys_blocksize;
4184 user_vtoc->v_nparts = cl->cl_vtoc.v_nparts;
4185
4186 for (i = 0; i < 10; i++)
4187 user_vtoc->v_reserved[i] = cl->cl_vtoc.v_reserved[i];
4188
4189 /*
4190 * Convert partitioning information.
4191 *
4192 * Note the conversion from starting cylinder number
4193 * to starting sector number.
4194 */
4195 lmap = cl->cl_map;
4196 lpart = (struct dk_map2 *)cl->cl_vtoc.v_part;
4197 vpart = user_vtoc->v_part;
4198
4199 nblks = cl->cl_g.dkg_nsect * cl->cl_g.dkg_nhead;
4200
4201 for (i = 0; i < V_NUMPAR; i++) {
4202 vpart->p_tag = lpart->p_tag;
4203 vpart->p_flag = lpart->p_flag;
4204 vpart->p_start = lmap->dkl_cylno * nblks;
4205 vpart->p_size = lmap->dkl_nblk;
4206 lmap++;
4207 lpart++;
4208 vpart++;
4209
4210 /* (4364927) */
4211 user_vtoc->timestamp[i] = (time_t)cl->cl_vtoc.v_timestamp[i];
4212 }
4213
4214 bcopy(cl->cl_asciilabel, user_vtoc->v_asciilabel, LEN_DKL_ASCII);
4215 }
4216 #endif
4217
4218 static int
4219 cmlb_dkio_partition(struct cmlb_lun *cl, caddr_t arg, int flag,
4220 void *tg_cookie)
4221 {
4222 struct partition64 p64;
4223 int rval = 0;
4224 uint_t nparts;
4225 efi_gpe_t *partitions;
4226 efi_gpt_t *buffer;
4227 diskaddr_t gpe_lba;
4228 int n_gpe_per_blk = 0;
4229
4230 if (ddi_copyin((const void *)arg, &p64,
4231 sizeof (struct partition64), flag)) {
4232 return (EFAULT);
4233 }
4234
4235 buffer = kmem_alloc(cl->cl_sys_blocksize, KM_SLEEP);
4236 rval = DK_TG_READ(cl, buffer, 1, cl->cl_sys_blocksize, tg_cookie);
4237 if (rval != 0)
4238 goto done_error;
4239
4240 cmlb_swap_efi_gpt(buffer);
4241
4242 if ((rval = cmlb_validate_efi(buffer)) != 0)
4243 goto done_error;
4244
4245 nparts = buffer->efi_gpt_NumberOfPartitionEntries;
4246 gpe_lba = buffer->efi_gpt_PartitionEntryLBA;
4247 if (p64.p_partno >= nparts) {
4248 /* couldn't find it */
4249 rval = ESRCH;
4250 goto done_error;
4251 }
4252 /*
4253 * Read the block that contains the requested GPE.
4254 */
4255 n_gpe_per_blk = cl->cl_sys_blocksize / sizeof (efi_gpe_t);
4256 gpe_lba += p64.p_partno / n_gpe_per_blk;
4257 rval = DK_TG_READ(cl, buffer, gpe_lba, cl->cl_sys_blocksize, tg_cookie);
4258
4259 if (rval) {
4260 goto done_error;
4261 }
4262 partitions = (efi_gpe_t *)buffer;
4263 partitions += p64.p_partno % n_gpe_per_blk;
4264
4265 /* Byte swap only the requested GPE */
4266 cmlb_swap_efi_gpe(1, partitions);
4267
4268 bcopy(&partitions->efi_gpe_PartitionTypeGUID, &p64.p_type,
4269 sizeof (struct uuid));
4270 p64.p_start = partitions->efi_gpe_StartingLBA;
4271 p64.p_size = partitions->efi_gpe_EndingLBA -
4272 p64.p_start + 1;
4273
4274 if (ddi_copyout(&p64, (void *)arg, sizeof (struct partition64), flag))
4275 rval = EFAULT;
4276
4277 done_error:
4278 kmem_free(buffer, cl->cl_sys_blocksize);
4279 return (rval);
4280 }
4281
4282
4283 /*
4284 * Function: cmlb_dkio_set_vtoc
4285 *
4286 * Description: This routine is the driver entry point for handling user
4287 * requests to set the current volume table of contents
4288 * (DKIOCSVTOC).
4289 *
4290 * Arguments:
4291 * dev the device number
4292 * arg pointer to user provided vtoc structure used to set the
4293 * current vtoc.
4294 *
4295 * flag this argument is a pass through to ddi_copyxxx()
4296 * directly from the mode argument of ioctl().
4297 *
4298 * tg_cookie cookie from target driver to be passed back to target
4299 * driver when we call back to it through tg_ops.
4300 *
4301 * Return Code: 0
4302 * EFAULT
4303 * ENXIO
4304 * EINVAL
4305 * ENOTSUP
4306 */
4307 static int
4308 cmlb_dkio_set_vtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag,
4309 void *tg_cookie)
4310 {
4311 struct vtoc user_vtoc;
4312 int rval = 0;
4313 boolean_t internal;
4314
4315 internal = VOID2BOOLEAN(
4316 (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0);
4317
4318 #ifdef _MULTI_DATAMODEL
4319 switch (ddi_model_convert_from(flag & FMODELS)) {
4320 case DDI_MODEL_ILP32: {
4321 struct vtoc32 user_vtoc32;
4322
4323 if (ddi_copyin((const void *)arg, &user_vtoc32,
4324 sizeof (struct vtoc32), flag)) {
4325 return (EFAULT);
4326 }
4327 vtoc32tovtoc(user_vtoc32, user_vtoc);
4328 break;
4329 }
4330
4331 case DDI_MODEL_NONE:
4332 if (ddi_copyin((const void *)arg, &user_vtoc,
4333 sizeof (struct vtoc), flag)) {
4334 return (EFAULT);
4335 }
4336 break;
4337 }
4338 #else /* ! _MULTI_DATAMODEL */
4339 if (ddi_copyin((const void *)arg, &user_vtoc,
4340 sizeof (struct vtoc), flag)) {
4341 return (EFAULT);
4342 }
4343 #endif /* _MULTI_DATAMODEL */
4344
4345 mutex_enter(CMLB_MUTEX(cl));
4346
4347 if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) {
4348 mutex_exit(CMLB_MUTEX(cl));
4349 return (EOVERFLOW);
4350 }
4351
4352 #if defined(__i386) || defined(__amd64)
4353 if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) {
4354 mutex_exit(CMLB_MUTEX(cl));
4355 return (EINVAL);
4356 }
4357 #endif
4358
4359 if (cl->cl_g.dkg_ncyl == 0) {
4360 mutex_exit(CMLB_MUTEX(cl));
4361 return (EINVAL);
4362 }
4363
4364 mutex_exit(CMLB_MUTEX(cl));
4365 cmlb_clear_efi(cl, tg_cookie);
4366 ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd");
4367 ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd,raw");
4368
4369 /*
4370 * cmlb_dkio_set_vtoc creates duplicate minor nodes when
4371 * relabeling an SMI disk. To avoid that we remove them
4372 * before creating.
4373 * It should be OK to remove a non-existed minor node.
4374 */
4375 ddi_remove_minor_node(CMLB_DEVINFO(cl), "h");
4376 ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw");
4377
4378 (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h",
4379 S_IFBLK, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE,
4380 cl->cl_node_type, NULL, internal);
4381 (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h,raw",
4382 S_IFCHR, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE,
4383 cl->cl_node_type, NULL, internal);
4384 mutex_enter(CMLB_MUTEX(cl));
4385
4386 if ((rval = cmlb_build_label_vtoc(cl, &user_vtoc)) == 0) {
4387 if ((rval = cmlb_write_label(cl, tg_cookie)) == 0) {
4388 if (cmlb_validate_geometry(cl,
4389 B_TRUE, 0, tg_cookie) != 0) {
4390 cmlb_dbg(CMLB_ERROR, cl,
4391 "cmlb_dkio_set_vtoc: "
4392 "Failed validate geometry\n");
4393 }
4394 cl->cl_msglog_flag |= CMLB_ALLOW_2TB_WARN;
4395 }
4396 }
4397 mutex_exit(CMLB_MUTEX(cl));
4398 return (rval);
4399 }
4400
4401 /*
4402 * Function: cmlb_dkio_set_extvtoc
4403 */
4404 static int
4405 cmlb_dkio_set_extvtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag,
4406 void *tg_cookie)
4407 {
4408 int rval = 0;
4409 struct vtoc user_vtoc;
4410 boolean_t internal;
4411
4412
4413 /*
4414 * Checking callers data model does not make much sense here
4415 * since extvtoc will always be equivalent to 64bit vtoc.
4416 * What is important is whether the kernel is in 32 or 64 bit
4417 */
4418
4419 #ifdef _LP64
4420 if (ddi_copyin((const void *)arg, &user_vtoc,
4421 sizeof (struct extvtoc), flag)) {
4422 return (EFAULT);
4423 }
4424 #else
4425 struct extvtoc user_extvtoc;
4426 if (ddi_copyin((const void *)arg, &user_extvtoc,
4427 sizeof (struct extvtoc), flag)) {
4428 return (EFAULT);
4429 }
4430
4431 vtoctovtoc32(user_extvtoc, user_vtoc);
4432 #endif
4433
4434 internal = VOID2BOOLEAN(
4435 (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0);
4436 mutex_enter(CMLB_MUTEX(cl));
4437 #if defined(__i386) || defined(__amd64)
4438 if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) {
4439 mutex_exit(CMLB_MUTEX(cl));
4440 return (EINVAL);
4441 }
4442 #endif
4443
4444 if (cl->cl_g.dkg_ncyl == 0) {
4445 mutex_exit(CMLB_MUTEX(cl));
4446 return (EINVAL);
4447 }
4448
4449 mutex_exit(CMLB_MUTEX(cl));
4450 cmlb_clear_efi(cl, tg_cookie);
4451 ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd");
4452 ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd,raw");
4453 /*
4454 * cmlb_dkio_set_extvtoc creates duplicate minor nodes when
4455 * relabeling an SMI disk. To avoid that we remove them
4456 * before creating.
4457 * It should be OK to remove a non-existed minor node.
4458 */
4459 ddi_remove_minor_node(CMLB_DEVINFO(cl), "h");
4460 ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw");
4461
4462 (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h",
4463 S_IFBLK, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE,
4464 cl->cl_node_type, NULL, internal);
4465 (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h,raw",
4466 S_IFCHR, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE,
4467 cl->cl_node_type, NULL, internal);
4468
4469 mutex_enter(CMLB_MUTEX(cl));
4470
4471 if ((rval = cmlb_build_label_vtoc(cl, &user_vtoc)) == 0) {
4472 if ((rval = cmlb_write_label(cl, tg_cookie)) == 0) {
4473 if (cmlb_validate_geometry(cl,
4474 B_TRUE, 0, tg_cookie) != 0) {
4475 cmlb_dbg(CMLB_ERROR, cl,
4476 "cmlb_dkio_set_vtoc: "
4477 "Failed validate geometry\n");
4478 }
4479 }
4480 }
4481 mutex_exit(CMLB_MUTEX(cl));
4482 return (rval);
4483 }
4484
4485 /*
4486 * Function: cmlb_build_label_vtoc
4487 *
4488 * Description: This routine updates the driver soft state current volume table
4489 * of contents based on a user specified vtoc.
4490 *
4491 * Arguments: cl - driver soft state (unit) structure
4492 * user_vtoc - pointer to vtoc structure specifying vtoc to be used
4493 * to update the driver soft state.
4494 *
4495 * Return Code: 0
4496 * EINVAL
4497 */
4498 static int
4499 cmlb_build_label_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc)
4500 {
4501 struct dk_map *lmap;
4502 struct partition *vpart;
4503 uint_t nblks;
4504 #if defined(_SUNOS_VTOC_8)
4505 int ncyl;
4506 struct dk_map2 *lpart;
4507 #endif /* defined(_SUNOS_VTOC_8) */
4508 int i;
4509
4510 ASSERT(mutex_owned(CMLB_MUTEX(cl)));
4511
4512 /* Sanity-check the vtoc */
4513 if (user_vtoc->v_sanity != VTOC_SANE ||
4514 user_vtoc->v_sectorsz != cl->cl_sys_blocksize ||
4515 user_vtoc->v_nparts != V_NUMPAR) {
4516 cmlb_dbg(CMLB_INFO, cl,
4517 "cmlb_build_label_vtoc: vtoc not valid\n");
4518 return (EINVAL);
4519 }
4520
4521 nblks = cl->cl_g.dkg_nsect * cl->cl_g.dkg_nhead;
4522 if (nblks == 0) {
4523 cmlb_dbg(CMLB_INFO, cl,
4524 "cmlb_build_label_vtoc: geom nblks is 0\n");
4525 return (EINVAL);
4526 }
4527
4528 #if defined(_SUNOS_VTOC_8)
4529 vpart = user_vtoc->v_part;
4530 for (i = 0; i < V_NUMPAR; i++) {
4531 if (((unsigned)vpart->p_start % nblks) != 0) {
4532 cmlb_dbg(CMLB_INFO, cl,
4533 "cmlb_build_label_vtoc: p_start not multiply of"
4534 "nblks part %d p_start %d nblks %d\n", i,
4535 vpart->p_start, nblks);
4536 return (EINVAL);
4537 }
4538 ncyl = (unsigned)vpart->p_start / nblks;
4539 ncyl += (unsigned)vpart->p_size / nblks;
4540 if (((unsigned)vpart->p_size % nblks) != 0) {
4541 ncyl++;
4542 }
4543 if (ncyl > (int)cl->cl_g.dkg_ncyl) {
4544 cmlb_dbg(CMLB_INFO, cl,
4545 "cmlb_build_label_vtoc: ncyl %d > dkg_ncyl %d"
4546 "p_size %ld p_start %ld nblks %d part number %d"
4547 "tag %d\n",
4548 ncyl, cl->cl_g.dkg_ncyl, vpart->p_size,
4549 vpart->p_start, nblks,
4550 i, vpart->p_tag);
4551
4552 return (EINVAL);
4553 }
4554 vpart++;
4555 }
4556 #endif /* defined(_SUNOS_VTOC_8) */
4557
4558 /* Put appropriate vtoc structure fields into the disk label */
4559 #if defined(_SUNOS_VTOC_16)
4560 /*
4561 * The vtoc is always a 32bit data structure to maintain the
4562 * on-disk format. Convert "in place" instead of doing bcopy.
4563 */
4564 vtoctovtoc32((*user_vtoc), (*((struct vtoc32 *)&(cl->cl_vtoc))));
4565
4566 /*
4567 * in the 16-slice vtoc, starting sectors are expressed in
4568 * numbers *relative* to the start of the Solaris fdisk partition.
4569 */
4570 lmap = cl->cl_map;
4571 vpart = user_vtoc->v_part;
4572
4573 for (i = 0; i < (int)user_vtoc->v_nparts; i++, lmap++, vpart++) {
4574 lmap->dkl_cylno = (unsigned)vpart->p_start / nblks;
4575 lmap->dkl_nblk = (unsigned)vpart->p_size;
4576 }
4577
4578 #elif defined(_SUNOS_VTOC_8)
4579
4580 cl->cl_vtoc.v_bootinfo[0] = (uint32_t)user_vtoc->v_bootinfo[0];
4581 cl->cl_vtoc.v_bootinfo[1] = (uint32_t)user_vtoc->v_bootinfo[1];
4582 cl->cl_vtoc.v_bootinfo[2] = (uint32_t)user_vtoc->v_bootinfo[2];
4583
4584 cl->cl_vtoc.v_sanity = (uint32_t)user_vtoc->v_sanity;
4585 cl->cl_vtoc.v_version = (uint32_t)user_vtoc->v_version;
4586
4587 bcopy(user_vtoc->v_volume, cl->cl_vtoc.v_volume, LEN_DKL_VVOL);
4588
4589 cl->cl_vtoc.v_nparts = user_vtoc->v_nparts;
4590
4591 for (i = 0; i < 10; i++)
4592 cl->cl_vtoc.v_reserved[i] = user_vtoc->v_reserved[i];
4593
4594 /*
4595 * Note the conversion from starting sector number
4596 * to starting cylinder number.
4597 * Return error if division results in a remainder.
4598 */
4599 lmap = cl->cl_map;
4600 lpart = cl->cl_vtoc.v_part;
4601 vpart = user_vtoc->v_part;
4602
4603 for (i = 0; i < (int)user_vtoc->v_nparts; i++) {
4604 lpart->p_tag = vpart->p_tag;
4605 lpart->p_flag = vpart->p_flag;
4606 lmap->dkl_cylno = (unsigned)vpart->p_start / nblks;
4607 lmap->dkl_nblk = (unsigned)vpart->p_size;
4608
4609 lmap++;
4610 lpart++;
4611 vpart++;
4612
4613 /* (4387723) */
4614 #ifdef _LP64
4615 if (user_vtoc->timestamp[i] > TIME32_MAX) {
4616 cl->cl_vtoc.v_timestamp[i] = TIME32_MAX;
4617 } else {
4618 cl->cl_vtoc.v_timestamp[i] = user_vtoc->timestamp[i];
4619 }
4620 #else
4621 cl->cl_vtoc.v_timestamp[i] = user_vtoc->timestamp[i];
4622 #endif
4623 }
4624
4625 bcopy(user_vtoc->v_asciilabel, cl->cl_asciilabel, LEN_DKL_ASCII);
4626 #else
4627 #error "No VTOC format defined."
4628 #endif
4629 return (0);
4630 }
4631
4632 /*
4633 * Function: cmlb_clear_efi
4634 *
4635 * Description: This routine clears all EFI labels.
4636 *
4637 * Arguments:
4638 * cl driver soft state (unit) structure
4639 *
4640 * tg_cookie cookie from target driver to be passed back to target
4641 * driver when we call back to it through tg_ops.
4642 * Return Code: void
4643 */
4644 static void
4645 cmlb_clear_efi(struct cmlb_lun *cl, void *tg_cookie)
4646 {
4647 efi_gpt_t *gpt;
4648 diskaddr_t cap;
4649 int rval;
4650
4651 ASSERT(!mutex_owned(CMLB_MUTEX(cl)));
4652
4653 mutex_enter(CMLB_MUTEX(cl));
4654 cl->cl_reserved = -1;
4655 mutex_exit(CMLB_MUTEX(cl));
4656
4657 gpt = kmem_alloc(cl->cl_sys_blocksize, KM_SLEEP);
4658
4659 if (DK_TG_READ(cl, gpt, 1, cl->cl_sys_blocksize, tg_cookie) != 0) {
4660 goto done;
4661 }
4662
4663 cmlb_swap_efi_gpt(gpt);
4664 rval = cmlb_validate_efi(gpt);
4665 if (rval == 0) {
4666 /* clear primary */
4667 bzero(gpt, sizeof (efi_gpt_t));
4668 if (rval = DK_TG_WRITE(cl, gpt, 1, cl->cl_sys_blocksize,
4669 tg_cookie)) {
4670 cmlb_dbg(CMLB_INFO, cl,
4671 "cmlb_clear_efi: clear primary label failed\n");
4672 }
4673 }
4674 /* the backup */
4675 rval = DK_TG_GETCAP(cl, &cap, tg_cookie);
4676 if (rval) {
4677 goto done;
4678 }
4679
4680 if ((rval = DK_TG_READ(cl, gpt, cap - 1, cl->cl_sys_blocksize,
4681 tg_cookie)) != 0) {
4682 goto done;
4683 }
4684 cmlb_swap_efi_gpt(gpt);
4685 rval = cmlb_validate_efi(gpt);
4686 if (rval == 0) {
4687 /* clear backup */
4688 cmlb_dbg(CMLB_TRACE, cl,
4689 "cmlb_clear_efi clear backup@%lu\n", cap - 1);
4690 bzero(gpt, sizeof (efi_gpt_t));
4691 if ((rval = DK_TG_WRITE(cl, gpt, cap - 1, cl->cl_sys_blocksize,
4692 tg_cookie))) {
4693 cmlb_dbg(CMLB_INFO, cl,
4694 "cmlb_clear_efi: clear backup label failed\n");
4695 }
4696 } else {
4697 /*
4698 * Refer to comments related to off-by-1 at the
4699 * header of this file
4700 */
4701 if ((rval = DK_TG_READ(cl, gpt, cap - 2,
4702 cl->cl_sys_blocksize, tg_cookie)) != 0) {
4703 goto done;
4704 }
4705 cmlb_swap_efi_gpt(gpt);
4706 rval = cmlb_validate_efi(gpt);
4707 if (rval == 0) {
4708 /* clear legacy backup EFI label */
4709 cmlb_dbg(CMLB_TRACE, cl,
4710 "cmlb_clear_efi clear legacy backup@%lu\n",
4711 cap - 2);
4712 bzero(gpt, sizeof (efi_gpt_t));
4713 if ((rval = DK_TG_WRITE(cl, gpt, cap - 2,
4714 cl->cl_sys_blocksize, tg_cookie))) {
4715 cmlb_dbg(CMLB_INFO, cl,
4716 "cmlb_clear_efi: clear legacy backup label "
4717 "failed\n");
4718 }
4719 }
4720 }
4721
4722 done:
4723 kmem_free(gpt, cl->cl_sys_blocksize);
4724 }
4725
4726 /*
4727 * Function: cmlb_set_vtoc
4728 *
4729 * Description: This routine writes data to the appropriate positions
4730 *
4731 * Arguments:
4732 * cl driver soft state (unit) structure
4733 *
4734 * dkl the data to be written
4735 *
4736 * tg_cookie cookie from target driver to be passed back to target
4737 * driver when we call back to it through tg_ops.
4738 *
4739 * Return: void
4740 */
4741 static int
4742 cmlb_set_vtoc(struct cmlb_lun *cl, struct dk_label *dkl, void *tg_cookie)
4743 {
4744 uint_t label_addr;
4745 int sec;
4746 diskaddr_t blk;
4747 int head;
4748 int cyl;
4749 int rval;
4750
4751 #if defined(__i386) || defined(__amd64)
4752 label_addr = cl->cl_solaris_offset + DK_LABEL_LOC;
4753 #else
4754 /* Write the primary label at block 0 of the solaris partition. */
4755 label_addr = 0;
4756 #endif
4757
4758 rval = DK_TG_WRITE(cl, dkl, label_addr, cl->cl_sys_blocksize,
4759 tg_cookie);
4760
4761 if (rval != 0) {
4762 return (rval);
4763 }
4764
4765 /*
4766 * Calculate where the backup labels go. They are always on
4767 * the last alternate cylinder, but some older drives put them
4768 * on head 2 instead of the last head. They are always on the
4769 * first 5 odd sectors of the appropriate track.
4770 *
4771 * We have no choice at this point, but to believe that the
4772 * disk label is valid. Use the geometry of the disk
4773 * as described in the label.
4774 */
4775 cyl = dkl->dkl_ncyl + dkl->dkl_acyl - 1;
4776 head = dkl->dkl_nhead - 1;
4777
4778 /*
4779 * Write and verify the backup labels. Make sure we don't try to
4780 * write past the last cylinder.
4781 */
4782 for (sec = 1; ((sec < 5 * 2 + 1) && (sec < dkl->dkl_nsect)); sec += 2) {
4783 blk = (diskaddr_t)(
4784 (cyl * ((dkl->dkl_nhead * dkl->dkl_nsect) - dkl->dkl_apc)) +
4785 (head * dkl->dkl_nsect) + sec);
4786 #if defined(__i386) || defined(__amd64)
4787 blk += cl->cl_solaris_offset;
4788 #endif
4789 rval = DK_TG_WRITE(cl, dkl, blk, cl->cl_sys_blocksize,
4790 tg_cookie);
4791 cmlb_dbg(CMLB_INFO, cl,
4792 "cmlb_set_vtoc: wrote backup label %llx\n", blk);
4793 if (rval != 0) {
4794 goto exit;
4795 }
4796 }
4797 exit:
4798 return (rval);
4799 }
4800
4801 /*
4802 * Function: cmlb_clear_vtoc
4803 *
4804 * Description: This routine clears out the VTOC labels.
4805 *
4806 * Arguments:
4807 * cl driver soft state (unit) structure
4808 *
4809 * tg_cookie cookie from target driver to be passed back to target
4810 * driver when we call back to it through tg_ops.
4811 *
4812 * Return: void
4813 */
4814 static void
4815 cmlb_clear_vtoc(struct cmlb_lun *cl, void *tg_cookie)
4816 {
4817 struct dk_label *dkl;
4818
4819 mutex_exit(CMLB_MUTEX(cl));
4820 dkl = kmem_zalloc(cl->cl_sys_blocksize, KM_SLEEP);
4821 mutex_enter(CMLB_MUTEX(cl));
4822 /*
4823 * cmlb_set_vtoc uses these fields in order to figure out
4824 * where to overwrite the backup labels
4825 */
4826 dkl->dkl_apc = cl->cl_g.dkg_apc;
4827 dkl->dkl_ncyl = cl->cl_g.dkg_ncyl;
4828 dkl->dkl_acyl = cl->cl_g.dkg_acyl;
4829 dkl->dkl_nhead = cl->cl_g.dkg_nhead;
4830 dkl->dkl_nsect = cl->cl_g.dkg_nsect;
4831 mutex_exit(CMLB_MUTEX(cl));
4832 (void) cmlb_set_vtoc(cl, dkl, tg_cookie);
4833 kmem_free(dkl, cl->cl_sys_blocksize);
4834
4835 mutex_enter(CMLB_MUTEX(cl));
4836 }
4837
4838 /*
4839 * Function: cmlb_write_label
4840 *
4841 * Description: This routine will validate and write the driver soft state vtoc
4842 * contents to the device.
4843 *
4844 * Arguments:
4845 * cl cmlb handle
4846 *
4847 * tg_cookie cookie from target driver to be passed back to target
4848 * driver when we call back to it through tg_ops.
4849 *
4850 *
4851 * Return Code: the code returned by cmlb_send_scsi_cmd()
4852 * 0
4853 * EINVAL
4854 * ENXIO
4855 * ENOMEM
4856 */
4857 static int
4858 cmlb_write_label(struct cmlb_lun *cl, void *tg_cookie)
4859 {
4860 struct dk_label *dkl;
4861 short sum;
4862 short *sp;
4863 int i;
4864 int rval;
4865
4866 ASSERT(mutex_owned(CMLB_MUTEX(cl)));
4867 mutex_exit(CMLB_MUTEX(cl));
4868 dkl = kmem_zalloc(cl->cl_sys_blocksize, KM_SLEEP);
4869 mutex_enter(CMLB_MUTEX(cl));
4870
4871 bcopy(&cl->cl_vtoc, &dkl->dkl_vtoc, sizeof (struct dk_vtoc));
4872 dkl->dkl_rpm = cl->cl_g.dkg_rpm;
4873 dkl->dkl_pcyl = cl->cl_g.dkg_pcyl;
4874 dkl->dkl_apc = cl->cl_g.dkg_apc;
4875 dkl->dkl_intrlv = cl->cl_g.dkg_intrlv;
4876 dkl->dkl_ncyl = cl->cl_g.dkg_ncyl;
4877 dkl->dkl_acyl = cl->cl_g.dkg_acyl;
4878 dkl->dkl_nhead = cl->cl_g.dkg_nhead;
4879 dkl->dkl_nsect = cl->cl_g.dkg_nsect;
4880
4881 #if defined(_SUNOS_VTOC_8)
4882 dkl->dkl_obs1 = cl->cl_g.dkg_obs1;
4883 dkl->dkl_obs2 = cl->cl_g.dkg_obs2;
4884 dkl->dkl_obs3 = cl->cl_g.dkg_obs3;
4885 for (i = 0; i < NDKMAP; i++) {
4886 dkl->dkl_map[i].dkl_cylno = cl->cl_map[i].dkl_cylno;
4887 dkl->dkl_map[i].dkl_nblk = cl->cl_map[i].dkl_nblk;
4888 }
4889 bcopy(cl->cl_asciilabel, dkl->dkl_asciilabel, LEN_DKL_ASCII);
4890 #elif defined(_SUNOS_VTOC_16)
4891 dkl->dkl_skew = cl->cl_dkg_skew;
4892 #else
4893 #error "No VTOC format defined."
4894 #endif
4895
4896 dkl->dkl_magic = DKL_MAGIC;
4897 dkl->dkl_write_reinstruct = cl->cl_g.dkg_write_reinstruct;
4898 dkl->dkl_read_reinstruct = cl->cl_g.dkg_read_reinstruct;
4899
4900 /* Construct checksum for the new disk label */
4901 sum = 0;
4902 sp = (short *)dkl;
4903 i = sizeof (struct dk_label) / sizeof (short);
4904 while (i--) {
4905 sum ^= *sp++;
4906 }
4907 dkl->dkl_cksum = sum;
4908
4909 mutex_exit(CMLB_MUTEX(cl));
4910
4911 rval = cmlb_set_vtoc(cl, dkl, tg_cookie);
4912 exit:
4913 kmem_free(dkl, cl->cl_sys_blocksize);
4914 mutex_enter(CMLB_MUTEX(cl));
4915 return (rval);
4916 }
4917
4918 /*
4919 * This routine implements the DKIOCSETEFI ioctl. This ioctl is currently
4920 * used to write (or clear) the GPT Partition Table header (primary/backup)
4921 * and GUID partition Entry Array (primary/backup). It is also used to write
4922 * the Protective MBR.
4923 */
4924 static int
4925 cmlb_dkio_set_efi(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag,
4926 void *tg_cookie)
4927 {
4928 dk_efi_t user_efi;
4929 int rval = 0;
4930 void *buffer;
4931 diskaddr_t tgt_lba;
4932 boolean_t internal;
4933
4934 if (ddi_copyin(arg, &user_efi, sizeof (dk_efi_t), flag))
4935 return (EFAULT);
4936
4937 internal = VOID2BOOLEAN(
4938 (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0);
4939
4940 user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64;
4941
4942 if (user_efi.dki_length == 0 ||
4943 user_efi.dki_length > cmlb_tg_max_efi_xfer)
4944 return (EINVAL);
4945
4946 tgt_lba = user_efi.dki_lba;
4947
4948 mutex_enter(CMLB_MUTEX(cl));
4949 if ((cmlb_check_update_blockcount(cl, tg_cookie) != 0) ||
4950 (cl->cl_tgt_blocksize == 0) ||
4951 (user_efi.dki_length % cl->cl_sys_blocksize)) {
4952 mutex_exit(CMLB_MUTEX(cl));
4953 return (EINVAL);
4954 }
4955 if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize)
4956 tgt_lba = tgt_lba *
4957 cl->cl_tgt_blocksize / cl->cl_sys_blocksize;
4958 mutex_exit(CMLB_MUTEX(cl));
4959
4960 buffer = kmem_alloc(user_efi.dki_length, KM_SLEEP);
4961 if (ddi_copyin(user_efi.dki_data, buffer, user_efi.dki_length, flag)) {
4962 rval = EFAULT;
4963 } else {
4964 /*
4965 * let's clear the vtoc labels and clear the softstate
4966 * vtoc.
4967 */
4968 mutex_enter(CMLB_MUTEX(cl));
4969 if (cl->cl_vtoc.v_sanity == VTOC_SANE) {
4970 cmlb_dbg(CMLB_TRACE, cl,
4971 "cmlb_dkio_set_efi: CLEAR VTOC\n");
4972 if (cl->cl_label_from_media == CMLB_LABEL_VTOC)
4973 cmlb_clear_vtoc(cl, tg_cookie);
4974 bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc));
4975 mutex_exit(CMLB_MUTEX(cl));
4976 ddi_remove_minor_node(CMLB_DEVINFO(cl), "h");
4977 ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw");
4978 (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd",
4979 S_IFBLK,
4980 (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE,
4981 cl->cl_node_type, NULL, internal);
4982 (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd,raw",
4983 S_IFCHR,
4984 (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE,
4985 cl->cl_node_type, NULL, internal);
4986 } else
4987 mutex_exit(CMLB_MUTEX(cl));
4988
4989 rval = DK_TG_WRITE(cl, buffer, tgt_lba, user_efi.dki_length,
4990 tg_cookie);
4991
4992 if (rval == 0) {
4993 mutex_enter(CMLB_MUTEX(cl));
4994 cl->cl_f_geometry_is_valid = B_FALSE;
4995 mutex_exit(CMLB_MUTEX(cl));
4996 }
4997 }
4998 kmem_free(buffer, user_efi.dki_length);
4999 return (rval);
5000 }
5001
5002 /*
5003 * Function: cmlb_dkio_get_mboot
5004 *
5005 * Description: This routine is the driver entry point for handling user
5006 * requests to get the current device mboot (DKIOCGMBOOT)
5007 *
5008 * Arguments:
5009 * arg pointer to user provided mboot structure specifying
5010 * the current mboot.
5011 *
5012 * flag this argument is a pass through to ddi_copyxxx()
5013 * directly from the mode argument of ioctl().
5014 *
5015 * tg_cookie cookie from target driver to be passed back to target
5016 * driver when we call back to it through tg_ops.
5017 *
5018 * Return Code: 0
5019 * EINVAL
5020 * EFAULT
5021 * ENXIO
5022 */
5023 static int
5024 cmlb_dkio_get_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie)
5025 {
5026 struct mboot *mboot;
5027 int rval;
5028 size_t buffer_size;
5029
5030
5031 #if defined(_SUNOS_VTOC_8)
5032 if ((!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) || (arg == NULL)) {
5033 #elif defined(_SUNOS_VTOC_16)
5034 if (arg == NULL) {
5035 #endif
5036 return (EINVAL);
5037 }
5038
5039 /*
5040 * Read the mboot block, located at absolute block 0 on the target.
5041 */
5042 buffer_size = cl->cl_sys_blocksize;
5043
5044 cmlb_dbg(CMLB_TRACE, cl,
5045 "cmlb_dkio_get_mboot: allocation size: 0x%x\n", buffer_size);
5046
5047 mboot = kmem_zalloc(buffer_size, KM_SLEEP);
5048 if ((rval = DK_TG_READ(cl, mboot, 0, buffer_size, tg_cookie)) == 0) {
5049 if (ddi_copyout(mboot, (void *)arg,
5050 sizeof (struct mboot), flag) != 0) {
5051 rval = EFAULT;
5052 }
5053 }
5054 kmem_free(mboot, buffer_size);
5055 return (rval);
5056 }
5057
5058
5059 /*
5060 * Function: cmlb_dkio_set_mboot
5061 *
5062 * Description: This routine is the driver entry point for handling user
5063 * requests to validate and set the device master boot
5064 * (DKIOCSMBOOT).
5065 *
5066 * Arguments:
5067 * arg pointer to user provided mboot structure used to set the
5068 * master boot.
5069 *
5070 * flag this argument is a pass through to ddi_copyxxx()
5071 * directly from the mode argument of ioctl().
5072 *
5073 * tg_cookie cookie from target driver to be passed back to target
5074 * driver when we call back to it through tg_ops.
5075 *
5076 * Return Code: 0
5077 * EINVAL
5078 * EFAULT
5079 * ENXIO
5080 */
5081 static int
5082 cmlb_dkio_set_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie)
5083 {
5084 struct mboot *mboot = NULL;
5085 int rval;
5086 ushort_t magic;
5087
5088
5089 ASSERT(!mutex_owned(CMLB_MUTEX(cl)));
5090
5091 #if defined(_SUNOS_VTOC_8)
5092 if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) {
5093 return (EINVAL);
5094 }
5095 #endif
5096
5097 if (arg == NULL) {
5098 return (EINVAL);
5099 }
5100
5101 mboot = kmem_zalloc(cl->cl_sys_blocksize, KM_SLEEP);
5102
5103 if (ddi_copyin((const void *)arg, mboot,
5104 cl->cl_sys_blocksize, flag) != 0) {
5105 kmem_free(mboot, cl->cl_sys_blocksize);
5106 return (EFAULT);
5107 }
5108
5109 /* Is this really a master boot record? */
5110 magic = LE_16(mboot->signature);
5111 if (magic != MBB_MAGIC) {
5112 kmem_free(mboot, cl->cl_sys_blocksize);
5113 return (EINVAL);
5114 }
5115
5116 rval = DK_TG_WRITE(cl, mboot, 0, cl->cl_sys_blocksize, tg_cookie);
5117
5118 mutex_enter(CMLB_MUTEX(cl));
5119 #if defined(__i386) || defined(__amd64)
5120 if (rval == 0) {
5121 /*
5122 * mboot has been written successfully.
5123 * update the fdisk and vtoc tables in memory
5124 */
5125 rval = cmlb_update_fdisk_and_vtoc(cl, tg_cookie);
5126 if ((!cl->cl_f_geometry_is_valid) || (rval != 0)) {
5127 mutex_exit(CMLB_MUTEX(cl));
5128 kmem_free(mboot, cl->cl_sys_blocksize);
5129 return (rval);
5130 }
5131 }
5132
5133 #ifdef __lock_lint
5134 cmlb_setup_default_geometry(cl, tg_cookie);
5135 #endif
5136
5137 #else
5138 if (rval == 0) {
5139 /*
5140 * mboot has been written successfully.
5141 * set up the default geometry and VTOC
5142 */
5143 if (cl->cl_blockcount <= CMLB_EXTVTOC_LIMIT)
5144 cmlb_setup_default_geometry(cl, tg_cookie);
5145 }
5146 #endif
5147 cl->cl_msglog_flag |= CMLB_ALLOW_2TB_WARN;
5148 mutex_exit(CMLB_MUTEX(cl));
5149 kmem_free(mboot, cl->cl_sys_blocksize);
5150 return (rval);
5151 }
5152
5153
5154 #if defined(__i386) || defined(__amd64)
5155 /*ARGSUSED*/
5156 static int
5157 cmlb_dkio_set_ext_part(struct cmlb_lun *cl, caddr_t arg, int flag,
5158 void *tg_cookie)
5159 {
5160 int fdisk_rval;
5161 diskaddr_t capacity;
5162
5163 ASSERT(!mutex_owned(CMLB_MUTEX(cl)));
5164
5165 mutex_enter(CMLB_MUTEX(cl));
5166 capacity = cl->cl_blockcount;
5167 fdisk_rval = cmlb_read_fdisk(cl, capacity, tg_cookie);
5168 if (fdisk_rval != 0) {
5169 mutex_exit(CMLB_MUTEX(cl));
5170 return (fdisk_rval);
5171 }
5172
5173 mutex_exit(CMLB_MUTEX(cl));
5174 return (fdisk_rval);
5175 }
5176 #endif
5177
5178 /*
5179 * Function: cmlb_setup_default_geometry
5180 *
5181 * Description: This local utility routine sets the default geometry as part of
5182 * setting the device mboot.
5183 *
5184 * Arguments:
5185 * cl driver soft state (unit) structure
5186 *
5187 * tg_cookie cookie from target driver to be passed back to target
5188 * driver when we call back to it through tg_ops.
5189 *
5190 *
5191 * Note: This may be redundant with cmlb_build_default_label.
5192 */
5193 static void
5194 cmlb_setup_default_geometry(struct cmlb_lun *cl, void *tg_cookie)
5195 {
5196 struct cmlb_geom pgeom;
5197 struct cmlb_geom *pgeomp = &pgeom;
5198 int ret;
5199 int geom_base_cap = 1;
5200
5201
5202 ASSERT(mutex_owned(CMLB_MUTEX(cl)));
5203
5204 /* zero out the soft state geometry and partition table. */
5205 bzero(&cl->cl_g, sizeof (struct dk_geom));
5206 bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc));
5207 bzero(cl->cl_map, NDKMAP * (sizeof (struct dk_map)));
5208
5209 /*
5210 * For the rpm, we use the minimum for the disk.
5211 * For the head, cyl and number of sector per track,
5212 * if the capacity <= 1GB, head = 64, sect = 32.
5213 * else head = 255, sect 63
5214 * Note: the capacity should be equal to C*H*S values.
5215 * This will cause some truncation of size due to
5216 * round off errors. For CD-ROMs, this truncation can
5217 * have adverse side effects, so returning ncyl and
5218 * nhead as 1. The nsect will overflow for most of
5219 * CD-ROMs as nsect is of type ushort.
5220 */
5221 if (cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8) {
5222 /*
5223 * newfs currently can not handle 255 ntracks for SPARC
5224 * so get the geometry from target driver instead of coming up
5225 * with one based on capacity.
5226 */
5227 mutex_exit(CMLB_MUTEX(cl));
5228 ret = DK_TG_GETPHYGEOM(cl, pgeomp, tg_cookie);
5229 mutex_enter(CMLB_MUTEX(cl));
5230
5231 if (ret == 0) {
5232 geom_base_cap = 0;
5233 } else {
5234 cmlb_dbg(CMLB_ERROR, cl,
5235 "cmlb_setup_default_geometry: "
5236 "tg_getphygeom failed %d\n", ret);
5237
5238 /* do default setting, geometry based on capacity */
5239 }
5240 }
5241
5242 if (geom_base_cap) {
5243 if (ISCD(cl)) {
5244 cl->cl_g.dkg_ncyl = 1;
5245 cl->cl_g.dkg_nhead = 1;
5246 cl->cl_g.dkg_nsect = cl->cl_blockcount;
5247 } else if (cl->cl_blockcount < 160) {
5248 /* Less than 80K */
5249 cl->cl_g.dkg_nhead = 1;
5250 cl->cl_g.dkg_ncyl = cl->cl_blockcount;
5251 cl->cl_g.dkg_nsect = 1;
5252 } else if (cl->cl_blockcount <= 0x1000) {
5253 /* Needed for unlabeled SCSI floppies. */
5254 cl->cl_g.dkg_nhead = 2;
5255 cl->cl_g.dkg_ncyl = 80;
5256 cl->cl_g.dkg_pcyl = 80;
5257 cl->cl_g.dkg_nsect = cl->cl_blockcount / (2 * 80);
5258 } else if (cl->cl_blockcount <= 0x200000) {
5259 cl->cl_g.dkg_nhead = 64;
5260 cl->cl_g.dkg_nsect = 32;
5261 cl->cl_g.dkg_ncyl = cl->cl_blockcount / (64 * 32);
5262 } else {
5263 cl->cl_g.dkg_nhead = 255;
5264
5265 cl->cl_g.dkg_nsect = ((cl->cl_blockcount +
5266 (UINT16_MAX * 255 * 63) - 1) /
5267 (UINT16_MAX * 255 * 63)) * 63;
5268
5269 if (cl->cl_g.dkg_nsect == 0)
5270 cl->cl_g.dkg_nsect = (UINT16_MAX / 63) * 63;
5271
5272 cl->cl_g.dkg_ncyl = cl->cl_blockcount /
5273 (255 * cl->cl_g.dkg_nsect);
5274 }
5275
5276 cl->cl_g.dkg_acyl = 0;
5277 cl->cl_g.dkg_bcyl = 0;
5278 cl->cl_g.dkg_intrlv = 1;
5279 cl->cl_g.dkg_rpm = 200;
5280 if (cl->cl_g.dkg_pcyl == 0)
5281 cl->cl_g.dkg_pcyl = cl->cl_g.dkg_ncyl +
5282 cl->cl_g.dkg_acyl;
5283 } else {
5284 cl->cl_g.dkg_ncyl = (short)pgeomp->g_ncyl;
5285 cl->cl_g.dkg_acyl = pgeomp->g_acyl;
5286 cl->cl_g.dkg_nhead = pgeomp->g_nhead;
5287 cl->cl_g.dkg_nsect = pgeomp->g_nsect;
5288 cl->cl_g.dkg_intrlv = pgeomp->g_intrlv;
5289 cl->cl_g.dkg_rpm = pgeomp->g_rpm;
5290 cl->cl_g.dkg_pcyl = cl->cl_g.dkg_ncyl + cl->cl_g.dkg_acyl;
5291 }
5292
5293 cl->cl_g.dkg_read_reinstruct = 0;
5294 cl->cl_g.dkg_write_reinstruct = 0;
5295 cl->cl_solaris_size = cl->cl_g.dkg_ncyl *
5296 cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect;
5297
5298 cl->cl_map['a'-'a'].dkl_cylno = 0;
5299 cl->cl_map['a'-'a'].dkl_nblk = cl->cl_solaris_size;
5300
5301 cl->cl_map['c'-'a'].dkl_cylno = 0;
5302 cl->cl_map['c'-'a'].dkl_nblk = cl->cl_solaris_size;
5303
5304 cl->cl_vtoc.v_part[2].p_tag = V_BACKUP;
5305 cl->cl_vtoc.v_part[2].p_flag = V_UNMNT;
5306 cl->cl_vtoc.v_nparts = V_NUMPAR;
5307 cl->cl_vtoc.v_version = V_VERSION;
5308 (void) sprintf((char *)cl->cl_asciilabel, "DEFAULT cyl %d alt %d"
5309 " hd %d sec %d", cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl,
5310 cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect);
5311
5312 cl->cl_f_geometry_is_valid = B_FALSE;
5313 }
5314
5315
5316 #if defined(__i386) || defined(__amd64)
5317 /*
5318 * Function: cmlb_update_fdisk_and_vtoc
5319 *
5320 * Description: This local utility routine updates the device fdisk and vtoc
5321 * as part of setting the device mboot.
5322 *
5323 * Arguments:
5324 * cl driver soft state (unit) structure
5325 *
5326 * tg_cookie cookie from target driver to be passed back to target
5327 * driver when we call back to it through tg_ops.
5328 *
5329 *
5330 * Return Code: 0 for success or errno-type return code.
5331 *
5332 * Note:x86: This looks like a duplicate of cmlb_validate_geometry(), but
5333 * these did exist separately in x86 sd.c.
5334 */
5335 static int
5336 cmlb_update_fdisk_and_vtoc(struct cmlb_lun *cl, void *tg_cookie)
5337 {
5338 int count;
5339 int label_rc = 0;
5340 int fdisk_rval;
5341 diskaddr_t capacity;
5342
5343 ASSERT(mutex_owned(CMLB_MUTEX(cl)));
5344
5345 if (cmlb_check_update_blockcount(cl, tg_cookie) != 0)
5346 return (EINVAL);
5347
5348 #if defined(_SUNOS_VTOC_16)
5349 /*
5350 * Set up the "whole disk" fdisk partition; this should always
5351 * exist, regardless of whether the disk contains an fdisk table
5352 * or vtoc.
5353 */
5354 cl->cl_map[P0_RAW_DISK].dkl_cylno = 0;
5355 cl->cl_map[P0_RAW_DISK].dkl_nblk = cl->cl_blockcount;
5356 #endif /* defined(_SUNOS_VTOC_16) */
5357
5358 /*
5359 * copy the lbasize and capacity so that if they're
5360 * reset while we're not holding the CMLB_MUTEX(cl), we will
5361 * continue to use valid values after the CMLB_MUTEX(cl) is
5362 * reacquired.
5363 */
5364 capacity = cl->cl_blockcount;
5365
5366 /*
5367 * refresh the logical and physical geometry caches.
5368 * (data from mode sense format/rigid disk geometry pages,
5369 * and scsi_ifgetcap("geometry").
5370 */
5371 cmlb_resync_geom_caches(cl, capacity, tg_cookie);
5372
5373 /*
5374 * Only DIRECT ACCESS devices will have Scl labels.
5375 * CD's supposedly have a Scl label, too
5376 */
5377 if (cl->cl_device_type == DTYPE_DIRECT || ISREMOVABLE(cl)) {
5378 fdisk_rval = cmlb_read_fdisk(cl, capacity, tg_cookie);
5379 if (fdisk_rval != 0) {
5380 ASSERT(mutex_owned(CMLB_MUTEX(cl)));
5381 return (fdisk_rval);
5382 }
5383
5384 if (cl->cl_solaris_size <= DK_LABEL_LOC) {
5385 /*
5386 * Found fdisk table but no Solaris partition entry,
5387 * so don't call cmlb_uselabel() and don't create
5388 * a default label.
5389 */
5390 label_rc = 0;
5391 cl->cl_f_geometry_is_valid = B_TRUE;
5392 goto no_solaris_partition;
5393 }
5394 } else if (capacity < 0) {
5395 ASSERT(mutex_owned(CMLB_MUTEX(cl)));
5396 return (EINVAL);
5397 }
5398
5399 /*
5400 * For Removable media We reach here if we have found a
5401 * SOLARIS PARTITION.
5402 * If cl_f_geometry_is_valid is B_FALSE it indicates that the SOLARIS
5403 * PARTITION has changed from the previous one, hence we will setup a
5404 * default VTOC in this case.
5405 */
5406 if (!cl->cl_f_geometry_is_valid) {
5407 /* if we get here it is writable */
5408 /* we are called from SMBOOT, and after a write of fdisk */
5409 cmlb_build_default_label(cl, tg_cookie);
5410 label_rc = 0;
5411 }
5412
5413 no_solaris_partition:
5414
5415 #if defined(_SUNOS_VTOC_16)
5416 /*
5417 * If we have valid geometry, set up the remaining fdisk partitions.
5418 * Note that dkl_cylno is not used for the fdisk map entries, so
5419 * we set it to an entirely bogus value.
5420 */
5421 for (count = 0; count < FDISK_PARTS; count++) {
5422 cl->cl_map[FDISK_P1 + count].dkl_cylno = UINT32_MAX;
5423 cl->cl_map[FDISK_P1 + count].dkl_nblk =
5424 cl->cl_fmap[count].fmap_nblk;
5425 cl->cl_offset[FDISK_P1 + count] =
5426 cl->cl_fmap[count].fmap_start;
5427 }
5428 #endif
5429
5430 for (count = 0; count < NDKMAP; count++) {
5431 #if defined(_SUNOS_VTOC_8)
5432 struct dk_map *lp = &cl->cl_map[count];
5433 cl->cl_offset[count] =
5434 cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno;
5435 #elif defined(_SUNOS_VTOC_16)
5436 struct dkl_partition *vp = &cl->cl_vtoc.v_part[count];
5437 cl->cl_offset[count] = vp->p_start + cl->cl_solaris_offset;
5438 #else
5439 #error "No VTOC format defined."
5440 #endif
5441 }
5442
5443 ASSERT(mutex_owned(CMLB_MUTEX(cl)));
5444 return (label_rc);
5445 }
5446 #endif
5447
5448 #if defined(__i386) || defined(__amd64)
5449 static int
5450 cmlb_dkio_get_virtgeom(struct cmlb_lun *cl, caddr_t arg, int flag)
5451 {
5452 int err = 0;
5453
5454 /* Return the driver's notion of the media's logical geometry */
5455 struct dk_geom disk_geom;
5456 struct dk_geom *dkgp = &disk_geom;
5457
5458 mutex_enter(CMLB_MUTEX(cl));
5459 /*
5460 * If there is no HBA geometry available, or
5461 * if the HBA returned us something that doesn't
5462 * really fit into an Int 13/function 8 geometry
5463 * result, just fail the ioctl. See PSARC 1998/313.
5464 */
5465 if (cl->cl_lgeom.g_nhead == 0 ||
5466 cl->cl_lgeom.g_nsect == 0 ||
5467 cl->cl_lgeom.g_ncyl > 1024) {
5468 mutex_exit(CMLB_MUTEX(cl));
5469 err = EINVAL;
5470 } else {
5471 dkgp->dkg_ncyl = cl->cl_lgeom.g_ncyl;
5472 dkgp->dkg_acyl = cl->cl_lgeom.g_acyl;
5473 dkgp->dkg_pcyl = dkgp->dkg_ncyl + dkgp->dkg_acyl;
5474 dkgp->dkg_nhead = cl->cl_lgeom.g_nhead;
5475 dkgp->dkg_nsect = cl->cl_lgeom.g_nsect;
5476
5477 mutex_exit(CMLB_MUTEX(cl));
5478 if (ddi_copyout(dkgp, (void *)arg,
5479 sizeof (struct dk_geom), flag)) {
5480 err = EFAULT;
5481 } else {
5482 err = 0;
5483 }
5484 }
5485 return (err);
5486 }
5487 #endif
5488
5489 #if defined(__i386) || defined(__amd64)
5490 static int
5491 cmlb_dkio_get_phygeom(struct cmlb_lun *cl, caddr_t arg, int flag,
5492 void *tg_cookie)
5493 {
5494 int err = 0;
5495 diskaddr_t capacity;
5496
5497
5498 /* Return the driver's notion of the media physical geometry */
5499 struct dk_geom disk_geom;
5500 struct dk_geom *dkgp = &disk_geom;
5501
5502 mutex_enter(CMLB_MUTEX(cl));
5503
5504 if (cl->cl_g.dkg_nhead != 0 &&
5505 cl->cl_g.dkg_nsect != 0) {
5506 /*
5507 * We succeeded in getting a geometry, but
5508 * right now it is being reported as just the
5509 * Solaris fdisk partition, just like for
5510 * DKIOCGGEOM. We need to change that to be
5511 * correct for the entire disk now.
5512 */
5513 bcopy(&cl->cl_g, dkgp, sizeof (*dkgp));
5514 dkgp->dkg_acyl = 0;
5515 dkgp->dkg_ncyl = cl->cl_blockcount /
5516 (dkgp->dkg_nhead * dkgp->dkg_nsect);
5517 } else {
5518 bzero(dkgp, sizeof (struct dk_geom));
5519 /*
5520 * This disk does not have a Solaris VTOC
5521 * so we must present a physical geometry
5522 * that will remain consistent regardless
5523 * of how the disk is used. This will ensure
5524 * that the geometry does not change regardless
5525 * of the fdisk partition type (ie. EFI, FAT32,
5526 * Solaris, etc).
5527 */
5528 if (ISCD(cl)) {
5529 dkgp->dkg_nhead = cl->cl_pgeom.g_nhead;
5530 dkgp->dkg_nsect = cl->cl_pgeom.g_nsect;
5531 dkgp->dkg_ncyl = cl->cl_pgeom.g_ncyl;
5532 dkgp->dkg_acyl = cl->cl_pgeom.g_acyl;
5533 } else {
5534 /*
5535 * Invalid cl_blockcount can generate invalid
5536 * dk_geom and may result in division by zero
5537 * system failure. Should make sure blockcount
5538 * is valid before using it here.
5539 */
5540 if (cl->cl_blockcount == 0) {
5541 mutex_exit(CMLB_MUTEX(cl));
5542 err = EIO;
5543 return (err);
5544 }
5545 /*
5546 * Refer to comments related to off-by-1 at the
5547 * header of this file
5548 */
5549 if (cl->cl_alter_behavior & CMLB_OFF_BY_ONE)
5550 capacity = cl->cl_blockcount - 1;
5551 else
5552 capacity = cl->cl_blockcount;
5553
5554 cmlb_convert_geometry(cl, capacity, dkgp, tg_cookie);
5555 dkgp->dkg_acyl = 0;
5556 dkgp->dkg_ncyl = capacity /
5557 (dkgp->dkg_nhead * dkgp->dkg_nsect);
5558 }
5559 }
5560 dkgp->dkg_pcyl = dkgp->dkg_ncyl + dkgp->dkg_acyl;
5561
5562 mutex_exit(CMLB_MUTEX(cl));
5563 if (ddi_copyout(dkgp, (void *)arg, sizeof (struct dk_geom), flag))
5564 err = EFAULT;
5565
5566 return (err);
5567 }
5568 #endif
5569
5570 #if defined(__i386) || defined(__amd64)
5571 static int
5572 cmlb_dkio_partinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag)
5573 {
5574 int err = 0;
5575
5576 /*
5577 * Return parameters describing the selected disk slice.
5578 * Note: this ioctl is for the intel platform only
5579 */
5580 int part;
5581
5582 part = CMLBPART(dev);
5583
5584 mutex_enter(CMLB_MUTEX(cl));
5585 /* don't check cl_solaris_size for pN */
5586 if (part < P0_RAW_DISK && cl->cl_solaris_size == 0) {
5587 err = EIO;
5588 mutex_exit(CMLB_MUTEX(cl));
5589 } else {
5590 struct part_info p;
5591
5592 p.p_start = (daddr_t)cl->cl_offset[part];
5593 p.p_length = (int)cl->cl_map[part].dkl_nblk;
5594 mutex_exit(CMLB_MUTEX(cl));
5595 #ifdef _MULTI_DATAMODEL
5596 switch (ddi_model_convert_from(flag & FMODELS)) {
5597 case DDI_MODEL_ILP32:
5598 {
5599 struct part_info32 p32;
5600
5601 p32.p_start = (daddr32_t)p.p_start;
5602 p32.p_length = p.p_length;
5603 if (ddi_copyout(&p32, (void *)arg,
5604 sizeof (p32), flag))
5605 err = EFAULT;
5606 break;
5607 }
5608
5609 case DDI_MODEL_NONE:
5610 {
5611 if (ddi_copyout(&p, (void *)arg, sizeof (p),
5612 flag))
5613 err = EFAULT;
5614 break;
5615 }
5616 }
5617 #else /* ! _MULTI_DATAMODEL */
5618 if (ddi_copyout(&p, (void *)arg, sizeof (p), flag))
5619 err = EFAULT;
5620 #endif /* _MULTI_DATAMODEL */
5621 }
5622 return (err);
5623 }
5624 static int
5625 cmlb_dkio_extpartinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag)
5626 {
5627 int err = 0;
5628
5629 /*
5630 * Return parameters describing the selected disk slice.
5631 * Note: this ioctl is for the intel platform only
5632 */
5633 int part;
5634
5635 part = CMLBPART(dev);
5636
5637 mutex_enter(CMLB_MUTEX(cl));
5638 /* don't check cl_solaris_size for pN */
5639 if (part < P0_RAW_DISK && cl->cl_solaris_size == 0) {
5640 err = EIO;
5641 mutex_exit(CMLB_MUTEX(cl));
5642 } else {
5643 struct extpart_info p;
5644
5645 p.p_start = (diskaddr_t)cl->cl_offset[part];
5646 p.p_length = (diskaddr_t)cl->cl_map[part].dkl_nblk;
5647 mutex_exit(CMLB_MUTEX(cl));
5648 if (ddi_copyout(&p, (void *)arg, sizeof (p), flag))
5649 err = EFAULT;
5650 }
5651 return (err);
5652 }
5653 #endif
5654
5655 int
5656 cmlb_prop_op(cmlb_handle_t cmlbhandle,
5657 dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
5658 char *name, caddr_t valuep, int *lengthp, int part, void *tg_cookie)
5659 {
5660 struct cmlb_lun *cl;
5661 diskaddr_t capacity;
5662 uint32_t lbasize;
5663 enum dp { DP_NBLOCKS, DP_BLKSIZE, DP_SSD, DP_ROT } dp;
5664 int callers_length;
5665 caddr_t buffer;
5666 uint64_t nblocks64;
5667 uint_t dblk;
5668 tg_attribute_t tgattr;
5669
5670 /* Always fallback to ddi_prop_op... */
5671 cl = (struct cmlb_lun *)cmlbhandle;
5672 if (cl == NULL) {
5673 fallback: return (ddi_prop_op(dev, dip, prop_op, mod_flags,
5674 name, valuep, lengthp));
5675 }
5676
5677 /* Pick up capacity and blocksize information. */
5678 capacity = cl->cl_blockcount;
5679 if (capacity == 0)
5680 goto fallback;
5681 lbasize = cl->cl_tgt_blocksize;
5682 if (lbasize == 0)
5683 lbasize = DEV_BSIZE; /* 0 -> DEV_BSIZE units */
5684
5685 /* Check for dynamic property of whole device. */
5686 if (dev == DDI_DEV_T_ANY) {
5687 /* Fallback to ddi_prop_op if we don't understand. */
5688 if (strcmp(name, "device-nblocks") == 0)
5689 dp = DP_NBLOCKS;
5690 else if (strcmp(name, "device-blksize") == 0)
5691 dp = DP_BLKSIZE;
5692 else if (strcmp(name, "device-solid-state") == 0)
5693 dp = DP_SSD;
5694 else if (strcmp(name, "device-rotational") == 0)
5695 dp = DP_ROT;
5696 else
5697 goto fallback;
5698
5699 /* get callers length, establish length of our dynamic prop */
5700 callers_length = *lengthp;
5701 if (dp == DP_NBLOCKS)
5702 *lengthp = sizeof (uint64_t);
5703 else if ((dp == DP_BLKSIZE) || (dp == DP_SSD))
5704 *lengthp = sizeof (uint32_t);
5705
5706 /* service request for the length of the property */
5707 if (prop_op == PROP_LEN)
5708 return (DDI_PROP_SUCCESS);
5709
5710 switch (prop_op) {
5711 case PROP_LEN_AND_VAL_ALLOC:
5712 if ((buffer = kmem_alloc(*lengthp,
5713 (mod_flags & DDI_PROP_CANSLEEP) ?
5714 KM_SLEEP : KM_NOSLEEP)) == NULL)
5715 return (DDI_PROP_NO_MEMORY);
5716 *(caddr_t *)valuep = buffer; /* set callers buf */
5717 break;
5718
5719 case PROP_LEN_AND_VAL_BUF:
5720 /* the length of the prop and the request must match */
5721 if (callers_length != *lengthp)
5722 return (DDI_PROP_INVAL_ARG);
5723 buffer = valuep; /* get callers buf */
5724 break;
5725
5726 default:
5727 return (DDI_PROP_INVAL_ARG);
5728 }
5729
5730 /* transfer the value into the buffer */
5731 switch (dp) {
5732 case DP_NBLOCKS:
5733 *((uint64_t *)buffer) = capacity;
5734 break;
5735 case DP_BLKSIZE:
5736 *((uint32_t *)buffer) = lbasize;
5737 break;
5738 case DP_SSD:
5739 if (DK_TG_GETATTRIBUTE(cl, &tgattr, tg_cookie) != 0)
5740 tgattr.media_is_solid_state = B_FALSE;
5741 *((uint32_t *)buffer) =
5742 tgattr.media_is_solid_state ? 1 : 0;
5743 break;
5744 case DP_ROT:
5745 if (DK_TG_GETATTRIBUTE(cl, &tgattr, tg_cookie) != 0)
5746 tgattr.media_is_rotational = B_TRUE;
5747 *((uint32_t *)buffer) =
5748 tgattr.media_is_rotational ? 1 : 0;
5749 break;
5750 }
5751 return (DDI_PROP_SUCCESS);
5752 }
5753
5754 /*
5755 * Support dynamic size oriented properties of partition. Requests
5756 * issued under conditions where size is valid are passed to
5757 * ddi_prop_op_nblocks with the size information, otherwise the
5758 * request is passed to ddi_prop_op. Size depends on valid geometry.
5759 */
5760 if (!cmlb_is_valid(cmlbhandle))
5761 goto fallback;
5762
5763 /* Get partition nblocks value. */
5764 (void) cmlb_partinfo(cmlbhandle, part,
5765 (diskaddr_t *)&nblocks64, NULL, NULL, NULL, tg_cookie);
5766
5767 /*
5768 * Assume partition information is in sys_blocksize units, compute
5769 * divisor for size(9P) property representation.
5770 */
5771 dblk = lbasize / cl->cl_sys_blocksize;
5772
5773 /* Now let ddi_prop_op_nblocks_blksize() handle the request. */
5774 return (ddi_prop_op_nblocks_blksize(dev, dip, prop_op, mod_flags,
5775 name, valuep, lengthp, nblocks64 / dblk, lbasize));
5776 }
5777