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