xref: /illumos-gate/usr/src/lib/cfgadm_plugins/ac/common/mema_test.c (revision e3ae4b35c024af1196582063ecee3ab79367227d)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 1996-1998, 2001 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 #include <stddef.h>
28 #include <stdio.h>
29 #include <sys/param.h>
30 #include <config_admin.h>
31 #include <memory.h>
32 #include <sys/types.h>
33 #include <time.h>
34 #include "mema_test.h"
35 
36 typedef u_longlong_t pbuf_t;
37 
38 /*
39  * Test for stuck-at fault and transitional faults
40  *   Algorithm:
41  *         for i = 0 to npages
42  *              write(0x55)
43  *         for npages to 0
44  *              read_compare(0x55)
45  *              write(0xaa)
46  *         for 0 to number of pages
47  *              read_compare(0xaa)
48  *              write(0x55)
49  *              read_compare(0x55)
50  *
51  * stuck-at fault is detected because each cell have a 1 and a 0 is read
52  * transitional fault is detected because after each 0 to 1 and 1 to 0
53  * transition the value is check to be sure that the cell is not frozen.
54  */
55 
56 /*
57  * The following strings are subject of stderr output and
58  * gettext() is not used for them.
59  */
60 static const char err_sum[] = "total error %u\n";
61 static const char nts_msg[] = "Normal test started\n";
62 static const char ntf_msg[] = "Normal test finished\n";
63 static const char qts_msg[] = "Quick test started\n";
64 static const char qtf_msg[] = "Quick test finished\n";
65 static const char ets_msg[] = "Extended test started\n";
66 static const char etf_msg[] = "Extended test finished\n";
67 static const char m1_msg[] = "    March 1, ";
68 static const char m2_msg[] = "    March 2, ";
69 static const char m3_msg[] = "    March 3, ";
70 static const char m4_msg[] = "    March 4, ";
71 static const char wr_msg[] = "write. ";
72 static const char rd_cmp_msg[] = "read/compare. ";
73 static const char rpt_rd_cmp_msg[] = "repeated read/compare. ";
74 static const char ml_rd_cmp_msg[] = "mixed line read/compare. ";
75 static const char ln_rd_cmp_msg[] = "line read/compare. ";
76 static const char report_msg[] = "%s%s%d%% complete.\n";
77 static const char pg_header_msg[] = "    Errors at page address: 0x%x.\n";
78 static const char rd_err_msg[] = "    Error reading page at address: 0x%x.\n";
79 static const char wr_err_msg[] = "    Error writing page at address: 0x%x.\n";
80 static const
81 char mem_err_msg[] = "      Offset: 0x%x, data written/read: 0x%2x/0x%2x.\n";
82 
83 /*
84  * Macros do deal with test conditions.
85  */
86 #define	TEST_END(END_MSG) \
87 			if ((handle->max_errors != 0) &&\
88 				(handle->max_errors == total_errors)) {\
89 				mtest_message(handle, (END_MSG));\
90 				error_summary(handle, total_errors);\
91 				SET_CONDITION(handle, cond);\
92 				return (MTEST_DONE);\
93 			}
94 
95 static void
96 error_summary(mtest_handle_t handle, uint_t total_errors)
97 {
98 	char msgbuf[100];
99 
100 	(void) sprintf(msgbuf, err_sum, total_errors);
101 	mtest_message(handle, msgbuf);
102 }
103 
104 
105 static void
106 error_print(char *writebuf, char *readbuf, mtest_handle_t handle, long pageno,
107 	uint_t *total_errorsp)
108 {
109 	char msgbuf[100];
110 	size_t offset;
111 
112 	(void) sprintf(msgbuf, pg_header_msg, PAGE_SIZE(handle) * pageno);
113 	mtest_message(handle, msgbuf);
114 
115 	for (offset = 0; offset < PAGE_SIZE(handle); offset++) {
116 		if ((handle->max_errors != 0) &&
117 		    (readbuf[offset] != writebuf[offset]) &&
118 		    (handle->max_errors == *total_errorsp))
119 			return;
120 		else {
121 			(*total_errorsp)++;
122 			(void) sprintf(msgbuf, mem_err_msg, offset,
123 			    writebuf[offset], readbuf[offset]);
124 			mtest_message(handle, msgbuf);
125 		}
126 	}
127 }
128 
129 int
130 memory_test_normal(
131 	mtest_handle_t handle)
132 {
133 	pbuf_t *patternbuf1;
134 	pbuf_t *patternbuf2;
135 	pbuf_t *readbuf;
136 	long npages, pageno;
137 	struct mtest_error errbuf;
138 	uint_t total_errors;
139 	cfga_cond_t cond;
140 	time_t time_rep;
141 	char msgbuf[100];
142 
143 	patternbuf1 = (pbuf_t *)mtest_allocate_page_buf(handle);
144 	patternbuf2 = (pbuf_t *)mtest_allocate_page_buf(handle);
145 	readbuf = (pbuf_t *)mtest_allocate_page_buf(handle);
146 	if (patternbuf1 == NULL || patternbuf2 == NULL || readbuf == NULL) {
147 		return (MTEST_LIB_ERROR);
148 	}
149 
150 	mtest_message(handle, nts_msg);
151 	npages = BANK_SIZE(handle) / PAGE_SIZE(handle);
152 
153 	total_errors = 0;
154 	cond = CFGA_COND_OK;
155 
156 	(void) memset((void *)patternbuf1, 0x55, PAGE_SIZE(handle));
157 	(void) memset((void *)patternbuf2, 0xaa, PAGE_SIZE(handle));
158 
159 	time_rep = time(NULL) + REPORT_SEC;
160 
161 	for (pageno = 0; pageno < npages; pageno++) {
162 		if (mtest_write(handle, (void *)patternbuf1, pageno, 0, 0)
163 		    == -1) {
164 			(void) sprintf(msgbuf, wr_err_msg, pageno);
165 			mtest_message(handle, msgbuf);
166 			return (MTEST_DEV_ERROR);
167 		}
168 		if ((time(NULL) >= time_rep) || (pageno == npages - 1) ||
169 		    (pageno == 0)) {
170 			(void) sprintf(msgbuf, report_msg, m1_msg, wr_msg,
171 			    ((pageno + 1) * 100) / npages);
172 			mtest_message(handle, msgbuf);
173 			time_rep = time(NULL) + REPORT_SEC;
174 		}
175 	}
176 	for (pageno = npages-1; pageno >= 0; pageno--) {
177 		if (mtest_read(handle, (void *)readbuf, pageno, 0, 0, &errbuf)
178 		    == -1) {
179 			(void) sprintf(msgbuf, rd_err_msg, pageno);
180 			mtest_message(handle, msgbuf);
181 			return (MTEST_DEV_ERROR);
182 		}
183 		if (errbuf.error_type != MTEST_ERR_NONE) {
184 			if (errbuf.error_type == MTEST_ERR_CE &&
185 			    cond != CFGA_COND_FAILED)
186 				cond = CFGA_COND_FAILING;
187 			else
188 				cond = CFGA_COND_FAILED;
189 			total_errors++;
190 			/*
191 			 * Keep going if max errors is 0 or limit not
192 			 * reached.
193 			 */
194 			TEST_END(ntf_msg);
195 		}
196 		if (memcmp((void *)patternbuf1, (void *)readbuf,
197 		    PAGE_SIZE(handle)) != 0) {
198 			cond = CFGA_COND_FAILED;
199 			error_print((void *)patternbuf1, (void *)readbuf,
200 			    handle, pageno, &total_errors);
201 			TEST_END(ntf_msg);
202 		}
203 		if (mtest_write(handle, (void *)patternbuf2, pageno, 0, 0)
204 		    == -1) {
205 			(void) sprintf(msgbuf, wr_err_msg, pageno);
206 			mtest_message(handle, msgbuf);
207 			return (MTEST_DEV_ERROR);
208 		}
209 		if ((time(NULL) >= time_rep) || (pageno == npages - 1) ||
210 		    (pageno == 0)) {
211 			(void) sprintf(msgbuf, report_msg, m1_msg, rd_cmp_msg,
212 			    ((npages - pageno) * 100) / npages);
213 			mtest_message(handle, msgbuf);
214 			time_rep = time(NULL) + REPORT_SEC;
215 		}
216 	}
217 	/* March 2 (repeated) */
218 	for (pageno = 0; pageno < npages; pageno++) {
219 		if (mtest_read(handle, (void *)readbuf, pageno, 0, 0, &errbuf)
220 		    == -1) {
221 			(void) sprintf(msgbuf, rd_err_msg, pageno);
222 			mtest_message(handle, msgbuf);
223 			return (MTEST_DEV_ERROR);
224 		}
225 		if (errbuf.error_type != MTEST_ERR_NONE) {
226 			if (errbuf.error_type == MTEST_ERR_CE &&
227 			    cond != CFGA_COND_FAILED)
228 				cond = CFGA_COND_FAILING;
229 			else
230 				cond = CFGA_COND_FAILED;
231 			total_errors++;
232 			TEST_END(ntf_msg);
233 		}
234 		if (memcmp((void *)patternbuf2, (void *)readbuf,
235 		    PAGE_SIZE(handle)) != 0) {
236 			cond = CFGA_COND_FAILED;
237 			error_print((void *)patternbuf2, (void *)readbuf,
238 			    handle, pageno, &total_errors);
239 			TEST_END(ntf_msg);
240 		}
241 		if (mtest_write(handle, (void *)patternbuf1, pageno, 0, 0)
242 		    == -1) {
243 			(void) sprintf(msgbuf, wr_err_msg, pageno);
244 			mtest_message(handle, msgbuf);
245 			return (MTEST_DEV_ERROR);
246 		}
247 		if (mtest_read(handle, (void *)readbuf, pageno, 0, 0, &errbuf)
248 		    == -1) {
249 			(void) sprintf(msgbuf, rd_err_msg, pageno);
250 			mtest_message(handle, msgbuf);
251 			return (MTEST_DEV_ERROR);
252 		}
253 		if (errbuf.error_type != MTEST_ERR_NONE) {
254 			if (errbuf.error_type == MTEST_ERR_CE &&
255 			    cond != CFGA_COND_FAILED)
256 				cond = CFGA_COND_FAILING;
257 			else
258 				cond = CFGA_COND_FAILED;
259 			total_errors++;
260 			TEST_END(ntf_msg);
261 		}
262 		if (memcmp((void *)patternbuf1, (void *)readbuf,
263 		    PAGE_SIZE(handle)) != 0) {
264 			cond = CFGA_COND_FAILED;
265 			error_print((void *)patternbuf1, (void *)readbuf,
266 			    handle, pageno, &total_errors);
267 			TEST_END(ntf_msg);
268 		}
269 		if ((time(NULL) >= time_rep) || (pageno == npages - 1) ||
270 		    (pageno == 0)) {
271 			(void) sprintf(msgbuf, report_msg, m2_msg,
272 			    rpt_rd_cmp_msg, ((pageno + 1) * 100) / npages);
273 			mtest_message(handle, msgbuf);
274 			time_rep = time(NULL) + REPORT_SEC;
275 		}
276 	}
277 	mtest_message(handle, ntf_msg);
278 	error_summary(handle, total_errors);
279 	SET_CONDITION(handle, cond);
280 	return (MTEST_DONE);
281 }
282 
283 /* this test look only for stuck-at fault */
284 int
285 memory_test_quick(
286 	mtest_handle_t handle)
287 {
288 	pbuf_t *patternbuf1;
289 	pbuf_t *patternbuf2;
290 	pbuf_t *readbuf;
291 	long npages, pageno;
292 	struct mtest_error errbuf;
293 	uint_t total_errors;
294 	cfga_cond_t cond;
295 	time_t time_rep;
296 	char msgbuf[100];
297 
298 	patternbuf1 = (pbuf_t *)mtest_allocate_page_buf(handle);
299 	patternbuf2 = (pbuf_t *)mtest_allocate_page_buf(handle);
300 	readbuf = (pbuf_t *)mtest_allocate_page_buf(handle);
301 	if (patternbuf1 == NULL || patternbuf2 == NULL || readbuf == NULL) {
302 		return (MTEST_LIB_ERROR);
303 	}
304 
305 	mtest_message(handle, qts_msg);
306 	npages = BANK_SIZE(handle) / PAGE_SIZE(handle);
307 
308 	total_errors = 0;
309 	cond = CFGA_COND_OK;
310 
311 	(void) memset((void *)patternbuf1, 0x55, PAGE_SIZE(handle));
312 	(void) memset((void *)patternbuf2, 0xaa, PAGE_SIZE(handle));
313 
314 	time_rep = time(NULL) + REPORT_SEC;
315 
316 	for (pageno = 0; pageno < npages; pageno++) {
317 		if (mtest_write(handle, (void *)patternbuf1, pageno, 0, 0)
318 		    == -1) {
319 			(void) sprintf(msgbuf, wr_err_msg, pageno);
320 			mtest_message(handle, msgbuf);
321 			return (MTEST_DEV_ERROR);
322 		}
323 		if ((time(NULL) >= time_rep) || (pageno == npages - 1) ||
324 		    (pageno == 0)) {
325 			(void) sprintf(msgbuf, report_msg, m1_msg, wr_msg,
326 			    ((pageno + 1) * 100) / npages);
327 			mtest_message(handle, msgbuf);
328 			time_rep = time(NULL) + REPORT_SEC;
329 		}
330 	}
331 
332 	for (pageno = npages-1; pageno >= 0; pageno--) {
333 		if (mtest_read(handle, (void *)readbuf, pageno, 0, 0, &errbuf)
334 		    == -1) {
335 			(void) sprintf(msgbuf, rd_err_msg, pageno);
336 			mtest_message(handle, msgbuf);
337 			return (MTEST_DEV_ERROR);
338 		}
339 		if (errbuf.error_type != MTEST_ERR_NONE) {
340 			if (errbuf.error_type == MTEST_ERR_CE &&
341 			    cond != CFGA_COND_FAILED)
342 				cond = CFGA_COND_FAILING;
343 			else
344 				cond = CFGA_COND_FAILED;
345 			total_errors++;
346 			/*
347 			 * Keep going if max errors is 0 or limit not
348 			 * reached.
349 			 */
350 			TEST_END(qtf_msg);
351 		}
352 		if (memcmp((void *)patternbuf1, (void *)readbuf,
353 		    PAGE_SIZE(handle)) != 0) {
354 			cond = CFGA_COND_FAILED;
355 			error_print((void *)patternbuf1, (void *)readbuf,
356 			    handle, pageno, &total_errors);
357 			TEST_END(qtf_msg);
358 		}
359 		if (mtest_write(handle, (void *)patternbuf2, pageno, 0, 0)
360 		    == -1) {
361 			(void) sprintf(msgbuf, wr_err_msg, pageno);
362 			mtest_message(handle, msgbuf);
363 			return (MTEST_DEV_ERROR);
364 		}
365 		if ((time(NULL) >= time_rep) || (pageno == npages - 1) ||
366 		    (pageno == 0)) {
367 			(void) sprintf(msgbuf, report_msg, m1_msg, rd_cmp_msg,
368 			    ((npages - pageno) * 100) / npages);
369 			mtest_message(handle, msgbuf);
370 			time_rep = time(NULL) + REPORT_SEC;
371 		}
372 	}
373 	/* March 2 */
374 	for (pageno = 0; pageno < npages; pageno++) {
375 		if (mtest_read(handle, (void *)readbuf, pageno, 0, 0, &errbuf)
376 		    == -1) {
377 			(void) sprintf(msgbuf, rd_err_msg, pageno);
378 			mtest_message(handle, msgbuf);
379 			return (MTEST_DEV_ERROR);
380 		}
381 		if (errbuf.error_type != MTEST_ERR_NONE) {
382 			if (errbuf.error_type == MTEST_ERR_CE &&
383 			    cond != CFGA_COND_FAILED)
384 				cond = CFGA_COND_FAILING;
385 			else
386 				cond = CFGA_COND_FAILED;
387 			total_errors++;
388 			TEST_END(qtf_msg);
389 		}
390 		if (memcmp((void *)patternbuf2, (void *)readbuf,
391 		    PAGE_SIZE(handle)) != 0) {
392 			cond = CFGA_COND_FAILED;
393 			error_print((void *)patternbuf2, (void *)readbuf,
394 			    handle, pageno, &total_errors);
395 			TEST_END(qtf_msg);
396 		}
397 		if ((time(NULL) >= time_rep) || (pageno == npages - 1) ||
398 		    (pageno == 0)) {
399 			(void) sprintf(msgbuf, report_msg, m2_msg, rd_cmp_msg,
400 			    ((pageno + 1) * 100) / npages);
401 			mtest_message(handle, msgbuf);
402 			time_rep = time(NULL) + REPORT_SEC;
403 		}
404 	}
405 	mtest_message(handle, qtf_msg);
406 	error_summary(handle, total_errors);
407 	SET_CONDITION(handle, cond);
408 	return (MTEST_DONE);
409 }
410 
411 
412 /* look for stuck-at, transition, coupling fault: inversion, idempotent */
413 int
414 memory_test_extended(
415 	mtest_handle_t handle)
416 {
417 	pbuf_t *patternbuf0, *patternbuf1;
418 	pbuf_t *readbuf0, *readbuf1, *readbuf2;
419 	long npages, pageno;
420 	long line;
421 	struct mtest_error errbuf;
422 	uint_t total_errors;
423 	cfga_cond_t cond;
424 	time_t time_rep;
425 	char msgbuf[100];
426 
427 	patternbuf0 = (pbuf_t *)mtest_allocate_page_buf(handle);
428 	patternbuf1 = (pbuf_t *)mtest_allocate_page_buf(handle);
429 	readbuf0 = (pbuf_t *)mtest_allocate_page_buf(handle);
430 	readbuf1 = (pbuf_t *)mtest_allocate_page_buf(handle);
431 	readbuf2 = (pbuf_t *)mtest_allocate_page_buf(handle);
432 	if (patternbuf0 == NULL || patternbuf1 == NULL ||
433 	    readbuf0 == NULL || readbuf1 == NULL || readbuf2 == NULL) {
434 		return (MTEST_LIB_ERROR);
435 	}
436 
437 	mtest_message(handle, ets_msg);
438 	npages = BANK_SIZE(handle) / PAGE_SIZE(handle);
439 
440 	total_errors = 0;
441 	cond = CFGA_COND_OK;
442 
443 	(void) memset((void *)patternbuf0, 0x55, PAGE_SIZE(handle));
444 	(void) memset((void *)patternbuf1, 0xaa, PAGE_SIZE(handle));
445 
446 	time_rep = time(NULL) + REPORT_SEC;
447 
448 	for (pageno = 0; pageno < npages; pageno++) {
449 		if (mtest_write(handle, (void *)patternbuf0, pageno, 0, 0)
450 		    == -1) {
451 			(void) sprintf(msgbuf, wr_err_msg, pageno);
452 			mtest_message(handle, msgbuf);
453 			return (MTEST_DEV_ERROR);
454 		}
455 		if ((time(NULL) >= time_rep) || (pageno == npages - 1) ||
456 		    (pageno == 0)) {
457 			(void) sprintf(msgbuf, report_msg, m1_msg, wr_msg,
458 			    ((pageno + 1) * 100) / npages);
459 			mtest_message(handle, msgbuf);
460 			time_rep = time(NULL) + REPORT_SEC;
461 		}
462 	}
463 
464 	/*
465 	 * Line tests take 5-9 time longer and the reprting interval
466 	 * should be extended 3-5 times.
467 	 */
468 
469 	/* March 1 */
470 	for (pageno = npages-1; pageno >= 0; pageno--) {
471 		for (line = (LINES_PER_PAGE(handle) - 1); line >= 0; line--) {
472 			if (mtest_read(handle, (void *)readbuf0, pageno,
473 			    line, 1, &errbuf) == -1) {
474 				(void) sprintf(msgbuf, rd_err_msg, pageno);
475 				mtest_message(handle, msgbuf);
476 				return (MTEST_DEV_ERROR);
477 			}
478 			if (errbuf.error_type != MTEST_ERR_NONE) {
479 				if (errbuf.error_type == MTEST_ERR_CE &&
480 				    cond != CFGA_COND_FAILED)
481 					cond = CFGA_COND_FAILING;
482 				else
483 					cond = CFGA_COND_FAILED;
484 				total_errors++;
485 				/*
486 				 * Keep going if max errors is 0 or limit not
487 				 * reached.
488 				 */
489 				TEST_END(ntf_msg);
490 			}
491 			if (mtest_write(handle, (void*)patternbuf1, pageno,
492 			    line, 1) == -1) {
493 				(void) sprintf(msgbuf, wr_err_msg, pageno);
494 				mtest_message(handle, msgbuf);
495 				return (MTEST_DEV_ERROR);
496 			}
497 			if (mtest_read(handle, (void *)readbuf1, pageno,
498 			    line, 1, &errbuf) == -1) {
499 				(void) sprintf(msgbuf, rd_err_msg, pageno);
500 				mtest_message(handle, msgbuf);
501 				return (MTEST_DEV_ERROR);
502 			}
503 			if (errbuf.error_type != MTEST_ERR_NONE) {
504 				if (errbuf.error_type == MTEST_ERR_CE &&
505 				    cond != CFGA_COND_FAILED)
506 					cond = CFGA_COND_FAILING;
507 				else
508 					cond = CFGA_COND_FAILED;
509 				total_errors++;
510 				TEST_END(ntf_msg);
511 			}
512 			if (mtest_write(handle, (void*)patternbuf0, pageno,
513 			    line, 1) == -1) {
514 				(void) sprintf(msgbuf, wr_err_msg, pageno);
515 				mtest_message(handle, msgbuf);
516 				return (MTEST_DEV_ERROR);
517 			}
518 			if (mtest_read(handle, (void *)readbuf2, pageno,
519 			    line, 1, &errbuf) == -1) {
520 				(void) sprintf(msgbuf, rd_err_msg, pageno);
521 				mtest_message(handle, msgbuf);
522 				return (MTEST_DEV_ERROR);
523 			}
524 			if (errbuf.error_type != MTEST_ERR_NONE) {
525 				if (errbuf.error_type == MTEST_ERR_CE &&
526 				    cond != CFGA_COND_FAILED)
527 					cond = CFGA_COND_FAILING;
528 				else
529 					cond = CFGA_COND_FAILED;
530 				total_errors++;
531 				TEST_END(ntf_msg);
532 			}
533 			if (mtest_write(handle, (void*)patternbuf1, pageno,
534 			    line, 1) == -1) {
535 				(void) sprintf(msgbuf, wr_err_msg, pageno);
536 				return (MTEST_DEV_ERROR);
537 			}
538 		}	/* line */
539 		if (memcmp((void *)patternbuf0, (void *)readbuf0,
540 		    PAGE_SIZE(handle)) != 0) {
541 			cond = CFGA_COND_FAILED;
542 			error_print((void *)patternbuf0, (void *)readbuf0,
543 			    handle, pageno, &total_errors);
544 			TEST_END(ntf_msg);
545 		}
546 		if (memcmp((void *)patternbuf1, (void *)readbuf1,
547 			PAGE_SIZE(handle)) != 0) {
548 			cond = CFGA_COND_FAILED;
549 			error_print((void *)patternbuf1, (void *)readbuf1,
550 			    handle, pageno, &total_errors);
551 			TEST_END(ntf_msg);
552 		}
553 		if (memcmp((void *)patternbuf0, (void *)readbuf2,
554 			PAGE_SIZE(handle)) != 0) {
555 			cond = CFGA_COND_FAILED;
556 			error_print((void *)patternbuf0, (void *)readbuf2,
557 			    handle, pageno, &total_errors);
558 			TEST_END(ntf_msg);
559 		}
560 		if ((time(NULL) >= time_rep) || (pageno == npages - 1) ||
561 		    (pageno == 0)) {
562 			(void) sprintf(msgbuf, report_msg, m1_msg,
563 			    ml_rd_cmp_msg, ((npages - pageno) * 100) / npages);
564 			mtest_message(handle, msgbuf);
565 			time_rep = time(NULL) + REPORT_SEC * 3;
566 		}
567 	}	/* page */
568 
569 	/* March 2 */
570 	for (pageno = npages-1; pageno >= 0; pageno--) {
571 		for (line = (LINES_PER_PAGE(handle) - 1); line >= 0; line--) {
572 			if (mtest_read(handle, (void *)readbuf0, pageno,
573 			    line, 1, &errbuf) == -1) {
574 				(void) sprintf(msgbuf, rd_err_msg, pageno);
575 				mtest_message(handle, msgbuf);
576 				return (MTEST_DEV_ERROR);
577 			}
578 			if (errbuf.error_type != MTEST_ERR_NONE) {
579 				if (errbuf.error_type == MTEST_ERR_CE &&
580 				    cond != CFGA_COND_FAILED)
581 					cond = CFGA_COND_FAILING;
582 				else
583 					cond = CFGA_COND_FAILED;
584 				total_errors++;
585 				/*
586 				 * Keep going if max errors is 0 or limit not
587 				 * reached.
588 				 */
589 				TEST_END(ntf_msg);
590 			}
591 			if (mtest_write(handle, (void*)patternbuf0, pageno,
592 			    line, 1) == -1) {
593 				(void) sprintf(msgbuf, wr_err_msg, pageno);
594 				mtest_message(handle, msgbuf);
595 				return (MTEST_DEV_ERROR);
596 			}
597 			if (mtest_write(handle, (void*)patternbuf1, pageno,
598 			    line, 1) == -1) {
599 				(void) sprintf(msgbuf, wr_err_msg, pageno);
600 				mtest_message(handle, msgbuf);
601 				return (MTEST_DEV_ERROR);
602 			}
603 		}
604 		if (memcmp((void *)patternbuf1, (void *)readbuf0,
605 			PAGE_SIZE(handle)) != 0) {
606 			cond = CFGA_COND_FAILED;
607 			total_errors++;
608 		}
609 		if ((time(NULL) >= time_rep) || (pageno == npages - 1) ||
610 		    (pageno == 0)) {
611 			(void) sprintf(msgbuf, report_msg, m2_msg,
612 			    ln_rd_cmp_msg, ((npages - pageno) * 100) / npages);
613 			mtest_message(handle, msgbuf);
614 			time_rep = time(NULL) + REPORT_SEC * 3;
615 		}
616 	}	/* page */
617 
618 	/* March 3 */
619 	for (pageno = 0; pageno < npages; pageno++) {
620 		for (line = 0; line < LINES_PER_PAGE(handle); line++) {
621 			if (mtest_read(handle, (void *)readbuf0, pageno,
622 			    line, 1, &errbuf) == -1) {
623 				(void) sprintf(msgbuf, rd_err_msg, pageno);
624 				mtest_message(handle, msgbuf);
625 				return (MTEST_DEV_ERROR);
626 			}
627 			if (errbuf.error_type != MTEST_ERR_NONE) {
628 				if (errbuf.error_type == MTEST_ERR_CE &&
629 				    cond != CFGA_COND_FAILED)
630 					cond = CFGA_COND_FAILING;
631 				else
632 					cond = CFGA_COND_FAILED;
633 				total_errors++;
634 				TEST_END(ntf_msg);
635 			}
636 			if (mtest_write(handle, (void*)patternbuf0, pageno,
637 			    line, 1) == -1) {
638 				(void) sprintf(msgbuf, wr_err_msg, pageno);
639 				mtest_message(handle, msgbuf);
640 				return (MTEST_DEV_ERROR);
641 			}
642 			if (mtest_write(handle, (void*)patternbuf1, pageno,
643 			    line, 1) == -1) {
644 				(void) sprintf(msgbuf, wr_err_msg, pageno);
645 				mtest_message(handle, msgbuf);
646 				return (MTEST_DEV_ERROR);
647 			}
648 			if (mtest_write(handle, (void*)patternbuf0, pageno,
649 			    line, 1) == -1) {
650 				(void) sprintf(msgbuf, wr_err_msg, pageno);
651 				mtest_message(handle, msgbuf);
652 				return (MTEST_DEV_ERROR);
653 			}
654 		}
655 		if (memcmp((void *)patternbuf1, (void *)readbuf0,
656 			PAGE_SIZE(handle)) != 0) {
657 			cond = CFGA_COND_FAILED;
658 			error_print((void *)patternbuf1, (void *)readbuf0,
659 			    handle, pageno, &total_errors);
660 			TEST_END(ntf_msg);
661 		}
662 		if ((time(NULL) >= time_rep) || (pageno == npages - 1) ||
663 		    (pageno == 0)) {
664 			(void) sprintf(msgbuf, report_msg, m3_msg,
665 			    ml_rd_cmp_msg, ((pageno + 1) * 100) / npages);
666 			mtest_message(handle, msgbuf);
667 			time_rep = time(NULL) + REPORT_SEC * 3;
668 		}
669 	}	/* page */
670 
671 	/* March 4 */
672 	for (pageno = 0; pageno < npages; pageno++) {
673 		for (line = 0; line < LINES_PER_PAGE(handle); line++) {
674 			if (mtest_read(handle, (void *)readbuf0, pageno,
675 			    line, 1, &errbuf) == -1) {
676 				(void) sprintf(msgbuf, rd_err_msg, pageno);
677 				mtest_message(handle, msgbuf);
678 				return (MTEST_DEV_ERROR);
679 			}
680 			if (errbuf.error_type != MTEST_ERR_NONE) {
681 				if (errbuf.error_type == MTEST_ERR_CE &&
682 				    cond != CFGA_COND_FAILED)
683 					cond = CFGA_COND_FAILING;
684 				else
685 					cond = CFGA_COND_FAILED;
686 				total_errors++;
687 				TEST_END(ntf_msg);
688 			}
689 			if (mtest_write(handle, (void*)patternbuf1, pageno,
690 			    line, 1) == -1) {
691 				(void) sprintf(msgbuf, wr_err_msg, pageno);
692 				mtest_message(handle, msgbuf);
693 				return (MTEST_DEV_ERROR);
694 			}
695 			if (mtest_write(handle, (void*)patternbuf0, pageno,
696 			    line, 1) == -1) {
697 				(void) sprintf(msgbuf, wr_err_msg, pageno);
698 				mtest_message(handle, msgbuf);
699 				return (MTEST_DEV_ERROR);
700 			}
701 		}
702 		if (memcmp((void *)patternbuf0, (void *)readbuf0,
703 			PAGE_SIZE(handle)) != 0) {
704 			cond = CFGA_COND_FAILED;
705 			error_print((void *)patternbuf0, (void *)readbuf0,
706 			    handle, pageno, &total_errors);
707 			TEST_END(ntf_msg);
708 		}
709 		if ((time(NULL) >= time_rep) || (pageno == npages - 1) ||
710 		    (pageno == 0)) {
711 			(void) sprintf(msgbuf, report_msg, m4_msg,
712 			    ln_rd_cmp_msg, ((pageno + 1) * 100) / npages);
713 			mtest_message(handle, msgbuf);
714 			time_rep = time(NULL) + REPORT_SEC * 3;
715 		}
716 	}	/* page */
717 	mtest_message(handle, etf_msg);
718 	error_summary(handle, total_errors);
719 	SET_CONDITION(handle, cond);
720 	return (MTEST_DONE);
721 }
722