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 /*
  23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /* #include <version.h> SKK */
  28 #include <errno.h>
  29 #include <sys/types.h>
  30 #include <sys/time.h>
  31 #include <sys/param.h>
  32 #include <sys/inttypes.h>
  33 #include <stdio.h>
  34 #include <strings.h>
  35 #include <fcntl.h>
  36 #include <sys/shm.h>
  37 #include <sys/wait.h>
  38 #include <unistd.h>
  39 #include <nsctl.h>
  40 
  41 #include <sys/nsctl/sd_cache.h>
  42 #include <sys/nsctl/sd_conf.h>
  43 
  44 #include <stdlib.h>
  45 #include <thread.h>
  46 #include <synch.h>
  47 
  48 #define MAXPARTS        100     /* Max disks */
  49 #define MAXBUF  65536   /* Max buffer size in long words */
  50 #define DISKLIST        "disk_config"   /* Default config file */
  51 #define DEF_SIZE        8192    /* Default buffer size */
  52 #define DEF_LOOP        1000    /* Loops for test */
  53 #define RAND_LOOPS      DEF_LOOP        /* # of random ios to do */
  54 
  55 /*
  56  *  >>>>>>>>> USER LEVEL SD CACHE DIAGNOSTICS <<<<<<<<<<
  57  *
  58  *  Write and read data blocks w/multiple processes
  59  *  Starts one process for each partition specified in
  60  *  the config file
  61  */
  62 
  63 int  buf1[MAXBUF];
  64 int  buf2[MAXBUF];
  65 char name[MAXPARTS][80];
  66 int  pattern[MAXPARTS];
  67 int  bufsize = DEF_SIZE;
  68 int  fba_num_bufsize;
  69 nsc_size_t  loops   = DEF_LOOP;
  70 nsc_size_t  r_loops   = RAND_LOOPS;
  71 int  fsize   = -1;
  72 int  readercount = 3;
  73 int  Rflag = O_EXCL;
  74 char config_file[32];
  75 
  76 int
  77 read_parts()
  78 {
  79         FILE *dfile;
  80         int   partitions = 0;
  81         int i;
  82 
  83         dfile = fopen(config_file, "r");
  84         if (dfile == NULL) {
  85                 (void) printf("cannot open file: %s\n", config_file);
  86                 perror("fopen");
  87                 exit(errno);
  88         }
  89         for (i = 0; i < MAXPARTS; i++) {
  90                 if (fscanf(dfile, "%s %x", name[i], (uint_t *)&pattern[i]) ==
  91                     EOF) {
  92                         break;
  93                 } else
  94                         if (name[i][0] == '#' || strchr(name[i], '/') == NULL) {
  95                                 i--;
  96                                 continue;
  97                         }
  98                 partitions++;
  99         }
 100         (void) fclose(dfile);
 101         (void) printf("No. of partitions listed in file '%s' = %d\n\n",
 102                         config_file, partitions);
 103         return (partitions);
 104 }
 105 
 106 void
 107 print_usage()
 108 {
 109         (void) printf("Usage:\n");
 110         (void) printf(
 111 "sd_diag [-R] [-b <bufsize>] [-d <datasize>] [-l <loops>] [-r <readers>]\n");
 112         (void) printf(
 113 "        [-f <disk_config_file>] <test#>\n");
 114         (void) printf(" test 1 = random read/write\n");
 115         (void) printf("      2 = random read/write/verify, read after write\n");
 116         (void) printf("      3 = random read/write/verify,");
 117         (void) printf(" all reads after all writes\n");
 118         (void) printf("      4 = sequential read/write\n");
 119         (void) printf("      5 = sequential write/read/verify,");
 120         (void) printf(" all reads after all writes\n");
 121         (void) printf(
 122         "      6 = altenating top/bottom sequential read/write/verify\n");
 123         (void) printf("      7 = multiple readers/1 random writer\n");
 124         (void) printf("      8 = random writes\n");
 125         (void) printf("      9 = sequential write of known data\n");
 126         (void) printf("      10 = sequential copy of datasize disk/verify\n");
 127         (void) printf("      11 = sequential read/verify test 9 data -");
 128         (void) printf(" then clear data with timestamp\n");
 129         (void) printf("      12 = sequential read/verify test 9 data -");
 130         (void) printf(" no clear data\n");
 131         (void) printf("\n");
 132         (void) printf("  <bufsize> in bytes (minimum is 512 bytes)\n");
 133         (void) printf("  <datasize> in Mbytes per disk\n");
 134         (void) printf("  <loops> is count of reads/writes,\n");
 135         (void) printf("          loops = 0 tests entire datasize disk");
 136         (void) printf(" for sequential tests.\n");
 137         (void) printf("          loops = 0 performs %d I/Os for the random "
 138             "tests\n", RAND_LOOPS);
 139         (void) printf("  <readers> is count of readers for test #7 (default "
 140             "is 3).\n");
 141         (void) printf(" [ defaults: bufsize = %d bytes, loops = %d,",
 142                         DEF_SIZE, DEF_LOOP);
 143         (void) printf(" datasize = disksize ]\n");
 144         (void) printf("\n");
 145         (void) printf("  -R : do nsc_reserve(), nsc_release(0 around each "
 146             "I/O\n");
 147 }
 148 
 149 void
 150 parse_opts(int argc, char *argv[])
 151 {
 152         extern char *optarg;
 153         int c;
 154 
 155         while ((c = getopt(argc, argv, "b:d:l:r:Rf:")) != -1) {
 156                 switch (c) {
 157                         case 'f':
 158                         /* printf("\n%s", optarg); */
 159                         (void) strcpy(config_file, optarg);
 160                         break;
 161                 case 'b':
 162                         /* bufsize between 1*512 and 512*512 */
 163                         bufsize = strtol(optarg, 0, 0);
 164                         if (bufsize > (MAXBUF*4))
 165                                 bufsize = MAXBUF*4;
 166                         else if (bufsize < FBA_SIZE(1))
 167                             bufsize = FBA_SIZE(1);
 168                         break;
 169                 case 'd':
 170                         /* convert datasize from Mb's to fba */
 171                         fsize = strtol(optarg, 0, 0) *  FBA_NUM(1 << 20);
 172                         break;
 173                 case 'l':
 174                         loops = (nsc_size_t)strtoll(optarg, 0, 0);
 175                         break;
 176                 case 'r':
 177                         /* count of readers for test 7 */
 178                         readercount = strtol(optarg, 0, 0);
 179                         break;
 180                 case 'R':
 181                         /* do reserve, release on a per io basis */
 182                         Rflag = 0;
 183                         break;
 184                 case '?':
 185                         print_usage();
 186                         exit(0);
 187                 }
 188         }
 189         bufsize &= ~FBA_MASK; /* multiple of 512 bytes for SECTMODE I/O */
 190         fba_num_bufsize = FBA_NUM(bufsize);
 191 
 192         /*  set #ios for random io tests */
 193         if (loops != 0)
 194                 r_loops = loops;
 195 
 196 }
 197 
 198 nsc_size_t
 199 set_part_size(char *path, nsc_fd_t *sdfd)
 200 {
 201         nsc_size_t filesize;
 202         int rc;
 203 
 204         rc = nsc_partsize(sdfd, &filesize); /* partsize in FBAs (512 bytes) */
 205         if (rc < 0 || filesize == 0) {
 206                 (void) fprintf(stderr,
 207                     "set_part_size: cannot access partition size");
 208                 (void) fprintf(stderr, " for %s\n", path);
 209                 (void) nsc_close(sdfd);
 210                 exit(1);
 211         }
 212 
 213         (void) printf("Partition %s, size:%" NSC_SZFMT " blocks\n", path,
 214             filesize);
 215 
 216         if (fsize != -1 && fsize < filesize)
 217                 filesize = fsize;
 218         filesize -= fba_num_bufsize;
 219         if (filesize < fba_num_bufsize) {
 220                 (void) printf("ERROR: Max block size %" NSC_SZFMT "\n",
 221                     filesize);
 222                 (void) nsc_close(sdfd);
 223                 exit(0);
 224         }
 225 
 226         return (filesize);
 227 }
 228 
 229 int
 230 do_sdtest1(int fd, nsc_size_t loops, nsc_size_t filesize)
 231 {
 232         nsc_off_t seekpos;
 233         nsc_size_t i;
 234         ssize_t r;
 235 
 236         for (i = 0; i < loops; i++) {
 237                 seekpos = (
 238 #ifdef NSC_MULTI_TERABYTE
 239                     ((nsc_off_t)rand() << 48) | ((nsc_off_t)rand() << 32) |
 240 #endif
 241                     (rand() << 16) | rand()) % filesize;
 242                 r = pwrite(fd, buf1, bufsize, (off_t)(seekpos << SCTRSHFT));
 243                 if (r <= 0) {
 244                         perror("Test1: write");
 245                         return (1);
 246                 }
 247                 seekpos = (
 248 #ifdef NSC_MULTI_TERABYTE
 249                     ((nsc_off_t)rand() << 48) | ((nsc_off_t)rand() << 32) |
 250 #endif
 251                     (rand() << 16) | rand()) % filesize;
 252                 r = pread(fd, buf2, bufsize, (off_t)(seekpos << SCTRSHFT));
 253                 if (r <= 0) {
 254                         perror("Test1: read");
 255                         return (1);
 256                 }
 257         }
 258         return (0);
 259 }
 260 
 261 void
 262 gen_data(int *buffer, int size)
 263 {
 264         int i;
 265 
 266         size /= 4;
 267         for (i = 0; i < size; i++)
 268                 buffer[i] = rand() << 16 | rand();
 269 }
 270 
 271 int
 272 do_sdtest2(int fd, nsc_size_t loops, nsc_size_t filesize, int h)
 273 {
 274         nsc_off_t seekpos;
 275         int err = 0;
 276         ssize_t r;
 277         nsc_size_t i;
 278 
 279         for (i = 0; i < loops; i++) {
 280                 seekpos = (
 281 #ifdef NSC_MULTI_TERABYTE
 282                     ((nsc_off_t)rand() << 48) | ((nsc_off_t)rand() << 32) |
 283 #endif
 284                     (rand() << 16) | rand()) % filesize;
 285                 gen_data(buf1, bufsize);
 286                 r = pwrite(fd, buf1, bufsize, (off_t)(seekpos << SCTRSHFT));
 287                 if (r <= 0) {
 288                         perror("Test2: write");
 289                         err++;
 290                         return (err);
 291                 }
 292                 r = pread(fd, buf2, bufsize, (off_t)(seekpos << SCTRSHFT));
 293                 if (r <= 0) {
 294                         perror("Test2: read");
 295                         err++;
 296                         return (err);
 297                 }
 298                 if (memcmp(buf1, buf2, bufsize)) {
 299                         (void) printf("Test2: Data corruption,"
 300                             " fd:%s, fpos:%" PRId64 ", len:%d\n",
 301                             name[h], (int64_t)(seekpos << SCTRSHFT),
 302                             bufsize);
 303                         err++;
 304                 }
 305         }
 306         return (err);
 307 }
 308 
 309 int
 310 do_sdtest3(int fd, nsc_size_t loops, nsc_size_t filesize, int h, nsc_fd_t *sdfd)
 311 {
 312         nsc_off_t *seekpos;
 313         int err = 0;
 314         nsc_size_t i;
 315         ssize_t r;
 316 
 317         seekpos = malloc(loops*sizeof (nsc_off_t));
 318         if (seekpos == NULL) {
 319                 perror("Test3: malloc");
 320                 (void) nsc_close(sdfd);
 321                 exit(errno);
 322         }
 323         gen_data(buf1, bufsize);
 324 
 325         for (i = 0; i < loops; i++) {
 326                 seekpos[i] = (
 327 #ifdef NSC_MULTI_TERABYTE
 328                     ((nsc_off_t)rand() << 48) | ((nsc_off_t)rand() << 32) |
 329 #endif
 330                     (rand() << 16) | rand()) % filesize;
 331                 seekpos[i] -= seekpos[i] % fba_num_bufsize;
 332                 r = pwrite(fd, buf1, bufsize, (off_t)(seekpos[i] << SCTRSHFT));
 333                 if (r <= 0) {
 334                         perror("Test3: write");
 335                         err++;
 336                         goto cleanup;
 337                 }
 338         }
 339         for (i = 0; i < loops; i++) {
 340                 buf2[0] = '\0'; /* clear buf to make sure something is read */
 341                 r = pread(fd, buf2, bufsize, (off_t)(seekpos[i] << SCTRSHFT));
 342                 if (r <= 0) {
 343                         perror("Test3: read");
 344                         err++;
 345                         goto cleanup;
 346                 }
 347                 if (memcmp(buf1, buf2, bufsize)) {
 348                         (void) printf("Data corruption, fd:%s, fpos:%" PRId64
 349                             ", len:%d\n", name[h],
 350                             (int64_t)(seekpos[i] << SCTRSHFT), bufsize);
 351                         err++;
 352                 }
 353         }
 354 
 355 cleanup:
 356         free(seekpos);
 357         return (err);
 358 }
 359 
 360 int
 361 do_sdtest4(int fd, nsc_size_t loops, nsc_size_t filesize)
 362 {
 363         ssize_t r;
 364         nsc_size_t i;
 365 
 366         /*
 367          * Do sequential reads/writes for loops number
 368          * of bufsize chunks, unless loops == 0, then do
 369          * entire disk.
 370          * 1. sequential reads from the top down,
 371          * 2. sequential writes from the top down,
 372          * 3. sequential reads from the bottom up,
 373          * 4. sequential writes from the bottom up.
 374          */
 375         if ((loops > (filesize / fba_num_bufsize)) || (!loops))
 376             loops = filesize / fba_num_bufsize; /* entire disk */
 377 
 378         for (i = 0; i < loops; i++) {
 379                 r = pread(fd, buf2, bufsize, (i*fba_num_bufsize) << SCTRSHFT);
 380                 if (r <= 0) {
 381                         perror("Test4: read");
 382                         return (1);
 383                 }
 384         }
 385         for (i = 0; i < loops; i++) {
 386                 r = pwrite(fd, buf1, bufsize, (i*fba_num_bufsize) << SCTRSHFT);
 387                 if (r <= 0) {
 388                         perror("Test4: write");
 389                         return (1);
 390                 }
 391         }
 392         for (i = loops - 1; i + 1 > 0; i--) {
 393                 r = pread(fd, buf2, bufsize, (i*fba_num_bufsize) << SCTRSHFT);
 394                 if (r <= 0) {
 395                         perror("Test4: read");
 396                         return (1);
 397                 }
 398         }
 399         for (i = loops - 1; i + 1 > 0; i--) {
 400                 r = pwrite(fd, buf1, bufsize, (i*fba_num_bufsize) << SCTRSHFT);
 401                 if (r <= 0) {
 402                         perror("Test4: write");
 403                         return (1);
 404                 }
 405         }
 406         return (0);
 407 }
 408 
 409 int
 410 do_sdtest5(int fd, nsc_size_t loops, nsc_size_t filesize, int h)
 411 {
 412         int err = 0;
 413         ssize_t r;
 414         nsc_size_t i;
 415 
 416         /*
 417          * Do sequential writes with verify reads for loops number
 418          * of bufsize chunks, unless loops == 0, then do
 419          * entire disk.
 420          * 1. sequential writes from the top down,
 421          * 2. sequential reads from the top down with verify,
 422          * 3. sequential writes from the bottom up,
 423          * 4. sequential reads from the bottom up with verify.
 424          */
 425         if ((loops > (filesize / fba_num_bufsize)) || (!loops))
 426             loops = filesize / fba_num_bufsize; /* entire disk */
 427 
 428         gen_data(buf1, bufsize);
 429 
 430         for (i = 0; i < loops; i++) {
 431                 r = pwrite(fd, buf1, bufsize, (i*fba_num_bufsize) << SCTRSHFT);
 432                 if (r <= 0) {
 433                         perror("Test5: write");
 434                         err++;
 435                         return (err);
 436                 }
 437         }
 438         for (i = 0; i < loops; i++) {
 439                 buf2[0] = '\0'; /* clear buf to make sure something is read */
 440                 r = pread(fd, buf2, bufsize, (i*fba_num_bufsize) << SCTRSHFT);
 441                 if (r <= 0) {
 442                         perror("Test5: read");
 443                         err++;
 444                         return (err);
 445                 }
 446                 if (memcmp(buf1, buf2, bufsize)) {
 447                         (void) printf("Test5: Data corruption,"
 448                             " fd:%s, fpos:%" NSC_SZFMT ", len:%d\n",
 449                             name[h], i, bufsize);
 450                         err++;
 451                 }
 452         }
 453 
 454         gen_data(buf1, bufsize);
 455 
 456         for (i = loops - 1; i + 1 > 0; i--) {
 457                 r = pwrite(fd, buf1, bufsize, (i*fba_num_bufsize) << SCTRSHFT);
 458                 if (r <= 0) {
 459                         perror("Test5: write");
 460                         err++;
 461                         return (err);
 462                 }
 463         }
 464         for (i = loops - 1; i + 1 > 0; i--) {
 465                 buf2[0] = '\0'; /* clear buf to make sure something is read */
 466                 r = pread(fd, buf2, bufsize, (i*fba_num_bufsize) << SCTRSHFT);
 467                 if (r <= 0) {
 468                         perror("Test5: read");
 469                         err++;
 470                         return (err);
 471                 }
 472                 if (memcmp(buf1, buf2, bufsize)) {
 473                         (void) printf("Test5: Data corruption,"
 474                             " fd:%s, fpos:%" NSC_SZFMT ", len:%d\n",
 475                             name[h], i, bufsize);
 476                         err++;
 477                 }
 478         }
 479         return (err);
 480 }
 481 
 482 
 483 int
 484 do_sdtest6(int fd, nsc_size_t loops, nsc_size_t filesize, int h)
 485 {
 486         int err = 0;
 487         nsc_size_t i;
 488         ssize_t r;
 489         nsc_size_t endloop = filesize / fba_num_bufsize;
 490         int  buf3[MAXBUF];
 491         int  buf4[MAXBUF];
 492         nsc_off_t  top_pos, bottom_pos;
 493 
 494         /*
 495          * Do alternating top down and bottom up sequential writes
 496          * (working towards middle) and verify with reads
 497          * for loops number of bufsize chunks, unless loops == 0, then do
 498          * entire disk.
 499          */
 500         if ((loops > (filesize / fba_num_bufsize)) || (!loops))
 501             loops = filesize / fba_num_bufsize; /* entire disk */
 502 
 503         for (i = 0; i < loops; i++) {
 504                 gen_data(buf1, bufsize);
 505                 bottom_pos = i*fba_num_bufsize;
 506                 r = pwrite(fd, buf1, bufsize, (off_t)(bottom_pos << SCTRSHFT));
 507                 if (r <= 0) {
 508                         perror("Test6: write");
 509                         err++;
 510                         return (err);
 511                 }
 512                 gen_data(buf2, bufsize);
 513                 top_pos = (endloop - i - 1)*fba_num_bufsize;
 514 
 515                 /* Make sure we don't collide in the middle */
 516 
 517                 if (abs(top_pos - bottom_pos) < fba_num_bufsize)
 518                         top_pos = bottom_pos + fba_num_bufsize;
 519 
 520                 r = pwrite(fd, buf2, bufsize, (off_t)(top_pos << SCTRSHFT));
 521                 if (r <= 0) {
 522                         perror("Test6: write");
 523                         err++;
 524                         return (err);
 525                 }
 526                 r = pread(fd, buf3, bufsize, (off_t)(bottom_pos << SCTRSHFT));
 527                 if (r <= 0) {
 528                         perror("Test6: read");
 529                         err++;
 530                         return (err);
 531                 }
 532                 if (memcmp(buf1, buf3, bufsize)) {
 533                         (void) printf("Data corruption(1), fd:%s, fpos:%"
 534                             PRId64 ", len:%d\n", name[h],
 535                             (int64_t)(bottom_pos << SCTRSHFT), bufsize);
 536                         err++;
 537                 }
 538                 r = pread(fd, buf4, bufsize, (off_t)(top_pos << SCTRSHFT));
 539                 if (r <= 0) {
 540                         perror("Test6: read");
 541                         return (1);
 542                 }
 543                 if (memcmp(buf2, buf4, bufsize)) {
 544                         (void) printf("Test6: Data corruption(2),"
 545                             " fd:%s, fpos:%" PRId64 ", len:%d\n",
 546                             name[h], (int64_t)(top_pos << SCTRSHFT), bufsize);
 547                         err++;
 548                 }
 549         }
 550         return (err);
 551 }
 552 
 553 int shmid;
 554 
 555 #define MAXREADERS 32
 556 
 557 struct shm_struct {
 558         int writebuf[MAXBUF];
 559         volatile nsc_off_t writepos;
 560         int quit;
 561         int err;
 562         mutex_t err_mutex;
 563         int rd_done[MAXREADERS];
 564         int rd_done_mask[MAXREADERS];
 565 } *shm;
 566 
 567 #define WRITEBUF (shm->writebuf)
 568 #define WRITEPOS (shm->writepos)
 569 
 570 #define QUIT    (shm->quit)
 571 #define ERR     (shm->err)
 572 #define ERRMUTEX (shm->err_mutex)
 573 #define RD_DONE (shm->rd_done)
 574 #define RD_DONE_MASK (shm->rd_done_mask)
 575 
 576 #define LOCKWRITE
 577 #define LOCKREAD(i)
 578 
 579 /*  Clear RD_DONE and Set WRITEPOS  */
 580 #define FREEWRITE { \
 581         bzero(RD_DONE, sizeof (RD_DONE)); \
 582         WRITEPOS = wr_pos; }
 583 
 584 /*  Reader i+1 marks himself as finished  */
 585 #define FREEREAD(i) (RD_DONE[(i)] = 1)
 586 
 587 
 588 int
 589 do_sdtest7read(int fd, int h, int which)
 590 {
 591         int err;
 592         ssize_t r_rd;
 593         nsc_off_t curr_pos;
 594         nsc_size_t loop_cnt;
 595         err = 0; curr_pos = 0; loop_cnt = 0;
 596         for (;;) {
 597                 /* Already read this? */
 598                 if (curr_pos == WRITEPOS) {
 599                         if (!QUIT) {
 600                                 continue;
 601                         } else {
 602                                 /*  Time to go!  */
 603                                 /* printf("Quitting [%d]\n", which+1); */
 604                                 break;
 605                         }
 606                 }
 607 
 608                 /* get location to read from */
 609                 curr_pos = WRITEPOS;
 610 
 611                 r_rd = pread(fd, buf1, bufsize, (curr_pos << SCTRSHFT));
 612                 loop_cnt += 1;
 613                 if (r_rd <= 0) {
 614                         FREEREAD(which);
 615                         perror("Test7: read");
 616                         err += 1;
 617                         continue;
 618                 }
 619 
 620                 if (memcmp(buf1, WRITEBUF, bufsize)) {
 621                         FREEREAD(which);
 622                         (void) printf("\nTest7: Data corruption, reader #%d, "
 623                             "fd:%s, \
 624                                 fpos:%" PRId64 ", len:%d\n", which + 1, name[h],
 625                                 (int64_t)(curr_pos << SCTRSHFT), bufsize);
 626                         err += 1;
 627                         continue;
 628                 }
 629 
 630                 FREEREAD(which);
 631         }
 632 
 633         (void) printf(
 634             "Partition %s, Test 7, reader #%d:  %d errors %lld loops\n",
 635                 name[h], which+1, err, loop_cnt);
 636 
 637         if (err > 0) {
 638                 (void) mutex_lock(&ERRMUTEX);
 639                 ERR += err;
 640                 (void) mutex_unlock(&ERRMUTEX);
 641         }
 642 
 643         if (err)
 644                 return (1);
 645         else
 646                 return (0);
 647 }
 648 
 649 
 650 int
 651 do_sdtest7write(int fd, nsc_size_t filesize, int h)
 652 {
 653         int err = 0;
 654         ssize_t r;
 655         nsc_off_t wr_pos;
 656 
 657         /*  Wait for readers to finish  */
 658         while (memcmp(RD_DONE, RD_DONE_MASK, readercount*sizeof (int)))
 659                 ;
 660 
 661         gen_data(WRITEBUF, bufsize);
 662         wr_pos = (
 663 #ifdef NSC_MULTI_TERABYTE
 664             ((nsc_off_t)rand() << 48) | ((nsc_off_t)rand() << 32) |
 665 #endif
 666             (rand() << 16) | rand()) % filesize;
 667         r = pwrite(fd, WRITEBUF, bufsize, (off_t)(wr_pos << SCTRSHFT));
 668         if (r <= 0) {
 669                 FREEWRITE;
 670                 perror("Test7: write");
 671                 return (1);
 672         }
 673         FREEWRITE;
 674 
 675         /* verify write */
 676         r = pread(fd, buf1, bufsize, (off_t)(wr_pos << SCTRSHFT));
 677         if (r <= 0) {
 678                 perror("Test7: writer: read");
 679                 return (1);
 680         }
 681 
 682 
 683         if (memcmp(buf1, WRITEBUF, bufsize)) {
 684                 (void) printf("\nTest7: Data corruption in writer,"
 685                     " fd:%s, fpos:%" PRId64 ", len:%d\n",
 686                     name[h], (int64_t)(wr_pos << SCTRSHFT), bufsize);
 687                 err++;
 688         }
 689 
 690 
 691         return (err);
 692 }
 693 
 694 void
 695 init_shm()
 696 {
 697         int i;
 698 
 699         /*  Clear out everything  */
 700         bzero(shm, sizeof (struct shm_struct));
 701 
 702         (void) mutex_init(&ERRMUTEX, USYNC_PROCESS, NULL);
 703 
 704         /*   Set up mask (constant) to test reader doneness  */
 705         for (i = 0; i < readercount; i++)
 706                 RD_DONE_MASK[i] = 1;
 707 
 708         /* Mark all readers done - so writer can start  */
 709         for (i = 0; i < readercount; i++)
 710                 RD_DONE[i] = 1;
 711 }
 712 
 713 int
 714 do_sdtest7(int fd, nsc_size_t loops, nsc_size_t filesize, int h, nsc_fd_t *sdfd)
 715 {
 716         int r, i, err;
 717         nsc_size_t j;
 718 
 719         if ((shmid = shmget(IPC_PRIVATE, sizeof (struct shm_struct),
 720                                 IPC_CREAT | 0666)) < 0) {
 721                 perror("shmget error: ");
 722                 (void) nsc_close(sdfd);
 723                 exit(1);
 724         }
 725 
 726         shm = (struct shm_struct *)shmat(shmid, NULL, 0);
 727         if (shm == (struct shm_struct *)-1) {
 728                 perror("shmat error: ");
 729                 (void) nsc_close(sdfd);
 730                 exit(1); /* cleanup exits */
 731         }
 732 
 733         init_shm();
 734 
 735         /*  Start Readers  */
 736         for (i = 0; i < readercount; i++) {
 737                 r = fork();
 738                 if (r == 0) { /* child */
 739                         (void) do_sdtest7read(fd, h, i);
 740                         (void) nsc_close(sdfd);
 741                         exit(0);
 742                 } else
 743                         continue;
 744         }
 745 
 746         /*  Start Writer  */
 747         srand(getpid()); err = 0;
 748         for (j = 0; j < loops; j++) {
 749                 err += do_sdtest7write(fd, filesize, h);
 750         }
 751         QUIT = 1;
 752 
 753         (void) printf("\n\nPartition %s, Test 7, writer:  %d errors\n",
 754             name[h], err);
 755 
 756         for (i = 0; i < readercount; i++)
 757                 (void) wait(0);
 758 
 759         /*  No lock needed here - everybody's finished  */
 760         err += ERR;
 761 
 762         (void) mutex_destroy(&ERRMUTEX);
 763         (void) shmctl(shmid, IPC_RMID, 0);
 764         return (err);
 765 }
 766 
 767 int
 768 do_sdtest8(int fd, nsc_size_t loops, nsc_size_t filesize)
 769 {
 770         nsc_off_t seekpos;
 771         int err = 0;
 772         ssize_t r;
 773         nsc_size_t i;
 774 
 775         for (i = 0; i < loops; i++) {
 776                 seekpos = (
 777 #ifdef NSC_MULTI_TERABYTE
 778                     ((nsc_off_t)rand() << 48) | ((nsc_off_t)rand() << 32) |
 779 #endif
 780                     (rand() << 16) | rand()) % filesize;
 781                 gen_data(buf1, bufsize);
 782                 r = pwrite(fd, buf1, bufsize, (off_t)(seekpos << SCTRSHFT));
 783                 if (r <= 0) {
 784                         perror("Test8: write");
 785                         err++;
 786                         return (err);
 787                 }
 788         }
 789         return (err);
 790 }
 791 
 792 void
 793 gen_data_known(int *buffer, int size, int data)
 794 {
 795         int i;
 796 
 797         size /= 4;
 798         for (i = 0; i < size; i++)
 799                 buffer[i] = data;
 800 }
 801 
 802 int
 803 do_sdtest9(int fd, nsc_size_t loops, nsc_size_t filesize, int h)
 804 {
 805         int err = 0;
 806         ssize_t r;
 807         nsc_off_t fba_offset;
 808         nsc_size_t i, wrapval;
 809 
 810         /*
 811          * Test 9 will write a given pattern over and over Test 11 or
 812          * Test 12 will read same pattern.
 813          */
 814         /* Large loop value that would cause write overflow will wrap */
 815 
 816         gen_data_known(buf1, bufsize, pattern[h]);
 817 
 818         wrapval = filesize / fba_num_bufsize;
 819 
 820         if (loops == 0)
 821                 loops = wrapval;  /* entire disk */
 822 
 823         for (i = 0; i < loops; i++) {
 824                 fba_offset = i % wrapval;
 825                 r = pwrite(fd, buf1, bufsize,
 826                     (off_t)(fba_offset * fba_num_bufsize) << SCTRSHFT);
 827                 if (r <= 0) {
 828                         perror("Test9: write");
 829                         err++;
 830                         return (err);
 831                 }
 832         }
 833         return (err);
 834 }
 835 
 836 int
 837 do_sdtest10(int fd1, int fd2, nsc_size_t loops, nsc_size_t filesize1,
 838     nsc_size_t filesize2, int h)
 839 {
 840         nsc_size_t filesize;
 841         int err = 0;
 842         nsc_size_t i;
 843         ssize_t r;
 844 
 845         /*
 846          * Do sequential copy of disk1 to disk2 for loops number
 847          * of bufsize chunks, unless loops == 0, then copy size of
 848          * the smaller disk.
 849          * Go back and verify that the two disks are identical.
 850          */
 851 
 852         filesize = (filesize1 < filesize2) ? filesize1 : filesize2;
 853         if ((loops > (filesize / fba_num_bufsize)) || (!loops))
 854             loops = filesize / fba_num_bufsize;
 855 
 856         /* copy disk1 to to disk2 */
 857         for (i = 0; i < loops; i++) {
 858                 r = pread(fd1, buf1, bufsize,
 859                     (off_t)(i*fba_num_bufsize) << SCTRSHFT);
 860                 if (r <= 0) {
 861                         perror("Test10: read");
 862                         return (1);
 863                 }
 864                 r = pwrite(fd2, buf1, bufsize,
 865                     (off_t)(i*fba_num_bufsize) << SCTRSHFT);
 866                 if (r <= 0) {
 867                         perror("Test10: write");
 868                         return (1);
 869                 }
 870         }
 871 
 872         /* verify disks are identical */
 873         for (i = 0; i < loops; i++) {
 874                 buf1[0] = '\0'; /* clear buf to make sure something is read */
 875                 r = pread(fd1, buf1, bufsize,
 876                     (off_t)(i * fba_num_bufsize) << SCTRSHFT);
 877                 if (r <= 0) {
 878                         perror("Test10: read");
 879                         return (1);
 880                 }
 881                 buf2[0] = 'x';  /* make sure something is read */
 882                 r = pread(fd2, buf2, bufsize,
 883                     (off_t)(i * fba_num_bufsize) << SCTRSHFT);
 884                 if (r <= 0) {
 885                         perror("Test10: read");
 886                         return (1);
 887                 }
 888                 if (memcmp(buf1, buf2, bufsize)) {
 889                         (void) printf("Test10: Data corruption,"
 890                             " fd1:%s, fd2:%s fpos:%" NSC_SZFMT ", len:%d\n",
 891                             name[2*h], name[2*h+1], i, bufsize);
 892                         err++;
 893                 }
 894         }
 895         return (err);
 896 }
 897 
 898 int
 899 buffcmp(int *b1, int *b2, int size)
 900 {
 901         int i;
 902 
 903         for (i = 0; i < size/4; i++) {
 904                 if (b1[i] != b2[i]) {
 905                         (void) printf("Word %d does not match b1=0x%x, "
 906                             "b2=0x%x\n", i, b1[i], b2[i]);
 907                         return (1);
 908                 }
 909         }
 910         return (0);
 911 
 912 }
 913 
 914 int
 915 do_sdtest11(int fd, nsc_size_t loops, nsc_size_t filesize, int h)
 916 {
 917         int err = 0;
 918         nsc_size_t i;
 919         ssize_t r;
 920         int buf3[MAXBUF];
 921         int buf4[MAXBUF];
 922         int timestamp;
 923         time_t clock;
 924         struct tm *tm;
 925 
 926 
 927         /*
 928          * Test 9 will write a given pattern over and over Test 11 will read
 929          * same pattern and clear with timestamp data (MM:SS).
 930          */
 931 
 932         clock = time(NULL);
 933         tm  = localtime(&clock);
 934         (void) ascftime((char *)&timestamp, "%M""%S", tm);
 935 
 936         gen_data_known(buf1, bufsize, pattern[h]);
 937         gen_data_known(buf4, bufsize, timestamp);
 938         if ((loops > filesize / fba_num_bufsize) || (!loops))
 939                 loops = filesize / fba_num_bufsize;  /* entire disk */
 940 
 941         for (i = 0; i < loops; i++) {
 942                 r = pread(fd, buf3, bufsize,
 943                     (off_t)(i*fba_num_bufsize) << SCTRSHFT);
 944                 if (r <= 0) {
 945                         perror("Test11: read");
 946                         err++;
 947                         return (err);
 948                 }
 949                 if (buffcmp(buf1, buf3, bufsize)) {
 950                         (void) printf("Data corr, fd:%s, fpos:%" NSC_SZFMT
 951                         ", len:%d\n", name[h], i, bufsize);
 952                         err++;
 953                         return (err);
 954                 }
 955                 r = pwrite(fd, buf4, bufsize,
 956                     (off_t)(i*fba_num_bufsize) << SCTRSHFT);
 957                 if (r <= 0) {
 958                         perror("Test11: write");
 959                         err++;
 960                         return (err);
 961                 }
 962         }
 963         return (err);
 964 }
 965 
 966 int
 967 do_sdtest12(int fd, nsc_size_t loops, nsc_size_t filesize, int h)
 968 {
 969         int err = 0;
 970         nsc_size_t i;
 971         ssize_t r;
 972         int buf3[MAXBUF];
 973 
 974         /*
 975          * Test 9 will write a given pattern over and over Test 12 will read
 976          * same pattern
 977          */
 978 
 979         gen_data_known(buf1, bufsize, pattern[h]);
 980         if ((loops > filesize / fba_num_bufsize) || (!loops))
 981                 loops = filesize / fba_num_bufsize;  /* entire disk */
 982 
 983         for (i = 0; i < loops; i++) {
 984                 r = pread(fd, buf3, bufsize,
 985                     (off_t)(i*fba_num_bufsize) << SCTRSHFT);
 986                 if (r <= 0) {
 987                         perror("Test12: read");
 988                         err++;
 989                         return (err);
 990                 }
 991                 if (buffcmp(buf1, buf3, bufsize)) {
 992                         (void) printf("Data corr, fd:%s, fpos:%" NSC_SZFMT
 993                         ", len:%d\n", name[h], i, bufsize);
 994                         err++;
 995                         return (err);
 996                 }
 997         }
 998         return (err);
 999 }
1000 
1001 #ifdef lint
1002 int
1003 sd_diag_lintmain(int argc, char *argv[])
1004 #else
1005 int
1006 main(int argc, char *argv[])
1007 #endif
1008 {
1009         int procs;
1010         nsc_size_t filesize, filesize2;
1011         int fd, fd2, r, id, h, i;
1012         nsc_fd_t *sdfd, *sdfd2;
1013 
1014         if (argc < 2) {
1015                 print_usage();
1016                 exit(0);
1017         }
1018         (void) strcpy(config_file, DISKLIST);
1019         parse_opts(argc, argv);
1020 
1021         _nsc_nocheck();
1022         if ((procs = read_parts()) == 0)
1023                 exit(0);
1024 
1025         id = strtol(argv[optind], 0, 0);
1026         if (id == 10) {
1027                 /*
1028                  * each process gets 2 disks and copies disk1 to disk2,
1029                  * then goes back and verifies that the two disks are
1030                  * identical.
1031                  */
1032                 if (procs < 2) {
1033                 (void) printf("%s requires having at least 2 disks for test "
1034                     "#10.\n", config_file);
1035                 exit(0);
1036                 }
1037 
1038             for (h = 0; h < procs/2; h++) {
1039                 r = fork();
1040                 if (r == 0) {
1041                         srand(getpid());
1042 
1043 
1044                         if (!(sdfd = nsc_open(name[2*h], NSC_CACHE,
1045                                         O_RDWR | Rflag))) {
1046                                 (void) fprintf(stderr,
1047                                     "sd_diag: Error opening %s\n", name[2*h]);
1048                                 exit(1);
1049                         }
1050                         fd = nsc_fileno(sdfd);
1051                         if (fd == -1) {
1052                                 (void) fprintf(stderr,
1053                                     "sd_diag: Error opening %s\n", name[2*h]);
1054                                 (void) nsc_close(sdfd);
1055                                 exit(1);
1056                         }
1057                         filesize = set_part_size(name[2*h], sdfd);
1058                         if (!(sdfd2 = nsc_open(name[2*h+1], NSC_CACHE,
1059                                         O_RDWR | Rflag))) {
1060                                 (void) fprintf(stderr,
1061                                     "sd_diag: Error opening %s\n", name[2*h+1]);
1062                                 exit(1);
1063                         }
1064                         fd2 = nsc_fileno(sdfd2);
1065                         if (fd2 == -1) {
1066                                 (void) fprintf(stderr,
1067                                     "sd_diag: Error opening %s\n", name[2*h+1]);
1068                                 (void) nsc_close(sdfd2);
1069                                 exit(1);
1070                         }
1071                         filesize2 = set_part_size(name[2*h+1], sdfd2);
1072                         (void) sleep(2);
1073                         r = do_sdtest10(fd, fd2, loops, filesize, filesize2, h);
1074 
1075                         (void) printf("Partitions %s and %s, Test %d,"
1076                             " Completed %d errors\n",
1077                             name[2*h], name[2*h+1], id, r);
1078                         (void) nsc_close(sdfd);
1079                         (void) nsc_close(sdfd2);
1080                         exit(0);
1081                 } else if (r == -1) {
1082                         perror("fork");
1083                         break;
1084                 } else
1085                         continue;
1086             } /* for */
1087             for (i = 0; i < h; i++)
1088                 (void) wait(0);
1089         } else {
1090 
1091         for (h = 0; h < procs; h++) {
1092                 r = fork();
1093                 if (r == 0) {
1094                         srand(getpid());
1095 
1096                         id = strtol(argv[optind], 0, 0);
1097                         if (!(sdfd = nsc_open(name[h], NSC_CACHE,
1098                                         O_RDWR | Rflag))) {
1099                                 (void) fprintf(stderr,
1100                                     "sd_diag: Error opening %s\n", name[h]);
1101                                 exit(1);
1102                         }
1103                         fd = nsc_fileno(sdfd);
1104 
1105                         if (fd == -1) {
1106                                 (void) fprintf(stderr,
1107                                     "sd_diag: Error opening %s\n", name[h]);
1108                                 (void) nsc_close(sdfd);
1109                                 exit(1);
1110                         }
1111                         filesize = set_part_size(name[h], sdfd);
1112 
1113                         (void) sleep(2);
1114 
1115 
1116                         switch (id) {
1117                             case 1:
1118                                 r = do_sdtest1(fd, r_loops, filesize);
1119                                 break;
1120                             case 2:
1121                                 r = do_sdtest2(fd, r_loops, filesize, h);
1122                                 break;
1123                             case 3:
1124                                 r = do_sdtest3(fd, r_loops, filesize, h, sdfd);
1125                                 break;
1126                             case 4:
1127                                 r = do_sdtest4(fd, loops, filesize);
1128                                 break;
1129                             case 5:
1130                                 r = do_sdtest5(fd, loops, filesize, h);
1131                                 break;
1132                             case 6:
1133                                 r = do_sdtest6(fd, loops, filesize, h);
1134                                 break;
1135                             case 7:
1136                                 r = do_sdtest7(fd, r_loops, filesize, h, sdfd);
1137                                 break;
1138                             case 8:
1139                                 r = do_sdtest8(fd, r_loops, filesize);
1140                                 break;
1141                             case 9:
1142                                 r = do_sdtest9(fd, loops, filesize, h);
1143                                 break;
1144                             case 11:
1145                                 r = do_sdtest11(fd, loops, filesize, h);
1146                                 break;
1147                             case 12:
1148                                 r = do_sdtest12(fd, loops, filesize, h);
1149                                 break;
1150                             default:
1151                                 break;
1152                         }
1153 
1154                         (void) printf("Partition %s, Test %d, Completed %d "
1155                             "errors\n", name[h], id, r);
1156                         (void) nsc_close(sdfd);
1157                         exit(r ? 1 : 0);
1158                 } else if (r == -1) {
1159                         perror("fork");
1160                         break;
1161                 } else
1162                         continue;
1163         }
1164         for (i = 0; i < h; i++)
1165                 (void) wait(0);
1166         }
1167 
1168         return (0);
1169 }