xref: /netbsd/sys/dev/raidframe/rf_sstf.c (revision bf9ec67e)
1 /*	$NetBSD: rf_sstf.c,v 1.8 2001/11/13 07:11:17 lukem 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.8 2001/11/13 07:11:17 lukem 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_CallocAndAdd(sstfq, 1, 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_CallocAndAdd(scanq, 1, 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_CallocAndAdd(cscanq, 1, 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_sstfDebug || rf_scanDebug || rf_cscanDebug) {
301 			RF_DiskQueue_t *dq;
302 			dq = (RF_DiskQueue_t *) req->queue;
303 			printf("raid%d: ENQ lopri %d,%d queues are %d,%d,%d\n",
304 			       req->raidPtr->raidid,
305 			       dq->row, dq->col,
306 			       sstfq->left.qlen, sstfq->right.qlen,
307 			       sstfq->lopri.qlen);
308 		}
309 		do_sstf_ord_q(&sstfq->lopri.queue, &sstfq->lopri.qtail, req);
310 		sstfq->lopri.qlen++;
311 	} else {
312 		if (req->sectorOffset < sstfq->last_sector) {
313 			do_sstf_ord_q(&sstfq->left.queue, &sstfq->left.qtail, req);
314 			sstfq->left.qlen++;
315 		} else {
316 			do_sstf_ord_q(&sstfq->right.queue, &sstfq->right.qtail, req);
317 			sstfq->right.qlen++;
318 		}
319 	}
320 }
321 
322 static void
323 do_dequeue(queue, req)
324 	RF_SstfQ_t *queue;
325 	RF_DiskQueueData_t *req;
326 {
327 	RF_DiskQueueData_t *req2;
328 
329 	if (rf_sstfDebug || rf_scanDebug || rf_cscanDebug) {
330 		printf("raid%d: do_dequeue\n", req->raidPtr->raidid);
331 	}
332 	if (req == queue->queue) {
333 		DO_HEAD_DEQ(req2, queue);
334 		RF_ASSERT(req2 == req);
335 	} else
336 		if (req == queue->qtail) {
337 			DO_TAIL_DEQ(req2, queue);
338 			RF_ASSERT(req2 == req);
339 		} else {
340 			/* dequeue from middle of list */
341 			RF_ASSERT(req->next);
342 			RF_ASSERT(req->prev);
343 			queue->qlen--;
344 			req->next->prev = req->prev;
345 			req->prev->next = req->next;
346 			req->next = req->prev = NULL;
347 		}
348 }
349 
350 RF_DiskQueueData_t *
351 rf_SstfDequeue(qptr)
352 	void   *qptr;
353 {
354 	RF_DiskQueueData_t *req = NULL;
355 	RF_Sstf_t *sstfq;
356 
357 	sstfq = (RF_Sstf_t *) qptr;
358 
359 	if (rf_sstfDebug) {
360 		RF_DiskQueue_t *dq;
361 		dq = (RF_DiskQueue_t *) req->queue;
362 		RF_ASSERT(QSUM(sstfq) == dq->queueLength);
363 		printf("raid%d: sstf: Dequeue %d,%d queues are %d,%d,%d\n",
364 		       req->raidPtr->raidid, dq->row, dq->col,
365 		       sstfq->left.qlen, sstfq->right.qlen, sstfq->lopri.qlen);
366 	}
367 	if (sstfq->left.queue == NULL) {
368 		RF_ASSERT(sstfq->left.qlen == 0);
369 		if (sstfq->right.queue == NULL) {
370 			RF_ASSERT(sstfq->right.qlen == 0);
371 			if (sstfq->lopri.queue == NULL) {
372 				RF_ASSERT(sstfq->lopri.qlen == 0);
373 				return (NULL);
374 			}
375 			if (rf_sstfDebug) {
376 				printf("raid%d: sstf: check for close lopri",
377 				       req->raidPtr->raidid);
378 			}
379 			req = closest_to_arm(&sstfq->lopri, sstfq->last_sector,
380 			    &sstfq->dir, sstfq->allow_reverse);
381 			if (rf_sstfDebug) {
382 				printf("raid%d: sstf: closest_to_arm said %lx",
383 				       req->raidPtr->raidid, (long) req);
384 			}
385 			if (req == NULL)
386 				return (NULL);
387 			do_dequeue(&sstfq->lopri, req);
388 		} else {
389 			DO_BEST_DEQ(sstfq->last_sector, req, &sstfq->right);
390 		}
391 	} else {
392 		if (sstfq->right.queue == NULL) {
393 			RF_ASSERT(sstfq->right.qlen == 0);
394 			DO_BEST_DEQ(sstfq->last_sector, req, &sstfq->left);
395 		} else {
396 			if (SNUM_DIFF(sstfq->last_sector, sstfq->right.queue->sectorOffset)
397 			    < SNUM_DIFF(sstfq->last_sector, sstfq->left.qtail->sectorOffset)) {
398 				DO_HEAD_DEQ(req, &sstfq->right);
399 			} else {
400 				DO_TAIL_DEQ(req, &sstfq->left);
401 			}
402 		}
403 	}
404 	RF_ASSERT(req);
405 	sstfq->last_sector = req->sectorOffset;
406 	return (req);
407 }
408 
409 RF_DiskQueueData_t *
410 rf_ScanDequeue(qptr)
411 	void   *qptr;
412 {
413 	RF_DiskQueueData_t *req = NULL;
414 	RF_Sstf_t *scanq;
415 
416 	scanq = (RF_Sstf_t *) qptr;
417 
418 	if (rf_scanDebug) {
419 		RF_DiskQueue_t *dq;
420 		dq = (RF_DiskQueue_t *) req->queue;
421 		RF_ASSERT(QSUM(scanq) == dq->queueLength);
422 		printf("raid%d: scan: Dequeue %d,%d queues are %d,%d,%d\n",
423 		       req->raidPtr->raidid, dq->row, dq->col,
424 		       scanq->left.qlen, scanq->right.qlen, scanq->lopri.qlen);
425 	}
426 	if (scanq->left.queue == NULL) {
427 		RF_ASSERT(scanq->left.qlen == 0);
428 		if (scanq->right.queue == NULL) {
429 			RF_ASSERT(scanq->right.qlen == 0);
430 			if (scanq->lopri.queue == NULL) {
431 				RF_ASSERT(scanq->lopri.qlen == 0);
432 				return (NULL);
433 			}
434 			req = closest_to_arm(&scanq->lopri, scanq->last_sector,
435 			    &scanq->dir, scanq->allow_reverse);
436 			if (req == NULL)
437 				return (NULL);
438 			do_dequeue(&scanq->lopri, req);
439 		} else {
440 			scanq->dir = DIR_RIGHT;
441 			DO_HEAD_DEQ(req, &scanq->right);
442 		}
443 	} else
444 		if (scanq->right.queue == NULL) {
445 			RF_ASSERT(scanq->right.qlen == 0);
446 			RF_ASSERT(scanq->left.queue);
447 			scanq->dir = DIR_LEFT;
448 			DO_TAIL_DEQ(req, &scanq->left);
449 		} else {
450 			RF_ASSERT(scanq->right.queue);
451 			RF_ASSERT(scanq->left.queue);
452 			if (scanq->dir == DIR_RIGHT) {
453 				DO_HEAD_DEQ(req, &scanq->right);
454 			} else {
455 				DO_TAIL_DEQ(req, &scanq->left);
456 			}
457 		}
458 	RF_ASSERT(req);
459 	scanq->last_sector = req->sectorOffset;
460 	return (req);
461 }
462 
463 RF_DiskQueueData_t *
464 rf_CscanDequeue(qptr)
465 	void   *qptr;
466 {
467 	RF_DiskQueueData_t *req = NULL;
468 	RF_Sstf_t *cscanq;
469 
470 	cscanq = (RF_Sstf_t *) qptr;
471 
472 	RF_ASSERT(cscanq->dir == DIR_RIGHT);
473 	if (rf_cscanDebug) {
474 		RF_DiskQueue_t *dq;
475 		dq = (RF_DiskQueue_t *) req->queue;
476 		RF_ASSERT(QSUM(cscanq) == dq->queueLength);
477 		printf("raid%d: scan: Dequeue %d,%d queues are %d,%d,%d\n",
478 		       req->raidPtr->raidid, dq->row, dq->col,
479 		       cscanq->left.qlen, cscanq->right.qlen,
480 		       cscanq->lopri.qlen);
481 	}
482 	if (cscanq->right.queue) {
483 		DO_HEAD_DEQ(req, &cscanq->right);
484 	} else {
485 		RF_ASSERT(cscanq->right.qlen == 0);
486 		if (cscanq->left.queue == NULL) {
487 			RF_ASSERT(cscanq->left.qlen == 0);
488 			if (cscanq->lopri.queue == NULL) {
489 				RF_ASSERT(cscanq->lopri.qlen == 0);
490 				return (NULL);
491 			}
492 			req = closest_to_arm(&cscanq->lopri, cscanq->last_sector,
493 			    &cscanq->dir, cscanq->allow_reverse);
494 			if (req == NULL)
495 				return (NULL);
496 			do_dequeue(&cscanq->lopri, req);
497 		} else {
498 			/*
499 			 * There's I/Os to the left of the arm. Swing
500 			 * on back (swap queues).
501 			 */
502 			cscanq->right = cscanq->left;
503 			cscanq->left.qlen = 0;
504 			cscanq->left.queue = cscanq->left.qtail = NULL;
505 			DO_HEAD_DEQ(req, &cscanq->right);
506 		}
507 	}
508 	RF_ASSERT(req);
509 	cscanq->last_sector = req->sectorOffset;
510 	return (req);
511 }
512 
513 RF_DiskQueueData_t *
514 rf_SstfPeek(qptr)
515 	void   *qptr;
516 {
517 	RF_DiskQueueData_t *req;
518 	RF_Sstf_t *sstfq;
519 
520 	sstfq = (RF_Sstf_t *) qptr;
521 
522 	if ((sstfq->left.queue == NULL) && (sstfq->right.queue == NULL)) {
523 		req = closest_to_arm(&sstfq->lopri, sstfq->last_sector, &sstfq->dir,
524 		    sstfq->allow_reverse);
525 	} else {
526 		if (sstfq->left.queue == NULL)
527 			req = sstfq->right.queue;
528 		else {
529 			if (sstfq->right.queue == NULL)
530 				req = sstfq->left.queue;
531 			else {
532 				if (SNUM_DIFF(sstfq->last_sector, sstfq->right.queue->sectorOffset)
533 				    < SNUM_DIFF(sstfq->last_sector, sstfq->left.qtail->sectorOffset)) {
534 					req = sstfq->right.queue;
535 				} else {
536 					req = sstfq->left.qtail;
537 				}
538 			}
539 		}
540 	}
541 	if (req == NULL) {
542 		RF_ASSERT(QSUM(sstfq) == 0);
543 	}
544 	return (req);
545 }
546 
547 RF_DiskQueueData_t *
548 rf_ScanPeek(qptr)
549 	void   *qptr;
550 {
551 	RF_DiskQueueData_t *req;
552 	RF_Sstf_t *scanq;
553 	int     dir;
554 
555 	scanq = (RF_Sstf_t *) qptr;
556 	dir = scanq->dir;
557 
558 	if (scanq->left.queue == NULL) {
559 		RF_ASSERT(scanq->left.qlen == 0);
560 		if (scanq->right.queue == NULL) {
561 			RF_ASSERT(scanq->right.qlen == 0);
562 			if (scanq->lopri.queue == NULL) {
563 				RF_ASSERT(scanq->lopri.qlen == 0);
564 				return (NULL);
565 			}
566 			req = closest_to_arm(&scanq->lopri, scanq->last_sector,
567 			    &dir, scanq->allow_reverse);
568 		} else {
569 			req = scanq->right.queue;
570 		}
571 	} else
572 		if (scanq->right.queue == NULL) {
573 			RF_ASSERT(scanq->right.qlen == 0);
574 			RF_ASSERT(scanq->left.queue);
575 			req = scanq->left.qtail;
576 		} else {
577 			RF_ASSERT(scanq->right.queue);
578 			RF_ASSERT(scanq->left.queue);
579 			if (scanq->dir == DIR_RIGHT) {
580 				req = scanq->right.queue;
581 			} else {
582 				req = scanq->left.qtail;
583 			}
584 		}
585 	if (req == NULL) {
586 		RF_ASSERT(QSUM(scanq) == 0);
587 	}
588 	return (req);
589 }
590 
591 RF_DiskQueueData_t *
592 rf_CscanPeek(qptr)
593 	void   *qptr;
594 {
595 	RF_DiskQueueData_t *req;
596 	RF_Sstf_t *cscanq;
597 
598 	cscanq = (RF_Sstf_t *) qptr;
599 
600 	RF_ASSERT(cscanq->dir == DIR_RIGHT);
601 	if (cscanq->right.queue) {
602 		req = cscanq->right.queue;
603 	} else {
604 		RF_ASSERT(cscanq->right.qlen == 0);
605 		if (cscanq->left.queue == NULL) {
606 			RF_ASSERT(cscanq->left.qlen == 0);
607 			if (cscanq->lopri.queue == NULL) {
608 				RF_ASSERT(cscanq->lopri.qlen == 0);
609 				return (NULL);
610 			}
611 			req = closest_to_arm(&cscanq->lopri, cscanq->last_sector,
612 			    &cscanq->dir, cscanq->allow_reverse);
613 		} else {
614 			/*
615 			 * There's I/Os to the left of the arm. We'll end
616 			 * up swinging on back.
617 			 */
618 			req = cscanq->left.queue;
619 		}
620 	}
621 	if (req == NULL) {
622 		RF_ASSERT(QSUM(cscanq) == 0);
623 	}
624 	return (req);
625 }
626 
627 int
628 rf_SstfPromote(qptr, parityStripeID, which_ru)
629 	void   *qptr;
630 	RF_StripeNum_t parityStripeID;
631 	RF_ReconUnitNum_t which_ru;
632 {
633 	RF_DiskQueueData_t *r, *next;
634 	RF_Sstf_t *sstfq;
635 	int     n;
636 
637 	sstfq = (RF_Sstf_t *) qptr;
638 
639 	n = 0;
640 	for (r = sstfq->lopri.queue; r; r = next) {
641 		next = r->next;
642 		if (rf_sstfDebug || rf_scanDebug || rf_cscanDebug) {
643 			printf("raid%d: check promote %lx\n",
644 			       r->raidPtr->raidid, (long) r);
645 		}
646 		if ((r->parityStripeID == parityStripeID)
647 		    && (r->which_ru == which_ru)) {
648 			do_dequeue(&sstfq->lopri, r);
649 			rf_SstfEnqueue(qptr, r, RF_IO_NORMAL_PRIORITY);
650 			n++;
651 		}
652 	}
653 	if (rf_sstfDebug || rf_scanDebug || rf_cscanDebug) {
654 		printf("raid%d: promoted %d matching I/Os queues are %d,%d,%d\n",
655 		       r->raidPtr->raidid, n, sstfq->left.qlen,
656 		       sstfq->right.qlen, sstfq->lopri.qlen);
657 	}
658 	return (n);
659 }
660