Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/ata Minimal support for mirror component. The relat...



details:   https://anonhg.NetBSD.org/src/rev/c9f8b32943b8
branches:  trunk
changeset: 570019:c9f8b32943b8
user:      enami <enami%NetBSD.org@localhost>
date:      Fri Sep 17 23:21:53 2004 +0000

description:
Minimal support for mirror component.  The relation between original and
mirror component learned from FreeBSD driver.

diffstat:

 sys/dev/ata/ld_ataraid.c |  123 ++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 112 insertions(+), 11 deletions(-)

diffs (217 lines):

diff -r c547bd37ccca -r c9f8b32943b8 sys/dev/ata/ld_ataraid.c
--- a/sys/dev/ata/ld_ataraid.c  Fri Sep 17 23:20:21 2004 +0000
+++ b/sys/dev/ata/ld_ataraid.c  Fri Sep 17 23:21:53 2004 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ld_ataraid.c,v 1.11 2004/04/22 00:17:10 itojun Exp $   */
+/*     $NetBSD: ld_ataraid.c,v 1.12 2004/09/17 23:21:53 enami Exp $    */
 
 /*
  * Copyright (c) 2003 Wasabi Systems, Inc.
@@ -45,7 +45,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ld_ataraid.c,v 1.11 2004/04/22 00:17:10 itojun Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ld_ataraid.c,v 1.12 2004/09/17 23:21:53 enami Exp $");
 
 #include "rnd.h"
 
@@ -102,6 +102,9 @@
        struct ld_ataraid_softc *cb_sc; /* pointer to ld softc */
        u_int           cb_comp;        /* target component */
        SIMPLEQ_ENTRY(cbuf) cb_q;       /* fifo of component buffers */
+       struct cbuf     *cb_other;      /* other cbuf in case of mirror */
+       int             cb_flags;
+#define        CBUF_IODONE     0x00000001      /* I/O is already successfully done */
 };
 
 #define        CBUF_GET()      pool_get(&ld_ataraid_cbufpl, PR_NOWAIT);
@@ -154,10 +157,14 @@
 
        case AAI_L_RAID1:
                level = "RAID-1";
+               ld->sc_start = ld_ataraid_start_raid0;
+               sc->sc_iodone = ld_ataraid_iodone_raid0;
                break;
 
        case AAI_L_RAID0 | AAI_L_RAID1:
                level = "RAID-10";
+               ld->sc_start = ld_ataraid_start_raid0;
+               sc->sc_iodone = ld_ataraid_iodone_raid0;
                break;
 
        default:
@@ -248,6 +255,8 @@
        cbp->cb_obp = bp;
        cbp->cb_sc = sc;
        cbp->cb_comp = comp;
+       cbp->cb_other = NULL;
+       cbp->cb_flags = 0;
 
        return (cbp);
 }
@@ -322,12 +331,16 @@
 {
        struct ld_ataraid_softc *sc = (void *) ld;
        struct ataraid_array_info *aai = sc->sc_aai;
+       struct ataraid_disk_info *adi;
        SIMPLEQ_HEAD(, cbuf) cbufq;
-       struct cbuf *cbp;
+       struct cbuf *cbp, *other_cbp;
        caddr_t addr;
        daddr_t bn, cbn, tbn, off;
        long bcount, rcount;
        u_int comp;
+       const int read = bp->b_flags & B_READ;
+       const int mirror = aai->aai_level & AAI_L_RAID1;
+       int error;
 
        /* Allocate component buffers. */
        SIMPLEQ_INIT(&cbufq);
@@ -357,16 +370,50 @@
                        rcount = min(bcount, dbtob(aai->aai_interleave - off));
                }
 
+               /*
+                * See if a component is valid.
+                */
+try_mirror:
+               adi = &aai->aai_disks[comp];
+               if ((adi->adi_status & ADI_S_ONLINE) == 0) {
+                       if (mirror && comp < aai->aai_width) {
+                               comp += aai->aai_width;
+                               goto try_mirror;
+                       }
+
+                       /*
+                        * No component available.
+                        */
+                       error = EIO;
+                       goto free_and_exit;
+               }
+
                cbp = ld_ataraid_make_cbuf(sc, bp, comp, cbn, addr, rcount);
                if (cbp == NULL) {
+resource_shortage:
+                       error = EAGAIN;
+free_and_exit:
                        /* Free the already allocated component buffers. */
                        while ((cbp = SIMPLEQ_FIRST(&cbufq)) != NULL) {
                                SIMPLEQ_REMOVE_HEAD(&cbufq, cb_q);
                                CBUF_PUT(cbp);
                        }
-                       return (EAGAIN);
+                       return (error);
                }
                SIMPLEQ_INSERT_TAIL(&cbufq, cbp, cb_q);
+               if (mirror && !read && comp < aai->aai_width) {
+                       comp += aai->aai_width;
+                       adi = &aai->aai_disks[comp];
+                       if (adi->adi_status & ADI_S_ONLINE) {
+                               other_cbp = ld_ataraid_make_cbuf(sc, bp,
+                                   comp, cbn, addr, rcount);
+                               if (other_cbp == NULL)
+                                       goto resource_shortage;
+                               SIMPLEQ_INSERT_TAIL(&cbufq, other_cbp, cb_q);
+                               other_cbp->cb_other = cbp;
+                               cbp->cb_other = other_cbp;
+                       }
+               }
                bn += btodb(rcount);
                addr += rcount;
        }
@@ -389,33 +436,87 @@
 static void
 ld_ataraid_iodone_raid0(struct buf *vbp)
 {
-       struct cbuf *cbp = (struct cbuf *) vbp;
+       struct cbuf *cbp = (struct cbuf *) vbp, *other_cbp;
        struct buf *bp = cbp->cb_obp;
        struct ld_ataraid_softc *sc = cbp->cb_sc;
+       struct ataraid_array_info *aai = sc->sc_aai;
+       struct ataraid_disk_info *adi;
        long count;
-       int s;
+       int s, iodone;
 
        s = splbio();
 
+       iodone = cbp->cb_flags & CBUF_IODONE;
+       other_cbp = cbp->cb_other;
+       if (other_cbp != NULL)
+               /* You are alone */
+               other_cbp->cb_other = NULL;
+
        if (cbp->cb_buf.b_flags & B_ERROR) {
-               bp->b_flags |= B_ERROR;
-               bp->b_error = cbp->cb_buf.b_error ?
-                   cbp->cb_buf.b_error : EIO;
+               /*
+                * Mark this component broken.
+                */
+               adi = &aai->aai_disks[cbp->cb_comp];
+               adi->adi_status &= ~ADI_S_ONLINE;
+
+               printf("%s: error %d on component %d (%s)\n",
+                   sc->sc_ld.sc_dv.dv_xname, bp->b_error, cbp->cb_comp,
+                   adi->adi_dev->dv_xname);
+
+               /*
+                * If we didn't see an error yet and we are reading
+                * RAID1 disk, try another component.
+                */
+               if ((bp->b_flags & B_ERROR) == 0 &&
+                   (cbp->cb_buf.b_flags & B_READ) != 0 &&
+                   (aai->aai_level & AAI_L_RAID1) != 0 &&
+                   cbp->cb_comp < aai->aai_width) {
+                       cbp->cb_comp += aai->aai_width;
+                       adi = &aai->aai_disks[cbp->cb_comp];
+                       if (adi->adi_status & ADI_S_ONLINE) {
+                               cbp->cb_buf.b_flags &= ~B_ERROR;
+                               VOP_STRATEGY(cbp->cb_buf.b_vp, &cbp->cb_buf);
+                               goto out;
+                       }
+               }
+
+               if (iodone || other_cbp != NULL)
+                       /*
+                        * If I/O on other component successfully done
+                        * or the I/O is still in progress, no need
+                        * to tell an error to upper layer.
+                        */
+                       ;
+               else {
+                       bp->b_flags |= B_ERROR;
+                       bp->b_error = cbp->cb_buf.b_error ?
+                           cbp->cb_buf.b_error : EIO;
+               }
 
                /* XXX Update component config blocks. */
 
-               printf("%s: error %d on component %d\n",
-                   sc->sc_ld.sc_dv.dv_xname, bp->b_error, cbp->cb_comp);
+       } else {
+               /*
+                * If other I/O is still in progress, tell it that
+                * our I/O is successfully done.
+                */
+               if (other_cbp != NULL)
+                       other_cbp->cb_flags |= CBUF_IODONE;
        }
        count = cbp->cb_buf.b_bcount;
        CBUF_PUT(cbp);
 
+       if (other_cbp != NULL)
+               goto out;
+
        /* If all done, "interrupt". */
        bp->b_resid -= count;
        if (bp->b_resid < 0)
                panic("ld_ataraid_iodone_raid0: count");
        if (bp->b_resid == 0)
                lddone(&sc->sc_ld, bp);
+
+out:
        splx(s);
 }
 



Home | Main Index | Thread Index | Old Index