//	ＡＩＧライブラリ　ＳＣＳＩ関数
//		Copyright (C) 2000-2002 by AIG-SOFT

#ifndef	__AIG_SCSI__
#define	__AIG_SCSI__	1

#include <scsi.h>
#include "defines.h"
#include "dma.h"

//------------------------------------
// SCSI キャッシュ

#define	S_CACHE_OFFSET	4	// BIT2 : オフセット表付きWrite : 必ずWRITEと同時に指定すること
#define	S_CACHE_WRITE	2	// BIT1
#define	S_CACHE_READ	1	// BIT0
				// 将来READ&WRITEを実装するためビット対応にしておく

typedef struct {		// １ブロック毎の情報(Read)
	unlong	sec;		// セクター番号
	unshort	ii;		// 対応するキャッシュブロック番号
} S_CACHE1;			// 使用したブロックを[0]に移動する

typedef struct {		// キャッシュ全体の情報
	// SCSI装置情報
	unlong	id;		// SCSI-ID+LUN
	short	sec1;		// １セクターサイズ
	long	blksz;		// ブロックの容量(0:256 1:512 2:1024 3:2048 …)
	// キャッシュ本体
	unchar	*cache;		// キャッシュ本体アドレス
	long	allblock;	// キャッシュ本体サイズ（sec1単位のブロック数）
				// 1〜65535 : 但し処理の都合上longにしている(unshortでは加算時にオーバーフローするので)
	int	mode;		// S_CACHE_WRITE/READ（読み書きいずれか）
	// 制御(Read/Write用)
	long	nextblock;	// 次回与えるブロック位置
	// 制御(Read/OffsetWrite用)
	S_CACHE1 *sectors;	// Read :各ブロックの示すセクターの表のアドレス
				// Write:同一データを複数セクター位置に書き出す時のオフセット表
	// 制御(Write用)
	unlong	sector0;	// nextblock=0の書き込みセクター番号
	long	blocks;		// 前回与えたブロック数
} S_CACHE_BUFF;

//------------------------------------
// SCSI制御

#define	SCSIRETRYMaxCount	6	// SCSIコマンドエラーが発生した時のリトライ回数
				// SUSIE内部のリトライ回数と同じにした(sdd.ap;SCSI_SELECT)

//------------------------------------
// SPC関係（89352:標準SPC）

typedef	struct	{	// SPCレジスター
	unchar	dummy0;
	unchar	bdid;
	unchar	dummy1;
	unchar	sctl;
	unchar	dummy2;
	unchar	scmd;
	unshort	dummy4;
	unchar	dummy3;
	unchar	ints;
	unchar	dummy5;
	unchar	psns;
	unchar	dummy6;
	unchar	ssts;
	unchar	dummy7;
	unchar	serr;
	unchar	dummy8;
	unchar	pctl;
	unchar	dummy9;
	unchar	mbc;
	unchar	dummy10;
	unchar	dreg;
	unchar	dummy11;
	unchar	temp;
	unchar	dummy12;
	unchar	tch;
	unchar	dummy13;
	unchar	tcm;
	unchar	dummy14;
	unchar	tcl;
} SPCREG;

// 現在のフェーズ	  76543210
#define	PSNS_REQ	0b10000000
#define	PSNS_ACK	0b01000000
#define	PSNS_ATN	0b00100000
#define	PSNS_SEL	0b00010000
#define	PSNS_BSY	0b00001000
#define	PSNS_MSG	0b00000100
#define	PSNS_CD		0b00000010
#define	PSNS_IO		0b00000001
//
#define	PSNS_BUSFREE		0b000	//		BSY=0
#define	PSNS_COMMAND		0b010	//    |CD|
#define	PSNS_DATA_IN		0b001	//    |  |IO
#define	PSNS_DATA_OUT		0b000	//    |  |	BSY=1
#define	PSNS_STATUS		0b011	//    |CD|IO
#define	PSNS_MESSAGE_IN		0b111	// MSG|CD|IO
#define	PSNS_MESSAGE_OUT	0b110	// MSG|CD|

// フェーズを決める定数
#define	PCTL_DATA_OUT		0b000
#define	PCTL_DATA_IN		0b001
#define	PCTL_COMMAND		0b010
#define	PCTL_STATUS		0b011
#define	PCTL_MESSAGE_OUT	0b110
#define	PCTL_MESSAGE_IN		0b111

// 動作指示		  76543210
#define	SCMD_CPU_TRNS	0b00000100	// CPU転送
#define	SCMD_DMA_TRNS	0b00000000	// DMA転送
#define	SCMD_SELECT	0b00100000	// 0x20
#define	SCMD_TRANSFER	0b10000000	// 0x80
#define	SCMD_SET_ATN	0b01100000
#define	SCMD_RESET_ATN	0b01000000
#define	SCMD_SET_ACK	0b11100100	// 0xe4 CPU転送
#define	SCMD_RESET_ACK	0b11000100	// 0xc4 CPU転送
#define	SCMD_SET_ACKB	0b11101100	// 0xec CPU転送（バッファー保存）
#define	SCMD_RESET_ACKB	0b11001100	// 0xcc CPU転送（バッファー保存）

#define	INTS_DISCONNECT	BIT5
#define	INTS_COMPLETE	BIT4
#define	INTS_CANTTRNS	BIT3
#define	INTS_TIMEOUT	BIT2

#define	SSTS_DREG_EMPTY	BIT0
#define	SSTS_DREG_FULL	BIT1

//------------------------------------

#ifdef	__cplusplus
// 95/11 : G++対応
extern	"C" {
#endif
	// 危ないのでプロトタイプのみ
	// SCSI基本関数
	int	S_X68ID(void);
	int	S_CMD0( unlong , int , unchar *, int , unchar * );
	int	S_CMD( unlong , int , unchar *, int , unchar * );
	int	S_SecRead(unlong ,long,unlong ,int ,unchar *);
	int	S_SecWrite(unlong ,long,unlong ,int ,unchar *);
	int	S_CheckReady(unlong );
	int	S_WriteProtect(unlong );
	int	S_Retry(unlong ,int ,int *);
	int	S_READCAP2(unlong ,unlong *,unlong *);
	int	S_EjectMode(unlong ,int );
	int	S_SeekExt(unlong ,unlong);
	// TwoScsi
	int	S_TW_CHK(void);
	int	S_TW_MAXID(void);
	int	_TW_CALL(int ,int );
	void	S_TW_RESET(int);
	void	S_TW_PHASE(int);
	int	S_TW_LEVEL(int);
	// Read/Writeキャッシュ
	int	S_CacheOpen(S_CACHE_BUFF *,unlong ,long ,int);
	int	S_CacheClose(S_CACHE_BUFF *);
	void	_S_CacheInit(S_CACHE_BUFF *);
	// Writeキャッシュ
	int	S_CacheFlush(S_CACHE_BUFF *);
	unchar	*S_CacheGetBuff(S_CACHE_BUFF *,long );
	int	S_CacheWrite(S_CACHE_BUFF *,unlong );
	int	_S_CacheWriteSub(S_CACHE_BUFF *);
	// Readキャッシュ
	int	S_CacheRead(S_CACHE_BUFF *,unlong ,long ,unchar *);
	// SPC制御
	int	SPC_init(time_t );
	void	SPC_reset(void);
	int	SPC_select(unlong ,int );
	int	SPC_command(int ,unchar *);
	int	SPC_data_inout(int ,unchar *,int );
	int	SPC_status_message(unchar *,unchar );
	int	SPC_status_in(unchar *);
	int	SPC_message_in(unchar *);
	int	SPC_message_out(unchar *);
	SPCREG	*SPC_adrs(int);
#ifdef	__cplusplus
}
#endif

//------------------------------------
// マクロ関数

// TwoScsi
#define	S_TW_RESET(port)	_TW_CALL(0x0200,port)
#define	S_TW_PHASE(port)	_TW_CALL(0x0209,port)
#define	S_TW_LEVEL(port)	_TW_CALL(0x020a,port)

// SPC
#define	SPC_adrs(type)	((SPCREG *)(type&BIT3? 0xea0000:0xe96020))
#define	SPC_status_in(dat)	SPC_status_message(dat,PSNS_STATUS)	 // ステータスイン
#define	SPC_message_in(dat)	SPC_status_message(dat,PSNS_MESSAGE_IN)	 // メッセージイン
#define	SPC_message_out(dat)	SPC_status_message(dat,PSNS_MESSAGE_OUT) // メッセージアウト

//------------------------------------

#endif
