Home | History | Annotate | Line # | Download | only in raidframe
rf_sstf.c revision 1.9
      1 /*	$NetBSD: rf_sstf.c,v 1.9 2002/09/17 03:43:34 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 (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 /*******************************************************************************
     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.9 2002/09/17 03:43:34 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_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_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,%d queues are %d,%d,%d\n",
    305 			       req->raidPtr->raidid,
    306 			       dq->row, 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,%d queues are %d,%d,%d\n",
    369 		       req->raidPtr->raidid, dq->row, 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,%d queues are %d,%d,%d\n",
    434 		       req->raidPtr->raidid, dq->row, 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,%d queues are %d,%d,%d\n",
    491 		       req->raidPtr->raidid, dq->row, 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