diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/ic/cac.c | 229 | ||||
-rw-r--r-- | sys/dev/ic/cacreg.h | 55 | ||||
-rw-r--r-- | sys/dev/ic/cacvar.h | 12 |
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 *); |