/* 
 * Mach Operating System
 * Copyright (c) 1993-1989 Carnegie Mellon University
 * All Rights Reserved.
 * 
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 * 
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 * 
 * Carnegie Mellon requests users of this software to return to
 * 
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 * 
 * any improvements or extensions that they make and grant Carnegie Mellon
 * the rights to redistribute these changes.
 */
/*
 *	File: scsi_defs.h
 * 	Author: Alessandro Forin, Carnegie Mellon University
 *	Date:	9/90
 *
 *	Controller-independent definitions for the SCSI driver
 */

#ifndef	_SCSI_SCSI_DEFS_H_
#define	_SCSI_SCSI_DEFS_H_

#include <kern/queue.h>
#include <kern/lock.h>

#include <rz_labels.h>

#define	await(event)	sleep(event,0)
extern	void wakeup();

typedef	vm_offset_t	opaque_t;	/* should be elsewhere */

/*
 * Internal error codes, and return values
 * XXX use the mach/error.h scheme XXX
 */
typedef unsigned int		scsi_ret_t;

#define	SCSI_ERR_GRAVITY(x)	((unsigned)(x)&0xf0000000U)
#define	SCSI_ERR_GRAVE		0x80000000U
#define SCSI_ERR_BAD		0x40000000

#define	SCSI_ERR_CLASS(x)	((unsigned)(x)&0x0fffffffU)
#define	SCSI_ERR_STATUS		0x00000001
#define	SCSI_ERR_SENSE		0x00000002
#define SCSI_ERR_MSEL		0x00000004

extern	void	scsi_error(/* target_info_t *, unsigned, unsigned */);

#define	SCSI_RET_IN_PROGRESS	0x00
#define	SCSI_RET_SUCCESS	0x01
#define	SCSI_RET_RETRY		0x02
#define SCSI_RET_NEED_SENSE	0x04
#define SCSI_RET_ABORTED	0x08
#define	SCSI_RET_DEVICE_DOWN	0x10

/*
 * Device-specific information kept by driver
 */
#define MAX_SCSI_PARTS 32	/* maximum partitions on a disk;can be larger */
typedef struct {
	struct disklabel	l;  /* NOT accurate. partitions stored below */
	struct {
	    unsigned int	badblockno;
	    unsigned int	save_rec;
	    char		*save_addr;
	    int			save_count;
	    int			save_resid;
	    int			retry_count;
	} b;
#if 0 /* no longer used by partition code */
	int			labelsector;
	int			labeloffset;
#endif 0
	struct diskpart scsi_array[MAX_SCSI_PARTS]; /* new partition info */
} scsi_disk_info_t;

typedef struct {
	boolean_t	read_only;
	unsigned int	speed;
	unsigned int	density;
	unsigned int	maxreclen;
	boolean_t	fixed_size;
} scsi_tape_info_t;

typedef struct {
	char		req_pending;
	char		req_id;
	char		req_lun;
	char		req_cmd;
	unsigned int	req_len;
	/* more later */
} scsi_processor_info_t;

typedef struct {
	void		*result;
	boolean_t	result_available;
	int		result_size;
	struct red_list	*violates_standards;
} scsi_cdrom_info_t;

typedef struct {
#	define SCSI_MAX_COMM_TTYS	16
	struct tty	*tty[SCSI_MAX_COMM_TTYS];
	io_req_t	ior;
} scsi_comm_info_t;

/*
 * Device descriptor
 */

#define	SCSI_TARGET_NAME_LEN	8+16+4+8	/* our way to keep it */

typedef struct target_info {
	queue_chain_t	links;			/* to queue for bus */
	io_req_t	ior;			/* what we are doing */

	unsigned int	flags;
#define	TGT_DID_SYNCH		0x00000001	/* finished the synch neg */
#define	TGT_TRY_SYNCH		0x00000002	/* do the synch negotiation */
#define	TGT_FULLY_PROBED	0x00000004	/* can sleep to wait */
#define	TGT_ONLINE		0x00000008	/* did the once-only stuff */
#define	TGT_ALIVE		0x00000010
#define	TGT_BBR_ACTIVE		0x00000020	/* bad block replc in progress */
#define	TGT_DISCONNECTED	0x00000040	/* waiting for reconnect */
#define	TGT_WRITTEN_TO		0x00000080	/* tapes: needs a filemark on close */
#define	TGT_REWIND_ON_CLOSE	0x00000100	/* tapes: rewind */
#define	TGT_BIG			0x00000200	/* disks: > 1Gb, use long R/W */
#define	TGT_REMOVABLE_MEDIA	0x00000400	/* e.g. floppy, cd-rom,.. */
#define	TGT_READONLY		0x00000800	/* cd-rom, scanner, .. */
#define	TGT_OPTIONAL_CMD	0x00001000	/* optional cmd, ignore errors */
#define TGT_WRITE_LABEL		0x00002000	/* disks: enable overwriting of label */
#define	TGT_US			0x00004000	/* our desc, when target role */

#define	TGT_HW_SPECIFIC_BITS	0xffff0000U	/* see specific HBA */
	char		*hw_state;		/* opaque */
	char		*dma_ptr;
	char		*cmd_ptr;
	struct scsi_devsw_struct	*dev_ops;	/* circularity */
	struct target_info	*next_lun;	/* if multi-LUN */
	char		target_id;
	char		unit_no;
	unsigned char	sync_period;
	unsigned char	sync_offset;
	decl_simple_lock_data(,target_lock)
#ifdef	MACH_KERNEL
#else	/*MACH_KERNEL*/
	struct fdma	fdma;
#endif	/*MACH_KERNEL*/
	/*
	 * State info kept while waiting to seize bus, either for first
	 * selection or while in disconnected state
	 */
	struct {
	    struct script	*script;
	    int			(*handler)();
	    unsigned int	out_count;
	    unsigned int	in_count;
	    unsigned int	copy_count;	/* optional */
	    unsigned int	dma_offset;
	    unsigned char	identify;
	    unsigned char	cmd_count;
	    unsigned char	hba_dep[2];
	} transient_state;
	unsigned int	block_size;
	volatile char	done;
	unsigned char	cur_cmd;
	unsigned char	lun;
	char		masterno;
	char		tgt_name[SCSI_TARGET_NAME_LEN];
	union {
	    scsi_disk_info_t	disk;
	    scsi_tape_info_t	tape;
	    scsi_cdrom_info_t	cdrom;
	    scsi_processor_info_t	cpu;
	    scsi_comm_info_t	comm;
	} dev_info;
} target_info_t;


/*
 * Device-specific operations
 */
typedef struct scsi_devsw_struct {
	char		*(*driver_name)(boolean_t);	  /* my driver's name */
	void		(*optimize)(target_info_t *);	  /* tune up internal params */
	scsi_ret_t	(*open)(target_info_t *,io_req_t);/* open time ops */
	scsi_ret_t	(*close)(target_info_t *);	  /* close time ops */
	int		(*strategy)(io_req_t);	          /* sort/start routine */
	void		(*restart)(target_info_t *,
				   boolean_t);		  /* completion routine */
	io_return_t	(*get_status)(int, 
				      target_info_t *,
				      dev_flavor_t,
				      dev_status_t,
				      natural_t *);	  /* specialization */
	io_return_t	(*set_status)(int, 
				      target_info_t *,
				      dev_flavor_t,
				      dev_status_t,
				      natural_t);	  /* specialization */
} scsi_devsw_t;

#define SCSI_OPTIMIZE_NULL ((void (*)(target_info_t *)) 0)
#define SCSI_OPEN_NULL ((scsi_ret_t (*)(target_info_t *,io_req_t)) 0)
#define SCSI_CLOSE_NULL ((scsi_ret_t (*)(target_info_t *)) 0)

extern scsi_devsw_t	scsi_devsw[];

/*
 * HBA descriptor
 */

typedef struct {
	/* initiator (us) state */
	unsigned char	initiator_id;
	unsigned char	masterno;
	unsigned int	max_dma_data;
	char		*hw_state;		/* opaque */
	int		(*go)();
	void		(*watchdog)();
	boolean_t	(*probe)();
	/* per-target state */
	target_info_t		*target[8];
} scsi_softc_t;

extern scsi_softc_t	*scsi_softc[];
extern scsi_softc_t	*scsi_master_alloc(/* int unit */);
extern target_info_t	*scsi_slave_alloc(/* int unit, int slave, char *hw */);

#define	BGET(d,mid,id)	(d[mid] & (1 << id))		/* bitmap ops */
#define BSET(d,mid,id)	d[mid] |= (1 << id)
#define BCLR(d,mid,id)	d[mid] &= ~(1 << id)

extern unsigned char	scsi_no_synchronous_xfer[];	/* one bitmap per ctlr */
extern unsigned char	scsi_use_long_form[];		/* one bitmap per ctlr */
extern unsigned char	scsi_might_disconnect[];	/* one bitmap per ctlr */
extern unsigned char	scsi_should_disconnect[];	/* one bitmap per ctlr */
extern unsigned char	scsi_initiator_id[];		/* one id per ctlr */

extern boolean_t	scsi_exabyte_filemarks;
extern boolean_t	scsi_no_automatic_bbr;
extern int		scsi_bbr_retries;
extern int		scsi_watchdog_period;
extern int		scsi_delay_after_reset;
extern unsigned int	scsi_per_target_virtual;	/* 2.5 only */

extern int		scsi_debug;

/*
 * HBA-independent Watchdog
 */
typedef struct {

	unsigned short	reset_count;
	char		nactive;

	char		watchdog_state;

#define SCSI_WD_INACTIVE	0
#define	SCSI_WD_ACTIVE		1
#define SCSI_WD_EXPIRED		2

	int		(*reset)();

} watchdog_t;

extern void scsi_watchdog( watchdog_t* );

#endif	_SCSI_SCSI_DEFS_H_