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 2020 Oxide Computer Company
14  */
15 
16 /*
17  * This driver is used to implement parts of the ksensor test suite.
18  */
19 
20 #include <sys/ddi.h>
21 #include <sys/sunddi.h>
22 #include <sys/modctl.h>
23 #include <sys/conf.h>
24 #include <sys/devops.h>
25 #include <sys/zone.h>
26 #include <sys/sensors.h>
27 
28 typedef struct ksensor_test {
29 	dev_info_t *kt_dip;
30 	id_t kt_sensor1;
31 	id_t kt_sensor2;
32 	id_t kt_sensor3;
33 	id_t kt_sensor4;
34 	id_t kt_sensor5;
35 	id_t kt_volt;
36 	id_t kt_current;
37 } ksensor_test_t;
38 
39 static int
ksensor_test_temp(void * arg,sensor_ioctl_scalar_t * scalar)40 ksensor_test_temp(void *arg, sensor_ioctl_scalar_t *scalar)
41 {
42 	scalar->sis_unit = SENSOR_UNIT_CELSIUS;
43 	scalar->sis_gran = 4;
44 	scalar->sis_prec = -2;
45 	scalar->sis_value = 23;
46 	return (0);
47 }
48 
49 static const ksensor_ops_t ksensor_test_temp_ops = {
50 	.kso_kind = ksensor_kind_temperature,
51 	.kso_scalar = ksensor_test_temp
52 };
53 
54 static int
ksensor_test_volt(void * arg,sensor_ioctl_scalar_t * scalar)55 ksensor_test_volt(void *arg, sensor_ioctl_scalar_t *scalar)
56 {
57 	scalar->sis_unit = SENSOR_UNIT_VOLTS;
58 	scalar->sis_gran = 1000;
59 	scalar->sis_prec = 0;
60 	scalar->sis_value = 3300;
61 	return (0);
62 }
63 
64 static const ksensor_ops_t ksensor_test_volt_ops = {
65 	.kso_kind = ksensor_kind_voltage,
66 	.kso_scalar = ksensor_test_volt
67 };
68 
69 static int
ksensor_test_current(void * arg,sensor_ioctl_scalar_t * scalar)70 ksensor_test_current(void *arg, sensor_ioctl_scalar_t *scalar)
71 {
72 	scalar->sis_unit = SENSOR_UNIT_AMPS;
73 	scalar->sis_gran = 10;
74 	scalar->sis_prec = 0;
75 	scalar->sis_value = 5;
76 	return (0);
77 }
78 
79 static const ksensor_ops_t ksensor_test_current_ops = {
80 	.kso_kind = ksensor_kind_current,
81 	.kso_scalar = ksensor_test_current
82 };
83 
84 static int
ksensor_test_kind_eio(void * arg,sensor_ioctl_kind_t * kindp)85 ksensor_test_kind_eio(void *arg, sensor_ioctl_kind_t *kindp)
86 {
87 	return (EIO);
88 }
89 
90 static int
ksensor_test_temp_eio(void * arg,sensor_ioctl_scalar_t * scalar)91 ksensor_test_temp_eio(void *arg, sensor_ioctl_scalar_t *scalar)
92 {
93 	return (EIO);
94 }
95 
96 static const ksensor_ops_t ksensor_test_eio_ops = {
97 	.kso_kind = ksensor_test_kind_eio,
98 	.kso_scalar = ksensor_test_temp_eio
99 };
100 
101 static int
ksensor_test_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)102 ksensor_test_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
103 {
104 	int ret;
105 	char buf[128];
106 	ksensor_test_t *kt;
107 
108 	switch (cmd) {
109 	case DDI_RESUME:
110 		return (DDI_SUCCESS);
111 	case DDI_ATTACH:
112 		break;
113 	default:
114 		return (DDI_FAILURE);
115 	}
116 
117 	kt = kmem_zalloc(sizeof (ksensor_test_t), KM_SLEEP);
118 	kt->kt_dip = dip;
119 
120 	(void) snprintf(buf, sizeof (buf), "test.temp.%d.1",
121 	    ddi_get_instance(dip));
122 	if ((ret = ksensor_create(dip, &ksensor_test_temp_ops, NULL, buf,
123 	    "ddi_sensor:test", &kt->kt_sensor1)) != 0) {
124 		dev_err(dip, CE_WARN, "failed to attatch sensor %s: %d", buf,
125 		    ret);
126 		goto err;
127 	}
128 
129 	(void) snprintf(buf, sizeof (buf), "test.temp.%d.2",
130 	    ddi_get_instance(dip));
131 	if ((ret = ksensor_create(dip, &ksensor_test_temp_ops, NULL, buf,
132 	    "ddi_sensor:test", &kt->kt_sensor2)) != 0) {
133 		dev_err(dip, CE_WARN, "failed to attatch sensor %s: %d", buf,
134 		    ret);
135 		goto err;
136 	}
137 
138 	(void) snprintf(buf, sizeof (buf), "test.temp.%d.3",
139 	    ddi_get_instance(dip));
140 	if ((ret = ksensor_create(dip, &ksensor_test_temp_ops, NULL, buf,
141 	    "ddi_sensor:test", &kt->kt_sensor3)) != 0) {
142 		dev_err(dip, CE_WARN, "failed to attach sensor %s: %d", buf,
143 		    ret);
144 		goto err;
145 	}
146 
147 	(void) snprintf(buf, sizeof (buf), "test.temp.%d.4",
148 	    ddi_get_instance(dip));
149 	if ((ret = ksensor_create(dip, &ksensor_test_temp_ops, NULL, buf,
150 	    "ddi_sensor:test", &kt->kt_sensor4)) != 0) {
151 		dev_err(dip, CE_WARN, "failed to attach sensor %s: %d", buf,
152 		    ret);
153 		goto err;
154 	}
155 
156 	(void) snprintf(buf, sizeof (buf), "test.eio.%d",
157 	    ddi_get_instance(dip));
158 	if ((ret = ksensor_create(dip, &ksensor_test_eio_ops, NULL, buf,
159 	    "ddi_sensor:test", &kt->kt_sensor5)) != 0) {
160 		dev_err(dip, CE_WARN, "failed to attach sensor %s: %d", buf,
161 		    ret);
162 		goto err;
163 	}
164 
165 	(void) snprintf(buf, sizeof (buf), "test.volt.%d.1",
166 	    ddi_get_instance(dip));
167 	if ((ret = ksensor_create(dip, &ksensor_test_volt_ops, NULL, buf,
168 	    "ddi_sensor:test", &kt->kt_volt)) != 0) {
169 		dev_err(dip, CE_WARN, "failed to attach sensor %s: %d", buf,
170 		    ret);
171 		goto err;
172 	}
173 
174 	(void) snprintf(buf, sizeof (buf), "test.current.%d.1",
175 	    ddi_get_instance(dip));
176 	if ((ret = ksensor_create(dip, &ksensor_test_current_ops, NULL, buf,
177 	    "ddi_sensor:test", &kt->kt_current)) != 0) {
178 		dev_err(dip, CE_WARN, "failed to attach sensor %s: %d", buf,
179 		    ret);
180 		goto err;
181 	}
182 
183 	ddi_set_driver_private(dip, kt);
184 
185 	return (DDI_SUCCESS);
186 err:
187 	(void) ksensor_remove(dip, KSENSOR_ALL_IDS);
188 	kmem_free(kt, sizeof (ksensor_test_t));
189 	return (DDI_FAILURE);
190 }
191 
192 static int
ksensor_test_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)193 ksensor_test_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
194 {
195 	ksensor_test_t *kt;
196 
197 	switch (cmd) {
198 	case DDI_DETACH:
199 		break;
200 	case DDI_SUSPEND:
201 		return (DDI_SUCCESS);
202 	default:
203 		return (DDI_FAILURE);
204 	}
205 
206 	kt = ddi_get_driver_private(dip);
207 	if (kt == NULL) {
208 		dev_err(dip, CE_WARN, "failed to find ksensor_test_t");
209 		return (DDI_FAILURE);
210 	}
211 
212 	if (kt->kt_sensor3 != 0 &&
213 	    ksensor_remove(dip, kt->kt_sensor3) != 0) {
214 		dev_err(dip, CE_WARN, "failed to remove sensor 3");
215 		return (DDI_FAILURE);
216 	}
217 	kt->kt_sensor3 = 0;
218 	if (ksensor_remove(dip, KSENSOR_ALL_IDS) != 0) {
219 		dev_err(dip, CE_WARN, "failed to remove sensors");
220 		return (DDI_FAILURE);
221 	}
222 	kmem_free(kt, sizeof (*kt));
223 	ddi_set_driver_private(dip, NULL);
224 	return (DDI_SUCCESS);
225 }
226 
227 static struct dev_ops ksensor_test_dev_ops = {
228 	.devo_rev = DEVO_REV,
229 	.devo_refcnt = 0,
230 	.devo_getinfo = nodev,
231 	.devo_identify = nulldev,
232 	.devo_probe = nulldev,
233 	.devo_attach = ksensor_test_attach,
234 	.devo_detach = ksensor_test_detach,
235 	.devo_reset = nodev,
236 	.devo_power = ddi_power,
237 	.devo_quiesce = ddi_quiesce_not_needed,
238 };
239 
240 static struct modldrv ksensor_test_modldrv = {
241 	.drv_modops = &mod_driverops,
242 	.drv_linkinfo = "Kernel Sensor test driver",
243 	.drv_dev_ops = &ksensor_test_dev_ops
244 };
245 
246 static struct modlinkage ksensor_test_modlinkage = {
247 	.ml_rev = MODREV_1,
248 	.ml_linkage = { &ksensor_test_modldrv, NULL }
249 };
250 
251 int
_init(void)252 _init(void)
253 {
254 	return (mod_install(&ksensor_test_modlinkage));
255 }
256 
257 int
_info(struct modinfo * modinfop)258 _info(struct modinfo *modinfop)
259 {
260 	return (mod_info(&ksensor_test_modlinkage, modinfop));
261 }
262 
263 int
_fini(void)264 _fini(void)
265 {
266 	return (mod_remove(&ksensor_test_modlinkage));
267 }
268