xref: /illumos-gate/usr/src/uts/common/os/ksensor.c (revision 3ce5372277f4657ad0e52d36c979527c4ca22de2)
1*3ce53722SRobert Mustacchi /*
2*3ce53722SRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*3ce53722SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*3ce53722SRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*3ce53722SRobert Mustacchi  * 1.0 of the CDDL.
6*3ce53722SRobert Mustacchi  *
7*3ce53722SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*3ce53722SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*3ce53722SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*3ce53722SRobert Mustacchi  */
11*3ce53722SRobert Mustacchi 
12*3ce53722SRobert Mustacchi /*
13*3ce53722SRobert Mustacchi  * Copyright 2020 Oxide Computer Company
14*3ce53722SRobert Mustacchi  */
15*3ce53722SRobert Mustacchi 
16*3ce53722SRobert Mustacchi /*
17*3ce53722SRobert Mustacchi  * Kernel Sensor Framework
18*3ce53722SRobert Mustacchi  *
19*3ce53722SRobert Mustacchi  * The kernel sensor framework exists to provide a simple and straightforward
20*3ce53722SRobert Mustacchi  * means for various parts of the system to declare and instantiate sensor
21*3ce53722SRobert Mustacchi  * information. Between this and the ksensor character device
22*3ce53722SRobert Mustacchi  * (uts/common/io/ksensor/ksensor_drv.c) this exposes per-device sensors and
23*3ce53722SRobert Mustacchi  * character devices.
24*3ce53722SRobert Mustacchi  *
25*3ce53722SRobert Mustacchi  * --------------------------
26*3ce53722SRobert Mustacchi  * Driver and User Interfaces
27*3ce53722SRobert Mustacchi  * --------------------------
28*3ce53722SRobert Mustacchi  *
29*3ce53722SRobert Mustacchi  * Each sensor that is registered with the framework is exposed as a character
30*3ce53722SRobert Mustacchi  * device under /dev/sensors. The device class and node name are often ':'
31*3ce53722SRobert Mustacchi  * delineated and must begin with 'ddi_sensor'. Everything after 'ddi_sensor'
32*3ce53722SRobert Mustacchi  * will be created in a directory under /dev/sensors. So for example the Intel
33*3ce53722SRobert Mustacchi  * PCH driver uses a class "ddi_sensor:temperature:pch" and a node name of
34*3ce53722SRobert Mustacchi  * 'ts.%d'. This creates the node /dev/sensors/temperature/pch/ts.0. The
35*3ce53722SRobert Mustacchi  * devfsadm plugin automatically handles the creation of directories which makes
36*3ce53722SRobert Mustacchi  * the addition of additional sensor types easy to create.
37*3ce53722SRobert Mustacchi  *
38*3ce53722SRobert Mustacchi  * Strictly speaking, any device can manage their own sensors and minor nodes by
39*3ce53722SRobert Mustacchi  * using the appropriate class and implementing the corresponding ioctls. That
40*3ce53722SRobert Mustacchi  * was how the first kernel sensors were written; however, there are a lot of
41*3ce53722SRobert Mustacchi  * issues with that which led to this:
42*3ce53722SRobert Mustacchi  *
43*3ce53722SRobert Mustacchi  * 1. Every driver had to actually implement character devices.
44*3ce53722SRobert Mustacchi  *
45*3ce53722SRobert Mustacchi  * 2. Every driver had to duplicate a lot of the logic around open(9E),
46*3ce53722SRobert Mustacchi  *    close(9E), and ioctl(9E).
47*3ce53722SRobert Mustacchi  *
48*3ce53722SRobert Mustacchi  * 3. Drivers that tied into frameworks like mac(9E) or SCSAv3 needed a lot more
49*3ce53722SRobert Mustacchi  *    work to fit into this model. For example, because the minor state is
50*3ce53722SRobert Mustacchi  *    shared between all the instances and the frameworks, they would have
51*3ce53722SRobert Mustacchi  *    required shared, global state that they don't have today.
52*3ce53722SRobert Mustacchi  *
53*3ce53722SRobert Mustacchi  * Ultimately, having an operations vector and a callback argument makes work a
54*3ce53722SRobert Mustacchi  * lot simpler for the producers of sensor data and that simplicity makes it
55*3ce53722SRobert Mustacchi  * worthwhile to take on additional effort and work here.
56*3ce53722SRobert Mustacchi  *
57*3ce53722SRobert Mustacchi  * ----------
58*3ce53722SRobert Mustacchi  * Components
59*3ce53722SRobert Mustacchi  * ----------
60*3ce53722SRobert Mustacchi  *
61*3ce53722SRobert Mustacchi  * The ksensor framework is made of a couple of different pieces:
62*3ce53722SRobert Mustacchi  *
63*3ce53722SRobert Mustacchi  * 1. This glue that is a part of genunix.
64*3ce53722SRobert Mustacchi  * 2. The ksensor character device driver.
65*3ce53722SRobert Mustacchi  * 3. Sensor providers, which are generally drivers that register with the
66*3ce53722SRobert Mustacchi  *    ksensor framework.
67*3ce53722SRobert Mustacchi  *
68*3ce53722SRobert Mustacchi  * The implementation of (1) is all in this file. The implementation of (2) is
69*3ce53722SRobert Mustacchi  * in uts/common/io/ksensor/ksensor_drv.c. The implementation of (3) is found in
70*3ce53722SRobert Mustacchi  * all of the different leaf devices. Examples of (3) include pchtemp(7D) and
71*3ce53722SRobert Mustacchi  * igb(7D).
72*3ce53722SRobert Mustacchi  *
73*3ce53722SRobert Mustacchi  * We separate numbers one and two into two different components for a few
74*3ce53722SRobert Mustacchi  * reasons. The most important thing is that drivers that provide sensors should
75*3ce53722SRobert Mustacchi  * not be dependent on some other part of the system having been loaded. This
76*3ce53722SRobert Mustacchi  * makes a compelling argument for it being a part of the core kernel. However,
77*3ce53722SRobert Mustacchi  * like other subsystems (e.g. kstats, smbios, etc.), it's useful to separate
78*3ce53722SRobert Mustacchi  * out the thing that provides the interface to users with the thing that is
79*3ce53722SRobert Mustacchi  * used to glue together providers in the kernel. There's the added benefit that
80*3ce53722SRobert Mustacchi  * it's practically simpler to spin up a pseudo-device through a module.
81*3ce53722SRobert Mustacchi  *
82*3ce53722SRobert Mustacchi  * The ksensor character device driver (2) registers with the main genunix
83*3ce53722SRobert Mustacchi  * ksensor code (1) when it attaches and when it detaches. The kernel only
84*3ce53722SRobert Mustacchi  * allows a single driver to be attached to it. When that character device
85*3ce53722SRobert Mustacchi  * driver attaches, the ksensor framework will walk through all of the currently
86*3ce53722SRobert Mustacchi  * registered sensors and inform the character device driver of the nodes that
87*3ce53722SRobert Mustacchi  * it needs to create. While the character device driver is attached, the
88*3ce53722SRobert Mustacchi  * ksensor framework will also call back into it when a sensor needs to be
89*3ce53722SRobert Mustacchi  * removed.
90*3ce53722SRobert Mustacchi  *
91*3ce53722SRobert Mustacchi  * Generally speaking, this distinction of responsibilities allows the kernel
92*3ce53722SRobert Mustacchi  * sensor character device driver to attach and detach without impact to the
93*3ce53722SRobert Mustacchi  * sensor providers or them even being notified at all, it's all transparent to
94*3ce53722SRobert Mustacchi  * them.
95*3ce53722SRobert Mustacchi  *
96*3ce53722SRobert Mustacchi  * ------------------------------
97*3ce53722SRobert Mustacchi  * Sensor Lifetime and detach(9E)
98*3ce53722SRobert Mustacchi  * ------------------------------
99*3ce53722SRobert Mustacchi  *
100*3ce53722SRobert Mustacchi  * Traditionally, a device driver may be detached by the broader kernel whenever
101*3ce53722SRobert Mustacchi  * the kernel desires it. On debug builds this happens by a dedicated thread. On
102*3ce53722SRobert Mustacchi  * a non-debug build this may happen due to memory pressure or as an attempt to
103*3ce53722SRobert Mustacchi  * reclaim idle resources (though this is much less common). However, when the
104*3ce53722SRobert Mustacchi  * module is detached, the system remembers that minor nodes previously existed
105*3ce53722SRobert Mustacchi  * and that entries in /devices had been created. When something proceeds to
106*3ce53722SRobert Mustacchi  * access an entry in /devices again, the system will use that to bring a driver
107*3ce53722SRobert Mustacchi  * back to life. It doesn't matter whether it's a pseudo-device driver or
108*3ce53722SRobert Mustacchi  * something else, this can happen.
109*3ce53722SRobert Mustacchi  *
110*3ce53722SRobert Mustacchi  * One downside to the sensor framework, is that we need to emulate this
111*3ce53722SRobert Mustacchi  * behavior which leads to some amount of complexity here. But this is a
112*3ce53722SRobert Mustacchi  * worthwhile tradeoff as it makes things much simpler for providers and it's
113*3ce53722SRobert Mustacchi  * not too hard for us to emulate this behavior.
114*3ce53722SRobert Mustacchi  *
115*3ce53722SRobert Mustacchi  * When a sensor provider registers the sensor, the sensor becomes available to
116*3ce53722SRobert Mustacchi  * the system. When the sensor provider unregisters with the system, which
117*3ce53722SRobert Mustacchi  * happens during its detach routine, then we note that it has been detached;
118*3ce53722SRobert Mustacchi  * however, we don't delete its minor node and if something accesses it, we
119*3ce53722SRobert Mustacchi  * attempt to load the driver again, the same way that devfs (the file system
120*3ce53722SRobert Mustacchi  * behind /devices) does.
121*3ce53722SRobert Mustacchi  *
122*3ce53722SRobert Mustacchi  * For each dev_info_t that registers a sensor we register a callback such that
123*3ce53722SRobert Mustacchi  * when the device is removed, e.g. someone called rem_drv or physically pulls
124*3ce53722SRobert Mustacchi  * the device, then we'll be able to finally clean up the device. This lifetime
125*3ce53722SRobert Mustacchi  * can be represented in the following image:
126*3ce53722SRobert Mustacchi  *
127*3ce53722SRobert Mustacchi  *         |
128*3ce53722SRobert Mustacchi  *         |
129*3ce53722SRobert Mustacchi  *         +-----<-------------------------------------+
130*3ce53722SRobert Mustacchi  *         |                                           |
131*3ce53722SRobert Mustacchi  *         | . . call ksensor_create()                 |
132*3ce53722SRobert Mustacchi  *         v                                           |
133*3ce53722SRobert Mustacchi  *     +-------+                                       |
134*3ce53722SRobert Mustacchi  *     | Valid |                                       |
135*3ce53722SRobert Mustacchi  *     +-------+                                       |
136*3ce53722SRobert Mustacchi  *         |                                           ^
137*3ce53722SRobert Mustacchi  *         | . . call ksensor_remove()                 |
138*3ce53722SRobert Mustacchi  *         v                                           |
139*3ce53722SRobert Mustacchi  *    +---------+                                      |
140*3ce53722SRobert Mustacchi  *    | Invalid |                                      |
141*3ce53722SRobert Mustacchi  *    +---------+                                      |
142*3ce53722SRobert Mustacchi  *      |     |                                        |
143*3ce53722SRobert Mustacchi  *      |     | . . user uses sensor again             |
144*3ce53722SRobert Mustacchi  *      |     |                                        |
145*3ce53722SRobert Mustacchi  *      |     +-------------------+                    |
146*3ce53722SRobert Mustacchi  *      |                         |                    |
147*3ce53722SRobert Mustacchi  *      |                         v                    |
148*3ce53722SRobert Mustacchi  *      |                 +---------------+            |
149*3ce53722SRobert Mustacchi  *      |                 | Attatching... |-->---------+
150*3ce53722SRobert Mustacchi  *      |                 +---------------+
151*3ce53722SRobert Mustacchi  *      | . . ddi unbind cb       |
152*3ce53722SRobert Mustacchi  *      |                         |
153*3ce53722SRobert Mustacchi  *      v                         | . . attatch fails or
154*3ce53722SRobert Mustacchi  *   +---------+                  |     no call to ksensor_create()
155*3ce53722SRobert Mustacchi  *   | Deleted |--<---------------+     again
156*3ce53722SRobert Mustacchi  *   +---------+
157*3ce53722SRobert Mustacchi  *
158*3ce53722SRobert Mustacchi  * When the DDI unbind callback is called, we know that the device is going to
159*3ce53722SRobert Mustacchi  * be removed. However, this happens within a subtle context with a majority of
160*3ce53722SRobert Mustacchi  * the device tree held (at least the dip's parent). In particular, another
161*3ce53722SRobert Mustacchi  * thread may be trying to obtain a hold on it and be blocked in
162*3ce53722SRobert Mustacchi  * ndi_devi_enter(). As the callback thread holds that, that could lead to a
163*3ce53722SRobert Mustacchi  * deadlock. As a result, we clean things up in two phases. One during the
164*3ce53722SRobert Mustacchi  * synchronous callback and the other via a taskq. In the first phase we
165*3ce53722SRobert Mustacchi  * logically do the following:
166*3ce53722SRobert Mustacchi  *
167*3ce53722SRobert Mustacchi  *  o Remove the dip from the list of ksensor dips and set the flag that
168*3ce53722SRobert Mustacchi  *    indicates that it's been removed.
169*3ce53722SRobert Mustacchi  *  o Remove all of the sensors from the global avl to make sure that new
170*3ce53722SRobert Mustacchi  *    threads cannot look it up.
171*3ce53722SRobert Mustacchi  *
172*3ce53722SRobert Mustacchi  * Then, after the taskq is dispatched, we do the following in taskq context:
173*3ce53722SRobert Mustacchi  *
174*3ce53722SRobert Mustacchi  *  o Tell the ksensor driver that it should remove the minor node.
175*3ce53722SRobert Mustacchi  *  o Block on each sensor until it is no-longer busy and then clean it up.
176*3ce53722SRobert Mustacchi  *  o Clean up the ksensor_dip_t.
177*3ce53722SRobert Mustacchi  *
178*3ce53722SRobert Mustacchi  * ------------------
179*3ce53722SRobert Mustacchi  * Accessing a Sensor
180*3ce53722SRobert Mustacchi  * ------------------
181*3ce53722SRobert Mustacchi  *
182*3ce53722SRobert Mustacchi  * Access to a particular sensor is serialized in the system. In addition to
183*3ce53722SRobert Mustacchi  * that, a number of steps are required to access one that is not unlike
184*3ce53722SRobert Mustacchi  * accessing a character device. When a given sensor is held the KSENSOR_F_BUSY
185*3ce53722SRobert Mustacchi  * flag is set in the ksensor_flags member. In addition, as part of taking a
186*3ce53722SRobert Mustacchi  * hold a number of side effects occur that ensure that the sensor provider's
187*3ce53722SRobert Mustacchi  * dev_info_t is considered busy and can't be detached.
188*3ce53722SRobert Mustacchi  *
189*3ce53722SRobert Mustacchi  * To obtain a hold on a sensor the following logical steps are required (see
190*3ce53722SRobert Mustacchi  * ksensor_hold_by_id() for the implementation):
191*3ce53722SRobert Mustacchi  *
192*3ce53722SRobert Mustacchi  *  1. Map the minor to the ksensor_t via the avl tree
193*3ce53722SRobert Mustacchi  *  2. Check that the ksensor's dip is valid
194*3ce53722SRobert Mustacchi  *  3. If the sensor is busy, wait until it is no longer so, and restart from
195*3ce53722SRobert Mustacchi  *     the top. Otherwise, mark the sensor as busy.
196*3ce53722SRobert Mustacchi  *  4. Enter the parent and place a hold on the sensor provider's dip.
197*3ce53722SRobert Mustacchi  *  5. Once again check if the dip is removed or not because we have to drop
198*3ce53722SRobert Mustacchi  *     locks during that operation.
199*3ce53722SRobert Mustacchi  *  6. Check if the ksensor has the valid flag set. If not, attempt to configure
200*3ce53722SRobert Mustacchi  *     the dip.
201*3ce53722SRobert Mustacchi  *  7. Assuming the sensor is now valid, we can return it.
202*3ce53722SRobert Mustacchi  *
203*3ce53722SRobert Mustacchi  * After this point, the sensor is considered valid for use. Once the consumer
204*3ce53722SRobert Mustacchi  * is finished with the sensor, it should be released by calling
205*3ce53722SRobert Mustacchi  * ksensor_release().
206*3ce53722SRobert Mustacchi  *
207*3ce53722SRobert Mustacchi  * An important aspect of the above scheme is that the KSENSOR_F_BUSY flag is
208*3ce53722SRobert Mustacchi  * required to progress through the validation and holding of the device. This
209*3ce53722SRobert Mustacchi  * makes sure that only one thread is attempting to attach it at a given time. A
210*3ce53722SRobert Mustacchi  * reasonable future optimization would be to amortize this cost in open(9E)
211*3ce53722SRobert Mustacchi  * and close(9E) of the minor and to bump a count as it being referenced as long
212*3ce53722SRobert Mustacchi  * as it is open.
213*3ce53722SRobert Mustacchi  *
214*3ce53722SRobert Mustacchi  * -----------------------------
215*3ce53722SRobert Mustacchi  * Character Device Registration
216*3ce53722SRobert Mustacchi  * -----------------------------
217*3ce53722SRobert Mustacchi  *
218*3ce53722SRobert Mustacchi  * The 'ksensor' character device driver can come and go. To support this, the
219*3ce53722SRobert Mustacchi  * ksensor framework communicates with the ksensor character device by a
220*3ce53722SRobert Mustacchi  * well-defined set of callbacks, used to indicate sensor addition and removal.
221*3ce53722SRobert Mustacchi  * The ksensor character device is found in uts/common/io/ksensor/ksensor_drv.c.
222*3ce53722SRobert Mustacchi  * The ksensor character device is responsible for creating and destroying minor
223*3ce53722SRobert Mustacchi  * nodes.
224*3ce53722SRobert Mustacchi  *
225*3ce53722SRobert Mustacchi  * Each ksensor_t has a flag, KSENSOR_F_NOTIFIED, that is used to indicate
226*3ce53722SRobert Mustacchi  * whether or not the registered driver has been notified of the sensor. When a
227*3ce53722SRobert Mustacchi  * callback is first registered, we'll walk through the entire list of nodes to
228*3ce53722SRobert Mustacchi  * make sure that its minor has been created. When unregistering, the minor node
229*3ce53722SRobert Mustacchi  * remove callback will not be called; however, this can generally by dealt with
230*3ce53722SRobert Mustacchi  * by calling something like ddi_remove_minor_node(dip, NULL).
231*3ce53722SRobert Mustacchi  *
232*3ce53722SRobert Mustacchi  * -------
233*3ce53722SRobert Mustacchi  * Locking
234*3ce53722SRobert Mustacchi  * -------
235*3ce53722SRobert Mustacchi  *
236*3ce53722SRobert Mustacchi  * The following rules apply to dealing with lock ordering:
237*3ce53722SRobert Mustacchi  *
238*3ce53722SRobert Mustacchi  * 1. The global ksensor_g_mutex protects all global data and must be taken
239*3ce53722SRobert Mustacchi  *    before a ksensor_t's individual mutex.
240*3ce53722SRobert Mustacchi  *
241*3ce53722SRobert Mustacchi  * 2. A thread should not hold any two ksensor_t's mutex at any time.
242*3ce53722SRobert Mustacchi  *
243*3ce53722SRobert Mustacchi  * 3. No locks should be held when attempting to grab or manipulate a
244*3ce53722SRobert Mustacchi  *    dev_info_t, e.g. ndi_devi_enter().
245*3ce53722SRobert Mustacchi  *
246*3ce53722SRobert Mustacchi  * 4. Unless the ksensor is actively being held, whenever a ksensor is found,
247*3ce53722SRobert Mustacchi  *    one must check whether the ksensor_dip_t flag KSENSOR_DIP_F_REMOVED is
248*3ce53722SRobert Mustacchi  *    set or not and whether the ksensor_t's KSENSOR_F_VALID flag is set.
249*3ce53722SRobert Mustacchi  */
250*3ce53722SRobert Mustacchi 
251*3ce53722SRobert Mustacchi #include <sys/types.h>
252*3ce53722SRobert Mustacchi #include <sys/file.h>
253*3ce53722SRobert Mustacchi #include <sys/errno.h>
254*3ce53722SRobert Mustacchi #include <sys/cred.h>
255*3ce53722SRobert Mustacchi #include <sys/ddi.h>
256*3ce53722SRobert Mustacchi #include <sys/stat.h>
257*3ce53722SRobert Mustacchi #include <sys/sunddi.h>
258*3ce53722SRobert Mustacchi #include <sys/sunndi.h>
259*3ce53722SRobert Mustacchi #include <sys/esunddi.h>
260*3ce53722SRobert Mustacchi #include <sys/ksensor_impl.h>
261*3ce53722SRobert Mustacchi #include <sys/ddi_impldefs.h>
262*3ce53722SRobert Mustacchi #include <sys/pci.h>
263*3ce53722SRobert Mustacchi #include <sys/avl.h>
264*3ce53722SRobert Mustacchi #include <sys/list.h>
265*3ce53722SRobert Mustacchi #include <sys/stddef.h>
266*3ce53722SRobert Mustacchi #include <sys/sysmacros.h>
267*3ce53722SRobert Mustacchi #include <sys/fs/dv_node.h>
268*3ce53722SRobert Mustacchi 
269*3ce53722SRobert Mustacchi typedef enum {
270*3ce53722SRobert Mustacchi 	/*
271*3ce53722SRobert Mustacchi 	 * This flag indicates that the subscribing ksensor character device has
272*3ce53722SRobert Mustacchi 	 * been notified about this flag.
273*3ce53722SRobert Mustacchi 	 */
274*3ce53722SRobert Mustacchi 	KSENSOR_F_NOTIFIED	= 1 << 0,
275*3ce53722SRobert Mustacchi 	/*
276*3ce53722SRobert Mustacchi 	 * This indicates that the sensor is currently valid, meaning that the
277*3ce53722SRobert Mustacchi 	 * ops vector and argument are safe to use. This is removed when a
278*3ce53722SRobert Mustacchi 	 * driver with a sensor is detached.
279*3ce53722SRobert Mustacchi 	 */
280*3ce53722SRobert Mustacchi 	KSENSOR_F_VALID		= 1 << 1,
281*3ce53722SRobert Mustacchi 	/*
282*3ce53722SRobert Mustacchi 	 * Indicates that a client has a hold on the sensor for some purpose.
283*3ce53722SRobert Mustacchi 	 * This must be set before trying to get an NDI hold. Once this is set
284*3ce53722SRobert Mustacchi 	 * and a NDI hold is in place, it is safe to use the operations vector
285*3ce53722SRobert Mustacchi 	 * and argument.
286*3ce53722SRobert Mustacchi 	 */
287*3ce53722SRobert Mustacchi 	KSENSOR_F_BUSY		= 1 << 2,
288*3ce53722SRobert Mustacchi } ksensor_flags_t;
289*3ce53722SRobert Mustacchi 
290*3ce53722SRobert Mustacchi typedef enum {
291*3ce53722SRobert Mustacchi 	KSENSOR_DIP_F_REMOVED	= 1 << 0
292*3ce53722SRobert Mustacchi } ksensor_dip_flags_t;
293*3ce53722SRobert Mustacchi 
294*3ce53722SRobert Mustacchi typedef struct {
295*3ce53722SRobert Mustacchi 	list_node_t ksdip_link;
296*3ce53722SRobert Mustacchi 	ksensor_dip_flags_t ksdip_flags;
297*3ce53722SRobert Mustacchi 	dev_info_t *ksdip_dip;
298*3ce53722SRobert Mustacchi 	ddi_unbind_callback_t ksdip_cb;
299*3ce53722SRobert Mustacchi 	list_t ksdip_sensors;
300*3ce53722SRobert Mustacchi } ksensor_dip_t;
301*3ce53722SRobert Mustacchi 
302*3ce53722SRobert Mustacchi typedef struct {
303*3ce53722SRobert Mustacchi 	kmutex_t ksensor_mutex;
304*3ce53722SRobert Mustacchi 	kcondvar_t ksensor_cv;
305*3ce53722SRobert Mustacchi 	ksensor_flags_t ksensor_flags;
306*3ce53722SRobert Mustacchi 	list_node_t ksensor_dip_list;
307*3ce53722SRobert Mustacchi 	avl_node_t ksensor_id_avl;
308*3ce53722SRobert Mustacchi 	uint_t ksensor_nwaiters;
309*3ce53722SRobert Mustacchi 	ksensor_dip_t *ksensor_ksdip;
310*3ce53722SRobert Mustacchi 	char *ksensor_name;
311*3ce53722SRobert Mustacchi 	char *ksensor_class;
312*3ce53722SRobert Mustacchi 	id_t ksensor_id;
313*3ce53722SRobert Mustacchi 	const ksensor_ops_t *ksensor_ops;
314*3ce53722SRobert Mustacchi 	void *ksensor_arg;
315*3ce53722SRobert Mustacchi } ksensor_t;
316*3ce53722SRobert Mustacchi 
317*3ce53722SRobert Mustacchi static kmutex_t ksensor_g_mutex;
318*3ce53722SRobert Mustacchi static id_space_t *ksensor_ids;
319*3ce53722SRobert Mustacchi static list_t ksensor_dips;
320*3ce53722SRobert Mustacchi static avl_tree_t ksensor_avl;
321*3ce53722SRobert Mustacchi static dev_info_t *ksensor_cb_dip;
322*3ce53722SRobert Mustacchi static ksensor_create_f ksensor_cb_create;
323*3ce53722SRobert Mustacchi static ksensor_remove_f ksensor_cb_remove;
324*3ce53722SRobert Mustacchi 
325*3ce53722SRobert Mustacchi static int
326*3ce53722SRobert Mustacchi ksensor_avl_compare(const void *l, const void *r)
327*3ce53722SRobert Mustacchi {
328*3ce53722SRobert Mustacchi 	const ksensor_t *kl = l;
329*3ce53722SRobert Mustacchi 	const ksensor_t *kr = r;
330*3ce53722SRobert Mustacchi 
331*3ce53722SRobert Mustacchi 	if (kl->ksensor_id > kr->ksensor_id) {
332*3ce53722SRobert Mustacchi 		return (1);
333*3ce53722SRobert Mustacchi 	} else if (kl->ksensor_id < kr->ksensor_id) {
334*3ce53722SRobert Mustacchi 		return (-1);
335*3ce53722SRobert Mustacchi 	} else {
336*3ce53722SRobert Mustacchi 		return (0);
337*3ce53722SRobert Mustacchi 	}
338*3ce53722SRobert Mustacchi }
339*3ce53722SRobert Mustacchi 
340*3ce53722SRobert Mustacchi static ksensor_t *
341*3ce53722SRobert Mustacchi ksensor_find_by_id(id_t id)
342*3ce53722SRobert Mustacchi {
343*3ce53722SRobert Mustacchi 	ksensor_t k, *ret;
344*3ce53722SRobert Mustacchi 
345*3ce53722SRobert Mustacchi 	ASSERT(MUTEX_HELD(&ksensor_g_mutex));
346*3ce53722SRobert Mustacchi 
347*3ce53722SRobert Mustacchi 	k.ksensor_id = id;
348*3ce53722SRobert Mustacchi 	return (avl_find(&ksensor_avl, &k, NULL));
349*3ce53722SRobert Mustacchi 
350*3ce53722SRobert Mustacchi }
351*3ce53722SRobert Mustacchi 
352*3ce53722SRobert Mustacchi static ksensor_t *
353*3ce53722SRobert Mustacchi ksensor_search_ksdip(ksensor_dip_t *ksdip, const char *name, const char *class)
354*3ce53722SRobert Mustacchi {
355*3ce53722SRobert Mustacchi 	ksensor_t *s;
356*3ce53722SRobert Mustacchi 
357*3ce53722SRobert Mustacchi 	ASSERT(MUTEX_HELD(&ksensor_g_mutex));
358*3ce53722SRobert Mustacchi 
359*3ce53722SRobert Mustacchi 	for (s = list_head(&ksdip->ksdip_sensors); s != NULL;
360*3ce53722SRobert Mustacchi 	    s = list_next(&ksdip->ksdip_sensors, s)) {
361*3ce53722SRobert Mustacchi 		if (strcmp(s->ksensor_name, name) == 0 &&
362*3ce53722SRobert Mustacchi 		    strcmp(s->ksensor_class, class) == 0) {
363*3ce53722SRobert Mustacchi 			return (s);
364*3ce53722SRobert Mustacchi 		}
365*3ce53722SRobert Mustacchi 	}
366*3ce53722SRobert Mustacchi 
367*3ce53722SRobert Mustacchi 	return (NULL);
368*3ce53722SRobert Mustacchi }
369*3ce53722SRobert Mustacchi 
370*3ce53722SRobert Mustacchi static void
371*3ce53722SRobert Mustacchi ksensor_free_sensor(ksensor_t *sensor)
372*3ce53722SRobert Mustacchi {
373*3ce53722SRobert Mustacchi 	strfree(sensor->ksensor_name);
374*3ce53722SRobert Mustacchi 	strfree(sensor->ksensor_class);
375*3ce53722SRobert Mustacchi 	id_free(ksensor_ids, sensor->ksensor_id);
376*3ce53722SRobert Mustacchi 	mutex_destroy(&sensor->ksensor_mutex);
377*3ce53722SRobert Mustacchi 	kmem_free(sensor, sizeof (ksensor_t));
378*3ce53722SRobert Mustacchi }
379*3ce53722SRobert Mustacchi 
380*3ce53722SRobert Mustacchi static void
381*3ce53722SRobert Mustacchi ksensor_free_dip(ksensor_dip_t *ksdip)
382*3ce53722SRobert Mustacchi {
383*3ce53722SRobert Mustacchi 	list_destroy(&ksdip->ksdip_sensors);
384*3ce53722SRobert Mustacchi 	kmem_free(ksdip, sizeof (ksensor_dip_t));
385*3ce53722SRobert Mustacchi }
386*3ce53722SRobert Mustacchi 
387*3ce53722SRobert Mustacchi static void
388*3ce53722SRobert Mustacchi ksensor_dip_unbind_taskq(void *arg)
389*3ce53722SRobert Mustacchi {
390*3ce53722SRobert Mustacchi 	ksensor_dip_t *k = arg;
391*3ce53722SRobert Mustacchi 	ksensor_t *sensor;
392*3ce53722SRobert Mustacchi 
393*3ce53722SRobert Mustacchi 	/*
394*3ce53722SRobert Mustacchi 	 * First notify an attached driver that the nodes are going away
395*3ce53722SRobert Mustacchi 	 * before we block and wait on them.
396*3ce53722SRobert Mustacchi 	 */
397*3ce53722SRobert Mustacchi 	mutex_enter(&ksensor_g_mutex);
398*3ce53722SRobert Mustacchi 	for (sensor = list_head(&k->ksdip_sensors); sensor != NULL;
399*3ce53722SRobert Mustacchi 	    sensor = list_next(&k->ksdip_sensors, sensor)) {
400*3ce53722SRobert Mustacchi 		mutex_enter(&sensor->ksensor_mutex);
401*3ce53722SRobert Mustacchi 		if (sensor->ksensor_flags & KSENSOR_F_NOTIFIED) {
402*3ce53722SRobert Mustacchi 			ksensor_cb_remove(sensor->ksensor_id,
403*3ce53722SRobert Mustacchi 			    sensor->ksensor_name);
404*3ce53722SRobert Mustacchi 			sensor->ksensor_flags &= ~KSENSOR_F_NOTIFIED;
405*3ce53722SRobert Mustacchi 		}
406*3ce53722SRobert Mustacchi 		mutex_exit(&sensor->ksensor_mutex);
407*3ce53722SRobert Mustacchi 	}
408*3ce53722SRobert Mustacchi 	mutex_exit(&ksensor_g_mutex);
409*3ce53722SRobert Mustacchi 
410*3ce53722SRobert Mustacchi 	/*
411*3ce53722SRobert Mustacchi 	 * Now that the driver has destroyed its minor, wait for anything that's
412*3ce53722SRobert Mustacchi 	 * still there.
413*3ce53722SRobert Mustacchi 	 */
414*3ce53722SRobert Mustacchi 	while ((sensor = list_remove_head(&k->ksdip_sensors)) != NULL) {
415*3ce53722SRobert Mustacchi 		mutex_enter(&sensor->ksensor_mutex);
416*3ce53722SRobert Mustacchi 		while ((sensor->ksensor_flags & KSENSOR_F_BUSY) != 0 ||
417*3ce53722SRobert Mustacchi 		    sensor->ksensor_nwaiters > 0) {
418*3ce53722SRobert Mustacchi 			cv_wait(&sensor->ksensor_cv, &sensor->ksensor_mutex);
419*3ce53722SRobert Mustacchi 		}
420*3ce53722SRobert Mustacchi 		mutex_exit(&sensor->ksensor_mutex);
421*3ce53722SRobert Mustacchi 		ksensor_free_sensor(sensor);
422*3ce53722SRobert Mustacchi 	}
423*3ce53722SRobert Mustacchi 	ksensor_free_dip(k);
424*3ce53722SRobert Mustacchi }
425*3ce53722SRobert Mustacchi 
426*3ce53722SRobert Mustacchi static void
427*3ce53722SRobert Mustacchi ksensor_dip_unbind_cb(void *arg, dev_info_t *dip)
428*3ce53722SRobert Mustacchi {
429*3ce53722SRobert Mustacchi 	ksensor_dip_t *k = arg;
430*3ce53722SRobert Mustacchi 	ksensor_t *sensor;
431*3ce53722SRobert Mustacchi 
432*3ce53722SRobert Mustacchi 	/*
433*3ce53722SRobert Mustacchi 	 * Remove the dip and the associated sensors from global visibility.
434*3ce53722SRobert Mustacchi 	 * This will ensure that no new clients can find this; however, others
435*3ce53722SRobert Mustacchi 	 * may have extent attempts to grab it (but lost the race in an NDI
436*3ce53722SRobert Mustacchi 	 * hold).
437*3ce53722SRobert Mustacchi 	 */
438*3ce53722SRobert Mustacchi 	mutex_enter(&ksensor_g_mutex);
439*3ce53722SRobert Mustacchi 	list_remove(&ksensor_dips, k);
440*3ce53722SRobert Mustacchi 	k->ksdip_flags |= KSENSOR_DIP_F_REMOVED;
441*3ce53722SRobert Mustacchi 	for (sensor = list_head(&k->ksdip_sensors); sensor != NULL;
442*3ce53722SRobert Mustacchi 	    sensor = list_next(&k->ksdip_sensors, sensor)) {
443*3ce53722SRobert Mustacchi 		avl_remove(&ksensor_avl, sensor);
444*3ce53722SRobert Mustacchi 	}
445*3ce53722SRobert Mustacchi 	mutex_exit(&ksensor_g_mutex);
446*3ce53722SRobert Mustacchi 
447*3ce53722SRobert Mustacchi 	(void) taskq_dispatch(system_taskq, ksensor_dip_unbind_taskq, k,
448*3ce53722SRobert Mustacchi 	    TQ_SLEEP);
449*3ce53722SRobert Mustacchi }
450*3ce53722SRobert Mustacchi 
451*3ce53722SRobert Mustacchi static ksensor_dip_t *
452*3ce53722SRobert Mustacchi ksensor_dip_create(dev_info_t *dip)
453*3ce53722SRobert Mustacchi {
454*3ce53722SRobert Mustacchi 	ksensor_dip_t *k;
455*3ce53722SRobert Mustacchi 
456*3ce53722SRobert Mustacchi 	k = kmem_zalloc(sizeof (ksensor_dip_t), KM_SLEEP);
457*3ce53722SRobert Mustacchi 	k->ksdip_dip = dip;
458*3ce53722SRobert Mustacchi 	k->ksdip_cb.ddiub_cb = ksensor_dip_unbind_cb;
459*3ce53722SRobert Mustacchi 	k->ksdip_cb.ddiub_arg = k;
460*3ce53722SRobert Mustacchi 	list_create(&k->ksdip_sensors, sizeof (ksensor_t),
461*3ce53722SRobert Mustacchi 	    offsetof(ksensor_t, ksensor_dip_list));
462*3ce53722SRobert Mustacchi 	e_ddi_register_unbind_callback(dip, &k->ksdip_cb);
463*3ce53722SRobert Mustacchi 
464*3ce53722SRobert Mustacchi 	return (k);
465*3ce53722SRobert Mustacchi }
466*3ce53722SRobert Mustacchi 
467*3ce53722SRobert Mustacchi static ksensor_dip_t *
468*3ce53722SRobert Mustacchi ksensor_dip_find(dev_info_t *dip)
469*3ce53722SRobert Mustacchi {
470*3ce53722SRobert Mustacchi 	ksensor_dip_t *k;
471*3ce53722SRobert Mustacchi 
472*3ce53722SRobert Mustacchi 	ASSERT(MUTEX_HELD(&ksensor_g_mutex));
473*3ce53722SRobert Mustacchi 	for (k = list_head(&ksensor_dips); k != NULL;
474*3ce53722SRobert Mustacchi 	    k = list_next(&ksensor_dips, k)) {
475*3ce53722SRobert Mustacchi 		if (dip == k->ksdip_dip) {
476*3ce53722SRobert Mustacchi 			return (k);
477*3ce53722SRobert Mustacchi 		}
478*3ce53722SRobert Mustacchi 	}
479*3ce53722SRobert Mustacchi 
480*3ce53722SRobert Mustacchi 	return (NULL);
481*3ce53722SRobert Mustacchi }
482*3ce53722SRobert Mustacchi 
483*3ce53722SRobert Mustacchi int
484*3ce53722SRobert Mustacchi ksensor_create(dev_info_t *dip, const ksensor_ops_t *ops, void *arg,
485*3ce53722SRobert Mustacchi     const char *name, const char *class, id_t *idp)
486*3ce53722SRobert Mustacchi {
487*3ce53722SRobert Mustacchi 	ksensor_dip_t *ksdip;
488*3ce53722SRobert Mustacchi 	ksensor_t *sensor;
489*3ce53722SRobert Mustacchi 
490*3ce53722SRobert Mustacchi 	if (dip == NULL || ops == NULL || name == NULL || class == NULL ||
491*3ce53722SRobert Mustacchi 	    idp == NULL) {
492*3ce53722SRobert Mustacchi 		return (EINVAL);
493*3ce53722SRobert Mustacchi 	}
494*3ce53722SRobert Mustacchi 
495*3ce53722SRobert Mustacchi 	if (!DEVI_IS_ATTACHING(dip)) {
496*3ce53722SRobert Mustacchi 		return (EAGAIN);
497*3ce53722SRobert Mustacchi 	}
498*3ce53722SRobert Mustacchi 
499*3ce53722SRobert Mustacchi 	mutex_enter(&ksensor_g_mutex);
500*3ce53722SRobert Mustacchi 	ksdip = ksensor_dip_find(dip);
501*3ce53722SRobert Mustacchi 	if (ksdip == NULL) {
502*3ce53722SRobert Mustacchi 		ksdip = ksensor_dip_create(dip);
503*3ce53722SRobert Mustacchi 		list_insert_tail(&ksensor_dips, ksdip);
504*3ce53722SRobert Mustacchi 	}
505*3ce53722SRobert Mustacchi 
506*3ce53722SRobert Mustacchi 	sensor = ksensor_search_ksdip(ksdip, name, class);
507*3ce53722SRobert Mustacchi 	if (sensor != NULL) {
508*3ce53722SRobert Mustacchi 		ASSERT3P(sensor->ksensor_ksdip, ==, ksdip);
509*3ce53722SRobert Mustacchi 		if ((sensor->ksensor_flags & KSENSOR_F_VALID) != 0) {
510*3ce53722SRobert Mustacchi 			mutex_exit(&ksensor_g_mutex);
511*3ce53722SRobert Mustacchi 			dev_err(dip, CE_WARN, "tried to create sensor %s:%s "
512*3ce53722SRobert Mustacchi 			    "which is currently active", class, name);
513*3ce53722SRobert Mustacchi 			return (EEXIST);
514*3ce53722SRobert Mustacchi 		}
515*3ce53722SRobert Mustacchi 
516*3ce53722SRobert Mustacchi 		sensor->ksensor_ops = ops;
517*3ce53722SRobert Mustacchi 		sensor->ksensor_arg = arg;
518*3ce53722SRobert Mustacchi 	} else {
519*3ce53722SRobert Mustacchi 		sensor = kmem_zalloc(sizeof (ksensor_t), KM_SLEEP);
520*3ce53722SRobert Mustacchi 		sensor->ksensor_ksdip = ksdip;
521*3ce53722SRobert Mustacchi 		sensor->ksensor_name = ddi_strdup(name, KM_SLEEP);
522*3ce53722SRobert Mustacchi 		sensor->ksensor_class = ddi_strdup(class, KM_SLEEP);
523*3ce53722SRobert Mustacchi 		sensor->ksensor_id = id_alloc(ksensor_ids);
524*3ce53722SRobert Mustacchi 		sensor->ksensor_ops = ops;
525*3ce53722SRobert Mustacchi 		sensor->ksensor_arg = arg;
526*3ce53722SRobert Mustacchi 		list_insert_tail(&ksdip->ksdip_sensors, sensor);
527*3ce53722SRobert Mustacchi 		avl_add(&ksensor_avl, sensor);
528*3ce53722SRobert Mustacchi 	}
529*3ce53722SRobert Mustacchi 
530*3ce53722SRobert Mustacchi 	sensor->ksensor_flags |= KSENSOR_F_VALID;
531*3ce53722SRobert Mustacchi 
532*3ce53722SRobert Mustacchi 	if (ksensor_cb_create != NULL) {
533*3ce53722SRobert Mustacchi 
534*3ce53722SRobert Mustacchi 		if (ksensor_cb_create(sensor->ksensor_id, sensor->ksensor_class,
535*3ce53722SRobert Mustacchi 		    sensor->ksensor_name) == 0) {
536*3ce53722SRobert Mustacchi 			sensor->ksensor_flags |= KSENSOR_F_NOTIFIED;
537*3ce53722SRobert Mustacchi 		}
538*3ce53722SRobert Mustacchi 	}
539*3ce53722SRobert Mustacchi 
540*3ce53722SRobert Mustacchi 	*idp = sensor->ksensor_id;
541*3ce53722SRobert Mustacchi 	mutex_exit(&ksensor_g_mutex);
542*3ce53722SRobert Mustacchi 
543*3ce53722SRobert Mustacchi 	return (0);
544*3ce53722SRobert Mustacchi }
545*3ce53722SRobert Mustacchi 
546*3ce53722SRobert Mustacchi int
547*3ce53722SRobert Mustacchi ksensor_create_temp_pcidev(dev_info_t *dip, const ksensor_ops_t *ops,
548*3ce53722SRobert Mustacchi     void *arg, const char *name, id_t *idp)
549*3ce53722SRobert Mustacchi {
550*3ce53722SRobert Mustacchi 	char *pci_name, *type;
551*3ce53722SRobert Mustacchi 	int *regs, ret;
552*3ce53722SRobert Mustacchi 	uint_t nregs;
553*3ce53722SRobert Mustacchi 	uint16_t bus, dev;
554*3ce53722SRobert Mustacchi 
555*3ce53722SRobert Mustacchi 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0, "device_type",
556*3ce53722SRobert Mustacchi 	    &type) != DDI_PROP_SUCCESS) {
557*3ce53722SRobert Mustacchi 		return (EINVAL);
558*3ce53722SRobert Mustacchi 	}
559*3ce53722SRobert Mustacchi 
560*3ce53722SRobert Mustacchi 	if (strcmp(type, "pciex") != 0 && strcmp(type, "pci") != 0) {
561*3ce53722SRobert Mustacchi 		ddi_prop_free(type);
562*3ce53722SRobert Mustacchi 		return (EINVAL);
563*3ce53722SRobert Mustacchi 	}
564*3ce53722SRobert Mustacchi 	ddi_prop_free(type);
565*3ce53722SRobert Mustacchi 
566*3ce53722SRobert Mustacchi 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0, "reg",
567*3ce53722SRobert Mustacchi 	    &regs, &nregs) != DDI_PROP_SUCCESS) {
568*3ce53722SRobert Mustacchi 		return (EINVAL);
569*3ce53722SRobert Mustacchi 	}
570*3ce53722SRobert Mustacchi 
571*3ce53722SRobert Mustacchi 	if (nregs < 1) {
572*3ce53722SRobert Mustacchi 		ddi_prop_free(regs);
573*3ce53722SRobert Mustacchi 		return (EIO);
574*3ce53722SRobert Mustacchi 	}
575*3ce53722SRobert Mustacchi 
576*3ce53722SRobert Mustacchi 	bus = PCI_REG_BUS_G(regs[0]);
577*3ce53722SRobert Mustacchi 	dev = PCI_REG_DEV_G(regs[0]);
578*3ce53722SRobert Mustacchi 	ddi_prop_free(regs);
579*3ce53722SRobert Mustacchi 
580*3ce53722SRobert Mustacchi 	pci_name = kmem_asprintf("%x.%x:%s", bus, dev, name);
581*3ce53722SRobert Mustacchi 
582*3ce53722SRobert Mustacchi 	ret = ksensor_create(dip, ops, arg, pci_name,
583*3ce53722SRobert Mustacchi 	    "ddi_sensor:temperature:pci", idp);
584*3ce53722SRobert Mustacchi 	strfree(pci_name);
585*3ce53722SRobert Mustacchi 	return (ret);
586*3ce53722SRobert Mustacchi }
587*3ce53722SRobert Mustacchi 
588*3ce53722SRobert Mustacchi /*
589*3ce53722SRobert Mustacchi  * When a driver removes a sensor, we basically mark it as invalid. This happens
590*3ce53722SRobert Mustacchi  * because drivers can detach and we will need to reattach them when the sensor
591*3ce53722SRobert Mustacchi  * is used again.
592*3ce53722SRobert Mustacchi  */
593*3ce53722SRobert Mustacchi int
594*3ce53722SRobert Mustacchi ksensor_remove(dev_info_t *dip, id_t id)
595*3ce53722SRobert Mustacchi {
596*3ce53722SRobert Mustacchi 	ksensor_dip_t *kdip;
597*3ce53722SRobert Mustacchi 	ksensor_t *sensor;
598*3ce53722SRobert Mustacchi 
599*3ce53722SRobert Mustacchi 	if (!DEVI_IS_ATTACHING(dip) && !DEVI_IS_DETACHING(dip)) {
600*3ce53722SRobert Mustacchi 		return (EAGAIN);
601*3ce53722SRobert Mustacchi 	}
602*3ce53722SRobert Mustacchi 
603*3ce53722SRobert Mustacchi 	mutex_enter(&ksensor_g_mutex);
604*3ce53722SRobert Mustacchi 	kdip = ksensor_dip_find(dip);
605*3ce53722SRobert Mustacchi 	if (kdip == NULL) {
606*3ce53722SRobert Mustacchi 		mutex_exit(&ksensor_g_mutex);
607*3ce53722SRobert Mustacchi 		return (ENOENT);
608*3ce53722SRobert Mustacchi 	}
609*3ce53722SRobert Mustacchi 
610*3ce53722SRobert Mustacchi 	for (sensor = list_head(&kdip->ksdip_sensors); sensor != NULL;
611*3ce53722SRobert Mustacchi 	    sensor = list_next(&kdip->ksdip_sensors, sensor)) {
612*3ce53722SRobert Mustacchi 		if (sensor->ksensor_id == id || id == KSENSOR_ALL_IDS) {
613*3ce53722SRobert Mustacchi 			mutex_enter(&sensor->ksensor_mutex);
614*3ce53722SRobert Mustacchi 			sensor->ksensor_flags &= ~KSENSOR_F_VALID;
615*3ce53722SRobert Mustacchi 			sensor->ksensor_ops = NULL;
616*3ce53722SRobert Mustacchi 			sensor->ksensor_arg = NULL;
617*3ce53722SRobert Mustacchi 			mutex_exit(&sensor->ksensor_mutex);
618*3ce53722SRobert Mustacchi 		}
619*3ce53722SRobert Mustacchi 	}
620*3ce53722SRobert Mustacchi 	mutex_exit(&ksensor_g_mutex);
621*3ce53722SRobert Mustacchi 	return (0);
622*3ce53722SRobert Mustacchi }
623*3ce53722SRobert Mustacchi 
624*3ce53722SRobert Mustacchi static void
625*3ce53722SRobert Mustacchi ksensor_release(ksensor_t *sensor)
626*3ce53722SRobert Mustacchi {
627*3ce53722SRobert Mustacchi 	int circ;
628*3ce53722SRobert Mustacchi 	dev_info_t *pdip;
629*3ce53722SRobert Mustacchi 
630*3ce53722SRobert Mustacchi 	ddi_release_devi(sensor->ksensor_ksdip->ksdip_dip);
631*3ce53722SRobert Mustacchi 
632*3ce53722SRobert Mustacchi 	mutex_enter(&sensor->ksensor_mutex);
633*3ce53722SRobert Mustacchi 	sensor->ksensor_flags &= ~KSENSOR_F_BUSY;
634*3ce53722SRobert Mustacchi 	cv_broadcast(&sensor->ksensor_cv);
635*3ce53722SRobert Mustacchi 	mutex_exit(&sensor->ksensor_mutex);
636*3ce53722SRobert Mustacchi }
637*3ce53722SRobert Mustacchi 
638*3ce53722SRobert Mustacchi static int
639*3ce53722SRobert Mustacchi ksensor_hold_by_id(id_t id, ksensor_t **outp)
640*3ce53722SRobert Mustacchi {
641*3ce53722SRobert Mustacchi 	int circ;
642*3ce53722SRobert Mustacchi 	ksensor_t *sensor;
643*3ce53722SRobert Mustacchi 	dev_info_t *pdip;
644*3ce53722SRobert Mustacchi 
645*3ce53722SRobert Mustacchi restart:
646*3ce53722SRobert Mustacchi 	mutex_enter(&ksensor_g_mutex);
647*3ce53722SRobert Mustacchi 	sensor = ksensor_find_by_id(id);
648*3ce53722SRobert Mustacchi 	if (sensor == NULL) {
649*3ce53722SRobert Mustacchi 		mutex_exit(&ksensor_g_mutex);
650*3ce53722SRobert Mustacchi 		*outp = NULL;
651*3ce53722SRobert Mustacchi 		return (ESTALE);
652*3ce53722SRobert Mustacchi 	}
653*3ce53722SRobert Mustacchi 
654*3ce53722SRobert Mustacchi 	if ((sensor->ksensor_ksdip->ksdip_flags & KSENSOR_DIP_F_REMOVED) != 0) {
655*3ce53722SRobert Mustacchi 		mutex_exit(&ksensor_g_mutex);
656*3ce53722SRobert Mustacchi 		*outp = NULL;
657*3ce53722SRobert Mustacchi 		return (ESTALE);
658*3ce53722SRobert Mustacchi 	}
659*3ce53722SRobert Mustacchi 
660*3ce53722SRobert Mustacchi 	mutex_enter(&sensor->ksensor_mutex);
661*3ce53722SRobert Mustacchi 	if ((sensor->ksensor_flags & KSENSOR_F_BUSY) != 0) {
662*3ce53722SRobert Mustacchi 		mutex_exit(&ksensor_g_mutex);
663*3ce53722SRobert Mustacchi 		sensor->ksensor_nwaiters++;
664*3ce53722SRobert Mustacchi 		while ((sensor->ksensor_flags & KSENSOR_F_BUSY) != 0) {
665*3ce53722SRobert Mustacchi 			int cv = cv_wait_sig(&sensor->ksensor_cv,
666*3ce53722SRobert Mustacchi 			    &sensor->ksensor_mutex);
667*3ce53722SRobert Mustacchi 			if (cv == 0) {
668*3ce53722SRobert Mustacchi 				sensor->ksensor_nwaiters--;
669*3ce53722SRobert Mustacchi 				cv_broadcast(&sensor->ksensor_cv);
670*3ce53722SRobert Mustacchi 				mutex_exit(&sensor->ksensor_mutex);
671*3ce53722SRobert Mustacchi 				*outp = NULL;
672*3ce53722SRobert Mustacchi 				return (EINTR);
673*3ce53722SRobert Mustacchi 			}
674*3ce53722SRobert Mustacchi 		}
675*3ce53722SRobert Mustacchi 		sensor->ksensor_nwaiters--;
676*3ce53722SRobert Mustacchi 		cv_broadcast(&sensor->ksensor_cv);
677*3ce53722SRobert Mustacchi 		mutex_exit(&sensor->ksensor_mutex);
678*3ce53722SRobert Mustacchi 		goto restart;
679*3ce53722SRobert Mustacchi 	}
680*3ce53722SRobert Mustacchi 
681*3ce53722SRobert Mustacchi 	/*
682*3ce53722SRobert Mustacchi 	 * We have obtained ownership of the sensor. At this point, we should
683*3ce53722SRobert Mustacchi 	 * check to see if it's valid or not.
684*3ce53722SRobert Mustacchi 	 */
685*3ce53722SRobert Mustacchi 	sensor->ksensor_flags |= KSENSOR_F_BUSY;
686*3ce53722SRobert Mustacchi 	pdip = ddi_get_parent(sensor->ksensor_ksdip->ksdip_dip);
687*3ce53722SRobert Mustacchi 	mutex_exit(&sensor->ksensor_mutex);
688*3ce53722SRobert Mustacchi 	mutex_exit(&ksensor_g_mutex);
689*3ce53722SRobert Mustacchi 
690*3ce53722SRobert Mustacchi 	/*
691*3ce53722SRobert Mustacchi 	 * Grab a reference on the device node to ensure that it won't go away.
692*3ce53722SRobert Mustacchi 	 */
693*3ce53722SRobert Mustacchi 	ndi_devi_enter(pdip, &circ);
694*3ce53722SRobert Mustacchi 	e_ddi_hold_devi(sensor->ksensor_ksdip->ksdip_dip);
695*3ce53722SRobert Mustacchi 	ndi_devi_exit(pdip, circ);
696*3ce53722SRobert Mustacchi 
697*3ce53722SRobert Mustacchi 	/*
698*3ce53722SRobert Mustacchi 	 * Now that we have an NDI hold, check if it's valid or not. It may have
699*3ce53722SRobert Mustacchi 	 * become invalid while we were waiting due to a race.
700*3ce53722SRobert Mustacchi 	 */
701*3ce53722SRobert Mustacchi 	mutex_enter(&ksensor_g_mutex);
702*3ce53722SRobert Mustacchi 	if ((sensor->ksensor_ksdip->ksdip_flags & KSENSOR_DIP_F_REMOVED) != 0) {
703*3ce53722SRobert Mustacchi 		mutex_exit(&ksensor_g_mutex);
704*3ce53722SRobert Mustacchi 		ksensor_release(sensor);
705*3ce53722SRobert Mustacchi 		return (ESTALE);
706*3ce53722SRobert Mustacchi 	}
707*3ce53722SRobert Mustacchi 
708*3ce53722SRobert Mustacchi 	mutex_enter(&sensor->ksensor_mutex);
709*3ce53722SRobert Mustacchi 	if ((sensor->ksensor_flags & KSENSOR_F_VALID) == 0) {
710*3ce53722SRobert Mustacchi 		mutex_exit(&sensor->ksensor_mutex);
711*3ce53722SRobert Mustacchi 		mutex_exit(&ksensor_g_mutex);
712*3ce53722SRobert Mustacchi 		(void) ndi_devi_config(pdip, NDI_NO_EVENT);
713*3ce53722SRobert Mustacchi 		mutex_enter(&ksensor_g_mutex);
714*3ce53722SRobert Mustacchi 		mutex_enter(&sensor->ksensor_mutex);
715*3ce53722SRobert Mustacchi 
716*3ce53722SRobert Mustacchi 		/*
717*3ce53722SRobert Mustacchi 		 * If we attempted to reattach it and it isn't now valid, fail
718*3ce53722SRobert Mustacchi 		 * this request.
719*3ce53722SRobert Mustacchi 		 */
720*3ce53722SRobert Mustacchi 		if ((sensor->ksensor_ksdip->ksdip_flags &
721*3ce53722SRobert Mustacchi 		    KSENSOR_DIP_F_REMOVED) != 0 ||
722*3ce53722SRobert Mustacchi 		    (sensor->ksensor_flags & KSENSOR_F_VALID) == 0) {
723*3ce53722SRobert Mustacchi 			mutex_exit(&sensor->ksensor_mutex);
724*3ce53722SRobert Mustacchi 			mutex_exit(&ksensor_g_mutex);
725*3ce53722SRobert Mustacchi 			ksensor_release(sensor);
726*3ce53722SRobert Mustacchi 			return (ESTALE);
727*3ce53722SRobert Mustacchi 		}
728*3ce53722SRobert Mustacchi 	}
729*3ce53722SRobert Mustacchi 	mutex_exit(&sensor->ksensor_mutex);
730*3ce53722SRobert Mustacchi 	mutex_exit(&ksensor_g_mutex);
731*3ce53722SRobert Mustacchi 	*outp = sensor;
732*3ce53722SRobert Mustacchi 
733*3ce53722SRobert Mustacchi 	return (0);
734*3ce53722SRobert Mustacchi }
735*3ce53722SRobert Mustacchi 
736*3ce53722SRobert Mustacchi int
737*3ce53722SRobert Mustacchi ksensor_op_kind(id_t id, sensor_ioctl_kind_t *kind)
738*3ce53722SRobert Mustacchi {
739*3ce53722SRobert Mustacchi 	int ret;
740*3ce53722SRobert Mustacchi 	ksensor_t *sensor;
741*3ce53722SRobert Mustacchi 
742*3ce53722SRobert Mustacchi 	if ((ret = ksensor_hold_by_id(id, &sensor)) != 0) {
743*3ce53722SRobert Mustacchi 		return (ret);
744*3ce53722SRobert Mustacchi 	}
745*3ce53722SRobert Mustacchi 
746*3ce53722SRobert Mustacchi 	ret = sensor->ksensor_ops->kso_kind(sensor->ksensor_arg, kind);
747*3ce53722SRobert Mustacchi 	ksensor_release(sensor);
748*3ce53722SRobert Mustacchi 
749*3ce53722SRobert Mustacchi 	return (ret);
750*3ce53722SRobert Mustacchi }
751*3ce53722SRobert Mustacchi 
752*3ce53722SRobert Mustacchi int
753*3ce53722SRobert Mustacchi ksensor_op_temperature(id_t id, sensor_ioctl_temperature_t *temp)
754*3ce53722SRobert Mustacchi {
755*3ce53722SRobert Mustacchi 	int ret;
756*3ce53722SRobert Mustacchi 	ksensor_t *sensor;
757*3ce53722SRobert Mustacchi 
758*3ce53722SRobert Mustacchi 	if ((ret = ksensor_hold_by_id(id, &sensor)) != 0) {
759*3ce53722SRobert Mustacchi 		return (ret);
760*3ce53722SRobert Mustacchi 	}
761*3ce53722SRobert Mustacchi 
762*3ce53722SRobert Mustacchi 	ret = sensor->ksensor_ops->kso_temp(sensor->ksensor_arg, temp);
763*3ce53722SRobert Mustacchi 	ksensor_release(sensor);
764*3ce53722SRobert Mustacchi 
765*3ce53722SRobert Mustacchi 	return (ret);
766*3ce53722SRobert Mustacchi }
767*3ce53722SRobert Mustacchi 
768*3ce53722SRobert Mustacchi void
769*3ce53722SRobert Mustacchi ksensor_unregister(dev_info_t *reg_dip)
770*3ce53722SRobert Mustacchi {
771*3ce53722SRobert Mustacchi 	ksensor_t *sensor;
772*3ce53722SRobert Mustacchi 
773*3ce53722SRobert Mustacchi 	mutex_enter(&ksensor_g_mutex);
774*3ce53722SRobert Mustacchi 	if (ksensor_cb_dip != reg_dip) {
775*3ce53722SRobert Mustacchi 		dev_err(reg_dip, CE_PANIC, "asked to unregister illegal dip");
776*3ce53722SRobert Mustacchi 	}
777*3ce53722SRobert Mustacchi 
778*3ce53722SRobert Mustacchi 	for (sensor = avl_first(&ksensor_avl); sensor != NULL; sensor =
779*3ce53722SRobert Mustacchi 	    AVL_NEXT(&ksensor_avl, sensor)) {
780*3ce53722SRobert Mustacchi 		mutex_enter(&sensor->ksensor_mutex);
781*3ce53722SRobert Mustacchi 		sensor->ksensor_flags &= ~KSENSOR_F_NOTIFIED;
782*3ce53722SRobert Mustacchi 		mutex_exit(&sensor->ksensor_mutex);
783*3ce53722SRobert Mustacchi 	}
784*3ce53722SRobert Mustacchi 
785*3ce53722SRobert Mustacchi 	ksensor_cb_dip = NULL;
786*3ce53722SRobert Mustacchi 	ksensor_cb_create = NULL;
787*3ce53722SRobert Mustacchi 	ksensor_cb_remove = NULL;
788*3ce53722SRobert Mustacchi 	mutex_exit(&ksensor_g_mutex);
789*3ce53722SRobert Mustacchi }
790*3ce53722SRobert Mustacchi 
791*3ce53722SRobert Mustacchi int
792*3ce53722SRobert Mustacchi ksensor_register(dev_info_t *reg_dip, ksensor_create_f create,
793*3ce53722SRobert Mustacchi     ksensor_remove_f remove)
794*3ce53722SRobert Mustacchi {
795*3ce53722SRobert Mustacchi 	ksensor_t *sensor;
796*3ce53722SRobert Mustacchi 
797*3ce53722SRobert Mustacchi 	mutex_enter(&ksensor_g_mutex);
798*3ce53722SRobert Mustacchi 	if (ksensor_cb_dip != NULL) {
799*3ce53722SRobert Mustacchi 		dev_err(reg_dip, CE_WARN, "kernel sensors are already "
800*3ce53722SRobert Mustacchi 		    "registered");
801*3ce53722SRobert Mustacchi 		mutex_exit(&ksensor_g_mutex);
802*3ce53722SRobert Mustacchi 		return (EEXIST);
803*3ce53722SRobert Mustacchi 	}
804*3ce53722SRobert Mustacchi 
805*3ce53722SRobert Mustacchi 	ksensor_cb_dip = reg_dip;
806*3ce53722SRobert Mustacchi 	ksensor_cb_create = create;
807*3ce53722SRobert Mustacchi 	ksensor_cb_remove = remove;
808*3ce53722SRobert Mustacchi 
809*3ce53722SRobert Mustacchi 	for (sensor = avl_first(&ksensor_avl); sensor != NULL; sensor =
810*3ce53722SRobert Mustacchi 	    AVL_NEXT(&ksensor_avl, sensor)) {
811*3ce53722SRobert Mustacchi 		mutex_enter(&sensor->ksensor_mutex);
812*3ce53722SRobert Mustacchi 		ASSERT0(sensor->ksensor_flags & KSENSOR_F_NOTIFIED);
813*3ce53722SRobert Mustacchi 
814*3ce53722SRobert Mustacchi 		if (ksensor_cb_create(sensor->ksensor_id, sensor->ksensor_class,
815*3ce53722SRobert Mustacchi 		    sensor->ksensor_name) == 0) {
816*3ce53722SRobert Mustacchi 			sensor->ksensor_flags |= KSENSOR_F_NOTIFIED;
817*3ce53722SRobert Mustacchi 		}
818*3ce53722SRobert Mustacchi 
819*3ce53722SRobert Mustacchi 		mutex_exit(&sensor->ksensor_mutex);
820*3ce53722SRobert Mustacchi 	}
821*3ce53722SRobert Mustacchi 
822*3ce53722SRobert Mustacchi 	mutex_exit(&ksensor_g_mutex);
823*3ce53722SRobert Mustacchi 
824*3ce53722SRobert Mustacchi 	return (0);
825*3ce53722SRobert Mustacchi }
826*3ce53722SRobert Mustacchi 
827*3ce53722SRobert Mustacchi int
828*3ce53722SRobert Mustacchi ksensor_kind_temperature(void *unused, sensor_ioctl_kind_t *k)
829*3ce53722SRobert Mustacchi {
830*3ce53722SRobert Mustacchi 	k->sik_kind = SENSOR_KIND_TEMPERATURE;
831*3ce53722SRobert Mustacchi 	return (0);
832*3ce53722SRobert Mustacchi }
833*3ce53722SRobert Mustacchi 
834*3ce53722SRobert Mustacchi void
835*3ce53722SRobert Mustacchi ksensor_init(void)
836*3ce53722SRobert Mustacchi {
837*3ce53722SRobert Mustacchi 	mutex_init(&ksensor_g_mutex, NULL, MUTEX_DRIVER, NULL);
838*3ce53722SRobert Mustacchi 	list_create(&ksensor_dips, sizeof (ksensor_dip_t),
839*3ce53722SRobert Mustacchi 	    offsetof(ksensor_dip_t, ksdip_link));
840*3ce53722SRobert Mustacchi 	ksensor_ids = id_space_create("ksensor", 1, L_MAXMIN32);
841*3ce53722SRobert Mustacchi 	avl_create(&ksensor_avl, ksensor_avl_compare, sizeof (ksensor_t),
842*3ce53722SRobert Mustacchi 	    offsetof(ksensor_t, ksensor_id_avl));
843*3ce53722SRobert Mustacchi }
844