1 /*	$OpenBSD: rf_declusterPQ.c,v 1.4 2002/12/16 07:01:03 tdeval Exp $	*/
2 /*	$NetBSD: rf_declusterPQ.c,v 1.3 1999/02/05 00:06:09 oster Exp $	*/
3 
4 /*
5  * Copyright (c) 1995 Carnegie-Mellon University.
6  * All rights reserved.
7  *
8  * Authors: Daniel Stodolsky, Mark Holland, Jim Zelenka
9  *
10  * Permission to use, copy, modify and distribute this software and
11  * its documentation is hereby granted, provided that both the copyright
12  * notice and this permission notice appear in all copies of the
13  * software, derivative works or modified versions, and any portions
14  * thereof, and that both notices appear in supporting documentation.
15  *
16  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
17  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
18  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
19  *
20  * Carnegie Mellon requests users of this software to return to
21  *
22  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
23  *  School of Computer Science
24  *  Carnegie Mellon University
25  *  Pittsburgh PA 15213-3890
26  *
27  * any improvements or extensions that they make and grant Carnegie the
28  * rights to redistribute these changes.
29  */
30 
31 /*****************************************************************************
32  * rf_declusterPQ.c
33  *
34  * Mapping code for declustered P & Q or declustered EvenOdd.
35  * Much code borrowed from rf_decluster.c
36  *
37  *****************************************************************************/
38 
39 
40 #include "rf_types.h"
41 #include "rf_raid.h"
42 #include "rf_configure.h"
43 #include "rf_decluster.h"
44 #include "rf_declusterPQ.h"
45 #include "rf_debugMem.h"
46 #include "rf_utils.h"
47 #include "rf_alloclist.h"
48 #include "rf_general.h"
49 
50 /* Configuration code. */
51 
52 int
rf_ConfigureDeclusteredPQ(RF_ShutdownList_t ** listp,RF_Raid_t * raidPtr,RF_Config_t * cfgPtr)53 rf_ConfigureDeclusteredPQ(RF_ShutdownList_t **listp, RF_Raid_t *raidPtr,
54     RF_Config_t *cfgPtr)
55 {
56 	RF_RaidLayout_t *layoutPtr = &(raidPtr->Layout);
57 	int b, v, k, r, lambda;	/* block design params */
58 	int i, j, l;
59 	int *first_avail_slot;
60 	int complete_FT_count, SUID;
61 	RF_DeclusteredConfigInfo_t *info;
62 	int numCompleteFullTablesPerDisk;
63 	int PUsPerDisk, spareRegionDepthInPUs, extraPUsPerDisk;
64 	int numCompleteSpareRegionsPerDisk = 0;
65 	int totSparePUsPerDisk;
66 	int diskOffsetOfLastFullTableInSUs, SpareSpaceInSUs;
67 	char *cfgBuf = (char *)(cfgPtr->layoutSpecific);
68 
69 	cfgBuf += RF_SPAREMAP_NAME_LEN;
70 
71 	b = *((int *) cfgBuf);
72 	cfgBuf += sizeof(int);
73 	v = *((int *) cfgBuf);
74 	cfgBuf += sizeof(int);
75 	k = *((int *) cfgBuf);
76 	cfgBuf += sizeof(int);
77 	r = *((int *) cfgBuf);
78 	cfgBuf += sizeof(int);
79 	lambda = *((int *) cfgBuf);
80 	cfgBuf += sizeof(int);
81 	raidPtr->noRotate = *((int *) cfgBuf);
82 	cfgBuf += sizeof(int);
83 
84 	if (k <= 2) {
85 #ifdef	RAIDDEBUG
86 		printf("RAIDFRAME: k=%d, minimum value 2\n", k);
87 #endif	/* RAIDDEBUG */
88 		return (EINVAL);
89 	}
90 	/* 1. Create layout specific structure. */
91 	RF_MallocAndAdd(info, sizeof(RF_DeclusteredConfigInfo_t),
92 	    (RF_DeclusteredConfigInfo_t *), raidPtr->cleanupList);
93 	if (info == NULL)
94 		return (ENOMEM);
95 	layoutPtr->layoutSpecificInfo = (void *) info;
96 
97 	/*
98 	 * 2. The sparemaps are generated assuming that parity is rotated, so
99 	 * we issue a warning if both distributed sparing and no-rotate are on
100 	 * at the same time.
101 	 */
102 	if ((raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE) &&
103 	    raidPtr->noRotate) {
104 		RF_ERRORMSG("Warning:  distributed sparing specified without"
105 		    " parity rotation.\n");
106 	}
107 	if (raidPtr->numCol != v) {
108 		RF_ERRORMSG2("RAID: config error: table element count (%d)"
109 		    " not equal to no. of cols (%d).\n", v, raidPtr->numCol);
110 		return (EINVAL);
111 	}
112 	/* 3. Set up the values used in devRaidMap. */
113 	info->BlocksPerTable = b;
114 	info->NumParityReps = info->groupSize = k;
115 	info->PUsPerBlock = k - 2;	/* PQ */
116 	info->SUsPerTable = b * info->PUsPerBlock * layoutPtr->SUsPerPU;
117 		/* b blks, k-1 SUs each. */
118 	info->SUsPerFullTable = k * info->SUsPerTable;	/* Rot k times. */
119 	info->SUsPerBlock = info->PUsPerBlock * layoutPtr->SUsPerPU;
120 	info->TableDepthInPUs = (b * k) / v;
121 	info->FullTableDepthInPUs = info->TableDepthInPUs * k;
122 		/* k repetitions. */
123 
124 	/* Used only in distributed sparing case. */
125 	info->FullTablesPerSpareRegion = (v - 1) / rf_gcd(r, v - 1);
126 		/* (v-1)/gcd fulltables. */
127 	info->TablesPerSpareRegion = k * info->FullTablesPerSpareRegion;
128 	info->SpareSpaceDepthPerRegionInSUs = (r * info->TablesPerSpareRegion
129 	    / (v - 1)) * layoutPtr->SUsPerPU;
130 
131 	/* Check to make sure the block design is sufficiently small. */
132 	if ((raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE)) {
133 		if (info->FullTableDepthInPUs * layoutPtr->SUsPerPU +
134 		    info->SpareSpaceDepthPerRegionInSUs >
135 		    layoutPtr->stripeUnitsPerDisk) {
136 			RF_ERRORMSG3("RAID: config error: Full Table depth"
137 			    " (%d) + Spare Space (%d) larger than disk size"
138 			    " (%d) (BD too big).\n",
139 			    (int)info->FullTableDepthInPUs,
140 			    (int)info->SpareSpaceDepthPerRegionInSUs,
141 			    (int)layoutPtr->stripeUnitsPerDisk);
142 			return (EINVAL);
143 		}
144 	} else {
145 		if (info->TableDepthInPUs * layoutPtr->SUsPerPU >
146 		    layoutPtr->stripeUnitsPerDisk) {
147 			RF_ERRORMSG2("RAID: config error: Table depth (%d)"
148 			    " larger than disk size (%d) (BD too big).\n",
149 			    (int) (info->TableDepthInPUs * layoutPtr->SUsPerPU),
150 			    (int) layoutPtr->stripeUnitsPerDisk);
151 			return (EINVAL);
152 		}
153 	}
154 
155 	/*
156 	 * Compute the size of each disk, and the number of tables in the last
157 	 * fulltable (which need not be complete).
158 	 */
159 	if ((raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE)) {
160 
161 		PUsPerDisk = layoutPtr->stripeUnitsPerDisk /
162 		    layoutPtr->SUsPerPU;
163 		spareRegionDepthInPUs = (info->TablesPerSpareRegion *
164 		    info->TableDepthInPUs + (info->TablesPerSpareRegion *
165 		    info->TableDepthInPUs) / (v - 1));
166 		info->SpareRegionDepthInSUs = spareRegionDepthInPUs *
167 		    layoutPtr->SUsPerPU;
168 
169 		numCompleteSpareRegionsPerDisk = PUsPerDisk /
170 		    spareRegionDepthInPUs;
171 		info->NumCompleteSRs = numCompleteSpareRegionsPerDisk;
172 		extraPUsPerDisk = PUsPerDisk % spareRegionDepthInPUs;
173 
174 		/*
175 		 * Assume conservatively that we need the full amount of spare
176 		 * space in one region in order to provide spares for the
177 		 * partial spare region at the end of the array.  We set "i"
178 		 * to the number of tables in the partial spare region.  This
179 		 * may actually include some fulltables.
180 		 */
181 		extraPUsPerDisk -= (info->SpareSpaceDepthPerRegionInSUs /
182 		    layoutPtr->SUsPerPU);
183 		if (extraPUsPerDisk <= 0)
184 			i = 0;
185 		else
186 			i = extraPUsPerDisk / info->TableDepthInPUs;
187 
188 		complete_FT_count = raidPtr->numRow *
189 		    (numCompleteSpareRegionsPerDisk *
190 		    (info->TablesPerSpareRegion / k) + i / k);
191 		info->FullTableLimitSUID = complete_FT_count *
192 		    info->SUsPerFullTable;
193 		info->ExtraTablesPerDisk = i % k;
194 
195 		/*
196 		 * Note that in the last spare region, the spare space is
197 		 * complete even though data/parity space is not.
198 		 */
199 		totSparePUsPerDisk = (numCompleteSpareRegionsPerDisk + 1) *
200 		    (info->SpareSpaceDepthPerRegionInSUs / layoutPtr->SUsPerPU);
201 		info->TotSparePUsPerDisk = totSparePUsPerDisk;
202 
203 		layoutPtr->stripeUnitsPerDisk =
204 		    ((complete_FT_count / raidPtr->numRow) *
205 		    info->FullTableDepthInPUs +	/* data & parity space */
206 		    info->ExtraTablesPerDisk * info->TableDepthInPUs +
207 		    totSparePUsPerDisk	/* spare space */
208 		    ) * layoutPtr->SUsPerPU;
209 		layoutPtr->dataStripeUnitsPerDisk =
210 		    (complete_FT_count * info->FullTableDepthInPUs +
211 		    info->ExtraTablesPerDisk * info->TableDepthInPUs)
212 		    * layoutPtr->SUsPerPU * (k - 1) / k;
213 
214 	} else {
215 		/*
216 		 * Non-dist spare case:  force each disk to contain an
217 		 * integral number of tables.
218 		 */
219 		layoutPtr->stripeUnitsPerDisk /=
220 		    (info->TableDepthInPUs * layoutPtr->SUsPerPU);
221 		layoutPtr->stripeUnitsPerDisk *=
222 		    (info->TableDepthInPUs * layoutPtr->SUsPerPU);
223 
224 		/*
225 		 * Compute the number of tables in the last fulltable, which
226 		 * need not be complete.
227 		 */
228 		complete_FT_count = ((layoutPtr->stripeUnitsPerDisk /
229 		    layoutPtr->SUsPerPU) / info->FullTableDepthInPUs) *
230 		    raidPtr->numRow;
231 
232 		info->FullTableLimitSUID = complete_FT_count *
233 		    info->SUsPerFullTable;
234 		info->ExtraTablesPerDisk = ((layoutPtr->stripeUnitsPerDisk /
235 		    layoutPtr->SUsPerPU) / info->TableDepthInPUs) % k;
236 	}
237 
238 	raidPtr->sectorsPerDisk = layoutPtr->stripeUnitsPerDisk *
239 	    layoutPtr->sectorsPerStripeUnit;
240 
241 	/*
242 	 * Find the disk offset of the stripe unit where the last
243 	 * fulltable starts.
244 	 */
245 	numCompleteFullTablesPerDisk = complete_FT_count / raidPtr->numRow;
246 	diskOffsetOfLastFullTableInSUs = numCompleteFullTablesPerDisk *
247 	    info->FullTableDepthInPUs * layoutPtr->SUsPerPU;
248 	if ((raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE)) {
249 		SpareSpaceInSUs = numCompleteSpareRegionsPerDisk *
250 		    info->SpareSpaceDepthPerRegionInSUs;
251 		diskOffsetOfLastFullTableInSUs += SpareSpaceInSUs;
252 		info->DiskOffsetOfLastSpareSpaceChunkInSUs =
253 		    diskOffsetOfLastFullTableInSUs + info->ExtraTablesPerDisk *
254 		    info->TableDepthInPUs * layoutPtr->SUsPerPU;
255 	}
256 	info->DiskOffsetOfLastFullTableInSUs = diskOffsetOfLastFullTableInSUs;
257 	info->numCompleteFullTablesPerDisk = numCompleteFullTablesPerDisk;
258 
259 	/* 4. Create and initialize the lookup tables. */
260 	info->LayoutTable = rf_make_2d_array(b, k, raidPtr->cleanupList);
261 	if (info->LayoutTable == NULL)
262 		return (ENOMEM);
263 
264 	info->OffsetTable = rf_make_2d_array(b, k, raidPtr->cleanupList);
265 	if (info->OffsetTable == NULL)
266 		return (ENOMEM);
267 
268 	info->BlockTable = rf_make_2d_array(info->TableDepthInPUs *
269 	    layoutPtr->SUsPerPU, raidPtr->numCol, raidPtr->cleanupList);
270 	if (info->BlockTable == NULL)
271 		return (ENOMEM);
272 
273 	first_avail_slot = (int *) rf_make_1d_array(v, NULL);
274 	if (first_avail_slot == NULL)
275 		return (ENOMEM);
276 
277 	for (i = 0; i < b; i++)
278 		for (j = 0; j < k; j++)
279 			info->LayoutTable[i][j] = *cfgBuf++;
280 
281 	/* Initialize offset table. */
282 	for (i = 0; i < b; i++)
283 		for (j = 0; j < k; j++) {
284 			info->OffsetTable[i][j] =
285 			    first_avail_slot[info->LayoutTable[i][j]];
286 			first_avail_slot[info->LayoutTable[i][j]]++;
287 		}
288 
289 	/* Initialize block table. */
290 	for (SUID = l = 0; l < layoutPtr->SUsPerPU; l++) {
291 		for (i = 0; i < b; i++) {
292 			for (j = 0; j < k; j++) {
293 				info->BlockTable[(info->OffsetTable[i][j] *
294 				     layoutPtr->SUsPerPU) + l]
295 				    [info->LayoutTable[i][j]] = SUID;
296 			}
297 			SUID++;
298 		}
299 	}
300 
301 	rf_free_1d_array(first_avail_slot, v);
302 
303 	/* 5. Set up the remaining redundant-but-useful parameters. */
304 
305 	raidPtr->totalSectors = (k * complete_FT_count + raidPtr->numRow *
306 	    info->ExtraTablesPerDisk) * info->SUsPerTable *
307 	    layoutPtr->sectorsPerStripeUnit;
308 	layoutPtr->numStripe = (raidPtr->totalSectors /
309 	    layoutPtr->sectorsPerStripeUnit) / (k - 2);
310 
311 	/*
312 	 * Strange evaluation order below to try and minimize overflow
313 	 * problems.
314 	 */
315 
316 	layoutPtr->dataSectorsPerStripe = (k - 2) *
317 	    layoutPtr->sectorsPerStripeUnit;
318 	layoutPtr->bytesPerStripeUnit = layoutPtr->sectorsPerStripeUnit <<
319 	    raidPtr->logBytesPerSector;
320 	layoutPtr->numDataCol = k - 2;
321 	layoutPtr->numParityCol = 2;
322 
323 	return (0);
324 }
325 
326 int
rf_GetDefaultNumFloatingReconBuffersPQ(RF_Raid_t * raidPtr)327 rf_GetDefaultNumFloatingReconBuffersPQ(RF_Raid_t *raidPtr)
328 {
329 	int def_decl;
330 
331 	def_decl = rf_GetDefaultNumFloatingReconBuffersDeclustered(raidPtr);
332 	return (RF_MAX(3 * raidPtr->numCol, def_decl));
333 }
334 
335 void
rf_MapSectorDeclusteredPQ(RF_Raid_t * raidPtr,RF_RaidAddr_t raidSector,RF_RowCol_t * row,RF_RowCol_t * col,RF_SectorNum_t * diskSector,int remap)336 rf_MapSectorDeclusteredPQ(RF_Raid_t *raidPtr, RF_RaidAddr_t raidSector,
337     RF_RowCol_t *row, RF_RowCol_t *col, RF_SectorNum_t *diskSector, int remap)
338 {
339 	RF_RaidLayout_t *layoutPtr = &(raidPtr->Layout);
340 	RF_DeclusteredConfigInfo_t *info =
341 	    (RF_DeclusteredConfigInfo_t *) layoutPtr->layoutSpecificInfo;
342 	RF_StripeNum_t SUID = raidSector / layoutPtr->sectorsPerStripeUnit;
343 	RF_StripeNum_t FullTableID, FullTableOffset, TableID, TableOffset;
344 	RF_StripeNum_t BlockID, BlockOffset, RepIndex;
345 	RF_StripeCount_t sus_per_fulltable = info->SUsPerFullTable;
346 	RF_StripeCount_t fulltable_depth = info->FullTableDepthInPUs *
347 	    layoutPtr->SUsPerPU;
348 	RF_StripeNum_t base_suid = 0, outSU, SpareRegion = 0, SpareSpace = 0;
349 
350 	rf_decluster_adjust_params(layoutPtr, &SUID, &sus_per_fulltable,
351 	    &fulltable_depth, &base_suid);
352 
353 	/* Fulltable ID within array (across rows). */
354 	FullTableID = SUID / sus_per_fulltable;
355 	*row = FullTableID % raidPtr->numRow;
356 
357 	/* Convert to fulltable ID on this disk. */
358 	FullTableID /= raidPtr->numRow;
359 
360 	if ((raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE)) {
361 		SpareRegion = FullTableID / info->FullTablesPerSpareRegion;
362 		SpareSpace = SpareRegion * info->SpareSpaceDepthPerRegionInSUs;
363 	}
364 	FullTableOffset = SUID % sus_per_fulltable;
365 	TableID = FullTableOffset / info->SUsPerTable;
366 	TableOffset = FullTableOffset - TableID * info->SUsPerTable;
367 	BlockID = TableOffset / info->PUsPerBlock;
368 	BlockOffset = TableOffset - BlockID * info->PUsPerBlock;
369 	BlockID %= info->BlocksPerTable;
370 	RF_ASSERT(BlockOffset < info->groupSize - 2);
371 	/*
372 	 * TableIDs go from 0 .. GroupSize-1 inclusive.
373 	 * PUsPerBlock is k-2.
374 	 * We want the tableIDs to rotate from the
375 	 * right, so use GroupSize.
376 	 */
377 	RepIndex = info->groupSize - 1 - TableID;
378 	RF_ASSERT(RepIndex >= 0);
379 	if (!raidPtr->noRotate) {
380 		if (TableID == 0)
381 			/* P on last drive, Q on first. */
382 			BlockOffset++;
383 		else
384 			/* Skip over PQ. */
385 			BlockOffset += ((BlockOffset >= RepIndex) ? 2 : 0);
386 
387 		RF_ASSERT(BlockOffset < info->groupSize);
388 		*col = info->LayoutTable[BlockID][BlockOffset];
389 	}
390 	/* Remap to distributed spare space if indicated. */
391 	if (remap) {
392 		rf_remap_to_spare_space(layoutPtr, info, *row, FullTableID,
393 		    TableID, BlockID, (base_suid) ? 1 : 0, SpareRegion, col,
394 		    &outSU);
395 	} else {
396 
397 		outSU = base_suid;
398 		outSU += FullTableID * fulltable_depth;
399 			/* Offset to strt of FT. */
400 		outSU += SpareSpace;
401 			/* Skip reserved spare space. */
402 		outSU += TableID * info->TableDepthInPUs * layoutPtr->SUsPerPU;
403 			/* Offset to start of table. */
404 		outSU += info->OffsetTable[BlockID][BlockOffset] *
405 		    layoutPtr->SUsPerPU;
406 			/* Offset to the PU. */
407 	}
408 	outSU += TableOffset / (info->BlocksPerTable * info->PUsPerBlock);
409 		/* Offset to the SU within a PU. */
410 
411 	/*
412 	 * Convert SUs to sectors, and, if not aligned to SU boundary, add in
413 	 * offset to sector.
414 	 */
415 	*diskSector = outSU * layoutPtr->sectorsPerStripeUnit +
416 	    (raidSector % layoutPtr->sectorsPerStripeUnit);
417 }
418 
419 
420 void
rf_MapParityDeclusteredPQ(RF_Raid_t * raidPtr,RF_RaidAddr_t raidSector,RF_RowCol_t * row,RF_RowCol_t * col,RF_SectorNum_t * diskSector,int remap)421 rf_MapParityDeclusteredPQ(RF_Raid_t *raidPtr, RF_RaidAddr_t raidSector,
422     RF_RowCol_t *row, RF_RowCol_t *col, RF_SectorNum_t *diskSector, int remap)
423 {
424 	RF_RaidLayout_t *layoutPtr = &(raidPtr->Layout);
425 	RF_DeclusteredConfigInfo_t *info =
426 	    (RF_DeclusteredConfigInfo_t *) layoutPtr->layoutSpecificInfo;
427 	RF_StripeNum_t SUID = raidSector / layoutPtr->sectorsPerStripeUnit;
428 	RF_StripeNum_t FullTableID, FullTableOffset, TableID, TableOffset;
429 	RF_StripeNum_t BlockID, BlockOffset, RepIndex;
430 	RF_StripeCount_t sus_per_fulltable = info->SUsPerFullTable;
431 	RF_StripeCount_t fulltable_depth = info->FullTableDepthInPUs *
432 	    layoutPtr->SUsPerPU;
433 	RF_StripeNum_t base_suid = 0, outSU, SpareRegion, SpareSpace = 0;
434 
435 	rf_decluster_adjust_params(layoutPtr, &SUID, &sus_per_fulltable,
436 	    &fulltable_depth, &base_suid);
437 
438 	/* Compute row & (possibly) spare space exactly as before. */
439 	FullTableID = SUID / sus_per_fulltable;
440 	*row = FullTableID % raidPtr->numRow;
441 	/* Convert to fulltable ID on this disk. */
442 	FullTableID /= raidPtr->numRow;
443 	if ((raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE)) {
444 		SpareRegion = FullTableID / info->FullTablesPerSpareRegion;
445 		SpareSpace = SpareRegion * info->SpareSpaceDepthPerRegionInSUs;
446 	}
447 	/* Compute BlockID and RepIndex exactly as before. */
448 	FullTableOffset = SUID % sus_per_fulltable;
449 	TableID = FullTableOffset / info->SUsPerTable;
450 	TableOffset = FullTableOffset - TableID * info->SUsPerTable;
451 	BlockID = TableOffset / info->PUsPerBlock;
452 	BlockOffset = TableOffset - BlockID * info->PUsPerBlock;
453 	BlockID %= info->BlocksPerTable;
454 
455 	/* The parity block is in the position indicated by RepIndex. */
456 	RepIndex = (raidPtr->noRotate) ?
457 	    info->PUsPerBlock : info->groupSize - 1 - TableID;
458 	*col = info->LayoutTable[BlockID][RepIndex];
459 
460 	if (remap)
461 		RF_PANIC();
462 
463 	/*
464 	 * Compute sector as before, except use RepIndex instead of
465 	 * BlockOffset.
466 	 */
467 	outSU = base_suid;
468 	outSU += FullTableID * fulltable_depth;
469 	outSU += SpareSpace;	/* skip rsvd spare space */
470 	outSU += TableID * info->TableDepthInPUs * layoutPtr->SUsPerPU;
471 	outSU += info->OffsetTable[BlockID][RepIndex] * layoutPtr->SUsPerPU;
472 	outSU += TableOffset / (info->BlocksPerTable * info->PUsPerBlock);
473 
474 	*diskSector = outSU * layoutPtr->sectorsPerStripeUnit +
475 	    (raidSector % layoutPtr->sectorsPerStripeUnit);
476 }
477 
478 void
rf_MapQDeclusteredPQ(RF_Raid_t * raidPtr,RF_RaidAddr_t raidSector,RF_RowCol_t * row,RF_RowCol_t * col,RF_SectorNum_t * diskSector,int remap)479 rf_MapQDeclusteredPQ(RF_Raid_t *raidPtr, RF_RaidAddr_t raidSector,
480     RF_RowCol_t *row, RF_RowCol_t *col, RF_SectorNum_t *diskSector, int remap)
481 {
482 	RF_RaidLayout_t *layoutPtr = &(raidPtr->Layout);
483 	RF_DeclusteredConfigInfo_t *info =
484 	    (RF_DeclusteredConfigInfo_t *) layoutPtr->layoutSpecificInfo;
485 	RF_StripeNum_t SUID = raidSector / layoutPtr->sectorsPerStripeUnit;
486 	RF_StripeNum_t FullTableID, FullTableOffset, TableID, TableOffset;
487 	RF_StripeNum_t BlockID, BlockOffset, RepIndex, RepIndexQ;
488 	RF_StripeCount_t sus_per_fulltable = info->SUsPerFullTable;
489 	RF_StripeCount_t fulltable_depth = info->FullTableDepthInPUs *
490 	    layoutPtr->SUsPerPU;
491 	RF_StripeNum_t base_suid = 0, outSU, SpareRegion, SpareSpace = 0;
492 
493 	rf_decluster_adjust_params(layoutPtr, &SUID, &sus_per_fulltable,
494 	    &fulltable_depth, &base_suid);
495 
496 	/* Compute row & (possibly) spare space exactly as before. */
497 	FullTableID = SUID / sus_per_fulltable;
498 	*row = FullTableID % raidPtr->numRow;
499 	/* Convert to fulltable ID on this disk. */
500 	FullTableID /= raidPtr->numRow;
501 	if ((raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE)) {
502 		SpareRegion = FullTableID / info->FullTablesPerSpareRegion;
503 		SpareSpace = SpareRegion * info->SpareSpaceDepthPerRegionInSUs;
504 	}
505 	/* Compute BlockID and RepIndex exactly as before. */
506 	FullTableOffset = SUID % sus_per_fulltable;
507 	TableID = FullTableOffset / info->SUsPerTable;
508 	TableOffset = FullTableOffset - TableID * info->SUsPerTable;
509 	BlockID = TableOffset / info->PUsPerBlock;
510 	BlockOffset = TableOffset - BlockID * info->PUsPerBlock;
511 	BlockID %= info->BlocksPerTable;
512 
513 	/* The q block is in the position indicated by RepIndex. */
514 	RepIndex = (raidPtr->noRotate) ?
515 	    info->PUsPerBlock : info->groupSize - 1 - TableID;
516 	RepIndexQ = ((RepIndex == (info->groupSize - 1)) ? 0 : RepIndex + 1);
517 	*col = info->LayoutTable[BlockID][RepIndexQ];
518 
519 	if (remap)
520 		RF_PANIC();
521 
522 	/*
523 	 * Compute sector as before, except use RepIndex instead of
524 	 * BlockOffset.
525 	 */
526 	outSU = base_suid;
527 	outSU += FullTableID * fulltable_depth;
528 	outSU += SpareSpace;	/* skip rsvd spare space */
529 	outSU += TableID * info->TableDepthInPUs * layoutPtr->SUsPerPU;
530 	outSU += TableOffset / (info->BlocksPerTable * info->PUsPerBlock);
531 
532 	outSU += info->OffsetTable[BlockID][RepIndexQ] * layoutPtr->SUsPerPU;
533 	*diskSector = outSU * layoutPtr->sectorsPerStripeUnit +
534 	    (raidSector % layoutPtr->sectorsPerStripeUnit);
535 }
536 
537 /*
538  * Returns an array of ints identifying the disks that comprise the stripe
539  * containing the indicated address.
540  * The caller must _never_ attempt to modify this array.
541  */
542 void
rf_IdentifyStripeDeclusteredPQ(RF_Raid_t * raidPtr,RF_RaidAddr_t addr,RF_RowCol_t ** diskids,RF_RowCol_t * outRow)543 rf_IdentifyStripeDeclusteredPQ(RF_Raid_t *raidPtr, RF_RaidAddr_t addr,
544     RF_RowCol_t **diskids, RF_RowCol_t *outRow)
545 {
546 	RF_RaidLayout_t *layoutPtr = &(raidPtr->Layout);
547 	RF_DeclusteredConfigInfo_t *info =
548 	    (RF_DeclusteredConfigInfo_t *) layoutPtr->layoutSpecificInfo;
549 	RF_StripeCount_t sus_per_fulltable = info->SUsPerFullTable;
550 	RF_StripeCount_t fulltable_depth = info->FullTableDepthInPUs *
551 	    layoutPtr->SUsPerPU;
552 	RF_StripeNum_t base_suid = 0;
553 	RF_StripeNum_t SUID = rf_RaidAddressToStripeUnitID(layoutPtr, addr);
554 	RF_StripeNum_t stripeID, FullTableID;
555 	int tableOffset;
556 
557 	rf_decluster_adjust_params(layoutPtr, &SUID, &sus_per_fulltable,
558 	    &fulltable_depth, &base_suid);
559 	/* Fulltable ID within array (across rows). */
560 	FullTableID = SUID / sus_per_fulltable;
561 	*outRow = FullTableID % raidPtr->numRow;
562 	/* Find stripe offset into array. */
563 	stripeID = rf_StripeUnitIDToStripeID(layoutPtr, SUID);
564 	/* Find offset into block design table. */
565 	tableOffset = (stripeID % info->BlocksPerTable);
566 	*diskids = info->LayoutTable[tableOffset];
567 }
568