1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * sun4v VIO DR Module 29 */ 30 31 #include <sys/modctl.h> 32 #include <sys/sunddi.h> 33 #include <sys/sunndi.h> 34 #include <sys/note.h> 35 #include <sys/sysevent/dr.h> 36 #include <sys/hypervisor_api.h> 37 #include <sys/mach_descrip.h> 38 #include <sys/mdesc.h> 39 #include <sys/mdesc_impl.h> 40 #include <sys/ds.h> 41 #include <sys/drctl.h> 42 #include <sys/dr_util.h> 43 #include <sys/dr_io.h> 44 #include <sys/promif.h> 45 #include <sys/machsystm.h> 46 #include <sys/ethernet.h> 47 #include <sys/hotplug/pci/pcicfg.h> 48 49 50 static struct modlmisc modlmisc = { 51 &mod_miscops, 52 "sun4v VIO DR" 53 }; 54 55 static struct modlinkage modlinkage = { 56 MODREV_1, 57 (void *)&modlmisc, 58 NULL 59 }; 60 61 62 /* 63 * VIO DS Interface 64 */ 65 66 /* 67 * Global DS Handle 68 */ 69 static ds_svc_hdl_t ds_vio_handle; 70 71 /* 72 * Supported DS Capability Versions 73 */ 74 static ds_ver_t dr_vio_vers[] = { { 1, 0 } }; 75 #define DR_VIO_NVERS (sizeof (dr_vio_vers) / sizeof (dr_vio_vers[0])) 76 77 /* 78 * DS Capability Description 79 */ 80 static ds_capability_t dr_vio_cap = { 81 DR_VIO_DS_ID, /* svc_id */ 82 dr_vio_vers, /* vers */ 83 DR_VIO_NVERS /* nvers */ 84 }; 85 86 /* 87 * DS Callbacks 88 */ 89 static void dr_vio_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t); 90 static void dr_vio_unreg_handler(ds_cb_arg_t arg); 91 static void dr_vio_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen); 92 93 /* 94 * DS Client Ops Vector 95 */ 96 static ds_clnt_ops_t dr_vio_ops = { 97 dr_vio_reg_handler, /* ds_reg_cb */ 98 dr_vio_unreg_handler, /* ds_unreg_cb */ 99 dr_vio_data_handler, /* ds_data_cb */ 100 NULL /* cb_arg */ 101 }; 102 103 104 typedef struct { 105 char *name; 106 uint64_t devid; 107 dev_info_t *dip; 108 } dr_search_arg_t; 109 110 static int 111 dr_io_check_node(dev_info_t *dip, void *arg) 112 { 113 char *name; 114 uint64_t devid; 115 dr_search_arg_t *sarg = (dr_search_arg_t *)arg; 116 117 name = ddi_node_name(dip); 118 119 if (strcmp(name, sarg->name) != 0) 120 return (DDI_WALK_CONTINUE); 121 122 devid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 123 "reg", -1); 124 125 DR_DBG_IO("%s: found devid=%ld, looking for %ld\n", 126 __func__, devid, sarg->devid); 127 128 if (devid == sarg->devid) { 129 DR_DBG_IO("%s: matched", __func__); 130 131 /* matching node must be returned held */ 132 if (!e_ddi_branch_held(dip)) 133 e_ddi_branch_hold(dip); 134 135 sarg->dip = dip; 136 return (DDI_WALK_TERMINATE); 137 } 138 139 return (DDI_WALK_CONTINUE); 140 } 141 142 /* 143 * Walk the device tree to find the dip corresponding to the devid 144 * passed in. If present, the dip is returned held. The caller must 145 * release the hold on the dip once it is no longer required. If no 146 * matching node if found, NULL is returned. 147 */ 148 static dev_info_t * 149 dr_io_find_node(char *name, uint64_t devid) 150 { 151 dr_search_arg_t arg; 152 153 DR_DBG_IO("dr_io_find_node...\n"); 154 155 arg.name = name; 156 arg.devid = devid; 157 arg.dip = NULL; 158 159 ddi_walk_devs(ddi_root_node(), dr_io_check_node, &arg); 160 161 ASSERT((arg.dip == NULL) || (e_ddi_branch_held(arg.dip))); 162 163 return ((arg.dip) ? arg.dip : NULL); 164 } 165 166 /* 167 * Look up a particular IO node in the MD. Returns the mde_cookie_t 168 * representing that IO node if present, and MDE_INVAL_ELEM_COOKIE otherwise. 169 * It is assumed the scratch array has already been allocated so that 170 * it can accommodate the worst case scenario, every node in the MD. 171 */ 172 static mde_cookie_t 173 dr_io_find_node_md(md_t *mdp, char *name, uint64_t id, mde_cookie_t *listp) 174 { 175 int i; 176 int nnodes; 177 char *devnm; 178 uint64_t devid; 179 mde_cookie_t rootnode; 180 mde_cookie_t result = MDE_INVAL_ELEM_COOKIE; 181 182 DR_DBG_IO("%s: %s@%ld\n", __func__, name, id); 183 184 rootnode = md_root_node(mdp); 185 ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE); 186 187 /* 188 * Scan the DAG for all candidate nodes. 189 */ 190 nnodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "virtual-device"), 191 md_find_name(mdp, "fwd"), listp); 192 193 if (nnodes < 0) { 194 DR_DBG_IO("%s: scan for " 195 "'virtual-device' nodes failed\n", __func__); 196 return (result); 197 } 198 199 DR_DBG_IO("%s: found %d nodes in the MD\n", __func__, nnodes); 200 201 /* 202 * Find the node of interest 203 */ 204 for (i = 0; i < nnodes; i++) { 205 206 if (md_get_prop_str(mdp, listp[i], "name", &devnm)) { 207 DR_DBG_IO("%s: missing 'name' property for" 208 " IO node %d\n", __func__, i); 209 return (DDI_WALK_ERROR); 210 } 211 212 if (strcmp(devnm, name) != 0) 213 continue; 214 215 if (md_get_prop_val(mdp, listp[i], "cfg-handle", &devid)) { 216 DR_DBG_IO("%s: missing 'cfg-handle' property for" 217 " IO node %d\n", __func__, i); 218 break; 219 } 220 221 if (devid == id) { 222 /* found a match */ 223 DR_DBG_IO("%s: found IO node %s@%ld " 224 "in MD\n", __func__, name, id); 225 result = listp[i]; 226 break; 227 } 228 } 229 230 if (result == MDE_INVAL_ELEM_COOKIE) 231 DR_DBG_IO("%s: IO node %ld not in MD\n", __func__, id); 232 233 return (result); 234 } 235 236 typedef struct { 237 md_t *mdp; 238 mde_cookie_t node; 239 dev_info_t *dip; 240 } cb_arg_t; 241 242 #define STR_ARR_LEN 5 243 244 static int 245 new_dev_node(dev_info_t *new_node, void *arg, uint_t flags) 246 { 247 _NOTE(ARGUNUSED(flags)) 248 249 cb_arg_t *cba; 250 char *devnm, *devtype; 251 char *compat; 252 uint64_t devid; 253 int len = 0; 254 char *curr; 255 int i = 0; 256 char *str_arr[STR_ARR_LEN]; 257 258 cba = (cb_arg_t *)arg; 259 260 /* 261 * Add 'name' property 262 */ 263 if (md_get_prop_str(cba->mdp, cba->node, "name", &devnm)) { 264 DR_DBG_IO("%s: failed to read 'name' prop from MD\n", __func__); 265 return (DDI_WALK_ERROR); 266 } 267 DR_DBG_IO("%s: device name is %s\n", __func__, devnm); 268 269 if (ndi_prop_update_string(DDI_DEV_T_NONE, new_node, 270 "name", devnm) != DDI_SUCCESS) { 271 DR_DBG_IO("%s: failed to create 'name' prop\n", __func__); 272 return (DDI_WALK_ERROR); 273 } 274 275 /* 276 * Add 'compatible' property 277 */ 278 if (md_get_prop_data(cba->mdp, cba->node, "compatible", 279 (uint8_t **)&compat, &len)) { 280 DR_DBG_IO("%s: failed to read " 281 "'compatible' prop from MD\n", __func__); 282 return (DDI_WALK_ERROR); 283 } 284 285 /* parse the MD string array */ 286 curr = compat; 287 while (curr < (compat + len)) { 288 289 DR_DBG_IO("%s: adding '%s' to " 290 "'compatible' prop\n", __func__, curr); 291 292 str_arr[i++] = curr; 293 curr += strlen(curr) + 1; 294 295 if (i == STR_ARR_LEN) { 296 DR_DBG_CPU("exceeded str_arr len (%d)\n", STR_ARR_LEN); 297 break; 298 } 299 } 300 301 302 if (ndi_prop_update_string_array(DDI_DEV_T_NONE, new_node, 303 "compatible", str_arr, i) != DDI_SUCCESS) { 304 DR_DBG_IO("%s: cannot create 'compatible' prop\n", __func__); 305 return (DDI_WALK_ERROR); 306 } 307 308 /* 309 * Add 'device_type' property 310 */ 311 if (md_get_prop_str(cba->mdp, cba->node, "device-type", &devtype)) { 312 DR_DBG_IO("%s: failed to read " 313 "'device-type' prop from MD\n", __func__); 314 return (DDI_WALK_ERROR); 315 } 316 if (ndi_prop_update_string(DDI_DEV_T_NONE, new_node, 317 "device_type", devtype) != DDI_SUCCESS) { 318 DR_DBG_IO("%s: failed to create " 319 "'device-type' prop\n", __func__); 320 return (DDI_WALK_ERROR); 321 } 322 323 DR_DBG_IO("%s: device type is %s\n", __func__, devtype); 324 325 /* 326 * Add 'reg' (cfg-handle) property 327 */ 328 if (md_get_prop_val(cba->mdp, cba->node, "cfg-handle", &devid)) { 329 DR_DBG_IO("%s: failed to read " 330 "'cfg-handle' prop from MD\n", __func__); 331 return (DDI_WALK_ERROR); 332 } 333 334 DR_DBG_IO("%s: new device is %s@%ld\n", __func__, devnm, devid); 335 336 if (ndi_prop_update_int(DDI_DEV_T_NONE, new_node, "reg", devid) 337 != DDI_SUCCESS) { 338 DR_DBG_IO("%s: failed to create 'reg' prop\n", __func__); 339 return (DDI_WALK_ERROR); 340 } 341 342 /* if vnet/vswitch, probe and add mac-address and mtu properties */ 343 if (strcmp(devnm, "vsw") == 0 || strcmp(devnm, "network") == 0) { 344 345 int i, j; 346 uint64_t mtu, macaddr; 347 uchar_t maddr_arr[ETHERADDRL]; 348 349 if (md_get_prop_val(cba->mdp, cba->node, "local-mac-address", 350 &macaddr)) { 351 DR_DBG_IO("%s: failed to read " 352 "'local-mac-address' prop from MD\n", __func__); 353 return (DDI_WALK_ERROR); 354 } 355 356 for (i = 0, j = (ETHERADDRL - 1); i < ETHERADDRL; i++, j--) 357 maddr_arr[j] = (macaddr >> (i * 8)) & 0xff; 358 359 if (ndi_prop_update_byte_array(DDI_DEV_T_NONE, new_node, 360 "local-mac-address", maddr_arr, ETHERADDRL) 361 != DDI_SUCCESS) { 362 DR_DBG_IO("%s: failed to create " 363 "'local-mac-address' prop\n", __func__); 364 return (DDI_WALK_ERROR); 365 } 366 367 if (md_get_prop_val(cba->mdp, cba->node, "mtu", &mtu)) { 368 DR_DBG_IO("%s: failed to read " 369 "'mtu' prop from MD\n", __func__); 370 return (DDI_WALK_ERROR); 371 } 372 373 if (ndi_prop_update_int64(DDI_DEV_T_NONE, new_node, "mtu", 374 mtu) != DDI_SUCCESS) { 375 DR_DBG_IO("%s: failed to " 376 "create 'mtu' prop\n", __func__); 377 return (DDI_WALK_ERROR); 378 } 379 380 DR_DBG_IO("%s: Added properties for %s@%ld, " 381 "mac=%ld, mtu=%ld\n", __func__, devnm, devid, macaddr, mtu); 382 } 383 384 cba->dip = new_node; 385 386 return (DDI_WALK_TERMINATE); 387 } 388 389 /* 390 * Find the parent node of the argument virtual device node in 391 * the MD. For virtual devices, the parent is always 392 * "channel-devices", so scan the MD using the "back" arcs 393 * looking for a node with that name. 394 */ 395 static mde_cookie_t 396 dr_vio_find_parent_md(md_t *mdp, mde_cookie_t node) 397 { 398 int max_nodes; 399 int num_nodes; 400 int listsz; 401 mde_cookie_t *listp; 402 mde_cookie_t pnode = MDE_INVAL_ELEM_COOKIE; 403 404 max_nodes = md_node_count(mdp); 405 listsz = max_nodes * sizeof (mde_cookie_t); 406 listp = kmem_zalloc(listsz, KM_SLEEP); 407 408 num_nodes = md_scan_dag(mdp, node, 409 md_find_name(mdp, "channel-devices"), 410 md_find_name(mdp, "back"), listp); 411 412 ASSERT(num_nodes == 1); 413 414 if (num_nodes == 1) 415 pnode = listp[0]; 416 417 kmem_free(listp, listsz); 418 419 return (pnode); 420 } 421 422 static int 423 dr_io_configure(dr_vio_req_t *req, dr_vio_res_t *res) 424 { 425 int rv = ENXIO; 426 int listsz; 427 int nnodes; 428 uint64_t devid = req->dev_id; 429 uint64_t pdevid; 430 char *name = req->name; 431 char *pname; 432 md_t *mdp = NULL; 433 mde_cookie_t *listp = NULL; 434 mde_cookie_t node; 435 mde_cookie_t pnode; 436 dev_info_t *pdip = NULL; 437 dev_info_t *dip; 438 devi_branch_t br; 439 cb_arg_t cba; 440 int drctl_cmd; 441 int drctl_flags = 0; 442 drctl_rsrc_t *drctl_req; 443 size_t drctl_req_len; 444 drctl_rsrc_t *drctl_res = NULL; 445 size_t drctl_res_len = 0; 446 drctl_cookie_t drctl_res_ck; 447 char *p; 448 size_t reason_len; 449 450 res->result = DR_VIO_RES_FAILURE; 451 452 if ((dip = dr_io_find_node(name, devid)) != NULL) { 453 DR_DBG_IO("%s: %s@%ld already configured\n", 454 __func__, name, devid); 455 456 /* Return success if resources is already there. */ 457 res->result = DR_VIO_RES_OK; 458 res->status = DR_VIO_STAT_CONFIGURED; 459 e_ddi_branch_rele(dip); 460 return (0); 461 } 462 463 /* Assume we fail to find the node to be added. */ 464 res->status = DR_VIO_STAT_NOT_PRESENT; 465 466 if ((mdp = md_get_handle()) == NULL) { 467 DR_DBG_IO("%s: unable to initialize MD\n", __func__); 468 return (ENXIO); 469 } 470 471 nnodes = md_node_count(mdp); 472 ASSERT(nnodes > 0); 473 474 listsz = nnodes * sizeof (mde_cookie_t); 475 listp = kmem_zalloc(listsz, KM_SLEEP); 476 477 /* 478 * Get the MD device node. 479 */ 480 node = dr_io_find_node_md(mdp, name, devid, listp); 481 482 if (node == MDE_INVAL_ELEM_COOKIE) { 483 DR_DBG_IO("%s: scan for %s name node failed\n", __func__, name); 484 res->result = DR_VIO_RES_NOT_IN_MD; 485 goto done; 486 } 487 488 /* 489 * Get the MD parent node. 490 */ 491 pnode = dr_vio_find_parent_md(mdp, node); 492 if (pnode == MDE_INVAL_ELEM_COOKIE) { 493 DR_DBG_IO("%s: failed to find MD parent of %lx\n", 494 __func__, pnode); 495 goto done; 496 } 497 498 if (md_get_prop_str(mdp, pnode, "name", &pname)) { 499 DR_DBG_IO("%s: failed to read " 500 "'name' for pnode %lx from MD\n", __func__, pnode); 501 goto done; 502 } 503 504 if (md_get_prop_val(mdp, pnode, "cfg-handle", &pdevid)) { 505 DR_DBG_IO("%s: failed to read 'cfg-handle' " 506 "for pnode '%s' from MD\n", __func__, pname); 507 goto done; 508 } 509 510 DR_DBG_IO("%s: parent device %s@%lx\n", __func__, pname, pdevid); 511 512 /* 513 * Get the devinfo parent node. 514 */ 515 if ((pdip = dr_io_find_node(pname, pdevid)) == NULL) { 516 DR_DBG_IO("%s: parent device %s@%ld not found\n", 517 __func__, pname, pdevid); 518 goto done; 519 } 520 521 drctl_req_len = sizeof (drctl_rsrc_t) + MAXPATHLEN; 522 drctl_req = kmem_zalloc(drctl_req_len, KM_SLEEP); 523 drctl_req->status = DRCTL_STATUS_INIT; 524 525 drctl_cmd = DRCTL_IO_CONFIG_REQUEST; 526 527 /* 528 * Construct the path of the device as it will be if it 529 * is successfully added. 530 */ 531 p = drctl_req->res_dev_path; 532 (void) sprintf(p, "/devices"); 533 (void) ddi_pathname(pdip, p + strlen(p)); 534 (void) sprintf(p + strlen(p), "/%s@%ld", name, devid); 535 DR_DBG_IO("%s: devpath=%s\n", __func__, drctl_req->res_dev_path); 536 537 if ((rv = drctl_config_init(drctl_cmd, drctl_flags, drctl_req, 538 1, &drctl_res, &drctl_res_len, &drctl_res_ck)) != 0) { 539 540 DR_DBG_IO("%s: drctl_config_init failed: %d\n", __func__, rv); 541 goto done; 542 543 } else if (drctl_res->status == DRCTL_STATUS_DENY) { 544 res->result = DR_VIO_RES_BLOCKED; 545 546 DR_DBG_IO("%s: drctl_config_init denied\n", __func__); 547 p = (char *)drctl_res + drctl_res->offset; 548 reason_len = strlen(p); 549 550 if (reason_len >= DR_VIO_MAXREASONLEN) 551 reason_len = DR_VIO_MAXREASONLEN - 1; 552 553 (void) strncpy(res->reason, p, reason_len); 554 res->reason[reason_len] = '\0'; 555 DR_DBG_IO("%s: %s\n", __func__, res->reason); 556 557 drctl_req->status = DRCTL_STATUS_CONFIG_FAILURE; 558 559 rv = EPERM; 560 } else { 561 cba.mdp = mdp; 562 cba.node = node; 563 564 br.arg = (void *)&cba; 565 br.type = DEVI_BRANCH_SID; 566 br.create.sid_branch_create = new_dev_node; 567 br.devi_branch_callback = NULL; 568 569 rv = e_ddi_branch_create(pdip, 570 &br, NULL, DEVI_BRANCH_CONFIGURE); 571 572 drctl_req->status = (rv == 0) ? 573 DRCTL_STATUS_CONFIG_SUCCESS : DRCTL_STATUS_CONFIG_FAILURE; 574 575 DR_DBG_IO("%s: %s@%ld = %d\n", __func__, name, devid, rv); 576 } 577 578 if (drctl_config_fini(&drctl_res_ck, drctl_req, 1) != 0) 579 DR_DBG_IO("%s: drctl_config_fini returned: %d\n", __func__, rv); 580 581 done: 582 if (listp) 583 kmem_free(listp, listsz); 584 585 if (mdp) 586 (void) md_fini_handle(mdp); 587 588 if (pdip) 589 e_ddi_branch_rele(pdip); 590 591 kmem_free(drctl_req, drctl_req_len); 592 if (drctl_res) 593 kmem_free(drctl_res, drctl_res_len); 594 595 if (rv == 0) { 596 res->result = DR_VIO_RES_OK; 597 res->status = DR_VIO_STAT_CONFIGURED; 598 599 /* notify interested parties about the operation */ 600 dr_generate_event(DR_TYPE_VIO, SE_HINT_INSERT); 601 } else { 602 res->status = DR_VIO_STAT_UNCONFIGURED; 603 } 604 605 return (rv); 606 } 607 608 static int 609 dr_io_unconfigure(dr_vio_req_t *req, dr_vio_res_t *res) 610 { 611 int rv; 612 char *name = req->name; 613 char *p; 614 uint64_t devid = req->dev_id; 615 dev_info_t *dip; 616 dev_info_t *fdip = NULL; 617 int drctl_cmd; 618 int drctl_flags = 0; 619 drctl_rsrc_t *drctl_req; 620 size_t drctl_req_len; 621 drctl_rsrc_t *drctl_res = NULL; 622 size_t drctl_res_len = 0; 623 drctl_cookie_t drctl_res_ck; 624 size_t reason_len; 625 626 if ((dip = dr_io_find_node(name, devid)) == NULL) { 627 DR_DBG_IO("%s: %s@%ld already unconfigured\n", 628 __func__, name, devid); 629 res->result = DR_VIO_RES_OK; 630 res->status = DR_VIO_STAT_NOT_PRESENT; 631 return (0); 632 } 633 634 res->result = DR_VIO_RES_FAILURE; 635 636 ASSERT(e_ddi_branch_held(dip)); 637 638 /* Assume we fail to unconfigure the resource. */ 639 res->status = DR_VIO_STAT_CONFIGURED; 640 641 drctl_req_len = sizeof (drctl_rsrc_t) + MAXPATHLEN; 642 drctl_req = kmem_zalloc(drctl_req_len, KM_SLEEP); 643 drctl_req->status = DRCTL_STATUS_INIT; 644 645 drctl_cmd = DRCTL_IO_UNCONFIG_REQUEST; 646 647 if (req->msg_type == DR_VIO_FORCE_UNCONFIG) 648 drctl_flags = DRCTL_FLAG_FORCE; 649 650 p = drctl_req->res_dev_path; 651 (void) sprintf(p, "/devices"); 652 (void) ddi_pathname(dip, p + strlen(p)); 653 DR_DBG_IO("%s: devpath=%s\n", __func__, drctl_req->res_dev_path); 654 655 if ((rv = drctl_config_init(drctl_cmd, drctl_flags, drctl_req, 656 1, &drctl_res, &drctl_res_len, &drctl_res_ck)) != 0) { 657 658 DR_DBG_IO("%s: drctl_config_init failed: %d\n", __func__, rv); 659 goto done; 660 661 } else if (drctl_res->status == DRCTL_STATUS_DENY) { 662 res->result = DR_VIO_RES_BLOCKED; 663 664 DR_DBG_IO("%s: drctl_config_init denied\n", __func__); 665 p = (char *)drctl_res + drctl_res->offset; 666 reason_len = strlen(p); 667 668 if (reason_len >= DR_VIO_MAXREASONLEN) 669 reason_len = DR_VIO_MAXREASONLEN - 1; 670 671 (void) strncpy(res->reason, p, reason_len); 672 res->reason[reason_len] = '\0'; 673 DR_DBG_IO("%s: %s\n", __func__, res->reason); 674 675 drctl_req->status = DRCTL_STATUS_CONFIG_FAILURE; 676 677 rv = EPERM; 678 } else if (rv = e_ddi_branch_destroy(dip, &fdip, 0)) { 679 char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 680 681 /* 682 * If non-NULL, fdip is held and must be released. 683 */ 684 if (fdip != NULL) { 685 (void) ddi_pathname(fdip, path); 686 ddi_release_devi(fdip); 687 } else { 688 (void) ddi_pathname(dip, path); 689 } 690 691 DR_DBG_IO("%s: node removal failed: %s (%p)", 692 __func__, path, (fdip) ? (void *)fdip : (void *)dip); 693 694 drctl_req->status = DRCTL_STATUS_CONFIG_FAILURE; 695 696 kmem_free(path, MAXPATHLEN); 697 } else { 698 drctl_req->status = DRCTL_STATUS_CONFIG_SUCCESS; 699 } 700 701 if (drctl_config_fini(&drctl_res_ck, drctl_req, 1) != 0) 702 DR_DBG_IO("%s: drctl_config_fini returned: %d\n", __func__, rv); 703 704 DR_DBG_IO("%s: (%s@%ld) = %d\n", __func__, name, devid, rv); 705 706 if (rv == 0) { 707 res->result = DR_VIO_RES_OK; 708 res->status = DR_VIO_STAT_UNCONFIGURED; 709 710 /* Notify interested parties about the operation. */ 711 dr_generate_event(DR_TYPE_VIO, SE_HINT_REMOVE); 712 } 713 done: 714 kmem_free(drctl_req, drctl_req_len); 715 716 if (drctl_res) 717 kmem_free(drctl_res, drctl_res_len); 718 719 return (rv); 720 } 721 722 static void 723 dr_vio_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen) 724 { 725 _NOTE(ARGUNUSED(arg)) 726 727 size_t res_len; 728 dr_vio_res_t *res; 729 dr_vio_req_t *req; 730 731 /* 732 * Allocate a response buffer, because we always want to 733 * send back a response message. 734 */ 735 res_len = sizeof (dr_vio_res_t) + DR_VIO_MAXREASONLEN; 736 res = kmem_zalloc(res_len, KM_SLEEP); 737 res->result = DR_VIO_RES_FAILURE; 738 739 /* 740 * Sanity check the message 741 */ 742 if (buf == NULL) { 743 DR_DBG_IO("empty message: expected at least %ld bytes\n", 744 sizeof (dr_vio_req_t)); 745 goto done; 746 } 747 if (buflen < sizeof (dr_vio_req_t)) { 748 DR_DBG_IO("incoming message short: expected at least %ld " 749 "bytes, received %ld\n", sizeof (dr_vio_req_t), buflen); 750 goto done; 751 } 752 753 DR_DBG_TRANS("incoming request:\n"); 754 DR_DBG_DUMP_MSG(buf, buflen); 755 756 req = buf; 757 switch (req->msg_type) { 758 case DR_VIO_CONFIGURE: 759 (void) dr_io_configure(req, res); 760 break; 761 case DR_VIO_FORCE_UNCONFIG: 762 case DR_VIO_UNCONFIGURE: 763 (void) dr_io_unconfigure(req, res); 764 break; 765 default: 766 cmn_err(CE_NOTE, "bad msg_type %d\n", req->msg_type); 767 break; 768 } 769 done: 770 res->req_num = (req) ? req->req_num : 0; 771 772 DR_DBG_TRANS("outgoing response:\n"); 773 DR_DBG_DUMP_MSG(res, res_len); 774 775 /* send back the response */ 776 if (ds_cap_send(ds_vio_handle, res, res_len) != 0) 777 DR_DBG_IO("ds_send failed\n"); 778 779 if (res) 780 kmem_free(res, res_len); 781 } 782 783 static void 784 dr_vio_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl) 785 { 786 DR_DBG_IO("vio_reg_handler: arg=0x%p, ver=%d.%d, hdl=0x%lx\n", 787 arg, ver->major, ver->minor, hdl); 788 789 ds_vio_handle = hdl; 790 } 791 792 static void 793 dr_vio_unreg_handler(ds_cb_arg_t arg) 794 { 795 DR_DBG_IO("vio_unreg_handler: arg=0x%p\n", arg); 796 797 ds_vio_handle = DS_INVALID_HDL; 798 } 799 800 static int 801 dr_io_init(void) 802 { 803 int rv; 804 805 if ((rv = ds_cap_init(&dr_vio_cap, &dr_vio_ops)) != 0) { 806 cmn_err(CE_NOTE, "ds_cap_init vio failed: %d", rv); 807 return (-1); 808 } 809 810 return (0); 811 } 812 813 static int 814 dr_io_fini(void) 815 { 816 int rv; 817 818 if ((rv = ds_cap_fini(&dr_vio_cap)) != 0) { 819 cmn_err(CE_NOTE, "ds_cap_fini vio failed: %d", rv); 820 return (-1); 821 } 822 823 return (0); 824 } 825 826 int 827 _init(void) 828 { 829 int status; 830 831 /* check that IO DR is enabled */ 832 if (dr_is_disabled(DR_TYPE_VIO)) { 833 cmn_err(CE_CONT, "!VIO DR is disabled\n"); 834 return (-1); 835 } 836 837 if ((status = dr_io_init()) != 0) { 838 cmn_err(CE_NOTE, "VIO DR initialization failed"); 839 return (status); 840 } 841 842 if ((status = mod_install(&modlinkage)) != 0) { 843 (void) dr_io_fini(); 844 } 845 846 return (status); 847 } 848 849 int 850 _info(struct modinfo *modinfop) 851 { 852 return (mod_info(&modlinkage, modinfop)); 853 } 854 855 int dr_io_allow_unload = 0; 856 857 int 858 _fini(void) 859 { 860 int status; 861 862 if (dr_io_allow_unload == 0) 863 return (EBUSY); 864 865 if ((status = mod_remove(&modlinkage)) == 0) { 866 (void) dr_io_fini(); 867 } 868 869 return (status); 870 } 871