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