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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Routines for the Infinity Storage Device daemon 28 */ 29 30 #include <sys/types.h> 31 #include <sys/ksynch.h> 32 #include <sys/cmn_err.h> 33 #include <sys/errno.h> 34 #include <sys/buf.h> 35 #include <sys/kmem.h> 36 #include <sys/cred.h> 37 #include <sys/ddi.h> 38 #include <sys/nsc_thread.h> 39 40 #include "sd_bcache.h" 41 #include "sd_io.h" 42 #include "sd_bio.h" 43 #include "sd_ft.h" 44 #include "sd_misc.h" 45 46 #define _INFSD_LOCAL_MEM 47 48 #define _CD_VTRK_SIZE(cd) (dev_tsize[GET_CD_STATE(cd)] * 1024) 49 #define _CD_VTRK_NUM(cd, len) ((len)/_CD_VTRK_SIZE(cd)) 50 #define _CD_VTRK_OFF(cd, len) ((len)%(_CD_VTRK_SIZE(cd))) 51 52 #define FILESIZE (1 << 27) /* 128 MB */ 53 54 #define SIZEMASK 0x0000FFFF 55 #define _INFSD_RECORD_SIZE(ndx) REC_SIZE 56 #define GET_SEED(ndx) (gld[ndx] . seed & SIZEMASK) 57 #define MAX_CD_STS 600 58 #define MAX_TDAEMONS 128 59 60 static char devarray[MAX_TDAEMONS][MAX_TDAEMONS*2]; 61 static int dev_tsize[MAX_TDAEMONS*2]; 62 static int dev_flag[MAX_TDAEMONS*2]; 63 64 65 /* 66 * sd_test options 67 */ 68 #define SD_TEST_CACHE_HIT 0x00000001 69 #define SD_TEST_CACHE_MISS 0x00000002 70 #define SD_TEST_CHECK_DATA 0x00000004 71 #define SD_TEST_READ_ONLY 0x00000008 72 #define SD_TEST_WRITE_ONLY 0x00000010 73 #define SD_TEST_SEQUENTIAL 0x00000020 74 75 static struct cd_sts { 76 volatile short cd_state; 77 volatile char waiting; 78 volatile char inited; 79 kcondvar_t cd_blk; 80 volatile caddr_t asy_key; 81 } cd_test_sts[MAX_CD_STS]; 82 83 #define SET_CD_STATE(cd, i) (cd_test_sts[(cd)].cd_state = (short)(i)) 84 #define GET_CD_STATE(cd) (cd_test_sts[(cd)].cd_state) 85 86 static kmutex_t tdaemon_lock; 87 static kcondvar_t _wait_daemons; 88 dev_t _test_async_fail; /* fail async writes to cache dev_t */ 89 static volatile int test_stop; 90 91 static int daemon_awake(int i); 92 static void wakeup_all_tdaemons(void); 93 static void _sd_idle_daemon(void); 94 static void _td_detach_cd(int cd); 95 static int _fork_test_daemon(int num_disks, int test_typ, int loop_cnt, 96 int from, int seed); 97 static void _sd_test_rwloop_seq(int i, int loops, int seed, int forw); 98 static int _sd_copy_pattern_to_handle(_sd_buf_handle_t *handle, 99 nsc_off_t fba_pos, nsc_size_t fba_len); 100 static int _sd_copy_handle(_sd_buf_handle_t *handle1, _sd_buf_handle_t *handle2, 101 nsc_off_t fba_pos1, nsc_off_t fba_pos2, nsc_size_t fba_len, int skew); 102 static int _sd_compare_handle(_sd_buf_handle_t *handle1, 103 _sd_buf_handle_t *handle2, nsc_off_t fba_pos1, nsc_off_t fba_pos2, 104 nsc_size_t fba_len, int skew); 105 static void _sd_direct_test(int c, int loop, int seed, int type); 106 static void set_parameters(void); 107 static void test_dma_loop(int net, int seg); 108 static int _sd_hwrite(_sd_buf_handle_t *buf, nsc_off_t fba_pos, 109 nsc_size_t fba_len, int flag); 110 static void myend(blind_t arg, nsc_off_t fba_pos, nsc_size_t fba_len, 111 int error); 112 static int test_control(int typ, int cd, nsc_off_t fba_pos, nsc_size_t fba_len); 113 114 int 115 _sim_write(_sd_buf_handle_t *buf, int x) 116 { 117 int rval; 118 119 if (test_stop) 120 return (EINVAL); 121 rval = _sd_write(buf, buf->bh_fba_pos, buf->bh_fba_len, x); 122 return (rval == NSC_HIT ? NSC_DONE : rval); 123 } 124 125 static int 126 _sd_hwrite(_sd_buf_handle_t *buf, nsc_off_t fba_pos, nsc_size_t fba_len, 127 int flag) 128 { 129 int rval; 130 131 rval = _sd_write(buf, fba_pos, fba_len, flag); 132 return (rval == NSC_HIT ? NSC_DONE : rval); 133 } 134 135 #define _sd_allocate_buf _trk_allocate_buf 136 #define _sd_write _sim_write 137 138 /* 139 * INF SD daemon global data 140 */ 141 142 volatile int test_created; 143 static int _sd_daemon_created; 144 static int _sd_num_daemons; 145 146 static struct gld { 147 volatile int type; 148 volatile int loop; 149 volatile int seed; 150 volatile int asleep; 151 kcondvar_t blk; 152 } gld[MAX_TDAEMONS]; 153 154 /* 155 * _sdbc_tdaemon_load: cache is being loaded, initialize any global state that 156 * isn't configurable (lock/sv's). 157 */ 158 int 159 _sdbc_tdaemon_load(void) 160 { 161 int i; 162 163 for (i = 0; i < MAX_TDAEMONS; i++) 164 cv_init(&gld[i].blk, NULL, CV_DRIVER, NULL); 165 166 mutex_init(&tdaemon_lock, NULL, MUTEX_DRIVER, NULL); 167 cv_init(&_wait_daemons, NULL, CV_DRIVER, NULL); 168 169 return (0); 170 } 171 /* 172 * _sdbc_tdaemon_unload: cache is being unloaded. 173 */ 174 void 175 _sdbc_tdaemon_unload(void) 176 { 177 int i; 178 179 for (i = 0; i < MAX_TDAEMONS; i++) { 180 cv_destroy(&gld[i].blk); 181 } 182 183 mutex_destroy(&tdaemon_lock); 184 cv_destroy(&_wait_daemons); 185 186 } 187 188 /* 189 * _sdbc_tdaemon_configure: configure the desired number of test daemons. 190 */ 191 int 192 _sdbc_tdaemon_configure(int num) 193 { 194 int i; 195 196 if (num >= MAX_TDAEMONS) 197 return (-1); 198 199 for (i = 0; i < num; i++) { 200 cv_init(&gld[i].blk, NULL, CV_DRIVER, NULL); 201 } 202 mutex_enter(&tdaemon_lock); 203 test_created = 1; 204 test_stop = 0; 205 _sd_num_daemons = 0; 206 mutex_exit(&tdaemon_lock); 207 208 mutex_enter(&_sd_cache_lock); 209 if (_sd_daemon_created == 1) { 210 mutex_exit(&_sd_cache_lock); 211 return (-1); 212 } 213 _sd_daemon_created = 1; 214 mutex_exit(&_sd_cache_lock); 215 216 for (i = 0; i < num; i++) { 217 (void) nsc_create_process( 218 (void (*)(void *))_sd_idle_daemon, 0, FALSE); 219 } 220 221 #ifdef DEBUG 222 if (num) 223 cmn_err(CE_NOTE, "!Starting %d SDBC test daemon(s).", num); 224 #endif 225 return (0); 226 } 227 228 void 229 _sdbc_tdaemon_deconfigure(void) 230 { 231 int i, running, retry = 30; 232 233 if (_sd_num_daemons) { 234 _sd_daemon_created = 0; 235 236 mutex_enter(&tdaemon_lock); 237 test_created = 0; 238 test_stop = 1; 239 mutex_exit(&tdaemon_lock); 240 241 wakeup_all_tdaemons(); 242 while (retry--) { 243 delay(HZ); 244 running = 0; 245 for (i = 0; i < _sd_num_daemons; i++) 246 if (daemon_awake(i)) 247 running++; 248 if (running == 0) break; 249 } 250 } 251 for (i = 0; i < MAX_CD_STS; i++) { 252 cv_destroy(&cd_test_sts[i].cd_blk); 253 cd_test_sts[i].inited = 0; 254 } 255 _sd_num_daemons = 0; 256 } 257 258 259 int sind = 0; 260 261 /* 262 * Globals to change test parameters - Initially added for tests written 263 * by Ajay 264 */ 265 #ifdef SD_TDAEMON_DEBUG 266 struct statis { 267 int cd; 268 nsc_size_t len; 269 nsc_off_t offset; 270 int type; 271 } statis[4000]; 272 273 #define add_statis(c, l, o, t) (statis[sind].cd = (c), \ 274 statis[sind].len = (l), \ 275 statis[sind].offset = (o), \ 276 statis[sind].type = (t), sind++) 277 int 278 statis_upd(caddr_t adr) 279 { 280 (void) copyout(statis, adr, sizeof (struct statis) * sind); 281 return (sind); 282 } 283 #endif /* SD_TDAEMON_DEBUG */ 284 285 static int 286 daemon_awake(int i) 287 { 288 if (gld[i].asleep == 2) 289 return (1); 290 return (0); 291 } 292 293 static int 294 daemon_nexist(int i) 295 { 296 if (gld[i].asleep == 0) 297 return (1); 298 return (0); 299 } 300 301 static void 302 daemon_wakeup(int i) 303 { 304 #ifdef _SD_DEBUG 305 cmn_err(CE_NOTE, "!unblocking %d %x", i, gld[i].blk); 306 #endif 307 mutex_enter(&tdaemon_lock); 308 cv_broadcast(&gld[i].blk); 309 mutex_exit(&tdaemon_lock); 310 } 311 312 313 static void 314 wakeup_all_tdaemons(void) 315 { 316 int i; 317 318 for (i = 0; i < _sd_num_daemons; i++) 319 daemon_wakeup(i); 320 } 321 322 323 static void 324 _sd_idle_daemon(void) 325 { 326 int who; /* id of this daemon */ 327 328 mutex_enter(&_sd_cache_lock); 329 _sd_cache_dem_cnt++; 330 who = _sd_num_daemons++; 331 mutex_exit(&_sd_cache_lock); 332 333 /* CONSTCOND */ 334 while (1) { 335 mutex_enter(&tdaemon_lock); 336 gld[who].asleep = 1; 337 #ifdef DEBUG 338 cmn_err(CE_NOTE, "!%d daemon: sleeping %p", who, 339 (void *)&gld[who].blk); 340 #endif 341 342 cv_signal(&_wait_daemons); 343 if (test_created == 0) { 344 gld[who].asleep = 0; 345 mutex_exit(&tdaemon_lock); 346 mutex_enter(&_sd_cache_lock); 347 _sd_cache_dem_cnt--; 348 mutex_exit(&_sd_cache_lock); 349 return; 350 } else { 351 cv_wait(&gld[who].blk, &tdaemon_lock); 352 mutex_exit(&tdaemon_lock); 353 } 354 355 _sd_print(0, "%d daemon awake type %d loop %d seed %d", 356 who, gld[who].type, gld[who].loop, GET_SEED(who)); 357 358 if (test_created == 0) { 359 gld[who].asleep = 0; 360 mutex_enter(&_sd_cache_lock); 361 _sd_cache_dem_cnt--; 362 mutex_exit(&_sd_cache_lock); 363 return; 364 } 365 gld[who].asleep = 2; 366 367 switch (gld[who].type) { 368 369 case 210: 370 test_dma_loop(gld[who].loop, gld[who].seed); 371 break; 372 case 323: 373 _sd_direct_test(who, gld[who].loop, GET_SEED(who), 0); 374 break; 375 376 case 350: 377 _sd_test_rwloop_seq(who, gld[who].loop, GET_SEED(who), 378 1); 379 break; 380 case 351: 381 _sd_test_rwloop_seq(who, gld[who].loop, GET_SEED(who), 382 0); 383 break; 384 385 #if 0 386 case 400: 387 if (gld[who].loop >= 6) 388 numdevs = gld[who].loop; 389 break; 390 #endif 391 default: 392 cmn_err(CE_WARN, "!%d daemon %d type inval\n", who, 393 gld[who].type); 394 break; 395 } 396 if (test_created == 0) { 397 gld[who].asleep = 0; 398 mutex_enter(&_sd_cache_lock); 399 _sd_cache_dem_cnt--; 400 mutex_exit(&_sd_cache_lock); 401 return; 402 } 403 } 404 } 405 406 407 static void 408 _td_attach_cd(int cd) 409 { 410 (void) nsc_reserve(_sd_cache_files[cd].cd_rawfd, NSC_MULTI); 411 } 412 413 414 static void 415 _td_detach_cd(int cd) 416 { 417 nsc_release(_sd_cache_files[cd].cd_rawfd); 418 } 419 420 421 int 422 _sd_test_start(void *args, int *rvp) 423 { 424 425 register struct a { 426 long num; 427 long type; 428 long loop; 429 long from; 430 long seed; 431 } *uap = (struct a *)args; 432 433 *rvp = _fork_test_daemon(uap->num, uap->type, uap->loop, 434 uap->from, uap->seed); 435 436 return (0); 437 } 438 439 static int 440 test_control(int typ, int cd, nsc_off_t fba_pos, nsc_size_t fba_len) 441 /* 442 * test_control - perform control operations outside of the range 443 * of a test. This is typically called before/after a series of 444 * tests to either check a result or to setup/free a device. 445 */ 446 { 447 int rc = 0; 448 449 if ((cd < 0) || (cd >= sdbc_max_devs)) 450 return (-1); 451 switch (typ) { 452 case 1: 453 rc = _sdbc_io_attach_cd((blind_t)(unsigned long)cd); 454 cmn_err(CE_NOTE, "!_sdbc_io_attach_cd(%d): %d", cd, rc); 455 break; 456 case 2: 457 rc = _sdbc_io_detach_cd((blind_t)(unsigned long)cd); 458 cmn_err(CE_NOTE, "!_sdbc_io_detach_cd(%d): %d", cd, rc); 459 break; 460 case 3: 461 _test_async_fail = _sd_cache_files[cd].cd_crdev; 462 cmn_err(CE_NOTE, "!async fail dev %lu (cd=%d)", 463 _test_async_fail, cd); 464 break; 465 case 4: 466 _test_async_fail = 0; 467 cmn_err(CE_NOTE, "!async fail cleared"); 468 break; 469 #if 0 470 case 5: 471 _trk_alloc_flag = NSC_PINNABLE; 472 break; 473 case 6: 474 _trk_alloc_flag = 0; 475 break; 476 #endif 477 case 7: 478 rc = _sd_get_pinned((blind_t)(unsigned long)cd); 479 cmn_err(CE_NOTE, "!get_pinned(%d): %d", cd, rc); 480 break; 481 case 8: 482 rc = _sd_discard_pinned((blind_t)(unsigned long)cd, fba_pos, 483 fba_len); 484 cmn_err(CE_NOTE, "!discard_pinned(%d,%" NSC_SZFMT ",%" NSC_SZFMT 485 "): %d", cd, fba_pos, fba_len, rc); 486 break; 487 default: 488 cmn_err(CE_WARN, "!cache device command %d invalid\n", typ); 489 } 490 return (rc); 491 } 492 493 494 /* 495 * _fork_sd_daemon(): Fork an nunix process that periodically flushes the 496 * raw device buffer cache 497 */ 498 499 static int 500 _fork_test_daemon(int num_disks, int test_typ, int loop_cnt, int from, int seed) 501 { 502 int i; 503 int type; 504 int dowait = 0, verify = 0; 505 506 if (num_disks == -1) { 507 return (test_control(test_typ, loop_cnt, from, seed)); 508 } 509 510 type = test_typ; 511 cmn_err(CE_NOTE, 512 "!sd_test %d %d %d %d %d", num_disks, type, loop_cnt, from, seed); 513 if (type == 100) { 514 test_stop = 1; 515 return (0); 516 } 517 518 if (type == 99) { 519 /* Set some parameters for other tests */ 520 switch (num_disks) { 521 /* Params set for this test */ 522 #if 0 523 case 302 : 524 _sd_write_len = loop_cnt; 525 break; 526 case 303 : 527 _sd_write_len = loop_cnt; 528 break; 529 case 304 : 530 _sd_trk_zero = loop_cnt; 531 _sd_trk_size = from; 532 break; 533 case 305 : 534 _sd_min_blks = loop_cnt; 535 _sd_max_blks = from; 536 break; 537 #endif 538 default : 539 cmn_err(CE_WARN, 540 "!Usage : sd_test <test_num> 99" 541 " <param1> <param2> <param3>"); 542 break; 543 } 544 return (0); 545 } /* type == 99 */ 546 547 if (type > 1000) { 548 dowait = 1; 549 type -= 1000; 550 } 551 if (type > 1000) { 552 verify = 1; 553 type -= 1000; 554 } 555 556 again: 557 set_parameters(); 558 559 for (i = from; i < (from+num_disks); i++) { 560 if (daemon_awake(i)) { 561 cmn_err(CE_WARN, "!Daemon %d awake!?", i); 562 return (-1); 563 } 564 if (daemon_nexist(i)) { 565 cmn_err(CE_WARN, "!Daemon %d nexist!?", i); 566 return (-1); 567 } 568 569 gld[i].type = type; 570 gld[i].loop = loop_cnt; 571 gld[i].seed = seed; 572 daemon_wakeup(i); 573 } 574 cmn_err(CE_CONT, "!%d daemons woken (test %d)\n", num_disks, type); 575 if (num_disks <= 0) 576 return (0); 577 578 if (dowait) { 579 wait: 580 mutex_enter(&tdaemon_lock); 581 if (!cv_wait_sig(&_wait_daemons, &tdaemon_lock)) { 582 mutex_exit(&tdaemon_lock); 583 test_stop = 1; 584 cmn_err(CE_WARN, "!Interrupt: stopping tests"); 585 return (-1); /* interrupt */ 586 } 587 mutex_exit(&tdaemon_lock); 588 589 /* wait for all to stop */ 590 if (test_stop) 591 return (-1); 592 for (i = from; i < (from+num_disks); i++) { 593 if (daemon_awake(i)) 594 goto wait; 595 } 596 } 597 if (verify) { 598 verify = 0; 599 type++; /* next test */ 600 goto again; 601 } 602 return (0); 603 } 604 605 int 606 _sd_test_end(void) 607 { 608 test_created = 0; 609 test_stop = 1; 610 return (0); 611 } 612 613 int 614 _sd_test_init(void *args) 615 { 616 register struct a { 617 caddr_t addr; 618 long ar; 619 long len; 620 long tsize; 621 long flag; 622 } *uap = (struct a *)args; 623 624 if (copyin(uap->addr, devarray[uap->ar], uap->len)) { 625 return (EFAULT); 626 } 627 dev_tsize[uap->ar] = (uap->tsize < 48) ? 48 : uap->tsize; 628 dev_flag[uap->ar] = uap->flag; 629 return (0); 630 } 631 632 633 typedef struct io_type { 634 int cd, tsize; 635 _sd_buf_handle_t *wbuf, *rbuf; 636 int len, len2, rnet, wnet; 637 int trk_num, trk_off; 638 int offset, boff; 639 char test_pattern; 640 } infnsc_io_t; 641 642 /* static spinlock_t INFSD_iolock = { SLK_IFS_SRVR, 0 }; */ 643 #define _INFSD_TRK_SIZE() (64*1024) 644 #define _INFSD_BUF_ALIGN 512 /* Each read/write should be 512 aligned */ 645 646 /* 647 * _sd_test_rwloop_seq(i,loops, seed, forw): 648 * 649 * Sequential I/O test. Writes track records sequentially, either forwards 650 * or backwards (forw = 1 or forw = 0), writing a fixed pattern with a 651 * few unique bytes depending on loop id. Then reads back, checking 652 * for data consistency. 653 */ 654 655 /* ARGSUSED */ 656 static void 657 _sd_test_rwloop_seq(int i, int loops, int seed, int forw) 658 { 659 int cd; 660 int j, len; 661 nsc_off_t offset; 662 nsc_size_t fsize; 663 int sts; 664 _sd_buf_handle_t *fbuf, *buf; 665 666 if (strlen(devarray[i]) == 0) { 667 cmn_err(CE_WARN, "!child %d devarray null", i); 668 return; 669 } 670 if ((cd = _sd_open(devarray[i], dev_flag[i])) < 0) { 671 cmn_err(CE_WARN, "!Open error %s child %d", devarray[i], i); 672 return; 673 } 674 SET_CD_STATE(cd, i); 675 _td_attach_cd(cd); 676 677 (void) _sd_get_partsize((blind_t)(unsigned long)cd, &fsize); 678 len = 120; 679 680 /* 681 * Write a base pattern into the first buffer 682 */ 683 fbuf = NULL; 684 offset = 0; 685 sts = _sd_alloc_buf((blind_t)(unsigned long)cd, 0, len, NSC_WRBUF, 686 &fbuf); 687 if (sts > 0) { 688 cmn_err(CE_WARN, "!Buffer alloc failed %d", sts); 689 return; 690 } 691 (void) _sd_copy_pattern_to_handle(fbuf, 0, len); 692 _td_detach_cd(cd); 693 694 offset = 0; 695 for (j = 0; j < loops; j++) { 696 if (test_stop == 1) goto done; 697 698 offset += len; 699 if (offset + len > fsize) 700 break; 701 702 buf = NULL; 703 _td_attach_cd(cd); 704 sts = _sd_alloc_buf((blind_t)(unsigned long)cd, offset, len, 705 NSC_WRBUF, &buf); 706 if (sts > 0) { 707 cmn_err(CE_WARN, "!ch%d getbuf error(WRBUF)%d", i, sts); 708 goto done; 709 } 710 (void) _sd_copy_handle(fbuf, buf, 0, offset, len, j); 711 712 sts = len; 713 while (sts > 0) { 714 if (forw && _sd_hwrite(buf, offset + len - sts, 715 12, 0) > 0) { 716 cmn_err(CE_WARN, "!ch %d fwwr err", i); 717 test_stop = 1; 718 } 719 sts -= 12; 720 if (!forw && _sd_hwrite(buf, offset + sts, 12, 0) > 0) { 721 cmn_err(CE_WARN, "!ch %d rvwr err", i); 722 test_stop = 1; 723 } 724 } 725 if (sts = _sd_free_buf(buf)) { 726 cmn_err(CE_WARN, "!ch %d freebuf error %d", i, sts); 727 goto done; 728 } 729 _td_detach_cd(cd); 730 } 731 offset = 0; 732 for (j = 0; j < loops; j++) { 733 if (test_stop == 1) goto done; 734 735 offset += len; 736 if (offset + len > fsize) 737 break; 738 739 buf = NULL; 740 _td_attach_cd(cd); 741 sts = _sd_alloc_buf((blind_t)(unsigned long)cd, offset, len, 742 NSC_RDBUF, &buf); 743 if (sts > 0) { 744 cmn_err(CE_WARN, "!ch%d getbuf error(WRBUF)%d", i, sts); 745 goto done; 746 } 747 (void) _sd_compare_handle(fbuf, buf, 0, offset, len, j); 748 749 if (sts = _sd_free_buf(buf)) { 750 cmn_err(CE_WARN, "!ch %d freebuf error %d", i, sts); 751 goto done; 752 } 753 _td_detach_cd(cd); 754 } 755 done: 756 if (sts = _sd_free_buf(fbuf)) 757 cmn_err(CE_WARN, "!child %d freebuf error %d", i, sts); 758 cmn_err(CE_NOTE, "!TEST OVER : rwloop_seq_%s() child %d", 759 forw ? "forw" : "rev", i); 760 } 761 762 static int 763 _sd_copy_pattern_to_handle(_sd_buf_handle_t *handle, nsc_off_t fba_pos, 764 nsc_size_t fba_len) 765 { 766 sdbc_cblk_fba_t st_cblk_len; /* FBA len of starting cache block */ 767 sdbc_cblk_fba_t end_cblk_len; /* FBA len of ending cache block */ 768 sdbc_cblk_fba_t st_cblk_off; /* FBA offset into starting cblock */ 769 nsc_size_t cur_fba_len; 770 int i; 771 _sd_cctl_t *cc_ent; 772 773 cc_ent = handle->bh_centry; 774 while (CENTRY_BLK(cc_ent) != FBA_TO_BLK_NUM(fba_pos)) 775 cc_ent = cc_ent->cc_chain; 776 777 cur_fba_len = fba_len; 778 st_cblk_off = BLK_FBA_OFF(fba_pos); 779 st_cblk_len = (BLK_FBAS - st_cblk_off); 780 if ((nsc_size_t)st_cblk_len >= fba_len) { 781 end_cblk_len = 0; 782 st_cblk_len = (sdbc_cblk_fba_t)fba_len; 783 } else 784 end_cblk_len = BLK_FBA_OFF(fba_pos + fba_len); 785 786 for (i = 0; i < (int)FBA_SIZE(st_cblk_len); i += 4) 787 *((uint_t *)(void *)(cc_ent->cc_data + FBA_SIZE(st_cblk_off) + 788 i)) = nsc_usec(); 789 cur_fba_len -= st_cblk_len; 790 cc_ent = cc_ent->cc_chain; 791 792 while (cur_fba_len > (nsc_size_t)end_cblk_len) { 793 for (i = 0; i < CACHE_BLOCK_SIZE; i += 4) { 794 unsigned int usec = nsc_usec(); 795 bcopy(&usec, cc_ent->cc_data + i, 4); 796 } 797 cc_ent = cc_ent->cc_chain; 798 cur_fba_len -= BLK_FBAS; 799 } 800 if (cur_fba_len) { 801 for (i = 0; i < (int)FBA_SIZE(end_cblk_len); i += 4) { 802 unsigned int usec = nsc_usec(); 803 bcopy(&usec, cc_ent->cc_data + i, 4); 804 } 805 } 806 return (0); 807 } 808 809 static int 810 _sd_copy_handle(_sd_buf_handle_t *handle1, 811 _sd_buf_handle_t *handle2, 812 nsc_off_t fba_pos1, 813 nsc_off_t fba_pos2, 814 nsc_size_t fba_len, 815 int skew) 816 { 817 sdbc_cblk_fba_t st_cblk_len; /* FBA len of starting cache block */ 818 sdbc_cblk_fba_t end_cblk_len; /* FBA len of ending cache block */ 819 sdbc_cblk_fba_t st_cblk_off; /* FBA offset into starting cblock */ 820 nsc_size_t cur_fba_len; 821 _sd_cctl_t *cc_ent, *cc_ent1; 822 unsigned char *skew_word; 823 int skew_count = 0; 824 825 ASSERT_HANDLE_LIMITS(handle1, fba_pos1, fba_len); 826 ASSERT_HANDLE_LIMITS(handle2, fba_pos2, fba_len); 827 828 cc_ent = handle1->bh_centry; 829 while (CENTRY_BLK(cc_ent) != FBA_TO_BLK_NUM(fba_pos1)) 830 cc_ent = cc_ent->cc_chain; 831 832 cc_ent1 = handle2->bh_centry; 833 while (CENTRY_BLK(cc_ent1) != FBA_TO_BLK_NUM(fba_pos2)) 834 cc_ent1 = cc_ent1->cc_chain; 835 836 837 if (BLK_FBA_OFF(fba_pos1) != BLK_FBA_OFF(fba_pos2)) { 838 cmn_err(CE_WARN, "!Cannot copy unaligned handles"); 839 return (0); 840 } 841 842 cur_fba_len = fba_len; 843 st_cblk_off = BLK_FBA_OFF(fba_pos1); 844 st_cblk_len = (BLK_FBAS - st_cblk_off); 845 if ((nsc_size_t)st_cblk_len >= fba_len) { 846 end_cblk_len = 0; 847 st_cblk_len = (sdbc_cblk_fba_t)fba_len; 848 } else 849 end_cblk_len = BLK_FBA_OFF(fba_pos1 + fba_len); 850 851 skew_word = cc_ent->cc_data + FBA_SIZE(st_cblk_off); 852 *skew_word = skew | (++skew_count << 24); 853 bcopy(cc_ent->cc_data + FBA_SIZE(st_cblk_off), cc_ent1->cc_data + 854 FBA_SIZE(st_cblk_off), FBA_SIZE(st_cblk_len)); 855 cur_fba_len -= st_cblk_len; 856 cc_ent = cc_ent->cc_chain; 857 cc_ent1 = cc_ent1->cc_chain; 858 859 while (cur_fba_len > (nsc_size_t)end_cblk_len) { 860 skew_word = cc_ent->cc_data; 861 *skew_word = skew | (++skew_count << 24); 862 bcopy(cc_ent->cc_data, cc_ent1->cc_data, CACHE_BLOCK_SIZE); 863 cc_ent = cc_ent->cc_chain; 864 cc_ent1 = cc_ent1->cc_chain; 865 cur_fba_len -= BLK_FBAS; 866 } 867 if (cur_fba_len) { 868 skew_word = cc_ent->cc_data; 869 *skew_word = skew | (++skew_count << 24); 870 bcopy(cc_ent->cc_data, cc_ent1->cc_data, 871 FBA_SIZE(end_cblk_len)); 872 } 873 return (0); 874 } 875 876 static int 877 _sd_compare_handle(_sd_buf_handle_t *handle1, _sd_buf_handle_t *handle2, 878 nsc_off_t fba_pos1, nsc_off_t fba_pos2, nsc_size_t fba_len, int skew) 879 { 880 sdbc_cblk_fba_t st_cblk_len; /* FBA len of starting cache block */ 881 sdbc_cblk_fba_t end_cblk_len; /* FBA len of ending cache block */ 882 sdbc_cblk_fba_t st_cblk_off; /* FBA offset into starting cblock */ 883 nsc_size_t cur_fba_len; 884 _sd_cctl_t *cc_ent, *cc_ent1; 885 unsigned char *skew_word; 886 int skew_count = 0; 887 888 ASSERT_HANDLE_LIMITS(handle1, fba_pos1, fba_len); 889 ASSERT_HANDLE_LIMITS(handle2, fba_pos2, fba_len); 890 891 cc_ent = handle1->bh_centry; 892 while (CENTRY_BLK(cc_ent) != FBA_TO_BLK_NUM(fba_pos1)) 893 cc_ent = cc_ent->cc_chain; 894 895 cc_ent1 = handle2->bh_centry; 896 while (CENTRY_BLK(cc_ent1) != FBA_TO_BLK_NUM(fba_pos2)) 897 cc_ent1 = cc_ent1->cc_chain; 898 899 if (BLK_FBA_OFF(fba_pos1) != BLK_FBA_OFF(fba_pos2)) { 900 cmn_err(CE_WARN, "!Cannot compare unaligned handles"); 901 return (0); 902 } 903 904 cur_fba_len = fba_len; 905 st_cblk_off = BLK_FBA_OFF(fba_pos1); 906 st_cblk_len = (BLK_FBAS - st_cblk_off); 907 if ((nsc_size_t)st_cblk_len >= fba_len) { 908 end_cblk_len = 0; 909 st_cblk_len = (sdbc_cblk_fba_t)fba_len; 910 } else 911 end_cblk_len = BLK_FBA_OFF(fba_pos1 + fba_len); 912 913 skew_word = cc_ent->cc_data + FBA_SIZE(st_cblk_off); 914 *skew_word = skew | (++skew_count << 24); 915 if (bcmp(cc_ent->cc_data + FBA_SIZE(st_cblk_off), 916 cc_ent1->cc_data + FBA_SIZE(st_cblk_off), 917 FBA_SIZE(st_cblk_len)) != 0) 918 cmn_err(CE_WARN, "!Data mismatch fba_pos:%" NSC_SZFMT, 919 fba_pos2); 920 921 cur_fba_len -= st_cblk_len; 922 cc_ent = cc_ent->cc_chain; 923 cc_ent1 = cc_ent1->cc_chain; 924 925 while (cur_fba_len > (nsc_size_t)end_cblk_len) { 926 skew_word = cc_ent->cc_data; 927 *skew_word = skew | (++skew_count << 24); 928 if (bcmp(cc_ent->cc_data, cc_ent1->cc_data, 929 CACHE_BLOCK_SIZE) != 0) 930 cmn_err(CE_WARN, "!Data mismatch fba_pos:%" NSC_SZFMT, 931 fba_pos2); 932 933 cc_ent = cc_ent->cc_chain; 934 cc_ent1 = cc_ent1->cc_chain; 935 cur_fba_len -= BLK_FBAS; 936 } 937 if (cur_fba_len) { 938 skew_word = cc_ent->cc_data; 939 *skew_word = skew | (++skew_count << 24); 940 if (bcmp(cc_ent->cc_data, cc_ent1->cc_data, 941 FBA_SIZE(end_cblk_len)) != 0) 942 cmn_err(CE_WARN, "!Data mismatch fba_pos:%" NSC_SZFMT, 943 fba_pos2); 944 } 945 return (0); 946 } 947 948 /* 949 * Macro definition for waiting for an IO buffer to be allocated or a read 950 * to complete. Macro defined so code doesn't have to be typed each time 951 */ 952 #define WAIT_IO(st, cd, buf, l) \ 953 if ((st != NSC_DONE) && (st != NSC_HIT)) { \ 954 if (st != NSC_PENDING) \ 955 cmn_err(CE_WARN, "!alloc sts: %d", st); \ 956 else { \ 957 buf = wait_io(cd, &st); \ 958 if (st) { \ 959 cmn_err(CE_WARN, "!ch %d getbuf errpr %d\n", l, st); \ 960 if (buf) \ 961 (void) _sd_free_buf(buf); \ 962 return; \ 963 } \ 964 } \ 965 } 966 967 968 #undef _sd_write 969 970 static int tiodone, iosent, tioerr; 971 972 /* ARGSUSED */ 973 974 static void 975 myend(blind_t arg, nsc_off_t fba_pos, nsc_size_t fba_len, int error) 976 { 977 if (error) 978 tioerr++; 979 else tiodone++; 980 } 981 982 static int ckd_sskip = 3; 983 984 /* ARGSUSED3 */ 985 static void 986 _sd_direct_test(int c, int loop, int seed, int type) 987 { 988 nsc_size_t filesize; 989 int loops; 990 991 int cd; 992 int ckd_hd, recs, rec_size, ckd_doz; 993 int done_size; 994 clock_t st_time; 995 int i; 996 997 int ckd_hd_sz, rec_bsz; 998 int print_stuff; 999 int throttle; 1000 struct buf *bp; 1001 nsc_off_t curpos; 1002 1003 caddr_t caddr; 1004 iosent = 0; 1005 1006 print_stuff = 0; 1007 seed = gld[c].seed; 1008 rec_size = (seed & 0xff); 1009 recs = (seed & 0xf00)>>8; 1010 ckd_hd = (seed & 0xf000)>>12; 1011 ckd_doz = (seed & 0xf0000)>>16; 1012 throttle = (seed & 0xff00000)>>20; 1013 ckd_hd_sz = ckd_hd * 512; 1014 rec_bsz = rec_size * 512; 1015 1016 done_size = 0; 1017 tiodone = 0; 1018 curpos = 0; 1019 tioerr = 0; 1020 1021 if (strlen(devarray[c]) == 0) { 1022 cmn_err(CE_WARN, "!child %d devarray null\n", c); 1023 return; 1024 } 1025 if ((cd = _sd_open(devarray[c], dev_flag[c])) < 0) { 1026 cmn_err(CE_WARN, "!Open error %s child %d\n", devarray[c], c); 1027 return; 1028 } 1029 1030 caddr = (caddr_t)nsc_kmem_alloc(20 * 8192, KM_SLEEP, sdbc_local_mem); 1031 1032 (void) _sd_get_partsize((blind_t)(unsigned long)cd, &filesize); 1033 filesize = FBA_SIZE(filesize); 1034 loops = ((nsc_size_t)loop > (filesize / (60 * 1024))) ? 1035 (filesize / (60 * 1024)) : loop; 1036 1037 st_time = nsc_usec(); 1038 cmn_err(CE_CONT, "!Test 100: %s file %d cd %d loops %x seed\n", 1039 devarray[c], cd, loop, seed); 1040 cmn_err(CE_CONT, 1041 "!Test 100: %d recsize %d recs %d throttle %d hd %d doz\n", 1042 rec_size, recs, throttle, ckd_hd, ckd_doz); 1043 1044 for (i = 0; i < loops; i++) { 1045 curpos = i * 120; 1046 if (ckd_doz) { 1047 bp = sd_alloc_iob(_sd_cache_files[cd].cd_crdev, 1048 curpos, 20, B_WRITE); 1049 sd_add_mem(bp, caddr, ckd_hd_sz); 1050 (void) sd_start_io(bp, 1051 _sd_cache_files[cd].cd_strategy, myend, NULL); 1052 iosent++; 1053 curpos += ckd_sskip; 1054 } 1055 if (ckd_doz == 2) { 1056 bp = sd_alloc_iob(_sd_cache_files[cd].cd_crdev, 1057 curpos, 20, B_WRITE); 1058 sd_add_mem(bp, caddr, 4096-ckd_sskip*512); 1059 (void) sd_start_io(bp, 1060 _sd_cache_files[cd].cd_strategy, myend, NULL); 1061 iosent++; 1062 curpos += 4096-ckd_sskip*512; 1063 } 1064 bp = sd_alloc_iob(_sd_cache_files[cd].cd_crdev, 1065 curpos, 20, B_WRITE); 1066 sd_add_mem(bp, caddr, recs * rec_bsz); 1067 (void) sd_start_io(bp, 1068 _sd_cache_files[cd].cd_strategy, myend, NULL); 1069 iosent++; 1070 1071 done_size += recs * rec_bsz; 1072 1073 if (tiodone && ((tiodone / 300) > print_stuff)) { 1074 cmn_err(CE_CONT, "!Done %d ios %d size in %lu time\n", 1075 tiodone, 1076 ckd_doz ? ((ckd_doz == 2) ? 1077 (tiodone * (recs * rec_bsz + 4096)) / 3: 1078 (tiodone * (recs * rec_bsz + ckd_hd_sz)) / 2) : 1079 (tiodone * (recs * rec_bsz)), 1080 (nsc_usec() - st_time) / 1000); 1081 print_stuff++; 1082 } 1083 while ((iosent - (tiodone + tioerr)) > throttle) 1084 ; 1085 } 1086 while ((tiodone + tioerr) < iosent) { 1087 if (tiodone && ((tiodone / 300) > print_stuff)) { 1088 cmn_err(CE_CONT, "!Done %d ios %d size in %lu time\n", 1089 tiodone, 1090 ckd_doz ? ((ckd_doz == 2) ? 1091 (tiodone * (recs * rec_bsz + 4096)) / 3: 1092 (tiodone * (recs * rec_bsz + ckd_hd_sz)) / 2) : 1093 (tiodone * (recs * rec_bsz)), 1094 (nsc_usec() - st_time) / 1000); 1095 print_stuff++; 1096 } 1097 } 1098 cmn_err(CE_CONT, "!Done %d ios %d size in %lu time\n", 1099 tiodone, 1100 ckd_doz ? ((ckd_doz == 2) ? 1101 (tiodone * (recs * rec_bsz + 4096)) / 3: 1102 (tiodone * (recs * rec_bsz + ckd_hd_sz)) / 2) : 1103 (tiodone * (recs * rec_bsz)), 1104 (nsc_usec() - st_time) / 1000); 1105 1106 print_stuff++; 1107 nsc_kmem_free(caddr, 20 * 8192); 1108 } 1109 1110 static void 1111 set_parameters(void) 1112 { 1113 test_stop = 0; 1114 } 1115 1116 static nsc_mem_t *dma_test = NULL; 1117 static int *dma_mem = NULL; 1118 1119 static int 1120 init_dmatest(void) 1121 { 1122 dma_test = nsc_register_mem("dmatest:mem", NSC_MEM_GLOBAL, 0); 1123 dma_mem = (int *)nsc_kmem_zalloc(4096, 0, dma_test); 1124 if (!dma_mem) { 1125 cmn_err(CE_NOTE, "!could not get rm mem\n"); 1126 return (1); 1127 } 1128 cmn_err(CE_NOTE, "!rm = 0x%p\n", (void *)dma_mem); 1129 return (0); 1130 } 1131 1132 /*ARGSUSED*/ 1133 static void 1134 release_dmatest(void) 1135 { 1136 nsc_kmem_free(dma_mem, 1); 1137 nsc_unregister_mem(dma_test); 1138 dma_test = NULL; 1139 dma_mem = NULL; 1140 } 1141 /*ARGSUSED*/ 1142 static void 1143 test_dma_loop(int net, int seg) 1144 { 1145 delay(3*HZ); 1146 1147 if (!dma_mem && init_dmatest()) { 1148 cmn_err(CE_WARN, "!test_dma_loop: init failed"); 1149 return; 1150 } 1151 1152 /* 1153 * The body of test loop is removed since we don't use any more 1154 */ 1155 1156 release_dmatest(); 1157 }