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
63int  buf1[MAXBUF];
64int  buf2[MAXBUF];
65char name[MAXPARTS][80];
66int  pattern[MAXPARTS];
67int  bufsize = DEF_SIZE;
68int  fba_num_bufsize;
69nsc_size_t  loops   = DEF_LOOP;
70nsc_size_t  r_loops   = RAND_LOOPS;
71int  fsize   = -1;
72int  readercount = 3;
73int  Rflag = O_EXCL;
74char config_file[32];
75
76int
77read_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
106void
107print_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
149void
150parse_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
198nsc_size_t
199set_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
229int
230do_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
261void
262gen_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
271int
272do_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
309int
310do_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
355cleanup:
356	free(seekpos);
357	return (err);
358}
359
360int
361do_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
409int
410do_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
483int
484do_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
553int shmid;
554
555#define	MAXREADERS 32
556
557struct 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
588int
589do_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
650int
651do_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
694void
695init_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
713int
714do_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
767int
768do_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
792void
793gen_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
802int
803do_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
836int
837do_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
898int
899buffcmp(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
914int
915do_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
966int
967do_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
1002int
1003sd_diag_lintmain(int argc, char *argv[])
1004#else
1005int
1006main(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