−<□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□>−



			     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製作所)