xref: /openbsd-src/sys/scsi/safte.c (revision 9593dc34da13a12012033a17061c846c208061c2)
1*9593dc34Smglocker /*	$OpenBSD: safte.c,v 1.68 2024/09/04 07:54:53 mglocker Exp $ */
2d596fd10Sdlg 
3d596fd10Sdlg /*
4d596fd10Sdlg  * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
5d596fd10Sdlg  *
6d596fd10Sdlg  * Permission to use, copy, modify, and distribute this software for any
7d596fd10Sdlg  * purpose with or without fee is hereby granted, provided that the above
8d596fd10Sdlg  * copyright notice and this permission notice appear in all copies.
9d596fd10Sdlg  *
10d596fd10Sdlg  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11d596fd10Sdlg  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12d596fd10Sdlg  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13d596fd10Sdlg  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14d596fd10Sdlg  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15d596fd10Sdlg  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16d596fd10Sdlg  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17d596fd10Sdlg  */
18d596fd10Sdlg 
197579196dSdlg #include "bio.h"
207579196dSdlg 
21d596fd10Sdlg #include <sys/param.h>
22d596fd10Sdlg #include <sys/systm.h>
231122f506Sfgsch #include <sys/device.h>
24d596fd10Sdlg #include <sys/scsiio.h>
25d596fd10Sdlg #include <sys/malloc.h>
265c0b007dSderaadt #include <sys/pool.h>
2760eafd6fSdlg #include <sys/rwlock.h>
28d596fd10Sdlg #include <sys/queue.h>
29d596fd10Sdlg #include <sys/sensors.h>
30d596fd10Sdlg 
317579196dSdlg #if NBIO > 0
327579196dSdlg #include <dev/biovar.h>
33364ebb70Skrw #endif /* NBIO > 0 */
347579196dSdlg 
35d596fd10Sdlg #include <scsi/scsi_all.h>
36d596fd10Sdlg #include <scsi/scsiconf.h>
37d596fd10Sdlg 
38d596fd10Sdlg #include <scsi/safte.h>
39d596fd10Sdlg 
40d596fd10Sdlg #ifdef SAFTE_DEBUG
41d596fd10Sdlg #define DPRINTF(x)	do { if (safte_debug) printf x ; } while (0)
42d596fd10Sdlg int	safte_debug = 1;
43d596fd10Sdlg #else
44d596fd10Sdlg #define DPRINTF(x)	/* x */
45364ebb70Skrw #endif /* SAFTE_DEBUG */
46d596fd10Sdlg 
47d596fd10Sdlg 
48d596fd10Sdlg int	safte_match(struct device *, void *, void *);
49d596fd10Sdlg void	safte_attach(struct device *, struct device *, void *);
50d596fd10Sdlg int	safte_detach(struct device *, int);
51d596fd10Sdlg 
52816e8e59Sdlg struct safte_sensor {
53275cbf62Sderaadt 	struct ksensor		 se_sensor;
54816e8e59Sdlg 	enum {
55816e8e59Sdlg 		SAFTE_T_FAN,
56816e8e59Sdlg 		SAFTE_T_PWRSUP,
57816e8e59Sdlg 		SAFTE_T_DOORLOCK,
58816e8e59Sdlg 		SAFTE_T_ALARM,
59816e8e59Sdlg 		SAFTE_T_TEMP
60816e8e59Sdlg 	}			 se_type;
61816e8e59Sdlg 	u_int8_t		*se_field;
62816e8e59Sdlg };
63816e8e59Sdlg 
64d596fd10Sdlg struct safte_softc {
65d596fd10Sdlg 	struct device		 sc_dev;
66d596fd10Sdlg 	struct scsi_link	*sc_link;
6760eafd6fSdlg 	struct rwlock		 sc_lock;
68d596fd10Sdlg 
69816e8e59Sdlg 	u_int			 sc_encbuflen;
70d596fd10Sdlg 	u_char			*sc_encbuf;
71d596fd10Sdlg 
72d596fd10Sdlg 	int			 sc_nsensors;
73816e8e59Sdlg 	struct safte_sensor	*sc_sensors;
74275cbf62Sderaadt 	struct ksensordev	 sc_sensordev;
75abd9fc28Sdlg 	struct sensor_task	*sc_sensortask;
76816e8e59Sdlg 
77816e8e59Sdlg 	int			 sc_celsius;
78816e8e59Sdlg 	int			 sc_ntemps;
79816e8e59Sdlg 	struct safte_sensor	*sc_temps;
80a104ef5fSkettenis 	u_int8_t		*sc_temperrs;
81816e8e59Sdlg 
827579196dSdlg #if NBIO > 0
837579196dSdlg 	int			 sc_nslots;
847579196dSdlg 	u_int8_t		*sc_slots;
85364ebb70Skrw #endif /* NBIO > 0 */
86d596fd10Sdlg };
87d596fd10Sdlg 
889eaf72d1Smpi const struct cfattach safte_ca = {
89d596fd10Sdlg 	sizeof(struct safte_softc), safte_match, safte_attach, safte_detach
90d596fd10Sdlg };
91d596fd10Sdlg 
92d596fd10Sdlg struct cfdriver safte_cd = {
93d596fd10Sdlg 	NULL, "safte", DV_DULL
94d596fd10Sdlg };
95d596fd10Sdlg 
96d596fd10Sdlg #define DEVNAME(s)	((s)->sc_dev.dv_xname)
97d596fd10Sdlg 
98d596fd10Sdlg int	safte_read_config(struct safte_softc *);
99b054292eSdlg void	safte_read_encstat(void *);
100d596fd10Sdlg 
1017579196dSdlg #if NBIO > 0
1027579196dSdlg int	safte_ioctl(struct device *, u_long, caddr_t);
1037579196dSdlg int	safte_bio_blink(struct safte_softc *, struct bioc_blink *);
104364ebb70Skrw #endif /* NBIO > 0 */
1057579196dSdlg 
106d596fd10Sdlg int64_t	safte_temp2uK(u_int8_t, int);
107d596fd10Sdlg 
108d596fd10Sdlg int
109d596fd10Sdlg safte_match(struct device *parent, void *match, void *aux)
110d596fd10Sdlg {
111a0837789Sdlg 	struct scsi_attach_args		*sa = aux;
1120fbd355cSkrw 	struct scsi_inquiry_data	*inq = &sa->sa_sc_link->inqdata;
113f8bbb75aSkrw 	struct safte_inq		*si;
114f8bbb75aSkrw 
11557343048Skrw 	/* Match on Dell enclosures. */
116bf821d43Sdlg 	if ((inq->device & SID_TYPE) == T_PROCESSOR &&
1177b732f28Skrw 	    SID_ANSII_REV(inq) == SCSI_REV_SPC)
11857343048Skrw 		return 2;
119bf821d43Sdlg 
120d596fd10Sdlg 	if ((inq->device & SID_TYPE) != T_PROCESSOR ||
1217b732f28Skrw 	    SID_ANSII_REV(inq) != SCSI_REV_2 ||
1223da569d0Skrw 	    SID_RESPONSE_FORMAT(inq) != SID_SCSI2_RESPONSE)
12357343048Skrw 		return 0;
124d596fd10Sdlg 
12596a16d09Skrw 	if (inq->additional_length < SID_SCSI2_ALEN + sizeof(*si))
12657343048Skrw 		return 0;
1275c0b007dSderaadt 
12896a16d09Skrw 	si = (struct safte_inq *)&inq->extra;
12996a16d09Skrw 	if (memcmp(si->ident, SAFTE_IDENT, sizeof(si->ident)) == 0)
13057343048Skrw 		return 2;
131d596fd10Sdlg 
13257343048Skrw 	return 0;
133d596fd10Sdlg }
134d596fd10Sdlg 
135d596fd10Sdlg void
136d596fd10Sdlg safte_attach(struct device *parent, struct device *self, void *aux)
137d596fd10Sdlg {
138d596fd10Sdlg 	struct safte_softc		*sc = (struct safte_softc *)self;
139a0837789Sdlg 	struct scsi_attach_args		*sa = aux;
1401e5a5352Sdlg 	int				 i = 0;
141d596fd10Sdlg 
142d596fd10Sdlg 	sc->sc_link = sa->sa_sc_link;
143ba35ccc6Smarco 	sa->sa_sc_link->device_softc = sc;
14460eafd6fSdlg 	rw_init(&sc->sc_lock, DEVNAME(sc));
145d596fd10Sdlg 
14652c6b24cSdlg 	printf("\n");
147d596fd10Sdlg 
148b054292eSdlg 	sc->sc_encbuf = NULL;
149b054292eSdlg 	sc->sc_nsensors = 0;
1503974dfb4Sdlg #if NBIO > 0
151b054292eSdlg 	sc->sc_nslots = 0;
152364ebb70Skrw #endif /* NBIO > 0 */
1537579196dSdlg 
154d596fd10Sdlg 	if (safte_read_config(sc) != 0) {
155d596fd10Sdlg 		printf("%s: unable to read enclosure configuration\n",
156d596fd10Sdlg 		    DEVNAME(sc));
157d596fd10Sdlg 		return;
158d596fd10Sdlg 	}
159d596fd10Sdlg 
160abd9fc28Sdlg 	if (sc->sc_nsensors > 0) {
161abd9fc28Sdlg 		sc->sc_sensortask = sensor_task_register(sc,
162abd9fc28Sdlg 		    safte_read_encstat, 10);
163abd9fc28Sdlg 		if (sc->sc_sensortask == NULL) {
164abd9fc28Sdlg 			printf("%s: unable to register update task\n",
165abd9fc28Sdlg 			    DEVNAME(sc));
166a67129dbStedu 			free(sc->sc_sensors, M_DEVBUF,
167a67129dbStedu 			    sc->sc_nsensors * sizeof(struct safte_sensor));
1681e5a5352Sdlg 			sc->sc_nsensors = sc->sc_ntemps = 0;
169b054292eSdlg 		} else {
170b054292eSdlg 			for (i = 0; i < sc->sc_nsensors; i++)
17127515a6bSderaadt 				sensor_attach(&sc->sc_sensordev,
17227515a6bSderaadt 				    &sc->sc_sensors[i].se_sensor);
17327515a6bSderaadt 			sensordev_install(&sc->sc_sensordev);
174b054292eSdlg 		}
175abd9fc28Sdlg 	}
176b054292eSdlg 
177b054292eSdlg #if NBIO > 0
178b054292eSdlg 	if (sc->sc_nslots > 0 &&
179b054292eSdlg 	    bio_register(self, safte_ioctl) != 0) {
180b054292eSdlg 		printf("%s: unable to register ioctl with bio\n", DEVNAME(sc));
181b054292eSdlg 		sc->sc_nslots = 0;
1821e5a5352Sdlg 	} else
1831e5a5352Sdlg 		i++;
184364ebb70Skrw #endif /* NBIO > 0 */
1851e5a5352Sdlg 
1861e5a5352Sdlg 	if (i) /* if we're doing something, then preinit encbuf and sensors */
1871e5a5352Sdlg 		safte_read_encstat(sc);
1881e5a5352Sdlg 	else {
1895c0b007dSderaadt 		dma_free(sc->sc_encbuf, sc->sc_encbuflen);
1901e5a5352Sdlg 		sc->sc_encbuf = NULL;
1911e5a5352Sdlg 	}
192d596fd10Sdlg }
193d596fd10Sdlg 
194d596fd10Sdlg int
195d596fd10Sdlg safte_detach(struct device *self, int flags)
196d596fd10Sdlg {
197d596fd10Sdlg 	struct safte_softc		*sc = (struct safte_softc *)self;
198d596fd10Sdlg 	int				 i;
199d596fd10Sdlg 
20060eafd6fSdlg 	rw_enter_write(&sc->sc_lock);
2019c336412Sdlg 
2027579196dSdlg #if NBIO > 0
203b054292eSdlg 	if (sc->sc_nslots > 0)
2047579196dSdlg 		bio_unregister(self);
205364ebb70Skrw #endif /* NBIO > 0 */
2067579196dSdlg 
207b054292eSdlg 	if (sc->sc_nsensors > 0) {
20827515a6bSderaadt 		sensordev_deinstall(&sc->sc_sensordev);
209abd9fc28Sdlg 		sensor_task_unregister(sc->sc_sensortask);
210b054292eSdlg 
211d596fd10Sdlg 		for (i = 0; i < sc->sc_nsensors; i++)
21227515a6bSderaadt 			sensor_detach(&sc->sc_sensordev,
21327515a6bSderaadt 			    &sc->sc_sensors[i].se_sensor);
214a67129dbStedu 		free(sc->sc_sensors, M_DEVBUF,
215a67129dbStedu 		    sc->sc_nsensors * sizeof(struct safte_sensor));
216d596fd10Sdlg 	}
217d596fd10Sdlg 
218b054292eSdlg 	if (sc->sc_encbuf != NULL)
2195c0b007dSderaadt 		dma_free(sc->sc_encbuf, sc->sc_encbuflen);
220b054292eSdlg 
22160eafd6fSdlg 	rw_exit_write(&sc->sc_lock);
2229c336412Sdlg 
22357343048Skrw 	return 0;
224d596fd10Sdlg }
225d596fd10Sdlg 
226d596fd10Sdlg int
227d596fd10Sdlg safte_read_config(struct safte_softc *sc)
228d596fd10Sdlg {
2295c0b007dSderaadt 	struct safte_config		*config = NULL;
230f8bbb75aSkrw 	struct safte_readbuf_cmd	*cmd;
231816e8e59Sdlg 	struct safte_sensor		*s;
232f8bbb75aSkrw 	struct scsi_xfer		*xs;
2335c0b007dSderaadt 	int				  error = 0, flags = 0, i, j;
2345c0b007dSderaadt 
2355c0b007dSderaadt 	config = dma_alloc(sizeof(*config), PR_NOWAIT);
2365c0b007dSderaadt 	if (config == NULL)
23757343048Skrw 		return 1;
238d596fd10Sdlg 
2397351cb62Smarco 	if (cold)
240dacf4336Skrw 		SET(flags, SCSI_AUTOCONF);
241f8bbb75aSkrw 	xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_IN | SCSI_SILENT);
2425c0b007dSderaadt 	if (xs == NULL) {
2435c0b007dSderaadt 		error = 1;
2445c0b007dSderaadt 		goto done;
2455c0b007dSderaadt 	}
246f8bbb75aSkrw 	xs->cmdlen = sizeof(*cmd);
2475c0b007dSderaadt 	xs->data = (void *)config;
2485c0b007dSderaadt 	xs->datalen = sizeof(*config);
249f8bbb75aSkrw 	xs->retries = 2;
250f8bbb75aSkrw 	xs->timeout = 30000;
251cc96c0e3Sderaadt 
252664c6166Skrw 	cmd = (struct safte_readbuf_cmd *)&xs->cmd;
25349227f1aSmatthew 	cmd->opcode = READ_BUFFER;
254dacf4336Skrw 	SET(cmd->flags, SAFTE_RD_MODE);
255f8bbb75aSkrw 	cmd->bufferid = SAFTE_RD_CONFIG;
2565c0b007dSderaadt 	cmd->length = htobe16(sizeof(*config));
257f8bbb75aSkrw 
258f8bbb75aSkrw 	error = scsi_xs_sync(xs);
259f8bbb75aSkrw 	scsi_xs_put(xs);
260f8bbb75aSkrw 
2615c0b007dSderaadt 	if (error != 0) {
2625c0b007dSderaadt 		error = 1;
2635c0b007dSderaadt 		goto done;
2645c0b007dSderaadt 	}
265d596fd10Sdlg 
266d596fd10Sdlg 	DPRINTF(("%s: nfans: %d npwrsup: %d nslots: %d doorlock: %d ntemps: %d"
2675c0b007dSderaadt 	    " alarm: %d celsius: %d ntherm: %d\n", DEVNAME(sc), config->nfans,
2685c0b007dSderaadt 	    config->npwrsup, config->nslots, config->doorlock, config->ntemps,
2695c0b007dSderaadt 	    config->alarm, SAFTE_CFG_CELSIUS(config->therm),
2705c0b007dSderaadt 	    SAFTE_CFG_NTHERM(config->therm)));
271d596fd10Sdlg 
2725c0b007dSderaadt 	sc->sc_encbuflen = config->nfans * sizeof(u_int8_t) + /* fan status */
2735c0b007dSderaadt 	    config->npwrsup * sizeof(u_int8_t) + /* power supply status */
2745c0b007dSderaadt 	    config->nslots * sizeof(u_int8_t) + /* device scsi id (lun) */
275816e8e59Sdlg 	    sizeof(u_int8_t) + /* door lock status */
276816e8e59Sdlg 	    sizeof(u_int8_t) + /* speaker status */
2775c0b007dSderaadt 	    config->ntemps * sizeof(u_int8_t) + /* temp sensors */
278816e8e59Sdlg 	    sizeof(u_int16_t); /* temp out of range sensors */
279816e8e59Sdlg 
2805c0b007dSderaadt 	sc->sc_encbuf = dma_alloc(sc->sc_encbuflen, PR_NOWAIT);
2815c0b007dSderaadt 	if (sc->sc_encbuf == NULL) {
2825c0b007dSderaadt 		error = 1;
2835c0b007dSderaadt 		goto done;
2845c0b007dSderaadt 	}
285816e8e59Sdlg 
2865c0b007dSderaadt 	sc->sc_nsensors = config->nfans + config->npwrsup + config->ntemps +
2875c0b007dSderaadt 	    (config->doorlock ? 1 : 0) + (config->alarm ? 1 : 0);
288816e8e59Sdlg 
28957343048Skrw 	sc->sc_sensors = mallocarray(sc->sc_nsensors,
29057343048Skrw 	    sizeof(struct safte_sensor), M_DEVBUF, M_NOWAIT | M_ZERO);
291816e8e59Sdlg 	if (sc->sc_sensors == NULL) {
2925c0b007dSderaadt 		dma_free(sc->sc_encbuf, sc->sc_encbuflen);
293b054292eSdlg 		sc->sc_encbuf = NULL;
294b054292eSdlg 		sc->sc_nsensors = 0;
2955c0b007dSderaadt 		error = 1;
2965c0b007dSderaadt 		goto done;
297816e8e59Sdlg 	}
298816e8e59Sdlg 
29927515a6bSderaadt 	strlcpy(sc->sc_sensordev.xname, DEVNAME(sc),
30027515a6bSderaadt 	    sizeof(sc->sc_sensordev.xname));
30127515a6bSderaadt 
302816e8e59Sdlg 	s = sc->sc_sensors;
303816e8e59Sdlg 
3045c0b007dSderaadt 	for (i = 0; i < config->nfans; i++) {
305816e8e59Sdlg 		s->se_type = SAFTE_T_FAN;
306816e8e59Sdlg 		s->se_field = (u_int8_t *)(sc->sc_encbuf + i);
307816e8e59Sdlg 		s->se_sensor.type = SENSOR_INDICATOR;
308816e8e59Sdlg 		snprintf(s->se_sensor.desc, sizeof(s->se_sensor.desc),
3097447b807Sderaadt 		    "Fan%d", i);
310816e8e59Sdlg 
311816e8e59Sdlg 		s++;
312816e8e59Sdlg 	}
3135c0b007dSderaadt 	j = config->nfans;
314816e8e59Sdlg 
3155c0b007dSderaadt 	for (i = 0; i < config->npwrsup; i++) {
316816e8e59Sdlg 		s->se_type = SAFTE_T_PWRSUP;
31753668107Sdlg 		s->se_field = (u_int8_t *)(sc->sc_encbuf + j + i);
318816e8e59Sdlg 		s->se_sensor.type = SENSOR_INDICATOR;
319816e8e59Sdlg 		snprintf(s->se_sensor.desc, sizeof(s->se_sensor.desc),
3207447b807Sderaadt 		    "PSU%d", i);
321816e8e59Sdlg 
322816e8e59Sdlg 		s++;
323816e8e59Sdlg 	}
3245c0b007dSderaadt 	j += config->npwrsup;
3257579196dSdlg 
3267579196dSdlg #if NBIO > 0
3275c0b007dSderaadt 	sc->sc_nslots = config->nslots;
3287579196dSdlg 	sc->sc_slots = (u_int8_t *)(sc->sc_encbuf + j);
329364ebb70Skrw #endif /* NBIO > 0 */
3305c0b007dSderaadt 	j += config->nslots;
331816e8e59Sdlg 
3325c0b007dSderaadt 	if (config->doorlock) {
333816e8e59Sdlg 		s->se_type = SAFTE_T_DOORLOCK;
334816e8e59Sdlg 		s->se_field = (u_int8_t *)(sc->sc_encbuf + j);
335816e8e59Sdlg 		s->se_sensor.type = SENSOR_INDICATOR;
336816e8e59Sdlg 		strlcpy(s->se_sensor.desc, "doorlock",
337816e8e59Sdlg 		    sizeof(s->se_sensor.desc));
338816e8e59Sdlg 
339816e8e59Sdlg 		s++;
340816e8e59Sdlg 	}
341816e8e59Sdlg 	j++;
342816e8e59Sdlg 
3435c0b007dSderaadt 	if (config->alarm) {
344816e8e59Sdlg 		s->se_type = SAFTE_T_ALARM;
345816e8e59Sdlg 		s->se_field = (u_int8_t *)(sc->sc_encbuf + j);
346816e8e59Sdlg 		s->se_sensor.type = SENSOR_INDICATOR;
347816e8e59Sdlg 		strlcpy(s->se_sensor.desc, "alarm", sizeof(s->se_sensor.desc));
348816e8e59Sdlg 
349816e8e59Sdlg 		s++;
350816e8e59Sdlg 	}
351816e8e59Sdlg 	j++;
352816e8e59Sdlg 
353816e8e59Sdlg 	/*
35457343048Skrw 	 * Stash the temp info so we can get out of range status. Limit the
355*9593dc34Smglocker 	 * number so the out of temp checks can't go into memory it doesn't own.
356816e8e59Sdlg 	 */
3575c0b007dSderaadt 	sc->sc_ntemps = (config->ntemps > 15) ? 15 : config->ntemps;
358816e8e59Sdlg 	sc->sc_temps = s;
3595c0b007dSderaadt 	sc->sc_celsius = SAFTE_CFG_CELSIUS(config->therm);
3605c0b007dSderaadt 	for (i = 0; i < config->ntemps; i++) {
361816e8e59Sdlg 		s->se_type = SAFTE_T_TEMP;
362816e8e59Sdlg 		s->se_field = (u_int8_t *)(sc->sc_encbuf + j + i);
363816e8e59Sdlg 		s->se_sensor.type = SENSOR_TEMP;
364816e8e59Sdlg 
365816e8e59Sdlg 		s++;
366816e8e59Sdlg 	}
3675c0b007dSderaadt 	j += config->ntemps;
368816e8e59Sdlg 
369a104ef5fSkettenis 	sc->sc_temperrs = (u_int8_t *)(sc->sc_encbuf + j);
3705c0b007dSderaadt done:
3715c0b007dSderaadt 	dma_free(config, sizeof(*config));
37257343048Skrw 	return error;
373d596fd10Sdlg }
374d596fd10Sdlg 
375b054292eSdlg void
376b054292eSdlg safte_read_encstat(void *arg)
377d596fd10Sdlg {
378f8bbb75aSkrw 	struct safte_readbuf_cmd	*cmd;
379816e8e59Sdlg 	struct safte_sensor		*s;
380f8bbb75aSkrw 	struct safte_softc		*sc = (struct safte_softc *)arg;
381f8bbb75aSkrw 	struct scsi_xfer		*xs;
382f8bbb75aSkrw 	int				 error, i, flags = 0;
383816e8e59Sdlg 	u_int16_t			 oot;
384d596fd10Sdlg 
38560eafd6fSdlg 	rw_enter_write(&sc->sc_lock);
3869c336412Sdlg 
3877351cb62Smarco 	if (cold)
388dacf4336Skrw 		SET(flags, SCSI_AUTOCONF);
389f8bbb75aSkrw 	xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_IN | SCSI_SILENT);
3904daa7709Smatthew 	if (xs == NULL) {
3914daa7709Smatthew 		rw_exit_write(&sc->sc_lock);
392f8bbb75aSkrw 		return;
3934daa7709Smatthew 	}
394f8bbb75aSkrw 	xs->cmdlen = sizeof(*cmd);
395f8bbb75aSkrw 	xs->data = sc->sc_encbuf;
396f8bbb75aSkrw 	xs->datalen = sc->sc_encbuflen;
397f8bbb75aSkrw 	xs->retries = 2;
398f8bbb75aSkrw 	xs->timeout = 30000;
3997351cb62Smarco 
400664c6166Skrw 	cmd = (struct safte_readbuf_cmd *)&xs->cmd;
40149227f1aSmatthew 	cmd->opcode = READ_BUFFER;
402dacf4336Skrw 	SET(cmd->flags, SAFTE_RD_MODE);
403f8bbb75aSkrw 	cmd->bufferid = SAFTE_RD_ENCSTAT;
404f8bbb75aSkrw 	cmd->length = htobe16(sc->sc_encbuflen);
405f8bbb75aSkrw 
406f8bbb75aSkrw 	error = scsi_xs_sync(xs);
407f8bbb75aSkrw 	scsi_xs_put(xs);
408f8bbb75aSkrw 
409f8bbb75aSkrw 	if (error != 0) {
41060eafd6fSdlg 		rw_exit_write(&sc->sc_lock);
411b054292eSdlg 		return;
412b054292eSdlg 	}
413d596fd10Sdlg 
414816e8e59Sdlg 	for (i = 0; i < sc->sc_nsensors; i++) {
415816e8e59Sdlg 		s = &sc->sc_sensors[i];
41664e2b1d6Skrw 		CLR(s->se_sensor.flags, SENSOR_FUNKNOWN);
417816e8e59Sdlg 
418816e8e59Sdlg 		DPRINTF(("%s: %d type: %d field: 0x%02x\n", DEVNAME(sc), i,
419816e8e59Sdlg 		    s->se_type, *s->se_field));
420816e8e59Sdlg 
421816e8e59Sdlg 		switch (s->se_type) {
422816e8e59Sdlg 		case SAFTE_T_FAN:
423816e8e59Sdlg 			switch (*s->se_field) {
424816e8e59Sdlg 			case SAFTE_FAN_OP:
425816e8e59Sdlg 				s->se_sensor.value = 1;
426816e8e59Sdlg 				s->se_sensor.status = SENSOR_S_OK;
427816e8e59Sdlg 				break;
428816e8e59Sdlg 			case SAFTE_FAN_MF:
429816e8e59Sdlg 				s->se_sensor.value = 0;
430816e8e59Sdlg 				s->se_sensor.status = SENSOR_S_CRIT;
431816e8e59Sdlg 				break;
432816e8e59Sdlg 			case SAFTE_FAN_NOTINST:
433816e8e59Sdlg 			case SAFTE_FAN_UNKNOWN:
434816e8e59Sdlg 			default:
435816e8e59Sdlg 				s->se_sensor.value = 0;
436816e8e59Sdlg 				s->se_sensor.status = SENSOR_S_UNKNOWN;
437dacf4336Skrw 				SET(s->se_sensor.flags, SENSOR_FUNKNOWN);
438816e8e59Sdlg 				break;
439816e8e59Sdlg 			}
440816e8e59Sdlg 			break;
441816e8e59Sdlg 
442816e8e59Sdlg 		case SAFTE_T_PWRSUP:
443816e8e59Sdlg 			switch (*s->se_field) {
444816e8e59Sdlg 			case SAFTE_PWR_OP_ON:
445816e8e59Sdlg 				s->se_sensor.value = 1;
446816e8e59Sdlg 				s->se_sensor.status = SENSOR_S_OK;
447816e8e59Sdlg 				break;
448816e8e59Sdlg 			case SAFTE_PWR_OP_OFF:
449816e8e59Sdlg 				s->se_sensor.value = 0;
450816e8e59Sdlg 				s->se_sensor.status = SENSOR_S_OK;
451816e8e59Sdlg 				break;
452816e8e59Sdlg 			case SAFTE_PWR_MF_ON:
453816e8e59Sdlg 				s->se_sensor.value = 1;
454816e8e59Sdlg 				s->se_sensor.status = SENSOR_S_CRIT;
455816e8e59Sdlg 				break;
456816e8e59Sdlg 			case SAFTE_PWR_MF_OFF:
457816e8e59Sdlg 				s->se_sensor.value = 0;
458816e8e59Sdlg 				s->se_sensor.status = SENSOR_S_CRIT;
459816e8e59Sdlg 				break;
460816e8e59Sdlg 			case SAFTE_PWR_NOTINST:
461816e8e59Sdlg 			case SAFTE_PWR_PRESENT:
462816e8e59Sdlg 			case SAFTE_PWR_UNKNOWN:
463816e8e59Sdlg 				s->se_sensor.value = 0;
464816e8e59Sdlg 				s->se_sensor.status = SENSOR_S_UNKNOWN;
465dacf4336Skrw 				SET(s->se_sensor.flags, SENSOR_FUNKNOWN);
466816e8e59Sdlg 				break;
467816e8e59Sdlg 			}
468816e8e59Sdlg 			break;
469816e8e59Sdlg 
470816e8e59Sdlg 		case SAFTE_T_DOORLOCK:
471816e8e59Sdlg 			switch (*s->se_field) {
472816e8e59Sdlg 			case SAFTE_DOOR_LOCKED:
473816e8e59Sdlg 				s->se_sensor.value = 1;
474816e8e59Sdlg 				s->se_sensor.status = SENSOR_S_OK;
475816e8e59Sdlg 				break;
476816e8e59Sdlg 			case SAFTE_DOOR_UNLOCKED:
477816e8e59Sdlg 				s->se_sensor.value = 0;
478816e8e59Sdlg 				s->se_sensor.status = SENSOR_S_CRIT;
479816e8e59Sdlg 				break;
480816e8e59Sdlg 			case SAFTE_DOOR_UNKNOWN:
481816e8e59Sdlg 				s->se_sensor.value = 0;
482816e8e59Sdlg 				s->se_sensor.status = SENSOR_S_CRIT;
483dacf4336Skrw 				SET(s->se_sensor.flags, SENSOR_FUNKNOWN);
484816e8e59Sdlg 				break;
485816e8e59Sdlg 			}
486816e8e59Sdlg 			break;
487816e8e59Sdlg 
488816e8e59Sdlg 		case SAFTE_T_ALARM:
489816e8e59Sdlg 			switch (*s->se_field) {
490816e8e59Sdlg 			case SAFTE_SPKR_OFF:
491816e8e59Sdlg 				s->se_sensor.value = 0;
492816e8e59Sdlg 				s->se_sensor.status = SENSOR_S_OK;
493816e8e59Sdlg 				break;
494816e8e59Sdlg 			case SAFTE_SPKR_ON:
495816e8e59Sdlg 				s->se_sensor.value = 1;
496816e8e59Sdlg 				s->se_sensor.status = SENSOR_S_CRIT;
497816e8e59Sdlg 				break;
498d596fd10Sdlg 			}
49927899c6aSkrw 			break;
500d596fd10Sdlg 
501816e8e59Sdlg 		case SAFTE_T_TEMP:
502816e8e59Sdlg 			s->se_sensor.value = safte_temp2uK(*s->se_field,
503816e8e59Sdlg 			    sc->sc_celsius);
504816e8e59Sdlg 			break;
505816e8e59Sdlg 		}
506d596fd10Sdlg 	}
507d596fd10Sdlg 
508a104ef5fSkettenis 	oot = _2btol(sc->sc_temperrs);
509816e8e59Sdlg 	for (i = 0; i < sc->sc_ntemps; i++)
510816e8e59Sdlg 		sc->sc_temps[i].se_sensor.status =
511816e8e59Sdlg 		    (oot & (1 << i)) ? SENSOR_S_CRIT : SENSOR_S_OK;
5129c336412Sdlg 
51360eafd6fSdlg 	rw_exit_write(&sc->sc_lock);
514d596fd10Sdlg }
515d596fd10Sdlg 
5167579196dSdlg #if NBIO > 0
5177579196dSdlg int
5187579196dSdlg safte_ioctl(struct device *dev, u_long cmd, caddr_t addr)
5197579196dSdlg {
5207579196dSdlg 	struct safte_softc		*sc = (struct safte_softc *)dev;
5217579196dSdlg 	int				 error = 0;
5227579196dSdlg 
5237579196dSdlg 	switch (cmd) {
5247579196dSdlg 	case BIOCBLINK:
5257579196dSdlg 		error = safte_bio_blink(sc, (struct bioc_blink *)addr);
5267579196dSdlg 		break;
5277579196dSdlg 
5287579196dSdlg 	default:
5297579196dSdlg 		error = EINVAL;
5307579196dSdlg 		break;
5317579196dSdlg 	}
5327579196dSdlg 
53357343048Skrw 	return error;
5347579196dSdlg }
5357579196dSdlg 
5367579196dSdlg int
5377579196dSdlg safte_bio_blink(struct safte_softc *sc, struct bioc_blink *blink)
5387579196dSdlg {
539f8bbb75aSkrw 	struct safte_writebuf_cmd	*cmd;
5407579196dSdlg 	struct safte_slotop		*op;
541f8bbb75aSkrw 	struct scsi_xfer		*xs;
542f8bbb75aSkrw 	int				 error, slot, flags = 0, wantblink;
5437579196dSdlg 
5445ae89792Sderaadt 	switch (blink->bb_status) {
5455ae89792Sderaadt 	case BIOC_SBBLINK:
5465ae89792Sderaadt 		wantblink = 1;
5475ae89792Sderaadt 		break;
5485ae89792Sderaadt 	case BIOC_SBUNBLINK:
5495ae89792Sderaadt 		wantblink = 0;
5505ae89792Sderaadt 		break;
5515ae89792Sderaadt 	default:
55257343048Skrw 		return EINVAL;
5535ae89792Sderaadt 	}
5547579196dSdlg 
55560eafd6fSdlg 	rw_enter_read(&sc->sc_lock);
5567579196dSdlg 	for (slot = 0; slot < sc->sc_nslots; slot++) {
5577579196dSdlg 		if (sc->sc_slots[slot] == blink->bb_target)
5587579196dSdlg 			break;
5597579196dSdlg 	}
56060eafd6fSdlg 	rw_exit_read(&sc->sc_lock);
5617579196dSdlg 
5627579196dSdlg 	if (slot >= sc->sc_nslots)
56357343048Skrw 		return ENODEV;
5647579196dSdlg 
5655c0b007dSderaadt 	op = dma_alloc(sizeof(*op), PR_WAITOK | PR_ZERO);
5667579196dSdlg 
5677579196dSdlg 	op->opcode = SAFTE_WRITE_SLOTOP;
5687579196dSdlg 	op->slot = slot;
5695ae89792Sderaadt 	op->flags |= wantblink ? SAFTE_SLOTOP_IDENTIFY : 0;
5707579196dSdlg 
5717351cb62Smarco 	if (cold)
572dacf4336Skrw 		SET(flags, SCSI_AUTOCONF);
573f8bbb75aSkrw 	xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_OUT | SCSI_SILENT);
574f8bbb75aSkrw 	if (xs == NULL) {
5755c0b007dSderaadt 		dma_free(op, sizeof(*op));
57657343048Skrw 		return ENOMEM;
5777579196dSdlg 	}
578f8bbb75aSkrw 	xs->cmdlen = sizeof(*cmd);
579f8bbb75aSkrw 	xs->data = (void *)op;
580f8bbb75aSkrw 	xs->datalen = sizeof(*op);
581f8bbb75aSkrw 	xs->retries = 2;
582f8bbb75aSkrw 	xs->timeout = 30000;
5837579196dSdlg 
584664c6166Skrw 	cmd = (struct safte_writebuf_cmd *)&xs->cmd;
58549227f1aSmatthew 	cmd->opcode = WRITE_BUFFER;
586dacf4336Skrw 	SET(cmd->flags, SAFTE_WR_MODE);
587f8bbb75aSkrw 	cmd->length = htobe16(sizeof(struct safte_slotop));
588f8bbb75aSkrw 
589f8bbb75aSkrw 	error = scsi_xs_sync(xs);
590f8bbb75aSkrw 	scsi_xs_put(xs);
591f8bbb75aSkrw 
592f8bbb75aSkrw 	if (error != 0) {
593f8bbb75aSkrw 		error = EIO;
594f8bbb75aSkrw 	}
5955c0b007dSderaadt 	dma_free(op, sizeof(*op));
5967579196dSdlg 
59757343048Skrw 	return error;
5987579196dSdlg }
5997579196dSdlg #endif /* NBIO > 0 */
6007579196dSdlg 
601d596fd10Sdlg int64_t
602d596fd10Sdlg safte_temp2uK(u_int8_t measured, int celsius)
603d596fd10Sdlg {
604d596fd10Sdlg 	int64_t				temp;
605d596fd10Sdlg 
606d596fd10Sdlg 	temp = (int64_t)measured;
607d596fd10Sdlg 	temp += SAFTE_TEMP_OFFSET;
60857343048Skrw 	temp *= 1000000; /* Convert to micro (mu) degrees. */
609d596fd10Sdlg 	if (!celsius)
61057343048Skrw 		temp = ((temp - 32000000) * 5) / 9; /* Convert to Celsius. */
611d596fd10Sdlg 
61257343048Skrw 	temp += 273150000; /* Convert to kelvin. */
613d596fd10Sdlg 
61457343048Skrw 	return temp;
615d596fd10Sdlg }
616