1 /*        $NetBSD: rf_aselect.c,v 1.31 2022/03/20 19:26:27 andvar Exp $         */
2 /*
3  * Copyright (c) 1995 Carnegie-Mellon University.
4  * All rights reserved.
5  *
6  * Author: Mark Holland, William V. Courtright II
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  * aselect.c -- algorithm selection code
32  *
33  *****************************************************************************/
34 
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: rf_aselect.c,v 1.31 2022/03/20 19:26:27 andvar Exp $");
37 
38 #include <dev/raidframe/raidframevar.h>
39 
40 #include "rf_archs.h"
41 #include "rf_raid.h"
42 #include "rf_dag.h"
43 #include "rf_dagutils.h"
44 #include "rf_dagfuncs.h"
45 #include "rf_general.h"
46 #include "rf_desc.h"
47 #include "rf_map.h"
48 
49 static void InitHdrNode(RF_DagHeader_t **, RF_Raid_t *, RF_RaidAccessDesc_t *);
50 int     rf_SelectAlgorithm(RF_RaidAccessDesc_t *, RF_RaidAccessFlags_t);
51 
52 /******************************************************************************
53  *
54  * Create and Initialize a dag header and termination node
55  *
56  *****************************************************************************/
57 static void
InitHdrNode(RF_DagHeader_t ** hdr,RF_Raid_t * raidPtr,RF_RaidAccessDesc_t * desc)58 InitHdrNode(RF_DagHeader_t **hdr, RF_Raid_t *raidPtr, RF_RaidAccessDesc_t *desc)
59 {
60           /* create and initialize dag hdr */
61           *hdr = rf_AllocDAGHeader(raidPtr);
62           rf_MakeAllocList((*hdr)->allocList);
63           (*hdr)->status = rf_enable;
64           (*hdr)->numSuccedents = 0;
65           (*hdr)->nodes = NULL;
66           (*hdr)->raidPtr = raidPtr;
67           (*hdr)->next = NULL;
68           (*hdr)->desc = desc;
69 }
70 
71 /******************************************************************************
72  *
73  * Create a DAG to do a read or write operation.
74  *
75  * create a list of dagLists, one list per parity stripe.
76  * return the lists in the desc->dagList (which is a list of lists).
77  *
78  * Normally, each list contains one dag for the entire stripe.  In some
79  * tricky cases, we break this into multiple dags, either one per stripe
80  * unit or one per block (sector).  When this occurs, these dags are returned
81  * as a linked list (dagList) which is executed sequentially (to preserve
82  * atomic parity updates in the stripe).
83  *
84  * dags which operate on independent parity goups (stripes) are returned in
85  * independent dagLists (distinct elements in desc->dagArray) and may be
86  * executed concurrently.
87  *
88  * Finally, if the SelectionFunc fails to create a dag for a block, we punt
89  * and return 1.
90  *
91  * The above process is performed in two phases:
92  *   1) create an array(s) of creation functions (eg stripeFuncs)
93  *   2) create dags and concatenate/merge to form the final dag.
94  *
95  * Because dag's are basic blocks (single entry, single exit, unconditional
96  * control flow, we can add the following optimizations (future work):
97  *   first-pass optimizer to allow max concurrency (need all data dependencies)
98  *   second-pass optimizer to eliminate common subexpressions (need true
99  *                         data dependencies)
100  *   third-pass optimizer to eliminate dead code (need true data dependencies)
101  *****************************************************************************/
102 
103 int
rf_SelectAlgorithm(RF_RaidAccessDesc_t * desc,RF_RaidAccessFlags_t flags)104 rf_SelectAlgorithm(RF_RaidAccessDesc_t *desc, RF_RaidAccessFlags_t flags)
105 {
106           RF_AccessStripeMapHeader_t *asm_h = desc->asmap;
107           RF_IoType_t type = desc->type;
108           RF_Raid_t *raidPtr = desc->raidPtr;
109           void   *bp = desc->bp;
110 
111           RF_AccessStripeMap_t *asmap = asm_h->stripeMap;
112           RF_AccessStripeMap_t *asm_p;
113           RF_DagHeader_t *dag_h = NULL, *tempdag_h, *lastdag_h;
114           RF_DagList_t *dagList, *dagListend;
115           int     i, j, k;
116           RF_FuncList_t *stripeFuncsList, *stripeFuncs, *stripeFuncsEnd, *temp;
117           RF_AccessStripeMap_t *asm_up, *asm_bp;
118           RF_AccessStripeMapHeader_t *endASMList;
119           RF_ASMHeaderListElem_t *asmhle, *tmpasmhle;
120           RF_VoidFunctionPointerListElem_t *vfple, *tmpvfple;
121           RF_FailedStripe_t *failed_stripes_list, *failed_stripes_list_end;
122           RF_FailedStripe_t *tmpfailed_stripe, *failed_stripe = NULL;
123           RF_ASMHeaderListElem_t *failed_stripes_asmh_u_end = NULL;
124           RF_ASMHeaderListElem_t *failed_stripes_asmh_b_end = NULL;
125           RF_VoidFunctionPointerListElem_t *failed_stripes_vfple_end = NULL;
126           RF_VoidFunctionPointerListElem_t *failed_stripes_bvfple_end = NULL;
127           RF_VoidFuncPtr uFunc;
128           RF_VoidFuncPtr bFunc;
129           int     numStripesBailed = 0, cantCreateDAGs = RF_FALSE;
130           int     numStripeUnitsBailed = 0;
131           int     stripeNum, stripeUnitNum, numBlockDags = 0;
132           RF_StripeNum_t numStripeUnits;
133           RF_SectorNum_t numBlocks;
134           RF_RaidAddr_t address;
135           int     length;
136           RF_PhysDiskAddr_t *physPtr;
137           void *buffer;
138 
139           lastdag_h = NULL;
140 
141           stripeFuncsList = NULL;
142           stripeFuncsEnd = NULL;
143 
144           failed_stripes_list = NULL;
145           failed_stripes_list_end = NULL;
146 
147           /* walk through the asm list once collecting information */
148           /* attempt to find a single creation function for each stripe */
149           desc->numStripes = 0;
150           for (i = 0, asm_p = asmap; asm_p; asm_p = asm_p->next, i++) {
151                     desc->numStripes++;
152                     stripeFuncs = rf_AllocFuncList(raidPtr);
153 
154                     if (stripeFuncsEnd == NULL) {
155                               stripeFuncsList = stripeFuncs;
156                     } else {
157                               stripeFuncsEnd->next = stripeFuncs;
158                     }
159                     stripeFuncsEnd = stripeFuncs;
160 
161                     (raidPtr->Layout.map->SelectionFunc) (raidPtr, type, asm_p, &(stripeFuncs->fp));
162                     /* check to see if we found a creation func for this stripe */
163                     if (stripeFuncs->fp == NULL) {
164                               /* could not find creation function for entire stripe
165                                * so, let's see if we can find one for each stripe
166                                * unit in the stripe */
167 
168                               /* create a failed stripe structure to attempt to deal with the failure */
169                               failed_stripe = rf_AllocFailedStripeStruct(raidPtr);
170                               if (failed_stripes_list == NULL) {
171                                         failed_stripes_list = failed_stripe;
172                                         failed_stripes_list_end = failed_stripe;
173                               } else {
174                                         failed_stripes_list_end->next = failed_stripe;
175                                         failed_stripes_list_end = failed_stripe;
176                               }
177 
178                               /* create an array of creation funcs (called
179                                * stripeFuncs) for this stripe */
180                               numStripeUnits = asm_p->numStripeUnitsAccessed;
181 
182                               /* lookup array of stripeUnitFuncs for this stripe */
183                               failed_stripes_asmh_u_end = NULL;
184                               failed_stripes_vfple_end = NULL;
185                               for (j = 0, physPtr = asm_p->physInfo; physPtr; physPtr = physPtr->next, j++) {
186                                         /* remap for series of single stripe-unit
187                                          * accesses */
188                                         address = physPtr->raidAddress;
189                                         length = physPtr->numSector;
190                                         buffer = physPtr->bufPtr;
191 
192                                         asmhle = rf_AllocASMHeaderListElem(raidPtr);
193                                         if (failed_stripe->asmh_u == NULL) {
194                                                   failed_stripe->asmh_u = asmhle;      /* we're the head... */
195                                                   failed_stripes_asmh_u_end = asmhle;  /* and the tail      */
196                                         } else {
197                                                   /* tack us onto the end of the list */
198                                                   failed_stripes_asmh_u_end->next = asmhle;
199                                                   failed_stripes_asmh_u_end = asmhle;
200                                         }
201 
202 
203                                         asmhle->asmh = rf_MapAccess(raidPtr, address, length, buffer, RF_DONT_REMAP);
204                                         asm_up = asmhle->asmh->stripeMap;
205 
206                                         vfple = rf_AllocVFPListElem(raidPtr);
207                                         if (failed_stripe->vfple == NULL) {
208                                                   failed_stripe->vfple = vfple;
209                                                   failed_stripes_vfple_end = vfple;
210                                         } else {
211                                                   failed_stripes_vfple_end->next = vfple;
212                                                   failed_stripes_vfple_end = vfple;
213                                         }
214 
215                                         /* get the creation func for this stripe unit */
216                                         (raidPtr->Layout.map->SelectionFunc) (raidPtr, type, asm_up, &(vfple->fn));
217 
218                                         /* check to see if we found a creation func
219                                          * for this stripe unit */
220 
221                                         if (vfple->fn == NULL) {
222                                                   /* could not find creation function
223                                                    * for stripe unit so, let's see if we
224                                                    * can find one for each block in the
225                                                    * stripe unit */
226 
227                                                   numBlocks = physPtr->numSector;
228                                                   numBlockDags += numBlocks;
229 
230                                                   /* lookup array of blockFuncs for this
231                                                    * stripe unit */
232                                                   for (k = 0; k < numBlocks; k++) {
233                                                             /* remap for series of single
234                                                              * stripe-unit accesses */
235                                                             address = physPtr->raidAddress + k;
236                                                             length = 1;
237                                                             buffer = (char *)physPtr->bufPtr + (k * (1 << raidPtr->logBytesPerSector));
238 
239                                                             asmhle = rf_AllocASMHeaderListElem(raidPtr);
240                                                             if (failed_stripe->asmh_b == NULL) {
241                                                                       failed_stripe->asmh_b = asmhle;
242                                                                       failed_stripes_asmh_b_end = asmhle;
243                                                             } else {
244                                                                       failed_stripes_asmh_b_end->next = asmhle;
245                                                                       failed_stripes_asmh_b_end = asmhle;
246                                                             }
247 
248                                                             asmhle->asmh = rf_MapAccess(raidPtr, address, length, buffer, RF_DONT_REMAP);
249                                                             asm_bp = asmhle->asmh->stripeMap;
250 
251                                                             vfple = rf_AllocVFPListElem(raidPtr);
252                                                             if (failed_stripe->bvfple == NULL) {
253                                                                       failed_stripe->bvfple = vfple;
254                                                                       failed_stripes_bvfple_end = vfple;
255                                                             } else {
256                                                                       failed_stripes_bvfple_end->next = vfple;
257                                                                       failed_stripes_bvfple_end = vfple;
258                                                             }
259                                                             (raidPtr->Layout.map->SelectionFunc) (raidPtr, type, asm_bp, &(vfple->fn));
260 
261                                                             /* check to see if we found a
262                                                              * creation func for this
263                                                              * stripe unit */
264 
265                                                             if (vfple->fn == NULL)
266                                                                       cantCreateDAGs = RF_TRUE;
267                                                   }
268                                                   numStripeUnitsBailed++;
269                                         }
270                               }
271                               RF_ASSERT(j == numStripeUnits);
272                               numStripesBailed++;
273                     }
274           }
275 
276           if (cantCreateDAGs) {
277                     /* free memory and punt */
278                     if (numStripesBailed > 0) {
279                               stripeNum = 0;
280                               stripeFuncs = stripeFuncsList;
281                               failed_stripe = failed_stripes_list;
282                               for (i = 0, asm_p = asmap; asm_p; asm_p = asm_p->next, i++) {
283                                         if (stripeFuncs->fp == NULL) {
284 
285                                                   asmhle = failed_stripe->asmh_u;
286                                                   while (asmhle) {
287                                                             tmpasmhle= asmhle;
288                                                             asmhle = tmpasmhle->next;
289                                                             rf_FreeAccessStripeMap(raidPtr, tmpasmhle->asmh);
290                                                             rf_FreeASMHeaderListElem(raidPtr, tmpasmhle);
291                                                   }
292 
293                                                   asmhle = failed_stripe->asmh_b;
294                                                   while (asmhle) {
295                                                             tmpasmhle= asmhle;
296                                                             asmhle = tmpasmhle->next;
297                                                             rf_FreeAccessStripeMap(raidPtr, tmpasmhle->asmh);
298                                                             rf_FreeASMHeaderListElem(raidPtr, tmpasmhle);
299                                                   }
300 
301                                                   vfple = failed_stripe->vfple;
302                                                   while (vfple) {
303                                                             tmpvfple = vfple;
304                                                             vfple = tmpvfple->next;
305                                                             rf_FreeVFPListElem(raidPtr, tmpvfple);
306                                                   }
307 
308                                                   vfple = failed_stripe->bvfple;
309                                                   while (vfple) {
310                                                             tmpvfple = vfple;
311                                                             vfple = tmpvfple->next;
312                                                             rf_FreeVFPListElem(raidPtr, tmpvfple);
313                                                   }
314 
315                                                   stripeNum++;
316                                                   /* only move to the next failed stripe slot if the current one was used */
317                                                   tmpfailed_stripe = failed_stripe;
318                                                   failed_stripe = failed_stripe->next;
319                                                   rf_FreeFailedStripeStruct(raidPtr, tmpfailed_stripe);
320                                         }
321                                         stripeFuncs = stripeFuncs->next;
322                               }
323                               RF_ASSERT(stripeNum == numStripesBailed);
324                     }
325                     while (stripeFuncsList != NULL) {
326                               temp = stripeFuncsList;
327                               stripeFuncsList = stripeFuncsList->next;
328                               rf_FreeFuncList(raidPtr, temp);
329                     }
330                     desc->numStripes = 0;
331                     return (1);
332           } else {
333                     /* begin dag creation */
334                     stripeNum = 0;
335                     stripeUnitNum = 0;
336 
337                     /* create a list of dagLists and fill them in */
338 
339                     dagListend = NULL;
340 
341                     stripeFuncs = stripeFuncsList;
342                     failed_stripe = failed_stripes_list;
343                     for (i = 0, asm_p = asmap; asm_p; asm_p = asm_p->next, i++) {
344                               /* grab dag header for this stripe */
345                               dag_h = NULL;
346 
347                               dagList = rf_AllocDAGList(raidPtr);
348 
349                               /* always tack the new dagList onto the end of the list... */
350                               if (dagListend == NULL) {
351                                         desc->dagList = dagList;
352                               } else {
353                                         dagListend->next = dagList;
354                               }
355                               dagListend = dagList;
356 
357                               dagList->desc = desc;
358 
359                               if (stripeFuncs->fp == NULL) {
360                                         /* use bailout functions for this stripe */
361                                         asmhle = failed_stripe->asmh_u;
362                                         vfple = failed_stripe->vfple;
363                                         /* the following two may contain asm headers and
364                                            block function pointers for multiple asm within
365                                            this access.  We initialize tmpasmhle and tmpvfple
366                                            here in order to allow for that, and for correct
367                                            operation below */
368                                         tmpasmhle = failed_stripe->asmh_b;
369                                         tmpvfple = failed_stripe->bvfple;
370                                         for (j = 0, physPtr = asm_p->physInfo; physPtr; physPtr = physPtr->next, j++) {
371                                                   uFunc = vfple->fn; /* stripeUnitFuncs[stripeNum][j]; */
372                                                   if (uFunc == NULL) {
373                                                             /* use bailout functions for
374                                                              * this stripe unit */
375                                                             for (k = 0; k < physPtr->numSector; k++) {
376                                                                       /* create a dag for
377                                                                        * this block */
378                                                                       InitHdrNode(&tempdag_h, raidPtr, desc);
379                                                                       dagList->numDags++;
380                                                                       if (dag_h == NULL) {
381                                                                                 dag_h = tempdag_h;
382                                                                       } else {
383                                                                                 lastdag_h->next = tempdag_h;
384                                                                       }
385                                                                       lastdag_h = tempdag_h;
386 
387                                                                       bFunc = tmpvfple->fn; /* blockFuncs[stripeUnitNum][k]; */
388                                                                       RF_ASSERT(bFunc);
389                                                                       asm_bp = tmpasmhle->asmh->stripeMap; /* asmh_b[stripeUnitNum][k]->stripeMap; */
390                                                                       (*bFunc) (raidPtr, asm_bp, tempdag_h, bp, flags, tempdag_h->allocList);
391 
392                                                                       tmpasmhle = tmpasmhle->next;
393                                                                       tmpvfple = tmpvfple->next;
394                                                             }
395                                                             stripeUnitNum++;
396                                                   } else {
397                                                             /* create a dag for this unit */
398                                                             InitHdrNode(&tempdag_h, raidPtr, desc);
399                                                             dagList->numDags++;
400                                                             if (dag_h == NULL) {
401                                                                       dag_h = tempdag_h;
402                                                             } else {
403                                                                       lastdag_h->next = tempdag_h;
404                                                             }
405                                                             lastdag_h = tempdag_h;
406 
407                                                             asm_up = asmhle->asmh->stripeMap; /* asmh_u[stripeNum][j]->stripeMap; */
408                                                             (*uFunc) (raidPtr, asm_up, tempdag_h, bp, flags, tempdag_h->allocList);
409                                                   }
410                                                   asmhle = asmhle->next;
411                                                   vfple = vfple->next;
412                                         }
413                                         RF_ASSERT(j == asm_p->numStripeUnitsAccessed);
414                                         /* merge linked bailout dag to existing dag
415                                          * collection */
416                                         stripeNum++;
417                                         failed_stripe = failed_stripe->next;
418                               } else {
419                                         /* Create a dag for this parity stripe */
420                                         InitHdrNode(&tempdag_h, raidPtr, desc);
421                                         dagList->numDags++;
422                                         dag_h = tempdag_h;
423                                         lastdag_h = tempdag_h;
424 
425                                         (stripeFuncs->fp) (raidPtr, asm_p, tempdag_h, bp, flags, tempdag_h->allocList);
426                               }
427                               dagList->dags = dag_h;
428                               stripeFuncs = stripeFuncs->next;
429                     }
430                     RF_ASSERT(i == desc->numStripes);
431 
432                     /* free memory */
433                     if ((numStripesBailed > 0) || (numStripeUnitsBailed > 0)) {
434                               stripeNum = 0;
435                               stripeUnitNum = 0;
436                               /* walk through io, stripe by stripe */
437                               /* here we build up dag_h->asmList for this dag...
438                                  we need all of these asm's to do the IO, and
439                                  want them in a convenient place for freeing at a
440                                  later time */
441                               stripeFuncs = stripeFuncsList;
442                               failed_stripe = failed_stripes_list;
443                               dagList = desc->dagList;
444 
445                               for (i = 0, asm_p = asmap; asm_p; asm_p = asm_p->next, i++) {
446 
447                                         dag_h = dagList->dags;
448                                         if (dag_h->asmList) {
449                                                   endASMList = dag_h->asmList;
450                                                   while (endASMList->next)
451                                                             endASMList = endASMList->next;
452                                         } else
453                                                   endASMList = NULL;
454 
455                                         if (stripeFuncs->fp == NULL) {
456                                                   numStripeUnits = asm_p->numStripeUnitsAccessed;
457                                                   /* walk through stripe, stripe unit by
458                                                    * stripe unit */
459                                                   asmhle = failed_stripe->asmh_u;
460                                                   vfple = failed_stripe->vfple;
461                                                   /* this contains all of the asm headers for block funcs,
462                                                      so we have to initialize this here instead of below.*/
463                                                   tmpasmhle = failed_stripe->asmh_b;
464                                                   for (j = 0, physPtr = asm_p->physInfo; physPtr; physPtr = physPtr->next, j++) {
465                                                             if (vfple->fn == NULL) {
466                                                                       numBlocks = physPtr->numSector;
467                                                                       /* walk through stripe
468                                                                        * unit, block by
469                                                                        * block */
470                                                                       for (k = 0; k < numBlocks; k++) {
471                                                                                 if (dag_h->asmList == NULL) {
472                                                                                           dag_h->asmList = tmpasmhle->asmh; /* asmh_b[stripeUnitNum][k];*/
473                                                                                           endASMList = dag_h->asmList;
474                                                                                 } else {
475                                                                                           endASMList->next = tmpasmhle->asmh;
476                                                                                           endASMList = endASMList->next;
477                                                                                 }
478                                                                                 tmpasmhle = tmpasmhle->next;
479                                                                       }
480                                                                       stripeUnitNum++;
481                                                             }
482                                                             if (dag_h->asmList == NULL) {
483                                                                       dag_h->asmList = asmhle->asmh;
484                                                                       endASMList = dag_h->asmList;
485                                                             } else {
486                                                                       endASMList->next = asmhle->asmh;
487                                                                       endASMList = endASMList->next;
488                                                             }
489                                                             asmhle = asmhle->next;
490                                                             vfple = vfple->next;
491                                                   }
492                                                   stripeNum++;
493                                                   failed_stripe = failed_stripe->next;
494                                         }
495                                         dagList = dagList->next; /* need to move in stride with stripeFuncs */
496                                         stripeFuncs = stripeFuncs->next;
497                               }
498                               RF_ASSERT(stripeNum == numStripesBailed);
499                               RF_ASSERT(stripeUnitNum == numStripeUnitsBailed);
500 
501                               failed_stripe = failed_stripes_list;
502                               while (failed_stripe) {
503 
504                                         asmhle = failed_stripe->asmh_u;
505                                         while (asmhle) {
506                                                   tmpasmhle= asmhle;
507                                                   asmhle = tmpasmhle->next;
508                                                   rf_FreeASMHeaderListElem(raidPtr, tmpasmhle);
509                                         }
510 
511                                         asmhle = failed_stripe->asmh_b;
512                                         while (asmhle) {
513                                                   tmpasmhle= asmhle;
514                                                   asmhle = tmpasmhle->next;
515                                                   rf_FreeASMHeaderListElem(raidPtr, tmpasmhle);
516                                         }
517                                         vfple = failed_stripe->vfple;
518                                         while (vfple) {
519                                                   tmpvfple = vfple;
520                                                   vfple = tmpvfple->next;
521                                                   rf_FreeVFPListElem(raidPtr, tmpvfple);
522                                         }
523 
524                                         vfple = failed_stripe->bvfple;
525                                         while (vfple) {
526                                                   tmpvfple = vfple;
527                                                   vfple = tmpvfple->next;
528                                                   rf_FreeVFPListElem(raidPtr, tmpvfple);
529                                         }
530 
531                                         tmpfailed_stripe = failed_stripe;
532                                         failed_stripe = tmpfailed_stripe->next;
533                                         rf_FreeFailedStripeStruct(raidPtr, tmpfailed_stripe);
534                               }
535                     }
536                     while (stripeFuncsList != NULL) {
537                               temp = stripeFuncsList;
538                               stripeFuncsList = stripeFuncsList->next;
539                               rf_FreeFuncList(raidPtr, temp);
540                     }
541                     return (0);
542           }
543 }
544