Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/openprom.c
+++ new/usr/src/uts/common/io/openprom.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 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 /*
27 27 * Ported from 4.1.1_PSRA: "@(#)openprom.c 1.19 91/02/19 SMI";
28 28 *
29 29 * Porting notes:
30 30 *
31 31 * OPROMU2P unsupported after SunOS 4.x.
32 32 *
33 33 * Only one of these devices per system is allowed.
34 34 */
35 35
36 36 /*
37 37 * Openprom eeprom options/devinfo driver.
38 38 */
39 39
40 40 #include <sys/types.h>
41 41 #include <sys/errno.h>
42 42 #include <sys/file.h>
43 43 #include <sys/cmn_err.h>
44 44 #include <sys/kmem.h>
45 45 #include <sys/openpromio.h>
46 46 #include <sys/conf.h>
47 47 #include <sys/stat.h>
48 48 #include <sys/modctl.h>
49 49 #include <sys/debug.h>
50 50 #include <sys/autoconf.h>
51 51 #include <sys/ddi.h>
52 52 #include <sys/sunddi.h>
53 53 #include <sys/promif.h>
54 54 #include <sys/sysmacros.h> /* offsetof */
55 55 #include <sys/nvpair.h>
56 56 #include <sys/wanboot_impl.h>
57 57 #include <sys/zone.h>
58 58 #include <sys/consplat.h>
59 59 #include <sys/bootconf.h>
60 60 #include <sys/systm.h>
61 61 #include <sys/bootprops.h>
62 62
63 63 #define MAX_OPENS 32 /* Up to this many simultaneous opens */
64 64
65 65 #define IOC_IDLE 0 /* snapshot ioctl states */
66 66 #define IOC_SNAP 1 /* snapshot in progress */
67 67 #define IOC_DONE 2 /* snapshot done, but not copied out */
68 68 #define IOC_COPY 3 /* copyout in progress */
69 69
70 70 /*
71 71 * XXX Make this dynamic.. or (better still) make the interface stateless
72 72 */
73 73 static struct oprom_state {
74 74 pnode_t current_id; /* node we're fetching props from */
75 75 int16_t already_open; /* if true, this instance is 'active' */
76 76 int16_t ioc_state; /* snapshot ioctl state */
77 77 char *snapshot; /* snapshot of all prom nodes */
78 78 size_t size; /* size of snapshot */
79 79 prom_generation_cookie_t tree_gen;
80 80 } oprom_state[MAX_OPENS];
81 81
82 82 static kmutex_t oprom_lock; /* serialize instance assignment */
83 83
84 84 static int opromopen(dev_t *, int, int, cred_t *);
85 85 static int opromioctl(dev_t, int, intptr_t, int, cred_t *, int *);
86 86 static int opromclose(dev_t, int, int, cred_t *);
87 87
88 88 static int opinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
89 89 void **result);
90 90 static int opattach(dev_info_t *, ddi_attach_cmd_t cmd);
91 91 static int opdetach(dev_info_t *, ddi_detach_cmd_t cmd);
92 92
93 93 /* help functions */
94 94 static int oprom_checknodeid(pnode_t, pnode_t);
95 95 static int oprom_copyinstr(intptr_t, char *, size_t, size_t);
96 96 static int oprom_copynode(pnode_t, uint_t, char **, size_t *);
97 97 static int oprom_snapshot(struct oprom_state *, intptr_t);
98 98 static int oprom_copyout(struct oprom_state *, intptr_t);
99 99 static int oprom_setstate(struct oprom_state *, int16_t);
100 100
101 101 static struct cb_ops openeepr_cb_ops = {
102 102 opromopen, /* open */
103 103 opromclose, /* close */
104 104 nodev, /* strategy */
105 105 nodev, /* print */
106 106 nodev, /* dump */
107 107 nodev, /* read */
108 108 nodev, /* write */
109 109 opromioctl, /* ioctl */
110 110 nodev, /* devmap */
111 111 nodev, /* mmap */
112 112 nodev, /* segmap */
113 113 nochpoll, /* poll */
114 114 ddi_prop_op, /* prop_op */
115 115 NULL, /* streamtab */
116 116 D_NEW | D_MP /* Driver compatibility flag */
117 117 };
118 118
119 119 static struct dev_ops openeepr_ops = {
120 120 DEVO_REV, /* devo_rev, */
121 121 0, /* refcnt */
122 122 opinfo, /* info */
123 123 nulldev, /* identify */
124 124 nulldev, /* probe */
125 125 opattach, /* attach */
126 126 opdetach, /* detach */
127 127 nodev, /* reset */
128 128 &openeepr_cb_ops, /* driver operations */
129 129 NULL, /* bus operations */
130 130 NULL, /* power */
131 131 ddi_quiesce_not_needed, /* quiesce */
132 132 };
133 133
134 134 /*
↓ open down ↓ |
134 lines elided |
↑ open up ↑ |
135 135 * Module linkage information for the kernel.
136 136 */
137 137 static struct modldrv modldrv = {
138 138 &mod_driverops,
139 139 "OPENPROM/NVRAM Driver",
140 140 &openeepr_ops
141 141 };
142 142
143 143 static struct modlinkage modlinkage = {
144 144 MODREV_1,
145 - &modldrv,
146 - NULL
145 + { &modldrv, NULL }
147 146 };
148 147
149 148 int
150 149 _init(void)
151 150 {
152 151 int error;
153 152
154 153 mutex_init(&oprom_lock, NULL, MUTEX_DRIVER, NULL);
155 154
156 155 error = mod_install(&modlinkage);
157 156 if (error != 0) {
158 157 mutex_destroy(&oprom_lock);
159 158 return (error);
160 159 }
161 160
162 161 return (0);
163 162 }
164 163
165 164 int
166 165 _info(struct modinfo *modinfop)
167 166 {
168 167 return (mod_info(&modlinkage, modinfop));
169 168 }
170 169
171 170 int
172 171 _fini(void)
173 172 {
174 173 int error;
175 174
176 175 error = mod_remove(&modlinkage);
177 176 if (error != 0)
178 177 return (error);
179 178
180 179 mutex_destroy(&oprom_lock);
181 180 return (0);
182 181 }
183 182
184 183 static dev_info_t *opdip;
185 184 static pnode_t options_nodeid;
186 185
187 186 /*ARGSUSED*/
188 187 static int
189 188 opinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
190 189 {
191 190 int error = DDI_FAILURE;
192 191
193 192 switch (infocmd) {
194 193 case DDI_INFO_DEVT2DEVINFO:
195 194 *result = (void *)opdip;
196 195 error = DDI_SUCCESS;
197 196 break;
198 197 case DDI_INFO_DEVT2INSTANCE:
199 198 /* All dev_t's map to the same, single instance */
200 199 *result = (void *)0;
201 200 error = DDI_SUCCESS;
202 201 break;
203 202 default:
204 203 break;
205 204 }
206 205
207 206 return (error);
208 207 }
209 208
210 209 static int
211 210 opattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
212 211 {
213 212 switch (cmd) {
214 213
215 214 case DDI_ATTACH:
216 215 if (prom_is_openprom()) {
217 216 options_nodeid = prom_optionsnode();
218 217 } else {
219 218 options_nodeid = OBP_BADNODE;
220 219 }
221 220
222 221 opdip = dip;
223 222
224 223 if (ddi_create_minor_node(dip, "openprom", S_IFCHR,
225 224 0, DDI_PSEUDO, NULL) == DDI_FAILURE) {
226 225 return (DDI_FAILURE);
227 226 }
228 227
229 228 return (DDI_SUCCESS);
230 229
231 230 default:
232 231 return (DDI_FAILURE);
233 232 }
234 233 }
235 234
236 235 static int
237 236 opdetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
238 237 {
239 238 if (cmd != DDI_DETACH)
240 239 return (DDI_FAILURE);
241 240
242 241 ddi_remove_minor_node(dip, NULL);
243 242 opdip = NULL;
244 243
245 244 return (DDI_SUCCESS);
246 245 }
247 246
248 247 /*
249 248 * Allow multiple opens by tweaking the dev_t such that it looks like each
250 249 * open is getting a different minor device. Each minor gets a separate
251 250 * entry in the oprom_state[] table.
252 251 */
253 252 /*ARGSUSED*/
254 253 static int
255 254 opromopen(dev_t *devp, int flag, int otyp, cred_t *credp)
256 255 {
257 256 int m;
258 257 struct oprom_state *st = oprom_state;
259 258
260 259 if (getminor(*devp) != 0)
261 260 return (ENXIO);
262 261
263 262 mutex_enter(&oprom_lock);
264 263 for (m = 0; m < MAX_OPENS; m++)
265 264 if (st->already_open)
266 265 st++;
267 266 else {
268 267 st->already_open = 1;
269 268 /*
270 269 * It's ours.
271 270 */
272 271 st->current_id = (pnode_t)0;
273 272 ASSERT(st->snapshot == NULL && st->size == 0);
274 273 ASSERT(st->ioc_state == IOC_IDLE);
275 274 break;
276 275 }
277 276 mutex_exit(&oprom_lock);
278 277
279 278 if (m == MAX_OPENS) {
280 279 /*
281 280 * "Thank you for calling, but all our lines are
282 281 * busy at the moment.."
283 282 *
284 283 * We could get sophisticated here, and go into a
285 284 * sleep-retry loop .. but hey, I just can't see
286 285 * that many processes sitting in this driver.
287 286 *
288 287 * (And if it does become possible, then we should
289 288 * change the interface so that the 'state' is held
290 289 * external to the driver)
291 290 */
292 291 return (EAGAIN);
293 292 }
294 293
295 294 *devp = makedevice(getmajor(*devp), (minor_t)m);
296 295
297 296 return (0);
298 297 }
299 298
300 299 /*ARGSUSED*/
301 300 static int
302 301 opromclose(dev_t dev, int flag, int otype, cred_t *cred_p)
303 302 {
304 303 struct oprom_state *st;
305 304
306 305 st = &oprom_state[getminor(dev)];
307 306 ASSERT(getminor(dev) < MAX_OPENS && st->already_open != 0);
308 307 if (st->snapshot) {
309 308 kmem_free(st->snapshot, st->size);
310 309 st->snapshot = NULL;
311 310 st->size = 0;
312 311 st->ioc_state = IOC_IDLE;
313 312 }
314 313 mutex_enter(&oprom_lock);
315 314 st->already_open = 0;
316 315 mutex_exit(&oprom_lock);
317 316
318 317 return (0);
319 318 }
320 319
321 320 #ifdef __sparc
322 321 static int
323 322 get_bootpath_prop(char *bootpath)
324 323 {
325 324 if (root_is_ramdisk) {
326 325 if (BOP_GETPROP(bootops, "bootarchive", bootpath) == -1)
327 326 return (-1);
328 327 (void) strlcat(bootpath, ":a", BO_MAXOBJNAME);
329 328 } else {
330 329 if ((BOP_GETPROP(bootops, "bootpath", bootpath) == -1) ||
331 330 strlen(bootpath) == 0) {
332 331 if (BOP_GETPROP(bootops,
333 332 "boot-path", bootpath) == -1)
334 333 return (-1);
335 334 }
336 335 if (memcmp(bootpath, BP_ISCSI_DISK,
337 336 strlen(BP_ISCSI_DISK)) == 0) {
338 337 get_iscsi_bootpath_vhci(bootpath);
339 338 }
340 339 }
341 340 return (0);
342 341 }
343 342 #endif
344 343
345 344 struct opromioctl_args {
346 345 struct oprom_state *st;
347 346 int cmd;
348 347 intptr_t arg;
349 348 int mode;
350 349 };
351 350
352 351 /*ARGSUSED*/
353 352 static int
354 353 opromioctl_cb(void *avp, int has_changed)
355 354 {
356 355 struct opromioctl_args *argp = avp;
357 356 int cmd;
358 357 intptr_t arg;
359 358 int mode;
360 359 struct oprom_state *st;
361 360 struct openpromio *opp;
362 361 int valsize;
363 362 char *valbuf;
364 363 int error = 0;
365 364 uint_t userbufsize;
366 365 pnode_t node_id;
367 366 char propname[OBP_MAXPROPNAME];
368 367
369 368 st = argp->st;
370 369 cmd = argp->cmd;
371 370 arg = argp->arg;
372 371 mode = argp->mode;
373 372
374 373 if (has_changed) {
375 374 /*
376 375 * The prom tree has changed since we last used current_id,
377 376 * so we need to check it.
378 377 */
379 378 if ((st->current_id != OBP_NONODE) &&
380 379 (st->current_id != OBP_BADNODE)) {
381 380 if (oprom_checknodeid(st->current_id, OBP_NONODE) == 0)
382 381 st->current_id = OBP_BADNODE;
383 382 }
384 383 }
385 384
386 385 /*
387 386 * Check permissions
388 387 * and weed out unsupported commands on x86 platform
389 388 */
390 389 switch (cmd) {
391 390 #if !defined(__i386) && !defined(__amd64)
392 391 case OPROMLISTKEYSLEN:
393 392 valsize = prom_asr_list_keys_len();
394 393 opp = (struct openpromio *)kmem_zalloc(
395 394 sizeof (uint_t) + 1, KM_SLEEP);
396 395 opp->oprom_size = valsize;
397 396 if (copyout(opp, (void *)arg, (sizeof (uint_t))) != 0)
398 397 error = EFAULT;
399 398 kmem_free(opp, sizeof (uint_t) + 1);
400 399 break;
401 400 case OPROMLISTKEYS:
402 401 valsize = prom_asr_list_keys_len();
403 402 if (copyin((void *)arg, &userbufsize, sizeof (uint_t)) != 0)
404 403 return (EFAULT);
405 404 if (valsize > userbufsize)
406 405 return (EINVAL);
407 406 valbuf = (char *)kmem_zalloc(valsize + 1, KM_SLEEP);
408 407 if (prom_asr_list_keys((caddr_t)valbuf) == -1) {
409 408 kmem_free(valbuf, valsize + 1);
410 409 return (EFAULT);
411 410 }
412 411 opp = (struct openpromio *)kmem_zalloc(
413 412 valsize + sizeof (uint_t) + 1, KM_SLEEP);
414 413 opp->oprom_size = valsize;
415 414 bcopy(valbuf, opp->oprom_array, valsize);
416 415 if (copyout(opp, (void *)arg, (valsize + sizeof (uint_t))) != 0)
417 416 error = EFAULT;
418 417 kmem_free(valbuf, valsize + 1);
419 418 kmem_free(opp, valsize + sizeof (uint_t) + 1);
420 419 break;
421 420 case OPROMEXPORT:
422 421 valsize = prom_asr_export_len();
423 422 if (copyin((void *)arg, &userbufsize, sizeof (uint_t)) != 0)
424 423 return (EFAULT);
425 424 if (valsize > userbufsize)
426 425 return (EINVAL);
427 426 valbuf = (char *)kmem_zalloc(valsize + 1, KM_SLEEP);
428 427 if (prom_asr_export((caddr_t)valbuf) == -1) {
429 428 kmem_free(valbuf, valsize + 1);
430 429 return (EFAULT);
431 430 }
432 431 opp = (struct openpromio *)kmem_zalloc(
433 432 valsize + sizeof (uint_t) + 1, KM_SLEEP);
434 433 opp->oprom_size = valsize;
435 434 bcopy(valbuf, opp->oprom_array, valsize);
436 435 if (copyout(opp, (void *)arg, (valsize + sizeof (uint_t))) != 0)
437 436 error = EFAULT;
438 437 kmem_free(valbuf, valsize + 1);
439 438 kmem_free(opp, valsize + sizeof (uint_t) + 1);
440 439 break;
441 440 case OPROMEXPORTLEN:
442 441 valsize = prom_asr_export_len();
443 442 opp = (struct openpromio *)kmem_zalloc(
444 443 sizeof (uint_t) + 1, KM_SLEEP);
445 444 opp->oprom_size = valsize;
446 445 if (copyout(opp, (void *)arg, (sizeof (uint_t))) != 0)
447 446 error = EFAULT;
448 447 kmem_free(opp, sizeof (uint_t) + 1);
449 448 break;
450 449 #endif
451 450 case OPROMGETOPT:
452 451 case OPROMNXTOPT:
453 452 if ((mode & FREAD) == 0) {
454 453 return (EPERM);
455 454 }
456 455 node_id = options_nodeid;
457 456 break;
458 457
459 458 case OPROMSETOPT:
460 459 case OPROMSETOPT2:
461 460 #if !defined(__i386) && !defined(__amd64)
462 461 if (mode & FWRITE) {
463 462 node_id = options_nodeid;
464 463 break;
465 464 }
466 465 #endif /* !__i386 && !__amd64 */
467 466 return (EPERM);
468 467
469 468 case OPROMNEXT:
470 469 case OPROMCHILD:
471 470 case OPROMGETPROP:
472 471 case OPROMGETPROPLEN:
473 472 case OPROMNXTPROP:
474 473 case OPROMSETNODEID:
475 474 if ((mode & FREAD) == 0) {
476 475 return (EPERM);
477 476 }
478 477 node_id = st->current_id;
479 478 break;
480 479 case OPROMCOPYOUT:
481 480 if (st->snapshot == NULL)
482 481 return (EINVAL);
483 482 /*FALLTHROUGH*/
484 483 case OPROMSNAPSHOT:
485 484 case OPROMGETCONS:
486 485 case OPROMGETBOOTARGS:
487 486 case OPROMGETBOOTPATH:
488 487 case OPROMGETVERSION:
489 488 case OPROMPATH2DRV:
490 489 case OPROMPROM2DEVNAME:
491 490 #if !defined(__i386) && !defined(__amd64)
492 491 case OPROMGETFBNAME:
493 492 case OPROMDEV2PROMNAME:
494 493 case OPROMREADY64:
495 494 #endif /* !__i386 && !__amd64 */
496 495 if ((mode & FREAD) == 0) {
497 496 return (EPERM);
498 497 }
499 498 break;
500 499
501 500 #if !defined(__i386) && !defined(__amd64)
502 501 case WANBOOT_SETKEY:
503 502 if (!(mode & FWRITE))
504 503 return (EPERM);
505 504 break;
506 505 #endif /* !__i386 && !defined(__amd64) */
507 506
508 507 default:
509 508 return (EINVAL);
510 509 }
511 510
512 511 /*
513 512 * Deal with SNAPSHOT and COPYOUT ioctls first
514 513 */
515 514 switch (cmd) {
516 515 case OPROMCOPYOUT:
517 516 return (oprom_copyout(st, arg));
518 517
519 518 case OPROMSNAPSHOT:
520 519 return (oprom_snapshot(st, arg));
521 520 }
522 521
523 522 /*
524 523 * Copy in user argument length and allocation memory
525 524 *
526 525 * NB do not copyin the entire buffer we may not need
527 526 * to. userbufsize can be as big as 32 K.
528 527 */
529 528 if (copyin((void *)arg, &userbufsize, sizeof (uint_t)) != 0)
530 529 return (EFAULT);
531 530
532 531 if (userbufsize == 0 || userbufsize > OPROMMAXPARAM)
533 532 return (EINVAL);
534 533
535 534 opp = (struct openpromio *)kmem_zalloc(
536 535 userbufsize + sizeof (uint_t) + 1, KM_SLEEP);
537 536
538 537 /*
539 538 * Execute command
540 539 */
541 540 switch (cmd) {
542 541
543 542 case OPROMGETOPT:
544 543 case OPROMGETPROP:
545 544 case OPROMGETPROPLEN:
546 545
547 546 if ((prom_is_openprom() == 0) ||
548 547 (node_id == OBP_NONODE) || (node_id == OBP_BADNODE)) {
549 548 error = EINVAL;
550 549 break;
551 550 }
552 551
553 552 /*
554 553 * The argument, a NULL terminated string, is a prop name.
555 554 */
556 555 if ((error = oprom_copyinstr(arg, opp->oprom_array,
557 556 (size_t)userbufsize, OBP_MAXPROPNAME)) != 0) {
558 557 break;
559 558 }
560 559 (void) strcpy(propname, opp->oprom_array);
561 560 valsize = prom_getproplen(node_id, propname);
562 561
563 562 /*
564 563 * 4010173: 'name' is a property, but not an option.
565 564 */
566 565 if ((cmd == OPROMGETOPT) && (strcmp("name", propname) == 0))
567 566 valsize = -1;
568 567
569 568 if (cmd == OPROMGETPROPLEN) {
570 569 int proplen = valsize;
571 570
572 571 if (userbufsize < sizeof (int)) {
573 572 error = EINVAL;
574 573 break;
575 574 }
576 575 opp->oprom_size = valsize = sizeof (int);
577 576 bcopy(&proplen, opp->oprom_array, valsize);
578 577 } else if (valsize > 0 && valsize <= userbufsize) {
579 578 bzero(opp->oprom_array, valsize + 1);
580 579 (void) prom_getprop(node_id, propname,
581 580 opp->oprom_array);
582 581 opp->oprom_size = valsize;
583 582 if (valsize < userbufsize)
584 583 ++valsize; /* Forces NULL termination */
585 584 /* If space permits */
586 585 } else {
587 586 /*
588 587 * XXX: There is no error code if the buf is too small.
589 588 * which is consistent with the current behavior.
590 589 *
591 590 * NB: This clause also handles the non-error
592 591 * zero length (boolean) property value case.
593 592 */
594 593 opp->oprom_size = 0;
595 594 (void) strcpy(opp->oprom_array, "");
596 595 valsize = 1;
597 596 }
598 597 if (copyout(opp, (void *)arg, (valsize + sizeof (uint_t))) != 0)
599 598 error = EFAULT;
600 599 break;
601 600
602 601 case OPROMNXTOPT:
603 602 case OPROMNXTPROP:
604 603 if ((prom_is_openprom() == 0) ||
605 604 (node_id == OBP_NONODE) || (node_id == OBP_BADNODE)) {
606 605 error = EINVAL;
607 606 break;
608 607 }
609 608
610 609 /*
611 610 * The argument, a NULL terminated string, is a prop name.
612 611 */
613 612 if ((error = oprom_copyinstr(arg, opp->oprom_array,
614 613 (size_t)userbufsize, OBP_MAXPROPNAME)) != 0) {
615 614 break;
616 615 }
617 616 valbuf = (char *)prom_nextprop(node_id, opp->oprom_array,
618 617 propname);
619 618 valsize = strlen(valbuf);
620 619
621 620 /*
622 621 * 4010173: 'name' is a property, but it's not an option.
623 622 */
624 623 if ((cmd == OPROMNXTOPT) && valsize &&
625 624 (strcmp(valbuf, "name") == 0)) {
626 625 valbuf = (char *)prom_nextprop(node_id, "name",
627 626 propname);
628 627 valsize = strlen(valbuf);
629 628 }
630 629
631 630 if (valsize == 0) {
632 631 opp->oprom_size = 0;
633 632 } else if (++valsize <= userbufsize) {
634 633 opp->oprom_size = valsize;
635 634 bzero((caddr_t)opp->oprom_array, (size_t)valsize);
636 635 bcopy((caddr_t)valbuf, (caddr_t)opp->oprom_array,
637 636 (size_t)valsize);
638 637 }
639 638
640 639 if (copyout(opp, (void *)arg, valsize + sizeof (uint_t)) != 0)
641 640 error = EFAULT;
642 641 break;
643 642
644 643 case OPROMNEXT:
645 644 case OPROMCHILD:
646 645 case OPROMSETNODEID:
647 646
648 647 if (prom_is_openprom() == 0 ||
649 648 userbufsize < sizeof (pnode_t)) {
650 649 error = EINVAL;
651 650 break;
652 651 }
653 652
654 653 /*
655 654 * The argument is a phandle. (aka pnode_t)
656 655 */
657 656 if (copyin(((caddr_t)arg + sizeof (uint_t)),
658 657 opp->oprom_array, sizeof (pnode_t)) != 0) {
659 658 error = EFAULT;
660 659 break;
661 660 }
662 661
663 662 /*
664 663 * If pnode_t from userland is garbage, we
665 664 * could confuse the PROM.
666 665 */
667 666 node_id = *(pnode_t *)opp->oprom_array;
668 667 if (oprom_checknodeid(node_id, st->current_id) == 0) {
669 668 cmn_err(CE_NOTE, "!nodeid 0x%x not found",
670 669 (int)node_id);
671 670 error = EINVAL;
672 671 break;
673 672 }
674 673
675 674 if (cmd == OPROMNEXT)
676 675 st->current_id = prom_nextnode(node_id);
677 676 else if (cmd == OPROMCHILD)
678 677 st->current_id = prom_childnode(node_id);
679 678 else {
680 679 /* OPROMSETNODEID */
681 680 st->current_id = node_id;
682 681 break;
683 682 }
684 683
685 684 opp->oprom_size = sizeof (pnode_t);
686 685 *(pnode_t *)opp->oprom_array = st->current_id;
687 686
688 687 if (copyout(opp, (void *)arg,
689 688 sizeof (pnode_t) + sizeof (uint_t)) != 0)
690 689 error = EFAULT;
691 690 break;
692 691
693 692 case OPROMGETCONS:
694 693 /*
695 694 * Is openboot supported on this machine?
696 695 * This ioctl used to return the console device,
697 696 * information; this is now done via modctl()
698 697 * in libdevinfo.
699 698 */
700 699 opp->oprom_size = sizeof (char);
701 700
702 701 opp->oprom_array[0] |= prom_is_openprom() ?
703 702 OPROMCONS_OPENPROM : 0;
704 703
705 704 /*
706 705 * The rest of the info is needed by Install to
707 706 * decide if graphics should be started.
708 707 */
709 708 if ((getzoneid() == GLOBAL_ZONEID) &&
710 709 plat_stdin_is_keyboard()) {
711 710 opp->oprom_array[0] |= OPROMCONS_STDIN_IS_KBD;
712 711 }
713 712
714 713 if ((getzoneid() == GLOBAL_ZONEID) &&
715 714 plat_stdout_is_framebuffer()) {
716 715 opp->oprom_array[0] |= OPROMCONS_STDOUT_IS_FB;
717 716 }
718 717
719 718 if (copyout(opp, (void *)arg,
720 719 sizeof (char) + sizeof (uint_t)) != 0)
721 720 error = EFAULT;
722 721 break;
723 722
724 723 case OPROMGETBOOTARGS: {
725 724 extern char kern_bootargs[];
726 725
727 726 valsize = strlen(kern_bootargs) + 1;
728 727 if (valsize > userbufsize) {
729 728 error = EINVAL;
730 729 break;
731 730 }
732 731 (void) strcpy(opp->oprom_array, kern_bootargs);
733 732 opp->oprom_size = valsize - 1;
734 733
735 734 if (copyout(opp, (void *)arg, valsize + sizeof (uint_t)) != 0)
736 735 error = EFAULT;
737 736 break;
738 737 }
739 738
740 739 case OPROMGETBOOTPATH: {
741 740 #if defined(__sparc) && defined(_OBP)
742 741
743 742 char bpath[OBP_MAXPATHLEN];
744 743 if (get_bootpath_prop(bpath) != 0) {
745 744 error = EINVAL;
746 745 break;
747 746 }
748 747 valsize = strlen(bpath) + 1;
749 748 if (valsize > userbufsize) {
750 749 error = EINVAL;
751 750 break;
752 751 }
753 752 (void) strcpy(opp->oprom_array, bpath);
754 753
755 754 #elif defined(__i386) || defined(__amd64)
756 755
757 756 extern char saved_cmdline[];
758 757 valsize = strlen(saved_cmdline) + 1;
759 758 if (valsize > userbufsize) {
760 759 error = EINVAL;
761 760 break;
762 761 }
763 762 (void) strcpy(opp->oprom_array, saved_cmdline);
764 763 #endif
765 764 opp->oprom_size = valsize - 1;
766 765 if (copyout(opp, (void *)arg, valsize + sizeof (uint_t)) != 0)
767 766 error = EFAULT;
768 767 break;
769 768 }
770 769
771 770 /*
772 771 * convert a prom device path to an equivalent devfs path
773 772 */
774 773 case OPROMPROM2DEVNAME: {
775 774 char *dev_name;
776 775
777 776 /*
778 777 * The input argument, a pathname, is a NULL terminated string.
779 778 */
780 779 if ((error = oprom_copyinstr(arg, opp->oprom_array,
781 780 (size_t)userbufsize, MAXPATHLEN)) != 0) {
782 781 break;
783 782 }
784 783
785 784 dev_name = kmem_alloc(MAXPATHLEN, KM_SLEEP);
786 785
787 786 error = i_promname_to_devname(opp->oprom_array, dev_name);
788 787 if (error != 0) {
789 788 kmem_free(dev_name, MAXPATHLEN);
790 789 break;
791 790 }
792 791 valsize = opp->oprom_size = strlen(dev_name);
793 792 if (++valsize > userbufsize) {
794 793 kmem_free(dev_name, MAXPATHLEN);
795 794 error = EINVAL;
796 795 break;
797 796 }
798 797 (void) strcpy(opp->oprom_array, dev_name);
799 798 if (copyout(opp, (void *)arg, sizeof (uint_t) + valsize) != 0)
800 799 error = EFAULT;
801 800
802 801 kmem_free(dev_name, MAXPATHLEN);
803 802 break;
804 803 }
805 804
806 805 /*
807 806 * Convert a prom device path name to a driver name
808 807 */
809 808 case OPROMPATH2DRV: {
810 809 char *drv_name;
811 810 major_t maj;
812 811
813 812 /*
814 813 * The input argument, a pathname, is a NULL terminated string.
815 814 */
816 815 if ((error = oprom_copyinstr(arg, opp->oprom_array,
817 816 (size_t)userbufsize, MAXPATHLEN)) != 0) {
818 817 break;
819 818 }
820 819
821 820 /*
822 821 * convert path to a driver binding name
823 822 */
824 823 maj = path_to_major((char *)opp->oprom_array);
825 824 if (maj == DDI_MAJOR_T_NONE) {
826 825 error = EINVAL;
827 826 break;
828 827 }
829 828
830 829 /*
831 830 * resolve any aliases
832 831 */
833 832 if ((drv_name = ddi_major_to_name(maj)) == NULL) {
834 833 error = EINVAL;
835 834 break;
836 835 }
837 836
838 837 (void) strcpy(opp->oprom_array, drv_name);
839 838 opp->oprom_size = strlen(drv_name);
840 839 if (copyout(opp, (void *)arg,
841 840 sizeof (uint_t) + opp->oprom_size + 1) != 0)
842 841 error = EFAULT;
843 842 break;
844 843 }
845 844
846 845 case OPROMGETVERSION:
847 846 /*
848 847 * Get a string representing the running version of the
849 848 * prom. How to create such a string is platform dependent,
850 849 * so we just defer to a promif function. If no such
851 850 * association exists, the promif implementation
852 851 * may copy the string "unknown" into the given buffer,
853 852 * and return its length (incl. NULL terminator).
854 853 *
855 854 * We expect prom_version_name to return the actual
856 855 * length of the string, but copy at most userbufsize
857 856 * bytes into the given buffer, including NULL termination.
858 857 */
859 858
860 859 valsize = prom_version_name(opp->oprom_array, userbufsize);
861 860 if (valsize < 0) {
862 861 error = EINVAL;
863 862 break;
864 863 }
865 864
866 865 /*
867 866 * copyout only the part of the user buffer we need to.
868 867 */
869 868 if (copyout(opp, (void *)arg,
870 869 (size_t)(min((uint_t)valsize, userbufsize) +
871 870 sizeof (uint_t))) != 0)
872 871 error = EFAULT;
873 872 break;
874 873
875 874 #if !defined(__i386) && !defined(__amd64)
876 875 case OPROMGETFBNAME:
877 876 /*
878 877 * Return stdoutpath, if it's a frame buffer.
879 878 * Yes, we are comparing a possibly longer string against
880 879 * the size we're really going to copy, but so what?
881 880 */
882 881 if ((getzoneid() == GLOBAL_ZONEID) &&
883 882 (prom_stdout_is_framebuffer() != 0) &&
884 883 (userbufsize > strlen(prom_stdoutpath()))) {
885 884 prom_strip_options(prom_stdoutpath(),
886 885 opp->oprom_array); /* strip options and copy */
887 886 valsize = opp->oprom_size = strlen(opp->oprom_array);
888 887 if (copyout(opp, (void *)arg,
889 888 valsize + 1 + sizeof (uint_t)) != 0)
890 889 error = EFAULT;
891 890 } else
892 891 error = EINVAL;
893 892 break;
894 893
895 894 /*
896 895 * Convert a logical or physical device path to prom device path
897 896 */
898 897 case OPROMDEV2PROMNAME: {
899 898 char *prom_name;
900 899
901 900 /*
902 901 * The input argument, a pathname, is a NULL terminated string.
903 902 */
904 903 if ((error = oprom_copyinstr(arg, opp->oprom_array,
905 904 (size_t)userbufsize, MAXPATHLEN)) != 0) {
906 905 break;
907 906 }
908 907
909 908 prom_name = kmem_alloc(userbufsize, KM_SLEEP);
910 909
911 910 /*
912 911 * convert the devfs path to an equivalent prom path
913 912 */
914 913 error = i_devname_to_promname(opp->oprom_array, prom_name,
915 914 userbufsize);
916 915
917 916 if (error != 0) {
918 917 kmem_free(prom_name, userbufsize);
919 918 break;
920 919 }
921 920
922 921 for (valsize = 0; valsize < userbufsize; valsize++) {
923 922 opp->oprom_array[valsize] = prom_name[valsize];
924 923
925 924 if ((valsize > 0) && (prom_name[valsize] == '\0') &&
926 925 (prom_name[valsize-1] == '\0')) {
927 926 break;
928 927 }
929 928 }
930 929 opp->oprom_size = valsize;
931 930
932 931 kmem_free(prom_name, userbufsize);
933 932 if (copyout(opp, (void *)arg, sizeof (uint_t) + valsize) != 0)
934 933 error = EFAULT;
935 934
936 935 break;
937 936 }
938 937
939 938 case OPROMSETOPT:
940 939 case OPROMSETOPT2: {
941 940 int namebuflen;
942 941 int valbuflen;
943 942
944 943 if ((prom_is_openprom() == 0) ||
945 944 (node_id == OBP_NONODE) || (node_id == OBP_BADNODE)) {
946 945 error = EINVAL;
947 946 break;
948 947 }
949 948
950 949 /*
951 950 * The arguments are a property name and a value.
952 951 * Copy in the entire user buffer.
953 952 */
954 953 if (copyin(((caddr_t)arg + sizeof (uint_t)),
955 954 opp->oprom_array, userbufsize) != 0) {
956 955 error = EFAULT;
957 956 break;
958 957 }
959 958
960 959 /*
961 960 * The property name is the first string, value second
962 961 */
963 962 namebuflen = strlen(opp->oprom_array);
964 963 valbuf = opp->oprom_array + namebuflen + 1;
965 964 valbuflen = strlen(valbuf);
966 965
967 966 if (cmd == OPROMSETOPT) {
968 967 valsize = valbuflen + 1; /* +1 for the '\0' */
969 968 } else {
970 969 if ((namebuflen + 1 + valbuflen + 1) > userbufsize) {
971 970 error = EINVAL;
972 971 break;
973 972 }
974 973 valsize = (opp->oprom_array + userbufsize) - valbuf;
975 974 }
976 975
977 976 /*
978 977 * 4010173: 'name' is not an option, but it is a property.
979 978 */
980 979 if (strcmp(opp->oprom_array, "name") == 0)
981 980 error = EINVAL;
982 981 else if (prom_setprop(node_id, opp->oprom_array,
983 982 valbuf, valsize) < 0)
984 983 error = EINVAL;
985 984
986 985 break;
987 986 }
988 987
989 988 case OPROMREADY64: {
990 989 struct openprom_opr64 *opr =
991 990 (struct openprom_opr64 *)opp->oprom_array;
992 991 int i;
993 992 pnode_t id;
994 993
995 994 if (userbufsize < sizeof (*opr)) {
996 995 error = EINVAL;
997 996 break;
998 997 }
999 998
1000 999 valsize = userbufsize -
1001 1000 offsetof(struct openprom_opr64, message);
1002 1001
1003 1002 i = prom_version_check(opr->message, valsize, &id);
1004 1003 opr->return_code = i;
1005 1004 opr->nodeid = (int)id;
1006 1005
1007 1006 valsize = offsetof(struct openprom_opr64, message);
1008 1007 valsize += strlen(opr->message) + 1;
1009 1008
1010 1009 /*
1011 1010 * copyout only the part of the user buffer we need to.
1012 1011 */
1013 1012 if (copyout(opp, (void *)arg,
1014 1013 (size_t)(min((uint_t)valsize, userbufsize) +
1015 1014 sizeof (uint_t))) != 0)
1016 1015 error = EFAULT;
1017 1016 break;
1018 1017
1019 1018 } /* case OPROMREADY64 */
1020 1019
1021 1020 case WANBOOT_SETKEY: {
1022 1021 struct wankeyio *wp;
1023 1022 int reslen;
1024 1023 int status;
1025 1024 int rv;
1026 1025 int i;
1027 1026
1028 1027 /*
1029 1028 * The argument is a struct wankeyio. Validate it as best
1030 1029 * we can.
1031 1030 */
1032 1031 if (userbufsize != (sizeof (struct wankeyio))) {
1033 1032 error = EINVAL;
1034 1033 break;
1035 1034 }
1036 1035 if (copyin(((caddr_t)arg + sizeof (uint_t)),
1037 1036 opp->oprom_array, sizeof (struct wankeyio)) != 0) {
1038 1037 error = EFAULT;
1039 1038 break;
1040 1039 }
1041 1040 wp = (struct wankeyio *)opp->oprom_array;
1042 1041
1043 1042 /* check for key name and key size overflow */
1044 1043 for (i = 0; i < WANBOOT_MAXKEYNAMELEN; i++)
1045 1044 if (wp->wk_keyname[i] == '\0')
1046 1045 break;
1047 1046 if ((i == WANBOOT_MAXKEYNAMELEN) ||
1048 1047 (wp->wk_keysize > WANBOOT_MAXKEYLEN)) {
1049 1048 error = EINVAL;
1050 1049 break;
1051 1050 }
1052 1051
1053 1052 rv = prom_set_security_key(wp->wk_keyname, wp->wk_u.key,
1054 1053 wp->wk_keysize, &reslen, &status);
1055 1054 if (rv)
1056 1055 error = EIO;
1057 1056 else
1058 1057 switch (status) {
1059 1058 case 0:
1060 1059 error = 0;
1061 1060 break;
1062 1061
1063 1062 case -2: /* out of key storage space */
1064 1063 error = ENOSPC;
1065 1064 break;
1066 1065
1067 1066 case -3: /* key name or value too long */
1068 1067 error = EINVAL;
1069 1068 break;
1070 1069
1071 1070 case -4: /* can't delete: no such key */
1072 1071 error = ENOENT;
1073 1072 break;
1074 1073
1075 1074 case -1: /* unspecified error */
1076 1075 default: /* this should not happen */
1077 1076 error = EIO;
1078 1077 break;
1079 1078 }
1080 1079 break;
1081 1080 } /* case WANBOOT_SETKEY */
1082 1081 #endif /* !__i386 && !__amd64 */
1083 1082 } /* switch (cmd) */
1084 1083
1085 1084 kmem_free(opp, userbufsize + sizeof (uint_t) + 1);
1086 1085 return (error);
1087 1086 }
1088 1087
1089 1088 /*ARGSUSED*/
1090 1089 static int
1091 1090 opromioctl(dev_t dev, int cmd, intptr_t arg, int mode,
1092 1091 cred_t *credp, int *rvalp)
1093 1092 {
1094 1093 struct oprom_state *st;
1095 1094 struct opromioctl_args arg_block;
1096 1095
1097 1096 if (getminor(dev) >= MAX_OPENS)
1098 1097 return (ENXIO);
1099 1098
1100 1099 st = &oprom_state[getminor(dev)];
1101 1100 ASSERT(st->already_open);
1102 1101 arg_block.st = st;
1103 1102 arg_block.cmd = cmd;
1104 1103 arg_block.arg = arg;
1105 1104 arg_block.mode = mode;
1106 1105 return (prom_tree_access(opromioctl_cb, &arg_block, &st->tree_gen));
1107 1106 }
1108 1107
1109 1108 /*
1110 1109 * Copyin string and verify the actual string length is less than maxsize
1111 1110 * specified by the caller.
1112 1111 *
1113 1112 * Currently, maxsize is either OBP_MAXPROPNAME for property names
1114 1113 * or MAXPATHLEN for device path names. userbufsize is specified
1115 1114 * by the userland caller.
1116 1115 */
1117 1116 static int
1118 1117 oprom_copyinstr(intptr_t arg, char *buf, size_t bufsize, size_t maxsize)
1119 1118 {
1120 1119 int error;
1121 1120 size_t actual_len;
1122 1121
1123 1122 if ((error = copyinstr(((caddr_t)arg + sizeof (uint_t)),
1124 1123 buf, bufsize, &actual_len)) != 0) {
1125 1124 return (error);
1126 1125 }
1127 1126 if ((actual_len == 0) || (actual_len > maxsize)) {
1128 1127 return (EINVAL);
1129 1128 }
1130 1129
1131 1130 return (0);
1132 1131 }
1133 1132
1134 1133 /*
1135 1134 * Check pnode_t passed in from userland
1136 1135 */
1137 1136 static int
1138 1137 oprom_checknodeid(pnode_t node_id, pnode_t current_id)
1139 1138 {
1140 1139 int depth;
1141 1140 pnode_t id[OBP_STACKDEPTH];
1142 1141
1143 1142 /*
1144 1143 * optimized path
1145 1144 */
1146 1145 if (node_id == 0) {
1147 1146 return (1);
1148 1147 }
1149 1148 if (node_id == OBP_BADNODE) {
1150 1149 return (0);
1151 1150 }
1152 1151 if ((current_id != OBP_BADNODE) && ((node_id == current_id) ||
1153 1152 (node_id == prom_nextnode(current_id)) ||
1154 1153 (node_id == prom_childnode(current_id)))) {
1155 1154 return (1);
1156 1155 }
1157 1156
1158 1157 /*
1159 1158 * long path: walk from root till we find node_id
1160 1159 */
1161 1160 depth = 1;
1162 1161 id[0] = prom_nextnode((pnode_t)0);
1163 1162
1164 1163 while (depth) {
1165 1164 if (id[depth - 1] == node_id)
1166 1165 return (1); /* node_id found */
1167 1166
1168 1167 if (id[depth] = prom_childnode(id[depth - 1])) {
1169 1168 depth++;
1170 1169 continue;
1171 1170 }
1172 1171
1173 1172 while (depth &&
1174 1173 ((id[depth - 1] = prom_nextnode(id[depth - 1])) == 0))
1175 1174 depth--;
1176 1175 }
1177 1176 return (0); /* node_id not found */
1178 1177 }
1179 1178
1180 1179 static int
1181 1180 oprom_copytree(struct oprom_state *st, uint_t flag)
1182 1181 {
1183 1182 ASSERT(st->snapshot == NULL && st->size == 0);
1184 1183 return (oprom_copynode(
1185 1184 prom_nextnode(0), flag, &st->snapshot, &st->size));
1186 1185 }
1187 1186
1188 1187 static int
1189 1188 oprom_snapshot(struct oprom_state *st, intptr_t arg)
1190 1189 {
1191 1190 uint_t flag;
1192 1191
1193 1192 if (oprom_setstate(st, IOC_SNAP) == -1)
1194 1193 return (EBUSY);
1195 1194
1196 1195 /* copyin flag and create snapshot */
1197 1196 if ((copyin((void *)arg, &flag, sizeof (uint_t)) != 0) ||
1198 1197 (oprom_copytree(st, flag) != 0)) {
1199 1198 (void) oprom_setstate(st, IOC_IDLE);
1200 1199 return (EFAULT);
1201 1200 }
1202 1201
1203 1202
1204 1203 /* copyout the size of the snapshot */
1205 1204 flag = (uint_t)st->size;
1206 1205 if (copyout(&flag, (void *)arg, sizeof (uint_t)) != 0) {
1207 1206 kmem_free(st->snapshot, st->size);
1208 1207 st->snapshot = NULL;
1209 1208 st->size = 0;
1210 1209 (void) oprom_setstate(st, IOC_IDLE);
1211 1210 return (EFAULT);
1212 1211 }
1213 1212
1214 1213 (void) oprom_setstate(st, IOC_DONE);
1215 1214 return (0);
1216 1215 }
1217 1216
1218 1217 static int
1219 1218 oprom_copyout(struct oprom_state *st, intptr_t arg)
1220 1219 {
1221 1220 int error = 0;
1222 1221 uint_t size;
1223 1222
1224 1223 if (oprom_setstate(st, IOC_COPY) == -1)
1225 1224 return (EBUSY);
1226 1225
1227 1226 /* copyin size and copyout snapshot */
1228 1227 if (copyin((void *)arg, &size, sizeof (uint_t)) != 0)
1229 1228 error = EFAULT;
1230 1229 else if (size < st->size)
1231 1230 error = EINVAL;
1232 1231 else if (copyout(st->snapshot, (void *)arg, st->size) != 0)
1233 1232 error = EFAULT;
1234 1233
1235 1234 if (error) {
1236 1235 /*
1237 1236 * on error keep the snapshot until a successful
1238 1237 * copyout or when the driver is closed.
1239 1238 */
1240 1239 (void) oprom_setstate(st, IOC_DONE);
1241 1240 return (error);
1242 1241 }
1243 1242
1244 1243 kmem_free(st->snapshot, st->size);
1245 1244 st->snapshot = NULL;
1246 1245 st->size = 0;
1247 1246 (void) oprom_setstate(st, IOC_IDLE);
1248 1247 return (0);
1249 1248 }
1250 1249
1251 1250 /*
1252 1251 * Copy all properties of nodeid into a single packed nvlist
1253 1252 */
1254 1253 static int
1255 1254 oprom_copyprop(pnode_t nodeid, uint_t flag, nvlist_t *nvl)
1256 1255 {
1257 1256 int proplen;
1258 1257 char *propname, *propval, *buf1, *buf2;
1259 1258
1260 1259 ASSERT(nvl != NULL);
1261 1260
1262 1261 /*
1263 1262 * non verbose mode, get the "name" property only
1264 1263 */
1265 1264 if (flag == 0) {
1266 1265 proplen = prom_getproplen(nodeid, "name");
1267 1266 if (proplen <= 0) {
1268 1267 cmn_err(CE_WARN,
1269 1268 "failed to get the name of openprom node 0x%x",
1270 1269 nodeid);
1271 1270 (void) nvlist_add_string(nvl, "name", "");
1272 1271 return (0);
1273 1272 }
1274 1273 propval = kmem_zalloc(proplen + 1, KM_SLEEP);
1275 1274 (void) prom_getprop(nodeid, "name", propval);
1276 1275 (void) nvlist_add_string(nvl, "name", propval);
1277 1276 kmem_free(propval, proplen + 1);
1278 1277 return (0);
1279 1278 }
1280 1279
1281 1280 /*
1282 1281 * Ask for first property by passing a NULL string
1283 1282 */
1284 1283 buf1 = kmem_alloc(OBP_MAXPROPNAME, KM_SLEEP);
1285 1284 buf2 = kmem_zalloc(OBP_MAXPROPNAME, KM_SLEEP);
1286 1285 buf1[0] = '\0';
1287 1286 while (propname = (char *)prom_nextprop(nodeid, buf1, buf2)) {
1288 1287 if (strlen(propname) == 0)
1289 1288 break; /* end of prop list */
1290 1289 (void) strcpy(buf1, propname);
1291 1290
1292 1291 proplen = prom_getproplen(nodeid, propname);
1293 1292 if (proplen == 0) {
1294 1293 /* boolean property */
1295 1294 (void) nvlist_add_boolean(nvl, propname);
1296 1295 continue;
1297 1296 }
1298 1297 /* add 1 for null termination in case of a string */
1299 1298 propval = kmem_zalloc(proplen + 1, KM_SLEEP);
1300 1299 (void) prom_getprop(nodeid, propname, propval);
1301 1300 (void) nvlist_add_byte_array(nvl, propname,
1302 1301 (uchar_t *)propval, proplen + 1);
1303 1302 kmem_free(propval, proplen + 1);
1304 1303 bzero(buf2, OBP_MAXPROPNAME);
1305 1304 }
1306 1305
1307 1306 kmem_free(buf1, OBP_MAXPROPNAME);
1308 1307 kmem_free(buf2, OBP_MAXPROPNAME);
1309 1308
1310 1309 return (0);
1311 1310 }
1312 1311
1313 1312 /*
1314 1313 * Copy all children and descendents into a a packed nvlist
1315 1314 */
1316 1315 static int
1317 1316 oprom_copychild(pnode_t nodeid, uint_t flag, char **buf, size_t *size)
1318 1317 {
1319 1318 nvlist_t *nvl;
1320 1319 pnode_t child = prom_childnode(nodeid);
1321 1320
1322 1321 if (child == 0)
1323 1322 return (0);
1324 1323
1325 1324 (void) nvlist_alloc(&nvl, 0, KM_SLEEP);
1326 1325 while (child != 0) {
1327 1326 char *nodebuf = NULL;
1328 1327 size_t nodesize = 0;
1329 1328 if (oprom_copynode(child, flag, &nodebuf, &nodesize)) {
1330 1329 nvlist_free(nvl);
1331 1330 cmn_err(CE_WARN, "failed to copy nodeid 0x%x", child);
1332 1331 return (-1);
1333 1332 }
1334 1333 (void) nvlist_add_byte_array(nvl, "node",
1335 1334 (uchar_t *)nodebuf, nodesize);
1336 1335 kmem_free(nodebuf, nodesize);
1337 1336 child = prom_nextnode(child);
1338 1337 }
1339 1338
1340 1339 (void) nvlist_pack(nvl, buf, size, NV_ENCODE_NATIVE, KM_SLEEP);
1341 1340 nvlist_free(nvl);
1342 1341 return (0);
1343 1342 }
1344 1343
1345 1344 /*
1346 1345 * Copy a node into a packed nvlist
1347 1346 */
1348 1347 static int
1349 1348 oprom_copynode(pnode_t nodeid, uint_t flag, char **buf, size_t *size)
1350 1349 {
1351 1350 int error = 0;
1352 1351 nvlist_t *nvl;
1353 1352 char *childlist = NULL;
1354 1353 size_t childsize = 0;
1355 1354
1356 1355 (void) nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP);
1357 1356 ASSERT(nvl != NULL);
1358 1357
1359 1358 /* @nodeid -- @ is not a legal char in a 1275 property name */
1360 1359 (void) nvlist_add_int32(nvl, "@nodeid", (int32_t)nodeid);
1361 1360
1362 1361 /* properties */
1363 1362 if (error = oprom_copyprop(nodeid, flag, nvl))
1364 1363 goto fail;
1365 1364
1366 1365 /* children */
1367 1366 error = oprom_copychild(nodeid, flag, &childlist, &childsize);
1368 1367 if (error != 0)
1369 1368 goto fail;
1370 1369 if (childlist != NULL) {
1371 1370 (void) nvlist_add_byte_array(nvl, "@child",
1372 1371 (uchar_t *)childlist, (uint_t)childsize);
1373 1372 kmem_free(childlist, childsize);
1374 1373 }
1375 1374
1376 1375 /* pack into contiguous buffer */
1377 1376 error = nvlist_pack(nvl, buf, size, NV_ENCODE_NATIVE, KM_SLEEP);
1378 1377
1379 1378 fail:
1380 1379 nvlist_free(nvl);
1381 1380 return (error);
1382 1381 }
1383 1382
1384 1383 /*
1385 1384 * The driver is stateful across OPROMSNAPSHOT and OPROMCOPYOUT.
1386 1385 * This function encapsulates the state machine:
1387 1386 *
1388 1387 * -> IOC_IDLE -> IOC_SNAP -> IOC_DONE -> IOC_COPY ->
1389 1388 * | SNAPSHOT COPYOUT |
1390 1389 * --------------------------------------------------
1391 1390 *
1392 1391 * Returns 0 on success and -1 on failure
1393 1392 */
1394 1393 static int
1395 1394 oprom_setstate(struct oprom_state *st, int16_t new_state)
1396 1395 {
1397 1396 int ret = 0;
1398 1397
1399 1398 mutex_enter(&oprom_lock);
1400 1399 switch (new_state) {
1401 1400 case IOC_IDLE:
1402 1401 case IOC_DONE:
1403 1402 break;
1404 1403 case IOC_SNAP:
1405 1404 if (st->ioc_state != IOC_IDLE)
1406 1405 ret = -1;
1407 1406 break;
1408 1407 case IOC_COPY:
1409 1408 if (st->ioc_state != IOC_DONE)
1410 1409 ret = -1;
1411 1410 break;
1412 1411 default:
1413 1412 ret = -1;
1414 1413 }
1415 1414
1416 1415 if (ret == 0)
1417 1416 st->ioc_state = new_state;
1418 1417 else
1419 1418 cmn_err(CE_NOTE, "incorrect state transition from %d to %d",
1420 1419 st->ioc_state, new_state);
1421 1420 mutex_exit(&oprom_lock);
1422 1421 return (ret);
1423 1422 }
↓ open down ↓ |
1267 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX