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