Initial bio(4) support; only volume status is handled. The driver doesn't

yet know about physical drives.  Derived from the OpenBSD ciss(4) bio(4)
support.
This commit is contained in:
mhitch 2008-03-14 03:30:19 +00:00
parent f742db2180
commit b6044f13b8
3 changed files with 273 additions and 4 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: cac.c,v 1.43 2007/12/05 07:06:51 ad Exp $ */
/* $NetBSD: cac.c,v 1.44 2008/03/14 03:30:19 mhitch Exp $ */
/*-
* Copyright (c) 2000, 2006, 2007 The NetBSD Foundation, Inc.
@ -41,7 +41,9 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: cac.c,v 1.43 2007/12/05 07:06:51 ad Exp $");
__KERNEL_RCSID(0, "$NetBSD: cac.c,v 1.44 2008/03/14 03:30:19 mhitch Exp $");
#include "bio.h"
#include <sys/param.h>
#include <sys/systm.h>
@ -62,6 +64,10 @@ __KERNEL_RCSID(0, "$NetBSD: cac.c,v 1.43 2007/12/05 07:06:51 ad Exp $");
#include <dev/ic/cacreg.h>
#include <dev/ic/cacvar.h>
#if NBIO > 0
#include <dev/biovar.h>
#endif /* NBIO > 0 */
#include "locators.h"
static struct cac_ccb *cac_ccb_alloc(struct cac_softc *, int);
@ -80,6 +86,13 @@ static void cac_l0_submit(struct cac_softc *, struct cac_ccb *);
static void *cac_sdh; /* shutdown hook */
#if NBIO > 0
int cac_ioctl(struct device *, u_long, void *);
int cac_ioctl_vol(struct cac_softc *, struct bioc_vol *);
int cac_create_sensors(struct cac_softc *);
void cac_sensor_refresh(struct sysmon_envsys *, envsys_data_t *);
#endif /* NBIO > 0 */
const struct cac_linkage cac_l0 = {
cac_l0_completed,
cac_l0_fifo_full,
@ -203,6 +216,16 @@ cac_init(struct cac_softc *sc, const char *intrstr, int startfw)
(*sc->sc_cl.cl_intr_enable)(sc, CAC_INTR_ENABLE);
mutex_exit(&sc->sc_mutex);
#if NBIO > 0
if (bio_register(&sc->sc_dv, cac_ioctl) != 0)
printf("%s: controller registration failed",
sc->sc_dv.dv_xname);
else
sc->sc_ioctl = cac_ioctl;
if (cac_create_sensors(sc) != 0)
aprint_error("%s: unable to create sensors\n", sc->sc_dv.dv_xname);
#endif
return (0);
}
@ -571,3 +594,182 @@ 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, void *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:
case BIOCDISK_NOVOL:
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 = EINVAL;
}
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;
}
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;
}
int
cac_create_sensors(struct cac_softc *sc)
{
int i;
int nsensors = sc->sc_nunits;
sc->sc_sme = sysmon_envsys_create();
sc->sc_sensor = malloc(sizeof(envsys_data_t) * nsensors,
M_DEVBUF, M_NOWAIT | M_ZERO);
if (sc->sc_sensor == NULL) {
aprint_error("%s: can't allocate envsys_data_t\n",
sc->sc_dv.dv_xname);
return(ENOMEM);
}
for (i = 0; i < nsensors; i++) {
sc->sc_sensor[i].units = ENVSYS_DRIVE;
sc->sc_sensor[i].monitor = true;
/* Enable monitoring for drive state changes */
sc->sc_sensor[i].flags |= ENVSYS_FMONSTCHANGED;
/* logical drives */
snprintf(sc->sc_sensor[i].desc,
sizeof(sc->sc_sensor[i].desc), "%s:%d",
sc->sc_dv.dv_xname, i);
if (sysmon_envsys_sensor_attach(sc->sc_sme,
&sc->sc_sensor[i]))
goto out;
}
sc->sc_sme->sme_name = sc->sc_dv.dv_xname;
sc->sc_sme->sme_cookie = sc;
sc->sc_sme->sme_refresh = cac_sensor_refresh;
if (sysmon_envsys_register(sc->sc_sme)) {
printf("%s: unable to register with sysmon\n", sc->sc_dv.dv_xname);
return(1);
}
return (0);
out:
free(sc->sc_sensor, M_DEVBUF);
sysmon_envsys_destroy(sc->sc_sme);
return EINVAL;
}
void
cac_sensor_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
{
struct cac_softc *sc = sme->sme_cookie;
struct bioc_vol bv;
int s;
if (edata->sensor >= sc->sc_nunits)
return;
bzero(&bv, sizeof(bv));
bv.bv_volid = edata->sensor;
s = splbio();
if (cac_ioctl_vol(sc, &bv)) {
splx(s);
return;
}
splx(s);
switch(bv.bv_status) {
case BIOC_SVOFFLINE:
edata->value_cur = ENVSYS_DRIVE_FAIL;
edata->state = ENVSYS_SCRITICAL;
break;
case BIOC_SVDEGRADED:
edata->value_cur = ENVSYS_DRIVE_PFAIL;
edata->state = ENVSYS_SCRITICAL;
break;
case BIOC_SVSCRUB:
case BIOC_SVONLINE:
edata->value_cur = ENVSYS_DRIVE_ONLINE;
edata->state = ENVSYS_SVALID;
break;
case BIOC_SVREBUILD:
case BIOC_SVBUILDING:
edata->value_cur = ENVSYS_DRIVE_REBUILD;
edata->state = ENVSYS_SVALID;
break;
case BIOC_SVINVALID:
/* FALLTRHOUGH */
default:
edata->value_cur = 0; /* unknown */
edata->state = ENVSYS_SINVALID;
}
}
#endif /* NBIO > 0 */

View File

@ -1,4 +1,4 @@
/* $NetBSD: cacreg.h,v 1.9 2007/12/25 18:33:38 perry Exp $ */
/* $NetBSD: cacreg.h,v 1.10 2008/03/14 03:30:19 mhitch Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@ -177,6 +177,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 */

View File

@ -1,4 +1,4 @@
/* $NetBSD: cacvar.h,v 1.16 2007/06/27 17:57:55 mhitch Exp $ */
/* $NetBSD: cacvar.h,v 1.17 2008/03/14 03:30:19 mhitch Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@ -42,6 +42,9 @@
#include <sys/mutex.h>
#include <sys/condvar.h>
#include <dev/sysmon/sysmonvar.h>
#include <sys/envsys.h>
#define CAC_MAX_CCBS 256
#define CAC_MAX_XFER (0xffff * 512)
#define CAC_SG_SIZE 32
@ -122,8 +125,19 @@ struct cac_softc {
SIMPLEQ_HEAD(, cac_ccb) sc_ccb_queue;
kcondvar_t sc_ccb_cv;
struct cac_linkage sc_cl;
/* scsi ioctl from sd device */
int (*sc_ioctl)(struct device *, u_long, void *);
struct sysmon_envsys *sc_sme;
envsys_data_t *sc_sensor;
};
/* 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;
struct cac_attach_args {
int caca_unit;
};