1 /* @(#)rand_rw.c	1.27 18/02/19 Copyright 1993-2018 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)rand_rw.c	1.27 18/02/19 Copyright 1993-2018 J. Schilling";
6 #endif
7 /*
8  *	Copyright (c) 1993-2018 J. Schilling
9  */
10 /*
11  * The contents of this file are subject to the terms of the
12  * Common Development and Distribution License, Version 1.0 only
13  * (the "License").  You may not use this file except in compliance
14  * with the License.
15  *
16  * See the file CDDL.Schily.txt in this distribution for details.
17  * A copy of the CDDL is also available via the Internet at
18  * http://www.opensource.org/licenses/cddl1.txt
19  *
20  * When distributing Covered Code, include this CDDL HEADER in each
21  * file and include the License file CDDL.Schily.txt from this distribution.
22  */
23 
24 #include <schily/param.h>	/* Include various defs needed with some OS */
25 #include <schily/stdio.h>
26 #include <schily/standard.h>
27 #include <schily/stdlib.h>
28 #include <schily/time.h>
29 #include <schily/signal.h>
30 #include <schily/schily.h>
31 #include <scg/scgcmd.h>
32 #include <scg/scsireg.h>
33 #include <scg/scsidefs.h>
34 #include <scg/scsitransp.h>
35 
36 #include "scsicmds.h"
37 
38 #include "fmt.h"
39 #include "rand_rw.h"
40 
41 #undef	min
42 #define	min(a, b)	((a) < (b) ? (a) : (b))
43 #define	MAXBAD		(127)
44 
45 extern	long	RW;
46 extern	int	debug;
47 
48 struct	bb_list	*bad_blocks;
49 
50 int	rwbad		= 0;
51 int	rand_rw_intr	= 0;
52 
53 EXPORT	int	random_rw_test	__PR((SCSI *scgp, long first, long last));
54 EXPORT	int	random_v_test	__PR((SCSI *scgp, long first, long last));
55 LOCAL	int	random_rwv_test	__PR((SCSI *scgp, long first, long last, BOOL isrw));
56 LOCAL	void	sighandler	__PR((int));
57 LOCAL	int	rand_rw		__PR((SCSI *scgp, long first, long last));
58 LOCAL	int	rand_v		__PR((SCSI *scgp, long first, long last));
59 LOCAL	void	pr_percent	__PR((long));
60 LOCAL	int	check_fault	__PR((SCSI *scgp,
61 					int (*) (SCSI *scgp, caddr_t bp, long addr, int cnt),
62 							char *, long, long));
63 LOCAL	void	add_bad		__PR((long, u_char));
64 LOCAL	void	display_bad	__PR((void));
65 LOCAL	void	display_code	__PR((u_char));
66 
67 #define	rw_verify	(int (*) __PR((SCSI *, caddr_t bp, long addr, int cnt)))verify
68 
69 EXPORT int
random_rw_test(scgp,first,last)70 random_rw_test(scgp, first, last)
71 	SCSI	*scgp;
72 	long	first;
73 	long	last;
74 {
75 	return (random_rwv_test(scgp, first, last, TRUE));
76 }
77 
78 EXPORT int
random_v_test(scgp,first,last)79 random_v_test(scgp, first, last)
80 	SCSI	*scgp;
81 	long	first;
82 	long	last;
83 {
84 	return (random_rwv_test(scgp, first, last, FALSE));
85 }
86 
87 LOCAL int
random_rwv_test(scgp,first,last,isrw)88 random_rwv_test(scgp, first, last, isrw)
89 	SCSI	*scgp;
90 	long	first;
91 	long	last;
92 	BOOL	isrw;
93 {
94 	int	ret = 0;
95 
96 	if ((bad_blocks = (struct bb_list *) malloc((unsigned)((MAXBAD+1) *
97 					sizeof (struct bb_list)))) == 0) {
98 		comerr("No memory for bad block list.\n");
99 		/* NOTREACHED */
100 	}
101 	fillbytes((char *)bad_blocks,
102 				((MAXBAD+1) * sizeof (struct bb_list)), '\0');
103 
104 	getstarttime();
105 	if (isrw)
106 		ret = rand_rw(scgp, first, last);
107 	else
108 		ret = rand_v(scgp, first, last);
109 
110 	if (!is_ccs(scgp->dev)) {
111 		bad_to_def(scgp);
112 	}
113 	prstats();
114 	display_bad();
115 	return (ret);
116 }
117 
118 LOCAL void
sighandler(sig)119 sighandler(sig)
120 	int	sig;
121 {
122 	rand_rw_intr++;
123 }
124 
125 LOCAL int
rand_rw(scgp,first,last)126 rand_rw(scgp, first, last)
127 	SCSI	*scgp;
128 	long	first;
129 	long	last;
130 {
131 	void	(*osig) __PR((int));
132 	long	i;
133 	long	start = 0;
134 	long	end = scgp->cap->c_baddr;
135 	long	amount;
136 	long	bad_block = -1;
137 	long	pos[2];
138 	int	ret = 0;
139 	char	*buf[2];
140 
141 	for (i = 0; i < 2; i++) {
142 		buf[i]	= malloc((unsigned)scgp->cap->c_bsize);
143 		pos[i] = 0L;
144 	}
145 
146 	osig = signal(SIGINT, sighandler);
147 
148 	start = first;
149 	end = scgp->cap->c_baddr;
150 	if (start < 0 || start > end)
151 		start = 0L;
152 	if (last > 0 && last < end)
153 		end = last;
154 	amount = end - start;
155 	/*
156 	 * Do not write to Disk Label or Sinfo Block.
157 	 */
158 	if (start == 0)
159 		start++;
160 	if (start + amount <= scgp->cap->c_baddr)
161 		amount++;	/* If not full disk, include last block */
162 	if (debug)
163 		printf("start: %ld end: %ld amount: %ld last baddr: %ld\n",
164 				start, end, amount, (long)scgp->cap->c_baddr);
165 
166 	if (RW == -1)
167 		RW = amount / 50;
168 	printf("RAND R/W - %ld loops\n", RW);
169 	i = RW;
170 
171 #ifdef	HAVE_DRAND48
172 	pos[i%2] = drand48() * amount + start;
173 #else
174 	pos[i%2] = rand() % amount + start;
175 #endif
176 	while (read_scsi(scgp, buf[i%2], pos[i%2], 1) < 0) {
177 		ret = check_fault(scgp, read_scsi, buf[i%2],
178 						pos[i%2], pos[(i+1)%2]);
179 		add_bad(pos[i%2], ret | READ_FAULT);
180 #ifdef	HAVE_DRAND48
181 		pos[i%2] = drand48() * amount + start;
182 #else
183 		pos[i%2] = rand() % amount + start;
184 #endif
185 	}
186 	while (--i >= 0) {
187 #ifdef	HAVE_DRAND48
188 		pos[i%2] = drand48() * amount + start;
189 #else
190 		pos[i%2] = rand() % amount + start;
191 #endif
192 		while (read_scsi(scgp, buf[i%2], pos[i%2], 1) < 0) {
193 			ret = check_fault(scgp, read_scsi, buf[i%2],
194 						pos[i%2], pos[(i+1)%2]);
195 			add_bad(pos[i%2], ret | READ_FAULT);
196 #ifdef	HAVE_DRAND48
197 			pos[i%2] = drand48() * amount + start;
198 #else
199 			pos[i%2] = rand() % amount + start;
200 #endif
201 		}
202 
203 		if (write_scsi(scgp, buf[(i+1)%2], pos[(i+1)%2], 1) < 0) {
204 			int	j;
205 			ret = check_fault(scgp, write_scsi, buf[(i+1)%2],
206 						pos[(i+1)%2], pos[i%2]);
207 			scgp->silent++;
208 			for (j = 100; --j >= 0; ) {
209 				if (write_scsi(scgp, buf[(i+1)%2],
210 							pos[(i+1)%2], 1) >= 0)
211 					break;
212 			}
213 			scgp->silent--;
214 			add_bad(pos[(i+1)%2],
215 				ret | WRITE_FAULT | (j < 0?DATA_LOST:0));
216 		} else {
217 			if (verify(scgp, pos[(i+1)%2], 1, &bad_block) < 0) {
218 				ret = check_fault(scgp, rw_verify, (char *)0,
219 						pos[(i+1)%2], pos[i%2]);
220 				add_bad(pos[(i+1)%2], ret | VERIFY_FAULT);
221 			}
222 		}
223 		pr_percent(i);
224 		if (rand_rw_intr > 0) {
225 			printf("\n%lu loops done ( %ld%% ).\n",
226 					RW - i, (((RW - i) * 100) / RW));
227 			break;
228 		}
229 	}
230 	signal(SIGINT, osig);
231 	printf("\n");
232 	return (ret);
233 }
234 
235 LOCAL int
rand_v(scgp,first,last)236 rand_v(scgp, first, last)
237 	SCSI	*scgp;
238 	long	first;
239 	long	last;
240 {
241 	void	(*osig) __PR((int));
242 	long	i;
243 	long	start = 0;
244 	long	end = scgp->cap->c_baddr;
245 	long	amount;
246 	long	bad_block = -1;
247 	long	pos;
248 	int	ret = 0;
249 
250 	osig = signal(SIGINT, sighandler);
251 
252 	start = first;
253 	end = scgp->cap->c_baddr;
254 	if (start < 0 || start > end)
255 		start = 0L;
256 	if (last > 0 && last < end)
257 		end = last;
258 	amount = end - start;
259 
260 	/*
261 	 * Include "last" block
262 	 */
263 	amount++;
264 	if (debug)
265 		printf("start: %ld end: %ld amount: %ld last baddr: %ld\n",
266 				start, end, amount, (long)scgp->cap->c_baddr);
267 
268 	if (RW == -1)
269 		RW = amount / 50;
270 	printf("RAND V - %ld loops\n", RW);
271 	i = RW;
272 
273 	while (--i >= 0) {
274 #ifdef	HAVE_DRAND48
275 		pos = drand48() * amount + start;
276 #else
277 		pos = rand() % amount + start;
278 #endif
279 
280 		if (verify(scgp, pos, 1, &bad_block) < 0) {
281 			ret = check_fault(scgp, rw_verify, (char *)0,
282 					pos, pos);
283 			add_bad(pos, ret | VERIFY_FAULT);
284 		}
285 		pr_percent(i);
286 		if (rand_rw_intr > 0) {
287 			printf("\n%lu loops done ( %ld%% ).\n",
288 					RW - i, (((RW - i) * 100) / RW));
289 			break;
290 		}
291 	}
292 	signal(SIGINT, osig);
293 	printf("\n");
294 	return (ret);
295 }
296 
297 LOCAL void
pr_percent(loops)298 pr_percent(loops)
299 	long	loops;
300 {
301 	int	prozent;
302 static	int	prozent_last = -1;
303 
304 	prozent = ((RW - loops) * 100) / RW;
305 	if (prozent > prozent_last) {
306 		printf("\r %d%% ", prozent);
307 		flush();
308 	}
309 	prozent_last = prozent;
310 }
311 
312 LOCAL int
check_fault(scgp,op,buf,cur_pos,last_pos)313 check_fault(scgp, op, buf, cur_pos, last_pos)
314 	SCSI	*scgp;
315 	int	(*op) __PR((SCSI *scgp, caddr_t bp, long addr, int cnt));
316 	char	*buf;
317 	long	cur_pos;
318 	long	last_pos;
319 {
320 	long	bad_block;
321 	int	i;
322 
323 	if (scgp->scmd->error <= SCG_RETRYABLE) {
324 		error("\rBad Block found at: %ld\n", cur_pos);
325 		for (i = 0; i < 100; i++) {
326 			if (op == rw_verify) {
327 				if (verify(scgp, cur_pos, 1, &bad_block) < 0)
328 					break;
329 			} else {
330 				if ((*op)(scgp, buf, cur_pos, 1) < 0)
331 					break;
332 			}
333 		}
334 		if (i >= 100) {
335 			for (i = 0; i < 100; i++) {
336 				if (seek_scsi(scgp, last_pos) < 0)
337 					return (SEEK_FAULT);
338 				if (op == rw_verify) {
339 					if (verify(scgp, cur_pos, 1,
340 							&bad_block) < 0)
341 						break;
342 				} else {
343 					if ((*op)(scgp, buf, cur_pos, 1) < 0)
344 						break;
345 				}
346 			}
347 			if (i < 100) {
348 				error("SOFT DATA ERROR !!!!\n");
349 				return (SOFT_FAULT);
350 			} else {
351 				error("NO ERROR ????\n");
352 				return (NO_FAULT);
353 			}
354 		}
355 		error("HARD ERROR !!!!\n");
356 		return (HARD_FAULT);
357 	}
358 	return (DRV_ERR);
359 }
360 
361 LOCAL void
362 #ifdef	__STDC__
add_bad(long bb,u_char err)363 add_bad(long bb, u_char err)
364 #else
365 add_bad(bb, err)
366 	long	bb;
367 	u_char	err;
368 #endif
369 {
370 	register int	i;
371 
372 	if (get_nbad() >= MAXBAD) {
373 		display_bad();
374 		comerrno(EX_BAD, "Too many bad blocks (max is %d)\n", MAXBAD);
375 		/* NOTREACHED */
376 	}
377 	for (i = 0; i < rwbad; i++) {
378 		if (bad_blocks[i].block == bb && bad_blocks[i].code == err) {
379 			bad_blocks[i].count++;
380 			return;
381 		}
382 	}
383 	bad_blocks[rwbad].block = bb;
384 	bad_blocks[rwbad].code = err;
385 	bad_blocks[rwbad].count = 1;
386 	insert_bad(bb);
387 	rwbad++;
388 }
389 
390 LOCAL void
display_bad()391 display_bad()
392 {
393 	int	i;
394 
395 	if (rwbad > 0)
396 		printf("Count	Block		Code\n");
397 	else
398 		printf("no errors\n");
399 	for (i = 0; i < rwbad; i++) {
400 		printf("%d	%lu		",
401 			bad_blocks[i].count,
402 			bad_blocks[i].block);
403 		display_code(bad_blocks[i].code);
404 	}
405 }
406 
407 LOCAL void
408 #ifdef	__STDC__
display_code(u_char code)409 display_code(u_char code)
410 #else
411 display_code(code)
412 	u_char	code;
413 #endif
414 {
415 	if ((code & DRV_ERR) == DRV_ERR) {
416 		printf("FATAL ERROR.\n");
417 		return;
418 	}
419 
420 	if (code & READ_FAULT)
421 		printf("READ:");
422 	if (code & WRITE_FAULT)
423 		printf("WRITE:");
424 	if (code & VERIFY_FAULT)
425 		printf("VERIFY:");
426 	if (code & SEEK_FAULT)
427 		printf("SEEK:");
428 
429 	if (code & DATA_LOST)
430 		printf(" DATA LOST");
431 	if (code & HARD_FAULT)
432 		printf(" constant error");
433 	if (code & SOFT_FAULT)
434 		printf(" partial error");
435 	if (code & NO_FAULT)
436 		printf(" not reproducable error");
437 
438 	printf(".\n");
439 }
440