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