Logo Search packages:      
Sourcecode: faumachine version File versions  Download package

chip_lsi_53C810.c

/*
 * $Id: chip_lsi_53C810.c,v 1.167 2009-01-28 12:59:19 potyra Exp $
 *
 * Copyright (C) 2003-2009 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

#include "config.h"

#include <assert.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "pci.h" /* Should go away - FIXME */
#include "glue-log.h"
#include "glue-main.h"
#include "glue-shm.h"

#include "chip_lsi_53C810.h"

#define COMP "chip_lsi_53C810"

/* Debugging stuff */
#define WARNINGS 0x0

#define SIZE_IO_BUF 4096

#if 0
#define DEBUGMASK 0x03fb /* all except SCRIPTS_ATOMIC */
#else
#define DEBUGMASK 0
#endif

/* Add the following values together to select which debug messages you want */
#define DEBUG_CONFSPACE       0x0001
#define DEBUG_SCRIPTS         0x0002
#define DEBUG_SCRIPTS_ATOMIC  0x0004
#define DEBUG_IO        0x0008
#define DEBUG_IRQ       0x0010
#define DEBUG_TIMER           0x0020
#define DEBUG_SCSI            0x0040
#define DEBUG_SCSIBUS         0x0080
#define DEBUG_SCSIBUS_BLOCK   0x0100
#define DEBUG_OTHER           0x0200

/*how deep can ints be stacked... */
#define INT_QUEUE_DEPTH 5

/* SCSI bus phases... */
#define SCSI_PHASE_DATA_OUT   0x00
#define SCSI_PHASE_DATA_IN    0x01
#define SCSI_PHASE_COMMAND    0x02
#define SCSI_PHASE_STATUS     0x03
#define SCSI_PHASE_MESSAGE_OUT      0x06
#define SCSI_PHASE_MESSAGE_IN 0x07
#define SCSI_PHASE_BUSFREE    0x08

/* register-space in mapped-memory */
#define SZ_53C810MEM    0x60
#define SZ_53CROMREQUEST (64*1024)
#define SZ_53CBOOTROM (64*1024)

#define REVISION  1

struct cpssp {
      /* 32-bit-wide */
      uint32_t config_space[64];

      /* boot-rom */
      uint8_t bootrom[SZ_53CBOOTROM];

      /* Signals */
      struct sig_pci_bus_main *port_pci_bus;
      struct sig_scsi_bus *port_scsi_bus;
      struct sig_boolean_or *port_intA;
      unsigned int state_power;

      /* State */
      uint32_t scripts_counter;
      uint32_t pc_restart;
      unsigned long backup_i_counter;
      uint8_t SCSI_phase;
      uint8_t cardregs[96];
      uint8_t scsi_io_buf[SIZE_IO_BUF + 1];
      uint8_t int_queue_sist0[INT_QUEUE_DEPTH];
      uint8_t int_queue_sist1[INT_QUEUE_DEPTH];
      uint8_t int_queue_dstat[INT_QUEUE_DEPTH];
      uint8_t int_sist0_depth;
      uint8_t int_sist1_depth;
      uint8_t int_dstat_depth;
      bool scripts_running;
      bool ALU_CARRYBIT;
      bool int_active;
      bool abort_wait_reselect;
      bool abort_wait_phasecomp;
      bool delayed_transfer;
      bool pending_transfer;
      bool SCSI_phase_change;
      bool backup_phase_status;

      /* the controller has started a transaction as an initiator */
      bool SCSI_initiated;

      /* the SCSI-status of the controller */
      bool SCSI_selected;
      bool SCSI_reselected;
      bool SCSI_unserviced;

      /*In case the target wnaat to transfer data: */
      unsigned long SCSI_data_to_target;
      unsigned long SCSI_data_from_target;

      /* Timer-clocks */
      unsigned long long timertick_h2h;
      unsigned long long timertick_sel;
      unsigned long long timertick_gen;

      /* Timer-settings */
      unsigned long long timerset_h2h;
      unsigned long long timerset_sel;
      unsigned long long timerset_gen;
};


/* happy little makros for peaceful castings */
#define LONGCARDREG(cpssp,reg)      ((uint32_t *)&cpssp->cardregs[reg])
#define SHORTCARDREG(cpssp,reg)     ((uint16_t *)&cpssp->cardregs[reg])
#define CHARCARDREG(cpssp,reg)      ((uint8_t *)&cpssp->cardregs[reg])

#define LSI53C810MEMADDR(cpssp) \
      ((uint32_t)(cpssp->config_space[PCI_BASE_ADDRESS_1>>2] \
       & PCI_BASE_ADDRESS_MEM_MASK))

#define LSI53C810IOADDR(cpssp) \
      ((uint16_t)((cpssp->config_space[PCI_BASE_ADDRESS_0>>2] \
       & PCI_BASE_ADDRESS_IO_MASK)&0x0000ffff))


#define LSI53C810ROMADDR(cpssp) \
      ((uint32_t)(cpssp->config_space[PCI_ROM_ADDRESS>>2] \
      & PCI_ROM_ADDRESS_MASK))

/* Debugging */
#if (DEBUGMASK > 0)
#define TRACE(lvl, fmt, arg...) \
      if ((lvl & DEBUGMASK)) { \
            char tmplog[2]; \
            tmplog[0] = '-'; \
            tmplog[1] = 0; \
            faum_log(FAUM_LOG_DEBUG, COMP, \
             tmplog, "[ %04x  ] " fmt , \
             lvl, arg); \
      }
#else
#define TRACE(lvl, fmt, arg...) while(0) { } /* ; */
#endif /* DEBUGMASK > 0 */

/* Update-Interval of timer */
#define TIMERTICKS (TIME_HZ / 100) /* 10ms */

/* astimated time of a single SCRIPTS-Instruction */
#define SCRIPTS_TIMERTICKS (TIME_HZ / 200000) /* 5us */

/* timer interval for requeueing SCRIPS */
#define TSYNC_INTERVAL_SCRIPTS  (TIME_HZ / 20000) /* 50us*/

/* timer for reselect-wait */
/* This is the interval the controller
 * gets called in idle state to check for reselection */
#define TSYNC_INTERVAL_RESELECT  (TIME_HZ / 200) /*5ms*/

/* minimum timer Interval (125 microseconds) */
#define TIMER_BASE_INTERVAL  (TIME_HZ / 8000) /* 125us */

/* max. number of SCSI-SCRIPTS instructions executed at once */
#define MAX_SCRIPTS_EXE 1000

static const char * const reg_names[] = {
      "SCNTL0", "SCNTL1", "SCNTL2", "SCNTL3",
      "SCID", "SXFER", "SDID", "GPREG",
      "SFBR", "SOC", "SSID", "SBCL",
      "DSTAT", "SSTAT0", "SSTAT1", "SSTAT2",
      "DSA[0]", "DSA[1]", "DSA[2]", "DSA[3]",
      "ISTAT", "RESERVED", "RESERVED", "RESERVED",
      "RESERVED", "CTEST1", "CTEST2", "CTEST3",
      "TEMP[0]", "TEMP[1]", "TEMP[2]", "TEMP[3]",
      "DFIFO", "CTEST4", "CTEST5", "CTEST6",
      "DBC[0]", "DBC[1]", "DBC[2]", "DCMD",
      "DNAD[0]", "DNAD[1]", "DNAD[2]", "DNAD[3]",
      "DSP[0]", "DSP[1]", "DSP[2]", "DSP[3]",
      "DSPS[0]", "DSPS[1]", "DSPS[2]", "DSPS[3]",
      "SCRATCH_A[0]", "SCRATCH_A[1]", "SCRATCH_A[2]", "SCRATCH_A[3]",
      "DMODE", "DIEN", "SBR", "DCNTL",
      "ADDER[0]", "ADDER[1]", "ADDER[2]", "ADDER[3]",
      "SIEN0", "SIEN1", "SIST0", "SIST1",
      "SLPAR", "RESERVED", "MACNTL", "GPCNTL",
      "STIME0", "STIME1", "RESPID", "RESERVED",
      "STEST0", "STEST1", "STEST2", "STEST3",
      "SIDL", "RESERVED", "RESERVED", "RESERVED",
      "SODL", "RESERVED", "RESERVED", "RESERVED",
      "SBDL", "RESERVED", "RESERVED", "RESERVED",
      "SCRATCH_B[0]", "SCRATCH_B[1]", "SCRATCH_B[2]", "SCRATCH_B[3]"
};

/* some important bits... */
#define ISTAT_DIP 0x01
#define ISTAT_SIP 0x02
#define ISTAT_INTF 0x04

/*Card registers (offsets)*/
#define REG_SCNTL0 0x00
#define REG_SCNTL1 0x01
#define REG_SCNTL2 0x02
#define REG_SCNTL3 0x03

#define REG_SCID 0x04
#define REG_SXFER 0x05
#define REG_SDID 0x06
#define REG_GPREG 0x07

#define REG_SFBR 0x08
#define REG_SOCL 0x09
#define REG_SSID 0x0a
#define REG_SBCL 0x0b

#define REG_DSTAT 0x0c
#define REG_SSTAT0 0x0d
#define REG_SSTAT1 0x0e
#define REG_SSTAT2 0x0f

#define REG_DSA 0x10

#define REG_ISTAT 0x14
#define REG_RESERVED_1 0x15
#define REG_RESERVED_2 0x16
#define REG_RESERVED_3 0x17

#define REG_RESERVED_4 0x18
#define REG_CTEST1 0x19
#define REG_CTEST2 0x1a
#define REG_CTEST3 0x1b

#define REG_TEMP 0x1c

#define REG_DFIFO 0x20
#define REG_CTEST4 0x21
#define REG_CTEST5 0x22
#define REG_CTEST6 0x23

#define REG_DBC 0x24
#define REG_DCMD 0x27

#define REG_DNAD 0x28

#define REG_DSP 0x2c

#define REG_DSPS 0x30

#define REG_SCRATCH_A 0x34

#define REG_DMODE 0x38
#define REG_DIEN 0x39
#define REG_SBR 0x3a
#define REG_DCNTL 0x3b

#define REG_ADDER 0x3c

#define REG_SIEN0 0x40
#define REG_SIEN1 0x41
#define REG_SIST0 0x42
#define REG_SIST1 0x43

#define REG_SLPAR 0x44
#define REG_RESERVED_5 0x45
#define REG_MACNTL 0x46
#define REG_GPCNTL 0x47

#define REG_STIME0 0x48
#define REG_STIME1 0x49
#define REG_RESPID 0x4a
#define REG_RESERVED_6 0x4b

#define REG_STEST0 0x4c
#define REG_STEST1 0x4d
#define REG_STEST2 0x4e
#define REG_STEST3 0x4f

#define REG_SIDL 0x50
#define REG_RESERVED_7 0x51
#define REG_RESERVED_8 0x52
#define REG_RESERVED_9 0x53

#define REG_SODL 0x54
#define REG_RESERVED_10 0x55
#define REG_RESERVED_11 0x56
#define REG_RESERVED_12 0x57

#define REG_SBDL 0x58
#define REG_RESERVED_13 0x59
#define REG_RESERVED_14 0x5a
#define REG_RESERVED_15 0x5b

#define REG_SCRATCH_B 0x5c


/* forward declaration... */
static void
lsi_readb(struct cpssp *cpssp, uint16_t port, uint8_t *valp);
static void
lsi_writeb(struct cpssp *cpssp, uint16_t port, uint8_t val);
static void
chip_lsi_53C810_start_SCRIPTS(struct cpssp *cpssp);


/* do something on timer_event, i.e. continue SCRIPT operation */
static void
timer_event(void *_cpssp)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;

      TRACE(DEBUG_TIMER, "*** TIMER EVENT! %0x \n", 0);

      /* just restart SCRIPTS: It will reschedule itself again if needed...*/
      if (cpssp->scripts_running) {
            TRACE(DEBUG_TIMER, "***** RESTARTING SCRIPTS... %0x \n\n", 0);
            chip_lsi_53C810_start_SCRIPTS(cpssp);
      } else {
            TRACE(DEBUG_TIMER, "***** NO NEED TO RESTART SCRIPTS  %0x\n\n",
                                                      0);
      }
}

/* int_trigger:
 * Asserts IRQ-Line depending on DCNTL and the bits in
 * the interrupt-mask-registers.
 * Called for example after int_add and int_del */
static void
chip_lsi_int_trigger(struct cpssp *cpssp)
{
      /* Remember: All interrupts indicated in the ISTAT-register
       * are fatal anyway!
       * We are NOT dealing with non-fatal ints here any more!
       * Non-fatal ints are _always_ masked ints, but not every masked
       * int will be non-fatal :) (but int_add handles this)
       *
       * Onliest Exception: Interrupt-on-the-fly in SCRIPTS is
       * always non-fatal (but cannot be stacked or masked, so this
       * is not a big problem...) */


      /* easy one:
       * if DCNTL blocks the INT-line, then there will never be an Interrupt...*/
      if (cpssp->cardregs[REG_DCNTL] & 0x02) {
            TRACE(DEBUG_IRQ, "DCNTL BLOCKED! NO INTERRUPT WILL BE TRIGGERED! %0x \n", 0);
            sig_boolean_or_set(cpssp->port_intA, cpssp, 0);
            return;
      }

      /* This is also easy and the standard-case:
       * No (more) interrupt is pending, so there is no need for int (any more)*/
      if ((cpssp->cardregs[REG_ISTAT] & (ISTAT_DIP | ISTAT_SIP | ISTAT_INTF)) == 0){
            TRACE(DEBUG_IRQ, "ALL INT-conditions cleared! Deasserting INT-line! %0x \n", 0);
            sig_boolean_or_set(cpssp->port_intA, cpssp, 0);
            return;
      }

      /* Was there an Interrupt-on-the-fly?
       * if so, INT has to be asserted in any case*/
      if (cpssp->cardregs[REG_ISTAT] & ISTAT_INTF){
            TRACE(DEBUG_IRQ, "Asserting INT-line: INTFLY %0x \n", 0);
            sig_boolean_or_set(cpssp->port_intA, cpssp, 1);
            /*reset STD-bit */
            cpssp->cardregs[REG_DCNTL]&=~0x04;
            return;
      }

      /* Was there at least a DMA type interrupt? */
      if (cpssp->cardregs[REG_ISTAT] & ISTAT_DIP) {
            TRACE(DEBUG_IRQ, "DMA-type INT: %0x \n",
                        cpssp->cardregs[REG_DSTAT]);
#if 0
                  &&
            (cpssp->cardregs[REG_DSTAT] & cpssp->cardregs[REG_DIEN])){
#endif
            /* not masked? */
            if (cpssp->cardregs[REG_DSTAT] & cpssp->cardregs[REG_DIEN]) {
                  TRACE(DEBUG_IRQ, "Asserting INT-line: DMA-type INT: %0x \n",
                        cpssp->cardregs[REG_DSTAT]);
                  sig_boolean_or_set(cpssp->port_intA, cpssp, 1);
                  return;
            }  else {
                  TRACE(DEBUG_IRQ, "MASKED, not asserting int...: %0x \n",
                        cpssp->cardregs[REG_DSTAT]);

            }
            /*reset STD-bit */
            cpssp->cardregs[REG_DCNTL]&=~0x04;
      }

      /* Ok, now was there a SCSI-type interrupt? */
      if (cpssp->cardregs[REG_ISTAT] & ISTAT_SIP){
            /* And again: was it masked or not? */
            if (cpssp->cardregs[REG_SIST0] & cpssp->cardregs[REG_SIEN0]) {
                  TRACE(DEBUG_IRQ, "Asserting INT-line: SCSI-type(0) INT: %0x \n",
                              cpssp->cardregs[REG_SIST0]);
                  sig_boolean_or_set(cpssp->port_intA, cpssp, 1);
                  /*reset STD-bit */
                  cpssp->cardregs[REG_DCNTL]&=~0x04;
                  return;
            } else {
                  TRACE(DEBUG_IRQ, "MASKED in SIST0, not asserting int...: %0x \n",
                        cpssp->cardregs[REG_DSTAT]);
            }

            /* the same for SIST1: */
            if (cpssp->cardregs[REG_SIST1] & cpssp->cardregs[REG_SIEN1]) {
                  TRACE(DEBUG_IRQ, "Asserting INT-line: SCSI-type(1) INT: %0x \n",
                              cpssp->cardregs[REG_SIST1]);
                  sig_boolean_or_set(cpssp->port_intA, cpssp, 1);
                  /*reset STD-bit */
                  cpssp->cardregs[REG_DCNTL]&=~0x04;
                  return;
            } else {
                  TRACE(DEBUG_IRQ, "MASKED in SIST1, not asserting int...: %0x \n",
                        cpssp->cardregs[REG_DSTAT]);
            }
      }

      TRACE(DEBUG_IRQ, "EVERY POTENTIAL INTERRUPT WAS MASKED! %0x \n", 0);
      return;

}

/*
 * int_add:
 * Enqueues (stackable) interrupt-requests in the corresponding
 * register-queues:
 * Checks masking-bits in SIEN0, SIEN1, DIEN:
 * Note: Queueing only for non-masked and masked/fatal ints!
 */
static void
chip_lsi_int_add(struct cpssp *cpssp, uint8_t reg, uint8_t bits)
{

      switch(reg){
      case REG_ISTAT:
            assert(bits == ISTAT_INTF);

            TRACE(DEBUG_IRQ, "Setting ISTAT-int-on-fly: %0x\n", bits);

            cpssp->cardregs[REG_ISTAT] |= ISTAT_INTF;
            break;

      case REG_DSTAT:
            /*
             * DMA-type interrupts are simpler:
             * They are considered fatal in every case!
             */
            /* Queue sanity check */
            assert(cpssp->int_dstat_depth < INT_QUEUE_DEPTH);

            /*
             * Is there already a pending DMA-type-interrupt (DIP-bit=1)?
             */
            if (cpssp->cardregs[REG_ISTAT] & ISTAT_DIP) {
                  /* We have to queue this one for now... */
                  TRACE(DEBUG_IRQ, "Queueing DSTAT-condition, Istat = %0x\n", cpssp->cardregs[REG_ISTAT]);

                  cpssp->int_queue_dstat[cpssp->int_dstat_depth] = bits;
                  cpssp->int_dstat_depth++;

            } else {
                  /*
                   * ...otherwise we just set the corresponding bits
                   * in DSTAT and indicate our INT-condition in
                   * ISTAT by setting the DIP-bit to "1"
                   */
                  TRACE(DEBUG_IRQ, "Setting DSTAT-int: %0x\n", bits);
                  cpssp->cardregs[REG_DSTAT] |= bits;
                  cpssp->cardregs[REG_ISTAT] |= ISTAT_DIP;
            }

            /* These ints are always fatal -> stop SCRIPTS. */
            cpssp->scripts_running = false;
            break;

      case REG_SIST0:
            /* Queue sanity check */
            assert(cpssp->int_sist0_depth < INT_QUEUE_DEPTH);

            /*
             * TODO: catch masked non-fatal ints here: these will
             * set bits directly in SIST0, but will not trigger
             * further actions and will not stop SCRIPTS!
             * (--> not setting the SIP-bit in ISTAT)
             */

            /*
             * Is there already a pending SCSI-type-interrupt (SIP-bit=1)?
             */
            if (cpssp->cardregs[REG_ISTAT] & ISTAT_SIP) {
                  /* We have to queue this one for now... */
                  TRACE(DEBUG_IRQ, "Queueing SIST0-condition %0x\n", bits);
                  cpssp->int_queue_sist0[cpssp->int_sist0_depth] = bits;
                  cpssp->int_sist0_depth++;

            } else {
                  /*
                   * ...otherwise just set the corresponding bits
                   * in SIST0 and indicate our INT-condition in
                   * ISTAT (SIP-bit)!
                   */
                  TRACE(DEBUG_IRQ, "Setting SIST0-int: %0x\n", bits);
                  cpssp->cardregs[REG_SIST0] |= bits;
                  cpssp->cardregs[REG_ISTAT] |= ISTAT_SIP;
            }

            /*
             * INTs that are not filtered out above (masked & non-fatal)
             * are consifered as fatal -> stop SCRIPTS.
             */
            cpssp->scripts_running = false;
            break;

      case REG_SIST1:
            /* Queue sanity check */
            assert(cpssp->int_sist1_depth < INT_QUEUE_DEPTH);

            /*
             * TODO: catch masked non-fatal ints here: these will
             * set bits directly in SIST1, but will not trigger
             * further actions and will not stop SCRIPTS!
             */

            /*
             * Is there already a pending SCSI-type-interrupt (SIP-bit=1)?
             */
            if (cpssp->cardregs[REG_ISTAT] & ISTAT_SIP) {
                  /* We have to queue this one for now... */
                  TRACE(DEBUG_IRQ, "Queueing SIST1-condition %0x\n", bits);
                  cpssp->int_queue_sist1[cpssp->int_sist1_depth] = bits;
                  cpssp->int_sist1_depth++;

            } else {
                  /*
                   * ...otherwise just set the corresponding bits
                   * in SIST1 and indicate our INT-condition in
                   * ISTAT (SIP-bit)!
                   */
                  TRACE(DEBUG_IRQ, "Setting SIST1-int: %0x\n", bits);
                  cpssp->cardregs[REG_SIST1] |= bits;
                  cpssp->cardregs[REG_ISTAT] |= ISTAT_SIP;
            }

            /*
             * INTs that are not filtered out above (masked & non-fatal)
             * are consifered as fatal -> stop SCRIPTS.
             */
            cpssp->scripts_running = false;
            break;
      }

      /* This will take care of (re,de)-asserting the irq-line properly. */
      chip_lsi_int_trigger(cpssp);
}

/*
 * int_del:
 * Dequeues an interrupt-request from the corresponding register-queues:
 * Called for example after reading-out corresponding int-status-regs.
 * (IRQ-clearing).
 */
static void
chip_lsi_int_del(struct cpssp *cpssp, uint8_t reg)
{
      unsigned int i;

      switch (reg) {
      case REG_ISTAT:
            /*
             * Clearing Int-On-Fly Bit
             */
            TRACE(DEBUG_IRQ, "Clearing ISTAT-int-on-fly: %0x\n", 0);
            cpssp->cardregs[REG_ISTAT] &= ~ISTAT_INTF;
            break;

      case REG_DSTAT:
            /*
             * Dequeue one DMA Int
             */
            if (cpssp->int_dstat_depth == 0) {
                  TRACE(DEBUG_IRQ, "ALL DSTAT-int-conds cleared! %0x\n", 0);

                  cpssp->cardregs[REG_DSTAT] = 0;
                  cpssp->cardregs[REG_ISTAT] &= ~ISTAT_DIP;

                  TRACE(DEBUG_IRQ, "ISTAT =  %0x\n", cpssp->cardregs[REG_ISTAT]);

            } else {
                  TRACE(DEBUG_IRQ, "Dequeing DSTAT-int %0x\n", cpssp->int_queue_dstat[0]);

                  cpssp->cardregs[REG_DSTAT] = cpssp->int_queue_dstat[0];
                  for (i = 1; i < cpssp->int_dstat_depth; i++) {
                        cpssp->int_queue_dstat[i - 1] = cpssp->int_queue_dstat[i];
                  }
                  cpssp->int_dstat_depth--;
            }
            break;

      case REG_SIST0:
            /*
             * Dequeue SCSI Int
             */
            if (cpssp->int_sist0_depth == 0) {
                  TRACE(DEBUG_IRQ, "ALL SIST0-int-conds cleared! %0x\n", 0);
                  
                  cpssp->cardregs[REG_SIST0] = 0;
                  /* If SIST1 is also clear, we can clear SIP in ISTAT! */
                  if (cpssp->cardregs[REG_SIST1] == 0) {
                        cpssp->cardregs[REG_ISTAT] &= ~ISTAT_SIP;
                  }

            } else {
                  TRACE(DEBUG_IRQ, "Dequeing SIST0-int %0x\n", cpssp->int_queue_sist0[0]);

                  cpssp->cardregs[REG_SIST0] = cpssp->int_queue_sist0[0];
                  for (i = 1; i < cpssp->int_sist0_depth; i++) {
                        cpssp->int_queue_sist0[i - 1] = cpssp->int_queue_sist0[i];
                  }
                  cpssp->int_sist0_depth--;
            }
            break;

      case REG_SIST1:
            /*
             * Dequeue SCSI Int
             */
            if (cpssp->int_sist1_depth == 0) {
                  TRACE(DEBUG_IRQ, "ALL SIST1-int-conds cleared! %0x\n", 0);

                  cpssp->cardregs[REG_SIST1] = 0;
                  /* If SIST0 is also clear, we can clear SIP in ISTAT! */
                  if (cpssp->cardregs[REG_SIST0] == 0) {
                        cpssp->cardregs[REG_ISTAT] &= ~ISTAT_SIP;
                  }

            } else {
                  TRACE(DEBUG_IRQ, "Dequeing SIST1-int %0x\n", cpssp->int_queue_sist1[0]);

                  cpssp->cardregs[REG_SIST1] = cpssp->int_queue_sist1[0];
                  for (i = 1; i < cpssp->int_sist1_depth; i++) {
                        cpssp->int_queue_sist1[i - 1] = cpssp->int_queue_sist1[i];
                  }
                  cpssp->int_sist1_depth--;
            }
            break;
      }

      /* This will take care of (re,de)-asserting the irq-line properly. */
      chip_lsi_int_trigger(cpssp);
}

/*
 * This one checks on every phase-change, weather the initiator is
 * still waiting for data-transfer...
 */
static void
chip_lsi_check_phase_mismatch(struct cpssp *cpssp)
{
      if (cpssp->delayed_transfer) {
            TRACE(DEBUG_SCSIBUS_BLOCK,
                  "TARGET OFFERS NO MORE DATA,%0x \n",0);
            TRACE(DEBUG_SCSIBUS_BLOCK,
                  "BUT THE CONTROLLER WANTS STILL TO RECEIVE MORE!:%0x \n",0);
            TRACE(DEBUG_SCSIBUS_BLOCK,
                  "TRIGGERING PHASE MISMATCH INTERRUPT!:%0x \n",0);

            cpssp->delayed_transfer = false;
#if 0
            cpssp->SCSI_data_from_target = 0;
            cpssp->SCSI_data_to_target = 0;
#endif

            /* Phase Mismatch Interrupt */
            chip_lsi_int_add(cpssp,REG_SIST0,0x80);
      }
}

/*
 * Arithmetic and read/write operations on chip registers
 */
static void
chip_lsi_rwop(
      struct cpssp *cpssp,
      uint8_t source,
      uint8_t *destination,
      uint8_t data,
      uint8_t op
)
{
      uint16_t adder;

      TRACE(DEBUG_SCRIPTS_ATOMIC, "RW: Source %0x, Dest: %0x \n",
                  source, *destination);

      switch (op) {
      case 0x0: /* simply move...*/
            *destination = data;
            TRACE(DEBUG_SCRIPTS_ATOMIC, "rw-operation: move %0x \n", data);
            break;
      case 0x1: /* Shift left*/
            cpssp->ALU_CARRYBIT = (source & 0x80) >> 7;
            *destination = source << 1;
            TRACE(DEBUG_SCRIPTS_ATOMIC, "shift left %0x \n", 0);
            break;
      case 0x2: /* OR data */
            *destination = source | data;
            TRACE(DEBUG_SCRIPTS_ATOMIC, "OR data %0x \n", 0);
            break;
      case 0x3: /* XOR data */
            *destination = source ^ data;
            TRACE(DEBUG_SCRIPTS_ATOMIC, "XOR data %0x \n", 0);
            break;
      case 0x4: /* AND data */
            *destination = source & data;
            TRACE(DEBUG_SCRIPTS_ATOMIC, "AND data %0x \n", 0);
            break;
      case 0x5: /* Shift right */
            *destination = source >> 1;
            TRACE(DEBUG_SCRIPTS_ATOMIC, "shift right %0x \n", 0);
            if (cpssp->ALU_CARRYBIT) {
                  *destination |= 0x80;
                  TRACE(DEBUG_SCRIPTS_ATOMIC, 
                              "Carrybit shifted-in %0x \n", 0);
            }
            break;
      case 0x6: /* add without carry */
            *destination = source + data;
            TRACE(DEBUG_SCRIPTS_ATOMIC, "add (without carry) %0x \n", 0);
            break;
      case 0x7: /* add with carry */
            adder = source + data;
            *destination = adder & 0xff;
            cpssp->ALU_CARRYBIT = (adder & 0x100) >> 8;
            TRACE(DEBUG_SCRIPTS_ATOMIC, 
                        "add (with carry): %0x + %0x, carry: %0x \n",
                        source, data, cpssp->ALU_CARRYBIT);
            break;
      default:
            TRACE(DEBUG_SCRIPTS_ATOMIC, 
                        "UNKNOWN RW-OPERATION!!!! %0x \n",
                        0);
            assert(0);
            break;
      }
}


/* move memory from any to any address
 * (including memory-mapped-register-ranges) */
static void
chip_lsi_mmove(
      struct cpssp *cpssp,  
      unsigned long from, 
      unsigned long to, 
      uint32_t count
)
{
      uint32_t i;
      uint8_t val;
      uint32_t val32;

      /* FIX ME: I dont know why the hell the driver is using
       * relative register-addresses?!? */
      if (from <= SZ_53C810MEM) {
            from += LSI53C810MEMADDR(cpssp);
      }

      if (to <= SZ_53C810MEM) { 
            to += LSI53C810MEMADDR(cpssp); 
      }

      /* FIX ME: use something faster than bytewise copying */
      /* FIX ME: use chip read/write for register-access... */
      for (i = 0 ; i < count; i++) {
            /* Getting source-byte */
            if (LSI53C810MEMADDR(cpssp) <= from + i
             && from + i <= (LSI53C810MEMADDR(cpssp) + SZ_53C810MEM)) {
                  TRACE(DEBUG_SCRIPTS, 
                              "warning: direct register read: %lx\n",
                              from + i - LSI53C810MEMADDR(cpssp));
                  val = *CHARCARDREG(cpssp, 
                              from + i - LSI53C810MEMADDR(cpssp));
            } else {
                  sig_pci_bus_mr(cpssp->port_pci_bus, cpssp,
                        (from + i) & ~3, 1 << ((from + i) & 3),
                        &val32);
                  val = val32 >> ((from + i) & 3) * 8;
            }
            TRACE(DEBUG_SCRIPTS_ATOMIC, 
                        "MMOVE-DMA: read 1 bytes (%0x) from %0lx\n",
                        val, from + i);
            /* writing target-byte */
            if (LSI53C810MEMADDR(cpssp) <= to + i
             && to + i <= (LSI53C810MEMADDR(cpssp) + SZ_53C810MEM)) {
                  TRACE(DEBUG_SCRIPTS,
                              "warning: direct register write: %lx\n",
                              to + i - LSI53C810MEMADDR(cpssp));
                  *CHARCARDREG(cpssp, to + i - LSI53C810MEMADDR(cpssp)) = val;
            } else {
                  val32 = val << ((to + i) & 3) * 8;
                  sig_pci_bus_mw(cpssp->port_pci_bus, cpssp,
                        (to + i) & ~3, 1 << ((to + i) & 3),
                        val32);
            }
            TRACE(DEBUG_SCRIPTS_ATOMIC, 
                        "MMOVE-DMA: wrote 1 bytes (%0x) to %0lx\n",
                        val, to + i);
      }
}

/* This will take care of sending some data
 * in any data-transfer-phase from the target */
static uint32_t
chip_lsi_data_from_target(
      bool resume,
      struct cpssp *cpssp,
      uint32_t to_pci,
      unsigned long lsi_count,
      unsigned long target_offered
)
{
      unsigned long i = 0;
      unsigned long m = 0;
      unsigned long receive = 0;
      unsigned long pending;
      uint32_t buf_word;
      bool firstByte = false;


      /* We have transferred data, so this phase
       * has to be considered as serviced! */
      cpssp->SCSI_unserviced = false;

      cpssp->backup_phase_status = cpssp->SCSI_phase_change;

#if 0
      assert(target_offered);
#endif
      pending = target_offered;

      /* maybe we have to resume a transfer? */
      if (resume) {
            i = cpssp->backup_i_counter;
            TRACE(DEBUG_SCSIBUS_BLOCK, "RESUMING BLOCKTRANSFER FROM TARGET: Phase:%0x lsi_count: %0lx disk count: %0lx Index: %lx\n",
                        cpssp->SCSI_phase, lsi_count, target_offered, i);
      } else {
            TRACE(DEBUG_SCSIBUS_BLOCK, "BLOCKTRANSFER FROM TARGET: Phase:%0x lsi_count: %0lx disk count: %0lx\n",
                        cpssp->SCSI_phase, lsi_count, target_offered);
      }

      while (pending) {
            /* maybe the controller will exit
             * its block-move at this time? */
            if (i >= lsi_count) {
                  assert(cpssp->SCSI_phase == SCSI_PHASE_MESSAGE_IN
                      || cpssp->SCSI_phase == SCSI_PHASE_DATA_IN);
                  TRACE(DEBUG_SCSIBUS_BLOCK, "FINNISHED, BUT DISK WANTS TO TRANSFER MORE!!!:%0lx \n", 
                              pending);
                  /*  in this case the phase counts still as unserviced */
                  cpssp->SCSI_unserviced = true;
                  /* remember pending bytes for next blockmovetransfer... */
                  cpssp->SCSI_data_from_target = pending;
                  cpssp->pending_transfer = true;
                  break;
            } else {
                  cpssp->pending_transfer = false;
            }

            /* Generally take only as many bytes
             * as we can put in our buffer! */
            if (pending > SIZE_IO_BUF) {
                  receive = SIZE_IO_BUF;
            } else {
                  receive = pending;
            }

            /* On the other side,
             * never take more than the lsi wants to transfer
             * at the moment*/
#if 0
            if (lsi_count < receive) {
                  receive = lsi_count;
            }
#endif
            if (lsi_count < i + receive) {
                  receive = lsi_count - i;
            }


            /* Get byte(s) from SCSI-bus...*/
            pending = sig_scsi_bus_recv(cpssp->port_scsi_bus, cpssp,
                        cpssp->scsi_io_buf, receive);
            TRACE(DEBUG_SCSIBUS_BLOCK, "%0lx BYTES FETCHED FROM SCSI-BUS, %0lx to go \n", 
                        receive, pending);

            /* copy the first byte received into the
             * SCSI-FIRST-BYTE-RECEIVED-register */
            if (! firstByte) {
                  firstByte = true;
                  *CHARCARDREG(cpssp,REG_SFBR) = cpssp->scsi_io_buf[0];
                  TRACE(DEBUG_SCSIBUS_BLOCK, "COPIED FIRST BYTE RECEIVED TO SFBR-REG:%0x \n",
                              *CHARCARDREG(cpssp,REG_SFBR));
            }

            /* ...and write it to memory!*/
            for (m = 0; m < receive; m++) {
                  buf_word = cpssp->scsi_io_buf[m] << ((to_pci + m + i) & 3) * 8;
                  sig_pci_bus_mw(cpssp->port_pci_bus, cpssp,
                              (to_pci + m + i) & ~3, 1 << ((to_pci + m + i) & 3),
                              buf_word);
#if 0
                  TRACE(DEBUG_SCSIBUS, "WRITE TO PCI-BUS, BS: %0x, MEM: %0lx \n",
                        1 << ((to_pci + m + i) & 3), (to_pci + m + i) & ~3);
#endif

            }
            i += receive;
            *LONGCARDREG(cpssp,REG_DNAD) += receive;
      }

      if (lsi_count == i) {
            TRACE(DEBUG_SCSIBUS_BLOCK,
                  "ALL DATA RECEIVED FROM TARGET:%0x \n",0);
            cpssp->delayed_transfer = false;

            /* only clear counter if there is no pending transfer any more! */
            if (!(cpssp->pending_transfer)) {
                  /* Workaround for Helmis brain-dead scsi-disk,
                   * who did the phase change earlier */
                  if (cpssp->SCSI_phase_change != cpssp->backup_phase_status) {
                        /* bad disk: do not touch transfercounter! */
                  } else {
                        /* good disk: transfer finnished, reset counter! */
                        TRACE(DEBUG_SCSIBUS_BLOCK, "CLEARING TRANSFER-COUNTER:%0x \n",0);
                        cpssp->SCSI_data_from_target = 0;
                  }
            }

            return i;
      } else if (lsi_count > i) {
            TRACE(DEBUG_SCSIBUS_BLOCK, "TARGET DELAYED TRANSFER...:%0x \n",0);
            cpssp->delayed_transfer = true;
            cpssp->backup_i_counter = i;

            /* Workaround for Helmis brain-dead scsi-disk,
             * who did the phase change earlier...*/
            if (cpssp->SCSI_phase_change != cpssp->backup_phase_status) {
                  chip_lsi_check_phase_mismatch(cpssp);
                  return i;
            }

            return i;
      } else {
            /* should never happen at this place*/
            assert(0);
      }
      
      return i;

      /* Remember:
       * if the data-transfer has finished at this place,
       * maybe the next transfer was already set up by the target!
       * So dont touch cpssp->SCSI_data_from_target! */
}


/* This will take care of sending some data
 * in any data-transfer-phase to the target */
static uint32_t
chip_lsi_data_to_target(
      bool resume,
      struct cpssp *cpssp,
      uint32_t from_pci,
      unsigned long lsi_count,
      unsigned long target_wants)
{
      unsigned long i=0;
      unsigned long m=0;
      unsigned long pending;
      unsigned long _send = 0;
      uint32_t buf_word;

      /* We will transfer data, so this phase
       * has to be considered as serviced! */
      cpssp->SCSI_unserviced = false;

      cpssp->backup_phase_status = cpssp->SCSI_phase_change;

#if 0
      assert(target_wants);
#endif
      pending = target_wants;

      /* maybe we have to resume a transfer? */
      if (resume) {
            i = cpssp->backup_i_counter;
            TRACE(DEBUG_SCSIBUS_BLOCK, "RESUMING BLOCKTRANSFER TO TARGET: Phase:%0x lsi_count: %0lx disk count: %0lx index: %lx \n",
                        cpssp->SCSI_phase,
                        lsi_count,
                        target_wants,
                        i);
      } else {
            TRACE(DEBUG_SCSIBUS_BLOCK, "BLOCKTRANSFER TO TARGET: Phase:%0x lsi_count: %0lx disk count: %0lx\n",
                        cpssp->SCSI_phase,
                        lsi_count,
                        target_wants);
      }

      /* Only relevant in MSG-OUT-PHASE:
       * ATN-line-triggering */
      /* SCSI-Specs say:
       * "The initiator shall keep the ATN signal asserted
       * if more then one byte is to be transferred" */
      if (cpssp->SCSI_phase == SCSI_PHASE_MESSAGE_OUT) {
            if (lsi_count > 1) {
                  TRACE(DEBUG_SCSIBUS_BLOCK, "RISING ATN-LINE:%0x \n", 1);
                  sig_scsi_bus_atn_set(cpssp->port_scsi_bus, cpssp, 1);
            } else {
                  TRACE(DEBUG_SCSIBUS_BLOCK, "NO NEED TO RISE ATN-LINE:%0x \n", 1);
                  sig_scsi_bus_atn_set(cpssp->port_scsi_bus, cpssp, 0);
            }
      }

      while (pending) {

            /* maybe the controller will exit
             * its block-move at this time? */
            if (i >= lsi_count) {
                  assert(cpssp->SCSI_phase == SCSI_PHASE_DATA_OUT);
                  TRACE(DEBUG_SCSIBUS_BLOCK, "FINNISHED, BUT DISK WANTS TO TRANSFER MORE!!!:%0lx \n", 
                        pending);
                  /*  in this case the phase counts still as unserviced */
                  cpssp->SCSI_unserviced = true;
                  /* remember pending bytes for next blockmovetransfer... */
                  cpssp->SCSI_data_to_target = pending;
                  cpssp->pending_transfer = true;
                  break;
            } else {
                  cpssp->pending_transfer = false;
            }

            /* Only in MSG-OUT-phase:
             * before transferring the last byte,
             * disable ATN-Line */
            /* (again according to SCSI specs) */
            if (cpssp->SCSI_phase == SCSI_PHASE_MESSAGE_OUT) {
                  if (i == (lsi_count - 1)){
                        TRACE(DEBUG_SCSIBUS_BLOCK, "SETTING ATN-LINE LOW (transferring last MSG-OUT-BYTE):%0x \n", 0);
                        sig_scsi_bus_atn_set(cpssp->port_scsi_bus, cpssp, 0);
                  }
            }

            /* Generally send only as many bytes
             * as we have in our buffer! */
            if (pending > SIZE_IO_BUF) {
                  _send = SIZE_IO_BUF;
            }
            else {
                  _send = pending;
            }

            /* On the other side,
             * never give more than the lsi wants to transfer
             * at the moment*/
#if 0
            if (lsi_count < _send) {
#endif
            if (lsi_count < i + _send) {
                  _send = lsi_count - i;
            }
            TRACE(DEBUG_SCSIBUS_BLOCK, "SENDING %0lx BYTES TO TARGET:",
                        _send);

            /* get it from memory!*/
            for (m = 0; m < _send; m++) {
                  sig_pci_bus_mr(cpssp->port_pci_bus,
                              cpssp,
                              (from_pci + m + i) & ~3,
                              1 << ((from_pci + m + i) & 3),
                              &buf_word);

                  /* write byte to buffer */
                  cpssp->scsi_io_buf[m] = buf_word >> ((from_pci + m + i) & 3) * 8;
            }

            /* send buffer to scsibus */
            pending = sig_scsi_bus_send(cpssp->port_scsi_bus,
                              cpssp,
                              cpssp->scsi_io_buf,
                              _send);

            i+= _send;
            *LONGCARDREG(cpssp,REG_DNAD) += _send;
      }


      if (i < lsi_count) {
            TRACE(DEBUG_SCSIBUS_BLOCK, "TARGET DELAYED TRANSFER...:%0x \n",0);
            cpssp->delayed_transfer = true;
            cpssp->backup_i_counter = i;
            return i;
      } else {
            TRACE(DEBUG_SCSIBUS_BLOCK, "ALL DATA SENT TO TARGET:%0x \n",0);
            cpssp->delayed_transfer = false;

            /* only clear counter if there is no pending transfer any more! */
            if (!(cpssp->pending_transfer)) {
                  /* Workaround for Helmis brain-dead scsi-disk,
                   * who did the phase change earlier */
                  if (cpssp->backup_phase_status != cpssp->SCSI_phase_change) {
                        /* bad disk: do not touch transfercounter! */
                  } else {
                        /* good disk: transfer finnished, reset counter! */
                        cpssp->SCSI_data_to_target = 0;
                        TRACE(DEBUG_SCSIBUS_BLOCK, "CLEARING TRANSFER-COUNTER:%0x \n",0);
                  }
            }

            return i;
      }

      /* Remember:
       * if the data-transfer has finished at this place,
       * maybe the next transfer was already set up by the target!
       * So dont touch cpssp->SCSI_data_to_target! */

}

/* Checks whether there is a need for triggering
 * a timeout-condition:
 * returns TRUE if the timeout was considered fatal
 * (SCRIPTS stopped) */

static void
chip_lsi_timeoutcheck(struct cpssp *cpssp)
{
      /* Selection-timer timeout? */
      if (cpssp->timerset_sel && (cpssp->timertick_sel >= cpssp->timerset_sel) ){
            cpssp->timerset_sel = 0;
            cpssp->timertick_sel = 0;
            TRACE(DEBUG_SCRIPTS,"Selection timer timeout!%x\n",0);
            /* signal (potential) interrupt: */
            chip_lsi_int_add(cpssp,REG_SIST1,0x04);

      }

      /* H2H-timer timeout? */
      if (cpssp->timerset_h2h && (cpssp->timertick_h2h >= cpssp->timerset_h2h) ){
            cpssp->timerset_h2h = 0;
            cpssp->timertick_h2h = 0;
            TRACE(DEBUG_SCRIPTS,"H2H timer timeout!%x\n",0);
            /* signal (potential) interrupt: */
            chip_lsi_int_add(cpssp,REG_SIST1,0x01);
      }

      /*gen-timer timeout? */
      if (cpssp->timerset_gen && (cpssp->timertick_gen >= cpssp->timerset_gen) ){
            cpssp->timerset_gen = 0;
            cpssp->timertick_gen = 0;
            TRACE(DEBUG_SCRIPTS,"General purpose timer timeout!%x\n",0);
            /* signal (potential) interrupt: */
            chip_lsi_int_add(cpssp,REG_SIST1,0x02);
      }

      /*timertick_xxx = 0 */
}

/* increases the chip_internal ticks for the timer-clocks */
static void chip_lsi_update_timerticks(struct cpssp *cpssp, unsigned long long ticks)
{
      /* Selection Timer set?*/
      if (cpssp->timerset_sel) {
            cpssp->timertick_sel += ticks;
            TRACE(DEBUG_TIMER,
                  "Selection timer tick added: %llu (%llu)\n",ticks,cpssp->timertick_sel);
      }

      /* H2H Timer set? */
      if (cpssp->timerset_h2h) {
            cpssp->timertick_h2h += ticks;
            TRACE(DEBUG_TIMER,
                  "H2H timer tick added: %0llx\n",ticks);
            assert(0);
      }

      /* General purpose timer set? */
      if (cpssp->timerset_gen) {
            cpssp->timertick_gen += ticks;
            TRACE(DEBUG_TIMER,
                  "General purpose timer tick added: %0llx\n",ticks);
      }

}

/* updates the time periodically */
static void timer_tick(void *_cpssp)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;
      chip_lsi_timeoutcheck(cpssp);

      /* if there is a minimum of one timer active,
       * reschedule timer! */
      if ( cpssp->timerset_sel
        || cpssp->timerset_h2h
        || cpssp->timerset_gen) {
            chip_lsi_update_timerticks(cpssp,TIMERTICKS);
            time_call_at(time_virt() + TIMERTICKS,
                  timer_tick, cpssp);
      }

}


/* calculates the timer-interval in nano-seconds,
 * based on the given bit-parameter */
static long long
calc_timer_nano(uint8_t factor)
{
      unsigned long long base = TIMER_BASE_INTERVAL;

      TRACE(DEBUG_TIMER,
         "Calculated Timer Interval based on %0x: %0llx\n",
         factor,base << (factor - 1));

      return base << (factor - 1);
}

/* This will check the SCSI-bus for a RESELECT of the controller:
 * It will be periodically called by time,
 * until one of the following events occure:
 *
 * - The controller is finally reselected -> resume SCRIPTS
 * - The controller is selected bevore beeing reselected -> resume SCRIPTS @DNAD
 * - The SIGP-flag in ISTAT is set -> resume SCRIPTS @DNAD
 * - Some error occures -> TODO...*/
static void
chip_lsi_wait_reselect(void *_cpssp)
{

      struct cpssp *cpssp = (struct cpssp *) _cpssp;
      uint8_t istat = *CHARCARDREG(cpssp,REG_ISTAT);
      int32_t offset;

      TRACE(DEBUG_SCRIPTS_ATOMIC,"waiting for reselect. ISTAT=%0x\n",
                  *CHARCARDREG(cpssp,REG_ISTAT) );

      if (cpssp->abort_wait_reselect) {
            TRACE(DEBUG_SCRIPTS,"OPERATION ABORTED! STOPPING RESELECT-WAIT-SCHEDULER!%0x\n",
                  0);
            cpssp->abort_wait_reselect = false;
            return;
      }

      /* We dont support reselection right now! */

      if (cpssp->SCSI_reselected) {
            assert(0);
      } else if (cpssp->SCSI_selected) {
            assert(0);
      } else if ((istat & 0x20) == 0x20) {
            /*check options in DCMD-Register: */
            if (*CHARCARDREG(cpssp,REG_DCMD) & 0x04) {
#if 0
                  /* SIGNED 24-Bit! */
                  offset = (int32_t) ((*LONGCARDREG(cpssp,REG_DNAD) & (1 << 23)) ? *LONGCARDREG(cpssp,REG_DNAD) | (0xff << 24) : *LONGCARDREG(cpssp,REG_DNAD));
#endif
                  offset = *LONGCARDREG(cpssp,REG_DNAD);
                  *LONGCARDREG(cpssp,REG_DSP) += offset;
                  TRACE(DEBUG_SCRIPTS,"SIGP set! Cont. SCRIPTS @ OFFSET-DNAD: %0d\n",
                              offset);
                  chip_lsi_53C810_start_SCRIPTS(cpssp);
            } else {
                  *LONGCARDREG(cpssp,REG_DSP) = *LONGCARDREG(cpssp,REG_DNAD);
                  TRACE(DEBUG_SCRIPTS,"SIGP set! Cont. SCRIPTS @ DNAD: %0x\n",
                              *LONGCARDREG(cpssp,REG_DNAD));
                  chip_lsi_53C810_start_SCRIPTS(cpssp);
            }
      } else {
            /* nothing happenedi for now, so just reschedule...*/
            TRACE(DEBUG_SCRIPTS_ATOMIC,"rescheduling wait for reselect! %0x\n",
                                                      0);
            time_call_at(time_virt() + TSYNC_INTERVAL_RESELECT,
                              chip_lsi_wait_reselect, cpssp);
      }
      return;
}

static void
chip_lsi_wait_phasecomp(void *_cpssp)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;
#if 0
      uint8_t cmp_phase = cpssp->cardregs[REG_DCMD] & 0x07;
#endif
      if (cpssp->abort_wait_phasecomp) {
            TRACE(DEBUG_SCRIPTS,"OPERATION ABORTED! STOPPING PHASECOMP-WAIT-SCHEDULER!%0x\n",
                  0);
            cpssp->abort_wait_phasecomp = false;
            return;
      }

      TRACE(DEBUG_SCRIPTS_ATOMIC,"waiting to compare a valid unserviced SCSI bus-phase...%0x\n",0);

      if (cpssp->SCSI_unserviced) {
            TRACE(DEBUG_SCRIPTS,"...Phase valid!%0x\n",0);
            /*restart SCRIPTS-parsing...*/
            /*..but on the right position! */
            assert(cpssp->pc_restart);
            *LONGCARDREG(cpssp,REG_DSP) = cpssp->pc_restart;
            cpssp->pc_restart = 0;
            TRACE(DEBUG_SCRIPTS,"Ok, restarting SCRIPTS at %0x\n",
                        *LONGCARDREG(cpssp,REG_DSP));
            chip_lsi_53C810_start_SCRIPTS(cpssp);
      } else  {
            /* nothing happened for now, so just reschedule -
             * unless there is a timeout...*/

            chip_lsi_timeoutcheck(cpssp);

            if (!(cpssp->scripts_running)) {
                  /* ok, there was a timeout-interrupt and it was fatal! */
                  return;
            } else {
                  /* just go on waiting...*/
                  TRACE(DEBUG_SCRIPTS_ATOMIC,"rescheduling wait for phasecompare! %0x\n",
                                                            0);
                  /* we have to speed-up our card-timer a little... */
                  chip_lsi_update_timerticks(cpssp,TIMERTICKS);
                  time_call_at(time_virt() + TIMERTICKS,
                                    chip_lsi_wait_phasecomp, cpssp);
            }
      }
      return;
}

/* Little helper function:
 * backups the current DSP in TEMP register,
 * used for call() */

static void
call_backup_dsp(struct cpssp *cpssp, char opcode, uint32_t dsp)
{
      /* Was the jump actually a call? */
      /* The only difference between jump
       * and call is the saved IP */
      if (opcode == 0x01) {
            TRACE(DEBUG_SCRIPTS, 
                  "JUMP WAS ACTUALLY A CALL! PUTTING DSP IN TEMP: %0x\n",0);
            *LONGCARDREG(cpssp,REG_TEMP) = dsp;
      }
}


/* Notice:
 * This function will be called either at the beginning
 * of every SCRIPTS execution,
 * or at resume-time of a previous MAX_SCRIPTS_EXE-interrupted execution! */
static void
chip_lsi_53C810_start_SCRIPTS(struct cpssp *cpssp)
{
      int32_t reladdr;
      int32_t absaddr;
      uint32_t iodata_addr;
      uint8_t cmpdata;
      uint8_t phases;
      uint8_t options;
      uint8_t rwopcode;
      uint8_t opcode;
      uint8_t rwoperation;
      uint8_t reg;
      uint8_t mask;
      uint8_t mode;
      uint8_t data8;
      uint32_t data32;
      uint32_t backup_dsp;
      uint8_t iodata_config;
      uint8_t iodata_id;
      uint8_t iodata_period;
      uint8_t iodata_null;
      uint8_t reg_lst;
      uint32_t count;
      uint32_t subcount;
      uint32_t _bs;
      uint32_t _s;
      uint32_t _i;
      uint32_t addr;
      uint32_t reg_temp;
      uint32_t sel_stat;
      bool jumpflag;
      bool phaseflag;

      /* SCSI-SCRIPTS interpreter main-loop: 
       * after some instructions we must give back the cpu to the rest of the
       * simulator, so dont execute more than MAX_SCRIPTS_EXE instructions
       * at once.
       * The time-scheduler will restart the SCRIPTS processing later...*/

      /* Mention:
       * cpssp->scripts_running is set on DSP-Register write,
       * and is reset on SCRIPTS termination (INT, ISTAT-msg-flag,...)
       *
       * FIX ME:
       * Single-Step-Mode... */

      while (cpssp->scripts_counter < MAX_SCRIPTS_EXE) {

            /* maybe something has stopped SCRIPTS? */
            if (!cpssp->scripts_running) {
                  /* in this case lets restart later 
                   * with a fresh scripts-counter!*/
                  cpssp->scripts_counter = 0;
                  TRACE(DEBUG_SCRIPTS,"STOPPING SCRIPTS EXECUTION!!!%x\n",0);
                  return;
            }

            /* dont forget... */
            cpssp->scripts_counter++;

            /* For now, we assume that every SCRIPTS instruction 
             * has a constant execution time...*/
            chip_lsi_timeoutcheck(cpssp);
            chip_lsi_update_timerticks(cpssp,SCRIPTS_TIMERTICKS);

            TRACE(DEBUG_SCRIPTS,
                        "\n\n##### next SCRIPTS INSTRUCTION (%0x)### \n",
                        *LONGCARDREG(cpssp,REG_DSP));

            /* fetch instruction from memory:
             * program-counter is always in DSP,
             * first 32 bit of command in DBC/DCMD !
             */
            sig_pci_bus_mr(cpssp->port_pci_bus, cpssp, *LONGCARDREG(cpssp,REG_DSP),
                        0xf, LONGCARDREG(cpssp,REG_DBC));
            /* The second parameter is always in REG_DSPS */
            sig_pci_bus_mr(cpssp->port_pci_bus, cpssp, *LONGCARDREG(cpssp,REG_DSP)+4,
                        0xf, LONGCARDREG(cpssp,REG_DSPS));

            /* DSPS is copied to DNAD
             * at the start of every SCRIPTS operation... */
            *LONGCARDREG(cpssp,REG_DNAD) = *LONGCARDREG(cpssp,REG_DSPS);

#if 0
            TRACE(DEBUG_SCRIPTS, "1. parameter (DBC): %0x\n",
                              *LONGCARDREG(cpssp,REG_DBC));
            TRACE(DEBUG_SCRIPTS, "2. parameter (DSPS): %0x\n",
                              *LONGCARDREG(cpssp,REG_DSPS));
#endif

            switch(*CHARCARDREG(cpssp,REG_DCMD)){
            case 0x18: /* BLOCK-MOVE DATA-OUT-PHASE */
            case 0x19: /* BLOCK-MOVE DATA-IN-PHASE */
            case 0x10: /* BLOCK-MOVE DATA-OUT-PHASE (table-indirect, reserved bit set)*/
            case 0x11: /* BLOCK-MOVE DATA-IN-PHASE (table-indirect, reserved bit set)*/
            case 0x1a: /* BLOCK-MOVE COMMAND-PHASE */
            case 0x1b: /* BLOCK-MOVE STATUS-PHASE */
            case 0x1e: /* BLOCK-MOVE MSG-OUT-PHASE */
            case 0x1f: /* BLOCK-MOVE MSG-IN-PHASE (table-indirect)*/
            case 0x08: /* BLOCK-MOVE DATA-OUT-PHASE (direct addr)*/
            case 0x09: /* BLOCK-MOVE DATA-IN-PHASE (direct addr)*/
            case 0x0a: /* BLOCK-MOVE COMMAND-PHASE (direct addr)*/
            case 0x0b: /* BLOCK-MOVE STATUS-PHASE (direct addr)*/
            case 0x0e: /* BLOCK-MOVE MSG-OUT-PHASE (direct addr)*/
            case 0x0f: /* BLOCK-MOVE MSG-IN-PHASE (direct addr)*/
                  phases = cpssp->cardregs[REG_DCMD] & 0x07;
                  count = (*LONGCARDREG(cpssp,REG_DBC)) & 0x00ffffff;
                  TRACE(DEBUG_SCRIPTS, "BLOCK MOVE: %0x (phase %0x): Count: %0x, Addr: %0x\n",
                              *LONGCARDREG(cpssp,REG_DBC),phases, count, *LONGCARDREG(cpssp,REG_DSPS));

                  /* check for addressing-mode */
                  if (cpssp->cardregs[REG_DCMD] & 0x10) {
                        /* Table-indirect */
                        /* Fix me: DSA-Offset in DSPS is 24-Bit signed */
                        iodata_addr = *LONGCARDREG(cpssp,REG_DSA)
                              + (*LONGCARDREG(cpssp,REG_DSPS) & 0x00ffffff);
                        TRACE(DEBUG_SCRIPTS, "Using table-indirect addressing at: %0x\n",
                                    iodata_addr);
                        TRACE(DEBUG_SCRIPTS, "Offset: %0x\n",
                                    (*LONGCARDREG(cpssp,REG_DSPS) & 0x00ffffff));

                        /* fetch data structure: */
                        sig_pci_bus_mr(cpssp->port_pci_bus, cpssp, iodata_addr, 0xf,
                                    &data32);
                        count = data32;
                        sig_pci_bus_mr(cpssp->port_pci_bus, cpssp, iodata_addr + 4, 0xf,
                                    &data32);
                        addr = data32;
                        TRACE(DEBUG_SCRIPTS, 
                              "Block-move: Count: %0x, Addr: %0x\n",
                              count,addr);

                        /* Data-transfer FROM target at
                         * DATA-IN, STATUS and MSG-IN-phase */
                        if (phases == 0x01
                         || phases == 0x03
                         || phases == 0x07) {
                              /* This will handle the actual data-transfer 
                               * in data_from_target-phases */
                              subcount = chip_lsi_data_from_target(
                                    cpssp->delayed_transfer,
                                    cpssp,
                                    addr,
                                    count,
                                    cpssp->SCSI_data_from_target);
                        } else{
                              /* This will handle the actual data-transfer
                               * in data_to_target-phases */
                              subcount = chip_lsi_data_to_target(
                                    cpssp->delayed_transfer,
                                    cpssp,
                                    addr,
                                    count,
                                    cpssp->SCSI_data_to_target);
                        }

#if 0
                        /*(Decrement DBC), Increment DNAD */
                        *LONGCARDREG(cpssp,REG_DNAD) += subcount;
#endif

                  } else if (cpssp->cardregs[REG_DCMD] & 0x20) {
                        /* Indirect-adressing */
                        /* implement me! */
                        assert(0);

                  } else {
                        /* direct-adressing! */
                        count = *LONGCARDREG(cpssp,REG_DBC) & 0x00ffffff;
                        addr = *LONGCARDREG(cpssp,REG_DSPS);
                        TRACE(DEBUG_SCRIPTS, 
                              "Using direct addressing: Count%0x, Addr: %0x\n",
                                    count,addr);

                        /* Data-transfer FROM target at
                         * DATA-IN, STATUS and MSG-IN phase */
                        if ((phases == 0x01)
                          ||(phases == 0x03)
                          ||(phases == 0x07) ) {
                        /* This will handle the actual data-transfer 
                         * in data_from_target-phases */
                              subcount = chip_lsi_data_from_target(
                                    cpssp->delayed_transfer,
                                    cpssp,
                                    addr,
                                    count,
                                    cpssp->SCSI_data_from_target);
                        } else{
                        /* This will handle the actual data-transfer
                         * in data_to_target-phases */
                              subcount = chip_lsi_data_to_target(
                                    cpssp->delayed_transfer,
                                    cpssp,
                                    addr,
                                    count,
                                    cpssp->SCSI_data_to_target);
                        }

                        /*(Decrement DBC), Increment DNAD */
                        *LONGCARDREG(cpssp,REG_DNAD) += subcount;
                        *LONGCARDREG(cpssp,REG_DCMD) &= 0xff000000;

                  }

                  /* maybe the target delayed the transfer? */
                  if (cpssp->delayed_transfer) {
                        TRACE(DEBUG_SCRIPTS, "TARGET delayed transfer --> suspending SCRIPTS!%x\n", 0);
                        return;
                  }

                  /*inc PC */
                  *LONGCARDREG(cpssp,REG_DSP) += 8;
                  break;

            case 0x43: /* SELECT (table-indirect with ATN) */
            case 0x47: /* SELECT (table-relative with ATN) */
                  TRACE(DEBUG_SCRIPTS, "SELECT (table-indirect): %x\n", 
                              *LONGCARDREG(cpssp,REG_DBC));
                  /* Fix me: DBC is a 24-bit signed value! */
                  iodata_addr = *LONGCARDREG(cpssp,REG_DSA) +
                         (*LONGCARDREG(cpssp,REG_DBC) & 0x00ffffff);
                  TRACE(DEBUG_SCRIPTS, "IO-DATA at %0x (DBC: %0x)\n",
                              iodata_addr, 
                              (*LONGCARDREG(cpssp,REG_DBC) & 0x00ffffff) );
                  /* fetch io-data structure */
                  sig_pci_bus_mr(cpssp->port_pci_bus, cpssp, iodata_addr, 0xf,
                              &data32);
                  iodata_null = data32 >> 0;
                  iodata_period = data32 >> 8;
                  iodata_id = data32 >> 16;
                  iodata_config = data32 >> 24;
                  cpssp->cardregs[REG_SDID] = iodata_id;
                  cpssp->cardregs[REG_SXFER] = iodata_period;
                  cpssp->cardregs[REG_SCNTL3] = iodata_config;
                  TRACE(DEBUG_SCRIPTS, 
                              "FETCHED IO-DATA: config: %0x, id: %0x, priod/offset: %0x, null: %0x\n",
                              iodata_config,
                              iodata_id,
                              iodata_period,
                              iodata_null);

                  TRACE(DEBUG_SCRIPTS,
                              "Own ID: %0x\n",cpssp->cardregs[REG_SCID]);

                  /* start SELECT timer */
                  cpssp->timerset_sel = calc_timer_nano(cpssp->cardregs[REG_STIME0] & 0x0f);
                  TRACE(DEBUG_TIMER,"SELECT-TIMER started: %llu\n",cpssp->timerset_sel);

                  /* send SELECT to SCSI bus */
                  TRACE(DEBUG_SCSIBUS, "CHANGING SCSI-BUS-PHASE: SELECT: %0x \n", iodata_id);
                  sel_stat = sig_scsi_bus_phase_select(
                              cpssp->port_scsi_bus,
                              cpssp,
                              iodata_id);

                  /* Success? */
                  if (sel_stat) {
                        TRACE(DEBUG_SCSIBUS, "SELECT: accepted%0x \n", iodata_id);
                        /* stop timer */
                        cpssp->timertick_sel = 0;
                        cpssp->timerset_sel = 0;

                        /* now we are an initiator */
                        cpssp->SCSI_initiated = true;

                  } else {
                        TRACE(DEBUG_SCSIBUS, "SELECT: no answer%0x \n", iodata_id);
                        cpssp->SCSI_initiated = false;
                        cpssp->SCSI_unserviced = false;
                  }

                  /*inc PC */
                  *LONGCARDREG(cpssp,REG_DSP) += 8;
                  break;

            case 0x48:
                  TRACE(DEBUG_SCRIPTS, "WAIT FOR DISCONNECT... %x\n",0);
                  /* Wait for disconnect */
                  /* (Simply check for busfree) */

                  /* Normally we would wait here via
                   * time_call(), but our current scsi-disk
                   * already provided bus-free-phase at this time
                   * and we dont have to wait! */
                  if (cpssp->SCSI_phase == SCSI_PHASE_BUSFREE) {
                        TRACE(DEBUG_SCRIPTS, "DISCONNECTED! %x\n",0);
                        cpssp->SCSI_unserviced = false;
                  } else {
                        TRACE(DEBUG_SCRIPTS,
                              "Waiting for a new valid phase (BUSFREE)! Will reschedule command!%x\n",0);
                        /* any pending old abort-operation regarding wait_phasecomp
                         * is invalid now! */
                        cpssp->abort_wait_phasecomp = false;
                        /* wait for a new phase
                         * and reschedule this operation */
                        cpssp->pc_restart = *LONGCARDREG(cpssp,REG_DSP);
                        chip_lsi_wait_phasecomp(cpssp);
                        return;
                  }
                  /*inc PC */
                  *LONGCARDREG(cpssp,REG_DSP) += 8;
                  break;

            case 0x50: /* Wait (Re)Select */
            case 0x54: /* Wait (Re)Select relative adressing...*/
                  TRACE(DEBUG_SCRIPTS, "WAIT (RE)SELECT! %x\n",0);
                  TRACE(DEBUG_SCRIPTS, "DCMD/DBC: .%0x\n",
                                    *LONGCARDREG(cpssp,REG_DBC));

                  *LONGCARDREG(cpssp,REG_DSP) += 8;
                  /* this will reschedule itself again if needed
                   * and check the SCSI-bus... */

                  /* an pending old abort-operation regarding reselection
                   * is invalid now! */
                  cpssp->abort_wait_reselect = false;
                  chip_lsi_wait_reselect(cpssp);

                  /*...but it will return sooner or later in any case*/
                  return;

            case 0x60:
                  /* CLEAR SACK/SATN */
                  /* (ignored) */
                  TRACE(DEBUG_SCRIPTS, "CLEAR SACK/SATN (ignored) %x\n",0);
                  /*inc PC */
                  *LONGCARDREG(cpssp,REG_DSP) += 8;
                  break;

            case 0x68 ... 0x7f: /* Read/Write Instructions */
                  rwopcode = (*CHARCARDREG(cpssp,REG_DCMD) & 0x38) >> 3;
                  rwoperation = *CHARCARDREG(cpssp,REG_DCMD) & 0x7;
                  reg = (*LONGCARDREG(cpssp,REG_DBC) & 0x00ff0000) >> 16;
                  data8 = (*LONGCARDREG(cpssp,REG_DBC) & 0x0000ff00) >> 8;
                  TRACE(DEBUG_SCRIPTS, "R/W INSTRUCTION  typ=%0x, op=%0x,  reg=%0x, data=%0x\n",
                              rwopcode, rwoperation, reg, data8);
                  switch (rwopcode) {
                  uint8_t val_s;
                  uint8_t val_d;
                  case 0x5: /* move byte from SFBR */
                        /* &source, &target, data, operator */
                        lsi_readb(cpssp, REG_SFBR,
                                    &val_s);

                        chip_lsi_rwop(cpssp, val_s, &val_d,
                              data8, rwoperation);

                        lsi_writeb(cpssp,reg,val_d);
                        break;

                  case 0x6: /* move byte to SFBR */
                        /* &source, &target, data, operator */
                        lsi_readb(cpssp, reg, &val_s);

                        chip_lsi_rwop(cpssp, val_s, &val_d,
                              data8, rwoperation);

                        lsi_writeb(cpssp,REG_SFBR, val_d);
                        break;

                  case 0x7: /* Read modifiy write byte */
                        /* &source, &target, data, operator */
                        lsi_readb(cpssp, reg, &val_s);

                        chip_lsi_rwop(cpssp, val_s, &val_d,
                              data8, rwoperation);

                        lsi_writeb(cpssp,reg,val_d);
                        break;

                  default:
                        TRACE(DEBUG_SCRIPTS, 
                              "INVALID R/W OPCODE!!!%x\n",0);
                        assert(0);
                  }
                  /* incr pc */
                  *LONGCARDREG(cpssp,REG_DSP) += 8;
                  break;

            case 0xc0: /* Memory Move (with flush) */
            case 0xc1: /* Memory Move (no flush) */
                  count = (*LONGCARDREG(cpssp,REG_DBC)) & 0x00ffffff;
                  /* source address = REG_DSPS */
                  /* destination address -> REG_TEMP:
                   * although the third parameter is stored in
                   * REG_TEMP by the controller,
                   * the content of REG_TEMP has to be preserved
                   * during a MMOVE.
                   * So we use an temporary 'reg_temp' variable instead */
                  sig_pci_bus_mr(cpssp->port_pci_bus, cpssp,
                              *LONGCARDREG(cpssp,REG_DSP) + 8,
                              0xf, &reg_temp);
                  /* execute command: bytewise moving */
                  chip_lsi_mmove(cpssp,  
                              *LONGCARDREG(cpssp,REG_DSPS), 
                              reg_temp, count);
                  /* incr pc */
                  *LONGCARDREG(cpssp,REG_DSP) += 12;
                  TRACE(DEBUG_SCRIPTS, 
                        "MMOVE: %0x bytes from %0x to %0x\n",count,
                        *LONGCARDREG(cpssp,REG_DSPS),reg_temp);
                  break;

            case 0xf2: /* Register store (DSA offset) */
            case 0xe2: /* Register store (NO DSA offset) */
                  
                  /* which register? */
                  reg_lst = ((*LONGCARDREG(cpssp,REG_DBC)) & 0x00ff0000)
                     >> 16;

                  /* how many bytes to store (0..4)? */
                  count = (*LONGCARDREG(cpssp,REG_DBC)) & 0x00000007;

                  /* mem pos. */
                  if (*CHARCARDREG(cpssp,REG_DCMD) & 0x10) {
                        TRACE(DEBUG_SCRIPTS, 
                              "LOAD (DSA-RELATIVE): %0x\n",
                              0);

                        reladdr = (*LONGCARDREG(cpssp,REG_DSPS));
                        addr = *LONGCARDREG(cpssp,REG_DSA) + reladdr;
                  } else {
                        TRACE(DEBUG_SCRIPTS, 
                              "LOAD (DIRECT): %0x\n",
                              0);
                        addr = *LONGCARDREG(cpssp,REG_DSPS);
                  }

                  TRACE(DEBUG_SCRIPTS, 
                        "REGISTER STORE: %0x to %0x  count: %0x\n",
                        reg_lst, addr, count);

                  /* store it... */
                  for (_i = 0; _i < count; _i++){
                        TRACE(DEBUG_SCRIPTS_ATOMIC, "storing reg %0x to mem %0x...\n", reg_lst + _i, addr + _i);
                        data32 = *CHARCARDREG(cpssp,reg_lst + _i) << (_i & 3) * 8;
                        sig_pci_bus_mw(cpssp->port_pci_bus, cpssp, 
                                    (addr + _i) & ~3,
                                    1 << (_i & 3), data32);
                  }
                  /* incr pc */
                  *LONGCARDREG(cpssp,REG_DSP) += 8;
                  break;

            case 0xf3: /* Register load (DSA offset) */
            case 0xe3: /* Register load (no DSA offset) */
                  /* which register? */
                  reg_lst = ((*LONGCARDREG(cpssp,REG_DBC)) & 0x00ff0000)
                        >> 16;

                  /* how many bytes to load (0..4)? */
                  count = (*LONGCARDREG(cpssp,REG_DBC)) & 0x00000007;

                  /* mem pos. */
                  if (*CHARCARDREG(cpssp,REG_DCMD) & 0x10) {
                        TRACE(DEBUG_SCRIPTS, 
                              "LOAD (DSA-RELATIVE): %0x\n",
                              0);

                        reladdr = (*LONGCARDREG(cpssp,REG_DSPS));
                        addr = *LONGCARDREG(cpssp,REG_DSA) + reladdr;
                  } else {
                        TRACE(DEBUG_SCRIPTS, 
                              "LOAD (DIRECT): %0x\n",
                              0);
                        addr = *LONGCARDREG(cpssp,REG_DSPS);
                  }


                  TRACE(DEBUG_SCRIPTS,
                        "LOAD: Reg: %0x, From Mem: %0x Count: %0x\n",
                        reg_lst, addr,
                        (*LONGCARDREG(cpssp,REG_DBC)) & 0x00000007);

                  /* load maximum of 4 bytes and dispatch to registers */
                  sig_pci_bus_mr(cpssp->port_pci_bus, cpssp,
                               addr,
                              0xf, &_s);
                  _bs = 0x000000ff;
                  for (_i = 0; _i < count; _i++){
                        TRACE(DEBUG_SCRIPTS_ATOMIC,
                              "loading %0x to reg %0x...\n",
                              (_s & _bs) >> (_i * 8), reg_lst + _i);
                        *CHARCARDREG(cpssp,reg_lst + _i) = 
                                          (_s & _bs) >> (_i * 8);
                        _bs = _bs << 8;
                  }
                  /* incr pc */
                  *LONGCARDREG(cpssp,REG_DSP) += 8;
                  break;

            /* JUMP/CALL */
            case 0x80: /*(data-out-phase or nothing phase-related) */
            case 0x81: /*(data-in-phase) */
            case 0x82: /*(cmd-phase) */
            case 0x83: /*(status-phase) */
            case 0x86: /*(msg-out-phase) */
            case 0x87: /*(msg-in-phase) */
            case 0x88: /*call (nothing phase-related) */
                  TRACE(DEBUG_SCRIPTS, 
                        "EXECUTING JUMP/CALL: %0x\n",*LONGCARDREG(cpssp,REG_DBC));
                  options =(*LONGCARDREG(cpssp,REG_DBC) & 0x00ff0000) >> 16;
                  mask = ~((*LONGCARDREG(cpssp,REG_DBC) & 0x0000ff00) >> 8);
                  cmpdata = (*LONGCARDREG(cpssp,REG_DBC) & 0x000000ff);
                  jumpflag = (*LONGCARDREG(cpssp,REG_DBC) & 0x00080000) >> 19;
                  phaseflag = (*LONGCARDREG(cpssp,REG_DBC) & 0x00010000) >> 16;
                  phases = cpssp->cardregs[REG_DCMD] & 0x07;
                  opcode = (*CHARCARDREG(cpssp,REG_DCMD) & 0x38) >> 3;

                  if (! jumpflag) {
                        TRACE(DEBUG_SCRIPTS,
                              "JUMPFLAG: (JUMP IF NOT EQUAL!) %0x\n",0);
                  }

                  /* in case the jump is actually a call: */
                  /* (see below) */
                  backup_dsp = *LONGCARDREG(cpssp,REG_DSP);

                  /* do we have to wait for an unserviced phase? */
                  if (phaseflag) {
                        TRACE(DEBUG_SCRIPTS,
                              "Phaseflag set!%x\n",0);
                        if (cpssp->SCSI_unserviced) {
                              TRACE(DEBUG_SCRIPTS,
                                    "Phase valid! Continuing....%x\n",0);
#if 0
                              /* phase is considered as serviced now!*/
                              cpssp->SCSI_unserviced = false;
#endif
                        } else {
                              TRACE(DEBUG_SCRIPTS,
                                    "Waiting for a valid phase! Will reschedule command!%x\n",0);
                              cpssp->pc_restart = *LONGCARDREG(cpssp,REG_DSP);

                              /* any pending old abort-operation regarding wait_phasecomp
                               * is invalid now! */
                              cpssp->abort_wait_phasecomp = false;
                              chip_lsi_wait_phasecomp(cpssp);

                              /* SCRIPTS-interpreter will restart
                               * this command after waiting... */
                              return;
                        }
                  } 

                  switch (options) {
                  case 0x00: /* uncond. jump */
                        if (jumpflag) {
                              call_backup_dsp(cpssp, opcode, 
                                    *LONGCARDREG(cpssp,REG_DSP) + 8); /* call or jump? */

                              *LONGCARDREG(cpssp,REG_DSP) =
                                    *LONGCARDREG(cpssp,REG_DSPS);
                              TRACE(DEBUG_SCRIPTS, 
                                    "UNCOND. JUMP TAKEN TO!%0x\n",*LONGCARDREG(cpssp,REG_DSP));
                        } else {
                              /* do not branch...*/
                              *LONGCARDREG(cpssp,REG_DSP) += 8;
                              TRACE(DEBUG_SCRIPTS_ATOMIC, 
                                          "-->nobranch:%i\n",0);
                        }
                        break;

                  case 0x04: /*cond, jump, cmp SFBR, no jumpflag */
                  case 0x0c: /*cond. JUMP: cmp SFBR, jumpflag abs-adr)*/
                        /* FIX ME: DSP+4 is already in DSPS!!! */
                        sig_pci_bus_mr(cpssp->port_pci_bus, cpssp,
                                    *LONGCARDREG(cpssp,REG_DSP) + 4,
                                    0xf, &absaddr);
                        TRACE(DEBUG_SCRIPTS_ATOMIC, 
                              "(compare data, abs-jump/call if true to %i)\n", absaddr);
                        TRACE(DEBUG_SCRIPTS_ATOMIC, 
                              "(comparing SFBR:%0x, cmpdata:%0x)\n",
                              *CHARCARDREG(cpssp,REG_SFBR), cmpdata);
                        if ((jumpflag 
                          && ((cmpdata & mask) == (*CHARCARDREG(cpssp,REG_SFBR) & mask)))
                         || (! jumpflag 
                          && ((cmpdata & mask) != (*CHARCARDREG(cpssp,REG_SFBR) & mask)))) {
                              /* do a rel-branch */
                              TRACE(DEBUG_SCRIPTS_ATOMIC, 
                                          "-->branch:%i\n",0);
                              *LONGCARDREG(cpssp,REG_DSP) += 8;

                              call_backup_dsp(cpssp, opcode, 
                                    *LONGCARDREG(cpssp,REG_DSP)); /* call or jump? */

                              *LONGCARDREG(cpssp,REG_DSP) = absaddr;
                        } else {
                              /* do not branch...*/
                              *LONGCARDREG(cpssp,REG_DSP) += 8;
                              TRACE(DEBUG_SCRIPTS_ATOMIC, 
                                          "-->nobranch:%i\n",0);
                        }
                        break;

                  case 0x8c: /*(cond. JUMP: cmp SFBR, rel-adr, jumpflag)*/
                  case 0x84: /*(cond. JUMP: cmp SFBR, rel-adr)*/
                        /* FIX ME: DSP+4 is already in DSPS!!! */
                        sig_pci_bus_mr(cpssp->port_pci_bus, cpssp,
                                    *LONGCARDREG(cpssp,REG_DSP) + 4,
                                    0xf, &reladdr);
                        TRACE(DEBUG_SCRIPTS_ATOMIC, 
                              "(compare data, rel-jump/call if true to %i)\n", reladdr);
                        TRACE(DEBUG_SCRIPTS_ATOMIC, 
                              "(comparing SFBR:%0x, cmpdata:%0x)\n",
                              *CHARCARDREG(cpssp,REG_SFBR), cmpdata);
                        if (  (jumpflag  && ( (cmpdata & mask) == (*CHARCARDREG(cpssp,REG_SFBR) & mask) )) 
                           || (!jumpflag && ( (cmpdata & mask) != (*CHARCARDREG(cpssp,REG_SFBR) & mask) ))
                           ) {
                              /* do a rel-branch */
                              TRACE(DEBUG_SCRIPTS_ATOMIC, 
                                          "-->branch:%i\n",0);
                              *LONGCARDREG(cpssp,REG_DSP) += 8;

                              call_backup_dsp(cpssp, opcode, 
                                    *LONGCARDREG(cpssp,REG_DSP)); /* call or jump? */

                              *LONGCARDREG(cpssp,REG_DSP) += reladdr;
                        } else {
                              /* do not branch...*/
                              *LONGCARDREG(cpssp,REG_DSP) += 8;
                              TRACE(DEBUG_SCRIPTS_ATOMIC, 
                                          "-->nobranch:%i\n",0);
                        }
                        break;

                  case 0x88: /* uncond. jump/call rel-addr*/
                        sig_pci_bus_mr(cpssp->port_pci_bus, cpssp,
                                    *LONGCARDREG(cpssp,REG_DSP) + 4,
                                    0xf, &reladdr);
                              /* do a rel-branch */
                              TRACE(DEBUG_SCRIPTS_ATOMIC, 
                                          "UNCOND. REL-JUMP OFFSET:%d\n",reladdr);
                              *LONGCARDREG(cpssp,REG_DSP) += 8;

                              call_backup_dsp(cpssp, opcode, 
                                    *LONGCARDREG(cpssp,REG_DSP)); /* call or jump? */

                              *LONGCARDREG(cpssp,REG_DSP) += reladdr;
                        break;

                  case 0x08: /* uncond. JUMP/CALL, direct addr*/
                        /* FIX ME: DSP+4 is already in DSPS!!! */

                        call_backup_dsp(cpssp, opcode, 
                                    *LONGCARDREG(cpssp,REG_DSP) + 8); /* call or jump? */

                        sig_pci_bus_mr(cpssp->port_pci_bus, cpssp, 
                                    *LONGCARDREG(cpssp,REG_DSP) + 4,
                                    0xf, LONGCARDREG(cpssp,REG_DSP));

                        TRACE(DEBUG_SCRIPTS_ATOMIC,
                              "-->EXECUTING UNCOND. JUMP/CALL TO:%x\n",
                              *LONGCARDREG(cpssp,REG_DSP));
                        break;

                  case 0x03: /* jump on phasecmp */
                  case 0x0b: /* jump on phasecmp (jumpflag set)*/
                  case 0x0a: /* jump on phasecmp (jumpflag set, vo valid phase)*/
                        TRACE(DEBUG_SCRIPTS, 
                              "compare phases: %0x, abs-jump to :%0x\n",
                              phases,(*LONGCARDREG(cpssp,REG_DSPS)));

                        /* compare phase */
                        if ((jumpflag && (phases == cpssp->SCSI_phase))
                            || (!jumpflag && (phases != cpssp->SCSI_phase))) {

                              call_backup_dsp(cpssp, opcode, 
                                    *LONGCARDREG(cpssp,REG_DSP) + 8); /* call or jump? */

                              *LONGCARDREG(cpssp,REG_DSP) =
                                    *LONGCARDREG(cpssp,REG_DSPS);
                              TRACE(DEBUG_SCRIPTS, 
                                    "jump taken!%0x\n",0);

                        } else {
                              TRACE(DEBUG_SCRIPTS, 
                                    "NOT jumped!%0x\n",0);
                              /* incr pc */
                              *LONGCARDREG(cpssp,REG_DSP) += 8;
                        }
                        break;

                  case 0x8a: /* jump on phasecmp (jumpflag, no valid phase, relat. addr.)*/
                  case 0x82: /* jump on phasecmp (no valid phase, relat. addr.)*/
                        sig_pci_bus_mr(cpssp->port_pci_bus, cpssp,
                                    *LONGCARDREG(cpssp,REG_DSP) + 4,
                                    0xf, &reladdr);
                        TRACE(DEBUG_SCRIPTS, 
                              "compare phases: %0x, rel-jump offset :%0d\n",
                              phases,reladdr);

                        /* compare phase */
                        if ((jumpflag && (phases == cpssp->SCSI_phase))
                            || (!jumpflag && (phases != cpssp->SCSI_phase))) {
                              call_backup_dsp(cpssp, opcode, 
                                    *LONGCARDREG(cpssp,REG_DSP) + 8); /* call or jump? */

                              *LONGCARDREG(cpssp,REG_DSP) += 8;
                              *LONGCARDREG(cpssp,REG_DSP) += reladdr;

                              TRACE(DEBUG_SCRIPTS, 
                                    "jump taken!%0x\n",0);

                        } else {
                              TRACE(DEBUG_SCRIPTS, 
                                    "NOT jumped!%0x\n",0);
                              /* incr pc */
                              *LONGCARDREG(cpssp,REG_DSP) += 8;
                        }
                        break;

                  case 0x8b: /* jump on phasecmp (jumpflag set, valid phase, rel addr) */
                  case 0x83: /* jump on phasecmp (valid phase, rel addr) */
                        sig_pci_bus_mr(cpssp->port_pci_bus, cpssp,
                                    *LONGCARDREG(cpssp,REG_DSP) + 4,
                                    0xf, &reladdr);
                        TRACE(DEBUG_SCRIPTS, 
                              "compare phases: %0x, rel-jump offset :%0d\n",
                              phases,reladdr);

                        /* compare phase */
                        if ((jumpflag && (phases == cpssp->SCSI_phase))
                            || (!jumpflag && (phases != cpssp->SCSI_phase))) {

                              call_backup_dsp(cpssp, opcode, 
                                    *LONGCARDREG(cpssp,REG_DSP) + 8); /* call or jump? */

                              *LONGCARDREG(cpssp,REG_DSP) += 8;
                              *LONGCARDREG(cpssp,REG_DSP) += reladdr;

                              TRACE(DEBUG_SCRIPTS, 
                                    "jump taken!%0x\n",0);

                        } else {
                              TRACE(DEBUG_SCRIPTS, 
                                    "NOT jumped!%0x\n",0);
                              /* incr pc */
                              *LONGCARDREG(cpssp,REG_DSP) += 8;
                        }
                        break;

                  case 0x28: /* Carry test */
                        TRACE(DEBUG_SCRIPTS,
                              "CARRY TEST!%0x\n",cpssp->ALU_CARRYBIT);
                        if (
                           (jumpflag && cpssp->ALU_CARRYBIT)
                           || (!jumpflag && !cpssp->ALU_CARRYBIT)
                        ) {
                              call_backup_dsp(cpssp, opcode, 
                                    *LONGCARDREG(cpssp,REG_DSP) + 8); /* call or jump? */

                              *LONGCARDREG(cpssp,REG_DSP) =
                                    *LONGCARDREG(cpssp,REG_DSPS);
                              TRACE(DEBUG_SCRIPTS, 
                                    "jump taken!%0x\n",0);
                        } else {
                              TRACE(DEBUG_SCRIPTS, 
                                    "NOT jumped!%0x\n",0);
                              /* incr pc */
                              *LONGCARDREG(cpssp,REG_DSP) += 8;
                        }
                        break;

                  default:
                        TRACE(DEBUG_SCRIPTS, 
                              "UNKNOWN JUMP OPTION:%0x\n",
                              (*LONGCARDREG(cpssp,REG_DBC)));
                        assert(0);
                        break;
                  }

                  /* PC incremention in SWITCH-cases above!!! */
                  break;

            case 0x90: /* RETURN */
                  TRACE(DEBUG_SCRIPTS, "SCSI-SCRIPTS-RETURN: %x\n", *LONGCARDREG(cpssp,REG_DBC));

                  mode = (*LONGCARDREG(cpssp,REG_DBC) & 0x00ff0000) >> 16;
                  mask = ~((*LONGCARDREG(cpssp,REG_DBC) & 0x0000ff00) >> 8);
                  cmpdata = *LONGCARDREG(cpssp,REG_DBC) & 0x000000ff;

                  switch (mode) {
                  case 0x08: /* return uncond */
                        /* restore return-address from TEMP */
                        *LONGCARDREG(cpssp,REG_DSP) =
                                    *LONGCARDREG(cpssp,REG_TEMP);

                        TRACE(DEBUG_SCRIPTS,
                              "returning uncond to !%0x\n",
                              *LONGCARDREG(cpssp,REG_DSP));

                        break;

                  case 0x0c: /* return cmp */
                        if ((cmpdata & mask)
                           == (*CHARCARDREG(cpssp,REG_SFBR) & mask)) {

                              /* restore return-address from TEMP */
                              *LONGCARDREG(cpssp,REG_DSP) =
                                    *LONGCARDREG(cpssp,REG_TEMP);

                              TRACE(DEBUG_SCRIPTS,
                                    "returning due to cmp to %0x\n",
                                    *LONGCARDREG(cpssp,REG_DSP));
                        }
                        TRACE(DEBUG_SCRIPTS,
                              "not returning (cmp)!%x\n",0);
                        *LONGCARDREG(cpssp,REG_DSP) += 8;
                        break;

                  default: /*UNKOWN INT CONDITION */
                        TRACE(DEBUG_SCRIPTS, 
                              "UNKNOWN RETURN-COND!!:%0x\n", mode);
                        assert(0);
                        break;
                  }
                  break;

            case 0x98 ... 0x9f: /* Interrupt */
                  TRACE(DEBUG_SCRIPTS, "SCSI-SCRIPTS-INTERRUPT: %x\n",*LONGCARDREG(cpssp,REG_DBC));

                  phases = cpssp->cardregs[REG_DCMD] & 0x07;
                  mode = (*LONGCARDREG(cpssp,REG_DBC) & 0x00ff0000) >> 16;
                  mask = ~((*LONGCARDREG(cpssp,REG_DBC) & 0x0000ff00) >> 8);
                  cmpdata = *LONGCARDREG(cpssp,REG_DBC) & 0x000000ff;
                  jumpflag = (*LONGCARDREG(cpssp,REG_DBC) & 0x00080000) >> 19;
                  phaseflag = (*LONGCARDREG(cpssp,REG_DBC) & 0x00010000) >> 16;
      
                  if (! jumpflag) {
                        TRACE(DEBUG_SCRIPTS, 
                        "JUMPFLAG: (INT IF NOT EQUAL!) %0x\n",0);
                  }

                  /* inc PC */
                  /* This is crucial!
                   * The PC must already be increased in case of a potential
                   * selection timeout (INT-handler will check PC!) */
                  *LONGCARDREG(cpssp,REG_DSP) += 8;
            
                  /* do we have to wait for an unserviced phase? */
                  if (phaseflag) {
                        TRACE(DEBUG_SCRIPTS,
                              "Phaseflag set!%x\n",0);
                        if (cpssp->SCSI_unserviced) {
                              TRACE(DEBUG_SCRIPTS,
                                    "Phase valid! Continuing....%x\n",0);
#if 0
                              /* phase is considered as serviced now!*/
                              cpssp->SCSI_unserviced = false;
#endif
                        } else {
                              TRACE(DEBUG_SCRIPTS,
                                    "Waiting for a valid phase! Will reschedule command!%x\n",0);

                              cpssp->pc_restart = *LONGCARDREG(cpssp,REG_DSP) - 8;

                              /* an pending old abort-operation regarding reselection
                               * is invalid now! */
                              cpssp->abort_wait_phasecomp = false;
                              chip_lsi_wait_phasecomp(cpssp);

                              /* SCRIPTS-interpreter will restart
                               * this command after waiting... */
                              return;
                        }
                  }

                  switch (mode){
                  case 0x03: /* INT phase-cmp (phase valid) jumpifFalse*/
                        TRACE(DEBUG_SCRIPTS_ATOMIC, 
                              "cmp phases (waiting vor valid phase...): %0x\n",
                              phases);

                        /*This command will wait until there is a valid
                         * bus-phase (--> target has activated REQ).
                         * 
                         * In our case we simply wait till there arrives
                         * a new message on our virtual SCSI bus and we
                         * compare the type (or "phase") of this new message
                         * against the bus-phase indicated in 'phases'.
                         *
                         * This is an important place for timeouts!
                         * wait_phasecomp will take care of 
                         * waiting/requeueing/interrupt,... */

                        /* Let phasecompare suceed for now!
                         * (that means triggering NO interrupt in this context)
                         * for testing purposes only!*/

#if 0
                        cpssp->SCSI_unserviced = true;

                        /* is there already a valid phase? */
                        if (cpssp->SCSI_unserviced) {
                              /* will comparison of phases
                               * trigger an interrupt? */
                              /* Let it suceed for now... */
                              if (0) {
                                    TRACE(DEBUG_SCRIPTS, 
                                          "triggering INT!%x\n",0);
                                    chip_lsi_int_add(cpssp,REG_DSTAT,0x04);
                              } else { /* no? The just go on with SCRIPTS */
                                    break;
                              }

                        /* No? So just wait for a valid phase...*/
                        } else {
                              chip_lsi_wait_phasecomp(cpssp);
                              return;
                        }
#endif
                        if (! jumpflag) {
                              TRACE(DEBUG_SCRIPTS, 
                              "(CMP: INT IF NOT EQUAL!) %0x\n",0);
                        }

                        /* compare phase */
                        if ((jumpflag && (phases == cpssp->SCSI_phase))
                            || (!jumpflag && (phases != cpssp->SCSI_phase))) {
                              TRACE(DEBUG_SCRIPTS, 
                                    "triggering INT!%x\n",0);
                              chip_lsi_int_add(cpssp,REG_DSTAT,0x04);
                              return;

                        } else { /* no? The just go on with SCRIPTS */
                              TRACE(DEBUG_SCRIPTS, 
                                    "NOT triggering INT!%x\n",0);
                        }
                        break;

                  case 0x08: /* INT uncond, jumpifTrue */
                        TRACE(DEBUG_SCRIPTS, 
                              "triggering INT!%x\n",0);
                        chip_lsi_int_add(cpssp,REG_DSTAT,0x04);
                        return;

                  case 0x18: /* INT FLY */
                        TRACE(DEBUG_SCRIPTS, 
                              "triggering INT-ON-THE-FLY!%x\n",0);
                        chip_lsi_int_add(cpssp,REG_ISTAT,ISTAT_INTF);

                        /* After an interrupt we give the
                         * simulator-core the chance to react...*/
                        cpssp->scripts_counter = MAX_SCRIPTS_EXE;
                        break;

                  case 0x0c: /* INT data-cmp */
                  case 0x04: /* INT data-cmp */
                        if ((jumpflag
                          && ((cmpdata & mask) == (*CHARCARDREG(cpssp,REG_SFBR) & mask)))
                         || (! jumpflag
                          && ((cmpdata & mask) != (*CHARCARDREG(cpssp,REG_SFBR) & mask)))) {
                              TRACE(DEBUG_SCRIPTS, 
                                    "triggering INT (cmp)!%x\n",0);
                              chip_lsi_int_add(cpssp,REG_DSTAT,0x04);
                              return;
                        }
                        TRACE(DEBUG_SCRIPTS, 
                              "not triggering INT (cmp)%x\n",0);
                        break;

                  default: /*UNKOWN INT CONDITION */
                        TRACE(DEBUG_SCRIPTS, "UNKNOWN IRQ-COND!!:%0x\n",
                              mode);
                        assert(0);
                        break;
                  }
                  break;

            default: /* UNKOWN SCSI SCRIPTS OPCODE */
                   /* This should never happen! */
                  fprintf(stderr, "UNKNOWN OPCODE: DCMD: %0x\n",
                              *CHARCARDREG(cpssp,REG_DCMD));
                  fprintf(stderr, "(DCMD-DBC): %0x\n",
                              *LONGCARDREG(cpssp,REG_DBC));
                  assert(0);
            };

      }

      /* ah, while() is exiting: Seems we have reached MAX_SCRIPTS_EXE,
       * so reschedule SCRIPTS execution, it will continue later.
       * --> timer_event() will handle this...*/

      /* new round... */
      cpssp->scripts_counter = 0;

      TRACE(DEBUG_TIMER, "***** MAX_SCRIPT_EXE REACHED: RESCHEDULING SCRIPTS... %0x\n",0);
      time_call_at(time_virt() + TSYNC_INTERVAL_SCRIPTS,
                        timer_event, cpssp);

      return;
}


static void
chip_lsi_53C810_reset_chip(struct cpssp *cpssp)
{
      cpssp->scripts_counter = 0;
      cpssp->pc_restart = 0;
      cpssp->backup_i_counter = 0;
      cpssp->SCSI_phase = 0;

      memset(cpssp->cardregs, 0, sizeof(cpssp->cardregs));
      cpssp->cardregs[REG_SCNTL0] = 0xc0;

      memset(cpssp->scsi_io_buf, 0, sizeof(cpssp->scsi_io_buf));
      memset(cpssp->int_queue_sist0, 0, sizeof(cpssp->int_queue_sist0));
      memset(cpssp->int_queue_sist1, 0, sizeof(cpssp->int_queue_sist1));
      memset(cpssp->int_queue_dstat, 0, sizeof(cpssp->int_queue_dstat));
      cpssp->int_sist0_depth = 0;
      cpssp->int_sist1_depth = 0;
      cpssp->int_dstat_depth = 0;
      cpssp->scripts_running = false;
      cpssp->ALU_CARRYBIT = 0;
      cpssp->int_active = 0;
      cpssp->abort_wait_reselect = false;
      cpssp->abort_wait_phasecomp = false;
      cpssp->delayed_transfer = false;
      cpssp->pending_transfer = false;
      cpssp->SCSI_phase_change = false;
      cpssp->backup_phase_status = false;
      cpssp->SCSI_initiated = false;
      cpssp->SCSI_selected = false;
      cpssp->SCSI_reselected = false;
      cpssp->SCSI_unserviced = false;
      cpssp->SCSI_data_to_target = 0;
      cpssp->SCSI_data_from_target = 0;
      cpssp->timertick_h2h = 0;
      cpssp->timertick_sel = 0;
      cpssp->timertick_gen = 0;
      cpssp->timerset_h2h = 0;
      cpssp->timerset_sel = 0;
      cpssp->timerset_gen = 0;

      TRACE(DEBUG_OTHER,  "LSI 53C810 Card resetted!%x\n",0);
}

/* ============ PCI-CONFSPACE Section ================ */

static int
chip_lsi_53C810_cread0(
      void *_cpssp, 
      uint32_t addr, 
      unsigned int bs,
      uint32_t *valp
)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;
      addr &= 0x7ff;

      /* allow only valid access to CONF-Space */
      if (addr > 255) {
            TRACE(DEBUG_CONFSPACE, 
                  "IGNORED CONFSPACE-ACCESS TO ADDR: %0x\n",
                  addr);
            *valp = 0;
            return -1;
      }

      *valp = 0x00000000;
      if ((bs >> 0) & 1) {
            *valp |= pci_getconfigb(cpssp->config_space, addr + 0) << 0;
      }
      if ((bs >> 1) & 1) {
            *valp |= pci_getconfigb(cpssp->config_space, addr + 1) << 8;
      }
      if ((bs >> 2) & 1) {
            *valp |= pci_getconfigb(cpssp->config_space, addr + 2) << 16;
      }
      if ((bs >> 3) & 1) {
            *valp |= pci_getconfigb(cpssp->config_space, addr + 3) << 24;
      }
      TRACE(DEBUG_CONFSPACE, 
            "CSPACE READ: Addr: %0x Value: %0x BS: %0x\n",
            addr, *valp, bs);

return 0;
}


static int
chip_lsi_53C810_cwrite0(
      void *_cpssp,
      uint32_t addr,
      unsigned int bs,
      uint32_t val
)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;
      uint32_t val32;
      uint32_t oaddr;
      uint32_t naddr;

      addr &= 0x7ff;

      val32 = cpssp->config_space[addr >> 2];
      if ((bs >> 0) & 1) {
            val32 &= ~(0xff << 0);
            val32 |= val & (0xff << 0);
      }
      if ((bs >> 1) & 1) {
            val32 &= ~(0xff << 8);
            val32 |= val & (0xff << 8);
      }
      if ((bs >> 2) & 1) {
            val32 &= ~(0xff << 16);
            val32 |= val & (0xff << 16);
      }
      if ((bs >> 3) & 1) {
            val32 &= ~(0xff << 24);
            val32 |= val & (0xff << 24);
      }

      TRACE(DEBUG_CONFSPACE, "CSPACE WRITE: Addr: %0x Value:%0x BS:%0x\n",
            addr, val32, bs);

      switch (addr) {
      case PCI_CACHE_LINE_SIZE: /* actually 4 * 8 bit registers */
            val32 &= 0x0000FF18; /* filter the hardwired to 0-bits */
            cpssp->config_space[addr >> 2] = val32;
            TRACE(DEBUG_CONFSPACE,  "WRITE CACHELINESIZE: %0x\n",val32);
            break;
      case PCI_COMMAND:
            /* set default bits */
#if 0
            val32 |= 0x100; /* only bit 8 */
#endif
#if 0
            val32 |= 0x40; /* only bit 6 */
#endif
            /* Just filter the hardwired-to-0/unimplemented bits */
            /* val32 &= 0x157; */
#if 0
            pci_setconfigw(cpssp->config_space, addr & 0xff, val32 & 0xffff);
            /* FIX ME: Statusregister */
#endif
            pci_setconfigl(cpssp->config_space, addr, val32);
            TRACE(DEBUG_CONFSPACE,  "WRITE PCI_COMMAND: %0x\n",val32);
            break;
      case PCI_BASE_ADDRESS_1: /* Request 4 KB Memory space */
            oaddr = ((uint32_t)(cpssp->config_space[PCI_BASE_ADDRESS_1>>2]
                            & PCI_BASE_ADDRESS_MEM_MASK));
            cpssp->config_space[addr >> 2] = pci_requestspace(val32, 4096,
                                    PCI_BASE_ADDRESS_SPACE_MEMORY
                                    | PCI_BASE_ADDRESS_MEM_TYPE_32);
            naddr = ((uint32_t)(cpssp->config_space[PCI_BASE_ADDRESS_1>>2]
                            & PCI_BASE_ADDRESS_MEM_MASK));
            if (oaddr != naddr) {
                  /* Re-map old/new region. */
                  sig_pci_bus_unmap(cpssp->port_pci_bus, cpssp, oaddr, 4096);
                  sig_pci_bus_unmap(cpssp->port_pci_bus, cpssp, naddr, 4096);
            }
            TRACE(DEBUG_CONFSPACE, "WRITE BASE-ADDRESS_0:%0x,Using: %0x\n",
                 val32, ((uint32_t)(cpssp->config_space[PCI_BASE_ADDRESS_1>>2]
                                & PCI_BASE_ADDRESS_MEM_MASK)) );
            break;
      case PCI_BASE_ADDRESS_0: /* Request 96 IO Ports */
            cpssp->config_space[addr >> 2] = pci_requestspace(val32, 128,
                                    PCI_BASE_ADDRESS_SPACE_IO);
            TRACE(DEBUG_CONFSPACE, 
                  "WRITE IO-ADDRESS: %0x,  Using: %0x\n",
                  val32, ((uint16_t)((cpssp->config_space[PCI_BASE_ADDRESS_0
                                                      >> 2]
                  & PCI_BASE_ADDRESS_IO_MASK)&0x0000ffff)));
            break;
      case PCI_BASE_ADDRESS_2: /* used by flash rom (request 1 MB) */
            TRACE(DEBUG_CONFSPACE,  
                        "WRITE BASE-ADDRESS 2 (ignoring): %0x\n",val32);
            break;
      case PCI_ROM_ADDRESS: /* ROM address (bootrom) */
            oaddr = cpssp->config_space[PCI_ROM_ADDRESS >> 2]
                  & PCI_ROM_ADDRESS_MASK;
            cpssp->config_space[addr>>2] = pci_requestspace(val,
                                          SZ_53CROMREQUEST, 0);
            cpssp->config_space[addr>>2] &= PCI_ROM_ADDRESS_MASK;
            cpssp->config_space[addr>>2] |= val & PCI_ROM_ADDRESS_ENABLE;
            naddr = cpssp->config_space[PCI_ROM_ADDRESS >> 2]
                  & PCI_ROM_ADDRESS_MASK;
            if (oaddr != naddr) {
                  /* Re-map new region. */
                  sig_pci_bus_unmap(cpssp->port_pci_bus, cpssp,
                              oaddr, SZ_53CROMREQUEST);
                  sig_pci_bus_unmap(cpssp->port_pci_bus, cpssp,
                              naddr, SZ_53CROMREQUEST);
            }
            TRACE(DEBUG_CONFSPACE,
                  "Now Using ROM-Addr 0x%08x\n",
                  (uint32_t) (cpssp->config_space[addr >> 2] ));
            break;
      case PCI_INTERRUPT_LINE: /* actually 4 * 8 bit registers */
            /* only 8 bit of this are writeable */
            pci_setconfigb(cpssp->config_space, addr, val32 & 0xff);
            TRACE(DEBUG_CONFSPACE, "SET INTERRUPTLINE: %0x\n",val32 & 0xff);
            break;
      case PCI_REVISION_ID:
      case PCI_BASE_ADDRESS_3: /* unused */
      case PCI_BASE_ADDRESS_4: /* unused */
      case PCI_BASE_ADDRESS_5: /* unused */
      case 0x28:         /* reserved */
      case PCI_VENDOR_ID:      /* 16 bit Vendor ID and 16 bit Device ID */
      case PCI_SUBSYSTEM_VENDOR_ID:
      case PCI_CAPABILITY_LIST:/* not supported */
      case 0x38:         /* reserved */
      case 0x40 ... 0xfc:      /* unused/reserved */
            /* All the registers above are write-protected or
             * hard-wired to 0. That's why we ignore the write. */
            break;
      default:
            TRACE(DEBUG_CONFSPACE,  
             "UNKNOW CSPAVE WRITE: addr: %02x, val: %08x\n",
             addr, val32);
            break;
      };

      return 0;
}

/* ================= I/O Section ========================= */

/*
 * portread(), portwrite():
 * byteselect-based access to card-registers
 */
static void
chip_lsi_53C810_portread(
      struct cpssp *cpssp,
      uint32_t port,
      unsigned int bs,
      uint32_t *valp
)
{
      *valp = 0x00000000;

      /* Little Helper Makro:
       * reads 8bit-value from bs-specified byte-position.
       * We use this to just read from registers without
       * triggering further actions... */
#define _BS_REG_READ(_pos) \
      *valp |= cpssp->cardregs[port + _pos] << (_pos * 8); \
      TRACE(DEBUG_IO, "reading %s-register... (%0x) \n", \
                  reg_names[port + _pos], \
                  cpssp->cardregs[port + _pos]);

      switch (port) {
      case 0x0c:
            if ((bs >> 0) & 1) {
                  /* DSTAT */
                  _BS_REG_READ(0)
                  chip_lsi_int_del(cpssp,REG_DSTAT);
            }
            if ((bs >> 1) & 1) { _BS_REG_READ(1) }
            if ((bs >> 2) & 1) { _BS_REG_READ(2) }
            if ((bs >> 3) & 1) { _BS_REG_READ(3) }
            break;
      case 0x18:
            if ((bs >> 0) & 1) { _BS_REG_READ(0) }
            if ((bs >> 1) & 1) { _BS_REG_READ(1) }
            if ((bs >> 2) & 1) { /* CTEST2 */
                  _BS_REG_READ(2)
                  /* clear SIGP in ISTAT and CTEST2! */
                  cpssp->cardregs[REG_ISTAT]&=~0x20;
                  cpssp->cardregs[REG_CTEST2]&=~0x40;
            }
            if ((bs >> 3) & 1) {
                  _BS_REG_READ(3)
                  *valp |= (REVISION << 4) << 24;
            }
            break;
      case 0x40: /* SIST1, SIST0, SIEN1, SIEN0 */
            if ((bs >> 0) & 1) { _BS_REG_READ(0) }
            if ((bs >> 1) & 1) { _BS_REG_READ(1) }
            if ((bs >> 2) & 1) { /* SIST0 */
                  _BS_REG_READ(2) 
                  chip_lsi_int_del(cpssp,REG_SIST0);
            }
            if ((bs >> 3) & 1) { /*SIST1 */
                  _BS_REG_READ(3) 
                  chip_lsi_int_del(cpssp,REG_SIST1);
            }
            break;

      /* Just read-out register-values... */
      default:
            if ((bs >> 0) & 1) { _BS_REG_READ(0) }
            if ((bs >> 1) & 1) { _BS_REG_READ(1) }
            if ((bs >> 2) & 1) { _BS_REG_READ(2) }
            if ((bs >> 3) & 1) { _BS_REG_READ(3) }
            break;
      }
}

static void
chip_lsi_53C810_portwrite(
      struct cpssp *cpssp,
      uint32_t port,
      unsigned int bs,
      uint32_t val
)
{
      uint8_t val8 = 0;
      uint8_t backup_reg = 0;

      /* helper vars */
      uint8_t val8_pre = 0;

      /* Little Helper Makro:
       * writes 8bit-value to bs-specified byte-position.
       * We use this to just write into registers without
       * triggering further actions... */
#define _BS_REG_WRITE(_pos) \
      val8 =  (val & (0x000000ff << (_pos * 8) ) ) >> (_pos * 8); \
      cpssp->cardregs[port + _pos] = val8; \
      TRACE(DEBUG_IO, "writing %s-register... (%0x) \n", \
                  reg_names[port + _pos], \
                  cpssp->cardregs[port + _pos] ); 

      switch (port) {
      case 0x00: /* Only SCNTL1-Register (BS 1) needs special treatment: */
            if ((bs >> 0) & 1) { _BS_REG_WRITE(0) }

            if ((bs >> 1) & 1) {
                  val8 = (val & 0x0000ff00) >> 8;
                  cpssp->cardregs[port + 1] = val8;
                  TRACE(DEBUG_IO, "writing %s-register... (%0x) \n",
                              reg_names[port + 1],
                              cpssp->cardregs[port + 1] );
                  if (val8 & 0x8) { /* Trigger scsi-reset: */
                        /*for now, only set the scsi-status register! */
                        /* Triggers also Interrupt */
                        TRACE(DEBUG_IO, 
                              "RESETTING SCSIBUS....(%0x) \n",val8);
                        cpssp->cardregs[REG_SSTAT0] |= 0x2;
                        chip_lsi_int_add(cpssp,REG_SIST0,0x02);
                  } else {
                        cpssp->cardregs[REG_SSTAT0] &= ~0x2;
                        /*
                         * "SCSI reset detected" is edge triggered
                         * interrupt. FIXME
                         */
                        // chip_lsi_int_del(cpssp,REG_SIST0);
                  }
             }

            if ((bs >> 2) & 1) { _BS_REG_WRITE(2) }
            if ((bs >> 3) & 1) { _BS_REG_WRITE(3) }
            break;
      case 0x04: /* SCID, SXFER, SDID, GPREG */
            /* filter out RESERVED bits */
            val &= 0x03ffffff;

            if ((bs >> 0) & 1) { _BS_REG_WRITE(0) }
            if ((bs >> 1) & 1) { _BS_REG_WRITE(1) }
            if ((bs >> 2) & 1) { _BS_REG_WRITE(2) }
            if ((bs >> 3) & 1) { _BS_REG_WRITE(3) }

            break;

      case 0x0c: /* DSTAT, STAT0, STAT1, STAT1 are readonly-registers! */
            TRACE(DEBUG_IO, 
                        "ignoring portwrite to readonly register: bd: %0x, bs: %0x, val: %0x\n",
                        port, bs, val);
            break;

      case 0x14: /* ISTAT and reserved*/
            if ((bs >> 0) & 1) { 
                  /* backup INT status-bits */
                  backup_reg = cpssp->cardregs[port];

                  val8 = (val & 0x000000ff);
                  cpssp->cardregs[port] = val8;
                  TRACE(DEBUG_IO, "writing %s-register... (%0x) \n", 
                              reg_names[port],
                              cpssp->cardregs[port] ); 

                  /* restore INT status-bits */
                  cpssp->cardregs[port] &= ~0x7;
                  cpssp->cardregs[port] |= (backup_reg & 0x07);

                  /* set SIGP in CTEST2
                   * depending on SIGP in ISTAT */
                  if (cpssp->cardregs[REG_ISTAT] & 0x20) {
                        cpssp->cardregs[REG_CTEST2] |= 0x40;
                  }

                  if (val8 & 0x04) {
                        /* INT-FLY Reset */
                        chip_lsi_int_del(cpssp, REG_ISTAT);
                  }

                  if (val8 & 0x40) {
                        /* Reset Chip */
                        chip_lsi_53C810_reset_chip(cpssp);
                  }

                  if (val8 & 0x80) { /* ABORT */
                        TRACE(DEBUG_IO, 
                              "PROPAGATING ABORT OPERATION! %0x\n",
                              0);
                        /* We need to tell all sceduled tasks about
                         * the abort-operation! */
                        cpssp->abort_wait_reselect = true;
                        cpssp->abort_wait_phasecomp = true;

                        chip_lsi_int_add(cpssp, REG_DSTAT, 0x10);
                        /* Stop all timers! */
                        cpssp->timertick_sel = 0;
                        cpssp->timerset_sel = 0;
                        cpssp->timertick_h2h = 0;
                        cpssp->timerset_h2h = 0;
                        cpssp->timertick_gen = 0;
                        cpssp->timerset_gen = 0;
                  }
#if 0
                  /* the int-status-bits were overwritten at this time,
                   * so reset the int-status-bits 
                   * according to their status-registers...*/
                  TRACE(DEBUG_IO, 
                        "WRITE ON ISTAT: RECALCULATING INT-BITS! %0x\n",
                        0);
                  chip_lsi_int_trigger(cpssp);
#endif
            }
            if ((bs >> 1) & 1) { _BS_REG_WRITE(1) }
            if ((bs >> 2) & 1) { _BS_REG_WRITE(2) }
            if ((bs >> 3) & 1) { _BS_REG_WRITE(3) }
            break;

      case 0x18: /* CTEST-Register (32-bits) */
            if ((bs >> 0) & 1) { _BS_REG_WRITE(0) }
            if ((bs >> 1) & 1) { _BS_REG_WRITE(1) }
            if ((bs >> 2) & 1) { _BS_REG_WRITE(2) }
            if ((bs >> 3) & 1) {
                  /* CTEST3 */
                  /* Bit 7-4 are read-only (REVISION). */
                  val &= ~(0xf << (4+24));

                  if ((val >> (3+24)) & 1) {
                        /* Flush DMA FIFO */
                  }
                  if ((val >> (2+24)) & 1) {
                        /* Clear DMA FIFO */

                        /* Bit is self-clearing. */
                        val &= ~(1 << (2+24));
                  }

                  _BS_REG_WRITE(3)
            }
            break;

      case 0x2c: /* DSP-Register (32-bits) */
            if ((bs >> 0) & 1) { _BS_REG_WRITE(0) }
            if ((bs >> 1) & 1) { _BS_REG_WRITE(1) }
            if ((bs >> 2) & 1) { _BS_REG_WRITE(2) }
            if ((bs >> 3) & 1) { _BS_REG_WRITE(3) }
             /* After DSP-registervalues are set, start SCRIPTS */
            cpssp->scripts_running = true;
            chip_lsi_53C810_start_SCRIPTS(cpssp);
            break;

      case 0x38: /* DMODE, DIEN, SBR, DCNTL */
            if ((bs >> 0) & 1) { _BS_REG_WRITE(0) }
            if ((bs >> 1) & 1) { _BS_REG_WRITE(1) }
            if ((bs >> 2) & 1) { _BS_REG_WRITE(2) }
            if ((bs >> 3) & 1) { 
                  _BS_REG_WRITE(3)
                  /* Restart SCRIPTS? */
                  if (val8 & 0x04) {
                        TRACE(DEBUG_IO, 
                          "STD set, restarting SCRIPTS: %0x \n",val8);
                        cpssp->scripts_running = true;
                        chip_lsi_53C810_start_SCRIPTS(cpssp);
                  }
            }
            break;

      case 0x48: /* STIME0, STIME1, RESPID */
            if ((bs >> 0) & 1) {
                  /* get the previous value...*/
                  val8_pre = cpssp->cardregs[REG_STIME0];

                  _BS_REG_WRITE(0)

                  /* Note: Timers get only activated if
                   * they were previously resetted (written to 0) */

                  /* activate sel-timer? */
                  if (((val8_pre & 0x0f) == 0)
                      && (val8 & 0x0f)) {
                        TRACE(DEBUG_IO, 
                          "SEL-timer set (not yet running...): %0x \n",val8);
                        /* Selection Timer activated! */
                        cpssp->timertick_sel = 0;
#if 0
                        cpssp->timerset_sel = calc_timer_nano(val8 & 0x0f);
#endif

                        /* the timer gets started later on a SELECT... */
                        cpssp->timerset_sel = 0;
                  } else if ( ((val8 & 0x0f) == 0)
                        &&  (val8_pre & 0x0f)) {
                        TRACE(DEBUG_IO, 
                          "SEL-timer deactivated!: %0x \n",0);
                        /* deactivate timer */
                        cpssp->timertick_sel = 0;
                        cpssp->timerset_sel = 0;
                  }

                  /*activate h2h-timer? */
                  if (((val8_pre & 0xf0) == 0)
                      && (val8 & 0xf0)) {
                        TRACE(DEBUG_IO, 
                          "H2H-timer set (not yet running...): %0x \n",val8);
                        /* Selection Timer activated! */
                        cpssp->timertick_h2h = 0;
#if 0
                        cpssp->timerset_h2h = calc_timer_nano((val8 & 0xf0) >> 4);
#endif
                        /* the timer gets started later (on h2h?)... */
                        cpssp->timerset_h2h = 0;
                        assert(0);
                  } else if ( ((val8 & 0xf0) == 0)
                        &&  (val8_pre & 0xf0) ){
                        TRACE(DEBUG_IO, 
                          "H2H-timer deactivated!: %0x \n",0);
                        /* deactivate timer */
                        cpssp->timertick_h2h = 0;
                        cpssp->timerset_h2h = 0;
                  }

            }
            if ((bs >> 1) & 1) { 
                  /* get the previous value...*/
                  val8_pre = cpssp->cardregs[REG_STIME1];

                  _BS_REG_WRITE(1) 
                  /* Note: Timers get only activated if
                   * they were previously resetted (written to 0) */

                  /* activate gen-timer? */
                  if (((val8_pre & 0x0f) == 0)
                      && (val8 & 0x0f)) {
                        TRACE(DEBUG_IO, 
                          "GEN-timer activated!: %0x \n",val8);
                        cpssp->timertick_gen = 0;
                        cpssp->timerset_gen = calc_timer_nano(val8 & 0x0f);
                        timer_tick(cpssp);
                  } else if ( ((val8 & 0x0f) == 0)
                        && (val8_pre & 0x0f) ){
                        TRACE(DEBUG_IO, 
                          "GEN-timer deactivated!: %0x \n",0);
                        /* deactivate timer */
                        cpssp->timertick_gen = 0;
                        cpssp->timerset_gen = 0;
                  }

            }
            if ((bs >> 2) & 1) { _BS_REG_WRITE(2) }
            if ((bs >> 3) & 1) { _BS_REG_WRITE(3) }

            break;

      default: /* Default: Just write the 8bit-values into the cardregs
                (depending on bs), without triggering further actions... */
            if ((bs >> 0) & 1) { _BS_REG_WRITE(0) }
            if ((bs >> 1) & 1) { _BS_REG_WRITE(1) }
            if ((bs >> 2) & 1) { _BS_REG_WRITE(2) }
            if ((bs >> 3) & 1) { _BS_REG_WRITE(3) }
            break;
      }
}


/* small wrappers for bytewise register-access */
/* some SCRIPTS functions need this... */
static void
lsi_readb(struct cpssp *cpssp, uint16_t port, uint8_t *val)
{
      uint32_t val32 = 0;

      chip_lsi_53C810_portread(cpssp,
                  (port >> 2) << 2, 1 << (port & 0x03), &val32);
      *val = val32 >> (port & 0x03) * 8;
}

static void
lsi_writeb(struct cpssp *cpssp, uint16_t port, uint8_t val)
{
      uint32_t val32 = val << (port & 0x03) * 8;

      chip_lsi_53C810_portwrite(cpssp,
                  (port >> 2) << 2, 1 << (port & 0x03), val32);
}


/* PCI-Interface functions:
 * ior, iow, read, write */
static int
chip_lsi_53C810_iow(void *_cpssp, uint32_t portaddr, unsigned int bs, uint32_t val)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;
      uint32_t iobase;
      uint32_t iolimit;
      uint32_t port;

      /* card IO enabled? */
      if ( (pci_getconfigb(cpssp->config_space, PCI_COMMAND) & 0x01) == 0 ) {
            return -1;
      }

      iobase = LSI53C810IOADDR(cpssp);
      iolimit = LSI53C810IOADDR(cpssp) + SZ_53C810MEM;

      if (iobase <= portaddr && portaddr < iolimit){
            port = portaddr - iobase;
      } else return -1;

      chip_lsi_53C810_portwrite(cpssp, port, bs, val);
      return 0;

}

static int
chip_lsi_53C810_ior(
      void *_cpssp,
      uint32_t portaddr,
      unsigned int bs,
      uint32_t *valp
)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;
      uint32_t iobase;
      uint32_t iolimit;
      uint32_t port;

      /* card IO enabled? */
      if ( (pci_getconfigb(cpssp->config_space, PCI_COMMAND) & 0x01) == 0 ) {
            return -1;
      }

      iobase = LSI53C810IOADDR(cpssp);
      iolimit = LSI53C810IOADDR(cpssp) + SZ_53C810MEM;

      if (iobase <= portaddr && portaddr < iolimit){
            port = portaddr - iobase;
      } else return -1;
      
      chip_lsi_53C810_portread(cpssp, port, bs, valp);
      return 0;
}

/* ====================== READ/WRITE Section ===================== */

static int
chip_lsi_53C810_read(
      void *_cpssp,
      uint32_t portaddr,
      unsigned int bs,
      uint32_t *valp
)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;
      uint32_t membase;
      uint32_t memlimit;
      uint32_t port;

      membase = LSI53C810MEMADDR(cpssp);
      memlimit = LSI53C810MEMADDR(cpssp) + SZ_53C810MEM;

      if (membase <= portaddr && portaddr < memlimit) {
            port = portaddr - membase;
            chip_lsi_53C810_portread(cpssp, port, bs, valp);

      } else if ((cpssp->config_space[PCI_ROM_ADDRESS>>2] & PCI_ROM_ADDRESS_ENABLE)
             && LSI53C810ROMADDR(cpssp) <= portaddr
             && portaddr < LSI53C810ROMADDR(cpssp) + SZ_53CROMREQUEST) {
            portaddr %= SZ_53CROMREQUEST;
            *valp = 0;
            if ((bs >> 0) & 1) {
                  *valp |= cpssp->bootrom[portaddr + 0] << 0;
            }
            if ((bs >> 1) & 1) {
                  *valp |= cpssp->bootrom[portaddr + 1] << 8;
            }
            if ((bs >> 2) & 1) {
                  *valp |= cpssp->bootrom[portaddr + 2] << 16;
            }
            if ((bs >> 3) & 1) {
                  *valp |= cpssp->bootrom[portaddr + 3] << 24;
            }
      } else {
            return -1;
      }

      return 0;
}

static int
chip_lsi_53C810_write(
      void *_cpssp,
      uint32_t portaddr,
      unsigned int bs,
      uint32_t val
)
{
      uint32_t membase;
      uint32_t memlimit;
      uint32_t port;
      struct cpssp *cpssp = (struct cpssp *) _cpssp;

      membase = LSI53C810MEMADDR(cpssp);
      memlimit = LSI53C810MEMADDR(cpssp) + SZ_53C810MEM;

      if (membase <= portaddr
       && portaddr < memlimit) {
            port = portaddr - membase;
      } else {
            return -1;
      }

      chip_lsi_53C810_portwrite(cpssp, port, bs, val);
      return 0;
}


/*
 * ============= MAPPING Section =================
 */

static int
chip_lsi_53C810_map(
      void *_cpssp,
      unsigned long pa,
      unsigned int len,
      char **haddr_mr_p,
      char **haddr_mw_p
)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;

      if ((cpssp->config_space[PCI_COMMAND >> 2] & PCI_COMMAND_MEMORY) == 0) {
            return -1;
      }
      if (LSI53C810MEMADDR(cpssp) != 0x0000
       && LSI53C810MEMADDR(cpssp) <= pa
       && pa < LSI53C810MEMADDR(cpssp) + SZ_53C810MEM) {
            /* don't map but simulate access instead. */
            *haddr_mr_p = NULL;
            *haddr_mw_p = NULL;
            return 0;
      }

      if (cpssp->config_space[PCI_ROM_ADDRESS>>2] & PCI_ROM_ADDRESS_ENABLE
       && LSI53C810ROMADDR(cpssp) <= pa
       && pa < LSI53C810ROMADDR(cpssp) + SZ_53CROMREQUEST) {
            /* don't map but simulate access instead. */
            *haddr_mr_p = NULL;
            *haddr_mw_p = NULL;
            return 0;
      }

      return 1;
}

/* =================== SCSI-Bus ======================== */

static int
chip_lsi_53C810_phase_select(void *_cpssp, uint32_t id)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;

      if (id == cpssp->cardregs[REG_SCID]) {
            /* The controller is always the Initiator! */
            TRACE(DEBUG_SCSIBUS, "Tried to select the Controller!!!%0x \n", id);
            assert(0);
      }
      return 0;
}

static int
chip_lsi_53C810_phase_reselect(void *_cpssp, uint32_t id)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;

      if (id == cpssp->cardregs[REG_SCID]) {
            /* RESELECT not yet supported */
            TRACE(DEBUG_SCSIBUS, "RESELECT not working yet!%0x \n", id);
            assert(0);
            /* cpssp->SCSI_initiated = true */
      }
      return 0;
}

static void
chip_lsi_53C810_phase_msg_out(void *_cpssp)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;

      cpssp->SCSI_phase = SCSI_PHASE_MESSAGE_OUT;
      cpssp->SCSI_unserviced = true;
      TRACE(DEBUG_SCSIBUS, "LSI detected PHASE-MSG-OUT!!%0x \n", 0);

      /* indicate phasechange (needed for old-semantik-style scsi-disk)! */
      cpssp->SCSI_phase_change = !(cpssp->SCSI_phase_change);

      chip_lsi_check_phase_mismatch(cpssp);
}

static void
chip_lsi_53C810_phase_msg_in(void *_cpssp)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;

      cpssp->SCSI_phase = SCSI_PHASE_MESSAGE_IN;
      cpssp->SCSI_unserviced = true;
      TRACE(DEBUG_SCSIBUS, "LSI detected PHASE-MSG-IN!!%0x \n", 0);

      /* indicate phasechange (needed for old-semantik-style scsi-disk)! */
      cpssp->SCSI_phase_change = !(cpssp->SCSI_phase_change);

      chip_lsi_check_phase_mismatch(cpssp);
}

static void
chip_lsi_53C810_phase_command(void *_cpssp)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;

      cpssp->SCSI_phase = SCSI_PHASE_COMMAND;
      cpssp->SCSI_unserviced = true;
      TRACE(DEBUG_SCSIBUS, "LSI detected PHASE-COMMAND!!%0x \n", 0);

      /* indicate phasechange (needed for old-semantik-style scsi-disk)! */
      cpssp->SCSI_phase_change = !(cpssp->SCSI_phase_change);

      chip_lsi_check_phase_mismatch(cpssp);
}

static void
chip_lsi_53C810_phase_data_out(void *_cpssp)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;

      cpssp->SCSI_phase = SCSI_PHASE_DATA_OUT;
      cpssp->SCSI_unserviced = true;
      TRACE(DEBUG_SCSIBUS, "LSI detected PHASE-DATA-OUT!!%0x \n", 0);

      /* indicate phasechange (needed for old-semantik-style scsi-disk)! */
      cpssp->SCSI_phase_change = !(cpssp->SCSI_phase_change);

      chip_lsi_check_phase_mismatch(cpssp);
}

static void
chip_lsi_53C810_phase_data_in(void *_cpssp)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;

      cpssp->SCSI_phase = SCSI_PHASE_DATA_IN;
      cpssp->SCSI_unserviced = true;
      TRACE(DEBUG_SCSIBUS, "LSI detected PHASE-DATA-IN!!%0x \n", 0);

      /* indicate phasechange (needed for old-semantik-style scsi-disk)! */
      cpssp->SCSI_phase_change = !(cpssp->SCSI_phase_change);

      chip_lsi_check_phase_mismatch(cpssp);
}

static void
chip_lsi_53C810_phase_status(void *_cpssp)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;

      cpssp->SCSI_phase = SCSI_PHASE_STATUS;
      cpssp->SCSI_unserviced = true;
      TRACE(DEBUG_SCSIBUS, "LSI detected PHASE-STATUS!!%0x \n", 0);

      /* indicate phasechange (needed for old-semantik-style scsi-disk)! */
      cpssp->SCSI_phase_change = !(cpssp->SCSI_phase_change);

      chip_lsi_check_phase_mismatch(cpssp);
}

static void
chip_lsi_53C810_phase_free(void *_cpssp)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;

      /* There was a bus-free phase, so there is no longer a running transaction! */
      TRACE(DEBUG_SCSIBUS, "SCSIBUS WENT TO BUS-FREE PHASE: TA exited!%0x \n", 0);
      cpssp->SCSI_initiated = false;
      cpssp->SCSI_unserviced = true;
      cpssp->SCSI_phase = SCSI_PHASE_BUSFREE;

      /* indicate phasechange (needed for old-semantik-style scsi-disk)! */
      cpssp->SCSI_phase_change = !(cpssp->SCSI_phase_change);

      chip_lsi_check_phase_mismatch(cpssp);
}

static void
chip_lsi_53C810_atn_set(void *_cpssp, unsigned int val)
{
      TRACE(DEBUG_SCSIBUS, "ATN-line high!%0x \n", 0);
}

static void
chip_lsi_53C810_scsibus_want_recv(void *_cpssp, unsigned long count)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;

      if (cpssp->delayed_transfer) {
            TRACE(DEBUG_SCRIPTS,"Ok, TARGET REQs again: restarting SCRIPTS at %0x\n",
                        *LONGCARDREG(cpssp,REG_DSP));
            cpssp->SCSI_data_to_target = count;
            chip_lsi_53C810_start_SCRIPTS(cpssp);
      } else {
            /* the target wants to receive data,
             * so we keep the parameters in mind!
             * We need that when the controller is
             * entering SCRIPTS data-transfer...*/
            cpssp->SCSI_data_to_target = count;
            TRACE(DEBUG_SCSIBUS,
                  "RECEIVED TRANSFER-REQUEST FROM TARGET:%0lx \n", 
                  count);
      }

      /* The lsi will only transfer data when entering
       * BLOCK-MOVE oepration, so no data is beeing transferred yet */
}

static unsigned long
chip_lsi_53C810_scsibus_send(
      void *_cpssp,
      const uint8_t *buf,
      unsigned long bufsize
)
{
      return 0;
}

static void
chip_lsi_53C810_scsibus_want_send(void *_cpssp, unsigned long count)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;

      if (cpssp->delayed_transfer) {
            TRACE(DEBUG_SCRIPTS,"Ok, TARGET REQs again: restarting SCRIPTS at %0x\n",
                        *LONGCARDREG(cpssp,REG_DSP));
            cpssp->SCSI_data_from_target = count;
            chip_lsi_53C810_start_SCRIPTS(cpssp);
      } else {
            /* the target wants to receive data,
             * so we keep the parameters in mind!
             * We need that when the controller is
             * entering SCRIPTS data-transfer...*/
            cpssp->SCSI_data_from_target = count;
            TRACE(DEBUG_SCSIBUS,
                  "RECEIVED TRANSFER-REQUEST FROM TARGET:%0lx \n", 
                  count);
      }

      /* The lsi will only transfer data when entering
       * BLOCK-MOVE oepration, so no data is beeing transferred yet */

}

static unsigned long
chip_lsi_53C810_scsibus_recv(void *_cpssp, uint8_t *buf, unsigned long bufsize)
{
      return 0;
}

/* =================== Power / Reset ===================== */

static void
chip_lsi_53C810_power_set(void *_cpssp, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;

      TRACE(DEBUG_OTHER,  "LSI 53C810 POWER:%x\n",val);

      cpssp->state_power = val;
}

static void
chip_lsi_53C810_n_reset_set(void *_cpssp, unsigned int n_val)
{
      struct cpssp *cpssp = (struct cpssp *) _cpssp;

      TRACE(DEBUG_OTHER,  "LSI 53C810 RESETTING...%x\n",0);

      /* initialize/reset PCI config space */
      memset(cpssp->config_space, 0, 0x100);

      pci_setconfigw(cpssp->config_space, PCI_VENDOR_ID, 0x1000);
      pci_setconfigw(cpssp->config_space, PCI_DEVICE_ID, 0x0001);
      pci_setconfigw(cpssp->config_space, PCI_COMMAND, PCI_COMMAND_MASTER);

      pci_setconfigw(cpssp->config_space,
            PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM | PCI_STATUS_FAST_BACK);

      pci_setconfigb(cpssp->config_space, PCI_REVISION_ID, 0x10 | REVISION);
      pci_setconfigw(cpssp->config_space, PCI_CLASS_DEVICE, 0x0100);
      pci_setconfigb(cpssp->config_space, PCI_LATENCY_TIMER, 32);

      pci_setconfigl(cpssp->config_space, PCI_BASE_ADDRESS_1, 
            (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_32));
      pci_setconfigl(cpssp->config_space, PCI_BASE_ADDRESS_0,
            PCI_BASE_ADDRESS_SPACE_IO);


      pci_setconfigb(cpssp->config_space, PCI_INTERRUPT_PIN, PCI_INT_A);

      pci_setconfigb(cpssp->config_space, PCI_MIN_GNT, 0x08);
      pci_setconfigb(cpssp->config_space, PCI_MAX_LAT, 0x18);

      chip_lsi_53C810_reset_chip(cpssp);

      TRACE(DEBUG_OTHER,  "LSI 53C810 Card resetted!%x\n",0);
}


/* ====================== global functions ==================== */

void
chip_lsi_53C810_init(
      unsigned int nr,
      struct sig_boolean *port_power,
      struct sig_boolean *port_reset_hash_,
      struct sig_pci_bus_idsel *port_idsel,
      struct sig_pci_bus_main *port_pci_bus,
      struct sig_boolean_or *port_intA,
      struct sig_scsi_bus *port_scsi_bus
)
{
      static const struct sig_boolean_funcs power_funcs = {
            .set = chip_lsi_53C810_power_set,
      };
      static const struct sig_boolean_funcs reset_hash__funcs = {
            .set = chip_lsi_53C810_n_reset_set,
      };
      static const struct sig_pci_bus_idsel_funcs idsel_funcs = {
            .c0r =            chip_lsi_53C810_cread0,
            .c0w =            chip_lsi_53C810_cwrite0,
      };
      static const struct sig_pci_bus_main_funcs pci_bus_funcs = {
            .ior =            chip_lsi_53C810_ior,
            .iow =            chip_lsi_53C810_iow,
            .mr  =            chip_lsi_53C810_read,
            .mw  =            chip_lsi_53C810_write,
            .map =            chip_lsi_53C810_map,
      };
      static const struct sig_scsi_bus_funcs scsi_bus_funcs = {
            .phase_select =   chip_lsi_53C810_phase_select,
            .phase_reselect =       chip_lsi_53C810_phase_reselect,
            .phase_msg_out =  chip_lsi_53C810_phase_msg_out,
            .phase_msg_in =   chip_lsi_53C810_phase_msg_in,
            .phase_command =  chip_lsi_53C810_phase_command,
            .phase_data_out =       chip_lsi_53C810_phase_data_out,
            .phase_data_in =  chip_lsi_53C810_phase_data_in,
            .phase_status =   chip_lsi_53C810_phase_status,
            .phase_free =           chip_lsi_53C810_phase_free,
            .atn_set =        chip_lsi_53C810_atn_set,
            .want_recv =            chip_lsi_53C810_scsibus_want_recv,
            .send =           chip_lsi_53C810_scsibus_send,
            .want_send =            chip_lsi_53C810_scsibus_want_send,
            .recv =           chip_lsi_53C810_scsibus_recv,
      };
      struct cpssp *cpssp;

      cpssp = shm_map(COMP, nr, sizeof(*cpssp), 0);

      TRACE(DEBUG_OTHER,  "LSI 53C810 INIT START!%x\n",0);

      /* Out */
      cpssp->port_intA = port_intA;
      sig_boolean_or_connect_out(port_intA, cpssp, 0);

      /* Call */
      sig_pci_bus_idsel_connect(port_idsel, cpssp, &idsel_funcs);

      cpssp->port_pci_bus = port_pci_bus;
      sig_pci_bus_main_connect(port_pci_bus, cpssp, &pci_bus_funcs);

      cpssp->port_scsi_bus = port_scsi_bus;
      sig_scsi_bus_connect(port_scsi_bus, cpssp, &scsi_bus_funcs);

      /* In */
      sig_boolean_connect_in(port_power, cpssp, &power_funcs);

      sig_boolean_connect_in(port_reset_hash_, cpssp, &reset_hash__funcs);

      TRACE(DEBUG_OTHER,  "LSI 53C810 INIT END!%x\n",0);
}

unsigned int
chip_lsi_53C810_create(void)
{
      static unsigned int nr = 0;
      struct cpssp *cpssp;
      char fn[1024];
      int fd;
      int ret;

      shm_create(COMP, nr, sizeof(*cpssp));
      cpssp = shm_map(COMP, nr, sizeof(*cpssp), 0);

      /* initialize flash rom */
      sprintf(fn, "%s/" COMP "-bootrom", basedir);
      fd = open(fn, O_RDONLY);
      if (0 <= fd) { /* Load file */
            ret = read(fd, cpssp->bootrom, SZ_53CBOOTROM);
            assert(ret == SZ_53CBOOTROM);
            ret = close(fd);
            assert(0 <= ret);
      } else {
            memset(cpssp->bootrom, 0, SZ_53CBOOTROM);
      }

      shm_unmap(cpssp, sizeof(*cpssp));

      return nr++;
}

void
chip_lsi_53C810_destroy(unsigned int nr)
{
      struct cpssp *cpssp;

      cpssp = shm_map(COMP, nr, sizeof(*cpssp), 0);

      shm_unmap(cpssp, sizeof(*cpssp));
      shm_destroy(COMP, nr);
}

Generated by  Doxygen 1.6.0   Back to index