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