1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate * CDDL HEADER START
3*0Sstevel@tonic-gate *
4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
7*0Sstevel@tonic-gate * with the License.
8*0Sstevel@tonic-gate *
9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate * and limitations under the License.
13*0Sstevel@tonic-gate *
14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate *
20*0Sstevel@tonic-gate * CDDL HEADER END
21*0Sstevel@tonic-gate */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate * Copyright 2000, 2002 Sun Microsystems, Inc. All rights reserved.
24*0Sstevel@tonic-gate * Use is subject to license terms.
25*0Sstevel@tonic-gate */
26*0Sstevel@tonic-gate
27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
28*0Sstevel@tonic-gate
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate * fc_ops.c: Framework generic fcode ops
31*0Sstevel@tonic-gate */
32*0Sstevel@tonic-gate #include <sys/types.h>
33*0Sstevel@tonic-gate #include <sys/kmem.h>
34*0Sstevel@tonic-gate #include <sys/systm.h>
35*0Sstevel@tonic-gate #include <sys/ddi.h>
36*0Sstevel@tonic-gate #include <sys/sunddi.h>
37*0Sstevel@tonic-gate #include <sys/sunndi.h>
38*0Sstevel@tonic-gate #include <sys/modctl.h>
39*0Sstevel@tonic-gate #include <sys/fcode.h>
40*0Sstevel@tonic-gate #include <sys/ddi_implfuncs.h>
41*0Sstevel@tonic-gate #include <sys/ndi_impldefs.h>
42*0Sstevel@tonic-gate #include <sys/ethernet.h>
43*0Sstevel@tonic-gate
44*0Sstevel@tonic-gate static int fco_new_device(dev_info_t *, fco_handle_t, fc_ci_t *);
45*0Sstevel@tonic-gate static int fco_finish_device(dev_info_t *, fco_handle_t, fc_ci_t *);
46*0Sstevel@tonic-gate static int fco_create_property(dev_info_t *, fco_handle_t, fc_ci_t *);
47*0Sstevel@tonic-gate
48*0Sstevel@tonic-gate static int fco_validate(dev_info_t *, fco_handle_t, fc_ci_t *);
49*0Sstevel@tonic-gate static int fco_invalidate(dev_info_t *, fco_handle_t, fc_ci_t *);
50*0Sstevel@tonic-gate static int fco_exit(dev_info_t *, fco_handle_t, fc_ci_t *);
51*0Sstevel@tonic-gate
52*0Sstevel@tonic-gate static int fco_getproplen(dev_info_t *, fco_handle_t, fc_ci_t *);
53*0Sstevel@tonic-gate static int fco_getprop(dev_info_t *, fco_handle_t, fc_ci_t *);
54*0Sstevel@tonic-gate
55*0Sstevel@tonic-gate static int fco_ap_phandle(dev_info_t *, fco_handle_t, fc_ci_t *);
56*0Sstevel@tonic-gate static int fco_child(dev_info_t *, fco_handle_t, fc_ci_t *);
57*0Sstevel@tonic-gate static int fco_peer(dev_info_t *, fco_handle_t, fc_ci_t *);
58*0Sstevel@tonic-gate static int fco_parent(dev_info_t *, fco_handle_t, fc_ci_t *);
59*0Sstevel@tonic-gate static int fco_alloc_phandle(dev_info_t *, fco_handle_t, fc_ci_t *);
60*0Sstevel@tonic-gate
61*0Sstevel@tonic-gate static int fco_local_ether_addr(dev_info_t *, fco_handle_t, fc_ci_t *);
62*0Sstevel@tonic-gate
63*0Sstevel@tonic-gate struct fc_ops_v {
64*0Sstevel@tonic-gate char *svc_name;
65*0Sstevel@tonic-gate fc_ops_t *f;
66*0Sstevel@tonic-gate };
67*0Sstevel@tonic-gate
68*0Sstevel@tonic-gate static struct fc_ops_v fov[] = {
69*0Sstevel@tonic-gate { "open", fc_fail_op},
70*0Sstevel@tonic-gate { "close", fc_fail_op},
71*0Sstevel@tonic-gate { "$find", fc_fail_op},
72*0Sstevel@tonic-gate { "encode-unit", fc_fail_op},
73*0Sstevel@tonic-gate { "decode-unit", fc_fail_op},
74*0Sstevel@tonic-gate { FC_GET_MY_PROPLEN, fco_getproplen},
75*0Sstevel@tonic-gate { FC_GET_MY_PROP, fco_getprop},
76*0Sstevel@tonic-gate { FC_GET_PKG_PROPLEN, fco_getproplen},
77*0Sstevel@tonic-gate { FC_GET_PKG_PROP, fco_getprop},
78*0Sstevel@tonic-gate { FC_GET_IN_PROPLEN, fco_getproplen},
79*0Sstevel@tonic-gate { FC_GET_IN_PROP, fco_getprop},
80*0Sstevel@tonic-gate { FC_NEW_DEVICE, fco_new_device},
81*0Sstevel@tonic-gate { FC_FINISH_DEVICE, fco_finish_device},
82*0Sstevel@tonic-gate { FC_CREATE_PROPERTY, fco_create_property},
83*0Sstevel@tonic-gate { FC_AP_PHANDLE, fco_ap_phandle},
84*0Sstevel@tonic-gate { "child", fco_child},
85*0Sstevel@tonic-gate { "peer", fco_peer},
86*0Sstevel@tonic-gate { FC_PARENT, fco_parent},
87*0Sstevel@tonic-gate { FC_ALLOC_PHANDLE, fco_alloc_phandle},
88*0Sstevel@tonic-gate { FC_SVC_VALIDATE, fco_validate},
89*0Sstevel@tonic-gate { FC_SVC_INVALIDATE, fco_invalidate},
90*0Sstevel@tonic-gate { FC_SVC_EXIT, fco_exit},
91*0Sstevel@tonic-gate { "local-ether-addr", fco_local_ether_addr},
92*0Sstevel@tonic-gate { NULL, NULL}
93*0Sstevel@tonic-gate };
94*0Sstevel@tonic-gate
95*0Sstevel@tonic-gate /*
96*0Sstevel@tonic-gate * Allocate a handle for the ops function .. our handle is a resource list
97*0Sstevel@tonic-gate * Return the handle to our caller, so he can call us with it when we need it.
98*0Sstevel@tonic-gate */
99*0Sstevel@tonic-gate /*ARGSUSED*/
100*0Sstevel@tonic-gate fco_handle_t
fc_ops_alloc_handle(dev_info_t * ap,dev_info_t * child,void * fcode,size_t fcode_size,char * unit_address,void * bus_args)101*0Sstevel@tonic-gate fc_ops_alloc_handle(dev_info_t *ap, dev_info_t *child,
102*0Sstevel@tonic-gate void *fcode, size_t fcode_size, char *unit_address, void *bus_args)
103*0Sstevel@tonic-gate {
104*0Sstevel@tonic-gate fco_handle_t rp;
105*0Sstevel@tonic-gate char *up;
106*0Sstevel@tonic-gate
107*0Sstevel@tonic-gate rp = kmem_zalloc(sizeof (struct fc_resource_list), KM_SLEEP);
108*0Sstevel@tonic-gate rp->next_handle = NULL; /* nobody is downstream */
109*0Sstevel@tonic-gate rp->ap = ap;
110*0Sstevel@tonic-gate rp->child = child;
111*0Sstevel@tonic-gate rp->fcode = fcode;
112*0Sstevel@tonic-gate rp->fcode_size = fcode_size;
113*0Sstevel@tonic-gate if (unit_address) {
114*0Sstevel@tonic-gate up = kmem_zalloc(strlen(unit_address) + 1, KM_SLEEP);
115*0Sstevel@tonic-gate (void) strcpy(up, unit_address);
116*0Sstevel@tonic-gate rp->unit_address = up;
117*0Sstevel@tonic-gate }
118*0Sstevel@tonic-gate rp->bus_args = NULL; /* generic module has no bus args */
119*0Sstevel@tonic-gate fc_phandle_table_alloc(fc_handle_to_phandle_head(rp));
120*0Sstevel@tonic-gate
121*0Sstevel@tonic-gate (void) fc_dip_to_phandle(fc_handle_to_phandle_head(rp), ap);
122*0Sstevel@tonic-gate
123*0Sstevel@tonic-gate /*
124*0Sstevel@tonic-gate * Create our copy of the device tree.
125*0Sstevel@tonic-gate */
126*0Sstevel@tonic-gate fc_create_device_tree(ap, &rp->dtree);
127*0Sstevel@tonic-gate return (rp);
128*0Sstevel@tonic-gate }
129*0Sstevel@tonic-gate
130*0Sstevel@tonic-gate /*
131*0Sstevel@tonic-gate * Free any resources associated with this handle.
132*0Sstevel@tonic-gate */
133*0Sstevel@tonic-gate void
fc_ops_free_handle(fco_handle_t rp)134*0Sstevel@tonic-gate fc_ops_free_handle(fco_handle_t rp)
135*0Sstevel@tonic-gate {
136*0Sstevel@tonic-gate struct fc_resource *ip, *np;
137*0Sstevel@tonic-gate
138*0Sstevel@tonic-gate if (rp->unit_address)
139*0Sstevel@tonic-gate kmem_free(rp->unit_address, strlen(rp->unit_address) + 1);
140*0Sstevel@tonic-gate
141*0Sstevel@tonic-gate if (rp->dtree)
142*0Sstevel@tonic-gate fc_remove_device_tree(&rp->dtree);
143*0Sstevel@tonic-gate
144*0Sstevel@tonic-gate fc_phandle_table_free(fc_handle_to_phandle_head(rp));
145*0Sstevel@tonic-gate
146*0Sstevel@tonic-gate for (ip = rp->head; ip != NULL; ip = np) {
147*0Sstevel@tonic-gate np = ip->next;
148*0Sstevel@tonic-gate switch (ip->type) {
149*0Sstevel@tonic-gate case RT_NODEID:
150*0Sstevel@tonic-gate impl_ddi_free_nodeid(ip->fc_nodeid_r);
151*0Sstevel@tonic-gate break;
152*0Sstevel@tonic-gate default:
153*0Sstevel@tonic-gate cmn_err(CE_CONT, "pci_fc_ops_free: "
154*0Sstevel@tonic-gate "unknown resource type %d\n", ip->type);
155*0Sstevel@tonic-gate break;
156*0Sstevel@tonic-gate }
157*0Sstevel@tonic-gate fc_rem_resource(rp, ip);
158*0Sstevel@tonic-gate kmem_free(ip, sizeof (struct fc_resource));
159*0Sstevel@tonic-gate }
160*0Sstevel@tonic-gate kmem_free(rp, sizeof (struct fc_resource_list));
161*0Sstevel@tonic-gate }
162*0Sstevel@tonic-gate
163*0Sstevel@tonic-gate int
fc_ops(dev_info_t * ap,fco_handle_t handle,fc_ci_t * cp)164*0Sstevel@tonic-gate fc_ops(dev_info_t *ap, fco_handle_t handle, fc_ci_t *cp)
165*0Sstevel@tonic-gate {
166*0Sstevel@tonic-gate struct fc_ops_v *pv;
167*0Sstevel@tonic-gate char *name = fc_cell2ptr(cp->svc_name);
168*0Sstevel@tonic-gate
169*0Sstevel@tonic-gate for (pv = fov; pv->svc_name != NULL; ++pv)
170*0Sstevel@tonic-gate if (strcmp(pv->svc_name, name) == 0)
171*0Sstevel@tonic-gate return (pv->f(ap, handle, cp));
172*0Sstevel@tonic-gate
173*0Sstevel@tonic-gate return (-1);
174*0Sstevel@tonic-gate }
175*0Sstevel@tonic-gate
176*0Sstevel@tonic-gate /*
177*0Sstevel@tonic-gate * The interpreter can't do get-inherited-property directly,
178*0Sstevel@tonic-gate * because we don't want to return a kernel address, so it
179*0Sstevel@tonic-gate * has to break up the request into a get-proplen and get-prop
180*0Sstevel@tonic-gate * call so it can allocate memory for the property and pass that
181*0Sstevel@tonic-gate * buffer in to get-prop. The buffer should be 'suitably aligned'.
182*0Sstevel@tonic-gate *
183*0Sstevel@tonic-gate * XXX: We don't know the property type, so we can't return
184*0Sstevel@tonic-gate * prop-encoded arrays, which fortunately, isn't a problem
185*0Sstevel@tonic-gate * on big-endian machines.
186*0Sstevel@tonic-gate *
187*0Sstevel@tonic-gate * get-proplen has one result: proplen
188*0Sstevel@tonic-gate * proplen is returned as -1 if the propname doesn't exist and
189*0Sstevel@tonic-gate * as zero if the property is a boolean property.
190*0Sstevel@tonic-gate *
191*0Sstevel@tonic-gate * get-prop has one result: proplen, returned as -1 if propname doesn't exist.
192*0Sstevel@tonic-gate */
193*0Sstevel@tonic-gate
194*0Sstevel@tonic-gate /*
195*0Sstevel@tonic-gate * fco_getproplen ( propname phandle -- proplen )
196*0Sstevel@tonic-gate */
197*0Sstevel@tonic-gate
198*0Sstevel@tonic-gate /*ARGSUSED*/
199*0Sstevel@tonic-gate static int
fco_getproplen(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)200*0Sstevel@tonic-gate fco_getproplen(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
201*0Sstevel@tonic-gate {
202*0Sstevel@tonic-gate int proplen;
203*0Sstevel@tonic-gate int flags = 0;
204*0Sstevel@tonic-gate fc_phandle_t h;
205*0Sstevel@tonic-gate dev_info_t *dip;
206*0Sstevel@tonic-gate char *pnp;
207*0Sstevel@tonic-gate char propname[OBP_MAXPROPNAME];
208*0Sstevel@tonic-gate
209*0Sstevel@tonic-gate if (strstr(fc_cell2ptr(cp->svc_name), "inherited") == NULL)
210*0Sstevel@tonic-gate flags |= DDI_PROP_DONTPASS;
211*0Sstevel@tonic-gate
212*0Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 2)
213*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 2"));
214*0Sstevel@tonic-gate
215*0Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1)
216*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be > 0"));
217*0Sstevel@tonic-gate
218*0Sstevel@tonic-gate /*
219*0Sstevel@tonic-gate * Make sure this is a handle we gave out ...
220*0Sstevel@tonic-gate */
221*0Sstevel@tonic-gate h = fc_cell2phandle(fc_arg(cp, 0));
222*0Sstevel@tonic-gate if ((dip = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), h)) == NULL)
223*0Sstevel@tonic-gate return (fc_priv_error(cp, "unknown handle"));
224*0Sstevel@tonic-gate
225*0Sstevel@tonic-gate /*
226*0Sstevel@tonic-gate * XXX: We should care if the string is longer than OBP_MAXPROPNAME
227*0Sstevel@tonic-gate */
228*0Sstevel@tonic-gate pnp = fc_cell2ptr(fc_arg(cp, 1));
229*0Sstevel@tonic-gate bzero(propname, OBP_MAXPROPNAME);
230*0Sstevel@tonic-gate if (copyinstr(pnp, propname, OBP_MAXPROPNAME - 1, NULL))
231*0Sstevel@tonic-gate return (fc_priv_error(cp, "EFAULT copying in propname"));
232*0Sstevel@tonic-gate
233*0Sstevel@tonic-gate if (ddi_getproplen(DDI_DEV_T_ANY, dip, flags, propname, &proplen))
234*0Sstevel@tonic-gate proplen = -1;
235*0Sstevel@tonic-gate
236*0Sstevel@tonic-gate fc_result(cp, 0) = fc_int2cell(proplen);
237*0Sstevel@tonic-gate cp->nresults = fc_int2cell(1);
238*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
239*0Sstevel@tonic-gate }
240*0Sstevel@tonic-gate
241*0Sstevel@tonic-gate /*
242*0Sstevel@tonic-gate * fco_getprop ( propname buffer phandle -- proplen )
243*0Sstevel@tonic-gate */
244*0Sstevel@tonic-gate
245*0Sstevel@tonic-gate /*ARGSUSED*/
246*0Sstevel@tonic-gate static int
fco_getprop(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)247*0Sstevel@tonic-gate fco_getprop(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
248*0Sstevel@tonic-gate {
249*0Sstevel@tonic-gate int proplen = -1;
250*0Sstevel@tonic-gate int flags = DDI_PROP_CANSLEEP;
251*0Sstevel@tonic-gate char *pnp, *bp;
252*0Sstevel@tonic-gate fc_phandle_t h;
253*0Sstevel@tonic-gate dev_info_t *dip;
254*0Sstevel@tonic-gate char propname[OBP_MAXPROPNAME];
255*0Sstevel@tonic-gate
256*0Sstevel@tonic-gate if (strstr(fc_cell2ptr(cp->svc_name), "inherited") == NULL)
257*0Sstevel@tonic-gate flags |= DDI_PROP_DONTPASS;
258*0Sstevel@tonic-gate
259*0Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 3)
260*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 3"));
261*0Sstevel@tonic-gate
262*0Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1)
263*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be > 0"));
264*0Sstevel@tonic-gate
265*0Sstevel@tonic-gate /*
266*0Sstevel@tonic-gate * Make sure this is a handle we gave out ...
267*0Sstevel@tonic-gate */
268*0Sstevel@tonic-gate h = fc_cell2phandle(fc_arg(cp, 0));
269*0Sstevel@tonic-gate if ((dip = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), h)) == NULL)
270*0Sstevel@tonic-gate return (fc_priv_error(cp, "unknown handle"));
271*0Sstevel@tonic-gate
272*0Sstevel@tonic-gate /*
273*0Sstevel@tonic-gate * XXX: We should care if the string is longer than OBP_MAXPROPNAME
274*0Sstevel@tonic-gate */
275*0Sstevel@tonic-gate pnp = fc_cell2ptr(fc_arg(cp, 2));
276*0Sstevel@tonic-gate bzero(propname, OBP_MAXPROPNAME);
277*0Sstevel@tonic-gate if (copyinstr(pnp, propname, OBP_MAXPROPNAME - 1, NULL))
278*0Sstevel@tonic-gate return (fc_priv_error(cp, "EFAULT copying in propname"));
279*0Sstevel@tonic-gate
280*0Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, dip, flags,
281*0Sstevel@tonic-gate propname, (caddr_t)&bp, &proplen))
282*0Sstevel@tonic-gate proplen = -1;
283*0Sstevel@tonic-gate
284*0Sstevel@tonic-gate if (proplen > 0) {
285*0Sstevel@tonic-gate char *up = fc_cell2ptr(fc_arg(cp, 1));
286*0Sstevel@tonic-gate int error;
287*0Sstevel@tonic-gate
288*0Sstevel@tonic-gate error = copyout(bp, up, proplen);
289*0Sstevel@tonic-gate kmem_free(bp, proplen);
290*0Sstevel@tonic-gate if (error)
291*0Sstevel@tonic-gate return (fc_priv_error(cp, "EFAULT copying data out"));
292*0Sstevel@tonic-gate }
293*0Sstevel@tonic-gate
294*0Sstevel@tonic-gate cp->nresults = fc_int2cell(1);
295*0Sstevel@tonic-gate fc_result(cp, 0) = fc_int2cell(proplen);
296*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
297*0Sstevel@tonic-gate }
298*0Sstevel@tonic-gate
299*0Sstevel@tonic-gate static int
fco_ap_phandle(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)300*0Sstevel@tonic-gate fco_ap_phandle(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
301*0Sstevel@tonic-gate {
302*0Sstevel@tonic-gate fc_phandle_t h;
303*0Sstevel@tonic-gate
304*0Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 0)
305*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 0"));
306*0Sstevel@tonic-gate
307*0Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1)
308*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be > 0"));
309*0Sstevel@tonic-gate
310*0Sstevel@tonic-gate FC_DEBUG1(9, CE_CONT, "fco_ap_phandle: Looking up ap dip %p\n", ap);
311*0Sstevel@tonic-gate
312*0Sstevel@tonic-gate h = fc_dip_to_phandle(fc_handle_to_phandle_head(rp), ap);
313*0Sstevel@tonic-gate cp->nresults = fc_int2cell(1);
314*0Sstevel@tonic-gate fc_result(cp, 0) = fc_phandle2cell(h);
315*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
316*0Sstevel@tonic-gate }
317*0Sstevel@tonic-gate
318*0Sstevel@tonic-gate static int
fco_child(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)319*0Sstevel@tonic-gate fco_child(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
320*0Sstevel@tonic-gate {
321*0Sstevel@tonic-gate fc_phandle_t h;
322*0Sstevel@tonic-gate dev_info_t *dip;
323*0Sstevel@tonic-gate
324*0Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 1)
325*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 1"));
326*0Sstevel@tonic-gate
327*0Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1)
328*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be > 0"));
329*0Sstevel@tonic-gate
330*0Sstevel@tonic-gate /*
331*0Sstevel@tonic-gate * Make sure this is a handle we gave out ...
332*0Sstevel@tonic-gate */
333*0Sstevel@tonic-gate h = fc_cell2phandle(fc_arg(cp, 0));
334*0Sstevel@tonic-gate if ((dip = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), h)) == NULL)
335*0Sstevel@tonic-gate return (fc_priv_error(cp, "unknown handle"));
336*0Sstevel@tonic-gate
337*0Sstevel@tonic-gate /*
338*0Sstevel@tonic-gate * Find the child and if there is one, return it ...
339*0Sstevel@tonic-gate */
340*0Sstevel@tonic-gate dip = ddi_get_child(dip);
341*0Sstevel@tonic-gate h = 0;
342*0Sstevel@tonic-gate if (dip != NULL)
343*0Sstevel@tonic-gate h = fc_dip_to_phandle(fc_handle_to_phandle_head(rp), dip);
344*0Sstevel@tonic-gate
345*0Sstevel@tonic-gate cp->nresults = fc_int2cell(1);
346*0Sstevel@tonic-gate fc_result(cp, 0) = fc_phandle2cell(h);
347*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
348*0Sstevel@tonic-gate }
349*0Sstevel@tonic-gate
350*0Sstevel@tonic-gate static int
fco_peer(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)351*0Sstevel@tonic-gate fco_peer(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
352*0Sstevel@tonic-gate {
353*0Sstevel@tonic-gate fc_phandle_t h;
354*0Sstevel@tonic-gate dev_info_t *dip;
355*0Sstevel@tonic-gate
356*0Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 1)
357*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 1"));
358*0Sstevel@tonic-gate
359*0Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1)
360*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be > 0"));
361*0Sstevel@tonic-gate
362*0Sstevel@tonic-gate /*
363*0Sstevel@tonic-gate * Make sure this is a handle we gave out ...
364*0Sstevel@tonic-gate */
365*0Sstevel@tonic-gate h = fc_cell2phandle(fc_arg(cp, 0));
366*0Sstevel@tonic-gate if ((dip = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), h)) == NULL)
367*0Sstevel@tonic-gate return (fc_priv_error(cp, "unknown handle"));
368*0Sstevel@tonic-gate
369*0Sstevel@tonic-gate /*
370*0Sstevel@tonic-gate * Find the child and if there is one, return it ...
371*0Sstevel@tonic-gate */
372*0Sstevel@tonic-gate dip = ddi_get_next_sibling(dip);
373*0Sstevel@tonic-gate h = 0;
374*0Sstevel@tonic-gate if (dip != NULL)
375*0Sstevel@tonic-gate h = fc_dip_to_phandle(fc_handle_to_phandle_head(rp), dip);
376*0Sstevel@tonic-gate
377*0Sstevel@tonic-gate cp->nresults = fc_int2cell(1);
378*0Sstevel@tonic-gate fc_result(cp, 0) = fc_phandle2cell(h);
379*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
380*0Sstevel@tonic-gate }
381*0Sstevel@tonic-gate
382*0Sstevel@tonic-gate static int
fco_parent(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)383*0Sstevel@tonic-gate fco_parent(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
384*0Sstevel@tonic-gate {
385*0Sstevel@tonic-gate fc_phandle_t h;
386*0Sstevel@tonic-gate dev_info_t *dip;
387*0Sstevel@tonic-gate
388*0Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 1)
389*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 1"));
390*0Sstevel@tonic-gate
391*0Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1)
392*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be > 0"));
393*0Sstevel@tonic-gate
394*0Sstevel@tonic-gate /*
395*0Sstevel@tonic-gate * Make sure this is a handle we gave out ...
396*0Sstevel@tonic-gate */
397*0Sstevel@tonic-gate h = fc_cell2phandle(fc_arg(cp, 0));
398*0Sstevel@tonic-gate if ((dip = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), h)) == NULL)
399*0Sstevel@tonic-gate return (fc_priv_error(cp, "unknown handle"));
400*0Sstevel@tonic-gate
401*0Sstevel@tonic-gate /*
402*0Sstevel@tonic-gate * Find the parent and if there is one, return it ...
403*0Sstevel@tonic-gate */
404*0Sstevel@tonic-gate dip = ddi_get_parent(dip);
405*0Sstevel@tonic-gate h = 0;
406*0Sstevel@tonic-gate if (dip != NULL)
407*0Sstevel@tonic-gate h = fc_dip_to_phandle(fc_handle_to_phandle_head(rp), dip);
408*0Sstevel@tonic-gate
409*0Sstevel@tonic-gate cp->nresults = fc_int2cell(1);
410*0Sstevel@tonic-gate fc_result(cp, 0) = fc_phandle2cell(h);
411*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
412*0Sstevel@tonic-gate }
413*0Sstevel@tonic-gate
414*0Sstevel@tonic-gate /*
415*0Sstevel@tonic-gate * Allocate a phandle ... we don't currently track the phandle.
416*0Sstevel@tonic-gate */
417*0Sstevel@tonic-gate static int
fco_alloc_phandle(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)418*0Sstevel@tonic-gate fco_alloc_phandle(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
419*0Sstevel@tonic-gate {
420*0Sstevel@tonic-gate fc_phandle_t h;
421*0Sstevel@tonic-gate int n;
422*0Sstevel@tonic-gate struct fc_resource *ip;
423*0Sstevel@tonic-gate
424*0Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 0)
425*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 0"));
426*0Sstevel@tonic-gate
427*0Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1)
428*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be > 0"));
429*0Sstevel@tonic-gate
430*0Sstevel@tonic-gate if (impl_ddi_alloc_nodeid(&n))
431*0Sstevel@tonic-gate return (fc_priv_error(cp, "Can't allocate a nodeid"));
432*0Sstevel@tonic-gate
433*0Sstevel@tonic-gate /*
434*0Sstevel@tonic-gate * Log the nodeid resource so we can release it later if we need to.
435*0Sstevel@tonic-gate */
436*0Sstevel@tonic-gate ip = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP);
437*0Sstevel@tonic-gate ip->type = RT_NODEID;
438*0Sstevel@tonic-gate ip->fc_nodeid_r = n;
439*0Sstevel@tonic-gate fc_add_resource(rp, ip);
440*0Sstevel@tonic-gate
441*0Sstevel@tonic-gate h = (fc_phandle_t)n;
442*0Sstevel@tonic-gate
443*0Sstevel@tonic-gate cp->nresults = fc_int2cell(1);
444*0Sstevel@tonic-gate fc_result(cp, 0) = fc_phandle2cell(h);
445*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
446*0Sstevel@tonic-gate }
447*0Sstevel@tonic-gate
448*0Sstevel@tonic-gate static struct fc_resource *
find_nodeid_resource(fco_handle_t rp,int n)449*0Sstevel@tonic-gate find_nodeid_resource(fco_handle_t rp, int n)
450*0Sstevel@tonic-gate {
451*0Sstevel@tonic-gate struct fc_resource *ip;
452*0Sstevel@tonic-gate
453*0Sstevel@tonic-gate fc_lock_resource_list(rp);
454*0Sstevel@tonic-gate for (ip = rp->head; ip != NULL; ip = ip->next) {
455*0Sstevel@tonic-gate if (ip->type != RT_NODEID)
456*0Sstevel@tonic-gate continue;
457*0Sstevel@tonic-gate if (ip->fc_nodeid_r == n)
458*0Sstevel@tonic-gate break;
459*0Sstevel@tonic-gate }
460*0Sstevel@tonic-gate fc_unlock_resource_list(rp);
461*0Sstevel@tonic-gate
462*0Sstevel@tonic-gate return (ip);
463*0Sstevel@tonic-gate }
464*0Sstevel@tonic-gate
465*0Sstevel@tonic-gate /*
466*0Sstevel@tonic-gate * fco_new_device ( name-cstr unit-addr-cstr parent.phandle phandle -- )
467*0Sstevel@tonic-gate */
468*0Sstevel@tonic-gate static int
fco_new_device(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)469*0Sstevel@tonic-gate fco_new_device(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
470*0Sstevel@tonic-gate {
471*0Sstevel@tonic-gate fc_phandle_t ph, ch;
472*0Sstevel@tonic-gate dev_info_t *pdev, *cdev;
473*0Sstevel@tonic-gate char *s;
474*0Sstevel@tonic-gate int createmode = 0;
475*0Sstevel@tonic-gate char *unit_address = NULL;
476*0Sstevel@tonic-gate char nodename[OBP_MAXPROPNAME];
477*0Sstevel@tonic-gate
478*0Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 4)
479*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 4"));
480*0Sstevel@tonic-gate
481*0Sstevel@tonic-gate /*
482*0Sstevel@tonic-gate * Make sure these are handles we gave out ... and we have
483*0Sstevel@tonic-gate * a corresponding parent devinfo node.
484*0Sstevel@tonic-gate */
485*0Sstevel@tonic-gate ph = fc_cell2phandle(fc_arg(cp, 1));
486*0Sstevel@tonic-gate pdev = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), ph);
487*0Sstevel@tonic-gate if (pdev == NULL)
488*0Sstevel@tonic-gate return (fc_priv_error(cp, "unknown parent phandle"));
489*0Sstevel@tonic-gate
490*0Sstevel@tonic-gate ch = fc_cell2phandle(fc_arg(cp, 0));
491*0Sstevel@tonic-gate cdev = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), ch);
492*0Sstevel@tonic-gate
493*0Sstevel@tonic-gate switch (rp->cdip_state) {
494*0Sstevel@tonic-gate
495*0Sstevel@tonic-gate case FC_CDIP_NOSTATE:
496*0Sstevel@tonic-gate /*
497*0Sstevel@tonic-gate * The first child must be a child of the attachment point.
498*0Sstevel@tonic-gate */
499*0Sstevel@tonic-gate if (pdev != ap)
500*0Sstevel@tonic-gate return (fc_priv_error(cp, "first child must be a "
501*0Sstevel@tonic-gate "child of the attachment point"));
502*0Sstevel@tonic-gate
503*0Sstevel@tonic-gate /*
504*0Sstevel@tonic-gate * If this bus has a config child, the first child must
505*0Sstevel@tonic-gate * be the configuration child. Otherwise, the child must
506*0Sstevel@tonic-gate * be a new (unknown) node.
507*0Sstevel@tonic-gate */
508*0Sstevel@tonic-gate if (cdev != NULL) {
509*0Sstevel@tonic-gate if (rp->child != NULL) {
510*0Sstevel@tonic-gate if (cdev != rp->child)
511*0Sstevel@tonic-gate return (fc_priv_error(cp, "first "
512*0Sstevel@tonic-gate "child must be the "
513*0Sstevel@tonic-gate "configuration child"));
514*0Sstevel@tonic-gate } else {
515*0Sstevel@tonic-gate return (fc_priv_error(cp, "known child -- "
516*0Sstevel@tonic-gate "unknown child expected"));
517*0Sstevel@tonic-gate }
518*0Sstevel@tonic-gate }
519*0Sstevel@tonic-gate break;
520*0Sstevel@tonic-gate
521*0Sstevel@tonic-gate case FC_CDIP_DONE:
522*0Sstevel@tonic-gate /*
523*0Sstevel@tonic-gate * If we've already created the first child, this
524*0Sstevel@tonic-gate * child must be unknown and the parent must be a known
525*0Sstevel@tonic-gate * child of the attachment point.
526*0Sstevel@tonic-gate */
527*0Sstevel@tonic-gate if (cdev)
528*0Sstevel@tonic-gate return (fc_priv_error(cp, "known child -- "
529*0Sstevel@tonic-gate "unknown child expected"));
530*0Sstevel@tonic-gate if (fc_find_node(pdev, fc_handle_to_dtree(rp)) == NULL)
531*0Sstevel@tonic-gate return (fc_priv_error(cp, "parent is an unknown "
532*0Sstevel@tonic-gate "child of the attachment point"));
533*0Sstevel@tonic-gate break;
534*0Sstevel@tonic-gate
535*0Sstevel@tonic-gate default:
536*0Sstevel@tonic-gate /*
537*0Sstevel@tonic-gate * If we're in some other state, we shouldn't be here.
538*0Sstevel@tonic-gate */
539*0Sstevel@tonic-gate return (fc_priv_error(cp, "bad node-creation state"));
540*0Sstevel@tonic-gate /* NOTREACHED */
541*0Sstevel@tonic-gate }
542*0Sstevel@tonic-gate
543*0Sstevel@tonic-gate /*
544*0Sstevel@tonic-gate * Get the nodename and the unit address.
545*0Sstevel@tonic-gate */
546*0Sstevel@tonic-gate s = fc_cell2ptr(fc_arg(cp, 3));
547*0Sstevel@tonic-gate bzero(nodename, OBP_MAXPROPNAME);
548*0Sstevel@tonic-gate if (copyinstr(s, nodename, OBP_MAXPROPNAME - 1, NULL))
549*0Sstevel@tonic-gate return (fc_priv_error(cp, "EFAULT copying in nodename"));
550*0Sstevel@tonic-gate
551*0Sstevel@tonic-gate s = fc_cell2ptr(fc_arg(cp, 2));
552*0Sstevel@tonic-gate unit_address = kmem_zalloc(OBP_MAXPATHLEN, KM_SLEEP);
553*0Sstevel@tonic-gate if (copyinstr(s, unit_address, OBP_MAXPATHLEN - 1, NULL)) {
554*0Sstevel@tonic-gate kmem_free(unit_address, OBP_MAXPATHLEN);
555*0Sstevel@tonic-gate return (fc_priv_error(cp, "EFAULT copying in unit address"));
556*0Sstevel@tonic-gate }
557*0Sstevel@tonic-gate
558*0Sstevel@tonic-gate /*
559*0Sstevel@tonic-gate * If cdev is NULL, we have to create the child, otherwise, the
560*0Sstevel@tonic-gate * child already exists and we're just merging properties into
561*0Sstevel@tonic-gate * the existing node. The node must be unbound.
562*0Sstevel@tonic-gate */
563*0Sstevel@tonic-gate
564*0Sstevel@tonic-gate if (cdev == NULL)
565*0Sstevel@tonic-gate createmode = 1;
566*0Sstevel@tonic-gate
567*0Sstevel@tonic-gate if (createmode) {
568*0Sstevel@tonic-gate struct fc_resource *ip;
569*0Sstevel@tonic-gate int nodeid;
570*0Sstevel@tonic-gate /*
571*0Sstevel@tonic-gate * Make sure 'ch' is a nodeid we gave the interpreter.
572*0Sstevel@tonic-gate * It must be on our resource list.
573*0Sstevel@tonic-gate */
574*0Sstevel@tonic-gate if ((ip = find_nodeid_resource(rp, (int)ch)) == NULL) {
575*0Sstevel@tonic-gate kmem_free(unit_address, OBP_MAXPATHLEN);
576*0Sstevel@tonic-gate return (fc_priv_error(cp, "Unknown phandle"));
577*0Sstevel@tonic-gate }
578*0Sstevel@tonic-gate
579*0Sstevel@tonic-gate /*
580*0Sstevel@tonic-gate * Allocate a self-identifying, persistent node with
581*0Sstevel@tonic-gate * the auto-free attribute.
582*0Sstevel@tonic-gate */
583*0Sstevel@tonic-gate if (ndi_devi_alloc(pdev, nodename, DEVI_SID_NODEID, &cdev)) {
584*0Sstevel@tonic-gate kmem_free(unit_address, OBP_MAXPATHLEN);
585*0Sstevel@tonic-gate return (fc_priv_error(cp, "Can't create node"));
586*0Sstevel@tonic-gate }
587*0Sstevel@tonic-gate
588*0Sstevel@tonic-gate /*
589*0Sstevel@tonic-gate * Free the nodeid we just allocated here, and use
590*0Sstevel@tonic-gate * the one we handed in. Retain the attributes of
591*0Sstevel@tonic-gate * the original SID nodetype.
592*0Sstevel@tonic-gate */
593*0Sstevel@tonic-gate nodeid = ddi_get_nodeid(cdev);
594*0Sstevel@tonic-gate i_ndi_set_nodeid(cdev, (int)ch);
595*0Sstevel@tonic-gate impl_ddi_free_nodeid(nodeid);
596*0Sstevel@tonic-gate
597*0Sstevel@tonic-gate /*
598*0Sstevel@tonic-gate * Remove nodeid 'ch' from our resource list, now that it
599*0Sstevel@tonic-gate * will be managed by the ddi framework.
600*0Sstevel@tonic-gate */
601*0Sstevel@tonic-gate fc_rem_resource(rp, ip);
602*0Sstevel@tonic-gate kmem_free(ip, sizeof (struct fc_resource));
603*0Sstevel@tonic-gate
604*0Sstevel@tonic-gate } else if (strcmp(ddi_node_name(cdev), nodename) != 0) {
605*0Sstevel@tonic-gate FC_DEBUG2(1, CE_CONT, "Changing <%s> nodename to <%s>\n",
606*0Sstevel@tonic-gate ddi_node_name(cdev), nodename);
607*0Sstevel@tonic-gate if (ndi_devi_set_nodename(cdev, nodename, 0)) {
608*0Sstevel@tonic-gate kmem_free(unit_address, OBP_MAXPATHLEN);
609*0Sstevel@tonic-gate return (fc_priv_error(cp, "Can't set ndi nodename"));
610*0Sstevel@tonic-gate }
611*0Sstevel@tonic-gate }
612*0Sstevel@tonic-gate
613*0Sstevel@tonic-gate if (fc_ndi_prop_update(DDI_DEV_T_NONE, cdev, "name",
614*0Sstevel@tonic-gate (uchar_t *)nodename, strlen(nodename) + 1)) {
615*0Sstevel@tonic-gate kmem_free(unit_address, OBP_MAXPATHLEN);
616*0Sstevel@tonic-gate if (createmode)
617*0Sstevel@tonic-gate (void) ndi_devi_free(cdev);
618*0Sstevel@tonic-gate return (fc_priv_error(cp, "Can't create name property"));
619*0Sstevel@tonic-gate }
620*0Sstevel@tonic-gate
621*0Sstevel@tonic-gate /*
622*0Sstevel@tonic-gate * Add the dip->phandle translation to our list of known phandles.
623*0Sstevel@tonic-gate */
624*0Sstevel@tonic-gate fc_add_dip_to_phandle(fc_handle_to_phandle_head(rp), cdev, ch);
625*0Sstevel@tonic-gate
626*0Sstevel@tonic-gate /*
627*0Sstevel@tonic-gate * Add the new node to our copy of the subtree.
628*0Sstevel@tonic-gate */
629*0Sstevel@tonic-gate fc_add_child(cdev, pdev, fc_handle_to_dtree(rp));
630*0Sstevel@tonic-gate
631*0Sstevel@tonic-gate rp->cdip = cdev;
632*0Sstevel@tonic-gate rp->cdip_state = FC_CDIP_STARTED;
633*0Sstevel@tonic-gate
634*0Sstevel@tonic-gate kmem_free(unit_address, OBP_MAXPATHLEN);
635*0Sstevel@tonic-gate cp->nresults = fc_int2cell(0);
636*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
637*0Sstevel@tonic-gate }
638*0Sstevel@tonic-gate
639*0Sstevel@tonic-gate /*
640*0Sstevel@tonic-gate * fco_finish_device ( phandle -- )
641*0Sstevel@tonic-gate */
642*0Sstevel@tonic-gate static int
fco_finish_device(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)643*0Sstevel@tonic-gate fco_finish_device(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
644*0Sstevel@tonic-gate {
645*0Sstevel@tonic-gate fc_phandle_t h;
646*0Sstevel@tonic-gate dev_info_t *cdev;
647*0Sstevel@tonic-gate
648*0Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 1)
649*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 1"));
650*0Sstevel@tonic-gate
651*0Sstevel@tonic-gate if (rp->cdip_state != FC_CDIP_STARTED)
652*0Sstevel@tonic-gate return (fc_priv_error(cp, "bad node-creation state"));
653*0Sstevel@tonic-gate
654*0Sstevel@tonic-gate h = fc_cell2phandle(fc_arg(cp, 0));
655*0Sstevel@tonic-gate cdev = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), h);
656*0Sstevel@tonic-gate if (cdev != rp->cdip)
657*0Sstevel@tonic-gate return (fc_priv_error(cp, "bad phandle"));
658*0Sstevel@tonic-gate
659*0Sstevel@tonic-gate /*
660*0Sstevel@tonic-gate * We don't want to online children of the attachment point.
661*0Sstevel@tonic-gate * We'll 'config' them online later.
662*0Sstevel@tonic-gate *
663*0Sstevel@tonic-gate * XXX - APA - I've changed this a bit. The only time we don't
664*0Sstevel@tonic-gate * want to bind the device is if the parent is the attachment point
665*0Sstevel@tonic-gate * and the device is the same as the device that was passed to
666*0Sstevel@tonic-gate * the interpreter. We assume the configurator will do the binding.
667*0Sstevel@tonic-gate */
668*0Sstevel@tonic-gate if ((ddi_get_parent(cdev) == ap) && (cdev == rp->child)) {
669*0Sstevel@tonic-gate FC_DEBUG2(5, CE_CONT, "fc_finish_device: "
670*0Sstevel@tonic-gate "*not* binding <%s> dip %p\n", ddi_node_name(cdev), cdev);
671*0Sstevel@tonic-gate } else {
672*0Sstevel@tonic-gate FC_DEBUG2(5, CE_CONT, "fc_finish_device: binding <%s> dip %p\n",
673*0Sstevel@tonic-gate ddi_node_name(cdev), cdev);
674*0Sstevel@tonic-gate
675*0Sstevel@tonic-gate (void) ndi_devi_bind_driver(cdev, 0);
676*0Sstevel@tonic-gate }
677*0Sstevel@tonic-gate
678*0Sstevel@tonic-gate rp->cdip_state = FC_CDIP_DONE;
679*0Sstevel@tonic-gate cp->nresults = fc_int2cell(0);
680*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
681*0Sstevel@tonic-gate }
682*0Sstevel@tonic-gate
683*0Sstevel@tonic-gate /*
684*0Sstevel@tonic-gate * fco_create_property ( propname-cstr buf len phandle -- )
685*0Sstevel@tonic-gate */
686*0Sstevel@tonic-gate static int
fco_create_property(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)687*0Sstevel@tonic-gate fco_create_property(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
688*0Sstevel@tonic-gate {
689*0Sstevel@tonic-gate char *buf, *bp, *pnp;
690*0Sstevel@tonic-gate size_t len;
691*0Sstevel@tonic-gate fc_phandle_t h;
692*0Sstevel@tonic-gate dev_info_t *dev;
693*0Sstevel@tonic-gate int error;
694*0Sstevel@tonic-gate char propname[OBP_MAXPROPNAME];
695*0Sstevel@tonic-gate
696*0Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 4)
697*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 4"));
698*0Sstevel@tonic-gate
699*0Sstevel@tonic-gate h = fc_cell2phandle(fc_arg(cp, 0));
700*0Sstevel@tonic-gate len = fc_cell2size(fc_arg(cp, 1));
701*0Sstevel@tonic-gate bp = fc_cell2ptr(fc_arg(cp, 2));
702*0Sstevel@tonic-gate pnp = fc_cell2ptr(fc_arg(cp, 3));
703*0Sstevel@tonic-gate
704*0Sstevel@tonic-gate dev = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), h);
705*0Sstevel@tonic-gate if (dev == NULL)
706*0Sstevel@tonic-gate return (fc_priv_error(cp, "bad phandle"));
707*0Sstevel@tonic-gate
708*0Sstevel@tonic-gate bzero(propname, OBP_MAXPROPNAME);
709*0Sstevel@tonic-gate if (copyinstr(pnp, propname, OBP_MAXPROPNAME - 1, NULL))
710*0Sstevel@tonic-gate return (fc_priv_error(cp, "EFAULT copying in propname"));
711*0Sstevel@tonic-gate
712*0Sstevel@tonic-gate buf = NULL;
713*0Sstevel@tonic-gate if (len != 0) {
714*0Sstevel@tonic-gate buf = kmem_zalloc(len, KM_SLEEP);
715*0Sstevel@tonic-gate if (copyin(bp, buf, len)) {
716*0Sstevel@tonic-gate kmem_free(buf, len);
717*0Sstevel@tonic-gate return (fc_priv_error(cp, "EFAULT copying in propval"));
718*0Sstevel@tonic-gate }
719*0Sstevel@tonic-gate }
720*0Sstevel@tonic-gate
721*0Sstevel@tonic-gate /*
722*0Sstevel@tonic-gate * check for propname: 'name' ... we don't allow it
723*0Sstevel@tonic-gate * by changed here. It has to be specified when the node
724*0Sstevel@tonic-gate * is created.
725*0Sstevel@tonic-gate */
726*0Sstevel@tonic-gate if (strcmp(propname, "name") == 0) {
727*0Sstevel@tonic-gate char *n = ddi_node_name(dev);
728*0Sstevel@tonic-gate
729*0Sstevel@tonic-gate if (len == 0)
730*0Sstevel@tonic-gate return (fc_priv_error(cp, "setting <name> to NULL"));
731*0Sstevel@tonic-gate if ((len < (strlen(n) + 1)) || (strcmp(n, buf) != 0)) {
732*0Sstevel@tonic-gate kmem_free(buf, len);
733*0Sstevel@tonic-gate return (fc_priv_error(cp, "changing <name> property"));
734*0Sstevel@tonic-gate }
735*0Sstevel@tonic-gate /*
736*0Sstevel@tonic-gate * Since we're not changing the value, and we already created
737*0Sstevel@tonic-gate * the 'name' property when we created the node ...
738*0Sstevel@tonic-gate */
739*0Sstevel@tonic-gate kmem_free(buf, len);
740*0Sstevel@tonic-gate cp->nresults = fc_int2cell(0);
741*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
742*0Sstevel@tonic-gate }
743*0Sstevel@tonic-gate
744*0Sstevel@tonic-gate error = fc_ndi_prop_update(DDI_DEV_T_NONE, dev, propname,
745*0Sstevel@tonic-gate (uchar_t *)buf, len);
746*0Sstevel@tonic-gate
747*0Sstevel@tonic-gate if (len != 0)
748*0Sstevel@tonic-gate kmem_free(buf, len);
749*0Sstevel@tonic-gate
750*0Sstevel@tonic-gate if (error)
751*0Sstevel@tonic-gate return (fc_priv_error(cp, "Can't create property"));
752*0Sstevel@tonic-gate
753*0Sstevel@tonic-gate cp->nresults = fc_int2cell(0);
754*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
755*0Sstevel@tonic-gate }
756*0Sstevel@tonic-gate
757*0Sstevel@tonic-gate /*
758*0Sstevel@tonic-gate * Make sure any in-progress activity is completed,
759*0Sstevel@tonic-gate * and for now, online the subtree.
760*0Sstevel@tonic-gate * XXX: Presumably the configurator will online the subtree
761*0Sstevel@tonic-gate * XXX: by doing an ndi_devi_online with NDI_CONFIG on the child
762*0Sstevel@tonic-gate * XXX: if there is one. For now, we're doing it here.
763*0Sstevel@tonic-gate * XXX: For buses without a configurator (and thus no config child),
764*0Sstevel@tonic-gate * XXX: we have to do it here.
765*0Sstevel@tonic-gate *
766*0Sstevel@tonic-gate */
767*0Sstevel@tonic-gate static int
fco_validate(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)768*0Sstevel@tonic-gate fco_validate(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
769*0Sstevel@tonic-gate {
770*0Sstevel@tonic-gate rp->cdip_state = FC_CDIP_CONFIG;
771*0Sstevel@tonic-gate
772*0Sstevel@tonic-gate cp->nresults = fc_int2cell(0);
773*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
774*0Sstevel@tonic-gate }
775*0Sstevel@tonic-gate
776*0Sstevel@tonic-gate static void
remove_subtree(dev_info_t * root,struct fc_device_tree * subtree)777*0Sstevel@tonic-gate remove_subtree(dev_info_t *root, struct fc_device_tree *subtree)
778*0Sstevel@tonic-gate {
779*0Sstevel@tonic-gate dev_info_t *child;
780*0Sstevel@tonic-gate
781*0Sstevel@tonic-gate /*
782*0Sstevel@tonic-gate * Remove the subtree, depth first. Each iterative
783*0Sstevel@tonic-gate * call gets another child at each level of the tree
784*0Sstevel@tonic-gate * until there are no more children.
785*0Sstevel@tonic-gate */
786*0Sstevel@tonic-gate while ((child = fc_child_node(root, subtree)) != NULL)
787*0Sstevel@tonic-gate remove_subtree(child, subtree);
788*0Sstevel@tonic-gate
789*0Sstevel@tonic-gate /*
790*0Sstevel@tonic-gate * Delete the subtree root and remove its record from our
791*0Sstevel@tonic-gate * copy of the subtree.
792*0Sstevel@tonic-gate */
793*0Sstevel@tonic-gate fc_remove_child(root, subtree);
794*0Sstevel@tonic-gate (void) ndi_devi_offline(root, NDI_UNCONFIG | NDI_DEVI_REMOVE);
795*0Sstevel@tonic-gate }
796*0Sstevel@tonic-gate
797*0Sstevel@tonic-gate static int
fco_invalidate(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)798*0Sstevel@tonic-gate fco_invalidate(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
799*0Sstevel@tonic-gate {
800*0Sstevel@tonic-gate dev_info_t *root, *child;
801*0Sstevel@tonic-gate struct fc_device_tree *subtree = fc_handle_to_dtree(rp);
802*0Sstevel@tonic-gate int configured = (rp->cdip_state == FC_CDIP_CONFIG);
803*0Sstevel@tonic-gate
804*0Sstevel@tonic-gate /*
805*0Sstevel@tonic-gate * If we created any children, delete them. The root node is the
806*0Sstevel@tonic-gate * config child, if one exists for this bus, otherwise it's the
807*0Sstevel@tonic-gate * attachment point.
808*0Sstevel@tonic-gate *
809*0Sstevel@tonic-gate * Our copy of the subtree only contains records of nodes we created
810*0Sstevel@tonic-gate * under the subtree root and contains the parent->child linkage
811*0Sstevel@tonic-gate * that isn't yet established in the real device tree.
812*0Sstevel@tonic-gate *
813*0Sstevel@tonic-gate * XXX: What we don't do is restore the config child node to it's
814*0Sstevel@tonic-gate * pre-interpretive state. (We may have added properties to
815*0Sstevel@tonic-gate * that node. It's not clear if its necessary to clean them up.)
816*0Sstevel@tonic-gate */
817*0Sstevel@tonic-gate root = rp->child ? rp->child : ap;
818*0Sstevel@tonic-gate
819*0Sstevel@tonic-gate while ((child = fc_child_node(root, subtree)) != NULL) {
820*0Sstevel@tonic-gate FC_DEBUG2(1, CE_CONT, "fco_invalidate: remove subtree "
821*0Sstevel@tonic-gate "<%s> dip %p\n", ddi_node_name(child), child);
822*0Sstevel@tonic-gate remove_subtree(child, subtree);
823*0Sstevel@tonic-gate }
824*0Sstevel@tonic-gate
825*0Sstevel@tonic-gate if (configured)
826*0Sstevel@tonic-gate (void) ndi_devi_offline(root, NDI_UNCONFIG);
827*0Sstevel@tonic-gate
828*0Sstevel@tonic-gate cp->nresults = fc_int2cell(0);
829*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
830*0Sstevel@tonic-gate }
831*0Sstevel@tonic-gate
832*0Sstevel@tonic-gate static int
fco_exit(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)833*0Sstevel@tonic-gate fco_exit(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
834*0Sstevel@tonic-gate {
835*0Sstevel@tonic-gate FC_DEBUG0(1, CE_CONT, "exit op not implemented .. succeeding\n");
836*0Sstevel@tonic-gate cp->nresults = fc_int2cell(0);
837*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
838*0Sstevel@tonic-gate }
839*0Sstevel@tonic-gate
840*0Sstevel@tonic-gate /*
841*0Sstevel@tonic-gate * Needed to implement 'mac-address' Fcode, no obvious place to pick this
842*0Sstevel@tonic-gate * info up from user-land.
843*0Sstevel@tonic-gate */
844*0Sstevel@tonic-gate static int
fco_local_ether_addr(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)845*0Sstevel@tonic-gate fco_local_ether_addr(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
846*0Sstevel@tonic-gate {
847*0Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 0)
848*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 0"));
849*0Sstevel@tonic-gate
850*0Sstevel@tonic-gate if (fc_cell2int(cp->nresults) != 2)
851*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be 2"));
852*0Sstevel@tonic-gate
853*0Sstevel@tonic-gate cp->nresults = fc_int2cell(2);
854*0Sstevel@tonic-gate
855*0Sstevel@tonic-gate (void) localetheraddr(NULL, (struct ether_addr *)(&fc_result(cp, 0)));
856*0Sstevel@tonic-gate
857*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
858*0Sstevel@tonic-gate }
859*0Sstevel@tonic-gate
860*0Sstevel@tonic-gate #ifdef DEBUG
861*0Sstevel@tonic-gate void
fc_debug(char * fmt,uintptr_t a1,uintptr_t a2,uintptr_t a3,uintptr_t a4,uintptr_t a5)862*0Sstevel@tonic-gate fc_debug(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3,
863*0Sstevel@tonic-gate uintptr_t a4, uintptr_t a5)
864*0Sstevel@tonic-gate {
865*0Sstevel@tonic-gate cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5);
866*0Sstevel@tonic-gate }
867*0Sstevel@tonic-gate #endif
868