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
_sim_write(_sd_buf_handle_t * buf,int x)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
_sd_hwrite(_sd_buf_handle_t * buf,nsc_off_t fba_pos,nsc_size_t fba_len,int flag)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
_sdbc_tdaemon_load(void)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
_sdbc_tdaemon_unload(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
_sdbc_tdaemon_configure(int num)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
_sdbc_tdaemon_deconfigure(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
statis_upd(caddr_t adr)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
daemon_awake(int i)286 daemon_awake(int i)
287 {
288 if (gld[i].asleep == 2)
289 return (1);
290 return (0);
291 }
292
293 static int
daemon_nexist(int i)294 daemon_nexist(int i)
295 {
296 if (gld[i].asleep == 0)
297 return (1);
298 return (0);
299 }
300
301 static void
daemon_wakeup(int i)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
wakeup_all_tdaemons(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
_sd_idle_daemon(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
_td_attach_cd(int cd)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
_td_detach_cd(int cd)415 _td_detach_cd(int cd)
416 {
417 nsc_release(_sd_cache_files[cd].cd_rawfd);
418 }
419
420
421 int
_sd_test_start(void * args,int * rvp)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
test_control(int typ,int cd,nsc_off_t fba_pos,nsc_size_t fba_len)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
_fork_test_daemon(int num_disks,int test_typ,int loop_cnt,int from,int seed)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
_sd_test_end(void)606 _sd_test_end(void)
607 {
608 test_created = 0;
609 test_stop = 1;
610 return (0);
611 }
612
613 int
_sd_test_init(void * args)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
_sd_test_rwloop_seq(int i,int loops,int seed,int forw)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
_sd_copy_pattern_to_handle(_sd_buf_handle_t * handle,nsc_off_t fba_pos,nsc_size_t fba_len)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
_sd_copy_handle(_sd_buf_handle_t * handle1,_sd_buf_handle_t * handle2,nsc_off_t fba_pos1,nsc_off_t fba_pos2,nsc_size_t fba_len,int skew)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
_sd_compare_handle(_sd_buf_handle_t * handle1,_sd_buf_handle_t * handle2,nsc_off_t fba_pos1,nsc_off_t fba_pos2,nsc_size_t fba_len,int skew)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
myend(blind_t arg,nsc_off_t fba_pos,nsc_size_t fba_len,int error)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
_sd_direct_test(int c,int loop,int seed,int type)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
set_parameters(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
init_dmatest(void)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
release_dmatest(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
test_dma_loop(int net,int seg)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