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/softraid_raid0.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /* $OpenBSD: softraid_raid0.c,v 1.11 2008/11/25 23:05:17 marco Exp $ */
    2 /*
    3  * Copyright (c) 2008 Marco Peereboom <marco@peereboom.us>
    4  *
    5  * Permission to use, copy, modify, and distribute this software for any
    6  * purpose with or without fee is hereby granted, provided that the above
    7  * copyright notice and this permission notice appear in all copies.
    8  *
    9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   16  */
   17 
   18 #include "bio.h"
   19 
   20 #include <sys/param.h>
   21 #include <sys/systm.h>
   22 #include <sys/buf.h>
   23 #include <sys/device.h>
   24 #include <sys/ioctl.h>
   25 #include <sys/proc.h>
   26 #include <sys/malloc.h>
   27 #include <sys/kernel.h>
   28 #include <sys/disk.h>
   29 #include <sys/rwlock.h>
   30 #include <sys/queue.h>
   31 #include <sys/fcntl.h>
   32 #include <sys/disklabel.h>
   33 #include <sys/mount.h>
   34 #include <sys/sensors.h>
   35 #include <sys/stat.h>
   36 #include <sys/conf.h>
   37 #include <sys/uio.h>
   38 
   39 #include <scsi/scsi_all.h>
   40 #include <scsi/scsiconf.h>
   41 #include <scsi/scsi_disk.h>
   42 
   43 #include <dev/softraidvar.h>
   44 #include <dev/rndvar.h>
   45 
   46 /* RAID 0 functions */
   47 int
   48 sr_raid0_alloc_resources(struct sr_discipline *sd)
   49 {
   50         int                     rv = EINVAL;
   51 
   52         if (!sd)
   53                 return (rv);
   54 
   55         DNPRINTF(SR_D_DIS, "%s: sr_raid0_alloc_resources\n",
   56             DEVNAME(sd->sd_sc));
   57 
   58         if (sr_wu_alloc(sd))
   59                 goto bad;
   60         if (sr_ccb_alloc(sd))
   61                 goto bad;
   62 
   63         /* setup runtime values */
   64         sd->mds.mdd_raid0.sr0_strip_bits =
   65             sr_validate_stripsize(sd->sd_meta->ssdi.ssd_strip_size);
   66         if (sd->mds.mdd_raid0.sr0_strip_bits == -1)
   67                 goto bad;
   68 
   69         rv = 0;
   70 bad:
   71         return (rv);
   72 }
   73 
   74 int
   75 sr_raid0_free_resources(struct sr_discipline *sd)
   76 {
   77         int                     rv = EINVAL;
   78 
   79         if (!sd)
   80                 return (rv);
   81 
   82         DNPRINTF(SR_D_DIS, "%s: sr_raid0_free_resources\n",
   83             DEVNAME(sd->sd_sc));
   84 
   85         sr_wu_free(sd);
   86         sr_ccb_free(sd);
   87 
   88         rv = 0;
   89         return (rv);
   90 }
   91 
   92 void
   93 sr_raid0_set_chunk_state(struct sr_discipline *sd, int c, int new_state)
   94 {
   95         int                     old_state, s;
   96 
   97         DNPRINTF(SR_D_STATE, "%s: %s: %s: sr_raid_set_chunk_state %d -> %d\n",
   98             DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname,
   99             sd->sd_vol.sv_chunks[c]->src_meta.scmi.scm_devname, c, new_state);
  100 
  101         /* ok to go to splbio since this only happens in error path */
  102         s = splbio();
  103         old_state = sd->sd_vol.sv_chunks[c]->src_meta.scm_status;
  104 
  105         /* multiple IOs to the same chunk that fail will come through here */
  106         if (old_state == new_state)
  107                 goto done;
  108 
  109         switch (old_state) {
  110         case BIOC_SDONLINE:
  111                 if (new_state == BIOC_SDOFFLINE)
  112                         break;
  113                 else
  114                         goto die;
  115                 break;
  116 
  117         case BIOC_SDOFFLINE:
  118                 goto die;
  119 
  120         default:
  121 die:
  122                 splx(s); /* XXX */
  123                 panic("%s: %s: %s: invalid chunk state transition "
  124                     "%d -> %d\n", DEVNAME(sd->sd_sc),
  125                     sd->sd_meta->ssd_devname,
  126                     sd->sd_vol.sv_chunks[c]->src_meta.scmi.scm_devname,
  127                     old_state, new_state);
  128                 /* NOTREACHED */
  129         }
  130 
  131         sd->sd_vol.sv_chunks[c]->src_meta.scm_status = new_state;
  132         sd->sd_set_vol_state(sd);
  133 
  134         sd->sd_must_flush = 1;
  135         workq_add_task(NULL, 0, sr_meta_save_callback, sd, NULL);
  136 done:
  137         splx(s);
  138 }
  139 
  140 void
  141 sr_raid0_set_vol_state(struct sr_discipline *sd)
  142 {
  143         int                     states[SR_MAX_STATES];
  144         int                     new_state, i, s, nd;
  145         int                     old_state = sd->sd_vol_status;
  146 
  147         DNPRINTF(SR_D_STATE, "%s: %s: sr_raid_set_vol_state\n",
  148             DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname);
  149 
  150         nd = sd->sd_meta->ssdi.ssd_chunk_no;
  151 
  152         for (i = 0; i < SR_MAX_STATES; i++)
  153                 states[i] = 0;
  154 
  155         for (i = 0; i < nd; i++) {
  156                 s = sd->sd_vol.sv_chunks[i]->src_meta.scm_status;
  157                 if (s > SR_MAX_STATES)
  158                         panic("%s: %s: %s: invalid chunk state",
  159                             DEVNAME(sd->sd_sc),
  160                             sd->sd_meta->ssd_devname,
  161                             sd->sd_vol.sv_chunks[i]->src_meta.scmi.scm_devname);
  162                 states[s]++;
  163         }
  164 
  165         if (states[BIOC_SDONLINE] == nd)
  166                 new_state = BIOC_SVONLINE;
  167         else 
  168                 new_state = BIOC_SVOFFLINE;
  169 
  170         DNPRINTF(SR_D_STATE, "%s: %s: sr_raid_set_vol_state %d -> %d\n",
  171             DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname,
  172             old_state, new_state);
  173 
  174         switch (old_state) {
  175         case BIOC_SVONLINE:
  176                 if (new_state == BIOC_SVOFFLINE)
  177                         break;
  178                 else
  179                         goto die;
  180                 break;
  181 
  182         case BIOC_SVOFFLINE:
  183                 /* XXX this might be a little too much */
  184                 goto die;
  185 
  186         default:
  187 die:
  188                 panic("%s: %s: invalid volume state transition "
  189                     "%d -> %d\n", DEVNAME(sd->sd_sc),
  190                     sd->sd_meta->ssd_devname,
  191                     old_state, new_state);
  192                 /* NOTREACHED */
  193         }
  194 
  195         sd->sd_vol_status = new_state;
  196 }
  197 
  198 int
  199 sr_raid0_rw(struct sr_workunit *wu)
  200 {
  201         struct sr_discipline    *sd = wu->swu_dis;
  202         struct scsi_xfer        *xs = wu->swu_xs;
  203         struct sr_ccb           *ccb;
  204         struct sr_chunk         *scp;
  205         int                     s;
  206         daddr64_t               blk, lbaoffs, strip_no, chunk, stripoffs;
  207         daddr64_t               strip_size, no_chunk, chunkoffs, physoffs;
  208         daddr64_t               strip_bits, length, leftover;
  209         u_int8_t                *data;
  210 
  211         /* blk and scsi error will be handled by sr_validate_io */
  212         if (sr_validate_io(wu, &blk, "sr_raid0_rw"))
  213                 goto bad;
  214 
  215         strip_size = sd->sd_meta->ssdi.ssd_strip_size;
  216         strip_bits = sd->mds.mdd_raid0.sr0_strip_bits;
  217         no_chunk = sd->sd_meta->ssdi.ssd_chunk_no;
  218 
  219         DNPRINTF(SR_D_DIS, "%s: %s: front end io: lba %lld size %d\n",
  220             DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname,
  221             blk, xs->datalen);
  222 
  223         /* all offs are in bytes */
  224         lbaoffs = blk << DEV_BSHIFT;
  225         strip_no = lbaoffs >> strip_bits;
  226         chunk = strip_no % no_chunk;
  227         stripoffs = lbaoffs & (strip_size - 1);
  228         chunkoffs = (strip_no / no_chunk) << strip_bits;
  229         physoffs = chunkoffs + stripoffs +
  230             ((SR_META_OFFSET + SR_META_SIZE) << DEV_BSHIFT);
  231         length = MIN(xs->datalen, strip_size - stripoffs);
  232         leftover = xs->datalen;
  233         data = xs->data;
  234         for (wu->swu_io_count = 1;; wu->swu_io_count++) {
  235                 /* make sure chunk is online */
  236                 scp = sd->sd_vol.sv_chunks[chunk];
  237                 if (scp->src_meta.scm_status != BIOC_SDONLINE) {
  238                         goto bad;
  239                 }
  240 
  241                 ccb = sr_ccb_get(sd);
  242                 if (!ccb) {
  243                         /* should never happen but handle more gracefully */
  244                         printf("%s: %s: too many ccbs queued\n",
  245                             DEVNAME(sd->sd_sc),
  246                             sd->sd_meta->ssd_devname);
  247                         goto bad;
  248                 }
  249 
  250                 DNPRINTF(SR_D_DIS, "%s: %s raid io: lbaoffs: %lld "
  251                     "strip_no: %lld chunk: %lld stripoffs: %lld "
  252                     "chunkoffs: %lld physoffs: %lld length: %lld "
  253                     "leftover: %lld data: %p\n",
  254                     DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname, lbaoffs,
  255                     strip_no, chunk, stripoffs, chunkoffs, physoffs, length,
  256                     leftover, data);
  257 
  258                 ccb->ccb_buf.b_flags = B_CALL;
  259                 ccb->ccb_buf.b_iodone = sr_raid0_intr;
  260                 ccb->ccb_buf.b_blkno = physoffs >> DEV_BSHIFT;
  261                 ccb->ccb_buf.b_bcount = length;
  262                 ccb->ccb_buf.b_bufsize = length;
  263                 ccb->ccb_buf.b_resid = length;
  264                 ccb->ccb_buf.b_data = data;
  265                 ccb->ccb_buf.b_error = 0;
  266                 ccb->ccb_buf.b_proc = curproc;
  267                 ccb->ccb_wu = wu;
  268                 ccb->ccb_buf.b_flags |= xs->flags & SCSI_DATA_IN ?
  269                     B_READ : B_WRITE;
  270                 ccb->ccb_target = chunk;
  271                 ccb->ccb_buf.b_dev = sd->sd_vol.sv_chunks[chunk]->src_dev_mm;
  272                 ccb->ccb_buf.b_vp = NULL;
  273                 LIST_INIT(&ccb->ccb_buf.b_dep);
  274                 TAILQ_INSERT_TAIL(&wu->swu_ccb, ccb, ccb_link);
  275 
  276                 DNPRINTF(SR_D_DIS, "%s: %s: sr_raid0: b_bcount: %d "
  277                     "b_blkno: %lld b_flags 0x%0x b_data %p\n",
  278                     DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname,
  279                     ccb->ccb_buf.b_bcount, ccb->ccb_buf.b_blkno,
  280                     ccb->ccb_buf.b_flags, ccb->ccb_buf.b_data);
  281 
  282                 leftover -= length;
  283                 if (leftover == 0)
  284                         break;
  285 
  286                 data += length;
  287                 if (++chunk > no_chunk - 1) {
  288                         chunk = 0;
  289                         physoffs += length;
  290                 } else if (wu->swu_io_count == 1)
  291                         physoffs -= stripoffs;
  292                 length = MIN(leftover,strip_size);
  293         }
  294 
  295         s = splbio();
  296 
  297         if (sr_check_io_collision(wu))
  298                 goto queued;
  299 
  300         sr_raid_startwu(wu);
  301 queued:
  302         splx(s);
  303         return (0);
  304 bad:
  305         /* wu is unwound by sr_wu_put */
  306         return (1);
  307 }
  308 
  309 void
  310 sr_raid0_intr(struct buf *bp)
  311 {
  312         struct sr_ccb           *ccb = (struct sr_ccb *)bp;
  313         struct sr_workunit      *wu = ccb->ccb_wu, *wup;
  314         struct sr_discipline    *sd = wu->swu_dis;
  315         struct scsi_xfer        *xs = wu->swu_xs;
  316         struct sr_softc         *sc = sd->sd_sc;
  317         int                     s, pend;
  318 
  319         DNPRINTF(SR_D_INTR, "%s: sr_intr bp %x xs %x\n",
  320             DEVNAME(sc), bp, xs);
  321 
  322         DNPRINTF(SR_D_INTR, "%s: sr_intr: b_bcount: %d b_resid: %d"
  323             " b_flags: 0x%0x block: %lld target: %d\n", DEVNAME(sc),
  324             ccb->ccb_buf.b_bcount, ccb->ccb_buf.b_resid, ccb->ccb_buf.b_flags,
  325             ccb->ccb_buf.b_blkno, ccb->ccb_target);
  326 
  327         s = splbio();
  328 
  329         if (ccb->ccb_buf.b_flags & B_ERROR) {
  330                 printf("%s: i/o error on block %lld target: %d b_error: %d\n",
  331                     DEVNAME(sc), ccb->ccb_buf.b_blkno, ccb->ccb_target,
  332                     ccb->ccb_buf.b_error);
  333                 DNPRINTF(SR_D_INTR, "%s: i/o error on block %lld target: %d\n",
  334                     DEVNAME(sc), ccb->ccb_buf.b_blkno, ccb->ccb_target);
  335                 wu->swu_ios_failed++;
  336                 ccb->ccb_state = SR_CCB_FAILED;
  337                 if (ccb->ccb_target != -1)
  338                         sd->sd_set_chunk_state(sd, ccb->ccb_target,
  339                             BIOC_SDOFFLINE);
  340                 else
  341                         panic("%s: invalid target on wu: %p", DEVNAME(sc), wu);
  342         } else {
  343                 ccb->ccb_state = SR_CCB_OK;
  344                 wu->swu_ios_succeeded++;
  345         }
  346         wu->swu_ios_complete++;
  347 
  348         DNPRINTF(SR_D_INTR, "%s: sr_intr: comp: %d count: %d failed: %d\n",
  349             DEVNAME(sc), wu->swu_ios_complete, wu->swu_io_count,
  350             wu->swu_ios_failed);
  351 
  352         if (wu->swu_ios_complete >= wu->swu_io_count) {
  353                 if (wu->swu_ios_failed)
  354                         goto bad;
  355 
  356                 xs->error = XS_NOERROR;
  357                 xs->resid = 0;
  358                 xs->flags |= ITSDONE;
  359 
  360                 pend = 0;
  361                 TAILQ_FOREACH(wup, &sd->sd_wu_pendq, swu_link) {
  362                         if (wu == wup) {
  363                                 /* wu on pendq, remove */
  364                                 TAILQ_REMOVE(&sd->sd_wu_pendq, wu, swu_link);
  365                                 pend = 1;
  366 
  367                                 if (wu->swu_collider) {
  368                                         /* restart deferred wu */
  369                                         wu->swu_collider->swu_state =
  370                                             SR_WU_INPROGRESS;
  371                                         TAILQ_REMOVE(&sd->sd_wu_defq,
  372                                             wu->swu_collider, swu_link);
  373                                         sr_raid_startwu(wu->swu_collider);
  374                                 }
  375                                 break;
  376                         }
  377                 }
  378 
  379                 if (!pend)
  380                         printf("%s: wu: %p not on pending queue\n",
  381                             DEVNAME(sc), wu);
  382 
  383                 /* do not change the order of these 2 functions */
  384                 sr_wu_put(wu);
  385                 sr_scsi_done(sd, xs);
  386 
  387                 if (sd->sd_sync && sd->sd_wu_pending == 0)
  388                         wakeup(sd);
  389         }
  390 
  391         splx(s);
  392         return;
  393 bad:
  394         xs->error = XS_DRIVER_STUFFUP;
  395         xs->flags |= ITSDONE;
  396         sr_wu_put(wu);
  397         sr_scsi_done(sd, xs);
  398         splx(s);
  399 }

Cache object: c5f3c6e3068649a8cd54bf18f7c80081


[ 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.