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