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