xref: /titanic_51/usr/src/uts/common/avs/ns/sdbc/sd_tdaemon.c (revision 3270659f55e0928d6edec3d26217cc29398a8149)
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  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Routines for the Infinity Storage Device daemon
28  */
29 
30 #include <sys/types.h>
31 #include <sys/ksynch.h>
32 #include <sys/cmn_err.h>
33 #include <sys/errno.h>
34 #include <sys/buf.h>
35 #include <sys/kmem.h>
36 #include <sys/cred.h>
37 #include <sys/ddi.h>
38 #include <sys/nsc_thread.h>
39 
40 #include "sd_bcache.h"
41 #include "sd_io.h"
42 #include "sd_bio.h"
43 #include "sd_ft.h"
44 #include "sd_misc.h"
45 
46 #define	_INFSD_LOCAL_MEM
47 
48 #define	_CD_VTRK_SIZE(cd)	(dev_tsize[GET_CD_STATE(cd)] * 1024)
49 #define	_CD_VTRK_NUM(cd, len)	((len)/_CD_VTRK_SIZE(cd))
50 #define	_CD_VTRK_OFF(cd, len)	((len)%(_CD_VTRK_SIZE(cd)))
51 
52 #define	FILESIZE (1 << 27) 	/* 128 MB 	*/
53 
54 #define	SIZEMASK 0x0000FFFF
55 #define	_INFSD_RECORD_SIZE(ndx) REC_SIZE
56 #define	GET_SEED(ndx) (gld[ndx] . seed & SIZEMASK)
57 #define	MAX_CD_STS	600
58 #define	MAX_TDAEMONS  128
59 
60 static char devarray[MAX_TDAEMONS][MAX_TDAEMONS*2];
61 static int  dev_tsize[MAX_TDAEMONS*2];
62 static int  dev_flag[MAX_TDAEMONS*2];
63 
64 
65 /*
66  * sd_test options
67  */
68 #define	SD_TEST_CACHE_HIT    0x00000001
69 #define	SD_TEST_CACHE_MISS   0x00000002
70 #define	SD_TEST_CHECK_DATA   0x00000004
71 #define	SD_TEST_READ_ONLY    0x00000008
72 #define	SD_TEST_WRITE_ONLY   0x00000010
73 #define	SD_TEST_SEQUENTIAL   0x00000020
74 
75 static struct cd_sts {
76 	volatile short  cd_state;
77 	volatile char waiting;
78 	volatile char inited;
79 	kcondvar_t cd_blk;
80 	volatile caddr_t asy_key;
81 } cd_test_sts[MAX_CD_STS];
82 
83 #define	SET_CD_STATE(cd, i)	(cd_test_sts[(cd)].cd_state = (short)(i))
84 #define	GET_CD_STATE(cd)	(cd_test_sts[(cd)].cd_state)
85 
86 static kmutex_t tdaemon_lock;
87 static kcondvar_t _wait_daemons;
88 dev_t	_test_async_fail;	/* fail async writes to cache dev_t */
89 static volatile int 	test_stop;
90 
91 static int daemon_awake(int i);
92 static void wakeup_all_tdaemons(void);
93 static void _sd_idle_daemon(void);
94 static void _td_detach_cd(int cd);
95 static int _fork_test_daemon(int num_disks, int test_typ, int loop_cnt,
96     int from, int seed);
97 static void _sd_test_rwloop_seq(int i, int loops, int seed, int forw);
98 static int _sd_copy_pattern_to_handle(_sd_buf_handle_t *handle,
99     nsc_off_t fba_pos, nsc_size_t fba_len);
100 static int _sd_copy_handle(_sd_buf_handle_t *handle1, _sd_buf_handle_t *handle2,
101     nsc_off_t fba_pos1, nsc_off_t fba_pos2, nsc_size_t fba_len, int skew);
102 static int _sd_compare_handle(_sd_buf_handle_t *handle1,
103     _sd_buf_handle_t *handle2, nsc_off_t fba_pos1, nsc_off_t fba_pos2,
104     nsc_size_t fba_len, int skew);
105 static void _sd_direct_test(int c, int loop, int seed, int type);
106 static void set_parameters(void);
107 static void test_dma_loop(int net, int seg);
108 static int _sd_hwrite(_sd_buf_handle_t *buf, nsc_off_t fba_pos,
109     nsc_size_t fba_len, int flag);
110 static void myend(blind_t arg, nsc_off_t fba_pos, nsc_size_t fba_len,
111     int error);
112 static int test_control(int typ, int cd, nsc_off_t fba_pos, nsc_size_t fba_len);
113 
114 int
115 _sim_write(_sd_buf_handle_t *buf, int x)
116 {
117 	int rval;
118 
119 	if (test_stop)
120 		return (EINVAL);
121 	rval = _sd_write(buf, buf->bh_fba_pos, buf->bh_fba_len, x);
122 	return (rval == NSC_HIT ? NSC_DONE : rval);
123 }
124 
125 static int
126 _sd_hwrite(_sd_buf_handle_t *buf, nsc_off_t fba_pos, nsc_size_t fba_len,
127     int flag)
128 {
129 	int rval;
130 
131 	rval = _sd_write(buf, fba_pos, fba_len, flag);
132 	return (rval == NSC_HIT ? NSC_DONE : rval);
133 }
134 
135 #define	_sd_allocate_buf _trk_allocate_buf
136 #define	_sd_write	 _sim_write
137 
138 /*
139  * INF SD daemon global data
140  */
141 
142 volatile int	test_created;
143 static int	_sd_daemon_created;
144 static int 	_sd_num_daemons;
145 
146 static struct gld {
147 	volatile int type;
148 	volatile int loop;
149 	volatile int seed;
150 	volatile int asleep;
151 	kcondvar_t blk;
152 } gld[MAX_TDAEMONS];
153 
154 /*
155  * _sdbc_tdaemon_load: cache is being loaded, initialize any global state that
156  * isn't configurable (lock/sv's).
157  */
158 int
159 _sdbc_tdaemon_load(void)
160 {
161 	int i;
162 
163 	for (i = 0; i < MAX_TDAEMONS; i++)
164 		cv_init(&gld[i].blk, NULL, CV_DRIVER, NULL);
165 
166 	mutex_init(&tdaemon_lock, NULL, MUTEX_DRIVER, NULL);
167 	cv_init(&_wait_daemons, NULL, CV_DRIVER, NULL);
168 
169 	return (0);
170 }
171 /*
172  * _sdbc_tdaemon_unload: cache is being unloaded.
173  */
174 void
175 _sdbc_tdaemon_unload(void)
176 {
177 	int i;
178 
179 	for (i = 0; i < MAX_TDAEMONS; i++) {
180 		cv_destroy(&gld[i].blk);
181 	}
182 
183 	mutex_destroy(&tdaemon_lock);
184 	cv_destroy(&_wait_daemons);
185 
186 }
187 
188 /*
189  * _sdbc_tdaemon_configure: configure the desired number of test daemons.
190  */
191 int
192 _sdbc_tdaemon_configure(int num)
193 {
194 	int i;
195 
196 	if (num >= MAX_TDAEMONS)
197 		return (-1);
198 
199 	for (i = 0; i < num; i++) {
200 		cv_init(&gld[i].blk, NULL, CV_DRIVER, NULL);
201 	}
202 	mutex_enter(&tdaemon_lock);
203 	test_created = 1;
204 	test_stop = 0;
205 	_sd_num_daemons = 0;
206 	mutex_exit(&tdaemon_lock);
207 
208 	mutex_enter(&_sd_cache_lock);
209 	if (_sd_daemon_created == 1) {
210 		mutex_exit(&_sd_cache_lock);
211 		return (-1);
212 	}
213 	_sd_daemon_created = 1;
214 	mutex_exit(&_sd_cache_lock);
215 
216 	for (i = 0; i < num; i++) {
217 		(void) nsc_create_process(
218 		    (void (*)(void *))_sd_idle_daemon, 0, FALSE);
219 	}
220 
221 #ifdef DEBUG
222 	if (num)
223 		cmn_err(CE_NOTE, "!Starting %d SDBC test daemon(s).", num);
224 #endif
225 	return (0);
226 }
227 
228 void
229 _sdbc_tdaemon_deconfigure(void)
230 {
231 	int i, running, retry = 30;
232 
233 	if (_sd_num_daemons) {
234 		_sd_daemon_created = 0;
235 
236 		mutex_enter(&tdaemon_lock);
237 		test_created = 0;
238 		test_stop = 1;
239 		mutex_exit(&tdaemon_lock);
240 
241 		wakeup_all_tdaemons();
242 		while (retry--) {
243 			delay(HZ);
244 			running = 0;
245 			for (i = 0; i < _sd_num_daemons; i++)
246 				if (daemon_awake(i))
247 					running++;
248 			if (running == 0) break;
249 		}
250 	}
251 	for (i = 0; i < MAX_CD_STS; i++) {
252 		cv_destroy(&cd_test_sts[i].cd_blk);
253 		cd_test_sts[i].inited = 0;
254 	}
255 	_sd_num_daemons = 0;
256 }
257 
258 
259 int sind = 0;
260 
261 /*
262  * Globals to change test parameters - Initially added for tests written
263  * by Ajay
264  */
265 #ifdef SD_TDAEMON_DEBUG
266 struct statis {
267 	int cd;
268 	nsc_size_t len;
269 	nsc_off_t offset;
270 	int type;
271 } statis[4000];
272 
273 #define	add_statis(c, l, o, t) (statis[sind].cd = (c), \
274 				statis[sind].len = (l), \
275 				statis[sind].offset = (o), \
276 				statis[sind].type = (t), sind++)
277 int
278 statis_upd(caddr_t adr)
279 {
280 	(void) copyout(statis, adr, sizeof (struct statis) * sind);
281 	return (sind);
282 }
283 #endif /* SD_TDAEMON_DEBUG */
284 
285 static int
286 daemon_awake(int i)
287 {
288 	if (gld[i].asleep == 2)
289 		return (1);
290 	return (0);
291 }
292 
293 static int
294 daemon_nexist(int i)
295 {
296 	if (gld[i].asleep == 0)
297 		return (1);
298 	return (0);
299 }
300 
301 static void
302 daemon_wakeup(int i)
303 {
304 #ifdef _SD_DEBUG
305 	cmn_err(CE_NOTE, "!unblocking %d %x", i, gld[i].blk);
306 #endif
307 	mutex_enter(&tdaemon_lock);
308 	cv_broadcast(&gld[i].blk);
309 	mutex_exit(&tdaemon_lock);
310 }
311 
312 
313 static void
314 wakeup_all_tdaemons(void)
315 {
316 	int i;
317 
318 	for (i = 0; i < _sd_num_daemons; i++)
319 		daemon_wakeup(i);
320 }
321 
322 
323 static void
324 _sd_idle_daemon(void)
325 {
326 	int who;	/* id of this daemon */
327 
328 	mutex_enter(&_sd_cache_lock);
329 	_sd_cache_dem_cnt++;
330 	who = _sd_num_daemons++;
331 	mutex_exit(&_sd_cache_lock);
332 
333 	/* CONSTCOND */
334 	while (1) {
335 		mutex_enter(&tdaemon_lock);
336 		gld[who].asleep = 1;
337 #ifdef DEBUG
338 		cmn_err(CE_NOTE, "!%d daemon: sleeping %p", who,
339 		    (void *)&gld[who].blk);
340 #endif
341 
342 		cv_signal(&_wait_daemons);
343 		if (test_created == 0) {
344 			gld[who].asleep = 0;
345 			mutex_exit(&tdaemon_lock);
346 			mutex_enter(&_sd_cache_lock);
347 			_sd_cache_dem_cnt--;
348 			mutex_exit(&_sd_cache_lock);
349 			return;
350 		} else {
351 			cv_wait(&gld[who].blk, &tdaemon_lock);
352 			mutex_exit(&tdaemon_lock);
353 		}
354 
355 		_sd_print(0, "%d daemon awake type %d loop %d seed %d",
356 		    who, gld[who].type, gld[who].loop, GET_SEED(who));
357 
358 		if (test_created == 0) {
359 			gld[who].asleep = 0;
360 			mutex_enter(&_sd_cache_lock);
361 			_sd_cache_dem_cnt--;
362 			mutex_exit(&_sd_cache_lock);
363 			return;
364 		}
365 		gld[who].asleep = 2;
366 
367 		switch (gld[who].type) {
368 
369 		case 210:
370 			test_dma_loop(gld[who].loop, gld[who].seed);
371 			break;
372 		case 323:
373 			_sd_direct_test(who, gld[who].loop, GET_SEED(who), 0);
374 			break;
375 
376 		case 350:
377 			_sd_test_rwloop_seq(who, gld[who].loop, GET_SEED(who),
378 			    1);
379 			break;
380 		case 351:
381 			_sd_test_rwloop_seq(who, gld[who].loop, GET_SEED(who),
382 			    0);
383 			break;
384 
385 #if 0
386 		case 400:
387 			if (gld[who].loop >= 6)
388 				numdevs = gld[who].loop;
389 			break;
390 #endif
391 		default:
392 			cmn_err(CE_WARN, "!%d daemon %d type inval\n", who,
393 			    gld[who].type);
394 			break;
395 		}
396 		if (test_created == 0) {
397 			gld[who].asleep = 0;
398 			mutex_enter(&_sd_cache_lock);
399 			_sd_cache_dem_cnt--;
400 			mutex_exit(&_sd_cache_lock);
401 			return;
402 		}
403 	}
404 }
405 
406 
407 static void
408 _td_attach_cd(int cd)
409 {
410 	(void) nsc_reserve(_sd_cache_files[cd].cd_rawfd, NSC_MULTI);
411 }
412 
413 
414 static void
415 _td_detach_cd(int cd)
416 {
417 	nsc_release(_sd_cache_files[cd].cd_rawfd);
418 }
419 
420 
421 int
422 _sd_test_start(void *args, int *rvp)
423 {
424 
425 	register struct a {
426 		long num;
427 		long type;
428 		long loop;
429 		long from;
430 		long seed;
431 	} *uap = (struct a *)args;
432 
433 	*rvp = _fork_test_daemon(uap->num, uap->type, uap->loop,
434 	    uap->from, uap->seed);
435 
436 	return (0);
437 }
438 
439 static int
440 test_control(int typ, int cd, nsc_off_t fba_pos, nsc_size_t fba_len)
441 /*
442  * test_control - perform control operations outside of the range
443  * of a test. This is typically called before/after a series of
444  * tests to either check a result or to setup/free a device.
445  */
446 {
447 	int rc = 0;
448 
449 	if ((cd < 0) || (cd >= sdbc_max_devs))
450 		return (-1);
451 	switch (typ) {
452 	case 1:
453 		rc = _sdbc_io_attach_cd((blind_t)(unsigned long)cd);
454 		cmn_err(CE_NOTE, "!_sdbc_io_attach_cd(%d): %d", cd, rc);
455 		break;
456 	case 2:
457 		rc = _sdbc_io_detach_cd((blind_t)(unsigned long)cd);
458 		cmn_err(CE_NOTE, "!_sdbc_io_detach_cd(%d): %d", cd, rc);
459 		break;
460 	case 3:
461 		_test_async_fail = _sd_cache_files[cd].cd_crdev;
462 		cmn_err(CE_NOTE, "!async fail dev %lu (cd=%d)",
463 		    _test_async_fail, cd);
464 		break;
465 	case 4:
466 		_test_async_fail = 0;
467 		cmn_err(CE_NOTE, "!async fail cleared");
468 		break;
469 #if 0
470 	case 5:
471 		_trk_alloc_flag = NSC_PINNABLE;
472 		break;
473 	case 6:
474 		_trk_alloc_flag = 0;
475 		break;
476 #endif
477 	case 7:
478 		rc = _sd_get_pinned((blind_t)(unsigned long)cd);
479 		cmn_err(CE_NOTE, "!get_pinned(%d): %d", cd, rc);
480 		break;
481 	case 8:
482 		rc = _sd_discard_pinned((blind_t)(unsigned long)cd, fba_pos,
483 		    fba_len);
484 		cmn_err(CE_NOTE, "!discard_pinned(%d,%" NSC_SZFMT ",%" NSC_SZFMT
485 		    "): %d", cd, fba_pos, fba_len, rc);
486 		break;
487 	default:
488 		cmn_err(CE_WARN, "!cache device command %d invalid\n", typ);
489 	}
490 	return (rc);
491 }
492 
493 
494 /*
495  * _fork_sd_daemon(): Fork an nunix process that periodically flushes the
496  *                    raw device buffer cache
497  */
498 
499 static int
500 _fork_test_daemon(int num_disks, int test_typ, int loop_cnt, int from, int seed)
501 {
502 	int i;
503 	int type;
504 	int dowait = 0, verify = 0;
505 
506 	if (num_disks == -1) {
507 		return (test_control(test_typ, loop_cnt, from, seed));
508 	}
509 
510 	type = test_typ;
511 	cmn_err(CE_NOTE,
512 	    "!sd_test %d %d %d %d %d", num_disks, type, loop_cnt, from, seed);
513 	if (type == 100) {
514 		test_stop = 1;
515 		return (0);
516 	}
517 
518 	if (type == 99) {
519 		/* Set some parameters for other tests */
520 		switch (num_disks) {
521 			/* Params set for this test */
522 #if 0
523 			case 302 :
524 				_sd_write_len = loop_cnt;
525 				break;
526 			case 303 :
527 				_sd_write_len = loop_cnt;
528 				break;
529 			case 304 :
530 				_sd_trk_zero = loop_cnt;
531 				_sd_trk_size = from;
532 				break;
533 			case 305 :
534 				_sd_min_blks = loop_cnt;
535 				_sd_max_blks = from;
536 				break;
537 #endif
538 			default :
539 				cmn_err(CE_WARN,
540 				    "!Usage : sd_test <test_num> 99"
541 				    " <param1> <param2> <param3>");
542 				break;
543 		}
544 		return (0);
545 	}		/* type == 99 */
546 
547 	if (type > 1000) {
548 		dowait = 1;
549 		type -= 1000;
550 	}
551 	if (type > 1000) {
552 		verify = 1;
553 		type -= 1000;
554 	}
555 
556 again:
557 	set_parameters();
558 
559 	for (i = from; i < (from+num_disks); i++) {
560 		if (daemon_awake(i)) {
561 			cmn_err(CE_WARN, "!Daemon %d awake!?", i);
562 			return (-1);
563 		}
564 		if (daemon_nexist(i)) {
565 			cmn_err(CE_WARN, "!Daemon %d nexist!?", i);
566 			return (-1);
567 		}
568 
569 		gld[i].type = type;
570 		gld[i].loop = loop_cnt;
571 		gld[i].seed = seed;
572 		daemon_wakeup(i);
573 	}
574 	cmn_err(CE_CONT, "!%d daemons woken (test %d)\n", num_disks, type);
575 	if (num_disks <= 0)
576 		return (0);
577 
578 	if (dowait) {
579 	wait:
580 		mutex_enter(&tdaemon_lock);
581 		if (!cv_wait_sig(&_wait_daemons, &tdaemon_lock)) {
582 			mutex_exit(&tdaemon_lock);
583 			test_stop = 1;
584 			cmn_err(CE_WARN, "!Interrupt: stopping tests");
585 			return (-1); /* interrupt */
586 		}
587 		mutex_exit(&tdaemon_lock);
588 
589 		/* wait for all to stop */
590 		if (test_stop)
591 			return (-1);
592 		for (i = from; i < (from+num_disks); i++) {
593 			if (daemon_awake(i))
594 				goto wait;
595 		}
596 	}
597 	if (verify) {
598 		verify = 0;
599 		type++;		/* next test */
600 		goto again;
601 	}
602 	return (0);
603 }
604 
605 int
606 _sd_test_end(void)
607 {
608 	test_created = 0;
609 	test_stop = 1;
610 	return (0);
611 }
612 
613 int
614 _sd_test_init(void *args)
615 {
616 	register struct a {
617 		caddr_t addr;
618 		long ar;
619 		long len;
620 		long tsize;
621 		long flag;
622 	} *uap = (struct a *)args;
623 
624 	if (copyin(uap->addr, devarray[uap->ar], uap->len)) {
625 		return (EFAULT);
626 	}
627 	dev_tsize[uap->ar] = (uap->tsize < 48) ? 48 : uap->tsize;
628 	dev_flag[uap->ar] = uap->flag;
629 	return (0);
630 }
631 
632 
633 typedef struct io_type {
634 	int cd, tsize;
635 	_sd_buf_handle_t *wbuf, *rbuf;
636 	int len, len2, rnet, wnet;
637 	int trk_num, trk_off;
638 	int offset, boff;
639 	char test_pattern;
640 } infnsc_io_t;
641 
642 /* static spinlock_t INFSD_iolock = { SLK_IFS_SRVR, 0 }; */
643 #define	_INFSD_TRK_SIZE() (64*1024)
644 #define	_INFSD_BUF_ALIGN 512	/* Each read/write should be 512 aligned */
645 
646 /*
647  * _sd_test_rwloop_seq(i,loops, seed, forw):
648  *
649  * Sequential I/O test. Writes track records sequentially, either forwards
650  * or backwards (forw = 1 or forw = 0), writing a fixed pattern with a
651  * few unique bytes depending on loop id. Then reads back, checking
652  * for data consistency.
653  */
654 
655 /* ARGSUSED */
656 static void
657 _sd_test_rwloop_seq(int i, int loops, int seed, int forw)
658 {
659 	int cd;
660 	int j, len;
661 	nsc_off_t offset;
662 	nsc_size_t fsize;
663 	int sts;
664 	_sd_buf_handle_t *fbuf, *buf;
665 
666 	if (strlen(devarray[i]) == 0) {
667 		cmn_err(CE_WARN, "!child %d devarray null", i);
668 		return;
669 	}
670 	if ((cd = _sd_open(devarray[i], dev_flag[i])) < 0) {
671 		cmn_err(CE_WARN, "!Open error %s child %d", devarray[i], i);
672 		return;
673 	}
674 	SET_CD_STATE(cd, i);
675 	_td_attach_cd(cd);
676 
677 	(void) _sd_get_partsize((blind_t)(unsigned long)cd, &fsize);
678 	len = 120;
679 
680 	/*
681 	 * Write a base pattern into the first buffer
682 	 */
683 	fbuf = NULL;
684 	offset = 0;
685 	sts = _sd_alloc_buf((blind_t)(unsigned long)cd, 0, len, NSC_WRBUF,
686 	    &fbuf);
687 	if (sts > 0)  {
688 		cmn_err(CE_WARN, "!Buffer alloc failed %d", sts);
689 		return;
690 	}
691 	(void) _sd_copy_pattern_to_handle(fbuf, 0, len);
692 	_td_detach_cd(cd);
693 
694 	offset = 0;
695 	for (j = 0; j < loops; j++) {
696 		if (test_stop == 1) goto done;
697 
698 		offset += len;
699 		if (offset + len > fsize)
700 			break;
701 
702 		buf = NULL;
703 		_td_attach_cd(cd);
704 		sts = _sd_alloc_buf((blind_t)(unsigned long)cd, offset, len,
705 		    NSC_WRBUF, &buf);
706 		if (sts > 0) {
707 			cmn_err(CE_WARN, "!ch%d getbuf error(WRBUF)%d", i, sts);
708 			goto done;
709 		}
710 		(void) _sd_copy_handle(fbuf, buf, 0, offset, len, j);
711 
712 		sts = len;
713 		while (sts > 0) {
714 			if (forw && _sd_hwrite(buf, offset + len - sts,
715 			    12, 0) > 0) {
716 				cmn_err(CE_WARN, "!ch %d fwwr err", i);
717 				test_stop = 1;
718 			}
719 			sts -= 12;
720 			if (!forw && _sd_hwrite(buf, offset + sts, 12, 0) > 0) {
721 				cmn_err(CE_WARN, "!ch %d rvwr err", i);
722 				test_stop = 1;
723 			}
724 		}
725 		if (sts = _sd_free_buf(buf)) {
726 			cmn_err(CE_WARN, "!ch %d freebuf error %d", i, sts);
727 			goto done;
728 		}
729 		_td_detach_cd(cd);
730 	}
731 	offset = 0;
732 	for (j = 0; j < loops; j++) {
733 		if (test_stop == 1) goto done;
734 
735 		offset += len;
736 		if (offset + len > fsize)
737 			break;
738 
739 		buf = NULL;
740 		_td_attach_cd(cd);
741 		sts = _sd_alloc_buf((blind_t)(unsigned long)cd, offset, len,
742 		    NSC_RDBUF, &buf);
743 		if (sts > 0) {
744 			cmn_err(CE_WARN, "!ch%d getbuf error(WRBUF)%d", i, sts);
745 			goto done;
746 		}
747 		(void) _sd_compare_handle(fbuf, buf, 0, offset, len, j);
748 
749 		if (sts = _sd_free_buf(buf)) {
750 			cmn_err(CE_WARN, "!ch %d freebuf error %d", i, sts);
751 			goto done;
752 		}
753 		_td_detach_cd(cd);
754 	}
755 done:
756 	if (sts = _sd_free_buf(fbuf))
757 		cmn_err(CE_WARN, "!child %d freebuf error %d", i, sts);
758 	cmn_err(CE_NOTE, "!TEST OVER : rwloop_seq_%s() child %d",
759 	    forw ? "forw" : "rev", i);
760 }
761 
762 static int
763 _sd_copy_pattern_to_handle(_sd_buf_handle_t *handle, nsc_off_t fba_pos,
764     nsc_size_t fba_len)
765 {
766 	sdbc_cblk_fba_t st_cblk_len;	/* FBA len of starting cache block */
767 	sdbc_cblk_fba_t end_cblk_len;	/* FBA len of ending cache block */
768 	sdbc_cblk_fba_t st_cblk_off;	/* FBA offset into starting cblock */
769 	nsc_size_t cur_fba_len;
770 	int i;
771 	_sd_cctl_t *cc_ent;
772 
773 	cc_ent = handle->bh_centry;
774 	while (CENTRY_BLK(cc_ent) != FBA_TO_BLK_NUM(fba_pos))
775 		cc_ent = cc_ent->cc_chain;
776 
777 	cur_fba_len = fba_len;
778 	st_cblk_off = BLK_FBA_OFF(fba_pos);
779 	st_cblk_len = (BLK_FBAS - st_cblk_off);
780 	if ((nsc_size_t)st_cblk_len >= fba_len) {
781 		end_cblk_len = 0;
782 		st_cblk_len = (sdbc_cblk_fba_t)fba_len;
783 	} else
784 		end_cblk_len = BLK_FBA_OFF(fba_pos + fba_len);
785 
786 	for (i = 0; i < (int)FBA_SIZE(st_cblk_len); i += 4)
787 		*((uint_t *)(void *)(cc_ent->cc_data + FBA_SIZE(st_cblk_off) +
788 		    i)) = nsc_usec();
789 	cur_fba_len -= st_cblk_len;
790 	cc_ent = cc_ent->cc_chain;
791 
792 	while (cur_fba_len > (nsc_size_t)end_cblk_len) {
793 		for (i = 0; i < CACHE_BLOCK_SIZE; i += 4) {
794 			unsigned int usec = nsc_usec();
795 			bcopy(&usec, cc_ent->cc_data + i, 4);
796 		}
797 		cc_ent = cc_ent->cc_chain;
798 		cur_fba_len -= BLK_FBAS;
799 	}
800 	if (cur_fba_len) {
801 		for (i = 0; i < (int)FBA_SIZE(end_cblk_len); i += 4) {
802 			unsigned int usec = nsc_usec();
803 			bcopy(&usec, cc_ent->cc_data + i, 4);
804 		}
805 	}
806 	return (0);
807 }
808 
809 static int
810 _sd_copy_handle(_sd_buf_handle_t *handle1,
811 		_sd_buf_handle_t *handle2,
812 		nsc_off_t fba_pos1,
813 		nsc_off_t fba_pos2,
814 		nsc_size_t fba_len,
815 		int skew)
816 {
817 	sdbc_cblk_fba_t st_cblk_len;	/* FBA len of starting cache block */
818 	sdbc_cblk_fba_t end_cblk_len;	/* FBA len of ending cache block */
819 	sdbc_cblk_fba_t st_cblk_off;	/* FBA offset into starting cblock */
820 	nsc_size_t cur_fba_len;
821 	_sd_cctl_t *cc_ent, *cc_ent1;
822 	unsigned char *skew_word;
823 	int skew_count = 0;
824 
825 	ASSERT_HANDLE_LIMITS(handle1, fba_pos1, fba_len);
826 	ASSERT_HANDLE_LIMITS(handle2, fba_pos2, fba_len);
827 
828 	cc_ent = handle1->bh_centry;
829 	while (CENTRY_BLK(cc_ent) != FBA_TO_BLK_NUM(fba_pos1))
830 		cc_ent = cc_ent->cc_chain;
831 
832 	cc_ent1 = handle2->bh_centry;
833 	while (CENTRY_BLK(cc_ent1) != FBA_TO_BLK_NUM(fba_pos2))
834 		cc_ent1 = cc_ent1->cc_chain;
835 
836 
837 	if (BLK_FBA_OFF(fba_pos1) != BLK_FBA_OFF(fba_pos2)) {
838 		cmn_err(CE_WARN, "!Cannot copy unaligned handles");
839 		return (0);
840 	}
841 
842 	cur_fba_len = fba_len;
843 	st_cblk_off = BLK_FBA_OFF(fba_pos1);
844 	st_cblk_len = (BLK_FBAS - st_cblk_off);
845 	if ((nsc_size_t)st_cblk_len >= fba_len) {
846 		end_cblk_len = 0;
847 		st_cblk_len = (sdbc_cblk_fba_t)fba_len;
848 	} else
849 		end_cblk_len = BLK_FBA_OFF(fba_pos1 + fba_len);
850 
851 	skew_word = cc_ent->cc_data + FBA_SIZE(st_cblk_off);
852 	*skew_word = skew | (++skew_count << 24);
853 	bcopy(cc_ent->cc_data + FBA_SIZE(st_cblk_off), cc_ent1->cc_data +
854 	    FBA_SIZE(st_cblk_off), FBA_SIZE(st_cblk_len));
855 	cur_fba_len -= st_cblk_len;
856 	cc_ent = cc_ent->cc_chain;
857 	cc_ent1 = cc_ent1->cc_chain;
858 
859 	while (cur_fba_len > (nsc_size_t)end_cblk_len) {
860 		skew_word = cc_ent->cc_data;
861 		*skew_word = skew | (++skew_count << 24);
862 		bcopy(cc_ent->cc_data, cc_ent1->cc_data, CACHE_BLOCK_SIZE);
863 		cc_ent = cc_ent->cc_chain;
864 		cc_ent1 = cc_ent1->cc_chain;
865 		cur_fba_len -= BLK_FBAS;
866 	}
867 	if (cur_fba_len) {
868 		skew_word = cc_ent->cc_data;
869 		*skew_word = skew | (++skew_count << 24);
870 		bcopy(cc_ent->cc_data, cc_ent1->cc_data,
871 		    FBA_SIZE(end_cblk_len));
872 	}
873 	return (0);
874 }
875 
876 static int
877 _sd_compare_handle(_sd_buf_handle_t *handle1, _sd_buf_handle_t *handle2,
878     nsc_off_t fba_pos1, nsc_off_t fba_pos2, nsc_size_t fba_len, int skew)
879 {
880 	sdbc_cblk_fba_t st_cblk_len;	/* FBA len of starting cache block */
881 	sdbc_cblk_fba_t end_cblk_len;	/* FBA len of ending cache block */
882 	sdbc_cblk_fba_t st_cblk_off;	/* FBA offset into starting cblock */
883 	nsc_size_t cur_fba_len;
884 	_sd_cctl_t  *cc_ent, *cc_ent1;
885 	unsigned char *skew_word;
886 	int skew_count = 0;
887 
888 	ASSERT_HANDLE_LIMITS(handle1, fba_pos1, fba_len);
889 	ASSERT_HANDLE_LIMITS(handle2, fba_pos2, fba_len);
890 
891 	cc_ent = handle1->bh_centry;
892 	while (CENTRY_BLK(cc_ent) != FBA_TO_BLK_NUM(fba_pos1))
893 		cc_ent = cc_ent->cc_chain;
894 
895 	cc_ent1 = handle2->bh_centry;
896 	while (CENTRY_BLK(cc_ent1) != FBA_TO_BLK_NUM(fba_pos2))
897 		cc_ent1 = cc_ent1->cc_chain;
898 
899 	if (BLK_FBA_OFF(fba_pos1) != BLK_FBA_OFF(fba_pos2)) {
900 		cmn_err(CE_WARN, "!Cannot compare unaligned handles");
901 		return (0);
902 	}
903 
904 	cur_fba_len = fba_len;
905 	st_cblk_off = BLK_FBA_OFF(fba_pos1);
906 	st_cblk_len = (BLK_FBAS - st_cblk_off);
907 	if ((nsc_size_t)st_cblk_len >= fba_len) {
908 		end_cblk_len = 0;
909 		st_cblk_len = (sdbc_cblk_fba_t)fba_len;
910 	} else
911 		end_cblk_len = BLK_FBA_OFF(fba_pos1 + fba_len);
912 
913 	skew_word = cc_ent->cc_data + FBA_SIZE(st_cblk_off);
914 	*skew_word = skew | (++skew_count << 24);
915 	if (bcmp(cc_ent->cc_data + FBA_SIZE(st_cblk_off),
916 	    cc_ent1->cc_data + FBA_SIZE(st_cblk_off),
917 	    FBA_SIZE(st_cblk_len)) != 0)
918 		cmn_err(CE_WARN, "!Data mismatch fba_pos:%" NSC_SZFMT,
919 		    fba_pos2);
920 
921 	cur_fba_len -= st_cblk_len;
922 	cc_ent = cc_ent->cc_chain;
923 	cc_ent1 = cc_ent1->cc_chain;
924 
925 	while (cur_fba_len > (nsc_size_t)end_cblk_len) {
926 		skew_word = cc_ent->cc_data;
927 		*skew_word = skew | (++skew_count << 24);
928 		if (bcmp(cc_ent->cc_data, cc_ent1->cc_data,
929 		    CACHE_BLOCK_SIZE) != 0)
930 			cmn_err(CE_WARN, "!Data mismatch fba_pos:%" NSC_SZFMT,
931 			    fba_pos2);
932 
933 		cc_ent = cc_ent->cc_chain;
934 		cc_ent1 = cc_ent1->cc_chain;
935 		cur_fba_len -= BLK_FBAS;
936 	}
937 	if (cur_fba_len) {
938 		skew_word = cc_ent->cc_data;
939 		*skew_word = skew | (++skew_count << 24);
940 		if (bcmp(cc_ent->cc_data, cc_ent1->cc_data,
941 		    FBA_SIZE(end_cblk_len)) != 0)
942 			cmn_err(CE_WARN, "!Data mismatch fba_pos:%" NSC_SZFMT,
943 			    fba_pos2);
944 	}
945 	return (0);
946 }
947 
948 /*
949  * Macro definition for waiting for an IO buffer to be allocated or a read
950  * to complete. Macro defined so code doesn't have to be typed each time
951  */
952 #define	WAIT_IO(st, cd, buf, l) \
953 if ((st != NSC_DONE) && (st != NSC_HIT)) { \
954 	if (st != NSC_PENDING) \
955 		cmn_err(CE_WARN, "!alloc sts: %d", st); \
956 	else { \
957 		buf = wait_io(cd, &st); \
958 		if (st) { \
959 			cmn_err(CE_WARN, "!ch %d getbuf errpr %d\n", l, st); \
960 			if (buf) \
961 				(void) _sd_free_buf(buf); \
962 			return; \
963 		} \
964 	} \
965 }
966 
967 
968 #undef  _sd_write
969 
970 static int tiodone, iosent, tioerr;
971 
972 /* ARGSUSED */
973 
974 static void
975 myend(blind_t arg, nsc_off_t fba_pos, nsc_size_t fba_len, int error)
976 {
977 	if (error)
978 		tioerr++;
979 	else 	tiodone++;
980 }
981 
982 static int ckd_sskip = 3;
983 
984 /* ARGSUSED3 */
985 static void
986 _sd_direct_test(int c, int loop, int seed, int type)
987 {
988 	nsc_size_t filesize;
989 	int loops;
990 
991 	int cd;
992 	int ckd_hd, recs, rec_size, ckd_doz;
993 	int done_size;
994 	clock_t st_time;
995 	int i;
996 
997 	int ckd_hd_sz, rec_bsz;
998 	int print_stuff;
999 	int throttle;
1000 	struct buf *bp;
1001 	nsc_off_t curpos;
1002 
1003 	caddr_t caddr;
1004 	iosent = 0;
1005 
1006 	print_stuff = 0;
1007 	seed = gld[c].seed;
1008 	rec_size = (seed & 0xff);
1009 	recs = (seed & 0xf00)>>8;
1010 	ckd_hd = (seed & 0xf000)>>12;
1011 	ckd_doz = (seed & 0xf0000)>>16;
1012 	throttle = (seed & 0xff00000)>>20;
1013 	ckd_hd_sz = ckd_hd * 512;
1014 	rec_bsz = rec_size * 512;
1015 
1016 	done_size = 0;
1017 	tiodone = 0;
1018 	curpos = 0;
1019 	tioerr = 0;
1020 
1021 	if (strlen(devarray[c]) == 0) {
1022 		cmn_err(CE_WARN, "!child %d devarray null\n", c);
1023 		return;
1024 	}
1025 	if ((cd = _sd_open(devarray[c], dev_flag[c])) < 0) {
1026 		cmn_err(CE_WARN, "!Open error %s child %d\n", devarray[c], c);
1027 		return;
1028 	}
1029 
1030 	caddr = (caddr_t)nsc_kmem_alloc(20 * 8192, KM_SLEEP, sdbc_local_mem);
1031 
1032 	(void) _sd_get_partsize((blind_t)(unsigned long)cd, &filesize);
1033 	filesize = FBA_SIZE(filesize);
1034 	loops = ((nsc_size_t)loop > (filesize / (60 * 1024))) ?
1035 	    (filesize / (60 * 1024)) : loop;
1036 
1037 	st_time = nsc_usec();
1038 	cmn_err(CE_CONT, "!Test 100: %s file %d cd %d loops %x seed\n",
1039 	    devarray[c], cd, loop, seed);
1040 	cmn_err(CE_CONT,
1041 	    "!Test 100: %d recsize %d recs %d throttle %d hd %d doz\n",
1042 	    rec_size, recs, throttle, ckd_hd, ckd_doz);
1043 
1044 	for (i = 0; i < loops; i++) {
1045 		curpos = i * 120;
1046 		if (ckd_doz) {
1047 			bp = sd_alloc_iob(_sd_cache_files[cd].cd_crdev,
1048 			    curpos, 20, B_WRITE);
1049 			sd_add_mem(bp, caddr, ckd_hd_sz);
1050 			(void) sd_start_io(bp,
1051 			    _sd_cache_files[cd].cd_strategy, myend, NULL);
1052 			iosent++;
1053 			curpos += ckd_sskip;
1054 		}
1055 		if (ckd_doz == 2) {
1056 			bp = sd_alloc_iob(_sd_cache_files[cd].cd_crdev,
1057 			    curpos, 20, B_WRITE);
1058 			sd_add_mem(bp, caddr, 4096-ckd_sskip*512);
1059 			(void) sd_start_io(bp,
1060 			    _sd_cache_files[cd].cd_strategy, myend, NULL);
1061 			iosent++;
1062 			curpos += 4096-ckd_sskip*512;
1063 		}
1064 		bp = sd_alloc_iob(_sd_cache_files[cd].cd_crdev,
1065 		    curpos, 20, B_WRITE);
1066 		sd_add_mem(bp, caddr, recs * rec_bsz);
1067 		(void) sd_start_io(bp,
1068 		    _sd_cache_files[cd].cd_strategy, myend, NULL);
1069 		iosent++;
1070 
1071 		done_size += recs * rec_bsz;
1072 
1073 		if (tiodone && ((tiodone / 300) > print_stuff)) {
1074 			cmn_err(CE_CONT, "!Done %d ios %d size in %lu time\n",
1075 			    tiodone,
1076 			    ckd_doz ? ((ckd_doz == 2) ?
1077 			    (tiodone * (recs * rec_bsz + 4096)) / 3:
1078 			    (tiodone * (recs * rec_bsz + ckd_hd_sz)) / 2) :
1079 			    (tiodone * (recs * rec_bsz)),
1080 			    (nsc_usec() - st_time) / 1000);
1081 			print_stuff++;
1082 		}
1083 		while ((iosent - (tiodone + tioerr)) > throttle)
1084 			;
1085 	}
1086 	while ((tiodone + tioerr) < iosent) {
1087 		if (tiodone && ((tiodone / 300) > print_stuff)) {
1088 			cmn_err(CE_CONT, "!Done %d ios %d size in %lu time\n",
1089 			    tiodone,
1090 			    ckd_doz ? ((ckd_doz == 2) ?
1091 			    (tiodone * (recs * rec_bsz + 4096)) / 3:
1092 			    (tiodone * (recs * rec_bsz + ckd_hd_sz)) / 2) :
1093 			    (tiodone * (recs * rec_bsz)),
1094 			    (nsc_usec() - st_time) / 1000);
1095 			print_stuff++;
1096 		}
1097 	}
1098 	cmn_err(CE_CONT, "!Done %d ios %d size in %lu time\n",
1099 	    tiodone,
1100 	    ckd_doz ? ((ckd_doz == 2) ?
1101 	    (tiodone * (recs * rec_bsz + 4096)) / 3:
1102 	    (tiodone * (recs * rec_bsz + ckd_hd_sz)) / 2) :
1103 	    (tiodone * (recs * rec_bsz)),
1104 	    (nsc_usec() - st_time) / 1000);
1105 
1106 	print_stuff++;
1107 	nsc_kmem_free(caddr, 20 * 8192);
1108 }
1109 
1110 static void
1111 set_parameters(void)
1112 {
1113 	test_stop = 0;
1114 }
1115 
1116 static nsc_mem_t *dma_test = NULL;
1117 static int *dma_mem = NULL;
1118 
1119 static int
1120 init_dmatest(void)
1121 {
1122 	dma_test = nsc_register_mem("dmatest:mem", NSC_MEM_GLOBAL, 0);
1123 	dma_mem = (int *)nsc_kmem_zalloc(4096, 0, dma_test);
1124 	if (!dma_mem) {
1125 		cmn_err(CE_NOTE, "!could not get rm mem\n");
1126 		return (1);
1127 	}
1128 	cmn_err(CE_NOTE, "!rm = 0x%p\n", (void *)dma_mem);
1129 	return (0);
1130 }
1131 
1132 /*ARGSUSED*/
1133 static void
1134 release_dmatest(void)
1135 {
1136 	nsc_kmem_free(dma_mem, 1);
1137 	nsc_unregister_mem(dma_test);
1138 	dma_test = NULL;
1139 	dma_mem = NULL;
1140 }
1141 /*ARGSUSED*/
1142 static void
1143 test_dma_loop(int net, int seg)
1144 {
1145 	delay(3*HZ);
1146 
1147 	if (!dma_mem && init_dmatest()) {
1148 		cmn_err(CE_WARN, "!test_dma_loop: init failed");
1149 		return;
1150 	}
1151 
1152 	/*
1153 	 * The body of test loop is removed since we don't use any more
1154 	 */
1155 
1156 	release_dmatest();
1157 }
1158