xref: /openbsd/sys/scsi/safte.c (revision 17df1aa7)
1 /*	$OpenBSD: safte.c,v 1.40 2009/01/20 21:46:42 kettenis 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/proc.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
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)
42 int	safte_debug = 1;
43 #else
44 #define DPRINTF(x)	/* x */
45 #endif
46 
47 
48 int	safte_match(struct device *, void *, void *);
49 void	safte_attach(struct device *, struct device *, void *);
50 int	safte_detach(struct device *, int);
51 
52 struct 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 
64 struct 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
86 };
87 
88 struct cfattach safte_ca = {
89 	sizeof(struct safte_softc), safte_match, safte_attach, safte_detach
90 };
91 
92 struct cfdriver safte_cd = {
93 	NULL, "safte", DV_DULL
94 };
95 
96 #define DEVNAME(s)	((s)->sc_dev.dv_xname)
97 
98 int	safte_read_config(struct safte_softc *);
99 void	safte_read_encstat(void *);
100 
101 #if NBIO > 0
102 int	safte_ioctl(struct device *, u_long, caddr_t);
103 int	safte_bio_blink(struct safte_softc *, struct bioc_blink *);
104 #endif
105 
106 int64_t	safte_temp2uK(u_int8_t, int);
107 
108 int
109 safte_match(struct device *parent, void *match, void *aux)
110 {
111 	struct scsi_attach_args		*sa = aux;
112 	struct scsi_inquiry_data	*inq = sa->sa_inqbuf;
113 	struct scsi_inquiry_data	inqbuf;
114 	struct scsi_inquiry		cmd;
115 	struct safte_inq		*si = (struct safte_inq *)&inqbuf.extra;
116 	int				length, flags;
117 
118 	if (inq == NULL)
119 		return (0);
120 
121 	/* match on dell enclosures */
122 	if ((inq->device & SID_TYPE) == T_PROCESSOR &&
123 	    SCSISPC(inq->version) == 3)
124 		return (2);
125 
126 	if ((inq->device & SID_TYPE) != T_PROCESSOR ||
127 	    SCSISPC(inq->version) != 2 ||
128 	    (inq->response_format & SID_ANSII) != 2)
129 		return (0);
130 
131 	length = inq->additional_length + SAFTE_EXTRA_OFFSET;
132 	if (length < SAFTE_INQ_LEN)
133 		return (0);
134 	if (length > sizeof(inqbuf))
135 		length = sizeof(inqbuf);
136 
137 	memset(&cmd, 0, sizeof(cmd));
138 	cmd.opcode = INQUIRY;
139 	_lto2b(length, cmd.length);
140 
141 	memset(&inqbuf, 0, sizeof(inqbuf));
142 	memset(&inqbuf.extra, ' ', sizeof(inqbuf.extra));
143 
144 	flags = SCSI_DATA_IN;
145 	if (cold)
146 		flags |= SCSI_AUTOCONF;
147 
148 	if (scsi_scsi_cmd(sa->sa_sc_link, (struct scsi_generic *)&cmd,
149 	    sizeof(cmd), (u_char *)&inqbuf, length, 2, 10000, NULL,
150 	    flags) != 0)
151 		return (0);
152 
153 	if (memcmp(si->ident, SAFTE_IDENT, sizeof(si->ident)) == 0)
154 		return (2);
155 
156 	return (0);
157 }
158 
159 void
160 safte_attach(struct device *parent, struct device *self, void *aux)
161 {
162 	struct safte_softc		*sc = (struct safte_softc *)self;
163 	struct scsi_attach_args		*sa = aux;
164 	int				i = 0;
165 
166 	sc->sc_link = sa->sa_sc_link;
167 	sa->sa_sc_link->device_softc = sc;
168 	rw_init(&sc->sc_lock, DEVNAME(sc));
169 
170 	printf("\n");
171 
172 	sc->sc_encbuf = NULL;
173 	sc->sc_nsensors = 0;
174 #if NBIO > 0
175 	sc->sc_nslots = 0;
176 #endif
177 
178 	if (safte_read_config(sc) != 0) {
179 		printf("%s: unable to read enclosure configuration\n",
180 		    DEVNAME(sc));
181 		return;
182 	}
183 
184 	if (sc->sc_nsensors > 0) {
185 		sc->sc_sensortask = sensor_task_register(sc,
186 		    safte_read_encstat, 10);
187 		if (sc->sc_sensortask == NULL) {
188 			printf("%s: unable to register update task\n",
189 			    DEVNAME(sc));
190 			sc->sc_nsensors = sc->sc_ntemps = 0;
191 			free(sc->sc_sensors, M_DEVBUF);
192 		} else {
193 			for (i = 0; i < sc->sc_nsensors; i++)
194 				sensor_attach(&sc->sc_sensordev,
195 				    &sc->sc_sensors[i].se_sensor);
196 			sensordev_install(&sc->sc_sensordev);
197 		}
198 	}
199 
200 #if NBIO > 0
201 	if (sc->sc_nslots > 0 &&
202 	    bio_register(self, safte_ioctl) != 0) {
203 		printf("%s: unable to register ioctl with bio\n", DEVNAME(sc));
204 		sc->sc_nslots = 0;
205 	} else
206 		i++;
207 #endif
208 
209 	if (i) /* if we're doing something, then preinit encbuf and sensors */
210 		safte_read_encstat(sc);
211 	else {
212 		free(sc->sc_encbuf, M_DEVBUF);
213 		sc->sc_encbuf = NULL;
214 	}
215 }
216 
217 int
218 safte_detach(struct device *self, int flags)
219 {
220 	struct safte_softc		*sc = (struct safte_softc *)self;
221 	int				i;
222 
223 	rw_enter_write(&sc->sc_lock);
224 
225 #if NBIO > 0
226 	if (sc->sc_nslots > 0)
227 		bio_unregister(self);
228 #endif
229 
230 	if (sc->sc_nsensors > 0) {
231 		sensordev_deinstall(&sc->sc_sensordev);
232 		sensor_task_unregister(sc->sc_sensortask);
233 
234 		for (i = 0; i < sc->sc_nsensors; i++)
235 			sensor_detach(&sc->sc_sensordev,
236 			    &sc->sc_sensors[i].se_sensor);
237 		free(sc->sc_sensors, M_DEVBUF);
238 	}
239 
240 	if (sc->sc_encbuf != NULL)
241 		free(sc->sc_encbuf, M_DEVBUF);
242 
243 	rw_exit_write(&sc->sc_lock);
244 
245 	return (0);
246 }
247 
248 int
249 safte_read_config(struct safte_softc *sc)
250 {
251 	struct safte_readbuf_cmd	cmd;
252 	struct safte_config		config;
253 	struct safte_sensor		*s;
254 	int				flags, i, j;
255 
256 	memset(&cmd, 0, sizeof(cmd));
257 	cmd.opcode = READ_BUFFER;
258 	cmd.flags |= SAFTE_RD_MODE;
259 	cmd.bufferid = SAFTE_RD_CONFIG;
260 	cmd.length = htobe16(sizeof(config));
261 	flags = SCSI_DATA_IN;
262 #ifndef SCSIDEBUG
263 	flags |= SCSI_SILENT;
264 #endif
265 
266 	if (cold)
267 		flags |= SCSI_AUTOCONF;
268 
269 	if (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
270 	    sizeof(cmd), (u_char *)&config, sizeof(config), 2, 30000, NULL,
271 	    flags) != 0)
272 		return (1);
273 
274 	DPRINTF(("%s: nfans: %d npwrsup: %d nslots: %d doorlock: %d ntemps: %d"
275 	    " alarm: %d celsius: %d ntherm: %d\n", DEVNAME(sc), config.nfans,
276 	    config.npwrsup, config.nslots, config.doorlock, config.ntemps,
277 	    config.alarm, SAFTE_CFG_CELSIUS(config.therm),
278 	    SAFTE_CFG_NTHERM(config.therm)));
279 
280 	sc->sc_encbuflen = config.nfans * sizeof(u_int8_t) + /* fan status */
281 	    config.npwrsup * sizeof(u_int8_t) + /* power supply status */
282 	    config.nslots * sizeof(u_int8_t) + /* device scsi id (lun) */
283 	    sizeof(u_int8_t) + /* door lock status */
284 	    sizeof(u_int8_t) + /* speaker status */
285 	    config.ntemps * sizeof(u_int8_t) + /* temp sensors */
286 	    sizeof(u_int16_t); /* temp out of range sensors */
287 
288 	sc->sc_encbuf = malloc(sc->sc_encbuflen, M_DEVBUF, M_NOWAIT);
289 	if (sc->sc_encbuf == NULL)
290 		return (1);
291 
292 	sc->sc_nsensors = config.nfans + config.npwrsup + config.ntemps +
293 		(config.doorlock ? 1 : 0) + (config.alarm ? 1 : 0);
294 
295 	sc->sc_sensors = malloc(sc->sc_nsensors * sizeof(struct safte_sensor),
296 	    M_DEVBUF, M_NOWAIT | M_ZERO);
297 	if (sc->sc_sensors == NULL) {
298 		free(sc->sc_encbuf, M_DEVBUF);
299 		sc->sc_encbuf = NULL;
300 		sc->sc_nsensors = 0;
301 		return (1);
302 	}
303 
304 	strlcpy(sc->sc_sensordev.xname, DEVNAME(sc),
305 	    sizeof(sc->sc_sensordev.xname));
306 
307 	s = sc->sc_sensors;
308 
309 	for (i = 0; i < config.nfans; i++) {
310 		s->se_type = SAFTE_T_FAN;
311 		s->se_field = (u_int8_t *)(sc->sc_encbuf + i);
312 		s->se_sensor.type = SENSOR_INDICATOR;
313 		snprintf(s->se_sensor.desc, sizeof(s->se_sensor.desc),
314 		    "Fan%d", i);
315 
316 		s++;
317 	}
318 	j = config.nfans;
319 
320 	for (i = 0; i < config.npwrsup; i++) {
321 		s->se_type = SAFTE_T_PWRSUP;
322 		s->se_field = (u_int8_t *)(sc->sc_encbuf + j + i);
323 		s->se_sensor.type = SENSOR_INDICATOR;
324 		snprintf(s->se_sensor.desc, sizeof(s->se_sensor.desc),
325 		    "PSU%d", i);
326 
327 		s++;
328 	}
329 	j += config.npwrsup;
330 
331 #if NBIO > 0
332 	sc->sc_nslots = config.nslots;
333 	sc->sc_slots = (u_int8_t *)(sc->sc_encbuf + j);
334 #endif
335 	j += config.nslots;
336 
337 	if (config.doorlock) {
338 		s->se_type = SAFTE_T_DOORLOCK;
339 		s->se_field = (u_int8_t *)(sc->sc_encbuf + j);
340 		s->se_sensor.type = SENSOR_INDICATOR;
341 		strlcpy(s->se_sensor.desc, "doorlock",
342 		    sizeof(s->se_sensor.desc));
343 
344 		s++;
345 	}
346 	j++;
347 
348 	if (config.alarm) {
349 		s->se_type = SAFTE_T_ALARM;
350 		s->se_field = (u_int8_t *)(sc->sc_encbuf + j);
351 		s->se_sensor.type = SENSOR_INDICATOR;
352 		strlcpy(s->se_sensor.desc, "alarm", sizeof(s->se_sensor.desc));
353 
354 		s++;
355 	}
356 	j++;
357 
358 	/*
359 	 * stash the temp info so we can get out of range status. limit the
360 	 * number so the out of temp checks cant go into memory it doesnt own
361 	 */
362 	sc->sc_ntemps = (config.ntemps > 15) ? 15 : config.ntemps;
363 	sc->sc_temps = s;
364 	sc->sc_celsius = SAFTE_CFG_CELSIUS(config.therm);
365 	for (i = 0; i < config.ntemps; i++) {
366 		s->se_type = SAFTE_T_TEMP;
367 		s->se_field = (u_int8_t *)(sc->sc_encbuf + j + i);
368 		s->se_sensor.type = SENSOR_TEMP;
369 
370 		s++;
371 	}
372 	j += config.ntemps;
373 
374 	sc->sc_temperrs = (u_int8_t *)(sc->sc_encbuf + j);
375 
376 	return (0);
377 }
378 
379 void
380 safte_read_encstat(void *arg)
381 {
382 	struct safte_softc		*sc = (struct safte_softc *)arg;
383 	struct safte_readbuf_cmd	cmd;
384 	int				flags, i;
385 	struct safte_sensor		*s;
386 	u_int16_t			oot;
387 
388 	rw_enter_write(&sc->sc_lock);
389 
390 	memset(&cmd, 0, sizeof(cmd));
391 	cmd.opcode = READ_BUFFER;
392 	cmd.flags |= SAFTE_RD_MODE;
393 	cmd.bufferid = SAFTE_RD_ENCSTAT;
394 	cmd.length = htobe16(sc->sc_encbuflen);
395 	flags = SCSI_DATA_IN;
396 #ifndef SCSIDEBUG
397 	flags |= SCSI_SILENT;
398 #endif
399 
400 	if (cold)
401 		flags |= SCSI_AUTOCONF;
402 
403 	if (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
404 	    sizeof(cmd), sc->sc_encbuf, sc->sc_encbuflen, 2, 30000, NULL,
405 	    flags) != 0) {
406 		rw_exit_write(&sc->sc_lock);
407 		return;
408 	}
409 
410 	for (i = 0; i < sc->sc_nsensors; i++) {
411 		s = &sc->sc_sensors[i];
412 		s->se_sensor.flags &= ~SENSOR_FUNKNOWN;
413 
414 		DPRINTF(("%s: %d type: %d field: 0x%02x\n", DEVNAME(sc), i,
415 		    s->se_type, *s->se_field));
416 
417 		switch (s->se_type) {
418 		case SAFTE_T_FAN:
419 			switch (*s->se_field) {
420 			case SAFTE_FAN_OP:
421 				s->se_sensor.value = 1;
422 				s->se_sensor.status = SENSOR_S_OK;
423 				break;
424 			case SAFTE_FAN_MF:
425 				s->se_sensor.value = 0;
426 				s->se_sensor.status = SENSOR_S_CRIT;
427 				break;
428 			case SAFTE_FAN_NOTINST:
429 			case SAFTE_FAN_UNKNOWN:
430 			default:
431 				s->se_sensor.value = 0;
432 				s->se_sensor.status = SENSOR_S_UNKNOWN;
433 				s->se_sensor.flags |= SENSOR_FUNKNOWN;
434 				break;
435 			}
436 			break;
437 
438 		case SAFTE_T_PWRSUP:
439 			switch (*s->se_field) {
440 			case SAFTE_PWR_OP_ON:
441 				s->se_sensor.value = 1;
442 				s->se_sensor.status = SENSOR_S_OK;
443 				break;
444 			case SAFTE_PWR_OP_OFF:
445 				s->se_sensor.value = 0;
446 				s->se_sensor.status = SENSOR_S_OK;
447 				break;
448 			case SAFTE_PWR_MF_ON:
449 				s->se_sensor.value = 1;
450 				s->se_sensor.status = SENSOR_S_CRIT;
451 				break;
452 			case SAFTE_PWR_MF_OFF:
453 				s->se_sensor.value = 0;
454 				s->se_sensor.status = SENSOR_S_CRIT;
455 				break;
456 			case SAFTE_PWR_NOTINST:
457 			case SAFTE_PWR_PRESENT:
458 			case SAFTE_PWR_UNKNOWN:
459 				s->se_sensor.value = 0;
460 				s->se_sensor.status = SENSOR_S_UNKNOWN;
461 				s->se_sensor.flags |= SENSOR_FUNKNOWN;
462 				break;
463 			}
464 			break;
465 
466 		case SAFTE_T_DOORLOCK:
467 			switch (*s->se_field) {
468 			case SAFTE_DOOR_LOCKED:
469 				s->se_sensor.value = 1;
470 				s->se_sensor.status = SENSOR_S_OK;
471 				break;
472 			case SAFTE_DOOR_UNLOCKED:
473 				s->se_sensor.value = 0;
474 				s->se_sensor.status = SENSOR_S_CRIT;
475 				break;
476 			case SAFTE_DOOR_UNKNOWN:
477 				s->se_sensor.value = 0;
478 				s->se_sensor.status = SENSOR_S_CRIT;
479 				s->se_sensor.flags |= SENSOR_FUNKNOWN;
480 				break;
481 			}
482 			break;
483 
484 		case SAFTE_T_ALARM:
485 			switch (*s->se_field) {
486 			case SAFTE_SPKR_OFF:
487 				s->se_sensor.value = 0;
488 				s->se_sensor.status = SENSOR_S_OK;
489 				break;
490 			case SAFTE_SPKR_ON:
491 				s->se_sensor.value = 1;
492 				s->se_sensor.status = SENSOR_S_CRIT;
493 				break;
494 			}
495 			break;
496 
497 		case SAFTE_T_TEMP:
498 			s->se_sensor.value = safte_temp2uK(*s->se_field,
499 			    sc->sc_celsius);
500 			break;
501 		}
502 	}
503 
504 	oot = _2btol(sc->sc_temperrs);
505 	for (i = 0; i < sc->sc_ntemps; i++)
506 		sc->sc_temps[i].se_sensor.status =
507 		    (oot & (1 << i)) ? SENSOR_S_CRIT : SENSOR_S_OK;
508 
509 	rw_exit_write(&sc->sc_lock);
510 }
511 
512 #if NBIO > 0
513 int
514 safte_ioctl(struct device *dev, u_long cmd, caddr_t addr)
515 {
516 	struct safte_softc		*sc = (struct safte_softc *)dev;
517 	int				error = 0;
518 
519 	switch (cmd) {
520 	case BIOCBLINK:
521 		error = safte_bio_blink(sc, (struct bioc_blink *)addr);
522 		break;
523 
524 	default:
525 		error = EINVAL;
526 		break;
527 	}
528 
529 	return (error);
530 }
531 
532 int
533 safte_bio_blink(struct safte_softc *sc, struct bioc_blink *blink)
534 {
535 	struct safte_writebuf_cmd	cmd;
536 	struct safte_slotop		*op;
537 	int				slot;
538 	int				flags;
539 	int				wantblink;
540 
541 	switch (blink->bb_status) {
542 	case BIOC_SBBLINK:
543 		wantblink = 1;
544 		break;
545 	case BIOC_SBUNBLINK:
546 		wantblink = 0;
547 		break;
548 	default:
549 		return (EINVAL);
550 	}
551 
552 	rw_enter_read(&sc->sc_lock);
553 	for (slot = 0; slot < sc->sc_nslots; slot++) {
554 		if (sc->sc_slots[slot] == blink->bb_target)
555 			break;
556 	}
557 	rw_exit_read(&sc->sc_lock);
558 
559 	if (slot >= sc->sc_nslots)
560 		return (ENODEV);
561 
562 	op = malloc(sizeof(*op), M_TEMP, M_ZERO);
563 
564 	op->opcode = SAFTE_WRITE_SLOTOP;
565 	op->slot = slot;
566 	op->flags |= wantblink ? SAFTE_SLOTOP_IDENTIFY : 0;
567 
568 	memset(&cmd, 0, sizeof(cmd));
569 	cmd.opcode = WRITE_BUFFER;
570 	cmd.flags |= SAFTE_WR_MODE;
571 	cmd.length = htobe16(sizeof(struct safte_slotop));
572 	flags = SCSI_DATA_OUT;
573 #ifndef SCSIDEBUG
574 	flags |= SCSI_SILENT;
575 #endif
576 	if (cold)
577 		flags |= SCSI_AUTOCONF;
578 
579 	if (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
580 	    sizeof(cmd), (u_char *)op, sizeof(struct safte_slotop),
581 	    2, 30000, NULL, flags) != 0) {
582 		free(op, M_TEMP);
583 		return (EIO);
584 	}
585 
586 	free(op, M_TEMP);
587 
588 	return (0);
589 }
590 #endif /* NBIO > 0 */
591 
592 int64_t
593 safte_temp2uK(u_int8_t measured, int celsius)
594 {
595 	int64_t				temp;
596 
597 	temp = (int64_t)measured;
598 	temp += SAFTE_TEMP_OFFSET;
599 	temp *= 1000000; /* convert to micro (mu) degrees */
600 	if (!celsius)
601 		temp = ((temp - 32000000) * 5) / 9; /* convert to Celsius */
602 
603 	temp += 273150000; /* convert to kelvin */
604 
605 	return (temp);
606 }
607