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