18fea755aSjm22469 /* 28fea755aSjm22469 * CDDL HEADER START 38fea755aSjm22469 * 48fea755aSjm22469 * The contents of this file are subject to the terms of the 58fea755aSjm22469 * Common Development and Distribution License (the "License"). 68fea755aSjm22469 * You may not use this file except in compliance with the License. 78fea755aSjm22469 * 88fea755aSjm22469 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 98fea755aSjm22469 * or http://www.opensolaris.org/os/licensing. 108fea755aSjm22469 * See the License for the specific language governing permissions 118fea755aSjm22469 * and limitations under the License. 128fea755aSjm22469 * 138fea755aSjm22469 * When distributing Covered Code, include this CDDL HEADER in each 148fea755aSjm22469 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 158fea755aSjm22469 * If applicable, add the following below this CDDL HEADER, with the 168fea755aSjm22469 * fields enclosed by brackets "[]" replaced with your own identifying 178fea755aSjm22469 * information: Portions Copyright [yyyy] [name of copyright owner] 188fea755aSjm22469 * 198fea755aSjm22469 * CDDL HEADER END 208fea755aSjm22469 */ 218fea755aSjm22469 228fea755aSjm22469 /* 238fea755aSjm22469 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 248fea755aSjm22469 * Use is subject to license terms. 258fea755aSjm22469 */ 268fea755aSjm22469 278fea755aSjm22469 /* 288fea755aSjm22469 * sun4v VIO DR Module 298fea755aSjm22469 */ 308fea755aSjm22469 318fea755aSjm22469 #include <sys/modctl.h> 328fea755aSjm22469 #include <sys/sunddi.h> 338fea755aSjm22469 #include <sys/sunndi.h> 348fea755aSjm22469 #include <sys/note.h> 358fea755aSjm22469 #include <sys/sysevent/dr.h> 368fea755aSjm22469 #include <sys/hypervisor_api.h> 378fea755aSjm22469 #include <sys/mach_descrip.h> 388fea755aSjm22469 #include <sys/mdesc.h> 398fea755aSjm22469 #include <sys/mdesc_impl.h> 408fea755aSjm22469 #include <sys/ds.h> 418fea755aSjm22469 #include <sys/drctl.h> 428fea755aSjm22469 #include <sys/dr_util.h> 438fea755aSjm22469 #include <sys/dr_io.h> 448fea755aSjm22469 #include <sys/promif.h> 458fea755aSjm22469 #include <sys/machsystm.h> 468fea755aSjm22469 #include <sys/ethernet.h> 478fea755aSjm22469 #include <sys/hotplug/pci/pcicfg.h> 488fea755aSjm22469 498fea755aSjm22469 508fea755aSjm22469 static struct modlmisc modlmisc = { 518fea755aSjm22469 &mod_miscops, 52f500b196SRichard Bean "sun4v VIO DR" 538fea755aSjm22469 }; 548fea755aSjm22469 558fea755aSjm22469 static struct modlinkage modlinkage = { 568fea755aSjm22469 MODREV_1, 578fea755aSjm22469 (void *)&modlmisc, 588fea755aSjm22469 NULL 598fea755aSjm22469 }; 608fea755aSjm22469 618fea755aSjm22469 628fea755aSjm22469 /* 638fea755aSjm22469 * VIO DS Interface 648fea755aSjm22469 */ 658fea755aSjm22469 668fea755aSjm22469 /* 678fea755aSjm22469 * Global DS Handle 688fea755aSjm22469 */ 698fea755aSjm22469 static ds_svc_hdl_t ds_vio_handle; 708fea755aSjm22469 718fea755aSjm22469 /* 728fea755aSjm22469 * Supported DS Capability Versions 738fea755aSjm22469 */ 748fea755aSjm22469 static ds_ver_t dr_vio_vers[] = { { 1, 0 } }; 758fea755aSjm22469 #define DR_VIO_NVERS (sizeof (dr_vio_vers) / sizeof (dr_vio_vers[0])) 768fea755aSjm22469 778fea755aSjm22469 /* 788fea755aSjm22469 * DS Capability Description 798fea755aSjm22469 */ 808fea755aSjm22469 static ds_capability_t dr_vio_cap = { 818fea755aSjm22469 DR_VIO_DS_ID, /* svc_id */ 828fea755aSjm22469 dr_vio_vers, /* vers */ 838fea755aSjm22469 DR_VIO_NVERS /* nvers */ 848fea755aSjm22469 }; 858fea755aSjm22469 868fea755aSjm22469 /* 878fea755aSjm22469 * DS Callbacks 888fea755aSjm22469 */ 898fea755aSjm22469 static void dr_vio_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t); 908fea755aSjm22469 static void dr_vio_unreg_handler(ds_cb_arg_t arg); 918fea755aSjm22469 static void dr_vio_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen); 928fea755aSjm22469 938fea755aSjm22469 /* 948fea755aSjm22469 * DS Client Ops Vector 958fea755aSjm22469 */ 968fea755aSjm22469 static ds_clnt_ops_t dr_vio_ops = { 978fea755aSjm22469 dr_vio_reg_handler, /* ds_reg_cb */ 988fea755aSjm22469 dr_vio_unreg_handler, /* ds_unreg_cb */ 998fea755aSjm22469 dr_vio_data_handler, /* ds_data_cb */ 1008fea755aSjm22469 NULL /* cb_arg */ 1018fea755aSjm22469 }; 1028fea755aSjm22469 1038fea755aSjm22469 1048fea755aSjm22469 typedef struct { 1058fea755aSjm22469 char *name; 1068fea755aSjm22469 uint64_t devid; 1078fea755aSjm22469 dev_info_t *dip; 1088fea755aSjm22469 } dr_search_arg_t; 1098fea755aSjm22469 1108fea755aSjm22469 static int 1118fea755aSjm22469 dr_io_check_node(dev_info_t *dip, void *arg) 1128fea755aSjm22469 { 1138fea755aSjm22469 char *name; 1148fea755aSjm22469 uint64_t devid; 1158fea755aSjm22469 dr_search_arg_t *sarg = (dr_search_arg_t *)arg; 1168fea755aSjm22469 1178fea755aSjm22469 name = ddi_node_name(dip); 1188fea755aSjm22469 1198fea755aSjm22469 if (strcmp(name, sarg->name) != 0) 1208fea755aSjm22469 return (DDI_WALK_CONTINUE); 1218fea755aSjm22469 1228fea755aSjm22469 devid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1238fea755aSjm22469 "reg", -1); 1248fea755aSjm22469 1258fea755aSjm22469 DR_DBG_IO("%s: found devid=%ld, looking for %ld\n", 1268fea755aSjm22469 __func__, devid, sarg->devid); 1278fea755aSjm22469 1288fea755aSjm22469 if (devid == sarg->devid) { 1298fea755aSjm22469 DR_DBG_IO("%s: matched", __func__); 1308fea755aSjm22469 1318fea755aSjm22469 /* matching node must be returned held */ 1328fea755aSjm22469 if (!e_ddi_branch_held(dip)) 1338fea755aSjm22469 e_ddi_branch_hold(dip); 1348fea755aSjm22469 1358fea755aSjm22469 sarg->dip = dip; 1368fea755aSjm22469 return (DDI_WALK_TERMINATE); 1378fea755aSjm22469 } 1388fea755aSjm22469 1398fea755aSjm22469 return (DDI_WALK_CONTINUE); 1408fea755aSjm22469 } 1418fea755aSjm22469 1428fea755aSjm22469 /* 1438fea755aSjm22469 * Walk the device tree to find the dip corresponding to the devid 1448fea755aSjm22469 * passed in. If present, the dip is returned held. The caller must 1458fea755aSjm22469 * release the hold on the dip once it is no longer required. If no 1468fea755aSjm22469 * matching node if found, NULL is returned. 1478fea755aSjm22469 */ 1488fea755aSjm22469 static dev_info_t * 1498fea755aSjm22469 dr_io_find_node(char *name, uint64_t devid) 1508fea755aSjm22469 { 1518fea755aSjm22469 dr_search_arg_t arg; 1528fea755aSjm22469 1538fea755aSjm22469 DR_DBG_IO("dr_io_find_node...\n"); 1548fea755aSjm22469 1558fea755aSjm22469 arg.name = name; 1568fea755aSjm22469 arg.devid = devid; 1578fea755aSjm22469 arg.dip = NULL; 1588fea755aSjm22469 1598fea755aSjm22469 ddi_walk_devs(ddi_root_node(), dr_io_check_node, &arg); 1608fea755aSjm22469 1618fea755aSjm22469 ASSERT((arg.dip == NULL) || (e_ddi_branch_held(arg.dip))); 1628fea755aSjm22469 1638fea755aSjm22469 return ((arg.dip) ? arg.dip : NULL); 1648fea755aSjm22469 } 1658fea755aSjm22469 1668fea755aSjm22469 /* 1678fea755aSjm22469 * Look up a particular IO node in the MD. Returns the mde_cookie_t 1688fea755aSjm22469 * representing that IO node if present, and MDE_INVAL_ELEM_COOKIE otherwise. 1698fea755aSjm22469 * It is assumed the scratch array has already been allocated so that 1708fea755aSjm22469 * it can accommodate the worst case scenario, every node in the MD. 1718fea755aSjm22469 */ 1728fea755aSjm22469 static mde_cookie_t 1738fea755aSjm22469 dr_io_find_node_md(md_t *mdp, char *name, uint64_t id, mde_cookie_t *listp) 1748fea755aSjm22469 { 1758fea755aSjm22469 int i; 1768fea755aSjm22469 int nnodes; 1778fea755aSjm22469 char *devnm; 1788fea755aSjm22469 uint64_t devid; 1798fea755aSjm22469 mde_cookie_t rootnode; 1808fea755aSjm22469 mde_cookie_t result = MDE_INVAL_ELEM_COOKIE; 1818fea755aSjm22469 1828fea755aSjm22469 DR_DBG_IO("%s: %s@%ld\n", __func__, name, id); 1838fea755aSjm22469 1848fea755aSjm22469 rootnode = md_root_node(mdp); 1858fea755aSjm22469 ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE); 1868fea755aSjm22469 1878fea755aSjm22469 /* 1888fea755aSjm22469 * Scan the DAG for all candidate nodes. 1898fea755aSjm22469 */ 1908fea755aSjm22469 nnodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "virtual-device"), 1918fea755aSjm22469 md_find_name(mdp, "fwd"), listp); 1928fea755aSjm22469 1938fea755aSjm22469 if (nnodes < 0) { 1948fea755aSjm22469 DR_DBG_IO("%s: scan for " 1958fea755aSjm22469 "'virtual-device' nodes failed\n", __func__); 1968fea755aSjm22469 return (result); 1978fea755aSjm22469 } 1988fea755aSjm22469 1998fea755aSjm22469 DR_DBG_IO("%s: found %d nodes in the MD\n", __func__, nnodes); 2008fea755aSjm22469 2018fea755aSjm22469 /* 2028fea755aSjm22469 * Find the node of interest 2038fea755aSjm22469 */ 2048fea755aSjm22469 for (i = 0; i < nnodes; i++) { 2058fea755aSjm22469 2068fea755aSjm22469 if (md_get_prop_str(mdp, listp[i], "name", &devnm)) { 2078fea755aSjm22469 DR_DBG_IO("%s: missing 'name' property for" 2088fea755aSjm22469 " IO node %d\n", __func__, i); 2098fea755aSjm22469 return (DDI_WALK_ERROR); 2108fea755aSjm22469 } 2118fea755aSjm22469 2128fea755aSjm22469 if (strcmp(devnm, name) != 0) 2138fea755aSjm22469 continue; 2148fea755aSjm22469 2158fea755aSjm22469 if (md_get_prop_val(mdp, listp[i], "cfg-handle", &devid)) { 2168fea755aSjm22469 DR_DBG_IO("%s: missing 'cfg-handle' property for" 2178fea755aSjm22469 " IO node %d\n", __func__, i); 2188fea755aSjm22469 break; 2198fea755aSjm22469 } 2208fea755aSjm22469 2218fea755aSjm22469 if (devid == id) { 2228fea755aSjm22469 /* found a match */ 2238fea755aSjm22469 DR_DBG_IO("%s: found IO node %s@%ld " 2248fea755aSjm22469 "in MD\n", __func__, name, id); 2258fea755aSjm22469 result = listp[i]; 2268fea755aSjm22469 break; 2278fea755aSjm22469 } 2288fea755aSjm22469 } 2298fea755aSjm22469 2308fea755aSjm22469 if (result == MDE_INVAL_ELEM_COOKIE) 2318fea755aSjm22469 DR_DBG_IO("%s: IO node %ld not in MD\n", __func__, id); 2328fea755aSjm22469 2338fea755aSjm22469 return (result); 2348fea755aSjm22469 } 2358fea755aSjm22469 2368fea755aSjm22469 typedef struct { 2378fea755aSjm22469 md_t *mdp; 2388fea755aSjm22469 mde_cookie_t node; 2398fea755aSjm22469 dev_info_t *dip; 2408fea755aSjm22469 } cb_arg_t; 2418fea755aSjm22469 2428fea755aSjm22469 #define STR_ARR_LEN 5 2438fea755aSjm22469 2448fea755aSjm22469 static int 2458fea755aSjm22469 new_dev_node(dev_info_t *new_node, void *arg, uint_t flags) 2468fea755aSjm22469 { 2478fea755aSjm22469 _NOTE(ARGUNUSED(flags)) 2488fea755aSjm22469 2498fea755aSjm22469 cb_arg_t *cba; 2508fea755aSjm22469 char *devnm, *devtype; 2518fea755aSjm22469 char *compat; 2528fea755aSjm22469 uint64_t devid; 2538fea755aSjm22469 int len = 0; 2548fea755aSjm22469 char *curr; 2558fea755aSjm22469 int i = 0; 2568fea755aSjm22469 char *str_arr[STR_ARR_LEN]; 2578fea755aSjm22469 2588fea755aSjm22469 cba = (cb_arg_t *)arg; 2598fea755aSjm22469 2608fea755aSjm22469 /* 2618fea755aSjm22469 * Add 'name' property 2628fea755aSjm22469 */ 2638fea755aSjm22469 if (md_get_prop_str(cba->mdp, cba->node, "name", &devnm)) { 2648fea755aSjm22469 DR_DBG_IO("%s: failed to read 'name' prop from MD\n", __func__); 2658fea755aSjm22469 return (DDI_WALK_ERROR); 2668fea755aSjm22469 } 2678fea755aSjm22469 DR_DBG_IO("%s: device name is %s\n", __func__, devnm); 2688fea755aSjm22469 2698fea755aSjm22469 if (ndi_prop_update_string(DDI_DEV_T_NONE, new_node, 2708fea755aSjm22469 "name", devnm) != DDI_SUCCESS) { 2718fea755aSjm22469 DR_DBG_IO("%s: failed to create 'name' prop\n", __func__); 2728fea755aSjm22469 return (DDI_WALK_ERROR); 2738fea755aSjm22469 } 2748fea755aSjm22469 2758fea755aSjm22469 /* 2768fea755aSjm22469 * Add 'compatible' property 2778fea755aSjm22469 */ 2788fea755aSjm22469 if (md_get_prop_data(cba->mdp, cba->node, "compatible", 2798fea755aSjm22469 (uint8_t **)&compat, &len)) { 2808fea755aSjm22469 DR_DBG_IO("%s: failed to read " 2818fea755aSjm22469 "'compatible' prop from MD\n", __func__); 2828fea755aSjm22469 return (DDI_WALK_ERROR); 2838fea755aSjm22469 } 2848fea755aSjm22469 2858fea755aSjm22469 /* parse the MD string array */ 2868fea755aSjm22469 curr = compat; 2878fea755aSjm22469 while (curr < (compat + len)) { 2888fea755aSjm22469 2898fea755aSjm22469 DR_DBG_IO("%s: adding '%s' to " 2908fea755aSjm22469 "'compatible' prop\n", __func__, curr); 2918fea755aSjm22469 2928fea755aSjm22469 str_arr[i++] = curr; 2938fea755aSjm22469 curr += strlen(curr) + 1; 2948fea755aSjm22469 2958fea755aSjm22469 if (i == STR_ARR_LEN) { 2968fea755aSjm22469 DR_DBG_CPU("exceeded str_arr len (%d)\n", STR_ARR_LEN); 2978fea755aSjm22469 break; 2988fea755aSjm22469 } 2998fea755aSjm22469 } 3008fea755aSjm22469 3018fea755aSjm22469 3028fea755aSjm22469 if (ndi_prop_update_string_array(DDI_DEV_T_NONE, new_node, 3038fea755aSjm22469 "compatible", str_arr, i) != DDI_SUCCESS) { 3048fea755aSjm22469 DR_DBG_IO("%s: cannot create 'compatible' prop\n", __func__); 3058fea755aSjm22469 return (DDI_WALK_ERROR); 3068fea755aSjm22469 } 3078fea755aSjm22469 3088fea755aSjm22469 /* 3098fea755aSjm22469 * Add 'device_type' property 3108fea755aSjm22469 */ 3118fea755aSjm22469 if (md_get_prop_str(cba->mdp, cba->node, "device-type", &devtype)) { 3128fea755aSjm22469 DR_DBG_IO("%s: failed to read " 3138fea755aSjm22469 "'device-type' prop from MD\n", __func__); 3148fea755aSjm22469 return (DDI_WALK_ERROR); 3158fea755aSjm22469 } 3168fea755aSjm22469 if (ndi_prop_update_string(DDI_DEV_T_NONE, new_node, 3178fea755aSjm22469 "device_type", devtype) != DDI_SUCCESS) { 3188fea755aSjm22469 DR_DBG_IO("%s: failed to create " 3198fea755aSjm22469 "'device-type' prop\n", __func__); 3208fea755aSjm22469 return (DDI_WALK_ERROR); 3218fea755aSjm22469 } 3228fea755aSjm22469 3238fea755aSjm22469 DR_DBG_IO("%s: device type is %s\n", __func__, devtype); 3248fea755aSjm22469 3258fea755aSjm22469 /* 3268fea755aSjm22469 * Add 'reg' (cfg-handle) property 3278fea755aSjm22469 */ 3288fea755aSjm22469 if (md_get_prop_val(cba->mdp, cba->node, "cfg-handle", &devid)) { 3298fea755aSjm22469 DR_DBG_IO("%s: failed to read " 3308fea755aSjm22469 "'cfg-handle' prop from MD\n", __func__); 3318fea755aSjm22469 return (DDI_WALK_ERROR); 3328fea755aSjm22469 } 3338fea755aSjm22469 3348fea755aSjm22469 DR_DBG_IO("%s: new device is %s@%ld\n", __func__, devnm, devid); 3358fea755aSjm22469 3368fea755aSjm22469 if (ndi_prop_update_int(DDI_DEV_T_NONE, new_node, "reg", devid) 3378fea755aSjm22469 != DDI_SUCCESS) { 3388fea755aSjm22469 DR_DBG_IO("%s: failed to create 'reg' prop\n", __func__); 3398fea755aSjm22469 return (DDI_WALK_ERROR); 3408fea755aSjm22469 } 3418fea755aSjm22469 3428fea755aSjm22469 /* if vnet/vswitch, probe and add mac-address and mtu properties */ 3438fea755aSjm22469 if (strcmp(devnm, "vsw") == 0 || strcmp(devnm, "network") == 0) { 3448fea755aSjm22469 3458fea755aSjm22469 int i, j; 3468fea755aSjm22469 uint64_t mtu, macaddr; 3478fea755aSjm22469 uchar_t maddr_arr[ETHERADDRL]; 3488fea755aSjm22469 3498fea755aSjm22469 if (md_get_prop_val(cba->mdp, cba->node, "local-mac-address", 3508fea755aSjm22469 &macaddr)) { 3518fea755aSjm22469 DR_DBG_IO("%s: failed to read " 3528fea755aSjm22469 "'local-mac-address' prop from MD\n", __func__); 3538fea755aSjm22469 return (DDI_WALK_ERROR); 3548fea755aSjm22469 } 3558fea755aSjm22469 3568fea755aSjm22469 for (i = 0, j = (ETHERADDRL - 1); i < ETHERADDRL; i++, j--) 3578fea755aSjm22469 maddr_arr[j] = (macaddr >> (i * 8)) & 0xff; 3588fea755aSjm22469 3598fea755aSjm22469 if (ndi_prop_update_byte_array(DDI_DEV_T_NONE, new_node, 3608fea755aSjm22469 "local-mac-address", maddr_arr, ETHERADDRL) 3618fea755aSjm22469 != DDI_SUCCESS) { 3628fea755aSjm22469 DR_DBG_IO("%s: failed to create " 3638fea755aSjm22469 "'local-mac-address' prop\n", __func__); 3648fea755aSjm22469 return (DDI_WALK_ERROR); 3658fea755aSjm22469 } 3668fea755aSjm22469 3678fea755aSjm22469 if (md_get_prop_val(cba->mdp, cba->node, "mtu", &mtu)) { 3688fea755aSjm22469 DR_DBG_IO("%s: failed to read " 3698fea755aSjm22469 "'mtu' prop from MD\n", __func__); 3708fea755aSjm22469 return (DDI_WALK_ERROR); 3718fea755aSjm22469 } 3728fea755aSjm22469 3738fea755aSjm22469 if (ndi_prop_update_int64(DDI_DEV_T_NONE, new_node, "mtu", 3748fea755aSjm22469 mtu) != DDI_SUCCESS) { 3758fea755aSjm22469 DR_DBG_IO("%s: failed to " 3768fea755aSjm22469 "create 'mtu' prop\n", __func__); 3778fea755aSjm22469 return (DDI_WALK_ERROR); 3788fea755aSjm22469 } 3798fea755aSjm22469 3808fea755aSjm22469 DR_DBG_IO("%s: Added properties for %s@%ld, " 3818fea755aSjm22469 "mac=%ld, mtu=%ld\n", __func__, devnm, devid, macaddr, mtu); 3828fea755aSjm22469 } 3838fea755aSjm22469 3848fea755aSjm22469 cba->dip = new_node; 3858fea755aSjm22469 3868fea755aSjm22469 return (DDI_WALK_TERMINATE); 3878fea755aSjm22469 } 3888fea755aSjm22469 3898fea755aSjm22469 /* 3908fea755aSjm22469 * Find the parent node of the argument virtual device node in 3918fea755aSjm22469 * the MD. For virtual devices, the parent is always 3928fea755aSjm22469 * "channel-devices", so scan the MD using the "back" arcs 3938fea755aSjm22469 * looking for a node with that name. 3948fea755aSjm22469 */ 3958fea755aSjm22469 static mde_cookie_t 3968fea755aSjm22469 dr_vio_find_parent_md(md_t *mdp, mde_cookie_t node) 3978fea755aSjm22469 { 3988fea755aSjm22469 int max_nodes; 3998fea755aSjm22469 int num_nodes; 4008fea755aSjm22469 int listsz; 4018fea755aSjm22469 mde_cookie_t *listp; 4028fea755aSjm22469 mde_cookie_t pnode = MDE_INVAL_ELEM_COOKIE; 4038fea755aSjm22469 4048fea755aSjm22469 max_nodes = md_node_count(mdp); 4058fea755aSjm22469 listsz = max_nodes * sizeof (mde_cookie_t); 4068fea755aSjm22469 listp = kmem_zalloc(listsz, KM_SLEEP); 407*99c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %d\n", 408*99c7e855SJames Marks - Sun Microsystems __func__, (void *)listp, listsz); 4098fea755aSjm22469 4108fea755aSjm22469 num_nodes = md_scan_dag(mdp, node, 4118fea755aSjm22469 md_find_name(mdp, "channel-devices"), 4128fea755aSjm22469 md_find_name(mdp, "back"), listp); 4138fea755aSjm22469 4148fea755aSjm22469 ASSERT(num_nodes == 1); 4158fea755aSjm22469 4168fea755aSjm22469 if (num_nodes == 1) 4178fea755aSjm22469 pnode = listp[0]; 4188fea755aSjm22469 419*99c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %d\n", 420*99c7e855SJames Marks - Sun Microsystems __func__, (void *)listp, listsz); 4218fea755aSjm22469 kmem_free(listp, listsz); 4228fea755aSjm22469 4238fea755aSjm22469 return (pnode); 4248fea755aSjm22469 } 4258fea755aSjm22469 4268fea755aSjm22469 static int 4278fea755aSjm22469 dr_io_configure(dr_vio_req_t *req, dr_vio_res_t *res) 4288fea755aSjm22469 { 4298fea755aSjm22469 int rv = ENXIO; 4308fea755aSjm22469 int listsz; 4318fea755aSjm22469 int nnodes; 4328fea755aSjm22469 uint64_t devid = req->dev_id; 4338fea755aSjm22469 uint64_t pdevid; 4348fea755aSjm22469 char *name = req->name; 4358fea755aSjm22469 char *pname; 4368fea755aSjm22469 md_t *mdp = NULL; 4378fea755aSjm22469 mde_cookie_t *listp = NULL; 4388fea755aSjm22469 mde_cookie_t node; 4398fea755aSjm22469 mde_cookie_t pnode; 4408fea755aSjm22469 dev_info_t *pdip = NULL; 4418fea755aSjm22469 dev_info_t *dip; 4428fea755aSjm22469 devi_branch_t br; 4438fea755aSjm22469 cb_arg_t cba; 4448fea755aSjm22469 int drctl_cmd; 4458fea755aSjm22469 int drctl_flags = 0; 4468fea755aSjm22469 drctl_rsrc_t *drctl_req; 4478fea755aSjm22469 size_t drctl_req_len; 448*99c7e855SJames Marks - Sun Microsystems drctl_rsrc_t *drctl_rsrc = NULL; 4498fea755aSjm22469 drctl_cookie_t drctl_res_ck; 4508fea755aSjm22469 char *p; 451*99c7e855SJames Marks - Sun Microsystems drctl_resp_t *drctl_resp; 452*99c7e855SJames Marks - Sun Microsystems size_t drctl_resp_len = 0; 4538fea755aSjm22469 4548fea755aSjm22469 res->result = DR_VIO_RES_FAILURE; 4558fea755aSjm22469 4568fea755aSjm22469 if ((dip = dr_io_find_node(name, devid)) != NULL) { 4578fea755aSjm22469 DR_DBG_IO("%s: %s@%ld already configured\n", 4588fea755aSjm22469 __func__, name, devid); 4598fea755aSjm22469 4608fea755aSjm22469 /* Return success if resources is already there. */ 4618fea755aSjm22469 res->result = DR_VIO_RES_OK; 4628fea755aSjm22469 res->status = DR_VIO_STAT_CONFIGURED; 4638fea755aSjm22469 e_ddi_branch_rele(dip); 4648fea755aSjm22469 return (0); 4658fea755aSjm22469 } 4668fea755aSjm22469 4678fea755aSjm22469 /* Assume we fail to find the node to be added. */ 4688fea755aSjm22469 res->status = DR_VIO_STAT_NOT_PRESENT; 4698fea755aSjm22469 4708fea755aSjm22469 if ((mdp = md_get_handle()) == NULL) { 4718fea755aSjm22469 DR_DBG_IO("%s: unable to initialize MD\n", __func__); 4728fea755aSjm22469 return (ENXIO); 4738fea755aSjm22469 } 4748fea755aSjm22469 4758fea755aSjm22469 nnodes = md_node_count(mdp); 4768fea755aSjm22469 ASSERT(nnodes > 0); 4778fea755aSjm22469 4788fea755aSjm22469 listsz = nnodes * sizeof (mde_cookie_t); 4798fea755aSjm22469 listp = kmem_zalloc(listsz, KM_SLEEP); 480*99c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %d\n", 481*99c7e855SJames Marks - Sun Microsystems __func__, (void *)listp, listsz); 4828fea755aSjm22469 4838fea755aSjm22469 /* 4848fea755aSjm22469 * Get the MD device node. 4858fea755aSjm22469 */ 4868fea755aSjm22469 node = dr_io_find_node_md(mdp, name, devid, listp); 4878fea755aSjm22469 4888fea755aSjm22469 if (node == MDE_INVAL_ELEM_COOKIE) { 4898fea755aSjm22469 DR_DBG_IO("%s: scan for %s name node failed\n", __func__, name); 4908fea755aSjm22469 res->result = DR_VIO_RES_NOT_IN_MD; 4918fea755aSjm22469 goto done; 4928fea755aSjm22469 } 4938fea755aSjm22469 4948fea755aSjm22469 /* 4958fea755aSjm22469 * Get the MD parent node. 4968fea755aSjm22469 */ 4978fea755aSjm22469 pnode = dr_vio_find_parent_md(mdp, node); 4988fea755aSjm22469 if (pnode == MDE_INVAL_ELEM_COOKIE) { 4998fea755aSjm22469 DR_DBG_IO("%s: failed to find MD parent of %lx\n", 5008fea755aSjm22469 __func__, pnode); 5018fea755aSjm22469 goto done; 5028fea755aSjm22469 } 5038fea755aSjm22469 5048fea755aSjm22469 if (md_get_prop_str(mdp, pnode, "name", &pname)) { 5058fea755aSjm22469 DR_DBG_IO("%s: failed to read " 5068fea755aSjm22469 "'name' for pnode %lx from MD\n", __func__, pnode); 5078fea755aSjm22469 goto done; 5088fea755aSjm22469 } 5098fea755aSjm22469 5108fea755aSjm22469 if (md_get_prop_val(mdp, pnode, "cfg-handle", &pdevid)) { 5118fea755aSjm22469 DR_DBG_IO("%s: failed to read 'cfg-handle' " 5128fea755aSjm22469 "for pnode '%s' from MD\n", __func__, pname); 5138fea755aSjm22469 goto done; 5148fea755aSjm22469 } 5158fea755aSjm22469 5168fea755aSjm22469 DR_DBG_IO("%s: parent device %s@%lx\n", __func__, pname, pdevid); 5178fea755aSjm22469 5188fea755aSjm22469 /* 5198fea755aSjm22469 * Get the devinfo parent node. 5208fea755aSjm22469 */ 5218fea755aSjm22469 if ((pdip = dr_io_find_node(pname, pdevid)) == NULL) { 5228fea755aSjm22469 DR_DBG_IO("%s: parent device %s@%ld not found\n", 5238fea755aSjm22469 __func__, pname, pdevid); 5248fea755aSjm22469 goto done; 5258fea755aSjm22469 } 5268fea755aSjm22469 5278fea755aSjm22469 drctl_req_len = sizeof (drctl_rsrc_t) + MAXPATHLEN; 5288fea755aSjm22469 drctl_req = kmem_zalloc(drctl_req_len, KM_SLEEP); 529*99c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %ld\n", 530*99c7e855SJames Marks - Sun Microsystems __func__, (void *)drctl_req, drctl_req_len); 5318fea755aSjm22469 drctl_req->status = DRCTL_STATUS_INIT; 5328fea755aSjm22469 5338fea755aSjm22469 drctl_cmd = DRCTL_IO_CONFIG_REQUEST; 5348fea755aSjm22469 5358fea755aSjm22469 /* 5368fea755aSjm22469 * Construct the path of the device as it will be if it 5378fea755aSjm22469 * is successfully added. 5388fea755aSjm22469 */ 5398fea755aSjm22469 p = drctl_req->res_dev_path; 5408fea755aSjm22469 (void) sprintf(p, "/devices"); 5418fea755aSjm22469 (void) ddi_pathname(pdip, p + strlen(p)); 5428fea755aSjm22469 (void) sprintf(p + strlen(p), "/%s@%ld", name, devid); 5438fea755aSjm22469 DR_DBG_IO("%s: devpath=%s\n", __func__, drctl_req->res_dev_path); 5448fea755aSjm22469 545*99c7e855SJames Marks - Sun Microsystems rv = drctl_config_init(drctl_cmd, drctl_flags, drctl_req, 546*99c7e855SJames Marks - Sun Microsystems 1, &drctl_resp, &drctl_resp_len, &drctl_res_ck); 5478fea755aSjm22469 548*99c7e855SJames Marks - Sun Microsystems ASSERT((drctl_resp != NULL) && (drctl_resp_len != 0)); 549*99c7e855SJames Marks - Sun Microsystems 550*99c7e855SJames Marks - Sun Microsystems drctl_rsrc = drctl_resp->resp_resources; 551*99c7e855SJames Marks - Sun Microsystems 552*99c7e855SJames Marks - Sun Microsystems if (rv != 0) { 5538fea755aSjm22469 DR_DBG_IO("%s: drctl_config_init failed: %d\n", __func__, rv); 554*99c7e855SJames Marks - Sun Microsystems 555*99c7e855SJames Marks - Sun Microsystems ASSERT(drctl_resp->resp_type == DRCTL_RESP_ERR); 556*99c7e855SJames Marks - Sun Microsystems 557*99c7e855SJames Marks - Sun Microsystems (void) strlcpy(res->reason, 558*99c7e855SJames Marks - Sun Microsystems drctl_resp->resp_err_msg, DR_VIO_MAXREASONLEN); 559*99c7e855SJames Marks - Sun Microsystems 560*99c7e855SJames Marks - Sun Microsystems DR_DBG_IO("%s: %s\n", __func__, res->reason); 561*99c7e855SJames Marks - Sun Microsystems 5628fea755aSjm22469 goto done; 5638fea755aSjm22469 564*99c7e855SJames Marks - Sun Microsystems } 565*99c7e855SJames Marks - Sun Microsystems 566*99c7e855SJames Marks - Sun Microsystems ASSERT(drctl_resp->resp_type == DRCTL_RESP_OK); 567*99c7e855SJames Marks - Sun Microsystems 568*99c7e855SJames Marks - Sun Microsystems if (drctl_rsrc->status == DRCTL_STATUS_DENY) { 569*99c7e855SJames Marks - Sun Microsystems 5708fea755aSjm22469 res->result = DR_VIO_RES_BLOCKED; 5718fea755aSjm22469 5728fea755aSjm22469 DR_DBG_IO("%s: drctl_config_init denied\n", __func__); 573*99c7e855SJames Marks - Sun Microsystems p = (char *)drctl_rsrc + drctl_rsrc->offset; 5748fea755aSjm22469 575*99c7e855SJames Marks - Sun Microsystems (void) strlcpy(res->reason, p, DR_VIO_MAXREASONLEN); 5768fea755aSjm22469 5778fea755aSjm22469 DR_DBG_IO("%s: %s\n", __func__, res->reason); 5788fea755aSjm22469 5798fea755aSjm22469 drctl_req->status = DRCTL_STATUS_CONFIG_FAILURE; 5808fea755aSjm22469 5818fea755aSjm22469 rv = EPERM; 5828fea755aSjm22469 } else { 5838fea755aSjm22469 cba.mdp = mdp; 5848fea755aSjm22469 cba.node = node; 5858fea755aSjm22469 5868fea755aSjm22469 br.arg = (void *)&cba; 5878fea755aSjm22469 br.type = DEVI_BRANCH_SID; 5888fea755aSjm22469 br.create.sid_branch_create = new_dev_node; 5898fea755aSjm22469 br.devi_branch_callback = NULL; 5908fea755aSjm22469 5918fea755aSjm22469 rv = e_ddi_branch_create(pdip, 5928fea755aSjm22469 &br, NULL, DEVI_BRANCH_CONFIGURE); 5938fea755aSjm22469 5948fea755aSjm22469 drctl_req->status = (rv == 0) ? 5958fea755aSjm22469 DRCTL_STATUS_CONFIG_SUCCESS : DRCTL_STATUS_CONFIG_FAILURE; 5968fea755aSjm22469 5978fea755aSjm22469 DR_DBG_IO("%s: %s@%ld = %d\n", __func__, name, devid, rv); 5988fea755aSjm22469 } 5998fea755aSjm22469 6008fea755aSjm22469 if (drctl_config_fini(&drctl_res_ck, drctl_req, 1) != 0) 6018fea755aSjm22469 DR_DBG_IO("%s: drctl_config_fini returned: %d\n", __func__, rv); 6028fea755aSjm22469 6038fea755aSjm22469 done: 604*99c7e855SJames Marks - Sun Microsystems if (listp) { 605*99c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %d\n", 606*99c7e855SJames Marks - Sun Microsystems __func__, (void *)listp, listsz); 6078fea755aSjm22469 kmem_free(listp, listsz); 608*99c7e855SJames Marks - Sun Microsystems } 6098fea755aSjm22469 6108fea755aSjm22469 if (mdp) 6118fea755aSjm22469 (void) md_fini_handle(mdp); 6128fea755aSjm22469 6138fea755aSjm22469 if (pdip) 6148fea755aSjm22469 e_ddi_branch_rele(pdip); 6158fea755aSjm22469 616*99c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %ld\n", 617*99c7e855SJames Marks - Sun Microsystems __func__, (void *)drctl_req, drctl_req_len); 6188fea755aSjm22469 kmem_free(drctl_req, drctl_req_len); 619*99c7e855SJames Marks - Sun Microsystems 620*99c7e855SJames Marks - Sun Microsystems if (drctl_resp) { 621*99c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %ld\n", 622*99c7e855SJames Marks - Sun Microsystems __func__, (void *)drctl_resp, drctl_resp_len); 623*99c7e855SJames Marks - Sun Microsystems kmem_free(drctl_resp, drctl_resp_len); 624*99c7e855SJames Marks - Sun Microsystems } 6258fea755aSjm22469 6268fea755aSjm22469 if (rv == 0) { 6278fea755aSjm22469 res->result = DR_VIO_RES_OK; 6288fea755aSjm22469 res->status = DR_VIO_STAT_CONFIGURED; 6298fea755aSjm22469 6308fea755aSjm22469 /* notify interested parties about the operation */ 6318fea755aSjm22469 dr_generate_event(DR_TYPE_VIO, SE_HINT_INSERT); 6328fea755aSjm22469 } else { 6338fea755aSjm22469 res->status = DR_VIO_STAT_UNCONFIGURED; 6348fea755aSjm22469 } 6358fea755aSjm22469 6368fea755aSjm22469 return (rv); 6378fea755aSjm22469 } 6388fea755aSjm22469 6398fea755aSjm22469 static int 6408fea755aSjm22469 dr_io_unconfigure(dr_vio_req_t *req, dr_vio_res_t *res) 6418fea755aSjm22469 { 6428fea755aSjm22469 int rv; 6438fea755aSjm22469 char *name = req->name; 6448fea755aSjm22469 char *p; 6458fea755aSjm22469 uint64_t devid = req->dev_id; 6468fea755aSjm22469 dev_info_t *dip; 6478fea755aSjm22469 dev_info_t *fdip = NULL; 6488fea755aSjm22469 int drctl_cmd; 6498fea755aSjm22469 int drctl_flags = 0; 6508fea755aSjm22469 drctl_rsrc_t *drctl_req; 6518fea755aSjm22469 size_t drctl_req_len; 652*99c7e855SJames Marks - Sun Microsystems drctl_rsrc_t *drctl_rsrc = NULL; 6538fea755aSjm22469 drctl_cookie_t drctl_res_ck; 654*99c7e855SJames Marks - Sun Microsystems drctl_resp_t *drctl_resp; 655*99c7e855SJames Marks - Sun Microsystems size_t drctl_resp_len; 6568fea755aSjm22469 6578fea755aSjm22469 if ((dip = dr_io_find_node(name, devid)) == NULL) { 6588fea755aSjm22469 DR_DBG_IO("%s: %s@%ld already unconfigured\n", 6598fea755aSjm22469 __func__, name, devid); 6608fea755aSjm22469 res->result = DR_VIO_RES_OK; 6618fea755aSjm22469 res->status = DR_VIO_STAT_NOT_PRESENT; 6628fea755aSjm22469 return (0); 6638fea755aSjm22469 } 6648fea755aSjm22469 6658fea755aSjm22469 res->result = DR_VIO_RES_FAILURE; 6668fea755aSjm22469 6678fea755aSjm22469 ASSERT(e_ddi_branch_held(dip)); 6688fea755aSjm22469 6698fea755aSjm22469 /* Assume we fail to unconfigure the resource. */ 6708fea755aSjm22469 res->status = DR_VIO_STAT_CONFIGURED; 6718fea755aSjm22469 6728fea755aSjm22469 drctl_req_len = sizeof (drctl_rsrc_t) + MAXPATHLEN; 6738fea755aSjm22469 drctl_req = kmem_zalloc(drctl_req_len, KM_SLEEP); 674*99c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %ld\n", 675*99c7e855SJames Marks - Sun Microsystems __func__, (void *)drctl_req, drctl_req_len); 6768fea755aSjm22469 drctl_req->status = DRCTL_STATUS_INIT; 6778fea755aSjm22469 6788fea755aSjm22469 drctl_cmd = DRCTL_IO_UNCONFIG_REQUEST; 6798fea755aSjm22469 6808fea755aSjm22469 if (req->msg_type == DR_VIO_FORCE_UNCONFIG) 6818fea755aSjm22469 drctl_flags = DRCTL_FLAG_FORCE; 6828fea755aSjm22469 6838fea755aSjm22469 p = drctl_req->res_dev_path; 6848fea755aSjm22469 (void) sprintf(p, "/devices"); 6858fea755aSjm22469 (void) ddi_pathname(dip, p + strlen(p)); 6868fea755aSjm22469 DR_DBG_IO("%s: devpath=%s\n", __func__, drctl_req->res_dev_path); 6878fea755aSjm22469 688*99c7e855SJames Marks - Sun Microsystems rv = drctl_config_init(drctl_cmd, drctl_flags, drctl_req, 689*99c7e855SJames Marks - Sun Microsystems 1, &drctl_resp, &drctl_resp_len, &drctl_res_ck); 690*99c7e855SJames Marks - Sun Microsystems 691*99c7e855SJames Marks - Sun Microsystems ASSERT((drctl_resp != NULL) && (drctl_resp_len != 0)); 692*99c7e855SJames Marks - Sun Microsystems 693*99c7e855SJames Marks - Sun Microsystems drctl_rsrc = drctl_resp->resp_resources; 694*99c7e855SJames Marks - Sun Microsystems 695*99c7e855SJames Marks - Sun Microsystems if (rv != 0) { 6968fea755aSjm22469 6978fea755aSjm22469 DR_DBG_IO("%s: drctl_config_init failed: %d\n", __func__, rv); 6988fea755aSjm22469 699*99c7e855SJames Marks - Sun Microsystems ASSERT(drctl_resp->resp_type == DRCTL_RESP_ERR); 700*99c7e855SJames Marks - Sun Microsystems 701*99c7e855SJames Marks - Sun Microsystems (void) strlcpy(res->reason, 702*99c7e855SJames Marks - Sun Microsystems drctl_resp->resp_err_msg, DR_VIO_MAXREASONLEN); 703*99c7e855SJames Marks - Sun Microsystems 704*99c7e855SJames Marks - Sun Microsystems DR_DBG_IO("%s: %s\n", __func__, res->reason); 705*99c7e855SJames Marks - Sun Microsystems 706*99c7e855SJames Marks - Sun Microsystems goto done; 707*99c7e855SJames Marks - Sun Microsystems } 708*99c7e855SJames Marks - Sun Microsystems 709*99c7e855SJames Marks - Sun Microsystems if (drctl_rsrc->status == DRCTL_STATUS_DENY) { 7108fea755aSjm22469 res->result = DR_VIO_RES_BLOCKED; 7118fea755aSjm22469 7128fea755aSjm22469 DR_DBG_IO("%s: drctl_config_init denied\n", __func__); 713*99c7e855SJames Marks - Sun Microsystems p = (char *)drctl_rsrc + drctl_rsrc->offset; 7148fea755aSjm22469 715*99c7e855SJames Marks - Sun Microsystems (void) strlcpy(res->reason, p, DR_VIO_MAXREASONLEN); 7168fea755aSjm22469 7178fea755aSjm22469 DR_DBG_IO("%s: %s\n", __func__, res->reason); 7188fea755aSjm22469 7198fea755aSjm22469 drctl_req->status = DRCTL_STATUS_CONFIG_FAILURE; 7208fea755aSjm22469 7218fea755aSjm22469 rv = EPERM; 7228fea755aSjm22469 } else if (rv = e_ddi_branch_destroy(dip, &fdip, 0)) { 7238fea755aSjm22469 char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 7248fea755aSjm22469 725*99c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %d\n", 726*99c7e855SJames Marks - Sun Microsystems __func__, (void *)path, MAXPATHLEN); 7278fea755aSjm22469 /* 7288fea755aSjm22469 * If non-NULL, fdip is held and must be released. 7298fea755aSjm22469 */ 7308fea755aSjm22469 if (fdip != NULL) { 7318fea755aSjm22469 (void) ddi_pathname(fdip, path); 7328fea755aSjm22469 ddi_release_devi(fdip); 7338fea755aSjm22469 } else { 7348fea755aSjm22469 (void) ddi_pathname(dip, path); 7358fea755aSjm22469 } 7368fea755aSjm22469 7378fea755aSjm22469 DR_DBG_IO("%s: node removal failed: %s (%p)", 7388fea755aSjm22469 __func__, path, (fdip) ? (void *)fdip : (void *)dip); 7398fea755aSjm22469 7408fea755aSjm22469 drctl_req->status = DRCTL_STATUS_CONFIG_FAILURE; 7418fea755aSjm22469 742*99c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %d\n", 743*99c7e855SJames Marks - Sun Microsystems __func__, (void *)path, MAXPATHLEN); 7448fea755aSjm22469 kmem_free(path, MAXPATHLEN); 7458fea755aSjm22469 } else { 7468fea755aSjm22469 drctl_req->status = DRCTL_STATUS_CONFIG_SUCCESS; 7478fea755aSjm22469 } 7488fea755aSjm22469 7498fea755aSjm22469 if (drctl_config_fini(&drctl_res_ck, drctl_req, 1) != 0) 7508fea755aSjm22469 DR_DBG_IO("%s: drctl_config_fini returned: %d\n", __func__, rv); 7518fea755aSjm22469 7528fea755aSjm22469 DR_DBG_IO("%s: (%s@%ld) = %d\n", __func__, name, devid, rv); 7538fea755aSjm22469 7548fea755aSjm22469 if (rv == 0) { 7558fea755aSjm22469 res->result = DR_VIO_RES_OK; 7568fea755aSjm22469 res->status = DR_VIO_STAT_UNCONFIGURED; 7578fea755aSjm22469 7588fea755aSjm22469 /* Notify interested parties about the operation. */ 7598fea755aSjm22469 dr_generate_event(DR_TYPE_VIO, SE_HINT_REMOVE); 7608fea755aSjm22469 } 7618fea755aSjm22469 done: 762*99c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %ld\n", 763*99c7e855SJames Marks - Sun Microsystems __func__, (void *)drctl_req, drctl_req_len); 7648fea755aSjm22469 kmem_free(drctl_req, drctl_req_len); 7658fea755aSjm22469 766*99c7e855SJames Marks - Sun Microsystems if (drctl_resp) { 767*99c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %ld\n", 768*99c7e855SJames Marks - Sun Microsystems __func__, (void *)drctl_resp, drctl_resp_len); 769*99c7e855SJames Marks - Sun Microsystems kmem_free(drctl_resp, drctl_resp_len); 770*99c7e855SJames Marks - Sun Microsystems } 7718fea755aSjm22469 7728fea755aSjm22469 return (rv); 7738fea755aSjm22469 } 7748fea755aSjm22469 7758fea755aSjm22469 static void 7768fea755aSjm22469 dr_vio_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen) 7778fea755aSjm22469 { 7788fea755aSjm22469 _NOTE(ARGUNUSED(arg)) 7798fea755aSjm22469 7808fea755aSjm22469 size_t res_len; 7818fea755aSjm22469 dr_vio_res_t *res; 7828fea755aSjm22469 dr_vio_req_t *req; 7838fea755aSjm22469 7848fea755aSjm22469 /* 7858fea755aSjm22469 * Allocate a response buffer, because we always want to 7868fea755aSjm22469 * send back a response message. 7878fea755aSjm22469 */ 7888fea755aSjm22469 res_len = sizeof (dr_vio_res_t) + DR_VIO_MAXREASONLEN; 7898fea755aSjm22469 res = kmem_zalloc(res_len, KM_SLEEP); 790*99c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %ld\n", 791*99c7e855SJames Marks - Sun Microsystems __func__, (void *)res, res_len); 7928fea755aSjm22469 res->result = DR_VIO_RES_FAILURE; 7938fea755aSjm22469 7948fea755aSjm22469 /* 7958fea755aSjm22469 * Sanity check the message 7968fea755aSjm22469 */ 7978fea755aSjm22469 if (buf == NULL) { 7988fea755aSjm22469 DR_DBG_IO("empty message: expected at least %ld bytes\n", 7998fea755aSjm22469 sizeof (dr_vio_req_t)); 8008fea755aSjm22469 goto done; 8018fea755aSjm22469 } 8028fea755aSjm22469 if (buflen < sizeof (dr_vio_req_t)) { 8038fea755aSjm22469 DR_DBG_IO("incoming message short: expected at least %ld " 8048fea755aSjm22469 "bytes, received %ld\n", sizeof (dr_vio_req_t), buflen); 8058fea755aSjm22469 goto done; 8068fea755aSjm22469 } 8078fea755aSjm22469 8088fea755aSjm22469 DR_DBG_TRANS("incoming request:\n"); 8098fea755aSjm22469 DR_DBG_DUMP_MSG(buf, buflen); 8108fea755aSjm22469 8118fea755aSjm22469 req = buf; 8128fea755aSjm22469 switch (req->msg_type) { 8138fea755aSjm22469 case DR_VIO_CONFIGURE: 8148fea755aSjm22469 (void) dr_io_configure(req, res); 8158fea755aSjm22469 break; 8168fea755aSjm22469 case DR_VIO_FORCE_UNCONFIG: 8178fea755aSjm22469 case DR_VIO_UNCONFIGURE: 8188fea755aSjm22469 (void) dr_io_unconfigure(req, res); 8198fea755aSjm22469 break; 8208fea755aSjm22469 default: 8218fea755aSjm22469 cmn_err(CE_NOTE, "bad msg_type %d\n", req->msg_type); 8228fea755aSjm22469 break; 8238fea755aSjm22469 } 8248fea755aSjm22469 done: 8258fea755aSjm22469 res->req_num = (req) ? req->req_num : 0; 8268fea755aSjm22469 8278fea755aSjm22469 DR_DBG_TRANS("outgoing response:\n"); 8288fea755aSjm22469 DR_DBG_DUMP_MSG(res, res_len); 8298fea755aSjm22469 8308fea755aSjm22469 /* send back the response */ 8318fea755aSjm22469 if (ds_cap_send(ds_vio_handle, res, res_len) != 0) 8328fea755aSjm22469 DR_DBG_IO("ds_send failed\n"); 8338fea755aSjm22469 834*99c7e855SJames Marks - Sun Microsystems if (res) { 835*99c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %ld\n", 836*99c7e855SJames Marks - Sun Microsystems __func__, (void *)res, res_len); 8378fea755aSjm22469 kmem_free(res, res_len); 8388fea755aSjm22469 } 839*99c7e855SJames Marks - Sun Microsystems } 8408fea755aSjm22469 8418fea755aSjm22469 static void 8428fea755aSjm22469 dr_vio_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl) 8438fea755aSjm22469 { 8448fea755aSjm22469 DR_DBG_IO("vio_reg_handler: arg=0x%p, ver=%d.%d, hdl=0x%lx\n", 8458fea755aSjm22469 arg, ver->major, ver->minor, hdl); 8468fea755aSjm22469 8478fea755aSjm22469 ds_vio_handle = hdl; 8488fea755aSjm22469 } 8498fea755aSjm22469 8508fea755aSjm22469 static void 8518fea755aSjm22469 dr_vio_unreg_handler(ds_cb_arg_t arg) 8528fea755aSjm22469 { 8538fea755aSjm22469 DR_DBG_IO("vio_unreg_handler: arg=0x%p\n", arg); 8548fea755aSjm22469 8558fea755aSjm22469 ds_vio_handle = DS_INVALID_HDL; 8568fea755aSjm22469 } 8578fea755aSjm22469 8588fea755aSjm22469 static int 8598fea755aSjm22469 dr_io_init(void) 8608fea755aSjm22469 { 8618fea755aSjm22469 int rv; 8628fea755aSjm22469 8638fea755aSjm22469 if ((rv = ds_cap_init(&dr_vio_cap, &dr_vio_ops)) != 0) { 8648fea755aSjm22469 cmn_err(CE_NOTE, "ds_cap_init vio failed: %d", rv); 8658fea755aSjm22469 return (-1); 8668fea755aSjm22469 } 8678fea755aSjm22469 8688fea755aSjm22469 return (0); 8698fea755aSjm22469 } 8708fea755aSjm22469 8718fea755aSjm22469 static int 8728fea755aSjm22469 dr_io_fini(void) 8738fea755aSjm22469 { 8748fea755aSjm22469 int rv; 8758fea755aSjm22469 8768fea755aSjm22469 if ((rv = ds_cap_fini(&dr_vio_cap)) != 0) { 8778fea755aSjm22469 cmn_err(CE_NOTE, "ds_cap_fini vio failed: %d", rv); 8788fea755aSjm22469 return (-1); 8798fea755aSjm22469 } 8808fea755aSjm22469 8818fea755aSjm22469 return (0); 8828fea755aSjm22469 } 8838fea755aSjm22469 8848fea755aSjm22469 int 8858fea755aSjm22469 _init(void) 8868fea755aSjm22469 { 8878fea755aSjm22469 int status; 8888fea755aSjm22469 8898fea755aSjm22469 /* check that IO DR is enabled */ 8908fea755aSjm22469 if (dr_is_disabled(DR_TYPE_VIO)) { 8918fea755aSjm22469 cmn_err(CE_CONT, "!VIO DR is disabled\n"); 8928fea755aSjm22469 return (-1); 8938fea755aSjm22469 } 8948fea755aSjm22469 8958fea755aSjm22469 if ((status = dr_io_init()) != 0) { 8968fea755aSjm22469 cmn_err(CE_NOTE, "VIO DR initialization failed"); 8978fea755aSjm22469 return (status); 8988fea755aSjm22469 } 8998fea755aSjm22469 9008fea755aSjm22469 if ((status = mod_install(&modlinkage)) != 0) { 9018fea755aSjm22469 (void) dr_io_fini(); 9028fea755aSjm22469 } 9038fea755aSjm22469 9048fea755aSjm22469 return (status); 9058fea755aSjm22469 } 9068fea755aSjm22469 9078fea755aSjm22469 int 9088fea755aSjm22469 _info(struct modinfo *modinfop) 9098fea755aSjm22469 { 9108fea755aSjm22469 return (mod_info(&modlinkage, modinfop)); 9118fea755aSjm22469 } 9128fea755aSjm22469 9138fea755aSjm22469 int dr_io_allow_unload = 0; 9148fea755aSjm22469 9158fea755aSjm22469 int 9168fea755aSjm22469 _fini(void) 9178fea755aSjm22469 { 9188fea755aSjm22469 int status; 9198fea755aSjm22469 9208fea755aSjm22469 if (dr_io_allow_unload == 0) 9218fea755aSjm22469 return (EBUSY); 9228fea755aSjm22469 9238fea755aSjm22469 if ((status = mod_remove(&modlinkage)) == 0) { 9248fea755aSjm22469 (void) dr_io_fini(); 9258fea755aSjm22469 } 9268fea755aSjm22469 9278fea755aSjm22469 return (status); 9288fea755aSjm22469 } 929