xref: /titanic_44/usr/src/cmd/avs/sdbc/sd_diag.c (revision 20945219a0f4861cc03785ce980b5814bad7267d)
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 }
1170