/* $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 */

#ident "$Header: sec.h 1.19 89/08/07 $"

#ifndef	_SYS_SEC_H_

/* $Log:	sec.h,v $
 */

/* 
 * sec.h
 *
 * This file contains the definitions of the interfaces
 * to the SCSI/Ether (SEC) firmware.
 *
 *
 * Below are the device numbers that the firmware expects for the 
 * unit channel id when a message such as STARTIO is sent. The SCSI
 * devices have a range from 0x20 (32) to 0x5f (95) with each target
 * adapter having a maximum of 8 logical units. 
 *
 *	adapter#	lun	sed_chan#
 *	0		0-7	0x20-0x27
 *	1		0-7	0x28-0x2f
 *	2		0-7	0x30-0x37
 *	3		0-7	0x38-0x3f
 *	4		0-7	0x40-0x47
 *	5		0-7	0x48-0x4f
 *	6		0-7	0x50-0x57
 *	host(7)		0-7	0x58-0x5f
 *
 * The host adapter number by default is adapter number 7 but should
 * there be more than one SEC on a single scsi bus then the adapter
 * number should be changed as the board won't work if there are more
 * than one adapter with the same bus number.
 */

#define SDEV_SCSIBOARD		0	/* The SEC itself..... */
#define SDEV_ETHERREAD		1	/* ether input channel */
#define SDEV_ETHERWRITE		2	/* ether output channel */
#define SDEV_CONSOLE0IN		3	/* console port channel input */
#define SDEV_CONSOLE0OUT	4	/* console port channel output */
#define SDEV_CONSOLE1IN		5	/* diag port channel input */
#define SDEV_CONSOLE1OUT	6	/* diag port channel output */
#define SDEV_TOD		7	/* time of day clock channel */
#define SDEV_MEM		8	/* memory channel */
#define SDEV_WATCHDOG		9	/* watch dog timer channel */

#ifdef	KERNEL_PROFILING
#define SDEV_PROFILER		10	/* SEC profiler channel */
#define SDEV_NUM_NONSCSI	11	/* last non-scsi device */
#else
#define SDEV_NUM_NONSCSI	10	/* last non-scsi device */
#endif	/* KERNEL_PROFILING  */

#define SDEV_SCSISTART		0x20	/* scsi unit number start (32) */
#define SDEV_SCSIEND		0x5f	/* scsi unit number end (95) */
#define SDEV_NUM_DEVICES	96

#define	SEC_DELAY_TIME	50000		  /* Delay time for slic stuff, etc. */

#define SEC_WDT_TIMEOUT	10	/* SCED Watchdog timer timeout value in secs */
				/* Watchdog timer reset every 1/2 second */

/*
 * Indirect address table.
 */

#ifdef	ns32000
/* 
 * Must handle case where CLBYTES > 4095 which is a h/w limit
 * on the size of an xfer count. buf_iatsz() also handles this.
 */

#if (CLBYTES>4095)
#define IATBYTES	2048
#define IATSIZE		4
#else
#define IATSIZE		CLSIZE
#define IATBYTES	CLBYTES
#endif
#endif	/* ns32000  */

#ifdef	i386
/* 
 * Ideally, IATBYTES == CLBYTES.  However, IATBYTES must be < 4096, since
 * 4095 is a hardware limit on the size of an xfer count.  buf_iatsz()
 * also handles this.  Thus take power of two below this (2048).
 */
#define IATBYTES	2048
#endif	/* i386  */

#define SEC_IAT_FLAG		0x80000000	/* indirect bit for iat ptr */
#define SEC_IATIFY(addr)	((struct sec_iat *)(((int)(addr)) | SEC_IAT_FLAG))
#define IATVARIANCE		1		/* raw - for tail garbage */

struct sec_iat {
	unchar	*iat_data;		/* pointer to data */
	int	iat_count;		/* number of bytes to put there */
};


/*
 * Maximum amount of physical memory the SCED can address.  All transfers
 * must be to physical addresses below this address.
 */

#define	MAX_SCED_ADDR_MEM	(128 * 1024 * 1024)		/* 128Meg */

/*
 * device program for all devices except ether read and clocks
 */

#define SCSI_CMD_SIZE	16		/* Max no. of bytes in a scsi command */

struct sec_dev_prog {
	unchar	dp_status1;		/* byte 1 of status */
	unchar	dp_status2;		/* byte 2 of status */
	short	dp_reserved;
	int	dp_count;		/* number of bytes transferred */
	union {
		unchar	*dp_data;	/* ptr to data */
		struct sec_iat *dp_iat;	/* ptr to indirect address table */
	} dp_un;
	struct sec_dev_prog *dp_next;	/* ptr to next dev program if linked */
	int dp_data_len;		/* total number of bytes to transfer */
	int dp_cmd_len;			/* real size of next field */
	unchar dp_cmd[SCSI_CMD_SIZE];	/* SCSI Device command */
};

/*
 * channel instruction block
 */
struct sec_cib {
	int	cib_inst;		/* instruction */
	int	*cib_status;		/* ptr to status or other structs */
};

#define	SEC_ERROR_BIN 7

/* Error Flags */
#define SEC_ERR_NONE		0
#define SEC_ERR_INVALID_INS	1
#define SEC_ERR_INVALID_DEV	2
#define SEC_ERR_NO_MORE_IO	3
#define SEC_ERR_NO_SENSE	4
#define SEC_ERR_COUNT_TOO_BIG	128
#define SEC_ERR_BAD_MODE	129

/*
 * Instructions SCSI/Ether controller.
 */
#define SINST_INSDONE		0x80000000	/* instruction complete bit */
#define SINST_INIT		0	/* Initialize instruction */
#define SINST_SETMODE		1	/* set modes instruction */
#define SINST_STARTIO		2	/* start io instruction */
#define SINST_GETMODE		3	/* get modes instruction */
#define SINST_FLUSHQUEUE	4	/* flush queue instruction */
#define SINST_RESTARTCURRENTIO	5	/* restart current inst */
#define SINST_RESTARTIO		6	/* restart instruction */
#define SINST_REQUESTSENSE	7	/* request sense inst */
#define SINST_STOPIO		8	/* stop io instruction */
#define SINST_RETTODIAG		9	/* return to diagnostics inst */
#define SINST_DIAG_REQ		10	/* special diagnostics request */

#define SCSI_ETHER_WRITE	0xA	/* SCSI first byte for write */
#define SCSI_ETHER_STATION	0x0	/* SCSI 2nd byte for station */
#define SCSI_ETHER_MULTICAST	0x1	/* SCSI 2nd byte for multicast */

/*
 * device program queue
 */

#define SEC_POWERUP_QUEUE_SIZE	3	/* Queue size at power-up */

struct sec_progq {
	uint pq_head;			/* head of list */
	uint pq_tail;			/* tail of list */
	union {
		struct sec_dev_prog *pq_progs[SEC_POWERUP_QUEUE_SIZE];
		struct sec_edev_prog {
			int	edp_iat_count;		/* no. of iat's */
			struct	sec_iat *edp_iat;	/* ptr to iat's */
		} *pq_eprogs[SEC_POWERUP_QUEUE_SIZE];
	} pq_un;
};

/*
 * ether read output queue
 */
struct sec_eprogq {
	uint	epq_head;	/* head of list */
	uint	epq_tail;	/* tail of list */
	struct sec_ether_status {
		unchar	es_status1;	/* byte 1 of status */
		unchar	es_status2;	/* byte 2 of status */
		short	es_reserved;
		int 	es_count;	/* number of bytes received */
		unchar	*es_data;	/* pointer to the first byte received */
	} epq_status[SEC_POWERUP_QUEUE_SIZE]; /* ether status blocks */
};

/*
 * SCSI Queues at power-up.
 * The address of this is passed by power-up code to the kernel
 * for auto-config of the SCSI/Ether controller.
 */
struct sec_powerup {
	struct sec_cib	pu_cib;			/* all devices */
	struct sec_progq	pu_requestq;	/* all devices but ether read */
	struct sec_progq	pu_doneq;	/* all devices but ether read */
	struct sec_progq	pu_erequestq;	/* for ether read */
	struct sec_eprogq	pu_edoneq;	/* for ether read */
};

/*
 * init channel instruction data structure (ptr to it is passed in cib status
 * pointer)
 */
struct sec_init_chan_data {
	int	sic_status;		/* status of INIT instruction */
	struct	sec_cib	*sic_cib;	/* pointer to cibs (1/device) */
	struct sec_chan_descr {
		struct sec_progq *scd_requestq;	/* pointer to input queue */
		struct sec_progq *scd_doneq;	/* pointer to output queue */
		unchar	scd_bin;		/* bin to interrupt Unix on */
		unchar	scd_vector;		/* interrupt vector to return */
		unchar	scd_destslic;		/* Interrupt destination */
	} sic_chans[SDEV_NUM_DEVICES];	/* channel descriptors (1/device) */
};

/*
 * Diagnostic request.
 * A pointer to this is passed in the cib_status
 * when the cib_inst is SINST_DIAG_REQ.
 *
 * For SDR_CACHE_OFF and SDR_CACHE_ON, sdr_slic is the SLIC id
 * of the thing that needs its cache turned on or off.  This is
 * done with the processor held (via its PROC_CTL register),
 * if it is a processor.
 *
 * SDR_MEM_CHANGED has no arguments.
 *
 * SDR_WRSUBSLAVE writes the SLIC sub-slave register at SLIC
 * address sdr_slic, slave register sdr_s_slave and subslave
 * address sdr_s_subslave with the data in sdr_s_data.
 * This is intended primarily for use with SGS processor
 * boards, so it forces a bus PAUSE, then holds the
 * processor (and its neighbor) before doing the wrSubslave().
 * The VLSI wanted to assume these settings were static...
 */
struct sec_diag_req {
	int	sdr_status;		/* status from this cmd */
	unchar	sdr_cmd;		/* command for SCED to execute */
	unchar	sdr_slic;		/* SLIC target operand for some cmds */
	unchar	sdr_compad[2];		/* common data pad */
	union sdr_un {			/* command-specific fields: */
		struct sdru_slave {
			unchar	sdrus_slave;	/* SLIC slave address */
			unchar	sdrus_subslave;	/* SLIC sub-slave addr (opt) */
			unchar	sdrus_data;	/* SLIC data for write */
		}	sdru_slave;	/* slave command for SCED to execute */
		ulong	sdru_pad[10];	/* lots of padding for cmd-specifics */
	} sdr_un;
};

/*
 * Values for sdr_cmd.
 */
#define SDR_CACHE_OFF	0x00		/* turn cache off for someone */
#define SDR_CACHE_ON	0x01		/* turn cache on for someone */
#define SDR_MEM_CHANGED	0x02		/* notice that memory config changed */
#define SDR_WRSUBSLAVE	0x03		/* write a SLIC sub-slave register */

/*
 * Make union entries easy to get to.
 */
#define sdr_s_slave	sdr_un.sdru_slave.sdrus_slave
#define sdr_s_subslave	sdr_un.sdru_slave.sdrus_subslave
#define sdr_s_data	sdr_un.sdru_slave.sdrus_data
#define sdr_pad	sdr_un.sdru_pad


#ifdef	KERNEL_PROFILING

struct pc_mode {
	unsigned int pm_pc;
	unsigned int pm_mode;	/* usermode != 0, kernel mode = 0 */
};

/*
 * profiling get and set mode structure
 * used for communication with the profiler pseudo device on a SCED
 */
struct kp_modes {
	int kpm_interval;	/* SCED timer interrupt interval in ms */
	int kpm_reload;		/* SCED sends NMI every reload timer intrs */
	unsigned long kpm_sced_nmis;/* Number of nmi's sent by fw */
	int kpm_state;		/* state of profiling */
	int kpm_binshift;	/* Log2(Size in bytes of a bin) */
	int kpm_bins;		/* Number of bins used in profiling */
	int kpm_engines;	/* Number of engines to profile */
	unsigned kpm_b_text;	/* addr of 1st text symbol */
	struct pc_mode *kpm_pc;	/* addr of pc/psr pairs for processors */
				/* addr in main mem: passed in from driver */
	unsigned long *kpm_cntrs;/* address of the profiling cntrs */
				/* addr in main mem: passed in from driver */
};
#endif	/* KERNEL_PROFILING  */


/*
 * request sense structure.  ptr goes in channel status ptr.
 */
struct sec_req_sense {
	int	rs_status;
	struct sec_dev_prog rs_dev_prog;	/* device program to run for sense command */
};

/* SCSI Sense Info */
#define SSENSE_CHECK		2
#define SSENSE_INTSTAT		16
#define SSENSE_MOREINFO		0x80
#define SSENSE_HOST_ERR		1
#define SSENSE_NOTREADY		1

/*
 * SCSI bus device probe routine responses
 */

#define SECP_NOTFOUND		0x1		/* no good unit here */
#define SECP_NOTARGET		0x2		/* no good target here */
#define SECP_FOUND		0x4		/* multi-unit target found */
#define SECP_ONELUN		0x8		/* single-unit target found */

/* probe structure for backwards compatibility */
struct	sec_probe {
	struct	sec_desc	*secp_desc;	/* SEC controller descriptor */
	struct	sec_powerup	*secp_puq;	/* command/status queues */
	short			secp_target;	/* target number */
	short			secp_unit;	/* unit number */
	unchar			secp_chan;	/* channel # to interrupt */
	ulong			secp_flags;	/* copy of sec_flags */
};

/*
 * After probing, driver boot procedure is called with a pointer to an
 * array of these.  With conversion to init, this structure has been retained
 * within sec_device for backwards compatibilty of the drivers
 */

struct	sec_dev {
	ulong			sd_flags;	/* flags (arbitrary) */
	unchar			sd_bin;		/* interrupt bin number */
	short			sd_req_size;	/* size of the request queue */
	short			sd_doneq_size;	/* size of the done queue */
/*
 * The remaining fields are filled in when the configure() routine runs.
 * sd_vector of first sec_dev in a set defines "base" vector.
 */
	short			sd_sec_idx;	/* sec index; -1 == wildcard */
	short			sd_target;	/* target number */
	short			sd_unit;	/* unit number */
	struct	sec_desc	*sd_desc;	/* host ctrler descriptor */
	unchar			sd_chan;	/* channel # to interrupt */
	unchar			sd_vector;	/* assigned interrupt vector */
	unchar			sd_destslic;	/* id/group id to interrupt */
	unchar			sd_alive;	/* is the device alive? */
	struct sec_cib		*sd_cib;	/* device info cib */
	struct sec_progq	*sd_requestq;	/* device input q location */
	struct sec_progq	*sd_doneq;	/* device output q location */
};

/*
 * One of these exists per active SCSI/Ether Controller.
 */
struct sec_desc {
	uint			sec_diag_flags;	    /* flags from powerup */
	short			sec_target_no;      /* host adapter target # */
	unchar			sec_slicaddr;       /* slic address of SEC */
	unchar			sec_ether_addr[6];  /* ether address */
	unchar			sec_is_cons;        /* is this the console? */
	struct sec_powerup	*sec_powerup;       /* powerup queues */
	ushort			sec_version;        /* firmware version */
};

#ifdef INKERNEL
extern	struct	sec_desc	*SEC_desc;   /* array alloc'd by conf_scsi */
extern	int	NSEC;			     /* # SEC's to map at boot */
extern	uint	SECvec;			     /* bit-vector of existing SEC's */

#endif /* INKERNEL */

#define	_SYS_SEC_H_
#endif	/* _SYS_SEC_H_ */
