/*
 * SASI hard drive emulator class
 */

#ifndef SASI_H
#define SASI_H

#include <stdio.h>
#include "MemEmul.h"

class DiscEmul;

class SASI: public MMIO_Dev
{
protected:
	int data, status, next_status;
	enum stat_val
	{
		STAT_MSG = 1,
		STAT_BSY = 2,
		STAT_NIRQ = 0x10,
		STAT_REQ = 0x20,
		STAT_IO = 0x40,
		STAT_CD = 0x80
	};
	int en_irq;
	
	enum phase
	{
		PH_CMD = 0,
		PH_STAT,
		PH_DATAOUT,
		PH_DATAIN,
		PH_MSGIN,
	} phase;
	
	// Data for the various phases
	int msg, msgphase;
	byte command[6];
	int cmdbytes, cmd_len;
	
	byte databuf[256*6];
	int databuf_ptr, databuf_len;
	
	void Rel_REQ (void);
	void Select (enum phase ph);
	void DoWrite (int val);
	void ProcessCmd (void);
	
	DiscEmul *the_disc;

public:
	CompEmul *parent;
	SASI (void);
	virtual ~SASI (void);
	virtual byte MMIO_Read (int addr);
	virtual void MMIO_Write (int addr, byte val);
	virtual void Reset (void);
	
	virtual void AddOK (void);
};

// SCSI structures and definitions stolen from Linux cdrecord
struct	scsi_g0cdb {		/* scsi group 0 command description block */
	byte	cmd;		/* command code */
	unsigned	high_addr : 5;	/* high part of block address */
	unsigned	lun	  : 3;	/* logical unit number */
	byte	mid_addr;	/* middle part of block address */
	byte	low_addr;	/* low part of block address */
	byte	count;		/* transfer length */
	unsigned	link	  : 1;	/* link (another command follows) */
	unsigned	fr	  : 1;	/* flag request (interrupt at completion) */
	unsigned	rsvd	  : 4;	/* reserved */
	unsigned	vu_56	  : 1;	/* vendor unique (byte 5 bit 6) */
	unsigned	vu_57	  : 1;	/* vendor unique (byte 5 bit 7) */
};

/*
 * SCSI Operation codes. 
 */
#define SC_TEST_UNIT_READY	0x00
#define SC_REZERO_UNIT		0x01
#define SC_REQUEST_SENSE	0x03
#define SC_FORMAT		0x04
#define SC_FORMAT_TRACK		0x06
#define SC_REASSIGN_BLOCK	0x07		/* CCS only */
#define SC_SEEK			0x0b
#define SC_TRANSLATE		0x0f		/* ACB4000 only */
#define SC_INQUIRY		0x12		/* CCS only */
#define SC_MODE_SELECT		0x15
#define SC_RESERVE		0x16
#define SC_RELEASE		0x17
#define SC_MODE_SENSE		0x1a
#define SC_START		0x1b
#define SC_READ_DEFECT_LIST	0x37		/* CCS only, group 1 */
#define SC_READ_BUFFER          0x3c            /* CCS only, group 1 */
	/*
	 * Note, these two commands use identical command blocks for all
 	 * controllers except the Adaptec ACB 4000 which sets bit 1 of byte 1.
	 */
#define SC_READ			0x08
#define SC_WRITE		0x0a
#define SC_EREAD		0x28		/* 10 byte read */
#define SC_EWRITE		0x2a		/* 10 byte write */
#define SC_WRITE_VERIFY		0x2e            /* 10 byte write+verify */
#define SC_WRITE_FILE_MARK	0x10
#define SC_UNKNOWN		0xff		/* cmd list terminator */


/*
 * Messages that SCSI can send.
 */
#define SC_COMMAND_COMPLETE	0x00
#define SC_SYNCHRONOUS		0x01
#define SC_SAVE_DATA_PTR	0x02
#define SC_RESTORE_PTRS		0x03
#define SC_DISCONNECT		0x04
#define SC_ABORT		0x06
#define SC_MSG_REJECT		0x07
#define SC_NO_OP		0x08
#define SC_PARITY		0x09
#define SC_IDENTIFY		0x80
#define SC_DR_IDENTIFY		0xc0
#define SC_DEVICE_RESET		0x0c

struct	scsi_sense {		/* scsi sense for error classes 0-6 */
	unsigned	code	: 7;	/* error class/code */
	unsigned	adr_val	: 1;	/* sense data is valid */
#ifdef	comment
	unsigned	high_addr:5;	/* high byte of block addr */
	unsigned	rsvd	: 3;
#else
	byte	high_addr;	/* high byte of block addr */
#endif
	byte	mid_addr;	/* middle byte of block addr */
	byte	low_addr;	/* low byte of block addr */
};

struct	scsi_status {
	unsigned	vu_00	: 1;	/* vendor unique */
	unsigned	chk	: 1;	/* check condition: sense data available */
	unsigned	cm	: 1;	/* condition met */
	unsigned	busy	: 1;	/* device busy or reserved */
	unsigned	is	: 1;	/* intermediate status sent */
	unsigned	vu_05	: 1;	/* vendor unique */
#define st_scsi2	vu_05	/* SCSI-2 modifier bit */
	unsigned	vu_06	: 1;	/* vendor unique */
	unsigned	st_rsvd	: 1;	/* reserved */

#ifdef	SCSI_EXTENDED_STATUS
#define	ext_st1	st_rsvd		/* extended status (next byte valid) */
	/* byte 1 */
	unsigned	ha_er	: 1;	/* host adapter detected error */
	unsigned	reserved: 6;	/* reserved */
	unsigned	ext_st2	: 1;	/* extended status (next byte valid) */
	/* byte 2 */
	byte	byte2;		/* third byte */
#endif	/* SCSI_EXTENDED_STATUS */
};

#endif /* SASI_H */

/* End of file. */
