xref: /illumos-gate/usr/src/uts/common/os/ksensor.c (revision 1045e13a248d94941f864998aa859970ae3a4154)
13ce53722SRobert Mustacchi /*
23ce53722SRobert Mustacchi  * This file and its contents are supplied under the terms of the
33ce53722SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
43ce53722SRobert Mustacchi  * You may only use this file in accordance with the terms of version
53ce53722SRobert Mustacchi  * 1.0 of the CDDL.
63ce53722SRobert Mustacchi  *
73ce53722SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
83ce53722SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
93ce53722SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
103ce53722SRobert Mustacchi  */
113ce53722SRobert Mustacchi 
123ce53722SRobert Mustacchi /*
133ce53722SRobert Mustacchi  * Copyright 2020 Oxide Computer Company
143ce53722SRobert Mustacchi  */
153ce53722SRobert Mustacchi 
163ce53722SRobert Mustacchi /*
173ce53722SRobert Mustacchi  * Kernel Sensor Framework
183ce53722SRobert Mustacchi  *
193ce53722SRobert Mustacchi  * The kernel sensor framework exists to provide a simple and straightforward
203ce53722SRobert Mustacchi  * means for various parts of the system to declare and instantiate sensor
213ce53722SRobert Mustacchi  * information. Between this and the ksensor character device
223ce53722SRobert Mustacchi  * (uts/common/io/ksensor/ksensor_drv.c) this exposes per-device sensors and
233ce53722SRobert Mustacchi  * character devices.
243ce53722SRobert Mustacchi  *
253ce53722SRobert Mustacchi  * --------------------------
263ce53722SRobert Mustacchi  * Driver and User Interfaces
273ce53722SRobert Mustacchi  * --------------------------
283ce53722SRobert Mustacchi  *
293ce53722SRobert Mustacchi  * Each sensor that is registered with the framework is exposed as a character
303ce53722SRobert Mustacchi  * device under /dev/sensors. The device class and node name are often ':'
313ce53722SRobert Mustacchi  * delineated and must begin with 'ddi_sensor'. Everything after 'ddi_sensor'
323ce53722SRobert Mustacchi  * will be created in a directory under /dev/sensors. So for example the Intel
333ce53722SRobert Mustacchi  * PCH driver uses a class "ddi_sensor:temperature:pch" and a node name of
343ce53722SRobert Mustacchi  * 'ts.%d'. This creates the node /dev/sensors/temperature/pch/ts.0. The
353ce53722SRobert Mustacchi  * devfsadm plugin automatically handles the creation of directories which makes
363ce53722SRobert Mustacchi  * the addition of additional sensor types easy to create.
373ce53722SRobert Mustacchi  *
383ce53722SRobert Mustacchi  * Strictly speaking, any device can manage their own sensors and minor nodes by
393ce53722SRobert Mustacchi  * using the appropriate class and implementing the corresponding ioctls. That
403ce53722SRobert Mustacchi  * was how the first kernel sensors were written; however, there are a lot of
413ce53722SRobert Mustacchi  * issues with that which led to this:
423ce53722SRobert Mustacchi  *
433ce53722SRobert Mustacchi  * 1. Every driver had to actually implement character devices.
443ce53722SRobert Mustacchi  *
453ce53722SRobert Mustacchi  * 2. Every driver had to duplicate a lot of the logic around open(9E),
463ce53722SRobert Mustacchi  *    close(9E), and ioctl(9E).
473ce53722SRobert Mustacchi  *
483ce53722SRobert Mustacchi  * 3. Drivers that tied into frameworks like mac(9E) or SCSAv3 needed a lot more
493ce53722SRobert Mustacchi  *    work to fit into this model. For example, because the minor state is
503ce53722SRobert Mustacchi  *    shared between all the instances and the frameworks, they would have
513ce53722SRobert Mustacchi  *    required shared, global state that they don't have today.
523ce53722SRobert Mustacchi  *
533ce53722SRobert Mustacchi  * Ultimately, having an operations vector and a callback argument makes work a
543ce53722SRobert Mustacchi  * lot simpler for the producers of sensor data and that simplicity makes it
553ce53722SRobert Mustacchi  * worthwhile to take on additional effort and work here.
563ce53722SRobert Mustacchi  *
573ce53722SRobert Mustacchi  * ----------
583ce53722SRobert Mustacchi  * Components
593ce53722SRobert Mustacchi  * ----------
603ce53722SRobert Mustacchi  *
613ce53722SRobert Mustacchi  * The ksensor framework is made of a couple of different pieces:
623ce53722SRobert Mustacchi  *
633ce53722SRobert Mustacchi  * 1. This glue that is a part of genunix.
643ce53722SRobert Mustacchi  * 2. The ksensor character device driver.
653ce53722SRobert Mustacchi  * 3. Sensor providers, which are generally drivers that register with the
663ce53722SRobert Mustacchi  *    ksensor framework.
673ce53722SRobert Mustacchi  *
683ce53722SRobert Mustacchi  * The implementation of (1) is all in this file. The implementation of (2) is
693ce53722SRobert Mustacchi  * in uts/common/io/ksensor/ksensor_drv.c. The implementation of (3) is found in
703ce53722SRobert Mustacchi  * all of the different leaf devices. Examples of (3) include pchtemp(7D) and
713ce53722SRobert Mustacchi  * igb(7D).
723ce53722SRobert Mustacchi  *
733ce53722SRobert Mustacchi  * We separate numbers one and two into two different components for a few
743ce53722SRobert Mustacchi  * reasons. The most important thing is that drivers that provide sensors should
753ce53722SRobert Mustacchi  * not be dependent on some other part of the system having been loaded. This
763ce53722SRobert Mustacchi  * makes a compelling argument for it being a part of the core kernel. However,
773ce53722SRobert Mustacchi  * like other subsystems (e.g. kstats, smbios, etc.), it's useful to separate
783ce53722SRobert Mustacchi  * out the thing that provides the interface to users with the thing that is
793ce53722SRobert Mustacchi  * used to glue together providers in the kernel. There's the added benefit that
803ce53722SRobert Mustacchi  * it's practically simpler to spin up a pseudo-device through a module.
813ce53722SRobert Mustacchi  *
823ce53722SRobert Mustacchi  * The ksensor character device driver (2) registers with the main genunix
833ce53722SRobert Mustacchi  * ksensor code (1) when it attaches and when it detaches. The kernel only
843ce53722SRobert Mustacchi  * allows a single driver to be attached to it. When that character device
853ce53722SRobert Mustacchi  * driver attaches, the ksensor framework will walk through all of the currently
863ce53722SRobert Mustacchi  * registered sensors and inform the character device driver of the nodes that
873ce53722SRobert Mustacchi  * it needs to create. While the character device driver is attached, the
883ce53722SRobert Mustacchi  * ksensor framework will also call back into it when a sensor needs to be
893ce53722SRobert Mustacchi  * removed.
903ce53722SRobert Mustacchi  *
913ce53722SRobert Mustacchi  * Generally speaking, this distinction of responsibilities allows the kernel
923ce53722SRobert Mustacchi  * sensor character device driver to attach and detach without impact to the
933ce53722SRobert Mustacchi  * sensor providers or them even being notified at all, it's all transparent to
943ce53722SRobert Mustacchi  * them.
953ce53722SRobert Mustacchi  *
963ce53722SRobert Mustacchi  * ------------------------------
973ce53722SRobert Mustacchi  * Sensor Lifetime and detach(9E)
983ce53722SRobert Mustacchi  * ------------------------------
993ce53722SRobert Mustacchi  *
1003ce53722SRobert Mustacchi  * Traditionally, a device driver may be detached by the broader kernel whenever
1013ce53722SRobert Mustacchi  * the kernel desires it. On debug builds this happens by a dedicated thread. On
1023ce53722SRobert Mustacchi  * a non-debug build this may happen due to memory pressure or as an attempt to
1033ce53722SRobert Mustacchi  * reclaim idle resources (though this is much less common). However, when the
1043ce53722SRobert Mustacchi  * module is detached, the system remembers that minor nodes previously existed
1053ce53722SRobert Mustacchi  * and that entries in /devices had been created. When something proceeds to
1063ce53722SRobert Mustacchi  * access an entry in /devices again, the system will use that to bring a driver
1073ce53722SRobert Mustacchi  * back to life. It doesn't matter whether it's a pseudo-device driver or
1083ce53722SRobert Mustacchi  * something else, this can happen.
1093ce53722SRobert Mustacchi  *
1103ce53722SRobert Mustacchi  * One downside to the sensor framework, is that we need to emulate this
1113ce53722SRobert Mustacchi  * behavior which leads to some amount of complexity here. But this is a
1123ce53722SRobert Mustacchi  * worthwhile tradeoff as it makes things much simpler for providers and it's
1133ce53722SRobert Mustacchi  * not too hard for us to emulate this behavior.
1143ce53722SRobert Mustacchi  *
1153ce53722SRobert Mustacchi  * When a sensor provider registers the sensor, the sensor becomes available to
1163ce53722SRobert Mustacchi  * the system. When the sensor provider unregisters with the system, which
1173ce53722SRobert Mustacchi  * happens during its detach routine, then we note that it has been detached;
1183ce53722SRobert Mustacchi  * however, we don't delete its minor node and if something accesses it, we
1193ce53722SRobert Mustacchi  * attempt to load the driver again, the same way that devfs (the file system
1203ce53722SRobert Mustacchi  * behind /devices) does.
1213ce53722SRobert Mustacchi  *
1223ce53722SRobert Mustacchi  * For each dev_info_t that registers a sensor we register a callback such that
1233ce53722SRobert Mustacchi  * when the device is removed, e.g. someone called rem_drv or physically pulls
1243ce53722SRobert Mustacchi  * the device, then we'll be able to finally clean up the device. This lifetime
1253ce53722SRobert Mustacchi  * can be represented in the following image:
1263ce53722SRobert Mustacchi  *
1273ce53722SRobert Mustacchi  *         |
1283ce53722SRobert Mustacchi  *         |
1293ce53722SRobert Mustacchi  *         +-----<-------------------------------------+
1303ce53722SRobert Mustacchi  *         |                                           |
1313ce53722SRobert Mustacchi  *         | . . call ksensor_create()                 |
1323ce53722SRobert Mustacchi  *         v                                           |
1333ce53722SRobert Mustacchi  *     +-------+                                       |
1343ce53722SRobert Mustacchi  *     | Valid |                                       |
1353ce53722SRobert Mustacchi  *     +-------+                                       |
1363ce53722SRobert Mustacchi  *         |                                           ^
1373ce53722SRobert Mustacchi  *         | . . call ksensor_remove()                 |
1383ce53722SRobert Mustacchi  *         v                                           |
1393ce53722SRobert Mustacchi  *    +---------+                                      |
1403ce53722SRobert Mustacchi  *    | Invalid |                                      |
1413ce53722SRobert Mustacchi  *    +---------+                                      |
1423ce53722SRobert Mustacchi  *      |     |                                        |
1433ce53722SRobert Mustacchi  *      |     | . . user uses sensor again             |
1443ce53722SRobert Mustacchi  *      |     |                                        |
1453ce53722SRobert Mustacchi  *      |     +-------------------+                    |
1463ce53722SRobert Mustacchi  *      |                         |                    |
1473ce53722SRobert Mustacchi  *      |                         v                    |
1483ce53722SRobert Mustacchi  *      |                 +---------------+            |
1493ce53722SRobert Mustacchi  *      |                 | Attatching... |-->---------+
1503ce53722SRobert Mustacchi  *      |                 +---------------+
1513ce53722SRobert Mustacchi  *      | . . ddi unbind cb       |
1523ce53722SRobert Mustacchi  *      |                         |
1533ce53722SRobert Mustacchi  *      v                         | . . attatch fails or
1543ce53722SRobert Mustacchi  *   +---------+                  |     no call to ksensor_create()
1553ce53722SRobert Mustacchi  *   | Deleted |--<---------------+     again
1563ce53722SRobert Mustacchi  *   +---------+
1573ce53722SRobert Mustacchi  *
1583ce53722SRobert Mustacchi  * When the DDI unbind callback is called, we know that the device is going to
1593ce53722SRobert Mustacchi  * be removed. However, this happens within a subtle context with a majority of
1603ce53722SRobert Mustacchi  * the device tree held (at least the dip's parent). In particular, another
1613ce53722SRobert Mustacchi  * thread may be trying to obtain a hold on it and be blocked in
1623ce53722SRobert Mustacchi  * ndi_devi_enter(). As the callback thread holds that, that could lead to a
1633ce53722SRobert Mustacchi  * deadlock. As a result, we clean things up in two phases. One during the
1643ce53722SRobert Mustacchi  * synchronous callback and the other via a taskq. In the first phase we
1653ce53722SRobert Mustacchi  * logically do the following:
1663ce53722SRobert Mustacchi  *
1673ce53722SRobert Mustacchi  *  o Remove the dip from the list of ksensor dips and set the flag that
1683ce53722SRobert Mustacchi  *    indicates that it's been removed.
1693ce53722SRobert Mustacchi  *  o Remove all of the sensors from the global avl to make sure that new
1703ce53722SRobert Mustacchi  *    threads cannot look it up.
1713ce53722SRobert Mustacchi  *
1723ce53722SRobert Mustacchi  * Then, after the taskq is dispatched, we do the following in taskq context:
1733ce53722SRobert Mustacchi  *
1743ce53722SRobert Mustacchi  *  o Tell the ksensor driver that it should remove the minor node.
1753ce53722SRobert Mustacchi  *  o Block on each sensor until it is no-longer busy and then clean it up.
1763ce53722SRobert Mustacchi  *  o Clean up the ksensor_dip_t.
1773ce53722SRobert Mustacchi  *
1783ce53722SRobert Mustacchi  * ------------------
1793ce53722SRobert Mustacchi  * Accessing a Sensor
1803ce53722SRobert Mustacchi  * ------------------
1813ce53722SRobert Mustacchi  *
1823ce53722SRobert Mustacchi  * Access to a particular sensor is serialized in the system. In addition to
1833ce53722SRobert Mustacchi  * that, a number of steps are required to access one that is not unlike
1843ce53722SRobert Mustacchi  * accessing a character device. When a given sensor is held the KSENSOR_F_BUSY
1853ce53722SRobert Mustacchi  * flag is set in the ksensor_flags member. In addition, as part of taking a
1863ce53722SRobert Mustacchi  * hold a number of side effects occur that ensure that the sensor provider's
1873ce53722SRobert Mustacchi  * dev_info_t is considered busy and can't be detached.
1883ce53722SRobert Mustacchi  *
1893ce53722SRobert Mustacchi  * To obtain a hold on a sensor the following logical steps are required (see
1903ce53722SRobert Mustacchi  * ksensor_hold_by_id() for the implementation):
1913ce53722SRobert Mustacchi  *
1923ce53722SRobert Mustacchi  *  1. Map the minor to the ksensor_t via the avl tree
1933ce53722SRobert Mustacchi  *  2. Check that the ksensor's dip is valid
1943ce53722SRobert Mustacchi  *  3. If the sensor is busy, wait until it is no longer so, and restart from
1953ce53722SRobert Mustacchi  *     the top. Otherwise, mark the sensor as busy.
1963ce53722SRobert Mustacchi  *  4. Enter the parent and place a hold on the sensor provider's dip.
1973ce53722SRobert Mustacchi  *  5. Once again check if the dip is removed or not because we have to drop
1983ce53722SRobert Mustacchi  *     locks during that operation.
1993ce53722SRobert Mustacchi  *  6. Check if the ksensor has the valid flag set. If not, attempt to configure
2003ce53722SRobert Mustacchi  *     the dip.
2013ce53722SRobert Mustacchi  *  7. Assuming the sensor is now valid, we can return it.
2023ce53722SRobert Mustacchi  *
2033ce53722SRobert Mustacchi  * After this point, the sensor is considered valid for use. Once the consumer
2043ce53722SRobert Mustacchi  * is finished with the sensor, it should be released by calling
2053ce53722SRobert Mustacchi  * ksensor_release().
2063ce53722SRobert Mustacchi  *
2073ce53722SRobert Mustacchi  * An important aspect of the above scheme is that the KSENSOR_F_BUSY flag is
2083ce53722SRobert Mustacchi  * required to progress through the validation and holding of the device. This
2093ce53722SRobert Mustacchi  * makes sure that only one thread is attempting to attach it at a given time. A
2103ce53722SRobert Mustacchi  * reasonable future optimization would be to amortize this cost in open(9E)
2113ce53722SRobert Mustacchi  * and close(9E) of the minor and to bump a count as it being referenced as long
2123ce53722SRobert Mustacchi  * as it is open.
2133ce53722SRobert Mustacchi  *
2143ce53722SRobert Mustacchi  * -----------------------------
2153ce53722SRobert Mustacchi  * Character Device Registration
2163ce53722SRobert Mustacchi  * -----------------------------
2173ce53722SRobert Mustacchi  *
2183ce53722SRobert Mustacchi  * The 'ksensor' character device driver can come and go. To support this, the
2193ce53722SRobert Mustacchi  * ksensor framework communicates with the ksensor character device by a
2203ce53722SRobert Mustacchi  * well-defined set of callbacks, used to indicate sensor addition and removal.
2213ce53722SRobert Mustacchi  * The ksensor character device is found in uts/common/io/ksensor/ksensor_drv.c.
2223ce53722SRobert Mustacchi  * The ksensor character device is responsible for creating and destroying minor
2233ce53722SRobert Mustacchi  * nodes.
2243ce53722SRobert Mustacchi  *
2253ce53722SRobert Mustacchi  * Each ksensor_t has a flag, KSENSOR_F_NOTIFIED, that is used to indicate
2263ce53722SRobert Mustacchi  * whether or not the registered driver has been notified of the sensor. When a
2273ce53722SRobert Mustacchi  * callback is first registered, we'll walk through the entire list of nodes to
2283ce53722SRobert Mustacchi  * make sure that its minor has been created. When unregistering, the minor node
2293ce53722SRobert Mustacchi  * remove callback will not be called; however, this can generally by dealt with
2303ce53722SRobert Mustacchi  * by calling something like ddi_remove_minor_node(dip, NULL).
2313ce53722SRobert Mustacchi  *
2323ce53722SRobert Mustacchi  * -------
2333ce53722SRobert Mustacchi  * Locking
2343ce53722SRobert Mustacchi  * -------
2353ce53722SRobert Mustacchi  *
2363ce53722SRobert Mustacchi  * The following rules apply to dealing with lock ordering:
2373ce53722SRobert Mustacchi  *
2383ce53722SRobert Mustacchi  * 1. The global ksensor_g_mutex protects all global data and must be taken
2393ce53722SRobert Mustacchi  *    before a ksensor_t's individual mutex.
2403ce53722SRobert Mustacchi  *
2413ce53722SRobert Mustacchi  * 2. A thread should not hold any two ksensor_t's mutex at any time.
2423ce53722SRobert Mustacchi  *
2433ce53722SRobert Mustacchi  * 3. No locks should be held when attempting to grab or manipulate a
2443ce53722SRobert Mustacchi  *    dev_info_t, e.g. ndi_devi_enter().
2453ce53722SRobert Mustacchi  *
2463ce53722SRobert Mustacchi  * 4. Unless the ksensor is actively being held, whenever a ksensor is found,
2473ce53722SRobert Mustacchi  *    one must check whether the ksensor_dip_t flag KSENSOR_DIP_F_REMOVED is
2483ce53722SRobert Mustacchi  *    set or not and whether the ksensor_t's KSENSOR_F_VALID flag is set.
2493ce53722SRobert Mustacchi  */
2503ce53722SRobert Mustacchi 
2513ce53722SRobert Mustacchi #include <sys/types.h>
2523ce53722SRobert Mustacchi #include <sys/file.h>
2533ce53722SRobert Mustacchi #include <sys/errno.h>
2543ce53722SRobert Mustacchi #include <sys/cred.h>
2553ce53722SRobert Mustacchi #include <sys/ddi.h>
2563ce53722SRobert Mustacchi #include <sys/stat.h>
2573ce53722SRobert Mustacchi #include <sys/sunddi.h>
2583ce53722SRobert Mustacchi #include <sys/sunndi.h>
2593ce53722SRobert Mustacchi #include <sys/esunddi.h>
2603ce53722SRobert Mustacchi #include <sys/ksensor_impl.h>
2613ce53722SRobert Mustacchi #include <sys/ddi_impldefs.h>
2623ce53722SRobert Mustacchi #include <sys/pci.h>
2633ce53722SRobert Mustacchi #include <sys/avl.h>
2643ce53722SRobert Mustacchi #include <sys/list.h>
2653ce53722SRobert Mustacchi #include <sys/stddef.h>
2663ce53722SRobert Mustacchi #include <sys/sysmacros.h>
2673ce53722SRobert Mustacchi #include <sys/fs/dv_node.h>
2683ce53722SRobert Mustacchi 
2693ce53722SRobert Mustacchi typedef enum {
2703ce53722SRobert Mustacchi 	/*
2713ce53722SRobert Mustacchi 	 * This flag indicates that the subscribing ksensor character device has
2723ce53722SRobert Mustacchi 	 * been notified about this flag.
2733ce53722SRobert Mustacchi 	 */
2743ce53722SRobert Mustacchi 	KSENSOR_F_NOTIFIED	= 1 << 0,
2753ce53722SRobert Mustacchi 	/*
2763ce53722SRobert Mustacchi 	 * This indicates that the sensor is currently valid, meaning that the
2773ce53722SRobert Mustacchi 	 * ops vector and argument are safe to use. This is removed when a
2783ce53722SRobert Mustacchi 	 * driver with a sensor is detached.
2793ce53722SRobert Mustacchi 	 */
2803ce53722SRobert Mustacchi 	KSENSOR_F_VALID		= 1 << 1,
2813ce53722SRobert Mustacchi 	/*
2823ce53722SRobert Mustacchi 	 * Indicates that a client has a hold on the sensor for some purpose.
2833ce53722SRobert Mustacchi 	 * This must be set before trying to get an NDI hold. Once this is set
2843ce53722SRobert Mustacchi 	 * and a NDI hold is in place, it is safe to use the operations vector
2853ce53722SRobert Mustacchi 	 * and argument.
2863ce53722SRobert Mustacchi 	 */
2873ce53722SRobert Mustacchi 	KSENSOR_F_BUSY		= 1 << 2,
2883ce53722SRobert Mustacchi } ksensor_flags_t;
2893ce53722SRobert Mustacchi 
2903ce53722SRobert Mustacchi typedef enum {
2913ce53722SRobert Mustacchi 	KSENSOR_DIP_F_REMOVED	= 1 << 0
2923ce53722SRobert Mustacchi } ksensor_dip_flags_t;
2933ce53722SRobert Mustacchi 
2943ce53722SRobert Mustacchi typedef struct {
2953ce53722SRobert Mustacchi 	list_node_t ksdip_link;
2963ce53722SRobert Mustacchi 	ksensor_dip_flags_t ksdip_flags;
2973ce53722SRobert Mustacchi 	dev_info_t *ksdip_dip;
2983ce53722SRobert Mustacchi 	ddi_unbind_callback_t ksdip_cb;
2993ce53722SRobert Mustacchi 	list_t ksdip_sensors;
3003ce53722SRobert Mustacchi } ksensor_dip_t;
3013ce53722SRobert Mustacchi 
3023ce53722SRobert Mustacchi typedef struct {
3033ce53722SRobert Mustacchi 	kmutex_t ksensor_mutex;
3043ce53722SRobert Mustacchi 	kcondvar_t ksensor_cv;
3053ce53722SRobert Mustacchi 	ksensor_flags_t ksensor_flags;
3063ce53722SRobert Mustacchi 	list_node_t ksensor_dip_list;
3073ce53722SRobert Mustacchi 	avl_node_t ksensor_id_avl;
3083ce53722SRobert Mustacchi 	uint_t ksensor_nwaiters;
3093ce53722SRobert Mustacchi 	ksensor_dip_t *ksensor_ksdip;
3103ce53722SRobert Mustacchi 	char *ksensor_name;
3113ce53722SRobert Mustacchi 	char *ksensor_class;
3123ce53722SRobert Mustacchi 	id_t ksensor_id;
3133ce53722SRobert Mustacchi 	const ksensor_ops_t *ksensor_ops;
3143ce53722SRobert Mustacchi 	void *ksensor_arg;
3153ce53722SRobert Mustacchi } ksensor_t;
3163ce53722SRobert Mustacchi 
3173ce53722SRobert Mustacchi static kmutex_t ksensor_g_mutex;
3183ce53722SRobert Mustacchi static id_space_t *ksensor_ids;
3193ce53722SRobert Mustacchi static list_t ksensor_dips;
3203ce53722SRobert Mustacchi static avl_tree_t ksensor_avl;
3213ce53722SRobert Mustacchi static dev_info_t *ksensor_cb_dip;
3223ce53722SRobert Mustacchi static ksensor_create_f ksensor_cb_create;
3233ce53722SRobert Mustacchi static ksensor_remove_f ksensor_cb_remove;
3243ce53722SRobert Mustacchi 
3253ce53722SRobert Mustacchi static int
3263ce53722SRobert Mustacchi ksensor_avl_compare(const void *l, const void *r)
3273ce53722SRobert Mustacchi {
3283ce53722SRobert Mustacchi 	const ksensor_t *kl = l;
3293ce53722SRobert Mustacchi 	const ksensor_t *kr = r;
3303ce53722SRobert Mustacchi 
3313ce53722SRobert Mustacchi 	if (kl->ksensor_id > kr->ksensor_id) {
3323ce53722SRobert Mustacchi 		return (1);
3333ce53722SRobert Mustacchi 	} else if (kl->ksensor_id < kr->ksensor_id) {
3343ce53722SRobert Mustacchi 		return (-1);
3353ce53722SRobert Mustacchi 	} else {
3363ce53722SRobert Mustacchi 		return (0);
3373ce53722SRobert Mustacchi 	}
3383ce53722SRobert Mustacchi }
3393ce53722SRobert Mustacchi 
3403ce53722SRobert Mustacchi static ksensor_t *
3413ce53722SRobert Mustacchi ksensor_find_by_id(id_t id)
3423ce53722SRobert Mustacchi {
3433ce53722SRobert Mustacchi 	ksensor_t k, *ret;
3443ce53722SRobert Mustacchi 
3453ce53722SRobert Mustacchi 	ASSERT(MUTEX_HELD(&ksensor_g_mutex));
3463ce53722SRobert Mustacchi 
3473ce53722SRobert Mustacchi 	k.ksensor_id = id;
3483ce53722SRobert Mustacchi 	return (avl_find(&ksensor_avl, &k, NULL));
3493ce53722SRobert Mustacchi 
3503ce53722SRobert Mustacchi }
3513ce53722SRobert Mustacchi 
3523ce53722SRobert Mustacchi static ksensor_t *
3533ce53722SRobert Mustacchi ksensor_search_ksdip(ksensor_dip_t *ksdip, const char *name, const char *class)
3543ce53722SRobert Mustacchi {
3553ce53722SRobert Mustacchi 	ksensor_t *s;
3563ce53722SRobert Mustacchi 
3573ce53722SRobert Mustacchi 	ASSERT(MUTEX_HELD(&ksensor_g_mutex));
3583ce53722SRobert Mustacchi 
3593ce53722SRobert Mustacchi 	for (s = list_head(&ksdip->ksdip_sensors); s != NULL;
3603ce53722SRobert Mustacchi 	    s = list_next(&ksdip->ksdip_sensors, s)) {
3613ce53722SRobert Mustacchi 		if (strcmp(s->ksensor_name, name) == 0 &&
3623ce53722SRobert Mustacchi 		    strcmp(s->ksensor_class, class) == 0) {
3633ce53722SRobert Mustacchi 			return (s);
3643ce53722SRobert Mustacchi 		}
3653ce53722SRobert Mustacchi 	}
3663ce53722SRobert Mustacchi 
3673ce53722SRobert Mustacchi 	return (NULL);
3683ce53722SRobert Mustacchi }
3693ce53722SRobert Mustacchi 
3703ce53722SRobert Mustacchi static void
3713ce53722SRobert Mustacchi ksensor_free_sensor(ksensor_t *sensor)
3723ce53722SRobert Mustacchi {
3733ce53722SRobert Mustacchi 	strfree(sensor->ksensor_name);
3743ce53722SRobert Mustacchi 	strfree(sensor->ksensor_class);
3753ce53722SRobert Mustacchi 	id_free(ksensor_ids, sensor->ksensor_id);
3763ce53722SRobert Mustacchi 	mutex_destroy(&sensor->ksensor_mutex);
3773ce53722SRobert Mustacchi 	kmem_free(sensor, sizeof (ksensor_t));
3783ce53722SRobert Mustacchi }
3793ce53722SRobert Mustacchi 
3803ce53722SRobert Mustacchi static void
3813ce53722SRobert Mustacchi ksensor_free_dip(ksensor_dip_t *ksdip)
3823ce53722SRobert Mustacchi {
3833ce53722SRobert Mustacchi 	list_destroy(&ksdip->ksdip_sensors);
3843ce53722SRobert Mustacchi 	kmem_free(ksdip, sizeof (ksensor_dip_t));
3853ce53722SRobert Mustacchi }
3863ce53722SRobert Mustacchi 
3873ce53722SRobert Mustacchi static void
3883ce53722SRobert Mustacchi ksensor_dip_unbind_taskq(void *arg)
3893ce53722SRobert Mustacchi {
3903ce53722SRobert Mustacchi 	ksensor_dip_t *k = arg;
3913ce53722SRobert Mustacchi 	ksensor_t *sensor;
3923ce53722SRobert Mustacchi 
3933ce53722SRobert Mustacchi 	/*
3943ce53722SRobert Mustacchi 	 * First notify an attached driver that the nodes are going away
3953ce53722SRobert Mustacchi 	 * before we block and wait on them.
3963ce53722SRobert Mustacchi 	 */
3973ce53722SRobert Mustacchi 	mutex_enter(&ksensor_g_mutex);
3983ce53722SRobert Mustacchi 	for (sensor = list_head(&k->ksdip_sensors); sensor != NULL;
3993ce53722SRobert Mustacchi 	    sensor = list_next(&k->ksdip_sensors, sensor)) {
4003ce53722SRobert Mustacchi 		mutex_enter(&sensor->ksensor_mutex);
4013ce53722SRobert Mustacchi 		if (sensor->ksensor_flags & KSENSOR_F_NOTIFIED) {
4023ce53722SRobert Mustacchi 			ksensor_cb_remove(sensor->ksensor_id,
4033ce53722SRobert Mustacchi 			    sensor->ksensor_name);
4043ce53722SRobert Mustacchi 			sensor->ksensor_flags &= ~KSENSOR_F_NOTIFIED;
4053ce53722SRobert Mustacchi 		}
4063ce53722SRobert Mustacchi 		mutex_exit(&sensor->ksensor_mutex);
4073ce53722SRobert Mustacchi 	}
4083ce53722SRobert Mustacchi 	mutex_exit(&ksensor_g_mutex);
4093ce53722SRobert Mustacchi 
4103ce53722SRobert Mustacchi 	/*
4113ce53722SRobert Mustacchi 	 * Now that the driver has destroyed its minor, wait for anything that's
4123ce53722SRobert Mustacchi 	 * still there.
4133ce53722SRobert Mustacchi 	 */
4143ce53722SRobert Mustacchi 	while ((sensor = list_remove_head(&k->ksdip_sensors)) != NULL) {
4153ce53722SRobert Mustacchi 		mutex_enter(&sensor->ksensor_mutex);
4163ce53722SRobert Mustacchi 		while ((sensor->ksensor_flags & KSENSOR_F_BUSY) != 0 ||
4173ce53722SRobert Mustacchi 		    sensor->ksensor_nwaiters > 0) {
4183ce53722SRobert Mustacchi 			cv_wait(&sensor->ksensor_cv, &sensor->ksensor_mutex);
4193ce53722SRobert Mustacchi 		}
4203ce53722SRobert Mustacchi 		mutex_exit(&sensor->ksensor_mutex);
4213ce53722SRobert Mustacchi 		ksensor_free_sensor(sensor);
4223ce53722SRobert Mustacchi 	}
4233ce53722SRobert Mustacchi 	ksensor_free_dip(k);
4243ce53722SRobert Mustacchi }
4253ce53722SRobert Mustacchi 
4263ce53722SRobert Mustacchi static void
4273ce53722SRobert Mustacchi ksensor_dip_unbind_cb(void *arg, dev_info_t *dip)
4283ce53722SRobert Mustacchi {
4293ce53722SRobert Mustacchi 	ksensor_dip_t *k = arg;
4303ce53722SRobert Mustacchi 	ksensor_t *sensor;
4313ce53722SRobert Mustacchi 
4323ce53722SRobert Mustacchi 	/*
4333ce53722SRobert Mustacchi 	 * Remove the dip and the associated sensors from global visibility.
4343ce53722SRobert Mustacchi 	 * This will ensure that no new clients can find this; however, others
4353ce53722SRobert Mustacchi 	 * may have extent attempts to grab it (but lost the race in an NDI
4363ce53722SRobert Mustacchi 	 * hold).
4373ce53722SRobert Mustacchi 	 */
4383ce53722SRobert Mustacchi 	mutex_enter(&ksensor_g_mutex);
4393ce53722SRobert Mustacchi 	list_remove(&ksensor_dips, k);
4403ce53722SRobert Mustacchi 	k->ksdip_flags |= KSENSOR_DIP_F_REMOVED;
4413ce53722SRobert Mustacchi 	for (sensor = list_head(&k->ksdip_sensors); sensor != NULL;
4423ce53722SRobert Mustacchi 	    sensor = list_next(&k->ksdip_sensors, sensor)) {
4433ce53722SRobert Mustacchi 		avl_remove(&ksensor_avl, sensor);
4443ce53722SRobert Mustacchi 	}
4453ce53722SRobert Mustacchi 	mutex_exit(&ksensor_g_mutex);
4463ce53722SRobert Mustacchi 
4473ce53722SRobert Mustacchi 	(void) taskq_dispatch(system_taskq, ksensor_dip_unbind_taskq, k,
4483ce53722SRobert Mustacchi 	    TQ_SLEEP);
4493ce53722SRobert Mustacchi }
4503ce53722SRobert Mustacchi 
4513ce53722SRobert Mustacchi static ksensor_dip_t *
4523ce53722SRobert Mustacchi ksensor_dip_create(dev_info_t *dip)
4533ce53722SRobert Mustacchi {
4543ce53722SRobert Mustacchi 	ksensor_dip_t *k;
4553ce53722SRobert Mustacchi 
4563ce53722SRobert Mustacchi 	k = kmem_zalloc(sizeof (ksensor_dip_t), KM_SLEEP);
4573ce53722SRobert Mustacchi 	k->ksdip_dip = dip;
4583ce53722SRobert Mustacchi 	k->ksdip_cb.ddiub_cb = ksensor_dip_unbind_cb;
4593ce53722SRobert Mustacchi 	k->ksdip_cb.ddiub_arg = k;
4603ce53722SRobert Mustacchi 	list_create(&k->ksdip_sensors, sizeof (ksensor_t),
4613ce53722SRobert Mustacchi 	    offsetof(ksensor_t, ksensor_dip_list));
4623ce53722SRobert Mustacchi 	e_ddi_register_unbind_callback(dip, &k->ksdip_cb);
4633ce53722SRobert Mustacchi 
4643ce53722SRobert Mustacchi 	return (k);
4653ce53722SRobert Mustacchi }
4663ce53722SRobert Mustacchi 
4673ce53722SRobert Mustacchi static ksensor_dip_t *
4683ce53722SRobert Mustacchi ksensor_dip_find(dev_info_t *dip)
4693ce53722SRobert Mustacchi {
4703ce53722SRobert Mustacchi 	ksensor_dip_t *k;
4713ce53722SRobert Mustacchi 
4723ce53722SRobert Mustacchi 	ASSERT(MUTEX_HELD(&ksensor_g_mutex));
4733ce53722SRobert Mustacchi 	for (k = list_head(&ksensor_dips); k != NULL;
4743ce53722SRobert Mustacchi 	    k = list_next(&ksensor_dips, k)) {
4753ce53722SRobert Mustacchi 		if (dip == k->ksdip_dip) {
4763ce53722SRobert Mustacchi 			return (k);
4773ce53722SRobert Mustacchi 		}
4783ce53722SRobert Mustacchi 	}
4793ce53722SRobert Mustacchi 
4803ce53722SRobert Mustacchi 	return (NULL);
4813ce53722SRobert Mustacchi }
4823ce53722SRobert Mustacchi 
4833ce53722SRobert Mustacchi int
4843ce53722SRobert Mustacchi ksensor_create(dev_info_t *dip, const ksensor_ops_t *ops, void *arg,
4853ce53722SRobert Mustacchi     const char *name, const char *class, id_t *idp)
4863ce53722SRobert Mustacchi {
4873ce53722SRobert Mustacchi 	ksensor_dip_t *ksdip;
4883ce53722SRobert Mustacchi 	ksensor_t *sensor;
4893ce53722SRobert Mustacchi 
4903ce53722SRobert Mustacchi 	if (dip == NULL || ops == NULL || name == NULL || class == NULL ||
4913ce53722SRobert Mustacchi 	    idp == NULL) {
4923ce53722SRobert Mustacchi 		return (EINVAL);
4933ce53722SRobert Mustacchi 	}
4943ce53722SRobert Mustacchi 
4953ce53722SRobert Mustacchi 	if (!DEVI_IS_ATTACHING(dip)) {
4963ce53722SRobert Mustacchi 		return (EAGAIN);
4973ce53722SRobert Mustacchi 	}
4983ce53722SRobert Mustacchi 
4993ce53722SRobert Mustacchi 	mutex_enter(&ksensor_g_mutex);
5003ce53722SRobert Mustacchi 	ksdip = ksensor_dip_find(dip);
5013ce53722SRobert Mustacchi 	if (ksdip == NULL) {
5023ce53722SRobert Mustacchi 		ksdip = ksensor_dip_create(dip);
5033ce53722SRobert Mustacchi 		list_insert_tail(&ksensor_dips, ksdip);
5043ce53722SRobert Mustacchi 	}
5053ce53722SRobert Mustacchi 
5063ce53722SRobert Mustacchi 	sensor = ksensor_search_ksdip(ksdip, name, class);
5073ce53722SRobert Mustacchi 	if (sensor != NULL) {
5083ce53722SRobert Mustacchi 		ASSERT3P(sensor->ksensor_ksdip, ==, ksdip);
5093ce53722SRobert Mustacchi 		if ((sensor->ksensor_flags & KSENSOR_F_VALID) != 0) {
5103ce53722SRobert Mustacchi 			mutex_exit(&ksensor_g_mutex);
5113ce53722SRobert Mustacchi 			dev_err(dip, CE_WARN, "tried to create sensor %s:%s "
5123ce53722SRobert Mustacchi 			    "which is currently active", class, name);
5133ce53722SRobert Mustacchi 			return (EEXIST);
5143ce53722SRobert Mustacchi 		}
5153ce53722SRobert Mustacchi 
5163ce53722SRobert Mustacchi 		sensor->ksensor_ops = ops;
5173ce53722SRobert Mustacchi 		sensor->ksensor_arg = arg;
5183ce53722SRobert Mustacchi 	} else {
5193ce53722SRobert Mustacchi 		sensor = kmem_zalloc(sizeof (ksensor_t), KM_SLEEP);
5203ce53722SRobert Mustacchi 		sensor->ksensor_ksdip = ksdip;
5213ce53722SRobert Mustacchi 		sensor->ksensor_name = ddi_strdup(name, KM_SLEEP);
5223ce53722SRobert Mustacchi 		sensor->ksensor_class = ddi_strdup(class, KM_SLEEP);
5233ce53722SRobert Mustacchi 		sensor->ksensor_id = id_alloc(ksensor_ids);
5243ce53722SRobert Mustacchi 		sensor->ksensor_ops = ops;
5253ce53722SRobert Mustacchi 		sensor->ksensor_arg = arg;
5263ce53722SRobert Mustacchi 		list_insert_tail(&ksdip->ksdip_sensors, sensor);
5273ce53722SRobert Mustacchi 		avl_add(&ksensor_avl, sensor);
5283ce53722SRobert Mustacchi 	}
5293ce53722SRobert Mustacchi 
5303ce53722SRobert Mustacchi 	sensor->ksensor_flags |= KSENSOR_F_VALID;
5313ce53722SRobert Mustacchi 
5323ce53722SRobert Mustacchi 	if (ksensor_cb_create != NULL) {
5333ce53722SRobert Mustacchi 
5343ce53722SRobert Mustacchi 		if (ksensor_cb_create(sensor->ksensor_id, sensor->ksensor_class,
5353ce53722SRobert Mustacchi 		    sensor->ksensor_name) == 0) {
5363ce53722SRobert Mustacchi 			sensor->ksensor_flags |= KSENSOR_F_NOTIFIED;
5373ce53722SRobert Mustacchi 		}
5383ce53722SRobert Mustacchi 	}
5393ce53722SRobert Mustacchi 
5403ce53722SRobert Mustacchi 	*idp = sensor->ksensor_id;
5413ce53722SRobert Mustacchi 	mutex_exit(&ksensor_g_mutex);
5423ce53722SRobert Mustacchi 
5433ce53722SRobert Mustacchi 	return (0);
5443ce53722SRobert Mustacchi }
5453ce53722SRobert Mustacchi 
5463ce53722SRobert Mustacchi int
547*1045e13aSRobert Mustacchi ksensor_create_scalar_pcidev(dev_info_t *dip, uint_t kind,
548*1045e13aSRobert Mustacchi     const ksensor_ops_t *ops, void *arg, const char *name, id_t *idp)
5493ce53722SRobert Mustacchi {
5503ce53722SRobert Mustacchi 	char *pci_name, *type;
551*1045e13aSRobert Mustacchi 	const char *class;
5523ce53722SRobert Mustacchi 	int *regs, ret;
5533ce53722SRobert Mustacchi 	uint_t nregs;
5543ce53722SRobert Mustacchi 	uint16_t bus, dev;
5553ce53722SRobert Mustacchi 
556*1045e13aSRobert Mustacchi 	switch (kind) {
557*1045e13aSRobert Mustacchi 	case SENSOR_KIND_TEMPERATURE:
558*1045e13aSRobert Mustacchi 		class = "ddi_sensor:temperature:pci";
559*1045e13aSRobert Mustacchi 		break;
560*1045e13aSRobert Mustacchi 	case SENSOR_KIND_VOLTAGE:
561*1045e13aSRobert Mustacchi 		class = "ddi_sensor:voltage:pci";
562*1045e13aSRobert Mustacchi 		break;
563*1045e13aSRobert Mustacchi 	case SENSOR_KIND_CURRENT:
564*1045e13aSRobert Mustacchi 		class = "ddi_sensor:current:pci";
565*1045e13aSRobert Mustacchi 		break;
566*1045e13aSRobert Mustacchi 	default:
567*1045e13aSRobert Mustacchi 		return (ENOTSUP);
568*1045e13aSRobert Mustacchi 	}
569*1045e13aSRobert Mustacchi 
5703ce53722SRobert Mustacchi 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0, "device_type",
5713ce53722SRobert Mustacchi 	    &type) != DDI_PROP_SUCCESS) {
5723ce53722SRobert Mustacchi 		return (EINVAL);
5733ce53722SRobert Mustacchi 	}
5743ce53722SRobert Mustacchi 
5753ce53722SRobert Mustacchi 	if (strcmp(type, "pciex") != 0 && strcmp(type, "pci") != 0) {
5763ce53722SRobert Mustacchi 		ddi_prop_free(type);
5773ce53722SRobert Mustacchi 		return (EINVAL);
5783ce53722SRobert Mustacchi 	}
5793ce53722SRobert Mustacchi 	ddi_prop_free(type);
5803ce53722SRobert Mustacchi 
5813ce53722SRobert Mustacchi 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0, "reg",
5823ce53722SRobert Mustacchi 	    &regs, &nregs) != DDI_PROP_SUCCESS) {
5833ce53722SRobert Mustacchi 		return (EINVAL);
5843ce53722SRobert Mustacchi 	}
5853ce53722SRobert Mustacchi 
5863ce53722SRobert Mustacchi 	if (nregs < 1) {
5873ce53722SRobert Mustacchi 		ddi_prop_free(regs);
5883ce53722SRobert Mustacchi 		return (EIO);
5893ce53722SRobert Mustacchi 	}
5903ce53722SRobert Mustacchi 
5913ce53722SRobert Mustacchi 	bus = PCI_REG_BUS_G(regs[0]);
5923ce53722SRobert Mustacchi 	dev = PCI_REG_DEV_G(regs[0]);
5933ce53722SRobert Mustacchi 	ddi_prop_free(regs);
5943ce53722SRobert Mustacchi 
5953ce53722SRobert Mustacchi 	pci_name = kmem_asprintf("%x.%x:%s", bus, dev, name);
5963ce53722SRobert Mustacchi 
597*1045e13aSRobert Mustacchi 	ret = ksensor_create(dip, ops, arg, pci_name, class, idp);
5983ce53722SRobert Mustacchi 	strfree(pci_name);
5993ce53722SRobert Mustacchi 	return (ret);
6003ce53722SRobert Mustacchi }
6013ce53722SRobert Mustacchi 
6023ce53722SRobert Mustacchi /*
6033ce53722SRobert Mustacchi  * When a driver removes a sensor, we basically mark it as invalid. This happens
6043ce53722SRobert Mustacchi  * because drivers can detach and we will need to reattach them when the sensor
6053ce53722SRobert Mustacchi  * is used again.
6063ce53722SRobert Mustacchi  */
6073ce53722SRobert Mustacchi int
6083ce53722SRobert Mustacchi ksensor_remove(dev_info_t *dip, id_t id)
6093ce53722SRobert Mustacchi {
6103ce53722SRobert Mustacchi 	ksensor_dip_t *kdip;
6113ce53722SRobert Mustacchi 	ksensor_t *sensor;
6123ce53722SRobert Mustacchi 
6133ce53722SRobert Mustacchi 	if (!DEVI_IS_ATTACHING(dip) && !DEVI_IS_DETACHING(dip)) {
6143ce53722SRobert Mustacchi 		return (EAGAIN);
6153ce53722SRobert Mustacchi 	}
6163ce53722SRobert Mustacchi 
6173ce53722SRobert Mustacchi 	mutex_enter(&ksensor_g_mutex);
6183ce53722SRobert Mustacchi 	kdip = ksensor_dip_find(dip);
6193ce53722SRobert Mustacchi 	if (kdip == NULL) {
6203ce53722SRobert Mustacchi 		mutex_exit(&ksensor_g_mutex);
6213ce53722SRobert Mustacchi 		return (ENOENT);
6223ce53722SRobert Mustacchi 	}
6233ce53722SRobert Mustacchi 
6243ce53722SRobert Mustacchi 	for (sensor = list_head(&kdip->ksdip_sensors); sensor != NULL;
6253ce53722SRobert Mustacchi 	    sensor = list_next(&kdip->ksdip_sensors, sensor)) {
6263ce53722SRobert Mustacchi 		if (sensor->ksensor_id == id || id == KSENSOR_ALL_IDS) {
6273ce53722SRobert Mustacchi 			mutex_enter(&sensor->ksensor_mutex);
6283ce53722SRobert Mustacchi 			sensor->ksensor_flags &= ~KSENSOR_F_VALID;
6293ce53722SRobert Mustacchi 			sensor->ksensor_ops = NULL;
6303ce53722SRobert Mustacchi 			sensor->ksensor_arg = NULL;
6313ce53722SRobert Mustacchi 			mutex_exit(&sensor->ksensor_mutex);
6323ce53722SRobert Mustacchi 		}
6333ce53722SRobert Mustacchi 	}
6343ce53722SRobert Mustacchi 	mutex_exit(&ksensor_g_mutex);
6353ce53722SRobert Mustacchi 	return (0);
6363ce53722SRobert Mustacchi }
6373ce53722SRobert Mustacchi 
6383ce53722SRobert Mustacchi static void
6393ce53722SRobert Mustacchi ksensor_release(ksensor_t *sensor)
6403ce53722SRobert Mustacchi {
6413ce53722SRobert Mustacchi 	int circ;
6423ce53722SRobert Mustacchi 	dev_info_t *pdip;
6433ce53722SRobert Mustacchi 
6443ce53722SRobert Mustacchi 	ddi_release_devi(sensor->ksensor_ksdip->ksdip_dip);
6453ce53722SRobert Mustacchi 
6463ce53722SRobert Mustacchi 	mutex_enter(&sensor->ksensor_mutex);
6473ce53722SRobert Mustacchi 	sensor->ksensor_flags &= ~KSENSOR_F_BUSY;
6483ce53722SRobert Mustacchi 	cv_broadcast(&sensor->ksensor_cv);
6493ce53722SRobert Mustacchi 	mutex_exit(&sensor->ksensor_mutex);
6503ce53722SRobert Mustacchi }
6513ce53722SRobert Mustacchi 
6523ce53722SRobert Mustacchi static int
6533ce53722SRobert Mustacchi ksensor_hold_by_id(id_t id, ksensor_t **outp)
6543ce53722SRobert Mustacchi {
6553ce53722SRobert Mustacchi 	int circ;
6563ce53722SRobert Mustacchi 	ksensor_t *sensor;
6573ce53722SRobert Mustacchi 	dev_info_t *pdip;
6583ce53722SRobert Mustacchi 
6593ce53722SRobert Mustacchi restart:
6603ce53722SRobert Mustacchi 	mutex_enter(&ksensor_g_mutex);
6613ce53722SRobert Mustacchi 	sensor = ksensor_find_by_id(id);
6623ce53722SRobert Mustacchi 	if (sensor == NULL) {
6633ce53722SRobert Mustacchi 		mutex_exit(&ksensor_g_mutex);
6643ce53722SRobert Mustacchi 		*outp = NULL;
6653ce53722SRobert Mustacchi 		return (ESTALE);
6663ce53722SRobert Mustacchi 	}
6673ce53722SRobert Mustacchi 
6683ce53722SRobert Mustacchi 	if ((sensor->ksensor_ksdip->ksdip_flags & KSENSOR_DIP_F_REMOVED) != 0) {
6693ce53722SRobert Mustacchi 		mutex_exit(&ksensor_g_mutex);
6703ce53722SRobert Mustacchi 		*outp = NULL;
6713ce53722SRobert Mustacchi 		return (ESTALE);
6723ce53722SRobert Mustacchi 	}
6733ce53722SRobert Mustacchi 
6743ce53722SRobert Mustacchi 	mutex_enter(&sensor->ksensor_mutex);
6753ce53722SRobert Mustacchi 	if ((sensor->ksensor_flags & KSENSOR_F_BUSY) != 0) {
6763ce53722SRobert Mustacchi 		mutex_exit(&ksensor_g_mutex);
6773ce53722SRobert Mustacchi 		sensor->ksensor_nwaiters++;
6783ce53722SRobert Mustacchi 		while ((sensor->ksensor_flags & KSENSOR_F_BUSY) != 0) {
6793ce53722SRobert Mustacchi 			int cv = cv_wait_sig(&sensor->ksensor_cv,
6803ce53722SRobert Mustacchi 			    &sensor->ksensor_mutex);
6813ce53722SRobert Mustacchi 			if (cv == 0) {
6823ce53722SRobert Mustacchi 				sensor->ksensor_nwaiters--;
6833ce53722SRobert Mustacchi 				cv_broadcast(&sensor->ksensor_cv);
6843ce53722SRobert Mustacchi 				mutex_exit(&sensor->ksensor_mutex);
6853ce53722SRobert Mustacchi 				*outp = NULL;
6863ce53722SRobert Mustacchi 				return (EINTR);
6873ce53722SRobert Mustacchi 			}
6883ce53722SRobert Mustacchi 		}
6893ce53722SRobert Mustacchi 		sensor->ksensor_nwaiters--;
6903ce53722SRobert Mustacchi 		cv_broadcast(&sensor->ksensor_cv);
6913ce53722SRobert Mustacchi 		mutex_exit(&sensor->ksensor_mutex);
6923ce53722SRobert Mustacchi 		goto restart;
6933ce53722SRobert Mustacchi 	}
6943ce53722SRobert Mustacchi 
6953ce53722SRobert Mustacchi 	/*
6963ce53722SRobert Mustacchi 	 * We have obtained ownership of the sensor. At this point, we should
6973ce53722SRobert Mustacchi 	 * check to see if it's valid or not.
6983ce53722SRobert Mustacchi 	 */
6993ce53722SRobert Mustacchi 	sensor->ksensor_flags |= KSENSOR_F_BUSY;
7003ce53722SRobert Mustacchi 	pdip = ddi_get_parent(sensor->ksensor_ksdip->ksdip_dip);
7013ce53722SRobert Mustacchi 	mutex_exit(&sensor->ksensor_mutex);
7023ce53722SRobert Mustacchi 	mutex_exit(&ksensor_g_mutex);
7033ce53722SRobert Mustacchi 
7043ce53722SRobert Mustacchi 	/*
7053ce53722SRobert Mustacchi 	 * Grab a reference on the device node to ensure that it won't go away.
7063ce53722SRobert Mustacchi 	 */
7073ce53722SRobert Mustacchi 	ndi_devi_enter(pdip, &circ);
7083ce53722SRobert Mustacchi 	e_ddi_hold_devi(sensor->ksensor_ksdip->ksdip_dip);
7093ce53722SRobert Mustacchi 	ndi_devi_exit(pdip, circ);
7103ce53722SRobert Mustacchi 
7113ce53722SRobert Mustacchi 	/*
7123ce53722SRobert Mustacchi 	 * Now that we have an NDI hold, check if it's valid or not. It may have
7133ce53722SRobert Mustacchi 	 * become invalid while we were waiting due to a race.
7143ce53722SRobert Mustacchi 	 */
7153ce53722SRobert Mustacchi 	mutex_enter(&ksensor_g_mutex);
7163ce53722SRobert Mustacchi 	if ((sensor->ksensor_ksdip->ksdip_flags & KSENSOR_DIP_F_REMOVED) != 0) {
7173ce53722SRobert Mustacchi 		mutex_exit(&ksensor_g_mutex);
7183ce53722SRobert Mustacchi 		ksensor_release(sensor);
7193ce53722SRobert Mustacchi 		return (ESTALE);
7203ce53722SRobert Mustacchi 	}
7213ce53722SRobert Mustacchi 
7223ce53722SRobert Mustacchi 	mutex_enter(&sensor->ksensor_mutex);
7233ce53722SRobert Mustacchi 	if ((sensor->ksensor_flags & KSENSOR_F_VALID) == 0) {
7243ce53722SRobert Mustacchi 		mutex_exit(&sensor->ksensor_mutex);
7253ce53722SRobert Mustacchi 		mutex_exit(&ksensor_g_mutex);
7263ce53722SRobert Mustacchi 		(void) ndi_devi_config(pdip, NDI_NO_EVENT);
7273ce53722SRobert Mustacchi 		mutex_enter(&ksensor_g_mutex);
7283ce53722SRobert Mustacchi 		mutex_enter(&sensor->ksensor_mutex);
7293ce53722SRobert Mustacchi 
7303ce53722SRobert Mustacchi 		/*
7313ce53722SRobert Mustacchi 		 * If we attempted to reattach it and it isn't now valid, fail
7323ce53722SRobert Mustacchi 		 * this request.
7333ce53722SRobert Mustacchi 		 */
7343ce53722SRobert Mustacchi 		if ((sensor->ksensor_ksdip->ksdip_flags &
7353ce53722SRobert Mustacchi 		    KSENSOR_DIP_F_REMOVED) != 0 ||
7363ce53722SRobert Mustacchi 		    (sensor->ksensor_flags & KSENSOR_F_VALID) == 0) {
7373ce53722SRobert Mustacchi 			mutex_exit(&sensor->ksensor_mutex);
7383ce53722SRobert Mustacchi 			mutex_exit(&ksensor_g_mutex);
7393ce53722SRobert Mustacchi 			ksensor_release(sensor);
7403ce53722SRobert Mustacchi 			return (ESTALE);
7413ce53722SRobert Mustacchi 		}
7423ce53722SRobert Mustacchi 	}
7433ce53722SRobert Mustacchi 	mutex_exit(&sensor->ksensor_mutex);
7443ce53722SRobert Mustacchi 	mutex_exit(&ksensor_g_mutex);
7453ce53722SRobert Mustacchi 	*outp = sensor;
7463ce53722SRobert Mustacchi 
7473ce53722SRobert Mustacchi 	return (0);
7483ce53722SRobert Mustacchi }
7493ce53722SRobert Mustacchi 
7503ce53722SRobert Mustacchi int
7513ce53722SRobert Mustacchi ksensor_op_kind(id_t id, sensor_ioctl_kind_t *kind)
7523ce53722SRobert Mustacchi {
7533ce53722SRobert Mustacchi 	int ret;
7543ce53722SRobert Mustacchi 	ksensor_t *sensor;
7553ce53722SRobert Mustacchi 
7563ce53722SRobert Mustacchi 	if ((ret = ksensor_hold_by_id(id, &sensor)) != 0) {
7573ce53722SRobert Mustacchi 		return (ret);
7583ce53722SRobert Mustacchi 	}
7593ce53722SRobert Mustacchi 
7603ce53722SRobert Mustacchi 	ret = sensor->ksensor_ops->kso_kind(sensor->ksensor_arg, kind);
7613ce53722SRobert Mustacchi 	ksensor_release(sensor);
7623ce53722SRobert Mustacchi 
7633ce53722SRobert Mustacchi 	return (ret);
7643ce53722SRobert Mustacchi }
7653ce53722SRobert Mustacchi 
7663ce53722SRobert Mustacchi int
767*1045e13aSRobert Mustacchi ksensor_op_scalar(id_t id, sensor_ioctl_scalar_t *scalar)
7683ce53722SRobert Mustacchi {
7693ce53722SRobert Mustacchi 	int ret;
7703ce53722SRobert Mustacchi 	ksensor_t *sensor;
7713ce53722SRobert Mustacchi 
7723ce53722SRobert Mustacchi 	if ((ret = ksensor_hold_by_id(id, &sensor)) != 0) {
7733ce53722SRobert Mustacchi 		return (ret);
7743ce53722SRobert Mustacchi 	}
7753ce53722SRobert Mustacchi 
776*1045e13aSRobert Mustacchi 	ret = sensor->ksensor_ops->kso_scalar(sensor->ksensor_arg, scalar);
7773ce53722SRobert Mustacchi 	ksensor_release(sensor);
7783ce53722SRobert Mustacchi 
7793ce53722SRobert Mustacchi 	return (ret);
7803ce53722SRobert Mustacchi }
7813ce53722SRobert Mustacchi 
7823ce53722SRobert Mustacchi void
7833ce53722SRobert Mustacchi ksensor_unregister(dev_info_t *reg_dip)
7843ce53722SRobert Mustacchi {
7853ce53722SRobert Mustacchi 	ksensor_t *sensor;
7863ce53722SRobert Mustacchi 
7873ce53722SRobert Mustacchi 	mutex_enter(&ksensor_g_mutex);
7883ce53722SRobert Mustacchi 	if (ksensor_cb_dip != reg_dip) {
7893ce53722SRobert Mustacchi 		dev_err(reg_dip, CE_PANIC, "asked to unregister illegal dip");
7903ce53722SRobert Mustacchi 	}
7913ce53722SRobert Mustacchi 
7923ce53722SRobert Mustacchi 	for (sensor = avl_first(&ksensor_avl); sensor != NULL; sensor =
7933ce53722SRobert Mustacchi 	    AVL_NEXT(&ksensor_avl, sensor)) {
7943ce53722SRobert Mustacchi 		mutex_enter(&sensor->ksensor_mutex);
7953ce53722SRobert Mustacchi 		sensor->ksensor_flags &= ~KSENSOR_F_NOTIFIED;
7963ce53722SRobert Mustacchi 		mutex_exit(&sensor->ksensor_mutex);
7973ce53722SRobert Mustacchi 	}
7983ce53722SRobert Mustacchi 
7993ce53722SRobert Mustacchi 	ksensor_cb_dip = NULL;
8003ce53722SRobert Mustacchi 	ksensor_cb_create = NULL;
8013ce53722SRobert Mustacchi 	ksensor_cb_remove = NULL;
8023ce53722SRobert Mustacchi 	mutex_exit(&ksensor_g_mutex);
8033ce53722SRobert Mustacchi }
8043ce53722SRobert Mustacchi 
8053ce53722SRobert Mustacchi int
8063ce53722SRobert Mustacchi ksensor_register(dev_info_t *reg_dip, ksensor_create_f create,
8073ce53722SRobert Mustacchi     ksensor_remove_f remove)
8083ce53722SRobert Mustacchi {
8093ce53722SRobert Mustacchi 	ksensor_t *sensor;
8103ce53722SRobert Mustacchi 
8113ce53722SRobert Mustacchi 	mutex_enter(&ksensor_g_mutex);
8123ce53722SRobert Mustacchi 	if (ksensor_cb_dip != NULL) {
8133ce53722SRobert Mustacchi 		dev_err(reg_dip, CE_WARN, "kernel sensors are already "
8143ce53722SRobert Mustacchi 		    "registered");
8153ce53722SRobert Mustacchi 		mutex_exit(&ksensor_g_mutex);
8163ce53722SRobert Mustacchi 		return (EEXIST);
8173ce53722SRobert Mustacchi 	}
8183ce53722SRobert Mustacchi 
8193ce53722SRobert Mustacchi 	ksensor_cb_dip = reg_dip;
8203ce53722SRobert Mustacchi 	ksensor_cb_create = create;
8213ce53722SRobert Mustacchi 	ksensor_cb_remove = remove;
8223ce53722SRobert Mustacchi 
8233ce53722SRobert Mustacchi 	for (sensor = avl_first(&ksensor_avl); sensor != NULL; sensor =
8243ce53722SRobert Mustacchi 	    AVL_NEXT(&ksensor_avl, sensor)) {
8253ce53722SRobert Mustacchi 		mutex_enter(&sensor->ksensor_mutex);
8263ce53722SRobert Mustacchi 		ASSERT0(sensor->ksensor_flags & KSENSOR_F_NOTIFIED);
8273ce53722SRobert Mustacchi 
8283ce53722SRobert Mustacchi 		if (ksensor_cb_create(sensor->ksensor_id, sensor->ksensor_class,
8293ce53722SRobert Mustacchi 		    sensor->ksensor_name) == 0) {
8303ce53722SRobert Mustacchi 			sensor->ksensor_flags |= KSENSOR_F_NOTIFIED;
8313ce53722SRobert Mustacchi 		}
8323ce53722SRobert Mustacchi 
8333ce53722SRobert Mustacchi 		mutex_exit(&sensor->ksensor_mutex);
8343ce53722SRobert Mustacchi 	}
8353ce53722SRobert Mustacchi 
8363ce53722SRobert Mustacchi 	mutex_exit(&ksensor_g_mutex);
8373ce53722SRobert Mustacchi 
8383ce53722SRobert Mustacchi 	return (0);
8393ce53722SRobert Mustacchi }
8403ce53722SRobert Mustacchi 
8413ce53722SRobert Mustacchi int
8423ce53722SRobert Mustacchi ksensor_kind_temperature(void *unused, sensor_ioctl_kind_t *k)
8433ce53722SRobert Mustacchi {
8443ce53722SRobert Mustacchi 	k->sik_kind = SENSOR_KIND_TEMPERATURE;
8453ce53722SRobert Mustacchi 	return (0);
8463ce53722SRobert Mustacchi }
8473ce53722SRobert Mustacchi 
848*1045e13aSRobert Mustacchi int
849*1045e13aSRobert Mustacchi ksensor_kind_current(void *unused, sensor_ioctl_kind_t *k)
850*1045e13aSRobert Mustacchi {
851*1045e13aSRobert Mustacchi 	k->sik_kind = SENSOR_KIND_CURRENT;
852*1045e13aSRobert Mustacchi 	return (0);
853*1045e13aSRobert Mustacchi }
854*1045e13aSRobert Mustacchi 
855*1045e13aSRobert Mustacchi int
856*1045e13aSRobert Mustacchi ksensor_kind_voltage(void *unused, sensor_ioctl_kind_t *k)
857*1045e13aSRobert Mustacchi {
858*1045e13aSRobert Mustacchi 	k->sik_kind = SENSOR_KIND_VOLTAGE;
859*1045e13aSRobert Mustacchi 	return (0);
860*1045e13aSRobert Mustacchi }
861*1045e13aSRobert Mustacchi 
8623ce53722SRobert Mustacchi void
8633ce53722SRobert Mustacchi ksensor_init(void)
8643ce53722SRobert Mustacchi {
8653ce53722SRobert Mustacchi 	mutex_init(&ksensor_g_mutex, NULL, MUTEX_DRIVER, NULL);
8663ce53722SRobert Mustacchi 	list_create(&ksensor_dips, sizeof (ksensor_dip_t),
8673ce53722SRobert Mustacchi 	    offsetof(ksensor_dip_t, ksdip_link));
8683ce53722SRobert Mustacchi 	ksensor_ids = id_space_create("ksensor", 1, L_MAXMIN32);
8693ce53722SRobert Mustacchi 	avl_create(&ksensor_avl, ksensor_avl_compare, sizeof (ksensor_t),
8703ce53722SRobert Mustacchi 	    offsetof(ksensor_t, ksensor_id_avl));
8713ce53722SRobert Mustacchi }
872