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