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
60static char devarray[MAX_TDAEMONS][MAX_TDAEMONS*2];
61static int  dev_tsize[MAX_TDAEMONS*2];
62static 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
75static 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
86static kmutex_t tdaemon_lock;
87static kcondvar_t _wait_daemons;
88dev_t	_test_async_fail;	/* fail async writes to cache dev_t */
89static volatile int 	test_stop;
90
91static int daemon_awake(int i);
92static void wakeup_all_tdaemons(void);
93static void _sd_idle_daemon(void);
94static void _td_detach_cd(int cd);
95static int _fork_test_daemon(int num_disks, int test_typ, int loop_cnt,
96    int from, int seed);
97static void _sd_test_rwloop_seq(int i, int loops, int seed, int forw);
98static int _sd_copy_pattern_to_handle(_sd_buf_handle_t *handle,
99    nsc_off_t fba_pos, nsc_size_t fba_len);
100static 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);
102static 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);
105static void _sd_direct_test(int c, int loop, int seed, int type);
106static void set_parameters(void);
107static void test_dma_loop(int net, int seg);
108static int _sd_hwrite(_sd_buf_handle_t *buf, nsc_off_t fba_pos,
109    nsc_size_t fba_len, int flag);
110static void myend(blind_t arg, nsc_off_t fba_pos, nsc_size_t fba_len,
111    int error);
112static int test_control(int typ, int cd, nsc_off_t fba_pos, nsc_size_t fba_len);
113
114int
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
125static 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
142volatile int	test_created;
143static int	_sd_daemon_created;
144static int 	_sd_num_daemons;
145
146static 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 */
158int
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 */
174void
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 */
191int
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
228void
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
259int sind = 0;
260
261/*
262 * Globals to change test parameters - Initially added for tests written
263 * by Ajay
264 */
265#ifdef SD_TDAEMON_DEBUG
266struct 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++)
277int
278statis_upd(caddr_t adr)
279{
280	(void) copyout(statis, adr, sizeof (struct statis) * sind);
281	return (sind);
282}
283#endif /* SD_TDAEMON_DEBUG */
284
285static int
286daemon_awake(int i)
287{
288	if (gld[i].asleep == 2)
289		return (1);
290	return (0);
291}
292
293static int
294daemon_nexist(int i)
295{
296	if (gld[i].asleep == 0)
297		return (1);
298	return (0);
299}
300
301static void
302daemon_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
313static void
314wakeup_all_tdaemons(void)
315{
316	int i;
317
318	for (i = 0; i < _sd_num_daemons; i++)
319		daemon_wakeup(i);
320}
321
322
323static 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
407static void
408_td_attach_cd(int cd)
409{
410	(void) nsc_reserve(_sd_cache_files[cd].cd_rawfd, NSC_MULTI);
411}
412
413
414static void
415_td_detach_cd(int cd)
416{
417	nsc_release(_sd_cache_files[cd].cd_rawfd);
418}
419
420
421int
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
439static int
440test_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
499static 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
556again:
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
605int
606_sd_test_end(void)
607{
608	test_created = 0;
609	test_stop = 1;
610	return (0);
611}
612
613int
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
633typedef 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 */
656static 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	}
755done:
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
762static 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
809static 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
876static 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) \
953if ((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
970static int tiodone, iosent, tioerr;
971
972/* ARGSUSED */
973
974static void
975myend(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
982static int ckd_sskip = 3;
983
984/* ARGSUSED3 */
985static 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
1110static void
1111set_parameters(void)
1112{
1113	test_stop = 0;
1114}
1115
1116static nsc_mem_t *dma_test = NULL;
1117static int *dma_mem = NULL;
1118
1119static int
1120init_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*/
1133static void
1134release_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*/
1142static void
1143test_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