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 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 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 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 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 * 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 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 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 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 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