diff options
author | 2005-07-25 23:32:33 +0000 | |
---|---|---|
committer | 2005-07-25 23:32:33 +0000 | |
commit | fe4e9b4cfad70a89e8ba8dca18cc3ab8f1dec6c9 (patch) | |
tree | 5b8dc4e5644aedbb17b310d4d1d1f4fbd54d7f6a | |
parent | update DESCRIPTION to reflect the fact that another synopsis form was (diff) | |
download | wireguard-openbsd-fe4e9b4cfad70a89e8ba8dca18cc3ab8f1dec6c9.tar.xz wireguard-openbsd-fe4e9b4cfad70a89e8ba8dca18cc3ab8f1dec6c9.zip |
add safte, a small driver for monitoring scsi accessed fault-tolerant
enclosures via the hw.sensors sysctl tree.
ok marco@ krw@ please do tdeval@ looks ok grange@
-rw-r--r-- | sys/scsi/files.scsi | 7 | ||||
-rw-r--r-- | sys/scsi/scsi_safte.c | 386 | ||||
-rw-r--r-- | sys/scsi/scsi_safte.h | 155 |
3 files changed, 547 insertions, 1 deletions
diff --git a/sys/scsi/files.scsi b/sys/scsi/files.scsi index e0a1d4dbb17..8573f9279b2 100644 --- a/sys/scsi/files.scsi +++ b/sys/scsi/files.scsi @@ -1,4 +1,4 @@ -# $OpenBSD: files.scsi,v 1.16 2005/07/02 03:49:47 krw Exp $ +# $OpenBSD: files.scsi,v 1.17 2005/07/25 23:32:33 dlg Exp $ # $NetBSD: files.scsi,v 1.4 1996/05/16 04:01:08 mycroft Exp $ # # Config.new file and device description for machine-independent SCSI code. @@ -41,3 +41,8 @@ file scsi/ss_scanjet.c ss device uk: disk attach uk at scsibus file scsi/uk.c uk needs-flag + +device safte: disk +attach safte at scsibus +file scsi/scsi_safte.c safte needs-flag + diff --git a/sys/scsi/scsi_safte.c b/sys/scsi/scsi_safte.c new file mode 100644 index 00000000000..6bcc1b11ddb --- /dev/null +++ b/sys/scsi/scsi_safte.c @@ -0,0 +1,386 @@ +/* $OpenBSD: scsi_safte.c,v 1.1 2005/07/25 23:32:33 dlg 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 <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/stat.h> +#include <sys/scsiio.h> +#include <sys/uio.h> +#include <sys/malloc.h> +#include <sys/device.h> +#include <sys/conf.h> +#include <sys/queue.h> +#include <sys/sensors.h> + +#include <scsi/scsi_all.h> +#include <scsi/scsi_disk.h> +#include <scsi/scsiconf.h> + +#include <scsi/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_softc { + struct device sc_dev; + struct scsi_link *sc_link; + + enum safte_state { + SAFTE_ST_NONE, + SAFTE_ST_INIT, + SAFTE_ST_ERR + } sc_state; + + u_int sc_nfans; + u_int sc_npwrsup; + u_int sc_nslots; + u_int sc_ntemps; + u_int sc_ntherm; + int sc_flags; +#define SAFTE_FL_DOORLOCK (1<<0) +#define SAFTE_FL_ALARM (1<<1) +#define SAFTE_FL_CELCIUS (1<<2) + size_t sc_encstatlen; + u_char *sc_encbuf; + + int sc_nsensors; + struct sensor *sc_sensors; + struct timeout sc_timeout; +}; + +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) + +void safte_refresh(void *); +int safte_read_config(struct safte_softc *); +int safte_read_encstat(struct safte_softc *, int refresh); + +int64_t safte_temp2uK(u_int8_t, int); + +int +safte_match(struct device *parent, void *match, void *aux) +{ + struct scsibus_attach_args *sa = aux; + struct scsi_inquiry_data *inq = sa->sa_inqbuf; + struct scsi_inquiry_data inqbuf; + struct scsi_inquiry cmd; + struct safte_inq *si; + + if (inq == NULL) + return (0); + + if ((inq->device & SID_TYPE) != T_PROCESSOR) + return (0); + + if ((inq->version & SID_ANSII) != SID_ANSII_SCSI2) + return (0); + + if ((inq->response_format & SID_ANSII) != SID_ANSII_SCSI2) + return (0); + + memset(&cmd, 0, sizeof(cmd)); + cmd.opcode = INQUIRY; + cmd.length = inq->additional_length + SAFTE_EXTRA_OFFSET; + if (cmd.length > sizeof(inqbuf) || cmd.length < SAFTE_INQ_LEN) + return(0); + + memset(&inqbuf, 0, sizeof(inqbuf)); + memset(&inqbuf.extra, ' ', sizeof(inqbuf.extra)); + + if (scsi_scsi_cmd(sa->sa_sc_link, (struct scsi_generic *)&cmd, + sizeof(cmd), (u_char *)&inqbuf, cmd.length, 2, 10000, NULL, + SCSI_DATA_IN) != 0) + return (0); + + si = (struct safte_inq *)&inqbuf.extra; + if (memcmp(si->ident, SAFTE_IDENT, sizeof(si->ident)) == 0) + return (24); + + return (0); +} + +void +safte_attach(struct device *parent, struct device *self, void *aux) +{ + struct safte_softc *sc = (struct safte_softc *)self; + struct scsibus_attach_args *sa = aux; + + struct scsi_inquiry cmd; + struct scsi_inquiry_data inq; + struct safte_inq *si = (struct safte_inq *)&inq.extra; + char rev[5]; /* sizeof(si->revision) + 1 */ + int i; + + sc->sc_link = sa->sa_sc_link; + sc->sc_state = SAFTE_ST_NONE; + + printf("\n"); + + memset(&cmd, 0, sizeof(cmd)); + cmd.opcode = INQUIRY; + cmd.length = SAFTE_INQ_LEN; + memset(&inq, 0, sizeof(inq)); + memset(&inq.extra, ' ', sizeof(inq.extra)); + if (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd, + sizeof(cmd), (u_char *)&inq, cmd.length, 2, 10000, NULL, + SCSI_DATA_IN) != 0) { + printf("%s: unable to get inquiry information\n", DEVNAME(sc)); + return; + } + + memset(rev, 0, sizeof(rev)); + memcpy(rev, si->revision, sizeof(si->revision)); + + printf("%s: SCSI Accessed Fault-Tolerant Enclosure rev %s\n", + DEVNAME(sc), rev); + + if (safte_read_config(sc) != 0) { + printf("%s: unable to read enclosure configuration\n", + DEVNAME(sc)); + return; + } + + sc->sc_nsensors = sc->sc_ntemps; /* XXX we could do more than temp */ + if (sc->sc_nsensors == 0) + return; + + sc->sc_sensors = malloc(sc->sc_nsensors * sizeof(struct sensor), + M_DEVBUF, M_NOWAIT); + if (sc->sc_sensors == NULL) { + printf("%s: unable to allocate sensor storage\n", DEVNAME(sc)); + return; + } + memset(sc->sc_sensors, 0, sc->sc_nsensors * sizeof(struct sensor)); + + for (i = 0; i < sc->sc_ntemps; i++) { + sc->sc_sensors[i].type = SENSOR_TEMP; + snprintf(sc->sc_sensors[i].desc, + sizeof(sc->sc_sensors[i].desc), "temp%d", i); + } + + sc->sc_encstatlen = sc->sc_nfans * sizeof(u_int8_t) + /* fan status */ + sc->sc_npwrsup * sizeof(u_int8_t) + /* power supply status */ + sc->sc_nslots * sizeof(u_int8_t) + /* device scsi id (lun) */ + sizeof(u_int8_t) + /* door lock status */ + sizeof(u_int8_t) + /* speaker status */ + sc->sc_ntemps * sizeof(u_int8_t) + /* temp sensors */ + sizeof(u_int16_t); /* temp out of range sensors */ + + sc->sc_encbuf = malloc(sc->sc_encstatlen, M_DEVBUF, M_NOWAIT); + if (sc->sc_encbuf == NULL) { + printf("%s: unable to allocate enclosure status buffer\n", + DEVNAME(sc)); + free(sc->sc_sensors, M_DEVBUF); + return; + } + + if (safte_read_encstat(sc, 0) != 0) { + printf("%s: unable to read enclosure status\n", DEVNAME(sc)); + free(sc->sc_encbuf, M_DEVBUF); + free(sc->sc_sensors, M_DEVBUF); + return; + } + + sc->sc_state = SAFTE_ST_INIT; + + for (i = 0; i < sc->sc_nsensors; i++) { + strlcpy(sc->sc_sensors[i].device, DEVNAME(sc), + sizeof(sc->sc_sensors[i].device)); + SENSOR_ADD(&sc->sc_sensors[i]); + } + + timeout_set(&sc->sc_timeout, safte_refresh, sc); + timeout_add(&sc->sc_timeout, 10 * hz); +} + +int +safte_detach(struct device *self, int flags) +{ + struct safte_softc *sc = (struct safte_softc *)self; + int i; + + if (sc->sc_state != SAFTE_ST_NONE) { + /* + * we can't free the sensors since there is no mechanism to + * take them out of the sensor list. mark them invalid instead. + */ + for (i = 0; i < sc->sc_nsensors; i++) + sc->sc_sensors[i].flags |= SENSOR_FINVALID; + + free(sc->sc_encbuf, M_DEVBUF); + + sc->sc_state = SAFTE_ST_NONE; + } + + return (0); +} + +void +safte_refresh(void *arg) +{ + struct safte_softc *sc = arg; + + if (safte_read_encstat(sc, 1) != 0) { + if (sc->sc_state != SAFTE_ST_ERR) + printf("%s: error getting enclosure status\n", + DEVNAME(sc)); + sc->sc_state = SAFTE_ST_ERR; + } else { + if (sc->sc_state != SAFTE_ST_INIT) + printf("%s: enclosure back online\n", DEVNAME(sc)); + sc->sc_state = SAFTE_ST_INIT; + } + + timeout_add(&sc->sc_timeout, 10 * hz); +} + +int +safte_read_config(struct safte_softc *sc) +{ + struct safte_readbuf_cmd cmd; + struct safte_config config; + int flags; + + memset(&cmd, 0, sizeof(cmd)); + cmd.opcode = SAFTE_RD_OPCODE; + cmd.flags |= SAFTE_RD_MODE; + cmd.bufferid = SAFTE_RD_CONFIG; + cmd.length = htobe16(sizeof(config)); + flags = SCSI_DATA_IN; +#ifndef SCSIDEBUG + flags |= SCSI_SILENT; +#endif + + if (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd, + sizeof(cmd), (u_char *)&config, sizeof(config), 2, 30000, NULL, + flags) != 0) + return (1); + + DPRINTF(("%s: nfans: %d npwrsup: %d nslots: %d doorlock: %d ntemps: %d" + " alarm: %d celcius: %d ntherm: %d\n", DEVNAME(sc), config.nfans, + config.npwrsup, config.nslots, config.doorlock, config.ntemps, + config.alarm, SAFTE_CFG_CELCIUS(config.therm), + SAFTE_CFG_NTHERM(config.therm))); + + sc->sc_nfans = config.nfans; + sc->sc_npwrsup = config.npwrsup; + sc->sc_nslots = config.nslots; + sc->sc_ntemps = config.ntemps; + sc->sc_ntherm = SAFTE_CFG_NTHERM(config.therm); + sc->sc_flags = (config.doorlock ? SAFTE_FL_DOORLOCK : 0) | + (config.alarm ? SAFTE_FL_ALARM : 0) | + (SAFTE_CFG_CELCIUS(config.therm) ? SAFTE_FL_CELCIUS : 0); + + return (0); +} + +int +safte_read_encstat(struct safte_softc *sc, int refresh) +{ + struct safte_readbuf_cmd cmd; + int flags, i; + u_int8_t *p = sc->sc_encbuf; + struct sensor *s = sc->sc_sensors; + + memset(&cmd, 0, sizeof(cmd)); + cmd.opcode = SAFTE_RD_OPCODE; + cmd.flags |= SAFTE_RD_MODE; + cmd.bufferid = SAFTE_RD_ENCSTAT; + cmd.length = htobe16(sc->sc_encstatlen); + flags = SCSI_DATA_IN; +#ifndef SCSIDEBUG + flags |= SCSI_SILENT; +#endif + if (refresh) + flags |= SCSI_NOSLEEP; + + if (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd, + sizeof(cmd), sc->sc_encbuf, sc->sc_encstatlen, 2, 30000, NULL, + flags) != 0) + return (1); + + i = 0; + while (i < sc->sc_nfans) { + i++; + p++; + } + + i = 0; + while (i < sc->sc_npwrsup) { + i++; + p++; + } + + i = 0; + while (i < sc->sc_nslots) { + i++; + p++; + } + + /* doorlock */ + p++; + /* alarm */ + p++; + + i = 0; + while (i < sc->sc_ntemps) { + s->value = safte_temp2uK(*p, sc->sc_flags & SAFTE_FL_CELCIUS); + i++; + s++; + p++; + } + + /* temp over threshold (u_int16_t) */ + + return(0); +} + +int64_t +safte_temp2uK(u_int8_t measured, int celcius) +{ + int64_t temp; + + temp = (int64_t)measured; + temp += SAFTE_TEMP_OFFSET; + temp *= 1000000; /* convert to micro (mu) degrees */ + if (!celcius) + temp = ((temp - 32000000) * 5) / 9; /* convert to celcius */ + + temp += 273150000; /* convert to kelvin */ + + return (temp); +} diff --git a/sys/scsi/scsi_safte.h b/sys/scsi/scsi_safte.h new file mode 100644 index 00000000000..7053bc321d7 --- /dev/null +++ b/sys/scsi/scsi_safte.h @@ -0,0 +1,155 @@ +/* $OpenBSD: scsi_safte.h,v 1.1 2005/07/25 23:32:33 dlg Exp $ */ + +/* + * Copyright (c) 2005 Daivd 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. + */ + +#ifndef _SCSI_SAFTE_H_ +#define _SCSI_SAFTE_H_ + +#define SAFTE_EXTRA_OFFSET 0x05 +/* scsi_inquiry_data.extra */ +struct safte_inq { + u_int8_t uniqueid[7]; + u_int8_t chanid; + u_int8_t ident[6]; +#define SAFTE_IDENT "SAF-TE" + u_int8_t revision[4]; +#ifdef notyet + u_int8_t reserved[2]; +#endif +} __packed; +#define SAFTE_INQ_LEN 54 + +struct safte_readbuf_cmd { + u_int8_t opcode; +#define SAFTE_RD_OPCODE 0x3c /* READ BUFFER */ + u_int8_t flags; +#define SAFTE_RD_LUNMASK 0xe0 /* the lun should always be 0 */ +#define SAFTE_RD_MODEMASK 0x07 +#define SAFTE_RD_MODE 0x01 /* 0x01 is the SAF-TE command mode */ + u_int8_t bufferid; +#define SAFTE_RD_CONFIG 0x00 /* enclosure configuration */ +#define SAFTE_RD_ENCSTAT 0x01 /* enclosure status */ +#define SAFTE_RD_USAGE 0x02 /* usage statistics */ +#define SAFTE_RD_INSERTS 0x03 /* device insertions */ +#define SAFTE_RD_SLOTSTAT 0x04 /* slot status */ +#define SAFTE_RD_GLOBALS 0x05 /* global flags */ + u_int32_t reserved1; + u_int16_t length; /* transfer length (big endian) */ + u_int8_t reserved2; +} __packed; + +#define SAFTE_WRITE_SLOTSTAT 0x10 /* write device slot status */ +#define SAFTE_WRITE_SETID 0x11 /* set scsi id */ +#define SAFTE_WRITE_SLOTOP 0x12 /* perform slot operation */ +#define SAFTE_WRITE_FANSPEED 0x13 /* set fan speed */ +#define SAFTE_WRITE_PWRSUP 0x14 /* activate power supply */ +#define SAFTE_WRITE_GLOBALS 0x15 /* global flags */ + + +/* enclosure configuration */ +struct safte_config { + u_int8_t nfans; /* number of fans */ + u_int8_t npwrsup; /* number of power supplies */ + u_int8_t nslots; /* number of device slots */ + u_int8_t doorlock; /* door lock installed */ + u_int8_t ntemps; /* number of temp sensors */ + u_int8_t alarm; /* audible alarm installed */ + u_int8_t therm; /* temps in C and num of thermostats */ +#define SAFTE_CFG_CELCIUSMASK 0x80 +#define SAFTE_CFG_CELCIUS(a) ((a) & SAFTE_CFG_CELCIUSMASK ? 1 : 0) +#define SAFTE_CFG_NTHERMMASK 0x0f +#define SAFTE_CFG_NTHERM(a) ((a) & SAFTE_CFG_NTHERMMASK) + u_int8_t reserved[56]; /* 7 to 62 */ + u_int8_t vendor_bytes; /* number of vendor specific bytes */ +} __packed; +#define SAFTE_CONFIG_LEN sizeof(struct safte_config) + +/* enclosure status fields */ +/* fan status field */ +#define SAFTE_FAN_OP 0x00 /* operational */ +#define SAFTE_FAN_MF 0x01 /* malfunctioning */ +#define SAFTE_FAN_NOTINST 0x02 /* not installed */ +#define SAFTE_FAN_UNKNOWN 0x80 /* unknown status or unreportable */ + +/* power supply status field */ +#define SAFTE_PWR_OP_ON 0x00 /* operational and on */ +#define SAFTE_PWR_OP_OFF 0x01 /* operational and off */ +#define SAFTE_PWR_MF_ON 0x10 /* malfunctioning and on */ +#define SAFTE_PWR_MF_OFF 0x11 /* malfunctioning and off */ +#define SAFTE_PWR_NOTINST 0x20 /* not present */ +#define SAFTE_PWR_PRESENT 0x21 /* present */ +#define SAFTE_PWR_UNKOWN 0x80 /* unknown status or unreportable */ + +/* scsi id fields */ +/* are integers, not bitfields */ + +/* door lock status */ +#define SAFTE_DOOR_LOCKED 0x00 /* locked */ +#define SAFTE_DOOR_UNLOCKED 0x01 /* unlocked or uncontrollable */ +#define SAFTE_DOOR_UNKOWN 0x80 /* unknown status or unreportable */ + +/* speaker status */ +#define SAFTE_SPKR_OFF 0x00 /* off or not installed */ +#define SAFTE_SPKR_ON 0x01 /* speaker is currently on */ + +/* temperature */ +#define SAFTE_TEMP_OFFSET -10 /* -10 to 245 degrees */ + +/* temp out of range */ +#define SAFTE_TEMP_ETA 0x8000 /* any temp alert */ + + +/* usage statistics */ +struct safte_usage { + u_int32_t minutes; /* total number of minutes on */ + u_int32_t cycles; /* total number of power cycles */ + u_int8_t reserved[7]; + u_int8_t vendor_bytes; /* number of vendor specific bytes */ +}; + + +/* device insertions */ +/* u_int16_t * nslots */ + + +/* device slot status */ +#define SAFTE_SLOTSTAT_INSERT (1<<0) /* inserted */ +#define SAFTE_SLOTSTAT_SWAP (1<<1) /* ready to be inserted/removed */ +#define SAFTE_SLOTSTAT_OPER (1<<2) /* ready for operation */ + + +/* global flags */ +struct safte_globals { + u_int8_t flags1; +#define SAFTE_GLOBAL_ALARM (1<<0) /* audible alarm */ +#define SAFTE_GLOBAL_FAILURE (1<<1) /* global failure indication */ +#define SAFTE_GLOBAL_WARNING (1<<2) /* global warning indication */ +#define SAFTE_GLOBAL_POWER (1<<3) /* enclosure power */ +#define SAFTE_GLOBAL_COOLING (1<<4) /* cooling failure */ +#define SAFTE_GLOBAL_PWRFAIL (1<<5) /* power failture */ +#define SAFTE_GLOBAL_DRVFAIL (1<<6) /* drive failure */ +#define SAFTE_GLOBAL_DRVWARN (1<<6) /* drive warning */ + u_int8_t flags2; +#define SAFTE_GLOBAL_ARRAYFAIL (1<<0) /* array failure */ +#define SAFTE_GLOBAL_ARRAYWARN (1<<1) /* array warning */ +#define SAFTE_GLOBAL_LOCK (1<<2) /* enclosure lock */ +#define SAFTE_GLOBAL_IDENTIFY (1<<3) /* identify enclosure */ + u_int8_t flags3; + u_int8_t reserved[13]; +}; + +#endif /* _SCSI_SAFTE_H_ */ |