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 }