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 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <sys/types.h>
27 #include <sys/param.h>
28 #include <sys/modctl.h>
29 #include <sys/sysmacros.h>
30 #include <sys/kmem.h>
31 #include <sys/cmn_err.h>
32 #include <sys/ddi.h>
33 #include <sys/sunddi.h>
34 #include <sys/spl.h>
35 #include <sys/time.h>
36 #include <sys/varargs.h>
37 #include <ipp/ipp.h>
38 #include <ipp/ipp_impl.h>
39 #include <ipp/ipgpc/ipgpc.h>
40
41 /*
42 * Debug switch.
43 */
44
45 #if defined(DEBUG)
46 #define IPP_DBG
47 #endif
48
49 /*
50 * Globals
51 */
52
53 /*
54 * ipp_action_count is not static because it is imported by inet/ipp_common.h
55 */
56 uint32_t ipp_action_count = 0;
57
58 static kmem_cache_t *ipp_mod_cache = NULL;
59 static uint32_t ipp_mod_count = 0;
60 static uint32_t ipp_max_mod = IPP_NMOD;
61 static ipp_mod_t **ipp_mod_byid;
62 static krwlock_t ipp_mod_byid_lock[1];
63
64 static ipp_mod_id_t ipp_next_mid = IPP_MOD_RESERVED + 1;
65 static ipp_mod_id_t ipp_mid_limit;
66
67 static ipp_ref_t *ipp_mod_byname[IPP_NBUCKET];
68 static krwlock_t ipp_mod_byname_lock[1];
69
70 static kmem_cache_t *ipp_action_cache = NULL;
71 static uint32_t ipp_max_action = IPP_NACTION;
72 static ipp_action_t **ipp_action_byid;
73 static krwlock_t ipp_action_byid_lock[1];
74
75 static ipp_action_id_t ipp_next_aid = IPP_ACTION_RESERVED + 1;
76 static ipp_action_id_t ipp_aid_limit;
77
78 static ipp_ref_t *ipp_action_byname[IPP_NBUCKET];
79 static krwlock_t ipp_action_byname_lock[1];
80 static ipp_ref_t *ipp_action_noname;
81
82 static kmem_cache_t *ipp_packet_cache = NULL;
83 static uint_t ipp_packet_classes = IPP_NCLASS;
84 static uint_t ipp_packet_logging = 0;
85 static uint_t ipp_packet_log_entries = IPP_NLOG;
86
87 /*
88 * Prototypes
89 */
90
91 void ipp_init(void);
92
93 int ipp_list_mods(ipp_mod_id_t **, int *);
94
95 ipp_mod_id_t ipp_mod_lookup(const char *);
96 int ipp_mod_name(ipp_mod_id_t, char **);
97 int ipp_mod_register(const char *, ipp_ops_t *);
98 int ipp_mod_unregister(ipp_mod_id_t);
99 int ipp_mod_list_actions(ipp_mod_id_t, ipp_action_id_t **,
100 int *);
101
102 ipp_action_id_t ipp_action_lookup(const char *);
103 int ipp_action_name(ipp_action_id_t, char **);
104 int ipp_action_mod(ipp_action_id_t, ipp_mod_id_t *);
105 int ipp_action_create(ipp_mod_id_t, const char *,
106 nvlist_t **, ipp_flags_t, ipp_action_id_t *);
107 int ipp_action_modify(ipp_action_id_t, nvlist_t **,
108 ipp_flags_t);
109 int ipp_action_destroy(ipp_action_id_t, ipp_flags_t);
110 int ipp_action_info(ipp_action_id_t, int (*)(nvlist_t *,
111 void *), void *, ipp_flags_t);
112 void ipp_action_set_ptr(ipp_action_id_t, void *);
113 void *ipp_action_get_ptr(ipp_action_id_t);
114 int ipp_action_ref(ipp_action_id_t, ipp_action_id_t,
115 ipp_flags_t);
116 int ipp_action_unref(ipp_action_id_t, ipp_action_id_t,
117 ipp_flags_t);
118
119 int ipp_packet_alloc(ipp_packet_t **, const char *,
120 ipp_action_id_t);
121 void ipp_packet_free(ipp_packet_t *);
122 int ipp_packet_add_class(ipp_packet_t *, const char *,
123 ipp_action_id_t);
124 int ipp_packet_process(ipp_packet_t **);
125 int ipp_packet_next(ipp_packet_t *, ipp_action_id_t);
126 void ipp_packet_set_data(ipp_packet_t *, mblk_t *);
127 mblk_t *ipp_packet_get_data(ipp_packet_t *);
128 void ipp_packet_set_private(ipp_packet_t *, void *,
129 void (*)(void *));
130 void *ipp_packet_get_private(ipp_packet_t *);
131
132 int ipp_stat_create(ipp_action_id_t, const char *, int,
133 int (*)(ipp_stat_t *, void *, int), void *, ipp_stat_t **);
134 void ipp_stat_install(ipp_stat_t *);
135 void ipp_stat_destroy(ipp_stat_t *);
136 int ipp_stat_named_init(ipp_stat_t *, const char *, uchar_t,
137 ipp_named_t *);
138 int ipp_stat_named_op(ipp_named_t *, void *, int);
139
140 static int ref_mod(ipp_action_t *, ipp_mod_t *);
141 static void unref_mod(ipp_action_t *, ipp_mod_t *);
142 static int is_mod_busy(ipp_mod_t *);
143 static int get_mod_ref(ipp_mod_t *, ipp_action_id_t **, int *);
144 static int get_mods(ipp_mod_id_t **bufp, int *);
145 static ipp_mod_id_t find_mod(const char *);
146 static int alloc_mod(const char *, ipp_mod_id_t *);
147 static void free_mod(ipp_mod_t *);
148 static ipp_mod_t *hold_mod(ipp_mod_id_t);
149 static void rele_mod(ipp_mod_t *);
150 static ipp_mod_id_t get_mid(void);
151
152 static int condemn_action(ipp_ref_t **, ipp_action_t *);
153 static int destroy_action(ipp_action_t *, ipp_flags_t);
154 static int ref_action(ipp_action_t *, ipp_action_t *);
155 static int unref_action(ipp_action_t *, ipp_action_t *);
156 static int is_action_refd(ipp_action_t *);
157 static ipp_action_id_t find_action(const char *);
158 static int alloc_action(const char *, ipp_action_id_t *);
159 static void free_action(ipp_action_t *);
160 static ipp_action_t *hold_action(ipp_action_id_t);
161 static void rele_action(ipp_action_t *);
162 static ipp_action_id_t get_aid(void);
163
164 static int alloc_packet(const char *, ipp_action_id_t,
165 ipp_packet_t **);
166 static int realloc_packet(ipp_packet_t *);
167 static void free_packet(ipp_packet_t *);
168
169 static int hash(const char *);
170 static int update_stats(kstat_t *, int);
171 static void init_mods(void);
172 static void init_actions(void);
173 static void init_packets(void);
174 static int mod_constructor(void *, void *, int);
175 static void mod_destructor(void *, void *);
176 static int action_constructor(void *, void *, int);
177 static void action_destructor(void *, void *);
178 static int packet_constructor(void *, void *, int);
179 static void packet_destructor(void *, void *);
180
181 /*
182 * Debug message macros
183 */
184
185 #ifdef IPP_DBG
186
187 #define DBG_MOD 0x00000001ull
188 #define DBG_ACTION 0x00000002ull
189 #define DBG_PACKET 0x00000004ull
190 #define DBG_STATS 0x00000008ull
191 #define DBG_LIST 0x00000010ull
192
193 static uint64_t ipp_debug_flags =
194 /*
195 * DBG_PACKET |
196 * DBG_STATS |
197 * DBG_LIST |
198 * DBG_MOD |
199 * DBG_ACTION |
200 */
201 0;
202
203 static kmutex_t debug_mutex[1];
204
205 /*PRINTFLIKE3*/
206 static void ipp_debug(uint64_t, const char *, char *, ...)
207 __KPRINTFLIKE(3);
208
209 #define DBG0(_type, _fmt) \
210 ipp_debug((_type), __FN__, (_fmt));
211
212 #define DBG1(_type, _fmt, _a1) \
213 ipp_debug((_type), __FN__, (_fmt), (_a1));
214
215 #define DBG2(_type, _fmt, _a1, _a2) \
216 ipp_debug((_type), __FN__, (_fmt), (_a1), (_a2));
217
218 #define DBG3(_type, _fmt, _a1, _a2, _a3) \
219 ipp_debug((_type), __FN__, (_fmt), (_a1), (_a2), \
220 (_a3));
221
222 #define DBG4(_type, _fmt, _a1, _a2, _a3, _a4) \
223 ipp_debug((_type), __FN__, (_fmt), (_a1), (_a2), \
224 (_a3), (_a4));
225
226 #define DBG5(_type, _fmt, _a1, _a2, _a3, _a4, _a5) \
227 ipp_debug((_type), __FN__, (_fmt), (_a1), (_a2), \
228 (_a3), (_a4), (_a5));
229
230 #else /* IPP_DBG */
231
232 #define DBG0(_type, _fmt)
233 #define DBG1(_type, _fmt, _a1)
234 #define DBG2(_type, _fmt, _a1, _a2)
235 #define DBG3(_type, _fmt, _a1, _a2, _a3)
236 #define DBG4(_type, _fmt, _a1, _a2, _a3, _a4)
237 #define DBG5(_type, _fmt, _a1, _a2, _a3, _a4, _a5)
238
239 #endif /* IPP_DBG */
240
241 /*
242 * Lock macros
243 */
244
245 #define LOCK_MOD(_imp, _rw) \
246 rw_enter((_imp)->ippm_lock, (_rw))
247 #define UNLOCK_MOD(_imp) \
248 rw_exit((_imp)->ippm_lock)
249
250 #define LOCK_ACTION(_ap, _rw) \
251 rw_enter((_ap)->ippa_lock, (_rw))
252 #define UNLOCK_ACTION(_imp) \
253 rw_exit((_imp)->ippa_lock)
254
255 #define CONFIG_WRITE_START(_ap) \
256 CONFIG_LOCK_ENTER((_ap)->ippa_config_lock, CL_WRITE)
257
258 #define CONFIG_WRITE_END(_ap) \
259 CONFIG_LOCK_EXIT((_ap)->ippa_config_lock)
260
261 #define CONFIG_READ_START(_ap) \
262 CONFIG_LOCK_ENTER((_ap)->ippa_config_lock, CL_READ)
263
264 #define CONFIG_READ_END(_ap) \
265 CONFIG_LOCK_EXIT((_ap)->ippa_config_lock)
266
267 /*
268 * Exported functions
269 */
270
271 #define __FN__ "ipp_init"
272 void
ipp_init(void)273 ipp_init(
274 void)
275 {
276 #ifdef IPP_DBG
277 mutex_init(debug_mutex, NULL, MUTEX_ADAPTIVE,
278 (void *)ipltospl(LOCK_LEVEL));
279 #endif /* IPP_DBG */
280
281 /*
282 * Initialize module and action structure caches and associated locks.
283 */
284
285 init_mods();
286 init_actions();
287 init_packets();
288 }
289 #undef __FN__
290
291 #define __FN__ "ipp_list_mods"
292 int
ipp_list_mods(ipp_mod_id_t ** bufp,int * neltp)293 ipp_list_mods(
294 ipp_mod_id_t **bufp,
295 int *neltp)
296 {
297 ASSERT(bufp != NULL);
298 ASSERT(neltp != NULL);
299
300 return (get_mods(bufp, neltp));
301 }
302 #undef __FN__
303
304 /*
305 * Module manipulation interface.
306 */
307
308 #define __FN__ "ipp_mod_lookup"
309 ipp_mod_id_t
ipp_mod_lookup(const char * modname)310 ipp_mod_lookup(
311 const char *modname)
312 {
313 ipp_mod_id_t mid;
314 #define FIRST_TIME 0
315 int try = FIRST_TIME;
316
317 /*
318 * Sanity check the module name.
319 */
320
321 if (modname == NULL || strlen(modname) > MAXNAMELEN - 1)
322 return (IPP_MOD_INVAL);
323
324 try_again:
325 if ((mid = find_mod(modname)) == IPP_MOD_INVAL) {
326
327 /*
328 * Module not installed.
329 */
330
331 if (try++ == FIRST_TIME) {
332
333 /*
334 * This is the first attempt to find the module so
335 * try to 'demand load' it.
336 */
337
338 DBG1(DBG_MOD, "loading module '%s'\n", modname);
339 (void) modload("ipp", (char *)modname);
340 goto try_again;
341 }
342 }
343
344 return (mid);
345
346 #undef FIRST_TIME
347 }
348 #undef __FN__
349
350 #define __FN__ "ipp_mod_name"
351 int
ipp_mod_name(ipp_mod_id_t mid,char ** modnamep)352 ipp_mod_name(
353 ipp_mod_id_t mid,
354 char **modnamep)
355 {
356 ipp_mod_t *imp;
357 char *modname;
358 char *buf;
359
360 ASSERT(modnamep != NULL);
361
362 /*
363 * Translate the module id into the module pointer.
364 */
365
366 if ((imp = hold_mod(mid)) == NULL)
367 return (ENOENT);
368
369 LOCK_MOD(imp, RW_READER);
370 modname = imp->ippm_name;
371
372 /*
373 * Allocate a buffer to pass back to the caller.
374 */
375
376 if ((buf = kmem_zalloc(strlen(modname) + 1, KM_NOSLEEP)) == NULL) {
377 UNLOCK_MOD(imp);
378 rele_mod(imp);
379 return (ENOMEM);
380 }
381
382 /*
383 * Copy the module name into the buffer.
384 */
385
386 (void) strcpy(buf, modname);
387 UNLOCK_MOD(imp);
388
389 *modnamep = buf;
390
391 rele_mod(imp);
392 return (0);
393 }
394 #undef __FN__
395
396 #define __FN__ "ipp_mod_register"
397 int
ipp_mod_register(const char * modname,ipp_ops_t * ipp_ops)398 ipp_mod_register(
399 const char *modname,
400 ipp_ops_t *ipp_ops)
401 {
402 ipp_mod_id_t mid;
403 ipp_mod_t *imp;
404 int rc;
405
406 ASSERT(ipp_ops != NULL);
407
408 /*
409 * Sanity check the module name.
410 */
411
412 if (modname == NULL || strlen(modname) > MAXNAMELEN - 1)
413 return (EINVAL);
414
415 /*
416 * Allocate a module structure.
417 */
418
419 if ((rc = alloc_mod(modname, &mid)) != 0)
420 return (rc);
421
422 imp = hold_mod(mid);
423 ASSERT(imp != NULL);
424
425 /*
426 * Make module available for use.
427 */
428
429 LOCK_MOD(imp, RW_WRITER);
430 DBG1(DBG_MOD, "registering module '%s'\n", imp->ippm_name);
431 imp->ippm_ops = ipp_ops;
432 imp->ippm_state = IPP_MODSTATE_AVAILABLE;
433 UNLOCK_MOD(imp);
434
435 rele_mod(imp);
436 return (0);
437 }
438 #undef __FN__
439
440 #define __FN__ "ipp_mod_unregister"
441 int
ipp_mod_unregister(ipp_mod_id_t mid)442 ipp_mod_unregister(
443 ipp_mod_id_t mid)
444 {
445 ipp_mod_t *imp;
446
447 /*
448 * Translate the module id into the module pointer.
449 */
450
451 if ((imp = hold_mod(mid)) == NULL)
452 return (ENOENT);
453
454 LOCK_MOD(imp, RW_WRITER);
455 ASSERT(imp->ippm_state == IPP_MODSTATE_AVAILABLE);
456
457 /*
458 * Check to see if there are any actions that reference the module.
459 */
460
461 if (is_mod_busy(imp)) {
462 UNLOCK_MOD(imp);
463 rele_mod(imp);
464 return (EBUSY);
465 }
466
467 /*
468 * Prevent further use of the module.
469 */
470
471 DBG1(DBG_MOD, "unregistering module '%s'\n", imp->ippm_name);
472 imp->ippm_state = IPP_MODSTATE_PROTO;
473 imp->ippm_ops = NULL;
474 UNLOCK_MOD(imp);
475
476 /*
477 * Free the module structure.
478 */
479
480 free_mod(imp);
481 rele_mod(imp);
482
483 return (0);
484 }
485 #undef __FN__
486
487 #define __FN__ "ipp_mod_list_actions"
488 int
ipp_mod_list_actions(ipp_mod_id_t mid,ipp_action_id_t ** bufp,int * neltp)489 ipp_mod_list_actions(
490 ipp_mod_id_t mid,
491 ipp_action_id_t **bufp,
492 int *neltp)
493 {
494 ipp_mod_t *imp;
495 int rc;
496
497 ASSERT(bufp != NULL);
498 ASSERT(neltp != NULL);
499
500 /*
501 * Translate the module id into the module pointer.
502 */
503
504 if ((imp = hold_mod(mid)) == NULL)
505 return (ENOENT);
506
507 /*
508 * Get the list of actions referencing the module.
509 */
510
511 LOCK_MOD(imp, RW_READER);
512 rc = get_mod_ref(imp, bufp, neltp);
513 UNLOCK_MOD(imp);
514
515 rele_mod(imp);
516 return (rc);
517 }
518 #undef __FN__
519
520 /*
521 * Action manipulation interface.
522 */
523
524 #define __FN__ "ipp_action_lookup"
525 ipp_action_id_t
ipp_action_lookup(const char * aname)526 ipp_action_lookup(
527 const char *aname)
528 {
529 if (aname == NULL)
530 return (IPP_ACTION_INVAL);
531
532 /*
533 * Check for special case 'virtual action' names.
534 */
535
536 if (strcmp(aname, IPP_ANAME_CONT) == 0)
537 return (IPP_ACTION_CONT);
538 else if (strcmp(aname, IPP_ANAME_DEFER) == 0)
539 return (IPP_ACTION_DEFER);
540 else if (strcmp(aname, IPP_ANAME_DROP) == 0)
541 return (IPP_ACTION_DROP);
542
543 /*
544 * Now check real actions.
545 */
546
547 return (find_action(aname));
548 }
549 #undef __FN__
550
551 #define __FN__ "ipp_action_name"
552 int
ipp_action_name(ipp_action_id_t aid,char ** anamep)553 ipp_action_name(
554 ipp_action_id_t aid,
555 char **anamep)
556 {
557 ipp_action_t *ap;
558 char *aname;
559 char *buf;
560 int rc;
561
562 ASSERT(anamep != NULL);
563
564 /*
565 * Check for special case 'virtual action' ids.
566 */
567
568 switch (aid) {
569 case IPP_ACTION_CONT:
570 ap = NULL;
571 aname = IPP_ANAME_CONT;
572 break;
573 case IPP_ACTION_DEFER:
574 ap = NULL;
575 aname = IPP_ANAME_DEFER;
576 break;
577 case IPP_ACTION_DROP:
578 ap = NULL;
579 aname = IPP_ANAME_DROP;
580 break;
581 default:
582
583 /*
584 * Not a special case. Check for a real action.
585 */
586
587 if ((ap = hold_action(aid)) == NULL)
588 return (ENOENT);
589
590 LOCK_ACTION(ap, RW_READER);
591 aname = ap->ippa_name;
592 break;
593 }
594
595 /*
596 * Allocate a buffer to pass back to the caller.
597 */
598
599 if ((buf = kmem_zalloc(strlen(aname) + 1, KM_NOSLEEP)) == NULL) {
600 rc = ENOMEM;
601 goto done;
602 }
603
604 /*
605 * Copy the action name into the buffer.
606 */
607
608 (void) strcpy(buf, aname);
609 *anamep = buf;
610 rc = 0;
611 done:
612 /*
613 * Unlock the action if necessary (i.e. it wasn't a virtual action).
614 */
615
616 if (ap != NULL) {
617 UNLOCK_ACTION(ap);
618 rele_action(ap);
619 }
620
621 return (rc);
622 }
623 #undef __FN__
624
625 #define __FN__ "ipp_action_mod"
626 int
ipp_action_mod(ipp_action_id_t aid,ipp_mod_id_t * midp)627 ipp_action_mod(
628 ipp_action_id_t aid,
629 ipp_mod_id_t *midp)
630 {
631 ipp_action_t *ap;
632 ipp_mod_t *imp;
633
634 ASSERT(midp != NULL);
635
636 /*
637 * Return an error for 'virtual action' ids.
638 */
639
640 switch (aid) {
641 case IPP_ACTION_CONT:
642 /*FALLTHRU*/
643 case IPP_ACTION_DEFER:
644 /*FALLTHRU*/
645 case IPP_ACTION_DROP:
646 return (EINVAL);
647 default:
648 break;
649 }
650
651 /*
652 * This is a real action.
653 */
654
655 if ((ap = hold_action(aid)) == NULL)
656 return (ENOENT);
657
658 /*
659 * Check that the action is not in prototype state.
660 */
661
662 LOCK_ACTION(ap, RW_READER);
663 if (ap->ippa_state == IPP_ASTATE_PROTO) {
664 UNLOCK_ACTION(ap);
665 rele_action(ap);
666 return (ENOENT);
667 }
668
669 imp = ap->ippa_mod;
670 ASSERT(imp != NULL);
671 UNLOCK_ACTION(ap);
672
673 *midp = imp->ippm_id;
674
675 rele_action(ap);
676 return (0);
677 }
678 #undef __FN__
679
680 #define __FN__ "ipp_action_create"
681 int
ipp_action_create(ipp_mod_id_t mid,const char * aname,nvlist_t ** nvlpp,ipp_flags_t flags,ipp_action_id_t * aidp)682 ipp_action_create(
683 ipp_mod_id_t mid,
684 const char *aname,
685 nvlist_t **nvlpp,
686 ipp_flags_t flags,
687 ipp_action_id_t *aidp)
688 {
689 ipp_ops_t *ippo;
690 ipp_mod_t *imp;
691 ipp_action_id_t aid;
692 ipp_action_t *ap;
693 int rc;
694
695 ASSERT(nvlpp != NULL);
696 ASSERT(*nvlpp != NULL);
697
698 /*
699 * Sanity check the action name (NULL means the framework chooses the
700 * name).
701 */
702
703 if (aname != NULL && strlen(aname) > MAXNAMELEN - 1)
704 return (EINVAL);
705
706 /*
707 * Translate the module id into the module pointer.
708 */
709
710 if ((imp = hold_mod(mid)) == NULL)
711 return (ENOENT);
712
713 /*
714 * Allocate an action.
715 */
716
717 if ((rc = alloc_action(aname, &aid)) != 0) {
718 rele_mod(imp);
719 return (rc);
720 }
721
722 ap = hold_action(aid);
723 ASSERT(ap != NULL);
724
725 /*
726 * Note that the action is in the process of creation/destruction.
727 */
728
729 LOCK_ACTION(ap, RW_WRITER);
730 ap->ippa_state = IPP_ASTATE_CONFIG_PENDING;
731
732 /*
733 * Reference the module for which the action is being created.
734 */
735
736 LOCK_MOD(imp, RW_WRITER);
737 if ((rc = ref_mod(ap, imp)) != 0) {
738 UNLOCK_MOD(imp);
739 ap->ippa_state = IPP_ASTATE_PROTO;
740 UNLOCK_ACTION(ap);
741
742 free_action(ap);
743 rele_action(ap);
744 rele_mod(imp);
745 return (rc);
746 }
747
748 UNLOCK_ACTION(ap);
749
750 ippo = imp->ippm_ops;
751 ASSERT(ippo != NULL);
752 UNLOCK_MOD(imp);
753
754 /*
755 * Call into the module to create the action context.
756 */
757
758 CONFIG_WRITE_START(ap);
759 DBG2(DBG_ACTION, "creating action '%s' in module '%s'\n",
760 ap->ippa_name, imp->ippm_name);
761 if ((rc = ippo->ippo_action_create(ap->ippa_id, nvlpp, flags)) != 0) {
762 LOCK_ACTION(ap, RW_WRITER);
763 LOCK_MOD(imp, RW_WRITER);
764 unref_mod(ap, imp);
765 UNLOCK_MOD(imp);
766 ap->ippa_state = IPP_ASTATE_PROTO;
767 UNLOCK_ACTION(ap);
768
769 CONFIG_WRITE_END(ap);
770
771 free_action(ap);
772 rele_action(ap);
773 rele_mod(imp);
774 return (rc);
775 }
776 CONFIG_WRITE_END(ap);
777
778 /*
779 * Make the action available for use.
780 */
781
782 LOCK_ACTION(ap, RW_WRITER);
783 ap->ippa_state = IPP_ASTATE_AVAILABLE;
784 if (aidp != NULL)
785 *aidp = ap->ippa_id;
786 UNLOCK_ACTION(ap);
787
788 rele_action(ap);
789 rele_mod(imp);
790 return (0);
791 }
792 #undef __FN__
793
794 #define __FN__ "ipp_action_destroy"
795 int
ipp_action_destroy(ipp_action_id_t aid,ipp_flags_t flags)796 ipp_action_destroy(
797 ipp_action_id_t aid,
798 ipp_flags_t flags)
799 {
800 ipp_ref_t *rp = NULL;
801 ipp_ref_t *tmp;
802 ipp_action_t *ap;
803 int rc;
804
805 /*
806 * Translate the action id into the action pointer.
807 */
808
809 if ((ap = hold_action(aid)) == NULL)
810 return (ENOENT);
811
812 /*
813 * Set the condemned action list pointer and destroy the action.
814 */
815
816 ap->ippa_condemned = &rp;
817 if ((rc = destroy_action(ap, flags)) == 0) {
818
819 /*
820 * Destroy any other actions condemned by the destruction of
821 * the first action.
822 */
823
824 for (tmp = rp; tmp != NULL; tmp = tmp->ippr_nextp) {
825 ap = tmp->ippr_action;
826 ap->ippa_condemned = &rp;
827 (void) destroy_action(ap, flags);
828 }
829 } else {
830
831 /*
832 * Unreference any condemned actions since the destruction of
833 * the first action failed.
834 */
835
836 for (tmp = rp; tmp != NULL; tmp = tmp->ippr_nextp) {
837 ap = tmp->ippr_action;
838 rele_action(ap);
839 }
840 }
841
842 /*
843 * Clean up the condemned list.
844 */
845
846 while (rp != NULL) {
847 tmp = rp;
848 rp = rp->ippr_nextp;
849 kmem_free(tmp, sizeof (ipp_ref_t));
850 }
851
852 return (rc);
853 }
854 #undef __FN__
855
856 #define __FN__ "ipp_action_modify"
857 int
ipp_action_modify(ipp_action_id_t aid,nvlist_t ** nvlpp,ipp_flags_t flags)858 ipp_action_modify(
859 ipp_action_id_t aid,
860 nvlist_t **nvlpp,
861 ipp_flags_t flags)
862 {
863 ipp_action_t *ap;
864 ipp_ops_t *ippo;
865 ipp_mod_t *imp;
866 int rc;
867
868 ASSERT(nvlpp != NULL);
869 ASSERT(*nvlpp != NULL);
870
871 /*
872 * Translate the action id into the action pointer.
873 */
874
875 if ((ap = hold_action(aid)) == NULL)
876 return (ENOENT);
877
878 /*
879 * Check that the action is either available for use or is in the
880 * process of creation/destruction.
881 *
882 * NOTE: It is up to the module to lock multiple configuration
883 * operations against each other if necessary.
884 */
885
886 LOCK_ACTION(ap, RW_READER);
887 if (ap->ippa_state != IPP_ASTATE_AVAILABLE &&
888 ap->ippa_state != IPP_ASTATE_CONFIG_PENDING) {
889 UNLOCK_ACTION(ap);
890 rele_action(ap);
891 return (EPROTO);
892 }
893
894 imp = ap->ippa_mod;
895 ASSERT(imp != NULL);
896 UNLOCK_ACTION(ap);
897
898 ippo = imp->ippm_ops;
899 ASSERT(ippo != NULL);
900
901 /*
902 * Call into the module to modify the action context.
903 */
904
905 DBG1(DBG_ACTION, "modifying action '%s'\n", ap->ippa_name);
906 CONFIG_WRITE_START(ap);
907 rc = ippo->ippo_action_modify(aid, nvlpp, flags);
908 CONFIG_WRITE_END(ap);
909
910 rele_action(ap);
911 return (rc);
912 }
913 #undef __FN__
914
915 #define __FN__ "ipp_action_info"
916 int
ipp_action_info(ipp_action_id_t aid,int (* fn)(nvlist_t *,void *),void * arg,ipp_flags_t flags)917 ipp_action_info(
918 ipp_action_id_t aid,
919 int (*fn)(nvlist_t *, void *),
920 void *arg,
921 ipp_flags_t flags)
922 {
923 ipp_action_t *ap;
924 ipp_mod_t *imp;
925 ipp_ops_t *ippo;
926 int rc;
927
928 /*
929 * Translate the action id into the action pointer.
930 */
931
932 if ((ap = hold_action(aid)) == NULL)
933 return (ENOENT);
934
935 /*
936 * Check that the action is available for use. We don't want to
937 * read back parameters while the action is in the process of
938 * creation/destruction.
939 */
940
941 LOCK_ACTION(ap, RW_READER);
942 if (ap->ippa_state != IPP_ASTATE_AVAILABLE) {
943 UNLOCK_ACTION(ap);
944 rele_action(ap);
945 return (EPROTO);
946 }
947
948 imp = ap->ippa_mod;
949 ASSERT(imp != NULL);
950 UNLOCK_ACTION(ap);
951
952 ippo = imp->ippm_ops;
953 ASSERT(ippo != NULL);
954
955 /*
956 * Call into the module to get the action configuration information.
957 */
958
959 DBG1(DBG_ACTION,
960 "getting configuration information from action '%s'\n",
961 ap->ippa_name);
962 CONFIG_READ_START(ap);
963 if ((rc = ippo->ippo_action_info(aid, fn, arg, flags)) != 0) {
964 CONFIG_READ_END(ap);
965 rele_action(ap);
966 return (rc);
967 }
968 CONFIG_READ_END(ap);
969
970 rele_action(ap);
971 return (0);
972 }
973 #undef __FN__
974
975 #define __FN__ "ipp_action_set_ptr"
976 void
ipp_action_set_ptr(ipp_action_id_t aid,void * ptr)977 ipp_action_set_ptr(
978 ipp_action_id_t aid,
979 void *ptr)
980 {
981 ipp_action_t *ap;
982
983 /*
984 * Translate the action id into the action pointer.
985 */
986
987 ap = hold_action(aid);
988 ASSERT(ap != NULL);
989
990 /*
991 * Set the private data pointer.
992 */
993
994 ap->ippa_ptr = ptr;
995 rele_action(ap);
996 }
997 #undef __FN__
998
999 #define __FN__ "ipp_action_get_ptr"
1000 void *
ipp_action_get_ptr(ipp_action_id_t aid)1001 ipp_action_get_ptr(
1002 ipp_action_id_t aid)
1003 {
1004 ipp_action_t *ap;
1005 void *ptr;
1006
1007 /*
1008 * Translate the action id into the action pointer.
1009 */
1010
1011 ap = hold_action(aid);
1012 ASSERT(ap != NULL);
1013
1014 /*
1015 * Return the private data pointer.
1016 */
1017
1018 ptr = ap->ippa_ptr;
1019 rele_action(ap);
1020
1021 return (ptr);
1022 }
1023 #undef __FN__
1024
1025 #define __FN__ "ipp_action_ref"
1026 /*ARGSUSED*/
1027 int
ipp_action_ref(ipp_action_id_t aid,ipp_action_id_t ref_aid,ipp_flags_t flags)1028 ipp_action_ref(
1029 ipp_action_id_t aid,
1030 ipp_action_id_t ref_aid,
1031 ipp_flags_t flags)
1032 {
1033 ipp_action_t *ap;
1034 ipp_action_t *ref_ap;
1035 int rc;
1036
1037 /*
1038 * Actions are not allowed to reference themselves.
1039 */
1040
1041 if (aid == ref_aid)
1042 return (EINVAL);
1043
1044 /*
1045 * Check for a special case 'virtual action' id.
1046 */
1047
1048 switch (ref_aid) {
1049 case IPP_ACTION_CONT:
1050 /*FALLTHRU*/
1051 case IPP_ACTION_DEFER:
1052 /*FALLTHRU*/
1053 case IPP_ACTION_DROP:
1054 return (0);
1055 default:
1056 break;
1057 }
1058
1059 /*
1060 * Translate the action ids into action pointers.
1061 */
1062
1063 if ((ap = hold_action(aid)) == NULL)
1064 return (ENOENT);
1065
1066 if ((ref_ap = hold_action(ref_aid)) == NULL) {
1067 rele_action(ap);
1068 return (ENOENT);
1069 }
1070
1071 LOCK_ACTION(ap, RW_WRITER);
1072 LOCK_ACTION(ref_ap, RW_WRITER);
1073
1074 if (ref_ap->ippa_state != IPP_ASTATE_AVAILABLE) {
1075 UNLOCK_ACTION(ref_ap);
1076 UNLOCK_ACTION(ap);
1077
1078 rele_action(ref_ap);
1079 rele_action(ap);
1080 return (EPROTO);
1081 }
1082
1083 /*
1084 * Create references between the two actions.
1085 */
1086
1087 rc = ref_action(ap, ref_ap);
1088 UNLOCK_ACTION(ref_ap);
1089 UNLOCK_ACTION(ap);
1090
1091 rele_action(ref_ap);
1092 rele_action(ap);
1093 return (rc);
1094 }
1095 #undef __FN__
1096
1097 #define __FN__ "ipp_action_unref"
1098 int
ipp_action_unref(ipp_action_id_t aid,ipp_action_id_t ref_aid,ipp_flags_t flags)1099 ipp_action_unref(
1100 ipp_action_id_t aid,
1101 ipp_action_id_t ref_aid,
1102 ipp_flags_t flags)
1103 {
1104 ipp_action_t *ap;
1105 ipp_action_t *ref_ap;
1106 int ref_is_busy;
1107 int rc;
1108
1109 if (aid == ref_aid)
1110 return (EINVAL);
1111
1112 /*
1113 * Check for a special case 'virtual action' id.
1114 */
1115
1116 switch (ref_aid) {
1117 case IPP_ACTION_CONT:
1118 /*FALLTHRU*/
1119 case IPP_ACTION_DEFER:
1120 /*FALLTHRU*/
1121 case IPP_ACTION_DROP:
1122 return (0);
1123 default:
1124 break;
1125 }
1126
1127 /*
1128 * Translate the action ids into action pointers.
1129 */
1130
1131 if ((ap = hold_action(aid)) == NULL)
1132 return (ENOENT);
1133
1134 if ((ref_ap = hold_action(ref_aid)) == NULL) {
1135 rele_action(ap);
1136 return (ENOENT);
1137 }
1138
1139 LOCK_ACTION(ap, RW_WRITER);
1140 LOCK_ACTION(ref_ap, RW_WRITER);
1141
1142 /*
1143 * Remove the reference between the actions.
1144 */
1145
1146 if ((rc = unref_action(ap, ref_ap)) != 0) {
1147 UNLOCK_ACTION(ref_ap);
1148 UNLOCK_ACTION(ap);
1149 rele_action(ref_ap);
1150 rele_action(ap);
1151 return (rc);
1152 }
1153
1154 ref_is_busy = is_action_refd(ref_ap);
1155
1156 UNLOCK_ACTION(ref_ap);
1157 UNLOCK_ACTION(ap);
1158
1159 if (flags & IPP_DESTROY_REF) {
1160 if (!ref_is_busy) {
1161
1162 /*
1163 * Condemn the action so that it will be destroyed.
1164 */
1165
1166 (void) condemn_action(ap->ippa_condemned, ref_ap);
1167 return (0);
1168 }
1169 }
1170
1171 rele_action(ref_ap);
1172 rele_action(ap);
1173 return (0);
1174 }
1175 #undef __FN__
1176
1177 /*
1178 * Packet manipulation interface.
1179 */
1180
1181 #define __FN__ "ipp_packet_alloc"
1182 int
ipp_packet_alloc(ipp_packet_t ** ppp,const char * name,ipp_action_id_t aid)1183 ipp_packet_alloc(
1184 ipp_packet_t **ppp,
1185 const char *name,
1186 ipp_action_id_t aid)
1187 {
1188 ipp_packet_t *pp;
1189 int rc;
1190
1191 ASSERT(ppp != NULL);
1192
1193 /*
1194 * A name is required.
1195 */
1196
1197 if (name == NULL || strlen(name) > MAXNAMELEN - 1)
1198 return (EINVAL);
1199
1200 /*
1201 * Allocate a packet structure from the cache.
1202 */
1203
1204 if ((rc = alloc_packet(name, aid, &pp)) != 0)
1205 return (rc);
1206
1207 if (ipp_packet_logging != 0 && pp->ippp_log == NULL) {
1208
1209 /*
1210 * Logging is turned on but there's no log buffer. We need
1211 * to allocate one.
1212 */
1213 if ((pp->ippp_log = kmem_alloc(
1214 ipp_packet_log_entries * sizeof (ipp_log_t),
1215 KM_NOSLEEP)) != NULL) {
1216 pp->ippp_log_limit = ipp_packet_log_entries - 1;
1217 pp->ippp_log_windex = 0;
1218 }
1219 } else if (ipp_packet_logging == 0 && pp->ippp_log != NULL) {
1220
1221 /*
1222 * A log buffer is present but logging has been turned off.
1223 * Free the buffer now,
1224 */
1225
1226 kmem_free(pp->ippp_log,
1227 (pp->ippp_log_limit + 1) * sizeof (ipp_log_t));
1228 pp->ippp_log = NULL;
1229 pp->ippp_log_limit = 0;
1230 pp->ippp_log_windex = 0;
1231 }
1232
1233 *ppp = pp;
1234 return (0);
1235 }
1236 #undef __FN__
1237
1238 #define __FN__ "ipp_packet_free"
1239 void
ipp_packet_free(ipp_packet_t * pp)1240 ipp_packet_free(
1241 ipp_packet_t *pp)
1242 {
1243
1244 ASSERT(pp != NULL);
1245
1246 /*
1247 * If there is a private structure pointer set, call its free
1248 * function.
1249 */
1250
1251 if (pp->ippp_private) {
1252 pp->ippp_private_free(pp->ippp_private);
1253 pp->ippp_private = NULL;
1254 pp->ippp_private_free = NULL;
1255 }
1256
1257 /*
1258 * Free the packet structure back to the cache.
1259 */
1260
1261 free_packet(pp);
1262 }
1263 #undef __FN__
1264
1265 #define __FN__ "ipp_packet_add_class"
1266 int
ipp_packet_add_class(ipp_packet_t * pp,const char * name,ipp_action_id_t aid)1267 ipp_packet_add_class(
1268 ipp_packet_t *pp,
1269 const char *name,
1270 ipp_action_id_t aid)
1271 {
1272 ipp_class_t *cp;
1273 int rc;
1274
1275 ASSERT(pp != NULL);
1276
1277 /*
1278 * A name is required.
1279 */
1280
1281 if (name == NULL || strlen(name) > MAXNAMELEN - 1)
1282 return (EINVAL);
1283
1284 /*
1285 * Check if there is an available class structure.
1286 */
1287
1288 if (pp->ippp_class_windex == pp->ippp_class_limit) {
1289
1290 /*
1291 * No more structures. Re-allocate the array.
1292 */
1293
1294 if ((rc = realloc_packet(pp)) != 0)
1295 return (rc);
1296 }
1297 ASSERT(pp->ippp_class_windex < pp->ippp_class_limit);
1298
1299 /*
1300 * Set up a new class structure.
1301 */
1302
1303 cp = &(pp->ippp_class_array[pp->ippp_class_windex++]);
1304 (void) strcpy(cp->ippc_name, name);
1305 cp->ippc_aid = aid;
1306
1307 return (0);
1308 }
1309 #undef __FN__
1310
1311 #define __FN__ "ipp_packet_process"
1312 int
ipp_packet_process(ipp_packet_t ** ppp)1313 ipp_packet_process(
1314 ipp_packet_t **ppp)
1315 {
1316 ipp_packet_t *pp;
1317 ipp_action_id_t aid;
1318 ipp_class_t *cp;
1319 ipp_log_t *lp;
1320 ipp_action_t *ap;
1321 ipp_mod_t *imp;
1322 ipp_ops_t *ippo;
1323 int rc;
1324
1325 ASSERT(ppp != NULL);
1326 pp = *ppp;
1327 ASSERT(pp != NULL);
1328
1329 /*
1330 * Walk the class list.
1331 */
1332
1333 while (pp->ippp_class_rindex < pp->ippp_class_windex) {
1334 cp = &(pp->ippp_class_array[pp->ippp_class_rindex]);
1335
1336 /*
1337 * While there is a real action to invoke...
1338 */
1339
1340 aid = cp->ippc_aid;
1341 while (aid != IPP_ACTION_CONT &&
1342 aid != IPP_ACTION_DEFER &&
1343 aid != IPP_ACTION_DROP) {
1344
1345 ASSERT(aid != IPP_ACTION_INVAL);
1346
1347 /*
1348 * Translate the action id to the action pointer.
1349 */
1350
1351 if ((ap = hold_action(aid)) == NULL) {
1352 DBG1(DBG_PACKET,
1353 "action id '%d' not found\n", aid);
1354 return (ENOENT);
1355 }
1356
1357 /*
1358 * Check that the action is available for use...
1359 */
1360 LOCK_ACTION(ap, RW_READER);
1361 if (ap->ippa_state != IPP_ASTATE_AVAILABLE) {
1362 UNLOCK_ACTION(ap);
1363 rele_action(ap);
1364 return (EPROTO);
1365 }
1366
1367 /*
1368 * Increment the action's packet count to note that
1369 * it's being used.
1370 *
1371 * NOTE: We only have a read lock, so we need to use
1372 * atomic_add_32(). The read lock is still
1373 * important though as it is crucial to block
1374 * out a destroy operation between the action
1375 * state being checked and the packet count
1376 * being incremented.
1377 */
1378
1379 atomic_inc_32(&(ap->ippa_packets));
1380
1381 imp = ap->ippa_mod;
1382 ASSERT(imp != NULL);
1383 UNLOCK_ACTION(ap);
1384
1385 ippo = imp->ippm_ops;
1386 ASSERT(ippo != NULL);
1387
1388 /*
1389 * If there's a log, grab the next entry and fill it
1390 * in.
1391 */
1392
1393 if (pp->ippp_log != NULL &&
1394 pp->ippp_log_windex <= pp->ippp_log_limit) {
1395 lp = &(pp->ippp_log[pp->ippp_log_windex++]);
1396 lp->ippl_aid = aid;
1397 (void) strcpy(lp->ippl_name, cp->ippc_name);
1398 gethrestime(&lp->ippl_begin);
1399 } else {
1400 lp = NULL;
1401 }
1402
1403 /*
1404 * Invoke the action.
1405 */
1406
1407 rc = ippo->ippo_action_invoke(aid, pp);
1408
1409 /*
1410 * Also log the time that the action finished
1411 * processing.
1412 */
1413
1414 if (lp != NULL)
1415 gethrestime(&lp->ippl_end);
1416
1417 /*
1418 * Decrement the packet count.
1419 */
1420
1421 atomic_dec_32(&(ap->ippa_packets));
1422
1423 /*
1424 * If the class' action id is the same now as it was
1425 * before then clearly no 'next action' has been set.
1426 * This is a protocol error.
1427 */
1428
1429 if (cp->ippc_aid == aid) {
1430 DBG1(DBG_PACKET,
1431 "action '%s' did not set next action\n",
1432 ap->ippa_name);
1433 rele_action(ap);
1434 return (EPROTO);
1435 }
1436
1437 /*
1438 * The action did not complete successfully. Terminate
1439 * packet processing.
1440 */
1441
1442 if (rc != 0) {
1443 DBG2(DBG_PACKET,
1444 "action error '%d' from action '%s'\n",
1445 rc, ap->ippa_name);
1446 rele_action(ap);
1447 return (rc);
1448 }
1449
1450 rele_action(ap);
1451
1452 /*
1453 * Look at the next action.
1454 */
1455
1456 aid = cp->ippc_aid;
1457 }
1458
1459 /*
1460 * No more real actions to invoke, check for 'virtual' ones.
1461 */
1462
1463 /*
1464 * Packet deferred: module has held onto packet for processing
1465 * later.
1466 */
1467
1468 if (cp->ippc_aid == IPP_ACTION_DEFER) {
1469 *ppp = NULL;
1470 return (0);
1471 }
1472
1473 /*
1474 * Packet dropped: free the packet and discontinue processing.
1475 */
1476
1477 if (cp->ippc_aid == IPP_ACTION_DROP) {
1478 freemsg(pp->ippp_data);
1479 ipp_packet_free(pp);
1480 *ppp = NULL;
1481 return (0);
1482 }
1483
1484 /*
1485 * Must be 'continue processing': move onto the next class.
1486 */
1487
1488 ASSERT(cp->ippc_aid == IPP_ACTION_CONT);
1489 pp->ippp_class_rindex++;
1490 }
1491
1492 return (0);
1493 }
1494 #undef __FN__
1495
1496 #define __FN__ "ipp_packet_next"
1497 int
ipp_packet_next(ipp_packet_t * pp,ipp_action_id_t aid)1498 ipp_packet_next(
1499 ipp_packet_t *pp,
1500 ipp_action_id_t aid)
1501 {
1502 ipp_action_t *ap;
1503 ipp_class_t *cp;
1504
1505 ASSERT(pp != NULL);
1506
1507 cp = &(pp->ippp_class_array[pp->ippp_class_rindex]);
1508 ASSERT(cp != NULL);
1509
1510 /*
1511 * Check for a special case 'virtual action' id.
1512 */
1513
1514 switch (aid) {
1515 case IPP_ACTION_INVAL:
1516 return (EINVAL);
1517 case IPP_ACTION_DEFER:
1518 /*FALLTHRU*/
1519 case IPP_ACTION_CONT:
1520 /*FALLTHRU*/
1521 case IPP_ACTION_DROP:
1522 break;
1523 default:
1524
1525 /*
1526 * Not a virtual action so try to translate the action id
1527 * into the action pointer to confirm the actions existence.
1528 */
1529
1530 if ((ap = hold_action(aid)) == NULL) {
1531 DBG0(DBG_PACKET, "invalid action\n");
1532 return (ENOENT);
1533 }
1534 rele_action(ap);
1535
1536 break;
1537 }
1538
1539 /*
1540 * Set the class' new action id.
1541 */
1542
1543 cp->ippc_aid = aid;
1544
1545 return (0);
1546 }
1547 #undef __FN__
1548
1549 #define __FN__ "ipp_packet_set_data"
1550 void
ipp_packet_set_data(ipp_packet_t * pp,mblk_t * data)1551 ipp_packet_set_data(
1552 ipp_packet_t *pp,
1553 mblk_t *data)
1554 {
1555 ASSERT(pp != NULL);
1556 pp->ippp_data = data;
1557 }
1558 #undef __FN__
1559
1560 #define __FN__ "ipp_packet_get_data"
1561 mblk_t *
ipp_packet_get_data(ipp_packet_t * pp)1562 ipp_packet_get_data(
1563 ipp_packet_t *pp)
1564 {
1565 ASSERT(pp != NULL);
1566 return (pp->ippp_data);
1567 }
1568 #undef __FN__
1569
1570 #define __FN__ "ipp_packet_set_private"
1571 void
ipp_packet_set_private(ipp_packet_t * pp,void * buf,void (* free_func)(void *))1572 ipp_packet_set_private(
1573 ipp_packet_t *pp,
1574 void *buf,
1575 void (*free_func)(void *))
1576 {
1577 ASSERT(pp != NULL);
1578 ASSERT(free_func != NULL);
1579
1580 pp->ippp_private = buf;
1581 pp->ippp_private_free = free_func;
1582 }
1583 #undef __FN__
1584
1585 #define __FN__ "ipp_packet_get_private"
1586 void *
ipp_packet_get_private(ipp_packet_t * pp)1587 ipp_packet_get_private(
1588 ipp_packet_t *pp)
1589 {
1590 ASSERT(pp != NULL);
1591 return (pp->ippp_private);
1592 }
1593 #undef __FN__
1594
1595 /*
1596 * Statistics interface.
1597 */
1598
1599 #define __FN__ "ipp_stat_create"
1600 int
ipp_stat_create(ipp_action_id_t aid,const char * name,int nstat,int (* update)(ipp_stat_t *,void *,int),void * arg,ipp_stat_t ** spp)1601 ipp_stat_create(
1602 ipp_action_id_t aid,
1603 const char *name,
1604 int nstat,
1605 int (*update)(ipp_stat_t *, void *, int),
1606 void *arg,
1607 ipp_stat_t **spp)
1608 {
1609 ipp_action_t *ap;
1610 ipp_mod_t *imp;
1611 ipp_stat_impl_t *sip;
1612 ipp_stat_t *sp;
1613 kstat_t *ksp;
1614 char *class;
1615 char *modname;
1616 int instance;
1617
1618 ASSERT(spp != NULL);
1619
1620 /*
1621 * Sanity check the arguments.
1622 */
1623
1624 if (name == NULL || nstat <= 0 || update == NULL)
1625 return (EINVAL);
1626
1627 /*
1628 * Translate the action id into the action pointer.
1629 */
1630
1631 if ((ap = hold_action(aid)) == NULL)
1632 return (ENOENT);
1633
1634 /*
1635 * Grab relevant action and module information.
1636 */
1637
1638 LOCK_ACTION(ap, RW_READER);
1639 class = ap->ippa_name;
1640 instance = (int)ap->ippa_id;
1641
1642 imp = ap->ippa_mod;
1643 ASSERT(imp != NULL);
1644
1645 LOCK_MOD(imp, RW_READER);
1646 modname = imp->ippm_name;
1647
1648 /*
1649 * Allocate a stats info structure.
1650 */
1651
1652 if ((sip = kmem_alloc(sizeof (ipp_stat_impl_t), KM_NOSLEEP)) == NULL)
1653 return (ENOMEM);
1654
1655 /*
1656 * Create a set of kstats.
1657 */
1658
1659 DBG2(DBG_STATS, "creating stat set '%s' for action '%s'\n",
1660 name, class);
1661 if ((ksp = kstat_create(modname, instance, name, class,
1662 KSTAT_TYPE_NAMED, nstat, KSTAT_FLAG_WRITABLE)) == NULL) {
1663 kmem_free(sip, sizeof (ipp_stat_impl_t));
1664 UNLOCK_ACTION(ap);
1665 UNLOCK_MOD(imp);
1666 return (EINVAL); /* Assume EINVAL was the cause */
1667 }
1668
1669 UNLOCK_ACTION(ap);
1670 UNLOCK_MOD(imp);
1671
1672 DBG1(DBG_STATS, "ks_data = %p\n", ksp->ks_data);
1673
1674 /*
1675 * Set up the kstats structure with a private data pointer and an
1676 * 'update' function.
1677 */
1678
1679 ksp->ks_update = update_stats;
1680 ksp->ks_private = (void *)sip;
1681
1682 /*
1683 * Keep a reference to the kstats structure in our own stats info
1684 * structure.
1685 */
1686
1687 sip->ippsi_ksp = ksp;
1688 sip->ippsi_data = ksp->ks_data;
1689
1690 /*
1691 * Fill in the rest of the stats info structure.
1692 */
1693
1694 (void) strcpy(sip->ippsi_name, name);
1695 sip->ippsi_arg = arg;
1696 sip->ippsi_update = update;
1697 sip->ippsi_limit = nstat;
1698 sip->ippsi_count = 0;
1699 mutex_init(sip->ippsi_lock, NULL, MUTEX_ADAPTIVE,
1700 (void *)ipltospl(LOCK_LEVEL));
1701
1702 /*
1703 * Case the stats info structure to a semi-opaque structure that
1704 * we pass back to the caller.
1705 */
1706
1707 sp = (ipp_stat_t *)sip;
1708 ASSERT(sp->ipps_data == sip->ippsi_data);
1709 *spp = sp;
1710
1711 rele_action(ap);
1712 return (0);
1713 }
1714 #undef __FN__
1715
1716 #define __FN__ "ipp_stat_install"
1717 void
ipp_stat_install(ipp_stat_t * sp)1718 ipp_stat_install(
1719 ipp_stat_t *sp)
1720 {
1721 ipp_stat_impl_t *sip = (ipp_stat_impl_t *)sp;
1722
1723 ASSERT(sp != NULL);
1724
1725 /*
1726 * Install the set of kstats referenced by the stats info structure.
1727 */
1728
1729 DBG1(DBG_STATS, "installing stat set '%s'\n", sip->ippsi_name);
1730 kstat_install(sip->ippsi_ksp);
1731 }
1732 #undef __FN__
1733
1734 #define __FN__ "ipp_stat_destroy"
1735 void
ipp_stat_destroy(ipp_stat_t * sp)1736 ipp_stat_destroy(
1737 ipp_stat_t *sp)
1738 {
1739 ipp_stat_impl_t *sip = (ipp_stat_impl_t *)sp;
1740
1741 ASSERT(sp != NULL);
1742
1743 /*
1744 * Destroy the set of kstats referenced by the stats info structure.
1745 */
1746
1747 DBG1(DBG_STATS, "destroying stat set '%s'\n", sip->ippsi_name);
1748 kstat_delete(sip->ippsi_ksp);
1749
1750 /*
1751 * Destroy the stats info structure itself.
1752 */
1753
1754 mutex_destroy(sip->ippsi_lock);
1755 kmem_free(sip, sizeof (ipp_stat_impl_t));
1756 }
1757 #undef __FN__
1758
1759 #define __FN__ "ipp_stat_named_init"
1760 int
ipp_stat_named_init(ipp_stat_t * sp,const char * name,uchar_t type,ipp_named_t * np)1761 ipp_stat_named_init(
1762 ipp_stat_t *sp,
1763 const char *name,
1764 uchar_t type,
1765 ipp_named_t *np)
1766 {
1767 ipp_stat_impl_t *sip = (ipp_stat_impl_t *)sp;
1768 uchar_t ktype;
1769
1770 ASSERT(sp != NULL);
1771 ASSERT(np != NULL);
1772
1773 if (name == NULL)
1774 return (EINVAL);
1775
1776 if ((type & IPP_STAT_TAG) == 0)
1777 return (EINVAL);
1778 ktype = type & ~IPP_STAT_TAG;
1779
1780 /*
1781 * Check we will not exceed the maximum number of a stats that was
1782 * indicated during set creation.
1783 */
1784
1785 mutex_enter(sip->ippsi_lock);
1786 if (sip->ippsi_count >= sip->ippsi_limit) {
1787 mutex_exit(sip->ippsi_lock);
1788 return (ENOSPC);
1789 }
1790
1791 /*
1792 * Bump the count.
1793 */
1794
1795 sip->ippsi_count++;
1796
1797 /*
1798 * Create a new named kstat.
1799 */
1800
1801 DBG3(DBG_STATS, "%s.%s: knp = %p\n", sip->ippsi_name, name, np);
1802 kstat_named_init(np, name, ktype);
1803 mutex_exit(sip->ippsi_lock);
1804
1805 return (0);
1806 }
1807 #undef __FN__
1808
1809 #define __FN__ "ipp_stat_named_op"
1810 int
ipp_stat_named_op(ipp_named_t * np,void * valp,int rw)1811 ipp_stat_named_op(
1812 ipp_named_t *np,
1813 void *valp,
1814 int rw)
1815 {
1816 kstat_named_t *knp;
1817 uchar_t type;
1818 int rc = 0;
1819
1820 ASSERT(np != NULL);
1821 ASSERT(valp != NULL);
1822
1823 knp = np;
1824 type = knp->data_type | IPP_STAT_TAG;
1825
1826 /*
1827 * Copy data to or from the named kstat, depending on the specified
1828 * opcode.
1829 */
1830
1831 switch (rw) {
1832 case IPP_STAT_WRITE:
1833 switch (type) {
1834 case IPP_STAT_INT32:
1835 *(int32_t *)valp = knp->value.i32;
1836 break;
1837 case IPP_STAT_UINT32:
1838 *(uint32_t *)valp = knp->value.ui32;
1839 break;
1840 case IPP_STAT_INT64:
1841 *(int64_t *)valp = knp->value.i64;
1842 break;
1843 case IPP_STAT_UINT64:
1844 *(uint64_t *)valp = knp->value.ui64;
1845 break;
1846 case IPP_STAT_STRING:
1847 (void) strncpy(valp, knp->value.c, 16);
1848 break;
1849 default:
1850 ASSERT(0); /* should not reach here */
1851 break;
1852 }
1853
1854 break;
1855 case IPP_STAT_READ:
1856 switch (type) {
1857 case IPP_STAT_INT32:
1858 knp->value.i32 = *(int32_t *)valp;
1859 break;
1860 case IPP_STAT_UINT32:
1861 knp->value.ui32 = *(uint32_t *)valp;
1862 break;
1863 case IPP_STAT_INT64:
1864 knp->value.i64 = *(int64_t *)valp;
1865 break;
1866 case IPP_STAT_UINT64:
1867 knp->value.ui64 = *(uint64_t *)valp;
1868 break;
1869 case IPP_STAT_STRING:
1870 (void) strncpy(knp->value.c, valp, 16);
1871 break;
1872 default:
1873 ASSERT(0); /* should not reach here */
1874 break;
1875 }
1876
1877 break;
1878 default:
1879 rc = EINVAL;
1880 }
1881
1882 return (rc);
1883 }
1884 #undef __FN__
1885
1886 /*
1887 * Local functions (for local people. There's nothing for you here!)
1888 */
1889
1890 #define __FN__ "ref_mod"
1891 static int
ref_mod(ipp_action_t * ap,ipp_mod_t * imp)1892 ref_mod(
1893 ipp_action_t *ap,
1894 ipp_mod_t *imp)
1895 {
1896 ipp_ref_t **rpp;
1897 ipp_ref_t *rp;
1898
1899 ASSERT(rw_write_held(ap->ippa_lock));
1900 ASSERT(rw_write_held(imp->ippm_lock));
1901
1902 /*
1903 * Add the new reference at the end of the module's list.
1904 */
1905
1906 rpp = &(imp->ippm_action);
1907 while ((rp = *rpp) != NULL) {
1908 ASSERT(rp->ippr_action != ap);
1909 rpp = &(rp->ippr_nextp);
1910 }
1911
1912 /*
1913 * Allocate a reference structure.
1914 */
1915
1916 if ((rp = kmem_zalloc(sizeof (ipp_ref_t), KM_NOSLEEP)) == NULL)
1917 return (ENOMEM);
1918
1919 /*
1920 * Set the reference to the action and link it onto the module's list.
1921 */
1922
1923 rp->ippr_action = ap;
1924 *rpp = rp;
1925
1926 /*
1927 * Keep a 'back pointer' from the action structure to the module
1928 * structure.
1929 */
1930
1931 ap->ippa_mod = imp;
1932
1933 return (0);
1934 }
1935 #undef __FN__
1936
1937 #define __FN__ "unref_mod"
1938 static void
unref_mod(ipp_action_t * ap,ipp_mod_t * imp)1939 unref_mod(
1940 ipp_action_t *ap,
1941 ipp_mod_t *imp)
1942 {
1943 ipp_ref_t **rpp;
1944 ipp_ref_t *rp;
1945
1946 ASSERT(rw_write_held(ap->ippa_lock));
1947 ASSERT(rw_write_held(imp->ippm_lock));
1948
1949 /*
1950 * Scan the module's list for the reference to the action.
1951 */
1952
1953 rpp = &(imp->ippm_action);
1954 while ((rp = *rpp) != NULL) {
1955 if (rp->ippr_action == ap)
1956 break;
1957 rpp = &(rp->ippr_nextp);
1958 }
1959 ASSERT(rp != NULL);
1960
1961 /*
1962 * Unlink the reference structure and free it.
1963 */
1964
1965 *rpp = rp->ippr_nextp;
1966 kmem_free(rp, sizeof (ipp_ref_t));
1967
1968 /*
1969 * NULL the 'back pointer'.
1970 */
1971
1972 ap->ippa_mod = NULL;
1973 }
1974 #undef __FN__
1975
1976 #define __FN__ "is_mod_busy"
1977 static int
is_mod_busy(ipp_mod_t * imp)1978 is_mod_busy(
1979 ipp_mod_t *imp)
1980 {
1981 /*
1982 * Return a value which is true (non-zero) iff the module refers
1983 * to no actions.
1984 */
1985
1986 return (imp->ippm_action != NULL);
1987 }
1988 #undef __FN__
1989
1990 #define __FN__ "get_mod_ref"
1991 static int
get_mod_ref(ipp_mod_t * imp,ipp_action_id_t ** bufp,int * neltp)1992 get_mod_ref(
1993 ipp_mod_t *imp,
1994 ipp_action_id_t **bufp,
1995 int *neltp)
1996 {
1997 ipp_ref_t *rp;
1998 int nelt;
1999 ipp_action_t *ap;
2000 ipp_action_id_t *buf;
2001 int length;
2002
2003 ASSERT(rw_lock_held(imp->ippm_lock));
2004
2005 /*
2006 * Count the number of actions referred to from the module structure.
2007 */
2008
2009 nelt = 0;
2010 for (rp = imp->ippm_action; rp != NULL; rp = rp->ippr_nextp) {
2011 nelt++;
2012 }
2013 DBG1(DBG_LIST, "%d actions found\n", nelt);
2014
2015 /*
2016 * If there are no actions referred to then there's nothing to do.
2017 */
2018
2019 if (nelt == 0) {
2020 *bufp = NULL;
2021 *neltp = 0;
2022 return (0);
2023 }
2024
2025 /*
2026 * Allocate a buffer to pass back to the caller.
2027 */
2028
2029 length = nelt * sizeof (ipp_action_id_t);
2030 if ((buf = kmem_alloc(length, KM_NOSLEEP)) == NULL)
2031 return (ENOMEM);
2032
2033 /*
2034 * Fill the buffer with an array of action ids.
2035 */
2036
2037 *bufp = buf;
2038 *neltp = nelt;
2039
2040 for (rp = imp->ippm_action; rp != NULL; rp = rp->ippr_nextp) {
2041 ap = rp->ippr_action;
2042 *buf++ = ap->ippa_id;
2043 }
2044
2045 ASSERT((uintptr_t)buf == (uintptr_t)*bufp + length);
2046 return (0);
2047 }
2048 #undef __FN__
2049
2050 #define __FN__ "get_mods"
2051 static int
get_mods(ipp_mod_id_t ** bufp,int * neltp)2052 get_mods(
2053 ipp_mod_id_t **bufp,
2054 int *neltp)
2055 {
2056 ipp_mod_id_t *buf;
2057 int length;
2058 ipp_mod_id_t mid;
2059 ipp_mod_t *imp;
2060
2061
2062 rw_enter(ipp_mod_byname_lock, RW_READER);
2063
2064 /*
2065 * If there are no modules registered then there's nothing to do.
2066 */
2067
2068 if (ipp_mod_count == 0) {
2069 DBG0(DBG_LIST, "no modules registered\n");
2070 *bufp = NULL;
2071 *neltp = 0;
2072 rw_exit(ipp_mod_byname_lock);
2073 return (0);
2074 }
2075
2076 /*
2077 * Allocate a buffer to pass back to the caller.
2078 */
2079
2080 DBG1(DBG_LIST, "%d modules registered\n", ipp_mod_count);
2081 length = ipp_mod_count * sizeof (ipp_mod_id_t);
2082 if ((buf = kmem_alloc(length, KM_NOSLEEP)) == NULL) {
2083 rw_exit(ipp_mod_byname_lock);
2084 return (ENOMEM);
2085 }
2086
2087 rw_enter(ipp_mod_byid_lock, RW_READER);
2088
2089 /*
2090 * Search the array of all modules.
2091 */
2092
2093 *bufp = buf;
2094 *neltp = ipp_mod_count;
2095
2096 for (mid = IPP_MOD_RESERVED + 1; mid <= ipp_mid_limit; mid++) {
2097 if ((imp = ipp_mod_byid[mid]) == NULL)
2098 continue;
2099
2100 /*
2101 * If the module has 'destruct pending' set then it means it
2102 * is either still in the cache (i.e not allocated) or in the
2103 * process of being set up by alloc_mod().
2104 */
2105
2106 LOCK_MOD(imp, RW_READER);
2107 ASSERT(imp->ippm_id == mid);
2108
2109 if (imp->ippm_destruct_pending) {
2110 UNLOCK_MOD(imp);
2111 continue;
2112 }
2113 UNLOCK_MOD(imp);
2114
2115 *buf++ = mid;
2116 }
2117
2118 rw_exit(ipp_mod_byid_lock);
2119 rw_exit(ipp_mod_byname_lock);
2120
2121 ASSERT((uintptr_t)buf == (uintptr_t)*bufp + length);
2122 return (0);
2123 }
2124 #undef __FN__
2125
2126 #define __FN__ "find_mod"
2127 static ipp_mod_id_t
find_mod(const char * modname)2128 find_mod(
2129 const char *modname)
2130 {
2131 ipp_mod_id_t mid;
2132 ipp_mod_t *imp;
2133 ipp_ref_t *rp;
2134 int hb;
2135
2136 ASSERT(modname != NULL);
2137
2138 rw_enter(ipp_mod_byname_lock, RW_READER);
2139
2140 /*
2141 * Quick return if no modules are registered.
2142 */
2143
2144 if (ipp_mod_count == 0) {
2145 rw_exit(ipp_mod_byname_lock);
2146 return (IPP_MOD_INVAL);
2147 }
2148
2149 /*
2150 * Find the hash bucket where the module structure should be.
2151 */
2152
2153 hb = hash(modname);
2154 rp = ipp_mod_byname[hb];
2155
2156 /*
2157 * Scan the bucket for a match.
2158 */
2159
2160 while (rp != NULL) {
2161 imp = rp->ippr_mod;
2162 if (strcmp(imp->ippm_name, modname) == 0)
2163 break;
2164 rp = rp->ippr_nextp;
2165 }
2166
2167 if (rp == NULL) {
2168 rw_exit(ipp_mod_byname_lock);
2169 return (IPP_MOD_INVAL);
2170 }
2171
2172 if (imp->ippm_state == IPP_MODSTATE_PROTO) {
2173 rw_exit(ipp_mod_byname_lock);
2174 return (IPP_MOD_INVAL);
2175 }
2176
2177 mid = imp->ippm_id;
2178 rw_exit(ipp_mod_byname_lock);
2179
2180 return (mid);
2181 }
2182 #undef __FN__
2183
2184 #define __FN__ "alloc_mod"
2185 static int
alloc_mod(const char * modname,ipp_mod_id_t * midp)2186 alloc_mod(
2187 const char *modname,
2188 ipp_mod_id_t *midp)
2189 {
2190 ipp_mod_t *imp;
2191 ipp_ref_t **rpp;
2192 ipp_ref_t *rp;
2193 int hb;
2194
2195 ASSERT(modname != NULL);
2196 ASSERT(midp != NULL);
2197
2198 rw_enter(ipp_mod_byname_lock, RW_WRITER);
2199
2200 /*
2201 * Find the right hash bucket for a module of the given name.
2202 */
2203
2204 hb = hash(modname);
2205 rpp = &ipp_mod_byname[hb];
2206
2207 /*
2208 * Scan the bucket making sure the module isn't already
2209 * registered.
2210 */
2211
2212 while ((rp = *rpp) != NULL) {
2213 imp = rp->ippr_mod;
2214 if (strcmp(imp->ippm_name, modname) == 0) {
2215 DBG1(DBG_MOD, "module '%s' already exists\n", modname);
2216 rw_exit(ipp_mod_byname_lock);
2217 return (EEXIST);
2218 }
2219 rpp = &(rp->ippr_nextp);
2220 }
2221
2222 /*
2223 * Allocate a new reference structure and a new module structure.
2224 */
2225
2226 if ((rp = kmem_zalloc(sizeof (ipp_ref_t), KM_NOSLEEP)) == NULL) {
2227 rw_exit(ipp_mod_byname_lock);
2228 return (ENOMEM);
2229 }
2230
2231 if ((imp = kmem_cache_alloc(ipp_mod_cache, KM_NOSLEEP)) == NULL) {
2232 kmem_free(rp, sizeof (ipp_ref_t));
2233 rw_exit(ipp_mod_byname_lock);
2234 return (ENOMEM);
2235 }
2236
2237 /*
2238 * Set up the name of the new structure.
2239 */
2240
2241 (void) strcpy(imp->ippm_name, modname);
2242
2243 /*
2244 * Make sure the 'destruct pending' flag is clear. This indicates
2245 * that the structure is no longer part of the cache.
2246 */
2247
2248 LOCK_MOD(imp, RW_WRITER);
2249 imp->ippm_destruct_pending = B_FALSE;
2250 UNLOCK_MOD(imp);
2251
2252 /*
2253 * Set the reference and link it into the hash bucket.
2254 */
2255
2256 rp->ippr_mod = imp;
2257 *rpp = rp;
2258
2259 /*
2260 * Increment the module count.
2261 */
2262
2263 ipp_mod_count++;
2264
2265 *midp = imp->ippm_id;
2266 rw_exit(ipp_mod_byname_lock);
2267 return (0);
2268 }
2269 #undef __FN__
2270
2271 #define __FN__ "free_mod"
2272 static void
free_mod(ipp_mod_t * imp)2273 free_mod(
2274 ipp_mod_t *imp)
2275 {
2276 ipp_ref_t **rpp;
2277 ipp_ref_t *rp;
2278 int hb;
2279
2280 rw_enter(ipp_mod_byname_lock, RW_WRITER);
2281
2282 /*
2283 * Find the hash bucket where the module structure should be.
2284 */
2285
2286 hb = hash(imp->ippm_name);
2287 rpp = &ipp_mod_byname[hb];
2288
2289 /*
2290 * Scan the bucket for a match.
2291 */
2292
2293 while ((rp = *rpp) != NULL) {
2294 if (rp->ippr_mod == imp)
2295 break;
2296 rpp = &(rp->ippr_nextp);
2297 }
2298 ASSERT(rp != NULL);
2299
2300 /*
2301 * Unlink the reference structure and free it.
2302 */
2303
2304 *rpp = rp->ippr_nextp;
2305 kmem_free(rp, sizeof (ipp_ref_t));
2306
2307 /*
2308 * Decrement the module count.
2309 */
2310
2311 ipp_mod_count--;
2312
2313 /*
2314 * Empty the name.
2315 */
2316
2317 *imp->ippm_name = '\0';
2318
2319 /*
2320 * If the hold count is zero then we can free the structure
2321 * immediately, otherwise we defer to rele_mod().
2322 */
2323
2324 LOCK_MOD(imp, RW_WRITER);
2325 imp->ippm_destruct_pending = B_TRUE;
2326 if (imp->ippm_hold_count == 0) {
2327 UNLOCK_MOD(imp);
2328 kmem_cache_free(ipp_mod_cache, imp);
2329 rw_exit(ipp_mod_byname_lock);
2330 return;
2331 }
2332 UNLOCK_MOD(imp);
2333
2334 rw_exit(ipp_mod_byname_lock);
2335 }
2336 #undef __FN__
2337
2338 #define __FN__ "hold_mod"
2339 static ipp_mod_t *
hold_mod(ipp_mod_id_t mid)2340 hold_mod(
2341 ipp_mod_id_t mid)
2342 {
2343 ipp_mod_t *imp;
2344
2345 if (mid < 0)
2346 return (NULL);
2347
2348 /*
2349 * Use the module id as an index into the array of all module
2350 * structures.
2351 */
2352
2353 rw_enter(ipp_mod_byid_lock, RW_READER);
2354 if ((imp = ipp_mod_byid[mid]) == NULL) {
2355 rw_exit(ipp_mod_byid_lock);
2356 return (NULL);
2357 }
2358
2359 ASSERT(imp->ippm_id == mid);
2360
2361 /*
2362 * If the modul has 'destruct pending' set then it means it is either
2363 * still in the cache (i.e not allocated) or in the process of
2364 * being set up by alloc_mod().
2365 */
2366
2367 LOCK_MOD(imp, RW_READER);
2368 if (imp->ippm_destruct_pending) {
2369 UNLOCK_MOD(imp);
2370 rw_exit(ipp_mod_byid_lock);
2371 return (NULL);
2372 }
2373 UNLOCK_MOD(imp);
2374
2375 /*
2376 * Increment the hold count to prevent the structure from being
2377 * freed.
2378 */
2379
2380 atomic_inc_32(&(imp->ippm_hold_count));
2381 rw_exit(ipp_mod_byid_lock);
2382
2383 return (imp);
2384 }
2385 #undef __FN__
2386
2387 #define __FN__ "rele_mod"
2388 static void
rele_mod(ipp_mod_t * imp)2389 rele_mod(
2390 ipp_mod_t *imp)
2391 {
2392 /*
2393 * This call means we're done with the pointer so we can drop the
2394 * hold count.
2395 */
2396
2397 ASSERT(imp->ippm_hold_count != 0);
2398 atomic_dec_32(&(imp->ippm_hold_count));
2399
2400 /*
2401 * If the structure has 'destruct pending' set then we tried to free
2402 * it but couldn't, so do it now.
2403 */
2404
2405 LOCK_MOD(imp, RW_READER);
2406 if (imp->ippm_destruct_pending && imp->ippm_hold_count == 0) {
2407 UNLOCK_MOD(imp);
2408 kmem_cache_free(ipp_mod_cache, imp);
2409 return;
2410 }
2411
2412 UNLOCK_MOD(imp);
2413 }
2414 #undef __FN__
2415
2416 #define __FN__ "get_mid"
2417 static ipp_mod_id_t
get_mid(void)2418 get_mid(
2419 void)
2420 {
2421 int index;
2422 int start;
2423 int limit;
2424
2425 ASSERT(rw_write_held(ipp_mod_byid_lock));
2426
2427 /*
2428 * Start searching after the last module id we allocated.
2429 */
2430
2431 start = (int)ipp_next_mid;
2432 limit = (int)ipp_mid_limit;
2433
2434 /*
2435 * Look for a spare slot in the array.
2436 */
2437
2438 index = start;
2439 while (ipp_mod_byid[index] != NULL) {
2440 index++;
2441 if (index > limit)
2442 index = IPP_MOD_RESERVED + 1;
2443 if (index == start)
2444 return (IPP_MOD_INVAL);
2445 }
2446
2447 /*
2448 * Note that we've just allocated a new module id so that we can
2449 * start our search there next time.
2450 */
2451
2452 index++;
2453 if (index > limit) {
2454 ipp_next_mid = IPP_MOD_RESERVED + 1;
2455 } else
2456 ipp_next_mid = (ipp_mod_id_t)index;
2457
2458 return ((ipp_mod_id_t)(--index));
2459 }
2460 #undef __FN__
2461
2462 #define __FN__ "condemn_action"
2463 static int
condemn_action(ipp_ref_t ** rpp,ipp_action_t * ap)2464 condemn_action(
2465 ipp_ref_t **rpp,
2466 ipp_action_t *ap)
2467 {
2468 ipp_ref_t *rp;
2469
2470 DBG1(DBG_ACTION, "condemning action '%s'\n", ap->ippa_name);
2471
2472 /*
2473 * Check to see if the action is already condemned.
2474 */
2475
2476 while ((rp = *rpp) != NULL) {
2477 if (rp->ippr_action == ap)
2478 break;
2479 rpp = &(rp->ippr_nextp);
2480 }
2481
2482 /*
2483 * Create a new entry for the action.
2484 */
2485
2486 if (rp == NULL) {
2487 if ((rp = kmem_zalloc(sizeof (ipp_ref_t), KM_NOSLEEP)) == NULL)
2488 return (ENOMEM);
2489
2490 rp->ippr_action = ap;
2491 *rpp = rp;
2492 }
2493
2494 return (0);
2495 }
2496 #undef __FN__
2497
2498 #define __FN__ "destroy_action"
2499 static int
destroy_action(ipp_action_t * ap,ipp_flags_t flags)2500 destroy_action(
2501 ipp_action_t *ap,
2502 ipp_flags_t flags)
2503 {
2504 ipp_ops_t *ippo;
2505 ipp_mod_t *imp;
2506 #define MAXWAIT 10
2507 uint32_t wait;
2508 int rc;
2509
2510 /*
2511 * Check that the action is available.
2512 */
2513
2514 LOCK_ACTION(ap, RW_WRITER);
2515 if (ap->ippa_state != IPP_ASTATE_AVAILABLE) {
2516 UNLOCK_ACTION(ap);
2517 rele_action(ap);
2518 return (EPROTO);
2519 }
2520
2521 /*
2522 * Note that the action is in the process of creation/destruction.
2523 */
2524
2525 ap->ippa_state = IPP_ASTATE_CONFIG_PENDING;
2526
2527 /*
2528 * Wait for the in-transit packet count for this action to fall to
2529 * zero (checking at millisecond intervals).
2530 *
2531 * NOTE: no new packets will enter the action now that the
2532 * state has been changed.
2533 */
2534
2535 for (wait = 0; ap->ippa_packets > 0 && wait < (MAXWAIT * 1000000);
2536 wait += 1000) {
2537
2538 /*
2539 * NOTE: We can hang onto the lock because the packet count is
2540 * decremented without needing to take the lock.
2541 */
2542
2543 drv_usecwait(1000);
2544 }
2545
2546 /*
2547 * The packet count did not fall to zero.
2548 */
2549 if (ap->ippa_packets > 0) {
2550 ap->ippa_state = IPP_ASTATE_AVAILABLE;
2551 UNLOCK_ACTION(ap);
2552 rele_action(ap);
2553 return (EAGAIN);
2554 }
2555
2556 /*
2557 * Check to see if any other action has a dependency on this one.
2558 */
2559
2560 if (is_action_refd(ap)) {
2561 ap->ippa_state = IPP_ASTATE_AVAILABLE;
2562 UNLOCK_ACTION(ap);
2563 rele_action(ap);
2564 return (EBUSY);
2565 }
2566
2567 imp = ap->ippa_mod;
2568 ASSERT(imp != NULL);
2569 UNLOCK_ACTION(ap);
2570
2571 ippo = imp->ippm_ops;
2572 ASSERT(ippo != NULL);
2573
2574 /*
2575 * Call into the module to destroy the action context.
2576 */
2577
2578 CONFIG_WRITE_START(ap);
2579 DBG1(DBG_ACTION, "destroying action '%s'\n", ap->ippa_name);
2580 if ((rc = ippo->ippo_action_destroy(ap->ippa_id, flags)) != 0) {
2581 LOCK_ACTION(ap, RW_WRITER);
2582 ap->ippa_state = IPP_ASTATE_AVAILABLE;
2583 UNLOCK_ACTION(ap);
2584
2585 CONFIG_WRITE_END(ap);
2586
2587 rele_action(ap);
2588 return (rc);
2589 }
2590 CONFIG_WRITE_END(ap);
2591
2592 LOCK_ACTION(ap, RW_WRITER);
2593 LOCK_MOD(imp, RW_WRITER);
2594 unref_mod(ap, imp);
2595 UNLOCK_MOD(imp);
2596 ap->ippa_state = IPP_ASTATE_PROTO;
2597 UNLOCK_ACTION(ap);
2598
2599 /*
2600 * Free the action structure.
2601 */
2602
2603 ASSERT(ap->ippa_ref == NULL);
2604 free_action(ap);
2605 rele_action(ap);
2606 return (0);
2607 #undef MAXWAIT
2608 }
2609 #undef __FN__
2610
2611 #define __FN__ "ref_action"
2612 static int
ref_action(ipp_action_t * refby_ap,ipp_action_t * ref_ap)2613 ref_action(
2614 ipp_action_t *refby_ap,
2615 ipp_action_t *ref_ap)
2616 {
2617 ipp_ref_t **rpp;
2618 ipp_ref_t **save_rpp;
2619 ipp_ref_t *rp;
2620
2621 ASSERT(rw_write_held(refby_ap->ippa_lock));
2622 ASSERT(rw_write_held(ref_ap->ippa_lock));
2623
2624 /*
2625 * We want to add the new reference at the end of the refering
2626 * action's list.
2627 */
2628
2629 rpp = &(refby_ap->ippa_ref);
2630 while ((rp = *rpp) != NULL) {
2631 if (rp->ippr_action == ref_ap)
2632 break;
2633 rpp = &(rp->ippr_nextp);
2634 }
2635
2636 if ((rp = *rpp) != NULL) {
2637
2638 /*
2639 * There is an existing reference so increment its counter.
2640 */
2641
2642 rp->ippr_count++;
2643
2644 /*
2645 * Find the 'back pointer' and increment its counter too.
2646 */
2647
2648 rp = ref_ap->ippa_refby;
2649 while (rp != NULL) {
2650 if (rp->ippr_action == refby_ap)
2651 break;
2652 rp = rp->ippr_nextp;
2653 }
2654 ASSERT(rp != NULL);
2655
2656 rp->ippr_count++;
2657 } else {
2658
2659 /*
2660 * Allocate, fill in and link a new reference structure.
2661 */
2662
2663 if ((rp = kmem_zalloc(sizeof (ipp_ref_t), KM_NOSLEEP)) == NULL)
2664 return (ENOMEM);
2665
2666 rp->ippr_action = ref_ap;
2667 rp->ippr_count = 1;
2668 *rpp = rp;
2669 save_rpp = rpp;
2670
2671 /*
2672 * We keep a 'back pointer' which we want to add at the end of
2673 * a list in the referred action's structure.
2674 */
2675
2676 rpp = &(ref_ap->ippa_refby);
2677 while ((rp = *rpp) != NULL) {
2678 ASSERT(rp->ippr_action != refby_ap);
2679 rpp = &(rp->ippr_nextp);
2680 }
2681
2682 /*
2683 * Allocate another reference structure and, if this fails,
2684 * remember to clean up the first reference structure we
2685 * allocated.
2686 */
2687
2688 if ((rp = kmem_zalloc(sizeof (ipp_ref_t),
2689 KM_NOSLEEP)) == NULL) {
2690 rpp = save_rpp;
2691 rp = *rpp;
2692 *rpp = NULL;
2693 kmem_free(rp, sizeof (ipp_ref_t));
2694
2695 return (ENOMEM);
2696 }
2697
2698 /*
2699 * Fill in the reference structure with the 'back pointer' and
2700 * link it into the list.
2701 */
2702
2703 rp->ippr_action = refby_ap;
2704 rp->ippr_count = 1;
2705 *rpp = rp;
2706 }
2707
2708 return (0);
2709 }
2710 #undef __FN__
2711
2712 #define __FN__ "unref_action"
2713 static int
unref_action(ipp_action_t * refby_ap,ipp_action_t * ref_ap)2714 unref_action(
2715 ipp_action_t *refby_ap,
2716 ipp_action_t *ref_ap)
2717 {
2718 ipp_ref_t **rpp;
2719 ipp_ref_t *rp;
2720
2721 ASSERT(rw_write_held(refby_ap->ippa_lock));
2722 ASSERT(rw_write_held(ref_ap->ippa_lock));
2723
2724 /*
2725 * Scan for the reference in the referring action's list.
2726 */
2727
2728 rpp = &(refby_ap->ippa_ref);
2729 while ((rp = *rpp) != NULL) {
2730 if (rp->ippr_action == ref_ap)
2731 break;
2732 rpp = &(rp->ippr_nextp);
2733 }
2734
2735 if (rp == NULL)
2736 return (ENOENT);
2737
2738 if (rp->ippr_count > 1) {
2739
2740 /*
2741 * There are currently multiple references so decrement the
2742 * count.
2743 */
2744
2745 rp->ippr_count--;
2746
2747 /*
2748 * Find the 'back pointer' and decrement its counter too.
2749 */
2750
2751 rp = ref_ap->ippa_refby;
2752 while (rp != NULL) {
2753 if (rp->ippr_action == refby_ap)
2754 break;
2755 rp = rp->ippr_nextp;
2756 }
2757 ASSERT(rp != NULL);
2758
2759 rp->ippr_count--;
2760 } else {
2761
2762 /*
2763 * There is currently only a single reference, so unlink and
2764 * free the reference structure.
2765 */
2766
2767 *rpp = rp->ippr_nextp;
2768 kmem_free(rp, sizeof (ipp_ref_t));
2769
2770 /*
2771 * Scan for the 'back pointer' in the referred action's list.
2772 */
2773
2774 rpp = &(ref_ap->ippa_refby);
2775 while ((rp = *rpp) != NULL) {
2776 if (rp->ippr_action == refby_ap)
2777 break;
2778 rpp = &(rp->ippr_nextp);
2779 }
2780 ASSERT(rp != NULL);
2781
2782 /*
2783 * Unlink and free this reference structure too.
2784 */
2785
2786 *rpp = rp->ippr_nextp;
2787 kmem_free(rp, sizeof (ipp_ref_t));
2788 }
2789
2790 return (0);
2791 }
2792 #undef __FN__
2793
2794 #define __FN__ "is_action_refd"
2795 static int
is_action_refd(ipp_action_t * ap)2796 is_action_refd(
2797 ipp_action_t *ap)
2798 {
2799 /*
2800 * Return a value which is true (non-zero) iff the action is not
2801 * referred to by any other actions.
2802 */
2803
2804 return (ap->ippa_refby != NULL);
2805 }
2806 #undef __FN__
2807
2808 #define __FN__ "find_action"
2809 static ipp_action_id_t
find_action(const char * aname)2810 find_action(
2811 const char *aname)
2812 {
2813 ipp_action_id_t aid;
2814 ipp_action_t *ap;
2815 ipp_ref_t *rp;
2816 int hb;
2817
2818 ASSERT(aname != NULL);
2819
2820 rw_enter(ipp_action_byname_lock, RW_READER);
2821
2822 /*
2823 * Quick return if there are no actions defined at all.
2824 */
2825
2826 if (ipp_action_count == 0) {
2827 rw_exit(ipp_action_byname_lock);
2828 return (IPP_ACTION_INVAL);
2829 }
2830
2831 /*
2832 * Find the hash bucket where the action structure should be.
2833 */
2834
2835 hb = hash(aname);
2836 rp = ipp_action_byname[hb];
2837
2838 /*
2839 * Scan the bucket looking for a match.
2840 */
2841
2842 while (rp != NULL) {
2843 ap = rp->ippr_action;
2844 if (strcmp(ap->ippa_name, aname) == 0)
2845 break;
2846 rp = rp->ippr_nextp;
2847 }
2848
2849 if (rp == NULL) {
2850 rw_exit(ipp_action_byname_lock);
2851 return (IPP_ACTION_INVAL);
2852 }
2853
2854 if (ap->ippa_state == IPP_ASTATE_PROTO) {
2855 rw_exit(ipp_action_byname_lock);
2856 return (IPP_ACTION_INVAL);
2857 }
2858
2859 aid = ap->ippa_id;
2860 rw_exit(ipp_action_byname_lock);
2861
2862 return (aid);
2863 }
2864 #undef __FN__
2865
2866 #define __FN__ "alloc_action"
2867 static int
alloc_action(const char * aname,ipp_action_id_t * aidp)2868 alloc_action(
2869 const char *aname,
2870 ipp_action_id_t *aidp)
2871 {
2872 ipp_action_t *ap;
2873 ipp_ref_t **rpp;
2874 ipp_ref_t *rp;
2875 int hb;
2876
2877 ASSERT(aidp != NULL);
2878
2879 rw_enter(ipp_action_byname_lock, RW_WRITER);
2880
2881 /*
2882 * Find the right hash bucket for an action of the given name.
2883 * (Nameless actions always go in a special bucket).
2884 */
2885
2886 if (aname != NULL) {
2887 hb = hash(aname);
2888 rpp = &ipp_action_byname[hb];
2889 } else
2890 rpp = &ipp_action_noname;
2891
2892 /*
2893 * Scan the bucket to make sure that an action with the given name
2894 * does not already exist.
2895 */
2896
2897 while ((rp = *rpp) != NULL) {
2898 ap = rp->ippr_action;
2899 if (aname != NULL && strcmp(ap->ippa_name, aname) == 0) {
2900 DBG1(DBG_ACTION, "action '%s' already exists\n",
2901 aname);
2902 rw_exit(ipp_action_byname_lock);
2903 return (EEXIST);
2904 }
2905 rpp = &(rp->ippr_nextp);
2906 }
2907
2908 /*
2909 * Allocate a new reference structure and a new action structure.
2910 */
2911
2912 if ((rp = kmem_zalloc(sizeof (ipp_ref_t), KM_NOSLEEP)) == NULL) {
2913 rw_exit(ipp_action_byname_lock);
2914 return (ENOMEM);
2915 }
2916
2917 if ((ap = kmem_cache_alloc(ipp_action_cache, KM_NOSLEEP)) == NULL) {
2918 kmem_free(rp, sizeof (ipp_ref_t));
2919 rw_exit(ipp_action_byname_lock);
2920 return (ENOMEM);
2921 }
2922
2923 /*
2924 * Dream up a name if there isn't a real one and note that the action is
2925 * really nameless.
2926 */
2927
2928 if (aname == NULL) {
2929 (void) sprintf(ap->ippa_name, "$%08X", ap->ippa_id);
2930 ap->ippa_nameless = B_TRUE;
2931 } else
2932 (void) strcpy(ap->ippa_name, aname);
2933
2934 /*
2935 * Make sure the 'destruct pending' flag is clear. This indicates that
2936 * the structure is no longer part of the cache.
2937 */
2938
2939 LOCK_ACTION(ap, RW_WRITER);
2940 ap->ippa_destruct_pending = B_FALSE;
2941 UNLOCK_ACTION(ap);
2942
2943 /*
2944 * Fill in the reference structure and lint it onto the list.
2945 */
2946
2947 rp->ippr_action = ap;
2948 *rpp = rp;
2949
2950 /*
2951 * Increment the action count.
2952 */
2953
2954 ipp_action_count++;
2955
2956 *aidp = ap->ippa_id;
2957 rw_exit(ipp_action_byname_lock);
2958 return (0);
2959 }
2960 #undef __FN__
2961
2962 #define __FN__ "free_action"
2963 static void
free_action(ipp_action_t * ap)2964 free_action(
2965 ipp_action_t *ap)
2966 {
2967 ipp_ref_t **rpp;
2968 ipp_ref_t *rp;
2969 int hb;
2970
2971 rw_enter(ipp_action_byname_lock, RW_WRITER);
2972
2973 /*
2974 * Find the hash bucket where the action structure should be.
2975 */
2976
2977 if (!ap->ippa_nameless) {
2978 hb = hash(ap->ippa_name);
2979 rpp = &ipp_action_byname[hb];
2980 } else
2981 rpp = &ipp_action_noname;
2982
2983 /*
2984 * Scan the bucket for a match.
2985 */
2986
2987 while ((rp = *rpp) != NULL) {
2988 if (rp->ippr_action == ap)
2989 break;
2990 rpp = &(rp->ippr_nextp);
2991 }
2992 ASSERT(rp != NULL);
2993
2994 /*
2995 * Unlink and free the reference structure.
2996 */
2997
2998 *rpp = rp->ippr_nextp;
2999 kmem_free(rp, sizeof (ipp_ref_t));
3000
3001 /*
3002 * Decrement the action count.
3003 */
3004
3005 ipp_action_count--;
3006
3007 /*
3008 * Empty the name.
3009 */
3010
3011 *ap->ippa_name = '\0';
3012
3013 /*
3014 * If the hold count is zero then we can free the structure
3015 * immediately, otherwise we defer to rele_action().
3016 */
3017
3018 LOCK_ACTION(ap, RW_WRITER);
3019 ap->ippa_destruct_pending = B_TRUE;
3020 if (ap->ippa_hold_count == 0) {
3021 UNLOCK_ACTION(ap);
3022 kmem_cache_free(ipp_action_cache, ap);
3023 rw_exit(ipp_action_byname_lock);
3024 return;
3025 }
3026 UNLOCK_ACTION(ap);
3027
3028 rw_exit(ipp_action_byname_lock);
3029 }
3030 #undef __FN__
3031
3032 #define __FN__ "hold_action"
3033 static ipp_action_t *
hold_action(ipp_action_id_t aid)3034 hold_action(
3035 ipp_action_id_t aid)
3036 {
3037 ipp_action_t *ap;
3038
3039 if (aid < 0)
3040 return (NULL);
3041
3042 /*
3043 * Use the action id as an index into the array of all action
3044 * structures.
3045 */
3046
3047 rw_enter(ipp_action_byid_lock, RW_READER);
3048 if ((ap = ipp_action_byid[aid]) == NULL) {
3049 rw_exit(ipp_action_byid_lock);
3050 return (NULL);
3051 }
3052
3053 /*
3054 * If the action has 'destruct pending' set then it means it is either
3055 * still in the cache (i.e not allocated) or in the process of
3056 * being set up by alloc_action().
3057 */
3058
3059 LOCK_ACTION(ap, RW_READER);
3060 if (ap->ippa_destruct_pending) {
3061 UNLOCK_ACTION(ap);
3062 rw_exit(ipp_action_byid_lock);
3063 return (NULL);
3064 }
3065 UNLOCK_ACTION(ap);
3066
3067 /*
3068 * Increment the hold count to prevent the structure from being
3069 * freed.
3070 */
3071
3072 atomic_inc_32(&(ap->ippa_hold_count));
3073 rw_exit(ipp_action_byid_lock);
3074
3075 return (ap);
3076 }
3077 #undef __FN__
3078
3079 #define __FN__ "rele_action"
3080 static void
rele_action(ipp_action_t * ap)3081 rele_action(
3082 ipp_action_t *ap)
3083 {
3084 /*
3085 * This call means we're done with the pointer so we can drop the
3086 * hold count.
3087 */
3088
3089 ASSERT(ap->ippa_hold_count != 0);
3090 atomic_dec_32(&(ap->ippa_hold_count));
3091
3092 /*
3093 * If the structure has 'destruct pending' set then we tried to free
3094 * it but couldn't, so do it now.
3095 */
3096
3097 LOCK_ACTION(ap, RW_READER);
3098 if (ap->ippa_destruct_pending && ap->ippa_hold_count == 0) {
3099 UNLOCK_ACTION(ap);
3100 kmem_cache_free(ipp_action_cache, ap);
3101 return;
3102 }
3103 UNLOCK_ACTION(ap);
3104 }
3105 #undef __FN__
3106
3107 #define __FN__ "get_aid"
3108 static ipp_action_id_t
get_aid(void)3109 get_aid(
3110 void)
3111 {
3112 int index;
3113 int start;
3114 int limit;
3115
3116 ASSERT(rw_write_held(ipp_action_byid_lock));
3117
3118 /*
3119 * Start searching after the last action id that we allocated.
3120 */
3121
3122 start = (int)ipp_next_aid;
3123 limit = (int)ipp_aid_limit;
3124
3125 /*
3126 * Look for a spare slot in the array.
3127 */
3128
3129 index = start;
3130 while (ipp_action_byid[index] != NULL) {
3131 index++;
3132 if (index > limit)
3133 index = IPP_ACTION_RESERVED + 1;
3134 if (index == start)
3135 return (IPP_ACTION_INVAL);
3136 }
3137
3138 /*
3139 * Note that we've just allocated a new action id so that we can
3140 * start our search there next time.
3141 */
3142
3143 index++;
3144 if (index > limit)
3145 ipp_next_aid = IPP_ACTION_RESERVED + 1;
3146 else
3147 ipp_next_aid = (ipp_action_id_t)index;
3148
3149 return ((ipp_action_id_t)(--index));
3150 }
3151 #undef __FN__
3152
3153 #define __FN__ "alloc_packet"
3154 static int
alloc_packet(const char * name,ipp_action_id_t aid,ipp_packet_t ** ppp)3155 alloc_packet(
3156 const char *name,
3157 ipp_action_id_t aid,
3158 ipp_packet_t **ppp)
3159 {
3160 ipp_packet_t *pp;
3161 ipp_class_t *cp;
3162
3163 if ((pp = kmem_cache_alloc(ipp_packet_cache, KM_NOSLEEP)) == NULL)
3164 return (ENOMEM);
3165
3166 /*
3167 * Set the packet up with a single class.
3168 */
3169
3170 cp = &(pp->ippp_class_array[0]);
3171 pp->ippp_class_windex = 1;
3172
3173 (void) strcpy(cp->ippc_name, name);
3174 cp->ippc_aid = aid;
3175
3176 *ppp = pp;
3177 return (0);
3178 }
3179 #undef __FN__
3180
3181 #define __FN__ "realloc_packet"
3182 static int
realloc_packet(ipp_packet_t * pp)3183 realloc_packet(
3184 ipp_packet_t *pp)
3185 {
3186 uint_t length;
3187 ipp_class_t *array;
3188
3189 length = (pp->ippp_class_limit + 1) << 1;
3190 if ((array = kmem_alloc(length * sizeof (ipp_class_t),
3191 KM_NOSLEEP)) == NULL)
3192 return (ENOMEM);
3193
3194 bcopy(pp->ippp_class_array, array,
3195 (length >> 1) * sizeof (ipp_class_t));
3196
3197 kmem_free(pp->ippp_class_array,
3198 (length >> 1) * sizeof (ipp_class_t));
3199
3200 pp->ippp_class_array = array;
3201 pp->ippp_class_limit = length - 1;
3202
3203 return (0);
3204 }
3205 #undef __FN__
3206
3207 #define __FN__ "free_packet"
3208 static void
free_packet(ipp_packet_t * pp)3209 free_packet(
3210 ipp_packet_t *pp)
3211 {
3212 pp->ippp_class_windex = 0;
3213 pp->ippp_class_rindex = 0;
3214
3215 pp->ippp_data = NULL;
3216 pp->ippp_private = NULL;
3217
3218 kmem_cache_free(ipp_packet_cache, pp);
3219 }
3220 #undef __FN__
3221
3222 #define __FN__ "hash"
3223 static int
hash(const char * name)3224 hash(
3225 const char *name)
3226 {
3227 int val = 0;
3228 char *ptr;
3229
3230 /*
3231 * Make a hash value by XORing all the ascii codes in the text string.
3232 */
3233
3234 for (ptr = (char *)name; *ptr != '\0'; ptr++) {
3235 val ^= *ptr;
3236 }
3237
3238 /*
3239 * Return the value modulo the number of hash buckets we allow.
3240 */
3241
3242 return (val % IPP_NBUCKET);
3243 }
3244 #undef __FN__
3245
3246 #define __FN__ "update_stats"
3247 static int
update_stats(kstat_t * ksp,int rw)3248 update_stats(
3249 kstat_t *ksp,
3250 int rw)
3251 {
3252 ipp_stat_impl_t *sip;
3253
3254 ASSERT(ksp->ks_private != NULL);
3255 sip = (ipp_stat_impl_t *)ksp->ks_private;
3256
3257 /*
3258 * Call the update function passed to ipp_stat_create() for the given
3259 * set of kstats.
3260 */
3261
3262 return (sip->ippsi_update((ipp_stat_t *)sip, sip->ippsi_arg, rw));
3263 }
3264 #undef __FN__
3265
3266 #define __FN__ "init_mods"
3267 static void
init_mods(void)3268 init_mods(
3269 void)
3270 {
3271 /*
3272 * Initialise the array of all module structures and the module
3273 * structure kmem cache.
3274 */
3275
3276 rw_init(ipp_mod_byid_lock, NULL, RW_DEFAULT,
3277 (void *)ipltospl(LOCK_LEVEL));
3278 ipp_mod_byid = kmem_zalloc(sizeof (ipp_mod_t *) * (ipp_max_mod + 1),
3279 KM_SLEEP);
3280 ipp_mod_byid[ipp_max_mod] = (ipp_mod_t *)-1;
3281 ipp_mid_limit = (ipp_mod_id_t)(ipp_max_mod - 1);
3282
3283 ipp_mod_cache = kmem_cache_create("ipp_mod", sizeof (ipp_mod_t),
3284 IPP_ALIGN, mod_constructor, mod_destructor, NULL, NULL, NULL, 0);
3285 ASSERT(ipp_mod_cache != NULL);
3286
3287 /*
3288 * Initialize the 'module by name' hash bucket array.
3289 */
3290
3291 rw_init(ipp_mod_byname_lock, NULL, RW_DEFAULT,
3292 (void *)ipltospl(LOCK_LEVEL));
3293 bzero(ipp_mod_byname, IPP_NBUCKET * sizeof (ipp_ref_t *));
3294 }
3295 #undef __FN__
3296
3297 #define __FN__ "init_actions"
3298 static void
init_actions(void)3299 init_actions(
3300 void)
3301 {
3302 /*
3303 * Initialise the array of all action structures and the action
3304 * structure cache.
3305 */
3306
3307 rw_init(ipp_action_byid_lock, NULL, RW_DEFAULT,
3308 (void *)ipltospl(LOCK_LEVEL));
3309 ipp_action_byid = kmem_zalloc(sizeof (ipp_action_t *) *
3310 (ipp_max_action + 1), KM_SLEEP);
3311 ipp_action_byid[ipp_max_action] = (ipp_action_t *)-1;
3312 ipp_aid_limit = (ipp_action_id_t)(ipp_max_action - 1);
3313
3314 ipp_action_cache = kmem_cache_create("ipp_action",
3315 sizeof (ipp_action_t), IPP_ALIGN, action_constructor,
3316 action_destructor, NULL, NULL, NULL, 0);
3317 ASSERT(ipp_action_cache != NULL);
3318
3319 /*
3320 * Initialize the 'action by name' hash bucket array (and the special
3321 * 'hash' bucket for nameless actions).
3322 */
3323
3324 rw_init(ipp_action_byname_lock, NULL, RW_DEFAULT,
3325 (void *)ipltospl(LOCK_LEVEL));
3326 bzero(ipp_action_byname, IPP_NBUCKET * sizeof (ipp_ref_t *));
3327 ipp_action_noname = NULL;
3328 }
3329 #undef __FN__
3330
3331 #define __FN__ "init_packets"
3332 static void
init_packets(void)3333 init_packets(
3334 void)
3335 {
3336 /*
3337 * Initialise the packet structure cache.
3338 */
3339
3340 ipp_packet_cache = kmem_cache_create("ipp_packet",
3341 sizeof (ipp_packet_t), IPP_ALIGN, packet_constructor,
3342 packet_destructor, NULL, NULL, NULL, 0);
3343 ASSERT(ipp_packet_cache != NULL);
3344 }
3345 #undef __FN__
3346
3347 /*
3348 * Kmem cache constructor/destructor functions.
3349 */
3350
3351 #define __FN__ "mod_constructor"
3352 /*ARGSUSED*/
3353 static int
mod_constructor(void * buf,void * cdrarg,int kmflags)3354 mod_constructor(
3355 void *buf,
3356 void *cdrarg,
3357 int kmflags)
3358 {
3359 ipp_mod_t *imp;
3360 ipp_mod_id_t mid;
3361
3362 ASSERT(buf != NULL);
3363 bzero(buf, sizeof (ipp_mod_t));
3364 imp = (ipp_mod_t *)buf;
3365
3366 rw_enter(ipp_mod_byid_lock, RW_WRITER);
3367
3368 /*
3369 * Get a new module id.
3370 */
3371
3372 if ((mid = get_mid()) <= IPP_MOD_RESERVED) {
3373 rw_exit(ipp_mod_byid_lock);
3374 return (-1);
3375 }
3376
3377 /*
3378 * Initialize the buffer as a module structure in PROTO form.
3379 */
3380
3381 imp->ippm_destruct_pending = B_TRUE;
3382 imp->ippm_state = IPP_MODSTATE_PROTO;
3383 rw_init(imp->ippm_lock, NULL, RW_DEFAULT,
3384 (void *)ipltospl(LOCK_LEVEL));
3385
3386 /*
3387 * Insert it into the array of all module structures.
3388 */
3389
3390 imp->ippm_id = mid;
3391 ipp_mod_byid[mid] = imp;
3392
3393 rw_exit(ipp_mod_byid_lock);
3394
3395 return (0);
3396 }
3397 #undef __FN__
3398
3399 #define __FN__ "mod_destructor"
3400 /*ARGSUSED*/
3401 static void
mod_destructor(void * buf,void * cdrarg)3402 mod_destructor(
3403 void *buf,
3404 void *cdrarg)
3405 {
3406 ipp_mod_t *imp;
3407
3408 ASSERT(buf != NULL);
3409 imp = (ipp_mod_t *)buf;
3410
3411 ASSERT(imp->ippm_state == IPP_MODSTATE_PROTO);
3412 ASSERT(imp->ippm_action == NULL);
3413 ASSERT(*imp->ippm_name == '\0');
3414 ASSERT(imp->ippm_destruct_pending);
3415
3416 rw_enter(ipp_mod_byid_lock, RW_WRITER);
3417 ASSERT(imp->ippm_hold_count == 0);
3418
3419 /*
3420 * NULL the entry in the array of all module structures.
3421 */
3422
3423 ipp_mod_byid[imp->ippm_id] = NULL;
3424
3425 /*
3426 * Clean up any remnants of the module structure as the buffer is
3427 * about to disappear.
3428 */
3429
3430 rw_destroy(imp->ippm_lock);
3431 rw_exit(ipp_mod_byid_lock);
3432 }
3433 #undef __FN__
3434
3435 #define __FN__ "action_constructor"
3436 /*ARGSUSED*/
3437 static int
action_constructor(void * buf,void * cdrarg,int kmflags)3438 action_constructor(
3439 void *buf,
3440 void *cdrarg,
3441 int kmflags)
3442 {
3443 ipp_action_t *ap;
3444 ipp_action_id_t aid;
3445
3446 ASSERT(buf != NULL);
3447 bzero(buf, sizeof (ipp_action_t));
3448 ap = (ipp_action_t *)buf;
3449
3450 rw_enter(ipp_action_byid_lock, RW_WRITER);
3451
3452 /*
3453 * Get a new action id.
3454 */
3455
3456 if ((aid = get_aid()) <= IPP_ACTION_RESERVED) {
3457 rw_exit(ipp_action_byid_lock);
3458 return (-1);
3459 }
3460
3461 /*
3462 * Initialize the buffer as an action structure in PROTO form.
3463 */
3464
3465 ap->ippa_state = IPP_ASTATE_PROTO;
3466 ap->ippa_destruct_pending = B_TRUE;
3467 rw_init(ap->ippa_lock, NULL, RW_DEFAULT,
3468 (void *)ipltospl(LOCK_LEVEL));
3469 CONFIG_LOCK_INIT(ap->ippa_config_lock);
3470
3471 /*
3472 * Insert it into the array of all action structures.
3473 */
3474
3475 ap->ippa_id = aid;
3476 ipp_action_byid[aid] = ap;
3477
3478 rw_exit(ipp_action_byid_lock);
3479 return (0);
3480 }
3481 #undef __FN__
3482
3483 #define __FN__ "action_destructor"
3484 /*ARGSUSED*/
3485 static void
action_destructor(void * buf,void * cdrarg)3486 action_destructor(
3487 void *buf,
3488 void *cdrarg)
3489 {
3490 ipp_action_t *ap;
3491
3492 ASSERT(buf != NULL);
3493 ap = (ipp_action_t *)buf;
3494
3495 ASSERT(ap->ippa_state == IPP_ASTATE_PROTO);
3496 ASSERT(ap->ippa_ref == NULL);
3497 ASSERT(ap->ippa_refby == NULL);
3498 ASSERT(ap->ippa_packets == 0);
3499 ASSERT(*ap->ippa_name == '\0');
3500 ASSERT(ap->ippa_destruct_pending);
3501
3502 rw_enter(ipp_action_byid_lock, RW_WRITER);
3503 ASSERT(ap->ippa_hold_count == 0);
3504
3505 /*
3506 * NULL the entry in the array of all action structures.
3507 */
3508
3509 ipp_action_byid[ap->ippa_id] = NULL;
3510
3511 /*
3512 * Clean up any remnants of the action structure as the buffer is
3513 * about to disappear.
3514 */
3515
3516 CONFIG_LOCK_FINI(ap->ippa_config_lock);
3517 rw_destroy(ap->ippa_lock);
3518
3519 rw_exit(ipp_action_byid_lock);
3520 }
3521 #undef __FN__
3522
3523 #define __FN__ "packet_constructor"
3524 /*ARGSUSED*/
3525 static int
packet_constructor(void * buf,void * cdrarg,int kmflags)3526 packet_constructor(
3527 void *buf,
3528 void *cdrarg,
3529 int kmflags)
3530 {
3531 ipp_packet_t *pp;
3532 ipp_class_t *cp;
3533
3534 ASSERT(buf != NULL);
3535 bzero(buf, sizeof (ipp_packet_t));
3536 pp = (ipp_packet_t *)buf;
3537
3538 if ((cp = kmem_alloc(ipp_packet_classes * sizeof (ipp_class_t),
3539 KM_NOSLEEP)) == NULL)
3540 return (ENOMEM);
3541
3542 pp->ippp_class_array = cp;
3543 pp->ippp_class_windex = 0;
3544 pp->ippp_class_rindex = 0;
3545 pp->ippp_class_limit = ipp_packet_classes - 1;
3546
3547 return (0);
3548 }
3549 #undef __FN__
3550
3551 #define __FN__ "packet_destructor"
3552 /*ARGSUSED*/
3553 static void
packet_destructor(void * buf,void * cdrarg)3554 packet_destructor(
3555 void *buf,
3556 void *cdrarg)
3557 {
3558 ipp_packet_t *pp;
3559
3560 ASSERT(buf != NULL);
3561 pp = (ipp_packet_t *)buf;
3562
3563 ASSERT(pp->ippp_data == NULL);
3564 ASSERT(pp->ippp_class_windex == 0);
3565 ASSERT(pp->ippp_class_rindex == 0);
3566 ASSERT(pp->ippp_private == NULL);
3567 ASSERT(pp->ippp_private_free == NULL);
3568
3569 kmem_free(pp->ippp_class_array,
3570 (pp->ippp_class_limit + 1) * sizeof (ipp_class_t));
3571
3572 if (pp->ippp_log != NULL) {
3573 kmem_free(pp->ippp_log,
3574 (pp->ippp_log_limit + 1) * sizeof (ipp_log_t));
3575 }
3576 }
3577 #undef __FN__
3578
3579 /*
3580 * Debug message printout code.
3581 */
3582
3583 #ifdef IPP_DBG
3584 static void
ipp_debug(uint64_t type,const char * fn,char * fmt,...)3585 ipp_debug(
3586 uint64_t type,
3587 const char *fn,
3588 char *fmt,
3589 ...)
3590 {
3591 char buf[255];
3592 va_list adx;
3593
3594 if ((type & ipp_debug_flags) == 0)
3595 return;
3596
3597 mutex_enter(debug_mutex);
3598 va_start(adx, fmt);
3599 (void) vsnprintf(buf, 255, fmt, adx);
3600 va_end(adx);
3601
3602 printf("(%llx) %s: %s", (unsigned long long)curthread->t_did, fn,
3603 buf);
3604 mutex_exit(debug_mutex);
3605 }
3606 #endif /* IPP_DBG */
3607