1/*	$OpenBSD: safte.c,v 1.67 2021/10/24 16:57:30 mpi Exp $ */
2
3/*
4 * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include "bio.h"
20
21#include <sys/param.h>
22#include <sys/systm.h>
23#include <sys/device.h>
24#include <sys/scsiio.h>
25#include <sys/malloc.h>
26#include <sys/pool.h>
27#include <sys/rwlock.h>
28#include <sys/queue.h>
29#include <sys/sensors.h>
30
31#if NBIO > 0
32#include <dev/biovar.h>
33#endif /* NBIO > 0 */
34
35#include <scsi/scsi_all.h>
36#include <scsi/scsiconf.h>
37
38#include <scsi/safte.h>
39
40#ifdef SAFTE_DEBUG
41#define DPRINTF(x)	do { if (safte_debug) printf x ; } while (0)
42int	safte_debug = 1;
43#else
44#define DPRINTF(x)	/* x */
45#endif /* SAFTE_DEBUG */
46
47
48int	safte_match(struct device *, void *, void *);
49void	safte_attach(struct device *, struct device *, void *);
50int	safte_detach(struct device *, int);
51
52struct safte_sensor {
53	struct ksensor		 se_sensor;
54	enum {
55		SAFTE_T_FAN,
56		SAFTE_T_PWRSUP,
57		SAFTE_T_DOORLOCK,
58		SAFTE_T_ALARM,
59		SAFTE_T_TEMP
60	}			 se_type;
61	u_int8_t		*se_field;
62};
63
64struct safte_softc {
65	struct device		 sc_dev;
66	struct scsi_link	*sc_link;
67	struct rwlock		 sc_lock;
68
69	u_int			 sc_encbuflen;
70	u_char			*sc_encbuf;
71
72	int			 sc_nsensors;
73	struct safte_sensor	*sc_sensors;
74	struct ksensordev	 sc_sensordev;
75	struct sensor_task	*sc_sensortask;
76
77	int			 sc_celsius;
78	int			 sc_ntemps;
79	struct safte_sensor	*sc_temps;
80	u_int8_t		*sc_temperrs;
81
82#if NBIO > 0
83	int			 sc_nslots;
84	u_int8_t		*sc_slots;
85#endif /* NBIO > 0 */
86};
87
88const struct cfattach safte_ca = {
89	sizeof(struct safte_softc), safte_match, safte_attach, safte_detach
90};
91
92struct cfdriver safte_cd = {
93	NULL, "safte", DV_DULL
94};
95
96#define DEVNAME(s)	((s)->sc_dev.dv_xname)
97
98int	safte_read_config(struct safte_softc *);
99void	safte_read_encstat(void *);
100
101#if NBIO > 0
102int	safte_ioctl(struct device *, u_long, caddr_t);
103int	safte_bio_blink(struct safte_softc *, struct bioc_blink *);
104#endif /* NBIO > 0 */
105
106int64_t	safte_temp2uK(u_int8_t, int);
107
108int
109safte_match(struct device *parent, void *match, void *aux)
110{
111	struct scsi_attach_args		*sa = aux;
112	struct scsi_inquiry_data	*inq = &sa->sa_sc_link->inqdata;
113	struct safte_inq		*si;
114
115	/* Match on Dell enclosures. */
116	if ((inq->device & SID_TYPE) == T_PROCESSOR &&
117	    SID_ANSII_REV(inq) == SCSI_REV_SPC)
118		return 2;
119
120	if ((inq->device & SID_TYPE) != T_PROCESSOR ||
121	    SID_ANSII_REV(inq) != SCSI_REV_2 ||
122	    SID_RESPONSE_FORMAT(inq) != SID_SCSI2_RESPONSE)
123		return 0;
124
125	if (inq->additional_length < SID_SCSI2_ALEN + sizeof(*si))
126		return 0;
127
128	si = (struct safte_inq *)&inq->extra;
129	if (memcmp(si->ident, SAFTE_IDENT, sizeof(si->ident)) == 0)
130		return 2;
131
132	return 0;
133}
134
135void
136safte_attach(struct device *parent, struct device *self, void *aux)
137{
138	struct safte_softc		*sc = (struct safte_softc *)self;
139	struct scsi_attach_args		*sa = aux;
140	int				 i = 0;
141
142	sc->sc_link = sa->sa_sc_link;
143	sa->sa_sc_link->device_softc = sc;
144	rw_init(&sc->sc_lock, DEVNAME(sc));
145
146	printf("\n");
147
148	sc->sc_encbuf = NULL;
149	sc->sc_nsensors = 0;
150#if NBIO > 0
151	sc->sc_nslots = 0;
152#endif /* NBIO > 0 */
153
154	if (safte_read_config(sc) != 0) {
155		printf("%s: unable to read enclosure configuration\n",
156		    DEVNAME(sc));
157		return;
158	}
159
160	if (sc->sc_nsensors > 0) {
161		sc->sc_sensortask = sensor_task_register(sc,
162		    safte_read_encstat, 10);
163		if (sc->sc_sensortask == NULL) {
164			printf("%s: unable to register update task\n",
165			    DEVNAME(sc));
166			free(sc->sc_sensors, M_DEVBUF,
167			    sc->sc_nsensors * sizeof(struct safte_sensor));
168			sc->sc_nsensors = sc->sc_ntemps = 0;
169		} else {
170			for (i = 0; i < sc->sc_nsensors; i++)
171				sensor_attach(&sc->sc_sensordev,
172				    &sc->sc_sensors[i].se_sensor);
173			sensordev_install(&sc->sc_sensordev);
174		}
175	}
176
177#if NBIO > 0
178	if (sc->sc_nslots > 0 &&
179	    bio_register(self, safte_ioctl) != 0) {
180		printf("%s: unable to register ioctl with bio\n", DEVNAME(sc));
181		sc->sc_nslots = 0;
182	} else
183		i++;
184#endif /* NBIO > 0 */
185
186	if (i) /* if we're doing something, then preinit encbuf and sensors */
187		safte_read_encstat(sc);
188	else {
189		dma_free(sc->sc_encbuf, sc->sc_encbuflen);
190		sc->sc_encbuf = NULL;
191	}
192}
193
194int
195safte_detach(struct device *self, int flags)
196{
197	struct safte_softc		*sc = (struct safte_softc *)self;
198	int				 i;
199
200	rw_enter_write(&sc->sc_lock);
201
202#if NBIO > 0
203	if (sc->sc_nslots > 0)
204		bio_unregister(self);
205#endif /* NBIO > 0 */
206
207	if (sc->sc_nsensors > 0) {
208		sensordev_deinstall(&sc->sc_sensordev);
209		sensor_task_unregister(sc->sc_sensortask);
210
211		for (i = 0; i < sc->sc_nsensors; i++)
212			sensor_detach(&sc->sc_sensordev,
213			    &sc->sc_sensors[i].se_sensor);
214		free(sc->sc_sensors, M_DEVBUF,
215		    sc->sc_nsensors * sizeof(struct safte_sensor));
216	}
217
218	if (sc->sc_encbuf != NULL)
219		dma_free(sc->sc_encbuf, sc->sc_encbuflen);
220
221	rw_exit_write(&sc->sc_lock);
222
223	return 0;
224}
225
226int
227safte_read_config(struct safte_softc *sc)
228{
229	struct safte_config		*config = NULL;
230	struct safte_readbuf_cmd	*cmd;
231	struct safte_sensor		*s;
232	struct scsi_xfer		*xs;
233	int				  error = 0, flags = 0, i, j;
234
235	config = dma_alloc(sizeof(*config), PR_NOWAIT);
236	if (config == NULL)
237		return 1;
238
239	if (cold)
240		SET(flags, SCSI_AUTOCONF);
241	xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_IN | SCSI_SILENT);
242	if (xs == NULL) {
243		error = 1;
244		goto done;
245	}
246	xs->cmdlen = sizeof(*cmd);
247	xs->data = (void *)config;
248	xs->datalen = sizeof(*config);
249	xs->retries = 2;
250	xs->timeout = 30000;
251
252	cmd = (struct safte_readbuf_cmd *)&xs->cmd;
253	cmd->opcode = READ_BUFFER;
254	SET(cmd->flags, SAFTE_RD_MODE);
255	cmd->bufferid = SAFTE_RD_CONFIG;
256	cmd->length = htobe16(sizeof(*config));
257
258	error = scsi_xs_sync(xs);
259	scsi_xs_put(xs);
260
261	if (error != 0) {
262		error = 1;
263		goto done;
264	}
265
266	DPRINTF(("%s: nfans: %d npwrsup: %d nslots: %d doorlock: %d ntemps: %d"
267	    " alarm: %d celsius: %d ntherm: %d\n", DEVNAME(sc), config->nfans,
268	    config->npwrsup, config->nslots, config->doorlock, config->ntemps,
269	    config->alarm, SAFTE_CFG_CELSIUS(config->therm),
270	    SAFTE_CFG_NTHERM(config->therm)));
271
272	sc->sc_encbuflen = config->nfans * sizeof(u_int8_t) + /* fan status */
273	    config->npwrsup * sizeof(u_int8_t) + /* power supply status */
274	    config->nslots * sizeof(u_int8_t) + /* device scsi id (lun) */
275	    sizeof(u_int8_t) + /* door lock status */
276	    sizeof(u_int8_t) + /* speaker status */
277	    config->ntemps * sizeof(u_int8_t) + /* temp sensors */
278	    sizeof(u_int16_t); /* temp out of range sensors */
279
280	sc->sc_encbuf = dma_alloc(sc->sc_encbuflen, PR_NOWAIT);
281	if (sc->sc_encbuf == NULL) {
282		error = 1;
283		goto done;
284	}
285
286	sc->sc_nsensors = config->nfans + config->npwrsup + config->ntemps +
287	    (config->doorlock ? 1 : 0) + (config->alarm ? 1 : 0);
288
289	sc->sc_sensors = mallocarray(sc->sc_nsensors,
290	    sizeof(struct safte_sensor), M_DEVBUF, M_NOWAIT | M_ZERO);
291	if (sc->sc_sensors == NULL) {
292		dma_free(sc->sc_encbuf, sc->sc_encbuflen);
293		sc->sc_encbuf = NULL;
294		sc->sc_nsensors = 0;
295		error = 1;
296		goto done;
297	}
298
299	strlcpy(sc->sc_sensordev.xname, DEVNAME(sc),
300	    sizeof(sc->sc_sensordev.xname));
301
302	s = sc->sc_sensors;
303
304	for (i = 0; i < config->nfans; i++) {
305		s->se_type = SAFTE_T_FAN;
306		s->se_field = (u_int8_t *)(sc->sc_encbuf + i);
307		s->se_sensor.type = SENSOR_INDICATOR;
308		snprintf(s->se_sensor.desc, sizeof(s->se_sensor.desc),
309		    "Fan%d", i);
310
311		s++;
312	}
313	j = config->nfans;
314
315	for (i = 0; i < config->npwrsup; i++) {
316		s->se_type = SAFTE_T_PWRSUP;
317		s->se_field = (u_int8_t *)(sc->sc_encbuf + j + i);
318		s->se_sensor.type = SENSOR_INDICATOR;
319		snprintf(s->se_sensor.desc, sizeof(s->se_sensor.desc),
320		    "PSU%d", i);
321
322		s++;
323	}
324	j += config->npwrsup;
325
326#if NBIO > 0
327	sc->sc_nslots = config->nslots;
328	sc->sc_slots = (u_int8_t *)(sc->sc_encbuf + j);
329#endif /* NBIO > 0 */
330	j += config->nslots;
331
332	if (config->doorlock) {
333		s->se_type = SAFTE_T_DOORLOCK;
334		s->se_field = (u_int8_t *)(sc->sc_encbuf + j);
335		s->se_sensor.type = SENSOR_INDICATOR;
336		strlcpy(s->se_sensor.desc, "doorlock",
337		    sizeof(s->se_sensor.desc));
338
339		s++;
340	}
341	j++;
342
343	if (config->alarm) {
344		s->se_type = SAFTE_T_ALARM;
345		s->se_field = (u_int8_t *)(sc->sc_encbuf + j);
346		s->se_sensor.type = SENSOR_INDICATOR;
347		strlcpy(s->se_sensor.desc, "alarm", sizeof(s->se_sensor.desc));
348
349		s++;
350	}
351	j++;
352
353	/*
354	 * Stash the temp info so we can get out of range status. Limit the
355	 * number so the out of temp checks can't go into memory it doesnt own.
356	 */
357	sc->sc_ntemps = (config->ntemps > 15) ? 15 : config->ntemps;
358	sc->sc_temps = s;
359	sc->sc_celsius = SAFTE_CFG_CELSIUS(config->therm);
360	for (i = 0; i < config->ntemps; i++) {
361		s->se_type = SAFTE_T_TEMP;
362		s->se_field = (u_int8_t *)(sc->sc_encbuf + j + i);
363		s->se_sensor.type = SENSOR_TEMP;
364
365		s++;
366	}
367	j += config->ntemps;
368
369	sc->sc_temperrs = (u_int8_t *)(sc->sc_encbuf + j);
370done:
371	dma_free(config, sizeof(*config));
372	return error;
373}
374
375void
376safte_read_encstat(void *arg)
377{
378	struct safte_readbuf_cmd	*cmd;
379	struct safte_sensor		*s;
380	struct safte_softc		*sc = (struct safte_softc *)arg;
381	struct scsi_xfer		*xs;
382	int				 error, i, flags = 0;
383	u_int16_t			 oot;
384
385	rw_enter_write(&sc->sc_lock);
386
387	if (cold)
388		SET(flags, SCSI_AUTOCONF);
389	xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_IN | SCSI_SILENT);
390	if (xs == NULL) {
391		rw_exit_write(&sc->sc_lock);
392		return;
393	}
394	xs->cmdlen = sizeof(*cmd);
395	xs->data = sc->sc_encbuf;
396	xs->datalen = sc->sc_encbuflen;
397	xs->retries = 2;
398	xs->timeout = 30000;
399
400	cmd = (struct safte_readbuf_cmd *)&xs->cmd;
401	cmd->opcode = READ_BUFFER;
402	SET(cmd->flags, SAFTE_RD_MODE);
403	cmd->bufferid = SAFTE_RD_ENCSTAT;
404	cmd->length = htobe16(sc->sc_encbuflen);
405
406	error = scsi_xs_sync(xs);
407	scsi_xs_put(xs);
408
409	if (error != 0) {
410		rw_exit_write(&sc->sc_lock);
411		return;
412	}
413
414	for (i = 0; i < sc->sc_nsensors; i++) {
415		s = &sc->sc_sensors[i];
416		CLR(s->se_sensor.flags, SENSOR_FUNKNOWN);
417
418		DPRINTF(("%s: %d type: %d field: 0x%02x\n", DEVNAME(sc), i,
419		    s->se_type, *s->se_field));
420
421		switch (s->se_type) {
422		case SAFTE_T_FAN:
423			switch (*s->se_field) {
424			case SAFTE_FAN_OP:
425				s->se_sensor.value = 1;
426				s->se_sensor.status = SENSOR_S_OK;
427				break;
428			case SAFTE_FAN_MF:
429				s->se_sensor.value = 0;
430				s->se_sensor.status = SENSOR_S_CRIT;
431				break;
432			case SAFTE_FAN_NOTINST:
433			case SAFTE_FAN_UNKNOWN:
434			default:
435				s->se_sensor.value = 0;
436				s->se_sensor.status = SENSOR_S_UNKNOWN;
437				SET(s->se_sensor.flags, SENSOR_FUNKNOWN);
438				break;
439			}
440			break;
441
442		case SAFTE_T_PWRSUP:
443			switch (*s->se_field) {
444			case SAFTE_PWR_OP_ON:
445				s->se_sensor.value = 1;
446				s->se_sensor.status = SENSOR_S_OK;
447				break;
448			case SAFTE_PWR_OP_OFF:
449				s->se_sensor.value = 0;
450				s->se_sensor.status = SENSOR_S_OK;
451				break;
452			case SAFTE_PWR_MF_ON:
453				s->se_sensor.value = 1;
454				s->se_sensor.status = SENSOR_S_CRIT;
455				break;
456			case SAFTE_PWR_MF_OFF:
457				s->se_sensor.value = 0;
458				s->se_sensor.status = SENSOR_S_CRIT;
459				break;
460			case SAFTE_PWR_NOTINST:
461			case SAFTE_PWR_PRESENT:
462			case SAFTE_PWR_UNKNOWN:
463				s->se_sensor.value = 0;
464				s->se_sensor.status = SENSOR_S_UNKNOWN;
465				SET(s->se_sensor.flags, SENSOR_FUNKNOWN);
466				break;
467			}
468			break;
469
470		case SAFTE_T_DOORLOCK:
471			switch (*s->se_field) {
472			case SAFTE_DOOR_LOCKED:
473				s->se_sensor.value = 1;
474				s->se_sensor.status = SENSOR_S_OK;
475				break;
476			case SAFTE_DOOR_UNLOCKED:
477				s->se_sensor.value = 0;
478				s->se_sensor.status = SENSOR_S_CRIT;
479				break;
480			case SAFTE_DOOR_UNKNOWN:
481				s->se_sensor.value = 0;
482				s->se_sensor.status = SENSOR_S_CRIT;
483				SET(s->se_sensor.flags, SENSOR_FUNKNOWN);
484				break;
485			}
486			break;
487
488		case SAFTE_T_ALARM:
489			switch (*s->se_field) {
490			case SAFTE_SPKR_OFF:
491				s->se_sensor.value = 0;
492				s->se_sensor.status = SENSOR_S_OK;
493				break;
494			case SAFTE_SPKR_ON:
495				s->se_sensor.value = 1;
496				s->se_sensor.status = SENSOR_S_CRIT;
497				break;
498			}
499			break;
500
501		case SAFTE_T_TEMP:
502			s->se_sensor.value = safte_temp2uK(*s->se_field,
503			    sc->sc_celsius);
504			break;
505		}
506	}
507
508	oot = _2btol(sc->sc_temperrs);
509	for (i = 0; i < sc->sc_ntemps; i++)
510		sc->sc_temps[i].se_sensor.status =
511		    (oot & (1 << i)) ? SENSOR_S_CRIT : SENSOR_S_OK;
512
513	rw_exit_write(&sc->sc_lock);
514}
515
516#if NBIO > 0
517int
518safte_ioctl(struct device *dev, u_long cmd, caddr_t addr)
519{
520	struct safte_softc		*sc = (struct safte_softc *)dev;
521	int				 error = 0;
522
523	switch (cmd) {
524	case BIOCBLINK:
525		error = safte_bio_blink(sc, (struct bioc_blink *)addr);
526		break;
527
528	default:
529		error = EINVAL;
530		break;
531	}
532
533	return error;
534}
535
536int
537safte_bio_blink(struct safte_softc *sc, struct bioc_blink *blink)
538{
539	struct safte_writebuf_cmd	*cmd;
540	struct safte_slotop		*op;
541	struct scsi_xfer		*xs;
542	int				 error, slot, flags = 0, wantblink;
543
544	switch (blink->bb_status) {
545	case BIOC_SBBLINK:
546		wantblink = 1;
547		break;
548	case BIOC_SBUNBLINK:
549		wantblink = 0;
550		break;
551	default:
552		return EINVAL;
553	}
554
555	rw_enter_read(&sc->sc_lock);
556	for (slot = 0; slot < sc->sc_nslots; slot++) {
557		if (sc->sc_slots[slot] == blink->bb_target)
558			break;
559	}
560	rw_exit_read(&sc->sc_lock);
561
562	if (slot >= sc->sc_nslots)
563		return ENODEV;
564
565	op = dma_alloc(sizeof(*op), PR_WAITOK | PR_ZERO);
566
567	op->opcode = SAFTE_WRITE_SLOTOP;
568	op->slot = slot;
569	op->flags |= wantblink ? SAFTE_SLOTOP_IDENTIFY : 0;
570
571	if (cold)
572		SET(flags, SCSI_AUTOCONF);
573	xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_OUT | SCSI_SILENT);
574	if (xs == NULL) {
575		dma_free(op, sizeof(*op));
576		return ENOMEM;
577	}
578	xs->cmdlen = sizeof(*cmd);
579	xs->data = (void *)op;
580	xs->datalen = sizeof(*op);
581	xs->retries = 2;
582	xs->timeout = 30000;
583
584	cmd = (struct safte_writebuf_cmd *)&xs->cmd;
585	cmd->opcode = WRITE_BUFFER;
586	SET(cmd->flags, SAFTE_WR_MODE);
587	cmd->length = htobe16(sizeof(struct safte_slotop));
588
589	error = scsi_xs_sync(xs);
590	scsi_xs_put(xs);
591
592	if (error != 0) {
593		error = EIO;
594	}
595	dma_free(op, sizeof(*op));
596
597	return error;
598}
599#endif /* NBIO > 0 */
600
601int64_t
602safte_temp2uK(u_int8_t measured, int celsius)
603{
604	int64_t				temp;
605
606	temp = (int64_t)measured;
607	temp += SAFTE_TEMP_OFFSET;
608	temp *= 1000000; /* Convert to micro (mu) degrees. */
609	if (!celsius)
610		temp = ((temp - 32000000) * 5) / 9; /* Convert to Celsius. */
611
612	temp += 273150000; /* Convert to kelvin. */
613
614	return temp;
615}
616