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