diff options
author | groudier <groudier@FreeBSD.org> | 2000-04-29 10:20:16 +0000 |
---|---|---|
committer | groudier <groudier@FreeBSD.org> | 2000-04-29 10:20:16 +0000 |
commit | 22b8c23cfa70ae85832d75bd7e71984b28507497 (patch) | |
tree | b5d865d29a9faee6c30a80fc0208481489c3034a /sys/dev/sym | |
parent | 706084939e6e22a3e98307ed10974cabdff2837c (diff) | |
download | FreeBSD-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.h | 21 | ||||
-rw-r--r-- | sys/dev/sym/sym_defs.h | 5 | ||||
-rw-r--r-- | sys/dev/sym/sym_fw.h | 208 | ||||
-rw-r--r-- | sys/dev/sym/sym_fw1.h | 1798 | ||||
-rw-r--r-- | sys/dev/sym/sym_fw2.h | 1850 | ||||
-rw-r--r-- | sys/dev/sym/sym_hipd.c | 2751 |
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) |