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 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/file.h> 31 #include <sys/errno.h> 32 #include <sys/uio.h> 33 #include <sys/open.h> 34 #include <sys/cred.h> 35 #include <sys/kmem.h> 36 #include <sys/conf.h> 37 #include <sys/cmn_err.h> 38 #include <sys/ksynch.h> 39 #include <sys/modctl.h> 40 #include <sys/stat.h> /* needed for S_IFBLK and S_IFCHR */ 41 #include <sys/debug.h> 42 #include <sys/sysmacros.h> 43 #include <sys/types.h> 44 #include <sys/cred.h> 45 #include <sys/promif.h> 46 #include <sys/ddi.h> 47 #include <sys/sunddi.h> 48 #include <sys/cyclic.h> 49 #include <sys/note.h> 50 #include <sys/mach_descrip.h> 51 #include <sys/mdeg.h> 52 #include <sys/ldc.h> 53 #include <sys/vldc_impl.h> 54 55 /* 56 * Function prototypes. 57 */ 58 59 /* DDI entrypoints */ 60 static int vldc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 61 static int vldc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 62 static int vldc_open(dev_t *devp, int flag, int otyp, cred_t *cred); 63 static int vldc_close(dev_t dev, int flag, int otyp, cred_t *cred); 64 static int vldc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 65 cred_t *credp, int *rvalp); 66 static int vldc_read(dev_t dev, struct uio *uiop, cred_t *credp); 67 static int vldc_write(dev_t dev, struct uio *uiop, cred_t *credp); 68 static int vldc_chpoll(dev_t dev, short events, int anyyet, 69 short *reventsp, struct pollhead **phpp); 70 71 /* Internal functions */ 72 static uint_t i_vldc_cb(uint64_t event, caddr_t arg); 73 static int i_vldc_mdeg_cb(void *cb_argp, mdeg_result_t *resp); 74 static int i_vldc_mdeg_register(vldc_t *vldcp); 75 static int i_vldc_mdeg_unregister(vldc_t *vldcp); 76 static int i_vldc_add_port(vldc_t *vldcp, md_t *mdp, mde_cookie_t node); 77 static int i_vldc_remove_port(vldc_t *vldcp, uint_t portno); 78 static int i_vldc_close_port(vldc_t *vldcp, uint_t portno); 79 80 /* soft state structure */ 81 static void *vldc_ssp; 82 83 /* 84 * Matching criteria passed to the MDEG to register interest 85 * in changes to 'virtual-device-port' nodes identified by their 86 * 'id' property. 87 */ 88 static md_prop_match_t vport_prop_match[] = { 89 { MDET_PROP_VAL, "id" }, 90 { MDET_LIST_END, NULL } 91 }; 92 93 static mdeg_node_match_t vport_match = { "virtual-device-port", 94 vport_prop_match }; 95 96 /* 97 * Specification of an MD node passed to the MDEG to filter any 98 * 'virtual-device-port' nodes that do not belong to the specified 99 * node. This template is copied for each vldc instance and filled 100 * in with the appropriate 'name' and 'cfg-handle' values before 101 * being passed to the MDEG. 102 */ 103 static mdeg_prop_spec_t vldc_prop_template[] = { 104 { MDET_PROP_STR, "name", NULL }, 105 { MDET_PROP_VAL, "cfg-handle", NULL }, 106 { MDET_LIST_END, NULL, NULL } 107 }; 108 109 #define VLDC_MDEG_PROP_NAME(specp) ((specp)[0].ps_str) 110 #define VLDC_SET_MDEG_PROP_NAME(specp, name) ((specp)[0].ps_str = (name)) 111 #define VLDC_SET_MDEG_PROP_INST(specp, inst) ((specp)[1].ps_val = (inst)) 112 113 114 static struct cb_ops vldc_cb_ops = { 115 vldc_open, /* open */ 116 vldc_close, /* close */ 117 nodev, /* strategy */ 118 nodev, /* print */ 119 nodev, /* dump */ 120 vldc_read, /* read */ 121 vldc_write, /* write */ 122 vldc_ioctl, /* ioctl */ 123 nodev, /* devmap */ 124 nodev, /* mmap */ 125 ddi_segmap, /* segmap */ 126 vldc_chpoll, /* chpoll */ 127 ddi_prop_op, /* prop_op */ 128 NULL, /* stream */ 129 D_NEW | D_MP /* flag */ 130 }; 131 132 static struct dev_ops vldc_ops = { 133 DEVO_REV, /* rev */ 134 0, /* ref count */ 135 ddi_getinfo_1to1, /* getinfo */ 136 nulldev, /* identify */ 137 nulldev, /* probe */ 138 vldc_attach, /* attach */ 139 vldc_detach, /* detach */ 140 nodev, /* reset */ 141 &vldc_cb_ops, /* cb_ops */ 142 (struct bus_ops *)NULL /* bus_ops */ 143 }; 144 145 extern struct mod_ops mod_driverops; 146 147 static struct modldrv md = { 148 &mod_driverops, /* Type - it is a driver */ 149 "sun4v Virtual LDC Driver %I%", /* Name of the module */ 150 &vldc_ops, /* driver specific ops */ 151 }; 152 153 static struct modlinkage ml = { 154 MODREV_1, 155 &md, 156 NULL 157 }; 158 159 /* maximum MTU and cookie size tunables */ 160 uint32_t vldc_max_mtu = VLDC_MAX_MTU; 161 uint64_t vldc_max_cookie = VLDC_MAX_COOKIE; 162 163 /* 164 * when ldc_close() returns EAGAIN, it is retried with a wait 165 * of 'vldc_close_delay' between each retry. 166 */ 167 static clock_t vldc_close_delay = VLDC_CLOSE_DELAY; 168 169 #ifdef DEBUG 170 171 /* 172 * Print debug messages 173 * 174 * set vldcdbg to 0x7 to enable all messages 175 * 176 * 0x4 - Warnings 177 * 0x2 - All debug messages (most verbose) 178 * 0x1 - Minimal debug messages 179 */ 180 181 int vldcdbg = 0x0; 182 183 static void 184 vldcdebug(const char *fmt, ...) 185 { 186 char buf[512]; 187 va_list ap; 188 189 va_start(ap, fmt); 190 (void) vsnprintf(buf, sizeof (buf), fmt, ap); 191 va_end(ap); 192 193 cmn_err(CE_CONT, "?%s", buf); 194 } 195 196 #define D1 if (vldcdbg & 0x01) vldcdebug 197 #define D2 if (vldcdbg & 0x02) vldcdebug 198 #define DWARN if (vldcdbg & 0x04) vldcdebug 199 200 #else /* not DEBUG */ 201 202 #define D1 if (0) printf 203 #define D2 if (0) printf 204 #define DWARN if (0) printf 205 206 #endif /* not DEBUG */ 207 208 209 /* _init(9E): initialize the loadable module */ 210 int 211 _init(void) 212 { 213 int error; 214 215 /* init the soft state structure */ 216 error = ddi_soft_state_init(&vldc_ssp, sizeof (vldc_t), 1); 217 if (error != 0) { 218 return (error); 219 } 220 221 /* Link the driver into the system */ 222 error = mod_install(&ml); 223 224 return (error); 225 } 226 227 /* _info(9E): return information about the loadable module */ 228 int 229 _info(struct modinfo *modinfop) 230 { 231 /* Report status of the dynamically loadable driver module */ 232 return (mod_info(&ml, modinfop)); 233 } 234 235 /* _fini(9E): prepare the module for unloading. */ 236 int 237 _fini(void) 238 { 239 int error; 240 241 /* Unlink the driver module from the system */ 242 if ((error = mod_remove(&ml)) == 0) { 243 /* 244 * We have successfully "removed" the driver. 245 * destroy soft state 246 */ 247 ddi_soft_state_fini(&vldc_ssp); 248 } 249 250 return (error); 251 } 252 253 /* ldc callback */ 254 static uint_t 255 i_vldc_cb(uint64_t event, caddr_t arg) 256 { 257 int rv; 258 vldc_port_t *vport = (vldc_port_t *)arg; 259 ldc_status_t old_status; 260 short pollevents = 0; 261 262 ASSERT(vport != NULL); 263 ASSERT(vport->minorp != NULL); 264 265 D1("i_vldc_cb: vldc@%d:%d callback invoked, channel=0x%lx, " 266 "event=0x%lx\n", vport->inst, vport->number, vport->ldc_id, event); 267 268 /* ensure the port can't be destroyed while we are handling the cb */ 269 mutex_enter(&vport->minorp->lock); 270 271 if (vport->status == VLDC_PORT_CLOSED) { 272 return (LDC_SUCCESS); 273 } 274 275 old_status = vport->ldc_status; 276 rv = ldc_status(vport->ldc_handle, &vport->ldc_status); 277 if (rv != 0) { 278 DWARN("i_vldc_cb: vldc@%d:%d could not get ldc status, " 279 "rv=%d\n", vport->inst, vport->number, rv); 280 mutex_exit(&vport->minorp->lock); 281 return (LDC_SUCCESS); 282 } 283 284 if (event & LDC_EVT_UP) { 285 pollevents |= POLLOUT; 286 vport->hanged_up = B_FALSE; 287 288 } else if (event & LDC_EVT_RESET) { 289 /* 290 * Mark the port in reset, if it is not CLOSED and 291 * the channel was previously in LDC_UP state. This 292 * implies that the port cannot be used until it has 293 * been closed and reopened. 294 */ 295 if (old_status == LDC_UP) { 296 vport->status = VLDC_PORT_RESET; 297 vport->hanged_up = B_TRUE; 298 pollevents = POLLHUP; 299 } else { 300 rv = ldc_up(vport->ldc_handle); 301 if (rv) { 302 DWARN("i_vldc_cb: vldc@%d:%d cannot bring " 303 "channel UP rv=%d\n", vport->inst, 304 vport->number, rv); 305 mutex_exit(&vport->minorp->lock); 306 return (LDC_SUCCESS); 307 } 308 rv = ldc_status(vport->ldc_handle, &vport->ldc_status); 309 if (rv != 0) { 310 DWARN("i_vldc_cb: vldc@%d:%d could not get " 311 "ldc status, rv=%d\n", vport->inst, 312 vport->number, rv); 313 mutex_exit(&vport->minorp->lock); 314 return (LDC_SUCCESS); 315 } 316 if (vport->ldc_status == LDC_UP) { 317 pollevents |= POLLOUT; 318 vport->hanged_up = B_FALSE; 319 } 320 } 321 322 } else if (event & LDC_EVT_DOWN) { 323 /* 324 * The other side went away - mark port in RESET state 325 */ 326 vport->status = VLDC_PORT_RESET; 327 vport->hanged_up = B_TRUE; 328 pollevents = POLLHUP; 329 } 330 331 if (event & LDC_EVT_READ) 332 pollevents |= POLLIN; 333 334 mutex_exit(&vport->minorp->lock); 335 336 if (pollevents != 0) { 337 D1("i_vldc_cb: port@%d pollwakeup=0x%x\n", 338 vport->number, pollevents); 339 pollwakeup(&vport->poll, pollevents); 340 } 341 342 return (LDC_SUCCESS); 343 } 344 345 /* mdeg callback */ 346 static int 347 i_vldc_mdeg_cb(void *cb_argp, mdeg_result_t *resp) 348 { 349 vldc_t *vldcp; 350 int idx; 351 uint64_t portno; 352 int rv; 353 md_t *mdp; 354 mde_cookie_t node; 355 356 if (resp == NULL) { 357 D1("i_vldc_mdeg_cb: no result returned\n"); 358 return (MDEG_FAILURE); 359 } 360 361 vldcp = (vldc_t *)cb_argp; 362 363 mutex_enter(&vldcp->lock); 364 if (vldcp->detaching == B_TRUE) { 365 D1("i_vldc_mdeg_cb: detach in progress\n"); 366 mutex_exit(&vldcp->lock); 367 return (MDEG_FAILURE); 368 } 369 370 D1("i_vldc_mdeg_cb: added=%d, removed=%d, matched=%d\n", 371 resp->added.nelem, resp->removed.nelem, resp->match_prev.nelem); 372 373 /* process added ports */ 374 for (idx = 0; idx < resp->added.nelem; idx++) { 375 mdp = resp->added.mdp; 376 node = resp->added.mdep[idx]; 377 378 D1("i_vldc_mdeg_cb: processing added node 0x%lx\n", node); 379 380 /* attempt to add a port */ 381 if ((rv = i_vldc_add_port(vldcp, mdp, node)) != MDEG_SUCCESS) { 382 cmn_err(CE_NOTE, "?i_vldc_mdeg_cb: unable to add port, " 383 "err = %d", rv); 384 } 385 } 386 387 /* process removed ports */ 388 for (idx = 0; idx < resp->removed.nelem; idx++) { 389 mdp = resp->removed.mdp; 390 node = resp->removed.mdep[idx]; 391 392 D1("i_vldc_mdeg_cb: processing removed node 0x%lx\n", node); 393 394 /* read in the port's id property */ 395 if (md_get_prop_val(mdp, node, "id", &portno)) { 396 cmn_err(CE_NOTE, "?i_vldc_mdeg_cb: node 0x%lx of " 397 "removed list has no 'id' property", node); 398 continue; 399 } 400 401 /* attempt to remove a port */ 402 if ((rv = i_vldc_remove_port(vldcp, portno)) != 0) { 403 cmn_err(CE_NOTE, "?i_vldc_mdeg_cb: unable to remove " 404 "port %lu, err %d", portno, rv); 405 } 406 } 407 408 /* 409 * Currently no support for updating already active ports. So, ignore 410 * the match_curr and match_prev arrays for now. 411 */ 412 413 mutex_exit(&vldcp->lock); 414 415 return (MDEG_SUCCESS); 416 } 417 418 /* register callback to mdeg */ 419 static int 420 i_vldc_mdeg_register(vldc_t *vldcp) 421 { 422 mdeg_prop_spec_t *pspecp; 423 mdeg_node_spec_t *inst_specp; 424 mdeg_handle_t mdeg_hdl; 425 size_t templatesz; 426 int inst; 427 char *name; 428 size_t namesz; 429 char *nameprop; 430 int rv; 431 432 /* get the unique vldc instance assigned by the LDom manager */ 433 inst = ddi_prop_get_int(DDI_DEV_T_ANY, vldcp->dip, 434 DDI_PROP_DONTPASS, "reg", -1); 435 if (inst == -1) { 436 cmn_err(CE_NOTE, "?vldc%d has no 'reg' property", 437 ddi_get_instance(vldcp->dip)); 438 return (DDI_FAILURE); 439 } 440 441 /* get the name of the vldc instance */ 442 rv = ddi_prop_lookup_string(DDI_DEV_T_ANY, vldcp->dip, 443 DDI_PROP_DONTPASS, "name", &nameprop); 444 if (rv != DDI_PROP_SUCCESS) { 445 cmn_err(CE_NOTE, "?vldc%d has no 'name' property", 446 ddi_get_instance(vldcp->dip)); 447 return (DDI_FAILURE); 448 } 449 450 D1("i_vldc_mdeg_register: name=%s, instance=%d\n", nameprop, inst); 451 452 /* 453 * Allocate and initialize a per-instance copy 454 * of the global property spec array that will 455 * uniquely identify this vldc instance. 456 */ 457 templatesz = sizeof (vldc_prop_template); 458 pspecp = kmem_alloc(templatesz, KM_SLEEP); 459 460 bcopy(vldc_prop_template, pspecp, templatesz); 461 462 /* copy in the name property */ 463 namesz = strlen(nameprop) + 1; 464 name = kmem_alloc(namesz, KM_SLEEP); 465 466 bcopy(nameprop, name, namesz); 467 VLDC_SET_MDEG_PROP_NAME(pspecp, name); 468 ddi_prop_free(nameprop); 469 470 /* copy in the instance property */ 471 VLDC_SET_MDEG_PROP_INST(pspecp, inst); 472 473 /* initialize the complete prop spec structure */ 474 inst_specp = kmem_alloc(sizeof (mdeg_node_spec_t), KM_SLEEP); 475 inst_specp->namep = "virtual-device"; 476 inst_specp->specp = pspecp; 477 478 /* perform the registration */ 479 rv = mdeg_register(inst_specp, &vport_match, i_vldc_mdeg_cb, 480 vldcp, &mdeg_hdl); 481 482 if (rv != MDEG_SUCCESS) { 483 cmn_err(CE_NOTE, "?i_vldc_mdeg_register: mdeg_register " 484 "failed, err = %d", rv); 485 kmem_free(name, namesz); 486 kmem_free(pspecp, templatesz); 487 kmem_free(inst_specp, sizeof (mdeg_node_spec_t)); 488 return (DDI_FAILURE); 489 } 490 491 /* save off data that will be needed later */ 492 vldcp->inst_spec = inst_specp; 493 vldcp->mdeg_hdl = mdeg_hdl; 494 495 return (DDI_SUCCESS); 496 } 497 498 /* unregister callback from mdeg */ 499 static int 500 i_vldc_mdeg_unregister(vldc_t *vldcp) 501 { 502 char *name; 503 int rv; 504 505 D1("i_vldc_mdeg_unregister: hdl=0x%lx\n", vldcp->mdeg_hdl); 506 507 rv = mdeg_unregister(vldcp->mdeg_hdl); 508 if (rv != MDEG_SUCCESS) { 509 return (rv); 510 } 511 512 /* 513 * Clean up cached MDEG data 514 */ 515 name = VLDC_MDEG_PROP_NAME(vldcp->inst_spec->specp); 516 if (name != NULL) { 517 kmem_free(name, strlen(name) + 1); 518 } 519 kmem_free(vldcp->inst_spec->specp, sizeof (vldc_prop_template)); 520 vldcp->inst_spec->specp = NULL; 521 522 kmem_free(vldcp->inst_spec, sizeof (mdeg_node_spec_t)); 523 vldcp->inst_spec = NULL; 524 525 return (MDEG_SUCCESS); 526 } 527 528 static int 529 i_vldc_get_port_channel(md_t *mdp, mde_cookie_t node, uint64_t *ldc_id) 530 { 531 int num_nodes, nchan; 532 size_t listsz; 533 mde_cookie_t *listp; 534 535 /* 536 * Find the channel-endpoint node(s) (which should be under this 537 * port node) which contain the channel id(s). 538 */ 539 if ((num_nodes = md_node_count(mdp)) <= 0) { 540 cmn_err(CE_NOTE, "?i_vldc_get_port_channel: invalid number of " 541 "channel-endpoint nodes found (%d)", num_nodes); 542 return (-1); 543 } 544 545 /* allocate space for node list */ 546 listsz = num_nodes * sizeof (mde_cookie_t); 547 listp = kmem_alloc(listsz, KM_SLEEP); 548 549 nchan = md_scan_dag(mdp, node, md_find_name(mdp, "channel-endpoint"), 550 md_find_name(mdp, "fwd"), listp); 551 552 if (nchan <= 0) { 553 cmn_err(CE_NOTE, "?i_vldc_get_port_channel: no channel-endpoint" 554 " nodes found"); 555 kmem_free(listp, listsz); 556 return (-1); 557 } 558 559 D2("i_vldc_get_port_channel: %d channel-endpoint nodes found", nchan); 560 561 /* use property from first node found */ 562 if (md_get_prop_val(mdp, listp[0], "id", ldc_id)) { 563 cmn_err(CE_NOTE, "?i_vldc_get_port_channel: channel-endpoint " 564 "has no 'id' property"); 565 kmem_free(listp, listsz); 566 return (-1); 567 } 568 569 kmem_free(listp, listsz); 570 571 return (0); 572 } 573 574 /* add a vldc port */ 575 static int 576 i_vldc_add_port(vldc_t *vldcp, md_t *mdp, mde_cookie_t node) 577 { 578 vldc_port_t *vport; 579 char *sname; 580 uint64_t portno; 581 int vldc_inst; 582 minor_t minor; 583 int minor_idx; 584 boolean_t new_minor; 585 int rv; 586 587 ASSERT(MUTEX_HELD(&vldcp->lock)); 588 589 /* read in the port's id property */ 590 if (md_get_prop_val(mdp, node, "id", &portno)) { 591 cmn_err(CE_NOTE, "?i_vldc_add_port: node 0x%lx of added " 592 "list has no 'id' property", node); 593 return (MDEG_FAILURE); 594 } 595 596 if (portno >= VLDC_MAX_PORTS) { 597 cmn_err(CE_NOTE, "?i_vldc_add_port: found port number (%lu) " 598 "larger than maximum supported number of ports", portno); 599 return (MDEG_FAILURE); 600 } 601 602 vport = &(vldcp->port[portno]); 603 604 if (vport->minorp != NULL) { 605 cmn_err(CE_NOTE, "?i_vldc_add_port: trying to add a port (%lu)" 606 " which is already bound", portno); 607 return (MDEG_FAILURE); 608 } 609 610 vport->number = portno; 611 612 /* get all channels for this device (currently only one) */ 613 if (i_vldc_get_port_channel(mdp, node, &vport->ldc_id) == -1) { 614 return (MDEG_FAILURE); 615 } 616 617 /* set the default MTU */ 618 vport->mtu = VLDC_DEFAULT_MTU; 619 620 /* get the service being exported by this port */ 621 if (md_get_prop_str(mdp, node, "vldc-svc-name", &sname)) { 622 cmn_err(CE_NOTE, "?i_vldc_add_port: vdevice has no " 623 "'vldc-svc-name' property"); 624 return (MDEG_FAILURE); 625 } 626 627 /* minor number look up */ 628 for (minor_idx = 0; minor_idx < vldcp->minors_assigned; 629 minor_idx++) { 630 if (strcmp(vldcp->minor_tbl[minor_idx].sname, sname) == 0) { 631 /* found previously assigned minor number */ 632 break; 633 } 634 } 635 636 new_minor = B_FALSE; 637 if (minor_idx == vldcp->minors_assigned) { 638 /* end of lookup - assign new minor number */ 639 if (vldcp->minors_assigned == VLDC_MAX_MINORS) { 640 cmn_err(CE_NOTE, "?i_vldc_add_port: too many minor " 641 "nodes (%d)", minor_idx); 642 return (MDEG_FAILURE); 643 } 644 645 (void) strlcpy(vldcp->minor_tbl[minor_idx].sname, 646 sname, MAXPATHLEN); 647 648 vldcp->minors_assigned++; 649 new_minor = B_TRUE; 650 } 651 652 if (vldcp->minor_tbl[minor_idx].portno != VLDC_INVALID_PORTNO) { 653 cmn_err(CE_NOTE, "?i_vldc_add_port: trying to add a port (%lu)" 654 " which has a minor number in use by port (%u)", 655 portno, vldcp->minor_tbl[minor_idx].portno); 656 return (MDEG_FAILURE); 657 } 658 659 vldc_inst = ddi_get_instance(vldcp->dip); 660 661 vport->inst = vldc_inst; 662 vport->minorp = &vldcp->minor_tbl[minor_idx]; 663 vldcp->minor_tbl[minor_idx].portno = portno; 664 vldcp->minor_tbl[minor_idx].in_use = 0; 665 666 D1("i_vldc_add_port: vldc@%d:%d mtu=%d, ldc=%ld, service=%s\n", 667 vport->inst, vport->number, vport->mtu, vport->ldc_id, sname); 668 669 /* 670 * Create a minor node. The minor number is 671 * (vldc_inst << VLDC_INST_SHIFT) | minor_idx 672 */ 673 minor = (vldc_inst << VLDC_INST_SHIFT) | (minor_idx); 674 675 rv = ddi_create_minor_node(vldcp->dip, sname, S_IFCHR, 676 minor, DDI_NT_SERIAL, 0); 677 678 if (rv != DDI_SUCCESS) { 679 cmn_err(CE_NOTE, "?i_vldc_add_port: failed to create minor" 680 "node (%u), err = %d", minor, rv); 681 vldcp->minor_tbl[minor_idx].portno = VLDC_INVALID_PORTNO; 682 if (new_minor) { 683 vldcp->minors_assigned--; 684 } 685 return (MDEG_FAILURE); 686 } 687 688 /* 689 * The port is now bound to a minor node and is initially in the 690 * closed state. 691 */ 692 vport->status = VLDC_PORT_CLOSED; 693 694 D1("i_vldc_add_port: port %lu initialized\n", portno); 695 696 return (MDEG_SUCCESS); 697 } 698 699 /* remove a vldc port */ 700 static int 701 i_vldc_remove_port(vldc_t *vldcp, uint_t portno) 702 { 703 vldc_port_t *vport; 704 vldc_minor_t *vminor; 705 706 ASSERT(vldcp != NULL); 707 ASSERT(MUTEX_HELD(&vldcp->lock)); 708 709 vport = &(vldcp->port[portno]); 710 vminor = vport->minorp; 711 if (vminor == NULL) { 712 cmn_err(CE_NOTE, "?i_vldc_remove_port: trying to remove a " 713 "port (%u) which is not bound", portno); 714 return (MDEG_FAILURE); 715 } 716 717 /* 718 * Make sure that all new attempts to open or use the minor node 719 * associated with the port will fail. 720 */ 721 mutex_enter(&vminor->lock); 722 vminor->portno = VLDC_INVALID_PORTNO; 723 mutex_exit(&vminor->lock); 724 725 /* send hangup to anyone polling */ 726 pollwakeup(&vport->poll, POLLHUP); 727 728 /* Now wait for all current users of the minor node to finish. */ 729 mutex_enter(&vminor->lock); 730 while (vminor->in_use > 0) { 731 cv_wait(&vminor->cv, &vminor->lock); 732 } 733 734 if (vport->status != VLDC_PORT_CLOSED) { 735 /* close the port before it is torn down */ 736 (void) i_vldc_close_port(vldcp, portno); 737 } 738 739 /* remove minor node */ 740 ddi_remove_minor_node(vldcp->dip, vport->minorp->sname); 741 vport->minorp = NULL; 742 743 mutex_exit(&vminor->lock); 744 745 D1("i_vldc_remove_port: removed vldc port %u\n", portno); 746 747 return (MDEG_SUCCESS); 748 } 749 750 /* 751 * Close and destroy the ldc channel associated with the port 'vport' 752 * 753 * NOTE It may not be possible close and destroy the channel if resources 754 * are still in use so the fucntion may exit before all the teardown 755 * operations are completed and would have to be called again by the 756 * vldc framework. 757 * 758 * This function needs to be able to handle the case where it is called 759 * more than once and has to pick up from where it left off. 760 */ 761 static int 762 i_vldc_ldc_close(vldc_port_t *vport) 763 { 764 int err = 0; 765 766 ASSERT(MUTEX_HELD(&vport->minorp->lock)); 767 768 /* 769 * If ldc_close() succeeded or if the channel was already closed[*] 770 * (possibly by a previously unsuccessful call to this function) 771 * we keep going and try to teardown the rest of the LDC state, 772 * otherwise we bail out. 773 * 774 * [*] indicated by ldc_close() returning a value of EFAULT 775 */ 776 err = ldc_close(vport->ldc_handle); 777 if ((err != 0) && (err != EFAULT)) 778 return (err); 779 780 err = ldc_unreg_callback(vport->ldc_handle); 781 if (err != 0) 782 return (err); 783 784 err = ldc_fini(vport->ldc_handle); 785 if (err != 0) 786 return (err); 787 788 vport->status = VLDC_PORT_OPEN; 789 790 return (0); 791 } 792 793 /* close a vldc port */ 794 static int 795 i_vldc_close_port(vldc_t *vldcp, uint_t portno) 796 { 797 vldc_port_t *vport; 798 vldc_minor_t *vminor; 799 int rv = DDI_SUCCESS; 800 801 vport = &(vldcp->port[portno]); 802 803 ASSERT(MUTEX_HELD(&vport->minorp->lock)); 804 805 D1("i_vldc_close_port: vldc@%d:%d: closing port\n", 806 vport->inst, vport->minorp->portno); 807 808 vminor = vport->minorp; 809 810 switch (vport->status) { 811 case VLDC_PORT_CLOSED: 812 /* nothing to do */ 813 DWARN("i_vldc_close_port: port %d in an unexpected " 814 "state (%d)\n", portno, vport->status); 815 return (DDI_SUCCESS); 816 817 case VLDC_PORT_READY: 818 case VLDC_PORT_RESET: 819 do { 820 rv = i_vldc_ldc_close(vport); 821 if (rv != EAGAIN) 822 break; 823 824 /* 825 * EAGAIN indicates that ldc_close() failed because 826 * ldc callback thread is active for the channel. 827 * cv_timedwait() is used to release vminor->lock and 828 * allow ldc callback thread to complete. 829 * after waking up, check if the port has been closed 830 * by another thread in the meantime. 831 */ 832 (void) cv_timedwait(&vminor->cv, &vminor->lock, 833 ddi_get_lbolt() + drv_usectohz(vldc_close_delay)); 834 rv = 0; 835 } while (vport->status != VLDC_PORT_CLOSED); 836 837 if ((rv != 0) || (vport->status == VLDC_PORT_CLOSED)) 838 return (rv); 839 840 break; 841 842 case VLDC_PORT_OPEN: 843 break; 844 845 default: 846 DWARN("i_vldc_close_port: port %d in an unexpected " 847 "state (%d)\n", portno, vport->status); 848 ASSERT(0); /* fail quickly to help diagnosis */ 849 return (EINVAL); 850 } 851 852 ASSERT(vport->status == VLDC_PORT_OPEN); 853 854 /* free memory */ 855 kmem_free(vport->send_buf, vport->mtu); 856 kmem_free(vport->recv_buf, vport->mtu); 857 858 if (strcmp(vminor->sname, VLDC_HVCTL_SVCNAME) == 0) 859 kmem_free(vport->cookie_buf, vldc_max_cookie); 860 861 vport->status = VLDC_PORT_CLOSED; 862 863 return (rv); 864 } 865 866 /* 867 * attach(9E): attach a device to the system. 868 * called once for each instance of the device on the system. 869 */ 870 static int 871 vldc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 872 { 873 int i, instance; 874 vldc_t *vldcp; 875 876 switch (cmd) { 877 878 case DDI_ATTACH: 879 880 instance = ddi_get_instance(dip); 881 882 if (ddi_soft_state_zalloc(vldc_ssp, instance) != DDI_SUCCESS) { 883 return (DDI_FAILURE); 884 } 885 886 vldcp = ddi_get_soft_state(vldc_ssp, instance); 887 if (vldcp == NULL) { 888 ddi_soft_state_free(vldc_ssp, instance); 889 return (ENXIO); 890 } 891 892 D1("vldc_attach: DDI_ATTACH instance=%d\n", instance); 893 894 mutex_init(&vldcp->lock, NULL, MUTEX_DRIVER, NULL); 895 vldcp->dip = dip; 896 vldcp->detaching = B_FALSE; 897 898 for (i = 0; i < VLDC_MAX_PORTS; i++) { 899 /* No minor node association to start with */ 900 vldcp->port[i].minorp = NULL; 901 } 902 903 for (i = 0; i < VLDC_MAX_MINORS; i++) { 904 mutex_init(&(vldcp->minor_tbl[i].lock), NULL, 905 MUTEX_DRIVER, NULL); 906 cv_init(&(vldcp->minor_tbl[i].cv), NULL, 907 CV_DRIVER, NULL); 908 /* No port association to start with */ 909 vldcp->minor_tbl[i].portno = VLDC_INVALID_PORTNO; 910 } 911 912 /* Register for MD update notification */ 913 if (i_vldc_mdeg_register(vldcp) != DDI_SUCCESS) { 914 ddi_soft_state_free(vldc_ssp, instance); 915 return (DDI_FAILURE); 916 } 917 918 return (DDI_SUCCESS); 919 920 case DDI_RESUME: 921 922 return (DDI_SUCCESS); 923 924 default: 925 926 return (DDI_FAILURE); 927 } 928 } 929 930 /* 931 * detach(9E): detach a device from the system. 932 */ 933 static int 934 vldc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 935 { 936 int i, instance; 937 vldc_t *vldcp; 938 939 switch (cmd) { 940 941 case DDI_DETACH: 942 943 instance = ddi_get_instance(dip); 944 945 vldcp = ddi_get_soft_state(vldc_ssp, instance); 946 if (vldcp == NULL) { 947 return (DDI_FAILURE); 948 } 949 950 D1("vldc_detach: DDI_DETACH instance=%d\n", instance); 951 952 mutex_enter(&vldcp->lock); 953 954 /* Fail the detach if all ports have not been removed. */ 955 for (i = 0; i < VLDC_MAX_MINORS; i++) { 956 if (vldcp->minor_tbl[i].portno != VLDC_INVALID_PORTNO) { 957 D1("vldc_detach: vldc@%d:%d is bound, " 958 "detach failed\n", 959 instance, vldcp->minor_tbl[i].portno); 960 mutex_exit(&vldcp->lock); 961 return (DDI_FAILURE); 962 } 963 } 964 965 /* 966 * Prevent MDEG from adding new ports before the callback can 967 * be unregistered. The lock can't be held accross the 968 * unregistration call because a callback may be in progress 969 * and blocked on the lock. 970 */ 971 vldcp->detaching = B_TRUE; 972 973 mutex_exit(&vldcp->lock); 974 975 if (i_vldc_mdeg_unregister(vldcp) != MDEG_SUCCESS) { 976 vldcp->detaching = B_FALSE; 977 return (DDI_FAILURE); 978 } 979 980 /* Tear down all bound ports and free resources. */ 981 for (i = 0; i < VLDC_MAX_MINORS; i++) { 982 if (vldcp->minor_tbl[i].portno != VLDC_INVALID_PORTNO) { 983 (void) i_vldc_remove_port(vldcp, i); 984 } 985 mutex_destroy(&(vldcp->minor_tbl[i].lock)); 986 cv_destroy(&(vldcp->minor_tbl[i].cv)); 987 } 988 989 mutex_destroy(&vldcp->lock); 990 ddi_soft_state_free(vldc_ssp, instance); 991 992 return (DDI_SUCCESS); 993 994 case DDI_SUSPEND: 995 996 return (DDI_SUCCESS); 997 998 default: 999 1000 return (DDI_FAILURE); 1001 } 1002 } 1003 1004 /* cb_open */ 1005 static int 1006 vldc_open(dev_t *devp, int flag, int otyp, cred_t *cred) 1007 { 1008 _NOTE(ARGUNUSED(flag, otyp, cred)) 1009 1010 int instance; 1011 minor_t minor; 1012 uint64_t portno; 1013 vldc_t *vldcp; 1014 vldc_port_t *vport; 1015 vldc_minor_t *vminor; 1016 1017 minor = getminor(*devp); 1018 instance = VLDCINST(minor); 1019 vldcp = ddi_get_soft_state(vldc_ssp, instance); 1020 if (vldcp == NULL) 1021 return (ENXIO); 1022 1023 vminor = VLDCMINOR(vldcp, minor); 1024 mutex_enter(&vminor->lock); 1025 portno = vminor->portno; 1026 if (portno == VLDC_INVALID_PORTNO) { 1027 mutex_exit(&vminor->lock); 1028 return (ENXIO); 1029 } 1030 1031 vport = &(vldcp->port[portno]); 1032 1033 D1("vldc_open: opening vldc@%d:%lu\n", instance, portno); 1034 1035 if (vport->status != VLDC_PORT_CLOSED) { 1036 mutex_exit(&vminor->lock); 1037 return (EBUSY); 1038 } 1039 1040 vport->recv_buf = kmem_alloc(vport->mtu, KM_SLEEP); 1041 vport->send_buf = kmem_alloc(vport->mtu, KM_SLEEP); 1042 1043 if (strcmp(vport->minorp->sname, VLDC_HVCTL_SVCNAME) == 0) 1044 vport->cookie_buf = kmem_alloc(vldc_max_cookie, KM_SLEEP); 1045 1046 vport->is_stream = B_FALSE; /* assume not a stream */ 1047 vport->hanged_up = B_FALSE; 1048 1049 vport->status = VLDC_PORT_OPEN; 1050 1051 mutex_exit(&vminor->lock); 1052 1053 return (DDI_SUCCESS); 1054 } 1055 1056 /* cb_close */ 1057 static int 1058 vldc_close(dev_t dev, int flag, int otyp, cred_t *cred) 1059 { 1060 _NOTE(ARGUNUSED(flag, otyp, cred)) 1061 1062 int instance; 1063 minor_t minor; 1064 uint64_t portno; 1065 vldc_t *vldcp; 1066 vldc_minor_t *vminor; 1067 int rv; 1068 1069 minor = getminor(dev); 1070 instance = VLDCINST(minor); 1071 vldcp = ddi_get_soft_state(vldc_ssp, instance); 1072 if (vldcp == NULL) { 1073 return (ENXIO); 1074 } 1075 1076 vminor = VLDCMINOR(vldcp, minor); 1077 mutex_enter(&vminor->lock); 1078 portno = vminor->portno; 1079 if (portno == VLDC_INVALID_PORTNO) { 1080 mutex_exit(&vminor->lock); 1081 return (ENOLINK); 1082 } 1083 1084 D1("vldc_close: closing vldc@%d:%lu\n", instance, portno); 1085 1086 rv = i_vldc_close_port(vldcp, portno); 1087 1088 mutex_exit(&vminor->lock); 1089 1090 return (rv); 1091 } 1092 1093 static int 1094 vldc_set_ldc_mode(vldc_port_t *vport, vldc_t *vldcp, int channel_mode) 1095 { 1096 ldc_attr_t attr; 1097 int rv; 1098 1099 ASSERT(MUTEX_HELD(&vport->minorp->lock)); 1100 1101 /* validate mode */ 1102 switch (channel_mode) { 1103 case LDC_MODE_RELIABLE: 1104 vport->is_stream = B_TRUE; 1105 break; 1106 case LDC_MODE_RAW: 1107 case LDC_MODE_UNRELIABLE: 1108 vport->is_stream = B_FALSE; 1109 break; 1110 default: 1111 return (EINVAL); 1112 } 1113 1114 if (vport->status == VLDC_PORT_READY) { 1115 rv = i_vldc_ldc_close(vport); 1116 if (rv != 0) { 1117 DWARN("vldc_set_ldc_mode: i_vldc_ldc_close " 1118 "failed, rv=%d\n", rv); 1119 return (rv); 1120 } 1121 } 1122 1123 D1("vldc_set_ldc_mode: vport status %d, mode %d\n", 1124 vport->status, channel_mode); 1125 1126 vport->ldc_mode = channel_mode; 1127 1128 /* initialize the channel */ 1129 attr.devclass = LDC_DEV_SERIAL; 1130 attr.instance = ddi_get_instance(vldcp->dip); 1131 attr.mtu = vport->mtu; 1132 attr.mode = vport->ldc_mode; 1133 1134 if ((rv = ldc_init(vport->ldc_id, &attr, 1135 &vport->ldc_handle)) != 0) { 1136 DWARN("vldc_ioctl_opt_op: ldc_init failed, rv=%d\n", rv); 1137 goto error_init; 1138 } 1139 1140 /* register it */ 1141 if ((rv = ldc_reg_callback(vport->ldc_handle, 1142 i_vldc_cb, (caddr_t)vport)) != 0) { 1143 DWARN("vldc_ioctl_opt_op: ldc_reg_callback failed, rv=%d\n", 1144 rv); 1145 goto error_reg; 1146 } 1147 1148 /* open the channel */ 1149 if ((rv = ldc_open(vport->ldc_handle)) != 0) { 1150 DWARN("vldc_ioctl_opt_op: ldc_open failed, rv=%d\n", rv); 1151 goto error_open; 1152 } 1153 1154 vport->status = VLDC_PORT_READY; 1155 1156 /* 1157 * Attempt to bring the channel up, but do not 1158 * fail if the other end is not up yet. 1159 */ 1160 rv = ldc_up(vport->ldc_handle); 1161 if (rv == ECONNREFUSED) { 1162 D1("vldc_ioctl_opt_op: remote endpoint not up yet\n"); 1163 } else if (rv != 0) { 1164 DWARN("vldc_ioctl_opt_op: ldc_up failed, rv=%d\n", rv); 1165 goto error_up; 1166 } 1167 1168 rv = ldc_status(vport->ldc_handle, &vport->ldc_status); 1169 if (rv != 0) { 1170 DWARN("vldc_ioctl_opt_op: vldc@%d:%d could not get ldc " 1171 "status, rv=%d\n", vport->inst, vport->number, rv); 1172 goto error_up; 1173 } 1174 1175 D1("vldc_ioctl_opt_op: ldc %ld initialized successfully\n", 1176 vport->ldc_id); 1177 1178 return (0); 1179 1180 error_up: 1181 vport->status = VLDC_PORT_OPEN; 1182 (void) ldc_close(vport->ldc_handle); 1183 error_open: 1184 (void) ldc_unreg_callback(vport->ldc_handle); 1185 error_reg: 1186 (void) ldc_fini(vport->ldc_handle); 1187 error_init: 1188 return (rv); 1189 } 1190 1191 /* ioctl to read cookie */ 1192 static int 1193 i_vldc_ioctl_read_cookie(vldc_port_t *vport, int vldc_instance, void *arg, 1194 int mode) 1195 { 1196 vldc_data_t copy_info; 1197 uint64_t len, balance, copy_size; 1198 caddr_t src_addr, dst_addr; 1199 int rv; 1200 1201 if (ddi_copyin(arg, ©_info, sizeof (copy_info), mode) == -1) { 1202 return (EFAULT); 1203 } 1204 1205 len = balance = copy_info.length; 1206 src_addr = (caddr_t)copy_info.src_addr; 1207 dst_addr = (caddr_t)copy_info.dst_addr; 1208 while (balance > 0) { 1209 1210 /* get the max amount to the copied */ 1211 copy_size = MIN(balance, vldc_max_cookie); 1212 1213 mutex_enter(&vport->minorp->lock); 1214 1215 D2("i_vldc_ioctl_read_cookie: vldc@%d:%d reading from 0x%p " 1216 "size 0x%lx to 0x%p\n", vldc_instance, vport->number, 1217 dst_addr, copy_size, src_addr); 1218 1219 /* read from the HV into the temporary buffer */ 1220 rv = ldc_mem_rdwr_cookie(vport->ldc_handle, vport->cookie_buf, 1221 ©_size, dst_addr, LDC_COPY_IN); 1222 if (rv != 0) { 1223 DWARN("i_vldc_ioctl_read_cookie: vldc@%d:%d cannot " 1224 "read address 0x%p, rv=%d\n", 1225 vldc_instance, vport->number, dst_addr, rv); 1226 mutex_exit(&vport->minorp->lock); 1227 return (EFAULT); 1228 } 1229 1230 D2("i_vldc_ioctl_read_cookie: vldc@%d:%d read succeeded\n", 1231 vldc_instance, vport->number); 1232 1233 mutex_exit(&vport->minorp->lock); 1234 1235 /* 1236 * copy data from temporary buffer out to the 1237 * caller and free buffer 1238 */ 1239 rv = ddi_copyout(vport->cookie_buf, src_addr, copy_size, mode); 1240 if (rv != 0) { 1241 return (EFAULT); 1242 } 1243 1244 /* adjust len, source and dest */ 1245 balance -= copy_size; 1246 src_addr += copy_size; 1247 dst_addr += copy_size; 1248 } 1249 1250 /* set the structure to reflect outcome */ 1251 copy_info.length = len; 1252 if (ddi_copyout(©_info, arg, sizeof (copy_info), mode) != 0) { 1253 return (EFAULT); 1254 } 1255 1256 return (0); 1257 } 1258 1259 /* ioctl to write cookie */ 1260 static int 1261 i_vldc_ioctl_write_cookie(vldc_port_t *vport, int vldc_instance, void *arg, 1262 int mode) 1263 { 1264 vldc_data_t copy_info; 1265 uint64_t len, balance, copy_size; 1266 caddr_t src_addr, dst_addr; 1267 int rv; 1268 1269 if (ddi_copyin(arg, ©_info, sizeof (copy_info), mode) != 0) { 1270 return (EFAULT); 1271 } 1272 1273 D2("i_vldc_ioctl_write_cookie: vldc@%d:%d writing 0x%lx size 0x%lx " 1274 "to 0x%lx\n", vldc_instance, vport->number, copy_info.src_addr, 1275 copy_info.length, copy_info.dst_addr); 1276 1277 len = balance = copy_info.length; 1278 src_addr = (caddr_t)copy_info.src_addr; 1279 dst_addr = (caddr_t)copy_info.dst_addr; 1280 while (balance > 0) { 1281 1282 /* get the max amount to the copied */ 1283 copy_size = MIN(balance, vldc_max_cookie); 1284 1285 /* 1286 * copy into the temporary buffer the data 1287 * to be written to the HV 1288 */ 1289 if (ddi_copyin((caddr_t)src_addr, vport->cookie_buf, 1290 copy_size, mode) != 0) { 1291 return (EFAULT); 1292 } 1293 1294 mutex_enter(&vport->minorp->lock); 1295 1296 /* write the data from the temporary buffer to the HV */ 1297 rv = ldc_mem_rdwr_cookie(vport->ldc_handle, vport->cookie_buf, 1298 ©_size, dst_addr, LDC_COPY_OUT); 1299 if (rv != 0) { 1300 DWARN("i_vldc_ioctl_write_cookie: vldc@%d:%d " 1301 "failed to write at address 0x%p\n, rv=%d", 1302 vldc_instance, vport->number, dst_addr, rv); 1303 mutex_exit(&vport->minorp->lock); 1304 return (EFAULT); 1305 } 1306 1307 D2("i_vldc_ioctl_write_cookie: vldc@%d:%d write succeeded\n", 1308 vldc_instance, vport->number); 1309 1310 mutex_exit(&vport->minorp->lock); 1311 1312 /* adjust len, source and dest */ 1313 balance -= copy_size; 1314 src_addr += copy_size; 1315 dst_addr += copy_size; 1316 } 1317 1318 /* set the structure to reflect outcome */ 1319 copy_info.length = len; 1320 if (ddi_copyout(©_info, (caddr_t)arg, 1321 sizeof (copy_info), mode) != 0) { 1322 return (EFAULT); 1323 } 1324 1325 return (0); 1326 } 1327 1328 /* vldc specific ioctl option commands */ 1329 static int 1330 i_vldc_ioctl_opt_op(vldc_port_t *vport, vldc_t *vldcp, void *arg, int mode) 1331 { 1332 vldc_opt_op_t vldc_cmd; 1333 uint32_t new_mtu; 1334 int rv = 0; 1335 1336 if (ddi_copyin(arg, &vldc_cmd, sizeof (vldc_cmd), mode) != 0) { 1337 return (EFAULT); 1338 } 1339 1340 D1("vldc_ioctl_opt_op: op %d\n", vldc_cmd.opt_sel); 1341 1342 switch (vldc_cmd.opt_sel) { 1343 1344 case VLDC_OPT_MTU_SZ: 1345 1346 if (vldc_cmd.op_sel == VLDC_OP_GET) { 1347 vldc_cmd.opt_val = vport->mtu; 1348 if (ddi_copyout(&vldc_cmd, arg, 1349 sizeof (vldc_cmd), mode) == -1) { 1350 return (EFAULT); 1351 } 1352 } else { 1353 new_mtu = vldc_cmd.opt_val; 1354 1355 if ((new_mtu < LDC_PACKET_SIZE) || 1356 (new_mtu > vldc_max_mtu)) { 1357 return (EINVAL); 1358 } 1359 1360 mutex_enter(&vport->minorp->lock); 1361 1362 if ((vport->status != VLDC_PORT_CLOSED) && 1363 (new_mtu != vport->mtu)) { 1364 /* 1365 * The port has buffers allocated since it is 1366 * not closed plus the MTU size has changed. 1367 * Reallocate the buffers to the new MTU size. 1368 */ 1369 kmem_free(vport->recv_buf, vport->mtu); 1370 vport->recv_buf = kmem_alloc(new_mtu, KM_SLEEP); 1371 1372 kmem_free(vport->send_buf, vport->mtu); 1373 vport->send_buf = kmem_alloc(new_mtu, KM_SLEEP); 1374 1375 vport->mtu = new_mtu; 1376 } 1377 1378 mutex_exit(&vport->minorp->lock); 1379 } 1380 1381 break; 1382 1383 case VLDC_OPT_STATUS: 1384 1385 if (vldc_cmd.op_sel == VLDC_OP_GET) { 1386 vldc_cmd.opt_val = vport->status; 1387 if (ddi_copyout(&vldc_cmd, arg, 1388 sizeof (vldc_cmd), mode) == -1) { 1389 return (EFAULT); 1390 } 1391 } else { 1392 return (ENOTSUP); 1393 } 1394 1395 break; 1396 1397 case VLDC_OPT_MODE: 1398 1399 if (vldc_cmd.op_sel == VLDC_OP_GET) { 1400 vldc_cmd.opt_val = vport->ldc_mode; 1401 if (ddi_copyout(&vldc_cmd, arg, 1402 sizeof (vldc_cmd), mode) == -1) { 1403 return (EFAULT); 1404 } 1405 } else { 1406 mutex_enter(&vport->minorp->lock); 1407 rv = vldc_set_ldc_mode(vport, vldcp, vldc_cmd.opt_val); 1408 mutex_exit(&vport->minorp->lock); 1409 } 1410 1411 break; 1412 1413 default: 1414 1415 D1("vldc_ioctl_opt_op: unsupported op %d\n", vldc_cmd.opt_sel); 1416 return (ENOTSUP); 1417 } 1418 1419 return (rv); 1420 } 1421 1422 /* cb_ioctl */ 1423 static int 1424 vldc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 1425 int *rvalp) 1426 { 1427 _NOTE(ARGUNUSED(credp, rvalp)) 1428 1429 int rv = EINVAL; 1430 int instance; 1431 minor_t minor; 1432 uint64_t portno; 1433 vldc_t *vldcp; 1434 vldc_port_t *vport; 1435 vldc_minor_t *vminor; 1436 1437 minor = getminor(dev); 1438 instance = VLDCINST(minor); 1439 vldcp = ddi_get_soft_state(vldc_ssp, instance); 1440 if (vldcp == NULL) { 1441 return (ENXIO); 1442 } 1443 1444 vminor = VLDCMINOR(vldcp, minor); 1445 mutex_enter(&vminor->lock); 1446 portno = vminor->portno; 1447 if (portno == VLDC_INVALID_PORTNO) { 1448 mutex_exit(&vminor->lock); 1449 return (ENOLINK); 1450 } 1451 vminor->in_use += 1; 1452 mutex_exit(&vminor->lock); 1453 1454 vport = &(vldcp->port[portno]); 1455 1456 D1("vldc_ioctl: vldc@%d:%lu cmd=0x%x\n", instance, portno, cmd); 1457 1458 switch (cmd) { 1459 1460 case VLDC_IOCTL_OPT_OP: 1461 rv = i_vldc_ioctl_opt_op(vport, vldcp, (void *)arg, mode); 1462 break; 1463 1464 case VLDC_IOCTL_READ_COOKIE: 1465 if (strcmp(vport->minorp->sname, VLDC_HVCTL_SVCNAME)) { 1466 rv = EINVAL; 1467 break; 1468 } 1469 rv = i_vldc_ioctl_read_cookie(vport, instance, 1470 (void *)arg, mode); 1471 break; 1472 1473 case VLDC_IOCTL_WRITE_COOKIE: 1474 if (strcmp(vport->minorp->sname, VLDC_HVCTL_SVCNAME)) { 1475 rv = EINVAL; 1476 break; 1477 } 1478 rv = i_vldc_ioctl_write_cookie(vport, instance, 1479 (void *)arg, mode); 1480 break; 1481 1482 default: 1483 DWARN("vldc_ioctl: vldc@%d:%lu unknown cmd=0x%x\n", 1484 instance, portno, cmd); 1485 rv = EINVAL; 1486 break; 1487 } 1488 1489 mutex_enter(&vminor->lock); 1490 vminor->in_use -= 1; 1491 if (vminor->in_use == 0) { 1492 cv_signal(&vminor->cv); 1493 } 1494 mutex_exit(&vminor->lock); 1495 1496 D1("vldc_ioctl: rv=%d\n", rv); 1497 1498 return (rv); 1499 } 1500 1501 /* cb_read */ 1502 static int 1503 vldc_read(dev_t dev, struct uio *uiop, cred_t *credp) 1504 { 1505 _NOTE(ARGUNUSED(credp)) 1506 1507 int instance; 1508 minor_t minor; 1509 size_t size = 0; 1510 uint64_t portno; 1511 vldc_t *vldcp; 1512 vldc_port_t *vport; 1513 vldc_minor_t *vminor; 1514 int rv = 0; 1515 1516 minor = getminor(dev); 1517 instance = VLDCINST(minor); 1518 vldcp = ddi_get_soft_state(vldc_ssp, instance); 1519 if (vldcp == NULL) { 1520 return (ENXIO); 1521 } 1522 1523 vminor = VLDCMINOR(vldcp, minor); 1524 mutex_enter(&vminor->lock); 1525 portno = vminor->portno; 1526 if (portno == VLDC_INVALID_PORTNO) { 1527 mutex_exit(&vminor->lock); 1528 return (ENOLINK); 1529 } 1530 1531 D2("vldc_read: vldc@%d:%lu reading data\n", instance, portno); 1532 1533 vport = &(vldcp->port[portno]); 1534 1535 /* check the port status */ 1536 if (vport->status != VLDC_PORT_READY) { 1537 DWARN("vldc_read: vldc@%d:%lu not in the ready state\n", 1538 instance, portno); 1539 mutex_exit(&vminor->lock); 1540 return (ENOTACTIVE); 1541 } 1542 1543 /* read data */ 1544 size = MIN(vport->mtu, uiop->uio_resid); 1545 rv = ldc_read(vport->ldc_handle, vport->recv_buf, &size); 1546 1547 D2("vldc_read: vldc@%d:%lu ldc_read size=%ld, rv=%d\n", 1548 instance, portno, size, rv); 1549 1550 if (rv == 0) { 1551 if (size != 0) { 1552 rv = uiomove(vport->recv_buf, size, UIO_READ, uiop); 1553 } else { 1554 rv = EWOULDBLOCK; 1555 } 1556 } else { 1557 switch (rv) { 1558 case ENOBUFS: 1559 break; 1560 case ETIMEDOUT: 1561 case EWOULDBLOCK: 1562 rv = EWOULDBLOCK; 1563 break; 1564 default: 1565 rv = ECONNRESET; 1566 break; 1567 } 1568 } 1569 1570 mutex_exit(&vminor->lock); 1571 1572 return (rv); 1573 } 1574 1575 /* cb_write */ 1576 static int 1577 vldc_write(dev_t dev, struct uio *uiop, cred_t *credp) 1578 { 1579 _NOTE(ARGUNUSED(credp)) 1580 1581 int instance; 1582 minor_t minor; 1583 size_t size; 1584 size_t orig_size; 1585 uint64_t portno; 1586 vldc_t *vldcp; 1587 vldc_port_t *vport; 1588 vldc_minor_t *vminor; 1589 int rv = EINVAL; 1590 1591 minor = getminor(dev); 1592 instance = VLDCINST(minor); 1593 vldcp = ddi_get_soft_state(vldc_ssp, instance); 1594 if (vldcp == NULL) { 1595 return (ENXIO); 1596 } 1597 1598 vminor = VLDCMINOR(vldcp, minor); 1599 mutex_enter(&vminor->lock); 1600 portno = vminor->portno; 1601 if (portno == VLDC_INVALID_PORTNO) { 1602 mutex_exit(&vminor->lock); 1603 return (ENOLINK); 1604 } 1605 1606 vport = &(vldcp->port[portno]); 1607 1608 /* check the port status */ 1609 if (vport->status != VLDC_PORT_READY) { 1610 DWARN("vldc_write: vldc@%d:%lu not in the ready state\n", 1611 instance, portno); 1612 mutex_exit(&vminor->lock); 1613 return (ENOTACTIVE); 1614 } 1615 1616 orig_size = uiop->uio_resid; 1617 size = orig_size; 1618 1619 if (size > vport->mtu) { 1620 if (vport->is_stream) { 1621 /* can only send MTU size at a time */ 1622 size = vport->mtu; 1623 } else { 1624 mutex_exit(&vminor->lock); 1625 return (EMSGSIZE); 1626 } 1627 } 1628 1629 D2("vldc_write: vldc@%d:%lu writing %lu bytes\n", instance, portno, 1630 size); 1631 1632 rv = uiomove(vport->send_buf, size, UIO_WRITE, uiop); 1633 if (rv == 0) { 1634 rv = ldc_write(vport->ldc_handle, (caddr_t)vport->send_buf, 1635 &size); 1636 if (rv != 0) { 1637 DWARN("vldc_write: vldc@%d:%lu failed writing %lu " 1638 "bytes rv=%d\n", instance, portno, size, rv); 1639 } 1640 } else { 1641 size = 0; 1642 } 1643 1644 mutex_exit(&vminor->lock); 1645 1646 /* resid is total number of bytes *not* sent */ 1647 uiop->uio_resid = orig_size - size; 1648 1649 return (rv); 1650 } 1651 1652 /* cb_chpoll */ 1653 static int 1654 vldc_chpoll(dev_t dev, short events, int anyyet, short *reventsp, 1655 struct pollhead **phpp) 1656 { 1657 int instance; 1658 minor_t minor; 1659 uint64_t portno; 1660 vldc_t *vldcp; 1661 vldc_port_t *vport; 1662 vldc_minor_t *vminor; 1663 boolean_t haspkts; 1664 1665 minor = getminor(dev); 1666 instance = VLDCINST(minor); 1667 vldcp = ddi_get_soft_state(vldc_ssp, instance); 1668 if (vldcp == NULL) { 1669 return (ENXIO); 1670 } 1671 1672 vminor = VLDCMINOR(vldcp, minor); 1673 mutex_enter(&vminor->lock); 1674 portno = vminor->portno; 1675 if (portno == VLDC_INVALID_PORTNO) { 1676 mutex_exit(&vminor->lock); 1677 return (ENOLINK); 1678 } 1679 1680 vport = &(vldcp->port[portno]); 1681 1682 /* check the port status */ 1683 if (vport->status != VLDC_PORT_READY) { 1684 mutex_exit(&vminor->lock); 1685 return (ENOTACTIVE); 1686 } 1687 1688 D2("vldc_chpoll: vldc@%d:%lu polling events 0x%x\n", 1689 instance, portno, events); 1690 1691 *reventsp = 0; 1692 1693 if (vport->ldc_status == LDC_UP) { 1694 /* 1695 * Check if the receive queue is empty and if not, signal that 1696 * there is data ready to read. 1697 */ 1698 if (events & POLLIN) { 1699 if ((ldc_chkq(vport->ldc_handle, &haspkts) == 0) && 1700 haspkts) { 1701 *reventsp |= POLLIN; 1702 } 1703 } 1704 1705 if (events & POLLOUT) 1706 *reventsp |= POLLOUT; 1707 1708 } else if (vport->hanged_up) { 1709 *reventsp |= POLLHUP; 1710 vport->hanged_up = B_FALSE; 1711 } 1712 1713 mutex_exit(&vminor->lock); 1714 1715 if (((*reventsp) == 0) && (!anyyet)) { 1716 *phpp = &vport->poll; 1717 } 1718 1719 D2("vldc_chpoll: vldc@%d:%lu ev=0x%x, rev=0x%x\n", 1720 instance, portno, events, *reventsp); 1721 1722 return (0); 1723 } 1724