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