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