Author: mav
Date: Thu Mar 24 19:23:42 2011
New Revision: 219970
URL: http://svn.freebsd.org/changeset/base/219970

Log:
  MFgraid/head r218212, r218257:
  Introduce new type of BIO_GETATTR -- GEOM::setstate, used to inform lower
  GEOM about state of it's providers from the point of upper layers.
  Make geom_disk use led(4) subsystem to illuminate states in such fashion:
  FAILED - "1" (on), REBUILD - "f5" (slow blink), RESYNC - "f1" (fast blink),
  ACTIVE - "0" (off).
  LED name should be set for each disk via kern.geom.disk.%s.led sysctl.
  Later disk API could be extended to allow disk driver to report this info
  in custom way via it's own facilities.

Modified:
  head/sys/geom/geom.h
  head/sys/geom/geom_disk.c

Modified: head/sys/geom/geom.h
==============================================================================
--- head/sys/geom/geom.h        Thu Mar 24 19:11:05 2011        (r219969)
+++ head/sys/geom/geom.h        Thu Mar 24 19:23:42 2011        (r219970)
@@ -208,6 +208,12 @@ struct g_classifier_hook {
        void                    *arg;
 };
 
+/* BIO_GETATTR("GEOM::setstate") argument values. */
+#define G_STATE_FAILED         0
+#define G_STATE_REBUILD                1
+#define G_STATE_RESYNC         2
+#define G_STATE_ACTIVE         3
+
 /* geom_dev.c */
 struct cdev;
 void g_dev_print(void);

Modified: head/sys/geom/geom_disk.c
==============================================================================
--- head/sys/geom/geom_disk.c   Thu Mar 24 19:11:05 2011        (r219969)
+++ head/sys/geom/geom_disk.c   Thu Mar 24 19:23:42 2011        (r219970)
@@ -56,6 +56,16 @@ __FBSDID("$FreeBSD$");
 #include <geom/geom_disk.h>
 #include <geom/geom_int.h>
 
+#include <dev/led/led.h>
+
+struct g_disk_softc {
+       struct disk             *dp;
+       struct sysctl_ctx_list  sysctl_ctx;
+       struct sysctl_oid       *sysctl_tree;
+       char                    led[64];
+       uint32_t                state;
+};
+
 static struct mtx g_disk_done_mtx;
 
 static g_access_t g_disk_access;
@@ -76,6 +86,9 @@ static struct g_class g_disk_class = {
        .dumpconf = g_disk_dumpconf,
 };
 
+SYSCTL_DECL(_kern_geom);
+SYSCTL_NODE(_kern_geom, OID_AUTO, disk, CTLFLAG_RW, 0, "GEOM_DISK stuff");
+
 static void
 g_disk_init(struct g_class *mp __unused)
 {
@@ -110,13 +123,14 @@ static int
 g_disk_access(struct g_provider *pp, int r, int w, int e)
 {
        struct disk *dp;
+       struct g_disk_softc *sc;
        int error;
 
        g_trace(G_T_ACCESS, "g_disk_access(%s, %d, %d, %d)",
            pp->name, r, w, e);
        g_topology_assert();
-       dp = pp->geom->softc;
-       if (dp == NULL || dp->d_destroyed) {
+       sc = pp->geom->softc;
+       if (sc == NULL || (dp = sc->dp) == NULL || dp->d_destroyed) {
                /*
                 * Allow decreasing access count even if disk is not
                 * avaliable anymore.
@@ -155,6 +169,9 @@ g_disk_access(struct g_provider *pp, int
                                    pp->name, error);
                        g_disk_unlock_giant(dp);
                }
+               sc->state = G_STATE_ACTIVE;
+               if (sc->led[0] != 0)
+                       led_set(sc->led, "0");
                dp->d_flags &= ~DISKFLAG_OPEN;
        }
        return (error);
@@ -186,10 +203,37 @@ g_disk_kerneldump(struct bio *bp, struct
 }
 
 static void
+g_disk_setstate(struct bio *bp, struct g_disk_softc *sc)
+{
+       const char *cmd;
+
+       memcpy(&sc->state, bp->bio_data, sizeof(sc->state));
+       if (sc->led[0] != 0) {
+               switch (sc->state) {
+               case G_STATE_FAILED:
+                       cmd = "1";
+                       break;
+               case G_STATE_REBUILD:
+                       cmd = "f5";
+                       break;
+               case G_STATE_RESYNC:
+                       cmd = "f1";
+                       break;
+               default:
+                       cmd = "0";
+                       break;
+               }
+               led_set(sc->led, cmd);
+       }
+       g_io_deliver(bp, 0);
+}
+
+static void
 g_disk_done(struct bio *bp)
 {
        struct bio *bp2;
        struct disk *dp;
+       struct g_disk_softc *sc;
 
        /* See "notes" for why we need a mutex here */
        /* XXX: will witness accept a mix of Giant/unGiant drivers here ? */
@@ -201,7 +245,8 @@ g_disk_done(struct bio *bp)
                bp2->bio_error = bp->bio_error;
        bp2->bio_completed += bp->bio_completed;
        if ((bp->bio_cmd & (BIO_READ|BIO_WRITE|BIO_DELETE)) &&
-           (dp = bp2->bio_to->geom->softc)) {
+           (sc = bp2->bio_to->geom->softc) &&
+           (dp = sc->dp)) {
                devstat_end_transaction_bio(dp->d_devstat, bp);
        }
        g_destroy_bio(bp);
@@ -218,10 +263,12 @@ g_disk_ioctl(struct g_provider *pp, u_lo
 {
        struct g_geom *gp;
        struct disk *dp;
+       struct g_disk_softc *sc;
        int error;
 
        gp = pp->geom;
-       dp = gp->softc;
+       sc = gp->softc;
+       dp = sc->dp;
 
        if (dp->d_ioctl == NULL)
                return (ENOIOCTL);
@@ -236,11 +283,12 @@ g_disk_start(struct bio *bp)
 {
        struct bio *bp2, *bp3;
        struct disk *dp;
+       struct g_disk_softc *sc;
        int error;
        off_t off;
 
-       dp = bp->bio_to->geom->softc;
-       if (dp == NULL || dp->d_destroyed) {
+       sc = bp->bio_to->geom->softc;
+       if (sc == NULL || (dp = sc->dp) == NULL || dp->d_destroyed) {
                g_io_deliver(bp, ENXIO);
                return;
        }
@@ -319,6 +367,8 @@ g_disk_start(struct bio *bp)
                        break;
                else if (!strcmp(bp->bio_attribute, "GEOM::kerneldump"))
                        g_disk_kerneldump(bp, dp);
+               else if (!strcmp(bp->bio_attribute, "GEOM::setstate"))
+                       g_disk_setstate(bp, sc);
                else 
                        error = ENOIOCTL;
                break;
@@ -353,9 +403,10 @@ static void
 g_disk_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct 
g_consumer *cp, struct g_provider *pp)
 {
        struct disk *dp;
+       struct g_disk_softc *sc;
 
-       dp = gp->softc;
-       if (dp == NULL)
+       sc = gp->softc;
+       if (sc == NULL || (dp = sc->dp) == NULL)
                return;
        if (indent == NULL) {
                sbuf_printf(sb, " hd %u", dp->d_fwheads);
@@ -378,13 +429,17 @@ g_disk_create(void *arg, int flag)
        struct g_geom *gp;
        struct g_provider *pp;
        struct disk *dp;
+       struct g_disk_softc *sc;
+       char tmpstr[80];
 
        if (flag == EV_CANCEL)
                return;
        g_topology_assert();
        dp = arg;
+       sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO);
+       sc->dp = dp;
        gp = g_new_geomf(&g_disk_class, "%s%d", dp->d_name, dp->d_unit);
-       gp->softc = dp;
+       gp->softc = sc;
        pp = g_new_providerf(gp, "%s", gp->name);
        pp->mediasize = dp->d_mediasize;
        pp->sectorsize = dp->d_sectorsize;
@@ -394,6 +449,21 @@ g_disk_create(void *arg, int flag)
        pp->stripesize = dp->d_stripesize;
        if (bootverbose)
                printf("GEOM: new disk %s\n", gp->name);
+       sysctl_ctx_init(&sc->sysctl_ctx);
+       snprintf(tmpstr, sizeof(tmpstr), "GEOM disk %s", gp->name);
+       sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
+               SYSCTL_STATIC_CHILDREN(_kern_geom_disk), OID_AUTO, gp->name,
+               CTLFLAG_RD, 0, tmpstr);
+       if (sc->sysctl_tree != NULL) {
+               snprintf(tmpstr, sizeof(tmpstr),
+                   "kern.geom.disk.%s.led", gp->name);
+               TUNABLE_STR_FETCH(tmpstr, sc->led, sizeof(sc->led));
+               SYSCTL_ADD_STRING(&sc->sysctl_ctx,
+                   SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "led",
+                   CTLFLAG_RW | CTLFLAG_TUN, sc->led, sizeof(sc->led),
+                   "LED name");
+       }
+       pp->private = sc;
        dp->d_geom = gp;
        g_error_provider(pp, 0);
 }
@@ -403,11 +473,22 @@ g_disk_destroy(void *ptr, int flag)
 {
        struct disk *dp;
        struct g_geom *gp;
+       struct g_disk_softc *sc;
 
        g_topology_assert();
        dp = ptr;
        gp = dp->d_geom;
        if (gp != NULL) {
+               sc = gp->softc;
+               if (sc->sysctl_tree != NULL) {
+                       sysctl_ctx_free(&sc->sysctl_ctx);
+                       sc->sysctl_tree = NULL;
+               }
+               if (sc->led[0] != 0) {
+                       led_set(sc->led, "0");
+                       sc->led[0] = 0;
+               }
+               g_free(sc);
                gp->softc = NULL;
                g_wither_geom(gp, ENXIO);
        }
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to