summaryrefslogtreecommitdiff
path: root/scsi/adapters/scsi_33C93_hdw.c
diff options
context:
space:
mode:
Diffstat (limited to 'scsi/adapters/scsi_33C93_hdw.c')
-rw-r--r--scsi/adapters/scsi_33C93_hdw.c2078
1 files changed, 2078 insertions, 0 deletions
diff --git a/scsi/adapters/scsi_33C93_hdw.c b/scsi/adapters/scsi_33C93_hdw.c
new file mode 100644
index 0000000..169ccbf
--- /dev/null
+++ b/scsi/adapters/scsi_33C93_hdw.c
@@ -0,0 +1,2078 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS AS-IS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * File: scsi_33C93_hdw.h
+ * Author: Alessandro Forin, Carnegie Mellon University
+ * Date: 8/91
+ *
+ * Bottom layer of the SCSI driver: chip-dependent functions
+ *
+ * This file contains the code that is specific to the WD/AMD 33C93
+ * SCSI chip (Host Bus Adapter in SCSI parlance): probing, start
+ * operation, and interrupt routine.
+ */
+
+#if 0
+DISCLAIMER: THIS DOES NOT EVEN COMPILE YET, it went in by mistake.
+Code that probably makes some sense is from here to "TILL HERE"
+
+/*
+ * This layer works based on small simple 'scripts' that are installed
+ * at the start of the command and drive the chip to completion.
+ * The idea comes from the specs of the NCR 53C700 'script' processor.
+ *
+ * There are various reasons for this, mainly
+ * - Performance: identify the common (successful) path, and follow it;
+ * at interrupt time no code is needed to find the current status
+ * - Code size: it should be easy to compact common operations
+ * - Adaptability: the code skeleton should adapt to different chips without
+ * terrible complications.
+ * - Error handling: and it is easy to modify the actions performed
+ * by the scripts to cope with strange but well identified sequences
+ *
+ */
+
+#include <sbic.h>
+#if NSBIC > 0
+#include <platforms.h>
+
+#ifdef IRIS
+#define PAD(n) char n[3] /* or whatever */
+#define SBIC_MUX_ADDRESSING /* comment out if wrong */
+#define SBIC_CLOCK_FREQUENCY 20 /* FIXME FIXME FIXME */
+#define SBIC_MACHINE_DMA_MODE SBIC_CTL_DMA /* FIXME FIXME FIXME */
+
+#define SBIC_SET_RST_ADDR /*SCSI_INIT_ADDR*/
+#define SBIC_CLR_RST_ADDR /*SCSI_RDY_ADDR*/
+#define SBIC_MACHINE_RESET_SCSIBUS(regs,per) \
+ { int temp; \
+ temp = *(volatile unsigned int *)SBIC_SET_RST_ADDR; \
+ delay(per); \
+ temp = *(volatile unsigned int *)SBIC_CLR_RST_ADDR; \
+ }
+
+#endif
+
+#include <machine/machspl.h> /* spl definitions */
+#include <mach/std_types.h>
+#include <sys/types.h>
+#include <chips/busses.h>
+#include <scsi/compat_30.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi2.h>
+
+#include <scsi/adapters/scsi_33C93.h>
+#include <scsi/scsi_defs.h>
+#include <scsi/adapters/scsi_dma.h>
+
+/*
+ * Spell out all combinations of padded/nopadded and mux/nomux
+ */
+#ifdef PAD
+typedef struct {
+
+ volatile unsigned char sbic_myid; /* rw: My SCSI id */
+/*#define sbic_cdbsize sbic_myid /* w : size of CDB */
+ PAD(pad0)
+ volatile unsigned char sbic_control; /* rw: Control register */
+ PAD(pad1)
+ volatile unsigned char sbic_timeo; /* rw: Timeout period */
+ PAD(pad2)
+ volatile unsigned char sbic_cdb1; /* rw: CDB, 1st byte */
+ PAD(pad3)
+ volatile unsigned char sbic_cdb2; /* rw: CDB, 2nd byte */
+ PAD(pad4)
+ volatile unsigned char sbic_cdb3; /* rw: CDB, 3rd byte */
+ PAD(pad5)
+ volatile unsigned char sbic_cdb4; /* rw: CDB, 4th byte */
+ PAD(pad6)
+ volatile unsigned char sbic_cdb5; /* rw: CDB, 5th byte */
+ PAD(pad7)
+ volatile unsigned char sbic_cdb6; /* rw: CDB, 6th byte */
+ PAD(pad8)
+ volatile unsigned char sbic_cdb7; /* rw: CDB, 7th byte */
+ PAD(pad9)
+ volatile unsigned char sbic_cdb8; /* rw: CDB, 8th byte */
+ PAD(pad10)
+ volatile unsigned char sbic_cdb9; /* rw: CDB, 9th byte */
+ PAD(pad11)
+ volatile unsigned char sbic_cdb10; /* rw: CDB, 10th byte */
+ PAD(pad12)
+ volatile unsigned char sbic_cdb11; /* rw: CDB, 11th byte */
+ PAD(pad13)
+ volatile unsigned char sbic_cdb12; /* rw: CDB, 12th byte */
+ PAD(pad14)
+ volatile unsigned char sbic_tlun; /* rw: Target LUN */
+ PAD(pad15)
+ volatile unsigned char sbic_cmd_phase; /* rw: Command phase */
+ PAD(pad16)
+ volatile unsigned char sbic_syn; /* rw: Synch xfer params */
+ PAD(pad17)
+ volatile unsigned char sbic_count_hi; /* rw: Xfer count, hi */
+ PAD(pad18)
+ volatile unsigned char sbic_count_med; /* rw: Xfer count, med */
+ PAD(pad19)
+ volatile unsigned char sbic_count_lo; /* rw: Xfer count, lo */
+ PAD(pad20)
+ volatile unsigned char sbic_selid; /* rw: Target ID (select) */
+ PAD(pad21)
+ volatile unsigned char sbic_rselid; /* rw: Target ID (reselect) */
+ PAD(pad22)
+ volatile unsigned char sbic_csr; /* r : Status register */
+ PAD(pad23)
+ volatile unsigned char sbic_cmd; /* rw: Command register */
+ PAD(pad24)
+ volatile unsigned char sbic_data; /* rw: FIFO top */
+ PAD(pad25)
+ char u0; /* unused, padding */
+ PAD(pad26)
+ char u1; /* unused, padding */
+ PAD(pad27)
+ char u2; /* unused, padding */
+ PAD(pad28)
+ char u3; /* unused, padding */
+ PAD(pad29)
+ char u4; /* unused, padding */
+ PAD(pad30)
+ volatile unsigned char sbic_asr; /* r : Aux Status Register */
+ PAD(pad31)
+
+} sbic_padded_mux_regmap_t;
+
+typedef struct {
+ volatile unsigned char sbic_asr; /* r : Aux Status Register */
+/*#define sbic_address sbic_asr /* w : desired register no */
+ PAD(pad0);
+ volatile unsigned char sbic_value; /* rw: register value */
+ PAD(pad1);
+} sbic_padded_ind_regmap_t;
+
+#else /* !PAD */
+
+typedef sbic_mux_regmap_t sbic_padded_mux_regmap_t;
+typedef sbic_ind_regmap_t sbic_padded_ind_regmap_t;
+
+#endif /* !PAD */
+
+/*
+ * Could have used some non-ANSIsm in the following :-))
+ */
+#ifdef SBIC_MUX_ADDRESSING
+
+typedef sbic_padded_mux_regmap_t sbic_padded_regmap_t;
+
+#define SET_SBIC_myid(regs,val) (regs)->sbic_myid = (val)
+#define GET_SBIC_myid(regs,val) (val) = (regs)->sbic_myid
+#define SET_SBIC_cdbsize(regs,val) (regs)->sbic_cdbsize = (val)
+#define GET_SBIC_cdbsize(regs,val) (val) = (regs)->sbic_cdbsize
+#define SET_SBIC_control(regs,val) (regs)->sbic_control = (val)
+#define GET_SBIC_control(regs,val) (val) = (regs)->sbic_control
+#define SET_SBIC_timeo(regs,val) (regs)->sbic_timeo = (val)
+#define GET_SBIC_timeo(regs,val) (val) = (regs)->sbic_timeo
+#define SET_SBIC_cdb1(regs,val) (regs)->sbic_cdb1 = (val)
+#define GET_SBIC_cdb1(regs,val) (val) = (regs)->sbic_cdb1
+#define SET_SBIC_cdb2(regs,val) (regs)->sbic_cdb2 = (val)
+#define GET_SBIC_cdb2(regs,val) (val) = (regs)->sbic_cdb2
+#define SET_SBIC_cdb3(regs,val) (regs)->sbic_cdb3 = (val)
+#define GET_SBIC_cdb3(regs,val) (val) = (regs)->sbic_cdb3
+#define SET_SBIC_cdb4(regs,val) (regs)->sbic_cdb4 = (val)
+#define GET_SBIC_cdb4(regs,val) (val) = (regs)->sbic_cdb4
+#define SET_SBIC_cdb5(regs,val) (regs)->sbic_cdb5 = (val)
+#define GET_SBIC_cdb5(regs,val) (val) = (regs)->sbic_cdb5
+#define SET_SBIC_cdb6(regs,val) (regs)->sbic_cdb6 = (val)
+#define GET_SBIC_cdb6(regs,val) (val) = (regs)->sbic_cdb6
+#define SET_SBIC_cdb7(regs,val) (regs)->sbic_cdb7 = (val)
+#define GET_SBIC_cdb7(regs,val) (val) = (regs)->sbic_cdb7
+#define SET_SBIC_cdb8(regs,val) (regs)->sbic_cdb8 = (val)
+#define GET_SBIC_cdb8(regs,val) (val) = (regs)->sbic_cdb8
+#define SET_SBIC_cdb9(regs,val) (regs)->sbic_cdb9 = (val)
+#define GET_SBIC_cdb9(regs,val) (val) = (regs)->sbic_cdb9
+#define SET_SBIC_cdb10(regs,val) (regs)->sbic_cdb10 = (val)
+#define GET_SBIC_cdb10(regs,val) (val) = (regs)->sbic_cdb10
+#define SET_SBIC_cdb11(regs,val) (regs)->sbic_cdb11 = (val)
+#define GET_SBIC_cdb11(regs,val) (val) = (regs)->sbic_cdb11
+#define SET_SBIC_cdb12(regs,val) (regs)->sbic_cdb12 = (val)
+#define GET_SBIC_cdb12(regs,val) (val) = (regs)->sbic_cdb12
+#define SET_SBIC_tlun(regs,val) (regs)->sbic_tlun = (val)
+#define GET_SBIC_tlun(regs,val) (val) = (regs)->sbic_tlun
+#define SET_SBIC_cmd_phase(regs,val) (regs)->sbic_cmd_phase = (val)
+#define GET_SBIC_cmd_phase(regs,val) (val) = (regs)->sbic_cmd_phase
+#define SET_SBIC_syn(regs,val) (regs)->sbic_syn = (val)
+#define GET_SBIC_syn(regs,val) (val) = (regs)->sbic_syn
+#define SET_SBIC_count_hi(regs,val) (regs)->sbic_count_hi = (val)
+#define GET_SBIC_count_hi(regs,val) (val) = (regs)->sbic_count_hi
+#define SET_SBIC_count_med(regs,val) (regs)->sbic_count_med = (val)
+#define GET_SBIC_count_med(regs,val) (val) = (regs)->sbic_count_med
+#define SET_SBIC_count_lo(regs,val) (regs)->sbic_count_lo = (val)
+#define GET_SBIC_count_lo(regs,val) (val) = (regs)->sbic_count_lo
+#define SET_SBIC_selid(regs,val) (regs)->sbic_selid = (val)
+#define GET_SBIC_selid(regs,val) (val) = (regs)->sbic_selid
+#define SET_SBIC_rselid(regs,val) (regs)->sbic_rselid = (val)
+#define GET_SBIC_rselid(regs,val) (val) = (regs)->sbic_rselid
+#define SET_SBIC_csr(regs,val) (regs)->sbic_csr = (val)
+#define GET_SBIC_csr(regs,val) (val) = (regs)->sbic_csr
+#define SET_SBIC_cmd(regs,val) (regs)->sbic_cmd = (val)
+#define GET_SBIC_cmd(regs,val) (val) = (regs)->sbic_cmd
+#define SET_SBIC_data(regs,val) (regs)->sbic_data = (val)
+#define GET_SBIC_data(regs,val) (val) = (regs)->sbic_data
+
+#define SBIC_TC_SET(regs,val) { \
+ (regs)->sbic_count_hi = ((val)>>16)); \
+ (regs)->sbic_count_med = (val)>>8; \
+ (regs)->sbic_count_lo = (val); \
+ }
+#define SBIC_TC_GET(regs,val) { \
+ (val) = ((regs)->sbic_count_hi << 16) | \
+ ((regs)->sbic_count_med << 8) | \
+ ((regs)->sbic_count_lo); \
+ }
+
+#define SBIC_LOAD_COMMAND(regs,cmd,cmdsize) { \
+ register char *ptr = (char*)(cmd); \
+ (regs)->cis_cdb1 = *ptr++; \
+ (regs)->cis_cdb2 = *ptr++; \
+ (regs)->cis_cdb3 = *ptr++; \
+ (regs)->cis_cdb4 = *ptr++; \
+ (regs)->cis_cdb5 = *ptr++; \
+ (regs)->cis_cdb6 = *ptr++; \
+ if (cmdsize > 6) { \
+ (regs)->cis_cdb7 = *ptr++; \
+ (regs)->cis_cdb8 = *ptr++; \
+ (regs)->cis_cdb9 = *ptr++; \
+ (regs)->cis_cdb10 = *ptr++; \
+ } \
+ if (cmdsize > 10) { \
+ (regs)->cis_cdb11 = *ptr++; \
+ (regs)->cis_cdb12 = *ptr; \
+ } \
+ }
+
+#else /*SBIC_MUX_ADDRESSING*/
+
+typedef sbic_padded_ind_regmap_t sbic_padded_regmap_t;
+
+#define SET_SBIC_myid(regs,val) sbic_write_reg(regs,SBIC_myid,val)
+#define GET_SBIC_myid(regs,val) sbic_read_reg(regs,SBIC_myid,val)
+#define SET_SBIC_cdbsize(regs,val) sbic_write_reg(regs,SBIC_cdbsize,val)
+#define GET_SBIC_cdbsize(regs,val) sbic_read_reg(regs,SBIC_cdbsize,val)
+#define SET_SBIC_control(regs,val) sbic_write_reg(regs,SBIC_control,val)
+#define GET_SBIC_control(regs,val) sbic_read_reg(regs,SBIC_control,val)
+#define SET_SBIC_timeo(regs,val) sbic_write_reg(regs,SBIC_timeo,val)
+#define GET_SBIC_timeo(regs,val) sbic_read_reg(regs,SBIC_timeo,val)
+#define SET_SBIC_cdb1(regs,val) sbic_write_reg(regs,SBIC_cdb1,val)
+#define GET_SBIC_cdb1(regs,val) sbic_read_reg(regs,SBIC_cdb1,val)
+#define SET_SBIC_cdb2(regs,val) sbic_write_reg(regs,SBIC_cdb2,val)
+#define GET_SBIC_cdb2(regs,val) sbic_read_reg(regs,SBIC_cdb2,val)
+#define SET_SBIC_cdb3(regs,val) sbic_write_reg(regs,SBIC_cdb3,val)
+#define GET_SBIC_cdb3(regs,val) sbic_read_reg(regs,SBIC_cdb3,val)
+#define SET_SBIC_cdb4(regs,val) sbic_write_reg(regs,SBIC_cdb4,val)
+#define GET_SBIC_cdb4(regs,val) sbic_read_reg(regs,SBIC_cdb4,val)
+#define SET_SBIC_cdb5(regs,val) sbic_write_reg(regs,SBIC_cdb5,val)
+#define GET_SBIC_cdb5(regs,val) sbic_read_reg(regs,SBIC_cdb5,val)
+#define SET_SBIC_cdb6(regs,val) sbic_write_reg(regs,SBIC_cdb6,val)
+#define GET_SBIC_cdb6(regs,val) sbic_read_reg(regs,SBIC_cdb6,val)
+#define SET_SBIC_cdb7(regs,val) sbic_write_reg(regs,SBIC_cdb7,val)
+#define GET_SBIC_cdb7(regs,val) sbic_read_reg(regs,SBIC_cdb7,val)
+#define SET_SBIC_cdb8(regs,val) sbic_write_reg(regs,SBIC_cdb8,val)
+#define GET_SBIC_cdb8(regs,val) sbic_read_reg(regs,SBIC_cdb8,val)
+#define SET_SBIC_cdb9(regs,val) sbic_write_reg(regs,SBIC_cdb9,val)
+#define GET_SBIC_cdb9(regs,val) sbic_read_reg(regs,SBIC_cdb9,val)
+#define SET_SBIC_cdb10(regs,val) sbic_write_reg(regs,SBIC_cdb10,val)
+#define GET_SBIC_cdb10(regs,val) sbic_read_reg(regs,SBIC_cdb10,val)
+#define SET_SBIC_cdb11(regs,val) sbic_write_reg(regs,SBIC_cdb11,val)
+#define GET_SBIC_cdb11(regs,val) sbic_read_reg(regs,SBIC_cdb11,val)
+#define SET_SBIC_cdb12(regs,val) sbic_write_reg(regs,SBIC_cdb12,val)
+#define GET_SBIC_cdb12(regs,val) sbic_read_reg(regs,SBIC_cdb12,val)
+#define SET_SBIC_tlun(regs,val) sbic_write_reg(regs,SBIC_tlun,val)
+#define GET_SBIC_tlun(regs,val) sbic_read_reg(regs,SBIC_tlun,val)
+#define SET_SBIC_cmd_phase(regs,val) sbic_write_reg(regs,SBIC_cmd_phase,val)
+#define GET_SBIC_cmd_phase(regs,val) sbic_read_reg(regs,SBIC_cmd_phase,val)
+#define SET_SBIC_syn(regs,val) sbic_write_reg(regs,SBIC_syn,val)
+#define GET_SBIC_syn(regs,val) sbic_read_reg(regs,SBIC_syn,val)
+#define SET_SBIC_count_hi(regs,val) sbic_write_reg(regs,SBIC_count_hi,val)
+#define GET_SBIC_count_hi(regs,val) sbic_read_reg(regs,SBIC_count_hi,val)
+#define SET_SBIC_count_med(regs,val) sbic_write_reg(regs,SBIC_count_med,val)
+#define GET_SBIC_count_med(regs,val) sbic_read_reg(regs,SBIC_count_med,val)
+#define SET_SBIC_count_lo(regs,val) sbic_write_reg(regs,SBIC_count_lo,val)
+#define GET_SBIC_count_lo(regs,val) sbic_read_reg(regs,SBIC_count_lo,val)
+#define SET_SBIC_selid(regs,val) sbic_write_reg(regs,SBIC_selid,val)
+#define GET_SBIC_selid(regs,val) sbic_read_reg(regs,SBIC_selid,val)
+#define SET_SBIC_rselid(regs,val) sbic_write_reg(regs,SBIC_rselid,val)
+#define GET_SBIC_rselid(regs,val) sbic_read_reg(regs,SBIC_rselid,val)
+#define SET_SBIC_csr(regs,val) sbic_write_reg(regs,SBIC_csr,val)
+#define GET_SBIC_csr(regs,val) sbic_read_reg(regs,SBIC_csr,val)
+#define SET_SBIC_cmd(regs,val) sbic_write_reg(regs,SBIC_cmd,val)
+#define GET_SBIC_cmd(regs,val) sbic_read_reg(regs,SBIC_cmd,val)
+#define SET_SBIC_data(regs,val) sbic_write_reg(regs,SBIC_data,val)
+#define GET_SBIC_data(regs,val) sbic_read_reg(regs,SBIC_data,val)
+
+#define SBIC_TC_SET(regs,val) { \
+ sbic_write_reg(regs,SBIC_count_hi,((val)>>16)); \
+ (regs)->sbic_value = (val)>>8; wbflush(); \
+ (regs)->sbic_value = (val); \
+ }
+#define SBIC_TC_GET(regs,val) { \
+ sbic_read_reg(regs,SBIC_count_hi,(val)); \
+ (val) = ((val)<<8) | (regs)->sbic_value; \
+ (val) = ((val)<<8) | (regs)->sbic_value; \
+ }
+
+#define SBIC_LOAD_COMMAND(regs,cmd,cmdsize) {
+ register int n=cmdsize-1; \
+ register char *ptr = (char*)(cmd); \
+ sbic_write_reg(regs,SBIC_cdb1,*ptr++); \
+ while (n-- > 0) (regs)->sbic_value = *ptr++; \
+ }
+
+#endif /*SBIC_MUX_ADDRESSING*/
+
+#define GET_SBIC_asr(regs,val) (val) = (regs)->sbic_asr
+
+
+/*
+ * If all goes well (cross fingers) the typical read/write operation
+ * should complete in just one interrupt. Therefore our scripts
+ * have only two parts: a pre-condition and an action. The first
+ * triggers error handling if not satisfied and in our case it is a match
+ * of ....
+ * The action part is just a function pointer, invoked in a standard way.
+ * The script proceeds only if the action routine returns TRUE.
+ * See sbic_intr() for how and where this is all done.
+ */
+
+typedef struct script {
+ struct { /* expected state at interrupt: */
+ unsigned char csr; /* interrupt cause */
+ unsigned char pha; /* command phase */
+ } condition;
+/* unsigned char unused[2]; /* unused padding */
+ boolean_t (*action)(); /* extra operations */
+} *script_t;
+
+/* Matching on the condition value */
+#define ANY 0xff
+#define SCRIPT_MATCH(csr,pha,cond) \
+ (((cond).csr == (csr)) && \
+ (((cond).pha == (pha)) || ((cond).pha==ANY)))
+
+
+/* forward decls of script actions */
+boolean_t
+ sbic_end(), /* all come to an end */
+ sbic_get_status(), /* get status from target */
+ sbic_dma_in(), /* get data from target via dma */
+ sbic_dma_in_r(), /* get data from target via dma (restartable)*/
+ sbic_dma_out(), /* send data to target via dma */
+ sbic_dma_out_r(), /* send data to target via dma (restartable) */
+ sbic_dosynch(), /* negotiate synch xfer */
+ sbic_msg_in(), /* receive the disconenct message */
+ sbic_disconnected(), /* target has disconnected */
+ sbic_reconnect(); /* target reconnected */
+
+/* forward decls of error handlers */
+boolean_t
+ sbic_err_generic(), /* generic handler */
+ sbic_err_disconn(), /* target disconnects amidst */
+ gimmeabreak(); /* drop into the debugger */
+
+int sbic_reset_scsibus();
+boolean_t sbic_probe_target();
+static sbic_wait();
+
+/*
+ * State descriptor for this layer. There is one such structure
+ * per (enabled) SCSI-33c93 interface
+ */
+struct sbic_softc {
+ watchdog_t wd;
+ sbic_padded_regmap_t *regs; /* 33c93 registers */
+
+ scsi_dma_ops_t *dma_ops; /* DMA operations and state */
+ opaque_t dma_state;
+
+ script_t script; /* what should happen next */
+ boolean_t (*error_handler)();/* what if something is wrong */
+ int in_count; /* amnt we expect to receive */
+ int out_count; /* amnt we are going to ship */
+
+ volatile char state;
+#define SBIC_STATE_BUSY 0x01 /* selecting or currently connected */
+#define SBIC_STATE_TARGET 0x04 /* currently selected as target */
+#define SBIC_STATE_COLLISION 0x08 /* lost selection attempt */
+#define SBIC_STATE_DMA_IN 0x10 /* tgt --> initiator xfer */
+#define SBIC_STATE_AM_MODE 0x20 /* 33c93A with advanced mode (AM) */
+
+ unsigned char ntargets; /* how many alive on this scsibus */
+ unsigned char done;
+ unsigned char unused;
+
+ scsi_softc_t *sc; /* HBA-indep info */
+ target_info_t *active_target; /* the current one */
+
+ target_info_t *next_target; /* trying to seize bus */
+ queue_head_t waiting_targets;/* other targets competing for bus */
+
+} sbic_softc_data[NSBIC];
+
+typedef struct sbic_softc *sbic_softc_t;
+
+sbic_softc_t sbic_softc[NSBIC];
+
+/*
+ * Synch xfer parameters, and timing conversions
+ */
+int sbic_min_period = SBIC_SYN_MIN_PERIOD; /* in cycles = f(ICLK,FSn) */
+int sbic_max_offset = SBIC_SYN_MAX_OFFSET; /* pure number */
+
+int sbic_to_scsi_period(regs,a)
+{
+ unsigned int fs;
+
+ /* cycle = DIV / (2*CLK) */
+ /* DIV = FS+2 */
+ /* best we can do is 200ns at 20Mhz, 2 cycles */
+
+ GET_SBIC_myid(regs,fs);
+ fs = (fs >>6) + 2; /* DIV */
+ fs = (fs * 1000) / (SBIC_CLOCK_FREQUENCY<<1); /* Cycle, in ns */
+ if (a < 2) a = 8; /* map to Cycles */
+ return ((fs*a)>>2); /* in 4 ns units */
+}
+
+int scsi_period_to_sbic(regs,p)
+{
+ register unsigned int fs;
+
+ /* Just the inverse of the above */
+
+ GET_SBIC_myid(regs,fs);
+ fs = (fs >>6) + 2; /* DIV */
+ fs = (fs * 1000) / (SBIC_CLOCK_FREQUENCY<<1); /* Cycle, in ns */
+
+ ret = p << 2; /* in ns units */
+ ret = ret / fs; /* in Cycles */
+ if (ret < sbic_min_period)
+ return sbic_min_period;
+ /* verify rounding */
+ if (sbic_to_scsi_period(regs,ret) < p)
+ ret++;
+ return (ret >= 8) ? 0 : ret;
+}
+
+#define u_min(a,b) (((a) < (b)) ? (a) : (b))
+
+/*
+ * Definition of the controller for the auto-configuration program.
+ */
+
+int sbic_probe(), scsi_slave(), scsi_attach(), sbic_go(), sbic_intr();
+
+caddr_t sbic_std[NSBIC] = { 0 };
+struct bus_device *sbic_dinfo[NSBIC*8];
+struct bus_ctlr *sbic_minfo[NSBIC];
+struct bus_driver sbic_driver =
+ { sbic_probe, scsi_slave, scsi_attach, sbic_go, sbic_std, "rz", sbic_dinfo,
+ "sbic", sbic_minfo, BUS_INTR_B4_PROBE};
+
+
+sbic_set_dmaops(unit, dmaops)
+ unsigned int unit;
+ scsi_dma_ops_t *dmaops;
+{
+ if (unit < NSBIC)
+ sbic_std[unit] = (caddr_t)dmaops;
+}
+
+/*
+ * Scripts
+ */
+struct script
+sbic_script_any_cmd[] = { /* started with SEL & XFER */
+ {{SBIC_CSR_S_XFERRED, 0x60}, sbic_get_status},
+},
+
+sbic_script_try_synch[] = { /* started with SEL */
+ {{SBIC_CSR_INITIATOR, ANY}, sbic_dosynch},
+ {{SBIC_CSR_S_XFERRED, 0x60}, sbic_get_status},
+};
+
+
+#define DEBUG
+#ifdef DEBUG
+
+#define PRINT(x) if (scsi_debug) printf x
+
+sbic_state(regs, overrule)
+ sbic_padded_regmap_t *regs;
+{
+ register unsigned char asr,tmp;
+
+ if (regs == 0) {
+ if (sbic_softc[0])
+ regs = sbic_softc[0]->regs;
+ else
+ regs = (sbic_padded_regmap_t*)0xXXXXXXXX;
+ }
+
+ GET_SBIC_asr(regs,asr);
+
+ if ((asr & SBIC_ASR_BSY) && !overrule)
+ db_printf("-BUSY- ");
+ else {
+ unsigned char tlun,pha,selid,rselid;
+ unsigned int cnt;
+ GET_SBIC_tlun(regs,tlun);
+ GET_SBIC_cmd_phase(regs,pha);
+ GET_SBIC_selid(regs,selid);
+ GET_SBIC_rselid(regs,rselid);
+ SBIC_TC_GET(regs,cnt);
+ db_printf("tc %x tlun %x sel %x rsel %x pha %x ",
+ cnt, tlun, selid, rselid, pha);
+ }
+
+ if (asr & SBIC_ASR_INT)
+ db_printf("-INT- ");
+ else {
+ GET_SBIC_csr(regs,tmp);
+ db_printf("csr %x ", tmp);
+ }
+
+ if (asr & SBIC_ASR_CIP)
+ db_printf("-CIP-\n");
+ else {
+ GET_SBIC_cmd(regs,tmp);
+ db_printf("cmd %x\n", tmp);
+ }
+ return 0;
+}
+
+sbic_target_state(tgt)
+ target_info_t *tgt;
+{
+ if (tgt == 0)
+ tgt = sbic_softc[0]->active_target;
+ if (tgt == 0)
+ return 0;
+ db_printf("@x%x: fl %x dma %X+%x cmd %x@%X id %x per %x off %x ior %X ret %X\n",
+ tgt,
+ tgt->flags, tgt->dma_ptr, tgt->transient_state.dma_offset, tgt->cur_cmd,
+ tgt->cmd_ptr, tgt->target_id, tgt->sync_period, tgt->sync_offset,
+ tgt->ior, tgt->done);
+ if (tgt->flags & TGT_DISCONNECTED){
+ script_t spt;
+
+ spt = tgt->transient_state.script;
+ db_printf("disconnected at ");
+ db_printsym(spt,1);
+ db_printf(": %x %x ", spt->condition.csr, spt->condition.pha);
+ db_printsym(spt->action,1);
+ db_printf(", ");
+ db_printsym(tgt->transient_state.handler, 1);
+ db_printf("\n");
+ }
+
+ return 0;
+}
+
+sbic_all_targets(unit)
+{
+ int i;
+ target_info_t *tgt;
+ for (i = 0; i < 8; i++) {
+ tgt = sbic_softc[unit]->sc->target[i];
+ if (tgt)
+ sbic_target_state(tgt);
+ }
+}
+
+sbic_script_state(unit)
+{
+ script_t spt = sbic_softc[unit]->script;
+
+ if (spt == 0) return 0;
+ db_printsym(spt,1);
+ db_printf(": %x %x ", spt->condition.csr, spt->condition.pha);
+ db_printsym(spt->action,1);
+ db_printf(", ");
+ db_printsym(sbic_softc[unit]->error_handler, 1);
+ return 0;
+}
+
+#define TRMAX 200
+int tr[TRMAX+3];
+int trpt, trpthi;
+#define TR(x) tr[trpt++] = x
+#define TRWRAP trpthi = trpt; trpt = 0;
+#define TRCHECK if (trpt > TRMAX) {TRWRAP}
+
+#define TRACE
+
+#ifdef TRACE
+
+#define LOGSIZE 256
+int sbic_logpt;
+char sbic_log[LOGSIZE];
+
+#define MAXLOG_VALUE 0x1e
+struct {
+ char *name;
+ unsigned int count;
+} logtbl[MAXLOG_VALUE];
+
+static LOG(e,f)
+ char *f;
+{
+ sbic_log[sbic_logpt++] = (e);
+ if (sbic_logpt == LOGSIZE) sbic_logpt = 0;
+ if ((e) < MAXLOG_VALUE) {
+ logtbl[(e)].name = (f);
+ logtbl[(e)].count++;
+ }
+}
+
+sbic_print_log(skip)
+ int skip;
+{
+ register int i, j;
+ register unsigned char c;
+
+ for (i = 0, j = sbic_logpt; i < LOGSIZE; i++) {
+ c = sbic_log[j];
+ if (++j == LOGSIZE) j = 0;
+ if (skip-- > 0)
+ continue;
+ if (c < MAXLOG_VALUE)
+ db_printf(" %s", logtbl[c].name);
+ else
+ db_printf("-x%x", c & 0x7f);
+ }
+}
+
+sbic_print_stat()
+{
+ register int i;
+ register char *p;
+ for (i = 0; i < MAXLOG_VALUE; i++) {
+ if (p = logtbl[i].name)
+ printf("%d %s\n", logtbl[i].count, p);
+ }
+}
+
+#else /*TRACE*/
+#define LOG(e,f)
+#define LOGSIZE
+#endif /*TRACE*/
+
+#else /*DEBUG*/
+#define PRINT(x)
+#define LOG(e,f)
+#define LOGSIZE
+
+#endif /*DEBUG*/
+
+
+/*
+ * Probe/Slave/Attach functions
+ */
+
+/*
+ * Probe routine:
+ * Should find out (a) if the controller is
+ * present and (b) which/where slaves are present.
+ *
+ * Implementation:
+ * Send a test-unit-ready to each possible target on the bus
+ * except of course ourselves.
+ */
+sbic_probe(reg, ui)
+ unsigned reg;
+ struct bus_ctlr *ui;
+{
+ int unit = ui->unit;
+ sbic_softc_t sbic = &sbic_softc_data[unit];
+ int target_id;
+ scsi_softc_t *sc;
+ register sbic_padded_regmap_t *regs;
+ spl_t s;
+ boolean_t did_banner = FALSE;
+
+ /*
+ * We are only called if the right board is there,
+ * but make sure anyways..
+ */
+ if (check_memory(reg, 0))
+ return 0;
+
+#if MAPPABLE
+ /* Mappable version side */
+ SBIC_probe(reg, ui);
+#endif /*MAPPABLE*/
+
+ /*
+ * Initialize hw descriptor, cache some pointers
+ */
+ sbic_softc[unit] = sbic;
+ sbic->regs = (sbic_padded_regmap_t *) (reg);
+
+ if ((sbic->dma_ops = (scsi_dma_ops_t *)sbic_std[unit]) == 0)
+ /* use same as unit 0 if undefined */
+ sbic->dma_ops = (scsi_dma_ops_t *)sbic_std[0];
+
+ sbic->dma_state = (*sbic->dma_ops->init)(unit, reg);
+
+ queue_init(&sbic->waiting_targets);
+
+ sc = scsi_master_alloc(unit, sbic);
+ sbic->sc = sc;
+
+ sc->go = sbic_go;
+ sc->watchdog = scsi_watchdog;
+ sc->probe = sbic_probe_target;
+ sbic->wd.reset = sbic_reset_scsibus;
+
+#ifdef MACH_KERNEL
+ sc->max_dma_data = -1;
+#else
+ sc->max_dma_data = scsi_per_target_virtual;
+#endif
+
+ regs = sbic->regs;
+
+ /*
+ * Reset chip, fully. Note that interrupts are already enabled.
+ */
+ s = splbio();
+ if (sbic_reset(regs, TRUE))
+ sbic->state |= SBIC_STATE_AM_MODE;
+
+ /*
+ * Our SCSI id on the bus.
+ * The user can probably set this via the prom.
+ * If not, it is easy to fix: make a default that
+ * can be changed as boot arg. Otherwise we keep
+ * what the prom used.
+ */
+#ifdef unneeded
+ SET_SBIC_myid(regs, (scsi_initiator_id[unit] & 0x7));
+ sbic_reset(regs, TRUE);
+#endif
+ GET_SBIC_myid(regs,sc->initiator_id);
+ sc->initiator_id &= 0x7;
+ printf("%s%d: SCSI id %d", ui->name, unit, sc->initiator_id);
+
+ /*
+ * For all possible targets, see if there is one and allocate
+ * a descriptor for it if it is there.
+ */
+ for (target_id = 0; target_id < 8; target_id++) {
+ register unsigned char asr, csr, pha;
+ register scsi_status_byte_t status;
+
+ /* except of course ourselves */
+ if (target_id == sc->initiator_id)
+ continue;
+
+ SBIC_TC_SET(regs,0);
+ SET_SBIC_selid(regs,target_id);
+ SET_SBIC_timo(regs,SBIC_TIMEOUT(250,SBIC_CLOCK_FREQUENCY));
+
+ /*
+ * See if the unit is ready.
+ * XXX SHOULD inquiry LUN 0 instead !!!
+ */
+ {
+ scsi_command_test_unit_ready_y c;
+ bzero(&c, sizeof(c));
+ c.scsi_cmd_code = SCSI_CMD_TEST_UNIT_READY;
+ SBIC_LOAD_COMMAND(regs,&c,sizeof(c));
+ }
+
+ /* select and send it */
+ SET_SBIC_cmd(regs,SBIC_CMD_SEL_XFER);
+
+ /* wait for the chip to complete, or timeout */
+ asr = sbic_wait(regs, SBIC_ASR_INT);
+ GET_SBIC_csr(regs,csr);
+
+ /*
+ * Check if the select timed out
+ */
+ GET_SBIC_cmd_phase(regs,pha);
+ if ((SBIC_CPH(pha) == 0) && (csr & SBIC_CSR_CMD_ERR)) {
+ /* noone out there */
+#if notsure
+ SET_SBIC_cmd(regs,SBIC_CMD_DISC);
+ asr = sbic_wait(regs, SBIC_ASR_INT);
+ GET_SBIC_csr(regs,csr);
+#endif
+ continue;
+ }
+
+ printf(",%s%d", did_banner++ ? " " : " target(s) at ",
+ target_id);
+
+ if (SBIC_CPH(pha) < 0x60)
+ /* XXX recover by hand XXX */
+ panic(" target acts weirdo");
+
+ GET_SBIC_tlun(regs,status.bits);
+
+ if (status.st.scsi_status_code != SCSI_ST_GOOD)
+ scsi_error( 0, SCSI_ERR_STATUS, status.bits, 0);
+
+ /*
+ * Found a target
+ */
+ sbic->ntargets++;
+ {
+ register target_info_t *tgt;
+ tgt = scsi_slave_alloc(sc->masterno, target_id, sbic);
+
+ (*sbic->dma_ops->new_target)(sbic->dma_state, tgt);
+ }
+ }
+
+ printf(".\n");
+
+ splx(s);
+ return 1;
+}
+
+boolean_t
+sbic_probe_target(tgt, ior)
+ target_info_t *tgt;
+ io_req_t ior;
+{
+ sbic_softc_t sbic = sbic_softc[tgt->masterno];
+ boolean_t newlywed;
+
+ newlywed = (tgt->cmd_ptr == 0);
+ if (newlywed) {
+ (*sbic->dma_ops->new_target)(sbic->dma_state, tgt);
+ }
+
+ if (scsi_inquiry(tgt, SCSI_INQ_STD_DATA) == SCSI_RET_DEVICE_DOWN)
+ return FALSE;
+
+ tgt->flags = TGT_ALIVE;
+ return TRUE;
+}
+
+static sbic_wait(regs, until)
+ sbic_padded_regmap_t *regs;
+ char until;
+{
+ register unsigned char val;
+ int timeo = 1000000;
+
+ GET_SBIC_asr(regs,val);
+ while ((val & until) == 0) {
+ if (!timeo--) {
+ printf("sbic_wait TIMEO with x%x\n", regs->sbic_csr);
+ break;
+ }
+ delay(1);
+ GET_SBIC_asr(regs,val);
+ }
+ return val;
+}
+
+boolean_t
+sbic_reset(regs, quick)
+ sbic_padded_regmap_t *regs;
+{
+ char my_id, csr;
+
+ /* preserve our ID for now */
+ GET_SBIC_myid(regs,my_id);
+ my_id &= SBIC_ID_MASK;
+
+ if (SBIC_CLOCK_FREQUENCY < 11)
+ my_id |= SBIC_ID_FS_8_10;
+ else if (SBIC_CLOCK_FREQUENCY < 16)
+ my_id |= SBIC_ID_FS_12_15;
+ else if (SBIC_CLOCK_FREQUENCY < 21)
+ my_id |= SBIC_ID_FS_16_20;
+
+ my_id |= SBIC_ID_EAF|SBIC_ID_EHP;
+
+ SET_SBIC_myid(regs,myid);
+ wbflush();
+
+ /*
+ * Reset chip and wait till done
+ */
+ SET_SBIC_cmd(regs,SBIC_CMD_RESET);
+ delay(25);
+
+ (void) sbic_wait(regs, SBIC_ASR_INT);
+ GET_SBIC_csr(regs,csr); /* clears interrupt also */
+
+ /*
+ * Set up various chip parameters
+ */
+ SET_SBIC_control(regs, SBIC_CTL_HHP|SBIC_CTL_EDI|SBIC_CTL_HSP|
+ SBIC_MACHINE_DMA_MODE);
+ /* will do IDI on the fly */
+ SET_SBIC_rselid(regs, SBIC_RID_ER|SBIC_RID_ES|SBIC_RID_DSP);
+ SET_SBIC_syn(regs,SBIC_SYN(0,sbic_min_period)); /* asynch for now */
+
+ /* anything else was zeroed by reset */
+
+ if (quick)
+ return (csr & SBIC_CSR_RESET_AM);
+
+ /*
+ * reset the scsi bus, the interrupt routine does the rest
+ * or you can call sbic_bus_reset().
+ */
+ /*
+ * Now HOW do I do this ? I just want to drive the SCSI "RST"
+ * signal true for about 25 usecs; But the chip has no notion
+ * of such a signal at all. The spec suggest that the chip's
+ * reset pin be connected to the RST signal, which makes this
+ * operation a machdep one.
+ */
+ SBIC_MACHINE_RESET_SCSIBUS(regs, 30);
+
+ return (csr & SBIC_CSR_RESET_AM);
+}
+
+/*
+ * Operational functions
+ */
+
+/*
+ * Start a SCSI command on a target
+ */
+sbic_go(tgt, cmd_count, in_count, cmd_only)
+ target_info_t *tgt;
+ boolean_t cmd_only;
+{
+ sbic_softc_t sbic;
+ register spl_t s;
+ boolean_t disconn;
+ script_t scp;
+ boolean_t (*handler)();
+
+ LOG(1,"go");
+
+ sbic = (sbic_softc_t)tgt->hw_state;
+
+ tgt->transient_state.cmd_count = cmd_count; /* keep it here */
+
+ (*sbic->dma_ops->map)(sbic->dma_state, tgt);
+
+ disconn = BGET(scsi_might_disconnect,tgt->masterno,tgt->target_id);
+ disconn = disconn && (sbic->ntargets > 1);
+ disconn |= BGET(scsi_should_disconnect,tgt->masterno,tgt->target_id);
+
+ /*
+ * Setup target state
+ */
+ tgt->done = SCSI_RET_IN_PROGRESS;
+
+ handler = (disconn) ? sbic_err_disconn : sbic_err_generic;
+ scp = sbic_script_any_cmd;
+
+ switch (tgt->cur_cmd) {
+ case SCSI_CMD_READ:
+ case SCSI_CMD_LONG_READ:
+ LOG(2,"readop");
+ break;
+ case SCSI_CMD_WRITE:
+ case SCSI_CMD_LONG_WRITE:
+ LOG(0x1a,"writeop");
+ break;
+ case SCSI_CMD_INQUIRY:
+ /* This is likely the first thing out:
+ do the synch neg if so */
+ if (!cmd_only && ((tgt->flags&TGT_DID_SYNCH)==0)) {
+ scp = sbic_script_try_synch;
+ tgt->flags |= TGT_TRY_SYNCH;
+ break;
+ }
+ case SCSI_CMD_MODE_SELECT:
+ case SCSI_CMD_REASSIGN_BLOCKS:
+ case SCSI_CMD_FORMAT_UNIT:
+ tgt->transient_state.cmd_count = sizeof(scsi_command_group_0);
+ tgt->transient_state.out_count = cmd_count - sizeof(scsi_command_group_0);
+ /* fall through */
+ case SCSI_CMD_REQUEST_SENSE:
+ case SCSI_CMD_MODE_SENSE:
+ case SCSI_CMD_RECEIVE_DIAG_RESULTS:
+ case SCSI_CMD_READ_CAPACITY:
+ case SCSI_CMD_READ_BLOCK_LIMITS:
+ case SCSI_CMD_READ_TOC:
+ case SCSI_CMD_READ_SUBCH:
+ case SCSI_CMD_READ_HEADER:
+ LOG(0x1c,"cmdop");
+ LOG(0x80+tgt->cur_cmd,0);
+ break;
+ case SCSI_CMD_TEST_UNIT_READY:
+ /*
+ * Do the synch negotiation here, unless prohibited
+ * or done already
+ */
+ if ( ! (tgt->flags & TGT_DID_SYNCH)) {
+ scp = sbic_script_try_synch;
+ tgt->flags |= TGT_TRY_SYNCH;
+ cmd_only = FALSE;
+ }
+ /* fall through */
+ default:
+ LOG(0x1c,"cmdop");
+ LOG(0x80+tgt->cur_cmd,0);
+ break;
+ }
+
+ tgt->transient_state.script = scp;
+ tgt->transient_state.handler = handler;
+ tgt->transient_state.identify = (cmd_only) ? 0xff :
+ (disconn ? SCSI_IDENTIFY|SCSI_IFY_ENABLE_DISCONNECT :
+ SCSI_IDENTIFY);
+
+ if (in_count)
+ tgt->transient_state.in_count =
+ (in_count < tgt->block_size) ? tgt->block_size : in_count;
+ else
+ tgt->transient_state.in_count = 0;
+
+ /*
+ * See if another target is currently selected on
+ * this SCSI bus, e.g. lock the sbic structure.
+ * Note that it is the strategy routine's job
+ * to serialize ops on the same target as appropriate.
+ * XXX here and everywhere, locks!
+ */
+ /*
+ * Protection viz reconnections makes it tricky.
+ */
+ s = splbio();
+
+ if (sbic->wd.nactive++ == 0)
+ sbic->wd.watchdog_state = SCSI_WD_ACTIVE;
+
+ if (sbic->state & SBIC_STATE_BUSY) {
+ /*
+ * Queue up this target, note that this takes care
+ * of proper FIFO scheduling of the scsi-bus.
+ */
+ LOG(3,"enqueue");
+ enqueue_tail(&sbic->waiting_targets, (queue_entry_t) tgt);
+ } else {
+ /*
+ * It is down to at most two contenders now,
+ * we will treat reconnections same as selections
+ * and let the scsi-bus arbitration process decide.
+ */
+ sbic->state |= SBIC_STATE_BUSY;
+ sbic->next_target = tgt;
+ sbic_attempt_selection(sbic);
+ /*
+ * Note that we might still lose arbitration..
+ */
+ }
+ splx(s);
+}
+
+sbic_attempt_selection(sbic)
+ sbic_softc_t sbic;
+{
+ target_info_t *tgt;
+ sbic_padded_regmap_t *regs;
+ register unsigned char val;
+ register int out_count;
+
+ regs = sbic->regs;
+ tgt = sbic->next_target;
+
+ LOG(4,"select");
+ LOG(0x80+tgt->target_id,0);
+
+ /*
+ * We own the bus now.. unless we lose arbitration
+ */
+ sbic->active_target = tgt;
+
+ /* Try to avoid reselect collisions */
+ GET_SBIC_asr(regs,val);
+ if (val & SBIC_ASR_INT)
+ return;
+
+ /*
+ * Init bus state variables
+ */
+ sbic->script = tgt->transient_state.script;
+ sbic->error_handler = tgt->transient_state.handler;
+ sbic->done = SCSI_RET_IN_PROGRESS;
+
+ sbic->out_count = 0;
+ sbic->in_count = 0;
+
+ /* Define how the identify msg should be built */
+ GET_SBIC_rselid(regs, val);
+ val &= ~(SBIC_RID_MASK|SBIC_RID_ER);
+ /* the enable reselection bit is used to build the identify msg */
+ if (tgt->transient_state.identify != 0xff)
+ val |= (tgt->transient_state.identify & SCSI_IFY_ENABLE_DISCONNECT) << 1;
+ SET_SBIC_rselid(regs, val);
+ SET_SBIC_tlun(regs, tgt->lun);
+
+ /*
+ * Start the chip going
+ */
+ out_count = (*sbic->dma_ops->start_cmd)(sbic->dma_state, tgt);
+ SBIC_TC_PUT(regs, out_count);
+
+ val = tgt->target_id;
+ if (tgt->transient_state.in_count)
+ val |= SBIC_SID_FROM_SCSI;
+ SET_SBIC_selid(regs, val);
+
+ SET_SBIC_timo(regs,SBIC_TIMEOUT(250,SBIC_CLOCK_FREQUENCY));
+
+ SET_SBIC_syn(regs,SBIC_SYN(tgt->sync_offset,tgt->sync_period));
+
+ /* ugly little help for compiler */
+#define command out_count
+ if (tgt->flags & TGT_DID_SYNCH) {
+ command = (tgt->transient_state.identify == 0xff) ?
+ SBIC_CMD_SEL_XFER :
+ SBIC_CMD_SEL_ATN_XFER; /*preferred*/
+ } else if (tgt->flags & TGT_TRY_SYNCH)
+ command = SBIC_CMD_SEL_ATN;
+ else
+ command = SBIC_CMD_SEL_XFER;
+
+ /* load 10 bytes anyways, the chip knows how much to use */
+ SBIC_LOAD_COMMAND(regs, tgt->cmd_ptr, 10);
+
+ /* Try to avoid reselect collisions */
+ GET_SBIC_asr(regs,val);
+ if (val & SBIC_ASR_INT)
+ return;
+
+ SET_SBIC_cmd_phase(regs, 0); /* not a resume */
+ SET_SBIC_cmd(regs, command);
+#undef command
+}
+
+/*
+ * Interrupt routine
+ * Take interrupts from the chip
+ *
+ * Implementation:
+ * Move along the current command's script if
+ * all is well, invoke error handler if not.
+ */
+sbic_intr(unit, spllevel)
+ spl_t spllevel;
+{
+ register sbic_softc_t sbic;
+ register script_t scp;
+ register int asr, csr, pha;
+ register sbic_padded_regmap_t *regs;
+#if MAPPABLE
+ extern boolean_t rz_use_mapped_interface;
+
+ if (rz_use_mapped_interface)
+ return SBIC_intr(unit,spllevel);
+#endif /*MAPPABLE*/
+
+ sbic = sbic_softc[unit];
+ regs = sbic->regs;
+
+ LOG(5,"\n\tintr");
+
+ /* drop spurious interrupts */
+ GET_SBIC_asr(regs, asr);
+ if ((asr & SBIC_ASR_INT) == 0)
+ return;
+
+ /* collect ephemeral information */
+ GET_SBIC_cmd_phase(regs, pha);
+ GET_SBIC_csr(regs, csr);
+
+TR(csr);TR(asr);TR(pha);TRCHECK
+
+ /* XXX verify this is indeed the case for a SCSI RST asserted */
+ if ((csr & SBIC_CSR_CAUSE) == SBIC_CSR_RESET)
+ return sbic_bus_reset(sbic);
+
+ /* we got an interrupt allright */
+ if (sbic->active_target)
+ sbic->wd.watchdog_state = SCSI_WD_ACTIVE;
+
+ splx(spllevel); /* drop priority */
+
+ if ((sbic->state & SBIC_STATE_TARGET) ||
+ (csr == SBIC_CSR_RSLT_AM) || (csr == SBIC_CSR_RSLT_NOAM) ||
+ (csr == SBIC_CSR_SLT) || (csr == SBIC_CSR_SLT_ATN))
+ return sbic_target_intr(sbic);
+
+ /*
+ * In attempt_selection() we gave the select command even if
+ * the chip might have been reconnected already.
+ */
+ if ((csr == SBIC_CSR_RSLT_NI) || (csr == SBIC_CSR_RSLT_IFY))
+ return sbic_reconnect(sbic, csr, pha);
+
+ /*
+ * Check for parity errors
+ */
+ if (asr & SBIC_ASR_PE) {
+ char *msg;
+printf("{PE %x,%x}", asr, pha);
+
+ msg = "SCSI bus parity error";
+ /* all we can do is to throw a reset on the bus */
+ printf( "sbic%d: %s%s", sbic - sbic_softc_data, msg,
+ ", attempting recovery.\n");
+ sbic_reset(regs, FALSE);
+ return;
+ }
+
+ if ((scp = sbic->script) == 0) /* sanity */
+ return;
+
+ LOG(6,"match");
+ if (SCRIPT_MATCH(csr,pha,scp->condition)) {
+ /*
+ * Perform the appropriate operation,
+ * then proceed
+ */
+ if ((*scp->action)(sbic, csr, pha)) {
+ sbic->script = scp + 1;
+ }
+ } else
+ return (*sbic->error_handler)(sbic, csr, pha);
+}
+
+sbic_target_intr()
+{
+ panic("SBIC: TARGET MODE !!!\n");
+}
+
+/*
+ * Routines that the interrupt code might switch to
+ */
+
+boolean_t
+sbic_end(sbic, csr, pha)
+ register sbic_softc_t sbic;
+{
+ register target_info_t *tgt;
+ register io_req_t ior;
+
+ LOG(8,"end");
+
+ tgt = sbic->active_target;
+ if ((tgt->done = sbic->done) == SCSI_RET_IN_PROGRESS)
+ tgt->done = SCSI_RET_SUCCESS;
+
+ sbic->script = 0;
+
+ if (sbic->wd.nactive-- == 1)
+ sbic->wd.watchdog_state = SCSI_WD_INACTIVE;
+
+ sbic_release_bus(sbic);
+
+ if (ior = tgt->ior) {
+ (*sbic->dma_ops->end_cmd)(sbic->dma_state, tgt, ior);
+ LOG(0xA,"ops->restart");
+ (*tgt->dev_ops->restart)( tgt, TRUE);
+ }
+
+ return FALSE;
+}
+
+boolean_t
+sbic_release_bus(sbic)
+ register sbic_softc_t sbic;
+{
+ boolean_t ret = TRUE;
+
+ LOG(9,"release");
+ if (sbic->state & SBIC_STATE_COLLISION) {
+
+ LOG(0xB,"collided");
+ sbic->state &= ~SBIC_STATE_COLLISION;
+ sbic_attempt_selection(sbic);
+
+ } else if (queue_empty(&sbic->waiting_targets)) {
+
+ sbic->state &= ~SBIC_STATE_BUSY;
+ sbic->active_target = 0;
+ sbic->script = 0;
+ ret = FALSE;
+
+ } else {
+
+ LOG(0xC,"dequeue");
+ sbic->next_target = (target_info_t *)
+ dequeue_head(&sbic->waiting_targets);
+ sbic_attempt_selection(sbic);
+ }
+ return ret;
+}
+
+boolean_t
+sbic_get_status(sbic, csr, pha)
+ register sbic_softc_t sbic;
+{
+ register sbic_padded_regmap_t *regs = sbic->regs;
+ register scsi2_status_byte_t status;
+ int len;
+ io_req_t ior;
+ register target_info_t *tgt = sbic->active_target;
+
+ LOG(0xD,"get_status");
+TRWRAP
+
+ sbic->state &= ~SBIC_STATE_DMA_IN;
+
+ /*
+ * Get the status byte
+ */
+ GET_SBIC_tlun(regs, status.bits);
+
+ if (status.st.scsi_status_code != SCSI_ST_GOOD) {
+ scsi_error(sbic->active_target, SCSI_ERR_STATUS, status.bits, 0);
+ sbic->done = (status.st.scsi_status_code == SCSI_ST_BUSY) ?
+ SCSI_RET_RETRY : SCSI_RET_NEED_SENSE;
+ } else
+ sbic->done = SCSI_RET_SUCCESS;
+
+ /* Tell DMA engine we are done */
+ (*sbic->dma_ops->end_xfer)(sbic->dma_state, tgt, tgt->transient_state.in_count);
+
+ return sbic_end(sbic, csr, pha);
+
+}
+
+#if 0
+
+boolean_t
+sbic_dma_in(sbic, csr, ir)
+ register sbic_softc_t sbic;
+{
+ register target_info_t *tgt;
+ register sbic_padded_regmap_t *regs = sbic->regs;
+ register int count;
+ unsigned char ff = regs->sbic_flags;
+
+ LOG(0xE,"dma_in");
+ tgt = sbic->active_target;
+
+ sbic->state |= SBIC_STATE_DMA_IN;
+
+ count = (*sbic->dma_ops->start_datain)(sbic->dma_state, tgt);
+ SBIC_TC_PUT(regs, count);
+
+ if ((sbic->in_count = count) == tgt->transient_state.in_count)
+ return TRUE;
+ regs->sbic_cmd = sbic->script->command;
+ sbic->script = sbic_script_restart_data_in;
+ return FALSE;
+}
+
+sbic_dma_in_r(sbic, csr, ir)
+ register sbic_softc_t sbic;
+{
+ register target_info_t *tgt;
+ register sbic_padded_regmap_t *regs = sbic->regs;
+ register int count;
+ boolean_t advance_script = TRUE;
+
+
+ LOG(0xE,"dma_in");
+ tgt = sbic->active_target;
+
+ sbic->state |= SBIC_STATE_DMA_IN;
+
+ if (sbic->in_count == 0) {
+ /*
+ * Got nothing yet, we just reconnected.
+ */
+ register int avail;
+
+ /*
+ * Rather than using the messy RFB bit in cnfg2
+ * (which only works for synch xfer anyways)
+ * we just bump up the dma offset. We might
+ * endup with one more interrupt at the end,
+ * so what.
+ * This is done in sbic_err_disconn(), this
+ * way dma (of msg bytes too) is always aligned
+ */
+
+ count = (*sbic->dma_ops->restart_datain_1)
+ (sbic->dma_state, tgt);
+
+ /* common case of 8k-or-less read ? */
+ advance_script = (tgt->transient_state.in_count == count);
+
+ } else {
+
+ /*
+ * We received some data.
+ */
+ register int offset, xferred;
+
+ /*
+ * Problem: sometimes we get a 'spurious' interrupt
+ * right after a reconnect. It goes like disconnect,
+ * reconnect, dma_in_r, here but DMA is still rolling.
+ * Since there is no good reason we got here to begin with
+ * we just check for the case and dismiss it: we should
+ * get another interrupt when the TC goes to zero or the
+ * target disconnects.
+ */
+ SBIC_TC_GET(regs,xferred);
+ if (xferred != 0)
+ return FALSE;
+
+ xferred = sbic->in_count - xferred;
+ assert(xferred > 0);
+
+ tgt->transient_state.in_count -= xferred;
+ assert(tgt->transient_state.in_count > 0);
+
+ count = (*sbic->dma_ops->restart_datain_2)
+ (sbic->dma_state, tgt, xferred);
+
+ sbic->in_count = count;
+ SBIC_TC_PUT(regs, count);
+ regs->sbic_cmd = sbic->script->command;
+
+ (*sbic->dma_ops->restart_datain_3)
+ (sbic->dma_state, tgt);
+
+ /* last chunk ? */
+ if (count == tgt->transient_state.in_count)
+ sbic->script++;
+
+ return FALSE;
+ }
+
+ sbic->in_count = count;
+ SBIC_TC_PUT(regs, count);
+
+ if (!advance_script) {
+ regs->sbic_cmd = sbic->script->command;
+ }
+ return advance_script;
+}
+
+
+/* send data to target. Only called to start the xfer */
+
+boolean_t
+sbic_dma_out(sbic, csr, ir)
+ register sbic_softc_t sbic;
+{
+ register sbic_padded_regmap_t *regs = sbic->regs;
+ register int reload_count;
+ register target_info_t *tgt;
+ int command;
+
+ LOG(0xF,"dma_out");
+
+ SBIC_TC_GET(regs, reload_count);
+ sbic->extra_count = regs->sbic_flags & SBIC_FLAGS_FIFO_CNT;
+ reload_count += sbic->extra_count;
+ SBIC_TC_PUT(regs, reload_count);
+ sbic->state &= ~SBIC_STATE_DMA_IN;
+
+ tgt = sbic->active_target;
+
+ command = sbic->script->command;
+
+ if ((sbic->out_count = reload_count) >=
+ tgt->transient_state.out_count)
+ sbic->script++;
+ else
+ sbic->script = sbic_script_restart_data_out;
+
+ if ((*sbic->dma_ops->start_dataout)
+ (sbic->dma_state, tgt, &regs->sbic_cmd, command)) {
+ regs->sbic_cmd = command;
+ }
+
+ return FALSE;
+}
+
+/* send data to target. Called in two different ways:
+ (a) to restart a big transfer and
+ (b) after reconnection
+ */
+boolean_t
+sbic_dma_out_r(sbic, csr, ir)
+ register sbic_softc_t sbic;
+{
+ register sbic_padded_regmap_t *regs = sbic->regs;
+ register target_info_t *tgt;
+ boolean_t advance_script = TRUE;
+ int count;
+
+
+ LOG(0xF,"dma_out");
+
+ tgt = sbic->active_target;
+ sbic->state &= ~SBIC_STATE_DMA_IN;
+
+ if (sbic->out_count == 0) {
+ /*
+ * Nothing committed: we just got reconnected
+ */
+ count = (*sbic->dma_ops->restart_dataout_1)
+ (sbic->dma_state, tgt);
+
+ /* is this the last chunk ? */
+ advance_script = (tgt->transient_state.out_count == count);
+ } else {
+ /*
+ * We sent some data.
+ */
+ register int offset, xferred;
+
+ SBIC_TC_GET(regs,count);
+
+ /* see comment above */
+ if (count) {
+ return FALSE;
+ }
+
+ count += (regs->sbic_flags & SBIC_FLAGS_FIFO_CNT);
+ count -= sbic->extra_count;
+ xferred = sbic->out_count - count;
+ assert(xferred > 0);
+
+ tgt->transient_state.out_count -= xferred;
+ assert(tgt->transient_state.out_count > 0);
+
+ count = (*sbic->dma_ops->restart_dataout_2)
+ (sbic->dma_state, tgt, xferred);
+
+ /* last chunk ? */
+ if (tgt->transient_state.out_count == count)
+ goto quickie;
+
+ sbic->out_count = count;
+
+ sbic->extra_count = (*sbic->dma_ops->restart_dataout_3)
+ (sbic->dma_state, tgt, &regs->sbic_fifo);
+ SBIC_TC_PUT(regs, count);
+ regs->sbic_cmd = sbic->script->command;
+
+ (*sbic->dma_ops->restart_dataout_4)(sbic->dma_state, tgt);
+
+ return FALSE;
+ }
+
+quickie:
+ sbic->extra_count = (*sbic->dma_ops->restart_dataout_3)
+ (sbic->dma_state, tgt, &regs->sbic_fifo);
+
+ sbic->out_count = count;
+
+ SBIC_TC_PUT(regs, count);
+
+ if (!advance_script) {
+ regs->sbic_cmd = sbic->script->command;
+ }
+ return advance_script;
+}
+#endif /*0*/
+
+boolean_t
+sbic_dosynch(sbic, csr, pha)
+ register sbic_softc_t sbic;
+ register unsigned char csr, pha;
+{
+ register sbic_padded_regmap_t *regs = sbic->regs;
+ register unsigned char c;
+ int i, per, offs;
+ register target_info_t *tgt;
+
+ /*
+ * Try synch negotiation
+ * Phase is MSG_OUT here.
+ */
+ tgt = sbic->active_target;
+
+#if 0
+ regs->sbic_cmd = SBIC_CMD_FLUSH;
+ delay(2);
+
+ per = sbic_min_period;
+ if (BGET(scsi_no_synchronous_xfer,sbic->sc->masterno,tgt->target_id))
+ offs = 0;
+ else
+ offs = sbic_max_offset;
+
+ tgt->flags |= TGT_DID_SYNCH; /* only one chance */
+ tgt->flags &= ~TGT_TRY_SYNCH;
+
+ regs->sbic_fifo = SCSI_EXTENDED_MESSAGE;
+ regs->sbic_fifo = 3;
+ regs->sbic_fifo = SCSI_SYNC_XFER_REQUEST;
+ regs->sbic_fifo = sbic_to_scsi_period(regs,sbic_min_period);
+ regs->sbic_fifo = offs;
+ regs->sbic_cmd = SBIC_CMD_XFER_INFO;
+ csr = sbic_wait(regs, SBIC_CSR_INT);
+ ir = regs->sbic_intr;
+
+ if (SCSI_PHASE(csr) != SCSI_PHASE_MSG_IN)
+ gimmeabreak();
+
+ regs->sbic_cmd = SBIC_CMD_XFER_INFO;
+ csr = sbic_wait(regs, SBIC_CSR_INT);
+ ir = regs->sbic_intr;
+
+ while ((regs->sbic_flags & SBIC_FLAGS_FIFO_CNT) > 0)
+ c = regs->sbic_fifo; /* see what it says */
+
+ if (c == SCSI_MESSAGE_REJECT) {
+ printf(" did not like SYNCH xfer ");
+
+ /* Tk50s get in trouble with ATN, sigh. */
+ regs->sbic_cmd = SBIC_CMD_CLR_ATN;
+
+ goto cmd;
+ }
+
+ /*
+ * Receive the rest of the message
+ */
+ regs->sbic_cmd = SBIC_CMD_MSG_ACPT;
+ sbic_wait(regs, SBIC_CSR_INT);
+ ir = regs->sbic_intr;
+
+ if (c != SCSI_EXTENDED_MESSAGE)
+ gimmeabreak();
+
+ regs->sbic_cmd = SBIC_CMD_XFER_INFO;
+ sbic_wait(regs, SBIC_CSR_INT);
+ c = regs->sbic_intr;
+ if (regs->sbic_fifo != 3)
+ panic("sbic_dosynch");
+
+ for (i = 0; i < 3; i++) {
+ regs->sbic_cmd = SBIC_CMD_MSG_ACPT;
+ sbic_wait(regs, SBIC_CSR_INT);
+ c = regs->sbic_intr;
+
+ regs->sbic_cmd = SBIC_CMD_XFER_INFO;
+ sbic_wait(regs, SBIC_CSR_INT);
+ c = regs->sbic_intr;/*ack*/
+ c = regs->sbic_fifo;
+
+ if (i == 1) tgt->sync_period = scsi_period_to_sbic(regs,c);
+ if (i == 2) tgt->sync_offset = c;
+ }
+
+cmd:
+ regs->sbic_cmd = SBIC_CMD_MSG_ACPT;
+ csr = sbic_wait(regs, SBIC_CSR_INT);
+ c = regs->sbic_intr;
+
+ /* phase should normally be command here */
+ if (SCSI_PHASE(csr) == SCSI_PHASE_CMD) {
+ /* test unit ready or what ? */
+ regs->sbic_fifo = 0;
+ regs->sbic_fifo = 0;
+ regs->sbic_fifo = 0;
+ regs->sbic_fifo = 0;
+ regs->sbic_fifo = 0;
+ regs->sbic_fifo = 0;
+ SBIC_TC_PUT(regs,0xff);
+ regs->sbic_cmd = SBIC_CMD_XFER_PAD; /*0x98*/
+ csr = sbic_wait(regs, SBIC_CSR_INT);
+ ir = regs->sbic_intr;/*ack*/
+ }
+
+status:
+ if (SCSI_PHASE(csr) != SCSI_PHASE_STATUS)
+ gimmeabreak();
+
+#endif
+ return TRUE;
+}
+
+/*
+ * The bus was reset
+ */
+sbic_bus_reset(sbic)
+ register sbic_softc_t sbic;
+{
+ register sbic_padded_regmap_t *regs = sbic->regs;
+
+ LOG(0x1d,"bus_reset");
+
+ /*
+ * Clear bus descriptor
+ */
+ sbic->script = 0;
+ sbic->error_handler = 0;
+ sbic->active_target = 0;
+ sbic->next_target = 0;
+ sbic->state &= SBIC_STATE_AM_MODE; /* save this one bit only */
+ queue_init(&sbic->waiting_targets);
+ sbic->wd.nactive = 0;
+ (void) sbic_reset(regs, TRUE);
+
+ printf("sbic: (%d) bus reset ", ++sbic->wd.reset_count);
+ delay(scsi_delay_after_reset); /* some targets take long to reset */
+
+ if (sbic->sc == 0) /* sanity */
+ return;
+
+ scsi_bus_was_reset(sbic->sc);
+}
+
+/*
+ * Disconnect/reconnect mode ops
+ */
+
+/* save all relevant data, free the BUS */
+boolean_t
+sbic_disconnected(sbic, csr, pha)
+ register sbic_softc_t sbic;
+ register unsigned char csr, pha;
+
+{
+ register target_info_t *tgt;
+
+ LOG(0x11,"disconnected");
+
+ tgt = sbic->active_target;
+ tgt->flags |= TGT_DISCONNECTED;
+ tgt->transient_state.handler = sbic->error_handler;
+ /* anything else was saved in sbic_err_disconn() */
+
+ PRINT(("{D%d}", tgt->target_id));
+
+ sbic_release_bus(sbic);
+
+ return FALSE;
+}
+
+/* See who reconnected, restore BUS */
+boolean_t
+sbic_reconnect(sbic, csr, ir)
+ register sbic_softc_t sbic;
+ register unsigned char csr, ir;
+
+{
+ register target_info_t *tgt;
+ sbic_padded_regmap_t *regs;
+ int id, pha;
+
+ LOG(0x12,"reconnect");
+ /*
+ * See if this reconnection collided with a selection attempt
+ */
+ if (sbic->state & SBIC_STATE_BUSY)
+ sbic->state |= SBIC_STATE_COLLISION;
+
+ sbic->state |= SBIC_STATE_BUSY;
+
+ /* find tgt */
+ regs = sbic->regs;
+ GET_SBIC_rselid(regs,id);
+
+ id &= 0x7;
+
+ if ((sbic->state & SBIC_STATE_AM) == 0) {
+ /* Must pick the identify */
+ pha = 0x44;
+ } else
+ pha = 0x45;
+
+ tgt = sbic->sc->target[id];
+ if (id > 7 || tgt == 0) panic("sbic_reconnect");
+
+ /* synch things*/
+ SET_SBIC_syn(regs,SBIC_SYN(tgt->sync_offset,tgt->sync_period));
+
+ PRINT(("{R%d}", id));
+ if (sbic->state & SBIC_STATE_COLLISION)
+ PRINT(("[B %d-%d]", sbic->active_target->target_id, id));
+
+ LOG(0x80+id,0);
+
+ sbic->active_target = tgt;
+ tgt->flags &= ~TGT_DISCONNECTED;
+
+ sbic->script = tgt->transient_state.script;
+ sbic->error_handler = tgt->transient_state.handler;
+ sbic->in_count = 0;
+ sbic->out_count = 0;
+
+set counter and setup dma, then
+
+ /* Resume the command now */
+ SET_SBIC_cmd_phase(regs, pha);
+ SET_SBIC_cmd(regs, SBIC_CMD_SEL_XFER);
+
+ return FALSE;
+}
+
+TILL HERE
+
+/*
+ * Error handlers
+ */
+
+/*
+ * Fall-back error handler.
+ */
+sbic_err_generic(sbic, csr, ir)
+ register sbic_softc_t sbic;
+{
+ LOG(0x13,"err_generic");
+
+ /* handle non-existant or powered off devices here */
+ if ((ir == SBIC_INT_DISC) &&
+ (sbic_isa_select(sbic->cmd_was)) &&
+ (SBIC_SS(sbic->ss_was) == 0)) {
+ /* Powered off ? */
+ if (sbic->active_target->flags & TGT_FULLY_PROBED)
+ sbic->active_target->flags = 0;
+ sbic->done = SCSI_RET_DEVICE_DOWN;
+ sbic_end(sbic, csr, ir);
+ return;
+ }
+
+ switch (SCSI_PHASE(csr)) {
+ case SCSI_PHASE_STATUS:
+ if (sbic->script[-1].condition == SCSI_PHASE_STATUS) {
+ /* some are just slow to get out.. */
+ } else
+ sbic_err_to_status(sbic, csr, ir);
+ return;
+ break;
+ case SCSI_PHASE_DATAI:
+ if (sbic->script->condition == SCSI_PHASE_STATUS) {
+/* printf("{P}");*/
+ return;
+ }
+ break;
+ case SCSI_PHASE_DATAO:
+ if (sbic->script->condition == SCSI_PHASE_STATUS) {
+ /*
+ * See comment above. Actually seen on hitachis.
+ */
+/* printf("{P}");*/
+ return;
+ }
+ }
+ gimmeabreak();
+}
+
+/*
+ * Handle disconnections as exceptions
+ */
+sbic_err_disconn(sbic, csr, ir)
+ register sbic_softc_t sbic;
+ register unsigned char csr, ir;
+{
+ register sbic_padded_regmap_t *regs;
+ register target_info_t *tgt;
+ int count;
+ boolean_t callback = FALSE;
+
+ LOG(0x16,"err_disconn");
+
+ if (SCSI_PHASE(csr) != SCSI_PHASE_MSG_IN)
+ return sbic_err_generic(sbic, csr, ir);
+
+ regs = sbic->regs;
+ tgt = sbic->active_target;
+
+ switch (sbic->script->condition) {
+ case SCSI_PHASE_DATAO:
+ LOG(0x1b,"+DATAO");
+ if (sbic->out_count) {
+ register int xferred, offset;
+
+ SBIC_TC_GET(regs,xferred); /* temporary misnomer */
+ xferred += regs->sbic_flags & SBIC_FLAGS_FIFO_CNT;
+ xferred -= sbic->extra_count;
+ xferred = sbic->out_count - xferred; /* ok now */
+ tgt->transient_state.out_count -= xferred;
+ assert(tgt->transient_state.out_count > 0);
+
+ callback = (*sbic->dma_ops->disconn_1)
+ (sbic->dma_state, tgt, xferred);
+
+ } else {
+
+ callback = (*sbic->dma_ops->disconn_2)
+ (sbic->dma_state, tgt);
+
+ }
+ sbic->extra_count = 0;
+ tgt->transient_state.script = sbic_script_restart_data_out;
+ break;
+
+
+ case SCSI_PHASE_DATAI:
+ LOG(0x17,"+DATAI");
+ if (sbic->in_count) {
+ register int offset, xferred;
+
+ SBIC_TC_GET(regs,count);
+ xferred = sbic->in_count - count;
+ assert(xferred > 0);
+
+if (regs->sbic_flags & 0xf)
+printf("{Xf %x,%x,%x}", xferred, sbic->in_count, regs->sbic_flags & SBIC_FLAGS_FIFO_CNT);
+ tgt->transient_state.in_count -= xferred;
+ assert(tgt->transient_state.in_count > 0);
+
+ callback = (*sbic->dma_ops->disconn_3)
+ (sbic->dma_state, tgt, xferred);
+
+ tgt->transient_state.script = sbic_script_restart_data_in;
+ if (tgt->transient_state.in_count == 0)
+ tgt->transient_state.script++;
+
+ }
+ tgt->transient_state.script = sbic->script;
+ break;
+
+ case SCSI_PHASE_STATUS:
+ /* will have to restart dma */
+ SBIC_TC_GET(regs,count);
+ if (sbic->state & SBIC_STATE_DMA_IN) {
+ register int offset, xferred;
+
+ LOG(0x1a,"+STATUS+R");
+
+ xferred = sbic->in_count - count;
+ assert(xferred > 0);
+
+if (regs->sbic_flags & 0xf)
+printf("{Xf %x,%x,%x}", xferred, sbic->in_count, regs->sbic_flags & SBIC_FLAGS_FIFO_CNT);
+ tgt->transient_state.in_count -= xferred;
+/* assert(tgt->transient_state.in_count > 0);*/
+
+ callback = (*sbic->dma_ops->disconn_4)
+ (sbic->dma_state, tgt, xferred);
+
+ tgt->transient_state.script = sbic_script_restart_data_in;
+ if (tgt->transient_state.in_count == 0)
+ tgt->transient_state.script++;
+
+ } else {
+
+ /* add what's left in the fifo */
+ count += (regs->sbic_flags & SBIC_FLAGS_FIFO_CNT);
+ /* take back the extra we might have added */
+ count -= sbic->extra_count;
+ /* ..and drop that idea */
+ sbic->extra_count = 0;
+
+ LOG(0x19,"+STATUS+W");
+
+
+ if ((count == 0) && (tgt->transient_state.out_count == sbic->out_count)) {
+ /* all done */
+ tgt->transient_state.script = sbic->script;
+ tgt->transient_state.out_count = 0;
+ } else {
+ register int xferred, offset;
+
+ /* how much we xferred */
+ xferred = sbic->out_count - count;
+
+ tgt->transient_state.out_count -= xferred;
+ assert(tgt->transient_state.out_count > 0);
+
+ callback = (*sbic->dma_ops->disconn_5)
+ (sbic->dma_state,tgt,xferred);
+
+ tgt->transient_state.script = sbic_script_restart_data_out;
+ }
+ sbic->out_count = 0;
+ }
+ break;
+ default:
+ gimmeabreak();
+ return;
+ }
+ sbic_msg_in(sbic,csr,ir);
+ sbic->script = sbic_script_disconnect;
+ regs->sbic_cmd = SBIC_CMD_XFER_INFO|SBIC_CMD_DMA;
+ if (callback)
+ (*sbic->dma_ops->disconn_callback)(sbic->dma_state, tgt);
+}
+
+/*
+ * Watchdog
+ *
+ * We know that some (name withdrawn) disks get
+ * stuck in the middle of dma phases...
+ */
+sbic_reset_scsibus(sbic)
+ register sbic_softc_t sbic;
+{
+ register target_info_t *tgt = sbic->active_target;
+ register sbic_padded_regmap_t *regs = sbic->regs;
+ register int ir;
+
+ if (scsi_debug && tgt) {
+ int dmalen;
+ SBIC_TC_GET(sbic->regs,dmalen);
+ printf("Target %d was active, cmd x%x in x%x out x%x Sin x%x Sou x%x dmalen x%x\n",
+ tgt->target_id, tgt->cur_cmd,
+ tgt->transient_state.in_count, tgt->transient_state.out_count,
+ sbic->in_count, sbic->out_count,
+ dmalen);
+ }
+ ir = regs->sbic_intr;
+ if ((ir & SBIC_INT_RESEL) && (SCSI_PHASE(regs->sbic_csr) == SCSI_PHASE_MSG_IN)) {
+ /* getting it out of the woods is a bit tricky */
+ spl_t s = splbio();
+
+ (void) sbic_reconnect(sbic, regs->sbic_csr, ir);
+ sbic_wait(regs, SBIC_CSR_INT);
+ ir = regs->sbic_intr;
+ regs->sbic_cmd = SBIC_CMD_MSG_ACPT;
+ splx(s);
+ } else {
+ regs->sbic_cmd = SBIC_CMD_BUS_RESET;
+ delay(35);
+ }
+}
+
+#endif NSBIC > 0
+
+#endif 0