Home | History | Annotate | Download | only in drvobj
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*
     23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*
     28  *	Device Strategy
     29  */
     30 #include <sys/dktp/cm.h>
     31 #include <sys/kstat.h>
     32 
     33 #include <sys/dktp/quetypes.h>
     34 #include <sys/dktp/queue.h>
     35 #include <sys/dktp/tgcom.h>
     36 #include <sys/dktp/fctypes.h>
     37 #include <sys/dktp/flowctrl.h>
     38 #include <sys/param.h>
     39 #include <vm/page.h>
     40 #include <sys/modctl.h>
     41 
     42 /*
     43  *	Object Management
     44  */
     45 
     46 static struct buf *qmerge_nextbp(struct que_data *qfp, struct buf *bp_merge,
     47     int *can_merge);
     48 
     49 static struct modlmisc modlmisc = {
     50 	&mod_miscops,	/* Type of module */
     51 	"Device Strategy Objects"
     52 };
     53 
     54 static struct modlinkage modlinkage = {
     55 	MODREV_1,
     56 	&modlmisc,
     57 	NULL
     58 };
     59 
     60 int
     61 _init(void)
     62 {
     63 	return (mod_install(&modlinkage));
     64 }
     65 
     66 int
     67 _fini(void)
     68 {
     69 	return (mod_remove(&modlinkage));
     70 }
     71 
     72 int
     73 _info(struct modinfo *modinfop)
     74 {
     75 	return (mod_info(&modlinkage, modinfop));
     76 }
     77 
     78 
     79 /*
     80  *	Common Flow Control functions
     81  */
     82 
     83 /*
     84  * Local static data
     85  */
     86 #ifdef	FLC_DEBUG
     87 #define	DENT	0x0001
     88 #define	DERR	0x0002
     89 #define	DIO	0x0004
     90 static	int	flc_debug = DENT|DERR|DIO;
     91 
     92 #include <sys/thread.h>
     93 static 	int	flc_malloc_intr = 0;
     94 #endif	/* FLC_DEBUG */
     95 
     96 static	int	flc_kstat = 1;
     97 
     98 static struct flc_obj *fc_create(struct flc_objops *fcopsp);
     99 static int fc_init(opaque_t queuep, opaque_t tgcom_objp, opaque_t que_objp,
    100     void *lkarg);
    101 static int fc_free(struct flc_obj *flcobjp);
    102 static int fc_start_kstat(opaque_t queuep, char *devtype, int instance);
    103 static int fc_stop_kstat(opaque_t queuep);
    104 
    105 static struct flc_obj *
    106 fc_create(struct flc_objops *fcopsp)
    107 {
    108 	struct	flc_obj *flcobjp;
    109 	struct	fc_data *fcdp;
    110 
    111 	flcobjp = kmem_zalloc((sizeof (*flcobjp) + sizeof (*fcdp)), KM_NOSLEEP);
    112 	if (!flcobjp)
    113 		return (NULL);
    114 
    115 	fcdp = (struct fc_data *)(flcobjp+1);
    116 	flcobjp->flc_data = (opaque_t)fcdp;
    117 	flcobjp->flc_ops  = fcopsp;
    118 
    119 	return ((opaque_t)flcobjp);
    120 }
    121 
    122 static int dmult_maxcnt = DMULT_MAXCNT;
    123 
    124 static int
    125 fc_init(opaque_t queuep, opaque_t tgcom_objp, opaque_t que_objp, void *lkarg)
    126 {
    127 	struct fc_data *fcdp = (struct fc_data *)queuep;
    128 
    129 	mutex_init(&fcdp->ds_mutex, NULL, MUTEX_DRIVER, lkarg);
    130 
    131 	fcdp->ds_queobjp   = que_objp;
    132 	fcdp->ds_tgcomobjp = tgcom_objp;
    133 	fcdp->ds_waitcnt   = dmult_maxcnt;
    134 
    135 	QUE_INIT(que_objp, lkarg);
    136 	TGCOM_INIT(tgcom_objp);
    137 	return (DDI_SUCCESS);
    138 }
    139 
    140 static int
    141 fc_free(struct flc_obj *flcobjp)
    142 {
    143 	struct fc_data *fcdp;
    144 
    145 	fcdp = (struct fc_data *)flcobjp->flc_data;
    146 	if (fcdp->ds_queobjp)
    147 		QUE_FREE(fcdp->ds_queobjp);
    148 	if (fcdp->ds_tgcomobjp) {
    149 		TGCOM_FREE(fcdp->ds_tgcomobjp);
    150 		mutex_destroy(&fcdp->ds_mutex);
    151 	}
    152 	kmem_free(flcobjp, (sizeof (*flcobjp) + sizeof (*fcdp)));
    153 	return (0);
    154 }
    155 
    156 /*ARGSUSED*/
    157 static int
    158 fc_start_kstat(opaque_t queuep, char *devtype, int instance)
    159 {
    160 	struct fc_data *fcdp = (struct fc_data *)queuep;
    161 	if (!flc_kstat)
    162 		return (0);
    163 
    164 	if (!fcdp->ds_kstat) {
    165 		if (fcdp->ds_kstat = kstat_create("cmdk", instance, NULL,
    166 		    "disk", KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT)) {
    167 			kstat_install(fcdp->ds_kstat);
    168 		}
    169 	}
    170 	return (0);
    171 }
    172 
    173 static int
    174 fc_stop_kstat(opaque_t queuep)
    175 {
    176 	struct fc_data *fcdp = (struct fc_data *)queuep;
    177 
    178 	if (fcdp->ds_kstat) {
    179 		kstat_delete(fcdp->ds_kstat);
    180 		fcdp->ds_kstat = NULL;
    181 	}
    182 	return (0);
    183 }
    184 
    185 
    186 /*
    187  *	Single Command per Device
    188  */
    189 /*
    190  * Local Function Prototypes
    191  */
    192 static int dsngl_restart();
    193 
    194 static int dsngl_enque(opaque_t, struct buf *);
    195 static int dsngl_deque(opaque_t, struct buf *);
    196 
    197 struct 	flc_objops dsngl_ops = {
    198 	fc_init,
    199 	fc_free,
    200 	dsngl_enque,
    201 	dsngl_deque,
    202 	fc_start_kstat,
    203 	fc_stop_kstat,
    204 	0, 0
    205 };
    206 
    207 struct flc_obj *
    208 dsngl_create()
    209 {
    210 	return (fc_create((struct flc_objops *)&dsngl_ops));
    211 }
    212 
    213 static int
    214 dsngl_enque(opaque_t queuep, struct buf *in_bp)
    215 {
    216 	struct fc_data *dsnglp = (struct fc_data *)queuep;
    217 	opaque_t tgcom_objp;
    218 	opaque_t que_objp;
    219 
    220 	que_objp   = dsnglp->ds_queobjp;
    221 	tgcom_objp = dsnglp->ds_tgcomobjp;
    222 
    223 	if (!in_bp)
    224 		return (0);
    225 	mutex_enter(&dsnglp->ds_mutex);
    226 	if (dsnglp->ds_bp || dsnglp->ds_outcnt) {
    227 		QUE_ADD(que_objp, in_bp);
    228 		if (dsnglp->ds_kstat) {
    229 			kstat_waitq_enter(KSTAT_IO_PTR(dsnglp->ds_kstat));
    230 		}
    231 		mutex_exit(&dsnglp->ds_mutex);
    232 		return (0);
    233 	}
    234 	if (dsnglp->ds_kstat) {
    235 		kstat_waitq_enter(KSTAT_IO_PTR(dsnglp->ds_kstat));
    236 	}
    237 	if (TGCOM_PKT(tgcom_objp, in_bp, dsngl_restart,
    238 		(caddr_t)dsnglp) != DDI_SUCCESS) {
    239 
    240 		dsnglp->ds_bp = in_bp;
    241 		mutex_exit(&dsnglp->ds_mutex);
    242 		return (0);
    243 	}
    244 	dsnglp->ds_outcnt++;
    245 	if (dsnglp->ds_kstat)
    246 		kstat_waitq_to_runq(KSTAT_IO_PTR(dsnglp->ds_kstat));
    247 	mutex_exit(&dsnglp->ds_mutex);
    248 	TGCOM_TRANSPORT(tgcom_objp, in_bp);
    249 	return (0);
    250 }
    251 
    252 static int
    253 dsngl_deque(opaque_t queuep, struct buf *in_bp)
    254 {
    255 	struct fc_data *dsnglp = (struct fc_data *)queuep;
    256 	opaque_t tgcom_objp;
    257 	opaque_t que_objp;
    258 	struct	 buf *bp;
    259 
    260 	que_objp   = dsnglp->ds_queobjp;
    261 	tgcom_objp = dsnglp->ds_tgcomobjp;
    262 
    263 	mutex_enter(&dsnglp->ds_mutex);
    264 	if (in_bp) {
    265 		dsnglp->ds_outcnt--;
    266 		if (dsnglp->ds_kstat) {
    267 			if (in_bp->b_flags & B_READ) {
    268 				KSTAT_IO_PTR(dsnglp->ds_kstat)->reads++;
    269 				KSTAT_IO_PTR(dsnglp->ds_kstat)->nread +=
    270 				    (in_bp->b_bcount - in_bp->b_resid);
    271 			} else {
    272 				KSTAT_IO_PTR(dsnglp->ds_kstat)->writes++;
    273 				KSTAT_IO_PTR(dsnglp->ds_kstat)->nwritten +=
    274 				    (in_bp->b_bcount - in_bp->b_resid);
    275 			}
    276 			kstat_runq_exit(KSTAT_IO_PTR(dsnglp->ds_kstat));
    277 		}
    278 	}
    279 	for (;;) {
    280 		if (!dsnglp->ds_bp)
    281 			dsnglp->ds_bp = QUE_DEL(que_objp);
    282 		if (!dsnglp->ds_bp ||
    283 		    (TGCOM_PKT(tgcom_objp, dsnglp->ds_bp, dsngl_restart,
    284 		    (caddr_t)dsnglp) != DDI_SUCCESS) ||
    285 		    dsnglp->ds_outcnt) {
    286 			mutex_exit(&dsnglp->ds_mutex);
    287 			return (0);
    288 		}
    289 		dsnglp->ds_outcnt++;
    290 		bp = dsnglp->ds_bp;
    291 		dsnglp->ds_bp = QUE_DEL(que_objp);
    292 		if (dsnglp->ds_kstat)
    293 			kstat_waitq_to_runq(KSTAT_IO_PTR(dsnglp->ds_kstat));
    294 		mutex_exit(&dsnglp->ds_mutex);
    295 
    296 		TGCOM_TRANSPORT(tgcom_objp, bp);
    297 
    298 		if (!mutex_tryenter(&dsnglp->ds_mutex))
    299 			return (0);
    300 	}
    301 }
    302 
    303 static int
    304 dsngl_restart(struct fc_data *dsnglp)
    305 {
    306 	(void) dsngl_deque(dsnglp, NULL);
    307 	return (-1);
    308 }
    309 
    310 
    311 /*
    312  *	Multiple Commands per Device
    313  */
    314 /*
    315  * Local Function Prototypes
    316  */
    317 static int dmult_restart();
    318 
    319 static int dmult_enque(opaque_t, struct buf *);
    320 static int dmult_deque(opaque_t, struct buf *);
    321 
    322 struct 	flc_objops dmult_ops = {
    323 	fc_init,
    324 	fc_free,
    325 	dmult_enque,
    326 	dmult_deque,
    327 	fc_start_kstat,
    328 	fc_stop_kstat,
    329 	0, 0
    330 };
    331 
    332 struct flc_obj *
    333 dmult_create()
    334 {
    335 	return (fc_create((struct flc_objops *)&dmult_ops));
    336 
    337 }
    338 
    339 
    340 /*
    341  * Some of the object management functions QUE_ADD() and QUE_DEL()
    342  * do not accquire lock.
    343  * They depend on dmult_enque(), dmult_deque() to do all locking.
    344  * If this changes we have to grab locks in qmerge_add() and qmerge_del().
    345  */
    346 static int
    347 dmult_enque(opaque_t queuep, struct buf *in_bp)
    348 {
    349 	struct fc_data *dmultp = (struct fc_data *)queuep;
    350 	opaque_t tgcom_objp;
    351 	opaque_t que_objp;
    352 
    353 	que_objp   = dmultp->ds_queobjp;
    354 	tgcom_objp = dmultp->ds_tgcomobjp;
    355 
    356 	if (!in_bp)
    357 		return (0);
    358 	mutex_enter(&dmultp->ds_mutex);
    359 	if ((dmultp->ds_outcnt >= dmultp->ds_waitcnt) || dmultp->ds_bp) {
    360 		QUE_ADD(que_objp, in_bp);
    361 		if (dmultp->ds_kstat) {
    362 			kstat_waitq_enter(KSTAT_IO_PTR(dmultp->ds_kstat));
    363 		}
    364 		mutex_exit(&dmultp->ds_mutex);
    365 		return (0);
    366 	}
    367 	if (dmultp->ds_kstat) {
    368 		kstat_waitq_enter(KSTAT_IO_PTR(dmultp->ds_kstat));
    369 	}
    370 
    371 	if (TGCOM_PKT(tgcom_objp, in_bp, dmult_restart,
    372 		(caddr_t)dmultp) != DDI_SUCCESS) {
    373 
    374 		dmultp->ds_bp = in_bp;
    375 		mutex_exit(&dmultp->ds_mutex);
    376 		return (0);
    377 	}
    378 	dmultp->ds_outcnt++;
    379 	if (dmultp->ds_kstat)
    380 		kstat_waitq_to_runq(KSTAT_IO_PTR(dmultp->ds_kstat));
    381 	mutex_exit(&dmultp->ds_mutex);
    382 
    383 	TGCOM_TRANSPORT(tgcom_objp, in_bp);
    384 	return (0);
    385 }
    386 
    387 static int
    388 dmult_deque(opaque_t queuep, struct buf *in_bp)
    389 {
    390 	struct fc_data *dmultp = (struct fc_data *)queuep;
    391 	opaque_t tgcom_objp;
    392 	opaque_t que_objp;
    393 	struct	 buf *bp;
    394 
    395 	que_objp = dmultp->ds_queobjp;
    396 	tgcom_objp = dmultp->ds_tgcomobjp;
    397 
    398 	mutex_enter(&dmultp->ds_mutex);
    399 	if (in_bp) {
    400 		dmultp->ds_outcnt--;
    401 		if (dmultp->ds_kstat) {
    402 			if (in_bp->b_flags & B_READ) {
    403 				KSTAT_IO_PTR(dmultp->ds_kstat)->reads++;
    404 				KSTAT_IO_PTR(dmultp->ds_kstat)->nread +=
    405 				    (in_bp->b_bcount - in_bp->b_resid);
    406 			} else {
    407 				KSTAT_IO_PTR(dmultp->ds_kstat)->writes++;
    408 				KSTAT_IO_PTR(dmultp->ds_kstat)->nwritten +=
    409 				    (in_bp->b_bcount - in_bp->b_resid);
    410 			}
    411 			kstat_runq_exit(KSTAT_IO_PTR(dmultp->ds_kstat));
    412 		}
    413 	}
    414 
    415 	for (;;) {
    416 
    417 #ifdef	FLC_DEBUG
    418 		if ((curthread->t_intr) && (!dmultp->ds_bp) &&
    419 		    (!dmultp->ds_outcnt))
    420 			flc_malloc_intr++;
    421 #endif
    422 
    423 		if (!dmultp->ds_bp)
    424 			dmultp->ds_bp = QUE_DEL(que_objp);
    425 		if (!dmultp->ds_bp ||
    426 		    (TGCOM_PKT(tgcom_objp, dmultp->ds_bp, dmult_restart,
    427 		    (caddr_t)dmultp) != DDI_SUCCESS) ||
    428 		    (dmultp->ds_outcnt >= dmultp->ds_waitcnt)) {
    429 			mutex_exit(&dmultp->ds_mutex);
    430 			return (0);
    431 		}
    432 		dmultp->ds_outcnt++;
    433 		bp = dmultp->ds_bp;
    434 		dmultp->ds_bp = QUE_DEL(que_objp);
    435 
    436 		if (dmultp->ds_kstat)
    437 			kstat_waitq_to_runq(KSTAT_IO_PTR(dmultp->ds_kstat));
    438 
    439 		mutex_exit(&dmultp->ds_mutex);
    440 
    441 		TGCOM_TRANSPORT(tgcom_objp, bp);
    442 
    443 		if (!mutex_tryenter(&dmultp->ds_mutex))
    444 			return (0);
    445 	}
    446 }
    447 
    448 static int
    449 dmult_restart(struct fc_data *dmultp)
    450 {
    451 	(void) dmult_deque(dmultp, NULL);
    452 	return (-1);
    453 }
    454 
    455 /*
    456  *	Duplexed Commands per Device: Read Queue and Write Queue
    457  */
    458 /*
    459  * Local Function Prototypes
    460  */
    461 static int duplx_restart();
    462 
    463 static int duplx_init(opaque_t queuep, opaque_t tgcom_objp, opaque_t que_objp,
    464     void *lkarg);
    465 static int duplx_free(struct flc_obj *flcobjp);
    466 static int duplx_enque(opaque_t queuep, struct buf *bp);
    467 static int duplx_deque(opaque_t queuep, struct buf *bp);
    468 
    469 struct 	flc_objops duplx_ops = {
    470 	duplx_init,
    471 	duplx_free,
    472 	duplx_enque,
    473 	duplx_deque,
    474 	fc_start_kstat,
    475 	fc_stop_kstat,
    476 	0, 0
    477 };
    478 
    479 struct flc_obj *
    480 duplx_create()
    481 {
    482 	struct	flc_obj *flcobjp;
    483 	struct	duplx_data *fcdp;
    484 
    485 	flcobjp = kmem_zalloc((sizeof (*flcobjp) + sizeof (*fcdp)), KM_NOSLEEP);
    486 	if (!flcobjp)
    487 		return (NULL);
    488 
    489 	fcdp = (struct duplx_data *)(flcobjp+1);
    490 	flcobjp->flc_data = (opaque_t)fcdp;
    491 	flcobjp->flc_ops  = &duplx_ops;
    492 
    493 	fcdp->ds_writeq.fc_qobjp = qfifo_create();
    494 	if (!(fcdp->ds_writeq.fc_qobjp = qfifo_create())) {
    495 		kmem_free(flcobjp, (sizeof (*flcobjp) + sizeof (*fcdp)));
    496 		return (NULL);
    497 	}
    498 	return (flcobjp);
    499 }
    500 
    501 static int
    502 duplx_free(struct flc_obj *flcobjp)
    503 {
    504 	struct duplx_data *fcdp;
    505 
    506 	fcdp = (struct duplx_data *)flcobjp->flc_data;
    507 	if (fcdp->ds_writeq.fc_qobjp) {
    508 		QUE_FREE(fcdp->ds_writeq.fc_qobjp);
    509 	}
    510 	if (fcdp->ds_readq.fc_qobjp)
    511 		QUE_FREE(fcdp->ds_readq.fc_qobjp);
    512 	if (fcdp->ds_tgcomobjp) {
    513 		TGCOM_FREE(fcdp->ds_tgcomobjp);
    514 		mutex_destroy(&fcdp->ds_mutex);
    515 	}
    516 	kmem_free(flcobjp, (sizeof (*flcobjp) + sizeof (*fcdp)));
    517 	return (0);
    518 }
    519 
    520 static int
    521 duplx_init(opaque_t queuep, opaque_t tgcom_objp, opaque_t que_objp, void *lkarg)
    522 {
    523 	struct duplx_data *fcdp = (struct duplx_data *)queuep;
    524 	fcdp->ds_tgcomobjp = tgcom_objp;
    525 	fcdp->ds_readq.fc_qobjp = que_objp;
    526 
    527 	QUE_INIT(que_objp, lkarg);
    528 	QUE_INIT(fcdp->ds_writeq.fc_qobjp, lkarg);
    529 	TGCOM_INIT(tgcom_objp);
    530 
    531 	mutex_init(&fcdp->ds_mutex, NULL, MUTEX_DRIVER, lkarg);
    532 
    533 	fcdp->ds_writeq.fc_maxcnt = DUPLX_MAXCNT;
    534 	fcdp->ds_readq.fc_maxcnt  = DUPLX_MAXCNT;
    535 
    536 	/* queues point to each other for round robin */
    537 	fcdp->ds_readq.next = &fcdp->ds_writeq;
    538 	fcdp->ds_writeq.next = &fcdp->ds_readq;
    539 
    540 	return (DDI_SUCCESS);
    541 }
    542 
    543 static int
    544 duplx_enque(opaque_t queuep, struct buf *in_bp)
    545 {
    546 	struct duplx_data *duplxp = (struct duplx_data *)queuep;
    547 	opaque_t tgcom_objp;
    548 	struct fc_que *activeq;
    549 	struct buf *bp;
    550 
    551 	mutex_enter(&duplxp->ds_mutex);
    552 	if (in_bp) {
    553 		if (duplxp->ds_kstat) {
    554 			kstat_waitq_enter(KSTAT_IO_PTR(duplxp->ds_kstat));
    555 		}
    556 		if (in_bp->b_flags & B_READ)
    557 			activeq = &duplxp->ds_readq;
    558 		else
    559 			activeq = &duplxp->ds_writeq;
    560 
    561 		QUE_ADD(activeq->fc_qobjp, in_bp);
    562 	} else {
    563 		activeq = &duplxp->ds_readq;
    564 	}
    565 
    566 	tgcom_objp = duplxp->ds_tgcomobjp;
    567 
    568 	for (;;) {
    569 		if (!activeq->fc_bp)
    570 			activeq->fc_bp = QUE_DEL(activeq->fc_qobjp);
    571 		if (!activeq->fc_bp ||
    572 		    (TGCOM_PKT(tgcom_objp, activeq->fc_bp, duplx_restart,
    573 		    (caddr_t)duplxp) != DDI_SUCCESS) ||
    574 		    (activeq->fc_outcnt >= activeq->fc_maxcnt)) {
    575 
    576 			/* switch read/write queues */
    577 			activeq = activeq->next;
    578 			if (!activeq->fc_bp)
    579 				activeq->fc_bp = QUE_DEL(activeq->fc_qobjp);
    580 			if (!activeq->fc_bp ||
    581 			    (TGCOM_PKT(tgcom_objp, activeq->fc_bp,
    582 			    duplx_restart, (caddr_t)duplxp) != DDI_SUCCESS) ||
    583 			    (activeq->fc_outcnt >= activeq->fc_maxcnt)) {
    584 				mutex_exit(&duplxp->ds_mutex);
    585 				return (0);
    586 			}
    587 		}
    588 
    589 		activeq->fc_outcnt++;
    590 		bp = activeq->fc_bp;
    591 		activeq->fc_bp = NULL;
    592 
    593 		if (duplxp->ds_kstat)
    594 			kstat_waitq_to_runq(KSTAT_IO_PTR(duplxp->ds_kstat));
    595 		mutex_exit(&duplxp->ds_mutex);
    596 
    597 		TGCOM_TRANSPORT(tgcom_objp, bp);
    598 
    599 		if (!mutex_tryenter(&duplxp->ds_mutex))
    600 			return (0);
    601 
    602 		activeq = activeq->next;
    603 	}
    604 }
    605 
    606 static int
    607 duplx_deque(opaque_t queuep, struct buf *in_bp)
    608 {
    609 	struct duplx_data *duplxp = (struct duplx_data *)queuep;
    610 	opaque_t tgcom_objp;
    611 	struct fc_que *activeq;
    612 	struct buf *bp;
    613 
    614 	mutex_enter(&duplxp->ds_mutex);
    615 
    616 	tgcom_objp = duplxp->ds_tgcomobjp;
    617 
    618 	if (in_bp->b_flags & B_READ)
    619 		activeq = &duplxp->ds_readq;
    620 	else
    621 		activeq = &duplxp->ds_writeq;
    622 	activeq->fc_outcnt--;
    623 
    624 	if (duplxp->ds_kstat) {
    625 		if (in_bp->b_flags & B_READ) {
    626 			KSTAT_IO_PTR(duplxp->ds_kstat)->reads++;
    627 			KSTAT_IO_PTR(duplxp->ds_kstat)->nread +=
    628 			    (in_bp->b_bcount - in_bp->b_resid);
    629 		} else {
    630 			KSTAT_IO_PTR(duplxp->ds_kstat)->writes++;
    631 			KSTAT_IO_PTR(duplxp->ds_kstat)->nwritten +=
    632 			    (in_bp->b_bcount - in_bp->b_resid);
    633 		}
    634 		kstat_runq_exit(KSTAT_IO_PTR(duplxp->ds_kstat));
    635 	}
    636 
    637 	for (;;) {
    638 
    639 		/* if needed, try to pull request off a queue */
    640 		if (!activeq->fc_bp)
    641 			activeq->fc_bp = QUE_DEL(activeq->fc_qobjp);
    642 
    643 		if (!activeq->fc_bp ||
    644 		    (TGCOM_PKT(tgcom_objp, activeq->fc_bp, duplx_restart,
    645 		    (caddr_t)duplxp) != DDI_SUCCESS) ||
    646 		    (activeq->fc_outcnt >= activeq->fc_maxcnt)) {
    647 
    648 			activeq = activeq->next;
    649 			if (!activeq->fc_bp)
    650 				activeq->fc_bp = QUE_DEL(activeq->fc_qobjp);
    651 
    652 			if (!activeq->fc_bp ||
    653 			    (TGCOM_PKT(tgcom_objp, activeq->fc_bp,
    654 			    duplx_restart, (caddr_t)duplxp) != DDI_SUCCESS) ||
    655 			    (activeq->fc_outcnt >= activeq->fc_maxcnt)) {
    656 				mutex_exit(&duplxp->ds_mutex);
    657 				return (0);
    658 			}
    659 		}
    660 
    661 		activeq->fc_outcnt++;
    662 		bp = activeq->fc_bp;
    663 		activeq->fc_bp = NULL;
    664 
    665 		if (duplxp->ds_kstat)
    666 			kstat_waitq_to_runq(KSTAT_IO_PTR(duplxp->ds_kstat));
    667 
    668 		mutex_exit(&duplxp->ds_mutex);
    669 
    670 		TGCOM_TRANSPORT(tgcom_objp, bp);
    671 
    672 		if (!mutex_tryenter(&duplxp->ds_mutex))
    673 			return (0);
    674 
    675 		activeq = activeq->next;
    676 	}
    677 }
    678 
    679 static int
    680 duplx_restart(struct duplx_data *duplxp)
    681 {
    682 	(void) duplx_enque(duplxp, NULL);
    683 	return (-1);
    684 }
    685 
    686 /*
    687  *	Tagged queueing flow control
    688  */
    689 /*
    690  * Local Function Prototypes
    691  */
    692 
    693 struct 	flc_objops adapt_ops = {
    694 	fc_init,
    695 	fc_free,
    696 	dmult_enque,
    697 	dmult_deque,
    698 	fc_start_kstat,
    699 	fc_stop_kstat,
    700 	0, 0
    701 };
    702 
    703 struct flc_obj *
    704 adapt_create()
    705 {
    706 	return (fc_create((struct flc_objops *)&adapt_ops));
    707 
    708 }
    709 
    710 /*
    711  *	Common Queue functions
    712  */
    713 
    714 /*
    715  * 	Local static data
    716  */
    717 #ifdef	Q_DEBUG
    718 #define	DENT	0x0001
    719 #define	DERR	0x0002
    720 #define	DIO	0x0004
    721 static	int	que_debug = DENT|DERR|DIO;
    722 
    723 #endif	/* Q_DEBUG */
    724 /*
    725  * 	Local Function Prototypes
    726  */
    727 static struct que_obj *que_create(struct que_objops *qopsp);
    728 static int que_init(struct que_data *qfp, void *lkarg);
    729 static int que_free(struct que_obj *queobjp);
    730 static struct buf *que_del(struct que_data *qfp);
    731 
    732 static struct que_obj *
    733 que_create(struct que_objops *qopsp)
    734 {
    735 	struct	que_data *qfp;
    736 	struct	que_obj *queobjp;
    737 
    738 	queobjp = kmem_zalloc((sizeof (*queobjp) + sizeof (*qfp)), KM_NOSLEEP);
    739 	if (!queobjp)
    740 		return (NULL);
    741 
    742 	queobjp->que_ops = qopsp;
    743 	qfp = (struct que_data *)(queobjp+1);
    744 	queobjp->que_data = (opaque_t)qfp;
    745 
    746 	return ((opaque_t)queobjp);
    747 }
    748 
    749 static int
    750 que_init(struct que_data *qfp, void *lkarg)
    751 {
    752 	mutex_init(&qfp->q_mutex, NULL, MUTEX_DRIVER, lkarg);
    753 	return (DDI_SUCCESS);
    754 }
    755 
    756 static int
    757 que_free(struct que_obj *queobjp)
    758 {
    759 	struct	que_data *qfp;
    760 
    761 	qfp = (struct que_data *)queobjp->que_data;
    762 	mutex_destroy(&qfp->q_mutex);
    763 	kmem_free(queobjp, (sizeof (*queobjp) + sizeof (struct que_data)));
    764 	return (0);
    765 }
    766 
    767 static struct buf *
    768 que_del(struct que_data *qfp)
    769 {
    770 	struct buf *bp;
    771 
    772 	bp = qfp->q_tab.b_actf;
    773 	if (bp) {
    774 		qfp->q_tab.b_actf = bp->av_forw;
    775 		if (!qfp->q_tab.b_actf)
    776 			qfp->q_tab.b_actl = NULL;
    777 		bp->av_forw = 0;
    778 	}
    779 	return (bp);
    780 }
    781 
    782 
    783 
    784 /*
    785  *	Qmerge
    786  * 	Local Function Prototypes
    787  */
    788 static int qmerge_add(), qmerge_free();
    789 static struct buf *qmerge_del(struct que_data *qfp);
    790 
    791 struct 	que_objops qmerge_ops = {
    792 	que_init,
    793 	qmerge_free,
    794 	qmerge_add,
    795 	qmerge_del,
    796 	0, 0
    797 };
    798 
    799 /* fields in diskhd */
    800 #define	hd_cnt			b_back
    801 #define	hd_private		b_forw
    802 #define	hd_flags		b_flags
    803 #define	hd_sync_next		av_forw
    804 #define	hd_async_next		av_back
    805 
    806 #define	hd_sync2async		sync_async_ratio
    807 
    808 #define	QNEAR_FORWARD		0x01
    809 #define	QNEAR_BACKWARD		0x02
    810 #define	QNEAR_ASYNCONLY		0x04
    811 #define	QNEAR_ASYNCALSO		0x08
    812 
    813 #define	DBLK(bp) ((unsigned long)(bp)->b_private)
    814 
    815 #define	BP_LT_BP(a, b) (DBLK(a) < DBLK(b))
    816 #define	BP_GT_BP(a, b) (DBLK(a) > DBLK(b))
    817 #define	BP_LT_HD(a, b) (DBLK(a) < (unsigned long)((b)->hd_private))
    818 #define	BP_GT_HD(a, b) (DBLK(a) > (unsigned long)((b)->hd_private))
    819 #define	QNEAR_ASYNC	(QNEAR_ASYNCONLY|QNEAR_ASYNCALSO)
    820 
    821 #define	SYNC2ASYNC(a) ((a)->q_tab.hd_cnt)
    822 
    823 
    824 /*
    825  * qmerge implements a two priority queue, the low priority queue holding ASYNC
    826  * write requests, while the rest are queued in the high priority sync queue.
    827  * Requests on the async queue would be merged if possible.
    828  * By default qmerge2wayscan is 1, indicating an elevator algorithm. When
    829  * this variable is set to zero, it has the following side effects.
    830  * 1. We assume fairness is the number one issue.
    831  * 2. The next request to be picked indicates current head position.
    832  *
    833  * qmerge_sync2async indicates the ratio of scans of high prioriy
    834  * sync queue to low priority async queue.
    835  *
    836  * When qmerge variables have the following values it defaults to qsort
    837  *
    838  * qmerge1pri = 1, qmerge2wayscan = 0, qmerge_max_merge = 0
    839  *
    840  */
    841 static int	qmerge_max_merge = 128 * 1024;
    842 static intptr_t	qmerge_sync2async = 4;
    843 static int	qmerge2wayscan = 1;
    844 static int	qmerge1pri = 0;
    845 static int	qmerge_merge = 0;
    846 
    847 /*
    848  * 	Local static data
    849  */
    850 struct que_obj *
    851 qmerge_create()
    852 {
    853 	struct que_data *qfp;
    854 	struct que_obj *queobjp;
    855 
    856 	queobjp = kmem_zalloc((sizeof (*queobjp) + sizeof (*qfp)), KM_NOSLEEP);
    857 	if (!queobjp)
    858 		return (NULL);
    859 
    860 	queobjp->que_ops = &qmerge_ops;
    861 	qfp = (struct que_data *)(queobjp+1);
    862 	qfp->q_tab.hd_private = qfp->q_tab.hd_private = 0;
    863 	qfp->q_tab.hd_sync_next = qfp->q_tab.hd_async_next = NULL;
    864 	qfp->q_tab.hd_cnt = (void *)qmerge_sync2async;
    865 	queobjp->que_data = (opaque_t)qfp;
    866 
    867 	return ((opaque_t)queobjp);
    868 }
    869 
    870 static int
    871 qmerge_free(struct que_obj *queobjp)
    872 {
    873 	struct	que_data *qfp;
    874 
    875 	qfp = (struct que_data *)queobjp->que_data;
    876 	mutex_destroy(&qfp->q_mutex);
    877 	kmem_free(queobjp, (sizeof (*queobjp) + sizeof (*qfp)));
    878 	return (0);
    879 }
    880 
    881 static int
    882 qmerge_can_merge(bp1, bp2)
    883 struct	buf *bp1, *bp2;
    884 {
    885 	const int paw_flags = B_PAGEIO | B_ASYNC | B_WRITE;
    886 
    887 	if ((bp1->b_un.b_addr != 0) || (bp2->b_un.b_addr != 0) ||
    888 	    ((bp1->b_flags & (paw_flags | B_REMAPPED)) != paw_flags) ||
    889 	    ((bp2->b_flags & (paw_flags | B_REMAPPED)) != paw_flags) ||
    890 	    (bp1->b_bcount & PAGEOFFSET) || (bp2->b_bcount & PAGEOFFSET) ||
    891 	    (bp1->b_bcount + bp2->b_bcount > qmerge_max_merge))
    892 		return (0);
    893 
    894 	if ((DBLK(bp2) + bp2->b_bcount / DEV_BSIZE == DBLK(bp1)) ||
    895 	    (DBLK(bp1) + bp1->b_bcount / DEV_BSIZE == DBLK(bp2)))
    896 		return (1);
    897 	else
    898 		return (0);
    899 }
    900 
    901 static void
    902 qmerge_mergesetup(bp_merge, bp)
    903 struct	buf *bp_merge, *bp;
    904 {
    905 	struct	buf *bp1;
    906 	struct	page *pp, *pp_merge, *pp_merge_prev;
    907 	int	forward;
    908 
    909 	qmerge_merge++;
    910 	forward = DBLK(bp_merge) < DBLK(bp);
    911 
    912 	bp_merge->b_bcount += bp->b_bcount;
    913 
    914 	pp = bp->b_pages;
    915 	pp_merge = bp_merge->b_pages;
    916 
    917 	pp_merge_prev = pp_merge->p_prev;
    918 
    919 	pp_merge->p_prev->p_next = pp;
    920 	pp_merge->p_prev = pp->p_prev;
    921 	pp->p_prev->p_next = pp_merge;
    922 	pp->p_prev = pp_merge_prev;
    923 
    924 	bp1 = bp_merge->b_forw;
    925 
    926 	bp1->av_back->av_forw = bp;
    927 	bp->av_back = bp1->av_back;
    928 	bp1->av_back = bp;
    929 	bp->av_forw = bp1;
    930 
    931 	if (!forward) {
    932 		bp_merge->b_forw = bp;
    933 		bp_merge->b_pages = pp;
    934 		bp_merge->b_private = bp->b_private;
    935 	}
    936 }
    937 
    938 static void
    939 que_insert(struct que_data *qfp, struct buf *bp)
    940 {
    941 	struct buf	*bp1, *bp_start, *lowest_bp, *highest_bp;
    942 	uintptr_t	highest_blk, lowest_blk;
    943 	struct buf	**async_bpp, **sync_bpp, **bpp;
    944 	struct diskhd	*dp = &qfp->q_tab;
    945 
    946 	sync_bpp = &dp->hd_sync_next;
    947 	async_bpp = &dp->hd_async_next;
    948 	/*
    949 	 * The ioctl used by the format utility requires that bp->av_back be
    950 	 * preserved.
    951 	 */
    952 	if (bp->av_back)
    953 		bp->b_error = (intptr_t)bp->av_back;
    954 	if (!qmerge1pri &&
    955 	    ((bp->b_flags & (B_ASYNC|B_READ|B_FREE)) == B_ASYNC)) {
    956 		bpp = &dp->hd_async_next;
    957 	} else {
    958 		bpp = &dp->hd_sync_next;
    959 	}
    960 
    961 
    962 	if ((bp1 = *bpp) == NULL) {
    963 		*bpp = bp;
    964 		bp->av_forw = bp->av_back = bp;
    965 		if ((bpp == async_bpp) && (*sync_bpp == NULL)) {
    966 			dp->hd_flags |= QNEAR_ASYNCONLY;
    967 		} else if (bpp == sync_bpp) {
    968 			dp->hd_flags &= ~QNEAR_ASYNCONLY;
    969 			if (*async_bpp) {
    970 				dp->hd_flags |= QNEAR_ASYNCALSO;
    971 			}
    972 		}
    973 		return;
    974 	}
    975 	bp_start = bp1;
    976 	if (DBLK(bp) < DBLK(bp1)) {
    977 		lowest_blk = DBLK(bp1);
    978 		lowest_bp = bp1;
    979 		do {
    980 			if (DBLK(bp) > DBLK(bp1)) {
    981 				bp->av_forw = bp1->av_forw;
    982 				bp1->av_forw->av_back = bp;
    983 				bp1->av_forw = bp;
    984 				bp->av_back = bp1;
    985 
    986 				if (((bpp == async_bpp) &&
    987 				    (dp->hd_flags & QNEAR_ASYNC)) ||
    988 				    (bpp == sync_bpp)) {
    989 					if (!(dp->hd_flags & QNEAR_BACKWARD) &&
    990 					    BP_GT_HD(bp, dp)) {
    991 						*bpp = bp;
    992 					}
    993 				}
    994 				return;
    995 			} else if (DBLK(bp1) < lowest_blk) {
    996 				lowest_bp = bp1;
    997 				lowest_blk = DBLK(bp1);
    998 			}
    999 		} while ((DBLK(bp1->av_back) < DBLK(bp1)) &&
   1000 		    ((bp1 = bp1->av_back) != bp_start));
   1001 		bp->av_forw = lowest_bp;
   1002 		lowest_bp->av_back->av_forw = bp;
   1003 		bp->av_back = lowest_bp->av_back;
   1004 		lowest_bp->av_back = bp;
   1005 		if ((bpp == async_bpp) && !(dp->hd_flags & QNEAR_ASYNC)) {
   1006 			*bpp = bp;
   1007 		} else if (!(dp->hd_flags & QNEAR_BACKWARD) &&
   1008 		    BP_GT_HD(bp, dp)) {
   1009 			*bpp = bp;
   1010 		}
   1011 	} else {
   1012 		highest_blk = DBLK(bp1);
   1013 		highest_bp = bp1;
   1014 		do {
   1015 			if (DBLK(bp) < DBLK(bp1)) {
   1016 				bp->av_forw = bp1;
   1017 				bp1->av_back->av_forw = bp;
   1018 				bp->av_back = bp1->av_back;
   1019 				bp1->av_back = bp;
   1020 				if (((bpp == async_bpp) &&
   1021 				    (dp->hd_flags & QNEAR_ASYNC)) ||
   1022 				    (bpp == sync_bpp)) {
   1023 					if ((dp->hd_flags & QNEAR_BACKWARD) &&
   1024 					    BP_LT_HD(bp, dp)) {
   1025 						*bpp = bp;
   1026 					}
   1027 				}
   1028 				return;
   1029 			} else if (DBLK(bp1) > highest_blk) {
   1030 				highest_bp = bp1;
   1031 				highest_blk = DBLK(bp1);
   1032 			}
   1033 		} while ((DBLK(bp1->av_forw) > DBLK(bp1)) &&
   1034 		    ((bp1 = bp1->av_forw) != bp_start));
   1035 		bp->av_back = highest_bp;
   1036 		highest_bp->av_forw->av_back = bp;
   1037 		bp->av_forw = highest_bp->av_forw;
   1038 		highest_bp->av_forw = bp;
   1039 
   1040 		if (((bpp == sync_bpp) ||
   1041 		    ((bpp == async_bpp) && (dp->hd_flags & QNEAR_ASYNC))) &&
   1042 		    (dp->hd_flags & QNEAR_BACKWARD) && (BP_LT_HD(bp, dp)))
   1043 			*bpp = bp;
   1044 	}
   1045 }
   1046 
   1047 /*
   1048  * dmult_enque() holds dmultp->ds_mutex lock, so we dont grab
   1049  * lock here. If dmult_enque() changes we will have to visit
   1050  * this function again
   1051  */
   1052 static int
   1053 qmerge_add(struct que_data *qfp, struct buf *bp)
   1054 {
   1055 
   1056 	que_insert(qfp, bp);
   1057 	return (++qfp->q_cnt);
   1058 }
   1059 
   1060 static int
   1061 qmerge_iodone(struct buf *bp)
   1062 {
   1063 	struct buf *bp1;
   1064 	struct	page *pp, *pp1, *tmp_pp;
   1065 
   1066 	if (bp->b_flags & B_REMAPPED)
   1067 		bp_mapout(bp);
   1068 
   1069 	bp1 = bp->b_forw;
   1070 	do {
   1071 		bp->b_forw = bp1->av_forw;
   1072 		bp1->av_forw->av_back = bp1->av_back;
   1073 		bp1->av_back->av_forw = bp1->av_forw;
   1074 		pp = (page_t *)bp1->b_pages;
   1075 		pp1 = bp->b_forw->b_pages;
   1076 
   1077 		tmp_pp = pp->p_prev;
   1078 		pp->p_prev = pp1->p_prev;
   1079 		pp->p_prev->p_next = pp;
   1080 
   1081 		pp1->p_prev = tmp_pp;
   1082 		pp1->p_prev->p_next = pp1;
   1083 
   1084 		if (bp->b_flags & B_ERROR) {
   1085 			bp1->b_error = bp->b_error;
   1086 			bp1->b_flags |= B_ERROR;
   1087 		}
   1088 
   1089 		biodone(bp1);
   1090 	} while ((bp1 = bp->b_forw) != bp->b_forw->av_forw);
   1091 
   1092 	biodone(bp1);
   1093 	kmem_free(bp, sizeof (*bp));
   1094 	return (0);
   1095 }
   1096 
   1097 
   1098 
   1099 
   1100 static struct buf *
   1101 qmerge_nextbp(struct que_data *qfp, struct buf *bp_merge, int *can_merge)
   1102 {
   1103 	intptr_t	private, cnt;
   1104 	int		flags;
   1105 	struct		buf *sync_bp, *async_bp, *bp;
   1106 	struct		buf **sync_bpp, **async_bpp, **bpp;
   1107 	struct		diskhd *dp = &qfp->q_tab;
   1108 
   1109 	if (qfp->q_cnt == 0) {
   1110 		return (NULL);
   1111 	}
   1112 	flags = qfp->q_tab.hd_flags;
   1113 	sync_bpp = &qfp->q_tab.hd_sync_next;
   1114 	async_bpp = &qfp->q_tab.hd_async_next;
   1115 
   1116 begin_nextbp:
   1117 	if (flags & QNEAR_ASYNCONLY) {
   1118 		bp = *async_bpp;
   1119 		private = DBLK(bp);
   1120 		if (bp_merge && !qmerge_can_merge(bp, bp_merge)) {
   1121 			return (NULL);
   1122 		} else if (bp->av_forw == bp) {
   1123 			bp->av_forw = bp->av_back = NULL;
   1124 			flags &= ~(QNEAR_ASYNCONLY | QNEAR_BACKWARD);
   1125 			private = 0;
   1126 		} else if (flags & QNEAR_BACKWARD) {
   1127 			if (DBLK(bp) < DBLK(bp->av_back)) {
   1128 				flags &= ~QNEAR_BACKWARD;
   1129 				private = 0;
   1130 			}
   1131 		} else if (DBLK(bp) > DBLK(bp->av_forw)) {
   1132 			if (qmerge2wayscan) {
   1133 				flags |= QNEAR_BACKWARD;
   1134 			} else {
   1135 				private = 0;
   1136 			}
   1137 		} else if (qmerge2wayscan == 0) {
   1138 			private = DBLK(bp->av_forw);
   1139 		}
   1140 		bpp = async_bpp;
   1141 
   1142 	} else if (flags & QNEAR_ASYNCALSO) {
   1143 		sync_bp = *sync_bpp;
   1144 		async_bp = *async_bpp;
   1145 		if (flags & QNEAR_BACKWARD) {
   1146 			if (BP_GT_HD(sync_bp, dp) && BP_GT_HD(async_bp, dp)) {
   1147 				flags &= ~(QNEAR_BACKWARD|QNEAR_ASYNCALSO);
   1148 				*sync_bpp = sync_bp->av_forw;
   1149 				*async_bpp = async_bp->av_forw;
   1150 				SYNC2ASYNC(qfp) = (void *)qmerge_sync2async;
   1151 				qfp->q_tab.hd_private = 0;
   1152 				goto begin_nextbp;
   1153 			}
   1154 			if (BP_LT_HD(async_bp, dp) && BP_LT_HD(sync_bp, dp)) {
   1155 				if (BP_GT_BP(async_bp, sync_bp)) {
   1156 					bpp = async_bpp;
   1157 					bp = *async_bpp;
   1158 				} else {
   1159 					bpp = sync_bpp;
   1160 					bp = *sync_bpp;
   1161 				}
   1162 			} else if (BP_LT_HD(async_bp, dp)) {
   1163 				bpp = async_bpp;
   1164 				bp = *async_bpp;
   1165 			} else {
   1166 				bpp = sync_bpp;
   1167 				bp = *sync_bpp;
   1168 			}
   1169 		} else {
   1170 			if (BP_LT_HD(sync_bp, dp) && BP_LT_HD(async_bp, dp)) {
   1171 				if (qmerge2wayscan) {
   1172 					flags |= QNEAR_BACKWARD;
   1173 					*sync_bpp = sync_bp->av_back;
   1174 					*async_bpp = async_bp->av_back;
   1175 					goto begin_nextbp;
   1176 				} else {
   1177 					flags &= ~QNEAR_ASYNCALSO;
   1178 					SYNC2ASYNC(qfp) =
   1179 						(void *)qmerge_sync2async;
   1180 					qfp->q_tab.hd_private = 0;
   1181 					goto begin_nextbp;
   1182 				}
   1183 			}
   1184 			if (BP_GT_HD(async_bp, dp) && BP_GT_HD(sync_bp, dp)) {
   1185 				if (BP_LT_BP(async_bp, sync_bp)) {
   1186 					bpp = async_bpp;
   1187 					bp = *async_bpp;
   1188 				} else {
   1189 					bpp = sync_bpp;
   1190 					bp = *sync_bpp;
   1191 				}
   1192 			} else if (BP_GT_HD(async_bp, dp)) {
   1193 				bpp = async_bpp;
   1194 				bp = *async_bpp;
   1195 			} else {
   1196 				bpp = sync_bpp;
   1197 				bp = *sync_bpp;
   1198 			}
   1199 		}
   1200 		if (bp_merge && !qmerge_can_merge(bp, bp_merge)) {
   1201 			return (NULL);
   1202 		} else if (bp->av_forw == bp) {
   1203 			bp->av_forw = bp->av_back = NULL;
   1204 			flags &= ~QNEAR_ASYNCALSO;
   1205 			if (bpp == async_bpp) {
   1206 				SYNC2ASYNC(qfp) = (void *)qmerge_sync2async;
   1207 			} else {
   1208 				flags |= QNEAR_ASYNCONLY;
   1209 			}
   1210 		}
   1211 		private = DBLK(bp);
   1212 	} else {
   1213 		bp = *sync_bpp;
   1214 		private = DBLK(bp);
   1215 		if (bp_merge && !qmerge_can_merge(bp, bp_merge)) {
   1216 			return (NULL);
   1217 		} else if (bp->av_forw == bp) {
   1218 			private = 0;
   1219 			SYNC2ASYNC(qfp) = (void *)qmerge_sync2async;
   1220 			bp->av_forw = bp->av_back = NULL;
   1221 			flags &= ~QNEAR_BACKWARD;
   1222 			if (*async_bpp)
   1223 				flags |= QNEAR_ASYNCONLY;
   1224 		} else if (flags & QNEAR_BACKWARD) {
   1225 			if (DBLK(bp) < DBLK(bp->av_back)) {
   1226 				flags &= ~QNEAR_BACKWARD;
   1227 				cnt = (intptr_t)SYNC2ASYNC(qfp);
   1228 				if (cnt > 0) {
   1229 					cnt--;
   1230 					SYNC2ASYNC(qfp) = (void *)cnt;
   1231 				} else {
   1232 					if (*async_bpp)
   1233 						flags |= QNEAR_ASYNCALSO;
   1234 					SYNC2ASYNC(qfp) =
   1235 						(void *)qmerge_sync2async;
   1236 				}
   1237 				private = 0;
   1238 			}
   1239 		} else if (DBLK(bp) > DBLK(bp->av_forw)) {
   1240 			private = 0;
   1241 			if (qmerge2wayscan) {
   1242 				flags |= QNEAR_BACKWARD;
   1243 				private = DBLK(bp);
   1244 			} else {
   1245 				cnt = (intptr_t)SYNC2ASYNC(qfp);
   1246 				if (cnt > 0) {
   1247 					cnt--;
   1248 					SYNC2ASYNC(qfp) = (void *)cnt;
   1249 				} else {
   1250 					if (*async_bpp)
   1251 						flags |= QNEAR_ASYNCALSO;
   1252 					SYNC2ASYNC(qfp) =
   1253 						(void *)qmerge_sync2async;
   1254 				}
   1255 			}
   1256 		} else if (qmerge2wayscan == 0) {
   1257 			private = DBLK(bp->av_forw);
   1258 		}
   1259 		bpp = sync_bpp;
   1260 	}
   1261 
   1262 	if (bp->av_forw) {
   1263 		*can_merge = !(bp->b_flags & B_READ);
   1264 		if (flags & QNEAR_BACKWARD) {
   1265 			*bpp = bp->av_back;
   1266 			if ((DBLK(bp->av_back) +
   1267 			    bp->av_back->b_bcount / DEV_BSIZE) != DBLK(bp))
   1268 				*can_merge = 0;
   1269 		} else {
   1270 			*bpp = bp->av_forw;
   1271 			if ((DBLK(bp) + bp->b_bcount / DEV_BSIZE) !=
   1272 			    DBLK(bp->av_forw))
   1273 				*can_merge = 0;
   1274 		}
   1275 		bp->av_forw->av_back = bp->av_back;
   1276 		bp->av_back->av_forw = bp->av_forw;
   1277 		bp->av_forw = bp->av_back = NULL;
   1278 	} else {
   1279 		*bpp = NULL;
   1280 		*can_merge = 0;
   1281 	}
   1282 	qfp->q_tab.hd_private = (void *)private;
   1283 	qfp->q_cnt--;
   1284 	qfp->q_tab.hd_flags = flags;
   1285 	if (bp->b_error) {
   1286 		bp->av_back = (void *)(intptr_t)bp->b_error;
   1287 		bp->b_error = 0;
   1288 	}
   1289 	return (bp);
   1290 }
   1291 
   1292 static struct buf *
   1293 qmerge_del(struct que_data *qfp)
   1294 {
   1295 	struct	buf *bp, *next_bp, *bp_merge;
   1296 	int	alloc_mergebp, merge;
   1297 
   1298 	if (qfp->q_cnt == 0) {
   1299 		return (NULL);
   1300 	}
   1301 
   1302 	bp_merge = bp = qmerge_nextbp(qfp, NULL, &merge);
   1303 	alloc_mergebp = 1;
   1304 	while (merge && (next_bp = qmerge_nextbp(qfp, bp_merge, &merge))) {
   1305 		if (alloc_mergebp) {
   1306 			bp_merge = kmem_alloc(sizeof (*bp_merge), KM_NOSLEEP);
   1307 			if (bp_merge == NULL) {
   1308 				mutex_exit(&qfp->q_mutex);
   1309 				return (bp);
   1310 			}
   1311 			bcopy(bp, bp_merge, sizeof (*bp_merge));
   1312 			bp_merge->b_iodone = qmerge_iodone;
   1313 			bp_merge->b_forw = bp;
   1314 			bp_merge->b_back = (struct buf *)qfp;
   1315 			bp->av_forw = bp->av_back = bp;
   1316 			alloc_mergebp = 0;
   1317 		}
   1318 		qmerge_mergesetup(bp_merge, next_bp);
   1319 	}
   1320 	return (bp_merge);
   1321 }
   1322 
   1323 
   1324 /*
   1325  *	FIFO Queue functions
   1326  */
   1327 /*
   1328  * 	Local Function Prototypes
   1329  */
   1330 static int qfifo_add();
   1331 
   1332 struct 	que_objops qfifo_ops = {
   1333 	que_init,
   1334 	que_free,
   1335 	qfifo_add,
   1336 	que_del,
   1337 	0, 0
   1338 };
   1339 
   1340 /*
   1341  * 	Local static data
   1342  */
   1343 struct que_obj *
   1344 qfifo_create()
   1345 {
   1346 	return (que_create((struct que_objops *)&qfifo_ops));
   1347 }
   1348 
   1349 static int
   1350 qfifo_add(struct que_data *qfp, struct buf *bp)
   1351 {
   1352 
   1353 	if (!qfp->q_tab.b_actf)
   1354 		qfp->q_tab.b_actf = bp;
   1355 	else
   1356 		qfp->q_tab.b_actl->av_forw = bp;
   1357 	qfp->q_tab.b_actl = bp;
   1358 	bp->av_forw = NULL;
   1359 	return (0);
   1360 }
   1361 
   1362 /*
   1363  *	One-Way-Scan Queue functions
   1364  */
   1365 /*
   1366  * 	Local Function Prototypes
   1367  */
   1368 static int qsort_add();
   1369 static struct buf *qsort_del();
   1370 static void oneway_scan_binary(struct diskhd *dp, struct buf *bp);
   1371 
   1372 struct 	que_objops qsort_ops = {
   1373 	que_init,
   1374 	que_free,
   1375 	qsort_add,
   1376 	qsort_del,
   1377 	0, 0
   1378 };
   1379 
   1380 /*
   1381  * 	Local static data
   1382  */
   1383 struct que_obj *
   1384 qsort_create()
   1385 {
   1386 	return (que_create((struct que_objops *)&qsort_ops));
   1387 }
   1388 
   1389 static int
   1390 qsort_add(struct que_data *qfp, struct buf *bp)
   1391 {
   1392 	qfp->q_cnt++;
   1393 	oneway_scan_binary(&qfp->q_tab, bp);
   1394 	return (0);
   1395 }
   1396 
   1397 
   1398 #define	b_pasf	b_forw
   1399 #define	b_pasl	b_back
   1400 static void
   1401 oneway_scan_binary(struct diskhd *dp, struct buf *bp)
   1402 {
   1403 	struct buf *ap;
   1404 
   1405 	ap = dp->b_actf;
   1406 	if (ap == NULL) {
   1407 		dp->b_actf = bp;
   1408 		bp->av_forw = NULL;
   1409 		return;
   1410 	}
   1411 	if (DBLK(bp) < DBLK(ap)) {
   1412 		ap = dp->b_pasf;
   1413 		if ((ap == NULL) || (DBLK(bp) < DBLK(ap))) {
   1414 			dp->b_pasf = bp;
   1415 			bp->av_forw = ap;
   1416 			return;
   1417 		}
   1418 	}
   1419 	while (ap->av_forw) {
   1420 		if (DBLK(bp) < DBLK(ap->av_forw))
   1421 			break;
   1422 		ap = ap->av_forw;
   1423 	}
   1424 	bp->av_forw = ap->av_forw;
   1425 	ap->av_forw = bp;
   1426 }
   1427 
   1428 static struct buf *
   1429 qsort_del(struct que_data *qfp)
   1430 {
   1431 	struct buf *bp;
   1432 
   1433 	if (qfp->q_cnt == 0) {
   1434 		return (NULL);
   1435 	}
   1436 	qfp->q_cnt--;
   1437 	bp = qfp->q_tab.b_actf;
   1438 	qfp->q_tab.b_actf = bp->av_forw;
   1439 	bp->av_forw = 0;
   1440 	if (!qfp->q_tab.b_actf && qfp->q_tab.b_pasf) {
   1441 		qfp->q_tab.b_actf = qfp->q_tab.b_pasf;
   1442 		qfp->q_tab.b_pasf = NULL;
   1443 	}
   1444 	return (bp);
   1445 }
   1446 
   1447 /*
   1448  *	Tagged queueing
   1449  */
   1450 /*
   1451  * 	Local Function Prototypes
   1452  */
   1453 
   1454 struct 	que_objops qtag_ops = {
   1455 	que_init,
   1456 	que_free,
   1457 	qsort_add,
   1458 	qsort_del,
   1459 	0, 0
   1460 };
   1461 
   1462 /*
   1463  * 	Local static data
   1464  */
   1465 struct que_obj *
   1466 qtag_create()
   1467 {
   1468 	return (que_create((struct que_objops *)&qtag_ops));
   1469 }
   1470