Feb 7,1997 onl5v4: Solaris 2.5 cc ドライバのデバッグ. テスト・プログラムによるデバッグ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (http://www-online.kek.jp/~inoue/CAMAC/onl5v4-sol2.5/debug-step8-log.txt) (ftp://onl5v4.kek.jp/export/home/onl5v4/inoue/CAMAC/Log/step8.log) 高エネルギー加速器研究機構 素粒子原子核研究所 物理、オンライングループ 井上 栄二 (1). 現状確認。 (a). "cam1",シングル・アクション read/write は、ok. o "cam1" の実行。 onl5v4[43]% cam1 5 camlib: debug: enter CAMOPN() cc_open: debug: enter cc_open cc_getinfo: debug: enter cc_getinfo cc_getinfo: debug: enter cc_getinfo camlib: debug: CAMOPN() normal return Input n a f (data)>3 0 0 N=3 A=0 F=0 Q=1 X=1 Data:000000(Hex) 00000000(Dec) Input n a f (data)>3 0 16 55555 N=3 A=0 F=16 Q=1 X=1 Data:00D903(Hex) 00055555(Dec) Input n a f (data)>3 0 0 N=3 A=0 F=0 Q=1 X=1 Data:00D903(Hex) 00055555(Dec) Input n a f (data)>3 0 16 0 N=3 A=0 F=16 Q=1 X=1 Data:000000(Hex) 00000000(Dec) Input n a f (data)>3 0 0 N=3 A=0 F=0 Q=1 X=1 Data:000000(Hex) 00000000(Dec) onl5v4[44]% o ok. 正しく動作している。 CAMAC モジュール上の LED も正しく点灯 している。 (b). "cam3",camac 割り込み は、NG. o "cam3" の実行。 onl5v4[48]% make cam3 cc -O cam3.c -o cam3 -I. -L. -lcamac onl5v4[49]% cam3 camlib: debug: enter CAMOPN() cc_open: debug: enter cc_open cc_getinfo: debug: enter cc_getinfo cc_getinfo: debug: enter cc_getinfo camlib: debug: CAMOPN() normal return *** Now waiting LAM ... N=3 Loop=10 Timeout=0 sec Timeout !! count=1 Timeout !! count=2 Timeout !! count=3 Timeout !! count=4 Timeout !! count=5 Timeout !! count=6 Timeout !! count=7 Timeout !! count=8 Timeout !! count=9 Timeout !! count=10 *** cam3 nomal end. onl5v4[50]% Feb 3 13:57:45 onl5v4 su: 'su root' succeeded for inoue on /dev/pts/1 cc_detach: dettaching the CAMAC device driver... CAMAC device driver V1.3x, 1991-1993 by Y.TAKEUCHI (T.I.T.) cc0 at VME0: vme16d16 0xff00 VME level 4 vector 0xff sparc ipl 7 WARNING: spurios VMEbus interrupt on level 4, vec 0 WARNING: spurios VMEbus interrupt on level 4, vec 0 WARNING: spurios VMEbus interrupt on level 4, vec 0 WARNING: spurios VMEbus interrupt on level 4, vec 0 WARNING: spurios VMEbus interrupt on level 4, vec 0 WARNING: spurios VMEbus interrupt on level 4, vec 0 WARNING: spurios VMEbus interrupt on level 4, vec 0 WARNING: spurios VMEbus interrupt on level 4, vec 0 o "cam3" のループの途中で、CAMAC スイッチ・レジスタの LAM のボタン を押すと、k2917 のフロント・パネル上の LAM の LED が点灯し、 コンソール上には、 WARNING: spurios VMEbus interrupt on level 4, vec 0 のメッセージが表示される。 (2). k2917 のベクタ・アドレス用のジャンパをチェックする。 default の設定になっていることを確認した。 1. Bus Request Level 3 2. BGI 0-2 は BGO 0-2 にジャンパしてある。 BGI 3 / BGO 3 は、2917 の DMA コントローラのために選択してある。 3. ベース・アドレスは、0xff00 に選択してある。 以上である。 つまり、インタラプト・ベクタ・アドレスはジャンパで設定 するようにはなっていない。 o インタラプト・ベクタ・アドレスはどのように設定するのか。 チェック。 cc_probe 部で設定 ? (3). インタラプト・ベクタ・アドレスはどのように設定しているか。 o vec をキーにしてチェック onl5v4[42]% grep vec * | less camlib.c:static struct iovec vec[3]; camlib.c: vec[0].iov_base = (caddr_t)&message; camlib.c: vec[0].iov_len = sizeof(struct cc_message); camlib.c: if ((status = writev(cc_path, vec, 1)) != 0) : cc.c: * Device driver ops vector. * cc.c:u_short intrvec = 0x00ff; cc.c: cc->k->lamv = (u_short)intrvec; cc.c: cc->k->donv = (u_short)intrvec; cc.c: cc->k->empv = (u_short)intrvec; cc.c: cc->k->abov = (u_short)intrvec; cc.c: register struct iovec *iov = uio->uio_iov; cc.c: struct iovec iov_save, *iovs = &iov_save; : sys_obpdefs.h: * cope with this gracefully (e.g. by continuing to vector through the ROM onl5v4[43]% o cc.c を修正 onl5v4[51]% vi cc.c : u_short intrpri = 4; /* by E.Inoue */ /*u_short intrvec = 0x00ff; */ u_short intrvec = 0xff; : onl5v4[52]% o ドライバを make し直してみる。 onl5v4[53]% make clean \rm -f cc *.o libcamac.a cam1 cam3 *~ core onl5v4[54]% make ./script/cc_build.sh [Building for sun4m] "cc.c", line 1017: warning: semantics of ">>" change in ANSI C; use explicit cast : cc -O cam1.c -o cam1 -I. -L. -lcamac cc -O cam3.c -o cam3 -I. -L. -lcamac onl5v4[55]% onl5v4# make unload ./script/cc_unload.sh [Removing CAMAC device driver] [Removing CAMAC device driver from system] [Deleting CAMAC device files] onl5v4# make load ./script/cc_load.sh [Installing CAMAC device driver] [Adding CAMAC device driver to system] cc_identify: debug: enter cc_identify cc_identify: debug: succeeded cc_probe: debug: enter cc_probe cc_probe: debug: succeeded cc_attach: debug: enter cc_attach [Configuring CAMAC device driver] [Making CAMAC device files] onl5v4# onl5v4[41]% cam3 camlib: debug: enter CAMOPN() cc_open: debug: enter cc_open cc_getinfo: debug: enter cc_getinfo cc_getinfo: debug: enter cc_getinfo camlib: debug: CAMOPN() normal return *** Now waiting LAM ... N=3 Loop=10 Timeout=0 sec Timeout !! count=1 Timeout !! count=2 Timeout !! count=3 Timeout !! count=4 Timeout !! count=5 Timeout !! count=6 Timeout !! count=7 Timeout !! count=8 Timeout !! count=9 Timeout !! count=10 *** cam3 nomal end. onl5v4[42]% onl5v4 console login: Feb 4 14:02:09 onl5v4 su: 'su root' succeeded for inoue o n /dev/pts/3 cc_detach: dettaching the CAMAC device driver... CAMAC device driver V1.3x, 1991-1993 by Y.TAKEUCHI (T.I.T.) cc0 at VME0: vme16d16 0xff00 VME level 4 vector 0xff sparc ipl 7 WARNING: spurios VMEbus interrupt on level 4, vec 0 WARNING: spurios VMEbus interrupt on level 4, vec 0 WARNING: spurios VMEbus interrupt on level 4, vec 0 WARNING: spurios VMEbus interrupt on level 4, vec 0 WARNING: spurios VMEbus interrupt on level 4, vec 0 WARNING: spurios VMEbus interrupt on level 4, vec 0 WARNING: spurios VMEbus interrupt on level 4, vec 0 WARNING: spurios VMEbus interrupt on level 4, vec 0 WARNING: spurios VMEbus interrupt on level 4, vec 0 o 症状は変わらない。 o cc_open ルーチンで "cc->k->lamv" をセットした後で読み返してみる。 onl5v4[71]% vi cc.c : cc->k->aboc = (u_short)(CC_INT_AUTO_CLEAR | intrpri); cc->k->lamv = (u_short)intrvec; cc->k->donv = (u_short)intrvec; cc->k->empv = (u_short)intrvec; cc->k->abov = (u_short)intrvec; /* by E.Inoue */ uprintf("cc_open: debug: cc->k->lamv = %x\n", cc->k->lamv); return 0; } onl5v4[72]% o ドライバを make し直してみる。 onl5v4[38]% cam3 camlib: debug: enter CAMOPN() cc_open: debug: enter cc_open cc_open: debug: cc->k->lamv = ffff cc_getinfo: debug: enter cc_getinfo cc_getinfo: debug: enter cc_getinfo camlib: debug: CAMOPN() normal return *** Now waiting LAM ... N=3 Loop=10 Timeout=0 sec Timeout !! count=1 Timeout !! count=2 Timeout !! count=3 Timeout !! count=4 Timeout !! count=5 Timeout !! count=6 Timeout !! count=7 Timeout !! count=8 Timeout !! count=9 Timeout !! count=10 *** cam3 nomal end. onl5v4[39]% o cc_ioctl ルーチンにデバッグ用の uprintf 文を入れてみる。 コンパイル、ロード、cam3 実行 onl5v4[110]% cam3 camlib: debug: enter CAMOPN() cc_open: debug: enter cc_open cc_open: debug: uprintf cc->k->lamv = 0xffff cc_getinfo: debug: enter cc_getinfo cc_getinfo: debug: enter cc_getinfo camlib: debug: CAMOPN() normal return *** Now waiting LAM ... N=3 Loop=10 Timeout=0 sec cc_ioctl: CCIOC_WAIT_LAM: debug: uprintf cc->k->lamv = 0xff00 Timeout !! count=1 cc_ioctl: CCIOC_WAIT_LAM: debug: uprintf cc->k->lamv = 0xff00 Timeout !! count=2 cc_ioctl: CCIOC_WAIT_LAM: debug: uprintf cc->k->lamv = 0xff00 Timeout !! count=3 cc_ioctl: CCIOC_WAIT_LAM: debug: uprintf cc->k->lamv = 0xff00 Timeout !! count=4 cc_ioctl: CCIOC_WAIT_LAM: debug: uprintf cc->k->lamv = 0xff00 Timeout !! count=5 cc_ioctl: CCIOC_WAIT_LAM: debug: uprintf cc->k->lamv = 0xff00 Timeout !! count=6 cc_ioctl: CCIOC_WAIT_LAM: debug: uprintf cc->k->lamv = 0xff00 Timeout !! count=7 cc_ioctl: CCIOC_WAIT_LAM: debug: uprintf cc->k->lamv = 0xff00 Timeout !! count=8 cc_ioctl: CCIOC_WAIT_LAM: debug: uprintf cc->k->lamv = 0xff00 Timeout !! count=9 cc_ioctl: CCIOC_WAIT_LAM: debug: uprintf cc->k->lamv = 0xff00 Timeout !! count=10 *** cam3 nomal end. onl5v4[111]% o cc_open 時にセットしたインタラプト・ベクタ・アドレスが CAM_WaitLAM ルーチンを実行時には、リセットされてしまっている。 o k2917 のインタラプト・コントロール・レジスタについて インタラプト・コントロール・レジスタはインタラプト・リクエスト・レベ ルをイネーブルしたり選択するために使われる。 レジスタの構成および、 インタラプト・コントロール・レジスタの詳細は以下の通りである。 15 08 07 06 05 04 03 02 01 00 +----------------+------+-------+------+-----+------+-------+-------+-------+ | | FLAG | FLG | VEC- | INT | INT | IRQ | IRQ | IRQ | | <- Not Used -> | BIT | AUTO- | TOR | ENA | AUTO | LEVEL | LEVEL | LEVEL | | | | CLR | | | CLR | 2 | 1 | 0 | +----------------+------+-------+------+-----+------+-------+-------+-------+ インタラプト・コントロール・レジスタのオフセット LAM D16 = $40 DONE D16 = $42 DMA BUFFER EMPTY D16 = $44 LIST ABORT D16 = $46 BIT# MNEMONIC DESCRIPTION 15-8 N/U Not Used. D16動作が実行されるときには、これらのビットは 明確にするためだけに表示される。 7 FLAG FLAG. このビットはソフトウェアでテストや命令のセットに関連 して使うことができる。 6 VECTOR Vector. このビットはゼロにセットしなければならない。 2917は 内部ベクタを使う。 5 FLG AUTO-CLR Flag Auto-Clear. このビットがセットされる時は、インタラプト アクノリッジ・サイクルの期間に、FLAGビットは自動的にクリア される。 4 INT ENA Interrupt Enable. このビットを1にセットすると、インタラプト がイネーブルされる。 3 INT AUTO-CLR Interrupt Auto-Clear. このビットを1にセットすると、このリク エストに応じてインタラプト・アクノリッジ・サイクルの期間 に、ビット#4(INT ENA)をクリアする。 2-0 IRQ LEVEL Interrupt Request Level. この3ビットのフィールドはインタラ プトのレベルを決める。 1から7までを発行することができる。 値ゼロはインタラプトをディセーブルする。 o k2917 のインタラプト・ベクタ・レジスタについて 各インタラプト・コントロール・レジスタは自分に対応するインタラプト・ ベクタ・レジスタを持つ。 各レジスタは8ビット長で、インタラプト・アク ノリッジ・サイクルの期間にデータ・バイトを供給する。 インタラプト・ ベクタ・レジスタの構成は以下の通りである。 15 08 07 06 05 04 03 02 01 00 +----------------+------+-------+------+-----+------+-------+-------+-------+ | | Bit Bit | | <- Not Used -> | 07 <------------- Interrupt Vector ----------> 00 | | | | +----------------+------+-------+------+-----+------+-------+-------+-------+ インタラプト・ベクタ・レジスタのオフセット LAM D16 = $48 DONE D16 = $4A DMA BUFFER EMPTY D16 = $4C LIST ABORT D16 = $4E (3). cam3.c のチェック。 LAM のテストでコールしている順序はどうなっているか。 どの時点でインタラプト・ベクタ・レジスタはクリアされるのか。 cc.c のチェック。 どの部分でインタラプト・ベクタ・レジスタをセットし直すべきか。 o cam3.c が cc ドライバをコールする手順は次の通りである。 1. CAM_Open("/k3922",1) /* camac open */ camlib.h:#define CAM_Open CAMOPN CAMOPN() { printf("camlib: debug: enter CAMOPN()\n"); if ((cc_path = open("/dev/cc", O_RDWR)) == -1) return ENODEV; file_pointer = 0; printf("camlib: debug: CAMOPN() normal return\n"); return 0; } 参考. open("/dev/cc", O_RDWR) を実行すると、cc ドライバ・プログラ ムの "cc_open" ルーチンがコールされる。 static int cc_open(dev_t *devp, int flag, int otyp, cred_t *cred_p) { register int unit; register struct cc_device *cc = &ccdevice[0]; void bzero(); /* by E.Inoue */ int dat; /* if (unit >= NCC || !md || md->md_alive == 0) return (ENXIO); */ /* by E.Inoue */ uprintf("cc_open: debug: enter cc_open\n"); if (cc->cc_busy == CC_BUSY) return (EBUSY); /* initialize ccdevice */ cc->max_branch = CC_K_MAX_BRANCH; /* set busy flag */ cc->cc_busy = CC_BUSY; /* set interrupt registers of K2917 */ cc->k->lamc = (u_short)(CC_INT_AUTO_CLEAR | intrpri); cc->k->donc = (u_short)(CC_INT_AUTO_CLEAR | intrpri); cc->k->empc = (u_short)(CC_INT_AUTO_CLEAR | intrpri); cc->k->aboc = (u_short)(CC_INT_AUTO_CLEAR | intrpri); cc->k->lamv = (u_short)intrvec; cc->k->donv = (u_short)intrvec; cc->k->empv = (u_short)intrvec; cc->k->abov = (u_short)intrvec; /* by E.Inoue */ uprintf("cc_open: debug: uprintf cc->k->lamv = 0x%x\n", cc->k->lamv); return 0; } 現在の cc ドライバ・プログラムでは、このルーチンの中でベクタ・ アドレスの設定をやっている。 2. CSETBR(1) CSETBR(branch) int branch; { return ioctl(cc_path, CCIOC_SET_BRANCH, &branch); } ioctl(cc_path, CCIOC_SET_BRANCH, &branch) を実行すると、 cc ドライバ・プログラムの "cc_ioctl"ルーチンがコールされ、 以下の部分が実行される。 : case CCIOC_SET_BRANCH: if (*(int *)data >= 0 && *(int *)data < cc->max_branch) cc->cur_branch = *(int *)data; break; : 参考. このコールは、k2917 の最大の台数を1にセットしている。 3. CSETCR(0) CSETCR(crate) int crate; { return ioctl(cc_path, CCIOC_SET_CRATE, &crate); } ioctl(cc_path, CCIOC_SET_CRATE, &crate) を実行すると、 cc ドライバ・プログラムの "cc_ioctl"ルーチンがコールされ、 以下の部分が実行される。 : case CCIOC_SET_CRATE: if (*(int *)data >= 0 && *(int *)data < MAX_CRATE) cc->cur_crate = *(int *)data; break; : 参考. このコールは、k3922 のクレート・アドレスを0にセットしている。 4. CGENC() CGENC() { int status, i, q, x; status = CAMAC(NAF(30, 0, 1), &i, &q, &x); if (status != 0) return status; i |= 2; return CAMAC(NAF(30, 0, 17), &i, &q, &x); } : : CAMAC(naf, dat, q, x) int naf, *dat, *q, *x; { register int status; u_short qx; message.command = (u_short)CC_CMD_DOSINGLE; message.mode = (u_short)CC_BIT24; message.naf = (u_short)naf; message.ptr_data = (u_short *)dat; message.ptr_qx = (u_short *)&qx; vec[0].iov_base = (caddr_t)&message; vec[0].iov_len = sizeof(struct cc_message); if ((status = writev(cc_path, vec, 1)) != 0) return status; *x = ((qx & CC_NOX) == 0) ? 1 : 0; *q = ((qx & CC_NOQ) == 0) ? 1 : 0; check_file_pointer(2); return (qx >> 12); } : 参考. このコールは、CAMAC データウェイにCAMAC C(Clear) を生成する。 CAMAC モジュールをクリアする。 writev(cc_path, vec, 1) を実行すると、cc ドライバ・プログラム の "cc_write"ルーチンがコールされ、以下の部分が実行される。 static int cc_write(dev_t dev, struct uio *uio, cred_t *cred_p) { register struct cc_device *cc = &ccdevice[0]; register struct iovec *iov = uio->uio_iov; register u_short mode, naf; register int len, code, step_count; struct uio uio_save, *uios = &uio_save; struct iovec iov_save, *iovs = &iov_save; int retlen; char klname[9]; /* if (unit >= NCC) return ENXIO; */ cc->dev = dev; cc->uio = uio; cc->ptr_kdata = data_area; cc->len_kdata = 0; /* if (uiomove(&message, sizeof(struct cc_message), UIO_WRITE, uio)) return EFAULT; */ copyin((caddr_t)iov->iov_base, (caddr_t)&message, sizeof(message)); cc->status = 0; cc_sys_status = 0; cc->mode = mode = message.mode; cc->naf = naf = message.naf; /* save iov, uio */ iovs->iov_base = iov->iov_base; iovs->iov_len = iov->iov_len; uios->uio_iovcnt = uio->uio_iovcnt; uios->uio_offset = uio->uio_offset; uios->uio_segflg = uio->uio_segflg; uios->uio_resid = uio->uio_resid; switch (message.command) { /************************* * CAMAC single action * *************************/ case CC_CMD_DOSINGLE: switch (naf & 0x0018) { case 0x0000: /* CAMAC read */ camac_s(cc, mode, naf, data_area); if ((mode & CC_BIT16) == 0) copyout((caddr_t)data_area, (caddr_t)message.ptr_data, sizeof(u_short) * 2); else copyout((caddr_t)data_area, (caddr_t)message.ptr_data, sizeof(u_short)); break; case 0x0010: /* CAMAC write */ if ((mode & CC_BIT16) == 0) copyin((caddr_t)message.ptr_data, (caddr_t)data_area, sizeof(u_short) * 2); else copyin((caddr_t)message.ptr_data, (caddr_t)data_area, sizeof(u_short)); camac_s(cc, mode, naf, data_area); break; default: /* NDT */ camac_s(cc, mode, naf, data_area); break; } copyout((caddr_t)((u_short *)&cc->camac_qx), (caddr_t)message.ptr_qx, 2); break; 5. CGENZ() CGENZ() { int status, i, q, x; status = CAMAC(NAF(30, 0, 1), &i, &q, &x); if (status != 0) return status; i |= 1; return CAMAC(NAF(30, 0, 17), &i, &q, &x); } 参考. このコールは、CAMAC データウェイにCAMAC Z(Initialize) を生成 する。 CAMAC モジュールを初期化する。 6. CREMI() CREMI() { int status, i, q, x; status = CAMAC(NAF(30, 0, 1), &i, &q, &x); if (status != 0) return status; i &= ~4; return CAMAC(NAF(30, 0, 17), &i, &q, &x); } 参考. このコールは、k3922 CAMAC クレート・コントローラのレジスタの Inhibit をクリアする。 7. CAMAC(nafenalam, &dat, &q, &x) /* Enable LAM */ CAMAC(naf, dat, q, x) int naf, *dat, *q, *x; { register int status; u_short qx; message.command = (u_short)CC_CMD_DOSINGLE; message.mode = (u_short)CC_BIT24; message.naf = (u_short)naf; message.ptr_data = (u_short *)dat; message.ptr_qx = (u_short *)&qx; vec[0].iov_base = (caddr_t)&message; vec[0].iov_len = sizeof(struct cc_message); if ((status = writev(cc_path, vec, 1)) != 0) return status; *x = ((qx & CC_NOX) == 0) ? 1 : 0; *q = ((qx & CC_NOQ) == 0) ? 1 : 0; check_file_pointer(2); return (qx >> 12); } 8. CAM_EnableLAM(mask) camlib.h:#define CAM_EnableLAM CELAM CELAM(mask) int mask; { return ioctl(cc_path, CCIOC_ENABLE_LAM, &mask); } 9. CAM_WaitLAM(timeo) camlib.h:#define CAM_WaitLAM CWLAM CWLAM(timeout) int timeout; { errno = 0; ioctl(cc_path, CCIOC_WAIT_LAM, &timeout); return errno; } ioctl(cc_path, CCIOC_WAIT_LAM, &timeout) を実行すると、 cc ドライバ・プログラムの "cc_ioctl"ルーチンがコールされ、 以下の部分が実行される。 : case CCIOC_WAIT_LAM : cc->interrupt = 0; k->lamc = CC_INT_AUTO_CLEAR | CC_INT_ENABLE | intrpri; /* lock out clock */ s = spl5(); if (cc->interrupt & CC_INT_LAM) { cc->interrupt &= ~CC_INT_LAM; return 0; } mutex_enter(&cc->mutex); /* start MUTEX */ cc->timeout_id = timeout(cc_timeout, NULL, *(int *)data * hz); /* by E.Inoue */ printf("cc_ioctl: CCIOC_WAIT_LAM: debug: printf cc->k->lamv = 0x%x\n", cc->k ->lamv); uprintf("cc_ioctl: CCIOC_WAIT_LAM: debug: uprintf cc->k->lamv = 0x%x\n", cc- >k->lamv); /* */ /* wait interrupt */ /* cv_timedwait(&cc->cv, &cc->mutex, timeout); if (cc->interrupt == 0) cc->interrupt |= CC_INT_TIMEOUT; */ if (cv_wait_sig(&cc->cv, &cc->mutex) == 0) { untimeout(cc->timeout_id); mutex_exit(&cc->mutex); /* end MUTEX */ return EINTR; } mutex_exit(&cc->mutex); /* end MUTEX */ splx(s); if( cc->interrupt & CC_INT_LAM ) { cc->interrupt &= ~CC_INT_LAM; } else if( cc->interrupt & CC_INT_TIMEOUT ) { cc->interrupt &= ~CC_INT_TIMEOUT; return CC_STA_SINGLE_TIMEOUT; /* set value to "errno" */ } break; o このルーチンで気になる点 このルーチンでは、spln(), splx() コールが使われている。 "Writing Device Drivers - May 1996, Appendix A, Converting a 4.x Device Driver to SunOS 5.5, SunOS4.1.x to SunOS5.5 Differences, Page 377" を見るとspln(), splx() カーネル・サポート・ルーチンは SunOS4.1.x用であってSunOS5.5ではmutex_enter(),mutex_exit()を使うと 記述されている。 このルーチンではspln(), splx() コールと合わせて mutex_enter(),mutex_exit()使ってある。 spln(), splx() コールは削除し てもよいかもしれない。 10. CAMAC(nafclrlam, &dat, &q, &x) /* clear LAM */ 項目7. を参照 11. CAM_DisableLAM() camlib.h:#define CAM_DisableLAM CDLAM CDLAM() { int dummy; return ioctl(cc_path, CCIOC_DISABLE_LAM, &dummy); } 12. CAM_Close() camlib.h:#define CAM_Close CAMCLS CAMCLS() { return close(cc_path); } この内、項目9 の CAM_WaitLAM(timeo) をコールしている時に、LAM による割り 込みがかかることを期待している。 o 現在、cc ドライバ・プログラムは項目1 でベクタ・アドレスの設定をやって いる。 ところが、項目9 の CAM_WaitLAM(timeo) をコールするまでの間に ベクタ・アドレスの値がゼロにされてしまっている。 どこで、変えられたの かチェック。 (4). 上記(3)の項目1から項目9に関係する部分にデバッグ用の uprintf 文を入れて インタラプト・ベクタ・レジスタの内容をチェックしてどの部分でリセットされ るのかを調べる。 1. まず項目9に関係する部分について : case CCIOC_WAIT_LAM : /* by E.Inoue */ uprintf("cc_ioctl: CCIOC_WAIT_LAM enter: debug: uprintf cc->k->lamv = 0x%x\n ", cc- >k->lamv); /* */ cc->interrupt = 0; : これで、コンパイル、ロード、cam3実行をやってみる。 onl5v4[48]% cam3 : cc_ioctl: CCIOC_WAIT_LAM enter: debug: uprintf cc->k->lamv = 0xff00 cc_ioctl: CCIOC_WAIT_LAM: debug: uprintf cc->k->lamv = 0xff00 Timeout !! count=1 : cc_ioctl のCCIOC_WAIT_LAMに処理が移った時にはすでに、インタラプト・ ベクタ・レジスタの内容はリセットされてしまっている。 2. 項目6の、k3922 CAMAC クレート・コントローラのレジスタのInhibit を クリアした後でインタラプト・ベクタ・レジスタの内容はどうなっているか 調べる。 そのために、cc ドライバ・プログラムのcc_write ルーチンに デバッグのための uprintf 文を入れてみる。 static int cc_write(dev_t dev, struct uio *uio, cred_t *cred_p) { : /************************* * CAMAC single action * *************************/ case CC_CMD_DOSINGLE: switch (naf & 0x0018) { : case 0x0010: /* CAMAC write */ if ((mode & CC_BIT16) == 0) copyin((caddr_t)message.ptr_data, (caddr_t)data_area, sizeof(u_short) * 2); else copyin((caddr_t)message.ptr_data, (caddr_t)data_area, sizeof(u_short)); /* by E.Inoue */ uprintf("cc_write: debug: camac write: cc= 0x%x, mode= 0x%x, naf=0x%x", cc, mode, naf); uprintf("cc_write: debug: camac write: cc->k->lamv = 0x%x\n", cc->k->lamv); /* */ camac_s(cc, mode, naf, data_area); break; default: /* NDT */ camac_s(cc, mode, naf, data_area); break; : camlib.c にも CGENC、CGENZ、CREMI をコールした時にメッセージを出すように printf 文を入れる。 CGENC() { : /* by E.Inoue */ printf("camlib: debug: CGENC() normal return\n"); /* */ return CAMAC(NAF(30, 0, 17), &i, &q, &x); } : CGENZ() { : /* by E.Inoue */ printf("camlib: debug: CGENZ() normal return\n"); /* */ return CAMAC(NAF(30, 0, 17), &i, &q, &x); } : CREMI() { : /* by E.Inoue */ printf("camlib: debug: CREMI() normal return\n"); /* */ return CAMAC(NAF(30, 0, 17), &i, &q, &x); } これで、コンパイル、ロード、cam3実行をやってみる。 onl5v4[80]% cam3 camlib: debug: enter CAMOPN() cc_open: debug: enter cc_open cc_open: debug: uprintf cc->k->lamv = 0xffff cc_getinfo: debug: enter cc_getinfo cc_getinfo: debug: enter cc_getinfo camlib: debug: CAMOPN() normal return camlib: debug: CGENC() normal return cc_write: debug: camac write: cc= 0xf5d59598, mode= 0x0, naf=0x3c11 cc_write: debug: camac write: cc->k->lamv = 0xff00 camlib: debug: CGENZ() normal return cc_write: debug: camac write: cc= 0xf5d59598, mode= 0x0, naf=0x3c11 cc_write: debug: camac write: cc->k->lamv = 0xff00 camlib: debug: CREMI() normal return cc_write: debug: camac write: cc= 0xf5d59598, mode= 0x0, naf=0x3c11 cc_write: debug: camac write: cc->k->lamv = 0xff00 *** Now waiting LAM ... N=3 Loop=10 Timeout=0 sec cc_ioctl: CCIOC_WAIT_LAM enter: debug: uprintf cc->k->lamv = 0xff00 cc_ioctl: CCIOC_WAIT_LAM: debug: uprintf cc->k->lamv = 0xff00 Timeout !! count=1 : onl5v4[81]% 実行結果は、CGENC をやった時点ですでにインタラプト・ベクタ・レジスタの 内容はリセットされてしまっていることを示している。 o もう一段階前の項目3の CSETCR(0) の実行終了時にどうなっているか 調べる。 onl5v4[81]% vi cc.c : case CCIOC_SET_CRATE: if (*(int *)data >= 0 && *(int *)data < MAX_CRATE) cc->cur_crate = *(int *)data; /* by E.Inoue */ uprintf("cc_ioctl: CCIOC_SET_CRATE retrun: debug: cc->k->lamv = 0x%x\n", cc- >k->lamv); /* */ break; : onl5v4[82]% onl5v4[83]% vi camlib.c : CSETCR(crate) int crate; { /* by E.Inoue */ printf("camlib: debug: CSETCR() normal return\n"); /* */ return ioctl(cc_path, CCIOC_SET_CRATE, &crate); } : onl5v4[87]% これで、コンパイル、ロード、cam3実行をやってみる。 onl5v4[90]% cam3 camlib: debug: enter CAMOPN() cc_open: debug: enter cc_open cc_open: debug: uprintf cc->k->lamv = 0xffff cc_getinfo: debug: enter cc_getinfo cc_getinfo: debug: enter cc_getinfo camlib: debug: CAMOPN() normal return camlib: debug: CSETCR() normal return cc_ioctl: CCIOC_SET_CRATE retrun: debug: cc->k->lamv = 0xffff camlib: debug: CGENC() normal return cc_write: debug: camac write: cc= 0xf5d59598, mode= 0x0, naf=0x3c11 cc_write: debug: camac write: cc->k->lamv = 0xff00 camlib: debug: CGENZ() normal return cc_write: debug: camac write: cc= 0xf5d59598, mode= 0x0, naf=0x3c11 cc_write: debug: camac write: cc->k->lamv = 0xff00 camlib: debug: CREMI() normal return cc_write: debug: camac write: cc= 0xf5d59598, mode= 0x0, naf=0x3c11 cc_write: debug: camac write: cc->k->lamv = 0xff00 *** Now waiting LAM ... N=3 Loop=10 Timeout=0 sec cc_ioctl: CCIOC_WAIT_LAM enter: debug: uprintf cc->k->lamv = 0xff00 cc_ioctl: CCIOC_WAIT_LAM: debug: uprintf cc->k->lamv = 0xff00 Timeout !! count=1 : onl5v4[91]% 項目3の CSETCR(0) の実行終了時にはインタラプト・ベクタ・レジスタの内容は 正しく "0xff" になっている。 そして、次の項目4の CGENC を実行した時に インタラプト・ベクタ・レジスタの内容はリセットされていることを確認した。 (5). camac_s() ルーチンのチェック。 static int camac_s(struct cc_device *cc, u_short mode, u_short naf, u_short *dat) { register struct K_REG *k = cc->k; register int counter; cc->status = 0; k->csr = CC_RST; /* K2917 Reset */ k->cma = CC_CMA_INIT; /* Initialize memory pointer */ k->cmr = mode | (cc->cur_crate << 8); /* Write command list */ k->cmr = naf; k->cmr = CC_HALT; k->cma = CC_CMA_INIT; /* Reset memory pointer */ : camac_s() ルーチンでは、"k->csr = CC_RST;" をやっている。 これを実行する と2917はパワーアップ時の状態にされてしまう。 つまり、インタラプト・ベク タ・レジスタの内容もリセットされてしまう。 チェック。 onl5v4[47]% vi cc.c : static int camac_s(struct cc_device *cc, u_short mode, u_short naf, u_short *dat) { register struct K_REG *k = cc->k; register int counter; cc->status = 0; /* by E.Inoue */ uprintf("camac_s: debug: before RST cc->k->lamv = 0x%x\n", cc->k->lamv); /* */ k->csr = CC_RST; /* K2917 Reset */ /* by E.Inoue */ uprintf("camac_s: debug: after RST cc->k->lamv = 0x%x\n", cc->k->lamv); /* */ k->cma = CC_CMA_INIT; /* Initialize memory pointer */ : これで、コンパイル、ロード、cam3実行をやってみる。 onl5v4[37]% cam3 camlib: debug: enter CAMOPN() cc_open: debug: enter cc_open cc_open: debug: uprintf cc->k->lamv = 0xffff cc_getinfo: debug: enter cc_getinfo cc_getinfo: debug: enter cc_getinfo camlib: debug: CAMOPN() normal return camlib: debug: CSETCR() normal return cc_ioctl: CCIOC_SET_CRATE retrun: debug: cc->k->lamv = 0xffff camac_s: debug: before RST cc->k->lamv = 0xffff camac_s: debug: after RST cc->k->lamv = 0xff00 camlib: debug: CGENC() normal return cc_write: debug: camac write: cc= 0xf5d59598, mode= 0x0, naf=0x3c11 cc_write: debug: camac write: cc->k->lamv = 0xff00 : "k->csr = CC_RST" を実行した直後にインタラプト・ベクタ・レジスタが リセットされている様子を確認できた。 方針 1. 以下の、1〜4項にかかわる操作では、camac_s ルーチンがコール実行され る。 1. CGENC() 2. CGENZ() 3. CREMI() 4. およびcamacノーマル・ステーションに向けて発行されるシングル・ アクション read/write cam3 を例に上げて調べる。 cam3 が cc ドライバをコールしている部分、 およびその部分がcamac_s ルーチンをコールしているかどうかについて、 以下に示す。 o CAM_Open("/k3922",1) camac_sはコールしない o CSETBR(1) camac_sはコールしない o CSETCR(0) camac_sはコールしない o CGENC() camac_sをコールする o CGENZ() camac_sをコールする o CREMI() camac_sをコールする o CAMAC(nafenalam, &dat, &q, &x) camac_sをコールする o CAM_EnableLAM(mask) camac_sをコールする o CAM_WaitLAM(timeo) camac_sはコールしない o CAMAC(nafclrlam, &dat, &q, &x) camac_sをコールする o CAM_DisableLAM() camac_sをコールする o CAM_Close() camac_sはコールしない 現在の ccドライバでは cc_open() ルーチンの中でインタラプト・ベクタ・ レジスタの設定をやっている。 cc_open() ルーチンはユーザ・プログラム で CAM_Open("/k3922",1) が実行された時に、コールされる。 cam3 を例にとると、CAM_Open("/k3922",1) でインタラプト・ベクタ・ レジスタが設定された後、CAM_WaitLAM(timeo) で割り込み待ち状態に入る までに、CGENC()、CGENZ()、CREMI()、CAMAC(nafenalam, &dat, &q, &x)、 CAM_EnableLAM(mask) の各コールで5回もリセットされてしまう。 ccドライバ中の、CAM_EnableLAM(mask)でコールされる部分に、インタラプ ト・ベクタ・レジスタ設定のコードを付加する。 (6). cc.c の cc_ioctl()ルーチンの "case CCIOC_ENABLE_LAM" の部分にインタラプ ト・ベクタ・レジスタ設定のコードを付加する。 onl5v4[71]% vi cc.c : static int cc_ioctl(dev_t dev, int cmd, int arg, int flag, cred_t *cred_p, int *rval_p) { : case CCIOC_ENABLE_LAM : camac_s(cc, CC_BIT24, NAF(30, 13, 17), (u_short *)data); camac_s(cc, CC_BIT16, NAF(30, 0, 1), &sdat); sdat |= 0x100; camac_s(cc, CC_BIT16, NAF(30, 0, 17), &sdat); /* by E.Inoue */ /* set interrupt registers of K2917 */ cc->k->lamc = (u_short)(CC_INT_AUTO_CLEAR | intrpri); cc->k->donc = (u_short)(CC_INT_AUTO_CLEAR | intrpri); cc->k->empc = (u_short)(CC_INT_AUTO_CLEAR | intrpri); cc->k->aboc = (u_short)(CC_INT_AUTO_CLEAR | intrpri); cc->k->lamv = (u_short)intrvec; cc->k->donv = (u_short)intrvec; cc->k->empv = (u_short)intrvec; cc->k->abov = (u_short)intrvec; /* */ break; onl5v4[72]% これで、コンパイル、ロード、cam3実行をやってみる。 onl5v4[37]% cam3 camlib: debug: enter CAMOPN() cc_open: debug: enter cc_open cc_open: debug: uprintf cc->k->lamv = 0xffff cc_getinfo: debug: enter cc_getinfo cc_getinfo: debug: enter cc_getinfo camlib: debug: CAMOPN() normal return camlib: debug: CSETCR() normal return cc_ioctl: CCIOC_SET_CRATE retrun: debug: cc->k->lamv = 0xffff camac_s: debug: before RST cc->k->lamv = 0xffff camac_s: debug: after RST cc->k->lamv = 0xff00 camlib: debug: CGENC() normal return cc_write: debug: camac write: cc= 0xf5d59598, mode= 0x0, naf=0x3c11 cc_write: debug: camac write: cc->k->lamv = 0xff00 camac_s: debug: before RST cc->k->lamv = 0xff00 camac_s: debug: after RST cc->k->lamv = 0xff00 camac_s: debug: before RST cc->k->lamv = 0xff00 camac_s: debug: after RST cc->k->lamv = 0xff00 camlib: debug: CGENZ() normal return cc_write: debug: camac write: cc= 0xf5d59598, mode= 0x0, naf=0x3c11 cc_write: debug: camac write: cc->k->lamv = 0xff00 camac_s: debug: before RST cc->k->lamv = 0xff00 camac_s: debug: after RST cc->k->lamv = 0xff00 camac_s: debug: before RST cc->k->lamv = 0xff00 camac_s: debug: after RST cc->k->lamv = 0xff00 camlib: debug: CREMI() normal return cc_write: debug: camac write: cc= 0xf5d59598, mode= 0x0, naf=0x3c11 cc_write: debug: camac write: cc->k->lamv = 0xff00 camac_s: debug: before RST cc->k->lamv = 0xff00 camac_s: debug: after RST cc->k->lamv = 0xff00 camac_s: debug: before RST cc->k->lamv = 0xff00 camac_s: debug: after RST cc->k->lamv = 0xff00 camac_s: debug: before RST cc->k->lamv = 0xff00 camac_s: debug: after RST cc->k->lamv = 0xff00 camac_s: debug: before RST cc->k->lamv = 0xff00 camac_s: debug: after RST cc->k->lamv = 0xff00 camac_s: debug: before RST cc->k->lamv = 0xff00 camac_s: debug: after RST cc->k->lamv = 0xff00 *** Now waiting LAM ... N=3 Loop=10 Timeout=0 sec cc_ioctl: CCIOC_WAIT_LAM enter: debug: uprintf cc->k->lamv = 0xffff cc_ioctl: CCIOC_WAIT_LAM: debug: uprintf cc->k->lamv = 0xffff Timeout !! count=1 call CAMAC(nafclrlam, &dat, &q, &x) camac_s: debug: before RST cc->k->lamv = 0xffff camac_s: debug: after RST cc->k->lamv = 0xff00 cc_ioctl: CCIOC_WAIT_LAM enter: debug: uprintf cc->k->lamv = 0xff00 cc_ioctl: CCIOC_WAIT_LAM: debug: uprintf cc->k->lamv = 0xff00 Timeout !! count=2 call CAMAC(nafclrlam, &dat, &q, &x) camac_s: debug: before RST cc->k->lamv = 0xff00 camac_s: debug: after RST cc->k->lamv = 0xff00 cc_ioctl: CCIOC_WAIT_LAM enter: debug: uprintf cc->k->lamv = 0xff00 cc_ioctl: CCIOC_WAIT_LAM: debug: uprintf cc->k->lamv = 0xff00 Timeout !! count=3 : NG. 1回目の割り込み待ち時には、たしかにインタラプト・ベクタ・レジスタは 正しく設定される。 しかし、ここで LAM の発生あるいはタイム・アウトが 起こると、ユーザ・プログラムは LAM のクリアをする。 この操作は ccドライ バの camac_sルーチンがコールされることになるので、再びインタラプト・ ベクタ・レジスタはリセットされてしまう。 方針 2. camac_sルーチン中の "2917 リセット操作" をはずすことを考えた方が よさそうだ。 o camac_sルーチン中の "2917 リセット操作" をはずした場合、問題はおこら ないか。 チェック。 (7). camac_sルーチン中の "2917 リセット操作" をはずすことにした場合、この操作 をどこでやるのが適切か。 "2917 リセット操作" をやると、2917はパワー アップ時の状態にされてしまう。 このような操作はユーザ・プログラムを実行 開始する時に一度だけやればよいのではなかろうか。 つまり、cc_open()中やる のがいいだろう。 cam1、cam3 でチェック。