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