16441Sjm22469 /*
26441Sjm22469 * CDDL HEADER START
36441Sjm22469 *
46441Sjm22469 * The contents of this file are subject to the terms of the
56441Sjm22469 * Common Development and Distribution License (the "License").
66441Sjm22469 * You may not use this file except in compliance with the License.
76441Sjm22469 *
86441Sjm22469 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96441Sjm22469 * or http://www.opensolaris.org/os/licensing.
106441Sjm22469 * See the License for the specific language governing permissions
116441Sjm22469 * and limitations under the License.
126441Sjm22469 *
136441Sjm22469 * When distributing Covered Code, include this CDDL HEADER in each
146441Sjm22469 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156441Sjm22469 * If applicable, add the following below this CDDL HEADER, with the
166441Sjm22469 * fields enclosed by brackets "[]" replaced with your own identifying
176441Sjm22469 * information: Portions Copyright [yyyy] [name of copyright owner]
186441Sjm22469 *
196441Sjm22469 * CDDL HEADER END
206441Sjm22469 */
216441Sjm22469
226441Sjm22469 /*
236441Sjm22469 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
246441Sjm22469 * Use is subject to license terms.
256441Sjm22469 */
266441Sjm22469
276441Sjm22469 /*
286441Sjm22469 * sun4v VIO DR Module
296441Sjm22469 */
306441Sjm22469
316441Sjm22469 #include <sys/modctl.h>
326441Sjm22469 #include <sys/sunddi.h>
336441Sjm22469 #include <sys/sunndi.h>
346441Sjm22469 #include <sys/note.h>
356441Sjm22469 #include <sys/sysevent/dr.h>
366441Sjm22469 #include <sys/hypervisor_api.h>
376441Sjm22469 #include <sys/mach_descrip.h>
386441Sjm22469 #include <sys/mdesc.h>
396441Sjm22469 #include <sys/mdesc_impl.h>
406441Sjm22469 #include <sys/ds.h>
416441Sjm22469 #include <sys/drctl.h>
426441Sjm22469 #include <sys/dr_util.h>
436441Sjm22469 #include <sys/dr_io.h>
446441Sjm22469 #include <sys/promif.h>
456441Sjm22469 #include <sys/machsystm.h>
466441Sjm22469 #include <sys/ethernet.h>
476441Sjm22469 #include <sys/hotplug/pci/pcicfg.h>
486441Sjm22469
496441Sjm22469
506441Sjm22469 static struct modlmisc modlmisc = {
516441Sjm22469 &mod_miscops,
527799SRichard.Bean@Sun.COM "sun4v VIO DR"
536441Sjm22469 };
546441Sjm22469
556441Sjm22469 static struct modlinkage modlinkage = {
566441Sjm22469 MODREV_1,
576441Sjm22469 (void *)&modlmisc,
586441Sjm22469 NULL
596441Sjm22469 };
606441Sjm22469
616441Sjm22469
626441Sjm22469 /*
636441Sjm22469 * VIO DS Interface
646441Sjm22469 */
656441Sjm22469
666441Sjm22469 /*
676441Sjm22469 * Global DS Handle
686441Sjm22469 */
696441Sjm22469 static ds_svc_hdl_t ds_vio_handle;
706441Sjm22469
716441Sjm22469 /*
726441Sjm22469 * Supported DS Capability Versions
736441Sjm22469 */
746441Sjm22469 static ds_ver_t dr_vio_vers[] = { { 1, 0 } };
756441Sjm22469 #define DR_VIO_NVERS (sizeof (dr_vio_vers) / sizeof (dr_vio_vers[0]))
766441Sjm22469
776441Sjm22469 /*
786441Sjm22469 * DS Capability Description
796441Sjm22469 */
806441Sjm22469 static ds_capability_t dr_vio_cap = {
816441Sjm22469 DR_VIO_DS_ID, /* svc_id */
826441Sjm22469 dr_vio_vers, /* vers */
836441Sjm22469 DR_VIO_NVERS /* nvers */
846441Sjm22469 };
856441Sjm22469
866441Sjm22469 /*
876441Sjm22469 * DS Callbacks
886441Sjm22469 */
896441Sjm22469 static void dr_vio_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t);
906441Sjm22469 static void dr_vio_unreg_handler(ds_cb_arg_t arg);
916441Sjm22469 static void dr_vio_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
926441Sjm22469
936441Sjm22469 /*
946441Sjm22469 * DS Client Ops Vector
956441Sjm22469 */
966441Sjm22469 static ds_clnt_ops_t dr_vio_ops = {
976441Sjm22469 dr_vio_reg_handler, /* ds_reg_cb */
986441Sjm22469 dr_vio_unreg_handler, /* ds_unreg_cb */
996441Sjm22469 dr_vio_data_handler, /* ds_data_cb */
1006441Sjm22469 NULL /* cb_arg */
1016441Sjm22469 };
1026441Sjm22469
1036441Sjm22469
1046441Sjm22469 typedef struct {
1056441Sjm22469 char *name;
1066441Sjm22469 uint64_t devid;
1076441Sjm22469 dev_info_t *dip;
1086441Sjm22469 } dr_search_arg_t;
1096441Sjm22469
1106441Sjm22469 static int
dr_io_check_node(dev_info_t * dip,void * arg)1116441Sjm22469 dr_io_check_node(dev_info_t *dip, void *arg)
1126441Sjm22469 {
1136441Sjm22469 char *name;
1146441Sjm22469 uint64_t devid;
1156441Sjm22469 dr_search_arg_t *sarg = (dr_search_arg_t *)arg;
1166441Sjm22469
1176441Sjm22469 name = ddi_node_name(dip);
1186441Sjm22469
1196441Sjm22469 if (strcmp(name, sarg->name) != 0)
1206441Sjm22469 return (DDI_WALK_CONTINUE);
1216441Sjm22469
1226441Sjm22469 devid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1236441Sjm22469 "reg", -1);
1246441Sjm22469
1256441Sjm22469 DR_DBG_IO("%s: found devid=%ld, looking for %ld\n",
1266441Sjm22469 __func__, devid, sarg->devid);
1276441Sjm22469
1286441Sjm22469 if (devid == sarg->devid) {
1296441Sjm22469 DR_DBG_IO("%s: matched", __func__);
1306441Sjm22469
1316441Sjm22469 /* matching node must be returned held */
1326441Sjm22469 if (!e_ddi_branch_held(dip))
1336441Sjm22469 e_ddi_branch_hold(dip);
1346441Sjm22469
1356441Sjm22469 sarg->dip = dip;
1366441Sjm22469 return (DDI_WALK_TERMINATE);
1376441Sjm22469 }
1386441Sjm22469
1396441Sjm22469 return (DDI_WALK_CONTINUE);
1406441Sjm22469 }
1416441Sjm22469
1426441Sjm22469 /*
1436441Sjm22469 * Walk the device tree to find the dip corresponding to the devid
1446441Sjm22469 * passed in. If present, the dip is returned held. The caller must
1456441Sjm22469 * release the hold on the dip once it is no longer required. If no
1466441Sjm22469 * matching node if found, NULL is returned.
1476441Sjm22469 */
1486441Sjm22469 static dev_info_t *
dr_io_find_node(char * name,uint64_t devid)1496441Sjm22469 dr_io_find_node(char *name, uint64_t devid)
1506441Sjm22469 {
1516441Sjm22469 dr_search_arg_t arg;
1526441Sjm22469
1536441Sjm22469 DR_DBG_IO("dr_io_find_node...\n");
1546441Sjm22469
1556441Sjm22469 arg.name = name;
1566441Sjm22469 arg.devid = devid;
1576441Sjm22469 arg.dip = NULL;
1586441Sjm22469
1596441Sjm22469 ddi_walk_devs(ddi_root_node(), dr_io_check_node, &arg);
1606441Sjm22469
1616441Sjm22469 ASSERT((arg.dip == NULL) || (e_ddi_branch_held(arg.dip)));
1626441Sjm22469
1636441Sjm22469 return ((arg.dip) ? arg.dip : NULL);
1646441Sjm22469 }
1656441Sjm22469
1666441Sjm22469 /*
1676441Sjm22469 * Look up a particular IO node in the MD. Returns the mde_cookie_t
1686441Sjm22469 * representing that IO node if present, and MDE_INVAL_ELEM_COOKIE otherwise.
1696441Sjm22469 * It is assumed the scratch array has already been allocated so that
1706441Sjm22469 * it can accommodate the worst case scenario, every node in the MD.
1716441Sjm22469 */
1726441Sjm22469 static mde_cookie_t
dr_io_find_node_md(md_t * mdp,char * name,uint64_t id,mde_cookie_t * listp)1736441Sjm22469 dr_io_find_node_md(md_t *mdp, char *name, uint64_t id, mde_cookie_t *listp)
1746441Sjm22469 {
1756441Sjm22469 int i;
1766441Sjm22469 int nnodes;
1776441Sjm22469 char *devnm;
1786441Sjm22469 uint64_t devid;
1796441Sjm22469 mde_cookie_t rootnode;
1806441Sjm22469 mde_cookie_t result = MDE_INVAL_ELEM_COOKIE;
1816441Sjm22469
1826441Sjm22469 DR_DBG_IO("%s: %s@%ld\n", __func__, name, id);
1836441Sjm22469
1846441Sjm22469 rootnode = md_root_node(mdp);
1856441Sjm22469 ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE);
1866441Sjm22469
1876441Sjm22469 /*
1886441Sjm22469 * Scan the DAG for all candidate nodes.
1896441Sjm22469 */
1906441Sjm22469 nnodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "virtual-device"),
1916441Sjm22469 md_find_name(mdp, "fwd"), listp);
1926441Sjm22469
1936441Sjm22469 if (nnodes < 0) {
1946441Sjm22469 DR_DBG_IO("%s: scan for "
1956441Sjm22469 "'virtual-device' nodes failed\n", __func__);
1966441Sjm22469 return (result);
1976441Sjm22469 }
1986441Sjm22469
1996441Sjm22469 DR_DBG_IO("%s: found %d nodes in the MD\n", __func__, nnodes);
2006441Sjm22469
2016441Sjm22469 /*
2026441Sjm22469 * Find the node of interest
2036441Sjm22469 */
2046441Sjm22469 for (i = 0; i < nnodes; i++) {
2056441Sjm22469
2066441Sjm22469 if (md_get_prop_str(mdp, listp[i], "name", &devnm)) {
2076441Sjm22469 DR_DBG_IO("%s: missing 'name' property for"
2086441Sjm22469 " IO node %d\n", __func__, i);
2096441Sjm22469 return (DDI_WALK_ERROR);
2106441Sjm22469 }
2116441Sjm22469
2126441Sjm22469 if (strcmp(devnm, name) != 0)
2136441Sjm22469 continue;
2146441Sjm22469
2156441Sjm22469 if (md_get_prop_val(mdp, listp[i], "cfg-handle", &devid)) {
2166441Sjm22469 DR_DBG_IO("%s: missing 'cfg-handle' property for"
2176441Sjm22469 " IO node %d\n", __func__, i);
2186441Sjm22469 break;
2196441Sjm22469 }
2206441Sjm22469
2216441Sjm22469 if (devid == id) {
2226441Sjm22469 /* found a match */
2236441Sjm22469 DR_DBG_IO("%s: found IO node %s@%ld "
2246441Sjm22469 "in MD\n", __func__, name, id);
2256441Sjm22469 result = listp[i];
2266441Sjm22469 break;
2276441Sjm22469 }
2286441Sjm22469 }
2296441Sjm22469
2306441Sjm22469 if (result == MDE_INVAL_ELEM_COOKIE)
2316441Sjm22469 DR_DBG_IO("%s: IO node %ld not in MD\n", __func__, id);
2326441Sjm22469
2336441Sjm22469 return (result);
2346441Sjm22469 }
2356441Sjm22469
2366441Sjm22469 typedef struct {
2376441Sjm22469 md_t *mdp;
2386441Sjm22469 mde_cookie_t node;
2396441Sjm22469 dev_info_t *dip;
2406441Sjm22469 } cb_arg_t;
2416441Sjm22469
2426441Sjm22469 #define STR_ARR_LEN 5
2436441Sjm22469
2446441Sjm22469 static int
new_dev_node(dev_info_t * new_node,void * arg,uint_t flags)2456441Sjm22469 new_dev_node(dev_info_t *new_node, void *arg, uint_t flags)
2466441Sjm22469 {
2476441Sjm22469 _NOTE(ARGUNUSED(flags))
2486441Sjm22469
2496441Sjm22469 cb_arg_t *cba;
2506441Sjm22469 char *devnm, *devtype;
2516441Sjm22469 char *compat;
2526441Sjm22469 uint64_t devid;
2536441Sjm22469 int len = 0;
2546441Sjm22469 char *curr;
2556441Sjm22469 int i = 0;
2566441Sjm22469 char *str_arr[STR_ARR_LEN];
2576441Sjm22469
2586441Sjm22469 cba = (cb_arg_t *)arg;
2596441Sjm22469
2606441Sjm22469 /*
2616441Sjm22469 * Add 'name' property
2626441Sjm22469 */
2636441Sjm22469 if (md_get_prop_str(cba->mdp, cba->node, "name", &devnm)) {
2646441Sjm22469 DR_DBG_IO("%s: failed to read 'name' prop from MD\n", __func__);
2656441Sjm22469 return (DDI_WALK_ERROR);
2666441Sjm22469 }
2676441Sjm22469 DR_DBG_IO("%s: device name is %s\n", __func__, devnm);
2686441Sjm22469
2696441Sjm22469 if (ndi_prop_update_string(DDI_DEV_T_NONE, new_node,
2706441Sjm22469 "name", devnm) != DDI_SUCCESS) {
2716441Sjm22469 DR_DBG_IO("%s: failed to create 'name' prop\n", __func__);
2726441Sjm22469 return (DDI_WALK_ERROR);
2736441Sjm22469 }
2746441Sjm22469
2756441Sjm22469 /*
2766441Sjm22469 * Add 'compatible' property
2776441Sjm22469 */
2786441Sjm22469 if (md_get_prop_data(cba->mdp, cba->node, "compatible",
2796441Sjm22469 (uint8_t **)&compat, &len)) {
2806441Sjm22469 DR_DBG_IO("%s: failed to read "
2816441Sjm22469 "'compatible' prop from MD\n", __func__);
2826441Sjm22469 return (DDI_WALK_ERROR);
2836441Sjm22469 }
2846441Sjm22469
2856441Sjm22469 /* parse the MD string array */
2866441Sjm22469 curr = compat;
2876441Sjm22469 while (curr < (compat + len)) {
2886441Sjm22469
2896441Sjm22469 DR_DBG_IO("%s: adding '%s' to "
2906441Sjm22469 "'compatible' prop\n", __func__, curr);
2916441Sjm22469
2926441Sjm22469 str_arr[i++] = curr;
2936441Sjm22469 curr += strlen(curr) + 1;
2946441Sjm22469
2956441Sjm22469 if (i == STR_ARR_LEN) {
2966441Sjm22469 DR_DBG_CPU("exceeded str_arr len (%d)\n", STR_ARR_LEN);
2976441Sjm22469 break;
2986441Sjm22469 }
2996441Sjm22469 }
3006441Sjm22469
3016441Sjm22469
3026441Sjm22469 if (ndi_prop_update_string_array(DDI_DEV_T_NONE, new_node,
3036441Sjm22469 "compatible", str_arr, i) != DDI_SUCCESS) {
3046441Sjm22469 DR_DBG_IO("%s: cannot create 'compatible' prop\n", __func__);
3056441Sjm22469 return (DDI_WALK_ERROR);
3066441Sjm22469 }
3076441Sjm22469
3086441Sjm22469 /*
3096441Sjm22469 * Add 'device_type' property
3106441Sjm22469 */
3116441Sjm22469 if (md_get_prop_str(cba->mdp, cba->node, "device-type", &devtype)) {
3126441Sjm22469 DR_DBG_IO("%s: failed to read "
3136441Sjm22469 "'device-type' prop from MD\n", __func__);
3146441Sjm22469 return (DDI_WALK_ERROR);
3156441Sjm22469 }
3166441Sjm22469 if (ndi_prop_update_string(DDI_DEV_T_NONE, new_node,
3176441Sjm22469 "device_type", devtype) != DDI_SUCCESS) {
3186441Sjm22469 DR_DBG_IO("%s: failed to create "
3196441Sjm22469 "'device-type' prop\n", __func__);
3206441Sjm22469 return (DDI_WALK_ERROR);
3216441Sjm22469 }
3226441Sjm22469
3236441Sjm22469 DR_DBG_IO("%s: device type is %s\n", __func__, devtype);
3246441Sjm22469
3256441Sjm22469 /*
3266441Sjm22469 * Add 'reg' (cfg-handle) property
3276441Sjm22469 */
3286441Sjm22469 if (md_get_prop_val(cba->mdp, cba->node, "cfg-handle", &devid)) {
3296441Sjm22469 DR_DBG_IO("%s: failed to read "
3306441Sjm22469 "'cfg-handle' prop from MD\n", __func__);
3316441Sjm22469 return (DDI_WALK_ERROR);
3326441Sjm22469 }
3336441Sjm22469
3346441Sjm22469 DR_DBG_IO("%s: new device is %s@%ld\n", __func__, devnm, devid);
3356441Sjm22469
3366441Sjm22469 if (ndi_prop_update_int(DDI_DEV_T_NONE, new_node, "reg", devid)
3376441Sjm22469 != DDI_SUCCESS) {
3386441Sjm22469 DR_DBG_IO("%s: failed to create 'reg' prop\n", __func__);
3396441Sjm22469 return (DDI_WALK_ERROR);
3406441Sjm22469 }
3416441Sjm22469
3426441Sjm22469 /* if vnet/vswitch, probe and add mac-address and mtu properties */
3436441Sjm22469 if (strcmp(devnm, "vsw") == 0 || strcmp(devnm, "network") == 0) {
3446441Sjm22469
3456441Sjm22469 int i, j;
3466441Sjm22469 uint64_t mtu, macaddr;
3476441Sjm22469 uchar_t maddr_arr[ETHERADDRL];
3486441Sjm22469
3496441Sjm22469 if (md_get_prop_val(cba->mdp, cba->node, "local-mac-address",
3506441Sjm22469 &macaddr)) {
3516441Sjm22469 DR_DBG_IO("%s: failed to read "
3526441Sjm22469 "'local-mac-address' prop from MD\n", __func__);
3536441Sjm22469 return (DDI_WALK_ERROR);
3546441Sjm22469 }
3556441Sjm22469
3566441Sjm22469 for (i = 0, j = (ETHERADDRL - 1); i < ETHERADDRL; i++, j--)
3576441Sjm22469 maddr_arr[j] = (macaddr >> (i * 8)) & 0xff;
3586441Sjm22469
3596441Sjm22469 if (ndi_prop_update_byte_array(DDI_DEV_T_NONE, new_node,
3606441Sjm22469 "local-mac-address", maddr_arr, ETHERADDRL)
3616441Sjm22469 != DDI_SUCCESS) {
3626441Sjm22469 DR_DBG_IO("%s: failed to create "
3636441Sjm22469 "'local-mac-address' prop\n", __func__);
3646441Sjm22469 return (DDI_WALK_ERROR);
3656441Sjm22469 }
3666441Sjm22469
3676441Sjm22469 if (md_get_prop_val(cba->mdp, cba->node, "mtu", &mtu)) {
3686441Sjm22469 DR_DBG_IO("%s: failed to read "
3696441Sjm22469 "'mtu' prop from MD\n", __func__);
3706441Sjm22469 return (DDI_WALK_ERROR);
3716441Sjm22469 }
3726441Sjm22469
3736441Sjm22469 if (ndi_prop_update_int64(DDI_DEV_T_NONE, new_node, "mtu",
3746441Sjm22469 mtu) != DDI_SUCCESS) {
3756441Sjm22469 DR_DBG_IO("%s: failed to "
3766441Sjm22469 "create 'mtu' prop\n", __func__);
3776441Sjm22469 return (DDI_WALK_ERROR);
3786441Sjm22469 }
3796441Sjm22469
3806441Sjm22469 DR_DBG_IO("%s: Added properties for %s@%ld, "
3816441Sjm22469 "mac=%ld, mtu=%ld\n", __func__, devnm, devid, macaddr, mtu);
3826441Sjm22469 }
3836441Sjm22469
3846441Sjm22469 cba->dip = new_node;
3856441Sjm22469
3866441Sjm22469 return (DDI_WALK_TERMINATE);
3876441Sjm22469 }
3886441Sjm22469
3896441Sjm22469 /*
3906441Sjm22469 * Find the parent node of the argument virtual device node in
3916441Sjm22469 * the MD. For virtual devices, the parent is always
3926441Sjm22469 * "channel-devices", so scan the MD using the "back" arcs
3936441Sjm22469 * looking for a node with that name.
3946441Sjm22469 */
3956441Sjm22469 static mde_cookie_t
dr_vio_find_parent_md(md_t * mdp,mde_cookie_t node)3966441Sjm22469 dr_vio_find_parent_md(md_t *mdp, mde_cookie_t node)
3976441Sjm22469 {
3986441Sjm22469 int max_nodes;
3996441Sjm22469 int num_nodes;
4006441Sjm22469 int listsz;
4016441Sjm22469 mde_cookie_t *listp;
4026441Sjm22469 mde_cookie_t pnode = MDE_INVAL_ELEM_COOKIE;
4036441Sjm22469
4046441Sjm22469 max_nodes = md_node_count(mdp);
4056441Sjm22469 listsz = max_nodes * sizeof (mde_cookie_t);
4066441Sjm22469 listp = kmem_zalloc(listsz, KM_SLEEP);
407*7899SJames.Marks@Sun.COM DR_DBG_KMEM("%s: alloc addr %p size %d\n",
408*7899SJames.Marks@Sun.COM __func__, (void *)listp, listsz);
4096441Sjm22469
4106441Sjm22469 num_nodes = md_scan_dag(mdp, node,
4116441Sjm22469 md_find_name(mdp, "channel-devices"),
4126441Sjm22469 md_find_name(mdp, "back"), listp);
4136441Sjm22469
4146441Sjm22469 ASSERT(num_nodes == 1);
4156441Sjm22469
4166441Sjm22469 if (num_nodes == 1)
4176441Sjm22469 pnode = listp[0];
4186441Sjm22469
419*7899SJames.Marks@Sun.COM DR_DBG_KMEM("%s: free addr %p size %d\n",
420*7899SJames.Marks@Sun.COM __func__, (void *)listp, listsz);
4216441Sjm22469 kmem_free(listp, listsz);
4226441Sjm22469
4236441Sjm22469 return (pnode);
4246441Sjm22469 }
4256441Sjm22469
4266441Sjm22469 static int
dr_io_configure(dr_vio_req_t * req,dr_vio_res_t * res)4276441Sjm22469 dr_io_configure(dr_vio_req_t *req, dr_vio_res_t *res)
4286441Sjm22469 {
4296441Sjm22469 int rv = ENXIO;
4306441Sjm22469 int listsz;
4316441Sjm22469 int nnodes;
4326441Sjm22469 uint64_t devid = req->dev_id;
4336441Sjm22469 uint64_t pdevid;
4346441Sjm22469 char *name = req->name;
4356441Sjm22469 char *pname;
4366441Sjm22469 md_t *mdp = NULL;
4376441Sjm22469 mde_cookie_t *listp = NULL;
4386441Sjm22469 mde_cookie_t node;
4396441Sjm22469 mde_cookie_t pnode;
4406441Sjm22469 dev_info_t *pdip = NULL;
4416441Sjm22469 dev_info_t *dip;
4426441Sjm22469 devi_branch_t br;
4436441Sjm22469 cb_arg_t cba;
4446441Sjm22469 int drctl_cmd;
4456441Sjm22469 int drctl_flags = 0;
4466441Sjm22469 drctl_rsrc_t *drctl_req;
4476441Sjm22469 size_t drctl_req_len;
448*7899SJames.Marks@Sun.COM drctl_rsrc_t *drctl_rsrc = NULL;
4496441Sjm22469 drctl_cookie_t drctl_res_ck;
4506441Sjm22469 char *p;
451*7899SJames.Marks@Sun.COM drctl_resp_t *drctl_resp;
452*7899SJames.Marks@Sun.COM size_t drctl_resp_len = 0;
4536441Sjm22469
4546441Sjm22469 res->result = DR_VIO_RES_FAILURE;
4556441Sjm22469
4566441Sjm22469 if ((dip = dr_io_find_node(name, devid)) != NULL) {
4576441Sjm22469 DR_DBG_IO("%s: %s@%ld already configured\n",
4586441Sjm22469 __func__, name, devid);
4596441Sjm22469
4606441Sjm22469 /* Return success if resources is already there. */
4616441Sjm22469 res->result = DR_VIO_RES_OK;
4626441Sjm22469 res->status = DR_VIO_STAT_CONFIGURED;
4636441Sjm22469 e_ddi_branch_rele(dip);
4646441Sjm22469 return (0);
4656441Sjm22469 }
4666441Sjm22469
4676441Sjm22469 /* Assume we fail to find the node to be added. */
4686441Sjm22469 res->status = DR_VIO_STAT_NOT_PRESENT;
4696441Sjm22469
4706441Sjm22469 if ((mdp = md_get_handle()) == NULL) {
4716441Sjm22469 DR_DBG_IO("%s: unable to initialize MD\n", __func__);
4726441Sjm22469 return (ENXIO);
4736441Sjm22469 }
4746441Sjm22469
4756441Sjm22469 nnodes = md_node_count(mdp);
4766441Sjm22469 ASSERT(nnodes > 0);
4776441Sjm22469
4786441Sjm22469 listsz = nnodes * sizeof (mde_cookie_t);
4796441Sjm22469 listp = kmem_zalloc(listsz, KM_SLEEP);
480*7899SJames.Marks@Sun.COM DR_DBG_KMEM("%s: alloc addr %p size %d\n",
481*7899SJames.Marks@Sun.COM __func__, (void *)listp, listsz);
4826441Sjm22469
4836441Sjm22469 /*
4846441Sjm22469 * Get the MD device node.
4856441Sjm22469 */
4866441Sjm22469 node = dr_io_find_node_md(mdp, name, devid, listp);
4876441Sjm22469
4886441Sjm22469 if (node == MDE_INVAL_ELEM_COOKIE) {
4896441Sjm22469 DR_DBG_IO("%s: scan for %s name node failed\n", __func__, name);
4906441Sjm22469 res->result = DR_VIO_RES_NOT_IN_MD;
4916441Sjm22469 goto done;
4926441Sjm22469 }
4936441Sjm22469
4946441Sjm22469 /*
4956441Sjm22469 * Get the MD parent node.
4966441Sjm22469 */
4976441Sjm22469 pnode = dr_vio_find_parent_md(mdp, node);
4986441Sjm22469 if (pnode == MDE_INVAL_ELEM_COOKIE) {
4996441Sjm22469 DR_DBG_IO("%s: failed to find MD parent of %lx\n",
5006441Sjm22469 __func__, pnode);
5016441Sjm22469 goto done;
5026441Sjm22469 }
5036441Sjm22469
5046441Sjm22469 if (md_get_prop_str(mdp, pnode, "name", &pname)) {
5056441Sjm22469 DR_DBG_IO("%s: failed to read "
5066441Sjm22469 "'name' for pnode %lx from MD\n", __func__, pnode);
5076441Sjm22469 goto done;
5086441Sjm22469 }
5096441Sjm22469
5106441Sjm22469 if (md_get_prop_val(mdp, pnode, "cfg-handle", &pdevid)) {
5116441Sjm22469 DR_DBG_IO("%s: failed to read 'cfg-handle' "
5126441Sjm22469 "for pnode '%s' from MD\n", __func__, pname);
5136441Sjm22469 goto done;
5146441Sjm22469 }
5156441Sjm22469
5166441Sjm22469 DR_DBG_IO("%s: parent device %s@%lx\n", __func__, pname, pdevid);
5176441Sjm22469
5186441Sjm22469 /*
5196441Sjm22469 * Get the devinfo parent node.
5206441Sjm22469 */
5216441Sjm22469 if ((pdip = dr_io_find_node(pname, pdevid)) == NULL) {
5226441Sjm22469 DR_DBG_IO("%s: parent device %s@%ld not found\n",
5236441Sjm22469 __func__, pname, pdevid);
5246441Sjm22469 goto done;
5256441Sjm22469 }
5266441Sjm22469
5276441Sjm22469 drctl_req_len = sizeof (drctl_rsrc_t) + MAXPATHLEN;
5286441Sjm22469 drctl_req = kmem_zalloc(drctl_req_len, KM_SLEEP);
529*7899SJames.Marks@Sun.COM DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
530*7899SJames.Marks@Sun.COM __func__, (void *)drctl_req, drctl_req_len);
5316441Sjm22469 drctl_req->status = DRCTL_STATUS_INIT;
5326441Sjm22469
5336441Sjm22469 drctl_cmd = DRCTL_IO_CONFIG_REQUEST;
5346441Sjm22469
5356441Sjm22469 /*
5366441Sjm22469 * Construct the path of the device as it will be if it
5376441Sjm22469 * is successfully added.
5386441Sjm22469 */
5396441Sjm22469 p = drctl_req->res_dev_path;
5406441Sjm22469 (void) sprintf(p, "/devices");
5416441Sjm22469 (void) ddi_pathname(pdip, p + strlen(p));
5426441Sjm22469 (void) sprintf(p + strlen(p), "/%s@%ld", name, devid);
5436441Sjm22469 DR_DBG_IO("%s: devpath=%s\n", __func__, drctl_req->res_dev_path);
5446441Sjm22469
545*7899SJames.Marks@Sun.COM rv = drctl_config_init(drctl_cmd, drctl_flags, drctl_req,
546*7899SJames.Marks@Sun.COM 1, &drctl_resp, &drctl_resp_len, &drctl_res_ck);
547*7899SJames.Marks@Sun.COM
548*7899SJames.Marks@Sun.COM ASSERT((drctl_resp != NULL) && (drctl_resp_len != 0));
549*7899SJames.Marks@Sun.COM
550*7899SJames.Marks@Sun.COM drctl_rsrc = drctl_resp->resp_resources;
5516441Sjm22469
552*7899SJames.Marks@Sun.COM if (rv != 0) {
5536441Sjm22469 DR_DBG_IO("%s: drctl_config_init failed: %d\n", __func__, rv);
554*7899SJames.Marks@Sun.COM
555*7899SJames.Marks@Sun.COM ASSERT(drctl_resp->resp_type == DRCTL_RESP_ERR);
556*7899SJames.Marks@Sun.COM
557*7899SJames.Marks@Sun.COM (void) strlcpy(res->reason,
558*7899SJames.Marks@Sun.COM drctl_resp->resp_err_msg, DR_VIO_MAXREASONLEN);
559*7899SJames.Marks@Sun.COM
560*7899SJames.Marks@Sun.COM DR_DBG_IO("%s: %s\n", __func__, res->reason);
561*7899SJames.Marks@Sun.COM
5626441Sjm22469 goto done;
5636441Sjm22469
564*7899SJames.Marks@Sun.COM }
565*7899SJames.Marks@Sun.COM
566*7899SJames.Marks@Sun.COM ASSERT(drctl_resp->resp_type == DRCTL_RESP_OK);
567*7899SJames.Marks@Sun.COM
568*7899SJames.Marks@Sun.COM if (drctl_rsrc->status == DRCTL_STATUS_DENY) {
569*7899SJames.Marks@Sun.COM
5706441Sjm22469 res->result = DR_VIO_RES_BLOCKED;
5716441Sjm22469
5726441Sjm22469 DR_DBG_IO("%s: drctl_config_init denied\n", __func__);
573*7899SJames.Marks@Sun.COM p = (char *)drctl_rsrc + drctl_rsrc->offset;
5746441Sjm22469
575*7899SJames.Marks@Sun.COM (void) strlcpy(res->reason, p, DR_VIO_MAXREASONLEN);
5766441Sjm22469
5776441Sjm22469 DR_DBG_IO("%s: %s\n", __func__, res->reason);
5786441Sjm22469
5796441Sjm22469 drctl_req->status = DRCTL_STATUS_CONFIG_FAILURE;
5806441Sjm22469
5816441Sjm22469 rv = EPERM;
5826441Sjm22469 } else {
5836441Sjm22469 cba.mdp = mdp;
5846441Sjm22469 cba.node = node;
5856441Sjm22469
5866441Sjm22469 br.arg = (void *)&cba;
5876441Sjm22469 br.type = DEVI_BRANCH_SID;
5886441Sjm22469 br.create.sid_branch_create = new_dev_node;
5896441Sjm22469 br.devi_branch_callback = NULL;
5906441Sjm22469
5916441Sjm22469 rv = e_ddi_branch_create(pdip,
5926441Sjm22469 &br, NULL, DEVI_BRANCH_CONFIGURE);
5936441Sjm22469
5946441Sjm22469 drctl_req->status = (rv == 0) ?
5956441Sjm22469 DRCTL_STATUS_CONFIG_SUCCESS : DRCTL_STATUS_CONFIG_FAILURE;
5966441Sjm22469
5976441Sjm22469 DR_DBG_IO("%s: %s@%ld = %d\n", __func__, name, devid, rv);
5986441Sjm22469 }
5996441Sjm22469
6006441Sjm22469 if (drctl_config_fini(&drctl_res_ck, drctl_req, 1) != 0)
6016441Sjm22469 DR_DBG_IO("%s: drctl_config_fini returned: %d\n", __func__, rv);
6026441Sjm22469
6036441Sjm22469 done:
604*7899SJames.Marks@Sun.COM if (listp) {
605*7899SJames.Marks@Sun.COM DR_DBG_KMEM("%s: free addr %p size %d\n",
606*7899SJames.Marks@Sun.COM __func__, (void *)listp, listsz);
6076441Sjm22469 kmem_free(listp, listsz);
608*7899SJames.Marks@Sun.COM }
6096441Sjm22469
6106441Sjm22469 if (mdp)
6116441Sjm22469 (void) md_fini_handle(mdp);
6126441Sjm22469
6136441Sjm22469 if (pdip)
6146441Sjm22469 e_ddi_branch_rele(pdip);
6156441Sjm22469
616*7899SJames.Marks@Sun.COM DR_DBG_KMEM("%s: free addr %p size %ld\n",
617*7899SJames.Marks@Sun.COM __func__, (void *)drctl_req, drctl_req_len);
6186441Sjm22469 kmem_free(drctl_req, drctl_req_len);
619*7899SJames.Marks@Sun.COM
620*7899SJames.Marks@Sun.COM if (drctl_resp) {
621*7899SJames.Marks@Sun.COM DR_DBG_KMEM("%s: free addr %p size %ld\n",
622*7899SJames.Marks@Sun.COM __func__, (void *)drctl_resp, drctl_resp_len);
623*7899SJames.Marks@Sun.COM kmem_free(drctl_resp, drctl_resp_len);
624*7899SJames.Marks@Sun.COM }
6256441Sjm22469
6266441Sjm22469 if (rv == 0) {
6276441Sjm22469 res->result = DR_VIO_RES_OK;
6286441Sjm22469 res->status = DR_VIO_STAT_CONFIGURED;
6296441Sjm22469
6306441Sjm22469 /* notify interested parties about the operation */
6316441Sjm22469 dr_generate_event(DR_TYPE_VIO, SE_HINT_INSERT);
6326441Sjm22469 } else {
6336441Sjm22469 res->status = DR_VIO_STAT_UNCONFIGURED;
6346441Sjm22469 }
6356441Sjm22469
6366441Sjm22469 return (rv);
6376441Sjm22469 }
6386441Sjm22469
6396441Sjm22469 static int
dr_io_unconfigure(dr_vio_req_t * req,dr_vio_res_t * res)6406441Sjm22469 dr_io_unconfigure(dr_vio_req_t *req, dr_vio_res_t *res)
6416441Sjm22469 {
6426441Sjm22469 int rv;
6436441Sjm22469 char *name = req->name;
6446441Sjm22469 char *p;
6456441Sjm22469 uint64_t devid = req->dev_id;
6466441Sjm22469 dev_info_t *dip;
6476441Sjm22469 dev_info_t *fdip = NULL;
6486441Sjm22469 int drctl_cmd;
6496441Sjm22469 int drctl_flags = 0;
6506441Sjm22469 drctl_rsrc_t *drctl_req;
6516441Sjm22469 size_t drctl_req_len;
652*7899SJames.Marks@Sun.COM drctl_rsrc_t *drctl_rsrc = NULL;
6536441Sjm22469 drctl_cookie_t drctl_res_ck;
654*7899SJames.Marks@Sun.COM drctl_resp_t *drctl_resp;
655*7899SJames.Marks@Sun.COM size_t drctl_resp_len;
6566441Sjm22469
6576441Sjm22469 if ((dip = dr_io_find_node(name, devid)) == NULL) {
6586441Sjm22469 DR_DBG_IO("%s: %s@%ld already unconfigured\n",
6596441Sjm22469 __func__, name, devid);
6606441Sjm22469 res->result = DR_VIO_RES_OK;
6616441Sjm22469 res->status = DR_VIO_STAT_NOT_PRESENT;
6626441Sjm22469 return (0);
6636441Sjm22469 }
6646441Sjm22469
6656441Sjm22469 res->result = DR_VIO_RES_FAILURE;
6666441Sjm22469
6676441Sjm22469 ASSERT(e_ddi_branch_held(dip));
6686441Sjm22469
6696441Sjm22469 /* Assume we fail to unconfigure the resource. */
6706441Sjm22469 res->status = DR_VIO_STAT_CONFIGURED;
6716441Sjm22469
6726441Sjm22469 drctl_req_len = sizeof (drctl_rsrc_t) + MAXPATHLEN;
6736441Sjm22469 drctl_req = kmem_zalloc(drctl_req_len, KM_SLEEP);
674*7899SJames.Marks@Sun.COM DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
675*7899SJames.Marks@Sun.COM __func__, (void *)drctl_req, drctl_req_len);
6766441Sjm22469 drctl_req->status = DRCTL_STATUS_INIT;
6776441Sjm22469
6786441Sjm22469 drctl_cmd = DRCTL_IO_UNCONFIG_REQUEST;
6796441Sjm22469
6806441Sjm22469 if (req->msg_type == DR_VIO_FORCE_UNCONFIG)
6816441Sjm22469 drctl_flags = DRCTL_FLAG_FORCE;
6826441Sjm22469
6836441Sjm22469 p = drctl_req->res_dev_path;
6846441Sjm22469 (void) sprintf(p, "/devices");
6856441Sjm22469 (void) ddi_pathname(dip, p + strlen(p));
6866441Sjm22469 DR_DBG_IO("%s: devpath=%s\n", __func__, drctl_req->res_dev_path);
6876441Sjm22469
688*7899SJames.Marks@Sun.COM rv = drctl_config_init(drctl_cmd, drctl_flags, drctl_req,
689*7899SJames.Marks@Sun.COM 1, &drctl_resp, &drctl_resp_len, &drctl_res_ck);
690*7899SJames.Marks@Sun.COM
691*7899SJames.Marks@Sun.COM ASSERT((drctl_resp != NULL) && (drctl_resp_len != 0));
692*7899SJames.Marks@Sun.COM
693*7899SJames.Marks@Sun.COM drctl_rsrc = drctl_resp->resp_resources;
694*7899SJames.Marks@Sun.COM
695*7899SJames.Marks@Sun.COM if (rv != 0) {
6966441Sjm22469
6976441Sjm22469 DR_DBG_IO("%s: drctl_config_init failed: %d\n", __func__, rv);
698*7899SJames.Marks@Sun.COM
699*7899SJames.Marks@Sun.COM ASSERT(drctl_resp->resp_type == DRCTL_RESP_ERR);
700*7899SJames.Marks@Sun.COM
701*7899SJames.Marks@Sun.COM (void) strlcpy(res->reason,
702*7899SJames.Marks@Sun.COM drctl_resp->resp_err_msg, DR_VIO_MAXREASONLEN);
7036441Sjm22469
704*7899SJames.Marks@Sun.COM DR_DBG_IO("%s: %s\n", __func__, res->reason);
705*7899SJames.Marks@Sun.COM
706*7899SJames.Marks@Sun.COM goto done;
707*7899SJames.Marks@Sun.COM }
708*7899SJames.Marks@Sun.COM
709*7899SJames.Marks@Sun.COM if (drctl_rsrc->status == DRCTL_STATUS_DENY) {
7106441Sjm22469 res->result = DR_VIO_RES_BLOCKED;
7116441Sjm22469
7126441Sjm22469 DR_DBG_IO("%s: drctl_config_init denied\n", __func__);
713*7899SJames.Marks@Sun.COM p = (char *)drctl_rsrc + drctl_rsrc->offset;
7146441Sjm22469
715*7899SJames.Marks@Sun.COM (void) strlcpy(res->reason, p, DR_VIO_MAXREASONLEN);
7166441Sjm22469
7176441Sjm22469 DR_DBG_IO("%s: %s\n", __func__, res->reason);
7186441Sjm22469
7196441Sjm22469 drctl_req->status = DRCTL_STATUS_CONFIG_FAILURE;
7206441Sjm22469
7216441Sjm22469 rv = EPERM;
7226441Sjm22469 } else if (rv = e_ddi_branch_destroy(dip, &fdip, 0)) {
7236441Sjm22469 char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
7246441Sjm22469
725*7899SJames.Marks@Sun.COM DR_DBG_KMEM("%s: alloc addr %p size %d\n",
726*7899SJames.Marks@Sun.COM __func__, (void *)path, MAXPATHLEN);
7276441Sjm22469 /*
7286441Sjm22469 * If non-NULL, fdip is held and must be released.
7296441Sjm22469 */
7306441Sjm22469 if (fdip != NULL) {
7316441Sjm22469 (void) ddi_pathname(fdip, path);
7326441Sjm22469 ddi_release_devi(fdip);
7336441Sjm22469 } else {
7346441Sjm22469 (void) ddi_pathname(dip, path);
7356441Sjm22469 }
7366441Sjm22469
7376441Sjm22469 DR_DBG_IO("%s: node removal failed: %s (%p)",
7386441Sjm22469 __func__, path, (fdip) ? (void *)fdip : (void *)dip);
7396441Sjm22469
7406441Sjm22469 drctl_req->status = DRCTL_STATUS_CONFIG_FAILURE;
7416441Sjm22469
742*7899SJames.Marks@Sun.COM DR_DBG_KMEM("%s: free addr %p size %d\n",
743*7899SJames.Marks@Sun.COM __func__, (void *)path, MAXPATHLEN);
7446441Sjm22469 kmem_free(path, MAXPATHLEN);
7456441Sjm22469 } else {
7466441Sjm22469 drctl_req->status = DRCTL_STATUS_CONFIG_SUCCESS;
7476441Sjm22469 }
7486441Sjm22469
7496441Sjm22469 if (drctl_config_fini(&drctl_res_ck, drctl_req, 1) != 0)
7506441Sjm22469 DR_DBG_IO("%s: drctl_config_fini returned: %d\n", __func__, rv);
7516441Sjm22469
7526441Sjm22469 DR_DBG_IO("%s: (%s@%ld) = %d\n", __func__, name, devid, rv);
7536441Sjm22469
7546441Sjm22469 if (rv == 0) {
7556441Sjm22469 res->result = DR_VIO_RES_OK;
7566441Sjm22469 res->status = DR_VIO_STAT_UNCONFIGURED;
7576441Sjm22469
7586441Sjm22469 /* Notify interested parties about the operation. */
7596441Sjm22469 dr_generate_event(DR_TYPE_VIO, SE_HINT_REMOVE);
7606441Sjm22469 }
7616441Sjm22469 done:
762*7899SJames.Marks@Sun.COM DR_DBG_KMEM("%s: free addr %p size %ld\n",
763*7899SJames.Marks@Sun.COM __func__, (void *)drctl_req, drctl_req_len);
7646441Sjm22469 kmem_free(drctl_req, drctl_req_len);
7656441Sjm22469
766*7899SJames.Marks@Sun.COM if (drctl_resp) {
767*7899SJames.Marks@Sun.COM DR_DBG_KMEM("%s: free addr %p size %ld\n",
768*7899SJames.Marks@Sun.COM __func__, (void *)drctl_resp, drctl_resp_len);
769*7899SJames.Marks@Sun.COM kmem_free(drctl_resp, drctl_resp_len);
770*7899SJames.Marks@Sun.COM }
7716441Sjm22469
7726441Sjm22469 return (rv);
7736441Sjm22469 }
7746441Sjm22469
7756441Sjm22469 static void
dr_vio_data_handler(ds_cb_arg_t arg,void * buf,size_t buflen)7766441Sjm22469 dr_vio_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
7776441Sjm22469 {
7786441Sjm22469 _NOTE(ARGUNUSED(arg))
7796441Sjm22469
7806441Sjm22469 size_t res_len;
7816441Sjm22469 dr_vio_res_t *res;
7826441Sjm22469 dr_vio_req_t *req;
7836441Sjm22469
7846441Sjm22469 /*
7856441Sjm22469 * Allocate a response buffer, because we always want to
7866441Sjm22469 * send back a response message.
7876441Sjm22469 */
7886441Sjm22469 res_len = sizeof (dr_vio_res_t) + DR_VIO_MAXREASONLEN;
7896441Sjm22469 res = kmem_zalloc(res_len, KM_SLEEP);
790*7899SJames.Marks@Sun.COM DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
791*7899SJames.Marks@Sun.COM __func__, (void *)res, res_len);
7926441Sjm22469 res->result = DR_VIO_RES_FAILURE;
7936441Sjm22469
7946441Sjm22469 /*
7956441Sjm22469 * Sanity check the message
7966441Sjm22469 */
7976441Sjm22469 if (buf == NULL) {
7986441Sjm22469 DR_DBG_IO("empty message: expected at least %ld bytes\n",
7996441Sjm22469 sizeof (dr_vio_req_t));
8006441Sjm22469 goto done;
8016441Sjm22469 }
8026441Sjm22469 if (buflen < sizeof (dr_vio_req_t)) {
8036441Sjm22469 DR_DBG_IO("incoming message short: expected at least %ld "
8046441Sjm22469 "bytes, received %ld\n", sizeof (dr_vio_req_t), buflen);
8056441Sjm22469 goto done;
8066441Sjm22469 }
8076441Sjm22469
8086441Sjm22469 DR_DBG_TRANS("incoming request:\n");
8096441Sjm22469 DR_DBG_DUMP_MSG(buf, buflen);
8106441Sjm22469
8116441Sjm22469 req = buf;
8126441Sjm22469 switch (req->msg_type) {
8136441Sjm22469 case DR_VIO_CONFIGURE:
8146441Sjm22469 (void) dr_io_configure(req, res);
8156441Sjm22469 break;
8166441Sjm22469 case DR_VIO_FORCE_UNCONFIG:
8176441Sjm22469 case DR_VIO_UNCONFIGURE:
8186441Sjm22469 (void) dr_io_unconfigure(req, res);
8196441Sjm22469 break;
8206441Sjm22469 default:
8216441Sjm22469 cmn_err(CE_NOTE, "bad msg_type %d\n", req->msg_type);
8226441Sjm22469 break;
8236441Sjm22469 }
8246441Sjm22469 done:
8256441Sjm22469 res->req_num = (req) ? req->req_num : 0;
8266441Sjm22469
8276441Sjm22469 DR_DBG_TRANS("outgoing response:\n");
8286441Sjm22469 DR_DBG_DUMP_MSG(res, res_len);
8296441Sjm22469
8306441Sjm22469 /* send back the response */
8316441Sjm22469 if (ds_cap_send(ds_vio_handle, res, res_len) != 0)
8326441Sjm22469 DR_DBG_IO("ds_send failed\n");
8336441Sjm22469
834*7899SJames.Marks@Sun.COM if (res) {
835*7899SJames.Marks@Sun.COM DR_DBG_KMEM("%s: free addr %p size %ld\n",
836*7899SJames.Marks@Sun.COM __func__, (void *)res, res_len);
8376441Sjm22469 kmem_free(res, res_len);
838*7899SJames.Marks@Sun.COM }
8396441Sjm22469 }
8406441Sjm22469
8416441Sjm22469 static void
dr_vio_reg_handler(ds_cb_arg_t arg,ds_ver_t * ver,ds_svc_hdl_t hdl)8426441Sjm22469 dr_vio_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl)
8436441Sjm22469 {
8446441Sjm22469 DR_DBG_IO("vio_reg_handler: arg=0x%p, ver=%d.%d, hdl=0x%lx\n",
8456441Sjm22469 arg, ver->major, ver->minor, hdl);
8466441Sjm22469
8476441Sjm22469 ds_vio_handle = hdl;
8486441Sjm22469 }
8496441Sjm22469
8506441Sjm22469 static void
dr_vio_unreg_handler(ds_cb_arg_t arg)8516441Sjm22469 dr_vio_unreg_handler(ds_cb_arg_t arg)
8526441Sjm22469 {
8536441Sjm22469 DR_DBG_IO("vio_unreg_handler: arg=0x%p\n", arg);
8546441Sjm22469
8556441Sjm22469 ds_vio_handle = DS_INVALID_HDL;
8566441Sjm22469 }
8576441Sjm22469
8586441Sjm22469 static int
dr_io_init(void)8596441Sjm22469 dr_io_init(void)
8606441Sjm22469 {
8616441Sjm22469 int rv;
8626441Sjm22469
8636441Sjm22469 if ((rv = ds_cap_init(&dr_vio_cap, &dr_vio_ops)) != 0) {
8646441Sjm22469 cmn_err(CE_NOTE, "ds_cap_init vio failed: %d", rv);
8656441Sjm22469 return (-1);
8666441Sjm22469 }
8676441Sjm22469
8686441Sjm22469 return (0);
8696441Sjm22469 }
8706441Sjm22469
8716441Sjm22469 static int
dr_io_fini(void)8726441Sjm22469 dr_io_fini(void)
8736441Sjm22469 {
8746441Sjm22469 int rv;
8756441Sjm22469
8766441Sjm22469 if ((rv = ds_cap_fini(&dr_vio_cap)) != 0) {
8776441Sjm22469 cmn_err(CE_NOTE, "ds_cap_fini vio failed: %d", rv);
8786441Sjm22469 return (-1);
8796441Sjm22469 }
8806441Sjm22469
8816441Sjm22469 return (0);
8826441Sjm22469 }
8836441Sjm22469
8846441Sjm22469 int
_init(void)8856441Sjm22469 _init(void)
8866441Sjm22469 {
8876441Sjm22469 int status;
8886441Sjm22469
8896441Sjm22469 /* check that IO DR is enabled */
8906441Sjm22469 if (dr_is_disabled(DR_TYPE_VIO)) {
8916441Sjm22469 cmn_err(CE_CONT, "!VIO DR is disabled\n");
8926441Sjm22469 return (-1);
8936441Sjm22469 }
8946441Sjm22469
8956441Sjm22469 if ((status = dr_io_init()) != 0) {
8966441Sjm22469 cmn_err(CE_NOTE, "VIO DR initialization failed");
8976441Sjm22469 return (status);
8986441Sjm22469 }
8996441Sjm22469
9006441Sjm22469 if ((status = mod_install(&modlinkage)) != 0) {
9016441Sjm22469 (void) dr_io_fini();
9026441Sjm22469 }
9036441Sjm22469
9046441Sjm22469 return (status);
9056441Sjm22469 }
9066441Sjm22469
9076441Sjm22469 int
_info(struct modinfo * modinfop)9086441Sjm22469 _info(struct modinfo *modinfop)
9096441Sjm22469 {
9106441Sjm22469 return (mod_info(&modlinkage, modinfop));
9116441Sjm22469 }
9126441Sjm22469
9136441Sjm22469 int dr_io_allow_unload = 0;
9146441Sjm22469
9156441Sjm22469 int
_fini(void)9166441Sjm22469 _fini(void)
9176441Sjm22469 {
9186441Sjm22469 int status;
9196441Sjm22469
9206441Sjm22469 if (dr_io_allow_unload == 0)
9216441Sjm22469 return (EBUSY);
9226441Sjm22469
9236441Sjm22469 if ((status = mod_remove(&modlinkage)) == 0) {
9246441Sjm22469 (void) dr_io_fini();
9256441Sjm22469 }
9266441Sjm22469
9276441Sjm22469 return (status);
9286441Sjm22469 }
929