xref: /onnv-gate/usr/src/cmd/ldmad/ldma_dio.c (revision 11833:3b3fe296598b)
111596SJason.Beloro@Sun.COM /*
211596SJason.Beloro@Sun.COM  * CDDL HEADER START
311596SJason.Beloro@Sun.COM  *
411596SJason.Beloro@Sun.COM  * The contents of this file are subject to the terms of the
511596SJason.Beloro@Sun.COM  * Common Development and Distribution License (the "License").
611596SJason.Beloro@Sun.COM  * You may not use this file except in compliance with the License.
711596SJason.Beloro@Sun.COM  *
811596SJason.Beloro@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911596SJason.Beloro@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1011596SJason.Beloro@Sun.COM  * See the License for the specific language governing permissions
1111596SJason.Beloro@Sun.COM  * and limitations under the License.
1211596SJason.Beloro@Sun.COM  *
1311596SJason.Beloro@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1411596SJason.Beloro@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1511596SJason.Beloro@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1611596SJason.Beloro@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1711596SJason.Beloro@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1811596SJason.Beloro@Sun.COM  *
1911596SJason.Beloro@Sun.COM  * CDDL HEADER END
2011596SJason.Beloro@Sun.COM  */
2111596SJason.Beloro@Sun.COM 
2211596SJason.Beloro@Sun.COM /*
2311596SJason.Beloro@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
2411596SJason.Beloro@Sun.COM  * Use is subject to license terms.
2511596SJason.Beloro@Sun.COM  */
2611596SJason.Beloro@Sun.COM 
2711596SJason.Beloro@Sun.COM #include <stdio.h>
2811596SJason.Beloro@Sun.COM #include <string.h>
2911596SJason.Beloro@Sun.COM #include <stdlib.h>
3011596SJason.Beloro@Sun.COM #include <unistd.h>
3111596SJason.Beloro@Sun.COM #include <sys/types.h>
3211596SJason.Beloro@Sun.COM #include <alloca.h>
3311596SJason.Beloro@Sun.COM #include <sys/stat.h>
3411596SJason.Beloro@Sun.COM #include <malloc.h>
3511596SJason.Beloro@Sun.COM #include <fcntl.h>
3611596SJason.Beloro@Sun.COM #include <syslog.h>
3711596SJason.Beloro@Sun.COM #include <string.h>
3811596SJason.Beloro@Sun.COM #include <errno.h>
3911596SJason.Beloro@Sun.COM #include <sys/mdesc.h>
4011596SJason.Beloro@Sun.COM #include <sys/mdesc_impl.h>
4111596SJason.Beloro@Sun.COM #include <libdevinfo.h>
4211596SJason.Beloro@Sun.COM #include "ldma.h"
4311596SJason.Beloro@Sun.COM #include "mdesc_mutable.h"
4411596SJason.Beloro@Sun.COM 
4511596SJason.Beloro@Sun.COM 
4611596SJason.Beloro@Sun.COM static int get_devinfo(uint8_t **mdpp, size_t *size);
4711596SJason.Beloro@Sun.COM static boolean_t is_root_complex(di_prom_handle_t ph, di_node_t di);
4811596SJason.Beloro@Sun.COM static md_node_t *link_device_node(mmd_t *mdp,
4911596SJason.Beloro@Sun.COM     di_prom_handle_t ph, di_node_t di, md_node_t *node, char *path);
5011596SJason.Beloro@Sun.COM static int create_children(mmd_t *mdp,
5111596SJason.Beloro@Sun.COM     di_prom_handle_t ph, md_node_t *node, di_node_t parent);
5211596SJason.Beloro@Sun.COM static int create_peers(mmd_t *mdp,
5311596SJason.Beloro@Sun.COM     di_prom_handle_t ph, md_node_t *node, di_node_t dev);
5411596SJason.Beloro@Sun.COM static int device_tree_to_md(mmd_t *mdp, md_node_t *top);
5511596SJason.Beloro@Sun.COM 
5611596SJason.Beloro@Sun.COM 
5711596SJason.Beloro@Sun.COM #define	PCIEX		"pciex"
5811596SJason.Beloro@Sun.COM #define	LDMA_MODULE	LDMA_NAME_DIO
5911596SJason.Beloro@Sun.COM 
6011596SJason.Beloro@Sun.COM 
6111596SJason.Beloro@Sun.COM /* System Info version supported (only version 1.0) */
6211596SJason.Beloro@Sun.COM static ds_ver_t ldma_dio_vers[] = { {1, 0} };
6311596SJason.Beloro@Sun.COM 
6411596SJason.Beloro@Sun.COM #define	LDMA_DIO_NVERS	(sizeof (ldma_dio_vers) / sizeof (ds_ver_t))
6511596SJason.Beloro@Sun.COM #define	LDMA_DIO_NHANDLERS  (sizeof (ldma_dio_handlers) /		\
6611596SJason.Beloro@Sun.COM     sizeof (ldma_msg_handler_t))
6711596SJason.Beloro@Sun.COM 
6811596SJason.Beloro@Sun.COM static ldm_msg_func_t ldma_dio_pcidev_info_handler;
6911596SJason.Beloro@Sun.COM 
7011596SJason.Beloro@Sun.COM static ldma_msg_handler_t ldma_dio_handlers[] = {
71*11833SMichael.Christensen@Sun.COM 	{MSGDIO_PCIDEV_INFO, LDMA_MSGFLG_ACCESS_CONTROL,
72*11833SMichael.Christensen@Sun.COM 	    ldma_dio_pcidev_info_handler },
7311596SJason.Beloro@Sun.COM };
7411596SJason.Beloro@Sun.COM 
7511596SJason.Beloro@Sun.COM ldma_agent_info_t ldma_dio_info = {
7611596SJason.Beloro@Sun.COM 	LDMA_NAME_DIO,
7711596SJason.Beloro@Sun.COM 	ldma_dio_vers, LDMA_DIO_NVERS,
7811596SJason.Beloro@Sun.COM 	ldma_dio_handlers, LDMA_DIO_NHANDLERS
7911596SJason.Beloro@Sun.COM };
8011596SJason.Beloro@Sun.COM 
8111596SJason.Beloro@Sun.COM /* ARGSUSED */
8211596SJason.Beloro@Sun.COM static ldma_request_status_t
ldma_dio_pcidev_info_handler(ds_ver_t * ver,ldma_message_header_t * request,size_t request_dlen,ldma_message_header_t ** replyp,size_t * reply_dlenp)8311596SJason.Beloro@Sun.COM ldma_dio_pcidev_info_handler(ds_ver_t *ver, ldma_message_header_t *request,
8411596SJason.Beloro@Sun.COM     size_t request_dlen, ldma_message_header_t **replyp, size_t *reply_dlenp)
8511596SJason.Beloro@Sun.COM {
8611596SJason.Beloro@Sun.COM 	ldma_message_header_t *reply;
8711596SJason.Beloro@Sun.COM 	char *data;
8811596SJason.Beloro@Sun.COM 	uint8_t *md_bufp = NULL;
8911596SJason.Beloro@Sun.COM 	size_t md_size;
9011596SJason.Beloro@Sun.COM 	int rv;
9111596SJason.Beloro@Sun.COM 
9211596SJason.Beloro@Sun.COM 	LDMA_DBG("%s: PCI device info request", __func__);
9311596SJason.Beloro@Sun.COM 	rv  = get_devinfo(&md_bufp, &md_size);
9411596SJason.Beloro@Sun.COM 	if (rv != 0) {
9511596SJason.Beloro@Sun.COM 		LDMA_ERR("Failed to generate devinfo MD");
9611596SJason.Beloro@Sun.COM 		return (LDMA_REQ_FAILED);
9711596SJason.Beloro@Sun.COM 	}
9811596SJason.Beloro@Sun.COM 	reply = ldma_alloc_result_msg(request, md_size);
9911596SJason.Beloro@Sun.COM 	if (reply == NULL) {
10011596SJason.Beloro@Sun.COM 		LDMA_ERR("Memory allocation failure");
10111596SJason.Beloro@Sun.COM 		free(md_bufp);
10211596SJason.Beloro@Sun.COM 		return (LDMA_REQ_FAILED);
10311596SJason.Beloro@Sun.COM 	}
10411596SJason.Beloro@Sun.COM 
10511596SJason.Beloro@Sun.COM 	reply->msg_info = md_size;
10611596SJason.Beloro@Sun.COM 	data = LDMA_HDR2DATA(reply);
10711596SJason.Beloro@Sun.COM 	(void) memcpy(data, md_bufp, md_size);
10811596SJason.Beloro@Sun.COM 	*replyp = reply;
10911596SJason.Beloro@Sun.COM 	*reply_dlenp = md_size;
11011596SJason.Beloro@Sun.COM 	free(md_bufp);
11111596SJason.Beloro@Sun.COM 	LDMA_DBG("%s: sending PCI device info", __func__);
11211596SJason.Beloro@Sun.COM 	return (LDMA_REQ_COMPLETED);
11311596SJason.Beloro@Sun.COM }
11411596SJason.Beloro@Sun.COM 
11511596SJason.Beloro@Sun.COM static boolean_t
is_root_complex(di_prom_handle_t ph,di_node_t di)11611596SJason.Beloro@Sun.COM is_root_complex(di_prom_handle_t ph, di_node_t di)
11711596SJason.Beloro@Sun.COM {
11811596SJason.Beloro@Sun.COM 	int	len;
11911596SJason.Beloro@Sun.COM 	char	*type;
12011596SJason.Beloro@Sun.COM 
12111596SJason.Beloro@Sun.COM 	len = di_prom_prop_lookup_strings(ph, di, "device_type", &type);
12211596SJason.Beloro@Sun.COM 	if ((len == 0) || (type == NULL))
12311596SJason.Beloro@Sun.COM 		return (B_FALSE);
12411596SJason.Beloro@Sun.COM 
12511596SJason.Beloro@Sun.COM 	if (strcmp(type, PCIEX) != 0)
12611596SJason.Beloro@Sun.COM 		return (B_FALSE);
12711596SJason.Beloro@Sun.COM 
12811596SJason.Beloro@Sun.COM 	/*
12911596SJason.Beloro@Sun.COM 	 * A root complex node is directly under the root node.  So, if
13011596SJason.Beloro@Sun.COM 	 * 'di' is not the root node, and its parent has no parent,
13111596SJason.Beloro@Sun.COM 	 * then 'di' represents a root complex node.
13211596SJason.Beloro@Sun.COM 	 */
13311596SJason.Beloro@Sun.COM 	return ((di_parent_node(di) != DI_NODE_NIL) &&
13411596SJason.Beloro@Sun.COM 	    (di_parent_node(di_parent_node(di)) == DI_NODE_NIL));
13511596SJason.Beloro@Sun.COM }
13611596SJason.Beloro@Sun.COM 
13711596SJason.Beloro@Sun.COM /*
13811596SJason.Beloro@Sun.COM  * String properties in the prom can contain multiple null-terminated
13911596SJason.Beloro@Sun.COM  * strings which are concatenated together.  We must represent them in
14011596SJason.Beloro@Sun.COM  * an MD as a data property.  This function retrieves such a property
14111596SJason.Beloro@Sun.COM  * and adds it to the MD.  If the 'alt_name' PROM property exists then
14211596SJason.Beloro@Sun.COM  * the MD property is created with the value of the PROM 'alt_name'
14311596SJason.Beloro@Sun.COM  * property, otherwise it is created with the value of the PROM 'name'
14411596SJason.Beloro@Sun.COM  * property.
14511596SJason.Beloro@Sun.COM  */
14611596SJason.Beloro@Sun.COM static int
add_prom_string_prop(di_prom_handle_t ph,mmd_t * mdp,md_node_t * np,di_node_t di,char * name,char * alt_name)14711596SJason.Beloro@Sun.COM add_prom_string_prop(di_prom_handle_t ph,
14811596SJason.Beloro@Sun.COM     mmd_t *mdp, md_node_t *np, di_node_t di, char *name, char *alt_name)
14911596SJason.Beloro@Sun.COM {
15011596SJason.Beloro@Sun.COM 	int		count;
15111596SJason.Beloro@Sun.COM 	char		*pp_data = NULL;
15211596SJason.Beloro@Sun.COM 	char		*str;
15311596SJason.Beloro@Sun.COM 	int		rv = 0;
15411596SJason.Beloro@Sun.COM 
15511596SJason.Beloro@Sun.COM 	if (alt_name != NULL) {
15611596SJason.Beloro@Sun.COM 		count = di_prom_prop_lookup_strings(ph, di, alt_name, &pp_data);
15711596SJason.Beloro@Sun.COM 	}
15811596SJason.Beloro@Sun.COM 	if (pp_data == NULL) {
15911596SJason.Beloro@Sun.COM 		count = di_prom_prop_lookup_strings(ph, di, name, &pp_data);
16011596SJason.Beloro@Sun.COM 	}
16111596SJason.Beloro@Sun.COM 
16211596SJason.Beloro@Sun.COM 	if (count > 0 && pp_data != NULL) {
16311596SJason.Beloro@Sun.COM 		for (str = pp_data; count > 0; str += strlen(str) + 1)
16411596SJason.Beloro@Sun.COM 			count--;
16511596SJason.Beloro@Sun.COM 		rv = md_add_data_property(mdp,
16611596SJason.Beloro@Sun.COM 		    np, name, str - pp_data, (uint8_t *)pp_data);
16711596SJason.Beloro@Sun.COM 	}
16811596SJason.Beloro@Sun.COM 	return (rv);
16911596SJason.Beloro@Sun.COM }
17011596SJason.Beloro@Sun.COM 
17111596SJason.Beloro@Sun.COM /*
17211596SJason.Beloro@Sun.COM  * Add an int property 'name' to an MD from an existing PROM property. If
17311596SJason.Beloro@Sun.COM  * the 'alt_name' PROM property exists then the MD property is created with
17411596SJason.Beloro@Sun.COM  * the value of the PROM 'alt_name' property, otherwise it is created with
17511596SJason.Beloro@Sun.COM  * the value of the PROM 'name' property.
17611596SJason.Beloro@Sun.COM  */
17711596SJason.Beloro@Sun.COM static int
add_prom_int_prop(di_prom_handle_t ph,mmd_t * mdp,md_node_t * np,di_node_t di,char * name,char * alt_name)17811596SJason.Beloro@Sun.COM add_prom_int_prop(di_prom_handle_t ph,
17911596SJason.Beloro@Sun.COM     mmd_t *mdp, md_node_t *np, di_node_t di, char *name, char *alt_name)
18011596SJason.Beloro@Sun.COM {
18111596SJason.Beloro@Sun.COM 	int		count;
18211596SJason.Beloro@Sun.COM 	int		rv = 0;
18311596SJason.Beloro@Sun.COM 	int		*pp_data = NULL;
18411596SJason.Beloro@Sun.COM 
18511596SJason.Beloro@Sun.COM 	if (alt_name != NULL) {
18611596SJason.Beloro@Sun.COM 		count = di_prom_prop_lookup_ints(ph, di, alt_name, &pp_data);
18711596SJason.Beloro@Sun.COM 	}
18811596SJason.Beloro@Sun.COM 	if (pp_data == NULL) {
18911596SJason.Beloro@Sun.COM 		count = di_prom_prop_lookup_ints(ph, di, name, &pp_data);
19011596SJason.Beloro@Sun.COM 	}
19111596SJason.Beloro@Sun.COM 
19211596SJason.Beloro@Sun.COM 	/*
19311596SJason.Beloro@Sun.COM 	 * Note: We know that the properties of interest contain a
19411596SJason.Beloro@Sun.COM 	 * a single int.
19511596SJason.Beloro@Sun.COM 	 */
19611596SJason.Beloro@Sun.COM 	if (count > 0 && pp_data != NULL) {
19711596SJason.Beloro@Sun.COM 		ASSERT(count == 1);
19811596SJason.Beloro@Sun.COM 		rv = md_add_value_property(mdp, np, name, *pp_data);
19911596SJason.Beloro@Sun.COM 	}
20011596SJason.Beloro@Sun.COM 	return (rv);
20111596SJason.Beloro@Sun.COM }
20211596SJason.Beloro@Sun.COM 
20311596SJason.Beloro@Sun.COM static md_node_t *
link_device_node(mmd_t * mdp,di_prom_handle_t ph,di_node_t di,md_node_t * node,char * path)20411596SJason.Beloro@Sun.COM link_device_node(mmd_t *mdp,
20511596SJason.Beloro@Sun.COM     di_prom_handle_t ph, di_node_t di, md_node_t *node, char *path)
20611596SJason.Beloro@Sun.COM {
20711596SJason.Beloro@Sun.COM 	md_node_t	*np;
20811596SJason.Beloro@Sun.COM 
20911596SJason.Beloro@Sun.COM 	np = md_link_new_node(mdp, "iodevice", node, "fwd", "back");
21011596SJason.Beloro@Sun.COM 	if (np == NULL)
21111596SJason.Beloro@Sun.COM 		return (NULL);
21211596SJason.Beloro@Sun.COM 
21311596SJason.Beloro@Sun.COM 	/* Add the properties from the devinfo node. */
21411596SJason.Beloro@Sun.COM 	if (md_add_string_property(mdp, np, "dev_path", path) != 0)
21511596SJason.Beloro@Sun.COM 		goto fail;
21611596SJason.Beloro@Sun.COM 
21711596SJason.Beloro@Sun.COM 	/* Add the required properties for this node. */
21811596SJason.Beloro@Sun.COM 	if (add_prom_string_prop(ph, mdp, np, di, "device_type", NULL) != 0)
21911596SJason.Beloro@Sun.COM 		goto fail;
22011596SJason.Beloro@Sun.COM 
22111596SJason.Beloro@Sun.COM 	if (add_prom_string_prop(ph, mdp, np, di, "compatible", NULL) != 0)
22211596SJason.Beloro@Sun.COM 		goto fail;
22311596SJason.Beloro@Sun.COM 
22411596SJason.Beloro@Sun.COM 	if (add_prom_int_prop(ph,
22511596SJason.Beloro@Sun.COM 	    mdp, np, di, "device-id", "real-device-id") != 0)
22611596SJason.Beloro@Sun.COM 		goto fail;
22711596SJason.Beloro@Sun.COM 
22811596SJason.Beloro@Sun.COM 	if (add_prom_int_prop(ph,
22911596SJason.Beloro@Sun.COM 	    mdp, np, di, "vendor-id", "real-vendor-id") != 0)
23011596SJason.Beloro@Sun.COM 		goto fail;
23111596SJason.Beloro@Sun.COM 
23211596SJason.Beloro@Sun.COM 	if (add_prom_int_prop(ph,
23311596SJason.Beloro@Sun.COM 	    mdp, np, di, "class-code", "real-class-code") != 0)
23411596SJason.Beloro@Sun.COM 		goto fail;
23511596SJason.Beloro@Sun.COM 
23611596SJason.Beloro@Sun.COM 	return (np);
23711596SJason.Beloro@Sun.COM 
23811596SJason.Beloro@Sun.COM fail:
23911596SJason.Beloro@Sun.COM 	md_free_node(mdp, np);
24011596SJason.Beloro@Sun.COM 	return (NULL);
24111596SJason.Beloro@Sun.COM }
24211596SJason.Beloro@Sun.COM 
24311596SJason.Beloro@Sun.COM static int
create_children(mmd_t * mdp,di_prom_handle_t ph,md_node_t * md_parent,di_node_t di_parent)24411596SJason.Beloro@Sun.COM create_children(mmd_t *mdp,
24511596SJason.Beloro@Sun.COM     di_prom_handle_t ph, md_node_t *md_parent, di_node_t di_parent)
24611596SJason.Beloro@Sun.COM {
24711596SJason.Beloro@Sun.COM 	md_node_t	*md_node;
24811596SJason.Beloro@Sun.COM 	md_node_t	*md_child;
24911596SJason.Beloro@Sun.COM 	di_node_t	di_child;
25011596SJason.Beloro@Sun.COM 	char		*path;
25111596SJason.Beloro@Sun.COM 	int		rv;
25211596SJason.Beloro@Sun.COM 
25311596SJason.Beloro@Sun.COM 	path = di_devfs_path(di_parent);
25411596SJason.Beloro@Sun.COM 	if (path == NULL)
25511596SJason.Beloro@Sun.COM 		return (EIO);
25611596SJason.Beloro@Sun.COM 
25711596SJason.Beloro@Sun.COM 	md_node = link_device_node(mdp, ph, di_parent, md_parent, path);
25811596SJason.Beloro@Sun.COM 	di_devfs_path_free(path);
25911596SJason.Beloro@Sun.COM 	if (md_node == NULL) {
26011596SJason.Beloro@Sun.COM 		return (ENOMEM);
26111596SJason.Beloro@Sun.COM 	}
26211596SJason.Beloro@Sun.COM 
26311596SJason.Beloro@Sun.COM 	while ((di_child = di_child_node(di_parent)) != DI_NODE_NIL) {
26411596SJason.Beloro@Sun.COM 		path = di_devfs_path(di_child);
26511596SJason.Beloro@Sun.COM 		if (path != NULL) {
26611596SJason.Beloro@Sun.COM 			md_child = link_device_node(mdp,
26711596SJason.Beloro@Sun.COM 			    ph, di_child, md_node, path);
26811596SJason.Beloro@Sun.COM 			di_devfs_path_free(path);
26911596SJason.Beloro@Sun.COM 			if (md_child == NULL) {
27011596SJason.Beloro@Sun.COM 				return (ENOMEM);
27111596SJason.Beloro@Sun.COM 			}
27211596SJason.Beloro@Sun.COM 		}
27311596SJason.Beloro@Sun.COM 
27411596SJason.Beloro@Sun.COM 		rv = create_peers(mdp, ph, md_node, di_child);
27511596SJason.Beloro@Sun.COM 		if (rv != 0)
27611596SJason.Beloro@Sun.COM 			return (rv);
27711596SJason.Beloro@Sun.COM 
27811596SJason.Beloro@Sun.COM 		md_node = md_child;
27911596SJason.Beloro@Sun.COM 		di_parent = di_child;
28011596SJason.Beloro@Sun.COM 	}
28111596SJason.Beloro@Sun.COM 	return (0);
28211596SJason.Beloro@Sun.COM }
28311596SJason.Beloro@Sun.COM 
28411596SJason.Beloro@Sun.COM static int
create_peers(mmd_t * mdp,di_prom_handle_t ph,md_node_t * node,di_node_t dev)28511596SJason.Beloro@Sun.COM create_peers(mmd_t *mdp, di_prom_handle_t ph, md_node_t *node, di_node_t dev)
28611596SJason.Beloro@Sun.COM {
28711596SJason.Beloro@Sun.COM 	di_node_t	di_peer;
28811596SJason.Beloro@Sun.COM 	int		rv;
28911596SJason.Beloro@Sun.COM 
29011596SJason.Beloro@Sun.COM 	while ((di_peer = di_sibling_node(dev)) != DI_NODE_NIL) {
29111596SJason.Beloro@Sun.COM 		rv = create_children(mdp, ph, node, di_peer);
29211596SJason.Beloro@Sun.COM 		if (rv != 0)
29311596SJason.Beloro@Sun.COM 			return (rv);
29411596SJason.Beloro@Sun.COM 		dev = di_peer;
29511596SJason.Beloro@Sun.COM 	}
29611596SJason.Beloro@Sun.COM 	return (0);
29711596SJason.Beloro@Sun.COM }
29811596SJason.Beloro@Sun.COM 
29911596SJason.Beloro@Sun.COM static int
device_tree_to_md(mmd_t * mdp,md_node_t * top)30011596SJason.Beloro@Sun.COM device_tree_to_md(mmd_t *mdp, md_node_t *top)
30111596SJason.Beloro@Sun.COM {
30211596SJason.Beloro@Sun.COM 	di_node_t		node;
30311596SJason.Beloro@Sun.COM 	di_node_t		root;
30411596SJason.Beloro@Sun.COM 	di_prom_handle_t	ph;
30511596SJason.Beloro@Sun.COM 	int			rv = 0;
30611596SJason.Beloro@Sun.COM 
30711596SJason.Beloro@Sun.COM 	root = di_init("/", DINFOSUBTREE | DINFOPROP);
30811596SJason.Beloro@Sun.COM 
30911596SJason.Beloro@Sun.COM 	if (root == DI_NODE_NIL) {
31011596SJason.Beloro@Sun.COM 		LDMA_ERR("di_init cannot find device tree root node.");
31111596SJason.Beloro@Sun.COM 		return (errno);
31211596SJason.Beloro@Sun.COM 	}
31311596SJason.Beloro@Sun.COM 
31411596SJason.Beloro@Sun.COM 	ph = di_prom_init();
31511596SJason.Beloro@Sun.COM 	if (ph == DI_PROM_HANDLE_NIL) {
31611596SJason.Beloro@Sun.COM 		LDMA_ERR("di_prom_init failed.");
31711596SJason.Beloro@Sun.COM 		di_fini(root);
31811596SJason.Beloro@Sun.COM 		return (errno);
31911596SJason.Beloro@Sun.COM 	}
32011596SJason.Beloro@Sun.COM 
32111596SJason.Beloro@Sun.COM 	node = di_child_node(root);
32211596SJason.Beloro@Sun.COM 	while (node != NULL) {
32311596SJason.Beloro@Sun.COM 		if (is_root_complex(ph, node)) {
32411596SJason.Beloro@Sun.COM 			rv = create_children(mdp, ph, top, node);
32511596SJason.Beloro@Sun.COM 			if (rv != 0)
32611596SJason.Beloro@Sun.COM 				break;
32711596SJason.Beloro@Sun.COM 		}
32811596SJason.Beloro@Sun.COM 		node = di_sibling_node(node);
32911596SJason.Beloro@Sun.COM 	}
33011596SJason.Beloro@Sun.COM 
33111596SJason.Beloro@Sun.COM 	di_prom_fini(ph);
33211596SJason.Beloro@Sun.COM 	di_fini(root);
33311596SJason.Beloro@Sun.COM 	return (rv);
33411596SJason.Beloro@Sun.COM }
33511596SJason.Beloro@Sun.COM 
33611596SJason.Beloro@Sun.COM static int
get_devinfo(uint8_t ** mdpp,size_t * size)33711596SJason.Beloro@Sun.COM get_devinfo(uint8_t **mdpp, size_t *size)
33811596SJason.Beloro@Sun.COM {
33911596SJason.Beloro@Sun.COM 	mmd_t		*mdp;
34011596SJason.Beloro@Sun.COM 	md_node_t	*rootp;
34111596SJason.Beloro@Sun.COM 	size_t		md_size;
34211596SJason.Beloro@Sun.COM 	uint8_t		*md_bufp;
34311596SJason.Beloro@Sun.COM 
34411596SJason.Beloro@Sun.COM 	mdp = md_new_md();
34511596SJason.Beloro@Sun.COM 	if (mdp == NULL) {
34611596SJason.Beloro@Sun.COM 		return (ENOMEM);
34711596SJason.Beloro@Sun.COM 	}
34811596SJason.Beloro@Sun.COM 	rootp = md_new_node(mdp, "root");
34911596SJason.Beloro@Sun.COM 	if (rootp == NULL) {
35011596SJason.Beloro@Sun.COM 		md_destroy(mdp);
35111596SJason.Beloro@Sun.COM 		return (ENOMEM);
35211596SJason.Beloro@Sun.COM 	}
35311596SJason.Beloro@Sun.COM 
35411596SJason.Beloro@Sun.COM 	if (device_tree_to_md(mdp, rootp) != 0) {
35511596SJason.Beloro@Sun.COM 		md_destroy(mdp);
35611596SJason.Beloro@Sun.COM 		return (ENOMEM);
35711596SJason.Beloro@Sun.COM 	}
35811596SJason.Beloro@Sun.COM 	md_size = (int)md_gen_bin(mdp, &md_bufp);
35911596SJason.Beloro@Sun.COM 
36011596SJason.Beloro@Sun.COM 	if (md_size == 0) {
36111596SJason.Beloro@Sun.COM 		md_destroy(mdp);
36211596SJason.Beloro@Sun.COM 		return (EIO);
36311596SJason.Beloro@Sun.COM 	}
36411596SJason.Beloro@Sun.COM 	*mdpp = md_bufp;
36511596SJason.Beloro@Sun.COM 	*size = md_size;
36611596SJason.Beloro@Sun.COM 
36711596SJason.Beloro@Sun.COM 	md_destroy(mdp);
36811596SJason.Beloro@Sun.COM 	return (0);
36911596SJason.Beloro@Sun.COM }
370