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