xref: /illumos-gate/usr/src/cmd/ldmad/ldma_dio.c (revision 82629e30)
1fc256490SJason Beloro /*
2fc256490SJason Beloro  * CDDL HEADER START
3fc256490SJason Beloro  *
4fc256490SJason Beloro  * The contents of this file are subject to the terms of the
5fc256490SJason Beloro  * Common Development and Distribution License (the "License").
6fc256490SJason Beloro  * You may not use this file except in compliance with the License.
7fc256490SJason Beloro  *
8fc256490SJason Beloro  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fc256490SJason Beloro  * or http://www.opensolaris.org/os/licensing.
10fc256490SJason Beloro  * See the License for the specific language governing permissions
11fc256490SJason Beloro  * and limitations under the License.
12fc256490SJason Beloro  *
13fc256490SJason Beloro  * When distributing Covered Code, include this CDDL HEADER in each
14fc256490SJason Beloro  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fc256490SJason Beloro  * If applicable, add the following below this CDDL HEADER, with the
16fc256490SJason Beloro  * fields enclosed by brackets "[]" replaced with your own identifying
17fc256490SJason Beloro  * information: Portions Copyright [yyyy] [name of copyright owner]
18fc256490SJason Beloro  *
19fc256490SJason Beloro  * CDDL HEADER END
20fc256490SJason Beloro  */
21fc256490SJason Beloro 
22fc256490SJason Beloro /*
23fc256490SJason Beloro  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24fc256490SJason Beloro  * Use is subject to license terms.
25fc256490SJason Beloro  */
26fc256490SJason Beloro 
27fc256490SJason Beloro #include <stdio.h>
28fc256490SJason Beloro #include <string.h>
29fc256490SJason Beloro #include <stdlib.h>
30fc256490SJason Beloro #include <unistd.h>
31fc256490SJason Beloro #include <sys/types.h>
32fc256490SJason Beloro #include <alloca.h>
33fc256490SJason Beloro #include <sys/stat.h>
34fc256490SJason Beloro #include <malloc.h>
35fc256490SJason Beloro #include <fcntl.h>
36fc256490SJason Beloro #include <syslog.h>
37fc256490SJason Beloro #include <string.h>
38fc256490SJason Beloro #include <errno.h>
39fc256490SJason Beloro #include <sys/mdesc.h>
40fc256490SJason Beloro #include <sys/mdesc_impl.h>
41fc256490SJason Beloro #include <libdevinfo.h>
42fc256490SJason Beloro #include "ldma.h"
43fc256490SJason Beloro #include "mdesc_mutable.h"
44fc256490SJason Beloro 
45fc256490SJason Beloro 
46fc256490SJason Beloro static int get_devinfo(uint8_t **mdpp, size_t *size);
47fc256490SJason Beloro static boolean_t is_root_complex(di_prom_handle_t ph, di_node_t di);
48fc256490SJason Beloro static md_node_t *link_device_node(mmd_t *mdp,
49fc256490SJason Beloro     di_prom_handle_t ph, di_node_t di, md_node_t *node, char *path);
50fc256490SJason Beloro static int create_children(mmd_t *mdp,
51fc256490SJason Beloro     di_prom_handle_t ph, md_node_t *node, di_node_t parent);
52fc256490SJason Beloro static int create_peers(mmd_t *mdp,
53fc256490SJason Beloro     di_prom_handle_t ph, md_node_t *node, di_node_t dev);
54fc256490SJason Beloro static int device_tree_to_md(mmd_t *mdp, md_node_t *top);
55fc256490SJason Beloro 
56fc256490SJason Beloro 
57fc256490SJason Beloro #define	PCIEX		"pciex"
58fc256490SJason Beloro #define	LDMA_MODULE	LDMA_NAME_DIO
59fc256490SJason Beloro 
60fc256490SJason Beloro 
61fc256490SJason Beloro /* System Info version supported (only version 1.0) */
62fc256490SJason Beloro static ds_ver_t ldma_dio_vers[] = { {1, 0} };
63fc256490SJason Beloro 
64fc256490SJason Beloro #define	LDMA_DIO_NVERS	(sizeof (ldma_dio_vers) / sizeof (ds_ver_t))
65fc256490SJason Beloro #define	LDMA_DIO_NHANDLERS  (sizeof (ldma_dio_handlers) /		\
66fc256490SJason Beloro     sizeof (ldma_msg_handler_t))
67fc256490SJason Beloro 
68fc256490SJason Beloro static ldm_msg_func_t ldma_dio_pcidev_info_handler;
69fc256490SJason Beloro 
70fc256490SJason Beloro static ldma_msg_handler_t ldma_dio_handlers[] = {
71*82629e30SMike Christensen 	{MSGDIO_PCIDEV_INFO, LDMA_MSGFLG_ACCESS_CONTROL,
72*82629e30SMike Christensen 	    ldma_dio_pcidev_info_handler },
73fc256490SJason Beloro };
74fc256490SJason Beloro 
75fc256490SJason Beloro ldma_agent_info_t ldma_dio_info = {
76fc256490SJason Beloro 	LDMA_NAME_DIO,
77fc256490SJason Beloro 	ldma_dio_vers, LDMA_DIO_NVERS,
78fc256490SJason Beloro 	ldma_dio_handlers, LDMA_DIO_NHANDLERS
79fc256490SJason Beloro };
80fc256490SJason Beloro 
81fc256490SJason Beloro /* ARGSUSED */
82fc256490SJason Beloro 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)83fc256490SJason Beloro ldma_dio_pcidev_info_handler(ds_ver_t *ver, ldma_message_header_t *request,
84fc256490SJason Beloro     size_t request_dlen, ldma_message_header_t **replyp, size_t *reply_dlenp)
85fc256490SJason Beloro {
86fc256490SJason Beloro 	ldma_message_header_t *reply;
87fc256490SJason Beloro 	char *data;
88fc256490SJason Beloro 	uint8_t *md_bufp = NULL;
89fc256490SJason Beloro 	size_t md_size;
90fc256490SJason Beloro 	int rv;
91fc256490SJason Beloro 
92fc256490SJason Beloro 	LDMA_DBG("%s: PCI device info request", __func__);
93fc256490SJason Beloro 	rv  = get_devinfo(&md_bufp, &md_size);
94fc256490SJason Beloro 	if (rv != 0) {
95fc256490SJason Beloro 		LDMA_ERR("Failed to generate devinfo MD");
96fc256490SJason Beloro 		return (LDMA_REQ_FAILED);
97fc256490SJason Beloro 	}
98fc256490SJason Beloro 	reply = ldma_alloc_result_msg(request, md_size);
99fc256490SJason Beloro 	if (reply == NULL) {
100fc256490SJason Beloro 		LDMA_ERR("Memory allocation failure");
101fc256490SJason Beloro 		free(md_bufp);
102fc256490SJason Beloro 		return (LDMA_REQ_FAILED);
103fc256490SJason Beloro 	}
104fc256490SJason Beloro 
105fc256490SJason Beloro 	reply->msg_info = md_size;
106fc256490SJason Beloro 	data = LDMA_HDR2DATA(reply);
107fc256490SJason Beloro 	(void) memcpy(data, md_bufp, md_size);
108fc256490SJason Beloro 	*replyp = reply;
109fc256490SJason Beloro 	*reply_dlenp = md_size;
110fc256490SJason Beloro 	free(md_bufp);
111fc256490SJason Beloro 	LDMA_DBG("%s: sending PCI device info", __func__);
112fc256490SJason Beloro 	return (LDMA_REQ_COMPLETED);
113fc256490SJason Beloro }
114fc256490SJason Beloro 
115fc256490SJason Beloro static boolean_t
is_root_complex(di_prom_handle_t ph,di_node_t di)116fc256490SJason Beloro is_root_complex(di_prom_handle_t ph, di_node_t di)
117fc256490SJason Beloro {
118fc256490SJason Beloro 	int	len;
119fc256490SJason Beloro 	char	*type;
120fc256490SJason Beloro 
121fc256490SJason Beloro 	len = di_prom_prop_lookup_strings(ph, di, "device_type", &type);
122fc256490SJason Beloro 	if ((len == 0) || (type == NULL))
123fc256490SJason Beloro 		return (B_FALSE);
124fc256490SJason Beloro 
125fc256490SJason Beloro 	if (strcmp(type, PCIEX) != 0)
126fc256490SJason Beloro 		return (B_FALSE);
127fc256490SJason Beloro 
128fc256490SJason Beloro 	/*
129fc256490SJason Beloro 	 * A root complex node is directly under the root node.  So, if
130fc256490SJason Beloro 	 * 'di' is not the root node, and its parent has no parent,
131fc256490SJason Beloro 	 * then 'di' represents a root complex node.
132fc256490SJason Beloro 	 */
133fc256490SJason Beloro 	return ((di_parent_node(di) != DI_NODE_NIL) &&
134fc256490SJason Beloro 	    (di_parent_node(di_parent_node(di)) == DI_NODE_NIL));
135fc256490SJason Beloro }
136fc256490SJason Beloro 
137fc256490SJason Beloro /*
138fc256490SJason Beloro  * String properties in the prom can contain multiple null-terminated
139fc256490SJason Beloro  * strings which are concatenated together.  We must represent them in
140fc256490SJason Beloro  * an MD as a data property.  This function retrieves such a property
141fc256490SJason Beloro  * and adds it to the MD.  If the 'alt_name' PROM property exists then
142fc256490SJason Beloro  * the MD property is created with the value of the PROM 'alt_name'
143fc256490SJason Beloro  * property, otherwise it is created with the value of the PROM 'name'
144fc256490SJason Beloro  * property.
145fc256490SJason Beloro  */
146fc256490SJason Beloro 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)147fc256490SJason Beloro add_prom_string_prop(di_prom_handle_t ph,
148fc256490SJason Beloro     mmd_t *mdp, md_node_t *np, di_node_t di, char *name, char *alt_name)
149fc256490SJason Beloro {
150fc256490SJason Beloro 	int		count;
151fc256490SJason Beloro 	char		*pp_data = NULL;
152fc256490SJason Beloro 	char		*str;
153fc256490SJason Beloro 	int		rv = 0;
154fc256490SJason Beloro 
155fc256490SJason Beloro 	if (alt_name != NULL) {
156fc256490SJason Beloro 		count = di_prom_prop_lookup_strings(ph, di, alt_name, &pp_data);
157fc256490SJason Beloro 	}
158fc256490SJason Beloro 	if (pp_data == NULL) {
159fc256490SJason Beloro 		count = di_prom_prop_lookup_strings(ph, di, name, &pp_data);
160fc256490SJason Beloro 	}
161fc256490SJason Beloro 
162fc256490SJason Beloro 	if (count > 0 && pp_data != NULL) {
163fc256490SJason Beloro 		for (str = pp_data; count > 0; str += strlen(str) + 1)
164fc256490SJason Beloro 			count--;
165fc256490SJason Beloro 		rv = md_add_data_property(mdp,
166fc256490SJason Beloro 		    np, name, str - pp_data, (uint8_t *)pp_data);
167fc256490SJason Beloro 	}
168fc256490SJason Beloro 	return (rv);
169fc256490SJason Beloro }
170fc256490SJason Beloro 
171fc256490SJason Beloro /*
172fc256490SJason Beloro  * Add an int property 'name' to an MD from an existing PROM property. If
173fc256490SJason Beloro  * the 'alt_name' PROM property exists then the MD property is created with
174fc256490SJason Beloro  * the value of the PROM 'alt_name' property, otherwise it is created with
175fc256490SJason Beloro  * the value of the PROM 'name' property.
176fc256490SJason Beloro  */
177fc256490SJason Beloro 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)178fc256490SJason Beloro add_prom_int_prop(di_prom_handle_t ph,
179fc256490SJason Beloro     mmd_t *mdp, md_node_t *np, di_node_t di, char *name, char *alt_name)
180fc256490SJason Beloro {
181fc256490SJason Beloro 	int		count;
182fc256490SJason Beloro 	int		rv = 0;
183fc256490SJason Beloro 	int		*pp_data = NULL;
184fc256490SJason Beloro 
185fc256490SJason Beloro 	if (alt_name != NULL) {
186fc256490SJason Beloro 		count = di_prom_prop_lookup_ints(ph, di, alt_name, &pp_data);
187fc256490SJason Beloro 	}
188fc256490SJason Beloro 	if (pp_data == NULL) {
189fc256490SJason Beloro 		count = di_prom_prop_lookup_ints(ph, di, name, &pp_data);
190fc256490SJason Beloro 	}
191fc256490SJason Beloro 
192fc256490SJason Beloro 	/*
193fc256490SJason Beloro 	 * Note: We know that the properties of interest contain a
194fc256490SJason Beloro 	 * a single int.
195fc256490SJason Beloro 	 */
196fc256490SJason Beloro 	if (count > 0 && pp_data != NULL) {
197fc256490SJason Beloro 		ASSERT(count == 1);
198fc256490SJason Beloro 		rv = md_add_value_property(mdp, np, name, *pp_data);
199fc256490SJason Beloro 	}
200fc256490SJason Beloro 	return (rv);
201fc256490SJason Beloro }
202fc256490SJason Beloro 
203fc256490SJason Beloro 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)204fc256490SJason Beloro link_device_node(mmd_t *mdp,
205fc256490SJason Beloro     di_prom_handle_t ph, di_node_t di, md_node_t *node, char *path)
206fc256490SJason Beloro {
207fc256490SJason Beloro 	md_node_t	*np;
208fc256490SJason Beloro 
209fc256490SJason Beloro 	np = md_link_new_node(mdp, "iodevice", node, "fwd", "back");
210fc256490SJason Beloro 	if (np == NULL)
211fc256490SJason Beloro 		return (NULL);
212fc256490SJason Beloro 
213fc256490SJason Beloro 	/* Add the properties from the devinfo node. */
214fc256490SJason Beloro 	if (md_add_string_property(mdp, np, "dev_path", path) != 0)
215fc256490SJason Beloro 		goto fail;
216fc256490SJason Beloro 
217fc256490SJason Beloro 	/* Add the required properties for this node. */
218fc256490SJason Beloro 	if (add_prom_string_prop(ph, mdp, np, di, "device_type", NULL) != 0)
219fc256490SJason Beloro 		goto fail;
220fc256490SJason Beloro 
221fc256490SJason Beloro 	if (add_prom_string_prop(ph, mdp, np, di, "compatible", NULL) != 0)
222fc256490SJason Beloro 		goto fail;
223fc256490SJason Beloro 
224fc256490SJason Beloro 	if (add_prom_int_prop(ph,
225fc256490SJason Beloro 	    mdp, np, di, "device-id", "real-device-id") != 0)
226fc256490SJason Beloro 		goto fail;
227fc256490SJason Beloro 
228fc256490SJason Beloro 	if (add_prom_int_prop(ph,
229fc256490SJason Beloro 	    mdp, np, di, "vendor-id", "real-vendor-id") != 0)
230fc256490SJason Beloro 		goto fail;
231fc256490SJason Beloro 
232fc256490SJason Beloro 	if (add_prom_int_prop(ph,
233fc256490SJason Beloro 	    mdp, np, di, "class-code", "real-class-code") != 0)
234fc256490SJason Beloro 		goto fail;
235fc256490SJason Beloro 
236fc256490SJason Beloro 	return (np);
237fc256490SJason Beloro 
238fc256490SJason Beloro fail:
239fc256490SJason Beloro 	md_free_node(mdp, np);
240fc256490SJason Beloro 	return (NULL);
241fc256490SJason Beloro }
242fc256490SJason Beloro 
243fc256490SJason Beloro static int
create_children(mmd_t * mdp,di_prom_handle_t ph,md_node_t * md_parent,di_node_t di_parent)244fc256490SJason Beloro create_children(mmd_t *mdp,
245fc256490SJason Beloro     di_prom_handle_t ph, md_node_t *md_parent, di_node_t di_parent)
246fc256490SJason Beloro {
247fc256490SJason Beloro 	md_node_t	*md_node;
248fc256490SJason Beloro 	md_node_t	*md_child;
249fc256490SJason Beloro 	di_node_t	di_child;
250fc256490SJason Beloro 	char		*path;
251fc256490SJason Beloro 	int		rv;
252fc256490SJason Beloro 
253fc256490SJason Beloro 	path = di_devfs_path(di_parent);
254fc256490SJason Beloro 	if (path == NULL)
255fc256490SJason Beloro 		return (EIO);
256fc256490SJason Beloro 
257fc256490SJason Beloro 	md_node = link_device_node(mdp, ph, di_parent, md_parent, path);
258fc256490SJason Beloro 	di_devfs_path_free(path);
259fc256490SJason Beloro 	if (md_node == NULL) {
260fc256490SJason Beloro 		return (ENOMEM);
261fc256490SJason Beloro 	}
262fc256490SJason Beloro 
263fc256490SJason Beloro 	while ((di_child = di_child_node(di_parent)) != DI_NODE_NIL) {
264fc256490SJason Beloro 		path = di_devfs_path(di_child);
265fc256490SJason Beloro 		if (path != NULL) {
266fc256490SJason Beloro 			md_child = link_device_node(mdp,
267fc256490SJason Beloro 			    ph, di_child, md_node, path);
268fc256490SJason Beloro 			di_devfs_path_free(path);
269fc256490SJason Beloro 			if (md_child == NULL) {
270fc256490SJason Beloro 				return (ENOMEM);
271fc256490SJason Beloro 			}
272fc256490SJason Beloro 		}
273fc256490SJason Beloro 
274fc256490SJason Beloro 		rv = create_peers(mdp, ph, md_node, di_child);
275fc256490SJason Beloro 		if (rv != 0)
276fc256490SJason Beloro 			return (rv);
277fc256490SJason Beloro 
278fc256490SJason Beloro 		md_node = md_child;
279fc256490SJason Beloro 		di_parent = di_child;
280fc256490SJason Beloro 	}
281fc256490SJason Beloro 	return (0);
282fc256490SJason Beloro }
283fc256490SJason Beloro 
284fc256490SJason Beloro static int
create_peers(mmd_t * mdp,di_prom_handle_t ph,md_node_t * node,di_node_t dev)285fc256490SJason Beloro create_peers(mmd_t *mdp, di_prom_handle_t ph, md_node_t *node, di_node_t dev)
286fc256490SJason Beloro {
287fc256490SJason Beloro 	di_node_t	di_peer;
288fc256490SJason Beloro 	int		rv;
289fc256490SJason Beloro 
290fc256490SJason Beloro 	while ((di_peer = di_sibling_node(dev)) != DI_NODE_NIL) {
291fc256490SJason Beloro 		rv = create_children(mdp, ph, node, di_peer);
292fc256490SJason Beloro 		if (rv != 0)
293fc256490SJason Beloro 			return (rv);
294fc256490SJason Beloro 		dev = di_peer;
295fc256490SJason Beloro 	}
296fc256490SJason Beloro 	return (0);
297fc256490SJason Beloro }
298fc256490SJason Beloro 
299fc256490SJason Beloro static int
device_tree_to_md(mmd_t * mdp,md_node_t * top)300fc256490SJason Beloro device_tree_to_md(mmd_t *mdp, md_node_t *top)
301fc256490SJason Beloro {
302fc256490SJason Beloro 	di_node_t		node;
303fc256490SJason Beloro 	di_node_t		root;
304fc256490SJason Beloro 	di_prom_handle_t	ph;
305fc256490SJason Beloro 	int			rv = 0;
306fc256490SJason Beloro 
307fc256490SJason Beloro 	root = di_init("/", DINFOSUBTREE | DINFOPROP);
308fc256490SJason Beloro 
309fc256490SJason Beloro 	if (root == DI_NODE_NIL) {
310fc256490SJason Beloro 		LDMA_ERR("di_init cannot find device tree root node.");
311fc256490SJason Beloro 		return (errno);
312fc256490SJason Beloro 	}
313fc256490SJason Beloro 
314fc256490SJason Beloro 	ph = di_prom_init();
315fc256490SJason Beloro 	if (ph == DI_PROM_HANDLE_NIL) {
316fc256490SJason Beloro 		LDMA_ERR("di_prom_init failed.");
317fc256490SJason Beloro 		di_fini(root);
318fc256490SJason Beloro 		return (errno);
319fc256490SJason Beloro 	}
320fc256490SJason Beloro 
321fc256490SJason Beloro 	node = di_child_node(root);
322fc256490SJason Beloro 	while (node != NULL) {
323fc256490SJason Beloro 		if (is_root_complex(ph, node)) {
324fc256490SJason Beloro 			rv = create_children(mdp, ph, top, node);
325fc256490SJason Beloro 			if (rv != 0)
326fc256490SJason Beloro 				break;
327fc256490SJason Beloro 		}
328fc256490SJason Beloro 		node = di_sibling_node(node);
329fc256490SJason Beloro 	}
330fc256490SJason Beloro 
331fc256490SJason Beloro 	di_prom_fini(ph);
332fc256490SJason Beloro 	di_fini(root);
333fc256490SJason Beloro 	return (rv);
334fc256490SJason Beloro }
335fc256490SJason Beloro 
336fc256490SJason Beloro static int
get_devinfo(uint8_t ** mdpp,size_t * size)337fc256490SJason Beloro get_devinfo(uint8_t **mdpp, size_t *size)
338fc256490SJason Beloro {
339fc256490SJason Beloro 	mmd_t		*mdp;
340fc256490SJason Beloro 	md_node_t	*rootp;
341fc256490SJason Beloro 	size_t		md_size;
342fc256490SJason Beloro 	uint8_t		*md_bufp;
343fc256490SJason Beloro 
344fc256490SJason Beloro 	mdp = md_new_md();
345fc256490SJason Beloro 	if (mdp == NULL) {
346fc256490SJason Beloro 		return (ENOMEM);
347fc256490SJason Beloro 	}
348fc256490SJason Beloro 	rootp = md_new_node(mdp, "root");
349fc256490SJason Beloro 	if (rootp == NULL) {
350fc256490SJason Beloro 		md_destroy(mdp);
351fc256490SJason Beloro 		return (ENOMEM);
352fc256490SJason Beloro 	}
353fc256490SJason Beloro 
354fc256490SJason Beloro 	if (device_tree_to_md(mdp, rootp) != 0) {
355fc256490SJason Beloro 		md_destroy(mdp);
356fc256490SJason Beloro 		return (ENOMEM);
357fc256490SJason Beloro 	}
358fc256490SJason Beloro 	md_size = (int)md_gen_bin(mdp, &md_bufp);
359fc256490SJason Beloro 
360fc256490SJason Beloro 	if (md_size == 0) {
361fc256490SJason Beloro 		md_destroy(mdp);
362fc256490SJason Beloro 		return (EIO);
363fc256490SJason Beloro 	}
364fc256490SJason Beloro 	*mdpp = md_bufp;
365fc256490SJason Beloro 	*size = md_size;
366fc256490SJason Beloro 
367fc256490SJason Beloro 	md_destroy(mdp);
368fc256490SJason Beloro 	return (0);
369fc256490SJason Beloro }
370