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