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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/cmn_err.h> 28 #include <sys/errno.h> 29 #include <sys/ksynch.h> 30 #include <sys/kmem.h> 31 #include <sys/ddi.h> 32 #include <sys/varargs.h> 33 #if defined(DEBUG) && !defined(DS_DDICT) 34 #include <sys/kobj.h> 35 #endif 36 37 #include <sys/ncall/ncall.h> 38 39 #define __NSC_GEN__ 40 #include "nsc_gen.h" 41 #include "nsc_mem.h" 42 #include "../nsctl.h" 43 #ifdef DS_DDICT 44 #include "../contract.h" 45 #endif 46 47 48 static kcondvar_t _nsc_delay_cv; 49 static kmutex_t _nsc_delay_mutex; 50 51 static nsc_service_t *_nsc_services; 52 static kmutex_t _nsc_svc_mutex; 53 54 static int _nsc_rmmap_inuse(nsc_rmmap_t *, ulong_t *, size_t *); 55 56 static void _nsc_sprint_dec(char **, int, int, int); 57 static void _nsc_sprint_hex(char **, unsigned int, int, int, int, int); 58 59 clock_t HZ; 60 61 extern nsc_rmhdr_t *_nsc_rmhdr_ptr; 62 63 void 64 _nsc_init_gen() 65 { 66 HZ = drv_usectohz(1000000); 67 } 68 69 70 void 71 nsc_decode_param(nsc_def_t *args, nsc_def_t *def, long *v) 72 { 73 nsc_def_t *dp; 74 75 for (; def && def->name; def++) { 76 for (dp = args; dp && dp->name; dp++) { 77 if (strcmp(dp->name, def->name) == 0) { 78 v[def->offset] = dp->value; 79 break; 80 } 81 } 82 83 if ((!dp || !dp->name) && !v[def->offset]) 84 v[def->offset] = def->value; 85 } 86 } 87 88 89 clock_t 90 nsc_lbolt() 91 { 92 #ifdef _SunOS_5_6 93 clock_t lbolt; 94 time_t time; 95 96 if (drv_getparm(LBOLT, &lbolt) == 0) 97 return (lbolt); 98 99 if (drv_getparm(TIME, &time) != 0) 100 return ((clock_t)0); 101 102 time %= (60 * 60 * 24 * 365); 103 104 return (clock_t)(time * HZ); 105 #else 106 return (ddi_get_lbolt()); 107 #endif 108 } 109 110 111 time_t 112 nsc_time() 113 { 114 time_t time; 115 116 if (drv_getparm(TIME, &time) != 0) 117 return ((time_t)0); 118 119 return (time); 120 } 121 122 123 int 124 nsc_node_up(int node) 125 { 126 return (node == ncall_self()); 127 } 128 129 130 131 /* 132 * HACK increment nodeid in data parameter 133 */ 134 int 135 nsc_nodeid_data() 136 { 137 int data; 138 return ((data = nsc_node_id()) == 0 ? 1 : data); 139 } 140 141 142 int 143 nsc_node_id(void) 144 { 145 return (ncall_self()); 146 } 147 148 char * 149 nsc_node_name() 150 { 151 return (ncall_nodename(ncall_self())); 152 } 153 154 155 /* 156 * int 157 * _nsc_rmmap_init (nsc_rmmap_t *map, char *name, int nslot, 158 * size_t size, ulong_t offset) 159 * Initialise a global resource map. 160 * 161 * Calling/Exit State: 162 * Returns TRUE if the map was successfully created. Otherwise 163 * returns FALSE. 164 * 165 * Description: 166 * Initialises a global resource map. If the map already exists 167 * the arguments are validated against it. 168 */ 169 int 170 _nsc_rmmap_init(nsc_rmmap_t *map, char *name, 171 int nslot, size_t size, ulong_t offset) 172 { 173 nsc_rmmap_t *nvmap = NULL; 174 175 if (!size) 176 return (0); 177 178 mutex_enter(&_nsc_global_lock); 179 180 if (_nsc_rm_nvmem_base) 181 nvmap = _nsc_global_nvmemmap_lookup(map); 182 183 if (!map->size) 184 map->size = size; 185 if (!map->inuse) 186 map->inuse = nslot; 187 if (!map->offset) 188 map->offset = offset; 189 190 if (!map->name[0]) 191 (void) strncpy(map->name, name, _NSC_MAXNAME); 192 193 /* actually we only need to do this if an update occurred above */ 194 if (nvmap) { 195 (void) nsc_commit_mem(map, nvmap, 196 sizeof (nsc_rmmap_t), nsc_cm_errhdlr); 197 } 198 199 if (strncmp(map->name, name, _NSC_MAXNAME) || 200 (uint32_t)size != map->size || (int32_t)offset != map->offset) { 201 mutex_exit(&_nsc_global_lock); 202 return (0); 203 } 204 205 mutex_exit(&_nsc_global_lock); 206 return (1); 207 } 208 209 210 /* 211 * ulong_t 212 * _nsc_rmmap_alloc (nsc_rmmap_t *map, char *name, 213 * size_t size, void (*alloc)()) 214 * Allocate entry in a global resource map. 215 * 216 * Calling/Exit State: 217 * On success, returns the base of the allocated area. Otherwise, 218 * returns NULL. The function 'alloc' will be called if the 219 * allocated area is not currently in use. 220 * 221 * Description: 222 * Allocates an entry in the global resource map. If the entry 223 * already exists but is a different size an error is returned. 224 */ 225 ulong_t 226 _nsc_rmmap_alloc(nsc_rmmap_t *map, char *name, size_t size, void (*alloc)()) 227 { 228 int i, nslot = map[0].inuse; 229 size_t want = size; 230 ulong_t offset; 231 nsc_rmmap_t *nvmap = NULL; 232 233 if (!size) 234 return (0); 235 236 mutex_enter(&_nsc_global_lock); 237 if (_nsc_rm_nvmem_base) 238 nvmap = _nsc_global_nvmemmap_lookup(map); 239 240 for (i = 1; i < nslot; i++) { 241 if (!map[i].inuse || !map[i].size) 242 continue; 243 if (strncmp(map[i].name, name, _NSC_MAXNAME)) 244 continue; 245 if ((uint32_t)size == map[i].size) { 246 map[i].inuse |= (1 << nsc_node_id()); 247 if (nvmap) { 248 (void) nsc_commit_mem(&map[i], &nvmap[i], 249 sizeof (nsc_rmmap_t), nsc_cm_errhdlr); 250 } 251 mutex_exit(&_nsc_global_lock); 252 return (map[i].offset); 253 } 254 255 mutex_exit(&_nsc_global_lock); 256 return (0); 257 } 258 259 offset = map[0].offset; 260 261 while ((int32_t)offset < (map[0].offset + map[0].size)) { 262 if (_nsc_rmmap_inuse(map, &offset, &want)) 263 continue; 264 265 if (size > want) { 266 offset += want; 267 want = size; 268 continue; 269 } 270 271 for (i = 1; i < nslot; i++) 272 if (!map[i].inuse || !map[i].size) 273 break; 274 275 if (i == nslot) 276 break; 277 278 bzero(&map[i], sizeof (map[i])); 279 (void) strncpy(map[i].name, name, _NSC_MAXNAME); 280 281 map[i].size = size; 282 map[i].offset = offset; 283 map[i].inuse = (1 << nsc_node_id()); 284 if (nvmap) { /* update the map and hdr dirty bit. */ 285 (void) nsc_commit_mem(&map[i], &nvmap[i], 286 sizeof (nsc_rmmap_t), nsc_cm_errhdlr); 287 } 288 289 if (alloc) 290 (*alloc)(offset, size); 291 292 mutex_exit(&_nsc_global_lock); 293 return (offset); 294 } 295 296 mutex_exit(&_nsc_global_lock); 297 return (0); 298 } 299 300 301 /* 302 * void 303 * _nsc_rmmap_free (nsc_rmmap_t *map, char *name) 304 * Free entry in a global resource map. 305 * 306 * Description: 307 * Frees an entry in the global resource map. 308 */ 309 void 310 _nsc_rmmap_free(nsc_rmmap_t *map, char *name, nsc_mem_t *mp) 311 { 312 int i, nslot = map[0].inuse; 313 nsc_rmmap_t *nvmap = NULL; 314 315 mutex_enter(&_nsc_global_lock); 316 if (_nsc_rm_nvmem_base) 317 nvmap = _nsc_global_nvmemmap_lookup(map); 318 319 for (i = 1; i < nslot; i++) { 320 if (!map[i].inuse || !map[i].size) 321 continue; 322 if (strncmp(map[i].name, name, _NSC_MAXNAME)) 323 continue; 324 325 map[i].inuse &= ~(1 << nsc_node_id()); 326 if (nvmap) { 327 /* 328 * if dirty, set the inuse bit so this area 329 * will not be _nsc_global_zero'd on restart. 330 */ 331 if (mp && (mp->type & NSC_MEM_NVDIRTY)) { 332 map[i].inuse |= (1 << nsc_node_id()); 333 } 334 335 (void) nsc_commit_mem(&map[i], &nvmap[i], 336 sizeof (nsc_rmmap_t), nsc_cm_errhdlr); 337 } 338 mutex_exit(&_nsc_global_lock); 339 return; 340 } 341 342 mutex_exit(&_nsc_global_lock); 343 344 cmn_err(CE_WARN, "!nsctl: _nsc_rmmap_free: invalid free"); 345 } 346 347 348 /* 349 * size_t 350 * _nsc_rmmap_size (nsc_rmmap_t *map, char *name) 351 * Find size of area in map. 352 * 353 * Calling/Exit State: 354 * Returns the size of the specified area in the map, 355 * or 0 if it is currently unallocated. 356 */ 357 size_t 358 _nsc_rmmap_size(nsc_rmmap_t *map, char *name) 359 { 360 int i, nslot = map[0].inuse; 361 size_t size = 0; 362 363 mutex_enter(&_nsc_global_lock); 364 365 for (i = 1; i < nslot; i++) { 366 if (!map[i].inuse || !map[i].size) 367 continue; 368 369 if (strncmp(map[i].name, name, _NSC_MAXNAME) == 0) { 370 size = map[i].size; 371 break; 372 } 373 } 374 375 mutex_exit(&_nsc_global_lock); 376 return (size); 377 } 378 379 380 /* 381 * size_t 382 * _nsc_rmmap_avail (nsc_rmmap_t *map) 383 * Find available space in global resource map. 384 * 385 * Calling/Exit State: 386 * Returns the size of the largest available area in 387 * the global resource map. 388 */ 389 size_t 390 _nsc_rmmap_avail(nsc_rmmap_t *map) 391 { 392 size_t size, avail = 0; 393 ulong_t offset; 394 395 mutex_enter(&_nsc_global_lock); 396 397 size = 1; 398 offset = map[0].offset; 399 400 while ((int32_t)offset < (map[0].offset + map[0].size)) 401 if (!_nsc_rmmap_inuse(map, &offset, &size)) { 402 if (size > avail) 403 avail = size; 404 offset += size; 405 size = 1; 406 } 407 408 mutex_exit(&_nsc_global_lock); 409 return (avail); 410 } 411 412 413 /* 414 * static int 415 * _nsc_rmmap_inuse (nsc_rmmap_t *map, ulong_t *offsetp, size_t *sizep) 416 * Check if a section of the map is in use. 417 * 418 * Calling/Exit State: 419 * The global lock must be held across calls to the function. 420 * 421 * Returns TRUE if the specified area is currently in use and 422 * updates offset to point just past the section that was found 423 * to be in use. 424 * 425 * Otherwise, returns FALSE and updates size to reflect the 426 * amount of free space at the specified offset. 427 * 428 * Description: 429 * Checks the specified global map to determine if any part 430 * of the area is in use. 431 */ 432 static int 433 _nsc_rmmap_inuse(nsc_rmmap_t *map, ulong_t *offsetp, size_t *sizep) 434 { 435 size_t avail, size = (*sizep); 436 ulong_t offset = (*offsetp); 437 int i, nslot; 438 439 nslot = map[0].inuse; 440 avail = map[0].offset + map[0].size - offset; 441 442 for (i = 1; i < nslot; i++) { 443 if (!map[i].size || !map[i].inuse) 444 continue; 445 if ((int32_t)(offset + size) > map[i].offset && 446 (int32_t)offset < (map[i].offset + map[i].size)) { 447 (*offsetp) = map[i].offset + map[i].size; 448 return (1); 449 } 450 451 if (map[i].offset >= (int32_t)offset) 452 if (avail > map[i].offset - offset) 453 avail = map[i].offset - offset; 454 } 455 456 (*sizep) = avail; 457 return (0); 458 } 459 460 /* 461 * int 462 * nsc_delay_sig (clock_t tics) 463 * Delay for a number of clock ticks. 464 * 465 * Calling/Exit State: 466 * Returns FALSE if the delay was interrupted by a 467 * signal, TRUE otherwise. 468 * 469 * Description: 470 * Delays execution for the specified number of ticks 471 * or until a signal is received. 472 */ 473 int 474 nsc_delay_sig(clock_t tics) 475 { 476 clock_t target, remain, rc; 477 478 target = nsc_lbolt() + tics; 479 rc = 1; 480 481 mutex_enter(&_nsc_delay_mutex); 482 483 /* CONSTCOND */ 484 485 while (1) { 486 remain = target - nsc_lbolt(); 487 488 if (remain <= 0 || rc == -1) { 489 /* timeout */ 490 break; 491 } 492 493 rc = cv_timedwait_sig(&_nsc_delay_cv, 494 &_nsc_delay_mutex, target); 495 496 if (rc == 0) { 497 /* signalled */ 498 mutex_exit(&_nsc_delay_mutex); 499 return (FALSE); 500 } 501 } 502 503 mutex_exit(&_nsc_delay_mutex); 504 505 return (TRUE); 506 } 507 508 509 /* 510 * void 511 * nsc_sprintf (char *s, char *fmt, ...) 512 * String printf. 513 * 514 * Calling/Exit State: 515 * Builds a NULL terminated string in the buffer 516 * pointed to by 's', using the format 'fmt'. 517 * 518 * Description: 519 * Simple version of sprintf supporting fairly 520 * basic formats. 521 */ 522 523 /* PRINTFLIKE2 */ 524 525 void 526 nsc_sprintf(char *s, char *fmt, ...) 527 { 528 int alt, zero, len; 529 char c, *cp; 530 va_list p; 531 532 va_start(p, fmt); 533 534 /* CONSTCOND */ 535 536 while (1) { 537 alt = 0, zero = 0, len = 0; 538 539 if ((c = *fmt++) != '%') { 540 if (!c) 541 break; 542 *s++ = c; 543 continue; 544 } 545 546 if ((c = *fmt++) == 0) { 547 *s++ = '%'; 548 break; 549 } 550 551 alt = (c == '#'); 552 if (alt && !(c = *fmt++)) 553 break; 554 555 zero = (c == '0'); 556 if (zero && !(c = *fmt++)) 557 break; 558 559 while ((len ? '0' : '1') <= c && c <= '9') { 560 len = (len * 10) + (c - '0'); 561 if (!(c = *fmt++)) 562 break; 563 } 564 565 if (c == 's') { 566 cp = (char *)va_arg(p, caddr_t); 567 while (*cp) 568 *s++ = *cp++; 569 continue; 570 } 571 572 if (c == 'd' || c == 'u') { 573 _nsc_sprint_dec(&s, va_arg(p, int), zero, len); 574 continue; 575 } 576 577 if (c == 'x' || c == 'X') { 578 _nsc_sprint_hex(&s, va_arg(p, uint_t), 579 (c == 'X'), alt, zero, len); 580 continue; 581 } 582 583 *s++ = '%'; 584 if (alt) 585 *s++ = '#'; 586 if (zero) 587 *s++ = '0'; 588 589 if (len) 590 _nsc_sprint_dec(&s, len, 0, 0); 591 *s++ = c; 592 } 593 594 if (alt || zero || len) { 595 *s++ = '%'; 596 597 if (alt) 598 *s++ = '#'; 599 if (zero) 600 *s++ = '0'; 601 602 if (len) 603 _nsc_sprint_dec(&s, len, 0, 0); 604 } 605 606 va_end(p); 607 *s = 0; 608 } 609 610 611 /* 612 * static void 613 * _nsc_sprint_dec (char **sptr, int n, int zero, int len) 614 * Decimal to string conversion. 615 * 616 * Calling/Exit State: 617 * Stores a character representation of 'n' in the 618 * buffer referenced by 'sptr' and updates the pointer 619 * accordingly. 620 * 621 * Description: 622 * Generates a string representation of a signed decimal 623 * integer. 624 */ 625 626 static void 627 _nsc_sprint_dec(char **sptr, int n, int zero, int len) 628 { 629 unsigned int v = (n < 0) ? (-n) : n; 630 char c[20]; 631 int i; 632 633 for (i = 0; v; i++) { 634 c[i] = (v % 10) + '0'; 635 v /= 10; 636 } 637 638 len -= (i ? i : 1); 639 640 if (n < 0 && !zero) 641 for (len--; len > 0; len--) 642 *(*sptr)++ = ' '; 643 644 if (n < 0) { 645 *(*sptr)++ = '-'; 646 len--; 647 } 648 649 for (; len > 0; len--) 650 *(*sptr)++ = (zero ? '0' : ' '); 651 652 if (!i) 653 *(*sptr)++ = '0'; 654 655 while (i--) 656 *(*sptr)++ = c[i]; 657 } 658 659 660 /* 661 * static void 662 * _nsc_sprint_hex (char **sptr, unsigned int v, 663 * int up, int alt, int zero, int len) 664 * Hexadecimal to string conversion. 665 * 666 * Calling/Exit State: 667 * Stores a character representation of 'v' in the 668 * buffer referenced by 'sptr' and updates the pointer 669 * accordingly. 670 * 671 * Description: 672 * Generates a string representation of an unsigned 673 * hexadecimal integer. 674 */ 675 676 static void 677 _nsc_sprint_hex(char **sptr, uint_t v, int up, int alt, int zero, int len) 678 { 679 char *str = "0123456789abcdef"; 680 char c[20]; 681 int i; 682 683 if (up) 684 str = "0123456789ABCDEF"; 685 686 for (i = 0; v; i++) { 687 c[i] = str[(v % 16)]; 688 v /= 16; 689 } 690 691 if (alt) { 692 *(*sptr)++ = '0'; 693 *(*sptr)++ = (up ? 'X' : 'x'); 694 } 695 696 for (len -= (i ? i : 1); len > 0; len--) 697 *(*sptr)++ = (zero ? '0' : ' '); 698 699 if (!i) 700 *(*sptr)++ = '0'; 701 while (i--) 702 *(*sptr)++ = c[i]; 703 } 704 705 706 /* 707 * char * 708 * nsc_strdup (char *s) 709 * Duplicate string. 710 * 711 * Calling/Exit State: 712 * Returns the address of the new string. 713 * 714 * Description: 715 * Allocates a suitably sized area of memory and 716 * copies the string into it. The string should be 717 * free'd using nsc_strfree(). 718 */ 719 char * 720 nsc_strdup(char *s) 721 { 722 char *cp; 723 724 if (s == NULL) 725 return (NULL); 726 727 cp = nsc_kmem_alloc(strlen(s) + 1, KM_SLEEP, NULL); 728 (void) strcpy(cp, s); 729 return (cp); 730 } 731 732 733 /* 734 * void 735 * nsc_strfree (char *s) 736 * Free string. 737 * 738 * Description: 739 * Frees a string previously allocated by nsc_strdup. 740 */ 741 void 742 nsc_strfree(char *s) 743 { 744 if (s) 745 nsc_kmem_free(s, strlen(s) + 1); 746 } 747 748 749 /* 750 * int 751 * nsc_strmatch (char *s, char *pat) 752 * Match string against pattern. 753 * 754 * Calling/Exit State: 755 * Returns TRUE if the string matches against the 756 * pattern, FALSE otherwise. 757 * 758 * Description: 759 * Compares string against regular expression which 760 * can contain '*', '?' and '[]' constructs. 761 */ 762 int 763 nsc_strmatch(char *s, char *pat) 764 { 765 int neg; 766 767 for (; *pat; pat++, s++) { 768 if (*pat == '*') { 769 while (*pat == '*') 770 pat++; 771 772 if (!*pat) 773 return (1); 774 775 for (; *s; s++) 776 if (*pat == '[' || *pat == '?' || *pat == *s) 777 if (nsc_strmatch(s, pat)) 778 return (1); 779 return (0); 780 } 781 782 if (!*s) 783 return (0); 784 785 if (*pat == '[') { 786 if ((neg = (*++pat == '^')) != 0) 787 pat++; 788 789 while (*pat) { 790 if (*pat == *s) 791 break; 792 793 if (pat[1] == '-' && pat[2] != ']') { 794 if (*pat <= *s && *s <= pat[2]) 795 break; 796 pat += 2; 797 } 798 799 if (*++pat == ']') { 800 if (neg) 801 goto lp; 802 else 803 return (0); 804 } 805 } 806 807 while (*pat && *++pat != ']') 808 ; 809 810 if (!*pat || neg) 811 return (0); 812 lp: 813 continue; 814 } 815 816 if (*pat != '?' && *pat != *s) 817 return (0); 818 } 819 820 return (!*s); 821 } 822 823 824 /* 825 * uint64_t 826 * nsc_strhash(char *str) 827 * Calculate a simple hash for the specified string 828 * 829 * Calling/Exit State: 830 * Returns a simple hash of the NULL terminated string, str. 831 * 832 * Description: 833 */ 834 uint64_t 835 nsc_strhash(char *str) 836 { 837 uint64_t hash = (uint64_t)0; 838 839 if (str == NULL) 840 return (hash); 841 842 while (*str != '\0') { 843 hash <<= 1; 844 hash += (uint64_t)*str; 845 str++; 846 } 847 848 return (hash); 849 } 850 851 852 /* 853 * int 854 * nsc_fatal(void) 855 * Fatal error stub function 856 * 857 * Calling/Exit State: 858 * Returns EINVAL (non-DEBUG) or forces a panic. 859 * 860 * Description: 861 * This is a stub function suitable for default actions in 862 * nsctl i/o provider definitions. It should be used when 863 * calling the stub would be a programming error. The most 864 * common reason for nsc_fatal() being called is that an 865 * nsctl client module has called an nsc_fd_t i/o function 866 * without the fd already reserved. 867 * 868 * The function will display a diagnostic message and when 869 * built -DDEBUG will force a panic and display the textual 870 * name of the symbol closest to the caller address of this 871 * function. 872 */ 873 int 874 nsc_fatal() 875 { 876 void *caller = nsc_caller(); 877 #ifdef DEBUG 878 caddr_t caller_sym = NULL; 879 ulong_t offset = 0UL; 880 881 #ifndef DS_DDICT 882 caller_sym = kobj_getsymname((uintptr_t)caller, &offset); 883 #endif /* !DS_DDICT */ 884 885 cmn_err(CE_WARN, "!nsctl: nsc_fatal called at 0x%p (%s+0x%lx)", 886 caller, caller_sym ? caller_sym : "?", offset); 887 888 /* 889 * Force TRAP due to NULL pointer dereference 890 * - CE_PANIC can result in the stack trace being unreadable 891 * by (k)adb. 892 */ 893 *(int *)0 = 0x12345678; 894 895 #else /* !DEBUG */ 896 897 cmn_err(CE_WARN, "!nsctl: nsc_fatal called at 0x%p", caller); 898 899 #endif /* DEBUG */ 900 901 return (EINVAL); 902 } 903 904 905 int nsc_null() { return (0); } 906 int nsc_true() { return (1); } 907 int nsc_inval() { return (-1); } 908 int nsc_ioerr() { return (EIO); } 909 910 /*ARGSUSED*/ 911 int 912 nsc_commit_mem(void *src, void *dst, size_t len, nsc_mem_err_cb err_action) 913 { 914 915 return (0); 916 } 917 918 static int _nsc_nvmem_errs; 919 920 /* ARGSUSED */ 921 void 922 nsc_cm_errhdlr(void *src, void *dst, size_t len, int errval) 923 { 924 static int _nsc_baddma_already_seen = 0; 925 926 if (!(_nsc_baddma_already_seen % 100)) { 927 cmn_err(CE_WARN, "!nsc_cm_errhdlr: media down, forced_wrthru"); 928 929 _nsc_baddma_already_seen += 1; 930 931 if (_nsc_baddma_already_seen >= 100) { 932 cmn_err(CE_WARN, 933 "!nsc_cm_errhdlr: this message " 934 "displayed every 100 errors"); 935 } 936 } 937 938 (void) nsc_node_hints_set(NSC_FORCED_WRTHRU); 939 940 _nsc_nvmem_errs++; 941 } 942 943 944 void 945 _nsc_init_svc(void) 946 { 947 mutex_init(&_nsc_svc_mutex, NULL, MUTEX_DRIVER, NULL); 948 mutex_init(&_nsc_delay_mutex, NULL, MUTEX_DRIVER, NULL); 949 cv_init(&_nsc_delay_cv, NULL, CV_DRIVER, NULL); 950 } 951 952 953 void 954 _nsc_deinit_svc(void) 955 { 956 if (_nsc_services != NULL) { 957 cmn_err(CE_PANIC, 958 "nsctl: services registered in _nsc_deinit_svc"); 959 /* NOTREACHED */ 960 } 961 962 cv_destroy(&_nsc_delay_cv); 963 mutex_destroy(&_nsc_delay_mutex); 964 mutex_destroy(&_nsc_svc_mutex); 965 } 966 967 968 nsc_svc_t * 969 nsc_register_svc(char *name, void (*service_fn)(intptr_t)) 970 { 971 nsc_service_t *sp, *new; 972 nsc_svc_t *svc; 973 974 new = nsc_kmem_zalloc(sizeof (*new), KM_SLEEP, 0); 975 if (new == NULL) 976 return (NULL); 977 978 svc = nsc_kmem_zalloc(sizeof (*svc), KM_SLEEP, 0); 979 if (svc == NULL) { 980 nsc_kmem_free(new, sizeof (*new)); 981 return (NULL); 982 } 983 984 mutex_enter(&_nsc_svc_mutex); 985 986 for (sp = _nsc_services; sp != NULL; sp = sp->s_next) 987 if (strcmp(name, sp->s_name) == 0) 988 break; 989 990 if (sp == NULL) { 991 sp = new; 992 sp->s_name = nsc_strdup(name); 993 if (sp->s_name == NULL) { 994 mutex_exit(&_nsc_svc_mutex); 995 nsc_kmem_free(new, sizeof (*new)); 996 nsc_kmem_free(svc, sizeof (*svc)); 997 return (NULL); 998 } 999 1000 rw_init(&sp->s_rwlock, NULL, RW_DRIVER, NULL); 1001 sp->s_next = _nsc_services; 1002 _nsc_services = sp; 1003 } 1004 1005 rw_enter(&sp->s_rwlock, RW_WRITER); 1006 1007 svc->svc_fn = service_fn; 1008 svc->svc_svc = sp; 1009 1010 if (svc->svc_fn != NULL) { 1011 svc->svc_next = sp->s_servers; 1012 sp->s_servers = svc; 1013 } else { 1014 svc->svc_next = sp->s_clients; 1015 sp->s_clients = svc; 1016 } 1017 1018 rw_exit(&sp->s_rwlock); 1019 mutex_exit(&_nsc_svc_mutex); 1020 1021 if (sp != new) 1022 nsc_kmem_free(new, sizeof (*new)); 1023 1024 return (svc); 1025 } 1026 1027 1028 int 1029 nsc_unregister_svc(nsc_svc_t *svc) 1030 { 1031 nsc_service_t *sp, **spp; 1032 nsc_svc_t **svcp; 1033 1034 if (svc == NULL) 1035 return (EINVAL); 1036 1037 sp = svc->svc_svc; 1038 if (sp == NULL) 1039 return (EINVAL); 1040 1041 mutex_enter(&_nsc_svc_mutex); 1042 rw_enter(&sp->s_rwlock, RW_WRITER); 1043 1044 svcp = (svc->svc_fn == NULL) ? &sp->s_clients : &sp->s_servers; 1045 for (; *svcp; svcp = &((*svcp)->svc_next)) 1046 if (svc == (*svcp)) 1047 break; 1048 1049 if (*svcp) 1050 (*svcp) = svc->svc_next; 1051 1052 nsc_kmem_free(svc, sizeof (*svc)); 1053 1054 if (sp->s_servers == NULL && sp->s_clients == NULL) { 1055 for (spp = &_nsc_services; *spp; spp = &((*spp)->s_next)) 1056 if ((*spp) == sp) 1057 break; 1058 1059 if (*spp) 1060 (*spp) = sp->s_next; 1061 1062 rw_exit(&sp->s_rwlock); 1063 mutex_exit(&_nsc_svc_mutex); 1064 1065 rw_destroy(&sp->s_rwlock); 1066 nsc_strfree(sp->s_name); 1067 1068 nsc_kmem_free(sp, sizeof (*sp)); 1069 return (0); 1070 } 1071 1072 rw_exit(&sp->s_rwlock); 1073 mutex_exit(&_nsc_svc_mutex); 1074 1075 return (0); 1076 } 1077 1078 1079 int 1080 nsc_call_svc(nsc_svc_t *svc, intptr_t arg) 1081 { 1082 nsc_service_t *sp; 1083 nsc_svc_t *svcp; 1084 int found; 1085 1086 if (svc == NULL) 1087 return (EINVAL); 1088 1089 sp = svc->svc_svc; 1090 if (sp == NULL) 1091 return (EINVAL); 1092 1093 rw_enter(&sp->s_rwlock, RW_READER); 1094 1095 found = (sp->s_servers != NULL); 1096 1097 for (svcp = sp->s_servers; svcp; svcp = svcp->svc_next) 1098 (*svcp->svc_fn)(arg); 1099 1100 rw_exit(&sp->s_rwlock); 1101 1102 if (found == 0) 1103 return (ENOSYS); 1104 1105 return (0); 1106 }