123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650 |
- /* $OpenBSD: safte.c,v 1.52 2015/06/07 19:13:27 krw Exp $ */
- /*
- * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- #include "bio.h"
- #include <sys/param.h>
- #include <sys/systm.h>
- #include <sys/device.h>
- #include <sys/scsiio.h>
- #include <sys/malloc.h>
- #include <sys/pool.h>
- #include <sys/rwlock.h>
- #include <sys/queue.h>
- #include <sys/sensors.h>
- #if NBIO > 0
- #include <dev/biovar.h>
- #endif
- #include <scsi/scsi_all.h>
- #include <scsi/scsiconf.h>
- #include <scsi/safte.h>
- #ifdef SAFTE_DEBUG
- #define DPRINTF(x) do { if (safte_debug) printf x ; } while (0)
- int safte_debug = 1;
- #else
- #define DPRINTF(x) /* x */
- #endif
- int safte_match(struct device *, void *, void *);
- void safte_attach(struct device *, struct device *, void *);
- int safte_detach(struct device *, int);
- struct safte_sensor {
- struct ksensor se_sensor;
- enum {
- SAFTE_T_FAN,
- SAFTE_T_PWRSUP,
- SAFTE_T_DOORLOCK,
- SAFTE_T_ALARM,
- SAFTE_T_TEMP
- } se_type;
- u_int8_t *se_field;
- };
- struct safte_softc {
- struct device sc_dev;
- struct scsi_link *sc_link;
- struct rwlock sc_lock;
- u_int sc_encbuflen;
- u_char *sc_encbuf;
- int sc_nsensors;
- struct safte_sensor *sc_sensors;
- struct ksensordev sc_sensordev;
- struct sensor_task *sc_sensortask;
- int sc_celsius;
- int sc_ntemps;
- struct safte_sensor *sc_temps;
- u_int8_t *sc_temperrs;
- #if NBIO > 0
- int sc_nslots;
- u_int8_t *sc_slots;
- #endif
- };
- struct cfattach safte_ca = {
- sizeof(struct safte_softc), safte_match, safte_attach, safte_detach
- };
- struct cfdriver safte_cd = {
- NULL, "safte", DV_DULL
- };
- #define DEVNAME(s) ((s)->sc_dev.dv_xname)
- int safte_read_config(struct safte_softc *);
- void safte_read_encstat(void *);
- #if NBIO > 0
- int safte_ioctl(struct device *, u_long, caddr_t);
- int safte_bio_blink(struct safte_softc *, struct bioc_blink *);
- #endif
- int64_t safte_temp2uK(u_int8_t, int);
- int
- safte_match(struct device *parent, void *match, void *aux)
- {
- struct scsi_inquiry_data *inqbuf;
- struct scsi_attach_args *sa = aux;
- struct scsi_inquiry_data *inq = sa->sa_inqbuf;
- struct scsi_xfer *xs;
- struct safte_inq *si;
- int error, flags = 0, length;
- if (inq == NULL)
- return (0);
- /* match on dell enclosures */
- if ((inq->device & SID_TYPE) == T_PROCESSOR &&
- SCSISPC(inq->version) == 3)
- return (2);
- if ((inq->device & SID_TYPE) != T_PROCESSOR ||
- SCSISPC(inq->version) != 2 ||
- (inq->response_format & SID_ANSII) != 2)
- return (0);
- length = inq->additional_length + SAFTE_EXTRA_OFFSET;
- if (length < SAFTE_INQ_LEN)
- return (0);
- if (length > sizeof(*inqbuf))
- length = sizeof(*inqbuf);
- inqbuf = dma_alloc(sizeof(*inqbuf), PR_NOWAIT | PR_ZERO);
- if (inqbuf == NULL)
- return (0);
- memset(inqbuf->extra, ' ', sizeof(inqbuf->extra));
- if (cold)
- flags |= SCSI_AUTOCONF;
- xs = scsi_xs_get(sa->sa_sc_link, flags | SCSI_DATA_IN);
- if (xs == NULL)
- goto fail;
- xs->retries = 2;
- xs->timeout = 10000;
- scsi_init_inquiry(xs, 0, 0, inqbuf, length);
- error = scsi_xs_sync(xs);
- scsi_xs_put(xs);
- if (error)
- goto fail;
- si = (struct safte_inq *)&inqbuf->extra;
- if (memcmp(si->ident, SAFTE_IDENT, sizeof(si->ident)) == 0) {
- dma_free(inqbuf, sizeof(*inqbuf));
- return (2);
- }
- fail:
- dma_free(inqbuf, sizeof(*inqbuf));
- return (0);
- }
- void
- safte_attach(struct device *parent, struct device *self, void *aux)
- {
- struct safte_softc *sc = (struct safte_softc *)self;
- struct scsi_attach_args *sa = aux;
- int i = 0;
- sc->sc_link = sa->sa_sc_link;
- sa->sa_sc_link->device_softc = sc;
- rw_init(&sc->sc_lock, DEVNAME(sc));
- printf("\n");
- sc->sc_encbuf = NULL;
- sc->sc_nsensors = 0;
- #if NBIO > 0
- sc->sc_nslots = 0;
- #endif
- if (safte_read_config(sc) != 0) {
- printf("%s: unable to read enclosure configuration\n",
- DEVNAME(sc));
- return;
- }
- if (sc->sc_nsensors > 0) {
- sc->sc_sensortask = sensor_task_register(sc,
- safte_read_encstat, 10);
- if (sc->sc_sensortask == NULL) {
- printf("%s: unable to register update task\n",
- DEVNAME(sc));
- sc->sc_nsensors = sc->sc_ntemps = 0;
- free(sc->sc_sensors, M_DEVBUF, 0);
- } else {
- for (i = 0; i < sc->sc_nsensors; i++)
- sensor_attach(&sc->sc_sensordev,
- &sc->sc_sensors[i].se_sensor);
- sensordev_install(&sc->sc_sensordev);
- }
- }
- #if NBIO > 0
- if (sc->sc_nslots > 0 &&
- bio_register(self, safte_ioctl) != 0) {
- printf("%s: unable to register ioctl with bio\n", DEVNAME(sc));
- sc->sc_nslots = 0;
- } else
- i++;
- #endif
- if (i) /* if we're doing something, then preinit encbuf and sensors */
- safte_read_encstat(sc);
- else {
- dma_free(sc->sc_encbuf, sc->sc_encbuflen);
- sc->sc_encbuf = NULL;
- }
- }
- int
- safte_detach(struct device *self, int flags)
- {
- struct safte_softc *sc = (struct safte_softc *)self;
- int i;
- rw_enter_write(&sc->sc_lock);
- #if NBIO > 0
- if (sc->sc_nslots > 0)
- bio_unregister(self);
- #endif
- if (sc->sc_nsensors > 0) {
- sensordev_deinstall(&sc->sc_sensordev);
- sensor_task_unregister(sc->sc_sensortask);
- for (i = 0; i < sc->sc_nsensors; i++)
- sensor_detach(&sc->sc_sensordev,
- &sc->sc_sensors[i].se_sensor);
- free(sc->sc_sensors, M_DEVBUF, 0);
- }
- if (sc->sc_encbuf != NULL)
- dma_free(sc->sc_encbuf, sc->sc_encbuflen);
- rw_exit_write(&sc->sc_lock);
- return (0);
- }
- int
- safte_read_config(struct safte_softc *sc)
- {
- struct safte_config *config = NULL;
- struct safte_readbuf_cmd *cmd;
- struct safte_sensor *s;
- struct scsi_xfer *xs;
- int error = 0, flags = 0, i, j;
- config = dma_alloc(sizeof(*config), PR_NOWAIT);
- if (config == NULL)
- return (1);
- if (cold)
- flags |= SCSI_AUTOCONF;
- xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_IN | SCSI_SILENT);
- if (xs == NULL) {
- error = 1;
- goto done;
- }
- xs->cmdlen = sizeof(*cmd);
- xs->data = (void *)config;
- xs->datalen = sizeof(*config);
- xs->retries = 2;
- xs->timeout = 30000;
- cmd = (struct safte_readbuf_cmd *)xs->cmd;
- cmd->opcode = READ_BUFFER;
- cmd->flags |= SAFTE_RD_MODE;
- cmd->bufferid = SAFTE_RD_CONFIG;
- cmd->length = htobe16(sizeof(*config));
- error = scsi_xs_sync(xs);
- scsi_xs_put(xs);
- if (error != 0) {
- error = 1;
- goto done;
- }
- DPRINTF(("%s: nfans: %d npwrsup: %d nslots: %d doorlock: %d ntemps: %d"
- " alarm: %d celsius: %d ntherm: %d\n", DEVNAME(sc), config->nfans,
- config->npwrsup, config->nslots, config->doorlock, config->ntemps,
- config->alarm, SAFTE_CFG_CELSIUS(config->therm),
- SAFTE_CFG_NTHERM(config->therm)));
- sc->sc_encbuflen = config->nfans * sizeof(u_int8_t) + /* fan status */
- config->npwrsup * sizeof(u_int8_t) + /* power supply status */
- config->nslots * sizeof(u_int8_t) + /* device scsi id (lun) */
- sizeof(u_int8_t) + /* door lock status */
- sizeof(u_int8_t) + /* speaker status */
- config->ntemps * sizeof(u_int8_t) + /* temp sensors */
- sizeof(u_int16_t); /* temp out of range sensors */
- sc->sc_encbuf = dma_alloc(sc->sc_encbuflen, PR_NOWAIT);
- if (sc->sc_encbuf == NULL) {
- error = 1;
- goto done;
- }
- sc->sc_nsensors = config->nfans + config->npwrsup + config->ntemps +
- (config->doorlock ? 1 : 0) + (config->alarm ? 1 : 0);
- sc->sc_sensors = mallocarray(sc->sc_nsensors, sizeof(struct safte_sensor),
- M_DEVBUF, M_NOWAIT | M_ZERO);
- if (sc->sc_sensors == NULL) {
- dma_free(sc->sc_encbuf, sc->sc_encbuflen);
- sc->sc_encbuf = NULL;
- sc->sc_nsensors = 0;
- error = 1;
- goto done;
- }
- strlcpy(sc->sc_sensordev.xname, DEVNAME(sc),
- sizeof(sc->sc_sensordev.xname));
- s = sc->sc_sensors;
- for (i = 0; i < config->nfans; i++) {
- s->se_type = SAFTE_T_FAN;
- s->se_field = (u_int8_t *)(sc->sc_encbuf + i);
- s->se_sensor.type = SENSOR_INDICATOR;
- snprintf(s->se_sensor.desc, sizeof(s->se_sensor.desc),
- "Fan%d", i);
- s++;
- }
- j = config->nfans;
- for (i = 0; i < config->npwrsup; i++) {
- s->se_type = SAFTE_T_PWRSUP;
- s->se_field = (u_int8_t *)(sc->sc_encbuf + j + i);
- s->se_sensor.type = SENSOR_INDICATOR;
- snprintf(s->se_sensor.desc, sizeof(s->se_sensor.desc),
- "PSU%d", i);
- s++;
- }
- j += config->npwrsup;
- #if NBIO > 0
- sc->sc_nslots = config->nslots;
- sc->sc_slots = (u_int8_t *)(sc->sc_encbuf + j);
- #endif
- j += config->nslots;
- if (config->doorlock) {
- s->se_type = SAFTE_T_DOORLOCK;
- s->se_field = (u_int8_t *)(sc->sc_encbuf + j);
- s->se_sensor.type = SENSOR_INDICATOR;
- strlcpy(s->se_sensor.desc, "doorlock",
- sizeof(s->se_sensor.desc));
- s++;
- }
- j++;
- if (config->alarm) {
- s->se_type = SAFTE_T_ALARM;
- s->se_field = (u_int8_t *)(sc->sc_encbuf + j);
- s->se_sensor.type = SENSOR_INDICATOR;
- strlcpy(s->se_sensor.desc, "alarm", sizeof(s->se_sensor.desc));
- s++;
- }
- j++;
- /*
- * stash the temp info so we can get out of range status. limit the
- * number so the out of temp checks cant go into memory it doesnt own
- */
- sc->sc_ntemps = (config->ntemps > 15) ? 15 : config->ntemps;
- sc->sc_temps = s;
- sc->sc_celsius = SAFTE_CFG_CELSIUS(config->therm);
- for (i = 0; i < config->ntemps; i++) {
- s->se_type = SAFTE_T_TEMP;
- s->se_field = (u_int8_t *)(sc->sc_encbuf + j + i);
- s->se_sensor.type = SENSOR_TEMP;
- s++;
- }
- j += config->ntemps;
- sc->sc_temperrs = (u_int8_t *)(sc->sc_encbuf + j);
- done:
- dma_free(config, sizeof(*config));
- return (error);
- }
- void
- safte_read_encstat(void *arg)
- {
- struct safte_readbuf_cmd *cmd;
- struct safte_sensor *s;
- struct safte_softc *sc = (struct safte_softc *)arg;
- struct scsi_xfer *xs;
- int error, i, flags = 0;
- u_int16_t oot;
- rw_enter_write(&sc->sc_lock);
- if (cold)
- flags |= SCSI_AUTOCONF;
- xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_IN | SCSI_SILENT);
- if (xs == NULL) {
- rw_exit_write(&sc->sc_lock);
- return;
- }
- xs->cmdlen = sizeof(*cmd);
- xs->data = sc->sc_encbuf;
- xs->datalen = sc->sc_encbuflen;
- xs->retries = 2;
- xs->timeout = 30000;
- cmd = (struct safte_readbuf_cmd *)xs->cmd;
- cmd->opcode = READ_BUFFER;
- cmd->flags |= SAFTE_RD_MODE;
- cmd->bufferid = SAFTE_RD_ENCSTAT;
- cmd->length = htobe16(sc->sc_encbuflen);
- error = scsi_xs_sync(xs);
- scsi_xs_put(xs);
- if (error != 0) {
- rw_exit_write(&sc->sc_lock);
- return;
- }
- for (i = 0; i < sc->sc_nsensors; i++) {
- s = &sc->sc_sensors[i];
- s->se_sensor.flags &= ~SENSOR_FUNKNOWN;
- DPRINTF(("%s: %d type: %d field: 0x%02x\n", DEVNAME(sc), i,
- s->se_type, *s->se_field));
- switch (s->se_type) {
- case SAFTE_T_FAN:
- switch (*s->se_field) {
- case SAFTE_FAN_OP:
- s->se_sensor.value = 1;
- s->se_sensor.status = SENSOR_S_OK;
- break;
- case SAFTE_FAN_MF:
- s->se_sensor.value = 0;
- s->se_sensor.status = SENSOR_S_CRIT;
- break;
- case SAFTE_FAN_NOTINST:
- case SAFTE_FAN_UNKNOWN:
- default:
- s->se_sensor.value = 0;
- s->se_sensor.status = SENSOR_S_UNKNOWN;
- s->se_sensor.flags |= SENSOR_FUNKNOWN;
- break;
- }
- break;
- case SAFTE_T_PWRSUP:
- switch (*s->se_field) {
- case SAFTE_PWR_OP_ON:
- s->se_sensor.value = 1;
- s->se_sensor.status = SENSOR_S_OK;
- break;
- case SAFTE_PWR_OP_OFF:
- s->se_sensor.value = 0;
- s->se_sensor.status = SENSOR_S_OK;
- break;
- case SAFTE_PWR_MF_ON:
- s->se_sensor.value = 1;
- s->se_sensor.status = SENSOR_S_CRIT;
- break;
- case SAFTE_PWR_MF_OFF:
- s->se_sensor.value = 0;
- s->se_sensor.status = SENSOR_S_CRIT;
- break;
- case SAFTE_PWR_NOTINST:
- case SAFTE_PWR_PRESENT:
- case SAFTE_PWR_UNKNOWN:
- s->se_sensor.value = 0;
- s->se_sensor.status = SENSOR_S_UNKNOWN;
- s->se_sensor.flags |= SENSOR_FUNKNOWN;
- break;
- }
- break;
- case SAFTE_T_DOORLOCK:
- switch (*s->se_field) {
- case SAFTE_DOOR_LOCKED:
- s->se_sensor.value = 1;
- s->se_sensor.status = SENSOR_S_OK;
- break;
- case SAFTE_DOOR_UNLOCKED:
- s->se_sensor.value = 0;
- s->se_sensor.status = SENSOR_S_CRIT;
- break;
- case SAFTE_DOOR_UNKNOWN:
- s->se_sensor.value = 0;
- s->se_sensor.status = SENSOR_S_CRIT;
- s->se_sensor.flags |= SENSOR_FUNKNOWN;
- break;
- }
- break;
- case SAFTE_T_ALARM:
- switch (*s->se_field) {
- case SAFTE_SPKR_OFF:
- s->se_sensor.value = 0;
- s->se_sensor.status = SENSOR_S_OK;
- break;
- case SAFTE_SPKR_ON:
- s->se_sensor.value = 1;
- s->se_sensor.status = SENSOR_S_CRIT;
- break;
- }
- break;
- case SAFTE_T_TEMP:
- s->se_sensor.value = safte_temp2uK(*s->se_field,
- sc->sc_celsius);
- break;
- }
- }
- oot = _2btol(sc->sc_temperrs);
- for (i = 0; i < sc->sc_ntemps; i++)
- sc->sc_temps[i].se_sensor.status =
- (oot & (1 << i)) ? SENSOR_S_CRIT : SENSOR_S_OK;
- rw_exit_write(&sc->sc_lock);
- }
- #if NBIO > 0
- int
- safte_ioctl(struct device *dev, u_long cmd, caddr_t addr)
- {
- struct safte_softc *sc = (struct safte_softc *)dev;
- int error = 0;
- switch (cmd) {
- case BIOCBLINK:
- error = safte_bio_blink(sc, (struct bioc_blink *)addr);
- break;
- default:
- error = EINVAL;
- break;
- }
- return (error);
- }
- int
- safte_bio_blink(struct safte_softc *sc, struct bioc_blink *blink)
- {
- struct safte_writebuf_cmd *cmd;
- struct safte_slotop *op;
- struct scsi_xfer *xs;
- int error, slot, flags = 0, wantblink;
- switch (blink->bb_status) {
- case BIOC_SBBLINK:
- wantblink = 1;
- break;
- case BIOC_SBUNBLINK:
- wantblink = 0;
- break;
- default:
- return (EINVAL);
- }
- rw_enter_read(&sc->sc_lock);
- for (slot = 0; slot < sc->sc_nslots; slot++) {
- if (sc->sc_slots[slot] == blink->bb_target)
- break;
- }
- rw_exit_read(&sc->sc_lock);
- if (slot >= sc->sc_nslots)
- return (ENODEV);
- op = dma_alloc(sizeof(*op), PR_WAITOK | PR_ZERO);
- op->opcode = SAFTE_WRITE_SLOTOP;
- op->slot = slot;
- op->flags |= wantblink ? SAFTE_SLOTOP_IDENTIFY : 0;
- if (cold)
- flags |= SCSI_AUTOCONF;
- xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_OUT | SCSI_SILENT);
- if (xs == NULL) {
- dma_free(op, sizeof(*op));
- return (ENOMEM);
- }
- xs->cmdlen = sizeof(*cmd);
- xs->data = (void *)op;
- xs->datalen = sizeof(*op);
- xs->retries = 2;
- xs->timeout = 30000;
- cmd = (struct safte_writebuf_cmd *)xs->cmd;
- cmd->opcode = WRITE_BUFFER;
- cmd->flags |= SAFTE_WR_MODE;
- cmd->length = htobe16(sizeof(struct safte_slotop));
- error = scsi_xs_sync(xs);
- scsi_xs_put(xs);
- if (error != 0) {
- error = EIO;
- }
- dma_free(op, sizeof(*op));
- return (error);
- }
- #endif /* NBIO > 0 */
- int64_t
- safte_temp2uK(u_int8_t measured, int celsius)
- {
- int64_t temp;
- temp = (int64_t)measured;
- temp += SAFTE_TEMP_OFFSET;
- temp *= 1000000; /* convert to micro (mu) degrees */
- if (!celsius)
- temp = ((temp - 32000000) * 5) / 9; /* convert to Celsius */
- temp += 273150000; /* convert to kelvin */
- return (temp);
- }
|