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