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 }