summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordlg <dlg@openbsd.org>2005-07-25 23:32:33 +0000
committerdlg <dlg@openbsd.org>2005-07-25 23:32:33 +0000
commitfe4e9b4cfad70a89e8ba8dca18cc3ab8f1dec6c9 (patch)
tree5b8dc4e5644aedbb17b310d4d1d1f4fbd54d7f6a
parentupdate DESCRIPTION to reflect the fact that another synopsis form was (diff)
downloadwireguard-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.scsi7
-rw-r--r--sys/scsi/scsi_safte.c386
-rw-r--r--sys/scsi/scsi_safte.h155
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_ */