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