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
_nsc_init_gen()64 _nsc_init_gen()
65 {
66 HZ = drv_usectohz(1000000);
67 }
68
69
70 void
nsc_decode_param(nsc_def_t * args,nsc_def_t * def,long * v)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
nsc_lbolt()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
nsc_time()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
nsc_node_up(int node)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
nsc_nodeid_data()135 nsc_nodeid_data()
136 {
137 int data;
138 return ((data = nsc_node_id()) == 0 ? 1 : data);
139 }
140
141
142 int
nsc_node_id(void)143 nsc_node_id(void)
144 {
145 return (ncall_self());
146 }
147
148 char *
nsc_node_name()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
_nsc_rmmap_init(nsc_rmmap_t * map,char * name,int nslot,size_t size,ulong_t offset)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
_nsc_rmmap_alloc(nsc_rmmap_t * map,char * name,size_t size,void (* alloc)())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
_nsc_rmmap_free(nsc_rmmap_t * map,char * name,nsc_mem_t * mp)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
_nsc_rmmap_size(nsc_rmmap_t * map,char * name)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
_nsc_rmmap_avail(nsc_rmmap_t * map)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
_nsc_rmmap_inuse(nsc_rmmap_t * map,ulong_t * offsetp,size_t * sizep)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
nsc_delay_sig(clock_t tics)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
nsc_sprintf(char * s,char * fmt,...)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
_nsc_sprint_dec(char ** sptr,int n,int zero,int len)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
_nsc_sprint_hex(char ** sptr,uint_t v,int up,int alt,int zero,int len)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 *
nsc_strdup(char * s)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
nsc_strfree(char * s)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
nsc_strmatch(char * s,char * pat)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
nsc_strhash(char * str)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
nsc_fatal()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
nsc_null()905 int nsc_null() { return (0); }
nsc_true()906 int nsc_true() { return (1); }
nsc_inval()907 int nsc_inval() { return (-1); }
nsc_ioerr()908 int nsc_ioerr() { return (EIO); }
909
910 /*ARGSUSED*/
911 int
nsc_commit_mem(void * src,void * dst,size_t len,nsc_mem_err_cb err_action)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
nsc_cm_errhdlr(void * src,void * dst,size_t len,int errval)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
_nsc_init_svc(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
_nsc_deinit_svc(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 *
nsc_register_svc(char * name,void (* service_fn)(intptr_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
nsc_unregister_svc(nsc_svc_t * svc)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
nsc_call_svc(nsc_svc_t * svc,intptr_t arg)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 }
1107