17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate * with the License.
87c478bd9Sstevel@tonic-gate *
97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate * and limitations under the License.
137c478bd9Sstevel@tonic-gate *
147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate *
207c478bd9Sstevel@tonic-gate * CDDL HEADER END
217c478bd9Sstevel@tonic-gate */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate * Copyright 2000, 2002 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
25*48bbca81SDaniel Hoffman * Copyright (c) 2016 by Delphix. All rights reserved.
267c478bd9Sstevel@tonic-gate */
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate * fc_ops.c: Framework generic fcode ops
327c478bd9Sstevel@tonic-gate */
337c478bd9Sstevel@tonic-gate #include <sys/types.h>
347c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
357c478bd9Sstevel@tonic-gate #include <sys/systm.h>
367c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
377c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
387c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
397c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
407c478bd9Sstevel@tonic-gate #include <sys/fcode.h>
417c478bd9Sstevel@tonic-gate #include <sys/ddi_implfuncs.h>
427c478bd9Sstevel@tonic-gate #include <sys/ndi_impldefs.h>
437c478bd9Sstevel@tonic-gate #include <sys/ethernet.h>
447c478bd9Sstevel@tonic-gate
457c478bd9Sstevel@tonic-gate static int fco_new_device(dev_info_t *, fco_handle_t, fc_ci_t *);
467c478bd9Sstevel@tonic-gate static int fco_finish_device(dev_info_t *, fco_handle_t, fc_ci_t *);
477c478bd9Sstevel@tonic-gate static int fco_create_property(dev_info_t *, fco_handle_t, fc_ci_t *);
487c478bd9Sstevel@tonic-gate
497c478bd9Sstevel@tonic-gate static int fco_validate(dev_info_t *, fco_handle_t, fc_ci_t *);
507c478bd9Sstevel@tonic-gate static int fco_invalidate(dev_info_t *, fco_handle_t, fc_ci_t *);
517c478bd9Sstevel@tonic-gate static int fco_exit(dev_info_t *, fco_handle_t, fc_ci_t *);
527c478bd9Sstevel@tonic-gate
537c478bd9Sstevel@tonic-gate static int fco_getproplen(dev_info_t *, fco_handle_t, fc_ci_t *);
547c478bd9Sstevel@tonic-gate static int fco_getprop(dev_info_t *, fco_handle_t, fc_ci_t *);
557c478bd9Sstevel@tonic-gate
567c478bd9Sstevel@tonic-gate static int fco_ap_phandle(dev_info_t *, fco_handle_t, fc_ci_t *);
577c478bd9Sstevel@tonic-gate static int fco_child(dev_info_t *, fco_handle_t, fc_ci_t *);
587c478bd9Sstevel@tonic-gate static int fco_peer(dev_info_t *, fco_handle_t, fc_ci_t *);
597c478bd9Sstevel@tonic-gate static int fco_parent(dev_info_t *, fco_handle_t, fc_ci_t *);
607c478bd9Sstevel@tonic-gate static int fco_alloc_phandle(dev_info_t *, fco_handle_t, fc_ci_t *);
617c478bd9Sstevel@tonic-gate
627c478bd9Sstevel@tonic-gate static int fco_local_ether_addr(dev_info_t *, fco_handle_t, fc_ci_t *);
637c478bd9Sstevel@tonic-gate
647c478bd9Sstevel@tonic-gate struct fc_ops_v {
657c478bd9Sstevel@tonic-gate char *svc_name;
667c478bd9Sstevel@tonic-gate fc_ops_t *f;
677c478bd9Sstevel@tonic-gate };
687c478bd9Sstevel@tonic-gate
697c478bd9Sstevel@tonic-gate static struct fc_ops_v fov[] = {
707c478bd9Sstevel@tonic-gate { "open", fc_fail_op},
717c478bd9Sstevel@tonic-gate { "close", fc_fail_op},
727c478bd9Sstevel@tonic-gate { "$find", fc_fail_op},
737c478bd9Sstevel@tonic-gate { "encode-unit", fc_fail_op},
747c478bd9Sstevel@tonic-gate { "decode-unit", fc_fail_op},
757c478bd9Sstevel@tonic-gate { FC_GET_MY_PROPLEN, fco_getproplen},
767c478bd9Sstevel@tonic-gate { FC_GET_MY_PROP, fco_getprop},
777c478bd9Sstevel@tonic-gate { FC_GET_PKG_PROPLEN, fco_getproplen},
787c478bd9Sstevel@tonic-gate { FC_GET_PKG_PROP, fco_getprop},
797c478bd9Sstevel@tonic-gate { FC_GET_IN_PROPLEN, fco_getproplen},
807c478bd9Sstevel@tonic-gate { FC_GET_IN_PROP, fco_getprop},
817c478bd9Sstevel@tonic-gate { FC_NEW_DEVICE, fco_new_device},
827c478bd9Sstevel@tonic-gate { FC_FINISH_DEVICE, fco_finish_device},
837c478bd9Sstevel@tonic-gate { FC_CREATE_PROPERTY, fco_create_property},
847c478bd9Sstevel@tonic-gate { FC_AP_PHANDLE, fco_ap_phandle},
857c478bd9Sstevel@tonic-gate { "child", fco_child},
867c478bd9Sstevel@tonic-gate { "peer", fco_peer},
877c478bd9Sstevel@tonic-gate { FC_PARENT, fco_parent},
887c478bd9Sstevel@tonic-gate { FC_ALLOC_PHANDLE, fco_alloc_phandle},
897c478bd9Sstevel@tonic-gate { FC_SVC_VALIDATE, fco_validate},
907c478bd9Sstevel@tonic-gate { FC_SVC_INVALIDATE, fco_invalidate},
917c478bd9Sstevel@tonic-gate { FC_SVC_EXIT, fco_exit},
927c478bd9Sstevel@tonic-gate { "local-ether-addr", fco_local_ether_addr},
937c478bd9Sstevel@tonic-gate { NULL, NULL}
947c478bd9Sstevel@tonic-gate };
957c478bd9Sstevel@tonic-gate
967c478bd9Sstevel@tonic-gate /*
977c478bd9Sstevel@tonic-gate * Allocate a handle for the ops function .. our handle is a resource list
98*48bbca81SDaniel Hoffman * Return the handle to our caller, so it can call us with it when we need it.
997c478bd9Sstevel@tonic-gate */
1007c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1017c478bd9Sstevel@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)1027c478bd9Sstevel@tonic-gate fc_ops_alloc_handle(dev_info_t *ap, dev_info_t *child,
1037c478bd9Sstevel@tonic-gate void *fcode, size_t fcode_size, char *unit_address, void *bus_args)
1047c478bd9Sstevel@tonic-gate {
1057c478bd9Sstevel@tonic-gate fco_handle_t rp;
1067c478bd9Sstevel@tonic-gate char *up;
1077c478bd9Sstevel@tonic-gate
1087c478bd9Sstevel@tonic-gate rp = kmem_zalloc(sizeof (struct fc_resource_list), KM_SLEEP);
1097c478bd9Sstevel@tonic-gate rp->next_handle = NULL; /* nobody is downstream */
1107c478bd9Sstevel@tonic-gate rp->ap = ap;
1117c478bd9Sstevel@tonic-gate rp->child = child;
1127c478bd9Sstevel@tonic-gate rp->fcode = fcode;
1137c478bd9Sstevel@tonic-gate rp->fcode_size = fcode_size;
1147c478bd9Sstevel@tonic-gate if (unit_address) {
1157c478bd9Sstevel@tonic-gate up = kmem_zalloc(strlen(unit_address) + 1, KM_SLEEP);
1167c478bd9Sstevel@tonic-gate (void) strcpy(up, unit_address);
1177c478bd9Sstevel@tonic-gate rp->unit_address = up;
1187c478bd9Sstevel@tonic-gate }
1197c478bd9Sstevel@tonic-gate rp->bus_args = NULL; /* generic module has no bus args */
1207c478bd9Sstevel@tonic-gate fc_phandle_table_alloc(fc_handle_to_phandle_head(rp));
1217c478bd9Sstevel@tonic-gate
1227c478bd9Sstevel@tonic-gate (void) fc_dip_to_phandle(fc_handle_to_phandle_head(rp), ap);
1237c478bd9Sstevel@tonic-gate
1247c478bd9Sstevel@tonic-gate /*
1257c478bd9Sstevel@tonic-gate * Create our copy of the device tree.
1267c478bd9Sstevel@tonic-gate */
1277c478bd9Sstevel@tonic-gate fc_create_device_tree(ap, &rp->dtree);
1287c478bd9Sstevel@tonic-gate return (rp);
1297c478bd9Sstevel@tonic-gate }
1307c478bd9Sstevel@tonic-gate
1317c478bd9Sstevel@tonic-gate /*
1327c478bd9Sstevel@tonic-gate * Free any resources associated with this handle.
1337c478bd9Sstevel@tonic-gate */
1347c478bd9Sstevel@tonic-gate void
fc_ops_free_handle(fco_handle_t rp)1357c478bd9Sstevel@tonic-gate fc_ops_free_handle(fco_handle_t rp)
1367c478bd9Sstevel@tonic-gate {
1377c478bd9Sstevel@tonic-gate struct fc_resource *ip, *np;
1387c478bd9Sstevel@tonic-gate
1397c478bd9Sstevel@tonic-gate if (rp->unit_address)
1407c478bd9Sstevel@tonic-gate kmem_free(rp->unit_address, strlen(rp->unit_address) + 1);
1417c478bd9Sstevel@tonic-gate
1427c478bd9Sstevel@tonic-gate if (rp->dtree)
1437c478bd9Sstevel@tonic-gate fc_remove_device_tree(&rp->dtree);
1447c478bd9Sstevel@tonic-gate
1457c478bd9Sstevel@tonic-gate fc_phandle_table_free(fc_handle_to_phandle_head(rp));
1467c478bd9Sstevel@tonic-gate
1477c478bd9Sstevel@tonic-gate for (ip = rp->head; ip != NULL; ip = np) {
1487c478bd9Sstevel@tonic-gate np = ip->next;
1497c478bd9Sstevel@tonic-gate switch (ip->type) {
1507c478bd9Sstevel@tonic-gate case RT_NODEID:
1517c478bd9Sstevel@tonic-gate impl_ddi_free_nodeid(ip->fc_nodeid_r);
1527c478bd9Sstevel@tonic-gate break;
1537c478bd9Sstevel@tonic-gate default:
1547c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pci_fc_ops_free: "
1557c478bd9Sstevel@tonic-gate "unknown resource type %d\n", ip->type);
1567c478bd9Sstevel@tonic-gate break;
1577c478bd9Sstevel@tonic-gate }
1587c478bd9Sstevel@tonic-gate fc_rem_resource(rp, ip);
1597c478bd9Sstevel@tonic-gate kmem_free(ip, sizeof (struct fc_resource));
1607c478bd9Sstevel@tonic-gate }
1617c478bd9Sstevel@tonic-gate kmem_free(rp, sizeof (struct fc_resource_list));
1627c478bd9Sstevel@tonic-gate }
1637c478bd9Sstevel@tonic-gate
1647c478bd9Sstevel@tonic-gate int
fc_ops(dev_info_t * ap,fco_handle_t handle,fc_ci_t * cp)1657c478bd9Sstevel@tonic-gate fc_ops(dev_info_t *ap, fco_handle_t handle, fc_ci_t *cp)
1667c478bd9Sstevel@tonic-gate {
1677c478bd9Sstevel@tonic-gate struct fc_ops_v *pv;
1687c478bd9Sstevel@tonic-gate char *name = fc_cell2ptr(cp->svc_name);
1697c478bd9Sstevel@tonic-gate
1707c478bd9Sstevel@tonic-gate for (pv = fov; pv->svc_name != NULL; ++pv)
1717c478bd9Sstevel@tonic-gate if (strcmp(pv->svc_name, name) == 0)
1727c478bd9Sstevel@tonic-gate return (pv->f(ap, handle, cp));
1737c478bd9Sstevel@tonic-gate
1747c478bd9Sstevel@tonic-gate return (-1);
1757c478bd9Sstevel@tonic-gate }
1767c478bd9Sstevel@tonic-gate
1777c478bd9Sstevel@tonic-gate /*
1787c478bd9Sstevel@tonic-gate * The interpreter can't do get-inherited-property directly,
1797c478bd9Sstevel@tonic-gate * because we don't want to return a kernel address, so it
1807c478bd9Sstevel@tonic-gate * has to break up the request into a get-proplen and get-prop
1817c478bd9Sstevel@tonic-gate * call so it can allocate memory for the property and pass that
1827c478bd9Sstevel@tonic-gate * buffer in to get-prop. The buffer should be 'suitably aligned'.
1837c478bd9Sstevel@tonic-gate *
1847c478bd9Sstevel@tonic-gate * XXX: We don't know the property type, so we can't return
1857c478bd9Sstevel@tonic-gate * prop-encoded arrays, which fortunately, isn't a problem
1867c478bd9Sstevel@tonic-gate * on big-endian machines.
1877c478bd9Sstevel@tonic-gate *
1887c478bd9Sstevel@tonic-gate * get-proplen has one result: proplen
1897c478bd9Sstevel@tonic-gate * proplen is returned as -1 if the propname doesn't exist and
1907c478bd9Sstevel@tonic-gate * as zero if the property is a boolean property.
1917c478bd9Sstevel@tonic-gate *
1927c478bd9Sstevel@tonic-gate * get-prop has one result: proplen, returned as -1 if propname doesn't exist.
1937c478bd9Sstevel@tonic-gate */
1947c478bd9Sstevel@tonic-gate
1957c478bd9Sstevel@tonic-gate /*
1967c478bd9Sstevel@tonic-gate * fco_getproplen ( propname phandle -- proplen )
1977c478bd9Sstevel@tonic-gate */
1987c478bd9Sstevel@tonic-gate
1997c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2007c478bd9Sstevel@tonic-gate static int
fco_getproplen(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)2017c478bd9Sstevel@tonic-gate fco_getproplen(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
2027c478bd9Sstevel@tonic-gate {
2037c478bd9Sstevel@tonic-gate int proplen;
2047c478bd9Sstevel@tonic-gate int flags = 0;
2057c478bd9Sstevel@tonic-gate fc_phandle_t h;
2067c478bd9Sstevel@tonic-gate dev_info_t *dip;
2077c478bd9Sstevel@tonic-gate char *pnp;
2087c478bd9Sstevel@tonic-gate char propname[OBP_MAXPROPNAME];
2097c478bd9Sstevel@tonic-gate
2107c478bd9Sstevel@tonic-gate if (strstr(fc_cell2ptr(cp->svc_name), "inherited") == NULL)
2117c478bd9Sstevel@tonic-gate flags |= DDI_PROP_DONTPASS;
2127c478bd9Sstevel@tonic-gate
2137c478bd9Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 2)
2147c478bd9Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 2"));
2157c478bd9Sstevel@tonic-gate
2167c478bd9Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1)
2177c478bd9Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be > 0"));
2187c478bd9Sstevel@tonic-gate
2197c478bd9Sstevel@tonic-gate /*
2207c478bd9Sstevel@tonic-gate * Make sure this is a handle we gave out ...
2217c478bd9Sstevel@tonic-gate */
2227c478bd9Sstevel@tonic-gate h = fc_cell2phandle(fc_arg(cp, 0));
2237c478bd9Sstevel@tonic-gate if ((dip = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), h)) == NULL)
2247c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "unknown handle"));
2257c478bd9Sstevel@tonic-gate
2267c478bd9Sstevel@tonic-gate /*
2277c478bd9Sstevel@tonic-gate * XXX: We should care if the string is longer than OBP_MAXPROPNAME
2287c478bd9Sstevel@tonic-gate */
2297c478bd9Sstevel@tonic-gate pnp = fc_cell2ptr(fc_arg(cp, 1));
2307c478bd9Sstevel@tonic-gate bzero(propname, OBP_MAXPROPNAME);
2317c478bd9Sstevel@tonic-gate if (copyinstr(pnp, propname, OBP_MAXPROPNAME - 1, NULL))
2327c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "EFAULT copying in propname"));
2337c478bd9Sstevel@tonic-gate
2347c478bd9Sstevel@tonic-gate if (ddi_getproplen(DDI_DEV_T_ANY, dip, flags, propname, &proplen))
2357c478bd9Sstevel@tonic-gate proplen = -1;
2367c478bd9Sstevel@tonic-gate
2377c478bd9Sstevel@tonic-gate fc_result(cp, 0) = fc_int2cell(proplen);
2387c478bd9Sstevel@tonic-gate cp->nresults = fc_int2cell(1);
2397c478bd9Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
2407c478bd9Sstevel@tonic-gate }
2417c478bd9Sstevel@tonic-gate
2427c478bd9Sstevel@tonic-gate /*
2437c478bd9Sstevel@tonic-gate * fco_getprop ( propname buffer phandle -- proplen )
2447c478bd9Sstevel@tonic-gate */
2457c478bd9Sstevel@tonic-gate
2467c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2477c478bd9Sstevel@tonic-gate static int
fco_getprop(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)2487c478bd9Sstevel@tonic-gate fco_getprop(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
2497c478bd9Sstevel@tonic-gate {
2507c478bd9Sstevel@tonic-gate int proplen = -1;
2517c478bd9Sstevel@tonic-gate int flags = DDI_PROP_CANSLEEP;
2527c478bd9Sstevel@tonic-gate char *pnp, *bp;
2537c478bd9Sstevel@tonic-gate fc_phandle_t h;
2547c478bd9Sstevel@tonic-gate dev_info_t *dip;
2557c478bd9Sstevel@tonic-gate char propname[OBP_MAXPROPNAME];
2567c478bd9Sstevel@tonic-gate
2577c478bd9Sstevel@tonic-gate if (strstr(fc_cell2ptr(cp->svc_name), "inherited") == NULL)
2587c478bd9Sstevel@tonic-gate flags |= DDI_PROP_DONTPASS;
2597c478bd9Sstevel@tonic-gate
2607c478bd9Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 3)
2617c478bd9Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 3"));
2627c478bd9Sstevel@tonic-gate
2637c478bd9Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1)
2647c478bd9Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be > 0"));
2657c478bd9Sstevel@tonic-gate
2667c478bd9Sstevel@tonic-gate /*
2677c478bd9Sstevel@tonic-gate * Make sure this is a handle we gave out ...
2687c478bd9Sstevel@tonic-gate */
2697c478bd9Sstevel@tonic-gate h = fc_cell2phandle(fc_arg(cp, 0));
2707c478bd9Sstevel@tonic-gate if ((dip = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), h)) == NULL)
2717c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "unknown handle"));
2727c478bd9Sstevel@tonic-gate
2737c478bd9Sstevel@tonic-gate /*
2747c478bd9Sstevel@tonic-gate * XXX: We should care if the string is longer than OBP_MAXPROPNAME
2757c478bd9Sstevel@tonic-gate */
2767c478bd9Sstevel@tonic-gate pnp = fc_cell2ptr(fc_arg(cp, 2));
2777c478bd9Sstevel@tonic-gate bzero(propname, OBP_MAXPROPNAME);
2787c478bd9Sstevel@tonic-gate if (copyinstr(pnp, propname, OBP_MAXPROPNAME - 1, NULL))
2797c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "EFAULT copying in propname"));
2807c478bd9Sstevel@tonic-gate
2817c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, dip, flags,
2827c478bd9Sstevel@tonic-gate propname, (caddr_t)&bp, &proplen))
2837c478bd9Sstevel@tonic-gate proplen = -1;
2847c478bd9Sstevel@tonic-gate
2857c478bd9Sstevel@tonic-gate if (proplen > 0) {
2867c478bd9Sstevel@tonic-gate char *up = fc_cell2ptr(fc_arg(cp, 1));
2877c478bd9Sstevel@tonic-gate int error;
2887c478bd9Sstevel@tonic-gate
2897c478bd9Sstevel@tonic-gate error = copyout(bp, up, proplen);
2907c478bd9Sstevel@tonic-gate kmem_free(bp, proplen);
2917c478bd9Sstevel@tonic-gate if (error)
2927c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "EFAULT copying data out"));
2937c478bd9Sstevel@tonic-gate }
2947c478bd9Sstevel@tonic-gate
2957c478bd9Sstevel@tonic-gate cp->nresults = fc_int2cell(1);
2967c478bd9Sstevel@tonic-gate fc_result(cp, 0) = fc_int2cell(proplen);
2977c478bd9Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
2987c478bd9Sstevel@tonic-gate }
2997c478bd9Sstevel@tonic-gate
3007c478bd9Sstevel@tonic-gate static int
fco_ap_phandle(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)3017c478bd9Sstevel@tonic-gate fco_ap_phandle(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
3027c478bd9Sstevel@tonic-gate {
3037c478bd9Sstevel@tonic-gate fc_phandle_t h;
3047c478bd9Sstevel@tonic-gate
3057c478bd9Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 0)
3067c478bd9Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 0"));
3077c478bd9Sstevel@tonic-gate
3087c478bd9Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1)
3097c478bd9Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be > 0"));
3107c478bd9Sstevel@tonic-gate
3117c478bd9Sstevel@tonic-gate FC_DEBUG1(9, CE_CONT, "fco_ap_phandle: Looking up ap dip %p\n", ap);
3127c478bd9Sstevel@tonic-gate
3137c478bd9Sstevel@tonic-gate h = fc_dip_to_phandle(fc_handle_to_phandle_head(rp), ap);
3147c478bd9Sstevel@tonic-gate cp->nresults = fc_int2cell(1);
3157c478bd9Sstevel@tonic-gate fc_result(cp, 0) = fc_phandle2cell(h);
3167c478bd9Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
3177c478bd9Sstevel@tonic-gate }
3187c478bd9Sstevel@tonic-gate
3197c478bd9Sstevel@tonic-gate static int
fco_child(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)3207c478bd9Sstevel@tonic-gate fco_child(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
3217c478bd9Sstevel@tonic-gate {
3227c478bd9Sstevel@tonic-gate fc_phandle_t h;
3237c478bd9Sstevel@tonic-gate dev_info_t *dip;
3247c478bd9Sstevel@tonic-gate
3257c478bd9Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 1)
3267c478bd9Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 1"));
3277c478bd9Sstevel@tonic-gate
3287c478bd9Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1)
3297c478bd9Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be > 0"));
3307c478bd9Sstevel@tonic-gate
3317c478bd9Sstevel@tonic-gate /*
3327c478bd9Sstevel@tonic-gate * Make sure this is a handle we gave out ...
3337c478bd9Sstevel@tonic-gate */
3347c478bd9Sstevel@tonic-gate h = fc_cell2phandle(fc_arg(cp, 0));
3357c478bd9Sstevel@tonic-gate if ((dip = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), h)) == NULL)
3367c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "unknown handle"));
3377c478bd9Sstevel@tonic-gate
3387c478bd9Sstevel@tonic-gate /*
3397c478bd9Sstevel@tonic-gate * Find the child and if there is one, return it ...
3407c478bd9Sstevel@tonic-gate */
3417c478bd9Sstevel@tonic-gate dip = ddi_get_child(dip);
3427c478bd9Sstevel@tonic-gate h = 0;
3437c478bd9Sstevel@tonic-gate if (dip != NULL)
3447c478bd9Sstevel@tonic-gate h = fc_dip_to_phandle(fc_handle_to_phandle_head(rp), dip);
3457c478bd9Sstevel@tonic-gate
3467c478bd9Sstevel@tonic-gate cp->nresults = fc_int2cell(1);
3477c478bd9Sstevel@tonic-gate fc_result(cp, 0) = fc_phandle2cell(h);
3487c478bd9Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
3497c478bd9Sstevel@tonic-gate }
3507c478bd9Sstevel@tonic-gate
3517c478bd9Sstevel@tonic-gate static int
fco_peer(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)3527c478bd9Sstevel@tonic-gate fco_peer(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
3537c478bd9Sstevel@tonic-gate {
3547c478bd9Sstevel@tonic-gate fc_phandle_t h;
3557c478bd9Sstevel@tonic-gate dev_info_t *dip;
3567c478bd9Sstevel@tonic-gate
3577c478bd9Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 1)
3587c478bd9Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 1"));
3597c478bd9Sstevel@tonic-gate
3607c478bd9Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1)
3617c478bd9Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be > 0"));
3627c478bd9Sstevel@tonic-gate
3637c478bd9Sstevel@tonic-gate /*
3647c478bd9Sstevel@tonic-gate * Make sure this is a handle we gave out ...
3657c478bd9Sstevel@tonic-gate */
3667c478bd9Sstevel@tonic-gate h = fc_cell2phandle(fc_arg(cp, 0));
3677c478bd9Sstevel@tonic-gate if ((dip = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), h)) == NULL)
3687c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "unknown handle"));
3697c478bd9Sstevel@tonic-gate
3707c478bd9Sstevel@tonic-gate /*
3717c478bd9Sstevel@tonic-gate * Find the child and if there is one, return it ...
3727c478bd9Sstevel@tonic-gate */
3737c478bd9Sstevel@tonic-gate dip = ddi_get_next_sibling(dip);
3747c478bd9Sstevel@tonic-gate h = 0;
3757c478bd9Sstevel@tonic-gate if (dip != NULL)
3767c478bd9Sstevel@tonic-gate h = fc_dip_to_phandle(fc_handle_to_phandle_head(rp), dip);
3777c478bd9Sstevel@tonic-gate
3787c478bd9Sstevel@tonic-gate cp->nresults = fc_int2cell(1);
3797c478bd9Sstevel@tonic-gate fc_result(cp, 0) = fc_phandle2cell(h);
3807c478bd9Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
3817c478bd9Sstevel@tonic-gate }
3827c478bd9Sstevel@tonic-gate
3837c478bd9Sstevel@tonic-gate static int
fco_parent(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)3847c478bd9Sstevel@tonic-gate fco_parent(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
3857c478bd9Sstevel@tonic-gate {
3867c478bd9Sstevel@tonic-gate fc_phandle_t h;
3877c478bd9Sstevel@tonic-gate dev_info_t *dip;
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 1)
3907c478bd9Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 1"));
3917c478bd9Sstevel@tonic-gate
3927c478bd9Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1)
3937c478bd9Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be > 0"));
3947c478bd9Sstevel@tonic-gate
3957c478bd9Sstevel@tonic-gate /*
3967c478bd9Sstevel@tonic-gate * Make sure this is a handle we gave out ...
3977c478bd9Sstevel@tonic-gate */
3987c478bd9Sstevel@tonic-gate h = fc_cell2phandle(fc_arg(cp, 0));
3997c478bd9Sstevel@tonic-gate if ((dip = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), h)) == NULL)
4007c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "unknown handle"));
4017c478bd9Sstevel@tonic-gate
4027c478bd9Sstevel@tonic-gate /*
4037c478bd9Sstevel@tonic-gate * Find the parent and if there is one, return it ...
4047c478bd9Sstevel@tonic-gate */
4057c478bd9Sstevel@tonic-gate dip = ddi_get_parent(dip);
4067c478bd9Sstevel@tonic-gate h = 0;
4077c478bd9Sstevel@tonic-gate if (dip != NULL)
4087c478bd9Sstevel@tonic-gate h = fc_dip_to_phandle(fc_handle_to_phandle_head(rp), dip);
4097c478bd9Sstevel@tonic-gate
4107c478bd9Sstevel@tonic-gate cp->nresults = fc_int2cell(1);
4117c478bd9Sstevel@tonic-gate fc_result(cp, 0) = fc_phandle2cell(h);
4127c478bd9Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
4137c478bd9Sstevel@tonic-gate }
4147c478bd9Sstevel@tonic-gate
4157c478bd9Sstevel@tonic-gate /*
4167c478bd9Sstevel@tonic-gate * Allocate a phandle ... we don't currently track the phandle.
4177c478bd9Sstevel@tonic-gate */
4187c478bd9Sstevel@tonic-gate static int
fco_alloc_phandle(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)4197c478bd9Sstevel@tonic-gate fco_alloc_phandle(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
4207c478bd9Sstevel@tonic-gate {
4217c478bd9Sstevel@tonic-gate fc_phandle_t h;
4227c478bd9Sstevel@tonic-gate int n;
4237c478bd9Sstevel@tonic-gate struct fc_resource *ip;
4247c478bd9Sstevel@tonic-gate
4257c478bd9Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 0)
4267c478bd9Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 0"));
4277c478bd9Sstevel@tonic-gate
4287c478bd9Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1)
4297c478bd9Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be > 0"));
4307c478bd9Sstevel@tonic-gate
4317c478bd9Sstevel@tonic-gate if (impl_ddi_alloc_nodeid(&n))
4327c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "Can't allocate a nodeid"));
4337c478bd9Sstevel@tonic-gate
4347c478bd9Sstevel@tonic-gate /*
4357c478bd9Sstevel@tonic-gate * Log the nodeid resource so we can release it later if we need to.
4367c478bd9Sstevel@tonic-gate */
4377c478bd9Sstevel@tonic-gate ip = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP);
4387c478bd9Sstevel@tonic-gate ip->type = RT_NODEID;
4397c478bd9Sstevel@tonic-gate ip->fc_nodeid_r = n;
4407c478bd9Sstevel@tonic-gate fc_add_resource(rp, ip);
4417c478bd9Sstevel@tonic-gate
4427c478bd9Sstevel@tonic-gate h = (fc_phandle_t)n;
4437c478bd9Sstevel@tonic-gate
4447c478bd9Sstevel@tonic-gate cp->nresults = fc_int2cell(1);
4457c478bd9Sstevel@tonic-gate fc_result(cp, 0) = fc_phandle2cell(h);
4467c478bd9Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
4477c478bd9Sstevel@tonic-gate }
4487c478bd9Sstevel@tonic-gate
4497c478bd9Sstevel@tonic-gate static struct fc_resource *
find_nodeid_resource(fco_handle_t rp,int n)4507c478bd9Sstevel@tonic-gate find_nodeid_resource(fco_handle_t rp, int n)
4517c478bd9Sstevel@tonic-gate {
4527c478bd9Sstevel@tonic-gate struct fc_resource *ip;
4537c478bd9Sstevel@tonic-gate
4547c478bd9Sstevel@tonic-gate fc_lock_resource_list(rp);
4557c478bd9Sstevel@tonic-gate for (ip = rp->head; ip != NULL; ip = ip->next) {
4567c478bd9Sstevel@tonic-gate if (ip->type != RT_NODEID)
4577c478bd9Sstevel@tonic-gate continue;
4587c478bd9Sstevel@tonic-gate if (ip->fc_nodeid_r == n)
4597c478bd9Sstevel@tonic-gate break;
4607c478bd9Sstevel@tonic-gate }
4617c478bd9Sstevel@tonic-gate fc_unlock_resource_list(rp);
4627c478bd9Sstevel@tonic-gate
4637c478bd9Sstevel@tonic-gate return (ip);
4647c478bd9Sstevel@tonic-gate }
4657c478bd9Sstevel@tonic-gate
4667c478bd9Sstevel@tonic-gate /*
4677c478bd9Sstevel@tonic-gate * fco_new_device ( name-cstr unit-addr-cstr parent.phandle phandle -- )
4687c478bd9Sstevel@tonic-gate */
4697c478bd9Sstevel@tonic-gate static int
fco_new_device(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)4707c478bd9Sstevel@tonic-gate fco_new_device(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
4717c478bd9Sstevel@tonic-gate {
4727c478bd9Sstevel@tonic-gate fc_phandle_t ph, ch;
4737c478bd9Sstevel@tonic-gate dev_info_t *pdev, *cdev;
4747c478bd9Sstevel@tonic-gate char *s;
4757c478bd9Sstevel@tonic-gate int createmode = 0;
4767c478bd9Sstevel@tonic-gate char *unit_address = NULL;
4777c478bd9Sstevel@tonic-gate char nodename[OBP_MAXPROPNAME];
4787c478bd9Sstevel@tonic-gate
4797c478bd9Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 4)
4807c478bd9Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 4"));
4817c478bd9Sstevel@tonic-gate
4827c478bd9Sstevel@tonic-gate /*
4837c478bd9Sstevel@tonic-gate * Make sure these are handles we gave out ... and we have
4847c478bd9Sstevel@tonic-gate * a corresponding parent devinfo node.
4857c478bd9Sstevel@tonic-gate */
4867c478bd9Sstevel@tonic-gate ph = fc_cell2phandle(fc_arg(cp, 1));
4877c478bd9Sstevel@tonic-gate pdev = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), ph);
4887c478bd9Sstevel@tonic-gate if (pdev == NULL)
4897c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "unknown parent phandle"));
4907c478bd9Sstevel@tonic-gate
4917c478bd9Sstevel@tonic-gate ch = fc_cell2phandle(fc_arg(cp, 0));
4927c478bd9Sstevel@tonic-gate cdev = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), ch);
4937c478bd9Sstevel@tonic-gate
4947c478bd9Sstevel@tonic-gate switch (rp->cdip_state) {
4957c478bd9Sstevel@tonic-gate
4967c478bd9Sstevel@tonic-gate case FC_CDIP_NOSTATE:
4977c478bd9Sstevel@tonic-gate /*
4987c478bd9Sstevel@tonic-gate * The first child must be a child of the attachment point.
4997c478bd9Sstevel@tonic-gate */
5007c478bd9Sstevel@tonic-gate if (pdev != ap)
5017c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "first child must be a "
5027c478bd9Sstevel@tonic-gate "child of the attachment point"));
5037c478bd9Sstevel@tonic-gate
5047c478bd9Sstevel@tonic-gate /*
5057c478bd9Sstevel@tonic-gate * If this bus has a config child, the first child must
5067c478bd9Sstevel@tonic-gate * be the configuration child. Otherwise, the child must
5077c478bd9Sstevel@tonic-gate * be a new (unknown) node.
5087c478bd9Sstevel@tonic-gate */
5097c478bd9Sstevel@tonic-gate if (cdev != NULL) {
5107c478bd9Sstevel@tonic-gate if (rp->child != NULL) {
5117c478bd9Sstevel@tonic-gate if (cdev != rp->child)
5127c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "first "
5137c478bd9Sstevel@tonic-gate "child must be the "
5147c478bd9Sstevel@tonic-gate "configuration child"));
5157c478bd9Sstevel@tonic-gate } else {
5167c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "known child -- "
5177c478bd9Sstevel@tonic-gate "unknown child expected"));
5187c478bd9Sstevel@tonic-gate }
5197c478bd9Sstevel@tonic-gate }
5207c478bd9Sstevel@tonic-gate break;
5217c478bd9Sstevel@tonic-gate
5227c478bd9Sstevel@tonic-gate case FC_CDIP_DONE:
5237c478bd9Sstevel@tonic-gate /*
5247c478bd9Sstevel@tonic-gate * If we've already created the first child, this
5257c478bd9Sstevel@tonic-gate * child must be unknown and the parent must be a known
5267c478bd9Sstevel@tonic-gate * child of the attachment point.
5277c478bd9Sstevel@tonic-gate */
5287c478bd9Sstevel@tonic-gate if (cdev)
5297c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "known child -- "
5307c478bd9Sstevel@tonic-gate "unknown child expected"));
5317c478bd9Sstevel@tonic-gate if (fc_find_node(pdev, fc_handle_to_dtree(rp)) == NULL)
5327c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "parent is an unknown "
5337c478bd9Sstevel@tonic-gate "child of the attachment point"));
5347c478bd9Sstevel@tonic-gate break;
5357c478bd9Sstevel@tonic-gate
5367c478bd9Sstevel@tonic-gate default:
5377c478bd9Sstevel@tonic-gate /*
5387c478bd9Sstevel@tonic-gate * If we're in some other state, we shouldn't be here.
5397c478bd9Sstevel@tonic-gate */
5407c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "bad node-creation state"));
5417c478bd9Sstevel@tonic-gate /* NOTREACHED */
5427c478bd9Sstevel@tonic-gate }
5437c478bd9Sstevel@tonic-gate
5447c478bd9Sstevel@tonic-gate /*
5457c478bd9Sstevel@tonic-gate * Get the nodename and the unit address.
5467c478bd9Sstevel@tonic-gate */
5477c478bd9Sstevel@tonic-gate s = fc_cell2ptr(fc_arg(cp, 3));
5487c478bd9Sstevel@tonic-gate bzero(nodename, OBP_MAXPROPNAME);
5497c478bd9Sstevel@tonic-gate if (copyinstr(s, nodename, OBP_MAXPROPNAME - 1, NULL))
5507c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "EFAULT copying in nodename"));
5517c478bd9Sstevel@tonic-gate
5527c478bd9Sstevel@tonic-gate s = fc_cell2ptr(fc_arg(cp, 2));
5537c478bd9Sstevel@tonic-gate unit_address = kmem_zalloc(OBP_MAXPATHLEN, KM_SLEEP);
5547c478bd9Sstevel@tonic-gate if (copyinstr(s, unit_address, OBP_MAXPATHLEN - 1, NULL)) {
5557c478bd9Sstevel@tonic-gate kmem_free(unit_address, OBP_MAXPATHLEN);
5567c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "EFAULT copying in unit address"));
5577c478bd9Sstevel@tonic-gate }
5587c478bd9Sstevel@tonic-gate
5597c478bd9Sstevel@tonic-gate /*
5607c478bd9Sstevel@tonic-gate * If cdev is NULL, we have to create the child, otherwise, the
5617c478bd9Sstevel@tonic-gate * child already exists and we're just merging properties into
5627c478bd9Sstevel@tonic-gate * the existing node. The node must be unbound.
5637c478bd9Sstevel@tonic-gate */
5647c478bd9Sstevel@tonic-gate
5657c478bd9Sstevel@tonic-gate if (cdev == NULL)
5667c478bd9Sstevel@tonic-gate createmode = 1;
5677c478bd9Sstevel@tonic-gate
5687c478bd9Sstevel@tonic-gate if (createmode) {
5697c478bd9Sstevel@tonic-gate struct fc_resource *ip;
5707c478bd9Sstevel@tonic-gate int nodeid;
5717c478bd9Sstevel@tonic-gate /*
5727c478bd9Sstevel@tonic-gate * Make sure 'ch' is a nodeid we gave the interpreter.
5737c478bd9Sstevel@tonic-gate * It must be on our resource list.
5747c478bd9Sstevel@tonic-gate */
5757c478bd9Sstevel@tonic-gate if ((ip = find_nodeid_resource(rp, (int)ch)) == NULL) {
5767c478bd9Sstevel@tonic-gate kmem_free(unit_address, OBP_MAXPATHLEN);
5777c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "Unknown phandle"));
5787c478bd9Sstevel@tonic-gate }
5797c478bd9Sstevel@tonic-gate
5807c478bd9Sstevel@tonic-gate /*
5817c478bd9Sstevel@tonic-gate * Allocate a self-identifying, persistent node with
5827c478bd9Sstevel@tonic-gate * the auto-free attribute.
5837c478bd9Sstevel@tonic-gate */
5847c478bd9Sstevel@tonic-gate if (ndi_devi_alloc(pdev, nodename, DEVI_SID_NODEID, &cdev)) {
5857c478bd9Sstevel@tonic-gate kmem_free(unit_address, OBP_MAXPATHLEN);
5867c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "Can't create node"));
5877c478bd9Sstevel@tonic-gate }
5887c478bd9Sstevel@tonic-gate
5897c478bd9Sstevel@tonic-gate /*
5907c478bd9Sstevel@tonic-gate * Free the nodeid we just allocated here, and use
5917c478bd9Sstevel@tonic-gate * the one we handed in. Retain the attributes of
5927c478bd9Sstevel@tonic-gate * the original SID nodetype.
5937c478bd9Sstevel@tonic-gate */
5947c478bd9Sstevel@tonic-gate nodeid = ddi_get_nodeid(cdev);
5957c478bd9Sstevel@tonic-gate i_ndi_set_nodeid(cdev, (int)ch);
5967c478bd9Sstevel@tonic-gate impl_ddi_free_nodeid(nodeid);
5977c478bd9Sstevel@tonic-gate
5987c478bd9Sstevel@tonic-gate /*
5997c478bd9Sstevel@tonic-gate * Remove nodeid 'ch' from our resource list, now that it
6007c478bd9Sstevel@tonic-gate * will be managed by the ddi framework.
6017c478bd9Sstevel@tonic-gate */
6027c478bd9Sstevel@tonic-gate fc_rem_resource(rp, ip);
6037c478bd9Sstevel@tonic-gate kmem_free(ip, sizeof (struct fc_resource));
6047c478bd9Sstevel@tonic-gate
6057c478bd9Sstevel@tonic-gate } else if (strcmp(ddi_node_name(cdev), nodename) != 0) {
6067c478bd9Sstevel@tonic-gate FC_DEBUG2(1, CE_CONT, "Changing <%s> nodename to <%s>\n",
6077c478bd9Sstevel@tonic-gate ddi_node_name(cdev), nodename);
6087c478bd9Sstevel@tonic-gate if (ndi_devi_set_nodename(cdev, nodename, 0)) {
6097c478bd9Sstevel@tonic-gate kmem_free(unit_address, OBP_MAXPATHLEN);
6107c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "Can't set ndi nodename"));
6117c478bd9Sstevel@tonic-gate }
6127c478bd9Sstevel@tonic-gate }
6137c478bd9Sstevel@tonic-gate
6147c478bd9Sstevel@tonic-gate if (fc_ndi_prop_update(DDI_DEV_T_NONE, cdev, "name",
6157c478bd9Sstevel@tonic-gate (uchar_t *)nodename, strlen(nodename) + 1)) {
6167c478bd9Sstevel@tonic-gate kmem_free(unit_address, OBP_MAXPATHLEN);
6177c478bd9Sstevel@tonic-gate if (createmode)
6187c478bd9Sstevel@tonic-gate (void) ndi_devi_free(cdev);
6197c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "Can't create name property"));
6207c478bd9Sstevel@tonic-gate }
6217c478bd9Sstevel@tonic-gate
6227c478bd9Sstevel@tonic-gate /*
6237c478bd9Sstevel@tonic-gate * Add the dip->phandle translation to our list of known phandles.
6247c478bd9Sstevel@tonic-gate */
6257c478bd9Sstevel@tonic-gate fc_add_dip_to_phandle(fc_handle_to_phandle_head(rp), cdev, ch);
6267c478bd9Sstevel@tonic-gate
6277c478bd9Sstevel@tonic-gate /*
6287c478bd9Sstevel@tonic-gate * Add the new node to our copy of the subtree.
6297c478bd9Sstevel@tonic-gate */
6307c478bd9Sstevel@tonic-gate fc_add_child(cdev, pdev, fc_handle_to_dtree(rp));
6317c478bd9Sstevel@tonic-gate
6327c478bd9Sstevel@tonic-gate rp->cdip = cdev;
6337c478bd9Sstevel@tonic-gate rp->cdip_state = FC_CDIP_STARTED;
6347c478bd9Sstevel@tonic-gate
6357c478bd9Sstevel@tonic-gate kmem_free(unit_address, OBP_MAXPATHLEN);
6367c478bd9Sstevel@tonic-gate cp->nresults = fc_int2cell(0);
6377c478bd9Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
6387c478bd9Sstevel@tonic-gate }
6397c478bd9Sstevel@tonic-gate
6407c478bd9Sstevel@tonic-gate /*
6417c478bd9Sstevel@tonic-gate * fco_finish_device ( phandle -- )
6427c478bd9Sstevel@tonic-gate */
6437c478bd9Sstevel@tonic-gate static int
fco_finish_device(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)6447c478bd9Sstevel@tonic-gate fco_finish_device(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
6457c478bd9Sstevel@tonic-gate {
6467c478bd9Sstevel@tonic-gate fc_phandle_t h;
6477c478bd9Sstevel@tonic-gate dev_info_t *cdev;
6487c478bd9Sstevel@tonic-gate
6497c478bd9Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 1)
6507c478bd9Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 1"));
6517c478bd9Sstevel@tonic-gate
6527c478bd9Sstevel@tonic-gate if (rp->cdip_state != FC_CDIP_STARTED)
6537c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "bad node-creation state"));
6547c478bd9Sstevel@tonic-gate
6557c478bd9Sstevel@tonic-gate h = fc_cell2phandle(fc_arg(cp, 0));
6567c478bd9Sstevel@tonic-gate cdev = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), h);
6577c478bd9Sstevel@tonic-gate if (cdev != rp->cdip)
6587c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "bad phandle"));
6597c478bd9Sstevel@tonic-gate
6607c478bd9Sstevel@tonic-gate /*
6617c478bd9Sstevel@tonic-gate * We don't want to online children of the attachment point.
6627c478bd9Sstevel@tonic-gate * We'll 'config' them online later.
6637c478bd9Sstevel@tonic-gate *
6647c478bd9Sstevel@tonic-gate * XXX - APA - I've changed this a bit. The only time we don't
6657c478bd9Sstevel@tonic-gate * want to bind the device is if the parent is the attachment point
6667c478bd9Sstevel@tonic-gate * and the device is the same as the device that was passed to
6677c478bd9Sstevel@tonic-gate * the interpreter. We assume the configurator will do the binding.
6687c478bd9Sstevel@tonic-gate */
6697c478bd9Sstevel@tonic-gate if ((ddi_get_parent(cdev) == ap) && (cdev == rp->child)) {
6707c478bd9Sstevel@tonic-gate FC_DEBUG2(5, CE_CONT, "fc_finish_device: "
6717c478bd9Sstevel@tonic-gate "*not* binding <%s> dip %p\n", ddi_node_name(cdev), cdev);
6727c478bd9Sstevel@tonic-gate } else {
6737c478bd9Sstevel@tonic-gate FC_DEBUG2(5, CE_CONT, "fc_finish_device: binding <%s> dip %p\n",
6747c478bd9Sstevel@tonic-gate ddi_node_name(cdev), cdev);
6757c478bd9Sstevel@tonic-gate
6767c478bd9Sstevel@tonic-gate (void) ndi_devi_bind_driver(cdev, 0);
6777c478bd9Sstevel@tonic-gate }
6787c478bd9Sstevel@tonic-gate
6797c478bd9Sstevel@tonic-gate rp->cdip_state = FC_CDIP_DONE;
6807c478bd9Sstevel@tonic-gate cp->nresults = fc_int2cell(0);
6817c478bd9Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
6827c478bd9Sstevel@tonic-gate }
6837c478bd9Sstevel@tonic-gate
6847c478bd9Sstevel@tonic-gate /*
6857c478bd9Sstevel@tonic-gate * fco_create_property ( propname-cstr buf len phandle -- )
6867c478bd9Sstevel@tonic-gate */
6877c478bd9Sstevel@tonic-gate static int
fco_create_property(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)6887c478bd9Sstevel@tonic-gate fco_create_property(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
6897c478bd9Sstevel@tonic-gate {
6907c478bd9Sstevel@tonic-gate char *buf, *bp, *pnp;
6917c478bd9Sstevel@tonic-gate size_t len;
6927c478bd9Sstevel@tonic-gate fc_phandle_t h;
6937c478bd9Sstevel@tonic-gate dev_info_t *dev;
6947c478bd9Sstevel@tonic-gate int error;
6957c478bd9Sstevel@tonic-gate char propname[OBP_MAXPROPNAME];
6967c478bd9Sstevel@tonic-gate
6977c478bd9Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 4)
6987c478bd9Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 4"));
6997c478bd9Sstevel@tonic-gate
7007c478bd9Sstevel@tonic-gate h = fc_cell2phandle(fc_arg(cp, 0));
7017c478bd9Sstevel@tonic-gate len = fc_cell2size(fc_arg(cp, 1));
7027c478bd9Sstevel@tonic-gate bp = fc_cell2ptr(fc_arg(cp, 2));
7037c478bd9Sstevel@tonic-gate pnp = fc_cell2ptr(fc_arg(cp, 3));
7047c478bd9Sstevel@tonic-gate
7057c478bd9Sstevel@tonic-gate dev = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), h);
7067c478bd9Sstevel@tonic-gate if (dev == NULL)
7077c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "bad phandle"));
7087c478bd9Sstevel@tonic-gate
7097c478bd9Sstevel@tonic-gate bzero(propname, OBP_MAXPROPNAME);
7107c478bd9Sstevel@tonic-gate if (copyinstr(pnp, propname, OBP_MAXPROPNAME - 1, NULL))
7117c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "EFAULT copying in propname"));
7127c478bd9Sstevel@tonic-gate
7137c478bd9Sstevel@tonic-gate buf = NULL;
7147c478bd9Sstevel@tonic-gate if (len != 0) {
7157c478bd9Sstevel@tonic-gate buf = kmem_zalloc(len, KM_SLEEP);
7167c478bd9Sstevel@tonic-gate if (copyin(bp, buf, len)) {
7177c478bd9Sstevel@tonic-gate kmem_free(buf, len);
7187c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "EFAULT copying in propval"));
7197c478bd9Sstevel@tonic-gate }
7207c478bd9Sstevel@tonic-gate }
7217c478bd9Sstevel@tonic-gate
7227c478bd9Sstevel@tonic-gate /*
7237c478bd9Sstevel@tonic-gate * check for propname: 'name' ... we don't allow it
7247c478bd9Sstevel@tonic-gate * by changed here. It has to be specified when the node
7257c478bd9Sstevel@tonic-gate * is created.
7267c478bd9Sstevel@tonic-gate */
7277c478bd9Sstevel@tonic-gate if (strcmp(propname, "name") == 0) {
7287c478bd9Sstevel@tonic-gate char *n = ddi_node_name(dev);
7297c478bd9Sstevel@tonic-gate
7307c478bd9Sstevel@tonic-gate if (len == 0)
7317c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "setting <name> to NULL"));
7327c478bd9Sstevel@tonic-gate if ((len < (strlen(n) + 1)) || (strcmp(n, buf) != 0)) {
7337c478bd9Sstevel@tonic-gate kmem_free(buf, len);
7347c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "changing <name> property"));
7357c478bd9Sstevel@tonic-gate }
7367c478bd9Sstevel@tonic-gate /*
7377c478bd9Sstevel@tonic-gate * Since we're not changing the value, and we already created
7387c478bd9Sstevel@tonic-gate * the 'name' property when we created the node ...
7397c478bd9Sstevel@tonic-gate */
7407c478bd9Sstevel@tonic-gate kmem_free(buf, len);
7417c478bd9Sstevel@tonic-gate cp->nresults = fc_int2cell(0);
7427c478bd9Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
7437c478bd9Sstevel@tonic-gate }
7447c478bd9Sstevel@tonic-gate
7457c478bd9Sstevel@tonic-gate error = fc_ndi_prop_update(DDI_DEV_T_NONE, dev, propname,
7467c478bd9Sstevel@tonic-gate (uchar_t *)buf, len);
7477c478bd9Sstevel@tonic-gate
7487c478bd9Sstevel@tonic-gate if (len != 0)
7497c478bd9Sstevel@tonic-gate kmem_free(buf, len);
7507c478bd9Sstevel@tonic-gate
7517c478bd9Sstevel@tonic-gate if (error)
7527c478bd9Sstevel@tonic-gate return (fc_priv_error(cp, "Can't create property"));
7537c478bd9Sstevel@tonic-gate
7547c478bd9Sstevel@tonic-gate cp->nresults = fc_int2cell(0);
7557c478bd9Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
7567c478bd9Sstevel@tonic-gate }
7577c478bd9Sstevel@tonic-gate
7587c478bd9Sstevel@tonic-gate /*
7597c478bd9Sstevel@tonic-gate * Make sure any in-progress activity is completed,
7607c478bd9Sstevel@tonic-gate * and for now, online the subtree.
7617c478bd9Sstevel@tonic-gate * XXX: Presumably the configurator will online the subtree
7627c478bd9Sstevel@tonic-gate * XXX: by doing an ndi_devi_online with NDI_CONFIG on the child
7637c478bd9Sstevel@tonic-gate * XXX: if there is one. For now, we're doing it here.
7647c478bd9Sstevel@tonic-gate * XXX: For buses without a configurator (and thus no config child),
7657c478bd9Sstevel@tonic-gate * XXX: we have to do it here.
7667c478bd9Sstevel@tonic-gate *
7677c478bd9Sstevel@tonic-gate */
7687c478bd9Sstevel@tonic-gate static int
fco_validate(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)7697c478bd9Sstevel@tonic-gate fco_validate(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
7707c478bd9Sstevel@tonic-gate {
7717c478bd9Sstevel@tonic-gate rp->cdip_state = FC_CDIP_CONFIG;
7727c478bd9Sstevel@tonic-gate
7737c478bd9Sstevel@tonic-gate cp->nresults = fc_int2cell(0);
7747c478bd9Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
7757c478bd9Sstevel@tonic-gate }
7767c478bd9Sstevel@tonic-gate
7777c478bd9Sstevel@tonic-gate static void
remove_subtree(dev_info_t * root,struct fc_device_tree * subtree)7787c478bd9Sstevel@tonic-gate remove_subtree(dev_info_t *root, struct fc_device_tree *subtree)
7797c478bd9Sstevel@tonic-gate {
7807c478bd9Sstevel@tonic-gate dev_info_t *child;
7817c478bd9Sstevel@tonic-gate
7827c478bd9Sstevel@tonic-gate /*
7837c478bd9Sstevel@tonic-gate * Remove the subtree, depth first. Each iterative
7847c478bd9Sstevel@tonic-gate * call gets another child at each level of the tree
7857c478bd9Sstevel@tonic-gate * until there are no more children.
7867c478bd9Sstevel@tonic-gate */
7877c478bd9Sstevel@tonic-gate while ((child = fc_child_node(root, subtree)) != NULL)
7887c478bd9Sstevel@tonic-gate remove_subtree(child, subtree);
7897c478bd9Sstevel@tonic-gate
7907c478bd9Sstevel@tonic-gate /*
7917c478bd9Sstevel@tonic-gate * Delete the subtree root and remove its record from our
7927c478bd9Sstevel@tonic-gate * copy of the subtree.
7937c478bd9Sstevel@tonic-gate */
7947c478bd9Sstevel@tonic-gate fc_remove_child(root, subtree);
7957c478bd9Sstevel@tonic-gate (void) ndi_devi_offline(root, NDI_UNCONFIG | NDI_DEVI_REMOVE);
7967c478bd9Sstevel@tonic-gate }
7977c478bd9Sstevel@tonic-gate
7987c478bd9Sstevel@tonic-gate static int
fco_invalidate(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)7997c478bd9Sstevel@tonic-gate fco_invalidate(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
8007c478bd9Sstevel@tonic-gate {
8017c478bd9Sstevel@tonic-gate dev_info_t *root, *child;
8027c478bd9Sstevel@tonic-gate struct fc_device_tree *subtree = fc_handle_to_dtree(rp);
8037c478bd9Sstevel@tonic-gate int configured = (rp->cdip_state == FC_CDIP_CONFIG);
8047c478bd9Sstevel@tonic-gate
8057c478bd9Sstevel@tonic-gate /*
8067c478bd9Sstevel@tonic-gate * If we created any children, delete them. The root node is the
8077c478bd9Sstevel@tonic-gate * config child, if one exists for this bus, otherwise it's the
8087c478bd9Sstevel@tonic-gate * attachment point.
8097c478bd9Sstevel@tonic-gate *
8107c478bd9Sstevel@tonic-gate * Our copy of the subtree only contains records of nodes we created
8117c478bd9Sstevel@tonic-gate * under the subtree root and contains the parent->child linkage
8127c478bd9Sstevel@tonic-gate * that isn't yet established in the real device tree.
8137c478bd9Sstevel@tonic-gate *
8147c478bd9Sstevel@tonic-gate * XXX: What we don't do is restore the config child node to it's
8157c478bd9Sstevel@tonic-gate * pre-interpretive state. (We may have added properties to
8167c478bd9Sstevel@tonic-gate * that node. It's not clear if its necessary to clean them up.)
8177c478bd9Sstevel@tonic-gate */
8187c478bd9Sstevel@tonic-gate root = rp->child ? rp->child : ap;
8197c478bd9Sstevel@tonic-gate
8207c478bd9Sstevel@tonic-gate while ((child = fc_child_node(root, subtree)) != NULL) {
8217c478bd9Sstevel@tonic-gate FC_DEBUG2(1, CE_CONT, "fco_invalidate: remove subtree "
8227c478bd9Sstevel@tonic-gate "<%s> dip %p\n", ddi_node_name(child), child);
8237c478bd9Sstevel@tonic-gate remove_subtree(child, subtree);
8247c478bd9Sstevel@tonic-gate }
8257c478bd9Sstevel@tonic-gate
8267c478bd9Sstevel@tonic-gate if (configured)
8277c478bd9Sstevel@tonic-gate (void) ndi_devi_offline(root, NDI_UNCONFIG);
8287c478bd9Sstevel@tonic-gate
8297c478bd9Sstevel@tonic-gate cp->nresults = fc_int2cell(0);
8307c478bd9Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
8317c478bd9Sstevel@tonic-gate }
8327c478bd9Sstevel@tonic-gate
8337c478bd9Sstevel@tonic-gate static int
fco_exit(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)8347c478bd9Sstevel@tonic-gate fco_exit(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
8357c478bd9Sstevel@tonic-gate {
8367c478bd9Sstevel@tonic-gate FC_DEBUG0(1, CE_CONT, "exit op not implemented .. succeeding\n");
8377c478bd9Sstevel@tonic-gate cp->nresults = fc_int2cell(0);
8387c478bd9Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
8397c478bd9Sstevel@tonic-gate }
8407c478bd9Sstevel@tonic-gate
8417c478bd9Sstevel@tonic-gate /*
8427c478bd9Sstevel@tonic-gate * Needed to implement 'mac-address' Fcode, no obvious place to pick this
8437c478bd9Sstevel@tonic-gate * info up from user-land.
8447c478bd9Sstevel@tonic-gate */
8457c478bd9Sstevel@tonic-gate static int
fco_local_ether_addr(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)8467c478bd9Sstevel@tonic-gate fco_local_ether_addr(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
8477c478bd9Sstevel@tonic-gate {
8487c478bd9Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 0)
8497c478bd9Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 0"));
8507c478bd9Sstevel@tonic-gate
8517c478bd9Sstevel@tonic-gate if (fc_cell2int(cp->nresults) != 2)
8527c478bd9Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be 2"));
8537c478bd9Sstevel@tonic-gate
8547c478bd9Sstevel@tonic-gate cp->nresults = fc_int2cell(2);
8557c478bd9Sstevel@tonic-gate
8567c478bd9Sstevel@tonic-gate (void) localetheraddr(NULL, (struct ether_addr *)(&fc_result(cp, 0)));
8577c478bd9Sstevel@tonic-gate
8587c478bd9Sstevel@tonic-gate return (fc_success_op(ap, rp, cp));
8597c478bd9Sstevel@tonic-gate }
8607c478bd9Sstevel@tonic-gate
8617c478bd9Sstevel@tonic-gate #ifdef DEBUG
8627c478bd9Sstevel@tonic-gate void
fc_debug(char * fmt,uintptr_t a1,uintptr_t a2,uintptr_t a3,uintptr_t a4,uintptr_t a5)8637c478bd9Sstevel@tonic-gate fc_debug(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3,
8647c478bd9Sstevel@tonic-gate uintptr_t a4, uintptr_t a5)
8657c478bd9Sstevel@tonic-gate {
8667c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5);
8677c478bd9Sstevel@tonic-gate }
8687c478bd9Sstevel@tonic-gate #endif
869