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