/*
 * $Header: /smsa/bsd:include/dev/scsi.h:bsd  1.5  $
 * $Source: /smsa/bsd:include/dev/scsi.h: $
 *
 * Copyright (c) 1988 Acorn Computers Ltd., Cambridge, England
 */

#ifndef __dev_scsi_h
#define __dev_scsi_h

/* scsi.h
 *
 * Some useful definitions for the Acorn UNIX SCSI driver.
 * M4/A680 uses the WD-33C93 SCSI-Bus Interface Controller.
 */

#ifdef DIRECT_ADDRESSING
#undef DIRECT_ADDRESSING	/* M4/A680 always has the paged approach active */
#endif

#define ALIGNUP(x)	((x+3)&~3)	/* align to word, rounding up */
#define ALIGN(x)	((x)&~3)	/* align to word, rounding down */

/* This is the interrupt declaration for the m4/a680 scsi drivers */

static void scsiintr();
static struct int_hndlr scsiirqstruct = { 0x08, scsiintr, 0, 0 };
/*					  ^^^^
					Note clash with old winc.c bits */

#ifdef DIRECT_ADDRESSING		/* Never used, but here for completeness */

typedef	struct
{ volatile unsigned char reg, padding[15]; }
SCSIReg;

typedef struct
{ SCSIReg
	own_id,
	control,
	timeout_period;
        CDB[12],
	target_lun,
	command_phase,
	synchronous_transfer,
	transfer_count[3],
	destination_id,
	source_id,
	scsi_status,
	command,
	data,
	UNUSED[0x1E-0x1A+1],
	auxiliary_status;
} SCSIChip, *SCSIChipRef;

#define SCSI_aux_status(chip)		((chip)->auxiliary_status.reg)

#define SCSI_put_reg(chip,regname,value) (chip)->regname.reg = (value)
#define SCSI_get_reg(dest,chip,regname) dest = (chip)->regname.reg

#else /* !DIRECT_ADDRESSING */

/* The address register values to select a particular SCSI controller
 * register.  For all registers except command and data, the address
 * register is incremented automatically. Note that "CDB" is the start
 * of the 12 CDB registers, of which the first 6, 10, or all 12 are 
 * normally accessed in sequence when loading a CDB to be sent.
 */
#define SC_own_id		0x00
#define SC_control		0x01
#define SC_timeout_period	0x02
#define SC_CDB			0x03	/* 12 elements in CDB */
#define SC_target_lun		0x0F	/* also status at end of cmd */
#define SC_command_phase	0x10
#define SC_synchronous_transfer	0x11
#define SC_sync_xfer		0x11	/* alias to keep typing reasonable! */
#define SC_transfer_count	0x12	/* start of 3... */
#define SC_transfer_count_msb	0x12
#define SC_transfer_count_xsb	0x13
#define SC_transfer_count_lsb	0x14
#define SC_destination_id	0x15
#define SC_source_id		0x16
#define SC_scsi_status		0x17
#define SC_command		0x18
#define SC_data			0x19

typedef struct 
{
    volatile unsigned char reg, pad[3];
} SCSIReg;

typedef struct
{
    union 
    {
	SCSIReg address;
	SCSIReg auxiliary_status;
    } rc;
    SCSIReg rd;
} SCSIChip, *SCSIChipRef;

#define SCSI_aux_status(chip)		((chip)->rc.auxiliary_status.reg)

#define SCSI_set_reg(chip,regname)	(chip)->rc.address.reg = SC_/**/regname
#define SCSI_put(chip,value)		(chip)->rd.reg = (value)
#define SCSI_get(dest,chip)		 dest = (chip)->rd.reg

#define SCSI_put_reg(chip,regname,value) { SCSI_set_reg((chip),regname); SCSI_put(chip,value); }
#define SCSI_get_reg(dest,chip,regname)  { SCSI_set_reg((chip),regname); SCSI_get(dest,chip); }

#endif				/* endif direct addressing */

#define SCSI_DEV(notused)  ((SCSIChipRef)0x31e0000)

/* SCSI Controller chip registers - what the bits in them mean */

/* Auxiliary status register */

#define SCSI_AUX_DBR	(1 << 0)	/* 01 */
#define SCSI_AUX_PE	(1 << 1)	/* 02 */

/* 2,3 reserved */

#define SCSI_AUX_CIP	(1 << 4)	/* 10 */
#define SCSI_AUX_BSY	(1 << 5)	/* 20 */
#define SCSI_AUX_LCI	(1 << 6)	/* 40 */
#define SCSI_AUX_INT	(1 << 7)	/* 80 */

/* Control register */

#define SCSI_CON_HPE	(1 << 0)	/* 01 */
#define SCSI_CON_HA	(1 << 1)	/* 02 */

/* 2..5 reserved */

#define SCSI_CON_WDB	(1 << 6)	/* 40 */
#define SCSI_CON_DMA	(1 << 7)	/* 80 */

/* Bits 7..4 define the status class */

#define SCSI_SS_COMPLETED	(1 << 4) /* 10 */
#define SCSI_SS_PAUSED		(1 << 5) /* 20     paused/aborted have the same class */
#define SCSI_SS_ABORTED		(1 << 5) /* 20                     .....              */
#define SCSI_SS_TERMINATED	(1 << 6) /* 40 */
#define SCSI_SS_SERVICE_REQ	(1 << 7) /* 80 */
#define SCSI_SS_STATUS_MASK	0xF0

/* Bit 3 defines whether bits 2.1.0 give the current SCSI-Bus
 * status as M.C.I, or are an int-class-specific code.
 */

#define SCSI_SS_MCI_BIT		(1 << 3) /* 08 */
#define SCSI_SS_MCI_MASK	0x7
#define SCSI_SS_M		(1 << 2) /* 04 */
#define SCSI_SS_C		(1 << 1) /* 02 */
#define SCSI_SS_I		(1 << 0) /* 01 */

/* Define phases on the SCSI-Bus in terms of bits 3..0 of
 * the SCSI status register
 */

#define SCSI_PHASE(m,c,i) \
  (SCSI_SS_MCI_BIT|(SCSI_SS_M*m)|(SCSI_SS_C*c)|(SCSI_SS_I*i))

#define SCSI_PH_DATA_OUT	SCSI_PHASE(0,0,0)
#define SCSI_PH_DATA_IN		SCSI_PHASE(0,0,1)
#define SCSI_PH_COMMAND		SCSI_PHASE(0,1,0)
#define SCSI_PH_STATUS		SCSI_PHASE(0,1,1)

/* phases 1,0,0 and 1,0,1 reserved */

#define SCSI_PH_MESSAGE_OUT	SCSI_PHASE(1,1,0)
#define SCSI_PH_MESSAGE_IN	SCSI_PHASE(1,1,1)

/* Now define specific values we can expect in the SCSI status */

#define SCSI_SS_Reset			0	/* unique - bits 7..4 all 0 */
#define SCSI_SS_S_A_T_Done		(SCSI_SS_COMPLETED   | 0x06) /* 16 */
#define SCSI_SS_Selection_Timeout	(SCSI_SS_TERMINATED  | 0x02) /* 42 */
#define SCSI_SS_Transfer_Disconnect	(SCSI_SS_TERMINATED  | 0x01) /* 41 */
#define SCSI_SS_Device_Disconnect	(SCSI_SS_SERVICE_REQ | 0x05) /* 85 */
#define SCSI_SS_Unexpected_Status	(SCSI_SS_TERMINATED  | SCSI_PH_STATUS) /* 4b */
#define SCSI_SS_Transfer_Message_In	(SCSI_SS_COMPLETED   | SCSI_PH_MESSAGE_IN) /* 1f */
#define SCSI_SS_Message_Paused_ACK	(SCSI_SS_PAUSED      | 0x00) /* 20 */

/* SCSI Controller commands.		
 * These occur as values of the lowest 7 bits written to
 * the command register on the chip. The top bit (bit 7)
 * is set to indicate a single byte transfer for certain
 * data-moving commands.
 */
#define SCSI_CMD_SBT	0x80	/* Single Byte Transfer */

#define SCSI_CMD_Reset					0x00
#define SCSI_CMD_Abort					0x01
#define SCSI_CMD_Assert_ATN				0x02
#define SCSI_CMD_Negate_ACK				0x03
#define SCSI_CMD_Disconnect				0x04
#define SCSI_CMD_Reselect				0x05
#define SCSI_CMD_Select_With_ATN			0x06
#define SCSI_CMD_Select_Without_ATN			0x07
#define SCSI_CMD_Select_With_ATN_And_Transfer		0x08
#define SCSI_CMD_Select_Without_ATN_And_Transfer	0x09
#define SCSI_CMD_Reselect_And_Receive_Data		0x0A
#define SCSI_CMD_Reselect_And_Send_Data			0x0B
#define SCSI_CMD_Wait_For_Select_And_Receive		0x0C

#define SCSI_CMD_Receive_Command			0x10
#define SCSI_CMD_Receive_Data				0x11
#define SCSI_CMD_Receive_Message_Out			0x12
#define SCSI_CMD_Receive_Unspecified_Info_Out		0x13
#define SCSI_CMD_Send_Status				0x14
#define SCSI_CMD_Send_Data				0x15
#define SCSI_CMD_Send_Message_In			0x16
#define SCSI_CMD_Send_Unspecified_Info_In		0x17

#define SCSI_CMD_Translate_Address			0x18

#define SCSI_CMD_Transfer_Info				0x20
#define SCSI_CMD_Transfer_Pad				0x21

/*
 * The mapping of a device number to the corresponding SCSI
 * Numbers is done as follows:
 *
 * Major number:
 *
 * This specifies the SCSI target number, with 8 entries in
 * the /dev directory to help with this. Depending upon whether
 * a character or block device is being accessed, the valid
 * ranges are:
 *            SCSI_BLOCK to SCSI_BLOCK + SCSI_NUM_DEVS
 *            SCSI_CHAR  to SCSI_CHAR  + SCSI_NUM_DEVS
 *
 * Anything outside these ranges is invalid, and will
 * cause a panic. Note that a character reference with a
 * block device number (for example) will confuse the drivers.
 *
 * Minor number:
 *
 * The minor number is used to specify the SCSI LUN and the
 * partition within the LUN. The top 4 bits of the minor device
 * number are the LUN and the bottom 4 bits the partition index.
 * For example, 0x43 is LUN 4, partition 3.
 *
 * Partition information will eventually be read from a fixed place
 * on the device dynamically when opened (note, however, this is
 * not a readyily applicable action to perform on tape devices!).
 *
 * The only valid Target IDs are in the range 0..6; 7 is reserved.
 * N.B. All SCSI controllers are implemented as
 * device 7 on their SCSI bus.  Use of target 7 is
 * therefore interpreted as an operation on the controller
 * itself, rather than a target's logical unit.  No meaning
 * is currently given to this by the driver, but there a
 * number of possibilities (e.g. ioctls on this could be
 * used to set controller options, etc).
 */

/* SCSI_UNITNO(mindev) is no longer an applicable concept; keep it
   and always check that it is zero.
*/

/* was #define SCSI_UNITNO(devnum)	(((devnum) >> 6) & 3) */

#define SCSI_UNITNO(not_used)	(0)	/* N/A concept now... */

#define SCSI_TARGETNO(devnum)	(scsi_determine_target_id(devnum))
/* If anyone wishes to replace the above with a macro, please do so! */
#define SCSI_LUNO(devnum)	(((devnum) >> 4) & 0x7)
#define SCSI_PART(devnum)	(((devnum) >> 0) & 0xf)

/* The most partitions a drive currently gets is 4, for 0/0.
 * These are referred to as 0..num_parts - 1.
 */

#define SCSI_CONTROLLER_ID	7

/* Now some items which are part of the SCSI-Bus definition proper. */

/* Command status byte define as bitfield or simple byte */

typedef union
{	unsigned char	byte;
	struct
	{ unsigned int	vu_0		:1,	/* Vendor Unique */
			code		:4,	/* code proper */
			vu_56		:2,	/* more Vendor Unique */
			reserved	:1;	/* MBZ */
	} bits;
} SCSICommandStatus;

#define STATUS_MASK 0x1e		/* mask scsi status to remove res/vu stuff */

/* Values of the code field of OpResult type field */

#define	SCSI_CS_GOOD			 (0 << 1)
#define SCSI_CS_CHECK_CONDITION		 (1 << 1)
#define SCSI_CS_CONDITION_MET		 (2 << 1)

/* 3 reserved */

#define SCSI_CS_BUSY			 (4 << 1)

/* 5-7 reserved */

#define SCSI_CS_INTERMEDIATE_G		 (8 << 1)

/* 9 reserved */

#define	SCSI_CS_INTERMEDIATE_CM_G	 (10 << 1)

/* 11 reserved */

#define SCSI_CS_RESERVATION_CONFLICT	 (12 << 1)

/* 13-15 reserved */

/* Device types (first byte of INQUIRY return data) */

#define SCSI_DEV_DA	0
#define SCSI_DEV_SEQ	1

#endif/*__dev_scsi_h*/

/* EOF scsi.h */
