The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ata/ld_ataraid.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: ld_ataraid.c,v 1.10 2004/01/25 18:06:48 hannken Exp $  */
    2 
    3 /*
    4  * Copyright (c) 2003 Wasabi Systems, Inc.
    5  * All rights reserved.
    6  *
    7  * Written by Jason R. Thorpe for Wasabi Systems, Inc.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. All advertising materials mentioning features or use of this software
   18  *    must display the following acknowledgement:
   19  *      This product includes software developed for the NetBSD Project by
   20  *      Wasabi Systems, Inc.
   21  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
   22  *    or promote products derived from this software without specific prior
   23  *    written permission.
   24  *
   25  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
   26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
   29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   35  * POSSIBILITY OF SUCH DAMAGE.
   36  */
   37 
   38 /*
   39  * Support for ATA RAID logical disks.
   40  *
   41  * Note that all the RAID happens in software here; the ATA RAID
   42  * controllers we're dealing with (Promise, etc.) only support
   43  * configuration data on the component disks, with the BIOS supporting
   44  * booting from the RAID volumes.
   45  */
   46 
   47 #include <sys/cdefs.h>
   48 __KERNEL_RCSID(0, "$NetBSD: ld_ataraid.c,v 1.10 2004/01/25 18:06:48 hannken Exp $");
   49 
   50 #include "rnd.h"
   51 
   52 #include <sys/param.h>
   53 #include <sys/systm.h>
   54 #include <sys/conf.h>
   55 #include <sys/kernel.h>
   56 #include <sys/device.h>
   57 #include <sys/buf.h>
   58 #include <sys/dkio.h>
   59 #include <sys/disk.h>
   60 #include <sys/disklabel.h>
   61 #include <sys/fcntl.h>
   62 #include <sys/malloc.h>
   63 #include <sys/vnode.h>
   64 #if NRND > 0
   65 #include <sys/rnd.h>
   66 #endif
   67 
   68 #include <miscfs/specfs/specdev.h>
   69 
   70 #include <dev/ldvar.h>
   71 
   72 #include <dev/ata/ata_raidvar.h>
   73 
   74 struct ld_ataraid_softc {
   75         struct ld_softc sc_ld;
   76 
   77         struct ataraid_array_info *sc_aai;
   78         struct vnode *sc_vnodes[ATA_RAID_MAX_DISKS];
   79 
   80         void    (*sc_iodone)(struct buf *);
   81 };
   82 
   83 static int      ld_ataraid_match(struct device *, struct cfdata *, void *);
   84 static void     ld_ataraid_attach(struct device *, struct device *, void *);
   85 
   86 static int      ld_ataraid_dump(struct ld_softc *, void *, int, int);
   87 
   88 static int      ld_ataraid_start_span(struct ld_softc *, struct buf *);
   89 
   90 static int      ld_ataraid_start_raid0(struct ld_softc *, struct buf *);
   91 static void     ld_ataraid_iodone_raid0(struct buf *);
   92 
   93 CFATTACH_DECL(ld_ataraid, sizeof(struct ld_ataraid_softc),
   94     ld_ataraid_match, ld_ataraid_attach, NULL, NULL);
   95 
   96 static int ld_ataraid_initialized;
   97 static struct pool ld_ataraid_cbufpl;
   98 
   99 struct cbuf {
  100         struct buf      cb_buf;         /* new I/O buf */
  101         struct buf      *cb_obp;        /* ptr. to original I/O buf */
  102         struct ld_ataraid_softc *cb_sc; /* pointer to ld softc */
  103         u_int           cb_comp;        /* target component */
  104         SIMPLEQ_ENTRY(cbuf) cb_q;       /* fifo of component buffers */
  105 };
  106 
  107 #define CBUF_GET()      pool_get(&ld_ataraid_cbufpl, PR_NOWAIT);
  108 #define CBUF_PUT(cbp)   pool_put(&ld_ataraid_cbufpl, (cbp))
  109 
  110 static int
  111 ld_ataraid_match(struct device *parent, struct cfdata *match, void *aux)
  112 {
  113 
  114         return (1);
  115 }
  116 
  117 static void
  118 ld_ataraid_attach(struct device *parent, struct device *self, void *aux)
  119 {
  120         struct ld_ataraid_softc *sc = (void *) self;
  121         struct ld_softc *ld = &sc->sc_ld;
  122         struct ataraid_array_info *aai = aux;
  123         const char *level;
  124         struct vnode *vp;
  125         char unklev[32];
  126         u_int i;
  127 
  128         if (ld_ataraid_initialized == 0) {
  129                 ld_ataraid_initialized = 1;
  130                 pool_init(&ld_ataraid_cbufpl, sizeof(struct cbuf), 0,
  131                     0, 0, "ldcbuf", NULL);
  132         }
  133 
  134         sc->sc_aai = aai;       /* this data persists */
  135 
  136         ld->sc_maxxfer = MAXPHYS * aai->aai_width;      /* XXX */
  137         ld->sc_secperunit = aai->aai_capacity;
  138         ld->sc_secsize = 512;                           /* XXX */
  139         ld->sc_maxqueuecnt = 128;                       /* XXX */
  140         ld->sc_dump = ld_ataraid_dump;
  141 
  142         switch (aai->aai_level) {
  143         case AAI_L_SPAN:
  144                 level = "SPAN";
  145                 ld->sc_start = ld_ataraid_start_span;
  146                 sc->sc_iodone = ld_ataraid_iodone_raid0;
  147                 break;
  148 
  149         case AAI_L_RAID0:
  150                 level = "RAID-0";
  151                 ld->sc_start = ld_ataraid_start_raid0;
  152                 sc->sc_iodone = ld_ataraid_iodone_raid0;
  153                 break;
  154 
  155         case AAI_L_RAID1:
  156                 level = "RAID-1";
  157                 break;
  158 
  159         case AAI_L_RAID0 | AAI_L_RAID1:
  160                 level = "RAID-10";
  161                 break;
  162 
  163         default:
  164                 sprintf(unklev, "<unknown level 0x%x>", aai->aai_level);
  165                 level = unklev;
  166         }
  167 
  168         aprint_naive(": ATA %s array\n", level);
  169         aprint_normal(": %s ATA %s array\n",
  170             ata_raid_type_name(aai->aai_type), level);
  171 
  172         if (ld->sc_start == NULL) {
  173                 aprint_error("%s: unsupported array type\n",
  174                     ld->sc_dv.dv_xname);
  175                 return;
  176         }
  177 
  178         /*
  179          * We get a geometry from the device; use it.
  180          */
  181         ld->sc_nheads = aai->aai_heads;
  182         ld->sc_nsectors = aai->aai_sectors;
  183         ld->sc_ncylinders = aai->aai_cylinders;
  184 
  185         /*
  186          * Configure all the component disks.
  187          */
  188         for (i = 0; i < aai->aai_ndisks; i++) {
  189                 struct ataraid_disk_info *adi = &aai->aai_disks[i];
  190                 int bmajor, error;
  191                 dev_t dev;
  192 
  193                 bmajor = devsw_name2blk(adi->adi_dev->dv_xname, NULL, 0);
  194                 dev = MAKEDISKDEV(bmajor, adi->adi_dev->dv_unit, RAW_PART);
  195                 error = bdevvp(dev, &vp);
  196                 if (error)
  197                         break;
  198                 error = VOP_OPEN(vp, FREAD|FWRITE, NOCRED, 0);
  199                 if (error) {
  200                         vput(vp);
  201                         /*
  202                          * XXX This is bogus.  We should just mark the
  203                          * XXX component as FAILED, and write-back new
  204                          * XXX config blocks.
  205                          */
  206                         break;
  207                 }
  208 
  209                 VOP_UNLOCK(vp, 0);
  210                 sc->sc_vnodes[i] = vp;
  211         }
  212         if (i == aai->aai_ndisks) {
  213                 ld->sc_flags = LDF_ENABLED;
  214                 goto finish;
  215         }
  216 
  217         for (i = 0; i < aai->aai_ndisks; i++) {
  218                 vp = sc->sc_vnodes[i];
  219                 sc->sc_vnodes[i] = NULL;
  220                 if (vp != NULL)
  221                         (void) vn_close(vp, FREAD|FWRITE, NOCRED, curproc);
  222         }
  223 
  224  finish:
  225         ldattach(ld);
  226 }
  227 
  228 static struct cbuf *
  229 ld_ataraid_make_cbuf(struct ld_ataraid_softc *sc, struct buf *bp,
  230     u_int comp, daddr_t bn, caddr_t addr, long bcount)
  231 {
  232         struct cbuf *cbp;
  233 
  234         cbp = CBUF_GET();
  235         if (cbp == NULL)
  236                 return (NULL);
  237         BUF_INIT(&cbp->cb_buf);
  238         cbp->cb_buf.b_flags = bp->b_flags | B_CALL;
  239         cbp->cb_buf.b_iodone = sc->sc_iodone;
  240         cbp->cb_buf.b_proc = bp->b_proc;
  241         cbp->cb_buf.b_vp = sc->sc_vnodes[comp];
  242         cbp->cb_buf.b_blkno = bn + sc->sc_aai->aai_offset;
  243         cbp->cb_buf.b_data = addr;
  244         cbp->cb_buf.b_bcount = bcount;
  245 
  246         /* Context for iodone */
  247         cbp->cb_obp = bp;
  248         cbp->cb_sc = sc;
  249         cbp->cb_comp = comp;
  250 
  251         return (cbp);
  252 }
  253 
  254 static int
  255 ld_ataraid_start_span(struct ld_softc *ld, struct buf *bp)
  256 {
  257         struct ld_ataraid_softc *sc = (void *) ld;
  258         struct ataraid_array_info *aai = sc->sc_aai;
  259         struct ataraid_disk_info *adi;
  260         SIMPLEQ_HEAD(, cbuf) cbufq;
  261         struct cbuf *cbp;
  262         caddr_t addr;
  263         daddr_t bn;
  264         long bcount, rcount;
  265         u_int comp;
  266 
  267         /* Allocate component buffers. */
  268         SIMPLEQ_INIT(&cbufq);
  269         addr = bp->b_data;
  270 
  271         /* Find the first component. */
  272         comp = 0;
  273         adi = &aai->aai_disks[comp];
  274         bn = bp->b_rawblkno;
  275         while (bn >= adi->adi_compsize) {
  276                 bn -= adi->adi_compsize;
  277                 adi = &aai->aai_disks[++comp];
  278         }
  279 
  280         bp->b_resid = bp->b_bcount;
  281 
  282         for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) {
  283                 rcount = bp->b_bcount;
  284                 if ((adi->adi_compsize - bn) < btodb(rcount))
  285                         rcount = dbtob(adi->adi_compsize - bn);
  286 
  287                 cbp = ld_ataraid_make_cbuf(sc, bp, comp, bn, addr, rcount);
  288                 if (cbp == NULL) {
  289                         /* Free the already allocated component buffers. */
  290                         while ((cbp = SIMPLEQ_FIRST(&cbufq)) != NULL) {
  291                                 SIMPLEQ_REMOVE_HEAD(&cbufq, cb_q);
  292                                 CBUF_PUT(cbp);
  293                         }
  294                         return (EAGAIN);
  295                 }
  296 
  297                 /*
  298                  * For a span, we always know we advance to the next disk,
  299                  * and always start at offset 0 on that disk.
  300                  */
  301                 adi = &aai->aai_disks[++comp];
  302                 bn = 0;
  303 
  304                 SIMPLEQ_INSERT_TAIL(&cbufq, cbp, cb_q);
  305                 addr += rcount;
  306         }
  307 
  308         /* Now fire off the requests. */
  309         while ((cbp = SIMPLEQ_FIRST(&cbufq)) != NULL) {
  310                 SIMPLEQ_REMOVE_HEAD(&cbufq, cb_q);
  311                 if ((cbp->cb_buf.b_flags & B_READ) == 0)
  312                         cbp->cb_buf.b_vp->v_numoutput++;
  313                 VOP_STRATEGY(cbp->cb_buf.b_vp, &cbp->cb_buf);
  314         }
  315 
  316         return (0);
  317 }
  318 
  319 static int
  320 ld_ataraid_start_raid0(struct ld_softc *ld, struct buf *bp)
  321 {
  322         struct ld_ataraid_softc *sc = (void *) ld;
  323         struct ataraid_array_info *aai = sc->sc_aai;
  324         SIMPLEQ_HEAD(, cbuf) cbufq;
  325         struct cbuf *cbp;
  326         caddr_t addr;
  327         daddr_t bn, cbn, tbn, off;
  328         long bcount, rcount;
  329         u_int comp;
  330 
  331         /* Allocate component buffers. */
  332         SIMPLEQ_INIT(&cbufq);
  333         addr = bp->b_data;
  334         bn = bp->b_rawblkno;
  335 
  336         bp->b_resid = bp->b_bcount;
  337 
  338         for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) {
  339                 tbn = bn / aai->aai_interleave;
  340                 off = bn % aai->aai_interleave;
  341 
  342                 if (__predict_false(tbn == aai->aai_capacity /
  343                                            aai->aai_interleave)) {
  344                         /* Last stripe. */
  345                         daddr_t sz = (aai->aai_capacity -
  346                                       (tbn * aai->aai_interleave)) /
  347                                      aai->aai_width;
  348                         comp = off / sz;
  349                         cbn = ((tbn / aai->aai_width) * aai->aai_interleave) +
  350                             (off % sz);
  351                         rcount = min(bcount, dbtob(sz));
  352                 } else {
  353                         comp = tbn % aai->aai_width;
  354                         cbn = ((tbn / aai->aai_width) * aai->aai_interleave) +
  355                             off;
  356                         rcount = min(bcount, dbtob(aai->aai_interleave - off));
  357                 }
  358 
  359                 cbp = ld_ataraid_make_cbuf(sc, bp, comp, cbn, addr, rcount);
  360                 if (cbp == NULL) {
  361                         /* Free the already allocated component buffers. */
  362                         while ((cbp = SIMPLEQ_FIRST(&cbufq)) != NULL) {
  363                                 SIMPLEQ_REMOVE_HEAD(&cbufq, cb_q);
  364                                 CBUF_PUT(cbp);
  365                         }
  366                         return (EAGAIN);
  367                 }
  368                 SIMPLEQ_INSERT_TAIL(&cbufq, cbp, cb_q);
  369                 bn += btodb(rcount);
  370                 addr += rcount;
  371         }
  372 
  373         /* Now fire off the requests. */
  374         while ((cbp = SIMPLEQ_FIRST(&cbufq)) != NULL) {
  375                 SIMPLEQ_REMOVE_HEAD(&cbufq, cb_q);
  376                 if ((cbp->cb_buf.b_flags & B_READ) == 0)
  377                         cbp->cb_buf.b_vp->v_numoutput++;
  378                 VOP_STRATEGY(cbp->cb_buf.b_vp, &cbp->cb_buf);
  379         }
  380 
  381         return (0);
  382 }
  383 
  384 /*
  385  * Called at interrupt time.  Mark the component as done and if all
  386  * components are done, take an "interrupt".
  387  */
  388 static void
  389 ld_ataraid_iodone_raid0(struct buf *vbp)
  390 {
  391         struct cbuf *cbp = (struct cbuf *) vbp;
  392         struct buf *bp = cbp->cb_obp;
  393         struct ld_ataraid_softc *sc = cbp->cb_sc;
  394         long count;
  395         int s;
  396 
  397         s = splbio();
  398 
  399         if (cbp->cb_buf.b_flags & B_ERROR) {
  400                 bp->b_flags |= B_ERROR;
  401                 bp->b_error = cbp->cb_buf.b_error ?
  402                     cbp->cb_buf.b_error : EIO;
  403 
  404                 /* XXX Update component config blocks. */
  405 
  406                 printf("%s: error %d on component %d\n",
  407                     sc->sc_ld.sc_dv.dv_xname, bp->b_error, cbp->cb_comp);
  408         }
  409         count = cbp->cb_buf.b_bcount;
  410         CBUF_PUT(cbp);
  411 
  412         /* If all done, "interrupt". */
  413         bp->b_resid -= count;
  414         if (bp->b_resid < 0)
  415                 panic("ld_ataraid_iodone_raid0: count");
  416         if (bp->b_resid == 0)
  417                 lddone(&sc->sc_ld, bp);
  418         splx(s);
  419 }
  420 
  421 static int
  422 ld_ataraid_dump(struct ld_softc *sc, void *data, int blkno, int blkcnt)
  423 {
  424 
  425         return (EIO);
  426 }

Cache object: 4ae5a11afea4599dc9517c522cc9720b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.