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