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