1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 28 /* 29 * Domain Services Module System Specific Code. 30 * 31 * The Domain Services (DS) module is responsible for communication 32 * with external service entities. It provides a kernel API for clients to 33 * publish capabilities and handles the low level communication and 34 * version negotiation required to export those capabilities to any 35 * interested service entity. Once a capability has been successfully 36 * registered with a service entity, the DS module facilitates all 37 * data transfers between the service entity and the client providing 38 * that particular capability. 39 * 40 * This file provides the system interfaces that are required for 41 * the ds.c module, which is common to both Solaris and VBSC (linux). 42 */ 43 44 #include <sys/modctl.h> 45 #include <sys/ksynch.h> 46 #include <sys/taskq.h> 47 #include <sys/disp.h> 48 #include <sys/cmn_err.h> 49 #include <sys/note.h> 50 #include <sys/mach_descrip.h> 51 #include <sys/mdesc.h> 52 #include <sys/mdeg.h> 53 #include <sys/ldc.h> 54 #include <sys/ds.h> 55 #include <sys/ds_impl.h> 56 57 /* 58 * All DS ports in the system 59 * 60 * The list of DS ports is read in from the MD when the DS module is 61 * initialized and is never modified. This eliminates the need for 62 * locking to access the port array itself. Access to the individual 63 * ports are synchronized at the port level. 64 */ 65 ds_port_t ds_ports[DS_MAX_PORTS]; 66 ds_portset_t ds_allports; /* all DS ports in the system */ 67 68 /* 69 * Table of registered services 70 * 71 * Locking: Accesses to the table of services are synchronized using 72 * a mutex lock. The reader lock must be held when looking up service 73 * information in the table. The writer lock must be held when any 74 * service information is being modified. 75 */ 76 ds_svcs_t ds_svcs; 77 78 /* 79 * Taskq for internal task processing 80 */ 81 static taskq_t *ds_taskq; 82 83 /* 84 * The actual required number of parallel threads is not expected 85 * to be very large. Use the maximum number of CPUs in the system 86 * as a rough upper bound. 87 */ 88 #define DS_MAX_TASKQ_THR NCPU 89 #define DS_DISPATCH(fn, arg) taskq_dispatch(ds_taskq, fn, arg, TQ_SLEEP) 90 91 ds_domain_hdl_t ds_my_domain_hdl = NULL; 92 93 #ifdef DEBUG 94 /* 95 * Debug Flag 96 */ 97 uint_t ds_debug = 0; 98 #endif /* DEBUG */ 99 100 /* initialization functions */ 101 static void ds_init(void); 102 static void ds_fini(void); 103 static int ds_ports_init(void); 104 static int ds_ports_fini(void); 105 106 /* port utilities */ 107 static int ds_port_add(md_t *mdp, mde_cookie_t port, mde_cookie_t chan); 108 109 /* log functions */ 110 static void ds_log_init(void); 111 static void ds_log_fini(void); 112 static int ds_log_remove(void); 113 static void ds_log_purge(void *arg); 114 115 static struct modlmisc modlmisc = { 116 &mod_miscops, 117 "Domain Services 1.9" 118 }; 119 120 static struct modlinkage modlinkage = { 121 MODREV_1, 122 (void *)&modlmisc, 123 NULL 124 }; 125 126 int 127 _init(void) 128 { 129 int rv; 130 131 /* 132 * Perform all internal setup before initializing 133 * the DS ports. This ensures that events can be 134 * processed as soon as the port comes up. 135 */ 136 ds_init(); 137 138 /* force attach channel nexus */ 139 (void) i_ddi_attach_hw_nodes("cnex"); 140 141 if ((rv = ds_ports_init()) != 0) { 142 cmn_err(CE_WARN, "Domain Services initialization failed"); 143 ds_fini(); 144 return (rv); 145 } 146 147 if ((rv = mod_install(&modlinkage)) != 0) { 148 (void) ds_ports_fini(); 149 ds_fini(); 150 } 151 152 return (rv); 153 } 154 155 int 156 _info(struct modinfo *modinfop) 157 { 158 return (mod_info(&modlinkage, modinfop)); 159 } 160 161 int 162 _fini(void) 163 { 164 int rv; 165 166 if ((rv = mod_remove(&modlinkage)) == 0) { 167 (void) ds_ports_fini(); 168 ds_fini(); 169 } 170 171 return (rv); 172 } 173 174 static void 175 ds_fini(void) 176 { 177 /* 178 * Flip the enabled switch to make sure that no 179 * incoming events get dispatched while things 180 * are being torn down. 181 */ 182 ds_enabled = B_FALSE; 183 184 /* 185 * Destroy the taskq. 186 */ 187 taskq_destroy(ds_taskq); 188 189 /* 190 * Destroy the message log. 191 */ 192 ds_log_fini(); 193 194 /* 195 * Deallocate the table of registered services 196 */ 197 198 /* clear out all entries */ 199 mutex_enter(&ds_svcs.lock); 200 (void) ds_walk_svcs(ds_svc_free, NULL); 201 mutex_exit(&ds_svcs.lock); 202 203 /* destroy the table itself */ 204 DS_FREE(ds_svcs.tbl, ds_svcs.maxsvcs * sizeof (ds_svc_t *)); 205 mutex_destroy(&ds_svcs.lock); 206 bzero(&ds_svcs, sizeof (ds_svcs)); 207 } 208 209 /* 210 * Initialize the list of ports based on the MD. 211 */ 212 static int 213 ds_ports_init(void) 214 { 215 int idx; 216 int rv = 0; 217 md_t *mdp; 218 int num_nodes; 219 int listsz; 220 mde_cookie_t rootnode; 221 mde_cookie_t dsnode; 222 mde_cookie_t *portp = NULL; 223 mde_cookie_t *chanp = NULL; 224 int nport; 225 int nchan; 226 227 if ((mdp = md_get_handle()) == NULL) { 228 cmn_err(CE_WARN, "Unable to initialize machine description"); 229 return (-1); 230 } 231 232 num_nodes = md_node_count(mdp); 233 ASSERT(num_nodes > 0); 234 235 listsz = num_nodes * sizeof (mde_cookie_t); 236 237 /* allocate temporary storage for MD scans */ 238 portp = kmem_zalloc(listsz, KM_SLEEP); 239 chanp = kmem_zalloc(listsz, KM_SLEEP); 240 241 rootnode = md_root_node(mdp); 242 ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE); 243 244 /* 245 * The root of the search for DS port nodes is the 246 * DS node. Perform a scan to find that node. 247 */ 248 nport = md_scan_dag(mdp, rootnode, md_find_name(mdp, DS_MD_ROOT_NAME), 249 md_find_name(mdp, "fwd"), portp); 250 251 if (nport <= 0) { 252 DS_DBG_MD(CE_NOTE, "No '%s' node in MD", DS_MD_ROOT_NAME); 253 goto done; 254 } 255 256 /* expecting only one DS node */ 257 if (nport != 1) { 258 DS_DBG_MD(CE_NOTE, "Expected one '%s' node in the MD, found %d", 259 DS_MD_ROOT_NAME, nport); 260 } 261 262 dsnode = portp[0]; 263 264 /* find all the DS ports in the MD */ 265 nport = md_scan_dag(mdp, dsnode, md_find_name(mdp, DS_MD_PORT_NAME), 266 md_find_name(mdp, "fwd"), portp); 267 268 if (nport <= 0) { 269 DS_DBG_MD(CE_NOTE, "No '%s' nodes in MD", DS_MD_PORT_NAME); 270 goto done; 271 } 272 273 /* 274 * Initialize all the ports found in the MD. 275 */ 276 for (idx = 0; idx < nport; idx++) { 277 278 /* get the channels for this port */ 279 nchan = md_scan_dag(mdp, portp[idx], 280 md_find_name(mdp, DS_MD_CHAN_NAME), 281 md_find_name(mdp, "fwd"), chanp); 282 283 if (nchan <= 0) { 284 cmn_err(CE_WARN, "No '%s' node for DS port", 285 DS_MD_CHAN_NAME); 286 rv = -1; 287 goto done; 288 } 289 290 /* expecting only one channel */ 291 if (nchan != 1) { 292 DS_DBG_MD(CE_NOTE, "Expected one '%s' node for DS " 293 " port, found %d", DS_MD_CHAN_NAME, nchan); 294 } 295 296 if (ds_port_add(mdp, portp[idx], chanp[0]) != 0) { 297 rv = -1; 298 goto done; 299 } 300 } 301 302 done: 303 if (rv != 0) 304 (void) ds_ports_fini(); 305 306 DS_FREE(portp, listsz); 307 DS_FREE(chanp, listsz); 308 309 (void) md_fini_handle(mdp); 310 311 return (rv); 312 } 313 314 static int 315 ds_ports_fini(void) 316 { 317 int idx; 318 319 /* 320 * Tear down each initialized port. 321 */ 322 for (idx = 0; idx < DS_MAX_PORTS; idx++) { 323 if (DS_PORT_IN_SET(ds_allports, idx)) { 324 (void) ds_remove_port(idx, 1); 325 } 326 } 327 328 return (0); 329 } 330 331 static int 332 ds_port_add(md_t *mdp, mde_cookie_t port, mde_cookie_t chan) 333 { 334 uint64_t port_id; 335 uint64_t ldc_id; 336 uint64_t dhdl; 337 char *dom_name; 338 339 /* get the ID for this port */ 340 if (md_get_prop_val(mdp, port, "id", &port_id) != 0) { 341 cmn_err(CE_WARN, "%s: port 'id' property not found", 342 __func__); 343 return (-1); 344 } 345 346 /* sanity check the port id */ 347 if (port_id > DS_MAX_PORT_ID) { 348 cmn_err(CE_WARN, "%s: port ID %ld out of range", 349 __func__, port_id); 350 return (-1); 351 } 352 353 /* get the channel ID for this port */ 354 if (md_get_prop_val(mdp, chan, "id", &ldc_id) != 0) { 355 cmn_err(CE_WARN, "ds@%lx: %s: no channel 'id' property", 356 port_id, __func__); 357 return (-1); 358 } 359 360 /* get the remote-domain-id property if it's there */ 361 if (md_get_prop_val(mdp, port, "remote-domain-id", &dhdl) != 0) { 362 DS_DBG_MD(CE_NOTE, "ds@%lx: %s: 'remote-domain-id' prop " 363 " not found", port_id, __func__); 364 dhdl = DS_DHDL_INVALID; 365 } 366 367 /* get the remote-domain-name property if it's there */ 368 if (md_get_prop_str(mdp, port, "remote-domain-name", &dom_name) != 0) { 369 DS_DBG_MD(CE_NOTE, "ds@%lx: %s: 'remote-domain-name' prop " 370 " not found", port_id, __func__); 371 dom_name = NULL; 372 } 373 374 if (ds_add_port(port_id, ldc_id, dhdl, dom_name, 1) != 0) 375 return (-1); 376 377 return (0); 378 } 379 380 void 381 ds_init() 382 { 383 ds_common_init(); 384 385 /* 386 * Create taskq for internal processing threads. This 387 * includes processing incoming request messages and 388 * sending out of band registration messages. 389 */ 390 ds_taskq = taskq_create("ds_taskq", 1, minclsyspri, 1, 391 DS_MAX_TASKQ_THR, TASKQ_PREPOPULATE | TASKQ_DYNAMIC); 392 393 /* 394 * Initialize the message log. 395 */ 396 ds_log_init(); 397 } 398 399 int 400 ds_sys_dispatch_func(void (func)(void *), void *arg) 401 { 402 return (DS_DISPATCH(func, arg) == NULL); 403 } 404 405 /* 406 * Drain event queue, if necessary. 407 */ 408 void 409 ds_sys_drain_events(ds_port_t *port) 410 { 411 _NOTE(ARGUNUSED(port)) 412 } 413 414 /* 415 * System specific port initalization. 416 */ 417 void 418 ds_sys_port_init(ds_port_t *port) 419 { 420 _NOTE(ARGUNUSED(port)) 421 } 422 423 /* 424 * System specific port teardown. 425 */ 426 void 427 ds_sys_port_fini(ds_port_t *port) 428 { 429 _NOTE(ARGUNUSED(port)) 430 } 431 432 /* 433 * System specific LDC channel initialization. 434 */ 435 void 436 ds_sys_ldc_init(ds_port_t *port) 437 { 438 int rv; 439 char ebuf[DS_EBUFSIZE]; 440 441 ASSERT(MUTEX_HELD(&port->lock)); 442 443 if ((rv = ldc_open(port->ldc.hdl)) != 0) { 444 cmn_err(CE_WARN, "ds@%lx: %s: ldc_open: %s", 445 PORTID(port), __func__, ds_errno_to_str(rv, ebuf)); 446 return; 447 } 448 449 (void) ldc_up(port->ldc.hdl); 450 451 (void) ldc_status(port->ldc.hdl, &port->ldc.state); 452 453 DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: initial LDC state 0x%x", 454 PORTID(port), __func__, port->ldc.state); 455 456 port->state = DS_PORT_LDC_INIT; 457 } 458 459 /* 460 * DS message log 461 * 462 * Locking: The message log is protected by a single mutex. This 463 * protects all fields in the log structure itself as well as 464 * everything in the entry structures on both the log and the 465 * free list. 466 */ 467 static struct log { 468 ds_log_entry_t *head; /* head of the log */ 469 ds_log_entry_t *freelist; /* head of the free list */ 470 size_t size; /* size of the log in bytes */ 471 uint32_t nentry; /* number of entries */ 472 kmutex_t lock; /* log lock */ 473 } ds_log; 474 475 /* log soft limit */ 476 uint_t ds_log_sz = DS_LOG_DEFAULT_SZ; 477 478 /* initial pool of log entry structures */ 479 static ds_log_entry_t ds_log_entry_pool[DS_LOG_NPOOL]; 480 481 /* 482 * Logging Support 483 */ 484 static void 485 ds_log_init(void) 486 { 487 ds_log_entry_t *new; 488 489 /* initialize global lock */ 490 mutex_init(&ds_log.lock, NULL, MUTEX_DRIVER, NULL); 491 492 mutex_enter(&ds_log.lock); 493 494 /* initialize the log */ 495 ds_log.head = NULL; 496 ds_log.size = 0; 497 ds_log.nentry = 0; 498 499 /* initialize the free list */ 500 for (new = ds_log_entry_pool; new < DS_LOG_POOL_END; new++) { 501 new->next = ds_log.freelist; 502 ds_log.freelist = new; 503 } 504 505 mutex_exit(&ds_log.lock); 506 507 DS_DBG_LOG(CE_NOTE, "ds_log initialized: size=%d bytes, " 508 " limit=%d bytes, ninit=%ld", ds_log_sz, DS_LOG_LIMIT, 509 DS_LOG_NPOOL); 510 } 511 512 static void 513 ds_log_fini(void) 514 { 515 ds_log_entry_t *next; 516 517 mutex_enter(&ds_log.lock); 518 519 /* clear out the log */ 520 while (ds_log.nentry > 0) 521 (void) ds_log_remove(); 522 523 /* 524 * Now all the entries are on the free list. 525 * Clear out the free list, deallocating any 526 * entry that was dynamically allocated. 527 */ 528 while (ds_log.freelist != NULL) { 529 next = ds_log.freelist->next; 530 531 if (!DS_IS_POOL_ENTRY(ds_log.freelist)) { 532 kmem_free(ds_log.freelist, sizeof (ds_log_entry_t)); 533 } 534 535 ds_log.freelist = next; 536 } 537 538 mutex_exit(&ds_log.lock); 539 540 mutex_destroy(&ds_log.lock); 541 } 542 543 static ds_log_entry_t * 544 ds_log_entry_alloc(void) 545 { 546 ds_log_entry_t *new = NULL; 547 548 ASSERT(MUTEX_HELD(&ds_log.lock)); 549 550 if (ds_log.freelist != NULL) { 551 new = ds_log.freelist; 552 ds_log.freelist = ds_log.freelist->next; 553 } 554 555 if (new == NULL) { 556 /* free list was empty */ 557 new = kmem_zalloc(sizeof (ds_log_entry_t), KM_SLEEP); 558 } 559 560 ASSERT(new); 561 562 return (new); 563 } 564 565 static void 566 ds_log_entry_free(ds_log_entry_t *entry) 567 { 568 ASSERT(MUTEX_HELD(&ds_log.lock)); 569 570 if (entry == NULL) 571 return; 572 573 if (entry->data != NULL) { 574 kmem_free(entry->data, entry->datasz); 575 entry->data = NULL; 576 } 577 578 /* place entry on the free list */ 579 entry->next = ds_log.freelist; 580 ds_log.freelist = entry; 581 } 582 583 /* 584 * Add a message to the end of the log 585 */ 586 static int 587 ds_log_add(ds_log_entry_t *new) 588 { 589 ASSERT(MUTEX_HELD(&ds_log.lock)); 590 591 if (ds_log.head == NULL) { 592 593 new->prev = new; 594 new->next = new; 595 596 ds_log.head = new; 597 } else { 598 ds_log_entry_t *head = ds_log.head; 599 ds_log_entry_t *tail = ds_log.head->prev; 600 601 new->next = head; 602 new->prev = tail; 603 tail->next = new; 604 head->prev = new; 605 } 606 607 /* increase the log size, including the metadata size */ 608 ds_log.size += DS_LOG_ENTRY_SZ(new); 609 ds_log.nentry++; 610 611 DS_DBG_LOG(CE_NOTE, "ds_log: added %ld data bytes, %ld total bytes", 612 new->datasz, DS_LOG_ENTRY_SZ(new)); 613 614 return (0); 615 } 616 617 /* 618 * Remove an entry from the head of the log 619 */ 620 static int 621 ds_log_remove(void) 622 { 623 ds_log_entry_t *head; 624 625 ASSERT(MUTEX_HELD(&ds_log.lock)); 626 627 head = ds_log.head; 628 629 /* empty list */ 630 if (head == NULL) 631 return (0); 632 633 if (head->next == ds_log.head) { 634 /* one element list */ 635 ds_log.head = NULL; 636 } else { 637 head->next->prev = head->prev; 638 head->prev->next = head->next; 639 ds_log.head = head->next; 640 } 641 642 DS_DBG_LOG(CE_NOTE, "ds_log: removed %ld data bytes, %ld total bytes", 643 head->datasz, DS_LOG_ENTRY_SZ(head)); 644 645 ds_log.size -= DS_LOG_ENTRY_SZ(head); 646 ds_log.nentry--; 647 648 ds_log_entry_free(head); 649 650 return (0); 651 } 652 653 /* 654 * Replace the data in the entry at the front of the list with then 655 * new data. This has the effect of removing the oldest entry and 656 * adding the new entry. 657 */ 658 static int 659 ds_log_replace(int32_t dest, uint8_t *msg, size_t sz) 660 { 661 ds_log_entry_t *head; 662 663 ASSERT(MUTEX_HELD(&ds_log.lock)); 664 665 head = ds_log.head; 666 667 DS_DBG_LOG(CE_NOTE, "ds_log: replaced %ld data bytes (%ld total) with " 668 " %ld data bytes (%ld total)", head->datasz, 669 DS_LOG_ENTRY_SZ(head), sz, sz + sizeof (ds_log_entry_t)); 670 671 ds_log.size -= DS_LOG_ENTRY_SZ(head); 672 673 kmem_free(head->data, head->datasz); 674 675 head->data = msg; 676 head->datasz = sz; 677 head->timestamp = ddi_get_time(); 678 head->dest = dest; 679 680 ds_log.size += DS_LOG_ENTRY_SZ(head); 681 682 ds_log.head = head->next; 683 684 return (0); 685 } 686 687 static void 688 ds_log_purge(void *arg) 689 { 690 _NOTE(ARGUNUSED(arg)) 691 692 mutex_enter(&ds_log.lock); 693 694 DS_DBG_LOG(CE_NOTE, "ds_log: purging oldest log entries"); 695 696 while ((ds_log.nentry) && (ds_log.size >= ds_log_sz)) { 697 (void) ds_log_remove(); 698 } 699 700 mutex_exit(&ds_log.lock); 701 } 702 703 int 704 ds_log_add_msg(int32_t dest, uint8_t *msg, size_t sz) 705 { 706 int rv = 0; 707 void *data; 708 709 mutex_enter(&ds_log.lock); 710 711 /* allocate a local copy of the data */ 712 data = kmem_alloc(sz, KM_SLEEP); 713 bcopy(msg, data, sz); 714 715 /* check if the log is larger than the soft limit */ 716 if ((ds_log.nentry) && ((ds_log.size + sz) >= ds_log_sz)) { 717 /* 718 * The log is larger than the soft limit. 719 * Swap the oldest entry for the newest. 720 */ 721 DS_DBG_LOG(CE_NOTE, "%s: replacing oldest entry with new entry", 722 __func__); 723 (void) ds_log_replace(dest, data, sz); 724 } else { 725 /* 726 * Still have headroom under the soft limit. 727 * Add the new entry to the log. 728 */ 729 ds_log_entry_t *new; 730 731 new = ds_log_entry_alloc(); 732 733 /* fill in message data */ 734 new->data = data; 735 new->datasz = sz; 736 new->timestamp = ddi_get_time(); 737 new->dest = dest; 738 739 rv = ds_log_add(new); 740 } 741 742 /* check if the log is larger than the hard limit */ 743 if ((ds_log.nentry > 1) && (ds_log.size >= DS_LOG_LIMIT)) { 744 /* 745 * Wakeup the thread to remove entries 746 * from the log until it is smaller than 747 * the soft limit. 748 */ 749 DS_DBG_LOG(CE_NOTE, "%s: log exceeded %d bytes, scheduling" 750 " a purge...", __func__, DS_LOG_LIMIT); 751 752 if (DS_DISPATCH(ds_log_purge, NULL) == NULL) { 753 cmn_err(CE_NOTE, "%s: purge thread failed to start", 754 __func__); 755 } 756 } 757 758 mutex_exit(&ds_log.lock); 759 760 return (rv); 761 } 762 763 int 764 ds_add_port(uint64_t port_id, uint64_t ldc_id, ds_domain_hdl_t dhdl, 765 char *dom_name, int verbose) 766 { 767 ds_port_t *newport; 768 769 /* sanity check the port id */ 770 if (port_id > DS_MAX_PORT_ID) { 771 cmn_err(CE_WARN, "%s: port ID %ld out of range", 772 __func__, port_id); 773 return (EINVAL); 774 } 775 776 DS_DBG_MD(CE_NOTE, "%s: adding port ds@%ld, LDC: 0x%lx, dhdl: 0x%lx", 777 __func__, port_id, ldc_id, dhdl); 778 779 /* get the port structure from the array of ports */ 780 newport = &ds_ports[port_id]; 781 782 /* check for a duplicate port in the MD */ 783 if (newport->state != DS_PORT_FREE) { 784 if (verbose) { 785 cmn_err(CE_WARN, "ds@%lx: %s: port already exists", 786 port_id, __func__); 787 } 788 if (newport->domain_hdl == DS_DHDL_INVALID) { 789 newport->domain_hdl = dhdl; 790 } 791 if (newport->domain_name == NULL && dom_name != NULL) { 792 newport->domain_name = ds_strdup(dom_name); 793 } 794 return (EBUSY); 795 } 796 797 /* initialize the port */ 798 newport->id = port_id; 799 newport->ldc.id = ldc_id; 800 newport->domain_hdl = dhdl; 801 if (dom_name) { 802 newport->domain_name = ds_strdup(dom_name); 803 } else 804 newport->domain_name = NULL; 805 ds_port_common_init(newport); 806 807 return (0); 808 } 809 810 int 811 ds_remove_port(uint64_t port_id, int is_fini) 812 { 813 ds_port_t *port; 814 815 if (port_id >= DS_MAX_PORTS || !DS_PORT_IN_SET(ds_allports, port_id)) { 816 DS_DBG_MD(CE_NOTE, "%s: invalid port %lx", __func__, 817 port_id); 818 return (EINVAL); 819 } 820 821 DS_DBG_MD(CE_NOTE, "%s: removing port ds@%lx", __func__, port_id); 822 823 port = &ds_ports[port_id]; 824 825 mutex_enter(&port->lock); 826 827 if (port->state >= DS_PORT_LDC_INIT) { 828 /* shut down the LDC for this port */ 829 (void) ds_ldc_fini(port); 830 } 831 832 mutex_exit(&port->lock); 833 834 if (port->domain_name) { 835 DS_FREE(port->domain_name, strlen(port->domain_name) + 1); 836 port->domain_name = NULL; 837 } 838 port->domain_hdl = DS_DHDL_INVALID; 839 840 /* clean up the port structure */ 841 ds_port_common_fini(port, is_fini); 842 return (0); 843 } 844 845 /* 846 * Interface for ds_service_lookup in lds driver. 847 */ 848 int 849 ds_service_lookup(ds_svc_hdl_t hdl, char **servicep, uint_t *is_client) 850 { 851 ds_svc_t *svc; 852 853 mutex_enter(&ds_svcs.lock); 854 if ((svc = ds_get_svc(hdl)) == NULL) { 855 mutex_exit(&ds_svcs.lock); 856 DS_DBG(CE_NOTE, "%s: handle 0x%llx not found", __func__, 857 (u_longlong_t)hdl); 858 return (ENXIO); 859 } 860 *servicep = svc->cap.svc_id; 861 *is_client = svc->flags & DSSF_ISCLIENT; 862 mutex_exit(&ds_svcs.lock); 863 return (0); 864 } 865 866 /* 867 * Interface for ds_domain_lookup in lds driver. 868 */ 869 int 870 ds_domain_lookup(ds_svc_hdl_t hdl, ds_domain_hdl_t *dhdlp) 871 { 872 ds_svc_t *svc; 873 874 mutex_enter(&ds_svcs.lock); 875 if ((svc = ds_get_svc(hdl)) == NULL) { 876 mutex_exit(&ds_svcs.lock); 877 DS_DBG(CE_NOTE, "%s: handle 0x%llx not found", __func__, 878 (u_longlong_t)hdl); 879 return (ENXIO); 880 } 881 if (svc->port == NULL) 882 *dhdlp = ds_my_domain_hdl; 883 else 884 *dhdlp = svc->port->domain_hdl; 885 mutex_exit(&ds_svcs.lock); 886 return (0); 887 } 888 889 /* 890 * Interface for ds_hdl_isready in lds driver. 891 */ 892 int 893 ds_hdl_isready(ds_svc_hdl_t hdl, uint_t *is_ready) 894 { 895 ds_svc_t *svc; 896 897 mutex_enter(&ds_svcs.lock); 898 if ((svc = ds_get_svc(hdl)) == NULL) { 899 mutex_exit(&ds_svcs.lock); 900 DS_DBG(CE_NOTE, "%s: handle 0x%llx not found", __func__, 901 (u_longlong_t)hdl); 902 return (ENXIO); 903 } 904 *is_ready = (svc->state == DS_SVC_ACTIVE); 905 mutex_exit(&ds_svcs.lock); 906 return (0); 907 } 908 909 /* 910 * Interface for ds_dom_name_to_hdl in lds driver. 911 */ 912 int 913 ds_dom_name_to_hdl(char *domain_name, ds_domain_hdl_t *dhdlp) 914 { 915 int i; 916 ds_port_t *port; 917 918 for (i = 0, port = ds_ports; i < DS_MAX_PORTS; i++, port++) { 919 if (port->state != DS_PORT_FREE && 920 port->domain_name != NULL && 921 strcmp(port->domain_name, domain_name) == 0) { 922 *dhdlp = port->domain_hdl; 923 return (0); 924 } 925 } 926 return (ENXIO); 927 } 928 929 /* 930 * Interface for ds_dom_hdl_to_name in lds driver. 931 */ 932 int 933 ds_dom_hdl_to_name(ds_domain_hdl_t dhdl, char **domain_namep) 934 { 935 int i; 936 ds_port_t *port; 937 938 for (i = 0, port = ds_ports; i < DS_MAX_PORTS; i++, port++) { 939 if (port->state != DS_PORT_FREE && 940 port->domain_hdl == dhdl) { 941 *domain_namep = port->domain_name; 942 return (0); 943 } 944 } 945 return (ENXIO); 946 } 947 948 /* 949 * Unregister all handles related to device open instance. 950 */ 951 void 952 ds_unreg_all(int instance) 953 { 954 int idx; 955 ds_svc_t *svc; 956 ds_svc_hdl_t hdl; 957 958 DS_DBG_USR(CE_NOTE, "%s: entered", __func__); 959 960 /* walk every table entry */ 961 mutex_enter(&ds_svcs.lock); 962 for (idx = 0; idx < ds_svcs.maxsvcs; idx++) { 963 svc = ds_svcs.tbl[idx]; 964 if (DS_SVC_ISFREE(svc)) 965 continue; 966 if ((svc->flags & DSSF_ISUSER) != 0 && svc->drvi == instance) { 967 hdl = svc->hdl; 968 mutex_exit(&ds_svcs.lock); 969 (void) ds_unreg_hdl(hdl); 970 mutex_enter(&ds_svcs.lock); 971 DS_DBG_USR(CE_NOTE, "%s: ds_unreg_hdl(0x%llx):", 972 __func__, (u_longlong_t)hdl); 973 } 974 } 975 mutex_exit(&ds_svcs.lock); 976 } 977 978 /* 979 * Special callbacks to allow the lds module revision-independent access 980 * to service structure data in the callback routines. This assumes that 981 * we put a special "cookie" in the arg argument passed to those 982 * routines (for now, a ptr to the svc structure, but it could be a svc 983 * table index or something that we could get back to the svc table entry). 984 */ 985 void 986 ds_cbarg_get_hdl(ds_cb_arg_t arg, ds_svc_hdl_t *hdlp) 987 { 988 ds_svc_t *svc = (ds_svc_t *)arg; 989 990 ASSERT(svc == (ds_svc_t *)svc->ops.cb_arg); 991 *hdlp = svc->hdl; 992 } 993 994 void 995 ds_cbarg_get_flags(ds_cb_arg_t arg, uint32_t *flagsp) 996 { 997 ds_svc_t *svc = (ds_svc_t *)arg; 998 999 ASSERT(svc == (ds_svc_t *)svc->ops.cb_arg); 1000 *flagsp = svc->flags; 1001 } 1002 1003 void 1004 ds_cbarg_get_drv_info(ds_cb_arg_t arg, int *drvip) 1005 { 1006 ds_svc_t *svc = (ds_svc_t *)arg; 1007 1008 ASSERT(svc == (ds_svc_t *)svc->ops.cb_arg); 1009 *drvip = svc->drvi; 1010 } 1011 1012 void 1013 ds_cbarg_get_drv_per_svc_ptr(ds_cb_arg_t arg, void **dpspp) 1014 { 1015 ds_svc_t *svc = (ds_svc_t *)arg; 1016 1017 ASSERT(svc == (ds_svc_t *)svc->ops.cb_arg); 1018 *dpspp = svc->drv_psp; 1019 } 1020 1021 void 1022 ds_cbarg_get_domain(ds_cb_arg_t arg, ds_domain_hdl_t *dhdlp) 1023 { 1024 ds_svc_t *svc = (ds_svc_t *)arg; 1025 1026 ASSERT(svc == (ds_svc_t *)svc->ops.cb_arg); 1027 if (svc->port == NULL) 1028 *dhdlp = ds_my_domain_hdl; 1029 else 1030 *dhdlp = svc->port->domain_hdl; 1031 } 1032 1033 void 1034 ds_cbarg_get_service_id(ds_cb_arg_t arg, char **servicep) 1035 { 1036 ds_svc_t *svc = (ds_svc_t *)arg; 1037 1038 ASSERT(svc == (ds_svc_t *)svc->ops.cb_arg); 1039 *servicep = svc->cap.svc_id; 1040 } 1041 1042 void 1043 ds_cbarg_set_drv_per_svc_ptr(ds_cb_arg_t arg, void *dpsp) 1044 { 1045 ds_svc_t *svc = (ds_svc_t *)arg; 1046 1047 ASSERT(svc == (ds_svc_t *)svc->ops.cb_arg); 1048 svc->drv_psp = dpsp; 1049 } 1050 1051 void 1052 ds_cbarg_set_cookie(ds_svc_t *svc) 1053 { 1054 svc->ops.cb_arg = (ds_cb_arg_t)(svc); 1055 } 1056 1057 int 1058 ds_hdl_get_cbarg(ds_svc_hdl_t hdl, ds_cb_arg_t *cbargp) 1059 { 1060 ds_svc_t *svc; 1061 1062 mutex_enter(&ds_svcs.lock); 1063 if ((svc = ds_get_svc(hdl)) != NULL && 1064 (svc->flags & DSSF_ISUSER) != 0) { 1065 ASSERT(svc == (ds_svc_t *)svc->ops.cb_arg); 1066 *cbargp = svc->ops.cb_arg; 1067 mutex_exit(&ds_svcs.lock); 1068 return (0); 1069 } 1070 mutex_exit(&ds_svcs.lock); 1071 return (ENXIO); 1072 } 1073 1074 int 1075 ds_is_my_hdl(ds_svc_hdl_t hdl, int instance) 1076 { 1077 ds_svc_t *svc; 1078 int rv = 0; 1079 1080 mutex_enter(&ds_svcs.lock); 1081 if ((svc = ds_get_svc(hdl)) == NULL) { 1082 DS_DBG_USR(CE_NOTE, "%s: invalid hdl: 0x%llx\n", __func__, 1083 (u_longlong_t)hdl); 1084 rv = ENXIO; 1085 } else if (instance == DS_INVALID_INSTANCE) { 1086 if ((svc->flags & DSSF_ISUSER) != 0) { 1087 DS_DBG_USR(CE_NOTE, "%s: unowned hdl: 0x%llx\n", 1088 __func__, (u_longlong_t)hdl); 1089 rv = EACCES; 1090 } 1091 } else if ((svc->flags & DSSF_ISUSER) == 0 || svc->drvi != instance) { 1092 DS_DBG_USR(CE_NOTE, "%s: unowned hdl: 0x%llx\n", __func__, 1093 (u_longlong_t)hdl); 1094 rv = EACCES; 1095 } 1096 mutex_exit(&ds_svcs.lock); 1097 return (rv); 1098 } 1099