rf_states.c revision 1.5 1 /* $NetBSD: rf_states.c,v 1.5 1999/01/26 04:40:03 oster Exp $ */
2 /*
3 * Copyright (c) 1995 Carnegie-Mellon University.
4 * All rights reserved.
5 *
6 * Author: Mark Holland, William V. Courtright II, Robby Findler
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 (at) 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 #include <sys/errno.h>
30
31 #include "rf_archs.h"
32 #include "rf_threadstuff.h"
33 #include "rf_raid.h"
34 #include "rf_dag.h"
35 #include "rf_desc.h"
36 #include "rf_aselect.h"
37 #include "rf_threadid.h"
38 #include "rf_general.h"
39 #include "rf_states.h"
40 #include "rf_dagutils.h"
41 #include "rf_driver.h"
42 #include "rf_engine.h"
43 #include "rf_map.h"
44 #include "rf_etimer.h"
45
46 #if defined(KERNEL) && (DKUSAGE > 0)
47 #include <sys/dkusage.h>
48 #include <io/common/iotypes.h>
49 #include <io/cam/dec_cam.h>
50 #include <io/cam/cam.h>
51 #include <io/cam/pdrv.h>
52 #endif /* KERNEL && DKUSAGE > 0 */
53
54 /* prototypes for some of the available states.
55
56 States must:
57
58 - not block.
59
60 - either schedule rf_ContinueRaidAccess as a callback and return
61 RF_TRUE, or complete all of their work and return RF_FALSE.
62
63 - increment desc->state when they have finished their work.
64 */
65
66 static char *StateName(RF_AccessState_t state)
67 {
68 switch (state) {
69 case rf_QuiesceState: return "QuiesceState";
70 case rf_MapState: return "MapState";
71 case rf_LockState: return "LockState";
72 case rf_CreateDAGState: return "CreateDAGState";
73 case rf_ExecuteDAGState: return "ExecuteDAGState";
74 case rf_ProcessDAGState: return "ProcessDAGState";
75 case rf_CleanupState: return "CleanupState";
76 case rf_LastState: return "LastState";
77 case rf_IncrAccessesCountState: return "IncrAccessesCountState";
78 case rf_DecrAccessesCountState: return "DecrAccessesCountState";
79 default: return "!!! UnnamedState !!!";
80 }
81 }
82
83 void rf_ContinueRaidAccess(RF_RaidAccessDesc_t *desc)
84 {
85 int suspended = RF_FALSE;
86 int current_state_index = desc->state;
87 RF_AccessState_t current_state = desc->states[current_state_index];
88
89 do {
90
91 current_state_index = desc->state;
92 current_state = desc->states [current_state_index];
93
94 switch (current_state) {
95
96 case rf_QuiesceState: suspended = rf_State_Quiesce(desc);
97 break;
98 case rf_IncrAccessesCountState: suspended = rf_State_IncrAccessCount(desc);
99 break;
100 case rf_MapState: suspended = rf_State_Map(desc);
101 break;
102 case rf_LockState: suspended = rf_State_Lock(desc);
103 break;
104 case rf_CreateDAGState: suspended = rf_State_CreateDAG(desc);
105 break;
106 case rf_ExecuteDAGState: suspended = rf_State_ExecuteDAG(desc);
107 break;
108 case rf_ProcessDAGState: suspended = rf_State_ProcessDAG(desc);
109 break;
110 case rf_CleanupState: suspended = rf_State_Cleanup(desc);
111 break;
112 case rf_DecrAccessesCountState: suspended = rf_State_DecrAccessCount(desc);
113 break;
114 case rf_LastState: suspended = rf_State_LastState(desc);
115 break;
116 }
117
118 /* after this point, we cannot dereference desc since desc may
119 have been freed. desc is only freed in LastState, so if we
120 renter this function or loop back up, desc should be valid. */
121
122 if (rf_printStatesDebug) {
123 int tid;
124 rf_get_threadid (tid);
125
126 printf ("[%d] State: %-24s StateIndex: %3i desc: 0x%ld %s\n",
127 tid, StateName(current_state), current_state_index, (long)desc,
128 suspended ? "callback scheduled" : "looping");
129 }
130 } while (!suspended && current_state != rf_LastState);
131
132 return;
133 }
134
135
136 void rf_ContinueDagAccess (RF_DagList_t *dagList)
137 {
138 RF_AccTraceEntry_t *tracerec = &(dagList->desc->tracerec);
139 RF_RaidAccessDesc_t *desc;
140 RF_DagHeader_t *dag_h;
141 RF_Etimer_t timer;
142 int i;
143
144 desc = dagList->desc;
145
146 timer = tracerec->timer;
147 RF_ETIMER_STOP(timer);
148 RF_ETIMER_EVAL(timer);
149 tracerec->specific.user.exec_us = RF_ETIMER_VAL_US(timer);
150 RF_ETIMER_START(tracerec->timer);
151
152 /* skip to dag which just finished */
153 dag_h = dagList->dags;
154 for (i = 0; i < dagList->numDagsDone; i++) {
155 dag_h = dag_h->next;
156 }
157
158 /* check to see if retry is required */
159 if (dag_h->status == rf_rollBackward) {
160 /* when a dag fails, mark desc status as bad and allow all other dags
161 * in the desc to execute to completion. then, free all dags and start over */
162 desc->status = 1; /* bad status */
163 {
164 printf("[%d] DAG failure: %c addr 0x%lx (%ld) nblk 0x%x (%d) buf 0x%lx\n",
165 desc->tid, desc->type, (long)desc->raidAddress,
166 (long)desc->raidAddress,(int)desc->numBlocks,
167 (int)desc->numBlocks, (unsigned long) (desc->bufPtr));
168 }
169 }
170
171 dagList->numDagsDone++;
172 rf_ContinueRaidAccess(desc);
173 }
174
175
176 int rf_State_LastState(RF_RaidAccessDesc_t *desc)
177 {
178 void (*callbackFunc)(RF_CBParam_t) = desc->callbackFunc;
179 RF_CBParam_t callbackArg;
180
181 callbackArg.p = desc->callbackArg;
182
183 if (!(desc->flags & RF_DAG_TEST_ACCESS)) {/* don't biodone if this */
184 #if DKUSAGE > 0
185 RF_DKU_END_IO(((RF_Raid_t *)desc->raidPtr)->raidid,(struct buf *)desc->bp);
186 #else
187 RF_DKU_END_IO(((RF_Raid_t *)desc->raidPtr)->raidid);
188 #endif /* DKUSAGE > 0 */
189
190 /*
191 * If this is not an async request, wake up the caller
192 */
193 if (desc->async_flag == 0)
194 wakeup(desc->bp);
195
196 /* printf("Calling biodone on 0x%x\n",desc->bp); */
197 biodone(desc->bp); /* access came through ioctl */
198 }
199
200 if (callbackFunc) callbackFunc(callbackArg);
201 rf_FreeRaidAccDesc(desc);
202
203 return RF_FALSE;
204 }
205
206 int rf_State_IncrAccessCount(RF_RaidAccessDesc_t *desc)
207 {
208 RF_Raid_t *raidPtr;
209
210 raidPtr = desc->raidPtr;
211 /* Bummer. We have to do this to be 100% safe w.r.t. the increment below */
212 RF_LOCK_MUTEX(raidPtr->access_suspend_mutex);
213 raidPtr->accs_in_flight++; /* used to detect quiescence */
214 RF_UNLOCK_MUTEX(raidPtr->access_suspend_mutex);
215
216 desc->state++;
217 return RF_FALSE;
218 }
219
220 int rf_State_DecrAccessCount(RF_RaidAccessDesc_t *desc)
221 {
222 RF_Raid_t *raidPtr;
223
224 raidPtr = desc->raidPtr;
225
226 RF_LOCK_MUTEX(raidPtr->access_suspend_mutex);
227 raidPtr->accs_in_flight--;
228 if (raidPtr->accesses_suspended && raidPtr->accs_in_flight == 0) {
229 rf_SignalQuiescenceLock(raidPtr, raidPtr->reconDesc);
230 }
231 rf_UpdateUserStats(raidPtr, RF_ETIMER_VAL_US(desc->timer), desc->numBlocks);
232 RF_UNLOCK_MUTEX(raidPtr->access_suspend_mutex);
233
234 desc->state++;
235 return RF_FALSE;
236 }
237
238 int rf_State_Quiesce(RF_RaidAccessDesc_t *desc)
239 {
240 RF_AccTraceEntry_t *tracerec = &desc->tracerec;
241 RF_Etimer_t timer;
242 int suspended = RF_FALSE;
243 RF_Raid_t *raidPtr;
244
245 raidPtr = desc->raidPtr;
246
247 RF_ETIMER_START(timer);
248 RF_ETIMER_START(desc->timer);
249
250 RF_LOCK_MUTEX(raidPtr->access_suspend_mutex);
251 if (raidPtr->accesses_suspended) {
252 RF_CallbackDesc_t *cb;
253 cb = rf_AllocCallbackDesc();
254 /* XXX the following cast is quite bogus... rf_ContinueRaidAccess
255 takes a (RF_RaidAccessDesc_t *) as an argument.. GO */
256 cb->callbackFunc = (void (*)(RF_CBParam_t))rf_ContinueRaidAccess;
257 cb->callbackArg.p = (void *) desc;
258 cb->next = raidPtr->quiesce_wait_list;
259 raidPtr->quiesce_wait_list = cb;
260 suspended = RF_TRUE;
261 }
262
263 RF_UNLOCK_MUTEX(raidPtr->access_suspend_mutex);
264
265 RF_ETIMER_STOP(timer);
266 RF_ETIMER_EVAL(timer);
267 tracerec->specific.user.suspend_ovhd_us += RF_ETIMER_VAL_US(timer);
268
269 if (suspended && rf_quiesceDebug)
270 printf("Stalling access due to quiescence lock\n");
271
272 desc->state++;
273 return suspended;
274 }
275
276 int rf_State_Map(RF_RaidAccessDesc_t *desc)
277 {
278 RF_Raid_t *raidPtr = desc->raidPtr;
279 RF_AccTraceEntry_t *tracerec = &desc->tracerec;
280 RF_Etimer_t timer;
281
282 RF_ETIMER_START(timer);
283
284 if (!(desc->asmap = rf_MapAccess(raidPtr, desc->raidAddress, desc->numBlocks,
285 desc->bufPtr, RF_DONT_REMAP)))
286 RF_PANIC();
287
288 RF_ETIMER_STOP(timer);
289 RF_ETIMER_EVAL(timer);
290 tracerec->specific.user.map_us = RF_ETIMER_VAL_US(timer);
291
292 desc->state ++;
293 return RF_FALSE;
294 }
295
296 int rf_State_Lock(RF_RaidAccessDesc_t *desc)
297 {
298 RF_AccTraceEntry_t *tracerec = &desc->tracerec;
299 RF_Raid_t *raidPtr = desc->raidPtr;
300 RF_AccessStripeMapHeader_t *asmh = desc->asmap;
301 RF_AccessStripeMap_t *asm_p;
302 RF_Etimer_t timer;
303 int suspended = RF_FALSE;
304
305 RF_ETIMER_START(timer);
306 if (!(raidPtr->Layout.map->flags & RF_NO_STRIPE_LOCKS)) {
307 RF_StripeNum_t lastStripeID = -1;
308
309 /* acquire each lock that we don't already hold */
310 for (asm_p = asmh->stripeMap; asm_p; asm_p = asm_p->next) {
311 RF_ASSERT(RF_IO_IS_R_OR_W(desc->type));
312 if (!rf_suppressLocksAndLargeWrites &&
313 asm_p->parityInfo &&
314 !(desc->flags& RF_DAG_SUPPRESS_LOCKS) &&
315 !(asm_p->flags & RF_ASM_FLAGS_LOCK_TRIED))
316 {
317 asm_p->flags |= RF_ASM_FLAGS_LOCK_TRIED;
318 RF_ASSERT(asm_p->stripeID > lastStripeID); /* locks must be acquired
319 hierarchically */
320 lastStripeID = asm_p->stripeID;
321 /* XXX the cast to (void (*)(RF_CBParam_t)) below is bogus! GO */
322 RF_INIT_LOCK_REQ_DESC(asm_p->lockReqDesc, desc->type,
323 (void (*)(struct buf *))rf_ContinueRaidAccess, desc, asm_p,
324 raidPtr->Layout.dataSectorsPerStripe);
325 if (rf_AcquireStripeLock(raidPtr->lockTable, asm_p->stripeID,
326 &asm_p->lockReqDesc))
327 {
328 suspended = RF_TRUE;
329 break;
330 }
331 }
332
333 if (desc->type == RF_IO_TYPE_WRITE &&
334 raidPtr->status[asm_p->physInfo->row] == rf_rs_reconstructing)
335 {
336 if (! (asm_p->flags & RF_ASM_FLAGS_FORCE_TRIED) ) {
337 int val;
338
339 asm_p->flags |= RF_ASM_FLAGS_FORCE_TRIED;
340 /* XXX the cast below is quite bogus!!! XXX GO */
341 val = rf_ForceOrBlockRecon(raidPtr, asm_p,
342 (void (*)(RF_Raid_t *,void *))rf_ContinueRaidAccess, desc);
343 if (val == 0) {
344 asm_p->flags |= RF_ASM_FLAGS_RECON_BLOCKED;
345 }
346 else {
347 suspended = RF_TRUE;
348 break;
349 }
350 }
351 else {
352 if (rf_pssDebug) {
353 printf("[%d] skipping force/block because already done, psid %ld\n",
354 desc->tid,(long)asm_p->stripeID);
355 }
356 }
357 }
358 else {
359 if (rf_pssDebug) {
360 printf("[%d] skipping force/block because not write or not under recon, psid %ld\n",
361 desc->tid,(long)asm_p->stripeID);
362 }
363 }
364 }
365
366 RF_ETIMER_STOP(timer);
367 RF_ETIMER_EVAL(timer);
368 tracerec->specific.user.lock_us += RF_ETIMER_VAL_US(timer);
369
370 if (suspended)
371 return(RF_TRUE);
372 }
373
374 desc->state++;
375 return(RF_FALSE);
376 }
377
378 /*
379 * the following three states create, execute, and post-process dags
380 * the error recovery unit is a single dag.
381 * by default, SelectAlgorithm creates an array of dags, one per parity stripe
382 * in some tricky cases, multiple dags per stripe are created
383 * - dags within a parity stripe are executed sequentially (arbitrary order)
384 * - dags for distinct parity stripes are executed concurrently
385 *
386 * repeat until all dags complete successfully -or- dag selection fails
387 *
388 * while !done
389 * create dag(s) (SelectAlgorithm)
390 * if dag
391 * execute dag (DispatchDAG)
392 * if dag successful
393 * done (SUCCESS)
394 * else
395 * !done (RETRY - start over with new dags)
396 * else
397 * done (FAIL)
398 */
399 int rf_State_CreateDAG (RF_RaidAccessDesc_t *desc)
400 {
401 RF_AccTraceEntry_t *tracerec = &desc->tracerec;
402 RF_Etimer_t timer;
403 RF_DagHeader_t *dag_h;
404 int i, selectStatus;
405
406 /* generate a dag for the access, and fire it off. When the dag
407 completes, we'll get re-invoked in the next state. */
408 RF_ETIMER_START(timer);
409 /* SelectAlgorithm returns one or more dags */
410 selectStatus = rf_SelectAlgorithm(desc, desc->flags|RF_DAG_SUPPRESS_LOCKS);
411 if (rf_printDAGsDebug)
412 for (i = 0; i < desc->numStripes; i++)
413 rf_PrintDAGList(desc->dagArray[i].dags);
414 RF_ETIMER_STOP(timer);
415 RF_ETIMER_EVAL(timer);
416 /* update time to create all dags */
417 tracerec->specific.user.dag_create_us = RF_ETIMER_VAL_US(timer);
418
419 desc->status = 0; /* good status */
420
421 if (selectStatus) {
422 /* failed to create a dag */
423 /* this happens when there are too many faults or incomplete dag libraries */
424 printf("[Failed to create a DAG\n]");
425 RF_PANIC();
426 }
427 else {
428 /* bind dags to desc */
429 for (i = 0; i < desc->numStripes; i++) {
430 dag_h = desc->dagArray[i].dags;
431 while (dag_h) {
432 dag_h->bp = (struct buf *) desc->bp;
433 dag_h->tracerec = tracerec;
434 dag_h = dag_h->next;
435 }
436 }
437 desc->flags |= RF_DAG_DISPATCH_RETURNED;
438 desc->state++; /* next state should be rf_State_ExecuteDAG */
439 }
440 return RF_FALSE;
441 }
442
443
444
445 /* the access has an array of dagLists, one dagList per parity stripe.
446 * fire the first dag in each parity stripe (dagList).
447 * dags within a stripe (dagList) must be executed sequentially
448 * - this preserves atomic parity update
449 * dags for independents parity groups (stripes) are fired concurrently */
450
451 int rf_State_ExecuteDAG(RF_RaidAccessDesc_t *desc)
452 {
453 int i;
454 RF_DagHeader_t *dag_h;
455 RF_DagList_t *dagArray = desc->dagArray;
456
457 /* next state is always rf_State_ProcessDAG
458 * important to do this before firing the first dag
459 * (it may finish before we leave this routine) */
460 desc->state++;
461
462 /* sweep dag array, a stripe at a time, firing the first dag in each stripe */
463 for (i = 0; i < desc->numStripes; i++) {
464 RF_ASSERT(dagArray[i].numDags > 0);
465 RF_ASSERT(dagArray[i].numDagsDone == 0);
466 RF_ASSERT(dagArray[i].numDagsFired == 0);
467 RF_ETIMER_START(dagArray[i].tracerec.timer);
468 /* fire first dag in this stripe */
469 dag_h = dagArray[i].dags;
470 RF_ASSERT(dag_h);
471 dagArray[i].numDagsFired++;
472 /* XXX Yet another case where we pass in a conflicting function pointer
473 :-( XXX GO */
474 rf_DispatchDAG(dag_h, (void (*)(void *))rf_ContinueDagAccess, &dagArray[i]);
475 }
476
477 /* the DAG will always call the callback, even if there was no
478 * blocking, so we are always suspended in this state */
479 return RF_TRUE;
480 }
481
482
483
484 /* rf_State_ProcessDAG is entered when a dag completes.
485 * first, check to all dags in the access have completed
486 * if not, fire as many dags as possible */
487
488 int rf_State_ProcessDAG(RF_RaidAccessDesc_t *desc)
489 {
490 RF_AccessStripeMapHeader_t *asmh = desc->asmap;
491 RF_Raid_t *raidPtr = desc->raidPtr;
492 RF_DagHeader_t *dag_h;
493 int i, j, done = RF_TRUE;
494 RF_DagList_t *dagArray = desc->dagArray;
495 RF_Etimer_t timer;
496
497 /* check to see if this is the last dag */
498 for (i = 0; i < desc->numStripes; i++)
499 if (dagArray[i].numDags != dagArray[i].numDagsDone)
500 done = RF_FALSE;
501
502 if (done) {
503 if (desc->status) {
504 /* a dag failed, retry */
505 RF_ETIMER_START(timer);
506 /* free all dags */
507 for (i = 0; i < desc->numStripes; i++) {
508 rf_FreeDAG(desc->dagArray[i].dags);
509 }
510 rf_MarkFailuresInASMList(raidPtr, asmh);
511 /* back up to rf_State_CreateDAG */
512 desc->state = desc->state - 2;
513 return RF_FALSE;
514 }
515 else {
516 /* move on to rf_State_Cleanup */
517 desc->state++;
518 }
519 return RF_FALSE;
520 }
521 else {
522 /* more dags to execute */
523 /* see if any are ready to be fired. if so, fire them */
524 /* don't fire the initial dag in a list, it's fired in rf_State_ExecuteDAG */
525 for (i = 0; i < desc->numStripes; i++) {
526 if ((dagArray[i].numDagsDone < dagArray[i].numDags)
527 && (dagArray[i].numDagsDone == dagArray[i].numDagsFired)
528 && (dagArray[i].numDagsFired > 0)) {
529 RF_ETIMER_START(dagArray[i].tracerec.timer);
530 /* fire next dag in this stripe */
531 /* first, skip to next dag awaiting execution */
532 dag_h = dagArray[i].dags;
533 for (j = 0; j < dagArray[i].numDagsDone; j++)
534 dag_h = dag_h->next;
535 dagArray[i].numDagsFired++;
536 /* XXX and again we pass a different function pointer.. GO */
537 rf_DispatchDAG(dag_h, (void (*)(void *))rf_ContinueDagAccess,
538 &dagArray[i]);
539 }
540 }
541 return RF_TRUE;
542 }
543 }
544
545 /* only make it this far if all dags complete successfully */
546 int rf_State_Cleanup(RF_RaidAccessDesc_t *desc)
547 {
548 RF_AccTraceEntry_t *tracerec = &desc->tracerec;
549 RF_AccessStripeMapHeader_t *asmh = desc->asmap;
550 RF_Raid_t *raidPtr = desc->raidPtr;
551 RF_AccessStripeMap_t *asm_p;
552 RF_DagHeader_t *dag_h;
553 RF_Etimer_t timer;
554 int tid, i;
555
556 desc->state ++;
557
558 rf_get_threadid(tid);
559
560 timer = tracerec->timer;
561 RF_ETIMER_STOP(timer);
562 RF_ETIMER_EVAL(timer);
563 tracerec->specific.user.dag_retry_us = RF_ETIMER_VAL_US(timer);
564
565 /* the RAID I/O is complete. Clean up. */
566 tracerec->specific.user.dag_retry_us = 0;
567
568 RF_ETIMER_START(timer);
569 if (desc->flags & RF_DAG_RETURN_DAG) {
570 /* copy dags into paramDAG */
571 *(desc->paramDAG) = desc->dagArray[0].dags;
572 dag_h = *(desc->paramDAG);
573 for (i = 1; i < desc->numStripes; i++) {
574 /* concatenate dags from remaining stripes */
575 RF_ASSERT(dag_h);
576 while (dag_h->next)
577 dag_h = dag_h->next;
578 dag_h->next = desc->dagArray[i].dags;
579 }
580 }
581 else {
582 /* free all dags */
583 for (i = 0; i < desc->numStripes; i++) {
584 rf_FreeDAG(desc->dagArray[i].dags);
585 }
586 }
587
588 RF_ETIMER_STOP(timer);
589 RF_ETIMER_EVAL(timer);
590 tracerec->specific.user.cleanup_us = RF_ETIMER_VAL_US(timer);
591
592 RF_ETIMER_START(timer);
593 if (!(raidPtr->Layout.map->flags & RF_NO_STRIPE_LOCKS)) {
594 for (asm_p = asmh->stripeMap; asm_p; asm_p = asm_p->next) {
595 if (!rf_suppressLocksAndLargeWrites &&
596 asm_p->parityInfo &&
597 !(desc->flags&RF_DAG_SUPPRESS_LOCKS))
598 {
599 RF_ASSERT_VALID_LOCKREQ(&asm_p->lockReqDesc);
600 rf_ReleaseStripeLock(raidPtr->lockTable, asm_p->stripeID,
601 &asm_p->lockReqDesc);
602 }
603 if (asm_p->flags & RF_ASM_FLAGS_RECON_BLOCKED) {
604 rf_UnblockRecon(raidPtr, asm_p);
605 }
606 }
607 }
608
609 RF_ETIMER_STOP(timer);
610 RF_ETIMER_EVAL(timer);
611 tracerec->specific.user.lock_us += RF_ETIMER_VAL_US(timer);
612
613 RF_ETIMER_START(timer);
614 if (desc->flags & RF_DAG_RETURN_ASM)
615 *(desc->paramASM) = asmh;
616 else
617 rf_FreeAccessStripeMap(asmh);
618 RF_ETIMER_STOP(timer);
619 RF_ETIMER_EVAL(timer);
620 tracerec->specific.user.cleanup_us += RF_ETIMER_VAL_US(timer);
621
622 RF_ETIMER_STOP(desc->timer);
623 RF_ETIMER_EVAL(desc->timer);
624
625 timer = desc->tracerec.tot_timer;
626 RF_ETIMER_STOP(timer);
627 RF_ETIMER_EVAL(timer);
628 desc->tracerec.total_us = RF_ETIMER_VAL_US(timer);
629
630 rf_LogTraceRec(raidPtr, tracerec);
631
632 desc->flags |= RF_DAG_ACCESS_COMPLETE;
633
634 return RF_FALSE;
635 }
636