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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 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 /* 30 * hot-plug services module 31 */ 32 33 #include <sys/modctl.h> 34 #include <sys/kmem.h> 35 #include <sys/sunddi.h> 36 #include <sys/sunndi.h> 37 #include <sys/disp.h> 38 #include <sys/stat.h> 39 #include <sys/hotplug/hpcsvc.h> 40 #include <sys/callb.h> 41 42 /* 43 * debug macros: 44 */ 45 #if defined(DEBUG) 46 47 int hpcsvc_debug = 0; 48 49 static void debug(char *, uintptr_t, uintptr_t, uintptr_t, 50 uintptr_t, uintptr_t); 51 52 #define DEBUG0(fmt) \ 53 debug(fmt, 0, 0, 0, 0, 0); 54 #define DEBUG1(fmt, a1) \ 55 debug(fmt, (uintptr_t)(a1), 0, 0, 0, 0); 56 #define DEBUG2(fmt, a1, a2) \ 57 debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), 0, 0, 0); 58 #define DEBUG3(fmt, a1, a2, a3) \ 59 debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), (uintptr_t)(a3), 0, 0); 60 #else 61 #define DEBUG0(fmt) 62 #define DEBUG1(fmt, a1) 63 #define DEBUG2(fmt, a1, a2) 64 #define DEBUG3(fmt, a1, a2, a3) 65 #endif 66 67 /* 68 * Definitions for the bus node registration list: 69 * 70 * The hot-plug service module maintains a linked list of items 71 * representing the device bus nodes that have been registered via 72 * hpc_nexus_register, or identified as candidates for registration 73 * by the bus argument to hpc_slot_register. 74 * 75 * The head of the linked listed is stored in hpc_bus_list_head. Insertions 76 * and removals from the list should be locked with mutex hpc_bus_mutex. 77 * 78 * Items in the list are allocated/freed with the macros hpc_alloc_bus_entry() 79 * and hpc_free_bus_entry(). 80 * 81 * Each item in the list contains the following fields: 82 * 83 * bus_dip - pointer to devinfo node of the registering bus 84 * 85 * bus_name - device path name of the bus (ie /pci@1f,4000) 86 * 87 * bus_callback - bus nexus driver callback function registered 88 * with the bus 89 * 90 * bus_registered - a boolean value which is true if the bus has 91 * been registered with hpc_nexus_register, false otherwise 92 * 93 * bus_mutex - mutex lock to be held while updating this list entry 94 * 95 * bus_slot_list - linked list of the slots registered for this 96 * bus node (see slot list details below) 97 * 98 * bus_thread - kernel thread for running slot event handlers for 99 * slots associated with this bus 100 * 101 * bus_thread_cv - condition variable for synchronization between 102 * the service routines and the thread for running slot 103 * event handlers 104 * 105 * bus_thread_exit - a boolean value used to instruct the thread 106 * for invoking the slot event handlers to exit 107 * 108 * bus_slot_event_list_head - the head of the linked list of instances 109 * of slot event handlers to be run 110 * handlers to be invoked 111 * 112 * bus_next - pointer to next list entry 113 */ 114 115 typedef struct hpc_bus_entry hpc_bus_entry_t; 116 typedef struct hpc_slot_entry hpc_slot_entry_t; 117 typedef struct hpc_event_entry hpc_event_entry_t; 118 119 struct hpc_event_entry { 120 hpc_slot_entry_t *slotp; 121 int event; 122 hpc_event_entry_t *next; 123 }; 124 125 #define hpc_alloc_event_entry() \ 126 (hpc_event_entry_t *)kmem_zalloc(sizeof (hpc_event_entry_t), KM_SLEEP) 127 128 #define hpc_free_event_entry(a) \ 129 kmem_free((a), sizeof (hpc_event_entry_t)) 130 131 struct hpc_bus_entry { 132 dev_info_t *bus_dip; 133 char bus_name[MAXPATHLEN + 1]; 134 boolean_t bus_registered; 135 kmutex_t bus_mutex; 136 int (* bus_callback)(dev_info_t *dip, hpc_slot_t hdl, 137 hpc_slot_info_t *slot_info, int slot_state); 138 hpc_slot_entry_t *bus_slot_list; 139 kthread_t *bus_thread; 140 kcondvar_t bus_thread_cv; 141 boolean_t bus_thread_exit; 142 hpc_event_entry_t *bus_slot_event_list_head; 143 hpc_bus_entry_t *bus_next; 144 }; 145 146 #define hpc_alloc_bus_entry() \ 147 (hpc_bus_entry_t *)kmem_zalloc(sizeof (hpc_bus_entry_t), KM_SLEEP) 148 149 #define hpc_free_bus_entry(a) \ 150 kmem_free((a), sizeof (hpc_bus_entry_t)) 151 152 153 /* 154 * Definitions for the per-bus node slot registration list: 155 * 156 * For each bus node in the bus list, the hot-plug service module maintains 157 * a doubly linked link list of items representing the slots that have been 158 * registered (by hot-plug controllers) for that bus. 159 * 160 * The head of the linked listed is stored in bus_slot_list field of the bus 161 * node. Insertions and removals from this list should locked with the mutex 162 * in the bus_mutex field of the bus node. 163 * 164 * Items in the list are allocated/freed with the macros hpc_alloc_slot_entry() 165 * and hpc_free_slot_entry(). 166 * 167 * Each item in the list contains the following fields: 168 * 169 * slot_handle - handle for slot (hpc_slot_t) 170 * 171 * slot_info - information registered with the slot (hpc_slot_info_t) 172 * 173 * slot_ops - ops vector registered with the slot (hpc_slot_ops_t) 174 * 175 * slot_ops_arg - argument to be passed to ops routines (caddr_t) 176 * 177 * slot_event_handler - handler registered for slot events 178 * 179 * slot_event_handler_arg - argument to be passed to event handler 180 * 181 * slot_event_mask - the set of events for which the event handler 182 * gets invoked 183 * 184 * slot_bus - pointer to bus node for the slot 185 * 186 * slot_hpc_dip - devinfo node pointer to the HPC driver instance 187 * that controls this slot 188 * 189 * slot_{prev,next} - point to {previous,next} node in the list 190 */ 191 192 struct hpc_slot_entry { 193 hpc_slot_t slot_handle; 194 hpc_slot_info_t slot_info; /* should be static & copied */ 195 hpc_slot_ops_t slot_ops; 196 caddr_t slot_ops_arg; 197 int (* slot_event_handler)(caddr_t, uint_t); 198 caddr_t slot_event_handler_arg; 199 uint_t slot_event_mask; 200 hpc_bus_entry_t *slot_bus; 201 dev_info_t *slot_hpc_dip; 202 hpc_slot_entry_t *slot_next, *slot_prev; 203 }; 204 205 #define hpc_alloc_slot_entry() \ 206 (hpc_slot_entry_t *)kmem_zalloc(sizeof (hpc_slot_entry_t), KM_SLEEP) 207 208 #define hpc_free_slot_entry(a) \ 209 kmem_free((a), sizeof (hpc_slot_entry_t)) 210 211 212 /* 213 * Definitions for slot registration callback table. 214 */ 215 216 typedef struct hpc_callback_entry hpc_callback_entry_t; 217 218 struct hpc_callback_entry { 219 int (* callback)(dev_info_t *dip, hpc_slot_t hdl, 220 hpc_slot_info_t *slot_info, int slot_state); 221 dev_info_t *dip; 222 hpc_slot_t hdl; 223 hpc_slot_info_t *slot_info; 224 int slot_state; 225 hpc_callback_entry_t *next; 226 }; 227 228 #define hpc_alloc_callback_entry() \ 229 (hpc_callback_entry_t *) \ 230 kmem_zalloc(sizeof (hpc_callback_entry_t), KM_SLEEP) 231 232 #define hpc_free_callback_entry(a) \ 233 kmem_free((a), sizeof (hpc_callback_entry_t)) 234 235 236 237 /* 238 * Mutex lock for bus registration table and table head. 239 */ 240 static kmutex_t hpc_bus_mutex; 241 static hpc_bus_entry_t *hpc_bus_list_head; 242 243 244 /* 245 * Forward function declarations. 246 */ 247 static hpc_bus_entry_t *hpc_find_bus_by_name(char *name); 248 static void hpc_slot_event_dispatcher(hpc_bus_entry_t *busp); 249 250 251 /* 252 * loadable module definitions: 253 */ 254 extern struct mod_ops mod_miscops; 255 256 static struct modlmisc modlmisc = { 257 &mod_miscops, /* Type of module */ 258 "hot-plug controller services v%I%" 259 }; 260 261 static struct modlinkage modlinkage = { 262 MODREV_1, (void *)&modlmisc, NULL 263 }; 264 265 int 266 _init(void) 267 { 268 int e; 269 270 mutex_init(&hpc_bus_mutex, NULL, MUTEX_DRIVER, NULL); 271 272 /* 273 * Install the module. 274 */ 275 e = mod_install(&modlinkage); 276 if (e != 0) { 277 mutex_destroy(&hpc_bus_mutex); 278 } 279 return (e); 280 } 281 282 int 283 _fini(void) 284 { 285 int e; 286 287 e = mod_remove(&modlinkage); 288 if (e == 0) { 289 mutex_destroy(&hpc_bus_mutex); 290 } 291 return (e); 292 } 293 294 int 295 _info(struct modinfo *modinfop) 296 { 297 return (mod_info(&modlinkage, modinfop)); 298 } 299 300 301 302 hpc_slot_ops_t * 303 hpc_alloc_slot_ops(int flag) 304 { 305 hpc_slot_ops_t *ops; 306 307 ops = (hpc_slot_ops_t *)kmem_zalloc(sizeof (hpc_slot_ops_t), flag); 308 return (ops); 309 } 310 311 312 void 313 hpc_free_slot_ops(hpc_slot_ops_t *ops) 314 { 315 kmem_free((void *)ops, sizeof (hpc_slot_ops_t)); 316 } 317 318 319 /*ARGSUSED2*/ 320 int 321 hpc_nexus_register_bus(dev_info_t *dip, 322 int (* callback)(dev_info_t *dip, hpc_slot_t hdl, 323 hpc_slot_info_t *slot_info, int slot_state), uint_t flags) 324 { 325 hpc_bus_entry_t *busp; 326 hpc_slot_entry_t *slotp; 327 char bus_path[MAXPATHLEN + 1]; 328 329 DEBUG2("hpc_nexus_register_bus: %s%d", 330 ddi_node_name(dip), ddi_get_instance(dip)); 331 mutex_enter(&hpc_bus_mutex); 332 (void) ddi_pathname(dip, bus_path); 333 busp = hpc_find_bus_by_name(bus_path); 334 if (busp == NULL) { 335 336 /* 337 * Initialize the new bus node and link it at the head 338 * of the bus list. 339 */ 340 DEBUG0("hpc_nexus_register_bus: not in bus list"); 341 busp = hpc_alloc_bus_entry(); 342 busp->bus_dip = dip; 343 busp->bus_registered = B_TRUE; 344 (void) strcpy(busp->bus_name, bus_path); 345 mutex_init(&busp->bus_mutex, NULL, MUTEX_DRIVER, NULL); 346 busp->bus_callback = callback; 347 busp->bus_slot_list = NULL; 348 busp->bus_next = hpc_bus_list_head; 349 hpc_bus_list_head = busp; 350 351 } else { 352 353 /* 354 * The bus is in the bus list but isn't registered yet. 355 * Mark it as registered, and run the registration callbacks 356 * for it slots. 357 */ 358 DEBUG0("hpc_nexus_register_bus: in list, but not registered"); 359 mutex_enter(&busp->bus_mutex); 360 if (busp->bus_registered == B_TRUE) { 361 mutex_exit(&busp->bus_mutex); 362 mutex_exit(&hpc_bus_mutex); 363 return (HPC_ERR_BUS_DUPLICATE); 364 } 365 busp->bus_dip = dip; 366 busp->bus_callback = callback; 367 busp->bus_registered = B_TRUE; 368 369 mutex_exit(&busp->bus_mutex); 370 mutex_exit(&hpc_bus_mutex); 371 if (callback) { 372 DEBUG0("hpc_nexus_register_bus: running callbacks"); 373 for (slotp = busp->bus_slot_list; slotp; 374 slotp = slotp->slot_next) { 375 (void) callback(dip, slotp, &slotp->slot_info, 376 HPC_SLOT_ONLINE); 377 } 378 } 379 return (HPC_SUCCESS); 380 } 381 mutex_exit(&hpc_bus_mutex); 382 return (HPC_SUCCESS); 383 } 384 385 386 int 387 hpc_nexus_unregister_bus(dev_info_t *dip) 388 { 389 hpc_bus_entry_t *busp, *busp_prev; 390 hpc_slot_entry_t *slotp; 391 392 /* 393 * Search the list for the bus node and remove it. 394 */ 395 DEBUG2("hpc_nexus_unregister_bus: %s%d", 396 ddi_node_name(dip), ddi_get_instance(dip)); 397 mutex_enter(&hpc_bus_mutex); 398 for (busp = hpc_bus_list_head; busp != NULL; busp_prev = busp, 399 busp = busp->bus_next) { 400 if (busp->bus_dip == dip) 401 break; 402 } 403 if (busp == NULL) { 404 mutex_exit(&hpc_bus_mutex); 405 return (HPC_ERR_BUS_NOTREGISTERED); 406 } 407 408 /* 409 * If the bus has slots, mark the bus as unregistered, otherwise 410 * remove the bus entry from the list. 411 */ 412 mutex_enter(&busp->bus_mutex); 413 if (busp->bus_slot_list == NULL) { 414 if (busp == hpc_bus_list_head) 415 hpc_bus_list_head = busp->bus_next; 416 else 417 busp_prev->bus_next = busp->bus_next; 418 mutex_exit(&busp->bus_mutex); 419 mutex_destroy(&busp->bus_mutex); 420 hpc_free_bus_entry(busp); 421 mutex_exit(&hpc_bus_mutex); 422 return (HPC_SUCCESS); 423 } 424 425 /* 426 * unregister event handlers for all the slots on this bus. 427 */ 428 for (slotp = busp->bus_slot_list; slotp != NULL; 429 slotp = slotp->slot_next) { 430 slotp->slot_event_handler = NULL; 431 slotp->slot_event_handler_arg = NULL; 432 } 433 busp->bus_registered = B_FALSE; 434 mutex_exit(&busp->bus_mutex); 435 mutex_exit(&hpc_bus_mutex); 436 return (HPC_SUCCESS); 437 } 438 439 440 /*ARGSUSED5*/ 441 int 442 hpc_slot_register(dev_info_t *hpc_dip, char *bus, hpc_slot_info_t *infop, 443 hpc_slot_t *handlep, hpc_slot_ops_t *opsp, 444 caddr_t ops_arg, uint_t flags) 445 { 446 hpc_bus_entry_t *busp; 447 hpc_slot_entry_t *slotp, *slot_list_head; 448 boolean_t run_callback = B_FALSE; 449 int (* callback)(dev_info_t *dip, hpc_slot_t hdl, 450 hpc_slot_info_t *slot_info, int slot_state); 451 dev_info_t *dip; 452 kthread_t *t; 453 454 /* 455 * Validate the arguments. 456 */ 457 DEBUG1("hpc_slot_register: %s", bus); 458 if (handlep == NULL || infop == NULL || opsp == NULL || hpc_dip == NULL) 459 return (HPC_ERR_INVALID); 460 461 /* 462 * The bus for the slot may or may not be in the bus list. If it's 463 * not, we create a node for the bus in the bus list and mark it as 464 * not registered. 465 */ 466 mutex_enter(&hpc_bus_mutex); 467 busp = hpc_find_bus_by_name(bus); 468 if (busp == NULL) { 469 470 /* 471 * Initialize the new bus node and link it at the 472 * head of the bus list. 473 */ 474 DEBUG1("hpc_slot_register: %s not in bus list", bus); 475 busp = hpc_alloc_bus_entry(); 476 busp->bus_registered = B_FALSE; 477 (void) strcpy(busp->bus_name, bus); 478 mutex_init(&busp->bus_mutex, NULL, MUTEX_DRIVER, NULL); 479 busp->bus_slot_list = NULL; 480 busp->bus_next = hpc_bus_list_head; 481 hpc_bus_list_head = busp; 482 483 } else { 484 if (busp->bus_registered == B_TRUE) { 485 run_callback = B_TRUE; 486 callback = busp->bus_callback; 487 dip = busp->bus_dip; 488 } 489 } 490 491 mutex_enter(&busp->bus_mutex); 492 slot_list_head = busp->bus_slot_list; 493 if (slot_list_head == NULL) { 494 495 /* 496 * The slot list was empty, so this is the first slot 497 * registered for the bus. Create a per-bus thread 498 * for running the slot event handlers. 499 */ 500 DEBUG0("hpc_slot_register: creating event callback thread"); 501 cv_init(&busp->bus_thread_cv, NULL, CV_DRIVER, NULL); 502 busp->bus_thread_exit = B_FALSE; 503 t = thread_create(NULL, 0, hpc_slot_event_dispatcher, 504 (caddr_t)busp, 0, &p0, TS_RUN, minclsyspri); 505 busp->bus_thread = t; 506 } 507 508 /* 509 * Create and initialize a new entry in the slot list for the bus. 510 */ 511 slotp = hpc_alloc_slot_entry(); 512 slotp->slot_handle = (hpc_slot_t)slotp; 513 slotp->slot_info = *infop; 514 slotp->slot_ops = *opsp; 515 slotp->slot_ops_arg = ops_arg; 516 slotp->slot_bus = busp; 517 slotp->slot_hpc_dip = hpc_dip; 518 slotp->slot_prev = NULL; 519 busp->bus_slot_list = slotp; 520 slotp->slot_next = slot_list_head; 521 if (slot_list_head != NULL) 522 slot_list_head->slot_prev = slotp; 523 mutex_exit(&busp->bus_mutex); 524 mutex_exit(&hpc_bus_mutex); 525 526 /* 527 * Return the handle to the caller prior to return to avoid recursion. 528 */ 529 *handlep = (hpc_slot_t)slotp; 530 531 /* 532 * If the bus was registered, we run the callback registered by 533 * the bus node. 534 */ 535 if (run_callback) { 536 DEBUG0("hpc_slot_register: running callback"); 537 538 (void) callback(dip, slotp, infop, HPC_SLOT_ONLINE); 539 } 540 541 /* 542 * Keep hpc driver in memory 543 */ 544 (void) ndi_hold_driver(hpc_dip); 545 546 return (HPC_SUCCESS); 547 } 548 549 550 int 551 hpc_slot_unregister(hpc_slot_t *handlep) 552 { 553 hpc_slot_entry_t *slotp; 554 hpc_bus_entry_t *busp, *busp_prev; 555 boolean_t run_callback; 556 int (* callback)(dev_info_t *dip, hpc_slot_t hdl, 557 hpc_slot_info_t *slot_info, int slot_state); 558 int r; 559 dev_info_t *dip; 560 char *bus_name; 561 562 DEBUG0("hpc_slot_unregister:"); 563 564 ASSERT(handlep != NULL); 565 566 /* validate the handle */ 567 slotp = (hpc_slot_entry_t *)*handlep; 568 if ((slotp == NULL) || slotp->slot_handle != *handlep) 569 return (HPC_ERR_INVALID); 570 571 /* 572 * Get the bus list entry from the slot to grap the mutex for 573 * the slot list of the bus. 574 */ 575 mutex_enter(&hpc_bus_mutex); 576 busp = slotp->slot_bus; 577 DEBUG2("hpc_slot_unregister: handlep=%x, slotp=%x", handlep, slotp); 578 if (busp == NULL) { 579 mutex_exit(&hpc_bus_mutex); 580 return (HPC_ERR_SLOT_NOTREGISTERED); 581 } 582 583 /* 584 * Determine if we need to run the slot offline callback and 585 * save the data necessary to do so. 586 */ 587 callback = busp->bus_callback; 588 run_callback = (busp->bus_registered == B_TRUE) && (callback != NULL); 589 dip = busp->bus_dip; 590 bus_name = busp->bus_name; 591 592 /* 593 * Run the slot offline callback if necessary. 594 */ 595 if (run_callback) { 596 mutex_exit(&hpc_bus_mutex); 597 DEBUG0("hpc_slot_unregister: running callback"); 598 r = callback(dip, (hpc_slot_t)slotp, &slotp->slot_info, 599 HPC_SLOT_OFFLINE); 600 DEBUG1("hpc_slot_unregister: callback returned %x", r); 601 if (r != HPC_SUCCESS) 602 return (HPC_ERR_FAILED); 603 mutex_enter(&hpc_bus_mutex); 604 } 605 606 /* 607 * Remove the slot from list and free the memory associated with it. 608 */ 609 mutex_enter(&busp->bus_mutex); 610 DEBUG1("hpc_slot_unregister: freeing slot, bus_slot_list=%x", 611 busp->bus_slot_list); 612 if (slotp->slot_prev != NULL) 613 slotp->slot_prev->slot_next = slotp->slot_next; 614 if (slotp->slot_next != NULL) 615 slotp->slot_next->slot_prev = slotp->slot_prev; 616 if (slotp == busp->bus_slot_list) 617 busp->bus_slot_list = slotp->slot_next; 618 619 /* 620 * Release hold from slot registration 621 */ 622 ndi_rele_driver(slotp->slot_hpc_dip); 623 624 /* Free the memory associated with the slot entry structure */ 625 hpc_free_slot_entry(slotp); 626 627 /* 628 * If the slot list is empty then stop the event handler thread. 629 */ 630 if (busp->bus_slot_list == NULL) { 631 DEBUG0("hpc_slot_unregister: stopping thread"); 632 busp->bus_thread_exit = B_TRUE; 633 cv_signal(&busp->bus_thread_cv); 634 DEBUG0("hpc_slot_unregister: waiting for thread to exit"); 635 cv_wait(&busp->bus_thread_cv, &busp->bus_mutex); 636 DEBUG0("hpc_slot_unregister: thread exit"); 637 cv_destroy(&busp->bus_thread_cv); 638 } 639 640 /* 641 * If the bus is unregistered and this is the last slot for this bus 642 * then remove the entry from the bus list. 643 */ 644 if (busp->bus_registered == B_FALSE && busp->bus_slot_list == NULL) { 645 /* locate the previous entry in the bus list */ 646 for (busp = hpc_bus_list_head; busp != NULL; busp_prev = busp, 647 busp = busp->bus_next) 648 if (strcmp(bus_name, busp->bus_name) == 0) 649 break; 650 651 if (busp == hpc_bus_list_head) 652 hpc_bus_list_head = busp->bus_next; 653 else 654 busp_prev->bus_next = busp->bus_next; 655 656 mutex_exit(&busp->bus_mutex); 657 mutex_destroy(&busp->bus_mutex); 658 hpc_free_bus_entry(busp); 659 } else 660 mutex_exit(&busp->bus_mutex); 661 mutex_exit(&hpc_bus_mutex); 662 663 /* 664 * reset the slot handle. 665 */ 666 *handlep = NULL; 667 return (HPC_SUCCESS); 668 } 669 670 671 int 672 hpc_install_event_handler(hpc_slot_t handle, uint_t event_mask, 673 int (*event_handler)(caddr_t, uint_t), caddr_t arg) 674 { 675 hpc_slot_entry_t *slotp; 676 hpc_bus_entry_t *busp; 677 678 DEBUG3("hpc_install_event_handler: handle=%x, mask=%x, arg=%x", 679 handle, event_mask, arg); 680 ASSERT((handle != NULL) && (event_handler != NULL)); 681 slotp = (hpc_slot_entry_t *)handle; 682 busp = slotp->slot_bus; 683 ASSERT(slotp == slotp->slot_handle); 684 mutex_enter(&busp->bus_mutex); 685 slotp->slot_event_mask = event_mask; 686 slotp->slot_event_handler = event_handler; 687 slotp->slot_event_handler_arg = arg; 688 mutex_exit(&busp->bus_mutex); 689 return (HPC_SUCCESS); 690 } 691 692 693 int 694 hpc_remove_event_handler(hpc_slot_t handle) 695 { 696 hpc_slot_entry_t *slotp; 697 hpc_bus_entry_t *busp; 698 699 DEBUG1("hpc_remove_event_handler: handle=%x", handle); 700 ASSERT(handle != NULL); 701 slotp = (hpc_slot_entry_t *)handle; 702 ASSERT(slotp == slotp->slot_handle); 703 busp = slotp->slot_bus; 704 mutex_enter(&busp->bus_mutex); 705 slotp->slot_event_mask = 0; 706 slotp->slot_event_handler = NULL; 707 slotp->slot_event_handler_arg = NULL; 708 mutex_exit(&busp->bus_mutex); 709 return (HPC_SUCCESS); 710 } 711 712 713 /*ARGSUSED2*/ 714 int 715 hpc_slot_event_notify(hpc_slot_t handle, uint_t event, uint_t flags) 716 { 717 hpc_slot_entry_t *slotp; 718 hpc_bus_entry_t *busp; 719 hpc_event_entry_t *eventp; 720 721 DEBUG2("hpc_slot_event_notify: handle=%x event=%x", handle, event); 722 ASSERT(handle != NULL); 723 slotp = (hpc_slot_entry_t *)handle; 724 ASSERT(slotp == slotp->slot_handle); 725 726 if (slotp->slot_event_handler == NULL) 727 return (HPC_EVENT_UNCLAIMED); 728 729 /* 730 * If the request is to handle the event synchronously, then call 731 * the event handler without queuing the event. 732 */ 733 if (flags == HPC_EVENT_SYNCHRONOUS) { 734 caddr_t arg; 735 int (* func)(caddr_t, uint_t); 736 737 func = slotp->slot_event_handler; 738 arg = slotp->slot_event_handler_arg; 739 return (func(arg, event)); 740 } 741 /* 742 * Insert the event into the bus slot event handler list and 743 * signal the bus slot event handler dispatch thread. 744 */ 745 busp = slotp->slot_bus; 746 mutex_enter(&busp->bus_mutex); 747 748 if (busp->bus_slot_event_list_head == NULL) { 749 eventp = busp->bus_slot_event_list_head = 750 hpc_alloc_event_entry(); 751 } else { 752 for (eventp = busp->bus_slot_event_list_head; 753 eventp->next != NULL; eventp = eventp->next) 754 ; 755 eventp->next = hpc_alloc_event_entry(); 756 eventp = eventp->next; 757 } 758 eventp->slotp = slotp; 759 eventp->event = event; 760 eventp->next = NULL; 761 DEBUG2("hpc_slot_event_notify: busp=%x event=%x", busp, event); 762 cv_signal(&busp->bus_thread_cv); 763 mutex_exit(&busp->bus_mutex); 764 return (HPC_EVENT_CLAIMED); 765 } 766 767 768 int 769 hpc_nexus_connect(hpc_slot_t handle, void *data, uint_t flags) 770 { 771 hpc_slot_entry_t *slotp; 772 773 ASSERT(handle != NULL); 774 slotp = (hpc_slot_entry_t *)handle; 775 if (slotp->slot_ops.hpc_op_connect) 776 return (slotp->slot_ops.hpc_op_connect(slotp->slot_ops_arg, 777 handle, data, flags)); 778 return (HPC_ERR_FAILED); 779 } 780 781 782 int 783 hpc_nexus_disconnect(hpc_slot_t handle, void *data, uint_t flags) 784 { 785 hpc_slot_entry_t *slotp; 786 787 ASSERT(handle != NULL); 788 slotp = (hpc_slot_entry_t *)handle; 789 if (slotp->slot_ops.hpc_op_disconnect) 790 return (slotp->slot_ops.hpc_op_disconnect(slotp->slot_ops_arg, 791 handle, data, flags)); 792 return (HPC_ERR_FAILED); 793 } 794 795 796 int 797 hpc_nexus_insert(hpc_slot_t handle, void *data, uint_t flags) 798 { 799 hpc_slot_entry_t *slotp; 800 801 ASSERT(handle != NULL); 802 slotp = (hpc_slot_entry_t *)handle; 803 if (slotp->slot_ops.hpc_op_insert) 804 return (slotp->slot_ops.hpc_op_insert(slotp->slot_ops_arg, 805 handle, data, flags)); 806 return (HPC_ERR_FAILED); 807 } 808 809 810 int 811 hpc_nexus_remove(hpc_slot_t handle, void *data, uint_t flags) 812 { 813 hpc_slot_entry_t *slotp; 814 815 ASSERT(handle != NULL); 816 slotp = (hpc_slot_entry_t *)handle; 817 if (slotp->slot_ops.hpc_op_remove) 818 return (slotp->slot_ops.hpc_op_remove(slotp->slot_ops_arg, 819 handle, data, flags)); 820 return (HPC_ERR_FAILED); 821 } 822 823 824 int 825 hpc_nexus_control(hpc_slot_t handle, int request, caddr_t arg) 826 { 827 hpc_slot_entry_t *slotp; 828 829 ASSERT(handle != NULL); 830 slotp = (hpc_slot_entry_t *)handle; 831 if (slotp->slot_ops.hpc_op_control) 832 return (slotp->slot_ops.hpc_op_control(slotp->slot_ops_arg, 833 handle, request, arg)); 834 return (HPC_ERR_FAILED); 835 } 836 837 /* 838 * The following function is run from the bus entries slot event handling 839 * thread. 840 */ 841 static void 842 hpc_slot_event_dispatcher(hpc_bus_entry_t *busp) 843 { 844 hpc_event_entry_t *eventp; 845 hpc_slot_entry_t *slotp; 846 int event; 847 caddr_t arg; 848 int (* func)(caddr_t, uint_t); 849 callb_cpr_t cprinfo; 850 851 /* 852 * The creator of this thread is waiting to be signaled that 853 * the thread has been started. 854 */ 855 DEBUG1("hpc_slot_event_dispatcher: busp=%x", busp); 856 857 CALLB_CPR_INIT(&cprinfo, &busp->bus_mutex, callb_generic_cpr, 858 "hpc_slot_event_dispatcher"); 859 860 mutex_enter(&busp->bus_mutex); 861 /* 862 * Wait for events to queue and then process them. 863 */ 864 for (;;) { 865 866 /* 867 * Note we only hold the mutex while determining 868 * the number of entries that have been added to 869 * the event list, while updating the event list 870 * after processing the event list entries. 871 */ 872 if (busp->bus_slot_event_list_head == NULL) { 873 CALLB_CPR_SAFE_BEGIN(&cprinfo); 874 cv_wait(&busp->bus_thread_cv, &busp->bus_mutex); 875 CALLB_CPR_SAFE_END(&cprinfo, &busp->bus_mutex); 876 if (busp->bus_thread_exit) 877 break; 878 continue; 879 } 880 881 /* 882 * We have an event handler instance in the list to 883 * process. Remove the head of the list, saving the 884 * information required to run the event handler. 885 * Then run the event handler while the bus mutex 886 * is released. 887 */ 888 eventp = busp->bus_slot_event_list_head; 889 slotp = eventp->slotp; 890 event = eventp->event; 891 func = slotp->slot_event_handler; 892 arg = slotp->slot_event_handler_arg; 893 busp->bus_slot_event_list_head = eventp->next; 894 hpc_free_event_entry(eventp); 895 mutex_exit(&busp->bus_mutex); 896 func(arg, event); 897 mutex_enter(&busp->bus_mutex); 898 899 if (busp->bus_thread_exit) 900 break; 901 } 902 903 DEBUG0("hpc_slot_event_dispatcher: thread_exit"); 904 cv_signal(&busp->bus_thread_cv); 905 CALLB_CPR_EXIT(&cprinfo); 906 thread_exit(); 907 } 908 909 910 static hpc_bus_entry_t * 911 hpc_find_bus_by_name(char *path) 912 { 913 hpc_bus_entry_t *busp; 914 915 for (busp = hpc_bus_list_head; busp != NULL; busp = busp->bus_next) { 916 if (strcmp(path, busp->bus_name) == 0) 917 break; 918 } 919 return (busp); 920 } 921 922 boolean_t 923 hpc_bus_registered(hpc_slot_t slot_hdl) 924 { 925 hpc_slot_entry_t *slotp; 926 hpc_bus_entry_t *busp; 927 928 slotp = (hpc_slot_entry_t *)slot_hdl; 929 busp = slotp->slot_bus; 930 return (busp->bus_registered); 931 } 932 933 934 #ifdef DEBUG 935 936 extern void prom_printf(const char *, ...); 937 938 static void 939 debug(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3, 940 uintptr_t a4, uintptr_t a5) 941 { 942 if (hpcsvc_debug != 0) { 943 cmn_err(CE_CONT, "hpcsvc: "); 944 cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5); 945 cmn_err(CE_CONT, "\n"); 946 } 947 } 948 #endif 949