4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2000, 2002 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright (c) 2016 by Delphix. All rights reserved.
28 #pragma ident "%Z%%M% %I% %E% SMI"
31 * fc_ops.c: Framework generic fcode ops
33 #include <sys/types.h>
35 #include <sys/systm.h>
37 #include <sys/sunddi.h>
38 #include <sys/sunndi.h>
39 #include <sys/modctl.h>
40 #include <sys/fcode.h>
41 #include <sys/ddi_implfuncs.h>
42 #include <sys/ndi_impldefs.h>
43 #include <sys/ethernet.h>
45 static int fco_new_device(dev_info_t
*, fco_handle_t
, fc_ci_t
*);
46 static int fco_finish_device(dev_info_t
*, fco_handle_t
, fc_ci_t
*);
47 static int fco_create_property(dev_info_t
*, fco_handle_t
, fc_ci_t
*);
49 static int fco_validate(dev_info_t
*, fco_handle_t
, fc_ci_t
*);
50 static int fco_invalidate(dev_info_t
*, fco_handle_t
, fc_ci_t
*);
51 static int fco_exit(dev_info_t
*, fco_handle_t
, fc_ci_t
*);
53 static int fco_getproplen(dev_info_t
*, fco_handle_t
, fc_ci_t
*);
54 static int fco_getprop(dev_info_t
*, fco_handle_t
, fc_ci_t
*);
56 static int fco_ap_phandle(dev_info_t
*, fco_handle_t
, fc_ci_t
*);
57 static int fco_child(dev_info_t
*, fco_handle_t
, fc_ci_t
*);
58 static int fco_peer(dev_info_t
*, fco_handle_t
, fc_ci_t
*);
59 static int fco_parent(dev_info_t
*, fco_handle_t
, fc_ci_t
*);
60 static int fco_alloc_phandle(dev_info_t
*, fco_handle_t
, fc_ci_t
*);
62 static int fco_local_ether_addr(dev_info_t
*, fco_handle_t
, fc_ci_t
*);
69 static struct fc_ops_v fov
[] = {
70 { "open", fc_fail_op
},
71 { "close", fc_fail_op
},
72 { "$find", fc_fail_op
},
73 { "encode-unit", fc_fail_op
},
74 { "decode-unit", fc_fail_op
},
75 { FC_GET_MY_PROPLEN
, fco_getproplen
},
76 { FC_GET_MY_PROP
, fco_getprop
},
77 { FC_GET_PKG_PROPLEN
, fco_getproplen
},
78 { FC_GET_PKG_PROP
, fco_getprop
},
79 { FC_GET_IN_PROPLEN
, fco_getproplen
},
80 { FC_GET_IN_PROP
, fco_getprop
},
81 { FC_NEW_DEVICE
, fco_new_device
},
82 { FC_FINISH_DEVICE
, fco_finish_device
},
83 { FC_CREATE_PROPERTY
, fco_create_property
},
84 { FC_AP_PHANDLE
, fco_ap_phandle
},
85 { "child", fco_child
},
87 { FC_PARENT
, fco_parent
},
88 { FC_ALLOC_PHANDLE
, fco_alloc_phandle
},
89 { FC_SVC_VALIDATE
, fco_validate
},
90 { FC_SVC_INVALIDATE
, fco_invalidate
},
91 { FC_SVC_EXIT
, fco_exit
},
92 { "local-ether-addr", fco_local_ether_addr
},
97 * Allocate a handle for the ops function .. our handle is a resource list
98 * Return the handle to our caller, so it can call us with it when we need it.
102 fc_ops_alloc_handle(dev_info_t
*ap
, dev_info_t
*child
,
103 void *fcode
, size_t fcode_size
, char *unit_address
, void *bus_args
)
108 rp
= kmem_zalloc(sizeof (struct fc_resource_list
), KM_SLEEP
);
109 rp
->next_handle
= NULL
; /* nobody is downstream */
113 rp
->fcode_size
= fcode_size
;
115 up
= kmem_zalloc(strlen(unit_address
) + 1, KM_SLEEP
);
116 (void) strcpy(up
, unit_address
);
117 rp
->unit_address
= up
;
119 rp
->bus_args
= NULL
; /* generic module has no bus args */
120 fc_phandle_table_alloc(fc_handle_to_phandle_head(rp
));
122 (void) fc_dip_to_phandle(fc_handle_to_phandle_head(rp
), ap
);
125 * Create our copy of the device tree.
127 fc_create_device_tree(ap
, &rp
->dtree
);
132 * Free any resources associated with this handle.
135 fc_ops_free_handle(fco_handle_t rp
)
137 struct fc_resource
*ip
, *np
;
139 if (rp
->unit_address
)
140 kmem_free(rp
->unit_address
, strlen(rp
->unit_address
) + 1);
143 fc_remove_device_tree(&rp
->dtree
);
145 fc_phandle_table_free(fc_handle_to_phandle_head(rp
));
147 for (ip
= rp
->head
; ip
!= NULL
; ip
= np
) {
151 impl_ddi_free_nodeid(ip
->fc_nodeid_r
);
154 cmn_err(CE_CONT
, "pci_fc_ops_free: "
155 "unknown resource type %d\n", ip
->type
);
158 fc_rem_resource(rp
, ip
);
159 kmem_free(ip
, sizeof (struct fc_resource
));
161 kmem_free(rp
, sizeof (struct fc_resource_list
));
165 fc_ops(dev_info_t
*ap
, fco_handle_t handle
, fc_ci_t
*cp
)
168 char *name
= fc_cell2ptr(cp
->svc_name
);
170 for (pv
= fov
; pv
->svc_name
!= NULL
; ++pv
)
171 if (strcmp(pv
->svc_name
, name
) == 0)
172 return (pv
->f(ap
, handle
, cp
));
178 * The interpreter can't do get-inherited-property directly,
179 * because we don't want to return a kernel address, so it
180 * has to break up the request into a get-proplen and get-prop
181 * call so it can allocate memory for the property and pass that
182 * buffer in to get-prop. The buffer should be 'suitably aligned'.
184 * XXX: We don't know the property type, so we can't return
185 * prop-encoded arrays, which fortunately, isn't a problem
186 * on big-endian machines.
188 * get-proplen has one result: proplen
189 * proplen is returned as -1 if the propname doesn't exist and
190 * as zero if the property is a boolean property.
192 * get-prop has one result: proplen, returned as -1 if propname doesn't exist.
196 * fco_getproplen ( propname phandle -- proplen )
201 fco_getproplen(dev_info_t
*ap
, fco_handle_t rp
, fc_ci_t
*cp
)
208 char propname
[OBP_MAXPROPNAME
];
210 if (strstr(fc_cell2ptr(cp
->svc_name
), "inherited") == NULL
)
211 flags
|= DDI_PROP_DONTPASS
;
213 if (fc_cell2int(cp
->nargs
) != 2)
214 return (fc_syntax_error(cp
, "nargs must be 2"));
216 if (fc_cell2int(cp
->nresults
) < 1)
217 return (fc_syntax_error(cp
, "nresults must be > 0"));
220 * Make sure this is a handle we gave out ...
222 h
= fc_cell2phandle(fc_arg(cp
, 0));
223 if ((dip
= fc_phandle_to_dip(fc_handle_to_phandle_head(rp
), h
)) == NULL
)
224 return (fc_priv_error(cp
, "unknown handle"));
227 * XXX: We should care if the string is longer than OBP_MAXPROPNAME
229 pnp
= fc_cell2ptr(fc_arg(cp
, 1));
230 bzero(propname
, OBP_MAXPROPNAME
);
231 if (copyinstr(pnp
, propname
, OBP_MAXPROPNAME
- 1, NULL
))
232 return (fc_priv_error(cp
, "EFAULT copying in propname"));
234 if (ddi_getproplen(DDI_DEV_T_ANY
, dip
, flags
, propname
, &proplen
))
237 fc_result(cp
, 0) = fc_int2cell(proplen
);
238 cp
->nresults
= fc_int2cell(1);
239 return (fc_success_op(ap
, rp
, cp
));
243 * fco_getprop ( propname buffer phandle -- proplen )
248 fco_getprop(dev_info_t
*ap
, fco_handle_t rp
, fc_ci_t
*cp
)
251 int flags
= DDI_PROP_CANSLEEP
;
255 char propname
[OBP_MAXPROPNAME
];
257 if (strstr(fc_cell2ptr(cp
->svc_name
), "inherited") == NULL
)
258 flags
|= DDI_PROP_DONTPASS
;
260 if (fc_cell2int(cp
->nargs
) != 3)
261 return (fc_syntax_error(cp
, "nargs must be 3"));
263 if (fc_cell2int(cp
->nresults
) < 1)
264 return (fc_syntax_error(cp
, "nresults must be > 0"));
267 * Make sure this is a handle we gave out ...
269 h
= fc_cell2phandle(fc_arg(cp
, 0));
270 if ((dip
= fc_phandle_to_dip(fc_handle_to_phandle_head(rp
), h
)) == NULL
)
271 return (fc_priv_error(cp
, "unknown handle"));
274 * XXX: We should care if the string is longer than OBP_MAXPROPNAME
276 pnp
= fc_cell2ptr(fc_arg(cp
, 2));
277 bzero(propname
, OBP_MAXPROPNAME
);
278 if (copyinstr(pnp
, propname
, OBP_MAXPROPNAME
- 1, NULL
))
279 return (fc_priv_error(cp
, "EFAULT copying in propname"));
281 if (ddi_getlongprop(DDI_DEV_T_ANY
, dip
, flags
,
282 propname
, (caddr_t
)&bp
, &proplen
))
286 char *up
= fc_cell2ptr(fc_arg(cp
, 1));
289 error
= copyout(bp
, up
, proplen
);
290 kmem_free(bp
, proplen
);
292 return (fc_priv_error(cp
, "EFAULT copying data out"));
295 cp
->nresults
= fc_int2cell(1);
296 fc_result(cp
, 0) = fc_int2cell(proplen
);
297 return (fc_success_op(ap
, rp
, cp
));
301 fco_ap_phandle(dev_info_t
*ap
, fco_handle_t rp
, fc_ci_t
*cp
)
305 if (fc_cell2int(cp
->nargs
) != 0)
306 return (fc_syntax_error(cp
, "nargs must be 0"));
308 if (fc_cell2int(cp
->nresults
) < 1)
309 return (fc_syntax_error(cp
, "nresults must be > 0"));
311 FC_DEBUG1(9, CE_CONT
, "fco_ap_phandle: Looking up ap dip %p\n", ap
);
313 h
= fc_dip_to_phandle(fc_handle_to_phandle_head(rp
), ap
);
314 cp
->nresults
= fc_int2cell(1);
315 fc_result(cp
, 0) = fc_phandle2cell(h
);
316 return (fc_success_op(ap
, rp
, cp
));
320 fco_child(dev_info_t
*ap
, fco_handle_t rp
, fc_ci_t
*cp
)
325 if (fc_cell2int(cp
->nargs
) != 1)
326 return (fc_syntax_error(cp
, "nargs must be 1"));
328 if (fc_cell2int(cp
->nresults
) < 1)
329 return (fc_syntax_error(cp
, "nresults must be > 0"));
332 * Make sure this is a handle we gave out ...
334 h
= fc_cell2phandle(fc_arg(cp
, 0));
335 if ((dip
= fc_phandle_to_dip(fc_handle_to_phandle_head(rp
), h
)) == NULL
)
336 return (fc_priv_error(cp
, "unknown handle"));
339 * Find the child and if there is one, return it ...
341 dip
= ddi_get_child(dip
);
344 h
= fc_dip_to_phandle(fc_handle_to_phandle_head(rp
), dip
);
346 cp
->nresults
= fc_int2cell(1);
347 fc_result(cp
, 0) = fc_phandle2cell(h
);
348 return (fc_success_op(ap
, rp
, cp
));
352 fco_peer(dev_info_t
*ap
, fco_handle_t rp
, fc_ci_t
*cp
)
357 if (fc_cell2int(cp
->nargs
) != 1)
358 return (fc_syntax_error(cp
, "nargs must be 1"));
360 if (fc_cell2int(cp
->nresults
) < 1)
361 return (fc_syntax_error(cp
, "nresults must be > 0"));
364 * Make sure this is a handle we gave out ...
366 h
= fc_cell2phandle(fc_arg(cp
, 0));
367 if ((dip
= fc_phandle_to_dip(fc_handle_to_phandle_head(rp
), h
)) == NULL
)
368 return (fc_priv_error(cp
, "unknown handle"));
371 * Find the child and if there is one, return it ...
373 dip
= ddi_get_next_sibling(dip
);
376 h
= fc_dip_to_phandle(fc_handle_to_phandle_head(rp
), dip
);
378 cp
->nresults
= fc_int2cell(1);
379 fc_result(cp
, 0) = fc_phandle2cell(h
);
380 return (fc_success_op(ap
, rp
, cp
));
384 fco_parent(dev_info_t
*ap
, fco_handle_t rp
, fc_ci_t
*cp
)
389 if (fc_cell2int(cp
->nargs
) != 1)
390 return (fc_syntax_error(cp
, "nargs must be 1"));
392 if (fc_cell2int(cp
->nresults
) < 1)
393 return (fc_syntax_error(cp
, "nresults must be > 0"));
396 * Make sure this is a handle we gave out ...
398 h
= fc_cell2phandle(fc_arg(cp
, 0));
399 if ((dip
= fc_phandle_to_dip(fc_handle_to_phandle_head(rp
), h
)) == NULL
)
400 return (fc_priv_error(cp
, "unknown handle"));
403 * Find the parent and if there is one, return it ...
405 dip
= ddi_get_parent(dip
);
408 h
= fc_dip_to_phandle(fc_handle_to_phandle_head(rp
), dip
);
410 cp
->nresults
= fc_int2cell(1);
411 fc_result(cp
, 0) = fc_phandle2cell(h
);
412 return (fc_success_op(ap
, rp
, cp
));
416 * Allocate a phandle ... we don't currently track the phandle.
419 fco_alloc_phandle(dev_info_t
*ap
, fco_handle_t rp
, fc_ci_t
*cp
)
423 struct fc_resource
*ip
;
425 if (fc_cell2int(cp
->nargs
) != 0)
426 return (fc_syntax_error(cp
, "nargs must be 0"));
428 if (fc_cell2int(cp
->nresults
) < 1)
429 return (fc_syntax_error(cp
, "nresults must be > 0"));
431 if (impl_ddi_alloc_nodeid(&n
))
432 return (fc_priv_error(cp
, "Can't allocate a nodeid"));
435 * Log the nodeid resource so we can release it later if we need to.
437 ip
= kmem_zalloc(sizeof (struct fc_resource
), KM_SLEEP
);
438 ip
->type
= RT_NODEID
;
440 fc_add_resource(rp
, ip
);
444 cp
->nresults
= fc_int2cell(1);
445 fc_result(cp
, 0) = fc_phandle2cell(h
);
446 return (fc_success_op(ap
, rp
, cp
));
449 static struct fc_resource
*
450 find_nodeid_resource(fco_handle_t rp
, int n
)
452 struct fc_resource
*ip
;
454 fc_lock_resource_list(rp
);
455 for (ip
= rp
->head
; ip
!= NULL
; ip
= ip
->next
) {
456 if (ip
->type
!= RT_NODEID
)
458 if (ip
->fc_nodeid_r
== n
)
461 fc_unlock_resource_list(rp
);
467 * fco_new_device ( name-cstr unit-addr-cstr parent.phandle phandle -- )
470 fco_new_device(dev_info_t
*ap
, fco_handle_t rp
, fc_ci_t
*cp
)
473 dev_info_t
*pdev
, *cdev
;
476 char *unit_address
= NULL
;
477 char nodename
[OBP_MAXPROPNAME
];
479 if (fc_cell2int(cp
->nargs
) != 4)
480 return (fc_syntax_error(cp
, "nargs must be 4"));
483 * Make sure these are handles we gave out ... and we have
484 * a corresponding parent devinfo node.
486 ph
= fc_cell2phandle(fc_arg(cp
, 1));
487 pdev
= fc_phandle_to_dip(fc_handle_to_phandle_head(rp
), ph
);
489 return (fc_priv_error(cp
, "unknown parent phandle"));
491 ch
= fc_cell2phandle(fc_arg(cp
, 0));
492 cdev
= fc_phandle_to_dip(fc_handle_to_phandle_head(rp
), ch
);
494 switch (rp
->cdip_state
) {
496 case FC_CDIP_NOSTATE
:
498 * The first child must be a child of the attachment point.
501 return (fc_priv_error(cp
, "first child must be a "
502 "child of the attachment point"));
505 * If this bus has a config child, the first child must
506 * be the configuration child. Otherwise, the child must
507 * be a new (unknown) node.
510 if (rp
->child
!= NULL
) {
511 if (cdev
!= rp
->child
)
512 return (fc_priv_error(cp
, "first "
514 "configuration child"));
516 return (fc_priv_error(cp
, "known child -- "
517 "unknown child expected"));
524 * If we've already created the first child, this
525 * child must be unknown and the parent must be a known
526 * child of the attachment point.
529 return (fc_priv_error(cp
, "known child -- "
530 "unknown child expected"));
531 if (fc_find_node(pdev
, fc_handle_to_dtree(rp
)) == NULL
)
532 return (fc_priv_error(cp
, "parent is an unknown "
533 "child of the attachment point"));
538 * If we're in some other state, we shouldn't be here.
540 return (fc_priv_error(cp
, "bad node-creation state"));
545 * Get the nodename and the unit address.
547 s
= fc_cell2ptr(fc_arg(cp
, 3));
548 bzero(nodename
, OBP_MAXPROPNAME
);
549 if (copyinstr(s
, nodename
, OBP_MAXPROPNAME
- 1, NULL
))
550 return (fc_priv_error(cp
, "EFAULT copying in nodename"));
552 s
= fc_cell2ptr(fc_arg(cp
, 2));
553 unit_address
= kmem_zalloc(OBP_MAXPATHLEN
, KM_SLEEP
);
554 if (copyinstr(s
, unit_address
, OBP_MAXPATHLEN
- 1, NULL
)) {
555 kmem_free(unit_address
, OBP_MAXPATHLEN
);
556 return (fc_priv_error(cp
, "EFAULT copying in unit address"));
560 * If cdev is NULL, we have to create the child, otherwise, the
561 * child already exists and we're just merging properties into
562 * the existing node. The node must be unbound.
569 struct fc_resource
*ip
;
572 * Make sure 'ch' is a nodeid we gave the interpreter.
573 * It must be on our resource list.
575 if ((ip
= find_nodeid_resource(rp
, (int)ch
)) == NULL
) {
576 kmem_free(unit_address
, OBP_MAXPATHLEN
);
577 return (fc_priv_error(cp
, "Unknown phandle"));
581 * Allocate a self-identifying, persistent node with
582 * the auto-free attribute.
584 if (ndi_devi_alloc(pdev
, nodename
, DEVI_SID_NODEID
, &cdev
)) {
585 kmem_free(unit_address
, OBP_MAXPATHLEN
);
586 return (fc_priv_error(cp
, "Can't create node"));
590 * Free the nodeid we just allocated here, and use
591 * the one we handed in. Retain the attributes of
592 * the original SID nodetype.
594 nodeid
= ddi_get_nodeid(cdev
);
595 i_ndi_set_nodeid(cdev
, (int)ch
);
596 impl_ddi_free_nodeid(nodeid
);
599 * Remove nodeid 'ch' from our resource list, now that it
600 * will be managed by the ddi framework.
602 fc_rem_resource(rp
, ip
);
603 kmem_free(ip
, sizeof (struct fc_resource
));
605 } else if (strcmp(ddi_node_name(cdev
), nodename
) != 0) {
606 FC_DEBUG2(1, CE_CONT
, "Changing <%s> nodename to <%s>\n",
607 ddi_node_name(cdev
), nodename
);
608 if (ndi_devi_set_nodename(cdev
, nodename
, 0)) {
609 kmem_free(unit_address
, OBP_MAXPATHLEN
);
610 return (fc_priv_error(cp
, "Can't set ndi nodename"));
614 if (fc_ndi_prop_update(DDI_DEV_T_NONE
, cdev
, "name",
615 (uchar_t
*)nodename
, strlen(nodename
) + 1)) {
616 kmem_free(unit_address
, OBP_MAXPATHLEN
);
618 (void) ndi_devi_free(cdev
);
619 return (fc_priv_error(cp
, "Can't create name property"));
623 * Add the dip->phandle translation to our list of known phandles.
625 fc_add_dip_to_phandle(fc_handle_to_phandle_head(rp
), cdev
, ch
);
628 * Add the new node to our copy of the subtree.
630 fc_add_child(cdev
, pdev
, fc_handle_to_dtree(rp
));
633 rp
->cdip_state
= FC_CDIP_STARTED
;
635 kmem_free(unit_address
, OBP_MAXPATHLEN
);
636 cp
->nresults
= fc_int2cell(0);
637 return (fc_success_op(ap
, rp
, cp
));
641 * fco_finish_device ( phandle -- )
644 fco_finish_device(dev_info_t
*ap
, fco_handle_t rp
, fc_ci_t
*cp
)
649 if (fc_cell2int(cp
->nargs
) != 1)
650 return (fc_syntax_error(cp
, "nargs must be 1"));
652 if (rp
->cdip_state
!= FC_CDIP_STARTED
)
653 return (fc_priv_error(cp
, "bad node-creation state"));
655 h
= fc_cell2phandle(fc_arg(cp
, 0));
656 cdev
= fc_phandle_to_dip(fc_handle_to_phandle_head(rp
), h
);
657 if (cdev
!= rp
->cdip
)
658 return (fc_priv_error(cp
, "bad phandle"));
661 * We don't want to online children of the attachment point.
662 * We'll 'config' them online later.
664 * XXX - APA - I've changed this a bit. The only time we don't
665 * want to bind the device is if the parent is the attachment point
666 * and the device is the same as the device that was passed to
667 * the interpreter. We assume the configurator will do the binding.
669 if ((ddi_get_parent(cdev
) == ap
) && (cdev
== rp
->child
)) {
670 FC_DEBUG2(5, CE_CONT
, "fc_finish_device: "
671 "*not* binding <%s> dip %p\n", ddi_node_name(cdev
), cdev
);
673 FC_DEBUG2(5, CE_CONT
, "fc_finish_device: binding <%s> dip %p\n",
674 ddi_node_name(cdev
), cdev
);
676 (void) ndi_devi_bind_driver(cdev
, 0);
679 rp
->cdip_state
= FC_CDIP_DONE
;
680 cp
->nresults
= fc_int2cell(0);
681 return (fc_success_op(ap
, rp
, cp
));
685 * fco_create_property ( propname-cstr buf len phandle -- )
688 fco_create_property(dev_info_t
*ap
, fco_handle_t rp
, fc_ci_t
*cp
)
690 char *buf
, *bp
, *pnp
;
695 char propname
[OBP_MAXPROPNAME
];
697 if (fc_cell2int(cp
->nargs
) != 4)
698 return (fc_syntax_error(cp
, "nargs must be 4"));
700 h
= fc_cell2phandle(fc_arg(cp
, 0));
701 len
= fc_cell2size(fc_arg(cp
, 1));
702 bp
= fc_cell2ptr(fc_arg(cp
, 2));
703 pnp
= fc_cell2ptr(fc_arg(cp
, 3));
705 dev
= fc_phandle_to_dip(fc_handle_to_phandle_head(rp
), h
);
707 return (fc_priv_error(cp
, "bad phandle"));
709 bzero(propname
, OBP_MAXPROPNAME
);
710 if (copyinstr(pnp
, propname
, OBP_MAXPROPNAME
- 1, NULL
))
711 return (fc_priv_error(cp
, "EFAULT copying in propname"));
715 buf
= kmem_zalloc(len
, KM_SLEEP
);
716 if (copyin(bp
, buf
, len
)) {
718 return (fc_priv_error(cp
, "EFAULT copying in propval"));
723 * check for propname: 'name' ... we don't allow it
724 * by changed here. It has to be specified when the node
727 if (strcmp(propname
, "name") == 0) {
728 char *n
= ddi_node_name(dev
);
731 return (fc_priv_error(cp
, "setting <name> to NULL"));
732 if ((len
< (strlen(n
) + 1)) || (strcmp(n
, buf
) != 0)) {
734 return (fc_priv_error(cp
, "changing <name> property"));
737 * Since we're not changing the value, and we already created
738 * the 'name' property when we created the node ...
741 cp
->nresults
= fc_int2cell(0);
742 return (fc_success_op(ap
, rp
, cp
));
745 error
= fc_ndi_prop_update(DDI_DEV_T_NONE
, dev
, propname
,
746 (uchar_t
*)buf
, len
);
752 return (fc_priv_error(cp
, "Can't create property"));
754 cp
->nresults
= fc_int2cell(0);
755 return (fc_success_op(ap
, rp
, cp
));
759 * Make sure any in-progress activity is completed,
760 * and for now, online the subtree.
761 * XXX: Presumably the configurator will online the subtree
762 * XXX: by doing an ndi_devi_online with NDI_CONFIG on the child
763 * XXX: if there is one. For now, we're doing it here.
764 * XXX: For buses without a configurator (and thus no config child),
765 * XXX: we have to do it here.
769 fco_validate(dev_info_t
*ap
, fco_handle_t rp
, fc_ci_t
*cp
)
771 rp
->cdip_state
= FC_CDIP_CONFIG
;
773 cp
->nresults
= fc_int2cell(0);
774 return (fc_success_op(ap
, rp
, cp
));
778 remove_subtree(dev_info_t
*root
, struct fc_device_tree
*subtree
)
783 * Remove the subtree, depth first. Each iterative
784 * call gets another child at each level of the tree
785 * until there are no more children.
787 while ((child
= fc_child_node(root
, subtree
)) != NULL
)
788 remove_subtree(child
, subtree
);
791 * Delete the subtree root and remove its record from our
792 * copy of the subtree.
794 fc_remove_child(root
, subtree
);
795 (void) ndi_devi_offline(root
, NDI_UNCONFIG
| NDI_DEVI_REMOVE
);
799 fco_invalidate(dev_info_t
*ap
, fco_handle_t rp
, fc_ci_t
*cp
)
801 dev_info_t
*root
, *child
;
802 struct fc_device_tree
*subtree
= fc_handle_to_dtree(rp
);
803 int configured
= (rp
->cdip_state
== FC_CDIP_CONFIG
);
806 * If we created any children, delete them. The root node is the
807 * config child, if one exists for this bus, otherwise it's the
810 * Our copy of the subtree only contains records of nodes we created
811 * under the subtree root and contains the parent->child linkage
812 * that isn't yet established in the real device tree.
814 * XXX: What we don't do is restore the config child node to it's
815 * pre-interpretive state. (We may have added properties to
816 * that node. It's not clear if its necessary to clean them up.)
818 root
= rp
->child
? rp
->child
: ap
;
820 while ((child
= fc_child_node(root
, subtree
)) != NULL
) {
821 FC_DEBUG2(1, CE_CONT
, "fco_invalidate: remove subtree "
822 "<%s> dip %p\n", ddi_node_name(child
), child
);
823 remove_subtree(child
, subtree
);
827 (void) ndi_devi_offline(root
, NDI_UNCONFIG
);
829 cp
->nresults
= fc_int2cell(0);
830 return (fc_success_op(ap
, rp
, cp
));
834 fco_exit(dev_info_t
*ap
, fco_handle_t rp
, fc_ci_t
*cp
)
836 FC_DEBUG0(1, CE_CONT
, "exit op not implemented .. succeeding\n");
837 cp
->nresults
= fc_int2cell(0);
838 return (fc_success_op(ap
, rp
, cp
));
842 * Needed to implement 'mac-address' Fcode, no obvious place to pick this
843 * info up from user-land.
846 fco_local_ether_addr(dev_info_t
*ap
, fco_handle_t rp
, fc_ci_t
*cp
)
848 if (fc_cell2int(cp
->nargs
) != 0)
849 return (fc_syntax_error(cp
, "nargs must be 0"));
851 if (fc_cell2int(cp
->nresults
) != 2)
852 return (fc_syntax_error(cp
, "nresults must be 2"));
854 cp
->nresults
= fc_int2cell(2);
856 (void) localetheraddr(NULL
, (struct ether_addr
*)(&fc_result(cp
, 0)));
858 return (fc_success_op(ap
, rp
, cp
));
863 fc_debug(char *fmt
, uintptr_t a1
, uintptr_t a2
, uintptr_t a3
,
864 uintptr_t a4
, uintptr_t a5
)
866 cmn_err(CE_CONT
, fmt
, a1
, a2
, a3
, a4
, a5
);