[BACK]Return to rf_reconstruct.c CVS log [TXT][DIR] Up to [local] / sys / dev / raidframe

Annotation of sys/dev/raidframe/rf_reconstruct.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: rf_reconstruct.c,v 1.16 2007/06/05 00:38:22 deraadt Exp $     */
        !             2: /*     $NetBSD: rf_reconstruct.c,v 1.26 2000/06/04 02:05:13 oster Exp $        */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1995 Carnegie-Mellon University.
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * Author: Mark Holland
        !             9:  *
        !            10:  * Permission to use, copy, modify and distribute this software and
        !            11:  * its documentation is hereby granted, provided that both the copyright
        !            12:  * notice and this permission notice appear in all copies of the
        !            13:  * software, derivative works or modified versions, and any portions
        !            14:  * thereof, and that both notices appear in supporting documentation.
        !            15:  *
        !            16:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
        !            17:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
        !            18:  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
        !            19:  *
        !            20:  * Carnegie Mellon requests users of this software to return to
        !            21:  *
        !            22:  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
        !            23:  *  School of Computer Science
        !            24:  *  Carnegie Mellon University
        !            25:  *  Pittsburgh PA 15213-3890
        !            26:  *
        !            27:  * any improvements or extensions that they make and grant Carnegie the
        !            28:  * rights to redistribute these changes.
        !            29:  */
        !            30:
        !            31: /**************************************************************
        !            32:  *
        !            33:  * rf_reconstruct.c -- Code to perform on-line reconstruction.
        !            34:  *
        !            35:  **************************************************************/
        !            36:
        !            37: #include "rf_types.h"
        !            38: #include <sys/time.h>
        !            39: #include <sys/buf.h>
        !            40: #include <sys/errno.h>
        !            41:
        !            42: #include <sys/types.h>
        !            43: #include <sys/param.h>
        !            44: #include <sys/systm.h>
        !            45: #include <sys/proc.h>
        !            46: #include <sys/ioctl.h>
        !            47: #include <sys/fcntl.h>
        !            48: #if    __NETBSD__
        !            49: #include <sys/vnode.h>
        !            50: #endif
        !            51:
        !            52: #include "rf_raid.h"
        !            53: #include "rf_reconutil.h"
        !            54: #include "rf_revent.h"
        !            55: #include "rf_reconbuffer.h"
        !            56: #include "rf_acctrace.h"
        !            57: #include "rf_etimer.h"
        !            58: #include "rf_dag.h"
        !            59: #include "rf_desc.h"
        !            60: #include "rf_general.h"
        !            61: #include "rf_freelist.h"
        !            62: #include "rf_debugprint.h"
        !            63: #include "rf_driver.h"
        !            64: #include "rf_utils.h"
        !            65: #include "rf_shutdown.h"
        !            66:
        !            67: #include "rf_kintf.h"
        !            68:
        !            69: /*
        !            70:  * Setting these to -1 causes them to be set to their default values if not set
        !            71:  * by debug options.
        !            72:  */
        !            73:
        !            74: #define        Dprintf(s)                                                      \
        !            75: do {                                                                   \
        !            76:        if (rf_reconDebug)                                              \
        !            77:                rf_debug_printf(s,                                      \
        !            78:                    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);    \
        !            79: } while (0)
        !            80: #define        Dprintf1(s,a)                                                   \
        !            81: do {                                                                   \
        !            82:        if (rf_reconDebug)                                              \
        !            83:                rf_debug_printf(s,                                      \
        !            84:                    (void *)((unsigned long)a),                         \
        !            85:                    NULL, NULL, NULL, NULL, NULL, NULL, NULL);          \
        !            86: } while (0)
        !            87: #define        Dprintf2(s,a,b)                                                 \
        !            88: do {                                                                   \
        !            89:        if (rf_reconDebug)                                              \
        !            90:                rf_debug_printf(s,                                      \
        !            91:                    (void *)((unsigned long)a),                         \
        !            92:                    (void *)((unsigned long)b),                         \
        !            93:                    NULL, NULL, NULL, NULL, NULL, NULL);                \
        !            94: } while (0)
        !            95: #define        Dprintf3(s,a,b,c)                                               \
        !            96: do {                                                                   \
        !            97:        if (rf_reconDebug)                                              \
        !            98:                rf_debug_printf(s,                                      \
        !            99:                    (void *)((unsigned long)a),                         \
        !           100:                    (void *)((unsigned long)b),                         \
        !           101:                    (void *)((unsigned long)c),                         \
        !           102:                    NULL, NULL, NULL, NULL, NULL);                      \
        !           103: } while (0)
        !           104: #define        Dprintf4(s,a,b,c,d)                                             \
        !           105: do {                                                                   \
        !           106:        if (rf_reconDebug)                                              \
        !           107:                rf_debug_printf(s,                                      \
        !           108:                    (void *)((unsigned long)a),                         \
        !           109:                    (void *)((unsigned long)b),                         \
        !           110:                    (void *)((unsigned long)c),                         \
        !           111:                    (void *)((unsigned long)d),                         \
        !           112:                    NULL, NULL, NULL, NULL);                            \
        !           113: } while (0)
        !           114: #define        Dprintf5(s,a,b,c,d,e)                                           \
        !           115: do {                                                                   \
        !           116:        if (rf_reconDebug)                                              \
        !           117:                rf_debug_printf(s,                                      \
        !           118:                    (void *)((unsigned long)a),                         \
        !           119:                    (void *)((unsigned long)b),                         \
        !           120:                    (void *)((unsigned long)c),                         \
        !           121:                    (void *)((unsigned long)d),                         \
        !           122:                    (void *)((unsigned long)e),                         \
        !           123:                    NULL, NULL, NULL);                                  \
        !           124: } while (0)
        !           125: #define        Dprintf6(s,a,b,c,d,e,f)                                         \
        !           126: do {                                                                   \
        !           127:        if (rf_reconDebug)                                              \
        !           128:                rf_debug_printf(s,                                      \
        !           129:                    (void *)((unsigned long)a),                         \
        !           130:                    (void *)((unsigned long)b),                         \
        !           131:                    (void *)((unsigned long)c),                         \
        !           132:                    (void *)((unsigned long)d),                         \
        !           133:                    (void *)((unsigned long)e),                         \
        !           134:                    (void *)((unsigned long)f),                         \
        !           135:                    NULL, NULL);                                        \
        !           136: } while (0)
        !           137: #define        Dprintf7(s,a,b,c,d,e,f,g)                                       \
        !           138: do {                                                                   \
        !           139:        if (rf_reconDebug)                                              \
        !           140:                rf_debug_printf(s,                                      \
        !           141:                    (void *)((unsigned long)a),                         \
        !           142:                    (void *)((unsigned long)b),                         \
        !           143:                    (void *)((unsigned long)c),                         \
        !           144:                    (void *)((unsigned long)d),                         \
        !           145:                    (void *)((unsigned long)e),                         \
        !           146:                    (void *)((unsigned long)f),                         \
        !           147:                    (void *)((unsigned long)g),                         \
        !           148:                    NULL);                                              \
        !           149: } while (0)
        !           150:
        !           151: #define        DDprintf1(s,a)                                                  \
        !           152: do {                                                                   \
        !           153:        if (rf_reconDebug)                                              \
        !           154:                rf_debug_printf(s,                                      \
        !           155:                    (void *)((unsigned long)a),                         \
        !           156:                    NULL, NULL, NULL, NULL, NULL, NULL, NULL);          \
        !           157: } while (0)
        !           158: #define        DDprintf2(s,a,b)                                                \
        !           159: do {                                                                   \
        !           160:        if (rf_reconDebug)                                              \
        !           161:                rf_debug_printf(s,                                      \
        !           162:                    (void *)((unsigned long)a),                         \
        !           163:                    (void *)((unsigned long)b),                         \
        !           164:                    NULL, NULL, NULL, NULL, NULL, NULL);                \
        !           165: } while (0)
        !           166:
        !           167: static RF_FreeList_t *rf_recond_freelist;
        !           168: #define        RF_MAX_FREE_RECOND      4
        !           169: #define        RF_RECOND_INC           1
        !           170:
        !           171: RF_RaidReconDesc_t *rf_AllocRaidReconDesc(RF_Raid_t *,
        !           172:        RF_RowCol_t, RF_RowCol_t, RF_RaidDisk_t *, int,
        !           173:        RF_RowCol_t, RF_RowCol_t);
        !           174: int  rf_ProcessReconEvent(RF_Raid_t *, RF_RowCol_t, RF_ReconEvent_t *);
        !           175: int  rf_IssueNextReadRequest(RF_Raid_t *, RF_RowCol_t, RF_RowCol_t);
        !           176: int  rf_TryToRead(RF_Raid_t *, RF_RowCol_t, RF_RowCol_t);
        !           177: int  rf_ComputePSDiskOffsets(RF_Raid_t *, RF_StripeNum_t,
        !           178:        RF_RowCol_t, RF_RowCol_t, RF_SectorNum_t *, RF_SectorNum_t *,
        !           179:        RF_RowCol_t *, RF_RowCol_t *, RF_SectorNum_t *);
        !           180: int  rf_ReconReadDoneProc(void *, int);
        !           181: int  rf_ReconWriteDoneProc(void *, int);
        !           182: void rf_CheckForNewMinHeadSep(RF_Raid_t *, RF_RowCol_t, RF_HeadSepLimit_t);
        !           183: int  rf_CheckHeadSeparation(RF_Raid_t *, RF_PerDiskReconCtrl_t *,
        !           184:        RF_RowCol_t, RF_RowCol_t, RF_HeadSepLimit_t, RF_ReconUnitNum_t);
        !           185: void rf_ForceReconReadDoneProc(void *, int);
        !           186: void rf_ShutdownReconstruction(void *);
        !           187:
        !           188: /*
        !           189:  * These functions are inlined on gcc. If they are used more than
        !           190:  * once, it is strongly advised to un-line them.
        !           191:  */
        !           192: void rf_FreeReconDesc(RF_RaidReconDesc_t *);
        !           193: int  rf_IssueNextWriteRequest(RF_Raid_t *, RF_RowCol_t);
        !           194: int  rf_CheckForcedOrBlockedReconstruction(RF_Raid_t *,
        !           195:        RF_ReconParityStripeStatus_t *, RF_PerDiskReconCtrl_t *,
        !           196:        RF_RowCol_t, RF_RowCol_t, RF_StripeNum_t, RF_ReconUnitNum_t);
        !           197: void rf_SignalReconDone(RF_Raid_t *);
        !           198:
        !           199: struct RF_ReconDoneProc_s {
        !           200:        void                    (*proc) (RF_Raid_t *, void *);
        !           201:        void                     *arg;
        !           202:        RF_ReconDoneProc_t       *next;
        !           203: };
        !           204:
        !           205: static RF_FreeList_t *rf_rdp_freelist;
        !           206: #define        RF_MAX_FREE_RDP         4
        !           207: #define        RF_RDP_INC              1
        !           208:
        !           209: void
        !           210: rf_SignalReconDone(RF_Raid_t *raidPtr)
        !           211: {
        !           212:        RF_ReconDoneProc_t *p;
        !           213:
        !           214:        RF_LOCK_MUTEX(raidPtr->recon_done_proc_mutex);
        !           215:        for (p = raidPtr->recon_done_procs; p; p = p->next) {
        !           216:                p->proc(raidPtr, p->arg);
        !           217:        }
        !           218:        RF_UNLOCK_MUTEX(raidPtr->recon_done_proc_mutex);
        !           219: }
        !           220:
        !           221: int
        !           222: rf_RegisterReconDoneProc(RF_Raid_t *raidPtr, void (*proc) (RF_Raid_t *, void *),
        !           223:     void *arg, RF_ReconDoneProc_t **handlep)
        !           224: {
        !           225:        RF_ReconDoneProc_t *p;
        !           226:
        !           227:        RF_FREELIST_GET(rf_rdp_freelist, p, next, (RF_ReconDoneProc_t *));
        !           228:        if (p == NULL)
        !           229:                return (ENOMEM);
        !           230:        p->proc = proc;
        !           231:        p->arg = arg;
        !           232:        RF_LOCK_MUTEX(raidPtr->recon_done_proc_mutex);
        !           233:        p->next = raidPtr->recon_done_procs;
        !           234:        raidPtr->recon_done_procs = p;
        !           235:        RF_UNLOCK_MUTEX(raidPtr->recon_done_proc_mutex);
        !           236:        if (handlep)
        !           237:                *handlep = p;
        !           238:        return (0);
        !           239: }
        !           240:
        !           241: /*****************************************************************************
        !           242:  *
        !           243:  * Sets up the parameters that will be used by the reconstruction process.
        !           244:  * Currently there are none, except for those that the layout-specific
        !           245:  * configuration (e.g. rf_ConfigureDeclustered) routine sets up.
        !           246:  *
        !           247:  * In the kernel, we fire off the recon thread.
        !           248:  *
        !           249:  *****************************************************************************/
        !           250: void
        !           251: rf_ShutdownReconstruction(void *ignored)
        !           252: {
        !           253:        RF_FREELIST_DESTROY(rf_recond_freelist, next, (RF_RaidReconDesc_t *));
        !           254:        RF_FREELIST_DESTROY(rf_rdp_freelist, next, (RF_ReconDoneProc_t *));
        !           255: }
        !           256:
        !           257: int
        !           258: rf_ConfigureReconstruction(RF_ShutdownList_t **listp)
        !           259: {
        !           260:        int rc;
        !           261:
        !           262:        RF_FREELIST_CREATE(rf_recond_freelist, RF_MAX_FREE_RECOND,
        !           263:            RF_RECOND_INC, sizeof(RF_RaidReconDesc_t));
        !           264:        if (rf_recond_freelist == NULL)
        !           265:                return (ENOMEM);
        !           266:        RF_FREELIST_CREATE(rf_rdp_freelist, RF_MAX_FREE_RDP,
        !           267:            RF_RDP_INC, sizeof(RF_ReconDoneProc_t));
        !           268:        if (rf_rdp_freelist == NULL) {
        !           269:                RF_FREELIST_DESTROY(rf_recond_freelist, next,
        !           270:                    (RF_RaidReconDesc_t *));
        !           271:                return (ENOMEM);
        !           272:        }
        !           273:        rc = rf_ShutdownCreate(listp, rf_ShutdownReconstruction, NULL);
        !           274:        if (rc) {
        !           275:                RF_ERRORMSG3("Unable to add to shutdown list file %s line %d"
        !           276:                    " rc=%d.\n", __FILE__, __LINE__, rc);
        !           277:                rf_ShutdownReconstruction(NULL);
        !           278:                return (rc);
        !           279:        }
        !           280:        return (0);
        !           281: }
        !           282:
        !           283: RF_RaidReconDesc_t *
        !           284: rf_AllocRaidReconDesc(RF_Raid_t *raidPtr, RF_RowCol_t row, RF_RowCol_t col,
        !           285:     RF_RaidDisk_t *spareDiskPtr, int numDisksDone, RF_RowCol_t srow,
        !           286:     RF_RowCol_t scol)
        !           287: {
        !           288:
        !           289:        RF_RaidReconDesc_t *reconDesc;
        !           290:
        !           291:        RF_FREELIST_GET(rf_recond_freelist, reconDesc, next,
        !           292:            (RF_RaidReconDesc_t *));
        !           293:
        !           294:        reconDesc->raidPtr = raidPtr;
        !           295:        reconDesc->row = row;
        !           296:        reconDesc->col = col;
        !           297:        reconDesc->spareDiskPtr = spareDiskPtr;
        !           298:        reconDesc->numDisksDone = numDisksDone;
        !           299:        reconDesc->srow = srow;
        !           300:        reconDesc->scol = scol;
        !           301:        reconDesc->state = 0;
        !           302:        reconDesc->next = NULL;
        !           303:
        !           304:        return (reconDesc);
        !           305: }
        !           306:
        !           307: void
        !           308: rf_FreeReconDesc(RF_RaidReconDesc_t *reconDesc)
        !           309: {
        !           310: #if    RF_RECON_STATS > 0
        !           311:        printf("RAIDframe: %qu recon event waits, %qu recon delays.\n",
        !           312:            reconDesc->numReconEventWaits, reconDesc->numReconExecDelays);
        !           313: #endif /* RF_RECON_STATS > 0 */
        !           314:
        !           315:        printf("RAIDframe: %qu max exec ticks.\n",
        !           316:            reconDesc->maxReconExecTicks);
        !           317:
        !           318: #if    (RF_RECON_STATS > 0) || defined(_KERNEL)
        !           319:        printf("\n");
        !           320: #endif /* (RF_RECON_STATS > 0) || _KERNEL */
        !           321:        RF_FREELIST_FREE(rf_recond_freelist, reconDesc, next);
        !           322: }
        !           323:
        !           324:
        !           325: /*****************************************************************************
        !           326:  *
        !           327:  * Primary routine to reconstruct a failed disk. This should be called from
        !           328:  * within its own thread. It won't return until reconstruction completes,
        !           329:  * fails, or is aborted.
        !           330:  *
        !           331:  *****************************************************************************/
        !           332: int
        !           333: rf_ReconstructFailedDisk(RF_Raid_t *raidPtr, RF_RowCol_t row, RF_RowCol_t col)
        !           334: {
        !           335:        RF_LayoutSW_t *lp;
        !           336:        int rc;
        !           337:
        !           338:        lp = raidPtr->Layout.map;
        !           339:        if (lp->SubmitReconBuffer) {
        !           340:                /*
        !           341:                 * The current infrastructure only supports reconstructing one
        !           342:                 * disk at a time for each array.
        !           343:                 */
        !           344:                RF_LOCK_MUTEX(raidPtr->mutex);
        !           345:                while (raidPtr->reconInProgress) {
        !           346:                        RF_WAIT_COND(raidPtr->waitForReconCond, raidPtr->mutex);
        !           347:                }
        !           348:                raidPtr->reconInProgress++;
        !           349:                RF_UNLOCK_MUTEX(raidPtr->mutex);
        !           350:                rc = rf_ReconstructFailedDiskBasic(raidPtr, row, col);
        !           351:                RF_LOCK_MUTEX(raidPtr->mutex);
        !           352:                raidPtr->reconInProgress--;
        !           353:                RF_UNLOCK_MUTEX(raidPtr->mutex);
        !           354:        } else {
        !           355:                RF_ERRORMSG1("RECON: no way to reconstruct failed disk for"
        !           356:                    " arch %c.\n", lp->parityConfig);
        !           357:                rc = EIO;
        !           358:        }
        !           359:        RF_SIGNAL_COND(raidPtr->waitForReconCond);
        !           360:        wakeup(&raidPtr->waitForReconCond);     /*
        !           361:                                                 * XXX Methinks this will be
        !           362:                                                 * needed at some point... GO
        !           363:                                                 */
        !           364:        return (rc);
        !           365: }
        !           366:
        !           367: int
        !           368: rf_ReconstructFailedDiskBasic(RF_Raid_t *raidPtr, RF_RowCol_t row,
        !           369:     RF_RowCol_t col)
        !           370: {
        !           371:        RF_ComponentLabel_t c_label;
        !           372:        RF_RaidDisk_t *spareDiskPtr = NULL;
        !           373:        RF_RaidReconDesc_t *reconDesc;
        !           374:        RF_RowCol_t srow, scol;
        !           375:        int numDisksDone = 0, rc;
        !           376:
        !           377:        /* First look for a spare drive onto which to reconstruct the data. */
        !           378:        /*
        !           379:         * Spare disk descriptors are stored in row 0. This may have to
        !           380:         * change eventually.
        !           381:         */
        !           382:
        !           383:        RF_LOCK_MUTEX(raidPtr->mutex);
        !           384:        RF_ASSERT(raidPtr->Disks[row][col].status == rf_ds_failed);
        !           385:
        !           386:        if (raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE) {
        !           387:                if (raidPtr->status[row] != rf_rs_degraded) {
        !           388:                        RF_ERRORMSG2("Unable to reconstruct disk at row %d"
        !           389:                            " col %d because status not degraded.\n", row, col);
        !           390:                        RF_UNLOCK_MUTEX(raidPtr->mutex);
        !           391:                        return (EINVAL);
        !           392:                }
        !           393:                srow = row;
        !           394:                scol = (-1);
        !           395:        } else {
        !           396:                srow = 0;
        !           397:                for (scol = raidPtr->numCol;
        !           398:                     scol < raidPtr->numCol + raidPtr->numSpare; scol++) {
        !           399:                        if (raidPtr->Disks[srow][scol].status == rf_ds_spare) {
        !           400:                                spareDiskPtr = &raidPtr->Disks[srow][scol];
        !           401:                                spareDiskPtr->status = rf_ds_used_spare;
        !           402:                                break;
        !           403:                        }
        !           404:                }
        !           405:                if (!spareDiskPtr) {
        !           406:                        RF_ERRORMSG2("Unable to reconstruct disk at row %d"
        !           407:                            " col %d because no spares are available.\n",
        !           408:                            row, col);
        !           409:                        RF_UNLOCK_MUTEX(raidPtr->mutex);
        !           410:                        return (ENOSPC);
        !           411:                }
        !           412:                printf("RECON: initiating reconstruction on row %d col %d"
        !           413:                    " -> spare at row %d col %d.\n", row, col, srow, scol);
        !           414:        }
        !           415:        RF_UNLOCK_MUTEX(raidPtr->mutex);
        !           416:
        !           417:        reconDesc = rf_AllocRaidReconDesc((void *) raidPtr, row, col,
        !           418:            spareDiskPtr, numDisksDone, srow, scol);
        !           419:        raidPtr->reconDesc = (void *) reconDesc;
        !           420: #if    RF_RECON_STATS > 0
        !           421:        reconDesc->hsStallCount = 0;
        !           422:        reconDesc->numReconExecDelays = 0;
        !           423:        reconDesc->numReconEventWaits = 0;
        !           424: #endif /* RF_RECON_STATS > 0 */
        !           425:        reconDesc->reconExecTimerRunning = 0;
        !           426:        reconDesc->reconExecTicks = 0;
        !           427:        reconDesc->maxReconExecTicks = 0;
        !           428:        rc = rf_ContinueReconstructFailedDisk(reconDesc);
        !           429:
        !           430:        if (!rc) {
        !           431:                /* Fix up the component label. */
        !           432:                /* Don't actually need the read here... */
        !           433:                raidread_component_label(
        !           434:                    raidPtr->raid_cinfo[srow][scol].ci_dev,
        !           435:                    raidPtr->raid_cinfo[srow][scol].ci_vp,
        !           436:                    &c_label);
        !           437:
        !           438:                raid_init_component_label(raidPtr, &c_label);
        !           439:                c_label.row = row;
        !           440:                c_label.column = col;
        !           441:                c_label.clean = RF_RAID_DIRTY;
        !           442:                c_label.status = rf_ds_optimal;
        !           443:
        !           444:                /* XXXX MORE NEEDED HERE. */
        !           445:
        !           446:                raidwrite_component_label(
        !           447:                    raidPtr->raid_cinfo[srow][scol].ci_dev,
        !           448:                    raidPtr->raid_cinfo[srow][scol].ci_vp,
        !           449:                    &c_label);
        !           450:
        !           451:        }
        !           452:        return (rc);
        !           453: }
        !           454:
        !           455: /*
        !           456:  *
        !           457:  * Allow reconstructing a disk in-place -- i.e. component /dev/sd2e goes AWOL,
        !           458:  * and you don't get a spare until the next Monday. With this function
        !           459:  * (and hot-swappable drives) you can now put your new disk containing
        !           460:  * /dev/sd2e on the bus, scsictl it alive, and then use raidctl(8) to
        !           461:  * rebuild the data "on the spot".
        !           462:  *
        !           463:  */
        !           464:
        !           465: int
        !           466: rf_ReconstructInPlace(RF_Raid_t *raidPtr, RF_RowCol_t row, RF_RowCol_t col)
        !           467: {
        !           468:        RF_RaidDisk_t *spareDiskPtr = NULL;
        !           469:        RF_RaidReconDesc_t *reconDesc;
        !           470:        RF_LayoutSW_t *lp;
        !           471:        RF_RaidDisk_t *badDisk;
        !           472:        RF_ComponentLabel_t c_label;
        !           473:        int numDisksDone = 0, rc;
        !           474:        struct partinfo dpart;
        !           475:        struct vnode *vp;
        !           476:        struct vattr va;
        !           477:        struct proc *proc;
        !           478:        int retcode;
        !           479:        int ac;
        !           480:
        !           481:        lp = raidPtr->Layout.map;
        !           482:        if (lp->SubmitReconBuffer) {
        !           483:                /*
        !           484:                 * The current infrastructure only supports reconstructing one
        !           485:                 * disk at a time for each array.
        !           486:                 */
        !           487:                RF_LOCK_MUTEX(raidPtr->mutex);
        !           488:                if ((raidPtr->Disks[row][col].status == rf_ds_optimal) &&
        !           489:                    (raidPtr->numFailures > 0)) {
        !           490:                        /* XXX 0 above shouldn't be constant !!! */
        !           491:                        /*
        !           492:                         * Some component other than this has failed.
        !           493:                         * Let's not make things worse than they already
        !           494:                         * are...
        !           495:                         */
        !           496: #ifdef RAIDDEBUG
        !           497:                        printf("RAIDFRAME: Unable to reconstruct to disk at:\n"
        !           498:                            "      Row: %d Col: %d   Too many failures.\n",
        !           499:                            row, col);
        !           500: #endif /* RAIDDEBUG */
        !           501:                        RF_UNLOCK_MUTEX(raidPtr->mutex);
        !           502:                        return (EINVAL);
        !           503:                }
        !           504:                if (raidPtr->Disks[row][col].status == rf_ds_reconstructing) {
        !           505: #ifdef RAIDDEBUG
        !           506:                        printf("RAIDFRAME: Unable to reconstruct to disk at:\n"
        !           507:                            "      Row: %d Col: %d   Reconstruction already"
        !           508:                            " occurring !\n", row, col);
        !           509: #endif /* RAIDDEBUG */
        !           510:
        !           511:                        RF_UNLOCK_MUTEX(raidPtr->mutex);
        !           512:                        return (EINVAL);
        !           513:                }
        !           514:
        !           515:
        !           516:                if (raidPtr->Disks[row][col].status != rf_ds_failed) {
        !           517:                        /* "It's gone..." */
        !           518:                        raidPtr->numFailures++;
        !           519:                        raidPtr->Disks[row][col].status = rf_ds_failed;
        !           520:                        raidPtr->status[row] = rf_rs_degraded;
        !           521:                        rf_update_component_labels(raidPtr,
        !           522:                            RF_NORMAL_COMPONENT_UPDATE);
        !           523:                }
        !           524:
        !           525:                while (raidPtr->reconInProgress) {
        !           526:                        RF_WAIT_COND(raidPtr->waitForReconCond, raidPtr->mutex);
        !           527:                }
        !           528:
        !           529:                raidPtr->reconInProgress++;
        !           530:
        !           531:                /*
        !           532:                 * First look for a spare drive onto which to reconstruct
        !           533:                 * the data. Spare disk descriptors are stored in row 0.
        !           534:                 * This may have to change eventually.
        !           535:                 */
        !           536:
        !           537:                /*
        !           538:                 * Actually, we don't care if it's failed or not...
        !           539:                 * On a RAID set with correct parity, this function
        !           540:                 * should be callable on any component without ill effects.
        !           541:                 */
        !           542:                /*
        !           543:                 * RF_ASSERT(raidPtr->Disks[row][col].status == rf_ds_failed);
        !           544:                 */
        !           545:
        !           546:                if (raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE) {
        !           547:                        RF_ERRORMSG2("Unable to reconstruct to disk at row %d"
        !           548:                            " col %d: operation not supported for"
        !           549:                            " RF_DISTRIBUTE_SPARE.\n", row, col);
        !           550:
        !           551:                        raidPtr->reconInProgress--;
        !           552:                        RF_UNLOCK_MUTEX(raidPtr->mutex);
        !           553:                        return (EINVAL);
        !           554:                }
        !           555:
        !           556:                /*
        !           557:                 * XXX Need goop here to see if the disk is alive,
        !           558:                 * and, if not, make it so...
        !           559:                 */
        !           560:
        !           561:                badDisk = &raidPtr->Disks[row][col];
        !           562:
        !           563:                proc = raidPtr->recon_thread;
        !           564:
        !           565:                /*
        !           566:                 * This device may have been opened successfully the
        !           567:                 * first time. Close it before trying to open it again...
        !           568:                 */
        !           569:
        !           570:                if (raidPtr->raid_cinfo[row][col].ci_vp != NULL) {
        !           571:                        printf("Closing the opened device: %s\n",
        !           572:                            raidPtr->Disks[row][col].devname);
        !           573:                        vp = raidPtr->raid_cinfo[row][col].ci_vp;
        !           574:                        ac = raidPtr->Disks[row][col].auto_configured;
        !           575:                        rf_close_component(raidPtr, vp, ac);
        !           576:                        raidPtr->raid_cinfo[row][col].ci_vp = NULL;
        !           577:                }
        !           578:                /*
        !           579:                 * Note that this disk was *not* auto_configured (any longer).
        !           580:                 */
        !           581:                raidPtr->Disks[row][col].auto_configured = 0;
        !           582:
        !           583:                printf("About to (re-)open the device for rebuilding: %s\n",
        !           584:                    raidPtr->Disks[row][col].devname);
        !           585:
        !           586:                retcode = raidlookup(raidPtr->Disks[row][col].devname,
        !           587:                    proc, &vp);
        !           588:
        !           589:                if (retcode) {
        !           590:                        printf("raid%d: rebuilding: raidlookup on device: %s"
        !           591:                            " failed: %d !\n", raidPtr->raidid,
        !           592:                            raidPtr->Disks[row][col].devname, retcode);
        !           593:
        !           594:                        /*
        !           595:                         * XXX the component isn't responding properly...
        !           596:                         * Must still be dead :-(
        !           597:                         */
        !           598:                        raidPtr->reconInProgress--;
        !           599:                        RF_UNLOCK_MUTEX(raidPtr->mutex);
        !           600:                        return(retcode);
        !           601:
        !           602:                } else {
        !           603:
        !           604:                        /*
        !           605:                         * Ok, so we can at least do a lookup...
        !           606:                         * How about actually getting a vp for it ?
        !           607:                         */
        !           608:
        !           609:                        if ((retcode =
        !           610:                             VOP_GETATTR(vp, &va, proc->p_ucred, proc)) != 0) {
        !           611:                                raidPtr->reconInProgress--;
        !           612:                                RF_UNLOCK_MUTEX(raidPtr->mutex);
        !           613:                                return(retcode);
        !           614:                        }
        !           615:                        retcode = VOP_IOCTL(vp, DIOCGPART, (caddr_t) & dpart,
        !           616:                            FREAD, proc->p_ucred, proc);
        !           617:                        if (retcode) {
        !           618:                                raidPtr->reconInProgress--;
        !           619:                                RF_UNLOCK_MUTEX(raidPtr->mutex);
        !           620:                                return(retcode);
        !           621:                        }
        !           622:                        raidPtr->Disks[row][col].blockSize =
        !           623:                            dpart.disklab->d_secsize;
        !           624:
        !           625:                        raidPtr->Disks[row][col].numBlocks =
        !           626:                            DL_GETPSIZE(dpart.part) - rf_protectedSectors;
        !           627:
        !           628:                        raidPtr->raid_cinfo[row][col].ci_vp = vp;
        !           629:                        raidPtr->raid_cinfo[row][col].ci_dev = va.va_rdev;
        !           630:
        !           631:                        raidPtr->Disks[row][col].dev = va.va_rdev;
        !           632:
        !           633:                        /*
        !           634:                         * We allow the user to specify that only a
        !           635:                         * fraction of the disks should be used this is
        !           636:                         * just for debug:  it speeds up the parity scan.
        !           637:                         */
        !           638:                        raidPtr->Disks[row][col].numBlocks =
        !           639:                            raidPtr->Disks[row][col].numBlocks *
        !           640:                            rf_sizePercentage / 100;
        !           641:                }
        !           642:
        !           643:                spareDiskPtr = &raidPtr->Disks[row][col];
        !           644:                spareDiskPtr->status = rf_ds_used_spare;
        !           645:
        !           646:                printf("RECON: Initiating in-place reconstruction on\n");
        !           647:                printf("       row %d col %d -> spare at row %d col %d.\n",
        !           648:                    row, col, row, col);
        !           649:
        !           650:                RF_UNLOCK_MUTEX(raidPtr->mutex);
        !           651:
        !           652:                reconDesc = rf_AllocRaidReconDesc((void *) raidPtr, row, col,
        !           653:                    spareDiskPtr, numDisksDone, row, col);
        !           654:                raidPtr->reconDesc = (void *) reconDesc;
        !           655: #if    RF_RECON_STATS > 0
        !           656:                reconDesc->hsStallCount = 0;
        !           657:                reconDesc->numReconExecDelays = 0;
        !           658:                reconDesc->numReconEventWaits = 0;
        !           659: #endif /* RF_RECON_STATS > 0 */
        !           660:                reconDesc->reconExecTimerRunning = 0;
        !           661:                reconDesc->reconExecTicks = 0;
        !           662:                reconDesc->maxReconExecTicks = 0;
        !           663:                rc = rf_ContinueReconstructFailedDisk(reconDesc);
        !           664:
        !           665:                RF_LOCK_MUTEX(raidPtr->mutex);
        !           666:                raidPtr->reconInProgress--;
        !           667:                RF_UNLOCK_MUTEX(raidPtr->mutex);
        !           668:
        !           669:        } else {
        !           670:                RF_ERRORMSG1("RECON: no way to reconstruct failed disk for"
        !           671:                    " arch %c.\n", lp->parityConfig);
        !           672:                rc = EIO;
        !           673:        }
        !           674:        RF_LOCK_MUTEX(raidPtr->mutex);
        !           675:
        !           676:        if (!rc) {
        !           677:                /*
        !           678:                 * Need to set these here, as at this point it'll be claiming
        !           679:                 * that the disk is in rf_ds_spared !  But we know better :-)
        !           680:                 */
        !           681:
        !           682:                raidPtr->Disks[row][col].status = rf_ds_optimal;
        !           683:                raidPtr->status[row] = rf_rs_optimal;
        !           684:
        !           685:                /* Fix up the component label. */
        !           686:                /* Don't actually need the read here... */
        !           687:                raidread_component_label(
        !           688:                    raidPtr->raid_cinfo[row][col].ci_dev,
        !           689:                    raidPtr->raid_cinfo[row][col].ci_vp,
        !           690:                    &c_label);
        !           691:
        !           692:                raid_init_component_label(raidPtr, &c_label);
        !           693:
        !           694:                c_label.row = row;
        !           695:                c_label.column = col;
        !           696:
        !           697:                raidwrite_component_label(raidPtr->raid_cinfo[row][col].ci_dev,
        !           698:                    raidPtr->raid_cinfo[row][col].ci_vp, &c_label);
        !           699:
        !           700:        }
        !           701:        RF_UNLOCK_MUTEX(raidPtr->mutex);
        !           702:        RF_SIGNAL_COND(raidPtr->waitForReconCond);
        !           703:        wakeup(&raidPtr->waitForReconCond);
        !           704:        return (rc);
        !           705: }
        !           706:
        !           707:
        !           708: int
        !           709: rf_ContinueReconstructFailedDisk(RF_RaidReconDesc_t *reconDesc)
        !           710: {
        !           711:        RF_Raid_t *raidPtr = reconDesc->raidPtr;
        !           712:        RF_RowCol_t row = reconDesc->row;
        !           713:        RF_RowCol_t col = reconDesc->col;
        !           714:        RF_RowCol_t srow = reconDesc->srow;
        !           715:        RF_RowCol_t scol = reconDesc->scol;
        !           716:        RF_ReconMap_t *mapPtr;
        !           717:
        !           718:        RF_ReconEvent_t *event;
        !           719:        struct timeval etime, elpsd;
        !           720:        unsigned long xor_s, xor_resid_us;
        !           721:        int retcode, i, ds;
        !           722:
        !           723:        switch (reconDesc->state) {
        !           724:        case 0:
        !           725:                raidPtr->accumXorTimeUs = 0;
        !           726:
        !           727:                /* Create one trace record per physical disk. */
        !           728:                RF_Malloc(raidPtr->recon_tracerecs, raidPtr->numCol *
        !           729:                    sizeof(RF_AccTraceEntry_t), (RF_AccTraceEntry_t *));
        !           730:
        !           731:                /*
        !           732:                 * Quiesce the array prior to starting recon. This is needed
        !           733:                 * to assure no nasty interactions with pending user writes.
        !           734:                 * We need to do this before we change the disk or row status.
        !           735:                 */
        !           736:                reconDesc->state = 1;
        !           737:
        !           738:                Dprintf("RECON: begin request suspend.\n");
        !           739:                retcode = rf_SuspendNewRequestsAndWait(raidPtr);
        !           740:                Dprintf("RECON: end request suspend.\n");
        !           741:                rf_StartUserStats(raidPtr);     /*
        !           742:                                                 * Zero out the stats kept on
        !           743:                                                 * user accs.
        !           744:                                                 */
        !           745:                /* Fall through to state 1. */
        !           746:        case 1:
        !           747:                RF_LOCK_MUTEX(raidPtr->mutex);
        !           748:
        !           749:                /*
        !           750:                 * Create the reconstruction control pointer and install it in
        !           751:                 * the right slot.
        !           752:                 */
        !           753:                raidPtr->reconControl[row] =
        !           754:                    rf_MakeReconControl(reconDesc, row, col, srow, scol);
        !           755:                mapPtr = raidPtr->reconControl[row]->reconMap;
        !           756:                raidPtr->status[row] = rf_rs_reconstructing;
        !           757:                raidPtr->Disks[row][col].status = rf_ds_reconstructing;
        !           758:                raidPtr->Disks[row][col].spareRow = srow;
        !           759:                raidPtr->Disks[row][col].spareCol = scol;
        !           760:
        !           761:                RF_UNLOCK_MUTEX(raidPtr->mutex);
        !           762:
        !           763:                RF_GETTIME(raidPtr->reconControl[row]->starttime);
        !           764:
        !           765:                /*
        !           766:                 * Now start up the actual reconstruction: issue a read for
        !           767:                 * each surviving disk.
        !           768:                 */
        !           769:
        !           770:                reconDesc->numDisksDone = 0;
        !           771:                for (i = 0; i < raidPtr->numCol; i++) {
        !           772:                        if (i != col) {
        !           773:                                /*
        !           774:                                 * Find and issue the next I/O on the
        !           775:                                 * indicated disk.
        !           776:                                 */
        !           777:                                if (rf_IssueNextReadRequest(raidPtr, row, i)) {
        !           778:                                        Dprintf2("RECON: done issuing for r%d"
        !           779:                                            " c%d.\n", row, i);
        !           780:                                        reconDesc->numDisksDone++;
        !           781:                                }
        !           782:                        }
        !           783:                }
        !           784:
        !           785:                reconDesc->state = 2;
        !           786:
        !           787:        case 2:
        !           788:                Dprintf("RECON: resume requests.\n");
        !           789:                rf_ResumeNewRequests(raidPtr);
        !           790:
        !           791:                reconDesc->state = 3;
        !           792:
        !           793:        case 3:
        !           794:
        !           795:                /*
        !           796:                 * Process reconstruction events until all disks report that
        !           797:                 * they've completed all work.
        !           798:                 */
        !           799:                mapPtr = raidPtr->reconControl[row]->reconMap;
        !           800:
        !           801:                while (reconDesc->numDisksDone < raidPtr->numCol - 1) {
        !           802:
        !           803:                        event = rf_GetNextReconEvent(reconDesc, row,
        !           804:                           (void (*) (void *)) rf_ContinueReconstructFailedDisk,
        !           805:                            reconDesc);
        !           806:                        RF_ASSERT(event);
        !           807:
        !           808:                        if (rf_ProcessReconEvent(raidPtr, row, event))
        !           809:                                reconDesc->numDisksDone++;
        !           810:                        raidPtr->reconControl[row]->numRUsTotal =
        !           811:                                mapPtr->totalRUs;
        !           812:                        raidPtr->reconControl[row]->numRUsComplete =
        !           813:                                mapPtr->totalRUs -
        !           814:                                rf_UnitsLeftToReconstruct(mapPtr);
        !           815:
        !           816:                        raidPtr->reconControl[row]->percentComplete =
        !           817:                            (raidPtr->reconControl[row]->numRUsComplete * 100 /
        !           818:                             raidPtr->reconControl[row]->numRUsTotal);
        !           819:                        if (rf_prReconSched) {
        !           820:                                rf_PrintReconSchedule(
        !           821:                                    raidPtr->reconControl[row]->reconMap,
        !           822:                                    &(raidPtr->reconControl[row]->starttime));
        !           823:                        }
        !           824:                }
        !           825:
        !           826:                reconDesc->state = 4;
        !           827:
        !           828:        case 4:
        !           829:                mapPtr = raidPtr->reconControl[row]->reconMap;
        !           830:                if (rf_reconDebug) {
        !           831:                        printf("RECON: all reads completed.\n");
        !           832:                }
        !           833:                /*
        !           834:                 * At this point all the reads have completed. We now wait
        !           835:                 * for any pending writes to complete, and then we're done.
        !           836:                 */
        !           837:
        !           838:                while (rf_UnitsLeftToReconstruct(
        !           839:                    raidPtr->reconControl[row]->reconMap) > 0) {
        !           840:
        !           841:                        event = rf_GetNextReconEvent(reconDesc, row,
        !           842:                           (void (*) (void *)) rf_ContinueReconstructFailedDisk,
        !           843:                            reconDesc);
        !           844:                        RF_ASSERT(event);
        !           845:
        !           846:                        /* Ignore return code. */
        !           847:                        (void) rf_ProcessReconEvent(raidPtr, row, event);
        !           848:                        raidPtr->reconControl[row]->percentComplete =
        !           849:                            100 - (rf_UnitsLeftToReconstruct(mapPtr) * 100 /
        !           850:                            mapPtr->totalRUs);
        !           851:                        if (rf_prReconSched) {
        !           852:                                rf_PrintReconSchedule(
        !           853:                                    raidPtr->reconControl[row]->reconMap,
        !           854:                                    &(raidPtr->reconControl[row]->starttime));
        !           855:                        }
        !           856:                }
        !           857:                reconDesc->state = 5;
        !           858:
        !           859:        case 5:
        !           860:                /*
        !           861:                 * Success:  mark the dead disk as reconstructed. We quiesce
        !           862:                 * the array here to assure no nasty interactions with pending
        !           863:                 * user accesses, when we free up the psstatus structure as
        !           864:                 * part of FreeReconControl().
        !           865:                 */
        !           866:
        !           867:                reconDesc->state = 6;
        !           868:
        !           869:                retcode = rf_SuspendNewRequestsAndWait(raidPtr);
        !           870:                rf_StopUserStats(raidPtr);
        !           871:                rf_PrintUserStats(raidPtr);     /*
        !           872:                                                 * Print out the stats on user
        !           873:                                                 * accs accumulated during
        !           874:                                                 * recon.
        !           875:                                                 */
        !           876:
        !           877:                /* Fall through to state 6. */
        !           878:        case 6:
        !           879:                RF_LOCK_MUTEX(raidPtr->mutex);
        !           880:                raidPtr->numFailures--;
        !           881:                ds = (raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE);
        !           882:                raidPtr->Disks[row][col].status = (ds) ? rf_ds_dist_spared :
        !           883:                                                         rf_ds_spared;
        !           884:                raidPtr->status[row] = (ds) ? rf_rs_reconfigured :
        !           885:                                              rf_rs_optimal;
        !           886:                RF_UNLOCK_MUTEX(raidPtr->mutex);
        !           887:                RF_GETTIME(etime);
        !           888:                RF_TIMEVAL_DIFF(&(raidPtr->reconControl[row]->starttime),
        !           889:                    &etime, &elpsd);
        !           890:
        !           891:                /*
        !           892:                 * XXX -- Why is state 7 different from state 6 if there is no
        !           893:                 * return() here ? -- XXX Note that I set elpsd above & use it
        !           894:                 * below, so if you put a return here you'll have to fix this.
        !           895:                 * (also, FreeReconControl is called below).
        !           896:                 */
        !           897:
        !           898:        case 7:
        !           899:
        !           900:                rf_ResumeNewRequests(raidPtr);
        !           901:
        !           902:                printf("Reconstruction of disk at row %d col %d completed.\n",
        !           903:                    row, col);
        !           904:                xor_s = raidPtr->accumXorTimeUs / 1000000;
        !           905:                xor_resid_us = raidPtr->accumXorTimeUs % 1000000;
        !           906:                printf("Recon time was %d.%06d seconds, accumulated XOR time"
        !           907:                    " was %ld us (%ld.%06ld).\n", (int) elpsd.tv_sec,
        !           908:                    (int) elpsd.tv_usec, raidPtr->accumXorTimeUs, xor_s,
        !           909:                    xor_resid_us);
        !           910:                printf("  (start time %d sec %d usec, end time %d sec %d"
        !           911:                    " usec)\n",
        !           912:                    (int) raidPtr->reconControl[row]->starttime.tv_sec,
        !           913:                    (int) raidPtr->reconControl[row]->starttime.tv_usec,
        !           914:                    (int) etime.tv_sec, (int) etime.tv_usec);
        !           915:
        !           916: #if    RF_RECON_STATS > 0
        !           917:                printf("Total head-sep stall count was %d.\n",
        !           918:                    (int) reconDesc->hsStallCount);
        !           919: #endif /* RF_RECON_STATS > 0 */
        !           920:                rf_FreeReconControl(raidPtr, row);
        !           921:                RF_Free(raidPtr->recon_tracerecs, raidPtr->numCol *
        !           922:                    sizeof(RF_AccTraceEntry_t));
        !           923:                rf_FreeReconDesc(reconDesc);
        !           924:
        !           925:        }
        !           926:
        !           927:        rf_SignalReconDone(raidPtr);
        !           928:        return (0);
        !           929: }
        !           930:
        !           931:
        !           932: /*****************************************************************************
        !           933:  * Do the right thing upon each reconstruction event.
        !           934:  * Returns nonzero if and only if there is nothing left unread on the
        !           935:  * indicated disk.
        !           936:  *****************************************************************************/
        !           937: int
        !           938: rf_ProcessReconEvent(RF_Raid_t *raidPtr, RF_RowCol_t frow,
        !           939:     RF_ReconEvent_t *event)
        !           940: {
        !           941:        int retcode = 0, submitblocked;
        !           942:        RF_ReconBuffer_t *rbuf;
        !           943:        RF_SectorCount_t sectorsPerRU;
        !           944:
        !           945:        Dprintf1("RECON: rf_ProcessReconEvent type %d.\n", event->type);
        !           946:
        !           947:        switch (event->type) {
        !           948:
        !           949:                /* A read I/O has completed. */
        !           950:        case RF_REVENT_READDONE:
        !           951:                rbuf = raidPtr->reconControl[frow]
        !           952:                    ->perDiskInfo[event->col].rbuf;
        !           953:                Dprintf3("RECON: READDONE EVENT: row %d col %d psid %ld.\n",
        !           954:                    frow, event->col, rbuf->parityStripeID);
        !           955:                Dprintf7("RECON: done read  psid %ld buf %lx  %02x %02x %02x"
        !           956:                    " %02x %02x.\n", rbuf->parityStripeID, rbuf->buffer,
        !           957:                    rbuf->buffer[0] & 0xff, rbuf->buffer[1] & 0xff,
        !           958:                    rbuf->buffer[2] & 0xff, rbuf->buffer[3] & 0xff,
        !           959:                    rbuf->buffer[4] & 0xff);
        !           960:                rf_FreeDiskQueueData((RF_DiskQueueData_t *) rbuf->arg);
        !           961:                submitblocked = rf_SubmitReconBuffer(rbuf, 0, 0);
        !           962:                Dprintf1("RECON: submitblocked=%d.\n", submitblocked);
        !           963:                if (!submitblocked)
        !           964:                        retcode = rf_IssueNextReadRequest(raidPtr, frow,
        !           965:                            event->col);
        !           966:                break;
        !           967:
        !           968:                /* A write I/O has completed. */
        !           969:        case RF_REVENT_WRITEDONE:
        !           970:                if (rf_floatingRbufDebug) {
        !           971:                        rf_CheckFloatingRbufCount(raidPtr, 1);
        !           972:                }
        !           973:                sectorsPerRU = raidPtr->Layout.sectorsPerStripeUnit *
        !           974:                    raidPtr->Layout.SUsPerRU;
        !           975:                rbuf = (RF_ReconBuffer_t *) event->arg;
        !           976:                rf_FreeDiskQueueData((RF_DiskQueueData_t *) rbuf->arg);
        !           977:                Dprintf3("RECON: WRITEDONE EVENT: psid %d ru %d"
        !           978:                    " (%d %% complete).\n",
        !           979:                    rbuf->parityStripeID, rbuf->which_ru,
        !           980:                    raidPtr->reconControl[frow]->percentComplete);
        !           981:                rf_ReconMapUpdate(raidPtr, raidPtr->reconControl[frow]
        !           982:                    ->reconMap, rbuf->failedDiskSectorOffset,
        !           983:                    rbuf->failedDiskSectorOffset + sectorsPerRU - 1);
        !           984:                rf_RemoveFromActiveReconTable(raidPtr, frow,
        !           985:                    rbuf->parityStripeID, rbuf->which_ru);
        !           986:
        !           987:                if (rbuf->type == RF_RBUF_TYPE_FLOATING) {
        !           988:                        RF_LOCK_MUTEX(raidPtr->reconControl[frow]->rb_mutex);
        !           989:                        raidPtr->numFullReconBuffers--;
        !           990:                        rf_ReleaseFloatingReconBuffer(raidPtr, frow, rbuf);
        !           991:                        RF_UNLOCK_MUTEX(raidPtr->reconControl[frow]->rb_mutex);
        !           992:                } else
        !           993:                        if (rbuf->type == RF_RBUF_TYPE_FORCED)
        !           994:                                rf_FreeReconBuffer(rbuf);
        !           995:                        else
        !           996:                                RF_ASSERT(0);
        !           997:                break;
        !           998:
        !           999:                /* A buffer-stall condition has been cleared. */
        !          1000:        case RF_REVENT_BUFCLEAR:
        !          1001:                Dprintf2("RECON: BUFCLEAR EVENT: row %d col %d.\n", frow,
        !          1002:                    event->col);
        !          1003:                submitblocked = rf_SubmitReconBuffer(raidPtr
        !          1004:                    ->reconControl[frow]->perDiskInfo[event->col].rbuf, 0,
        !          1005:                    (int) (long) event->arg);
        !          1006:                RF_ASSERT(!submitblocked);      /*
        !          1007:                                                 * We wouldn't have gotten the
        !          1008:                                                 * BUFCLEAR event if we
        !          1009:                                                 * couldn't submit.
        !          1010:                                                 */
        !          1011:                retcode = rf_IssueNextReadRequest(raidPtr, frow, event->col);
        !          1012:                break;
        !          1013:
        !          1014:                /* A user-write reconstruction blockage has been cleared. */
        !          1015:        case RF_REVENT_BLOCKCLEAR:
        !          1016:                DDprintf2("RECON: BLOCKCLEAR EVENT: row %d col %d.\n",
        !          1017:                    frow, event->col);
        !          1018:                retcode = rf_TryToRead(raidPtr, frow, event->col);
        !          1019:                break;
        !          1020:
        !          1021:                /*
        !          1022:                 * A max-head-separation reconstruction blockage has been
        !          1023:                 * cleared.
        !          1024:                 */
        !          1025:        case RF_REVENT_HEADSEPCLEAR:
        !          1026:                Dprintf2("RECON: HEADSEPCLEAR EVENT: row %d col %d.\n",
        !          1027:                    frow, event->col);
        !          1028:                retcode = rf_TryToRead(raidPtr, frow, event->col);
        !          1029:                break;
        !          1030:
        !          1031:                /* A buffer has become ready to write. */
        !          1032:        case RF_REVENT_BUFREADY:
        !          1033:                Dprintf2("RECON: BUFREADY EVENT: row %d col %d.\n",
        !          1034:                    frow, event->col);
        !          1035:                retcode = rf_IssueNextWriteRequest(raidPtr, frow);
        !          1036:                if (rf_floatingRbufDebug) {
        !          1037:                        rf_CheckFloatingRbufCount(raidPtr, 1);
        !          1038:                }
        !          1039:                break;
        !          1040:
        !          1041:                /*
        !          1042:                 * We need to skip the current RU entirely because it got
        !          1043:                 * recon'd while we were waiting for something else to happen.
        !          1044:                 */
        !          1045:        case RF_REVENT_SKIP:
        !          1046:                DDprintf2("RECON: SKIP EVENT: row %d col %d.\n",
        !          1047:                    frow, event->col);
        !          1048:                retcode = rf_IssueNextReadRequest(raidPtr, frow, event->col);
        !          1049:                break;
        !          1050:
        !          1051:                /*
        !          1052:                 * A forced-reconstruction read access has completed. Just
        !          1053:                 * submit the buffer.
        !          1054:                 */
        !          1055:        case RF_REVENT_FORCEDREADDONE:
        !          1056:                rbuf = (RF_ReconBuffer_t *) event->arg;
        !          1057:                rf_FreeDiskQueueData((RF_DiskQueueData_t *) rbuf->arg);
        !          1058:                DDprintf2("RECON: FORCEDREADDONE EVENT: row %d col %d.\n",
        !          1059:                    frow, event->col);
        !          1060:                submitblocked = rf_SubmitReconBuffer(rbuf, 1, 0);
        !          1061:                RF_ASSERT(!submitblocked);
        !          1062:                break;
        !          1063:
        !          1064:        default:
        !          1065:                RF_PANIC();
        !          1066:        }
        !          1067:        rf_FreeReconEventDesc(event);
        !          1068:        return (retcode);
        !          1069: }
        !          1070:
        !          1071: /*****************************************************************************
        !          1072:  *
        !          1073:  * Find the next thing that's needed on the indicated disk, and issue
        !          1074:  * a read request for it. We assume that the reconstruction buffer
        !          1075:  * associated with this process is free to receive the data. If
        !          1076:  * reconstruction is blocked on the indicated RU, we issue a
        !          1077:  * blockage-release request instead of a physical disk read request.
        !          1078:  * If the current disk gets too far ahead of the others, we issue a
        !          1079:  * head-separation wait request and return.
        !          1080:  *
        !          1081:  * ctrl->{ru_count, curPSID, diskOffset} and
        !          1082:  * rbuf->failedDiskSectorOffset are maintained to point to the unit
        !          1083:  * we're currently accessing. Note that this deviates from the
        !          1084:  * standard C idiom of having counters point to the next thing to be
        !          1085:  * accessed. This allows us to easily retry when we're blocked by
        !          1086:  * head separation or reconstruction-blockage events.
        !          1087:  *
        !          1088:  * Returns nonzero if and only if there is nothing left unread on the
        !          1089:  * indicated disk.
        !          1090:  *
        !          1091:  *****************************************************************************/
        !          1092: int
        !          1093: rf_IssueNextReadRequest(RF_Raid_t *raidPtr, RF_RowCol_t row, RF_RowCol_t col)
        !          1094: {
        !          1095:        RF_PerDiskReconCtrl_t *ctrl =
        !          1096:            &raidPtr->reconControl[row]->perDiskInfo[col];
        !          1097:        RF_RaidLayout_t *layoutPtr = &raidPtr->Layout;
        !          1098:        RF_ReconBuffer_t *rbuf = ctrl->rbuf;
        !          1099:        RF_ReconUnitCount_t RUsPerPU =
        !          1100:            layoutPtr->SUsPerPU / layoutPtr->SUsPerRU;
        !          1101:        RF_SectorCount_t sectorsPerRU =
        !          1102:            layoutPtr->sectorsPerStripeUnit * layoutPtr->SUsPerRU;
        !          1103:        int do_new_check = 0, retcode = 0, status;
        !          1104:
        !          1105:        /*
        !          1106:         * If we are currently the slowest disk, mark that we have to do a new
        !          1107:         * check.
        !          1108:         */
        !          1109:        if (ctrl->headSepCounter <=
        !          1110:            raidPtr->reconControl[row]->minHeadSepCounter)
        !          1111:                do_new_check = 1;
        !          1112:
        !          1113:        while (1) {
        !          1114:
        !          1115:                ctrl->ru_count++;
        !          1116:                if (ctrl->ru_count < RUsPerPU) {
        !          1117:                        ctrl->diskOffset += sectorsPerRU;
        !          1118:                        rbuf->failedDiskSectorOffset += sectorsPerRU;
        !          1119:                } else {
        !          1120:                        ctrl->curPSID++;
        !          1121:                        ctrl->ru_count = 0;
        !          1122:                        /* code left over from when head-sep was based on
        !          1123:                         * parity stripe id */
        !          1124:                        if (ctrl->curPSID >=
        !          1125:                            raidPtr->reconControl[row]->lastPSID) {
        !          1126:                                rf_CheckForNewMinHeadSep(raidPtr, row,
        !          1127:                                    ++(ctrl->headSepCounter));
        !          1128:                                return (1);     /* Finito ! */
        !          1129:                        }
        !          1130:                        /*
        !          1131:                         * Find the disk offsets of the start of the parity
        !          1132:                         * stripe on both the current disk and the failed
        !          1133:                         * disk. Skip this entire parity stripe if either disk
        !          1134:                         * does not appear in the indicated PS.
        !          1135:                         */
        !          1136:                        status = rf_ComputePSDiskOffsets(raidPtr,
        !          1137:                            ctrl->curPSID, row, col, &ctrl->diskOffset,
        !          1138:                            &rbuf->failedDiskSectorOffset, &rbuf->spRow,
        !          1139:                            &rbuf->spCol, &rbuf->spOffset);
        !          1140:                        if (status) {
        !          1141:                                ctrl->ru_count = RUsPerPU - 1;
        !          1142:                                continue;
        !          1143:                        }
        !          1144:                }
        !          1145:                rbuf->which_ru = ctrl->ru_count;
        !          1146:
        !          1147:                /* Skip this RU if it's already been reconstructed. */
        !          1148:                if (rf_CheckRUReconstructed(raidPtr->reconControl[row]
        !          1149:                    ->reconMap, rbuf->failedDiskSectorOffset)) {
        !          1150:                        Dprintf2("Skipping psid %ld ru %d: already"
        !          1151:                            " reconstructed.\n", ctrl->curPSID, ctrl->ru_count);
        !          1152:                        continue;
        !          1153:                }
        !          1154:                break;
        !          1155:        }
        !          1156:        ctrl->headSepCounter++;
        !          1157:        if (do_new_check)       /* Update min if needed. */
        !          1158:                rf_CheckForNewMinHeadSep(raidPtr, row, ctrl->headSepCounter);
        !          1159:
        !          1160:
        !          1161:        /*
        !          1162:         * At this point, we have definitely decided what to do, and we have
        !          1163:         * only to see if we can actually do it now.
        !          1164:         */
        !          1165:        rbuf->parityStripeID = ctrl->curPSID;
        !          1166:        rbuf->which_ru = ctrl->ru_count;
        !          1167:        bzero((char *) &raidPtr->recon_tracerecs[col],
        !          1168:            sizeof(raidPtr->recon_tracerecs[col]));
        !          1169:        raidPtr->recon_tracerecs[col].reconacc = 1;
        !          1170:        RF_ETIMER_START(raidPtr->recon_tracerecs[col].recon_timer);
        !          1171:        retcode = rf_TryToRead(raidPtr, row, col);
        !          1172:        return (retcode);
        !          1173: }
        !          1174:
        !          1175: /*
        !          1176:  * Tries to issue the next read on the indicated disk. We may be
        !          1177:  * blocked by (a) the heads being too far apart, or (b) recon on the
        !          1178:  * indicated RU being blocked due to a write by a user thread. In
        !          1179:  * this case, we issue a head-sep or blockage wait request, which will
        !          1180:  * cause this same routine to be invoked again later when the blockage
        !          1181:  * has cleared.
        !          1182:  */
        !          1183:
        !          1184: int
        !          1185: rf_TryToRead(RF_Raid_t *raidPtr, RF_RowCol_t row, RF_RowCol_t col)
        !          1186: {
        !          1187:        RF_PerDiskReconCtrl_t *ctrl =
        !          1188:            &raidPtr->reconControl[row]->perDiskInfo[col];
        !          1189:        RF_SectorCount_t sectorsPerRU =
        !          1190:            raidPtr->Layout.sectorsPerStripeUnit * raidPtr->Layout.SUsPerRU;
        !          1191:        RF_StripeNum_t psid = ctrl->curPSID;
        !          1192:        RF_ReconUnitNum_t which_ru = ctrl->ru_count;
        !          1193:        RF_DiskQueueData_t *req;
        !          1194:        int status, created = 0;
        !          1195:        RF_ReconParityStripeStatus_t *pssPtr;
        !          1196:
        !          1197:        /*
        !          1198:         * If the current disk is too far ahead of the others, issue a
        !          1199:         * head-separation wait and return.
        !          1200:         */
        !          1201:        if (rf_CheckHeadSeparation(raidPtr, ctrl, row, col,
        !          1202:            ctrl->headSepCounter, which_ru))
        !          1203:                return (0);
        !          1204:        RF_LOCK_PSS_MUTEX(raidPtr, row, psid);
        !          1205:        pssPtr = rf_LookupRUStatus(raidPtr, raidPtr->reconControl[row]
        !          1206:            ->pssTable, psid, which_ru, RF_PSS_CREATE, &created);
        !          1207:
        !          1208:        /*
        !          1209:         * If recon is blocked on the indicated parity stripe, issue a
        !          1210:         * block-wait request and return. This also must mark the indicated RU
        !          1211:         * in the stripe as under reconstruction if not blocked.
        !          1212:         */
        !          1213:        status = rf_CheckForcedOrBlockedReconstruction(raidPtr, pssPtr, ctrl,
        !          1214:            row, col, psid, which_ru);
        !          1215:        if (status == RF_PSS_RECON_BLOCKED) {
        !          1216:                Dprintf2("RECON: Stalling psid %ld ru %d: recon blocked.\n",
        !          1217:                    psid, which_ru);
        !          1218:                goto out;
        !          1219:        } else
        !          1220:                if (status == RF_PSS_FORCED_ON_WRITE) {
        !          1221:                        rf_CauseReconEvent(raidPtr, row, col, NULL,
        !          1222:                            RF_REVENT_SKIP);
        !          1223:                        goto out;
        !          1224:                }
        !          1225:        /*
        !          1226:         * Make one last check to be sure that the indicated RU didn't get
        !          1227:         * reconstructed while we were waiting for something else to happen.
        !          1228:         * This is unfortunate in that it causes us to make this check twice
        !          1229:         * in the normal case. Might want to make some attempt to re-work
        !          1230:         * this so that we only do this check if we've definitely blocked on
        !          1231:         * one of the above checks. When this condition is detected, we may
        !          1232:         * have just created a bogus status entry, which we need to delete.
        !          1233:         */
        !          1234:        if (rf_CheckRUReconstructed(raidPtr->reconControl[row]->reconMap,
        !          1235:            ctrl->rbuf->failedDiskSectorOffset)) {
        !          1236:                Dprintf2("RECON: Skipping psid %ld ru %d: prior recon after"
        !          1237:                    " stall.\n", psid, which_ru);
        !          1238:                if (created)
        !          1239:                        rf_PSStatusDelete(raidPtr,
        !          1240:                            raidPtr->reconControl[row]->pssTable, pssPtr);
        !          1241:                rf_CauseReconEvent(raidPtr, row, col, NULL, RF_REVENT_SKIP);
        !          1242:                goto out;
        !          1243:        }
        !          1244:        /* Found something to read. Issue the I/O. */
        !          1245:        Dprintf5("RECON: Read for psid %ld on row %d col %d offset %ld"
        !          1246:            " buf %lx.\n", psid, row, col, ctrl->diskOffset,
        !          1247:            ctrl->rbuf->buffer);
        !          1248:        RF_ETIMER_STOP(raidPtr->recon_tracerecs[col].recon_timer);
        !          1249:        RF_ETIMER_EVAL(raidPtr->recon_tracerecs[col].recon_timer);
        !          1250:        raidPtr->recon_tracerecs[col].specific.recon.recon_start_to_fetch_us =
        !          1251:            RF_ETIMER_VAL_US(raidPtr->recon_tracerecs[col].recon_timer);
        !          1252:        RF_ETIMER_START(raidPtr->recon_tracerecs[col].recon_timer);
        !          1253:
        !          1254:        /*
        !          1255:         * Should be ok to use a NULL proc pointer here, all the bufs we use
        !          1256:         * should be in kernel space.
        !          1257:         */
        !          1258:        req = rf_CreateDiskQueueData(RF_IO_TYPE_READ, ctrl->diskOffset,
        !          1259:            sectorsPerRU, ctrl->rbuf->buffer, psid, which_ru,
        !          1260:            rf_ReconReadDoneProc, (void *) ctrl, NULL,
        !          1261:            &raidPtr->recon_tracerecs[col], (void *) raidPtr, 0, NULL);
        !          1262:
        !          1263:        RF_ASSERT(req);         /* XXX -- Fix this. -- XXX */
        !          1264:
        !          1265:        ctrl->rbuf->arg = (void *) req;
        !          1266:        rf_DiskIOEnqueue(&raidPtr->Queues[row][col], req, RF_IO_RECON_PRIORITY);
        !          1267:        pssPtr->issued[col] = 1;
        !          1268:
        !          1269: out:
        !          1270:        RF_UNLOCK_PSS_MUTEX(raidPtr, row, psid);
        !          1271:        return (0);
        !          1272: }
        !          1273:
        !          1274:
        !          1275: /*
        !          1276:  * Given a parity stripe ID, we want to find out whether both the
        !          1277:  * current disk and the failed disk exist in that parity stripe. If
        !          1278:  * not, we want to skip this whole PS. If so, we want to find the
        !          1279:  * disk offset of the start of the PS on both the current disk and the
        !          1280:  * failed disk.
        !          1281:  *
        !          1282:  * This works by getting a list of disks comprising the indicated
        !          1283:  * parity stripe, and searching the list for the current and failed
        !          1284:  * disks. Once we've decided they both exist in the parity stripe, we
        !          1285:  * need to decide whether each is data or parity, so that we'll know
        !          1286:  * which mapping function to call to get the corresponding disk
        !          1287:  * offsets.
        !          1288:  *
        !          1289:  * This is kind of unpleasant, but doing it this way allows the
        !          1290:  * reconstruction code to use parity stripe IDs rather than physical
        !          1291:  * disks address to march through the failed disk, which greatly
        !          1292:  * simplifies a lot of code, as well as eliminating the need for a
        !          1293:  * reverse-mapping function. I also think it will execute faster,
        !          1294:  * since the calls to the mapping module are kept to a minimum.
        !          1295:  *
        !          1296:  * ASSUMES THAT THE STRIPE IDENTIFIER IDENTIFIES THE DISKS COMPRISING
        !          1297:  * THE STRIPE IN THE CORRECT ORDER.
        !          1298:  */
        !          1299:
        !          1300: int
        !          1301: rf_ComputePSDiskOffsets(
        !          1302:     RF_Raid_t          *raidPtr,       /* RAID descriptor. */
        !          1303:     RF_StripeNum_t      psid,          /* Parity stripe identifier. */
        !          1304:     RF_RowCol_t                 row,           /*
        !          1305:                                         * Row and column of disk to find
        !          1306:                                         * the offsets for.
        !          1307:                                         */
        !          1308:     RF_RowCol_t                 col,
        !          1309:     RF_SectorNum_t     *outDiskOffset,
        !          1310:     RF_SectorNum_t     *outFailedDiskSectorOffset,
        !          1311:     RF_RowCol_t                *spRow,         /*
        !          1312:                                         * OUT: Row,col of spare unit for
        !          1313:                                         * failed unit.
        !          1314:                                         */
        !          1315:     RF_RowCol_t                *spCol,
        !          1316:     RF_SectorNum_t     *spOffset       /*
        !          1317:                                         * OUT: Offset into disk containing
        !          1318:                                         * spare unit.
        !          1319:                                         */
        !          1320: )
        !          1321: {
        !          1322:        RF_RaidLayout_t *layoutPtr = &raidPtr->Layout;
        !          1323:        RF_RowCol_t fcol = raidPtr->reconControl[row]->fcol;
        !          1324:        RF_RaidAddr_t sosRaidAddress;   /* start-of-stripe */
        !          1325:        RF_RowCol_t *diskids;
        !          1326:        u_int i, j, k, i_offset, j_offset;
        !          1327:        RF_RowCol_t prow, pcol;
        !          1328:        int testcol, testrow;
        !          1329:        RF_RowCol_t stripe;
        !          1330:        RF_SectorNum_t poffset;
        !          1331:        char i_is_parity = 0, j_is_parity = 0;
        !          1332:        RF_RowCol_t stripeWidth =
        !          1333:            layoutPtr->numDataCol + layoutPtr->numParityCol;
        !          1334:
        !          1335:        /* Get a listing of the disks comprising that stripe. */
        !          1336:        sosRaidAddress = rf_ParityStripeIDToRaidAddress(layoutPtr, psid);
        !          1337:        (layoutPtr->map->IdentifyStripe) (raidPtr, sosRaidAddress, &diskids,
        !          1338:            &stripe);
        !          1339:        RF_ASSERT(diskids);
        !          1340:
        !          1341:        /*
        !          1342:         * Reject this entire parity stripe if it does not contain the
        !          1343:         * indicated disk or it does not contain the failed disk.
        !          1344:         */
        !          1345:        if (row != stripe)
        !          1346:                goto skipit;
        !          1347:        for (i = 0; i < stripeWidth; i++) {
        !          1348:                if (col == diskids[i])
        !          1349:                        break;
        !          1350:        }
        !          1351:        if (i == stripeWidth)
        !          1352:                goto skipit;
        !          1353:        for (j = 0; j < stripeWidth; j++) {
        !          1354:                if (fcol == diskids[j])
        !          1355:                        break;
        !          1356:        }
        !          1357:        if (j == stripeWidth) {
        !          1358:                goto skipit;
        !          1359:        }
        !          1360:        /* Find out which disk the parity is on. */
        !          1361:        (layoutPtr->map->MapParity) (raidPtr, sosRaidAddress, &prow, &pcol,
        !          1362:            &poffset, RF_DONT_REMAP);
        !          1363:
        !          1364:        /* Find out if either the current RU or the failed RU is parity. */
        !          1365:        /*
        !          1366:         * Also, if the parity occurs in this stripe prior to the data and/or
        !          1367:         * failed col, we need to decrement i and/or j.
        !          1368:         */
        !          1369:        for (k = 0; k < stripeWidth; k++)
        !          1370:                if (diskids[k] == pcol)
        !          1371:                        break;
        !          1372:        RF_ASSERT(k < stripeWidth);
        !          1373:        i_offset = i;
        !          1374:        j_offset = j;
        !          1375:        if (k < i)
        !          1376:                i_offset--;
        !          1377:        else
        !          1378:                if (k == i) {
        !          1379:                        i_is_parity = 1;
        !          1380:                        i_offset = 0;
        !          1381:                }               /*
        !          1382:                                 * Set offsets to zero to disable multiply
        !          1383:                                 * below.
        !          1384:                                 */
        !          1385:        if (k < j)
        !          1386:                j_offset--;
        !          1387:        else
        !          1388:                if (k == j) {
        !          1389:                        j_is_parity = 1;
        !          1390:                        j_offset = 0;
        !          1391:                }
        !          1392:        /*
        !          1393:         * At this point, [ij]_is_parity tells us whether the [current,failed]
        !          1394:         * disk is parity at the start of this RU, and, if data, "[ij]_offset"
        !          1395:         * tells us how far into the stripe the [current,failed] disk is.
        !          1396:         */
        !          1397:
        !          1398:        /*
        !          1399:         * Call the mapping routine to get the offset into the current disk,
        !          1400:         * repeat for failed disk.
        !          1401:         */
        !          1402:        if (i_is_parity)
        !          1403:                layoutPtr->map->MapParity(raidPtr, sosRaidAddress + i_offset *
        !          1404:                    layoutPtr->sectorsPerStripeUnit, &testrow, &testcol,
        !          1405:                    outDiskOffset, RF_DONT_REMAP);
        !          1406:        else
        !          1407:                layoutPtr->map->MapSector(raidPtr, sosRaidAddress + i_offset *
        !          1408:                    layoutPtr->sectorsPerStripeUnit, &testrow, &testcol,
        !          1409:                    outDiskOffset, RF_DONT_REMAP);
        !          1410:
        !          1411:        RF_ASSERT(row == testrow && col == testcol);
        !          1412:
        !          1413:        if (j_is_parity)
        !          1414:                layoutPtr->map->MapParity(raidPtr, sosRaidAddress + j_offset *
        !          1415:                    layoutPtr->sectorsPerStripeUnit, &testrow, &testcol,
        !          1416:                    outFailedDiskSectorOffset, RF_DONT_REMAP);
        !          1417:        else
        !          1418:                layoutPtr->map->MapSector(raidPtr, sosRaidAddress + j_offset *
        !          1419:                    layoutPtr->sectorsPerStripeUnit, &testrow, &testcol,
        !          1420:                    outFailedDiskSectorOffset, RF_DONT_REMAP);
        !          1421:        RF_ASSERT(row == testrow && fcol == testcol);
        !          1422:
        !          1423:        /* Now locate the spare unit for the failed unit. */
        !          1424:        if (layoutPtr->map->flags & RF_DISTRIBUTE_SPARE) {
        !          1425:                if (j_is_parity)
        !          1426:                        layoutPtr->map->MapParity(raidPtr, sosRaidAddress +
        !          1427:                            j_offset * layoutPtr->sectorsPerStripeUnit, spRow,
        !          1428:                            spCol, spOffset, RF_REMAP);
        !          1429:                else
        !          1430:                        layoutPtr->map->MapSector(raidPtr, sosRaidAddress +
        !          1431:                            j_offset * layoutPtr->sectorsPerStripeUnit, spRow,
        !          1432:                            spCol, spOffset, RF_REMAP);
        !          1433:        } else {
        !          1434:                *spRow = raidPtr->reconControl[row]->spareRow;
        !          1435:                *spCol = raidPtr->reconControl[row]->spareCol;
        !          1436:                *spOffset = *outFailedDiskSectorOffset;
        !          1437:        }
        !          1438:
        !          1439:        return (0);
        !          1440:
        !          1441: skipit:
        !          1442:        Dprintf3("RECON: Skipping psid %ld: nothing needed from r%d c%d.\n",
        !          1443:            psid, row, col);
        !          1444:        return (1);
        !          1445: }
        !          1446:
        !          1447:
        !          1448: /*
        !          1449:  * This is called when a buffer has become ready to write to the replacement
        !          1450:  * disk.
        !          1451:  */
        !          1452: int
        !          1453: rf_IssueNextWriteRequest(RF_Raid_t *raidPtr, RF_RowCol_t row)
        !          1454: {
        !          1455:        RF_RaidLayout_t *layoutPtr = &raidPtr->Layout;
        !          1456:        RF_SectorCount_t sectorsPerRU =
        !          1457:            layoutPtr->sectorsPerStripeUnit * layoutPtr->SUsPerRU;
        !          1458:        RF_RowCol_t fcol = raidPtr->reconControl[row]->fcol;
        !          1459:        RF_ReconBuffer_t *rbuf;
        !          1460:        RF_DiskQueueData_t *req;
        !          1461:
        !          1462:        rbuf = rf_GetFullReconBuffer(raidPtr->reconControl[row]);
        !          1463:        RF_ASSERT(rbuf);        /*
        !          1464:                                 * There must be one available, or we wouldn't
        !          1465:                                 * have gotten the event that sent us here.
        !          1466:                                 */
        !          1467:        RF_ASSERT(rbuf->pssPtr);
        !          1468:
        !          1469:        rbuf->pssPtr->writeRbuf = rbuf;
        !          1470:        rbuf->pssPtr = NULL;
        !          1471:
        !          1472:        Dprintf7("RECON: New write (r %d c %d offs %d) for psid %ld ru %d"
        !          1473:            " (failed disk offset %ld) buf %lx.\n",
        !          1474:            rbuf->spRow, rbuf->spCol, rbuf->spOffset, rbuf->parityStripeID,
        !          1475:            rbuf->which_ru, rbuf->failedDiskSectorOffset, rbuf->buffer);
        !          1476:        Dprintf6("RECON: new write psid %ld   %02x %02x %02x %02x %02x.\n",
        !          1477:            rbuf->parityStripeID, rbuf->buffer[0] & 0xff,
        !          1478:            rbuf->buffer[1] & 0xff, rbuf->buffer[2] & 0xff,
        !          1479:            rbuf->buffer[3] & 0xff, rbuf->buffer[4] & 0xff);
        !          1480:
        !          1481:        /*
        !          1482:         * Should be ok to use a NULL b_proc here b/c all addrs should be in
        !          1483:         * kernel space.
        !          1484:         */
        !          1485:        req = rf_CreateDiskQueueData(RF_IO_TYPE_WRITE, rbuf->spOffset,
        !          1486:            sectorsPerRU, rbuf->buffer, rbuf->parityStripeID, rbuf->which_ru,
        !          1487:            rf_ReconWriteDoneProc, (void *) rbuf, NULL,
        !          1488:            &raidPtr->recon_tracerecs[fcol], (void *) raidPtr, 0, NULL);
        !          1489:
        !          1490:        RF_ASSERT(req);         /* XXX -- Fix this. -- XXX */
        !          1491:
        !          1492:        rbuf->arg = (void *) req;
        !          1493:        rf_DiskIOEnqueue(&raidPtr->Queues[rbuf->spRow][rbuf->spCol], req,
        !          1494:            RF_IO_RECON_PRIORITY);
        !          1495:
        !          1496:        return (0);
        !          1497: }
        !          1498:
        !          1499: /*
        !          1500:  * This gets called upon the completion of a reconstruction read
        !          1501:  * operation. The arg is a pointer to the per-disk reconstruction
        !          1502:  * control structure for the process that just finished a read.
        !          1503:  *
        !          1504:  * Called at interrupt context in the kernel, so don't do anything
        !          1505:  * illegal here.
        !          1506:  */
        !          1507: int
        !          1508: rf_ReconReadDoneProc(void *arg, int status)
        !          1509: {
        !          1510:        RF_PerDiskReconCtrl_t *ctrl = (RF_PerDiskReconCtrl_t *) arg;
        !          1511:        RF_Raid_t *raidPtr = ctrl->reconCtrl->reconDesc->raidPtr;
        !          1512:
        !          1513:        if (status) {
        !          1514:                /*
        !          1515:                 * XXX
        !          1516:                 */
        !          1517:                printf("Recon read failed !\n");
        !          1518:                RF_PANIC();
        !          1519:        }
        !          1520:        RF_ETIMER_STOP(raidPtr->recon_tracerecs[ctrl->col].recon_timer);
        !          1521:        RF_ETIMER_EVAL(raidPtr->recon_tracerecs[ctrl->col].recon_timer);
        !          1522:        raidPtr->recon_tracerecs[ctrl->col].specific.recon.
        !          1523:           recon_fetch_to_return_us =
        !          1524:             RF_ETIMER_VAL_US(raidPtr->recon_tracerecs[ctrl->col].recon_timer);
        !          1525:        RF_ETIMER_START(raidPtr->recon_tracerecs[ctrl->col].recon_timer);
        !          1526:
        !          1527:        rf_CauseReconEvent(raidPtr, ctrl->row, ctrl->col, NULL,
        !          1528:            RF_REVENT_READDONE);
        !          1529:        return (0);
        !          1530: }
        !          1531:
        !          1532:
        !          1533: /*
        !          1534:  * This gets called upon the completion of a reconstruction write operation.
        !          1535:  * The arg is a pointer to the rbuf that was just written.
        !          1536:  *
        !          1537:  * Called at interrupt context in the kernel, so don't do anything illegal here.
        !          1538:  */
        !          1539: int
        !          1540: rf_ReconWriteDoneProc(void *arg, int status)
        !          1541: {
        !          1542:        RF_ReconBuffer_t *rbuf = (RF_ReconBuffer_t *) arg;
        !          1543:
        !          1544:        Dprintf2("Reconstruction completed on psid %ld ru %d.\n",
        !          1545:            rbuf->parityStripeID, rbuf->which_ru);
        !          1546:        if (status) {
        !          1547:                /* fprintf(stderr, "Recon write failed !\n"); */
        !          1548:                printf("Recon write failed !\n");
        !          1549:                RF_PANIC();
        !          1550:        }
        !          1551:        rf_CauseReconEvent((RF_Raid_t *) rbuf->raidPtr, rbuf->row, rbuf->col,
        !          1552:            arg, RF_REVENT_WRITEDONE);
        !          1553:        return (0);
        !          1554: }
        !          1555:
        !          1556:
        !          1557: /*
        !          1558:  * Computes a new minimum head sep, and wakes up anyone who needs to
        !          1559:  * be woken as a result.
        !          1560:  */
        !          1561: void
        !          1562: rf_CheckForNewMinHeadSep(RF_Raid_t *raidPtr, RF_RowCol_t row,
        !          1563:     RF_HeadSepLimit_t hsCtr)
        !          1564: {
        !          1565:        RF_ReconCtrl_t *reconCtrlPtr = raidPtr->reconControl[row];
        !          1566:        RF_HeadSepLimit_t new_min;
        !          1567:        RF_RowCol_t i;
        !          1568:        RF_CallbackDesc_t *p;
        !          1569:        /* From the definition of a minimum. */
        !          1570:        RF_ASSERT(hsCtr >= reconCtrlPtr->minHeadSepCounter);
        !          1571:
        !          1572:
        !          1573:        RF_LOCK_MUTEX(reconCtrlPtr->rb_mutex);
        !          1574:
        !          1575:        new_min = ~(1L << (8 * sizeof(long) - 1));      /* 0x7FFF....FFF */
        !          1576:        for (i = 0; i < raidPtr->numCol; i++)
        !          1577:                if (i != reconCtrlPtr->fcol) {
        !          1578:                        if (reconCtrlPtr->perDiskInfo[i].headSepCounter <
        !          1579:                            new_min)
        !          1580:                                new_min =
        !          1581:                                    reconCtrlPtr->perDiskInfo[i].headSepCounter;
        !          1582:                }
        !          1583:        /* Set the new minimum and wake up anyone who can now run again. */
        !          1584:        if (new_min != reconCtrlPtr->minHeadSepCounter) {
        !          1585:                reconCtrlPtr->minHeadSepCounter = new_min;
        !          1586:                Dprintf1("RECON:  new min head pos counter val is %ld.\n",
        !          1587:                    new_min);
        !          1588:                while (reconCtrlPtr->headSepCBList) {
        !          1589:                        if (reconCtrlPtr->headSepCBList->callbackArg.v >
        !          1590:                            new_min)
        !          1591:                                break;
        !          1592:                        p = reconCtrlPtr->headSepCBList;
        !          1593:                        reconCtrlPtr->headSepCBList = p->next;
        !          1594:                        p->next = NULL;
        !          1595:                        rf_CauseReconEvent(raidPtr, p->row, p->col, NULL,
        !          1596:                            RF_REVENT_HEADSEPCLEAR);
        !          1597:                        rf_FreeCallbackDesc(p);
        !          1598:                }
        !          1599:
        !          1600:        }
        !          1601:        RF_UNLOCK_MUTEX(reconCtrlPtr->rb_mutex);
        !          1602: }
        !          1603:
        !          1604: /*
        !          1605:  * Checks to see that the maximum head separation will not be violated
        !          1606:  * if we initiate a reconstruction I/O on the indicated disk.
        !          1607:  * Limiting the maximum head separation between two disks eliminates
        !          1608:  * the nasty buffer-stall conditions that occur when one disk races
        !          1609:  * ahead of the others and consumes all of the floating recon buffers.
        !          1610:  * This code is complex and unpleasant but it's necessary to avoid
        !          1611:  * some very nasty, albeit fairly rare, reconstruction behavior.
        !          1612:  *
        !          1613:  * Returns non-zero if and only if we have to stop working on the
        !          1614:  * indicated disk due to a head-separation delay.
        !          1615:  */
        !          1616: int
        !          1617: rf_CheckHeadSeparation(
        !          1618:     RF_Raid_t                  *raidPtr,
        !          1619:     RF_PerDiskReconCtrl_t      *ctrl,
        !          1620:     RF_RowCol_t                         row,
        !          1621:     RF_RowCol_t                         col,
        !          1622:     RF_HeadSepLimit_t           hsCtr,
        !          1623:     RF_ReconUnitNum_t           which_ru
        !          1624: )
        !          1625: {
        !          1626:        RF_ReconCtrl_t *reconCtrlPtr = raidPtr->reconControl[row];
        !          1627:        RF_CallbackDesc_t *cb, *p, *pt;
        !          1628:        int retval = 0;
        !          1629:
        !          1630:        /*
        !          1631:         * If we're too far ahead of the slowest disk, stop working on this
        !          1632:         * disk until the slower ones catch up. We do this by scheduling a
        !          1633:         * wakeup callback for the time when the slowest disk has caught up.
        !          1634:         * We define "caught up" with 20% hysteresis, i.e. the head separation
        !          1635:         * must have fallen to at most 80% of the max allowable head
        !          1636:         * separation before we'll wake up.
        !          1637:         */
        !          1638:        RF_LOCK_MUTEX(reconCtrlPtr->rb_mutex);
        !          1639:        if ((raidPtr->headSepLimit >= 0) &&
        !          1640:            ((ctrl->headSepCounter - reconCtrlPtr->minHeadSepCounter) >
        !          1641:             raidPtr->headSepLimit)) {
        !          1642:                Dprintf6("raid%d: RECON: head sep stall: row %d col %d hsCtr"
        !          1643:                    " %ld minHSCtr %ld limit %ld.\n",
        !          1644:                    raidPtr->raidid, row, col, ctrl->headSepCounter,
        !          1645:                    reconCtrlPtr->minHeadSepCounter, raidPtr->headSepLimit);
        !          1646:                cb = rf_AllocCallbackDesc();
        !          1647:                /*
        !          1648:                 * The minHeadSepCounter value we have to get to before we'll
        !          1649:                 * wake up. Build in 20% hysteresis.
        !          1650:                 */
        !          1651:                cb->callbackArg.v = (ctrl->headSepCounter -
        !          1652:                    raidPtr->headSepLimit + raidPtr->headSepLimit / 5);
        !          1653:                cb->row = row;
        !          1654:                cb->col = col;
        !          1655:                cb->next = NULL;
        !          1656:
        !          1657:                /*
        !          1658:                 * Insert this callback descriptor into the sorted list of
        !          1659:                 * pending head-sep callbacks.
        !          1660:                 */
        !          1661:                p = reconCtrlPtr->headSepCBList;
        !          1662:                if (!p)
        !          1663:                        reconCtrlPtr->headSepCBList = cb;
        !          1664:                else
        !          1665:                        if (cb->callbackArg.v < p->callbackArg.v) {
        !          1666:                                cb->next = reconCtrlPtr->headSepCBList;
        !          1667:                                reconCtrlPtr->headSepCBList = cb;
        !          1668:                        } else {
        !          1669:                                for (pt = p, p = p->next;
        !          1670:                                    p && (p->callbackArg.v < cb->callbackArg.v);
        !          1671:                                    pt = p, p = p->next);
        !          1672:                                cb->next = p;
        !          1673:                                pt->next = cb;
        !          1674:                        }
        !          1675:                retval = 1;
        !          1676: #if    RF_RECON_STATS > 0
        !          1677:                ctrl->reconCtrl->reconDesc->hsStallCount++;
        !          1678: #endif /* RF_RECON_STATS > 0 */
        !          1679:        }
        !          1680:        RF_UNLOCK_MUTEX(reconCtrlPtr->rb_mutex);
        !          1681:
        !          1682:        return (retval);
        !          1683: }
        !          1684:
        !          1685:
        !          1686:
        !          1687: /*
        !          1688:  * Checks to see if reconstruction has been either forced or blocked
        !          1689:  * by a user operation. If forced, we skip this RU entirely. Else if
        !          1690:  * blocked, put ourselves on the wait list. Else return 0.
        !          1691:  *
        !          1692:  * ASSUMES THE PSS MUTEX IS LOCKED UPON ENTRY.
        !          1693:  */
        !          1694: int
        !          1695: rf_CheckForcedOrBlockedReconstruction(
        !          1696:     RF_Raid_t                   *raidPtr,
        !          1697:     RF_ReconParityStripeStatus_t *pssPtr,
        !          1698:     RF_PerDiskReconCtrl_t       *ctrl,
        !          1699:     RF_RowCol_t                          row,
        !          1700:     RF_RowCol_t                          col,
        !          1701:     RF_StripeNum_t               psid,
        !          1702:     RF_ReconUnitNum_t            which_ru
        !          1703: )
        !          1704: {
        !          1705:        RF_CallbackDesc_t *cb;
        !          1706:        int retcode = 0;
        !          1707:
        !          1708:        if ((pssPtr->flags & RF_PSS_FORCED_ON_READ) ||
        !          1709:            (pssPtr->flags & RF_PSS_FORCED_ON_WRITE))
        !          1710:                retcode = RF_PSS_FORCED_ON_WRITE;
        !          1711:        else
        !          1712:                if (pssPtr->flags & RF_PSS_RECON_BLOCKED) {
        !          1713:                        Dprintf4("RECON: row %d col %d blocked at psid %ld"
        !          1714:                            " ru %d.\n", row, col, psid, which_ru);
        !          1715:                        cb = rf_AllocCallbackDesc();    /*
        !          1716:                                                         * Append ourselves to
        !          1717:                                                         * the blockage-wait
        !          1718:                                                         * list.
        !          1719:                                                         */
        !          1720:                        cb->row = row;
        !          1721:                        cb->col = col;
        !          1722:                        cb->next = pssPtr->blockWaitList;
        !          1723:                        pssPtr->blockWaitList = cb;
        !          1724:                        retcode = RF_PSS_RECON_BLOCKED;
        !          1725:                }
        !          1726:        if (!retcode)
        !          1727:                pssPtr->flags |= RF_PSS_UNDER_RECON;    /*
        !          1728:                                                         * Mark this RU as under
        !          1729:                                                         * reconstruction.
        !          1730:                                                         */
        !          1731:
        !          1732:        return (retcode);
        !          1733: }
        !          1734:
        !          1735:
        !          1736: /*
        !          1737:  * If reconstruction is currently ongoing for the indicated stripeID,
        !          1738:  * reconstruction is forced to completion and we return non-zero to
        !          1739:  * indicate that the caller must wait. If not, then reconstruction is
        !          1740:  * blocked on the indicated stripe and the routine returns zero. If
        !          1741:  * and only if we return non-zero, we'll cause the cbFunc to get
        !          1742:  * invoked with the cbArg when the reconstruction has completed.
        !          1743:  */
        !          1744: int
        !          1745: rf_ForceOrBlockRecon(RF_Raid_t *raidPtr, RF_AccessStripeMap_t *asmap,
        !          1746:        void (*cbFunc) (RF_Raid_t *, void *), void *cbArg)
        !          1747: {
        !          1748:        RF_RowCol_t row = asmap->physInfo->row; /*
        !          1749:                                                 * Which row of the array
        !          1750:                                                 * we're working on.
        !          1751:                                                 */
        !          1752:        RF_StripeNum_t stripeID = asmap->stripeID;      /*
        !          1753:                                                         * The stripe ID we're
        !          1754:                                                         * forcing recon on.
        !          1755:                                                         */
        !          1756:        RF_SectorCount_t sectorsPerRU = raidPtr->Layout.sectorsPerStripeUnit *
        !          1757:            raidPtr->Layout.SUsPerRU;           /* Num sects in one RU. */
        !          1758:        RF_ReconParityStripeStatus_t *pssPtr;   /*
        !          1759:                                                 * A pointer to the parity
        !          1760:                                                 * stripe status structure.
        !          1761:                                                 */
        !          1762:        RF_StripeNum_t psid;                    /* Parity stripe id. */
        !          1763:        RF_SectorNum_t offset, fd_offset;       /*
        !          1764:                                                 * Disk offset, failed-disk
        !          1765:                                                 * offset.
        !          1766:                                                 */
        !          1767:        RF_RowCol_t *diskids;
        !          1768:        RF_RowCol_t stripe;
        !          1769:        RF_ReconUnitNum_t which_ru;     /* RU within parity stripe. */
        !          1770:        RF_RowCol_t fcol, diskno, i;
        !          1771:        RF_ReconBuffer_t *new_rbuf;     /* Ptr to newly allocated rbufs. */
        !          1772:        RF_DiskQueueData_t *req;        /* Disk I/O req to be enqueued. */
        !          1773:        RF_CallbackDesc_t *cb;
        !          1774:        int created = 0, nPromoted;
        !          1775:
        !          1776:        psid = rf_MapStripeIDToParityStripeID(&raidPtr->Layout, stripeID,
        !          1777:            &which_ru);
        !          1778:
        !          1779:        RF_LOCK_PSS_MUTEX(raidPtr, row, psid);
        !          1780:
        !          1781:        pssPtr = rf_LookupRUStatus(raidPtr,
        !          1782:            raidPtr->reconControl[row]->pssTable, psid, which_ru,
        !          1783:            RF_PSS_CREATE | RF_PSS_RECON_BLOCKED, &created);
        !          1784:
        !          1785:        /* If recon is not ongoing on this PS, just return. */
        !          1786:        if (!(pssPtr->flags & RF_PSS_UNDER_RECON)) {
        !          1787:                RF_UNLOCK_PSS_MUTEX(raidPtr, row, psid);
        !          1788:                return (0);
        !          1789:        }
        !          1790:        /*
        !          1791:         * Otherwise, we have to wait for reconstruction to complete on this
        !          1792:         * RU.
        !          1793:         */
        !          1794:        /*
        !          1795:         * In order to avoid waiting for a potentially large number of
        !          1796:         * low-priority accesses to complete, we force a normal-priority (i.e.
        !          1797:         * not low-priority) reconstruction on this RU.
        !          1798:         */
        !          1799:        if (!(pssPtr->flags & RF_PSS_FORCED_ON_WRITE) &&
        !          1800:            !(pssPtr->flags & RF_PSS_FORCED_ON_READ)) {
        !          1801:                DDprintf1("Forcing recon on psid %ld.\n", psid);
        !          1802:                /* Mark this RU as under forced recon. */
        !          1803:                pssPtr->flags |= RF_PSS_FORCED_ON_WRITE;
        !          1804:                /* Clear the blockage that we just set. */
        !          1805:                pssPtr->flags &= ~RF_PSS_RECON_BLOCKED;
        !          1806:                fcol = raidPtr->reconControl[row]->fcol;
        !          1807:
        !          1808:                /*
        !          1809:                 * Get a listing of the disks comprising the indicated stripe.
        !          1810:                 */
        !          1811:                (raidPtr->Layout.map->IdentifyStripe) (raidPtr,
        !          1812:                    asmap->raidAddress, &diskids, &stripe);
        !          1813:                RF_ASSERT(row == stripe);
        !          1814:
        !          1815:                /*
        !          1816:                 * For previously issued reads, elevate them to normal
        !          1817:                 * priority. If the I/O has already completed, it won't be
        !          1818:                 * found in the queue, and hence this will be a no-op. For
        !          1819:                 * unissued reads, allocate buffers and issue new reads. The
        !          1820:                 * fact that we've set the FORCED bit means that the regular
        !          1821:                 * recon procs will not re-issue these reqs.
        !          1822:                 */
        !          1823:                for (i = 0; i < raidPtr->Layout.numDataCol +
        !          1824:                    raidPtr->Layout.numParityCol; i++)
        !          1825:                        if ((diskno = diskids[i]) != fcol) {
        !          1826:                                if (pssPtr->issued[diskno]) {
        !          1827:                                        nPromoted = rf_DiskIOPromote(&raidPtr
        !          1828:                                            ->Queues[row][diskno], psid,
        !          1829:                                            which_ru);
        !          1830:                                        if (rf_reconDebug && nPromoted)
        !          1831:                                                printf("raid%d: promoted read"
        !          1832:                                                    " from row %d col %d.\n",
        !          1833:                                                    raidPtr->raidid, row,
        !          1834:                                                    diskno);
        !          1835:                                } else {
        !          1836:                                        /* Create new buf. */
        !          1837:                                        new_rbuf = rf_MakeReconBuffer(raidPtr,
        !          1838:                                            row, diskno, RF_RBUF_TYPE_FORCED);
        !          1839:                                        /* Find offsets & spare locationp */
        !          1840:                                        rf_ComputePSDiskOffsets(raidPtr, psid,
        !          1841:                                            row, diskno, &offset, &fd_offset,
        !          1842:                                            &new_rbuf->spRow, &new_rbuf->spCol,
        !          1843:                                            &new_rbuf->spOffset);
        !          1844:                                        new_rbuf->parityStripeID = psid;
        !          1845:                                        /* Fill in the buffer. */
        !          1846:                                        new_rbuf->which_ru = which_ru;
        !          1847:                                        new_rbuf->failedDiskSectorOffset =
        !          1848:                                            fd_offset;
        !          1849:                                        new_rbuf->priority =
        !          1850:                                            RF_IO_NORMAL_PRIORITY;
        !          1851:
        !          1852:                                        /*
        !          1853:                                         * Use NULL b_proc b/c all addrs
        !          1854:                                         * should be in kernel space.
        !          1855:                                         */
        !          1856:                                        req = rf_CreateDiskQueueData(
        !          1857:                                            RF_IO_TYPE_READ, offset +
        !          1858:                                            which_ru * sectorsPerRU,
        !          1859:                                            sectorsPerRU, new_rbuf->buffer,
        !          1860:                                            psid, which_ru, (int (*)
        !          1861:                                            (void *, int))
        !          1862:                                              rf_ForceReconReadDoneProc,
        !          1863:                                            (void *) new_rbuf, NULL,
        !          1864:                                            NULL, (void *) raidPtr, 0, NULL);
        !          1865:
        !          1866:                                        RF_ASSERT(req); /*
        !          1867:                                                         * XXX -- Fix this. --
        !          1868:                                                         * XXX
        !          1869:                                                         */
        !          1870:
        !          1871:                                        new_rbuf->arg = req;
        !          1872:                                        /* Enqueue the I/O. */
        !          1873:                                        rf_DiskIOEnqueue(&raidPtr
        !          1874:                                            ->Queues[row][diskno], req,
        !          1875:                                            RF_IO_NORMAL_PRIORITY);
        !          1876:                                        Dprintf3("raid%d: Issued new read req"
        !          1877:                                            " on row %d col %d.\n",
        !          1878:                                            raidPtr->raidid, row, diskno);
        !          1879:                                }
        !          1880:                        }
        !          1881:                /*
        !          1882:                 * If the write is sitting in the disk queue, elevate its
        !          1883:                 * priority.
        !          1884:                 */
        !          1885:                if (rf_DiskIOPromote(&raidPtr->Queues[row][fcol],
        !          1886:                    psid, which_ru))
        !          1887:                        printf("raid%d: promoted write to row %d col %d.\n",
        !          1888:                            raidPtr->raidid, row, fcol);
        !          1889:        }
        !          1890:        /*
        !          1891:         * Install a callback descriptor to be invoked when recon completes on
        !          1892:         * this parity stripe.
        !          1893:         */
        !          1894:        cb = rf_AllocCallbackDesc();
        !          1895:        /*
        !          1896:         * XXX The following is bogus... These functions don't really match !!!
        !          1897:         * GO
        !          1898:         */
        !          1899:        cb->callbackFunc = (void (*) (RF_CBParam_t)) cbFunc;
        !          1900:        cb->callbackArg.p = (void *) cbArg;
        !          1901:        cb->next = pssPtr->procWaitList;
        !          1902:        pssPtr->procWaitList = cb;
        !          1903:        DDprintf2("raid%d: Waiting for forced recon on psid %ld.\n",
        !          1904:            raidPtr->raidid, psid);
        !          1905:
        !          1906:        RF_UNLOCK_PSS_MUTEX(raidPtr, row, psid);
        !          1907:        return (1);
        !          1908: }
        !          1909:
        !          1910:
        !          1911: /*
        !          1912:  * Called upon the completion of a forced reconstruction read.
        !          1913:  * All we do is schedule the FORCEDREADONE event.
        !          1914:  * Called at interrupt context in the kernel, so don't do anything illegal here.
        !          1915:  */
        !          1916: void
        !          1917: rf_ForceReconReadDoneProc(void *arg, int status)
        !          1918: {
        !          1919:        RF_ReconBuffer_t *rbuf = arg;
        !          1920:
        !          1921:        if (status) {
        !          1922:                /* fprintf(stderr, "Forced recon read failed !\n"); */
        !          1923:                printf("Forced recon read failed !\n");
        !          1924:                RF_PANIC();
        !          1925:        }
        !          1926:        rf_CauseReconEvent((RF_Raid_t *) rbuf->raidPtr, rbuf->row, rbuf->col,
        !          1927:            (void *) rbuf, RF_REVENT_FORCEDREADDONE);
        !          1928: }
        !          1929:
        !          1930:
        !          1931: /* Releases a block on the reconstruction of the indicated stripe. */
        !          1932: int
        !          1933: rf_UnblockRecon(RF_Raid_t *raidPtr, RF_AccessStripeMap_t *asmap)
        !          1934: {
        !          1935:        RF_RowCol_t row = asmap->origRow;
        !          1936:        RF_StripeNum_t stripeID = asmap->stripeID;
        !          1937:        RF_ReconParityStripeStatus_t *pssPtr;
        !          1938:        RF_ReconUnitNum_t which_ru;
        !          1939:        RF_StripeNum_t psid;
        !          1940:        int created = 0;
        !          1941:        RF_CallbackDesc_t *cb;
        !          1942:
        !          1943:        psid = rf_MapStripeIDToParityStripeID(&raidPtr->Layout, stripeID,
        !          1944:            &which_ru);
        !          1945:        RF_LOCK_PSS_MUTEX(raidPtr, row, psid);
        !          1946:        pssPtr = rf_LookupRUStatus(raidPtr, raidPtr->reconControl[row]
        !          1947:            ->pssTable, psid, which_ru, RF_PSS_NONE, &created);
        !          1948:
        !          1949:        /*
        !          1950:         * When recon is forced, the pss desc can get deleted before we get
        !          1951:         * back to unblock recon. But, this can _only_ happen when recon is
        !          1952:         * forced. It would be good to put some kind of sanity check here, but
        !          1953:         * how to decide if recon was just forced or not ?
        !          1954:         */
        !          1955:        if (!pssPtr) {
        !          1956:                /*
        !          1957:                 * printf("Warning: no pss descriptor upon unblock on psid %ld"
        !          1958:                 *     " RU %d.\n", psid, which_ru);
        !          1959:                 */
        !          1960:                if (rf_reconDebug || rf_pssDebug)
        !          1961:                        printf("Warning: no pss descriptor upon unblock on"
        !          1962:                            " psid %ld RU %d.\n", (long) psid, which_ru);
        !          1963:                goto out;
        !          1964:        }
        !          1965:        pssPtr->blockCount--;
        !          1966:        Dprintf3("raid%d: unblocking recon on psid %ld: blockcount is %d.\n",
        !          1967:            raidPtr->raidid, psid, pssPtr->blockCount);
        !          1968:        if (pssPtr->blockCount == 0) {
        !          1969:                /* If recon blockage has been released. */
        !          1970:
        !          1971:                /*
        !          1972:                 * Unblock recon before calling CauseReconEvent in case
        !          1973:                 * CauseReconEvent causes us to try to issue a new read before
        !          1974:                 * returning here.
        !          1975:                 */
        !          1976:                pssPtr->flags &= ~RF_PSS_RECON_BLOCKED;
        !          1977:
        !          1978:
        !          1979:                while (pssPtr->blockWaitList) {
        !          1980:                        /*
        !          1981:                         * Spin through the block-wait list and
        !          1982:                         * release all the waiters.
        !          1983:                         */
        !          1984:                        cb = pssPtr->blockWaitList;
        !          1985:                        pssPtr->blockWaitList = cb->next;
        !          1986:                        cb->next = NULL;
        !          1987:                        rf_CauseReconEvent(raidPtr, cb->row, cb->col, NULL,
        !          1988:                            RF_REVENT_BLOCKCLEAR);
        !          1989:                        rf_FreeCallbackDesc(cb);
        !          1990:                }
        !          1991:                if (!(pssPtr->flags & RF_PSS_UNDER_RECON)) {
        !          1992:                        /* If no recon was requested while recon was blocked. */
        !          1993:                        rf_PSStatusDelete(raidPtr, raidPtr->reconControl[row]
        !          1994:                            ->pssTable, pssPtr);
        !          1995:                }
        !          1996:        }
        !          1997: out:
        !          1998:        RF_UNLOCK_PSS_MUTEX(raidPtr, row, psid);
        !          1999:        return (0);
        !          2000: }

CVSweb