summaryrefslogtreecommitdiffstats
path: root/sys/dev/sym
diff options
context:
space:
mode:
authorgroudier <groudier@FreeBSD.org>2000-04-29 10:20:16 +0000
committergroudier <groudier@FreeBSD.org>2000-04-29 10:20:16 +0000
commit22b8c23cfa70ae85832d75bd7e71984b28507497 (patch)
treeb5d865d29a9faee6c30a80fc0208481489c3034a /sys/dev/sym
parent706084939e6e22a3e98307ed10974cabdff2837c (diff)
downloadFreeBSD-src-22b8c23cfa70ae85832d75bd7e71984b28507497.zip
FreeBSD-src-22b8c23cfa70ae85832d75bd7e71984b28507497.tar.gz
This new version adds support for early NCR chips.
53C810 non 'A', 53C815 and 53C825 non 'A' are now attached by the driver (by default). The driver uses a different SCRIPTS set based on MEMORY MOVE instructions for these chips. 2 SCRIPTS sets (firmwares) numbered #1 and #2 are used for the whole support of the 53C8XX family to get possible: - FW #1 : Only based on MEMORY MOVE instructions. Selected for 810, 815, 825. - FW #2 : LOAD/STORE based. This is the firmware also used by previous driver versions. Selected for other chips. When both `ncr' and `sym' are configured, `sym' will now attach all the 53C8XX devices by default. Previous balancing between `ncr' and `sym' can be preserved by: - Either editing sym_conf.h and commenting the following compile option: #define SYM_CONF_GENERIC_SUPPORT (This also saves about 3.5Kb of kernel memory). - Or setting kernel config option SYM_SETUP_LP_PROBE_MAP to 64 (bit 0x40)
Diffstat (limited to 'sys/dev/sym')
-rw-r--r--sys/dev/sym/sym_conf.h21
-rw-r--r--sys/dev/sym/sym_defs.h5
-rw-r--r--sys/dev/sym/sym_fw.h208
-rw-r--r--sys/dev/sym/sym_fw1.h1798
-rw-r--r--sys/dev/sym/sym_fw2.h1850
-rw-r--r--sys/dev/sym/sym_hipd.c2751
6 files changed, 4517 insertions, 2116 deletions
diff --git a/sys/dev/sym/sym_conf.h b/sys/dev/sym/sym_conf.h
index 44b06f2..2fe71d8 100644
--- a/sys/dev/sym/sym_conf.h
+++ b/sys/dev/sym/sym_conf.h
@@ -5,10 +5,9 @@
* Copyright (C) 1999-2000 Gerard Roudier <groudier@club-internet.fr>
*
* This driver also supports the following Symbios/LSI PCI-SCSI chips:
- * 53C810A, 53C825A, 53C860, 53C875, 53C876, 53C885, 53C895.
+ * 53C810A, 53C825A, 53C860, 53C875, 53C876, 53C885, 53C895,
+ * 53C810, 53C815, 53C825 and the 53C1510D is 53C8XX mode.
*
- * but does not support earlier chips as the following ones:
- * 53C810, 53C815, 53C825.
*
* This driver for FreeBSD-CAM is derived from the Linux sym53c8xx driver.
* Copyright (C) 1998-1999 Gerard Roudier
@@ -67,6 +66,11 @@
*/
/*
+ * Also support early NCR 810, 815 and 825 chips.
+ */
+#define SYM_CONF_GENERIC_SUPPORT
+
+/*
* Use Normal IO instead of MMIO.
*/
/* #define SYM_CONF_IOMAPPED */
@@ -115,7 +119,7 @@
* Support for NVRAM.
*/
#define SYM_CONF_NVRAM_SUPPORT
-/* #define SYM_CONF_DEBUG_SUPPORT */
+/* #define SYM_CONF_NVRAM_SUPPORT */
/*
* Support for Immediate Arbitration.
@@ -272,10 +276,11 @@
* driver are configured.
*
* Bits are to be coded as follows:
- * 1 -> 810a, 860
- * 2 -> 825a, 875, 885, 895
- * 4 -> 895a, 896, 1510d
- * 8 -> 1010
+ * 0x01 -> 810a, 860
+ * 0x02 -> 825a, 875, 885, 895
+ * 0x04 -> 895a, 896, 1510d
+ * 0x08 -> 1010
+ * 0x40 -> 810, 815, 825
*
* For example, value 5 tells the driver to claim support
* for 810a, 860, 895a, 896 and 1510d with low priority,
diff --git a/sys/dev/sym/sym_defs.h b/sys/dev/sym/sym_defs.h
index 5e84055..d456d04 100644
--- a/sys/dev/sym/sym_defs.h
+++ b/sys/dev/sym/sym_defs.h
@@ -5,10 +5,9 @@
* Copyright (C) 1999-2000 Gerard Roudier <groudier@club-internet.fr>
*
* This driver also supports the following Symbios/LSI PCI-SCSI chips:
- * 53C810A, 53C825A, 53C860, 53C875, 53C876, 53C885, 53C895.
+ * 53C810A, 53C825A, 53C860, 53C875, 53C876, 53C885, 53C895,
+ * 53C810, 53C815, 53C825 and the 53C1510D is 53C8XX mode.
*
- * but does not support earlier chips as the following ones:
- * 53C810, 53C815, 53C825.
*
* This driver for FreeBSD-CAM is derived from the Linux sym53c8xx driver.
* Copyright (C) 1998-1999 Gerard Roudier
diff --git a/sys/dev/sym/sym_fw.h b/sys/dev/sym/sym_fw.h
new file mode 100644
index 0000000..23b7099
--- /dev/null
+++ b/sys/dev/sym/sym_fw.h
@@ -0,0 +1,208 @@
+/*
+ * Device driver optimized for the Symbios/LSI 53C896/53C895A/53C1010
+ * PCI-SCSI controllers.
+ *
+ * Copyright (C) 1999-2000 Gerard Roudier <groudier@club-internet.fr>
+ *
+ * This driver also supports the following Symbios/LSI PCI-SCSI chips:
+ * 53C810A, 53C825A, 53C860, 53C875, 53C876, 53C885, 53C895,
+ * 53C810, 53C815, 53C825 and the 53C1510D is 53C8XX mode.
+ *
+ *
+ * This driver for FreeBSD-CAM is derived from the Linux sym53c8xx driver.
+ * Copyright (C) 1998-1999 Gerard Roudier
+ *
+ * The sym53c8xx driver is derived from the ncr53c8xx driver that had been
+ * a port of the FreeBSD ncr driver to Linux-1.2.13.
+ *
+ * The original ncr driver has been written for 386bsd and FreeBSD by
+ * Wolfgang Stanglmeier <wolf@cologne.de>
+ * Stefan Esser <se@mi.Uni-Koeln.de>
+ * Copyright (C) 1994 Wolfgang Stanglmeier
+ *
+ * The initialisation code, and part of the code that addresses
+ * FreeBSD-CAM services is based on the aic7xxx driver for FreeBSD-CAM
+ * written by Justin T. Gibbs.
+ *
+ * Other major contributions:
+ *
+ * NVRAM detection and reading.
+ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
+ *
+ *-----------------------------------------------------------------------------
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $FreeBSD$ */
+
+#ifndef SYM_FW_H
+#define SYM_FW_H
+/*
+ * Macro used to generate interfaces for script A.
+ */
+#define SYM_GEN_FW_A(s) \
+ SYM_GEN_A(s, start) SYM_GEN_A(s, getjob_begin) \
+ SYM_GEN_A(s, getjob_end) \
+ SYM_GEN_A(s, select) SYM_GEN_A(s, wf_sel_done) \
+ SYM_GEN_A(s, send_ident) \
+ SYM_GEN_A(s, dispatch) SYM_GEN_A(s, init) \
+ SYM_GEN_A(s, clrack) SYM_GEN_A(s, complete_error) \
+ SYM_GEN_A(s, done) SYM_GEN_A(s, done_end) \
+ SYM_GEN_A(s, idle) SYM_GEN_A(s, ungetjob) \
+ SYM_GEN_A(s, reselect) \
+ SYM_GEN_A(s, resel_tag) SYM_GEN_A(s, resel_dsa) \
+ SYM_GEN_A(s, resel_no_tag) \
+ SYM_GEN_A(s, data_in) SYM_GEN_A(s, data_in2) \
+ SYM_GEN_A(s, data_out) SYM_GEN_A(s, data_out2) \
+ SYM_GEN_A(s, pm0_data) SYM_GEN_A(s, pm1_data)
+
+/*
+ * Macro used to generate interfaces for script B.
+ */
+#define SYM_GEN_FW_B(s) \
+ SYM_GEN_B(s, no_data) \
+ SYM_GEN_B(s, sel_for_abort) SYM_GEN_B(s, sel_for_abort_1) \
+ SYM_GEN_B(s, msg_bad) SYM_GEN_B(s, msg_weird) \
+ SYM_GEN_B(s, wdtr_resp) SYM_GEN_B(s, send_wdtr) \
+ SYM_GEN_B(s, sdtr_resp) SYM_GEN_B(s, send_sdtr) \
+ SYM_GEN_B(s, ppr_resp) SYM_GEN_B(s, send_ppr) \
+ SYM_GEN_B(s, nego_bad_phase) \
+ SYM_GEN_B(s, ident_break) SYM_GEN_B(s, ident_break_atn) \
+ SYM_GEN_B(s, sdata_in) SYM_GEN_B(s, resel_bad_lun) \
+ SYM_GEN_B(s, bad_i_t_l) SYM_GEN_B(s, bad_i_t_l_q) \
+ SYM_GEN_B(s, wsr_ma_helper) \
+ SYM_GEN_B(s, snooptest) SYM_GEN_B(s, snoopend)
+
+/*
+ * Generates structure interface that contains
+ * offsets within script A and script B.
+ */
+#define SYM_GEN_A(s, label) s label;
+#define SYM_GEN_B(s, label) s label;
+struct sym_fwa_ofs {
+ SYM_GEN_FW_A(u_short)
+};
+struct sym_fwb_ofs {
+ SYM_GEN_FW_B(u_short)
+ SYM_GEN_B(u_short, start64);
+ SYM_GEN_B(u_short, pm_handle);
+};
+
+/*
+ * Generates structure interface that contains
+ * bus addresses within script A and script B.
+ */
+struct sym_fwa_ba {
+ SYM_GEN_FW_A(u32)
+};
+struct sym_fwb_ba {
+ SYM_GEN_FW_B(u32)
+ SYM_GEN_B(u32, start64);
+ SYM_GEN_B(u32, pm_handle);
+};
+#undef SYM_GEN_A
+#undef SYM_GEN_B
+
+/*
+ * Let cc know about the name of the controller data structure.
+ * We need this for function prototype declarations just below.
+ */
+struct sym_hcb;
+
+/*
+ * Generic structure that defines a firmware.
+ */
+struct sym_fw {
+ char *name; /* Name we want to print out */
+ u32 *a_base; /* Pointer to script A template */
+ int a_size; /* Size of script A */
+ struct sym_fwa_ofs
+ *a_ofs; /* Useful offsets in script A */
+ u32 *b_base; /* Pointer to script B template */
+ int b_size; /* Size of script B */
+ struct sym_fwb_ofs
+ *b_ofs; /* Useful offsets in script B */
+ /* Setup and patch methods for this firmware */
+ void (*setup)(struct sym_hcb *, struct sym_fw *);
+ void (*patch)(struct sym_hcb *);
+};
+
+/*
+ * Macro used to declare a firmware.
+ */
+#define SYM_FW_ENTRY(fw, name) \
+{ \
+ name, \
+ (u32 *) &fw##a_scr, sizeof(fw##a_scr), &fw##a_ofs, \
+ (u32 *) &fw##b_scr, sizeof(fw##b_scr), &fw##b_ofs, \
+ fw##_setup, fw##_patch \
+}
+
+/*
+ * Macros used from the C code to get useful
+ * SCRIPTS bus addresses.
+ */
+#define SCRIPTA_BA(np, label) (np->fwa_bas.label)
+#define SCRIPTB_BA(np, label) (np->fwb_bas.label)
+#define SCRIPTB0_BA(np,label) \
+ (np->scriptb0_ba + (np->fwb_bas.label - np->scriptb_ba))
+
+/*
+ * Macros used by scripts definitions.
+ *
+ * HADDR_1 generates a reference to a field of the controller data.
+ * HADDR_2 generates a reference to a field of the controller data
+ * with offset.
+ * RADDR_1 generates a reference to a script processor register.
+ * RADDR_2 generates a reference to a script processor register
+ * with offset.
+ * PADDR_A generates a reference to another part of script A.
+ * PADDR_B generates a reference to another part of script B.
+ *
+ * SYM_GEN_PADDR_A and SYM_GEN_PADDR_B are used to define respectively
+ * the PADDR_A and PADDR_B macros for each firmware by setting argument
+ * `s' to the name of the corresponding structure.
+ *
+ * SCR_DATA_ZERO is used to allocate a DWORD of data in scripts areas.
+ */
+
+#define RELOC_SOFTC 0x40000000
+#define RELOC_LABEL_A 0x50000000
+#define RELOC_REGISTER 0x60000000
+#define RELOC_LABEL_B 0x80000000
+#define RELOC_MASK 0xf0000000
+
+#define HADDR_1(label) (RELOC_SOFTC | offsetof(struct sym_hcb, label))
+#define HADDR_2(label,ofs) (RELOC_SOFTC | \
+ (offsetof(struct sym_hcb, label)+(ofs)))
+#define RADDR_1(label) (RELOC_REGISTER | REG(label))
+#define RADDR_2(label,ofs) (RELOC_REGISTER | ((REG(label))+(ofs)))
+
+#define SYM_GEN_PADDR_A(s, label) (RELOC_LABEL_A | offsetof(s, label))
+#define SYM_GEN_PADDR_B(s, label) (RELOC_LABEL_B | offsetof(s, label))
+
+#define SCR_DATA_ZERO 0xf00ff00f
+
+#endif /* SYM_FW_H */
diff --git a/sys/dev/sym/sym_fw1.h b/sys/dev/sym/sym_fw1.h
new file mode 100644
index 0000000..8c84f02
--- /dev/null
+++ b/sys/dev/sym/sym_fw1.h
@@ -0,0 +1,1798 @@
+/*
+ * Device driver optimized for the Symbios/LSI 53C896/53C895A/53C1010
+ * PCI-SCSI controllers.
+ *
+ * Copyright (C) 1999-2000 Gerard Roudier <groudier@club-internet.fr>
+ *
+ * This driver also supports the following Symbios/LSI PCI-SCSI chips:
+ * 53C810A, 53C825A, 53C860, 53C875, 53C876, 53C885, 53C895,
+ * 53C810, 53C815, 53C825 and the 53C1510D is 53C8XX mode.
+ *
+ *
+ * This driver for FreeBSD-CAM is derived from the Linux sym53c8xx driver.
+ * Copyright (C) 1998-1999 Gerard Roudier
+ *
+ * The sym53c8xx driver is derived from the ncr53c8xx driver that had been
+ * a port of the FreeBSD ncr driver to Linux-1.2.13.
+ *
+ * The original ncr driver has been written for 386bsd and FreeBSD by
+ * Wolfgang Stanglmeier <wolf@cologne.de>
+ * Stefan Esser <se@mi.Uni-Koeln.de>
+ * Copyright (C) 1994 Wolfgang Stanglmeier
+ *
+ * The initialisation code, and part of the code that addresses
+ * FreeBSD-CAM services is based on the aic7xxx driver for FreeBSD-CAM
+ * written by Justin T. Gibbs.
+ *
+ * Other major contributions:
+ *
+ * NVRAM detection and reading.
+ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
+ *
+ *-----------------------------------------------------------------------------
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $FreeBSD$ */
+
+/*
+ * Scripts for SYMBIOS-Processor
+ *
+ * We have to know the offsets of all labels before we reach
+ * them (for forward jumps). Therefore we declare a struct
+ * here. If you make changes inside the script,
+ *
+ * DONT FORGET TO CHANGE THE LENGTHS HERE!
+ */
+
+/*
+ * Script fragments which are loaded into the on-chip RAM
+ * of 825A, 875, 876, 895, 895A, 896 and 1010 chips.
+ * Must not exceed 4K bytes.
+ */
+struct SYM_FWA_SCR {
+ u32 start [ 11];
+ u32 getjob_begin [ 4];
+ u32 _sms_a10 [ 5];
+ u32 getjob_end [ 4];
+ u32 _sms_a20 [ 4];
+ u32 select [ 8];
+ u32 _sms_a30 [ 8];
+ u32 wf_sel_done [ 2];
+ u32 send_ident [ 2];
+#ifdef SYM_CONF_IARB_SUPPORT
+ u32 select2 [ 8];
+#else
+ u32 select2 [ 2];
+#endif
+ u32 command [ 2];
+ u32 dispatch [ 28];
+ u32 sel_no_cmd [ 10];
+ u32 init [ 6];
+ u32 clrack [ 4];
+ u32 disp_status [ 4];
+ u32 datai_done [ 26];
+ u32 datao_done [ 12];
+ u32 datai_phase [ 2];
+ u32 datao_phase [ 2];
+ u32 msg_in [ 2];
+ u32 msg_in2 [ 10];
+#ifdef SYM_CONF_IARB_SUPPORT
+ u32 status [ 14];
+#else
+ u32 status [ 10];
+#endif
+ u32 complete [ 9];
+ u32 complete2 [ 8];
+ u32 _sms_a40 [ 12];
+ u32 complete_error [ 5];
+ u32 done [ 5];
+ u32 _sms_a50 [ 5];
+ u32 _sms_a60 [ 2];
+ u32 done_end [ 4];
+ u32 save_dp [ 9];
+ u32 restore_dp [ 5];
+ u32 disconnect [ 20];
+ u32 disconnect2 [ 5];
+ u32 _sms_a65 [ 3];
+#ifdef SYM_CONF_IARB_SUPPORT
+ u32 idle [ 4];
+#else
+ u32 idle [ 2];
+#endif
+#ifdef SYM_CONF_IARB_SUPPORT
+ u32 ungetjob [ 7];
+#else
+ u32 ungetjob [ 5];
+#endif
+ u32 reselect [ 4];
+ u32 reselected [ 19];
+ u32 _sms_a70 [ 6];
+ u32 _sms_a80 [ 4];
+ u32 reselected1 [ 25];
+ u32 _sms_a90 [ 4];
+ u32 resel_lun0 [ 7];
+ u32 _sms_a100 [ 4];
+ u32 resel_tag [ 8];
+#if SYM_CONF_MAX_TASK*4 > 512
+ u32 _sms_a110 [ 23];
+#elif SYM_CONF_MAX_TASK*4 > 256
+ u32 _sms_a110 [ 17];
+#else
+ u32 _sms_a110 [ 13];
+#endif
+ u32 _sms_a120 [ 2];
+ u32 resel_go [ 4];
+ u32 _sms_a130 [ 7];
+ u32 resel_dsa [ 2];
+ u32 resel_dsa1 [ 4];
+ u32 _sms_a140 [ 10];
+ u32 resel_no_tag [ 4];
+ u32 _sms_a145 [ 7];
+ u32 data_in [SYM_CONF_MAX_SG * 2];
+ u32 data_in2 [ 4];
+ u32 data_out [SYM_CONF_MAX_SG * 2];
+ u32 data_out2 [ 4];
+ u32 pm0_data [ 12];
+ u32 pm0_data_out [ 6];
+ u32 pm0_data_end [ 7];
+ u32 pm_data_end [ 4];
+ u32 _sms_a150 [ 4];
+ u32 pm1_data [ 12];
+ u32 pm1_data_out [ 6];
+ u32 pm1_data_end [ 9];
+};
+
+/*
+ * Script fragments which stay in main memory for all chips
+ * except for chips that support 8K on-chip RAM.
+ */
+struct SYM_FWB_SCR {
+ u32 no_data [ 2];
+ u32 sel_for_abort [ 18];
+ u32 sel_for_abort_1 [ 2];
+ u32 msg_in_etc [ 12];
+ u32 msg_received [ 5];
+ u32 msg_weird_seen [ 5];
+ u32 msg_extended [ 17];
+ u32 _sms_b10 [ 4];
+ u32 msg_bad [ 6];
+ u32 msg_weird [ 4];
+ u32 msg_weird1 [ 8];
+ u32 wdtr_resp [ 6];
+ u32 send_wdtr [ 4];
+ u32 sdtr_resp [ 6];
+ u32 send_sdtr [ 4];
+ u32 ppr_resp [ 6];
+ u32 send_ppr [ 4];
+ u32 nego_bad_phase [ 4];
+ u32 msg_out [ 4];
+ u32 msg_out_done [ 4];
+ u32 data_ovrun [ 3];
+ u32 data_ovrun1 [ 22];
+ u32 data_ovrun2 [ 8];
+ u32 abort_resel [ 16];
+ u32 resend_ident [ 4];
+ u32 ident_break [ 4];
+ u32 ident_break_atn [ 4];
+ u32 sdata_in [ 6];
+ u32 resel_bad_lun [ 4];
+ u32 bad_i_t_l [ 4];
+ u32 bad_i_t_l_q [ 4];
+ u32 bad_status [ 7];
+ u32 wsr_ma_helper [ 4];
+
+ /* Data area */
+ u32 zero [ 1];
+ u32 scratch [ 1];
+ u32 scratch1 [ 1];
+ u32 prev_done [ 1];
+ u32 done_pos [ 1];
+ u32 nextjob [ 1];
+ u32 startpos [ 1];
+ u32 targtbl [ 1];
+ /* End of data area */
+
+ u32 snooptest [ 9];
+ u32 snoopend [ 2];
+};
+
+static struct SYM_FWA_SCR SYM_FWA_SCR = {
+/*--------------------------< START >----------------------------*/ {
+ /*
+ * Switch the LED on.
+ * Will be patched with a NO_OP if LED
+ * not needed or not desired.
+ */
+ SCR_REG_REG (gpreg, SCR_AND, 0xfe),
+ 0,
+ /*
+ * Clear SIGP.
+ */
+ SCR_FROM_REG (ctest2),
+ 0,
+ /*
+ * Stop here if the C code wants to perform
+ * some error recovery procedure manually.
+ * (Indicate this by setting SEM in ISTAT)
+ */
+ SCR_FROM_REG (istat),
+ 0,
+ /*
+ * Report to the C code the next position in
+ * the start queue the SCRIPTS will schedule.
+ * The C code must not change SCRATCHA.
+ */
+ SCR_COPY (4),
+ PADDR_B (startpos),
+ RADDR_1 (scratcha),
+ SCR_INT ^ IFTRUE (MASK (SEM, SEM)),
+ SIR_SCRIPT_STOPPED,
+ /*
+ * Start the next job.
+ *
+ * @DSA = start point for this job.
+ * SCRATCHA = address of this job in the start queue.
+ *
+ * We will restore startpos with SCRATCHA if we fails the
+ * arbitration or if it is the idle job.
+ *
+ * The below GETJOB_BEGIN to GETJOB_END section of SCRIPTS
+ * is a critical path. If it is partially executed, it then
+ * may happen that the job address is not yet in the DSA
+ * and the the next queue position points to the next JOB.
+ */
+}/*-------------------------< GETJOB_BEGIN >---------------------*/,{
+ /*
+ * Copy to a fixed location both the next STARTPOS
+ * and the current JOB address, using self modifying
+ * SCRIPTS.
+ */
+ SCR_COPY (4),
+ RADDR_1 (scratcha),
+ PADDR_A (_sms_a10),
+ SCR_COPY (8),
+}/*-------------------------< _SMS_A10 >-------------------------*/,{
+ 0,
+ PADDR_B (nextjob),
+ /*
+ * Move the start address to TEMP using self-
+ * modifying SCRIPTS and jump indirectly to
+ * that address.
+ */
+ SCR_COPY (4),
+ PADDR_B (nextjob),
+ RADDR_1 (dsa),
+}/*-------------------------< GETJOB_END >-----------------------*/,{
+ SCR_COPY (4),
+ RADDR_1 (dsa),
+ PADDR_A (_sms_a20),
+ SCR_COPY (4),
+}/*-------------------------< _SMS_A20 >-------------------------*/,{
+ 0,
+ RADDR_1 (temp),
+ SCR_RETURN,
+ 0,
+}/*-------------------------< SELECT >---------------------------*/,{
+ /*
+ * DSA contains the address of a scheduled
+ * data structure.
+ *
+ * SCRATCHA contains the address of the start queue
+ * entry which points to the next job.
+ *
+ * Set Initiator mode.
+ *
+ * (Target mode is left as an exercise for the reader)
+ */
+ SCR_CLR (SCR_TRG),
+ 0,
+ /*
+ * And try to select this target.
+ */
+ SCR_SEL_TBL_ATN ^ offsetof (struct sym_dsb, select),
+ PADDR_A (ungetjob),
+ /*
+ * Now there are 4 possibilities:
+ *
+ * (1) The chip looses arbitration.
+ * This is ok, because it will try again,
+ * when the bus becomes idle.
+ * (But beware of the timeout function!)
+ *
+ * (2) The chip is reselected.
+ * Then the script processor takes the jump
+ * to the RESELECT label.
+ *
+ * (3) The chip wins arbitration.
+ * Then it will execute SCRIPTS instruction until
+ * the next instruction that checks SCSI phase.
+ * Then will stop and wait for selection to be
+ * complete or selection time-out to occur.
+ *
+ * After having won arbitration, the SCRIPTS
+ * processor is able to execute instructions while
+ * the SCSI core is performing SCSI selection.
+ */
+
+ /*
+ * Copy the CCB header to a fixed location
+ * in the HCB using self-modifying SCRIPTS.
+ */
+ SCR_COPY (4),
+ RADDR_1 (dsa),
+ PADDR_A (_sms_a30),
+ SCR_COPY (sizeof(struct sym_ccbh)),
+}/*-------------------------< _SMS_A30 >-------------------------*/,{
+ 0,
+ HADDR_1 (ccb_head),
+ /*
+ * Load the savep (saved data pointer) into
+ * the actual data pointer.
+ */
+ SCR_COPY (4),
+ HADDR_1 (ccb_head.savep),
+ RADDR_1 (temp),
+ /*
+ * Initialize the status register
+ */
+ SCR_COPY (4),
+ HADDR_1 (ccb_head.status),
+ RADDR_1 (scr0),
+}/*-------------------------< WF_SEL_DONE >----------------------*/,{
+ SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+ SIR_SEL_ATN_NO_MSG_OUT,
+}/*-------------------------< SEND_IDENT >-----------------------*/,{
+ /*
+ * Selection complete.
+ * Send the IDENTIFY and possibly the TAG message
+ * and negotiation message if present.
+ */
+ SCR_MOVE_TBL ^ SCR_MSG_OUT,
+ offsetof (struct sym_dsb, smsg),
+}/*-------------------------< SELECT2 >--------------------------*/,{
+#ifdef SYM_CONF_IARB_SUPPORT
+ /*
+ * Set IMMEDIATE ARBITRATION if we have been given
+ * a hint to do so. (Some job to do after this one).
+ */
+ SCR_FROM_REG (HF_REG),
+ 0,
+ SCR_JUMPR ^ IFFALSE (MASK (HF_HINT_IARB, HF_HINT_IARB)),
+ 8,
+ SCR_REG_REG (scntl1, SCR_OR, IARB),
+ 0,
+#endif
+ /*
+ * Anticipate the COMMAND phase.
+ * This is the PHASE we expect at this point.
+ */
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_COMMAND)),
+ PADDR_A (sel_no_cmd),
+}/*-------------------------< COMMAND >--------------------------*/,{
+ /*
+ * ... and send the command
+ */
+ SCR_MOVE_TBL ^ SCR_COMMAND,
+ offsetof (struct sym_dsb, cmd),
+}/*-------------------------< DISPATCH >-------------------------*/,{
+ /*
+ * MSG_IN is the only phase that shall be
+ * entered at least once for each (re)selection.
+ * So we test it first.
+ */
+ SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
+ PADDR_A (msg_in),
+ SCR_JUMP ^ IFTRUE (IF (SCR_DATA_OUT)),
+ PADDR_A (datao_phase),
+ SCR_JUMP ^ IFTRUE (IF (SCR_DATA_IN)),
+ PADDR_A (datai_phase),
+ SCR_JUMP ^ IFTRUE (IF (SCR_STATUS)),
+ PADDR_A (status),
+ SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND)),
+ PADDR_A (command),
+ SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)),
+ PADDR_B (msg_out),
+ /*
+ * Discard as many illegal phases as
+ * required and tell the C code about.
+ */
+ SCR_JUMPR ^ IFFALSE (WHEN (SCR_ILG_OUT)),
+ 16,
+ SCR_MOVE_ABS (1) ^ SCR_ILG_OUT,
+ HADDR_1 (scratch),
+ SCR_JUMPR ^ IFTRUE (WHEN (SCR_ILG_OUT)),
+ -16,
+ SCR_JUMPR ^ IFFALSE (WHEN (SCR_ILG_IN)),
+ 16,
+ SCR_MOVE_ABS (1) ^ SCR_ILG_IN,
+ HADDR_1 (scratch),
+ SCR_JUMPR ^ IFTRUE (WHEN (SCR_ILG_IN)),
+ -16,
+ SCR_INT,
+ SIR_BAD_PHASE,
+ SCR_JUMP,
+ PADDR_A (dispatch),
+}/*-------------------------< SEL_NO_CMD >-----------------------*/,{
+ /*
+ * The target does not switch to command
+ * phase after IDENTIFY has been sent.
+ *
+ * If it stays in MSG OUT phase send it
+ * the IDENTIFY again.
+ */
+ SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)),
+ PADDR_B (resend_ident),
+ /*
+ * If target does not switch to MSG IN phase
+ * and we sent a negotiation, assert the
+ * failure immediately.
+ */
+ SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
+ PADDR_A (dispatch),
+ SCR_FROM_REG (HS_REG),
+ 0,
+ SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)),
+ SIR_NEGO_FAILED,
+ /*
+ * Jump to dispatcher.
+ */
+ SCR_JUMP,
+ PADDR_A (dispatch),
+}/*-------------------------< INIT >-----------------------------*/,{
+ /*
+ * Wait for the SCSI RESET signal to be
+ * inactive before restarting operations,
+ * since the chip may hang on SEL_ATN
+ * if SCSI RESET is active.
+ */
+ SCR_FROM_REG (sstat0),
+ 0,
+ SCR_JUMPR ^ IFTRUE (MASK (IRST, IRST)),
+ -16,
+ SCR_JUMP,
+ PADDR_A (start),
+}/*-------------------------< CLRACK >---------------------------*/,{
+ /*
+ * Terminate possible pending message phase.
+ */
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_JUMP,
+ PADDR_A (dispatch),
+}/*-------------------------< DISP_STATUS >----------------------*/,{
+ /*
+ * Anticipate STATUS phase.
+ *
+ * Does spare 3 SCRIPTS instructions when we have
+ * completed the INPUT of the data.
+ */
+ SCR_JUMP ^ IFTRUE (WHEN (SCR_STATUS)),
+ PADDR_A (status),
+ SCR_JUMP,
+ PADDR_A (dispatch),
+}/*-------------------------< DATAI_DONE >-----------------------*/,{
+ /*
+ * If the device still wants to send us data,
+ * we must count the extra bytes.
+ */
+ SCR_JUMP ^ IFTRUE (WHEN (SCR_DATA_IN)),
+ PADDR_B (data_ovrun),
+ /*
+ * If the SWIDE is not full, jump to dispatcher.
+ * We anticipate a STATUS phase.
+ */
+ SCR_FROM_REG (scntl2),
+ 0,
+ SCR_JUMP ^ IFFALSE (MASK (WSR, WSR)),
+ PADDR_A (disp_status),
+ /*
+ * The SWIDE is full.
+ * Clear this condition.
+ */
+ SCR_REG_REG (scntl2, SCR_OR, WSR),
+ 0,
+ /*
+ * We are expecting an IGNORE RESIDUE message
+ * from the device, otherwise we are in data
+ * overrun condition. Check against MSG_IN phase.
+ */
+ SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ SIR_SWIDE_OVERRUN,
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ PADDR_A (disp_status),
+ /*
+ * We are in MSG_IN phase,
+ * Read the first byte of the message.
+ * If it is not an IGNORE RESIDUE message,
+ * signal overrun and jump to message
+ * processing.
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ HADDR_1 (msgin[0]),
+ SCR_INT ^ IFFALSE (DATA (M_IGN_RESIDUE)),
+ SIR_SWIDE_OVERRUN,
+ SCR_JUMP ^ IFFALSE (DATA (M_IGN_RESIDUE)),
+ PADDR_A (msg_in2),
+ /*
+ * We got the message we expected.
+ * Read the 2nd byte, and jump to dispatcher.
+ */
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ HADDR_1 (msgin[1]),
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_JUMP,
+ PADDR_A (disp_status),
+}/*-------------------------< DATAO_DONE >-----------------------*/,{
+ /*
+ * If the device wants us to send more data,
+ * we must count the extra bytes.
+ */
+ SCR_JUMP ^ IFTRUE (WHEN (SCR_DATA_OUT)),
+ PADDR_B (data_ovrun),
+ /*
+ * If the SODL is not full jump to dispatcher.
+ * We anticipate a STATUS phase.
+ */
+ SCR_FROM_REG (scntl2),
+ 0,
+ SCR_JUMP ^ IFFALSE (MASK (WSS, WSS)),
+ PADDR_A (disp_status),
+ /*
+ * The SODL is full, clear this condition.
+ */
+ SCR_REG_REG (scntl2, SCR_OR, WSS),
+ 0,
+ /*
+ * And signal a DATA UNDERRUN condition
+ * to the C code.
+ */
+ SCR_INT,
+ SIR_SODL_UNDERRUN,
+ SCR_JUMP,
+ PADDR_A (dispatch),
+}/*-------------------------< DATAI_PHASE >----------------------*/,{
+ SCR_RETURN,
+ 0,
+}/*-------------------------< DATAO_PHASE >----------------------*/,{
+ SCR_RETURN,
+ 0,
+}/*-------------------------< MSG_IN >---------------------------*/,{
+ /*
+ * Get the first byte of the message.
+ *
+ * The script processor doesn't negate the
+ * ACK signal after this transfer.
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ HADDR_1 (msgin[0]),
+}/*-------------------------< MSG_IN2 >--------------------------*/,{
+ /*
+ * Check first against 1 byte messages
+ * that we handle from SCRIPTS.
+ */
+ SCR_JUMP ^ IFTRUE (DATA (M_COMPLETE)),
+ PADDR_A (complete),
+ SCR_JUMP ^ IFTRUE (DATA (M_DISCONNECT)),
+ PADDR_A (disconnect),
+ SCR_JUMP ^ IFTRUE (DATA (M_SAVE_DP)),
+ PADDR_A (save_dp),
+ SCR_JUMP ^ IFTRUE (DATA (M_RESTORE_DP)),
+ PADDR_A (restore_dp),
+ /*
+ * We handle all other messages from the
+ * C code, so no need to waste on-chip RAM
+ * for those ones.
+ */
+ SCR_JUMP,
+ PADDR_B (msg_in_etc),
+}/*-------------------------< STATUS >---------------------------*/,{
+ /*
+ * get the status
+ */
+ SCR_MOVE_ABS (1) ^ SCR_STATUS,
+ HADDR_1 (scratch),
+#ifdef SYM_CONF_IARB_SUPPORT
+ /*
+ * If STATUS is not GOOD, clear IMMEDIATE ARBITRATION,
+ * since we may have to tamper the start queue from
+ * the C code.
+ */
+ SCR_JUMPR ^ IFTRUE (DATA (S_GOOD)),
+ 8,
+ SCR_REG_REG (scntl1, SCR_AND, ~IARB),
+ 0,
+#endif
+ /*
+ * save status to scsi_status.
+ * mark as complete.
+ */
+ SCR_TO_REG (SS_REG),
+ 0,
+ SCR_LOAD_REG (HS_REG, HS_COMPLETE),
+ 0,
+ /*
+ * Anticipate the MESSAGE PHASE for
+ * the TASK COMPLETE message.
+ */
+ SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
+ PADDR_A (msg_in),
+ SCR_JUMP,
+ PADDR_A (dispatch),
+}/*-------------------------< COMPLETE >-------------------------*/,{
+ /*
+ * Complete message.
+ *
+ * Copy the data pointer to LASTP.
+ */
+ SCR_COPY (4),
+ RADDR_1 (temp),
+ HADDR_1 (ccb_head.lastp),
+ /*
+ * When we terminate the cycle by clearing ACK,
+ * the target may disconnect immediately.
+ *
+ * We don't want to be told of an "unexpected disconnect",
+ * so we disable this feature.
+ */
+ SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+ 0,
+ /*
+ * Terminate cycle ...
+ */
+ SCR_CLR (SCR_ACK|SCR_ATN),
+ 0,
+ /*
+ * ... and wait for the disconnect.
+ */
+ SCR_WAIT_DISC,
+ 0,
+}/*-------------------------< COMPLETE2 >------------------------*/,{
+ /*
+ * Save host status.
+ */
+ SCR_COPY (4),
+ RADDR_1 (scr0),
+ HADDR_1 (ccb_head.status),
+ /*
+ * Move back the CCB header using self-modifying
+ * SCRIPTS.
+ */
+ SCR_COPY (4),
+ RADDR_1 (dsa),
+ PADDR_A (_sms_a40),
+ SCR_COPY (sizeof(struct sym_ccbh)),
+ HADDR_1 (ccb_head),
+}/*-------------------------< _SMS_A40 >-------------------------*/,{
+ 0,
+ /*
+ * Some bridges may reorder DMA writes to memory.
+ * We donnot want the CPU to deal with completions
+ * without all the posted write having been flushed
+ * to memory. This DUMMY READ should flush posted
+ * buffers prior to the CPU having to deal with
+ * completions.
+ */
+ SCR_COPY (4), /* DUMMY READ */
+ HADDR_1 (ccb_head.status),
+ RADDR_1 (scr0),
+ /*
+ * If command resulted in not GOOD status,
+ * call the C code if needed.
+ */
+ SCR_FROM_REG (SS_REG),
+ 0,
+ SCR_CALL ^ IFFALSE (DATA (S_GOOD)),
+ PADDR_B (bad_status),
+ /*
+ * If we performed an auto-sense, call
+ * the C code to synchronyze task aborts
+ * with UNIT ATTENTION conditions.
+ */
+ SCR_FROM_REG (HF_REG),
+ 0,
+ SCR_JUMP ^ IFTRUE (MASK (0 ,(HF_SENSE|HF_EXT_ERR))),
+ PADDR_A (done),
+}/*-------------------------< COMPLETE_ERROR >-------------------*/,{
+ SCR_COPY (4),
+ PADDR_B (startpos),
+ RADDR_1 (scratcha),
+ SCR_INT,
+ SIR_COMPLETE_ERROR,
+}/*-------------------------< DONE >-----------------------------*/,{
+ /*
+ * Copy the DSA to the DONE QUEUE and
+ * signal completion to the host.
+ * If we are interrupted between DONE
+ * and DONE_END, we must reset, otherwise
+ * the completed CCB may be lost.
+ */
+ SCR_COPY (4),
+ PADDR_B (done_pos),
+ PADDR_A (_sms_a50),
+ SCR_COPY (4),
+ RADDR_1 (dsa),
+}/*-------------------------< _SMS_A50 >-------------------------*/,{
+ 0,
+ SCR_COPY (4),
+ PADDR_B (done_pos),
+ PADDR_A (_sms_a60),
+ /*
+ * The instruction below reads the DONE QUEUE next
+ * free position from memory.
+ * In addition it ensures that all PCI posted writes
+ * are flushed and so the DSA value of the done
+ * CCB is visible by the CPU before INTFLY is raised.
+ */
+ SCR_COPY (8),
+}/*-------------------------< _SMS_A60 >-------------------------*/,{
+ 0,
+ PADDR_B (prev_done),
+}/*-------------------------< DONE_END >-------------------------*/,{
+ SCR_INT_FLY,
+ 0,
+ SCR_JUMP,
+ PADDR_A (start),
+}/*-------------------------< SAVE_DP >--------------------------*/,{
+ /*
+ * Clear ACK immediately.
+ * No need to delay it.
+ */
+ SCR_CLR (SCR_ACK),
+ 0,
+ /*
+ * Keep track we received a SAVE DP, so
+ * we will switch to the other PM context
+ * on the next PM since the DP may point
+ * to the current PM context.
+ */
+ SCR_REG_REG (HF_REG, SCR_OR, HF_DP_SAVED),
+ 0,
+ /*
+ * SAVE_DP message:
+ * Copy the data pointer to SAVEP.
+ */
+ SCR_COPY (4),
+ RADDR_1 (temp),
+ HADDR_1 (ccb_head.savep),
+ SCR_JUMP,
+ PADDR_A (dispatch),
+}/*-------------------------< RESTORE_DP >-----------------------*/,{
+ /*
+ * RESTORE_DP message:
+ * Copy SAVEP to actual data pointer.
+ */
+ SCR_COPY (4),
+ HADDR_1 (ccb_head.savep),
+ RADDR_1 (temp),
+ SCR_JUMP,
+ PADDR_A (clrack),
+}/*-------------------------< DISCONNECT >-----------------------*/,{
+ /*
+ * DISCONNECTing ...
+ *
+ * disable the "unexpected disconnect" feature,
+ * and remove the ACK signal.
+ */
+ SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+ 0,
+ SCR_CLR (SCR_ACK|SCR_ATN),
+ 0,
+ /*
+ * Wait for the disconnect.
+ */
+ SCR_WAIT_DISC,
+ 0,
+ /*
+ * Status is: DISCONNECTED.
+ */
+ SCR_LOAD_REG (HS_REG, HS_DISCONNECT),
+ 0,
+ /*
+ * Save host status.
+ */
+ SCR_COPY (4),
+ RADDR_1 (scr0),
+ HADDR_1 (ccb_head.status),
+ /*
+ * If QUIRK_AUTOSAVE is set,
+ * do an "save pointer" operation.
+ */
+ SCR_FROM_REG (QU_REG),
+ 0,
+ SCR_JUMP ^ IFFALSE (MASK (SYM_QUIRK_AUTOSAVE, SYM_QUIRK_AUTOSAVE)),
+ PADDR_A (disconnect2),
+ /*
+ * like SAVE_DP message:
+ * Remember we saved the data pointer.
+ * Copy data pointer to SAVEP.
+ */
+ SCR_REG_REG (HF_REG, SCR_OR, HF_DP_SAVED),
+ 0,
+ SCR_COPY (4),
+ RADDR_1 (temp),
+ HADDR_1 (ccb_head.savep),
+}/*-------------------------< DISCONNECT2 >----------------------*/,{
+ /*
+ * Move back the CCB header using self-modifying
+ * SCRIPTS.
+ */
+ SCR_COPY (4),
+ RADDR_1 (dsa),
+ PADDR_A (_sms_a65),
+ SCR_COPY (sizeof(struct sym_ccbh)),
+ HADDR_1 (ccb_head),
+}/*-------------------------< _SMS_A65 >-------------------------*/,{
+ 0,
+ SCR_JUMP,
+ PADDR_A (start),
+}/*-------------------------< IDLE >-----------------------------*/,{
+ /*
+ * Nothing to do?
+ * Switch the LED off and wait for reselect.
+ * Will be patched with a NO_OP if LED
+ * not needed or not desired.
+ */
+ SCR_REG_REG (gpreg, SCR_OR, 0x01),
+ 0,
+#ifdef SYM_CONF_IARB_SUPPORT
+ SCR_JUMPR,
+ 8,
+#endif
+}/*-------------------------< UNGETJOB >-------------------------*/,{
+#ifdef SYM_CONF_IARB_SUPPORT
+ /*
+ * Set IMMEDIATE ARBITRATION, for the next time.
+ * This will give us better chance to win arbitration
+ * for the job we just wanted to do.
+ */
+ SCR_REG_REG (scntl1, SCR_OR, IARB),
+ 0,
+#endif
+ /*
+ * We are not able to restart the SCRIPTS if we are
+ * interrupted and these instruction haven't been
+ * all executed. BTW, this is very unlikely to
+ * happen, but we check that from the C code.
+ */
+ SCR_LOAD_REG (dsa, 0xff),
+ 0,
+ SCR_COPY (4),
+ RADDR_1 (scratcha),
+ PADDR_B (startpos),
+}/*-------------------------< RESELECT >-------------------------*/,{
+ /*
+ * Make sure we are in initiator mode.
+ */
+ SCR_CLR (SCR_TRG),
+ 0,
+ /*
+ * Sleep waiting for a reselection.
+ */
+ SCR_WAIT_RESEL,
+ PADDR_A(start),
+}/*-------------------------< RESELECTED >-----------------------*/,{
+ /*
+ * Switch the LED on.
+ * Will be patched with a NO_OP if LED
+ * not needed or not desired.
+ */
+ SCR_REG_REG (gpreg, SCR_AND, 0xfe),
+ 0,
+ /*
+ * load the target id into the sdid
+ */
+ SCR_REG_SFBR (ssid, SCR_AND, 0x8F),
+ 0,
+ SCR_TO_REG (sdid),
+ 0,
+ /*
+ * Load the target control block address
+ */
+ SCR_COPY (4),
+ PADDR_B (targtbl),
+ RADDR_1 (dsa),
+ SCR_SFBR_REG (dsa, SCR_SHL, 0),
+ 0,
+ SCR_REG_REG (dsa, SCR_SHL, 0),
+ 0,
+ SCR_REG_REG (dsa, SCR_AND, 0x3c),
+ 0,
+ SCR_COPY (4),
+ RADDR_1 (dsa),
+ PADDR_A (_sms_a70),
+ SCR_COPY (4),
+}/*-------------------------< _SMS_A70 >-------------------------*/,{
+ 0,
+ RADDR_1 (dsa),
+ /*
+ * Copy the TCB header to a fixed place in
+ * the HCB.
+ */
+ SCR_COPY (4),
+ RADDR_1 (dsa),
+ PADDR_A (_sms_a80),
+ SCR_COPY (sizeof(struct sym_tcbh)),
+}/*-------------------------< _SMS_A80 >-------------------------*/,{
+ 0,
+ HADDR_1 (tcb_head),
+ /*
+ * We expect MESSAGE IN phase.
+ * If not, get help from the C code.
+ */
+ SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ SIR_RESEL_NO_MSG_IN,
+}/*-------------------------< RESELECTED1 >----------------------*/,{
+ /*
+ * Load the synchronous transfer registers.
+ */
+ SCR_COPY (1),
+ HADDR_1 (tcb_head.wval),
+ RADDR_1 (scntl3),
+ SCR_COPY (1),
+ HADDR_1 (tcb_head.sval),
+ RADDR_1 (sxfer),
+ /*
+ * Get the IDENTIFY message.
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ HADDR_1 (msgin),
+ /*
+ * If IDENTIFY LUN #0, use a faster path
+ * to find the LCB structure.
+ */
+ SCR_JUMP ^ IFTRUE (MASK (0x80, 0xbf)),
+ PADDR_A (resel_lun0),
+ /*
+ * If message isn't an IDENTIFY,
+ * tell the C code about.
+ */
+ SCR_INT ^ IFFALSE (MASK (0x80, 0x80)),
+ SIR_RESEL_NO_IDENTIFY,
+ /*
+ * It is an IDENTIFY message,
+ * Load the LUN control block address.
+ */
+ SCR_COPY (4),
+ HADDR_1 (tcb_head.luntbl_sa),
+ RADDR_1 (dsa),
+ SCR_SFBR_REG (dsa, SCR_SHL, 0),
+ 0,
+ SCR_REG_REG (dsa, SCR_SHL, 0),
+ 0,
+ SCR_REG_REG (dsa, SCR_AND, 0xfc),
+ 0,
+ SCR_COPY (4),
+ RADDR_1 (dsa),
+ PADDR_A (_sms_a90),
+ SCR_COPY (4),
+}/*-------------------------< _SMS_A90 >-------------------------*/,{
+ 0,
+ RADDR_1 (dsa),
+ SCR_JUMPR,
+ 12,
+}/*-------------------------< RESEL_LUN0 >-----------------------*/,{
+ /*
+ * LUN 0 special case (but usual one :))
+ */
+ SCR_COPY (4),
+ HADDR_1 (tcb_head.lun0_sa),
+ RADDR_1 (dsa),
+ /*
+ * Jump indirectly to the reselect action for this LUN.
+ * (lcb.head.resel_sa assumed at offset zero of lcb).
+ */
+ SCR_COPY (4),
+ RADDR_1 (dsa),
+ PADDR_A (_sms_a100),
+ SCR_COPY (4),
+}/*-------------------------< _SMS_A100 >------------------------*/,{
+ 0,
+ RADDR_1 (temp),
+ SCR_RETURN,
+ 0,
+ /* In normal situations, we jump to RESEL_TAG or RESEL_NO_TAG */
+}/*-------------------------< RESEL_TAG >------------------------*/,{
+ /*
+ * ACK the IDENTIFY or TAG previously received.
+ */
+ SCR_CLR (SCR_ACK),
+ 0,
+ /*
+ * It shall be a tagged command.
+ * Read SIMPLE+TAG.
+ * The C code will deal with errors.
+ * Agressive optimization, is'nt it? :)
+ */
+ SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
+ HADDR_1 (msgin),
+ /*
+ * Copy the LCB header to a fixed place in
+ * the HCB using self-modifying SCRIPTS.
+ */
+ SCR_COPY (4),
+ RADDR_1 (dsa),
+ PADDR_A (_sms_a110),
+ SCR_COPY (sizeof(struct sym_lcbh)),
+}/*-------------------------< _SMS_A110 >------------------------*/,{
+ 0,
+ HADDR_1 (lcb_head),
+ /*
+ * Load the pointer to the tagged task
+ * table for this LUN.
+ */
+ SCR_COPY (4),
+ HADDR_1 (lcb_head.itlq_tbl_sa),
+ RADDR_1 (dsa),
+ /*
+ * The SIDL still contains the TAG value.
+ * Agressive optimization, isn't it? :):)
+ */
+ SCR_REG_SFBR (sidl, SCR_SHL, 0),
+ 0,
+#if SYM_CONF_MAX_TASK*4 > 512
+ SCR_JUMPR ^ IFFALSE (CARRYSET),
+ 8,
+ SCR_REG_REG (dsa1, SCR_OR, 2),
+ 0,
+ SCR_REG_REG (sfbr, SCR_SHL, 0),
+ 0,
+ SCR_JUMPR ^ IFFALSE (CARRYSET),
+ 8,
+ SCR_REG_REG (dsa1, SCR_OR, 1),
+ 0,
+#elif SYM_CONF_MAX_TASK*4 > 256
+ SCR_JUMPR ^ IFFALSE (CARRYSET),
+ 8,
+ SCR_REG_REG (dsa1, SCR_OR, 1),
+ 0,
+#endif
+ /*
+ * Retrieve the DSA of this task.
+ * JUMP indirectly to the restart point of the CCB.
+ */
+ SCR_SFBR_REG (dsa, SCR_AND, 0xfc),
+ 0,
+ SCR_COPY (4),
+ RADDR_1 (dsa),
+ PADDR_A (_sms_a120),
+ SCR_COPY (4),
+}/*-------------------------< _SMS_A120 >------------------------*/,{
+ 0,
+ RADDR_1 (dsa),
+}/*-------------------------< RESEL_GO >-------------------------*/,{
+ SCR_COPY (4),
+ RADDR_1 (dsa),
+ PADDR_A (_sms_a130),
+ /*
+ * Move 'ccb.phys.head.go' action to
+ * scratch/scratch1. So scratch1 will
+ * contain the 'restart' field of the
+ * 'go' structure.
+ */
+ SCR_COPY (8),
+}/*-------------------------< _SMS_A130 >------------------------*/,{
+ 0,
+ PADDR_B (scratch),
+ SCR_COPY (4),
+ PADDR_B (scratch1), /* phys.head.go.restart */
+ RADDR_1 (temp),
+ SCR_RETURN,
+ 0,
+ /* In normal situations we branch to RESEL_DSA */
+}/*-------------------------< RESEL_DSA >------------------------*/,{
+ /*
+ * ACK the IDENTIFY or TAG previously received.
+ */
+ SCR_CLR (SCR_ACK),
+ 0,
+}/*-------------------------< RESEL_DSA1 >-----------------------*/,{
+ /*
+ * Copy the CCB header to a fixed location
+ * in the HCB using self-modifying SCRIPTS.
+ */
+ SCR_COPY (4),
+ RADDR_1 (dsa),
+ PADDR_A (_sms_a140),
+ SCR_COPY (sizeof(struct sym_ccbh)),
+}/*-------------------------< _SMS_A140 >------------------------*/,{
+ 0,
+ HADDR_1 (ccb_head),
+ /*
+ * Load the savep (saved data pointer) into
+ * the actual data pointer.
+ */
+ SCR_COPY (4),
+ HADDR_1 (ccb_head.savep),
+ RADDR_1 (temp),
+ /*
+ * Initialize the status register
+ */
+ SCR_COPY (4),
+ HADDR_1 (ccb_head.status),
+ RADDR_1 (scr0),
+ /*
+ * Jump to dispatcher.
+ */
+ SCR_JUMP,
+ PADDR_A (dispatch),
+}/*-------------------------< RESEL_NO_TAG >---------------------*/,{
+ /*
+ * Copy the LCB header to a fixed place in
+ * the HCB using self-modifying SCRIPTS.
+ */
+ SCR_COPY (4),
+ RADDR_1 (dsa),
+ PADDR_A (_sms_a145),
+ SCR_COPY (sizeof(struct sym_lcbh)),
+}/*-------------------------< _SMS_A145 >------------------------*/,{
+ 0,
+ HADDR_1 (lcb_head),
+ /*
+ * Load the DSA with the unique ITL task.
+ */
+ SCR_COPY (4),
+ HADDR_1 (lcb_head.itl_task_sa),
+ RADDR_1 (dsa),
+ SCR_JUMP,
+ PADDR_A (resel_go),
+}/*-------------------------< DATA_IN >--------------------------*/,{
+/*
+ * Because the size depends on the
+ * #define SYM_CONF_MAX_SG parameter,
+ * it is filled in at runtime.
+ *
+ * ##===========< i=0; i<SYM_CONF_MAX_SG >=========
+ * || SCR_CHMOV_TBL ^ SCR_DATA_IN,
+ * || offsetof (struct sym_dsb, data[ i]),
+ * ##==========================================
+ */
+0
+}/*-------------------------< DATA_IN2 >-------------------------*/,{
+ SCR_CALL,
+ PADDR_A (datai_done),
+ SCR_JUMP,
+ PADDR_B (data_ovrun),
+}/*-------------------------< DATA_OUT >-------------------------*/,{
+/*
+ * Because the size depends on the
+ * #define SYM_CONF_MAX_SG parameter,
+ * it is filled in at runtime.
+ *
+ * ##===========< i=0; i<SYM_CONF_MAX_SG >=========
+ * || SCR_CHMOV_TBL ^ SCR_DATA_OUT,
+ * || offsetof (struct sym_dsb, data[ i]),
+ * ##==========================================
+ */
+0
+}/*-------------------------< DATA_OUT2 >------------------------*/,{
+ SCR_CALL,
+ PADDR_A (datao_done),
+ SCR_JUMP,
+ PADDR_B (data_ovrun),
+}/*-------------------------< PM0_DATA >-------------------------*/,{
+ /*
+ * Read our host flags to SFBR, so we will be able
+ * to check against the data direction we expect.
+ */
+ SCR_FROM_REG (HF_REG),
+ 0,
+ /*
+ * Check against actual DATA PHASE.
+ */
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
+ PADDR_A (pm0_data_out),
+ /*
+ * Actual phase is DATA IN.
+ * Check against expected direction.
+ */
+ SCR_JUMP ^ IFFALSE (MASK (HF_DATA_IN, HF_DATA_IN)),
+ PADDR_B (data_ovrun),
+ /*
+ * Keep track we are moving data from the
+ * PM0 DATA mini-script.
+ */
+ SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM0),
+ 0,
+ /*
+ * Move the data to memory.
+ */
+ SCR_CHMOV_TBL ^ SCR_DATA_IN,
+ offsetof (struct sym_ccb, phys.pm0.sg),
+ SCR_JUMP,
+ PADDR_A (pm0_data_end),
+}/*-------------------------< PM0_DATA_OUT >---------------------*/,{
+ /*
+ * Actual phase is DATA OUT.
+ * Check against expected direction.
+ */
+ SCR_JUMP ^ IFTRUE (MASK (HF_DATA_IN, HF_DATA_IN)),
+ PADDR_B (data_ovrun),
+ /*
+ * Keep track we are moving data from the
+ * PM0 DATA mini-script.
+ */
+ SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM0),
+ 0,
+ /*
+ * Move the data from memory.
+ */
+ SCR_CHMOV_TBL ^ SCR_DATA_OUT,
+ offsetof (struct sym_ccb, phys.pm0.sg),
+}/*-------------------------< PM0_DATA_END >---------------------*/,{
+ /*
+ * Clear the flag that told we were moving
+ * data from the PM0 DATA mini-script.
+ */
+ SCR_REG_REG (HF_REG, SCR_AND, (~HF_IN_PM0)),
+ 0,
+ /*
+ * Return to the previous DATA script which
+ * is guaranteed by design (if no bug) to be
+ * the main DATA script for this transfer.
+ */
+ SCR_COPY (4),
+ RADDR_1 (dsa),
+ RADDR_1 (scratcha),
+ SCR_REG_REG (scratcha, SCR_ADD, offsetof (struct sym_ccb,phys.pm0.ret)),
+ 0,
+}/*-------------------------< PM_DATA_END >----------------------*/,{
+ SCR_COPY (4),
+ RADDR_1 (scratcha),
+ PADDR_A (_sms_a150),
+ SCR_COPY (4),
+}/*-------------------------< _SMS_A150 >------------------------*/,{
+ 0,
+ RADDR_1 (temp),
+ SCR_RETURN,
+ 0,
+}/*-------------------------< PM1_DATA >-------------------------*/,{
+ /*
+ * Read our host flags to SFBR, so we will be able
+ * to check against the data direction we expect.
+ */
+ SCR_FROM_REG (HF_REG),
+ 0,
+ /*
+ * Check against actual DATA PHASE.
+ */
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
+ PADDR_A (pm1_data_out),
+ /*
+ * Actual phase is DATA IN.
+ * Check against expected direction.
+ */
+ SCR_JUMP ^ IFFALSE (MASK (HF_DATA_IN, HF_DATA_IN)),
+ PADDR_B (data_ovrun),
+ /*
+ * Keep track we are moving data from the
+ * PM1 DATA mini-script.
+ */
+ SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM1),
+ 0,
+ /*
+ * Move the data to memory.
+ */
+ SCR_CHMOV_TBL ^ SCR_DATA_IN,
+ offsetof (struct sym_ccb, phys.pm1.sg),
+ SCR_JUMP,
+ PADDR_A (pm1_data_end),
+}/*-------------------------< PM1_DATA_OUT >---------------------*/,{
+ /*
+ * Actual phase is DATA OUT.
+ * Check against expected direction.
+ */
+ SCR_JUMP ^ IFTRUE (MASK (HF_DATA_IN, HF_DATA_IN)),
+ PADDR_B (data_ovrun),
+ /*
+ * Keep track we are moving data from the
+ * PM1 DATA mini-script.
+ */
+ SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM1),
+ 0,
+ /*
+ * Move the data from memory.
+ */
+ SCR_CHMOV_TBL ^ SCR_DATA_OUT,
+ offsetof (struct sym_ccb, phys.pm1.sg),
+}/*-------------------------< PM1_DATA_END >---------------------*/,{
+ /*
+ * Clear the flag that told we were moving
+ * data from the PM1 DATA mini-script.
+ */
+ SCR_REG_REG (HF_REG, SCR_AND, (~HF_IN_PM1)),
+ 0,
+ /*
+ * Return to the previous DATA script which
+ * is guaranteed by design (if no bug) to be
+ * the main DATA script for this transfer.
+ */
+ SCR_COPY (4),
+ RADDR_1 (dsa),
+ RADDR_1 (scratcha),
+ SCR_REG_REG (scratcha, SCR_ADD, offsetof (struct sym_ccb,phys.pm1.ret)),
+ 0,
+ SCR_JUMP,
+ PADDR_A (pm_data_end),
+}/*--------------------------<>----------------------------------*/
+};
+
+static struct SYM_FWB_SCR SYM_FWB_SCR = {
+/*-------------------------< NO_DATA >--------------------------*/ {
+ SCR_JUMP,
+ PADDR_B (data_ovrun),
+}/*-------------------------< SEL_FOR_ABORT >--------------------*/,{
+ /*
+ * We are jumped here by the C code, if we have
+ * some target to reset or some disconnected
+ * job to abort. Since error recovery is a serious
+ * busyness, we will really reset the SCSI BUS, if
+ * case of a SCSI interrupt occuring in this path.
+ */
+
+ /*
+ * Set initiator mode.
+ */
+ SCR_CLR (SCR_TRG),
+ 0,
+ /*
+ * And try to select this target.
+ */
+ SCR_SEL_TBL_ATN ^ offsetof (struct sym_hcb, abrt_sel),
+ PADDR_A (reselect),
+ /*
+ * Wait for the selection to complete or
+ * the selection to time out.
+ */
+ SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+ -8,
+ /*
+ * Call the C code.
+ */
+ SCR_INT,
+ SIR_TARGET_SELECTED,
+ /*
+ * The C code should let us continue here.
+ * Send the 'kiss of death' message.
+ * We expect an immediate disconnect once
+ * the target has eaten the message.
+ */
+ SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+ 0,
+ SCR_MOVE_TBL ^ SCR_MSG_OUT,
+ offsetof (struct sym_hcb, abrt_tbl),
+ SCR_CLR (SCR_ACK|SCR_ATN),
+ 0,
+ SCR_WAIT_DISC,
+ 0,
+ /*
+ * Tell the C code that we are done.
+ */
+ SCR_INT,
+ SIR_ABORT_SENT,
+}/*-------------------------< SEL_FOR_ABORT_1 >------------------*/,{
+ /*
+ * Jump at scheduler.
+ */
+ SCR_JUMP,
+ PADDR_A (start),
+}/*-------------------------< MSG_IN_ETC >-----------------------*/,{
+ /*
+ * If it is an EXTENDED (variable size message)
+ * Handle it.
+ */
+ SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)),
+ PADDR_B (msg_extended),
+ /*
+ * Let the C code handle any other
+ * 1 byte message.
+ */
+ SCR_JUMP ^ IFTRUE (MASK (0x00, 0xf0)),
+ PADDR_B (msg_received),
+ SCR_JUMP ^ IFTRUE (MASK (0x10, 0xf0)),
+ PADDR_B (msg_received),
+ /*
+ * We donnot handle 2 bytes messages from SCRIPTS.
+ * So, let the C code deal with these ones too.
+ */
+ SCR_INT ^ IFFALSE (MASK (0x20, 0xf0)),
+ SIR_MSG_WEIRD,
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ HADDR_1 (msgin[1]),
+}/*-------------------------< MSG_RECEIVED >---------------------*/,{
+ SCR_COPY (4), /* DUMMY READ */
+ HADDR_1 (cache),
+ RADDR_1 (scratcha),
+ SCR_INT,
+ SIR_MSG_RECEIVED,
+}/*-------------------------< MSG_WEIRD_SEEN >-------------------*/,{
+ SCR_COPY (4), /* DUMMY READ */
+ HADDR_1 (cache),
+ RADDR_1 (scratcha),
+ SCR_INT,
+ SIR_MSG_WEIRD,
+}/*-------------------------< MSG_EXTENDED >---------------------*/,{
+ /*
+ * Clear ACK and get the next byte
+ * assumed to be the message length.
+ */
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ HADDR_1 (msgin[1]),
+ /*
+ * Try to catch some unlikely situations as 0 length
+ * or too large the length.
+ */
+ SCR_JUMP ^ IFTRUE (DATA (0)),
+ PADDR_B (msg_weird_seen),
+ SCR_TO_REG (scratcha),
+ 0,
+ SCR_REG_REG (sfbr, SCR_ADD, (256-8)),
+ 0,
+ SCR_JUMP ^ IFTRUE (CARRYSET),
+ PADDR_B (msg_weird_seen),
+ /*
+ * We donnot handle extended messages from SCRIPTS.
+ * Read the amount of data correponding to the
+ * message length and call the C code.
+ */
+ SCR_COPY (1),
+ RADDR_1 (scratcha),
+ PADDR_B (_sms_b10),
+ SCR_CLR (SCR_ACK),
+ 0,
+}/*-------------------------< _SMS_B10 >-------------------------*/,{
+ SCR_MOVE_ABS (0) ^ SCR_MSG_IN,
+ HADDR_1 (msgin[2]),
+ SCR_JUMP,
+ PADDR_B (msg_received),
+}/*-------------------------< MSG_BAD >--------------------------*/,{
+ /*
+ * unimplemented message - reject it.
+ */
+ SCR_INT,
+ SIR_REJECT_TO_SEND,
+ SCR_SET (SCR_ATN),
+ 0,
+ SCR_JUMP,
+ PADDR_A (clrack),
+}/*-------------------------< MSG_WEIRD >------------------------*/,{
+ /*
+ * weird message received
+ * ignore all MSG IN phases and reject it.
+ */
+ SCR_INT,
+ SIR_REJECT_TO_SEND,
+ SCR_SET (SCR_ATN),
+ 0,
+}/*-------------------------< MSG_WEIRD1 >-----------------------*/,{
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ PADDR_A (dispatch),
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ HADDR_1 (scratch),
+ SCR_JUMP,
+ PADDR_B (msg_weird1),
+}/*-------------------------< WDTR_RESP >------------------------*/,{
+ /*
+ * let the target fetch our answer.
+ */
+ SCR_SET (SCR_ATN),
+ 0,
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+ PADDR_B (nego_bad_phase),
+}/*-------------------------< SEND_WDTR >------------------------*/,{
+ /*
+ * Send the M_X_WIDE_REQ
+ */
+ SCR_MOVE_ABS (4) ^ SCR_MSG_OUT,
+ HADDR_1 (msgout),
+ SCR_JUMP,
+ PADDR_B (msg_out_done),
+}/*-------------------------< SDTR_RESP >------------------------*/,{
+ /*
+ * let the target fetch our answer.
+ */
+ SCR_SET (SCR_ATN),
+ 0,
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+ PADDR_B (nego_bad_phase),
+}/*-------------------------< SEND_SDTR >------------------------*/,{
+ /*
+ * Send the M_X_SYNC_REQ
+ */
+ SCR_MOVE_ABS (5) ^ SCR_MSG_OUT,
+ HADDR_1 (msgout),
+ SCR_JUMP,
+ PADDR_B (msg_out_done),
+}/*-------------------------< PPR_RESP >-------------------------*/,{
+ /*
+ * let the target fetch our answer.
+ */
+ SCR_SET (SCR_ATN),
+ 0,
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+ PADDR_B (nego_bad_phase),
+}/*-------------------------< SEND_PPR >-------------------------*/,{
+ /*
+ * Send the M_X_PPR_REQ
+ */
+ SCR_MOVE_ABS (8) ^ SCR_MSG_OUT,
+ HADDR_1 (msgout),
+ SCR_JUMP,
+ PADDR_B (msg_out_done),
+}/*-------------------------< NEGO_BAD_PHASE >-------------------*/,{
+ SCR_INT,
+ SIR_NEGO_PROTO,
+ SCR_JUMP,
+ PADDR_A (dispatch),
+}/*-------------------------< MSG_OUT >--------------------------*/,{
+ /*
+ * The target requests a message.
+ * We donnot send messages that may
+ * require the device to go to bus free.
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
+ HADDR_1 (msgout),
+ /*
+ * ... wait for the next phase
+ * if it's a message out, send it again, ...
+ */
+ SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)),
+ PADDR_B (msg_out),
+}/*-------------------------< MSG_OUT_DONE >---------------------*/,{
+ /*
+ * Let the C code be aware of the
+ * sent message and clear the message.
+ */
+ SCR_INT,
+ SIR_MSG_OUT_DONE,
+ /*
+ * ... and process the next phase
+ */
+ SCR_JUMP,
+ PADDR_A (dispatch),
+}/*-------------------------< DATA_OVRUN >-----------------------*/,{
+ /*
+ * Zero scratcha that will count the
+ * extras bytes.
+ */
+ SCR_COPY (4),
+ PADDR_B (zero),
+ RADDR_1 (scratcha),
+}/*-------------------------< DATA_OVRUN1 >----------------------*/,{
+ /*
+ * The target may want to transfer too much data.
+ *
+ * If phase is DATA OUT write 1 byte and count it.
+ */
+ SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_OUT)),
+ 16,
+ SCR_CHMOV_ABS (1) ^ SCR_DATA_OUT,
+ HADDR_1 (scratch),
+ SCR_JUMP,
+ PADDR_B (data_ovrun2),
+ /*
+ * If WSR is set, clear this condition, and
+ * count this byte.
+ */
+ SCR_FROM_REG (scntl2),
+ 0,
+ SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)),
+ 16,
+ SCR_REG_REG (scntl2, SCR_OR, WSR),
+ 0,
+ SCR_JUMP,
+ PADDR_B (data_ovrun2),
+ /*
+ * Finally check against DATA IN phase.
+ * Signal data overrun to the C code
+ * and jump to dispatcher if not so.
+ * Read 1 byte otherwise and count it.
+ */
+ SCR_JUMPR ^ IFTRUE (WHEN (SCR_DATA_IN)),
+ 16,
+ SCR_INT,
+ SIR_DATA_OVERRUN,
+ SCR_JUMP,
+ PADDR_A (dispatch),
+ SCR_CHMOV_ABS (1) ^ SCR_DATA_IN,
+ HADDR_1 (scratch),
+}/*-------------------------< DATA_OVRUN2 >----------------------*/,{
+ /*
+ * Count this byte.
+ * This will allow to return a negative
+ * residual to user.
+ */
+ SCR_REG_REG (scratcha, SCR_ADD, 0x01),
+ 0,
+ SCR_REG_REG (scratcha1, SCR_ADDC, 0),
+ 0,
+ SCR_REG_REG (scratcha2, SCR_ADDC, 0),
+ 0,
+ /*
+ * .. and repeat as required.
+ */
+ SCR_JUMP,
+ PADDR_B (data_ovrun1),
+}/*-------------------------< ABORT_RESEL >----------------------*/,{
+ SCR_SET (SCR_ATN),
+ 0,
+ SCR_CLR (SCR_ACK),
+ 0,
+ /*
+ * send the abort/abortag/reset message
+ * we expect an immediate disconnect
+ */
+ SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+ 0,
+ SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
+ HADDR_1 (msgout),
+ SCR_CLR (SCR_ACK|SCR_ATN),
+ 0,
+ SCR_WAIT_DISC,
+ 0,
+ SCR_INT,
+ SIR_RESEL_ABORTED,
+ SCR_JUMP,
+ PADDR_A (start),
+}/*-------------------------< RESEND_IDENT >---------------------*/,{
+ /*
+ * The target stays in MSG OUT phase after having acked
+ * Identify [+ Tag [+ Extended message ]]. Targets shall
+ * behave this way on parity error.
+ * We must send it again all the messages.
+ */
+ SCR_SET (SCR_ATN), /* Shall be asserted 2 deskew delays before the */
+ 0, /* 1rst ACK = 90 ns. Hope the chip isn't too fast */
+ SCR_JUMP,
+ PADDR_A (send_ident),
+}/*-------------------------< IDENT_BREAK >----------------------*/,{
+ SCR_CLR (SCR_ATN),
+ 0,
+ SCR_JUMP,
+ PADDR_A (select2),
+}/*-------------------------< IDENT_BREAK_ATN >------------------*/,{
+ SCR_SET (SCR_ATN),
+ 0,
+ SCR_JUMP,
+ PADDR_A (select2),
+}/*-------------------------< SDATA_IN >-------------------------*/,{
+ SCR_CHMOV_TBL ^ SCR_DATA_IN,
+ offsetof (struct sym_dsb, sense),
+ SCR_CALL,
+ PADDR_A (datai_done),
+ SCR_JUMP,
+ PADDR_B (data_ovrun),
+}/*-------------------------< RESEL_BAD_LUN >--------------------*/,{
+ /*
+ * Message is an IDENTIFY, but lun is unknown.
+ * Signal problem to C code for logging the event.
+ * Send a M_ABORT to clear all pending tasks.
+ */
+ SCR_INT,
+ SIR_RESEL_BAD_LUN,
+ SCR_JUMP,
+ PADDR_B (abort_resel),
+}/*-------------------------< BAD_I_T_L >------------------------*/,{
+ /*
+ * We donnot have a task for that I_T_L.
+ * Signal problem to C code for logging the event.
+ * Send a M_ABORT message.
+ */
+ SCR_INT,
+ SIR_RESEL_BAD_I_T_L,
+ SCR_JUMP,
+ PADDR_B (abort_resel),
+}/*-------------------------< BAD_I_T_L_Q >----------------------*/,{
+ /*
+ * We donnot have a task that matches the tag.
+ * Signal problem to C code for logging the event.
+ * Send a M_ABORTTAG message.
+ */
+ SCR_INT,
+ SIR_RESEL_BAD_I_T_L_Q,
+ SCR_JUMP,
+ PADDR_B (abort_resel),
+}/*-------------------------< BAD_STATUS >-----------------------*/,{
+ /*
+ * Anything different from INTERMEDIATE
+ * CONDITION MET should be a bad SCSI status,
+ * given that GOOD status has already been tested.
+ * Call the C code.
+ */
+ SCR_COPY (4),
+ PADDR_B (startpos),
+ RADDR_1 (scratcha),
+ SCR_INT ^ IFFALSE (DATA (S_COND_MET)),
+ SIR_BAD_SCSI_STATUS,
+ SCR_RETURN,
+ 0,
+}/*-------------------------< WSR_MA_HELPER >--------------------*/,{
+ /*
+ * Helper for the C code when WSR bit is set.
+ * Perform the move of the residual byte.
+ */
+ SCR_CHMOV_TBL ^ SCR_DATA_IN,
+ offsetof (struct sym_ccb, phys.wresid),
+ SCR_JUMP,
+ PADDR_A (dispatch),
+}/*-------------------------< ZERO >-----------------------------*/,{
+ SCR_DATA_ZERO,
+}/*-------------------------< SCRATCH >--------------------------*/,{
+ SCR_DATA_ZERO, /* MUST BE BEFORE SCRATCH1 */
+}/*-------------------------< SCRATCH1 >-------------------------*/,{
+ SCR_DATA_ZERO,
+}/*-------------------------< PREV_DONE >------------------------*/,{
+ SCR_DATA_ZERO, /* MUST BE BEFORE DONE_POS ! */
+}/*-------------------------< DONE_POS >-------------------------*/,{
+ SCR_DATA_ZERO,
+}/*-------------------------< NEXTJOB >--------------------------*/,{
+ SCR_DATA_ZERO, /* MUST BE BEFORE STARTPOS ! */
+}/*-------------------------< STARTPOS >-------------------------*/,{
+ SCR_DATA_ZERO,
+}/*-------------------------< TARGTBL >--------------------------*/,{
+ SCR_DATA_ZERO,
+
+}/*-------------------------< SNOOPTEST >------------------------*/,{
+ /*
+ * Read the variable.
+ */
+ SCR_COPY (4),
+ HADDR_1 (cache),
+ RADDR_1 (scratcha),
+ /*
+ * Write the variable.
+ */
+ SCR_COPY (4),
+ RADDR_1 (temp),
+ HADDR_1 (cache),
+ /*
+ * Read back the variable.
+ */
+ SCR_COPY (4),
+ HADDR_1 (cache),
+ RADDR_1 (temp),
+}/*-------------------------< SNOOPEND >-------------------------*/,{
+ /*
+ * And stop.
+ */
+ SCR_INT,
+ 99,
+}/*--------------------------<>----------------------------------*/
+};
diff --git a/sys/dev/sym/sym_fw2.h b/sys/dev/sym/sym_fw2.h
new file mode 100644
index 0000000..8af671e
--- /dev/null
+++ b/sys/dev/sym/sym_fw2.h
@@ -0,0 +1,1850 @@
+/*
+ * Device driver optimized for the Symbios/LSI 53C896/53C895A/53C1010
+ * PCI-SCSI controllers.
+ *
+ * Copyright (C) 1999-2000 Gerard Roudier <groudier@club-internet.fr>
+ *
+ * This driver also supports the following Symbios/LSI PCI-SCSI chips:
+ * 53C810A, 53C825A, 53C860, 53C875, 53C876, 53C885, 53C895,
+ * 53C810, 53C815, 53C825 and the 53C1510D is 53C8XX mode.
+ *
+ *
+ * This driver for FreeBSD-CAM is derived from the Linux sym53c8xx driver.
+ * Copyright (C) 1998-1999 Gerard Roudier
+ *
+ * The sym53c8xx driver is derived from the ncr53c8xx driver that had been
+ * a port of the FreeBSD ncr driver to Linux-1.2.13.
+ *
+ * The original ncr driver has been written for 386bsd and FreeBSD by
+ * Wolfgang Stanglmeier <wolf@cologne.de>
+ * Stefan Esser <se@mi.Uni-Koeln.de>
+ * Copyright (C) 1994 Wolfgang Stanglmeier
+ *
+ * The initialisation code, and part of the code that addresses
+ * FreeBSD-CAM services is based on the aic7xxx driver for FreeBSD-CAM
+ * written by Justin T. Gibbs.
+ *
+ * Other major contributions:
+ *
+ * NVRAM detection and reading.
+ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
+ *
+ *-----------------------------------------------------------------------------
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $FreeBSD$ */
+
+/*
+ * Scripts for SYMBIOS-Processor
+ *
+ * We have to know the offsets of all labels before we reach
+ * them (for forward jumps). Therefore we declare a struct
+ * here. If you make changes inside the script,
+ *
+ * DONT FORGET TO CHANGE THE LENGTHS HERE!
+ */
+
+/*
+ * Script fragments which are loaded into the on-chip RAM
+ * of 825A, 875, 876, 895, 895A, 896 and 1010 chips.
+ * Must not exceed 4K bytes.
+ */
+struct SYM_FWA_SCR {
+ u32 start [ 14];
+ u32 getjob_begin [ 4];
+ u32 getjob_end [ 4];
+ u32 select [ 8];
+ u32 wf_sel_done [ 2];
+ u32 send_ident [ 2];
+#ifdef SYM_CONF_IARB_SUPPORT
+ u32 select2 [ 8];
+#else
+ u32 select2 [ 2];
+#endif
+ u32 command [ 2];
+ u32 dispatch [ 28];
+ u32 sel_no_cmd [ 10];
+ u32 init [ 6];
+ u32 clrack [ 4];
+ u32 disp_status [ 4];
+ u32 datai_done [ 26];
+ u32 datao_done [ 12];
+ u32 datai_phase [ 2];
+ u32 datao_phase [ 2];
+ u32 msg_in [ 2];
+ u32 msg_in2 [ 10];
+#ifdef SYM_CONF_IARB_SUPPORT
+ u32 status [ 14];
+#else
+ u32 status [ 10];
+#endif
+ u32 complete [ 8];
+ u32 complete2 [ 12];
+ u32 complete_error [ 4];
+ u32 done [ 14];
+ u32 done_end [ 2];
+ u32 save_dp [ 8];
+ u32 restore_dp [ 4];
+ u32 disconnect [ 20];
+#ifdef SYM_CONF_IARB_SUPPORT
+ u32 idle [ 4];
+#else
+ u32 idle [ 2];
+#endif
+#ifdef SYM_CONF_IARB_SUPPORT
+ u32 ungetjob [ 6];
+#else
+ u32 ungetjob [ 4];
+#endif
+ u32 reselect [ 4];
+ u32 reselected [ 22];
+ u32 resel_scntl4 [ 20];
+ u32 resel_lun0 [ 6];
+#if SYM_CONF_MAX_TASK*4 > 512
+ u32 resel_tag [ 26];
+#elif SYM_CONF_MAX_TASK*4 > 256
+ u32 resel_tag [ 20];
+#else
+ u32 resel_tag [ 16];
+#endif
+ u32 resel_dsa [ 2];
+ u32 resel_dsa1 [ 6];
+ u32 resel_no_tag [ 6];
+ u32 data_in [SYM_CONF_MAX_SG * 2];
+ u32 data_in2 [ 4];
+ u32 data_out [SYM_CONF_MAX_SG * 2];
+ u32 data_out2 [ 4];
+ u32 pm0_data [ 12];
+ u32 pm0_data_out [ 6];
+ u32 pm0_data_end [ 6];
+ u32 pm1_data [ 12];
+ u32 pm1_data_out [ 6];
+ u32 pm1_data_end [ 6];
+};
+
+/*
+ * Script fragments which stay in main memory for all chips
+ * except for chips that support 8K on-chip RAM.
+ */
+struct SYM_FWB_SCR {
+ u32 start64 [ 2];
+ u32 no_data [ 2];
+ u32 sel_for_abort [ 18];
+ u32 sel_for_abort_1 [ 2];
+ u32 msg_in_etc [ 12];
+ u32 msg_received [ 4];
+ u32 msg_weird_seen [ 4];
+ u32 msg_extended [ 20];
+ u32 msg_bad [ 6];
+ u32 msg_weird [ 4];
+ u32 msg_weird1 [ 8];
+
+ u32 wdtr_resp [ 6];
+ u32 send_wdtr [ 4];
+ u32 sdtr_resp [ 6];
+ u32 send_sdtr [ 4];
+ u32 ppr_resp [ 6];
+ u32 send_ppr [ 4];
+ u32 nego_bad_phase [ 4];
+ u32 msg_out [ 4];
+ u32 msg_out_done [ 4];
+ u32 data_ovrun [ 2];
+ u32 data_ovrun1 [ 22];
+ u32 data_ovrun2 [ 8];
+ u32 abort_resel [ 16];
+ u32 resend_ident [ 4];
+ u32 ident_break [ 4];
+ u32 ident_break_atn [ 4];
+ u32 sdata_in [ 6];
+ u32 resel_bad_lun [ 4];
+ u32 bad_i_t_l [ 4];
+ u32 bad_i_t_l_q [ 4];
+ u32 bad_status [ 6];
+ u32 pm_handle [ 20];
+ u32 pm_handle1 [ 4];
+ u32 pm_save [ 4];
+ u32 pm0_save [ 14];
+ u32 pm1_save [ 14];
+
+ /* WSR handling */
+ u32 pm_wsr_handle [ 42];
+ u32 wsr_ma_helper [ 4];
+
+ /* Data area */
+ u32 zero [ 1];
+ u32 scratch [ 1];
+ u32 pm0_data_addr [ 1];
+ u32 pm1_data_addr [ 1];
+ u32 saved_dsa [ 1];
+ u32 saved_drs [ 1];
+ u32 done_pos [ 1];
+ u32 startpos [ 1];
+ u32 targtbl [ 1];
+ /* End of data area */
+
+ u32 snooptest [ 6];
+ u32 snoopend [ 2];
+};
+
+static struct SYM_FWA_SCR SYM_FWA_SCR = {
+/*--------------------------< START >----------------------------*/ {
+ /*
+ * Switch the LED on.
+ * Will be patched with a NO_OP if LED
+ * not needed or not desired.
+ */
+ SCR_REG_REG (gpreg, SCR_AND, 0xfe),
+ 0,
+ /*
+ * Clear SIGP.
+ */
+ SCR_FROM_REG (ctest2),
+ 0,
+ /*
+ * Stop here if the C code wants to perform
+ * some error recovery procedure manually.
+ * (Indicate this by setting SEM in ISTAT)
+ */
+ SCR_FROM_REG (istat),
+ 0,
+ /*
+ * Report to the C code the next position in
+ * the start queue the SCRIPTS will schedule.
+ * The C code must not change SCRATCHA.
+ */
+ SCR_LOAD_ABS (scratcha, 4),
+ PADDR_B (startpos),
+ SCR_INT ^ IFTRUE (MASK (SEM, SEM)),
+ SIR_SCRIPT_STOPPED,
+ /*
+ * Start the next job.
+ *
+ * @DSA = start point for this job.
+ * SCRATCHA = address of this job in the start queue.
+ *
+ * We will restore startpos with SCRATCHA if we fails the
+ * arbitration or if it is the idle job.
+ *
+ * The below GETJOB_BEGIN to GETJOB_END section of SCRIPTS
+ * is a critical path. If it is partially executed, it then
+ * may happen that the job address is not yet in the DSA
+ * and the the next queue position points to the next JOB.
+ */
+ SCR_LOAD_ABS (dsa, 4),
+ PADDR_B (startpos),
+ SCR_LOAD_REL (temp, 4),
+ 4,
+}/*-------------------------< GETJOB_BEGIN >---------------------*/,{
+ SCR_STORE_ABS (temp, 4),
+ PADDR_B (startpos),
+ SCR_LOAD_REL (dsa, 4),
+ 0,
+}/*-------------------------< GETJOB_END >-----------------------*/,{
+ SCR_LOAD_REL (temp, 4),
+ 0,
+ SCR_RETURN,
+ 0,
+}/*-------------------------< SELECT >---------------------------*/,{
+ /*
+ * DSA contains the address of a scheduled
+ * data structure.
+ *
+ * SCRATCHA contains the address of the start queue
+ * entry which points to the next job.
+ *
+ * Set Initiator mode.
+ *
+ * (Target mode is left as an exercise for the reader)
+ */
+ SCR_CLR (SCR_TRG),
+ 0,
+ /*
+ * And try to select this target.
+ */
+ SCR_SEL_TBL_ATN ^ offsetof (struct sym_dsb, select),
+ PADDR_A (ungetjob),
+ /*
+ * Now there are 4 possibilities:
+ *
+ * (1) The chip looses arbitration.
+ * This is ok, because it will try again,
+ * when the bus becomes idle.
+ * (But beware of the timeout function!)
+ *
+ * (2) The chip is reselected.
+ * Then the script processor takes the jump
+ * to the RESELECT label.
+ *
+ * (3) The chip wins arbitration.
+ * Then it will execute SCRIPTS instruction until
+ * the next instruction that checks SCSI phase.
+ * Then will stop and wait for selection to be
+ * complete or selection time-out to occur.
+ *
+ * After having won arbitration, the SCRIPTS
+ * processor is able to execute instructions while
+ * the SCSI core is performing SCSI selection.
+ */
+ /*
+ * load the savep (saved data pointer) into
+ * the actual data pointer.
+ */
+ SCR_LOAD_REL (temp, 4),
+ offsetof (struct sym_ccb, phys.head.savep),
+ /*
+ * Initialize the status registers
+ */
+ SCR_LOAD_REL (scr0, 4),
+ offsetof (struct sym_ccb, phys.head.status),
+}/*-------------------------< WF_SEL_DONE >----------------------*/,{
+ SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+ SIR_SEL_ATN_NO_MSG_OUT,
+}/*-------------------------< SEND_IDENT >-----------------------*/,{
+ /*
+ * Selection complete.
+ * Send the IDENTIFY and possibly the TAG message
+ * and negotiation message if present.
+ */
+ SCR_MOVE_TBL ^ SCR_MSG_OUT,
+ offsetof (struct sym_dsb, smsg),
+}/*-------------------------< SELECT2 >--------------------------*/,{
+#ifdef SYM_CONF_IARB_SUPPORT
+ /*
+ * Set IMMEDIATE ARBITRATION if we have been given
+ * a hint to do so. (Some job to do after this one).
+ */
+ SCR_FROM_REG (HF_REG),
+ 0,
+ SCR_JUMPR ^ IFFALSE (MASK (HF_HINT_IARB, HF_HINT_IARB)),
+ 8,
+ SCR_REG_REG (scntl1, SCR_OR, IARB),
+ 0,
+#endif
+ /*
+ * Anticipate the COMMAND phase.
+ * This is the PHASE we expect at this point.
+ */
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_COMMAND)),
+ PADDR_A (sel_no_cmd),
+}/*-------------------------< COMMAND >--------------------------*/,{
+ /*
+ * ... and send the command
+ */
+ SCR_MOVE_TBL ^ SCR_COMMAND,
+ offsetof (struct sym_dsb, cmd),
+}/*-------------------------< DISPATCH >-------------------------*/,{
+ /*
+ * MSG_IN is the only phase that shall be
+ * entered at least once for each (re)selection.
+ * So we test it first.
+ */
+ SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
+ PADDR_A (msg_in),
+ SCR_JUMP ^ IFTRUE (IF (SCR_DATA_OUT)),
+ PADDR_A (datao_phase),
+ SCR_JUMP ^ IFTRUE (IF (SCR_DATA_IN)),
+ PADDR_A (datai_phase),
+ SCR_JUMP ^ IFTRUE (IF (SCR_STATUS)),
+ PADDR_A (status),
+ SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND)),
+ PADDR_A (command),
+ SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)),
+ PADDR_B (msg_out),
+ /*
+ * Discard as many illegal phases as
+ * required and tell the C code about.
+ */
+ SCR_JUMPR ^ IFFALSE (WHEN (SCR_ILG_OUT)),
+ 16,
+ SCR_MOVE_ABS (1) ^ SCR_ILG_OUT,
+ HADDR_1 (scratch),
+ SCR_JUMPR ^ IFTRUE (WHEN (SCR_ILG_OUT)),
+ -16,
+ SCR_JUMPR ^ IFFALSE (WHEN (SCR_ILG_IN)),
+ 16,
+ SCR_MOVE_ABS (1) ^ SCR_ILG_IN,
+ HADDR_1 (scratch),
+ SCR_JUMPR ^ IFTRUE (WHEN (SCR_ILG_IN)),
+ -16,
+ SCR_INT,
+ SIR_BAD_PHASE,
+ SCR_JUMP,
+ PADDR_A (dispatch),
+}/*-------------------------< SEL_NO_CMD >-----------------------*/,{
+ /*
+ * The target does not switch to command
+ * phase after IDENTIFY has been sent.
+ *
+ * If it stays in MSG OUT phase send it
+ * the IDENTIFY again.
+ */
+ SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)),
+ PADDR_B (resend_ident),
+ /*
+ * If target does not switch to MSG IN phase
+ * and we sent a negotiation, assert the
+ * failure immediately.
+ */
+ SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
+ PADDR_A (dispatch),
+ SCR_FROM_REG (HS_REG),
+ 0,
+ SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)),
+ SIR_NEGO_FAILED,
+ /*
+ * Jump to dispatcher.
+ */
+ SCR_JUMP,
+ PADDR_A (dispatch),
+}/*-------------------------< INIT >-----------------------------*/,{
+ /*
+ * Wait for the SCSI RESET signal to be
+ * inactive before restarting operations,
+ * since the chip may hang on SEL_ATN
+ * if SCSI RESET is active.
+ */
+ SCR_FROM_REG (sstat0),
+ 0,
+ SCR_JUMPR ^ IFTRUE (MASK (IRST, IRST)),
+ -16,
+ SCR_JUMP,
+ PADDR_A (start),
+}/*-------------------------< CLRACK >---------------------------*/,{
+ /*
+ * Terminate possible pending message phase.
+ */
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_JUMP,
+ PADDR_A (dispatch),
+}/*-------------------------< DISP_STATUS >----------------------*/,{
+ /*
+ * Anticipate STATUS phase.
+ *
+ * Does spare 3 SCRIPTS instructions when we have
+ * completed the INPUT of the data.
+ */
+ SCR_JUMP ^ IFTRUE (WHEN (SCR_STATUS)),
+ PADDR_A (status),
+ SCR_JUMP,
+ PADDR_A (dispatch),
+}/*-------------------------< DATAI_DONE >-----------------------*/,{
+ /*
+ * If the device still wants to send us data,
+ * we must count the extra bytes.
+ */
+ SCR_JUMP ^ IFTRUE (WHEN (SCR_DATA_IN)),
+ PADDR_B (data_ovrun),
+ /*
+ * If the SWIDE is not full, jump to dispatcher.
+ * We anticipate a STATUS phase.
+ */
+ SCR_FROM_REG (scntl2),
+ 0,
+ SCR_JUMP ^ IFFALSE (MASK (WSR, WSR)),
+ PADDR_A (disp_status),
+ /*
+ * The SWIDE is full.
+ * Clear this condition.
+ */
+ SCR_REG_REG (scntl2, SCR_OR, WSR),
+ 0,
+ /*
+ * We are expecting an IGNORE RESIDUE message
+ * from the device, otherwise we are in data
+ * overrun condition. Check against MSG_IN phase.
+ */
+ SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ SIR_SWIDE_OVERRUN,
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ PADDR_A (disp_status),
+ /*
+ * We are in MSG_IN phase,
+ * Read the first byte of the message.
+ * If it is not an IGNORE RESIDUE message,
+ * signal overrun and jump to message
+ * processing.
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ HADDR_1 (msgin[0]),
+ SCR_INT ^ IFFALSE (DATA (M_IGN_RESIDUE)),
+ SIR_SWIDE_OVERRUN,
+ SCR_JUMP ^ IFFALSE (DATA (M_IGN_RESIDUE)),
+ PADDR_A (msg_in2),
+ /*
+ * We got the message we expected.
+ * Read the 2nd byte, and jump to dispatcher.
+ */
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ HADDR_1 (msgin[1]),
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_JUMP,
+ PADDR_A (disp_status),
+}/*-------------------------< DATAO_DONE >-----------------------*/,{
+ /*
+ * If the device wants us to send more data,
+ * we must count the extra bytes.
+ */
+ SCR_JUMP ^ IFTRUE (WHEN (SCR_DATA_OUT)),
+ PADDR_B (data_ovrun),
+ /*
+ * If the SODL is not full jump to dispatcher.
+ * We anticipate a STATUS phase.
+ */
+ SCR_FROM_REG (scntl2),
+ 0,
+ SCR_JUMP ^ IFFALSE (MASK (WSS, WSS)),
+ PADDR_A (disp_status),
+ /*
+ * The SODL is full, clear this condition.
+ */
+ SCR_REG_REG (scntl2, SCR_OR, WSS),
+ 0,
+ /*
+ * And signal a DATA UNDERRUN condition
+ * to the C code.
+ */
+ SCR_INT,
+ SIR_SODL_UNDERRUN,
+ SCR_JUMP,
+ PADDR_A (dispatch),
+}/*-------------------------< DATAI_PHASE >----------------------*/,{
+ SCR_RETURN,
+ 0,
+}/*-------------------------< DATAO_PHASE >----------------------*/,{
+ SCR_RETURN,
+ 0,
+}/*-------------------------< MSG_IN >---------------------------*/,{
+ /*
+ * Get the first byte of the message.
+ *
+ * The script processor doesn't negate the
+ * ACK signal after this transfer.
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ HADDR_1 (msgin[0]),
+}/*-------------------------< MSG_IN2 >--------------------------*/,{
+ /*
+ * Check first against 1 byte messages
+ * that we handle from SCRIPTS.
+ */
+ SCR_JUMP ^ IFTRUE (DATA (M_COMPLETE)),
+ PADDR_A (complete),
+ SCR_JUMP ^ IFTRUE (DATA (M_DISCONNECT)),
+ PADDR_A (disconnect),
+ SCR_JUMP ^ IFTRUE (DATA (M_SAVE_DP)),
+ PADDR_A (save_dp),
+ SCR_JUMP ^ IFTRUE (DATA (M_RESTORE_DP)),
+ PADDR_A (restore_dp),
+ /*
+ * We handle all other messages from the
+ * C code, so no need to waste on-chip RAM
+ * for those ones.
+ */
+ SCR_JUMP,
+ PADDR_B (msg_in_etc),
+}/*-------------------------< STATUS >---------------------------*/,{
+ /*
+ * get the status
+ */
+ SCR_MOVE_ABS (1) ^ SCR_STATUS,
+ HADDR_1 (scratch),
+#ifdef SYM_CONF_IARB_SUPPORT
+ /*
+ * If STATUS is not GOOD, clear IMMEDIATE ARBITRATION,
+ * since we may have to tamper the start queue from
+ * the C code.
+ */
+ SCR_JUMPR ^ IFTRUE (DATA (S_GOOD)),
+ 8,
+ SCR_REG_REG (scntl1, SCR_AND, ~IARB),
+ 0,
+#endif
+ /*
+ * save status to scsi_status.
+ * mark as complete.
+ */
+ SCR_TO_REG (SS_REG),
+ 0,
+ SCR_LOAD_REG (HS_REG, HS_COMPLETE),
+ 0,
+ /*
+ * Anticipate the MESSAGE PHASE for
+ * the TASK COMPLETE message.
+ */
+ SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
+ PADDR_A (msg_in),
+ SCR_JUMP,
+ PADDR_A (dispatch),
+}/*-------------------------< COMPLETE >-------------------------*/,{
+ /*
+ * Complete message.
+ *
+ * Copy the data pointer to LASTP.
+ */
+ SCR_STORE_REL (temp, 4),
+ offsetof (struct sym_ccb, phys.head.lastp),
+ /*
+ * When we terminate the cycle by clearing ACK,
+ * the target may disconnect immediately.
+ *
+ * We don't want to be told of an "unexpected disconnect",
+ * so we disable this feature.
+ */
+ SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+ 0,
+ /*
+ * Terminate cycle ...
+ */
+ SCR_CLR (SCR_ACK|SCR_ATN),
+ 0,
+ /*
+ * ... and wait for the disconnect.
+ */
+ SCR_WAIT_DISC,
+ 0,
+}/*-------------------------< COMPLETE2 >------------------------*/,{
+ /*
+ * Save host status.
+ */
+ SCR_STORE_REL (scr0, 4),
+ offsetof (struct sym_ccb, phys.head.status),
+ /*
+ * Some bridges may reorder DMA writes to memory.
+ * We donnot want the CPU to deal with completions
+ * without all the posted write having been flushed
+ * to memory. This DUMMY READ should flush posted
+ * buffers prior to the CPU having to deal with
+ * completions.
+ */
+ SCR_LOAD_REL (scr0, 4), /* DUMMY READ */
+ offsetof (struct sym_ccb, phys.head.status),
+
+ /*
+ * If command resulted in not GOOD status,
+ * call the C code if needed.
+ */
+ SCR_FROM_REG (SS_REG),
+ 0,
+ SCR_CALL ^ IFFALSE (DATA (S_GOOD)),
+ PADDR_B (bad_status),
+ /*
+ * If we performed an auto-sense, call
+ * the C code to synchronyze task aborts
+ * with UNIT ATTENTION conditions.
+ */
+ SCR_FROM_REG (HF_REG),
+ 0,
+ SCR_JUMPR ^ IFTRUE (MASK (0 ,(HF_SENSE|HF_EXT_ERR))),
+ 16,
+}/*-------------------------< COMPLETE_ERROR >-------------------*/,{
+ SCR_LOAD_ABS (scratcha, 4),
+ PADDR_B (startpos),
+ SCR_INT,
+ SIR_COMPLETE_ERROR,
+}/*-------------------------< DONE >-----------------------------*/,{
+ /*
+ * Copy the DSA to the DONE QUEUE and
+ * signal completion to the host.
+ * If we are interrupted between DONE
+ * and DONE_END, we must reset, otherwise
+ * the completed CCB may be lost.
+ */
+ SCR_STORE_ABS (dsa, 4),
+ PADDR_B (saved_dsa),
+ SCR_LOAD_ABS (dsa, 4),
+ PADDR_B (done_pos),
+ SCR_LOAD_ABS (scratcha, 4),
+ PADDR_B (saved_dsa),
+ SCR_STORE_REL (scratcha, 4),
+ 0,
+ /*
+ * The instruction below reads the DONE QUEUE next
+ * free position from memory.
+ * In addition it ensures that all PCI posted writes
+ * are flushed and so the DSA value of the done
+ * CCB is visible by the CPU before INTFLY is raised.
+ */
+ SCR_LOAD_REL (temp, 4),
+ 4,
+ SCR_INT_FLY,
+ 0,
+ SCR_STORE_ABS (temp, 4),
+ PADDR_B (done_pos),
+}/*-------------------------< DONE_END >-------------------------*/,{
+ SCR_JUMP,
+ PADDR_A (start),
+}/*-------------------------< SAVE_DP >--------------------------*/,{
+ /*
+ * Clear ACK immediately.
+ * No need to delay it.
+ */
+ SCR_CLR (SCR_ACK),
+ 0,
+ /*
+ * Keep track we received a SAVE DP, so
+ * we will switch to the other PM context
+ * on the next PM since the DP may point
+ * to the current PM context.
+ */
+ SCR_REG_REG (HF_REG, SCR_OR, HF_DP_SAVED),
+ 0,
+ /*
+ * SAVE_DP message:
+ * Copy the data pointer to SAVEP.
+ */
+ SCR_STORE_REL (temp, 4),
+ offsetof (struct sym_ccb, phys.head.savep),
+ SCR_JUMP,
+ PADDR_A (dispatch),
+}/*-------------------------< RESTORE_DP >-----------------------*/,{
+ /*
+ * RESTORE_DP message:
+ * Copy SAVEP to actual data pointer.
+ */
+ SCR_LOAD_REL (temp, 4),
+ offsetof (struct sym_ccb, phys.head.savep),
+ SCR_JUMP,
+ PADDR_A (clrack),
+}/*-------------------------< DISCONNECT >-----------------------*/,{
+ /*
+ * DISCONNECTing ...
+ *
+ * disable the "unexpected disconnect" feature,
+ * and remove the ACK signal.
+ */
+ SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+ 0,
+ SCR_CLR (SCR_ACK|SCR_ATN),
+ 0,
+ /*
+ * Wait for the disconnect.
+ */
+ SCR_WAIT_DISC,
+ 0,
+ /*
+ * Status is: DISCONNECTED.
+ */
+ SCR_LOAD_REG (HS_REG, HS_DISCONNECT),
+ 0,
+ /*
+ * Save host status.
+ */
+ SCR_STORE_REL (scr0, 4),
+ offsetof (struct sym_ccb, phys.head.status),
+ /*
+ * If QUIRK_AUTOSAVE is set,
+ * do an "save pointer" operation.
+ */
+ SCR_FROM_REG (QU_REG),
+ 0,
+ SCR_JUMP ^ IFFALSE (MASK (SYM_QUIRK_AUTOSAVE, SYM_QUIRK_AUTOSAVE)),
+ PADDR_A (start),
+ /*
+ * like SAVE_DP message:
+ * Remember we saved the data pointer.
+ * Copy data pointer to SAVEP.
+ */
+ SCR_REG_REG (HF_REG, SCR_OR, HF_DP_SAVED),
+ 0,
+ SCR_STORE_REL (temp, 4),
+ offsetof (struct sym_ccb, phys.head.savep),
+ SCR_JUMP,
+ PADDR_A (start),
+}/*-------------------------< IDLE >-----------------------------*/,{
+ /*
+ * Nothing to do?
+ * Switch the LED off and wait for reselect.
+ * Will be patched with a NO_OP if LED
+ * not needed or not desired.
+ */
+ SCR_REG_REG (gpreg, SCR_OR, 0x01),
+ 0,
+#ifdef SYM_CONF_IARB_SUPPORT
+ SCR_JUMPR,
+ 8,
+#endif
+}/*-------------------------< UNGETJOB >-------------------------*/,{
+#ifdef SYM_CONF_IARB_SUPPORT
+ /*
+ * Set IMMEDIATE ARBITRATION, for the next time.
+ * This will give us better chance to win arbitration
+ * for the job we just wanted to do.
+ */
+ SCR_REG_REG (scntl1, SCR_OR, IARB),
+ 0,
+#endif
+ /*
+ * We are not able to restart the SCRIPTS if we are
+ * interrupted and these instruction haven't been
+ * all executed. BTW, this is very unlikely to
+ * happen, but we check that from the C code.
+ */
+ SCR_LOAD_REG (dsa, 0xff),
+ 0,
+ SCR_STORE_ABS (scratcha, 4),
+ PADDR_B (startpos),
+}/*-------------------------< RESELECT >-------------------------*/,{
+ /*
+ * Make sure we are in initiator mode.
+ */
+ SCR_CLR (SCR_TRG),
+ 0,
+ /*
+ * Sleep waiting for a reselection.
+ */
+ SCR_WAIT_RESEL,
+ PADDR_A(start),
+}/*-------------------------< RESELECTED >-----------------------*/,{
+ /*
+ * Switch the LED on.
+ * Will be patched with a NO_OP if LED
+ * not needed or not desired.
+ */
+ SCR_REG_REG (gpreg, SCR_AND, 0xfe),
+ 0,
+ /*
+ * load the target id into the sdid
+ */
+ SCR_REG_SFBR (ssid, SCR_AND, 0x8F),
+ 0,
+ SCR_TO_REG (sdid),
+ 0,
+ /*
+ * Load the target control block address
+ */
+ SCR_LOAD_ABS (dsa, 4),
+ PADDR_B (targtbl),
+ SCR_SFBR_REG (dsa, SCR_SHL, 0),
+ 0,
+ SCR_REG_REG (dsa, SCR_SHL, 0),
+ 0,
+ SCR_REG_REG (dsa, SCR_AND, 0x3c),
+ 0,
+ SCR_LOAD_REL (dsa, 4),
+ 0,
+ /*
+ * We expect MESSAGE IN phase.
+ * If not, get help from the C code.
+ */
+ SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ SIR_RESEL_NO_MSG_IN,
+ /*
+ * Load the legacy synchronous transfer registers.
+ */
+ SCR_LOAD_REL (scntl3, 1),
+ offsetof(struct sym_tcb, head.wval),
+ SCR_LOAD_REL (sxfer, 1),
+ offsetof(struct sym_tcb, head.sval),
+}/*-------------------------< RESEL_SCNTL4 >---------------------*/,{
+ /*
+ * The C1010 uses a new synchronous timing scheme.
+ * Will be patched with a NO_OP if not a C1010.
+ */
+ SCR_LOAD_REL (scntl4, 1),
+ offsetof(struct sym_tcb, head.uval),
+ /*
+ * Get the IDENTIFY message.
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ HADDR_1 (msgin),
+ /*
+ * If IDENTIFY LUN #0, use a faster path
+ * to find the LCB structure.
+ */
+ SCR_JUMP ^ IFTRUE (MASK (0x80, 0xbf)),
+ PADDR_A (resel_lun0),
+ /*
+ * If message isn't an IDENTIFY,
+ * tell the C code about.
+ */
+ SCR_INT ^ IFFALSE (MASK (0x80, 0x80)),
+ SIR_RESEL_NO_IDENTIFY,
+ /*
+ * It is an IDENTIFY message,
+ * Load the LUN control block address.
+ */
+ SCR_LOAD_REL (dsa, 4),
+ offsetof(struct sym_tcb, head.luntbl_sa),
+ SCR_SFBR_REG (dsa, SCR_SHL, 0),
+ 0,
+ SCR_REG_REG (dsa, SCR_SHL, 0),
+ 0,
+ SCR_REG_REG (dsa, SCR_AND, 0xfc),
+ 0,
+ SCR_LOAD_REL (dsa, 4),
+ 0,
+ SCR_JUMPR,
+ 8,
+}/*-------------------------< RESEL_LUN0 >-----------------------*/,{
+ /*
+ * LUN 0 special case (but usual one :))
+ */
+ SCR_LOAD_REL (dsa, 4),
+ offsetof(struct sym_tcb, head.lun0_sa),
+ /*
+ * Jump indirectly to the reselect action for this LUN.
+ */
+ SCR_LOAD_REL (temp, 4),
+ offsetof(struct sym_lcb, head.resel_sa),
+ SCR_RETURN,
+ 0,
+ /* In normal situations, we jump to RESEL_TAG or RESEL_NO_TAG */
+}/*-------------------------< RESEL_TAG >------------------------*/,{
+ /*
+ * ACK the IDENTIFY or TAG previously received.
+ */
+ SCR_CLR (SCR_ACK),
+ 0,
+ /*
+ * It shall be a tagged command.
+ * Read SIMPLE+TAG.
+ * The C code will deal with errors.
+ * Agressive optimization, is'nt it? :)
+ */
+ SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
+ HADDR_1 (msgin),
+ /*
+ * Load the pointer to the tagged task
+ * table for this LUN.
+ */
+ SCR_LOAD_REL (dsa, 4),
+ offsetof(struct sym_lcb, head.itlq_tbl_sa),
+ /*
+ * The SIDL still contains the TAG value.
+ * Agressive optimization, isn't it? :):)
+ */
+ SCR_REG_SFBR (sidl, SCR_SHL, 0),
+ 0,
+#if SYM_CONF_MAX_TASK*4 > 512
+ SCR_JUMPR ^ IFFALSE (CARRYSET),
+ 8,
+ SCR_REG_REG (dsa1, SCR_OR, 2),
+ 0,
+ SCR_REG_REG (sfbr, SCR_SHL, 0),
+ 0,
+ SCR_JUMPR ^ IFFALSE (CARRYSET),
+ 8,
+ SCR_REG_REG (dsa1, SCR_OR, 1),
+ 0,
+#elif SYM_CONF_MAX_TASK*4 > 256
+ SCR_JUMPR ^ IFFALSE (CARRYSET),
+ 8,
+ SCR_REG_REG (dsa1, SCR_OR, 1),
+ 0,
+#endif
+ /*
+ * Retrieve the DSA of this task.
+ * JUMP indirectly to the restart point of the CCB.
+ */
+ SCR_SFBR_REG (dsa, SCR_AND, 0xfc),
+ 0,
+ SCR_LOAD_REL (dsa, 4),
+ 0,
+ SCR_LOAD_REL (temp, 4),
+ offsetof(struct sym_ccb, phys.head.go.restart),
+ SCR_RETURN,
+ 0,
+ /* In normal situations we branch to RESEL_DSA */
+}/*-------------------------< RESEL_DSA >------------------------*/,{
+ /*
+ * ACK the IDENTIFY or TAG previously received.
+ */
+ SCR_CLR (SCR_ACK),
+ 0,
+}/*-------------------------< RESEL_DSA1 >-----------------------*/,{
+ /*
+ * load the savep (saved pointer) into
+ * the actual data pointer.
+ */
+ SCR_LOAD_REL (temp, 4),
+ offsetof (struct sym_ccb, phys.head.savep),
+ /*
+ * Initialize the status registers
+ */
+ SCR_LOAD_REL (scr0, 4),
+ offsetof (struct sym_ccb, phys.head.status),
+ /*
+ * Jump to dispatcher.
+ */
+ SCR_JUMP,
+ PADDR_A (dispatch),
+}/*-------------------------< RESEL_NO_TAG >---------------------*/,{
+ /*
+ * Load the DSA with the unique ITL task.
+ */
+ SCR_LOAD_REL (dsa, 4),
+ offsetof(struct sym_lcb, head.itl_task_sa),
+ /*
+ * JUMP indirectly to the restart point of the CCB.
+ */
+ SCR_LOAD_REL (temp, 4),
+ offsetof(struct sym_ccb, phys.head.go.restart),
+ SCR_RETURN,
+ 0,
+ /* In normal situations we branch to RESEL_DSA */
+}/*-------------------------< DATA_IN >--------------------------*/,{
+/*
+ * Because the size depends on the
+ * #define SYM_CONF_MAX_SG parameter,
+ * it is filled in at runtime.
+ *
+ * ##===========< i=0; i<SYM_CONF_MAX_SG >=========
+ * || SCR_CHMOV_TBL ^ SCR_DATA_IN,
+ * || offsetof (struct sym_dsb, data[ i]),
+ * ##==========================================
+ */
+0
+}/*-------------------------< DATA_IN2 >-------------------------*/,{
+ SCR_CALL,
+ PADDR_A (datai_done),
+ SCR_JUMP,
+ PADDR_B (data_ovrun),
+}/*-------------------------< DATA_OUT >-------------------------*/,{
+/*
+ * Because the size depends on the
+ * #define SYM_CONF_MAX_SG parameter,
+ * it is filled in at runtime.
+ *
+ * ##===========< i=0; i<SYM_CONF_MAX_SG >=========
+ * || SCR_CHMOV_TBL ^ SCR_DATA_OUT,
+ * || offsetof (struct sym_dsb, data[ i]),
+ * ##==========================================
+ */
+0
+}/*-------------------------< DATA_OUT2 >------------------------*/,{
+ SCR_CALL,
+ PADDR_A (datao_done),
+ SCR_JUMP,
+ PADDR_B (data_ovrun),
+}/*-------------------------< PM0_DATA >-------------------------*/,{
+ /*
+ * Read our host flags to SFBR, so we will be able
+ * to check against the data direction we expect.
+ */
+ SCR_FROM_REG (HF_REG),
+ 0,
+ /*
+ * Check against actual DATA PHASE.
+ */
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
+ PADDR_A (pm0_data_out),
+ /*
+ * Actual phase is DATA IN.
+ * Check against expected direction.
+ */
+ SCR_JUMP ^ IFFALSE (MASK (HF_DATA_IN, HF_DATA_IN)),
+ PADDR_B (data_ovrun),
+ /*
+ * Keep track we are moving data from the
+ * PM0 DATA mini-script.
+ */
+ SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM0),
+ 0,
+ /*
+ * Move the data to memory.
+ */
+ SCR_CHMOV_TBL ^ SCR_DATA_IN,
+ offsetof (struct sym_ccb, phys.pm0.sg),
+ SCR_JUMP,
+ PADDR_A (pm0_data_end),
+}/*-------------------------< PM0_DATA_OUT >---------------------*/,{
+ /*
+ * Actual phase is DATA OUT.
+ * Check against expected direction.
+ */
+ SCR_JUMP ^ IFTRUE (MASK (HF_DATA_IN, HF_DATA_IN)),
+ PADDR_B (data_ovrun),
+ /*
+ * Keep track we are moving data from the
+ * PM0 DATA mini-script.
+ */
+ SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM0),
+ 0,
+ /*
+ * Move the data from memory.
+ */
+ SCR_CHMOV_TBL ^ SCR_DATA_OUT,
+ offsetof (struct sym_ccb, phys.pm0.sg),
+}/*-------------------------< PM0_DATA_END >---------------------*/,{
+ /*
+ * Clear the flag that told we were moving
+ * data from the PM0 DATA mini-script.
+ */
+ SCR_REG_REG (HF_REG, SCR_AND, (~HF_IN_PM0)),
+ 0,
+ /*
+ * Return to the previous DATA script which
+ * is guaranteed by design (if no bug) to be
+ * the main DATA script for this transfer.
+ */
+ SCR_LOAD_REL (temp, 4),
+ offsetof (struct sym_ccb, phys.pm0.ret),
+ SCR_RETURN,
+ 0,
+}/*-------------------------< PM1_DATA >-------------------------*/,{
+ /*
+ * Read our host flags to SFBR, so we will be able
+ * to check against the data direction we expect.
+ */
+ SCR_FROM_REG (HF_REG),
+ 0,
+ /*
+ * Check against actual DATA PHASE.
+ */
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
+ PADDR_A (pm1_data_out),
+ /*
+ * Actual phase is DATA IN.
+ * Check against expected direction.
+ */
+ SCR_JUMP ^ IFFALSE (MASK (HF_DATA_IN, HF_DATA_IN)),
+ PADDR_B (data_ovrun),
+ /*
+ * Keep track we are moving data from the
+ * PM1 DATA mini-script.
+ */
+ SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM1),
+ 0,
+ /*
+ * Move the data to memory.
+ */
+ SCR_CHMOV_TBL ^ SCR_DATA_IN,
+ offsetof (struct sym_ccb, phys.pm1.sg),
+ SCR_JUMP,
+ PADDR_A (pm1_data_end),
+}/*-------------------------< PM1_DATA_OUT >---------------------*/,{
+ /*
+ * Actual phase is DATA OUT.
+ * Check against expected direction.
+ */
+ SCR_JUMP ^ IFTRUE (MASK (HF_DATA_IN, HF_DATA_IN)),
+ PADDR_B (data_ovrun),
+ /*
+ * Keep track we are moving data from the
+ * PM1 DATA mini-script.
+ */
+ SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM1),
+ 0,
+ /*
+ * Move the data from memory.
+ */
+ SCR_CHMOV_TBL ^ SCR_DATA_OUT,
+ offsetof (struct sym_ccb, phys.pm1.sg),
+}/*-------------------------< PM1_DATA_END >---------------------*/,{
+ /*
+ * Clear the flag that told we were moving
+ * data from the PM1 DATA mini-script.
+ */
+ SCR_REG_REG (HF_REG, SCR_AND, (~HF_IN_PM1)),
+ 0,
+ /*
+ * Return to the previous DATA script which
+ * is guaranteed by design (if no bug) to be
+ * the main DATA script for this transfer.
+ */
+ SCR_LOAD_REL (temp, 4),
+ offsetof (struct sym_ccb, phys.pm1.ret),
+ SCR_RETURN,
+ 0,
+}/*-------------------------<>-----------------------------------*/
+};
+
+static struct SYM_FWB_SCR SYM_FWB_SCR = {
+/*--------------------------< START64 >--------------------------*/ {
+ /*
+ * SCRIPT entry point for the 895A, 896 and 1010.
+ * For now, there is no specific stuff for those
+ * chips at this point, but this may come.
+ */
+ SCR_JUMP,
+ PADDR_A (init),
+}/*-------------------------< NO_DATA >--------------------------*/,{
+ SCR_JUMP,
+ PADDR_B (data_ovrun),
+}/*-------------------------< SEL_FOR_ABORT >--------------------*/,{
+ /*
+ * We are jumped here by the C code, if we have
+ * some target to reset or some disconnected
+ * job to abort. Since error recovery is a serious
+ * busyness, we will really reset the SCSI BUS, if
+ * case of a SCSI interrupt occuring in this path.
+ */
+
+ /*
+ * Set initiator mode.
+ */
+ SCR_CLR (SCR_TRG),
+ 0,
+ /*
+ * And try to select this target.
+ */
+ SCR_SEL_TBL_ATN ^ offsetof (struct sym_hcb, abrt_sel),
+ PADDR_A (reselect),
+ /*
+ * Wait for the selection to complete or
+ * the selection to time out.
+ */
+ SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+ -8,
+ /*
+ * Call the C code.
+ */
+ SCR_INT,
+ SIR_TARGET_SELECTED,
+ /*
+ * The C code should let us continue here.
+ * Send the 'kiss of death' message.
+ * We expect an immediate disconnect once
+ * the target has eaten the message.
+ */
+ SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+ 0,
+ SCR_MOVE_TBL ^ SCR_MSG_OUT,
+ offsetof (struct sym_hcb, abrt_tbl),
+ SCR_CLR (SCR_ACK|SCR_ATN),
+ 0,
+ SCR_WAIT_DISC,
+ 0,
+ /*
+ * Tell the C code that we are done.
+ */
+ SCR_INT,
+ SIR_ABORT_SENT,
+}/*-------------------------< SEL_FOR_ABORT_1 >------------------*/,{
+ /*
+ * Jump at scheduler.
+ */
+ SCR_JUMP,
+ PADDR_A (start),
+}/*-------------------------< MSG_IN_ETC >-----------------------*/,{
+ /*
+ * If it is an EXTENDED (variable size message)
+ * Handle it.
+ */
+ SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)),
+ PADDR_B (msg_extended),
+ /*
+ * Let the C code handle any other
+ * 1 byte message.
+ */
+ SCR_JUMP ^ IFTRUE (MASK (0x00, 0xf0)),
+ PADDR_B (msg_received),
+ SCR_JUMP ^ IFTRUE (MASK (0x10, 0xf0)),
+ PADDR_B (msg_received),
+ /*
+ * We donnot handle 2 bytes messages from SCRIPTS.
+ * So, let the C code deal with these ones too.
+ */
+ SCR_INT ^ IFFALSE (MASK (0x20, 0xf0)),
+ SIR_MSG_WEIRD,
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ HADDR_1 (msgin[1]),
+}/*-------------------------< MSG_RECEIVED >---------------------*/,{
+ SCR_LOAD_REL (scratcha, 4), /* DUMMY READ */
+ 0,
+ SCR_INT,
+ SIR_MSG_RECEIVED,
+}/*-------------------------< MSG_WEIRD_SEEN >-------------------*/,{
+ SCR_LOAD_REL (scratcha, 4), /* DUMMY READ */
+ 0,
+ SCR_INT,
+ SIR_MSG_WEIRD,
+}/*-------------------------< MSG_EXTENDED >---------------------*/,{
+ /*
+ * Clear ACK and get the next byte
+ * assumed to be the message length.
+ */
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ HADDR_1 (msgin[1]),
+ /*
+ * Try to catch some unlikely situations as 0 length
+ * or too large the length.
+ */
+ SCR_JUMP ^ IFTRUE (DATA (0)),
+ PADDR_B (msg_weird_seen),
+ SCR_TO_REG (scratcha),
+ 0,
+ SCR_REG_REG (sfbr, SCR_ADD, (256-8)),
+ 0,
+ SCR_JUMP ^ IFTRUE (CARRYSET),
+ PADDR_B (msg_weird_seen),
+ /*
+ * We donnot handle extended messages from SCRIPTS.
+ * Read the amount of data correponding to the
+ * message length and call the C code.
+ */
+ SCR_STORE_REL (scratcha, 1),
+ offsetof (struct sym_dsb, smsg_ext.size),
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_MOVE_TBL ^ SCR_MSG_IN,
+ offsetof (struct sym_dsb, smsg_ext),
+ SCR_JUMP,
+ PADDR_B (msg_received),
+}/*-------------------------< MSG_BAD >--------------------------*/,{
+ /*
+ * unimplemented message - reject it.
+ */
+ SCR_INT,
+ SIR_REJECT_TO_SEND,
+ SCR_SET (SCR_ATN),
+ 0,
+ SCR_JUMP,
+ PADDR_A (clrack),
+}/*-------------------------< MSG_WEIRD >------------------------*/,{
+ /*
+ * weird message received
+ * ignore all MSG IN phases and reject it.
+ */
+ SCR_INT,
+ SIR_REJECT_TO_SEND,
+ SCR_SET (SCR_ATN),
+ 0,
+}/*-------------------------< MSG_WEIRD1 >-----------------------*/,{
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ PADDR_A (dispatch),
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ HADDR_1 (scratch),
+ SCR_JUMP,
+ PADDR_B (msg_weird1),
+}/*-------------------------< WDTR_RESP >------------------------*/,{
+ /*
+ * let the target fetch our answer.
+ */
+ SCR_SET (SCR_ATN),
+ 0,
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+ PADDR_B (nego_bad_phase),
+}/*-------------------------< SEND_WDTR >------------------------*/,{
+ /*
+ * Send the M_X_WIDE_REQ
+ */
+ SCR_MOVE_ABS (4) ^ SCR_MSG_OUT,
+ HADDR_1 (msgout),
+ SCR_JUMP,
+ PADDR_B (msg_out_done),
+}/*-------------------------< SDTR_RESP >------------------------*/,{
+ /*
+ * let the target fetch our answer.
+ */
+ SCR_SET (SCR_ATN),
+ 0,
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+ PADDR_B (nego_bad_phase),
+}/*-------------------------< SEND_SDTR >------------------------*/,{
+ /*
+ * Send the M_X_SYNC_REQ
+ */
+ SCR_MOVE_ABS (5) ^ SCR_MSG_OUT,
+ HADDR_1 (msgout),
+ SCR_JUMP,
+ PADDR_B (msg_out_done),
+}/*-------------------------< PPR_RESP >-------------------------*/,{
+ /*
+ * let the target fetch our answer.
+ */
+ SCR_SET (SCR_ATN),
+ 0,
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+ PADDR_B (nego_bad_phase),
+}/*-------------------------< SEND_PPR >-------------------------*/,{
+ /*
+ * Send the M_X_PPR_REQ
+ */
+ SCR_MOVE_ABS (8) ^ SCR_MSG_OUT,
+ HADDR_1 (msgout),
+ SCR_JUMP,
+ PADDR_B (msg_out_done),
+}/*-------------------------< NEGO_BAD_PHASE >-------------------*/,{
+ SCR_INT,
+ SIR_NEGO_PROTO,
+ SCR_JUMP,
+ PADDR_A (dispatch),
+}/*-------------------------< MSG_OUT >--------------------------*/,{
+ /*
+ * The target requests a message.
+ * We donnot send messages that may
+ * require the device to go to bus free.
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
+ HADDR_1 (msgout),
+ /*
+ * ... wait for the next phase
+ * if it's a message out, send it again, ...
+ */
+ SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)),
+ PADDR_B (msg_out),
+}/*-------------------------< MSG_OUT_DONE >---------------------*/,{
+ /*
+ * Let the C code be aware of the
+ * sent message and clear the message.
+ */
+ SCR_INT,
+ SIR_MSG_OUT_DONE,
+ /*
+ * ... and process the next phase
+ */
+ SCR_JUMP,
+ PADDR_A (dispatch),
+}/*-------------------------< DATA_OVRUN >-----------------------*/,{
+ /*
+ * Use scratcha to count the extra bytes.
+ */
+ SCR_LOAD_ABS (scratcha, 4),
+ PADDR_B (zero),
+}/*-------------------------< DATA_OVRUN1 >----------------------*/,{
+ /*
+ * The target may want to transfer too much data.
+ *
+ * If phase is DATA OUT write 1 byte and count it.
+ */
+ SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_OUT)),
+ 16,
+ SCR_CHMOV_ABS (1) ^ SCR_DATA_OUT,
+ HADDR_1 (scratch),
+ SCR_JUMP,
+ PADDR_B (data_ovrun2),
+ /*
+ * If WSR is set, clear this condition, and
+ * count this byte.
+ */
+ SCR_FROM_REG (scntl2),
+ 0,
+ SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)),
+ 16,
+ SCR_REG_REG (scntl2, SCR_OR, WSR),
+ 0,
+ SCR_JUMP,
+ PADDR_B (data_ovrun2),
+ /*
+ * Finally check against DATA IN phase.
+ * Signal data overrun to the C code
+ * and jump to dispatcher if not so.
+ * Read 1 byte otherwise and count it.
+ */
+ SCR_JUMPR ^ IFTRUE (WHEN (SCR_DATA_IN)),
+ 16,
+ SCR_INT,
+ SIR_DATA_OVERRUN,
+ SCR_JUMP,
+ PADDR_A (dispatch),
+ SCR_CHMOV_ABS (1) ^ SCR_DATA_IN,
+ HADDR_1 (scratch),
+}/*-------------------------< DATA_OVRUN2 >----------------------*/,{
+ /*
+ * Count this byte.
+ * This will allow to return a negative
+ * residual to user.
+ */
+ SCR_REG_REG (scratcha, SCR_ADD, 0x01),
+ 0,
+ SCR_REG_REG (scratcha1, SCR_ADDC, 0),
+ 0,
+ SCR_REG_REG (scratcha2, SCR_ADDC, 0),
+ 0,
+ /*
+ * .. and repeat as required.
+ */
+ SCR_JUMP,
+ PADDR_B (data_ovrun1),
+}/*-------------------------< ABORT_RESEL >----------------------*/,{
+ SCR_SET (SCR_ATN),
+ 0,
+ SCR_CLR (SCR_ACK),
+ 0,
+ /*
+ * send the abort/abortag/reset message
+ * we expect an immediate disconnect
+ */
+ SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+ 0,
+ SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
+ HADDR_1 (msgout),
+ SCR_CLR (SCR_ACK|SCR_ATN),
+ 0,
+ SCR_WAIT_DISC,
+ 0,
+ SCR_INT,
+ SIR_RESEL_ABORTED,
+ SCR_JUMP,
+ PADDR_A (start),
+}/*-------------------------< RESEND_IDENT >---------------------*/,{
+ /*
+ * The target stays in MSG OUT phase after having acked
+ * Identify [+ Tag [+ Extended message ]]. Targets shall
+ * behave this way on parity error.
+ * We must send it again all the messages.
+ */
+ SCR_SET (SCR_ATN), /* Shall be asserted 2 deskew delays before the */
+ 0, /* 1rst ACK = 90 ns. Hope the chip isn't too fast */
+ SCR_JUMP,
+ PADDR_A (send_ident),
+}/*-------------------------< IDENT_BREAK >----------------------*/,{
+ SCR_CLR (SCR_ATN),
+ 0,
+ SCR_JUMP,
+ PADDR_A (select2),
+}/*-------------------------< IDENT_BREAK_ATN >------------------*/,{
+ SCR_SET (SCR_ATN),
+ 0,
+ SCR_JUMP,
+ PADDR_A (select2),
+}/*-------------------------< SDATA_IN >-------------------------*/,{
+ SCR_CHMOV_TBL ^ SCR_DATA_IN,
+ offsetof (struct sym_dsb, sense),
+ SCR_CALL,
+ PADDR_A (datai_done),
+ SCR_JUMP,
+ PADDR_B (data_ovrun),
+}/*-------------------------< RESEL_BAD_LUN >--------------------*/,{
+ /*
+ * Message is an IDENTIFY, but lun is unknown.
+ * Signal problem to C code for logging the event.
+ * Send a M_ABORT to clear all pending tasks.
+ */
+ SCR_INT,
+ SIR_RESEL_BAD_LUN,
+ SCR_JUMP,
+ PADDR_B (abort_resel),
+}/*-------------------------< BAD_I_T_L >------------------------*/,{
+ /*
+ * We donnot have a task for that I_T_L.
+ * Signal problem to C code for logging the event.
+ * Send a M_ABORT message.
+ */
+ SCR_INT,
+ SIR_RESEL_BAD_I_T_L,
+ SCR_JUMP,
+ PADDR_B (abort_resel),
+}/*-------------------------< BAD_I_T_L_Q >----------------------*/,{
+ /*
+ * We donnot have a task that matches the tag.
+ * Signal problem to C code for logging the event.
+ * Send a M_ABORTTAG message.
+ */
+ SCR_INT,
+ SIR_RESEL_BAD_I_T_L_Q,
+ SCR_JUMP,
+ PADDR_B (abort_resel),
+}/*-------------------------< BAD_STATUS >-----------------------*/,{
+ /*
+ * Anything different from INTERMEDIATE
+ * CONDITION MET should be a bad SCSI status,
+ * given that GOOD status has already been tested.
+ * Call the C code.
+ */
+ SCR_LOAD_ABS (scratcha, 4),
+ PADDR_B (startpos),
+ SCR_INT ^ IFFALSE (DATA (S_COND_MET)),
+ SIR_BAD_SCSI_STATUS,
+ SCR_RETURN,
+ 0,
+}/*-------------------------< PM_HANDLE >------------------------*/,{
+ /*
+ * Phase mismatch handling.
+ *
+ * Since we have to deal with 2 SCSI data pointers
+ * (current and saved), we need at least 2 contexts.
+ * Each context (pm0 and pm1) has a saved area, a
+ * SAVE mini-script and a DATA phase mini-script.
+ */
+ /*
+ * Get the PM handling flags.
+ */
+ SCR_FROM_REG (HF_REG),
+ 0,
+ /*
+ * If no flags (1rst PM for example), avoid
+ * all the below heavy flags testing.
+ * This makes the normal case a bit faster.
+ */
+ SCR_JUMP ^ IFTRUE (MASK (0, (HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED))),
+ PADDR_B (pm_handle1),
+ /*
+ * If we received a SAVE DP, switch to the
+ * other PM context since the savep may point
+ * to the current PM context.
+ */
+ SCR_JUMPR ^ IFFALSE (MASK (HF_DP_SAVED, HF_DP_SAVED)),
+ 8,
+ SCR_REG_REG (sfbr, SCR_XOR, HF_ACT_PM),
+ 0,
+ /*
+ * If we have been interrupt in a PM DATA mini-script,
+ * we take the return address from the corresponding
+ * saved area.
+ * This ensure the return address always points to the
+ * main DATA script for this transfer.
+ */
+ SCR_JUMP ^ IFTRUE (MASK (0, (HF_IN_PM0 | HF_IN_PM1))),
+ PADDR_B (pm_handle1),
+ SCR_JUMPR ^ IFFALSE (MASK (HF_IN_PM0, HF_IN_PM0)),
+ 16,
+ SCR_LOAD_REL (ia, 4),
+ offsetof(struct sym_ccb, phys.pm0.ret),
+ SCR_JUMP,
+ PADDR_B (pm_save),
+ SCR_LOAD_REL (ia, 4),
+ offsetof(struct sym_ccb, phys.pm1.ret),
+ SCR_JUMP,
+ PADDR_B (pm_save),
+}/*-------------------------< PM_HANDLE1 >-----------------------*/,{
+ /*
+ * Normal case.
+ * Update the return address so that it
+ * will point after the interrupted MOVE.
+ */
+ SCR_REG_REG (ia, SCR_ADD, 8),
+ 0,
+ SCR_REG_REG (ia1, SCR_ADDC, 0),
+ 0,
+}/*-------------------------< PM_SAVE >--------------------------*/,{
+ /*
+ * Clear all the flags that told us if we were
+ * interrupted in a PM DATA mini-script and/or
+ * we received a SAVE DP.
+ */
+ SCR_SFBR_REG (HF_REG, SCR_AND, (~(HF_IN_PM0|HF_IN_PM1|HF_DP_SAVED))),
+ 0,
+ /*
+ * Choose the current PM context.
+ */
+ SCR_JUMP ^ IFTRUE (MASK (HF_ACT_PM, HF_ACT_PM)),
+ PADDR_B (pm1_save),
+}/*-------------------------< PM0_SAVE >-------------------------*/,{
+ SCR_STORE_REL (ia, 4),
+ offsetof(struct sym_ccb, phys.pm0.ret),
+ /*
+ * If WSR bit is set, either UA and RBC may
+ * have to be changed whether the device wants
+ * to ignore this residue or not.
+ */
+ SCR_FROM_REG (scntl2),
+ 0,
+ SCR_CALL ^ IFTRUE (MASK (WSR, WSR)),
+ PADDR_B (pm_wsr_handle),
+ /*
+ * Save the remaining byte count, the updated
+ * address and the return address.
+ */
+ SCR_STORE_REL (rbc, 4),
+ offsetof(struct sym_ccb, phys.pm0.sg.size),
+ SCR_STORE_REL (ua, 4),
+ offsetof(struct sym_ccb, phys.pm0.sg.addr),
+ /*
+ * Set the current pointer at the PM0 DATA mini-script.
+ */
+ SCR_LOAD_ABS (temp, 4),
+ PADDR_B (pm0_data_addr),
+ SCR_JUMP,
+ PADDR_A (dispatch),
+}/*-------------------------< PM1_SAVE >-------------------------*/,{
+ SCR_STORE_REL (ia, 4),
+ offsetof(struct sym_ccb, phys.pm1.ret),
+ /*
+ * If WSR bit is set, either UA and RBC may
+ * have to be changed whether the device wants
+ * to ignore this residue or not.
+ */
+ SCR_FROM_REG (scntl2),
+ 0,
+ SCR_CALL ^ IFTRUE (MASK (WSR, WSR)),
+ PADDR_B (pm_wsr_handle),
+ /*
+ * Save the remaining byte count, the updated
+ * address and the return address.
+ */
+ SCR_STORE_REL (rbc, 4),
+ offsetof(struct sym_ccb, phys.pm1.sg.size),
+ SCR_STORE_REL (ua, 4),
+ offsetof(struct sym_ccb, phys.pm1.sg.addr),
+ /*
+ * Set the current pointer at the PM1 DATA mini-script.
+ */
+ SCR_LOAD_ABS (temp, 4),
+ PADDR_B (pm1_data_addr),
+ SCR_JUMP,
+ PADDR_A (dispatch),
+}/*-------------------------< PM_WSR_HANDLE >--------------------*/,{
+ /*
+ * Phase mismatch handling from SCRIPT with WSR set.
+ * Such a condition can occur if the chip wants to
+ * execute a CHMOV(size > 1) when the WSR bit is
+ * set and the target changes PHASE.
+ *
+ * We must move the residual byte to memory.
+ *
+ * UA contains bit 0..31 of the address to
+ * move the residual byte.
+ * Move it to the table indirect.
+ */
+ SCR_STORE_REL (ua, 4),
+ offsetof (struct sym_ccb, phys.wresid.addr),
+ /*
+ * Increment UA (move address to next position).
+ */
+ SCR_REG_REG (ua, SCR_ADD, 1),
+ 0,
+ SCR_REG_REG (ua1, SCR_ADDC, 0),
+ 0,
+ SCR_REG_REG (ua2, SCR_ADDC, 0),
+ 0,
+ SCR_REG_REG (ua3, SCR_ADDC, 0),
+ 0,
+ /*
+ * Compute SCRATCHA as:
+ * - size to transfer = 1 byte.
+ * - bit 24..31 = high address bit [32...39].
+ */
+ SCR_LOAD_ABS (scratcha, 4),
+ PADDR_B (zero),
+ SCR_REG_REG (scratcha, SCR_OR, 1),
+ 0,
+ SCR_FROM_REG (rbc3),
+ 0,
+ SCR_TO_REG (scratcha3),
+ 0,
+ /*
+ * Move this value to the table indirect.
+ */
+ SCR_STORE_REL (scratcha, 4),
+ offsetof (struct sym_ccb, phys.wresid.size),
+ /*
+ * Wait for a valid phase.
+ * While testing with bogus QUANTUM drives, the C1010
+ * sometimes raised a spurious phase mismatch with
+ * WSR and the CHMOV(1) triggered another PM.
+ * Waiting explicitely for the PHASE seemed to avoid
+ * the nested phase mismatch. Btw, this didn't happen
+ * using my IBM drives.
+ */
+ SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_IN)),
+ 0,
+ /*
+ * Perform the move of the residual byte.
+ */
+ SCR_CHMOV_TBL ^ SCR_DATA_IN,
+ offsetof (struct sym_ccb, phys.wresid),
+ /*
+ * We can now handle the phase mismatch with UA fixed.
+ * RBC[0..23]=0 is a special case that does not require
+ * a PM context. The C code also checks against this.
+ */
+ SCR_FROM_REG (rbc),
+ 0,
+ SCR_RETURN ^ IFFALSE (DATA (0)),
+ 0,
+ SCR_FROM_REG (rbc1),
+ 0,
+ SCR_RETURN ^ IFFALSE (DATA (0)),
+ 0,
+ SCR_FROM_REG (rbc2),
+ 0,
+ SCR_RETURN ^ IFFALSE (DATA (0)),
+ 0,
+ /*
+ * RBC[0..23]=0.
+ * Not only we donnot need a PM context, but this would
+ * lead to a bogus CHMOV(0). This condition means that
+ * the residual was the last byte to move from this CHMOV.
+ * So, we just have to move the current data script pointer
+ * (i.e. TEMP) to the SCRIPTS address following the
+ * interrupted CHMOV and jump to dispatcher.
+ */
+ SCR_STORE_ABS (ia, 4),
+ PADDR_B (scratch),
+ SCR_LOAD_ABS (temp, 4),
+ PADDR_B (scratch),
+ SCR_JUMP,
+ PADDR_A (dispatch),
+}/*-------------------------< WSR_MA_HELPER >--------------------*/,{
+ /*
+ * Helper for the C code when WSR bit is set.
+ * Perform the move of the residual byte.
+ */
+ SCR_CHMOV_TBL ^ SCR_DATA_IN,
+ offsetof (struct sym_ccb, phys.wresid),
+ SCR_JUMP,
+ PADDR_A (dispatch),
+}/*-------------------------< ZERO >-----------------------------*/,{
+ SCR_DATA_ZERO,
+}/*-------------------------< SCRATCH >--------------------------*/,{
+ SCR_DATA_ZERO,
+}/*-------------------------< PM0_DATA_ADDR >--------------------*/,{
+ SCR_DATA_ZERO,
+}/*-------------------------< PM1_DATA_ADDR >--------------------*/,{
+ SCR_DATA_ZERO,
+}/*-------------------------< SAVED_DSA >------------------------*/,{
+ SCR_DATA_ZERO,
+}/*-------------------------< SAVED_DRS >------------------------*/,{
+ SCR_DATA_ZERO,
+}/*-------------------------< DONE_POS >-------------------------*/,{
+ SCR_DATA_ZERO,
+}/*-------------------------< STARTPOS >-------------------------*/,{
+ SCR_DATA_ZERO,
+}/*-------------------------< TARGTBL >--------------------------*/,{
+ SCR_DATA_ZERO,
+
+}/*-------------------------< SNOOPTEST >------------------------*/,{
+ /*
+ * Read the variable from memory.
+ */
+ SCR_LOAD_REL (scratcha, 4),
+ offsetof(struct sym_hcb, cache),
+ /*
+ * Write the variable to memory.
+ */
+ SCR_STORE_REL (temp, 4),
+ offsetof(struct sym_hcb, cache),
+ /*
+ * Read back the variable from memory.
+ */
+ SCR_LOAD_REL (temp, 4),
+ offsetof(struct sym_hcb, cache),
+}/*-------------------------< SNOOPEND >-------------------------*/,{
+ /*
+ * And stop.
+ */
+ SCR_INT,
+ 99,
+}/*-------------------------<>-----------------------------------*/
+};
diff --git a/sys/dev/sym/sym_hipd.c b/sys/dev/sym/sym_hipd.c
index e2fb26b..28140a5 100644
--- a/sys/dev/sym/sym_hipd.c
+++ b/sys/dev/sym/sym_hipd.c
@@ -5,10 +5,9 @@
* Copyright (C) 1999-2000 Gerard Roudier <groudier@club-internet.fr>
*
* This driver also supports the following Symbios/LSI PCI-SCSI chips:
- * 53C810A, 53C825A, 53C860, 53C875, 53C876, 53C885, 53C895.
+ * 53C810A, 53C825A, 53C860, 53C875, 53C876, 53C885, 53C895,
+ * 53C810, 53C815, 53C825 and the 53C1510D is 53C8XX mode.
*
- * but does not support earlier chips as the following ones:
- * 53C810, 53C815, 53C825.
*
* This driver for FreeBSD-CAM is derived from the Linux sym53c8xx driver.
* Copyright (C) 1998-1999 Gerard Roudier
@@ -58,7 +57,7 @@
/* $FreeBSD$ */
-#define SYM_DRIVER_NAME "sym-1.4.3-20000415"
+#define SYM_DRIVER_NAME "sym-1.5.1-20000429"
#include <pci.h>
#include <stddef.h> /* For offsetof */
@@ -128,10 +127,12 @@ typedef u_int32_t u32;
#include "opt_sym.h"
#include <dev/sym/sym_conf.h>
#include <dev/sym/sym_defs.h>
+#include <dev/sym/sym_fw.h>
#else
#include "ncr.h" /* To know if the ncr has been configured */
#include <pci/sym_conf.h>
#include <pci/sym_defs.h>
+#include <pci/sym_fw.h>
#endif
/*
@@ -1129,8 +1130,6 @@ typedef struct sym_tcb *tcb_p;
typedef struct sym_lcb *lcb_p;
typedef struct sym_ccb *ccb_p;
typedef struct sym_hcb *hcb_p;
-typedef struct sym_scra *scripta_p;
-typedef struct sym_scrb *scriptb_p;
/*
* Gather negotiable parameters value
@@ -1152,19 +1151,49 @@ struct sym_tinfo {
#define BUS_16_BIT MSG_EXT_WDTR_BUS_16_BIT
/*
- * Target Control Block
+ * Global TCB HEADER.
+ *
+ * Due to lack of indirect addressing on earlier NCR chips,
+ * this substructure is copied from the TCB to a global
+ * address after selection.
+ * For SYMBIOS chips that support LOAD/STORE this copy is
+ * not needed and thus not performed.
*/
-struct sym_tcb {
+struct sym_tcbh {
/*
- * LUN table used by the SCRIPTS processor.
- * An array of bus addresses is used on reselection.
+ * Scripts bus addresses of LUN table accessed from scripts.
* LUN #0 is a special case, since multi-lun devices are rare,
* and we we want to speed-up the general case and not waste
* resources.
*/
- u32 *luntbl; /* LCBs bus address table */
u32 luntbl_sa; /* bus address of this table */
u32 lun0_sa; /* bus address of LCB #0 */
+ /*
+ * Actual SYNC/WIDE IO registers value for this target.
+ * 'sval', 'wval' and 'uval' are read from SCRIPTS and
+ * so have alignment constraints.
+ */
+/*0*/ u_char uval; /* -> SCNTL4 register */
+/*1*/ u_char sval; /* -> SXFER io register */
+/*2*/ u_char filler1;
+/*3*/ u_char wval; /* -> SCNTL3 io register */
+};
+
+/*
+ * Target Control Block
+ */
+struct sym_tcb {
+ /*
+ * TCB header.
+ * Assumed at offset 0.
+ */
+/*0*/ struct sym_tcbh head;
+
+ /*
+ * LUN table used by the SCRIPTS processor.
+ * An array of bus addresses is used on reselection.
+ */
+ u32 *luntbl; /* LCBs bus address table */
/*
* LUN table used by the C code.
@@ -1188,16 +1217,6 @@ struct sym_tcb {
u32 busy0_map[(SYM_CONF_MAX_LUN+31)/32];
/*
- * Actual SYNC/WIDE IO registers value for this target.
- * 'sval', 'wval' and 'uval' are read from SCRIPTS and
- * so have alignment constraints.
- */
-/*0*/ u_char uval; /* -> SCNTL4 register */
-/*1*/ u_char sval; /* -> SXFER io register */
-/*2*/ u_char filler1;
-/*3*/ u_char wval; /* -> SCNTL3 io register */
-
- /*
* Transfer capabilities (SIP)
*/
struct sym_tinfo tinfo;
@@ -1222,14 +1241,20 @@ struct sym_tcb {
};
/*
- * Logical Unit Control Block
+ * Global LCB HEADER.
+ *
+ * Due to lack of indirect addressing on earlier NCR chips,
+ * this substructure is copied from the LCB to a global
+ * address after selection.
+ * For SYMBIOS chips that support LOAD/STORE this copy is
+ * not needed and thus not performed.
*/
-struct sym_lcb {
+struct sym_lcbh {
/*
* SCRIPTS address jumped by SCRIPTS on reselection.
* For not probed logical units, this address points to
* SCRIPTS that deal with bad LU handling (must be at
- * offset zero for that reason).
+ * offset zero of the LCB for that reason).
*/
/*0*/ u32 resel_sa;
@@ -1240,11 +1265,27 @@ struct sym_lcb {
u32 itl_task_sa;
/*
+ * Task table bus address (read from SCRIPTS).
+ */
+ u32 itlq_tbl_sa;
+};
+
+/*
+ * Logical Unit Control Block
+ */
+struct sym_lcb {
+ /*
+ * TCB header.
+ * Assumed at offset 0.
+ */
+/*0*/ struct sym_lcbh head;
+
+ /*
* Task table read from SCRIPTS that contains pointers to
- * ITLQ nexuses (bus addresses read from SCRIPTS).
+ * ITLQ nexuses. The bus address read from SCRIPTS is
+ * inside the header.
*/
u32 *itlq_tbl; /* Kernel virtual address */
- u32 itlq_tbl_sa; /* Bus address used by SCRIPTS */
/*
* Busy CCBs management.
@@ -1329,10 +1370,10 @@ struct sym_pmc {
/*
* Last four bytes (host)
*/
-#define actualquirks phys.status[0]
-#define host_status phys.status[1]
-#define ssss_status phys.status[2]
-#define host_flags phys.status[3]
+#define actualquirks phys.head.status[0]
+#define host_status phys.head.status[1]
+#define ssss_status phys.head.status[2]
+#define host_flags phys.head.status[3]
/*
* Host flags
@@ -1349,13 +1390,17 @@ struct sym_pmc {
#endif
/*
- * Data Structure Block
+ * Global CCB HEADER.
*
- * During execution of a ccb by the script processor, the
- * DSA (data structure address) register points to this
- * substructure of the ccb.
+ * Due to lack of indirect addressing on earlier NCR chips,
+ * this substructure is copied from the ccb to a global
+ * address after selection (or reselection) and copied back
+ * before disconnect.
+ * For SYMBIOS chips that support LOAD/STORE this copy is
+ * not needed and thus not performed.
*/
-struct dsb {
+
+struct sym_ccbh {
/*
* Start and restart SCRIPTS addresses (must be at 0).
*/
@@ -1364,17 +1409,41 @@ struct dsb {
/*
* SCRIPTS jump address that deal with data pointers.
* 'savep' points to the position in the script responsible
- * for the actual transfer of data.
+ * for the actual transfer of data.
* It's written on reception of a SAVE_DATA_POINTER message.
*/
u32 savep; /* Jump address to saved data pointer */
u32 lastp; /* SCRIPTS address at end of data */
- u32 goalp; /* Not used for now */
+ u32 goalp; /* Not accessed for now from SCRIPTS */
/*
* Status fields.
*/
u8 status[4];
+};
+
+/*
+ * Data Structure Block
+ *
+ * During execution of a ccb by the script processor, the
+ * DSA (data structure address) register points to this
+ * substructure of the ccb.
+ */
+struct sym_dsb {
+ /*
+ * CCB header.
+ * Also Assumed at offset 0 of the sym_ccb structure.
+ */
+/*0*/ struct sym_ccbh head;
+
+ /*
+ * Phase mismatch contexts.
+ * We need two to handle correctly the SAVED DATA POINTER.
+ * MUST BOTH BE AT OFFSET < 256, due to using 8 bit arithmetic
+ * for address calculation from SCRIPTS.
+ */
+ struct sym_pmc pm0;
+ struct sym_pmc pm1;
/*
* Table data for Script
@@ -1386,13 +1455,6 @@ struct dsb {
struct sym_tblmove sense;
struct sym_tblmove wresid;
struct sym_tblmove data [SYM_CONF_MAX_SG];
-
- /*
- * Phase mismatch contexts.
- * We need two to handle correctly the SAVED DATA POINTER.
- */
- struct sym_pmc pm0;
- struct sym_pmc pm1;
};
/*
@@ -1404,7 +1466,7 @@ struct sym_ccb {
* register when it is executed by the script processor.
* It must be the first entry.
*/
- struct dsb phys;
+ struct sym_dsb phys;
/*
* Pointer to CAM ccb and related stuff.
@@ -1478,6 +1540,17 @@ struct sym_ccb {
*/
struct sym_hcb {
/*
+ * Global headers.
+ * Due to poorness of addressing capabilities, earlier
+ * chips (810, 815, 825) copy part of the data structures
+ * (CCB, TCB and LCB) in fixed areas.
+ */
+#ifdef SYM_CONF_GENERIC_SUPPORT
+ struct sym_ccbh ccb_head;
+ struct sym_tcbh tcb_head;
+ struct sym_lcbh lcb_head;
+#endif
+ /*
* Idle task and invalid task actions and
* their bus addresses.
*/
@@ -1541,6 +1614,7 @@ struct sym_hcb {
* on reselection.
*/
u32 *targtbl;
+ u32 targtbl_ba;
/*
* CAM SIM information for this instance.
@@ -1607,11 +1681,23 @@ struct sym_hcb {
* 'scripth' stays in main memory for all chips except the
* 53C895A, 53C896 and 53C1010 that provide 8K on-chip RAM.
*/
- struct sym_scra *scripta0; /* Copies of script and scripth */
- struct sym_scrb *scriptb0; /* relocated for this host. */
+ u_char *scripta0; /* Copies of script and scripth */
+ u_char *scriptb0; /* Copies of script and scripth */
vm_offset_t scripta_ba; /* Actual script and scripth */
vm_offset_t scriptb_ba; /* bus addresses. */
vm_offset_t scriptb0_ba;
+ u_short scripta_sz; /* Actual size of script A */
+ u_short scriptb_sz; /* Actual size of script B */
+
+ /*
+ * Bus addresses, setup and patch methods for
+ * the selected firmware.
+ */
+ struct sym_fwa_ba fwa_bas; /* Useful SCRIPTA bus addresses */
+ struct sym_fwb_ba fwb_bas; /* Useful SCRIPTB bus addresses */
+ void (*fw_setup)(hcb_p np, struct sym_fw *fw);
+ void (*fw_patch)(hcb_p np);
+ char *fw_name;
/*
* General controller parameters and configuration.
@@ -1649,6 +1735,7 @@ struct sym_hcb {
u_short dqueueget; /* Next position to scan */
volatile /* Prevent code optimizations */
u32 *dqueue; /* Completion (done) queue */
+ u32 dqueue_ba; /* Done queue BUS address */
/*
* Miscellaneous buffers accessed by the scripts-processor.
@@ -1717,1987 +1804,307 @@ struct sym_hcb {
u_char istat_sem; /* Tells the chip to stop (SEM) */
};
-#define HCB_BA(np, lbl) (np->hcb_ba + offsetof(struct sym_hcb, lbl))
-#define SCRIPTA_BA(np,lbl) (np->scripta_ba + offsetof(struct sym_scra, lbl))
-#define SCRIPTB_BA(np,lbl) (np->scriptb_ba + offsetof(struct sym_scrb,lbl))
-#define SCRIPTB0_BA(np,lbl) (np->scriptb0_ba + offsetof(struct sym_scrb,lbl))
+#define HCB_BA(np, lbl) (np->hcb_ba + offsetof(struct sym_hcb, lbl))
/*
- * Scripts for SYMBIOS-Processor
- *
- * Use sym_fill_scripts() to create the variable parts.
- * Use sym_bind_script() to make a copy and bind to
- * physical bus addresses.
- * We have to know the offsets of all labels before we reach
- * them (for forward jumps). Therefore we declare a struct
- * here. If you make changes inside the script,
- *
- * DONT FORGET TO CHANGE THE LENGTHS HERE!
+ * Return the name of the controller.
*/
+static __inline char *sym_name(hcb_p np)
+{
+ return np->inst_name;
+}
-/*
- * Script fragments which are loaded into the on-chip RAM
- * of 825A, 875, 876, 895, 895A, 896 and 1010 chips.
- * Must not exceed 4K bytes.
- */
-struct sym_scra {
- u32 start [ 14];
- u32 getjob_begin [ 4];
- u32 getjob_end [ 4];
- u32 select [ 8];
- u32 wf_sel_done [ 2];
- u32 send_ident [ 2];
-#ifdef SYM_CONF_IARB_SUPPORT
- u32 select2 [ 8];
-#else
- u32 select2 [ 2];
-#endif
- u32 command [ 2];
- u32 dispatch [ 28];
- u32 sel_no_cmd [ 10];
- u32 init [ 6];
- u32 clrack [ 4];
- u32 disp_status [ 4];
- u32 datai_done [ 26];
- u32 datao_done [ 12];
- u32 datai_phase [ 2];
- u32 datao_phase [ 2];
- u32 msg_in [ 2];
- u32 msg_in2 [ 10];
-#ifdef SYM_CONF_IARB_SUPPORT
- u32 status [ 14];
-#else
- u32 status [ 10];
-#endif
- u32 complete [ 8];
- u32 complete2 [ 12];
- u32 complete_error [ 4];
- u32 done [ 14];
- u32 done_end [ 2];
- u32 save_dp [ 8];
- u32 restore_dp [ 4];
- u32 disconnect [ 20];
-#ifdef SYM_CONF_IARB_SUPPORT
- u32 idle [ 4];
-#else
- u32 idle [ 2];
-#endif
-#ifdef SYM_CONF_IARB_SUPPORT
- u32 ungetjob [ 6];
-#else
- u32 ungetjob [ 4];
-#endif
- u32 reselect [ 4];
- u32 reselected [ 20];
- u32 resel_scntl4 [ 28];
-#if SYM_CONF_MAX_TASK*4 > 512
- u32 resel_tag [ 26];
-#elif SYM_CONF_MAX_TASK*4 > 256
- u32 resel_tag [ 20];
-#else
- u32 resel_tag [ 16];
-#endif
- u32 resel_dsa [ 2];
- u32 resel_dsa1 [ 6];
- u32 resel_no_tag [ 6];
- u32 data_in [SYM_CONF_MAX_SG * 2];
- u32 data_in2 [ 4];
- u32 data_out [SYM_CONF_MAX_SG * 2];
- u32 data_out2 [ 4];
- u32 pm0_data [ 12];
- u32 pm0_data_out [ 6];
- u32 pm0_data_end [ 6];
- u32 pm1_data [ 12];
- u32 pm1_data_out [ 6];
- u32 pm1_data_end [ 6];
-};
+/*--------------------------------------------------------------------------*/
+/*------------------------------ FIRMWARES ---------------------------------*/
+/*--------------------------------------------------------------------------*/
/*
- * Script fragments which stay in main memory for all chips
- * except for chips that support 8K on-chip RAM.
- */
-struct sym_scrb {
- u32 start64 [ 2];
- u32 no_data [ 2];
- u32 sel_for_abort [ 18];
- u32 sel_for_abort_1 [ 2];
- u32 msg_in_etc [ 14];
- u32 msg_received [ 4];
- u32 msg_weird_seen [ 4];
- u32 msg_extended [ 20];
- u32 msg_bad [ 6];
- u32 msg_weird [ 4];
- u32 msg_weird1 [ 8];
-
- u32 wdtr_resp [ 6];
- u32 send_wdtr [ 4];
- u32 sdtr_resp [ 6];
- u32 send_sdtr [ 4];
- u32 ppr_resp [ 6];
- u32 send_ppr [ 4];
- u32 nego_bad_phase [ 4];
- u32 msg_out [ 4];
- u32 msg_out_done [ 4];
- u32 data_ovrun [ 2];
- u32 data_ovrun1 [ 22];
- u32 data_ovrun2 [ 8];
- u32 abort_resel [ 16];
- u32 resend_ident [ 4];
- u32 ident_break [ 4];
- u32 ident_break_atn [ 4];
- u32 sdata_in [ 6];
- u32 resel_bad_lun [ 4];
- u32 bad_i_t_l [ 4];
- u32 bad_i_t_l_q [ 4];
- u32 bad_status [ 6];
- u32 pm_handle [ 20];
- u32 pm_handle1 [ 4];
- u32 pm_save [ 4];
- u32 pm0_save [ 14];
- u32 pm1_save [ 14];
-
- /* WSR handling */
- u32 pm_wsr_handle [ 42];
- u32 wsr_ma_helper [ 4];
-
- /* Data area */
- u32 zero [ 1];
- u32 scratch [ 1];
- u32 pm0_data_addr [ 1];
- u32 pm1_data_addr [ 1];
- u32 saved_dsa [ 1];
- u32 saved_drs [ 1];
- u32 done_pos [ 1];
- u32 startpos [ 1];
- u32 targtbl [ 1];
- /* End of data area */
-
- u32 snooptest [ 6];
- u32 snoopend [ 2];
-};
+ * This stuff will be moved to a separate source file when
+ * the driver will be broken into several source modules.
+ */
/*
- * Function prototypes.
+ * Macros used for all firmwares.
*/
-static void sym_fill_scripts (scripta_p scra, scriptb_p scrb);
-static void sym_bind_script (hcb_p np, u32 *src, u32 *dst, int len);
-static void sym_save_initial_setting (hcb_p np);
-static int sym_prepare_setting (hcb_p np, struct sym_nvram *nvram);
-static int sym_prepare_nego (hcb_p np, ccb_p cp, int nego, u_char *msgptr);
-static void sym_put_start_queue (hcb_p np, ccb_p cp);
-static void sym_chip_reset (hcb_p np);
-static void sym_soft_reset (hcb_p np);
-static void sym_start_reset (hcb_p np);
-static int sym_reset_scsi_bus (hcb_p np, int enab_int);
-static int sym_wakeup_done (hcb_p np);
-static void sym_flush_busy_queue (hcb_p np, int cam_status);
-static void sym_flush_comp_queue (hcb_p np, int cam_status);
-static void sym_init (hcb_p np, int reason);
-static int sym_getsync(hcb_p np, u_char dt, u_char sfac, u_char *divp,
- u_char *fakp);
-static void sym_setsync (hcb_p np, ccb_p cp, u_char ofs, u_char per,
- u_char div, u_char fak);
-static void sym_setwide (hcb_p np, ccb_p cp, u_char wide);
-static void sym_setpprot(hcb_p np, ccb_p cp, u_char dt, u_char ofs,
- u_char per, u_char wide, u_char div, u_char fak);
-static void sym_settrans(hcb_p np, ccb_p cp, u_char dt, u_char ofs,
- u_char per, u_char wide, u_char div, u_char fak);
-static void sym_log_hard_error (hcb_p np, u_short sist, u_char dstat);
-static void sym_intr (void *arg);
-static void sym_poll (struct cam_sim *sim);
-static void sym_recover_scsi_int (hcb_p np, u_char hsts);
-static void sym_int_sto (hcb_p np);
-static void sym_int_udc (hcb_p np);
-static void sym_int_sbmc (hcb_p np);
-static void sym_int_par (hcb_p np, u_short sist);
-static void sym_int_ma (hcb_p np);
-static int sym_dequeue_from_squeue(hcb_p np, int i, int target, int lun,
- int task);
-static void sym_sir_bad_scsi_status (hcb_p np, int num, ccb_p cp);
-static int sym_clear_tasks (hcb_p np, int status, int targ, int lun, int task);
-static void sym_sir_task_recovery (hcb_p np, int num);
-static int sym_evaluate_dp (hcb_p np, ccb_p cp, u32 scr, int *ofs);
-static void sym_modify_dp (hcb_p np, tcb_p tp, ccb_p cp, int ofs);
-static int sym_compute_residual (hcb_p np, ccb_p cp);
-static int sym_show_msg (u_char * msg);
-static void sym_print_msg (ccb_p cp, char *label, u_char *msg);
-static void sym_sync_nego (hcb_p np, tcb_p tp, ccb_p cp);
-static void sym_ppr_nego (hcb_p np, tcb_p tp, ccb_p cp);
-static void sym_wide_nego (hcb_p np, tcb_p tp, ccb_p cp);
-static void sym_nego_default (hcb_p np, tcb_p tp, ccb_p cp);
-static void sym_nego_rejected (hcb_p np, tcb_p tp, ccb_p cp);
-static void sym_int_sir (hcb_p np);
-static void sym_free_ccb (hcb_p np, ccb_p cp);
-static ccb_p sym_get_ccb (hcb_p np, u_char tn, u_char ln, u_char tag_order);
-static ccb_p sym_alloc_ccb (hcb_p np);
-static ccb_p sym_ccb_from_dsa (hcb_p np, u_long dsa);
-static lcb_p sym_alloc_lcb (hcb_p np, u_char tn, u_char ln);
-static void sym_alloc_lcb_tags (hcb_p np, u_char tn, u_char ln);
-static int sym_snooptest (hcb_p np);
-static void sym_selectclock(hcb_p np, u_char scntl3);
-static void sym_getclock (hcb_p np, int mult);
-static int sym_getpciclock (hcb_p np);
-static void sym_complete_ok (hcb_p np, ccb_p cp);
-static void sym_complete_error (hcb_p np, ccb_p cp);
-static void sym_timeout (void *arg);
-static int sym_abort_scsiio (hcb_p np, union ccb *ccb, int timed_out);
-static void sym_reset_dev (hcb_p np, union ccb *ccb);
-static void sym_action (struct cam_sim *sim, union ccb *ccb);
-static void sym_action1 (struct cam_sim *sim, union ccb *ccb);
-static int sym_setup_cdb (hcb_p np, struct ccb_scsiio *csio, ccb_p cp);
-static void sym_setup_data_and_start (hcb_p np, struct ccb_scsiio *csio,
- ccb_p cp);
-#ifdef FreeBSD_Bus_Dma_Abstraction
-static int sym_fast_scatter_sg_physical(hcb_p np, ccb_p cp,
- bus_dma_segment_t *psegs, int nsegs);
-#else
-static int sym_scatter_virtual (hcb_p np, ccb_p cp, vm_offset_t vaddr,
- vm_size_t len);
-static int sym_scatter_sg_virtual (hcb_p np, ccb_p cp,
- bus_dma_segment_t *psegs, int nsegs);
-static int sym_scatter_physical (hcb_p np, ccb_p cp, vm_offset_t paddr,
- vm_size_t len);
-#endif
-static int sym_scatter_sg_physical (hcb_p np, ccb_p cp,
- bus_dma_segment_t *psegs, int nsegs);
-static void sym_action2 (struct cam_sim *sim, union ccb *ccb);
-static void sym_update_trans (hcb_p np, tcb_p tp, struct sym_trans *tip,
- struct ccb_trans_settings *cts);
-static void sym_update_dflags(hcb_p np, u_char *flags,
- struct ccb_trans_settings *cts);
+#define SYM_GEN_A(s, label) ((short) offsetof(s, label)),
+#define SYM_GEN_B(s, label) ((short) offsetof(s, label)),
+#define PADDR_A(label) SYM_GEN_PADDR_A(struct SYM_FWA_SCR, label)
+#define PADDR_B(label) SYM_GEN_PADDR_B(struct SYM_FWB_SCR, label)
-#ifdef FreeBSD_Bus_Io_Abstraction
-static struct sym_pci_chip *sym_find_pci_chip (device_t dev);
-static int sym_pci_probe (device_t dev);
-static int sym_pci_attach (device_t dev);
-#else
-static struct sym_pci_chip *sym_find_pci_chip (pcici_t tag);
-static const char *sym_pci_probe (pcici_t tag, pcidi_t type);
-static void sym_pci_attach (pcici_t tag, int unit);
-static int sym_pci_attach2 (pcici_t tag, int unit);
-#endif
-
-static void sym_pci_free (hcb_p np);
-static int sym_cam_attach (hcb_p np);
-static void sym_cam_free (hcb_p np);
-
-static void sym_nvram_setup_host (hcb_p np, struct sym_nvram *nvram);
-static void sym_nvram_setup_target (hcb_p np, int targ, struct sym_nvram *nvp);
-static int sym_read_nvram (hcb_p np, struct sym_nvram *nvp);
+#ifdef SYM_CONF_GENERIC_SUPPORT
/*
- * Return the name of the controller.
+ * Allocate firmware #1 script area.
*/
-static __inline char *sym_name(hcb_p np)
-{
- return np->inst_name;
-}
+#define SYM_FWA_SCR sym_fw1a_scr
+#define SYM_FWB_SCR sym_fw1b_scr
+#include <dev/sym/sym_fw1.h>
+struct sym_fwa_ofs sym_fw1a_ofs = {
+ SYM_GEN_FW_A(struct SYM_FWA_SCR)
+};
+struct sym_fwb_ofs sym_fw1b_ofs = {
+ SYM_GEN_FW_B(struct SYM_FWB_SCR)
+};
+#undef SYM_FWA_SCR
+#undef SYM_FWB_SCR
+#endif /* SYM_CONF_GENERIC_SUPPORT */
/*
- * Scripts for SYMBIOS-Processor
- *
- * Use sym_bind_script for binding to physical addresses.
- *
- * HADDR_1 generates a reference to a field of the controller data.
- * PADDR_A generates a reference to another part of script A.
- * PADDR_B generates a reference to another part of script B.
- * RADDR_1 generates a reference to a script processor register.
- * RADDR_2 generates a reference to a script processor register
- * with offset.
- *
+ * Allocate firmware #2 script area.
*/
-#define RELOC_SOFTC 0x40000000
-#define RELOC_LABELA 0x50000000
-#define RELOC_REGISTER 0x60000000
-#define RELOC_LABELB 0x80000000
-#define RELOC_MASK 0xf0000000
+#define SYM_FWA_SCR sym_fw2a_scr
+#define SYM_FWB_SCR sym_fw2b_scr
+#include <dev/sym/sym_fw2.h>
+struct sym_fwa_ofs sym_fw2a_ofs = {
+ SYM_GEN_FW_A(struct SYM_FWA_SCR)
+};
+struct sym_fwb_ofs sym_fw2b_ofs = {
+ SYM_GEN_FW_B(struct SYM_FWB_SCR)
+ SYM_GEN_B(struct SYM_FWB_SCR, start64)
+ SYM_GEN_B(struct SYM_FWB_SCR, pm_handle)
+};
+#undef SYM_FWA_SCR
+#undef SYM_FWB_SCR
-#define HADDR_1(label) (RELOC_SOFTC | offsetof(struct sym_hcb, label))
-#define PADDR_A(label) (RELOC_LABELA | offsetof(struct sym_scra, label))
-#define PADDR_B(label) (RELOC_LABELB | offsetof(struct sym_scrb, label))
-#define RADDR_1(label) (RELOC_REGISTER | REG(label))
-#define RADDR_2(label,ofs) (RELOC_REGISTER | ((REG(label))+(ofs)))
+#undef SYM_GEN_A
+#undef SYM_GEN_B
+#undef PADDR_A
+#undef PADDR_B
-#define SCR_DATA_ZERO 0xf00ff00f
+#ifdef SYM_CONF_GENERIC_SUPPORT
+/*
+ * Patch routine for firmware #1.
+ */
+static void
+sym_fw1_patch(hcb_p np)
+{
+ struct sym_fw1a_scr *scripta0;
+ struct sym_fw1b_scr *scriptb0;
+
+ scripta0 = (struct sym_fw1a_scr *) np->scripta0;
+ scriptb0 = (struct sym_fw1b_scr *) np->scriptb0;
-static struct sym_scra scripta0 = {
-/*--------------------------< START >----------------------------*/ {
- /*
- * Switch the LED on.
- * Will be patched with a NO_OP if LED
- * not needed or not desired.
- */
- SCR_REG_REG (gpreg, SCR_AND, 0xfe),
- 0,
- /*
- * Clear SIGP.
- */
- SCR_FROM_REG (ctest2),
- 0,
- /*
- * Stop here if the C code wants to perform
- * some error recovery procedure manually.
- * (Indicate this by setting SEM in ISTAT)
- */
- SCR_FROM_REG (istat),
- 0,
- /*
- * Report to the C code the next position in
- * the start queue the SCRIPTS will schedule.
- * The C code must not change SCRATCHA.
- */
- SCR_LOAD_ABS (scratcha, 4),
- PADDR_B (startpos),
- SCR_INT ^ IFTRUE (MASK (SEM, SEM)),
- SIR_SCRIPT_STOPPED,
- /*
- * Start the next job.
- *
- * @DSA = start point for this job.
- * SCRATCHA = address of this job in the start queue.
- *
- * We will restore startpos with SCRATCHA if we fails the
- * arbitration or if it is the idle job.
- *
- * The below GETJOB_BEGIN to GETJOB_END section of SCRIPTS
- * is a critical path. If it is partially executed, it then
- * may happen that the job address is not yet in the DSA
- * and the the next queue position points to the next JOB.
- */
- SCR_LOAD_ABS (dsa, 4),
- PADDR_B (startpos),
- SCR_LOAD_REL (temp, 4),
- 4,
-}/*-------------------------< GETJOB_BEGIN >---------------------*/,{
- SCR_STORE_ABS (temp, 4),
- PADDR_B (startpos),
- SCR_LOAD_REL (dsa, 4),
- 0,
-}/*-------------------------< GETJOB_END >-----------------------*/,{
- SCR_LOAD_REL (temp, 4),
- 0,
- SCR_RETURN,
- 0,
-}/*-------------------------< SELECT >---------------------------*/,{
- /*
- * DSA contains the address of a scheduled
- * data structure.
- *
- * SCRATCHA contains the address of the start queue
- * entry which points to the next job.
- *
- * Set Initiator mode.
- *
- * (Target mode is left as an exercise for the reader)
- */
- SCR_CLR (SCR_TRG),
- 0,
- /*
- * And try to select this target.
- */
- SCR_SEL_TBL_ATN ^ offsetof (struct dsb, select),
- PADDR_A (ungetjob),
- /*
- * Now there are 4 possibilities:
- *
- * (1) The chip looses arbitration.
- * This is ok, because it will try again,
- * when the bus becomes idle.
- * (But beware of the timeout function!)
- *
- * (2) The chip is reselected.
- * Then the script processor takes the jump
- * to the RESELECT label.
- *
- * (3) The chip wins arbitration.
- * Then it will execute SCRIPTS instruction until
- * the next instruction that checks SCSI phase.
- * Then will stop and wait for selection to be
- * complete or selection time-out to occur.
- *
- * After having won arbitration, the SCRIPTS
- * processor is able to execute instructions while
- * the SCSI core is performing SCSI selection.
- */
- /*
- * load the savep (saved data pointer) into
- * the actual data pointer.
- */
- SCR_LOAD_REL (temp, 4),
- offsetof (struct sym_ccb, phys.savep),
- /*
- * Initialize the status registers
- */
- SCR_LOAD_REL (scr0, 4),
- offsetof (struct sym_ccb, phys.status),
-}/*-------------------------< WF_SEL_DONE >----------------------*/,{
- SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)),
- SIR_SEL_ATN_NO_MSG_OUT,
-}/*-------------------------< SEND_IDENT >-----------------------*/,{
- /*
- * Selection complete.
- * Send the IDENTIFY and possibly the TAG message
- * and negotiation message if present.
- */
- SCR_MOVE_TBL ^ SCR_MSG_OUT,
- offsetof (struct dsb, smsg),
-}/*-------------------------< SELECT2 >--------------------------*/,{
-#ifdef SYM_CONF_IARB_SUPPORT
- /*
- * Set IMMEDIATE ARBITRATION if we have been given
- * a hint to do so. (Some job to do after this one).
- */
- SCR_FROM_REG (HF_REG),
- 0,
- SCR_JUMPR ^ IFFALSE (MASK (HF_HINT_IARB, HF_HINT_IARB)),
- 8,
- SCR_REG_REG (scntl1, SCR_OR, IARB),
- 0,
-#endif
- /*
- * Anticipate the COMMAND phase.
- * This is the PHASE we expect at this point.
- */
- SCR_JUMP ^ IFFALSE (WHEN (SCR_COMMAND)),
- PADDR_A (sel_no_cmd),
-}/*-------------------------< COMMAND >--------------------------*/,{
- /*
- * ... and send the command
- */
- SCR_MOVE_TBL ^ SCR_COMMAND,
- offsetof (struct dsb, cmd),
-}/*-------------------------< DISPATCH >-------------------------*/,{
- /*
- * MSG_IN is the only phase that shall be
- * entered at least once for each (re)selection.
- * So we test it first.
- */
- SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
- PADDR_A (msg_in),
- SCR_JUMP ^ IFTRUE (IF (SCR_DATA_OUT)),
- PADDR_A (datao_phase),
- SCR_JUMP ^ IFTRUE (IF (SCR_DATA_IN)),
- PADDR_A (datai_phase),
- SCR_JUMP ^ IFTRUE (IF (SCR_STATUS)),
- PADDR_A (status),
- SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND)),
- PADDR_A (command),
- SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)),
- PADDR_B (msg_out),
- /*
- * Discard as many illegal phases as
- * required and tell the C code about.
- */
- SCR_JUMPR ^ IFFALSE (WHEN (SCR_ILG_OUT)),
- 16,
- SCR_MOVE_ABS (1) ^ SCR_ILG_OUT,
- HADDR_1 (scratch),
- SCR_JUMPR ^ IFTRUE (WHEN (SCR_ILG_OUT)),
- -16,
- SCR_JUMPR ^ IFFALSE (WHEN (SCR_ILG_IN)),
- 16,
- SCR_MOVE_ABS (1) ^ SCR_ILG_IN,
- HADDR_1 (scratch),
- SCR_JUMPR ^ IFTRUE (WHEN (SCR_ILG_IN)),
- -16,
- SCR_INT,
- SIR_BAD_PHASE,
- SCR_JUMP,
- PADDR_A (dispatch),
-}/*-------------------------< SEL_NO_CMD >-----------------------*/,{
- /*
- * The target does not switch to command
- * phase after IDENTIFY has been sent.
- *
- * If it stays in MSG OUT phase send it
- * the IDENTIFY again.
- */
- SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)),
- PADDR_B (resend_ident),
- /*
- * If target does not switch to MSG IN phase
- * and we sent a negotiation, assert the
- * failure immediately.
- */
- SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
- PADDR_A (dispatch),
- SCR_FROM_REG (HS_REG),
- 0,
- SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)),
- SIR_NEGO_FAILED,
- /*
- * Jump to dispatcher.
- */
- SCR_JUMP,
- PADDR_A (dispatch),
-}/*-------------------------< INIT >-----------------------------*/,{
- /*
- * Wait for the SCSI RESET signal to be
- * inactive before restarting operations,
- * since the chip may hang on SEL_ATN
- * if SCSI RESET is active.
- */
- SCR_FROM_REG (sstat0),
- 0,
- SCR_JUMPR ^ IFTRUE (MASK (IRST, IRST)),
- -16,
- SCR_JUMP,
- PADDR_A (start),
-}/*-------------------------< CLRACK >---------------------------*/,{
- /*
- * Terminate possible pending message phase.
- */
- SCR_CLR (SCR_ACK),
- 0,
- SCR_JUMP,
- PADDR_A (dispatch),
-}/*-------------------------< DISP_STATUS >----------------------*/,{
- /*
- * Anticipate STATUS phase.
- *
- * Does spare 3 SCRIPTS instructions when we have
- * completed the INPUT of the data.
- */
- SCR_JUMP ^ IFTRUE (WHEN (SCR_STATUS)),
- PADDR_A (status),
- SCR_JUMP,
- PADDR_A (dispatch),
-}/*-------------------------< DATAI_DONE >-----------------------*/,{
- /*
- * If the device still wants to send us data,
- * we must count the extra bytes.
- */
- SCR_JUMP ^ IFTRUE (WHEN (SCR_DATA_IN)),
- PADDR_B (data_ovrun),
- /*
- * If the SWIDE is not full, jump to dispatcher.
- * We anticipate a STATUS phase.
- */
- SCR_FROM_REG (scntl2),
- 0,
- SCR_JUMP ^ IFFALSE (MASK (WSR, WSR)),
- PADDR_A (disp_status),
- /*
- * The SWIDE is full.
- * Clear this condition.
- */
- SCR_REG_REG (scntl2, SCR_OR, WSR),
- 0,
- /*
- * We are expecting an IGNORE RESIDUE message
- * from the device, otherwise we are in data
- * overrun condition. Check against MSG_IN phase.
- */
- SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)),
- SIR_SWIDE_OVERRUN,
- SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
- PADDR_A (disp_status),
- /*
- * We are in MSG_IN phase,
- * Read the first byte of the message.
- * If it is not an IGNORE RESIDUE message,
- * signal overrun and jump to message
- * processing.
- */
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- HADDR_1 (msgin[0]),
- SCR_INT ^ IFFALSE (DATA (M_IGN_RESIDUE)),
- SIR_SWIDE_OVERRUN,
- SCR_JUMP ^ IFFALSE (DATA (M_IGN_RESIDUE)),
- PADDR_A (msg_in2),
- /*
- * We got the message we expected.
- * Read the 2nd byte, and jump to dispatcher.
- */
- SCR_CLR (SCR_ACK),
- 0,
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- HADDR_1 (msgin[1]),
- SCR_CLR (SCR_ACK),
- 0,
- SCR_JUMP,
- PADDR_A (disp_status),
-}/*-------------------------< DATAO_DONE >-----------------------*/,{
- /*
- * If the device wants us to send more data,
- * we must count the extra bytes.
- */
- SCR_JUMP ^ IFTRUE (WHEN (SCR_DATA_OUT)),
- PADDR_B (data_ovrun),
- /*
- * If the SODL is not full jump to dispatcher.
- * We anticipate a STATUS phase.
- */
- SCR_FROM_REG (scntl2),
- 0,
- SCR_JUMP ^ IFFALSE (MASK (WSS, WSS)),
- PADDR_A (disp_status),
- /*
- * The SODL is full, clear this condition.
- */
- SCR_REG_REG (scntl2, SCR_OR, WSS),
- 0,
- /*
- * And signal a DATA UNDERRUN condition
- * to the C code.
- */
- SCR_INT,
- SIR_SODL_UNDERRUN,
- SCR_JUMP,
- PADDR_A (dispatch),
-}/*-------------------------< DATAI_PHASE >----------------------*/,{
- SCR_RETURN,
- 0,
-}/*-------------------------< DATAO_PHASE >----------------------*/,{
- SCR_RETURN,
- 0,
-}/*-------------------------< MSG_IN >---------------------------*/,{
- /*
- * Get the first byte of the message.
- *
- * The script processor doesn't negate the
- * ACK signal after this transfer.
- */
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- HADDR_1 (msgin[0]),
-}/*-------------------------< MSG_IN2 >--------------------------*/,{
- /*
- * Check first against 1 byte messages
- * that we handle from SCRIPTS.
- */
- SCR_JUMP ^ IFTRUE (DATA (M_COMPLETE)),
- PADDR_A (complete),
- SCR_JUMP ^ IFTRUE (DATA (M_DISCONNECT)),
- PADDR_A (disconnect),
- SCR_JUMP ^ IFTRUE (DATA (M_SAVE_DP)),
- PADDR_A (save_dp),
- SCR_JUMP ^ IFTRUE (DATA (M_RESTORE_DP)),
- PADDR_A (restore_dp),
- /*
- * We handle all other messages from the
- * C code, so no need to waste on-chip RAM
- * for those ones.
- */
- SCR_JUMP,
- PADDR_B (msg_in_etc),
-}/*-------------------------< STATUS >---------------------------*/,{
/*
- * get the status
+ * Remove LED support if not needed.
*/
- SCR_MOVE_ABS (1) ^ SCR_STATUS,
- HADDR_1 (scratch),
+ if (!(np->features & FE_LED0)) {
+ scripta0->idle[0] = cpu_to_scr(SCR_NO_OP);
+ scripta0->reselected[0] = cpu_to_scr(SCR_NO_OP);
+ scripta0->start[0] = cpu_to_scr(SCR_NO_OP);
+ }
+
#ifdef SYM_CONF_IARB_SUPPORT
/*
- * If STATUS is not GOOD, clear IMMEDIATE ARBITRATION,
- * since we may have to tamper the start queue from
- * the C code.
+ * If user does not want to use IMMEDIATE ARBITRATION
+ * when we are reselected while attempting to arbitrate,
+ * patch the SCRIPTS accordingly with a SCRIPT NO_OP.
*/
- SCR_JUMPR ^ IFTRUE (DATA (S_GOOD)),
- 8,
- SCR_REG_REG (scntl1, SCR_AND, ~IARB),
- 0,
+ if (!SYM_CONF_SET_IARB_ON_ARB_LOST)
+ scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP);
#endif
/*
- * save status to scsi_status.
- * mark as complete.
- */
- SCR_TO_REG (SS_REG),
- 0,
- SCR_LOAD_REG (HS_REG, HS_COMPLETE),
- 0,
- /*
- * Anticipate the MESSAGE PHASE for
- * the TASK COMPLETE message.
- */
- SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
- PADDR_A (msg_in),
- SCR_JUMP,
- PADDR_A (dispatch),
-}/*-------------------------< COMPLETE >-------------------------*/,{
- /*
- * Complete message.
- *
- * Copy the data pointer to LASTP.
- */
- SCR_STORE_REL (temp, 4),
- offsetof (struct sym_ccb, phys.lastp),
- /*
- * When we terminate the cycle by clearing ACK,
- * the target may disconnect immediately.
- *
- * We don't want to be told of an "unexpected disconnect",
- * so we disable this feature.
- */
- SCR_REG_REG (scntl2, SCR_AND, 0x7f),
- 0,
- /*
- * Terminate cycle ...
- */
- SCR_CLR (SCR_ACK|SCR_ATN),
- 0,
- /*
- * ... and wait for the disconnect.
- */
- SCR_WAIT_DISC,
- 0,
-}/*-------------------------< COMPLETE2 >------------------------*/,{
- /*
- * Save host status.
- */
- SCR_STORE_REL (scr0, 4),
- offsetof (struct sym_ccb, phys.status),
- /*
- * Some bridges may reorder DMA writes to memory.
- * We donnot want the CPU to deal with completions
- * without all the posted write having been flushed
- * to memory. This DUMMY READ should flush posted
- * buffers prior to the CPU having to deal with
- * completions.
- */
- SCR_LOAD_REL (scr0, 4), /* DUMMY READ */
- offsetof (struct sym_ccb, phys.status),
-
- /*
- * If command resulted in not GOOD status,
- * call the C code if needed.
- */
- SCR_FROM_REG (SS_REG),
- 0,
- SCR_CALL ^ IFFALSE (DATA (S_GOOD)),
- PADDR_B (bad_status),
- /*
- * If we performed an auto-sense, call
- * the C code to synchronyze task aborts
- * with UNIT ATTENTION conditions.
- */
- SCR_FROM_REG (HF_REG),
- 0,
- SCR_JUMPR ^ IFTRUE (MASK (0 ,(HF_SENSE|HF_EXT_ERR))),
- 16,
-}/*-------------------------< COMPLETE_ERROR >-------------------*/,{
- SCR_LOAD_ABS (scratcha, 4),
- PADDR_B (startpos),
- SCR_INT,
- SIR_COMPLETE_ERROR,
-}/*-------------------------< DONE >-----------------------------*/,{
- /*
- * Copy the DSA to the DONE QUEUE and
- * signal completion to the host.
- * If we are interrupted between DONE
- * and DONE_END, we must reset, otherwise
- * the completed CCB may be lost.
- */
- SCR_STORE_ABS (dsa, 4),
- PADDR_B (saved_dsa),
- SCR_LOAD_ABS (dsa, 4),
- PADDR_B (done_pos),
- SCR_LOAD_ABS (scratcha, 4),
- PADDR_B (saved_dsa),
- SCR_STORE_REL (scratcha, 4),
- 0,
- /*
- * The instruction below reads the DONE QUEUE next
- * free position from memory.
- * In addition it ensures that all PCI posted writes
- * are flushed and so the DSA value of the done
- * CCB is visible by the CPU before INTFLY is raised.
- */
- SCR_LOAD_REL (temp, 4),
- 4,
- SCR_INT_FLY,
- 0,
- SCR_STORE_ABS (temp, 4),
- PADDR_B (done_pos),
-}/*-------------------------< DONE_END >-------------------------*/,{
- SCR_JUMP,
- PADDR_A (start),
-}/*-------------------------< SAVE_DP >--------------------------*/,{
- /*
- * Clear ACK immediately.
- * No need to delay it.
- */
- SCR_CLR (SCR_ACK),
- 0,
- /*
- * Keep track we received a SAVE DP, so
- * we will switch to the other PM context
- * on the next PM since the DP may point
- * to the current PM context.
- */
- SCR_REG_REG (HF_REG, SCR_OR, HF_DP_SAVED),
- 0,
- /*
- * SAVE_DP message:
- * Copy the data pointer to SAVEP.
- */
- SCR_STORE_REL (temp, 4),
- offsetof (struct sym_ccb, phys.savep),
- SCR_JUMP,
- PADDR_A (dispatch),
-}/*-------------------------< RESTORE_DP >-----------------------*/,{
- /*
- * RESTORE_DP message:
- * Copy SAVEP to actual data pointer.
- */
- SCR_LOAD_REL (temp, 4),
- offsetof (struct sym_ccb, phys.savep),
- SCR_JUMP,
- PADDR_A (clrack),
-}/*-------------------------< DISCONNECT >-----------------------*/,{
- /*
- * DISCONNECTing ...
- *
- * disable the "unexpected disconnect" feature,
- * and remove the ACK signal.
- */
- SCR_REG_REG (scntl2, SCR_AND, 0x7f),
- 0,
- SCR_CLR (SCR_ACK|SCR_ATN),
- 0,
- /*
- * Wait for the disconnect.
- */
- SCR_WAIT_DISC,
- 0,
- /*
- * Status is: DISCONNECTED.
- */
- SCR_LOAD_REG (HS_REG, HS_DISCONNECT),
- 0,
- /*
- * Save host status.
- */
- SCR_STORE_REL (scr0, 4),
- offsetof (struct sym_ccb, phys.status),
- /*
- * If QUIRK_AUTOSAVE is set,
- * do an "save pointer" operation.
+ * Patch some data in SCRIPTS.
+ * - start and done queue initial bus address.
+ * - target bus address table bus address.
*/
- SCR_FROM_REG (QU_REG),
- 0,
- SCR_JUMP ^ IFFALSE (MASK (SYM_QUIRK_AUTOSAVE, SYM_QUIRK_AUTOSAVE)),
- PADDR_A (start),
- /*
- * like SAVE_DP message:
- * Remember we saved the data pointer.
- * Copy data pointer to SAVEP.
- */
- SCR_REG_REG (HF_REG, SCR_OR, HF_DP_SAVED),
- 0,
- SCR_STORE_REL (temp, 4),
- offsetof (struct sym_ccb, phys.savep),
- SCR_JUMP,
- PADDR_A (start),
-}/*-------------------------< IDLE >-----------------------------*/,{
+ scriptb0->startpos[0] = cpu_to_scr(np->squeue_ba);
+ scriptb0->done_pos[0] = cpu_to_scr(np->dqueue_ba);
+ scriptb0->targtbl[0] = cpu_to_scr(np->targtbl_ba);
+}
+#endif /* SYM_CONF_GENERIC_SUPPORT */
+
+/*
+ * Patch routine for firmware 2.
+ */
+static void
+sym_fw2_patch(hcb_p np)
+{
+ struct sym_fw2a_scr *scripta0;
+ struct sym_fw2b_scr *scriptb0;
+
+ scripta0 = (struct sym_fw2a_scr *) np->scripta0;
+ scriptb0 = (struct sym_fw2b_scr *) np->scriptb0;
+
/*
- * Nothing to do?
- * Switch the LED off and wait for reselect.
- * Will be patched with a NO_OP if LED
- * not needed or not desired.
+ * Remove LED support if not needed.
*/
- SCR_REG_REG (gpreg, SCR_OR, 0x01),
- 0,
-#ifdef SYM_CONF_IARB_SUPPORT
- SCR_JUMPR,
- 8,
-#endif
-}/*-------------------------< UNGETJOB >-------------------------*/,{
+ if (!(np->features & FE_LED0)) {
+ scripta0->idle[0] = cpu_to_scr(SCR_NO_OP);
+ scripta0->reselected[0] = cpu_to_scr(SCR_NO_OP);
+ scripta0->start[0] = cpu_to_scr(SCR_NO_OP);
+ }
+
#ifdef SYM_CONF_IARB_SUPPORT
/*
- * Set IMMEDIATE ARBITRATION, for the next time.
- * This will give us better chance to win arbitration
- * for the job we just wanted to do.
- */
- SCR_REG_REG (scntl1, SCR_OR, IARB),
- 0,
-#endif
- /*
- * We are not able to restart the SCRIPTS if we are
- * interrupted and these instruction haven't been
- * all executed. BTW, this is very unlikely to
- * happen, but we check that from the C code.
- */
- SCR_LOAD_REG (dsa, 0xff),
- 0,
- SCR_STORE_ABS (scratcha, 4),
- PADDR_B (startpos),
-}/*-------------------------< RESELECT >-------------------------*/,{
- /*
- * Make sure we are in initiator mode.
- */
- SCR_CLR (SCR_TRG),
- 0,
- /*
- * Sleep waiting for a reselection.
- */
- SCR_WAIT_RESEL,
- PADDR_A(start),
-}/*-------------------------< RESELECTED >-----------------------*/,{
- /*
- * Switch the LED on.
- * Will be patched with a NO_OP if LED
- * not needed or not desired.
- */
- SCR_REG_REG (gpreg, SCR_AND, 0xfe),
- 0,
- /*
- * load the target id into the sdid
- */
- SCR_REG_SFBR (ssid, SCR_AND, 0x8F),
- 0,
- SCR_TO_REG (sdid),
- 0,
- /*
- * Load the target control block address
+ * If user does not want to use IMMEDIATE ARBITRATION
+ * when we are reselected while attempting to arbitrate,
+ * patch the SCRIPTS accordingly with a SCRIPT NO_OP.
*/
- SCR_LOAD_ABS (dsa, 4),
- PADDR_B (targtbl),
- SCR_SFBR_REG (dsa, SCR_SHL, 0),
- 0,
- SCR_REG_REG (dsa, SCR_SHL, 0),
- 0,
- SCR_REG_REG (dsa, SCR_AND, 0x3c),
- 0,
- SCR_LOAD_REL (dsa, 4),
- 0,
- /*
- * Load the legacy synchronous transfer registers.
- */
- SCR_LOAD_REL (scntl3, 1),
- offsetof(struct sym_tcb, wval),
- SCR_LOAD_REL (sxfer, 1),
- offsetof(struct sym_tcb, sval),
-}/*-------------------------< RESEL_SCNTL4 >---------------------*/,{
- /*
- * The C1010 uses a new synchronous timing scheme.
- * Will be patched with a NO_OP if not a C1010.
- */
- SCR_LOAD_REL (scntl4, 1),
- offsetof(struct sym_tcb, uval),
- /*
- * We expect MESSAGE IN phase.
- * If not, get help from the C code.
- */
- SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)),
- SIR_RESEL_NO_MSG_IN,
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- HADDR_1 (msgin),
- /*
- * If IDENTIFY LUN #0, use a faster path
- * to find the LCB structure.
- */
- SCR_JUMPR ^ IFTRUE (MASK (0x80, 0xbf)),
- 56,
- /*
- * If message isn't an IDENTIFY,
- * tell the C code about.
- */
- SCR_INT ^ IFFALSE (MASK (0x80, 0x80)),
- SIR_RESEL_NO_IDENTIFY,
- /*
- * It is an IDENTIFY message,
- * Load the LUN control block address.
- */
- SCR_LOAD_REL (dsa, 4),
- offsetof(struct sym_tcb, luntbl_sa),
- SCR_SFBR_REG (dsa, SCR_SHL, 0),
- 0,
- SCR_REG_REG (dsa, SCR_SHL, 0),
- 0,
- SCR_REG_REG (dsa, SCR_AND, 0xfc),
- 0,
- SCR_LOAD_REL (dsa, 4),
- 0,
- SCR_JUMPR,
- 8,
- /*
- * LUN 0 special case (but usual one :))
- */
- SCR_LOAD_REL (dsa, 4),
- offsetof(struct sym_tcb, lun0_sa),
- /*
- * Jump indirectly to the reselect action for this LUN.
- */
- SCR_LOAD_REL (temp, 4),
- offsetof(struct sym_lcb, resel_sa),
- SCR_RETURN,
- 0,
- /* In normal situations, we jump to RESEL_TAG or RESEL_NO_TAG */
-}/*-------------------------< RESEL_TAG >------------------------*/,{
- /*
- * ACK the IDENTIFY or TAG previously received.
- */
- SCR_CLR (SCR_ACK),
- 0,
- /*
- * It shall be a tagged command.
- * Read SIMPLE+TAG.
- * The C code will deal with errors.
- * Agressive optimization, is'nt it? :)
- */
- SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
- HADDR_1 (msgin),
- /*
- * Load the pointer to the tagged task
- * table for this LUN.
- */
- SCR_LOAD_REL (dsa, 4),
- offsetof(struct sym_lcb, itlq_tbl_sa),
- /*
- * The SIDL still contains the TAG value.
- * Agressive optimization, isn't it? :):)
- */
- SCR_REG_SFBR (sidl, SCR_SHL, 0),
- 0,
-#if SYM_CONF_MAX_TASK*4 > 512
- SCR_JUMPR ^ IFFALSE (CARRYSET),
- 8,
- SCR_REG_REG (dsa1, SCR_OR, 2),
- 0,
- SCR_REG_REG (sfbr, SCR_SHL, 0),
- 0,
- SCR_JUMPR ^ IFFALSE (CARRYSET),
- 8,
- SCR_REG_REG (dsa1, SCR_OR, 1),
- 0,
-#elif SYM_CONF_MAX_TASK*4 > 256
- SCR_JUMPR ^ IFFALSE (CARRYSET),
- 8,
- SCR_REG_REG (dsa1, SCR_OR, 1),
- 0,
+ if (!SYM_CONF_SET_IARB_ON_ARB_LOST)
+ scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP);
#endif
/*
- * Retrieve the DSA of this task.
- * JUMP indirectly to the restart point of the CCB.
+ * Patch some variable in SCRIPTS.
+ * - start and done queue initial bus address.
+ * - target bus address table bus address.
*/
- SCR_SFBR_REG (dsa, SCR_AND, 0xfc),
- 0,
- SCR_LOAD_REL (dsa, 4),
- 0,
- SCR_LOAD_REL (temp, 4),
- offsetof(struct sym_ccb, phys.go.restart),
- SCR_RETURN,
- 0,
- /* In normal situations we branch to RESEL_DSA */
-}/*-------------------------< RESEL_DSA >------------------------*/,{
- /*
- * ACK the IDENTIFY or TAG previously received.
- */
- SCR_CLR (SCR_ACK),
- 0,
-}/*-------------------------< RESEL_DSA1 >-----------------------*/,{
- /*
- * load the savep (saved pointer) into
- * the actual data pointer.
- */
- SCR_LOAD_REL (temp, 4),
- offsetof (struct sym_ccb, phys.savep),
- /*
- * Initialize the status registers
- */
- SCR_LOAD_REL (scr0, 4),
- offsetof (struct sym_ccb, phys.status),
- /*
- * Jump to dispatcher.
- */
- SCR_JUMP,
- PADDR_A (dispatch),
-}/*-------------------------< RESEL_NO_TAG >---------------------*/,{
+ scriptb0->startpos[0] = cpu_to_scr(np->squeue_ba);
+ scriptb0->done_pos[0] = cpu_to_scr(np->dqueue_ba);
+ scriptb0->targtbl[0] = cpu_to_scr(np->targtbl_ba);
+
/*
- * Load the DSA with the unique ITL task.
+ * Remove the load of SCNTL4 on reselection if not a C10.
*/
- SCR_LOAD_REL (dsa, 4),
- offsetof(struct sym_lcb, itl_task_sa),
+ if (!(np->features & FE_C10)) {
+ scripta0->resel_scntl4[0] = cpu_to_scr(SCR_NO_OP);
+ scripta0->resel_scntl4[1] = cpu_to_scr(0);
+ }
+
/*
- * JUMP indirectly to the restart point of the CCB.
+ * Patch some other variables in SCRIPTS.
+ * These ones are loaded by the SCRIPTS processor.
*/
- SCR_LOAD_REL (temp, 4),
- offsetof(struct sym_ccb, phys.go.restart),
- SCR_RETURN,
- 0,
- /* In normal situations we branch to RESEL_DSA */
-}/*-------------------------< DATA_IN >--------------------------*/,{
+ scriptb0->pm0_data_addr[0] =
+ cpu_to_scr(np->scriptb_ba +
+ offsetof(struct sym_fw2a_scr, pm0_data));
+ scriptb0->pm1_data_addr[0] =
+ cpu_to_scr(np->scriptb_ba +
+ offsetof(struct sym_fw2a_scr, pm1_data));
+}
+
/*
- * Because the size depends on the
- * #define SYM_CONF_MAX_SG parameter,
- * it is filled in at runtime.
- *
- * ##===========< i=0; i<SYM_CONF_MAX_SG >=========
- * || SCR_CHMOV_TBL ^ SCR_DATA_IN,
- * || offsetof (struct dsb, data[ i]),
- * ##==========================================
- */
-0
-}/*-------------------------< DATA_IN2 >-------------------------*/,{
- SCR_CALL,
- PADDR_A (datai_done),
- SCR_JUMP,
- PADDR_B (data_ovrun),
-}/*-------------------------< DATA_OUT >-------------------------*/,{
-/*
- * Because the size depends on the
- * #define SYM_CONF_MAX_SG parameter,
- * it is filled in at runtime.
- *
- * ##===========< i=0; i<SYM_CONF_MAX_SG >=========
- * || SCR_CHMOV_TBL ^ SCR_DATA_OUT,
- * || offsetof (struct dsb, data[ i]),
- * ##==========================================
+ * Fill the data area in scripts.
+ * To be done for all firmwares.
*/
-0
-}/*-------------------------< DATA_OUT2 >------------------------*/,{
- SCR_CALL,
- PADDR_A (datao_done),
- SCR_JUMP,
- PADDR_B (data_ovrun),
-}/*-------------------------< PM0_DATA >-------------------------*/,{
- /*
- * Read our host flags to SFBR, so we will be able
- * to check against the data direction we expect.
- */
- SCR_FROM_REG (HF_REG),
- 0,
- /*
- * Check against actual DATA PHASE.
- */
- SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
- PADDR_A (pm0_data_out),
- /*
- * Actual phase is DATA IN.
- * Check against expected direction.
- */
- SCR_JUMP ^ IFFALSE (MASK (HF_DATA_IN, HF_DATA_IN)),
- PADDR_B (data_ovrun),
- /*
- * Keep track we are moving data from the
- * PM0 DATA mini-script.
- */
- SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM0),
- 0,
- /*
- * Move the data to memory.
- */
- SCR_CHMOV_TBL ^ SCR_DATA_IN,
- offsetof (struct sym_ccb, phys.pm0.sg),
- SCR_JUMP,
- PADDR_A (pm0_data_end),
-}/*-------------------------< PM0_DATA_OUT >---------------------*/,{
- /*
- * Actual phase is DATA OUT.
- * Check against expected direction.
- */
- SCR_JUMP ^ IFTRUE (MASK (HF_DATA_IN, HF_DATA_IN)),
- PADDR_B (data_ovrun),
- /*
- * Keep track we are moving data from the
- * PM0 DATA mini-script.
- */
- SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM0),
- 0,
- /*
- * Move the data from memory.
- */
- SCR_CHMOV_TBL ^ SCR_DATA_OUT,
- offsetof (struct sym_ccb, phys.pm0.sg),
-}/*-------------------------< PM0_DATA_END >---------------------*/,{
- /*
- * Clear the flag that told we were moving
- * data from the PM0 DATA mini-script.
- */
- SCR_REG_REG (HF_REG, SCR_AND, (~HF_IN_PM0)),
- 0,
- /*
- * Return to the previous DATA script which
- * is guaranteed by design (if no bug) to be
- * the main DATA script for this transfer.
- */
- SCR_LOAD_REL (temp, 4),
- offsetof (struct sym_ccb, phys.pm0.ret),
- SCR_RETURN,
- 0,
-}/*-------------------------< PM1_DATA >-------------------------*/,{
- /*
- * Read our host flags to SFBR, so we will be able
- * to check against the data direction we expect.
- */
- SCR_FROM_REG (HF_REG),
- 0,
- /*
- * Check against actual DATA PHASE.
- */
- SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
- PADDR_A (pm1_data_out),
- /*
- * Actual phase is DATA IN.
- * Check against expected direction.
- */
- SCR_JUMP ^ IFFALSE (MASK (HF_DATA_IN, HF_DATA_IN)),
- PADDR_B (data_ovrun),
- /*
- * Keep track we are moving data from the
- * PM1 DATA mini-script.
- */
- SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM1),
- 0,
- /*
- * Move the data to memory.
- */
- SCR_CHMOV_TBL ^ SCR_DATA_IN,
- offsetof (struct sym_ccb, phys.pm1.sg),
- SCR_JUMP,
- PADDR_A (pm1_data_end),
-}/*-------------------------< PM1_DATA_OUT >---------------------*/,{
- /*
- * Actual phase is DATA OUT.
- * Check against expected direction.
- */
- SCR_JUMP ^ IFTRUE (MASK (HF_DATA_IN, HF_DATA_IN)),
- PADDR_B (data_ovrun),
+static void
+sym_fw_fill_data (u32 *in, u32 *out)
+{
+ int i;
+
+ for (i = 0; i < SYM_CONF_MAX_SG; i++) {
+ *in++ = SCR_CHMOV_TBL ^ SCR_DATA_IN;
+ *in++ = offsetof (struct sym_dsb, data[i]);
+ *out++ = SCR_CHMOV_TBL ^ SCR_DATA_OUT;
+ *out++ = offsetof (struct sym_dsb, data[i]);
+ }
+}
+
+/*
+ * Setup useful script bus addresses.
+ * To be done for all firmwares.
+ */
+static void
+sym_fw_setup_bus_addresses(hcb_p np, struct sym_fw *fw)
+{
+ u32 *pa;
+ u_short *po;
+ int i;
+
/*
- * Keep track we are moving data from the
- * PM1 DATA mini-script.
+ * Build the bus address table for script A
+ * from the script A offset table.
*/
- SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM1),
- 0,
+ po = (u_short *) fw->a_ofs;
+ pa = (u32 *) &np->fwa_bas;
+ for (i = 0 ; i < sizeof(np->fwa_bas)/sizeof(u32) ; i++)
+ pa[i] = np->scripta_ba + po[i];
+
/*
- * Move the data from memory.
+ * Same for script B.
*/
- SCR_CHMOV_TBL ^ SCR_DATA_OUT,
- offsetof (struct sym_ccb, phys.pm1.sg),
-}/*-------------------------< PM1_DATA_END >---------------------*/,{
+ po = (u_short *) fw->b_ofs;
+ pa = (u32 *) &np->fwb_bas;
+ for (i = 0 ; i < sizeof(np->fwb_bas)/sizeof(u32) ; i++)
+ pa[i] = np->scriptb_ba + po[i];
+}
+
+#ifdef SYM_CONF_GENERIC_SUPPORT
+/*
+ * Setup routine for firmware #1.
+ */
+static void
+sym_fw1_setup(hcb_p np, struct sym_fw *fw)
+{
+ struct sym_fw1a_scr *scripta0;
+ struct sym_fw1b_scr *scriptb0;
+
+ scripta0 = (struct sym_fw1a_scr *) np->scripta0;
+ scriptb0 = (struct sym_fw1b_scr *) np->scriptb0;
+
/*
- * Clear the flag that told we were moving
- * data from the PM1 DATA mini-script.
+ * Fill variable parts in scripts.
*/
- SCR_REG_REG (HF_REG, SCR_AND, (~HF_IN_PM1)),
- 0,
+ sym_fw_fill_data(scripta0->data_in, scripta0->data_out);
+
/*
- * Return to the previous DATA script which
- * is guaranteed by design (if no bug) to be
- * the main DATA script for this transfer.
+ * Setup bus addresses used from the C code..
*/
- SCR_LOAD_REL (temp, 4),
- offsetof (struct sym_ccb, phys.pm1.ret),
- SCR_RETURN,
- 0,
-}/*-------------------------<>-----------------------------------*/
-};
+ sym_fw_setup_bus_addresses(np, fw);
+}
+#endif /* SYM_CONF_GENERIC_SUPPORT */
+
+/*
+ * Setup routine for firmware 2.
+ */
+static void
+sym_fw2_setup(hcb_p np, struct sym_fw *fw)
+{
+ struct sym_fw2a_scr *scripta0;
+ struct sym_fw2b_scr *scriptb0;
+
+ scripta0 = (struct sym_fw2a_scr *) np->scripta0;
+ scriptb0 = (struct sym_fw2b_scr *) np->scriptb0;
-static struct sym_scrb scriptb0 = {
-/*--------------------------< START64 >--------------------------*/ {
/*
- * SCRIPT entry point for the 895A, 896 and 1010.
- * For now, there is no specific stuff for those
- * chips at this point, but this may come.
+ * Fill variable parts in scripts.
*/
- SCR_JUMP,
- PADDR_A (init),
-}/*-------------------------< NO_DATA >--------------------------*/,{
- SCR_JUMP,
- PADDR_B (data_ovrun),
-}/*-------------------------< SEL_FOR_ABORT >--------------------*/,{
+ sym_fw_fill_data(scripta0->data_in, scripta0->data_out);
+
/*
- * We are jumped here by the C code, if we have
- * some target to reset or some disconnected
- * job to abort. Since error recovery is a serious
- * busyness, we will really reset the SCSI BUS, if
- * case of a SCSI interrupt occuring in this path.
+ * Setup bus addresses used from the C code..
*/
+ sym_fw_setup_bus_addresses(np, fw);
+}
- /*
- * Set initiator mode.
- */
- SCR_CLR (SCR_TRG),
- 0,
- /*
- * And try to select this target.
- */
- SCR_SEL_TBL_ATN ^ offsetof (struct sym_hcb, abrt_sel),
- PADDR_A (reselect),
- /*
- * Wait for the selection to complete or
- * the selection to time out.
- */
- SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_OUT)),
- -8,
- /*
- * Call the C code.
- */
- SCR_INT,
- SIR_TARGET_SELECTED,
- /*
- * The C code should let us continue here.
- * Send the 'kiss of death' message.
- * We expect an immediate disconnect once
- * the target has eaten the message.
- */
- SCR_REG_REG (scntl2, SCR_AND, 0x7f),
- 0,
- SCR_MOVE_TBL ^ SCR_MSG_OUT,
- offsetof (struct sym_hcb, abrt_tbl),
- SCR_CLR (SCR_ACK|SCR_ATN),
- 0,
- SCR_WAIT_DISC,
- 0,
- /*
- * Tell the C code that we are done.
- */
- SCR_INT,
- SIR_ABORT_SENT,
-}/*-------------------------< SEL_FOR_ABORT_1 >------------------*/,{
- /*
- * Jump at scheduler.
- */
- SCR_JUMP,
- PADDR_A (start),
-}/*-------------------------< MSG_IN_ETC >-----------------------*/,{
- /*
- * If it is an EXTENDED (variable size message)
- * Handle it.
- */
- SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)),
- PADDR_B (msg_extended),
- /*
- * Let the C code handle any other
- * 1 byte message.
- */
- SCR_INT ^ IFTRUE (MASK (0x00, 0xf0)),
- SIR_MSG_RECEIVED,
- SCR_INT ^ IFTRUE (MASK (0x10, 0xf0)),
- SIR_MSG_RECEIVED,
- /*
- * We donnot handle 2 bytes messages from SCRIPTS.
- * So, let the C code deal with these ones too.
- */
- SCR_INT ^ IFFALSE (MASK (0x20, 0xf0)),
- SIR_MSG_WEIRD,
- SCR_CLR (SCR_ACK),
- 0,
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- HADDR_1 (msgin[1]),
- SCR_INT,
- SIR_MSG_RECEIVED,
-}/*-------------------------< MSG_RECEIVED >---------------------*/,{
- SCR_LOAD_REL (scratcha, 4), /* DUMMY READ */
- 0,
- SCR_INT,
- SIR_MSG_RECEIVED,
-}/*-------------------------< MSG_WEIRD_SEEN >-------------------*/,{
- SCR_LOAD_REL (scratcha, 4), /* DUMMY READ */
- 0,
- SCR_INT,
- SIR_MSG_WEIRD,
-}/*-------------------------< MSG_EXTENDED >---------------------*/,{
- /*
- * Clear ACK and get the next byte
- * assumed to be the message length.
- */
- SCR_CLR (SCR_ACK),
- 0,
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- HADDR_1 (msgin[1]),
- /*
- * Try to catch some unlikely situations as 0 length
- * or too large the length.
- */
- SCR_JUMP ^ IFTRUE (DATA (0)),
- PADDR_B (msg_weird_seen),
- SCR_TO_REG (scratcha),
- 0,
- SCR_REG_REG (sfbr, SCR_ADD, (256-8)),
- 0,
- SCR_JUMP ^ IFTRUE (CARRYSET),
- PADDR_B (msg_weird_seen),
- /*
- * We donnot handle extended messages from SCRIPTS.
- * Read the amount of data correponding to the
- * message length and call the C code.
- */
- SCR_STORE_REL (scratcha, 1),
- offsetof (struct dsb, smsg_ext.size),
- SCR_CLR (SCR_ACK),
- 0,
- SCR_MOVE_TBL ^ SCR_MSG_IN,
- offsetof (struct dsb, smsg_ext),
- SCR_JUMP,
- PADDR_B (msg_received),
-}/*-------------------------< MSG_BAD >--------------------------*/,{
- /*
- * unimplemented message - reject it.
- */
- SCR_INT,
- SIR_REJECT_TO_SEND,
- SCR_SET (SCR_ATN),
- 0,
- SCR_JUMP,
- PADDR_A (clrack),
-}/*-------------------------< MSG_WEIRD >------------------------*/,{
- /*
- * weird message received
- * ignore all MSG IN phases and reject it.
- */
- SCR_INT,
- SIR_REJECT_TO_SEND,
- SCR_SET (SCR_ATN),
- 0,
-}/*-------------------------< MSG_WEIRD1 >-----------------------*/,{
- SCR_CLR (SCR_ACK),
- 0,
- SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
- PADDR_A (dispatch),
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- HADDR_1 (scratch),
- SCR_JUMP,
- PADDR_B (msg_weird1),
-}/*-------------------------< WDTR_RESP >------------------------*/,{
- /*
- * let the target fetch our answer.
- */
- SCR_SET (SCR_ATN),
- 0,
- SCR_CLR (SCR_ACK),
- 0,
- SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
- PADDR_B (nego_bad_phase),
-}/*-------------------------< SEND_WDTR >------------------------*/,{
- /*
- * Send the M_X_WIDE_REQ
- */
- SCR_MOVE_ABS (4) ^ SCR_MSG_OUT,
- HADDR_1 (msgout),
- SCR_JUMP,
- PADDR_B (msg_out_done),
-}/*-------------------------< SDTR_RESP >------------------------*/,{
- /*
- * let the target fetch our answer.
- */
- SCR_SET (SCR_ATN),
- 0,
- SCR_CLR (SCR_ACK),
- 0,
- SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
- PADDR_B (nego_bad_phase),
-}/*-------------------------< SEND_SDTR >------------------------*/,{
- /*
- * Send the M_X_SYNC_REQ
- */
- SCR_MOVE_ABS (5) ^ SCR_MSG_OUT,
- HADDR_1 (msgout),
- SCR_JUMP,
- PADDR_B (msg_out_done),
-}/*-------------------------< PPR_RESP >-------------------------*/,{
- /*
- * let the target fetch our answer.
- */
- SCR_SET (SCR_ATN),
- 0,
- SCR_CLR (SCR_ACK),
- 0,
- SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
- PADDR_B (nego_bad_phase),
-}/*-------------------------< SEND_PPR >-------------------------*/,{
- /*
- * Send the M_X_PPR_REQ
- */
- SCR_MOVE_ABS (8) ^ SCR_MSG_OUT,
- HADDR_1 (msgout),
- SCR_JUMP,
- PADDR_B (msg_out_done),
-}/*-------------------------< NEGO_BAD_PHASE >-------------------*/,{
- SCR_INT,
- SIR_NEGO_PROTO,
- SCR_JUMP,
- PADDR_A (dispatch),
-}/*-------------------------< MSG_OUT >--------------------------*/,{
- /*
- * The target requests a message.
- * We donnot send messages that may
- * require the device to go to bus free.
- */
- SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
- HADDR_1 (msgout),
- /*
- * ... wait for the next phase
- * if it's a message out, send it again, ...
- */
- SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)),
- PADDR_B (msg_out),
-}/*-------------------------< MSG_OUT_DONE >---------------------*/,{
- /*
- * Let the C code be aware of the
- * sent message and clear the message.
- */
- SCR_INT,
- SIR_MSG_OUT_DONE,
- /*
- * ... and process the next phase
- */
- SCR_JUMP,
- PADDR_A (dispatch),
-}/*-------------------------< DATA_OVRUN >-----------------------*/,{
- /*
- * Use scratcha to count the extra bytes.
- */
- SCR_LOAD_ABS (scratcha, 4),
- PADDR_B (zero),
-}/*-------------------------< DATA_OVRUN1 >----------------------*/,{
- /*
- * The target may want to transfer too much data.
- *
- * If phase is DATA OUT write 1 byte and count it.
- */
- SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_OUT)),
- 16,
- SCR_CHMOV_ABS (1) ^ SCR_DATA_OUT,
- HADDR_1 (scratch),
- SCR_JUMP,
- PADDR_B (data_ovrun2),
- /*
- * If WSR is set, clear this condition, and
- * count this byte.
- */
- SCR_FROM_REG (scntl2),
- 0,
- SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)),
- 16,
- SCR_REG_REG (scntl2, SCR_OR, WSR),
- 0,
- SCR_JUMP,
- PADDR_B (data_ovrun2),
- /*
- * Finally check against DATA IN phase.
- * Signal data overrun to the C code
- * and jump to dispatcher if not so.
- * Read 1 byte otherwise and count it.
- */
- SCR_JUMPR ^ IFTRUE (WHEN (SCR_DATA_IN)),
- 16,
- SCR_INT,
- SIR_DATA_OVERRUN,
- SCR_JUMP,
- PADDR_A (dispatch),
- SCR_CHMOV_ABS (1) ^ SCR_DATA_IN,
- HADDR_1 (scratch),
-}/*-------------------------< DATA_OVRUN2 >----------------------*/,{
- /*
- * Count this byte.
- * This will allow to return a negative
- * residual to user.
- */
- SCR_REG_REG (scratcha, SCR_ADD, 0x01),
- 0,
- SCR_REG_REG (scratcha1, SCR_ADDC, 0),
- 0,
- SCR_REG_REG (scratcha2, SCR_ADDC, 0),
- 0,
- /*
- * .. and repeat as required.
- */
- SCR_JUMP,
- PADDR_B (data_ovrun1),
-}/*-------------------------< ABORT_RESEL >----------------------*/,{
- SCR_SET (SCR_ATN),
- 0,
- SCR_CLR (SCR_ACK),
- 0,
- /*
- * send the abort/abortag/reset message
- * we expect an immediate disconnect
- */
- SCR_REG_REG (scntl2, SCR_AND, 0x7f),
- 0,
- SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
- HADDR_1 (msgout),
- SCR_CLR (SCR_ACK|SCR_ATN),
- 0,
- SCR_WAIT_DISC,
- 0,
- SCR_INT,
- SIR_RESEL_ABORTED,
- SCR_JUMP,
- PADDR_A (start),
-}/*-------------------------< RESEND_IDENT >---------------------*/,{
- /*
- * The target stays in MSG OUT phase after having acked
- * Identify [+ Tag [+ Extended message ]]. Targets shall
- * behave this way on parity error.
- * We must send it again all the messages.
- */
- SCR_SET (SCR_ATN), /* Shall be asserted 2 deskew delays before the */
- 0, /* 1rst ACK = 90 ns. Hope the chip isn't too fast */
- SCR_JUMP,
- PADDR_A (send_ident),
-}/*-------------------------< IDENT_BREAK >----------------------*/,{
- SCR_CLR (SCR_ATN),
- 0,
- SCR_JUMP,
- PADDR_A (select2),
-}/*-------------------------< IDENT_BREAK_ATN >------------------*/,{
- SCR_SET (SCR_ATN),
- 0,
- SCR_JUMP,
- PADDR_A (select2),
-}/*-------------------------< SDATA_IN >-------------------------*/,{
- SCR_CHMOV_TBL ^ SCR_DATA_IN,
- offsetof (struct dsb, sense),
- SCR_CALL,
- PADDR_A (datai_done),
- SCR_JUMP,
- PADDR_B (data_ovrun),
-}/*-------------------------< RESEL_BAD_LUN >--------------------*/,{
- /*
- * Message is an IDENTIFY, but lun is unknown.
- * Signal problem to C code for logging the event.
- * Send a M_ABORT to clear all pending tasks.
- */
- SCR_INT,
- SIR_RESEL_BAD_LUN,
- SCR_JUMP,
- PADDR_B (abort_resel),
-}/*-------------------------< BAD_I_T_L >------------------------*/,{
- /*
- * We donnot have a task for that I_T_L.
- * Signal problem to C code for logging the event.
- * Send a M_ABORT message.
- */
- SCR_INT,
- SIR_RESEL_BAD_I_T_L,
- SCR_JUMP,
- PADDR_B (abort_resel),
-}/*-------------------------< BAD_I_T_L_Q >----------------------*/,{
- /*
- * We donnot have a task that matches the tag.
- * Signal problem to C code for logging the event.
- * Send a M_ABORTTAG message.
- */
- SCR_INT,
- SIR_RESEL_BAD_I_T_L_Q,
- SCR_JUMP,
- PADDR_B (abort_resel),
-}/*-------------------------< BAD_STATUS >-----------------------*/,{
- /*
- * Anything different from INTERMEDIATE
- * CONDITION MET should be a bad SCSI status,
- * given that GOOD status has already been tested.
- * Call the C code.
- */
- SCR_LOAD_ABS (scratcha, 4),
- PADDR_B (startpos),
- SCR_INT ^ IFFALSE (DATA (S_COND_MET)),
- SIR_BAD_SCSI_STATUS,
- SCR_RETURN,
- 0,
-}/*-------------------------< PM_HANDLE >------------------------*/,{
- /*
- * Phase mismatch handling.
- *
- * Since we have to deal with 2 SCSI data pointers
- * (current and saved), we need at least 2 contexts.
- * Each context (pm0 and pm1) has a saved area, a
- * SAVE mini-script and a DATA phase mini-script.
- */
- /*
- * Get the PM handling flags.
- */
- SCR_FROM_REG (HF_REG),
- 0,
- /*
- * If no flags (1rst PM for example), avoid
- * all the below heavy flags testing.
- * This makes the normal case a bit faster.
- */
- SCR_JUMP ^ IFTRUE (MASK (0, (HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED))),
- PADDR_B (pm_handle1),
- /*
- * If we received a SAVE DP, switch to the
- * other PM context since the savep may point
- * to the current PM context.
- */
- SCR_JUMPR ^ IFFALSE (MASK (HF_DP_SAVED, HF_DP_SAVED)),
- 8,
- SCR_REG_REG (sfbr, SCR_XOR, HF_ACT_PM),
- 0,
- /*
- * If we have been interrupt in a PM DATA mini-script,
- * we take the return address from the corresponding
- * saved area.
- * This ensure the return address always points to the
- * main DATA script for this transfer.
- */
- SCR_JUMP ^ IFTRUE (MASK (0, (HF_IN_PM0 | HF_IN_PM1))),
- PADDR_B (pm_handle1),
- SCR_JUMPR ^ IFFALSE (MASK (HF_IN_PM0, HF_IN_PM0)),
- 16,
- SCR_LOAD_REL (ia, 4),
- offsetof(struct sym_ccb, phys.pm0.ret),
- SCR_JUMP,
- PADDR_B (pm_save),
- SCR_LOAD_REL (ia, 4),
- offsetof(struct sym_ccb, phys.pm1.ret),
- SCR_JUMP,
- PADDR_B (pm_save),
-}/*-------------------------< PM_HANDLE1 >-----------------------*/,{
- /*
- * Normal case.
- * Update the return address so that it
- * will point after the interrupted MOVE.
- */
- SCR_REG_REG (ia, SCR_ADD, 8),
- 0,
- SCR_REG_REG (ia1, SCR_ADDC, 0),
- 0,
-}/*-------------------------< PM_SAVE >--------------------------*/,{
- /*
- * Clear all the flags that told us if we were
- * interrupted in a PM DATA mini-script and/or
- * we received a SAVE DP.
- */
- SCR_SFBR_REG (HF_REG, SCR_AND, (~(HF_IN_PM0|HF_IN_PM1|HF_DP_SAVED))),
- 0,
- /*
- * Choose the current PM context.
- */
- SCR_JUMP ^ IFTRUE (MASK (HF_ACT_PM, HF_ACT_PM)),
- PADDR_B (pm1_save),
-}/*-------------------------< PM0_SAVE >-------------------------*/,{
- SCR_STORE_REL (ia, 4),
- offsetof(struct sym_ccb, phys.pm0.ret),
- /*
- * If WSR bit is set, either UA and RBC may
- * have to be changed whether the device wants
- * to ignore this residue or not.
- */
- SCR_FROM_REG (scntl2),
- 0,
- SCR_CALL ^ IFTRUE (MASK (WSR, WSR)),
- PADDR_B (pm_wsr_handle),
- /*
- * Save the remaining byte count, the updated
- * address and the return address.
- */
- SCR_STORE_REL (rbc, 4),
- offsetof(struct sym_ccb, phys.pm0.sg.size),
- SCR_STORE_REL (ua, 4),
- offsetof(struct sym_ccb, phys.pm0.sg.addr),
- /*
- * Set the current pointer at the PM0 DATA mini-script.
- */
- SCR_LOAD_ABS (temp, 4),
- PADDR_B (pm0_data_addr),
- SCR_JUMP,
- PADDR_A (dispatch),
-}/*-------------------------< PM1_SAVE >-------------------------*/,{
- SCR_STORE_REL (ia, 4),
- offsetof(struct sym_ccb, phys.pm1.ret),
- /*
- * If WSR bit is set, either UA and RBC may
- * have to be changed whether the device wants
- * to ignore this residue or not.
- */
- SCR_FROM_REG (scntl2),
- 0,
- SCR_CALL ^ IFTRUE (MASK (WSR, WSR)),
- PADDR_B (pm_wsr_handle),
- /*
- * Save the remaining byte count, the updated
- * address and the return address.
- */
- SCR_STORE_REL (rbc, 4),
- offsetof(struct sym_ccb, phys.pm1.sg.size),
- SCR_STORE_REL (ua, 4),
- offsetof(struct sym_ccb, phys.pm1.sg.addr),
- /*
- * Set the current pointer at the PM1 DATA mini-script.
- */
- SCR_LOAD_ABS (temp, 4),
- PADDR_B (pm1_data_addr),
- SCR_JUMP,
- PADDR_A (dispatch),
-}/*-------------------------< PM_WSR_HANDLE >--------------------*/,{
- /*
- * Phase mismatch handling from SCRIPT with WSR set.
- * Such a condition can occur if the chip wants to
- * execute a CHMOV(size > 1) when the WSR bit is
- * set and the target changes PHASE.
- *
- * We must move the residual byte to memory.
- *
- * UA contains bit 0..31 of the address to
- * move the residual byte.
- * Move it to the table indirect.
- */
- SCR_STORE_REL (ua, 4),
- offsetof (struct sym_ccb, phys.wresid.addr),
- /*
- * Increment UA (move address to next position).
- */
- SCR_REG_REG (ua, SCR_ADD, 1),
- 0,
- SCR_REG_REG (ua1, SCR_ADDC, 0),
- 0,
- SCR_REG_REG (ua2, SCR_ADDC, 0),
- 0,
- SCR_REG_REG (ua3, SCR_ADDC, 0),
- 0,
- /*
- * Compute SCRATCHA as:
- * - size to transfer = 1 byte.
- * - bit 24..31 = high address bit [32...39].
- */
- SCR_LOAD_ABS (scratcha, 4),
- PADDR_B (zero),
- SCR_REG_REG (scratcha, SCR_OR, 1),
- 0,
- SCR_FROM_REG (rbc3),
- 0,
- SCR_TO_REG (scratcha3),
- 0,
- /*
- * Move this value to the table indirect.
- */
- SCR_STORE_REL (scratcha, 4),
- offsetof (struct sym_ccb, phys.wresid.size),
- /*
- * Wait for a valid phase.
- * While testing with bogus QUANTUM drives, the C1010
- * sometimes raised a spurious phase mismatch with
- * WSR and the CHMOV(1) triggered another PM.
- * Waiting explicitely for the PHASE seemed to avoid
- * the nested phase mismatch. Btw, this didn't happen
- * using my IBM drives.
- */
- SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_IN)),
- 0,
- /*
- * Perform the move of the residual byte.
- */
- SCR_CHMOV_TBL ^ SCR_DATA_IN,
- offsetof (struct sym_ccb, phys.wresid),
- /*
- * We can now handle the phase mismatch with UA fixed.
- * RBC[0..23]=0 is a special case that does not require
- * a PM context. The C code also checks against this.
- */
- SCR_FROM_REG (rbc),
- 0,
- SCR_RETURN ^ IFFALSE (DATA (0)),
- 0,
- SCR_FROM_REG (rbc1),
- 0,
- SCR_RETURN ^ IFFALSE (DATA (0)),
- 0,
- SCR_FROM_REG (rbc2),
- 0,
- SCR_RETURN ^ IFFALSE (DATA (0)),
- 0,
- /*
- * RBC[0..23]=0.
- * Not only we donnot need a PM context, but this would
- * lead to a bogus CHMOV(0). This condition means that
- * the residual was the last byte to move from this CHMOV.
- * So, we just have to move the current data script pointer
- * (i.e. TEMP) to the SCRIPTS address following the
- * interrupted CHMOV and jump to dispatcher.
- */
- SCR_STORE_ABS (ia, 4),
- PADDR_B (scratch),
- SCR_LOAD_ABS (temp, 4),
- PADDR_B (scratch),
- SCR_JUMP,
- PADDR_A (dispatch),
-}/*-------------------------< WSR_MA_HELPER >--------------------*/,{
- /*
- * Helper for the C code when WSR bit is set.
- * Perform the move of the residual byte.
- */
- SCR_CHMOV_TBL ^ SCR_DATA_IN,
- offsetof (struct sym_ccb, phys.wresid),
- SCR_JUMP,
- PADDR_A (dispatch),
-}/*-------------------------< ZERO >-----------------------------*/,{
- SCR_DATA_ZERO,
-}/*-------------------------< SCRATCH >--------------------------*/,{
- SCR_DATA_ZERO,
-}/*-------------------------< PM0_DATA_ADDR >--------------------*/,{
- SCR_DATA_ZERO,
-}/*-------------------------< PM1_DATA_ADDR >--------------------*/,{
- SCR_DATA_ZERO,
-}/*-------------------------< SAVED_DSA >------------------------*/,{
- SCR_DATA_ZERO,
-}/*-------------------------< SAVED_DRS >------------------------*/,{
- SCR_DATA_ZERO,
-}/*-------------------------< DONE_POS >-------------------------*/,{
- SCR_DATA_ZERO,
-}/*-------------------------< STARTPOS >-------------------------*/,{
- SCR_DATA_ZERO,
-}/*-------------------------< TARGTBL >--------------------------*/,{
- SCR_DATA_ZERO,
-
-}/*-------------------------< SNOOPTEST >------------------------*/,{
- /*
- * Read the variable from memory.
- */
- SCR_LOAD_REL (scratcha, 4),
- offsetof(struct sym_hcb, cache),
- /*
- * Write the variable to memory.
- */
- SCR_STORE_REL (temp, 4),
- offsetof(struct sym_hcb, cache),
- /*
- * Read back the variable from memory.
- */
- SCR_LOAD_REL (temp, 4),
- offsetof(struct sym_hcb, cache),
-}/*-------------------------< SNOOPEND >-------------------------*/,{
- /*
- * And stop.
- */
- SCR_INT,
- 99,
-}/*-------------------------<>-----------------------------------*/
-};
+/*
+ * Allocate firmware descriptors.
+ */
+#ifdef SYM_CONF_GENERIC_SUPPORT
+static struct sym_fw sym_fw1 = SYM_FW_ENTRY(sym_fw1, "NCR-generic");
+#endif /* SYM_CONF_GENERIC_SUPPORT */
+static struct sym_fw sym_fw2 = SYM_FW_ENTRY(sym_fw2, "LOAD/STORE-based");
/*
- * Fill in #define dependent parts of the scripts
+ * Find the most appropriate firmware for a chip.
*/
-static void sym_fill_scripts (scripta_p scra, scriptb_p scrb)
+static struct sym_fw *
+sym_find_firmware(struct sym_pci_chip *chip)
{
- int i;
- u32 *p;
-
- p = scra->data_in;
- for (i=0; i<SYM_CONF_MAX_SG; i++) {
- *p++ =SCR_CHMOV_TBL ^ SCR_DATA_IN;
- *p++ =offsetof (struct dsb, data[i]);
- };
- assert ((u_long)p == (u_long)&scra->data_in + sizeof (scra->data_in));
-
- p = scra->data_out;
- for (i=0; i<SYM_CONF_MAX_SG; i++) {
- *p++ =SCR_CHMOV_TBL ^ SCR_DATA_OUT;
- *p++ =offsetof (struct dsb, data[i]);
- };
- assert ((u_long)p == (u_long)&scra->data_out + sizeof (scra->data_out));
+ if (chip->features & FE_LDSTR)
+ return &sym_fw2;
+#ifdef SYM_CONF_GENERIC_SUPPORT
+ else if (!(chip->features & (FE_PFEN|FE_NOPM|FE_64BIT)))
+ return &sym_fw1;
+#endif
+ else
+ return 0;
}
/*
- * Copy and bind a script.
+ * Bind a script to physical addresses.
*/
-static void sym_bind_script (hcb_p np, u32 *src, u32 *dst, int len)
+static void sym_fw_bind_script (hcb_p np, u32 *start, int len)
{
u32 opcode, new, old, tmp1, tmp2;
- u32 *start, *end;
+ u32 *end, *cur;
int relocs;
- int opchanged = 0;
- start = src;
- end = src + len/4;
+ cur = start;
+ end = start + len/4;
- while (src < end) {
+ while (cur < end) {
- opcode = *src++;
- *dst++ = cpu_to_scr(opcode);
+ opcode = *cur;
/*
* If we forget to change the length
@@ -3707,8 +2114,9 @@ static void sym_bind_script (hcb_p np, u32 *src, u32 *dst, int len)
*/
if (opcode == 0) {
printf ("%s: ERROR0 IN SCRIPT at %d.\n",
- sym_name(np), (int) (src-start-1));
+ sym_name(np), (int) (cur-start));
MDELAY (10000);
+ ++cur;
continue;
};
@@ -3717,12 +2125,12 @@ static void sym_bind_script (hcb_p np, u32 *src, u32 *dst, int len)
* to reserve data area in SCRIPTS.
*/
if (opcode == SCR_DATA_ZERO) {
- dst[-1] = 0;
+ *cur++ = 0;
continue;
}
if (DEBUG_FLAGS & DEBUG_SCRIPT)
- printf ("%p: <%x>\n", (src-1), (unsigned)opcode);
+ printf ("%x: <%x>\n", cur-start, (unsigned)opcode);
/*
* We don't have to decode ALL commands
@@ -3745,12 +2153,12 @@ static void sym_bind_script (hcb_p np, u32 *src, u32 *dst, int len)
* COPY has TWO arguments.
*/
relocs = 2;
- tmp1 = src[0];
- tmp2 = src[1];
+ tmp1 = cur[1];
+ tmp2 = cur[2];
if ((tmp1 ^ tmp2) & 3) {
printf ("%s: ERROR1 IN SCRIPT at %d.\n",
- sym_name(np), (int) (src-start-1));
- MDELAY (1000);
+ sym_name(np), (int) (cur-start));
+ MDELAY (10000);
}
/*
* If PREFETCH feature not enabled, remove
@@ -3758,8 +2166,7 @@ static void sym_bind_script (hcb_p np, u32 *src, u32 *dst, int len)
*/
if ((opcode & SCR_NO_FLUSH) &&
!(np->features & FE_PFEN)) {
- dst[-1] = cpu_to_scr(opcode & ~SCR_NO_FLUSH);
- ++opchanged;
+ opcode = (opcode & ~SCR_NO_FLUSH);
}
break;
case 0x0:
@@ -3767,7 +2174,7 @@ static void sym_bind_script (hcb_p np, u32 *src, u32 *dst, int len)
* MOVE/CHMOV (absolute address)
*/
if (!(np->features & FE_WIDE))
- dst[-1] = cpu_to_scr(opcode | OPC_MOVE);
+ opcode = (opcode | OPC_MOVE);
relocs = 1;
break;
case 0x1:
@@ -3775,7 +2182,7 @@ static void sym_bind_script (hcb_p np, u32 *src, u32 *dst, int len)
* MOVE/CHMOV (table indirect)
*/
if (!(np->features & FE_WIDE))
- dst[-1] = cpu_to_scr(opcode | OPC_MOVE);
+ opcode = (opcode | OPC_MOVE);
relocs = 0;
break;
case 0x8:
@@ -3801,45 +2208,174 @@ static void sym_bind_script (hcb_p np, u32 *src, u32 *dst, int len)
break;
};
+ /*
+ * Scriptify:) the opcode.
+ */
+ *cur++ = cpu_to_scr(opcode);
+
+ /*
+ * If no relocation, assume 1 argument
+ * and just scriptize:) it.
+ */
if (!relocs) {
- *dst++ = cpu_to_scr(*src++);
+ *cur = cpu_to_scr(*cur);
+ ++cur;
continue;
}
+
+ /*
+ * Otherwise performs all needed relocations.
+ */
while (relocs--) {
- old = *src++;
+ old = *cur;
switch (old & RELOC_MASK) {
case RELOC_REGISTER:
new = (old & ~RELOC_MASK) + np->mmio_ba;
break;
- case RELOC_LABELA:
+ case RELOC_LABEL_A:
new = (old & ~RELOC_MASK) + np->scripta_ba;
break;
- case RELOC_LABELB:
+ case RELOC_LABEL_B:
new = (old & ~RELOC_MASK) + np->scriptb_ba;
break;
case RELOC_SOFTC:
new = (old & ~RELOC_MASK) + np->hcb_ba;
break;
case 0:
- /* Don't relocate a 0 address. */
+ /*
+ * Don't relocate a 0 address.
+ * They are mostly used for patched or
+ * script self-modified areas.
+ */
if (old == 0) {
new = old;
break;
}
/* fall through */
default:
- new = 0; /* For 'cc' not to complain */
- panic("sym_bind_script: "
+ new = 0;
+ panic("sym_fw_bind_script: "
"weird relocation %x\n", old);
break;
}
- *dst++ = cpu_to_scr(new);
+ *cur++ = cpu_to_scr(new);
}
};
}
+/*--------------------------------------------------------------------------*/
+/*--------------------------- END OF FIRMARES -----------------------------*/
+/*--------------------------------------------------------------------------*/
+
+/*
+ * Function prototypes.
+ */
+static void sym_save_initial_setting (hcb_p np);
+static int sym_prepare_setting (hcb_p np, struct sym_nvram *nvram);
+static int sym_prepare_nego (hcb_p np, ccb_p cp, int nego, u_char *msgptr);
+static void sym_put_start_queue (hcb_p np, ccb_p cp);
+static void sym_chip_reset (hcb_p np);
+static void sym_soft_reset (hcb_p np);
+static void sym_start_reset (hcb_p np);
+static int sym_reset_scsi_bus (hcb_p np, int enab_int);
+static int sym_wakeup_done (hcb_p np);
+static void sym_flush_busy_queue (hcb_p np, int cam_status);
+static void sym_flush_comp_queue (hcb_p np, int cam_status);
+static void sym_init (hcb_p np, int reason);
+static int sym_getsync(hcb_p np, u_char dt, u_char sfac, u_char *divp,
+ u_char *fakp);
+static void sym_setsync (hcb_p np, ccb_p cp, u_char ofs, u_char per,
+ u_char div, u_char fak);
+static void sym_setwide (hcb_p np, ccb_p cp, u_char wide);
+static void sym_setpprot(hcb_p np, ccb_p cp, u_char dt, u_char ofs,
+ u_char per, u_char wide, u_char div, u_char fak);
+static void sym_settrans(hcb_p np, ccb_p cp, u_char dt, u_char ofs,
+ u_char per, u_char wide, u_char div, u_char fak);
+static void sym_log_hard_error (hcb_p np, u_short sist, u_char dstat);
+static void sym_intr (void *arg);
+static void sym_poll (struct cam_sim *sim);
+static void sym_recover_scsi_int (hcb_p np, u_char hsts);
+static void sym_int_sto (hcb_p np);
+static void sym_int_udc (hcb_p np);
+static void sym_int_sbmc (hcb_p np);
+static void sym_int_par (hcb_p np, u_short sist);
+static void sym_int_ma (hcb_p np);
+static int sym_dequeue_from_squeue(hcb_p np, int i, int target, int lun,
+ int task);
+static void sym_sir_bad_scsi_status (hcb_p np, int num, ccb_p cp);
+static int sym_clear_tasks (hcb_p np, int status, int targ, int lun, int task);
+static void sym_sir_task_recovery (hcb_p np, int num);
+static int sym_evaluate_dp (hcb_p np, ccb_p cp, u32 scr, int *ofs);
+static void sym_modify_dp (hcb_p np, tcb_p tp, ccb_p cp, int ofs);
+static int sym_compute_residual (hcb_p np, ccb_p cp);
+static int sym_show_msg (u_char * msg);
+static void sym_print_msg (ccb_p cp, char *label, u_char *msg);
+static void sym_sync_nego (hcb_p np, tcb_p tp, ccb_p cp);
+static void sym_ppr_nego (hcb_p np, tcb_p tp, ccb_p cp);
+static void sym_wide_nego (hcb_p np, tcb_p tp, ccb_p cp);
+static void sym_nego_default (hcb_p np, tcb_p tp, ccb_p cp);
+static void sym_nego_rejected (hcb_p np, tcb_p tp, ccb_p cp);
+static void sym_int_sir (hcb_p np);
+static void sym_free_ccb (hcb_p np, ccb_p cp);
+static ccb_p sym_get_ccb (hcb_p np, u_char tn, u_char ln, u_char tag_order);
+static ccb_p sym_alloc_ccb (hcb_p np);
+static ccb_p sym_ccb_from_dsa (hcb_p np, u_long dsa);
+static lcb_p sym_alloc_lcb (hcb_p np, u_char tn, u_char ln);
+static void sym_alloc_lcb_tags (hcb_p np, u_char tn, u_char ln);
+static int sym_snooptest (hcb_p np);
+static void sym_selectclock(hcb_p np, u_char scntl3);
+static void sym_getclock (hcb_p np, int mult);
+static int sym_getpciclock (hcb_p np);
+static void sym_complete_ok (hcb_p np, ccb_p cp);
+static void sym_complete_error (hcb_p np, ccb_p cp);
+static void sym_timeout (void *arg);
+static int sym_abort_scsiio (hcb_p np, union ccb *ccb, int timed_out);
+static void sym_reset_dev (hcb_p np, union ccb *ccb);
+static void sym_action (struct cam_sim *sim, union ccb *ccb);
+static void sym_action1 (struct cam_sim *sim, union ccb *ccb);
+static int sym_setup_cdb (hcb_p np, struct ccb_scsiio *csio, ccb_p cp);
+static void sym_setup_data_and_start (hcb_p np, struct ccb_scsiio *csio,
+ ccb_p cp);
+#ifdef FreeBSD_Bus_Dma_Abstraction
+static int sym_fast_scatter_sg_physical(hcb_p np, ccb_p cp,
+ bus_dma_segment_t *psegs, int nsegs);
+#else
+static int sym_scatter_virtual (hcb_p np, ccb_p cp, vm_offset_t vaddr,
+ vm_size_t len);
+static int sym_scatter_sg_virtual (hcb_p np, ccb_p cp,
+ bus_dma_segment_t *psegs, int nsegs);
+static int sym_scatter_physical (hcb_p np, ccb_p cp, vm_offset_t paddr,
+ vm_size_t len);
+#endif
+static int sym_scatter_sg_physical (hcb_p np, ccb_p cp,
+ bus_dma_segment_t *psegs, int nsegs);
+static void sym_action2 (struct cam_sim *sim, union ccb *ccb);
+static void sym_update_trans (hcb_p np, tcb_p tp, struct sym_trans *tip,
+ struct ccb_trans_settings *cts);
+static void sym_update_dflags(hcb_p np, u_char *flags,
+ struct ccb_trans_settings *cts);
+
+#ifdef FreeBSD_Bus_Io_Abstraction
+static struct sym_pci_chip *sym_find_pci_chip (device_t dev);
+static int sym_pci_probe (device_t dev);
+static int sym_pci_attach (device_t dev);
+#else
+static struct sym_pci_chip *sym_find_pci_chip (pcici_t tag);
+static const char *sym_pci_probe (pcici_t tag, pcidi_t type);
+static void sym_pci_attach (pcici_t tag, int unit);
+static int sym_pci_attach2 (pcici_t tag, int unit);
+#endif
+
+static void sym_pci_free (hcb_p np);
+static int sym_cam_attach (hcb_p np);
+static void sym_cam_free (hcb_p np);
+
+static void sym_nvram_setup_host (hcb_p np, struct sym_nvram *nvram);
+static void sym_nvram_setup_target (hcb_p np, int targ, struct sym_nvram *nvp);
+static int sym_read_nvram (hcb_p np, struct sym_nvram *nvp);
+
/*
* Print something which allows to retrieve the controler type,
* unit, target, lun concerned by a kernel message.
@@ -4319,6 +2855,7 @@ static int sym_prepare_setting(hcb_p np, struct sym_nvram *nvram)
sym_name(np),
np->rv_dcntl & IRQM ? "totem pole" : "open drain",
np->ram_ba ? ", using on-chip SRAM" : "");
+ printf("%s: using %s firmware.\n", sym_name(np), np->fw_name);
if (np->features & FE_NOPM)
printf("%s: handling phase mismatch from SCRIPTS.\n",
sym_name(np));
@@ -4681,12 +3218,11 @@ static void sym_init (hcb_p np, int reason)
* Start at first entry.
*/
np->squeueput = 0;
- np->scriptb0->startpos[0] = cpu_to_scr(phys);
/*
* Clear Done Queue
*/
- phys = vtobus(np->dqueue);
+ phys = np->dqueue_ba;
for (i = 0; i < MAX_QUEUE*2; i += 2) {
np->dqueue[i] = 0;
np->dqueue[i+1] = cpu_to_scr(phys + (i+2)*4);
@@ -4696,10 +3232,16 @@ static void sym_init (hcb_p np, int reason)
/*
* Start at first entry.
*/
- np->scriptb0->done_pos[0] = cpu_to_scr(phys);
np->dqueueget = 0;
/*
+ * Install patches in scripts.
+ * This also let point to first position the start
+ * and done queue pointers used from SCRIPTS.
+ */
+ np->fw_patch(np);
+
+ /*
* Wakeup all pending jobs.
*/
sym_flush_busy_queue(np, CAM_SCSI_BUS_RESET);
@@ -4813,10 +3355,10 @@ static void sym_init (hcb_p np, int reason)
for (i=0;i<SYM_CONF_MAX_TARGET;i++) {
tcb_p tp = &np->target[i];
- tp->to_reset = 0;
- tp->sval = 0;
- tp->wval = np->rv_scntl3;
- tp->uval = 0;
+ tp->to_reset = 0;
+ tp->head.sval = 0;
+ tp->head.wval = np->rv_scntl3;
+ tp->head.uval = 0;
tp->tinfo.current.period = 0;
tp->tinfo.current.offset = 0;
@@ -4834,7 +3376,7 @@ static void sym_init (hcb_p np, int reason)
sym_name(np));
if (np->ram_ws == 8192) {
memcpy_to_pci(np->ram_va + 4096,
- np->scriptb0, sizeof(struct sym_scrb));
+ np->scriptb0, np->scriptb_sz);
OUTL (nc_mmws, np->scr_ram_seg);
OUTL (nc_mmrs, np->scr_ram_seg);
OUTL (nc_sfs, np->scr_ram_seg);
@@ -4842,7 +3384,7 @@ static void sym_init (hcb_p np, int reason)
}
else
phys = SCRIPTA_BA (np, init);
- memcpy_to_pci(np->ram_va,np->scripta0,sizeof(struct sym_scra));
+ memcpy_to_pci(np->ram_va, np->scripta0, np->scripta_sz);
}
else
phys = SCRIPTA_BA (np, init);
@@ -5062,9 +3604,9 @@ static void sym_settrans(hcb_p np, ccb_p cp, u_char dt, u_char ofs,
assert (target == (cp->target & 0xf));
tp = &np->target[target];
- sval = tp->sval;
- wval = tp->wval;
- uval = tp->uval;
+ sval = tp->head.sval;
+ wval = tp->head.wval;
+ uval = tp->head.uval;
#if 0
printf("XXXX sval=%x wval=%x uval=%x (%x)\n",
@@ -5117,10 +3659,13 @@ static void sym_settrans(hcb_p np, ccb_p cp, u_char dt, u_char ofs,
/*
* Stop there if sync parameters are unchanged.
*/
- if (tp->sval == sval && tp->wval == wval && tp->uval == uval) return;
- tp->sval = sval;
- tp->wval = wval;
- tp->uval = uval;
+ if (tp->head.sval == sval &&
+ tp->head.wval == wval &&
+ tp->head.uval == uval)
+ return;
+ tp->head.sval = sval;
+ tp->head.wval = wval;
+ tp->head.uval = uval;
/*
* Disable extended Sreq/Sack filtering if per < 50.
@@ -5132,11 +3677,11 @@ static void sym_settrans(hcb_p np, ccb_p cp, u_char dt, u_char ofs,
/*
* set actual value and sync_status
*/
- OUTB (nc_sxfer, tp->sval);
- OUTB (nc_scntl3, tp->wval);
+ OUTB (nc_sxfer, tp->head.sval);
+ OUTB (nc_scntl3, tp->head.wval);
if (np->features & FE_C10) {
- OUTB (nc_scntl4, tp->uval);
+ OUTB (nc_scntl4, tp->head.uval);
}
/*
@@ -5146,10 +3691,10 @@ static void sym_settrans(hcb_p np, ccb_p cp, u_char dt, u_char ofs,
cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
if (cp->target != target)
continue;
- cp->phys.select.sel_scntl3 = tp->wval;
- cp->phys.select.sel_sxfer = tp->sval;
+ cp->phys.select.sel_scntl3 = tp->head.wval;
+ cp->phys.select.sel_sxfer = tp->head.sval;
if (np->features & FE_C10) {
- cp->phys.select.sel_scntl4 = tp->uval;
+ cp->phys.select.sel_scntl4 = tp->head.uval;
}
}
}
@@ -5192,16 +3737,16 @@ static void sym_log_hard_error(hcb_p np, u_short sist, u_char dstat)
dsp = INL (nc_dsp);
if (dsp > np->scripta_ba &&
- dsp <= np->scripta_ba + sizeof(struct sym_scra)) {
+ dsp <= np->scripta_ba + np->scripta_sz) {
script_ofs = dsp - np->scripta_ba;
- script_size = sizeof(struct sym_scra);
+ script_size = np->scripta_sz;
script_base = (u_char *) np->scripta0;
script_name = "scripta";
}
else if (np->scriptb_ba < dsp &&
- dsp <= np->scriptb_ba + sizeof(struct sym_scrb)) {
+ dsp <= np->scriptb_ba + np->scriptb_sz) {
script_ofs = dsp - np->scriptb_ba;
- script_size = sizeof(struct sym_scrb);
+ script_size = np->scriptb_sz;
script_base = (u_char *) np->scriptb0;
script_name = "scriptb";
} else {
@@ -5794,12 +4339,12 @@ static void sym_int_ma (hcb_p np)
vdsp = 0;
nxtdsp = 0;
if (dsp > np->scripta_ba &&
- dsp <= np->scripta_ba + sizeof(struct sym_scra)) {
+ dsp <= np->scripta_ba + np->scripta_sz) {
vdsp = (u32 *)((char*)np->scripta0 + (dsp-np->scripta_ba-8));
nxtdsp = dsp;
}
else if (dsp > np->scriptb_ba &&
- dsp <= np->scriptb_ba + sizeof(struct sym_scrb)) {
+ dsp <= np->scriptb_ba + np->scriptb_sz) {
vdsp = (u32 *)((char*)np->scriptb0 + (dsp-np->scriptb_ba-8));
nxtdsp = dsp;
}
@@ -6272,9 +4817,9 @@ static void sym_sir_bad_scsi_status(hcb_p np, int num, ccb_p cp)
*/
startp = SCRIPTB_BA (np, sdata_in);
- cp->phys.savep = cpu_to_scr(startp);
- cp->phys.goalp = cpu_to_scr(startp + 16);
- cp->phys.lastp = cpu_to_scr(startp);
+ cp->phys.head.savep = cpu_to_scr(startp);
+ cp->phys.head.goalp = cpu_to_scr(startp + 16);
+ cp->phys.head.lastp = cpu_to_scr(startp);
cp->startp = cpu_to_scr(startp);
cp->actualquirks = SYM_QUIRK_AUTOSAVE;
@@ -6284,8 +4829,7 @@ static void sym_sir_bad_scsi_status(hcb_p np, int num, ccb_p cp)
cp->xerr_status = 0;
cp->extra_bytes = 0;
- cp->phys.go.start =
- cpu_to_scr(SCRIPTA_BA (np, select));
+ cp->phys.head.go.start = cpu_to_scr(SCRIPTA_BA (np, select));
/*
* Requeue the command.
@@ -6458,8 +5002,8 @@ static void sym_sir_task_recovery(hcb_p np, int num)
if (target != -1) {
tp = &np->target[target];
np->abrt_sel.sel_id = target;
- np->abrt_sel.sel_scntl3 = tp->wval;
- np->abrt_sel.sel_sxfer = tp->sval;
+ np->abrt_sel.sel_scntl3 = tp->head.wval;
+ np->abrt_sel.sel_sxfer = tp->head.sval;
OUTL(nc_dsa, np->hcb_ba);
OUTL (nc_dsp, SCRIPTB_BA (np, sel_for_abort));
return;
@@ -6666,9 +5210,9 @@ static void sym_sir_task_recovery(hcb_p np, int num)
lun = -1;
task = -1;
if (np->abrt_msg[0] == M_RESET) {
- tp->sval = 0;
- tp->wval = np->rv_scntl3;
- tp->uval = 0;
+ tp->head.sval = 0;
+ tp->head.wval = np->rv_scntl3;
+ tp->head.uval = 0;
tp->tinfo.current.period = 0;
tp->tinfo.current.offset = 0;
tp->tinfo.current.width = BUS_8_BIT;
@@ -6786,7 +5330,7 @@ static int sym_evaluate_dp(hcb_p np, ccb_p cp, u32 scr, int *ofs)
* If result is dp_sg = SYM_CONF_MAX_SG, then we are at the
* end of the data.
*/
- tmp = scr_to_cpu(cp->phys.goalp);
+ tmp = scr_to_cpu(cp->phys.head.goalp);
dp_sg = SYM_CONF_MAX_SG;
if (dp_scr != tmp)
dp_sg -= (tmp - 8 - (int)dp_scr) / (2*4);
@@ -6893,7 +5437,7 @@ static void sym_modify_dp(hcb_p np, tcb_p tp, ccb_p cp, int ofs)
* And our alchemy:) allows to easily calculate the data
* script address we want to return for the next data phase.
*/
- dp_ret = cpu_to_scr(cp->phys.goalp);
+ dp_ret = cpu_to_scr(cp->phys.head.goalp);
dp_ret = dp_ret - 8 - (SYM_CONF_MAX_SG - dp_sg) * (2*4);
/*
@@ -6989,15 +5533,16 @@ static int sym_compute_residual(hcb_p np, ccb_p cp)
* If all data has been transferred,
* there is no residual.
*/
- if (cp->phys.lastp == cp->phys.goalp)
+ if (cp->phys.head.lastp == cp->phys.head.goalp)
return resid;
/*
* If no data transfer occurs, or if the data
* pointer is weird, return full residual.
*/
- if (cp->startp == cp->phys.lastp ||
- sym_evaluate_dp(np, cp, scr_to_cpu(cp->phys.lastp), &dp_ofs) < 0) {
+ if (cp->startp == cp->phys.head.lastp ||
+ sym_evaluate_dp(np, cp, scr_to_cpu(cp->phys.head.lastp),
+ &dp_ofs) < 0) {
return cp->data_len;
}
@@ -7026,7 +5571,7 @@ static int sym_compute_residual(hcb_p np, ccb_p cp)
}
/*
- * Print out the containt of a SCSI message.
+ * Print out the content of a SCSI message.
*/
static int sym_show_msg (u_char * msg)
@@ -7369,7 +5914,7 @@ static void sym_wide_nego(hcb_p np, tcb_p tp, ccb_p cp)
if (chg) /* Answer wasn't acceptable. */
goto reject_it;
sym_setwide (np, cp, wide);
-#if 1
+
/*
* Negotiate for SYNC immediately after WIDE response.
* This allows to negotiate for both WIDE and SYNC on
@@ -7391,7 +5936,7 @@ static void sym_wide_nego(hcb_p np, tcb_p tp, ccb_p cp)
OUTL (nc_dsp, SCRIPTB_BA (np, sdtr_resp));
return;
}
-#endif
+
OUTL (nc_dsp, SCRIPTA_BA (np, clrack));
return;
};
@@ -7791,7 +6336,7 @@ static ccb_p sym_get_ccb (hcb_p np, u_char tn, u_char ln, u_char tag_order)
lp->ia_tag = 0;
lp->itlq_tbl[tag] = cpu_to_scr(cp->ccb_ba);
++lp->busy_itlq;
- lp->resel_sa =
+ lp->head.resel_sa =
cpu_to_scr(SCRIPTA_BA (np, resel_tag));
}
else
@@ -7813,9 +6358,9 @@ static ccb_p sym_get_ccb (hcb_p np, u_char tn, u_char ln, u_char tag_order)
* Toggle reselect path to untagged.
*/
if (++lp->busy_itl == 1) {
- lp->itl_task_sa = cpu_to_scr(cp->ccb_ba);
- lp->resel_sa =
- cpu_to_scr(SCRIPTA_BA (np,resel_no_tag));
+ lp->head.itl_task_sa = cpu_to_scr(cp->ccb_ba);
+ lp->head.resel_sa =
+ cpu_to_scr(SCRIPTA_BA (np, resel_no_tag));
}
else
goto out_free;
@@ -7884,14 +6429,14 @@ static void sym_free_ccb (hcb_p np, ccb_p cp)
* Make the reselect path invalid,
* and uncount this CCB.
*/
- lp->itl_task_sa = cpu_to_scr(np->bad_itl_ba);
+ lp->head.itl_task_sa = cpu_to_scr(np->bad_itl_ba);
--lp->busy_itl;
}
/*
* If no JOB active, make the LUN reselect path invalid.
*/
if (lp->busy_itlq == 0 && lp->busy_itl == 0)
- lp->resel_sa =
+ lp->head.resel_sa =
cpu_to_scr(SCRIPTB_BA (np, resel_bad_lun));
}
/*
@@ -7993,8 +6538,8 @@ static ccb_p sym_alloc_ccb(hcb_p np)
/*
* Initialyze the start and restart actions.
*/
- cp->phys.go.start = cpu_to_scr(SCRIPTA_BA (np, idle));
- cp->phys.go.restart = cpu_to_scr(SCRIPTB_BA (np, bad_i_t_l));
+ cp->phys.head.go.start = cpu_to_scr(SCRIPTA_BA (np, idle));
+ cp->phys.head.go.restart = cpu_to_scr(SCRIPTB_BA (np, bad_i_t_l));
/*
* Initilialyze some other fields.
@@ -8045,9 +6590,9 @@ static void sym_init_tcb (hcb_p np, u_char tn)
* Check some alignments required by the chip.
*/
assert (((offsetof(struct sym_reg, nc_sxfer) ^
- offsetof(struct sym_tcb, sval)) &3) == 0);
+ offsetof(struct sym_tcb, head.sval)) &3) == 0);
assert (((offsetof(struct sym_reg, nc_scntl3) ^
- offsetof(struct sym_tcb, wval)) &3) == 0);
+ offsetof(struct sym_tcb, head.wval)) &3) == 0);
}
/*
@@ -8085,7 +6630,7 @@ static lcb_p sym_alloc_lcb (hcb_p np, u_char tn, u_char ln)
goto fail;
for (i = 0 ; i < 64 ; i++)
tp->luntbl[i] = cpu_to_scr(vtobus(&np->badlun_sa));
- tp->luntbl_sa = cpu_to_scr(vtobus(tp->luntbl));
+ tp->head.luntbl_sa = cpu_to_scr(vtobus(tp->luntbl));
}
/*
@@ -8111,18 +6656,18 @@ static lcb_p sym_alloc_lcb (hcb_p np, u_char tn, u_char ln)
}
else {
tp->lun0p = lp;
- tp->lun0_sa = cpu_to_scr(vtobus(lp));
+ tp->head.lun0_sa = cpu_to_scr(vtobus(lp));
}
/*
* Let the itl task point to error handling.
*/
- lp->itl_task_sa = cpu_to_scr(np->bad_itl_ba);
+ lp->head.itl_task_sa = cpu_to_scr(np->bad_itl_ba);
/*
* Set the reselect pattern to our default. :)
*/
- lp->resel_sa = cpu_to_scr(SCRIPTB_BA (np, resel_bad_lun));
+ lp->head.resel_sa = cpu_to_scr(SCRIPTB_BA (np, resel_bad_lun));
/*
* Set user capabilities.
@@ -8178,7 +6723,7 @@ static void sym_alloc_lcb_tags (hcb_p np, u_char tn, u_char ln)
* Make the task table available to SCRIPTS,
* And accept tagged commands now.
*/
- lp->itlq_tbl_sa = cpu_to_scr(vtobus(lp->itlq_tbl));
+ lp->head.itlq_tbl_sa = cpu_to_scr(vtobus(lp->itlq_tbl));
return;
fail:
@@ -8290,6 +6835,7 @@ static int sym_snooptest (hcb_p np)
(int) sym_wr, (int) sym_bk);
err |= 4;
};
+
return (err);
}
@@ -8732,7 +7278,7 @@ static void sym_complete_ok (hcb_p np, ccb_p cp)
* extended error did occur, there is no residual.
*/
csio->resid = 0;
- if (cp->phys.lastp != cp->phys.goalp)
+ if (cp->phys.head.lastp != cp->phys.head.goalp)
csio->resid = sym_compute_residual(np, cp);
/*
@@ -9031,16 +7577,16 @@ static void sym_action1(struct cam_sim *sim, union ccb *ccb)
/*
* Startqueue
*/
- cp->phys.go.start = cpu_to_scr(SCRIPTA_BA (np, select));
- cp->phys.go.restart = cpu_to_scr(SCRIPTA_BA (np, resel_dsa));
+ cp->phys.head.go.start = cpu_to_scr(SCRIPTA_BA (np, select));
+ cp->phys.head.go.restart = cpu_to_scr(SCRIPTA_BA (np, resel_dsa));
/*
* select
*/
cp->phys.select.sel_id = cp->target;
- cp->phys.select.sel_scntl3 = tp->wval;
- cp->phys.select.sel_sxfer = tp->sval;
- cp->phys.select.sel_scntl4 = tp->uval;
+ cp->phys.select.sel_scntl3 = tp->head.wval;
+ cp->phys.select.sel_sxfer = tp->head.sval;
+ cp->phys.select.sel_scntl4 = tp->head.uval;
/*
* message
@@ -9166,10 +7712,10 @@ sym_setup_data_pointers(hcb_p np, ccb_p cp, int dir)
break;
}
- cp->phys.lastp = cpu_to_scr(lastp);
- cp->phys.goalp = cpu_to_scr(goalp);
- cp->phys.savep = cpu_to_scr(lastp);
- cp->startp = cp->phys.savep;
+ cp->phys.head.lastp = cpu_to_scr(lastp);
+ cp->phys.head.goalp = cpu_to_scr(goalp);
+ cp->phys.head.savep = cpu_to_scr(lastp);
+ cp->startp = cp->phys.head.savep;
}
@@ -9895,13 +8441,22 @@ DATA_SET (pcidevice_set, sym_pci_driver);
#endif /* FreeBSD_Bus_Io_Abstraction */
static struct sym_pci_chip sym_pci_dev_table[] = {
- {PCI_ID_SYM53C810, 0x0f, "810", 4, 8, 4, 0,
+ {PCI_ID_SYM53C810, 0x0f, "810", 4, 8, 4, 64,
FE_ERL}
,
+#ifdef SYM_DEBUG_GENERIC_SUPPORT
+ {PCI_ID_SYM53C810, 0xff, "810a", 4, 8, 4, 1,
+ FE_BOF}
+ ,
+#else
{PCI_ID_SYM53C810, 0xff, "810a", 4, 8, 4, 1,
FE_CACHE_SET|FE_LDSTR|FE_PFEN|FE_BOF}
,
- {PCI_ID_SYM53C825, 0x0f, "825", 6, 8, 4, 0,
+#endif
+ {PCI_ID_SYM53C815, 0xff, "815", 4, 8, 4, 64,
+ FE_BOF|FE_ERL}
+ ,
+ {PCI_ID_SYM53C825, 0x0f, "825", 6, 8, 4, 64,
FE_WIDE|FE_BOF|FE_ERL|FE_DIFF}
,
{PCI_ID_SYM53C825, 0xff, "825a", 6, 8, 4, 2,
@@ -9926,10 +8481,17 @@ static struct sym_pci_chip sym_pci_dev_table[] = {
FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|
FE_RAM|FE_DIFF}
,
+#ifdef SYM_DEBUG_GENERIC_SUPPORT
+ {PCI_ID_SYM53C895, 0xff, "895", 6, 31, 7, 2,
+ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|
+ FE_RAM|FE_LCKFRQ}
+ ,
+#else
{PCI_ID_SYM53C895, 0xff, "895", 6, 31, 7, 2,
FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|
FE_RAM|FE_LCKFRQ}
,
+#endif
{PCI_ID_SYM53C896, 0xff, "896", 6, 31, 7, 4,
FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|
FE_RAM|FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM|FE_LEDC|FE_LCKFRQ}
@@ -9999,9 +8561,7 @@ sym_find_pci_chip(pcici_t pci_tag)
continue;
if (revision > chip->revision_id)
continue;
- if (FE_LDSTR & chip->features)
- return chip;
- break;
+ return chip;
}
return 0;
@@ -10017,7 +8577,7 @@ sym_pci_probe(device_t dev)
struct sym_pci_chip *chip;
chip = sym_find_pci_chip(dev);
- if (chip) {
+ if (chip && sym_find_firmware(chip)) {
device_set_desc(dev, chip->name);
return (chip->lp_probe_bit & SYM_SETUP_LP_PROBE_MAP)? -2000 : 0;
}
@@ -10030,13 +8590,15 @@ sym_pci_probe(pcici_t pci_tag, pcidi_t type)
struct sym_pci_chip *chip;
chip = sym_find_pci_chip(pci_tag);
+ if (chip && sym_find_firmware(chip)) {
#if NNCR > 0
/* Only claim chips we are allowed to take precedence over the ncr */
- if (chip && !(chip->lp_probe_bit & SYM_SETUP_LP_PROBE_MAP))
+ if (!(chip->lp_probe_bit & SYM_SETUP_LP_PROBE_MAP))
#else
- if (chip)
+ if (1)
#endif
return chip->name;
+ }
return 0;
}
#endif
@@ -10064,6 +8626,7 @@ sym_pci_attach2(pcici_t pci_tag, int unit)
u_char cachelnsz;
struct sym_hcb *np = 0;
struct sym_nvram nvram;
+ struct sym_fw *fw = 0;
int i;
#ifdef FreeBSD_Bus_Dma_Abstraction
bus_dma_tag_t bus_dmat;
@@ -10084,7 +8647,7 @@ sym_pci_attach2(pcici_t pci_tag, int unit)
#else
chip = sym_find_pci_chip(pci_tag);
#endif
- if (chip == NULL)
+ if (chip == NULL || (fw = sym_find_firmware(chip)) == NULL)
return (ENXIO);
/*
@@ -10125,6 +8688,11 @@ sym_pci_attach2(pcici_t pci_tag, int unit)
np->clock_divn = chip->nr_divisor;
np->maxoffs = chip->offset_max;
np->maxburst = chip->burst_max;
+ np->scripta_sz = fw->a_size;
+ np->scriptb_sz = fw->b_size;
+ np->fw_setup = fw->setup;
+ np->fw_patch = fw->patch;
+ np->fw_name = fw->name;
/*
* Edit its name.
@@ -10347,6 +8915,7 @@ sym_pci_attach2(pcici_t pci_tag, int unit)
np->dqueue = (u32 *) sym_calloc_dma(sizeof(u32)*(MAX_QUEUE*2),"DQUEUE");
if (!np->dqueue)
goto attach_failed;
+ np->dqueue_ba = vtobus(np->dqueue);
/*
* Allocate the target bus address array.
@@ -10354,14 +8923,13 @@ sym_pci_attach2(pcici_t pci_tag, int unit)
np->targtbl = (u32 *) sym_calloc_dma(256, "TARGTBL");
if (!np->targtbl)
goto attach_failed;
+ np->targtbl_ba = cpu_to_scr(vtobus(np->targtbl));
/*
* Allocate SCRIPTS areas.
*/
- np->scripta0 = (struct sym_scra *)
- sym_calloc_dma(sizeof(struct sym_scra), "SCRIPTA0");
- np->scriptb0 = (struct sym_scrb *)
- sym_calloc_dma(sizeof(struct sym_scrb), "SCRIPTB0");
+ np->scripta0 = sym_calloc_dma(np->scripta_sz, "SCRIPTA0");
+ np->scriptb0 = sym_calloc_dma(np->scriptb_sz, "SCRIPTB0");
if (!np->scripta0 || !np->scriptb0)
goto attach_failed;
@@ -10381,11 +8949,6 @@ sym_pci_attach2(pcici_t pci_tag, int unit)
sym_que_init(&np->cam_ccbq);
/*
- * Fill-up variable-size parts of the SCRIPTS.
- */
- sym_fill_scripts(&scripta0, &scriptb0);
-
- /*
* Calculate BUS addresses where we are going
* to load the SCRIPTS.
*/
@@ -10407,49 +8970,26 @@ sym_pci_attach2(pcici_t pci_tag, int unit)
}
/*
- * Bind SCRIPTS with physical addresses usable by the
- * SCRIPTS processor (as seen from the BUS = BUS addresses).
+ * Copy scripts to controller instance.
*/
- sym_bind_script(np, (u32 *) &scripta0,
- (u32 *) np->scripta0, sizeof(struct sym_scra));
- sym_bind_script(np, (u32 *) &scriptb0,
- (u32 *) np->scriptb0, sizeof(struct sym_scrb));
+ bcopy(fw->a_base, np->scripta0, np->scripta_sz);
+ bcopy(fw->b_base, np->scriptb0, np->scriptb_sz);
/*
- * Patch some variables in SCRIPTS.
- * These ones are loaded by the SCRIPTS processor.
+ * Setup variable parts in scripts and compute
+ * scripts bus addresses used from the C code.
*/
- np->scriptb0->pm0_data_addr[0] = cpu_to_scr(SCRIPTA_BA (np, pm0_data));
- np->scriptb0->pm1_data_addr[0] = cpu_to_scr(SCRIPTA_BA (np, pm1_data));
-
+ np->fw_setup(np, fw);
/*
- * Still some for removing LED support.
- */
- if (!(np->features & FE_LED0)) {
- np->scripta0->idle[0] = cpu_to_scr(SCR_NO_OP);
- np->scripta0->reselected[0] = cpu_to_scr(SCR_NO_OP);
- np->scripta0->start[0] = cpu_to_scr(SCR_NO_OP);
- }
-
- /*
- * Remove the load of SCNTL4 on reselection if not a C10.
+ * Bind SCRIPTS with physical addresses usable by the
+ * SCRIPTS processor (as seen from the BUS = BUS addresses).
*/
- if (!(np->features & FE_C10)) {
- np->scripta0->resel_scntl4[0] = cpu_to_scr(SCR_NO_OP);
- np->scripta0->resel_scntl4[1] = cpu_to_scr(0);
- }
+ sym_fw_bind_script(np, (u32 *) np->scripta0, np->scripta_sz);
+ sym_fw_bind_script(np, (u32 *) np->scriptb0, np->scriptb_sz);
#ifdef SYM_CONF_IARB_SUPPORT
/*
- * If user does not want to use IMMEDIATE ARBITRATION
- * when we are reselected while attempting to arbitrate,
- * patch the SCRIPTS accordingly with a SCRIPT NO_OP.
- */
- if (!SYM_CONF_SET_IARB_ON_ARB_LOST)
- np->scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP);
-
- /*
* If user wants IARB to be set when we win arbitration
* and have other jobs, compute the max number of consecutive
* settings of IARB hints before we leave devices a chance to
@@ -10500,11 +9040,12 @@ sym_pci_attach2(pcici_t pci_tag, int unit)
* address of each target control bloc.
* For now, assume all logical unit are wrong. :)
*/
- np->scriptb0->targtbl[0] = cpu_to_scr(vtobus(np->targtbl));
for (i = 0 ; i < SYM_CONF_MAX_TARGET ; i++) {
np->targtbl[i] = cpu_to_scr(vtobus(&np->target[i]));
- np->target[i].luntbl_sa = cpu_to_scr(vtobus(np->badluntbl));
- np->target[i].lun0_sa = cpu_to_scr(vtobus(&np->badlun_sa));
+ np->target[i].head.luntbl_sa =
+ cpu_to_scr(vtobus(np->badluntbl));
+ np->target[i].head.lun0_sa =
+ cpu_to_scr(vtobus(&np->badlun_sa));
}
/*
@@ -10587,9 +9128,9 @@ static void sym_pci_free(hcb_p np)
#endif
if (np->scriptb0)
- sym_mfree_dma(np->scriptb0, sizeof(struct sym_scrb),"SCRIPTB0");
+ sym_mfree_dma(np->scriptb0, np->scriptb_sz, "SCRIPTB0");
if (np->scripta0)
- sym_mfree_dma(np->scripta0, sizeof(struct sym_scra),"SCRIPTA0");
+ sym_mfree_dma(np->scripta0, np->scripta_sz, "SCRIPTA0");
if (np->squeue)
sym_mfree_dma(np->squeue, sizeof(u32)*(MAX_QUEUE*2), "SQUEUE");
if (np->dqueue)
OpenPOWER on IntegriCloud