summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorBrad Smith <brad@cvs.openbsd.org>2008-10-29 21:17:16 +0000
committerBrad Smith <brad@cvs.openbsd.org>2008-10-29 21:17:16 +0000
commit619c3eac3b8820589c70a72fbb75bc410bb37154 (patch)
treeb409d701e614c8a643335b89f52d1bfd1972775a /sys
parent529bfd4502af6997805e92a2671cab5e3af698ec (diff)
Add initial bio support; only volume status is handled.
Based on cac(4) bio support from NetBSD which is derived from OpenBSD's ciss(4) bio support. Tested by otto@ jbg@ ok marco@
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/ic/cac.c229
-rw-r--r--sys/dev/ic/cacreg.h55
-rw-r--r--sys/dev/ic/cacvar.h12
3 files changed, 290 insertions, 6 deletions
diff --git a/sys/dev/ic/cac.c b/sys/dev/ic/cac.c
index 89c81926aa4..a19ccb3f2be 100644
--- a/sys/dev/ic/cac.c
+++ b/sys/dev/ic/cac.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cac.c,v 1.26 2008/06/26 05:42:15 ray Exp $ */
+/* $OpenBSD: cac.c,v 1.27 2008/10/29 21:17:15 brad Exp $ */
/* $NetBSD: cac.c,v 1.15 2000/11/08 19:20:35 ad Exp $ */
/*
@@ -62,11 +62,14 @@
* Driver for Compaq array controllers.
*/
+#include "bio.h"
+
/* #define CAC_DEBUG */
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
+#include <sys/ioctl.h>
#include <sys/device.h>
#include <sys/queue.h>
#include <sys/proc.h>
@@ -84,6 +87,11 @@
#include <dev/ic/cacreg.h>
#include <dev/ic/cacvar.h>
+#if NBIO > 0
+#include <dev/biovar.h>
+#endif
+#include <sys/sensors.h>
+
struct cfdriver cac_cd = {
NULL, "cac", DV_DULL
};
@@ -117,6 +125,16 @@ void cac_l0_intr_enable(struct cac_softc *, int);
int cac_l0_intr_pending(struct cac_softc *);
void cac_l0_submit(struct cac_softc *, struct cac_ccb *);
+#if NBIO > 0
+int cac_ioctl(struct device *, u_long, caddr_t);
+int cac_ioctl_vol(struct cac_softc *, struct bioc_vol *);
+
+#ifndef SMALL_KERNEL
+int cac_create_sensors(struct cac_softc *);
+void cac_sensor_refresh(void *);
+#endif
+#endif /* NBIO > 0 */
+
void *cac_sdh; /* shutdown hook */
const
@@ -245,6 +263,20 @@ cac_init(struct cac_softc *sc, int startfw)
(*sc->sc_cl->cl_intr_enable)(sc, 1);
+#if NBIO > 0
+ if (bio_register(&sc->sc_dv, cac_ioctl) != 0)
+ printf("%s: controller registration failed\n",
+ sc->sc_dv.dv_xname);
+ else
+ sc->sc_ioctl = cac_ioctl;
+
+#ifndef SMALL_KERNEL
+ if (cac_create_sensors(sc) != 0)
+ printf("%s: unable to create sensors\n", sc->sc_dv.dv_xname);
+#endif
+#endif
+
+
return (0);
}
@@ -391,10 +423,10 @@ int
cac_ccb_poll(struct cac_softc *sc, struct cac_ccb *wantccb, int timo)
{
struct cac_ccb *ccb;
- int s, t = timo * 10;
+ int s, t = timo * 100;
do {
- for (; t--; DELAY(100))
+ for (; t--; DELAY(10))
if ((ccb = (*sc->sc_cl->cl_completed)(sc)) != NULL)
break;
if (t < 0) {
@@ -773,3 +805,194 @@ cac_l0_intr_enable(struct cac_softc *sc, int state)
cac_outl(sc, CAC_REG_INTR_MASK,
state ? CAC_INTR_ENABLE : CAC_INTR_DISABLE);
}
+
+#if NBIO > 0
+const int cac_level[] = { 0, 4, 1, 5, 51, 7 };
+const int cac_stat[] = { BIOC_SVONLINE, BIOC_SVOFFLINE, BIOC_SVOFFLINE,
+ BIOC_SVDEGRADED, BIOC_SVREBUILD, BIOC_SVREBUILD, BIOC_SVDEGRADED,
+ BIOC_SVDEGRADED, BIOC_SVINVALID, BIOC_SVINVALID, BIOC_SVBUILDING,
+ BIOC_SVOFFLINE, BIOC_SVBUILDING };
+
+int
+cac_ioctl(struct device *dev, u_long cmd, caddr_t addr)
+{
+ struct cac_softc *sc = (struct cac_softc *)dev;
+ struct bioc_inq *bi;
+ struct bioc_disk *bd;
+ cac_lock_t lock;
+ int error = 0;
+
+ lock = CAC_LOCK(sc);
+ switch (cmd) {
+ case BIOCINQ:
+ bi = (struct bioc_inq *)addr;
+ strlcpy(bi->bi_dev, sc->sc_dv.dv_xname, sizeof(bi->bi_dev));
+ bi->bi_novol = sc->sc_nunits;
+ bi->bi_nodisk = 0;
+ break;
+
+ case BIOCVOL:
+ error = cac_ioctl_vol(sc, (struct bioc_vol *)addr);
+ break;
+
+ case BIOCDISK:
+ bd = (struct bioc_disk *)addr;
+ if (bd->bd_volid > sc->sc_nunits) {
+ error = EINVAL;
+ break;
+ }
+ /* No disk information yet */
+ break;
+
+ case BIOCBLINK:
+ case BIOCALARM:
+ case BIOCSETSTATE:
+ default:
+ error = ENOTTY;
+ }
+ CAC_UNLOCK(sc, lock);
+
+ return (error);
+}
+
+int
+cac_ioctl_vol(struct cac_softc *sc, struct bioc_vol *bv)
+{
+ struct cac_drive_info dinfo;
+ struct cac_drive_status dstatus;
+ u_int32_t blks;
+
+ if (bv->bv_volid > sc->sc_nunits)
+ return (EINVAL);
+ if (cac_cmd(sc, CAC_CMD_GET_LOG_DRV_INFO, &dinfo, sizeof(dinfo),
+ bv->bv_volid, 0, CAC_CCB_DATA_IN, NULL))
+ return (EIO);
+ if (cac_cmd(sc, CAC_CMD_SENSE_DRV_STATUS, &dstatus, sizeof(dstatus),
+ bv->bv_volid, 0, CAC_CCB_DATA_IN, NULL))
+ return (EIO);
+ bv->bv_status = BIOC_SVINVALID;
+ blks = CAC_GET2(dinfo.ncylinders) * CAC_GET1(dinfo.nheads) *
+ CAC_GET1(dinfo.nsectors);
+ bv->bv_size = (off_t)blks * CAC_GET2(dinfo.secsize);
+ bv->bv_level = cac_level[CAC_GET1(dinfo.mirror)]; /*XXX limit check */
+ bv->bv_nodisk = 0; /* XXX */
+ bv->bv_status = 0; /* XXX */
+ bv->bv_percent = -1;
+ bv->bv_seconds = 0;
+ if (dstatus.stat < sizeof(cac_stat)/sizeof(cac_stat[0]))
+ bv->bv_status = cac_stat[dstatus.stat];
+ if (bv->bv_status == BIOC_SVREBUILD ||
+ bv->bv_status == BIOC_SVBUILDING)
+ bv->bv_percent = ((blks - CAC_GET4(dstatus.prog)) * 1000ULL) /
+ blks;
+
+ return (0);
+}
+
+#ifndef SMALL_KERNEL
+int
+cac_create_sensors(struct cac_softc *sc)
+{
+ struct device *dev;
+ struct scsibus_softc *ssc;
+ int i;
+
+ TAILQ_FOREACH(dev, &alldevs, dv_list) {
+ if (dev->dv_parent != &sc->sc_dv)
+ continue;
+
+ /* check if this is the scsibus for the logical disks */
+ ssc = (struct scsibus_softc *)dev;
+ if (ssc->adapter_link == &sc->sc_link)
+ break;
+ }
+
+ if (ssc == NULL)
+ return (1);
+
+ sc->sc_sensors = malloc(sizeof(struct ksensor) * sc->sc_nunits,
+ M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (sc->sc_sensors == NULL)
+ return (1);
+
+ strlcpy(sc->sc_sensordev.xname, sc->sc_dv.dv_xname,
+ sizeof(sc->sc_sensordev.xname));
+
+ for (i = 0; i < sc->sc_nunits; i++) {
+ if (ssc->sc_link[i][0] == NULL)
+ goto bad;
+
+ dev = ssc->sc_link[i][0]->device_softc;
+
+ sc->sc_sensors[i].type = SENSOR_DRIVE;
+ sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
+
+ strlcpy(sc->sc_sensors[i].desc, dev->dv_xname,
+ sizeof(sc->sc_sensors[i].desc));
+
+ sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
+ }
+
+ if (sensor_task_register(sc, cac_sensor_refresh, 10) == NULL)
+ goto bad;
+
+ sensordev_install(&sc->sc_sensordev);
+
+ return (0);
+
+bad:
+ free(sc->sc_sensors, M_DEVBUF);
+
+ return (1);
+}
+
+void
+cac_sensor_refresh(void *arg)
+{
+ struct cac_softc *sc = arg;
+ struct bioc_vol bv;
+ int i, s;
+
+ for (i = 0; i < sc->sc_nunits; i++) {
+ bzero(&bv, sizeof(bv));
+ bv.bv_volid = i;
+ s = splbio();
+ if (cac_ioctl_vol(sc, &bv)) {
+ splx(s);
+ return;
+ }
+ splx(s);
+
+ switch (bv.bv_status) {
+ case BIOC_SVOFFLINE:
+ sc->sc_sensors[i].value = SENSOR_DRIVE_FAIL;
+ sc->sc_sensors[i].status = SENSOR_S_CRIT;
+ break;
+
+ case BIOC_SVDEGRADED:
+ sc->sc_sensors[i].value = SENSOR_DRIVE_PFAIL;
+ sc->sc_sensors[i].status = SENSOR_S_WARN;
+ break;
+
+ case BIOC_SVSCRUB:
+ case BIOC_SVONLINE:
+ sc->sc_sensors[i].value = SENSOR_DRIVE_ONLINE;
+ sc->sc_sensors[i].status = SENSOR_S_OK;
+ break;
+
+ case BIOC_SVREBUILD:
+ case BIOC_SVBUILDING:
+ sc->sc_sensors[i].value = SENSOR_DRIVE_REBUILD;
+ sc->sc_sensors[i].status = SENSOR_S_OK;
+ break;
+
+ case BIOC_SVINVALID:
+ /* FALLTRHOUGH */
+ default:
+ sc->sc_sensors[i].value = 0; /* unknown */
+ sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
+ }
+ }
+}
+#endif /* SMALL_KERNEL */
+#endif /* NBIO > 0 */
diff --git a/sys/dev/ic/cacreg.h b/sys/dev/ic/cacreg.h
index 9e1ac7bedfd..2906df9963b 100644
--- a/sys/dev/ic/cacreg.h
+++ b/sys/dev/ic/cacreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cacreg.h,v 1.5 2008/06/26 05:42:15 ray Exp $ */
+/* $OpenBSD: cacreg.h,v 1.6 2008/10/29 21:17:15 brad Exp $ */
/* $NetBSD: cacreg.h,v 1.5 2001/01/10 16:48:04 ad Exp $ */
/*-
@@ -174,6 +174,59 @@ struct cac_controller_info {
u_int8_t reserved[403];
} __packed;
+struct cac_drive_status {
+ u_int8_t stat;
+#define CAC_LD_OK 0
+#define CAC_LD_FAILED 1
+#define CAC_LD_UNCONF 2
+#define CAC_LD_DEGRAD 3
+#define CAC_LD_RBLDRD 4 /* ready for rebuild */
+#define CAC_LD_REBLD 5
+#define CAC_LD_PDINV 6 /* wrong phys drive replaced */
+#define CAC_LD_PDUNC 7 /* phys drive is not connected proper */
+#define CAC_LD_EXPND 10 /* expanding */
+#define CAC_LD_NORDY 11 /* volume is not ready */
+#define CAC_LD_QEXPND 12 /* queued for expansion */
+ u_int8_t failed[4]; /* failed map */
+ u_int8_t res0[416];
+ u_int8_t prog[4]; /* blocks left to rebuild/expand */
+ u_int8_t rebuild; /* drive that is rebuilding */
+ u_int16_t remapcnt[32]; /* count of re3mapped blocks for pds */
+ u_int8_t replaced[4]; /* replaced drives map */
+ u_int8_t spare[4]; /* used spares map */
+ u_int8_t sparestat; /* spare status */
+#define CAC_LD_CONF 0x01 /* spare configured */
+#define CAC_LD_RBLD 0x02 /* spare is used and rebuilding */
+#define CAC_LD_DONE 0x04 /* spare rebuild done */
+#define CAC_LD_FAIL 0x08 /* at least one spare drive has failed */
+#define CAC_LD_USED 0x10 /* at least one spare drive is used */
+#define CAC_LD_AVAIL 0x20 /* at least one spare is available */
+ u_int8_t sparemap[32]; /* spare->pd replacement map */
+ u_int8_t replok[4]; /* replaced failed map */
+ u_int8_t readyok; /* ready to become ok */
+ u_int8_t memfail; /* cache mem failure */
+ u_int8_t expfail; /* expansion failure */
+ u_int8_t rebldfail; /* rebuild failure */
+#define CAC_LD_RBLD_READ 0x01 /* read faild */
+#define CAC_LD_RBLD_WRITE 0x02 /* write fail */
+ u_int8_t bigfailed[16]; /* bigmap vers of same of the above */
+ u_int8_t bigremapcnt[256];
+ u_int8_t bigreplaced[16];
+ u_int8_t bigspare[16];
+ u_int8_t bigsparemap[128];
+ u_int8_t bigreplok[16];
+ u_int8_t bigrebuild; /* big-number rebuilding driveno */
+} __packed;
+
+struct cac_blink {
+ u_int32_t duration; /* x100ms */
+ u_int32_t elapsed; /* only for sense */
+ u_int8_t pdtab[256];
+#define CAC_BLINK_ALL 1
+#define CAC_BLINK_TIMED 2
+ u_int8_t res[248];
+} __packed;
+
struct cac_hdr {
u_int8_t drive; /* logical drive */
u_int8_t priority; /* block priority */
diff --git a/sys/dev/ic/cacvar.h b/sys/dev/ic/cacvar.h
index dec3792c7e9..51a307b1c1b 100644
--- a/sys/dev/ic/cacvar.h
+++ b/sys/dev/ic/cacvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cacvar.h,v 1.4 2008/06/26 05:42:15 ray Exp $ */
+/* $OpenBSD: cacvar.h,v 1.5 2008/10/29 21:17:15 brad Exp $ */
/* $NetBSD: cacvar.h,v 1.7 2000/10/19 14:28:47 ad Exp $ */
/*-
@@ -61,7 +61,7 @@
(((u_char *)&(x))[0] | (((u_char *)&(x))[1] << 8))
#define CAC_GET4(x) \
((((u_char *)&(x))[0] | (((u_char *)&(x))[1] << 8)) | \
- (((u_char *)&(x))[0] << 16 | (((u_char *)&(x))[1] << 24)))
+ (((u_char *)&(x))[2] << 16 | (((u_char *)&(x))[3] << 24)))
struct cac_ccb {
/* Data the controller will touch - 276 bytes */
@@ -107,8 +107,16 @@ struct cac_softc {
SIMPLEQ_HEAD(, cac_ccb) sc_ccb_free;
SIMPLEQ_HEAD(, cac_ccb) sc_ccb_queue;
struct cac_drive_info *sc_dinfos;
+ int (*sc_ioctl)(struct device *, u_long, caddr_t);
+ struct ksensor *sc_sensors;
+ struct ksensordev sc_sensordev;
};
+/* XXX These have to become spinlocks in case of fine SMP */
+#define CAC_LOCK(sc) splbio()
+#define CAC_UNLOCK(sc, lock) splx(lock)
+typedef int cac_lock_t;
+
int cac_init(struct cac_softc *, int);
int cac_intr(void *);