-<□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□>- SCSI-TARGET IOCS SCSITAI.SYS 技術資料など... -<□■□ SCSITAI.SYS のデフォルト... □■□>- そのまま常駐した状態で、デフォルトの SCSI コマンド処理ルーチンが有効にな ります。最低限の基本的なコマンドに対応しています。READ,WRITE では、グラフ ィック/テキスト V-RAM を読み書きします(SCTVCPY.x 参照。2台の X68 間で V-RAM のやり取りをします)。INQUIRY では、デバイスタイプ = PROCESSOR と返 します。 更に、メモリを読み書きする MEMPEEK , MEMPOKE 、IOCSCALL を実行する SCSI コマンドもデフォルトで用意しています。 なお、LUN 0~7 まで、すべて同じ対応をしますが、LUN 7 以外は INQUIRY を含 む SCSI コマンドを全取り替えても構いません(SCTRDISK.x 参照。これは LUN 0 の INQUIRY で「ダイレクトデバイス」を返すようにして、他を全部仮想HDと動 作する SCSI コマンドに替えてます)。LUN 7 はデフォルトの SCSI コマンドを殺 ・・・・・・・・・・・・・・・・・・ さないようにしてください。逆に言えば、デフォルトの SCSI コマンドをコールす ・ ・・・・・・・・・・・・・・ る時は LUN 7 を使用してください。 -<□■□ 拡張 SCSI-IOCS CALL について... □■□>- SCSI-IOCS CALL は、CALL 番号を d1.l に入れて IOCS CALL の $f5 を実行する ことで呼び出されます。例えば、S_RESET を実行するには moveq.l #$00,d1 moveq.l #$f5,d0 tarp #15 となります。SCSI-IOCS CALL の $00~$0f はフェーズ単位など低レベルな機能を 持つもので、$20~$3f には ID 指定でいきなり読み書きできるなどの高レベルな ルーチンが用意されています。 SCSI-TARGET IOCS(SCSITAI.SYS)では SCSI-IOCS CALL のうち $140~を独自の 拡張 CALL として使用します($1F,$3Fだけ例外)。ですから、それぞれ move.l #$140,d1 moveq.l #$f5,d0 tarp #15 などのようにして呼び出すことができます。また登録した SCSI コマンドなど割り 込みルーチン内で呼び出す場合のために、_TS_WORKADR によってジャンプベクタを 得たのち move.l #$140,d1 jsr (a0) などのように TRAP を使用せずに直接エントリを呼び出すことができます。TARGET ルーチン内ではこちらの方法を推奨します。 なお、この SCSI-IOCS CALL は、出力に書かれていないものであっても常に d0.l が破壊されますので注意して下さい。 `◎'のついているコマンドは target.x では存在せず、SCSITAI.SYS で追加され たもの、あるいは仕様の変更されたものです。 `★'のついているコマンドは普通使わない物(SCSITAI.SYS 内部で使用している) ですので、考えすぎない方がいいと思います ^^; 。 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ◎ $1F SCSITAI.SYS の登録チェック 出力 d0.l : -1 常駐していない (-2) target.x が常駐している -3 常駐している $140 番以降の拡張コールを使用する前に、SCSITAI.SYS の登録チェック を行うことができます。 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- <ターゲット動作時、使用> ・ $140 _TS_DATAIN データインフェーズの実行 入力 d3.l : バイト数 a1.l : データを指すアドレス ターゲットとしての DATAIN フェーズを実行します。ターゲット側から見 ればデータの出力になります。 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- <ターゲット動作時、使用> ・ $141 _TS_DATAOUT データアウトフェーズの実行 入力 d3.l : バイト数 a1.l : データ格納領域指すアドレス ターゲットとして DATAOUT フェーズを実行します。ターゲット側から見 ればデータの入力になります。 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- <ターゲット動作時、使用> ・ $142 _TS_MSGIN メッセージインフェーズの実行 入力 a1.l : メッセージ格納領域指すアドレス ターゲットとして MESSAGE IN フェーズを実行します。拡張メッセージ($01) はルーチンで判定するため、特にデータ長を与える必要はありません。 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- <ターゲット動作時、使用> ・ $143 _TS_MSGIN1 メッセージインフェーズの実行 入力 d2.l : 1byteのメッセージ ターゲットとして MESSAGE IN フェーズを実行します。拡張メッセージ以 外の 1byte メッセージを簡単に出力するために用意したルーチンです。 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- <ターゲット動作時、使用> ・ $144 _TS_MSGOUT メッセージアウトフェーズの実行 入力 a1.l : 受け取ったメッセージを格納するアドレス ターゲットとして MESSAGE OUT フェーズを実行します。通常は 1byte で すが、拡張メッセージの場合が考えられるので、バッファは若干の余裕を 取っておいて下さい(MESSAGE 最大は 258byte あります)。 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- <ターゲット動作時、使用> ・ $145 _TS_STSIN ステータスフェーズの実行 入力 a1.l : ステータス格納領域のアドレス ターゲットとして STATUS フェーズを実行します。1byte のステータスを イニシエータに渡します。 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- <ターゲット動作時、使用> ・ $146 _TS_STSIN1 ステータスフェーズの実行 入力 d2.l : ステータス TS_STSIN を簡単に使えるようにしたものです。 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- <ターゲット動作時、使用> ★ $147 _TS_COMMAND コマンドフェーズの実行 入力 a1.l : コマンド格納領域のアドレス d3.l : GROUP 0,1,5 以外の時コマンドを読み取るバイト数 コマンドフェーズを実行して、コマンドを受け取ります。普通は SCSITAI.SYS が自動に COMMAND フェーズは行いますのでユーザーが使う必要はありま せん。 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- <ターゲット動作時、使用> ・ $148 _TS_RELEASE バスフリーフェーズの実行 バスフリーフェーズを実行します。 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- <ターゲット動作時、使用> ・ $149 _TS_RELEASEF バスフリーフェーズの実行 バスフリーフェーズを実行します。 _TS_RELEASE($148)と同じです。 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- <ターゲット動作時、使用> ◎ $14A _TS_SETSENSEKEY SENSE KEY を設定 入力 d2.l : KEY*0x10000 + ASC*0x100 + ASCQ d2.l : -1 なら d3.l = インフォメーション REQUEST SENSE で返すセンスデータを設定します。インフォメーション設 定の場合は必ず、KEY,ASC,ASCQ を設定してから行ってください。インフォ メーションは d0>=0 でクリアされるので、設定の順に注意して下さい。 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- <ターゲットルーチン登録用> ◎ $14B _TS_SETPAGE Page Data テーブルのアドレス 入力 d2.l : 登録したい LUN d4.l : 0 a1.l : Page Data テーブルアドレス 出力 d0.l : 前の Page Data テーブルアドレス -1 ; LUN が異常 LUN 別に Page Data を設定します。各ページは、ページ $3f で返される 形で表記します。セーブページはサポートしていません。 PageDataTable: .dc.l カレントページアドレス .dc.l チェンジページアドレス .dc.l デフォルトページアドレス .dc.l (*)SELECT 後に呼び出されるルーチンアドレス (*)SELECT 後に呼び出されるルーチンアドレス 現在使用されません。rts をさすアドレスを指定してお いて下さい。 補)現在、SenseMode/SelectMode は Page $3f 以外サポートしていませ ん。 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- <ターゲット動作時、使用> ★ $14c _TS_INPUT マニュアル転送によるデータの直接読み込み 入力 a1.l : バッファアドレス d3.l : バイト数 マニュアル転送による読み込みを行います。ルーチンで呼び出されます。 名前がややこしいですが、フェーズ名はイニシエータからみた IN/OUT に なってるため、このルーチン名とは逆です。 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- <ターゲット動作時、使用> ★ $14d _TS_OUTPUT マニュアル転送によるデータの直接書き込み 入力 a1.l : バッファアドレス d3.l : バイト数 マニュアル転送による書き込みを行います。 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- <ターゲット動作時、使用> ★ $14e _TS_INPUTH ハード転送によるデータの直接読み込み 入力 a1.l : バッファアドレス d3.l : バイト数 ハード転送による(CPU転送)読み込みを行います。 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- <ターゲット動作時、使用> ★ $14f _TS_OUTPUTH ハード転送によるデータの直接書き込み 入力 a1.l : バッファアドレス d3.l : バイト数 ハード転送による(CPU転送)書き込みを行います。 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- <ターゲット動作時、使用> ★ $150 _TS_INPUTD DMA転送によるデータの直接読み込み 入力 a1.l : バッファアドレス d3.l : バイト数 ハード転送による(DMA転送)読み込みを行います。 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- <ターゲット動作時、使用> ★ $151 _TS_OUTPUTD DMA転送によるデータの直接書き込み 入力 a1.l : バッファアドレス d3.l : バイト数 ハード転送による(DMA転送)書き込みを行います。 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- <ターゲット動作時、使用> ◎ $154 _TS_STMSE ステイタス メッセージ バスフリー を行う 入力 d2.wl = ステイタス d2.wh = メッセージ _TS_STSIN($145),_TS_MSGIN($142),_TS_RELEASE($148) を行います。ただしメッセージは 1byte のものしか送 れません。 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- <ターゲット動作時、使用> ★ $158 _TS_CMDEXEC SCSIコマンドの実行 入力 (a1) : コマンド コマンドフェーズで得た SCSI コマンドに従い、それぞれの処理に分岐し ます。その処理はあらかじめ _TS_CMDSET によって登録しておきます。 通常は SCSITAI.SYS が処理呼出まで自動的行いますので、単独では使い ません。 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- <ターゲットルーチン登録用> ◎ $159 _TS_CMDSET SCSIコマンドの実行ルーチンの登録 入力 a1.l : 処理ルーチンのアドレス d2.wl = OP.CODE + CDB 長さ*0x100 注意)CDB 長さは グループ 0,1,5 以外は指定必須! d2.wh = LUN d4.l = 0 出力 d0.l : 処理ルーチンのアドレス+1 SCSI コマンド処理ルーチンを追加登録、あるいは削除します。例えば SCSI コマンドの オペコード $0e (WRITE AND VERIFY) を LUN 1 に登録 したければ d2 には $0001002e を格納して下さい。GROUP 0/1/5 以外は CDB 長さも明記してください。例えば、オペコード $FF を LUN 6 に登録 する場合は、 d2 には $00060AFF となります(GROUP 6/7 の CDB は 10 byte である必要はありませんが、外部からの SCSI コマンドの登録チェッ クが困難になりますので、普通は 10 byte にしてください)。 登録出来る数は限りがある(現在200個)ので、もしいっぱいの場合は d0 に -1 を返します。 削除は登録時に d0 に返ってきた値を a1 に入れ、本コールをコールし てください。 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- <ターゲット動作時、使用> ◎ $15D _TS_IDENIN イニシエータからの IDENTIFY、イニシエータの ID 、 対象の LUN が返る 出力 (d0.wh ) = LUN (d0.wl>>8 and $07) = 自分の ID と相手の ID の BIT が立つ (d0.b and $C0) が $C0 なら disconnect やっても可。 d0.l がマイナスなら無効 ターゲットルーチンを複数の LUN で共通させ、このコールで LUN を得て 分岐することも出来ます。また、相手の ID が判るのでそれによって処理 を変更することも可能です。 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- <ターゲットルーチン登録用> ◎ $160 _TS_WORKADR SCSITAI.SYS ワークエリアアドレスの獲得 入力 d4.l = 0 出力 d0.l : ワークエリアアドレス SCSITAI.SYS の内部ワークエリアアドレスを得ます。ワークエリアの内容 は以下の通りで、この領域の先頭アドレスが返ります。なお常駐している SCSITAI.SYS のバージョン番号は、ここで得たアドレス -8 から文字列と して書き込まれているので、参照することができます。 ($00) .dc.l SPC割り込みのベクタアドレス ($04) .dc.l SPC のアドレス ($08) .dc.w SPC で使用している割り込みのベクタ番号 ($0A) .dc.w 未使用 ($0C) .dc.l SCSI-IOCS CALL の元のベクタアドレス ($10) .dc.l ◎ 未使用 ($14) .dc.l SCSI-IOCS CALL ベクタテーブルのアドレス ($18) .dc.l 拡張SCSI-IOCS CALL のベクタテーブルのアドレス (*) ($1C) .dc.l SCSITAI.SYS 内での SCSI IOCS CALL 呼び出しアドレス ($20) .dc.l SPC 割り込みの処理ルーチンアドレス ---- ($24) .dc.l 'Tai!' ($28) .dc.w flag; -1ならイニシエータ時 DMAC を使用しない ($2A) .dc.w flag; -1ならターゲット時 DMAC を使用しない ($2C) .dc.w flag; -1なら[ヒラカナ]でデバックモードになる ($2E) .dc.w flag; -1ならターゲットアクセス時 TIMER-LED 点灯 これらの値は全部常駐時に書き込まれる定数です。最初に説明した、 trap #15 ではなく jsr による直接呼び出しを行うには、(*) に書かれて いるアドレスを取り出しておく必要があります。 例) move.w #$160,d1 moveq #$f5,d0 trap #15 move.l d0,a0 move.l $1C(a0),_scsicallent *SUPER バイザモードなので注意 : move.l _scsicallent,a5 : move.w #$145,d1 jsr (a5) =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- <その他> ・$161 _TS_PORTCHECK SCSI ポートのアドレスを調べます 入力 d4.l = 0 出力 a6.l : SPC へアクセスするためのベースアドレス d0.w : SPC で使用している割り込みベクタ番号 SCSI のアドレスを調べます。もし SCSI がなければ d0 に 0 を返します。 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- <その他> ・$162 _TS_SCSIVCS SCSI IOCS CALL のベクタを設定します 入力 a1.l : 処理ルーチンのアドレス d2.l : オペレーションコード d4.l = 0 出力 d0.l : 以前の実行アドレス SCSI CALL の処理アドレスを設定します。以上説明してきた拡張 CALL お よび元々の $00~$3f の標準 SCSI CALL も置き換えることができます。 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- <ターゲットルーチン登録用> ◎ $163 _TS_BRESET バスリセットの割り込み 入力 a1.l : 処理ルーチンのアドレス d2.l : 0 ; 登録 1 ; 解除 d4.l = 0 出力 d0.l : 0;登録成功 -1;失敗(限界を超えた、登録されていなかった) 外部からバスリセットが起きると割り込みでルーチンが呼ばれます。 ルーチン内でレジスタは破壊しないで下さい。 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- <イニシエータ動作時、使用> ◎ $168 _S_MSGINDAT 拡張メッセージを得る 出力 d0.l : メッセージのアドレス MSGIN(SCSI$07)で $01、あるいは高級コール($20~$3F)で上位ワード に $01 (拡張メッセージ)を受けた時、このコールで残りのメッセージ を得られます。アドレスには、最初のメッセージ($01)から入っていま す。 -<□■□ SCSI フェーズについて... □■□>- SCSI フェーズとは、SCSI バスの状態をさします。SCSI の動作は フェーズ単位 にわけて考えることが出来ます。 ・バスフリーフェーズ: 誰もフェーズを使用していない状態です。 ・アービトレーションフェーズ: イニシエータが、SCSI バスの使用権の調停を行います。だれかが SCSI を使用している場合や、同時に使おうとした時、待つことになります。 ・セレクションフェーズ: 接続したいターゲット ID に機器を指定します。指定された ID の機器は 応答する。これで接続は完成する。 補)SCSITAI.SYS の場合、SPC 割り込みが発生します。 ・コマンドフェーズ: イニシエータからターゲットにコマンド(CDB)を送ります。ターゲット 側は CDB を解析して、対応を考える。 補)SCSITAI.SYS の場合、自動的にコマンドフェーズを 行い、CDB のオペランドコードを解析し各コマンドの ルーチンへ分岐します。 ・データフェーズ: CDB の オペランドコード(CDB の 1byte目)によっては、このフェーズ がない場合もある。また、CDB の内容や、ターゲットの状態の都合で、イ ニシエータの要求を無視しデータフェーズを行わないことも出来る(イニ シエータで転送エラーは出る)。 データフェースはインとアウトのどちらかがあります。ターゲット側から 見ると、ターゲットからデータを送り出すのはデータインフェーズになり ます。ご注意。 補)SCSITAI.SYS の場合、TS_DATAIN TS_DATAOUT を使 用します。 ・ステイタスフェーズ: ターゲットからイニシエータに1byte のステイタスを送ります。ステイ タスは、 0 ・・・ 正常終了 2 ・・・ チェックコンディション。イニシエータ側はこの「2」 を受け取ったら、次に SCSI REQUEST を実行してきます。 8 ・・・ BUSY 。ターゲット機器が忙しい時。イニシエータは再 度同じ SCSI コマンドを実行します。 補)SCSITAI.SYS の場合、TS_STSIN or TS_STSIN1 を使 用します。 ・メッセージインフェーズ: ターゲットからイニシエータにメッセージを送ります。メッセージは SCSI で決められています。基本的に0です。ベンダユニークのコマンドであれ ば、独自にメッセージを決めても問題はありません。 補)SCSITAI.SYS の場合、TS_MSGIN or TS_MSGIN1 を使 用します。 ・バスフリーフェーズ: メッセージインフェーズ後、バスフリーされます。 補)SCSITAI.SYS の場合、TS_RELEASE を使用します。 その後、rts で SPC 割り込みを終わります。 -<□■□ SCSI コマンドについて... □■□>- 拡張された SCSI IOCS CALL のほとんどは、X68k がターゲットとして動作する ために必要なものです。フェーズを移行したり実行したりデータのやりとりを行う、 いわば自分のインターフェースであるハードに対する命令です。それに対して、 SCSI コマンドとは SCSI 装置同士がコミュニケーションをはかる上での取り決め であり、他の装置へのソフト的な命令といえます。 X68K 本体を SCSI 装置として認識させるためには、外から SCSI コマンドで話 し掛けられたらちゃんと返事をしてあげなければなりません。SCSITAI.SYS はごく 基本的なコマンドに対する処理を内部に持っています。それが以下のリストです。 オペレーションコード$00 TESTUNIT ステータス0を返します $01 REZEROUNIT 何もしません $03 REQUEST REQUEST SENSEを返します $08 READ V-RAM を読みます $0A WRITE V-RAM に書きます $12 INQUIRY 適当な装置情報を返します $1A MODESENSE PAGE を返します $1B STARTSTOP 何もしません オペレーションコード $25 READCAP 適当に反応します $28 READEXT V-RAM を読みます $2A WRITEEXT V-RAM に書きます $2E WRITEVRY V-RAM に書きます オペレーションコード ベンダユニーク (SCSITAI 独自コード) $D0 MEMPEEK メモリを読み込みます $D1 MEMPOKE メモリに書き込みます $D8 IOCSCALL IOCS コールを実行します $D9 IOCSCALLIN IOCS コールの結果を見ます デフォルトの状態でも、相手の V-RAM 操作や、IOCS 実行、メモリ読み書き、い ろいろ出来ますが、更に、ユーザーで必要なコマンドの処理を定義することで、出 来ることが広がります。例えば SCTRDISK.x では以下のコマンドを LUN 0 に登録 しています。 $08 READ 確保した領域から読み込む $0A WRITE 確保した領域に書き込む $12 INQUIRY 適当な装置情報を返します $25 READ CAPACITY ブロック数とブロックサイズ設定 $28 READ(10) 確保した領域から読み込む $2A WRITE(10) 確保した領域に書き込む $0B SEEK 何もしません $2B SEEK(10) 何もしません $2F VERIFY 何もしません $04 FORMAT 何もしません このようなコマンド登録には _TS_CMDSET を使います。以下は、READ コマンドの 実際の処理ルーチンの例です。 -------------------- .include target.mac TCALL macro ent move.w #ent.d1 jsr (a5) endm _scsi_read: * この段階でセレクションフェーズ、 * コマンドフェーズは終わっている。 move.l (a1),d0 * (a1) に CDB がある andi.l #$001FFFFF,d0 * コマンドから BLOCK 番号を得る lsl.l #8,d0 * 256倍(BLOCKサイズが256byteの時) moveq #0,d3 move.b 4(a1),d3 * コマンドから BLOCK 長を得る lsl.l #8,d3 * 256倍(BLOCKサイズが256byteの時) move.l DISKBUFADR(pc),a1 add.l d0,a1 * バッファアドレスを計算する move.l SCSI_IOCS_ENT(pc),a5 * コール先を用意 TCALL _TS_DATAIN * データインフェーズに答える * ターゲット側から見ればデータをイ * ニシエータに転送することになる moveq.l #0,d2 TCALL _TS_STSIN1 * ステータス 0 を返す TCALL _TS_MSGIN1 * メッセージ 0 を返す TCALL _TS_RELEASE * バスフリーフェーズを実行する rts DISKBUFADR: .dc.l DISKで使う領域のアドレス SCSI_IOCS_ENT: .dc.l 予め初期化ルーチン(常駐時等)でアドレスを書き込んでおく -------------------- SCSI の $08 READ コマンドは GROUP 0 なので、以下のような 6byte の構造になっ ています。 7 6 5 4 3 2 1 0 ┏━┷━┷━┷━┷━┷━┷━┷━┓ 0┃ OP.CODE $D0 ┃ ┣━┿━┿━┿━┿━┿━┿━┿━┫ 1┃ LUN | ┃ ┣━┿━┿━┿ ┫ 2┃ ┃ ┣ 転送開始 BLOCK ┫ 3┃ ┃ ┣━┿━┿━┿━┿━┿━┿━┿━┫ 4┃ 転送 BLOCK 長 ┃ ┣━┿━┿━┿━┿━┿━┿━┿━┫ 5┃ R | コントロール ┃ ┗━┷━┷━┷━┷━┷━┷━┷━┛ と入っています。 この 6byte の先頭アドレスが a1 に入った状態で、上記の _scsi_read ルーチ ンは呼び出されるわけです。このように、登録する処理は1つで完結していなけれ ばならず、_TS_STSIN と _TS_MSGIN が続いて最後に _TS_RELEASE が必要です。 簡単な流れにすると ・TS_CMDSET で登録したアドレスからはじまる。 ・(a1) に格納された CDBを解析する。 ・データ IN/OUT が必要ならデータフェーズを行う。CDB の値(フラグ) により、データフェースを行わなくても構わない。 ・ステイタスフェーズを行う。問題無く処理出来たら、0を送る。処理出 来なかった場合、2か8を返す。2の場合、rts の前に SENSE KEY を 設定($14A _TS_SETSENSEKEY)するのを忘れないようにしましょう。 ・メッセージフェーズを行う。普通は、0を送る。ベンダユニークコマン ドであれば、ベンダユニークなメッセージを用意しても構わない。 ・バスフリーにする。 ・もし、ステイタスが2であれば REQUEST SENSE をされるのは必至なの で、SENSE KEY を設定する。 SCSI_IOCS_ENT に書き込む値は、SCSI-IOCS CALL のエントリアドレスです。こ れは自分でマクロ TCALL を使用する直前に move.l SCSI_IOCS_ENT(pc),a5 として 参照しています。trap を使わずにルーチンを呼び出すための処置です。これは以 下のようにして得ます。 TSCSI _TS_WORKADR move.l d0,a0 move.l 28(a0),SCSI_IOCS_ENT - SUPER バイザエリアなので注意 上記の _scsi_read を登録するには、次のようになります。 moveq #$08,d2 * READ のオペレーションコード move.l #_scsi_read,a1 * 処理アドレス TSCSI _TS_CMDSET move.l d0,_old_scsi_read なお、コマンドルーチンが呼び出された場合 a6 レジスタには常に SPC のベー スアドレスが入ります。SPC レジスタアクセスは全部この値が用いられますので、 a6 の内容は破壊しないようにして下さい。 a6.l SPC ベースアドレス a1.l コマンドが格納されている領域のアドレス その他、具体的な利用法は、サンプルアプリケーションのソースを参照して下さ い。 -<□■□ SCSITAI.SYS のデフォルトのベンダユニーク... □■□>- 7 6 5 4 3 2 1 0 ┏━┷━┷━┷━┷━┷━┷━┷━┓ 0┃ OP.CODE $D0 ┃ ┣━┿━┿━┿━┿━┿━┿━┿━┫ 1┃ LUN | R |BC|MP┃ ┣━┿━┿━┿━┿━┿━┿━┿━┫ 2┃ ┃ ┣ ┫ 3┃ ┃ ┣ メモリアドレス ┫ 4┃ ┃ ┣ ┫ 5┃ ┃ ┣━┿━┿━┿━┿━┿━┿━┿━┫ 6┃ R ┃ ┣━┿━┿━┿━┿━┿━┿━┿━┫ 7┃ ┃ ┣ 転送byte長 ┫ 8┃ ┃ MEMPEEK OP.= $D0 ┣━┿━┿━┿━┿━┿━┿━┿━┫ グループ6 9┃ R | コントロール ┃ ┗━┷━┷━┷━┷━┷━┷━┷━┛ 指定「メモリアドレス」から指定「転送byte長」読み出す。ターゲットである X68 から見れば、自分のメモリの内容をイニシエータに送り出すことになる。 MP =1 の場合、メモリ読み込みに MPU 以外は使用しないようになる。I/O ポー トなどを読む場合、指定する。 ==================================== 7 6 5 4 3 2 1 0 ┏━┷━┷━┷━┷━┷━┷━┷━┓ 0┃ OP.CODE $D1 ┃ ┣━┿━┿━┿━┿━┿━┿━┿━┫ 1┃ LUN | R |BC|MP┃ ┣━┿━┿━┿━┿━┿━┿━┿━┫ 2┃ ┃ ┣ ┫ 3┃ ┃ ┣ メモリアドレス ┫ 4┃ ┃ ┣ ┫ 5┃ ┃ ┣━┿━┿━┿━┿━┿━┿━┿━┫ 6┃ R ┃ ┣━┿━┿━┿━┿━┿━┿━┿━┫ 7┃ ┃ ┣ 転送byte長 ┫ 8┃ ┃ MEMPOKE OP.= $D1 ┣━┿━┿━┿━┿━┿━┿━┿━┫ グループ6 9┃ R | コントロール ┃ ┗━┷━┷━┷━┷━┷━┷━┷━┛ 指定「メモリアドレス」から指定「転送byte長」書き出す。ターゲットである X68 から見れば、イニシエータからもらったデータを自分のメモリに対して書き込 むことになる。 MP =1 の場合、メモリ書き込みに MPU 以外は使用しないようになる。I/O ポー トなどを書く場合、指定する。 尚、書き込みは相手の状態、アドレスを十分理解して行うこと。 ==================================== 7 6 5 4 3 2 1 0 ┏━┷━┷━┷━┷━┷━┷━┷━┓ 0┃ OP.CODE $D8 ┃ ┣━┿━┿━┿━┿━┿━┿━┿━┫ 1┃ LUN | R |AA┃ ┣━┿━┿━┿━┿━┿━┿━┿━┫ 2┃ R ┃ ┣━┿━┿━┿━┿━┿━┿━┿━┫ 3┃ R ┃ ┣━┿━┿━┿━┿━┿━┿━┿━┫ 4┃ R ┃ ┣━┿━┿━┿━┿━┿━┿━┿━┫ 5┃ R ┃ ┣━┿━┿━┿━┿━┿━┿━┿━┫ 6┃ R ┃ ┣━┿━┿━┿━┿━┿━┿━┿━┫ 7┃ ┃ ┣ 転送byte長 ┫ 8┃ ┃ IOCSCALL OP.= $D8 ┣━┿━┿━┿━┿━┿━┿━┿━┫ グループ6 9┃ R | コントロール ┃ ┗━┷━┷━┷━┷━┷━┷━┷━┛ OP.= $D9 と対になる。戻り値等はOP.= $D9で得る。戻り値がないもの、必要 がない場合は、OP.= $D9を使用する必要はない。 AA=1 の場合、a1 を「データやり取りのバッファ用」に使うこととする。デー タ内の a1 の内容の意味はなくなる。 転送byte長は AA=0 の場合、4×15= 60 固定。AA=1 の場合、60+αとなる。た だし、基本は 4096 までとする(拡張の可能性もある)。越えるとチェックコン ディションとなり、KEY=5 ASC=24 ASCQ=00。そして Valid=1 の場合 インフォメーション で限界値を知ることが可能である(限界長-要求転送byte長が入っている)。 更に(a1)にデータを入れるコールはデータ量が 4096 (拡張の可能性もある) が越える可能性のあるものは使用禁止とする。エラーチェックはない。 データアウトで以下のデータを送る。 ┏━━━━━━━┓ ┃ d0~d7 ┃ 4byte × 8 ┣━━━━━━━┫ ┃ a0~a6 ┃ 4byte × 7 ┣━━━━━━━┫ ┃(a1)内のデータ┃ コールによる ┃ : ┃ ┗━━━━━━━┛ 尚、IOCS コールは相手の状態、IOCS コール内容を十分理解して行うこと。 ==================================== 7 6 5 4 3 2 1 0 ┏━┷━┷━┷━┷━┷━┷━┷━┓ 0┃ OP.CODE $D9 ┃ ┣━┿━┿━┿━┿━┿━┿━┿━┫ 1┃ LUN | R ┃ ┣━┿━┿━┿━┿━┿━┿━┿━┫ 2┃ R ┃ ┣━┿━┿━┿━┿━┿━┿━┿━┫ 3┃ R ┃ ┣━┿━┿━┿━┿━┿━┿━┿━┫ 4┃ R ┃ ┣━┿━┿━┿━┿━┿━┿━┿━┫ 5┃ R ┃ ┣━┿━┿━┿━┿━┿━┿━┿━┫ 6┃ R ┃ ┣━┿━┿━┿━┿━┿━┿━┿━┫ 7┃ ┃ ┣ 転送byte長 ┫ 8┃ ┃ IOCSCALLIN OP.= $D9 ┣━┿━┿━┿━┿━┿━┿━┿━┫ グループ6 9┃ R | コントロール ┃ ┗━┷━┷━┷━┷━┷━┷━┷━┛ OP.= $D8 と対になる。IOCSCALL(OP.=$D8)の実行結果を受け取るために使用す る。 転送 byte 長は IOCSCALL(OP.=$D8)で AA=1 の場合、(a1)内に入るデータを受け 取れる。転送 byte 長は レジスタの戻り値、(a1)内のデータ、となる。よって長 さは考慮して算出すること。 データインで以下のデータを貰える。 ┏━━━━━━━━┓ ┃ d0~d7 ┃ 4byte × 8 ┣━━━━━━━━┫ ┃ a0~a6 ┃ 4byte × 7 ┣━━━━━━━━┫ ┃ (a1)内のデータ ┃ コールによる ┃ : ┃ ┗━━━━━━━━┛ データ内容は、最後に実行したIOCSCALL(OP.=$D8)の内容が保持されている。 ==================================== このテキストは、target.x(作:COR.氏)のドキュ メントをベースにしております。 文:田圃 鴎(TNB製作所)