summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorthorpej <thorpej@NetBSD.org>2003-09-22 18:31:10 +0000
committerthorpej <thorpej@NetBSD.org>2003-09-22 18:31:10 +0000
commitddfcdc4f1f958d7ca75934320bb74b750d3011b4 (patch)
tree26c1666570f5b1a3981760a7c717adf81256cfcd /sys/dev
parentbc88a034889547e12e10afd503b2bd1f0ce59871 (diff)
Add support for dynamically attaching and detaching RAID array units.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pci/ld_twe.c36
-rw-r--r--sys/dev/pci/twe.c246
-rw-r--r--sys/dev/pci/twevar.h12
3 files changed, 218 insertions, 76 deletions
diff --git a/sys/dev/pci/ld_twe.c b/sys/dev/pci/ld_twe.c
index 1cf7dd178ab..bc11e553220 100644
--- a/sys/dev/pci/ld_twe.c
+++ b/sys/dev/pci/ld_twe.c
@@ -1,4 +1,4 @@
-/* $NetBSD: ld_twe.c,v 1.15 2003/09/21 19:33:10 thorpej Exp $ */
+/* $NetBSD: ld_twe.c,v 1.16 2003/09/22 18:31:10 thorpej Exp $ */
/*-
* Copyright (c) 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -41,7 +41,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ld_twe.c,v 1.15 2003/09/21 19:33:10 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ld_twe.c,v 1.16 2003/09/22 18:31:10 thorpej Exp $");
#include "rnd.h"
@@ -72,6 +72,7 @@ struct ld_twe_softc {
};
static void ld_twe_attach(struct device *, struct device *, void *);
+static int ld_twe_detach(struct device *, int);
static int ld_twe_dobio(struct ld_twe_softc *, void *, int, int, int,
struct buf *);
static int ld_twe_dump(struct ld_softc *, void *, int, int);
@@ -79,8 +80,14 @@ static void ld_twe_handler(struct twe_ccb *, int);
static int ld_twe_match(struct device *, struct cfdata *, void *);
static int ld_twe_start(struct ld_softc *, struct buf *);
+static void ld_twe_adjqparam(struct device *, int);
+
CFATTACH_DECL(ld_twe, sizeof(struct ld_twe_softc),
- ld_twe_match, ld_twe_attach, NULL, NULL);
+ ld_twe_match, ld_twe_attach, ld_twe_detach, NULL);
+
+static const struct twe_callbacks ld_twe_callbacks = {
+ ld_twe_adjqparam,
+};
static int
ld_twe_match(struct device *parent, struct cfdata *match, void *aux)
@@ -108,12 +115,14 @@ ld_twe_attach(struct device *parent, struct device *self, void *aux)
twea = aux;
td = &twe->sc_units[twea->twea_unit];
+ twe_register_callbacks(twe, twea->twea_unit, &ld_twe_callbacks);
+
sc->sc_hwunit = twea->twea_unit;
ld->sc_flags = LDF_ENABLED;
ld->sc_maxxfer = twe_get_maxxfer(twe_get_maxsegs());
ld->sc_secperunit = td->td_size;
ld->sc_secsize = TWE_SECTOR_SIZE;
- ld->sc_maxqueuecnt = (TWE_MAX_QUEUECNT - 1) / twe->sc_nunits;
+ ld->sc_maxqueuecnt = twe->sc_openings;
ld->sc_start = ld_twe_start;
ld->sc_dump = ld_twe_dump;
@@ -156,6 +165,18 @@ ld_twe_attach(struct device *parent, struct device *self, void *aux)
}
static int
+ld_twe_detach(struct device *self, int flags)
+{
+ int rv;
+
+ if ((rv = ldbegindetach((struct ld_softc *)self, flags)) != 0)
+ return (rv);
+ ldenddetach((struct ld_softc *)self);
+
+ return (0);
+}
+
+static int
ld_twe_dobio(struct ld_twe_softc *sc, void *data, int datasize, int blkno,
int dowrite, struct buf *bp)
{
@@ -253,3 +274,10 @@ ld_twe_dump(struct ld_softc *ld, void *data, int blkno, int blkcnt)
return (ld_twe_dobio((struct ld_twe_softc *)ld, data,
blkcnt * ld->sc_secsize, blkno, 1, NULL));
}
+
+static void
+ld_twe_adjqparam(struct device *self, int openings)
+{
+
+ ldadjqparam((struct ld_softc *)self, openings);
+}
diff --git a/sys/dev/pci/twe.c b/sys/dev/pci/twe.c
index 3fa83ac53b0..b60311bd1e9 100644
--- a/sys/dev/pci/twe.c
+++ b/sys/dev/pci/twe.c
@@ -1,4 +1,4 @@
-/* $NetBSD: twe.c,v 1.45 2003/09/22 01:13:02 thorpej Exp $ */
+/* $NetBSD: twe.c,v 1.46 2003/09/22 18:31:11 thorpej Exp $ */
/*-
* Copyright (c) 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -70,7 +70,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: twe.c,v 1.45 2003/09/22 01:13:02 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: twe.c,v 1.46 2003/09/22 18:31:11 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -115,6 +115,9 @@ static int twe_status_check(struct twe_softc *, u_int);
static int twe_status_wait(struct twe_softc *, u_int, int);
static void twe_describe_controller(struct twe_softc *);
+static int twe_add_unit(struct twe_softc *, int);
+static int twe_del_unit(struct twe_softc *, int);
+
static inline u_int32_t twe_inl(struct twe_softc *, int);
static inline void twe_outl(struct twe_softc *, int, u_int32_t);
@@ -302,14 +305,9 @@ twe_attach(struct device *parent, struct device *self, void *aux)
const char *intrstr;
int size, i, rv, rseg;
size_t max_segs, max_xfer;
- struct twe_param *dtp, *atp;
- struct twe_array_descriptor *ad;
- struct twe_drive *td;
bus_dma_segment_t seg;
struct twe_cmd *tc;
- struct twe_attach_args twea;
struct twe_ccb *ccb;
- uint16_t dsize;
sc = (struct twe_softc *)self;
pa = aux;
@@ -435,86 +433,184 @@ twe_attach(struct device *parent, struct device *self, void *aux)
return;
}
+ /* Initialise connection with controller. */
+ twe_init_connection(sc);
+
+ twe_describe_controller(sc);
+
+ /* Find and attach RAID array units. */
+ sc->sc_nunits = 0;
+ for (i = 0; i < TWE_MAX_UNITS; i++)
+ (void) twe_add_unit(sc, i);
+
+ /* ...and finally, enable interrupts. */
+ twe_outl(sc, TWE_REG_CTL, TWE_CTL_CLEAR_ATTN_INTR |
+ TWE_CTL_UNMASK_RESP_INTR |
+ TWE_CTL_ENABLE_INTRS);
+}
+
+void
+twe_register_callbacks(struct twe_softc *sc, int unit,
+ const struct twe_callbacks *tcb)
+{
+
+ sc->sc_units[unit].td_callbacks = tcb;
+}
+
+static void
+twe_recompute_openings(struct twe_softc *sc)
+{
+ struct twe_drive *td;
+ int unit, openings;
+
+ if (sc->sc_nunits != 0)
+ openings = (TWE_MAX_QUEUECNT - 1) / sc->sc_nunits;
+ else
+ openings = 0;
+ if (openings == sc->sc_openings)
+ return;
+ sc->sc_openings = openings;
+
+#ifdef TWE_DEBUG
+ printf("%s: %d array%s, %d openings per array\n",
+ sc->sc_dv.dv_xname, sc->sc_nunits,
+ sc->sc_nunits == 1 ? "" : "s", sc->sc_openings);
+#endif
+
+ for (unit = 0; unit < TWE_MAX_UNITS; unit++) {
+ td = &sc->sc_units[unit];
+ if (td->td_dev != NULL)
+ (*td->td_callbacks->tcb_openings)(td->td_dev,
+ sc->sc_openings);
+ }
+}
+
+static int
+twe_add_unit(struct twe_softc *sc, int unit)
+{
+ struct twe_param *dtp, *atp;
+ struct twe_array_descriptor *ad;
+ struct twe_drive *td;
+ struct twe_attach_args twea;
+ uint32_t newsize;
+ int rv;
+ uint16_t dsize;
+ uint8_t newtype, newstripe;
+
+ if (unit < 0 || unit >= TWE_MAX_UNITS)
+ return (EINVAL);
+
/* Find attached units. */
rv = twe_param_get(sc, TWE_PARAM_UNITSUMMARY,
TWE_PARAM_UNITSUMMARY_Status, TWE_MAX_UNITS, NULL, &dtp);
if (rv != 0) {
- aprint_error("%s: can't detect attached units (%d)\n",
+ aprint_error("%s: error %d fetching unit summary\n",
sc->sc_dv.dv_xname, rv);
- return;
+ return (rv);
}
/* For each detected unit, collect size and store in an array. */
- for (i = 0, sc->sc_nunits = 0; i < TWE_MAX_UNITS; i++) {
- td = &sc->sc_units[i];
-
- /* Unit present? */
- if ((dtp->tp_data[i] & TWE_PARAM_UNITSTATUS_Online) == 0) {
- td->td_size = 0;
- td->td_type = 0;
- td->td_stripe = 0;
- continue;
- }
-
- rv = twe_param_get_2(sc, TWE_PARAM_UNITINFO + i,
- TWE_PARAM_UNITINFO_DescriptorSize, &dsize);
- if (rv != 0) {
- aprint_error("%s: error %d fetching descriptor size "
- "for unit %d\n", sc->sc_dv.dv_xname, rv, i);
- td->td_size = 0;
- td->td_type = 0;
- td->td_stripe = 0;
- continue;
- }
+ td = &sc->sc_units[unit];
+
+ /* Unit present? */
+ if ((dtp->tp_data[unit] & TWE_PARAM_UNITSTATUS_Online) == 0) {
+ /*
+ * XXX Should we check to see if a device has been
+ * XXX attached at this index and detach it if it
+ * XXX has? ("rescan" semantics)
+ */
+ rv = 0;
+ goto out;
+ }
- rv = twe_param_get(sc, TWE_PARAM_UNITINFO + i,
- TWE_PARAM_UNITINFO_Descriptor, dsize - 3, NULL, &atp);
- if (rv != 0) {
- aprint_error("%s: error %d fetching array descriptor "
- "for unit %d\n", sc->sc_dv.dv_xname, rv, i);
- td->td_size = 0;
- td->td_type = 0;
- td->td_stripe = 0;
- continue;
- }
- ad = (struct twe_array_descriptor *)atp->tp_data;
- td->td_type = ad->configuration;
- td->td_stripe = ad->stripe_size;
- free(atp, M_DEVBUF);
+ rv = twe_param_get_2(sc, TWE_PARAM_UNITINFO + unit,
+ TWE_PARAM_UNITINFO_DescriptorSize, &dsize);
+ if (rv != 0) {
+ aprint_error("%s: error %d fetching descriptor size "
+ "for unit %d\n", sc->sc_dv.dv_xname, rv, unit);
+ goto out;
+ }
- rv = twe_param_get_4(sc, TWE_PARAM_UNITINFO + i,
- TWE_PARAM_UNITINFO_Capacity, &td->td_size);
- if (rv != 0) {
- aprint_error(
- "%s: error %d fetching capacity for unit %d\n",
- sc->sc_dv.dv_xname, rv, i);
- td->td_size = 0;
- td->td_type = 0;
- td->td_stripe = 0;
- continue;
- }
+ rv = twe_param_get(sc, TWE_PARAM_UNITINFO + unit,
+ TWE_PARAM_UNITINFO_Descriptor, dsize - 3, NULL, &atp);
+ if (rv != 0) {
+ aprint_error("%s: error %d fetching array descriptor "
+ "for unit %d\n", sc->sc_dv.dv_xname, rv, unit);
+ goto out;
+ }
- sc->sc_nunits++;
+ ad = (struct twe_array_descriptor *)atp->tp_data;
+ newtype = ad->configuration;
+ newstripe = ad->stripe_size;
+ free(atp, M_DEVBUF);
+
+ rv = twe_param_get_4(sc, TWE_PARAM_UNITINFO + unit,
+ TWE_PARAM_UNITINFO_Capacity, &newsize);
+ if (rv != 0) {
+ aprint_error(
+ "%s: error %d fetching capacity for unit %d\n",
+ sc->sc_dv.dv_xname, rv, unit);
+ goto out;
}
- free(dtp, M_DEVBUF);
- /* Initialise connection with controller and enable interrupts. */
- twe_init_connection(sc);
- twe_outl(sc, TWE_REG_CTL, TWE_CTL_CLEAR_ATTN_INTR |
- TWE_CTL_UNMASK_RESP_INTR |
- TWE_CTL_ENABLE_INTRS);
+ /*
+ * Have a device, so we need to attach it. If there is currently
+ * something sitting at the slot, and the parameters are different,
+ * then we detach the old device before attaching the new one.
+ */
+ if (td->td_dev != NULL &&
+ td->td_size == newsize &&
+ td->td_type == newtype &&
+ td->td_stripe == newstripe) {
+ /* Same as the old device; just keep using it. */
+ rv = 0;
+ goto out;
+ } else if (td->td_dev != NULL) {
+ /* Detach the old device first. */
+ (void) config_detach(td->td_dev, DETACH_FORCE);
+ td->td_dev = NULL;
+ } else if (td->td_size == 0)
+ sc->sc_nunits++;
- twe_describe_controller(sc);
+ /*
+ * Committed to the new array unit; assign its parameters and
+ * recompute the number of available command openings.
+ */
+ td->td_size = newsize;
+ td->td_type = newtype;
+ td->td_stripe = newstripe;
+ twe_recompute_openings(sc);
- /* Attach sub-devices. */
- for (i = 0; i < TWE_MAX_UNITS; i++) {
- td = &sc->sc_units[i];
- if (td->td_size == 0)
- continue;
- twea.twea_unit = i;
- td->td_dev = config_found_sm(&sc->sc_dv, &twea, twe_print,
- twe_submatch);
+ twea.twea_unit = unit;
+ td->td_dev = config_found_sm(&sc->sc_dv, &twea, twe_print,
+ twe_submatch);
+
+ rv = 0;
+ out:
+ free(dtp, M_DEVBUF);
+ return (rv);
+}
+
+static int
+twe_del_unit(struct twe_softc *sc, int unit)
+{
+ struct twe_drive *td;
+
+ if (unit < 0 || unit >= TWE_MAX_UNITS)
+ return (EINVAL);
+
+ td = &sc->sc_units[unit];
+ if (td->td_size != 0)
+ sc->sc_nunits--;
+ td->td_size = 0;
+ td->td_type = 0;
+ td->td_stripe = 0;
+ if (td->td_dev != NULL) {
+ (void) config_detach(td->td_dev, DETACH_FORCE);
+ td->td_dev = NULL;
}
+ twe_recompute_openings(sc);
+ return (0);
}
/*
@@ -1516,6 +1612,14 @@ tweioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
twe_reset(twe);
return (0);
+ case TWEIO_ADD_UNIT:
+ /* XXX mutex */
+ return (twe_add_unit(twe, *(int *)data));
+
+ case TWEIO_DEL_UNIT:
+ /* XXX mutex */
+ return (twe_del_unit(twe, *(int *)data));
+
default:
return EINVAL;
}
diff --git a/sys/dev/pci/twevar.h b/sys/dev/pci/twevar.h
index 286d45d8838..04fed0731d3 100644
--- a/sys/dev/pci/twevar.h
+++ b/sys/dev/pci/twevar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: twevar.h,v 1.17 2003/09/22 01:13:03 thorpej Exp $ */
+/* $NetBSD: twevar.h,v 1.18 2003/09/22 18:31:11 thorpej Exp $ */
/*-
* Copyright (c) 2000, 2001, 2002 The NetBSD Foundation, Inc.
@@ -43,6 +43,11 @@
#define TWE_MAX_QUEUECNT 129
+/* Callbacks from controller to array. */
+struct twe_callbacks {
+ void (*tcb_openings)(struct device *, int);
+};
+
/* Per-array drive information. */
struct twe_drive {
uint32_t td_size;
@@ -50,6 +55,7 @@ struct twe_drive {
uint8_t td_stripe;
struct device *td_dev;
+ const struct twe_callbacks *td_callbacks;
};
/* Per-controller state. */
@@ -67,6 +73,7 @@ struct twe_softc {
SIMPLEQ_HEAD(, twe_ccb) sc_ccb_queue;
SLIST_HEAD(, twe_ccb) sc_ccb_freelist;
int sc_flags;
+ int sc_openings;
int sc_nunits;
struct twe_drive sc_units[TWE_MAX_UNITS];
@@ -128,6 +135,9 @@ int twe_param_get_1(struct twe_softc *, int, int, uint8_t *);
int twe_param_get_2(struct twe_softc *, int, int, uint16_t *);
int twe_param_get_4(struct twe_softc *, int, int, uint32_t *);
+void twe_register_callbacks(struct twe_softc *, int,
+ const struct twe_callbacks *);
+
static __inline__ size_t twe_get_maxsegs(void) {
size_t max_segs = ((MAXPHYS + PAGE_SIZE - 1) / PAGE_SIZE) + 1;
#ifdef TWE_SG_SIZE