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, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#include <sys/conf.h>
30#include <sys/sysmacros.h>
31#include <sys/async.h>
32
33static bus_func_desc_t *bfd_list = NULL; /* list of busfunc descriptors */
34kmutex_t bfd_lock;		/* lock protecting bfd_list */
35
36/*
37 * Register a new bus function.  We expect this function to be called from a
38 * driver attach or detach routine, so we can safely perform a sleeping
39 * allocation here.  We just insert the new element at the head of the list.
40 * For more information on bus_func semantics, refer to sun4u/sys/async.h.
41 */
42void
43bus_func_register(int type, busfunc_t func, void *arg)
44{
45	bus_func_desc_t *bfd = kmem_alloc(sizeof (bus_func_desc_t), KM_SLEEP);
46
47	bfd->bf_type = type;
48	bfd->bf_func = func;
49	bfd->bf_arg = arg;
50
51	mutex_enter(&bfd_lock);
52	bfd->bf_next = bfd_list;
53	bfd_list = bfd;
54	mutex_exit(&bfd_lock);
55}
56
57/*
58 * Unregister the specified bus function.  We only delete an element that
59 * exactly matches the specified (type, func, arg) tuple.  We expect this
60 * function to only be called from driver detach context.
61 */
62void
63bus_func_unregister(int type, busfunc_t func, void *arg)
64{
65	bus_func_desc_t *bfd, **pp;
66
67	mutex_enter(&bfd_lock);
68	pp = &bfd_list;
69
70	for (bfd = bfd_list; bfd != NULL; bfd = bfd->bf_next) {
71		if (bfd->bf_type == type && bfd->bf_func == func &&
72		    bfd->bf_arg == arg) {
73			*pp = bfd->bf_next;
74			break;
75		}
76		pp = &bfd->bf_next;
77	}
78
79	mutex_exit(&bfd_lock);
80
81	if (bfd != NULL)
82		kmem_free(bfd, sizeof (bus_func_desc_t));
83}
84
85/*
86 * Invoke the registered bus functions of the specified type.  We return the
87 * maximum of the result values (e.g. BF_FATAL if any call returned BF_FATAL).
88 * This function assumes that (1) the BF_* constants are defined so that the
89 * most fatal error has the highest numerical value, and (2) that the bf_func
90 * callbacks obey the rules described in async.h.
91 */
92uint_t
93bus_func_invoke(int type)
94{
95	bus_func_desc_t *bfd;
96	uint_t err = BF_NONE;
97
98	mutex_enter(&bfd_lock);
99
100	for (bfd = bfd_list; bfd != NULL; bfd = bfd->bf_next) {
101		if (bfd->bf_type == type) {
102			uint_t status = bfd->bf_func(bfd->bf_arg);
103			err = MAX(err, status);
104		}
105	}
106
107	mutex_exit(&bfd_lock);
108	return (err);
109}
110