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