root/scsi/safte.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. safte_match
  2. safte_attach
  3. safte_detach
  4. safte_read_config
  5. safte_read_encstat
  6. safte_ioctl
  7. safte_bio_blink
  8. safte_temp2uK

    1 /*      $OpenBSD: safte.c,v 1.37 2007/06/24 05:34:35 dlg 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_int16_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);
  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         memset(sc->sc_sensors, 0,
  308             sc->sc_nsensors * sizeof(struct safte_sensor));
  309         s = sc->sc_sensors;
  310 
  311         for (i = 0; i < config.nfans; i++) {
  312                 s->se_type = SAFTE_T_FAN;
  313                 s->se_field = (u_int8_t *)(sc->sc_encbuf + i);
  314                 s->se_sensor.type = SENSOR_INDICATOR;
  315                 snprintf(s->se_sensor.desc, sizeof(s->se_sensor.desc),
  316                     "Fan%d", i);
  317 
  318                 s++;
  319         }
  320         j = config.nfans;
  321 
  322         for (i = 0; i < config.npwrsup; i++) {
  323                 s->se_type = SAFTE_T_PWRSUP;
  324                 s->se_field = (u_int8_t *)(sc->sc_encbuf + j + i);
  325                 s->se_sensor.type = SENSOR_INDICATOR;
  326                 snprintf(s->se_sensor.desc, sizeof(s->se_sensor.desc),
  327                     "PSU%d", i);
  328 
  329                 s++;
  330         }
  331         j += config.npwrsup;
  332 
  333 #if NBIO > 0
  334         sc->sc_nslots = config.nslots;
  335         sc->sc_slots = (u_int8_t *)(sc->sc_encbuf + j);
  336 #endif
  337         j += config.nslots;
  338 
  339         if (config.doorlock) {
  340                 s->se_type = SAFTE_T_DOORLOCK;
  341                 s->se_field = (u_int8_t *)(sc->sc_encbuf + j);
  342                 s->se_sensor.type = SENSOR_INDICATOR;
  343                 strlcpy(s->se_sensor.desc, "doorlock",
  344                     sizeof(s->se_sensor.desc));
  345 
  346                 s++;
  347         }
  348         j++;
  349 
  350         if (config.alarm) {
  351                 s->se_type = SAFTE_T_ALARM;
  352                 s->se_field = (u_int8_t *)(sc->sc_encbuf + j);
  353                 s->se_sensor.type = SENSOR_INDICATOR;
  354                 strlcpy(s->se_sensor.desc, "alarm", sizeof(s->se_sensor.desc));
  355 
  356                 s++;
  357         }
  358         j++;
  359 
  360         /*
  361          * stash the temp info so we can get out of range status. limit the
  362          * number so the out of temp checks cant go into memory it doesnt own
  363          */
  364         sc->sc_ntemps = (config.ntemps > 15) ? 15 : config.ntemps;
  365         sc->sc_temps = s;
  366         sc->sc_celsius = SAFTE_CFG_CELSIUS(config.therm);
  367         for (i = 0; i < config.ntemps; i++) {
  368                 s->se_type = SAFTE_T_TEMP;
  369                 s->se_field = (u_int8_t *)(sc->sc_encbuf + j + i);
  370                 s->se_sensor.type = SENSOR_TEMP;
  371 
  372                 s++;
  373         }
  374         j += config.ntemps;
  375 
  376         sc->sc_temperrs = (u_int16_t *)(sc->sc_encbuf + j);
  377 
  378         return (0);
  379 }
  380 
  381 void
  382 safte_read_encstat(void *arg)
  383 {
  384         struct safte_softc              *sc = (struct safte_softc *)arg;
  385         struct safte_readbuf_cmd        cmd;
  386         int                             flags, i;
  387         struct safte_sensor             *s;
  388         u_int16_t                       oot;
  389 
  390         rw_enter_write(&sc->sc_lock);
  391 
  392         memset(&cmd, 0, sizeof(cmd));
  393         cmd.opcode = READ_BUFFER;
  394         cmd.flags |= SAFTE_RD_MODE;
  395         cmd.bufferid = SAFTE_RD_ENCSTAT;
  396         cmd.length = htobe16(sc->sc_encbuflen);
  397         flags = SCSI_DATA_IN;
  398 #ifndef SCSIDEBUG
  399         flags |= SCSI_SILENT;
  400 #endif
  401 
  402         if (cold)
  403                 flags |= SCSI_AUTOCONF;
  404 
  405         if (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
  406             sizeof(cmd), sc->sc_encbuf, sc->sc_encbuflen, 2, 30000, NULL,
  407             flags) != 0) {
  408                 rw_exit_write(&sc->sc_lock);
  409                 return;
  410         }
  411 
  412         for (i = 0; i < sc->sc_nsensors; i++) {
  413                 s = &sc->sc_sensors[i];
  414                 s->se_sensor.flags &= ~SENSOR_FUNKNOWN;
  415 
  416                 DPRINTF(("%s: %d type: %d field: 0x%02x\n", DEVNAME(sc), i,
  417                     s->se_type, *s->se_field));
  418 
  419                 switch (s->se_type) {
  420                 case SAFTE_T_FAN:
  421                         switch (*s->se_field) {
  422                         case SAFTE_FAN_OP:
  423                                 s->se_sensor.value = 1;
  424                                 s->se_sensor.status = SENSOR_S_OK;
  425                                 break;
  426                         case SAFTE_FAN_MF:
  427                                 s->se_sensor.value = 0;
  428                                 s->se_sensor.status = SENSOR_S_CRIT;
  429                                 break;
  430                         case SAFTE_FAN_NOTINST:
  431                         case SAFTE_FAN_UNKNOWN:
  432                         default:
  433                                 s->se_sensor.value = 0;
  434                                 s->se_sensor.status = SENSOR_S_UNKNOWN;
  435                                 s->se_sensor.flags |= SENSOR_FUNKNOWN;
  436                                 break;
  437                         }
  438                         break;
  439 
  440                 case SAFTE_T_PWRSUP:
  441                         switch (*s->se_field) {
  442                         case SAFTE_PWR_OP_ON:
  443                                 s->se_sensor.value = 1;
  444                                 s->se_sensor.status = SENSOR_S_OK;
  445                                 break;
  446                         case SAFTE_PWR_OP_OFF:
  447                                 s->se_sensor.value = 0;
  448                                 s->se_sensor.status = SENSOR_S_OK;
  449                                 break;
  450                         case SAFTE_PWR_MF_ON:
  451                                 s->se_sensor.value = 1;
  452                                 s->se_sensor.status = SENSOR_S_CRIT;
  453                                 break;
  454                         case SAFTE_PWR_MF_OFF:
  455                                 s->se_sensor.value = 0;
  456                                 s->se_sensor.status = SENSOR_S_CRIT;
  457                                 break;
  458                         case SAFTE_PWR_NOTINST:
  459                         case SAFTE_PWR_PRESENT:
  460                         case SAFTE_PWR_UNKNOWN:
  461                                 s->se_sensor.value = 0;
  462                                 s->se_sensor.status = SENSOR_S_UNKNOWN;
  463                                 s->se_sensor.flags |= SENSOR_FUNKNOWN;
  464                                 break;
  465                         }
  466                         break;
  467 
  468                 case SAFTE_T_DOORLOCK:
  469                         switch (*s->se_field) {
  470                         case SAFTE_DOOR_LOCKED:
  471                                 s->se_sensor.value = 1;
  472                                 s->se_sensor.status = SENSOR_S_OK;
  473                                 break;
  474                         case SAFTE_DOOR_UNLOCKED:
  475                                 s->se_sensor.value = 0;
  476                                 s->se_sensor.status = SENSOR_S_CRIT;
  477                                 break;
  478                         case SAFTE_DOOR_UNKNOWN:
  479                                 s->se_sensor.value = 0;
  480                                 s->se_sensor.status = SENSOR_S_CRIT;
  481                                 s->se_sensor.flags |= SENSOR_FUNKNOWN;
  482                                 break;
  483                         }
  484                         break;
  485 
  486                 case SAFTE_T_ALARM:
  487                         switch (*s->se_field) {
  488                         case SAFTE_SPKR_OFF:
  489                                 s->se_sensor.value = 0;
  490                                 s->se_sensor.status = SENSOR_S_OK;
  491                                 break;
  492                         case SAFTE_SPKR_ON:
  493                                 s->se_sensor.value = 1;
  494                                 s->se_sensor.status = SENSOR_S_CRIT;
  495                                 break;
  496                         }
  497                         break;
  498 
  499                 case SAFTE_T_TEMP:
  500                         s->se_sensor.value = safte_temp2uK(*s->se_field,
  501                             sc->sc_celsius);
  502                         break;
  503                 }
  504         }
  505 
  506         oot = betoh16(*sc->sc_temperrs);
  507         for (i = 0; i < sc->sc_ntemps; i++)
  508                 sc->sc_temps[i].se_sensor.status = 
  509                     (oot & (1 << i)) ? SENSOR_S_CRIT : SENSOR_S_OK;
  510 
  511         rw_exit_write(&sc->sc_lock);
  512 }
  513 
  514 #if NBIO > 0
  515 int
  516 safte_ioctl(struct device *dev, u_long cmd, caddr_t addr)
  517 {
  518         struct safte_softc              *sc = (struct safte_softc *)dev;
  519         int                             error = 0;
  520 
  521         switch (cmd) {
  522         case BIOCBLINK:
  523                 error = safte_bio_blink(sc, (struct bioc_blink *)addr);
  524                 break;
  525 
  526         default:
  527                 error = EINVAL;
  528                 break;
  529         }
  530 
  531         return (error);
  532 }
  533 
  534 int
  535 safte_bio_blink(struct safte_softc *sc, struct bioc_blink *blink)
  536 {
  537         struct safte_writebuf_cmd       cmd;
  538         struct safte_slotop             *op;
  539         int                             slot;
  540         int                             flags;
  541         int                             wantblink;
  542 
  543         switch (blink->bb_status) {
  544         case BIOC_SBBLINK:
  545                 wantblink = 1;
  546                 break;
  547         case BIOC_SBUNBLINK:
  548                 wantblink = 0;
  549                 break;
  550         default:
  551                 return (EINVAL);
  552         }
  553 
  554         rw_enter_read(&sc->sc_lock);
  555         for (slot = 0; slot < sc->sc_nslots; slot++) {
  556                 if (sc->sc_slots[slot] == blink->bb_target)
  557                         break;
  558         }
  559         rw_exit_read(&sc->sc_lock);
  560 
  561         if (slot >= sc->sc_nslots)
  562                 return (ENODEV);
  563 
  564         op = malloc(sizeof(struct safte_slotop), M_TEMP, 0);
  565 
  566         memset(op, 0, sizeof(struct safte_slotop));
  567         op->opcode = SAFTE_WRITE_SLOTOP;
  568         op->slot = slot;
  569         op->flags |= wantblink ? SAFTE_SLOTOP_IDENTIFY : 0;
  570 
  571         memset(&cmd, 0, sizeof(cmd));
  572         cmd.opcode = WRITE_BUFFER;
  573         cmd.flags |= SAFTE_WR_MODE;
  574         cmd.length = htobe16(sizeof(struct safte_slotop));
  575         flags = SCSI_DATA_OUT;
  576 #ifndef SCSIDEBUG
  577         flags |= SCSI_SILENT;
  578 #endif
  579         if (cold)
  580                 flags |= SCSI_AUTOCONF;
  581 
  582         if (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
  583             sizeof(cmd), (u_char *)op, sizeof(struct safte_slotop),
  584             2, 30000, NULL, flags) != 0) {
  585                 free(op, M_TEMP);
  586                 return (EIO);
  587         }
  588 
  589         free(op, M_TEMP);
  590 
  591         return (0);
  592 }
  593 #endif /* NBIO > 0 */
  594 
  595 int64_t
  596 safte_temp2uK(u_int8_t measured, int celsius)
  597 {
  598         int64_t                         temp;
  599 
  600         temp = (int64_t)measured;
  601         temp += SAFTE_TEMP_OFFSET;
  602         temp *= 1000000; /* convert to micro (mu) degrees */
  603         if (!celsius)
  604                 temp = ((temp - 32000000) * 5) / 9; /* convert to Celsius */
  605 
  606         temp += 273150000; /* convert to kelvin */
  607 
  608         return (temp);
  609 }

/* [<][>][^][v][top][bottom][index][help] */