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