xref: /netbsd-src/sys/dev/raidframe/rf_sstf.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /*	$NetBSD: rf_sstf.c,v 1.11 2004/03/04 01:57:54 oster Exp $	*/
2 /*
3  * Copyright (c) 1995 Carnegie-Mellon University.
4  * All rights reserved.
5  *
6  * Author: Jim Zelenka
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  * sstf.c --  prioritized shortest seek time first disk queueing code
32  *
33  ******************************************************************************/
34 
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: rf_sstf.c,v 1.11 2004/03/04 01:57:54 oster Exp $");
37 
38 #include <dev/raidframe/raidframevar.h>
39 
40 #include "rf_alloclist.h"
41 #include "rf_stripelocks.h"
42 #include "rf_layout.h"
43 #include "rf_diskqueue.h"
44 #include "rf_sstf.h"
45 #include "rf_debugMem.h"
46 #include "rf_general.h"
47 #include "rf_options.h"
48 #include "rf_raid.h"
49 
50 #define DIR_LEFT   1
51 #define DIR_RIGHT  2
52 #define DIR_EITHER 3
53 
54 #define SNUM_DIFF(_a_,_b_) (((_a_)>(_b_))?((_a_)-(_b_)):((_b_)-(_a_)))
55 
56 #define QSUM(_sstfq_) (((_sstfq_)->lopri.qlen)+((_sstfq_)->left.qlen)+((_sstfq_)->right.qlen))
57 
58 
59 static void
60 do_sstf_ord_q(RF_DiskQueueData_t **,
61     RF_DiskQueueData_t **,
62     RF_DiskQueueData_t *);
63 
64 static RF_DiskQueueData_t *
65 closest_to_arm(RF_SstfQ_t *,
66     RF_SectorNum_t,
67     int *,
68     int);
69 static void do_dequeue(RF_SstfQ_t *, RF_DiskQueueData_t *);
70 
71 
72 static void
73 do_sstf_ord_q(queuep, tailp, req)
74 	RF_DiskQueueData_t **queuep;
75 	RF_DiskQueueData_t **tailp;
76 	RF_DiskQueueData_t *req;
77 {
78 	RF_DiskQueueData_t *r, *s;
79 
80 	if (*queuep == NULL) {
81 		*queuep = req;
82 		*tailp = req;
83 		req->next = NULL;
84 		req->prev = NULL;
85 		return;
86 	}
87 	if (req->sectorOffset <= (*queuep)->sectorOffset) {
88 		req->next = *queuep;
89 		req->prev = NULL;
90 		(*queuep)->prev = req;
91 		*queuep = req;
92 		return;
93 	}
94 	if (req->sectorOffset > (*tailp)->sectorOffset) {
95 		/* optimization */
96 		r = NULL;
97 		s = *tailp;
98 		goto q_at_end;
99 	}
100 	for (s = NULL, r = *queuep; r; s = r, r = r->next) {
101 		if (r->sectorOffset >= req->sectorOffset) {
102 			/* insert after s, before r */
103 			RF_ASSERT(s);
104 			req->next = r;
105 			r->prev = req;
106 			s->next = req;
107 			req->prev = s;
108 			return;
109 		}
110 	}
111 q_at_end:
112 	/* insert after s, at end of queue */
113 	RF_ASSERT(r == NULL);
114 	RF_ASSERT(s);
115 	RF_ASSERT(s == (*tailp));
116 	req->next = NULL;
117 	req->prev = s;
118 	s->next = req;
119 	*tailp = req;
120 }
121 /* for removing from head-of-queue */
122 #define DO_HEAD_DEQ(_r_,_q_) { \
123 	_r_ = (_q_)->queue; \
124 	RF_ASSERT((_r_) != NULL); \
125 	(_q_)->queue = (_r_)->next; \
126 	(_q_)->qlen--; \
127 	if ((_q_)->qlen == 0) { \
128 		RF_ASSERT((_r_) == (_q_)->qtail); \
129 		RF_ASSERT((_q_)->queue == NULL); \
130 		(_q_)->qtail = NULL; \
131 	} \
132 	else { \
133 		RF_ASSERT((_q_)->queue->prev == (_r_)); \
134 		(_q_)->queue->prev = NULL; \
135 	} \
136 }
137 
138 /* for removing from end-of-queue */
139 #define DO_TAIL_DEQ(_r_,_q_) { \
140 	_r_ = (_q_)->qtail; \
141 	RF_ASSERT((_r_) != NULL); \
142 	(_q_)->qtail = (_r_)->prev; \
143 	(_q_)->qlen--; \
144 	if ((_q_)->qlen == 0) { \
145 		RF_ASSERT((_r_) == (_q_)->queue); \
146 		RF_ASSERT((_q_)->qtail == NULL); \
147 		(_q_)->queue = NULL; \
148 	} \
149 	else { \
150 		RF_ASSERT((_q_)->qtail->next == (_r_)); \
151 		(_q_)->qtail->next = NULL; \
152 	} \
153 }
154 
155 #define DO_BEST_DEQ(_l_,_r_,_q_) { \
156 	if (SNUM_DIFF((_q_)->queue->sectorOffset,_l_) \
157 		< SNUM_DIFF((_q_)->qtail->sectorOffset,_l_)) \
158 	{ \
159 		DO_HEAD_DEQ(_r_,_q_); \
160 	} \
161 	else { \
162 		DO_TAIL_DEQ(_r_,_q_); \
163 	} \
164 }
165 
166 static RF_DiskQueueData_t *
167 closest_to_arm(queue, arm_pos, dir, allow_reverse)
168 	RF_SstfQ_t *queue;
169 	RF_SectorNum_t arm_pos;
170 	int    *dir;
171 	int     allow_reverse;
172 {
173 	RF_SectorNum_t best_pos_l = 0, this_pos_l = 0, last_pos = 0;
174 	RF_SectorNum_t best_pos_r = 0, this_pos_r = 0;
175 	RF_DiskQueueData_t *r, *best_l, *best_r;
176 
177 	best_r = best_l = NULL;
178 	for (r = queue->queue; r; r = r->next) {
179 		if (r->sectorOffset < arm_pos) {
180 			if (best_l == NULL) {
181 				best_l = r;
182 				last_pos = best_pos_l = this_pos_l;
183 			} else {
184 				this_pos_l = arm_pos - r->sectorOffset;
185 				if (this_pos_l < best_pos_l) {
186 					best_l = r;
187 					last_pos = best_pos_l = this_pos_l;
188 				} else {
189 					last_pos = this_pos_l;
190 				}
191 			}
192 		} else {
193 			if (best_r == NULL) {
194 				best_r = r;
195 				last_pos = best_pos_r = this_pos_r;
196 			} else {
197 				this_pos_r = r->sectorOffset - arm_pos;
198 				if (this_pos_r < best_pos_r) {
199 					best_r = r;
200 					last_pos = best_pos_r = this_pos_r;
201 				} else {
202 					last_pos = this_pos_r;
203 				}
204 				if (this_pos_r > last_pos) {
205 					/* getting farther away */
206 					break;
207 				}
208 			}
209 		}
210 	}
211 	if ((best_r == NULL) && (best_l == NULL))
212 		return (NULL);
213 	if ((*dir == DIR_RIGHT) && best_r)
214 		return (best_r);
215 	if ((*dir == DIR_LEFT) && best_l)
216 		return (best_l);
217 	if (*dir == DIR_EITHER) {
218 		if (best_l == NULL)
219 			return (best_r);
220 		if (best_r == NULL)
221 			return (best_l);
222 		if (best_pos_r < best_pos_l)
223 			return (best_r);
224 		else
225 			return (best_l);
226 	}
227 	/*
228 	 * Nothing in the direction we want to go. Reverse or
229 	 * reset the arm. We know we have an I/O in the other
230 	 * direction.
231 	 */
232 	if (allow_reverse) {
233 		if (*dir == DIR_RIGHT) {
234 			*dir = DIR_LEFT;
235 			return (best_l);
236 		} else {
237 			*dir = DIR_RIGHT;
238 			return (best_r);
239 		}
240 	}
241 	/*
242 	 * Reset (beginning of queue).
243 	 */
244 	RF_ASSERT(*dir == DIR_RIGHT);
245 	return (queue->queue);
246 }
247 
248 void   *
249 rf_SstfCreate(sect_per_disk, cl_list, listp)
250 	RF_SectorCount_t sect_per_disk;
251 	RF_AllocListElem_t *cl_list;
252 	RF_ShutdownList_t **listp;
253 {
254 	RF_Sstf_t *sstfq;
255 
256 	RF_MallocAndAdd(sstfq, sizeof(RF_Sstf_t), (RF_Sstf_t *), cl_list);
257 	sstfq->dir = DIR_EITHER;
258 	sstfq->allow_reverse = 1;
259 	return ((void *) sstfq);
260 }
261 
262 void   *
263 rf_ScanCreate(sect_per_disk, cl_list, listp)
264 	RF_SectorCount_t sect_per_disk;
265 	RF_AllocListElem_t *cl_list;
266 	RF_ShutdownList_t **listp;
267 {
268 	RF_Sstf_t *scanq;
269 
270 	RF_MallocAndAdd(scanq, sizeof(RF_Sstf_t), (RF_Sstf_t *), cl_list);
271 	scanq->dir = DIR_RIGHT;
272 	scanq->allow_reverse = 1;
273 	return ((void *) scanq);
274 }
275 
276 void   *
277 rf_CscanCreate(sect_per_disk, cl_list, listp)
278 	RF_SectorCount_t sect_per_disk;
279 	RF_AllocListElem_t *cl_list;
280 	RF_ShutdownList_t **listp;
281 {
282 	RF_Sstf_t *cscanq;
283 
284 	RF_MallocAndAdd(cscanq, sizeof(RF_Sstf_t), (RF_Sstf_t *), cl_list);
285 	cscanq->dir = DIR_RIGHT;
286 	return ((void *) cscanq);
287 }
288 
289 void
290 rf_SstfEnqueue(qptr, req, priority)
291 	void   *qptr;
292 	RF_DiskQueueData_t *req;
293 	int     priority;
294 {
295 	RF_Sstf_t *sstfq;
296 
297 	sstfq = (RF_Sstf_t *) qptr;
298 
299 	if (priority == RF_IO_LOW_PRIORITY) {
300 #if RF_DEBUG_QUEUE
301 		if (rf_sstfDebug || rf_scanDebug || rf_cscanDebug) {
302 			RF_DiskQueue_t *dq;
303 			dq = (RF_DiskQueue_t *) req->queue;
304 			printf("raid%d: ENQ lopri %d queues are %d,%d,%d\n",
305 			       req->raidPtr->raidid,
306 			       dq->col,
307 			       sstfq->left.qlen, sstfq->right.qlen,
308 			       sstfq->lopri.qlen);
309 		}
310 #endif
311 		do_sstf_ord_q(&sstfq->lopri.queue, &sstfq->lopri.qtail, req);
312 		sstfq->lopri.qlen++;
313 	} else {
314 		if (req->sectorOffset < sstfq->last_sector) {
315 			do_sstf_ord_q(&sstfq->left.queue, &sstfq->left.qtail, req);
316 			sstfq->left.qlen++;
317 		} else {
318 			do_sstf_ord_q(&sstfq->right.queue, &sstfq->right.qtail, req);
319 			sstfq->right.qlen++;
320 		}
321 	}
322 }
323 
324 static void
325 do_dequeue(queue, req)
326 	RF_SstfQ_t *queue;
327 	RF_DiskQueueData_t *req;
328 {
329 	RF_DiskQueueData_t *req2;
330 
331 #if RF_DEBUG_QUEUE
332 	if (rf_sstfDebug || rf_scanDebug || rf_cscanDebug) {
333 		printf("raid%d: do_dequeue\n", req->raidPtr->raidid);
334 	}
335 #endif
336 	if (req == queue->queue) {
337 		DO_HEAD_DEQ(req2, queue);
338 		RF_ASSERT(req2 == req);
339 	} else
340 		if (req == queue->qtail) {
341 			DO_TAIL_DEQ(req2, queue);
342 			RF_ASSERT(req2 == req);
343 		} else {
344 			/* dequeue from middle of list */
345 			RF_ASSERT(req->next);
346 			RF_ASSERT(req->prev);
347 			queue->qlen--;
348 			req->next->prev = req->prev;
349 			req->prev->next = req->next;
350 			req->next = req->prev = NULL;
351 		}
352 }
353 
354 RF_DiskQueueData_t *
355 rf_SstfDequeue(qptr)
356 	void   *qptr;
357 {
358 	RF_DiskQueueData_t *req = NULL;
359 	RF_Sstf_t *sstfq;
360 
361 	sstfq = (RF_Sstf_t *) qptr;
362 
363 #if RF_DEBUG_QUEUE
364 	if (rf_sstfDebug) {
365 		RF_DiskQueue_t *dq;
366 		dq = (RF_DiskQueue_t *) req->queue;
367 		RF_ASSERT(QSUM(sstfq) == dq->queueLength);
368 		printf("raid%d: sstf: Dequeue %d queues are %d,%d,%d\n",
369 		       req->raidPtr->raidid, dq->col,
370 		       sstfq->left.qlen, sstfq->right.qlen, sstfq->lopri.qlen);
371 	}
372 #endif
373 	if (sstfq->left.queue == NULL) {
374 		RF_ASSERT(sstfq->left.qlen == 0);
375 		if (sstfq->right.queue == NULL) {
376 			RF_ASSERT(sstfq->right.qlen == 0);
377 			if (sstfq->lopri.queue == NULL) {
378 				RF_ASSERT(sstfq->lopri.qlen == 0);
379 				return (NULL);
380 			}
381 #if RF_DEBUG_QUEUE
382 			if (rf_sstfDebug) {
383 				printf("raid%d: sstf: check for close lopri",
384 				       req->raidPtr->raidid);
385 			}
386 #endif
387 			req = closest_to_arm(&sstfq->lopri, sstfq->last_sector,
388 			    &sstfq->dir, sstfq->allow_reverse);
389 #if RF_DEBUG_QUEUE
390 			if (rf_sstfDebug) {
391 				printf("raid%d: sstf: closest_to_arm said %lx",
392 				       req->raidPtr->raidid, (long) req);
393 			}
394 #endif
395 			if (req == NULL)
396 				return (NULL);
397 			do_dequeue(&sstfq->lopri, req);
398 		} else {
399 			DO_BEST_DEQ(sstfq->last_sector, req, &sstfq->right);
400 		}
401 	} else {
402 		if (sstfq->right.queue == NULL) {
403 			RF_ASSERT(sstfq->right.qlen == 0);
404 			DO_BEST_DEQ(sstfq->last_sector, req, &sstfq->left);
405 		} else {
406 			if (SNUM_DIFF(sstfq->last_sector, sstfq->right.queue->sectorOffset)
407 			    < SNUM_DIFF(sstfq->last_sector, sstfq->left.qtail->sectorOffset)) {
408 				DO_HEAD_DEQ(req, &sstfq->right);
409 			} else {
410 				DO_TAIL_DEQ(req, &sstfq->left);
411 			}
412 		}
413 	}
414 	RF_ASSERT(req);
415 	sstfq->last_sector = req->sectorOffset;
416 	return (req);
417 }
418 
419 RF_DiskQueueData_t *
420 rf_ScanDequeue(qptr)
421 	void   *qptr;
422 {
423 	RF_DiskQueueData_t *req = NULL;
424 	RF_Sstf_t *scanq;
425 
426 	scanq = (RF_Sstf_t *) qptr;
427 
428 #if RF_DEBUG_QUEUE
429 	if (rf_scanDebug) {
430 		RF_DiskQueue_t *dq;
431 		dq = (RF_DiskQueue_t *) req->queue;
432 		RF_ASSERT(QSUM(scanq) == dq->queueLength);
433 		printf("raid%d: scan: Dequeue %d queues are %d,%d,%d\n",
434 		       req->raidPtr->raidid, dq->col,
435 		       scanq->left.qlen, scanq->right.qlen, scanq->lopri.qlen);
436 	}
437 #endif
438 	if (scanq->left.queue == NULL) {
439 		RF_ASSERT(scanq->left.qlen == 0);
440 		if (scanq->right.queue == NULL) {
441 			RF_ASSERT(scanq->right.qlen == 0);
442 			if (scanq->lopri.queue == NULL) {
443 				RF_ASSERT(scanq->lopri.qlen == 0);
444 				return (NULL);
445 			}
446 			req = closest_to_arm(&scanq->lopri, scanq->last_sector,
447 			    &scanq->dir, scanq->allow_reverse);
448 			if (req == NULL)
449 				return (NULL);
450 			do_dequeue(&scanq->lopri, req);
451 		} else {
452 			scanq->dir = DIR_RIGHT;
453 			DO_HEAD_DEQ(req, &scanq->right);
454 		}
455 	} else
456 		if (scanq->right.queue == NULL) {
457 			RF_ASSERT(scanq->right.qlen == 0);
458 			RF_ASSERT(scanq->left.queue);
459 			scanq->dir = DIR_LEFT;
460 			DO_TAIL_DEQ(req, &scanq->left);
461 		} else {
462 			RF_ASSERT(scanq->right.queue);
463 			RF_ASSERT(scanq->left.queue);
464 			if (scanq->dir == DIR_RIGHT) {
465 				DO_HEAD_DEQ(req, &scanq->right);
466 			} else {
467 				DO_TAIL_DEQ(req, &scanq->left);
468 			}
469 		}
470 	RF_ASSERT(req);
471 	scanq->last_sector = req->sectorOffset;
472 	return (req);
473 }
474 
475 RF_DiskQueueData_t *
476 rf_CscanDequeue(qptr)
477 	void   *qptr;
478 {
479 	RF_DiskQueueData_t *req = NULL;
480 	RF_Sstf_t *cscanq;
481 
482 	cscanq = (RF_Sstf_t *) qptr;
483 
484 	RF_ASSERT(cscanq->dir == DIR_RIGHT);
485 #if RF_DEBUG_QUEUE
486 	if (rf_cscanDebug) {
487 		RF_DiskQueue_t *dq;
488 		dq = (RF_DiskQueue_t *) req->queue;
489 		RF_ASSERT(QSUM(cscanq) == dq->queueLength);
490 		printf("raid%d: scan: Dequeue %d queues are %d,%d,%d\n",
491 		       req->raidPtr->raidid, dq->col,
492 		       cscanq->left.qlen, cscanq->right.qlen,
493 		       cscanq->lopri.qlen);
494 	}
495 #endif
496 	if (cscanq->right.queue) {
497 		DO_HEAD_DEQ(req, &cscanq->right);
498 	} else {
499 		RF_ASSERT(cscanq->right.qlen == 0);
500 		if (cscanq->left.queue == NULL) {
501 			RF_ASSERT(cscanq->left.qlen == 0);
502 			if (cscanq->lopri.queue == NULL) {
503 				RF_ASSERT(cscanq->lopri.qlen == 0);
504 				return (NULL);
505 			}
506 			req = closest_to_arm(&cscanq->lopri, cscanq->last_sector,
507 			    &cscanq->dir, cscanq->allow_reverse);
508 			if (req == NULL)
509 				return (NULL);
510 			do_dequeue(&cscanq->lopri, req);
511 		} else {
512 			/*
513 			 * There's I/Os to the left of the arm. Swing
514 			 * on back (swap queues).
515 			 */
516 			cscanq->right = cscanq->left;
517 			cscanq->left.qlen = 0;
518 			cscanq->left.queue = cscanq->left.qtail = NULL;
519 			DO_HEAD_DEQ(req, &cscanq->right);
520 		}
521 	}
522 	RF_ASSERT(req);
523 	cscanq->last_sector = req->sectorOffset;
524 	return (req);
525 }
526 
527 RF_DiskQueueData_t *
528 rf_SstfPeek(qptr)
529 	void   *qptr;
530 {
531 	RF_DiskQueueData_t *req;
532 	RF_Sstf_t *sstfq;
533 
534 	sstfq = (RF_Sstf_t *) qptr;
535 
536 	if ((sstfq->left.queue == NULL) && (sstfq->right.queue == NULL)) {
537 		req = closest_to_arm(&sstfq->lopri, sstfq->last_sector, &sstfq->dir,
538 		    sstfq->allow_reverse);
539 	} else {
540 		if (sstfq->left.queue == NULL)
541 			req = sstfq->right.queue;
542 		else {
543 			if (sstfq->right.queue == NULL)
544 				req = sstfq->left.queue;
545 			else {
546 				if (SNUM_DIFF(sstfq->last_sector, sstfq->right.queue->sectorOffset)
547 				    < SNUM_DIFF(sstfq->last_sector, sstfq->left.qtail->sectorOffset)) {
548 					req = sstfq->right.queue;
549 				} else {
550 					req = sstfq->left.qtail;
551 				}
552 			}
553 		}
554 	}
555 	if (req == NULL) {
556 		RF_ASSERT(QSUM(sstfq) == 0);
557 	}
558 	return (req);
559 }
560 
561 RF_DiskQueueData_t *
562 rf_ScanPeek(qptr)
563 	void   *qptr;
564 {
565 	RF_DiskQueueData_t *req;
566 	RF_Sstf_t *scanq;
567 	int     dir;
568 
569 	scanq = (RF_Sstf_t *) qptr;
570 	dir = scanq->dir;
571 
572 	if (scanq->left.queue == NULL) {
573 		RF_ASSERT(scanq->left.qlen == 0);
574 		if (scanq->right.queue == NULL) {
575 			RF_ASSERT(scanq->right.qlen == 0);
576 			if (scanq->lopri.queue == NULL) {
577 				RF_ASSERT(scanq->lopri.qlen == 0);
578 				return (NULL);
579 			}
580 			req = closest_to_arm(&scanq->lopri, scanq->last_sector,
581 			    &dir, scanq->allow_reverse);
582 		} else {
583 			req = scanq->right.queue;
584 		}
585 	} else
586 		if (scanq->right.queue == NULL) {
587 			RF_ASSERT(scanq->right.qlen == 0);
588 			RF_ASSERT(scanq->left.queue);
589 			req = scanq->left.qtail;
590 		} else {
591 			RF_ASSERT(scanq->right.queue);
592 			RF_ASSERT(scanq->left.queue);
593 			if (scanq->dir == DIR_RIGHT) {
594 				req = scanq->right.queue;
595 			} else {
596 				req = scanq->left.qtail;
597 			}
598 		}
599 	if (req == NULL) {
600 		RF_ASSERT(QSUM(scanq) == 0);
601 	}
602 	return (req);
603 }
604 
605 RF_DiskQueueData_t *
606 rf_CscanPeek(qptr)
607 	void   *qptr;
608 {
609 	RF_DiskQueueData_t *req;
610 	RF_Sstf_t *cscanq;
611 
612 	cscanq = (RF_Sstf_t *) qptr;
613 
614 	RF_ASSERT(cscanq->dir == DIR_RIGHT);
615 	if (cscanq->right.queue) {
616 		req = cscanq->right.queue;
617 	} else {
618 		RF_ASSERT(cscanq->right.qlen == 0);
619 		if (cscanq->left.queue == NULL) {
620 			RF_ASSERT(cscanq->left.qlen == 0);
621 			if (cscanq->lopri.queue == NULL) {
622 				RF_ASSERT(cscanq->lopri.qlen == 0);
623 				return (NULL);
624 			}
625 			req = closest_to_arm(&cscanq->lopri, cscanq->last_sector,
626 			    &cscanq->dir, cscanq->allow_reverse);
627 		} else {
628 			/*
629 			 * There's I/Os to the left of the arm. We'll end
630 			 * up swinging on back.
631 			 */
632 			req = cscanq->left.queue;
633 		}
634 	}
635 	if (req == NULL) {
636 		RF_ASSERT(QSUM(cscanq) == 0);
637 	}
638 	return (req);
639 }
640 
641 int
642 rf_SstfPromote(qptr, parityStripeID, which_ru)
643 	void   *qptr;
644 	RF_StripeNum_t parityStripeID;
645 	RF_ReconUnitNum_t which_ru;
646 {
647 	RF_DiskQueueData_t *r, *next;
648 	RF_Sstf_t *sstfq;
649 	int     n;
650 
651 	sstfq = (RF_Sstf_t *) qptr;
652 
653 	n = 0;
654 	for (r = sstfq->lopri.queue; r; r = next) {
655 		next = r->next;
656 #if RF_DEBUG_QUEUE
657 		if (rf_sstfDebug || rf_scanDebug || rf_cscanDebug) {
658 			printf("raid%d: check promote %lx\n",
659 			       r->raidPtr->raidid, (long) r);
660 		}
661 #endif
662 		if ((r->parityStripeID == parityStripeID)
663 		    && (r->which_ru == which_ru)) {
664 			do_dequeue(&sstfq->lopri, r);
665 			rf_SstfEnqueue(qptr, r, RF_IO_NORMAL_PRIORITY);
666 			n++;
667 		}
668 	}
669 #if RF_DEBUG_QUEUE
670 	if (rf_sstfDebug || rf_scanDebug || rf_cscanDebug) {
671 		printf("raid%d: promoted %d matching I/Os queues are %d,%d,%d\n",
672 		       r->raidPtr->raidid, n, sstfq->left.qlen,
673 		       sstfq->right.qlen, sstfq->lopri.qlen);
674 	}
675 #endif
676 	return (n);
677 }
678