#include "scsi.h"

/* Commodore */
#define BOARD_MANUFACT	514
#ifdef A2090
#define BOARD_PROCUCT	1
#endif
#ifdef A2091
#define BOARD_PROCUCT	3
#endif

/* anyone for LUN's ??? not me.... :-)) */
#define MAX_UNITS 8
#ifdef DEBUG
#define UNIT_STACKSIZE 10000
#else
/* probably too much, but better than any stack overflows:-) */
#define UNIT_STACKSIZE 4096
#endif
#define UNIT_PRIORITY 5
#ifdef A2090
#define UNIT_NAME "scsi90.device"
#endif
#ifdef A2091
#define UNIT_NAME "scsi91.device"
#endif
/*
 * when changing the number of buffers, don't exceed a total buffer size
 * of 64K, because the buffer HAS to be transmittable with one DMA job
 * (you can drop this restriction on the 2091)
 */
#define UNIT_NUM_BUFS 1
#define UNIT_SEC_SIZE 512
/* if you set this to 1, every error on a direct-access medium gets
 * you nice requestors.. (in addition to what the fs might do:-)) */
#define UNIT_MAX_ERRORS 5

/* version 37 fits kick 2.0, I like it:-)) */
#define SCSI_VERSION	37
#define SCSI_REVISION	2
#define SCSI_PRIORITY	5
#ifdef A2090
#define SCSI_NAME 	"scsi90.device"
#define SCSI_IDSTRING	"scsi90 37.2 (" ## __DATE__ ## ")\r\n"
#endif
#ifdef A2091
#define SCSI_NAME 	"scsi91.device"
#define SCSI_IDSTRING	"scsi91 37.2 (" ## __DATE__ ## ")\r\n"
#endif
#define HANDLER_PRIORITY 6
#ifdef DEBUG
#define HANDLER_STACKSIZE 10000
#else
/* same applies as with UNIT_STACKSIZE */
#define HANDLER_STACKSIZE 4096
#endif
#ifdef A2090
#define HANDLER_NAME "Handler for 2090-scsi.device"
#endif
#ifdef A2091
#define HANDLER_NAME "Handler for 2091-scsi.device"
#endif

/*
 * Define our cache management
 */
#include "cache.h"

struct scsi_unit;

struct scsi_dev {
  struct Device sc_device;
  ubyte  sc_flags;
  ubyte  sc_pad1;
  ulong  sc_seglist;
  volatile ulong sc_base; /* *DON'T* forget volatile... the optimizer needs it ! */
  struct SignalSemaphore sc_semaph; /* to block out Open during Init.. */
  struct scsi_unit *sc_units[MAX_UNITS];
  /* here comes the stuff for the handler task */
  struct Task sc_htcb;
  ubyte  sc_hstack[HANDLER_STACKSIZE];
  /* interrupt data for scsi handler */
  struct Task    *id_sig_task;
  long           id_sig_mask;
  long           id_signal;
  volatile ubyte *id_board;
  struct Interrupt sc_iv;
  /* "normal" handler data */
  struct MsgPort sc_msgport;	/* our msgport */
  struct MsgPort *sc_hmsgport;	/* handler-msgport */
  struct scsi_msg sc_hmessage;	/* a scsi_msg to send to handler */
};


struct scsi_unit {
  struct Unit scu_unit; 	/* its MsgPort is used to communicate with the handler */
  struct MsgPort *scu_cmd_mp; 	/* here arrive commands from BeginIO */
  ubyte  scu_unitnum; 		/* our number as specified in OpenDevice() */
  ubyte  scu_errors; 		/* #errors on this errorlevel (<UNIT_MAX_ERRORS) */
  ubyte  scu_errorlevel; 	/* #times, scu_errors was > UNIT_MAX_ERRORS */
  ubyte  scu_cmd[13]; 		/* scsi-cmd string, only 12 byte are used */
  struct scsi_dev *scu_device; 	/* points back to device (not used so far..) */
  ubyte  scu_stack[UNIT_STACKSIZE]; /* that's "me" .. */
  struct Task scu_tcb;
  ulong  scu_type;		/* type as got from INQUIRY, see later */
  struct scsi_msg scu_hmessage;	/* handler msg */
  struct MsgPort *scu_hmsgport;	/* handler's msgport */
  struct SCSICmd scu_scsicmd;	/* handler scsi-cmd used by read/write... */
  /* buffer part (for odd aligned data) */
  short  word_pad; /* just to make sure, the buffer is word aligned */
  ubyte  scu_buf[UNIT_NUM_BUFS * UNIT_SEC_SIZE];
  /* cache part.. looks like for typical DOS operations this is useful */
  struct cache_cb scu_ccb[CCB_PER_UNIT];
};  

/* 
 * if the medium is removable, its type is ored with the SCU_TYPE_RMB
 * qualifier 
 */
#define SCU_TYPE_RMB		(1<<31)

/*
 * the following device types correspond to the "peripheral device type"
 * field in the scsi-answer to the INQUIRY command 
 */
#define SCU_TYPE_DIRECT		0
#define SCU_TYPE_SEQUENTIAL	1
#define SCU_TYPE_PRINTER	2
#define SCU_TYPE_PROCESSOR	3
#define SCU_TYPE_WORM		4
#define SCU_TYPE_RO_DIRECT	5

/*
 * C-support for macros, that are only in asm-include files;
 * to use, declare a struct, then for each INIT used later declare the
 * respective type, the argument should be different for each invocation,
 * just increment some integer value
 */
#define DECLARE_BYTE(val) ushort foo ## val [2]; ubyte bar ## val [2]
#define DECLARE_WORD(val) ushort foo ## val [3]
#define DECLARE_LONG(val) ushort foo ## val [2]; ulong bar ## val
#define INITBYTE(off,val) 0xe000,off,(ubyte)val,0
#define INITWORD(off,val) 0xd000,off,(ushort)val
#define INITLONG(off,val) 0xc000,off,(ulong)val

#ifdef DEBUG
#define DPRINTF(args) dprintf args ;
#define DECL_DPRINTF extern void dprintf(char *fmt, ...)
#else
#define DPRINTF(args)
#define DECL_DPRINTF
#endif

/*
 * this garantees, that the sent out message has been replied to and can
 * be reused 
 */
static inline void 
PutGetMsg(struct MsgPort *to, struct MsgPort *from, struct Message *msg)
{
  struct Message *rm;
  DECL_DPRINTF;

  PutMsg(to, msg);
  while ((rm = GetMsg(from)) != msg)
	if (!rm) WaitPort(from);
	else
	  {
		DPRINTF(("PANIC: got wild message, port $%x, message $%x",
				from, rm));
		DPRINTF(("PANIC: these are the names of the ports:"));
		DPRINTF(("PANIC: to: %10.10s, from: %10.10s",
				to->mp_Node.ln_Name ? to->mp_Node.ln_Name : "(no name)",
				from->mp_Node.ln_Name ? from->mp_Node.ln_Name : "(no name)"));
		DPRINTF(("PANIC: message->replyport = $%x", rm->mn_ReplyPort));
		Wait(1<<12); /* grin.. well, doesn't matter in this case anyway.. */
	  }
}
