targ始めました

とりあえず手持ちの部材で[targ](https://qiita.com/yamori813/items/974287b5ac94b2ec942c)ができないか試してみました。忘れてしまうので、大まかな流れを書いておきます。

目標はPC-9801のハードディスクとして使えるようにすることです。

![targ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/4b2e6876-a646-77b5-5646-61dbf566b836.png)

PC-9801FA2にICMのPC-9801-55互換のIF-2560が入っています。ちなみにこのボードではAM33C93Aが使われています。55や互換が使えるのはMS-DOS 3.3(無印)以降のようです。

SCSIのデバイスはほとんど捨ててしまいましたが、インターフェースカードはいくつか残っています。使わなくなったカードはPCMCIAが2枚とPCIが1枚あります。PCMCIAはNCRとAdvansysでPCIカードはAdvansysです。

|カード|バス|チップ|FreeBSD|ドライバ|
|:--|:--|:--|:--|:--|
|MSC-110|PCMCIA|NCR|OK|ncv|
|REX-R231|PCMCIA|Advansys|NG|-|
|PUI3050-AC|PCI|initio(Advansys)|OK|adv|

Advansysはデーターシートなどが存在しない事と、マイクロコードを使っていて複雑になっているので単純なNCRを使うことにしました。PCCARDにはBIOSのサポートがないので、複雑にならないメリットもあります。

カードは20年くらい前にPAOでサポートされていたので買ったMedia Intelligent(Macnica)のMSC-110というものです。PentiumIIIのNEC ValueStarに入れて使います。

MSC-110にはケーブルが二本付いてて、一本がフルで、一本がハーフピッチのエッジのタイプで直接PC-9801につなぐ事ができます。

おそらくこのケーブルはIO DATAのPCSC-Fと同じ並びのピン配置と思われます。サンワサプライのKB-PSH1Nという互換ケーブルもあるようです。

|ピン|信号|ピン|信号|
|:--|:--|:--|:--|
|1|TERMPWR|14|-DBP|
|2|-ACK|15|-DB7|
|3|GND|16|-DB6|
|4|-REQ|17|GND|
|5|GND|18|-DB5|
|6|-I/O|19|-DB4|
|7|-C/D|20|-DB3|
|8|-SEL|21|GND|
|9|-MSG|22|-DB2|
|10|-RST|23|-DB1|
|11|-BSY|24|-DB0|
|12|-ATN|25|-DB0|
|13|GND|||

同じ形状の25PinでもREXはまったく違っていました。機器側はハーフのピンのタイプでした。こちらの並びはMacの25Pinと同じようです。こちらもサンワサプライのKB-PSH1Rという互換ケーブルもあるようです。

|ピン|信号|ピン|信号|
|:--|:--|:--|:--|
|1|REQ|14|GND|
|2|MSG|15|C/D|
|3|I/O|16|GND|
|4|RST|17|ATN|
|5|ACK|18|GND|
|6|BSY|19|SEL|
|7|GND|20|DBP|
|8|DB0|21|DB1|
|9|GND|22|DB2|
|10|DB3|23|DB4|
|11|DB5|24|GND|
|12|DB6|25|TERMPWR|
|13|DB7|||

いろいろ探したところ1と25が逆になっている情報もありました。

閑話休題で、このカードにはNCR53C500が使われていてFreeBSDではPAO由来のncvでサポートされていましが、13RでPCMCIAのサポートと一緒に消されてしまいました。

いろいろ調べたところ[NCR53C500はNCR53C90系](https://qiita.com/yamori813/items/481eda5242404d323968)でこのドライバーはespとして別に存在しています。

```
% apropos SCSI -a NCR
esp(4) - Emulex ESP, NCR 53C9x and QLogic FAS families based SCSI controllers
ncr(4) - NCR 53C8xx SCSI driver
ncv(4) - NCR 53C500 based SCSI host adapter driver
sym(4) - NCR/Symbios/LSI Logic 53C8XX PCI SCSI host adapter driver
```

関係ないけど、おじさんの若い頃はwhatisだったんだけれど、aproposに入れ替わったみたいね。whatisもリンクされてて使えるけど、リザルトが違う。

ncvはcamの共通処理を別にした凝った作りになっていて、いじりにくいので、とりあえずespで使えるようにします。

FreeBSDのncr53c500_pccard.cとNetBSDのesp_pcmcia.cをがっちゃんこしてesp_pccard.cを作ります。

NCR53C500のデーターシートは手に入ってませんが、9xのデーターシートはいくつかあるので、それを参考にしています。

いろいろやっていたらとりあえず動くようになりました。

ドライバが組み込まれて、PC-9801につないでPC-9801をリセットするとBus Reset割り込みが上がればちゃんと動作してると判断できます。PC-9801の電源が入ってない状態でSCSIケーブルつないでFreeBSDを上げるとバスのターミネートがうまくいかずBus Resetが延々と繰り返されるので注意が必要です。

SCSIは以下の流れで処理を行います。

SELECTION -> COMMAND -> DATA IN/OUT -> STATUS -> MESSAGE

INQUERYの場合イニシエーターは

SELECTしてコマンドを出す
DATA INする
STATUSを受け取る
MESSAGEを受け取る

でターゲットは

SELECTを待つ
コマンドを受け取る
DATA OUTする
STATUSを送る
MESSAGEを送る

です。

ターゲットが送るデーターはコマンドとDATAです。イニシエーターはDATAとSTATUS,MESSAGEを送ります。DATAの部分は反対になるので、既存コードの部分的な再利用が可能かもしれません。

targのサポートですがとりあえずGENERICにdevice targを入れてカーネルをビルドします。カーネルはcorei5のBastilleBSD下でビルドしてPCCARDが使えるPentiumIIIなマシンにコピーして確認します。

NCR53C500はイニシエーターとターゲットで同じSCSI IDを使います。通常ホストのSCSI IDは7ですが、PC-9801も7を使うので、0に設定しておきます。本来はXPT_EN_LUNで設定するのですが正しいです。

まずサポートのフラグを入れます。

```
cpi->target_sprt = PIT_PROCESSOR | PIT_DISCONNECT | PIT_TERM_IO;
```

accept_tioのリストを初期化してncr53c9x_action()でXPT_ACCEPT_TARGET_IOが呼ばれたときにリストに積む処理を入れます。xpt_done()はしません。

immed_notifiesは使ってませんが同じような処理をします。

NCR53C500でターゲットモードでセレクトが受けられるように下記を追加します。

```
 NCRCMD(sc, NCRCMD_ENSEL);
```

これでイニシエーターからセレクトされると割り込みが上がるので割り込みルーチンをいじります。

NCR53C500のセレクト割り込みは0x01なので、この時の処理を追加します。もともとの割り込み処理には0x01の場合はありません。

割り込みが上がったときにはFIFOにCDBに入っているので、それを読み出します。読み出したデータをaccept_tioのリストから取り出したatioに突っ込んで、xpt_done()に渡します。FIFOの先頭に2バイトのCDB以外のデーターが入ってますが、内容不明です。

これでユーザープロセス(scsi_target)にCDBが渡って返答がXPT_CONT_TARGET_IO(ctio)で返ってきます。

INQUIRYの場合これのdata_ptrをFIFOに入れてNCRCMD(sc, NCRCMD_SNDDATA);するとイニシエーターに渡ります。

イニシエーターはPC-9801で55互換ボードを使っているのですが、このボードは起動後にSCSIのバスリセットを二回してINQUIRY(0x12),TEST UNIT READY(0x00),INQUIRY(0x12)を送ってきます。最初のINQUIRYの長さが0x0bと半端なのですが、これはベンダーのNECまでを拾うためかもしれません。

とりあえずPC-9801でドライブがいる事は認識できるようになりました。

参考実装のisp,ahcは複数のイニシエーターやLUNに対応しているので、複雑になっていますが、単一のイニシエーターやLUNしかサポートしなければ、かなり簡単に実装できるような気がします。

当初なぜかINQUIRYのユーザランドからのデーターが空になる状態だったのですが、scsi_cmd.cのdirが逆でcam_periph_mapmem()でcopyinされてませんでした。いつから動かなくなってたんだろう？

バグジラ入れました。

https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=257976

全部逆になりおかしいので、いったん落として、質問をfreebsd-scsiのMLに投げました。（バグでした）

![IMG_20210821_081212.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/ecef657a-acb1-e7dc-4252-cab2f4370fd3.jpeg)

```
% sudo camcontrol devlist -v
scbus0 on ata0 bus 0:
<HDS722580VLAT20 V32OA63A>         at scbus0 target 0 lun 0 (pass0,ada0)
<TOSHIBA DVD-ROM SD-R1102 1N20>    at scbus0 target 1 lun 0 (cd0,pass1)
<>                                 at scbus0 target -1 lun ffffffff ()
scbus1 on ata1 bus 0:
<>                                 at scbus1 target -1 lun ffffffff ()
scbus2 on esp0 bus 0:
<>                                 at scbus2 target 0 lun 0 (targ0)
<>                                 at scbus2 target -1 lun ffffffff ()
scbus-1 on xpt0 bus 0:
<>                                 at scbus-1 target -1 lun ffffffff (xpt0)
```

![IMG_20210909_104239.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/7c9f3fbc-5706-909d-6a83-5a360ee37c20.jpeg)

# その後

とりあえずPC-9801FAでMS-DOS 3.3D/5.0AのFORMATコマンドで初期化して領域確保して、起動できるようになりましが、どきどきハングしたり不安定です。

scsi_target.cに不足したいた部分を追加したり、データーフェーズの調整などを行いました。

不足部分やPC-9801固有の処理はRaSCSIのコードを参考にしました。RaSCSIはBSDライセンスなので安心して参照できます。

PC-9801はMODE_SENSEでドライブの構成を取得しているのでscsi_targetでサポートが必要です。またscsi_targetが使用するボリュームファイルのサイズはMODE_SENSEで返した、ヘッド(8)・トラック(25)・シリンダーの積にする必要があります。実際にはボリュームファイルのサイズをセクターサイズxヘッドxトラックで割ってシリンダー数を出すようにしました。

NCR53C500はDMAは使えませんが、128x2の拡張されたFIFO(PIO)があるので、ncvのコードを参考にそれを使うようにしました。

割り込みは使用せずビジーループで実装してあります。扱うデータも小さかったり、ターゲットはデーターのやり取りが主な仕事なので、それでも良いような気もします。

データーフェーズのコマンドDONE割り込みで、Terminate Stepsコマンドを発行して、スタータスフェーズとメッセージフェーズを行っています。

今のところ問題は以下のとおりです。

* scsi_targetを立ち上げた直後にPC-9801を起動するとこける。二度目はOK。
* FIFOの読み書きに失敗する事がある。
* PC-9801側からのREADの処理でCOMMAND DONE割り込みが上がらない事がある。
* COMMAND DONEのタイミングで不明(0)な割り込みが上がり処理がとまる。

シリアルコンソールを設定して確認すると安定します。これは処理が遅くなる事が影響している可能性が高いです。。。

![IMG_20210828_202657.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/4f5a9df6-0fb8-2baa-be90-48af85f1291b.jpeg)

Windows 3.1 Update-2をインストールしてみました。

FIFOのエラーについて考えてみました。NCR53C500は16バイトのFIFOと128バイトのFIFO(PIO)があります。

イニシエーターへのデータの送信の場合は、送信のタイミングでデーターがFIFOに入っていない状態（アンダーラン）しないようにしなければなりません。128バイトのFIFOが空でも16バイトのFIFOにデータがあれば大丈夫ですが、両方ともなくなってしまうとアウトです。

イニシエーターからのデータの受信の場合は、受信のタイミングでFIFOがフルにならないようにしなければなりません。これも送信の場合と同じで128バイトのFIFOがフルでも16バイトのFIFOに空きがあれば大丈夫ですが、両方とも埋まった状態で、受信データが入ってきた場合はアウトです。

データの送受信は一定間隔で行われていて、FIFOが空だったりフルだったりしても、遅らせてくれません。

注意が必要なのはイニシエーターへのデータの送信の場合、コマンドを発行する前に、FIFOにデータをつめておく必要があります。

1KByte/secだと1msで1Byteで1MByte/secだと1usで1Byteで10MByte/secだと0.1usで1Byteになります。128バイトのFIFOは12.8usで処理されます。ただ128バイトのFIFOが空になり16バイトしか残っていない場合は1.6usで新たなデータを入れないとエラーになります。

PC-9801FA2のSCSIはIFボードから中のSCSI籠に入って、正面のファイルスロットに出て、それがIFボードに戻ってきて、外部コネクタに出てるようです。~~不安定なのはターミネーションに由来する問題な気がしてきましたが、今手元に部材がないので確かめられません。部材が手に入ったら確認してみたいと思います。~~

とりあえず、上げておきました。

https://github.com/yamori813/esp-targ

いろいろやってるうちに、FIFOのR/Wの問題と0割り込みの問題だけになった。

FIFOアクセス中は割り込みを禁止したところ安定したようです。ncvのコードではFIFOアクセスは割り込みルーチン内で、実質的に割り込み禁止状態です。これでほぼ問題なく使えそうです。

Windows 3.1を起動したときのvmstatはこんな感じです。

```
procs  memory       page                    disks     faults         cpu
r b w  avm   fre   flt  re  pi  po    fr   sr ad0 cd0   in    sy    cs us sy id
0 0 0 147M  269M     0   0   0   0     0    2   0   0 2007    98   134  0  0 100
0 0 0 147M  269M     0   0   0   0     0    3   0   0 2004    67   124  1  0 99
0 0 0 147M  269M     0   0   0   0     0    2   0   0 1946   234   213  0  5 95
1 0 0 147M  269M     1   0   0   0     0    3   0   0 1872  1321   557  1 13 87
0 0 0 147M  269M     0   0   0   0     0    2  27   0 1746  5528  1836  5 36 59
0 0 0 147M  269M     0   0   0   0     8    3   1   0 2070  2894   904  4  4 92
0 0 0 147M  269M     0   0   0   0     0    2   0   0 1883  1862   725  2 13 85
1 0 0 147M  269M     0   0   0   0     0    3   4   0 1843  3552  1214  4 25 71
0 0 0 147M  269M     0   0   0   0     0    2   2   0 1890  2252   822  1 14 85
0 0 0 147M  269M     0   0   0   0     0    3   0   0 1891  1616   608  2 11 88
0 0 0 147M  269M     1   0   0   0     0    2   0   0 1987   319   256  0  2 98
0 0 0 147M  269M     0   0   0   0     0    3   0   0 1941  2839   991  0 17 83
0 0 0 147M  269M     0   0   0   0     0    2   0   0 1861  2996  1040  2 23 76
0 0 0 147M  269M     0   0   0   0     0    3   0   0 1808  3217  1133  3 25 72
1 0 0 147M  269M     0   0   0   0     0    2   0   0 1919  3003  1057  5 14 80
1 0 0 147M  269M     0   0   0   0     0    3   0   0 1916  3299  1128  0 18 82
0 0 0 147M  269M     0   0   0   0     0    2   0   0 1949  1370   543  4  6 90
1 0 0 147M  269M     0   0   0   0     0    3   0   0 1982  1081   460  1  5 95
0 0 0 147M  269M     0   0   0   0     0    2   0   0 2001   699   367  2  1 96
0 0 0 147M  269M     0   0   0   0     0    3   0   0 1917  2083   766  1 14 86
0 0 0 147M  269M     0   0   0   0     0    2   0   0 2064  2103   696  2  5 93
0 0 0 147M  269M     0   0   0   0     0    3   0   0 1970   571   317  1  4 95
0 0 0 147M  269M     0   0   0   0     0    2   0   0 1986   445   299  0  2 98
0 0 0 147M  269M     0   0   0   0     0    3   0   0 2006    98   164  0  1 99
0 0 0 147M  269M     0   0   0   0     0    2   0   0 2005    67   153  0  0 100
```

|メーカー|製品名|
|:--|:--|
|NEC|PC-9801N-J03R|
|I-O DATA|[PCSC-II](https://yuuuuuutu.seesaa.net/article/502878428.html)|
|Logitec|LPM-SCSI2/A,LPM-SCSI2/D,LPM-SCSI2/E|
|緑電子|CN-SC43|
|MACNICA|MSC-110,MIRACLE SCSI II|
|Caravell|PSC-SCSI/mkII|

あたりが同等品なのかもしれませんが、未確認です。

簡単に実装できるのでビジーループしています。

![BS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/ea78023b-750c-e6f4-fb67-059ebfe4a1c0.png)

イニシエーターからの読み込み（送信）の場合赤い部分でFIFOに詰めて、FIFOが空になるまでの黄色い時間のCPU資源が無駄になってしまいます。

割り込みで処理で処理する場合

![INT.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/67505656-776b-4e08-068d-a4e69442f7f6.png)

無駄がなくなりますが、実装が複雑になるし、タイミング的に上手くいかない可能性もあります。

またビジーループでは空やフルで処理をしていますが、割り込みで処理する場合は、実際の処理までに他の割り込みにブロックされるなどの遅延が発生する可能性があるので、1/3や2/3での処理が必要になり厄介です。

scsi_targetで使ってるファイルをコピーすることで簡単にディスクのスナップショットが取れて便利です。

FreeBSD 12.2Rで開発を始めたのですが、updateした12.3Rp3でもkernelに突っ込んで試してみましたが、ちゃんと動きます。今となってみるとどうやって動いているのか、自分でも不思議です。