xref: /illumos-gate/usr/src/uts/sun4/io/efcode/fc_ops.c (revision 48bbca81)
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