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