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