xref: /titanic_52/usr/src/uts/common/avs/ns/nsctl/nsc_gen.c (revision 3270659f55e0928d6edec3d26217cc29398a8149)
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 }
1107