xref: /titanic_51/usr/src/uts/intel/io/dktp/drvobj/strategy.c (revision 2bc987325e3ded1865bff043128661815c4690b9)
1507c3241Smlf /*
2507c3241Smlf  * CDDL HEADER START
3507c3241Smlf  *
4507c3241Smlf  * The contents of this file are subject to the terms of the
5507c3241Smlf  * Common Development and Distribution License, Version 1.0 only
6507c3241Smlf  * (the "License").  You may not use this file except in compliance
7507c3241Smlf  * with the License.
8507c3241Smlf  *
9507c3241Smlf  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10507c3241Smlf  * or http://www.opensolaris.org/os/licensing.
11507c3241Smlf  * See the License for the specific language governing permissions
12507c3241Smlf  * and limitations under the License.
13507c3241Smlf  *
14507c3241Smlf  * When distributing Covered Code, include this CDDL HEADER in each
15507c3241Smlf  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16507c3241Smlf  * If applicable, add the following below this CDDL HEADER, with the
17507c3241Smlf  * fields enclosed by brackets "[]" replaced with your own identifying
18507c3241Smlf  * information: Portions Copyright [yyyy] [name of copyright owner]
19507c3241Smlf  *
20507c3241Smlf  * CDDL HEADER END
21507c3241Smlf  */
22507c3241Smlf /*
23613b2871SRichard Bean  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24507c3241Smlf  * Use is subject to license terms.
25507c3241Smlf  */
26507c3241Smlf 
27507c3241Smlf /*
28507c3241Smlf  *	Device Strategy
29507c3241Smlf  */
30507c3241Smlf #include <sys/dktp/cm.h>
31507c3241Smlf #include <sys/kstat.h>
32507c3241Smlf 
33507c3241Smlf #include <sys/dktp/quetypes.h>
34507c3241Smlf #include <sys/dktp/queue.h>
35507c3241Smlf #include <sys/dktp/tgcom.h>
36507c3241Smlf #include <sys/dktp/fctypes.h>
37507c3241Smlf #include <sys/dktp/flowctrl.h>
38507c3241Smlf #include <sys/param.h>
39507c3241Smlf #include <vm/page.h>
40507c3241Smlf #include <sys/modctl.h>
41507c3241Smlf 
42507c3241Smlf /*
43507c3241Smlf  *	Object Management
44507c3241Smlf  */
45507c3241Smlf 
46507c3241Smlf static struct buf *qmerge_nextbp(struct que_data *qfp, struct buf *bp_merge,
47507c3241Smlf     int *can_merge);
48507c3241Smlf 
49507c3241Smlf static struct modlmisc modlmisc = {
50507c3241Smlf 	&mod_miscops,	/* Type of module */
51613b2871SRichard Bean 	"Device Strategy Objects"
52507c3241Smlf };
53507c3241Smlf 
54507c3241Smlf static struct modlinkage modlinkage = {
55507c3241Smlf 	MODREV_1,
56507c3241Smlf 	&modlmisc,
57507c3241Smlf 	NULL
58507c3241Smlf };
59507c3241Smlf 
60507c3241Smlf int
61507c3241Smlf _init(void)
62507c3241Smlf {
63507c3241Smlf 	return (mod_install(&modlinkage));
64507c3241Smlf }
65507c3241Smlf 
66507c3241Smlf int
67507c3241Smlf _fini(void)
68507c3241Smlf {
69507c3241Smlf 	return (mod_remove(&modlinkage));
70507c3241Smlf }
71507c3241Smlf 
72507c3241Smlf int
73507c3241Smlf _info(struct modinfo *modinfop)
74507c3241Smlf {
75507c3241Smlf 	return (mod_info(&modlinkage, modinfop));
76507c3241Smlf }
77507c3241Smlf 
78507c3241Smlf 
79507c3241Smlf /*
80507c3241Smlf  *	Common Flow Control functions
81507c3241Smlf  */
82507c3241Smlf 
83507c3241Smlf /*
84507c3241Smlf  * Local static data
85507c3241Smlf  */
86507c3241Smlf #ifdef	FLC_DEBUG
87507c3241Smlf #define	DENT	0x0001
88507c3241Smlf #define	DERR	0x0002
89507c3241Smlf #define	DIO	0x0004
90507c3241Smlf static	int	flc_debug = DENT|DERR|DIO;
91507c3241Smlf 
92507c3241Smlf #include <sys/thread.h>
93507c3241Smlf static 	int	flc_malloc_intr = 0;
94507c3241Smlf #endif	/* FLC_DEBUG */
95507c3241Smlf 
96507c3241Smlf static	int	flc_kstat = 1;
97507c3241Smlf 
98507c3241Smlf static struct flc_obj *fc_create(struct flc_objops *fcopsp);
99507c3241Smlf static int fc_init(opaque_t queuep, opaque_t tgcom_objp, opaque_t que_objp,
100507c3241Smlf     void *lkarg);
101507c3241Smlf static int fc_free(struct flc_obj *flcobjp);
102507c3241Smlf static int fc_start_kstat(opaque_t queuep, char *devtype, int instance);
103507c3241Smlf static int fc_stop_kstat(opaque_t queuep);
104507c3241Smlf 
105507c3241Smlf static struct flc_obj *
106507c3241Smlf fc_create(struct flc_objops *fcopsp)
107507c3241Smlf {
108507c3241Smlf 	struct	flc_obj *flcobjp;
109507c3241Smlf 	struct	fc_data *fcdp;
110507c3241Smlf 
111507c3241Smlf 	flcobjp = kmem_zalloc((sizeof (*flcobjp) + sizeof (*fcdp)), KM_NOSLEEP);
112507c3241Smlf 	if (!flcobjp)
113507c3241Smlf 		return (NULL);
114507c3241Smlf 
115507c3241Smlf 	fcdp = (struct fc_data *)(flcobjp+1);
116507c3241Smlf 	flcobjp->flc_data = (opaque_t)fcdp;
117507c3241Smlf 	flcobjp->flc_ops  = fcopsp;
118507c3241Smlf 
119507c3241Smlf 	return ((opaque_t)flcobjp);
120507c3241Smlf }
121507c3241Smlf 
122507c3241Smlf static int dmult_maxcnt = DMULT_MAXCNT;
123507c3241Smlf 
124507c3241Smlf static int
125507c3241Smlf fc_init(opaque_t queuep, opaque_t tgcom_objp, opaque_t que_objp, void *lkarg)
126507c3241Smlf {
127507c3241Smlf 	struct fc_data *fcdp = (struct fc_data *)queuep;
128507c3241Smlf 
129507c3241Smlf 	mutex_init(&fcdp->ds_mutex, NULL, MUTEX_DRIVER, lkarg);
130507c3241Smlf 
131507c3241Smlf 	fcdp->ds_queobjp   = que_objp;
132507c3241Smlf 	fcdp->ds_tgcomobjp = tgcom_objp;
133507c3241Smlf 	fcdp->ds_waitcnt   = dmult_maxcnt;
134507c3241Smlf 
135507c3241Smlf 	QUE_INIT(que_objp, lkarg);
136507c3241Smlf 	TGCOM_INIT(tgcom_objp);
137507c3241Smlf 	return (DDI_SUCCESS);
138507c3241Smlf }
139507c3241Smlf 
140507c3241Smlf static int
141507c3241Smlf fc_free(struct flc_obj *flcobjp)
142507c3241Smlf {
143507c3241Smlf 	struct fc_data *fcdp;
144507c3241Smlf 
145507c3241Smlf 	fcdp = (struct fc_data *)flcobjp->flc_data;
146507c3241Smlf 	if (fcdp->ds_queobjp)
147507c3241Smlf 		QUE_FREE(fcdp->ds_queobjp);
148507c3241Smlf 	if (fcdp->ds_tgcomobjp) {
149507c3241Smlf 		TGCOM_FREE(fcdp->ds_tgcomobjp);
150507c3241Smlf 		mutex_destroy(&fcdp->ds_mutex);
151507c3241Smlf 	}
152507c3241Smlf 	kmem_free(flcobjp, (sizeof (*flcobjp) + sizeof (*fcdp)));
153507c3241Smlf 	return (0);
154507c3241Smlf }
155507c3241Smlf 
156507c3241Smlf /*ARGSUSED*/
157507c3241Smlf static int
158507c3241Smlf fc_start_kstat(opaque_t queuep, char *devtype, int instance)
159507c3241Smlf {
160507c3241Smlf 	struct fc_data *fcdp = (struct fc_data *)queuep;
161507c3241Smlf 	if (!flc_kstat)
162507c3241Smlf 		return (0);
163507c3241Smlf 
164507c3241Smlf 	if (!fcdp->ds_kstat) {
165507c3241Smlf 		if (fcdp->ds_kstat = kstat_create("cmdk", instance, NULL,
166507c3241Smlf 		    "disk", KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT)) {
167507c3241Smlf 			kstat_install(fcdp->ds_kstat);
168507c3241Smlf 		}
169507c3241Smlf 	}
170507c3241Smlf 	return (0);
171507c3241Smlf }
172507c3241Smlf 
173507c3241Smlf static int
174507c3241Smlf fc_stop_kstat(opaque_t queuep)
175507c3241Smlf {
176507c3241Smlf 	struct fc_data *fcdp = (struct fc_data *)queuep;
177507c3241Smlf 
178507c3241Smlf 	if (fcdp->ds_kstat) {
179507c3241Smlf 		kstat_delete(fcdp->ds_kstat);
180507c3241Smlf 		fcdp->ds_kstat = NULL;
181507c3241Smlf 	}
182507c3241Smlf 	return (0);
183507c3241Smlf }
184507c3241Smlf 
185507c3241Smlf 
186507c3241Smlf /*
187507c3241Smlf  *	Single Command per Device
188507c3241Smlf  */
189507c3241Smlf /*
190507c3241Smlf  * Local Function Prototypes
191507c3241Smlf  */
192507c3241Smlf static int dsngl_restart();
193507c3241Smlf 
194507c3241Smlf static int dsngl_enque(opaque_t, struct buf *);
195507c3241Smlf static int dsngl_deque(opaque_t, struct buf *);
196507c3241Smlf 
197507c3241Smlf struct 	flc_objops dsngl_ops = {
198507c3241Smlf 	fc_init,
199507c3241Smlf 	fc_free,
200507c3241Smlf 	dsngl_enque,
201507c3241Smlf 	dsngl_deque,
202507c3241Smlf 	fc_start_kstat,
203507c3241Smlf 	fc_stop_kstat,
204507c3241Smlf 	0, 0
205507c3241Smlf };
206507c3241Smlf 
207507c3241Smlf struct flc_obj *
208507c3241Smlf dsngl_create()
209507c3241Smlf {
210507c3241Smlf 	return (fc_create((struct flc_objops *)&dsngl_ops));
211507c3241Smlf }
212507c3241Smlf 
213507c3241Smlf static int
214507c3241Smlf dsngl_enque(opaque_t queuep, struct buf *in_bp)
215507c3241Smlf {
216507c3241Smlf 	struct fc_data *dsnglp = (struct fc_data *)queuep;
217507c3241Smlf 	opaque_t tgcom_objp;
218507c3241Smlf 	opaque_t que_objp;
219507c3241Smlf 
220507c3241Smlf 	que_objp   = dsnglp->ds_queobjp;
221507c3241Smlf 	tgcom_objp = dsnglp->ds_tgcomobjp;
222507c3241Smlf 
223507c3241Smlf 	if (!in_bp)
224507c3241Smlf 		return (0);
225507c3241Smlf 	mutex_enter(&dsnglp->ds_mutex);
226507c3241Smlf 	if (dsnglp->ds_bp || dsnglp->ds_outcnt) {
227507c3241Smlf 		QUE_ADD(que_objp, in_bp);
228507c3241Smlf 		if (dsnglp->ds_kstat) {
229507c3241Smlf 			kstat_waitq_enter(KSTAT_IO_PTR(dsnglp->ds_kstat));
230507c3241Smlf 		}
231507c3241Smlf 		mutex_exit(&dsnglp->ds_mutex);
232507c3241Smlf 		return (0);
233507c3241Smlf 	}
234507c3241Smlf 	if (dsnglp->ds_kstat) {
235507c3241Smlf 		kstat_waitq_enter(KSTAT_IO_PTR(dsnglp->ds_kstat));
236507c3241Smlf 	}
237507c3241Smlf 	if (TGCOM_PKT(tgcom_objp, in_bp, dsngl_restart,
238507c3241Smlf 	    (caddr_t)dsnglp) != DDI_SUCCESS) {
239507c3241Smlf 
240507c3241Smlf 		dsnglp->ds_bp = in_bp;
241507c3241Smlf 		mutex_exit(&dsnglp->ds_mutex);
242507c3241Smlf 		return (0);
243507c3241Smlf 	}
244507c3241Smlf 	dsnglp->ds_outcnt++;
245507c3241Smlf 	if (dsnglp->ds_kstat)
246507c3241Smlf 		kstat_waitq_to_runq(KSTAT_IO_PTR(dsnglp->ds_kstat));
247507c3241Smlf 	mutex_exit(&dsnglp->ds_mutex);
248507c3241Smlf 	TGCOM_TRANSPORT(tgcom_objp, in_bp);
249507c3241Smlf 	return (0);
250507c3241Smlf }
251507c3241Smlf 
252507c3241Smlf static int
253507c3241Smlf dsngl_deque(opaque_t queuep, struct buf *in_bp)
254507c3241Smlf {
255507c3241Smlf 	struct fc_data *dsnglp = (struct fc_data *)queuep;
256507c3241Smlf 	opaque_t tgcom_objp;
257507c3241Smlf 	opaque_t que_objp;
258507c3241Smlf 	struct	 buf *bp;
259507c3241Smlf 
260507c3241Smlf 	que_objp   = dsnglp->ds_queobjp;
261507c3241Smlf 	tgcom_objp = dsnglp->ds_tgcomobjp;
262507c3241Smlf 
263507c3241Smlf 	mutex_enter(&dsnglp->ds_mutex);
264507c3241Smlf 	if (in_bp) {
265507c3241Smlf 		dsnglp->ds_outcnt--;
266507c3241Smlf 		if (dsnglp->ds_kstat) {
267507c3241Smlf 			if (in_bp->b_flags & B_READ) {
268507c3241Smlf 				KSTAT_IO_PTR(dsnglp->ds_kstat)->reads++;
269507c3241Smlf 				KSTAT_IO_PTR(dsnglp->ds_kstat)->nread +=
270507c3241Smlf 				    (in_bp->b_bcount - in_bp->b_resid);
271507c3241Smlf 			} else {
272507c3241Smlf 				KSTAT_IO_PTR(dsnglp->ds_kstat)->writes++;
273507c3241Smlf 				KSTAT_IO_PTR(dsnglp->ds_kstat)->nwritten +=
274507c3241Smlf 				    (in_bp->b_bcount - in_bp->b_resid);
275507c3241Smlf 			}
276507c3241Smlf 			kstat_runq_exit(KSTAT_IO_PTR(dsnglp->ds_kstat));
277507c3241Smlf 		}
278507c3241Smlf 	}
279507c3241Smlf 	for (;;) {
280507c3241Smlf 		if (!dsnglp->ds_bp)
281507c3241Smlf 			dsnglp->ds_bp = QUE_DEL(que_objp);
282507c3241Smlf 		if (!dsnglp->ds_bp ||
283507c3241Smlf 		    (TGCOM_PKT(tgcom_objp, dsnglp->ds_bp, dsngl_restart,
284507c3241Smlf 		    (caddr_t)dsnglp) != DDI_SUCCESS) ||
285507c3241Smlf 		    dsnglp->ds_outcnt) {
286507c3241Smlf 			mutex_exit(&dsnglp->ds_mutex);
287507c3241Smlf 			return (0);
288507c3241Smlf 		}
289507c3241Smlf 		dsnglp->ds_outcnt++;
290507c3241Smlf 		bp = dsnglp->ds_bp;
291507c3241Smlf 		dsnglp->ds_bp = QUE_DEL(que_objp);
292507c3241Smlf 		if (dsnglp->ds_kstat)
293507c3241Smlf 			kstat_waitq_to_runq(KSTAT_IO_PTR(dsnglp->ds_kstat));
294507c3241Smlf 		mutex_exit(&dsnglp->ds_mutex);
295507c3241Smlf 
296507c3241Smlf 		TGCOM_TRANSPORT(tgcom_objp, bp);
297507c3241Smlf 
298507c3241Smlf 		if (!mutex_tryenter(&dsnglp->ds_mutex))
299507c3241Smlf 			return (0);
300507c3241Smlf 	}
301507c3241Smlf }
302507c3241Smlf 
303507c3241Smlf static int
304507c3241Smlf dsngl_restart(struct fc_data *dsnglp)
305507c3241Smlf {
306507c3241Smlf 	(void) dsngl_deque(dsnglp, NULL);
307507c3241Smlf 	return (-1);
308507c3241Smlf }
309507c3241Smlf 
310507c3241Smlf 
311507c3241Smlf /*
312507c3241Smlf  *	Multiple Commands per Device
313507c3241Smlf  */
314507c3241Smlf /*
315507c3241Smlf  * Local Function Prototypes
316507c3241Smlf  */
317507c3241Smlf static int dmult_restart();
318507c3241Smlf 
319507c3241Smlf static int dmult_enque(opaque_t, struct buf *);
320507c3241Smlf static int dmult_deque(opaque_t, struct buf *);
321507c3241Smlf 
322507c3241Smlf struct 	flc_objops dmult_ops = {
323507c3241Smlf 	fc_init,
324507c3241Smlf 	fc_free,
325507c3241Smlf 	dmult_enque,
326507c3241Smlf 	dmult_deque,
327507c3241Smlf 	fc_start_kstat,
328507c3241Smlf 	fc_stop_kstat,
329507c3241Smlf 	0, 0
330507c3241Smlf };
331507c3241Smlf 
332507c3241Smlf struct flc_obj *
333507c3241Smlf dmult_create()
334507c3241Smlf {
335507c3241Smlf 	return (fc_create((struct flc_objops *)&dmult_ops));
336507c3241Smlf 
337507c3241Smlf }
338507c3241Smlf 
339507c3241Smlf 
340507c3241Smlf /*
341507c3241Smlf  * Some of the object management functions QUE_ADD() and QUE_DEL()
342507c3241Smlf  * do not accquire lock.
343507c3241Smlf  * They depend on dmult_enque(), dmult_deque() to do all locking.
344507c3241Smlf  * If this changes we have to grab locks in qmerge_add() and qmerge_del().
345507c3241Smlf  */
346507c3241Smlf static int
347507c3241Smlf dmult_enque(opaque_t queuep, struct buf *in_bp)
348507c3241Smlf {
349507c3241Smlf 	struct fc_data *dmultp = (struct fc_data *)queuep;
350507c3241Smlf 	opaque_t tgcom_objp;
351507c3241Smlf 	opaque_t que_objp;
352507c3241Smlf 
353507c3241Smlf 	que_objp   = dmultp->ds_queobjp;
354507c3241Smlf 	tgcom_objp = dmultp->ds_tgcomobjp;
355507c3241Smlf 
356507c3241Smlf 	if (!in_bp)
357507c3241Smlf 		return (0);
358507c3241Smlf 	mutex_enter(&dmultp->ds_mutex);
359507c3241Smlf 	if ((dmultp->ds_outcnt >= dmultp->ds_waitcnt) || dmultp->ds_bp) {
360507c3241Smlf 		QUE_ADD(que_objp, in_bp);
361507c3241Smlf 		if (dmultp->ds_kstat) {
362507c3241Smlf 			kstat_waitq_enter(KSTAT_IO_PTR(dmultp->ds_kstat));
363507c3241Smlf 		}
364507c3241Smlf 		mutex_exit(&dmultp->ds_mutex);
365507c3241Smlf 		return (0);
366507c3241Smlf 	}
367507c3241Smlf 	if (dmultp->ds_kstat) {
368507c3241Smlf 		kstat_waitq_enter(KSTAT_IO_PTR(dmultp->ds_kstat));
369507c3241Smlf 	}
370507c3241Smlf 
371507c3241Smlf 	if (TGCOM_PKT(tgcom_objp, in_bp, dmult_restart,
372507c3241Smlf 	    (caddr_t)dmultp) != DDI_SUCCESS) {
373507c3241Smlf 
374507c3241Smlf 		dmultp->ds_bp = in_bp;
375507c3241Smlf 		mutex_exit(&dmultp->ds_mutex);
376507c3241Smlf 		return (0);
377507c3241Smlf 	}
378507c3241Smlf 	dmultp->ds_outcnt++;
379507c3241Smlf 	if (dmultp->ds_kstat)
380507c3241Smlf 		kstat_waitq_to_runq(KSTAT_IO_PTR(dmultp->ds_kstat));
381507c3241Smlf 	mutex_exit(&dmultp->ds_mutex);
382507c3241Smlf 
383507c3241Smlf 	TGCOM_TRANSPORT(tgcom_objp, in_bp);
384507c3241Smlf 	return (0);
385507c3241Smlf }
386507c3241Smlf 
387507c3241Smlf static int
388507c3241Smlf dmult_deque(opaque_t queuep, struct buf *in_bp)
389507c3241Smlf {
390507c3241Smlf 	struct fc_data *dmultp = (struct fc_data *)queuep;
391507c3241Smlf 	opaque_t tgcom_objp;
392507c3241Smlf 	opaque_t que_objp;
393507c3241Smlf 	struct	 buf *bp;
394507c3241Smlf 
395507c3241Smlf 	que_objp = dmultp->ds_queobjp;
396507c3241Smlf 	tgcom_objp = dmultp->ds_tgcomobjp;
397507c3241Smlf 
398507c3241Smlf 	mutex_enter(&dmultp->ds_mutex);
399507c3241Smlf 	if (in_bp) {
400507c3241Smlf 		dmultp->ds_outcnt--;
401507c3241Smlf 		if (dmultp->ds_kstat) {
402507c3241Smlf 			if (in_bp->b_flags & B_READ) {
403507c3241Smlf 				KSTAT_IO_PTR(dmultp->ds_kstat)->reads++;
404507c3241Smlf 				KSTAT_IO_PTR(dmultp->ds_kstat)->nread +=
405507c3241Smlf 				    (in_bp->b_bcount - in_bp->b_resid);
406507c3241Smlf 			} else {
407507c3241Smlf 				KSTAT_IO_PTR(dmultp->ds_kstat)->writes++;
408507c3241Smlf 				KSTAT_IO_PTR(dmultp->ds_kstat)->nwritten +=
409507c3241Smlf 				    (in_bp->b_bcount - in_bp->b_resid);
410507c3241Smlf 			}
411507c3241Smlf 			kstat_runq_exit(KSTAT_IO_PTR(dmultp->ds_kstat));
412507c3241Smlf 		}
413507c3241Smlf 	}
414507c3241Smlf 
415507c3241Smlf 	for (;;) {
416507c3241Smlf 
417507c3241Smlf #ifdef	FLC_DEBUG
418507c3241Smlf 		if ((curthread->t_intr) && (!dmultp->ds_bp) &&
419507c3241Smlf 		    (!dmultp->ds_outcnt))
420507c3241Smlf 			flc_malloc_intr++;
421507c3241Smlf #endif
422507c3241Smlf 
423507c3241Smlf 		if (!dmultp->ds_bp)
424507c3241Smlf 			dmultp->ds_bp = QUE_DEL(que_objp);
425507c3241Smlf 		if (!dmultp->ds_bp ||
426507c3241Smlf 		    (TGCOM_PKT(tgcom_objp, dmultp->ds_bp, dmult_restart,
427507c3241Smlf 		    (caddr_t)dmultp) != DDI_SUCCESS) ||
428507c3241Smlf 		    (dmultp->ds_outcnt >= dmultp->ds_waitcnt)) {
429507c3241Smlf 			mutex_exit(&dmultp->ds_mutex);
430507c3241Smlf 			return (0);
431507c3241Smlf 		}
432507c3241Smlf 		dmultp->ds_outcnt++;
433507c3241Smlf 		bp = dmultp->ds_bp;
434507c3241Smlf 		dmultp->ds_bp = QUE_DEL(que_objp);
435507c3241Smlf 
436507c3241Smlf 		if (dmultp->ds_kstat)
437507c3241Smlf 			kstat_waitq_to_runq(KSTAT_IO_PTR(dmultp->ds_kstat));
438507c3241Smlf 
439507c3241Smlf 		mutex_exit(&dmultp->ds_mutex);
440507c3241Smlf 
441507c3241Smlf 		TGCOM_TRANSPORT(tgcom_objp, bp);
442507c3241Smlf 
443507c3241Smlf 		if (!mutex_tryenter(&dmultp->ds_mutex))
444507c3241Smlf 			return (0);
445507c3241Smlf 	}
446507c3241Smlf }
447507c3241Smlf 
448507c3241Smlf static int
449507c3241Smlf dmult_restart(struct fc_data *dmultp)
450507c3241Smlf {
451507c3241Smlf 	(void) dmult_deque(dmultp, NULL);
452507c3241Smlf 	return (-1);
453507c3241Smlf }
454507c3241Smlf 
455507c3241Smlf /*
456507c3241Smlf  *	Duplexed Commands per Device: Read Queue and Write Queue
457507c3241Smlf  */
458507c3241Smlf /*
459507c3241Smlf  * Local Function Prototypes
460507c3241Smlf  */
461507c3241Smlf static int duplx_restart();
462507c3241Smlf 
463507c3241Smlf static int duplx_init(opaque_t queuep, opaque_t tgcom_objp, opaque_t que_objp,
464507c3241Smlf     void *lkarg);
465507c3241Smlf static int duplx_free(struct flc_obj *flcobjp);
466507c3241Smlf static int duplx_enque(opaque_t queuep, struct buf *bp);
467507c3241Smlf static int duplx_deque(opaque_t queuep, struct buf *bp);
468507c3241Smlf 
469507c3241Smlf struct 	flc_objops duplx_ops = {
470507c3241Smlf 	duplx_init,
471507c3241Smlf 	duplx_free,
472507c3241Smlf 	duplx_enque,
473507c3241Smlf 	duplx_deque,
474507c3241Smlf 	fc_start_kstat,
475507c3241Smlf 	fc_stop_kstat,
476507c3241Smlf 	0, 0
477507c3241Smlf };
478507c3241Smlf 
479507c3241Smlf struct flc_obj *
480507c3241Smlf duplx_create()
481507c3241Smlf {
482507c3241Smlf 	struct	flc_obj *flcobjp;
483507c3241Smlf 	struct	duplx_data *fcdp;
484507c3241Smlf 
485507c3241Smlf 	flcobjp = kmem_zalloc((sizeof (*flcobjp) + sizeof (*fcdp)), KM_NOSLEEP);
486507c3241Smlf 	if (!flcobjp)
487507c3241Smlf 		return (NULL);
488507c3241Smlf 
489507c3241Smlf 	fcdp = (struct duplx_data *)(flcobjp+1);
490507c3241Smlf 	flcobjp->flc_data = (opaque_t)fcdp;
491507c3241Smlf 	flcobjp->flc_ops  = &duplx_ops;
492507c3241Smlf 
493507c3241Smlf 	fcdp->ds_writeq.fc_qobjp = qfifo_create();
494507c3241Smlf 	if (!(fcdp->ds_writeq.fc_qobjp = qfifo_create())) {
495507c3241Smlf 		kmem_free(flcobjp, (sizeof (*flcobjp) + sizeof (*fcdp)));
496507c3241Smlf 		return (NULL);
497507c3241Smlf 	}
498507c3241Smlf 	return (flcobjp);
499507c3241Smlf }
500507c3241Smlf 
501507c3241Smlf static int
502507c3241Smlf duplx_free(struct flc_obj *flcobjp)
503507c3241Smlf {
504507c3241Smlf 	struct duplx_data *fcdp;
505507c3241Smlf 
506507c3241Smlf 	fcdp = (struct duplx_data *)flcobjp->flc_data;
507507c3241Smlf 	if (fcdp->ds_writeq.fc_qobjp) {
508507c3241Smlf 		QUE_FREE(fcdp->ds_writeq.fc_qobjp);
509507c3241Smlf 	}
510507c3241Smlf 	if (fcdp->ds_readq.fc_qobjp)
511507c3241Smlf 		QUE_FREE(fcdp->ds_readq.fc_qobjp);
512507c3241Smlf 	if (fcdp->ds_tgcomobjp) {
513507c3241Smlf 		TGCOM_FREE(fcdp->ds_tgcomobjp);
514507c3241Smlf 		mutex_destroy(&fcdp->ds_mutex);
515507c3241Smlf 	}
516507c3241Smlf 	kmem_free(flcobjp, (sizeof (*flcobjp) + sizeof (*fcdp)));
517507c3241Smlf 	return (0);
518507c3241Smlf }
519507c3241Smlf 
520507c3241Smlf static int
521507c3241Smlf duplx_init(opaque_t queuep, opaque_t tgcom_objp, opaque_t que_objp, void *lkarg)
522507c3241Smlf {
523507c3241Smlf 	struct duplx_data *fcdp = (struct duplx_data *)queuep;
524507c3241Smlf 	fcdp->ds_tgcomobjp = tgcom_objp;
525507c3241Smlf 	fcdp->ds_readq.fc_qobjp = que_objp;
526507c3241Smlf 
527507c3241Smlf 	QUE_INIT(que_objp, lkarg);
528507c3241Smlf 	QUE_INIT(fcdp->ds_writeq.fc_qobjp, lkarg);
529507c3241Smlf 	TGCOM_INIT(tgcom_objp);
530507c3241Smlf 
531507c3241Smlf 	mutex_init(&fcdp->ds_mutex, NULL, MUTEX_DRIVER, lkarg);
532507c3241Smlf 
533507c3241Smlf 	fcdp->ds_writeq.fc_maxcnt = DUPLX_MAXCNT;
534507c3241Smlf 	fcdp->ds_readq.fc_maxcnt  = DUPLX_MAXCNT;
535507c3241Smlf 
536507c3241Smlf 	/* queues point to each other for round robin */
537507c3241Smlf 	fcdp->ds_readq.next = &fcdp->ds_writeq;
538507c3241Smlf 	fcdp->ds_writeq.next = &fcdp->ds_readq;
539507c3241Smlf 
540507c3241Smlf 	return (DDI_SUCCESS);
541507c3241Smlf }
542507c3241Smlf 
543507c3241Smlf static int
544507c3241Smlf duplx_enque(opaque_t queuep, struct buf *in_bp)
545507c3241Smlf {
546507c3241Smlf 	struct duplx_data *duplxp = (struct duplx_data *)queuep;
547507c3241Smlf 	opaque_t tgcom_objp;
548507c3241Smlf 	struct fc_que *activeq;
549507c3241Smlf 	struct buf *bp;
550507c3241Smlf 
551507c3241Smlf 	mutex_enter(&duplxp->ds_mutex);
552507c3241Smlf 	if (in_bp) {
553507c3241Smlf 		if (duplxp->ds_kstat) {
554507c3241Smlf 			kstat_waitq_enter(KSTAT_IO_PTR(duplxp->ds_kstat));
555507c3241Smlf 		}
556507c3241Smlf 		if (in_bp->b_flags & B_READ)
557507c3241Smlf 			activeq = &duplxp->ds_readq;
558507c3241Smlf 		else
559507c3241Smlf 			activeq = &duplxp->ds_writeq;
560507c3241Smlf 
561507c3241Smlf 		QUE_ADD(activeq->fc_qobjp, in_bp);
562507c3241Smlf 	} else {
563507c3241Smlf 		activeq = &duplxp->ds_readq;
564507c3241Smlf 	}
565507c3241Smlf 
566507c3241Smlf 	tgcom_objp = duplxp->ds_tgcomobjp;
567507c3241Smlf 
568507c3241Smlf 	for (;;) {
569507c3241Smlf 		if (!activeq->fc_bp)
570507c3241Smlf 			activeq->fc_bp = QUE_DEL(activeq->fc_qobjp);
571507c3241Smlf 		if (!activeq->fc_bp ||
572507c3241Smlf 		    (TGCOM_PKT(tgcom_objp, activeq->fc_bp, duplx_restart,
573507c3241Smlf 		    (caddr_t)duplxp) != DDI_SUCCESS) ||
574507c3241Smlf 		    (activeq->fc_outcnt >= activeq->fc_maxcnt)) {
575507c3241Smlf 
576507c3241Smlf 			/* switch read/write queues */
577507c3241Smlf 			activeq = activeq->next;
578507c3241Smlf 			if (!activeq->fc_bp)
579507c3241Smlf 				activeq->fc_bp = QUE_DEL(activeq->fc_qobjp);
580507c3241Smlf 			if (!activeq->fc_bp ||
581507c3241Smlf 			    (TGCOM_PKT(tgcom_objp, activeq->fc_bp,
582507c3241Smlf 			    duplx_restart, (caddr_t)duplxp) != DDI_SUCCESS) ||
583507c3241Smlf 			    (activeq->fc_outcnt >= activeq->fc_maxcnt)) {
584507c3241Smlf 				mutex_exit(&duplxp->ds_mutex);
585507c3241Smlf 				return (0);
586507c3241Smlf 			}
587507c3241Smlf 		}
588507c3241Smlf 
589507c3241Smlf 		activeq->fc_outcnt++;
590507c3241Smlf 		bp = activeq->fc_bp;
591507c3241Smlf 		activeq->fc_bp = NULL;
592507c3241Smlf 
593507c3241Smlf 		if (duplxp->ds_kstat)
594507c3241Smlf 			kstat_waitq_to_runq(KSTAT_IO_PTR(duplxp->ds_kstat));
595507c3241Smlf 		mutex_exit(&duplxp->ds_mutex);
596507c3241Smlf 
597507c3241Smlf 		TGCOM_TRANSPORT(tgcom_objp, bp);
598507c3241Smlf 
599507c3241Smlf 		if (!mutex_tryenter(&duplxp->ds_mutex))
600507c3241Smlf 			return (0);
601507c3241Smlf 
602507c3241Smlf 		activeq = activeq->next;
603507c3241Smlf 	}
604507c3241Smlf }
605507c3241Smlf 
606507c3241Smlf static int
607507c3241Smlf duplx_deque(opaque_t queuep, struct buf *in_bp)
608507c3241Smlf {
609507c3241Smlf 	struct duplx_data *duplxp = (struct duplx_data *)queuep;
610507c3241Smlf 	opaque_t tgcom_objp;
611507c3241Smlf 	struct fc_que *activeq;
612507c3241Smlf 	struct buf *bp;
613507c3241Smlf 
614507c3241Smlf 	mutex_enter(&duplxp->ds_mutex);
615507c3241Smlf 
616507c3241Smlf 	tgcom_objp = duplxp->ds_tgcomobjp;
617507c3241Smlf 
618507c3241Smlf 	if (in_bp->b_flags & B_READ)
619507c3241Smlf 		activeq = &duplxp->ds_readq;
620507c3241Smlf 	else
621507c3241Smlf 		activeq = &duplxp->ds_writeq;
622507c3241Smlf 	activeq->fc_outcnt--;
623507c3241Smlf 
624507c3241Smlf 	if (duplxp->ds_kstat) {
625507c3241Smlf 		if (in_bp->b_flags & B_READ) {
626507c3241Smlf 			KSTAT_IO_PTR(duplxp->ds_kstat)->reads++;
627507c3241Smlf 			KSTAT_IO_PTR(duplxp->ds_kstat)->nread +=
628507c3241Smlf 			    (in_bp->b_bcount - in_bp->b_resid);
629507c3241Smlf 		} else {
630507c3241Smlf 			KSTAT_IO_PTR(duplxp->ds_kstat)->writes++;
631507c3241Smlf 			KSTAT_IO_PTR(duplxp->ds_kstat)->nwritten +=
632507c3241Smlf 			    (in_bp->b_bcount - in_bp->b_resid);
633507c3241Smlf 		}
634507c3241Smlf 		kstat_runq_exit(KSTAT_IO_PTR(duplxp->ds_kstat));
635507c3241Smlf 	}
636507c3241Smlf 
637507c3241Smlf 	for (;;) {
638507c3241Smlf 
639507c3241Smlf 		/* if needed, try to pull request off a queue */
640507c3241Smlf 		if (!activeq->fc_bp)
641507c3241Smlf 			activeq->fc_bp = QUE_DEL(activeq->fc_qobjp);
642507c3241Smlf 
643507c3241Smlf 		if (!activeq->fc_bp ||
644507c3241Smlf 		    (TGCOM_PKT(tgcom_objp, activeq->fc_bp, duplx_restart,
645507c3241Smlf 		    (caddr_t)duplxp) != DDI_SUCCESS) ||
646507c3241Smlf 		    (activeq->fc_outcnt >= activeq->fc_maxcnt)) {
647507c3241Smlf 
648507c3241Smlf 			activeq = activeq->next;
649507c3241Smlf 			if (!activeq->fc_bp)
650507c3241Smlf 				activeq->fc_bp = QUE_DEL(activeq->fc_qobjp);
651507c3241Smlf 
652507c3241Smlf 			if (!activeq->fc_bp ||
653507c3241Smlf 			    (TGCOM_PKT(tgcom_objp, activeq->fc_bp,
654507c3241Smlf 			    duplx_restart, (caddr_t)duplxp) != DDI_SUCCESS) ||
655507c3241Smlf 			    (activeq->fc_outcnt >= activeq->fc_maxcnt)) {
656507c3241Smlf 				mutex_exit(&duplxp->ds_mutex);
657507c3241Smlf 				return (0);
658507c3241Smlf 			}
659507c3241Smlf 		}
660507c3241Smlf 
661507c3241Smlf 		activeq->fc_outcnt++;
662507c3241Smlf 		bp = activeq->fc_bp;
663507c3241Smlf 		activeq->fc_bp = NULL;
664507c3241Smlf 
665507c3241Smlf 		if (duplxp->ds_kstat)
666507c3241Smlf 			kstat_waitq_to_runq(KSTAT_IO_PTR(duplxp->ds_kstat));
667507c3241Smlf 
668507c3241Smlf 		mutex_exit(&duplxp->ds_mutex);
669507c3241Smlf 
670507c3241Smlf 		TGCOM_TRANSPORT(tgcom_objp, bp);
671507c3241Smlf 
672507c3241Smlf 		if (!mutex_tryenter(&duplxp->ds_mutex))
673507c3241Smlf 			return (0);
674507c3241Smlf 
675507c3241Smlf 		activeq = activeq->next;
676507c3241Smlf 	}
677507c3241Smlf }
678507c3241Smlf 
679507c3241Smlf static int
680507c3241Smlf duplx_restart(struct duplx_data *duplxp)
681507c3241Smlf {
682507c3241Smlf 	(void) duplx_enque(duplxp, NULL);
683507c3241Smlf 	return (-1);
684507c3241Smlf }
685507c3241Smlf 
686507c3241Smlf /*
687507c3241Smlf  *	Tagged queueing flow control
688507c3241Smlf  */
689507c3241Smlf /*
690507c3241Smlf  * Local Function Prototypes
691507c3241Smlf  */
692507c3241Smlf 
693507c3241Smlf struct 	flc_objops adapt_ops = {
694507c3241Smlf 	fc_init,
695507c3241Smlf 	fc_free,
696507c3241Smlf 	dmult_enque,
697507c3241Smlf 	dmult_deque,
698507c3241Smlf 	fc_start_kstat,
699507c3241Smlf 	fc_stop_kstat,
700507c3241Smlf 	0, 0
701507c3241Smlf };
702507c3241Smlf 
703507c3241Smlf struct flc_obj *
704507c3241Smlf adapt_create()
705507c3241Smlf {
706507c3241Smlf 	return (fc_create((struct flc_objops *)&adapt_ops));
707507c3241Smlf 
708507c3241Smlf }
709507c3241Smlf 
710507c3241Smlf /*
711507c3241Smlf  *	Common Queue functions
712507c3241Smlf  */
713507c3241Smlf 
714507c3241Smlf /*
715507c3241Smlf  * 	Local static data
716507c3241Smlf  */
717507c3241Smlf #ifdef	Q_DEBUG
718507c3241Smlf #define	DENT	0x0001
719507c3241Smlf #define	DERR	0x0002
720507c3241Smlf #define	DIO	0x0004
721507c3241Smlf static	int	que_debug = DENT|DERR|DIO;
722507c3241Smlf 
723507c3241Smlf #endif	/* Q_DEBUG */
724507c3241Smlf /*
725507c3241Smlf  * 	Local Function Prototypes
726507c3241Smlf  */
727507c3241Smlf static struct que_obj *que_create(struct que_objops *qopsp);
728507c3241Smlf static int que_init(struct que_data *qfp, void *lkarg);
729507c3241Smlf static int que_free(struct que_obj *queobjp);
730507c3241Smlf static struct buf *que_del(struct que_data *qfp);
731507c3241Smlf 
732507c3241Smlf static struct que_obj *
733507c3241Smlf que_create(struct que_objops *qopsp)
734507c3241Smlf {
735507c3241Smlf 	struct	que_data *qfp;
736507c3241Smlf 	struct	que_obj *queobjp;
737507c3241Smlf 
738507c3241Smlf 	queobjp = kmem_zalloc((sizeof (*queobjp) + sizeof (*qfp)), KM_NOSLEEP);
739507c3241Smlf 	if (!queobjp)
740507c3241Smlf 		return (NULL);
741507c3241Smlf 
742507c3241Smlf 	queobjp->que_ops = qopsp;
743507c3241Smlf 	qfp = (struct que_data *)(queobjp+1);
744507c3241Smlf 	queobjp->que_data = (opaque_t)qfp;
745507c3241Smlf 
746507c3241Smlf 	return ((opaque_t)queobjp);
747507c3241Smlf }
748507c3241Smlf 
749507c3241Smlf static int
750507c3241Smlf que_init(struct que_data *qfp, void *lkarg)
751507c3241Smlf {
752507c3241Smlf 	mutex_init(&qfp->q_mutex, NULL, MUTEX_DRIVER, lkarg);
753507c3241Smlf 	return (DDI_SUCCESS);
754507c3241Smlf }
755507c3241Smlf 
756507c3241Smlf static int
757507c3241Smlf que_free(struct que_obj *queobjp)
758507c3241Smlf {
759507c3241Smlf 	struct	que_data *qfp;
760507c3241Smlf 
761507c3241Smlf 	qfp = (struct que_data *)queobjp->que_data;
762507c3241Smlf 	mutex_destroy(&qfp->q_mutex);
763507c3241Smlf 	kmem_free(queobjp, (sizeof (*queobjp) + sizeof (struct que_data)));
764507c3241Smlf 	return (0);
765507c3241Smlf }
766507c3241Smlf 
767507c3241Smlf static struct buf *
768507c3241Smlf que_del(struct que_data *qfp)
769507c3241Smlf {
770507c3241Smlf 	struct buf *bp;
771507c3241Smlf 
772507c3241Smlf 	bp = qfp->q_tab.b_actf;
773507c3241Smlf 	if (bp) {
774507c3241Smlf 		qfp->q_tab.b_actf = bp->av_forw;
775507c3241Smlf 		if (!qfp->q_tab.b_actf)
776507c3241Smlf 			qfp->q_tab.b_actl = NULL;
777507c3241Smlf 		bp->av_forw = 0;
778507c3241Smlf 	}
779507c3241Smlf 	return (bp);
780507c3241Smlf }
781507c3241Smlf 
782507c3241Smlf 
783507c3241Smlf 
784507c3241Smlf /*
785507c3241Smlf  *	Qmerge
786507c3241Smlf  * 	Local Function Prototypes
787507c3241Smlf  */
788507c3241Smlf static int qmerge_add(), qmerge_free();
789507c3241Smlf static struct buf *qmerge_del(struct que_data *qfp);
790507c3241Smlf 
791507c3241Smlf struct 	que_objops qmerge_ops = {
792507c3241Smlf 	que_init,
793507c3241Smlf 	qmerge_free,
794507c3241Smlf 	qmerge_add,
795507c3241Smlf 	qmerge_del,
796507c3241Smlf 	0, 0
797507c3241Smlf };
798507c3241Smlf 
799507c3241Smlf /* fields in diskhd */
800507c3241Smlf #define	hd_cnt			b_back
801507c3241Smlf #define	hd_private		b_forw
802507c3241Smlf #define	hd_flags		b_flags
803507c3241Smlf #define	hd_sync_next		av_forw
804507c3241Smlf #define	hd_async_next		av_back
805507c3241Smlf 
806507c3241Smlf #define	hd_sync2async		sync_async_ratio
807507c3241Smlf 
808507c3241Smlf #define	QNEAR_FORWARD		0x01
809507c3241Smlf #define	QNEAR_BACKWARD		0x02
810507c3241Smlf #define	QNEAR_ASYNCONLY		0x04
811507c3241Smlf #define	QNEAR_ASYNCALSO		0x08
812507c3241Smlf 
813507c3241Smlf #define	DBLK(bp) ((unsigned long)(bp)->b_private)
814507c3241Smlf 
815507c3241Smlf #define	BP_LT_BP(a, b) (DBLK(a) < DBLK(b))
816507c3241Smlf #define	BP_GT_BP(a, b) (DBLK(a) > DBLK(b))
817507c3241Smlf #define	BP_LT_HD(a, b) (DBLK(a) < (unsigned long)((b)->hd_private))
818507c3241Smlf #define	BP_GT_HD(a, b) (DBLK(a) > (unsigned long)((b)->hd_private))
819507c3241Smlf #define	QNEAR_ASYNC	(QNEAR_ASYNCONLY|QNEAR_ASYNCALSO)
820507c3241Smlf 
821507c3241Smlf #define	SYNC2ASYNC(a) ((a)->q_tab.hd_cnt)
822507c3241Smlf 
823507c3241Smlf 
824507c3241Smlf /*
825507c3241Smlf  * qmerge implements a two priority queue, the low priority queue holding ASYNC
826507c3241Smlf  * write requests, while the rest are queued in the high priority sync queue.
827507c3241Smlf  * Requests on the async queue would be merged if possible.
828507c3241Smlf  * By default qmerge2wayscan is 1, indicating an elevator algorithm. When
829507c3241Smlf  * this variable is set to zero, it has the following side effects.
830507c3241Smlf  * 1. We assume fairness is the number one issue.
831507c3241Smlf  * 2. The next request to be picked indicates current head position.
832507c3241Smlf  *
833507c3241Smlf  * qmerge_sync2async indicates the ratio of scans of high prioriy
834507c3241Smlf  * sync queue to low priority async queue.
835507c3241Smlf  *
836507c3241Smlf  * When qmerge variables have the following values it defaults to qsort
837507c3241Smlf  *
838507c3241Smlf  * qmerge1pri = 1, qmerge2wayscan = 0, qmerge_max_merge = 0
839507c3241Smlf  *
840507c3241Smlf  */
841507c3241Smlf static int	qmerge_max_merge = 128 * 1024;
842507c3241Smlf static intptr_t	qmerge_sync2async = 4;
843507c3241Smlf static int	qmerge2wayscan = 1;
844507c3241Smlf static int	qmerge1pri = 0;
845507c3241Smlf static int	qmerge_merge = 0;
846507c3241Smlf 
847507c3241Smlf /*
848507c3241Smlf  * 	Local static data
849507c3241Smlf  */
850507c3241Smlf struct que_obj *
851507c3241Smlf qmerge_create()
852507c3241Smlf {
853507c3241Smlf 	struct que_data *qfp;
854507c3241Smlf 	struct que_obj *queobjp;
855507c3241Smlf 
856507c3241Smlf 	queobjp = kmem_zalloc((sizeof (*queobjp) + sizeof (*qfp)), KM_NOSLEEP);
857507c3241Smlf 	if (!queobjp)
858507c3241Smlf 		return (NULL);
859507c3241Smlf 
860507c3241Smlf 	queobjp->que_ops = &qmerge_ops;
861507c3241Smlf 	qfp = (struct que_data *)(queobjp+1);
862*2bc98732SRichard Lowe 	qfp->q_tab.hd_private = 0;
863507c3241Smlf 	qfp->q_tab.hd_sync_next = qfp->q_tab.hd_async_next = NULL;
864507c3241Smlf 	qfp->q_tab.hd_cnt = (void *)qmerge_sync2async;
865507c3241Smlf 	queobjp->que_data = (opaque_t)qfp;
866507c3241Smlf 
867507c3241Smlf 	return ((opaque_t)queobjp);
868507c3241Smlf }
869507c3241Smlf 
870507c3241Smlf static int
871507c3241Smlf qmerge_free(struct que_obj *queobjp)
872507c3241Smlf {
873507c3241Smlf 	struct	que_data *qfp;
874507c3241Smlf 
875507c3241Smlf 	qfp = (struct que_data *)queobjp->que_data;
876507c3241Smlf 	mutex_destroy(&qfp->q_mutex);
877507c3241Smlf 	kmem_free(queobjp, (sizeof (*queobjp) + sizeof (*qfp)));
878507c3241Smlf 	return (0);
879507c3241Smlf }
880507c3241Smlf 
881507c3241Smlf static int
882507c3241Smlf qmerge_can_merge(bp1, bp2)
883507c3241Smlf struct	buf *bp1, *bp2;
884507c3241Smlf {
885507c3241Smlf 	const int paw_flags = B_PAGEIO | B_ASYNC | B_WRITE;
886507c3241Smlf 
887507c3241Smlf 	if ((bp1->b_un.b_addr != 0) || (bp2->b_un.b_addr != 0) ||
888507c3241Smlf 	    ((bp1->b_flags & (paw_flags | B_REMAPPED)) != paw_flags) ||
889507c3241Smlf 	    ((bp2->b_flags & (paw_flags | B_REMAPPED)) != paw_flags) ||
890507c3241Smlf 	    (bp1->b_bcount & PAGEOFFSET) || (bp2->b_bcount & PAGEOFFSET) ||
891507c3241Smlf 	    (bp1->b_bcount + bp2->b_bcount > qmerge_max_merge))
892507c3241Smlf 		return (0);
893507c3241Smlf 
894507c3241Smlf 	if ((DBLK(bp2) + bp2->b_bcount / DEV_BSIZE == DBLK(bp1)) ||
895507c3241Smlf 	    (DBLK(bp1) + bp1->b_bcount / DEV_BSIZE == DBLK(bp2)))
896507c3241Smlf 		return (1);
897507c3241Smlf 	else
898507c3241Smlf 		return (0);
899507c3241Smlf }
900507c3241Smlf 
901507c3241Smlf static void
902507c3241Smlf qmerge_mergesetup(bp_merge, bp)
903507c3241Smlf struct	buf *bp_merge, *bp;
904507c3241Smlf {
905507c3241Smlf 	struct	buf *bp1;
906507c3241Smlf 	struct	page *pp, *pp_merge, *pp_merge_prev;
907507c3241Smlf 	int	forward;
908507c3241Smlf 
909507c3241Smlf 	qmerge_merge++;
910507c3241Smlf 	forward = DBLK(bp_merge) < DBLK(bp);
911507c3241Smlf 
912507c3241Smlf 	bp_merge->b_bcount += bp->b_bcount;
913507c3241Smlf 
914507c3241Smlf 	pp = bp->b_pages;
915507c3241Smlf 	pp_merge = bp_merge->b_pages;
916507c3241Smlf 
917507c3241Smlf 	pp_merge_prev = pp_merge->p_prev;
918507c3241Smlf 
919507c3241Smlf 	pp_merge->p_prev->p_next = pp;
920507c3241Smlf 	pp_merge->p_prev = pp->p_prev;
921507c3241Smlf 	pp->p_prev->p_next = pp_merge;
922507c3241Smlf 	pp->p_prev = pp_merge_prev;
923507c3241Smlf 
924507c3241Smlf 	bp1 = bp_merge->b_forw;
925507c3241Smlf 
926507c3241Smlf 	bp1->av_back->av_forw = bp;
927507c3241Smlf 	bp->av_back = bp1->av_back;
928507c3241Smlf 	bp1->av_back = bp;
929507c3241Smlf 	bp->av_forw = bp1;
930507c3241Smlf 
931507c3241Smlf 	if (!forward) {
932507c3241Smlf 		bp_merge->b_forw = bp;
933507c3241Smlf 		bp_merge->b_pages = pp;
934507c3241Smlf 		bp_merge->b_private = bp->b_private;
935507c3241Smlf 	}
936507c3241Smlf }
937507c3241Smlf 
938507c3241Smlf static void
939507c3241Smlf que_insert(struct que_data *qfp, struct buf *bp)
940507c3241Smlf {
941507c3241Smlf 	struct buf	*bp1, *bp_start, *lowest_bp, *highest_bp;
942507c3241Smlf 	uintptr_t	highest_blk, lowest_blk;
943507c3241Smlf 	struct buf	**async_bpp, **sync_bpp, **bpp;
944507c3241Smlf 	struct diskhd	*dp = &qfp->q_tab;
945507c3241Smlf 
946507c3241Smlf 	sync_bpp = &dp->hd_sync_next;
947507c3241Smlf 	async_bpp = &dp->hd_async_next;
948507c3241Smlf 	/*
949507c3241Smlf 	 * The ioctl used by the format utility requires that bp->av_back be
950507c3241Smlf 	 * preserved.
951507c3241Smlf 	 */
952507c3241Smlf 	if (bp->av_back)
953507c3241Smlf 		bp->b_error = (intptr_t)bp->av_back;
954507c3241Smlf 	if (!qmerge1pri &&
955507c3241Smlf 	    ((bp->b_flags & (B_ASYNC|B_READ|B_FREE)) == B_ASYNC)) {
956507c3241Smlf 		bpp = &dp->hd_async_next;
957507c3241Smlf 	} else {
958507c3241Smlf 		bpp = &dp->hd_sync_next;
959507c3241Smlf 	}
960507c3241Smlf 
961507c3241Smlf 
962507c3241Smlf 	if ((bp1 = *bpp) == NULL) {
963507c3241Smlf 		*bpp = bp;
964507c3241Smlf 		bp->av_forw = bp->av_back = bp;
965507c3241Smlf 		if ((bpp == async_bpp) && (*sync_bpp == NULL)) {
966507c3241Smlf 			dp->hd_flags |= QNEAR_ASYNCONLY;
967507c3241Smlf 		} else if (bpp == sync_bpp) {
968507c3241Smlf 			dp->hd_flags &= ~QNEAR_ASYNCONLY;
969507c3241Smlf 			if (*async_bpp) {
970507c3241Smlf 				dp->hd_flags |= QNEAR_ASYNCALSO;
971507c3241Smlf 			}
972507c3241Smlf 		}
973507c3241Smlf 		return;
974507c3241Smlf 	}
975507c3241Smlf 	bp_start = bp1;
976507c3241Smlf 	if (DBLK(bp) < DBLK(bp1)) {
977507c3241Smlf 		lowest_blk = DBLK(bp1);
978507c3241Smlf 		lowest_bp = bp1;
979507c3241Smlf 		do {
980507c3241Smlf 			if (DBLK(bp) > DBLK(bp1)) {
981507c3241Smlf 				bp->av_forw = bp1->av_forw;
982507c3241Smlf 				bp1->av_forw->av_back = bp;
983507c3241Smlf 				bp1->av_forw = bp;
984507c3241Smlf 				bp->av_back = bp1;
985507c3241Smlf 
986507c3241Smlf 				if (((bpp == async_bpp) &&
987507c3241Smlf 				    (dp->hd_flags & QNEAR_ASYNC)) ||
988507c3241Smlf 				    (bpp == sync_bpp)) {
989507c3241Smlf 					if (!(dp->hd_flags & QNEAR_BACKWARD) &&
990507c3241Smlf 					    BP_GT_HD(bp, dp)) {
991507c3241Smlf 						*bpp = bp;
992507c3241Smlf 					}
993507c3241Smlf 				}
994507c3241Smlf 				return;
995507c3241Smlf 			} else if (DBLK(bp1) < lowest_blk) {
996507c3241Smlf 				lowest_bp = bp1;
997507c3241Smlf 				lowest_blk = DBLK(bp1);
998507c3241Smlf 			}
999507c3241Smlf 		} while ((DBLK(bp1->av_back) < DBLK(bp1)) &&
1000507c3241Smlf 		    ((bp1 = bp1->av_back) != bp_start));
1001507c3241Smlf 		bp->av_forw = lowest_bp;
1002507c3241Smlf 		lowest_bp->av_back->av_forw = bp;
1003507c3241Smlf 		bp->av_back = lowest_bp->av_back;
1004507c3241Smlf 		lowest_bp->av_back = bp;
1005507c3241Smlf 		if ((bpp == async_bpp) && !(dp->hd_flags & QNEAR_ASYNC)) {
1006507c3241Smlf 			*bpp = bp;
1007507c3241Smlf 		} else if (!(dp->hd_flags & QNEAR_BACKWARD) &&
1008507c3241Smlf 		    BP_GT_HD(bp, dp)) {
1009507c3241Smlf 			*bpp = bp;
1010507c3241Smlf 		}
1011507c3241Smlf 	} else {
1012507c3241Smlf 		highest_blk = DBLK(bp1);
1013507c3241Smlf 		highest_bp = bp1;
1014507c3241Smlf 		do {
1015507c3241Smlf 			if (DBLK(bp) < DBLK(bp1)) {
1016507c3241Smlf 				bp->av_forw = bp1;
1017507c3241Smlf 				bp1->av_back->av_forw = bp;
1018507c3241Smlf 				bp->av_back = bp1->av_back;
1019507c3241Smlf 				bp1->av_back = bp;
1020507c3241Smlf 				if (((bpp == async_bpp) &&
1021507c3241Smlf 				    (dp->hd_flags & QNEAR_ASYNC)) ||
1022507c3241Smlf 				    (bpp == sync_bpp)) {
1023507c3241Smlf 					if ((dp->hd_flags & QNEAR_BACKWARD) &&
1024507c3241Smlf 					    BP_LT_HD(bp, dp)) {
1025507c3241Smlf 						*bpp = bp;
1026507c3241Smlf 					}
1027507c3241Smlf 				}
1028507c3241Smlf 				return;
1029507c3241Smlf 			} else if (DBLK(bp1) > highest_blk) {
1030507c3241Smlf 				highest_bp = bp1;
1031507c3241Smlf 				highest_blk = DBLK(bp1);
1032507c3241Smlf 			}
1033507c3241Smlf 		} while ((DBLK(bp1->av_forw) > DBLK(bp1)) &&
1034507c3241Smlf 		    ((bp1 = bp1->av_forw) != bp_start));
1035507c3241Smlf 		bp->av_back = highest_bp;
1036507c3241Smlf 		highest_bp->av_forw->av_back = bp;
1037507c3241Smlf 		bp->av_forw = highest_bp->av_forw;
1038507c3241Smlf 		highest_bp->av_forw = bp;
1039507c3241Smlf 
1040507c3241Smlf 		if (((bpp == sync_bpp) ||
1041507c3241Smlf 		    ((bpp == async_bpp) && (dp->hd_flags & QNEAR_ASYNC))) &&
1042507c3241Smlf 		    (dp->hd_flags & QNEAR_BACKWARD) && (BP_LT_HD(bp, dp)))
1043507c3241Smlf 			*bpp = bp;
1044507c3241Smlf 	}
1045507c3241Smlf }
1046507c3241Smlf 
1047507c3241Smlf /*
1048507c3241Smlf  * dmult_enque() holds dmultp->ds_mutex lock, so we dont grab
1049507c3241Smlf  * lock here. If dmult_enque() changes we will have to visit
1050507c3241Smlf  * this function again
1051507c3241Smlf  */
1052507c3241Smlf static int
1053507c3241Smlf qmerge_add(struct que_data *qfp, struct buf *bp)
1054507c3241Smlf {
1055507c3241Smlf 
1056507c3241Smlf 	que_insert(qfp, bp);
1057507c3241Smlf 	return (++qfp->q_cnt);
1058507c3241Smlf }
1059507c3241Smlf 
1060507c3241Smlf static int
1061507c3241Smlf qmerge_iodone(struct buf *bp)
1062507c3241Smlf {
1063507c3241Smlf 	struct buf *bp1;
1064507c3241Smlf 	struct	page *pp, *pp1, *tmp_pp;
1065507c3241Smlf 
1066507c3241Smlf 	if (bp->b_flags & B_REMAPPED)
1067507c3241Smlf 		bp_mapout(bp);
1068507c3241Smlf 
1069507c3241Smlf 	bp1 = bp->b_forw;
1070507c3241Smlf 	do {
1071507c3241Smlf 		bp->b_forw = bp1->av_forw;
1072507c3241Smlf 		bp1->av_forw->av_back = bp1->av_back;
1073507c3241Smlf 		bp1->av_back->av_forw = bp1->av_forw;
1074507c3241Smlf 		pp = (page_t *)bp1->b_pages;
1075507c3241Smlf 		pp1 = bp->b_forw->b_pages;
1076507c3241Smlf 
1077507c3241Smlf 		tmp_pp = pp->p_prev;
1078507c3241Smlf 		pp->p_prev = pp1->p_prev;
1079507c3241Smlf 		pp->p_prev->p_next = pp;
1080507c3241Smlf 
1081507c3241Smlf 		pp1->p_prev = tmp_pp;
1082507c3241Smlf 		pp1->p_prev->p_next = pp1;
1083507c3241Smlf 
1084507c3241Smlf 		if (bp->b_flags & B_ERROR) {
1085507c3241Smlf 			bp1->b_error = bp->b_error;
1086507c3241Smlf 			bp1->b_flags |= B_ERROR;
1087507c3241Smlf 		}
1088507c3241Smlf 
1089507c3241Smlf 		biodone(bp1);
1090507c3241Smlf 	} while ((bp1 = bp->b_forw) != bp->b_forw->av_forw);
1091507c3241Smlf 
1092507c3241Smlf 	biodone(bp1);
1093507c3241Smlf 	kmem_free(bp, sizeof (*bp));
1094507c3241Smlf 	return (0);
1095507c3241Smlf }
1096507c3241Smlf 
1097507c3241Smlf 
1098507c3241Smlf 
1099507c3241Smlf 
1100507c3241Smlf static struct buf *
1101507c3241Smlf qmerge_nextbp(struct que_data *qfp, struct buf *bp_merge, int *can_merge)
1102507c3241Smlf {
1103507c3241Smlf 	intptr_t	private, cnt;
1104507c3241Smlf 	int		flags;
1105507c3241Smlf 	struct		buf *sync_bp, *async_bp, *bp;
1106507c3241Smlf 	struct		buf **sync_bpp, **async_bpp, **bpp;
1107507c3241Smlf 	struct		diskhd *dp = &qfp->q_tab;
1108507c3241Smlf 
1109507c3241Smlf 	if (qfp->q_cnt == 0) {
1110507c3241Smlf 		return (NULL);
1111507c3241Smlf 	}
1112507c3241Smlf 	flags = qfp->q_tab.hd_flags;
1113507c3241Smlf 	sync_bpp = &qfp->q_tab.hd_sync_next;
1114507c3241Smlf 	async_bpp = &qfp->q_tab.hd_async_next;
1115507c3241Smlf 
1116507c3241Smlf begin_nextbp:
1117507c3241Smlf 	if (flags & QNEAR_ASYNCONLY) {
1118507c3241Smlf 		bp = *async_bpp;
1119507c3241Smlf 		private = DBLK(bp);
1120507c3241Smlf 		if (bp_merge && !qmerge_can_merge(bp, bp_merge)) {
1121507c3241Smlf 			return (NULL);
1122507c3241Smlf 		} else if (bp->av_forw == bp) {
1123507c3241Smlf 			bp->av_forw = bp->av_back = NULL;
1124507c3241Smlf 			flags &= ~(QNEAR_ASYNCONLY | QNEAR_BACKWARD);
1125507c3241Smlf 			private = 0;
1126507c3241Smlf 		} else if (flags & QNEAR_BACKWARD) {
1127507c3241Smlf 			if (DBLK(bp) < DBLK(bp->av_back)) {
1128507c3241Smlf 				flags &= ~QNEAR_BACKWARD;
1129507c3241Smlf 				private = 0;
1130507c3241Smlf 			}
1131507c3241Smlf 		} else if (DBLK(bp) > DBLK(bp->av_forw)) {
1132507c3241Smlf 			if (qmerge2wayscan) {
1133507c3241Smlf 				flags |= QNEAR_BACKWARD;
1134507c3241Smlf 			} else {
1135507c3241Smlf 				private = 0;
1136507c3241Smlf 			}
1137507c3241Smlf 		} else if (qmerge2wayscan == 0) {
1138507c3241Smlf 			private = DBLK(bp->av_forw);
1139507c3241Smlf 		}
1140507c3241Smlf 		bpp = async_bpp;
1141507c3241Smlf 
1142507c3241Smlf 	} else if (flags & QNEAR_ASYNCALSO) {
1143507c3241Smlf 		sync_bp = *sync_bpp;
1144507c3241Smlf 		async_bp = *async_bpp;
1145507c3241Smlf 		if (flags & QNEAR_BACKWARD) {
1146507c3241Smlf 			if (BP_GT_HD(sync_bp, dp) && BP_GT_HD(async_bp, dp)) {
1147507c3241Smlf 				flags &= ~(QNEAR_BACKWARD|QNEAR_ASYNCALSO);
1148507c3241Smlf 				*sync_bpp = sync_bp->av_forw;
1149507c3241Smlf 				*async_bpp = async_bp->av_forw;
1150507c3241Smlf 				SYNC2ASYNC(qfp) = (void *)qmerge_sync2async;
1151507c3241Smlf 				qfp->q_tab.hd_private = 0;
1152507c3241Smlf 				goto begin_nextbp;
1153507c3241Smlf 			}
1154507c3241Smlf 			if (BP_LT_HD(async_bp, dp) && BP_LT_HD(sync_bp, dp)) {
1155507c3241Smlf 				if (BP_GT_BP(async_bp, sync_bp)) {
1156507c3241Smlf 					bpp = async_bpp;
1157507c3241Smlf 					bp = *async_bpp;
1158507c3241Smlf 				} else {
1159507c3241Smlf 					bpp = sync_bpp;
1160507c3241Smlf 					bp = *sync_bpp;
1161507c3241Smlf 				}
1162507c3241Smlf 			} else if (BP_LT_HD(async_bp, dp)) {
1163507c3241Smlf 				bpp = async_bpp;
1164507c3241Smlf 				bp = *async_bpp;
1165507c3241Smlf 			} else {
1166507c3241Smlf 				bpp = sync_bpp;
1167507c3241Smlf 				bp = *sync_bpp;
1168507c3241Smlf 			}
1169507c3241Smlf 		} else {
1170507c3241Smlf 			if (BP_LT_HD(sync_bp, dp) && BP_LT_HD(async_bp, dp)) {
1171507c3241Smlf 				if (qmerge2wayscan) {
1172507c3241Smlf 					flags |= QNEAR_BACKWARD;
1173507c3241Smlf 					*sync_bpp = sync_bp->av_back;
1174507c3241Smlf 					*async_bpp = async_bp->av_back;
1175507c3241Smlf 					goto begin_nextbp;
1176507c3241Smlf 				} else {
1177507c3241Smlf 					flags &= ~QNEAR_ASYNCALSO;
1178507c3241Smlf 					SYNC2ASYNC(qfp) =
1179507c3241Smlf 					    (void *)qmerge_sync2async;
1180507c3241Smlf 					qfp->q_tab.hd_private = 0;
1181507c3241Smlf 					goto begin_nextbp;
1182507c3241Smlf 				}
1183507c3241Smlf 			}
1184507c3241Smlf 			if (BP_GT_HD(async_bp, dp) && BP_GT_HD(sync_bp, dp)) {
1185507c3241Smlf 				if (BP_LT_BP(async_bp, sync_bp)) {
1186507c3241Smlf 					bpp = async_bpp;
1187507c3241Smlf 					bp = *async_bpp;
1188507c3241Smlf 				} else {
1189507c3241Smlf 					bpp = sync_bpp;
1190507c3241Smlf 					bp = *sync_bpp;
1191507c3241Smlf 				}
1192507c3241Smlf 			} else if (BP_GT_HD(async_bp, dp)) {
1193507c3241Smlf 				bpp = async_bpp;
1194507c3241Smlf 				bp = *async_bpp;
1195507c3241Smlf 			} else {
1196507c3241Smlf 				bpp = sync_bpp;
1197507c3241Smlf 				bp = *sync_bpp;
1198507c3241Smlf 			}
1199507c3241Smlf 		}
1200507c3241Smlf 		if (bp_merge && !qmerge_can_merge(bp, bp_merge)) {
1201507c3241Smlf 			return (NULL);
1202507c3241Smlf 		} else if (bp->av_forw == bp) {
1203507c3241Smlf 			bp->av_forw = bp->av_back = NULL;
1204507c3241Smlf 			flags &= ~QNEAR_ASYNCALSO;
1205507c3241Smlf 			if (bpp == async_bpp) {
1206507c3241Smlf 				SYNC2ASYNC(qfp) = (void *)qmerge_sync2async;
1207507c3241Smlf 			} else {
1208507c3241Smlf 				flags |= QNEAR_ASYNCONLY;
1209507c3241Smlf 			}
1210507c3241Smlf 		}
1211507c3241Smlf 		private = DBLK(bp);
1212507c3241Smlf 	} else {
1213507c3241Smlf 		bp = *sync_bpp;
1214507c3241Smlf 		private = DBLK(bp);
1215507c3241Smlf 		if (bp_merge && !qmerge_can_merge(bp, bp_merge)) {
1216507c3241Smlf 			return (NULL);
1217507c3241Smlf 		} else if (bp->av_forw == bp) {
1218507c3241Smlf 			private = 0;
1219507c3241Smlf 			SYNC2ASYNC(qfp) = (void *)qmerge_sync2async;
1220507c3241Smlf 			bp->av_forw = bp->av_back = NULL;
1221507c3241Smlf 			flags &= ~QNEAR_BACKWARD;
1222507c3241Smlf 			if (*async_bpp)
1223507c3241Smlf 				flags |= QNEAR_ASYNCONLY;
1224507c3241Smlf 		} else if (flags & QNEAR_BACKWARD) {
1225507c3241Smlf 			if (DBLK(bp) < DBLK(bp->av_back)) {
1226507c3241Smlf 				flags &= ~QNEAR_BACKWARD;
1227507c3241Smlf 				cnt = (intptr_t)SYNC2ASYNC(qfp);
1228507c3241Smlf 				if (cnt > 0) {
1229507c3241Smlf 					cnt--;
1230507c3241Smlf 					SYNC2ASYNC(qfp) = (void *)cnt;
1231507c3241Smlf 				} else {
1232507c3241Smlf 					if (*async_bpp)
1233507c3241Smlf 						flags |= QNEAR_ASYNCALSO;
1234507c3241Smlf 					SYNC2ASYNC(qfp) =
1235507c3241Smlf 					    (void *)qmerge_sync2async;
1236507c3241Smlf 				}
1237507c3241Smlf 				private = 0;
1238507c3241Smlf 			}
1239507c3241Smlf 		} else if (DBLK(bp) > DBLK(bp->av_forw)) {
1240507c3241Smlf 			private = 0;
1241507c3241Smlf 			if (qmerge2wayscan) {
1242507c3241Smlf 				flags |= QNEAR_BACKWARD;
1243507c3241Smlf 				private = DBLK(bp);
1244507c3241Smlf 			} else {
1245507c3241Smlf 				cnt = (intptr_t)SYNC2ASYNC(qfp);
1246507c3241Smlf 				if (cnt > 0) {
1247507c3241Smlf 					cnt--;
1248507c3241Smlf 					SYNC2ASYNC(qfp) = (void *)cnt;
1249507c3241Smlf 				} else {
1250507c3241Smlf 					if (*async_bpp)
1251507c3241Smlf 						flags |= QNEAR_ASYNCALSO;
1252507c3241Smlf 					SYNC2ASYNC(qfp) =
1253507c3241Smlf 					    (void *)qmerge_sync2async;
1254507c3241Smlf 				}
1255507c3241Smlf 			}
1256507c3241Smlf 		} else if (qmerge2wayscan == 0) {
1257507c3241Smlf 			private = DBLK(bp->av_forw);
1258507c3241Smlf 		}
1259507c3241Smlf 		bpp = sync_bpp;
1260507c3241Smlf 	}
1261507c3241Smlf 
1262507c3241Smlf 	if (bp->av_forw) {
1263507c3241Smlf 		*can_merge = !(bp->b_flags & B_READ);
1264507c3241Smlf 		if (flags & QNEAR_BACKWARD) {
1265507c3241Smlf 			*bpp = bp->av_back;
1266507c3241Smlf 			if ((DBLK(bp->av_back) +
1267507c3241Smlf 			    bp->av_back->b_bcount / DEV_BSIZE) != DBLK(bp))
1268507c3241Smlf 				*can_merge = 0;
1269507c3241Smlf 		} else {
1270507c3241Smlf 			*bpp = bp->av_forw;
1271507c3241Smlf 			if ((DBLK(bp) + bp->b_bcount / DEV_BSIZE) !=
1272507c3241Smlf 			    DBLK(bp->av_forw))
1273507c3241Smlf 				*can_merge = 0;
1274507c3241Smlf 		}
1275507c3241Smlf 		bp->av_forw->av_back = bp->av_back;
1276507c3241Smlf 		bp->av_back->av_forw = bp->av_forw;
1277507c3241Smlf 		bp->av_forw = bp->av_back = NULL;
1278507c3241Smlf 	} else {
1279507c3241Smlf 		*bpp = NULL;
1280507c3241Smlf 		*can_merge = 0;
1281507c3241Smlf 	}
1282507c3241Smlf 	qfp->q_tab.hd_private = (void *)private;
1283507c3241Smlf 	qfp->q_cnt--;
1284507c3241Smlf 	qfp->q_tab.hd_flags = flags;
1285507c3241Smlf 	if (bp->b_error) {
1286507c3241Smlf 		bp->av_back = (void *)(intptr_t)bp->b_error;
1287507c3241Smlf 		bp->b_error = 0;
1288507c3241Smlf 	}
1289507c3241Smlf 	return (bp);
1290507c3241Smlf }
1291507c3241Smlf 
1292507c3241Smlf static struct buf *
1293507c3241Smlf qmerge_del(struct que_data *qfp)
1294507c3241Smlf {
1295507c3241Smlf 	struct	buf *bp, *next_bp, *bp_merge;
1296507c3241Smlf 	int	alloc_mergebp, merge;
1297507c3241Smlf 
1298507c3241Smlf 	if (qfp->q_cnt == 0) {
1299507c3241Smlf 		return (NULL);
1300507c3241Smlf 	}
1301507c3241Smlf 
1302507c3241Smlf 	bp_merge = bp = qmerge_nextbp(qfp, NULL, &merge);
1303507c3241Smlf 	alloc_mergebp = 1;
1304507c3241Smlf 	while (merge && (next_bp = qmerge_nextbp(qfp, bp_merge, &merge))) {
1305507c3241Smlf 		if (alloc_mergebp) {
1306507c3241Smlf 			bp_merge = kmem_alloc(sizeof (*bp_merge), KM_NOSLEEP);
1307507c3241Smlf 			if (bp_merge == NULL) {
1308507c3241Smlf 				mutex_exit(&qfp->q_mutex);
1309507c3241Smlf 				return (bp);
1310507c3241Smlf 			}
1311507c3241Smlf 			bcopy(bp, bp_merge, sizeof (*bp_merge));
1312507c3241Smlf 			bp_merge->b_iodone = qmerge_iodone;
1313507c3241Smlf 			bp_merge->b_forw = bp;
1314507c3241Smlf 			bp_merge->b_back = (struct buf *)qfp;
1315507c3241Smlf 			bp->av_forw = bp->av_back = bp;
1316507c3241Smlf 			alloc_mergebp = 0;
1317507c3241Smlf 		}
1318507c3241Smlf 		qmerge_mergesetup(bp_merge, next_bp);
1319507c3241Smlf 	}
1320507c3241Smlf 	return (bp_merge);
1321507c3241Smlf }
1322507c3241Smlf 
1323507c3241Smlf 
1324507c3241Smlf /*
1325507c3241Smlf  *	FIFO Queue functions
1326507c3241Smlf  */
1327507c3241Smlf /*
1328507c3241Smlf  * 	Local Function Prototypes
1329507c3241Smlf  */
1330507c3241Smlf static int qfifo_add();
1331507c3241Smlf 
1332507c3241Smlf struct 	que_objops qfifo_ops = {
1333507c3241Smlf 	que_init,
1334507c3241Smlf 	que_free,
1335507c3241Smlf 	qfifo_add,
1336507c3241Smlf 	que_del,
1337507c3241Smlf 	0, 0
1338507c3241Smlf };
1339507c3241Smlf 
1340507c3241Smlf /*
1341507c3241Smlf  * 	Local static data
1342507c3241Smlf  */
1343507c3241Smlf struct que_obj *
1344507c3241Smlf qfifo_create()
1345507c3241Smlf {
1346507c3241Smlf 	return (que_create((struct que_objops *)&qfifo_ops));
1347507c3241Smlf }
1348507c3241Smlf 
1349507c3241Smlf static int
1350507c3241Smlf qfifo_add(struct que_data *qfp, struct buf *bp)
1351507c3241Smlf {
1352507c3241Smlf 
1353507c3241Smlf 	if (!qfp->q_tab.b_actf)
1354507c3241Smlf 		qfp->q_tab.b_actf = bp;
1355507c3241Smlf 	else
1356507c3241Smlf 		qfp->q_tab.b_actl->av_forw = bp;
1357507c3241Smlf 	qfp->q_tab.b_actl = bp;
1358507c3241Smlf 	bp->av_forw = NULL;
1359507c3241Smlf 	return (0);
1360507c3241Smlf }
1361507c3241Smlf 
1362507c3241Smlf /*
1363507c3241Smlf  *	One-Way-Scan Queue functions
1364507c3241Smlf  */
1365507c3241Smlf /*
1366507c3241Smlf  * 	Local Function Prototypes
1367507c3241Smlf  */
1368507c3241Smlf static int qsort_add();
1369507c3241Smlf static struct buf *qsort_del();
1370507c3241Smlf static void oneway_scan_binary(struct diskhd *dp, struct buf *bp);
1371507c3241Smlf 
1372507c3241Smlf struct 	que_objops qsort_ops = {
1373507c3241Smlf 	que_init,
1374507c3241Smlf 	que_free,
1375507c3241Smlf 	qsort_add,
1376507c3241Smlf 	qsort_del,
1377507c3241Smlf 	0, 0
1378507c3241Smlf };
1379507c3241Smlf 
1380507c3241Smlf /*
1381507c3241Smlf  * 	Local static data
1382507c3241Smlf  */
1383507c3241Smlf struct que_obj *
1384507c3241Smlf qsort_create()
1385507c3241Smlf {
1386507c3241Smlf 	return (que_create((struct que_objops *)&qsort_ops));
1387507c3241Smlf }
1388507c3241Smlf 
1389507c3241Smlf static int
1390507c3241Smlf qsort_add(struct que_data *qfp, struct buf *bp)
1391507c3241Smlf {
1392507c3241Smlf 	qfp->q_cnt++;
1393507c3241Smlf 	oneway_scan_binary(&qfp->q_tab, bp);
1394507c3241Smlf 	return (0);
1395507c3241Smlf }
1396507c3241Smlf 
1397507c3241Smlf 
1398507c3241Smlf #define	b_pasf	b_forw
1399507c3241Smlf #define	b_pasl	b_back
1400507c3241Smlf static void
1401507c3241Smlf oneway_scan_binary(struct diskhd *dp, struct buf *bp)
1402507c3241Smlf {
1403507c3241Smlf 	struct buf *ap;
1404507c3241Smlf 
1405507c3241Smlf 	ap = dp->b_actf;
1406507c3241Smlf 	if (ap == NULL) {
1407507c3241Smlf 		dp->b_actf = bp;
1408507c3241Smlf 		bp->av_forw = NULL;
1409507c3241Smlf 		return;
1410507c3241Smlf 	}
1411507c3241Smlf 	if (DBLK(bp) < DBLK(ap)) {
1412507c3241Smlf 		ap = dp->b_pasf;
1413507c3241Smlf 		if ((ap == NULL) || (DBLK(bp) < DBLK(ap))) {
1414507c3241Smlf 			dp->b_pasf = bp;
1415507c3241Smlf 			bp->av_forw = ap;
1416507c3241Smlf 			return;
1417507c3241Smlf 		}
1418507c3241Smlf 	}
1419507c3241Smlf 	while (ap->av_forw) {
1420507c3241Smlf 		if (DBLK(bp) < DBLK(ap->av_forw))
1421507c3241Smlf 			break;
1422507c3241Smlf 		ap = ap->av_forw;
1423507c3241Smlf 	}
1424507c3241Smlf 	bp->av_forw = ap->av_forw;
1425507c3241Smlf 	ap->av_forw = bp;
1426507c3241Smlf }
1427507c3241Smlf 
1428507c3241Smlf static struct buf *
1429507c3241Smlf qsort_del(struct que_data *qfp)
1430507c3241Smlf {
1431507c3241Smlf 	struct buf *bp;
1432507c3241Smlf 
1433507c3241Smlf 	if (qfp->q_cnt == 0) {
1434507c3241Smlf 		return (NULL);
1435507c3241Smlf 	}
1436507c3241Smlf 	qfp->q_cnt--;
1437507c3241Smlf 	bp = qfp->q_tab.b_actf;
1438507c3241Smlf 	qfp->q_tab.b_actf = bp->av_forw;
1439507c3241Smlf 	bp->av_forw = 0;
1440507c3241Smlf 	if (!qfp->q_tab.b_actf && qfp->q_tab.b_pasf) {
1441507c3241Smlf 		qfp->q_tab.b_actf = qfp->q_tab.b_pasf;
1442507c3241Smlf 		qfp->q_tab.b_pasf = NULL;
1443507c3241Smlf 	}
1444507c3241Smlf 	return (bp);
1445507c3241Smlf }
1446507c3241Smlf 
1447507c3241Smlf /*
1448507c3241Smlf  *	Tagged queueing
1449507c3241Smlf  */
1450507c3241Smlf /*
1451507c3241Smlf  * 	Local Function Prototypes
1452507c3241Smlf  */
1453507c3241Smlf 
1454507c3241Smlf struct 	que_objops qtag_ops = {
1455507c3241Smlf 	que_init,
1456507c3241Smlf 	que_free,
1457507c3241Smlf 	qsort_add,
1458507c3241Smlf 	qsort_del,
1459507c3241Smlf 	0, 0
1460507c3241Smlf };
1461507c3241Smlf 
1462507c3241Smlf /*
1463507c3241Smlf  * 	Local static data
1464507c3241Smlf  */
1465507c3241Smlf struct que_obj *
1466507c3241Smlf qtag_create()
1467507c3241Smlf {
1468507c3241Smlf 	return (que_create((struct que_objops *)&qtag_ops));
1469507c3241Smlf }
1470