rf_chaindecluster.c revision 1.3
1/*	$NetBSD: rf_chaindecluster.c,v 1.3 1999/02/05 00:06:06 oster Exp $	*/
2/*
3 * Copyright (c) 1995 Carnegie-Mellon University.
4 * All rights reserved.
5 *
6 * Author: Khalil Amiri
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_chaindecluster.c -- implements chained declustering
32 *
33 *****************************************************************************/
34
35#include "rf_archs.h"
36#include "rf_types.h"
37#include "rf_raid.h"
38#include "rf_chaindecluster.h"
39#include "rf_dag.h"
40#include "rf_dagutils.h"
41#include "rf_dagffrd.h"
42#include "rf_dagffwr.h"
43#include "rf_dagdegrd.h"
44#include "rf_dagfuncs.h"
45#include "rf_threadid.h"
46#include "rf_general.h"
47#include "rf_utils.h"
48
49typedef struct RF_ChaindeclusterConfigInfo_s {
50	RF_RowCol_t **stripeIdentifier;	/* filled in at config time and used
51					 * by IdentifyStripe */
52	RF_StripeCount_t numSparingRegions;
53	RF_StripeCount_t stripeUnitsPerSparingRegion;
54	RF_SectorNum_t mirrorStripeOffset;
55}       RF_ChaindeclusterConfigInfo_t;
56
57int
58rf_ConfigureChainDecluster(
59    RF_ShutdownList_t ** listp,
60    RF_Raid_t * raidPtr,
61    RF_Config_t * cfgPtr)
62{
63	RF_RaidLayout_t *layoutPtr = &raidPtr->Layout;
64	RF_StripeCount_t num_used_stripeUnitsPerDisk;
65	RF_ChaindeclusterConfigInfo_t *info;
66	RF_RowCol_t i;
67
68	/* create a Chained Declustering configuration structure */
69	RF_MallocAndAdd(info, sizeof(RF_ChaindeclusterConfigInfo_t), (RF_ChaindeclusterConfigInfo_t *), raidPtr->cleanupList);
70	if (info == NULL)
71		return (ENOMEM);
72	layoutPtr->layoutSpecificInfo = (void *) info;
73
74	/* fill in the config structure.  */
75	info->stripeIdentifier = rf_make_2d_array(raidPtr->numCol, 2, raidPtr->cleanupList);
76	if (info->stripeIdentifier == NULL)
77		return (ENOMEM);
78	for (i = 0; i < raidPtr->numCol; i++) {
79		info->stripeIdentifier[i][0] = i % raidPtr->numCol;
80		info->stripeIdentifier[i][1] = (i + 1) % raidPtr->numCol;
81	}
82
83	RF_ASSERT(raidPtr->numRow == 1);
84
85	/* fill in the remaining layout parameters */
86	num_used_stripeUnitsPerDisk = layoutPtr->stripeUnitsPerDisk - (layoutPtr->stripeUnitsPerDisk %
87	    (2 * raidPtr->numCol - 2));
88	info->numSparingRegions = num_used_stripeUnitsPerDisk / (2 * raidPtr->numCol - 2);
89	info->stripeUnitsPerSparingRegion = raidPtr->numCol * (raidPtr->numCol - 1);
90	info->mirrorStripeOffset = info->numSparingRegions * (raidPtr->numCol - 1);
91	layoutPtr->numStripe = info->numSparingRegions * info->stripeUnitsPerSparingRegion;
92	layoutPtr->bytesPerStripeUnit = layoutPtr->sectorsPerStripeUnit << raidPtr->logBytesPerSector;
93	layoutPtr->numDataCol = 1;
94	layoutPtr->dataSectorsPerStripe = layoutPtr->numDataCol * layoutPtr->sectorsPerStripeUnit;
95	layoutPtr->numParityCol = 1;
96
97	layoutPtr->dataStripeUnitsPerDisk = num_used_stripeUnitsPerDisk;
98
99	raidPtr->sectorsPerDisk =
100	    num_used_stripeUnitsPerDisk * layoutPtr->sectorsPerStripeUnit;
101
102	raidPtr->totalSectors =
103	    (layoutPtr->numStripe) * layoutPtr->sectorsPerStripeUnit;
104
105	layoutPtr->stripeUnitsPerDisk = raidPtr->sectorsPerDisk / layoutPtr->sectorsPerStripeUnit;
106
107	return (0);
108}
109
110RF_ReconUnitCount_t
111rf_GetNumSpareRUsChainDecluster(raidPtr)
112	RF_Raid_t *raidPtr;
113{
114	RF_ChaindeclusterConfigInfo_t *info = (RF_ChaindeclusterConfigInfo_t *) raidPtr->Layout.layoutSpecificInfo;
115
116	/*
117         * The layout uses two stripe units per disk as spare within each
118         * sparing region.
119         */
120	return (2 * info->numSparingRegions);
121}
122
123
124/* Maps to the primary copy of the data, i.e. the first mirror pair */
125void
126rf_MapSectorChainDecluster(
127    RF_Raid_t * raidPtr,
128    RF_RaidAddr_t raidSector,
129    RF_RowCol_t * row,
130    RF_RowCol_t * col,
131    RF_SectorNum_t * diskSector,
132    int remap)
133{
134	RF_ChaindeclusterConfigInfo_t *info = (RF_ChaindeclusterConfigInfo_t *) raidPtr->Layout.layoutSpecificInfo;
135	RF_StripeNum_t SUID = raidSector / raidPtr->Layout.sectorsPerStripeUnit;
136	RF_SectorNum_t index_within_region, index_within_disk;
137	RF_StripeNum_t sparing_region_id;
138	int     col_before_remap;
139
140	*row = 0;
141	sparing_region_id = SUID / info->stripeUnitsPerSparingRegion;
142	index_within_region = SUID % info->stripeUnitsPerSparingRegion;
143	index_within_disk = index_within_region / raidPtr->numCol;
144	col_before_remap = SUID % raidPtr->numCol;
145
146	if (!remap) {
147		*col = col_before_remap;
148		*diskSector = (index_within_disk + ((raidPtr->numCol - 1) * sparing_region_id)) *
149		    raidPtr->Layout.sectorsPerStripeUnit;
150		*diskSector += (raidSector % raidPtr->Layout.sectorsPerStripeUnit);
151	} else {
152		/* remap sector to spare space... */
153		*diskSector = sparing_region_id * (raidPtr->numCol + 1) * raidPtr->Layout.sectorsPerStripeUnit;
154		*diskSector += (raidPtr->numCol - 1) * raidPtr->Layout.sectorsPerStripeUnit;
155		*diskSector += (raidSector % raidPtr->Layout.sectorsPerStripeUnit);
156		index_within_disk = index_within_region / raidPtr->numCol;
157		if (index_within_disk < col_before_remap)
158			*col = index_within_disk;
159		else
160			if (index_within_disk == raidPtr->numCol - 2) {
161				*col = (col_before_remap + raidPtr->numCol - 1) % raidPtr->numCol;
162				*diskSector += raidPtr->Layout.sectorsPerStripeUnit;
163			} else
164				*col = (index_within_disk + 2) % raidPtr->numCol;
165	}
166
167}
168
169
170
171/* Maps to the second copy of the mirror pair, which is chain declustered. The second copy is contained
172   in the next disk (mod numCol) after the disk containing the primary copy.
173   The offset into the disk is one-half disk down */
174void
175rf_MapParityChainDecluster(
176    RF_Raid_t * raidPtr,
177    RF_RaidAddr_t raidSector,
178    RF_RowCol_t * row,
179    RF_RowCol_t * col,
180    RF_SectorNum_t * diskSector,
181    int remap)
182{
183	RF_ChaindeclusterConfigInfo_t *info = (RF_ChaindeclusterConfigInfo_t *) raidPtr->Layout.layoutSpecificInfo;
184	RF_StripeNum_t SUID = raidSector / raidPtr->Layout.sectorsPerStripeUnit;
185	RF_SectorNum_t index_within_region, index_within_disk;
186	RF_StripeNum_t sparing_region_id;
187	int     col_before_remap;
188
189	*row = 0;
190	if (!remap) {
191		*col = SUID % raidPtr->numCol;
192		*col = (*col + 1) % raidPtr->numCol;
193		*diskSector = info->mirrorStripeOffset * raidPtr->Layout.sectorsPerStripeUnit;
194		*diskSector += (SUID / raidPtr->numCol) * raidPtr->Layout.sectorsPerStripeUnit;
195		*diskSector += (raidSector % raidPtr->Layout.sectorsPerStripeUnit);
196	} else {
197		/* remap parity to spare space ... */
198		sparing_region_id = SUID / info->stripeUnitsPerSparingRegion;
199		index_within_region = SUID % info->stripeUnitsPerSparingRegion;
200		index_within_disk = index_within_region / raidPtr->numCol;
201		*diskSector = sparing_region_id * (raidPtr->numCol + 1) * raidPtr->Layout.sectorsPerStripeUnit;
202		*diskSector += (raidPtr->numCol) * raidPtr->Layout.sectorsPerStripeUnit;
203		*diskSector += (raidSector % raidPtr->Layout.sectorsPerStripeUnit);
204		col_before_remap = SUID % raidPtr->numCol;
205		if (index_within_disk < col_before_remap)
206			*col = index_within_disk;
207		else
208			if (index_within_disk == raidPtr->numCol - 2) {
209				*col = (col_before_remap + 2) % raidPtr->numCol;
210				*diskSector -= raidPtr->Layout.sectorsPerStripeUnit;
211			} else
212				*col = (index_within_disk + 2) % raidPtr->numCol;
213	}
214
215}
216
217void
218rf_IdentifyStripeChainDecluster(
219    RF_Raid_t * raidPtr,
220    RF_RaidAddr_t addr,
221    RF_RowCol_t ** diskids,
222    RF_RowCol_t * outRow)
223{
224	RF_ChaindeclusterConfigInfo_t *info = (RF_ChaindeclusterConfigInfo_t *) raidPtr->Layout.layoutSpecificInfo;
225	RF_StripeNum_t SUID;
226	RF_RowCol_t col;
227
228	SUID = addr / raidPtr->Layout.sectorsPerStripeUnit;
229	col = SUID % raidPtr->numCol;
230	*outRow = 0;
231	*diskids = info->stripeIdentifier[col];
232}
233
234void
235rf_MapSIDToPSIDChainDecluster(
236    RF_RaidLayout_t * layoutPtr,
237    RF_StripeNum_t stripeID,
238    RF_StripeNum_t * psID,
239    RF_ReconUnitNum_t * which_ru)
240{
241	*which_ru = 0;
242	*psID = stripeID;
243}
244/******************************************************************************
245 * select a graph to perform a single-stripe access
246 *
247 * Parameters:  raidPtr    - description of the physical array
248 *              type       - type of operation (read or write) requested
249 *              asmap      - logical & physical addresses for this access
250 *              createFunc - function to use to create the graph (return value)
251 *****************************************************************************/
252
253void
254rf_RAIDCDagSelect(
255    RF_Raid_t * raidPtr,
256    RF_IoType_t type,
257    RF_AccessStripeMap_t * asmap,
258    RF_VoidFuncPtr * createFunc)
259#if 0
260	void    (**createFunc) (RF_Raid_t *, RF_AccessStripeMap_t *,
261            RF_DagHeader_t *, void *, RF_RaidAccessFlags_t,
262/**INDENT** Warning@258: Extra ) */
263            RF_AllocListElem_t *))
264#endif
265{
266	RF_ASSERT(RF_IO_IS_R_OR_W(type));
267	RF_ASSERT(raidPtr->numRow == 1);
268
269	if (asmap->numDataFailed + asmap->numParityFailed > 1) {
270		RF_ERRORMSG("Multiple disks failed in a single group!  Aborting I/O operation.\n");
271		*createFunc = NULL;
272		return;
273	}
274	*createFunc = (type == RF_IO_TYPE_READ) ? (RF_VoidFuncPtr) rf_CreateFaultFreeReadDAG : (RF_VoidFuncPtr) rf_CreateRaidOneWriteDAG;
275
276	if (type == RF_IO_TYPE_READ) {
277		if ((raidPtr->status[0] == rf_rs_degraded) || (raidPtr->status[0] == rf_rs_reconstructing))
278			*createFunc = (RF_VoidFuncPtr) rf_CreateRaidCDegradedReadDAG;	/* array status is
279											 * degraded, implement
280											 * workload shifting */
281		else
282			*createFunc = (RF_VoidFuncPtr) rf_CreateMirrorPartitionReadDAG;	/* array status not
283											 * degraded, so use
284											 * mirror partition dag */
285	} else
286		*createFunc = (RF_VoidFuncPtr) rf_CreateRaidOneWriteDAG;
287}
288